Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)

Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.

Layout:
  engine/   MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
            work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
            models) + image codec; the minimal rp/ headers the audio HAL needs
  game/     reconstructed BT logic + surviving-original BT source + fwd shims
            + WinMain launcher
  content/  full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
  docs/     format specs + reconstruction ledgers
  reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
  tools/    MP console emulator + map/resource scanners

One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-05 21:03:40 -05:00
co-authored by Claude Opus 4.8
commit 7b7d465e5e
4192 changed files with 604371 additions and 0 deletions
+40
View File
@@ -0,0 +1,40 @@
#pragma once
enum dpl_TYPE
{
dpl_type_error,
dpl_type_scene,
dpl_type_zones,
dpl_type_view,
dpl_type_instance,
dpl_type_dcs,
dpl_type_light,
dpl_type_object,
dpl_type_lod,
dpl_type_geogroup,
dpl_type_geometry,
dpl_type_material,
dpl_type_texture,
dpl_type_texmap,
dpl_type_ramp
};
class dpl_OBJECT {};
class dpl_DCS {};
class dpl_ZONE {};
class dpl_PARTICLESTART_EFFECT_INFO {};
class dpl_VIEW {};
class dpl_INSTANCE {};
class dpl_GEOGROUP {};
class dpl_GEOMETRY {};
class dpl_LIGHT {};
class dpl_LIGHT_TYPE {};
class dpl_LOAD_MODE {};
class dpl_ISECT_MODE {};
class dpl_TEXTURE {};
class dpl_MATERIAL {};
class dpl_TEXMAP {};
class dpl_EXPLOSION_EFFECT_INFO {};
class dpl2d_DISPLAY {};
class dpl2d_MATRIX {};
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <stdio.h>
class Logger
{
public:
static bool Init(const char *filename);
static int Printf(const char *format, ...);
private:
static FILE *mLogFile;
};
+785
View File
@@ -0,0 +1,785 @@
#include "munga.h"
#pragma hdrstop
#include "affnmtrx.h"
#include "matrix.h"
#include "linmtrx.h"
#include "origin.h"
const AffineMatrix AffineMatrix::Identity(true);
#if defined(USE_SIGNATURE)
int Is_Signature_Bad(const volatile AffineMatrix *)
{
return false;
}
#endif
AffineMatrix& AffineMatrix::BuildIdentity()
{
Check_Pointer(this);
entries[0] = 1.0f;
entries[1] = 0.0f;
entries[2] = 0.0f;
entries[3] = 0.0f;
entries[4] = 0.0f;
entries[5] = 1.0f;
entries[6] = 0.0f;
entries[7] = 0.0f;
entries[8] = 0.0f;
entries[9] = 0.0f;
entries[10] = 1.0f;
entries[11] = 0.0f;
return *this;
}
AffineMatrix& AffineMatrix::operator=(const AffineMatrix& m)
{
Check_Pointer(this);
Check(&m);
//#if sizeof(entries) > sizeof(m.entries)
//# error memcpy mismatch
//#endif
memcpy(entries, m.entries, sizeof(m.entries));
return *this;
}
AffineMatrix& AffineMatrix::operator=(const Origin& p)
{
Check_Pointer(this);
Check(&p);
*this = p.angularPosition;
*this = p.linearPosition;
return *this;
}
AffineMatrix& AffineMatrix::operator=(const Hinge &hinge)
{
Check_Pointer(this);
Check(&hinge);
SinCosPair x,y,z;
switch (hinge.axisNumber)
{
case X_Axis:
x = hinge.rotationAmount;
(*this)(0,0) = 1.0f;
(*this)(0,1) = 0.0f;
(*this)(0,2) = 0.0f;
(*this)(1,0) = 0.0f;
(*this)(1,1) = x.cosine;
(*this)(1,2) = -x.sine;
(*this)(2,0) = 0.0f;
(*this)(2,1) = x.sine;
(*this)(2,2) = x.cosine;
break;
case Y_Axis:
y = hinge.rotationAmount;
(*this)(0,0) = y.cosine;
(*this)(0,1) = 0.0f;
(*this)(0,2) = y.sine;
(*this)(1,0) = 0.0f;
(*this)(1,1) = 1.0f;
(*this)(1,2) = 0.0f;
(*this)(2,0) = -y.sine;
(*this)(2,1) = 0.0f;
(*this)(2,2) = y.cosine;
break;
case Z_Axis:
z = hinge.rotationAmount;
(*this)(0,0) = z.cosine;
(*this)(0,1) = -z.sine;
(*this)(0,2) = 0.0f;
(*this)(1,0) = z.sine;
(*this)(1,1) = z.cosine;
(*this)(1,2) = 0.0f;
(*this)(2,0) = 0.0f;
(*this)(2,1) = 0.0f;
(*this)(2,2) = 1.0f;
break;
}
return *this;
}
//
//#############################################################################
//#############################################################################
//
AffineMatrix&
AffineMatrix::operator=(const EulerAngles &angles)
{
Check_Pointer(this);
Check(&angles);
SinCosPair
x,
y,
z;
x = angles.pitch;
y = angles.yaw;
z = angles.roll;
(*this)(0,0) = y.cosine*z.cosine;
(*this)(0,1) = y.cosine*z.sine;
(*this)(0,2) = -y.sine;
(*this)(1,0) = x.sine*y.sine*z.cosine - x.cosine*z.sine;
(*this)(1,1) = x.sine*y.sine*z.sine + x.cosine*z.cosine;
(*this)(1,2) = x.sine*y.cosine;
(*this)(2,0) = x.cosine*y.sine*z.cosine + x.sine*z.sine;
(*this)(2,1) = x.cosine*y.sine*z.sine - x.sine*z.cosine;
(*this)(2,2) = x.cosine*y.cosine;
Check(this);
return *this;
}
//
//#############################################################################
//#############################################################################
//
AffineMatrix&
AffineMatrix::operator=(const YawPitchRoll &angles)
{
Check_Pointer(this);
Check(&angles);
SinCosPair
x,
y,
z;
x = angles.pitch;
y = angles.yaw;
z = angles.roll;
(*this)(0,0) = y.cosine*z.cosine + x.sine*y.sine*z.sine;
(*this)(0,1) = x.cosine*z.sine;
(*this)(0,2) = x.sine*y.cosine*z.sine - y.sine*z.cosine;
(*this)(1,0) = x.sine*y.sine*z.cosine - y.cosine*z.sine;
(*this)(1,1) = x.cosine*z.cosine;
(*this)(1,2) = y.sine*z.sine + x.sine*y.cosine*z.cosine;
(*this)(2,0) = x.cosine*y.sine;
(*this)(2,1) = -x.sine;
(*this)(2,2) = x.cosine*y.cosine;
Check(this);
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::operator=(const Quaternion &q)
{
Check_Pointer(this);
Check(&q);
Scalar
a = q.x*q.y,
b = q.y*q.z,
c = q.z*q.x,
d = q.w*q.x,
e = q.w*q.y,
f = q.w*q.z,
g = q.w*q.w,
h = q.x*q.x,
i = q.y*q.y,
j = q.z*q.z;
(*this)(0,0) = g + h - i - j;
(*this)(1,0) = 2.0f*(a - f);
(*this)(2,0) = 2.0f*(c + e);
(*this)(0,1) = 2.0f*(f + a);
(*this)(1,1) = g - h + i - j;
(*this)(2,1) = 2.0f*(b - d);
(*this)(0,2) = 2.0f*(c - e);
(*this)(1,2) = 2.0f*(b + d);
(*this)(2,2) = g - h - i + j;
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::operator=(const Matrix4x4 &m)
{
Check_Pointer(this);
Check(&m);
Warn(!Small_Enough(m(0,3)));
Warn(!Small_Enough(m(1,3)));
Warn(!Small_Enough(m(2,3)));
Warn(!Close_Enough(m(3,3),1.0f));
(*this)(0,0) = m(0,0);
(*this)(0,1) = m(0,1);
(*this)(0,2) = m(0,2);
(*this)(1,0) = m(1,0);
(*this)(1,1) = m(1,1);
(*this)(1,2) = m(1,2);
(*this)(2,0) = m(2,0);
(*this)(2,1) = m(2,1);
(*this)(2,2) = m(2,2);
(*this)(3,0) = m(3,0);
(*this)(3,1) = m(3,1);
(*this)(3,2) = m(3,2);
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::operator=(const TransposedMatrix &m)
{
Check_Pointer(this);
Check(&m);
Warn(!Small_Enough(m(3,0)));
Warn(!Small_Enough(m(3,1)));
Warn(!Small_Enough(m(3,2)));
Warn(!Close_Enough(m(3,3),1.0f));
(*this)(0,0) = m(0,0);
(*this)(0,1) = m(1,0);
(*this)(0,2) = m(2,0);
(*this)(1,0) = m(0,1);
(*this)(1,1) = m(1,1);
(*this)(1,2) = m(2,1);
(*this)(2,0) = m(0,2);
(*this)(2,1) = m(1,2);
(*this)(2,2) = m(2,2);
(*this)(3,0) = m(0,3);
(*this)(3,1) = m(1,3);
(*this)(3,2) = m(2,3);
return *this;
}
//
//###########################################################################
//###########################################################################
//
Logical
AffineMatrix::operator==(const AffineMatrix& m) const
{
Check(this);
Check(&m);
for (size_t i=0; i<ELEMENTS(entries); ++i) {
if (!Close_Enough(entries[i],m.entries[i])) {
return False;
}
}
return True;
}
//
//###########################################################################
//###########################################################################
//
Logical
AffineMatrix::operator!=(const AffineMatrix& m) const
{
Check(this);
Check(&m);
for (size_t i=0; i<ELEMENTS(entries); ++i) {
if (!Close_Enough(entries[i],m.entries[i])) {
return True;
}
}
return False;
}
//
//###########################################################################
//###########################################################################
//
void
AffineMatrix::GetFromAxis(
size_t index,
Vector3D *v
) const
{
Check(this);
Check_Pointer(v);
Warn(index>W_Axis);
v->x = (*this)(index,X_Axis);
v->y = (*this)(index,Y_Axis);
v->z = (*this)(index,Z_Axis);
}
//
//###########################################################################
//###########################################################################
//
void
AffineMatrix::GetToAxis(
size_t index,
Vector3D *v
) const
{
Check(this);
Check_Pointer(v);
Warn(index>Z_Axis);
v->x = (*this)(X_Axis,index);
v->y = (*this)(Y_Axis,index);
v->z = (*this)(Z_Axis,index);
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::SetFromAxis(
size_t index,
const Vector3D &v
)
{
Check_Pointer(this);
Check(&v);
Warn(index>W_Axis);
(*this)(index,X_Axis) = v.x;
(*this)(index,Y_Axis) = v.y;
(*this)(index,Z_Axis) = v.z;
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::SetToAxis(
size_t index,
const Vector3D &v
)
{
Check_Pointer(this);
Check(&v);
Warn(index>Z_Axis);
(*this)(X_Axis,index) = v.x;
(*this)(Y_Axis,index) = v.y;
(*this)(Z_Axis,index) = v.z;
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Multiply(
const AffineMatrix& Source1,
const AffineMatrix& Source2
)
{
Check_Pointer(this);
Check(&Source1);
Check(&Source2);
(*this)(0,0) =
Source1(0,0)*Source2(0,0)
+ Source1(0,1)*Source2(1,0)
+ Source1(0,2)*Source2(2,0);
(*this)(1,0) =
Source1(1,0)*Source2(0,0)
+ Source1(1,1)*Source2(1,0)
+ Source1(1,2)*Source2(2,0);
(*this)(2,0) =
Source1(2,0)*Source2(0,0)
+ Source1(2,1)*Source2(1,0)
+ Source1(2,2)*Source2(2,0);
(*this)(3,0) =
Source1(3,0)*Source2(0,0)
+ Source1(3,1)*Source2(1,0)
+ Source1(3,2)*Source2(2,0)
+ Source2(3,0);
(*this)(0,1) =
Source1(0,0)*Source2(0,1)
+ Source1(0,1)*Source2(1,1)
+ Source1(0,2)*Source2(2,1);
(*this)(1,1) =
Source1(1,0)*Source2(0,1)
+ Source1(1,1)*Source2(1,1)
+ Source1(1,2)*Source2(2,1);
(*this)(2,1) =
Source1(2,0)*Source2(0,1)
+ Source1(2,1)*Source2(1,1)
+ Source1(2,2)*Source2(2,1);
(*this)(3,1) =
Source1(3,0)*Source2(0,1)
+ Source1(3,1)*Source2(1,1)
+ Source1(3,2)*Source2(2,1)
+ Source2(3,1);
(*this)(0,2) =
Source1(0,0)*Source2(0,2)
+ Source1(0,1)*Source2(1,2)
+ Source1(0,2)*Source2(2,2);
(*this)(1,2) =
Source1(1,0)*Source2(0,2)
+ Source1(1,1)*Source2(1,2)
+ Source1(1,2)*Source2(2,2);
(*this)(2,2) =
Source1(2,0)*Source2(0,2)
+ Source1(2,1)*Source2(1,2)
+ Source1(2,2)*Source2(2,2);
(*this)(3,2) =
Source1(3,0)*Source2(0,2)
+ Source1(3,1)*Source2(1,2)
+ Source1(3,2)*Source2(2,2)
+ Source2(3,2);
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Invert(const AffineMatrix& Source)
{
Check_Pointer(this);
Check(&Source);
(*this)(0,0) = Source(1,1)*Source(2,2) - Source(1,2)*Source(2,1);
(*this)(1,0) = Source(1,2)*Source(2,0) - Source(1,0)*Source(2,2);
(*this)(2,0) = Source(1,0)*Source(2,1) - Source(1,1)*Source(2,0);
Scalar det =
(*this)(0,0)*Source(0,0)
+ (*this)(1,0)*Source(0,1)
+ (*this)(2,0)*Source(0,2);
Verify(!Small_Enough(det));
(*this)(3,0) =
-Source(3,0)*(*this)(0,0)
- Source(3,1)*(*this)(1,0)
- Source(3,2)*(*this)(2,0);
(*this)(0,1) = Source(0,2)*Source(2,1) - Source(0,1)*Source(2,2);
(*this)(1,1) = Source(0,0)*Source(2,2) - Source(0,2)*Source(2,0);
(*this)(2,1) = Source(0,1)*Source(2,0) - Source(0,0)*Source(2,1);
(*this)(3,1) =
-Source(3,0)*(*this)(0,1)
- Source(3,1)*(*this)(1,1)
- Source(3,2)*(*this)(2,1);
(*this)(0,2) = Source(0,1)*Source(1,2) - Source(0,2)*Source(1,1);
(*this)(1,2) = Source(1,0)*Source(0,2) - Source(0,0)*Source(1,2);
(*this)(2,2) = Source(0,0)*Source(1,1) - Source(0,1)*Source(1,0);
(*this)(3,2) =
-Source(3,0)*(*this)(0,2)
- Source(3,1)*(*this)(1,2)
- Source(3,2)*(*this)(2,2);
det = 1.0f/det;
for (int i=0; i<12; ++i)
{
entries[i] *= det;
}
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Multiply(const AffineMatrix &m,const Vector3D &v)
{
Check_Pointer(this);
Check(&m);
Check(&v);
(*this)(0,0) = m(0,0)*v.x;
(*this)(1,0) = m(1,0)*v.x;
(*this)(2,0) = m(2,0)*v.x;
(*this)(3,0) = m(3,0)*v.x;
(*this)(0,1) = m(0,1)*v.y;
(*this)(1,1) = m(1,1)*v.y;
(*this)(2,1) = m(2,1)*v.y;
(*this)(3,1) = m(3,1)*v.y;
(*this)(0,2) = m(0,2)*v.z;
(*this)(1,2) = m(1,2)*v.z;
(*this)(2,2) = m(2,2)*v.z;
(*this)(3,2) = m(3,2)*v.z;
return *this;
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Multiply(const AffineMatrix& m,const Quaternion &q)
{
Check_Pointer(this);
Check(&m);
Check(&q);
LinearMatrix t(LinearMatrix::Identity);
t = q;
return Multiply(m,t);
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Multiply(const AffineMatrix &m,const Point3D& p)
{
Check_Pointer(this);
Check(&m);
Check(&p);
(*this)(3,0) = m(3,0) + p.x;
(*this)(3,1) = m(3,1) + p.y;
(*this)(3,2) = m(3,2) + p.z;
return *this;
}
//
//###########################################################################
//###########################################################################
//
Scalar
AffineMatrix::Determinant() const
{
Check(this);
return
(*this)(0,0)*((*this)(1,1)*(*this)(2,2) - (*this)(1,2)*(*this)(2,1))
+ (*this)(0,1)*((*this)(1,2)*(*this)(2,0) - (*this)(1,0)*(*this)(2,2))
+ (*this)(0,2)*((*this)(1,0)*(*this)(2,1) - (*this)(1,1)*(*this)(2,0));
}
//
//###########################################################################
//###########################################################################
//
AffineMatrix&
AffineMatrix::Solve()
{
Check(this);
int column;
Scalar temp;
//
//------------------------------------------------------------------
// Make sure that we get a decent value into the first diagonal spot
//------------------------------------------------------------------
//
if (!(*this)(0,0))
{
for (column=0; column<3; ++column)
if ((*this)(0,column))
break;
Verify(column != 3);
//
//--------------
// Swap the columns
//--------------
//
temp = (*this)(0,0);
(*this)(0,0) = (*this)(0,column);
(*this)(0,column) = temp;
temp = (*this)(1,0);
(*this)(1,0) = (*this)(1,column);
(*this)(1,column) = temp;
temp = (*this)(2,0);
(*this)(2,0) = (*this)(2,column);
(*this)(2,column) = temp;
temp = (*this)(3,0);
(*this)(3,0) = (*this)(3,column);
(*this)(3,column) = temp;
}
//
//------------------------------------
// Make sure the diagonal entry is 1.0
//------------------------------------
//
temp = (*this)(0,0);
(*this)(0,0) = 1.0f;
(*this)(1,0) /= temp;
(*this)(2,0) /= temp;
(*this)(3,0) /= temp;
//
//------------------------
// Make the first row zero
//------------------------
//
temp = (*this)(0,1);
(*this)(0,1) = 0.0f;
(*this)(1,1) -= temp * (*this)(1,0);
(*this)(2,1) -= temp * (*this)(2,0);
(*this)(3,1) -= temp * (*this)(3,0);
temp = (*this)(0,2);
(*this)(0,2) = 0.0f;
(*this)(1,2) -= temp * (*this)(1,0);
(*this)(2,2) -= temp * (*this)(2,0);
(*this)(3,2) -= temp * (*this)(3,0);
//
//-------------------------------------------------------------------
// Make sure that we get a decent value into the second diagonal spot
//-------------------------------------------------------------------
//
if (!(*this)(1,1))
{
Verify(!(*this)(2,2));
//
//---------------------
// Swap the (*this) columns
//---------------------
//
temp = (*this)(1,1);
(*this)(1,1) = (*this)(1,2);
(*this)(1,2) = temp;
temp = (*this)(2,1);
(*this)(2,1) = (*this)(2,2);
(*this)(2,2) = temp;
temp = (*this)(3,1);
(*this)(3,1) = (*this)(3,2);
(*this)(3,2) = temp;
}
//
//-----------------------------------
// Make the second diaginal entry 1.0
//-----------------------------------
//
temp = (*this)(1,1);
(*this)(1,1) = 1.0f;
(*this)(2,1) /= temp;
(*this)(3,1) /= temp;
//
//------------------------------------
// Make the second row zeros otherwise
//------------------------------------
//
temp = (*this)(1,0);
(*this)(1,0) = 0.0f;
(*this)(2,0) -= temp * (*this)(2,1);
(*this)(3,0) -= temp * (*this)(3,1);
temp = (*this)(1,2);
(*this)(1,2) = 0.0f;
(*this)(2,2) -= temp * (*this)(2,1);
(*this)(3,2) -= temp * (*this)(3,1);
//
//---------------------------
// Make the last diagonal 1.0
//---------------------------
//
Verify((*this)(2,2));
temp = (*this)(2,2);
(*this)(2,2) = 1.0f;
(*this)(3,2) /= temp;
//
//------------------------------------
// Make the third row zeros otherwise
//------------------------------------
//
temp = (*this)(2,0);
(*this)(2,0) = 0.0f;
(*this)(3,0) -= temp * (*this)(3,2);
temp = (*this)(2,1);
(*this)(2,1) = 0.0f;
(*this)(3,1) -= temp * (*this)(3,2);
//
//-------------------------
// Return the reduced array
//-------------------------
//
return *this;
}
//
//###########################################################################
//###########################################################################
//
std::ostream& operator <<(std::ostream& Stream, const AffineMatrix& M)
{
Check(&M);
return Stream << std::setprecision(4) << "\n\t| " << std::setw(9) << M(0,0) << ", "
<< std::setw(9) << M(0,1) << ", " << std::setw(9) << M(0,2) << ", 0 |\n\t| "
<< std::setw(9) << M(1,0) << ", " << std::setw(9) << M(1,1) << ", " << std::setw(9)
<< M(1,2) << ", 0 |\n\t| " << std::setw(9) << M(2,0) << ", " << std::setw(9)
<< M(2,1) << ", " << std::setw(9) << M(2,2) << ", 0 |\n\t| " << std::setw(9)
<< M(3,0) << ", " << std::setw(9) << M(3,1) << ", " << std::setw(9) << M(3,2)
<< ", 1 |";
}
//
//###########################################################################
//###########################################################################
//
Logical AffineMatrix::TestInstance() const
{
return True;
}
#if defined(TEST_CLASS)
#include "affnmtrx.tcp"
#endif
+145
View File
@@ -0,0 +1,145 @@
#pragma once
#include "point3d.h"
class Origin;
class TransposedMatrix;
class Hinge;
class EulerAngles;
class Quaternion;
class YawPitchRoll;
class AffineMatrix
{
public:
static const AffineMatrix Identity;
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const volatile AffineMatrix *);
#endif
Scalar entries[12];
//
// Constructors
//
AffineMatrix() {}
AffineMatrix& BuildIdentity();
AffineMatrix(int) { BuildIdentity(); }
//
// Assignment Operators
//
AffineMatrix& operator=(const AffineMatrix &m);
AffineMatrix& operator=(const Origin &p);
AffineMatrix& operator=(const Hinge &hinge);
AffineMatrix& operator=(const EulerAngles &angles);
AffineMatrix& operator=(const YawPitchRoll &angles);
AffineMatrix& operator=(const Quaternion &q);
AffineMatrix& operator=(const Point3D &p) { return SetFromAxis(W_Axis, p); }
AffineMatrix& operator=(const Matrix4x4 &m);
AffineMatrix& operator=(const TransposedMatrix &m);
//
// Comparison operators
//
Logical operator==(const AffineMatrix& m) const;
Logical operator!=(const AffineMatrix& m) const;
//
// Index operators
//
Scalar& operator()(size_t row, size_t column)
{
Check_Pointer(this);
Warn(row>3);
Warn(column>2);
return entries[(column<<2)+row];
}
const Scalar& operator()(size_t row, size_t column) const
{
Check_Pointer(this);
Warn(row>3);
Warn(column>2);
return entries[(column<<2)+row];
}
//
// Axis Manipulation functions
//
void GetFromAxis(size_t index, Vector3D *v) const;
void GetToAxis(size_t index, Vector3D *v) const;
AffineMatrix& SetFromAxis(size_t index, const Vector3D &v);
AffineMatrix& SetToAxis(size_t index, const Vector3D &v);
//
// Matrix Multiplication
//
AffineMatrix& Multiply(const AffineMatrix& m1, const AffineMatrix& m2);
AffineMatrix& operator*=(const AffineMatrix& m)
{
AffineMatrix temp(*this);
return Multiply(temp,m);
}
//
// Matrix Inversion
//
AffineMatrix& Invert(const AffineMatrix& Source);
AffineMatrix& Invert()
{
AffineMatrix src(*this);
return Invert(src);
}
//
// Scaling, Rotation and Translation
//
AffineMatrix& Multiply(const AffineMatrix &m,const Vector3D &v);
AffineMatrix& operator*=(const Vector3D &v)
{
AffineMatrix m(*this);
return Multiply(m,v);
}
AffineMatrix& Multiply(const AffineMatrix &m,const Quaternion &q);
AffineMatrix& operator*=(const Quaternion &q)
{
AffineMatrix m(*this);
return Multiply(m,q);
}
AffineMatrix& Multiply(const AffineMatrix &m,const Point3D &p);
AffineMatrix& operator*=(const Point3D& p)
{
AffineMatrix m(*this);
return Multiply(m,p);
}
//
// Miscellaneous Functions
//
Scalar Determinant() const;
AffineMatrix& Solve();
//
// Support functions
//
friend std::ostream& operator <<(std::ostream& stream, const AffineMatrix& m);
Logical TestInstance() const;
static Logical TestClass();
};
inline Point3D& Point3D::operator=(const AffineMatrix& m)
{
m.GetFromAxis(W_Axis,this);
return *this;
}
inline MemoryStream& MemoryStream_Read(MemoryStream *stream, AffineMatrix *output)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream& MemoryStream_Write(MemoryStream *stream, const AffineMatrix *input)
{
return stream->WriteBytes(input, sizeof(*input));
}
+167
View File
@@ -0,0 +1,167 @@
#include "munga.h"
#pragma hdrstop
#include "angle.h"
#if defined(USE_SIGNATURE)
int Is_Signature_Bad(const volatile Radian *)
{
return false;
}
#endif
Scalar Radian::Normalize(Scalar Value)
{
Scalar temp;
temp = fmod(Value,TWO_PI);
if (temp > PI) {
temp -= TWO_PI;
}
else if (temp < -PI) {
temp += TWO_PI;
}
return temp;
}
//
//#############################################################################
//#############################################################################
//
Radian&
Radian::Normalize()
{
Check(this);
angle = fmod(angle,TWO_PI);
if (angle > PI) {
angle -= TWO_PI;
}
else if (angle < -PI) {
angle += TWO_PI;
}
return *this;
}
//
//#############################################################################
//#############################################################################
//
Radian&
Radian::Lerp(const Radian &a,const Radian &b,Scalar t)
{
Scalar a1,a2;
Check_Pointer(this);
Check(&a);
Check(&b);
a1 = Radian::Normalize(a.angle);
a2 = Radian::Normalize(b.angle);
if (a2-a1 > PI) {
a2 -= TWO_PI;
}
else if (a2-a1 < -PI) {
a2 += TWO_PI;
}
angle = ::Lerp(a1, a2, t);
return *this;
}
//
//#############################################################################
//#############################################################################
//
std::ostream& operator<<(std::ostream& stream, const Radian& radian)
{
return stream << radian.angle << " rad";
}
//
//#############################################################################
//#############################################################################
//
Logical Radian::TestInstance() const
{
return angle >= -100.0f && angle <= 100.0f;
}
#if defined(USE_SIGNATURE)
int Is_Signature_Bad(const volatile Degree *)
{
return false;
}
#endif
//
//#############################################################################
//#############################################################################
//
std::ostream& operator<<(std::ostream& stream, const Degree& degree)
{
return stream << degree.angle << " deg";
}
//
//#############################################################################
//#############################################################################
//
Logical
Degree::TestInstance() const
{
return True;
}
#if defined(USE_SIGNATURE)
int
Is_Signature_Bad(const volatile SinCosPair *)
{
return False;
}
#endif
//
//#############################################################################
//#############################################################################
//
SinCosPair&
SinCosPair::operator=(const Radian &radian)
{
Check_Pointer(this);
Check(&radian);
cosine = cos(radian);
sine = sin(radian);
#if defined(__BCPLUSPLUS__)
cosine = cos(radian); // STUPID FUCKING BORLAND LIBRARY HACK!!!!!
#endif
Check(this);
return *this;
}
//
//#############################################################################
//#############################################################################
//
std::ostream& operator<<(std::ostream& stream, const SinCosPair& pair)
{
return stream << '{' << pair.cosine << ',' << pair.sine << '}';
}
//
//#############################################################################
//#############################################################################
//
Logical SinCosPair::TestInstance() const
{
Scalar t = sine*sine + cosine*cosine;
if (!Close_Enough(t,1.0f,0.001f))
{
Dump(*this);
Dump(t);
return False;
}
return True;
}
#if defined(TEST_CLASS)
# include "angle.tcp"
#endif
+228
View File
@@ -0,0 +1,228 @@
#pragma once
#include "scalar.h"
class Degree;
class SinCosPair;
class Radian
{
public:
Scalar angle;
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const volatile Radian *);
#endif
Radian() {}
Radian(Scalar angle) { this->angle = angle; }
Radian& operator=(Scalar angle)
{
Check_Pointer(this);
this->angle = angle;
return *this;
}
Radian& operator=(const Radian &radian)
{
Check_Pointer(this);
Check(&radian);
angle = radian.angle;
return *this;
}
Radian& operator=(const Degree &degree);
Radian& operator=(const SinCosPair &pair);
operator Scalar() const
{
Check(this);
return angle;
}
//
// These comparator functions are not designed to make exact comparisons
// of Scalaring point numbers, but rather to compare them to within some
// specified error threshold
//
Logical operator!() const { return Small_Enough(angle); }
Logical operator==(const Radian &r) const { return Close_Enough(angle, r.angle); }
Logical operator==(float r) const { return Close_Enough(angle, r); }
Logical operator!=(const Radian &r) const { return !Close_Enough(angle, r.angle); }
Logical operator!=(float r) const { return !Close_Enough(angle, r); }
Radian& Negate(Scalar r)
{
Check_Pointer(this);
angle = -r;
return *this;
}
Radian& Add(Scalar r1, Scalar r2)
{
Check_Pointer(this);
angle = r1 + r2;
return *this;
}
Radian& operator+=(Scalar r)
{
Check(this);
angle += r;
return *this;
}
Radian& Subtract(Scalar r1, Scalar r2)
{
Check_Pointer(this);
angle = r1 - r2;
return *this;
}
Radian& operator-=(Scalar r)
{
Check(this);
angle -= r;
return *this;
}
Radian& Multiply(Scalar r1, Scalar r2)
{
Check_Pointer(this);
angle = r1 * r2;
return *this;
}
Radian& operator*=(Scalar r)
{
Check(this);
angle *= r;
return *this;
}
Radian& Divide(Scalar r1, Scalar r2)
{
Check_Pointer(this);
Verify(!Small_Enough(r2));
angle = r1 / r2;
return *this;
}
Radian& operator/=(Scalar r)
{
Check(this);
Verify(!Small_Enough(r));
angle /= r;
return *this;
}
Radian& Lerp(const Radian &a, const Radian &b, Scalar t);
static Scalar Normalize(Scalar value);
Radian& Normalize();
friend std::ostream& operator<<(std::ostream& stream, const Radian &radian);
Logical TestInstance() const;
static Logical TestClass();
};
class Degree
{
public:
Scalar angle;
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const volatile Degree *);
#endif
//
// constructors
//
Degree() {}
Degree(Scalar angle) { this->angle = angle; }
//
// Assignment operators
//
Degree& operator=(const Degree &degree)
{
Check(this);
Check(&degree);
angle = degree.angle;
return *this;
}
Degree& operator=(Scalar angle)
{
Check(this);
this->angle = angle;
return *this;
}
Degree& operator=(const Radian &radian)
{
Check(this);
Check(&radian);
angle = radian.angle * DEG_PER_RAD;
return *this;
}
//
// Support functions
//
friend std::ostream& operator<<(std::ostream& stream, const Degree &angle);
Logical TestInstance() const;
static Logical TestClass();
};
inline Radian& Radian::operator=(const Degree& degree)
{
Check_Pointer(this);
Check(&degree);
angle = degree.angle * RAD_PER_DEG;
return *this;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SinCosPair ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SinCosPair
{
public:
Scalar sine, cosine;
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const volatile SinCosPair *);
#endif
//
// Constructors
//
SinCosPair() {}
SinCosPair(Scalar sin, Scalar cos)
{
Check_Pointer(this);
sine = sin;
cosine = cos;
Check(this);
}
//
// Assignment operators
//
SinCosPair& operator=(const SinCosPair &pair)
{
Check_Pointer(this);
Check(&pair);
sine = pair.sine; cosine = pair.cosine;
return *this;
}
SinCosPair& operator=(const Radian &radian);
//
// Support functions
//
friend std::ostream& operator<<(std::ostream& stream, const SinCosPair &pair);
Logical TestInstance() const;
static Logical TestClass();
};
inline Radian& Radian::operator=(const SinCosPair& pair)
{
Check_Pointer(this);
Check(&pair);
angle = Arctan(pair.sine, pair.cosine);
return *this;
}
File diff suppressed because it is too large Load Diff
+1777
View File
File diff suppressed because it is too large Load Diff
+764
View File
@@ -0,0 +1,764 @@
#pragma once
#include "network.h"
#include "event.h"
#include "state.h"
#include "cstr.h"
#if defined(TRACE_FOREGROUND_PROCESSING)
extern BitTrace Foreground_Processing;
#define SET_FOREGROUND_PROCESSING() Foreground_Processing.Set()
#define CLEAR_FOREGROUND_PROCESSING() Foreground_Processing.Clear()
#else
#define SET_FOREGROUND_PROCESSING()
#define CLEAR_FOREGROUND_PROCESSING()
#endif
#if defined(TRACE_UPDATE_MANAGER)
extern BitTrace Update_Manager;
#define SET_UPDATE_MANAGER() Update_Manager.Set()
#define CLEAR_UPDATE_MANAGER() Update_Manager.Clear()
#else
#define SET_UPDATE_MANAGER()
#define CLEAR_UPDATE_MANAGER()
#endif
#if defined(TRACE_RENDERER_MANAGER)
extern BitTrace Renderer_Manager;
#define SET_RENDERER_MANAGER() Renderer_Manager.Set()
#define CLEAR_RENDERER_MANAGER() Renderer_Manager.Clear()
#else
#define SET_RENDERER_MANAGER()
#define CLEAR_RENDERER_MANAGER()
#endif
class Mission;
class Registry;
class InterestManager;
class HostManager;
class UpdateManager;
class RendererManager;
class ControlsManager;
class Entity;
class EntityManager;
class Renderer;
class BackgroundTasks;
class ApplicationManager;
class CameraShip;
class SpoolFile;
class AudioRenderer;
class VideoRenderer;
class GaugeRenderer;
class IcomManager;
class ModeManager;
class Player;
class GeneralEventQueue;
class Entity__MakeMessage;
class ResourceFile;
//##########################################################################
//######################### Application ##############################
//##########################################################################
class Application__StateQueryMessage;
class Application__CheckLoadMessage;
class Application__RunMissionMessage;
class Application__StopMissionMessage;
class Application__SuspendMissionMessage;
class Application__ResumeMissionMessage;
class Application__AbortMissionMessage;
enum EventPriorities
{
MinEventPriority = 0,
LowEventPriority,
DefaultEventPriority,
HighEventPriority,
MaxEventPriority
};
const EventPriorities ControlsEventPriority = HighEventPriority;
const EventPriorities CreationEventPriority = HighEventPriority;
const EventPriorities DestructionEventPriority = HighEventPriority;
const EventPriorities UpdateEventPriority = MaxEventPriority;
const EventPriorities HighInterestEventPriority = DefaultEventPriority;
const EventPriorities LowInterestEventPriority = LowEventPriority;
const EventPriorities EntityManagerEventPriority = DefaultEventPriority;
const EventPriorities EntityInvalidEventPriority = LowEventPriority;
enum ApplicationID
{
RPL4,
BTL4,
NDL4
};
#define EVENT_PRIORITIES_COUNT (5)
class Application:
public NetworkClient
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
Application(
ResourceFile *resource_file,
ApplicationID application_id,
ClassID class_ID=ApplicationClassID,
SharedData &shared_data=DefaultData
);
~Application();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execution control
//
public:
virtual void Initialize();
virtual void
LoadBackgroundTasks();
virtual Logical
ExecuteForeground(
Time start_of_frame,
Scalar frame_duration
);
virtual void
ExecuteBackgroundTask();
void
Stop();
virtual Logical
Shutdown(int remainingApps);
virtual void
Terminate();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creation Callbacks
//
public:
void
CreateMission(NotationFile *egg_notation_file);
virtual Entity*
MakeAndLinkViewpointEntity(Entity__MakeMessage *message);
protected:
virtual Mission*
MakeMission(
NotationFile *notation_file,
ResourceFile *resources
);
virtual Entity*
MakeViewpointEntity(Entity__MakeMessage *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Current mission
//
public:
Mission*
GetCurrentMission();
Player*
GetMissionPlayer()
{return missionPlayer;}
SpoolFile*
GetSpoolFile()
{return spoolFile;}
protected:
Player
*missionPlayer;
SpoolFile*
spoolFile;
Time
lastCreationMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Application State
//
public:
enum {
InitializingState = 0,
WaitingForEgg,
LoadingMission,
WaitingForLaunch,
LaunchingMission,
RunningMission,
EndingMission,
StoppingMission,
SuspendingMission,
ResumingMission,
AbortingMission,
CreatingMission,
ApplicationStateCount
};
Enumeration
GetApplicationState();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// System level event processing
//
public:
void
Post(
int priority,
Receiver *target,
Receiver::Message *message,
const Time &when=Time::Null
);
void
SendEvent(
int priority,
HostID host_ID,
NetworkManager::ClientID client_ID,
Receiver::Message *message,
Time when=Time::Null
);
void
BroadcastEvent(
int priority,
NetworkManager::ClientID client_ID,
Receiver::Message *message,
Time when=Time::Null
);
void
ExclusiveBroadcastEvent(
int priority,
NetworkManager::ClientID client_ID,
Receiver::Message *message,
Time when=Time::Null
);
#if defined(TRACE_EVENT_COUNT)
size_t
GetEventCount();
#endif
void
DumpEventQueue();
#if 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Creation and Interest Event Posting
//
public:
void
PostCreationEvent(
Receiver::Message *message,
const Time &when=Time::Null
);
void
PostInterestEvent(
Entity *entity,
Renderer *renderer
);
void
PostUpdateEvent(
Entity *entity,
Receiver::Message *message
);
void
PostDestructionEvent(
Entity *entity,
Receiver::Message *message
);
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// System level message processing
//
public:
void
SendMessage(
HostID host_ID,
NetworkManager::ClientID client_ID,
Receiver::Message *message
);
void
BroadcastMessage(
NetworkManager::ClientID client_ID,
Receiver::Message *message
);
void
ExclusiveBroadcastMessage(
NetworkManager::ClientID client_ID,
Receiver::Message *message
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Event level event processing
//
public:
Logical
ProcessOneEvent(int min_priority=0);
void
ProcessAllEvents(int min_priority=0);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Accessors
//
public:
Scalar
GetApplicationLoopFrameRate();
Scalar
GetSecondsRemainingInGame()
{return secondsRemainingInGame;}
ApplicationID
GetApplicationID()
{return applicationID;}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Module accessors
//
public:
//
// Managers
//
NetworkManager*
GetNetworkManager();
EntityManager*
GetEntityManager();
Registry*
GetRegistry();
HostManager*
GetHostManager();
InterestManager*
GetInterestManager();
UpdateManager*
GetUpdateManager();
RendererManager*
GetRendererManager();
ControlsManager*
GetControlsManager();
IcomManager*
GetIntercomManager();
AudioRenderer*
GetAudioRenderer();
VideoRenderer*
GetVideoRenderer();
GaugeRenderer*
GetGaugeRenderer();
ModeManager*
GetModeManager();
//
// StreamableResourceFile
//
ResourceFile*
GetResourceFile();
void
SetResourceFile(ResourceFile *resources);
ApplicationManager*
GetApplicationManager();
//
// Viewpoint entity
//
Entity*
GetViewpointEntity();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
enum {
StateQueryMessageID = NetworkClient::NextMessageID,
CheckLoadMessageID,
RunMissionMessageID,
StopMissionMessageID,
KeyCommandMessageID,
SuspendMissionMessageID,
ResumeMissionMessageID,
LoadMissionMessageID,
AbortMissionMessageID,
NextMessageID
};
typedef Application__StateQueryMessage StateQueryMessage;
typedef Application__CheckLoadMessage CheckLoadMessage;
typedef Application__RunMissionMessage RunMissionMessage;
typedef Application__StopMissionMessage StopMissionMessage;
typedef Application__SuspendMissionMessage SuspendMissionMessage;
typedef Application__ResumeMissionMessage ResumeMissionMessage;
typedef Application__AbortMissionMessage AbortMissionMessage;
static const HandlerEntry
MessageHandlerEntries[];
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
void
StateQueryMessageHandler(StateQueryMessage *message);
void
CheckLoadMessageHandler(CheckLoadMessage *message);
void
RunMissionMessageHandler(RunMissionMessage *message);
void
StopMissionMessageHandler(StopMissionMessage *message);
void
SuspendMissionMessageHandler(SuspendMissionMessage *message);
void
ResumeMissionMessageHandler(ResumeMissionMessage *message);
void
KeyCommandMessageHandler(ReceiverDataMessageOf<int> *message);
void
LoadMissionMessageHandler(Message *message);
void
AbortMissionMessageHandler(AbortMissionMessage *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
static Logical DoSuppressGauges() { return suppressGauges; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Modules
//
protected:
//
// Managers
//
NetworkManager
*networkManager;
EntityManager
*entityManager;
Registry
*registry;
HostManager
*hostManager;
InterestManager
*interestManager;
UpdateManager
*updateManager;
RendererManager
*rendererManager;
ControlsManager
*controlsManager;
IcomManager
*intercomManager;
AudioRenderer
*audioRenderer;
VideoRenderer
*videoRenderer;
GaugeRenderer
*gaugeRenderer;
ModeManager
*modeManager;
static Logical suppressGauges;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Module Creation
//
protected:
//
// Managers
//
virtual NetworkManager*
MakeNetworkManager();
virtual Registry*
MakeRegistry();
virtual ControlsManager*
MakeControlsManager();
virtual IcomManager*
MakeIntercomManager();
virtual InterestManager*
MakeInterestManager();
virtual AudioRenderer*
MakeAudioRenderer();
virtual VideoRenderer*
MakeVideoRenderer();
virtual GaugeRenderer*
MakeGaugeRenderer(int *secondaryIndex, int *aux1Index, int *aux2Index);
virtual ModeManager*
MakeModeManager();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
protected:
ApplicationID
applicationID;
Scalar
secondsRemainingInGame;
Time
gameStarted;
GeneralEventQueue
*eventQueue;
BackgroundTasks
*backgroundTasks;
ResourceFile
*resourceFile;
Entity
*viewpointEntity;
Logical
executeFrames;
StateIndicator
applicationState;
Mission
*currentMission;
Logical
routePacketFinished;
};
extern Application *application;
extern int Exit_Code;
//~~~~~~~~~~~~~~~~~~~~ Application__CheckLoadMessage ~~~~~~~~~~~~~~~~~~~~~~~
class Application__CheckLoadMessage:
public NetworkClient::Message
{
public:
Application__CheckLoadMessage();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~ Application inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline Mission*
Application::GetCurrentMission()
{
Check(this);
return currentMission;
}
inline Enumeration
Application::GetApplicationState()
{
Check(this);
return applicationState.GetState();
}
inline void
Application::Post(
int priority,
Receiver *target,
Receiver::Message *message,
const Time &when
)
{
Check(this);
eventQueue->Post(priority,target,message,when);
}
inline void
Application::SendEvent(
int priority,
HostID host_ID,
NetworkClient::ClientID client_ID,
Receiver::Message *message,
Time when
)
{
Check(this);
eventQueue->SendEvent(priority,host_ID,client_ID,message,when);
}
inline void
Application::BroadcastEvent(
int priority,
NetworkClient::ClientID client_ID,
Receiver::Message *message,
Time when
)
{
Check(this);
eventQueue->BroadcastEvent(priority,client_ID,message,when);
}
inline void
Application::ExclusiveBroadcastEvent(
int priority,
NetworkClient::ClientID client_ID,
Receiver::Message *message,
Time when
)
{
Check(this);
eventQueue->ExclusiveBroadcastEvent(priority,client_ID,message,when);
}
#if defined(GET_EVENT_COUNT)
inline size_t
Application::GetEventCount()
{
return eventQueue->GetEventCount();
}
#endif
inline void
Application::DumpEventQueue()
{
eventQueue->DumpEventQueue();
}
inline void
Application::SendMessage(
HostID host_ID,
NetworkClient::ClientID client_ID,
Receiver::Message *message
)
{
Check(this);
networkManager->Send(message,client_ID,host_ID);
}
inline void
Application::BroadcastMessage(
NetworkManager::ClientID client_ID,
Receiver::Message *message
)
{
Check(this);
networkManager->Broadcast(message,client_ID);
}
inline void
Application::ExclusiveBroadcastMessage(
NetworkManager::ClientID client_ID,
Receiver::Message *message
)
{
Check(this);
networkManager->ExclusiveBroadcast(message,client_ID);
}
inline Logical
Application::ProcessOneEvent(int min_priority)
{
Check(this);
return eventQueue->ProcessOneEvent(min_priority);
}
inline void
Application::ProcessAllEvents(int min_priority)
{
Check(this);
eventQueue->ProcessAllEvents(min_priority);
}
inline NetworkManager*
Application::GetNetworkManager()
{
Check(networkManager);
return networkManager;
}
inline EntityManager*
Application::GetEntityManager()
{
return entityManager;
}
inline Registry*
Application::GetRegistry()
{
return registry;
}
inline HostManager*
Application::GetHostManager()
{
return hostManager;
}
inline InterestManager*
Application::GetInterestManager()
{
return interestManager;
}
inline UpdateManager*
Application::GetUpdateManager()
{
return updateManager;
}
inline RendererManager*
Application::GetRendererManager()
{
return rendererManager;
}
inline ControlsManager*
Application::GetControlsManager()
{
return controlsManager;
}
inline IcomManager*
Application::GetIntercomManager()
{
return intercomManager;
}
inline ResourceFile*
Application::GetResourceFile()
{
return resourceFile;
}
inline void
Application::SetResourceFile(ResourceFile *resources)
{
resourceFile = resources;
}
inline Entity*
Application::GetViewpointEntity()
{
return viewpointEntity;
}
inline AudioRenderer*
Application::GetAudioRenderer()
{
return audioRenderer;
}
inline VideoRenderer*
Application::GetVideoRenderer()
{
return videoRenderer;
}
inline GaugeRenderer*
Application::GetGaugeRenderer()
{
return gaugeRenderer;
}
inline ModeManager*
Application::GetModeManager()
{
return modeManager;
}
+236
View File
@@ -0,0 +1,236 @@
#include "munga.h"
#pragma hdrstop
#include "appmgr.h"
HWND ghWnd = 0;
ApplicationManager* ApplicationManager::CurrentAppManager = NULL;
ApplicationManager::ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate) : Node(ApplicationManagerClassID), runningApplications(this)
{
frameRate = frame_rate;
frameDuration = 1.0f/frameRate;
mHInstance = hInstance;
ghWnd = hWnd;
ApplicationManager::CurrentAppManager = this;
Check_Fpu();
}
ApplicationManager::~ApplicationManager()
{
}
void ApplicationManager::StartApplication(Application *new_app)
{
Check(this);
Check(new_app);
runningApplications.Add(new_app);
application = new_app;
new_app->Initialize();
}
//
//#############################################################################
// RunMissions
//#############################################################################
//
void ApplicationManager::RunMissions()
{
Check(this);
int backgroundTasksRun = 0;
int foregroundTasksRun = 0;
Time beginFrameTimestamp, lastFrameTimestamp;
MSG msg;
SChainIteratorOf<Application*> current_application(runningApplications);
SChainOf<Application*> endedApplications(NULL);
SChainIteratorOf<Application*> endingApplication(endedApplications);
Start_Of_Frame:
backgroundTasksRun = 0;
foregroundTasksRun = 0;
beginFrameTimestamp = Now();
current_application.First();
lastFrameTimestamp = Now();
Time end_of_frame = Now();
end_of_frame += frameDuration;
#if defined(LAB_ONLY)
int bad_count = 0;
#endif
//
//----------------------------------
// Run all relevant foreground loops
//----------------------------------
//
Time startForeground = Now();
while ((application = current_application.ReadAndNext()) != NULL)
{
Check(application);
foregroundTasksRun++;
if (!application->ExecuteForeground(end_of_frame, frameDuration))
{
if (!application->Shutdown(current_application.GetSize()))
{
endedApplications.Add(application);
if (current_application.GetCurrent() == NULL)
{
current_application.Last();
} else
{
current_application.Previous();
}
current_application.Remove();
}
}
}
Time endForeground = Now();
//
//-----------------------------------------------------------------------
// Check the Windows message queue for messages to be processed
//-----------------------------------------------------------------------
//
//InvalidateRect(ghWnd, NULL, false);
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
endingApplication.First();
while (application = endingApplication.ReadAndNext())
{
application->Terminate();
delete application;
}
return;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
//
//-----------------------------------------------------------------------
// Run all relevant background loops until it is time for the next frame.
// If no applications remain, exit the whole loop
//-----------------------------------------------------------------------
//
current_application.First();
application = current_application.GetCurrent();
if (!application)
{
endingApplication.First();
while (application = endingApplication.ReadAndNext())
{
application->Terminate();
delete application;
}
return;
}
do
{
while (application->GetNetworkManager()->RoutePacket())
;
current_application.Next();
application = current_application.GetCurrent();
} while (application);
current_application.First();
application = current_application.GetCurrent();
if (!application)
{
endingApplication.First();
while (application = endingApplication.ReadAndNext())
{
application->Terminate();
delete application;
}
return;
}
//
//------------------------------------------------------------------
// Give each application a chance to do at least one background task
//------------------------------------------------------------------
//
Time startBackground = Now();
Background_Loop:
do
{
Check(application);
application->ExecuteBackgroundTask();
backgroundTasksRun++;
//
// Move to the next application
//
current_application.Next();
application = current_application.GetCurrent();
} while (application);
//
//---------------------------------------------------------------------
// If time remains before the next frame is due, do another pass on the
// background tasks
//---------------------------------------------------------------------
//
Time t2 = Now();
Time lateTime = Now();
lateTime += 15L;
current_application.First();
application = current_application.GetCurrent();
if (t2 < end_of_frame)
{
#if defined(LAB_ONLY)
if (end_of_frame - t2 > 0.1f)
{
DEBUG_STREAM << t2 << ',' << end_of_frame << endl << std::flush;
if (++bad_count == 1000)
{
Fail("End-of-frame cannot be correctly calculated!");
}
}
#endif
goto Background_Loop;
}
Time endBackground = Now();
// BT perf probe (env BT_PERF): 1-Hz frame breakdown.
{
static int s_perf = -1;
if (s_perf < 0) { const char *e = getenv("BT_PERF"); s_perf = (e && *e != '0') ? 1 : 0; }
if (s_perf)
{
static Time s_lastP = Now();
if (Now() - s_lastP >= 1.0f)
{
s_lastP = Now();
DEBUG_STREAM << "[perf] frame=" << (float)(Now() - beginFrameTimestamp)
<< " fg=" << (float)(startBackground - beginFrameTimestamp)
<< " bg=" << (float)(endBackground - startBackground)
<< " bgTasks=" << backgroundTasksRun << "\n" << std::flush;
}
}
}
//char str[256];
//Scalar lastFrameLength = Now() - beginFrameTimestamp;
//sprintf(str, "RPL4 - %.2f FPS", 1.0f / lastFrameLength);
//SetWindowTextA(ghWnd, str);
goto Start_Of_Frame;
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "app.h"
extern HWND ghWnd;
class ApplicationManager : public Node
{
public:
ApplicationManager(HINSTANCE hInstance, HWND hWnd, Scalar frame_rate);
~ApplicationManager();
void StartApplication(Application *new_app);
void RunMissions();
Scalar GetFrameRate()
{
Check(this);
return frameRate;
}
HINSTANCE GetHInstance() { return mHInstance; }
HWND GetHWnd() { return ghWnd; }
static ApplicationManager* GetCurrentManager() { return CurrentAppManager; }
protected:
static ApplicationManager* CurrentAppManager;
Scalar frameDuration, frameRate;
SChainOf<Application*> runningApplications;
HINSTANCE mHInstance;
};
+46
View File
@@ -0,0 +1,46 @@
#include "munga.h"
#pragma hdrstop
#include "appmsg.h"
#include "app.h"
//~~~~~~~~~~~~~~~~~~~~~ Application__StateQueryMessage ~~~~~~~~~~~~~~~~~~~~~~~~
Application__StateQueryMessage::Application__StateQueryMessage(HostID requesting_host)
: NetworkClient::Message(Application::StateQueryMessageID, sizeof(Application__StateQueryMessage))
{
requestingHost = requesting_host;
}
//~~~~~~~~~~~~~~~~~~~~~~ Application__RunMissionMessage ~~~~~~~~~~~~~~~~~~~~~~~
Application__RunMissionMessage::Application__RunMissionMessage()
: NetworkClient::Message(Application::RunMissionMessageID, sizeof(Application__RunMissionMessage))
{
}
//~~~~~~~~~~~~~~~~~~~~~~ Application__StopMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
Application__StopMissionMessage::Application__StopMissionMessage(Enumeration exit_code)
: NetworkClient::Message(Application::StopMissionMessageID, sizeof(Application__StopMissionMessage))
{
exitCode = exit_code;
}
//~~~~~~~~~~~~~~~~~~~~~~ Application__AbortMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
Application__AbortMissionMessage::Application__AbortMissionMessage(Enumeration exit_code)
: NetworkClient::Message(Application::AbortMissionMessageID, sizeof(Application__AbortMissionMessage))
{
exitCode = exit_code;
}
//~~~~~~~~~~~~~~~~~~~~ Application__SuspendMissionMessage ~~~~~~~~~~~~~~~~~~~~~
Application__SuspendMissionMessage::Application__SuspendMissionMessage()
: NetworkClient::Message(Application::SuspendMissionMessageID, sizeof(Application__SuspendMissionMessage))
{
}
//~~~~~~~~~~~~~~~~~~~~ Application__ResumeMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
Application__ResumeMissionMessage::Application__ResumeMissionMessage()
: NetworkClient::Message(Application::ResumeMissionMessageID, sizeof(Application__ResumeMissionMessage))
{
}
//==============================================================================
+223
View File
@@ -0,0 +1,223 @@
#pragma once
#if defined(MAC)
#include <NetworkEndpoint.h>
#include <Participant.h>
#else
#include "network.h"
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Application IDs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
enum ApplicationMessageID
{
StateQueryMessageID = NetworkEndpoint::NextMessageID,
CheckLoadMessageID,
RunMissionMessageID,
StopMissionMessageID,
KeyCommandMessageID,
SuspendMissionMessageID,
ResumeMissionMessageID,
LoadMissionMessageID,
AbortMissionMessageID,
ApplicationNextMessageID
};
enum ApplicationID
{
RPL4,
BTL4,
BTW4
};
typedef ApplicationID ApplicationID;
enum ExitCodeID
{
NullExitCodeID = 0,
AbortExitCodeID,
RunRedPlanetExitCodeID,
RunBattleTechExitCodeID,
RunSinglePlayerRedPlanetExitCodeID,
RunSinglePlayerBattleTechExitCodeID,
DisplayMainTestPatternExitCodeID,
DisplayAuxTestPatternExitCodeID,
TestPlasmaDisplayExitCodeID,
ResetRIOExitCodeID,
RunAudioTestExitCodeID,
RunNortonDiskDoctorExitCodeID,
CheckDiskUsageExitCodeID,
RefreshRedPlanetExitCodeID,
RefreshBattleTechExitCodeID,
ChangeScreenModeExitCodeID,
SoftwareResetExitCodeID,
ClearCrashlogExitCodeID,
KillSpoolFileExitCodeID,
RunRedPlanetCameraExitCodeID,
RunBattleTechCameraExitCodeID,
RunRedPlanetMissionReviewExitCodeID,
RunBattleTechMissionReviewExitCodeID
};
typedef ExitCodeID ExitCodeID;
#endif
//~~~~~~~~~~~~~~~~~~~ Application__StateQueryMessage ~~~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__StateQueryMessage:
public NetworkEndpoint::Message
{
public:
Application__StateQueryMessage(HostID requesting_host);
long
GetRequestingHostID()
{return requestingHost.value();}
private:
HostID
requestingHost;
};
#pragma options align=reset
#else
class Application__StateQueryMessage:
public NetworkClient::Message
{
public:
Application__StateQueryMessage(HostID requesting_host);
HostID
GetRequestingHostID()
{return requestingHost;}
private:
HostID
requestingHost;
};
#endif
//~~~~~~~~~~~~~~~~~~~~ Application__RunMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__RunMissionMessage:
public NetworkEndpoint::Message
{
public:
Application__RunMissionMessage();
};
#pragma options align=reset
#else
class Application__RunMissionMessage:
public NetworkClient::Message
{
public:
Application__RunMissionMessage();
};
#endif
//~~~~~~~~~~~~~~~~~~~~ Application__StopMissionMessage ~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__StopMissionMessage:
public NetworkEndpoint::Message
{
public:
Application__StopMissionMessage(ExitCodeID exit_code);
ExitCodeID
GetExitCodeID()
{return((ExitCodeID) exitCode.value());}
private:
LEDWORD
exitCode;
};
#pragma options align=reset
#else
class Application__StopMissionMessage:
public NetworkClient::Message
{
public:
Application__StopMissionMessage(Enumeration exit_code);
Enumeration
GetExitCode()
{return(exitCode);}
private:
Enumeration
exitCode;
};
#endif
//~~~~~~~~~~~~~~~~~~~~ Application__AbortMissionMessage ~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__AbortMissionMessage:
public NetworkEndpoint::Message
{
public:
Application__AbortMissionMessage(ExitCodeID exit_code);
ExitCodeID
GetExitCode()
{return((ExitCodeID) exitCode.value());}
private:
LEDWORD
exitCode;
};
#pragma options align=reset
#else
class Application__AbortMissionMessage:
public NetworkClient::Message
{
public:
Application__AbortMissionMessage(Enumeration exit_code);
Enumeration
GetExitCode()
{return(exitCode);}
private:
Enumeration
exitCode;
};
#endif
//~~~~~~~~~~~~~~~~~~ Application__SuspendMissionMessage ~~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__SuspendMissionMessage:
public NetworkEndpoint::Message
{
public:
Application__SuspendMissionMessage();
};
#pragma options align=reset
#else
class Application__SuspendMissionMessage:
public NetworkClient::Message
{
public:
Application__SuspendMissionMessage();
};
#endif
//~~~~~~~~~~~~~~~~~~~ Application__ResumeMissionMessage ~~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class Application__ResumeMissionMessage:
public NetworkEndpoint::Message
{
public:
Application__ResumeMissionMessage();
};
#pragma options align=reset
#else
class Application__ResumeMissionMessage:
public NetworkClient::Message
{
public:
Application__ResumeMissionMessage();
};
#endif
+185
View File
@@ -0,0 +1,185 @@
#include "munga.h"
#pragma hdrstop
#include "apptask.h"
#include "renderer.h"
#include "audrend.h"
#include "app.h"
#include "nttmgr.h"
#include "gaugrend.h"
#if defined(TRACE_COMPLETE_CYCLES)
BitTrace Complete_Cycles("Complete Cycles");
#endif
#if defined(TRACE_DEATH_ROW)
BitTrace Death_Row("Death Row");
#endif
//#############################################################################
//########################### ApplicationTask ###########################
//#############################################################################
ApplicationTask::ApplicationTask(ClassID class_ID):
Component(class_ID)
{
}
ApplicationTask::~ApplicationTask()
{
}
//#############################################################################
//########################### BackgroundTasks ###########################
//#############################################################################
BackgroundTasks::BackgroundTasks():
taskSocket(NULL)
{
taskIterator = new SChainIteratorOf<ApplicationTask*>(&taskSocket);
Register_Object(taskIterator);
}
BackgroundTasks::~BackgroundTasks()
{
Check(taskIterator);
taskIterator->DeletePlugs();
Unregister_Object(taskIterator);
delete taskIterator;
}
Logical
BackgroundTasks::TestInstance() const
{
Component::TestInstance();
Check(&taskSocket);
Check(taskIterator);
return True;
}
void
BackgroundTasks::AddTask(ApplicationTask *task)
{
Check(this);
Check(task);
taskSocket.Add(task);
}
void
BackgroundTasks::Execute()
{
Check(this);
Check(taskIterator);
if (taskIterator->GetCurrent() == NULL)
{
taskIterator->First();
}
ApplicationTask *task = taskIterator->GetCurrent();
Check(task);
task->Execute();
taskIterator->Next();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkManagerTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
NetworkManagerTask::Execute()
{
Check(this);
Check(application);
Check(application->GetNetworkManager());
Time start = Now();
application->GetNetworkManager()->ExecuteBackground();
Time end = Now();
if (end.ticks - start.ticks > 10)
{
end = start;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RoutePacketTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
RoutePacketTask::Execute()
{
Check(this);
Check(application);
Check(application->GetNetworkManager());
application->GetNetworkManager()->RoutePacket();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ProcessEventTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
ProcessEventTask::Execute()
{
Check(this);
Check(application);
application->ProcessOneEvent();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioRendererTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
AudioRendererTask::Execute()
{
Check(this);
Check(application);
if (application->GetAudioRenderer() != NULL)
{
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->ExecuteBackground();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ GaugeRendererTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
GaugeRendererTask::Execute()
{
Check(this);
Check(application);
if (application->GetGaugeRenderer() != NULL)
{
Check(application->GetGaugeRenderer());
application->GetGaugeRenderer()->ExecuteBackground();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ CompleteCyclesTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
CompleteCyclesTask::Execute()
{
SET_COMPLETE_CYCLES();
Check(this);
Check(application);
Check(application->GetRendererManager());
// application->GetRendererManager()->CompleteCycles();
CLEAR_COMPLETE_CYCLES();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FryDeathRowTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
FryDeathRowTask::Execute()
{
SET_DEATH_ROW();
Check(this);
Check(application);
Check(application->GetEntityManager());
application->GetEntityManager()->FryDeathRow();
CLEAR_DEATH_ROW();
}
+153
View File
@@ -0,0 +1,153 @@
#pragma once
#include "style.h"
#include "cmpnnt.h"
#include "schain.h"
#if defined(TRACE_COMPLETE_CYCLES)
extern BitTrace Complete_Cycles;
#define SET_COMPLETE_CYCLES() Complete_Cycles.Set()
#define CLEAR_COMPLETE_CYCLES() Complete_Cycles.Clear()
#else
#define SET_COMPLETE_CYCLES()
#define CLEAR_COMPLETE_CYCLES()
#endif
#if defined(TRACE_DEATH_ROW)
extern BitTrace Death_Row;
#define SET_DEATH_ROW() Death_Row.Set()
#define CLEAR_DEATH_ROW() Death_Row.Clear()
#else
#define SET_DEATH_ROW()
#define CLEAR_DEATH_ROW()
#endif
//##########################################################################
//####################### ApplicationTask ############################
//##########################################################################
class ApplicationTask:
public Component
{
public:
ApplicationTask(ClassID class_ID = ApplicationTaskClassID);
~ApplicationTask();
};
//##########################################################################
//####################### BackgroundTasks ############################
//##########################################################################
class BackgroundTasks:
public Component
{
public:
BackgroundTasks();
~BackgroundTasks();
Logical
TestInstance() const;
void
AddTask(ApplicationTask *task);
void
Execute();
private:
SChainOf<ApplicationTask*>
taskSocket;
SChainIteratorOf<ApplicationTask*>
*taskIterator;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~ NetworkManagerTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class NetworkManagerTask:
public ApplicationTask
{
public:
NetworkManagerTask() {}
~NetworkManagerTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ RoutePacketTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class RoutePacketTask:
public ApplicationTask
{
public:
RoutePacketTask() {}
~RoutePacketTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ ProcessEventTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class ProcessEventTask:
public ApplicationTask
{
public:
ProcessEventTask() {}
~ProcessEventTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioRendererTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioRendererTask:
public ApplicationTask
{
public:
AudioRendererTask() {}
~AudioRendererTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ GaugeRendererTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class GaugeRendererTask:
public ApplicationTask
{
public:
GaugeRendererTask() {}
~GaugeRendererTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~ CompleteCyclesTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CompleteCyclesTask:
public ApplicationTask
{
public:
CompleteCyclesTask() {}
~CompleteCyclesTask() {}
void
Execute();
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ FryDeathRowTask ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class FryDeathRowTask:
public ApplicationTask
{
public:
FryDeathRowTask() {}
~FryDeathRowTask() {}
void
Execute();
};
File diff suppressed because it is too large Load Diff
+720
View File
@@ -0,0 +1,720 @@
#pragma once
#include "style.h"
#include "audio.h"
#include "audloc.h"
#include "average.h"
#include "audtime.h"
//##########################################################################
//######################## AudioMessageWatcher #######################
//##########################################################################
class AudioMessageWatcher:
public AudioComponent
{
public:
//
//-----------------------------------------------------------------------
// Constructor, Destructor
//-----------------------------------------------------------------------
//
AudioMessageWatcher(
PlugStream *stream,
Entity *entity
);
~AudioMessageWatcher();
Logical
TestInstance() const;
//
//-----------------------------------------------------------------------
// BuildFromPage
//-----------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//-----------------------------------------------------------------------
// MessageTapScanCallback
//-----------------------------------------------------------------------
//
void
MessageTapScanCallback(
Receiver::Message *message,
Receiver *receiver
);
//
//-----------------------------------------------------------------------
// Controller methods
//-----------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//-----------------------------------------------------------------------
// Controller methods
//-----------------------------------------------------------------------
//
virtual Logical
DoesMessageMatch(Receiver::Message*)
{return True;}
//
//-----------------------------------------------------------------------
// Private Data
//-----------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlID controlID;
AudioControlValue controlValue;
MessageTap *messageTap;
#if DEBUG_LEVEL>0
Receiver *verifyReceiver;
Receiver::MessageID verifyMessageID;
#endif
};
//##########################################################################
//############### AudioControlsButtonMessageWatcher ##################
//##########################################################################
class AudioControlsButtonMessageWatcher:
public AudioMessageWatcher
{
public:
//
//-----------------------------------------------------------------------
// Constructor, Destructor
//-----------------------------------------------------------------------
//
AudioControlsButtonMessageWatcher(
PlugStream *stream,
Entity *entity
);
~AudioControlsButtonMessageWatcher();
private:
//
//-----------------------------------------------------------------------
// Controller methods
//-----------------------------------------------------------------------
//
Logical
DoesMessageMatch(Receiver::Message*);
};
//##########################################################################
//######################### AudioControlSend #########################
//##########################################################################
class AudioControlSend:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioControlSend(
PlugStream *stream,
Entity *entity
);
~AudioControlSend();
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
};
//##########################################################################
//####################### AudioControlSplitter #######################
//##########################################################################
class AudioControlSplitter:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioControlSplitter(
PlugStream *stream,
Entity *entity
);
void
AudioControlSplitterX(Entity *entity);
~AudioControlSplitter();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SChainOf<AudioComponent*> audioComponentSocket;
};
//##########################################################################
//####################### AudioControlMixer ##########################
//##########################################################################
#define AUDIO_CONTROL_MIXER_MAX_CONTROLS (4)
class AudioControlMixer:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioControlMixer(
PlugStream *stream,
Entity *entity
);
void
AudioControlMixerX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID first_input_control_ID,
AudioControlID last_input_control_ID,
AudioControlID output_control_ID
);
~AudioControlMixer();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlValue
controlValueArray[AUDIO_CONTROL_MIXER_MAX_CONTROLS];
AudioControlID
firstInputControlID;
int
numberOfInputs;
AudioControlID
outputControlID;
};
//##########################################################################
//###################### AudioControlMultiplier ######################
//##########################################################################
#define AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS (4)
class AudioControlMultiplier:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioControlMultiplier(
PlugStream *stream,
Entity *entity
);
void
AudioControlMultiplierX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID first_input_control_ID,
AudioControlID last_input_control_ID,
AudioControlID output_control_ID
);
~AudioControlMultiplier();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlValue
controlValueArray[AUDIO_CONTROL_MULTIPLIER_MAX_CONTROLS];
AudioControlID
firstInputControlID;
int
numberOfInputs;
AudioControlID
outputControlID;
};
//##########################################################################
//######################## AudioControlSmoother ######################
//##########################################################################
class AudioControlSmoother:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioControlSmoother(
PlugStream *stream,
Entity *entity
);
void
AudioControlSmootherX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID control_ID
);
~AudioControlSmoother();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AverageOf<AudioControlValue>
audioControlAverage;
AudioControlID
controlID;
};
//##########################################################################
//####################### AudioResourceSelector ######################
//##########################################################################
class AudioResourceIndex;
class AudioResourceSelector:
public AudioComponent
{
public:
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
AudioResourceSelector(
PlugStream *stream,
Entity *entity
);
void
AudioResourceSelectorX(
AudioSource *audio_source,
Entity *entity,
AudioResourceIndex *audio_resource_index,
AudioControlID control_ID,
AudioControlValue min_control_value,
AudioControlValue max_control_value,
Logical dump_value
);
~AudioResourceSelector();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioSourceSocket;
AudioResourceIndex
*audioResourceIndex;
AudioControlID
controlID;
AudioControlValue
minControlValue,
maxControlValue;
Logical
dumpValue;
};
//##########################################################################
//######################## AudioSampleAndHold ########################
//##########################################################################
class AudioSampleAndHold:
public AudioComponent
{
public:
//
//-----------------------------------------------------------------------
// Construction, Destruction, Testing
//-----------------------------------------------------------------------
//
AudioSampleAndHold(
PlugStream *stream,
Entity *entity
);
void
AudioSampleAndHoldX(
AudioComponent *audio_component,
Entity *entity,
AudioControlID audio_control_ID,
const AudioTime &sample_duration,
Scalar min_value,
Scalar max_value
);
~AudioSampleAndHold();
//
//-----------------------------------------------------------------------
// BuildFromPage
//-----------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Execute
//--------------------------------------------------------------------
//
void
Execute();
//
//-----------------------------------------------------------------------
// Controller methods
//-----------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//-----------------------------------------------------------------------
// Private methods
//-----------------------------------------------------------------------
//
void
SampleAndHold();
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlID
audioControlID;
AudioControlValue
minValue,
maxValue,
currentValue;
AudioTime
nextSampleTime,
sampleDuration;
};
//##########################################################################
//############################# AudioLFO #############################
//##########################################################################
enum AudioLFOWaveForm
{
SinusoidalAudioLFOWaveForm = 0,
TriangularAudioLFOWaveForm = 1
};
inline MemoryStream&
MemoryStream_Read(
MemoryStream *stream,
AudioLFOWaveForm *ptr
)
{return stream->ReadBytes(ptr, sizeof(*ptr));}
inline MemoryStream&
MemoryStream_Write(
MemoryStream *stream,
const AudioLFOWaveForm *ptr
)
{return stream->WriteBytes(ptr, sizeof(*ptr));}
class AudioLFO:
public AudioComponent
{
public:
//
//-----------------------------------------------------------------------
// Construction, Destruction, Testing
//-----------------------------------------------------------------------
//
AudioLFO(
PlugStream *stream,
Entity *entity
);
void
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
);
~AudioLFO();
//
//-----------------------------------------------------------------------
// BuildFromPage
//-----------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//--------------------------------------------------------------------
// Execute
//--------------------------------------------------------------------
//
void
Execute();
//
//-----------------------------------------------------------------------
// Controller methods
//-----------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
//
//-----------------------------------------------------------------------
// Private methods
//-----------------------------------------------------------------------
//
void
Generate();
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlID
audioControlID;
AudioLFOWaveForm
waveForm;
AudioControlValue
minValue,
maxValue;
AudioTime
period;
AudioTime
startTime;
Logical
dumpValue;
};
+177
View File
@@ -0,0 +1,177 @@
#include "munga.h"
#pragma hdrstop
#include "audent.h"
#include "jmover.h"
#include "app.h"
#include "hostmgr.h"
//#############################################################################
//########################### AudioEntity ###############################
//#############################################################################
//#############################################################################
// Shared Data Support
//
Derivation* AudioEntity::GetClassDerivations()
{ static Derivation classDerivations(Explosion::GetClassDerivations(), "AudioEntity");
return &classDerivations;
}
AudioEntity::SharedData
AudioEntity::DefaultData(
AudioEntity::GetClassDerivations(),
AudioEntity::GetMessageHandlers(),
AudioEntity::GetAttributeIndex(),
AudioEntity::StateCount,
(Entity::MakeHandler)AudioEntity::Make
);
//
//#############################################################################
//#############################################################################
//
AudioEntity::AudioEntity(
AudioEntity::MakeMessage *creation_message,
AudioEntity::SharedData &shared_data
):
Explosion(creation_message, shared_data),
parentEntitySocket(NULL)
{
Check_Pointer(this);
Check_Pointer(creation_message);
//
// Get the parent entity
//
Entity *parent_entity;
parent_entity =
application->GetHostManager()->GetEntityPointer(
creation_message->parentEntityID
);
if (parent_entity != NULL)
{
parentEntitySocket.Add(parent_entity);
parentEntitySegment = creation_message->parentEntitySegment;
}
else
{
parentEntitySegment = NULL;
}
//
// Set simulation
//
SetPerformance(&AudioEntity::AudioEntitySimulation);
SetValidFlag();
}
//
//#############################################################################
//#############################################################################
//
AudioEntity::~AudioEntity()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioEntity::TestInstance() const
{
if (!IsDerivedFrom(*GetClassDerivations()))
{
return False;
}
Check(&parentEntitySocket);
if (parentEntitySegment != NULL)
{
Check(parentEntitySegment);
}
return True;
}
//
//#############################################################################
//#############################################################################
//
AudioEntity*
AudioEntity::Make(AudioEntity::MakeMessage *creation_message)
{
return new AudioEntity(creation_message);
}
//
//#############################################################################
//#############################################################################
//
void
AudioEntity::AudioEntitySimulation(Scalar time_slice)
{
Check(this);
//
// Get the parent entity, if it does not exist, condemn to death row
//
Entity *parent_entity;
if ((parent_entity = parentEntitySocket.GetCurrent()) == NULL)
{
CondemnToDeathRow();
return;
}
//
// Get the orign of the parent entities segment
//
JointedMover *jointed_mover;
Verify(parent_entity->IsDerivedFrom(JointedMover::GetClassDerivations()));
jointed_mover = Cast_Object(JointedMover*, parent_entity);
Check(jointed_mover);
Check(parentEntitySegment);
jointed_mover->GetSegmentToWorld(
*parentEntitySegment,
&localToWorld
);
//
// Set the origin of this entity
//
localOrigin = localToWorld;
updateOrigin = localOrigin;
//
// Call inherited simulation
//
Explosion::ExplosionSimulation(time_slice);
}
//#############################################################################
//##################### AudioEntity__MakeMessage ########################
//#############################################################################
AudioEntity__MakeMessage::AudioEntity__MakeMessage(
ResourceDescription::ResourceID resource_ID,
Entity *parent_entity,
EntitySegment *parent_entity_segment
):
Explosion::MakeMessage(
AudioEntity::MakeMessageID,
sizeof(AudioEntity__MakeMessage),
RegisteredClass::AudioEntityClassID,
EntityID::Null,
resource_ID,
Entity::HermitInstance|Entity::DynamicFlag,
parent_entity->localOrigin,
parent_entity->GetEntityID(),
EntityID::Null
),
parentEntityID(parent_entity->GetEntityID()),
parentEntitySegment(parent_entity_segment)
{
}
+72
View File
@@ -0,0 +1,72 @@
#pragma once
#include "explode.h"
#include "segment.h"
#include "slot.h"
//##########################################################################
//########################## AudioEntity #############################
//##########################################################################
class AudioEntity__MakeMessage;
class AudioEntity : public Explosion
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public types
//
public:
typedef AudioEntity__MakeMessage MakeMessage;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
AudioEntity(MakeMessage *creation_message, SharedData &shared_data = DefaultData);
~AudioEntity();
static AudioEntity* Make(MakeMessage *creation_message);
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
typedef void (AudioEntity::*Performance)(Scalar time_slice);
void SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void AudioEntitySimulation(Scalar time_slice);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Data
//
private:
SlotOf<Entity*> parentEntitySocket;
EntitySegment *parentEntitySegment;
};
//##########################################################################
//#################### AudioEntity__MakeMessage ######################
//##########################################################################
class AudioEntity__MakeMessage : public Explosion::MakeMessage
{
public:
AudioEntity__MakeMessage(ResourceDescription::ResourceID resource_ID, Entity *parent_entity, EntitySegment *parent_entity_segment);
EntityID parentEntityID;
EntitySegment *parentEntitySegment;
};
+474
View File
@@ -0,0 +1,474 @@
#include "munga.h"
#pragma hdrstop
#include "audio.h"
#include "audrend.h"
#include "app.h"
#include "..\munga_l4\openal\al.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Audio Constants ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const Scalar AudioDoubleTriggerCutoff = 0.2f;
const AudioControlValue MaxAudioVolume = 1.0f;
const AudioControlValue MinAudioVolume = 0.0f;
const AudioControlValue LowAudioVolumeThreshold = 0.3f;
const AudioControlValue MaxAudioBrightness = 1.0f;
const AudioControlValue MinAudioBrightness = 0.0f;
const AudioControlValue MaxAudioAttack = 1.0f;
const AudioControlValue MinAudioAttack = 0.0f;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHead ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioHead::AudioHead():
headEntitySocket(NULL)
{
//
// Start frame counter at 0, other counts should be at
// NullAudioFrameCount
//
audioFrameCount = 0;
//
// Other audio parameters
//
clippingRadius = 100.0f;
distanceBetweenEars = 1.0f;
amplitudeRollOffExponent = 1.0f;
amplitudeRollOffKnee = 10.0f,
amplitudeRollOffDistanceScale = 0.05f;
highFrequencyRollOffExponent = 0.5f;
highFrequencyRollOffKnee = 10.0f;
highFrequencyRollOffDistanceScale = 0.05f;
reverbToDryRatio = 0.1f;
audioSoundSpeed = 345.0f;
audioDopplerConstant = 20.0f;
sourceCompressionExponent = 0.5f;
sourceCompressionScale = 0.5f;
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
AudioHead::~AudioHead()
{
Check(this);
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioHead::TestInstance() const
{
Check(&headEntitySocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::LinkToEntity(Entity *entity)
{
Check(this);
Check(entity);
//
// Remove existing entity, add new one
//
if (headEntitySocket.GetCurrent() != NULL)
{
headEntitySocket.Remove();
}
headEntitySocket.Add(entity);
alDistanceModel(AL_LINEAR_DISTANCE);
alDopplerFactor(0.3f);
#if 0
//
// Make the new clipping sphere
//
clippingSphere.SetCurrentOrigin(entity->localOrigin.linearPosition);
#endif
}
//
//#############################################################################
//#############################################################################
//
LinearMatrix
AudioHead::GetEarToWorld()
{
Check(this);
Entity *entity = headEntitySocket.GetCurrent();
Check(entity);
return entity->localToWorld;
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::Execute()
{
Check(this);
//
// Increment frame counter
//
audioFrameCount = Now().ticks;
Verify(audioFrameCount < LONG_MAX);
//set current listener orientation
Vector3D headVelocity;
headVelocity.MultiplyByInverse(this->GetHeadEntity()->GetWorldLinearVelocity(), this->GetHeadEntity()->localToWorld);
alListener3f(AL_VELOCITY, -headVelocity.x, -headVelocity.y, -headVelocity.z);
#if 0
//
// Get the entity
//
Entity *entity = headEntitySocket.GetCurrent();
Check(entity);
//
// Make the new clipping sphere
//
clippingSphere.SetCurrentOrigin(entity->localOrigin.linearPosition);
#endif
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::DefineClippingSphere(Scalar radius)
{
Check(this);
clippingRadius = radius;
#if 0
//
// Get entity position
//
Entity *entity;
Point3D position(0.0f, 0.0f, 0.0f);
if ((entity = headEntitySocket.GetCurrent()) != NULL)
{
Check(entity);
position = entity->localOrigin.linearPosition;
}
//
// Make the new clipping sphere
//
clippingSphere.SetCurrentOrigin(position);
clippingSphere.SetReferenceRadius(radius);
#endif
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioHead::IsPointClipped(const Point3D &point)
{
Check(this);
Entity
*entity;
Vector3D
difference;
entity = headEntitySocket.GetCurrent();
Check(entity);
difference.Subtract(entity->localOrigin.linearPosition, point);
return difference.LengthSquared() > clippingRadius*clippingRadius;
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::ControlDopplerEffect(
Scalar doppler_constant,
Scalar sound_speed
)
{
Check(this);
audioDopplerConstant = doppler_constant;
audioSoundSpeed = sound_speed;
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::ControlAmplitudeRollOff(
Scalar exponent,
Scalar amplitude_rolloff_knee,
Scalar distance_scale
)
{
Check(this);
amplitudeRollOffExponent = exponent;
amplitudeRollOffKnee = amplitude_rolloff_knee;
amplitudeRollOffDistanceScale = distance_scale;
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::ControlHighFrequencyRollOff(
Scalar exponent,
Scalar high_frequency_rolloff_knee,
Scalar distance_scale
)
{
Check(this);
highFrequencyRollOffExponent = exponent;
highFrequencyRollOffKnee = high_frequency_rolloff_knee;
highFrequencyRollOffDistanceScale = distance_scale;
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::ControlSourceCompression(
Scalar exponent,
Scalar scale
)
{
Check(this);
sourceCompressionExponent = exponent;
sourceCompressionScale = scale;
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioHead::SetPositionalCulling(Logical)
{
Check(this);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioComponent ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
const Receiver::HandlerEntry
AudioComponent::MessageHandlerEntries[]=
{
{
AudioComponent::ReceiveControlMessageID,
"ReceiveControl",
(AudioComponent::Handler)&AudioComponent::ReceiveControlMessageHandler
}
};
AudioComponent::MessageHandlerSet& AudioComponent::GetMessageHandlers()
{
static AudioComponent::MessageHandlerSet messageHandlers(ELEMENTS(AudioComponent::MessageHandlerEntries), AudioComponent::MessageHandlerEntries, Component::GetMessageHandlers());
return messageHandlers;
}
//
//#############################################################################
//#############################################################################
//
Derivation* AudioComponent::GetClassDerivations()
{
static Derivation classDerivations(Component::GetClassDerivations(), "AudioComponent");
return &classDerivations;
}
AudioComponent::SharedData
AudioComponent::DefaultData(
AudioComponent::GetClassDerivations(),
AudioComponent::GetMessageHandlers()
);
//
//#############################################################################
//#############################################################################
//
AudioComponent::AudioComponent(
PlugStream *stream,
SharedData &shared_data
):
Component(stream, shared_data),
audioWatcherSocket(NULL)
{
nextExecuteWatcherFrame = NullAudioFrameCount;
}
//
//#############################################################################
//#############################################################################
//
AudioComponent::~AudioComponent()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioComponent::TestInstance() const
{
if (!IsDerivedFrom(*GetClassDerivations()))
{
return False;
}
Check(&audioWatcherSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioComponent::ExecuteWatchers()
{
Check(this);
//
// Execute watchers if this is the next watcher frame
//
AudioFrameCount
audio_frame_count;
Check(application);
Check(application->GetAudioRenderer());
audio_frame_count = application->GetAudioRenderer()->GetAudioFrameCount();
if (nextExecuteWatcherFrame <= audio_frame_count)
{
nextExecuteWatcherFrame = audio_frame_count + DefaultAudioFrameDelay;
//
// Execute watchers
//
ChainIteratorOf<Component*>
iterator(&audioWatcherSocket);
Component
*component;
while ((component = iterator.ReadAndNext()) != NULL)
{
Check(component);
component->Execute();
}
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioComponent::Execute()
{
Check(this);
ExecuteWatchers();
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioComponent::ReceiveControl(
AudioControlID,
AudioControlValue
)
{
Fail("AudioComponent::ReceiveControl - Should never reach here");
}
//
//#############################################################################
//#############################################################################
//
void
AudioComponent::PostReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
ReceiveControlMessage
message(control_ID, control_value);
Check(application);
// ECH 1/26/96 - application->Post(HighEventPriority, this, &message);
application->Post(DefaultEventPriority, this, &message);
Check_Fpu();
}
//
//#############################################################################
//#############################################################################
//
void
AudioComponent::ReceiveControlMessageHandler(ReceiveControlMessage *message)
{
Check(this);
Check(message);
ReceiveControl(message->controlID, message->controlValue);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~ AudioComponent__ReceiveControlMessage ~~~~~~~~~~~~~~~~~~~~
AudioComponent__ReceiveControlMessage::AudioComponent__ReceiveControlMessage(
AudioControlID control_ID,
AudioControlValue control_value
):
Receiver::Message(
AudioComponent::ReceiveControlMessageID,
sizeof(AudioComponent__ReceiveControlMessage)
)
{
controlID = control_ID;
controlValue = control_value;
}
+655
View File
@@ -0,0 +1,655 @@
#pragma once
#include "style.h"
#include "entity.h"
#include "sphere.h"
#include "slot.h"
#include "table.h"
class PlugStream;
//
//--------------------------------------------------------------------------
// Support types
//--------------------------------------------------------------------------
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Time types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef long AudioTick;
typedef long AudioDivisionsPerBeat;
typedef long AudioTempo;
typedef long AudioFrameCount;
const AudioFrameCount NullAudioFrameCount = -1;
const AudioFrameCount DefaultAudioFrameDelay = 2;
extern const Scalar AudioDoubleTriggerCutoff;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Resource types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
typedef int AudioResourceID;
typedef int AudioVoiceCount;
typedef Scalar AudioRadiationProfile;
typedef Scalar AudioPitchCents;
enum AudioRenderType
{
TransientAudioRenderType = 0,
SustainedAudioRenderType = 1
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Source types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum AudioRepresentation
{
InternalAudioRepresentation = 0,
ExternalAudioRepresentation = 1
};
#define AUDIO_SOURCE_PRIORITY_COUNT (5)
enum AudioSourcePriority
{
MinAudioSourcePriority = 0,
LowAudioSourcePriority = 1,
MedAudioSourcePriority = 2,
HighAudioSourcePriority = 3,
MaxAudioSourcePriority = 4
};
enum AudioSourceState
{
StoppedAudioSourceState = 0,
DormantAudioSourceState = 1,
RunningAudioSourceState = 2,
SuspendedAudioSourceState = 3
};
enum AudioSourceMixPresence
{
ManualAudioSourceMixPresence = 0,
MaxAudioSourceMixPresence = 1,
HighAudioSourceMixPresence = 2,
MedAudioSourceMixPresence = 3,
LowAudioSourceMixPresence = 4,
MinAudioSourceMixPresence = 5
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Control types ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum AudioControlID
{
NullAudioControlID = 0,
StartAudioControlID,
StopAudioControlID,
VolumeAudioControlID,
PitchAudioControlID,
BrightnessAudioControlID,
AttackVolumeAudioControlID,
AttackTimeAudioControlID,
NoteAudioControlID,
IdleAudioControlID,
DurationAudioControlID,
FlushMessagesAudioControlID,
TempoAudioControlID,
AudioControlIDCount
};
typedef Scalar AudioControlValue;
extern const AudioControlValue MaxAudioVolume;
extern const AudioControlValue MinAudioVolume;
extern const AudioControlValue LowAudioVolumeThreshold;
extern const AudioControlValue MaxAudioBrightness;
extern const AudioControlValue MinAudioBrightness;
extern const AudioControlValue MaxAudioAttack;
extern const AudioControlValue MinAudioAttack;
#if 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioClippingSphere ~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioClippingSphere SIGNATURED
{
public:
AudioClippingSphere();
~AudioClippingSphere();
void
SetReferenceRadius(Scalar radius);
void
SetCurrentOrigin(const Point3D &origin);
void
SetCurrentScale(Scalar scale);
Logical
Contains(const Point3D &point) const;
private:
Scalar
referenceRadius;
Sphere
currentSphere;
};
//~~~~~~~~~~~~~~~~~~~~~~~ AudioClippingSphere inlines ~~~~~~~~~~~~~~~~~~~~~~
inline AudioClippingSphere::AudioClippingSphere():
referenceRadius(100.0f),
currentSphere(0.0f, 0.0f, 0.0f, 100.0f)
{
}
inline AudioClippingSphere::~AudioClippingSphere()
{
}
inline void
AudioClippingSphere::SetReferenceRadius(Scalar radius)
{
Check(this);
referenceRadius = radius;
currentSphere.radius = radius;
}
inline void
AudioClippingSphere::SetCurrentOrigin(const Point3D &origin)
{
Check(this);
currentSphere.center = origin;
}
inline void
AudioClippingSphere::SetCurrentScale(Scalar scale)
{
Check(this);
currentSphere.radius = scale * referenceRadius;
}
inline Logical
AudioClippingSphere::Contains(const Point3D &point) const
{
Check(this);
return currentSphere.Contains(point);
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHead ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioSource;
class AudioHead SIGNATURED
{
public:
//
//-----------------------------------------------------------------------
// Construction, Destruction, Testing
//-----------------------------------------------------------------------
//
AudioHead();
~AudioHead();
Logical
TestInstance() const;
//
//-----------------------------------------------------------------------
// Get current frame of audio simulation
//-----------------------------------------------------------------------
//
AudioFrameCount
GetAudioFrameCount()
{return audioFrameCount;}
//
//-----------------------------------------------------------------------
// Sets the location and orientation of the head
//-----------------------------------------------------------------------
//
virtual void
LinkToEntity(Entity *entity);
Entity*
GetHeadEntity();
//
//-----------------------------------------------------------------------
// Get the ear to world linear matrix
//-----------------------------------------------------------------------
//
virtual LinearMatrix
GetEarToWorld();
//
//-----------------------------------------------------------------------
// Execute
//-----------------------------------------------------------------------
//
virtual void
Execute();
//
//-----------------------------------------------------------------------
// Sets the distance between ears. Expressed in meters.
//-----------------------------------------------------------------------
//
void
SetDistanceBetweenEars(Scalar distance)
{distanceBetweenEars = distance;}
Scalar
GetDistanceBetweenEars()
{return distanceBetweenEars;}
//
//-----------------------------------------------------------------------
// Controls Doppler effects
//-----------------------------------------------------------------------
//
void
ControlDopplerEffect(
Scalar doppler_constant,
Scalar sound_speed
);
Scalar
GetAudioSoundSpeed()
{return audioSoundSpeed;}
AudioPitchCents
GetAudioDopplerConstant()
{return audioDopplerConstant;}
//
//-----------------------------------------------------------------------
// Reverb scaling
//-----------------------------------------------------------------------
//
void
SetReverbToDryRatio(Scalar ratio)
{reverbToDryRatio = ratio;}
Scalar
GetReverbToDryRatio()
{return reverbToDryRatio;}
// HACK
void
SetGlobalReverbScale(Scalar global_reverb_scale)
{globalReverbScale = global_reverb_scale;}
Scalar
GetGlobalReverbScale()
{return globalReverbScale;}
//
//-----------------------------------------------------------------------
// Controls the attenuation of an audio source with respect to its
// distance from the head.
//-----------------------------------------------------------------------
//
void
ControlAmplitudeRollOff(
Scalar exponent,
Scalar amplitude_rolloff_knee,
Scalar distance_scale
);
Scalar
GetAmplitudeRollOffExponent()
{return amplitudeRollOffExponent;}
Scalar
GetAmplitudeRollOffKnee()
{return amplitudeRollOffKnee;}
Scalar
GetAmplitudeRollOffDistanceScale()
{return amplitudeRollOffDistanceScale;}
//
//-----------------------------------------------------------------------
// Controls the attenuation of the high frequencies
// of an audio source with respect to its distance from
// the head.
//-----------------------------------------------------------------------
//
void
ControlHighFrequencyRollOff(
Scalar exponent,
Scalar high_frequency_rolloff_knee,
Scalar distance_scale
);
Scalar
GetHighFrequencyRollOffExponent()
{return highFrequencyRollOffExponent;}
Scalar
GetHighFrequencyRollOffKnee()
{return highFrequencyRollOffKnee;}
Scalar
GetHighFrequencyRollOffDistanceScale()
{return highFrequencyRollOffDistanceScale;}
//
//-----------------------------------------------------------------------
// Controls source compression
//-----------------------------------------------------------------------
//
void
ControlSourceCompression(
Scalar exponent,
Scalar scale
);
Scalar
GetSourceCompressionExponent()
{return sourceCompressionExponent;}
Scalar
GetSourceCompressionScale()
{return sourceCompressionScale;}
//
//-----------------------------------------------------------------------
// Defines the audio clipping sphere
//-----------------------------------------------------------------------
//
void
DefineClippingSphere(Scalar radius);
Logical
IsPointClipped(const Point3D &point);
Scalar
GetClippingRadius()
{return clippingRadius;}
//
//-----------------------------------------------------------------------
// ITD Difference
//-----------------------------------------------------------------------
//
void
SetITDDifference(Scalar itd_difference)
{itdDifference = itd_difference;}
Scalar
GetITDDifference()
{return itdDifference;}
//
//-----------------------------------------------------------------------
// The SetPositionalCulling method allows the rendering process to
// not play audio locations whose positions are masked by other
// audio sources. This has found to be useful for controlling
// audio when resources are limited, but must be
// selectable globally or on a per audio effect basis.
//-----------------------------------------------------------------------
//
void
SetPositionalCulling(Logical turn_on);
private:
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
AudioFrameCount
audioFrameCount;
SlotOf<Entity*>
headEntitySocket;
Scalar
clippingRadius;
Scalar
distanceBetweenEars;
Scalar
amplitudeRollOffExponent,
amplitudeRollOffKnee,
amplitudeRollOffDistanceScale;
Scalar
highFrequencyRollOffExponent,
highFrequencyRollOffKnee,
highFrequencyRollOffDistanceScale;
Scalar
reverbToDryRatio;
Scalar
audioSoundSpeed;
Scalar
audioDopplerConstant;
Scalar
sourceCompressionExponent,
sourceCompressionScale;
Scalar
itdDifference;
Scalar
globalReverbScale;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioHead inlines ~~~~~~~~~~~~~~~~~~~~~~~~~
inline Entity*
AudioHead::GetHeadEntity()
{
Check(this);
return headEntitySocket.GetCurrent();
}
//##########################################################################
//######################### AudioComponent ###########################
//##########################################################################
class AudioComponent__ReceiveControlMessage;
class AudioComponent:
public Component
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
AudioComponent(
PlugStream *stream,
SharedData &shared_data = DefaultData
);
~AudioComponent();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Audio Component Methods
//
public:
void
AddWatcher(Component *component);
void
ExecuteWatchers();
void
Execute();
virtual void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
void
PostReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
enum {
ReceiveControlMessageID = Component::NextMessageID,
NextMessageID
};
typedef AudioComponent__ReceiveControlMessage
ReceiveControlMessage;
static const HandlerEntry
MessageHandlerEntries[];
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
void
ReceiveControlMessageHandler(
ReceiveControlMessage *message
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation *GetClassDerivations();
static SharedData
DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Data
//
private:
AudioFrameCount
nextExecuteWatcherFrame;
ChainOf<Component*>
audioWatcherSocket;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioComponent inlines ~~~~~~~~~~~~~~~~~~~~~~~~
inline void
AudioComponent::AddWatcher(Component *component)
{
Check(component);
Check(&audioWatcherSocket);
audioWatcherSocket.Add(component);
}
//~~~~~~~~~~~~~~~~~~ AudioComponent__ReceiveControlMessage ~~~~~~~~~~~~~~~~~
class AudioComponent__ReceiveControlMessage:
public Receiver::Message
{
friend class AudioComponent;
public:
AudioComponent__ReceiveControlMessage(
AudioControlID control_ID,
AudioControlValue control_value
);
private:
AudioControlID
controlID;
AudioControlValue
controlValue;
};
//~~~~~~~~~~~~~~~~~~~~~~~~ Resource type inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioRenderType *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioRenderType *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioRepresentation *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioRepresentation *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ Source type inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioSourceState *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioSourceState *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioSourcePriority *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioSourcePriority *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioSourceMixPresence *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioSourceMixPresence *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ Control type inlines ~~~~~~~~~~~~~~~~~~~~~~~~~
inline MemoryStream&
MemoryStream_Read(
MemoryStream* stream,
AudioControlID *output
)
{
return stream->ReadBytes(output, sizeof(*output));
}
inline MemoryStream&
MemoryStream_Write(
MemoryStream* stream,
const AudioControlID *input
)
{
return stream->WriteBytes(input, sizeof(*input));
}
+508
View File
@@ -0,0 +1,508 @@
#include "munga.h"
#pragma hdrstop
#include "audloc.h"
#include "objstrm.h"
#include "namelist.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLocation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioLocation::AudioLocation(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
vectorToSource(0.0f, 0.0f, 0.0f),
locationOffset(0.0f, 0.0f, 0.0f)
{
AudioFrameCount next_update_delay;
Scalar clipping_scale;
MemoryStream_Read(stream, &locationOffset);
MemoryStream_Read(stream, &next_update_delay);
MemoryStream_Read(stream, &clipping_scale);
AudioLocationX(entity, next_update_delay, clipping_scale);
}
//
//#############################################################################
//#############################################################################
//
AudioLocation::~AudioLocation()
{
}
//
//#############################################################################
//#############################################################################
//
void
AudioLocation::AudioLocationX(
Entity *entity,
AudioFrameCount next_update_delay,
Scalar clipping_scale
)
{
Check(entity);
linkedEntity = entity;
entity->AddAudioComponent(this);
clippingScale = clipping_scale;
isHeadSource = False;
distanceToSource = 1.0f;
dopplerCents = 0;
#if 0
angleOffOrientation = 0.0f;
#endif
azimuthOfSource = 0.0f;
distanceVolumeScale = 1.0f;
highFreqCutoffScale = 1.0f;
#if 0
reverbVolumeScale = 0.0f;
#endif
nextUpdateDelay = next_update_delay;
nextUpdateFrame = NullAudioFrameCount;
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioLocation::TestInstance() const
{
Component::TestInstance();
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioLocation::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Point3D, location_offset);
//
// Read update delay
//
CString update_delay_string("update_delay");
AudioFrameCount update_delay = DefaultAudioFrameDelay;
if (name_list->FindData(update_delay_string) != NULL)
{
Check_Pointer(name_list->FindData(update_delay_string));
Convert_From_Ascii(
(const char *)name_list->FindData(update_delay_string),
&update_delay
);
}
MemoryStream_Write(stream, &update_delay);
//
// Read culling scale
//
CString clipping_scale_string("clipping_scale");
Scalar clipping_scale = 1.0f;
if (name_list->FindData(clipping_scale_string) != NULL)
{
Check_Pointer(name_list->FindData(clipping_scale_string));
Convert_From_Ascii(
(const char *)name_list->FindData(clipping_scale_string),
&clipping_scale
);
}
MemoryStream_Write(stream, &clipping_scale);
}
//
//#############################################################################
//#############################################################################
//
void
AudioLocation::ReceiveControl(
AudioControlID,
AudioControlValue
)
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioLocation::IsAudioLocationClipped(AudioHead *audio_head)
{
Check(this);
Check(audio_head);
//
// HACK - This is a rough approximation in that it does not
// take into account the offset of the location from the
// center of the entity. But, this is more efficient and is OK
// as long as the clipping sphere does not exclude the location
// unnaturally
//
Entity
*head_entity;
Vector3D
difference;
Scalar
scaled_radius;
head_entity = audio_head->GetHeadEntity();
Check(head_entity);
Check(linkedEntity);
difference.Subtract(
head_entity->localOrigin.linearPosition,
linkedEntity->localOrigin.linearPosition
);
scaled_radius = audio_head->GetClippingRadius() * clippingScale;
return difference.LengthSquared() > scaled_radius * scaled_radius;
}
//
//#############################################################################
//#############################################################################
//
void
AudioLocation::UpdateSpatialModelImplementation(AudioHead *audio_head)
{
Check(this);
Check(audio_head);
//
//--------------------------------------------------------------------------
// Get head and source entity
//--------------------------------------------------------------------------
//
Entity *source_entity = GetLinkedEntity();
Entity *head_entity = audio_head->GetHeadEntity();
Check(source_entity);
Check(head_entity);
//
//--------------------------------------------------------------------------
// Catch case of head == source at origin
//--------------------------------------------------------------------------
//
if (
head_entity == source_entity &&
locationOffset == Vector3D::Identity
)
{
isHeadSource = True;
vectorToSource = Vector3D::Identity;
distanceToSource = 0.0f;
dopplerCents = 0;
#if 0
angleOffOrientation = 0.0f;
#endif
azimuthOfSource = 0.0f;
distanceVolumeScale = 1.0f;
highFreqCutoffScale = 1.0f;
#if 0
reverbVolumeScale = audio_head->GetReverbToDryRatio();
#endif
return;
}
isHeadSource = False;
//
//--------------------------------------------------------------------------
// Get the ear to world linear matrix
//--------------------------------------------------------------------------
//
LinearMatrix ear_to_world = audio_head->GetEarToWorld();
//
//--------------------------------------------------------------------------
// Calculate vector to source with respect to local coordinate system
// of the ears
//--------------------------------------------------------------------------
//
{
//
// Get the source location offset from the entity position in
// world coordinates
//
Vector3D world_location_offset;
Vector3D world_source_location;
world_location_offset.Multiply(
locationOffset,
source_entity->localToWorld
);
Check(&world_location_offset);
world_source_location.Add(
source_entity->localOrigin.linearPosition,
world_location_offset
);
Check(&world_source_location);
//
// Get the vector from the ear to the source, note that the vector
// is not calculated by the ears offset but from the entities location
//
Vector3D world_ear_to_source_vector;
world_ear_to_source_vector.Subtract(
world_source_location,
head_entity->localOrigin.linearPosition
);
Check(&world_ear_to_source_vector);
//
// Transform the vector into ear coordinates
//
vectorToSource.MultiplyByInverse(
world_ear_to_source_vector,
ear_to_world
);
Check(&vectorToSource);
}
//
//--------------------------------------------------------------------------
// Calculate distance to source
//--------------------------------------------------------------------------
//
distanceToSource = vectorToSource.Length();
//
//--------------------------------------------------------------------------
// Calculate normal to source
//--------------------------------------------------------------------------
//
Vector3D normal_to_source(0.0f, 0.0f, -1.0f);
if (!Small_Enough(distanceToSource))
{
normal_to_source.Normalize(vectorToSource);
Check(&normal_to_source);
}
#if 0
//
//--------------------------------------------------------------------------
// Calculate angle between the orientation of the head and source
//--------------------------------------------------------------------------
//
if (Small_Enough(distanceToSource))
{
angleOffOrientation = 0.0f;
}
else
{
UnitVector direction;
Scalar cosine;
ear_to_world.GetToAxis(Z_Axis, &direction);
Check(&direction);
Check(&normal_to_source);
cosine = normal_to_source * direction;
Clamp(cosine, -1.0f, 1.0f);
angleOffOrientation = Arccos(cosine);
angleOffOrientation.Normalize();
}
Verify(
angleOffOrientation <= 180.0f*RAD_PER_DEG &&
angleOffOrientation >= -180.0f*RAD_PER_DEG
);
#endif
//
//--------------------------------------------------------------------------
// Calculate azimuth
//--------------------------------------------------------------------------
//
if (Small_Enough(vectorToSource.x) && Small_Enough(vectorToSource.z))
{
azimuthOfSource = 0.0f;
}
else
{
Verify(!(Small_Enough(vectorToSource.x) && Small_Enough(vectorToSource.z)));
azimuthOfSource = Arctan(vectorToSource.x, vectorToSource.z);
}
Verify(
azimuthOfSource <= 180.0f*RAD_PER_DEG &&
azimuthOfSource >= -180.0f*RAD_PER_DEG
);
//
//--------------------------------------------------------------------------
// Calculate distance volume scaling
// Apply clipping scale to rolloff distance scale, thereby giving this
// audio location a specifc rolloff characteristic
//--------------------------------------------------------------------------
//
if (distanceToSource > audio_head->GetAmplitudeRollOffKnee())
{
//
// y = 1 / 1 + (K(x - knee))^exp
//
Verify(!Small_Enough(clippingScale));
const Scalar temp =
(audio_head->GetAmplitudeRollOffDistanceScale() / clippingScale) *
(distanceToSource - audio_head->GetAmplitudeRollOffKnee());
const Scalar temp2 =
1.0f + pow(temp, audio_head->GetAmplitudeRollOffExponent());
Verify(!Small_Enough(temp2));
distanceVolumeScale = 1.0f / temp2;
}
else
{
distanceVolumeScale = 1.0f;
}
Verify(distanceVolumeScale >= 0.0f && distanceVolumeScale <= 1.0f);
//
//--------------------------------------------------------------------------
// Calculate high frequency cutoff scaling
// Apply clipping scale to high frequency rolloff distance scale, thereby
// giving this audio location a specifc rolloff characteristic
//--------------------------------------------------------------------------
//
if (distanceToSource > audio_head->GetHighFrequencyRollOffKnee())
{
//
// y = 1 / 1 + (K(x - knee))^exp
//
Verify(!Small_Enough(clippingScale));
const Scalar temp =
(audio_head->GetHighFrequencyRollOffDistanceScale() / clippingScale) *
(distanceToSource - audio_head->GetHighFrequencyRollOffKnee());
const Scalar temp2 =
1.0f + pow(temp, audio_head->GetHighFrequencyRollOffExponent());
Verify(!Small_Enough(temp2));
highFreqCutoffScale = 1.0f / temp2;
}
else
{
highFreqCutoffScale = 1.0f;
}
Verify(highFreqCutoffScale >= 0.0f && highFreqCutoffScale <= 1.0f);
#if 0
//
//--------------------------------------------------------------------------
// Calculate reverb volume scaling
//--------------------------------------------------------------------------
//
if (distanceToSource > audio_head->GetAmplitudeRollOffKnee())
{
const Scalar temp =
distanceToSource - audio_head->GetAmplitudeRollOffKnee() + 1.0f;
reverbVolumeScale =
audio_head->GetReverbToDryRatio() *
pow(temp, audio_head->GetAmplitudeRollOffExponent());
if (reverbVolumeScale > 1.0f)
reverbVolumeScale = 1.0f;
}
else
{
reverbVolumeScale = audio_head->GetReverbToDryRatio();
}
Verify(reverbVolumeScale >= 0.0f && reverbVolumeScale <= 1.0f);
#endif
//
//--------------------------------------------------------------------------
// Calculate relative velocity of source
//--------------------------------------------------------------------------
//
Vector3D relative_velocity_temp;
Vector3D relative_velocity;
relative_velocity_temp.Subtract(
source_entity->GetWorldLinearVelocity(),
head_entity->GetWorldLinearVelocity()
);
Check(&relative_velocity_temp);
relative_velocity.MultiplyByInverse(
relative_velocity_temp,
head_entity->localToWorld
);
Check(&relative_velocity);
//
//--------------------------------------------------------------------------
// Calculate doppler shift in cents
// cents = (c / (c - v)) / ScaleRatio
//--------------------------------------------------------------------------
//
if (!Small_Enough(distanceToSource))
{
AudioPitchCents
cents;
Scalar speed_of_source =
normal_to_source * relative_velocity;
const Scalar ear_radius =
audio_head->GetDistanceBetweenEars() * 0.5f;
if (distanceToSource < ear_radius)
{
Verify(!Small_Enough(ear_radius));
speed_of_source *= (distanceToSource / ear_radius);
}
if (CalculateDoppler(audio_head, speed_of_source, &cents))
{
dopplerCents = cents;
}
}
else
{
dopplerCents = 0;
}
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioLocation::CalculateDoppler(
AudioHead *audio_head,
Scalar speed,
AudioPitchCents *result
)
{
Check(this);
Check(audio_head);
Check_Pointer(result);
Scalar speed_of_sound = audio_head->GetAudioSoundSpeed();
Clamp(speed, -speed_of_sound, speed_of_sound);
if (!Small_Enough(speed_of_sound - speed))
{
*result = audio_head->GetAudioDopplerConstant() *
( 1 - speed_of_sound / (speed_of_sound - speed) );
return True;
}
return False;
}
+202
View File
@@ -0,0 +1,202 @@
#pragma once
#include "style.h"
#include "audio.h"
//##########################################################################
//######################## AudioLocation #############################
//##########################################################################
class AudioLocation:
public AudioComponent
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
AudioLocation(
PlugStream *stream,
Entity *entity
);
void
AudioLocationX(
Entity *entity,
AudioFrameCount next_update_delay,
Scalar clipping_scale
);
~AudioLocation();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resource Building
//
public:
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Audio Component Support
//
public:
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Audio Location Support
//
public:
//
//-----------------------------------------------------------------------
// GetLinkedEntity
//-----------------------------------------------------------------------
//
Entity*
GetLinkedEntity();
//
//-----------------------------------------------------------------------
// IsAudioLocationClipped
//-----------------------------------------------------------------------
//
Logical
IsAudioLocationClipped(AudioHead *audio_head);
//
//-----------------------------------------------------------------------
// UpdateSpatialModel
//-----------------------------------------------------------------------
//
void
UpdateSpatialModel(AudioHead *audio_head);
//
//-----------------------------------------------------------------------
// Access to localization results
//-----------------------------------------------------------------------
//
Logical
IsHeadSource()
{return isHeadSource;}
Scalar
GetDistanceToSource()
{return distanceToSource;}
Scalar
GetDistanceToSourceListenerPlane();
Radian
GetAzimuthOfSource()
{return azimuthOfSource;}
Scalar
GetDistanceVolumeScale()
{return distanceVolumeScale;}
Scalar
GetHighFreqCutoffScale()
{return highFreqCutoffScale;}
AudioPitchCents
GetDopplerCents()
{return dopplerCents;}
Scalar getMaxDistance(AudioHead *audio_head) {return audio_head->GetClippingRadius() * clippingScale;}
Vector3D GetVectorToSource() { return this->vectorToSource; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Protected Implementations
//
protected:
virtual void
UpdateSpatialModelImplementation(AudioHead *audio_head);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Methods
//
private:
Logical
CalculateDoppler(
AudioHead *audio_head,
Scalar speed,
AudioPitchCents *result
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Data
//
private:
Entity
*linkedEntity;
Point3D
locationOffset;
Scalar
clippingScale;
Logical
isHeadSource;
Vector3D
vectorToSource;
Scalar
distanceToSource;
#if 0
Radian
angleOffOrientation;
#endif
Radian
azimuthOfSource;
Scalar
distanceVolumeScale;
Scalar
highFreqCutoffScale;
#if 0
Scalar
reverbVolumeScale;
#endif
AudioPitchCents
dopplerCents;
AudioFrameCount
nextUpdateDelay;
AudioFrameCount
nextUpdateFrame;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLocation inlines ~~~~~~~~~~~~~~~~~~~~~~~~
inline Entity*
AudioLocation::GetLinkedEntity()
{
Check(this);
return linkedEntity;
}
inline Scalar
AudioLocation::GetDistanceToSourceListenerPlane()
{
Check(this);
Vector3D
vector_to_source_listener_plane(
vectorToSource.x,
0.0f,
vectorToSource.z
);
return vector_to_source_listener_plane.Length();
}
inline void
AudioLocation::UpdateSpatialModel(AudioHead *audio_head)
{
Check(this);
Check(audio_head);
if (nextUpdateFrame <= audio_head->GetAudioFrameCount())
{
nextUpdateFrame = audio_head->GetAudioFrameCount() + nextUpdateDelay;
UpdateSpatialModelImplementation(audio_head);
}
}
+450
View File
@@ -0,0 +1,450 @@
#include "munga.h"
#pragma hdrstop
#include "audlvl.h"
#include "objstrm.h"
#include "namelist.h"
#include "app.h"
#include "audrend.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioLevelOfDetail ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioLevelOfDetail::AudioLevelOfDetail(PlugStream *stream):
Plug(stream)
{
#if 0
amplitudeRadiationProfile = 0.0f;
filterRadiationProfile = 0.0f;
#endif
//
// Read fields
//
MemoryStream_Read(stream, &voiceCount);
MemoryStream_Read(stream, &audioRenderType);
//
// Read suspend seconds and calculate suspendDelay
//
Scalar
suspend_delay_seconds;
MemoryStream_Read(stream, &suspend_delay_seconds);
Check(application);
Check(application->GetAudioRenderer());
suspendDelay = suspend_delay_seconds *
application->GetAudioRenderer()->GetCalibrationRate() + 0.5f;
}
//
//#############################################################################
//#############################################################################
//
void
AudioLevelOfDetail::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
Plug::BuildFromPage(stream, name_list, class_ID, object_ID);
//
// Store fields
//
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioVoiceCount, voice_count);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, render_type);
//
// Store suspend delay
//
CString suspend_delay_string("suspend_delay");
Scalar suspend_delay_seconds = 0.33f; // HACK - should come from somewhere else
if (name_list->FindData(suspend_delay_string) != NULL)
{
Check_Pointer(name_list->FindData(suspend_delay_string));
Convert_From_Ascii(
(const char *)name_list->FindData(suspend_delay_string),
&suspend_delay_seconds
);
}
MemoryStream_Write(stream, &suspend_delay_seconds);
}
//
//#############################################################################
//#############################################################################
//
AudioLevelOfDetail::~AudioLevelOfDetail()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioLevelOfDetail::TestInstance() const
{
Plug::TestInstance();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResource ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioResource::AudioResource(PlugStream *stream):
Node(stream),
audioLevelOfDetailSocket(NULL, True)
{
//
// Read the table
//
CollectionSize i, number_of_entries;
MemoryStream_Read(stream, &number_of_entries);
for (i = 0; i < number_of_entries; i++)
{
Scalar distance;
AudioLevelOfDetail *audio_level_of_detail;
MemoryStream_Read(stream, &distance);
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_level_of_detail);
Check(audio_level_of_detail);
audioLevelOfDetailSocket.AddValue(audio_level_of_detail, distance);
}
//
// Verify that there is at least one entry and the first one is at 0.0f
//
#if DEBUG_LEVEL>0
{
TableIteratorOf<AudioLevelOfDetail*, Scalar> iterator(&audioLevelOfDetailSocket);
Check(&iterator);
Verify(iterator.GetSize() > 0);
Verify(iterator.GetCurrent() != NULL);
Verify(iterator.GetValue() == 0.0f);
}
#endif
//
// Select the first entry
//
TableIteratorOf<AudioLevelOfDetail*, Scalar> iterator(&audioLevelOfDetailSocket);
audioLevelOfDetail = iterator.GetCurrent();
Check(audioLevelOfDetail);
}
//
//#############################################################################
//#############################################################################
//
void
AudioResource::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
Node::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_level_of_detail"))
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_level_of_detail"))
{
CString object_string;
Scalar distance;
ObjectID object_ID;
Check_Pointer(entry->GetChar());
object_string = entry->GetChar();
Check_Pointer(object_string.GetNthToken(0));
Convert_From_Ascii(object_string.GetNthToken(0), &distance);
MemoryStream_Write(stream, &distance);
Check(stream);
Check_Pointer(object_string.GetNthToken(1));
object_ID = stream->FindObjectID(object_string.GetNthToken(1));
Verify(object_ID != NullObjectID);
MemoryStream_Write(stream, &object_ID);
}
entry = entry->GetNextEntry();
}
}
//
//#############################################################################
//#############################################################################
//
AudioResource::~AudioResource()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioResource::TestInstance() const
{
Node::TestInstance();
Check(&audioLevelOfDetailSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioResource::SetDistance(Scalar distance)
{
Check(this);
Verify(distance >= 0.0f);
//
// Goto the last entry
//
TableIteratorOf<AudioLevelOfDetail*, Scalar>
iterator(&audioLevelOfDetailSocket);
Check(&iterator);
iterator.Last();
//
// While the distance is less than the distance of the entry
//
while (distance < iterator.GetValue())
{
iterator.Previous();
}
audioLevelOfDetail = iterator.GetCurrent();
Check(audioLevelOfDetail);
//
// Verify that the distance is greater than this entry, and less than
// the next
//
#if DEBUG_LEVEL>0
Verify(distance >= iterator.GetValue());
iterator.Next();
if (iterator.GetCurrent() != NULL)
{
Verify(distance < iterator.GetValue());
}
#endif
//
// Dump the LOD of the resource
//
#if 0
CollectionSize i = 0;
iterator.First();
while (iterator.GetCurrent() != NULL)
{
Check(iterator.GetCurrent());
if (audioLevelOfDetail == iterator.GetCurrent() /* && i > 0 */ )
{
Tell(
"AudioLOD:" << i <<
" d:" << distance <<
" t:" << iterator.GetValue() <<
"\n"
);
break;
}
iterator.Next();
i++;
}
#endif
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResourceIndex ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioResourceIndex::AudioResourceIndex(PlugStream *stream):
Node(stream),
audioResourceSocket(NULL, True)
{
CollectionSize i, number_of_entries;
MemoryStream_Read(stream, &number_of_entries);
for (i = 0; i < number_of_entries; i++)
{
AudioResource *audio_resource;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource);
Check(audio_resource);
AddAudioResource(audio_resource, i);
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioResourceIndex::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
Node::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_resource"))
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_resource"))
{
CString object_name;
ObjectID object_ID;
Check_Pointer(entry->GetChar());
object_name = entry->GetChar();
Check(stream);
object_ID = stream->FindObjectID(object_name);
Verify(object_ID != NullObjectID);
MemoryStream_Write(stream, &object_ID);
}
entry = entry->GetNextEntry();
}
}
//
//#############################################################################
//#############################################################################
//
AudioResourceIndex::~AudioResourceIndex()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioResourceIndex::TestInstance() const
{
Node::TestInstance();
Check(&audioResourceSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioResourceIndex::AddAudioResource(
AudioResource *audio_resource,
Enumeration index
)
{
Check(this);
audioResourceSocket.AddValue(audio_resource, index);
#if DEBUG_LEVEL>0
TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
Check(&iterator);
for (int i = 0; i < iterator.GetSize(); i++)
{
Verify(iterator.GetNth(i) == audioResourceSocket.Find(i));
}
#endif
}
//
//#############################################################################
//#############################################################################
//
AudioResource*
AudioResourceIndex::GetAudioResource(Enumeration index)
{
Check(this);
TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
Check(&iterator);
Verify(iterator.GetNth(index) == audioResourceSocket.Find(index));
return iterator.GetNth(index);
}
//
//#############################################################################
//#############################################################################
//
CollectionSize
AudioResourceIndex::GetSize()
{
Check(this);
TableIteratorOf<AudioResource*, Enumeration> iterator(&audioResourceSocket);
Check(&iterator);
return iterator.GetSize();
}
+247
View File
@@ -0,0 +1,247 @@
#pragma once
#include "style.h"
#include "audio.h"
//##########################################################################
//####################### AudioLevelOfDetail #########################
//##########################################################################
class AudioLevelOfDetail:
public Plug
{
public:
//
//-----------------------------------------------------------------------
// Construction, Destruction, Testing
//-----------------------------------------------------------------------
//
AudioLevelOfDetail(PlugStream *stream);
~AudioLevelOfDetail();
Logical
TestInstance() const;
//
//-----------------------------------------------------------------------
// BuildFromPage
//-----------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//-----------------------------------------------------------------------
// Accessors
//-----------------------------------------------------------------------
//
virtual AudioVoiceCount
GetVoiceCount()
{return voiceCount;}
AudioRenderType
GetAudioRenderType()
{return audioRenderType;}
AudioFrameCount
GetSuspendDelay()
{return suspendDelay;}
private:
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
#if 0
//
//-----------------------------------------------------------------------
// Defines the radial variation of the amplitude of the audio source.
// This feature is implemented well in Crystal River Engineering's
// API. The radiation profile of an audio source is specified with
// an array of sound levels in decibels paired with angles off of
// the audio source orientation. For example, you can design a
// rocket sound that is louder when heard from directly behind then
// from the side.
//-----------------------------------------------------------------------
//
AudioRadiationProfile
amplitudeRadiationProfile;
#endif
#if 0
//
//-----------------------------------------------------------------------
// Defines the radial variation of the high frequency content of the
// audio source. This concept is analogous to
// SetAmplitudeRadiationProfile except applied to the high frequency
// content of the audio source. Again, this allows the audio source
// to vary with respect to the position and orientation of the audio
// source and head.
//-----------------------------------------------------------------------
//
AudioRadiationProfile
filterRadiationProfile;
#endif
//
//-----------------------------------------------------------------------
// Misc
//-----------------------------------------------------------------------
//
AudioVoiceCount
voiceCount;
AudioRenderType
audioRenderType;
AudioFrameCount
suspendDelay;
};
//##########################################################################
//########################## AudioResource ############################
//##########################################################################
class AudioResource:
public Node
{
public:
//
//-----------------------------------------------------------------------
// Construction, Destruction, Testing
//-----------------------------------------------------------------------
//
AudioResource(PlugStream *stream);
~AudioResource();
Logical
TestInstance() const;
//
//-----------------------------------------------------------------------
// BuildFromPage
//-----------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//
//-----------------------------------------------------------------------
// SetDistance
//-----------------------------------------------------------------------
//
void
SetDistance(Scalar distance);
//
//-----------------------------------------------------------------------
// Accessors
//-----------------------------------------------------------------------
//
AudioVoiceCount
GetVoiceCount();
AudioRenderType
GetAudioRenderType();
AudioFrameCount
GetSuspendDelay();
protected:
//
//-----------------------------------------------------------------------
// Protected data
//-----------------------------------------------------------------------
//
AudioLevelOfDetail*
GetAudioLevelOfDetail();
private:
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
AudioLevelOfDetail
*audioLevelOfDetail;
TableOf<AudioLevelOfDetail*, Scalar>
audioLevelOfDetailSocket;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioResource inlines ~~~~~~~~~~~~~~~~~~~~~~~~~
inline AudioLevelOfDetail*
AudioResource::GetAudioLevelOfDetail()
{
Check(this);
return audioLevelOfDetail;
}
inline AudioVoiceCount
AudioResource::GetVoiceCount()
{
Check(this);
Check(audioLevelOfDetail);
return audioLevelOfDetail->GetVoiceCount();
}
inline AudioRenderType
AudioResource::GetAudioRenderType()
{
Check(this);
Check(audioLevelOfDetail);
return audioLevelOfDetail->GetAudioRenderType();
}
inline AudioFrameCount
AudioResource::GetSuspendDelay()
{
Check(this);
Check(audioLevelOfDetail);
return audioLevelOfDetail->GetSuspendDelay();
}
//##########################################################################
//######################## AudioResourceIndex ########################
//##########################################################################
class AudioResourceIndex:
public Node
{
public:
AudioResourceIndex(PlugStream *stream);
~AudioResourceIndex();
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
void
AddAudioResource(
AudioResource *audio_resource,
Enumeration index
);
AudioResource*
GetAudioResource(Enumeration index);
CollectionSize
GetSize();
private:
TableOf<AudioResource*, Enumeration>
audioResourceSocket;
};
+690
View File
@@ -0,0 +1,690 @@
#include "munga.h"
#pragma hdrstop
#include "audmidi.h"
//#############################################################################
//########################### MidiParse #################################
//#############################################################################
#define NOTEOFF (0x80)
#define NOTEON (0x90)
#define PRESSURE (0xa0)
#define CONTROLLER (0xb0)
#define PITCHBEND (0xe0)
#define PROGRAM (0xc0)
#define CHANPRESSURE (0xd0)
#define METATEXT "Text Event"
#define METACOPYRIGHT "Copyright Notice"
#define METASEQUENCE "Sequence/Track Name"
#define METAINSTRUMENT "Instrument Name"
#define METALYRIC "Lyric"
#define METAMARKER "Marker"
#define METACUE "Cue Point"
#define METAUNRECOGNIZED "Unrecognized"
#define CHAR_BUFF_SIZE (32)
//
//#############################################################################
//#############################################################################
//
MidiParse::MidiParse()
{
Mf_nomerge = 0; // 1 => continue'ed system exclusives are not collapsed.
Mf_currtime = 0L; // current time in delta-time units
Mf_skipinit = 0; // 1 if initial garbage should be skipped
Mf_toberead = 0L;
Msgbuff = NULL; // message buffer
Msgsize = 0; // Size of currently allocated Msg
Msgindex = 0; // index of next available location in Msg
}
//
//#############################################################################
//#############################################################################
//
MidiParse::~MidiParse()
{
if (Msgbuff != NULL)
{
Unregister_Pointer(Msgbuff);
#if 0
free(Msgbuff);
#else
delete[] Msgbuff;
#endif
Msgbuff = NULL;
}
}
//
//#############################################################################
//#############################################################################
//
Logical
MidiParse::TestInstance() const
{
Node::TestInstance();
return True;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedLongWord
MidiParse::CurTime()
{
Check(this);
return Mf_currtime;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::Parse()
{
Check(this);
SignedWord ntrks;
ntrks = readheader();
Verify(ntrks > 0);
while (ntrks-- > 0)
readtrack();
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::readmt(
char *s,
SignedWord skip
)
{
Check(this);
SignedWord nread = 0;
char b[4];
char buff[CHAR_BUFF_SIZE];
SignedWord c;
char *errmsg = "expecting ";
// read through the "MThd" or "MTrk" header string
// if 1, we attempt to skip initial garbage.
retry:
while ( nread<4 )
{
c = Mf_getc();
if ( c == EOF )
{
errmsg = "EOF while expecting ";
goto err;
}
b[nread++] = (char)c;
}
// See if we found the 4 characters we're looking for
if ( s[0]==b[0] && s[1]==b[1] && s[2]==b[2] && s[3]==b[3] )
return 0;
if ( skip )
{
// If we are supposed to skip initial garbage,
// try again with the next character.
b[0]=b[1];
b[1]=b[2];
b[2]=b[3];
nread = 3;
goto retry;
}
err:
Str_Copy(buff, errmsg, CHAR_BUFF_SIZE);
Str_Cat(buff, s, CHAR_BUFF_SIZE);
mferror(buff);
return 0;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::egetc()
{
Check(this);
// read a single character and abort on EOF
SignedWord c = Mf_getc();
if ( c == EOF )
mferror("premature EOF");
Mf_toberead--;
return c;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::readheader()
{
Check(this);
// read a header chunk
SignedWord
format, ntrks, division;
if ( readmt("MThd", Mf_skipinit) == EOF )
return 0;
Mf_toberead = read32bit();
format = read16bit();
ntrks = read16bit();
division = read16bit();
Mf_header(format,ntrks,division);
// flush any extra stuff, in case the length of header is not 6
while ( Mf_toberead > 0 )
egetc();
return ntrks;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::readtrack()
{
Check(this);
// read a track chunk
// This array is indexed by the high half of a status byte. It's
// value is either the number of bytes needed (1 or 2) for a channel
// message, or 0 (meaning it's not a channel message).
static SignedWord chantype[] =
{
0, 0, 0, 0, 0, 0, 0, 0, // 0x00 through 0x70
2, 2, 2, 2, 1, 1, 2, 0 // 0x80 through 0xf0
};
SignedLongWord lookfor, lng;
SignedWord c, c1, type;
SignedWord sysexcontinue = 0; // 1 if last message was an unfinished sysex
SignedWord running; // 1 when running status used
SignedWord status = 0; // (possibly running) status byte
SignedWord needed;
if ( readmt("MTrk",0) == EOF )
return;
Mf_toberead = read32bit();
Mf_currtime = 0;
Mf_starttrack();
while ( Mf_toberead > 0 )
{
Mf_currtime += readvarinum(); // delta time
c = egetc();
if ( sysexcontinue && c != 0xf7 )
mferror("didn't find expected continuation of a sysex");
if ( (c & 0x80) == 0 ) // running status?
{
if ( status == 0 )
mferror("unexpected running status");
running = 1;
}
else
{
status = c;
running = 0;
}
needed = chantype[ (status>>4) & 0xf ];
if ( needed ) // ie. is it a channel message?
{
if ( running )
c1 = c;
else
c1 = egetc();
chanmessage( status, c1, (needed>1) ? egetc() : (SignedWord)0 );
continue;
}
switch ( c )
{
case 0xff: // meta event
type = egetc();
// watch out - Don't combine the next 2 statements
lng = readvarinum();
lookfor = Mf_toberead - lng;
msginit();
while ( Mf_toberead > lookfor )
msgadd(egetc());
metaevent(type);
break;
case 0xf0: // start of system exclusive
// watch out - Don't combine the next 2 statements
lng = readvarinum();
lookfor = Mf_toberead - lng;
msginit();
msgadd(0xf0);
while ( Mf_toberead > lookfor )
msgadd(c=egetc());
if ( c==0xf7 || Mf_nomerge==0 )
sysex();
else
sysexcontinue = 1; // merge into next msg
break;
case 0xf7: // sysex continuation or arbitrary stuff
// watch out - Don't combine the next 2 statements
lng = readvarinum();
lookfor = Mf_toberead - lng;
if ( ! sysexcontinue )
msginit();
while ( Mf_toberead > lookfor )
msgadd(c=egetc());
if ( ! sysexcontinue )
{
Mf_arbitrary(msgleng(),msg());
}
else if ( c == 0xf7 )
{
sysex();
sysexcontinue = 0;
}
break;
default:
badbyte(c);
break;
}
}
Mf_endtrack();
return;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::badbyte(SignedWord c)
{
Check(this);
char buff[CHAR_BUFF_SIZE];
sprintf(buff,"unexpected byte: 0x%02x",c);
mferror(buff);
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::metaevent(SignedWord type)
{
Check(this);
SignedWord leng = msgleng();
char *m = msg();
switch ( type )
{
case 0x00:
Mf_seqnum(to16bit(m[0],m[1]));
break;
case 0x01: // Text event
case 0x02: // Copyright notice
case 0x03: // Sequence/Track name
case 0x04: // Instrument name
case 0x05: // Lyric
case 0x06: // Marker
case 0x07: // Cue point
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f:
// These are all text events
Mf_text(type,leng,m);
break;
case 0x2f: // End of Track
Mf_eot();
break;
case 0x51: // Set tempo
Mf_tempo(to32bit((SignedWord)0,m[0],m[1],m[2]));
break;
case 0x54:
Mf_smpte(m[0],m[1],m[2],m[3],m[4]);
break;
case 0x58:
Mf_timesig(m[0],m[1],m[2],m[3]);
break;
case 0x59:
Mf_keysig(m[0],m[1]);
break;
case 0x7f:
Mf_sqspecific(leng,m);
break;
default:
Mf_metamisc(type,leng,m);
}
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::sysex()
{
Check(this);
Mf_sysex(msgleng(),msg());
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::chanmessage(
SignedWord status,
SignedWord c1,
SignedWord c2
)
{
Check(this);
SignedWord chan = status & (SignedWord)0xf;
switch ( status & 0xf0 )
{
case NOTEOFF:
Mf_off(chan,c1,c2);
break;
case NOTEON:
Mf_on(chan,c1,c2);
break;
case PRESSURE:
Mf_pressure(chan,c1,c2);
break;
case CONTROLLER:
Mf_controller(chan,c1,c2);
break;
case PITCHBEND:
Mf_pitchbend(chan,c1,c2);
break;
case PROGRAM:
Mf_program(chan,c1);
break;
case CHANPRESSURE:
Mf_chanpressure(chan,c1);
break;
}
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedLongWord
MidiParse::readvarinum()
{
Check(this);
// readvarinum - read a varying-length number, and return the
// number of characters it took.
SignedLongWord value;
SignedWord c;
c = egetc();
value = c;
if (c & 0x80)
{
value &= 0x7f;
do
{
c = egetc();
value <<= 7;
value += (c & 0x7f);
} while (c & 0x80);
}
return value;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedLongWord
MidiParse::to32bit(SignedWord c1, SignedWord c2,SignedWord c3, SignedWord c4)
{
Check(this);
SignedLongWord value;
value = (c1 & 0xff);
value = (value<<8) + (c2 & 0xff);
value = (value<<8) + (c3 & 0xff);
value = (value<<8) + (c4 & 0xff);
return value;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::to16bit(SignedWord c1,SignedWord c2)
{
Check(this);
SignedWord value;
value = (c1 & (SignedWord)0xff);
value = (SignedWord)((SignedWord)(value<<8) + (c2 & (SignedWord)0xff));
return value;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedLongWord
MidiParse::read32bit()
{
Check(this);
SignedWord c1, c2, c3, c4;
c1 = egetc();
c2 = egetc();
c3 = egetc();
c4 = egetc();
return to32bit(c1,c2,c3,c4);
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::read16bit()
{
Check(this);
SignedWord c1, c2;
c1 = egetc();
c2 = egetc();
return to16bit(c1,c2);
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::mferror(char *s)
{
Check(this);
Mf_error(s);
}
// The code below allows collection of a system exclusive message of
// arbitrary length. The Msgbuff is expanded as necessary. The only
// visible data/routines are msginit(), msgadd(), msg(), msgleng().
#define MSGINCREMENT ((SignedWord)128)
//
//#############################################################################
//#############################################################################
//
void
MidiParse::msginit()
{
Check(this);
Msgindex = 0;
}
//
//#############################################################################
//#############################################################################
//
char*
MidiParse::msg()
{
Check(this);
return Msgbuff;
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::msgleng()
{
Check(this);
return Msgindex;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::msgadd(SignedWord c)
{
Check(this);
// If necessary, allocate larger message buffer.
if ( Msgindex >= Msgsize )
msgenlarge();
Msgbuff[Msgindex++] = (char)c;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::msgenlarge()
{
Check(this);
char *newmess;
char *oldmess = Msgbuff;
SignedWord oldleng = Msgsize;
Msgsize += MSGINCREMENT;
#if 0
newmess = (char*)malloc( sizeof(char)*Msgsize );
#else
newmess = new char[Msgsize];
#endif
Register_Pointer(newmess);
// copy old message into larger new one
if ( oldmess != 0 )
{
char *p = newmess;
char *q = oldmess;
char *endq = &oldmess[oldleng];
for ( ; q!=endq ; p++,q++ )
*p = *q;
Unregister_Pointer(oldmess);
#if 0
free(oldmess);
#else
delete[] oldmess;
#endif
}
Msgbuff = newmess;
}
// METHODS TO OVERRIDE
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
MidiParse::Mf_getc()
{
Fail("MidiParse::Mf_getc - Should never reach here");
return 0;
}
//
//#############################################################################
//#############################################################################
//
void
MidiParse::Mf_error(char*)
{
Fail("MidiParse::Mf_error - Should never reach here");
}
+147
View File
@@ -0,0 +1,147 @@
#pragma once
#include "node.h"
//##########################################################################
//########################## MidiParse ###############################
//##########################################################################
class MidiParse:
public Node
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
typedef long SignedLongWord; // 4 bytes
typedef short int SignedWord; // 2 bytes
typedef char SignedByte; // 1 bytes
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
MidiParse();
~MidiParse();
Logical
TestInstance() const;
void
Parse();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Accessors
//
protected:
SignedLongWord
CurTime();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Sub-class callbacks
//
private:
virtual SignedWord
Mf_getc();
virtual void
Mf_error(char *);
virtual void
Mf_starttrack() {}
virtual void
Mf_endtrack() {}
virtual void
Mf_eot() {}
virtual void
Mf_header(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_on(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_off(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_pressure(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_controller(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_pitchbend(SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_program(SignedWord,SignedWord) {}
virtual void
Mf_chanpressure(SignedWord,SignedWord) {}
virtual void
Mf_sysex(SignedWord,char*) {}
virtual void
Mf_arbitrary(SignedWord,char*) {}
virtual void
Mf_metamisc(SignedWord,SignedWord,char*) {}
virtual void
Mf_seqnum(SignedWord) {}
virtual void
Mf_smpte(SignedWord,SignedWord,SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_timesig(SignedWord,SignedWord,SignedWord,SignedWord) {}
virtual void
Mf_tempo(SignedLongWord) {}
virtual void
Mf_keysig(SignedWord,SignedWord) {}
virtual void
Mf_sqspecific(SignedWord,char*) {}
virtual void
Mf_text(SignedWord,SignedWord,char*) {}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private methods
//
private:
SignedWord
readmt(char *s,SignedWord skip);
SignedWord
egetc();
SignedWord
readheader();
void
readtrack();
void
badbyte(SignedWord c);
void
metaevent(SignedWord type);
void
sysex();
void
chanmessage(SignedWord status,SignedWord c1,SignedWord c2);
SignedLongWord
readvarinum();
SignedLongWord
to32bit(SignedWord c1, SignedWord c2,SignedWord c3, SignedWord c4);
SignedWord
to16bit(SignedWord c1,SignedWord c2);
SignedLongWord
read32bit();
SignedWord
read16bit();
void
mferror(char *s);
void
msginit();
char*
msg();
SignedWord
msgleng();
void
msgadd(SignedWord c);
void
msgenlarge();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
SignedWord Mf_nomerge;
SignedLongWord Mf_currtime;
SignedWord Mf_skipinit;
SignedLongWord Mf_toberead;
char *Msgbuff;
SignedWord Msgsize;
SignedWord Msgindex;
};
+513
View File
@@ -0,0 +1,513 @@
#include "munga.h"
#pragma hdrstop
#include "audrend.h"
#include "audent.h"
#include "jmover.h"
#include "app.h"
//#############################################################################
//########################### 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();
audio_source_volume_scale = audio_source->CalculateSourceVolumeScale();
}
//
//--------------------------------------------------------------------------
// If this a transient source and volume is lower than threshold
// Then return
//--------------------------------------------------------------------------
//
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::GetClassDerivations()));
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::GetAllocatedMemory()
{
static MemoryBlock allocatedMemory(sizeof(Event), AUDIOEVENT_MEMORYBLOCK_ALLOCATION, AUDIOEVENT_MEMORYBLOCK_ALLOCATION, "AudioEvents");
return &allocatedMemory;
}
//
//#############################################################################
//#############################################################################
//
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;
}
+250
View File
@@ -0,0 +1,250 @@
#pragma once
#include "renderer.h"
#include "audio.h"
#include "audsrc.h"
#include "audwgt.h"
#include "event.h"
#include "..\munga_l4\l4audhdw.h"
//##########################################################################
//######################## AudioRenderer #############################
//##########################################################################
class AudioEvent;
class AudioRenderer:
public Renderer
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
AudioRenderer(RendererRate render_rate);
~AudioRenderer();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Renderer Interface
//
public:
virtual void
Initialize();
void
LinkToEntity(Entity *entity);
AudioHead*
GetAudioHead();
AudioFrameCount
GetAudioFrameCount();
virtual void ReleaseSourceSet(SourceSet &sourceSet) = 0;
void
PostAudioRequestMessage(
AudioSource *audio_source,
AudioSource::RequestMessage *message
);
Logical
ProcessAudioRequestMessage();
void
FlushAudioMessages(AudioSource *audio_source);
Logical
ExecuteBackground();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Implementations
//
protected:
void
ExecuteImplementation(
RendererComplexity complexity_update,
RendererOrigin::InterestingEntityIterator *iterator
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Methods
//
private:
virtual AudioHead*
MakeAudioHead();
void
StartEntityEffectImplementation(
Entity *entity,
DamageZone *damage_zone,
ResourceDescription::ResourceID resource_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
typedef VChainOf<AudioEvent*, AudioWeighting>
AudioEventSocket;
typedef VChainIteratorOf<AudioEvent*, AudioWeighting>
AudioEventIterator;
AudioHead
*audioHead;
AudioEventSocket
audioEventSocket;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Audio Renderer Statistics
//
#ifdef LAB_ONLY
public:
int
sourceClippedCount;
int
sourceStartCount;
int
sourceSuspendCount;
int
sourceResumeCount;
int
doubleTriggerCount;
int
resourceStealCount;
int
resourceStealPriorityCount;
int
resourceStealVolumeCount;
int
stealShortDurationCount;
#endif
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer inlines ~~~~~~~~~~~~~~~~~~~~~~~~
inline AudioHead*
AudioRenderer::GetAudioHead()
{
Check(audioHead);
return audioHead;
}
inline AudioFrameCount
AudioRenderer::GetAudioFrameCount()
{
Check(audioHead);
return audioHead->GetAudioFrameCount();
}
inline Logical
AudioRenderer::ExecuteBackground()
{
Check(this);
return ProcessAudioRequestMessage();
}
//~~~~~~~~~~~~~~~~~~~~~~~~ AudioRenderer profile macros ~~~~~~~~~~~~~~~~~~~~
#if defined(TRACE_AUDIO_RENDERER)
extern BitTrace Audio_Renderer;
#define SET_AUDIO_RENDERER() Audio_Renderer.Set()
#define CLEAR_AUDIO_RENDERER() Audio_Renderer.Clear()
#else
#define SET_AUDIO_RENDERER()
#define CLEAR_AUDIO_RENDERER()
#endif
#if defined(TRACE_AUDIO_RENDERER_CREATE_OBJECTS)
extern BitTrace Audio_Renderer_Create_Objects;
#define SET_AUDIO_RENDERER_CREATE_OBJECTS() Audio_Renderer_Create_Objects.Set()
#define CLEAR_AUDIO_RENDERER_CREATE_OBJECTS() Audio_Renderer_Create_Objects.Clear()
#else
#define SET_AUDIO_RENDERER_CREATE_OBJECTS()
#define CLEAR_AUDIO_RENDERER_CREATE_OBJECTS()
#endif
#if defined(TRACE_AUDIO_RENDERER_DESTROY_OBJECTS)
extern BitTrace Audio_Renderer_Destroy_Objects;
#define SET_AUDIO_RENDERER_DESTROY_OBJECTS() Audio_Renderer_Destroy_Objects.Set()
#define CLEAR_AUDIO_RENDERER_DESTROY_OBJECTS() Audio_Renderer_Destroy_Objects.Clear()
#else
#define SET_AUDIO_RENDERER_DESTROY_OBJECTS()
#define CLEAR_AUDIO_RENDERER_DESTROY_OBJECTS()
#endif
#if defined(TRACE_AUDIO_RENDERER_START_HANDLER)
extern BitTrace Audio_Renderer_Start_Handler;
#define SET_AUDIO_RENDERER_START_HANDLER() Audio_Renderer_Start_Handler.Set()
#define CLEAR_AUDIO_RENDERER_START_HANDLER() Audio_Renderer_Start_Handler.Clear()
#else
#define SET_AUDIO_RENDERER_START_HANDLER()
#define CLEAR_AUDIO_RENDERER_START_HANDLER()
#endif
#if defined(TRACE_AUDIO_RENDERER_STOP_HANDLER)
extern BitTrace Audio_Renderer_Stop_Handler;
#define SET_AUDIO_RENDERER_STOP_HANDLER() Audio_Renderer_Stop_Handler.Set()
#define CLEAR_AUDIO_RENDERER_STOP_HANDLER() Audio_Renderer_Stop_Handler.Clear()
#else
#define SET_AUDIO_RENDERER_STOP_HANDLER()
#define CLEAR_AUDIO_RENDERER_STOP_HANDLER()
#endif
#if defined(TRACE_AUDIO_RENDERER_EXECUTE)
extern BitTrace Audio_Renderer_Execute;
#define SET_AUDIO_RENDERER_EXECUTE() Audio_Renderer_Execute.Set()
#define CLEAR_AUDIO_RENDERER_EXECUTE() Audio_Renderer_Execute.Clear()
#else
#define SET_AUDIO_RENDERER_EXECUTE()
#define CLEAR_AUDIO_RENDERER_EXECUTE()
#endif
//##########################################################################
//######################### AudioEvent ###############################
//##########################################################################
#define AUDIOEVENT_MEMORYBLOCK_ALLOCATION (20)
class AudioEvent:
public Node
{
friend class AudioRenderer;
private:
AudioEvent(
AudioSource *target,
AudioSource::RequestMessage *message
);
~AudioEvent();
static MemoryBlock* GetAllocatedMemory();
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
void
Process();
void
ReleaseLinkHandler(
Socket *socket,
Plug *plug
);
AudioSource::RequestMessage
*messageToSend;
SlotOf<AudioSource*>
targetReceiver;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioEvent inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
inline void
AudioEvent::Process()
{
Check(targetReceiver.GetCurrent());
targetReceiver.GetCurrent()->Receive(messageToSend);
Unregister_Object(this);
delete this;
}
+868
View File
@@ -0,0 +1,868 @@
#include "munga.h"
#pragma hdrstop
#include "audseq.h"
#include "objstrm.h"
#include "namelist.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlEvent ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlEvent::AudioControlEvent(
AudioTick start_tick,
AudioControlID audio_control_ID,
AudioControlValue audio_control_value
):
Plug(AudioControlEventClassID)
{
startTick = start_tick;
audioControlID = audio_control_ID;
audioControlValue = audio_control_value;
}
//
//#############################################################################
//#############################################################################
//
AudioControlEvent::AudioControlEvent():
Plug(AudioControlEventClassID)
{
startTick = 0;
audioControlID = NullAudioControlID;
audioControlValue = 0.0f;
}
//
//#############################################################################
//#############################################################################
//
AudioControlEvent::~AudioControlEvent()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlEvent::TestInstance() const
{
Plug::TestInstance();
Verify(
(Enumeration)audioControlID >= (Enumeration)0 &&
(Enumeration)audioControlID < (Enumeration)AudioControlIDCount
);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlEvent::Send(AudioComponent *audio_component)
{
Check(this);
Check(audio_component);
audio_component->ReceiveControl(audioControlID, audioControlValue);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlEvent::Chase(AudioComponent *audio_component)
{
Check(this);
Check(audio_component);
switch (audioControlID)
{
case StartAudioControlID:
return False;
case StopAudioControlID:
Send(audio_component);
return False;
default:
break;
}
return True;
}
//
//#############################################################################
//#############################################################################
//
MemoryStream&
MemoryStream_Read(
MemoryStream *stream,
AudioControlEvent *control_event
)
{
Check(stream);
Check_Signature(control_event);
MemoryStream_Read(stream, &control_event->startTick);
MemoryStream_Read(stream, &control_event->audioControlID);
MemoryStream_Read(stream, &control_event->audioControlValue);
Check(control_event);
return *stream;
}
//
//#############################################################################
//#############################################################################
//
MemoryStream&
MemoryStream_Write(
MemoryStream *stream,
const AudioControlEvent *control_event
)
{
Check(stream);
Check(control_event);
MemoryStream_Write(stream, &control_event->startTick);
MemoryStream_Write(stream, &control_event->audioControlID);
MemoryStream_Write(stream, &control_event->audioControlValue);
return *stream;
}
//
//#############################################################################
//#############################################################################
//
std::ostream& operator << (std::ostream &strm, const AudioControlEvent &control_event)
{
Check(&control_event);
strm << "[" ;
strm << control_event.startTick << ",";
strm << control_event.audioControlID << ",";
strm << control_event.audioControlValue;
strm << "]";
return strm;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioControlSequence ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
AudioControlSequence::AudioControlSequence(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream),
audioComponentSocket(NULL),
audioControlEventSocket(NULL)
{
Logical dump_value;
Logical is_looped;
AudioComponent *audio_component;
AudioControlEvent *audio_control_event;
CollectionSize i, number_of_control_events;
AudioDivisionsPerBeat divisions_per_beat;
AudioTempo tempo;
MemoryStream_Read(stream, &dump_value);
MemoryStream_Read(stream, &is_looped);
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_component);
MemoryStream_Read(stream, &divisions_per_beat);
MemoryStream_Read(stream, &tempo);
MemoryStream_Read(stream, &number_of_control_events);
for (i = 0; i < number_of_control_events; i++)
{
audio_control_event = new AudioControlEvent;
Register_Object(audio_control_event);
MemoryStream_Read(stream, audio_control_event);
audioControlEventSocket.Add(audio_control_event);
}
AudioControlSequenceX(
audio_component,
entity,
is_looped,
divisions_per_beat,
tempo,
dump_value
);
}
//
//#############################################################################
//#############################################################################
//
#if DEBUG_LEVEL>0
void
AudioControlSequence::AudioControlSequenceX(
AudioComponent *audio_component,
Entity *entity,
Logical is_looped,
AudioDivisionsPerBeat divisions_per_beat,
AudioTempo the_tempo,
Logical dump_value
)
#else
void
AudioControlSequence::AudioControlSequenceX(
AudioComponent *audio_component,
Entity *entity,
Logical is_looped,
AudioDivisionsPerBeat divisions_per_beat,
AudioTempo the_tempo,
Logical
)
#endif
{
Check(audio_component);
audioComponentSocket.Add(audio_component);
isLooped = is_looped;
isRunning = False;
startTime = AudioTime::Null;
audioControlEventIterator = NULL;
divisionsPerBeat = divisions_per_beat;
tempo = the_tempo;
#if DEBUG_LEVEL>0
dumpValue = dump_value;
#endif
audio_component->AddWatcher(this);
Check(entity);
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
AudioControlSequence::~AudioControlSequence()
{
StopSequence();
Verify(!isRunning);
Verify(audioControlEventIterator == NULL);
AudioControlEventIterator iterator(&audioControlEventSocket);
Check(&iterator);
iterator.DeletePlugs();
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSequence::BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
)
{
AudioComponent::BuildFromPage(stream, name_list, class_ID, object_ID);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, dump_value);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, is_looped);
//
// Write audio component
//
CString audio_component_name("audio_component");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_component_name);
//
// Read tempo
//
AudioTempo tempo = 100;
if (name_list->FindData("tempo") != NULL)
{
Check_Pointer(name_list->FindData("tempo"));
Convert_From_Ascii((const char *)name_list->FindData("tempo"), &tempo);
}
//
// Read midi file
//
DynamicMemoryStream midi_file_stream;
{
CString midi_file_name;
Check_Pointer(name_list->FindData("midi_file"));
midi_file_name = (const char*)name_list->FindData("midi_file");
std::ifstream input_midi_file(midi_file_name, std::ios::in | std::ios::binary);
#if DEBUG_LEVEL>0
if (!input_midi_file)
{
Dump(midi_file_name);
}
#endif
MemoryStream_Write(&midi_file_stream, &input_midi_file);
midi_file_stream.Rewind();
}
//
// Parse midi stream
//
DynamicMemoryStream control_event_stream;
CreateAudioControlEventStream midi_parser;
Check(&midi_file_stream);
Check(&control_event_stream);
Check(&midi_parser);
midi_parser.Parse(&midi_file_stream, &control_event_stream, tempo);
control_event_stream.Rewind();
//
// Write the divisions per beat and tempo
//
AudioDivisionsPerBeat divisions_per_beat;
divisions_per_beat = midi_parser.GetDivisionsPerBeat();
tempo = midi_parser.GetTempo();
MemoryStream_Write(stream, &divisions_per_beat);
MemoryStream_Write(stream, &tempo);
//
// Write control event stream
//
CollectionSize number_of_control_events;
number_of_control_events = midi_parser.GetNumberOfEvents();
MemoryStream_Write(stream, &number_of_control_events);
MemoryStream_Write(stream, &control_event_stream);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlSequence::TestInstance() const
{
AudioComponent::TestInstance();
Check(&audioComponentSocket);
Check(&audioControlEventSocket);
if (isRunning)
{
Check(audioControlEventIterator);
}
else
{
Verify(audioControlEventIterator == NULL);
}
Verify(tempo >= 1 && tempo <= 600);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSequence::StartSequence()
{
Check(this);
//
// If already running, stop sequence
//
if (isRunning)
{
StopSequence();
}
//
// Make an iterator for the control sequence
//
Verify(audioControlEventIterator == NULL);
audioControlEventIterator =
new AudioControlEventIterator(&audioControlEventSocket);
Register_Object(audioControlEventIterator);
startTime = AudioTime::Now();
isRunning = True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSequence::StopSequence()
{
Check(this);
//
// If not running, return
//
if (!isRunning)
return;
//
// Find next on or off event
//
AudioControlEvent *control_event;
Check(audioControlEventIterator);
while ((control_event = audioControlEventIterator->ReadAndNext()) != NULL)
{
Check(control_event);
if (!control_event->Chase(audioComponentSocket.GetCurrent()))
break;
}
//
// Destroy the iterator for the control sequence
//
Unregister_Object(audioControlEventIterator);
delete audioControlEventIterator;
audioControlEventIterator = NULL;
isRunning = False;
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSequence::RunSequence()
{
Check(this);
//
// If the sequence is not running, then return
//
if (!isRunning)
return;
//
// Play events which have a start time less then the
// current time
//
AudioControlEvent *control_event;
Check(audioControlEventIterator);
control_event = audioControlEventIterator->GetCurrent();
while (
control_event != NULL &&
IsEventReady(control_event)
)
{
#if DEBUG_LEVEL>0
if (dumpValue)
{
Dump(*control_event);
}
#endif
#if 0
//
// HACK - convert start control to use duration
//
Verify(control_event->audioControlID != StopAudioControlID);
if (control_event->audioControlID == StartAudioControlID)
{
//
// Convert ticks to seconds
// seconds = ticks / (divisionsPerBeat (t/b) * tempo (b/60s))
//
Scalar denominator =
(Scalar)divisionsPerBeat * (Scalar)tempo / 60.0f;
Verify(!Small_Enough(denominator));
control_event->audioControlValue =
control_event->audioControlValue / denominator;
}
#endif
//
// Send the controller to the connected audio component
//
Check(control_event);
control_event->Send(audioComponentSocket.GetCurrent());
//
// Step to next event
//
audioControlEventIterator->Next();
control_event = audioControlEventIterator->GetCurrent();
}
//
// If there are no more events to be played then stop running
//
if (control_event == NULL)
{
StopSequence();
if (isLooped)
{
StartSequence();
}
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioControlSequence::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
switch(control_ID)
{
case StartAudioControlID:
StartSequence();
break;
case StopAudioControlID:
StopSequence();
break;
case IdleAudioControlID:
RunSequence();
break;
case TempoAudioControlID:
tempo = control_value;
Verify(tempo >= 1 && tempo <= 600);
break;
default:
break;
}
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioControlSequence::IsEventReady(AudioControlEvent *audio_control_event)
{
Check(this);
AudioTime offset_time(startTime);
offset_time += CalculateEventSeconds(audio_control_event);
return (offset_time <= AudioTime::Now());
}
//
//#############################################################################
//#############################################################################
//
Scalar
AudioControlSequence::CalculateEventSeconds(
AudioControlEvent *audio_control_event
)
{
Check(this);
Check(audio_control_event);
//
// Convert ticks to seconds
// seconds = ticks / (divisionsPerBeat (t/b) * tempo (b/60s))
//
Scalar denominator = (Scalar)divisionsPerBeat * (Scalar)tempo / 60.0f;
Verify(!Small_Enough(denominator));
return (Scalar)audio_control_event->GetStartTick() / denominator;
}
//#############################################################################
//#################### CreateAudioControlEventStream ####################
//#############################################################################
CreateAudioControlEventStream::CreateAudioControlEventStream():
audioControlEventSocket(NULL, False)
{
inputStream = NULL;
outputStream = NULL;
divisionsPerBeat = 120;
tempo = 100;
}
//
//#############################################################################
//#############################################################################
//
CreateAudioControlEventStream::~CreateAudioControlEventStream(void)
{
AudioControlEventIterator iterator(&audioControlEventSocket);
Check(&iterator);
iterator.DeletePlugs();
}
//
//#############################################################################
//#############################################################################
//
Logical
CreateAudioControlEventStream::TestInstance() const
{
MidiParse::TestInstance();
Check(&audioControlEventSocket);
return True;
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Parse(
MemoryStream *input_stream,
MemoryStream *output_stream,
SignedLongWord tempo_argument
)
{
Check(this);
Check(input_stream);
Check(output_stream);
inputStream = input_stream;
outputStream = output_stream;
//
// Parse the stream
//
tempo = tempo_argument;
Verify(GetNumberOfEvents() == 0);
MidiParse::Parse();
//
// Write the events
//
AudioControlEventIterator iterator(&audioControlEventSocket);
AudioControlEvent *control_event;
Check(&iterator);
while ((control_event = iterator.ReadAndNext()) != NULL)
{
Check(control_event);
MemoryStream_Write(outputStream, control_event);
}
}
//
//#############################################################################
//#############################################################################
//
CollectionSize
CreateAudioControlEventStream::GetNumberOfEvents()
{
Check(this);
AudioControlEventIterator iterator(&audioControlEventSocket);
Check(&iterator);
return iterator.GetSize();
}
//
//#############################################################################
//#############################################################################
//
MidiParse::SignedWord
CreateAudioControlEventStream::Mf_getc()
{
Check(this);
unsigned char c;
MemoryStream_Read(inputStream, &c);
return c;
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Mf_error(char *str)
{
Check(this);
Check_Pointer(str);
Fail(str);
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Mf_header(
SignedWord,
SignedWord,
SignedWord division
)
{
Check(this);
divisionsPerBeat = division;
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Mf_on(
SignedWord channel,
SignedWord pitch,
SignedWord vol
)
{
Check(this);
//
// Interpret vol 0 as note off
//
if (vol == 0)
{
Mf_off(channel, pitch, vol);
return;
}
//
// Verify that last event was a stop
//
#if DEBUG_LEVEL>0
{
AudioControlEventIterator iterator(&audioControlEventSocket);
AudioControlEvent *last_control_event;
iterator.Last();
if ((last_control_event = iterator.GetCurrent()) != NULL)
{
Check(last_control_event);
Verify(last_control_event->audioControlID == StopAudioControlID);
}
}
#endif
AudioTick current_ticks = CurTime();
AudioControlEvent *audio_control_event;
//
// Add note value event
//
audio_control_event
= new AudioControlEvent(
current_ticks,
NoteAudioControlID,
(Scalar)pitch
);
Register_Object(audio_control_event);
audioControlEventSocket.AddValue(audio_control_event, current_ticks);
//
// Add velocity event
//
audio_control_event
= new AudioControlEvent(
current_ticks,
AttackVolumeAudioControlID,
(Scalar)vol / (Scalar)127
);
Register_Object(audio_control_event);
audioControlEventSocket.AddValue(audio_control_event, current_ticks);
//
// Add start event
//
audio_control_event
= new AudioControlEvent(
current_ticks,
StartAudioControlID,
0.0f
);
Register_Object(audio_control_event);
audioControlEventSocket.AddValue(audio_control_event, current_ticks);
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Mf_off(
SignedWord,
SignedWord pitch,
SignedWord
)
{
Check(this);
AudioTick current_ticks = CurTime();
AudioControlEvent *audio_control_event;
#if 0
//
// HACK - convert start control to use duration
//
AudioControlEventIterator
iterator(&audioControlEventSocket);
iterator.Last();
audio_control_event = iterator.GetCurrent();
Check(audio_control_event);
Verify(audio_control_event->audioControlID == StartAudioControlID);
audio_control_event->audioControlValue =
current_ticks - audio_control_event->startTick;
#else
//
// Add note value event
//
audio_control_event
= new AudioControlEvent(
current_ticks,
NoteAudioControlID,
(Scalar)pitch
);
Register_Object(audio_control_event);
audioControlEventSocket.AddValue(audio_control_event, current_ticks);
//
// Add stop event
//
audio_control_event
= new AudioControlEvent(
current_ticks,
StopAudioControlID,
0.0f
);
Register_Object(audio_control_event);
audioControlEventSocket.AddValue(audio_control_event, current_ticks);
#endif
}
//
//#############################################################################
//#############################################################################
//
void
CreateAudioControlEventStream::Mf_tempo(SignedLongWord)
{
Check(this);
// tempo = i1; // HACK - Cakewalk appears to produce bogus tempo
}
+244
View File
@@ -0,0 +1,244 @@
#pragma once
#include "style.h"
#include "audio.h"
#include "audmidi.h"
#include "vchain.h"
#include "audtime.h"
//##########################################################################
//####################### AudioControlEvent ##########################
//##########################################################################
class AudioControlEvent:
public Plug
{
friend MemoryStream&
MemoryStream_Read(
MemoryStream *stream,
AudioControlEvent *control_event
);
friend MemoryStream&
MemoryStream_Write(
MemoryStream *stream,
const AudioControlEvent *control_event
);
public:
AudioControlEvent(
AudioTick start_tick,
AudioControlID audio_control_ID,
AudioControlValue audio_control_value
);
AudioControlEvent();
~AudioControlEvent();
Logical
AudioControlEvent::TestInstance() const;
AudioTick
GetStartTick()
{return startTick;}
void
Send(AudioComponent *audio_component);
Logical
Chase(AudioComponent *audio_component);
public:
friend std::ostream& operator << (std::ostream &strm, const AudioControlEvent &control_event);
// private: // HACK
AudioTick
startTick;
AudioControlID
audioControlID;
AudioControlValue
audioControlValue;
};
//##########################################################################
//####################### AudioControlSequence #######################
//##########################################################################
class AudioControlSequence:
public AudioComponent
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
AudioControlSequence(
PlugStream *stream,
Entity *entity
);
void
AudioControlSequenceX(
AudioComponent *audio_component,
Entity *entity,
Logical is_looped,
AudioDivisionsPerBeat divisions_per_beat,
AudioTempo tempo,
Logical dump_value
);
~AudioControlSequence();
Logical
TestInstance() const;
//
//--------------------------------------------------------------------
// BuildFromPage
//--------------------------------------------------------------------
//
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Sequence methods
//
public:
//
//--------------------------------------------------------------------
// Controller methods
//--------------------------------------------------------------------
//
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
//
//--------------------------------------------------------------------
// Sequence control
//--------------------------------------------------------------------
//
void
StartSequence();
void
RunSequence();
void
StopSequence();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private methods
//
private:
Logical
IsEventReady(AudioControlEvent *audio_control_event);
Scalar
CalculateEventSeconds(AudioControlEvent *audio_control_event);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
typedef SChainOf<AudioControlEvent*>
AudioControlEventSocket;
typedef SChainIteratorOf<AudioControlEvent*>
AudioControlEventIterator;
Logical isLooped;
Logical isRunning;
AudioTime startTime;
AudioDivisionsPerBeat divisionsPerBeat;
AudioTempo tempo;
SlotOf<AudioComponent*>
audioComponentSocket;
AudioControlEventSocket
audioControlEventSocket;
AudioControlEventIterator
*audioControlEventIterator;
#if DEBUG_LEVEL>0
Logical
dumpValue;
#endif
};
//##########################################################################
//################### CreateAudioControlEventStream ##################
//##########################################################################
class CreateAudioControlEventStream:
public MidiParse
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
CreateAudioControlEventStream();
~CreateAudioControlEventStream();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Parsing
//
public:
void
Parse(
MemoryStream *input_stream,
MemoryStream *output_stream,
SignedLongWord tempo=100
);
AudioDivisionsPerBeat
GetDivisionsPerBeat()
{return divisionsPerBeat;}
AudioTempo
GetTempo()
{return tempo;}
CollectionSize
GetNumberOfEvents();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Implementations
//
private:
SignedWord
Mf_getc();
void
Mf_error(char *);
void
Mf_header(SignedWord,SignedWord,SignedWord);
void
Mf_on(SignedWord,SignedWord,SignedWord);
void
Mf_off(SignedWord,SignedWord,SignedWord);
void
Mf_tempo(SignedLongWord);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
typedef VChainOf<AudioControlEvent*, AudioTick>
AudioControlEventSocket;
typedef VChainIteratorOf<AudioControlEvent*, AudioTick>
AudioControlEventIterator;
MemoryStream
*inputStream;
MemoryStream
*outputStream;
AudioDivisionsPerBeat
divisionsPerBeat;
AudioTempo
tempo;
AudioControlEventSocket
audioControlEventSocket;
};
+817
View File
@@ -0,0 +1,817 @@
#include "munga.h"
#pragma hdrstop
#include "audsrc.h"
#include "audrend.h"
#include "objstrm.h"
#include "app.h"
#include "namelist.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSourceStartState ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
#define DEFAULT_NOTE (60)
AudioSourceStartState::AudioSourceStartState()
{
noteValue = DEFAULT_NOTE;
isDurationSet = False;
hasDuration = False;
duration = 0.0f;
startTime = 0.0f;
endTime = 0.0f;
}
//
//#############################################################################
//#############################################################################
//
AudioSourceStartState::~AudioSourceStartState()
{
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioSourceStartState::TestInstance() const
{
if (isDurationSet || hasDuration)
{
Verify(duration >= 0.0f);
}
if (hasDuration)
{
Verify(endTime >= startTime);
}
return True;
}
//
//#############################################################################
//#############################################################################
//
void
AudioSourceStartState::CalculateDuration(AudioControlValue control_value)
{
//
// Calculate duration
//
if (control_value > 0.0f)
{
hasDuration = True;
endTime = AudioTime::Now();
endTime += control_value;
}
else if (isDurationSet)
{
hasDuration = True;
endTime = AudioTime::Now();
endTime += duration;
isDurationSet = False;
}
else
{
hasDuration = False;
endTime = 0.0f;
}
}
#if 0
//
//#############################################################################
//#############################################################################
//
AudioTime
AudioSourceStartState::GetCurrentRunningTime()
{
Check(this);
AudioTime current_duration = AudioTime::Now();
return (current_duration -= startTime);
}
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSource ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
//#############################################################################
//
const Receiver::HandlerEntry
AudioSource::MessageHandlerEntries[]=
{
{
AudioSource::StartMessageID,
"Start",
(AudioSource::Handler)&AudioSource::StartMessageHandler
},
{
AudioSource::StopMessageID,
"Stop",
(AudioSource::Handler)&AudioSource::StopMessageHandler
}
};
AudioSource::MessageHandlerSet& AudioSource::GetMessageHandlers()
{
static AudioSource::MessageHandlerSet messageHandlers(ELEMENTS(AudioSource::MessageHandlerEntries), AudioSource::MessageHandlerEntries, AudioComponent::GetMessageHandlers());
return messageHandlers;
}
//
//#############################################################################
//#############################################################################
//
Derivation* AudioSource::GetClassDerivations()
{
static Derivation classDerivations(AudioComponent::GetClassDerivations(), "AudioSource");
return &classDerivations;
}
AudioSource::SharedData
AudioSource::DefaultData(
AudioSource::GetClassDerivations(),
AudioSource::GetMessageHandlers()
);
//
//#############################################################################
//#############################################################################
//
AudioSource::AudioSource(
PlugStream *stream,
Entity *entity
):
AudioComponent(stream, DefaultData)
{
AudioResource *audio_resource;
AudioLocation *audio_location;
AudioSourcePriority priority;
AudioSourceMixPresence mix_presence;
AudioControlValue volume_mix_level;
AudioPitchCents pitch_mix_offset;
AudioControlValue brightness_mix_level;
Logical has_compression_curve;
Scalar seconds;
AudioTime compression_duration;
Logical use_brightness_scale;
Logical use_attack_time_scale;
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_resource);
PlugStream_ReadObjectIDAndFindPlug(stream, &audio_location);
MemoryStream_Read(stream, &priority);
MemoryStream_Read(stream, &mix_presence);
MemoryStream_Read(stream, &volume_mix_level);
MemoryStream_Read(stream, &pitch_mix_offset);
MemoryStream_Read(stream, &brightness_mix_level);
MemoryStream_Read(stream, &has_compression_curve);
MemoryStream_Read(stream, &seconds);
compression_duration = seconds;
MemoryStream_Read(stream, &use_brightness_scale);
MemoryStream_Read(stream, &use_attack_time_scale);
AudioSourceX(
audio_resource,
audio_location,
entity,
priority,
mix_presence,
volume_mix_level,
pitch_mix_offset,
brightness_mix_level,
has_compression_curve,
compression_duration,
use_brightness_scale,
use_attack_time_scale
);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::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_resource_name("resource");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_resource_name);
CString audio_location_name("location");
PlugStream_FindEntryAndWriteObjectID(stream, name_list, audio_location_name);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, priority);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Enumeration, mix_presence);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, volume_mix_level);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioPitchCents, pitch_mix_offset);
MEM_STRM_WRITE_ENTRY(*stream, name_list, AudioControlValue, brightness_mix_level);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, has_compression_curve);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Scalar, compression_duration);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, use_brightness_scale);
MEM_STRM_WRITE_ENTRY(*stream, name_list, Logical, use_attack_time_scale);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::AudioSourceX(
AudioResource *audio_resource,
AudioLocation *audio_location,
Entity *entity,
AudioSourcePriority priority,
AudioSourceMixPresence mix_presence,
AudioControlValue volume_mix_level,
AudioPitchCents pitch_mix_offset,
AudioControlValue brightness_mix_level,
Logical has_compression_curve,
const AudioTime &compression_duration,
Logical use_brightness_scale,
Logical use_attack_time_scale
)
{
Check(audio_resource);
Check(audio_location);
Check(entity);
audioLocation = audio_location;
audioResource = audio_resource;
audioSourceState = StoppedAudioSourceState;
attackVolumeScale = 1.0f;
useAttackTimeScale = use_attack_time_scale;
attackTimeScale = 0.0f;
audioSourcePriority = priority;
audioSourceMixPresence = mix_presence;
volumeCompressionScale = 1.0f;
hasCompressionCurve = has_compression_curve;
compressionDuration = compression_duration;
volumeMixScale = volume_mix_level;
pitchMixOffset = pitch_mix_offset;
useBrightnessScale = use_brightness_scale;
brightnessMixScale = brightness_mix_level;
volumeScale = 1.0f;
pitchOffset = 0.0f;
brightnessScale = 1.0f;
nextExecuteFrame = NullAudioFrameCount;
suspendFinishedFrame = NullAudioFrameCount;
entity->AddAudioComponent(this);
}
//
//#############################################################################
//#############################################################################
//
AudioSource::~AudioSource()
{
Verify(audioSourceState == StoppedAudioSourceState);
}
//
//#############################################################################
//#############################################################################
//
Logical
AudioSource::TestInstance() const
{
AudioComponent::TestInstance();
return True;
}
//
// Resource methods
//
//
//#############################################################################
//#############################################################################
//
void
AudioSource::SetAudioResource(AudioResource *audio_resource)
{
Check(this);
Check(audio_resource);
Verify(audioSourceState == StoppedAudioSourceState);
Check(audioResource);
audioResource = audio_resource;
}
//
// Current State/Status Accessors
//
//
//#############################################################################
//#############################################################################
//
void
AudioSource::AssignAudioSourceState(AudioSourceState audio_source_state)
{
Check(this);
//
// Initialize the next start state if the source is now running
//
if (audio_source_state == RunningAudioSourceState)
{
AudioSourceStartState null_state;
nextStartState = null_state;
}
audioSourceState = audio_source_state;
}
//
// Mixing & Logical compression methods
//
//
//#############################################################################
//#############################################################################
//
AudioControlValue
AudioSource::CalculateSourceCompressionEffect()
{
Check(this);
//
// Get current volume level
//
AudioControlValue current_volume_level;
current_volume_level = CalculateSourceVolumeScale();
Verify(current_volume_level >= 0.0f && current_volume_level <= 1.0f);
//
// Calculate the amount of this to apply to compression
//
if (hasCompressionCurve)
{
//
// scale = 1 / (1 + ((1/comp_dur) * duration)^2)
//
Scalar current_running_time = GetCurrentRunningTime();
Scalar compression_duration = compressionDuration;
Scalar duration_factor;
Scalar denominator;
AudioControlValue compression_effect;
Verify(!Small_Enough(compression_duration));
duration_factor = pow((1.0f/compression_duration) * current_running_time, 2.0f);
// Warn(!(duration_factor > 0.0f));
denominator = 1.0f + duration_factor;
Verify(!Small_Enough(denominator));
compression_effect = 1.0f / denominator;
Verify(compression_effect >= 0.0f && compression_effect <=1.0f);
return compression_effect * current_volume_level;
}
return current_volume_level;
}
//
//#############################################################################
//#############################################################################
//
AudioControlValue
AudioSource::CalculateSourceVolumeScale()
{
Check(this);
//
// Execute the watchers that will update the volume related
// member parameters
//
ExecuteWatchers();
//
// Calculate the resulting volume scale
//
AudioControlValue
volume_scale;
volume_scale = volumeScale * volumeMixScale * volumeCompressionScale;
Clamp(volume_scale, MinAudioVolume, MaxAudioVolume);
return volume_scale;
}
//
//#############################################################################
//#############################################################################
//
AudioControlValue
AudioSource::CalculateSourceBrightnessScale()
{
Check(this);
AudioControlValue brightness_mix_scale;
brightness_mix_scale = brightnessScale * brightnessMixScale;
Clamp(brightness_mix_scale, MinAudioBrightness, MaxAudioBrightness);
return brightness_mix_scale;
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
)
{
Check(this);
switch (control_ID)
{
//
//----------------------------------------------------------------------
// StartAudioControlID
//----------------------------------------------------------------------
//
case StartAudioControlID:
{
StartMessage message(control_value);
Check(application);
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->PostAudioRequestMessage(
this,
&message
);
}
break;
//
//----------------------------------------------------------------------
// StopAudioControlID
//----------------------------------------------------------------------
//
case StopAudioControlID:
{
StopMessage message;
Check(application);
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->PostAudioRequestMessage(
this,
&message
);
}
break;
//
//----------------------------------------------------------------------
// Misc...
//----------------------------------------------------------------------
//
case VolumeAudioControlID:
VolumeAudioHandler(control_value);
break;
case PitchAudioControlID:
PitchAudioHandler(control_value);
break;
case BrightnessAudioControlID:
BrightnessAudioHandler(control_value);
break;
case AttackVolumeAudioControlID:
AttackVolumeAudioHandler(control_value);
break;
case AttackTimeAudioControlID:
AttackTimeAudioHandler(control_value);
break;
case NoteAudioControlID:
NoteAudioHandler(control_value);
break;
case DurationAudioControlID:
DurationAudioHandler(control_value);
break;
case FlushMessagesAudioControlID:
Check(application);
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->FlushAudioMessages(this);
break;
case NullAudioControlID:
case IdleAudioControlID:
break;
default:
Fail("AudioSource::ReceiveControl - Should never reach here");
break;
}
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::StartMessageHandler(StartMessage *message)
{
SET_AUDIO_RENDERER();
SET_AUDIO_RENDERER_START_HANDLER();
Check(this);
Check(message);
Verify(message->messageID == StartMessageID);
//
//--------------------------------------------------------------------------
// if double trigger condition exists
// then return
//--------------------------------------------------------------------------
//
AudioTime double_trigger_cutoff(AudioDoubleTriggerCutoff);
#if 0
double_trigger_cutoff = AudioDoubleTriggerCutoff;
#endif
if (
audioSourceState == RunningAudioSourceState &&
GetCurrentRunningTime() <= double_trigger_cutoff
)
{
#ifdef LAB_ONLY
Check(application);
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->doubleTriggerCount++;
#endif
CLEAR_AUDIO_RENDERER_START_HANDLER();
CLEAR_AUDIO_RENDERER();
return;
}
//
//--------------------------------------------------------------------------
// If the source is not stopped then stop it
//--------------------------------------------------------------------------
//
if (audioSourceState != StoppedAudioSourceState)
{
StopMessage stop_message;
StopMessageHandler(&stop_message);
}
//
//--------------------------------------------------------------------------
// Verify that the state is stopped
// Copy the next start state into the current start state
// Calculate duration
//--------------------------------------------------------------------------
//
Verify(audioSourceState == StoppedAudioSourceState);
currentStartState = nextStartState;
currentStartState.CalculateDuration(message->controlValue);
//
//--------------------------------------------------------------------------
// Implementation specific start request
//--------------------------------------------------------------------------
//
StartMessageImplementation();
CLEAR_AUDIO_RENDERER_START_HANDLER();
CLEAR_AUDIO_RENDERER();
}
//
//#############################################################################
//#############################################################################
//
void
#if DEBUG_LEVEL>0
AudioSource::StopMessageHandler(StopMessage *message)
#else
AudioSource::StopMessageHandler(StopMessage*)
#endif
{
SET_AUDIO_RENDERER();
SET_AUDIO_RENDERER_STOP_HANDLER();
Check(this);
Check(message);
Verify(message->messageID == StopMessageID);
//
// if the source is stopped
// then return
//
if (audioSourceState == StoppedAudioSourceState)
{
CLEAR_AUDIO_RENDERER_STOP_HANDLER();
CLEAR_AUDIO_RENDERER();
return;
}
//
// Implementation specific stop request
//
StopMessageImplementation();
CLEAR_AUDIO_RENDERER_STOP_HANDLER();
CLEAR_AUDIO_RENDERER();
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::VolumeAudioHandler(AudioControlValue control_value)
{
Check(this);
Clamp(control_value, MinAudioVolume, MaxAudioVolume);
volumeScale = control_value / (MaxAudioVolume - MinAudioVolume);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::PitchAudioHandler(AudioControlValue control_value)
{
Check(this);
pitchOffset = control_value;
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::BrightnessAudioHandler(AudioControlValue control_value)
{
Check(this);
Clamp(control_value, MinAudioBrightness, MaxAudioBrightness);
brightnessScale = control_value / (MaxAudioBrightness - MinAudioBrightness);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::AttackVolumeAudioHandler(AudioControlValue control_value)
{
Check(this);
Clamp(control_value, MinAudioAttack, MaxAudioAttack);
attackVolumeScale = control_value / (MaxAudioAttack - MinAudioAttack);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::AttackTimeAudioHandler(AudioControlValue control_value)
{
Check(this);
Clamp(control_value, MinAudioAttack, MaxAudioAttack);
attackTimeScale = control_value / (MaxAudioAttack - MinAudioAttack);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::NoteAudioHandler(AudioControlValue control_value)
{
Check(this);
nextStartState.SetNoteValue(control_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::DurationAudioHandler(AudioControlValue control_value)
{
Check(this);
nextStartState.SetDurationValue(control_value);
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::StartImplementation()
{
currentStartState.Start();
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::StopImplementation()
{
Fail("AudioSource::StopImplementation - Should never reach here");
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::SuspendImplementation()
{
StopImplementation();
Check(application);
Check(application->GetAudioRenderer());
Check(audioResource);
suspendFinishedFrame =
application->GetAudioRenderer()->GetAudioFrameCount() +
audioResource->GetSuspendDelay();
#ifdef LAB_ONLY
application->GetAudioRenderer()->sourceSuspendCount++;
#endif
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::ResumeImplementation()
{
StartImplementation();
suspendFinishedFrame = NullAudioFrameCount;
#ifdef LAB_ONLY
Check(application);
Check(application->GetAudioRenderer());
application->GetAudioRenderer()->sourceResumeCount++;
#endif
}
//
//#############################################################################
//#############################################################################
//
void
AudioSource::Execute()
{
Check(this);
//
// Execute source if this is the next execution frame
//
AudioRenderer
*audio_renderer;
Check(application);
audio_renderer = application->GetAudioRenderer();
Check(audio_renderer);
if (nextExecuteFrame <= audio_renderer->GetAudioFrameCount())
{
nextExecuteFrame =
audio_renderer->GetAudioFrameCount() + DefaultAudioFrameDelay;
//
// Update the sources spatial model
// Execute inherited method
// Execute this sources sound model
//
UpdateSpatialModel(audio_renderer->GetAudioHead());
AudioComponent::Execute();
ExecuteModel(False);
}
}
+664
View File
@@ -0,0 +1,664 @@
#pragma once
#include "style.h"
#include "audio.h"
#include "audloc.h"
#include "audlvl.h"
#include "audwgt.h"
#include "audtime.h"
//##########################################################################
//##################### AudioSourceStartState ########################
//##########################################################################
class AudioSourceStartState SIGNATURED
{
public:
AudioSourceStartState();
~AudioSourceStartState();
Logical
TestInstance() const;
void
CalculateDuration(AudioControlValue control_value);
Logical
IsFinishedPlaying();
AudioTime
GetCurrentRunningTime();
void
SetNoteValue(AudioControlValue note_value)
{noteValue = note_value;}
AudioControlValue
GetNoteValue()
{return noteValue;}
void
SetDurationValue(AudioControlValue duration_value);
void
Start()
{startTime = AudioTime::Now();}
private:
AudioControlValue
noteValue;
Logical
isDurationSet;
Logical
hasDuration;
Scalar
duration;
AudioTime
startTime;
AudioTime
endTime;
};
//~~~~~~~~~~~~~~~~~~~~~ AudioSourceStartState inlines ~~~~~~~~~~~~~~~~~~~~~~
inline Logical
AudioSourceStartState::IsFinishedPlaying()
{
Check(this);
if (hasDuration)
{
return (AudioTime::Now() > endTime);
}
return False;
}
inline void
AudioSourceStartState::SetDurationValue(AudioControlValue duration_value)
{
Check(this);
isDurationSet = True;
duration = duration_value;
}
inline AudioTime
AudioSourceStartState::GetCurrentRunningTime()
{
Check(this);
return (AudioTime::Now() - startTime);
}
//##########################################################################
//######################### AudioSource ##############################
//##########################################################################
class AudioSource__RequestMessage;
class AudioSource__StartMessage;
class AudioSource__StopMessage;
class AudioSource:
public AudioComponent
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
AudioSource(
PlugStream *stream,
Entity *entity
);
void
AudioSource::AudioSourceX(
AudioResource *audio_resource,
AudioLocation *audio_location,
Entity *entity,
AudioSourcePriority priority,
AudioSourceMixPresence mix_presence,
AudioControlValue volume_mix_level,
AudioPitchCents pitch_mix_offset,
AudioControlValue brightness_mix_level,
Logical has_compression_curve,
const AudioTime &compression_duration,
Logical use_brightness_scale,
Logical use_attack_time_scale
);
~AudioSource();
Logical
TestInstance() const;
static void
BuildFromPage(
PlugStream *stream,
NameList *name_list,
ClassID class_ID,
ObjectID object_ID
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Location methods
//
public:
AudioLocation*
GetAudioLocation();
void
UpdateSpatialModel(AudioHead *audio_head);
Scalar
GetDistanceToSource();
virtual Logical
IsAudioSourceClipped(AudioHead *audio_head);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resource methods
//
public:
void
SetAudioResource(AudioResource *audio_resource);
AudioResource*
GetAudioResource();
AudioVoiceCount
GetAudioVoiceCount();
AudioRenderType
GetAudioRenderType();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Current State/Status Accessors
//
public:
void
AssignAudioSourceState(AudioSourceState audio_source_state);
AudioSourceState
GetAudioSourceState();
Logical
IsFinishedPlaying();
AudioTime
GetCurrentRunningTime();
AudioControlValue
GetCurrentNoteValue();
AudioControlValue
CalculateSourceAttackVolumeScale();
Logical
UseSourceAttackTime();
AudioControlValue
CalculateSourceAttackTime();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Priority Accessors
//
public:
void
SetAudioSourcePriority(AudioSourcePriority audio_source_priority);
AudioSourcePriority
GetAudioSourcePriority();
AudioWeighting
CalculateAudioWeighting();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mixing & Logical compression methods
//
public:
AudioSourceMixPresence
GetAudioSourceMixPresence();
void
SetVolumeCompressionScale(AudioControlValue compression_scale);
AudioControlValue
CalculateSourceCompressionEffect();
virtual AudioControlValue
CalculateSourceVolumeScale();
virtual AudioPitchCents
CalculateSourcePitchOffset();
Logical
UseSourceBrightnessScale();
virtual AudioControlValue
CalculateSourceBrightnessScale();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Controller methods
//
public:
void
ReceiveControl(
AudioControlID control_ID,
AudioControlValue control_value
);
virtual void
VolumeAudioHandler(AudioControlValue);
virtual void
PitchAudioHandler(AudioControlValue);
virtual void
BrightnessAudioHandler(AudioControlValue);
virtual void
AttackVolumeAudioHandler(AudioControlValue);
virtual void
AttackTimeAudioHandler(AudioControlValue);
virtual void
NoteAudioHandler(AudioControlValue);
virtual void
DurationAudioHandler(AudioControlValue);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State implementations
//
public:
virtual void
StartImplementation();
virtual void
StopImplementation();
virtual void
SuspendImplementation();
virtual void
ResumeImplementation();
protected:
virtual void
StartMessageImplementation() {}
virtual void
StopMessageImplementation() {}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Execution
//
public:
Logical
RequiresMaintenance(AudioHead *audio_head);
Logical
CanResume(AudioHead *audio_head);
void
Execute();
protected:
virtual void
ExecuteModel(Logical force_update) {}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
enum {
StartMessageID = AudioComponent::NextMessageID,
StopMessageID,
NextMessageID
};
typedef AudioSource__RequestMessage
RequestMessage;
typedef AudioSource__StartMessage
StartMessage;
typedef AudioSource__StopMessage
StopMessage;
static const HandlerEntry
MessageHandlerEntries[];
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
void
StartMessageHandler(StartMessage *message);
void
StopMessageHandler(StopMessage *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation *GetClassDerivations();
static SharedData
DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
//
// Location data
//
AudioLocation
*audioLocation;
//
// Resource data
//
AudioResource
*audioResource;
//
// State/Status data
//
AudioSourceState
audioSourceState;
AudioSourceStartState
nextStartState,
currentStartState;
AudioControlValue
attackVolumeScale;
Logical
useAttackTimeScale;
AudioControlValue
attackTimeScale;
//
// Priority data
//
AudioSourcePriority
audioSourcePriority;
//
// Mixing and compression
//
AudioSourceMixPresence
audioSourceMixPresence;
AudioControlValue
volumeCompressionScale;
Logical
hasCompressionCurve;
AudioTime
compressionDuration;
AudioControlValue
volumeMixScale;
AudioPitchCents
pitchMixOffset;
Logical
useBrightnessScale;
AudioControlValue
brightnessMixScale;
AudioControlValue
volumeScale;
AudioPitchCents
pitchOffset;
AudioControlValue
brightnessScale;
//
// Execution
//
AudioFrameCount
nextExecuteFrame;
AudioFrameCount
suspendFinishedFrame;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioSource inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Location methods
//
inline AudioLocation*
AudioSource::GetAudioLocation()
{
Check(this);
return audioLocation;
}
inline void
AudioSource::UpdateSpatialModel(AudioHead *audio_head)
{
Check(this);
Check(audioLocation);
audioLocation->UpdateSpatialModel(audio_head);
}
inline Scalar
AudioSource::GetDistanceToSource()
{
Check(this);
Check(audioLocation);
return audioLocation->GetDistanceToSource();
}
inline Logical
AudioSource::IsAudioSourceClipped(AudioHead *audio_head)
{
Check(this);
Check(audioLocation);
return audioLocation->IsAudioLocationClipped(audio_head);
}
//
// Resource methods
//
inline AudioResource*
AudioSource::GetAudioResource()
{
Check(this);
return audioResource;
}
inline AudioVoiceCount
AudioSource::GetAudioVoiceCount()
{
Check(this);
Check(audioResource);
return audioResource->GetVoiceCount();
}
inline AudioRenderType
AudioSource::GetAudioRenderType()
{
Check(this);
Check(audioResource);
return audioResource->GetAudioRenderType();
}
//
// Current State/Status Accessors
//
inline AudioSourceState
AudioSource::GetAudioSourceState()
{
Check(this);
return audioSourceState;
}
inline Logical
AudioSource::IsFinishedPlaying()
{
Check(this);
return currentStartState.IsFinishedPlaying();
}
inline AudioTime
AudioSource::GetCurrentRunningTime()
{
Check(this);
Verify(audioSourceState == RunningAudioSourceState);
return currentStartState.GetCurrentRunningTime();
}
inline AudioControlValue
AudioSource::GetCurrentNoteValue()
{
Check(this);
return currentStartState.GetNoteValue();
}
inline AudioControlValue
AudioSource::CalculateSourceAttackVolumeScale()
{
Check(this);
return attackVolumeScale;
}
inline Logical
AudioSource::UseSourceAttackTime()
{
Check(this);
return useAttackTimeScale;
}
inline AudioControlValue
AudioSource::CalculateSourceAttackTime()
{
Check(this);
return attackTimeScale;
}
//
// Priority Accessors
//
inline void
AudioSource::SetAudioSourcePriority(
AudioSourcePriority audio_source_priority
)
{
Check(this);
audioSourcePriority = audio_source_priority;
}
inline AudioSourcePriority
AudioSource::GetAudioSourcePriority()
{
Check(this);
return audioSourcePriority;
}
inline AudioWeighting
AudioSource::CalculateAudioWeighting()
{
Check(this);
AudioWeighting
audio_weight(
GetAudioSourcePriority(),
CalculateSourceVolumeScale()
);
return audio_weight;
}
//
// Mixing & Logical compression methods
//
inline AudioSourceMixPresence
AudioSource::GetAudioSourceMixPresence()
{
Check(this);
return audioSourceMixPresence;
}
inline void
AudioSource::SetVolumeCompressionScale(
AudioControlValue compression_level
)
{
Check(this);
volumeCompressionScale = compression_level;
}
inline AudioPitchCents
AudioSource::CalculateSourcePitchOffset()
{
Check(this);
return pitchMixOffset + pitchOffset;
}
inline Logical
AudioSource::UseSourceBrightnessScale()
{
Check(this);
return useBrightnessScale;
}
//
// Execute
//
inline Logical
AudioSource::RequiresMaintenance(AudioHead *audio_head)
{
Check(this);
Check(audio_head);
return (nextExecuteFrame <= audio_head->GetAudioFrameCount());
}
inline Logical
AudioSource::CanResume(AudioHead *audio_head)
{
Check(this);
Check(audio_head);
return (suspendFinishedFrame <= audio_head->GetAudioFrameCount());
}
//~~~~~~~~~~~~~~~~~~~~~~ AudioSource__RequestMessage ~~~~~~~~~~~~~~~~~~~~~~~
class AudioSource__RequestMessage:
public Receiver::Message
{
public:
AudioSource__RequestMessage(
Receiver::MessageID id,
size_t message_length,
AudioControlID control_ID,
AudioControlValue control_value
);
AudioControlID
controlID;
AudioControlValue
controlValue;
};
inline AudioSource__RequestMessage::AudioSource__RequestMessage(
Receiver::MessageID message_ID,
size_t message_length,
AudioControlID control_ID,
AudioControlValue control_value
):
Receiver::Message(
message_ID,
message_length
)
{
controlID = control_ID;
controlValue = control_value;
}
//~~~~~~~~~~~~~~~~~~~~~~ AudioSource__StartMessage ~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioSource__StartMessage:
public AudioSource::RequestMessage
{
public:
AudioSource__StartMessage(AudioControlValue control_value);
};
inline AudioSource__StartMessage::AudioSource__StartMessage(
AudioControlValue control_value
):
AudioSource::RequestMessage(
AudioSource::StartMessageID,
sizeof(AudioSource__StartMessage),
StartAudioControlID,
control_value
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~ AudioSource__StopMessage ~~~~~~~~~~~~~~~~~~~~~~~~~~
class AudioSource__StopMessage:
public AudioSource::RequestMessage
{
public:
AudioSource__StopMessage();
};
inline AudioSource__StopMessage::AudioSource__StopMessage():
AudioSource::RequestMessage(
AudioSource::StopMessageID,
sizeof(AudioSource__StopMessage),
StopAudioControlID,
0.0f
)
{
}
+54
View File
@@ -0,0 +1,54 @@
#include "munga.h"
#pragma hdrstop
#include "audtime.h"
#include "app.h"
#include "audrend.h"
//#############################################################################
//############################# AudioTime ###############################
//#############################################################################
const AudioTime AudioTime::Null;
//
//#############################################################################
//#############################################################################
//
Logical AudioTime::TestInstance() const
{
return True;
}
//
//#############################################################################
//#############################################################################
//
AudioTime AudioTime::Now()
{
Check(application);
Check(application->GetAudioRenderer());
return AudioTime(application->GetAudioRenderer()->GetAudioFrameCount());
}
//
//#############################################################################
//#############################################################################
//
AudioFrameCount AudioTime::Seconds_To_Frames(Scalar seconds) const
{
Check(application);
Check(application->GetAudioRenderer());
return (seconds * application->GetAudioRenderer()->GetCalibrationRate() + 0.5f);
}
//
//#############################################################################
//#############################################################################
//
Scalar AudioTime::Frames_To_Seconds(AudioFrameCount frames) const
{
Check(application);
Check(application->GetAudioRenderer());
return ((Scalar)frames / application->GetAudioRenderer()->GetCalibrationRate());
}
+258
View File
@@ -0,0 +1,258 @@
#pragma once
#include "scalar.h"
#include "audio.h"
//##########################################################################
//########################## AudioTime ###############################
//##########################################################################
class AudioTime SIGNATURED
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
AudioTime();
AudioTime(const AudioTime&);
AudioTime(Scalar seconds);
AudioTime(AudioFrameCount frame_count);
~AudioTime();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Assignment
//
public:
AudioTime&
operator=(const AudioTime&);
AudioTime&
operator=(Scalar seconds);
AudioTime&
operator=(AudioFrameCount frame_count);
operator Scalar() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Logical Operators
//
public:
Logical
operator<(const AudioTime&) const;
Logical
operator<=(const AudioTime&) const;
Logical
operator>(const AudioTime&) const;
Logical
operator>=(const AudioTime&) const;
Logical
operator==(const AudioTime&) const;
Logical
operator!=(const AudioTime&) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Addition Operators
//
public:
operator AudioFrameCount() const;
AudioTime
operator+(const AudioTime&) const;
AudioTime
operator-(const AudioTime&) const;
AudioTime&
operator+=(const AudioTime &t);
AudioTime&
operator-=(const AudioTime &t);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public Constants
//
public:
static const AudioTime
Null;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Current Time
//
public:
static AudioTime
Now();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Methods
//
private:
AudioFrameCount
Seconds_To_Frames(Scalar seconds) const;
Scalar
Frames_To_Seconds(AudioFrameCount frames) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Data
//
private:
AudioFrameCount
frameCount;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioTime inlines ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Construction, Destruction, and Testing
//
inline AudioTime::AudioTime():
frameCount(NullAudioFrameCount)
{
}
inline AudioTime::AudioTime(const AudioTime &audio_time):
frameCount(audio_time.frameCount)
{
}
inline AudioTime::AudioTime(Scalar seconds)
{
frameCount = Seconds_To_Frames(seconds);
}
inline AudioTime::AudioTime(AudioFrameCount frame_count):
frameCount(frame_count)
{
}
inline AudioTime::~AudioTime()
{
}
//
// Assignment
//
inline AudioTime&
AudioTime::operator=(const AudioTime &audio_time)
{
Check(this);
Check(&audio_time);
frameCount = audio_time.frameCount;
return *this;
}
inline AudioTime&
AudioTime::operator=(Scalar seconds)
{
Check(this);
frameCount = Seconds_To_Frames(seconds);
return *this;
}
inline AudioTime&
AudioTime::operator=(AudioFrameCount frame_count)
{
Check(this);
frameCount = frame_count;
return *this;
}
inline
AudioTime::operator Scalar() const
{
Check(this);
return Frames_To_Seconds(frameCount);
}
//
// Logical Operators
//
inline Logical
AudioTime::operator<(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount < audio_time.frameCount;
}
inline Logical
AudioTime::operator<=(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount <= audio_time.frameCount;
}
inline Logical
AudioTime::operator>(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount > audio_time.frameCount;
}
inline Logical
AudioTime::operator>=(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount >= audio_time.frameCount;
}
inline Logical
AudioTime::operator==(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount == audio_time.frameCount;
}
inline Logical
AudioTime::operator!=(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return frameCount != audio_time.frameCount;
}
//
// Addition Operators
//
inline AudioTime::operator AudioFrameCount() const
{
Check(this);
return frameCount;
}
inline AudioTime
AudioTime::operator+(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return AudioTime(frameCount + audio_time.frameCount);
}
inline AudioTime
AudioTime::operator-(const AudioTime &audio_time) const
{
Check(this);
Check(&audio_time);
return AudioTime(frameCount - audio_time.frameCount);
}
inline AudioTime&
AudioTime::operator+=(const AudioTime &audio_time)
{
Check(this);
Check(&audio_time);
frameCount += audio_time.frameCount;
return *this;
}
inline AudioTime&
AudioTime::operator-=(const AudioTime &audio_time)
{
Check(this);
Check(&audio_time);
frameCount -= audio_time.frameCount;
return *this;
}
+102
View File
@@ -0,0 +1,102 @@
#include "munga.h"
#pragma hdrstop
#include "audtools.h"
#include <fstream>
#include <io.h>
#include <sys\stat.h>
#include "audio.h"
#include "boxsolid.h"
AudioCreateSymbols::AudioCreateSymbols()
{
}
AudioCreateSymbols::~AudioCreateSymbols()
{
}
void AudioCreateSymbols::MakeFileReadWrite(const CString &file_name)
{
if (access(file_name, 0) == 0)
{
int amode = S_IREAD|S_IWRITE;
#if DEBUG_LEVEL>0
int ret =
#endif
chmod(file_name, amode);
Verify(ret == 0);
}
}
void AudioCreateSymbols::Execute()
{
CString file_name("audio\\symbols.scp");
MakeFileReadWrite(file_name);
std::ofstream symbol_file(file_name, std::ios::out);
Verify(symbol_file);
symbol_file << "[macro]\n";
WriteEntryStream(symbol_file);
}
void AudioCreateSymbols::WriteEntryStream(std::ofstream &symbol_file)
{
#define WRITE_ENTRY(name)\
{\
Verify(symbol_file);\
symbol_file << #name;\
symbol_file << "=";\
symbol_file << name;\
symbol_file << "\n";\
}
//
// Solids
//
WRITE_ENTRY(BoxedSolid::StoneMaterial);
WRITE_ENTRY(BoxedSolid::GravelMaterial);
WRITE_ENTRY(BoxedSolid::ConcreteMaterial);
WRITE_ENTRY(BoxedSolid::WoodMaterial);
WRITE_ENTRY(BoxedSolid::RockMaterial);
WRITE_ENTRY(BoxedSolid::OurCraftMaterial);
WRITE_ENTRY(BoxedSolid::OtherCraftMaterial);
//
// Audio
//
WRITE_ENTRY(TransientAudioRenderType);
WRITE_ENTRY(SustainedAudioRenderType);
WRITE_ENTRY(MinAudioSourcePriority);
WRITE_ENTRY(LowAudioSourcePriority);
WRITE_ENTRY(MedAudioSourcePriority);
WRITE_ENTRY(HighAudioSourcePriority);
WRITE_ENTRY(MaxAudioSourcePriority);
WRITE_ENTRY(MinAudioSourceMixPresence);
WRITE_ENTRY(LowAudioSourceMixPresence);
WRITE_ENTRY(MedAudioSourceMixPresence);
WRITE_ENTRY(HighAudioSourceMixPresence);
WRITE_ENTRY(MaxAudioSourceMixPresence);
WRITE_ENTRY(ManualAudioSourceMixPresence);
WRITE_ENTRY(NullAudioControlID);
WRITE_ENTRY(NoteAudioControlID);
WRITE_ENTRY(AttackVolumeAudioControlID);
WRITE_ENTRY(AttackTimeAudioControlID);
WRITE_ENTRY(DurationAudioControlID);
WRITE_ENTRY(VolumeAudioControlID);
WRITE_ENTRY(PitchAudioControlID);
WRITE_ENTRY(BrightnessAudioControlID);
WRITE_ENTRY(StartAudioControlID);
WRITE_ENTRY(StopAudioControlID);
WRITE_ENTRY(IdleAudioControlID);
WRITE_ENTRY(FlushMessagesAudioControlID);
WRITE_ENTRY(TempoAudioControlID);
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "style.h"
#include "cstr.h"
class AudioCreateSymbols
{
public:
AudioCreateSymbols();
~AudioCreateSymbols();
void Execute();
private:
static void MakeFileReadWrite(const CString &file_name);
protected:
virtual void WriteEntryStream(std::ofstream &symbol_file);
};
+12
View File
@@ -0,0 +1,12 @@
#include "munga.h"
#pragma hdrstop
#include "audwgt.h"
const AudioWeighting AudioWeighting::Null;
Logical AudioWeighting::TestInstance() const
{
return True;
}
+128
View File
@@ -0,0 +1,128 @@
#pragma once
#include "style.h"
#include "audio.h"
//##########################################################################
//######################## AudioWeighting ############################
//##########################################################################
class AudioWeighting SIGNATURED
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, and Testing
//
public:
AudioWeighting();
AudioWeighting(const AudioWeighting&);
AudioWeighting(AudioSourcePriority audio_priority, AudioControlValue audio_volume);
AudioWeighting& operator=(const AudioWeighting&);
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Logical Operators
//
public:
Logical operator<(const AudioWeighting&) const;
Logical operator<=(const AudioWeighting&) const;
Logical operator>(const AudioWeighting&) const;
Logical operator>=(const AudioWeighting&) const;
Logical operator==(const AudioWeighting&) const;
Logical operator!=(const AudioWeighting&) const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public Constants
//
public:
static const AudioWeighting Null;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private Data
//
private:
Scalar weight;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ AudioWeighting inlines ~~~~~~~~~~~~~~~~~~~~~~~
inline AudioWeighting::AudioWeighting():
weight(0.0f)
{
}
inline AudioWeighting::AudioWeighting(const AudioWeighting &audio_weighting):
weight(audio_weighting.weight)
{
}
inline AudioWeighting::AudioWeighting(
AudioSourcePriority audio_priority,
AudioControlValue audio_volume
)
{
Verify(
(Enumeration)audio_priority >= 0 &&
(Enumeration)audio_priority < AUDIO_SOURCE_PRIORITY_COUNT
);
Verify(
(Enumeration)audio_priority >= (Enumeration)MinAudioSourcePriority &&
(Enumeration)audio_priority <= (Enumeration)MaxAudioSourcePriority
);
Verify(
audio_volume >= 0.0f &&
audio_volume <= 1.0f
);
weight = 0.0f -(Scalar)audio_priority - audio_volume;
}
inline AudioWeighting&
AudioWeighting::operator=(const AudioWeighting &audio_weighting)
{
Check(this);
weight = audio_weighting.weight;
return *this;
}
inline Logical
AudioWeighting::operator<(const AudioWeighting &audio_weighting) const
{
Check(this);
return weight < audio_weighting.weight;
}
inline Logical
AudioWeighting::operator<=(const AudioWeighting &audio_weighting) const
{
Check(this);
return weight <= audio_weighting.weight;
}
inline Logical
AudioWeighting::operator>(const AudioWeighting &audio_weighting) const
{
Check(this);
return weight > audio_weighting.weight;
}
inline Logical
AudioWeighting::operator>=(const AudioWeighting &audio_weighting) const
{
Check(this);
return weight >= audio_weighting.weight;
}
inline Logical
AudioWeighting::operator==(const AudioWeighting &audio_weighting) const
{
Check(this);
return Close_Enough(weight, audio_weighting.weight, 0.01f);
}
inline Logical
AudioWeighting::operator!=(const AudioWeighting &audio_weighting) const
{
Check(this);
return !Close_Enough(weight, audio_weighting.weight, 0.01f);
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+4
View File
@@ -0,0 +1,4 @@
#include "munga.h"
#pragma hdrstop
#include "average.h"
+298
View File
@@ -0,0 +1,298 @@
#pragma once
#include "style.h"
//##########################################################################
//########################### AverageOf ##############################
//##########################################################################
template <class T> class AverageOf SIGNATURED
{
public:
//
//-----------------------------------------------------------------------
// Constructor, Destructor, Testing
//-----------------------------------------------------------------------
//
AverageOf();
AverageOf(
size_t size,
T initial=(T)0
);
~AverageOf();
Logical
TestInstance() const;
//
//-----------------------------------------------------------------------
// SetSize
//-----------------------------------------------------------------------
//
void
SetSize(
size_t size,
T initial=(T)0
);
//
//-----------------------------------------------------------------------
// Add
//-----------------------------------------------------------------------
//
void
Add(T value);
//
//-----------------------------------------------------------------------
// CalculateAverage
//-----------------------------------------------------------------------
//
T
CalculateAverage();
//
//-----------------------------------------------------------------------
// CalculateOlympicAverage
//-----------------------------------------------------------------------
//
T
CalculateOlympicAverage();
//
//-----------------------------------------------------------------------
// Calculate Trend of Average
//-----------------------------------------------------------------------
//
Scalar
CalculateTrend();
private:
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
size_t size;
size_t next;
T *array;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~ AverageOf templates ~~~~~~~~~~~~~~~~~~~~~~~~~
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T>
AverageOf<T>::AverageOf()
{
array = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T>
AverageOf<T>::AverageOf(
size_t the_size,
T initial
)
{
array = NULL;
SetSize(the_size, initial);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> void
AverageOf<T>::SetSize(
size_t the_size,
T initial
)
{
if (array != NULL)
{
Unregister_Pointer(array);
delete[] array;
}
size = the_size;
array = new T[size];
Register_Pointer(array);
next = 0;
for (size_t i = 0; i < size; i++)
{
Check_Pointer(array);
Verify(i < size);
array[i] = initial;
Check_Fpu();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T>
AverageOf<T>::~AverageOf()
{
Unregister_Pointer(array);
delete[] array;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> Logical
AverageOf<T>::TestInstance() const
{
Check_Pointer(array);
Verify(next < size);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> void
AverageOf<T>::Add(T value)
{
Check(this);
Check_Pointer(array);
Verify(next < size);
array[next] = value;
++next;
if (next >= size)
{
Verify(next == size);
next = 0;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> T
AverageOf<T>::CalculateAverage()
{
Check(this);
size_t i;
T accumulate;
for (i = 0, accumulate = (T)0; i < size; i++)
{
Check_Pointer(array);
Verify(i < size);
accumulate += array[i];
Check_Fpu();
}
Verify(!Small_Enough((T)size));
return (accumulate / (T)size);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> T
AverageOf<T>::CalculateOlympicAverage()
{
Check(this);
size_t i;
T accumulate, min_value, max_value;
Verify(0 < size);
min_value = array[0];
max_value = array[0];
Check_Fpu();
for (i = 0, accumulate = (T)0; i < size; i++)
{
Check_Pointer(array);
Verify(i < size);
accumulate += array[i];
Check_Fpu();
min_value = Min(array[i], min_value);
max_value = Max(array[i], max_value);
Check_Fpu();
}
accumulate -= min_value;
accumulate -= max_value;
Check_Fpu();
Verify(!Small_Enough((T)(size - 2)));
return (accumulate / (T)(size - 2));
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template <class T> Scalar
AverageOf<T>::CalculateTrend()
{
Check(this);
size_t i;
Scalar f = 0.0f;
Scalar fx = 0.0f;
Scalar x1 = size;
Scalar x2 = x1*x1/2.0f;
Scalar x3 = x2 + x1*x1*x1/3.0f + x1/6.0f;
x2 += x1/2.0f;
i = next;
Scalar t = 1.0f;
do
{
f += array[i];
fx += t*array[i];
t += 1.0f;
if (++i == size)
{
i = 0;
}
} while (i != next);
return (x1*fx - x2*f) / (x1*x3 - x2*x2);
}
//##########################################################################
//######################## StaticAverageOf ###########################
//##########################################################################
template <class T> class StaticAverageOf SIGNATURED
{
public:
//
//-----------------------------------------------------------------------
// Constructor, Destructor, Testing
//-----------------------------------------------------------------------
//
StaticAverageOf()
{size = (T)0; total = (T)0;}
~StaticAverageOf()
{}
Logical
TestInstance() const
{return True;}
//
//-----------------------------------------------------------------------
// Add
//-----------------------------------------------------------------------
//
void
Add(T value)
{Check(this); size++; total += value;}
//
//-----------------------------------------------------------------------
// CalculateAverage
//-----------------------------------------------------------------------
//
T
CalculateAverage()
{Check(this); return (size == 0) ? ((T)0) : (total / (T)size);}
//
//-----------------------------------------------------------------------
// GetSize
//-----------------------------------------------------------------------
//
size_t
GetSize()
{Check(this); return size;}
private:
//
//-----------------------------------------------------------------------
// Private data
//-----------------------------------------------------------------------
//
size_t size;
T total;
};
+451
View File
@@ -0,0 +1,451 @@
#include "munga.h"
#pragma hdrstop
#include "bndgbox.h"
#include "origin.h"
#include "line.h"
//#############################################################################
//############################## BoundingBox ############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox::BoundingBox(const ExtentBox &extents):
ExtentBox(extents)
{
Check_Pointer(this);
Check(&extents);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox::BoundingBox()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void
BoundingBox::PlaceBoundingBox(const Origin& origin)
{
Check(this);
Check(&origin);
Dump(origin);
minX += origin.linearPosition.x;
maxX += origin.linearPosition.x;
minY += origin.linearPosition.y;
maxY += origin.linearPosition.y;
minZ += origin.linearPosition.z;
maxZ += origin.linearPosition.z;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox::~BoundingBox()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::Intersects(const ExtentBox &extents)
{
Check(this);
Check(&extents);
if (ExtentBox::Intersects(extents))
{
ExtentBox slice;
slice.Intersect(*this, extents);
return IntersectsBounded(slice);
}
else
{
return False;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::Intersects(
const ExtentBox &extents,
ExtentBox *slice
)
{
Check(this);
Check(&extents);
Check_Pointer(slice);
if (ExtentBox::Intersects(extents))
{
slice->Intersect(*this, extents);
return IntersectsBounded(*slice);
}
else
{
return False;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::Contains(const Point3D &point)
{
Check(this);
Check(&point);
if (ExtentBox::Contains(point))
{
return ContainsBounded(point);
}
else
{
return False;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoundingBox::FindDistanceBelow(const Point3D &point)
{
Check(this);
Check(&point);
if (
minX <= point.x && maxX >= point.x && minY <= point.y
&& minZ <= point.z && maxZ >= point.z
)
{
return FindDistanceBelowBounded(point);
}
else
{
return -1.0f;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::HitBy(Line *line)
{
Check(this);
Check(line);
Scalar
enter,
leave,
perpendicular,
drift,
distance;
//
//--------------------
// Set up for the test
//--------------------
//
Logical entered = False;
Logical left = False;
for (int i=0; i<6; ++i)
{
//
//--------------------------------------------------------------------
// Figure out what axis we are dealing with, then based upon the
// direction of the face, find out the distance from the origin to the
// place against the normal, and find out how fast the perpendicular
// distance changes with a unit movement along the line
//--------------------------------------------------------------------
//
int face = i;
int axis = face >> 1;
if (face&1)
{
perpendicular = line->origin[axis] - (*this)[face];
drift = line->direction[axis];
}
else
{
perpendicular = (*this)[face] - line->origin[axis];
drift = -line->direction[axis];
}
//
//-------------------------------------------------------------------
// If the line is parallel to the face, figure out whether or not the
// line origin lies within the face's half-space
//-------------------------------------------------------------------
//
if (Small_Enough(drift))
{
if (perpendicular > 0.0f)
{
return False;
}
else
{
continue;
}
}
//
//--------------------------------------------------------------------
// If the drift is towards the plane's halfspace, this plane is one of
// the one through which the line could enter the node
//--------------------------------------------------------------------
//
distance = -perpendicular / drift;
if (drift < 0.0f)
{
if (!entered)
{
entered = True;
enter = distance;
}
else if (distance > enter)
{
enter = distance;
}
if (enter > line->length)
{
return False;
}
}
//
//--------------------------------------------------------------------
// If the drift is towards the plane's halfspace, this plane is one of
// the one through which the line could enter the node
//--------------------------------------------------------------------
//
else
{
if (!left)
{
left = True;
leave = distance;
}
else if (distance < leave)
{
leave = distance;
}
if (leave < 0.0f)
{
return False;
}
}
}
//
//-----------------------------------------------------------------------
// If we exit the loop, then make sure that we actually hit the interior,
// and let the box figure out if the what happens inside it
//-----------------------------------------------------------------------
//
if (enter <= leave)
{
return HitByBounded(line, enter, leave);
}
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
#if DEBUG_LEVEL>0
BoundingBox::IntersectsBounded(const ExtentBox &extents)
#else
BoundingBox::IntersectsBounded(const ExtentBox &)
#endif
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
#if DEBUG_LEVEL>0
BoundingBox::ContainsBounded(const Point3D &point)
#else
BoundingBox::ContainsBounded(const Point3D &)
#endif
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoundingBox::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
Scalar result = point.y - maxY;
return Max(result, 0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::HitByBounded(
Line *line,
Scalar enters,
#if DEBUG_LEVEL>0
Scalar leaves
#else
Scalar
#endif
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
line->length = Max(enters, 0.0f);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBox::TestInstance() const
{
return True;
}
//#############################################################################
//######################### BoundingBoxCollision ########################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBoxCollision::TestInstance() const
{
return True;
}
//#############################################################################
//####################### BoundingBoxCollisionList ######################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBoxCollisionList::BoundingBoxCollisionList(int max_length)
{
listStart = new BoundingBoxCollision[max_length];
Register_Pointer(listStart);
maxCollisions = max_length;
Reset();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxCollisionList::AddCollisionToList(
BoundingBox *tree_volume,
const ExtentBox &slice
)
{
Check(tree_volume);
Check(&slice);
Check(this);
Check_Pointer(nextCollision);
Verify(collisionsLeft);
//
// BT port fix: Verify() compiles out at DEBUG_LEVEL=0, leaving NO live bounds
// check -- and several callers are add-then-check (MOVER.cpp:1589,
// BOXLIST.cpp:230), so a list entered with exactly 0 slots free went NEGATIVE,
// every later "!collisionsLeft" full-test read nonzero-negative as "room
// left", and the static-tree pass then appended EVERY overlapping terrain/
// building box past the 10-slot heap block (0x1C bytes per entry). Trigger:
// >10 simultaneous contacts from >1 source -- e.g. a mech standing INSIDE a
// building solid while gravity presses it into terrain boxes. Clamp at
// capacity: overflow contacts are dropped, never written.
//
if (collisionsLeft <= 0)
{
return;
}
nextCollision->treeVolume = tree_volume;
nextCollision->collisionSlice = slice;
++nextCollision;
--collisionsLeft;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBoxCollisionList::TestInstance() const
{
return True;
}
//#############################################################################
//########################### TaggedBoundingBox #########################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TaggedBoundingBox::TaggedBoundingBox(void *tag)
{
tagPointer = tag;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TaggedBoundingBox::TaggedBoundingBox(
const ExtentBox &extents,
void *tag
):
BoundingBox(extents)
{
tagPointer = tag;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
TaggedBoundingBox::~TaggedBoundingBox()
{
}
#if defined(TEST_CLASS)
#include "bndgbox.tcp"
#endif
+195
View File
@@ -0,0 +1,195 @@
#pragma once
#include "extntbox.h"
class Line;
class Point3D;
class Origin;
class BoundingBoxTreeNode;
class BoundingBoxList;
class BoundingBoxCollision;
//##########################################################################
//########################### BoundingBox ############################
//##########################################################################
class BoundingBox:
public ExtentBox
{
friend class BoundingBoxTreeNode;
friend class BoundingBoxList;
public:
BoundingBox();
BoundingBox(const ExtentBox &extents);
virtual ~BoundingBox();
Logical
Intersects(const ExtentBox &extents);
Logical
Intersects(
const ExtentBox &extents,
ExtentBox *slice
);
Logical
Contains(const Point3D &point);
Scalar
FindDistanceBelow(const Point3D &point);
Logical
HitBy(Line *line);
void
PlaceBoundingBox(const Origin& origin);
protected:
virtual Logical
IntersectsBounded(const ExtentBox &extents);
virtual Logical
ContainsBounded(const Point3D &point);
virtual Scalar
FindDistanceBelowBounded(const Point3D &point);
virtual Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
public:
static Logical
TestClass();
virtual Logical
TestInstance() const;
};
//##########################################################################
//###################### BoundingBoxCollision ########################
//##########################################################################
class BoundingBoxCollision SIGNATURED
{
public:
BoundingBox
*treeVolume;
ExtentBox
collisionSlice;
BoundingBox*
GetTreeVolume()
{Check(this); return treeVolume;}
Logical
TestInstance() const;
};
//##########################################################################
//#################### BoundingBoxCollisionList ######################
//##########################################################################
class BoundingBoxCollisionList SIGNATURED
{
friend class BoundingBoxTreeNode;
friend class BoundingBoxList;
protected:
BoundingBoxCollision
*listStart,
*nextCollision;
int
maxCollisions,
collisionsLeft;
public:
BoundingBoxCollisionList(int max_length);
~BoundingBoxCollisionList()
{Check(this); Unregister_Pointer(listStart); delete[] listStart;}
void
Reset()
{nextCollision = listStart; collisionsLeft = maxCollisions;}
void
AddCollisionToList(
BoundingBox *tree_volume,
const ExtentBox &slice
);
BoundingBoxCollision&
operator[](int index)
{
Check(this); Verify((unsigned)index < maxCollisions);
return listStart[index];
}
int
GetCollisionCount()
{Check(this); return maxCollisions - collisionsLeft;}
int
GetCollisionsLeft()
{Check(this); return collisionsLeft;}
Logical
TestInstance() const;
};
//##########################################################################
//######################## TaggedBoundingBox #########################
//##########################################################################
class TaggedBoundingBox:
public BoundingBox
{
public:
void*
GetTagPointer()
{Check(this); return tagPointer;}
protected:
TaggedBoundingBox(void *tag = NULL);
TaggedBoundingBox(
const ExtentBox &extents,
void *tag = NULL
);
~TaggedBoundingBox();
void *tagPointer;
};
//##########################################################################
//####################### TaggedBoundingBoxOf ########################
//##########################################################################
template <class T> class TaggedBoundingBoxOf:
public TaggedBoundingBox
{
public:
TaggedBoundingBoxOf(T *tag);
TaggedBoundingBoxOf(
const ExtentBox &extents,
T *tag = NULL
);
~TaggedBoundingBoxOf();
T*
GetTagPointer()
{return (T*)tagPointer;}
};
//~~~~~~~~~~~~~~~~~~~~~~~~ TaggedBoundingBoxOf templates ~~~~~~~~~~~~~~~~~~~
template <class T>
TaggedBoundingBoxOf<T>::TaggedBoundingBoxOf(T *tag):
TaggedBoundingBox(tag)
{
}
template <class T>
TaggedBoundingBoxOf<T>::TaggedBoundingBoxOf(
const ExtentBox &extents,
T *tag
):
TaggedBoundingBox(extents, tag)
{
}
template <class T>
TaggedBoundingBoxOf<T>::~TaggedBoundingBoxOf()
{
}
+464
View File
@@ -0,0 +1,464 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "line.h"
//#############################################################################
//############################### BoxedCone #############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedCone::BoxedCone(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, ConeType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedCone::~BoxedCone()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedCone::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//------------------------------------------------------------------------
// Find the center point in the XZ plane of the cone, and find the biggest
// radius of the cone by measuring in the X axis, along with its height
//------------------------------------------------------------------------
//
Vector3D center;
center.x = (minX + maxX) * 0.5f;
center.y = minY;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
Verify(!Small_Enough(radius));
//
//--------------------------------------------------------------------------
// Convert the closest point in the slice to the coordinates of the cone,
// putting the apex of the cone at the origin, then make sure that the point
// isn't in one of the corners of the box
//--------------------------------------------------------------------------
//
Vector3D nearest(center);
extents.Constrain(&nearest);
center.y = maxY;
nearest.Subtract(center,nearest);
Scalar r = nearest.x*nearest.x + nearest.z*nearest.z;
if (r > radius*radius)
{
return False;
}
//
//--------------------------------------------------------------------------
// Compute the distance from the axis, and then see if the slope of the line
// from the cone apex to the test point is less than the slope of the cone
//--------------------------------------------------------------------------
//
r = Sqrt(r);
Scalar height = maxY - minY;
return r*height <= nearest.y*radius;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedCone::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Find the center point in the XZ plane of the cone, and find the biggest
// radius of the cone by measuring in the X axis, along with its height
//------------------------------------------------------------------------
//
Vector3D center;
center.x = (minX + maxX) * 0.5f;
center.y = maxY;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
Verify(!Small_Enough(radius));
//
//--------------------------------------------------------------------------
// Convert the closest point in the slice to the coordinates of the cone,
// putting the apex of the cone at the origin, then make sure that the point
// isn't in one of the corners of the box
//--------------------------------------------------------------------------
//
Vector3D nearest;
nearest.Subtract(center, point);
Scalar r = nearest.x*nearest.x + nearest.z*nearest.z;
if (r > radius*radius)
{
return False;
}
//
//--------------------------------------------------------------------------
// Compute the distance from the axis, and then see if the slope of the line
// from the cone apex to the test point is less than the slope of the cone
//--------------------------------------------------------------------------
//
r = Sqrt(r);
Scalar height = maxY - minY;
return r*height <= nearest.y*radius;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedCone::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Find the center point in the XZ plane of the cone, and find the biggest
// radius of the cone by measuring in the X axis, along with its height
//------------------------------------------------------------------------
//
Vector3D center;
center.x = (minX + maxX) * 0.5f;
center.y = maxY;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
Verify(!Small_Enough(radius));
//
//--------------------------------------------------------------------------
// Convert the closest point in the slice to the coordinates of the cone,
// putting the apex of the cone at the origin, then make sure that the point
// isn't in one of the corners of the box
//--------------------------------------------------------------------------
//
Vector3D nearest;
nearest.Subtract(point, center);
Scalar r = nearest.x*nearest.x + nearest.z*nearest.z;
if (r > radius*radius)
{
return -1.0f;
}
//
//--------------------------------------------------------------------------
// Compute the distance from the axis, and then see if the slope of the line
// from the cone apex to the test point is less than the slope of the cone
//--------------------------------------------------------------------------
//
r = Sqrt(r);
Scalar height = maxY - minY;
nearest.y += r*(height/radius);
return Max(nearest.y,0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// This function is a helper function used in the derivation for the terms of
// the quadratic equation to find t when colliding a line and a cone. I'm not
// real clear on the physical representation of this kind of dot product
//
static Scalar
Special_Cone_Dot_Product(
const Vector3D &v1,
const Vector3D &v2,
Scalar squared_tan
)
{
return v1.x*v2.x - squared_tan*v1.y*v2.y + v1.z*v2.z;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedCone::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
//
//--------------------------------------------------------------------------
// Find out the size of the box, and set up the height and maximum radius of
// the cone, along with the squared tangent of the spread angle
//--------------------------------------------------------------------------
//
Vector3D center;
center.x = (minX + maxX) * 0.5f;
center.y = maxY;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
Scalar height = maxY - minY;
Verify(!Small_Enough(height));
Scalar squared_tan = radius*radius/(height*height);
//
//-------------------------------------------------------------------------
// Find the line between the point of the cone and the origin of our line,
// then set up the conditions for the quadratic equation. The following
// equation sets up a*t^2 + b*t + c = 0. The terms a, b, and c are derived
// by solving the following equations for t:
//
// p == line->origin + line->direction * t
// r == p - cone->apex
// r.x^2 + r.z^2 == tan^2(cone_angle)*r.y^2
//
// The special cone dot product function is a handy way to reduce the
// complexity of the problem
//-------------------------------------------------------------------------
//
Vector3D v;
v.Subtract(line->origin,center);
//
//--------------------------------------------------------------------------
// If the line diverges from the axis at the same angle as the spread angle,
// we need to find the closest point on the line to the axis. We then drop
// a vertical plane containing the line through the cone at this point, thus
// generating a hyperbola. We then solve the hyperbola vs. line equation to
// get our intersection point
//--------------------------------------------------------------------------
//
Scalar a =
Special_Cone_Dot_Product(line->direction, line->direction, squared_tan);
if (Small_Enough(a))
{
}
//
//-----------------------------------------------
// Otherwise, continue solving the first equation
//-----------------------------------------------
//
else
{
Scalar b =
2.0f * Special_Cone_Dot_Product(v, line->direction, squared_tan);
Scalar c = Special_Cone_Dot_Product(v, v, squared_tan);
//
//-----------------------------------------------------------------------
// Now, use the quadratic equation to determine where the two points
// intersect the cone. If there is no solution, than the line missed the
// cone
//-----------------------------------------------------------------------
//
Verify(!Small_Enough(a));
Scalar t = -b / (2.0f * a);
Scalar i = b*b - 4.0f*a*c;
if (i < 0.0f)
{
return False;
}
//
//----------------------------------------------------------------------
// If the interval is zero, then the line hits the cone in one spot only
// (a tangential hit). Check to see if hits the lower half of the conic
// equation (our cone)
//----------------------------------------------------------------------
//
if (Small_Enough(i))
{
Scalar y = v.y + line->direction.y * t;
if (y > 0.0f)
{
return False;
}
//
//----------------------------------------------------------------
// It hit the lower cone, so see if it was entering or leaving the
// cone
//----------------------------------------------------------------
//
if (line->direction.y > 0.0f)
{
//
//-------------------------------------------------------------
// The line is leaving the cone, so see if we need to reset the
// leaving distance
//-------------------------------------------------------------
//
if (t < leaves)
{
leaves = t;
}
}
//
//------------------------------------------------------------
// The line is entering the cone, so see if we need to set the
// entering distance
//------------------------------------------------------------
//
else if (t > enters)
{
enters = t;
}
//
//-------------------------------------------------------------------
// See if we still have a collision with the cone, and if so, set the
// new line length
//-------------------------------------------------------------------
//
if (enters > leaves || enters > line->length || leaves < 0.0f)
{
return False;
}
line->length = Max(enters, 0.0f);
return True;
}
//
//----------------------------------------------------------------------
// If the interval is non-zero, then the conic section was struck in two
// places. Find out the lengths to those places and the y values for
// those points
//----------------------------------------------------------------------
//
i = Sqrt(i) / (2.0f * a);
Scalar t1,t2;
if (i > 0.0f)
{
t1 = t - i;
t2 = t + i;
}
else
{
t1 = t + i;
t2 = t - i;
}
Scalar y1 = v.y + line->direction.y * t1;
Scalar y2 = v.y + line->direction.y * t2;
//
//----------------------------------------------------------------------
// There are four combinations of the signs of the y values. Each has a
// different effect on missing/hitting, entering or leaving distances.
// First check to see if only the upper conic was hit
//----------------------------------------------------------------------
//
if (y1 > 0.0f)
{
if (y2 > 0.0f)
{
return False;
}
//
//-----------------------------------------------------------------
// The ray is entering our conic, so set the distance appropriately
//-----------------------------------------------------------------
//
if (t2 > enters)
{
enters = t2;
}
}
//
//----------------------------------------------------------------------
// See if the ray is leaving the lower conic, and if so, set the leaving
// distance accordingly
//----------------------------------------------------------------------
//
else
{
if (y2 > 0.0f)
{
if (t1 < leaves)
{
leaves = t1;
}
}
//
//--------------------------------------------------------------------
// Both spots are in the lower conic, so set both leaving and entering
// distances
//--------------------------------------------------------------------
//
else
{
if (t1 > enters)
{
enters = t1;
}
if (t2 < leaves)
{
leaves = t2;
}
}
}
//
//-----------------------------------------------------------------------
// See if we still have a collision with the cone, and if so, set the new
// line length
//-----------------------------------------------------------------------
//
if (enters > leaves || enters > line->length || leaves < 0.0f)
{
return False;
}
line->length = Max(enters, 0.0f);
}
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedCone::TestInstance() const
{
return solidType == ConeType;
}
File diff suppressed because it is too large Load Diff
+911
View File
@@ -0,0 +1,911 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "plane.h"
extern Logical
BoxedRampContainsLine(
Line *line,
const Plane& plane,
Scalar enters,
Scalar leaves
);
//#############################################################################
//##################### BoxedInvertedRampFacingNegativeZ ################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingNegativeZ::BoxedInvertedRampFacingNegativeZ(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
InvertedRampFacingNegativeZType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingNegativeZ::~BoxedInvertedRampFacingNegativeZ()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeZ::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = extents.maxY - minY;
Scalar z = extents.minZ - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/z yields
// rise*z <= y*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return z*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeZ::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/z yields
// rise*z <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedInvertedRampFacingNegativeZ::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------
// If the point is above the ramp, it will hit the top of the ramp
//----------------------------------------------------------------
//
if (point.y > maxY)
{
return point.y - maxY;
}
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - minZ;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
return (z*rise <= y*run) ? 0.0f : -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeZ::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.x = 0.0f;
ramp.normal.y = minZ - maxZ;
ramp.normal.z = maxY - minY;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.z /= temp;
ramp.offset = maxY*ramp.normal.y + maxZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeZ::TestInstance() const
{
return solidType == InvertedRampFacingNegativeZType;
}
//#############################################################################
//##################### BoxedInvertedRampFacingPositiveZ ################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingPositiveZ::BoxedInvertedRampFacingPositiveZ(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
InvertedRampFacingPositiveZType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingPositiveZ::~BoxedInvertedRampFacingPositiveZ()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveZ::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = extents.maxY - minY;
Scalar z = extents.maxZ - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/z yields
// rise*z >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveZ::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/z yields
// rise*z >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedInvertedRampFacingPositiveZ::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------
// If the point is above the ramp, it will hit the top of the ramp
//----------------------------------------------------------------
//
if (point.y > maxY)
{
return point.y - maxY;
}
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - maxZ;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
return (z*rise >= y*run) ? 0.0f : -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveZ::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.x = 0.0f;
ramp.normal.y = minZ - maxZ;
ramp.normal.z = minY - maxY;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.z /= temp;
ramp.offset = minY*ramp.normal.y + maxZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveZ::TestInstance() const
{
return solidType == InvertedRampFacingPositiveZType;
}
//#############################################################################
//##################### BoxedInvertedRampFacingNegativeX ################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingNegativeX::BoxedInvertedRampFacingNegativeX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
InvertedRampFacingNegativeXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingNegativeX::~BoxedInvertedRampFacingNegativeX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.minX - minX;
Scalar y = extents.maxY - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/x yields
// rise*x <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar y = point.y - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/x yields
// rise*x <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedInvertedRampFacingNegativeX::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------
// If the point is above the ramp, it will hit the top of the ramp
//----------------------------------------------------------------
//
if (point.y > maxY)
{
return point.y - maxY;
}
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar y = point.y - minY;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
return (x*rise <= y*run) ? 0.0f : -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.y = minX - maxX;
ramp.normal.x = maxY - minY;
ramp.normal.z = 0.0f;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.x*ramp.normal.x;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.x /= temp;
ramp.offset = minY*ramp.normal.y + minX*ramp.normal.x;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingNegativeX::TestInstance() const
{
return solidType == InvertedRampFacingNegativeXType;
}
//#############################################################################
//##################### BoxedInvertedRampFacingPositiveX ################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingPositiveX::BoxedInvertedRampFacingPositiveX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
InvertedRampFacingPositiveXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedInvertedRampFacingPositiveX::~BoxedInvertedRampFacingPositiveX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.maxX - maxX;
Scalar y = extents.maxY - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/x yields
// rise*x >= x*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar y = point.y - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/x yields
// rise*x >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedInvertedRampFacingPositiveX::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------
// If the point is above the ramp, it will hit the top of the ramp
//----------------------------------------------------------------
//
if (point.y > maxY)
{
return point.y - maxY;
}
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar y = point.y - minY;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
return (x*rise >= y*run) ? 0.0f : -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.y = minX - maxX;
ramp.normal.x = minY - maxY;
ramp.normal.z = 0.0f;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.x*ramp.normal.x;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.x /= temp;
ramp.offset = maxY*ramp.normal.y + minX*ramp.normal.x;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedInvertedRampFacingPositiveX::TestInstance() const
{
return solidType == InvertedRampFacingPositiveXType;
}
+311
View File
@@ -0,0 +1,311 @@
#include "munga.h"
#pragma hdrstop
#include "boxlist.h"
//#############################################################################
//######################### BoundingBoxListNode #########################
//#############################################################################
MemoryBlock *BoundingBoxListNode::GetAllocatedMemory()
{
static MemoryBlock allocatedMemory(sizeof(BoundingBoxListNode), 500, 50, "BoundingBoxList Nodes");
return &allocatedMemory;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBoxListNode::TestInstance() const
{
return True;
}
//#############################################################################
//########################### BoundingBoxList ###########################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBoxList::BoundingBoxList()
{
root = NULL;
nodeCount = 0;
scoreBoard = NULL;
boundingBoxIndex = NULL;
isXMajorAxis = True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBoxList::~BoundingBoxList()
{
if (scoreBoard)
{
Unregister_Pointer(scoreBoard);
delete scoreBoard;
}
if (boundingBoxIndex)
{
Unregister_Pointer(boundingBoxIndex);
delete boundingBoxIndex;
}
EraseList();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::Add(
BoundingBox* volume,
const ExtentBox &slice
)
{
Check(this);
Check(volume);
++nodeCount;
BoundingBoxListNode *node = new BoundingBoxListNode(volume, slice);
Register_Object(node);
node->previousNode = root;
root = node;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::Remove(BoundingBox* volume)
{
Check(this);
Check(volume);
//
//--------------------------------------------------------------------------
// Spin through all the boxes until we find the one we are after or until we
// run off the list
//--------------------------------------------------------------------------
//
BoundingBoxListNode
*p = NULL,
*c = root;
while (c)
{
Check(c);
if (c->boundingBox == volume)
{
break;
}
p = c;
c = c->previousNode;
}
//
//----------------------------------------------
// Unlink the node from the list if it was found
//----------------------------------------------
//
if (!c)
{
return;
}
Check(c);
if (p)
{
Check(p);
p->previousNode = c->previousNode;
}
else
{
root = c->previousNode;
}
//
//-----------------
// Delete this node
//-----------------
//
--nodeCount;
Unregister_Object(c);
delete c;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::EraseList()
{
Check(this);
//
//-----------------------------
// Delete each node in the list
//-----------------------------
//
BoundingBoxListNode *p = root;
while (p)
{
Check(p);
BoundingBoxListNode *q = p;
p = p->previousNode;
Unregister_Object(q);
delete q;
}
root = NULL;
nodeCount = 0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox*
BoundingBoxList::FindBoundingBoxContaining(const Point3D &point)
{
Check(this);
Check(&point);
//
//--------------------------------------------------------------------------
// Spin through each of the boxes in reverse order until we find a box which
// contains the specified point. It will be default have priority over any
// boxes put in before it
//--------------------------------------------------------------------------
//
for (BoundingBoxListNode *p=root; p; p = p->previousNode)
{
Check(p);
BoundingBox *box = p->boundingBox;
Check(box);
if (box->Contains(point))
{
return box;
}
}
return NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::FindBoundingBoxesContaining(
BoundingBox *volume,
BoundingBoxCollisionList &list
)
{
Check(this);
Check(volume);
Check(&list);
//
//-------------------------------------------------------------
// Spin through each of the boxes in reverse order, looking for
// intesections between the test volume and the box list
//-------------------------------------------------------------
//
for (BoundingBoxListNode *p=root; p; p = p->previousNode)
{
Check(p);
BoundingBox *box = p->boundingBox;
Check(box);
if (box->ExtentBox::Intersects(*volume))
{
//
//----------------------------------------------------------------
// Build the intersection slice, and make sure that it really does
// intersect the list box
//----------------------------------------------------------------
//
ExtentBox slice;
slice.Intersect(*volume, *box);
if (box->IntersectsBounded(slice))
{
//
//------------------------------------------------------------
// It intersects, so add this to the list. If we are out of
// collisions in the list, we are finished detecting, and just
// return
//------------------------------------------------------------
//
Verify(list.collisionsLeft);
list.AddCollisionToList(box, slice);
if (!list.collisionsLeft)
{
return;
}
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox*
BoundingBoxList::FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
)
{
Check(this);
Check(&point);
Check_Pointer(height);
//
//-----------------------------------------------------------------------
// Spin through each of the bounding boxes, keeping track of which box is
// hit after the shortest distance
//-----------------------------------------------------------------------
//
BoundingBox *best_box = NULL;
*height = -1.0f;
for (BoundingBoxListNode *p=root; p; p = p->previousNode)
{
Check(p);
BoundingBox *box = p->boundingBox;
Check(box);
Scalar h = box->FindDistanceBelow(point);
if (h != -1.0f)
{
if (!best_box || *height > h)
{
best_box = box;
*height = h;
}
}
}
return best_box;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoundingBox*
BoundingBoxList::FindBoundingBoxHitBy(Line *line)
{
//
//-----------------------------------------------------------------------
// Spin through each of the boxes, letting each box in turn clip the line
// lengths
//-----------------------------------------------------------------------
//
BoundingBox *best_box = NULL;
for (BoundingBoxListNode *p=root; p; p = p->previousNode)
{
Check(p);
BoundingBox *box = p->boundingBox;
Check(box);
Logical h = box->HitBy(line);
if (h)
{
best_box = box;
}
}
return best_box;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoundingBoxList::TestInstance() const
{
return True;
}
+147
View File
@@ -0,0 +1,147 @@
#pragma once
#include "bndgbox.h"
#include "memblock.h"
//##########################################################################
//####################### BoundingBoxListNode ########################
//##########################################################################
class BoundingBoxList;
class BoxedSolidList;
class BoundingBoxTree;
class BoundingBoxListNode SIGNATURED
{
friend class BoundingBoxList;
friend class BoxedSolidList;
//##########################################################################
// Memory Allocation
//
private:
static MemoryBlock* GetAllocatedMemory();
void* operator new(size_t) { return GetAllocatedMemory()->New(); }
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
//##########################################################################
// Construction and Destruction
//
protected:
BoundingBox
*boundingBox;
BoundingBoxListNode
*previousNode;
BoundingBoxListNode(
BoundingBox *volume,
const ExtentBox &slice
):
boundingBox(volume),
solidSlice(slice),
previousNode(NULL)
{Check_Pointer(this); Check(volume);}
~BoundingBoxListNode()
{Check(this);}
public:
ExtentBox
solidSlice;
BoundingBox*
GetBoundingBox()
{Check(this); return boundingBox;}
BoundingBoxListNode*
GetNextNode()
{Check(this); return previousNode;}
//##########################################################################
// Test Support
//
public:
Logical
TestInstance() const;
};
//##########################################################################
//######################## BoundingBoxList ###########################
//##########################################################################
class BoundingBoxList SIGNATURED
{
//##########################################################################
// Construction and Destruction
//
protected:
BoundingBoxListNode
*root;
int
nodeCount;
int*
scoreBoard;
BoundingBox
**boundingBoxIndex;
Logical
isXMajorAxis;
public:
BoundingBoxList();
~BoundingBoxList();
void
Add(
BoundingBox* volume,
const ExtentBox &slice
);
void
Remove(BoundingBox* volume);
void
EraseList();
BoundingBoxListNode*
GetRoot()
{Check(this); return root;}
//##########################################################################
// Tree Traversal Functions
//
public:
BoundingBox*
FindBoundingBoxContaining(const Point3D &point);
void
FindBoundingBoxesContaining(
BoundingBox *volume,
BoundingBoxCollisionList &list
);
BoundingBox*
FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
);
BoundingBox*
FindBoundingBoxHitBy(Line *line);
void
Reduce();
void
SortForTree();
protected:
void
Sort(
BoundingBoxList &active_solids,
ExtentBox &clipping_box,
BoundingBoxTree &tree_so_far
);
//##########################################################################
// Test Support
//
public:
Logical
TestInstance() const;
};
+924
View File
@@ -0,0 +1,924 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "plane.h"
#include "line.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampContainsLine(
Line *line,
const Plane& plane,
Scalar enters,
Scalar leaves
)
{
//
//------------------------------------------------------------------------
// Find the perpendicular distance from the origin of the ray to the ramp,
// and find the direction of the ray relative to the ramp
//------------------------------------------------------------------------
//
Scalar distance = plane.DistanceTo(line->origin);
Scalar drift = line->direction*plane.normal;
//
//--------------------------------------------------------------------------
// If the ray is going out of the ramp and the origin of the
// ray is in the half-space that the plane's normal points to
//--------------------------------------------------------------------------
//
if (drift > 0 && distance > 0)
{
return False;
}
//
//--------------------------------------------------------------------------
// If the ray is parallel to the ramp, the ray will hit if the origin of the
// ray is not in the half-space that the plane's normal points to
//--------------------------------------------------------------------------
//
if (!drift)
{
if (distance <= 0.0f)
{
line->length = Max(enters, 0.0f);
return True;
}
return False;
}
//
//--------------------------------------------------------------------
// Otherwise, if the plane faces the ray, check to see how far the ray
// travels before hitting it
//--------------------------------------------------------------------
//
if (drift < 0.0f)
{
distance /= -drift;
//
//-----------------------------------------------------------------------
// If the ray strikes the plane after all other facing surfaces, then the
// ray enters the solid through this plane. So check to make sure that
// the ray does not miss the plane as clipped by the other surfaces, and
// if it hits, return this distance as the projection length. If the ray
// enters the ramp through an edge face of the bounding box, set the line
// length to the entering value calculated for the box
//-----------------------------------------------------------------------
//
if (distance > enters)
{
if (distance > leaves || distance > line->length)
{
return False;
}
enters = distance;
}
line->length = Max(enters, 0.0f);
return True;
}
//
//------------------------------------------------------------------------
// If the plane faces away from the ray, check to see how far the ray
// travels before exiting it, and ensure this is not before the ray enters
// the object
//------------------------------------------------------------------------
//
distance /= -drift;
if (distance >= enters)
{
line->length = Max(enters, 0.0f);
return True;
}
return False;
}
//#############################################################################
//######################### BoxedRampFacingNegativeZ ####################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingNegativeZ::BoxedRampFacingNegativeZ(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, RampFacingNegativeZType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingNegativeZ::~BoxedRampFacingNegativeZ()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeZ::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = extents.minY - minY;
Scalar z = extents.minZ - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/z yields
// rise*z <= y*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return z*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeZ::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/z yields
// rise*z <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedRampFacingNegativeZ::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = minZ - maxZ;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - maxZ;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
y -= (rise/run)*z;
return Max(y,0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeZ::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.x = 0.0f;
ramp.normal.y = maxZ - minZ;
ramp.normal.z = maxY - minY;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.z /= temp;
ramp.offset = maxY*ramp.normal.y + minZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeZ::TestInstance() const
{
return solidType == RampFacingNegativeZType;
}
//#############################################################################
//######################### BoxedRampFacingPositiveZ ####################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingPositiveZ::BoxedRampFacingPositiveZ(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, RampFacingPositiveZType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingPositiveZ::~BoxedRampFacingPositiveZ()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveZ::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = extents.minY - minY;
Scalar z = extents.maxZ - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/z yields
// rise*z >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveZ::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/z slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/z yields
// rise*z >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return z*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedRampFacingPositiveZ::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar rise = maxY - minY;
Scalar run = maxZ - minZ;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar y = point.y - minY;
Scalar z = point.z - minZ;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
y -= (rise/run)*z;
return Max(y,0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveZ::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.x = 0.0f;
ramp.normal.y = maxZ - minZ;
ramp.normal.z = minY - maxY;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.z /= temp;
ramp.offset = minY*ramp.normal.y + minZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveZ::TestInstance() const
{
return solidType == RampFacingPositiveZType;
}
//#############################################################################
//######################### BoxedRampFacingNegativeX ####################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingNegativeX::BoxedRampFacingNegativeX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, RampFacingNegativeXType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingNegativeX::~BoxedRampFacingNegativeX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeX::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.minX - maxX;
Scalar y = extents.minY - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/x yields
// rise*x <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar y = point.y - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= y/x yields
// rise*x <= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise <= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedRampFacingNegativeX::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar y = point.y - minY;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
y -= (rise/run)*x;
return Max(y,0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.y = maxX - minX;
ramp.normal.x = maxY - minY;
ramp.normal.z = 0.0f;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.x*ramp.normal.x;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.x /= temp;
ramp.offset = maxY*ramp.normal.y + minX*ramp.normal.x;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingNegativeX::TestInstance() const
{
return solidType == RampFacingNegativeXType;
}
//#############################################################################
//######################### BoxedRampFacingPositiveX ####################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingPositiveX::BoxedRampFacingPositiveX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, RampFacingPositiveXType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedRampFacingPositiveX::~BoxedRampFacingPositiveX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveX::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.maxX - minX;
Scalar y = extents.minY - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/x yields
// rise*x >= x*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar y = point.y - minY;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than y/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= y/x yields
// rise*x >= y*run, which avoids any divide-by-0 errors
//------------------------------------------------------------------------
//
return x*rise >= y*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedRampFacingPositiveX::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin. If the run is zero, make sure no divide by zero
// happens
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxY - minY;
Verify(!Small_Enough(run));
//
//----------------------------------------------------------
// Get the point coordinates local the the start of the ramp
//----------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar y = point.y - minY;
//
//-------------------------------------------------------------------
// Return the distance from the point to where it intersects the ramp
//-------------------------------------------------------------------
//
y -= (rise/run)*x;
return Max(y,0.0f);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
Scalar
temp;
//
//-------------------------------------------------------------------
// Make a vector pointing normal to the face of the north facing ramp
//-------------------------------------------------------------------
//
ramp.normal.y = maxX - minX;
ramp.normal.x = minY - maxY;
ramp.normal.z = 0.0f;
//
//-------------------------------------------------------------
// Scale the vector to a normal and figure out the plane offset
//-------------------------------------------------------------
//
temp = ramp.normal.y*ramp.normal.y + ramp.normal.x*ramp.normal.x;
Verify(!Small_Enough(temp))
temp = Sqrt(temp);
ramp.normal.y /= temp;
ramp.normal.x /= temp;
ramp.offset = minY*ramp.normal.y + minX*ramp.normal.x;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedRampFacingPositiveX::TestInstance() const
{
return solidType == RampFacingPositiveXType;
}
File diff suppressed because it is too large Load Diff
+976
View File
@@ -0,0 +1,976 @@
#pragma once
#include "bndgbox.h"
#include "boxtree.h"
#include "boxlist.h"
#include "resource.h"
struct BoxedSolidResource;
class BoxedSolidCollision;
class BoxedSolidCollisionList;
class Simulation;
class NotationFile;
class Normal;
//##########################################################################
//########################### BoxedSolid #############################
//##########################################################################
class BoxedSolid:
public TaggedBoundingBox
{
public:
enum Type {
BlockType=0,
SphereType=1,
ConeType=2,
ReducibleBlockType=3,
RampType=4,
RampFacingNegativeZType=4,
RampFacingNegativeXType,
RampFacingPositiveZType,
RampFacingPositiveXType,
InvertedRampType=8,
InvertedRampFacingNegativeZType=8,
InvertedRampFacingNegativeXType,
InvertedRampFacingPositiveZType,
InvertedRampFacingPositiveXType,
WedgeType=12,
WedgeFacingNegativeZAndPositiveXType=12,
WedgeFacingNegativeZAndNegativeXType,
WedgeFacingPositiveZAndNegativeXType,
WedgeFacingPositiveZAndPositiveXType,
XAxisCylinderType=16,
YAxisCylinderType=17,
ZAxisCylinderType=18,
RightHandedTileType=19,
LeftHandedTileType=20,
SolidTypeCount
}
solidType;
enum Material {
StoneMaterial = 0,
GravelMaterial,
ConcreteMaterial,
SteelMaterial,
WoodMaterial,
RockMaterial,
OurCraftMaterial,
OtherCraftMaterial,
MaterialCount
}
materialType;
BoxedSolid(
const ExtentBox &extents,
Type type,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
BoxedSolid(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedSolid();
static BoxedSolid*
MakeBoxedSolid(
BoxedSolidResource *resource,
Simulation *owner,
BoxedSolid *next_solid
);
virtual Logical
VerifyCollision(BoxedSolidCollision &collision);
virtual Logical
ProcessCollision(
BoxedSolidCollision &collision,
const Vector3D &velocity,
BoxedSolidCollisionList *last_collisions,
Normal *normal,
Scalar *penetration
);
Logical
TestInstance() const;
static Logical
TestClass();
Simulation*
GetOwningSimulation()
{Check(this); return (Simulation*)GetTagPointer();}
BoxedSolid*
GetNextSolid()
{Check(this); return nextSolid;}
protected:
BoxedSolid
*nextSolid;
};
//##########################################################################
//####################### BoxedSolidCollision ########################
//##########################################################################
class BoxedSolidCollision:
public BoundingBoxCollision
{
public:
BoxedSolid*
GetTreeVolume()
{Check(this); return (BoxedSolid*)treeVolume;}
Logical
Occludes(
BoxedSolidCollision &collision,
const Vector3D &velocity
);
};
//##########################################################################
//##################### BoxedSolidCollisionList ######################
//##########################################################################
class BoxedSolidCollisionList:
public BoundingBoxCollisionList
{
protected:
int phantomCollisions;
public:
BoxedSolidCollisionList(int max_length = 10):
BoundingBoxCollisionList(max_length)
{Reset();}
void
Reset()
{phantomCollisions = 0; BoundingBoxCollisionList::Reset();}
BoxedSolidCollision&
operator[](int index)
{
Check(this); Verify((unsigned)index < maxCollisions);
return ((BoxedSolidCollision*)listStart)[index];
}
int
GetRealCollisions()
{Check(this); return GetCollisionCount() - phantomCollisions;}
void
ReduceCollisionList(const Vector3D &velocity);
};
//##########################################################################
//####################### BoxedSolidResource #########################
//##########################################################################
struct BoxedSolidResource
{
size_t recordLength;
ExtentBox
solidExtents,
sliceExtents;
BoxedSolid::Type solidType;
BoxedSolid::Material materialType;
void
Instance(
const BoxedSolidResource &source,
const Origin& origin
);
static ResourceDescription::ResourceID
CreateBoxedSolidStream(
const char *entry_data,
ResourceFile *file,
const ResourceDirectories *resource_directories,
Logical convert_boxes = False
);
};
//##########################################################################
//########################### BoxedSphere ############################
//##########################################################################
class BoxedSphere:
public BoxedSolid
{
public:
BoxedSphere(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedSphere();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//############################ BoxedCone #############################
//##########################################################################
class BoxedCone:
public BoxedSolid
{
public:
BoxedCone(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedCone();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//####################### BoxedReducibleBlock ########################
//##########################################################################
class BoxedReducibleBlock:
public BoxedSolid
{
public:
BoxedReducibleBlock(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedReducibleBlock();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//###################### BoxedRampFacingNegativeZ ####################
//##########################################################################
class BoxedRampFacingNegativeZ:
public BoxedSolid
{
public:
BoxedRampFacingNegativeZ(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedRampFacingNegativeZ();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//#################### BoxedRampFacingPositiveX ######################
//##########################################################################
class BoxedRampFacingPositiveX:
public BoxedSolid
{
public:
BoxedRampFacingPositiveX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedRampFacingPositiveX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//#################### BoxedRampFacingPositiveZ ######################
//##########################################################################
class BoxedRampFacingPositiveZ:
public BoxedSolid
{
public:
BoxedRampFacingPositiveZ(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedRampFacingPositiveZ();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//#################### BoxedRampFacingNegativeX ######################
//##########################################################################
class BoxedRampFacingNegativeX:
public BoxedSolid
{
public:
BoxedRampFacingNegativeX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedRampFacingNegativeX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//################## BoxedInvertedRampFacingNegativeZ ################
//##########################################################################
class BoxedInvertedRampFacingNegativeZ:
public BoxedSolid
{
public:
BoxedInvertedRampFacingNegativeZ(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedInvertedRampFacingNegativeZ();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//################## BoxedInvertedRampFacingNegativeX ################
//##########################################################################
class BoxedInvertedRampFacingNegativeX:
public BoxedSolid
{
public:
BoxedInvertedRampFacingNegativeX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedInvertedRampFacingNegativeX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//################## BoxedInvertedRampFacingPositiveZ ################
//##########################################################################
class BoxedInvertedRampFacingPositiveZ:
public BoxedSolid
{
public:
BoxedInvertedRampFacingPositiveZ(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedInvertedRampFacingPositiveZ();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//################## BoxedInvertedRampFacingPositiveX ################
//##########################################################################
class BoxedInvertedRampFacingPositiveX:
public BoxedSolid
{
public:
BoxedInvertedRampFacingPositiveX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedInvertedRampFacingPositiveX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//############## BoxedWedgeFacingNegativeZAndPositiveX ###############
//##########################################################################
class BoxedWedgeFacingNegativeZAndPositiveX:
public BoxedSolid
{
public:
BoxedWedgeFacingNegativeZAndPositiveX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedWedgeFacingNegativeZAndPositiveX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//############## BoxedWedgeFacingPositiveZAndPositiveX ###############
//##########################################################################
class BoxedWedgeFacingPositiveZAndPositiveX:
public BoxedSolid
{
public:
BoxedWedgeFacingPositiveZAndPositiveX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedWedgeFacingPositiveZAndPositiveX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//############## BoxedWedgeFacingPositiveZAndNegativeX ###############
//##########################################################################
class BoxedWedgeFacingPositiveZAndNegativeX:
public BoxedSolid
{
public:
BoxedWedgeFacingPositiveZAndNegativeX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedWedgeFacingPositiveZAndNegativeX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//############## BoxedWedgeFacingNegativeZAndNegativeX ###############
//##########################################################################
class BoxedWedgeFacingNegativeZAndNegativeX:
public BoxedSolid
{
public:
BoxedWedgeFacingNegativeZAndNegativeX(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedWedgeFacingNegativeZAndNegativeX();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//####################### BoxedXAxisCylinder #########################
//##########################################################################
class BoxedXAxisCylinder:
public BoxedSolid
{
public:
BoxedXAxisCylinder(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedXAxisCylinder();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//####################### BoxedYAxisCylinder #########################
//##########################################################################
class BoxedYAxisCylinder:
public BoxedSolid
{
public:
BoxedYAxisCylinder(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedYAxisCylinder();
Logical
VerifyCollision(BoxedSolidCollision &collision);
Logical
ProcessCollision(
BoxedSolidCollision &collision,
const Vector3D &velocity,
BoxedSolidCollisionList *last_collisions,
Normal *normal,
Scalar *penetration
);
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//####################### BoxedZAxisCylinder #########################
//##########################################################################
class BoxedZAxisCylinder:
public BoxedSolid
{
public:
BoxedZAxisCylinder(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid
);
~BoxedZAxisCylinder();
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//##################### RightHandedTile #######################
//##########################################################################
class RightHandedTile:
public BoxedSolid
{
public:
RightHandedTile(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid,
Scalar *cornerHeights,
Type type=RightHandedTileType
);
~RightHandedTile();
Scalar
cornerHeight[4];
Logical
IntersectsBounded(const ExtentBox &extents);
Logical
ContainsBounded(const Point3D &point);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//######################## LeftHandedTile #########################
//##########################################################################
class LeftHandedTile:
public RightHandedTile
{
public:
LeftHandedTile(
const ExtentBox &extents,
Material material,
Simulation *owner,
BoxedSolid *next_solid,
Scalar *cornerHeights
);
~LeftHandedTile();
Logical
IntersectsBounded(const ExtentBox &extents);
Scalar
FindDistanceBelowBounded(const Point3D &point);
Logical
HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
);
Logical
TestInstance() const;
};
//##########################################################################
//####################### TerrainTileResource ########################
//##########################################################################
struct TileResource:
public BoxedSolidResource
{
Scalar
cornerHeight[4];
void
Instance(
const TileResource &source,
const Origin& origin
);
};
//##########################################################################
//######################## BoxedSolidTree ############################
//##########################################################################
class BoxedSolidTree:
public BoundingBoxTree
{
//##########################################################################
// Construction and Destruction
//
public:
BoxedSolidTree()
{}
~BoxedSolidTree()
{}
//##########################################################################
// Tree Traversal Functions
//
public:
BoxedSolid*
FindBoundingBoxContaining(const Point3D &point)
{
return
(BoxedSolid*)
BoundingBoxTree::FindBoundingBoxContaining(point);
}
BoxedSolid*
FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
)
{
return
(BoxedSolid*)
BoundingBoxTree::FindBoundingBoxUnder(point, height);
}
BoxedSolid*
FindBoundingBoxHitBy(Line *line)
{return (BoxedSolid*)BoundingBoxTree::FindBoundingBoxHitBy(line);}
};
//##########################################################################
//######################## BoxedSolidList ############################
//##########################################################################
class BoxedSolidList:
public BoundingBoxList
{
//##########################################################################
// Construction and Destruction
//
public:
BoxedSolidList() {}
~BoxedSolidList() {}
//##########################################################################
// Tree Traversal Functions
//
public:
int
AddBoxedSolids(NotationFile *notation_file);
BoxedSolid*
FindBoundingBoxContaining(const Point3D &point)
{
return
(BoxedSolid*)
BoundingBoxList::FindBoundingBoxContaining(point);
}
BoxedSolid*
FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
)
{
return
(BoxedSolid*)
BoundingBoxList::FindBoundingBoxUnder(point, height);
}
BoxedSolid*
FindBoundingBoxHitBy(Line *line)
{return (BoxedSolid*)BoundingBoxList::FindBoundingBoxHitBy(line);}
void
Reduce();
};
+474
View File
@@ -0,0 +1,474 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "vector3d.h"
//#############################################################################
//########################### BoxedSolidList ############################
//#############################################################################
enum {
X_Axis_Bit = 1,
Y_Axis_Bit = 2,
Z_Axis_Bit = 4
};
enum {
Min_Side = 0x001,
Inside = 0x002,
Max_Side = 0x004,
Both_Sides = Min_Side|Max_Side,
Shift = 3,
X_Shift = 2 * Shift,
Min_X_Side = Min_Side << X_Shift,
Inside_X = Inside << X_Shift,
Max_X_Side = Max_Side << X_Shift,
X_Mask = Min_X_Side|Inside_X|Max_X_Side,
Y_Shift = Shift,
Min_Y_Side = Min_Side << Y_Shift,
Inside_Y = Inside << Y_Shift,
Max_Y_Side = Max_Side << Y_Shift,
Y_Mask = Min_Y_Side|Inside_Y|Max_Y_Side,
Z_Shift = 0,
Min_Z_Side = Min_Side << Z_Shift,
Inside_Z = Inside << Z_Shift,
Max_Z_Side = Max_Side << Z_Shift,
Z_Mask = Min_Z_Side|Inside_Z|Max_Z_Side
};
int
Legal_To_Fuse[BoxedSolid::SolidTypeCount]=
{
X_Axis_Bit|Y_Axis_Bit|Z_Axis_Bit, 0, 0, 0,
X_Axis_Bit, Z_Axis_Bit, X_Axis_Bit, Z_Axis_Bit,
X_Axis_Bit, Z_Axis_Bit, X_Axis_Bit, Z_Axis_Bit,
Y_Axis_Bit, Y_Axis_Bit, Y_Axis_Bit, Y_Axis_Bit,
X_Axis_Bit, Y_Axis_Bit, Z_Axis_Bit
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::Reduce()
{
Check(this);
BoundingBoxListNode
*i, *j, *previous;
//
//--------------------------------------------------------------------------
// Fuse the collision slices together into the largest possible chunks based
// upon the collision model of each of the involved slices. Repeat until no
// fusings were made in the last pass or only one collision slice remains
//--------------------------------------------------------------------------
//
Logical again = True;
while (again)
{
again = False;
//
//--------------------------------------------------------------------
// Check each collision slice against the remaining slices in the list
//--------------------------------------------------------------------
//
for (i=root; i; i = i->previousNode)
{
Check(i);
previous = i;
j = i->previousNode;
while (j)
{
Check(j);
//
//-------------------------------------------------------------
// If the model types are different, these two slices cannot be
// fused
//-------------------------------------------------------------
//
BoundingBox *first = i->boundingBox;
BoundingBox *second = j->boundingBox;
//
//----------------------------------------------------
// Make sure that the faces on two sets of sides match
//----------------------------------------------------
//
int matches = 0;
int face = -1;
for (int side=0; side<6; side += 2)
{
if (
(*first)[side] == (*second)[side]
&& (*first)[side+1] == (*second)[side+1]
)
{
++matches;
}
else if (face<0)
{
face = side;
}
}
if (matches != 2)
{
Next_Solid:
previous = j;
j = j->previousNode;
continue;
}
//
//----------------------------------------------------------------
// Check to make sure that the two solids have an opposing face in
// common, which will allow the solids to be fused
//----------------------------------------------------------------
//
if (
(*first)[face] != (*second)[face+1]
&& (*first)[face+1] != (*second)[face]
)
{
goto Next_Solid;
}
//
//----------------------------------------------------
// Find the face to fuse, and fuse the blocks together
//----------------------------------------------------
//
if ((*first)[face+1] == (*second)[face])
{
++face;
}
(*first)[face] = (*second)[face];
//
//-----------------------------------------------
// Erase the second solid from the collision list
//-----------------------------------------------
//
--nodeCount;
if (previous)
{
previous->previousNode = j->previousNode;
Unregister_Object(j);
delete(j);
j = previous->previousNode;
}
else
{
root = j->previousNode;
Unregister_Object(j);
delete(j);
j = root;
}
again = True;
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::SortForTree()
{
Check(this);
int
i, j;
BoundingBoxListNode
*p, *q;
//
//-----------------------------------------------------------------------
// Find out how many collision solids are in the list, and figure out the
// total extent box so that we can set the traversal order correctly
//-----------------------------------------------------------------------
//
ExtentBox map_extents;
map_extents.minX = 65535.9999f;
map_extents.minY = 65535.9999f;
map_extents.minZ = 65535.9999f;
map_extents.maxX = -65535.9999f;
map_extents.maxY = -65535.9999f;
map_extents.maxZ = -65535.9999f;
for (p=root; p; p = p->previousNode)
{
Check(p);
if (p->boundingBox->minX < map_extents.minX)
{
map_extents.minX = p->boundingBox->minX;
}
if (p->boundingBox->maxX > map_extents.maxX)
{
map_extents.maxX = p->boundingBox->maxX;
}
if (p->boundingBox->minY < map_extents.minY)
{
map_extents.minY = p->boundingBox->minY;
}
if (p->boundingBox->maxY > map_extents.maxY)
{
map_extents.maxY = p->boundingBox->maxY;
}
if (p->boundingBox->minZ < map_extents.minZ)
{
map_extents.minZ = p->boundingBox->minZ;
}
if (p->boundingBox->maxZ > map_extents.maxZ)
{
map_extents.maxZ = p->boundingBox->maxZ;
}
}
if (
map_extents.maxZ - map_extents.minZ
> map_extents.maxX - map_extents.minX
)
{
isXMajorAxis = False;
}
//
//----------------------------------------------------
// Allocate a scoreboard and fill it with sorting info
//----------------------------------------------------
//
Verify(!scoreBoard);
scoreBoard = new int[nodeCount * nodeCount];
Register_Pointer(scoreBoard);
int *score = scoreBoard;
boundingBoxIndex = new BoundingBox* [nodeCount];
Register_Pointer(boundingBoxIndex);
for (p=root,i=0; p; p = p->previousNode,++i)
{
Check(p);
BoundingBox *first = p->boundingBox;
boundingBoxIndex[i] = first;
for (q=root,j=0; q; q = q->previousNode,++j,++score)
{
//
//------------------------------
// Ignore scoring against itself
//------------------------------
//
Check(q);
*score = 0;
if (p == q)
{
continue;
}
BoundingBox *second = q->boundingBox;
//
//--------------------------------------------------------------------
// Step through the three axes and set the flags showing how the
// second solid is split up by the first solid. Make sure that if the
// second solid completely covers the first that this inside bit is
// set correctly
//--------------------------------------------------------------------
//
for (int axis = X_Axis; axis <= Z_Axis; --axis)
{
*score <<= Shift;
int face = axis << 1;
if ((*second)[face] < (*first)[face])
{
*score |= Min_Side;
}
else if ((*second)[face] < (*first)[face+1])
{
*score |= Inside;
}
if ((*second)[face+1] > (*first)[face+1])
{
*score |= Max_Side;
}
else if ((*second)[face+1] > (*first)[face])
{
*score |= Inside;
}
if ((*score & Both_Sides) == Both_Sides)
{
*score |= Inside;
}
}
}
}
//
//--------------------------------------------------------------------------
// Create a new BoxedSolid list for results to go into, and a third in which
// to pass the active list
//--------------------------------------------------------------------------
//
BoundingBoxList active;
active.root = root;
active.nodeCount = nodeCount;
root = NULL;
BoundingBoxTree tree_so_far;
Sort(
active,
map_extents,
tree_so_far
);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoundingBoxList::Sort(
BoundingBoxList &,//active,
ExtentBox &,//map_extents,
BoundingBoxTree &//tree_so_far
)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
BoxedSolidList::Reduce()
{
Check(this);
BoundingBoxListNode
*i, *j, *previous;
//
//--------------------------------------------------------------------------
// Fuse the collision slices together into the largest possible chunks based
// upon the collision model of each of the involved slices. Repeat until no
// fusings were made in the last pass or only one collision slice remains
//--------------------------------------------------------------------------
//
Logical again = True;
while (again)
{
again = False;
//
//--------------------------------------------------------------------
// Check each collision slice against the remaining slices in the list
//--------------------------------------------------------------------
//
for (i=root; i; i = i->previousNode)
{
Check(i);
previous = i;
j = i->previousNode;
while (j)
{
Check(j);
//
//-------------------------------------------------------------
// If the model types are different, these two slices cannot be
// fused
//-------------------------------------------------------------
//
BoxedSolid *first = Cast_Object(BoxedSolid*, i->boundingBox);
BoxedSolid *second = Cast_Object(BoxedSolid*, j->boundingBox);
if (first->solidType != second->solidType)
{
Next_Solid:
previous = j;
j = j->previousNode;
continue;
}
//
//----------------------------------------------------
// Make sure that the faces on two sets of sides match
//----------------------------------------------------
//
int matches = 0;
int face = -1;
for (int side=0; side<6; side += 2)
{
if (
(*first)[side] == (*second)[side]
&& (*first)[side+1] == (*second)[side+1]
)
{
++matches;
}
else if (face<0)
{
face = side;
}
}
if (matches != 2)
{
goto Next_Solid;
}
//
//----------------------------------------------------------------
// Check to make sure that the two solids have an opposing face in
// common, which will allow the solids to be fused
//----------------------------------------------------------------
//
if (
(*first)[face] != (*second)[face+1]
&& (*first)[face+1] != (*second)[face]
)
{
goto Next_Solid;
}
//
//---------------------------------------------------------------
// Make sure that this type of solid is legal to be fused in this
// direction
//---------------------------------------------------------------
//
if (!(Legal_To_Fuse[first->solidType] & (face>>1)))
{
goto Next_Solid;
}
//
//----------------------------------------------------
// Find the face to fuse, and fuse the blocks together
//----------------------------------------------------
//
if ((*first)[face+1] == (*second)[face])
{
++face;
}
(*first)[face] = (*second)[face];
//
//-----------------------------------------------
// Erase the second solid from the collision list
//-----------------------------------------------
//
if (previous)
{
previous->previousNode = j->previousNode;
Unregister_Object(j);
delete(j);
j = previous->previousNode;
}
else
{
root = j->previousNode;
Unregister_Object(j);
delete(j);
j = root;
}
again = True;
}
}
}
}
+235
View File
@@ -0,0 +1,235 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "origin.h"
#include "linmtrx.h"
#include "line.h"
//#############################################################################
//############################## BoxedSphere ############################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSphere::BoxedSphere(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(extents, SphereType, material, owner, next_solid)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedSphere::~BoxedSphere()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//--------------------------------------------------------------------------
// Constrain the centerpoint of the sphere to be within the bounded extents.
// Then see if the constrained point is within the radius of the sphere. If
// so, it is an intersection
//--------------------------------------------------------------------------
//
Point3D closest = center;
extents.Constrain(&closest);
closest -= center;
return radius*radius >= closest.LengthSquared();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-------------------------------------------------------------------------
// translate the test point into the sphere's frame of reference and see if
// it is close enough
//-------------------------------------------------------------------------
//
center -= point;
return radius*radius >= center.LengthSquared();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedSphere::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-----------------------------------------------------------------------
// Convert the point to the coordinates of the sphere, putting the center
// point of the sphere at the origin. Note that we are subtracting the
// point from the center point as opposed to the normal way. This will
// result in both X and Y being negated, but since we are squaring them,
// this will not matter
//-----------------------------------------------------------------------
//
Scalar x = center.x - point.x;
Scalar z = center.z - point.z;
Scalar h = radius*radius - x*x - z*z;
if (h < SMALL)
{
return -1.0f;
}
//
//-------------------------------------------------------------------
// If the point is in the XZ shadow of the sphere, then the height is
// determined by the height of the sphere at that point
//-------------------------------------------------------------------
//
Scalar height = point.y - (center.y + Sqrt(h));
return Abs(height);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
//
//----------------------------------------------
// Find the centerpoint and radius of the sphere
//----------------------------------------------
//
Point3D center;
center.x = (minX + maxX) * 0.5f;
center.y = (minY + maxY) * 0.5f;
center.z = (minZ + maxZ) * 0.5f;
Scalar radius = maxX - center.x;
//
//-------------------------------------------------------------------------
// Find the point of closest approach to the center of the sphere, and make
// sure that it is within the boundaries of the sphere
//-------------------------------------------------------------------------
//
Scalar midlen = line->LengthToClosestPointTo(center);
Point3D closest;
line->Project(midlen, &closest);
closest -= center;
Scalar v = radius*radius - closest.LengthSquared();
if (v < 0.0f)
{
return False;
}
//
//---------------------------------------------------------------------
// Find the closest possible length of ray traversal before hitting the
// sphere
//---------------------------------------------------------------------
//
v = Sqrt(v);
Scalar enter = midlen - v;
if (enter > enters)
{
enters = enter;
}
Scalar leave = midlen + v;
if (leave < leaves)
{
leaves = leave;
}
if (enters > leaves || enters > line->length || leaves < 0.0f)
{
return False;
}
line->length = Max(enters, 0.0f);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedSphere::TestInstance() const
{
return solidType == SphereType;
}
+641
View File
@@ -0,0 +1,641 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "origin.h"
#include "linmtrx.h"
#include "line.h"
#include "plane.h"
#include "vector2d.h"
//#############################################################################
//######################### RightHandedTile ######################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RightHandedTile::RightHandedTile(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid,
Scalar *corners,
Type type
):
BoxedSolid(extents, type, material, owner, next_solid)
{
Check_Pointer(this);
for (int i=0; i<ELEMENTS(cornerHeight); ++i)
{
cornerHeight[i] = corners[i];
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
RightHandedTile::~RightHandedTile()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RightHandedTile::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//-------------------------------------------------------------------
// See if the box hits the upper-right triangle anywhere on its plane
//-------------------------------------------------------------------
//
Point3D p0,p1,p2;
p0.x = maxX;
p0.y = cornerHeight[1];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[0];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[3];
p2.z = maxZ;
Plane plane1(p0, p1, p2);
if (plane1.ContainsSomeOf(extents))
{
//
//-------------------------------------------------------------------
// Make sure the XZ projections of the triangle and the box intersect
//-------------------------------------------------------------------
//
return True;
}
//
//------------------------------------------------------------------
// See if the box hits the lower-left triangle anywhere on its plane
//------------------------------------------------------------------
//
p0.x = minX;
p0.y = cornerHeight[2];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[3];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[0];
p2.z = minZ;
Plane plane2(p0, p1, p2);
if (plane2.ContainsSomeOf(extents))
{
//
//-------------------------------------------------------------------
// Make sure the XZ projections of the triangle and the box intersect
//-------------------------------------------------------------------
//
return True;
}
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RightHandedTile::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(maxY >= point.y);
return FindDistanceBelowBounded(point) <= 0.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
RightHandedTile::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//---------------------------------------------------
// Figure out which triangle the point will reside in
//---------------------------------------------------
//
Scalar rise = maxX - minX;
Scalar run = maxZ - minZ;
Verify(rise > SMALL);
Verify(run > SMALL);
Scalar dx = point.x - minX;
Scalar dz = point.z - minZ;
//
//-----------------------------------------------------------------
// Set up the appropriate triangle based upon which have it lies in
//-----------------------------------------------------------------
//
Point3D p0,p1,p2;
if (dx*run > dz*rise)
{
p0.x = maxX;
p0.y = cornerHeight[1];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[0];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[3];
p2.z = maxZ;
}
else
{
p0.x = minX;
p0.y = cornerHeight[2];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[3];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[0];
p2.z = minZ;
}
//
//---------------------------------------------------------------------
// Make a plane out of the triangle, and have the plane solve for the Y
// coordinate
//---------------------------------------------------------------------
//
Plane plane(p0, p1, p2);
Verify(!Small_Enough(plane.normal.y));
Scalar height = point.y - plane.CalculateY(point.x, point.z);
Check_Fpu();
return height;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static Scalar
LineHitsTriangle(
Line *line,
const Point3D &p0,
const Point3D &p1,
const Point3D &p2,
Scalar *cosine
)
{
//
//--------------------------------------------------------------------------
// Make the plane out of the three corner points, and figure out how far the
// ray must travel to reach this plane. Try some trivial rejections:
// parallel lines, lines starting outside the halfspace heading away from
// the plane, and lines starting outside the halfspace and heading towards
// the plane but are too far away
//--------------------------------------------------------------------------
//
Plane plane(p0, p1, p2);
Scalar length = line->DistanceTo(plane, cosine);
if (
Small_Enough(*cosine)
|| *cosine > 0.0f && length < 0.0f
|| *cosine < 0.0f && length > line->length
)
{
return -1.0f;
}
//
//--------------------------------------------------------
// Project the impact point and triangle unto the XZ plane
//--------------------------------------------------------
//
Point3D impact;
line->Project(length, &impact);
Vector2DOf<Scalar> proj(impact.x - p0.x, impact.z - p0.z);
Scalar x = p1.x - p0.x;
Scalar z = p2.z - p0.z;
//
//-------------------------------------------------------------------------
// Make sure that the area of the triangle made with the test point and the
// first leg is not negative or greater than the area of the triangle made
// by the two legs. The area of the triangle is half the cross product of
// the legs of that triangle
//-------------------------------------------------------------------------
//
Scalar area_ratio = z*x;
Verify(!Small_Enough(area_ratio));
area_ratio = x*proj.y / area_ratio;
Check_Fpu();
if (area_ratio >= 0.0f && area_ratio <= 1.0f)
{
//
//----------------------------------------------------------------------
// The area ratio represents the height of the test triangle relative to
// the given triangle. One edge of the value is represented by
// projecting the second leg a percentage equal to the ratio. The bounds
// of its variance is 1-area_ratio * the first leg of the triangle
//----------------------------------------------------------------------
//
Scalar span = proj.x / x;
Check_Fpu();
if (span >= 0.0f && span+area_ratio <= 1.0f)
{
return length;
}
}
return -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RightHandedTile::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
//
//----------------------------------------------
// See if the line hits the upper-right triangle
//----------------------------------------------
//
Point3D p0,p1,p2;
p0.x = maxX;
p0.y = cornerHeight[1];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[0];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[3];
p2.z = maxZ;
Scalar cosine;
Scalar length = LineHitsTriangle(line, p0, p1, p2, &cosine);
//
//--------------------------------------------------------------
// If we are entering the the plane, set the new entering length
//--------------------------------------------------------------
//
if (length >= 0.0f && cosine < 0.0f && length >= enters && length <= leaves)
{
line->length = length;
return True;
}
//
//---------------------------------------------
// See if the line hits the lower left triangle
//---------------------------------------------
//
p0.x = minX;
p0.y = cornerHeight[2];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[3];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[0];
p2.z = minZ;
length = LineHitsTriangle(line, p0, p1, p2, &cosine);
//
//--------------------------------------------------------------
// If we are entering the the plane, set the new entering length
//--------------------------------------------------------------
//
if (length >= 0.0f && cosine < 0.0f && length >= enters && length <= leaves)
{
line->length = length;
return True;
}
//
//-------------------------------------------
// Neither triangle was entered, so we missed
//-------------------------------------------
//
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
RightHandedTile::TestInstance() const
{
return solidType == RightHandedTileType;
}
//#############################################################################
//######################### LeftHandedTile ######################
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LeftHandedTile::LeftHandedTile(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid,
Scalar *corners
):
RightHandedTile(
extents,
material,
owner,
next_solid,
corners,
LeftHandedTileType
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
LeftHandedTile::~LeftHandedTile()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
LeftHandedTile::IntersectsBounded(const ExtentBox &extents)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//-------------------------------------------------------------------
// See if the box hits the upper-left triangle anywhere on its plane
//-------------------------------------------------------------------
//
Point3D p0,p1,p2;
p0.x = maxX;
p0.y = cornerHeight[2];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[1];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[0];
p2.z = maxZ;
Plane plane1(p0, p1, p2);
if (plane1.ContainsSomeOf(extents))
{
//
//-------------------------------------------------------------------
// Make sure the XZ projections of the triangle and the box intersect
//-------------------------------------------------------------------
//
return True;
}
//
//------------------------------------------------------------------
// See if the box hits the lower-right triangle anywhere on its plane
//------------------------------------------------------------------
//
p0.x = minX;
p0.y = cornerHeight[1];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[2];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[3];
p2.z = minZ;
Plane plane2(p0, p1, p2);
if (plane2.ContainsSomeOf(extents))
{
//
//-------------------------------------------------------------------
// Make sure the XZ projections of the triangle and the box intersect
//-------------------------------------------------------------------
//
return True;
}
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
LeftHandedTile::FindDistanceBelowBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//---------------------------------------------------
// Figure out which triangle the point will reside in
//---------------------------------------------------
//
Scalar rise = maxX - minX;
Scalar run = maxZ - minZ;
Verify(rise > SMALL);
Verify(run > SMALL);
Scalar dx = point.x - minX; // HACK - needs to be set up for other diagonal
Scalar dz = point.z - minZ;
//
//-----------------------------------------------------------------
// Set up the appropriate triangle based upon which have it lies in
//-----------------------------------------------------------------
//
Point3D p0,p1,p2;
if (dx*run > dz*rise)
{
p0.x = maxX;
p0.y = cornerHeight[1];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[0];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[3];
p2.z = maxZ;
}
else
{
p0.x = minX;
p0.y = cornerHeight[2];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[3];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[0];
p2.z = minZ;
}
//
//---------------------------------------------------------------------
// Make a plane out of the triangle, and have the plane solve for the Y
// coordinate
//---------------------------------------------------------------------
//
Plane plane(p0, p1, p2);
Verify(!Small_Enough(plane.normal.y));
Scalar height = point.y - plane.CalculateY(point.x, point.z);
Check_Fpu();
return height;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
LeftHandedTile::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Check(this);
Check(line);
Verify(enters <= leaves);
Verify(leaves >= 0.0f);
//
//----------------------------------------------
// See if the line hits the upper-right triangle
//----------------------------------------------
//
Point3D p0,p1,p2;
p0.x = maxX;
p0.y = cornerHeight[2];
p0.z = minZ;
p1.x = minX;
p1.y = cornerHeight[1];
p1.z = minZ;
p2.x = maxX;
p2.y = cornerHeight[0];
p2.z = maxZ;
Scalar cosine;
Scalar length = LineHitsTriangle(line, p0, p1, p2, &cosine);
//
//--------------------------------------------------------------
// If we are entering the the plane, set the new entering length
//--------------------------------------------------------------
//
if (length >= 0.0f && cosine < 0.0f && length >= enters && length <= leaves)
{
line->length = length;
return True;
}
//
//---------------------------------------------
// See if the line hits the lower left triangle
//---------------------------------------------
//
p0.x = minX;
p0.y = cornerHeight[1];
p0.z = maxZ;
p1.x = maxX;
p1.y = cornerHeight[2];
p1.z = maxZ;
p2.x = minX;
p2.y = cornerHeight[3];
p2.z = minZ;
length = LineHitsTriangle(line, p0, p1, p2, &cosine);
//
//--------------------------------------------------------------
// If we are entering the the plane, set the new entering length
//--------------------------------------------------------------
//
if (length >= 0.0f && cosine < 0.0f && length >= enters && length <= leaves)
{
line->length = length;
return True;
}
//
//-------------------------------------------
// Neither triangle was entered, so we missed
//-------------------------------------------
//
return False;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
LeftHandedTile::TestInstance() const
{
return solidType == LeftHandedTileType;
}
File diff suppressed because it is too large Load Diff
+208
View File
@@ -0,0 +1,208 @@
#pragma once
#include "bndgbox.h"
#include "memblock.h"
//##########################################################################
//####################### BoundingBoxTreeNode ########################
//##########################################################################
class BoundingBoxTree;
class BoundingBoxTreeNode SIGNATURED
{
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); }
//##########################################################################
// Construction and Destruction
//
protected:
ExtentBox
nodeExtents;
BoundingBox
*staticContents;
BoundingBoxTreeNode
*nodeBranches[6],
*innerNode;
BoundingBoxTreeNode(
BoundingBox *volume,
const ExtentBox &extents
);
~BoundingBoxTreeNode();
void
Add(
BoundingBox *BoundingBox,
const ExtentBox &extents
);
void
Remove(
BoundingBox *BoundingBox,
const ExtentBox &extents
);
//##########################################################################
// Tree Traversal Functions
//
protected:
static int
TraversalOrder[6];
static void
SetTraversalOrder(
int first,
int second,
int third
);
public:
BoundingBoxTreeNode*
FindSmallestNodeContaining(
const ExtentBox &extents,
BoundingBoxTreeNode *parent
);
BoundingBoxTreeNode*
FindSmallestNodeContainingColumn(const ExtentBox &extents);
BoundingBox*
FindBoundingBoxContaining(
const Point3D &point,
BoundingBox *parent
);
void
FindBoundingBoxesContaining(
BoundingBox *volume,
const ExtentBox &slice,
BoundingBoxCollisionList &list
);
BoundingBox*
FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
);
BoundingBox*
FindBoundingBoxHitBy(Line *line);
//##########################################################################
// Test Support
//
public:
Logical
TestInstance() const;
};
//##########################################################################
//######################## BoundingBoxTree ###########################
//##########################################################################
class BoundingBoxTree SIGNATURED
{
//##########################################################################
// Construction and Destruction
//
protected:
BoundingBoxTreeNode *root;
public:
BoundingBoxTree()
{Check_Pointer(this); root = NULL;}
~BoundingBoxTree()
{Check(this); EraseTree();}
static void
SetTraversalOrder(
int first,
int second,
int third
)
{BoundingBoxTreeNode::SetTraversalOrder(first, second, third);}
void
Add(
BoundingBox* volume,
const ExtentBox &extents
);
void
Remove(BoundingBox* volume)
{
Check(this); Check(volume); Check(root);
root->Remove(volume, *volume);
}
void
EraseTree();
//##########################################################################
// Tree Traversal Functions
//
public:
BoundingBox*
FindBoundingBoxContaining(const Point3D &point)
{
Check(this); Check(&point); Check(root);
return root->FindBoundingBoxContaining(point, NULL);
}
BoundingBoxTreeNode*
FindSmallestNodeContaining(const ExtentBox &extents)
{
Check(this); Check(&extents); Check(root);
return root->FindSmallestNodeContaining(extents, NULL);
}
void
FindBoundingBoxesContaining(
BoundingBox *volume,
BoundingBoxCollisionList &list
)
{
Check(this); Check(volume); Check(&list); Check(root);
root->FindBoundingBoxesContaining(
volume,
*volume,
list
);
}
BoundingBoxTreeNode*
FindSmallestNodeContainingColumn(const ExtentBox &extents)
{
Check(this); Check(&extents); Check(root);
Verify((BoundingBoxTreeNode::TraversalOrder[4]>>1) == Y_Axis);
return root->FindSmallestNodeContainingColumn(extents);
}
BoundingBox*
FindBoundingBoxUnder(
const Point3D &point,
Scalar *height
)
{
Check(this); Check(&point); Check(root); Check_Pointer(height);
Verify((BoundingBoxTreeNode::TraversalOrder[4]>>1) == Y_Axis);
return root->FindBoundingBoxUnder(point, height);
}
BoundingBox*
FindBoundingBoxHitBy(Line *line);
//##########################################################################
// Test Support
//
public:
Logical
TestInstance() const;
};
+872
View File
@@ -0,0 +1,872 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "plane.h"
extern Logical
BoxedRampContainsLine(
Line *line,
const Plane& plane,
Scalar enters,
Scalar leaves
);
//#############################################################################
//################# BoxedWedgeFacingNegativeZAndPositiveX ###############
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingNegativeZAndPositiveX::BoxedWedgeFacingNegativeZAndPositiveX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
WedgeFacingNegativeZAndPositiveXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingNegativeZAndPositiveX::~BoxedWedgeFacingNegativeZAndPositiveX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndPositiveX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.maxX - minX;
Scalar z = extents.minZ - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise >= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndPositiveX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise >= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedWedgeFacingNegativeZAndPositiveX::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Calculate the "slope" of the ramp when the NW corner the ramp is placed
// at the origin
//------------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
if (x*rise >= z*run)
{
x = point.y - maxY;
return Max(x,0.0f);
}
return -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndPositiveX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
ramp.normal.x = minZ - maxZ;
ramp.normal.y = 0.0f;
ramp.normal.z = maxX - minX;
//
//-----------------------------
// Scale the vector to a normal
//-----------------------------
//
Scalar temp = ramp.normal.x*ramp.normal.x + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp));
temp = Sqrt(temp);
ramp.normal.x /= temp;
ramp.normal.z /= temp;
ramp.offset = maxX*ramp.normal.x + maxZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndPositiveX::TestInstance() const
{
return solidType == WedgeFacingNegativeZAndPositiveXType;
}
//#############################################################################
//################# BoxedWedgeFacingPositiveZAndNegativeX ###############
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingPositiveZAndNegativeX::BoxedWedgeFacingPositiveZAndNegativeX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
WedgeFacingPositiveZAndNegativeXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingPositiveZAndNegativeX::~BoxedWedgeFacingPositiveZAndNegativeX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndNegativeX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.minX - maxX;
Scalar z = extents.maxZ - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise >= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndNegativeX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise >= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedWedgeFacingPositiveZAndNegativeX::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Calculate the "slope" of the ramp when the NW corner the ramp is placed
// at the origin
//------------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = minZ - maxZ;
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more positive than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run >= z/x yields
// rise*x >= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
if (x*rise >= z*run)
{
x = point.y - maxY;
return Max(x,0.0f);
}
return -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndNegativeX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
ramp.normal.x = maxZ - minZ;
ramp.normal.y = 0.0f;
ramp.normal.z = minX - maxX;
//
//-----------------------------
// Scale the vector to a normal
//-----------------------------
//
Scalar temp = ramp.normal.x*ramp.normal.x + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp));
temp = Sqrt(temp);
ramp.normal.x /= temp;
ramp.normal.z /= temp;
ramp.offset = maxX*ramp.normal.x + maxZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndNegativeX::TestInstance() const
{
return solidType == WedgeFacingPositiveZAndNegativeXType;
}
//#############################################################################
//################# BoxedWedgeFacingPositiveZAndPositiveX ###############
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingPositiveZAndPositiveX::BoxedWedgeFacingPositiveZAndPositiveX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
WedgeFacingPositiveZAndPositiveXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingPositiveZAndPositiveX::~BoxedWedgeFacingPositiveZAndPositiveX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndPositiveX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.maxX - minX;
Scalar z = extents.maxZ - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise <= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndPositiveX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise <= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedWedgeFacingPositiveZAndPositiveX::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Calculate the "slope" of the ramp when the NW corner the ramp is placed
// at the origin
//------------------------------------------------------------------------
//
Scalar run = maxX - minX;
Scalar rise = minZ - maxZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - minX;
Scalar z = point.z - maxZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
if (x*rise <= z*run)
{
x = point.y - maxY;
return Max(x,0.0f);
}
return -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndPositiveX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
ramp.normal.x = minZ - maxZ;
ramp.normal.y = 0.0f;
ramp.normal.z = minX - maxX;
//
//-----------------------------
// Scale the vector to a normal
//-----------------------------
//
Scalar temp = ramp.normal.x*ramp.normal.x + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp));
temp = Sqrt(temp);
ramp.normal.x /= temp;
ramp.normal.z /= temp;
ramp.offset = maxX*ramp.normal.x + minZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingPositiveZAndPositiveX::TestInstance() const
{
return solidType == WedgeFacingPositiveZAndPositiveXType;
}
//#############################################################################
//################# BoxedWedgeFacingNegativeZAndNegativeX ###############
//#############################################################################
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingNegativeZAndNegativeX::BoxedWedgeFacingNegativeZAndNegativeX(
const ExtentBox &extents,
BoxedSolid::Material material,
Simulation *owner,
BoxedSolid *next_solid
):
BoxedSolid(
extents,
WedgeFacingNegativeZAndNegativeXType,
material,
owner,
next_solid
)
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
BoxedWedgeFacingNegativeZAndNegativeX::~BoxedWedgeFacingNegativeZAndNegativeX()
{
Check_Pointer(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndNegativeX::IntersectsBounded(
const ExtentBox &extents
)
{
Check(this);
Check(&extents);
Verify(minX <= extents.minX);
Verify(maxX >= extents.maxX);
Verify(minY <= extents.minY);
Verify(maxY >= extents.maxY);
Verify(minZ <= extents.minZ);
Verify(maxZ >= extents.maxZ);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = extents.minX - maxX;
Scalar z = extents.minZ - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise <= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndNegativeX::ContainsBounded(const Point3D &point)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(maxY >= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//----------------------------------------------------------------------
// Calculate the "slope" of the ramp when the base of the ramp is placed
// at the origin
//----------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
return x*rise <= z*run;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Scalar
BoxedWedgeFacingNegativeZAndNegativeX::FindDistanceBelowBounded(
const Point3D &point
)
{
Check(this);
Check(&point);
Verify(minX <= point.x);
Verify(maxX >= point.x);
Verify(minY <= point.y);
Verify(minZ <= point.z);
Verify(maxZ >= point.z);
//
//------------------------------------------------------------------------
// Calculate the "slope" of the ramp when the NW corner the ramp is placed
// at the origin
//------------------------------------------------------------------------
//
Scalar run = minX - maxX;
Scalar rise = maxZ - minZ;
Verify(!Small_Enough(run));
//
//-------------------------------------------------------------------
// Calculate the "slope" of the line from the base of the ramp to the
// lower-north edge of the block
//-------------------------------------------------------------------
//
Scalar x = point.x - maxX;
Scalar z = point.z - minZ;
//
//------------------------------------------------------------------------
// If the slope rise/run is more negative than z/x slope, then the extent
// box of the disk has clipped the ramp. Note that rise/run <= z/x yields
// rise*x <= z*run, which avoids any divide-by-0 errors.
//------------------------------------------------------------------------
//
if (x*rise <= z*run)
{
x = point.y - maxY;
return Max(x,0.0f);
}
return -1.0f;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndNegativeX::HitByBounded(
Line *line,
Scalar enters,
Scalar leaves
)
{
Plane
ramp;
ramp.normal.x = maxZ - minZ;
ramp.normal.y = 0.0f;
ramp.normal.z = maxX - minX;
//
//-----------------------------
// Scale the vector to a normal
//-----------------------------
//
Scalar temp = ramp.normal.x*ramp.normal.x + ramp.normal.z*ramp.normal.z;
Verify(!Small_Enough(temp));
temp = Sqrt(temp);
ramp.normal.x /= temp;
ramp.normal.z /= temp;
ramp.offset = minX*ramp.normal.x + maxZ*ramp.normal.z;
//
//---------------------------------------------------------------------
// Now that we have added a new plane into the definition of the convex
// polyhedron, call a common ramp line collider
//---------------------------------------------------------------------
//
return BoxedRampContainsLine(line, ramp, enters, leaves);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
BoxedWedgeFacingNegativeZAndNegativeX::TestInstance() const
{
return solidType == WedgeFacingNegativeZAndNegativeXType;
}
+567
View File
@@ -0,0 +1,567 @@
#include "munga.h"
#pragma hdrstop
#include "caminst.h"
#include "notation.h"
//##########################################################################
//############################# CameraInstance #######################
//##########################################################################
//##########################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance::CameraInstance(
int camera_ID,
const Origin &camera_origin,
Enumeration camera_type
)
{
Str_Copy(cameraName, "camera", sizeof(cameraName));
itoa(camera_ID, cameraName+6, 10);
cameraID = camera_ID;
cameraDataType = camera_type;
SetLocalOrigin(camera_origin);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance::CameraInstance(StreamedInstance *model)
{
cameraID = model->cameraID;
localOrigin = model->localOrigin;
cameraToWorld = localOrigin;
cameraDataType = model->cameraType;
for (int i=0; i<4; ++i)
{
clampValues[i] = model->clampValues[i];
}
Str_Copy(cameraName, "camera", sizeof(cameraName));
itoa(cameraID, cameraName+6, 10);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#define READ_CAMERA_ENTRY(name,value)\
if (\
!cam_file->GetEntry(\
camera_page_name,\
name,\
&value\
)\
)\
{ \
DEBUG_STREAM << camera_page_name << " missing " name "!\n" << std::flush;\
Fail("Bad cameras!");\
}
CameraInstance::CameraInstance(
NotationFile *cam_file,
const char *camera_page_name
)
{
Check(this);
Check(cam_file);
Check_Pointer(camera_page_name);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// PageName represents the cameraName
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Str_Copy(cameraName, camera_page_name, sizeof(cameraName));
//
//~~~~~~~~~~~~~~~~~~~~~
// Read in the position
//~~~~~~~~~~~~~~~~~~~~~
//
READ_CAMERA_ENTRY("tranx", localOrigin.linearPosition.x);
READ_CAMERA_ENTRY("trany", localOrigin.linearPosition.y);
READ_CAMERA_ENTRY("tranz", localOrigin.linearPosition.z);
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the Orientation
//~~~~~~~~~~~~~~~~~~~~~~~~
//
READ_CAMERA_ENTRY("quatx", localOrigin.angularPosition.x);
READ_CAMERA_ENTRY("quaty", localOrigin.angularPosition.y);
READ_CAMERA_ENTRY("quatz", localOrigin.angularPosition.z);
READ_CAMERA_ENTRY("quatw", localOrigin.angularPosition.w);
cameraToWorld = localOrigin;
//
//---------------------
// Read in camera clamp
//---------------------
//
clampValues[0] = -PI;
cam_file->GetEntry(
camera_page_name,
"minYawClamp",
&clampValues[0].angle
);
clampValues[1] = PI;
cam_file->GetEntry(
camera_page_name,
"maxYawClamp",
&clampValues[1].angle
);
clampValues[2] = -PI_OVER_2;
cam_file->GetEntry(
camera_page_name,
"minPitchClamp",
&clampValues[2].angle
);
clampValues[3] = PI_OVER_2;
cam_file->GetEntry(
camera_page_name,
"maxPitchClamp",
&clampValues[3].angle
);
//
// Overwrite default cameraID
//
const char *camera_data_entry;
if(
!cam_file->GetEntry(
camera_page_name,
"cameraType",
&camera_data_entry
)
)
{
cameraDataType = DefaultCameraType;
}
else
{
Check_Pointer(camera_data_entry);
cameraDataType = FindCameraType(camera_data_entry);
}
READ_CAMERA_ENTRY("cameraID", cameraID);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance::~CameraInstance()
{
}
//##########################################################################
// Data Access Funtions
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
CameraInstance::FindCameraType(const char *camera_data_type)
{
if(strcmp("DefaultCameraType", camera_data_type) == 0)
{
return DefaultCameraType;
}
else if(strcmp("AlwaysSeesCameraType", camera_data_type) == 0)
{
return AlwaysSeesCameraType;
}
return ErrorCameraType;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::GetCameraTypeString(char *camera_type_string)
{
switch(cameraDataType)
{
case DefaultCameraType:
Str_Copy(
camera_type_string,
"DefaultCameraType",
(sizeof(char) * 128)
);
break;
case AlwaysSeesCameraType:
Str_Copy(
camera_type_string,
"AlwaysSeesCameraType",
(sizeof(char) * 128)
);
break;
default:
Tell(cameraDataType);
Warn(" Invalid cameraType !\n");
break;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::CalculateCameraRotation(
YawPitchRoll *result,
const Point3D &world
)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Given a Vector this function finds a rotation involving only
// pitch and yaw, roll will not be affected. In addition the rotation
// chosed will always be in the direction of least rotation
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(this);
Check(result);
Check(&world);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// find the vector from where we are to where we want to point
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Point3D local;
local.MultiplyByInverse(world, cameraToWorld);
if (Small_Enough(local.LengthSquared()))
{
*result = YawPitchRoll::Identity;
return;
}
//
//~~~~~~~~~~~~~~~~~~~~~
// Calculate the angles
//~~~~~~~~~~~~~~~~~~~~~
//
result->yaw = Radian::Normalize(Arctan(-local.x, -local.z));
Scalar xz_direction = Sqrt((local.x * local.x) + (local.z *local.z));
result->pitch = Radian::Normalize(Arctan(local.y, xz_direction));
result->roll = 0.0f;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::SetLocalOrigin(
const Origin &new_origin
)
{
Check(this);
Check(&new_origin);
YawPitchRoll ypr;
ypr = new_origin.angularPosition;
clampValues[0] = clampValues[1] = 0.0f;
clampValues[2] = clampValues[3] = ypr.pitch;
ypr.pitch = 0.0f;
localOrigin.linearPosition = new_origin.linearPosition;
localOrigin.angularPosition = ypr;
cameraToWorld = localOrigin;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::LookAt(
Origin *result,
const Point3D &world_point
)
{
result->linearPosition = localOrigin.linearPosition;
YawPitchRoll first,local;
first = localOrigin.angularPosition;
CalculateCameraRotation(&local, world_point);
Clamp(local.yaw, clampValues[0], clampValues[1]);
Clamp(local.pitch, clampValues[2], clampValues[3]);
first.yaw += local.yaw;
first.pitch = local.pitch;
result->angularPosition = first;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::AllowLookingAt(const Point3D &world)
{
YawPitchRoll local;
CalculateCameraRotation(&local, world);
if (local.yaw < clampValues[0])
{
clampValues[0] = local.yaw;
}
else if (local.yaw > clampValues[1])
{
clampValues[1] = local.yaw;
}
if (local.pitch < clampValues[2])
{
clampValues[2] = local.pitch;
}
else if (local.pitch > clampValues[3])
{
clampValues[3] = local.pitch;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#define YAW_SLOP (PI/12.0)
#define PITCH_SLOP (0.75*(YAW_SLOP))
Logical
CameraInstance::CanCameraSee(const Point3D &world_point)
{
YawPitchRoll ypr;
CalculateCameraRotation(&ypr, world_point);
return
clampValues[0]-YAW_SLOP <= ypr.yaw
&& clampValues[1]+YAW_SLOP >= ypr.yaw
&& clampValues[2]-PITCH_SLOP <= ypr.pitch
&& clampValues[3]+PITCH_SLOP >= ypr.pitch;
}
//##########################################################################
// Test Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
CameraInstance::TestInstance() const
{
return True;
}
//##########################################################################
// Tool Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstance::WriteNotationPage(NotationFile *camera_stream)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Output this camera's information to the given notation file
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(this);
Check(camera_stream);
camera_stream->SetEntry(
cameraName,
"cameraID",
cameraID
);
char camera_type[128];
GetCameraTypeString(camera_type);
camera_stream->SetEntry(
cameraName,
"cameraType",
camera_type
);
camera_stream->SetEntry(
cameraName,
"tranx",
localOrigin.linearPosition.x
);
camera_stream->SetEntry(
cameraName,
"trany",
localOrigin.linearPosition.y
);
camera_stream->SetEntry(
cameraName,
"tranz",
localOrigin.linearPosition.z
);
camera_stream->SetEntry(
cameraName,
"quatx",
localOrigin.angularPosition.x
);
camera_stream->SetEntry(
cameraName,
"quaty",
localOrigin.angularPosition.y
);
camera_stream->SetEntry(
cameraName,
"quatz",
localOrigin.angularPosition.z
);
camera_stream->SetEntry(
cameraName,
"quatw",
localOrigin.angularPosition.w
);
camera_stream->SetEntry(
cameraName,
"minYawClamp",
clampValues[0]
);
camera_stream->SetEntry(
cameraName,
"maxYawClamp",
clampValues[1]
);
camera_stream->SetEntry(
cameraName,
"minPitchClamp",
clampValues[2]
);
camera_stream->SetEntry(
cameraName,
"maxPitchClamp",
clampValues[3]
);
camera_stream->AppendEntry(cameraName, NULL, (char *)NULL);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#undef READ_CAMERA_ENTRY
#define READ_CAMERA_ENTRY(name,value)\
if (\
!cam_file->GetEntry(\
camera_page_name,\
name,\
&value\
)\
)\
{ \
DEBUG_STREAM << camera_page_name << " missing " name "!\n" << std::flush;\
return False;\
}
Logical
CameraInstance::CreateStreamedInstance(
StreamedInstance *model,
NotationFile *cam_file,
const char *camera_page_name
)
{
Check_Pointer(model);
Check(cam_file);
Check_Pointer(camera_page_name);
//
//~~~~~~~~~~~~~~~~~~~~~
// Read in the position
//~~~~~~~~~~~~~~~~~~~~~
//
READ_CAMERA_ENTRY("tranx", model->localOrigin.linearPosition.x);
READ_CAMERA_ENTRY("trany", model->localOrigin.linearPosition.y);
READ_CAMERA_ENTRY("tranz", model->localOrigin.linearPosition.z);
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// Read in the Orientation
//~~~~~~~~~~~~~~~~~~~~~~~~
//
READ_CAMERA_ENTRY("quatx", model->localOrigin.angularPosition.x);
READ_CAMERA_ENTRY("quaty", model->localOrigin.angularPosition.y);
READ_CAMERA_ENTRY("quatz", model->localOrigin.angularPosition.z);
READ_CAMERA_ENTRY("quatw", model->localOrigin.angularPosition.w);
//
//---------------------
// Read in camera clamp
//---------------------
//
model->clampValues[0] = -PI;
cam_file->GetEntry(
camera_page_name,
"minYawClamp",
&model->clampValues[0].angle
);
model->clampValues[1] = PI;
cam_file->GetEntry(
camera_page_name,
"maxYawClamp",
&model->clampValues[1].angle
);
model->clampValues[2] = -PI_OVER_2;
cam_file->GetEntry(
camera_page_name,
"minPitchClamp",
&model->clampValues[2].angle
);
model->clampValues[3] = PI_OVER_2;
cam_file->GetEntry(
camera_page_name,
"maxPitchClamp",
&model->clampValues[3].angle
);
//
// Overwrite default cameraID
//
const char *camera_data_entry;
if(
!cam_file->GetEntry(
camera_page_name,
"cameraType",
&camera_data_entry
)
)
{
model->cameraType = DefaultCameraType;
}
else
{
Check_Pointer(camera_data_entry);
model->cameraType = FindCameraType(camera_data_entry);
}
READ_CAMERA_ENTRY("cameraID", model->cameraID);
model->instanceSize = sizeof(*model);
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AlwaysSeesCameraInstance::AlwaysSeesCameraInstance(
int camera_ID,
const Origin &camera_origin,
Enumeration camera_type
):
CameraInstance(camera_ID, camera_origin, camera_type)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AlwaysSeesCameraInstance::AlwaysSeesCameraInstance(StreamedInstance *model):
CameraInstance(model)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
AlwaysSeesCameraInstance::AlwaysSeesCameraInstance(
NotationFile *cam_file,
const char *camera_page_name
):
CameraInstance(cam_file, camera_page_name)
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
AlwaysSeesCameraInstance::CanCameraSee(const Point3D &)
{
return True;
}
+173
View File
@@ -0,0 +1,173 @@
#pragma once
#include "plug.h"
#include "origin.h"
#include "rotation.h"
#include "linmtrx.h"
class NotationFile;
struct CameraInstance__StreamedInstance
{
size_t instanceSize;
int
cameraType,
cameraID;
Origin
localOrigin;
Radian
clampValues[4];
};
//##########################################################################
//############################# CameraInstance #######################
//##########################################################################
class CameraInstance :
public Plug
{
friend class CameraInstanceManager;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// local member data
//
public:
enum {
ErrorCameraType,
DefaultCameraType,
AlwaysSeesCameraType,
CameraTypeCount,
};
Radian
clampValues[4];
protected:
Origin
localOrigin;
LinearMatrix
cameraToWorld;
static int
FindCameraType(const char *camera_data_type);
void
GetCameraTypeString(char *camera_type_string);
Enumeration
cameraDataType;
int
cameraID;
char
cameraName[128];
void
CalculateCameraRotation(
YawPitchRoll *result,
const Point3D &world
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// public member data access functions
//
public:
int
GetCameraID()
{Check(this); return cameraID;}
const char*
GetCameraName()
{Check(this); return cameraName;}
void
SetCameraName(const char* camera_name)
{Str_Copy(cameraName, camera_name, sizeof(cameraName));}
const Enumeration
GetCameraType()
{Check(this); return cameraDataType;}
const Origin&
GetLocalOrigin()
{Check(this); return localOrigin;}
void
SetLocalOrigin(const Origin &new_origin);
const Point3D&
GetPosition()
{Check(this); return localOrigin.linearPosition;}
void
LookAt(
Origin *result,
const Point3D &world_point
);
void
AllowLookingAt(const Point3D &world);
virtual Logical
CanCameraSee(const Point3D &world_point);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Class Support
//
public:
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Contruction and Destruction Support
//
public:
typedef CameraInstance__StreamedInstance StreamedInstance;
CameraInstance(
int camera_ID,
const Origin &camera_origin,
Enumeration camera_type = DefaultCameraType
);
CameraInstance(StreamedInstance *model);
CameraInstance(
NotationFile *cam_file,
const char *camera_page_name
);
~CameraInstance();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tool Support
//
public:
void
WriteNotationPage(NotationFile *camera_stream);
static Logical
CreateStreamedInstance(
StreamedInstance *model,
NotationFile *cam_file,
const char *camera_page_name
);
};
//##########################################################################
//############################# CameraInstance #######################
//##########################################################################
class AlwaysSeesCameraInstance :
public CameraInstance
{
public:
AlwaysSeesCameraInstance(
int camera_ID,
const Origin &camera_origin,
Enumeration camera_type = DefaultCameraType
);
AlwaysSeesCameraInstance(StreamedInstance *model);
AlwaysSeesCameraInstance(
NotationFile *cam_file,
const char *camera_page_name
);
Logical
CanCameraSee(const Point3D &world_point);
};
+748
View File
@@ -0,0 +1,748 @@
#include "munga.h"
#pragma hdrstop
#include "cammgr.h"
#include "mission.h"
#include "app.h"
#include "notation.h"
#include "namelist.h"
//##########################################################################
//##################### CameraInstanceManager #######################
//##########################################################################
//##########################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstanceManager::CameraInstanceManager() :
cameraList(NULL)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize local member data
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
cameraIterator = new SChainIteratorOf<CameraInstance*>(cameraList);
Register_Object(cameraIterator);
InitializeCameraInstances();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstanceManager::~CameraInstanceManager()
{
DeleteCameraList();
Unregister_Object(cameraIterator);
delete cameraIterator;
cameraIterator = NULL;
Check_Fpu();
}
//##########################################################################
// CameraInstance Creation and Deletion Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
CameraInstanceManager::FindUniqueCameraID()
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Finds a cameraID that has been freed up or the next sequential number
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
SChainIteratorOf<CameraInstance*> iterator(cameraList);
CameraInstance *camera_instance;
int camera_ID = 0;
Logical ID_exists = False;
while(1)
{
//
//~~~~~~~~~~~~~~~~~~~~
// Reset the iterator
//~~~~~~~~~~~~~~~~~~~~
//
iterator.First();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Iterate through the list of all cameraInstances for every ID Chosen
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
while ( (camera_instance = iterator.ReadAndNext()) != NULL)
{
if(camera_ID == camera_instance->GetCameraID())
{
ID_exists = True;
break;
}
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If this cameraID not already used return the ID
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if(!ID_exists)
{
break;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Otherwise increment the ID and reset the boolean
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
++camera_ID;
ID_exists = False;
}
Check_Fpu();
return camera_ID;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstanceManager::SetCamera(
const Origin &new_origin,
CameraInstance *camera_instance
)
{
if(!camera_instance)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// No camera passed as an argument use cameraIterator
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
camera_instance = cameraIterator->GetCurrent();
if(!camera_instance)
{
CreateCameraInstance(new_origin);
}
else
{
camera_instance->SetLocalOrigin(new_origin);
}
}
else
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Camera passed in set its origin
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
camera_instance->SetLocalOrigin(new_origin);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::CreateCameraInstance(const Origin &new_origin)
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// Find a Unique CameraID
//~~~~~~~~~~~~~~~~~~~~~~~~
//
int camera_ID;
camera_ID = FindUniqueCameraID();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the new cameraInstance
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance *camera_instance =
new CameraInstance(
camera_ID,
new_origin
);
Register_Object(camera_instance);
AddCameraInstance(camera_instance);
Check_Fpu();
return camera_instance;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::AddCameraInstance(CameraInstance *camera_instance)
{
Check(this);
Check(cameraIterator);
Check(&cameraList);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Insert the new Camera Instance into the cameraList
// & Point the cameraIterator to it
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (!cameraIterator->GetCurrent())
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// If nothing in the cameraList create the first element
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
cameraList.Add(camera_instance);
cameraIterator->First();
Tell("Created the First Camera Instance \n");
}
else
{
cameraList.Add(camera_instance);
cameraIterator->Next();
Tell("Created a Camera Instance \n");
}
Check_Fpu();
return camera_instance;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::DeleteCameraInstance()
{
CameraInstance *camera_instance = cameraIterator->GetCurrent();
if(!camera_instance)
{
return NULL;
}
cameraIterator->Remove();
if(!cameraIterator->GetCurrent())
{
cameraIterator->First();
}
Unregister_Object(camera_instance);
delete camera_instance;
return GetCurrent();
}
//##########################################################################
// CameraList Manipulator Functions
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstanceManager::DeleteCameraList()
{
while (cameraIterator->GetCurrent() != NULL)
{
DeleteCameraInstance();
}
}
//##########################################################################
// CameraList Iterator Manipulator Functions
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::IncrementIterator()
{
Check(this);
if (cameraIterator->GetCurrent())
{
Check(cameraIterator);
cameraIterator->ReadAndNext();
if (!cameraIterator->GetCurrent())
{
cameraIterator->First();
}
}
Check_Fpu();
return GetCurrent();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::DecrementIterator()
{
Check(this);
if (cameraIterator->GetCurrent())
{
Check(cameraIterator);
cameraIterator->ReadAndPrevious();
if (!cameraIterator->GetCurrent())
{
cameraIterator->Last();
}
}
Check_Fpu();
return GetCurrent();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::AdvanceIterator(const CameraInstance &camera_instance)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Search for the camera_instance in the cameraList
// Iterator points to camera_instance upon return
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(&camera_instance);
Check(&cameraList);
Check(cameraIterator);
CameraInstance *current_instance;
cameraIterator->First();
while((current_instance = cameraIterator->GetCurrent()) != NULL)
{
if(current_instance == &camera_instance)
{
Check_Fpu();
return current_instance;
}
cameraIterator->Next();
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// camera_instance not found return NULL
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check_Fpu();
return NULL;
}
//##########################################################################
// CameraList Searching and Query Functions
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance*
CameraInstanceManager::FindClosestCamera(const Point3D &point_3D)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Use a Simple distance formula to find closest camera
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Check(this);
CameraInstance *closest_camera = NULL;
Scalar dist_to_goal, min_dist=1e8f;
SChainIteratorOf<CameraInstance*> iterator(cameraList);
CameraInstance *camera_instance;
while ( (camera_instance = iterator.ReadAndNext()) != NULL)
{
Check(camera_instance);
if (camera_instance->CanCameraSee(point_3D))
{
Vector3D v;
v.Subtract(point_3D, camera_instance->GetPosition());
dist_to_goal = v.LengthSquared();
Check_Fpu();
if (dist_to_goal < min_dist)
{
min_dist = dist_to_goal;
closest_camera = camera_instance;
}
}
}
Check_Fpu();
return closest_camera;
}
//##########################################################################
// Test Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
CameraInstanceManager::TestInstance() const
{
return True;
}
//##########################################################################
// Tool Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstanceManager::InitializeCameraInstances()
{
Check(application);
ResourceDescription::ResourceID map_ID;
map_ID = application->GetCurrentMission()->GetMapID();
ResourceFile *res_file;
res_file = application->GetResourceFile();
Check(res_file);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the camera filename from the map name
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription *res = res_file->FindResourceDescription(map_ID);
Check(res);
Str_Copy(
cameraFilename,
"cameras\\",
sizeof(cameraFilename)
);
//
// cam name matches map name
//
Str_Cat(
cameraFilename,
res->resourceName,
sizeof(cameraFilename)
);
//
// trunc cam name to DOS filename size
//
int name_length = strlen(cameraFilename);
if(name_length > 17)
{
cameraFilename[17] = '\0';
}
//
// Add the extension
//
Str_Cat(
cameraFilename,
".cam",
sizeof(cameraFilename)
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// See if the file exists
//~~~~~~~~~~~~~~~~~~~~~~~~
//
std::fstream cam_file;
//cam_file.open(cameraFilename, std::ios::nocreate | std::ios::in | std::ios::out);
// following alternate line created by Ryan Bunker on 1/6/07
cam_file.open(cameraFilename, std::ios::in);
if(cam_file) //NOTE: this appears broken (RB 1/6/07)
{
cam_file.close();
ReadNotationFile();
}
else
{
cam_file.close();
CreateStreamedCameraInstances(res_file, res->resourceName);
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstanceManager::ReadNotationFile()
{
Check(this);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a Notation file out of the camera file
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
NotationFile *cam_file = new NotationFile(cameraFilename);
Register_Object(cam_file);
NameList* camera_namelist = cam_file->MakePageList();
Register_Object(camera_namelist);
NameList::Entry *camera_entry = camera_namelist->GetFirstEntry();
char
camera_page_name[128];
while (camera_entry)
{
Str_Copy(
camera_page_name,
camera_entry->GetName(),
sizeof(camera_page_name)
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create a new camera Instance for this page
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraInstance *camera_instance;
const char *camera_data_entry;
int cam_type;
if(
!cam_file->GetEntry(
camera_page_name,
"cameraType",
&camera_data_entry
)
)
{
cam_type = CameraInstance::DefaultCameraType;
}
else
{
Check_Pointer(camera_data_entry);
cam_type = CameraInstance::FindCameraType(camera_data_entry);
}
switch (cam_type)
{
case CameraInstance::DefaultCameraType:
camera_instance = new CameraInstance(cam_file, camera_page_name);
break;
case CameraInstance::AlwaysSeesCameraType:
camera_instance =
new AlwaysSeesCameraInstance(cam_file, camera_page_name);
break;
}
Register_Object(camera_instance);
AddCameraInstance(camera_instance);
camera_entry = camera_entry->GetNextEntry();
}
Unregister_Object(camera_namelist);
delete camera_namelist;
Unregister_Object(cam_file);
delete cam_file;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#define PAGE_NAME_SIZE 128
void
CameraInstanceManager::CreateStreamedCameraInstances(
ResourceFile *res_file,
const char *map_name
)
{
Check(this);
Check_Pointer(res_file);
Check_Pointer(map_name);
ResourceDescription *res =
res_file->FindResourceDescription(
map_name,
ResourceDescription::CameraStreamResourceType
);
if (!res)
{
Check_Fpu();
return;
}
res->Lock();
MemoryStream camera_stream(res->resourceAddress, res->resourceSize);
int camera_count = *(int*)camera_stream.GetPointer();
camera_stream.AdvancePointer(sizeof(camera_count));
//
//--------------------
// Read in each camera
//--------------------
//
while (camera_count--)
{
Check(&camera_stream);
CameraInstance::StreamedInstance *model =
(CameraInstance::StreamedInstance*)camera_stream.GetPointer();
Check_Pointer(model);
CameraInstance *camera_instance;
switch (model->cameraType)
{
case CameraInstance::DefaultCameraType:
camera_instance = new CameraInstance(model);
break;
case CameraInstance::AlwaysSeesCameraType:
camera_instance = new AlwaysSeesCameraInstance(model);
break;
}
Register_Object(camera_instance);
AddCameraInstance(camera_instance);
camera_stream.AdvancePointer(model->instanceSize);
}
res->Unlock();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraInstanceManager::WriteNotationFile()
{
Check(this);
Check(&cameraList);
NotationFile *camera_stream = new NotationFile();
Register_Object(camera_stream);
if(!camera_stream)
{
Fail("Error Opening Camera File\n");
}
SChainIteratorOf<CameraInstance*> iterator(cameraList);
CameraInstance *camera_instance;
iterator.First();
while ( (camera_instance = iterator.ReadAndNext()) != NULL)
{
camera_instance->WriteNotationPage(camera_stream);
}
camera_stream->WriteFile(cameraFilename);
Unregister_Object(camera_stream);
delete camera_stream;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
#define PAGE_NAME_SIZE 128
ResourceDescription::ResourceID
CameraInstanceManager::CreateCameraInstancesStream(
ResourceFile *resource_file,
const char *camera_name,
const ResourceDirectories *directories
)
{
Check_Pointer(camera_name);
Check_Pointer(directories);
//
//-------------------
// Open the .cam file
//-------------------
//
int length = strlen(camera_name) + strlen(directories->mapDirectory)+ 1;
char *filename = new char[length];
Register_Pointer(filename);
Str_Copy(filename, directories->mapDirectory, length);
strncat(filename, camera_name, strlen(camera_name)-3);
Str_Cat(filename, "cam", length);
NotationFile *camera_notation = new NotationFile(filename);
Register_Object(camera_notation);
if (camera_notation->PageCount() == 0)
{
DEBUG_STREAM << "Missing .cam file" << std::endl << std::flush;
Dump_And_Die:
Unregister_Object(camera_notation);
delete camera_notation;
Unregister_Pointer(filename);
delete[] filename;
return ResourceDescription::NullResourceID;
}
int camera_count = 0;
NameList *pagelist = camera_notation->MakePageList();
Register_Object(pagelist);
NameList::Entry *entry = pagelist->GetFirstEntry();
char page_name[PAGE_NAME_SIZE];
while (entry)
{
++camera_count;
entry = entry->GetNextEntry();
}
size_t array_size =
sizeof(CameraInstance::StreamedInstance) * camera_count * 2;
long *camera_array = new long[(array_size+3) >> 2];
Register_Pointer(camera_array);
MemoryStream camera_stream(camera_array, array_size);
*(int*)camera_stream.GetPointer() = camera_count;
camera_stream.AdvancePointer(sizeof(camera_count));
entry = pagelist->GetFirstEntry();
while (entry)
{
Str_Copy(
page_name,
entry->GetName(),
sizeof(page_name)
);
if(strcmp(page_name, "CameraInfo") == 0)
{
entry = entry->GetNextEntry();
continue;
}
Check(&camera_stream);
CameraInstance::StreamedInstance *model =
(CameraInstance::StreamedInstance*)camera_stream.GetPointer();
Check_Pointer(model);
if (
!CameraInstance::CreateStreamedInstance(
model,
camera_notation,
page_name
)
)
{
Unregister_Pointer(camera_array);
delete[] camera_array;
Unregister_Object(pagelist);
delete pagelist;
goto Dump_And_Die;
}
camera_stream.AdvancePointer(model->instanceSize);
entry = entry->GetNextEntry();
}
//
//-------------------------------
// Write the stream out to disk.
//
Str_Copy(filename, camera_name, length);
filename[strlen(camera_name)-4] = '\0';
ResourceDescription *new_res =
resource_file->AddResource(
filename,
ResourceDescription::CameraStreamResourceType,
1,
ResourceDescription::LoadOnDemandFlag,
camera_array,
camera_stream.GetBytesUsed()
);
Check(new_res);
//-----------
// Free Mem
//
Unregister_Pointer(camera_array);
delete[] camera_array;
Unregister_Pointer(filename);
delete[] filename;
Unregister_Object(camera_notation);
delete camera_notation;
Unregister_Object(pagelist);
delete pagelist;
return new_res->resourceID;
}
+106
View File
@@ -0,0 +1,106 @@
#pragma once
#include "resource.h"
#include "schain.h"
#include "caminst.h"
//##########################################################################
//##################### CameraInstanceManager #######################
//##########################################################################
class CameraInstanceManager SIGNATURED
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// local member data
//
protected:
//
// cameraList is a circular Linked list
// which holds cameraInstances
//
SChainOf<CameraInstance*> cameraList;
//
// CameraIterator holds the current position in the
// camera list for the lifetime of the class
// & == NULL if the list is empty
//
SChainIteratorOf<CameraInstance*> *cameraIterator;
int FindUniqueCameraID();
char cameraFilename[128];
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public Member Manipulation Functions
//
public:
//
// CameraList Manipulator Functions
//
void SetCamera(const Origin &new_origin, CameraInstance *camera_instance = NULL);
CameraInstance* CreateCameraInstance(const Origin &new_origin);
CameraInstance* AddCameraInstance(CameraInstance *camera_instance);
CameraInstance* DeleteCameraInstance();
void DeleteCameraList();
//
// Iterator Manipulator Functions (Circular Chain)
//
CameraInstance* IncrementIterator();
CameraInstance* DecrementIterator();
CameraInstance* AdvanceIterator(const CameraInstance &camera_instance);
CameraInstance* GetCurrent() const
{
Check(this);
return cameraIterator->GetCurrent();
}
CameraInstance* First()
{
Check(this);
Check(cameraIterator->GetCurrent());
cameraIterator->First();
return GetCurrent();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CameraList Searching and Query Functions
//
public:
CameraInstance* FindClosestCamera(const Point3D &point_3D);
CameraInstance* FindClosestCameraShowing(const Point3D *points);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Class Support
//
public:
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction Support
//
public:
CameraInstanceManager();
~CameraInstanceManager();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Tool Support
//
protected:
void InitializeCameraInstances();
public:
void ReadNotationFile();
void CreateStreamedCameraInstances(ResourceFile *res_file, const char *map_name);
void WriteNotationFile();
static ResourceDescription::ResourceID CreateCameraInstancesStream(ResourceFile *resource_file, const char *camera_name, const ResourceDirectories *directories);
};
+244
View File
@@ -0,0 +1,244 @@
#include "munga.h"
#pragma hdrstop
#include "cammppr.h"
//#############################################################################
// Shared Data Support
//
CameraControlsMapper::SharedData
CameraControlsMapper::DefaultData(
CameraControlsMapper::GetClassDerivations(),
CameraControlsMapper::GetMessageHandlers(),
CameraControlsMapper::GetAttributeIndex(),
CameraControlsMapper::StateCount
);
Derivation* CameraControlsMapper::GetClassDerivations()
{
static Derivation classDerivations(Subsystem::GetClassDerivations(), "CameraControlsMapper");
return &classDerivations;
}
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
CameraControlsMapper::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(CameraControlsMapper, Keypress),
MESSAGE_ENTRY(CameraControlsMapper, DirectorMode),
MESSAGE_ENTRY(CameraControlsMapper, IncrementCamera),
MESSAGE_ENTRY(CameraControlsMapper, DecrementCamera),
MESSAGE_ENTRY(CameraControlsMapper, CreateCameraInstance),
MESSAGE_ENTRY(CameraControlsMapper, DeleteCameraInstance),
MESSAGE_ENTRY(CameraControlsMapper, OutputCameraInstances)
};
CameraControlsMapper::MessageHandlerSet& CameraControlsMapper::GetMessageHandlers()
{
static CameraControlsMapper::MessageHandlerSet messageHandlers(ELEMENTS(CameraControlsMapper::MessageHandlerEntries), CameraControlsMapper::MessageHandlerEntries, Subsystem::GetMessageHandlers());
return messageHandlers;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::KeypressMessageHandler(
ReceiverDataMessageOf<ControlsKey> *message
)
{
Check(this);
Check(message);
switch (message->dataContents)
{
case 'd':
case 'D':
{
ReceiverDataMessageOf<ControlsButton>
button_message2(
CameraControlsMapper::DirectorModeMessageID,
sizeof(ReceiverDataMessageOf<ControlsButton>),
1
);
Dispatch(&button_message2);
break;
}
case 'o':
case 'O':
{
ReceiverDataMessageOf<ControlsButton>
button_message2(
CameraControlsMapper::OutputCameraInstancesMessageID,
sizeof(ReceiverDataMessageOf<ControlsButton>),
1
);
Dispatch(&button_message2);
break;
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::DirectorModeMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
if(camera->GetSimulationState() != CameraShip::ConfigureCamerasState)
{
camera->SetPerformance(&CameraShip::DriveCamera);
camera->SetSimulationState(CameraShip::ConfigureCamerasState);
CameraInstance *cam = camera->GetCurrentCamera();
Check(cam);
//DEBUG_STREAM << cam->GetCameraName() << std::endl << std::flush;
}
else
{
camera->SetPerformance(&CameraShip::FollowGoal);
camera->SetSimulationState(CameraShip::DefaultState);
camera->lastSwitch = Now();
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::IncrementCameraMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if(message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
camera->IncrementCameraInstance();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::DecrementCameraMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
camera->DecrementCameraInstance();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::CreateCameraInstanceMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
camera->CreateCameraInstance();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::DeleteCameraInstanceMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
camera->DeleteCameraInstance();
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraControlsMapper::OutputCameraInstancesMessageHandler(
ReceiverDataMessageOf<ControlsButton> *message
)
{
if (message->dataContents > 0)
{
CameraShip *camera = GetEntity();
Check(camera);
camera->OutputCameraList();
}
}
//#############################################################################
// Attribute Support
//
const CameraControlsMapper::IndexEntry
CameraControlsMapper::AttributePointers[]=
{
ATTRIBUTE_ENTRY(CameraControlsMapper, StickPosition, stickPosition),
ATTRIBUTE_ENTRY(CameraControlsMapper, ThrottlePosition, throttlePosition),
ATTRIBUTE_ENTRY(CameraControlsMapper, PedalsPosition, pedalsPosition),
ATTRIBUTE_ENTRY(CameraControlsMapper, ReverseThrust, reverseThrust),
ATTRIBUTE_ENTRY(CameraControlsMapper, DriveCamera, driveCamera),
ATTRIBUTE_ENTRY(CameraControlsMapper, SlideOrClamp, slideOrClamp)
};
CameraControlsMapper::AttributeIndexSet& CameraControlsMapper::GetAttributeIndex()
{
static CameraControlsMapper::AttributeIndexSet attributeIndex(ELEMENTS(CameraControlsMapper::AttributePointers),
CameraControlsMapper::AttributePointers,
Subsystem::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraControlsMapper::CameraControlsMapper(
CameraShip *owner,
int subsystem_ID,
SubsystemResource *subsystem_resource,
SharedData &shared_data
):
Subsystem(owner, subsystem_ID, subsystem_resource, shared_data)
{
stickPosition.x = 0.0f;
stickPosition.y = 0.0f;
throttlePosition = 0.0f;
pedalsPosition = 0.0f;
driveCamera = 0;
slideOrClamp = 0;
reverseThrust = 0;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraControlsMapper::~CameraControlsMapper()
{
}
Logical
CameraControlsMapper::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+110
View File
@@ -0,0 +1,110 @@
#pragma once
#include "subsystm.h"
#include "camship.h"
#include "controls.h"
//##########################################################################
//####################### CameraControlsMapper ########################
//##########################################################################
class CameraControlsMapper : public Subsystem
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Messaging Support
//
public:
enum
{
KeypressMessageID = Subsystem::NextMessageID,
DirectorModeMessageID,
IncrementCameraMessageID,
DecrementCameraMessageID,
CreateCameraInstanceMessageID,
DeleteCameraInstanceMessageID,
OutputCameraInstancesMessageID,
NextMessageID
};
void KeypressMessageHandler(ReceiverDataMessageOf<ControlsKey> *message);
void DirectorModeMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
void IncrementCameraMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
void DecrementCameraMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
void CreateCameraInstanceMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
void DeleteCameraInstanceMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
void OutputCameraInstancesMessageHandler(ReceiverDataMessageOf<ControlsButton> *message);
protected:
static const HandlerEntry MessageHandlerEntries[];
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
enum
{
StickPositionAttributeID = Subsystem::NextAttributeID,
ThrottlePositionAttributeID,
PedalsPositionAttributeID,
ReverseThrustAttributeID,
DriveCameraAttributeID,
SlideOrClampAttributeID,
NextAttributeID
};
private:
static const IndexEntry AttributePointers[];
protected:
//static AttributeIndexSet AttributeIndex
static AttributeIndexSet& GetAttributeIndex();
//
// public attribute declarations go here
//
public:
ControlsJoystick stickPosition;
Scalar throttlePosition;
Scalar pedalsPosition;
ControlsButton reverseThrust;
ControlsButton driveCamera;
ControlsButton slideOrClamp;
//##########################################################################
// Model support
//
public:
CameraShip* GetEntity() { return (CameraShip*)Subsystem::GetEntity(); }
typedef void (CameraControlsMapper::*Performance)(Scalar time_slice);
void SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
protected:
CameraControlsMapper(CameraShip *owner, int subsystem_ID, SubsystemResource *subsystem_resource, SharedData &shared_data);
public:
~CameraControlsMapper();
Logical TestInstance() const;
};
+732
View File
@@ -0,0 +1,732 @@
#include "munga.h"
#pragma hdrstop
#include "camship.h"
#include "player.h"
#include "mission.h"
#include "cammppr.h"
#include "app.h"
#include "hostmgr.h"
//##########################################################################
//############################# CameraShip ################################
//##########################################################################
//#############################################################################
// Shared Data Support
//
Derivation* CameraShip::GetClassDerivations()
{ static Derivation classDerivations(Mover::GetClassDerivations(), "CameraShip");
return &classDerivations;
}
CameraShip::SharedData
CameraShip::DefaultData(
CameraShip::GetClassDerivations(),
CameraShip::MessageHandlers,
CameraShip::GetAttributeIndex(),
CameraShip::StateCount,
(Entity::MakeHandler)CameraShip::Make
);
//#############################################################################
// Attribute Support
//
const CameraShip::IndexEntry
CameraShip::AttributePointers[]=
{
ATTRIBUTE_ENTRY(CameraShip, MapRange, mapRange),
ATTRIBUTE_ENTRY(CameraShip, MapLinearPosition, mapLinearPosition),
ATTRIBUTE_ENTRY(CameraShip, MapAngularPosition, mapAngularPosition)
};
CameraShip::AttributeIndexSet& CameraShip::GetAttributeIndex()
{
static CameraShip::AttributeIndexSet attributeIndex(ELEMENTS(CameraShip::AttributePointers),
CameraShip::AttributePointers,
Mover::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
CameraShip::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(CameraShip, Direction)
};
CameraShip::MessageHandlerSet
CameraShip::MessageHandlers(
ELEMENTS(CameraShip::MessageHandlerEntries),
CameraShip::MessageHandlerEntries,
Entity::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DirectionMessageHandler(DirectionMessage *message)
{
Check(this);
Check(message);
Check(application);
HostManager *host = application->GetHostManager();
Check(host);
SetGoalEntity(host->GetEntityPointer(message->goalEntity));
Check(goalEntity);
mapLinearPosition = &goalEntity->localOrigin.linearPosition;
focusOffset = message->focusOffset;
SetSimulationState(DefaultState);
timeOnCamera = message->timeOnCamera;
lastSwitch = Now();
lastSwitch -= timeOnCamera;
Check_Fpu();
}
//#############################################################################
// ControlsMapper Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::SetMappingSubsystem(CameraControlsMapper *mapper)
{
Check(this);
Check(mapper);
if(subsystemArray[ControlsMapperSubsystem])
{
Unregister_Object(subsystemArray[ControlsMapperSubsystem]);
delete subsystemArray[ControlsMapperSubsystem];
}
subsystemArray[ControlsMapperSubsystem] = mapper;
Check_Fpu();
}
//#############################################################################
// Simulation Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DriveCamera(Scalar time_slice)
{
Check(this);
CameraControlsMapper* controls =
Cast_Object(
CameraControlsMapper*,
GetSubsystem(CameraShip::ControlsMapperSubsystem)
);
Check(controls);
//
//-----------------------------------------------
// If we are in positioning mode, move the camera
//-----------------------------------------------
//
if (controls->driveCamera > 0)
{
ApplyControlledPanAndTilt(controls, time_slice);
ApplyControlledCameraMotion(controls, time_slice);
ApplyControlledCameraHeight(controls);
currentCamera->SetLocalOrigin(localOrigin);
}
//
//------------------------------------------------------------------------
// Operate in camera mode, obeying the limits of the camera as established
// by the clamps
//------------------------------------------------------------------------
//
else
{
//
//-------------------------
// Stop any existing motion
//-------------------------
//
worldLinearVelocity = Vector3D::Identity;
//
//-----------------------------------------------------------------------
// Read the controls for panning the camera, and if the clamp override is
// on, tell the camera to allow this orientation
//-----------------------------------------------------------------------
//
ApplyControlledPanAndTilt(controls, time_slice);
localToWorld = localOrigin;
//
//---------------------------------------------------------------------
// Establish an aim point along negative Z and figure out where that is
// in world space, then point the camera there. The camera clamps will
// automatically do their thing
//---------------------------------------------------------------------
//
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
if (controls->slideOrClamp > 0)
{
currentCamera->AllowLookingAt(world_aim);
}
AimCameraAtPoint(world_aim);
}
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledPanAndTilt(
CameraControlsMapper *controls,
Scalar time_slice
)
{
Check(this);
Check(controls);
//
//-----------------------------------------
// Point the Camera in the direction of the
// Joystick Position Calc Pitch and Yaw only
//-----------------------------------------
//
Scalar rotation_amount;
if(controls->stickPosition.x < -0.02f)
{
rotation_amount = controls->stickPosition.x + 0.02f;
rotation_amount *= rotation_amount;
rotation_amount *= -1.0f;
}
else if (controls->stickPosition.x > 0.02f)
{
rotation_amount = controls->stickPosition.x - 0.02f;
rotation_amount *= rotation_amount;
}
else
{
rotation_amount = 0.0f;
}
YawPitchRoll ypr;
ypr = localOrigin.angularPosition;
ypr.yaw += rotation_amount * PI * time_slice;
ypr.pitch += controls->stickPosition.y * PI * 0.2f * time_slice;
localOrigin.angularPosition = ypr;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledCameraHeight(CameraControlsMapper *controls)
{
Check(this);
Check(controls);
//
//----------------------------------------------------
// Raise and lower the cameraShip according to the pedals
//----------------------------------------------------
//
localOrigin.linearPosition.y += controls->pedalsPosition;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::ApplyControlledCameraMotion(
CameraControlsMapper *controls,
Scalar time_slice
)
{
Check(this);
Check(controls);
localAcceleration.linearMotion.z =
-25.0f * controls->throttlePosition * time_slice;
if (controls->reverseThrust > 0)
{
localAcceleration.linearMotion.z = -localAcceleration.linearMotion.z;
}
//
//~~~~~~~~~~~~~~~~~~~
// Apply Linear Drag
//~~~~~~~~~~~~~~~~~~~
//
Vector3D drag_force;
drag_force.Multiply(
localVelocity.linearMotion,
positiveLinearDragCoefficients
);
Vector3D new_accel;
new_accel.Subtract(
localAcceleration.linearMotion,
drag_force
);
localAcceleration.linearMotion = new_accel;
//
//~~~~~~~~~~~~~~~~~~~~~~~~
// ApplyWorldAccelerations
//~~~~~~~~~~~~~~~~~~~~~~~~
localVelocity.linearMotion += localAcceleration.linearMotion;
worldLinearVelocity.Multiply(
localVelocity.linearMotion,
localToWorld
);
localOrigin.linearPosition += worldLinearVelocity;
Check_Fpu();
}
//#############################################################################
// Follow GoalEntity Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::FollowGoal(Scalar time_slice)
{
Check(this);
//
//-----------------------------------------------
// If no goalEntity assigned ask for one and wait
//-----------------------------------------------
//
if (!goalEntity)
{
return;
}
Check(goalEntity);
Point3D target;
target.Multiply(focusOffset, goalEntity->localToWorld);
//
//------------------------------------------------------------------------
// If time has not yet expired on this camera, keep with it if can see the
// goal entity
//------------------------------------------------------------------------
//
Check(currentCamera);
if (
lastPerformance - lastSwitch > timeOnCamera
|| !currentCamera->CanCameraSee(target)
)
{
CameraInstance *old_camera = currentCamera;
GoToClosestCamera(target);
if (!currentCamera)
{
currentCamera = old_camera;
}
Check(currentCamera);
//
//------------------------------------------------------------------------
// If we need to switch cameras, have the new camera point directly at the
// target
//------------------------------------------------------------------------
//
if (currentCamera != old_camera)
{
AimCameraAtPoint(target);
lastSwitch = lastPerformance;
}
else
{
goto Rotate_Camera;
}
}
//
//---------------------------------------------------
// Otherwise, rotate the camera as needed and allowed
//---------------------------------------------------
//
else
{
Rotate_Camera:
RotateCameraToPoint(time_slice, target);
}
//
//------------------------
// Set the tranform matrix
//------------------------
//
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::GoToClosestCamera(const Point3D &point_3D)
{
Check(this);
currentCamera = cameraManager.FindClosestCamera(point_3D);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::AimCameraAtPoint(const Point3D &point_3D)
{
Check(this);
Check(currentCamera);
currentCamera->LookAt(&localOrigin, point_3D);
localVelocity.angularMotion = Vector3D::Identity;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::RotateCameraToPoint(
Scalar time_slice,
const Point3D &point_3D
)
{
Check(this);
Check(currentCamera);
Check(&point_3D);
//
//---------------------------------------------------------
// Calculate the rotation needed to point to the goalEntity
//---------------------------------------------------------
//
Origin target;
currentCamera->LookAt(&target, point_3D);
YawPitchRoll new_yaw_pitch_roll;
new_yaw_pitch_roll = target.angularPosition;
Vector3D new_pos(new_yaw_pitch_roll.pitch, new_yaw_pitch_roll.yaw, 0.0f);
YawPitchRoll old_pos_euler;
old_pos_euler = localOrigin.angularPosition;
Vector3D old_pos(old_pos_euler.pitch, old_pos_euler.yaw, 0.0f);
old_pos.x = Radian::Normalize(old_pos.x);
old_pos.y = Radian::Normalize(old_pos.y);
//
// new - old position
//
if (new_pos.x-old_pos.x > PI) {
new_pos.x -= TWO_PI;
}
else if (new_pos.x-old_pos.x < -PI) {
new_pos.x += TWO_PI;
}
if (new_pos.y-old_pos.y > PI) {
new_pos.y -= TWO_PI;
}
else if (new_pos.y-old_pos.y < -PI) {
new_pos.y += TWO_PI;
}
Vector3D delta_rot;
delta_rot.Subtract(
new_pos,
old_pos
);
//
//-------------------
// Apply Angular Drag
//-------------------
//
Vector3D
drag;
drag.Multiply(
localVelocity.angularMotion,
angularDragCoefficients
);
//
//~~~~~~~~~~~~~~~~~~~~~
// Apply SpringConstant
//~~~~~~~~~~~~~~~~~~~~~
//
Vector3D
delta_rot_spring;
delta_rot_spring.Multiply(
delta_rot,
elasticityCoefficient
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Calculate the new angular acceleration
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
localAcceleration.angularMotion.Subtract(
delta_rot_spring,
drag
);
Scalar halft_squared = 0.5 *(time_slice * time_slice);
Vector3D
accel_comp;
accel_comp.Multiply(
localAcceleration.angularMotion,
halft_squared
);
//
// velocity * delta time
//
Vector3D
scaled_velocity;
scaled_velocity.Multiply(
localVelocity.angularMotion,
time_slice
);
Vector3D
tmp_position;
tmp_position.Add(
scaled_velocity,
accel_comp
);
Vector3D
clamped_accel;
clamped_accel.Add(
old_pos,
tmp_position
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Apply Acceleration to angular Position
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
YawPitchRoll
new_yawpitchroll(clamped_accel.y, clamped_accel.x, clamped_accel.z);
LinearMatrix
rot_matrix(LinearMatrix::Identity);
rot_matrix = new_yawpitchroll;
localOrigin.angularPosition = rot_matrix;
//
// Calc new Velocity
//
Vector3D
scaled_accel;
scaled_accel.Multiply(
localAcceleration.angularMotion,
time_slice
);
Vector3D
ang_vel;
ang_vel.Add(
localVelocity.angularMotion,
scaled_accel
);
localVelocity.angularMotion = ang_vel;
Check_Fpu();
}
//#############################################################################
// CameraInstanceManager Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::CreateCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.CreateCameraInstance(localOrigin);
DEBUG_STREAM << currentCamera->GetCameraName() << std::endl << std::flush;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DeleteCameraInstance()
{
Check(this);
//
//---------------------------------------------
// If this is the last camera, don't delete it!
//---------------------------------------------
//
Check(&cameraManager);
CameraInstance *next_camera = cameraManager.IncrementIterator();
if (next_camera == currentCamera)
{
return;
}
currentCamera = cameraManager.DeleteCameraInstance();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << std::endl << std::flush;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::IncrementCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.IncrementIterator();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << std::endl << std::flush;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraShip::DecrementCameraInstance()
{
Check(this);
Check(&cameraManager);
currentCamera = cameraManager.DecrementIterator();
Check(currentCamera);
DEBUG_STREAM << currentCamera->GetCameraName() << std::endl << std::flush;
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
Check_Fpu();
}
//#############################################################################
// Motion Support Functions
//
//#############################################################################
// Construction and Destruction Support
//
CameraShip::CameraShip(
CameraShip::MakeMessage *creation_message,
CameraShip::SharedData &virtual_data
):
Mover(creation_message, virtual_data)
{
SetValidFlag();
if (GetInstance() == ReplicantInstance)
{
return;
}
//
//----------------------------
// Initialize local variables
//----------------------------
//
goalEntity = NULL;
localOrigin = Origin::Identity;
focusOffset = Vector3D::Identity;
//
//------------------------------
// Initialize attributes
//------------------------------
//
mapRange = 1000.0; // number of meters across display
mapLinearPosition = NULL; // force nav display to use object's lin. pos
mapAngularPosition = NULL; // force nav display to not turn or tilt
//
//------------------------------
// Initialize the subsystemArray
//------------------------------
//
subsystemCount = BasicSubsystemCount;
Verify(!subsystemArray);
subsystemArray = new (Subsystem (*[subsystemCount]));
Register_Pointer(subsystemArray);
subsystemArray[ControlsMapperSubsystem] = NULL;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Initialize the camera's viewpoint to the first camera
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
currentCamera = cameraManager.GetCurrent();
if (!currentCamera)
{
CreateCameraInstance();
}
Check(currentCamera);
localOrigin = currentCamera->GetLocalOrigin();
localToWorld = localOrigin;
Point3D local_aim(0.0f, 0.0f, -1.0f);
Point3D world_aim;
world_aim.Multiply(local_aim, localToWorld);
AimCameraAtPoint(world_aim);
localToWorld = localOrigin;
lastSwitch = Now();
timeOnCamera = 0.0f;
SetPerformance(&CameraShip::FollowGoal);
SetSimulationState(DefaultState);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraShip*
CameraShip::Make(MakeMessage *creation_message)
{
return new CameraShip(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraShip::~CameraShip()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
CameraShip::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+202
View File
@@ -0,0 +1,202 @@
#pragma once
#include "mover.h"
#include "cammgr.h"
class CameraControlsMapper;
//##########################################################################
//############### CameraShip::DirectionMessage #################
//##########################################################################
class CameraShip__DirectionMessage : public Mover::Message
{
public:
EntityID goalEntity;
Scalar timeOnCamera;
Point3D focusOffset;
CameraShip__DirectionMessage(Receiver::MessageID message_ID, size_t length, const EntityID& goal_entity, Scalar time_on_camera, const Point3D& focus) : Entity::Message(message_ID, length), goalEntity(goal_entity), timeOnCamera(time_on_camera), focusOffset(focus) {}
};
//##########################################################################
//############################# CameraShip ################################
//##########################################################################
class CameraShip : public Mover
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Messaging support
//
protected:
static const HandlerEntry MessageHandlerEntries[];
static MessageHandlerSet MessageHandlers;
public:
enum
{
DirectionMessageID = Entity::NextMessageID,
NextMessageID
};
typedef CameraShip__DirectionMessage DirectionMessage;
void DirectionMessageHandler(DirectionMessage *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
enum
{
MapRangeAttributeID = Mover::NextAttributeID,
MapLinearPositionAttributeID,
MapAngularPositionAttributeID,
NextAttributeID
};
private:
static const IndexEntry AttributePointers[];
protected:
//static AttributeIndexSet AttributeIndex
static AttributeIndexSet& GetAttributeIndex();
public:
Scalar mapRange;
Point3D *mapLinearPosition; // pointer to linear position of object or NULL
Quaternion *mapAngularPosition; // pointer to angular position of object or NULL
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model support
//
public:
enum
{
ControlsMapperSubsystem,
BasicSubsystemCount
};
void SetMappingSubsystem(CameraControlsMapper *mapper);
//
// Various States of the CameraShip
//
enum
{
ConfigureCamerasState = Mover::StateCount,
StateCount
};
typedef void (CameraShip::*Performance)(Scalar time_slice);
void SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void FollowGoal(Scalar time_slice);
void DriveCamera(Scalar time_slice);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Flag Support
//
public:
enum
{
DefaultFlags = Mover::DefaultFlags | NoCollisionVolumeFlag | NoCollisionTestFlag | InitialStasisFlag
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
static CameraShip* Make(MakeMessage *creation_message);
CameraShip(MakeMessage *creation_message, SharedData &virtual_data = DefaultData);
~CameraShip();
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public Data and Member Access Functions
//
public:
void SetGoalEntity(Entity *goal_entity)
{
Check(this);
Check(goal_entity);
goalEntity = goal_entity;
}
Entity* GetGoalEntity()
{
Check(this);
return goalEntity;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Member Data
//
public:
void GoToClosestCamera(const Point3D &point_3D);
CameraInstance* GetCurrentCamera()
{
Check(this);
return currentCamera;
}
Time lastSwitch;
Scalar timeOnCamera;
protected:
CameraInstanceManager cameraManager;
Entity *goalEntity;
CameraInstance *currentCamera;
Point3D focusOffset;
void MoveCameraShip(CameraInstance *camera_instance);
void AimCameraAtPoint(const Point3D &point_3D);
void RotateCameraToPoint(Scalar time_slice, const Point3D &point_3D);
//
// Camera Motion Support
//
public:
void ResetMotionVariables()
{
Check(this);
localVelocity = Motion::Identity;
localAcceleration = Motion::Identity;
worldLinearVelocity = Vector3D::Identity;
worldLinearAcceleration = Vector3D::Identity;
}
protected:
void ApplyControlledPanAndTilt(CameraControlsMapper *controls, Scalar time_slice);
void ApplyControlledCameraHeight(CameraControlsMapper *controls);
void ApplyControlledCameraMotion(CameraControlsMapper *controls, Scalar time_slice);
//
// Camera Manager Support
//
public:
void CreateCameraInstance();
void DeleteCameraInstance();
void IncrementCameraInstance();
void DecrementCameraInstance();
public:
void OutputCameraList() { cameraManager.WriteNotationFile(); }
};
+451
View File
@@ -0,0 +1,451 @@
#include "munga.h"
#pragma hdrstop
#include "chain.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ChainLink ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
MemoryBlock *ChainLink::GetAllocatedMemory()
{
static MemoryBlock allocatedMemory(sizeof(ChainLink), CHAINLINK_MEMORYBLOCK_ALLOCATION, CHAINLINK_MEMORYBLOCK_ALLOCATION, "ChainLink");
return &allocatedMemory;
}
//
//#############################################################################
// ChainLink
//#############################################################################
//
ChainLink::ChainLink(
Chain *chain,
Plug *plug,
ChainLink *next_link,
ChainLink *prev_link
):
Link(chain, plug)
{
//
//-------------------------
// Link into existing chain
//-------------------------
//
if ((nextChainLink = next_link) != NULL)
{
Check(nextChainLink);
nextChainLink->prevChainLink = this;
}
if ((prevChainLink = prev_link) != NULL)
{
Check(prevChainLink);
prevChainLink->nextChainLink = this;
}
}
//
//#############################################################################
// ~ChainLink
//#############################################################################
//
ChainLink::~ChainLink()
{
Chain *chain = Cast_Object(Chain*, socket);
//
//--------------------------------------
// Remove this link from the linked list
//--------------------------------------
//
if (prevChainLink != NULL)
{
Check(prevChainLink);
prevChainLink->nextChainLink = nextChainLink;
}
else
{
Check(chain);
chain->head = nextChainLink;
}
if (nextChainLink != NULL)
{
Check(nextChainLink);
nextChainLink->prevChainLink = prevChainLink;
}
else
{
Check(chain);
chain->tail = prevChainLink;
}
prevChainLink = nextChainLink = NULL;
//
//------------------------------------------
// Remove this link from any plug references
//------------------------------------------
//
ReleaseFromPlug();
//
//-------------------------------------------------------------
// Tell the node to release this link. Note that this link
// is not referenced by the plug or the chain at this point in
// time.
//-------------------------------------------------------------
//
if (chain->GetReleaseNode() != NULL)
{
Check(chain->GetReleaseNode());
chain->GetReleaseNode()->ReleaseLinkHandler(chain, plug);
}
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
ChainLink::TestInstance() const
{
Link::TestInstance();
if (prevChainLink != NULL)
{
Check_Signature(prevChainLink);
}
if (nextChainLink != NULL)
{
Check_Signature(nextChainLink);
}
return( True );
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Chain ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
// Chain
//#############################################################################
//
Chain::Chain(Node *node):
Socket(node)
{
head = NULL;
tail = NULL;
}
//
//#############################################################################
// ~Chain
//#############################################################################
//
Chain::~Chain()
{
SetReleaseNode(NULL);
while (head != NULL)
{
Unregister_Object(head);
delete head;
}
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
Chain::TestInstance() const
{
Socket::TestInstance();
if (head != NULL)
{
Check(head);
}
if (tail != NULL)
{
Check(tail);
}
return True;
}
//
//#############################################################################
// AddImplementation
//#############################################################################
//
void
Chain::AddImplementation(Plug *plug)
{
Check(this);
tail = new ChainLink(this, plug, NULL, tail);
Register_Object(tail);
if (head == NULL)
{
head = tail;
}
}
//
//#############################################################################
// InsertChainLink
//#############################################################################
//
ChainLink*
Chain::InsertChainLink(
Plug *plug,
ChainLink *current_link
)
{
Check(this);
Check(plug);
Check(current_link);
ChainLink *new_link =
new ChainLink(
this,
plug,
current_link,
current_link->prevChainLink
);
Register_Object(new_link);
Check(head);
if (head == current_link)
{
head = new_link;
}
return new_link;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ChainIterator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//#############################################################################
// ChainIterator
//#############################################################################
//
ChainIterator::ChainIterator(Chain *chain):
SocketIterator(chain)
{
Check(chain);
currentLink = chain->head;
}
ChainIterator::ChainIterator(const ChainIterator &iterator):
SocketIterator(Cast_Object(Chain*, iterator.socket))
{
Check(&iterator);
currentLink = iterator.currentLink;
}
ChainIterator::~ChainIterator()
{
}
//
//###########################################################################
// TestInstance
//###########################################################################
//
Logical
ChainIterator::TestInstance() const
{
SocketIterator::TestInstance();
if (currentLink != NULL)
{
Check( currentLink );
}
return(True);
}
//
//###########################################################################
// First
//###########################################################################
//
void
ChainIterator::First()
{
currentLink = Cast_Object(Chain*, socket)->head;
}
//
//###########################################################################
// Last
//###########################################################################
//
void
ChainIterator::Last()
{
currentLink = Cast_Object(Chain*, socket)->tail;
}
//
//###########################################################################
// Next
//###########################################################################
//
void
ChainIterator::Next()
{
Check(currentLink);
currentLink = currentLink->nextChainLink;
}
//
//###########################################################################
// Previous
//###########################################################################
//
void
ChainIterator::Previous()
{
Check( currentLink );
currentLink = currentLink->prevChainLink;
}
//
//###########################################################################
// ReadAndNextImplementation
//###########################################################################
//
void*
ChainIterator::ReadAndNextImplementation()
{
if (currentLink != NULL)
{
Plug *plug;
Check(currentLink);
plug = currentLink->plug;
currentLink = currentLink->nextChainLink;
return plug;
}
return NULL;
}
//
//###########################################################################
// ReadAndPreviousImplementation
//###########################################################################
//
void*
ChainIterator::ReadAndPreviousImplementation()
{
if (currentLink != NULL)
{
Plug *plug;
Check(currentLink);
plug = currentLink->plug;
currentLink = currentLink->prevChainLink;
return plug;
}
return NULL;
}
//
//###########################################################################
// GetCurrentImplementation
//###########################################################################
//
void*
ChainIterator::GetCurrentImplementation()
{
if (currentLink != NULL)
{
Check(currentLink);
return currentLink->plug;
}
return NULL;
}
//
//###########################################################################
// GetSize
//###########################################################################
//
CollectionSize
ChainIterator::GetSize()
{
ChainLink *link;
CollectionSize count;
count = 0;
for (
link = Cast_Object(Chain*, socket)->head;
link != NULL;
link = link->nextChainLink
) {
Check(link);
count++;
}
return count;
}
//
//###########################################################################
// GetNthImplementation
//###########################################################################
//
void*
ChainIterator::GetNthImplementation(CollectionSize index)
{
ChainLink *link;
CollectionSize count;
count = 0;
for (
link = Cast_Object(Chain*, socket)->head;
link != NULL;
link = link->nextChainLink
) {
Check(link);
if (count == index) {
currentLink = link;
return currentLink->plug;
}
count++;
}
return NULL;
}
//
//###########################################################################
// Remove
//###########################################################################
//
void
ChainIterator::Remove()
{
ChainLink *oldLink = currentLink;
Check(currentLink);
currentLink = currentLink->nextChainLink;
Unregister_Object(oldLink);
delete oldLink ;
}
//
//###########################################################################
// InsertImplementation
//###########################################################################
//
void
ChainIterator::InsertImplementation(Plug *plug)
{
currentLink =
Cast_Object(Chain*, socket)->InsertChainLink(plug, currentLink);
Check(currentLink);
}
#ifdef TEST_CLASS
# include "chain.tcp"
#endif
+157
View File
@@ -0,0 +1,157 @@
#pragma once
#include "node.h"
#include "memblock.h"
class Chain;
class ChainIterator;
#define CHAINLINK_MEMORYBLOCK_ALLOCATION (100)
class ChainLink : public Link
{
friend class Chain;
friend class ChainIterator;
public:
~ChainLink();
Logical TestInstance() const;
private:
ChainLink(Chain *chain, Plug *plug, ChainLink *nextChainLink, ChainLink *prevChainLink);
ChainLink *nextChainLink;
ChainLink *prevChainLink;
private:
static MemoryBlock* GetAllocatedMemory();
void *operator new(size_t) { return GetAllocatedMemory()->New(); }
void operator delete(void *where) { GetAllocatedMemory()->Delete(where); }
};
class Chain : public Socket
{
friend class ChainLink;
friend class ChainIterator;
public:
Chain(Node *node);
~Chain();
Logical TestInstance() const;
static Logical TestClass();
static Logical ProfileClass();
protected:
void AddImplementation(Plug *plug);
private:
ChainLink *InsertChainLink(Plug *plug, ChainLink *current_link);
ChainLink *head, *tail;
};
template <class T> class ChainOf : public Chain
{
public:
ChainOf(Node *node);
~ChainOf();
void Add(T plug)
{
Chain::AddImplementation(Cast_Object(Plug*, plug));
}
};
template <class T> ChainOf<T>::ChainOf(Node *node) : Chain(node)
{
}
template <class T> ChainOf<T>::~ChainOf()
{
}
class ChainIterator : public SocketIterator
{
public:
ChainIterator(Chain *chain);
ChainIterator(const ChainIterator &iterator);
~ChainIterator();
Logical TestInstance() const;
void First();
void Last();
void Next();
void Previous();
CollectionSize GetSize();
void Remove();
protected:
void *ReadAndNextImplementation();
void *ReadAndPreviousImplementation();
void *GetCurrentImplementation();
void *GetNthImplementation(CollectionSize index);
void InsertImplementation(Plug*);
ChainLink *currentLink;
};
template <class T> class ChainIteratorOf : public ChainIterator
{
public:
ChainIteratorOf(ChainOf<T> *chain);
ChainIteratorOf(ChainOf<T> &chain);
ChainIteratorOf(const ChainIteratorOf<T> &iterator);
~ChainIteratorOf();
T ReadAndNext() { return (T)ReadAndNextImplementation(); }
T ReadAndPrevious() { return (T)ReadAndPreviousImplementation(); }
T GetCurrent() { return (T)GetCurrentImplementation(); }
T GetNth(CollectionSize index) { return (T)GetNthImplementation(index); }
void Insert(T plug) { InsertImplementation(Cast_Object(Plug*, plug)); }
ChainIteratorOf<T>& Begin() { return (ChainIteratorOf<T>&)BeginImplementation(); }
ChainIteratorOf<T>& End() { return (ChainIteratorOf<T>&)EndImplementation(); }
ChainIteratorOf<T>& Forward() { return (ChainIteratorOf<T>&)ForwardImplementation(); }
ChainIteratorOf<T>& Backward() { return (ChainIteratorOf<T>&)BackwardImplementation(); }
#if 0
Logical operator!() { return currentLink == NULL; }
operator T*() { return GetCurrent(); }
T* operator->() { return GetCurrent(); }
T& operator*() { return *GetCurrent(); }
ChainIteratorOf<T>& operator++()
{
Next();
return *this;
}
ChainIteratorOf<T>& operator--()
{
Previous();
return *this;
}
T* operator++(int) { return ReadAndNext(); }
T* operator--(int) { return ReadAndPrevious(); }
#endif
};
template <class T> ChainIteratorOf<T>::ChainIteratorOf(ChainOf<T> *chain) : ChainIterator(chain)
{
}
template <class T> ChainIteratorOf<T>::ChainIteratorOf(ChainOf<T> &chain) : ChainIterator(&chain)
{
}
template <class T> ChainIteratorOf<T>::ChainIteratorOf(const ChainIteratorOf<T> &iterator) : ChainIterator(iterator)
{
}
template <class T> ChainIteratorOf<T>::~ChainIteratorOf()
{
}
+59
View File
@@ -0,0 +1,59 @@
#include "munga.h"
#pragma hdrstop
#include "cmpnnt.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Component ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Shared Data Support
//
Derivation* Component::GetClassDerivations()
{
static Derivation classDerivations(Receiver::GetClassDerivations(), "Component");
return &classDerivations;
}
Component::SharedData Component::DefaultData(Component::GetClassDerivations(), Component::GetMessageHandlers());
//
//#############################################################################
//#############################################################################
//
Component::Component(ClassID class_id, SharedData &shared_data) : Receiver(class_id, shared_data)
{
}
//
//#############################################################################
//#############################################################################
//
Component::Component(PlugStream *stream, SharedData &shared_data) : Receiver(stream, shared_data)
{
}
//
//#############################################################################
//#############################################################################
//
Component::~Component()
{
}
//
//#############################################################################
//#############################################################################
//
void Component::Execute()
{
Fail("Component::Execute - Should never reach here");
}
//
//#############################################################################
//#############################################################################
//
Logical Component::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include "receiver.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Component ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class Component : public Receiver
{
public:
~Component();
virtual void Execute();
static Derivation *GetClassDerivations();
static SharedData DefaultData;
Logical TestInstance() const;
protected:
Component(ClassID class_id = TrivialComponentClassID, SharedData &shared_data = DefaultData);
Component(PlugStream *stream, SharedData &shared_data = DefaultData);
};
+367
View File
@@ -0,0 +1,367 @@
#include "munga.h"
#pragma hdrstop
#include "collasst.h"
#include "mover.h"
#include "app.h"
#include "interest.h"
//
//#############################################################################
// Make
//#############################################################################
//
CollisionAssistant*
CollisionAssistant::Make(Mover *mover)
{
Check(mover);
//
// Create the collision assistant
//
CollisionAssistant *collision_assistant;
collision_assistant = new CollisionAssistant(mover->GetInterestZoneID());
Check(collision_assistant);
return collision_assistant;
}
//
//#############################################################################
// CollisionAssistant
//#############################################################################
//
CollisionAssistant::CollisionAssistant(InterestZoneID interest_zone_ID):
collisionOriginSocket(NULL)
{
Verify(interest_zone_ID != NullInterestZoneID);
currentInterestZoneID = interest_zone_ID;
LinkToInterestZone(interest_zone_ID);
}
//
//#############################################################################
// ~CollisionAssistant
//#############################################################################
//
CollisionAssistant::~CollisionAssistant()
{
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
CollisionAssistant::TestInstance() const
{
Node::TestInstance();
Verify(currentInterestZoneID != NullInterestZoneID);
Check(&collisionOriginSocket);
return True;
}
//
//#############################################################################
// Update
//#############################################################################
//
void
CollisionAssistant::Update(InterestZoneID interest_zone_ID)
{
Check(this);
Verify(interest_zone_ID != NullInterestZoneID);
if (interest_zone_ID == currentInterestZoneID)
return;
currentInterestZoneID = interest_zone_ID;
//
// Remove current collision origin and link to new one
//
if (collisionOriginSocket.GetCurrent() != NULL)
{
collisionOriginSocket.Remove();
}
LinkToInterestZone(interest_zone_ID);
}
//
//#############################################################################
// LinkToInterestZone
//#############################################################################
//
void
CollisionAssistant::LinkToInterestZone(InterestZoneID interest_zone_ID)
{
Check(this);
Verify(interest_zone_ID != NullInterestZoneID);
//
//--------------------------------------------------------------------------
// Does the interest zone have a collision origin?
//--------------------------------------------------------------------------
//
InterestZone *interest_zone;
CollisionOrigin *collision_origin;
Check(application);
Check(application->GetInterestManager());
interest_zone =
application->GetInterestManager()->GetInterestZone(interest_zone_ID);
Check(interest_zone);
collision_origin = interest_zone->GetCollisionOrigin();
if (collision_origin == NULL)
{
//
// It does not, so create one
//
collision_origin = new CollisionOrigin(interest_zone_ID);
Register_Object(collision_origin);
interest_zone->AdoptCollisionOrigin(collision_origin);
application->GetInterestManager()->AdoptInterestOrigin(collision_origin);
}
Check(collision_origin);
//
// link to the collision origin
//
collisionOriginSocket.Add(collision_origin);
}
//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~~~~
CollisionAssistant__MovingEntityIterator::
CollisionAssistant__MovingEntityIterator(
CollisionAssistant *collision_assistant
):
CollisionOrigin__MovingEntityIterator(
collision_assistant->collisionOriginSocket.GetCurrent()
)
{
}
CollisionAssistant__MovingEntityIterator::
~CollisionAssistant__MovingEntityIterator()
{
}
#if 0
//
//#############################################################################
// Make
//#############################################################################
//
CollisionAssistant*
CollisionAssistant::Make(Mover *mover)
{
Check(mover);
//
//-----------------------------------------------------------------------
// Create the collision assistant
//-----------------------------------------------------------------------
//
CollisionAssistant *collision_assistant;
Check(application);
collision_assistant = new CollisionAssistant(
application->GetApplicationLoopFrameRate()
);
Check(collision_assistant);
//
//-----------------------------------------------------------------------
// Prime the collision assistant
//-----------------------------------------------------------------------
//
collision_assistant->LinkToMover(mover);
collision_assistant->LoadMission(NULL); // JM - This should work...
return collision_assistant;
}
//
//#############################################################################
// CollisionAssistant
//#############################################################################
//
CollisionAssistant::CollisionAssistant(RendererRate render_rate):
Renderer(
render_rate,
MaxRendererComplexity,
DefaultRendererPriority,
CollisionInterestType,
DefaultInterestDepth,
CollisionAssistantClassID
),
movingEntitySocket(NULL)
{
}
//
//#############################################################################
// ~CollisionAssistant
//#############################################################################
//
CollisionAssistant::~CollisionAssistant()
{
Suspend();
UnlinkFromEntity();
Shutdown();
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
CollisionAssistant::TestInstance() const
{
Renderer::TestInstance();
Check(&movingEntitySocket);
return True;
}
//
//#############################################################################
// LinkToEntity
//#############################################################################
//
void
CollisionAssistant::LinkToMover(Mover *mover)
{
Check(this);
Check(mover);
//
// Call inherited method
//
Renderer::LinkToEntity(mover);
//
//-----------------------------------------------------------------
// Tell the entity that is collisionable here ...
//-----------------------------------------------------------------
//
}
//
//#############################################################################
// NotifyOfNewInterestingEntity
//#############################################################################
//
void
CollisionAssistant::NotifyOfNewInterestingEntity(
Entity *interesting_entity
)
{
Check(this);
Check(interesting_entity);
//
//-------------------------------------------------------------------------
// Make sure that we don't check against ourself our against something that
// doesn't move
//-------------------------------------------------------------------------
//
if (
interesting_entity != GetLinkedEntity()
&& interesting_entity->IsDynamic()
)
{
//
//-------------------------------------------------------------
// If it is a mover and tangible, or a door, add it to our list
//-------------------------------------------------------------
//
if (interesting_entity->IsDerivedFrom(Mover::GetClassDerivations()))
{
Mover *mover = Cast_Object(Mover*, interesting_entity);
if (mover->IsTangible())
{
goto Add_Entity;
}
}
else if (interesting_entity->IsDerivedFrom(DoorFrame::GetClassDerivations()))
{
Add_Entity:
movingEntitySocket.Add(interesting_entity);
}
}
}
//
//#############################################################################
// NotifyOfBecomingUninterestingEntity
//#############################################################################
//
void
CollisionAssistant::NotifyOfBecomingUninterestingEntity(
Entity *uninteresting_entity
)
{
//
// HACK - ECH The following may not be a legitimate assertion
//
#if DEBUG_LEVEL>0 && 0
{
SChainIteratorOf<Mover*> iterator(&movingEntitySocket);
Verify(iterator.IsPlugMember(uninteresting_entity) == True);
}
#endif
//
// Remove from socket
//
PlugIterator iterator(uninteresting_entity);
iterator.RemoveSocket(&movingEntitySocket);
}
//
//#############################################################################
// GetCollisionRoot
//#############################################################################
//
BoxedSolidTree*
CollisionAssistant::GetCollisionRoot()
{
Check(GetInterestOrigin());
Check(GetInterestOrigin()->GetInterestArena());
return GetInterestOrigin()->GetInterestArena()->GetCollisionRoot();
}
//
//#############################################################################
// ExecuteImplementation
//#############################################################################
//
void
CollisionAssistant::ExecuteImplementation(
RendererComplexity,
InterestOrigin::InterestingEntityIterator*
)
{
}
//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CollisionAssistant__MovingEntityIterator::
CollisionAssistant__MovingEntityIterator(
CollisionAssistant *collision_assistant
):
SChainIteratorOf<Entity*>(collision_assistant->movingEntitySocket)
{
}
CollisionAssistant__MovingEntityIterator::
~CollisionAssistant__MovingEntityIterator()
{
}
#endif
+180
View File
@@ -0,0 +1,180 @@
#pragma once
#include "node.h"
#include "slot.h"
#include "collorgn.h"
//##########################################################################
//####################### CollisionAssistant #########################
//##########################################################################
class Mover;
class CollisionAssistant:
public Node
{
friend class CollisionAssistant__MovingEntityIterator;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Public Types
//
public:
typedef CollisionAssistant__MovingEntityIterator
MovingEntityIterator;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
CollisionAssistant(InterestZoneID interest_zone_ID);
~CollisionAssistant();
Logical
TestInstance() const;
static CollisionAssistant*
Make(Mover *mover);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update
//
public:
void
Update(InterestZoneID interest_zone_ID);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private
//
private:
void
LinkToInterestZone(InterestZoneID interest_zone_ID);
InterestZoneID
currentInterestZoneID;
SlotOf<CollisionOrigin*>
collisionOriginSocket;
};
//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~
class CollisionAssistant__MovingEntityIterator:
public CollisionOrigin__MovingEntityIterator
{
public:
CollisionAssistant__MovingEntityIterator(
CollisionAssistant *collision_assistant
);
~CollisionAssistant__MovingEntityIterator();
};
#if 0
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CollisionAssistant ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CollisionAssistant:
public Renderer
{
friend class CollisionAssistant__MovingEntityIterator;
public:
//
//--------------------------------------------------------------------
// Public Types
//--------------------------------------------------------------------
//
typedef CollisionAssistant__MovingEntityIterator
MovingEntityIterator;
//
//--------------------------------------------------------------------
// Construction, Destruction, Testing
//--------------------------------------------------------------------
//
CollisionAssistant(RendererRate render_rate);
~CollisionAssistant();
Logical
TestInstance() const;
static CollisionAssistant*
Make(Mover *mover);
//
//--------------------------------------------------------------------
// LinkToEntity
//--------------------------------------------------------------------
//
void
LinkToMover(Mover *mover);
//
//--------------------------------------------------------------------
// NotifyOfNewInterestingEntity
//--------------------------------------------------------------------
//
void
NotifyOfNewInterestingEntity(Entity *interesting_entity);
//
//--------------------------------------------------------------------
// NotifyOfBecomingUninterestingEntity
//--------------------------------------------------------------------
//
void
NotifyOfBecomingUninterestingEntity(Entity *uninteresting_entity);
//
//--------------------------------------------------------------------
// GetCollisionRoot
//--------------------------------------------------------------------
//
BoxedSolidTree*
GetCollisionRoot();
protected:
//
//--------------------------------------------------------------------
// ExecuteImplementation
//--------------------------------------------------------------------
//
void
ExecuteImplementation(
RendererComplexity complexity_update,
InterestOrigin::InterestingEntityIterator *iterator
);
private:
//
//--------------------------------------------------------------------
// Private methods
//--------------------------------------------------------------------
//
void
LoadMissionImplementation(Mission*) {}
void
ShutdownImplementation() {}
void
SuspendImplementation() {}
void
ResumeImplementation() {}
//
//--------------------------------------------------------------------
// Private data
//--------------------------------------------------------------------
//
SChainOf<Entity*>
movingEntitySocket;
};
//~~~~~~~~~~~~~~~~~ CollisionAssistant__MovingEntityIterator ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class CollisionAssistant__MovingEntityIterator:
public SChainIteratorOf<Entity*>
{
public:
CollisionAssistant__MovingEntityIterator(
CollisionAssistant *collision_assistant
);
~CollisionAssistant__MovingEntityIterator();
};
#endif
+144
View File
@@ -0,0 +1,144 @@
#include "munga.h"
#pragma hdrstop
#include "collorgn.h"
#include "mover.h"
#include "doorfram.h"
//
//#############################################################################
// CollisionOrigin
//#############################################################################
//
CollisionOrigin::CollisionOrigin(InterestZoneID interest_zone_ID):
InterestOrigin(
interest_zone_ID,
CollisionInterestType,
DefaultInterestDepth
),
movingEntitySocket(NULL)
{
}
//
//#############################################################################
// ~CollisionOrigin
//#############################################################################
//
CollisionOrigin::~CollisionOrigin()
{
}
//
//#############################################################################
// TestInstance
//#############################################################################
//
Logical
CollisionOrigin::TestInstance() const
{
InterestOrigin::TestInstance();
Check(&movingEntitySocket);
return True;
}
//
//#############################################################################
// AddInterestingEntity
//#############################################################################
//
void
CollisionOrigin::AddInterestingEntity(Entity *interesting_entity)
{
Check(this);
Check(interesting_entity);
//
//--------------------------------------------------------------------------
// Make sure that we don't check against something that doesn't move
//--------------------------------------------------------------------------
//
if (interesting_entity->IsDynamic())
{
//
//-----------------------------------------------------------------------
// If it is a mover and tangible, or a door, add it to our list
//-----------------------------------------------------------------------
//
if (interesting_entity->IsDerivedFrom(*Mover::GetClassDerivations()))
{
Mover *mover = Cast_Object(Mover*, interesting_entity);
if (mover->IsCollisionTestable())
{
movingEntitySocket.Add(interesting_entity);
}
}
else if (interesting_entity->IsDerivedFrom(*DoorFrame::GetClassDerivations()))
{
movingEntitySocket.Add(interesting_entity);
}
}
}
//
//#############################################################################
// RemoveUninterestingEntity
//#############################################################################
//
void
CollisionOrigin::RemoveUninterestingEntity(Entity *uninteresting_entity)
{
Check(this);
Check(uninteresting_entity);
//
// HACK - ECH The following may not be a legitimate assertion
//
#if DEBUG_LEVEL>0 && 0
{
SChainIteratorOf<Mover*> iterator(&movingEntitySocket);
Verify(iterator.IsPlugMember(uninteresting_entity) == True);
}
#endif
//
// Remove from socket
//
PlugIterator iterator(uninteresting_entity);
Check(&iterator);
iterator.RemoveSocket(&movingEntitySocket);
}
//
//#############################################################################
// RemoveUninterestingEntities
//#############################################################################
//
void
CollisionOrigin::RemoveUninterestingEntities()
{
Check(this);
SChainIteratorOf<Entity*> iterator(&movingEntitySocket);
Check(&iterator);
while (iterator.GetCurrent() != NULL)
{
Check(iterator.GetCurrent());
iterator.Remove();
}
}
//~~~~~~~~~~~~~~~~~~~ CollisionOrigin__MovingEntityIterator ~~~~~~~~~~~~~~~~~~~
CollisionOrigin__MovingEntityIterator::CollisionOrigin__MovingEntityIterator(
CollisionOrigin *collision_origin
):
SChainIteratorOf<Entity*>(collision_origin->movingEntitySocket)
{
}
CollisionOrigin__MovingEntityIterator::~CollisionOrigin__MovingEntityIterator()
{
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include "interest.h"
//##########################################################################
//###################### CollisionOrigin #############################
//##########################################################################
class CollisionOrigin : public InterestOrigin
{
friend class CollisionOrigin__MovingEntityIterator;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Interest Manager support
//
public:
typedef CollisionOrigin__MovingEntityIterator MovingEntityIterator;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction, Destruction, Testing
//
public:
CollisionOrigin(InterestZoneID interest_zone_ID);
~CollisionOrigin();
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Interest Manager support
//
protected:
void AddInterestingEntity(Entity *interesting_entity);
void RemoveUninterestingEntity(Entity *uninteresting_entity);
void RemoveUninterestingEntities();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Private data
//
private:
SChainOf<Entity*> movingEntitySocket;
};
//~~~~~~~~~~~~~~~~~~~~ CollisionOrigin__MovingEntityIterator ~~~~~~~~~~~~~~~
class CollisionOrigin__MovingEntityIterator : public SChainIteratorOf<Entity*>
{
public:
CollisionOrigin__MovingEntityIterator(CollisionOrigin *collision_origin);
~CollisionOrigin__MovingEntityIterator();
};
+68
View File
@@ -0,0 +1,68 @@
#include "munga.h"
#pragma hdrstop
#include "color.h"
#include "cstr.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~ RGBColor functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//###########################################################################
//###########################################################################
//
void Convert_From_Ascii(const char *str, RGBColor *color)
{
Check_Pointer(str);
Check_Signature(color);
CString parse_string(str);
Check_Pointer(parse_string.GetNthToken(0));
color->Red = atof(parse_string.GetNthToken(0));
Check_Pointer(parse_string.GetNthToken(1));
color->Green = atof(parse_string.GetNthToken(1));
Check_Pointer(parse_string.GetNthToken(2));
color->Blue = atof(parse_string.GetNthToken(2));
Check(color);
}
//
//###########################################################################
//###########################################################################
//
Logical RGBColor::TestInstance() const
{
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~ RGBAColor functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//###########################################################################
//###########################################################################
//
void Convert_From_Ascii(const char *str, RGBAColor *color)
{
Check_Pointer(str);
Check_Signature(color);
CString parse_string(str);
Check_Pointer(parse_string.GetNthToken(0));
color->Red = atof(parse_string.GetNthToken(0));
Check_Pointer(parse_string.GetNthToken(1));
color->Green = atof(parse_string.GetNthToken(1));
Check_Pointer(parse_string.GetNthToken(2));
color->Blue = atof(parse_string.GetNthToken(2));
Check_Pointer(parse_string.GetNthToken(3));
color->Alpha = atof(parse_string.GetNthToken(3));
Check(color);
}
+92
View File
@@ -0,0 +1,92 @@
#pragma once
#include "memstrm.h"
#include "scalar.h"
//##########################################################################
//############## RGBColor ############################################
//##########################################################################
class RGBColor
{
friend class RGBAColor;
public:
Scalar Red, Green, Blue;
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const volatile RGBColor *p)
{
return False;
}
#endif
RGBColor()
{
Red = Green = Blue = -1.0f;
}
RGBColor(Scalar r, Scalar g, Scalar b)
{
Red = r;
Green = g;
Blue = b;
}
Logical operator==(const RGBColor &a_RGBColor) const
{
return !memcmp(this, &a_RGBColor, sizeof(RGBColor));
}
Logical operator!=(const RGBColor &a_RGBColor) const
{
return memcmp(this, &a_RGBColor, sizeof(RGBColor));
}
Logical TestInstance() const;
RGBColor operator+(const RGBColor &a_RGBColor) const { return RGBColor(Min(this->Red + a_RGBColor.Red, 1.0), Min(this->Green + a_RGBColor.Green, 1.0), Min(this->Blue + a_RGBColor.Blue, 1.0)); }
Scalar Infrared() const { return 0.3 * this->Red + 0.5 * this->Green + 0.2 * this->Blue; }
//
// Support functions
//
friend std::ostream& operator<<(std::ostream& stream, const RGBColor& C);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ RGBColor functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Convert_From_Ascii(const char *str, RGBColor *color);
inline MemoryStream& MemoryStream_Read(MemoryStream* stream, RGBColor *output) { return stream->ReadBytes(output, sizeof(*output)); }
inline MemoryStream& MemoryStream_Write(MemoryStream* stream, const RGBColor *input) { return stream->WriteBytes(input, sizeof(*input)); }
//##########################################################################
//############## RGBAColor ###########################################
//##########################################################################
class RGBAColor : public RGBColor
{
public:
Scalar Alpha;
RGBAColor() : RGBColor() { Alpha = -1.0f; }
RGBAColor(Scalar r, Scalar g, Scalar b, Scalar a) : RGBColor(r, g, b) { Alpha = a; }
Logical operator==(const RGBAColor &a_RGBAColor) const { return !memcmp(this, &a_RGBAColor, sizeof(RGBAColor)); }
Logical operator!=(const RGBAColor &a_RGBAColor) const { return memcmp(this, &a_RGBAColor, sizeof(RGBAColor)); }
//
// Support functions
//
friend std::ostream& operator<<(std::ostream& stream, const RGBAColor& c);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~ RGBAColor functions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Convert_From_Ascii(const char *str, RGBAColor *color);
inline MemoryStream& MemoryStream_Read(MemoryStream* stream, RGBAColor *output) { return stream->ReadBytes(output, sizeof(*output)); }
inline MemoryStream& MemoryStream_Write(MemoryStream* stream, const RGBAColor *input) { return stream->WriteBytes(input, sizeof(*input)); }
+151
View File
@@ -0,0 +1,151 @@
#pragma once
#if DEBUG_LEVEL >= 3
#undef USE_ACTIVE_PROFILE // Disables trace activity
#define USE_TIME_ANALYSIS // Enables trace time statistics
#undef USE_TRACE_LOG // Disables logging functions
#define USE_FPU_ANALYSIS // Enables entity FPU checks
#define USE_MEMORY_ANALYSIS // Enables heap statistics
#undef USE_EVENT_STATISTICS // Disables event statistics
#elif DEBUG_LEVEL == 2
#undef USE_ACTIVE_PROFILE // Disables trace activity
#define USE_TIME_ANALYSIS // Enables trace time statistics
#undef USE_TRACE_LOG // Disables logging functions
#define USE_FPU_ANALYSIS // Enables entity FPU checks
#define USE_MEMORY_ANALYSIS // Enables heap statistics
#undef USE_EVENT_STATISTICS // Disables event statistics
#elif DEBUG_LEVEL == 1
#undef USE_ACTIVE_PROFILE // Disables trace activity
#define USE_TIME_ANALYSIS // Enables trace time statistics
#undef USE_TRACE_LOG // Disables logging functions
#define USE_FPU_ANALYSIS // Enables entity FPU checks
#define USE_MEMORY_ANALYSIS // Enables heap statistics
#undef USE_EVENT_STATISTICS // Disables event statistics
#elif DEBUG_LEVEL == 0
#if defined(LAB_ONLY)
#undef USE_ACTIVE_PROFILE // Disables trace activity
#define USE_TIME_ANALYSIS // Enables trace time statistics
#define USE_TRACE_LOG // Enables logging functions
#undef USE_FPU_ANALYSIS // Disables entity FPU checks
#undef USE_MEMORY_ANALYSIS // Disables heap statistics
#define USE_EVENT_STATISTICS // Enables event statistics
#else
#undef USE_ACTIVE_PROFILE // Disables trace activity
#undef USE_TIME_ANALYSIS // Disables trace time statistics
#undef USE_TRACE_LOG // Disables logging functions
#undef USE_FPU_ANALYSIS // Disables entity FPU checks
#undef USE_MEMORY_ANALYSIS // Disables heap statistics
#undef USE_EVENT_STATISTICS // Disables event statistics
#endif
#endif
#if defined(USE_TIME_ANALYSIS) || defined(USE_ACTIVE_PROFILE) || defined(USE_TRACE_LOG)
#define TRACE_ON
#endif
//
// Traces are expensive, release build should not have them
//
#if defined(TRACE_ON) && defined(LAB_ONLY)
#define TRACE_FOREGROUND_PROCESSING
// #define TRACE_RENDERER_MANAGER
// #define TRACE_PROCESS_EVENT
#define TRACE_EVENT_COUNT
//
// Update Manager Group
//
// #define TRACE_UPDATE_MANAGER
// #define TRACE_UPDATE_MASTER
// #define TRACE_UPDATE_REPLICANTS
//
// Networking Group
//
// #define TRACE_SEND_PACKET
// #define TRACE_ROUTE_PACKET
// #define TRACE_LOST_DATA
// #define TRACE_SEND_BUFFER
//
// Video Renderer group
// To see all the video renderer traces seperately, DO NOT define USE_ONE_VIDEO_TRACE
// To see all of the video renderer on the same trace, enable the following:
//
// USE_ONE_VIDEO_TRACE
// TRACE_VIDEO_RENDERER
// TRACE_VIDEO_BECOME_INTERESTING
// TRACE_VIDEO_BECOME_UNINTERESTING
// TRACE_VIDEO_RENDERER_FRAME_DONE
//
// The time used by the above four traces will all appear on the video renderer
// trace together. This configuration should not cause any buzzing of traces and
// should capture 100% of the video renderer's activity.
// Other video renderer traces may be enabled but will appear seperately
//
// CAUTION: Depending on the setup, TRACE_VIDEO_RENDERABLES can buzz, severly
// lengthening the video renderer profile times. Use carefully.
//
// #define USE_ONE_VIDEO_TRACE
// #define TRACE_VIDEO_RENDERER
// #define TRACE_VIDEO_BECOME_INTERESTING
// #define TRACE_VIDEO_BECOME_UNINTERESTING
// #define TRACE_VIDEO_RENDERER_FRAME_DONE
// #define TRACE_VIDEO_CULL_SETUP
// #define TRACE_VIDEO_VEHICLE_RENDERABLES
// #define TRACE_VIDEO_ALL_RENDERABLES
// #define TRACE_VIDEO_MECH_CULL_RENDERABLE
// #define TRACE_VIDEO_BATCH_FLUSH
// #define TRACE_VIDEO_LOAD_OBJECT
// #define TRACE_VIDEO_PICKPOINT
// #define TRACE_VIDEO_RENDERABLES
// #define TRACE_VIDEO_CONSTRUCT_ROOT // construct the root of
// #define TRACE_VIDEO_FIRST_FRAME_DONE // obsolete soon
//
// Audio renderer group
//
// #define TRACE_AUDIO_RENDERER
// #define TRACE_AUDIO_RENDERER_MIDI
// #define TRACE_AUDIO_RENDERER_CREATE_OBJECTS
// #define TRACE_AUDIO_RENDERER_DESTROY_OBJECTS
// #define TRACE_AUDIO_RENDERER_START_HANDLER
// #define TRACE_AUDIO_RENDERER_STOP_HANDLER
// #define TRACE_AUDIO_RENDERER_EXECUTE
// #define TRACE_AUDIO_RENDERER_RUNNING_SOURCES
// #define TRACE_AUDIO_RENDERER_RUNNING_SORT
// #define TRACE_AUDIO_RENDERER_CALCULATE_MIX
// #define TRACE_AUDIO_RENDERER_EXECUTE_SOURCES
// #define TRACE_AUDIO_RENDERER_DORMANT_SOURCES
//
// Gauge renderer group
//
// #define TRACE_GAUGE_RENDERER
// #define TRACE_SCREEN_COPY
//
// Other leftovers, these are probably obsolete, if you know ones that are, kill
// kill them off as appropriate.
//
#if 0
#define TRACE_COMPLETE_CYCLES
#define TRACE_DEATH_ROW
#define TRACE_EXECUTE_ENTITY
#define TRACE_PERFORM_ENTITY
#define TRACE_PERFORM_SUBSYSTEMS
#define TRACE_EXECUTE_WATCHERS
#define TRACE_RIO_RECEIVE_PACKET
#define TRACE_RIO_SEND_PACKET
#define TRACE_CHECK_BUFFERS
#define TRACE_CALL_NETNUB
#endif
#endif
+85
View File
@@ -0,0 +1,85 @@
#include "munga.h"
#pragma hdrstop
#include "console.h"
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationReadyToRunMessage ~~~~~~~~~~~~~~~~~~~~~~
ConsoleApplicationReadyToRunMessage::
ConsoleApplicationReadyToRunMessage(HostID ready_to_run_host_ID):
NetworkClient::Message(
ConsoleApplicationReadyToRunMessageID,
sizeof(ConsoleApplicationReadyToRunMessage)
)
{
readyToRunHostID = ready_to_run_host_ID;
}
//~~~~~~~~~~~~~~~~ ConsoleApplicationStateResponseMessage ~~~~~~~~~~~~~~~~~~~~~
ConsoleApplicationStateResponseMessage::ConsoleApplicationStateResponseMessage(
HostID responding_host_ID,
Enumeration application_state,
Enumeration application_type
):
NetworkClient::Message(
ConsoleApplicationStateResponseMessageID,
sizeof(ConsoleApplicationStateResponseMessage)
)
{
respondingHostID = responding_host_ID;
applicationState = application_state;
application = application_type;
}
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationEndMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
ConsoleApplicationEndMissionMessage::
ConsoleApplicationEndMissionMessage(
HostID player_host_ID,
int final_score
):
NetworkClient::Message(
ConsoleApplicationEndMissionMessageID,
sizeof(ConsoleApplicationEndMissionMessage)
)
{
playerHostID = player_host_ID;
finalScore = final_score;
}
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationAbortMissionMessage ~~~~~~~~~~~~~~~~~~~~~~
ConsoleApplicationAbortMissionMessage::
ConsoleApplicationAbortMissionMessage(
HostID player_host_ID
):
NetworkClient::Message(
ConsoleApplicationAbortMissionMessageID,
sizeof(ConsoleApplicationAbortMissionMessage)
)
{
playerHostID = player_host_ID;
}
//~~~~~~~~~~~~~~~~ ConsoleApplicationTeamEndMissionMessage ~~~~~~~~~~~~~~~~~~~~
ConsoleApplicationTeamEndMissionMessage::
ConsoleApplicationTeamEndMissionMessage(
HostID player_host_ID,
int player_score,
int team_ID,
int team_score
):
NetworkClient::Message(
ConsoleApplicationTeamEndMissionMessageID,
sizeof(ConsoleApplicationTeamEndMissionMessage)
)
{
playerHostID = player_host_ID;
playerScore = player_score;
teamID = team_ID;
teamScore = team_score;
}
//==============================================================================
+281
View File
@@ -0,0 +1,281 @@
#pragma once
#if defined(MAC)
#include <NetworkEndpoint.h>
#include <Participant.h>
#else
#include "network.h"
#endif
//~~~~~~~~~~~~~~~~~~~~~~~~ Console Message IDs ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
enum ConsoleMessageID
{
ConsoleApplicationReadyToRunMessageID = 0,
ConsoleApplicationStateResponseMessageID = 1,
ConsoleApplicationEndMissionMessageID = 7,
ConsoleApplicationAbortMissionMessageID = 11,
ConsoleApplicationTeamEndMissionMessageID = 14
};
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationReadyToRunMessage ~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class ConsoleApplicationReadyToRunMessage:
public NetworkEndpoint::Message
{
public:
ConsoleApplicationReadyToRunMessage(HostID ready_to_run_host_ID);
long
GetReadyToRunHostID()
{return readyToRunHostID.value();}
private:
HostID
readyToRunHostID;
};
#pragma options align=reset
#else
class ConsoleApplicationReadyToRunMessage:
public NetworkClient::Message
{
public:
ConsoleApplicationReadyToRunMessage(HostID ready_to_run_host_ID);
HostID
GetReadyToRunHostID()
{return readyToRunHostID;}
private:
HostID
readyToRunHostID;
};
#endif
//~~~~~~~~~~~~~~~~ ConsoleApplicationStateResponseMessage ~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class ConsoleApplicationStateResponseMessage:
public NetworkEndpoint::Message
{
public:
ConsoleApplicationStateResponseMessage(
HostID responding_host_ID,
LEDWORD application_state,
LEDWORD application_type
);
long
GetRespondingHostID()
{return respondingHostID.value();}
long
GetApplicationState()
{return applicationState.value();}
ApplicationID
GetApplication()
{return((ApplicationID) application.value());}
private:
HostID
respondingHostID;
LEDWORD
applicationState;
LEDWORD
application;
};
#pragma options align=reset
#else
class ConsoleApplicationStateResponseMessage:
public NetworkClient::Message
{
public:
ConsoleApplicationStateResponseMessage(
HostID responding_host_ID,
Enumeration application_state,
Enumeration application
);
HostID
GetRespondingHostID()
{return respondingHostID;}
Enumeration
GetApplicationState()
{return applicationState;}
Enumeration
GetApplication()
{return application;}
private:
HostID
respondingHostID;
Enumeration
applicationState;
Enumeration
application;
};
#endif
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationEndMissionMessage ~~~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class ConsoleApplicationEndMissionMessage:
public NetworkEndpoint::Message
{
public:
ConsoleApplicationEndMissionMessage(
HostID player_ID,
LEDWORD final_score
);
long
GetPlayerHostID()
{return playerHostID.value();}
long
GetFinalScore()
{return finalScore.value();}
private:
HostID
playerHostID;
LEDWORD
finalScore;
};
#pragma options align=reset
#else
class ConsoleApplicationEndMissionMessage:
public NetworkClient::Message
{
public:
ConsoleApplicationEndMissionMessage(
HostID player_host_ID,
int final_score
);
HostID
GetPlayerHostID()
{return playerHostID;}
int
GetFinalScore()
{return finalScore;}
private:
HostID
playerHostID;
int
finalScore;
};
#endif
//~~~~~~~~~~~~~~~~~~ ConsoleApplicationAbortMissionMessage ~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class ConsoleApplicationAbortMissionMessage:
public NetworkEndpoint::Message
{
public:
ConsoleApplicationAbortMissionMessage(
HostID player_ID
);
long
GetPlayerHostID()
{return playerHostID.value();}
private:
HostID
playerHostID;
};
#pragma options align=reset
#else
class ConsoleApplicationAbortMissionMessage:
public NetworkClient::Message
{
public:
ConsoleApplicationAbortMissionMessage(
HostID player_host_ID
);
HostID
GetPlayerHostID()
{return playerHostID;}
private:
HostID
playerHostID;
};
#endif
//~~~~~~~~~~~~~~~~ ConsoleApplicationTeamEndMissionMessage ~~~~~~~~~~~~~~~~~
#ifdef MAC
#pragma options align=mac68k4byte
class ConsoleApplicationTeamEndMissionMessage:
public NetworkEndpoint::Message
{
public:
ConsoleApplicationTeamEndMissionMessage(
HostID player_ID,
LEDWORD player_score,
LEDWORD team_id,
LEDWORD team_score
);
long
GetPlayerHostID()
{return playerHostID.value();}
long
GetPlayerScore()
{return playerScore.value();}
long
GetTeamID()
{return teamID.value();}
long
GetTeamScore()
{return teamScore.value();}
private:
HostID
playerHostID;
LEDWORD
playerScore;
LEDWORD
teamID;
LEDWORD
teamScore;
};
#pragma options align=reset
#else
class ConsoleApplicationTeamEndMissionMessage:
public NetworkClient::Message
{
public:
ConsoleApplicationTeamEndMissionMessage(
HostID player_host_ID,
int player_score,
int team_id,
int team_score
);
HostID
GetPlayerHostID()
{return playerHostID;}
int
GetFinalScore()
{return playerScore;}
int
GetTeamID()
{return teamID;}
int
GetTeamScore()
{return teamScore;}
private:
HostID
playerHostID;
int
playerScore;
int
teamID;
int
teamScore;
};
#endif
+660
View File
@@ -0,0 +1,660 @@
#include "munga.h"
#pragma hdrstop
#include "controls.h"
#include "app.h"
#if defined(DEBUG)
# define Test_Tell(n) DEBUG_STREAM << n
#else
# define Test_Tell(n)
#endif
//############################################################################
//####################### ControlsInstance #############################
//############################################################################
ControlsInstance::ControlsInstance(
ClassID class_ID,
ModeMask mode_mask,
Plug *dependant
):
Node(class_ID),
dependantPlug(this)
{
Check_Pointer(this);
modeMask = mode_mask;
dependantPlug.Add(dependant);
Check_Fpu();
}
ControlsInstance::~ControlsInstance()
{
Check(this);
Check_Fpu();
}
void
ControlsInstance::Update(void *)
{
Fail("ControlsInstance::Update not overridden!");
}
//
//#############################################################################
//#############################################################################
//
void
ControlsInstance::ReleaseLinkHandler(
Socket*,
Plug*
)
{
Unregister_Object(this);
delete this;
Check_Fpu();
}
//############################################################################
//######################### ControlsMappingGroup #############################
//############################################################################
//
// The ControlsMappingGroup object maintains a group of ControlInstances.
//
// ControlsMappingGroup.Update() will call ControlsInstance.Update()
// for each instance in the group.
//
ControlsMappingGroup::ControlsMappingGroup():
Node(ControlsMappingGroup::ControlsMappingGroupClassID),
instanceList(this)
{
Check_Pointer(this);
Check_Fpu();
}
ControlsMappingGroup::~ControlsMappingGroup()
{
Check(this);
Remove(0); // remove all mappings
Check_Fpu();
}
void ControlsMappingGroup::Remove(ModeMask mode_mask)
{
Check(this);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
while ((controls_instance=i.ReadAndNext()) != NULL)
{
Check(controls_instance);
//---------------------------------------------
// Remove mapping bit(s)
//---------------------------------------------
controls_instance->modeMask &= ~mode_mask;
//---------------------------------------------
// If no bits left, delete mapping
//---------------------------------------------
if (controls_instance->modeMask == (ModeMask)0)
{
Unregister_Object(controls_instance);
delete controls_instance;
}
}
Check_Fpu();
}
void
ControlsMappingGroup::Update(void *data_source, ModeMask mode_mask)
{
Check(this);
Check_Pointer(data_source);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
while ((controls_instance=i.ReadAndNext()) != NULL)
{
//------------------------------------------------
// Process only if at least one mode bit matches
//------------------------------------------------
Check(controls_instance);
if (controls_instance->modeMask & mode_mask)
{
controls_instance->Update(data_source);
}
}
Check_Fpu();
}
Logical
ControlsMappingGroup::CurrentFilterStatus(ModeMask mode_mask)
{
Check(this);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
while ((controls_instance=i.ReadAndNext()) != NULL)
{
Check(controls_instance);
if (controls_instance->modeMask & mode_mask)
{
Check_Fpu();
return True;
}
}
Check_Fpu();
return False;
}
//############################################################################
//########################### ControlsManager ################################
//############################################################################
//---------------------------------------------------------------------------
// Class derivation
//---------------------------------------------------------------------------
Derivation* ControlsManager::GetClassDerivations()
{
static Derivation classDerivations(Receiver::GetClassDerivations(), "ControlsManager");
return &classDerivations;
}
unsigned int
ControlsManager::nextOwnerID=0;
ControlsManager
*ControlsManager::headControlsManager = NULL;
//
//############################################################################
// ControlsManager
//
// Creator method
//----------------------------------------------------------------------------
// Enter: virtualDataPtr
//############################################################################
//
ControlsManager::ControlsManager(
ClassID class_ID,
SharedData &shared_data
):
Receiver(
class_ID,
shared_data
)
{
activeDestination = NULL;
activeReceiver = NULL;
activeMessageID = (Receiver::MessageID) 0;
activeDependant = NULL;
//----------------------------------------------------
// Add this object to the chain
//----------------------------------------------------
nextControlsManager = headControlsManager;
headControlsManager = this;
Check_Fpu();
}
//
//############################################################################
// ~ControlsManager
//
// Destructor method
//############################################################################
//
ControlsManager::~ControlsManager()
{
//----------------------------------------------------
// Unlink this object from the chain
//----------------------------------------------------
ControlsManager
*controls_manager,
*previous_controls_manager(NULL);
//
// Search for 'this' in the chain
//
for(
controls_manager = headControlsManager;
controls_manager != NULL;
controls_manager = controls_manager->nextControlsManager
)
{
if (controls_manager == this)
{
//
// Found! head of list?
//
if (previous_controls_manager == NULL)
{
headControlsManager = nextControlsManager;
}
//
// Not head, remove from chain
//
else
{
previous_controls_manager->nextControlsManager =
nextControlsManager;
}
break;
}
//
// Keep track of 'previous' object
//
previous_controls_manager = controls_manager;
}
Check_Fpu();
}
void
ControlsManager::Remove(ModeMask /*mode_mask*/)
{
Fail("ControlsManager::Remove should not be called!\n");
}
void
ControlsManager::Execute()
{
Fail("ControlsManager::Execute should not be called!\n");
}
void
ControlsManager::StartMappableButtonsConfigure(
void *active_direct_target,
Receiver *target,
Plug *dependant,
Receiver::MessageID active_message_id,
ModeMask remove_mode_mask,
ModeMask add_mode_mask
)
{
Check(this);
activeReceiver = target;
activeMessageID = active_message_id;
activeDestination = active_direct_target;
activeDependant = dependant;
Check(application);
ModeManager
*mode_manager = application->GetModeManager();
Check(mode_manager);
mode_manager->RemoveModeMask(remove_mode_mask);
mode_manager->AddModeMask(add_mode_mask);
Check_Fpu();
}
void
ControlsManager::StopMappableButtonsConfigure(
ModeMask remove_mode_mask,
ModeMask add_mode_mask
)
{
Check(this);
Check(application);
ModeManager
*mode_manager = application->GetModeManager();
Check(mode_manager);
mode_manager->RemoveModeMask(remove_mode_mask);
mode_manager->AddModeMask(add_mode_mask);
activeDestination = NULL;
activeReceiver = NULL;
activeMessageID = (Receiver::MessageID) 0;
activeDependant = NULL;
Check_Fpu();
}
void
ControlsManager::AddOrEraseMappableButton(
int /*button_number*/,
ModeMask /*mode_mask*/
)
{
Check(this);
Check_Fpu();
}
//
//############################################################################
// TestInstance
//
//############################################################################
//
Logical
ControlsManager::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//
//############################################################################
// Shutdown
//
//############################################################################
//
void
ControlsManager::Shutdown()
{
ControlsManager
*controls_manager;
for(
controls_manager = headControlsManager;
controls_manager != NULL;
controls_manager = controls_manager->nextControlsManager
)
{
controls_manager->LocalShutdown();
}
Check_Fpu();
}
void
ControlsManager::LocalShutdown()
{
Check(this);
Check_Fpu();
}
//#########################################################################
//############################# ControlsString ############################
//#########################################################################
int
ControlsString::nextID = 1;
ControlsString::ControlsString(
const char *new_string,
int keypad_unit_number,
Receiver *receiver_pointer,
Receiver::MessageID message_id,
int user_code
):
Node(RegisteredClass::ControlsStringClassID)
{
Test_Tell(
"ControlsString creator('" new_string <<
"'," << keypad_unit_number <<
"," << receiver_pointer <<
"," << message_id <<
")\n"
);
Check_Pointer(this);
Check_Pointer(new_string);
Check(receiver_pointer);
//----------------------------------------------
// Assign unique ID
//----------------------------------------------
id = nextID++;
matchStringPointer = new_string;
keypadUnitNumber = keypad_unit_number;
//----------------------------------------------
// Save message data
//----------------------------------------------
receiverPointer = receiver_pointer;
messageID = message_id;
userCode = user_code;
//----------------------------------------------
// Clear the buffer
//----------------------------------------------
string[0] = '\0';
stringLength = 0;
Check_Fpu();
}
ControlsString::~ControlsString()
{
Test_Tell("ControlsString destructor\n");
Check(this);
Check_Fpu();
}
Logical
ControlsString::TestInstance() const
{
return True;
}
void
ControlsString::Update(int keypad_unit_number, ControlsKey new_key)
{
Test_Tell(
"ControlsString::Update(" << keypad_unit_number <<
"," << new_key <<
"\n"
);
Check(this);
//----------------------------------------------
// Update only if proper keyboard unit
//----------------------------------------------
if (keypad_unit_number == keypadUnitNumber)
{
//--------------------------------------
// Get string length
//--------------------------------------
Check_Pointer(matchStringPointer);
int
length = strlen(matchStringPointer);
if (length > maxStringLength)
{
length = maxStringLength;
}
if (stringLength > length) // in case matchString changes
{
stringLength = length;
string[stringLength] = '\0';
}
//--------------------------------------
// Update string buffer
//--------------------------------------
if (stringLength < length)
{
string[stringLength++] = (char) new_key;
string[stringLength] = '\0';
}
else
{
if (length > 1)
{
memmove(&string[0],&string[1], length-1);
}
string[length-1] = (char) new_key;
}
Test_Tell("string=" << string << "\n");
//--------------------------------------
// Check for match
//--------------------------------------
if (strnicmp(string, matchStringPointer, length) == 0)
{
Test_Tell(
"ControlsString::Update, '" << matchStringPointer <<
"' matched!\n"
);
//--------------------------------------
// Match found, send message
//--------------------------------------
Check(receiverPointer);
Check(application);
ControlsStringMessage
message(messageID, this->userCode);
receiverPointer->Dispatch(&message);
//--------------------------------------
// Clear the string
//--------------------------------------
string[0] = '\0';
stringLength = 0;
}
}
Check_Fpu();
}
//#########################################################################
//######################## ControlsStringManager ##########################
//#########################################################################
ControlsStringManager::ControlsStringManager() :
Node(RegisteredClass::ControlsStringManagerClassID),
instanceList(this)
{
Test_Tell("ControlsStringManager creator\n");
Check_Pointer(this);
}
ControlsStringManager::~ControlsStringManager()
{
Test_Tell("ControlsStringManager destructor\n");
Check(this);
//----------------------------------------------
// Remove all ControlStrings
//----------------------------------------------
Remove(0);
Check_Fpu();
}
Logical
ControlsStringManager::TestInstance() const
{
return True;
}
ControlsStringID
ControlsStringManager::Add(
const char *new_string,
int keypad_unit_number,
Receiver *receiver_pointer,
Receiver::MessageID message_id,
int user_code
)
{
Test_Tell("ControlsStringManager::Add(" << new_string <<
"," << keypad_unit_number <<
"," << receiver_pointer <<
"," << message_id <<
"\n"
);
Check(this);
Check_Pointer(new_string);
Check(receiver_pointer);
//----------------------------------------------
// Create the ControlsString
//----------------------------------------------
ControlsString
*string_item = new ControlsString(
new_string,
keypad_unit_number,
receiver_pointer,
message_id,
user_code
);
Check(string_item);
Register_Object(string_item);
//----------------------------------------------
// Add to the instance list
//----------------------------------------------
instanceList.Add(string_item);
//----------------------------------------------
// return the new string's (unique) ID
//----------------------------------------------
Check_Fpu();
return string_item->id;
}
void
ControlsStringManager::Remove(ControlsStringID string_id)
{
Test_Tell("ControlsStringManager::Remove(" << string_id << ")\n");
Check(this);
ChainIteratorOf<ControlsString*>
i(instanceList);
ControlsString
*controls_string;
//----------------------------------------------
// Search for the given ID (or universal match)
//----------------------------------------------
while ((controls_string=i.ReadAndNext()) != NULL)
{
Check(controls_string);
if (
(string_id == 0) ||
(controls_string->id == string_id)
)
{
Unregister_Object(controls_string);
delete controls_string;
//------------------------------------------
// If this is not a 'universal' remove,
// we're done (ID's are unique)
//------------------------------------------
if (string_id != 0)
{
break;
}
}
}
Check_Fpu();
}
void
ControlsStringManager::Update(
int keypad_unit_number,
ControlsKey new_key
)
{
Test_Tell("ControlsStringManager::Update(" << keypad_unit_number <<
"," << new_key <<
")\n"
);
Check(this);
//--------------------------------------
// Update all matching string items
//--------------------------------------
ChainIteratorOf<ControlsString*>
i(instanceList);
ControlsString
*controls_string;
while ((controls_string=i.ReadAndNext()) != NULL)
{
Check(controls_string);
controls_string->Update(keypad_unit_number, new_key);
}
Check_Fpu();
}
#if defined(TEST_CLASS)
#include "controls.tcp"
#endif
+910
View File
@@ -0,0 +1,910 @@
#pragma once
#include "style.h"
class Controls;
class ControlsInstance;
class ControlsMappingGroup;
struct ControlsMapping;
class ControlsOwner;
class ControlsManager;
#include "slot.h"
#include "chain.h"
#include "vector2d.h"
#include "receiver.h"
#include "simulate.h"
#include "mode.h"
//########################################################################
//######################## Basic control typedefs ########################
//########################################################################
typedef Scalar ControlsScalar;
typedef Vector2DOf<Scalar> ControlsJoystick;
typedef int ControlsKey;
typedef int ControlsButton; // negative for release
typedef Vector2DOf<int> ControlsMouse;
//#########################################################################
//######################### ControlsInstance ##############################
//#########################################################################
// The ControlsInstance object exists to serve the ControlsMappingGroup
// object. It maintains one instance of a mapping from a physical
// input device to either an entity event message or a value.
class ControlsInstance :
public Node
{
friend class ControlsMappingGroup;
friend class ControlsManager; // required for testing
friend class L4MappableButtonManager;
public:
ControlsInstance(
ClassID class_id,
ModeMask mode_mask,
Plug *dependant
);
~ControlsInstance();
ModeMask
modeMask; // lots of objects (and templates) need access to this
protected:
virtual void Update(void *data_source);
SlotOf<Plug*>
dependantPlug;
void
ReleaseLinkHandler(
Socket *socket,
Plug *plug
);
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceDirectOf ~~~~~~~~~~~~~~~~~~
template <class T> class ControlsInstanceDirectOf:
public ControlsInstance
{
friend class ControlsMappingGroup;
friend class ControlsManager; // required for testing
public:
ControlsInstanceDirectOf(
ModeMask mode_mask,
T* data_pointer,
Plug *dependant
);
ControlsInstanceDirectOf(
ControlsInstanceDirectOf<T> *original
);
~ControlsInstanceDirectOf();
Logical
TestInstance() const;
// protected:
void Update(void *data_source);
T *dataPointer;
};
template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
ModeMask mode_mask,
T* data,
Plug *dependant
):
ControlsInstance(
DirectControlsInstanceClassID,
mode_mask,
dependant
),
dataPointer(data)
{}
template <class T> ControlsInstanceDirectOf<T>::ControlsInstanceDirectOf(
ControlsInstanceDirectOf<T> *original
):
ControlsInstance(
DirectControlsInstanceClassID,
original->modeMask,
original->dependantPlug.GetCurrent()
),
dataPointer(original->dataPointer)
{}
template <class T> ControlsInstanceDirectOf<T>::~ControlsInstanceDirectOf()
{}
template <class T> void
ControlsInstanceDirectOf<T>::Update(void *data_source)
{
Check(this);
Check_Pointer(data_source);
Check_Pointer(dataPointer);
*dataPointer = *(T*)data_source;
Verify(*dataPointer == *(T*)data_source);
Check_Fpu();
}
template <class T> Logical
ControlsInstanceDirectOf<T>::TestInstance() const
{
Check_Pointer(this);
Check_Pointer(dataPointer);
Check_Fpu();
return Plug::TestInstance();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ControlsInstanceEventOf ~~~~~~~~~~~~~~~~~~
template <class T> class ControlsInstanceEventOf:
public ControlsInstance
{
friend class ControlsMappingGroup;
friend class ControlsManager; // required for testing
public:
ControlsInstanceEventOf(
ModeMask mode_mask,
Receiver *receiver,
Receiver::MessageID message_id,
Plug *dependant
);
ControlsInstanceEventOf(
ControlsInstanceEventOf<T> *original
);
~ControlsInstanceEventOf();
Logical
TestInstance() const;
// protected:
void Update(void *data_source);
Receiver *receiverPointer;
Receiver::MessageID messageID;
};
template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
ModeMask mode_mask,
Receiver *receiver,
Receiver::MessageID message_id,
Plug *dependant
):
ControlsInstance(
EventControlsInstanceClassID,
mode_mask,
dependant
),
receiverPointer(receiver),
messageID(message_id)
{}
template <class T> ControlsInstanceEventOf<T>::ControlsInstanceEventOf(
ControlsInstanceEventOf<T> *original
):
ControlsInstance(
EventControlsInstanceClassID,
original->modeMask,
original->dependantPlug.GetCurrent()
),
receiverPointer(original->receiverPointer),
messageID(original->messageID)
{}
template <class T> ControlsInstanceEventOf<T>::~ControlsInstanceEventOf()
{}
template <class T> void
ControlsInstanceEventOf<T>::Update(void *data_source)
{
Check(this);
Check_Pointer(data_source);
Check(application);
ReceiverDataMessageOf<T>
update_message(
messageID,
sizeof(ReceiverDataMessageOf<T>),
*(T*)data_source
);
application->Post(
ControlsEventPriority,
receiverPointer,
&update_message
);
}
template <class T> Logical
ControlsInstanceEventOf<T>::TestInstance() const
{
Check_Pointer(this);
Check(receiverPointer);
Check_Fpu();
return Plug::TestInstance();
}
//#########################################################################
//######################### ControlsMappingGroup ##########################
//#########################################################################
// The ControlsMappingGroup object maintains a group of ControlInstances.
//
// ControlsMappingGroup.Update() will call ControlsInstance.Update()
// for each instance in the group.
class ControlsMappingGroup :
public Node
{
friend class ControlsManager; // required for testing
public:
ControlsMappingGroup();
~ControlsMappingGroup();
void
Add(ControlsInstance *mapping)
{
Check(this);
Check(mapping);
instanceList.Add(mapping);
}
virtual void
Remove(ModeMask mode_mask);
virtual void
Update(void *value, ModeMask mode_mask);
Logical // returns true if at least one button active
CurrentFilterStatus(ModeMask mode_mask);
protected:
ChainOf<ControlsInstance*>
instanceList;
};
//#########################################################################
//########################## ControlsUpdateManager ########################
//#########################################################################
template <class T> class ControlsUpdateManager :
public ControlsMappingGroup
{
public:
ControlsUpdateManager();
~ControlsUpdateManager();
Logical
TestInstance() const;
virtual ControlsInstance*
Add(
ModeMask mode_mask,
Receiver *receiver_pointer,
Receiver::MessageID id,
Plug *dependant
);
virtual ControlsInstance*
Add(
ModeMask mode_mask,
T *destination,
Plug *dependant
);
virtual ControlsInstance*
AddOrErase(
ModeMask mode_mask,
Receiver *target,
Receiver::MessageID message_ID,
Plug *dependant
);
virtual ControlsInstance*
AddOrErase(
ModeMask mode_mask,
T *destination,
Plug *dependant
);
enum
{
unmapped = 0,
mappedByOthers = 1,
mappedByMe = 2
};
virtual int
GetMapState(
void *direct_destination,
Receiver *event_receiver,
Receiver::MessageID message_id,
ModeMask mode_mask
);
virtual void
Update(void *sourcePointer, ModeMask mode_mask);
void
ForceUpdate(T *sourcePointer, ModeMask mode_mask);
T
previousValue;
};
template <class T> Logical
ControlsUpdateManager<T>::TestInstance() const
{
return True;
}
template <class T>
ControlsUpdateManager<T>::ControlsUpdateManager()
: ControlsMappingGroup()
{
}
template <class T> ControlsUpdateManager<T>::~ControlsUpdateManager()
{
}
template <class T> void
ControlsUpdateManager<T>::Update(
void * source_pointer,
ModeMask mode_mask
)
{
Check(this);
Check_Pointer(source_pointer);
if (previousValue != *(T*) source_pointer)
{
ForceUpdate((T*)source_pointer, mode_mask);
}
Check_Fpu();
}
template <class T> void
ControlsUpdateManager<T>::ForceUpdate(
T* source_pointer,
ModeMask mode_mask
)
{
Check(this);
Check_Pointer(source_pointer);
previousValue = *source_pointer;
ControlsMappingGroup::Update(source_pointer, mode_mask);
Check_Fpu();
}
template <class T> ControlsInstance*
ControlsUpdateManager<T>::Add(
ModeMask mode_mask,
Receiver *receiver_pointer,
Receiver::MessageID message_id,
Plug *dependant
)
{
Check(this);
Check(receiver_pointer);
ControlsInstanceEventOf<T> *instance =
new ControlsInstanceEventOf<T>(
mode_mask,
receiver_pointer,
message_id,
dependant
);
Register_Object(instance);
ControlsMappingGroup::Add(instance);
Check_Fpu();
return instance;
}
template <class T> ControlsInstance*
ControlsUpdateManager<T>::Add(
ModeMask mode_mask,
T *destination,
Plug *dependant
)
{
Check(this);
Check_Pointer(destination);
ControlsInstanceDirectOf<T> *instance =
new ControlsInstanceDirectOf<T>(
mode_mask,
destination,
dependant
);
Register_Object(instance);
ControlsMappingGroup::Add(instance);
Check_Fpu();
return instance;
}
template <class T> ControlsInstance*
ControlsUpdateManager<T>::AddOrErase(
ModeMask mode_mask,
Receiver *receiver_pointer,
Receiver::MessageID message_id,
Plug *dependant
)
{
Check(this);
Check(receiver_pointer);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
ControlsInstanceEventOf<T>
*event_mapping;
//-----------------------------------------------
// Search through all mappings
//-----------------------------------------------
while ((controls_instance=i.ReadAndNext()) != NULL)
{
Check(controls_instance);
//-----------------------------------------------
// Process only the event mappings
//-----------------------------------------------
if (controls_instance->GetClassID() == EventControlsInstanceClassID)
{
event_mapping = (ControlsInstanceEventOf<T> *)controls_instance;
Check(event_mapping);
//-----------------------------------------------
// Process only if the target is correct, AND
// if the mapping is allowed under the given
// mode mask
//-----------------------------------------------
if (
(event_mapping->receiverPointer == receiver_pointer) &&
(event_mapping->messageID == message_id) &&
(event_mapping->modeMask & mode_mask)
)
{
//-----------------------------------------------
// Found! Remove mode enable bit(s)
//-----------------------------------------------
event_mapping->modeMask &= ~mode_mask;
//-----------------------------------------------
// If this mapping no longer matches ANY mode
// (i.e., all bits cleared), delete it, 'cuz
// it doesn't do anything anymore.
//-----------------------------------------------
if (event_mapping->modeMask == (ModeMask)0)
{
Unregister_Object(event_mapping);
delete event_mapping;
}
//-----------------------------------------------
// We found the match, break out of the loop
//-----------------------------------------------
break;
}
}
}
//----------------------------------------------------------
// If the mapping wasn't found (controls_instance == NULL),
// then create one.
//----------------------------------------------------------
if (controls_instance == NULL)
{
event_mapping =
new ControlsInstanceEventOf<T>(
mode_mask,
receiver_pointer,
message_id,
dependant
);
Register_Object(event_mapping);
ControlsMappingGroup::Add(event_mapping);
Check_Fpu();
return event_mapping;
}
Check_Fpu();
return NULL;
}
template <class T> ControlsInstance*
ControlsUpdateManager<T>::AddOrErase(
ModeMask mode_mask,
T *destination,
Plug *dependant
)
{
Check(this);
Check_Pointer(destination);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
ControlsInstanceDirectOf<T>
*direct_mapping;
//-----------------------------------------------
// Search through all mappings
//-----------------------------------------------
while ((controls_instance=i.ReadAndNext()) != NULL)
{
Check(controls_instance);
//-----------------------------------------------
// Process only the direct mappings
//-----------------------------------------------
if (controls_instance->GetClassID() == DirectControlsInstanceClassID)
{
direct_mapping = (ControlsInstanceDirectOf<T> *)controls_instance;
Check(direct_mapping);
//-----------------------------------------------
// Process only if the target is correct, AND
// if the mapping is allowed under the given
// mode mask
//-----------------------------------------------
if (
(direct_mapping->dataPointer == destination) &&
(direct_mapping->modeMask & mode_mask)
)
{
//-----------------------------------------------
// Found! Remove mode enable bit(s)
//-----------------------------------------------
direct_mapping->modeMask &= ~mode_mask;
//-----------------------------------------------
// If this mapping no longer matches ANY mode
// (i.e., all bits cleared), delete it, 'cuz
// it doesn't do anything anymore.
//-----------------------------------------------
if (direct_mapping->modeMask == (ModeMask)0)
{
Unregister_Object(direct_mapping);
delete direct_mapping;
}
//-----------------------------------------------
// We found the match, break out of the loop
//-----------------------------------------------
break;
}
}
}
//----------------------------------------------------------
// If the mapping wasn't found (controls_instance == NULL),
// then create one.
//----------------------------------------------------------
if (controls_instance == NULL)
{
direct_mapping =
new ControlsInstanceDirectOf<T>(
mode_mask,
destination,
dependant
);
Register_Object(direct_mapping);
ControlsMappingGroup::Add(direct_mapping);
Check_Fpu();
return direct_mapping;
}
Check_Fpu();
return NULL;
}
template <class T> int
ControlsUpdateManager<T>::GetMapState(
void *direct_destination,
Receiver *event_receiver,
Receiver::MessageID message_id,
ModeMask mode_mask
)
{
Check(this);
ChainIteratorOf<ControlsInstance*>
i(instanceList);
ControlsInstance
*controls_instance;
int
map_state = 0;
//-----------------------------------------------
// Search through all mappings
//-----------------------------------------------
while ((controls_instance=i.ReadAndNext()) != NULL)
{
Check(controls_instance);
//------------------------------------
// Process if allowed mode
//------------------------------------
if (controls_instance->modeMask & mode_mask)
{
//------------------------------------
// Process direct mappings
//------------------------------------
if (controls_instance->GetClassID() ==
DirectControlsInstanceClassID
)
{
ControlsInstanceDirectOf<T>
*direct_mapping = (ControlsInstanceDirectOf<T> *)
controls_instance;
Check(direct_mapping);
if (direct_mapping->dataPointer == direct_destination)
{
map_state |= mappedByMe;
}
else
{
map_state |= mappedByOthers;
}
}
//------------------------------------
// Process event mappings
//------------------------------------
else
{
Verify(controls_instance->GetClassID() ==
EventControlsInstanceClassID
);
ControlsInstanceEventOf<T>
*event_mapping = (ControlsInstanceEventOf<T> *)
controls_instance;
Check(event_mapping);
if (
(event_mapping->receiverPointer == event_receiver) &&
(event_mapping->messageID == message_id)
)
{
map_state |= mappedByMe;
}
else
{
map_state |= mappedByOthers;
}
}
}
}
Check_Fpu();
return map_state;
}
//#########################################################################
//############################ ControlsManager ############################
//#########################################################################
class ControlsManager:
public Receiver
{
friend class ControlsMappingGroup; // for access to groupEnable
//-------------------------------------------------------------------
// Shared data support
//-------------------------------------------------------------------
public:
static Derivation *GetClassDerivations();
// static SharedData DefaultData;
//-------------------------------------------------------------------
// Construction/destruction/verification
//-------------------------------------------------------------------
protected:
ControlsManager(
ClassID class_ID = ControlsManagerClassID,
SharedData &shared_data = ControlsManager::DefaultData
);
public:
~ControlsManager();
unsigned int
UniqueOwnerID()
{
if ((nextOwnerID+1)==0) { ++nextOwnerID; }
Check_Fpu();
return (++nextOwnerID);
}
virtual void
Remove(ModeMask mode_mask);
virtual void
Execute();
static Logical
TestClass();
Logical
TestInstance() const;
static void
Shutdown();
virtual void
LocalShutdown();
//-------------------------------------------------------------------
// Mode control
//-------------------------------------------------------------------
virtual void
StartMappableButtonsConfigure(
void *active_direct_target,
Receiver *target,
Plug *dependant,
Receiver::MessageID active_message_id,
ModeMask remove_mode_mask,
ModeMask add_mode_mask
);
virtual void
StopMappableButtonsConfigure(
ModeMask remove_mode_mask,
ModeMask add_mode_mask
);
virtual void
AddOrEraseMappableButton(
int button_number,
ModeMask mode_mask
);
//-------------------------------------------------------------------
// Gauge support
//-------------------------------------------------------------------
void
*activeDestination;
Receiver
*activeReceiver;
Receiver::MessageID
activeMessageID;
Plug
*activeDependant;
private:
static ControlsManager
*headControlsManager;
ControlsManager
*nextControlsManager;
static unsigned int
nextOwnerID;
};
//#########################################################################
//############################ ControlsMapping ############################
//#########################################################################
// Used by tools for building/reading control map streams
struct ControlsMapping
{
public:
enum {
DirectMapping=0,
EventMapping=1
};
Enumeration
controlsGroup,
controlsElement,
mappingType,
subsystemID;
ModeMask
modeMask;
union
{
Simulation::AttributeID attributeID;
Receiver::MessageID messageID;
};
};
//#########################################################################
//############################ ControlsString #############################
//#########################################################################
typedef int ControlsStringID;
class ControlsString :
public Node
{
friend class ControlsStringManager;
protected:
enum
{
maxStringLength=16
};
ControlsString(
const char *new_string,
int keypad_unit_number,
Receiver *receiver_pointer,
Receiver::MessageID message_id,
int user_code
);
~ControlsString();
Logical
TestInstance() const;
void
Update(int keypad_unit_number, ControlsKey new_key);
ControlsStringID
id;
const char
*matchStringPointer;
char
string[maxStringLength+1];
int
stringLength,
keypadUnitNumber,
userCode;
Receiver
*receiverPointer;
Receiver::MessageID
messageID;
static ControlsStringID
nextID;
};
//#########################################################################
//######################## ControlsStringMessage ##########################
//#########################################################################
// This is sent by the controlsString object when a match is detected
class ControlsStringMessage:
public Receiver::Message
{
public:
ControlsStringMessage(
Receiver::MessageID message_ID,
int user_code
):
Receiver::Message(message_ID, sizeof(ControlsStringMessage)),
userCode(user_code)
{}
int
userCode;
};
//#########################################################################
//######################## ControlsStringManager ##########################
//#########################################################################
// This class matches strings from a keypad. When the given string
// is matched, it sends an event to the given receiver.
class ControlsStringManager :
public Node
{
public:
ControlsStringManager();
~ControlsStringManager();
Logical
TestInstance() const;
ControlsStringID
Add(
const char *new_string,
int keypad_unit_number,
Receiver *receiver_pointer,
Receiver::MessageID id,
int user_code = 0
);
void
Remove(ControlsStringID string_id);
void
Update(int keypad_unit_number, ControlsKey new_key);
ChainOf<ControlsString*>
instanceList;
};
+444
View File
@@ -0,0 +1,444 @@
#include "munga.h"
#include "cstr.h"
#include "memstrm.h"
//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
+644
View File
@@ -0,0 +1,644 @@
#pragma once
#include "style.h"
//namespace Munga
//{
class CStringRepresentation;
class CString;
class MemoryStream;
class StringRepresentation;
class pString;
class pcString;
typedef StringRepresentation& rString;
typedef const StringRepresentation& rcString;
class StringRepresentation
{
private:
char firstByte;
StringRepresentation();
StringRepresentation(rcString string);
public:
const char& operator[](size_t index) const
{
Check(this);
return (&firstByte)[index];
}
char& operator[](size_t index)
{
Check(this);
return (&firstByte)[index];
}
operator const char*() const
{
Check(this);
return &firstByte;
}
operator char*()
{
Check(this);
return &firstByte;
}
size_t GetLength() const
{
Check(this);
return strlen(&firstByte);
}
public:
rString operator=(const char* string)
{
Check(this);
Check_Pointer(string);
strcpy(&firstByte, string);
return *this;
}
rString operator=(rcString string)
{
Check(this);
Check(&string);
strcpy(&firstByte, &string.firstByte);
return *this;
}
rString operator=(char byte)
{
Check(this);
firstByte = byte;
return *this;
}
rString operator+=(const char* string)
{
Check(this);
Check_Pointer(string);
strcat(&firstByte, string);
return *this;
}
rString operator+=(char chr);
public:
int Compare(const char *string) const { return strcmp(&firstByte, string); }
int Compare(const char *string, size_t length) const { return strncmp(&firstByte, string, length); }
int CaselessCompare(const char *string) const { return stricmp(&firstByte, string); }
int CaselessCompare(const char *string, size_t length) const { return strnicmp(&firstByte, string, length); }
Logical operator<(const char* string) const { return Compare(string) < 0; }
Logical operator<=(const char* string) const { return Compare(string) <= 0; }
Logical operator>(const char* string) const { return Compare(string) > 0; }
Logical operator>=(const char* string) const { return Compare(string) >= 0; }
Logical operator==(const char* string) const { return Compare(string) == 0; }
Logical operator!=(const char* string) const { return Compare(string) != 0; }
Logical operator<(char chr) const { return firstByte < chr; }
Logical operator<=(char chr) const { return firstByte <= chr; }
Logical operator>(char chr) const { return firstByte > chr; }
Logical operator>=(char chr) const { return firstByte >= chr; }
Logical operator==(char chr) const { return firstByte == chr; }
Logical operator!=(char chr) const { return firstByte != chr; }
public:
friend std::ostream& operator <<(std::ostream &strm, rcString str) { return strm << &str.firstByte; }
friend MemoryStream& MemoryStream_Read(MemoryStream* stream, StringRepresentation *str);
friend MemoryStream& MemoryStream_Write(MemoryStream* stream, const StringRepresentation *str);
public:
#if defined(USE_SIGNATURE)
friend int Is_Signature_Bad(const StringRepresentation *p);
#endif
Logical TestInstance() const { return true; }
};
class pString SIGNATURED
{
friend class pcString;
protected:
StringRepresentation* stringText;
public:
pString(char *string = NULL) { stringText = (StringRepresentation*)string; }
pString(rString string) { stringText = &string; }
pString(const pString& string) { stringText = string.stringText; }
public:
pString& operator= (char *string)
{
stringText = (StringRepresentation*)string;
return *this;
}
pString& operator= (rString string)
{
stringText = &string;
return *this;
}
pString& operator= (const pString& string)
{
stringText = string.stringText;
return *this;
}
public:
pString& operator++()
{
++SKIPPY_CAST(char*, stringText);
return *this;
}
pString operator++(int) { return pString(SKIPPY_CAST(char*,stringText)++); }
pString& operator--()
{
--SKIPPY_CAST(char*,stringText);
return *this;
}
pString operator--(int) { return pString(SKIPPY_CAST(char*, stringText)--); }
public:
rString operator*() const { return *stringText; }
StringRepresentation* operator->() const { return stringText; }
char& operator[](size_t index) const
{
Check(this);
return (*stringText)[index];
}
operator char*() const
{
Check(this);
return (char*)stringText;
}
Logical operator!() const { return !stringText; }
char** GetTextPtr() { return (char**)&stringText; }
public:
friend MemoryStream& MemoryStream_Read(MemoryStream* stream, pString str) { return MemoryStream_Read(stream, str.stringText); }
public:
Logical TestInstance() const { return true; }
};
class pcString SIGNATURED
{
protected:
const StringRepresentation* stringText;
public:
pcString(const char *string = NULL) { stringText = (const StringRepresentation*)string; }
pcString(rcString string) { stringText = &string; }
pcString(const pString& string) { stringText = string.stringText; }
pcString(const pcString& string) { stringText = string.stringText; }
public:
pcString& operator=(const char *string)
{
stringText = (const StringRepresentation*)string;
return *this;
}
pcString& operator=(rcString string)
{
stringText = &string;
return *this;
}
pcString& operator=(const pString& string)
{
stringText = string.stringText;
return *this;
}
pcString& operator=(const pcString& string)
{
stringText = string.stringText;
return *this;
}
public:
pcString& operator++()
{
++SKIPPY_CAST(const char*, stringText);
return *this;
}
pcString operator++(int) { return pcString(SKIPPY_CAST(const char*, stringText)++); }
pcString& operator--()
{
--SKIPPY_CAST(const char*, stringText);
return *this;
}
pcString operator--(int) { return pcString(SKIPPY_CAST(const char*, stringText)--); }
public:
rcString operator*() const { return *stringText; }
const StringRepresentation* operator->() const { return stringText; }
const char& operator[](size_t index) const
{
Check(this);
return (*stringText)[index];
}
operator const char*() const
{
Check(this);
return (const char*)stringText;
}
Logical operator!() const { return !stringText; }
const char** GetTextPtr() { return (const char**)&stringText; }
public:
Logical TestInstance() const { return true; }
};
void Convert_From_Ascii(const char* str, char* value);
void Convert_From_Ascii(const char* str, Byte* value);
void Convert_From_Ascii(const char* str, short* value);
void Convert_From_Ascii(const char* str, Word* value);
void Convert_From_Ascii(const char* str, int* value);
void Convert_From_Ascii(const char* str, unsigned* value);
void Convert_From_Ascii(const char* str, long* value);
void Convert_From_Ascii(const char* str, LWord* value);
class CStringRepresentation SIGNATURED
{
friend CString;
friend CString operator + (const CString &str1, const CString &str2);
friend CString operator + (const CString &str1, char ch);
friend MemoryStream& MemoryStream_Read(MemoryStream* stream, CString *str);
friend void Convert_From_Ascii(const char *str, CString *value);
friend CStringRepresentation operator + (const CStringRepresentation &str1, const CStringRepresentation &str2);
friend CStringRepresentation operator + (const CStringRepresentation &str1, char ch);
private:
CStringRepresentation();
CStringRepresentation(const CStringRepresentation &str);
CStringRepresentation(const char *cstr);
public:
~CStringRepresentation();
Logical TestInstance() const;
private:
size_t Length() const;
size_t Size() const;
private:
operator char*() const;
CStringRepresentation operator = (const CStringRepresentation &str);
CStringRepresentation operator = (const char *cstr);
void operator += (const CStringRepresentation &str);
void operator += (char ch);
int Compare(const CStringRepresentation &str) const;
int operator < (const CStringRepresentation &str) const;
int operator > (const CStringRepresentation &str) const;
int operator <= (const CStringRepresentation &str) const;
int operator >= (const CStringRepresentation &str) const;
int operator == (const CStringRepresentation &str) const;
int operator != (const CStringRepresentation &str) const;
char operator [] (size_t pos) const;
CStringRepresentation GetNthToken(size_t nth_token, char *delimiters = NULL) const;
#if 0
void ToUpper();
void ToLower();
#endif
friend std::ostream& operator << (std::ostream &strm, const CStringRepresentation &str);
friend MemoryStream& MemoryStream_Read(MemoryStream* stream, CStringRepresentation *str);
friend MemoryStream& MemoryStream_Write(MemoryStream* stream, const CStringRepresentation& str);
friend void Convert_From_Ascii(const char *str, CStringRepresentation *value);
private:
void IncrementReferenceCount();
void DecrementReferenceCount();
private:
static size_t allocationIncrement;
static size_t CalculateSize(size_t needed);
size_t stringSize;
size_t stringLength;
char *stringText;
int referenceCount;
};
inline size_t CStringRepresentation::Length() const
{
Check(this);
return stringLength;
}
inline size_t CStringRepresentation::Size() const
{
Check(this);
return stringSize;
}
inline CStringRepresentation::operator char *() const
{
Check(this);
return stringText;
}
inline void CStringRepresentation::operator += (const CStringRepresentation &str)
{
Check(this);
*this = *this + str;
}
inline void CStringRepresentation::operator +=(char ch)
{
Check(this);
*this = *this + ch;
}
inline int CStringRepresentation::operator <(const CStringRepresentation &str) const
{
return (Compare(str) < 0);
}
inline int CStringRepresentation::operator >(const CStringRepresentation &str) const
{
return (Compare(str) > 0);
}
inline int CStringRepresentation::operator <=(const CStringRepresentation &str) const
{
return !(Compare(str) > 0);
}
inline int CStringRepresentation::operator >=(const CStringRepresentation &str) const
{
return !(Compare(str) < 0);
}
inline int CStringRepresentation::operator ==(const CStringRepresentation &str) const
{
return (Compare(str) == 0);
}
inline int CStringRepresentation::operator !=(const CStringRepresentation &str) const
{
return (Compare(str) != 0);
}
inline char CStringRepresentation::operator [](size_t pos) const
{
Check(this);
return (pos >= stringLength) ? ('\x00') : (stringText[pos]);
}
inline std::ostream& operator << (std::ostream &strm, const CStringRepresentation &str)
{
Check(&str);
strm << str.stringText;
return strm;
}
inline void CStringRepresentation::IncrementReferenceCount()
{
Check(this);
Verify(referenceCoutn >= 0);
referenceCount++;
}
inline void CStringRepresentation::DecrementReferenceCount()
{
Check(this);
Verify(referenceCount > 0);
if (--referenceCount == 0)
{
Unregister_Object(this);
delete this;
}
}
class CString SIGNATURED
{
public:
CString();
CString(const CString &str);
CString(const char *cstr);
~CString();
Logical TestInstance() const;
static Logical TestClass();
public:
size_t Length() const;
size_t Size() const;
public:
operator char*() const;
CString operator = (const CString &str);
CString operator = (const char *cstr);
friend CString operator + (const CString &str1, const CString &str2);
friend CString operator + (const CString &str1, char ch);
void operator += (const CString &str);
void operator += (char ch);
int Compare(const CString &str) const;
int operator < (const CString &str) const;
int operator > (const CString &str) const;
int operator <= (const CString &str) const;
int operator >= (const CString &str) const;
int operator == (const CString &str) const;
int operator != (const CString &str) const;
char operator [] (size_t pos) const;
CString GetNthToken(size_t nth_token, char *delimiters = NULL) const;
friend std::ostream& operator << (std::ostream &strm, const CString &str);
friend MemoryStream& MemoryStream_Read(MemoryStream* stream, CString *str);
friend MemoryStream& MemoryStream_Write(MemoryStream* stream, const CString* str);
friend void Convert_From_Ascii(const char *str, CString *value);
private:
CStringRepresentation *representation;
};
inline CString::CString()
{
representation = new CStringRepresentation;
Register_Object(representation);
representation->IncrementReferenceCount();
Verify(representation->referenceCount == 1);
}
inline CString::CString(const CString &str)
{
Check(&str);
representation = str.representation;
Check(representation);
representation->IncrementReferenceCount();
}
inline CString::CString(const char *cstr)
{
representation = new CStringRepresentation(cstr);
Register_Object(representation);
representation->IncrementReferenceCount();
Verify(representation->referenceCount == 1);
}
inline CString::~CString()
{
Check(representation);
representation->DecrementReferenceCount();
}
inline Logical CString::TestInstance() const
{
Check(representation);
return true;
}
inline size_t CString::Length() const
{
Check(representation);
return representation->Length();
}
inline size_t CString::Size() const
{
Check(representation);
return representation->Size();
}
inline CString::operator char *() const
{
Check(representation);
return representation->stringText;
}
inline CString operator + (const CString &str1, const CString &str2)
{
Check(&str1);
Check(&str2);
CStringRepresentation temp = *str1.representation + *str2.representation;
return CString(temp.stringText);
}
inline CString operator + (const CString &str1, char ch)
{
Check(&str1);
CStringRepresentation temp = *str1.representation + ch;
return CString(temp.stringText);
}
inline void CString::operator +=(const CString &str)
{
Check(this);
Check(&str);
*this = *this + str;
}
inline void CString::operator +=(char ch)
{
Check(this);
*this = *this + ch;
}
inline int CString::Compare(const CString &str) const
{
Check(&str);
Check(representation);
return representation->Compare(*str.representation);
}
inline int CString::operator <(const CString &str) const
{
return (Compare(str) < 0);
}
inline int CString::operator >(const CString &str) const
{
return (Compare(str) > 0);
}
inline int CString::operator <=(const CString &str) const
{
return !(Compare(str) > 0);
}
inline int CString::operator >=(const CString &str) const
{
return !(Compare(str) < 0);
}
inline int CString::operator ==(const CString &str) const
{
return (Compare(str) == 0);
}
inline int CString::operator !=(const CString &str) const
{
return (Compare(str) != 0);
}
inline char CString::operator [](size_t pos) const
{
Check(representation);
return (*representation)[pos];
}
inline CString CString::GetNthToken(size_t nth_token, char *delimiters) const
{
Check(representation);
CStringRepresentation temp = representation->GetNthToken(nth_token, delimiters);
return CString(temp.stringText);
}
inline std::ostream& operator << (std::ostream &strm, const CString &str)
{
Check(&str);
strm << *str.representation;
return strm;
}
inline MemoryStream& MemoryStream_Write(MemoryStream* stream, const CString* str)
{
return MemoryStream_Write(stream, *str->representation);
}
//}
File diff suppressed because it is too large Load Diff
+800
View File
@@ -0,0 +1,800 @@
#include "munga.h"
#pragma hdrstop
#include "segment.h"
#include "exptbl.h"
#include "fileutil.h"
#include "jmover.h"
#include "schain.h"
#include "notation.h"
#include "namelist.h"
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MaterialList::MaterialList() :
materialList(NULL)
{
listIterator = new CStringSocketIterator(materialList);
Register_Object(listIterator);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
MaterialList::~MaterialList()
{
DeletePlugs();
Unregister_Object(listIterator);
delete listIterator;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Damage::Damage()
{
damageAmount = 0.0f;
damageForce = Vector3D::Identity;
surfaceNormal.x = 0.0f;
surfaceNormal.y = 1.0f;
surfaceNormal.z = 0.0f;
impactPoint = Point3D::Identity;
burstCount = 1.0f;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
EntitySegment*
DamageZone::GetCurrentEffectSite(Enumeration effect_site_type)
{
Check(this);
EntitySegment *return_segment;
switch(effect_site_type)
{
Return_Default_Effect:
case DefaultEffectSite:
default:
{
SChainIteratorOf<EntitySegment*> iterator(defaultEffectSiteChain);
Check(iterator.GetCurrent());
return iterator.GetCurrent();
}
case InternalVideoEffectSite:
{
SChainIteratorOf<EntitySegment*> iterator(internalVideoEffectSiteChain);
return_segment = iterator.GetCurrent();
if (return_segment)
{
Check(return_segment);
return return_segment;
}
else
{
goto Return_Default_Effect;
}
}
case ExternalVideoEffectSite:
{
SChainIteratorOf<EntitySegment*> iterator(externalVideoEffectSiteChain);
return_segment = iterator.GetCurrent();
if (return_segment)
{
Check(return_segment);
return return_segment;
}
else
{
goto Return_Default_Effect;
}
}
case InternalAudioEffectSite:
{
SChainIteratorOf<EntitySegment*> iterator(internalAudioEffectSiteChain);
return_segment = iterator.GetCurrent();
if (return_segment)
{
Check(return_segment);
return return_segment;
}
else
{
goto Return_Default_Effect;
}
}
case ExternalAudioEffectSite:
{
SChainIteratorOf<EntitySegment*> iterator(externalAudioEffectSiteChain);
return_segment = iterator.GetCurrent();
if (return_segment)
{
Check(return_segment);
return return_segment;
}
else
{
goto Return_Default_Effect;
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DamageZone::Reset(Logical )
{
SetDamageZoneState(DefaultState);
damageZoneGraphicState.SetState(ExistsGraphicState);
damageLevel = 0.0f;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DamageZone::WriteUpdateRecord(UpdateRecord *update_record)
{
Check(this);
Check_Pointer(update_record);
update_record->damageLevel = damageLevel;
update_record->damageZoneState = damageZoneState.GetState();
update_record->damageZoneGraphicState = damageZoneGraphicState.GetState();
update_record->damageZoneIndex = damageZoneIndex;
update_record->changedFlags = changedFlags;
update_record->recordLength = sizeof(*update_record);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Clear Flags here for MasterInstance DamageZones!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResetChangedFlags();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DamageZone::ReadUpdateRecord(UpdateRecord *update_record)
{
Check(this);
Check_Pointer(update_record);
Verify(damageZoneIndex == update_record->damageZoneIndex);
damageLevel = update_record->damageLevel;
damageZoneState.SetState(update_record->damageZoneState);
damageZoneGraphicState.SetState(update_record->damageZoneGraphicState);
changedFlags = update_record->changedFlags;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DamageZone::DamageZone(Simulation *owner, int damage_zone_index) :
Node(DamageZoneClassID),
materialTable(NULL, False),
damageZoneState(DamageStateCount),
damageZoneGraphicState(GraphicStateCount),
defaultEffectSiteChain(NULL),
internalVideoEffectSiteChain(NULL),
externalVideoEffectSiteChain(NULL),
internalAudioEffectSiteChain(NULL),
externalAudioEffectSiteChain(NULL)
{
Check(owner);
damageZoneIndex = damage_zone_index;
owningSimulation = owner;
damageLevel = 0.0f;
explosionTable = NULL;
for(int ii=0;ii<Damage::DamageTypeCount;ii++)
{
damageScale[ii] = 0.0f;
}
damageZoneName = "TrivialDamageZone_Name";
changedFlags = 0;
Reset();
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DamageZone::DamageZone(
Simulation *owning_simulation,
int damage_zone_index,
MemoryStream *stream
) :
Node(DamageZoneClassID),
materialTable(NULL, False),
damageZoneState(DamageStateCount),
damageZoneGraphicState(GraphicStateCount),
defaultEffectSiteChain(NULL),
internalVideoEffectSiteChain(NULL),
externalVideoEffectSiteChain(NULL),
internalAudioEffectSiteChain(NULL),
externalAudioEffectSiteChain(NULL)
{
Check(owning_simulation);
Check(stream);
owningSimulation = owning_simulation;
damageZoneIndex = damage_zone_index;
damageLevel = 0.0f;
explosionTable = NULL;
Reset();
*stream >> damageZoneName;
if (owningSimulation->IsDerivedFrom(*JointedMover::GetClassDerivations()))
{
JointedMover *jointed_mover = Cast_Object(
JointedMover*,
owningSimulation
);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in all Effect Sites
//~~~~~~~~~~~~~~~~~~~~~~~~~
//
int effect_site_count;
int effect_site_index;
EntitySegment *effect_site_segment;
//
//~~~~~~~~~~~~~~~~~~~~~~~
// Read in External Video
//~~~~~~~~~~~~~~~~~~~~~~~
//
for (int jj=0;jj<EffectSiteCount;++jj)
{
*stream >> effect_site_count;
for(int ii=0;ii<effect_site_count;++ii)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the Site Segment From the Index
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
*stream >> effect_site_index;
effect_site_segment = jointed_mover->GetSegment(effect_site_index);
Check(effect_site_segment);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Add the Segment to the Appropriate Chain
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
switch (jj)
{
case DefaultEffectSite:
defaultEffectSiteChain.Add(effect_site_segment);
break;
case ExternalVideoEffectSite :
externalVideoEffectSiteChain.Add(effect_site_segment);
break;
case InternalVideoEffectSite :
internalVideoEffectSiteChain.Add(effect_site_segment);
break;
case ExternalAudioEffectSite :
externalAudioEffectSiteChain.Add(effect_site_segment);
break;
case InternalAudioEffectSite :
internalAudioEffectSiteChain.Add(effect_site_segment);
break;
}
}
}
}
else
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read in these for consistancy
// and for later improvements for
// not Jointed Mover Objects!
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int filler_int;
for (int jj=0;jj<EffectSiteCount;++jj)
{
*stream >> filler_int;
}
}
*stream >> defaultArmorPoints;
int ii;
for (ii=0; ii<Damage::DamageTypeCount; ii++)
{
*stream >> damageScale[ii];
}
int skeleton_count;
EntitySegment::SkeletonType skl_type;
*stream >> skeleton_count;
for(ii=0;ii<skeleton_count;++ii)
{
*stream >> skl_type;
int material_count;
*stream >> material_count;
if(!material_count)
{
continue;
}
MaterialList *material_list = new MaterialList;
Register_Object(material_list);
for(int jj=0;jj<material_count;++jj)
{
CString new_material;
*stream >> new_material;
MaterialList::CStringPlug *new_plug =
new MaterialList::CStringPlug(new_material);
Register_Object(new_plug);
material_list->Add(new_plug);
}
material_list->First();
materialTable.AddValue(material_list, skl_type);
}
changedFlags = 0;
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DamageZone::~DamageZone()
{
MaterialTableIterator iterator(materialTable);
iterator.DeletePlugs();
if (explosionTable)
{
Unregister_Object(explosionTable);
delete explosionTable;
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ExplosionTable*
DamageZone::CreateExplosionTable(MemoryStream *explosion_stream)
{
Check(this);
explosionTable = new ExplosionTable(explosion_stream);
Register_Object(explosionTable);
Check_Fpu();
return explosionTable;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DamageZone::TakeDamage(Damage &damage)
{
Check(this);
Check_Pointer(&damage);
damageLevel += damage.damageAmount * damageScale[damage.damageType];
Clamp(damageLevel, 0.0f, 1.0f);
SetDamageLevelChangedFlag();
if (damageLevel >= 1.0f)
{
SetDamageZoneState(BurningState);
SetGraphicState(DestroyedGraphicState);
SetGraphicStateChangedFlag();
}
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
DamageZone::TestInstance() const
{
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
DamageZone::CreateStreamedDamageZone(
NotationFile *model_file,
const char *,
NotationFile *skl_file,
CString damage_zone_name,
MemoryStream *damage_zone_stream,
NotationFile *dmg_file,
const ResourceDirectories *directories
)
{
Check_Pointer(damage_zone_name);
Check_Pointer(&damage_zone_stream);
Check_Pointer(directories);
Check(dmg_file);
*damage_zone_stream << damage_zone_name;
//
// Find dzone name in .dmg file
//
if(!dmg_file->PageExists(damage_zone_name))
{
std::cerr << damage_zone_name <<" listed in .skl, does not exist in .dmg file"<<std::endl;
Check_Fpu();
return -1;
}
if (skl_file)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Read and Write All The Effect Sites
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
WriteEffectSegmentIndicies(
damage_zone_stream,
damage_zone_name,
dmg_file,
skl_file,
"DefaultEffectSiteName"
);
WriteEffectSegmentIndicies(
damage_zone_stream,
damage_zone_name,
dmg_file,
skl_file,
"ExternalVideoEffectSiteName"
);
WriteEffectSegmentIndicies(
damage_zone_stream,
damage_zone_name,
dmg_file,
skl_file,
"InternalVideoEffectSiteName"
);
WriteEffectSegmentIndicies(
damage_zone_stream,
damage_zone_name,
dmg_file,
skl_file,
"ExternalAudioEffectSiteName"
);
WriteEffectSegmentIndicies(
damage_zone_stream,
damage_zone_name,
dmg_file,
skl_file,
"InternalAudioEffectSiteName"
);
}
else
{
int zero_int(0);
for(int ii=0;ii<EffectSiteCount;++ii)
{
*damage_zone_stream << zero_int;
}
}
Scalar default_points;
if(!dmg_file->GetEntry(
damage_zone_name,
"WeaponDamagePoints",
&default_points
)
)
{
std::cerr<<damage_zone_name<<" Must have a WeaponDamagePoints"<<std::endl;
return False;
}
if (!default_points)
{
std::cerr<<"DefaultDamagePoints must have a non-zero value !"<<std::endl;
Check_Fpu();
return False;
}
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write default armor values
//~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
*damage_zone_stream << default_points;
//
// Read the damage Points values
//
float point_data;
Scalar modified_armor;
if(!dmg_file->GetEntry(
damage_zone_name,
"CollisionDamagePoints",
&point_data
)
)
{
modified_armor = 1.0f/default_points;
}
else
{
if (point_data == 0.0f)
{
modified_armor = 1.0f/default_points;
}
else
{
modified_armor = 1.0f/point_data;
}
Check_Fpu();
}
*damage_zone_stream << modified_armor;
if(!dmg_file->GetEntry(
damage_zone_name,
"BallisticDamagePoints",
&point_data
)
)
{
modified_armor = 1.0f/default_points;
}
else
{
modified_armor = 1.0f/point_data;
}
*damage_zone_stream << modified_armor;
if(!dmg_file->GetEntry(
damage_zone_name,
"ExplosiveDamagePoints",
&point_data
)
)
{
modified_armor = 1.0f/default_points;
}
else
{
modified_armor = 1.0f/point_data;
}
*damage_zone_stream << modified_armor;
if(!dmg_file->GetEntry(
damage_zone_name,
"LaserDamagePoints",
&point_data
)
)
{
modified_armor = 1.0f/default_points;
}
else
{
modified_armor = 1.0f/point_data;
}
*damage_zone_stream << modified_armor;
if(!dmg_file->GetEntry(
damage_zone_name,
"EnergyDamagePoints",
&point_data
)
)
{
modified_armor = 1.0f/default_points;
}
else
{
modified_armor = 1.0f/point_data;
}
*damage_zone_stream << modified_armor;
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get dzm filename
//~~~~~~~~~~~~~~~~~~~~~~~~~~
//
NameList *dzm_namelist = model_file->MakeEntryList("video","dzm");
if(!dzm_namelist)
{
int zero_scalar(0.0f);
*damage_zone_stream << zero_scalar;
return True;
}
Register_Object(dzm_namelist);
int dzm_filecount;
dzm_filecount = dzm_namelist->EntryCount();
*damage_zone_stream << dzm_filecount;
if(dzm_filecount)
{
NameList::Entry *dzm_fileentry = dzm_namelist->GetFirstEntry();
while(dzm_fileentry)
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// write out the skeleton type of the material
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
//
CString dzm_entry_name;
dzm_entry_name = dzm_fileentry->GetName();
EntitySegment::SkeletonType skeleton_type;
if (! dzm_entry_name.Compare("dzm") )
{
skeleton_type = EntitySegment::SkeletonType_N;
}
else if (! dzm_entry_name.Compare("dzms") )
{
skeleton_type = EntitySegment::SkeletonType_S;
}
else if (! dzm_entry_name.Compare("dzmt") )
{
skeleton_type = EntitySegment::SkeletonType_T;
}
else if (! dzm_entry_name.Compare("dzmo") )
{
skeleton_type = EntitySegment::SkeletonType_O;
}
else if (! dzm_entry_name.Compare("dzma") )
{
skeleton_type = EntitySegment::SkeletonType_A;
}
else if (! dzm_entry_name.Compare("dzmb") )
{
skeleton_type = EntitySegment::SkeletonType_B;
}
else if (! dzm_entry_name.Compare("dzmc") )
{
skeleton_type = EntitySegment::SkeletonType_C;
}
else if (! dzm_entry_name.Compare("dzmd") )
{
skeleton_type = EntitySegment::SkeletonType_D;
}
*damage_zone_stream << skeleton_type;
//
// Get the name of the dzm File
//
char *filename = MakePathedFilename(
directories->videoDirectory,
dzm_fileentry->GetChar()
);
Register_Pointer(filename);
//
// Create a Notation file from the dzm ASCII File
//
NotationFile *dzm_file = new NotationFile(filename);
Register_Object(dzm_file);
NameList *material_list;
material_list = dzm_file->MakeEntryList(damage_zone_name, "material");
int entry_count(0);
if(material_list)
{
Register_Object(material_list);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write out how many materials
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
entry_count = material_list->EntryCount();
*damage_zone_stream << entry_count;
if(entry_count)
{
NameList::Entry *dzm_entry;
dzm_entry = material_list->GetFirstEntry();
Check(dzm_entry);
CString material_name;
while(dzm_entry)
{
material_name = dzm_entry->GetChar();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write out the material name
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
*damage_zone_stream << material_name;
dzm_entry = dzm_entry->GetNextEntry();
}
}
Unregister_Object(material_list);
delete material_list;
}
else
{
*damage_zone_stream << entry_count;
}
dzm_fileentry = dzm_fileentry->GetNextEntry();
Unregister_Pointer(filename);
delete filename;
Unregister_Object(dzm_file);
delete dzm_file;
}
}
Unregister_Object(dzm_namelist);
delete dzm_namelist;
Check_Fpu();
return True;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int
DamageZone::WriteEffectSegmentIndicies(
MemoryStream *damage_zone_stream,
const char *damage_zone_name,
NotationFile *dmg_file,
NotationFile *skl_file,
const char *effect_type
)
{
Check(dmg_file);
Check(skl_file);
Check_Pointer(damage_zone_name);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Make an Entry list for this type of effect Site
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
int effect_count(0);
NameList::Entry *effect_entry;
NameList *effect_namelist = dmg_file->MakeEntryList(damage_zone_name, effect_type);
if (!effect_namelist)
{
//
//~~~~~~~~~~~
// No Entries
//~~~~~~~~~~~
//
*damage_zone_stream << effect_count;
Check_Fpu();
return 1;
}
else
{
Register_Object(effect_namelist);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~
// Write Out number of sites
//~~~~~~~~~~~~~~~~~~~~~~~~~~
//
effect_count = effect_namelist->EntryCount();
*damage_zone_stream << effect_count;
effect_entry = effect_namelist->GetFirstEntry();
CString site_page_name;
int effect_site_index;
while(effect_entry)
{
site_page_name = effect_entry->GetChar();
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get SegmentIndex for this effect site Name
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
effect_site_index =
JointedMover::GetSegmentIndex(site_page_name, skl_file);
if (effect_site_index == -1)
{
std::cerr<<site_page_name<<" not found in skl file !"<<std::endl;
Unregister_Object(effect_namelist);
delete effect_namelist;
return -1;
}
//
//~~~~~~~~~~~~~~~~~~~~
// Write Out the Index
//~~~~~~~~~~~~~~~~~~~~
//
*damage_zone_stream << effect_site_index;
effect_entry = effect_entry->GetNextEntry();
}
Unregister_Object(effect_namelist);
delete effect_namelist;
}
Check_Fpu();
return 1;
}
+384
View File
@@ -0,0 +1,384 @@
#pragma once
#include "point3d.h"
#include "node.h"
#include "normal.h"
#include "cstr.h"
#include "table.h"
#include "schain.h"
#include "simulate.h"
class MaterialList;
class EntitySegment;
class ExplosionTable;
class Simulation;
class MemoryStream;
class NotationFile;
struct ResourceDirectories;
class Entity;
//##########################################################################
//########################### Damage #################################
//##########################################################################
class Damage
{
public:
enum {
CollisionDamageType,
BallisticDamageType,
ExplosiveDamageType,
LaserDamageType,
EnergyDamageType,
DamageTypeCount
};
Enumeration
damageType;
Scalar
damageAmount;
Vector3D
damageForce;
Normal
surfaceNormal;
// impact point should be in the global coordinate space.
Point3D
impactPoint;
//
// burst count should be thought of as number of times
// to apply the damage.
//
int
burstCount;
Damage();
};
//##########################################################################
//######################### MaterialList #############################
//##########################################################################
class MaterialList :
public Plug
{
public:
typedef PlugOf<CString> CStringPlug;
typedef SChainOf<CStringPlug*>
CStringSocket;
typedef SChainIteratorOf<CStringPlug*>
CStringSocketIterator;
protected:
CStringSocketIterator*
listIterator;
CStringSocket
materialList;
public:
MaterialList();
~MaterialList();
void
DeletePlugs()
{Check(this); listIterator->DeletePlugs();}
void
Add(CStringPlug *new_plug)
{Check(this); materialList.Add(new_plug);}
void
First()
{ Check(this);listIterator->First();}
void
Last()
{Check(this); listIterator->Last(); }
CString*
ReadAndNext()
{
Check(this);
if (!listIterator->GetCurrent())
return NULL;
else
return listIterator->ReadAndNext()->GetPointer();
}
CString*
GetCurrent()
{
Check(this);
if (!listIterator->GetCurrent())
return NULL;
else
return listIterator->GetCurrent()->GetPointer();
}
void
Next()
{Check(this); if(listIterator->GetCurrent()) listIterator->Next();}
};
//##########################################################################
//################# DamageZone::UpdateRecord #########################
//##########################################################################
struct DamageZone__UpdateRecord
{
public:
size_t recordLength;
int damageZoneIndex;
Scalar damageLevel;
Enumeration damageZoneState;
Enumeration damageZoneGraphicState;
LWord changedFlags;
};
//##########################################################################
//######################### DamageZone ###############################
//##########################################################################
class DamageZone:
public Node
{
protected:
Simulation*
owningSimulation;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// State Support
//
private:
StateIndicator
damageZoneState;
StateIndicator
damageZoneGraphicState;
public:
enum{
ExistsGraphicState = 0,
DestroyedGraphicState,
GoneGraphicState,
GraphicStateCount
};
enum{
DefaultState = 0,
BurningState,
DamageStateCount
};
StateIndicator*
GetGraphicStatePointer()
{Check(this); return &damageZoneGraphicState;}
Enumeration
GetDamageZoneState()
{Check(this); return damageZoneState.GetState();}
void
SetDamageZoneState(Enumeration new_state)
{Check(this); damageZoneState.SetState(new_state); }
Enumeration
GetGraphicState()
{Check(this); return damageZoneGraphicState.GetState();}
virtual void
SetGraphicState(Enumeration new_state)
{
Check(this);
damageZoneGraphicState.SetState(new_state);
SetGraphicStateChangedFlag();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Flag Support
//
public:
enum {
DamageLevelChangedBit = 2,
GraphicStateChangedBit,
NextBit
};
enum {
DamageLevelChangedFlag = 1 << DamageLevelChangedBit,
GraphicStateChangedFlag = 1 << GraphicStateChangedBit
};
Logical
DamageLevelChanged() const
{Check(this); return ((changedFlags & DamageLevelChangedFlag) != 0); }
Logical
GraphicStateChanged() const
{Check(this); return ((changedFlags & GraphicStateChangedFlag) != 0); }
void
SetDamageLevelChangedFlag()
{Check(this); changedFlags |= DamageLevelChangedFlag; }
void
SetGraphicStateChangedFlag()
{Check(this); changedFlags |= GraphicStateChangedFlag; }
void
ResetChangedFlags()
{Check(this); changedFlags = 0; }
LWord
changedFlags;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update Support
//
public:
typedef DamageZone__UpdateRecord UpdateRecord;
virtual void
ReadUpdateRecord(UpdateRecord *message);
virtual void
WriteUpdateRecord(UpdateRecord *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Material Support
//
public:
typedef TableOf<MaterialList*, Enumeration>
MaterialTable;
typedef TableIteratorOf<MaterialList*, Enumeration>
MaterialTableIterator;
MaterialList*
GetMaterialList(Enumeration skl_type)
{
Check(this);
return materialTable.Find(skl_type);
}
protected:
MaterialTable
materialTable;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Explosion Support
//
protected:
ExplosionTable
*explosionTable;
public:
ExplosionTable*
CreateExplosionTable(MemoryStream *explosion_stream);
ExplosionTable*
GetExplosionTable()
{Check(this); return explosionTable; }
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Effect Support
//
public:
SChainOf<EntitySegment*>
defaultEffectSiteChain,
internalVideoEffectSiteChain,
externalVideoEffectSiteChain,
internalAudioEffectSiteChain,
externalAudioEffectSiteChain;
enum {
DefaultEffectSite,
ExternalVideoEffectSite,
InternalVideoEffectSite,
ExternalAudioEffectSite,
InternalAudioEffectSite,
EffectSiteCount
};
EntitySegment*
GetCurrentEffectSite(Enumeration effect_site_type = DefaultEffectSite);
static int WriteEffectSegmentIndicies(MemoryStream *damage_zone_stream, const char *damage_zone_name, NotationFile *dmg_file, NotationFile *skl_file, const char *effect_type);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Support
//
public:
Simulation*
GetOwningSimulation()
{return owningSimulation;}
int
damageZoneIndex;
Scalar
defaultArmorPoints;
Scalar
damageScale[Damage::DamageTypeCount];
Scalar
damageLevel;
CString damageZoneName;
virtual void
TakeDamage(Damage &damage);
void
Reset(Logical full_reset=True);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction / Destruction Support
//
DamageZone(
Simulation *owner,
int damage_zone_index,
MemoryStream *dzone_res
);
DamageZone(Simulation *owner, int damage_zone_index);
virtual ~DamageZone();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Resource Support
//
static Logical
CreateStreamedDamageZone(
NotationFile *model_file,
const char *model_name,
NotationFile *skl_file,
CString damage_zone_name,
MemoryStream *damage_zone_stream,
NotationFile *dmg_file,
const ResourceDirectories *directories
);
};
+134
View File
@@ -0,0 +1,134 @@
#pragma once
#include <stdio.h>
#if !defined(OLD_DEBUG_LEVEL)
#define OLD_DEBUG_LEVEL 1
#else
#undef OLD_DEBUG_LEVEL
#if DEBUG_LEVEL >= 3
#define OLD_DEBUG_LEVEL 3
#elif DEBUG_LEVEL == 1
#define OLD_DEBUG_LEVEL 1
#elif DEBUG_LEVEL == 0
#define OLD_DEBUG_LEVEL 0
#endif
#endif
#undef DEBUG_LEVEL
#undef Verify
#undef Verify_And_Dump
#undef Dump
#undef Tell
#undef Warn
#undef Warn_And_Dump
#undef Check_Signature
#undef Check_Pointer
#undef Check
#undef Check_Fpu
#undef Fail
#undef Cast_Object
#undef DEBUG_CODE
#undef Mem_Copy
#undef Str_Copy
#undef Str_Cat
#undef Sqrt
#undef Arctan
#undef Arccos
#undef Arcsin
#define DEBUG_LEVEL 1
#define DEBUG_CODE(x) { x }
#define Dump(v)\
(DEBUG_STREAM << __FILE__ "(" << __LINE__ << "): "#v" = " << (v) << endl << flush)
#define Verify(c)\
if (!(c)) {\
Verify_Failed(#c,__FILE__,__LINE__);\
}
#define Verify_And_Dump(c,v)\
if (!(c)) {\
DEBUG_STREAM << __FILE__ "(" << __LINE__ << "): "#v" = " << (v) << endl << std::flush;\
Verify_Failed(#c,__FILE__,__LINE__);\
}
#define Warn(c)\
if (c) {\
DEBUG_STREAM << __FILE__"(" << __LINE__ << "): Warning -> "#c"\n" << flush;\
}
#define Warn_And_Dump(c,v)\
if (c) {\
DEBUG_STREAM << __FILE__ "(" << __LINE__ << "): "#v" = " << (v) << endl << std::flush;\
DEBUG_STREAM << __FILE__"(" << __LINE__ << "): Warning -> "#c"\n" << flush;\
}
#define Tell(m)\
(DEBUG_STREAM << m << flush)
#define Check_Pointer(p) Verify(p)
#define Check_Fpu() Verify(Fpu_Ok())
#define Mem_Copy(destination, source, length, available)\
{\
Check_Pointer(destination);\
Check_Pointer(source);\
memcpy(destination, source, length);\
}
#define Str_Copy(destination, source, available)\
{\
Check_Pointer(destination);\
Check_Pointer(source);\
strcpy(destination, source);\
}
#define Str_Cat(destination, source, available)\
{\
Check_Pointer(destination);\
Check_Pointer(source);\
strcat(destination, source);\
}
#define Sqrt(value)\
((value>=0.0f) ? sqrt(value) : (Fail("Bad parameter to sqrt"),0.0f))
#define Arctan(y,x)\
(\
(!Small_Enough(y) || !Small_Enough(x))\
? atan2((y),(x)) :\
(Fail("Zero Arctan!"),0.0f)\
)
#define Arccos(x)\
(\
((x)>=-1.0f && (x)<=1.0f)\
? acos(x) :\
(Fail("Out of range Arccos!"),0.0f)\
)
#define Arcsin(x)\
(\
((x)>=-1.0f && (x)<=1.0f)\
? asin(x) :\
(Fail("Out of range Arcsin!"),0.0f)\
)
#define Power(x,y)\
(\
((x)<0.0f)\
? (Fail("Out of range Power!"),0.0f) :\
pow(x,y)\
)
#define Check_Signature(p) Check_Pointer(p)
#define Check(p) Check_Pointer(p)
#define Fail(m) Fail_To_Debugger(m,__FILE__,__LINE__)
#define Cast_Object(type, ptr) ((type)(ptr))
+63
View File
@@ -0,0 +1,63 @@
#pragma once
#include <stdio.h>
#if !defined(OLD_DEBUG_LEVEL)
#define OLD_DEBUG_LEVEL 0
#else
#undef OLD_DEBUG_LEVEL
#if DEBUG_LEVEL>=3
#define OLD_DEBUG_LEVEL 3
#elif DEBUG_LEVEL==2
#define OLD_DEBUG_LEVEL 2
#elif DEBUG_LEVEL==1
#define OLD_DEBUG_LEVEL 1
#endif
#endif
#undef DEBUG_LEVEL
#undef Verify
#undef Verify_And_Dump
#undef Warn
#undef Warn_And_Dump
#undef Dump
#undef Tell
#undef Check_Signature
#undef Check_Pointer
#undef Mem_Copy
#undef Str_Copy
#undef Str_Cat
#undef Check
#undef Check_Fpu
#undef Fail
#undef Cast_Object
#undef DEBUG_CODE
#undef Sqrt
#undef Arctan
#undef Arccos
#undef Arcsin
#define DEBUG_LEVEL 0
#define DEBUG_CODE(x)
#define Verify(c)
#define Verify_And_Dump(c,v)
#define Warn(c)
#define Warn_And_Dump(c,v)
#define Dump(v)
#define Tell(m)
#define Check_Pointer(p)
#define Check_Fpu()
#define Mem_Copy(destination, source, length, available) memcpy(destination, source, length)
#define Str_Copy(destination, source, available) strcpy(destination, source);
#define Str_Cat(destination, source, available) strcat(destination, source);
#define Sqrt(value) sqrt(value)
#define Arctan(y,x) atan2(y,x)
#define Arccos(x) acos(x)
#define Arcsin(x) asin(x)
#define Power(x,y) pow(x,y)
#define Check(p)
#define Check_Signature(p)
//#define Fail(m) Fail_To_Debugger(m,__FILE__,__LINE__)
#define Fail(m) abort();
#define Cast_Object(type, ptr) ((type)(ptr))
+309
View File
@@ -0,0 +1,309 @@
#include "munga.h"
#pragma hdrstop
#include "director.h"
#include "mission.h"
#include "player.h"
#include "app.h"
#include "hostmgr.h"
#include "nttmgr.h"
//#############################################################################
// Shared Data support
//
Derivation* CameraDirector::GetClassDerivations()
{ static Derivation classDerivations(Player::GetClassDerivations(), "CameraDirector");
return &classDerivations;
}
CameraDirector::SharedData
CameraDirector::DefaultData(
CameraDirector::GetClassDerivations(),
CameraDirector::MessageHandlers,
CameraDirector::GetAttributeIndex(),
CameraDirector::StateCount,
(Entity::MakeHandler) CameraDirector::Make
);
//#############################################################################
// Messaging Support
//
const Receiver::HandlerEntry
CameraDirector::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(CameraDirector, AttachCameraShip)
};
CameraDirector::MessageHandlerSet
CameraDirector::MessageHandlers(
ELEMENTS(CameraDirector::MessageHandlerEntries),
CameraDirector::MessageHandlerEntries,
Player::GetMessageHandlers()
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraDirector::AttachCameraShipMessageHandler(
AttachCameraShipMessage *in_message
)
{
Check(in_message);
Check(application);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the cameraship ID to attach to
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
HostManager *host = application->GetHostManager();
Check(host);
Entity *entity_ptr = host->GetEntityPointer(in_message->cameraShipID);
Check(entity_ptr);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Get the cameraShip Pointer Object
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraShip *camera_ship;
camera_ship = Cast_Object(CameraShip*, entity_ptr);
Check(this);
Check(camera_ship);
cameraShip = camera_ship;
}
//#############################################################################
// Model Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraDirector::UpdateHUD(
Scalar time_slice
)
{
Check(this);
Check(application);
//
//~~~~~~~~~~~~
// HUD Support
//~~~~~~~~~~~~
//
if (GetGoalEntity())
{
Check(GetGoalEntity());
Player *goal_player = GetGoalEntity()->GetPlayerLink();
if (goal_player)
{
Check(goal_player);
goalPlayerIndex = goal_player->playerBitmapIndex;
}
}
if (
application->GetApplicationState() == Application::StoppingMission ||
application->GetApplicationState() == Application::EndingMission
)
{
displayRankingWindow = False;
return;
}
else if (application->GetSecondsRemainingInGame() <= 30.0f)
{
displayRankingWindow = True;
}
else
{
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Check times for Ranking Window Display
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (displayRankingWindow)
{
timeDisplayed += time_slice;
if(timeDisplayed >= displayIntervalOn)
{
timeTillDisplayed = displayIntervalOff;
displayRankingWindow = False;
}
}
else
{
timeTillDisplayed -= time_slice;
if (timeTillDisplayed <= 0.0f)
{
timeDisplayed = 0.0f;
displayRankingWindow = True;
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraDirector::BeADirector(Scalar time_slice)
{
Check(this);
Player::PlayerSimulation(time_slice);
UpdateHUD(time_slice);
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Time To Cut To a new Player?
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
if (
timeLeftOnPlayer > 0.0f
&& application->GetApplicationState() == Application::RunningMission)
{
timeLeftOnPlayer -= time_slice;
return;
}
Player *top_dog = FindPlayerByRank(0);
if (top_dog)
{
Check(top_dog);
Entity *vehicle = top_dog->GetPlayerVehicle();
if (vehicle)
{
Check(vehicle);
if ((GetGoalEntity() != vehicle))
{
SetGoalEntity(vehicle);
timeLeftOnPlayer = 10.0f;
Check(cameraShip);
CameraShip::DirectionMessage direction_message(
CameraShip::DirectionMessageID,
sizeof(CameraShip::DirectionMessage),
GetGoalEntity()->GetEntityID(),
0.0f,
Point3D::Identity
);
Check(cameraShip);
cameraShip->Dispatch(&direction_message);
}
}
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
CameraDirector::CreateCameraShip(Scalar)
{
CreatePlayerVehicle(localOrigin);
PlayerLinkMessage player_link_message (
PlayerLinkMessageID,
sizeof(PlayerLinkMessage),
this->GetEntityID()
);
Check(playerVehicle);
playerVehicle->Dispatch(&player_link_message);
playerVehicle->DispatchToReplicants(&player_link_message);
SetPerformance(&CameraDirector::BeADirector);
deathCount = 0;
CameraDirector::AttachCameraShipMessage
message(
CameraDirector::AttachCameraShipMessageID,
sizeof(CameraDirector::AttachCameraShipMessage),
playerVehicle->GetEntityID()
);
Dispatch(&message);
}
//#############################################################################
// Construction and Destruction Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraDirector::CameraDirector(
CameraDirector::MakeMessage *creation_message,
CameraDirector::SharedData &virtual_data
) :
Player(creation_message, virtual_data),
goalEntity(this)
{
cameraShip = NULL;
SetValidFlag();
timeLeftOnPlayer = -1.0f;
if (GetInstance() != ReplicantInstance)
{
SetPerformance(&CameraDirector::CreateCameraShip);
}
//
//~~~~~~~~~~~~
// HUD Support
//~~~~~~~~~~~~
//
goalPlayerIndex = -1;
displayRankingWindow = False;
displayIntervalOn = 10.0f;
displayIntervalOff = 15.0f;
timeDisplayed = 0.0f;
timeTillDisplayed = displayIntervalOff;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraDirector*
CameraDirector::Make(MakeMessage *creation_message)
{
return new CameraDirector(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
CameraDirector::~CameraDirector()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Player*
CameraDirector::FindPlayerByRank(int rank_to_find)
{
Check(application);
//
//---------------------------------------
// Get all players from the entity group
//---------------------------------------
//
EntityGroup *player_group =
application->GetEntityManager()->FindGroup("Players");
if(player_group)
{
Player *leading_player;
//
//-----------------------------------------------------
// Iterate through the players find the leading player
//-----------------------------------------------------
//
ChainIteratorOf<Node*> iterator(player_group->groupMembers);
while ((leading_player = (Player*) iterator.ReadAndNext()) != NULL)
{
Check(leading_player);
if (leading_player->playerRanking == rank_to_find)
{
return leading_player;
}
}
}
return NULL;
}
Logical
CameraDirector::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+157
View File
@@ -0,0 +1,157 @@
#pragma once
#include "style.h"
#include "player.h"
#include "schain.h"
#include "camship.h"
#include "graph2d.h"
#include "slot.h"
//##########################################################################
//################# CameraDirector::AttachCameraShip #################
//##########################################################################
class CameraDirector__AttachCameraShipMessage:
public Player::Message
{
public:
EntityID
cameraShipID;
CameraDirector__AttachCameraShipMessage(
Receiver::MessageID message_ID,
size_t length,
EntityID camera_ship_ID
):
Entity::Message(message_ID, length),
cameraShipID(camera_ship_ID)
{}
};
//##########################################################################
//############################# CameraDirector #############################
//##########################################################################
class CameraDirector:
public Player
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Messaging support
//
public:
friend class CameraDirector__AttachCameraShipMessage;
enum{
AttachCameraShipMessageID = Entity::NextMessageID,
NextMessageID
};
typedef CameraDirector__AttachCameraShipMessage AttachCameraShipMessage;
void
AttachCameraShipMessageHandler(AttachCameraShipMessage *message);
protected:
static const HandlerEntry
MessageHandlerEntries[];
static MessageHandlerSet
MessageHandlers;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Simulation Support
//
public:
typedef void
(CameraDirector::*Performance)(Scalar time_slice);
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void
CreateCameraShip(Scalar time_slice);
void
BeADirector(Scalar time_slice);
void
UpdateHUD(Scalar time_slice);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction Support
//
public:
CameraDirector(
MakeMessage *creation_message,
SharedData &virtual_data = DefaultData
);
static CameraDirector*
CameraDirector::Make(CameraDirector::MakeMessage *creation_message);
~CameraDirector();
Logical
TestInstance() const;
enum {
DefaultFlags = Entity::DefaultFlags | PreRunFlag | CameraShipPlayerFlag
};
static Player*
FindPlayerByRank(int rank_to_find);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Simulation Support Data & Functions
//
protected:
SlotOf<Entity*>
goalEntity;
void
SetGoalEntity(Entity *goal_entity)
{
Check(this);
goalEntity.Remove();
Check(goal_entity);
goalEntity.Add(goal_entity);
}
Entity*
GetGoalEntity()
{Check(this); return goalEntity.GetCurrent(); }
Scalar
timeLeftOnPlayer;
CameraShip
*cameraShip;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// HUD Support
//
public:
int
goalPlayerIndex;
Logical
displayRankingWindow;
Scalar
timeDisplayed,
timeTillDisplayed,
displayIntervalOn,
displayIntervalOff;
};
+537
View File
@@ -0,0 +1,537 @@
#include "munga.h"
#pragma hdrstop
#include "door.h"
#include "fileutil.h"
#include "boxsolid.h"
#include "doorfram.h"
#include "app.h"
#include "notation.h"
//#############################################################################
// Shared Data Support
//
Door::SharedData
Door::DefaultData(
Door::GetClassDerivations(),
Door::GetMessageHandlers(),
Door::GetAttributeIndex(),
Door::StateCount
);
Derivation* Door::GetClassDerivations()
{
static Derivation classDerivations(Subsystem::GetClassDerivations(), "Door");
return &classDerivations;
}
//#############################################################################
// Messaging Support
//
//#############################################################################
// Attribute Support
//
const Door::IndexEntry
Door::AttributePointers[]=
{
{
Door::CurrentPositionAttributeID,
"CurrentPosition",
(Simulation::AttributePointer)&Door::currentPosition
},
{
Door::VideoResourceAttributeID,
"VideoResource",
(Simulation::AttributePointer)&Door::videoResource
},
{
Door::PercentOpenAttributeID,
"PercentOpen",
(Simulation::AttributePointer)&Door::percentOpen
},
{
Door::CurrentVelocityAttributeID,
"CurrentVelocity",
(Simulation::AttributePointer)&Door::currentVelocity
}
};
Door::AttributeIndexSet& Door::GetAttributeIndex()
{
static Door::AttributeIndexSet attributeIndex(ELEMENTS(Door::AttributePointers),
Door::AttributePointers,
Subsystem::GetAttributeIndex()
);
return attributeIndex;
}
//#############################################################################
// Model Support
//
void
Door::ReadUpdateRecord(Simulation::UpdateRecord *message)
{
Check(this);
Check_Pointer(message);
Subsystem::ReadUpdateRecord(message);
UpdateRecord* record = (UpdateRecord*) message;
percentOpen = record->percentOpen;
switch (GetSimulationState())
{
case Opening:
case Closing:
phaseTimeRemaining = travelTime;
break;
case Opened:
case Closed:
phaseTimeRemaining = deadTime;
break;
}
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door updated to state "
// << GetSimulationState() << " @ "
// << application->GetSecondsRemainingInGame() << endl;
MoveCollisionVolume(percentOpen);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::WriteUpdateRecord(Simulation::UpdateRecord *record, int update_model)
{
Check(this);
Check_Pointer(record);
Subsystem::WriteUpdateRecord(record, update_model);
UpdateRecord *update = (UpdateRecord*)record;
update->percentOpen = percentOpen;
update->recordLength = sizeof(*update);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::SlideDoor(Scalar time_slice)
{
Check(this);
//
//------------------------------------------------------------
// Advance the clock, then branch based upon our current state
//------------------------------------------------------------
//
int new_state;
if (time_slice > 1.0f)
{
Check_Fpu();
return;
}
phaseTimeRemaining -= time_slice;
Scalar percent_open;
switch (GetSimulationState())
{
//
//------------------------------------------------------------------------
// If the door is not done opening, set its new position, otherwise branch
// to the opened state
//------------------------------------------------------------------------
//
case Opening:
Door_Opening:
new_state = Opening;
if (phaseTimeRemaining > 0.0f)
{
percent_open = 1.0f - phaseTimeRemaining/travelTime;
}
else
{
phaseTimeRemaining += deadTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door opened @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Opened;
}
currentVelocity.Subtract(
worldExtent,
GetEntity()->localOrigin.linearPosition
);
currentVelocity /= travelTime;
Check_Fpu();
break;
//
//-------------------------------------------------------------
// If the door is ready to start closing, jump to closing state
//-------------------------------------------------------------
//
case Opened:
Door_Opened:
new_state = Opened;
if (phaseTimeRemaining <= 0.0f)
{
phaseTimeRemaining += travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door closing @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Closing;
}
percent_open = 1.0f;
currentVelocity = Vector3D::Identity;
Check_Fpu();
break;
//
//------------------------------------------------------------------------
// If the door is not done closing, set its new position, otherwise branch
// to the closed state
//------------------------------------------------------------------------
//
case DefaultState:
phaseTimeRemaining = travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door default @ "
// << application->GetSecondsRemainingInGame() << endl;
case Closing:
Door_Closing:
new_state = Closing;
if (phaseTimeRemaining > 0.0f)
{
percent_open = phaseTimeRemaining/travelTime;
}
else
{
phaseTimeRemaining += deadTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door closed @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Closed;
}
currentVelocity.Subtract(
GetEntity()->localOrigin.linearPosition,
worldExtent
);
currentVelocity /= travelTime;
Check_Fpu();
break;
//
//-------------------------------------------------------------
// If the door is ready to start opening, jump to opening state
//-------------------------------------------------------------
//
case Closed:
Door_Closed:
new_state = Closed;
if (phaseTimeRemaining <= 0.0f)
{
phaseTimeRemaining += travelTime;
// DEBUG_STREAM << GetEntity()->GetEntityID() << " door opening @ "
// << application->GetSecondsRemainingInGame() << endl;
goto Door_Opening;
}
percent_open = 0.0f;
currentVelocity = Vector3D::Identity;
Check_Fpu();
break;
}
//
//-------------------------------------------------
// Move the collision volumes and set the new state
//-------------------------------------------------
//
MoveCollisionVolume(percent_open);
SetSimulationState(new_state);
Check_Fpu();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Door::MoveCollisionVolume(Scalar percent_open)
{
Check(this);
//
//---------------------------------------------------------
// If the door hasn't moved, don't bother updating anything
//---------------------------------------------------------
//
Entity *entity = GetEntity();
Check(entity);
if (
GetSimulationState() != simulationState.GetOldState()
&& entity->GetInstance() == Entity::MasterInstance
&& entity->IsDynamic()
)
{
ForceUpdate();
}
if (percent_open == percentOpen)
{
return;
}
//
//-----------------------------------
// Otherwise, lerp the local position
//-----------------------------------
//
percentOpen = percent_open;
currentPosition.Lerp(Point3D::Identity, localExtent, percentOpen);
//
//-----------------------------------------------------------
// Now, lerp the world position and set the collision volumes
//-----------------------------------------------------------
//
Point3D world;
world.Lerp(
GetEntity()->localOrigin.linearPosition,
worldExtent,
percentOpen
);
BoxedSolid* temp = collisionTemplates;
BoxedSolid* vol = collisionVolumes;
while (temp)
{
Check(temp);
Check(vol);
vol->minX = temp->minX + world.x;
vol->maxX = temp->maxX + world.x;
vol->minY = temp->minY + world.y;
vol->maxY = temp->maxY + world.y;
vol->minZ = temp->minZ + world.z;
vol->maxZ = temp->maxZ + world.z;
vol = vol->GetNextSolid();
temp = temp->GetNextSolid();
}
Verify(!vol);
Check_Fpu();
}
//#############################################################################
// Constructer/Destructor Support
//
Door::Door(
DoorFrame *entity,
int subsystem_ID,
SubsystemResource *subsystem_resource
):
Subsystem(entity, subsystem_ID, subsystem_resource, DefaultData)
{
Check_Pointer(this);
Check(entity);
Check_Pointer(subsystem_resource);
//
// GetStream data NOTE::This must be in the same order as below!!!
//
localExtent = subsystem_resource->motionExtent;
travelTime = subsystem_resource->travelTime;
deadTime = subsystem_resource->deadTime;
//
// Initialize variables
//
phaseTimeRemaining = 0.0f;
currentPosition = Point3D::Identity;
SetPerformance(&Door::SlideDoor);
SetSimulationState(DefaultState);
collisionVolumeCount = 0;
collisionTemplates = NULL;
collisionVolumes = NULL;
percentOpen = -1.0f;
//
//-------------------------------------
// Establish the worldspace coordinates
//-------------------------------------
//
worldExtent.Multiply(localExtent, entity->localToWorld);
Origin local_origin = entity->localOrigin;
local_origin.linearPosition = Point3D::Identity;
//
//------------------------------
// Read in the collision volumes
//------------------------------
//
Check(application);
ResourceFile *res_file = application->GetResourceFile();
Check(res_file);
ResourceDescription *res =
res_file->FindResourceDescription(subsystem_resource->collisionID);
Check(res);
res->Lock();
BoxedSolidResource* box =
(BoxedSolidResource*)res->resourceAddress;
Check_Pointer(box);
collisionVolumeCount = res->resourceSize / sizeof(BoxedSolidResource);
for (int i=0; i<collisionVolumeCount; ++i)
{
BoxedSolidResource world_box,local_box;
world_box.Instance(*box,entity->localOrigin);
local_box.Instance(*box,local_origin);
collisionTemplates =
BoxedSolid::MakeBoxedSolid(&local_box, this, collisionTemplates);
Register_Object(collisionTemplates);
collisionVolumes =
BoxedSolid::MakeBoxedSolid(&world_box, this, collisionVolumes);
Register_Object(collisionVolumes);
++box;
}
res->Unlock();
MoveCollisionVolume(0.0f);
Check(this);
}
Door::~Door()
{
BoxedSolid *box = collisionTemplates;
while (box)
{
BoxedSolid *next_box = box->GetNextSolid();
Unregister_Object(box);
delete box;
box = next_box;
}
box = collisionVolumes;
while (box)
{
BoxedSolid *next_box = box->GetNextSolid();
Unregister_Object(box);
delete box;
box = next_box;
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// CreateStreamedSubsystem
//
Logical
Door::CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char* subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
const ResourceDirectories *directories,
ResourceFile *res_file
)
{
if (
!Subsystem::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
subsystem_resource,
subsystem_file,
directories
)
)
{
return False;
}
subsystem_resource->subsystemModelSize = sizeof(*subsystem_resource);
subsystem_resource->classID = RegisteredClass::DoorClassID;
//
// Get the motion Extent
//
const char *extent_data;
if(
!subsystem_file->GetEntry(
subsystem_name,
"MotionExtent",
&extent_data
)
)
{
std::cerr << subsystem_name << " missing MotionExtent!!\n";
return -1;
}
sscanf(
extent_data,
"%f %f %f",
&subsystem_resource->motionExtent.x,
&subsystem_resource->motionExtent.y,
&subsystem_resource->motionExtent.z
);
//
// Get the travelTime
//
if(
!subsystem_file->GetEntry(
subsystem_name,
"TravelTime",
&subsystem_resource->travelTime
)
)
{
std::cerr << subsystem_name << " missing TravelTime!\n";
return -1;
}
//
// Read in the Deadtime
//
if(
!subsystem_file->GetEntry(
subsystem_name,
"DeadTime",
&subsystem_resource->deadTime
)
)
{
std::cerr << subsystem_name << " missing DeadTime!\n";
return False;
}
const char* collision_file;
if (
!subsystem_file->GetEntry(
subsystem_name,
"Collision",
&collision_file
)
)
{
std::cerr << subsystem_name << " missing Collision!\n";
return False;
}
subsystem_resource->collisionID =
BoxedSolidResource::CreateBoxedSolidStream(
collision_file,
res_file,
directories
);
return True;
}
Logical
Door::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+164
View File
@@ -0,0 +1,164 @@
#pragma once
#include "subsystm.h"
#include "boxsolid.h"
class DoorFrame;
//##########################################################################
//##################### Door::SubsystemResource ###################
//##########################################################################
struct Door__SubsystemResource:
public Subsystem::SubsystemResource
{
Vector3D motionExtent;
Scalar
travelTime,
deadTime;
ResourceDescription::ResourceID
collisionID;
};
//##########################################################################
//##################### Chute::UpdateRecord #####################
//##########################################################################
struct Door__UpdateRecord :
public Subsystem::UpdateRecord
{
Scalar
percentOpen;
};
//##########################################################################
//######################### CLASS Door ########################
//##########################################################################
class Door :
public Subsystem
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Messaging Support
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data Support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Attribute Support
//
public:
enum {
PercentOpenAttributeID = Subsystem::NextAttributeID,
CurrentPositionAttributeID,
VideoResourceAttributeID,
CurrentVelocityAttributeID,
NextAttributeID
};
private:
static const IndexEntry AttributePointers[];
protected:
//static AttributeIndexSet AttributeIndex
static AttributeIndexSet& GetAttributeIndex();
public:
Scalar percentOpen;
ResourceDescription::ResourceID videoResource;
Point3D currentPosition;
Vector3D currentVelocity;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model Support
//
public:
enum {
Opening = Subsystem::StateCount,
Opened,
Closing,
Closed,
StateCount
};
typedef void
(Door::*Performance)(Scalar time_slice);
typedef Door__UpdateRecord UpdateRecord;
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
void
SlideDoor(Scalar time_slice);
void
MoveCollisionVolume(Scalar open_percent);
BoxedSolid*
GetFirstBoxedSolid()
{Check(this); return collisionVolumes;}
protected:
void
WriteUpdateRecord(Simulation::UpdateRecord *message, int update_model);
void
ReadUpdateRecord(Simulation::UpdateRecord *message);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
typedef Door__SubsystemResource SubsystemResource;
Door(
DoorFrame *entity,
int subsystem_ID,
SubsystemResource *subsystem_resource
);
~Door();
Logical
TestInstance() const;
static Logical
CreateStreamedSubsystem(
NotationFile *model_file,
const char *model_name,
const char *subsystem_name,
SubsystemResource *subsystem_resource,
NotationFile *subsystem_file,
const ResourceDirectories *directories,
ResourceFile *res_file
);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Local Support
//
private:
Point3D
localExtent,
worldExtent;
Scalar
phaseTimeRemaining,
travelTime,
deadTime;
int collisionVolumeCount;
BoxedSolid
*collisionTemplates,
*collisionVolumes;
};
+278
View File
@@ -0,0 +1,278 @@
#include "munga.h"
#pragma hdrstop
#include "boxsolid.h"
#include "fileutil.h"
#include "doorfram.h"
#include "door.h"
#include "app.h"
#include "notation.h"
#include "namelist.h"
//#############################################################################
// Shared Data Support
//
Derivation* DoorFrame::GetClassDerivations()
{ static Derivation classDerivations(UnscalableTerrain::GetClassDerivations(), "DoorFrame");
return &classDerivations;
}
DoorFrame::SharedData
DoorFrame::DefaultData(
DoorFrame::GetClassDerivations(),
DoorFrame::GetMessageHandlers(),
DoorFrame::GetAttributeIndex(),
DoorFrame::StateCount,
(Entity::MakeHandler)DoorFrame::Make
);
//#############################################################################
// Test Support
//
Logical
DoorFrame::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DoorFrame::DoorFrame(
DoorFrame::MakeMessage *creation_message,
DoorFrame::SharedData &virtual_data
):
UnscalableTerrain(creation_message, virtual_data)
{
Check_Pointer(this);
Check(creation_message);
Check(&virtual_data);
SetValidFlag();
SetPerformance(&DoorFrame::DoNothing);
//
// Get the subsystem_resource from the resource file
//
Check(application);
ResourceDescription *subsystem_resource =
application->GetResourceFile()->SearchList(
resourceID,
ResourceDescription::SubsystemModelStreamResourceType
);
Check(subsystem_resource);
subsystem_resource->Lock();
Check_Pointer(subsystem_resource->resourceAddress);
MemoryStream subsystem_stream(
subsystem_resource->resourceAddress,
subsystem_resource->resourceSize);
subsystemCount = *(int*)subsystem_stream.GetPointer();
subsystem_stream.AdvancePointer(sizeof(int));
Verify(subsystemCount);
//
// Set up Subsystems
//
subsystemArray = new (Subsystem(*[subsystemCount]));
Register_Pointer(subsystemArray);
//
// Attach the doors as defined in the mod file
//
for (int ii=BasicSubsystemCount; ii<subsystemCount; ++ii)
{
Door::SubsystemResource *subsystem_resource =
(Door::SubsystemResource *)subsystem_stream.GetPointer();
subsystemArray[ii] = new Door(this, ii, subsystem_resource);
Register_Object(subsystemArray[ii]);
subsystem_stream.AdvancePointer(subsystem_resource->subsystemModelSize);
}
subsystem_resource->Unlock();
Check(this);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DoorFrame*
DoorFrame::Make(DoorFrame::MakeMessage *creation_message)
{
return new DoorFrame(creation_message);
}
Logical
DoorFrame::CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(creation_message);
Check(model_file);
if (
!UnscalableTerrain::CreateMakeMessage(
creation_message,
model_file,
directories
)
)
{
return false;
}
creation_message->classToCreate = RegisteredClass::DoorFrameClassID;
creation_message->instanceFlags =
MasterInstance|DynamicFlag|MapFlag|TrappedFlag;
return true;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DoorFrame::~DoorFrame()
{
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
ResourceDescription::ResourceID
DoorFrame::CreateSubsystemStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
)
{
Check(resource_file);
Check_Pointer(model_name);
Check(model_file);
Check_Pointer(directories);
//
//-------------------
// Find the .sub file
//-------------------
//
const char* entry_data;
if (
!model_file->GetEntry(
"gamedata",
"Subsystems",
&entry_data
)
)
{
std::cerr << model_name << " is missing .sub file specification!\n";
return -1;
}
char *sub_filename = MakePathedFilename(directories->modelDirectory, entry_data);
Register_Pointer(sub_filename);
NotationFile *sub_file = new NotationFile(sub_filename);
Register_Object(sub_file);
NameList *sub_namelist = sub_file->MakePageList();
Register_Object(sub_namelist);
int subsystem_count = sub_file->PageCount();
if (!subsystem_count)
{
std::cerr << sub_filename << " empty of missing!\n";
Dump_And_Die:
Unregister_Pointer(sub_filename);
delete sub_filename;
Unregister_Object(sub_file);
delete sub_file;
Unregister_Object(sub_namelist);
delete sub_namelist;
return -1;
}
int buf_size =
subsystem_count * sizeof(Door::SubsystemResource) + sizeof(int);
char *buffer = new char[buf_size];
Register_Pointer(buffer);
MemoryStream subsystem_stream(buffer, buf_size);
*(int*)subsystem_stream.GetPointer() = subsystem_count;
subsystem_stream.AdvancePointer(sizeof(int));
NameList::Entry *sub_entry = sub_namelist->GetFirstEntry();
while(sub_entry)
{
char subsystem_name[32];
Str_Copy(subsystem_name, sub_entry->GetName(), sizeof(subsystem_name));
const char *sub_type;
if(!sub_file->GetEntry(
subsystem_name,
"Type",
&sub_type
)
)
{
std::cerr << model_name << ':' << subsystem_name << " missing Type!\n";
Dump_And_Die_2:
Unregister_Pointer(buffer);
delete[] buffer;
goto Dump_And_Die;
}
Subsystem::SubsystemResource *sub_res =
(Subsystem::SubsystemResource*)subsystem_stream.GetPointer();
if (!strcmp(sub_type, "DoorClassID"))
{
if (
Door::CreateStreamedSubsystem(
model_file,
model_name,
subsystem_name,
(Door::SubsystemResource*)sub_res,
sub_file,
directories,
resource_file
) == -1
)
{
goto Dump_And_Die_2;
}
}
else
{
std::cerr << model_name << ':' << subsystem_name
<< " has an unknown component type of " << sub_type << std::endl;
goto Dump_And_Die_2;
}
subsystem_stream.AdvancePointer(sub_res->subsystemModelSize);
sub_entry = sub_entry->GetNextEntry();
}
ResourceDescription *res_desc = resource_file->
ResourceFile::AddResourceMemoryStream(
model_name,
ResourceDescription::SubsystemModelStreamResourceType,
1,
ResourceDescription::Preload,
&subsystem_stream
);
ResourceDescription::ResourceID res_id;
if(!res_desc)
{
res_id = ResourceDescription::NullResourceID;
}
else
{
res_id = res_desc->resourceID;
}
Unregister_Pointer(sub_filename);
delete sub_filename;
Unregister_Object(sub_file);
delete sub_file;
Unregister_Object(sub_namelist);
delete sub_namelist;
Unregister_Pointer(buffer);
delete[] buffer;
return res_id;
}
+52
View File
@@ -0,0 +1,52 @@
#pragma once
#include "terrain.h"
//##########################################################################
//############################# DoorFrame ################################
//##########################################################################
class DoorFrame : public UnscalableTerrain
{
public:
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Test Instance support
//
Logical TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Model support
//
enum
{
BasicSubsystemCount
};
public:
typedef void (DoorFrame::*Performance)(Scalar time_slice);
void SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
static Logical CreateMakeMessage(MakeMessage *creation_message, NotationFile *model_file, const ResourceDirectories *directories);
static ResourceDescription::ResourceID CreateSubsystemStream(ResourceFile *resource_file, const char *model_name, NotationFile *model_file, const ResourceDirectories *directories);
static DoorFrame* Make(MakeMessage *creation_message);
DoorFrame(MakeMessage *creation_message, SharedData &virtual_data = DefaultData);
~DoorFrame();
};
+447
View File
@@ -0,0 +1,447 @@
#include "munga.h"
#pragma hdrstop
#include "dropzone.h"
#include "random.h"
#include "app.h"
#include "hostmgr.h"
#include "nttmgr.h"
#include "notation.h"
#include "namelist.h"
#include "player.h"
#define DOWN_TIME 5.0f
//#############################################################################
//############################### DropZone #################################
//#############################################################################
//#############################################################################
// Shared Data Support
//
Derivation* DropZone::GetClassDerivations()
{
static Derivation classDerivations(Entity::GetClassDerivations(),"DropZone");
return &classDerivations;
}
DropZone::SharedData
DropZone::DefaultData(
DropZone::GetClassDerivations(),
DropZone::GetMessageHandlers(),
DropZone::GetAttributeIndex(),
DropZone::StateCount,
(Entity::MakeHandler)DropZone::Make
);
//#############################################################################
// Message Support
//
const Receiver::HandlerEntry
DropZone::MessageHandlerEntries[]=
{
MESSAGE_ENTRY(DropZone, AssignDropZone)
};
Receiver::MessageHandlerSet& DropZone::GetMessageHandlers()
{
static Receiver::MessageHandlerSet messageHandlers(ELEMENTS(DropZone::MessageHandlerEntries), DropZone::MessageHandlerEntries, Entity::GetMessageHandlers());
return messageHandlers;
}
//#############################################################################
// Construction and Destruction
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DropZone::DropZone(
DropZone::MakeMessage *creation_message,
DropZone::SharedData &virtual_data
):
Entity(creation_message, virtual_data)
{
Check_Pointer(this);
Check_Pointer(creation_message);
SetValidFlag();
dropZoneCount = 0;
dropZones = NULL;
//
//--------------------------------------------------------------
// Name the drop zone, and enter the zone in the drop zone group
//--------------------------------------------------------------
//
Str_Copy(dropZoneName, creation_message->dropZoneName, sizeof(dropZoneName));
EntityManager *entity_manager = application->GetEntityManager();
Check(entity_manager);
EntityGroup* drop_zones = entity_manager->UseGroup("DropZones");
Check(drop_zones);
drop_zones->Add(this);
//
//-----------------------------------------------------------------------
// Now, interpret the data to create the appropriate number of drop zones
//-----------------------------------------------------------------------
//
MemoryStream
stream(
creation_message,
creation_message->messageLength,
sizeof(*creation_message)
);
dropZoneCount = creation_message->dropZoneCount;
Verify(dropZoneCount > 0);
dropZones = new Origin[dropZoneCount];
Register_Pointer(dropZones);
lastUsageTime = new Time[dropZoneCount];
Register_Pointer(lastUsageTime);
lastUsedBy = new EntityID[dropZoneCount];
Register_Pointer(lastUsedBy);
lastDeathCount = new int[dropZoneCount];
Register_Pointer(lastDeathCount);
for (int i=0; i<dropZoneCount; ++i)
{
dropZones[i] = *(Origin*)stream.GetPointer();
lastUsageTime[i] = Time::Null;
lastUsedBy[i] = EntityID::Null;
lastDeathCount[i] = -3;
stream.AdvancePointer(sizeof(Origin));
}
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DropZone*
DropZone::Make(DropZone::MakeMessage *creation_message)
{
return new DropZone(creation_message);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
DropZone::~DropZone()
{
if (dropZones)
{
Unregister_Pointer(dropZones);
delete[] dropZones;
Unregister_Pointer(lastUsageTime);
delete[] lastUsageTime;
Unregister_Pointer(lastUsedBy);
delete[] lastUsedBy;
Unregister_Pointer(lastDeathCount);
delete[] lastDeathCount;
}
}
//#############################################################################
// Dropzone assignment
//
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
DropZone::IsAvailable(int index)
{
Check(this);
Verify(index >= 0 && index < dropZoneCount);
Check(application);
return
!lastUsageTime[index].ticks
|| Now() - lastUsageTime[index] > DOWN_TIME
&& application->GetApplicationState() == Application::RunningMission;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
DropZone::AssignDropZoneMessageHandler(AssignDropZoneMessage* message)
{
Check(this);
Check_Pointer(message);
Check(application);
HostManager *host = application->GetHostManager();
Check(host);
Entity *entity = host->GetEntityPointer(message->requestingEntity);
Check(entity);
//
//---------------------------------------------------------------------
// If we have allocated a dropzone within the last ten seconds for this
// player, resend the data
//---------------------------------------------------------------------
//
Origin *drop_zone = NULL;
int
lowest, highest, remaining, i;
for (i=0; i<dropZoneCount; ++i)
{
if (
!IsAvailable(i)
&& lastUsedBy[i] == message->requestingEntity
&& lastDeathCount[i] == message->deathCount
)
{
lastUsageTime[i] = Now();
drop_zone = &dropZones[i];
goto Found_One;
}
}
//
//------------------------------------------------------------------------
// Figure out how many drop zones are available. If none are, repost this
// message to ourself
//------------------------------------------------------------------------
//
lowest = dropZoneCount;
highest = -1;
remaining = 0;
for (i=0; i<dropZoneCount; ++i)
{
if (IsAvailable(i))
{
++remaining;
if (i < lowest)
{
lowest = i;
}
if (i > highest)
{
highest = i;
}
}
}
//
//-----------------------------------------------------
// Now, randomly look about until we find one available
//-----------------------------------------------------
//
highest = highest - lowest + 1;
while (remaining)
{
i = lowest + Random(highest);
Verify(i < dropZoneCount && i >= 0);
if (IsAvailable(i))
{
//
//-------------------------------------------------------------------
// Check to see if vehicle attached to a player is within 2 meters of
// this drop zone. If so, mark it unavailable for 3 seconds
//-------------------------------------------------------------------
//
EntityManager *entity_mgr = application->GetEntityManager();
Check(entity_mgr);
EntityGroup *player_group = entity_mgr->FindGroup("Players");
if (
player_group
&& application->GetApplicationState()
== Application::RunningMission
)
{
Player *player;
ChainIteratorOf<Node*> iterator(player_group->groupMembers);
while ((player = (Player*)iterator.ReadAndNext()) != NULL)
{
Check(player);
Entity *vehicle = player->GetPlayerVehicle();
if (vehicle && player != entity)
{
Check(vehicle);
Vector3D distance;
distance.Subtract(
vehicle->localOrigin.linearPosition,
dropZones[i].linearPosition
);
if (distance.LengthSquared() <= 4.0f)
{
lastUsedBy[i] = NULL;
lastUsageTime[i] = Now();
lastUsageTime[i] -= DOWN_TIME - 1.0f;
--remaining;
if (i == lowest)
{
++lowest;
--highest;
}
else if (i == lowest + highest - 1)
{
--highest;
}
break;
}
}
}
//
//----------------------------------------------------------
// If someone was in this spot, keep looking for another one
//----------------------------------------------------------
//
if (player)
{
continue;
}
}
lastUsageTime[i] = Now();
drop_zone = &dropZones[i];
lastUsedBy[i] = message->requestingEntity;
lastDeathCount[i] = message->deathCount;
remaining = 0;
}
}
//
//----------------------------------------------------------------
// If no drop_zone could be found, repost the message to ourselves
//----------------------------------------------------------------
//
if (!drop_zone)
{
Time when=Now();
when += 0.1f;
application->Post(MaxEventPriority, this, message, when);
return;
}
//
//--------------------------------------------------------------------
// Send a message back to the requesting object what sent this message
//--------------------------------------------------------------------
//
Found_One:
ReplyMessage
reply(
message->replyMessageID,
sizeof(ReplyMessage),
*drop_zone,
message->deathCount
);
entity->Dispatch(&reply);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Logical
DropZone::CreateMakeMessage(
MakeMessage *creation_message,
const char* model_name,
const char* resource_name,
NotationFile *map_file
)
{
Check(creation_message);
Check(map_file);
Check_Pointer(model_name);
Check_Pointer(resource_name);
if (!Entity::CreateMakeMessage(creation_message, map_file, NULL))
{
return False;
}
creation_message->classToCreate = RegisteredClass::DropZoneClassID;
creation_message->instanceFlags = MapFlag|TrappedFlag;
//
//-----------------------------------------------
// Count up the number of drop zones in our model
//-----------------------------------------------
//
Enumeration save_modes = map_file->GetModes();
map_file->SetMode(NotationFile::CleanListMode);
NameList *zone_list =
map_file->MakeEntryList(model_name, "dropzone");
Register_Object(zone_list);
creation_message->dropZoneCount = zone_list->EntryCount();
creation_message->messageLength =
sizeof(*creation_message)
+ creation_message->dropZoneCount*sizeof(Origin);
if (!creation_message->dropZoneCount)
{
std::cout << "Error: " << model_name << " hasn't specified any drop zones!\n";
Dump_And_Die:
Unregister_Object(zone_list);
delete zone_list;
map_file->PutModes(save_modes);
return False;
}
//
//---------------------------------------------
// Allocate a buffer to hold the drop zone data
//---------------------------------------------
//
MemoryStream
stream(
creation_message,
creation_message->messageLength,
sizeof(*creation_message)
);
//
//----------------------------
// zero out the drop zone name
//----------------------------
//
for (int ii=0; ii<sizeof(creation_message->dropZoneName); ii++)
{
creation_message->dropZoneName[ii] = '\0';
}
Str_Copy(
creation_message->dropZoneName,
resource_name,
sizeof(creation_message->dropZoneName)
);
//
//-----------------
// Read in the data
//-----------------
//
NameList::Entry *drop_zone = zone_list->GetFirstEntry();
while (drop_zone)
{
Point3D translation;
EulerAngles tmp_rotation;
const char* zone_data = drop_zone->GetChar();
sscanf(
zone_data,
"%f %f %f %f %f %f",
&translation.x,
&translation.y,
&translation.z,
&tmp_rotation.pitch,
&tmp_rotation.yaw,
&tmp_rotation.roll
);
((Origin*)stream.GetPointer())->linearPosition = translation;
((Origin*)stream.GetPointer())->angularPosition = tmp_rotation;
stream.AdvancePointer(sizeof(Origin));
drop_zone = drop_zone->GetNextEntry();
}
Unregister_Object(zone_list);
delete zone_list;
map_file->PutModes(save_modes);
return True;
}
Logical
DropZone::TestInstance() const
{
return IsDerivedFrom(*GetClassDerivations());
}
+152
View File
@@ -0,0 +1,152 @@
#pragma once
#include "entity.h"
#include "cstr.h"
//##########################################################################
//##################### Mover::ModelResource #########################
//##########################################################################
class DropZone__MakeMessage:
public Entity::MakeMessage
{
public:
char dropZoneName[32];
int dropZoneCount;
};
//##########################################################################
//################# DropZone::AssignDropZoneMessage ##################
//##########################################################################
class DropZone__AssignDropZoneMessage:
public Entity::Message
{
public:
EntityID
requestingEntity;
Receiver::MessageID
replyMessageID;
int
deathCount;
DropZone__AssignDropZoneMessage(
Receiver::MessageID message_ID,
size_t length,
const EntityID &reply_to,
Receiver::MessageID reply_ID,
int death_count
):
Entity::Message(message_ID, length),
requestingEntity(reply_to),
replyMessageID(reply_ID),
deathCount(death_count)
{}
};
//##########################################################################
//##################### DropZone::ReplyMessage ##########################
//##########################################################################
class DropZone__ReplyMessage:
public Entity::Message
{
public:
Origin
dropZoneLocation;
int
deathCount;
DropZone__ReplyMessage(
Receiver::MessageID message_ID,
size_t length,
const Origin &location,
int death_count
):
Entity::Message(message_ID, length),
dropZoneLocation(location),
deathCount(death_count)
{}
};
//##########################################################################
//########################### DropZone ################################
//##########################################################################
class DropZone:
public Entity
{
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Shared Data support
//
public:
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Message Support
//
public:
enum {
AssignDropZoneMessageID = Entity::NextMessageID,
NextMessageID
};
private:
static const HandlerEntry MessageHandlerEntries[];
protected:
static MessageHandlerSet& GetMessageHandlers();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Construction and Destruction
//
public:
typedef DropZone__MakeMessage MakeMessage;
static DropZone*
Make(MakeMessage *creation_message);
static Logical
CreateMakeMessage(
MakeMessage *creation_message,
const char* model_name,
const char* resource_name,
NotationFile *map_file
);
DropZone(
MakeMessage *creation_message,
SharedData &virtual_data = DefaultData
);
~DropZone();
Logical
TestInstance() const;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dropzone assignment
//
public:
typedef DropZone__AssignDropZoneMessage AssignDropZoneMessage;
typedef DropZone__ReplyMessage ReplyMessage;
const char*
GetDropZoneName()
{Check(this); return dropZoneName;}
Logical
IsAvailable(int index);
protected:
int dropZoneCount;
char dropZoneName[32];
Origin *dropZones;
Time *lastUsageTime;
EntityID *lastUsedBy;
int *lastDeathCount;
void
AssignDropZoneMessageHandler(AssignDropZoneMessage *message);
};
File diff suppressed because it is too large Load Diff
+621
View File
@@ -0,0 +1,621 @@
#pragma once
#include "simulate.h"
#include "origin.h"
#include "linmtrx.h"
class Player;
class NotationFile;
class DamageZone;
class Damage;
class Subsystem;
#define ENTITY_CONTINUATION
#include "entity2.h"
//##########################################################################
//########################### Entity #################################
//##########################################################################
class Entity:
public Simulation
{
friend class Entity__StaticVideoSocketIterator;
friend class Entity__DynamicVideoSocketIterator;
friend class Entity__AudioSocketIterator;
friend class Entity__GaugeSocketIterator;
friend class Entity__AudioLocationIterator;
//##########################################################################
// Shared Data support
//
public:
typedef Entity__SharedData SharedData;
SharedData*
GetSharedData();
static Derivation *GetClassDerivations();
static SharedData DefaultData;
//##########################################################################
// Message Support
//
public:
enum {
MakeMessageID = Simulation::NextMessageID,
MakeReadyMessageID,
RemakeEntityMessageID,
RemakeReadyMessageID,
RemakeCompleteMessageID,
RemakeIncompleteMessageID,
DestroyEntityMessageID,
TransferEntityMessageID,
TransferCompleteMessageID,
TransferIncompleteMessageID,
BecomeInterestingMessageID,
BecomeUninterestingMessageID,
UpdateMessageID,
SubscribeReplicantMessageID,
UnsubscribeReplicantMessageID,
TakeDamageMessageID,
TakeDamageStreamMessageID,
PlayerLinkMessageID,
NextMessageID
};
typedef Entity__Message Message;
typedef Entity__MakeMessage MakeMessage;
typedef Entity__MakeReadyMessage MakeReadyMessage;
typedef Entity__RemakeEntityMessage RemakeEntityMessage;
typedef Entity__RemakeReadyMessage RemakeReadyMessage;
typedef Entity__RemakeCompleteMessage RemakeCompleteMessage;
typedef Entity__RemakeIncompleteMessage RemakeIncompleteMessage;
typedef Entity__DestroyEntityMessage DestroyEntityMessage;
typedef Entity__TransferEntityMessage TransferEntityMessage;
typedef Entity__TransferCompleteMessage TransferCompleteMessage;
typedef Entity__TransferIncompleteMessage TransferIncompleteMessage;
typedef Entity__BecomeInterestingMessage BecomeInterestingMessage;
typedef Entity__BecomeUninterestingMessage BecomeUninterestingMessage;
typedef Entity__UpdateMessage UpdateMessage;
typedef Entity__SubscribeReplicantMessage SubscribeReplicantMessage;
typedef Entity__UnsubscribeReplicantMessage UnsubscribeReplicantMessage;
typedef Entity__TakeDamageMessage TakeDamageMessage;
typedef Entity__TakeDamageStreamMessage TakeDamageStreamMessage;
typedef Entity__PlayerLinkMessage PlayerLinkMessage;
typedef Entity__DynamicMessage DynamicMessage;
typedef Entity__MakeMapMessage MakeMapMessage;
void
Receive(Event *event);
void
LocalDispatch(Message *what)
{Receiver::Receive(Cast_Object(Receiver::Message*,what));}
void
Dispatch(Receiver::Message *what);
void
DispatchToReplicant(
Message *what,
HostID host
);
void
DispatchToReplicants(Message *what);
private:
static const HandlerEntry MessageHandlerEntries[];
protected:
//static MessageHandlerSet MessageHandlers;
static MessageHandlerSet& GetMessageHandlers();
//##########################################################################
// Attribute Support
//
public:
enum {
LocalToWorldAttributeID = Simulation::NextAttributeID,
LocalOriginAttributeID,
DamageZoneCountAttributeID,
DamageZonesAttributeID,
NextAttributeID
};
private:
static const IndexEntry AttributePointers[];
protected:
//static AttributeIndexSet AttributeIndex
static AttributeIndexSet& GetAttributeIndex();
//
// public attribute declarations go here
//
public:
LinearMatrix localToWorld;
Origin localOrigin;
int damageZoneCount;
DamageZone **damageZones;
int
GetDamageZoneIndex(const CString &damage_zone_name) const;
//
// virtual access
//
public:
virtual Vector3D
GetWorldLinearVelocity()
{return Vector3D(0.0f, 0.0f, 0.0f);}
virtual Vector3D
GetWorldLinearAcceleration()
{return Vector3D(0.0f, 0.0f, 0.0f);}
//##########################################################################
// Model Support
//
public:
UpdateMessage*
Execute(const Time &till);
Subsystem*
GetSubsystem(int index)
{
Check(this); Verify((unsigned)index < subsystemCount);
return subsystemArray[index];
}
Simulation*
GetSimulation(int index);
int
GetSubsystemCount()
{Check(this); return subsystemCount;}
Subsystem*
FindSubsystem(const char* name);
typedef void
(Entity::*Performance)(Scalar time_slice);
typedef Entity__UpdateRecord UpdateRecord;
void
SetPerformance(Performance performance)
{
Check(this);
activePerformance = (Simulation::Performance)performance;
}
enum {
EntitySubsystemID = -1
};
static int
FindSubsytemID(
const char *model_name,
const char *subsystem_name
);
public:
enum {
DamageZoneUpdateModelBit = Simulation::NextUpdateModelBit,
NextUpdateModelBit
};
enum {
DamageZoneUpdateModelFlag = 1 << DamageZoneUpdateModelBit
};
Logical DamageZoneUpdateModelFlagSet()
{
Check(this);
return ((updateModel & DamageZoneUpdateModelFlag) != 0);
}
protected:
void
WriteUpdateRecord(
Simulation::UpdateRecord *message,
int update_model
);
void
UpdateMessageHandler(UpdateMessage *message);
void
ReadUpdateRecord(Simulation::UpdateRecord *message);
void
ReadDamageUpdateRecord(Simulation::UpdateRecord *update_record);
void
WriteDamageUpdateRecord(Simulation::UpdateRecord *update_record);
void
PerformAndWatch(
const Time &till,
MemoryStream *update_stream
);
int
subsystemCount;
Subsystem
**subsystemArray;
Origin
updateOrigin;
void
TakeDamageStreamMessageHandler(TakeDamageStreamMessage *message);
void
TakeDamageMessageHandler(TakeDamageMessage *message);
void
PlayerLinkMessageHandler(PlayerLinkMessage *message);
//##########################################################################
// Renderer Support
//
public:
void
AddStaticVideoComponent(Component *component);
void
AddDynamicVideoComponent(Component *component);
void
AddAudioComponent(Component *component);
typedef Entity__StaticVideoSocketIterator
StaticVideoSocketIterator;
typedef Entity__DynamicVideoSocketIterator
DynamicVideoSocketIterator;
typedef Entity__AudioSocketIterator
AudioSocketIterator;
virtual Enumeration
GetAudioRepresentation(Entity *linked_entity);
private:
SChainOf<Component*>
staticVideoSocket;
SChainOf<Component*>
dynamicVideoSocket;
SChainOf<Component*>
audioSocket;
//##########################################################################
// Flag Support
//
public:
//
// MasterInstance - created on owning host, replicated on remote hosts,
// sends updates to replicants
// ReplicantInstance - created on remote hosts, receives updates from
// MasterInstance
// IndependantInstance - created on owning host, replicated on remote
// hosts, never receives updates from MasterInstance
// HermitInstance - created on owning host, is not replicated, does
// send updates
//
enum {
InstanceBits = Simulation::NextBit,
ValidBit = InstanceBits+2,
TransferableBit,
InterestBit,
InterestLockedBit,
DynamicBit,
TrappedBit,
StatueBit,
MapBit,
PreRunBit,
CondemnedBit,
NextBit
};
enum Instance
{
MasterInstance=0,
ReplicantInstance=1<<InstanceBits,
IndependantInstance=2<<InstanceBits,
HermitInstance=3<<InstanceBits
};
enum {
InstanceMask = HermitInstance,
ValidFlag = 1<<ValidBit,
TransferableFlag = 1<<TransferableBit,
InterestFlag = 1<<InterestBit,
InterestLockedFlag = 1<<InterestLockedBit,
DynamicFlag = 1<<DynamicBit,
TrappedFlag = 1<<TrappedBit,
StatueFlag = 1<<StatueBit,
MapFlag = 1<<MapBit,
PreRunFlag = 1<<PreRunBit,
CondemnedFlag = 1<<CondemnedBit,
TypeMask = DynamicFlag|TrappedFlag|MapFlag,
// DefaultFlags = MasterInstance
DefaultFlags = DynamicFlag|MasterInstance
};
enum Type {
StaticType = 0,
DynamicType = DynamicFlag,
TrappedType = DynamicFlag|TrappedFlag,
StatueType = DynamicFlag|TrappedFlag|StatueFlag,
MapType = DynamicFlag|MapFlag,
TrappedMapType = DynamicFlag|TrappedFlag|MapFlag,
};
//##########################################################################
// Instance Type support
//
public:
void
SetInstance(Instance type)
{Check(this); simulationFlags &= ~InstanceMask; simulationFlags |= type;}
Instance
GetInstance()
{Check(this); return (Instance)(simulationFlags&InstanceMask);}
static LWord
EntityFlagsSetInstance(LWord entity_flags, Instance type)
{
entity_flags &= ~InstanceMask;
entity_flags |= type;
return entity_flags;
}
static Instance
EntityFlagsGetInstance(LWord entity_flags)
{return (Instance)(entity_flags&InstanceMask);}
//##########################################################################
// Validity Support
//
public:
void
SetValidFlag()
{Check(this); simulationFlags |= ValidFlag;}
void
SetInvalidFlag()
{Check(this); simulationFlags &= ~ValidFlag;}
Logical
IsValid()
{Check(this); return (simulationFlags&ValidFlag) != 0;}
void
SetPreRunFlag()
{Check(this); simulationFlags |= PreRunFlag;}
void
SetNoPreRunFlag()
{Check(this); simulationFlags &= ~PreRunFlag;}
Logical
IsPreRunnable()
{Check(this); return (simulationFlags&PreRunFlag) != 0;}
void
SetCondemnedFlag()
{Check(this); simulationFlags |= CondemnedFlag;}
Logical
IsCondemned()
{Check(this); return (simulationFlags&CondemnedFlag) != 0;}
//##########################################################################
// Transference Support
//
public:
void
SetTransferableFlag()
{Check(this); simulationFlags |= TransferableFlag;}
void
SetNontransferableFlag()
{Check(this); simulationFlags &= ~TransferableFlag;}
Logical
IsTransferable()
{Check(this); return (simulationFlags&TransferableFlag) != 0;}
const EntityID&
GetEntityID()
{return entityID;}
HostID
GetOwnerID()
{return ownerID;}
EntityID
entityID;
HostID
ownerID;
Player
*playerLink;
Player*
GetPlayerLink()
{return playerLink;}
//##########################################################################
// Interest Support
//
public:
void
BecomeInteresting();
void
BecomeInterestingMessageHandler(const Receiver::Message*);
void
BecomeUninterestingMessageHandler();
Logical
IsInteresting()
{Check(this); return interestCount != 0;}
void
SetInterestLockedFlag();
void
SetInterestUnlockedFlag();
Logical
IsInterestLocked()
{Check(this); return (simulationFlags&InterestLockedFlag) != 0;}
void
SetInterestZoneID(InterestZoneID interest_zone_ID)
{interestZoneID = interest_zone_ID;}
InterestZoneID
GetInterestZoneID()
{return interestZoneID;}
Logical
IsStatic()
{Check(this); return (simulationFlags&DynamicFlag) == 0;}
Logical
IsDynamic()
{Check(this); return (simulationFlags&DynamicFlag) != 0;}
void
SetTrappedFlag()
{Check(this); simulationFlags |= TrappedFlag;}
Logical
IsTrapped()
{Check(this); return (simulationFlags&TrappedFlag) != 0;}
Logical
IsStatue()
{Check(this); return (simulationFlags&StatueFlag) != 0;}
Logical
IsMap()
{Check(this); return (simulationFlags&MapFlag) != 0;}
static Logical
EntityFlagsIsMap(LWord entity_flags)
{return (entity_flags&MapFlag) != 0;}
Type
GetType()
{Check(this); return (Type)(simulationFlags&TypeMask);}
virtual Enumeration
GetInterestPriority(Entity *linked_entity);
InterestZoneID
interestZoneID;
int
interestCount;
Time
creationTime;
//##########################################################################
// Camera Support
//
protected:
Origin
cameraOffset;
public:
Origin
GetCameraOffset() const
{Check(this); return cameraOffset; }
//##########################################################################
// Scoring support
//
public:
//
// HACK - ECH 7/6/95 - Allow the player vehicle to respond to score
// messages, allows attribute system to be used for scoring
//
virtual void
RespondToScoreMessage(Message *message) {}
//##########################################################################
// Construction and Destruction
//
public:
typedef Entity* (*MakeHandler)(MakeMessage *);
static Entity*
Make(MakeMessage *creation_message);
//
// Warning... This function requires a properly set up strtok!!!!
//
static Logical
CreateMakeMessage(
MakeMessage *creation_message,
NotationFile *model_file,
const ResourceDirectories *directories
);
static Logical
CreateMakeMapMessage(
MakeMapMessage *creation_message,
ResourceDescription::ResourceID resource_id,
NotationFile *model_file,
const ResourceDirectories * //directories
);
static ResourceDescription::ResourceID
CreateDamageZoneStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
static ResourceDescription::ResourceID
CreateExplosionTableStream(
ResourceFile *resource_file,
const char *model_name,
NotationFile *model_file,
const ResourceDirectories *directories
);
ResourceDescription::ResourceID
GetResourceID()
{Check(this); return resourceID;}
Player*
GetOwningPlayer()
{Check(this); return owningPlayer;}
void
SetupNetworkMessage(Entity::Message *message);
protected:
Entity(
MakeMessage *creation_message,
SharedData &virtual_data
);
ResourceDescription::ResourceID
resourceID;
Player
*owningPlayer;
void
DestroyEntityMessageHandler(Message *message);
public:
~Entity();
void
CondemnToDeathRow();
//##########################################################################
// Test Support
//
public:
Logical
TestInstance() const;
static Logical
TestClass();
};
inline void
Entity::SetupNetworkMessage(Entity::Message *message)
{
Check(this);
Check(message);
message->entityID = entityID;
message->interestZoneID = interestZoneID;
message->ownerID = ownerID;
}
#include "entity3.h"
#undef ENTITY_CONTINUATION
+80
View File
@@ -0,0 +1,80 @@
#include "munga.h"
#pragma hdrstop
#include "hostmgr.h"
#include "registry.h"
#include "app.h"
#include "namelist.h"
#include "notation.h"
#include "entity.h"
//##########################################################################
//############# Entity::StaticVideoSocketIterator ####################
//##########################################################################
Entity__StaticVideoSocketIterator::Entity__StaticVideoSocketIterator(Entity *entity) : SChainIteratorOf<Component*>(&entity->staticVideoSocket)
{
}
Entity__StaticVideoSocketIterator::Entity__StaticVideoSocketIterator(const Entity__StaticVideoSocketIterator &iterator) : SChainIteratorOf<Component*>(iterator)
{
}
Entity__StaticVideoSocketIterator::~Entity__StaticVideoSocketIterator()
{
}
//##########################################################################
//############# Entity::DynamicVideoSocketIterator ###################
//##########################################################################
Entity__DynamicVideoSocketIterator::Entity__DynamicVideoSocketIterator(Entity *entity) : SChainIteratorOf<Component*>(&entity->dynamicVideoSocket)
{
}
Entity__DynamicVideoSocketIterator::Entity__DynamicVideoSocketIterator(const Entity__DynamicVideoSocketIterator &iterator) : SChainIteratorOf<Component*>(iterator)
{
}
Entity__DynamicVideoSocketIterator::~Entity__DynamicVideoSocketIterator()
{
}
//##########################################################################
//################ Entity::AudioSocketIterator #######################
//##########################################################################
Entity__AudioSocketIterator::Entity__AudioSocketIterator(Entity *entity) : SChainIteratorOf<Component*>(&entity->audioSocket)
{
}
Entity__AudioSocketIterator::~Entity__AudioSocketIterator()
{
}
int Find_Subsystem_Index(NotationFile *file, const char* name)
{
Check(file);
Check_Pointer(name);
NameList *namelist = file->MakePageList();
Register_Object(namelist);
NameList::Entry *entry = namelist->GetFirstEntry();
int count = 0;
while (entry)
{
if (!strcmp(name, entry->GetName()))
{
Unregister_Object(namelist);
delete namelist;
return count;
}
++count;
entry = entry->GetNextEntry();
}
Unregister_Object(namelist);
delete namelist;
return (!strcmp(name, "None")) ? count : -1;
}

Some files were not shown because too many files have changed in this diff Show More