mirror of
https://github.com/UberGames/GtkRadiant.git
synced 2024-11-29 15:11:54 +00:00
1448 lines
35 KiB
C++
1448 lines
35 KiB
C++
/*
|
|
Copyright (C) 1999-2007 id Software, Inc. and contributors.
|
|
For a list of contributors, see the accompanying CONTRIBUTORS file.
|
|
|
|
This file is part of GtkRadiant.
|
|
|
|
GtkRadiant 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.
|
|
|
|
GtkRadiant 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 GtkRadiant; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#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 );
|
|
void Cbuf_AddText( const char *text );
|
|
void Cbuf_Execute( void );
|
|
}
|
|
|
|
float Q_fabs( float f ) {
|
|
int tmp = *( int * ) &f;
|
|
tmp &= 0x7FFFFFFF;
|
|
return *( float * ) &tmp;
|
|
}
|
|
|
|
// (SA) making a list of cameras so I can use
|
|
// the splines as targets for other things.
|
|
// Certainly better ways to do this, but this lets
|
|
// me get underway quickly with ents that need spline
|
|
// targets.
|
|
#define MAX_CAMERAS 64
|
|
|
|
idCameraDef camera[MAX_CAMERAS];
|
|
|
|
extern "C" {
|
|
qboolean loadCamera( int camNum, const char *name ) {
|
|
if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
|
|
return qfalse;
|
|
}
|
|
camera[camNum].clear();
|
|
return (qboolean)camera[camNum].load( name );
|
|
}
|
|
|
|
qboolean getCameraInfo( int camNum, int time, float *origin, float *angles, float *fov ) {
|
|
idVec3 dir, org;
|
|
if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
|
|
return qfalse;
|
|
}
|
|
org[0] = origin[0];
|
|
org[1] = origin[1];
|
|
org[2] = origin[2];
|
|
if ( camera[camNum].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 camNum, int time ) {
|
|
if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
|
|
return;
|
|
}
|
|
camera[camNum].startCamera( time );
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//#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 idSplineList::zero( 0,0,0 );
|
|
|
|
void glLabeledPoint( idVec3 &color, idVec3 &point, float size, const char *label ) {
|
|
qglColor3fv( color );
|
|
qglPointSize( size );
|
|
qglBegin( GL_POINTS );
|
|
qglVertex3fv( point );
|
|
qglEnd();
|
|
idVec3 v = point;
|
|
v.x += 1;
|
|
v.y += 1;
|
|
v.z += 1;
|
|
qglRasterPos3fv( v );
|
|
qglCallLists( strlen( label ), GL_UNSIGNED_BYTE, label );
|
|
}
|
|
|
|
|
|
void glBox( idVec3 &color, idVec3 &point, float size ) {
|
|
idVec3 mins( point );
|
|
idVec3 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 &color, const idVec3 &start, const idVec3 &end );
|
|
|
|
void debugLine( idVec3 &color, float x, float y, float z, float x2, float y2, float z2 ) {
|
|
idVec3 from( x, y, z );
|
|
idVec3 to( x2, y2, z2 );
|
|
//D_DebugLine(color, from, to);
|
|
}
|
|
|
|
void idSplineList::addToRenderer() {
|
|
|
|
if ( controlPoints.Num() == 0 ) {
|
|
return;
|
|
}
|
|
|
|
idVec3 mins, maxs;
|
|
idVec3 yellow( 1.0, 1.0, 0 );
|
|
idVec3 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 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( 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;
|
|
idVec4 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() {
|
|
|
|
// FIXME: save dist and return
|
|
//
|
|
if ( controlPoints.Num() == 0 ) {
|
|
return 0.0;
|
|
}
|
|
|
|
if ( dirty ) {
|
|
buildSpline();
|
|
}
|
|
|
|
float dist = 0.0;
|
|
idVec3 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( bt );
|
|
double dist = totalDistance();
|
|
double distSoFar = 0.0;
|
|
idVec3 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();
|
|
double 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 &move ) {
|
|
if ( selected ) {
|
|
dirty = true;
|
|
VectorAdd( *selected, move, *selected );
|
|
}
|
|
}
|
|
|
|
|
|
void idSplineList::setSelectedPoint( idVec3 *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 *idSplineList::getPosition( long t ) {
|
|
static idVec3 interpolatedPos;
|
|
|
|
int count = splineTime.Num();
|
|
if ( count == 0 ) {
|
|
return &zero;
|
|
}
|
|
|
|
// Com_Printf("Time: %d\n", t);
|
|
assert( splineTime.Num() == splinePoints.Num() );
|
|
|
|
while ( activeSegment < count ) {
|
|
if ( splineTime[activeSegment] >= t ) {
|
|
if ( activeSegment > 0 && activeSegment < count - 1 ) {
|
|
double timeHi = splineTime[activeSegment + 1];
|
|
double timeLo = splineTime[activeSegment - 1];
|
|
double percent = ( timeHi - t ) / ( timeHi - timeLo );
|
|
// pick two bounding points
|
|
idVec3 v1 = *splinePoints[activeSegment - 1];
|
|
idVec3 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 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 &origin, idVec3 &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 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 &origin, idVec3 &direction, float *fv ) {
|
|
|
|
char buff[1024];
|
|
|
|
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 ) {
|
|
memset( buff, 0, sizeof( buff ) );
|
|
strcpy( buff, events[i]->getParam() );
|
|
const char *param1 = strtok( buff, " \t,\0" );
|
|
const char *param2 = strtok( NULL, " \t,\0" );
|
|
float len = ( param2 ) ? atof( param2 ) : 0;
|
|
float newfov = ( param1 ) ? atof( param1 ) : 90;
|
|
fov.reset( fov.getFOV( time ), newfov, time, len );
|
|
//*fv = fov = atof(events[i]->getParam());
|
|
}
|
|
else if ( events[i]->getType() == idCameraEvent::EVENT_FADEIN ) {
|
|
float time = atof( events[i]->getParam() );
|
|
Cbuf_AddText( va( "fade 0 0 0 0 %f", time ) );
|
|
Cbuf_Execute();
|
|
}
|
|
else if ( events[i]->getType() == idCameraEvent::EVENT_FADEOUT ) {
|
|
float time = atof( events[i]->getParam() );
|
|
Cbuf_AddText( va( "fade 0 0 0 255 %f", time ) );
|
|
Cbuf_Execute();
|
|
}
|
|
else if ( events[i]->getType() == idCameraEvent::EVENT_CAMERA ) {
|
|
memset( buff, 0, sizeof( buff ) );
|
|
strcpy( buff, events[i]->getParam() );
|
|
const char *param1 = strtok( buff, " \t,\0" );
|
|
const char *param2 = strtok( NULL, " \t,\0" );
|
|
|
|
if ( param2 ) {
|
|
loadCamera( atoi( param1 ), va( "cameras/%s.camera", param2 ) );
|
|
startCamera( time );
|
|
}
|
|
else {
|
|
loadCamera( 0, va( "cameras/%s.camera", events[i]->getParam() ) );
|
|
startCamera( time );
|
|
}
|
|
return true;
|
|
}
|
|
else if ( events[i]->getType() == idCameraEvent::EVENT_STOP ) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
origin = *cameraPosition->getPosition( time );
|
|
|
|
*fv = fov.getFOV( time );
|
|
|
|
idVec3 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 {
|
|
if ( getActiveTarget()->numPoints() > 0 ) {
|
|
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;
|
|
idList<float> waits;
|
|
idList<int> targets;
|
|
|
|
totalTime = baseTime;
|
|
cameraPosition->setTime( (long)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++ ) {
|
|
events[i]->setTriggered( false );
|
|
switch ( events[i]->getType() ) {
|
|
case idCameraEvent::EVENT_TARGET: {
|
|
targets.Append( i );
|
|
break;
|
|
}
|
|
case idCameraEvent::EVENT_FEATHER: {
|
|
long startTime = 0;
|
|
float speed = 0;
|
|
long loopTime = 10;
|
|
float stepGoal = cameraPosition->getBaseVelocity() / ( 1000 / loopTime );
|
|
while ( startTime <= 1000 ) {
|
|
cameraPosition->addVelocity( startTime, loopTime, speed );
|
|
speed += stepGoal;
|
|
if ( speed > cameraPosition->getBaseVelocity() ) {
|
|
speed = cameraPosition->getBaseVelocity();
|
|
}
|
|
startTime += loopTime;
|
|
}
|
|
|
|
startTime = (long)( totalTime * 1000 - 1000 );
|
|
long endTime = startTime + 1000;
|
|
speed = cameraPosition->getBaseVelocity();
|
|
while ( startTime < endTime ) {
|
|
speed -= stepGoal;
|
|
if ( speed < 0 ) {
|
|
speed = 0;
|
|
}
|
|
cameraPosition->addVelocity( startTime, loopTime, speed );
|
|
startTime += loopTime;
|
|
}
|
|
break;
|
|
|
|
}
|
|
case idCameraEvent::EVENT_WAIT: {
|
|
waits.Append( atof( events[i]->getParam() ) );
|
|
|
|
//FIXME: this is quite hacky for Wolf E3, accel and decel needs
|
|
// do be parameter based etc..
|
|
long startTime = events[i]->getTime() - 1000;
|
|
if ( startTime < 0 ) {
|
|
startTime = 0;
|
|
}
|
|
float speed = cameraPosition->getBaseVelocity();
|
|
long loopTime = 10;
|
|
float steps = speed / ( ( events[i]->getTime() - startTime ) / loopTime );
|
|
while ( startTime <= events[i]->getTime() - loopTime ) {
|
|
cameraPosition->addVelocity( startTime, loopTime, speed );
|
|
speed -= steps;
|
|
startTime += loopTime;
|
|
}
|
|
cameraPosition->addVelocity( events[i]->getTime(), (long)atof( events[i]->getParam() ) * 1000, 0 );
|
|
|
|
startTime = (long)( events[i]->getTime() + atof( events[i]->getParam() ) * 1000 );
|
|
long endTime = startTime + 1000;
|
|
speed = 0;
|
|
while ( startTime <= endTime ) {
|
|
cameraPosition->addVelocity( startTime, loopTime, speed );
|
|
speed += steps;
|
|
startTime += loopTime;
|
|
}
|
|
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 = (long)( 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 ) {
|
|
cameraPosition->clearVelocities();
|
|
cameraPosition->start( t );
|
|
buildCamera();
|
|
fov.reset( 90, 90, t, 0 );
|
|
//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 );
|
|
}
|
|
else if ( Q_stricmp( token, "camera_fixed" ) == 0 ) {
|
|
cameraPosition = new idFixedPosition();
|
|
cameraPosition->parse( text );
|
|
}
|
|
else if ( Q_stricmp( token, "camera_interpolated" ) == 0 ) {
|
|
cameraPosition = new idInterpolatedPosition();
|
|
cameraPosition->parse( text );
|
|
}
|
|
else if ( Q_stricmp( token, "camera_spline" ) == 0 ) {
|
|
cameraPosition = new idSplinePosition();
|
|
cameraPosition->parse( text );
|
|
}
|
|
else if ( Q_stricmp( token, "target_fixed" ) == 0 ) {
|
|
idFixedPosition *pos = new idFixedPosition();
|
|
pos->parse( text );
|
|
targetPositions.Append( pos );
|
|
}
|
|
else if ( Q_stricmp( token, "target_interpolated" ) == 0 ) {
|
|
idInterpolatedPosition *pos = new idInterpolatedPosition();
|
|
pos->parse( text );
|
|
targetPositions.Append( pos );
|
|
}
|
|
else if ( Q_stricmp( token, "target_spline" ) == 0 ) {
|
|
idSplinePosition *pos = new idSplinePosition();
|
|
pos->parse( text );
|
|
targetPositions.Append( pos );
|
|
}
|
|
else if ( Q_stricmp( token, "fov" ) == 0 ) {
|
|
fov.parse( text );
|
|
}
|
|
else if ( Q_stricmp( token, "event" ) == 0 ) {
|
|
idCameraEvent *event = new idCameraEvent();
|
|
event->parse( text );
|
|
addEvent( event );
|
|
}
|
|
|
|
|
|
} while ( 1 );
|
|
|
|
if ( !cameraPosition ) {
|
|
Com_Printf( "no camera position specified\n" );
|
|
// prevent a crash later on
|
|
cameraPosition = new idFixedPosition();
|
|
}
|
|
|
|
Com_UngetToken();
|
|
Com_MatchToken( text, "}" );
|
|
|
|
}
|
|
|
|
bool idCameraDef::load( const char *filename ) {
|
|
char *buf;
|
|
const char *buf_p;
|
|
|
|
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();
|
|
}
|
|
|
|
void idCameraDef::removeEvent( int index ) {
|
|
events.RemoveIndex( index );
|
|
buildCamera();
|
|
}
|
|
|
|
|
|
const char *idCameraEvent::eventStr[] = {
|
|
"NA",
|
|
"WAIT",
|
|
"TARGETWAIT",
|
|
"SPEED",
|
|
"TARGET",
|
|
"SNAPTARGET",
|
|
"FOV",
|
|
"CMD",
|
|
"TRIGGER",
|
|
"STOP",
|
|
"CAMERA",
|
|
"FADEOUT",
|
|
"FADEIN",
|
|
"FEATHER"
|
|
};
|
|
|
|
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 *idInterpolatedPosition::getPosition( long t ) {
|
|
static idVec3 interpolatedPos;
|
|
|
|
float velocity = getVelocity( t );
|
|
float timePassed = t - lastTime;
|
|
lastTime = t;
|
|
|
|
// convert to seconds
|
|
timePassed /= 1000;
|
|
|
|
float distToTravel = timePassed * velocity;
|
|
|
|
idVec3 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 v1 = startPos;
|
|
idVec3 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 ) {
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
|
|
const idVec3 *idSplinePosition::getPosition( long t ) {
|
|
static idVec3 interpolatedPos;
|
|
|
|
float velocity = getVelocity( t );
|
|
float timePassed = t - lastTime;
|
|
lastTime = t;
|
|
|
|
// convert to seconds
|
|
timePassed /= 1000;
|
|
|
|
float distToTravel = timePassed * velocity;
|
|
|
|
distSoFar += distToTravel;
|
|
double tempDistance = target.totalDistance();
|
|
|
|
double percent = (double)( distSoFar ) / tempDistance;
|
|
|
|
double targetDistance = percent * tempDistance;
|
|
tempDistance = 0;
|
|
|
|
double lastDistance1,lastDistance2;
|
|
lastDistance1 = lastDistance2 = 0;
|
|
idVec3 temp;
|
|
int count = target.numSegments();
|
|
int i;
|
|
for ( i = 1; i < count; i++ ) {
|
|
temp = *target.getSegmentPoint( i - 1 );
|
|
temp -= *target.getSegmentPoint( i );
|
|
tempDistance += temp.Length();
|
|
if ( i & 1 ) {
|
|
lastDistance1 = tempDistance;
|
|
}
|
|
else {
|
|
lastDistance2 = tempDistance;
|
|
}
|
|
if ( tempDistance >= targetDistance ) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( i >= count - 1 ) {
|
|
interpolatedPos = *target.getSegmentPoint( i - 1 );
|
|
}
|
|
else {
|
|
#if 0
|
|
double timeHi = target.getSegmentTime( i + 1 );
|
|
double timeLo = target.getSegmentTime( i - 1 );
|
|
double percent = ( timeHi - t ) / ( timeHi - timeLo );
|
|
idVec3 v1 = *target.getSegmentPoint( i - 1 );
|
|
idVec3 v2 = *target.getSegmentPoint( i + 1 );
|
|
v2 *= ( 1.0 - percent );
|
|
v1 *= percent;
|
|
v2 += v1;
|
|
interpolatedPos = v2;
|
|
#else
|
|
if ( lastDistance1 > lastDistance2 ) {
|
|
double d = lastDistance2;
|
|
lastDistance2 = lastDistance1;
|
|
lastDistance1 = d;
|
|
}
|
|
|
|
idVec3 v1 = *target.getSegmentPoint( i - 1 );
|
|
idVec3 v2 = *target.getSegmentPoint( i );
|
|
double percent = ( lastDistance2 - targetDistance ) / ( lastDistance2 - lastDistance1 );
|
|
v2 *= ( 1.0 - percent );
|
|
v1 *= percent;
|
|
v2 += v1;
|
|
interpolatedPos = v2;
|
|
#endif
|
|
}
|
|
return &interpolatedPos;
|
|
|
|
}
|