From 5b35eb973c66a173abccc2d9fa654bccbded1828 Mon Sep 17 00:00:00 2001 From: Cyd Date: Sun, 19 Jul 2026 19:05:53 -0500 Subject: [PATCH] 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 --- .gitignore | 3 + restoration/source410/BT/BTDIRECT.CPP | 20 + restoration/source410/BT/BTPLAYER.CPP | 20 + restoration/source410/BT/MECH.CPP | 17 + restoration/source410/BT/MECHMPPR.CPP | 58 + restoration/source410/BT/MISSILE.CPP | 7 + restoration/source410/BT/PROJTILE.CPP | 7 + restoration/source410/BT_L4/BTL4.CPP | 91 + restoration/source410/BT_L4/BTL4.NOTES.md | 65 + restoration/source410/BT_L4/BTL4GRND.CPP | 34 + restoration/source410/BT_L4/BTL4MPPR.CPP | 77 + restoration/source410/BT_L4/BTL4MSSN.CPP | 34 + restoration/source410/BT_L4/BTL4VID.CPP | 43 + restoration/source410/MUNGA/AUDCMP.CPP | 1564 ++++++++ restoration/source410/MUNGA/AUDREND.CPP | 540 +++ restoration/source410/MUNGA/AUDREND.HPP | 6 +- restoration/source410/MUNGA/BOXTREE.HPP | 10 +- restoration/source410/MUNGA/CSTR.CPP | 450 +++ restoration/source410/MUNGA/EXPTBL.CPP | 625 +++ restoration/source410/MUNGA/FILEUTIL.CPP | 832 ++++ restoration/source410/MUNGA/GAUGE.CPP | 827 ++++ restoration/source410/MUNGA/GAUGMAP.CPP | 744 ++++ restoration/source410/MUNGA/GAUGREND.CPP | 4336 +++++++++++++++++++++ restoration/source410/MUNGA/GRAPH2D.CPP | 3111 +++++++++++++++ restoration/source410/MUNGA/NETWORK.CPP | 484 ++- restoration/source410/MUNGA/OBJSTRM.CPP | 1217 ++++++ restoration/source410/MUNGA/RAY.CPP | 176 + restoration/source410/MUNGA/RESOURCE.CPP | 916 +++++ restoration/source410/MUNGA/SCNROLE.CPP | 243 ++ restoration/source410/MUNGA/STUBS.CPP | 45 + restoration/source410/MUNGA/VERIFY.CPP | 204 + restoration/source410/MUNGA_L4/L4APP.CPP | 949 ++++- restoration/source410/MUNGA_L4/L4NET.CPP | 119 + restoration/source410/backdate.py | 2 +- restoration/source410/build410.sh | 86 +- 35 files changed, 17798 insertions(+), 164 deletions(-) create mode 100644 restoration/source410/BT/MECHMPPR.CPP create mode 100644 restoration/source410/BT_L4/BTL4.CPP create mode 100644 restoration/source410/BT_L4/BTL4.NOTES.md create mode 100644 restoration/source410/BT_L4/BTL4GRND.CPP create mode 100644 restoration/source410/BT_L4/BTL4MSSN.CPP create mode 100644 restoration/source410/BT_L4/BTL4VID.CPP create mode 100644 restoration/source410/MUNGA/AUDCMP.CPP create mode 100644 restoration/source410/MUNGA/AUDREND.CPP create mode 100644 restoration/source410/MUNGA/CSTR.CPP create mode 100644 restoration/source410/MUNGA/EXPTBL.CPP create mode 100644 restoration/source410/MUNGA/FILEUTIL.CPP create mode 100644 restoration/source410/MUNGA/GAUGE.CPP create mode 100644 restoration/source410/MUNGA/GAUGMAP.CPP create mode 100644 restoration/source410/MUNGA/GAUGREND.CPP create mode 100644 restoration/source410/MUNGA/GRAPH2D.CPP create mode 100644 restoration/source410/MUNGA/OBJSTRM.CPP create mode 100644 restoration/source410/MUNGA/RAY.CPP create mode 100644 restoration/source410/MUNGA/RESOURCE.CPP create mode 100644 restoration/source410/MUNGA/SCNROLE.CPP create mode 100644 restoration/source410/MUNGA/STUBS.CPP create mode 100644 restoration/source410/MUNGA/VERIFY.CPP create mode 100644 restoration/source410/MUNGA_L4/L4NET.CPP diff --git a/.gitignore b/.gitignore index 2e2a87b5..690e4771 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ __pycache__/ /emulator/pod-launch/publish/ /emulator/pod-launch/bin/pkg/ /emulator/bld*.log + +# 4.10 source reconstruction build outputs (rebuild: bash restoration/source410/build410.sh all) +/restoration/build410/ diff --git a/restoration/source410/BT/BTDIRECT.CPP b/restoration/source410/BT/BTDIRECT.CPP index 3710496d..aa076937 100644 --- a/restoration/source410/BT/BTDIRECT.CPP +++ b/restoration/source410/BT/BTDIRECT.CPP @@ -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; +} diff --git a/restoration/source410/BT/BTPLAYER.CPP b/restoration/source410/BT/BTPLAYER.CPP index 6c2ce4b8..ded2d2a1 100644 --- a/restoration/source410/BT/BTPLAYER.CPP +++ b/restoration/source410/BT/BTPLAYER.CPP @@ -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; +} diff --git a/restoration/source410/BT/MECH.CPP b/restoration/source410/BT/MECH.CPP index f1553c8f..dfcea78d 100644 --- a/restoration/source410/BT/MECH.CPP +++ b/restoration/source410/BT/MECH.CPP @@ -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"); +} diff --git a/restoration/source410/BT/MECHMPPR.CPP b/restoration/source410/BT/MECHMPPR.CPP new file mode 100644 index 00000000..99149d21 --- /dev/null +++ b/restoration/source410/BT/MECHMPPR.CPP @@ -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 +#pragma hdrstop + +#if !defined(MECHMPPR_HPP) +# include +#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); +} diff --git a/restoration/source410/BT/MISSILE.CPP b/restoration/source410/BT/MISSILE.CPP index 577d4e37..609a1559 100644 --- a/restoration/source410/BT/MISSILE.CPP +++ b/restoration/source410/BT/MISSILE.CPP @@ -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; +} diff --git a/restoration/source410/BT/PROJTILE.CPP b/restoration/source410/BT/PROJTILE.CPP index 7f94096e..26a577ac 100644 --- a/restoration/source410/BT/PROJTILE.CPP +++ b/restoration/source410/BT/PROJTILE.CPP @@ -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; +} diff --git a/restoration/source410/BT_L4/BTL4.CPP b/restoration/source410/BT_L4/BTL4.CPP new file mode 100644 index 00000000..cef1c512 --- /dev/null +++ b/restoration/source410/BT_L4/BTL4.CPP @@ -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 +#pragma hdrstop + +#if !defined(BTL4APP_HPP) +# include +#endif + +#if !defined(APPMGR_HPP) +# include +#endif + +#if !defined(BTL4VER_HPP) +# include +#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; +} diff --git a/restoration/source410/BT_L4/BTL4.NOTES.md b/restoration/source410/BT_L4/BTL4.NOTES.md new file mode 100644 index 00000000..f629b15e --- /dev/null +++ b/restoration/source410/BT_L4/BTL4.NOTES.md @@ -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 = ; +if (spool_file) + mgr->StartApplication(new(0xd8) BTL4PlaybackApplication(&resources, spool_file)); +if (mode == 1) + mgr->StartApplication(new(0xd8) (&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. diff --git a/restoration/source410/BT_L4/BTL4GRND.CPP b/restoration/source410/BT_L4/BTL4GRND.CPP new file mode 100644 index 00000000..12f392e1 --- /dev/null +++ b/restoration/source410/BT_L4/BTL4GRND.CPP @@ -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 +#pragma hdrstop + +#if !defined(BTL4GRND_HPP) +# include +#endif + +BTL4GaugeRenderer::BTL4GaugeRenderer() +{ +} + +BTL4GaugeRenderer::~BTL4GaugeRenderer() +{ +} + +void + BTL4GaugeRenderer::NotifyOfNewInterestingEntity(Entity *) +{ +} + +void + BTL4GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *) +{ +} diff --git a/restoration/source410/BT_L4/BTL4MPPR.CPP b/restoration/source410/BT_L4/BTL4MPPR.CPP index df609a84..727455d5 100644 --- a/restoration/source410/BT_L4/BTL4MPPR.CPP +++ b/restoration/source410/BT_L4/BTL4MPPR.CPP @@ -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); +} diff --git a/restoration/source410/BT_L4/BTL4MSSN.CPP b/restoration/source410/BT_L4/BTL4MSSN.CPP new file mode 100644 index 00000000..a0217e67 --- /dev/null +++ b/restoration/source410/BT_L4/BTL4MSSN.CPP @@ -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 +#pragma hdrstop + +#if !defined(BTL4MSSN_HPP) +# include +#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"); +} diff --git a/restoration/source410/BT_L4/BTL4VID.CPP b/restoration/source410/BT_L4/BTL4VID.CPP new file mode 100644 index 00000000..1c9c27aa --- /dev/null +++ b/restoration/source410/BT_L4/BTL4VID.CPP @@ -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 +#pragma hdrstop + +#if !defined(BTL4VID_HPP) +# include +#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"); +} diff --git a/restoration/source410/MUNGA/AUDCMP.CPP b/restoration/source410/MUNGA/AUDCMP.CPP new file mode 100644 index 00000000..b5d03ac8 --- /dev/null +++ b/restoration/source410/MUNGA/AUDCMP.CPP @@ -0,0 +1,1564 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(AUDCMP_HPP) +# include +# endif +# if !defined(AUDSRC_HPP) +# include +# endif +# if !defined(RANDOM_HPP) +# include +# endif +# if !defined(CONTROLS_HPP) +# include +# endif +# if !defined(OBJSTRM_HPP) +# include +# endif +# if !defined(SUBSYSTM_HPP) +# include +# endif +# if !defined(NAMELIST_HPP) +# include +# endif + +//############################################################################# +//######################### AudioMessageWatcher ######################### +//############################################################################# + +// +//############################################################################# +//############################################################################# +// +AudioMessageWatcher::AudioMessageWatcher( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL), + messageTap(NULL) +{ + Check(stream); + Check(entity); + + // + // HACK - Get simulation pointer using names + // + Simulation *simulation; + CString subsystem_name; + + MemoryStream_Read(stream, &subsystem_name); + if ((simulation = entity->FindSubsystem(subsystem_name)) == NULL) + { + #if DEBUG_LEVEL>0 + { + CString entity_name("Entity"); + if (!(subsystem_name == entity_name)) + { + Dump(subsystem_name); + } + Verify(subsystem_name == entity_name); + } + #else + { + CString entity_name("Entity"); + if (!(subsystem_name == entity_name)) + { + DEBUG_STREAM << + "MessageWatcher::MessageWatcher - subsystem " << + subsystem_name << + "\n"; + Fail("MessageWatcher::MessageWatcher - subsystem not found\n"); + } + } + #endif + simulation = entity; + } + Check(simulation); + + // + // Get message id + // + Receiver::MessageID message_ID; + MemoryStream_Read(stream, &message_ID); + + // + // Get audio component, control ID, control value + // + AudioComponent *audio_component; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + MemoryStream_Read(stream, &controlID); + MemoryStream_Read(stream, &controlValue); + + audioComponentSocket.Add(audio_component); + + // + // Make the message tap + // + messageTap = + MakeMessageTap( + simulation->GetDerivation(), + (ScanCallback)&AudioMessageWatcher::MessageTapScanCallback, + message_ID, + simulation + ); + Register_Object(messageTap); + + entity->AddAudioComponent(this); + + #if DEBUG_LEVEL>0 + verifyReceiver = simulation; + verifyMessageID = message_ID; + #endif +} + +// +//############################################################################# +//############################################################################# +// +AudioMessageWatcher::~AudioMessageWatcher() +{ + Unregister_Object(messageTap); + delete messageTap; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioMessageWatcher::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // HACK - Store simulation pointer using names + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, CString, subsystem); + + // + // Store message ID + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, message_ID); + + // + // Store audio_component, control ID, control value + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, control_value); +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioMessageWatcher::TestInstance() const +{ + Component::TestInstance(); + if (messageTap != NULL) + { + Check(messageTap); + } + Check(&audioComponentSocket); + return True; +} + +// +//############################################################################# +//############################################################################# +// +#if DEBUG_LEVEL>0 +void + AudioMessageWatcher::MessageTapScanCallback( + Receiver::Message *message, + Receiver *receiver + ) +#else +void + AudioMessageWatcher::MessageTapScanCallback( + Receiver::Message *message, + Receiver* + ) +#endif +{ + Check(this); + Check(message); + Check(receiver); + Verify(verifyReceiver == receiver); + Verify(verifyMessageID == message->messageID); + + // + // Send the audio control message + // + if (DoesMessageMatch(message)) + { + Check(audioComponentSocket.GetCurrent()); + #if 1 + audioComponentSocket.GetCurrent()->ReceiveControl( + controlID, + controlValue + ); + #else + audioComponentSocket.GetCurrent()->PostReceiveControl( + controlID, + controlValue + ); + #endif + } +} + +// +//############################################################################# +//############################################################################# +// +void + AudioMessageWatcher::ReceiveControl( + AudioControlID, + AudioControlValue + ) +{ +} + +//############################################################################# +//################# AudioControlsButtonMessageWatcher ################### +//############################################################################# + +// +//############################################################################# +//############################################################################# +// +AudioControlsButtonMessageWatcher::AudioControlsButtonMessageWatcher( + PlugStream *stream, + Entity *entity +): + AudioMessageWatcher(stream, entity) +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioControlsButtonMessageWatcher::~AudioControlsButtonMessageWatcher() +{ +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioControlsButtonMessageWatcher::DoesMessageMatch( + Receiver::Message *message + ) +{ + Check(this); + Check(message); + + ReceiverDataMessageOf *controls_button_message = + Cast_Object( + ReceiverDataMessageOf*, + message + ); + Check(controls_button_message); + + return (controls_button_message->dataContents > 0); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioControlSend::~AudioControlSend() +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioControlSend::AudioControlSend( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream) +{ + AudioComponent *audio_component; + AudioControlID control_ID; + AudioControlValue control_value; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + MemoryStream_Read(stream, &control_ID); + MemoryStream_Read(stream, &control_value); + + if (getenv("BT_ATTRBIND_LOG")) { static int s_sd=0; if (s_sd++<80) + DEBUG_STREAM << "[sendcfg] tgt=" << (void*)audio_component + << " ctl=" << (int)control_ID << "/" << control_value + << " entity=" << (void*)entity << "\n" << flush; } + + Check(entity); + entity->AddAudioComponent(this); + + Check(audio_component); + #if 1 + audio_component->ReceiveControl(control_ID, control_value); + #else + audio_component->PostReceiveControl(control_ID, control_value); + #endif +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSend::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Store fields + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, control_value); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSend::ReceiveControl( + AudioControlID, + AudioControlValue + ) +{ +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSplitter ~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioControlSplitter::AudioControlSplitter( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + int i, number_of_entries; + + MemoryStream_Read(stream, &number_of_entries); + for (i = 0; i < number_of_entries; i++) + { + AudioComponent *audio_component; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + } + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +AudioControlSplitter::~AudioControlSplitter() +{ +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSplitter::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Count number of entries + // + int number_of_entries = 0; + NameList::Entry *entry; + + Check(name_list); + entry = name_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->IsName("audio_component")) + number_of_entries++; + entry = entry->GetNextEntry(); + } + + // + // Store entries + // + MemoryStream_Write(stream, &number_of_entries); + + Check(name_list); + entry = name_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->IsName("audio_component")) + { + CString object_name; + ObjectID object_ID; + + Check_Pointer(entry->GetChar()); + object_name = entry->GetChar(); + + Check(stream); + object_ID = stream->FindObjectID(object_name); + if (object_ID == NullObjectID) + { + cout << "AudioControlSplitter::BuildFromPage - object_name == "; + cout << object_name << "\n"; + Fail("AudioControlSplitter::BuildFromPage - object_ID == NullObjectID"); + } + Verify(object_ID != NullObjectID); + MemoryStream_Write(stream, &object_ID); + } + entry = entry->GetNextEntry(); + } +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioControlSplitter::TestInstance() const +{ + AudioComponent::TestInstance(); + Check(&audioComponentSocket); + return True; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSplitter::ReceiveControl( + AudioControlID control_ID, + AudioControlValue control_value + ) +{ + Check(this); + + // + // Send to all of the components in the socket + // + SChainIteratorOf iterator(&audioComponentSocket); + AudioComponent *audio_component; + + Check(&iterator); + while ((audio_component = iterator.ReadAndNext()) != NULL) + { + Check(audio_component); + if (getenv("BT_AUDIO_SPATIAL")) { static int s_sp2=0; if (s_sp2++<200) + DEBUG_STREAM << "[split] " << (void*)this << " -> tgt=" << (void*)audio_component + << " ctl=" << (int)control_ID << "/" << control_value << "\n" << flush; } + audio_component->ReceiveControl(control_ID, control_value); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlMixer ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioControlMixer::~AudioControlMixer() +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioControlMixer::AudioControlMixer( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + AudioComponent *audio_component; + AudioControlID first_input_control_ID; + AudioControlID last_input_control_ID; + AudioControlID output_control_ID; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + MemoryStream_Read(stream, &first_input_control_ID); + MemoryStream_Read(stream, &last_input_control_ID); + MemoryStream_Read(stream, &output_control_ID); + + AudioControlMixerX( + audio_component, + entity, + first_input_control_ID, + last_input_control_ID, + output_control_ID + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMixer::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Store fields + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, first_input_control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, last_input_control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, output_control_ID); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMixer::AudioControlMixerX( + AudioComponent *audio_component, + Entity *entity, + AudioControlID first_input_control_ID, + AudioControlID last_input_control_ID, + AudioControlID output_control_ID + ) +{ + // + // Set up the control mix parameters + // + firstInputControlID = first_input_control_ID; + outputControlID = output_control_ID; + + Verify(last_input_control_ID > first_input_control_ID); + numberOfInputs = last_input_control_ID - first_input_control_ID + 1; + Verify(numberOfInputs <= AUDIO_CONTROL_MIXER_MAX_CONTROLS); + + for (int i = 0; i < numberOfInputs; i++) + { + Verify(i >= 0 && i < AUDIO_CONTROL_MIXER_MAX_CONTROLS); + controlValueArray[i] = 0.0f; + } + + // + // Remember the audio component to mix to and add this + // component to the entity + // + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioControlMixer::TestInstance() const +{ + AudioComponent::TestInstance(); + Check(&audioComponentSocket); + return True; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMixer::ReceiveControl( + AudioControlID control_ID, + AudioControlValue control_value + ) +{ + Check(this); + + // + // Index the controller into the mix table + // + int index = control_ID - firstInputControlID; + + if (index >= 0 && index < numberOfInputs) + { + // + // Set the control value + // + Verify(index >= 0 && index < AUDIO_CONTROL_MIXER_MAX_CONTROLS); + controlValueArray[index] = control_value; + + // + // Mix the new control value + // + AudioControlValue mixed_value = 0.0f; + + for (int i = 0; i < numberOfInputs; i++) + { + Verify(i >= 0 && i < AUDIO_CONTROL_MIXER_MAX_CONTROLS); + mixed_value += controlValueArray[i]; + } + + Check(audioComponentSocket.GetCurrent()); + if (getenv("BT_AUDIO_SPATIAL")) { static int s_mix=0; if (s_mix++<80) + DEBUG_STREAM << "[mix] mixer=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent() + << " outCtl=" << (int)outputControlID << " in[" << index << "]=" << control_value + << " sum=" << mixed_value << "\n" << flush; } + audioComponentSocket.GetCurrent()->ReceiveControl( + outputControlID, + mixed_value + ); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlMultiplier ~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioControlMultiplier::~AudioControlMultiplier() +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioControlMultiplier::AudioControlMultiplier( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + AudioComponent *audio_component; + AudioControlID first_input_control_ID; + AudioControlID last_input_control_ID; + AudioControlID output_control_ID; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + MemoryStream_Read(stream, &first_input_control_ID); + MemoryStream_Read(stream, &last_input_control_ID); + MemoryStream_Read(stream, &output_control_ID); + + AudioControlMultiplierX( + audio_component, + entity, + first_input_control_ID, + last_input_control_ID, + output_control_ID + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMultiplier::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Store fields + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, first_input_control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, last_input_control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, output_control_ID); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMultiplier::AudioControlMultiplierX( + AudioComponent *audio_component, + Entity *entity, + AudioControlID first_input_control_ID, + AudioControlID last_input_control_ID, + AudioControlID output_control_ID + ) +{ + // + // Set up the control mix parameters + // + firstInputControlID = first_input_control_ID; + outputControlID = output_control_ID; + + Verify(last_input_control_ID > first_input_control_ID); + numberOfInputs = last_input_control_ID - first_input_control_ID + 1; + Verify(numberOfInputs <= AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS); + + for (int i = 0; i < numberOfInputs; i++) + { + Verify(i >= 0 && i < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS); + controlValueArray[i] = 1.0f; + } + + // + // Remember the audio component to mix to and add this + // component to the entity + // + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioControlMultiplier::TestInstance() const +{ + AudioComponent::TestInstance(); + Check(&audioComponentSocket); + return True; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlMultiplier::ReceiveControl( + AudioControlID control_ID, + AudioControlValue control_value + ) +{ + Check(this); + + // + // Index the controller into the mix table + // + int index = control_ID - firstInputControlID; + + if (index >= 0 && index < numberOfInputs) + { + // + // Set the control value + // + Verify(index >= 0 && index < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS); + controlValueArray[index] = control_value; + + // + // Multiply the new control value + // + AudioControlValue mult_value = 1.0f; + + for (int i = 0; i < numberOfInputs; i++) + { + Verify(i >= 0 && i < AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS); + mult_value *= controlValueArray[i]; + } + + Check(audioComponentSocket.GetCurrent()); + if (getenv("BT_AUDIO_SPATIAL") && mult_value <= 0.0f) { static int s_mx=0; if (s_mx++<300) + DEBUG_STREAM << "[mult0] mult=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent() + << " in[" << index << "]=" << control_value << " product=" << mult_value << "\n" << flush; } + audioComponentSocket.GetCurrent()->ReceiveControl( + outputControlID, + mult_value + ); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSmoother ~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioControlSmoother::~AudioControlSmoother() +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioControlSmoother::AudioControlSmoother( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + // + // Get audio component + // + AudioComponent *audio_component; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + + // + // Get audio control id, sample size, and initial fill value + // + size_t number_of_samples; + AudioControlValue initial_fill_value; + AudioControlID control_ID; + + MemoryStream_Read(stream, &control_ID); + MemoryStream_Read(stream, &number_of_samples); + MemoryStream_Read(stream, &initial_fill_value); + audioControlAverage.SetSize(number_of_samples, initial_fill_value); + + if (getenv("BT_ATTRBIND_LOG")) { static int s_sm=0; if (s_sm++<40) + DEBUG_STREAM << "[smoothcfg] this=" << (void*)this << " ctlID=" << (int)control_ID + << " samples=" << (int)number_of_samples << " fill=" << initial_fill_value + << "\n" << flush; } + + AudioControlSmootherX( + audio_component, + entity, + control_ID + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSmoother::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Store audio component + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + // + // Store audio control id, sample size, and initial fill value + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, size_t, number_of_samples); + + AudioControlValue initial_fill_value = 0.0f; + if (name_list->FindData("initial_fill_value") != NULL) + { + Check_Pointer(name_list->FindData("initial_fill_value")); + Convert_From_Ascii( + (const char *)name_list->FindData("initial_fill_value"), + &initial_fill_value + ); + } + MemoryStream_Write(stream, &initial_fill_value); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSmoother::AudioControlSmootherX( + AudioComponent *audio_component, + Entity *entity, + AudioControlID control_ID + ) +{ + controlID = control_ID; + + // + // Remember the audio component and add this + // component to the entity + // + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioControlSmoother::TestInstance() const +{ + AudioComponent::TestInstance(); + Check(&audioComponentSocket); + Check(&audioControlAverage); + return True; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioControlSmoother::ReceiveControl( + AudioControlID control_ID, + AudioControlValue control_value + ) +{ + Check(this); + + if (control_ID == controlID) + { + audioControlAverage.Add(control_value); + + + Check(audioComponentSocket.GetCurrent()); + audioComponentSocket.GetCurrent()->ReceiveControl( + controlID, + audioControlAverage.CalculateOlympicAverage() + ); + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResourceSelector ~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioResourceSelector::~AudioResourceSelector() +{ +} + +// +//############################################################################# +//############################################################################# +// +AudioResourceSelector::AudioResourceSelector( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioSourceSocket(NULL) +{ + AudioSource *audio_source; + AudioResourceIndex *audio_resource_index; + AudioControlID control_ID; + AudioControlValue min_control_value; + AudioControlValue max_control_value; + Logical dump_value; + + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_source); + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource_index); + MemoryStream_Read(stream, &control_ID); + MemoryStream_Read(stream, &min_control_value); + MemoryStream_Read(stream, &max_control_value); + MemoryStream_Read(stream, &dump_value); + + AudioResourceSelectorX( + audio_source, + entity, + audio_resource_index, + control_ID, + min_control_value, + max_control_value, + dump_value + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioResourceSelector::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // Store fields + // + CString audio_source_name("audio_source"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_source_name); + + CString audio_resource_index_name("audio_resource_index"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_resource_index_name); + + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, min_control_value); + MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, max_control_value); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioResourceSelector::AudioResourceSelectorX( + AudioSource *audio_source, + Entity *entity, + AudioResourceIndex *audio_resource_index, + AudioControlID control_ID, + AudioControlValue min_control_value, + AudioControlValue max_control_value, + Logical dump_value + ) +{ + controlID = control_ID; + minControlValue = min_control_value; + maxControlValue = max_control_value; + dumpValue = dump_value; + + Check(audio_resource_index); + audioResourceIndex = audio_resource_index; + + Check(audio_source); + audioSourceSocket.Add(audio_source); + audio_source->AddWatcher(this); + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +Logical + AudioResourceSelector::TestInstance() const +{ + AudioComponent::TestInstance(); + Check(&audioSourceSocket); + Check(audioResourceIndex); + return True; +} + +// +//############################################################################# +//############################################################################# +// +void + AudioResourceSelector::ReceiveControl( + AudioControlID control_ID, + AudioControlValue control_value + ) +{ + Check(this); + + if (control_ID == controlID) + { + AudioComponent *audio_component; + AudioSource *audio_source; + + audio_component = audioSourceSocket.GetCurrent(); + audio_source = Cast_Object(AudioSource*, audio_component); + Check(audio_source); + + if (audio_source->GetAudioSourceState() == StoppedAudioSourceState) + { + AudioResource *audio_resource; + int index; + + Clamp(control_value, minControlValue, maxControlValue); + Verify(!Small_Enough(maxControlValue - minControlValue)); + + index = + ( ((Scalar)audioResourceIndex->GetSize()-1.0f) * + (control_value - minControlValue) / + (maxControlValue - minControlValue) ) + 0.5f; + #if DEBUG_LEVEL>0 + if (!(index >= 0 && index < audioResourceIndex->GetSize())) + { + Dump(control_value); + Dump(index); + Dump(audioResourceIndex->GetSize()); + } + #endif + Verify(index >= 0 && index < audioResourceIndex->GetSize()); + + #if DEBUG_LEVEL>0 + if (dumpValue) + { + Tell("index:" << index); + Tell("; size: " << audioResourceIndex->GetSize() << "\n"); + } + #endif + + audio_resource = audioResourceIndex->GetAudioResource(index); + Check(audio_resource); + audio_source->SetAudioResource(audio_resource); + } + } +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSampleAndHold ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioSampleAndHold::AudioSampleAndHold( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + AudioComponent *audio_component; + AudioControlID control_ID; + Scalar seconds; + AudioTime sample_duration; + Scalar min_value; + Scalar max_value; + + // + // audio_component + // + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + + // + // control_ID, sample_duration + // + MemoryStream_Read(stream, &control_ID); + MemoryStream_Read(stream, &seconds); + sample_duration = seconds; + + // + // min_value, max_value + // + MemoryStream_Read(stream, &min_value); + MemoryStream_Read(stream, &max_value); + + AudioSampleAndHoldX( + audio_component, + entity, + control_ID, + sample_duration, + min_value, + max_value + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioSampleAndHold::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // audio_component + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + // + // control_ID, sample_duration + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, sample_duration); + + // + // min_value, max_value + // + Scalar min_value = 0.0f; + Scalar max_value = 1.0f; + + if (name_list->FindData("min_value") != NULL) + { + Convert_From_Ascii( + (const char *)name_list->FindData("min_value"), + &min_value + ); + } + if (name_list->FindData("max_value") != NULL) + { + Convert_From_Ascii( + (const char *)name_list->FindData("max_value"), + &max_value + ); + } + Verify(max_value > min_value); + MemoryStream_Write(stream, &min_value); + MemoryStream_Write(stream, &max_value); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioSampleAndHold::AudioSampleAndHoldX( + AudioComponent *audio_component, + Entity *entity, + AudioControlID audio_control_ID, + const AudioTime &sample_duration, + Scalar min_value, + Scalar max_value + ) +{ + audioControlID = audio_control_ID; + currentValue = 0.0f; + nextSampleTime = AudioTime::Now(); + sampleDuration = sample_duration; + Verify(max_value > min_value); + minValue = min_value; + maxValue = max_value; + + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +AudioSampleAndHold::~AudioSampleAndHold() +{ +} + +// +//############################################################################# +//############################################################################# +// +void + AudioSampleAndHold::Execute() +{ + Check(this); + + AudioComponent::Execute(); + + if (AudioTime::Now() > nextSampleTime) + { + SampleAndHold(); + } +} + +// +//############################################################################# +//############################################################################# +// +void + AudioSampleAndHold::ReceiveControl( + AudioControlID control_ID, + AudioControlValue + ) +{ + Check(this); + + if (control_ID == StartAudioControlID) + { + SampleAndHold(); + } +} + +// +//############################################################################# +//############################################################################# +// +void + AudioSampleAndHold::SampleAndHold() +{ + Check(this); + + Scalar random_sample = Random; + + Verify(0.0f <= random_sample && random_sample <= 1.0f); + Verify(maxValue > minValue); + currentValue = minValue + random_sample * (maxValue - minValue); + + nextSampleTime = AudioTime::Now(); + nextSampleTime += sampleDuration; + + Check(audioComponentSocket.GetCurrent()); + if (getenv("BT_AUDIO_SPATIAL")) { static int s_sh=0; if (s_sh++<60) + DEBUG_STREAM << "[snh] this=" << (void*)this << " -> tgt=" << (void*)audioComponentSocket.GetCurrent() + << " ctlID=" << (int)audioControlID << " val=" << currentValue + << " range=[" << minValue << "," << maxValue << "]\n" << flush; } + audioComponentSocket.GetCurrent()->ReceiveControl( + audioControlID, + currentValue + ); +} + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLFO ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +// +//############################################################################# +//############################################################################# +// +AudioLFO::AudioLFO( + PlugStream *stream, + Entity *entity +): + AudioComponent(stream), + audioComponentSocket(NULL) +{ + AudioComponent *audio_component; + AudioControlID control_ID; + AudioLFOWaveForm wave_form; + Scalar the_period; + AudioControlValue min_value; + AudioControlValue max_value; + Logical dump_value; + + // + // audio_component + // + PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component); + + // + // control_ID, wave_form, period + // + MemoryStream_Read(stream, &control_ID); + MemoryStream_Read(stream, &wave_form); + MemoryStream_Read(stream, &the_period); + + // + // min_value, max_value, dump_value + // + MemoryStream_Read(stream, &min_value); + MemoryStream_Read(stream, &max_value); + MemoryStream_Read(stream, &dump_value); + + AudioLFOX( + audio_component, + entity, + control_ID, + wave_form, + the_period, + min_value, + max_value, + dump_value + ); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioLFO::BuildFromPage( + PlugStream *stream, + NameList *name_list, + ClassID class_ID, + ObjectID object_ID + ) +{ + AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID); + + // + // audio_component + // + CString audio_component_name("audio_component"); + PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name); + + // + // control_ID, wave_form, period + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, control_ID); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, wave_form); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, period); + + // + // min_value, max_value + // + MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, min_value); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, max_value); + MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioLFO::AudioLFOX( + AudioComponent *audio_component, + Entity *entity, + AudioControlID audio_control_ID, + AudioLFOWaveForm wave_form, + Scalar the_period, + AudioControlValue min_value, + AudioControlValue max_value, + Logical dump_value + ) +{ + Check(audio_component); + audioComponentSocket.Add(audio_component); + audio_component->AddWatcher(this); + + audioControlID = audio_control_ID; + waveForm = wave_form; + minValue = min_value; + maxValue = max_value; + Verify(max_value > min_value); + + period = the_period; + startTime = AudioTime::Now(); + + dumpValue = dump_value; + + Check(entity); + entity->AddAudioComponent(this); +} + +// +//############################################################################# +//############################################################################# +// +AudioLFO::~AudioLFO() +{ +} + +// +//############################################################################# +//############################################################################# +// +void + AudioLFO::Execute() +{ + Check(this); + AudioComponent::Execute(); + Generate(); +} + +// +//############################################################################# +//############################################################################# +// +void + AudioLFO::ReceiveControl( + AudioControlID control_ID, + AudioControlValue + ) +{ + Check(this); + if (control_ID == StartAudioControlID) + { + Generate(); + } +} + +// +//############################################################################# +//############################################################################# +// +void + AudioLFO::Generate() +{ + Check(this); + + // + // HACK - For now, everything is sinusoidal + // + // res = sin( (now-start) * (PI/period) ) + // val = min + ( 0.5 * (res+1) ) * (max - min) + // + Scalar time_factor; + Scalar sample; + Scalar current_value; + + time_factor = AudioTime::Now(); + Verify(!Small_Enough((Scalar)period)); + time_factor = (time_factor - (Scalar)startTime) / (Scalar)period; + + sample = (sin(time_factor * PI) + 1.0f) * 0.5f; + Verify(0.0f <= sample && sample <= 1.0f); + Verify(maxValue > minValue); + current_value = minValue + sample * (maxValue - minValue); + + #if DEBUG_LEVEL>0 + if (dumpValue) + { + Dump(current_value); + } + #endif + + Check(audioComponentSocket.GetCurrent()); + audioComponentSocket.GetCurrent()->ReceiveControl( + audioControlID, + current_value + ); +} diff --git a/restoration/source410/MUNGA/AUDREND.CPP b/restoration/source410/MUNGA/AUDREND.CPP new file mode 100644 index 00000000..b3742288 --- /dev/null +++ b/restoration/source410/MUNGA/AUDREND.CPP @@ -0,0 +1,540 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(AUDREND_HPP) +# include +# endif +# if !defined(AUDENT_HPP) +# include +# endif +# if !defined(JMOVER_HPP) +# include +# endif +# if !defined(APP_HPP) +# include +# 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; +} diff --git a/restoration/source410/MUNGA/AUDREND.HPP b/restoration/source410/MUNGA/AUDREND.HPP index 310b3a67..939bde99 100644 --- a/restoration/source410/MUNGA/AUDREND.HPP +++ b/restoration/source410/MUNGA/AUDREND.HPP @@ -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(); diff --git a/restoration/source410/MUNGA/BOXTREE.HPP b/restoration/source410/MUNGA/BOXTREE.HPP index f28e43d0..e6667c21 100644 --- a/restoration/source410/MUNGA/BOXTREE.HPP +++ b/restoration/source410/MUNGA/BOXTREE.HPP @@ -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 diff --git a/restoration/source410/MUNGA/CSTR.CPP b/restoration/source410/MUNGA/CSTR.CPP new file mode 100644 index 00000000..6ceb77cb --- /dev/null +++ b/restoration/source410/MUNGA/CSTR.CPP @@ -0,0 +1,450 @@ +# if !defined(MUNGA_HPP) +# include +# endif +# if !defined(CSTR_HPP) +# include +# endif +# if !defined(MEMSTRM_HPP) +# include +# 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 + diff --git a/restoration/source410/MUNGA/EXPTBL.CPP b/restoration/source410/MUNGA/EXPTBL.CPP new file mode 100644 index 00000000..c4ce9792 --- /dev/null +++ b/restoration/source410/MUNGA/EXPTBL.CPP @@ -0,0 +1,625 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(EXPTBL_HPP) +# include +# endif +# if !defined(NAMELIST_HPP) +# include +# endif +# if !defined(REGISTRY_HPP) +# include +# endif +# if !defined(APP_HPP) +# include +# endif +# if !defined(EXPLODE_HPP) +# include +# endif +# if !defined(DAMAGE_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# endif +# if !defined(FILEUTIL_HPP) +# include +# endif +# if !defined(RENDERER_HPP) +# include +# 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 <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(NULL, True) +{ + int entry_count; + *exp_stream >> entry_count; + + // + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Create all of the ExplosionTableEntries + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // + ExplosionTableEntry *exp_entry; + + for(int ii=0;iiMakePageList(); + Register_Object(exp_namelist); + if (!exp_namelist->EntryCount()) + { + DEBUG_STREAM << exp_file << " is empty or missing \n"<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;iidamageZoneCount;++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;iidamageZoneCount; ++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; +} diff --git a/restoration/source410/MUNGA/FILEUTIL.CPP b/restoration/source410/MUNGA/FILEUTIL.CPP new file mode 100644 index 00000000..2a592960 --- /dev/null +++ b/restoration/source410/MUNGA/FILEUTIL.CPP @@ -0,0 +1,832 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +#include + +#include +# if !defined(FILEUTIL_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# 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; +} + +//============================================================================= diff --git a/restoration/source410/MUNGA/GAUGE.CPP b/restoration/source410/MUNGA/GAUGE.CPP new file mode 100644 index 00000000..84d951f0 --- /dev/null +++ b/restoration/source410/MUNGA/GAUGE.CPP @@ -0,0 +1,827 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(GAUGE_HPP) +# include +# endif +# if !defined(GAUGREND_HPP) +# include +# 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 + 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 + 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 + 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 + 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 + 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 diff --git a/restoration/source410/MUNGA/GAUGMAP.CPP b/restoration/source410/MUNGA/GAUGMAP.CPP new file mode 100644 index 00000000..5179415b --- /dev/null +++ b/restoration/source410/MUNGA/GAUGMAP.CPP @@ -0,0 +1,744 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(GAUGMAP_HPP) +# include +# endif +# if !defined(POINT3D_HPP) +# include +# endif +# if !defined(ENTITY_HPP) +# include +# 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 + 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 + i(instanceList); + + Check_Fpu(); + return i.GetSize(); +} + +//============================================================================ +// Clear +//============================================================================ +void + GaugeEntityList::Clear() +{ +// Test_Tell("GaugeEntityList::Clear()\n"); + Check(this); + + ChainIteratorOf + 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 + 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 + 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 = 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>1); + + if (q < 0) + { + q = 0; + } + if (q >= gaugeMapArraySize) + { + q = (gaugeMapArraySize-1); + } + + Check_Fpu(); + return q; +} diff --git a/restoration/source410/MUNGA/GAUGREND.CPP b/restoration/source410/MUNGA/GAUGREND.CPP new file mode 100644 index 00000000..b17805cf --- /dev/null +++ b/restoration/source410/MUNGA/GAUGREND.CPP @@ -0,0 +1,4336 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(GAUGREND_HPP) +# include +# endif +# if !defined(LAMP_HPP) +# include +# endif +# if !defined(MOVER_HPP) +# include +# endif +# if !defined(TERRAIN_HPP) +# include +# endif +# if !defined(APP_HPP) +# include +# endif +# if !defined(HOSTMGR_HPP) +# include +# endif + +// #define LOCAL_TEST + +#if defined(LOCAL_TEST) +# define Test_Tell(n) DEBUG_STREAM << n +#else +# define Test_Tell(n) +#endif + + #define PROFILE_GAUGES + +#if defined(TRACE_GAUGE_RENDERER) + BitTrace Gauge_Renderer("Gauge Renderer"); +#endif + +//####################################################################### +// Miscellaneous utilities +//####################################################################### +int + LookupTable::Search(const char *string) +{ + Check_Pointer(this); + Verify(string != NULL); + + LookupTable + *table = this; + + for(; table->typeString!=NULL; ++table) + { + if (stricmp(string, table->typeString) == 0) + { + break; + } + } + Check_Fpu(); + return table->value; +} + + +//####################################################################### +// GaugeSymbol +//####################################################################### + +GaugeSymbol::GaugeSymbol( + GaugeSymbol **head_pointer, + const char *new_label, + GaugeInterpreterOffset new_offset, + Logical new_resolved +) +{ + Check(this); + Check_Pointer(head_pointer); + Check_Pointer(new_label); + Test_Tell( + "GaugeSymbol::GaugeSymbol(" << head_pointer << + "," << new_label << + "," << new_offset << + "," << new_resolved << + ")\n" + ); + + nextSymbol = *head_pointer; + *head_pointer = this; + + Str_Copy(label, new_label, sizeof(label)); + offset = new_offset; + resolved = new_resolved; + Check_Fpu(); +} + +GaugeSymbol::~GaugeSymbol() +{ + Check(this); + Check_Fpu(); +} + +Logical + GaugeSymbol::TestInstance() const +{ + return True; +} + +//####################################################################### +// GaugeSymbolTable +//####################################################################### +GaugeSymbolTable::GaugeSymbolTable(char *table_pointer) +{ + Test_Tell( + "GaugeSymbolTable::GaugeSymbolTable(" << ((void *) table_pointer) << + ")\n" + ); + Check_Pointer(this); + + head = NULL; + tablePointer = table_pointer; + Check_Fpu(); +} + +GaugeSymbolTable::~GaugeSymbolTable() +{ + Test_Tell( + "GaugeSymbolTable::~GaugeSymbolTable()\n" + ); + Check(this); + + GaugeSymbol + *symbol, + *next_symbol; + + for(symbol=head; symbol!=NULL; symbol=next_symbol) + { + Check(symbol); + + next_symbol = symbol->nextSymbol; + Unregister_Object(symbol); + delete symbol; + } + head = NULL; + Check_Fpu(); +} + +Logical + GaugeSymbolTable::TestInstance() const +{ + return True; +} + +void + GaugeSymbolTable::Add(const char *label, GaugeInterpreterOffset new_offset) +{ + Check(this); + Check_Pointer(label); + + Test_Tell( + "GaugeSymbolTable::Add(" << label << + "," << new_offset << + ")\n" + ); + + GaugeSymbol + *symbol; + + //------------------------------------------------- + // Check to see if this label already exists + //------------------------------------------------- + for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) + { + Check(symbol); + + if (stricmp(label, symbol->label) == 0) + { + Test_Tell("Exists.\n"); + //------------------------------------------------- + // It DOES exist. Has it already been resolved? + //------------------------------------------------- + if (!symbol->resolved) + { + Test_Tell("Unresolved.\n"); + //------------------------------------------------- + // No, resolve all forward references to it + //------------------------------------------------- + // Forward references (references to undefined + // labels) are saved as a singly-linked list + // of offsets within the table itself: each + // reference to the label contains an offset to + // the previous reference. The list is + // terminated by an offset of -1. + //------------------------------------------------- + GaugeInterpreterOffset + table_offset, + next_offset, + *offset_pointer; + + for ( + table_offset=symbol->offset; + table_offset>=0; + table_offset = next_offset) + { + Test_Tell("Resolving " << table_offset << "\n"); + + offset_pointer = + (GaugeInterpreterOffset *) &tablePointer[table_offset]; + + next_offset = *offset_pointer; + *offset_pointer = (GaugeInterpreterOffset) new_offset; + } + symbol->offset = new_offset; + symbol->resolved = True; + Test_Tell("Done!\n"); + Check_Fpu(); + return; + } + else + { + Test_Tell("Resolved?!?!?.\n"); + //------------------------------------------------- + // Yes, this is an error. Throw a fit. + //------------------------------------------------- + DEBUG_STREAM << "label =" << label << "\n" << flush; + Fail("Already resolved"); + } + } + } + //------------------------------------------------- + // This is a new, resolved definition: just add it + //------------------------------------------------- + Test_Tell("New.\n"); +# if DEBUG_LEVEL > 0 + symbol = new GaugeSymbol(&head, label, new_offset, True); + Check(symbol); + Register_Object(symbol); +# else + new GaugeSymbol(&head, label, new_offset, True); +# endif + Check_Fpu(); +} + +GaugeInterpreterOffset + GaugeSymbolTable::Refer( + const char *label, + GaugeInterpreterOffset new_offset + ) +{ + Check(this); + Check_Pointer(label); + + Test_Tell( + "GaugeSymbolTable::Refer(" << label << + "," << new_offset << + ")\n" + ); + + GaugeSymbol + *symbol; + + //------------------------------------------------- + // Check to see if this label already exists + //------------------------------------------------- + for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) + { + Check(symbol); + + if (stricmp(label, symbol->label) == 0) + { + Test_Tell("Exists.\n"); + //------------------------------------------------- + // It DOES exist. Is it resolved? + //------------------------------------------------- + if (symbol->resolved) + { + Test_Tell("Resolved.\n"); + //------------------------------------------------- + // Yes, return the value. + //------------------------------------------------- + Check_Fpu(); + return symbol->offset; + } + else + { + Test_Tell("Unresolved.\n"); + //------------------------------------------------- + // No, add to the list of forward references. + //------------------------------------------------- + GaugeInterpreterOffset + previous_offset = symbol->offset; + + Test_Tell("Returning previous " << previous_offset << ".\n"); + symbol->offset = new_offset; + Check_Fpu(); + return previous_offset; + } + } + } + //------------------------------------------------- + // This is a new forward reference. + // A (-1) is returned to mark the end of + // the reference chain. + // + // IT IS NOT AN ERROR! + //------------------------------------------------- + Test_Tell("New.\n"); +# if DEBUG_LEVEL > 0 + symbol = new GaugeSymbol(&head, label, new_offset, False); + Check(symbol); + Register_Object(symbol); +# else + new GaugeSymbol(&head, label, new_offset, False); +# endif + Check_Fpu(); + return -1; +} + +GaugeInterpreterOffset + GaugeSymbolTable::Get(const char *label) +{ + Test_Tell( + "GaugeSymbolTable::Get(" << label << + ")\n" + ); + Check(this); + Check_Pointer(label); + + GaugeSymbol + *symbol; + + //------------------------------------------------- + // Check to see if this label exists + //------------------------------------------------- + for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) + { + Check(symbol); + + if (stricmp(label, symbol->label) == 0) + { + Test_Tell("Exists.\n"); + //------------------------------------------------- + // It DOES exist. Is it resolved? + //------------------------------------------------- + if (symbol->resolved) + { + Test_Tell("Resolved.\n"); + //------------------------------------------------- + // Yes, return the value. + //------------------------------------------------- + Check_Fpu(); + return symbol->offset; + } + else + { + Test_Tell("Unresolved (error).\n"); + //------------------------------------------------- + // Return error. + //------------------------------------------------- + Check_Fpu(); + return errUnresolvedForwardReference; + } + } + } + //------------------------------------------------- + // Undefined, return error. + //------------------------------------------------- + Test_Tell("Undefined (error).\n"); + Check_Fpu(); + return errUndefinedSymbol; +} + +const char * + GaugeSymbolTable::LabelFromValue(GaugeInterpreterOffset value) +{ +# if defined SHOW_EVERYTHING + Test_Tell( + "GaugeSymbolTable::LabelFromValue(" << value << + ")\n" + ); +# endif + Check(this); + + GaugeSymbol + *symbol; + + //------------------------------------------------- + // Check to see if this label exists + //------------------------------------------------- + for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) + { + Check(symbol); + + if (symbol->offset == value) + { + //------------------------------------------------- + // It DOES exist. Is it resolved? + //------------------------------------------------- + if (symbol->resolved) + { + //------------------------------------------------- + // Yes, return the value. + //------------------------------------------------- + Check_Fpu(); + return symbol->label; + } + else + { + //------------------------------------------------- + // Return error. + //------------------------------------------------- + Check_Fpu(); + return NULL; + } + } + } + //------------------------------------------------- + // Undefined, return error. + //------------------------------------------------- + Check_Fpu(); + return NULL; +} + +Logical + GaugeSymbolTable::UnresolvedForwardReferences() +{ + Test_Tell( + "GaugeSymbolTable::UnresolvedForwardReferences()\n" + ); + Check(this); + + GaugeSymbol + *symbol; + + //------------------------------------------------- + // Check for unrersolved symbols + //------------------------------------------------- + for(symbol=head; symbol!=NULL; symbol=symbol->nextSymbol) + { + Test_Tell("Symbol '" << symbol->label << "' at " << symbol << "\n"); + Check(symbol); + + if (!symbol->resolved) + { + Test_Tell("Unresolved!\n"); + Check_Fpu(); + return True; + } + } + //------------------------------------------------- + // Everything is resolved! + //------------------------------------------------- + Test_Tell("All is resolved.\n"); + Check_Fpu(); + return False; +} + +//####################################################################### +// GaugeInterpreter +//####################################################################### +GaugeInterpreter::GaugeInterpreter() +{ + Test_Tell("GaugeInterpreter::GaugeInterpreter()\n"); + Check_Pointer(this); + //------------------------------------------------- + // Create interpreter table + //------------------------------------------------- + interpreterTable = new char[interpreterTableSize]; + Check_Pointer(interpreterTable); + Register_Pointer(interpreterTable); + //------------------------------------------------- + // Clear attribute variable array + //------------------------------------------------- + for (int i=0; i= sizeof(currentToken)) + { + Fail("Token too large"); + return NULL; + } + + if (c < 0) + { + if (char_pointer == currentToken) + { +# if defined(SHOW_EVERYTHING) + Test_Tell("EOF, NULL\n"); +# endif + return NULL; + } + else + { + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("EOF, token=<" << currentToken << ">\n"); +# endif + return currentToken; + } + } + + if (c == '\n') + { +# if defined(SHOW_EVERYTHING) + Test_Tell("newline\n"); +# endif + ++lineNumber; + } + + switch(parsingState) + { + case parsingWhiteSpace: + switch(c) + { + case ' ': + case '\t': + case '\r': + case '\n': + case '\0': + file.stossc(); // discard character + break; + + case '#': + file.stossc(); // discard character +# if defined(SHOW_EVERYTHING) + Test_Tell("start comment\n"); +# endif + parsingState = parsingComment; + break; + + default: +# if defined(SHOW_EVERYTHING) + Test_Tell("non-white\n"); +# endif + parsingState = parsingToken; + break; + } + break; + + case parsingToken: + switch(c) + { + default: + file.stossc(); // discard character + *char_pointer++ = (char) c; + break; + + case '"': + file.stossc(); // discard character + if (char_pointer == currentToken) + { +# if defined(SHOW_EVERYTHING) + Test_Tell("start string\n"); +# endif + parsingState = parsingString; + } + else + { + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("start string, token=<" << currentToken << ">\n"); +# endif + return currentToken; + } + break; + + case '{': + case '}': + case '(': + case ')': + case ',': + case '=': + case ';': + if (char_pointer == currentToken) + { + file.stossc(); // discard character + *char_pointer++ = (char) c; + } + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("punctuation, token=<" << currentToken << ">\n"); +# endif + return currentToken; + + case '#': + file.stossc(); // discard character +# if defined(SHOW_EVERYTHING) + Test_Tell("start comment\n"); +# endif + parsingState = parsingComment; + break; + + case ' ': + case '\t': + case '\r': + case '\n': + case '\0': + file.stossc(); // discard character + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("trailing white, token=<" << currentToken << ">\n"); +# endif + return currentToken; + } + break; + + case parsingComment: + file.stossc(); // discard character + switch(c) + { + case '\n': + case '\r': + if (char_pointer == currentToken) + { +# if defined(SHOW_EVERYTHING) + Test_Tell("end of comment\n"); +# endif + parsingState = parsingWhiteSpace; + } + else + { + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("end of comment, token=<" <\n"); +# endif + return currentToken; + } + break; + } + break; + + case parsingString: + file.stossc(); // discard character + if (c == '"') + { + *char_pointer = '\0'; +# if defined(SHOW_EVERYTHING) + Test_Tell("end of string, token=<" << currentToken << ">\n"); +# endif + return currentToken; + } + else + { + *char_pointer++ = (char) c; + } + break; + } + } + Fail("Unintended exit"); + Check_Fpu(); + return NULL; +} + +void + GaugeInterpreter::UngetPreviousToken() +{ + Check(this); + tokenNotTaken = True; + Check_Fpu(); +} + +Logical + GaugeInterpreter::GetInteger(int *int_pointer) +{ + Test_Tell( + "GaugeInterpreter::GetInteger(" << ((void *) int_pointer) << + ")..." + ); + Check(this); + Check_Pointer(int_pointer); + + const char + *token = GetToken(); + Check_Pointer(token); + Test_Tell("token=" << token << "..."); + + int + c, + value = 0; + Logical + result, + is_negative = False; + + if (*token == '-') + { + is_negative = True; + ++token; + } + + if (*token == '0') + { + ++token; + if (*token == '\0') + { + Test_Tell("found zero value\n"); + *int_pointer = 0; + return True; + } + } + + if (*token == 'x' || *token == 'X') + { + for(++token; *token != '\0'; ++token) + { + c = toupper(*token); + + if (!isxdigit(c)) + { + return False; + } + + if (c > '9') + { + c -= ('A'-':'); + } + value = (value << 4) + (c - '0'); + } + result = True; + } + else + { + for( ; *token != '\0'; ++token) + { + c = *token; + if (!isdigit(c)) + { + return False; + } + value = (value*10) + (c - '0'); + } + result = True; + } + + if (result == True) + { + if (is_negative) + { + value = - value; + } + Test_Tell("found value " << value << "\n"); + *int_pointer = value; + } +# if defined(LOCAL_TEST) + else + { + Test_Tell("FAILED\n"); + } +# endif + Check_Fpu(); + return result; +} + +Logical + GaugeInterpreter::GetScalar(Scalar *scalar_pointer) +{ + Test_Tell( + "GaugeInterpreter::GetScalar(" << ((void *) scalar_pointer) << + ")..." + ); + Check(this); + Check_Pointer(scalar_pointer); + + const char + *token = GetToken(); + Check_Pointer(token); + Test_Tell("token=" << token << "\n"); + + float // HACK - I don't know how to avoid an explicit 'float'... + value; + Logical + is_negative = False; + + if (*token == '-') + { + is_negative = True; + ++token; + } + + if (sscanf(token, "%f", &value) > 0) + { + Test_Tell("found " << value << "\n"); + + if (is_negative) + { + value = - value; + } + *scalar_pointer = (Scalar) value; + return True; + } + ReportParsingError("Token not a scalar value"); + Check_Fpu(); + return False; +} + +Logical + GaugeInterpreter::GetVector(Vector2DOf *vector) +{ + Test_Tell("GaugeInterpreter::GetVector(" << ((void *) vector) << ")..."); + Check(this); + Check_Pointer(vector); + + Vector2DOf + local_vector; + + if (strcmp(GetToken(), "(") != 0) + { + ReportParsingError("Missing leading '(' for 2D vector"); + return False; + } + if (!GetInteger(&local_vector.x)) + { + return False; + } + if (strcmp(GetToken(), ",") != 0) + { + ReportParsingError("Missing ',' for 2D vector"); + return False; + } + if (!GetInteger(&local_vector.y)) + { + return False; + } + if (strcmp(GetToken(), ")") != 0) + { + ReportParsingError("Missing trailing ')' for 2D vector"); + return False; + } + + *vector = local_vector; + Check_Fpu(); + return True; +} + +Logical + GaugeInterpreter::GetRate(GaugeRate *rate) +{ + Test_Tell("GaugeInterpreter::GetRate(" << ((void *) rate) << ")..."); + Check(this); + const char + *text = GetToken(); + Test_Tell("token='" << text << "'\n"); + Check_Pointer(text); + Check_Pointer(rate); + + int + c; + //----------------------------------------------- + // Get rate (A..P) + //----------------------------------------------- + c = *text; + if (!isalpha(c)) + { + ReportParsingError("Token is not a valid rate"); + } + else + { + c = toupper(c); + if ((c >= 'A') && (c <= 'Z')) + { + *rate = Gauge::ConvertIndexToRate(c -'A'); + Check_Fpu(); + return True; + } + else + { + ReportParsingError("Token is not a valid rate"); + } + } + Check_Fpu(); + return False; +} + +Logical + GaugeInterpreter::GetModeMask(ModeMask *mask_pointer) +{ + Test_Tell( + "GaugeInterpreter::GetLong(" << ((void *) mask_pointer) << + ")..." + ); + Check(this); + Check_Pointer(mask_pointer); + + const char + *token = GetToken(); + Check_Pointer(token); + Test_Tell("token=" << token << "..."); + + int + c; + ModeMask + value = (ModeMask) 0; + Logical + result = False, + is_negative = False; + + //------------------------------------------------------ + // Deal with negative sign here + //------------------------------------------------------ + if (*token == '-') + { + is_negative = True; + ++token; + } + + if (isalpha(*token)) + { + //------------------------------------------------------ + // Check for a named constant + //------------------------------------------------------ + Check(application); + Check(application->GetModeManager()); + + result = application->GetModeManager()->ModeStringLookup(token, &value); + } + else + { + //-------------------------------------------------------- + // Not a named constant. must be either number or an error + //-------------------------------------------------------- + if (*token == '0') + { + ++token; + result = True; // might be a single lonely zero (which is legit) + } + + if (*token == 'x' || *token == 'X') + { + //-------------------------------------------------------- + // Process hex value + //-------------------------------------------------------- + for(++token; *token != '\0'; ++token) + { + c = toupper(*token); + + if (!isxdigit(c)) + { + return False; + } + + if (c > '9') + { + c -= ('A'-':'); + } + value = (value << 4) + (ModeMask) (c - '0'); + } + result = True; + } + else + { + //-------------------------------------------------------- + // Process decimal value + //-------------------------------------------------------- + for( ; *token != '\0'; ++token) + { + c = *token; + if (!isdigit(c)) + { + Check_Fpu(); + return result; + } + value = (value*10) + (ModeMask) (c - '0'); + } + result = True; + } + } + + if (result == True) + { + if (is_negative) + { + value = - value; + } + Test_Tell("found value " << value << "\n"); + *mask_pointer = value; + } +# if defined(LOCAL_TEST) + else + { + Test_Tell("FAILED\n"); + } +# endif + Check_Fpu(); + return result; +} + +void + GaugeInterpreter::ReportParsingError( + const char *string + ) +{ + Check(this); + Check_Pointer(string); + + DEBUG_STREAM << + "Interpreter parsing error:" << string << + " in line " << lineNumber << + "\n"; + Fail("Parsing error"); +} + +void + GaugeInterpreter::Initialize( + const char *file_name, + MethodDescription **method_list, + Warehouse *warehouse_pointer + ) +{ + Check(this); + Check_Pointer(file_name); + Check_Pointer(method_list); + Check(warehouse_pointer); + //------------------------------------------------------------------------ + // Determine the number of primitives + //------------------------------------------------------------------------ + MethodDescription + *method_entry, + **list; + + primitiveCount = 0; + list = method_list; + while(list != NULL) + { + Check_Pointer(list); + method_entry = *list++; + Check_Pointer(method_entry); + if (method_entry->name == NULL) + { + //------------------------------------------------------------- + // Attempt to chain to next list: if NULL, we're done. + //------------------------------------------------------------- + list = method_entry->parameterList[0].data.nextMethodList; + } + else + { + //------------------------------------------------------------- + // Increment the primitive count + //------------------------------------------------------------- + ++primitiveCount; + } + } + //------------------------------------------------------------------------ + // Allocate the primitive table + //------------------------------------------------------------------------ + primitiveTable = new MethodDescription*[primitiveCount]; + Register_Pointer(primitiveTable); + //------------------------------------------------------------------------ + // Fill in the primitiveTable + //------------------------------------------------------------------------ + MethodDescription + **method_pointer = primitiveTable; + + list = method_list; + while(list != NULL) + { + Check_Pointer(list); + method_entry = *list++; + Check_Pointer(method_entry); + if (method_entry->name == NULL) + { + //------------------------------------------------------------- + // Attempt to chain to next list: if NULL, we're done. + //------------------------------------------------------------- + list = method_entry->parameterList[0].data.nextMethodList; + } + else + { + //------------------------------------------------------------- + // Save a pointer to the method description + //------------------------------------------------------------- + Verify((method_pointer-primitiveTable) < primitiveCount); + *(method_pointer++) = method_entry; + } + } + //------------------------------------------------------------------------ + // Parse the text file to build the interpreter table + //------------------------------------------------------------------------ + file.open(file_name, ios::in|ios::nocreate, filebuf::openprot); + + if (!file.is_open()) + { + DEBUG_STREAM << "Cannot open interpreter file '" << file_name << "'\n" << flush; + } + else + { + lineNumber = 1; + tokenNotTaken = False; + + const char + *name; + char + local_name[32]; + //---------------------------------------------------- + // Parse the statement: + // { } + //---------------------------------------------------- + // + + while((name = GetToken()) != NULL ) + { + Str_Copy(local_name, name, sizeof(local_name)); + + if (stricmp(GetToken(), "{") != 0) + { + ReportParsingError("Missing '{'"); + } + symbolTable->Add(local_name, currentOffset); + GetProcedureBody(method_list, warehouse_pointer); + } + if (symbolTable->UnresolvedForwardReferences()) + { + ReportParsingError("Unresolved forward references"); + } + file.close(); + + { + GaugeInterpreterCommand + command = endMarker; + Insert(&command, sizeof(GaugeInterpreterCommand)); +# if defined(LOCAL_TEST) + DumpTable(); +# endif + }; + } + //------------------------------------------------------------------------ + // All done! + //------------------------------------------------------------------------ + Check_Fpu(); +} + +void + GaugeInterpreter::GetProcedureBody( + MethodDescription **method_list, + Warehouse *warehouse_pointer + ) +{ + Check(this); + Check_Pointer(method_list); + Check(warehouse_pointer); + + int + running = 1; + GaugeInterpreterCommand + command; + const char + *name; + char + local_name[32]; + + while (running) + { + name = GetToken(); + if (name == NULL) + { + ReportParsingError("Internal error (NULL token)"); + } + + Str_Copy(local_name, name, sizeof(local_name)); + + if (stricmp(name, "}") == 0) + { + Test_Tell("End\n"); + command = returnCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + break; + } + else if (*name == '@') // example: @1 = ppc/reloadtime; + { + if (strlen(name) != 2) + { + ReportParsingError("Ill-formed attribute variable index"); + } + unsigned char + index = (unsigned char) ((*(name+1)) - '0'); + + if (index > maxVariableNameArrayIndex) + { + ReportParsingError("Illegal attribute variable index"); + } + + if (strcmp(GetToken(), "=") != 0) + { + ReportParsingError("Missing '='"); + } + Test_Tell("Attribute variable\n"); + command = attributeVariableCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + Insert(&index, sizeof(unsigned char)); + InsertString(GetToken()); + } + else if (stricmp(name, "enable") == 0) + { + if (strcmp(GetToken(), "=") != 0) + { + ReportParsingError("Missing '='"); + } + + ModeMask + mode_mask; + GetModeMask(&mode_mask); // fails to debugger if bad input + + Test_Tell("Enable\n"); + command = enableCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + Insert(&mode_mask, sizeof(ModeMask)); + } + else if (stricmp(name, "disable") == 0) + { + if (strcmp(GetToken(), "=") != 0) + { + ReportParsingError("Missing '='"); + } + + ModeMask + mode_mask; + GetModeMask(&mode_mask); // fails to debugger if bad input + + Test_Tell("Disable\n"); + command = disableCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + Insert(&mode_mask, sizeof(ModeMask)); + } + else if (stricmp(name, "offset") == 0) + { + if (strcmp(GetToken(), "=") != 0) + { + ReportParsingError("Missing '='"); + } + + Vector2DOf + offset; + + GetVector(&offset); // fails to debugger if input bad + + Test_Tell("offset\n"); + command = addOffsetCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + Insert(&offset, sizeof(Vector2DOf)); + } + else if (stricmp(name, "port") == 0) + { + if (strcmp(GetToken(), "=") != 0) + { + ReportParsingError("Missing '='"); + } + + command = setPortIndexCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + InsertString(GetToken()); + } + else // must be either call or primitive + { + const char + *token = GetToken(); + if (stricmp(token, "(") == 0) + { + if ( + ParsePrimitive( + local_name, + method_list, + warehouse_pointer + ) == False + ) + { + // + // BT DEV-GAUGES bring-up: the BT-specific gauge primitive + // table (BTL4MethodDescription, btl4grnd.cpp) is still a stub + // -- the BT gauge widget classes (PlayerStatus, ...) aren't + // reconstructed yet, so they don't resolve here. Rather than + // Fail() -- which pops a modal assert dialog and FREEZES the + // game mid-parse -- SKIP the unknown primitive's parameter + // list so the parse can continue: it still registers every + // label (e.g. Bhk1Init -> MechInit) and runs the base + // "configure" primitives that build the gauge PORTS/surfaces + // (the beachhead needs the 'sec'/radar surface, not the + // widgets). Gated on BT_DEV_GAUGES so the POD path keeps the + // strict Fail (it needs a complete, real method table). + // + if (getenv("BT_DEV_GAUGES") != NULL || getenv("L4MFDSPLIT") != NULL) + { + if (getenv("BT_GAUGE_SKIP_LOG")) + DEBUG_STREAM << "[gskip] unresolved primitive '" + << local_name << "' -> skipped\n" << flush; + const char + *skip_token; + int + paren_depth = 1; // the '(' already consumed above + while ( + (paren_depth > 0) && + ((skip_token = GetToken()) != NULL) + ) + { + if (stricmp(skip_token, "(") == 0) + ++paren_depth; + else if (stricmp(skip_token, ")") == 0) + --paren_depth; + } + UngetPreviousToken(); // leave ')' for the check below + } + else + { + ReportParsingError("Undefined primitive"); + } + } + if (stricmp(GetToken(), ")") != 0) + { + ReportParsingError("Missing ')'"); + } + } + else + { + UngetPreviousToken(); + + Test_Tell("Call to '" << local_name << "'\n"); + + command = callCommand; + Insert(&command, sizeof(GaugeInterpreterCommand)); + + Check(symbolTable); + GaugeInterpreterOffset + offset = symbolTable->Refer(local_name, currentOffset); + Insert(&offset, sizeof(GaugeInterpreterOffset)); + } + } + + if (stricmp(GetToken(), ";") != 0) + { + ReportParsingError("Missing ';'"); + } + } + Check_Fpu(); +} + +Logical + GaugeInterpreter::ParsePrimitive( + const char *name, + MethodDescription **method_list, + Warehouse *warehouse_pointer + ) +{ + Test_Tell( + "GaugeInterpreter::ParsePrimitive(" << name << + ", " << method_list << + ", " << warehouse_pointer << + ")\n" + ); + Check(this); + Check_Pointer(name); + Check_Pointer(method_list); + Check(warehouse_pointer); + + MethodDescription + *method_entry, + **list; + GaugeInterpreterCommand + command_number = nextAvailableCommand; + int + i; + Logical + first_parameter = True; + + list = method_list; + while(list != NULL) + { + Check_Pointer(list); + method_entry = *list++; + Check_Pointer(method_entry); + if (method_entry->name == NULL) + { + //------------------------------------------------------------- + // Attempt to chain to next list: if NULL, we didn't match. + //------------------------------------------------------------- + list = method_entry->parameterList[0].data.nextMethodList; + } + else + { + //------------------------------------------------------------- + // Attempt to match this entry + //------------------------------------------------------------- + Test_Tell("<" << method_entry->name << ">\n"); + if (stricmp(method_entry->name, name) != 0) + { + command_number = (GaugeInterpreterCommand) (command_number + 1); + } + else + { + //------------------------------------------------------- + // Name found, attempt to procure parameters + //------------------------------------------------------- + Test_Tell("Found, attempt to match parameters\n"); + for ( + i=0; + method_entry->parameterList[i].type != + ParameterDescription::typeEmpty; + ++i + ) + { + //------------------------------------------------------- + // Eat commas (after first parameter) + //------------------------------------------------------- + if (first_parameter) + { + first_parameter = False; + } + else + { + if (stricmp(GetToken(), ",") != 0) + { + ReportParsingError("Missing ','"); + return False; + } + } + //------------------------------------------------------- + // Read a parameter + //------------------------------------------------------- + if (method_entry->parameterList[i]. + Extract(this, warehouse_pointer) == False + ) + { + //---------------------------------------------- + // Not found, error + //---------------------------------------------- + ReportParsingError("Wrong or missing parameter"); + return False; + } + } + //------------------------------------------------------- + // All parameters found, write to the interpreter table + //------------------------------------------------------- + Test_Tell("All parameters matched\n"); + + Check_Pointer(method_entry->execute); // make sure it's executable + Verify((command_number-nextAvailableCommand) >= 0); + Verify((command_number-nextAvailableCommand) < primitiveCount); + + Insert(&command_number, sizeof(GaugeInterpreterCommand)); + + for ( + i=0; + method_entry->parameterList[i].type != + ParameterDescription::typeEmpty; + ++i + ) + { + method_entry->parameterList[i].Save(this); + } + Test_Tell("All done\n"); + Check_Fpu(); + return True; + } + } + } + //------------------------------------------------------------- + // Name not matched, return error + //------------------------------------------------------------- + Test_Tell("Not found!\n"); + Check_Fpu(); + return False; +} + +void + GaugeInterpreter::Insert(const void *value_pointer, int size_in_chars) +{ +# if defined(SHOW_EVERYTHING) + Test_Tell( + "GaugeInterpreter::Insert(" << ((void *) value_pointer) << + "," << size_in_chars << + ")\n" + ); +# endif + Check(this); + Check_Pointer(value_pointer); + Verify(size_in_chars > 0); + + Verify((currentOffset+size_in_chars) < interpreterTableSize); + + char + *source; + + for( + source= (char *) value_pointer; + size_in_chars!=0; + ++source, --size_in_chars + ) + { + interpreterTable[currentOffset++] = *source; + } + Check_Fpu(); +} + +void * + GaugeInterpreter::Retrieve(int size_in_chars) +{ +# if defined(SHOW_EVERYTHING) + Test_Tell( + "GaugeInterpreter::Retrieve(" << size_in_chars << ")\n" + ); +# endif + Check(this); + + Verify(size_in_chars > 0); + + Verify(currentOffset >= 0); + Verify(currentOffset < interpreterTableSize); + + void + *here = &interpreterTable[currentOffset]; + + currentOffset = (GaugeInterpreterOffset) (currentOffset + size_in_chars); + Verify(currentOffset < interpreterTableSize); + + Check_Fpu(); + return here; +} + +void + GaugeInterpreter::InsertString(const char *string) +{ + Check(this); + Check_Pointer(string); + + unsigned short + length = (unsigned short) (strlen(string)+1); + + Test_Tell( + "GaugeInterpreter::InsertString(" << string << + "), len=" << length << "\n" + ); + + Verify(length < ParameterDescription::maxStringLength); + + Insert(&length, sizeof(unsigned short)); + Insert(string, length); + Check_Fpu(); +} + +const char * + GaugeInterpreter::RetrieveString() +{ +# if defined(SHOW_EVERYTHING) + Test_Tell( + "GaugeInterpreter::RetrieveString()='" + ); +# endif + Check(this); + + const char + *pointer; + + unsigned short + length = *(unsigned short *) Retrieve(sizeof(unsigned short)); + + Verify(length < ParameterDescription::maxStringLength); + + pointer = (const char *) &interpreterTable[currentOffset]; + Check_Pointer(pointer); + + currentOffset = (GaugeInterpreterOffset) (currentOffset + length); + +# if defined(SHOW_EVERYTHING) + Test_Tell( pointer << "', len=" << length << "\n"); +# endif + Check_Fpu(); + return pointer; +} + + +void + GaugeInterpreter::Interpret( + const char *label, + GaugeRenderer *renderer, + int display_port_index, + Vector2DOf position, + Entity *entity + ) +{ + Test_Tell( + "GaugeInterpreter::Interpret('" << label << + "'," << renderer << + "," << display_port_index << + "," << position << + "," << entity << + "\n" + ); + Check(this); + Check_Pointer(label); + Check(renderer); + // 'entity' is allowed to be NULL + + Check(symbolTable); + Check_Pointer(interpreterTable); + + GaugeInterpreterOffset + offset = symbolTable->Get(label); + if (offset < 0) + { + DEBUG_STREAM << "GaugeInterpreter: undefined label '" << label << "'\n" << flush; + } + else + { + InterpretFromOffset( + offset, + renderer, + display_port_index, + position, + entity + ); + } + Check_Fpu(); +} + +void + GaugeInterpreter::InterpretFromOffset( + GaugeInterpreterOffset offset, + GaugeRenderer *renderer, + int display_port_index, + Vector2DOf original_position, + Entity *entity + ) +{ + Test_Tell( + "GaugeInterpreter::InterpretFromOffset(" << offset << + "," << renderer << + "," << display_port_index << + "," << original_position << + "," << entity << + "\n" + ); + Check(this); + Check(renderer); + Verify(offset >= 0); + // 'entity' is allowed to be NULL + Check_Pointer(interpreterTable); + + currentOffset = offset; + + GaugeInterpreterCommand + command; + + int + running = 1; + Vector2DOf + position; + + position = original_position; + + while(running) + { + command = *(GaugeInterpreterCommand *) + Retrieve(sizeof(GaugeInterpreterCommand)); + switch(command) + { + case endMarker: + case returnCommand: + Test_Tell("Return\n"); + running = 0; + break; + + case setPortIndexCommand: + { + const char + *port_name = RetrieveString(); + Test_Tell("Set port=" << port_name << "\n"); + //------------------------------------------ + // Replace variable if needed + //------------------------------------------ + port_name = ReplaceVariable(port_name); + + int + port = renderer->FindGraphicsPort(port_name); + + if (port >= 0) + { + display_port_index = port; + } + else + { + Tell( + "GaugeInterpreter::InterpretFromOffset: port '"<< + port_name << "' not found!\n" + ); + } + } + break; + + case addOffsetCommand: + { + Vector2DOf + temp; + + temp = *(Vector2DOf *) Retrieve(sizeof(Vector2DOf)); + Test_Tell("Add offset " << dec << temp); + position.x = original_position.x + temp.x; + position.y = original_position.y + temp.y; + Test_Tell(" to " << position << "\n"); + } + break; + + case attributeVariableCommand: + { + unsigned char + index = *(unsigned char *)Retrieve(sizeof(unsigned char)); + const char + *attribute_name = RetrieveString(); + Test_Tell( + "attribute variable #" << index << "=" << attribute_name << "\n" + ); + + Verify(index < maxVariableNameArrayIndex); + attributeNameArray[index] = attribute_name; + } + break; + case callCommand: + { + GaugeInterpreterOffset + new_offset = + *(GaugeInterpreterOffset *) + Retrieve(sizeof(GaugeInterpreterOffset)); + + Test_Tell("Call " << hex << new_offset << dec << "\n"); + offset = currentOffset; // save for call + + InterpretFromOffset( + new_offset, + renderer, + display_port_index, + position, + entity + ); + currentOffset = offset; // restore offset + } + break; + + case enableCommand: + Test_Tell("Enable\n"); + { + Check(application); + Check(application->GetModeManager()); + + application->GetModeManager()->AddModeMask( + *(ModeMask*)Retrieve(sizeof(ModeMask)) + ); + } + break; + + case disableCommand: + Test_Tell("Disable\n"); + { + Check(application); + Check(application->GetModeManager()); + + application->GetModeManager()->RemoveModeMask( + *(ModeMask*)Retrieve(sizeof(ModeMask)) + ); + } + break; + + default: + command = (GaugeInterpreterCommand) (command - nextAvailableCommand); + Verify(command < primitiveCount); + Check_Pointer(primitiveTable); + + Test_Tell("****" << primitiveTable[command]->name<< "\n"); + primitiveTable[command]->Execute( + display_port_index, + position, + entity, + renderer + ); + break; + } + } + Check_Fpu(); +} + +const char * + GaugeInterpreter::ReplaceVariable(const char *string) +{ + Check(this); + Verify(string != NULL); + if (*string == '@') + { + unsigned char + index = *(string+1); + if ((index >= '0') && (index <= '9')) + { + string = attributeNameArray[index - '0']; + Verify(string != NULL); + Test_Tell( + "Variable @" << index << " replaced with '" << string <<"'\n" + ); + } + } + Check_Fpu(); + return string; +} + +void + GaugeInterpreter::DumpTable() +{ + Test_Tell("GaugeInterpreter::DumpTable\n"); + Check(this); + + GaugeInterpreterCommand + command; + + const char + *label; + + currentOffset = 0; + do + { + label = symbolTable->LabelFromValue(currentOffset); + if (label != NULL) + { + DEBUG_STREAM << label << ":\n" << flush; + } + + DEBUG_STREAM << " " << hex << currentOffset << ":" << flush; + + command = *(GaugeInterpreterCommand *) + Retrieve(sizeof(GaugeInterpreterCommand)); + switch(command) + { + case endMarker: + DEBUG_STREAM << "---------End of table---------\n" << flush; + break; + + case returnCommand: + DEBUG_STREAM <<"return\n" << flush; + break; + + case setPortIndexCommand: + { + const char + *port_name = RetrieveString(); + DEBUG_STREAM << "setport '" << port_name << "'\n" << flush; + } + break; + + case addOffsetCommand: + { + Vector2DOf + offset = *(Vector2DOf *) Retrieve(sizeof(Vector2DOf)); + + DEBUG_STREAM << "offset " << dec << offset << "\n" << flush; + } + break; + + case callCommand: + { + GaugeInterpreterOffset + new_offset = + *(GaugeInterpreterOffset *) + Retrieve(sizeof(GaugeInterpreterOffset)); + + DEBUG_STREAM << "call 0x" << new_offset << " (" << flush; + + const char + *name = symbolTable->LabelFromValue(new_offset); + + if (name == NULL) + { + DEBUG_STREAM << "UNDEFINED!!!)\n" << flush; + } + else + { + DEBUG_STREAM << name << ")\n" << flush; + } + } + break; + + case enableCommand: + { + ModeMask + mask = *(ModeMask*)Retrieve(sizeof(ModeMask)); + DEBUG_STREAM << "enable 0x" << mask << "\n" << flush; + } + break; + + case disableCommand: + { + ModeMask + mask = *(ModeMask*)Retrieve(sizeof(ModeMask)); + DEBUG_STREAM << "disable 0x" << mask << "\n" << flush; + } + break; + + default: + { + MethodDescription + *method_entry = primitiveTable[command-nextAvailableCommand]; + DEBUG_STREAM << method_entry->name << ":\n" << flush; + + int + i; + for ( + i=0; + method_entry->parameterList[i].type != + ParameterDescription::typeEmpty; + ++i + ) + { + //------------------------------------------------------- + // Show a parameter + //------------------------------------------------------- + method_entry->parameterList[i].DumpInterpreterEntry( + this, + " " + ); + } + } + break; + } + } + while(command != endMarker); + Check_Fpu(); +} + +//############################################################################# +// ParameterDescription +//############################################################################# +ParameterDescription::~ParameterDescription() +{ + Check_Fpu(); +} + +#if DEBUG_LEVEL <= 0 +void + ParameterDescription::CheckIt(int /*this_type*/) +{ +} +#else +void + ParameterDescription::CheckIt(int this_type) +{ + Check_Pointer(this); + Verify(type == this_type); + + switch(type) + { + case typeEmpty: + case typeRate: + case typeModeMask: + case typeInteger: + case typeColor: + case typeScalar: + case typeVector: + case typeRectangle: + break; + + case typeAttribute: + case typeString: + if (data.string != NULL) + { + Check_Pointer(data.string); + } + break; + + default: + Fail("Illegal parameter type!"); + } + Check_Fpu(); +} +#endif + +void + ParameterDescription::ShowInstance( + char *indent + ) +{ + Check_Pointer(this); + DEBUG_STREAM << indent << "ParameterDescription:" << dec << flush; + switch(type) + { + case typeEmpty: + DEBUG_STREAM << "empty" << flush; + break; + + case typeRate: + DEBUG_STREAM << "rate=" << flush; + { + int + i,j; + + for(i='A',j=0x10000; i<'Q'; ++i, j<<=1) + { + if (data.rate & j) + { + DEBUG_STREAM << (char) i << flush; + } + } + } + break; + + case typeModeMask: + DEBUG_STREAM << hex << "modeMask=" << data.modeMask << dec << flush; + break; + + case typeInteger: + DEBUG_STREAM << "integer=" << data.integer << flush; + break; + + case typeColor: + DEBUG_STREAM << "color=0x" << hex << data.color << dec << flush; + break; + + case typeScalar: + DEBUG_STREAM << "scalar=" << data.scalar << flush; + break; + + case typeVector: + DEBUG_STREAM << + "vector= (" << data.vector.x << + ", " << data.vector.y << + ")"; + break; + + case typeRectangle: + DEBUG_STREAM << + "rectangle= ((" << data.rectangle.bottomLeft.x << + ", " << data.rectangle.bottomLeft.y << + "),(" << data.rectangle.topRight.x << + ", " << data.rectangle.topRight.y << + ")"; + break; + + case typeAttribute: + if (data.string == NULL) + { + DEBUG_STREAM << "attribute=NULL\n" << flush; + } + else + { + DEBUG_STREAM << "attribute=<" << data.string << ">" << flush; + } + break; + + case typeString: + if (data.string == NULL) + { + DEBUG_STREAM << "string=NULL\n" << flush; + } + else + { + DEBUG_STREAM << "string=<" << data.string << ">" << flush; + } + break; + + default: + DEBUG_STREAM << "ILLEGAL TYPE=" << type << flush; + } + DEBUG_STREAM << "\n" << flush; + Check_Fpu(); +} + +void * + ParameterDescription::ParseAttribute( + const char *string_pointer, + Entity *entity + ) +{ + Test_Tell( + "ParameterDescription::ParseAttribute('" << string_pointer << + "', " << entity << + ")\n" + ); + Check_Pointer(this); + Check_Pointer(string_pointer); + Check(entity); + + Simulation* + simulation; + + char + temp_string[80], + *source, + *temp_ptr; + + Verify(type == typeAttribute); + + Str_Copy(temp_string, string_pointer, sizeof(temp_string)); + + source = temp_string; + for(temp_ptr = source; *temp_ptr != '\0'; ++temp_ptr) + { + if (*temp_ptr == '/') + { + *temp_ptr = '\0'; + + Test_Tell("Subsystem name=" << source << "\n"); + + simulation = (Simulation *) entity->FindSubsystem(source); + if (simulation == NULL) + { + Tell("parseAttribute - subsystem '" << source << "' not found\n"); + Check_Fpu(); + return NULL; + } + else + { + source = temp_ptr+1; + Test_Tell("Subsystem attribute name=" << source << "\n"); + + void + *attribute_pointer = simulation->GetAttributePointer(source); + + if (attribute_pointer == NULL) + { + Tell( + "parseAttribute - attribute '" << + string_pointer << "' not found\n" + ); + } + // gauge data-binding wave: a per-binding resolution trace to the + // log file (env BT_GAUGE_ATTR_LOG) -- proves which cockpit bindings + // resolve to a live member vs read NULL (unpublished attribute). + if (getenv("BT_GAUGE_ATTR_LOG")) + DEBUG_STREAM << "[attr] " << string_pointer + << (attribute_pointer ? " OK\n" : " NULL\n") << flush; + Check_Fpu(); + return attribute_pointer; + } + } + } + + Test_Tell("Entity attribute name=" << source << "\n"); + + void + *attribute_pointer = ((Simulation *)entity)->GetAttributePointer(source); + + if (attribute_pointer == NULL) + { + Tell( + "parseAttribute - attribute '" << + source << "' not found\n" + ); + } + if (getenv("BT_GAUGE_ATTR_LOG")) + DEBUG_STREAM << "[attr] " << source + << (attribute_pointer ? " OK (entity)\n" : " NULL (entity)\n") << flush; + Check_Fpu(); + return attribute_pointer; +} + +Logical + ParameterDescription::Extract( + GaugeInterpreter *interpreter, + Warehouse *warehouse_pointer + ) +{ + Test_Tell( + "ParameterDescription::Extract(" << interpreter << + ", " << warehouse_pointer << + ")\n" + ); + Check_Pointer(this); + Check(interpreter); + // + //---------------------------------------------------------------- + // Choose the appropriate parameter type, attempt to create it + //---------------------------------------------------------------- + // + switch(type) + { + case typeEmpty: + Fail("type == empty!"); + break; + + case typeRate: + Test_Tell("rate? "); + if (interpreter->GetRate(&data.rate)) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + break; + + case typeModeMask: + Test_Tell("modeMask? "); + if (interpreter->GetModeMask(&data.modeMask)) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + break; + + case typeInteger: + Test_Tell("integer? "); + if (interpreter->GetInteger(&data.integer)) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + break; + + case typeColor: + Test_Tell("color? "); + if (interpreter->GetInteger(&data.color)) + { + if (data.color <= 0xFF && data.color >= 0) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + } + break; + + case typeScalar: + Test_Tell("scalar? "); + if (interpreter->GetScalar(&data.scalar)) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + break; + + case typeVector: + Test_Tell("vector? "); + { + Vector2DOf + temp_vector; + + if (interpreter->GetVector(&temp_vector)) + { + data.vector.x = temp_vector.x; + data.vector.y = temp_vector.y; + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + } + break; + + case typeRectangle: + Test_Tell("rectangle? "); + { + int + success; + + success = (strcmp(interpreter->GetToken(), "(") == 0); + success &= interpreter->GetInteger(&data.rectangle.bottomLeft.x); + success &= (strcmp(interpreter->GetToken(), ",") == 0); + success &= interpreter->GetInteger(&data.rectangle.bottomLeft.y); + success &= (strcmp(interpreter->GetToken(), ",") == 0); + success &= interpreter->GetInteger(&data.rectangle.topRight.x); + success &= (strcmp(interpreter->GetToken(), ",") == 0); + success &= interpreter->GetInteger(&data.rectangle.topRight.y); + success &= (strcmp(interpreter->GetToken(), ")") == 0); + + if (success) + { + Test_Tell("yes.\n"); + Check_Fpu(); + return True; + } + } + break; + + case typeAttribute: + { + const char + *token = interpreter->GetToken(); + Test_Tell("attribute='"); + Str_Copy(data.string, token, maxStringLength-1); + Test_Tell(data.string << "'\n"); + Check_Fpu(); + } + return True; + + case typeString: + { + const char + *token = interpreter->GetToken(); + Test_Tell("string='"); + Str_Copy(data.string, token, maxStringLength-1); + Test_Tell(data.string << "'\n"); + Check_Fpu(); + } + return True; + + default: + Fail("Illegal type"); + return False; + } + + Test_Tell("NO!\n"); + Check_Fpu(); + return False; +} + +void + ParameterDescription::Save(GaugeInterpreter *interpreter) +{ + Test_Tell("ParameterDescription::Save(" << interpreter << ")\n"); + Check_Pointer(this); + Check(interpreter); + + // + //---------------------------------------------------------------- + // Choose the appropriate type, write to interpreter table + //---------------------------------------------------------------- + // + switch(type) + { + case typeEmpty: + Fail("type == empty!"); + break; + + case typeRate: + Test_Tell("rate\n"); + interpreter->Insert(&data.rate, sizeof(GaugeRate)); + break; + + case typeModeMask: + Test_Tell("modeMask\n"); + interpreter->Insert(&data.modeMask, sizeof(ModeMask)); + break; + + case typeInteger: + Test_Tell("integer\n"); + interpreter->Insert(&data.integer, sizeof(int)); + break; + + case typeColor: + Test_Tell("color\n"); + interpreter->Insert(&data.color, sizeof(int)); + break; + + case typeScalar: + Test_Tell("scalar\n"); + interpreter->Insert(&data.scalar, sizeof(Scalar)); + break; + + case typeVector: + Test_Tell("vector\n"); + interpreter->Insert(&data.vector.x, sizeof(int)); + interpreter->Insert(&data.vector.y, sizeof(int)); + break; + + case typeRectangle: + Test_Tell("rectangle\n"); + interpreter->Insert(&data.rectangle.bottomLeft.x, sizeof(int)); + interpreter->Insert(&data.rectangle.bottomLeft.y, sizeof(int)); + interpreter->Insert(&data.rectangle.topRight.x, sizeof(int)); + interpreter->Insert(&data.rectangle.topRight.y, sizeof(int)); + break; + + case typeAttribute: + Test_Tell("attribute\n"); + Check_Pointer(data.string); + interpreter->InsertString(data.string); + break; + + case typeString: + Test_Tell("string\n"); + interpreter->InsertString(data.string); + break; + + default: + Fail("Illegal type"); + break; + } + Check_Fpu(); +} + +void + ParameterDescription::Restore( + GaugeInterpreter *interpreter, + Entity *entity + ) +{ + Check_Pointer(this); + Check(interpreter); + + Test_Tell("\nParameterDescription::Restore-"); + // + //---------------------------------------------------------------- + // Choose the appropriate type, read from interpreter table + //---------------------------------------------------------------- + // + switch(type) + { + case typeEmpty: + Fail("type == empty!"); + break; + + case typeRate: + data.rate = *(GaugeRate *)interpreter->Retrieve(sizeof(GaugeRate)); + Test_Tell("rate=" << hex << data.rate << dec << "\n"); + break; + + case typeModeMask: + data.modeMask = *(ModeMask *) + interpreter->Retrieve(sizeof(ModeMask)); + Test_Tell("modeMask=" << hex << data.modeMask << dec << "\n"); + break; + + case typeInteger: + data.integer = *(int *) (interpreter->Retrieve(sizeof(int))); + Test_Tell("integer=" << data.integer << "\n"); + break; + + case typeColor: + data.color = *(int *) (interpreter->Retrieve(sizeof(int))); + Test_Tell("color=" << data.color << "\n"); + break; + + case typeScalar: + data.scalar = *(Scalar *) (interpreter->Retrieve(sizeof(Scalar))); + Test_Tell("scalar=" << data.scalar << "\n"); + break; + + case typeVector: + data.vector.x = *(int*) interpreter->Retrieve(sizeof(int)); + data.vector.y = *(int*) interpreter->Retrieve(sizeof(int)); + Test_Tell("vector=(" << data.vector.x << "," << data.vector.y << ")\n"); + break; + + case typeRectangle: + data.rectangle.bottomLeft.x = *(int*) interpreter->Retrieve(sizeof(int)); + data.rectangle.bottomLeft.y = *(int*) interpreter->Retrieve(sizeof(int)); + data.rectangle.topRight.x = *(int*) interpreter->Retrieve(sizeof(int)); + data.rectangle.topRight.y = *(int*) interpreter->Retrieve(sizeof(int)); + Test_Tell( + "rectangle=((" << data.rectangle.bottomLeft.x << + "," << data.rectangle.bottomLeft.y << + "),(" << data.rectangle.topRight.x << + "," << data.rectangle.topRight.y << + "))\n" + ); + break; + + case typeAttribute: + { + const char + *string_pointer = interpreter->RetrieveString(); + + Verify(string_pointer != NULL); + Test_Tell("attribute=" << string_pointer << "\n"); + //-------------------------------------- + // Replace if variable name + //-------------------------------------- + string_pointer = interpreter->ReplaceVariable(string_pointer); + //-------------------------------------- + // Change into True attribute pointer + //-------------------------------------- + Check(entity); + data.attributePointer = ParseAttribute(string_pointer, entity); + Verify(data.attributePointer != NULL); + } + break; + + case typeString: + Test_Tell("string\n"); + { + // Get the string here INSTEAD of inside Str_Copy() because + // of side effects! (string_pointer is referenced multiple times) + const char + *string_pointer = interpreter->RetrieveString(); + //-------------------------------------- + // Replace if variable name + //-------------------------------------- + string_pointer = interpreter->ReplaceVariable(string_pointer); + + Test_Tell("string=" << string_pointer << "\n"); + Str_Copy( + data.string, + string_pointer, + maxStringLength-1 + ); + } + break; + + default: + Fail("Illegal type"); + break; + } + Check_Fpu(); +} + +void + ParameterDescription::DumpInterpreterEntry( + GaugeInterpreter *interpreter, + const char *indent + ) +{ + Check_Pointer(this); + Check(interpreter); + //---------------------------------------------------------------- + // Choose the appropriate type, read from interpreter table + //---------------------------------------------------------------- + DEBUG_STREAM << indent << flush; + + switch(type) + { + case typeEmpty: + DEBUG_STREAM << "***EMPTY***\n" << flush; + break; + + case typeRate: + { + GaugeRate + rate = *(GaugeRate *) + interpreter->Retrieve(sizeof(GaugeRate)); + DEBUG_STREAM << "rate " << rate << "\n" << flush; + } + break; + + case typeModeMask: + { + ModeMask + mask = *(ModeMask *) + interpreter->Retrieve(sizeof(ModeMask)); + DEBUG_STREAM << "mask " << mask << "\n" << flush; + } + break; + + case typeInteger: + { + int + i = *(int *) (interpreter->Retrieve(sizeof(int))); + DEBUG_STREAM << dec << "int " << i << "\n" << flush; + } + break; + + case typeColor: + { + int + i = *(int *) (interpreter->Retrieve(sizeof(int))); + DEBUG_STREAM << "color 0x" << i << "\n" << flush; + } + break; + + case typeScalar: + { + Scalar + s = *(int *) (interpreter->Retrieve(sizeof(Scalar))); + DEBUG_STREAM << dec << "scalar " << s << "\n" << flush; + } + break; + + case typeVector: + { + Vector2DOf + v; + + v.x = *(int *) (interpreter->Retrieve(sizeof(int))); + v.y = *(int *) (interpreter->Retrieve(sizeof(int))); + DEBUG_STREAM << dec << "vector " << v << "\n" << flush; + } + break; + + case typeRectangle: + { + Rectangle2D + r; + + r.bottomLeft.x = *(int *) (interpreter->Retrieve(sizeof(int))); + r.bottomLeft.y = *(int *) (interpreter->Retrieve(sizeof(int))); + r.topRight.x = *(int *) (interpreter->Retrieve(sizeof(int))); + r.topRight.y = *(int *) (interpreter->Retrieve(sizeof(int))); + DEBUG_STREAM << dec << "rectangle " << r << "\n" << flush; + } + break; + + case typeAttribute: + DEBUG_STREAM << "attribute '" << interpreter->RetrieveString() << "'\n" << flush; + break; + + case typeString: + DEBUG_STREAM << "string '" << interpreter->RetrieveString() << "'\n" << flush; + break; + + default: + DEBUG_STREAM << "ILLEGAL TYPE=" << type << "!!\n" << flush; + break; + } + Check_Fpu(); +} + +//############################################################################# +// MethodDescription +//############################################################################# +void + MethodDescription::ShowInstance(char *indent) +{ + Check_Pointer(this); + + DEBUG_STREAM << indent << "MethodDescription:\n" << flush; + + char + temp[80]; + int + i; + + DEBUG_STREAM << indent << "name =" << name << "\n" << flush; + DEBUG_STREAM << indent << "execute=" << execute << "\n" << flush; + + for(i=0; i position, + Entity *entity, + GaugeRenderer *renderer + ) +{ + Check_Pointer(this); + Check(renderer); + Check(renderer->interpreter); + int + i; + //------------------------------------------------------------- + // Restore the parameters from the interpreter table + //------------------------------------------------------------- + for (i=0; parameterList[i].type != ParameterDescription::typeEmpty; ++i) + { + parameterList[i].Restore(renderer->interpreter, entity); + } + //------------------------------------------------------------- + // Execute the call + //------------------------------------------------------------- + Check_Pointer(execute); +# if DEBUG_LEVEL > 0 + Logical + result = + (*execute)( + display_port_index, + position, + entity, + renderer + ); + Verify(result == True); +# else + (*execute)( + display_port_index, + position, + entity, + renderer + ); +# endif + Check_Fpu(); +} + +//####################################################################### +// GaugeRendererStatistics +//####################################################################### +void + GaugeRendererStatistics::Clear() +{ + sampleCount = 0; + sum = (Scalar) 0; + maximum = (Scalar) 0; + Check_Fpu(); +} + +void + GaugeRendererStatistics::Update(Scalar delta) +{ + ++sampleCount; + sum += delta; + if (maximum < delta) + { + maximum = delta; + } + Check_Fpu(); +} + +Scalar + GaugeRendererStatistics::CalculateAverage() +{ + Scalar + average; + + if (sampleCount <= 0) + { + average = (Scalar) 0; + } + else + { + average = (Scalar) (sum/sampleCount); + } + + Check_Fpu(); + return average; +} + +//############################################################################# +// GaugeRenderer +//############################################################################# +GaugeRenderer + *GaugeRenderer::headGaugeRenderer = NULL; + +GaugeRenderer::GaugeRenderer(): + Renderer( + application->GetApplicationLoopFrameRate(), + MaxRendererComplexity, // in renderer.cc (3.0f) + DefaultRendererPriority, // in renderer.hh (1) + GaugeInterestType, // in interest.hh + DefaultInterestDepth, // in interest.hh (1) + GaugeRendererClassID // in vdata.hh + ), + newList(NULL), + activeList(NULL), + inactiveList(NULL), + lampManager(NULL) // instantiated at topmost level only +{ + Test_Tell("GaugeRenderer::GaugeRenderer()\n"); + Check_Pointer(this); + + int + i; + + suspended = False; + previousModeMask = (ModeMask) 0; + //--------------------------------------------------------------------- + // Ensure that graphicsPort pointers are NULL + //--------------------------------------------------------------------- + for (i=0; i(activeList); + Register_Object(activeIterator); + //---------------------------------------------------- + // Clear load-balancing data + //---------------------------------------------------- + for(i=0; inextGaugeRenderer + ) + { + if (gauge_renderer == this) + { + // + // Found! head of list? + // + if (previous_gauge_renderer == NULL) + { + headGaugeRenderer = nextGaugeRenderer; + } + // + // Not head, remove from chain + // + else + { + previous_gauge_renderer->nextGaugeRenderer = + nextGaugeRenderer; + } + break; + } + // + // Keep track of 'previous' object + // + previous_gauge_renderer = gauge_renderer; + } + + Check_Fpu(); +} + +//=========================================================================== +// EmergencyShutdown +//=========================================================================== +void + GaugeRenderer::EmergencyShutdown() +{ + Test_Tell("GaugeRenderer::EmergencyShutdown()\n"); + + GaugeRenderer + *gauge_renderer; + + for( + gauge_renderer = headGaugeRenderer; + gauge_renderer != NULL; + gauge_renderer = gauge_renderer->nextGaugeRenderer + ) + { + gauge_renderer->LocalEmergencyShutdown(); + } +} + +//=========================================================================== +// LocalEmergencyShutdown +//=========================================================================== +void + GaugeRenderer::LocalEmergencyShutdown() +{ +} + +// +//=========================================================================== +// TestInstance +//=========================================================================== +// +Logical + GaugeRenderer::TestInstance() const +{ + //-------------------------------------------------------------------- + // Check the base renderer + //-------------------------------------------------------------------- + return Renderer::TestInstance(); +} + +// +//=========================================================================== +// LinkToEntity +//=========================================================================== +// +void + GaugeRenderer::LinkToEntity(Entity *entity) +{ + Check(this); + Check(entity); + + Test_Tell("GaugeRenderer::LinkToEntity(" << entity << ")\n"); + + // + //-------------------------------------------------------------------- + // Inform all gauges + //-------------------------------------------------------------------- + // + GaugeBase + *base_pointer; + + if (! suspended) + { + { + SChainIteratorOf + i(newList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->LinkToEntity(entity); + } + } + { + SChainIteratorOf + i(activeList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->LinkToEntity(entity); + } + } + { + SChainIteratorOf + i(inactiveList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->LinkToEntity(entity); + } + } + } + // + //-------------------------------------------------------------------- + // Call inherited method + //-------------------------------------------------------------------- + // + Renderer::LinkToEntity(entity); + Check_Fpu(); +} + +// +//=========================================================================== +// NotifyOfNewInterestingEntity +//=========================================================================== +// +void + GaugeRenderer::NotifyOfNewInterestingEntity(Entity *entity) +{ + Test_Tell("GaugeRenderer::NotifyOfNewInterestingEntity\n"); + Check(this); + Check(entity); + + //------------------------------------------------------ + // This method used to update both the movingEntities + // and staticEntities records. That functionality has + // been moved up to the game-specific level (e.g., + // RPL4GaugeRenderer) to allow the game to determine + // what to show. Note that all descendents MUST chain + // back to this base method... + //------------------------------------------------------ + // + //-------------------------------------------------------------------- + // Inform all gauges + //-------------------------------------------------------------------- + // + GaugeBase + *base_pointer; + + if (! suspended) + { + { + SChainIteratorOf + i(newList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfNewInterestingEntity(entity); + } + } + { + SChainIteratorOf + i(activeList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfNewInterestingEntity(entity); + } + } + { + SChainIteratorOf + i(inactiveList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfNewInterestingEntity(entity); + } + } + } + Check_Fpu(); +} + + +// +//=========================================================================== +// NotifyOfBecomingUninterestingEntity +//=========================================================================== +// +void + GaugeRenderer::NotifyOfBecomingUninterestingEntity(Entity *entity) +{ + Test_Tell("GaugeRenderer::NotifyOfBecomingUninterestingEntity\n"); + Check(this); + Check(entity); + //------------------------------------------------------ + // This method used to update both the movingEntities + // and staticEntities records. That functionality has + // been moved up to the game-specific level (e.g., + // RPL4GaugeRenderer) to allow the game to determine + // what to show. Note that all descendents MUST chain + // back to this base method... + //------------------------------------------------------ + // + //-------------------------------------------------------------------- + // Inform all gauges + //-------------------------------------------------------------------- + // + GaugeBase + *base_pointer; + + if (! suspended) + { + { + SChainIteratorOf + i(newList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfBecomingUninterestingEntity(entity); + } + } + { + SChainIteratorOf + i(activeList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfBecomingUninterestingEntity(entity); + } + } + { + SChainIteratorOf + i(inactiveList); + + while ((base_pointer=i.ReadAndNext()) != NULL) + { + Check(base_pointer); + base_pointer->NotifyOfBecomingUninterestingEntity(entity); + } + } + } + Check_Fpu(); +} + +// +//=========================================================================== +// Entity alarms +//=========================================================================== +// +void + GaugeRenderer::StartEntityAlarmImplementation( + Entity *entity, + Subsystem *subsystem, + Enumeration condition, + ResourceDescription::ResourceID resource_ID + ) +{ + Check(this); + + Check(gaugeAlarmManager); + gaugeAlarmManager->Activate( + entity, + subsystem, + condition, + resource_ID + ); + Check_Fpu(); +} +void + GaugeRenderer::StopEntityAlarmImplementation( + Entity *entity, + Subsystem *subsystem, + Enumeration condition + ) +{ + Check(this); + + Check(gaugeAlarmManager); + gaugeAlarmManager->Deactivate( + entity, + subsystem, + condition + ); + Check_Fpu(); +} + +// +//=========================================================================== +// LoadMissionImplementation +//=========================================================================== +// +void + GaugeRenderer::LoadMissionImplementation(Mission */*mission*/) +{ + Tell("GaugeRenderer::LoadMissionImplementation()\n"); + Check(this); + + +//DEBUG_STREAM << "Mover list has " << +// movingGaugeImages.NumberOfItems() << "items.\n"; +//staticGaugeImages.PrintStatistics(); + + + Check_Fpu(); +} + +// +//=========================================================================== +// ShutdownImplementation +//=========================================================================== +// +void + GaugeRenderer::ShutdownImplementation() +{ + Tell("GaugeRenderer::ShutdownImplementation()\n"); + Check(this); + + //-------------------------------------------------------------------- + // Turn off all gauge alarms + //-------------------------------------------------------------------- + if (gaugeAlarmManager != NULL) + { + Check(gaugeAlarmManager); + gaugeAlarmManager->RemoveAllAlarms(); + } + //-------------------------------------------------------------------- + // Delete all remaining gauges BEFORE clearing out the warehouse! + // ...otherwise the gauges will attempt to reference items which + // no longer exist in the warehouse... + //-------------------------------------------------------------------- + Remove(0); + //-------------------------------------------------------------------- + // Remove all lamps + //-------------------------------------------------------------------- + if (lampManager != NULL) + { + Check(lampManager); + lampManager->RemoveAllLamps(); + } + //-------------------------------------------------------------------- + // Clear out the warehouse + //-------------------------------------------------------------------- + if (warehousePointer != NULL) + { + Check(warehousePointer); + warehousePointer->Purge(); + } + //-------------------------------------------------------------------- + // Clear auxiliary data structures + //-------------------------------------------------------------------- + movingEntities.Clear(); + staticEntities.Clear(); + //--------------------------------------------------------------------- + // Destroy all graphicsPort objects + //--------------------------------------------------------------------- + int + i; + + for (i=0; iname << " "); + if (stricmp(graphicsPort[i]->name, port_name) == 0) + { + Test_Tell("<-Found\n"); + Check_Fpu(); + return i; + } + } + } + } + Check_Fpu(); + return -1; +} + +// +//=========================================================================== +// GetGraphicsPort +//=========================================================================== +// +GraphicsPort + *GaugeRenderer::GetGraphicsPort(const char * port_name) +{ + int i(FindGraphicsPort(port_name)); + + Check_Fpu(); + if (i >= 0) + { + return graphicsPort[i]; + } + return NULL; +} + +GraphicsPort + *GaugeRenderer::GetGraphicsPort(int port_number) +{ + Check_Fpu(); + if ((port_number >= 0) && (port_number < maximumGraphicsPorts)) + { + return graphicsPort[port_number]; + } + else + { + return NULL; + } +} + +// +//=========================================================================== +// Add +//=========================================================================== +// +void + GaugeRenderer::Add(GaugeBase *new_gauge) +{ + Tell("GaugeRenderer::Add(" << hex << new_gauge << dec << ")\n"); + Check(this); + // + // Don't call Check(new_gauge) here! + // The Gauge creator calls AddGauge before the gauge is fully built! + // + Check_Pointer(new_gauge); + //------------------------------------------------------------------------- + // Add to 'new' list + //------------------------------------------------------------------------- + newList.Add(new_gauge); + Check_Fpu(); +} + +// +//=========================================================================== +// Remove +//=========================================================================== +// +void + GaugeRenderer::Remove(unsigned int owner_ID) +{ + Tell("GaugeRenderer::Remove(" << owner_ID << ")\n"); + Check(this); + + GaugeBase + *the_base; + + //-------------------------------------------------- + // Search active list first + //-------------------------------------------------- + { + SChainIteratorOf + i(activeList); + //-------------------------------------------------- + // Process all matching gauges + //-------------------------------------------------- + while ((the_base=i.GetCurrent()) != NULL) + { + Check(the_base); + + if ((owner_ID == 0) || (the_base->ownerID == owner_ID)) + { + //----------------------------------------------- + // 'Flush' the gauge before deleting it + //----------------------------------------------- + the_base->Update(Gauge::gaugeRate_A); + //----------------------------------------------- + // Delete it + //----------------------------------------------- + i.Remove(); + Tell(the_base->identificationString << "\n" << flush); + Unregister_Object(the_base); + delete the_base; + } + else + { + i.Next(); + } + } + } + //-------------------------------------------------- + // Search inactive list second + //-------------------------------------------------- + { + SChainIteratorOf + i(inactiveList); + //-------------------------------------------------- + // Process all matching gauges + //-------------------------------------------------- + while ((the_base=i.GetCurrent()) != NULL) + { + Check(the_base); + + if ((owner_ID == 0) || (the_base->ownerID == owner_ID)) + { + //----------------------------------------------- + // Delete it + //----------------------------------------------- + i.Remove(); + Tell(the_base->identificationString << "\n" << flush); + Unregister_Object(the_base); + delete the_base; + } + else + { + i.Next(); + } + } + } + Check_Fpu(); +} + +// +//=========================================================================== +// Remove +//=========================================================================== +// +void + GaugeRenderer::Inactivate(GaugeBase *the_base) +{ + Tell("GaugeRenderer::Inactivate(" << hex << the_base << dec << ")\n"); + Check(this); + + GaugeBase + *the_other_base; + + //-------------------------------------------------- + // Search active list for the base + //-------------------------------------------------- + SChainIteratorOf + i(activeList); + + while ((the_other_base=i.GetCurrent()) != NULL) + { + Check(the_other_base); + + if (the_base == the_other_base) + { + //----------------------------------------------- + // Remove from this list, place in inactive list + //----------------------------------------------- + i.Remove(); + inactiveList.Add(the_base); + the_base->BecameInactive(); + break; + } + else + { + i.Next(); + } + } + Check_Fpu(); +} + +GaugeRate + GaugeRenderer::FindBestFirstTierRate() +{ + return Gauge::gaugeRate_B; // HACK -stubbed in +} + +GaugeRate + GaugeRenderer::FindBestSecondTierRate() +{ + return Gauge::gaugeRate_D; // HACK -stubbed in +} + +GaugeRate + GaugeRenderer::FindBestThirdTierRate() +{ + return Gauge::gaugeRate_H; // HACK -stubbed in +} + +GaugeRate + GaugeRenderer::FindBestFourthTierRate() +{ + return Gauge::gaugeRate_P; // HACK -stubbed in +} + +// +//=========================================================================== +// ExecuteImplementation +//=========================================================================== +// +void + GaugeRenderer::ExecuteImplementation( + RendererComplexity /*complexity*/, + RendererOrigin::InterestingEntityIterator */*iterator*/ + ) +{ + SET_GAUGE_RENDERER(); + Check(this); + + if (! suspended) + { + if (taskMode == foreground) + { + ExecuteForeground(); + } + } + Check_Fpu(); + CLEAR_GAUGE_RENDERER(); +} + +// +//=========================================================================== +// RebuildEntityGrid -- repopulate the moving/static entity grids from the world +// entity list (the port dropped ExecuteImplementation's InterestingEntity feed, +// so the radar/map gauge's within-bounds queries found no contacts). +//=========================================================================== +// +void + GaugeRenderer::RebuildEntityGrid() +{ + Check(this); + + movingEntities.Clear(); + staticEntities.Clear(); + + if (application == NULL) + { + return; + } + HostManager *host_manager = application->GetHostManager(); + if (host_manager == NULL) + { + return; + } + + // Radar contacts are the DYNAMIC vehicles (mechs), not the props/terrain/ + // projectiles that AllEntityIterator would flood the grid with -- iterate the + // dynamic masters (the local + AI/dummy vehicles) plus the dynamic replicants + // (peer vehicles in multiplayer). + // CLASSIFICATION (the phantom-red-pip fix, 2026-07-12): the dynamic + // iterators ALSO surface non-Mover world entities (the map's CulturalIcon + // props, class 0x5E, register dynamic on this port) -- unsorted, they drew + // through the radar's MOVING loop as RED contacts ("multiple pips with one + // player"). Sort by Mover derivation: vehicles into the moving grid (red + // pips), everything else into the static grid (the dim silhouette layer + // DrawStatic draws) -- the follow-up the old note deferred. + { + HostManager::DynamicMasterEntityIterator master_iterator(host_manager); + master_iterator.First(); + Entity *entity; + while ((entity = master_iterator.ReadAndNext()) != NULL) + { + if (entity->IsDerivedFrom(Mover::ClassDerivations)) + movingEntities.Add(entity); + else + staticEntities.Add(entity); + } + } + { + HostManager::DynamicReplicantEntityIterator replicant_iterator(host_manager); + replicant_iterator.First(); + Entity *entity; + while ((entity = replicant_iterator.ReadAndNext()) != NULL) + { + if (entity->IsDerivedFrom(Mover::ClassDerivations)) + movingEntities.Add(entity); + else + staticEntities.Add(entity); + } + } + Check_Fpu(); +} + +void + GaugeRenderer::ExecuteForeground() +{ + + Check(this); + Check(activeIterator); + + //------------------------------------------------------------------- + // Get the current mode mask + //------------------------------------------------------------------- + Check(application); + Check(application->GetModeManager()); + ModeMask + current_mode_mask = application->GetModeManager()->GetModeMask(); + // DEV-COMPOSITE (2026-07-12, the frozen-dial fix): page-gated gauges (mode + // = their MFD page bit) freeze when their page isn't mode-active -- on the + // pod you FLIP pages, but the dev window shows every page surface at once, + // so six of seven weapon dials sat frozen on screen (user-hit; the arcs + // executed exactly 8 times at startup then never again). Under + // BT_DEV_GAUGES force the 15 MFD page-plane bits (BTL4 mode bits 0..14 = + // MFD1/2/3 Quad+Eng1-4) active so every visible page runs. The secondary + // trio (bits 18-20) stays authentic -- those views SHARE pixels and are + // exclusive by design. + { + static int s_devAllPages = -1; + if (s_devAllPages < 0) + s_devAllPages = (getenv("BT_DEV_GAUGES") != NULL || + getenv("L4MFDSPLIT") != NULL) ? 1 : 0; + if (s_devAllPages) + current_mode_mask |= (ModeMask)0x7FFF; + } + ModeMask + previous_mode_mask = application->GetModeManager()->GetPreviousModeMask(); + ModeMask + change_mode_mask = current_mode_mask ^ previous_mode_mask; // xor tells me what has changed + //------------------------------------------------------------------- + // Update lamp manager + //------------------------------------------------------------------- + if (lampManager != NULL) + { + Check(lampManager); + lampManager->Update(current_mode_mask); + } + //------------------------------------------------------------------- + // Move new gauges to active/inactive lists + //------------------------------------------------------------------- + { + SChainIteratorOf + i(newList); + GaugeBase + *base_pointer; + + while ((base_pointer=i.GetCurrent()) != NULL) + { + //------------------------------------- + // Always remove from 'new' list + //------------------------------------- + i.Remove(); + //------------------------------------- + // Place in appropriate list + //------------------------------------- + Check(base_pointer); + if (base_pointer->modeMask & current_mode_mask) + { + + // If not already flagged, or gauge's mode mask is always active, + // or the mode change affects us, place into active list + if (!(base_pointer->alreadyActivatedFlag) + // || (base_pointer->modeMask == ModeManager::ModeAlwaysActive) + || (base_pointer->modeMask & change_mode_mask)) + { + base_pointer->alreadyActivatedFlag = True; + //------------------------------------- + // Announce new status + //------------------------------------- + base_pointer->BecameActive(); + //------------------------------------- + // Place in active list only if legal + //------------------------------------- + if (base_pointer->stayInactive) + { + inactiveList.Add(base_pointer); + } + else + { + activeList.Add(base_pointer); + } + } + } + else + { + inactiveList.Add(base_pointer); + } + } + } + //--------------------------------------------------------------- + // If the modeMask has changed, update the active/inactive lists. + //--------------------------------------------------------------- + if (previousModeMask != current_mode_mask) + { + previousModeMask = current_mode_mask; + + ActivateGaugeBases(current_mode_mask,change_mode_mask); + DeactivateGaugeBases(current_mode_mask); + } + //--------------------------------------------------------------- + // Restart background processing + //--------------------------------------------------------------- + taskMode = background; + activeIterator->First(); + //-------------------------------- + // Reset rate bit mask if needed + //-------------------------------- + if (rateBitMask == 0) + { + rateBitMask = 0x8000; +# if defined (PROFILE_GAUGES) + rateProfileIndex = 0; +# endif + } + Check_Fpu(); +} + +// +//=========================================================================== +// ExecuteBackground +//=========================================================================== +// +Logical + GaugeRenderer::ExecuteBackground() +{ + SET_GAUGE_RENDERER(); + Check(this); + + Logical + result; + + Time start, end; + int oldTaskMode = taskMode; + + switch(taskMode) + { + case foreground: + result = ExecuteBackgroundDisplayUpdate(); // might as well update + break; + + case background: + { + result = ProcessOneActiveGauge(); + break; + } + + case copy: + result = ExecuteBackgroundDisplayUpdate(); + break; + } + + if (end.ticks - start.ticks > 100) + { + end = start; + } + + Check_Fpu(); + CLEAR_GAUGE_RENDERER(); + return result; +} + +Logical + GaugeRenderer::ExecuteBackgroundDisplayUpdate() +{ + Check(this); + return False; +} + +// +//=========================================================================== +// ActivateGaugeBases +//=========================================================================== +// +void + GaugeRenderer::ActivateGaugeBases(ModeMask current_mode_mask, ModeMask change_mode_mask) +{ + Check(this); + //----------------------------------------------------------- + // Test the objects in the 'inactive' list. If any of them + // have bits in their modeMask corresponding to the + // new mode mask, move them to the 'active' list. + //----------------------------------------------------------- + SChainIteratorOf + i(inactiveList); + GaugeBase + *base_pointer; + + while ((base_pointer=i.GetCurrent()) != NULL) + { + Check(base_pointer); + //----------------------------------- + // Became active? + //----------------------------------- + if (base_pointer->modeMask & current_mode_mask) + { + if (!(base_pointer->alreadyActivatedFlag) + // || (base_pointer->modeMask == ModeManager::ModeAlwaysActive) + || (base_pointer->modeMask & change_mode_mask)) + { + #if 0 + DEBUG_STREAM << "Activating an inactive (not visible) gauge on inactive list" << endl << flush; + #endif + //----------------------------------- + // Inform object of new status + //----------------------------------- + base_pointer->BecameActive(); + base_pointer->alreadyActivatedFlag = True; + + + //----------------------------------- + // Move to 'active' list if allowed + //----------------------------------- + if (base_pointer->stayInactive) + { + i.Next(); + } + else + { + i.Remove(); + activeList.Add(base_pointer); + } + } + else + { + i.Next(); + } + } + else + { + //----------------------------------- + // No, try the next one + //----------------------------------- + i.Next(); + } + } + Check_Fpu(); +} + +// +//=========================================================================== +// DeactivateGaugeBases +//=========================================================================== +// +void + GaugeRenderer::DeactivateGaugeBases(ModeMask current_mode_mask) +{ + Check(this); + //--------------------------------------------------------------- + // Test the objects in the 'active' list. If any of them do NOT + // have bits in their modeMask corresponding to the new mode + // mask, move them to the 'inactive' list. + //--------------------------------------------------------------- + SChainIteratorOf + i(activeList); + GaugeBase + *base_pointer; + + while ((base_pointer=i.GetCurrent()) != NULL) + { + Check(base_pointer); + //----------------------------------- + // Became inactive? + //----------------------------------- + if (!(base_pointer->modeMask & current_mode_mask)) + { + base_pointer->alreadyActivatedFlag = False; + //----------------------------------- + // Yes, move to 'inactive' list + //----------------------------------- + i.Remove(); + inactiveList.Add(base_pointer); + + base_pointer->BecameInactive(); + + } + else + { + //----------------------------------- + // No, try the next one + //----------------------------------- + i.Next(); + } + } + Check_Fpu(); +} + +// +//=========================================================================== +// ProcessOneActiveGauge +//=========================================================================== +// +Logical + GaugeRenderer::ProcessOneActiveGauge() +{ + Check(this); + Check(activeIterator); + + Logical + result; + GaugeBase + *base_pointer = activeIterator->ReadAndNext(); + + if (base_pointer == NULL) + { + //-------------------------------------------------- + // We're done! + // Bump the bit mask and index for the next pass + //-------------------------------------------------- + rateBitMask >>= 1; +# if defined (PROFILE_GAUGES) + ++rateProfileIndex; +# endif + //-------------------------------------------------- + // Inform system that we are finished + //-------------------------------------------------- + taskMode = copy; + result = True; // Don't stop just yet! Go into third phase! + } + else + { + //-------------------------------------------------- + // Process one gauge + //-------------------------------------------------- + Check(base_pointer); +# if defined (PROFILE_GAUGES) + Scalar + delta = GetCurrentFramePercentage(); + + Logical + actually_ran = +# endif + base_pointer->Update(rateBitMask); + +# if defined (PROFILE_GAUGES) + delta = GetCurrentFramePercentage() - delta; + if (delta < (Scalar) 0) + { + // Hack - what does it REALLY mean when it's negative?!? + delta = - delta; + } + + if (actually_ran) + { + base_pointer->UpdateProfile(delta); + } + statistics[rateProfileIndex][base_pointer->DiscernTier()] + .Update(delta); +# endif + //-------------------------------------------------- + // Tell renderer manager that we have more to do + //-------------------------------------------------- + result = True; + } + return result; +} + +// +//=========================================================================== +// GetCurrentFramePercentage +//=========================================================================== +// +Scalar + GaugeRenderer::GetCurrentFramePercentage() +{ + Check(this); + return (Scalar) 0; +} + +enum +{ + average_bar, + maximum_bar +}; + +#if defined (PROFILE_GAUGES) + static Scalar + draw_bar( + GaugeRenderer *renderer, + int bar_width, + int slot_index, + int bar_type + ) + { + Check(renderer); + //------------------------------------ + // Show individual tier contributors + //------------------------------------ + Scalar + value, + total_value = (Scalar) 0; + Scalar + position = (Scalar) 0; + int + tier_index, + char_position = 0, + next_char_position; + + for(tier_index=0; tier_indexstatistics[slot_index][tier_index].CalculateAverage(); + break; + + case maximum_bar: + value= + renderer->statistics[slot_index][tier_index].maximum; + break; + } + //------------------------------------ + // Add to total + // Calculate next bar position + //------------------------------------ + total_value += value; + position += bar_width * value; + //------------------------------------ + // Limit it in case of overflow + //------------------------------------ + if (position > (Scalar) bar_width) + { + position = (Scalar) bar_width; + } + //------------------------------------ + // Draw with marker to next position + //------------------------------------ + next_char_position = (int) position; + + for( ; char_position < next_char_position; ++char_position) + { + DEBUG_STREAM << tier_marker << flush; + } + } + //------------------------------------ + // Fill unused space in bar + //------------------------------------ + for( ; char_position < bar_width; ++char_position) + { + DEBUG_STREAM << "." << flush; + } + + Check_Fpu(); + return total_value; + } +#endif + + +void + GaugeRenderer::ProfileReport() +{ + Check(this); + +# if defined (PROFILE_GAUGES) + //-------------------------------------------------------------- + // Show all gauges + //-------------------------------------------------------------- + { + SChainIteratorOf + i(activeList); + GaugeBase + *the_base; + + DEBUG_STREAM <<"Active name count avg worst\n" << flush; + DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << flush; + while ((the_base=i.ReadAndNext()) != NULL) + { + Check(the_base); + the_base->ReportProfile(); + } + } + { + SChainIteratorOf + i(inactiveList); + GaugeBase + *the_base; + + DEBUG_STREAM <<"Inactive name count avg worst\n" << flush; + DEBUG_STREAM <<"-------------------------------- ----- ------ -----\n" << flush; + while ((the_base=i.ReadAndNext()) != NULL) + { + Check(the_base); + the_base->ReportProfile(); + } + } + //-------------------------------------------------------------------- + // Dump profiling data + //-------------------------------------------------------------------- + int + slot_index, + tier_index, + bar_width = 40; // total width of bar graph + char + buffer[80]; + //------------------------------------ + // Print header bar + //------------------------------------ + DEBUG_STREAM << "\nSlot|Count|Tier values " << flush; + DEBUG_STREAM << "|Total %\n" << flush; + DEBUG_STREAM << "----+-----+" << flush; + { + for(int i=0; iInitialize(file_name, method_description, warehousePointer); + //----------------------------------------------- + // Execute app initialization call, if it exists + //----------------------------------------------- + Configure("Initialization", NULL); + Check_Fpu(); +} + +void + GaugeRenderer::Configure( + const char *label, + Entity *entity + ) +{ + Test_Tell( + "GaugeRenderer::Configure('" << label << + "', " << entity << + ")\n" + ); + Check(this); + Check_Pointer(label); + + Vector2DOf + position; + + position.x = 0; + position.y = 0; + Check(interpreter); + interpreter->Interpret(label, this, 0, position, entity); + + Check_Fpu(); +} diff --git a/restoration/source410/MUNGA/GRAPH2D.CPP b/restoration/source410/MUNGA/GRAPH2D.CPP new file mode 100644 index 00000000..309033ed --- /dev/null +++ b/restoration/source410/MUNGA/GRAPH2D.CPP @@ -0,0 +1,3111 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(GRAPH2D_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# endif +# if !defined(NAMELIST_HPP) +# include +# endif + +//#define DEBUG + +struct PCXHeader +{ + Byte manufacturer; + Byte version; + Byte encoding; + Byte bitsPerPixel; + Word xMin, yMin; + Word xMax, yMax; + Word hRes, vRes; + Byte palette16[48]; + Byte reserved; + Byte colorPlanes; + Word bytesPerLine; + Word paletteType; + Byte filler[58]; +}; + +Logical + PCXRead( + const char *file_name, + PCXHeader *header, + Byte **body_ptr, + Byte *palette_ptr + ) +{ + FILE + *fp; + + Check_Pointer(file_name); + Verify(header != NULL); + + fp = fopen(file_name, "rb"); + if (fp == NULL) + { + Tell( "PCXRead: Cannot open file '" << file_name << "'\n"); + return False; + } + if (fread (header, sizeof(PCXHeader), 1, fp) != 1) + { + Tell("PCXRead: Cannot read header from '" << file_name << "'\n"); + fclose(fp); + return False; + } + if ( + (header->manufacturer != 0x0A) || // flags 'PCX'-type file + (header->bitsPerPixel != 8) || // we require standard 8-bit + (header->encoding != 1) || // PCX is always encoded + (header->colorPlanes != 1) // 256-color ONLY!!! + ) + { + Tell("PCXRead: '" << file_name << + " 'either not a PCX file, or the wrong type!\n"); + fclose(fp); + return False; + } + + int + data_width(header->bytesPerLine), + width(header->xMax-header->xMin+1), + height(header->yMax-header->yMin+1), + x, + x2, + y, + count; + + Byte + *dest; + + Byte + c; + + + if (body_ptr == NULL) + { + fseek(fp, -769, SEEK_END); // seek to beginning of palette + } + else + { + if (*body_ptr != NULL) + { + Unregister_Pointer(*body_ptr); + delete *body_ptr; + *body_ptr = NULL; + } + *body_ptr = new Byte[width*height]; + Register_Pointer(*body_ptr); + + dest = *body_ptr; + for(y=height; y>0; --y) + { + x2 = width; + for (x=data_width; x > 0; ) + { + c = (Byte) fgetc(fp); + + if (ferror(fp)) + { + Tell("PCXRead: File error reading '" << file_name << "'\n"); + fclose(fp); + Unregister_Pointer(*body_ptr); + delete *body_ptr; + *body_ptr = NULL; + return False; + } + + if ((c & 0xC0) == 0xC0) + { + count = c & 0x3F; + x -= count; + c = (Byte) fgetc(fp); + + while (count--) + { + if (x2 > 0) + { + --x2; + *dest++ = c; + } + } + } + else + { + if (x2 > 0) + { + --x2; + *dest++ = c; + } + --x; + } + } + } + } + + if (palette_ptr != NULL) + { + Byte + identifier; + + if (fread (&identifier, 1, 1, fp) != 1) + { + Tell("PCXRead: Cannot read palette from '" << file_name << "'\n"); + fclose(fp); + return False; + } + + if (identifier != 0x0C) + { + Tell("PCXRead: Invalid palette in '" << file_name << "'\n"); + fclose(fp); + return False; + } + + if (fread (palette_ptr, (256*3), 1, fp) != 1) + { + Tell("PCXRead: Cannot read palette from '" << file_name << "'\n"); + fclose(fp); + Check_Fpu(); + return False; + } + } + + fclose(fp); + Check_Fpu(); + return True; +} + + +//######################################################################## +//################################ BitMap ################################ +//######################################################################## +BitMap * + BitMap::Make(const char *name) +{ + Check_Pointer(name); + + char + file_name[80]; + + Str_Copy(file_name, "gauge\\", sizeof(file_name)); + Str_Cat(file_name, name, sizeof(file_name)); + + BitMap + *bitmap = new BitMap(file_name); + Check_Pointer(bitmap); + if (bitmap->Data.MapPointer == NULL) + { + delete bitmap; + bitmap = NULL; + } + else + { + Check(bitmap); + } + Check_Fpu(); + return bitmap; +} + +BitMap * + BitMap::Make(ResourceDescription::ResourceID /*new_resource_id*/) +{ + Check_Fpu(); + return NULL; // not yet 'resourcified' +} + +BitMap::BitMap(int width, int height) +{ + Check_Pointer(this); + Verify(width >0); + Verify(height >0); + + Data.WidthInWords = (width+15)>>4; + + Data.MapPointer = new Word[Data.WidthInWords*height]; + Register_Pointer(Data.MapPointer); + Data.Size.x = width; + Data.Size.y = height; + Check_Fpu(); +} + +BitMap::BitMap(int width, int height, Word *body) +{ + Check_Pointer(this); + Check_Pointer(body); + + Data.WidthInWords = 0; + Data.Size.x = 0; + Data.Size.y = 0; + + if (width > 0) + { + if (height > 0) + { + int + word_width = (width+15)>>4; + + Data.MapPointer = new Word[word_width * height]; + Register_Pointer(Data.MapPointer); + Data.WidthInWords = word_width; + Data.Size.x = width; + Data.Size.y = height; + + Mem_Copy( + Data.MapPointer, + body, + word_width * height * sizeof(Word), + word_width * height * sizeof(Word) + ); + } +# if DEBUG_LEVEL > 0 + else + { + Warn("BitMap::BitMap has illicit height"); + } +# endif + } +# if DEBUG_LEVEL > 0 + else + { + Warn("BitMap::BitMap has illicit width"); + } +# endif + Check_Fpu(); +} + +BitMap::BitMap(const char *file_name) +{ + Check_Pointer(file_name); + + PCXHeader + header; + Byte + *temp(NULL); + + Data.WidthInWords = 0; + Data.Size.x = 0; + Data.Size.y = 0; + Data.MapPointer = NULL; + + if (PCXRead(file_name, &header, &temp, NULL) == True) + { + if (temp != NULL) + { + Data.Size.x = header.xMax - header.xMin + 1; + Data.Size.y = header.yMax - header.yMin + 1; + Data.WidthInWords = (Data.Size.x + 15) >> 4; + Data.MapPointer = new Word[Data.WidthInWords * Data.Size.y]; + Check_Pointer(Data.MapPointer); + Register_Pointer(Data.MapPointer); + + Byte + *source(temp); + Word + *dest(Data.MapPointer); + Word + bits(0), + bitmask(0x8000); + int + x, + y; + for (y=Data.Size.y; y>0; --y) + { + for (x=Data.Size.x; x>0; --x) + { + if (*source++ != 0) + { + bits |= bitmask; + } + bitmask >>= 1; + if (bitmask == 0) + { + *dest++ = bits; + bitmask = 0x8000; + bits = 0; + } + } + + if (bitmask != 0x8000) + { + *dest++ = bits; + bitmask = 0x8000; + bits = 0; + } + } + Unregister_Pointer(temp); + delete temp; + } + } + Check_Fpu(); +} + +BitMap::BitMap(NotationFile *notation_file, const char *page_name) +{ + Check_Pointer(this); + Check(notation_file); + Check_Pointer(page_name); + + int + x, + y, + width_in_words; + + //----------------------------------------- + // Render bitmap benign in case of failure + //----------------------------------------- + Data.Size.x = 0; + Data.Size.y = 0; + Data.WidthInWords = 0; + Data.MapPointer = NULL; + //-------------------------------------------- + // Attempt to read the x, y, and width values + //-------------------------------------------- + if (!notation_file->GetEntry(page_name, "x", &x)) + { + Warn("BitMap::BitMap notation file: 'x' not found!\n"); + return; + } + Verify(x > 0); + + if (!notation_file->GetEntry(page_name, "y", &y)) + { + Warn("BitMap::BitMap notation file: 'y' not found!\n"); + return; + } + Verify(y > 0); + + if (!notation_file->GetEntry(page_name, "width", &width_in_words)) + { + Warn("BitMap::BitMap notation file: 'width' not found!\n"); + return; + } + //Tell("BitMap::BitMap x=" << x << ", y=" << y << ", width_in_words=" << width_in_words << "\n"); + Verify(x <= (width_in_words << 4)); + + //-------------------------------------------- + // Attempt to allocate the map + //-------------------------------------------- + Data.MapPointer = new Word[width_in_words * y]; + Register_Pointer(Data.MapPointer); + //-------------------------------------------- + // So far, so good! Save the values + //-------------------------------------------- + Data.Size.x = x; + Data.Size.y = y; + Data.WidthInWords = width_in_words; + //-------------------------------------------- + // Read the map data + //-------------------------------------------- + NameList *lines = + notation_file->MakeEntryList(page_name); + Check(lines); + Register_Object(lines); + + NameList::Entry + *line_entry; + const char + *text; + int + collect = 0, + nybble, + nybble_count = 4; + Word + *destination = Data.MapPointer; + + //-------------------------------------------- + // Collect all the entries in the page + //-------------------------------------------- + for ( + line_entry = lines->GetFirstEntry(); + line_entry != NULL; + line_entry = line_entry->GetNextEntry() + ) + { + //-------------------------------------------- + // Get the entry name + //-------------------------------------------- + if ((text=line_entry->GetName()) != NULL) + { + //-------------------------------------------- + // Process only if it's a 'bitmap' entry + //-------------------------------------------- + if (strcmp(text, "bitmap") == 0) + { + //-------------------------------------------- + // Get the entry text + //-------------------------------------------- + text=line_entry->GetChar(); + Verify(text != NULL); + //-------------------------------------------- + // Parse the 'bitmap' entry + //-------------------------------------------- + for ( ; *text != '\0'; ++text) + { + //-------------------------------------------- + // Convert char to hex nybble + //-------------------------------------------- + nybble = toupper(*text); + Verify(isxdigit(nybble)); + + if (nybble > '9') + { + nybble -= ('A' - '9' - 1); + } + nybble -= '0'; + //-------------------------------------------- + // Collect in a word + //-------------------------------------------- + collect = (collect << 4) + nybble; + //-------------------------------------------- + // If a full word is collected, save it + //-------------------------------------------- + --nybble_count; + if (nybble_count <= 0) + { + //-------------------------------------------- + // Verify that we've not gone too far + //-------------------------------------------- + if ((destination-Data.MapPointer) >= (width_in_words*y)) + { + Tell("BitMap::BitMap(notation file) attempted overrun"); + break; + } + //-------------------------------------------- + // Save it, set up for next word + //-------------------------------------------- + *destination++ = (Word) collect; + nybble_count = 4; + collect = 0; + } + } + } + } + } + Unregister_Object(lines); + delete lines; + //-------------------------------------------- + // Make sure we collected the proper + // amount of data- + //-------------------------------------------- +// Verify(nybble_count == 4); +// Verify(word_count == 0); + Check_Fpu(); +} + +BitMap::~BitMap() +{ + Check(this); + + if (Data.MapPointer != NULL) + { + Unregister_Pointer(Data.MapPointer); + delete Data.MapPointer; + Data.Size.x = 0; // safety code + Data.Size.y = 0; + Data.MapPointer = NULL; + } + Check_Fpu(); +} + +Logical + BitMap::TestInstance() const +{ + Verify(Data.Size.x > 0); + Verify(Data.Size.x < 8192); // unreasonably large + Verify(Data.Size.y > 0); + Verify(Data.Size.y < 8192); // unreasonably large + Verify(Data.WidthInWords == ((Data.Size.x + 15) >> 4)); + Check_Pointer(Data.MapPointer); + Check_Fpu(); + return True; +} + +void + BitMap::ShowInstance(char * indent) +{ + Check(this); + + cout << indent << "BitMap:\n"; + char + temp[80]; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "Size =" << Data.Size << "\n"; + cout << temp << "WidthInWords=" << Data.WidthInWords << "\n"; + cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n"; + cout << flush; + + if (Data.MapPointer != NULL) + { + int + x, + y, + bits, + bitmask, + bitwidth; + + Word + *source((Word *) Data.MapPointer); + + for(y=Data.Size.y; y>0; y--) + { + cout << temp; + bitwidth=0; + for(x=Data.WidthInWords; x>0; --x) + { + bits = *source++; + + for(bitmask=0x8000; bitmask!=0; bitmask>>=1) + { + if (++bitwidth > Data.Size.x) + { + cout << "-"; + } + else if (bits & bitmask) + { + cout <<"#"; + } + else + { + cout <<" "; + } + } + } + cout << "\n"; + } + cout << "\n"; + } + Check_Fpu(); +} + +//######################################################################## +//############################### Palette8 ############################### +//######################################################################## + +// +//------------------------------------------------------------------------ +// Output stream operator +//------------------------------------------------------------------------ +// +ostream& operator<<(ostream& Stream, const PaletteTriplet& p) +{ + Check_Fpu(); + return Stream << hex << + (((int) p.Red) & 0xFF) << ':' << + (((int) p.Green) & 0xFF) << ':' << + (((int) p.Blue) & 0xFF) << dec; +} + +Palette8::Palette8() +{ + Check_Pointer(this); + Valid = False; + Check_Fpu(); +} + +Palette8 * + Palette8::Make(const char *name) +{ + Check_Pointer(name); + + char + file_name[80]; + + Str_Copy(file_name, "gauge\\", sizeof(file_name)); + Str_Cat(file_name, name, sizeof(file_name)); + + + Palette8 + *palette = new Palette8(file_name); + Check_Pointer(palette); + if (!palette->Valid) + { + delete palette; + palette = NULL; + } + Check_Fpu(); + return palette; +} + +Palette8 * + Palette8::Make(ResourceDescription::ResourceID /*new_resource_id*/) +{ + Check_Fpu(); + return NULL; // not yet 'resourcified' +} + + + +Palette8::Palette8(int count, PaletteTriplet *source) +{ + Check_Pointer(this); + + int + i; + + Check_Pointer(source); + Verify(count > 0); + Verify(count <= 256); + + for(i=0; i= 0); + Verify(end < 256); + Verify(start <= end); + + for( ; start <= end; ++start) + { + Color[start] = new_color; + } + Check_Fpu(); +} + +void + Palette8::BuildColorRange( + int start, + int end, + PaletteTriplet first_color, + PaletteTriplet last_color + ) +{ + Check(this); + + int + range, + rate_red, + rate_green, + rate_blue, + accum_red, + accum_green, + accum_blue; + + Verify(start >= 0); + Verify(end < 256); + Verify(start <= end); + + range = end - start; + + if (range == 0) + { + Color[start] = first_color; + } + else + { + rate_red = (((int)(last_color.Red - first_color.Red) ) << 5)/range; + rate_green = (((int)(last_color.Green - first_color.Green)) << 5)/range; + rate_blue = (((int)(last_color.Blue - first_color.Blue) ) << 5)/range; + + accum_red = ((int)first_color.Red) << 5; + accum_green = ((int)first_color.Green) << 5; + accum_blue = ((int)first_color.Blue) << 5; + + for( ; start<=end; ++start) + { + Color[start].Red = (Byte) (accum_red >> 5); + Color[start].Green = (Byte) (accum_green >> 5); + Color[start].Blue = (Byte) (accum_blue >> 5); + + accum_red += rate_red; + accum_green += rate_green; + accum_blue += rate_blue; + } + } + Check_Fpu(); +} + +Logical + Palette8::TestInstance() const +{ + return True; +} + +void + Palette8::ShowInstance(char *indent) +{ + Check(this); + + char + temp[80], + buffer[32]; + PaletteTriplet + *source; + int + x, + y; + + cout << indent << "Palette8:\n"; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "Valid =" << Valid << "\n"; + + if (Valid) + { + source = Color; + for(y=0; y<256; y+=4) + { + sprintf(buffer, "%02X= ", y); + cout << temp << buffer; + + for(x=4; x>0; --x) + { + cout << *source++ << " "; + } + cout << "\n"; + } + } + Check_Fpu(); +} + +//######################################################################## +//############################## PixelMap8 ############################### +//######################################################################## +PixelMap8 * + PixelMap8::Make(const char *name) +{ + Check_Pointer(name); + + char + file_name[80]; + + Str_Copy(file_name, "gauge\\", sizeof(file_name)); + Str_Cat(file_name, name, sizeof(file_name)); + + PixelMap8 + *pixelmap = new PixelMap8(file_name); + Check_Pointer(pixelmap); + if (pixelmap->Data.MapPointer == NULL) + { + delete pixelmap; + pixelmap = NULL; + } + else + { + Check(pixelmap); + } + Check_Fpu(); + return pixelmap; +} + +PixelMap8 * + PixelMap8::Make(ResourceDescription::ResourceID /*new_resource_id*/) +{ + Check_Fpu(); + return NULL; // not yet 'resourcified' +} + +PixelMap8::PixelMap8(int width, int height) +{ + Check_Pointer(this); + Verify(width >0); + Verify(height >0); + + Data.Size.x = width; + Data.Size.y = height; + Data.MapPointer = new Byte[width*height]; + Register_Pointer(Data.MapPointer); + Check_Fpu(); +} + +PixelMap8::PixelMap8(const char *file_name) +{ + Check_Pointer(file_name); + PCXHeader + header; + + Data.MapPointer = NULL; + + if (PCXRead(file_name, &header, &Data.MapPointer, NULL) == True) + { + if (Data.MapPointer == NULL) + { + Data.Size.x = 0; + Data.Size.y = 0; + } + else + { + //Data.MapPointer already registered by PCXRead() + Data.Size.x = header.xMax - header.xMin + 1; + Data.Size.y = header.yMax - header.yMin + 1; + } + } + Check_Fpu(); +} + +PixelMap8::~PixelMap8() +{ + Check(this); + + if (Data.MapPointer != NULL) + { + Unregister_Pointer(Data.MapPointer); + delete Data.MapPointer; + Data.Size.x = 0; // safety code + Data.Size.y = 0; + Data.MapPointer = NULL; + } + Check_Fpu(); +} + +Logical + PixelMap8::TestInstance() const +{ + Verify (Data.Size.x >0); + Verify (Data.Size.x < 8192); // an unreasonably large image! + Verify (Data.Size.y >0); + Verify (Data.Size.y < 8192); // an unreasonably large image! + Check_Pointer(Data.MapPointer); + Check_Fpu(); + return True; +} + +void + PixelMap8::ShowInstance(char *indent) +{ + Check(this); + + char + temp[80], + buffer[32]; + Byte + *source; + int + x, + y; + + cout << indent << "PixelMap8:\n"; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "Size =" << Data.Size << "\n"; + cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n"; + + source = Data.MapPointer; + if (source != NULL) + { + for(y=Data.Size.y; y>0; --y) + { + cout << temp; + for(x=Data.Size.x; x>0; --x) + { + sprintf(buffer, "%02X ",*source++); + cout << buffer; + } + cout << "\n"; + } + } + Check_Fpu(); +} + +//######################################################################## +//############################## PixelMap16 ############################## +//######################################################################## +PixelMap16::PixelMap16(int width, int height) +{ + Check_Pointer(this); + Verify(width >0); + Verify(height >0); + + Data.Size.x = width; + Data.Size.y = height; + Data.MapPointer = new Word[width*height]; + Register_Pointer(Data.MapPointer); + + Check_Fpu(); +} + +PixelMap16::PixelMap16(char *) +{ + Fail("PixelMap16::PixelMap16(char *) UNIMPLEMENTED\n"); + Data.MapPointer = NULL; + Data.Size.x = 0; + Data.Size.y = 0; + Check_Fpu(); +} + +PixelMap16::~PixelMap16() +{ + Check(this); + + if (Data.MapPointer != NULL) + { + Unregister_Pointer(Data.MapPointer); + delete Data.MapPointer; + Data.Size.x = 0; // safety code + Data.Size.y = 0; + Data.MapPointer = NULL; + } + Check_Fpu(); +} + +Logical + PixelMap16::TestInstance() const +{ + return True; +} + +void + PixelMap16::ShowInstance(char *indent) +{ + Check(this); + + char + temp[80]; + + cout << indent << "PixelMap16:\n"; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "Size =" << Data.Size << "\n"; + cout << temp << "MapPointer =" << (void *) Data.MapPointer << "\n"; + Check_Fpu(); +} + +//######################################################################## +//########################### GraphicsDisplay ############################ +//######################################################################## +GraphicsDisplay::GraphicsDisplay(int x, int y) +{ + Check_Pointer(this); + Verify(x >0); + Verify(y >0); + + bounds.bottomLeft.x = 0; + bounds.bottomLeft.y = 0; + bounds.topRight.x = x-1; + bounds.topRight.y = y-1; + Check_Fpu(); +} + +GraphicsDisplay::~GraphicsDisplay() +{ + Check(this); + Check_Fpu(); +} + +void + GraphicsDisplay::ShowInstance(char *indent) +{ + Check(this); + cout << indent << "GraphicsDisplay:\n"; + + char + temp[80]; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "bounds =" << bounds << "\n"; + Check_Fpu(); +} + +Logical + GraphicsDisplay::TestInstance() const +{ + return True; +} + +Logical + GraphicsDisplay::Update(Logical) +{ + // no-op for base class + return False; // always returns 'all done' +} + +void + GraphicsDisplay::WaitForUpdate() +{ + // no-op for base class: immediately returns +} + +Rectangle2D + GraphicsDisplay::TextBounds( + Enumeration, + Logical, + GraphicsDisplay::Justification, + char * + ) +{ + Fail("GraphicsDisplay::TextBounds(...) is UNIMPLEMENTED\n"); + + Rectangle2D + r; + Check_Fpu(); + return r; +} + +void + GraphicsDisplay::DrawPoint( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*x*/, + int /*y*/ + ) +{ + Fail("GraphicsDisplay::DrawPoint not overridden"); +} + +void + GraphicsDisplay::DrawLine( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*x1*/, + int /*y1*/, + int /*x2*/, + int /*y2*/, + Logical /*include_last_pixel*/ + ) +{ + Fail("GraphicsDisplay::DrawLine not overridden"); +} + +void + GraphicsDisplay::DrawFilledRectangle( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*x1*/, + int /*y1*/, + int /*x2*/, + int /*y2*/ + ) +{ + Fail("GraphicsDisplay::DrawFilledRectangle not overridden"); +} + +void + GraphicsDisplay::DrawText( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + Logical /*opaque*/, + int /*rotation*/, + Enumeration /*fontNumber*/, + Logical /*vertical*/, + GraphicsDisplay::Justification /*justification*/, + Rectangle2D * /*clippingRectanglePtr*/, + char * /*stringPointer*/ + ) +{ + Fail("GraphicsDisplay::DrawText not overridden"); +} + +void + GraphicsDisplay::DrawBitMap( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + BitMap * /*bitmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsDisplay::DrawBitMap not overridden"); +} + +void + GraphicsDisplay::DrawBitMapOpaque( + int /*color*/, + int /*background*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + BitMap * /*bitmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsDisplay::DrawBitMapOpaque not overridden"); +} + +void + GraphicsDisplay::DrawPixelMap8( + int * /*translation_table*/, + int /*bitmask*/, + Enumeration /*operation*/, + Logical /*opaque*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + PixelMap8 * /*pixelmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsDisplay::DrawPixelMap8 not overridden"); +} + +void + GraphicsDisplay::DrawPixelMap8SingleColor( + int /*color*/, + int /*bitmask*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + PixelMap8 * /*pixelmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsDisplay::DrawPixelMap8SingleColor not overridden"); +} + +//######################################################################## +//############################ GraphicsPort ############################## +//######################################################################## +GraphicsPort::GraphicsPort( + GraphicsDisplay *graphics_display, + const char *new_name +) +{ + Check_Pointer(this); + + if (graphics_display != NULL) + { + Check(graphics_display); + bounds = graphics_display->bounds; + } + else + { + bounds.bottomLeft.x = 0; + bounds.bottomLeft.y = 0; + bounds.topRight.x = 0; + bounds.topRight.y = 0; + } + graphicsDisplay = graphics_display; + + Str_Copy(name, new_name, sizeof(name)); + Check_Fpu(); +} + +GraphicsPort::~GraphicsPort() +{ + Check(this); + Check_Fpu(); +} + +Logical + GraphicsPort::TestInstance() const +{ + return True; +} + +void + GraphicsPort::ShowInstance(char *indent) +{ + Check(this); + + cout << indent << "GraphicsPort:\n"; + + char + temp[80]; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "bounds =" << bounds << "\n"; + cout << temp << "graphicsDisplay=" << graphicsDisplay << "\n"; + cout << flush; + Check_Fpu(); +} + +Rectangle2D + GraphicsPort::TextBounds( + Enumeration fontNumber, + Logical vertical, + GraphicsDisplay::Justification justification, + char *stringPointer + ) +{ + Check(this); + Check(graphicsDisplay); // HACK!!!! Check for NULL! + + Check_Fpu(); + return + graphicsDisplay-> + TextBounds( + fontNumber, + vertical, + justification, + stringPointer + ); +} + +void + GraphicsPort::SetColor( + PaletteTriplet * /*source_color*/, + int /*color_index*/ + ) +{ + Fail("GraphicsPort::SetColor not overridden"); +} + +void + GraphicsPort::DrawPoint( + int /*color*/, + Enumeration /*operation*/, + int /*x*/, + int /*y*/ + ) +{ + Fail("GraphicsPort::DrawPoint not overridden"); +} + +void + GraphicsPort::DrawLine( + int /*color*/, + Enumeration /*operation*/, + int /*x1*/, + int /*y1*/, + int /*x2*/, + int /*y2*/, + Logical /*include_last_pixel*/ + ) +{ + Fail("GraphicsPort::DrawLine not overridden"); +} + +void + GraphicsPort::DrawFilledRectangle( + int /*color*/, + Enumeration /*operation*/, + int /*x1*/, + int /*y1*/, + int /*x2*/, + int /*y2*/ + ) +{ + Fail("GraphicsPort::DrawFilledRectangle not overridden"); +} + +void + GraphicsPort::DrawText( + int /*color*/, + Enumeration /*operation*/, + Logical /*opaque*/, + int /*rotation*/, + Enumeration /*fontNumber*/, + Logical /*vertical*/, + GraphicsDisplay::Justification /*justification*/, + Rectangle2D * /*clippingRectanglePtr*/, + char * /*stringPointer*/ + ) +{ + Fail("GraphicsPort::DrawText not overridden"); +} + +void + GraphicsPort::DrawBitMap( + int /*color*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + BitMap * /*bitmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsPort::DrawBitMap not overridden"); +} + +void + GraphicsPort::DrawBitMapOpaque( + int /*color*/, + int /*background*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + BitMap * /*bitmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsPort::DrawBitMapOpaque not overridden"); +} + +void + GraphicsPort::DrawPixelMap8( + Enumeration /*operation*/, + Logical /*opaque*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + PixelMap8 * /*pixelmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsPort::DrawPixelMap8 not overridden"); +} + +void + GraphicsPort::DrawPixelMap8SingleColor( + int /*color*/, + Enumeration /*operation*/, + int /*rotation*/, + int /*x*/, + int /*y*/, + PixelMap8 * /*pixelmap*/, + int /*sx1*/, + int /*sy1*/, + int /*sx2*/, + int /*sy2*/ // these are SOURCE coordinates + ) +{ + Fail("GraphicsPort::DrawPixelMap8SingleColor not overridden"); +} + +//######################################################################## +//######################### GraphicsViewRecord ########################### +//######################################################################## +GraphicsViewRecord::GraphicsViewRecord() +{ + Check_Pointer(this); + + commandListLength = 4096; + commandListIndex = 0; + commandList = new char[commandListLength]; + Register_Pointer(commandList); + link = NULL; + Check_Fpu(); +} + +GraphicsViewRecord::~GraphicsViewRecord() +{ + Check(this); + + if (link != NULL) + { + Check(link); + Unregister_Object(link); + delete link; + link = NULL; // safety code + } + + if (commandList != NULL) + { + Unregister_Pointer(commandList); + delete commandList; + commandList = NULL; // safety code + } + Check_Fpu(); +} + +Logical + GraphicsViewRecord::TestInstance() const +{ + return True; +} + +void + GraphicsViewRecord::Clear() +{ + Check(this); + + if (link != NULL) + { + Check(link); + link->Clear(); + } + + commandListIndex = 0; + Check_Fpu(); +} + +void + GraphicsViewRecord::Draw(GraphicsView *graphics_view, int forced_color) +{ + Check(this); + + GraphicsPort + *graphics_port(graphics_view->graphicsPort); + if (graphics_port == NULL) + { + Clear(); + return; + } + + PixelMap8 + *pixelmap_pointer; + BitMap + *bitmap_pointer; + + int + running=1, + color, bg, + op, + x1, y1, x2, y2, + sx1, sy1, sx2, sy2, + rot, q; + + //-------------------------------------------------------------- + // Mark end of list, rewind to beginning + //-------------------------------------------------------------- + PutChar(GraphicsViewRecord::endCommand); + Clear(); + //-------------------------------------------------------------- + // Parse the command stream + //-------------------------------------------------------------- + while(running) + { + switch(GetChar()) + { + case endCommand: + running = 0; + break; + +#define RECORDER_POINT(recorder, color, op, x1, y1) \ + if (recorder != NULL) \ + { \ + recorder->PutChar(GraphicsViewRecord::pointCommand); \ + recorder->PutShort(color); \ + recorder->PutChar(op); \ + recorder->PutShort(x1); \ + recorder->PutShort(y1); \ + } + case pointCommand: + color = GetShort(); + op = GetChar(); + x1 = GetShort(); + y1 = GetShort(); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawPoint(color, op, x1, y1); + break; + +#define RECORDER_LINE(recorder, color, op, x1, y1, x2, y2, endpoint) \ + if (recorder != NULL) \ + { \ + recorder->PutChar(GraphicsViewRecord::lineCommand); \ + recorder->PutShort(color); \ + recorder->PutChar(op); \ + recorder->PutShort(x1); \ + recorder->PutShort(y1); \ + recorder->PutShort(x2); \ + recorder->PutShort(y2); \ + recorder->PutLogical(endpoint); \ + } + case lineCommand: + color = GetShort(); + op = GetChar(); + x1 = GetShort(); + y1 = GetShort(); + x2 = GetShort(); + y2 = GetShort(); + q = GetLogical(); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawLine(color, op, x1, y1, x2, y2, q); + break; + +#define RECORDER_FRECT(recorder, color, op, x1, y1, x2, y2) \ + if (recorder != NULL) \ + { \ + recorder->PutChar(GraphicsViewRecord::frectCommand); \ + recorder->PutShort(color); \ + recorder->PutChar(op); \ + recorder->PutShort(x1); \ + recorder->PutShort(y1); \ + recorder->PutShort(x2); \ + recorder->PutShort(y2); \ + } + case frectCommand: + color = GetShort(); + op = GetChar(); + x1 = GetShort(); + y1 = GetShort(); + x2 = GetShort(); + y2 = GetShort(); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawFilledRectangle(color, op, x1, y1, x2, y2); + break; + +#define RECORDER_BITMAP(r, color, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \ + if (r != NULL) \ + { \ + r->PutChar(GraphicsViewRecord::bitmapCommand); \ + r->PutShort(color); \ + r->PutChar(op); \ + r->PutShort(rot); \ + r->PutShort(x1); \ + r->PutShort(y1); \ + r->PutPointer(p); \ + r->PutShort(sx1); \ + r->PutShort(sy1); \ + r->PutShort(sx2); \ + r->PutShort(sy2); \ + } + case bitmapCommand: + color = GetShort(); + op = GetChar(); + rot = GetShort(); + x1 = GetShort(); + y1 = GetShort(); + bitmap_pointer = (BitMap *) GetPointer(); + sx1 = GetShort(); + sy1 = GetShort(); + sx2 = GetShort(); + sy2 = GetShort(); + + Check(bitmap_pointer); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawBitMap( + color, + op, + rot, + x1, y1, + bitmap_pointer, + sx1, sy1, sx2, sy2 + ); + break; + +#define RECORDER_BITMAP_OPAQUE( \ + r, fg, bg, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \ + if (r != NULL) \ + { \ + r->PutChar(GraphicsViewRecord::bitmapOpaqueCommand); \ + r->PutShort(fg); \ + r->PutShort(bg); \ + r->PutChar(op); \ + r->PutShort(rot); \ + r->PutShort(x1); \ + r->PutShort(y1); \ + r->PutPointer(p); \ + r->PutShort(sx1); \ + r->PutShort(sy1); \ + r->PutShort(sx2); \ + r->PutShort(sy2); \ + } + case bitmapOpaqueCommand: + color = GetShort(); + bg = GetShort(); + op = GetChar(); + rot = GetShort(); + x1 = GetShort(); + y1 = GetShort(); + bitmap_pointer = (BitMap *) GetPointer(); + sx1 = GetShort(); + sy1 = GetShort(); + sx2 = GetShort(); + sy2 = GetShort(); + + Check(bitmap_pointer); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawBitMapOpaque( + color, + bg, + op, + rot, + x1, y1, + bitmap_pointer, + sx1, sy1, sx2, sy2 + ); + break; + +#define RECORDER_PIXELMAP( \ + r, op, q, rot, x1, y1, p, sx1, sy1, sx2, sy2) \ + if (r != NULL) \ + { \ + r->PutChar(GraphicsViewRecord::pixelmap8Command); \ + r->PutChar(op); \ + r->PutShort(q); \ + r->PutShort(rot); \ + r->PutShort(x1); \ + r->PutShort(y1); \ + r->PutPointer(p); \ + r->PutShort(sx1); \ + r->PutShort(sy1); \ + r->PutShort(sx2); \ + r->PutShort(sy2); \ + } + case pixelmap8Command: + op = GetChar(); + q = GetShort(); + rot = GetShort(); + x1 = GetShort(); + y1 = GetShort(); + pixelmap_pointer = (PixelMap8 *) GetPointer(); + sx1 = GetShort(); + sy1 = GetShort(); + sx2 = GetShort(); + sy2 = GetShort(); + + Check(pixelmap_pointer); + + if (forced_color != -1) + { + graphics_port->DrawPixelMap8SingleColor( + forced_color, + op, + rot, + x1, y1, + pixelmap_pointer, + sx1, sy1, sx2, sy2 + ); + } + else + { + graphics_port->DrawPixelMap8( + op, + q, + rot, + x1, y1, + pixelmap_pointer, + sx1, sy1, sx2, sy2 + ); + } + break; + +#define RECORDER_PIXELMAP_SINGLE_COLOR( \ + r, color, op, rot, x1, y1, p, sx1, sy1, sx2, sy2) \ + if (r != NULL) \ + { \ + r->PutChar(GraphicsViewRecord::pixelmap8SolidCommand); \ + r->PutShort(color); \ + r->PutChar(op); \ + r->PutShort(rot); \ + r->PutShort(x1); \ + r->PutShort(y1); \ + r->PutPointer(p); \ + r->PutShort(sx1); \ + r->PutShort(sy1); \ + r->PutShort(sx2); \ + r->PutShort(sy2); \ + } + case pixelmap8SolidCommand: + color = GetShort(); + op = GetChar(); + rot = GetShort(); + x1 = GetShort(); + y1 = GetShort(); + pixelmap_pointer = (PixelMap8 *) GetPointer(); + sx1 = GetShort(); + sy1 = GetShort(); + sx2 = GetShort(); + sy2 = GetShort(); + + Check(pixelmap_pointer); + + if (forced_color != -1) + { + color = forced_color; + } + graphics_port->DrawPixelMap8SingleColor( + color, + op, + rot, + x1, y1, + pixelmap_pointer, + sx1, sy1, sx2, sy2 + ); + break; + } + } + Check_Fpu(); +} + +void + GraphicsViewRecord::PutChar(int value) +{ + Check(this); + //-------------------------------------------------------------- + // If the buffer is not full, jam it in + //-------------------------------------------------------------- + if (commandListIndex < commandListLength) + { + commandList[commandListIndex++] = (char) value; + } + //-------------------------------------------------------------- + // If the buffer IS full, put it in the 'next' linked buffer + //-------------------------------------------------------------- + else + { + //-------------------------------------------------------------- + // If there is no linked buffer, create one + //-------------------------------------------------------------- + if (link == NULL) + { + link = new GraphicsViewRecord(); + Check(link); + Register_Object(link); + } + //-------------------------------------------------------------- + // Give it to the linked buffer + //-------------------------------------------------------------- + link->PutChar(value); + } + Check_Fpu(); +} + +int + GraphicsViewRecord::GetChar() +{ + Check(this); + //-------------------------------------------------------------- + // If the buffer is not empty, pull the char out + //-------------------------------------------------------------- + if (commandListIndex < commandListLength) + { + Check_Fpu(); + return (int) commandList[commandListIndex++]; + } + //-------------------------------------------------------------- + // If the buffer IS empty, get char from the 'next' linked buffer + //-------------------------------------------------------------- + else + { + //-------------------------------------------------------------- + // If there is no linked buffer, it's a catastrophe + //-------------------------------------------------------------- + if (link == NULL) + { + Fail("GraphicsViewRecord::GetChar() has no link"); + Check_Fpu(); + return GraphicsViewRecord::endCommand; + } + //-------------------------------------------------------------- + // Read from the linked buffer + //-------------------------------------------------------------- + Check(link); + Check_Fpu(); + return link->GetChar(); + } +} + +void + GraphicsViewRecord::PutLogical(Logical value) +{ + Check(this); + if (value) + { + PutChar(1); + } + else + { + PutChar(0); + } + Check_Fpu(); +} + +Logical + GraphicsViewRecord::GetLogical() +{ + Check(this); + Check_Fpu(); + if (GetChar()) + { + return True; + } + else + { + return False; + } +} + +void + GraphicsViewRecord::PutShort(int value) +{ + Check(this); + PutChar(value >> 8); + PutChar(value); + Check_Fpu(); +} + +int + GraphicsViewRecord::GetShort() +{ + Check(this); + int + q; + + q = GetChar() << 8; + q |= GetChar() & 0xFF; + + if (q & 0x8000) // extend sign + { + q |= 0xFFFF0000; + } + + Check_Fpu(); + return q; +} + +void + GraphicsViewRecord::PutPointer(void *pointer) +{ + Check(this); + Verify(pointer != NULL); + union + { + void *pointer; + int value; // assumes 32-bit integer! + } + faker; + + faker.pointer = pointer; + + PutChar(faker.value >> 24); + PutChar(faker.value >> 16); + PutChar(faker.value >> 8); + PutChar(faker.value); + Check_Fpu(); +} + + +void * + GraphicsViewRecord::GetPointer() +{ + Check(this); + union + { + void *pointer; + int value; // assumes 32-bit integer! + } + faker; + + faker.value = GetChar() << 24; + faker.value |= (GetChar() & 0xFF) << 16; + faker.value |= (GetChar() & 0xFF) << 8; + faker.value |= GetChar() & 0xFF; + + Verify(faker.pointer != NULL); + Check_Fpu(); + return faker.pointer; +} + +//######################################################################## +//############################ GraphicsView ############################## +//######################################################################## +GraphicsView::GraphicsView( + GraphicsPort *graphics_port, + int x1, int y1, int x2, int y2 +) +{ + Check_Pointer(this); + // NOTE: graphics_port may be NULL! + + //-------------------------------------------------------------- + // Initialize values + //-------------------------------------------------------------- + graphicsPort = graphics_port; + + currentPosition.x = 0; + currentPosition.y = 0; + currentFontID = 0; + currentColor = 1; + currentOperation = GraphicsDisplay::Replace; + + //-------------------------------------------------------------- + // Set areaWithinPort + //-------------------------------------------------------------- + if (graphics_port == NULL) + { + //-------------------------------------------------------------- + // GraphicsPort doesn't exist, set areaWithinPort to safe value + //-------------------------------------------------------------- + areaWithinPort.bottomLeft.x = 0; + areaWithinPort.bottomLeft.y = 0; + areaWithinPort.topRight.x = 0; + areaWithinPort.topRight.y = 0; + + origin = areaWithinPort.bottomLeft; + } + else + { + //-------------------------------------------------------------- + // Set areaWithinPort to given size + //-------------------------------------------------------------- + areaWithinPort.bottomLeft.x = x1; + areaWithinPort.bottomLeft.y = y1; + areaWithinPort.topRight.x = x2; + areaWithinPort.topRight.y = y2; + //-------------------------------------------------------------- + // Adjust area according to graphicsPort offset + //-------------------------------------------------------------- + areaWithinPort.bottomLeft += graphicsPort->bounds.bottomLeft; + areaWithinPort.topRight += graphicsPort->bounds.bottomLeft; + //-------------------------------------------------------------- + // Set origin to bottom left corner of area + //-------------------------------------------------------------- + origin = areaWithinPort.bottomLeft; + //-------------------------------------------------------------- + // Clip to graphicsPort bounds + //-------------------------------------------------------------- + areaWithinPort.Intersection(areaWithinPort, graphicsPort->bounds); + } + //-------------------------------------------------------------- + // Set clipping rectangle to size of view + //-------------------------------------------------------------- + clippingRectangle = areaWithinPort; + //-------------------------------------------------------------- + // Clear recorder pointer + //-------------------------------------------------------------- + recorder = (GraphicsViewRecord *) NULL; + Check_Fpu(); +} + +GraphicsView::GraphicsView(GraphicsPort *graphics_port) +{ + Check_Pointer(this); + + // NOTE: graphics_port may be NULL! + //-------------------------------------------------------------- + // Initialize values + //-------------------------------------------------------------- + graphicsPort = graphics_port; + + currentPosition.x = 0; + currentPosition.y = 0; + currentFontID = 0; + currentColor = 1; + currentOperation = GraphicsDisplay::Replace; + //-------------------------------------------------------------- + // Set areaWithinPort + //-------------------------------------------------------------- + if (graphics_port == NULL) + { + //-------------------------------------------------------------- + // GraphicsPort doesn't exist, set areaWithinPort to safe value + //-------------------------------------------------------------- + areaWithinPort.bottomLeft.x = 0; + areaWithinPort.bottomLeft.y = 0; + areaWithinPort.topRight.x = 0; + areaWithinPort.topRight.y = 0; + } + else + { + //-------------------------------------------------------------- + // Set areaWithinPort to size of graphicsPort + //-------------------------------------------------------------- + areaWithinPort = graphics_port->bounds; + } + //-------------------------------------------------------------- + // Set origin to bottom left corner of area + //-------------------------------------------------------------- + origin = areaWithinPort.bottomLeft; + //-------------------------------------------------------------- + // Set clipping rectangle to size of view + //-------------------------------------------------------------- + clippingRectangle = areaWithinPort; + //-------------------------------------------------------------- + // Clear recorder pointer + //-------------------------------------------------------------- + recorder = (GraphicsViewRecord *) NULL; + Check_Fpu(); +} + +GraphicsView::~GraphicsView() +{ + Check(this); + Check_Fpu(); +} + +void + GraphicsView::SetPositionWithinPort(int x1, int y1, int x2, int y2) +{ +# if defined(DEBUG) + Tell( + "GraphicsView::SetPositionWithinPort(" << x1 << + "," << y1 << + ", " << x2 << + "," << y2 << + "\n" + ); +# endif + Check(this); + Verify (x2 > x1); + Verify (y2 > y1); + + if (graphicsPort != NULL) + { + //-------------------------------------------------------------- + // Set the new area + //-------------------------------------------------------------- + areaWithinPort.bottomLeft.x = x1; + areaWithinPort.bottomLeft.y = y1; + areaWithinPort.topRight.x = x2-1; + areaWithinPort.topRight.y = y2-1; + //-------------------------------------------------------------- + // Adjust area according to graphicsPort offset + //-------------------------------------------------------------- + areaWithinPort.bottomLeft += graphicsPort->bounds.bottomLeft; + areaWithinPort.topRight += graphicsPort->bounds.bottomLeft; + //-------------------------------------------------------------- + // Set new origin + //-------------------------------------------------------------- + origin = areaWithinPort.bottomLeft; + //-------------------------------------------------------------- + // Clip to graphicsPort bounds + //-------------------------------------------------------------- + areaWithinPort.Intersection(areaWithinPort, graphicsPort->bounds); + //-------------------------------------------------------------- + // Set clipping rectangle to size of view + //-------------------------------------------------------------- + clippingRectangle = areaWithinPort; + } +# if defined(DEBUG) + Tell( + "areaWithinPort=" << areaWithinPort << + "\n" + ); +# endif + Check_Fpu(); +} + +Logical + GraphicsView::TestInstance() const +{ + return True; +} + +void + GraphicsView::ShowInstance(char *indent) +{ + Check(this); + + cout << indent << "GraphicsView:\n"; + + char + temp[80]; + + Str_Copy(temp, indent, 80); + Str_Cat(temp, "...", 80); + + cout << temp << "areaWithinPort =" << areaWithinPort << "\n"; + cout << temp << "origin =" << origin << "\n"; + cout << temp << "currentPosition =" << currentPosition << "\n"; + cout << temp << "currentFontID =" << currentFontID << "\n"; + cout << temp << "currentColor =" << currentColor << "\n"; + cout << temp << "clippingRectangle =" << clippingRectangle << "\n"; + cout << temp << "currentOperation ="; + switch(currentOperation) + { + case GraphicsDisplay::And: cout << "AND\n"; break; + case GraphicsDisplay::Or: cout << "OR\n"; break; + case GraphicsDisplay::Replace: cout << "REPLACE\n"; break; + default: cout << "Unsupported type:" << currentOperation << "\n"; break; + } + cout << temp << "graphicsPort =" << graphicsPort << "\n"; + Check_Fpu(); +} + +void + GraphicsView::SetOperation(GraphicsDisplay::Operation new_operation) +{ + Check(this); + currentOperation = new_operation; + Check_Fpu(); +} + +void + GraphicsView::SetOrigin(int x, int y) +{ +# if defined(DEBUG) + Tell( + "GraphicsView::SetOrigin(" << x << + "," << y << + "\n" + ); +# endif + Check(this); + //-------------------------------------------------------------- + // Adjust the current position + //-------------------------------------------------------------- + currentPosition -= origin; + //-------------------------------------------------------------- + // Set the new origin + //-------------------------------------------------------------- + origin.x = x + areaWithinPort.bottomLeft.x; + origin.y = y + areaWithinPort.bottomLeft.y; + //-------------------------------------------------------------- + // Adjust the current position to the new location + //-------------------------------------------------------------- + currentPosition += origin; +# if defined(DEBUG) + Tell( + "origin=" << origin << + ", currentPosition=" << currentPosition << + "\n" + ); +# endif + Check_Fpu(); +} + +void + GraphicsView::SetFont(Enumeration new_font_ID) +{ + Check(this); + + currentFontID = new_font_ID; + Check_Fpu(); +} + +void + GraphicsView::SetColor(int new_color) +{ + Check(this); + + currentColor = new_color; + Check_Fpu(); +} + +void + GraphicsView::SetClippingRectangle(Rectangle2D *clippingRectanglePtr) +{ + Check(this); + Check(clippingRectanglePtr); + + Rectangle2D r; + //-------------------------------------------------------------- + // Get a copy of the requested clipping rectangle, + // add origin offset + //-------------------------------------------------------------- + r = *clippingRectanglePtr; + r.bottomLeft += origin; + r.topRight += origin; + //-------------------------------------------------------------- + // Limit it to the graphicsPort bounds, save the result + //-------------------------------------------------------------- + if (graphicsPort != NULL) + { + clippingRectangle.Intersection(graphicsPort->bounds, r); + } + else + { + clippingRectangle.MakeEmpty(); + } + Check_Fpu(); +} + +void + GraphicsView::ClearClippingRectangle() +{ + Check(this); + + clippingRectangle = areaWithinPort; + Check_Fpu(); +} + +void + GraphicsView::MoveToAbsolute(int x, int y) +{ + Check(this); + + currentPosition.x = origin.x + x; + currentPosition.y = origin.y + y; + Check_Fpu(); +} + +void + GraphicsView::MoveToRelative(int x, int y) +{ + Check(this); + + currentPosition.x += x; + currentPosition.y += y; + Check_Fpu(); +} + +void + GraphicsView::DrawPoint() +{ + Check(this); + + int code(BuildPointCode(currentPosition)); + + if (graphicsPort != NULL) + { + if (code == GraphicsView::IsWithin) + { + graphicsPort-> + DrawPoint( + currentColor, + currentOperation, + currentPosition.x, currentPosition.y + ); + + RECORDER_POINT( + recorder, + currentColor, + currentOperation, + currentPosition.x, currentPosition.y + ); + } + } + Check_Fpu(); +} + +void + GraphicsView::DrawLineToAbsolute(int x, int y) +{ + Check(this); + + Vector2DOf + end; + + end.x = origin.x + x; + end.y = origin.y + y; + DrawLine(currentPosition, end, True); + currentPosition = end; + Check_Fpu(); +} + +void + GraphicsView::DrawLineToRelative(int x, int y) +{ + Check(this); + + Vector2DOf + end; + + end.x = currentPosition.x + x; + end.y = currentPosition.y + y; + DrawLine(currentPosition, end, True); + currentPosition = end; + Check_Fpu(); +} + +void + GraphicsView::DrawThickLineToAbsolute(int x, int y) +{ + Check(this); + + Vector2DOf + end, + start, + stop; + + end.x = origin.x + x; + end.y = origin.y + y; + + start.x = currentPosition.x; + start.y = currentPosition.y; + stop.x = end.x; + stop.y = end.y; + DrawThickLine(start, stop); + + currentPosition = end; + Check_Fpu(); +} + +void + GraphicsView::DrawThickLineToRelative(int x, int y) +{ + Check(this); + + Vector2DOf + end, + start, + stop; + + end.x = currentPosition.x + x; + end.y = currentPosition.y + y; + + start.x = currentPosition.x; + start.y = currentPosition.y; + stop.x = end.x; + stop.y = end.y; + DrawThickLine(start, stop); + + currentPosition = end; + Check_Fpu(); +} + +void + GraphicsView::DrawRectangleToAbsolute(int x, int y) +{ + Check(this); + + Vector2DOf + home; + + home = currentPosition; + home -= origin; + DrawLineToAbsolute(home.x, y); + DrawLineToAbsolute(x, y); + DrawLineToAbsolute(x, home.y); + DrawLineToAbsolute(home.x, home.y); + + currentPosition.x = x; + currentPosition.y = y; + Check_Fpu(); +} + +void + GraphicsView::DrawRectangleToRelative(int x, int y) +{ + Check(this); + + Vector2DOf + home; + + home = currentPosition; + home -= origin; + DrawLineToRelative(0, y); + DrawLineToRelative(x, 0); + DrawLineToRelative(0, -y); + DrawLineToRelative(-x, 0); + + currentPosition.x = home.x + x; + currentPosition.y = home.y + y; + Check_Fpu(); +} + +void + GraphicsView::DrawFilledRectangleToAbsolute(int x, int y) +{ + Check(this); + + Rectangle2D r; + + r.bottomLeft = currentPosition; + r.topRight.x = origin.x + x; + r.topRight.y = origin.y + y; + + DrawFilledRectangle(r); + + currentPosition = r.topRight; + Check_Fpu(); +} + +void + GraphicsView::DrawFilledRectangleToRelative(int x, int y) +{ + Check(this); + + Rectangle2D r; + + r.bottomLeft = currentPosition; + r.topRight.x = currentPosition.x + x; + r.topRight.y = currentPosition.y + y; + + DrawFilledRectangle(r); + + currentPosition = r.topRight; + Check_Fpu(); +} + +void + GraphicsView::DrawText( + Logical , + Logical , + GraphicsDisplay::Justification , + Rectangle2D *, + char * + ) +{ + Check(this); + Check_Fpu(); +} + +void + GraphicsView::DrawBitMap( + int rotation, + BitMap *bitmap, + int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates + ) +{ + Check(this); + + Rectangle2D sourceBounds(sx1, sy1, sx2, sy2); + Vector2DOf position; + + if (bitmap != NULL) + { + Check(bitmap); + + if (ClipImage(&sourceBounds, &position, bitmap->Data.Size)) + { + graphicsPort-> + DrawBitMap( + currentColor, + currentOperation, + rotation, + position.x, position.y, + bitmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + RECORDER_BITMAP( + recorder, + currentColor, + currentOperation, + rotation, + position.x, position.y, + bitmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + } + } + Check_Fpu(); +} + +void + GraphicsView::DrawBitMapOpaque( + int background, + int rotation, + BitMap *bitmap, + int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates + ) +{ + Check(this); + + Rectangle2D sourceBounds(sx1, sy1, sx2, sy2); + Vector2DOf position; + + if (bitmap != NULL) + { + Check(bitmap); + + if (ClipImage(&sourceBounds, &position, bitmap->Data.Size)) + { + graphicsPort-> + DrawBitMapOpaque( + currentColor, + background, + currentOperation, + rotation, + position.x, position.y, + bitmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + RECORDER_BITMAP_OPAQUE( + recorder, + currentColor, + background, + currentOperation, + rotation, + position.x, position.y, + bitmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + } + } + Check_Fpu(); +} + +void + GraphicsView::DrawPixelMap8( + Logical opaque, + int rotation, + PixelMap8 *pixelmap, + int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates + ) +{ + Check(this); + + Rectangle2D sourceBounds(sx1, sy1, sx2, sy2); + Vector2DOf position; + + if (pixelmap != NULL) + { + Check(pixelmap); + + if (ClipImage(&sourceBounds, &position, pixelmap->Data.Size)) + { + graphicsPort-> + DrawPixelMap8( + currentOperation, + opaque, + rotation, + position.x, position.y, + pixelmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + RECORDER_PIXELMAP( + recorder, + currentOperation, + opaque, + rotation, + position.x, position.y, + pixelmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + } + } + Check_Fpu(); +} + +void + GraphicsView::DrawPixelMap8SingleColor( + int rotation, + PixelMap8 *pixelmap, + int sx1, int sy1, int sx2, int sy2 // these are SOURCE coordinates + ) +{ + Check(this); + + Rectangle2D sourceBounds(sx1, sy1, sx2, sy2); + Vector2DOf position; + + if (pixelmap != NULL) + { + Check(pixelmap); + + if (ClipImage(&sourceBounds, &position, pixelmap->Data.Size)) + { + graphicsPort-> + DrawPixelMap8SingleColor( + currentColor, + currentOperation, + rotation, + position.x, position.y, + pixelmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + RECORDER_PIXELMAP_SINGLE_COLOR( + recorder, + currentColor, + currentOperation, + rotation, + position.x, position.y, + pixelmap, + sourceBounds.bottomLeft.x, sourceBounds.bottomLeft.y, + sourceBounds.topRight.x, sourceBounds.topRight.y + ); + } + } + Check_Fpu(); +} + +void + GraphicsView::SetColor( + PaletteTriplet *source_color, + int color_index + ) +{ + Check(this); + Check_Pointer(source_color); + + if (graphicsPort != NULL) + { + graphicsPort->SetColor(source_color, color_index); + } + Check_Fpu(); +} + +void + GraphicsView::AttachRecorder(GraphicsViewRecord *graphics_view_record) +{ + Check(this); + Verify(recorder == NULL); + Check(graphics_view_record); + recorder = graphics_view_record; + Check_Fpu(); +} + +void + GraphicsView::DetachRecorder() +{ + Check(this); + recorder = NULL; + Check_Fpu(); +} + +int + GraphicsView::BuildPointCode(Vector2DOf vector) +{ + // This is static. Don't attempt to check for signature! + + int result(0); + + if (vector.x < clippingRectangle.bottomLeft.x) + { + result |= GraphicsView::IsLeft; + } + else if (vector.x > clippingRectangle.topRight.x) + { + result |= GraphicsView::IsRight; + } + + if (vector.y < clippingRectangle.bottomLeft.y) + { + result |= GraphicsView::IsBelow; + } + else if (vector.y > clippingRectangle.topRight.y) + { + result |= GraphicsView::IsAbove; + } + Check_Fpu(); + return result; +} + +void + GraphicsView::DrawThickLine( + Vector2DOf start, + Vector2DOf stop + ) +{ + Check(this); + + DrawLine(start, stop, True); + --start.x; + --stop.x; + DrawLine(start, stop, True); + ++start.x; + ++stop.x; + ++start.y; + ++stop.y; + DrawLine(start, stop, True); + ++start.x; + ++stop.x; + --start.y; + --stop.y; + DrawLine(start, stop, True); + --start.x; + --stop.x; + --start.y; + --stop.y; + DrawLine(start, stop, True); + + Check_Fpu(); +} + +void + GraphicsView::DrawLine( + Vector2DOf start, + Vector2DOf end, + Logical include_last_pixel + ) +{ +# if defined(DEBUG) + Tell( + "DrawLine(=" << start << + ", " << end << + ", " << include_last_pixel << + ")\n" + ); + Tell( + "clippingRectangle=" << clippingRectangle << + "\n" + ); +# endif + Check(this); + + int + start_code, + end_code; + + Logical + swapped(False), + start_clipped(False), + end_clipped(False); + + if (graphicsPort != NULL) + { + //---------------------------------------------------- + // Generate endpoint codes + //---------------------------------------------------- + start_code = BuildPointCode(start); + end_code = BuildPointCode(end); +# if defined(DEBUG) + Tell( + "start code=" << start_code << + ", end_code=" << end_code << + "\n" + ); +# endif + + //---------------------------------------------------- + // Loop until either both codes are zero + // or it's completely out of the display + //---------------------------------------------------- + while(start_code | end_code) + { +# if defined(DEBUG) + Tell( + "Clipping, start=" << start << + ", end=" << end << + "\n" + ); +# endif + //---------------------------------------------------- + // If the line is totally off the display, abandon it + //---------------------------------------------------- + if ((start_code & end_code) != 0) + { +# if defined(DEBUG) + Tell("Abandoned\n"); +# endif + return; + } + //---------------------------------------------------- + // Make sure an out-of-bounds point is being clipped + //---------------------------------------------------- + if (start_code == GraphicsView::IsWithin) + { +# if defined(DEBUG) + Tell("Swapping endpoints\n"); +# endif + + Vector2DOf + temp_vector; + temp_vector = start; + start = end; + end = temp_vector; + + int temp_code; + temp_code = start_code; + start_code = end_code; + end_code = temp_code; + + Logical temp_flag; + temp_flag = start_clipped; + start_clipped = end_clipped; + end_clipped = temp_flag; + + swapped ^= True; + } + //---------------------------------------------------- + // Clip the starting segment + //---------------------------------------------------- + if (start_code & GraphicsView::IsLeft) + { +# if defined(DEBUG) + Tell("Clip left\n"); +# endif + Verify(end.x != start.x); + start.y += (end.y - start.y) * + (clippingRectangle.bottomLeft.x-start.x) / (end.x-start.x); + Check_Fpu(); + start.x = clippingRectangle.bottomLeft.x; + + start_clipped = True; + } + else if (start_code & GraphicsView::IsRight) + { +# if defined(DEBUG) + Tell("Clip right\n"); +# endif + Verify(end.x != start.x); + start.y += (end.y - start.y) * + (clippingRectangle.topRight.x-start.x) / (end.x-start.x); + Check_Fpu(); + start.x = clippingRectangle.topRight.x; + + start_clipped = True; + } + else if (start_code & GraphicsView::IsAbove) + { +# if defined(DEBUG) + Tell("Clip above\n"); +# endif + Verify(end.y != start.y); + start.x += (end.x - start.x) * + (clippingRectangle.topRight.y-start.y) / (end.y-start.y); + Check_Fpu(); + start.y = clippingRectangle.topRight.y; + + start_clipped = True; + } + else if (start_code & GraphicsView::IsBelow) + { +# if defined(DEBUG) + Tell("Clip below\n"); +# endif + Verify(end.y != start.y); + start.x += (end.x - start.x) * + (clippingRectangle.bottomLeft.y-start.y) / (end.y-start.y); + Check_Fpu(); + start.y = clippingRectangle.bottomLeft.y; + + start_clipped = True; + } + //---------------------------------------------------- + // Build a new point code for the starting point, + // loop until line is either in or out. + //---------------------------------------------------- + start_code = BuildPointCode(start); + } +# if defined(DEBUG) + Tell( + "Clipping done, start=" << start << + ", end=" << end << + "\n" + ); +# endif + //---------------------------------------------------- + // If swapped, flip them back + //---------------------------------------------------- + if (swapped) + { +# if defined(DEBUG) + Tell("Swapping back\n"); +# endif + Vector2DOf + temp_vector; + temp_vector = start; + start = end; + end = temp_vector; + + Logical temp_flag; + temp_flag = start_clipped; + start_clipped = end_clipped; + end_clipped = temp_flag; + } + //---------------------------------------------------- + // If the endpoint was clipped, include the final pixel + //---------------------------------------------------- + if (end_clipped) + { +# if defined(DEBUG) + Tell("End was clipped, including last pixel\n"); +# endif + include_last_pixel = True; + } + //---------------------------------------------------- + // Finally, draw the line! + //---------------------------------------------------- +# if defined(DEBUG) + Tell( + "All done, start=" << start << + ", end=" << end << + "\n" + ); +# endif + + Verify(BuildPointCode(start) == 0); + Verify(BuildPointCode(end) == 0); + + graphicsPort->DrawLine( + currentColor, + currentOperation, + start.x, start.y, + end.x, end.y, + include_last_pixel + ); + + RECORDER_LINE( + recorder, + currentColor, + currentOperation, + start.x, start.y, + end.x, end.y, + include_last_pixel + ); + } + Check_Fpu(); +} + +void + GraphicsView::DrawFilledRectangle(Rectangle2D r) +{ + Check(this); + if (graphicsPort != NULL) + { + // + // Swap X positions if needed + // + if (r.bottomLeft.x > r.topRight.x) + { + int temp; + + temp = r.bottomLeft.x; + r.bottomLeft.x = r.topRight.x; + r.topRight.x = temp; + } + // + // Swap Y positions if needed + // + if (r.bottomLeft.y > r.topRight.y) + { + int temp; + + temp = r.bottomLeft.y; + r.bottomLeft.y = r.topRight.y; + r.topRight.y = temp; + } + // + // Clip to clipping rectangle + // + r.Intersection(clippingRectangle, r); + // + // Draw if non-empty + // + if (! r.IsEmpty()) + { + graphicsPort-> + DrawFilledRectangle( + currentColor, + currentOperation, + r.bottomLeft.x, r.bottomLeft.y, r.topRight.x, r.topRight.y + ); + RECORDER_FRECT( + recorder, + currentColor, + currentOperation, + r.bottomLeft.x, r.bottomLeft.y, r.topRight.x, r.topRight.y + ); + } + } + Check_Fpu(); +} + +Logical + GraphicsView::ClipImage( + Rectangle2D *sourceRect, + Vector2DOf *position, + Vector2DOf imageLimits + ) +{ + Check(this); + + if (graphicsPort != NULL) + { + Rectangle2D + destRect; + + Vector2DOf + source_origin, + source_size; + + // + // clip sourceRect to image limits + // + if (sourceRect->bottomLeft.x < 0) + { + sourceRect->bottomLeft.x = 0; + } + if (sourceRect->topRight.x >= imageLimits.x) + { + sourceRect->topRight.x = imageLimits.x-1; + } + + if (sourceRect->bottomLeft.y < 0) + { + sourceRect->bottomLeft.y = 0; + } + if (sourceRect->topRight.y >= imageLimits.y) + { + sourceRect->topRight.y = imageLimits.y-1; + } + + source_origin = sourceRect->bottomLeft; + source_size = sourceRect->topRight; + source_size -= sourceRect->bottomLeft; + + // + // build corresponding rectangle in port space + // + destRect.bottomLeft = currentPosition; + destRect.topRight = currentPosition; + destRect.topRight += source_size; + // + // now, clip the rectangle + // + Rectangle2D r; + r = destRect; + destRect.Intersection(r, clippingRectangle); + // + // draw if non-empty + // + if (! destRect.IsEmpty()) + { + // + // Set position + // + *position = destRect.bottomLeft; + // + // return rectangle to image space + // + source_size = destRect.topRight; + source_size -= destRect.bottomLeft; + + sourceRect->bottomLeft = source_origin; + sourceRect->topRight = source_origin; + sourceRect->topRight += source_size; + Check_Fpu(); + return True; + } + } + Check_Fpu(); + return False; +} diff --git a/restoration/source410/MUNGA/NETWORK.CPP b/restoration/source410/MUNGA/NETWORK.CPP index e4ed6dfc..a67d9e19 100644 --- a/restoration/source410/MUNGA/NETWORK.CPP +++ b/restoration/source410/MUNGA/NETWORK.CPP @@ -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 -#pragma hdrstop - -#if !defined(NETWORK_HPP) -# include -#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 +# endif +#pragma hdrstop + +# if !defined(HOSTMGR_HPP) +# include +# endif +# if !defined(INTEREST_HPP) +# include +# endif +# if !defined(ICOM_HPP) +# include +# endif +# if !defined(APP_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# endif +# if !defined(NTTMGR_HPP) +# include +# 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 "<clientID<<" gameID "<gameID<<" fromHost "<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!"); +} diff --git a/restoration/source410/MUNGA/OBJSTRM.CPP b/restoration/source410/MUNGA/OBJSTRM.CPP new file mode 100644 index 00000000..79d22090 --- /dev/null +++ b/restoration/source410/MUNGA/OBJSTRM.CPP @@ -0,0 +1,1217 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(OBJSTRM_HPP) +# include +# endif +# if !defined(FILEUTIL_HPP) +# include +# endif +# if !defined(RESOURCE_HPP) +# include +# endif +# if !defined(CSTR_HPP) +# include +# endif +# if !defined(NAMELIST_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# endif + +//############################################################################# +//########################## ObjectStream ############################### +//############################################################################# + +ObjectID ObjectStream::lastObjectID = NullObjectID; + +// +//############################################################################# +// ObjectStream +//############################################################################# +// +ObjectStream::ObjectStream() +{ + resourceFile = NULL; + macroSocket = NULL; +} + +// +//############################################################################# +// ObjectStream +//############################################################################# +// +ObjectStream::ObjectStream( + void *stream_start, + size_t stream_size +): + DynamicMemoryStream(stream_start, stream_size) +{ + resourceFile = NULL; + macroSocket = NULL; +} + +// +//############################################################################# +// ObjectStream +//############################################################################# +// +ObjectStream::ObjectStream(ResourceDescription *resource_description): + DynamicMemoryStream( + resource_description->resourceAddress, + resource_description->resourceSize + ) +{ + resourceFile = NULL; + macroSocket = NULL; +} + +// +//############################################################################# +// ~ObjectStream +//############################################################################# +// +ObjectStream::~ObjectStream() +{ + Verify(resourceFile == NULL); + Verify(macroSocket == NULL); +} + +// +//############################################################################# +// TestInstance +//############################################################################# +// +Logical + ObjectStream::TestInstance() const +{ + DynamicMemoryStream::TestInstance(); + if (resourceFile != NULL) + { + Check(resourceFile); + } + if (macroSocket != NULL) + { + Check(macroSocket); + } + return True; +} + +// +//############################################################################# +// MakeUniqueObjectID +//############################################################################# +// +ObjectID + ObjectStream::MakeUniqueObjectID() +{ + lastObjectID++; + Verify(lastObjectID < ULONG_MAX); + return lastObjectID; +} + +// +//############################################################################# +// CreateObjects +//############################################################################# +// +void + ObjectStream::CreateObjects() +{ + Check(this); + + // + //-------------------------------------------------------------------------- + // While the stream is not empty, read objects... + //-------------------------------------------------------------------------- + // + while (GetBytesRemaining() > 0L) + { + // + //----------------------------------------------------------------------- + // Read the class ID and object ID + //----------------------------------------------------------------------- + // + Enumeration class_ID; + ObjectID object_ID; + + MemoryStream_Read(this, &class_ID); + MemoryStream_Read(this, &object_ID); + RewindPointer(sizeof(object_ID)); + RewindPointer(sizeof(class_ID)); + + Verify(class_ID != RegisteredClass::NullClassID); + Verify(object_ID != NullObjectID); + + // + //----------------------------------------------------------------------- + // Read the object + //----------------------------------------------------------------------- + // + RegisteredClass *object = MakeObjectImplementation(class_ID); + Register_Object(object); + + // + //----------------------------------------------------------------------- + // Perform post creation processing + //----------------------------------------------------------------------- + // + CreatedObjectImplementation(object, object_ID); + } +} + +// +//############################################################################# +// MakeObject +//############################################################################# +// +RegisteredClass* + ObjectStream::MakeObjectImplementation(Enumeration class_ID) +{ + Check(this); + Verify(class_ID != RegisteredClass::NullClassID); + + // + //----------------------------------------------------------------------- + // HACK - Constructors should be referenced through registration, for + // now just use a switch statement + //----------------------------------------------------------------------- + // + RegisteredClass *object = NULL; + + switch (class_ID) + { + default: + Dump(class_ID); + Fail("ObjectStream::MakeObject - Unknown class ID"); + break; + } + return object; +} + +// +//############################################################################# +// CreatedObject +//############################################################################# +// +void + ObjectStream::CreatedObjectImplementation( + RegisteredClass*, + ObjectID + ) +{ + Check(this); + + // + // Default behavior is to do nothing + // +} + +// +//############################################################################# +// BuildFromNotationFile +//############################################################################# +// +void + ObjectStream::BuildFromNotationFile( + NotationFile *notation_file, + ResourceFile *resource_file + ) +{ + Check(this); + Check(notation_file); + Check(resource_file); + + // + // Remember resource file + // + Verify(resourceFile == NULL); + resourceFile = resource_file; + + // + // Make the macro socket + // + macroSocket = new MacroSocket(NULL, True); + Register_Object(macroSocket); + + // + // Parse... + // + ParseNotationFile(notation_file); + + // + // Delete macros + // + { + MacroIterator iterator(macroSocket); + iterator.DeletePlugs(); + } + + // + // Clean up + // + Unregister_Object(macroSocket); + delete macroSocket; + macroSocket = NULL; + resourceFile = NULL; +} + +// +//############################################################################# +// ParseNotationFile +//############################################################################# +// +void + ObjectStream::ParseNotationFile(NotationFile *notation_file) +{ + Check(this); + Check(notation_file); + Verify(DoesNotationFileExist(notation_file)); + + // + //-------------------------------------------------------------------------- + // Parse pages + //-------------------------------------------------------------------------- + // + NameList *page_name_list; + NameList::Entry *page_entry; + + page_name_list = notation_file->MakePageList(); + Register_Object(page_name_list); + page_entry = page_name_list->GetFirstEntry(); + while (page_entry != NULL) + { + Check(page_entry); + + // + //----------------------------------------------------------------------- + // Read the page name + //----------------------------------------------------------------------- + // + CString inculde_name_string("include"); + CString macro_name_string("macro"); + CString page_name_string; + + Check_Pointer(page_entry->GetName()); + page_name_string = page_entry->GetName(); + + // + //----------------------------------------------------------------------- + // Skip "no-ops" + //----------------------------------------------------------------------- + // + if (page_name_string.operator [](0) == '!') + { + page_entry = page_entry->GetNextEntry(); + continue; + } + + // + //----------------------------------------------------------------------- + // Make the entry list + //----------------------------------------------------------------------- + // + NameList *entry_list = + notation_file->MakeEntryList( + (NotationFile::NotePage*)page_entry->GetData() + ); + Register_Object(entry_list); + + // + //----------------------------------------------------------------------- + // Read "included" files + //----------------------------------------------------------------------- + // + if (page_name_string == inculde_name_string) + { + ReadIncludedFiles(entry_list); + } + + // + //----------------------------------------------------------------------- + // Read "macros" + //----------------------------------------------------------------------- + // + else if (page_name_string == macro_name_string) + { + ReadMacros(entry_list); + } + + // + //----------------------------------------------------------------------- + // Read the class ID and object name + //----------------------------------------------------------------------- + // + else + { + Tell(" Class " << page_name_string << "\n"); + + // + // Get class ID and object ID + // + Enumeration class_ID; + ObjectID object_ID; + + class_ID = RegisteredClass::GetClassID(page_name_string); + if (class_ID == RegisteredClass::NullClassID) + { + Dump(page_name_string); + Dump(class_ID); + } + Verify(class_ID != RegisteredClass::NullClassID); + object_ID = MakeUniqueObjectID(); + Verify(object_ID != NullObjectID); + + // + // Get object name + // + const char *object_name; + CString object_name_string; + + PerformMacroReplacement(entry_list); + if ( + (object_name = (const char *)entry_list->FindData("name")) != NULL + ) + { + object_name_string = object_name; + } + Check(&object_name_string); + + // + //-------------------------------------------------------------------- + // Build the object stream from the page + //-------------------------------------------------------------------- + // + BuildFromPageImplementation(entry_list, class_ID, object_ID); + CleanupMacroReplacement(entry_list); + + // + //-------------------------------------------------------------------- + // Perform post build processing + //-------------------------------------------------------------------- + // + BuiltFromPageImplementation(class_ID, object_ID, object_name_string); + } + + Unregister_Object(entry_list); + delete entry_list; + page_entry = page_entry->GetNextEntry(); + } + + Unregister_Object(page_name_list); + delete page_name_list; +} + +// +//############################################################################# +// ReadIncludedFiles +//############################################################################# +// +void + ObjectStream::ReadIncludedFiles(NameList *entry_list) +{ + Check(this); + NameList::Entry *entry; + + Check(entry_list); + entry = entry_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->IsName("file")) + { + Check_Pointer(entry->GetChar()); + + CString included_file_name_string; + included_file_name_string = entry->GetChar(); + Tell(" File " << included_file_name_string << "\n"); + + NotationFile included_notation_file(included_file_name_string); + Check(&included_notation_file); + ParseNotationFile(&included_notation_file); + } + entry = entry->GetNextEntry(); + } +} + +// +//############################################################################# +// ReadMacros +//############################################################################# +// +void + ObjectStream::ReadMacros(NameList *entry_list) +{ + Check(this); + NameList::Entry *entry; + + Check(entry_list); + entry = entry_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->GetData() != NULL) + { + Check_Pointer(entry->GetName()); + Check_Pointer(entry->GetChar()); + + CString macro_name; + MacroValue *macro_value; + MacroValue *current_macro_value; + + macro_name = entry->GetName(); + macro_value = new MacroValue(entry->GetChar()); + Register_Object(macro_value); + + Check(macroSocket); + if ((current_macro_value = macroSocket->Find(macro_name)) != NULL) + { + Unregister_Object(current_macro_value); + delete current_macro_value; + } + macroSocket->AddValue(macro_value, macro_name); + } + entry = entry->GetNextEntry(); + } +} + +// +//############################################################################# +// PerformMacroReplacement +//############################################################################# +// +void + ObjectStream::PerformMacroReplacement(NameList *entry_list) +{ + Check(this); + NameList::Entry *entry; + + Check(entry_list); + entry = entry_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->GetData() != NULL) + { + CString value_string(entry->GetChar()); + + // + // Create a replacement string by matching each token in the + // value against the tokens in the macro table + // + CString replacement_string; + CString token_string; + CString delimiter_string(","); + CString empty_string; + int i = 0; + + Check(&value_string); + Check(&empty_string); + while ((token_string = value_string.GetNthToken(i)) != empty_string) + { + Check(&token_string); + + // + // Append delimter + // + if (replacement_string != empty_string) + { + replacement_string += delimiter_string; + } + + // + // Does a macro exist for this token? If so, use it, otherwise + // use the original token + // + #if 0 + MacroValue *macro_value; + + Check(macroSocket); + if ((macro_value = macroSocket->Find(token_string)) != NULL) + { + Check(macro_value); + Check(&replacement_string); + replacement_string += macro_value->GetItem(); + } + else + { + replacement_string += token_string; + } + #else + replacement_string += DeriveMacroValue(token_string); + #endif + i++; + } + + // + // Allocate memory for the string and assign it to the entry + // + size_t size; + char *pointer; + + size = replacement_string.Length() + 1; +#if 0 + pointer = (char*)malloc(size); +#else + pointer = new char[size]; +#endif + Register_Pointer(pointer); + Str_Copy(pointer, ((const char*)replacement_string), size); + entry->dataReference = pointer; + } + entry = entry->GetNextEntry(); + } +} + +// +//############################################################################# +//############################################################################# +// +CString + ObjectStream::DeriveMacroValue(const CString &token_string) +{ + Check(this); + Check(&token_string); + + MacroValue *macro_value; + CString replacement_string = token_string; + + Check(macroSocket); + while ((macro_value = macroSocket->Find(replacement_string)) != NULL) + { + Check(macro_value); + replacement_string = macro_value->GetItem(); + } + return replacement_string; +} + +// +//############################################################################# +// CleanupMacroReplacement +//############################################################################# +// +void + ObjectStream::CleanupMacroReplacement(NameList *entry_list) +{ + Check(this); + NameList::Entry *entry; + + Check(entry_list); + entry = entry_list->GetFirstEntry(); + while (entry != NULL) + { + Check(entry); + if (entry->GetData() != NULL) + { + char *replacement_string = entry->GetChar(); + + Unregister_Pointer(replacement_string); +#if 0 + free(replacement_string); +#else + delete[] replacement_string; +#endif + } + entry = entry->GetNextEntry(); + } +} + +// +//############################################################################# +// BuildFromPage +//############################################################################# +// +void + ObjectStream::BuildFromPageImplementation( + NameList*, + Enumeration class_ID, + ObjectID + ) +{ + Check(this); + Verify(class_ID != RegisteredClass::NullClassID); + + // + //----------------------------------------------------------------------- + // HACK - Page interpreters should be referenced through registration, + // for now just use a switch statement + //----------------------------------------------------------------------- + // + switch (class_ID) + { + default: + Dump(class_ID); + Fail("ObjectStream::BuildFromPage - Unknown class ID"); + break; + } +} + +// +//############################################################################# +// BuiltFromPage +//############################################################################# +// +void + ObjectStream::BuiltFromPageImplementation( + Enumeration, + ObjectID, + const CString& + ) +{ + Check(this); + + // + // Default behavior is to do nothing + // +} + +//############################################################################# +//####################### PlugStreamManager ############################# +//############################################################################# + +PlugStreamManager PlugStreamManager::plugStreamManager; + +#define PLUGSTREAMMANAGER_HASHSIZE (500) + +// +//############################################################################# +// PlugStreamManager +//############################################################################# +// +PlugStreamManager::PlugStreamManager(): + plugIndex(PLUGSTREAMMANAGER_HASHSIZE, NULL, True), + objectIDIndex(NULL, True) +{ +} + +// +//############################################################################# +// ~PlugStreamManager +//############################################################################# +// +PlugStreamManager::~PlugStreamManager() +{ + Cleanup(); +} + +// +//############################################################################# +// TestInstance +//############################################################################# +// +Logical + PlugStreamManager::TestInstance() const +{ + Node::TestInstance(); + Check(&plugIndex); + Check(&objectIDIndex); + return True; +} + +// +//############################################################################# +// Cleanup +//############################################################################# +// +void + PlugStreamManager::Cleanup() +{ + Check(this); + + // + // Delete static objects + // + { + TreeIteratorOf iterator(&objectIDIndex); + + Check(&iterator); + iterator.DeletePlugs(); + } + { + HashIteratorOf iterator(&plugIndex); + + Check(&iterator); + iterator.DeletePlugs(); + } +} + +// +//############################################################################# +// AddPlug +//############################################################################# +// +void + PlugStreamManager::AddPlug( + Plug *plug, + ObjectID object_ID + ) +{ + Check(plug); + Check(&plugStreamManager); + plugStreamManager.plugIndex.AddValue(plug, object_ID); +} + +// +//############################################################################# +// FindPlug +//############################################################################# +// +Plug* + PlugStreamManager::FindPlug(ObjectID object_ID) +{ + Check(&plugStreamManager); + return plugStreamManager.plugIndex.Find(object_ID); +} + +// +//############################################################################# +// AddPlugName +//############################################################################# +// +void + PlugStreamManager::AddPlugName( + ObjectID object_ID, + const CString &object_name_string + ) +{ + Check(&object_name_string); + + ObjectIDPlug *object_ID_plug = + new ObjectIDPlug(object_ID); + Register_Object(object_ID_plug); + + Check(&plugStreamManager.objectIDIndex); + #if DEBUG_LEVEL>0 + if (plugStreamManager.objectIDIndex.Find(object_name_string) != NULL) + { + Dump(object_name_string); + } + #endif + plugStreamManager.objectIDIndex.AddValue( + object_ID_plug, + object_name_string + ); +} + +// +//############################################################################# +// FindPlugName +//############################################################################# +// +ObjectID + PlugStreamManager::FindPlugName(const CString &object_name_string) +{ + Check(&object_name_string); + Check(&plugStreamManager.objectIDIndex); + ObjectIDPlug *plug = plugStreamManager.objectIDIndex.Find(object_name_string); + if (plug != NULL) + { + Check(plug); + return plug->GetItem(); + } + return NullObjectID; +} + +//############################################################################# +//########################### PlugStream ################################ +//############################################################################# + +// +//############################################################################# +// PlugStream +//############################################################################# +// +PlugStream::PlugStream() +{ + localPlugIndex = NULL; + localObjectIDIndex = NULL; +} + +// +//############################################################################# +// PlugStream +//############################################################################# +// +PlugStream::PlugStream( + void *stream_start, + size_t stream_size +): + ObjectStream(stream_start, stream_size) +{ + localPlugIndex = NULL; + localObjectIDIndex = NULL; +} + +// +//############################################################################# +// PlugStream +//############################################################################# +// +PlugStream::PlugStream(ResourceDescription *resource_description): + ObjectStream(resource_description) +{ + localPlugIndex = NULL; + localObjectIDIndex = NULL; +} + +// +//############################################################################# +// ~PlugStream +//############################################################################# +// +PlugStream::~PlugStream() +{ + Verify(localPlugIndex == NULL); + Verify(localObjectIDIndex == NULL); +} + +// +//############################################################################# +// TestInstance +//############################################################################# +// +Logical + PlugStream::TestInstance() const +{ + ObjectStream::TestInstance(); + if (localPlugIndex != NULL) + { + Check(localPlugIndex); + } + if (localObjectIDIndex != NULL) + { + Check(localObjectIDIndex); + } + return True; +} + +// +//############################################################################# +// CreateObjects +//############################################################################# +// +void + PlugStream::CreateObjects() +{ + Check(this); + + // + //-------------------------------------------------------------------------- + // Keep local object address index + //-------------------------------------------------------------------------- + // + LocalPlugIndex + local_index(NULL, True); + + Check(&local_index); + localPlugIndex = &local_index; + + // + //-------------------------------------------------------------------------- + // Parse object stream + //-------------------------------------------------------------------------- + // + ObjectStream::CreateObjects(); + + // + //-------------------------------------------------------------------------- + // Forget local object address index + //-------------------------------------------------------------------------- + // + localPlugIndex = NULL; +} + +// +//############################################################################# +// CreatedObject +//############################################################################# +// +void + PlugStream::CreatedObjectImplementation( + RegisteredClass *object, + ObjectID object_ID + ) +{ + Check(this); + AddLocalPlug(Cast_Object(Plug*, object), object_ID); +} + +// +//############################################################################# +// AddLocalPlugAddress +//############################################################################# +// +void + PlugStream::AddLocalPlug( + Plug *plug, + ObjectID object_ID + ) +{ + Check(this); + Check(localPlugIndex); + localPlugIndex->AddValue(plug, object_ID); +} + +// +//############################################################################# +// AddGlobalPlugAddress +//############################################################################# +// +void + PlugStream::AddGlobalPlug( + Plug *plug, + ObjectID object_ID + ) +{ + Check(this); + #if 0 + Check(&plugStreamManager); + plugStreamManager.globalPlugIndex.AddValue(plug, object_ID); + #else + PlugStreamManager::AddPlug(plug, object_ID); + #endif +} + +// +//############################################################################# +// FindPlug +//############################################################################# +// +Plug* + PlugStream::FindPlug(ObjectID object_ID) +{ + Check(this); + + // + //-------------------------------------------------------------------------- + // Search the local address index + //-------------------------------------------------------------------------- + // + Plug *plug; + + Check(localPlugIndex); + if ((plug = localPlugIndex->Find(object_ID)) != NULL) + { + Check(plug); + return plug; + } + + // + //-------------------------------------------------------------------------- + // Search the global address index + //-------------------------------------------------------------------------- + // + #if 0 + Check(&plugStreamManager); + if ((plug = plugStreamManager.globalPlugIndex.Find(object_ID)) != NULL) + { + Check(plug); + return plug; + } + return NULL; + #else + if ((plug = PlugStreamManager::FindPlug(object_ID)) != NULL) + { + Check(plug); + return plug; + } + return NULL; + #endif +} + +// +//############################################################################# +// BuildFromNotationFile +//############################################################################# +// +void + PlugStream::BuildFromNotationFile( + NotationFile *notation_file, + ResourceFile *resource_file + ) +{ + Check(this); + Check(notation_file); + Check(resource_file); + + // + //-------------------------------------------------------------------------- + // Keep local object ID index + //-------------------------------------------------------------------------- + // + LocalObjectIDIndex + local_index(NULL, True); + + Check(&local_index); + localObjectIDIndex = &local_index; + + // + //-------------------------------------------------------------------------- + // Parse notation file + //-------------------------------------------------------------------------- + // + ObjectStream::BuildFromNotationFile(notation_file, resource_file); + + // + //-------------------------------------------------------------------------- + // Forget local object ID index + //-------------------------------------------------------------------------- + // + { + VChainIteratorOf iterator(&local_index); + Check(&iterator); + iterator.DeletePlugs(); + } + localObjectIDIndex = NULL; +} + +// +//############################################################################# +// BuiltFromPage +//############################################################################# +// +void + PlugStream::BuiltFromPageImplementation( + Enumeration, + ObjectID object_ID, + const CString &object_name_string + ) +{ + Check(this); + Check(&object_name_string); + AddLocalObjectID(object_ID, object_name_string); +} + +// +//############################################################################# +// AddLocalObjectID +//############################################################################# +// +void + PlugStream::AddLocalObjectID( + ObjectID object_ID, + const CString &object_name_string + ) +{ + Check(this); + Check(&object_name_string); + + ObjectIDPlug *object_ID_plug = + new ObjectIDPlug(object_ID); + Register_Object(object_ID_plug); + + Check(localObjectIDIndex); + #if DEBUG_LEVEL>0 + if (localObjectIDIndex->Find(object_name_string) != NULL) + { + Dump(object_name_string); + } + #endif + localObjectIDIndex->AddValue(object_ID_plug, object_name_string); +} + +// +//############################################################################# +// AddGlobalObjectID +//############################################################################# +// +void + PlugStream::AddGlobalObjectID( + ObjectID object_ID, + const CString &object_name_string + ) +{ + Check(this); + Check(&object_name_string); + + PlugStreamManager::AddPlugName(object_ID, object_name_string); +} + +// +//############################################################################# +// FindObjectID +//############################################################################# +// +ObjectID + PlugStream::FindObjectID(const CString &object_name_string) +{ + Check(this); + Check(&object_name_string); + + // + //-------------------------------------------------------------------------- + // Search the local object ID index + //-------------------------------------------------------------------------- + // + ObjectIDPlug *plug; + + Check(localObjectIDIndex); + if ((plug = localObjectIDIndex->Find(object_name_string)) != NULL) + { + Check(plug); + return plug->GetItem(); + } + + // + //-------------------------------------------------------------------------- + // Search the global address index + //-------------------------------------------------------------------------- + // + #if 0 + Check(&plugStreamManager); + plug = plugStreamManager.globalObjectIDIndex.Find(object_name_string); + if (plug != NULL) + { + Check(plug); + return plug->GetItem(); + } + return NULL; + #else + return PlugStreamManager::FindPlugName(object_name_string); + #endif +} + +// +//############################################################################# +// PlugStream_FindEntryAndWriteObjectID +//############################################################################# +// +void + PlugStream_FindEntryAndWriteObjectID( + PlugStream *stream, + NameList *name_list, + const CString &entry_name + ) +{ + Check(stream); + Check(name_list); + Check(&entry_name); + + void *entry_data; + CString object_name; + ObjectID object_ID; + + entry_data = name_list->FindData(entry_name); + if (entry_data == NULL) + { + cout << "PlugStream_FindEntryAndWriteObjectID - entry_name == "; + cout << entry_name << "\n"; + Fail("PlugStream_FindEntryAndWriteObjectID - entry_data == NULL"); + } + Check_Pointer(entry_data); + object_name = (const char *)entry_data; + + Check(stream); + object_ID = stream->FindObjectID(object_name); + if (object_ID == NullObjectID) + { + cout << "PlugStream_FindEntryAndWriteObjectID - object_name == "; + cout << object_name << "\n"; + Fail("PlugStream_FindEntryAndWriteObjectID - object_ID == NullObjectID"); + } + Verify(object_ID != NullObjectID); + MemoryStream_Write(stream, &object_ID); +} diff --git a/restoration/source410/MUNGA/RAY.CPP b/restoration/source410/MUNGA/RAY.CPP new file mode 100644 index 00000000..245f35cf --- /dev/null +++ b/restoration/source410/MUNGA/RAY.CPP @@ -0,0 +1,176 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(RAY_HPP) +# include +# endif +# if !defined(PLANE_HPP) +# include +# endif +# if !defined(SPHERE_HPP) +# include +# 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 (*penetrationAddScaled(origin1, velocity1, *time); + result2->AddScaled(origin2, velocity2, *time); + d = closest.Length(); + Check_Fpu(); + return d; +} + +#if defined(TEST_CLASS) +# include "ray.tcp" +#endif diff --git a/restoration/source410/MUNGA/RESOURCE.CPP b/restoration/source410/MUNGA/RESOURCE.CPP new file mode 100644 index 00000000..c12061fc --- /dev/null +++ b/restoration/source410/MUNGA/RESOURCE.CPP @@ -0,0 +1,916 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(RESOURCE_HPP) +# include +# endif +# if !defined(RESVER_HPP) +# include +# 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; iLoadResource(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) + { + // + //---------------------------------------- + // 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 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; iGetBytesUsed(); + 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> 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> 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; iresourceAddress, 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 diff --git a/restoration/source410/MUNGA/SCNROLE.CPP b/restoration/source410/MUNGA/SCNROLE.CPP new file mode 100644 index 00000000..291ed888 --- /dev/null +++ b/restoration/source410/MUNGA/SCNROLE.CPP @@ -0,0 +1,243 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(SCNROLE_HPP) +# include +# endif +# if !defined(APP_HPP) +# include +# endif +# if !defined(NOTATION_HPP) +# include +# 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; + } +} diff --git a/restoration/source410/MUNGA/STUBS.CPP b/restoration/source410/MUNGA/STUBS.CPP new file mode 100644 index 00000000..3979ec49 --- /dev/null +++ b/restoration/source410/MUNGA/STUBS.CPP @@ -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 +#pragma hdrstop + +#include + +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() +{ +} diff --git a/restoration/source410/MUNGA/VERIFY.CPP b/restoration/source410/MUNGA/VERIFY.CPP new file mode 100644 index 00000000..975d00a9 --- /dev/null +++ b/restoration/source410/MUNGA/VERIFY.CPP @@ -0,0 +1,204 @@ +# if !defined(MUNGA_HPP) +# include +# endif +#pragma hdrstop + +# if !defined(CONTROLS_HPP) +# include +# endif +# if !defined(GAUGREND_HPP) +# include +# 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 diff --git a/restoration/source410/MUNGA_L4/L4APP.CPP b/restoration/source410/MUNGA_L4/L4APP.CPP index 4a420e53..8e45a2f0 100644 --- a/restoration/source410/MUNGA_L4/L4APP.CPP +++ b/restoration/source410/MUNGA_L4/L4APP.CPP @@ -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 -#pragma hdrstop - -#if !defined(L4APP_HPP) -# include -#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 +# endif +#pragma hdrstop + +# if !defined(CAMSHIP_HPP) +# include +# endif +# if !defined(APPMSG_HPP) +# include +# endif +# if !defined(L4APP_HPP) +# include +# endif +# if !defined(L4CTRL_HPP) +# include +# endif +# if !defined(L4ICOM_HPP) +# include +# endif +# if !defined(L4VIDEO_HPP) +# include +# endif +# if !defined(L4AUDRND_HPP) +# include +# endif +# if !defined(L4GREND_HPP) +# include +# endif +# if !defined(L4NET_HPP) +# include +# endif +# if !defined(L4MPPR_HPP) +# include +# endif +# if !defined(PLAYER_HPP) +# include +# endif +# if !defined(MISSION_HPP) +# include +# 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 -net -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 *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 diff --git a/restoration/source410/MUNGA_L4/L4NET.CPP b/restoration/source410/MUNGA_L4/L4NET.CPP new file mode 100644 index 00000000..38117cad --- /dev/null +++ b/restoration/source410/MUNGA_L4/L4NET.CPP @@ -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 +#pragma hdrstop + +#if !defined(L4NET_HPP) +# include +#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"); +} diff --git a/restoration/source410/backdate.py b/restoration/source410/backdate.py index d7daa60e..762ca764 100644 --- a/restoration/source410/backdate.py +++ b/restoration/source410/backdate.py @@ -75,7 +75,7 @@ def main(): line = re.sub(r"(?", "", ""): if bad in line and "#include" in line: line = "" break diff --git a/restoration/source410/build410.sh b/restoration/source410/build410.sh index 3be72d14..b06c0754 100644 --- a/restoration/source410/build410.sh +++ b/restoration/source410/build410.sh @@ -52,7 +52,7 @@ srcfor() { # srcfor [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 < 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