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