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:
@@ -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 {};
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 °ree);
|
||||
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 °ree)
|
||||
{
|
||||
Check(this);
|
||||
Check(°ree);
|
||||
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(°ree);
|
||||
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
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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))
|
||||
{
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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, ¢s))
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
)
|
||||
{
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "audwgt.h"
|
||||
|
||||
const AudioWeighting AudioWeighting::Null;
|
||||
|
||||
Logical AudioWeighting::TestInstance() const
|
||||
{
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -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
@@ -0,0 +1,4 @@
|
||||
#include "munga.h"
|
||||
#pragma hdrstop
|
||||
|
||||
#include "average.h"
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
@@ -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();
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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(); }
|
||||
};
|
||||
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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()
|
||||
{
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)); }
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
};
|
||||
@@ -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))
|
||||
|
||||
@@ -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))
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -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());
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user