aboutsummaryrefslogtreecommitdiffstats
path: root/q3radiant/splines
diff options
context:
space:
mode:
Diffstat (limited to 'q3radiant/splines')
-rwxr-xr-xq3radiant/splines/Splines.vcproj296
-rwxr-xr-xq3radiant/splines/math_angles.cpp150
-rwxr-xr-xq3radiant/splines/math_angles.h195
-rwxr-xr-xq3radiant/splines/math_matrix.cpp134
-rwxr-xr-xq3radiant/splines/math_matrix.h223
-rwxr-xr-xq3radiant/splines/math_quaternion.cpp78
-rwxr-xr-xq3radiant/splines/math_quaternion.h190
-rwxr-xr-xq3radiant/splines/math_vector.cpp144
-rwxr-xr-xq3radiant/splines/math_vector.h572
-rwxr-xr-xq3radiant/splines/q_parse.cpp535
-rwxr-xr-xq3radiant/splines/q_shared.cpp976
-rwxr-xr-xq3radiant/splines/q_shared.h798
-rwxr-xr-xq3radiant/splines/splines.cpp1244
-rwxr-xr-xq3radiant/splines/splines.h1080
-rwxr-xr-xq3radiant/splines/util_list.h346
-rwxr-xr-xq3radiant/splines/util_str.cpp618
-rwxr-xr-xq3radiant/splines/util_str.h817
17 files changed, 8396 insertions, 0 deletions
diff --git a/q3radiant/splines/Splines.vcproj b/q3radiant/splines/Splines.vcproj
new file mode 100755
index 0000000..be579ae
--- /dev/null
+++ b/q3radiant/splines/Splines.vcproj
@@ -0,0 +1,296 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="Splines"
+ SccProjectName="&quot;$/source/q3radiant/splines&quot;, XINAAAAA"
+ SccLocalPath=".">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory=".\Release"
+ IntermediateDirectory=".\Release"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ InlineFunctionExpansion="1"
+ PreprocessorDefinitions="WIN32;NDEBUG;_LIB;Q3RADIANT"
+ StringPooling="TRUE"
+ RuntimeLibrary="4"
+ EnableFunctionLevelLinking="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Release/Splines.pch"
+ AssemblerListingLocation=".\Release/"
+ ObjectFile=".\Release/"
+ ProgramDataBaseFileName=".\Release/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Release\Splines.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="NDEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory=".\Debug"
+ IntermediateDirectory=".\Debug"
+ ConfigurationType="4"
+ UseOfMFC="0"
+ ATLMinimizesCRunTimeLibraryUsage="FALSE"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_LIB;Q3RADIANT"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="1"
+ RuntimeTypeInfo="TRUE"
+ UsePrecompiledHeader="2"
+ PrecompiledHeaderFile=".\Debug/Splines.pch"
+ AssemblerListingLocation=".\Debug/"
+ ObjectFile=".\Debug/"
+ ProgramDataBaseFileName=".\Debug/"
+ WarningLevel="3"
+ SuppressStartupBanner="TRUE"
+ DebugInformationFormat="4"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLibrarianTool"
+ OutputFile=".\Debug\Splines.lib"
+ SuppressStartupBanner="TRUE"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"
+ PreprocessorDefinitions="_DEBUG"
+ Culture="1033"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;rc;def;r;odl;idl;hpj;bat">
+ <File
+ RelativePath="math_angles.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="math_matrix.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="math_quaternion.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="math_vector.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="q_parse.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="q_shared.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="splines.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath="util_str.cpp">
+ <FileConfiguration
+ Name="Release|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="2"
+ PreprocessorDefinitions=""/>
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug|Win32">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions=""
+ BasicRuntimeChecks="3"/>
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl">
+ <File
+ RelativePath="math_angles.h">
+ </File>
+ <File
+ RelativePath="math_matrix.h">
+ </File>
+ <File
+ RelativePath="math_quaternion.h">
+ </File>
+ <File
+ RelativePath="math_vector.h">
+ </File>
+ <File
+ RelativePath="q_shared.h">
+ </File>
+ <File
+ RelativePath="splines.h">
+ </File>
+ <File
+ RelativePath="util_list.h">
+ </File>
+ <File
+ RelativePath="util_str.h">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/q3radiant/splines/math_angles.cpp b/q3radiant/splines/math_angles.cpp
new file mode 100755
index 0000000..0142d3d
--- /dev/null
+++ b/q3radiant/splines/math_angles.cpp
@@ -0,0 +1,150 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#include "q_shared.h"
+#include <float.h>
+
+angles_t ang_zero( 0.0f, 0.0f, 0.0f );
+
+void toAngles( mat3_t &src, angles_t &dst ) {
+ double theta;
+ double cp;
+ double sp;
+
+ sp = src[ 0 ][ 2 ];
+
+ // cap off our sin value so that we don't get any NANs
+ if ( sp > 1.0 ) {
+ sp = 1.0;
+ } else if ( sp < -1.0 ) {
+ sp = -1.0;
+ }
+
+ theta = -asin( sp );
+ cp = cos( theta );
+
+ if ( cp > 8192 * FLT_EPSILON ) {
+ dst.pitch = theta * 180 / M_PI;
+ dst.yaw = atan2( src[ 0 ][ 1 ], src[ 0 ][ 0 ] ) * 180 / M_PI;
+ dst.roll = atan2( src[ 1 ][ 2 ], src[ 2 ][ 2 ] ) * 180 / M_PI;
+ } else {
+ dst.pitch = theta * 180 / M_PI;
+ dst.yaw = -atan2( src[ 1 ][ 0 ], src[ 1 ][ 1 ] ) * 180 / M_PI;
+ dst.roll = 0;
+ }
+}
+
+void toAngles( quat_t &src, angles_t &dst ) {
+ mat3_t temp;
+
+ toMatrix( src, temp );
+ toAngles( temp, dst );
+}
+
+void toAngles( idVec3_t &src, angles_t &dst ) {
+ dst.pitch = src[ 0 ];
+ dst.yaw = src[ 1 ];
+ dst.roll = src[ 2 ];
+}
+
+void angles_t::toVectors( idVec3_t *forward, idVec3_t *right, idVec3_t *up ) {
+ float angle;
+ static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs
+
+ angle = yaw * ( M_PI * 2 / 360 );
+ sy = sin( angle );
+ cy = cos( angle );
+
+ angle = pitch * ( M_PI * 2 / 360 );
+ sp = sin( angle );
+ cp = cos( angle );
+
+ angle = roll * ( M_PI * 2 / 360 );
+ sr = sin( angle );
+ cr = cos( angle );
+
+ if ( forward ) {
+ forward->set( cp * cy, cp * sy, -sp );
+ }
+
+ if ( right ) {
+ right->set( -sr * sp * cy + cr * sy, -sr * sp * sy + -cr * cy, -sr * cp );
+ }
+
+ if ( up ) {
+ up->set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp );
+ }
+}
+
+idVec3_t angles_t::toForward( void ) {
+ float angle;
+ static float sp, sy, cp, cy; // static to help MS compiler fp bugs
+
+ angle = yaw * ( M_PI * 2 / 360 );
+ sy = sin( angle );
+ cy = cos( angle );
+
+ angle = pitch * ( M_PI * 2 / 360 );
+ sp = sin( angle );
+ cp = cos( angle );
+
+ return idVec3_t( cp * cy, cp * sy, -sp );
+}
+
+/*
+=================
+Normalize360
+
+returns angles normalized to the range [0 <= angle < 360]
+=================
+*/
+angles_t& angles_t::Normalize360( void ) {
+ pitch = (360.0 / 65536) * ( ( int )( pitch * ( 65536 / 360.0 ) ) & 65535 );
+ yaw = (360.0 / 65536) * ( ( int )( yaw * ( 65536 / 360.0 ) ) & 65535 );
+ roll = (360.0 / 65536) * ( ( int )( roll * ( 65536 / 360.0 ) ) & 65535 );
+
+ return *this;
+}
+
+
+/*
+=================
+Normalize180
+
+returns angles normalized to the range [-180 < angle <= 180]
+=================
+*/
+angles_t& angles_t::Normalize180( void ) {
+ Normalize360();
+
+ if ( pitch > 180.0 ) {
+ pitch -= 360.0;
+ }
+
+ if ( yaw > 180.0 ) {
+ yaw -= 360.0;
+ }
+
+ if ( roll > 180.0 ) {
+ roll -= 360.0;
+ }
+ return *this;
+}
diff --git a/q3radiant/splines/math_angles.h b/q3radiant/splines/math_angles.h
new file mode 100755
index 0000000..7156e46
--- /dev/null
+++ b/q3radiant/splines/math_angles.h
@@ -0,0 +1,195 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __MATH_ANGLES_H__
+#define __MATH_ANGLES_H__
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "math_vector.h"
+
+class mat3_t;
+class quat_t;
+class idVec3_t;
+typedef idVec3_t &vec3_p;
+
+class angles_t {
+public:
+ float pitch;
+ float yaw;
+ float roll;
+
+ angles_t();
+ angles_t( float pitch, float yaw, float roll );
+ angles_t( const idVec3_t &vec );
+
+ friend void toAngles( idVec3_t &src, angles_t &dst );
+ friend void toAngles( quat_t &src, angles_t &dst );
+ friend void toAngles( mat3_t &src, angles_t &dst );
+
+ operator vec3_p();
+
+ float operator[]( int index ) const;
+ float& operator[]( int index );
+
+ void set( float pitch, float yaw, float roll );
+
+ void operator=( angles_t const &a );
+ void operator=( idVec3_t const &a );
+
+ friend angles_t operator+( const angles_t &a, const angles_t &b );
+ angles_t &operator+=( angles_t const &a );
+ angles_t &operator+=( idVec3_t const &a );
+
+ friend angles_t operator-( angles_t &a, angles_t &b );
+ angles_t &operator-=( angles_t &a );
+
+ friend angles_t operator*( const angles_t &a, float b );
+ friend angles_t operator*( float a, const angles_t &b );
+ angles_t &operator*=( float a );
+
+ friend int operator==( angles_t &a, angles_t &b );
+
+ friend int operator!=( angles_t &a, angles_t &b );
+
+ void toVectors( idVec3_t *forward, idVec3_t *right = NULL, idVec3_t *up = NULL );
+ idVec3_t toForward( void );
+
+ angles_t &Zero( void );
+
+ angles_t &Normalize360( void );
+ angles_t &Normalize180( void );
+};
+
+extern angles_t ang_zero;
+
+inline angles_t::angles_t() {}
+
+inline angles_t::angles_t( float pitch, float yaw, float roll ) {
+ this->pitch = pitch;
+ this->yaw = yaw;
+ this->roll = roll;
+}
+
+inline angles_t::angles_t( const idVec3_t &vec ) {
+ this->pitch = vec.x;
+ this->yaw = vec.y;
+ this->roll = vec.z;
+}
+
+inline float angles_t::operator[]( int index ) const {
+ assert( ( index >= 0 ) && ( index < 3 ) );
+ return ( &pitch )[ index ];
+}
+
+inline float& angles_t::operator[]( int index ) {
+ assert( ( index >= 0 ) && ( index < 3 ) );
+ return ( &pitch )[ index ];
+}
+
+inline angles_t::operator vec3_p( void ) {
+ return *( idVec3_t * )&pitch;
+}
+
+inline void angles_t::set( float pitch, float yaw, float roll ) {
+ this->pitch = pitch;
+ this->yaw = yaw;
+ this->roll = roll;
+}
+
+inline void angles_t::operator=( angles_t const &a ) {
+ pitch = a.pitch;
+ yaw = a.yaw;
+ roll = a.roll;
+}
+
+inline void angles_t::operator=( idVec3_t const &a ) {
+ pitch = a[ 0 ];
+ yaw = a[ 1 ];
+ roll = a[ 2 ];
+}
+
+inline angles_t operator+( const angles_t &a, const angles_t &b ) {
+ return angles_t( a.pitch + b.pitch, a.yaw + b.yaw, a.roll + b.roll );
+}
+
+inline angles_t& angles_t::operator+=( angles_t const &a ) {
+ pitch += a.pitch;
+ yaw += a.yaw;
+ roll += a.roll;
+
+ return *this;
+}
+
+inline angles_t& angles_t::operator+=( idVec3_t const &a ) {
+ pitch += a.x;
+ yaw += a.y;
+ roll += a.z;
+
+ return *this;
+}
+
+inline angles_t operator-( angles_t &a, angles_t &b ) {
+ return angles_t( a.pitch - b.pitch, a.yaw - b.yaw, a.roll - b.roll );
+}
+
+inline angles_t& angles_t::operator-=( angles_t &a ) {
+ pitch -= a.pitch;
+ yaw -= a.yaw;
+ roll -= a.roll;
+
+ return *this;
+}
+
+inline angles_t operator*( const angles_t &a, float b ) {
+ return angles_t( a.pitch * b, a.yaw * b, a.roll * b );
+}
+
+inline angles_t operator*( float a, const angles_t &b ) {
+ return angles_t( a * b.pitch, a * b.yaw, a * b.roll );
+}
+
+inline angles_t& angles_t::operator*=( float a ) {
+ pitch *= a;
+ yaw *= a;
+ roll *= a;
+
+ return *this;
+}
+
+inline int operator==( angles_t &a, angles_t &b ) {
+ return ( ( a.pitch == b.pitch ) && ( a.yaw == b.yaw ) && ( a.roll == b.roll ) );
+}
+
+inline int operator!=( angles_t &a, angles_t &b ) {
+ return ( ( a.pitch != b.pitch ) || ( a.yaw != b.yaw ) || ( a.roll != b.roll ) );
+}
+
+inline angles_t& angles_t::Zero( void ) {
+ pitch = 0.0f;
+ yaw = 0.0f;
+ roll = 0.0f;
+
+ return *this;
+}
+
+#endif /* !__MATH_ANGLES_H__ */
diff --git a/q3radiant/splines/math_matrix.cpp b/q3radiant/splines/math_matrix.cpp
new file mode 100755
index 0000000..24ae914
--- /dev/null
+++ b/q3radiant/splines/math_matrix.cpp
@@ -0,0 +1,134 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#include "q_shared.h"
+
+mat3_t mat3_default( idVec3_t( 1, 0, 0 ), idVec3_t( 0, 1, 0 ), idVec3_t( 0, 0, 1 ) );
+
+void toMatrix( quat_t const &src, mat3_t &dst ) {
+ float wx, wy, wz;
+ float xx, yy, yz;
+ float xy, xz, zz;
+ float x2, y2, z2;
+
+ x2 = src.x + src.x;
+ y2 = src.y + src.y;
+ z2 = src.z + src.z;
+
+ xx = src.x * x2;
+ xy = src.x * y2;
+ xz = src.x * z2;
+
+ yy = src.y * y2;
+ yz = src.y * z2;
+ zz = src.z * z2;
+
+ wx = src.w * x2;
+ wy = src.w * y2;
+ wz = src.w * z2;
+
+ dst[ 0 ][ 0 ] = 1.0f - ( yy + zz );
+ dst[ 0 ][ 1 ] = xy - wz;
+ dst[ 0 ][ 2 ] = xz + wy;
+
+ dst[ 1 ][ 0 ] = xy + wz;
+ dst[ 1 ][ 1 ] = 1.0f - ( xx + zz );
+ dst[ 1 ][ 2 ] = yz - wx;
+
+ dst[ 2 ][ 0 ] = xz - wy;
+ dst[ 2 ][ 1 ] = yz + wx;
+ dst[ 2 ][ 2 ] = 1.0f - ( xx + yy );
+}
+
+void toMatrix( angles_t const &src, mat3_t &dst ) {
+ float angle;
+ static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs
+
+ angle = src.yaw * ( M_PI * 2.0f / 360.0f );
+ sy = sin( angle );
+ cy = cos( angle );
+
+ angle = src.pitch * ( M_PI * 2.0f / 360.0f );
+ sp = sin( angle );
+ cp = cos( angle );
+
+ angle = src.roll * ( M_PI * 2.0f / 360.0f );
+ sr = sin( angle );
+ cr = cos( angle );
+
+ dst[ 0 ].set( cp * cy, cp * sy, -sp );
+ dst[ 1 ].set( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp );
+ dst[ 2 ].set( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp );
+}
+
+void toMatrix( idVec3_t const &src, mat3_t &dst ) {
+ angles_t sup = src;
+ toMatrix(sup, dst);
+}
+
+void mat3_t::ProjectVector( const idVec3_t &src, idVec3_t &dst ) const {
+ dst.x = src * mat[ 0 ];
+ dst.y = src * mat[ 1 ];
+ dst.z = src * mat[ 2 ];
+}
+
+void mat3_t::UnprojectVector( const idVec3_t &src, idVec3_t &dst ) const {
+ dst = mat[ 0 ] * src.x + mat[ 1 ] * src.y + mat[ 2 ] * src.z;
+}
+
+void mat3_t::Transpose( mat3_t &matrix ) {
+ int i;
+ int j;
+
+ for( i = 0; i < 3; i++ ) {
+ for( j = 0; j < 3; j++ ) {
+ matrix[ i ][ j ] = mat[ j ][ i ];
+ }
+ }
+}
+
+void mat3_t::Transpose( void ) {
+ float temp;
+ int i;
+ int j;
+
+ for( i = 0; i < 3; i++ ) {
+ for( j = i + 1; j < 3; j++ ) {
+ temp = mat[ i ][ j ];
+ mat[ i ][ j ] = mat[ j ][ i ];
+ mat[ j ][ i ] = temp;
+ }
+ }
+}
+
+mat3_t mat3_t::Inverse( void ) const {
+ mat3_t inv( *this );
+
+ inv.Transpose();
+
+ return inv;
+}
+
+void mat3_t::Clear( void ) {
+ mat[0].set( 1, 0, 0 );
+ mat[1].set( 0, 1, 0 );
+ mat[2].set( 0, 0, 1 );
+}
diff --git a/q3radiant/splines/math_matrix.h b/q3radiant/splines/math_matrix.h
new file mode 100755
index 0000000..ed1da0d
--- /dev/null
+++ b/q3radiant/splines/math_matrix.h
@@ -0,0 +1,223 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __MATH_MATRIX_H__
+#define __MATH_MATRIX_H__
+
+#include <string.h>
+#include "math_vector.h"
+
+#ifndef ID_INLINE
+#ifdef _WIN32
+#define ID_INLINE __inline
+#else
+#define ID_INLINE inline
+#endif
+#endif
+
+class quat_t;
+class angles_t;
+
+class mat3_t {
+public:
+ idVec3_t mat[ 3 ];
+
+ mat3_t();
+ mat3_t( float src[ 3 ][ 3 ] );
+ mat3_t( idVec3_t const &x, idVec3_t const &y, idVec3_t const &z );
+ mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz );
+
+ friend void toMatrix( quat_t const &src, mat3_t &dst );
+ friend void toMatrix( angles_t const &src, mat3_t &dst );
+ friend void toMatrix( idVec3_t const &src, mat3_t &dst );
+
+ idVec3_t operator[]( int index ) const;
+ idVec3_t &operator[]( int index );
+
+ idVec3_t operator*( const idVec3_t &vec ) const;
+ mat3_t operator*( const mat3_t &a ) const;
+ mat3_t operator*( float a ) const;
+ mat3_t operator+( mat3_t const &a ) const;
+ mat3_t operator-( mat3_t const &a ) const;
+
+ friend idVec3_t operator*( const idVec3_t &vec, const mat3_t &mat );
+ friend mat3_t operator*( float a, mat3_t const &b );
+
+ mat3_t &operator*=( float a );
+ mat3_t &operator+=( mat3_t const &a );
+ mat3_t &operator-=( mat3_t const &a );
+
+ void Clear( void );
+
+ void ProjectVector( const idVec3_t &src, idVec3_t &dst ) const;
+ void UnprojectVector( const idVec3_t &src, idVec3_t &dst ) const;
+
+ void OrthoNormalize( void );
+ void Transpose( mat3_t &matrix );
+ void Transpose( void );
+ mat3_t Inverse( void ) const;
+ void Identity( void );
+
+ friend void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst );
+ friend mat3_t SkewSymmetric( idVec3_t const &src );
+};
+
+ID_INLINE mat3_t::mat3_t() {
+}
+
+ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
+ memcpy( mat, src, sizeof( src ) );
+}
+
+ID_INLINE mat3_t::mat3_t( idVec3_t const &x, idVec3_t const &y, idVec3_t const &z ) {
+ mat[ 0 ].x = x.x; mat[ 0 ].y = x.y; mat[ 0 ].z = x.z;
+ mat[ 1 ].x = y.x; mat[ 1 ].y = y.y; mat[ 1 ].z = y.z;
+ mat[ 2 ].x = z.x; mat[ 2 ].y = z.y; mat[ 2 ].z = z.z;
+}
+
+ID_INLINE mat3_t::mat3_t( const float xx, const float xy, const float xz, const float yx, const float yy, const float yz, const float zx, const float zy, const float zz ) {
+ mat[ 0 ].x = xx; mat[ 0 ].y = xy; mat[ 0 ].z = xz;
+ mat[ 1 ].x = yx; mat[ 1 ].y = yy; mat[ 1 ].z = yz;
+ mat[ 2 ].x = zx; mat[ 2 ].y = zy; mat[ 2 ].z = zz;
+}
+
+ID_INLINE idVec3_t mat3_t::operator[]( int index ) const {
+ assert( ( index >= 0 ) && ( index < 3 ) );
+ return mat[ index ];
+}
+
+ID_INLINE idVec3_t& mat3_t::operator[]( int index ) {
+ assert( ( index >= 0 ) && ( index < 3 ) );
+ return mat[ index ];
+}
+
+ID_INLINE idVec3_t mat3_t::operator*( const idVec3_t &vec ) const {
+ return idVec3_t(
+ mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z,
+ mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z,
+ mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z );
+}
+
+ID_INLINE mat3_t mat3_t::operator*( const mat3_t &a ) const {
+ return mat3_t(
+ mat[0].x * a[0].x + mat[0].y * a[1].x + mat[0].z * a[2].x,
+ mat[0].x * a[0].y + mat[0].y * a[1].y + mat[0].z * a[2].y,
+ mat[0].x * a[0].z + mat[0].y * a[1].z + mat[0].z * a[2].z,
+ mat[1].x * a[0].x + mat[1].y * a[1].x + mat[1].z * a[2].x,
+ mat[1].x * a[0].y + mat[1].y * a[1].y + mat[1].z * a[2].y,
+ mat[1].x * a[0].z + mat[1].y * a[1].z + mat[1].z * a[2].z,
+ mat[2].x * a[0].x + mat[2].y * a[1].x + mat[2].z * a[2].x,
+ mat[2].x * a[0].y + mat[2].y * a[1].y + mat[2].z * a[2].y,
+ mat[2].x * a[0].z + mat[2].y * a[1].z + mat[2].z * a[2].z );
+}
+
+ID_INLINE mat3_t mat3_t::operator*( float a ) const {
+ return mat3_t(
+ mat[0].x * a, mat[0].y * a, mat[0].z * a,
+ mat[1].x * a, mat[1].y * a, mat[1].z * a,
+ mat[2].x * a, mat[2].y * a, mat[2].z * a );
+}
+
+ID_INLINE mat3_t mat3_t::operator+( mat3_t const &a ) const {
+ return mat3_t(
+ mat[0].x + a[0].x, mat[0].y + a[0].y, mat[0].z + a[0].z,
+ mat[1].x + a[1].x, mat[1].y + a[1].y, mat[1].z + a[1].z,
+ mat[2].x + a[2].x, mat[2].y + a[2].y, mat[2].z + a[2].z );
+}
+
+ID_INLINE mat3_t mat3_t::operator-( mat3_t const &a ) const {
+ return mat3_t(
+ mat[0].x - a[0].x, mat[0].y - a[0].y, mat[0].z - a[0].z,
+ mat[1].x - a[1].x, mat[1].y - a[1].y, mat[1].z - a[1].z,
+ mat[2].x - a[2].x, mat[2].y - a[2].y, mat[2].z - a[2].z );
+}
+
+ID_INLINE idVec3_t operator*( const idVec3_t &vec, const mat3_t &mat ) {
+ return idVec3_t(
+ mat[ 0 ].x * vec.x + mat[ 1 ].x * vec.y + mat[ 2 ].x * vec.z,
+ mat[ 0 ].y * vec.x + mat[ 1 ].y * vec.y + mat[ 2 ].y * vec.z,
+ mat[ 0 ].z * vec.x + mat[ 1 ].z * vec.y + mat[ 2 ].z * vec.z );
+}
+
+ID_INLINE mat3_t operator*( float a, mat3_t const &b ) {
+ return mat3_t(
+ b[0].x * a, b[0].y * a, b[0].z * a,
+ b[1].x * a, b[1].y * a, b[1].z * a,
+ b[2].x * a, b[2].y * a, b[2].z * a );
+}
+
+ID_INLINE mat3_t &mat3_t::operator*=( float a ) {
+ mat[0].x *= a; mat[0].y *= a; mat[0].z *= a;
+ mat[1].x *= a; mat[1].y *= a; mat[1].z *= a;
+ mat[2].x *= a; mat[2].y *= a; mat[2].z *= a;
+
+ return *this;
+}
+
+ID_INLINE mat3_t &mat3_t::operator+=( mat3_t const &a ) {
+ mat[0].x += a[0].x; mat[0].y += a[0].y; mat[0].z += a[0].z;
+ mat[1].x += a[1].x; mat[1].y += a[1].y; mat[1].z += a[1].z;
+ mat[2].x += a[2].x; mat[2].y += a[2].y; mat[2].z += a[2].z;
+
+ return *this;
+}
+
+ID_INLINE mat3_t &mat3_t::operator-=( mat3_t const &a ) {
+ mat[0].x -= a[0].x; mat[0].y -= a[0].y; mat[0].z -= a[0].z;
+ mat[1].x -= a[1].x; mat[1].y -= a[1].y; mat[1].z -= a[1].z;
+ mat[2].x -= a[2].x; mat[2].y -= a[2].y; mat[2].z -= a[2].z;
+
+ return *this;
+}
+
+ID_INLINE void mat3_t::OrthoNormalize( void ) {
+ mat[ 0 ].Normalize();
+ mat[ 2 ].Cross( mat[ 0 ], mat[ 1 ] );
+ mat[ 2 ].Normalize();
+ mat[ 1 ].Cross( mat[ 2 ], mat[ 0 ] );
+ mat[ 1 ].Normalize();
+}
+
+ID_INLINE void mat3_t::Identity( void ) {
+ mat[ 0 ].x = 1.f; mat[ 0 ].y = 0.f; mat[ 0 ].z = 0.f;
+ mat[ 1 ].x = 0.f; mat[ 1 ].y = 1.f; mat[ 1 ].z = 0.f;
+ mat[ 2 ].x = 0.f; mat[ 2 ].y = 0.f; mat[ 2 ].z = 1.f;
+}
+
+ID_INLINE void InverseMultiply( const mat3_t &inv, const mat3_t &b, mat3_t &dst ) {
+ dst[0].x = inv[0].x * b[0].x + inv[1].x * b[1].x + inv[2].x * b[2].x;
+ dst[0].y = inv[0].x * b[0].y + inv[1].x * b[1].y + inv[2].x * b[2].y;
+ dst[0].z = inv[0].x * b[0].z + inv[1].x * b[1].z + inv[2].x * b[2].z;
+ dst[1].x = inv[0].y * b[0].x + inv[1].y * b[1].x + inv[2].y * b[2].x;
+ dst[1].y = inv[0].y * b[0].y + inv[1].y * b[1].y + inv[2].y * b[2].y;
+ dst[1].z = inv[0].y * b[0].z + inv[1].y * b[1].z + inv[2].y * b[2].z;
+ dst[2].x = inv[0].z * b[0].x + inv[1].z * b[1].x + inv[2].z * b[2].x;
+ dst[2].y = inv[0].z * b[0].y + inv[1].z * b[1].y + inv[2].z * b[2].y;
+ dst[2].z = inv[0].z * b[0].z + inv[1].z * b[1].z + inv[2].z * b[2].z;
+}
+
+ID_INLINE mat3_t SkewSymmetric( idVec3_t const &src ) {
+ return mat3_t( 0.0f, -src.z, src.y, src.z, 0.0f, -src.x, -src.y, src.x, 0.0f );
+}
+
+extern mat3_t mat3_default;
+
+#endif /* !__MATH_MATRIX_H__ */
diff --git a/q3radiant/splines/math_quaternion.cpp b/q3radiant/splines/math_quaternion.cpp
new file mode 100755
index 0000000..4ef670e
--- /dev/null
+++ b/q3radiant/splines/math_quaternion.cpp
@@ -0,0 +1,78 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#include "math_quaternion.h"
+#include "math_matrix.h"
+
+void toQuat( idVec3_t &src, quat_t &dst ) {
+ dst.x = src.x;
+ dst.y = src.y;
+ dst.z = src.z;
+ dst.w = 0.0f;
+}
+
+void toQuat( angles_t &src, quat_t &dst ) {
+ mat3_t temp;
+
+ toMatrix( src, temp );
+ toQuat( temp, dst );
+}
+
+void toQuat( mat3_t &src, quat_t &dst ) {
+ float trace;
+ float s;
+ int i;
+ int j;
+ int k;
+
+ static int next[ 3 ] = { 1, 2, 0 };
+
+ trace = src[ 0 ][ 0 ] + src[ 1 ][ 1 ] + src[ 2 ][ 2 ];
+ if ( trace > 0.0f ) {
+ s = ( float )sqrt( trace + 1.0f );
+ dst.w = s * 0.5f;
+ s = 0.5f / s;
+
+ dst.x = ( src[ 2 ][ 1 ] - src[ 1 ][ 2 ] ) * s;
+ dst.y = ( src[ 0 ][ 2 ] - src[ 2 ][ 0 ] ) * s;
+ dst.z = ( src[ 1 ][ 0 ] - src[ 0 ][ 1 ] ) * s;
+ } else {
+ i = 0;
+ if ( src[ 1 ][ 1 ] > src[ 0 ][ 0 ] ) {
+ i = 1;
+ }
+ if ( src[ 2 ][ 2 ] > src[ i ][ i ] ) {
+ i = 2;
+ }
+
+ j = next[ i ];
+ k = next[ j ];
+
+ s = ( float )sqrt( ( src[ i ][ i ] - ( src[ j ][ j ] + src[ k ][ k ] ) ) + 1.0f );
+ dst[ i ] = s * 0.5f;
+
+ s = 0.5f / s;
+
+ dst.w = ( src[ k ][ j ] - src[ j ][ k ] ) * s;
+ dst[ j ] = ( src[ j ][ i ] + src[ i ][ j ] ) * s;
+ dst[ k ] = ( src[ k ][ i ] + src[ i ][ k ] ) * s;
+ }
+}
diff --git a/q3radiant/splines/math_quaternion.h b/q3radiant/splines/math_quaternion.h
new file mode 100755
index 0000000..74ae2ac
--- /dev/null
+++ b/q3radiant/splines/math_quaternion.h
@@ -0,0 +1,190 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __MATH_QUATERNION_H__
+#define __MATH_QUATERNION_H__
+
+#include <assert.h>
+#include <math.h>
+
+class idVec3_t;
+class angles_t;
+class mat3_t;
+
+class quat_t {
+public:
+ float x;
+ float y;
+ float z;
+ float w;
+
+ quat_t();
+ quat_t( float x, float y, float z, float w );
+
+ friend void toQuat( idVec3_t &src, quat_t &dst );
+ friend void toQuat( angles_t &src, quat_t &dst );
+ friend void toQuat( mat3_t &src, quat_t &dst );
+
+ float *vec4( void );
+
+ float operator[]( int index ) const;
+ float &operator[]( int index );
+
+ void set( float x, float y, float z, float w );
+
+ void operator=( quat_t a );
+
+ friend quat_t operator+( quat_t a, quat_t b );
+ quat_t &operator+=( quat_t a );
+
+ friend quat_t operator-( quat_t a, quat_t b );
+ quat_t &operator-=( quat_t a );
+
+ friend quat_t operator*( quat_t a, float b );
+ friend quat_t operator*( float a, quat_t b );
+ quat_t &operator*=( float a );
+
+ friend int operator==( quat_t a, quat_t b );
+ friend int operator!=( quat_t a, quat_t b );
+
+ float Length( void );
+ quat_t &Normalize( void );
+
+ quat_t operator-();
+};
+
+inline quat_t::quat_t() {
+}
+
+inline quat_t::quat_t( float x, float y, float z, float w ) {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+ this->w = w;
+}
+
+inline float *quat_t::vec4( void ) {
+ return &x;
+}
+
+inline float quat_t::operator[]( int index ) const {
+ assert( ( index >= 0 ) && ( index < 4 ) );
+ return ( &x )[ index ];
+}
+
+inline float& quat_t::operator[]( int index ) {
+ assert( ( index >= 0 ) && ( index < 4 ) );
+ return ( &x )[ index ];
+}
+
+inline void quat_t::set( float x, float y, float z, float w ) {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+ this->w = w;
+}
+
+inline void quat_t::operator=( quat_t a ) {
+ x = a.x;
+ y = a.y;
+ z = a.z;
+ w = a.w;
+}
+
+inline quat_t operator+( quat_t a, quat_t b ) {
+ return quat_t( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w );
+}
+
+inline quat_t& quat_t::operator+=( quat_t a ) {
+ x += a.x;
+ y += a.y;
+ z += a.z;
+ w += a.w;
+
+ return *this;
+}
+
+inline quat_t operator-( quat_t a, quat_t b ) {
+ return quat_t( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w );
+}
+
+inline quat_t& quat_t::operator-=( quat_t a ) {
+ x -= a.x;
+ y -= a.y;
+ z -= a.z;
+ w -= a.w;
+
+ return *this;
+}
+
+inline quat_t operator*( quat_t a, float b ) {
+ return quat_t( a.x * b, a.y * b, a.z * b, a.w * b );
+}
+
+inline quat_t operator*( float a, quat_t b ) {
+ return b * a;
+}
+
+inline quat_t& quat_t::operator*=( float a ) {
+ x *= a;
+ y *= a;
+ z *= a;
+ w *= a;
+
+ return *this;
+}
+
+inline int operator==( quat_t a, quat_t b ) {
+ return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) );
+}
+
+inline int operator!=( quat_t a, quat_t b ) {
+ return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) );
+}
+
+inline float quat_t::Length( void ) {
+ float length;
+
+ length = x * x + y * y + z * z + w * w;
+ return ( float )sqrt( length );
+}
+
+inline quat_t& quat_t::Normalize( void ) {
+ float length;
+ float ilength;
+
+ length = this->Length();
+ if ( length ) {
+ ilength = 1 / length;
+ x *= ilength;
+ y *= ilength;
+ z *= ilength;
+ w *= ilength;
+ }
+
+ return *this;
+}
+
+inline quat_t quat_t::operator-() {
+ return quat_t( -x, -y, -z, -w );
+}
+
+#endif /* !__MATH_QUATERNION_H__ */
diff --git a/q3radiant/splines/math_vector.cpp b/q3radiant/splines/math_vector.cpp
new file mode 100755
index 0000000..120258c
--- /dev/null
+++ b/q3radiant/splines/math_vector.cpp
@@ -0,0 +1,144 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//#include "../game/q_shared.h"
+#include "math_vector.h"
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+
+#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
+
+#define LERP_DELTA 1e-6
+
+idVec3_t vec_zero( 0.0f, 0.0f, 0.0f );
+
+Bounds boundsZero;
+
+float idVec3_t::toYaw( void ) {
+ float yaw;
+
+ if ( ( y == 0 ) && ( x == 0 ) ) {
+ yaw = 0;
+ } else {
+ yaw = atan2( y, x ) * 180 / M_PI;
+ if ( yaw < 0 ) {
+ yaw += 360;
+ }
+ }
+
+ return yaw;
+}
+
+float idVec3_t::toPitch( void ) {
+ float forward;
+ float pitch;
+
+ if ( ( x == 0 ) && ( y == 0 ) ) {
+ if ( z > 0 ) {
+ pitch = 90;
+ } else {
+ pitch = 270;
+ }
+ } else {
+ forward = ( float )idSqrt( x * x + y * y );
+ pitch = atan2( z, forward ) * 180 / M_PI;
+ if ( pitch < 0 ) {
+ pitch += 360;
+ }
+ }
+
+ return pitch;
+}
+
+/*
+angles_t idVec3_t::toAngles( void ) {
+ float forward;
+ float yaw;
+ float pitch;
+
+ if ( ( x == 0 ) && ( y == 0 ) ) {
+ yaw = 0;
+ if ( z > 0 ) {
+ pitch = 90;
+ } else {
+ pitch = 270;
+ }
+ } else {
+ yaw = atan2( y, x ) * 180 / M_PI;
+ if ( yaw < 0 ) {
+ yaw += 360;
+ }
+
+ forward = ( float )idSqrt( x * x + y * y );
+ pitch = atan2( z, forward ) * 180 / M_PI;
+ if ( pitch < 0 ) {
+ pitch += 360;
+ }
+ }
+
+ return angles_t( -pitch, yaw, 0 );
+}
+*/
+
+idVec3_t LerpVector( idVec3_t &w1, idVec3_t &w2, const float t ) {
+ float omega, cosom, sinom, scale0, scale1;
+
+ cosom = w1 * w2;
+ if ( ( 1.0 - cosom ) > LERP_DELTA ) {
+ omega = acos( cosom );
+ sinom = sin( omega );
+ scale0 = sin( ( 1.0 - t ) * omega ) / sinom;
+ scale1 = sin( t * omega ) / sinom;
+ } else {
+ scale0 = 1.0 - t;
+ scale1 = t;
+ }
+
+ return ( w1 * scale0 + w2 * scale1 );
+}
+
+/*
+=============
+idVec3_t::string
+
+This is just a convenience function
+for printing vectors
+=============
+*/
+char *idVec3_t::string( void ) {
+ static int index = 0;
+ static char str[ 8 ][ 36 ];
+ char *s;
+
+ // use an array so that multiple toString's won't collide
+ s = str[ index ];
+ index = (index + 1)&7;
+
+ sprintf( s, "%.2f %.2f %.2f", x, y, z );
+
+ return s;
+}
diff --git a/q3radiant/splines/math_vector.h b/q3radiant/splines/math_vector.h
new file mode 100755
index 0000000..8afc541
--- /dev/null
+++ b/q3radiant/splines/math_vector.h
@@ -0,0 +1,572 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __MATH_VECTOR_H__
+#define __MATH_VECTOR_H__
+
+#pragma warning(disable : 4244)
+
+#include <math.h>
+#include <assert.h>
+
+//#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
+//#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
+//#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
+//#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
+//#define VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z])
+
+//#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
+#define __VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
+//#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
+
+#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3])
+#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3])
+#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3])
+#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s))
+#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s))
+
+
+//#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
+#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
+//#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
+#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+
+#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];}
+
+
+//#include "util_heap.h"
+
+#ifndef EQUAL_EPSILON
+#define EQUAL_EPSILON 0.001
+#endif
+
+float Q_fabs( float f );
+
+#ifndef ID_INLINE
+#ifdef _WIN32
+#define ID_INLINE __inline
+#else
+#define ID_INLINE inline
+#endif
+#endif
+
+// if this is defined, vec3 will take four elements, which may allow
+// easier SIMD optimizations
+//#define FAT_VEC3
+//#ifdef __ppc__
+//#pragma align(16)
+//#endif
+
+class angles_t;
+#ifdef __ppc__
+// Vanilla PPC code, but since PPC has a reciprocal square root estimate instruction,
+// runs *much* faster than calling sqrt(). We'll use two Newton-Raphson
+// refinement steps to get bunch more precision in the 1/sqrt() value for very little cost.
+// We'll then multiply 1/sqrt times the original value to get the sqrt.
+// This is about 12.4 times faster than sqrt() and according to my testing (not exhaustive)
+// it returns fairly accurate results (error below 1.0e-5 up to 100000.0 in 0.1 increments).
+
+static inline float idSqrt(float x) {
+ const float half = 0.5;
+ const float one = 1.0;
+ float B, y0, y1;
+
+ // This'll NaN if it hits frsqrte. Handle both +0.0 and -0.0
+ if (fabs(x) == 0.0)
+ return x;
+ B = x;
+
+#ifdef __GNUC__
+ asm("frsqrte %0,%1" : "=f" (y0) : "f" (B));
+#else
+ y0 = __frsqrte(B);
+#endif
+ /* First refinement step */
+
+ y1 = y0 + half*y0*(one - B*y0*y0);
+
+ /* Second refinement step -- copy the output of the last step to the input of this step */
+
+ y0 = y1;
+ y1 = y0 + half*y0*(one - B*y0*y0);
+
+ /* Get sqrt(x) from x * 1/sqrt(x) */
+ return x * y1;
+}
+#else
+static inline double idSqrt(double x) {
+ return sqrt(x);
+}
+#endif
+
+
+//class idVec3_t : public idHeap<idVec3_t> {
+class idVec3_t {
+public:
+#ifndef FAT_VEC3
+ float x,y,z;
+#else
+ float x,y,z,dist;
+#endif
+
+#ifndef FAT_VEC3
+ idVec3_t() {};
+#else
+ idVec3_t() {dist = 0.0f;};
+#endif
+ idVec3_t( const float x, const float y, const float z );
+
+ operator float *();
+
+ float operator[]( const int index ) const;
+ float &operator[]( const int index );
+
+ void set( const float x, const float y, const float z );
+
+ idVec3_t operator-() const;
+
+ idVec3_t &operator=( const idVec3_t &a );
+
+ float operator*( const idVec3_t &a ) const;
+ idVec3_t operator*( const float a ) const;
+ friend idVec3_t operator*( float a, idVec3_t b );
+
+ idVec3_t operator+( const idVec3_t &a ) const;
+ idVec3_t operator-( const idVec3_t &a ) const;
+
+ idVec3_t &operator+=( const idVec3_t &a );
+ idVec3_t &operator-=( const idVec3_t &a );
+ idVec3_t &operator*=( const float a );
+
+ int operator==( const idVec3_t &a ) const;
+ int operator!=( const idVec3_t &a ) const;
+
+ idVec3_t Cross( const idVec3_t &a ) const;
+ idVec3_t &Cross( const idVec3_t &a, const idVec3_t &b );
+
+ float Length( void ) const;
+ float Normalize( void );
+
+ void Zero( void );
+ void Snap( void );
+ void SnapTowards( const idVec3_t &to );
+
+ float toYaw( void );
+ float toPitch( void );
+ angles_t toAngles( void );
+ friend idVec3_t LerpVector( const idVec3_t &w1, const idVec3_t &w2, const float t );
+
+ char *string( void );
+};
+
+extern idVec3_t vec_zero;
+
+ID_INLINE idVec3_t::idVec3_t( const float x, const float y, const float z ) {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+#ifdef FAT_VEC3
+ this->dist = 0.0f;
+#endif
+}
+
+ID_INLINE float idVec3_t::operator[]( const int index ) const {
+ return ( &x )[ index ];
+}
+
+ID_INLINE float &idVec3_t::operator[]( const int index ) {
+ return ( &x )[ index ];
+}
+
+ID_INLINE idVec3_t::operator float *( void ) {
+ return &x;
+}
+
+ID_INLINE idVec3_t idVec3_t::operator-() const {
+ return idVec3_t( -x, -y, -z );
+}
+
+ID_INLINE idVec3_t &idVec3_t::operator=( const idVec3_t &a ) {
+ x = a.x;
+ y = a.y;
+ z = a.z;
+
+ return *this;
+}
+
+ID_INLINE void idVec3_t::set( const float x, const float y, const float z ) {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+}
+
+ID_INLINE idVec3_t idVec3_t::operator-( const idVec3_t &a ) const {
+ return idVec3_t( x - a.x, y - a.y, z - a.z );
+}
+
+ID_INLINE float idVec3_t::operator*( const idVec3_t &a ) const {
+ return x * a.x + y * a.y + z * a.z;
+}
+
+ID_INLINE idVec3_t idVec3_t::operator*( const float a ) const {
+ return idVec3_t( x * a, y * a, z * a );
+}
+
+ID_INLINE idVec3_t operator*( const float a, const idVec3_t b ) {
+ return idVec3_t( b.x * a, b.y * a, b.z * a );
+}
+
+ID_INLINE idVec3_t idVec3_t::operator+( const idVec3_t &a ) const {
+ return idVec3_t( x + a.x, y + a.y, z + a.z );
+}
+
+ID_INLINE idVec3_t &idVec3_t::operator+=( const idVec3_t &a ) {
+ x += a.x;
+ y += a.y;
+ z += a.z;
+
+ return *this;
+}
+
+ID_INLINE idVec3_t &idVec3_t::operator-=( const idVec3_t &a ) {
+ x -= a.x;
+ y -= a.y;
+ z -= a.z;
+
+ return *this;
+}
+
+ID_INLINE idVec3_t &idVec3_t::operator*=( const float a ) {
+ x *= a;
+ y *= a;
+ z *= a;
+
+ return *this;
+}
+
+ID_INLINE int idVec3_t::operator==( const idVec3_t &a ) const {
+ if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) {
+ return false;
+ }
+
+ if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) {
+ return false;
+ }
+
+ if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) {
+ return false;
+ }
+
+ return true;
+}
+
+ID_INLINE int idVec3_t::operator!=( const idVec3_t &a ) const {
+ if ( Q_fabs( x - a.x ) > EQUAL_EPSILON ) {
+ return true;
+ }
+
+ if ( Q_fabs( y - a.y ) > EQUAL_EPSILON ) {
+ return true;
+ }
+
+ if ( Q_fabs( z - a.z ) > EQUAL_EPSILON ) {
+ return true;
+ }
+
+ return false;
+}
+
+ID_INLINE idVec3_t idVec3_t::Cross( const idVec3_t &a ) const {
+ return idVec3_t( y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x );
+}
+
+ID_INLINE idVec3_t &idVec3_t::Cross( const idVec3_t &a, const idVec3_t &b ) {
+ x = a.y * b.z - a.z * b.y;
+ y = a.z * b.x - a.x * b.z;
+ z = a.x * b.y - a.y * b.x;
+
+ return *this;
+}
+
+ID_INLINE float idVec3_t::Length( void ) const {
+ float length;
+
+ length = x * x + y * y + z * z;
+ return ( float )idSqrt( length );
+}
+
+ID_INLINE float idVec3_t::Normalize( void ) {
+ float length;
+ float ilength;
+
+ length = this->Length();
+ if ( length ) {
+ ilength = 1.0f / length;
+ x *= ilength;
+ y *= ilength;
+ z *= ilength;
+ }
+
+ return length;
+}
+
+ID_INLINE void idVec3_t::Zero( void ) {
+ x = 0.0f;
+ y = 0.0f;
+ z = 0.0f;
+}
+
+ID_INLINE void idVec3_t::Snap( void ) {
+ x = float( int( x ) );
+ y = float( int( y ) );
+ z = float( int( z ) );
+}
+
+/*
+======================
+SnapTowards
+
+Round a vector to integers for more efficient network
+transmission, but make sure that it rounds towards a given point
+rather than blindly truncating. This prevents it from truncating
+into a wall.
+======================
+*/
+ID_INLINE void idVec3_t::SnapTowards( const idVec3_t &to ) {
+ if ( to.x <= x ) {
+ x = float( int( x ) );
+ } else {
+ x = float( int( x ) + 1 );
+ }
+
+ if ( to.y <= y ) {
+ y = float( int( y ) );
+ } else {
+ y = float( int( y ) + 1 );
+ }
+
+ if ( to.z <= z ) {
+ z = float( int( z ) );
+ } else {
+ z = float( int( z ) + 1 );
+ }
+}
+
+//===============================================================
+
+class Bounds {
+public:
+ idVec3_t b[2];
+
+ Bounds();
+ Bounds( const idVec3_t &mins, const idVec3_t &maxs );
+
+ void Clear();
+ void Zero();
+ float Radius(); // radius from origin, not from center
+ idVec3_t Center();
+ void AddPoint( const idVec3_t &v );
+ void AddBounds( const Bounds &bb );
+ bool IsCleared();
+ bool ContainsPoint( const idVec3_t &p );
+ bool IntersectsBounds( const Bounds &b2 ); // touching is NOT intersecting
+};
+
+extern Bounds boundsZero;
+
+ID_INLINE Bounds::Bounds(){
+}
+
+ID_INLINE bool Bounds::IsCleared() {
+ return b[0][0] > b[1][0];
+}
+
+ID_INLINE bool Bounds::ContainsPoint( const idVec3_t &p ) {
+ if ( p[0] < b[0][0] || p[1] < b[0][1] || p[2] < b[0][2]
+ || p[0] > b[1][0] || p[1] > b[1][1] || p[2] > b[1][2] ) {
+ return false;
+ }
+ return true;
+}
+
+ID_INLINE bool Bounds::IntersectsBounds( const Bounds &b2 ) {
+ if ( b2.b[1][0] < b[0][0] || b2.b[1][1] < b[0][1] || b2.b[1][2] < b[0][2]
+ || b2.b[0][0] > b[1][0] || b2.b[0][1] > b[1][1] || b2.b[0][2] > b[1][2] ) {
+ return false;
+ }
+ return true;
+}
+
+ID_INLINE Bounds::Bounds( const idVec3_t &mins, const idVec3_t &maxs ) {
+ b[0] = mins;
+ b[1] = maxs;
+}
+
+ID_INLINE idVec3_t Bounds::Center() {
+ return idVec3_t( ( b[1][0] + b[0][0] ) * 0.5f, ( b[1][1] + b[0][1] ) * 0.5f, ( b[1][2] + b[0][2] ) * 0.5f );
+}
+
+ID_INLINE void Bounds::Clear() {
+ b[0][0] = b[0][1] = b[0][2] = 99999;
+ b[1][0] = b[1][1] = b[1][2] = -99999;
+}
+
+ID_INLINE void Bounds::Zero() {
+ b[0][0] = b[0][1] = b[0][2] =
+ b[1][0] = b[1][1] = b[1][2] = 0;
+}
+
+ID_INLINE void Bounds::AddPoint( const idVec3_t &v ) {
+ if ( v[0] < b[0][0]) {
+ b[0][0] = v[0];
+ }
+ if ( v[0] > b[1][0]) {
+ b[1][0] = v[0];
+ }
+ if ( v[1] < b[0][1] ) {
+ b[0][1] = v[1];
+ }
+ if ( v[1] > b[1][1]) {
+ b[1][1] = v[1];
+ }
+ if ( v[2] < b[0][2] ) {
+ b[0][2] = v[2];
+ }
+ if ( v[2] > b[1][2]) {
+ b[1][2] = v[2];
+ }
+}
+
+
+ID_INLINE void Bounds::AddBounds( const Bounds &bb ) {
+ if ( bb.b[0][0] < b[0][0]) {
+ b[0][0] = bb.b[0][0];
+ }
+ if ( bb.b[0][1] < b[0][1]) {
+ b[0][1] = bb.b[0][1];
+ }
+ if ( bb.b[0][2] < b[0][2]) {
+ b[0][2] = bb.b[0][2];
+ }
+
+ if ( bb.b[1][0] > b[1][0]) {
+ b[1][0] = bb.b[1][0];
+ }
+ if ( bb.b[1][1] > b[1][1]) {
+ b[1][1] = bb.b[1][1];
+ }
+ if ( bb.b[1][2] > b[1][2]) {
+ b[1][2] = bb.b[1][2];
+ }
+}
+
+ID_INLINE float Bounds::Radius( ) {
+ int i;
+ float total;
+ float a, aa;
+
+ total = 0;
+ for (i=0 ; i<3 ; i++) {
+ a = (float)fabs( b[0][i] );
+ aa = (float)fabs( b[1][i] );
+ if ( aa > a ) {
+ a = aa;
+ }
+ total += a * a;
+ }
+
+ return (float)idSqrt( total );
+}
+
+//===============================================================
+
+
+class idVec2_t {
+public:
+ float x;
+ float y;
+
+ operator float *();
+ float operator[]( int index ) const;
+ float &operator[]( int index );
+};
+
+ID_INLINE float idVec2_t::operator[]( int index ) const {
+ return ( &x )[ index ];
+}
+
+ID_INLINE float& idVec2_t::operator[]( int index ) {
+ return ( &x )[ index ];
+}
+
+ID_INLINE idVec2_t::operator float *( void ) {
+ return &x;
+}
+
+class vec4_t : public idVec3_t {
+public:
+#ifndef FAT_VEC3
+ float dist;
+#endif
+ vec4_t();
+ ~vec4_t() {};
+
+ vec4_t( float x, float y, float z, float dist );
+ float operator[]( int index ) const;
+ float &operator[]( int index );
+};
+
+ID_INLINE vec4_t::vec4_t() {}
+ID_INLINE vec4_t::vec4_t( float x, float y, float z, float dist ) {
+ this->x = x;
+ this->y = y;
+ this->z = z;
+ this->dist = dist;
+}
+
+ID_INLINE float vec4_t::operator[]( int index ) const {
+ return ( &x )[ index ];
+}
+
+ID_INLINE float& vec4_t::operator[]( int index ) {
+ return ( &x )[ index ];
+}
+
+
+class idVec5_t : public idVec3_t {
+public:
+ float s;
+ float t;
+ float operator[]( int index ) const;
+ float &operator[]( int index );
+};
+
+
+ID_INLINE float idVec5_t::operator[]( int index ) const {
+ return ( &x )[ index ];
+}
+
+ID_INLINE float& idVec5_t::operator[]( int index ) {
+ return ( &x )[ index ];
+}
+
+#endif /* !__MATH_VECTOR_H__ */
diff --git a/q3radiant/splines/q_parse.cpp b/q3radiant/splines/q_parse.cpp
new file mode 100755
index 0000000..1f61ba4
--- /dev/null
+++ b/q3radiant/splines/q_parse.cpp
@@ -0,0 +1,535 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// q_parse.c -- support for parsing text files
+
+#include "q_shared.h"
+
+/*
+============================================================================
+
+PARSING
+
+============================================================================
+*/
+
+// multiple character punctuation tokens
+static const char *punctuation[] = {
+ "+=", "-=", "*=", "/=", "&=", "|=", "++", "--",
+ "&&", "||", "<=", ">=", "==", "!=",
+ NULL
+};
+
+typedef struct {
+ char token[MAX_TOKEN_CHARS];
+ int lines;
+ qboolean ungetToken;
+ char parseFile[MAX_QPATH];
+} parseInfo_t;
+
+#define MAX_PARSE_INFO 16
+static parseInfo_t parseInfo[MAX_PARSE_INFO];
+static int parseInfoNum;
+static parseInfo_t *pi = &parseInfo[0];
+
+/*
+===================
+Com_BeginParseSession
+===================
+*/
+void Com_BeginParseSession( const char *filename ) {
+ if ( parseInfoNum == MAX_PARSE_INFO - 1 ) {
+ Com_Error( ERR_FATAL, "Com_BeginParseSession: session overflow" );
+ }
+ parseInfoNum++;
+ pi = &parseInfo[parseInfoNum];
+
+ pi->lines = 1;
+ Q_strncpyz( pi->parseFile, filename, sizeof( pi->parseFile ) );
+}
+
+/*
+===================
+Com_EndParseSession
+===================
+*/
+void Com_EndParseSession( void ) {
+ if ( parseInfoNum == 0 ) {
+ Com_Error( ERR_FATAL, "Com_EndParseSession: session underflow" );
+ }
+ parseInfoNum--;
+ pi = &parseInfo[parseInfoNum];
+}
+
+/*
+===================
+Com_GetCurrentParseLine
+===================
+*/
+int Com_GetCurrentParseLine( void ) {
+ return pi->lines;
+}
+
+/*
+===================
+Com_ScriptError
+
+Prints the script name and line number in the message
+===================
+*/
+void Com_ScriptError( const char *msg, ... ) {
+ va_list argptr;
+ char string[32000];
+
+ va_start( argptr, msg );
+ vsprintf( string, msg,argptr );
+ va_end( argptr );
+
+ Com_Error( ERR_DROP, "File %s, line %i: %s", pi->parseFile, pi->lines, string );
+}
+
+void Com_ScriptWarning( const char *msg, ... ) {
+ va_list argptr;
+ char string[32000];
+
+ va_start( argptr, msg );
+ vsprintf( string, msg,argptr );
+ va_end( argptr );
+
+ Com_Printf( "File %s, line %i: %s", pi->parseFile, pi->lines, string );
+}
+
+
+/*
+===================
+Com_UngetToken
+
+Calling this will make the next Com_Parse return
+the current token instead of advancing the pointer
+===================
+*/
+void Com_UngetToken( void ) {
+ if ( pi->ungetToken ) {
+ Com_ScriptError( "UngetToken called twice" );
+ }
+ pi->ungetToken = qtrue;
+}
+
+
+static const char *SkipWhitespace( const char (*data), qboolean *hasNewLines ) {
+ int c;
+
+ while( (c = *data) <= ' ') {
+ if( !c ) {
+ return NULL;
+ }
+ if( c == '\n' ) {
+ pi->lines++;
+ *hasNewLines = qtrue;
+ }
+ data++;
+ }
+
+ return data;
+}
+
+/*
+==============
+Com_ParseExt
+
+Parse a token out of a string
+Will never return NULL, just empty strings.
+An empty string will only be returned at end of file.
+
+If "allowLineBreaks" is qtrue then an empty
+string will be returned if the next token is
+a newline.
+==============
+*/
+static char *Com_ParseExt( const char *(*data_p), qboolean allowLineBreaks ) {
+ int c = 0, len;
+ qboolean hasNewLines = qfalse;
+ const char *data;
+ const char **punc;
+
+ if ( !data_p ) {
+ Com_Error( ERR_FATAL, "Com_ParseExt: NULL data_p" );
+ }
+
+ data = *data_p;
+ len = 0;
+ pi->token[0] = 0;
+
+ // make sure incoming data is valid
+ if ( !data ) {
+ *data_p = NULL;
+ return pi->token;
+ }
+
+ // skip any leading whitespace
+ while ( 1 ) {
+ // skip whitespace
+ data = SkipWhitespace( data, &hasNewLines );
+ if ( !data ) {
+ *data_p = NULL;
+ return pi->token;
+ }
+ if ( hasNewLines && !allowLineBreaks ) {
+ *data_p = data;
+ return pi->token;
+ }
+
+ c = *data;
+
+ // skip double slash comments
+ if ( c == '/' && data[1] == '/' ) {
+ while (*data && *data != '\n') {
+ data++;
+ }
+ continue;
+ }
+
+ // skip /* */ comments
+ if ( c=='/' && data[1] == '*' ) {
+ while ( *data && ( *data != '*' || data[1] != '/' ) ) {
+ if( *data == '\n' ) {
+ pi->lines++;
+ }
+ data++;
+ }
+ if ( *data ) {
+ data += 2;
+ }
+ continue;
+ }
+
+ // a real token to parse
+ break;
+ }
+
+ // handle quoted strings
+ if ( c == '\"' ) {
+ data++;
+ while( 1 ) {
+ c = *data++;
+ if ( ( c=='\\' ) && ( *data == '\"' ) ) {
+ // allow quoted strings to use \" to indicate the " character
+ data++;
+ } else if ( c=='\"' || !c ) {
+ pi->token[len] = 0;
+ *data_p = ( char * ) data;
+ return pi->token;
+ } else if( *data == '\n' ) {
+ pi->lines++;
+ }
+ if ( len < MAX_TOKEN_CHARS - 1 ) {
+ pi->token[len] = c;
+ len++;
+ }
+ }
+ }
+
+ // check for a number
+ // is this parsing of negative numbers going to cause expression problems
+ if ( ( c >= '0' && c <= '9' ) || ( c == '-' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ||
+ ( c == '.' && data[ 1 ] >= '0' && data[ 1 ] <= '9' ) ) {
+ do {
+
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( ( c >= '0' && c <= '9' ) || c == '.' );
+
+ // parse the exponent
+ if ( c == 'e' || c == 'E' ) {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+
+ if ( c == '-' || c == '+' ) {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+ c = *data;
+ }
+
+ do {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( c >= '0' && c <= '9' );
+ }
+
+ if (len == MAX_TOKEN_CHARS) {
+ len = 0;
+ }
+ pi->token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return pi->token;
+ }
+
+ // check for a regular word
+ // we still allow forward and back slashes in name tokens for pathnames
+ // and also colons for drive letters
+ if ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_' || c == '/' || c == '\\' ) {
+ do {
+ if (len < MAX_TOKEN_CHARS - 1) {
+ pi->token[len] = c;
+ len++;
+ }
+ data++;
+
+ c = *data;
+ } while ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) || c == '_'
+ || ( c >= '0' && c <= '9' ) || c == '/' || c == '\\' || c == ':' || c == '.' );
+
+ if (len == MAX_TOKEN_CHARS) {
+ len = 0;
+ }
+ pi->token[len] = 0;
+
+ *data_p = ( char * ) data;
+ return pi->token;
+ }
+
+ // check for multi-character punctuation token
+ for ( punc = punctuation ; *punc ; punc++ ) {
+ int l;
+ int j;
+
+ l = strlen( *punc );
+ for ( j = 0 ; j < l ; j++ ) {
+ if ( data[j] != (*punc)[j] ) {
+ break;
+ }
+ }
+ if ( j == l ) {
+ // a valid multi-character punctuation
+ memcpy( pi->token, *punc, l );
+ pi->token[l] = 0;
+ data += l;
+ *data_p = (char *)data;
+ return pi->token;
+ }
+ }
+
+ // single character punctuation
+ pi->token[0] = *data;
+ pi->token[1] = 0;
+ data++;
+ *data_p = (char *)data;
+
+ return pi->token;
+}
+
+/*
+===================
+Com_Parse
+===================
+*/
+const char *Com_Parse( const char *(*data_p) ) {
+ if ( pi->ungetToken ) {
+ pi->ungetToken = qfalse;
+ return pi->token;
+ }
+ return Com_ParseExt( data_p, qtrue );
+}
+
+/*
+===================
+Com_ParseOnLine
+===================
+*/
+const char *Com_ParseOnLine( const char *(*data_p) ) {
+ if ( pi->ungetToken ) {
+ pi->ungetToken = qfalse;
+ return pi->token;
+ }
+ return Com_ParseExt( data_p, qfalse );
+}
+
+
+
+/*
+==================
+Com_MatchToken
+==================
+*/
+void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( strcmp( token, match ) ) {
+ if (warning) {
+ Com_ScriptWarning( "MatchToken: %s != %s", token, match );
+ } else {
+ Com_ScriptError( "MatchToken: %s != %s", token, match );
+ }
+ }
+}
+
+
+/*
+=================
+Com_SkipBracedSection
+
+The next token should be an open brace.
+Skips until a matching close brace is found.
+Internal brace depths are properly skipped.
+=================
+*/
+void Com_SkipBracedSection( const char *(*program) ) {
+ const char *token;
+ int depth;
+
+ depth = 0;
+ do {
+ token = Com_Parse( program );
+ if( token[1] == 0 ) {
+ if( token[0] == '{' ) {
+ depth++;
+ }
+ else if( token[0] == '}' ) {
+ depth--;
+ }
+ }
+ } while( depth && *program );
+}
+
+/*
+=================
+Com_SkipRestOfLine
+=================
+*/
+void Com_SkipRestOfLine ( const char *(*data) ) {
+ const char *p;
+ int c;
+
+ p = *data;
+ while ( (c = *p++) != 0 ) {
+ if ( c == '\n' ) {
+ pi->lines++;
+ break;
+ }
+ }
+
+ *data = p;
+}
+
+/*
+====================
+Com_ParseRestOfLine
+====================
+*/
+const char *Com_ParseRestOfLine( const char *(*data_p) ) {
+ static char line[MAX_TOKEN_CHARS];
+ const char *token;
+
+ line[0] = 0;
+ while( 1 ) {
+ token = Com_ParseOnLine( data_p );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( line[0] ) {
+ Q_strcat( line, sizeof(line), " " );
+ }
+ Q_strcat( line, sizeof(line), token );
+ }
+
+ return line;
+}
+
+
+float Com_ParseFloat( const char *(*buf_p) ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( !token[0] ) {
+ return 0;
+ }
+ return atof( token );
+}
+
+int Com_ParseInt( const char *(*buf_p) ) {
+ const char *token;
+
+ token = Com_Parse( buf_p );
+ if ( !token[0] ) {
+ return 0;
+ }
+ return atof( token );
+}
+
+
+
+void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m ) {
+ const char *token;
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < x ; i++) {
+ token = Com_Parse(buf_p);
+ m[i] = atof(token);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+
+void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m ) {
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < y ; i++) {
+ Com_Parse1DMatrix (buf_p, x, m + i * x);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+
+void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m ) {
+ int i;
+
+ Com_MatchToken( buf_p, "(" );
+
+ for (i = 0 ; i < z ; i++) {
+ Com_Parse2DMatrix (buf_p, y, x, m + i * x*y);
+ }
+
+ Com_MatchToken( buf_p, ")" );
+}
+
diff --git a/q3radiant/splines/q_shared.cpp b/q3radiant/splines/q_shared.cpp
new file mode 100755
index 0000000..56cbcf1
--- /dev/null
+++ b/q3radiant/splines/q_shared.cpp
@@ -0,0 +1,976 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// q_shared.c -- stateless support routines that are included in each code dll
+#include "q_shared.h"
+
+/*
+============================================================================
+
+GROWLISTS
+
+============================================================================
+*/
+
+// malloc / free all in one place for debugging
+extern "C" void *Com_Allocate( int bytes );
+extern "C" void Com_Dealloc( void *ptr );
+
+void Com_InitGrowList( growList_t *list, int maxElements ) {
+ list->maxElements = maxElements;
+ list->currentElements = 0;
+ list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
+}
+
+int Com_AddToGrowList( growList_t *list, void *data ) {
+ void **old;
+
+ if ( list->currentElements != list->maxElements ) {
+ list->elements[list->currentElements] = data;
+ return list->currentElements++;
+ }
+
+ // grow, reallocate and move
+ old = list->elements;
+
+ if ( list->maxElements < 0 ) {
+ Com_Error( ERR_FATAL, "Com_AddToGrowList: maxElements = %i", list->maxElements );
+ }
+
+ if ( list->maxElements == 0 ) {
+ // initialize the list to hold 100 elements
+ Com_InitGrowList( list, 100 );
+ return Com_AddToGrowList( list, data );
+ }
+
+ list->maxElements *= 2;
+
+ Com_DPrintf( "Resizing growlist to %i maxElements\n", list->maxElements );
+
+ list->elements = (void **)Com_Allocate( list->maxElements * sizeof( void * ) );
+
+ if ( !list->elements ) {
+ Com_Error( ERR_DROP, "Growlist alloc failed" );
+ }
+
+ memcpy( list->elements, old, list->currentElements * sizeof( void * ) );
+
+ Com_Dealloc( old );
+
+ return Com_AddToGrowList( list, data );
+}
+
+void *Com_GrowListElement( const growList_t *list, int index ) {
+ if ( index < 0 || index >= list->currentElements ) {
+ Com_Error( ERR_DROP, "Com_GrowListElement: %i out of range of %i",
+ index, list->currentElements );
+ }
+ return list->elements[index];
+}
+
+int Com_IndexForGrowListElement( const growList_t *list, const void *element ) {
+ int i;
+
+ for ( i = 0 ; i < list->currentElements ; i++ ) {
+ if ( list->elements[i] == element ) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+//============================================================================
+
+
+float Com_Clamp( float min, float max, float value ) {
+ if ( value < min ) {
+ return min;
+ }
+ if ( value > max ) {
+ return max;
+ }
+ return value;
+}
+
+/*
+============
+Com_StringContains
+============
+*/
+const char *Com_StringContains( const char *str1, const char *str2, int casesensitive) {
+ int len, i, j;
+
+ len = strlen(str1) - strlen(str2);
+ for (i = 0; i <= len; i++, str1++) {
+ for (j = 0; str2[j]; j++) {
+ if (casesensitive) {
+ if (str1[j] != str2[j]) {
+ break;
+ }
+ }
+ else {
+ if (toupper(str1[j]) != toupper(str2[j])) {
+ break;
+ }
+ }
+ }
+ if (!str2[j]) {
+ return str1;
+ }
+ }
+ return NULL;
+}
+
+/*
+============
+Com_Filter
+============
+*/
+int Com_Filter( const char *filter, const char *name, int casesensitive)
+{
+ char buf[MAX_TOKEN_CHARS];
+ const char *ptr;
+ int i, found;
+
+ while(*filter) {
+ if (*filter == '*') {
+ filter++;
+ for (i = 0; *filter; i++) {
+ if (*filter == '*' || *filter == '?') break;
+ buf[i] = *filter;
+ filter++;
+ }
+ buf[i] = '\0';
+ if (strlen(buf)) {
+ ptr = Com_StringContains(name, buf, casesensitive);
+ if (!ptr) return qfalse;
+ name = ptr + strlen(buf);
+ }
+ }
+ else if (*filter == '?') {
+ filter++;
+ name++;
+ }
+ else if (*filter == '[' && *(filter+1) == '[') {
+ filter++;
+ }
+ else if (*filter == '[') {
+ filter++;
+ found = qfalse;
+ while(*filter && !found) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ if (*(filter+1) == '-' && *(filter+2) && (*(filter+2) != ']' || *(filter+3) == ']')) {
+ if (casesensitive) {
+ if (*name >= *filter && *name <= *(filter+2)) found = qtrue;
+ }
+ else {
+ if (toupper(*name) >= toupper(*filter) &&
+ toupper(*name) <= toupper(*(filter+2))) found = qtrue;
+ }
+ filter += 3;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter == *name) found = qtrue;
+ }
+ else {
+ if (toupper(*filter) == toupper(*name)) found = qtrue;
+ }
+ filter++;
+ }
+ }
+ if (!found) return qfalse;
+ while(*filter) {
+ if (*filter == ']' && *(filter+1) != ']') break;
+ filter++;
+ }
+ filter++;
+ name++;
+ }
+ else {
+ if (casesensitive) {
+ if (*filter != *name) return qfalse;
+ }
+ else {
+ if (toupper(*filter) != toupper(*name)) return qfalse;
+ }
+ filter++;
+ name++;
+ }
+ }
+ return qtrue;
+}
+
+
+/*
+================
+Com_HashString
+
+================
+*/
+int Com_HashString( const char *fname ) {
+ int i;
+ long hash;
+ char letter;
+
+ hash = 0;
+ i = 0;
+ while (fname[i] != '\0') {
+ letter = tolower(fname[i]);
+ if (letter =='.') break; // don't include extension
+ if (letter =='\\') letter = '/'; // damn path names
+ hash+=(long)(letter)*(i+119);
+ i++;
+ }
+ hash &= (FILE_HASH_SIZE-1);
+ return hash;
+}
+
+
+/*
+============
+Com_SkipPath
+============
+*/
+char *Com_SkipPath (char *pathname)
+{
+ char *last;
+
+ last = pathname;
+ while (*pathname)
+ {
+ if (*pathname=='/')
+ last = pathname+1;
+ pathname++;
+ }
+ return last;
+}
+
+/*
+============
+Com_StripExtension
+============
+*/
+void Com_StripExtension( const char *in, char *out ) {
+ while ( *in && *in != '.' ) {
+ *out++ = *in++;
+ }
+ *out = 0;
+}
+
+
+/*
+==================
+Com_DefaultExtension
+==================
+*/
+void Com_DefaultExtension (char *path, int maxSize, const char *extension ) {
+ char oldPath[MAX_QPATH];
+ char *src;
+
+//
+// if path doesn't have a .EXT, append extension
+// (extension should include the .)
+//
+ src = path + strlen(path) - 1;
+
+ while (*src != '/' && src != path) {
+ if ( *src == '.' ) {
+ return; // it has an extension
+ }
+ src--;
+ }
+
+ Q_strncpyz( oldPath, path, sizeof( oldPath ) );
+ Com_sprintf( path, maxSize, "%s%s", oldPath, extension );
+}
+
+/*
+============================================================================
+
+ BYTE ORDER FUNCTIONS
+
+============================================================================
+*/
+
+// can't just use function pointers, or dll linkage can
+// mess up when qcommon is included in multiple places
+static short (*_BigShort) (short l);
+static short (*_LittleShort) (short l);
+static int (*_BigLong) (int l);
+static int (*_LittleLong) (int l);
+static float (*_BigFloat) (float l);
+static float (*_LittleFloat) (float l);
+
+short BigShort(short l){return _BigShort(l);}
+short LittleShort(short l) {return _LittleShort(l);}
+int BigLong (int l) {return _BigLong(l);}
+int LittleLong (int l) {return _LittleLong(l);}
+float BigFloat (float l) {return _BigFloat(l);}
+float LittleFloat (float l) {return _LittleFloat(l);}
+
+short ShortSwap (short l)
+{
+ byte b1,b2;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+
+ return (b1<<8) + b2;
+}
+
+short ShortNoSwap (short l)
+{
+ return l;
+}
+
+int LongSwap (int l)
+{
+ byte b1,b2,b3,b4;
+
+ b1 = l&255;
+ b2 = (l>>8)&255;
+ b3 = (l>>16)&255;
+ b4 = (l>>24)&255;
+
+ return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
+}
+
+int LongNoSwap (int l)
+{
+ return l;
+}
+
+float FloatSwap (float f)
+{
+ union
+ {
+ float f;
+ byte b[4];
+ } dat1, dat2;
+
+
+ dat1.f = f;
+ dat2.b[0] = dat1.b[3];
+ dat2.b[1] = dat1.b[2];
+ dat2.b[2] = dat1.b[1];
+ dat2.b[3] = dat1.b[0];
+ return dat2.f;
+}
+
+float FloatNoSwap (float f)
+{
+ return f;
+}
+
+/*
+================
+Swap_Init
+================
+*/
+void Swap_Init (void)
+{
+ byte swaptest[2] = {1,0};
+
+// set the byte swapping variables in a portable manner
+ if ( *(short *)swaptest == 1)
+ {
+ _BigShort = ShortSwap;
+ _LittleShort = ShortNoSwap;
+ _BigLong = LongSwap;
+ _LittleLong = LongNoSwap;
+ _BigFloat = FloatSwap;
+ _LittleFloat = FloatNoSwap;
+ }
+ else
+ {
+ _BigShort = ShortNoSwap;
+ _LittleShort = ShortSwap;
+ _BigLong = LongNoSwap;
+ _LittleLong = LongSwap;
+ _BigFloat = FloatNoSwap;
+ _LittleFloat = FloatSwap;
+ }
+
+}
+
+/*
+===============
+Com_ParseInfos
+===============
+*/
+int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] ) {
+ const char *token;
+ int count;
+ char key[MAX_TOKEN_CHARS];
+
+ count = 0;
+
+ while ( 1 ) {
+ token = Com_Parse( &buf );
+ if ( !token[0] ) {
+ break;
+ }
+ if ( strcmp( token, "{" ) ) {
+ Com_Printf( "Missing { in info file\n" );
+ break;
+ }
+
+ if ( count == max ) {
+ Com_Printf( "Max infos exceeded\n" );
+ break;
+ }
+
+ infos[count][0] = 0;
+ while ( 1 ) {
+ token = Com_Parse( &buf );
+ if ( !token[0] ) {
+ Com_Printf( "Unexpected end of info file\n" );
+ break;
+ }
+ if ( !strcmp( token, "}" ) ) {
+ break;
+ }
+ Q_strncpyz( key, token, sizeof( key ) );
+
+ token = Com_ParseOnLine( &buf );
+ if ( !token[0] ) {
+ token = "<NULL>";
+ }
+ Info_SetValueForKey( infos[count], key, token );
+ }
+ count++;
+ }
+
+ return count;
+}
+
+
+
+/*
+============================================================================
+
+ LIBRARY REPLACEMENT FUNCTIONS
+
+============================================================================
+*/
+
+int Q_isprint( int c )
+{
+ if ( c >= 0x20 && c <= 0x7E )
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_islower( int c )
+{
+ if (c >= 'a' && c <= 'z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isupper( int c )
+{
+ if (c >= 'A' && c <= 'Z')
+ return ( 1 );
+ return ( 0 );
+}
+
+int Q_isalpha( int c )
+{
+ if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ return ( 1 );
+ return ( 0 );
+}
+
+char* Q_strrchr( const char* string, int c )
+{
+ char cc = c;
+ char *s;
+ char *sp=(char *)0;
+
+ s = (char*)string;
+
+ while (*s)
+ {
+ if (*s == cc)
+ sp = s;
+ s++;
+ }
+ if (cc == 0)
+ sp = s;
+
+ return sp;
+}
+
+/*
+=============
+Q_strncpyz
+
+Safe strncpy that ensures a trailing zero
+=============
+*/
+void Q_strncpyz( char *dest, const char *src, int destsize ) {
+ if ( !src ) {
+ Com_Error( ERR_FATAL, "Q_strncpyz: NULL src" );
+ }
+ if ( destsize < 1 ) {
+ Com_Error(ERR_FATAL,"Q_strncpyz: destsize < 1" );
+ }
+
+ strncpy( dest, src, destsize-1 );
+ dest[destsize-1] = 0;
+}
+
+int Q_stricmpn (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ if (c1 >= 'a' && c1 <= 'z') {
+ c1 -= ('a' - 'A');
+ }
+ if (c2 >= 'a' && c2 <= 'z') {
+ c2 -= ('a' - 'A');
+ }
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_strncmp (const char *s1, const char *s2, int n) {
+ int c1, c2;
+
+ do {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if (!n--) {
+ return 0; // strings are equal until end point
+ }
+
+ if (c1 != c2) {
+ return c1 < c2 ? -1 : 1;
+ }
+ } while (c1);
+
+ return 0; // strings are equal
+}
+
+int Q_stricmp (const char *s1, const char *s2) {
+ return Q_stricmpn (s1, s2, 99999);
+}
+
+
+char *Q_strlwr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = tolower(*s);
+ s++;
+ }
+ return s1;
+}
+
+char *Q_strupr( char *s1 ) {
+ char *s;
+
+ s = s1;
+ while ( *s ) {
+ *s = toupper(*s);
+ s++;
+ }
+ return s1;
+}
+
+
+// never goes past bounds or leaves without a terminating 0
+void Q_strcat( char *dest, int size, const char *src ) {
+ int l1;
+
+ l1 = strlen( dest );
+ if ( l1 >= size ) {
+ Com_Error( ERR_FATAL, "Q_strcat: already overflowed" );
+ }
+ Q_strncpyz( dest + l1, src, size - l1 );
+}
+
+
+int Q_PrintStrlen( const char *string ) {
+ int len;
+ const char *p;
+
+ if( !string ) {
+ return 0;
+ }
+
+ len = 0;
+ p = string;
+ while( *p ) {
+ if( Q_IsColorString( p ) ) {
+ p += 2;
+ continue;
+ }
+ p++;
+ len++;
+ }
+
+ return len;
+}
+
+
+char *Q_CleanStr( char *string ) {
+ char* d;
+ char* s;
+ int c;
+
+ s = string;
+ d = string;
+ while ((c = *s) != 0 ) {
+ if ( Q_IsColorString( s ) ) {
+ s++;
+ }
+ else if ( c >= 0x20 && c <= 0x7E ) {
+ *d++ = c;
+ }
+ s++;
+ }
+ *d = '\0';
+
+ return string;
+}
+
+
+void QDECL Com_sprintf( char *dest, int size, const char *fmt, ...) {
+ int len;
+ va_list argptr;
+ char bigbuffer[32000]; // big, but small enough to fit in PPC stack
+
+ va_start (argptr,fmt);
+ len = vsprintf (bigbuffer,fmt,argptr);
+ va_end (argptr);
+ if ( len >= sizeof( bigbuffer ) ) {
+ Com_Error( ERR_FATAL, "Com_sprintf: overflowed bigbuffer" );
+ }
+ if (len >= size) {
+ Com_Printf ("Com_sprintf: overflow of %i in %i\n", len, size);
+ }
+ Q_strncpyz (dest, bigbuffer, size );
+}
+
+
+/*
+============
+va
+
+does a varargs printf into a temp buffer, so I don't need to have
+varargs versions of all text functions.
+FIXME: make this buffer size safe someday
+============
+*/
+char * QDECL va( char *format, ... ) {
+ va_list argptr;
+ static char string[2][32000]; // in case va is called by nested functions
+ static int index = 0;
+ char *buf;
+
+ buf = string[index & 1];
+ index++;
+
+ va_start (argptr, format);
+ vsprintf (buf, format,argptr);
+ va_end (argptr);
+
+ return buf;
+}
+
+
+/*
+=====================================================================
+
+ INFO STRINGS
+
+=====================================================================
+*/
+
+/*
+===============
+Info_ValueForKey
+
+Searches the string for the given
+key and returns the associated value, or an empty string.
+FIXME: overflow check?
+===============
+*/
+char *Info_ValueForKey( const char *s, const char *key ) {
+ char pkey[MAX_INFO_KEY];
+ static char value[2][MAX_INFO_VALUE]; // use two buffers so compares
+ // work without stomping on each other
+ static int valueindex = 0;
+ char *o;
+
+ if ( !s || !key ) {
+ return "";
+ }
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_ValueForKey: oversize infostring" );
+ }
+
+ valueindex ^= 1;
+ if (*s == '\\')
+ s++;
+ while (1)
+ {
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return "";
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value[valueindex];
+
+ while (*s != '\\' && *s)
+ {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!Q_stricmp (key, pkey) )
+ return value[valueindex];
+
+ if (!*s)
+ break;
+ s++;
+ }
+
+ return "";
+}
+
+
+/*
+===================
+Info_NextPair
+
+Used to itterate through all the key/value pairs in an info string
+===================
+*/
+void Info_NextPair( const char *(*head), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] ) {
+ char *o;
+ const char *s;
+
+ s = *head;
+
+ if ( *s == '\\' ) {
+ s++;
+ }
+ key[0] = 0;
+ value[0] = 0;
+
+ o = key;
+ while ( *s != '\\' ) {
+ if ( !*s ) {
+ *o = 0;
+ *head = s;
+ return;
+ }
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while ( *s != '\\' && *s ) {
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ *head = s;
+}
+
+
+/*
+===================
+Info_RemoveKey
+===================
+*/
+void Info_RemoveKey( char *s, const char *key ) {
+ char *start;
+ char pkey[MAX_INFO_KEY];
+ char value[MAX_INFO_VALUE];
+ char *o;
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_RemoveKey: oversize infostring" );
+ }
+
+ if (strchr (key, '\\')) {
+ return;
+ }
+
+ while (1)
+ {
+ start = s;
+ if (*s == '\\')
+ s++;
+ o = pkey;
+ while (*s != '\\')
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+ s++;
+
+ o = value;
+ while (*s != '\\' && *s)
+ {
+ if (!*s)
+ return;
+ *o++ = *s++;
+ }
+ *o = 0;
+
+ if (!strcmp (key, pkey) )
+ {
+ strcpy (start, s); // remove this part
+ return;
+ }
+
+ if (!*s)
+ return;
+ }
+
+}
+
+
+/*
+==================
+Info_Validate
+
+Some characters are illegal in info strings because they
+can mess up the server's parsing
+==================
+*/
+qboolean Info_Validate( const char *s ) {
+ if ( strchr( s, '\"' ) ) {
+ return qfalse;
+ }
+ if ( strchr( s, ';' ) ) {
+ return qfalse;
+ }
+ return qtrue;
+}
+
+/*
+==================
+Info_SetValueForKey
+
+Changes or adds a key/value pair
+==================
+*/
+void Info_SetValueForKey( char *s, const char *key, const char *value ) {
+ char newi[MAX_INFO_STRING];
+
+ if ( strlen( s ) >= MAX_INFO_STRING ) {
+ Com_Error( ERR_DROP, "Info_SetValueForKey: oversize infostring" );
+ }
+
+ if (strchr (key, '\\') || strchr (value, '\\'))
+ {
+ Com_Printf ("Can't use keys or values with a \\\n");
+ return;
+ }
+
+ if (strchr (key, ';') || strchr (value, ';'))
+ {
+ Com_Printf ("Can't use keys or values with a semicolon\n");
+ return;
+ }
+
+ if (strchr (key, '\"') || strchr (value, '\"'))
+ {
+ Com_Printf ("Can't use keys or values with a \"\n");
+ return;
+ }
+
+ Info_RemoveKey (s, key);
+ if (!value || !strlen(value))
+ return;
+
+ Com_sprintf (newi, sizeof(newi), "\\%s\\%s", key, value);
+
+ if (strlen(newi) + strlen(s) > MAX_INFO_STRING)
+ {
+ Com_Printf ("Info string length exceeded\n");
+ return;
+ }
+
+ strcat (s, newi);
+}
+
+//====================================================================
+
+
+/*
+===============
+ParseHex
+===============
+*/
+int ParseHex( const char *text ) {
+ int value;
+ int c;
+
+ value = 0;
+ while ( ( c = *text++ ) != 0 ) {
+ if ( c >= '0' && c <= '9' ) {
+ value = value * 16 + c - '0';
+ continue;
+ }
+ if ( c >= 'a' && c <= 'f' ) {
+ value = value * 16 + 10 + c - 'a';
+ continue;
+ }
+ if ( c >= 'A' && c <= 'F' ) {
+ value = value * 16 + 10 + c - 'A';
+ continue;
+ }
+ }
+
+ return value;
+}
diff --git a/q3radiant/splines/q_shared.h b/q3radiant/splines/q_shared.h
new file mode 100755
index 0000000..6d9a563
--- /dev/null
+++ b/q3radiant/splines/q_shared.h
@@ -0,0 +1,798 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __Q_SHARED_H
+#define __Q_SHARED_H
+
+// q_shared.h -- included first by ALL program modules.
+// these are the definitions that have no dependance on
+// central system services, and can be used by any part
+// of the program without any state issues.
+
+// A user mod should never modify this file
+
+#define Q3_VERSION "DOOM 0.01"
+
+// alignment macros for SIMD
+#define ALIGN_ON
+#define ALIGN_OFF
+
+#ifdef _WIN32
+
+#pragma warning(disable : 4018) // signed/unsigned mismatch
+#pragma warning(disable : 4032)
+#pragma warning(disable : 4051)
+#pragma warning(disable : 4057) // slightly different base types
+#pragma warning(disable : 4100) // unreferenced formal parameter
+#pragma warning(disable : 4115)
+#pragma warning(disable : 4125) // decimal digit terminates octal escape sequence
+#pragma warning(disable : 4127) // conditional expression is constant
+#pragma warning(disable : 4136)
+#pragma warning(disable : 4201)
+#pragma warning(disable : 4214)
+#pragma warning(disable : 4244)
+#pragma warning(disable : 4305) // truncation from const double to float
+#pragma warning(disable : 4310) // cast truncates constant value
+#pragma warning(disable : 4514)
+#pragma warning(disable : 4711) // selected for automatic inline expansion
+#pragma warning(disable : 4220) // varargs matches remaining parameters
+
+#endif
+
+#include <assert.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <ctype.h>
+#ifdef WIN32 // mac doesn't have malloc.h
+#include <malloc.h> // for _alloca()
+#endif
+#ifdef _WIN32
+
+//#pragma intrinsic( memset, memcpy )
+
+#endif
+
+
+// this is the define for determining if we have an asm version of a C function
+#if (defined _M_IX86 || defined __i386__) && !defined __sun__ && !defined __LCC__
+#define id386 1
+#else
+#define id386 0
+#endif
+
+// for windows fastcall option
+
+#define QDECL
+
+//======================= WIN32 DEFINES =================================
+
+#ifdef WIN32
+
+#define MAC_STATIC
+
+#undef QDECL
+#define QDECL __cdecl
+
+// buildstring will be incorporated into the version string
+#ifdef NDEBUG
+#ifdef _M_IX86
+#define CPUSTRING "win-x86"
+#elif defined _M_ALPHA
+#define CPUSTRING "win-AXP"
+#endif
+#else
+#ifdef _M_IX86
+#define CPUSTRING "win-x86-debug"
+#elif defined _M_ALPHA
+#define CPUSTRING "win-AXP-debug"
+#endif
+#endif
+
+
+#define PATH_SEP '\\'
+
+#endif
+
+//======================= MAC OS X SERVER DEFINES =====================
+
+#if defined(__MACH__) && defined(__APPLE__)
+
+#define MAC_STATIC
+
+#ifdef __ppc__
+#define CPUSTRING "MacOSXS-ppc"
+#elif defined __i386__
+#define CPUSTRING "MacOSXS-i386"
+#else
+#define CPUSTRING "MacOSXS-other"
+#endif
+
+#define PATH_SEP '/'
+
+#define GAME_HARD_LINKED
+#define CGAME_HARD_LINKED
+#define UI_HARD_LINKED
+#define _alloca alloca
+
+#undef ALIGN_ON
+#undef ALIGN_OFF
+#define ALIGN_ON #pragma align(16)
+#define ALIGN_OFF #pragma align()
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+void *osxAllocateMemory(long size);
+void osxFreeMemory(void *pointer);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
+//======================= MAC DEFINES =================================
+
+#ifdef __MACOS__
+
+#define MAC_STATIC static
+
+#define CPUSTRING "MacOS-PPC"
+
+#define PATH_SEP ':'
+
+void Sys_PumpEvents( void );
+
+#endif
+
+#ifdef __MRC__
+
+#define MAC_STATIC
+
+#define CPUSTRING "MacOS-PPC"
+
+#define PATH_SEP ':'
+
+void Sys_PumpEvents( void );
+
+#undef QDECL
+#define QDECL __cdecl
+
+#define _alloca alloca
+#endif
+
+//======================= LINUX DEFINES =================================
+
+// the mac compiler can't handle >32k of locals, so we
+// just waste space and make big arrays static...
+#ifdef __linux__
+
+#define MAC_STATIC
+
+#ifdef __i386__
+#define CPUSTRING "linux-i386"
+#elif defined __axp__
+#define CPUSTRING "linux-alpha"
+#else
+#define CPUSTRING "linux-other"
+#endif
+
+#define PATH_SEP '/'
+
+#endif
+
+//=============================================================
+
+
+
+typedef enum {qfalse, qtrue} qboolean;
+
+typedef unsigned char byte;
+
+#define EQUAL_EPSILON 0.001
+
+typedef int qhandle_t;
+typedef int sfxHandle_t;
+typedef int fileHandle_t;
+typedef int clipHandle_t;
+
+typedef enum {
+ INVALID_JOINT = -1
+} jointHandle_t;
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define MAX_QINT 0x7fffffff
+#define MIN_QINT (-MAX_QINT-1)
+
+#ifndef max
+#define max( x, y ) ( ( ( x ) > ( y ) ) ? ( x ) : ( y ) )
+#define min( x, y ) ( ( ( x ) < ( y ) ) ? ( x ) : ( y ) )
+#endif
+
+#ifndef sign
+#define sign( f ) ( ( f > 0 ) ? 1 : ( ( f < 0 ) ? -1 : 0 ) )
+#endif
+
+// angle indexes
+#define PITCH 0 // up / down
+#define YAW 1 // left / right
+#define ROLL 2 // fall over
+
+// the game guarantees that no string from the network will ever
+// exceed MAX_STRING_CHARS
+#define MAX_STRING_CHARS 1024 // max length of a string passed to Cmd_TokenizeString
+#define MAX_STRING_TOKENS 256 // max tokens resulting from Cmd_TokenizeString
+#define MAX_TOKEN_CHARS 1024 // max length of an individual token
+
+#define MAX_INFO_STRING 1024
+#define MAX_INFO_KEY 1024
+#define MAX_INFO_VALUE 1024
+
+
+#define MAX_QPATH 64 // max length of a quake game pathname
+#define MAX_OSPATH 128 // max length of a filesystem pathname
+
+#define MAX_NAME_LENGTH 32 // max length of a client name
+
+// paramters for command buffer stuffing
+typedef enum {
+ EXEC_NOW, // don't return until completed, a VM should NEVER use this,
+ // because some commands might cause the VM to be unloaded...
+ EXEC_INSERT, // insert at current position, but don't run yet
+ EXEC_APPEND // add to end of the command buffer (normal case)
+} cbufExec_t;
+
+
+//
+// these aren't needed by any of the VMs. put in another header?
+//
+#define MAX_MAP_AREA_BYTES 32 // bit vector of area visibility
+
+#undef ERR_FATAL // malloc.h on unix
+
+// parameters to the main Error routine
+typedef enum {
+ ERR_NONE,
+ ERR_FATAL, // exit the entire game with a popup window
+ ERR_DROP, // print to console and disconnect from game
+ ERR_DISCONNECT, // don't kill server
+ ERR_NEED_CD // pop up the need-cd dialog
+} errorParm_t;
+
+
+// font rendering values used by ui and cgame
+
+#define PROP_GAP_WIDTH 3
+#define PROP_SPACE_WIDTH 8
+#define PROP_HEIGHT 27
+#define PROP_SMALL_SIZE_SCALE 0.75
+
+#define BLINK_DIVISOR 200
+#define PULSE_DIVISOR 75
+
+#define UI_LEFT 0x00000000 // default
+#define UI_CENTER 0x00000001
+#define UI_RIGHT 0x00000002
+#define UI_FORMATMASK 0x00000007
+#define UI_SMALLFONT 0x00000010
+#define UI_BIGFONT 0x00000020 // default
+#define UI_GIANTFONT 0x00000040
+#define UI_DROPSHADOW 0x00000800
+#define UI_BLINK 0x00001000
+#define UI_INVERSE 0x00002000
+#define UI_PULSE 0x00004000
+
+
+/*
+==============================================================
+
+MATHLIB
+
+==============================================================
+*/
+#ifdef __cplusplus // so we can include this in C code
+#define SIDE_FRONT 0
+#define SIDE_BACK 1
+#define SIDE_ON 2
+#define SIDE_CROSS 3
+
+#define Q_PI 3.14159265358979323846
+#ifndef M_PI
+#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
+#endif
+
+#include "math_vector.h"
+#include "math_angles.h"
+#include "math_matrix.h"
+#include "math_quaternion.h"
+
+class idVec3_t; // for defining vectors
+typedef idVec3_t &vec3_p; // for passing vectors as function arguments
+typedef const idVec3_t &vec3_c; // for passing vectors as const function arguments
+
+class angles_t; // for defining angle vectors
+typedef angles_t &angles_p; // for passing angles as function arguments
+typedef const angles_t &angles_c; // for passing angles as const function arguments
+
+class mat3_t; // for defining matrices
+typedef mat3_t &mat3_p; // for passing matrices as function arguments
+typedef const mat3_t &mat3_c; // for passing matrices as const function arguments
+
+
+
+#define NUMVERTEXNORMALS 162
+extern idVec3_t bytedirs[NUMVERTEXNORMALS];
+
+// all drawing is done to a 640*480 virtual screen size
+// and will be automatically scaled to the real resolution
+#define SCREEN_WIDTH 640
+#define SCREEN_HEIGHT 480
+
+#define TINYCHAR_WIDTH (SMALLCHAR_WIDTH)
+#define TINYCHAR_HEIGHT (SMALLCHAR_HEIGHT/2)
+
+#define SMALLCHAR_WIDTH 8
+#define SMALLCHAR_HEIGHT 16
+
+#define BIGCHAR_WIDTH 16
+#define BIGCHAR_HEIGHT 16
+
+#define GIANTCHAR_WIDTH 32
+#define GIANTCHAR_HEIGHT 48
+
+extern vec4_t colorBlack;
+extern vec4_t colorRed;
+extern vec4_t colorGreen;
+extern vec4_t colorBlue;
+extern vec4_t colorYellow;
+extern vec4_t colorMagenta;
+extern vec4_t colorCyan;
+extern vec4_t colorWhite;
+extern vec4_t colorLtGrey;
+extern vec4_t colorMdGrey;
+extern vec4_t colorDkGrey;
+
+#define Q_COLOR_ESCAPE '^'
+#define Q_IsColorString(p) ( p && *(p) == Q_COLOR_ESCAPE && *((p)+1) && *((p)+1) != Q_COLOR_ESCAPE )
+
+#define COLOR_BLACK '0'
+#define COLOR_RED '1'
+#define COLOR_GREEN '2'
+#define COLOR_YELLOW '3'
+#define COLOR_BLUE '4'
+#define COLOR_CYAN '5'
+#define COLOR_MAGENTA '6'
+#define COLOR_WHITE '7'
+#define ColorIndex(c) ( ( (c) - '0' ) & 7 )
+
+#define S_COLOR_BLACK "^0"
+#define S_COLOR_RED "^1"
+#define S_COLOR_GREEN "^2"
+#define S_COLOR_YELLOW "^3"
+#define S_COLOR_BLUE "^4"
+#define S_COLOR_CYAN "^5"
+#define S_COLOR_MAGENTA "^6"
+#define S_COLOR_WHITE "^7"
+
+extern vec4_t g_color_table[8];
+
+#define MAKERGB( v, r, g, b ) v[0]=r;v[1]=g;v[2]=b
+#define MAKERGBA( v, r, g, b, a ) v[0]=r;v[1]=g;v[2]=b;v[3]=a
+
+#define DEG2RAD( a ) ( ( (a) * M_PI ) / 180.0F )
+#define RAD2DEG( a ) ( ( (a) * 180.0f ) / M_PI )
+
+struct cplane_s;
+
+extern idVec3_t vec3_origin;
+extern vec4_t vec4_origin;
+extern mat3_t axisDefault;
+
+#define nanmask (255<<23)
+
+#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask)
+
+float Q_fabs( float f );
+float Q_rsqrt( float f ); // reciprocal square root
+
+#define SQRTFAST( x ) ( 1.0f / Q_rsqrt( x ) )
+
+signed char ClampChar( int i );
+signed short ClampShort( int i );
+
+// this isn't a real cheap function to call!
+int DirToByte( const idVec3_t &dir );
+void ByteToDir( int b, vec3_p dir );
+
+#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2])
+#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2])
+#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2])
+#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2])
+//#define VectorCopy(a,b) ((b).x=(a).x,(b).y=(a).y,(b).z=(a).z])
+
+#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s))
+#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s))
+#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0])
+
+#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3])
+#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3])
+#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3])
+#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s))
+#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s))
+
+
+#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0)
+#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2])
+#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z))
+#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3])
+
+#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];}
+
+float NormalizeColor( vec3_c in, vec3_p out );
+
+int VectorCompare( vec3_c v1, vec3_c v2 );
+float VectorLength( vec3_c v );
+float Distance( vec3_c p1, vec3_c p2 );
+float DistanceSquared( vec3_c p1, vec3_c p2 );
+float VectorNormalize (vec3_p v); // returns vector length
+void VectorNormalizeFast(vec3_p v); // does NOT return vector length, uses rsqrt approximation
+float VectorNormalize2( vec3_c v, vec3_p out );
+void VectorInverse (vec3_p v);
+void VectorRotate( vec3_c in, mat3_c matrix, vec3_p out );
+void VectorPolar(vec3_p v, float radius, float theta, float phi);
+void VectorSnap(vec3_p v);
+void Vector53Copy( const idVec5_t &in, vec3_p out);
+void Vector5Scale( const idVec5_t &v, float scale, idVec5_t &out);
+void Vector5Add( const idVec5_t &va, const idVec5_t &vb, idVec5_t &out);
+void VectorRotate3( vec3_c vIn, vec3_c vRotation, vec3_p out);
+void VectorRotate3Origin(vec3_c vIn, vec3_c vRotation, vec3_c vOrigin, vec3_p out);
+
+
+int Q_log2(int val);
+
+int Q_rand( int *seed );
+float Q_random( int *seed );
+float Q_crandom( int *seed );
+
+#define random() ((rand () & 0x7fff) / ((float)0x7fff))
+#define crandom() (2.0 * (random() - 0.5))
+
+float Q_rint( float in );
+
+void vectoangles( vec3_c value1, angles_p angles);
+void AnglesToAxis( angles_c angles, mat3_p axis );
+
+void AxisCopy( mat3_c in, mat3_p out );
+qboolean AxisRotated( mat3_c in ); // assumes a non-degenerate axis
+
+int SignbitsForNormal( vec3_c normal );
+int BoxOnPlaneSide( const Bounds &b, struct cplane_s *p );
+
+float AngleMod(float a);
+float LerpAngle (float from, float to, float frac);
+float AngleSubtract( float a1, float a2 );
+void AnglesSubtract( angles_c v1, angles_c v2, angles_p v3 );
+
+float AngleNormalize360 ( float angle );
+float AngleNormalize180 ( float angle );
+float AngleDelta ( float angle1, float angle2 );
+
+qboolean PlaneFromPoints( vec4_t &plane, vec3_c a, vec3_c b, vec3_c c );
+void ProjectPointOnPlane( vec3_p dst, vec3_c p, vec3_c normal );
+void RotatePointAroundVector( vec3_p dst, vec3_c dir, vec3_c point, float degrees );
+void RotateAroundDirection( mat3_p axis, float yaw );
+void MakeNormalVectors( vec3_c forward, vec3_p right, vec3_p up );
+// perpendicular vector could be replaced by this
+
+int PlaneTypeForNormal( vec3_c normal );
+
+void MatrixMultiply( mat3_c in1, mat3_c in2, mat3_p out );
+void MatrixInverseMultiply( mat3_c in1, mat3_c in2, mat3_p out ); // in2 is transposed during multiply
+void MatrixTransformVector( vec3_c in, mat3_c matrix, vec3_p out );
+void MatrixProjectVector( vec3_c in, mat3_c matrix, vec3_p out ); // Places the vector into a new coordinate system.
+void AngleVectors( angles_c angles, vec3_p forward, vec3_p right, vec3_p up);
+void PerpendicularVector( vec3_p dst, vec3_c src );
+
+float TriangleArea( vec3_c a, vec3_c b, vec3_c c );
+#endif // __cplusplus
+
+//=============================================
+
+float Com_Clamp( float min, float max, float value );
+
+#define FILE_HASH_SIZE 1024
+int Com_HashString( const char *fname );
+
+char *Com_SkipPath( char *pathname );
+
+// it is ok for out == in
+void Com_StripExtension( const char *in, char *out );
+
+// "extension" should include the dot: ".map"
+void Com_DefaultExtension( char *path, int maxSize, const char *extension );
+
+int Com_ParseInfos( const char *buf, int max, char infos[][MAX_INFO_STRING] );
+
+/*
+=====================================================================================
+
+SCRIPT PARSING
+
+=====================================================================================
+*/
+
+// this just controls the comment printing, it doesn't actually load a file
+void Com_BeginParseSession( const char *filename );
+void Com_EndParseSession( void );
+
+int Com_GetCurrentParseLine( void );
+
+// Will never return NULL, just empty strings.
+// An empty string will only be returned at end of file.
+// ParseOnLine will return empty if there isn't another token on this line
+
+// this funny typedef just means a moving pointer into a const char * buffer
+const char *Com_Parse( const char *(*data_p) );
+const char *Com_ParseOnLine( const char *(*data_p) );
+const char *Com_ParseRestOfLine( const char *(*data_p) );
+
+void Com_UngetToken( void );
+
+#ifdef __cplusplus
+void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning = qfalse );
+#else
+void Com_MatchToken( const char *(*buf_p), const char *match, qboolean warning );
+#endif
+
+void Com_ScriptError( const char *msg, ... );
+void Com_ScriptWarning( const char *msg, ... );
+
+void Com_SkipBracedSection( const char *(*program) );
+void Com_SkipRestOfLine( const char *(*data) );
+
+float Com_ParseFloat( const char *(*buf_p) );
+int Com_ParseInt( const char *(*buf_p) );
+
+void Com_Parse1DMatrix( const char *(*buf_p), int x, float *m );
+void Com_Parse2DMatrix( const char *(*buf_p), int y, int x, float *m );
+void Com_Parse3DMatrix( const char *(*buf_p), int z, int y, int x, float *m );
+
+//=====================================================================================
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+void QDECL Com_sprintf (char *dest, int size, const char *fmt, ...);
+
+
+// mode parm for FS_FOpenFile
+typedef enum {
+ FS_READ,
+ FS_WRITE,
+ FS_APPEND,
+ FS_APPEND_SYNC
+} fsMode_t;
+
+typedef enum {
+ FS_SEEK_CUR,
+ FS_SEEK_END,
+ FS_SEEK_SET
+} fsOrigin_t;
+
+//=============================================
+
+int Q_isprint( int c );
+int Q_islower( int c );
+int Q_isupper( int c );
+int Q_isalpha( int c );
+
+// portable case insensitive compare
+int Q_stricmp (const char *s1, const char *s2);
+int Q_strncmp (const char *s1, const char *s2, int n);
+int Q_stricmpn (const char *s1, const char *s2, int n);
+char *Q_strlwr( char *s1 );
+char *Q_strupr( char *s1 );
+char *Q_strrchr( const char* string, int c );
+
+// buffer size safe library replacements
+void Q_strncpyz( char *dest, const char *src, int destsize );
+void Q_strcat( char *dest, int size, const char *src );
+
+// strlen that discounts Quake color sequences
+int Q_PrintStrlen( const char *string );
+// removes color sequences from string
+char *Q_CleanStr( char *string );
+
+int Com_Filter( const char *filter, const char *name, int casesensitive );
+const char *Com_StringContains( const char *str1, const char *str2, int casesensitive );
+
+
+//=============================================
+
+short BigShort(short l);
+short LittleShort(short l);
+int BigLong (int l);
+int LittleLong (int l);
+float BigFloat (float l);
+float LittleFloat (float l);
+
+void Swap_Init (void);
+char * QDECL va(char *format, ...);
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+//=============================================
+#ifdef __cplusplus
+//
+// mapfile parsing
+//
+typedef struct ePair_s {
+ char *key;
+ char *value;
+} ePair_t;
+
+typedef struct mapSide_s {
+ char material[MAX_QPATH];
+ vec4_t plane;
+ vec4_t textureVectors[2];
+} mapSide_t;
+
+typedef struct {
+ int numSides;
+ mapSide_t **sides;
+} mapBrush_t;
+
+typedef struct {
+ idVec3_t xyz;
+ float st[2];
+} patchVertex_t;
+
+typedef struct {
+ char material[MAX_QPATH];
+ int width, height;
+ patchVertex_t *patchVerts;
+} mapPatch_t;
+
+typedef struct {
+ char modelName[MAX_QPATH];
+ float matrix[16];
+} mapModel_t;
+
+typedef struct mapPrimitive_s {
+ int numEpairs;
+ ePair_t **ePairs;
+
+ // only one of these will be non-NULL
+ mapBrush_t *brush;
+ mapPatch_t *patch;
+ mapModel_t *model;
+} mapPrimitive_t;
+
+typedef struct mapEntity_s {
+ int numPrimitives;
+ mapPrimitive_t **primitives;
+
+ int numEpairs;
+ ePair_t **ePairs;
+} mapEntity_t;
+
+typedef struct {
+ int numEntities;
+ mapEntity_t **entities;
+} mapFile_t;
+
+
+// the order of entities, brushes, and sides will be maintained, the
+// lists won't be swapped on each load or save
+mapFile_t *ParseMapFile( const char *text );
+void FreeMapFile( mapFile_t *mapFile );
+void WriteMapFile( const mapFile_t *mapFile, FILE *f );
+
+// key names are case-insensitive
+const char *ValueForMapEntityKey( const mapEntity_t *ent, const char *key );
+float FloatForMapEntityKey( const mapEntity_t *ent, const char *key );
+qboolean GetVectorForMapEntityKey( const mapEntity_t *ent, const char *key, idVec3_t &vec );
+
+typedef struct {
+ idVec3_t xyz;
+ idVec2_t st;
+ idVec3_t normal;
+ idVec3_t tangents[2];
+ byte smoothing[4]; // colors for silhouette smoothing
+} drawVert_t;
+
+typedef struct {
+ int width, height;
+ drawVert_t *verts;
+} drawVertMesh_t;
+
+// Tesselate a map patch into smoothed, drawable vertexes
+// MaxError of around 4 is reasonable
+drawVertMesh_t *SubdivideMapPatch( const mapPatch_t *patch, float maxError );
+#endif // __cplusplus
+
+//=========================================
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+void QDECL Com_Error( int level, const char *error, ... );
+void QDECL Com_Printf( const char *msg, ... );
+void QDECL Com_DPrintf( const char *msg, ... );
+
+#ifdef __cplusplus
+ }
+#endif
+
+
+typedef struct {
+ qboolean frameMemory;
+ int currentElements;
+ int maxElements; // will reallocate and move when exceeded
+ void **elements;
+} growList_t;
+
+// you don't need to init the growlist if you don't mind it growing and moving
+// the list as it expands
+void Com_InitGrowList( growList_t *list, int maxElements );
+int Com_AddToGrowList( growList_t *list, void *data );
+void *Com_GrowListElement( const growList_t *list, int index );
+int Com_IndexForGrowListElement( const growList_t *list, const void *element );
+
+
+//
+// key / value info strings
+//
+char *Info_ValueForKey( const char *s, const char *key );
+void Info_RemoveKey( char *s, const char *key );
+void Info_SetValueForKey( char *s, const char *key, const char *value );
+qboolean Info_Validate( const char *s );
+void Info_NextPair( const char *(*s), char key[MAX_INFO_KEY], char value[MAX_INFO_VALUE] );
+
+// get cvar defs, collision defs, etc
+//#include "../shared/interface.h"
+
+// get key code numbers for events
+//#include "../shared/keycodes.h"
+
+#ifdef __cplusplus
+// get the polygon winding functions
+//#include "../shared/windings.h"
+
+// get the flags class
+//#include "../shared/idflags.h"
+#endif // __cplusplus
+
+#endif // __Q_SHARED_H
+
diff --git a/q3radiant/splines/splines.cpp b/q3radiant/splines/splines.cpp
new file mode 100755
index 0000000..9c2b804
--- /dev/null
+++ b/q3radiant/splines/splines.cpp
@@ -0,0 +1,1244 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+
+//#include "stdafx.h"
+//#include "qe3.h"
+
+#include "q_shared.h"
+#include "splines.h"
+
+extern "C" {
+int FS_Write( const void *buffer, int len, fileHandle_t h );
+int FS_ReadFile( const char *qpath, void **buffer );
+void FS_FreeFile( void *buffer );
+fileHandle_t FS_FOpenFileWrite( const char *filename );
+void FS_FCloseFile( fileHandle_t f );
+}
+
+float Q_fabs( float f ) {
+ int tmp = * ( int * ) &f;
+ tmp &= 0x7FFFFFFF;
+ return * ( float * ) &tmp;
+}
+
+
+//#include "../shared/windings.h"
+//#include "../qcommon/qcommon.h"
+//#include "../sys/sys_public.h"
+//#include "../game/game_entity.h"
+
+idCameraDef splineList;
+idCameraDef *g_splineList = &splineList;
+
+idVec3_t idSplineList::zero(0,0,0);
+
+void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label) {
+ qglColor3fv(color);
+ qglPointSize(size);
+ qglBegin(GL_POINTS);
+ qglVertex3fv(point);
+ qglEnd();
+ idVec3_t v = point;
+ v.x += 1;
+ v.y += 1;
+ v.z += 1;
+ qglRasterPos3fv (v);
+ qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
+}
+
+
+void glBox(idVec3_t &color, idVec3_t &point, float size) {
+ idVec3_t mins(point);
+ idVec3_t maxs(point);
+ mins[0] -= size;
+ mins[1] += size;
+ mins[2] -= size;
+ maxs[0] += size;
+ maxs[1] -= size;
+ maxs[2] += size;
+ qglColor3fv(color);
+ qglBegin(GL_LINE_LOOP);
+ qglVertex3f(mins[0],mins[1],mins[2]);
+ qglVertex3f(maxs[0],mins[1],mins[2]);
+ qglVertex3f(maxs[0],maxs[1],mins[2]);
+ qglVertex3f(mins[0],maxs[1],mins[2]);
+ qglEnd();
+ qglBegin(GL_LINE_LOOP);
+ qglVertex3f(mins[0],mins[1],maxs[2]);
+ qglVertex3f(maxs[0],mins[1],maxs[2]);
+ qglVertex3f(maxs[0],maxs[1],maxs[2]);
+ qglVertex3f(mins[0],maxs[1],maxs[2]);
+ qglEnd();
+
+ qglBegin(GL_LINES);
+ qglVertex3f(mins[0],mins[1],mins[2]);
+ qglVertex3f(mins[0],mins[1],maxs[2]);
+ qglVertex3f(mins[0],maxs[1],maxs[2]);
+ qglVertex3f(mins[0],maxs[1],mins[2]);
+ qglVertex3f(maxs[0],mins[1],mins[2]);
+ qglVertex3f(maxs[0],mins[1],maxs[2]);
+ qglVertex3f(maxs[0],maxs[1],maxs[2]);
+ qglVertex3f(maxs[0],maxs[1],mins[2]);
+ qglEnd();
+
+}
+
+void splineTest() {
+ //g_splineList->load("p:/doom/base/maps/test_base1.camera");
+}
+
+void splineDraw() {
+ //g_splineList->addToRenderer();
+}
+
+
+//extern void D_DebugLine( const idVec3_t &color, const idVec3_t &start, const idVec3_t &end );
+
+void debugLine(idVec3_t &color, float x, float y, float z, float x2, float y2, float z2) {
+ idVec3_t from(x, y, z);
+ idVec3_t to(x2, y2, z2);
+ //D_DebugLine(color, from, to);
+}
+
+void idSplineList::addToRenderer() {
+
+ if (controlPoints.Num() == 0) {
+ return;
+ }
+
+ idVec3_t mins, maxs;
+ idVec3_t yellow(1.0, 1.0, 0);
+ idVec3_t white(1.0, 1.0, 1.0);
+ int i;
+
+ for(i = 0; i < controlPoints.Num(); i++) {
+ VectorCopy(*controlPoints[i], mins);
+ VectorCopy(mins, maxs);
+ mins[0] -= 8;
+ mins[1] += 8;
+ mins[2] -= 8;
+ maxs[0] += 8;
+ maxs[1] -= 8;
+ maxs[2] += 8;
+ debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
+ debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
+ debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
+ debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
+
+ debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
+ debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
+ debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
+ debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
+
+ }
+
+ int step = 0;
+ idVec3_t step1;
+ for(i = 3; i < controlPoints.Num(); i++) {
+ for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
+ float x = 0;
+ float y = 0;
+ float z = 0;
+ for (int j = 0; j < 4; j++) {
+ x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
+ y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
+ z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
+ }
+ if (step == 0) {
+ step1[0] = x;
+ step1[1] = y;
+ step1[2] = z;
+ step = 1;
+ } else {
+ debugLine( white, step1[0], step1[1], step1[2], x, y, z);
+ step = 0;
+ }
+
+ }
+ }
+}
+
+void idSplineList::buildSpline() {
+ //int start = Sys_Milliseconds();
+ clearSpline();
+ for(int i = 3; i < controlPoints.Num(); i++) {
+ for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
+ float x = 0;
+ float y = 0;
+ float z = 0;
+ for (int j = 0; j < 4; j++) {
+ x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
+ y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
+ z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
+ }
+ splinePoints.Append(new idVec3_t(x, y, z));
+ }
+ }
+ dirty = false;
+ //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
+}
+
+
+void idSplineList::draw(bool editMode) {
+ int i;
+ vec4_t yellow(1, 1, 0, 1);
+
+ if (controlPoints.Num() == 0) {
+ return;
+ }
+
+ if (dirty) {
+ buildSpline();
+ }
+
+
+ qglColor3fv(controlColor);
+ qglPointSize(5);
+
+ qglBegin(GL_POINTS);
+ for (i = 0; i < controlPoints.Num(); i++) {
+ qglVertex3fv(*controlPoints[i]);
+ }
+ qglEnd();
+
+ if (editMode) {
+ for(i = 0; i < controlPoints.Num(); i++) {
+ glBox(activeColor, *controlPoints[i], 4);
+ }
+ }
+
+ //Draw the curve
+ qglColor3fv(pathColor);
+ qglBegin(GL_LINE_STRIP);
+ int count = splinePoints.Num();
+ for (i = 0; i < count; i++) {
+ qglVertex3fv(*splinePoints[i]);
+ }
+ qglEnd();
+
+ if (editMode) {
+ qglColor3fv(segmentColor);
+ qglPointSize(3);
+ qglBegin(GL_POINTS);
+ for (i = 0; i < count; i++) {
+ qglVertex3fv(*splinePoints[i]);
+ }
+ qglEnd();
+ }
+ if (count > 0) {
+ //assert(activeSegment >=0 && activeSegment < count);
+ if (activeSegment >=0 && activeSegment < count) {
+ glBox(activeColor, *splinePoints[activeSegment], 6);
+ glBox(yellow, *splinePoints[activeSegment], 8);
+ }
+ }
+
+}
+
+float idSplineList::totalDistance() {
+
+ if (controlPoints.Num() == 0) {
+ return 0.0;
+ }
+
+ if (dirty) {
+ buildSpline();
+ }
+
+ float dist = 0.0;
+ idVec3_t temp;
+ int count = splinePoints.Num();
+ for(int i = 1; i < count; i++) {
+ temp = *splinePoints[i-1];
+ temp -= *splinePoints[i];
+ dist += temp.Length();
+ }
+ return dist;
+}
+
+void idSplineList::initPosition(long bt, long totalTime) {
+
+ if (dirty) {
+ buildSpline();
+ }
+
+ if (splinePoints.Num() == 0) {
+ return;
+ }
+
+ baseTime = bt;
+ time = totalTime;
+
+ // calc distance to travel ( this will soon be broken into time segments )
+ splineTime.Clear();
+ splineTime.Append(0);
+ float dist = totalDistance();
+ float distSoFar = 0.0;
+ idVec3_t temp;
+ int count = splinePoints.Num();
+ //for(int i = 2; i < count - 1; i++) {
+ for(int i = 1; i < count; i++) {
+ temp = *splinePoints[i-1];
+ temp -= *splinePoints[i];
+ distSoFar += temp.Length();
+ float percent = distSoFar / dist;
+ percent *= totalTime;
+ splineTime.Append(percent + bt);
+ }
+ assert(splineTime.Num() == splinePoints.Num());
+ activeSegment = 0;
+}
+
+
+
+float idSplineList::calcSpline(int step, float tension) {
+ switch(step) {
+ case 0: return (pow(1 - tension, 3)) / 6;
+ case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
+ case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
+ case 3: return pow(tension, 3) / 6;
+ }
+ return 0.0;
+}
+
+
+
+void idSplineList::updateSelection(const idVec3_t &move) {
+ if (selected) {
+ dirty = true;
+ VectorAdd(*selected, move, *selected);
+ }
+}
+
+
+void idSplineList::setSelectedPoint(idVec3_t *p) {
+ if (p) {
+ p->Snap();
+ for(int i = 0; i < controlPoints.Num(); i++) {
+ if (*p == *controlPoints[i]) {
+ selected = controlPoints[i];
+ }
+ }
+ } else {
+ selected = NULL;
+ }
+}
+
+const idVec3_t *idSplineList::getPosition(long t) {
+ static idVec3_t interpolatedPos;
+
+ int count = splineTime.Num();
+ if (count == 0) {
+ return &zero;
+ }
+
+ assert(splineTime.Num() == splinePoints.Num());
+
+ while (activeSegment < count) {
+ if (splineTime[activeSegment] >= t) {
+ if (activeSegment > 0 && activeSegment < count - 1) {
+ float timeHi = splineTime[activeSegment + 1];
+ float timeLo = splineTime[activeSegment - 1];
+ //float percent = (float)(baseTime + time - t) / time;
+ float percent = (timeHi - t) / (timeHi - timeLo);
+ // pick two bounding points
+ idVec3_t v1 = *splinePoints[activeSegment-1];
+ idVec3_t v2 = *splinePoints[activeSegment+1];
+ v2 *= (1.0 - percent);
+ v1 *= percent;
+ v2 += v1;
+ interpolatedPos = v2;
+ return &interpolatedPos;
+ }
+ return splinePoints[activeSegment];
+ } else {
+ activeSegment++;
+ }
+ }
+ return splinePoints[count-1];
+}
+
+void idSplineList::parse(const char *(*text) ) {
+ const char *token;
+ //Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !Q_stricmp (token, "}") ) {
+ break;
+ }
+
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "granularity") == 0) {
+ granularity = atof(token);
+ } else if (Q_stricmp(key.c_str(), "name") == 0) {
+ name = token;
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !Q_stricmp (token, "}") ) {
+ break;
+ }
+
+ Com_UngetToken();
+ // read the control point
+ idVec3_t point;
+ Com_Parse1DMatrix( text, 3, point );
+ addPoint(point.x, point.y, point.z);
+ } while (1);
+
+ //Com_UngetToken();
+ //Com_MatchToken( text, "}" );
+ dirty = true;
+}
+
+void idSplineList::write(fileHandle_t file, const char *p) {
+ idStr s = va("\t\t%s {\n", p);
+ FS_Write(s.c_str(), s.length(), file);
+ //s = va("\t\tname %s\n", name.c_str());
+ //FS_Write(s.c_str(), s.length(), file);
+ s = va("\t\t\tgranularity %f\n", granularity);
+ FS_Write(s.c_str(), s.length(), file);
+ int count = controlPoints.Num();
+ for (int i = 0; i < count; i++) {
+ s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z);
+ FS_Write(s.c_str(), s.length(), file);
+ }
+ s = "\t\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+
+void idCameraDef::getActiveSegmentInfo(int segment, idVec3_t &origin, idVec3_t &direction, float *fov) {
+#if 0
+ if (!cameraSpline.validTime()) {
+ buildCamera();
+ }
+ double d = (double)segment / numSegments();
+ getCameraInfo(d * totalTime * 1000, origin, direction, fov);
+#endif
+/*
+ if (!cameraSpline.validTime()) {
+ buildCamera();
+ }
+ origin = *cameraSpline.getSegmentPoint(segment);
+
+
+ idVec3_t temp;
+
+ int numTargets = getTargetSpline()->controlPoints.Num();
+ int count = cameraSpline.splineTime.Num();
+ if (numTargets == 0) {
+ // follow the path
+ if (cameraSpline.getActiveSegment() < count - 1) {
+ temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
+ }
+ } else if (numTargets == 1) {
+ temp = *getTargetSpline()->controlPoints[0];
+ } else {
+ temp = *getTargetSpline()->getSegmentPoint(segment);
+ }
+
+ temp -= origin;
+ temp.Normalize();
+ direction = temp;
+*/
+}
+
+bool idCameraDef::getCameraInfo(long time, idVec3_t &origin, idVec3_t &direction, float *fv) {
+
+
+ if ((time - startTime) / 1000 > totalTime) {
+ return false;
+ }
+
+
+ for (int i = 0; i < events.Num(); i++) {
+ if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {
+ events[i]->setTriggered(true);
+ if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {
+ setActiveTargetByName(events[i]->getParam());
+ getActiveTarget()->start(startTime + events[i]->getTime());
+ //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
+ } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {
+ //idEntity *ent = NULL;
+ //ent = level.FindTarget( ent, events[i]->getParam());
+ //if (ent) {
+ // ent->signal( SIG_TRIGGER );
+ // ent->ProcessEvent( &EV_Activate, world );
+ //}
+ } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {
+ //*fv = fov = atof(events[i]->getParam());
+ } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {
+ return false;
+ }
+ }
+ }
+
+ origin = *cameraPosition->getPosition(time);
+
+ *fv = fov.getFOV(time);
+
+ idVec3_t temp = origin;
+
+ int numTargets = targetPositions.Num();
+ if (numTargets == 0) {
+/*
+ // follow the path
+ if (cameraSpline.getActiveSegment() < count - 1) {
+ temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
+ if (temp == origin) {
+ int index = cameraSpline.getActiveSegment() + 2;
+ while (temp == origin && index < count - 1) {
+ temp = *cameraSpline.splinePoints[index++];
+ }
+ }
+ }
+*/
+ } else {
+ temp = *getActiveTarget()->getPosition(time);
+ }
+
+ temp -= origin;
+ temp.Normalize();
+ direction = temp;
+
+ return true;
+}
+
+bool idCameraDef::waitEvent(int index) {
+ //for (int i = 0; i < events.Num(); i++) {
+ // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
+ // return true;
+ // }
+ //}
+ return false;
+}
+
+
+#define NUM_CCELERATION_SEGS 10
+#define CELL_AMT 5
+
+void idCameraDef::buildCamera() {
+ int i;
+ int lastSwitch = 0;
+ idList<float> waits;
+ idList<int> targets;
+
+ totalTime = baseTime;
+ cameraPosition->setTime(totalTime * 1000);
+ // we have a base time layout for the path and the target path
+ // now we need to layer on any wait or speed changes
+ for (i = 0; i < events.Num(); i++) {
+ idCameraEvent *ev = events[i];
+ events[i]->setTriggered(false);
+ switch (events[i]->getType()) {
+ case idCameraEvent::EVENT_TARGET : {
+ targets.Append(i);
+ break;
+ }
+ case idCameraEvent::EVENT_WAIT : {
+ waits.Append(atof(events[i]->getParam()));
+ cameraPosition->addVelocity(events[i]->getTime(), atof(events[i]->getParam()) * 1000, 0);
+ break;
+ }
+ case idCameraEvent::EVENT_TARGETWAIT : {
+ //targetWaits.Append(i);
+ break;
+ }
+ case idCameraEvent::EVENT_SPEED : {
+/*
+ // take the average delay between up to the next five segments
+ float adjust = atof(events[i]->getParam());
+ int index = events[i]->getSegment();
+ total = 0;
+ count = 0;
+
+ // get total amount of time over the remainder of the segment
+ for (j = index; j < cameraSpline.numSegments() - 1; j++) {
+ total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
+ count++;
+ }
+
+ // multiply that by the adjustment
+ double newTotal = total * adjust;
+ // what is the difference..
+ newTotal -= total;
+ totalTime += newTotal / 1000;
+
+ // per segment difference
+ newTotal /= count;
+ int additive = newTotal;
+
+ // now propogate that difference out to each segment
+ for (j = index; j < cameraSpline.numSegments(); j++) {
+ cameraSpline.addSegmentTime(j, additive);
+ additive += newTotal;
+ }
+ break;
+*/
+ }
+ }
+ }
+
+
+ for (i = 0; i < waits.Num(); i++) {
+ totalTime += waits[i];
+ }
+
+ // on a new target switch, we need to take time to this point ( since last target switch )
+ // and allocate it across the active target, then reset time to this point
+ long timeSoFar = 0;
+ long total = totalTime * 1000;
+ for (i = 0; i < targets.Num(); i++) {
+ long t;
+ if (i < targets.Num() - 1) {
+ t = events[targets[i+1]]->getTime();
+ } else {
+ t = total - timeSoFar;
+ }
+ // t is how much time to use for this target
+ setActiveTargetByName(events[targets[i]]->getParam());
+ getActiveTarget()->setTime(t);
+ timeSoFar += t;
+ }
+
+
+}
+
+void idCameraDef::startCamera(long t) {
+ buildCamera();
+ cameraPosition->start(t);
+ //for (int i = 0; i < targetPositions.Num(); i++) {
+ // targetPositions[i]->
+ //}
+ startTime = t;
+ cameraRunning = true;
+}
+
+
+void idCameraDef::parse(const char *(*text) ) {
+
+ const char *token;
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !Q_stricmp (token, "}") ) {
+ break;
+ }
+
+ if (Q_stricmp(token, "time") == 0) {
+ baseTime = Com_ParseFloat(text);
+ }
+
+ if (Q_stricmp(token, "camera_fixed") == 0) {
+ cameraPosition = new idFixedPosition();
+ cameraPosition->parse(text);
+ }
+
+ if (Q_stricmp(token, "camera_interpolated") == 0) {
+ cameraPosition = new idInterpolatedPosition();
+ cameraPosition->parse(text);
+ }
+
+ if (Q_stricmp(token, "camera_spline") == 0) {
+ cameraPosition = new idSplinePosition();
+ cameraPosition->parse(text);
+ }
+
+ if (Q_stricmp(token, "target_fixed") == 0) {
+ idFixedPosition *pos = new idFixedPosition();
+ pos->parse(text);
+ targetPositions.Append(pos);
+ }
+
+ if (Q_stricmp(token, "target_interpolated") == 0) {
+ idInterpolatedPosition *pos = new idInterpolatedPosition();
+ pos->parse(text);
+ targetPositions.Append(pos);
+ }
+
+ if (Q_stricmp(token, "target_spline") == 0) {
+ idSplinePosition *pos = new idSplinePosition();
+ pos->parse(text);
+ targetPositions.Append(pos);
+ }
+
+ if (Q_stricmp(token, "fov") == 0) {
+ fov.parse(text);
+ }
+
+ if (Q_stricmp(token, "event") == 0) {
+ idCameraEvent *event = new idCameraEvent();
+ event->parse(text);
+ addEvent(event);
+ }
+
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+
+}
+
+bool idCameraDef::load(const char *filename) {
+ char *buf;
+ const char *buf_p;
+ int length = FS_ReadFile( filename, (void **)&buf );
+ if ( !buf ) {
+ return false;
+ }
+
+ clear();
+ Com_BeginParseSession( filename );
+ buf_p = buf;
+ parse(&buf_p);
+ Com_EndParseSession();
+ FS_FreeFile( buf );
+
+ return true;
+}
+
+void idCameraDef::save(const char *filename) {
+ fileHandle_t file = FS_FOpenFileWrite(filename);
+ if (file) {
+ int i;
+ idStr s = "cameraPathDef { \n";
+ FS_Write(s.c_str(), s.length(), file);
+ s = va("\ttime %f\n", baseTime);
+ FS_Write(s.c_str(), s.length(), file);
+
+ cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr()));
+
+ for (i = 0; i < numTargets(); i++) {
+ targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr()));
+ }
+
+ for (i = 0; i < events.Num(); i++) {
+ events[i]->write(file, "event");
+ }
+
+ fov.write(file, "fov");
+
+ s = "}\n";
+ FS_Write(s.c_str(), s.length(), file);
+ }
+ FS_FCloseFile(file);
+}
+
+int idCameraDef::sortEvents(const void *p1, const void *p2) {
+ idCameraEvent *ev1 = (idCameraEvent*)(p1);
+ idCameraEvent *ev2 = (idCameraEvent*)(p2);
+
+ if (ev1->getTime() > ev2->getTime()) {
+ return -1;
+ }
+ if (ev1->getTime() < ev2->getTime()) {
+ return 1;
+ }
+ return 0;
+}
+
+void idCameraDef::addEvent(idCameraEvent *event) {
+ events.Append(event);
+ //events.Sort(&sortEvents);
+
+}
+void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {
+ addEvent(new idCameraEvent(t, param, time));
+ buildCamera();
+}
+
+
+const char *idCameraEvent::eventStr[] = {
+ "NA",
+ "WAIT",
+ "TARGETWAIT",
+ "SPEED",
+ "TARGET",
+ "SNAPTARGET",
+ "FOV",
+ "SCRIPT",
+ "TRIGGER",
+ "STOP"
+};
+
+void idCameraEvent::parse(const char *(*text) ) {
+ const char *token;
+ Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ // here we may have to jump over brush epairs ( only used in editor )
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "type") == 0) {
+ type = static_cast<idCameraEvent::eventType>(atoi(token));
+ } else if (Q_stricmp(key.c_str(), "param") == 0) {
+ paramStr = token;
+ } else if (Q_stricmp(key.c_str(), "time") == 0) {
+ time = atoi(token);
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+}
+
+void idCameraEvent::write(fileHandle_t file, const char *name) {
+ idStr s = va("\t%s {\n", name);
+ FS_Write(s.c_str(), s.length(), file);
+ s = va("\t\ttype %d\n", static_cast<int>(type));
+ FS_Write(s.c_str(), s.length(), file);
+ s = va("\t\tparam %s\n", paramStr.c_str());
+ FS_Write(s.c_str(), s.length(), file);
+ s = va("\t\ttime %d\n", time);
+ FS_Write(s.c_str(), s.length(), file);
+ s = "\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+
+const char *idCameraPosition::positionStr[] = {
+ "Fixed",
+ "Interpolated",
+ "Spline",
+};
+
+
+
+const idVec3_t *idInterpolatedPosition::getPosition(long t) {
+ static idVec3_t interpolatedPos;
+
+ float velocity = getVelocity(t);
+ float timePassed = t - lastTime;
+ lastTime = t;
+
+ // convert to seconds
+ timePassed /= 1000;
+
+ float distToTravel = timePassed *= velocity;
+
+ idVec3_t temp = startPos;
+ temp -= endPos;
+ float distance = temp.Length();
+
+ distSoFar += distToTravel;
+ float percent = (float)(distSoFar) / distance;
+
+ if (percent > 1.0) {
+ percent = 1.0;
+ } else if (percent < 0.0) {
+ percent = 0.0;
+ }
+
+ // the following line does a straigt calc on percentage of time
+ // float percent = (float)(startTime + time - t) / time;
+
+ idVec3_t v1 = startPos;
+ idVec3_t v2 = endPos;
+ v1 *= (1.0 - percent);
+ v2 *= percent;
+ v1 += v2;
+ interpolatedPos = v1;
+ return &interpolatedPos;
+}
+
+
+void idCameraFOV::parse(const char *(*text) ) {
+ const char *token;
+ Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ // here we may have to jump over brush epairs ( only used in editor )
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "fov") == 0) {
+ fov = atof(token);
+ } else if (Q_stricmp(key.c_str(), "startFOV") == 0) {
+ startFOV = atof(token);
+ } else if (Q_stricmp(key.c_str(), "endFOV") == 0) {
+ endFOV = atof(token);
+ } else if (Q_stricmp(key.c_str(), "time") == 0) {
+ time = atoi(token);
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+}
+
+bool idCameraPosition::parseToken(const char *key, const char *(*text)) {
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key, "time") == 0) {
+ time = atol(token);
+ return true;
+ } else if (Q_stricmp(key, "type") == 0) {
+ type = static_cast<idCameraPosition::positionType>(atoi(token));
+ return true;
+ } else if (Q_stricmp(key, "velocity") == 0) {
+ long t = atol(token);
+ token = Com_Parse(text);
+ long d = atol(token);
+ token = Com_Parse(text);
+ float s = atof(token);
+ addVelocity(t, d, s);
+ return true;
+ } else if (Q_stricmp(key, "baseVelocity") == 0) {
+ baseVelocity = atof(token);
+ return true;
+ } else if (Q_stricmp(key, "name") == 0) {
+ name = token;
+ return true;
+ } else if (Q_stricmp(key, "time") == 0) {
+ time = atoi(token);
+ return true;
+ }
+ Com_UngetToken();
+ return false;
+}
+
+
+
+void idFixedPosition::parse(const char *(*text) ) {
+ const char *token;
+ Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ // here we may have to jump over brush epairs ( only used in editor )
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "pos") == 0) {
+ Com_UngetToken();
+ Com_Parse1DMatrix( text, 3, pos );
+ } else {
+ Com_UngetToken();
+ idCameraPosition::parseToken(key.c_str(), text);
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+}
+
+void idInterpolatedPosition::parse(const char *(*text) ) {
+ const char *token;
+ Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ // here we may have to jump over brush epairs ( only used in editor )
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "startPos") == 0) {
+ Com_UngetToken();
+ Com_Parse1DMatrix( text, 3, startPos );
+ } else if (Q_stricmp(key.c_str(), "endPos") == 0) {
+ Com_UngetToken();
+ Com_Parse1DMatrix( text, 3, endPos );
+ } else {
+ Com_UngetToken();
+ idCameraPosition::parseToken(key.c_str(), text);
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+}
+
+
+void idSplinePosition::parse(const char *(*text) ) {
+ const char *token;
+ Com_MatchToken( text, "{" );
+ do {
+ token = Com_Parse( text );
+
+ if ( !token[0] ) {
+ break;
+ }
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ // here we may have to jump over brush epairs ( only used in editor )
+ do {
+ // if token is not a brace, it is a key for a key/value pair
+ if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+ break;
+ }
+
+ Com_UngetToken();
+ idStr key = Com_ParseOnLine(text);
+
+ const char *token = Com_Parse(text);
+ if (Q_stricmp(key.c_str(), "target") == 0) {
+ target.parse(text);
+ } else {
+ Com_UngetToken();
+ idCameraPosition::parseToken(key.c_str(), text);
+ }
+ token = Com_Parse(text);
+
+ } while (1);
+
+ if ( !strcmp (token, "}") ) {
+ break;
+ }
+
+ } while (1);
+
+ Com_UngetToken();
+ Com_MatchToken( text, "}" );
+}
+
+
+
+void idCameraFOV::write(fileHandle_t file, const char *p) {
+ idStr s = va("\t%s {\n", p);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\tfov %f\n", fov);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\tstartFOV %f\n", startFOV);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\tendFOV %f\n", endFOV);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\ttime %i\n", time);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = "\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+
+void idCameraPosition::write(fileHandle_t file, const char *p) {
+
+ idStr s = va("\t\ttime %i\n", time);
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\ttype %i\n", static_cast<int>(type));
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\tname %s\n", name.c_str());
+ FS_Write(s.c_str(), s.length(), file);
+
+ s = va("\t\tbaseVelocity %f\n", baseVelocity);
+ FS_Write(s.c_str(), s.length(), file);
+
+ for (int i = 0; i < velocities.Num(); i++) {
+ s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed);
+ FS_Write(s.c_str(), s.length(), file);
+ }
+
+}
+
+void idFixedPosition::write(fileHandle_t file, const char *p) {
+ idStr s = va("\t%s {\n", p);
+ FS_Write(s.c_str(), s.length(), file);
+ idCameraPosition::write(file, p);
+ s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z);
+ FS_Write(s.c_str(), s.length(), file);
+ s = "\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+void idInterpolatedPosition::write(fileHandle_t file, const char *p) {
+ idStr s = va("\t%s {\n", p);
+ FS_Write(s.c_str(), s.length(), file);
+ idCameraPosition::write(file, p);
+ s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z);
+ FS_Write(s.c_str(), s.length(), file);
+ s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z);
+ FS_Write(s.c_str(), s.length(), file);
+ s = "\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+void idSplinePosition::write(fileHandle_t file, const char *p) {
+ idStr s = va("\t%s {\n", p);
+ FS_Write(s.c_str(), s.length(), file);
+ idCameraPosition::write(file, p);
+ target.write(file, "target");
+ s = "\t}\n";
+ FS_Write(s.c_str(), s.length(), file);
+}
+
+void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {
+ const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;
+ idCameraPosition *pos = newFromType(type);
+ if (pos) {
+ pos->setName(name);
+ targetPositions.Append(pos);
+ activeTarget = numTargets()-1;
+ if (activeTarget == 0) {
+ // first one
+ addEvent(idCameraEvent::EVENT_TARGET, name, 0);
+ }
+ }
+}
+
+
+
+idCameraDef camera;
+
+extern "C" {
+qboolean loadCamera(const char *name) {
+ camera.clear();
+ return static_cast<qboolean>(camera.load(name));
+}
+
+qboolean getCameraInfo(int time, float *origin, float*angles) {
+ idVec3_t dir, org;
+ org[0] = origin[0];
+ org[1] = origin[1];
+ org[2] = origin[2];
+ float fov = 90;
+ if (camera.getCameraInfo(time, org, dir, &fov)) {
+ origin[0] = org[0];
+ origin[1] = org[1];
+ origin[2] = org[2];
+ angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
+ angles[0] = asin (dir[2])*180/3.14159;
+ return qtrue;
+ }
+ return qfalse;
+}
+
+void startCamera(int time) {
+ camera.startCamera(time);
+}
+
+}
+
+
diff --git a/q3radiant/splines/splines.h b/q3radiant/splines/splines.h
new file mode 100755
index 0000000..1cd0d58
--- /dev/null
+++ b/q3radiant/splines/splines.h
@@ -0,0 +1,1080 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __SPLINES_H
+#define __SPLINES_H
+
+extern "C" {
+#ifdef Q3RADIANT
+#include "../qgl.h"
+#else
+#include "../renderer/qgl.h"
+#endif
+}
+#include "util_list.h"
+#include "util_str.h"
+#include "math_vector.h"
+
+typedef int fileHandle_t;
+
+extern void glBox(idVec3_t &color, idVec3_t &point, float size);
+extern void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label);
+
+static vec4_t blue(0, 0, 1, 1);
+static vec4_t red(1, 0, 0, 1);
+
+class idPointListInterface {
+public:
+ idPointListInterface() {
+ selectedPoints.Clear();
+ };
+ ~idPointListInterface() {};
+
+ virtual int numPoints() {
+ return 0;
+ }
+
+ virtual void addPoint(const float x, const float y, const float z) {}
+ virtual void addPoint(const idVec3_t &v) {}
+ virtual void removePoint(int index) {}
+ virtual idVec3_t *getPoint(int index) { return NULL; }
+
+ int selectPointByRay(float ox, float oy, float oz, float dx, float dy, float dz, bool single) {
+ idVec3_t origin(ox, oy, oz);
+ idVec3_t dir(dx, dy, dz);
+ return selectPointByRay(origin, dir, single);
+ }
+
+ int selectPointByRay(const idVec3_t origin, const idVec3_t direction, bool single) {
+ int i, besti, count;
+ float d, bestd;
+ idVec3_t temp, temp2;
+
+ // find the point closest to the ray
+ besti = -1;
+ bestd = 8;
+ count = numPoints();
+
+ for (i=0; i < count; i++) {
+ temp = *getPoint(i);
+ temp2 = temp;
+ temp -= origin;
+ d = DotProduct(temp, direction);
+ __VectorMA (origin, d, direction, temp);
+ temp2 -= temp;
+ d = temp2.Length();
+ if (d <= bestd) {
+ bestd = d;
+ besti = i;
+ }
+ }
+
+ if (besti >= 0) {
+ selectPoint(besti, single);
+ }
+
+ return besti;
+ }
+
+ int isPointSelected(int index) {
+ int count = selectedPoints.Num();
+ for (int i = 0; i < count; i++) {
+ if (selectedPoints[i] == index) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ int selectPoint(int index, bool single) {
+ if (index >= 0 && index < numPoints()) {
+ if (single) {
+ deselectAll();
+ } else {
+ if (isPointSelected(index) >= 0) {
+ selectedPoints.Remove(index);
+ }
+ }
+ return selectedPoints.Append(index);
+ }
+ return -1;
+ }
+
+ void selectAll() {
+ selectedPoints.Clear();
+ for (int i = 0; i < numPoints(); i++) {
+ selectedPoints.Append(i);
+ }
+ }
+
+ void deselectAll() {
+ selectedPoints.Clear();
+ }
+
+ int numSelectedPoints();
+
+ idVec3_t *getSelectedPoint(int index) {
+ assert(index >= 0 && index < numSelectedPoints());
+ return getPoint(selectedPoints[index]);
+ }
+
+ virtual void updateSelection(float x, float y, float z) {
+ idVec3_t move(x, y, z);
+ updateSelection(move);
+ }
+
+ virtual void updateSelection(const idVec3_t &move) {
+ int count = selectedPoints.Num();
+ for (int i = 0; i < count; i++) {
+ *getPoint(selectedPoints[i]) += move;
+ }
+ }
+
+ void drawSelection() {
+ int count = selectedPoints.Num();
+ for (int i = 0; i < count; i++) {
+ glBox(red, *getPoint(selectedPoints[i]), 4);
+ }
+ }
+
+protected:
+ idList<int> selectedPoints;
+
+};
+
+
+class idSplineList {
+
+public:
+
+ idSplineList() {
+ clear();
+ }
+
+ idSplineList(const char *p) {
+ clear();
+ name = p;
+ };
+
+ ~idSplineList() {
+ clear();
+ };
+
+ void clearControl() {
+ for (int i = 0; i < controlPoints.Num(); i++) {
+ delete controlPoints[i];
+ }
+ controlPoints.Clear();
+ }
+
+ void clearSpline() {
+ for (int i = 0; i < splinePoints.Num(); i++) {
+ delete splinePoints[i];
+ }
+ splinePoints.Clear();
+ }
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+ void clear() {
+ clearControl();
+ clearSpline();
+ splineTime.Clear();
+ selected = NULL;
+ dirty = true;
+ activeSegment = 0;
+ granularity = 0.025;
+ pathColor.set(1.0, 0.5, 0.0);
+ controlColor.set(0.7, 0.0, 1.0);
+ segmentColor.set(0.0, 0.0, 1.0);
+ activeColor.set(1.0, 0.0, 0.0);
+ }
+
+ void initPosition(long startTime, long totalTime);
+ const idVec3_t *getPosition(long time);
+
+
+ void draw(bool editMode);
+ void addToRenderer();
+
+ void setSelectedPoint(idVec3_t *p);
+ idVec3_t *getSelectedPoint() {
+ return selected;
+ }
+
+ void addPoint(const idVec3_t &v) {
+ controlPoints.Append(new idVec3_t(v));
+ dirty = true;
+ }
+
+ void addPoint(float x, float y, float z) {
+ controlPoints.Append(new idVec3_t(x, y, z));
+ dirty = true;
+ }
+
+ void updateSelection(const idVec3_t &move);
+
+ void startEdit() {
+ editMode = true;
+ }
+
+ void stopEdit() {
+ editMode = false;
+ }
+
+ void buildSpline();
+
+ void setGranularity(float f) {
+ granularity = f;
+ }
+
+ float getGranularity() {
+ return granularity;
+ }
+
+ int numPoints() {
+ return controlPoints.Num();
+ }
+
+ idVec3_t *getPoint(int index) {
+ assert(index >= 0 && index < controlPoints.Num());
+ return controlPoints[index];
+ }
+
+ idVec3_t *getSegmentPoint(int index) {
+ assert(index >= 0 && index < splinePoints.Num());
+ return splinePoints[index];
+ }
+
+
+ void setSegmentTime(int index, int time) {
+ assert(index >= 0 && index < splinePoints.Num());
+ splineTime[index] = time;
+ }
+
+ int getSegmentTime(int index) {
+ assert(index >= 0 && index < splinePoints.Num());
+ return splineTime[index];
+ }
+ void addSegmentTime(int index, int time) {
+ assert(index >= 0 && index < splinePoints.Num());
+ splineTime[index] += time;
+ }
+
+ float totalDistance();
+
+ static idVec3_t zero;
+
+ int getActiveSegment() {
+ return activeSegment;
+ }
+
+ void setActiveSegment(int i) {
+ //assert(i >= 0 && (splinePoints.Num() > 0 && i < splinePoints.Num()));
+ activeSegment = i;
+ }
+
+ int numSegments() {
+ return splinePoints.Num();
+ }
+
+ void setColors(idVec3_t &path, idVec3_t &segment, idVec3_t &control, idVec3_t &active) {
+ pathColor = path;
+ segmentColor = segment;
+ controlColor = control;
+ activeColor = active;
+ }
+
+ const char *getName() {
+ return name.c_str();
+ }
+
+ void setName(const char *p) {
+ name = p;
+ }
+
+ bool validTime() {
+ if (dirty) {
+ buildSpline();
+ }
+ // gcc doesn't allow static casting away from bools
+ // why? I've no idea...
+ return (bool)(splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num());
+ }
+
+ void setTime(long t) {
+ time = t;
+ }
+
+ void setBaseTime(long t) {
+ baseTime = t;
+ }
+
+protected:
+ idStr name;
+ float calcSpline(int step, float tension);
+ idList<idVec3_t*> controlPoints;
+ idList<idVec3_t*> splinePoints;
+ idList<float> splineTime;
+ idVec3_t *selected;
+ idVec3_t pathColor, segmentColor, controlColor, activeColor;
+ float granularity;
+ bool editMode;
+ bool dirty;
+ int activeSegment;
+ long baseTime;
+ long time;
+ friend class idCamera;
+};
+
+// time in milliseconds
+// velocity where 1.0 equal rough walking speed
+struct idVelocity {
+ idVelocity(long start, long duration, float s) {
+ startTime = start;
+ time = duration;
+ speed = s;
+ }
+ long startTime;
+ long time;
+ float speed;
+};
+
+// can either be a look at or origin position for a camera
+//
+class idCameraPosition : public idPointListInterface {
+public:
+
+ virtual void clear() {
+ editMode = false;
+ for (int i = 0; i < velocities.Num(); i++) {
+ delete velocities[i];
+ velocities[i] = NULL;
+ }
+ velocities.Clear();
+ }
+
+ idCameraPosition(const char *p) {
+ name = p;
+ }
+
+ idCameraPosition() {
+ time = 0;
+ name = "position";
+ }
+
+ idCameraPosition(long t) {
+ time = t;
+ }
+
+ virtual ~idCameraPosition() {
+ clear();
+ }
+
+
+ // this can be done with RTTI syntax but i like the derived classes setting a type
+ // makes serialization a bit easier to see
+ //
+ enum positionType {
+ FIXED = 0x00,
+ INTERPOLATED,
+ SPLINE,
+ POSITION_COUNT
+ };
+
+
+ virtual void start(long t) {
+ startTime = t;
+ }
+
+ long getTime() {
+ return time;
+ }
+
+ virtual void setTime(long t) {
+ time = t;
+ }
+
+ float getVelocity(long t) {
+ long check = t - startTime;
+ for (int i = 0; i < velocities.Num(); i++) {
+ if (check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time) {
+ return velocities[i]->speed;
+ }
+ }
+ return baseVelocity;
+ }
+
+ void addVelocity(long start, long duration, float speed) {
+ velocities.Append(new idVelocity(start, duration, speed));
+ }
+
+ virtual const idVec3_t *getPosition(long t) {
+ assert(true);
+ return NULL;
+ }
+
+ virtual void draw(bool editMode) {};
+
+ virtual void parse(const char *(*text)) {};
+ virtual void write(fileHandle_t file, const char *name);
+ virtual bool parseToken(const char *key, const char *(*text));
+
+ const char *getName() {
+ return name.c_str();
+ }
+
+ void setName(const char *p) {
+ name = p;
+ }
+
+ virtual startEdit() {
+ editMode = true;
+ }
+
+ virtual stopEdit() {
+ editMode = false;
+ }
+
+ virtual void draw() {};
+
+ const char *typeStr() {
+ return positionStr[static_cast<int>(type)];
+ }
+
+ void calcVelocity(float distance) {
+ float secs = (float)time / 1000;
+ baseVelocity = distance / secs;
+ }
+
+protected:
+ static const char* positionStr[POSITION_COUNT];
+ long startTime;
+ long time;
+ idCameraPosition::positionType type;
+ idStr name;
+ bool editMode;
+ idList<idVelocity*> velocities;
+ float baseVelocity;
+};
+
+class idFixedPosition : public idCameraPosition {
+public:
+
+ void init() {
+ pos.Zero();
+ type = idCameraPosition::FIXED;
+ }
+
+ idFixedPosition() : idCameraPosition() {
+ init();
+ }
+
+ idFixedPosition(idVec3_t p) : idCameraPosition() {
+ init();
+ pos = p;
+ }
+
+ virtual void addPoint(const idVec3_t &v) {
+ pos = v;
+ }
+
+ virtual void addPoint(const float x, const float y, const float z) {
+ pos.set(x, y, z);
+ }
+
+
+ ~idFixedPosition() {
+ }
+
+ virtual const idVec3_t *getPosition(long t) {
+ return &pos;
+ }
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+ virtual int numPoints() {
+ return 1;
+ }
+
+ virtual idVec3_t *getPoint(int index) {
+ if (index != 0) {
+ assert(true);
+ };
+ return &pos;
+ }
+
+ virtual void draw(bool editMode) {
+ glLabeledPoint(blue, pos, (editMode) ? 5 : 3, "Fixed point");
+ }
+
+protected:
+ idVec3_t pos;
+};
+
+class idInterpolatedPosition : public idCameraPosition {
+public:
+
+ void init() {
+ type = idCameraPosition::INTERPOLATED;
+ first = true;
+ startPos.Zero();
+ endPos.Zero();
+ }
+
+ idInterpolatedPosition() : idCameraPosition() {
+ init();
+ }
+
+ idInterpolatedPosition(idVec3_t start, idVec3_t end, long time) : idCameraPosition(time) {
+ init();
+ startPos = start;
+ endPos = end;
+ }
+
+ ~idInterpolatedPosition() {
+ }
+
+ virtual const idVec3_t *getPosition(long t);
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+ virtual int numPoints() {
+ return 2;
+ }
+
+ virtual idVec3_t *getPoint(int index) {
+ assert(index >= 0 && index < 2);
+ if (index == 0) {
+ return &startPos;
+ }
+ return &endPos;
+ }
+
+ virtual void addPoint(const float x, const float y, const float z) {
+ if (first) {
+ startPos.set(x, y, z);
+ first = false;
+ } else {
+ endPos.set(x, y, z);
+ first = true;
+ }
+ }
+
+ virtual void addPoint(const idVec3_t &v) {
+ if (first) {
+ startPos = v;
+ first = false;
+ } else {
+ endPos = v;
+ first = true;
+ }
+ }
+
+ virtual void draw(bool editMode) {
+ glLabeledPoint(blue, startPos, (editMode) ? 5 : 3, "Start interpolated");
+ glLabeledPoint(blue, endPos, (editMode) ? 5 : 3, "End interpolated");
+ qglBegin(GL_LINES);
+ qglVertex3fv(startPos);
+ qglVertex3fv(endPos);
+ qglEnd();
+ }
+
+ virtual void start(long t) {
+ idCameraPosition::start(t);
+ lastTime = startTime;
+ distSoFar = 0.0;
+ idVec3_t temp = startPos;
+ temp -= endPos;
+ calcVelocity(temp.Length());
+ }
+
+protected:
+ bool first;
+ idVec3_t startPos;
+ idVec3_t endPos;
+ long lastTime;
+ float distSoFar;
+};
+
+class idSplinePosition : public idCameraPosition {
+public:
+
+ void init() {
+ type = idCameraPosition::SPLINE;
+ }
+
+ idSplinePosition() : idCameraPosition() {
+ init();
+ }
+
+ idSplinePosition(long time) : idCameraPosition(time) {
+ init();
+ }
+
+ ~idSplinePosition() {
+ }
+
+ virtual void start(long t) {
+ idCameraPosition::start(t);
+ target.initPosition(t, time);
+ calcVelocity(target.totalDistance());
+ }
+
+ virtual const idVec3_t *getPosition(long t) {
+ return target.getPosition(t);
+ }
+
+ //virtual const idVec3_t *getPosition(long t) const {
+
+ void addControlPoint(idVec3_t &v) {
+ target.addPoint(v);
+ }
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+ virtual int numPoints() {
+ return target.numPoints();
+ }
+
+ virtual idVec3_t *getPoint(int index) {
+ return target.getPoint(index);
+ }
+
+ virtual void addPoint(const idVec3_t &v) {
+ target.addPoint(v);
+ }
+
+ virtual void addPoint(const float x, const float y, const float z) {
+ target.addPoint(x, y, z);
+ }
+
+ virtual void draw(bool editMode) {
+ target.draw(editMode);
+ }
+
+ virtual void updateSelection(const idVec3_t &move) {
+ idCameraPosition::updateSelection(move);
+ target.buildSpline();
+ }
+
+protected:
+ idSplineList target;
+};
+
+class idCameraFOV {
+public:
+
+ idCameraFOV() {
+ time = 0;
+ fov = 90;
+ }
+
+ idCameraFOV(int v) {
+ time = 0;
+ fov = v;
+ }
+
+ idCameraFOV(int s, int e, long t) {
+ startFOV = s;
+ endFOV = e;
+ time = t;
+ }
+
+
+ ~idCameraFOV(){}
+
+ void setFOV(float f) {
+ fov = f;
+ }
+
+ float getFOV(long t) {
+ if (time) {
+ assert(startTime);
+ float percent = t / startTime;
+ float temp = startFOV - endFOV;
+ temp *= percent;
+ fov = startFOV + temp;
+ }
+ return fov;
+ }
+
+ int start(long t) {
+ startTime = t;
+ }
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+protected:
+ float fov;
+ float startFOV;
+ float endFOV;
+ int startTime;
+ int time;
+};
+
+
+
+
+class idCameraEvent {
+public:
+ enum eventType {
+ EVENT_NA = 0x00,
+ EVENT_WAIT,
+ EVENT_TARGETWAIT,
+ EVENT_SPEED,
+ EVENT_TARGET,
+ EVENT_SNAPTARGET,
+ EVENT_FOV,
+ EVENT_SCRIPT,
+ EVENT_TRIGGER,
+ EVENT_STOP,
+ EVENT_COUNT
+ };
+
+ static const char* eventStr[EVENT_COUNT];
+
+ idCameraEvent() {
+ paramStr = "";
+ type = EVENT_NA;
+ time = 0;
+ }
+
+ idCameraEvent(eventType t, const char *param, long n) {
+ type = t;
+ paramStr = param;
+ time = n;
+ }
+
+ ~idCameraEvent() {};
+
+ eventType getType() {
+ return type;
+ }
+
+ const char *typeStr() {
+ return eventStr[static_cast<int>(type)];
+ }
+
+ const char *getParam() {
+ return paramStr.c_str();
+ }
+
+ long getTime() {
+ return time;
+ }
+
+ void setTime(long n) {
+ time = n;
+ }
+
+ void parse(const char *(*text));
+ void write(fileHandle_t file, const char *name);
+
+ void setTriggered(bool b) {
+ triggered = b;
+ }
+
+ bool getTriggered() {
+ return triggered;
+ }
+
+protected:
+ eventType type;
+ idStr paramStr;
+ long time;
+ bool triggered;
+
+};
+
+class idCameraDef {
+public:
+
+ void clear() {
+ currentCameraPosition = 0;
+ cameraRunning = false;
+ lastDirection.Zero();
+ baseTime = 30;
+ activeTarget = 0;
+ name = "camera01";
+ fov.setFOV(90);
+ int i;
+ for (i = 0; i < targetPositions.Num(); i++) {
+ delete targetPositions[i];
+ }
+ for (i = 0; i < events.Num(); i++) {
+ delete events[i];
+ }
+ delete cameraPosition;
+ cameraPosition = NULL;
+ events.Clear();
+ targetPositions.Clear();
+ }
+
+ idCameraPosition *startNewCamera(idCameraPosition::positionType type) {
+ clear();
+ if (type == idCameraPosition::SPLINE) {
+ cameraPosition = new idSplinePosition();
+ } else if (type == idCameraPosition::INTERPOLATED) {
+ cameraPosition = new idInterpolatedPosition();
+ } else {
+ cameraPosition = new idFixedPosition();
+ }
+ return cameraPosition;
+ }
+
+ idCameraDef() {
+ clear();
+ }
+
+ ~idCameraDef() {
+ clear();
+ }
+
+ void addEvent(idCameraEvent::eventType t, const char *param, long time);
+
+ void addEvent(idCameraEvent *event);
+
+ static int sortEvents(const void *p1, const void *p2);
+
+ int numEvents() {
+ return events.Num();
+ }
+
+ idCameraEvent *getEvent(int index) {
+ assert(index >= 0 && index < events.Num());
+ return events[index];
+ }
+
+ void parse(const char *(*text));
+ bool load(const char *filename);
+ void save(const char *filename);
+
+ void buildCamera();
+
+ //idSplineList *getcameraPosition() {
+ // return &cameraPosition;
+ //}
+
+ static idCameraPosition *newFromType(idCameraPosition::positionType t) {
+ switch (t) {
+ case idCameraPosition::FIXED : return new idFixedPosition();
+ case idCameraPosition::INTERPOLATED : return new idInterpolatedPosition();
+ case idCameraPosition::SPLINE : return new idSplinePosition();
+ };
+ return NULL;
+ }
+
+ void addTarget(const char *name, idCameraPosition::positionType type);
+
+ idCameraPosition *getActiveTarget() {
+ if (targetPositions.Num() == 0) {
+ addTarget(NULL, idCameraPosition::FIXED);
+ }
+ return targetPositions[activeTarget];
+ }
+
+ idCameraPosition *getActiveTarget(int index) {
+ if (targetPositions.Num() == 0) {
+ addTarget(NULL, idCameraPosition::FIXED);
+ return targetPositions[0];
+ }
+ return targetPositions[index];
+ }
+
+ int numTargets() {
+ return targetPositions.Num();
+ }
+
+
+ void setActiveTargetByName(const char *name) {
+ for (int i = 0; i < targetPositions.Num(); i++) {
+ if (stricmp(name, targetPositions[i]->getName()) == 0) {
+ setActiveTarget(i);
+ return;
+ }
+ }
+ }
+
+ void setActiveTarget(int index) {
+ assert(index >= 0 && index < targetPositions.Num());
+ activeTarget = index;
+ }
+
+ void setRunning(bool b) {
+ cameraRunning = b;
+ }
+
+ void setBaseTime(float f) {
+ baseTime = f;
+ }
+
+ float getBaseTime() {
+ return baseTime;
+ }
+
+ float getTotalTime() {
+ return totalTime;
+ }
+
+ void startCamera(long t);
+ void stopCamera() {
+ cameraRunning = true;
+ }
+ void getActiveSegmentInfo(int segment, idVec3_t &origin, idVec3_t &direction, float *fv);
+
+ bool getCameraInfo(long time, idVec3_t &origin, idVec3_t &direction, float *fv);
+ bool getCameraInfo(long time, float *origin, float *direction, float *fv) {
+ idVec3_t org, dir;
+ org[0] = origin[0];
+ org[1] = origin[1];
+ org[2] = origin[2];
+ dir[0] = direction[0];
+ dir[1] = direction[1];
+ dir[2] = direction[2];
+ bool b = getCameraInfo(time, org, dir, fv);
+ origin[0] = org[0];
+ origin[1] = org[1];
+ origin[2] = org[2];
+ direction[0] = dir[0];
+ direction[1] = dir[1];
+ direction[2] = dir[2];
+ return b;
+ }
+
+ void draw(bool editMode) {
+ // gcc doesn't allow casting away from bools
+ // why? I've no idea...
+ if (cameraPosition) {
+ cameraPosition->draw((bool)((editMode || cameraRunning) && cameraEdit));
+ int count = targetPositions.Num();
+ for (int i = 0; i < count; i++) {
+ targetPositions[i]->draw((bool)((editMode || cameraRunning) && i == activeTarget && !cameraEdit));
+ }
+ }
+ }
+
+/*
+ int numSegments() {
+ if (cameraEdit) {
+ return cameraPosition.numSegments();
+ }
+ return getTargetSpline()->numSegments();
+ }
+
+ int getActiveSegment() {
+ if (cameraEdit) {
+ return cameraPosition.getActiveSegment();
+ }
+ return getTargetSpline()->getActiveSegment();
+ }
+
+ void setActiveSegment(int i) {
+ if (cameraEdit) {
+ cameraPosition.setActiveSegment(i);
+ } else {
+ getTargetSpline()->setActiveSegment(i);
+ }
+ }
+*/
+ int numPoints() {
+ if (cameraEdit) {
+ return cameraPosition->numPoints();
+ }
+ return getActiveTarget()->numPoints();
+ }
+
+ const idVec3_t *getPoint(int index) {
+ if (cameraEdit) {
+ return cameraPosition->getPoint(index);
+ }
+ return getActiveTarget()->getPoint(index);
+ }
+
+ void stopEdit() {
+ editMode = false;
+ if (cameraEdit) {
+ cameraPosition->stopEdit();
+ } else {
+ getActiveTarget()->stopEdit();
+ }
+ }
+
+ void startEdit(bool camera) {
+ cameraEdit = camera;
+ if (camera) {
+ cameraPosition->startEdit();
+ for (int i = 0; i < targetPositions.Num(); i++) {
+ targetPositions[i]->stopEdit();
+ }
+ } else {
+ getActiveTarget()->startEdit();
+ cameraPosition->stopEdit();
+ }
+ editMode = true;
+ }
+
+ bool waitEvent(int index);
+
+ const char *getName() {
+ return name.c_str();
+ }
+
+ void setName(const char *p) {
+ name = p;
+ }
+
+ idCameraPosition *getPositionObj() {
+ if (cameraPosition == NULL) {
+ cameraPosition = new idFixedPosition();
+ }
+ return cameraPosition;
+ }
+
+protected:
+ idStr name;
+ int currentCameraPosition;
+ idVec3_t lastDirection;
+ bool cameraRunning;
+ idCameraPosition *cameraPosition;
+ idList<idCameraPosition*> targetPositions;
+ idList<idCameraEvent*> events;
+ idCameraFOV fov;
+ int activeTarget;
+ float totalTime;
+ float baseTime;
+ long startTime;
+
+ bool cameraEdit;
+ bool editMode;
+};
+
+extern bool g_splineMode;
+
+extern idCameraDef *g_splineList;
+
+
+#endif \ No newline at end of file
diff --git a/q3radiant/splines/util_list.h b/q3radiant/splines/util_list.h
new file mode 100755
index 0000000..4f93244
--- /dev/null
+++ b/q3radiant/splines/util_list.h
@@ -0,0 +1,346 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+#ifndef __UTIL_LIST_H__
+#define __UTIL_LIST_H__
+
+#include <stdlib.h>
+#include <assert.h>
+
+template< class type >
+class idList {
+private:
+ int m_num;
+ int m_size;
+ int m_granularity;
+ type *m_list;
+
+public:
+ idList( int granularity = 16 );
+ ~idList<type>();
+ void Clear( void );
+ int Num( void );
+ void SetNum( int num );
+ void SetGranularity( int granularity );
+ void Condense( void );
+ int Size( void );
+ void Resize( int size );
+ type operator[]( int index ) const;
+ type &operator[]( int index );
+ int Append( type const & obj );
+ int AddUnique( type const & obj );
+ type *Find( type const & obj, int *index = NULL );
+ bool RemoveIndex( int index );
+ bool Remove( type const & obj );
+ typedef int cmp_t(const void *, const void *);
+ void Sort( cmp_t *compare );
+};
+
+/*
+================
+idList<type>::idList( int )
+================
+*/
+template< class type >
+inline idList<type>::idList( int granularity ) {
+ assert( granularity > 0 );
+
+ m_list = NULL;
+ m_granularity = granularity;
+ Clear();
+}
+
+/*
+================
+idList<type>::~idList<type>
+================
+*/
+template< class type >
+inline idList<type>::~idList() {
+ Clear();
+}
+
+/*
+================
+idList<type>::Clear
+================
+*/
+template< class type >
+inline void idList<type>::Clear( void ) {
+ if ( m_list ) {
+ delete[] m_list;
+ }
+
+ m_list = NULL;
+ m_num = 0;
+ m_size = 0;
+}
+
+/*
+================
+idList<type>::Num
+================
+*/
+template< class type >
+inline int idList<type>::Num( void ) {
+ return m_num;
+}
+
+/*
+================
+idList<type>::SetNum
+================
+*/
+template< class type >
+inline void idList<type>::SetNum( int num ) {
+ assert( num >= 0 );
+ if ( num > m_size ) {
+ // resize it up to the closest level of granularity
+ Resize( ( ( num + m_granularity - 1 ) / m_granularity ) * m_granularity );
+ }
+ m_num = num;
+}
+
+/*
+================
+idList<type>::SetGranularity
+================
+*/
+template< class type >
+inline void idList<type>::SetGranularity( int granularity ) {
+ int newsize;
+
+ assert( granularity > 0 );
+ m_granularity = granularity;
+
+ if ( m_list ) {
+ // resize it to the closest level of granularity
+ newsize = ( ( m_num + m_granularity - 1 ) / m_granularity ) * m_granularity;
+ if ( newsize != m_size ) {
+ Resize( newsize );
+ }
+ }
+}
+
+/*
+================
+idList<type>::Condense
+
+Resizes the array to exactly the number of elements it contains
+================
+*/
+template< class type >
+inline void idList<type>::Condense( void ) {
+ if ( m_list ) {
+ if ( m_num ) {
+ Resize( m_num );
+ } else {
+ Clear();
+ }
+ }
+}
+
+/*
+================
+idList<type>::Size
+================
+*/
+template< class type >
+inline int idList<type>::Size( void ) {
+ return m_size;
+}
+
+/*
+================
+idList<type>::Resize
+================
+*/
+template< class type >
+inline void idList<type>::Resize( int size ) {
+ type *temp;
+ int i;
+
+ assert( size > 0 );
+
+ if ( size <= 0 ) {
+ Clear();
+ return;
+ }
+
+ temp = m_list;
+ m_size = size;
+ if ( m_size < m_num ) {
+ m_num = m_size;
+ }
+
+ m_list = new type[ m_size ];
+ for( i = 0; i < m_num; i++ ) {
+ m_list[ i ] = temp[ i ];
+ }
+
+ if ( temp ) {
+ delete[] temp;
+ }
+}
+
+/*
+================
+idList<type>::operator[] const
+================
+*/
+template< class type >
+inline type idList<type>::operator[]( int index ) const {
+ assert( index >= 0 );
+ assert( index < m_num );
+
+ return m_list[ index ];
+}
+
+/*
+================
+idList<type>::operator[]
+================
+*/
+template< class type >
+inline type &idList<type>::operator[]( int index ) {
+ assert( index >= 0 );
+ assert( index < m_num );
+
+ return m_list[ index ];
+}
+
+/*
+================
+idList<type>::Append
+================
+*/
+template< class type >
+inline int idList<type>::Append( type const & obj ) {
+ if ( !m_list ) {
+ Resize( m_granularity );
+ }
+
+ if ( m_num == m_size ) {
+ Resize( m_size + m_granularity );
+ }
+
+ m_list[ m_num ] = obj;
+ m_num++;
+
+ return m_num - 1;
+}
+
+/*
+================
+idList<type>::AddUnique
+================
+*/
+template< class type >
+inline int idList<type>::AddUnique( type const & obj ) {
+ int index;
+
+ if ( !Find( obj, &index ) ) {
+ index = Append( obj );
+ }
+
+ return index;
+}
+
+/*
+================
+idList<type>::Find
+================
+*/
+template< class type >
+inline type *idList<type>::Find( type const & obj, int *index ) {
+ int i;
+
+ for( i = 0; i < m_num; i++ ) {
+ if ( m_list[ i ] == obj ) {
+ if ( index ) {
+ *index = i;
+ }
+ return &m_list[ i ];
+ }
+ }
+
+ return NULL;
+}
+
+/*
+================
+idList<type>::RemoveIndex
+================
+*/
+template< class type >
+inline bool idList<type>::RemoveIndex( int index ) {
+ int i;
+
+ if ( !m_list || !m_num ) {
+ return false;
+ }
+
+ assert( index >= 0 );
+ assert( index < m_num );
+
+ if ( ( index < 0 ) || ( index >= m_num ) ) {
+ return false;
+ }
+
+ m_num--;
+ for( i = index; i < m_num; i++ ) {
+ m_list[ i ] = m_list[ i + 1 ];
+ }
+
+ return true;
+}
+
+/*
+================
+idList<type>::Remove
+================
+*/
+template< class type >
+inline bool idList<type>::Remove( type const & obj ) {
+ int index;
+
+ if ( Find( obj, &index ) ) {
+ return RemoveIndex( index );
+ }
+
+ return false;
+}
+
+/*
+================
+idList<type>::Sort
+================
+*/
+template< class type >
+inline void idList<type>::Sort( cmp_t *compare ) {
+ if ( !m_list ) {
+ return;
+ }
+
+ qsort( ( void * )m_list, ( size_t )m_num, sizeof( type ), compare );
+}
+
+#endif /* !__UTIL_LIST_H__ */
diff --git a/q3radiant/splines/util_str.cpp b/q3radiant/splines/util_str.cpp
new file mode 100755
index 0000000..230a77f
--- /dev/null
+++ b/q3radiant/splines/util_str.cpp
@@ -0,0 +1,618 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//need to rewrite this
+
+#include "util_str.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifdef _WIN32
+#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
+#pragma warning(disable : 4710) // function 'blah' not inlined
+#endif
+
+static const int STR_ALLOC_GRAN = 20;
+
+char *idStr::tolower
+ (
+ char *s1
+ )
+
+ {
+ char *s;
+
+ s = s1;
+ while( *s )
+ {
+ *s = ::tolower( *s );
+ s++;
+ }
+
+ return s1;
+ }
+
+char *idStr::toupper
+ (
+ char *s1
+ )
+
+ {
+ char *s;
+
+ s = s1;
+ while( *s )
+ {
+ *s = ::toupper( *s );
+ s++;
+ }
+
+ return s1;
+ }
+
+int idStr::icmpn
+ (
+ const char *s1,
+ const char *s2,
+ int n
+ )
+
+ {
+ int c1;
+ int c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if ( !n-- )
+ {
+ // idStrings are equal until end point
+ return 0;
+ }
+
+ if ( c1 != c2 )
+ {
+ if ( c1 >= 'a' && c1 <= 'z' )
+ {
+ c1 -= ( 'a' - 'A' );
+ }
+
+ if ( c2 >= 'a' && c2 <= 'z' )
+ {
+ c2 -= ( 'a' - 'A' );
+ }
+
+ if ( c1 < c2 )
+ {
+ // strings less than
+ return -1;
+ }
+ else if ( c1 > c2 )
+ {
+ // strings greater than
+ return 1;
+ }
+ }
+ }
+ while( c1 );
+
+ // strings are equal
+ return 0;
+ }
+
+int idStr::icmp
+ (
+ const char *s1,
+ const char *s2
+ )
+
+ {
+ int c1;
+ int c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if ( c1 != c2 )
+ {
+ if ( c1 >= 'a' && c1 <= 'z' )
+ {
+ c1 -= ( 'a' - 'A' );
+ }
+
+ if ( c2 >= 'a' && c2 <= 'z' )
+ {
+ c2 -= ( 'a' - 'A' );
+ }
+
+ if ( c1 < c2 )
+ {
+ // strings less than
+ return -1;
+ }
+ else if ( c1 > c2 )
+ {
+ // strings greater than
+ return 1;
+ }
+ }
+ }
+ while( c1 );
+
+ // strings are equal
+ return 0;
+ }
+
+int idStr::cmpn
+ (
+ const char *s1,
+ const char *s2,
+ int n
+ )
+
+ {
+ int c1;
+ int c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if ( !n-- )
+ {
+ // strings are equal until end point
+ return 0;
+ }
+
+ if ( c1 < c2 )
+ {
+ // strings less than
+ return -1;
+ }
+ else if ( c1 > c2 )
+ {
+ // strings greater than
+ return 1;
+ }
+ }
+ while( c1 );
+
+ // strings are equal
+ return 0;
+ }
+
+int idStr::cmp
+ (
+ const char *s1,
+ const char *s2
+ )
+
+ {
+ int c1;
+ int c2;
+
+ do
+ {
+ c1 = *s1++;
+ c2 = *s2++;
+
+ if ( c1 < c2 )
+ {
+ // strings less than
+ return -1;
+ }
+ else if ( c1 > c2 )
+ {
+ // strings greater than
+ return 1;
+ }
+ }
+ while( c1 );
+
+ // strings are equal
+ return 0;
+ }
+
+/*
+============
+IsNumeric
+
+Checks a string to see if it contains only numerical values.
+============
+*/
+bool idStr::isNumeric
+ (
+ const char *str
+ )
+
+ {
+ int len;
+ int i;
+ bool dot;
+
+ if ( *str == '-' )
+ {
+ str++;
+ }
+
+ dot = false;
+ len = strlen( str );
+ for( i = 0; i < len; i++ )
+ {
+ if ( !isdigit( str[ i ] ) )
+ {
+ if ( ( str[ i ] == '.' ) && !dot )
+ {
+ dot = true;
+ continue;
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+idStr operator+
+ (
+ const idStr& a,
+ const float b
+ )
+
+ {
+ char text[ 20 ];
+
+ idStr result( a );
+
+ sprintf( text, "%f", b );
+ result.append( text );
+
+ return result;
+ }
+
+idStr operator+
+ (
+ const idStr& a,
+ const int b
+ )
+
+ {
+ char text[ 20 ];
+
+ idStr result( a );
+
+ sprintf( text, "%d", b );
+ result.append( text );
+
+ return result;
+ }
+
+idStr operator+
+ (
+ const idStr& a,
+ const unsigned b
+ )
+
+ {
+ char text[ 20 ];
+
+ idStr result( a );
+
+ sprintf( text, "%u", b );
+ result.append( text );
+
+ return result;
+ }
+
+idStr& idStr::operator+=
+ (
+ const float a
+ )
+
+ {
+ char text[ 20 ];
+
+ sprintf( text, "%f", a );
+ append( text );
+
+ return *this;
+ }
+
+idStr& idStr::operator+=
+ (
+ const int a
+ )
+
+ {
+ char text[ 20 ];
+
+ sprintf( text, "%d", a );
+ append( text );
+
+ return *this;
+ }
+
+idStr& idStr::operator+=
+ (
+ const unsigned a
+ )
+
+ {
+ char text[ 20 ];
+
+ sprintf( text, "%u", a );
+ append( text );
+
+ return *this;
+ }
+
+void idStr::CapLength
+ (
+ int newlen
+ )
+
+ {
+ assert ( m_data );
+
+ if ( length() <= newlen )
+ return;
+
+ EnsureDataWritable ();
+
+ m_data->data[newlen] = 0;
+ m_data->len = newlen;
+ }
+
+void idStr::EnsureDataWritable
+ (
+ void
+ )
+
+ {
+ assert ( m_data );
+ strdata *olddata;
+ int len;
+
+ if ( !m_data->refcount )
+ return;
+
+ olddata = m_data;
+ len = length();
+
+ m_data = new strdata;
+
+ EnsureAlloced ( len + 1, false );
+ strncpy ( m_data->data, olddata->data, len+1 );
+ m_data->len = len;
+
+ olddata->DelRef ();
+ }
+
+void idStr::EnsureAlloced (int amount, bool keepold) {
+
+ if ( !m_data ) {
+ m_data = new strdata();
+ }
+
+ // Now, let's make sure it's writable
+ EnsureDataWritable ();
+
+ char *newbuffer;
+ bool wasalloced = ( m_data->alloced != 0 );
+
+ if ( amount < m_data->alloced ) {
+ return;
+ }
+
+ assert ( amount );
+ if ( amount == 1 ) {
+ m_data->alloced = 1;
+ } else {
+ int newsize, mod;
+ mod = amount % STR_ALLOC_GRAN;
+ if ( !mod ) {
+ newsize = amount;
+ } else {
+ newsize = amount + STR_ALLOC_GRAN - mod;
+ }
+ m_data->alloced = newsize;
+ }
+
+ newbuffer = new char[m_data->alloced];
+ if ( wasalloced && keepold ) {
+ strcpy ( newbuffer, m_data->data );
+ }
+
+ if ( m_data->data ) {
+ delete [] m_data->data;
+ }
+ m_data->data = newbuffer;
+}
+
+void idStr::BackSlashesToSlashes
+ (
+ void
+ )
+
+ {
+ int i;
+
+ EnsureDataWritable ();
+
+ for ( i=0; i < m_data->len; i++ )
+ {
+ if ( m_data->data[i] == '\\' )
+ m_data->data[i] = '/';
+ }
+ }
+
+void idStr::snprintf
+ (
+ char *dst,
+ int size,
+ const char *fmt,
+ ...
+ )
+
+ {
+ char buffer[0x10000];
+ int len;
+ va_list argptr;
+
+ va_start (argptr,fmt);
+ len = vsprintf (buffer,fmt,argptr);
+ va_end (argptr);
+
+ assert ( len < size );
+
+ strncpy (dst, buffer, size-1);
+ }
+
+#ifdef _WIN32
+#pragma warning(disable : 4189) // local variable is initialized but not referenced
+#endif
+
+/*
+=================
+TestStringClass
+
+This is a fairly rigorous test of the idStr class's functionality.
+Because of the fairly global and subtle ramifications of a bug occuring
+in this class, it should be run after any changes to the class.
+Add more tests as functionality is changed. Tests should include
+any possible bounds violation and NULL data tests.
+=================
+*/
+void TestStringClass
+ (
+ void
+ )
+
+ {
+ char ch; // ch == ?
+ idStr *t; // t == ?
+ idStr a; // a.len == 0, a.data == "\0"
+ idStr b; // b.len == 0, b.data == "\0"
+ idStr c( "test" ); // c.len == 4, c.data == "test\0"
+ idStr d( c ); // d.len == 4, d.data == "test\0"
+ idStr e( reinterpret_cast<const char *>(NULL) );
+ // e.len == 0, e.data == "\0" ASSERT!
+ int i; // i == ?
+
+ i = a.length(); // i == 0
+ i = c.length(); // i == 4
+
+ const char *s1 = a.c_str(); // s1 == "\0"
+ const char *s2 = c.c_str(); // s2 == "test\0"
+
+ t = new idStr(); // t->len == 0, t->data == "\0"
+ delete t; // t == ?
+
+ b = "test"; // b.len == 4, b.data == "test\0"
+ t = new idStr( "test" ); // t->len == 4, t->data == "test\0"
+ delete t; // t == ?
+
+ a = c; // a.len == 4, a.data == "test\0"
+// a = "";
+ a = NULL; // a.len == 0, a.data == "\0" ASSERT!
+ a = c + d; // a.len == 8, a.data == "testtest\0"
+ a = c + "wow"; // a.len == 7, a.data == "testwow\0"
+ a = c + reinterpret_cast<const char *>(NULL);
+ // a.len == 4, a.data == "test\0" ASSERT!
+ a = "this" + d; // a.len == 8, a.data == "thistest\0"
+ a = reinterpret_cast<const char *>(NULL) + d;
+ // a.len == 4, a.data == "test\0" ASSERT!
+ a += c; // a.len == 8, a.data == "testtest\0"
+ a += "wow"; // a.len == 11, a.data == "testtestwow\0"
+ a += reinterpret_cast<const char *>(NULL);
+ // a.len == 11, a.data == "testtestwow\0" ASSERT!
+
+ a = "test"; // a.len == 4, a.data == "test\0"
+ ch = a[ 0 ]; // ch == 't'
+ ch = a[ -1 ]; // ch == 0 ASSERT!
+ ch = a[ 1000 ]; // ch == 0 ASSERT!
+ ch = a[ 0 ]; // ch == 't'
+ ch = a[ 1 ]; // ch == 'e'
+ ch = a[ 2 ]; // ch == 's'
+ ch = a[ 3 ]; // ch == 't'
+ ch = a[ 4 ]; // ch == '\0' ASSERT!
+ ch = a[ 5 ]; // ch == '\0' ASSERT!
+
+ a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0"
+ a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT!
+ a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0"
+ a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0"
+ a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0"
+ a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0"
+ a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT!
+ a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT!
+ a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT!
+
+ a = "test"; // a.len == 4, a.data == "test\0"
+ b = "no"; // b.len == 2, b.data == "no\0"
+
+ i = ( a == b ); // i == 0
+ i = ( a == c ); // i == 1
+
+ i = ( a == "blow" ); // i == 0
+ i = ( a == "test" ); // i == 1
+ i = ( a == NULL ); // i == 0 ASSERT!
+
+ i = ( "test" == b ); // i == 0
+ i = ( "test" == a ); // i == 1
+ i = ( NULL == a ); // i == 0 ASSERT!
+
+ i = ( a != b ); // i == 1
+ i = ( a != c ); // i == 0
+
+ i = ( a != "blow" ); // i == 1
+ i = ( a != "test" ); // i == 0
+ i = ( a != NULL ); // i == 1 ASSERT!
+
+ i = ( "test" != b ); // i == 1
+ i = ( "test" != a ); // i == 0
+ i = ( NULL != a ); // i == 1 ASSERT!
+
+ a = "test"; // a.data == "test"
+ b = a; // b.data == "test"
+
+ a = "not"; // a.data == "not", b.data == "test"
+
+ a = b; // a.data == b.data == "test"
+
+ a += b; // a.data == "testtest", b.data = "test"
+
+ a = b;
+
+ a[1] = '1'; // a.data = "t1st", b.data = "test"
+ }
+
+#ifdef _WIN32
+#pragma warning(default : 4189) // local variable is initialized but not referenced
+#pragma warning(disable : 4514) // unreferenced inline function has been removed
+#endif
diff --git a/q3radiant/splines/util_str.h b/q3radiant/splines/util_str.h
new file mode 100755
index 0000000..896bf89
--- /dev/null
+++ b/q3radiant/splines/util_str.h
@@ -0,0 +1,817 @@
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake III Arena source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+//need to rewrite this
+
+#ifndef __UTIL_STR_H__
+#define __UTIL_STR_H__
+
+#include <assert.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef _WIN32
+#pragma warning(disable : 4710) // function 'blah' not inlined
+#endif
+
+void TestStringClass ();
+
+class strdata
+ {
+ public:
+ strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {}
+ ~strdata ()
+ {
+ if ( data )
+ delete [] data;
+ }
+
+ void AddRef () { refcount++; }
+ bool DelRef () // True if killed
+ {
+ refcount--;
+ if ( refcount < 0 )
+ {
+ delete this;
+ return true;
+ }
+
+ return false;
+ }
+
+ int len;
+ int refcount;
+ char *data;
+ int alloced;
+ };
+
+class idStr {
+protected:
+ strdata *m_data;
+ void EnsureAlloced ( int, bool keepold = true );
+ void EnsureDataWritable ();
+
+public:
+ ~idStr();
+ idStr();
+ idStr( const char *text );
+ idStr( const idStr& string );
+ idStr( const idStr string, int start, int end );
+ idStr( const char ch );
+ idStr( const int num );
+ idStr( const float num );
+ idStr( const unsigned num );
+ int length( void ) const;
+ int allocated( void ) const;
+ const char * c_str( void ) const;
+
+ void append( const char *text );
+ void append( const idStr& text );
+ char operator[]( int index ) const;
+ char& operator[]( int index );
+
+ void operator=( const idStr& text );
+ void operator=( const char *text );
+
+ friend idStr operator+( const idStr& a, const idStr& b );
+ friend idStr operator+( const idStr& a, const char *b );
+ friend idStr operator+( const char *a, const idStr& b );
+
+ friend idStr operator+( const idStr& a, const float b );
+ friend idStr operator+( const idStr& a, const int b );
+ friend idStr operator+( const idStr& a, const unsigned b );
+ friend idStr operator+( const idStr& a, const bool b );
+ friend idStr operator+( const idStr& a, const char b );
+
+ idStr& operator+=( const idStr& a );
+ idStr& operator+=( const char *a );
+ idStr& operator+=( const float a );
+ idStr& operator+=( const char a );
+ idStr& operator+=( const int a );
+ idStr& operator+=( const unsigned a );
+ idStr& operator+=( const bool a );
+
+ friend bool operator==( const idStr& a, const idStr& b );
+ friend bool operator==( const idStr& a, const char *b );
+ friend bool operator==( const char *a, const idStr& b );
+
+ friend bool operator!=( const idStr& a, const idStr& b );
+ friend bool operator!=( const idStr& a, const char *b );
+ friend bool operator!=( const char *a, const idStr& b );
+
+ operator const char * () const;
+ operator const char * ();
+
+ int icmpn( const char *text, int n ) const;
+ int icmpn( const idStr& text, int n ) const;
+ int icmp( const char *text ) const;
+ int icmp( const idStr& text ) const;
+ int cmpn( const char *text, int n ) const;
+ int cmpn( const idStr& text, int n ) const;
+ int cmp( const char *text ) const;
+ int cmp( const idStr& text ) const;
+
+ void tolower( void );
+ void toupper( void );
+
+ static char *tolower( char *s1 );
+ static char *toupper( char *s1 );
+
+ static int icmpn( const char *s1, const char *s2, int n );
+ static int icmp( const char *s1, const char *s2 );
+ static int cmpn( const char *s1, const char *s2, int n );
+ static int cmp( const char *s1, const char *s2 );
+
+ static void snprintf ( char *dst, int size, const char *fmt, ... );
+
+ static bool isNumeric( const char *str );
+ bool isNumeric( void ) const;
+
+ void CapLength ( int );
+
+ void BackSlashesToSlashes ();
+
+};
+
+inline idStr::~idStr()
+ {
+ if ( m_data )
+ {
+ m_data->DelRef ();
+ m_data = NULL;
+ }
+ }
+
+inline idStr::idStr() : m_data ( NULL )
+ {
+ EnsureAlloced ( 1 );
+ m_data->data[ 0 ] = 0;
+ }
+
+inline idStr::idStr
+ (
+ const char *text
+ ) : m_data ( NULL )
+
+ {
+ int len;
+
+ assert( text );
+
+ if ( text )
+ {
+ len = strlen( text );
+ EnsureAlloced ( len + 1 );
+ strcpy( m_data->data, text );
+ m_data->len = len;
+ }
+ else
+ {
+ EnsureAlloced ( 1 );
+ m_data->data[ 0 ] = 0;
+ m_data->len = 0;
+ }
+ }
+
+inline idStr::idStr
+ (
+ const idStr& text
+ ) : m_data ( NULL )
+
+ {
+ m_data = text.m_data;
+ m_data->AddRef ();
+ }
+
+inline idStr::idStr
+ (
+ const idStr text,
+ int start,
+ int end
+ ) : m_data ( NULL )
+
+ {
+ int i;
+ int len;
+
+ if ( end > text.length() )
+ {
+ end = text.length();
+ }
+
+ if ( start > text.length() )
+ {
+ start = text.length();
+ }
+
+ len = end - start;
+ if ( len < 0 )
+ {
+ len = 0;
+ }
+
+ EnsureAlloced ( len + 1 );
+
+ for( i = 0; i < len; i++ )
+ {
+ m_data->data[ i ] = text[ start + i ];
+ }
+
+ m_data->data[ len ] = 0;
+ m_data->len = len;
+ }
+
+inline idStr::idStr
+ (
+ const char ch
+ ) : m_data ( NULL )
+
+ {
+ EnsureAlloced ( 2 );
+
+ m_data->data[ 0 ] = ch;
+ m_data->data[ 1 ] = 0;
+ m_data->len = 1;
+ }
+
+inline idStr::idStr
+ (
+ const float num
+ ) : m_data ( NULL )
+
+ {
+ char text[ 32 ];
+ int len;
+
+ sprintf( text, "%.3f", num );
+ len = strlen( text );
+ EnsureAlloced( len + 1 );
+ strcpy( m_data->data, text );
+ m_data->len = len;
+ }
+
+inline idStr::idStr
+ (
+ const int num
+ ) : m_data ( NULL )
+
+ {
+ char text[ 32 ];
+ int len;
+
+ sprintf( text, "%d", num );
+ len = strlen( text );
+ EnsureAlloced( len + 1 );
+ strcpy( m_data->data, text );
+ m_data->len = len;
+ }
+
+inline idStr::idStr
+ (
+ const unsigned num
+ ) : m_data ( NULL )
+
+ {
+ char text[ 32 ];
+ int len;
+
+ sprintf( text, "%u", num );
+ len = strlen( text );
+ EnsureAlloced( len + 1 );
+ strcpy( m_data->data, text );
+ m_data->len = len;
+ }
+
+inline int idStr::length( void ) const
+ {
+ return ( m_data != NULL ) ? m_data->len : 0;
+ }
+
+inline int idStr::allocated( void ) const
+ {
+ return ( m_data != NULL ) ? m_data->alloced + sizeof( *m_data ) : 0;
+ }
+
+inline const char *idStr::c_str( void ) const
+ {
+ assert( m_data );
+
+ return m_data->data;
+ }
+
+inline void idStr::append
+ (
+ const char *text
+ )
+
+ {
+ int len;
+
+ assert( text );
+
+ if ( text )
+ {
+ len = length() + strlen( text );
+ EnsureAlloced( len + 1 );
+
+ strcat( m_data->data, text );
+ m_data->len = len;
+ }
+ }
+
+inline void idStr::append
+ (
+ const idStr& text
+ )
+
+ {
+ int len;
+
+ len = length() + text.length();
+ EnsureAlloced ( len + 1 );
+
+ strcat ( m_data->data, text.c_str () );
+ m_data->len = len;
+ }
+
+inline char idStr::operator[]( int index ) const
+ {
+ assert ( m_data );
+
+ if ( !m_data )
+ return 0;
+
+ // don't include the '/0' in the test, because technically, it's out of bounds
+ assert( ( index >= 0 ) && ( index < m_data->len ) );
+
+ // In release mode, give them a null character
+ // don't include the '/0' in the test, because technically, it's out of bounds
+ if ( ( index < 0 ) || ( index >= m_data->len ) )
+ {
+ return 0;
+ }
+
+ return m_data->data[ index ];
+ }
+
+inline char& idStr::operator[]
+ (
+ int index
+ )
+
+ {
+ // Used for result for invalid indices
+ static char dummy = 0;
+ assert ( m_data );
+
+ // We don't know if they'll write to it or not
+ // if it's not a const object
+ EnsureDataWritable ();
+
+ if ( !m_data )
+ return dummy;
+
+ // don't include the '/0' in the test, because technically, it's out of bounds
+ assert( ( index >= 0 ) && ( index < m_data->len ) );
+
+ // In release mode, let them change a safe variable
+ // don't include the '/0' in the test, because technically, it's out of bounds
+ if ( ( index < 0 ) || ( index >= m_data->len ) )
+ {
+ return dummy;
+ }
+
+ return m_data->data[ index ];
+ }
+
+inline void idStr::operator=
+ (
+ const idStr& text
+ )
+
+ {
+ // adding the reference before deleting our current reference prevents
+ // us from deleting our string if we are copying from ourself
+ text.m_data->AddRef();
+ m_data->DelRef();
+ m_data = text.m_data;
+ }
+
+inline void idStr::operator=
+ (
+ const char *text
+ )
+
+ {
+ int len;
+
+ assert( text );
+
+ if ( !text )
+ {
+ // safe behaviour if NULL
+ EnsureAlloced ( 1, false );
+ m_data->data[0] = 0;
+ m_data->len = 0;
+ return;
+ }
+
+ if ( !m_data )
+ {
+ len = strlen ( text );
+ EnsureAlloced( len + 1, false );
+ strcpy ( m_data->data, text );
+ m_data->len = len;
+ return;
+ }
+
+ if ( text == m_data->data )
+ return; // Copying same thing. Punt.
+
+ // If we alias and I don't do this, I could corrupt other strings... This
+ // will get called with EnsureAlloced anyway
+ EnsureDataWritable ();
+
+ // Now we need to check if we're aliasing..
+ if ( text >= m_data->data && text <= m_data->data + m_data->len )
+ {
+ // Great, we're aliasing. We're copying from inside ourselves.
+ // This means that I don't have to ensure that anything is alloced,
+ // though I'll assert just in case.
+ int diff = text - m_data->data;
+ int i;
+
+ assert ( strlen ( text ) < (unsigned) m_data->len );
+
+ for ( i = 0; text[i]; i++ )
+ {
+ m_data->data[i] = text[i];
+ }
+
+ m_data->data[i] = 0;
+
+ m_data->len -= diff;
+
+ return;
+ }
+
+ len = strlen( text );
+ EnsureAlloced ( len + 1, false );
+ strcpy( m_data->data, text );
+ m_data->len = len;
+ }
+
+inline idStr operator+
+ (
+ const idStr& a,
+ const idStr& b
+ )
+
+ {
+ idStr result( a );
+
+ result.append( b );
+
+ return result;
+ }
+
+inline idStr operator+
+ (
+ const idStr& a,
+ const char *b
+ )
+
+ {
+ idStr result( a );
+
+ result.append( b );
+
+ return result;
+ }
+
+inline idStr operator+
+ (
+ const char *a,
+ const idStr& b
+ )
+
+ {
+ idStr result( a );
+
+ result.append( b );
+
+ return result;
+ }
+
+inline idStr operator+
+ (
+ const idStr& a,
+ const bool b
+ )
+
+ {
+ idStr result( a );
+
+ result.append( b ? "true" : "false" );
+
+ return result;
+ }
+
+inline idStr operator+
+ (
+ const idStr& a,
+ const char b
+ )
+
+ {
+ char text[ 2 ];
+
+ text[ 0 ] = b;
+ text[ 1 ] = 0;
+
+ return a + text;
+ }
+
+inline idStr& idStr::operator+=
+ (
+ const idStr& a
+ )
+
+ {
+ append( a );
+ return *this;
+ }
+
+inline idStr& idStr::operator+=
+ (
+ const char *a
+ )
+
+ {
+ append( a );
+ return *this;
+ }
+
+inline idStr& idStr::operator+=
+ (
+ const char a
+ )
+
+ {
+ char text[ 2 ];
+
+ text[ 0 ] = a;
+ text[ 1 ] = 0;
+ append( text );
+
+ return *this;
+ }
+
+inline idStr& idStr::operator+=
+ (
+ const bool a
+ )
+
+ {
+ append( a ? "true" : "false" );
+ return *this;
+ }
+
+inline bool operator==
+ (
+ const idStr& a,
+ const idStr& b
+ )
+
+ {
+ return ( !strcmp( a.c_str(), b.c_str() ) );
+ }
+
+inline bool operator==
+ (
+ const idStr& a,
+ const char *b
+ )
+
+ {
+ assert( b );
+ if ( !b )
+ {
+ return false;
+ }
+ return ( !strcmp( a.c_str(), b ) );
+ }
+
+inline bool operator==
+ (
+ const char *a,
+ const idStr& b
+ )
+
+ {
+ assert( a );
+ if ( !a )
+ {
+ return false;
+ }
+ return ( !strcmp( a, b.c_str() ) );
+ }
+
+inline bool operator!=
+ (
+ const idStr& a,
+ const idStr& b
+ )
+
+ {
+ return !( a == b );
+ }
+
+inline bool operator!=
+ (
+ const idStr& a,
+ const char *b
+ )
+
+ {
+ return !( a == b );
+ }
+
+inline bool operator!=
+ (
+ const char *a,
+ const idStr& b
+ )
+
+ {
+ return !( a == b );
+ }
+
+inline int idStr::icmpn
+ (
+ const char *text,
+ int n
+ ) const
+
+ {
+ assert( m_data );
+ assert( text );
+
+ return idStr::icmpn( m_data->data, text, n );
+ }
+
+inline int idStr::icmpn
+ (
+ const idStr& text,
+ int n
+ ) const
+
+ {
+ assert( m_data );
+ assert( text.m_data );
+
+ return idStr::icmpn( m_data->data, text.m_data->data, n );
+ }
+
+inline int idStr::icmp
+ (
+ const char *text
+ ) const
+
+ {
+ assert( m_data );
+ assert( text );
+
+ return idStr::icmp( m_data->data, text );
+ }
+
+inline int idStr::icmp
+ (
+ const idStr& text
+ ) const
+
+ {
+ assert( c_str () );
+ assert( text.c_str () );
+
+ return idStr::icmp( c_str () , text.c_str () );
+ }
+
+inline int idStr::cmp
+ (
+ const char *text
+ ) const
+
+ {
+ assert( m_data );
+ assert( text );
+
+ return idStr::cmp( m_data->data, text );
+ }
+
+inline int idStr::cmp
+ (
+ const idStr& text
+ ) const
+
+ {
+ assert( c_str () );
+ assert( text.c_str () );
+
+ return idStr::cmp( c_str () , text.c_str () );
+ }
+
+inline int idStr::cmpn
+ (
+ const char *text,
+ int n
+ ) const
+
+ {
+ assert( c_str () );
+ assert( text );
+
+ return idStr::cmpn( c_str () , text, n );
+ }
+
+inline int idStr::cmpn
+ (
+ const idStr& text,
+ int n
+ ) const
+
+ {
+ assert( c_str () );
+ assert( text.c_str () );
+
+ return idStr::cmpn( c_str () , text.c_str () , n );
+ }
+
+inline void idStr::tolower
+ (
+ void
+ )
+
+ {
+ assert( m_data );
+
+ EnsureDataWritable ();
+
+ idStr::tolower( m_data->data );
+ }
+
+inline void idStr::toupper
+ (
+ void
+ )
+
+ {
+ assert( m_data );
+
+ EnsureDataWritable ();
+
+ idStr::toupper( m_data->data );
+ }
+
+inline bool idStr::isNumeric
+ (
+ void
+ ) const
+
+ {
+ assert( m_data );
+ return idStr::isNumeric( m_data->data );
+ }
+
+inline idStr::operator const char *() {
+ return c_str();
+}
+
+inline idStr::operator const char *
+ (
+ void
+ ) const
+
+ {
+ return c_str ();
+ }
+
+#endif \ No newline at end of file