1 /*
2 ===========================================================================
3
4 Return to Castle Wolfenstein single player GPL Source Code
5 Copyright (C) 1999-2010 id Software LLC, a ZeniMax Media company.
6
7 This file is part of the Return to Castle Wolfenstein single player GPL Source Code (RTCW SP Source Code).
8
9 RTCW SP Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 RTCW SP Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with RTCW SP Source Code. If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the RTCW SP Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the RTCW SP Source Code. If not, please request a copy in writing from id Software at the address below.
23
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25
26 ===========================================================================
27 */
28
29 #include "q_splineshared.h"
30 #include "splines.h"
31
32 extern "C" {
33 int FS_Write( const void *buffer, int len, fileHandle_t f );
34 long FS_ReadFile( const char *qpath, void **buffer );
35 void FS_FreeFile( void *buffer );
36 fileHandle_t FS_FOpenFileWrite( const char *filename );
37 void FS_FCloseFile( fileHandle_t f );
38 void Cbuf_AddText( const char *text );
39 void Cbuf_Execute( void );
40 }
41
Q_fabs(float f)42 float Q_fabs( float f ) {
43 int tmp = *( int * ) &f;
44 tmp &= 0x7FFFFFFF;
45 return *( float * ) &tmp;
46 }
47
48 // (SA) making a list of cameras so I can use
49 // the splines as targets for other things.
50 // Certainly better ways to do this, but this lets
51 // me get underway quickly with ents that need spline
52 // targets.
53 #define MAX_CAMERAS 64
54
55 idCameraDef camera[MAX_CAMERAS];
56
57 extern "C" {
loadCamera(int camNum,const char * name)58 qboolean loadCamera( int camNum, const char *name ) {
59 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
60 return qfalse;
61 }
62 camera[camNum].clear();
63 // TTimo static_cast confused gcc, went for C-style casting
64 return (qboolean)( camera[camNum].load( name ) );
65 }
66
getCameraInfo(int camNum,int time,float * origin,float * angles,float * fov)67 qboolean getCameraInfo( int camNum, int time, float *origin, float *angles, float *fov ) {
68 idVec3 dir, org;
69
70 dir[0] = 0;
71 dir[1] = 0;
72 dir[2] = 0;
73
74 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
75 return qfalse;
76 }
77 org[0] = origin[0];
78 org[1] = origin[1];
79 org[2] = origin[2];
80 if ( camera[camNum].getCameraInfo( time, org, dir, fov ) ) {
81 origin[0] = org[0];
82 origin[1] = org[1];
83 origin[2] = org[2];
84 angles[1] = atan2( dir[1], dir[0] ) * 180 / 3.14159;
85 angles[0] = asin( dir[2] ) * 180 / 3.14159;
86 return qtrue;
87 }
88 return qfalse;
89 }
90
startCamera(int camNum,int time)91 void startCamera( int camNum, int time ) {
92 if ( camNum < 0 || camNum >= MAX_CAMERAS ) {
93 return;
94 }
95 camera[camNum].startCamera( time );
96 }
97
98 }
99
100
101 //#include "../shared/windings.h"
102 //#include "../qcommon/qcommon.h"
103 //#include "../sys/sys_public.h"
104 //#include "../game/game_entity.h"
105
106 idCameraDef splineList;
107 idCameraDef *g_splineList = &splineList;
108
109 idVec3 idSplineList::zero( 0,0,0 );
110
glLabeledPoint(idVec3 & color,idVec3 & point,float size,const char * label)111 void glLabeledPoint( idVec3 &color, idVec3 &point, float size, const char *label ) {
112 #if 0
113 qglColor3fv( color );
114 qglPointSize( size );
115 qglBegin( GL_POINTS );
116 qglVertex3fv( point );
117 qglEnd();
118 idVec3 v = point;
119 v.x += 1;
120 v.y += 1;
121 v.z += 1;
122 qglRasterPos3fv( v );
123 qglCallLists( strlen( label ), GL_UNSIGNED_BYTE, label );
124 #endif
125 }
126
127
glBox(idVec3 & color,idVec3 & point,float size)128 void glBox( idVec3 &color, idVec3 &point, float size ) {
129 #if 0
130 idVec3 mins( point );
131 idVec3 maxs( point );
132 mins[0] -= size;
133 mins[1] += size;
134 mins[2] -= size;
135 maxs[0] += size;
136 maxs[1] -= size;
137 maxs[2] += size;
138 qglColor3fv( color );
139 qglBegin( GL_LINE_LOOP );
140 qglVertex3f( mins[0],mins[1],mins[2] );
141 qglVertex3f( maxs[0],mins[1],mins[2] );
142 qglVertex3f( maxs[0],maxs[1],mins[2] );
143 qglVertex3f( mins[0],maxs[1],mins[2] );
144 qglEnd();
145 qglBegin( GL_LINE_LOOP );
146 qglVertex3f( mins[0],mins[1],maxs[2] );
147 qglVertex3f( maxs[0],mins[1],maxs[2] );
148 qglVertex3f( maxs[0],maxs[1],maxs[2] );
149 qglVertex3f( mins[0],maxs[1],maxs[2] );
150 qglEnd();
151
152 qglBegin( GL_LINES );
153 qglVertex3f( mins[0],mins[1],mins[2] );
154 qglVertex3f( mins[0],mins[1],maxs[2] );
155 qglVertex3f( mins[0],maxs[1],maxs[2] );
156 qglVertex3f( mins[0],maxs[1],mins[2] );
157 qglVertex3f( maxs[0],mins[1],mins[2] );
158 qglVertex3f( maxs[0],mins[1],maxs[2] );
159 qglVertex3f( maxs[0],maxs[1],maxs[2] );
160 qglVertex3f( maxs[0],maxs[1],mins[2] );
161 qglEnd();
162 #endif
163 }
164
splineTest()165 void splineTest() {
166 //g_splineList->load("p:/doom/base/maps/test_base1.camera");
167 }
168
splineDraw()169 void splineDraw() {
170 //g_splineList->addToRenderer();
171 }
172
173
174 //extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end );
175
debugLine(idVec3 & color,float x,float y,float z,float x2,float y2,float z2)176 void debugLine( idVec3 &color, float x, float y, float z, float x2, float y2, float z2 ) {
177 // idVec3 from(x, y, z);
178 // idVec3 to(x2, y2, z2);
179 //D_DebugLine(color, from, to);
180 }
181
addToRenderer()182 void idSplineList::addToRenderer() {
183
184 if ( controlPoints.Num() == 0 ) {
185 return;
186 }
187
188 idVec3 mins, maxs;
189 idVec3 yellow( 1.0, 1.0, 0 );
190 idVec3 white( 1.0, 1.0, 1.0 );
191 int i;
192
193 for ( i = 0; i < controlPoints.Num(); i++ ) {
194 VectorCopy( *controlPoints[i], mins );
195 VectorCopy( mins, maxs );
196 mins[0] -= 8;
197 mins[1] += 8;
198 mins[2] -= 8;
199 maxs[0] += 8;
200 maxs[1] -= 8;
201 maxs[2] += 8;
202 debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2] );
203 debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2] );
204 debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2] );
205 debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2] );
206
207 debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2] );
208 debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2] );
209 debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2] );
210 debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2] );
211
212 }
213
214 int step = 0;
215 idVec3 step1;
216 for ( i = 3; i < controlPoints.Num(); i++ ) {
217 for ( float tension = 0.0f; tension < 1.001f; tension += 0.1f ) {
218 float x = 0;
219 float y = 0;
220 float z = 0;
221 for ( int j = 0; j < 4; j++ ) {
222 x += controlPoints[i - ( 3 - j )]->x * calcSpline( j, tension );
223 y += controlPoints[i - ( 3 - j )]->y * calcSpline( j, tension );
224 z += controlPoints[i - ( 3 - j )]->z * calcSpline( j, tension );
225 }
226 if ( step == 0 ) {
227 step1[0] = x;
228 step1[1] = y;
229 step1[2] = z;
230 step = 1;
231 } else {
232 debugLine( white, step1[0], step1[1], step1[2], x, y, z );
233 step = 0;
234 }
235
236 }
237 }
238 }
239
buildSpline()240 void idSplineList::buildSpline() {
241 //int start = Sys_Milliseconds();
242 clearSpline();
243 for ( int i = 3; i < controlPoints.Num(); i++ ) {
244 for ( float tension = 0.0f; tension < 1.001f; tension += granularity ) {
245 float x = 0;
246 float y = 0;
247 float z = 0;
248 for ( int j = 0; j < 4; j++ ) {
249 x += controlPoints[i - ( 3 - j )]->x * calcSpline( j, tension );
250 y += controlPoints[i - ( 3 - j )]->y * calcSpline( j, tension );
251 z += controlPoints[i - ( 3 - j )]->z * calcSpline( j, tension );
252 }
253 splinePoints.Append( new idVec3( x, y, z ) );
254 }
255 }
256 dirty = false;
257 //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
258 }
259
260
draw(bool editMode)261 void idSplineList::draw( bool editMode ) {
262 #if 0
263 int i;
264 idVec4 yellow( 1, 1, 0, 1 );
265
266 if ( controlPoints.Num() == 0 ) {
267 return;
268 }
269
270 if ( dirty ) {
271 buildSpline();
272 }
273
274
275 qglColor3fv( controlColor );
276 qglPointSize( 5 );
277
278 qglBegin( GL_POINTS );
279 for ( i = 0; i < controlPoints.Num(); i++ ) {
280 qglVertex3fv( *controlPoints[i] );
281 }
282 qglEnd();
283
284 if ( editMode ) {
285 for ( i = 0; i < controlPoints.Num(); i++ ) {
286 glBox( activeColor, *controlPoints[i], 4 );
287 }
288 }
289
290 //Draw the curve
291 qglColor3fv( pathColor );
292 qglBegin( GL_LINE_STRIP );
293 int count = splinePoints.Num();
294 for ( i = 0; i < count; i++ ) {
295 qglVertex3fv( *splinePoints[i] );
296 }
297 qglEnd();
298
299 if ( editMode ) {
300 qglColor3fv( segmentColor );
301 qglPointSize( 3 );
302 qglBegin( GL_POINTS );
303 for ( i = 0; i < count; i++ ) {
304 qglVertex3fv( *splinePoints[i] );
305 }
306 qglEnd();
307 }
308 if ( count > 0 ) {
309 //assert(activeSegment >=0 && activeSegment < count);
310 if ( activeSegment >= 0 && activeSegment < count ) {
311 glBox( activeColor, *splinePoints[activeSegment], 6 );
312 glBox( yellow, *splinePoints[activeSegment], 8 );
313 }
314 }
315 #endif
316 }
317
totalDistance()318 float idSplineList::totalDistance() {
319
320 // FIXME: save dist and return
321 //
322 if ( controlPoints.Num() == 0 ) {
323 return 0.0;
324 }
325
326 if ( dirty ) {
327 buildSpline();
328 }
329
330 float dist = 0.0;
331 idVec3 temp;
332 int count = splinePoints.Num();
333 for ( int i = 1; i < count; i++ ) {
334 temp = *splinePoints[i - 1];
335 temp -= *splinePoints[i];
336 dist += temp.Length();
337 }
338 return dist;
339 }
340
initPosition(long bt,long totalTime)341 void idSplineList::initPosition( long bt, long totalTime ) {
342
343 if ( dirty ) {
344 buildSpline();
345 }
346
347 if ( splinePoints.Num() == 0 ) {
348 return;
349 }
350
351 baseTime = bt;
352 time = totalTime;
353
354 // calc distance to travel ( this will soon be broken into time segments )
355 splineTime.Clear();
356 splineTime.Append( bt );
357 double dist = totalDistance();
358 double distSoFar = 0.0;
359 idVec3 temp;
360 int count = splinePoints.Num();
361 //for(int i = 2; i < count - 1; i++) {
362 for ( int i = 1; i < count; i++ ) {
363 temp = *splinePoints[i - 1];
364 temp -= *splinePoints[i];
365 distSoFar += temp.Length();
366 double percent = distSoFar / dist;
367 percent *= totalTime;
368 splineTime.Append( percent + bt );
369 }
370 assert( splineTime.Num() == splinePoints.Num() );
371 activeSegment = 0;
372 }
373
374
375
calcSpline(int step,float tension)376 float idSplineList::calcSpline( int step, float tension ) {
377 switch ( step ) {
378 case 0: return ( pow( 1 - tension, 3 ) ) / 6;
379 case 1: return ( 3 * pow( tension, 3 ) - 6 * pow( tension, 2 ) + 4 ) / 6;
380 case 2: return ( -3 * pow( tension, 3 ) + 3 * pow( tension, 2 ) + 3 * tension + 1 ) / 6;
381 case 3: return pow( tension, 3 ) / 6;
382 }
383 return 0.0;
384 }
385
386
387
updateSelection(const idVec3 & move)388 void idSplineList::updateSelection( const idVec3 &move ) {
389 if ( selected ) {
390 dirty = true;
391 VectorAdd( *selected, move, *selected );
392 }
393 }
394
395
setSelectedPoint(idVec3 * p)396 void idSplineList::setSelectedPoint( idVec3 *p ) {
397 if ( p ) {
398 p->Snap();
399 for ( int i = 0; i < controlPoints.Num(); i++ ) {
400 if ( *p == *controlPoints[i] ) {
401 selected = controlPoints[i];
402 }
403 }
404 } else {
405 selected = NULL;
406 }
407 }
408
getPosition(long t)409 const idVec3 *idSplineList::getPosition( long t ) {
410 static idVec3 interpolatedPos;
411 // static long lastTime = -1; // TTimo unused
412
413 int count = splineTime.Num();
414 if ( count == 0 ) {
415 return &zero;
416 }
417
418 // Com_Printf("Time: %d\n", t);
419 assert( splineTime.Num() == splinePoints.Num() );
420
421 while ( activeSegment < count ) {
422 if ( splineTime[activeSegment] >= t ) {
423 if ( activeSegment > 0 && activeSegment < count - 1 ) {
424 double timeHi = splineTime[activeSegment + 1];
425 double timeLo = splineTime[activeSegment - 1];
426 double percent = ( timeHi - t ) / ( timeHi - timeLo );
427 // pick two bounding points
428 idVec3 v1 = *splinePoints[activeSegment - 1];
429 idVec3 v2 = *splinePoints[activeSegment + 1];
430 v2 *= ( 1.0 - percent );
431 v1 *= percent;
432 v2 += v1;
433 interpolatedPos = v2;
434 return &interpolatedPos;
435 }
436 return splinePoints[activeSegment];
437 } else {
438 activeSegment++;
439 }
440 }
441 return splinePoints[count - 1];
442 }
443
parse(const char * (* text))444 void idSplineList::parse( const char *( *text ) ) {
445 const char *token;
446 //Com_MatchToken( text, "{" );
447 do {
448 token = Com_Parse( text );
449
450 if ( !token[0] ) {
451 break;
452 }
453 if ( !Q_stricmp( token, "}" ) ) {
454 break;
455 }
456
457 do {
458 // if token is not a brace, it is a key for a key/value pair
459 if ( !token[0] || !Q_stricmp( token, "(" ) || !Q_stricmp( token, "}" ) ) {
460 break;
461 }
462
463 Com_UngetToken();
464 idStr key = Com_ParseOnLine( text );
465 const char *token = Com_Parse( text );
466 if ( Q_stricmp( key.c_str(), "granularity" ) == 0 ) {
467 granularity = atof( token );
468 } else if ( Q_stricmp( key.c_str(), "name" ) == 0 ) {
469 name = token;
470 }
471 Com_Parse( text );
472
473 } while ( 1 );
474
475 if ( !Q_stricmp( token, "}" ) ) {
476 break;
477 }
478
479 Com_UngetToken();
480 // read the control point
481 idVec3 point;
482 Com_Parse1DMatrix( text, 3, point );
483 addPoint( point.x, point.y, point.z );
484 } while ( 1 );
485
486 //Com_UngetToken();
487 //Com_MatchToken( text, "}" );
488 dirty = true;
489 }
490
write(fileHandle_t file,const char * p)491 void idSplineList::write( fileHandle_t file, const char *p ) {
492 idStr s = va( (char *)"\t\t%s {\n", p );
493 FS_Write( s.c_str(), s.length(), file );
494 //s = va("\t\tname %s\n", name.c_str());
495 //FS_Write(s.c_str(), s.length(), file);
496 s = va( (char *)"\t\t\tgranularity %f\n", granularity );
497 FS_Write( s.c_str(), s.length(), file );
498 int count = controlPoints.Num();
499 for ( int i = 0; i < count; i++ ) {
500 s = va( (char *)"\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z );
501 FS_Write( s.c_str(), s.length(), file );
502 }
503 s = "\t\t}\n";
504 FS_Write( s.c_str(), s.length(), file );
505 }
506
507
getActiveSegmentInfo(int segment,idVec3 & origin,idVec3 & direction,float * fov)508 void idCameraDef::getActiveSegmentInfo( int segment, idVec3 &origin, idVec3 &direction, float *fov ) {
509 #if 0
510 if ( !cameraSpline.validTime() ) {
511 buildCamera();
512 }
513 double d = (double)segment / numSegments();
514 getCameraInfo( d * totalTime * 1000, origin, direction, fov );
515 #endif
516 /*
517 if (!cameraSpline.validTime()) {
518 buildCamera();
519 }
520 origin = *cameraSpline.getSegmentPoint(segment);
521
522
523 idVec3 temp;
524
525 int numTargets = getTargetSpline()->controlPoints.Num();
526 int count = cameraSpline.splineTime.Num();
527 if (numTargets == 0) {
528 // follow the path
529 if (cameraSpline.getActiveSegment() < count - 1) {
530 temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
531 }
532 } else if (numTargets == 1) {
533 temp = *getTargetSpline()->controlPoints[0];
534 } else {
535 temp = *getTargetSpline()->getSegmentPoint(segment);
536 }
537
538 temp -= origin;
539 temp.Normalize();
540 direction = temp;
541 */
542 }
543
getCameraInfo(long time,idVec3 & origin,idVec3 & direction,float * fv)544 bool idCameraDef::getCameraInfo( long time, idVec3 &origin, idVec3 &direction, float *fv ) {
545
546 char buff[1024];
547
548 if ( ( time - startTime ) / 1000 > totalTime ) {
549 return false;
550 }
551
552
553 for ( int i = 0; i < events.Num(); i++ ) {
554 if ( time >= startTime + events[i]->getTime() && !events[i]->getTriggered() ) {
555 events[i]->setTriggered( true );
556 if ( events[i]->getType() == idCameraEvent::EVENT_TARGET ) {
557 setActiveTargetByName( events[i]->getParam() );
558 getActiveTarget()->start( startTime + events[i]->getTime() );
559 //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
560 } else if ( events[i]->getType() == idCameraEvent::EVENT_TRIGGER ) {
561 // empty!
562 } else if ( events[i]->getType() == idCameraEvent::EVENT_FOV ) {
563 memset( buff, 0, sizeof( buff ) );
564 strcpy( buff, events[i]->getParam() );
565 const char *param1 = strtok( buff, " \t,\0" );
566 const char *param2 = strtok( NULL, " \t,\0" );
567 float len = ( param2 ) ? atof( param2 ) : 0;
568 float newfov = ( param1 ) ? atof( param1 ) : 90;
569 fov.reset( fov.getFOV( time ), newfov, time, len );
570 //*fv = fov = atof(events[i]->getParam());
571 } else if ( events[i]->getType() == idCameraEvent::EVENT_FADEIN ) {
572 float time = atof( events[i]->getParam() );
573 Cbuf_AddText( va( (char *)"fade 0 0 0 0 %f", time ) );
574 Cbuf_Execute();
575 } else if ( events[i]->getType() == idCameraEvent::EVENT_FADEOUT ) {
576 float time = atof( events[i]->getParam() );
577 Cbuf_AddText( va( (char *)"fade 0 0 0 255 %f", time ) );
578 Cbuf_Execute();
579 } else if ( events[i]->getType() == idCameraEvent::EVENT_CAMERA ) {
580 memset( buff, 0, sizeof( buff ) );
581 strcpy( buff, events[i]->getParam() );
582 const char *param1 = strtok( buff, " \t,\0" );
583 const char *param2 = strtok( NULL, " \t,\0" );
584
585 if ( param2 ) {
586 loadCamera( atoi( param1 ), va( (char *)"cameras/%s.camera", param2 ) );
587 startCamera( time );
588 } else {
589 loadCamera( 0, va( (char *)"cameras/%s.camera", events[i]->getParam() ) );
590 startCamera( time );
591 }
592 return true;
593 } else if ( events[i]->getType() == idCameraEvent::EVENT_STOP ) {
594 return false;
595 }
596 }
597 }
598
599 origin = *cameraPosition->getPosition( time );
600
601 // CHECK_NAN_VEC( origin );
602
603 *fv = fov.getFOV( time );
604
605 idVec3 temp = origin;
606
607 int numTargets = targetPositions.Num();
608 if ( numTargets == 0 ) {
609 // empty!
610 } else {
611 temp = *getActiveTarget()->getPosition( time );
612 }
613
614 temp -= origin;
615 temp.Normalize();
616 direction = temp;
617
618 return true;
619 }
620
waitEvent(int index)621 bool idCameraDef::waitEvent( int index ) {
622 //for (int i = 0; i < events.Num(); i++) {
623 // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
624 // return true;
625 // }
626 //}
627 return false;
628 }
629
630
631 #define NUM_CCELERATION_SEGS 10
632 #define CELL_AMT 5
633
buildCamera()634 void idCameraDef::buildCamera() {
635 int i;
636 //int lastSwitch = 0; // TTimo: unused
637 idList<float> waits;
638 idList<int> targets;
639
640 totalTime = baseTime;
641 cameraPosition->setTime( totalTime * 1000 );
642 // we have a base time layout for the path and the target path
643 // now we need to layer on any wait or speed changes
644 for ( i = 0; i < events.Num(); i++ ) {
645 //idCameraEvent *ev = events[i]; // TTimo: unused
646 events[i]->setTriggered( false );
647 switch ( events[i]->getType() ) {
648 case idCameraEvent::EVENT_TARGET: {
649 targets.Append( i );
650 break;
651 }
652 case idCameraEvent::EVENT_FEATHER: {
653 long startTime = 0;
654 float speed = 0;
655 long loopTime = 10;
656 float stepGoal = cameraPosition->getBaseVelocity() / ( 1000 / loopTime );
657 while ( startTime <= 1000 ) {
658 cameraPosition->addVelocity( startTime, loopTime, speed );
659 speed += stepGoal;
660 if ( speed > cameraPosition->getBaseVelocity() ) {
661 speed = cameraPosition->getBaseVelocity();
662 }
663 startTime += loopTime;
664 }
665
666 // TTimo gcc warns: assignment to `long int' from `float'
667 // more efficient to do (long int)(totalTime) * 1000 - 1000
668 // safer to (long int)(totalTime * 1000 - 1000)
669 startTime = ( long int )( totalTime * 1000 - 1000 );
670 long endTime = startTime + 1000;
671 speed = cameraPosition->getBaseVelocity();
672 while ( startTime < endTime ) {
673 speed -= stepGoal;
674 if ( speed < 0 ) {
675 speed = 0;
676 }
677 cameraPosition->addVelocity( startTime, loopTime, speed );
678 startTime += loopTime;
679 }
680 break;
681
682 }
683 case idCameraEvent::EVENT_WAIT: {
684 waits.Append( atof( events[i]->getParam() ) );
685
686 //FIXME: this is quite hacky for Wolf E3, accel and decel needs
687 // do be parameter based etc..
688 long startTime = events[i]->getTime() - 1000;
689 if ( startTime < 0 ) {
690 startTime = 0;
691 }
692 float speed = cameraPosition->getBaseVelocity();
693 long loopTime = 10;
694 float steps = speed / ( ( events[i]->getTime() - startTime ) / loopTime );
695 while ( startTime <= events[i]->getTime() - loopTime ) {
696 cameraPosition->addVelocity( startTime, loopTime, speed );
697 speed -= steps;
698 startTime += loopTime;
699 }
700 cameraPosition->addVelocity( events[i]->getTime(), atof( events[i]->getParam() ) * 1000, 0 );
701
702 startTime = ( long int )( events[i]->getTime() + atof( events[i]->getParam() ) * 1000 );
703 long endTime = startTime + 1000;
704 speed = 0;
705 while ( startTime <= endTime ) {
706 cameraPosition->addVelocity( startTime, loopTime, speed );
707 speed += steps;
708 startTime += loopTime;
709 }
710 break;
711 }
712 case idCameraEvent::EVENT_TARGETWAIT: {
713 //targetWaits.Append(i);
714 break;
715 }
716 case idCameraEvent::EVENT_SPEED: {
717 /*
718 // take the average delay between up to the next five segments
719 float adjust = atof(events[i]->getParam());
720 int index = events[i]->getSegment();
721 total = 0;
722 count = 0;
723
724 // get total amount of time over the remainder of the segment
725 for (j = index; j < cameraSpline.numSegments() - 1; j++) {
726 total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
727 count++;
728 }
729
730 // multiply that by the adjustment
731 double newTotal = total * adjust;
732 // what is the difference..
733 newTotal -= total;
734 totalTime += newTotal / 1000;
735
736 // per segment difference
737 newTotal /= count;
738 int additive = newTotal;
739
740 // now propogate that difference out to each segment
741 for (j = index; j < cameraSpline.numSegments(); j++) {
742 cameraSpline.addSegmentTime(j, additive);
743 additive += newTotal;
744 }
745 break;
746 */
747 default:
748 break;
749 }
750 }
751 }
752
753
754 for ( i = 0; i < waits.Num(); i++ ) {
755 totalTime += waits[i];
756 }
757
758 // on a new target switch, we need to take time to this point ( since last target switch )
759 // and allocate it across the active target, then reset time to this point
760 long timeSoFar = 0;
761 long total = ( long int )( totalTime * 1000 );
762 for ( i = 0; i < targets.Num(); i++ ) {
763 long t;
764 if ( i < targets.Num() - 1 ) {
765 t = events[targets[i + 1]]->getTime();
766 } else {
767 t = total - timeSoFar;
768 }
769 // t is how much time to use for this target
770 setActiveTargetByName( events[targets[i]]->getParam() );
771 getActiveTarget()->setTime( t );
772 timeSoFar += t;
773 }
774
775
776 }
777
startCamera(long t)778 void idCameraDef::startCamera( long t ) {
779 cameraPosition->clearVelocities();
780 cameraPosition->start( t );
781 buildCamera();
782 fov.reset( 90, 90, t, 0 );
783 //for (int i = 0; i < targetPositions.Num(); i++) {
784 // targetPositions[i]->
785 //}
786 startTime = t;
787 cameraRunning = true;
788 }
789
790
parse(const char * (* text))791 void idCameraDef::parse( const char *( *text ) ) {
792
793 const char *token;
794 do {
795 token = Com_Parse( text );
796
797 if ( !token[0] ) {
798 break;
799 }
800 if ( !Q_stricmp( token, "}" ) ) {
801 break;
802 }
803
804 if ( Q_stricmp( token, "time" ) == 0 ) {
805 baseTime = Com_ParseFloat( text );
806 } else if ( Q_stricmp( token, "camera_fixed" ) == 0 ) {
807 cameraPosition = new idFixedPosition();
808 cameraPosition->parse( text );
809 } else if ( Q_stricmp( token, "camera_interpolated" ) == 0 ) {
810 cameraPosition = new idInterpolatedPosition();
811 cameraPosition->parse( text );
812 } else if ( Q_stricmp( token, "camera_spline" ) == 0 ) {
813 cameraPosition = new idSplinePosition();
814 cameraPosition->parse( text );
815 } else if ( Q_stricmp( token, "target_fixed" ) == 0 ) {
816 idFixedPosition *pos = new idFixedPosition();
817 pos->parse( text );
818 targetPositions.Append( pos );
819 } else if ( Q_stricmp( token, "target_interpolated" ) == 0 ) {
820 idInterpolatedPosition *pos = new idInterpolatedPosition();
821 pos->parse( text );
822 targetPositions.Append( pos );
823 } else if ( Q_stricmp( token, "target_spline" ) == 0 ) {
824 idSplinePosition *pos = new idSplinePosition();
825 pos->parse( text );
826 targetPositions.Append( pos );
827 } else if ( Q_stricmp( token, "fov" ) == 0 ) {
828 fov.parse( text );
829 } else if ( Q_stricmp( token, "event" ) == 0 ) {
830 idCameraEvent *event = new idCameraEvent();
831 event->parse( text );
832 addEvent( event );
833 }
834
835
836 } while ( 1 );
837
838 if ( !cameraPosition ) {
839 Com_Printf( "no camera position specified\n" );
840 // prevent a crash later on
841 cameraPosition = new idFixedPosition();
842 }
843
844 Com_UngetToken();
845 Com_MatchToken( text, "}" );
846
847 }
848
load(const char * filename)849 bool idCameraDef::load( const char *filename ) {
850 char *buf;
851 const char *buf_p;
852 // TTimo: unused (int length = FS_ReadFile( filename, (void **)&buf );)
853 FS_ReadFile( filename, (void **)&buf );
854 if ( !buf ) {
855 return false;
856 }
857
858 clear();
859 Com_BeginParseSession( filename );
860 buf_p = buf;
861 parse( &buf_p );
862 Com_EndParseSession();
863 FS_FreeFile( buf );
864
865 return true;
866 }
867
save(const char * filename)868 void idCameraDef::save( const char *filename ) {
869 fileHandle_t file = FS_FOpenFileWrite( filename );
870 if ( file ) {
871 int i;
872 idStr s = "cameraPathDef { \n";
873 FS_Write( s.c_str(), s.length(), file );
874 s = va( (char *)"\ttime %f\n", baseTime );
875 FS_Write( s.c_str(), s.length(), file );
876
877 cameraPosition->write( file, va( (char *)"camera_%s",cameraPosition->typeStr() ) );
878
879 for ( i = 0; i < numTargets(); i++ ) {
880 targetPositions[i]->write( file, va( (char *)"target_%s", targetPositions[i]->typeStr() ) );
881 }
882
883 for ( i = 0; i < events.Num(); i++ ) {
884 events[i]->write( file, "event" );
885 }
886
887 fov.write( file, "fov" );
888
889 s = "}\n";
890 FS_Write( s.c_str(), s.length(), file );
891 }
892 FS_FCloseFile( file );
893 }
894
sortEvents(const void * p1,const void * p2)895 int idCameraDef::sortEvents( const void *p1, const void *p2 ) {
896 idCameraEvent *ev1 = ( idCameraEvent* )( p1 );
897 idCameraEvent *ev2 = ( idCameraEvent* )( p2 );
898
899 if ( ev1->getTime() > ev2->getTime() ) {
900 return -1;
901 }
902 if ( ev1->getTime() < ev2->getTime() ) {
903 return 1;
904 }
905 return 0;
906 }
907
addEvent(idCameraEvent * event)908 void idCameraDef::addEvent( idCameraEvent *event ) {
909 events.Append( event );
910 //events.Sort(&sortEvents);
911
912 }
addEvent(idCameraEvent::eventType t,const char * param,long time)913 void idCameraDef::addEvent( idCameraEvent::eventType t, const char *param, long time ) {
914 addEvent( new idCameraEvent( t, param, time ) );
915 buildCamera();
916 }
917
918
919 const char *idCameraEvent::eventStr[] = {
920 "NA",
921 "WAIT",
922 "TARGETWAIT",
923 "SPEED",
924 "TARGET",
925 "SNAPTARGET",
926 "FOV",
927 "CMD",
928 "TRIGGER",
929 "STOP",
930 "CAMERA",
931 "FADEOUT",
932 "FADEIN",
933 "FEATHER"
934 };
935
parse(const char * (* text))936 void idCameraEvent::parse( const char *( *text ) ) {
937 const char *token;
938 Com_MatchToken( text, "{" );
939 do {
940 token = Com_Parse( text );
941
942 if ( !token[0] ) {
943 break;
944 }
945 if ( !strcmp( token, "}" ) ) {
946 break;
947 }
948
949 // here we may have to jump over brush epairs ( only used in editor )
950 do {
951 // if token is not a brace, it is a key for a key/value pair
952 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
953 break;
954 }
955
956 Com_UngetToken();
957 idStr key = Com_ParseOnLine( text );
958 const char *token = Com_Parse( text );
959 if ( Q_stricmp( key.c_str(), "type" ) == 0 ) {
960 type = static_cast<idCameraEvent::eventType>( atoi( token ) );
961 } else if ( Q_stricmp( key.c_str(), "param" ) == 0 ) {
962 paramStr = token;
963 } else if ( Q_stricmp( key.c_str(), "time" ) == 0 ) {
964 time = atoi( token );
965 }
966 Com_Parse( text );
967
968 } while ( 1 );
969
970 if ( !strcmp( token, "}" ) ) {
971 break;
972 }
973
974 } while ( 1 );
975
976 Com_UngetToken();
977 Com_MatchToken( text, "}" );
978 }
979
write(fileHandle_t file,const char * name)980 void idCameraEvent::write( fileHandle_t file, const char *name ) {
981 idStr s = va( (char *)"\t%s {\n", name );
982 FS_Write( s.c_str(), s.length(), file );
983 s = va( (char *)"\t\ttype %d\n", static_cast<int>( type ) );
984 FS_Write( s.c_str(), s.length(), file );
985 s = va( (char *)"\t\tparam \"%s\"\n", paramStr.c_str() );
986 FS_Write( s.c_str(), s.length(), file );
987 s = va( (char *)"\t\ttime %ld\n", time );
988 FS_Write( s.c_str(), s.length(), file );
989 s = "\t}\n";
990 FS_Write( s.c_str(), s.length(), file );
991 }
992
993
994 const char *idCameraPosition::positionStr[] = {
995 "Fixed",
996 "Interpolated",
997 "Spline",
998 };
999
1000
1001
getPosition(long t)1002 const idVec3 *idInterpolatedPosition::getPosition( long t ) {
1003 static idVec3 interpolatedPos;
1004 float percent = 0.0;
1005 float velocity = getVelocity( t );
1006 float timePassed = t - lastTime;
1007 lastTime = t;
1008
1009 // convert to seconds
1010 timePassed /= 1000;
1011
1012 float distToTravel = timePassed * velocity;
1013
1014 idVec3 temp = startPos;
1015 temp -= endPos;
1016 float distance = temp.Length();
1017
1018 distSoFar += distToTravel;
1019
1020 // TTimo
1021 // show_bug.cgi?id=409
1022 // avoid NaN on fixed cameras
1023 if ( distance != 0.0 ) { //DAJ added to protect DBZ
1024 percent = (float)( distSoFar ) / distance;
1025 }
1026
1027 if ( percent > 1.0 ) {
1028 percent = 1.0;
1029 } else if ( percent < 0.0 ) {
1030 percent = 0.0;
1031 }
1032
1033 // the following line does a straigt calc on percentage of time
1034 // float percent = (float)(startTime + time - t) / time;
1035
1036 idVec3 v1 = startPos;
1037 idVec3 v2 = endPos;
1038 v1 *= ( 1.0 - percent );
1039 v2 *= percent;
1040 v1 += v2;
1041 interpolatedPos = v1;
1042 return &interpolatedPos;
1043 }
1044
1045
parse(const char * (* text))1046 void idCameraFOV::parse( const char *( *text ) ) {
1047 const char *token;
1048 Com_MatchToken( text, "{" );
1049 do {
1050 token = Com_Parse( text );
1051
1052 if ( !token[0] ) {
1053 break;
1054 }
1055 if ( !strcmp( token, "}" ) ) {
1056 break;
1057 }
1058
1059 // here we may have to jump over brush epairs ( only used in editor )
1060 do {
1061 // if token is not a brace, it is a key for a key/value pair
1062 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1063 break;
1064 }
1065
1066 Com_UngetToken();
1067 idStr key = Com_ParseOnLine( text );
1068 const char *token = Com_Parse( text );
1069 if ( Q_stricmp( key.c_str(), "fov" ) == 0 ) {
1070 fov = atof( token );
1071 } else if ( Q_stricmp( key.c_str(), "startFOV" ) == 0 ) {
1072 startFOV = atof( token );
1073 } else if ( Q_stricmp( key.c_str(), "endFOV" ) == 0 ) {
1074 endFOV = atof( token );
1075 } else if ( Q_stricmp( key.c_str(), "time" ) == 0 ) {
1076 time = atoi( token );
1077 }
1078 Com_Parse( text );
1079
1080 } while ( 1 );
1081
1082 if ( !strcmp( token, "}" ) ) {
1083 break;
1084 }
1085
1086 } while ( 1 );
1087
1088 Com_UngetToken();
1089 Com_MatchToken( text, "}" );
1090 }
1091
parseToken(const char * key,const char * (* text))1092 bool idCameraPosition::parseToken( const char *key, const char *( *text ) ) {
1093 const char *token = Com_Parse( text );
1094 if ( Q_stricmp( key, "time" ) == 0 ) {
1095 time = atol( token );
1096 return true;
1097 } else if ( Q_stricmp( key, "type" ) == 0 ) {
1098 type = static_cast<idCameraPosition::positionType>( atoi( token ) );
1099 return true;
1100 } else if ( Q_stricmp( key, "velocity" ) == 0 ) {
1101 long t = atol( token );
1102 token = Com_Parse( text );
1103 long d = atol( token );
1104 token = Com_Parse( text );
1105 float s = atof( token );
1106 addVelocity( t, d, s );
1107 return true;
1108 } else if ( Q_stricmp( key, "baseVelocity" ) == 0 ) {
1109 baseVelocity = atof( token );
1110 return true;
1111 } else if ( Q_stricmp( key, "name" ) == 0 ) {
1112 name = token;
1113 return true;
1114 } else if ( Q_stricmp( key, "time" ) == 0 ) {
1115 time = atoi( token );
1116 return true;
1117 }
1118 Com_UngetToken();
1119 return false;
1120 }
1121
1122
1123
parse(const char * (* text))1124 void idFixedPosition::parse( const char *( *text ) ) {
1125 const char *token;
1126 Com_MatchToken( text, "{" );
1127 do {
1128 token = Com_Parse( text );
1129
1130 if ( !token[0] ) {
1131 break;
1132 }
1133 if ( !strcmp( token, "}" ) ) {
1134 break;
1135 }
1136
1137 // here we may have to jump over brush epairs ( only used in editor )
1138 do {
1139 // if token is not a brace, it is a key for a key/value pair
1140 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1141 break;
1142 }
1143
1144 Com_UngetToken();
1145 idStr key = Com_ParseOnLine( text );
1146
1147 Com_Parse( text );
1148 if ( Q_stricmp( key.c_str(), "pos" ) == 0 ) {
1149 Com_UngetToken();
1150 Com_Parse1DMatrix( text, 3, pos );
1151 } else {
1152 Com_UngetToken();
1153 idCameraPosition::parseToken( key.c_str(), text );
1154 }
1155 Com_Parse( text );
1156
1157 } while ( 1 );
1158
1159 if ( !strcmp( token, "}" ) ) {
1160 break;
1161 }
1162
1163 } while ( 1 );
1164
1165 Com_UngetToken();
1166 Com_MatchToken( text, "}" );
1167 }
1168
parse(const char * (* text))1169 void idInterpolatedPosition::parse( const char *( *text ) ) {
1170 const char *token;
1171 Com_MatchToken( text, "{" );
1172 do {
1173 token = Com_Parse( text );
1174
1175 if ( !token[0] ) {
1176 break;
1177 }
1178 if ( !strcmp( token, "}" ) ) {
1179 break;
1180 }
1181
1182 // here we may have to jump over brush epairs ( only used in editor )
1183 do {
1184 // if token is not a brace, it is a key for a key/value pair
1185 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1186 break;
1187 }
1188
1189 Com_UngetToken();
1190 idStr key = Com_ParseOnLine( text );
1191
1192 Com_Parse( text );
1193 if ( Q_stricmp( key.c_str(), "startPos" ) == 0 ) {
1194 Com_UngetToken();
1195 Com_Parse1DMatrix( text, 3, startPos );
1196 } else if ( Q_stricmp( key.c_str(), "endPos" ) == 0 ) {
1197 Com_UngetToken();
1198 Com_Parse1DMatrix( text, 3, endPos );
1199 } else {
1200 Com_UngetToken();
1201 idCameraPosition::parseToken( key.c_str(), text );
1202 }
1203 Com_Parse( text );
1204
1205 } while ( 1 );
1206
1207 if ( !strcmp( token, "}" ) ) {
1208 break;
1209 }
1210
1211 } while ( 1 );
1212
1213 Com_UngetToken();
1214 Com_MatchToken( text, "}" );
1215 }
1216
1217
parse(const char * (* text))1218 void idSplinePosition::parse( const char *( *text ) ) {
1219 const char *token;
1220 Com_MatchToken( text, "{" );
1221 do {
1222 token = Com_Parse( text );
1223
1224 if ( !token[0] ) {
1225 break;
1226 }
1227 if ( !strcmp( token, "}" ) ) {
1228 break;
1229 }
1230
1231 // here we may have to jump over brush epairs ( only used in editor )
1232 do {
1233 // if token is not a brace, it is a key for a key/value pair
1234 if ( !token[0] || !strcmp( token, "(" ) || !strcmp( token, "}" ) ) {
1235 break;
1236 }
1237
1238 Com_UngetToken();
1239 idStr key = Com_ParseOnLine( text );
1240
1241 Com_Parse( text );
1242 if ( Q_stricmp( key.c_str(), "target" ) == 0 ) {
1243 target.parse( text );
1244 } else {
1245 Com_UngetToken();
1246 idCameraPosition::parseToken( key.c_str(), text );
1247 }
1248 Com_Parse( text );
1249
1250 } while ( 1 );
1251
1252 if ( !strcmp( token, "}" ) ) {
1253 break;
1254 }
1255
1256 } while ( 1 );
1257
1258 Com_UngetToken();
1259 Com_MatchToken( text, "}" );
1260 }
1261
1262
1263
write(fileHandle_t file,const char * p)1264 void idCameraFOV::write( fileHandle_t file, const char *p ) {
1265 idStr s = va( (char *)"\t%s {\n", p );
1266 FS_Write( s.c_str(), s.length(), file );
1267
1268 s = va( (char *)"\t\tfov %f\n", fov );
1269 FS_Write( s.c_str(), s.length(), file );
1270
1271 s = va( (char *)"\t\tstartFOV %f\n", startFOV );
1272 FS_Write( s.c_str(), s.length(), file );
1273
1274 s = va( (char *)"\t\tendFOV %f\n", endFOV );
1275 FS_Write( s.c_str(), s.length(), file );
1276
1277 s = va( (char *)"\t\ttime %i\n", time );
1278 FS_Write( s.c_str(), s.length(), file );
1279
1280 s = "\t}\n";
1281 FS_Write( s.c_str(), s.length(), file );
1282 }
1283
1284
write(fileHandle_t file,const char * p)1285 void idCameraPosition::write( fileHandle_t file, const char *p ) {
1286
1287 idStr s = va( (char *)"\t\ttime %li\n", time );
1288 FS_Write( s.c_str(), s.length(), file );
1289
1290 s = va( (char *)"\t\ttype %i\n", static_cast<int>( type ) );
1291 FS_Write( s.c_str(), s.length(), file );
1292
1293 s = va( (char *)"\t\tname %s\n", name.c_str() );
1294 FS_Write( s.c_str(), s.length(), file );
1295
1296 s = va( (char *)"\t\tbaseVelocity %f\n", baseVelocity );
1297 FS_Write( s.c_str(), s.length(), file );
1298
1299 for ( int i = 0; i < velocities.Num(); i++ ) {
1300 s = va( (char *)"\t\tvelocity %li %li %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed );
1301 FS_Write( s.c_str(), s.length(), file );
1302 }
1303
1304 }
1305
write(fileHandle_t file,const char * p)1306 void idFixedPosition::write( fileHandle_t file, const char *p ) {
1307 idStr s = va( (char *)"\t%s {\n", p );
1308 FS_Write( s.c_str(), s.length(), file );
1309 idCameraPosition::write( file, p );
1310 s = va( (char *)"\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z );
1311 FS_Write( s.c_str(), s.length(), file );
1312 s = "\t}\n";
1313 FS_Write( s.c_str(), s.length(), file );
1314 }
1315
write(fileHandle_t file,const char * p)1316 void idInterpolatedPosition::write( fileHandle_t file, const char *p ) {
1317 idStr s = va( (char *)"\t%s {\n", p );
1318 FS_Write( s.c_str(), s.length(), file );
1319 idCameraPosition::write( file, p );
1320 s = va( (char *)"\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z );
1321 FS_Write( s.c_str(), s.length(), file );
1322 s = va( (char *)"\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z );
1323 FS_Write( s.c_str(), s.length(), file );
1324 s = "\t}\n";
1325 FS_Write( s.c_str(), s.length(), file );
1326 }
1327
write(fileHandle_t file,const char * p)1328 void idSplinePosition::write( fileHandle_t file, const char *p ) {
1329 idStr s = va( (char *)"\t%s {\n", p );
1330 FS_Write( s.c_str(), s.length(), file );
1331 idCameraPosition::write( file, p );
1332 target.write( file, "target" );
1333 s = "\t}\n";
1334 FS_Write( s.c_str(), s.length(), file );
1335 }
1336
addTarget(const char * name,idCameraPosition::positionType type)1337 void idCameraDef::addTarget( const char *name, idCameraPosition::positionType type ) {
1338 // TTimo: unused
1339 //const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;
1340 idCameraPosition *pos = newFromType( type );
1341 if ( pos ) {
1342 pos->setName( name );
1343 targetPositions.Append( pos );
1344 activeTarget = numTargets() - 1;
1345 if ( activeTarget == 0 ) {
1346 // first one
1347 addEvent( idCameraEvent::EVENT_TARGET, name, 0 );
1348 }
1349 }
1350 }
1351
getPosition(long t)1352 const idVec3 *idSplinePosition::getPosition( long t ) {
1353 static idVec3 interpolatedPos;
1354
1355 float velocity = getVelocity( t );
1356 float timePassed = t - lastTime;
1357 lastTime = t;
1358
1359 // convert to seconds
1360 timePassed /= 1000;
1361
1362 float distToTravel = timePassed * velocity;
1363
1364 distSoFar += distToTravel;
1365 double tempDistance = target.totalDistance();
1366
1367 double percent = (double)( distSoFar ) / tempDistance;
1368
1369 double targetDistance = percent * tempDistance;
1370 tempDistance = 0;
1371
1372 double lastDistance1,lastDistance2;
1373 lastDistance1 = lastDistance2 = 0;
1374 //FIXME: calc distances on spline build
1375 idVec3 temp;
1376 int count = target.numSegments();
1377 // TTimo fixed MSVCism
1378 int i;
1379 for ( i = 1; i < count; i++ ) {
1380 temp = *target.getSegmentPoint( i - 1 );
1381 temp -= *target.getSegmentPoint( i );
1382 tempDistance += temp.Length();
1383 if ( i & 1 ) {
1384 lastDistance1 = tempDistance;
1385 } else {
1386 lastDistance2 = tempDistance;
1387 }
1388 if ( tempDistance >= targetDistance ) {
1389 break;
1390 }
1391 }
1392
1393 if ( i >= count - 1 ) {
1394 interpolatedPos = *target.getSegmentPoint( i - 1 );
1395 } else {
1396 #if 0
1397 double timeHi = target.getSegmentTime( i + 1 );
1398 double timeLo = target.getSegmentTime( i - 1 );
1399 double percent = ( timeHi - t ) / ( timeHi - timeLo );
1400 idVec3 v1 = *target.getSegmentPoint( i - 1 );
1401 idVec3 v2 = *target.getSegmentPoint( i + 1 );
1402 v2 *= ( 1.0 - percent );
1403 v1 *= percent;
1404 v2 += v1;
1405 interpolatedPos = v2;
1406 #else
1407 if ( lastDistance1 > lastDistance2 ) {
1408 double d = lastDistance2;
1409 lastDistance2 = lastDistance1;
1410 lastDistance1 = d;
1411 }
1412
1413 idVec3 v1 = *target.getSegmentPoint( i - 1 );
1414 idVec3 v2 = *target.getSegmentPoint( i );
1415 double percent = ( lastDistance2 - targetDistance ) / ( lastDistance2 - lastDistance1 );
1416 v2 *= ( 1.0 - percent );
1417 v1 *= percent;
1418 v2 += v1;
1419 interpolatedPos = v2;
1420 #endif
1421 }
1422 return &interpolatedPos;
1423
1424 }
1425
1426
1427
1428