2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 int FS_Write( const void *buffer, int len, fileHandle_t h );
27 int FS_ReadFile( const char *qpath, void **buffer );
28 void FS_FreeFile( void *buffer );
29 fileHandle_t FS_FOpenFileWrite( const char *filename );
30 void FS_FCloseFile( fileHandle_t f );
31 void Cbuf_AddText( const char *text );
32 void Cbuf_Execute( void );
35 float Q_fabs( float f ) {
36 int tmp = *( int * ) &f;
38 return *( float * ) &tmp;
41 // (SA) making a list of cameras so I can use
42 // the splines as targets for other things.
43 // Certainly better ways to do this, but this lets
44 // me get underway quickly with ents that need spline
46 #define MAX_CAMERAS 64
48 idCameraDef camera[MAX_CAMERAS];
51 qboolean loadCamera( int camNum, const char *name ) {
52 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
55 camera[camNum].clear();
56 return (qboolean)camera[camNum].load( name );
59 qboolean getCameraInfo( int camNum, int time, float *origin, float *angles, float *fov ) {
61 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
67 if ( camera[camNum].getCameraInfo( time, org, dir, fov ) ) {
71 angles[1] = atan2( dir[1], dir[0] ) * 180 / 3.14159;
72 angles[0] = asin( dir[2] ) * 180 / 3.14159;
78 void startCamera( int camNum, int time ) {
79 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
82 camera[camNum].startCamera( time );
88 //#include "../shared/windings.h"
89 //#include "../qcommon/qcommon.h"
90 //#include "../sys/sys_public.h"
91 //#include "../game/game_entity.h"
93 idCameraDef splineList;
94 idCameraDef *g_splineList = &splineList;
96 idVec3 idSplineList::zero( 0,0,0 );
98 void glLabeledPoint( idVec3 &color, idVec3 &point, float size, const char *label ) {
100 qglPointSize( size );
101 qglBegin( GL_POINTS );
102 qglVertex3fv( point );
108 qglRasterPos3fv( v );
109 qglCallLists( strlen( label ), GL_UNSIGNED_BYTE, label );
113 void glBox( idVec3 &color, idVec3 &point, float size ) {
114 idVec3 mins( point );
115 idVec3 maxs( point );
122 qglColor3fv( color );
123 qglBegin( GL_LINE_LOOP );
124 qglVertex3f( mins[0],mins[1],mins[2] );
125 qglVertex3f( maxs[0],mins[1],mins[2] );
126 qglVertex3f( maxs[0],maxs[1],mins[2] );
127 qglVertex3f( mins[0],maxs[1],mins[2] );
129 qglBegin( GL_LINE_LOOP );
130 qglVertex3f( mins[0],mins[1],maxs[2] );
131 qglVertex3f( maxs[0],mins[1],maxs[2] );
132 qglVertex3f( maxs[0],maxs[1],maxs[2] );
133 qglVertex3f( mins[0],maxs[1],maxs[2] );
136 qglBegin( GL_LINES );
137 qglVertex3f( mins[0],mins[1],mins[2] );
138 qglVertex3f( mins[0],mins[1],maxs[2] );
139 qglVertex3f( mins[0],maxs[1],maxs[2] );
140 qglVertex3f( mins[0],maxs[1],mins[2] );
141 qglVertex3f( maxs[0],mins[1],mins[2] );
142 qglVertex3f( maxs[0],mins[1],maxs[2] );
143 qglVertex3f( maxs[0],maxs[1],maxs[2] );
144 qglVertex3f( maxs[0],maxs[1],mins[2] );
150 //g_splineList->load("p:/doom/base/maps/test_base1.camera");
154 //g_splineList->addToRenderer();
158 //extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end );
160 void debugLine( idVec3 &color, float x, float y, float z, float x2, float y2, float z2 ) {
161 idVec3 from( x, y, z );
162 idVec3 to( x2, y2, z2 );
163 //D_DebugLine(color, from, to);
166 void idSplineList::addToRenderer() {
168 if ( controlPoints.Num() == 0 ) {
173 idVec3 yellow( 1.0, 1.0, 0 );
174 idVec3 white( 1.0, 1.0, 1.0 );
177 for ( i = 0; i < controlPoints.Num(); i++ ) {
178 VectorCopy( *controlPoints[i], mins );
179 VectorCopy( mins, maxs );
186 debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2] );
187 debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2] );
188 debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2] );
189 debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2] );
191 debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2] );
192 debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2] );
193 debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2] );
194 debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2] );
200 for ( i = 3; i < controlPoints.Num(); i++ ) {
201 for ( float tension = 0.0f; tension < 1.001f; tension += 0.1f ) {
205 for ( int j = 0; j < 4; j++ ) {
206 x += controlPoints[i - ( 3 - j )]->x * calcSpline( j, tension );
207 y += controlPoints[i - ( 3 - j )]->y * calcSpline( j, tension );
208 z += controlPoints[i - ( 3 - j )]->z * calcSpline( j, tension );
217 debugLine( white, step1[0], step1[1], step1[2], x, y, z );
225 void idSplineList::buildSpline() {
226 //int start = Sys_Milliseconds();
228 for ( int i = 3; i < controlPoints.Num(); i++ ) {
229 for ( float tension = 0.0f; tension < 1.001f; tension += granularity ) {
233 for ( int j = 0; j < 4; j++ ) {
234 x += controlPoints[i - ( 3 - j )]->x * calcSpline( j, tension );
235 y += controlPoints[i - ( 3 - j )]->y * calcSpline( j, tension );
236 z += controlPoints[i - ( 3 - j )]->z * calcSpline( j, tension );
238 splinePoints.Append( new idVec3( x, y, z ) );
242 //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
246 void idSplineList::draw( bool editMode ) {
248 idVec4 yellow( 1, 1, 0, 1 );
250 if ( controlPoints.Num() == 0 ) {
259 qglColor3fv( controlColor );
262 qglBegin( GL_POINTS );
263 for ( i = 0; i < controlPoints.Num(); i++ ) {
264 qglVertex3fv( *controlPoints[i] );
269 for ( i = 0; i < controlPoints.Num(); i++ ) {
270 glBox( activeColor, *controlPoints[i], 4 );
275 qglColor3fv( pathColor );
276 qglBegin( GL_LINE_STRIP );
277 int count = splinePoints.Num();
278 for ( i = 0; i < count; i++ ) {
279 qglVertex3fv( *splinePoints[i] );
284 qglColor3fv( segmentColor );
286 qglBegin( GL_POINTS );
287 for ( i = 0; i < count; i++ ) {
288 qglVertex3fv( *splinePoints[i] );
293 //assert(activeSegment >=0 && activeSegment < count);
294 if ( activeSegment >= 0 && activeSegment < count ) {
295 glBox( activeColor, *splinePoints[activeSegment], 6 );
296 glBox( yellow, *splinePoints[activeSegment], 8 );
302 float idSplineList::totalDistance() {
304 // FIXME: save dist and return
306 if ( controlPoints.Num() == 0 ) {
316 int count = splinePoints.Num();
317 for ( int i = 1; i < count; i++ ) {
318 temp = *splinePoints[i - 1];
319 temp -= *splinePoints[i];
320 dist += temp.Length();
325 void idSplineList::initPosition( long bt, long totalTime ) {
331 if ( splinePoints.Num() == 0 ) {
338 // calc distance to travel ( this will soon be broken into time segments )
340 splineTime.Append( bt );
341 double dist = totalDistance();
342 double distSoFar = 0.0;
344 int count = splinePoints.Num();
345 //for(int i = 2; i < count - 1; i++) {
346 for ( int i = 1; i < count; i++ ) {
347 temp = *splinePoints[i - 1];
348 temp -= *splinePoints[i];
349 distSoFar += temp.Length();
350 double percent = distSoFar / dist;
351 percent *= totalTime;
352 splineTime.Append( percent + bt );
354 assert( splineTime.Num() == splinePoints.Num() );
360 float idSplineList::calcSpline( int step, float tension ) {
362 case 0: return ( pow( 1 - tension, 3 ) ) / 6;
363 case 1: return ( 3 * pow( tension, 3 ) - 6 * pow( tension, 2 ) + 4 ) / 6;
364 case 2: return ( -3 * pow( tension, 3 ) + 3 * pow( tension, 2 ) + 3 * tension + 1 ) / 6;
365 case 3: return pow( tension, 3 ) / 6;
372 void idSplineList::updateSelection( const idVec3 &move ) {
375 VectorAdd( *selected, move, *selected );
380 void idSplineList::setSelectedPoint( idVec3 *p ) {
383 for ( int i = 0; i < controlPoints.Num(); i++ ) {
384 if ( *p == *controlPoints[i] ) {
385 selected = controlPoints[i];
394 const idVec3 *idSplineList::getPosition( long t ) {
395 static idVec3 interpolatedPos;
396 static long lastTime = -1;
398 int count = splineTime.Num();
403 // Com_Printf("Time: %d\n", t);
404 assert( splineTime.Num() == splinePoints.Num() );
406 while ( activeSegment < count ) {
407 if ( splineTime[activeSegment] >= t ) {
408 if ( activeSegment > 0 && activeSegment < count - 1 ) {
409 double timeHi = splineTime[activeSegment + 1];
410 double timeLo = splineTime[activeSegment - 1];
411 double percent = ( timeHi - t ) / ( timeHi - timeLo );
412 // pick two bounding points
413 idVec3 v1 = *splinePoints[activeSegment - 1];
414 idVec3 v2 = *splinePoints[activeSegment + 1];
415 v2 *= ( 1.0 - percent );
418 interpolatedPos = v2;
419 return &interpolatedPos;
421 return splinePoints[activeSegment];
427 return splinePoints[count - 1];
430 void idSplineList::parse( const char *( *text ) ) {
432 //Com_MatchToken( text, "{" );
434 token = Com_Parse( text );
439 if ( !Q_stricmp( token, "}" ) ) {
444 // if token is not a brace, it is a key for a key/value pair
445 if ( !token[0] || !Q_stricmp( token, "(" ) || !Q_stricmp( token, "}" ) ) {
450 idStr key = Com_ParseOnLine( text );
451 const char *token = Com_Parse( text );
452 if ( Q_stricmp( key.c_str(), "granularity" ) == 0 ) {
453 granularity = atof( token );
455 else if ( Q_stricmp( key.c_str(), "name" ) == 0 ) {
458 token = Com_Parse( text );
462 if ( !Q_stricmp( token, "}" ) ) {
467 // read the control point
469 Com_Parse1DMatrix( text, 3, point );
470 addPoint( point.x, point.y, point.z );
474 //Com_MatchToken( text, "}" );
478 void idSplineList::write( fileHandle_t file, const char *p ) {
479 idStr s = va( "\t\t%s {\n", p );
480 FS_Write( s.c_str(), s.length(), file );
481 //s = va("\t\tname %s\n", name.c_str());
482 //FS_Write(s.c_str(), s.length(), file);
483 s = va( "\t\t\tgranularity %f\n", granularity );
484 FS_Write( s.c_str(), s.length(), file );
485 int count = controlPoints.Num();
486 for ( int i = 0; i < count; i++ ) {
487 s = va( "\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z );
488 FS_Write( s.c_str(), s.length(), file );
491 FS_Write( s.c_str(), s.length(), file );
495 void idCameraDef::getActiveSegmentInfo( int segment, idVec3 &origin, idVec3 &direction, float *fov ) {
497 if ( !cameraSpline.validTime() ) {
500 double d = (double)segment / numSegments();
501 getCameraInfo( d * totalTime * 1000, origin, direction, fov );
504 if (!cameraSpline.validTime()) {
507 origin = *cameraSpline.getSegmentPoint(segment);
512 int numTargets = getTargetSpline()->controlPoints.Num();
513 int count = cameraSpline.splineTime.Num();
514 if (numTargets == 0) {
516 if (cameraSpline.getActiveSegment() < count - 1) {
517 temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
519 } else if (numTargets == 1) {
520 temp = *getTargetSpline()->controlPoints[0];
522 temp = *getTargetSpline()->getSegmentPoint(segment);
531 bool idCameraDef::getCameraInfo( long time, idVec3 &origin, idVec3 &direction, float *fv ) {
535 if ( ( time - startTime ) / 1000 > totalTime ) {
540 for ( int i = 0; i < events.Num(); i++ ) {
541 if ( time >= startTime + events[i]->getTime() && !events[i]->getTriggered() ) {
542 events[i]->setTriggered( true );
543 if ( events[i]->getType() == idCameraEvent::EVENT_TARGET ) {
544 setActiveTargetByName( events[i]->getParam() );
545 getActiveTarget()->start( startTime + events[i]->getTime() );
546 //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
548 else if ( events[i]->getType() == idCameraEvent::EVENT_TRIGGER ) {
549 //idEntity *ent = NULL;
550 //ent = level.FindTarget( ent, events[i]->getParam());
552 // ent->signal( SIG_TRIGGER );
553 // ent->ProcessEvent( &EV_Activate, world );
556 else if ( events[i]->getType() == idCameraEvent::EVENT_FOV ) {
557 memset( buff, 0, sizeof( buff ) );
558 strcpy( buff, events[i]->getParam() );
559 const char *param1 = strtok( buff, " \t,\0" );
560 const char *param2 = strtok( NULL, " \t,\0" );
561 float len = ( param2 ) ? atof( param2 ) : 0;
562 float newfov = ( param1 ) ? atof( param1 ) : 90;
563 fov.reset( fov.getFOV( time ), newfov, time, len );
564 //*fv = fov = atof(events[i]->getParam());
566 else if ( events[i]->getType() == idCameraEvent::EVENT_FADEIN ) {
567 float time = atof( events[i]->getParam() );
568 Cbuf_AddText( va( "fade 0 0 0 0 %f", time ) );
571 else if ( events[i]->getType() == idCameraEvent::EVENT_FADEOUT ) {
572 float time = atof( events[i]->getParam() );
573 Cbuf_AddText( va( "fade 0 0 0 255 %f", time ) );
576 else if ( events[i]->getType() == idCameraEvent::EVENT_CAMERA ) {
577 memset( buff, 0, sizeof( buff ) );
578 strcpy( buff, events[i]->getParam() );
579 const char *param1 = strtok( buff, " \t,\0" );
580 const char *param2 = strtok( NULL, " \t,\0" );
583 loadCamera( atoi( param1 ), va( "cameras/%s.camera", param2 ) );
587 loadCamera( 0, va( "cameras/%s.camera", events[i]->getParam() ) );
592 else if ( events[i]->getType() == idCameraEvent::EVENT_STOP ) {
598 origin = *cameraPosition->getPosition( time );
600 *fv = fov.getFOV( time );
602 idVec3 temp = origin;
604 int numTargets = targetPositions.Num();
605 if ( numTargets == 0 ) {
608 if (cameraSpline.getActiveSegment() < count - 1) {
609 temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
610 if (temp == origin) {
611 int index = cameraSpline.getActiveSegment() + 2;
612 while (temp == origin && index < count - 1) {
613 temp = *cameraSpline.splinePoints[index++];
620 if ( getActiveTarget()->numPoints() > 0 ) {
621 temp = *getActiveTarget()->getPosition( time );
632 bool idCameraDef::waitEvent( int index ) {
633 //for (int i = 0; i < events.Num(); i++) {
634 // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
642 #define NUM_CCELERATION_SEGS 10
645 void idCameraDef::buildCamera() {
651 totalTime = baseTime;
652 cameraPosition->setTime( (long)totalTime * 1000 );
653 // we have a base time layout for the path and the target path
654 // now we need to layer on any wait or speed changes
655 for ( i = 0; i < events.Num(); i++ ) {
656 idCameraEvent *ev = events[i];
657 events[i]->setTriggered( false );
658 switch ( events[i]->getType() ) {
659 case idCameraEvent::EVENT_TARGET: {
663 case idCameraEvent::EVENT_FEATHER: {
667 float stepGoal = cameraPosition->getBaseVelocity() / ( 1000 / loopTime );
668 while ( startTime <= 1000 ) {
669 cameraPosition->addVelocity( startTime, loopTime, speed );
671 if ( speed > cameraPosition->getBaseVelocity() ) {
672 speed = cameraPosition->getBaseVelocity();
674 startTime += loopTime;
677 startTime = (long)( totalTime * 1000 - 1000 );
678 long endTime = startTime + 1000;
679 speed = cameraPosition->getBaseVelocity();
680 while ( startTime < endTime ) {
685 cameraPosition->addVelocity( startTime, loopTime, speed );
686 startTime += loopTime;
691 case idCameraEvent::EVENT_WAIT: {
692 waits.Append( atof( events[i]->getParam() ) );
694 //FIXME: this is quite hacky for Wolf E3, accel and decel needs
695 // do be parameter based etc..
696 long startTime = events[i]->getTime() - 1000;
697 if ( startTime < 0 ) {
700 float speed = cameraPosition->getBaseVelocity();
702 float steps = speed / ( ( events[i]->getTime() - startTime ) / loopTime );
703 while ( startTime <= events[i]->getTime() - loopTime ) {
704 cameraPosition->addVelocity( startTime, loopTime, speed );
706 startTime += loopTime;
708 cameraPosition->addVelocity( events[i]->getTime(), (long)atof( events[i]->getParam() ) * 1000, 0 );
710 startTime = (long)( events[i]->getTime() + atof( events[i]->getParam() ) * 1000 );
711 long endTime = startTime + 1000;
713 while ( startTime <= endTime ) {
714 cameraPosition->addVelocity( startTime, loopTime, speed );
716 startTime += loopTime;
720 case idCameraEvent::EVENT_TARGETWAIT: {
721 //targetWaits.Append(i);
724 case idCameraEvent::EVENT_SPEED: {
726 // take the average delay between up to the next five segments
727 float adjust = atof(events[i]->getParam());
728 int index = events[i]->getSegment();
732 // get total amount of time over the remainder of the segment
733 for (j = index; j < cameraSpline.numSegments() - 1; j++) {
734 total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
738 // multiply that by the adjustment
739 double newTotal = total * adjust;
740 // what is the difference..
742 totalTime += newTotal / 1000;
744 // per segment difference
746 int additive = newTotal;
748 // now propogate that difference out to each segment
749 for (j = index; j < cameraSpline.numSegments(); j++) {
750 cameraSpline.addSegmentTime(j, additive);
751 additive += newTotal;
760 for ( i = 0; i < waits.Num(); i++ ) {
761 totalTime += waits[i];
764 // on a new target switch, we need to take time to this point ( since last target switch )
765 // and allocate it across the active target, then reset time to this point
767 long total = (long)( totalTime * 1000 );
768 for ( i = 0; i < targets.Num(); i++ ) {
770 if ( i < targets.Num() - 1 ) {
771 t = events[targets[i + 1]]->getTime();
774 t = total - timeSoFar;
776 // t is how much time to use for this target
777 setActiveTargetByName( events[targets[i]]->getParam() );
778 getActiveTarget()->setTime( t );
785 void idCameraDef::startCamera( long t ) {
786 cameraPosition->clearVelocities();
787 cameraPosition->start( t );
789 fov.reset( 90, 90, t, 0 );
790 //for (int i = 0; i < targetPositions.Num(); i++) {
791 // targetPositions[i]->
794 cameraRunning = true;
798 void idCameraDef::parse( const char *( *text ) ) {
802 token = Com_Parse( text );
807 if ( !Q_stricmp( token, "}" ) ) {
811 if ( Q_stricmp( token, "time" ) == 0 ) {
812 baseTime = Com_ParseFloat( text );
814 else if ( Q_stricmp( token, "camera_fixed" ) == 0 ) {
815 cameraPosition = new idFixedPosition();
816 cameraPosition->parse( text );
818 else if ( Q_stricmp( token, "camera_interpolated" ) == 0 ) {
819 cameraPosition = new idInterpolatedPosition();
820 cameraPosition->parse( text );
822 else if ( Q_stricmp( token, "camera_spline" ) == 0 ) {
823 cameraPosition = new idSplinePosition();
824 cameraPosition->parse( text );
826 else if ( Q_stricmp( token, "target_fixed" ) == 0 ) {
827 idFixedPosition *pos = new idFixedPosition();
829 targetPositions.Append( pos );
831 else if ( Q_stricmp( token, "target_interpolated" ) == 0 ) {
832 idInterpolatedPosition *pos = new idInterpolatedPosition();
834 targetPositions.Append( pos );
836 else if ( Q_stricmp( token, "target_spline" ) == 0 ) {
837 idSplinePosition *pos = new idSplinePosition();
839 targetPositions.Append( pos );
841 else if ( Q_stricmp( token, "fov" ) == 0 ) {
844 else if ( Q_stricmp( token, "event" ) == 0 ) {
845 idCameraEvent *event = new idCameraEvent();
846 event->parse( text );
853 if ( !cameraPosition ) {
854 Com_Printf( "no camera position specified\n" );
855 // prevent a crash later on
856 cameraPosition = new idFixedPosition();
860 Com_MatchToken( text, "}" );
864 bool idCameraDef::load( const char *filename ) {
867 int length = FS_ReadFile( filename, (void **)&buf );
873 Com_BeginParseSession( filename );
876 Com_EndParseSession();
882 void idCameraDef::save( const char *filename ) {
883 fileHandle_t file = FS_FOpenFileWrite( filename );
886 idStr s = "cameraPathDef { \n";
887 FS_Write( s.c_str(), s.length(), file );
888 s = va( "\ttime %f\n", baseTime );
889 FS_Write( s.c_str(), s.length(), file );
891 cameraPosition->write( file, va( "camera_%s",cameraPosition->typeStr() ) );
893 for ( i = 0; i < numTargets(); i++ ) {
894 targetPositions[i]->write( file, va( "target_%s", targetPositions[i]->typeStr() ) );
897 for ( i = 0; i < events.Num(); i++ ) {
898 events[i]->write( file, "event" );
901 fov.write( file, "fov" );
904 FS_Write( s.c_str(), s.length(), file );
906 FS_FCloseFile( file );
909 int idCameraDef::sortEvents( const void *p1, const void *p2 ) {
910 idCameraEvent *ev1 = (idCameraEvent*)( p1 );
911 idCameraEvent *ev2 = (idCameraEvent*)( p2 );
913 if ( ev1->getTime() > ev2->getTime() ) {
916 if ( ev1->getTime() < ev2->getTime() ) {
922 void idCameraDef::addEvent( idCameraEvent *event ) {
923 events.Append( event );
924 //events.Sort(&sortEvents);
927 void idCameraDef::addEvent( idCameraEvent::eventType t, const char *param, long time ) {
928 addEvent( new idCameraEvent( t, param, time ) );
932 void idCameraDef::removeEvent( int index ) {
933 events.RemoveIndex( index );
938 const char *idCameraEvent::eventStr[] = {
955 void idCameraEvent::parse( const char *( *text ) ) {
957 Com_MatchToken( text, "{" );
959 token = Com_Parse( text );
964 if ( !strcmp( token, "}" ) ) {
968 // here we may have to jump over brush epairs ( only used in editor )
970 // if token is not a brace, it is a key for a key/value pair
971 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
976 idStr key = Com_ParseOnLine( text );
977 const char *token = Com_Parse( text );
978 if ( Q_stricmp( key.c_str(), "type" ) == 0 ) {
979 type = static_cast<idCameraEvent::eventType>( atoi( token ) );
981 else if ( Q_stricmp( key.c_str(), "param" ) == 0 ) {
984 else if ( Q_stricmp( key.c_str(), "time" ) == 0 ) {
985 time = atoi( token );
987 token = Com_Parse( text );
991 if ( !strcmp( token, "}" ) ) {
998 Com_MatchToken( text, "}" );
1001 void idCameraEvent::write( fileHandle_t file, const char *name ) {
1002 idStr s = va( "\t%s {\n", name );
1003 FS_Write( s.c_str(), s.length(), file );
1004 s = va( "\t\ttype %d\n", static_cast<int>( type ) );
1005 FS_Write( s.c_str(), s.length(), file );
1006 s = va( "\t\tparam \"%s\"\n", paramStr.c_str() );
1007 FS_Write( s.c_str(), s.length(), file );
1008 s = va( "\t\ttime %d\n", time );
1009 FS_Write( s.c_str(), s.length(), file );
1011 FS_Write( s.c_str(), s.length(), file );
1015 const char *idCameraPosition::positionStr[] = {
1023 const idVec3 *idInterpolatedPosition::getPosition( long t ) {
1024 static idVec3 interpolatedPos;
1026 float velocity = getVelocity( t );
1027 float timePassed = t - lastTime;
1030 // convert to seconds
1033 float distToTravel = timePassed * velocity;
1035 idVec3 temp = startPos;
1037 float distance = temp.Length();
1039 distSoFar += distToTravel;
1040 float percent = (float)( distSoFar ) / distance;
1042 if ( percent > 1.0 ) {
1045 else if ( percent < 0.0 ) {
1049 // the following line does a straigt calc on percentage of time
1050 // float percent = (float)(startTime + time - t) / time;
1052 idVec3 v1 = startPos;
1054 v1 *= ( 1.0 - percent );
1057 interpolatedPos = v1;
1058 return &interpolatedPos;
1062 void idCameraFOV::parse( const char *( *text ) ) {
1064 Com_MatchToken( text, "{" );
1066 token = Com_Parse( text );
1071 if ( !strcmp( token, "}" ) ) {
1075 // here we may have to jump over brush epairs ( only used in editor )
1077 // if token is not a brace, it is a key for a key/value pair
1078 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1083 idStr key = Com_ParseOnLine( text );
1084 const char *token = Com_Parse( text );
1085 if ( Q_stricmp( key.c_str(), "fov" ) == 0 ) {
1086 fov = atof( token );
1088 else if ( Q_stricmp( key.c_str(), "startFOV" ) == 0 ) {
1089 startFOV = atof( token );
1091 else if ( Q_stricmp( key.c_str(), "endFOV" ) == 0 ) {
1092 endFOV = atof( token );
1094 else if ( Q_stricmp( key.c_str(), "time" ) == 0 ) {
1095 time = atoi( token );
1097 token = Com_Parse( text );
1101 if ( !strcmp( token, "}" ) ) {
1108 Com_MatchToken( text, "}" );
1111 bool idCameraPosition::parseToken( const char *key, const char *( *text ) ) {
1112 const char *token = Com_Parse( text );
1113 if ( Q_stricmp( key, "time" ) == 0 ) {
1114 time = atol( token );
1117 else if ( Q_stricmp( key, "type" ) == 0 ) {
1118 type = static_cast<idCameraPosition::positionType>( atoi( token ) );
1121 else if ( Q_stricmp( key, "velocity" ) == 0 ) {
1122 long t = atol( token );
1123 token = Com_Parse( text );
1124 long d = atol( token );
1125 token = Com_Parse( text );
1126 float s = atof( token );
1127 addVelocity( t, d, s );
1130 else if ( Q_stricmp( key, "baseVelocity" ) == 0 ) {
1131 baseVelocity = atof( token );
1134 else if ( Q_stricmp( key, "name" ) == 0 ) {
1138 else if ( Q_stricmp( key, "time" ) == 0 ) {
1139 time = atoi( token );
1148 void idFixedPosition::parse( const char *( *text ) ) {
1150 Com_MatchToken( text, "{" );
1152 token = Com_Parse( text );
1157 if ( !strcmp( token, "}" ) ) {
1161 // here we may have to jump over brush epairs ( only used in editor )
1163 // if token is not a brace, it is a key for a key/value pair
1164 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1169 idStr key = Com_ParseOnLine( text );
1171 const char *token = Com_Parse( text );
1172 if ( Q_stricmp( key.c_str(), "pos" ) == 0 ) {
1174 Com_Parse1DMatrix( text, 3, pos );
1178 idCameraPosition::parseToken( key.c_str(), text );
1180 token = Com_Parse( text );
1184 if ( !strcmp( token, "}" ) ) {
1191 Com_MatchToken( text, "}" );
1194 void idInterpolatedPosition::parse( const char *( *text ) ) {
1196 Com_MatchToken( text, "{" );
1198 token = Com_Parse( text );
1203 if ( !strcmp( token, "}" ) ) {
1207 // here we may have to jump over brush epairs ( only used in editor )
1209 // if token is not a brace, it is a key for a key/value pair
1210 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1215 idStr key = Com_ParseOnLine( text );
1217 const char *token = Com_Parse( text );
1218 if ( Q_stricmp( key.c_str(), "startPos" ) == 0 ) {
1220 Com_Parse1DMatrix( text, 3, startPos );
1222 else if ( Q_stricmp( key.c_str(), "endPos" ) == 0 ) {
1224 Com_Parse1DMatrix( text, 3, endPos );
1228 idCameraPosition::parseToken( key.c_str(), text );
1230 token = Com_Parse( text );
1234 if ( !strcmp( token, "}" ) ) {
1241 Com_MatchToken( text, "}" );
1245 void idSplinePosition::parse( const char *( *text ) ) {
1247 Com_MatchToken( text, "{" );
1249 token = Com_Parse( text );
1254 if ( !strcmp( token, "}" ) ) {
1258 // here we may have to jump over brush epairs ( only used in editor )
1260 // if token is not a brace, it is a key for a key/value pair
1261 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1266 idStr key = Com_ParseOnLine( text );
1268 const char *token = Com_Parse( text );
1269 if ( Q_stricmp( key.c_str(), "target" ) == 0 ) {
1270 target.parse( text );
1274 idCameraPosition::parseToken( key.c_str(), text );
1276 token = Com_Parse( text );
1280 if ( !strcmp( token, "}" ) ) {
1287 Com_MatchToken( text, "}" );
1292 void idCameraFOV::write( fileHandle_t file, const char *p ) {
1293 idStr s = va( "\t%s {\n", p );
1294 FS_Write( s.c_str(), s.length(), file );
1296 s = va( "\t\tfov %f\n", fov );
1297 FS_Write( s.c_str(), s.length(), file );
1299 s = va( "\t\tstartFOV %f\n", startFOV );
1300 FS_Write( s.c_str(), s.length(), file );
1302 s = va( "\t\tendFOV %f\n", endFOV );
1303 FS_Write( s.c_str(), s.length(), file );
1305 s = va( "\t\ttime %i\n", time );
1306 FS_Write( s.c_str(), s.length(), file );
1309 FS_Write( s.c_str(), s.length(), file );
1313 void idCameraPosition::write( fileHandle_t file, const char *p ) {
1315 idStr s = va( "\t\ttime %i\n", time );
1316 FS_Write( s.c_str(), s.length(), file );
1318 s = va( "\t\ttype %i\n", static_cast<int>( type ) );
1319 FS_Write( s.c_str(), s.length(), file );
1321 s = va( "\t\tname %s\n", name.c_str() );
1322 FS_Write( s.c_str(), s.length(), file );
1324 s = va( "\t\tbaseVelocity %f\n", baseVelocity );
1325 FS_Write( s.c_str(), s.length(), file );
1327 for ( int i = 0; i < velocities.Num(); i++ ) {
1328 s = va( "\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed );
1329 FS_Write( s.c_str(), s.length(), file );
1334 void idFixedPosition::write( fileHandle_t file, const char *p ) {
1335 idStr s = va( "\t%s {\n", p );
1336 FS_Write( s.c_str(), s.length(), file );
1337 idCameraPosition::write( file, p );
1338 s = va( "\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z );
1339 FS_Write( s.c_str(), s.length(), file );
1341 FS_Write( s.c_str(), s.length(), file );
1344 void idInterpolatedPosition::write( fileHandle_t file, const char *p ) {
1345 idStr s = va( "\t%s {\n", p );
1346 FS_Write( s.c_str(), s.length(), file );
1347 idCameraPosition::write( file, p );
1348 s = va( "\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z );
1349 FS_Write( s.c_str(), s.length(), file );
1350 s = va( "\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z );
1351 FS_Write( s.c_str(), s.length(), file );
1353 FS_Write( s.c_str(), s.length(), file );
1356 void idSplinePosition::write( fileHandle_t file, const char *p ) {
1357 idStr s = va( "\t%s {\n", p );
1358 FS_Write( s.c_str(), s.length(), file );
1359 idCameraPosition::write( file, p );
1360 target.write( file, "target" );
1362 FS_Write( s.c_str(), s.length(), file );
1365 void idCameraDef::addTarget( const char *name, idCameraPosition::positionType type ) {
1366 const char *text = ( name == NULL ) ? va( "target0%d", numTargets() + 1 ) : name;
1367 idCameraPosition *pos = newFromType( type );
1369 pos->setName( name );
1370 targetPositions.Append( pos );
1371 activeTarget = numTargets() - 1;
1372 if ( activeTarget == 0 ) {
1374 addEvent( idCameraEvent::EVENT_TARGET, name, 0 );
1379 const idVec3 *idSplinePosition::getPosition( long t ) {
1380 static idVec3 interpolatedPos;
1382 float velocity = getVelocity( t );
1383 float timePassed = t - lastTime;
1386 // convert to seconds
1389 float distToTravel = timePassed * velocity;
1391 distSoFar += distToTravel;
1392 double tempDistance = target.totalDistance();
1394 double percent = (double)( distSoFar ) / tempDistance;
1396 double targetDistance = percent * tempDistance;
1399 double lastDistance1,lastDistance2;
1400 lastDistance1 = lastDistance2 = 0;
1402 int count = target.numSegments();
1404 for ( i = 1; i < count; i++ ) {
1405 temp = *target.getSegmentPoint( i - 1 );
1406 temp -= *target.getSegmentPoint( i );
1407 tempDistance += temp.Length();
1409 lastDistance1 = tempDistance;
1412 lastDistance2 = tempDistance;
1414 if ( tempDistance >= targetDistance ) {
1419 if ( i >= count - 1 ) {
1420 interpolatedPos = *target.getSegmentPoint( i - 1 );
1424 double timeHi = target.getSegmentTime( i + 1 );
1425 double timeLo = target.getSegmentTime( i - 1 );
1426 double percent = ( timeHi - t ) / ( timeHi - timeLo );
1427 idVec3 v1 = *target.getSegmentPoint( i - 1 );
1428 idVec3 v2 = *target.getSegmentPoint( i + 1 );
1429 v2 *= ( 1.0 - percent );
1432 interpolatedPos = v2;
1434 if ( lastDistance1 > lastDistance2 ) {
1435 double d = lastDistance2;
1436 lastDistance2 = lastDistance1;
1440 idVec3 v1 = *target.getSegmentPoint( i - 1 );
1441 idVec3 v2 = *target.getSegmentPoint( i );
1442 double percent = ( lastDistance2 - targetDistance ) / ( lastDistance2 - lastDistance1 );
1443 v2 *= ( 1.0 - percent );
1446 interpolatedPos = v2;
1449 return &interpolatedPos;