]> icculus.org git repositories - icculus/iodoom3.git/blob - neo/tools/radiant/splines.cpp
hello world
[icculus/iodoom3.git] / neo / tools / radiant / splines.cpp
1 /*
2 ===========================================================================
3
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company. 
6
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).  
8
9 Doom 3 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 Doom 3 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 Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21
22 In addition, the Doom 3 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 Doom 3 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 "../../idlib/precompiled.h"
30 #pragma hdrstop
31
32 #include "splines.h"
33
34 idCameraDef splineList;
35 idCameraDef *g_splineList = &splineList;
36
37 /*
38 ================
39 glLabeledPoint
40 ================
41 */
42 void glLabeledPoint(idVec4 &color, idVec3 &point, float size, const char *label) {
43         qglColor3fv( color.ToFloatPtr() );
44         qglPointSize( size );
45         qglBegin( GL_POINTS );
46         qglVertex3fv( point.ToFloatPtr() );
47         qglEnd();
48         idVec3 v = point;
49         v.x += 1;
50         v.y += 1;
51         v.z += 1;
52         qglRasterPos3fv( v.ToFloatPtr() );
53         qglCallLists( strlen(label), GL_UNSIGNED_BYTE, label );
54 }
55
56 /*
57 ================
58 glBox
59 ================
60 */
61 void glBox(idVec4 &color, idVec3 &point, float size) {
62         idVec3 mins(point);
63         idVec3 maxs(point);
64         mins[0] -= size;
65         mins[1] += size;
66         mins[2] -= size;
67         maxs[0] += size;
68         maxs[1] -= size;
69         maxs[2] += size;
70         idVec4  saveColor;
71         qglGetFloatv(GL_CURRENT_COLOR, saveColor.ToFloatPtr());
72         qglColor3fv( color.ToFloatPtr() );
73         qglBegin(GL_LINE_LOOP);
74         qglVertex3f(mins[0],mins[1],mins[2]);
75         qglVertex3f(maxs[0],mins[1],mins[2]);
76         qglVertex3f(maxs[0],maxs[1],mins[2]);
77         qglVertex3f(mins[0],maxs[1],mins[2]);
78         qglEnd();
79         qglBegin(GL_LINE_LOOP);
80         qglVertex3f(mins[0],mins[1],maxs[2]);
81         qglVertex3f(maxs[0],mins[1],maxs[2]);
82         qglVertex3f(maxs[0],maxs[1],maxs[2]);
83         qglVertex3f(mins[0],maxs[1],maxs[2]);
84         qglEnd();
85
86         qglBegin(GL_LINES);
87         qglVertex3f(mins[0],mins[1],mins[2]);
88         qglVertex3f(mins[0],mins[1],maxs[2]);
89         qglVertex3f(mins[0],maxs[1],maxs[2]);
90         qglVertex3f(mins[0],maxs[1],mins[2]);
91         qglVertex3f(maxs[0],mins[1],mins[2]);
92         qglVertex3f(maxs[0],mins[1],maxs[2]);
93         qglVertex3f(maxs[0],maxs[1],maxs[2]);
94         qglVertex3f(maxs[0],maxs[1],mins[2]);
95         qglEnd();
96         qglColor4fv(saveColor.ToFloatPtr());
97
98 }
99
100 /*
101 ================
102 splineTest
103 ================
104 */
105 void splineTest() {
106         //g_splineList->load("p:/doom/base/maps/test_base1.camera");
107 }
108
109 /*
110 ================
111 splineDraw
112 ================
113 */
114 void splineDraw() {
115         //g_splineList->addToRenderer();
116 }
117
118 /*
119 ================
120 debugLine
121 ================
122 */
123 void debugLine(idVec4 &color, float x, float y, float z, float x2, float y2, float z2) {
124         idVec3 from(x, y, z);
125         idVec3 to(x2, y2, z2);
126         session->rw->DebugLine(color, from, to);
127 }
128
129
130 /*
131 =================================================================================
132
133 idPointListInterface
134
135 =================================================================================
136 */
137
138 /*
139 ================
140 idPointListInterface::selectPointByRay
141 ================
142 */
143 int idPointListInterface::selectPointByRay(const idVec3 &origin, const idVec3 &direction, bool single) {
144         int             i, besti, count;
145         float   d, bestd;
146         idVec3  temp, temp2;
147
148         // find the point closest to the ray
149         besti = -1;
150         bestd = 8;
151         count = numPoints();
152
153         for (i=0; i < count; i++) {
154                 temp = *getPoint(i);
155                 temp2 = temp;
156                 temp -= origin;
157                 d = DotProduct(temp, direction);
158                 VectorMA (origin, d, direction, temp);
159                 temp2 -= temp;
160                 d = temp2.Length();
161                 if (d <= bestd) {
162                         bestd = d;
163                         besti = i;
164                 }
165         }
166
167         if (besti >= 0) {
168                 selectPoint(besti, single);
169         }
170
171         return besti;
172 }
173
174 /*
175 ================
176 idPointListInterface::isPointSelected
177 ================
178 */
179 int idPointListInterface::isPointSelected(int index) {
180         int count = selectedPoints.Num();
181         for (int i = 0; i < count; i++) {
182                 if (selectedPoints[i] == index) {
183                         return i;
184                 }
185         }
186         return -1;
187 }
188
189 /*
190 ================
191 idPointListInterface::selectPoint
192 ================
193 */
194 int idPointListInterface::selectPoint(int index, bool single) {
195         if (index >= 0 && index < numPoints()) {
196                 if (single) {
197                         deselectAll();
198                 } else {
199                         if (isPointSelected(index) >= 0) {
200                                 selectedPoints.Remove(index);
201                         }
202                 }
203                 return selectedPoints.Append(index);
204         }
205         return -1;
206 }
207
208 /*
209 ================
210 idPointListInterface::selectAll
211 ================
212 */
213 void idPointListInterface::selectAll() {
214         selectedPoints.Clear();
215         for (int i = 0; i < numPoints(); i++) {
216                 selectedPoints.Append(i);
217         }
218 }
219
220 /*
221 ================
222 idPointListInterface::deselectAll
223 ================
224 */
225 void idPointListInterface::deselectAll() {
226         selectedPoints.Clear();
227 }
228
229 /*
230 ================
231 idPointListInterface::getSelectedPoint
232 ================
233 */
234 idVec3 *idPointListInterface::getSelectedPoint( int index ) {
235         assert(index >= 0 && index < numSelectedPoints());
236         return getPoint(selectedPoints[index]);
237 }
238
239 /*
240 ================
241 idPointListInterface::updateSelection
242 ================
243 */
244 void idPointListInterface::updateSelection(const idVec3 &move) {
245         int count = selectedPoints.Num();
246         for (int i = 0; i < count; i++) {
247                 *getPoint(selectedPoints[i]) += move;
248         }
249 }
250
251 /*
252 ================
253 idPointListInterface::drawSelection
254 ================
255 */
256 void idPointListInterface::drawSelection() {
257         int count = selectedPoints.Num();
258         for (int i = 0; i < count; i++) {
259                 glBox(colorRed, *getPoint(selectedPoints[i]), 4);
260         }
261 }
262
263 /*
264 =================================================================================
265
266 idSplineList
267
268 =================================================================================
269 */
270
271 /*
272 ================
273 idSplineList::clearControl
274 ================
275 */
276 void idSplineList::clearControl() {
277         for (int i = 0; i < controlPoints.Num(); i++) {
278                 delete controlPoints[i];
279         }
280         controlPoints.Clear();
281 }
282
283 /*
284 ================
285 idSplineList::clearSpline
286 ================
287 */
288 void idSplineList::clearSpline() {
289         for (int i = 0; i < splinePoints.Num(); i++) {
290                 delete splinePoints[i];
291         }
292         splinePoints.Clear();
293 }
294
295 /*
296 ================
297 idSplineList::clear
298 ================
299 */
300 void idSplineList::clear() {
301         clearControl();
302         clearSpline();
303         splineTime.Clear();
304         selected = NULL;
305         dirty = true;
306         activeSegment = 0;
307         granularity = 0.025f;
308         pathColor = idVec4(1.0f, 0.5f, 0.0f, 1.0f);
309         controlColor = idVec4(0.7f, 0.0f, 1.0f, 1.0f);
310         segmentColor = idVec4(0.0f, 0.0f, 1.0f, 1.0);
311         activeColor = idVec4(1.0f, 0.0f, 0.0f, 1.0f);
312 }
313
314 /*
315 ================
316 idSplineList::setColors
317 ================
318 */
319 void idSplineList::setColors(idVec4 &path, idVec4 &segment, idVec4 &control, idVec4 &active) {
320         pathColor = path;
321         segmentColor = segment;
322         controlColor = control;
323         activeColor = active;
324 }
325
326 /*
327 ================
328 idSplineList::validTime
329 ================
330 */
331 bool idSplineList::validTime() {
332         if (dirty) {
333                 buildSpline();
334         }
335         // gcc doesn't allow static casting away from bools
336         // why?  I've no idea...
337         return (bool)(splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num());
338 }
339
340 /*
341 ================
342 idSplineList::addToRenderer
343 ================
344 */
345 void idSplineList::addToRenderer() {
346         int i;
347         idVec3 mins, maxs;
348
349         if (controlPoints.Num() == 0) {
350                 return;
351         }
352         
353         for(i = 0; i < controlPoints.Num(); i++) {
354                 VectorCopy(*controlPoints[i], mins);
355                 VectorCopy(mins, maxs);
356                 mins[0] -= 8;
357                 mins[1] += 8;
358                 mins[2] -= 8;
359                 maxs[0] += 8;
360                 maxs[1] -= 8;
361                 maxs[2] += 8;
362                 debugLine( colorYellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
363                 debugLine( colorYellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
364                 debugLine( colorYellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
365                 debugLine( colorYellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
366                 
367                 debugLine( colorYellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
368                 debugLine( colorYellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
369                 debugLine( colorYellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
370                 debugLine( colorYellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
371             
372         }
373
374         int step = 0;
375         idVec3 step1;
376         for(i = 3; i < controlPoints.Num(); i++) {
377                 for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
378                         float x = 0;
379                         float y = 0;
380                         float z = 0;
381                         for (int j = 0; j < 4; j++) {
382                                 x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
383                                 y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
384                                 z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
385                         }
386                         if (step == 0) {
387                                 step1[0] = x;
388                                 step1[1] = y;
389                                 step1[2] = z;
390                                 step = 1;
391                         } else {
392                                 debugLine( colorWhite, step1[0], step1[1], step1[2], x, y, z);
393                                 step = 0;
394                         }
395
396                 }
397         }
398 }
399
400 /*
401 ================
402 idSplineList::buildSpline
403 ================
404 */
405 void idSplineList::buildSpline() {
406         int start = Sys_Milliseconds();
407         clearSpline();
408         for(int i = 3; i < controlPoints.Num(); i++) {
409                 for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
410                         float x = 0;
411                         float y = 0;
412                         float z = 0;
413                         for (int j = 0; j < 4; j++) {
414                                 x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
415                                 y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
416                                 z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
417                         }
418                         splinePoints.Append(new idVec3(x, y, z));
419                 }
420         }
421         dirty = false;
422         //common->Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
423 }
424
425 /*
426 ================
427 idSplineList::draw
428 ================
429 */
430 void idSplineList::draw(bool editMode) {
431         int i;
432         
433         if (controlPoints.Num() == 0) {
434                 return;
435         }
436
437         if (dirty) {
438                 buildSpline();
439         }
440
441
442         qglColor3fv( controlColor.ToFloatPtr() );
443         qglPointSize( 5 );
444         
445         qglBegin(GL_POINTS);
446         for (i = 0; i < controlPoints.Num(); i++) {
447                 qglVertex3fv( (*controlPoints[i]).ToFloatPtr() );
448         }
449         qglEnd();
450         
451         if (editMode) {
452                 for(i = 0; i < controlPoints.Num(); i++) {
453                         glBox(activeColor, *controlPoints[i], 4);
454                 }
455         }
456
457         //Draw the curve
458         qglColor3fv( pathColor.ToFloatPtr() );
459         qglBegin(GL_LINE_STRIP);
460         int count = splinePoints.Num();
461         for (i = 0; i < count; i++) {
462                 qglVertex3fv( (*splinePoints[i]).ToFloatPtr() );
463         }
464         qglEnd();
465
466         if (editMode) {
467                 qglColor3fv( segmentColor.ToFloatPtr() );
468                 qglPointSize(3);
469                 qglBegin(GL_POINTS);
470                 for (i = 0; i < count; i++) {
471                         qglVertex3fv( (*splinePoints[i]).ToFloatPtr() );
472                 }
473                 qglEnd();
474         }
475         if (count > 0) {
476                 //assert(activeSegment >=0 && activeSegment < count);
477                 if (activeSegment >=0 && activeSegment < count) {
478                         glBox(activeColor, *splinePoints[activeSegment], 6);
479                         glBox(colorYellow, *splinePoints[activeSegment], 8);
480                 }
481         }
482
483 }
484
485 /*
486 ================
487 idSplineList::totalDistance
488 ================
489 */
490 float idSplineList::totalDistance() {
491
492         // FIXME: save dist and return
493         // 
494         if (controlPoints.Num() == 0) {
495                 return 0.0f;
496         }
497
498         if (dirty) {
499                 buildSpline();
500         }
501
502         float dist = 0.0f;
503         idVec3 temp;
504         int count = splinePoints.Num();
505         for(int i = 1; i < count; i++) {
506                 temp = *splinePoints[i-1];
507                 temp -= *splinePoints[i];
508                 dist += temp.Length();
509         }
510         return dist;
511 }
512
513 /*
514 ================
515 idSplineList::initPosition
516 ================
517 */
518 void idSplineList::initPosition(long bt, long totalTime) {
519
520         if (dirty) {
521                 buildSpline();
522         }
523
524         if (splinePoints.Num() == 0) {
525                 return;
526         }
527
528         baseTime = bt;
529         time = totalTime;
530
531         // calc distance to travel ( this will soon be broken into time segments )
532         splineTime.Clear();
533         splineTime.Append(bt);
534         double dist = totalDistance();
535         double distSoFar = 0.0;
536         idVec3 temp;
537         int count = splinePoints.Num();
538         //for(int i = 2; i < count - 1; i++) {
539         for(int i = 1; i < count; i++) {
540                 temp = *splinePoints[i-1];
541                 temp -= *splinePoints[i];
542                 distSoFar += temp.Length();
543                 double percent = distSoFar / dist;
544                 percent *= totalTime;
545                 splineTime.Append(percent + bt);
546         }
547         assert(splineTime.Num() == splinePoints.Num());
548         activeSegment = 0;
549 }
550
551 /*
552 ================
553 idSplineList::calcSpline
554 ================
555 */
556 float idSplineList::calcSpline(int step, float tension) {
557         switch(step) {
558                 case 0: return (pow(1 - tension, 3)) / 6;
559                 case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
560                 case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
561                 case 3: return pow(tension, 3) / 6;
562         }
563         return 0.0f;
564 }
565
566 /*
567 ================
568 idSplineList::updateSelection
569 ================
570 */
571 void idSplineList::updateSelection(const idVec3 &move) {
572         if (selected) {
573                 dirty = true;
574                 VectorAdd(*selected, move, *selected);
575         }
576 }
577
578 /*
579 ================
580 idSplineList::setSelectedPoint
581 ================
582 */
583 void idSplineList::setSelectedPoint(idVec3 *p) {
584         if (p) {
585                 p->SnapInt();
586                 for(int i = 0; i < controlPoints.Num(); i++) {
587                         if ( (*p).Compare( *controlPoints[i], VECTOR_EPSILON ) ) {
588                                 selected = controlPoints[i];
589                         }
590                 }
591         } else {
592                 selected = NULL;
593         }
594 }
595
596 /*
597 ================
598 idSplineList::getPosition
599 ================
600 */
601 const idVec3 *idSplineList::getPosition(long t) {
602         static idVec3 interpolatedPos;
603
604         int count = splineTime.Num();
605         if (count == 0) {
606                 return &vec3_zero;
607         }
608
609         assert(splineTime.Num() == splinePoints.Num());
610
611 #if 0
612         float velocity = getVelocity(t);
613         float timePassed = t - lastTime;
614         lastTime = t;
615
616         // convert to seconds   
617         timePassed /= 1000;
618
619         float distToTravel = timePassed * velocity;
620
621         distSoFar += distToTravel;
622         float tempDistance = 0;
623
624         idVec3 temp;
625         int count = splinePoints.Num();
626         //for(int i = 2; i < count - 1; i++) {
627         for(int i = 1; i < count; i++) {
628                 temp = *splinePoints[i-1];
629                 temp -= *splinePoints[i];
630                 tempDistance += temp.Length();
631                 if (tempDistance >= distSoFar) {
632                         break;
633                 }
634         }
635
636         if (i == count) {
637                 interpolatedPos = splinePoints[i-1];
638         } else {
639                 double timeHi = splineTime[i + 1];
640                 double timeLo = splineTime[i - 1];
641                 double percent = (timeHi - t) / (timeHi - timeLo); 
642                 idVec3 v1 = *splinePoints[i - 1];
643                 idVec3 v2 = *splinePoints[i + 1];
644                 v2 *= (1.0f - percent);
645                 v1 *= percent;
646                 v2 += v1;
647                 interpolatedPos = v2;
648         }
649         return &interpolatedPos;
650
651 #else
652         while (activeSegment < count) {
653                 if (splineTime[activeSegment] >= t) {
654                         if (activeSegment > 0 && activeSegment < count - 1) {
655                                 double timeHi = splineTime[activeSegment + 1];
656                                 double timeLo = splineTime[activeSegment - 1];
657                                 //float percent = (float)(baseTime + time - t) / time;
658                                 double percent = (timeHi - t) / (timeHi - timeLo); 
659                                 // pick two bounding points
660                                 idVec3 v1 = *splinePoints[activeSegment-1];
661                                 idVec3 v2 = *splinePoints[activeSegment+1];
662                                 v2 *= (1.0f - percent);
663                                 v1 *= percent;
664                                 v2 += v1;
665                                 interpolatedPos = v2;
666                                 return &interpolatedPos;
667                         }
668                         return splinePoints[activeSegment];
669                 } else {
670                         activeSegment++;
671                 }
672         }
673         return splinePoints[count-1];
674 #endif
675 }
676
677 /*
678 ================
679 idSplineList::parse
680 ================
681 */
682 void idSplineList::parse( idParser *src ) {
683         idToken token;
684         idStr key;
685
686         src->ExpectTokenString( "{" );
687
688         while ( 1 ) {
689                 if ( !src->ExpectAnyToken( &token ) ) {
690                         break;
691                 }
692                 if ( token == "}" ) {
693                         break;
694                 }
695                 // if token is not a brace, it is a key for a key/value pair
696                 if ( token == "(" ) {
697                         src->UnreadToken( &token );
698                         // read the control point
699                         idVec3 point;
700                         src->Parse1DMatrix( 3, point.ToFloatPtr() );
701                         addPoint(point.x, point.y, point.z);
702                 }
703                 else {
704                         key = token;
705                         src->ReadTokenOnLine( &token );
706                         if ( !key.Icmp( "granularity" ) ) {
707                                 granularity = atof(token.c_str());
708                         }
709                         else if ( !key.Icmp( "name" ) ) {
710                                 name = token;
711                         }
712                         else {
713                                 src->Error( "unknown spline list key: %s", key.c_str() );
714                                 break;
715                         }
716                 }
717         }
718         dirty = true;
719 }
720
721 /*
722 ================
723 idSplineList::write
724 ================
725 */
726 void idSplineList::write( idFile *f, const char *p) {
727         f->Printf( "\t\t%s {\n", p );
728
729         //f->Printf( "\t\tname %s\n", name.c_str() );
730         f->Printf( "\t\t\tgranularity %f\n", granularity );
731         int count = controlPoints.Num();
732         for (int i = 0; i < count; i++) {
733                 f->Printf( "\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z );
734         }
735         f->Printf( "\t\t}\n" );
736 }
737
738 /*
739 =================================================================================
740
741 idCamaraDef
742
743 =================================================================================
744 */
745
746 /*
747 ================
748 idCameraDef::clear
749 ================
750 */
751 void idCameraDef::clear() {
752         currentCameraPosition = 0;
753         cameraRunning = false;
754         lastDirection.Zero();
755         baseTime = 30;
756         activeTarget = 0;
757         name = "camera01";
758         fov.SetFOV(90);
759         int i;
760         for (i = 0; i < targetPositions.Num(); i++) {
761                 delete targetPositions[i];
762         }
763         for (i = 0; i < events.Num(); i++) {
764                 delete events[i];
765         }
766         delete cameraPosition;
767         cameraPosition = NULL;
768         events.Clear();
769         targetPositions.Clear();
770 }
771
772 /*
773 ================
774 idCameraDef::startNewCamera
775 ================
776 */
777 idCameraPosition *idCameraDef::startNewCamera( idCameraPosition::positionType type ) {
778         clear();
779         if (type == idCameraPosition::SPLINE) {
780                 cameraPosition = new idSplinePosition();
781         } else if (type == idCameraPosition::INTERPOLATED) {
782                 cameraPosition = new idInterpolatedPosition();
783         } else {
784                 cameraPosition = new idFixedPosition();
785         }
786         return cameraPosition;
787 }
788
789 /*
790 ================
791 idCameraDef::addTarget
792 ================
793 */
794 void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {
795         const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;
796         idCameraPosition *pos = newFromType(type);
797         if (pos) {
798                 pos->setName(name);
799                 targetPositions.Append(pos);
800                 activeTarget = numTargets()-1;
801                 if (activeTarget == 0) {
802                         // first one
803                         addEvent(idCameraEvent::EVENT_TARGET, name, 0);
804                 }
805         }
806 }
807
808 /*
809 ================
810 idCameraDef::getActiveTarget
811 ================
812 */
813 idCameraPosition *idCameraDef::getActiveTarget() {
814         if (targetPositions.Num() == 0) {
815                 addTarget(NULL, idCameraPosition::FIXED);
816         }
817         return targetPositions[activeTarget];
818 }
819
820 /*
821 ================
822 idCameraDef::getActiveTarget
823 ================
824 */
825 idCameraPosition *idCameraDef::getActiveTarget(int index) {
826         if (targetPositions.Num() == 0) {
827                 addTarget(NULL, idCameraPosition::FIXED);
828                 return targetPositions[0];
829         }
830         return targetPositions[index];
831 }
832
833 /*
834 ================
835 idCameraDef::setActiveTargetByName
836 ================
837 */
838 void idCameraDef::setActiveTargetByName( const char *name ) {
839         for (int i = 0; i < targetPositions.Num(); i++) {
840                 if (idStr::Icmp(name, targetPositions[i]->getName()) == 0) {
841                         setActiveTarget(i);
842                         return;
843                 }
844         }
845 }
846
847 /*
848 ================
849 idCameraDef::setActiveTarget
850 ================
851 */
852 void idCameraDef::setActiveTarget( int index ) {
853         assert(index >= 0 && index < targetPositions.Num());
854         activeTarget = index;
855 }
856
857 /*
858 ================
859 idCameraDef::draw
860 ================
861 */
862 void idCameraDef::draw( bool editMode ) {
863             // gcc doesn't allow casting away from bools
864             // why?  I've no idea...
865         if (cameraPosition) {
866                 cameraPosition->draw((bool)((editMode || cameraRunning) && cameraEdit));
867                 int count = targetPositions.Num();
868                 for (int i = 0; i < count; i++) {
869                         targetPositions[i]->draw((bool)((editMode || cameraRunning) && i == activeTarget && !cameraEdit));
870                 }
871         }
872 }
873
874 /*
875 ================
876 idCameraDef::numPoints
877 ================
878 */
879 int idCameraDef::numPoints() {
880         if (cameraEdit) {
881                 return cameraPosition->numPoints();
882         }
883         return getActiveTarget()->numPoints();
884 }
885
886 /*
887 ================
888 idCameraDef::getPoint
889 ================
890 */
891 const idVec3 *idCameraDef::getPoint(int index) {
892         if (cameraEdit) {
893                 return cameraPosition->getPoint(index);
894         }
895         return getActiveTarget()->getPoint(index);
896 }
897
898 /*
899 ================
900 idCameraDef::stopEdit
901 ================
902 */
903 void idCameraDef::stopEdit() {
904         editMode = false;
905         if (cameraEdit) {
906                 cameraPosition->stopEdit();
907         } else {
908                 getActiveTarget()->stopEdit();
909         }
910 }
911
912 /*
913 ================
914 idCameraDef::startEdit
915 ================
916 */
917 void idCameraDef::startEdit(bool camera) {
918         cameraEdit = camera;
919         if (camera) {
920                 cameraPosition->startEdit();
921                 for (int i = 0; i < targetPositions.Num(); i++) {
922                         targetPositions[i]->stopEdit();
923                 }
924         } else {
925                 getActiveTarget()->startEdit();
926                 cameraPosition->stopEdit();
927         }
928         editMode = true;
929 }
930
931 /*
932 ================
933 idCameraDef::getPositionObj
934 ================
935 */
936 idCameraPosition *idCameraDef::getPositionObj() {
937         if (cameraPosition == NULL) {
938                 cameraPosition = new idFixedPosition();
939         }
940         return cameraPosition;
941 }
942
943 /*
944 ================
945 idCameraDef::getActiveSegmentInfo
946 ================
947 */
948 void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) {
949 #if 0
950         if (!cameraSpline.validTime()) {
951                 buildCamera();
952         }
953         double d = (double)segment / numSegments();
954         getCameraInfo(d * totalTime * 1000, origin, direction, fov);
955 #endif
956 /*
957         if (!cameraSpline.validTime()) {
958                 buildCamera();
959         }
960         origin = *cameraSpline.getSegmentPoint(segment);
961         
962
963         idVec3 temp;
964
965         int numTargets = getTargetSpline()->controlPoints.Num();
966         int count = cameraSpline.splineTime.Num();
967         if (numTargets == 0) {
968                 // follow the path
969                 if (cameraSpline.getActiveSegment() < count - 1) {
970                         temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
971                 }
972         } else if (numTargets == 1) {
973                 temp = *getTargetSpline()->controlPoints[0];
974         } else {
975                 temp = *getTargetSpline()->getSegmentPoint(segment);
976         }
977
978         temp -= origin;
979         temp.Normalize();
980         direction = temp;
981 */
982 }
983
984 /*
985 ================
986 idCameraDef::getCameraInfo
987 ================
988 */
989 bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) {
990         char    buff[ 1024 ];
991         int             i;
992
993         if ((time - startTime) / 1000 <= totalTime) {
994
995                 for( i = 0; i < events.Num(); i++ ) {
996                         if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {
997                                 events[i]->setTriggered(true);
998                                 if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {
999                                         setActiveTargetByName(events[i]->getParam());
1000                                         getActiveTarget()->start(startTime + events[i]->getTime());
1001                                         //common->Printf("Triggered event switch to target: %s\n",events[i]->getParam());
1002                                 } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {
1003 #if 0
1004 //FIXME: seperate game and editor spline code
1005                                         idEntity *ent;
1006                                         ent = gameLocal.FindEntity( events[i]->getParam() );
1007                                         if (ent) {
1008                                                 ent->Signal( SIG_TRIGGER );
1009                                                 ent->ProcessEvent( &EV_Activate, gameLocal.world );
1010                                         }
1011 #endif
1012                                 } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {
1013                                         memset(buff, 0, sizeof(buff));
1014                                         strcpy(buff, events[i]->getParam());
1015                                         const char *param1 = strtok(buff, " \t,\0");
1016                                         const char *param2 = strtok(NULL, " \t,\0");
1017                                         fov.reset(fov.GetFOV(time), atof(param1), time, atoi(param2)); 
1018                                         //*fv = fov = atof(events[i]->getParam());
1019                                 } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) {
1020                                 } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {
1021                                         return false;
1022                                 }
1023                         }
1024                 }
1025         } else {
1026         }
1027
1028         origin = *cameraPosition->getPosition(time);
1029         
1030         *fv = fov.GetFOV(time);
1031
1032         idVec3 temp = origin;
1033
1034         int numTargets = targetPositions.Num();
1035         if (numTargets == 0) {
1036 /*
1037                 // follow the path
1038                 if (cameraSpline.getActiveSegment() < count - 1) {
1039                         temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
1040                         if (temp == origin) {
1041                                 int index = cameraSpline.getActiveSegment() + 2;
1042                                 while (temp == origin && index < count - 1) {
1043                                         temp = *cameraSpline.splinePoints[index++];
1044                                 }
1045                         }
1046                 }
1047 */
1048         } else {
1049                 temp = *getActiveTarget()->getPosition(time);
1050         }
1051         
1052         temp -= origin;
1053         temp.Normalize();
1054         direction = temp;
1055
1056         return true;
1057 }
1058
1059 /*
1060 ================
1061 idCameraDef::waitEvent
1062 ================
1063 */
1064 bool idCameraDef::waitEvent(int index) {
1065         //for (int i = 0; i < events.Num(); i++) {
1066         //      if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
1067         //              return true;
1068         //      }
1069     //}
1070         return false;
1071 }
1072
1073 /*
1074 ================
1075 idCameraDef::buildCamera
1076 ================
1077 */
1078 #define NUM_CCELERATION_SEGS 10
1079 #define CELL_AMT 5
1080
1081 void idCameraDef::buildCamera() {
1082         int i;
1083         int lastSwitch = 0;
1084         idList<float> waits;
1085         idList<int> targets;
1086
1087         totalTime = baseTime;
1088         cameraPosition->setTime(totalTime * 1000);
1089         // we have a base time layout for the path and the target path
1090         // now we need to layer on any wait or speed changes
1091         for (i = 0; i < events.Num(); i++) {
1092                 idCameraEvent *ev = events[i];
1093                 events[i]->setTriggered(false);
1094                 switch (events[i]->getType()) {
1095                         case idCameraEvent::EVENT_TARGET : {
1096                                 targets.Append(i);
1097                                 break;
1098                         }
1099                         case idCameraEvent::EVENT_FEATHER : {
1100                                 long startTime = 0;
1101                                 float speed = 0;
1102                                 long loopTime = 10;
1103                                 float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime);
1104                                 while (startTime <= 1000) {
1105                                         cameraPosition->addVelocity(startTime, loopTime, speed);
1106                                         speed += stepGoal;
1107                                         if (speed > cameraPosition->getBaseVelocity()) {
1108                                                 speed = cameraPosition->getBaseVelocity();
1109                                         }
1110                                         startTime += loopTime;
1111                                 }
1112
1113                                 startTime = totalTime * 1000 - 1000;
1114                                 long endTime = startTime + 1000;
1115                                 speed = cameraPosition->getBaseVelocity();
1116                                 while (startTime < endTime) {
1117                                         speed -= stepGoal;
1118                                         if (speed < 0) {
1119                                                 speed = 0;
1120                                         }
1121                                         cameraPosition->addVelocity(startTime, loopTime, speed);
1122                                         startTime += loopTime;
1123                                 }
1124                                 break;
1125
1126                         }
1127                         case idCameraEvent::EVENT_WAIT : {
1128                                 waits.Append(atof(events[i]->getParam()));
1129
1130                                 //FIXME: this is quite hacky for Wolf E3, accel and decel needs
1131                                 // do be parameter based etc.. 
1132                                 long startTime = events[i]->getTime() - 1000;
1133                                 if (startTime < 0) {
1134                                         startTime = 0;
1135                                 }
1136                                 float speed = cameraPosition->getBaseVelocity();
1137                                 long loopTime = 10;
1138                                 float steps = speed / ((events[i]->getTime() - startTime) / loopTime);
1139                                 while (startTime <= events[i]->getTime() - loopTime) {
1140                                         cameraPosition->addVelocity(startTime, loopTime, speed);
1141                                         speed -= steps;
1142                                         startTime += loopTime;
1143                                 }
1144                                 cameraPosition->addVelocity(events[i]->getTime(), atof(events[i]->getParam()) * 1000, 0);
1145
1146                                 startTime = events[i]->getTime() + atof(events[i]->getParam()) * 1000;
1147                                 long endTime = startTime + 1000;
1148                                 speed = 0;
1149                                 while (startTime <= endTime) {
1150                                         cameraPosition->addVelocity(startTime, loopTime, speed);
1151                                         speed += steps;
1152                                         startTime += loopTime;
1153                                 }
1154                                 break;
1155                         }
1156                         case idCameraEvent::EVENT_TARGETWAIT : {
1157                                 //targetWaits.Append(i);
1158                                 break;
1159                         }
1160                         case idCameraEvent::EVENT_SPEED : {
1161 /*
1162                                 // take the average delay between up to the next five segments
1163                                 float adjust = atof(events[i]->getParam());
1164                                 int index = events[i]->getSegment();
1165                                 total = 0;
1166                                 count = 0;
1167
1168                                 // get total amount of time over the remainder of the segment
1169                                 for (j = index; j < cameraSpline.numSegments() - 1; j++) {
1170                                         total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
1171                                         count++;
1172                                 }
1173
1174                                 // multiply that by the adjustment
1175                                 double newTotal = total * adjust;
1176                                 // what is the difference.. 
1177                                 newTotal -= total;
1178                                 totalTime += newTotal / 1000;
1179
1180                                 // per segment difference
1181                                 newTotal /= count;
1182                                 int additive = newTotal;
1183
1184                                 // now propogate that difference out to each segment
1185                                 for (j = index; j < cameraSpline.numSegments(); j++) {
1186                                         cameraSpline.addSegmentTime(j, additive);
1187                                         additive += newTotal;
1188                                 }
1189                                 break;
1190 */
1191                         }
1192                 }
1193         }
1194
1195
1196         for (i = 0; i < waits.Num(); i++) {
1197                 totalTime += waits[i];
1198         }
1199
1200         // on a new target switch, we need to take time to this point ( since last target switch ) 
1201         // and allocate it across the active target, then reset time to this point
1202         long timeSoFar = 0;
1203         long total = totalTime * 1000;
1204         for (i = 0; i < targets.Num(); i++) {
1205                 long t;
1206                 if (i < targets.Num() - 1) {
1207                         t = events[targets[i+1]]->getTime();
1208                 } else {
1209                         t = total - timeSoFar;
1210                 }
1211                 // t is how much time to use for this target
1212                 setActiveTargetByName(events[targets[i]]->getParam());
1213                 getActiveTarget()->setTime(t);
1214                 timeSoFar += t;
1215         }
1216 }
1217
1218 /*
1219 ================
1220 idCameraDef::startCamera
1221 ================
1222 */
1223 void idCameraDef::startCamera(long t) {
1224         cameraPosition->clearVelocities();
1225         cameraPosition->start(t);
1226         buildCamera();
1227         //for (int i = 0; i < targetPositions.Num(); i++) {
1228         //      targetPositions[i]->
1229         //}
1230         startTime = t;
1231         cameraRunning = true;
1232 }
1233
1234 /*
1235 ================
1236 idCameraDef::parse
1237 ================
1238 */
1239 void idCameraDef::parse( idParser *src  ) {
1240         idToken token;
1241
1242         src->ReadToken(&token);
1243         src->ExpectTokenString( "{" );
1244         while ( 1 ) {
1245
1246                 src->ExpectAnyToken( &token );
1247
1248                 if ( token == "}" ) {
1249                         break;
1250                 }
1251                 else if ( !token.Icmp( "time" ) ) {
1252                         baseTime = src->ParseFloat();
1253                 }
1254                 else if ( !token.Icmp( "camera_fixed") ) {
1255                         cameraPosition = new idFixedPosition();
1256                         cameraPosition->parse( src );
1257                 }
1258                 else if ( !token.Icmp( "camera_interpolated") ) {
1259                         cameraPosition = new idInterpolatedPosition();
1260                         cameraPosition->parse( src );
1261                 }
1262                 else if ( !token.Icmp( "camera_spline") ) {
1263                         cameraPosition = new idSplinePosition();
1264                         cameraPosition->parse( src );
1265                 }
1266                 else if ( !token.Icmp( "target_fixed") ) {
1267                         idFixedPosition *pos = new idFixedPosition();
1268                         pos->parse( src );
1269                         targetPositions.Append(pos);
1270                 }
1271                 else if ( !token.Icmp( "target_interpolated") ) {
1272                         idInterpolatedPosition *pos = new idInterpolatedPosition();
1273                         pos->parse( src );
1274                         targetPositions.Append(pos);
1275                 }
1276                 else if ( !token.Icmp( "target_spline") ) {
1277                         idSplinePosition *pos = new idSplinePosition();
1278                         pos->parse( src );
1279                         targetPositions.Append(pos);
1280                 }
1281                 else if ( !token.Icmp( "fov") ) {
1282                         fov.parse( src );
1283                 }
1284                 else if ( !token.Icmp( "event") ) {
1285                         idCameraEvent *event = new idCameraEvent();
1286                         event->parse( src );
1287                         addEvent(event);
1288                 }
1289                 else {
1290                         src->Error( "unknown camera def: %s", token.c_str() );
1291                         break;
1292                 }
1293         }
1294
1295         if ( !cameraPosition ) {
1296                 common->Printf( "no camera position specified\n" );
1297                 // prevent a crash later on
1298                 cameraPosition = new idFixedPosition();
1299         }
1300 }
1301
1302 /*
1303 ================
1304 idCameraDef::load
1305 ================
1306 */
1307 bool idCameraDef::load( const char *filename ) {
1308         idParser *src;
1309
1310         src = new idParser( filename, LEXFL_NOSTRINGCONCAT | LEXFL_NOSTRINGESCAPECHARS | LEXFL_ALLOWPATHNAMES );
1311         if ( !src->IsLoaded() ) {
1312                 common->Printf( "couldn't load %s\n", filename );
1313                 delete src;
1314                 return false;
1315         }
1316
1317         clear();
1318         parse( src );
1319
1320         delete src;
1321
1322         return true;
1323 }
1324
1325 /*
1326 ================
1327 idCameraDef::save
1328 ================
1329 */
1330 void idCameraDef::save(const char *filename) {
1331         idFile *f = fileSystem->OpenFileWrite( filename, "fs_devpath" );
1332         if ( f ) {
1333                 int i;
1334                 f->Printf( "cameraPathDef { \n" );
1335                 f->Printf( "\ttime %f\n", baseTime );
1336
1337                 cameraPosition->write( f, va("camera_%s",cameraPosition->typeStr()) );
1338
1339                 for (i = 0; i < numTargets(); i++) {
1340                         targetPositions[i]->write( f, va("target_%s", targetPositions[i]->typeStr()) );
1341                 }
1342
1343                 for (i = 0; i < events.Num(); i++) {
1344                         events[i]->write( f, "event" );
1345                 }
1346
1347                 fov.write( f, "fov" );
1348
1349                 f->Printf( "}\n" );
1350         }
1351         fileSystem->CloseFile( f );
1352 }
1353
1354 /*
1355 ================
1356 idCameraDef::sortEvents
1357 ================
1358 */
1359 int idCameraDef::sortEvents(const void *p1, const void *p2) {
1360         idCameraEvent *ev1 = (idCameraEvent*)(p1);
1361         idCameraEvent *ev2 = (idCameraEvent*)(p2);
1362
1363         if (ev1->getTime() > ev2->getTime()) {
1364                 return -1;
1365         }
1366         if (ev1->getTime() < ev2->getTime()) {
1367                 return 1;
1368         }
1369         return 0; 
1370 }
1371
1372 /*
1373 ================
1374 idCameraDef::addEvent
1375 ================
1376 */
1377 void idCameraDef::addEvent(idCameraEvent *event) {
1378         events.Append(event);
1379         //events.Sort(&sortEvents);
1380
1381 }
1382
1383 /*
1384 ================
1385 idCameraDef::addEvent
1386 ================
1387 */
1388 void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {
1389         addEvent(new idCameraEvent(t, param, time));
1390         buildCamera();
1391 }
1392
1393 /*
1394 ================
1395 idCameraDef::newFromType
1396 ================
1397 */
1398 idCameraPosition *idCameraDef::newFromType( idCameraPosition::positionType t ) {
1399         switch (t) {
1400                 case idCameraPosition::FIXED : return new idFixedPosition();
1401                 case idCameraPosition::INTERPOLATED : return new idInterpolatedPosition();
1402                 case idCameraPosition::SPLINE : return new idSplinePosition();
1403         };
1404         return NULL;
1405 }
1406
1407
1408 /*
1409 =================================================================================
1410
1411 idCamaraEvent
1412
1413 =================================================================================
1414 */
1415
1416 /*
1417 ================
1418 idCameraEvent::eventStr
1419 ================
1420 */
1421 const char *idCameraEvent::eventStr[] = {
1422         "NA",
1423         "WAIT",
1424         "TARGETWAIT",
1425         "SPEED",
1426         "TARGET",
1427         "SNAPTARGET",
1428         "FOV",
1429         "CMD",
1430         "TRIGGER",
1431         "STOP",
1432         "CAMERA",
1433         "FADEOUT",
1434         "FADEIN",
1435         "FEATHER"
1436 };
1437
1438 /*
1439 ================
1440 idCameraEvent::parse
1441 ================
1442 */
1443 void idCameraEvent::parse( idParser *src ) {
1444         idToken token;
1445         idStr key;
1446
1447         src->ExpectTokenString( "{" );
1448
1449         while ( 1 ) {
1450
1451                 if ( !src->ExpectAnyToken( &token ) ) {
1452                         break;
1453                 }
1454                 if ( token == "}" ) {
1455                         break;
1456                 }
1457
1458                 key = token;
1459                 src->ReadTokenOnLine( &token );
1460                 if ( !key.Icmp( "type" ) ) {
1461                         type = static_cast<idCameraEvent::eventType>(atoi(token.c_str()));
1462                 }
1463                 else if ( !key.Icmp( "param" ) ) {
1464                         paramStr = token;
1465                 }
1466                 else if ( !key.Icmp( "time" ) ) {
1467                         time = atoi(token.c_str());
1468                 }
1469                 else {
1470                         src->Error( "unknown camera event key: %s", key.c_str() );
1471                         break;
1472                 }
1473         }
1474 }
1475
1476 /*
1477 ================
1478 idCameraEvent::write
1479 ================
1480 */
1481 void idCameraEvent::write( idFile *f, const char *name) {
1482         f->Printf( "\t%s {\n", name );
1483         f->Printf( "\t\ttype %d\n", static_cast<int>(type) );
1484         f->Printf( "\t\tparam \"%s\"\n", paramStr.c_str() );
1485         f->Printf( "\t\ttime %d\n", time );
1486         f->Printf( "\t}\n" );
1487 }
1488
1489 /*
1490 =================================================================================
1491
1492 idCamaraPosition
1493
1494 =================================================================================
1495 */
1496
1497 /*
1498 ================
1499 idCameraPosition::positionStr
1500 ================
1501 */
1502 const char *idCameraPosition::positionStr[] = {
1503         "Fixed",
1504         "Interpolated",
1505         "Spline",
1506 };
1507
1508 /*
1509 ================
1510 idCameraPosition::positionStr
1511 ================
1512 */
1513 void idCameraPosition::clearVelocities() {
1514         for (int i = 0; i < velocities.Num(); i++) {
1515                 delete velocities[i];
1516                 velocities[i] = NULL;
1517         }
1518         velocities.Clear();
1519 }
1520
1521 /*
1522 ================
1523 idCameraPosition::positionStr
1524 ================
1525 */
1526 float idCameraPosition::getVelocity( long t ) {
1527         long check = t - startTime;
1528         for ( int i = 0; i < velocities.Num(); i++ ) {
1529                 if (check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time) {
1530                         return velocities[i]->speed;
1531                 }
1532         }
1533         return baseVelocity;
1534 }
1535
1536 /*
1537 ================
1538 idCameraPosition::parseToken
1539 ================
1540 */
1541 bool idCameraPosition::parseToken( const idStr &key, idParser *src ) {
1542         idToken token;
1543
1544         if ( !key.Icmp( "time" ) ) {
1545                 time = src->ParseInt();
1546                 return true;
1547         }
1548         else if ( !key.Icmp( "type" ) ) {
1549                 type = static_cast<idCameraPosition::positionType> ( src->ParseInt() );
1550                 return true;
1551         }
1552         else if ( !key.Icmp( "velocity" ) ) {
1553                 long t = atol(token);
1554                 long d = src->ParseInt();
1555                 float s = src->ParseFloat();
1556                 addVelocity(t, d, s);
1557                 return true;
1558         }
1559         else if ( !key.Icmp( "baseVelocity" ) ) {
1560                 baseVelocity = src->ParseFloat();
1561                 return true;
1562         }
1563         else if ( !key.Icmp( "name" ) ) {
1564                 src->ReadToken( &token );
1565                 name = token;
1566                 return true;
1567         }
1568         else if ( !key.Icmp( "time" ) ) {
1569                 time = src->ParseInt();
1570                 return true;
1571         }
1572         else {
1573                 src->Error( "unknown camera position key: %s", key.c_str() );
1574                 return false;
1575         }
1576 }
1577
1578 /*
1579 ================
1580 idCameraPosition::write
1581 ================
1582 */
1583 void idCameraPosition::write( idFile *f, const char *p ) {
1584         f->Printf( "\t\ttime %i\n", time );
1585         f->Printf( "\t\ttype %i\n", static_cast<int>(type) );
1586         f->Printf( "\t\tname %s\n", name.c_str() );
1587         f->Printf( "\t\tbaseVelocity %f\n", baseVelocity );
1588         for (int i = 0; i < velocities.Num(); i++) {
1589                 f->Printf( "\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed );
1590         }
1591 }
1592
1593 /*
1594 =================================================================================
1595
1596 idInterpolatedPosition
1597
1598 =================================================================================
1599 */
1600
1601 /*
1602 ================
1603 idInterpolatedPosition::getPoint
1604 ================
1605 */
1606 idVec3 *idInterpolatedPosition::getPoint( int index ) {
1607         assert( index >= 0 && index < 2 );
1608         if ( index == 0 ) {
1609                 return &startPos;
1610         }
1611         return &endPos;
1612 }
1613
1614 /*
1615 ================
1616 idInterpolatedPosition::addPoint
1617 ================
1618 */
1619 void idInterpolatedPosition::addPoint( const float x, const float y, const float z ) {
1620         if (first) {
1621                 startPos.Set(x, y, z);
1622                 first = false;
1623         } else {
1624                 endPos.Set(x, y, z);
1625                 first = true;
1626         }
1627 }
1628
1629 /*
1630 ================
1631 idInterpolatedPosition::addPoint
1632 ================
1633 */
1634 void idInterpolatedPosition::addPoint( const idVec3 &v ) {
1635         if (first) {
1636                 startPos = v;
1637                 first = false;
1638         }
1639         else {
1640                 endPos = v;
1641                 first = true;
1642         }
1643 }
1644
1645 /*
1646 ================
1647 idInterpolatedPosition::draw
1648 ================
1649 */
1650 void idInterpolatedPosition::draw( bool editMode ) {
1651         glLabeledPoint(colorBlue, startPos, (editMode) ? 5 : 3, "Start interpolated");
1652         glLabeledPoint(colorBlue, endPos, (editMode) ? 5 : 3, "End interpolated");
1653         qglBegin(GL_LINES);
1654         qglVertex3fv( startPos.ToFloatPtr() );
1655         qglVertex3fv( endPos.ToFloatPtr() );
1656         qglEnd();
1657 }
1658
1659 /*
1660 ================
1661 idInterpolatedPosition::start
1662 ================
1663 */
1664 void idInterpolatedPosition::start( long t ) {
1665         idCameraPosition::start(t);
1666         lastTime = startTime;
1667         distSoFar = 0.0f;
1668         idVec3 temp = startPos;
1669         temp -= endPos;
1670         calcVelocity(temp.Length());
1671 }
1672
1673 /*
1674 ================
1675 idInterpolatedPosition::getPosition
1676 ================
1677 */
1678 const idVec3 *idInterpolatedPosition::getPosition( long t ) { 
1679         static idVec3 interpolatedPos;
1680
1681         if (t - startTime > 6000) {
1682                 int i = 0;
1683         }
1684
1685         float velocity = getVelocity(t);
1686         float timePassed = t - lastTime;
1687         lastTime = t;
1688
1689         // convert to seconds   
1690         timePassed /= 1000;
1691
1692         if (velocity != getBaseVelocity()) {
1693                 int i = 0;
1694         }
1695
1696         float distToTravel = timePassed * velocity;
1697
1698         idVec3 temp = startPos;
1699         temp -= endPos;
1700         float distance = temp.Length();
1701
1702         distSoFar += distToTravel;
1703         float percent = (float)(distSoFar) / distance;
1704
1705         if ( percent > 1.0f ) {
1706                 percent = 1.0f;
1707         } else if ( percent < 0.0f ) {
1708                 percent = 0.0f;
1709         }
1710
1711         // the following line does a straigt calc on percentage of time
1712         // float percent = (float)(startTime + time - t) / time;
1713
1714         idVec3 v1 = startPos;
1715         idVec3 v2 = endPos;
1716         v1 *= (1.0f - percent);
1717         v2 *= percent;
1718         v1 += v2;
1719         interpolatedPos = v1;
1720         return &interpolatedPos;
1721 }
1722
1723 /*
1724 ================
1725 idInterpolatedPosition::parse
1726 ================
1727 */
1728 void idInterpolatedPosition::parse( idParser *src ) {
1729         idToken token;
1730
1731         src->ExpectTokenString( "{" );
1732         while ( 1 ) {
1733                 if ( !src->ExpectAnyToken( &token ) ) {
1734                         break;
1735                 }
1736                 if ( token == "}" ) {
1737                         break;
1738                 }
1739
1740                 if ( !token.Icmp( "startPos" ) ) {
1741                         src->Parse1DMatrix( 3, startPos.ToFloatPtr() );
1742                 }
1743                 else if ( !token.Icmp( "endPos" ) ) {
1744                         src->Parse1DMatrix( 3, endPos.ToFloatPtr() );
1745                 }
1746                 else {
1747                         idCameraPosition::parseToken( token, src);
1748                 }
1749         }
1750 }
1751
1752 /*
1753 ================
1754 idInterpolatedPosition::write
1755 ================
1756 */
1757 void idInterpolatedPosition::write( idFile *f, const char *p ) {
1758         f->Printf( "\t%s {\n", p );
1759         idCameraPosition::write( f, p );
1760         f->Printf( "\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z );
1761         f->Printf( "\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z );
1762         f->Printf( "\t}\n" );
1763 }
1764
1765 /*
1766 =================================================================================
1767
1768 idCameraFOV
1769
1770 =================================================================================
1771 */
1772
1773 /*
1774 ================
1775 idCameraFOV::GetFOV
1776 ================
1777 */
1778 float idCameraFOV::GetFOV( long t ) {
1779         if (time) {
1780                 assert(startTime);
1781                 float percent = (t - startTime) / length;
1782                 if ( percent < 0.0f ) {
1783                         percent = 0.0f;
1784                 } else if ( percent > 1.0f ) {
1785                         percent = 1.0f;
1786                 }
1787                 float temp = endFOV - startFOV;
1788                 temp *= percent;
1789                 fov = startFOV + temp;
1790         }
1791         return fov;
1792 }
1793
1794 /*
1795 ================
1796 idCameraFOV::reset
1797 ================
1798 */
1799 void idCameraFOV::reset( float startfov, float endfov, int start, int len ) {
1800         startFOV = startfov;
1801         endFOV = endfov;
1802         startTime = start;
1803         length = len;
1804 }
1805
1806 /*
1807 ================
1808 idCameraFOV::parse
1809 ================
1810 */
1811 void idCameraFOV::parse( idParser *src ) {
1812         idToken token;
1813
1814         src->ExpectTokenString( "{" );
1815         while ( 1 ) {
1816                 if ( !src->ExpectAnyToken( &token ) ) {
1817                         break;
1818                 }
1819                 if ( token == "}" ) {
1820                         break;
1821                 }
1822
1823                 if ( !token.Icmp( "fov" ) ) {
1824                         fov = src->ParseFloat();
1825                 }
1826                 else if ( !token.Icmp( "startFOV" ) ) {
1827                         startFOV = src->ParseFloat();
1828                 }
1829                 else if ( !token.Icmp( "endFOV" ) ) {
1830                         endFOV = src->ParseFloat();
1831                 }
1832                 else if ( !token.Icmp( "time" ) ) {
1833                         time = src->ParseInt();
1834                 }
1835                 else {
1836                         src->Error( "unknown camera FOV key: %s", token.c_str() );
1837                         break;
1838                 }
1839         }
1840 }
1841
1842 /*
1843 ================
1844 idCameraFOV::write
1845 ================
1846 */
1847 void idCameraFOV::write( idFile *f, const char *p ) {
1848         f->Printf( "\t%s {\n", p );
1849         f->Printf( "\t\tfov %f\n", fov );
1850         f->Printf( "\t\tstartFOV %f\n", startFOV );
1851         f->Printf( "\t\tendFOV %f\n", endFOV );
1852         f->Printf( "\t\ttime %i\n", time );
1853         f->Printf( "\t}\n" );
1854 }
1855
1856 /*
1857 =================================================================================
1858
1859 idFixedPosition
1860
1861 =================================================================================
1862 */
1863
1864 /*
1865 ================
1866 idFixedPosition::parse
1867 ================
1868 */
1869 void idFixedPosition::parse( idParser *src ) {
1870         idToken token;
1871
1872         src->ExpectTokenString( "{" );
1873         while ( 1 ) {
1874                 if ( !src->ExpectAnyToken( &token ) ) {
1875                         break;
1876                 }
1877                 if ( token == "}" ) {
1878                         break;
1879                 }
1880
1881                 if ( !token.Icmp( "pos" ) ) {
1882                         src->Parse1DMatrix( 3, pos.ToFloatPtr() );
1883                 }
1884                 else {
1885                         idCameraPosition::parseToken( token, src );
1886                 }
1887         }
1888 }
1889
1890 /*
1891 ================
1892 idFixedPosition::write
1893 ================
1894 */
1895 void idFixedPosition::write( idFile *f, const char *p ) {
1896         f->Printf( "\t%s {\n", p );
1897         idCameraPosition::write( f, p );
1898         f->Printf( "\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z );
1899         f->Printf( "\t}\n" );
1900 }
1901
1902 /*
1903 =================================================================================
1904
1905 idSplinePosition
1906
1907 =================================================================================
1908 */
1909
1910 /*
1911 ================
1912 idSplinePosition::start
1913 ================
1914 */
1915 void idSplinePosition::start( long t ) {
1916         idCameraPosition::start( t );
1917         target.initPosition(t, time);
1918         lastTime = startTime;
1919         distSoFar = 0.0f;
1920         calcVelocity(target.totalDistance());
1921 }
1922
1923 /*
1924 ================
1925 idSplinePosition::parse
1926 ================
1927 */
1928 void idSplinePosition::parse( idParser *src ) {
1929         idToken token;
1930
1931         src->ExpectTokenString( "{" );
1932         while ( 1 ) {
1933                 if ( !src->ExpectAnyToken( &token ) ) {
1934                         break;
1935                 }
1936                 if ( token == "}" ) {
1937                         break;
1938                 }
1939                 if ( !token.Icmp( "target" ) ) {
1940                         target.parse( src );
1941                 }
1942                 else {
1943                         idCameraPosition::parseToken( token, src );     
1944                 }
1945         }
1946 }
1947
1948 /*
1949 ================
1950 idSplinePosition::write
1951 ================
1952 */
1953 void idSplinePosition::write( idFile *f, const char *p ) {
1954         f->Printf( "\t%s {\n", p );
1955         idCameraPosition::write( f, p );
1956         target.write( f, "target" );
1957         f->Printf( "\t}\n" );
1958 }
1959
1960 /*
1961 ================
1962 idSplinePosition::getPosition
1963 ================
1964 */
1965 const idVec3 *idSplinePosition::getPosition(long t) {
1966         static idVec3 interpolatedPos;
1967
1968         float velocity = getVelocity(t);
1969         float timePassed = t - lastTime;
1970         lastTime = t;
1971
1972         // convert to seconds   
1973         timePassed /= 1000;
1974
1975         float distToTravel = timePassed * velocity;
1976
1977         distSoFar += distToTravel;
1978         double tempDistance = target.totalDistance();
1979
1980         double percent = (double)(distSoFar) / tempDistance;
1981
1982         double targetDistance = percent * tempDistance;
1983         tempDistance = 0;
1984
1985         double lastDistance1,lastDistance2;
1986         lastDistance1 = lastDistance2 = 0;
1987         //FIXME: calc distances on spline build
1988         idVec3 temp;
1989         int count = target.numSegments();
1990         //for(int i = 2; i < count - 1; i++) {
1991         int i;
1992         for( i = 1; i < count; i++) {
1993                 temp = *target.getSegmentPoint(i-1);
1994                 temp -= *target.getSegmentPoint(i);
1995                 tempDistance += temp.Length();
1996                 if (i & 1) {
1997                         lastDistance1 = tempDistance;
1998                 } else {
1999                         lastDistance2 = tempDistance;
2000                 }
2001                 if (tempDistance >= targetDistance) {
2002                         break;
2003                 }
2004         }
2005
2006         if (i >= count - 1) {
2007                 interpolatedPos = *target.getSegmentPoint(i-1);
2008         } else {
2009 #if 0
2010                 double timeHi = target.getSegmentTime(i + 1);
2011                 double timeLo = target.getSegmentTime(i - 1);
2012                 double percent = (timeHi - t) / (timeHi - timeLo); 
2013                 idVec3 v1 = *target.getSegmentPoint(i - 1);
2014                 idVec3 v2 = *target.getSegmentPoint(i + 1);
2015                 v2 *= (1.0f - percent);
2016                 v1 *= percent;
2017                 v2 += v1;
2018                 interpolatedPos = v2;
2019 #else
2020                 if (lastDistance1 > lastDistance2) {
2021                         double d = lastDistance2;
2022                         lastDistance2 = lastDistance1;
2023                         lastDistance1 = d;
2024                 }
2025
2026                 idVec3 v1 = *target.getSegmentPoint(i - 1);
2027                 idVec3 v2 = *target.getSegmentPoint(i);
2028                 double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1); 
2029                 v2 *= (1.0f - percent);
2030                 v1 *= percent;
2031                 v2 += v1;
2032                 interpolatedPos = v2;
2033 #endif
2034         }
2035         return &interpolatedPos;
2036
2037 }