[q3map2] Unwind script stack in case of script loading error.
[xonotic/netradiant.git] / libs / splines / splines.h
1 /*
2    Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3    For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5    This file is part of GtkRadiant.
6
7    GtkRadiant is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    GtkRadiant is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with GtkRadiant; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21
22 #ifndef __SPLINES_H
23 #define __SPLINES_H
24
25 #define GTKRADIANT
26
27 #ifdef GTKRADIANT
28 #include "igl.h"
29 #endif
30
31 #include "util_list.h"
32 #include "util_str.h"
33 #include "math_vector.h"
34
35 typedef int fileHandle_t;
36
37 extern void glBox( idVec3 &color, idVec3 &point, float size );
38 extern void glLabeledPoint( idVec3 &color, idVec3 &point, float size, const char *label );
39
40 static idVec4 blue( 0, 0, 1, 1 );
41 static idVec4 red( 1, 0, 0, 1 );
42
43 class idPointListInterface {
44 public:
45 idPointListInterface() {
46         selectedPoints.Clear();
47 };
48 virtual ~idPointListInterface() {};
49
50 virtual int numPoints() {
51         return 0;
52 }
53
54 virtual void addPoint( const float x, const float y, const float z ) {}
55 virtual void addPoint( const idVec3 &v ) {}
56 virtual void removePoint( int index ) {}
57 virtual idVec3 *getPoint( int index ) { return NULL; }
58
59 int selectPointByRay( float ox, float oy, float oz, float dx, float dy, float dz, bool single ) {
60         idVec3 origin( ox, oy, oz );
61         idVec3 dir( dx, dy, dz );
62         return selectPointByRay( origin, dir, single );
63 }
64
65 int selectPointByRay( const idVec3 origin, const idVec3 direction, bool single ) {
66         int i, besti, count;
67         float d, bestd;
68         idVec3 temp, temp2;
69
70         // find the point closest to the ray
71         besti = -1;
72         bestd = 8;
73         count = numPoints();
74
75         for ( i = 0; i < count; i++ ) {
76                 temp = *getPoint( i );
77                 temp2 = temp;
78                 temp -= origin;
79                 d = DotProduct( temp, direction );
80                 __VectorMA( origin, d, direction, temp );
81                 temp2 -= temp;
82                 d = temp2.Length();
83                 if ( d <= bestd ) {
84                         bestd = d;
85                         besti = i;
86                 }
87         }
88
89         if ( besti >= 0 ) {
90                 selectPoint( besti, single );
91         }
92
93         return besti;
94 }
95
96 int isPointSelected( int index ) {
97         int count = selectedPoints.Num();
98         for ( int i = 0; i < count; i++ ) {
99                 if ( selectedPoints[i] == index ) {
100                         return i;
101                 }
102         }
103         return -1;
104 }
105
106 int selectPoint( int index, bool single ) {
107         if ( index >= 0 && index < numPoints() ) {
108                 if ( single ) {
109                         deselectAll();
110                 }
111                 else {
112                         if ( isPointSelected( index ) >= 0 ) {
113                                 selectedPoints.Remove( index );
114                         }
115                 }
116                 return selectedPoints.Append( index );
117         }
118         return -1;
119 }
120
121 void selectAll() {
122         selectedPoints.Clear();
123         for ( int i = 0; i < numPoints(); i++ ) {
124                 selectedPoints.Append( i );
125         }
126 }
127
128 void deselectAll() {
129         selectedPoints.Clear();
130 }
131
132 int numSelectedPoints();
133
134 idVec3 *getSelectedPoint( int index ) {
135         assert( index >= 0 && index < numSelectedPoints() );
136         return getPoint( selectedPoints[index] );
137 }
138
139 virtual void updateSelection( float x, float y, float z ) {
140         idVec3 move( x, y, z );
141         updateSelection( move );
142 }
143
144 virtual void updateSelection( const idVec3 &move ) {
145         int count = selectedPoints.Num();
146         for ( int i = 0; i < count; i++ ) {
147                 *getPoint( selectedPoints[i] ) += move;
148         }
149 }
150
151 void drawSelection() {
152         int count = selectedPoints.Num();
153         for ( int i = 0; i < count; i++ ) {
154                 glBox( red, *getPoint( selectedPoints[i] ), 4 );
155         }
156 }
157
158 protected:
159 idList<int> selectedPoints;
160
161 };
162
163
164 class idSplineList {
165
166 public:
167
168 idSplineList() {
169         clear();
170 }
171
172 idSplineList( const char *p ) {
173         clear();
174         name = p;
175 };
176
177 ~idSplineList() {
178         clear();
179 };
180
181 void clearControl() {
182         for ( int i = 0; i < controlPoints.Num(); i++ ) {
183                 delete controlPoints[i];
184         }
185         controlPoints.Clear();
186 }
187
188 void clearSpline() {
189         for ( int i = 0; i < splinePoints.Num(); i++ ) {
190                 delete splinePoints[i];
191         }
192         splinePoints.Clear();
193 }
194
195 void parse( const char *( *text ) );
196 void write( fileHandle_t file, const char *name );
197
198 void clear() {
199         clearControl();
200         clearSpline();
201         splineTime.Clear();
202         selected = NULL;
203         dirty = true;
204         activeSegment = 0;
205         granularity = 0.025f;
206         pathColor.set( 1.0f, 0.5f, 0.0f );
207         controlColor.set( 0.7f, 0.0f, 1.0f );
208         segmentColor.set( 0.0f, 0.0f, 1.0f );
209         activeColor.set( 1.0f, 0.0f, 0.0f );
210 }
211
212 void initPosition( long startTime, long totalTime );
213 const idVec3 *getPosition( long time );
214
215
216 void draw( bool editMode );
217 void addToRenderer();
218
219 void setSelectedPoint( idVec3 *p );
220 idVec3 *getSelectedPoint() {
221         return selected;
222 }
223
224 void addPoint( const idVec3 &v ) {
225         controlPoints.Append( new idVec3( v ) );
226         dirty = true;
227 }
228
229 void addPoint( float x, float y, float z ) {
230         controlPoints.Append( new idVec3( x, y, z ) );
231         dirty = true;
232 }
233
234 void updateSelection( const idVec3 &move );
235
236 void startEdit() {
237         editMode = true;
238 }
239
240 void stopEdit() {
241         editMode = false;
242 }
243
244 void buildSpline();
245
246 void setGranularity( float f ) {
247         granularity = f;
248 }
249
250 float getGranularity() {
251         return granularity;
252 }
253
254 int numPoints() {
255         return controlPoints.Num();
256 }
257
258 idVec3 *getPoint( int index ) {
259         assert( index >= 0 && index < controlPoints.Num() );
260         return controlPoints[index];
261 }
262
263 idVec3 *getSegmentPoint( int index ) {
264         assert( index >= 0 && index < splinePoints.Num() );
265         return splinePoints[index];
266 }
267
268
269 void setSegmentTime( int index, int time ) {
270         assert( index >= 0 && index < splinePoints.Num() );
271         splineTime[index] = time;
272 }
273
274 int getSegmentTime( int index ) {
275         assert( index >= 0 && index < splinePoints.Num() );
276         return (int)splineTime[index];
277 }
278 void addSegmentTime( int index, int time ) {
279         assert( index >= 0 && index < splinePoints.Num() );
280         splineTime[index] += time;
281 }
282
283 float totalDistance();
284
285 static idVec3 zero;
286
287 int getActiveSegment() {
288         return activeSegment;
289 }
290
291 void setActiveSegment( int i ) {
292         //assert(i >= 0 && (splinePoints.Num() > 0 && i < splinePoints.Num()));
293         activeSegment = i;
294 }
295
296 int numSegments() {
297         return splinePoints.Num();
298 }
299
300 void setColors( idVec3 &path, idVec3 &segment, idVec3 &control, idVec3 &active ) {
301         pathColor = path;
302         segmentColor = segment;
303         controlColor = control;
304         activeColor = active;
305 }
306
307 const char *getName() {
308         return name.c_str();
309 }
310
311 void setName( const char *p ) {
312         name = p;
313 }
314
315 bool validTime() {
316         if ( dirty ) {
317                 buildSpline();
318         }
319         // gcc doesn't allow static casting away from bools
320         // why?  I've no idea...
321         return (bool)( splineTime.Num() > 0 && splineTime.Num() == splinePoints.Num() );
322 }
323
324 void setTime( long t ) {
325         time = t;
326 }
327
328 void setBaseTime( long t ) {
329         baseTime = t;
330 }
331
332 protected:
333 idStr name;
334 float calcSpline( int step, float tension );
335 idList<idVec3*> controlPoints;
336 idList<idVec3*> splinePoints;
337 idList<double> splineTime;
338 idVec3 *selected;
339 idVec3 pathColor, segmentColor, controlColor, activeColor;
340 float granularity;
341 bool editMode;
342 bool dirty;
343 int activeSegment;
344 long baseTime;
345 long time;
346 friend class idCamera;
347 };
348
349 // time in milliseconds
350 // velocity where 1.0 equal rough walking speed
351 struct idVelocity {
352         idVelocity( long start, long duration, float s ) {
353                 startTime = start;
354                 time = duration;
355                 speed = s;
356         }
357         long startTime;
358         long time;
359         float speed;
360 };
361
362 // can either be a look at or origin position for a camera
363 //
364 class idCameraPosition : public idPointListInterface {
365 public:
366
367 virtual void clearVelocities() {
368         for ( int i = 0; i < velocities.Num(); i++ ) {
369                 delete velocities[i];
370                 velocities[i] = NULL;
371         }
372         velocities.Clear();
373 }
374
375 virtual void clear() {
376         editMode = false;
377         clearVelocities();
378 }
379
380 idCameraPosition( const char *p ) {
381         name = p;
382 }
383
384 idCameraPosition() {
385         time = 0;
386         name = "position";
387 }
388
389 idCameraPosition( long t ) {
390         time = t;
391 }
392
393 virtual ~idCameraPosition() {
394         clear();
395 }
396
397
398 // this can be done with RTTI syntax but i like the derived classes setting a type
399 // makes serialization a bit easier to see
400 //
401 enum positionType {
402         FIXED = 0x00,
403         INTERPOLATED,
404         SPLINE,
405         POSITION_COUNT
406 };
407
408
409 virtual void start( long t ) {
410         startTime = t;
411 }
412
413 long getTime() {
414         return time;
415 }
416
417 virtual void setTime( long t ) {
418         time = t;
419 }
420
421 float getBaseVelocity() {
422         return baseVelocity;
423 }
424
425 float getVelocity( long t ) {
426         long check = t - startTime;
427         for ( int i = 0; i < velocities.Num(); i++ ) {
428                 if ( check >= velocities[i]->startTime && check <= velocities[i]->startTime + velocities[i]->time ) {
429                         return velocities[i]->speed;
430                 }
431         }
432         return baseVelocity;
433 }
434
435 void addVelocity( long start, long duration, float speed ) {
436         velocities.Append( new idVelocity( start, duration, speed ) );
437 }
438
439 virtual const idVec3 *getPosition( long t ) {
440         assert( true );
441         return NULL;
442 }
443
444 virtual void draw( bool editMode ) {};
445
446 virtual void parse( const char *( *text ) ) {};
447 virtual void write( fileHandle_t file, const char *name );
448 virtual bool parseToken( const char *key, const char *( *text ) );
449
450 const char *getName() {
451         return name.c_str();
452 }
453
454 void setName( const char *p ) {
455         name = p;
456 }
457
458 virtual void startEdit() {
459         editMode = true;
460 }
461
462 virtual void stopEdit() {
463         editMode = false;
464 }
465
466 virtual void draw() {};
467
468 const char *typeStr() {
469         return positionStr[static_cast<int>( type )];
470 }
471
472 void calcVelocity( float distance ) {
473         float secs = (float)time / 1000;
474         baseVelocity = distance / secs;
475 }
476
477 protected:
478 static const char* positionStr[POSITION_COUNT];
479 long startTime;
480 long time;
481 idCameraPosition::positionType type;
482 idStr name;
483 bool editMode;
484 idList<idVelocity*> velocities;
485 float baseVelocity;
486 };
487
488 class idFixedPosition : public idCameraPosition {
489 public:
490
491 void init() {
492         pos.Zero();
493         type = idCameraPosition::FIXED;
494 }
495
496 idFixedPosition() : idCameraPosition() {
497         init();
498 }
499
500 idFixedPosition( idVec3 p ) : idCameraPosition() {
501         init();
502         pos = p;
503 }
504
505 virtual void addPoint( const idVec3 &v ) {
506         pos = v;
507 }
508
509 virtual void addPoint( const float x, const float y, const float z ) {
510         pos.set( x, y, z );
511 }
512
513
514 ~idFixedPosition() {
515 }
516
517 virtual const idVec3 *getPosition( long t ) {
518         return &pos;
519 }
520
521 void parse( const char *( *text ) );
522 void write( fileHandle_t file, const char *name );
523
524 virtual int numPoints() {
525         return 1;
526 }
527
528 virtual idVec3 *getPoint( int index ) {
529         if ( index != 0 ) {
530                 assert( true );
531         }
532         ;
533         return &pos;
534 }
535
536 virtual void draw( bool editMode ) {
537         glLabeledPoint( blue, pos, ( editMode ) ? 5 : 3, "Fixed point" );
538 }
539
540 protected:
541 idVec3 pos;
542 };
543
544 class idInterpolatedPosition : public idCameraPosition {
545 public:
546
547 void init() {
548         type = idCameraPosition::INTERPOLATED;
549         first = true;
550         startPos.Zero();
551         endPos.Zero();
552 }
553
554 idInterpolatedPosition() : idCameraPosition() {
555         init();
556 }
557
558 idInterpolatedPosition( idVec3 start, idVec3 end, long time ) : idCameraPosition( time ) {
559         init();
560         startPos = start;
561         endPos = end;
562 }
563
564 ~idInterpolatedPosition() {
565 }
566
567 virtual const idVec3 *getPosition( long t );
568
569 void parse( const char *( *text ) );
570 void write( fileHandle_t file, const char *name );
571
572 virtual int numPoints() {
573         return 2;
574 }
575
576 virtual idVec3 *getPoint( int index ) {
577         assert( index >= 0 && index < 2 );
578         if ( index == 0 ) {
579                 return &startPos;
580         }
581         return &endPos;
582 }
583
584 virtual void addPoint( const float x, const float y, const float z ) {
585         if ( first ) {
586                 startPos.set( x, y, z );
587                 first = false;
588         }
589         else {
590                 endPos.set( x, y, z );
591                 first = true;
592         }
593 }
594
595 virtual void addPoint( const idVec3 &v ) {
596         if ( first ) {
597                 startPos = v;
598                 first = false;
599         }
600         else {
601                 endPos = v;
602                 first = true;
603         }
604 }
605
606 virtual void draw( bool editMode ) {
607         glLabeledPoint( blue, startPos, ( editMode ) ? 5 : 3, "Start interpolated" );
608         glLabeledPoint( blue, endPos, ( editMode ) ? 5 : 3, "End interpolated" );
609         glBegin( GL_LINES );
610         glVertex3fv( startPos );
611         glVertex3fv( endPos );
612         glEnd();
613 }
614
615 virtual void start( long t ) {
616         idCameraPosition::start( t );
617         lastTime = startTime;
618         distSoFar = 0.0;
619         idVec3 temp = startPos;
620         temp -= endPos;
621         calcVelocity( temp.Length() );
622 }
623
624 protected:
625 bool first;
626 idVec3 startPos;
627 idVec3 endPos;
628 long lastTime;
629 float distSoFar;
630 };
631
632 class idSplinePosition : public idCameraPosition {
633 public:
634
635 void init() {
636         type = idCameraPosition::SPLINE;
637 }
638
639 idSplinePosition() : idCameraPosition() {
640         init();
641 }
642
643 idSplinePosition( long time ) : idCameraPosition( time ) {
644         init();
645 }
646
647 ~idSplinePosition() {
648 }
649
650 virtual void start( long t ) {
651         idCameraPosition::start( t );
652         target.initPosition( t, time );
653         lastTime = startTime;
654         distSoFar = 0.0;
655         calcVelocity( target.totalDistance() );
656 }
657
658 //virtual const idVec3 *getPosition(long t) {
659 //      return target.getPosition(t);
660 //}
661 virtual const idVec3 *getPosition( long t );
662
663
664 //virtual const idVec3 *getPosition(long t) const {
665
666 void addControlPoint( idVec3 &v ) {
667         target.addPoint( v );
668 }
669
670 void parse( const char *( *text ) );
671 void write( fileHandle_t file, const char *name );
672
673 virtual int numPoints() {
674         return target.numPoints();
675 }
676
677 virtual idVec3 *getPoint( int index ) {
678         return target.getPoint( index );
679 }
680
681 virtual void addPoint( const idVec3 &v ) {
682         target.addPoint( v );
683 }
684
685 virtual void addPoint( const float x, const float y, const float z ) {
686         target.addPoint( x, y, z );
687 }
688
689 virtual void draw( bool editMode ) {
690         target.draw( editMode );
691 }
692
693 virtual void updateSelection( const idVec3 &move ) {
694         idCameraPosition::updateSelection( move );
695         target.buildSpline();
696 }
697
698 protected:
699 idSplineList target;
700 long lastTime;
701 float distSoFar;
702 };
703
704 class idCameraFOV {
705 public:
706
707 idCameraFOV() {
708         time = 0;
709         length = 0;
710         fov = 90;
711 }
712
713 idCameraFOV( int v ) {
714         time = 0;
715         length = 0;
716         fov = v;
717 }
718
719 idCameraFOV( int s, int e, long t ) {
720         startFOV = s;
721         endFOV = e;
722         length = t;
723 }
724
725
726 ~idCameraFOV(){}
727
728 void setFOV( float f ) {
729         fov = f;
730 }
731
732 float getFOV( long t ) {
733         if ( length ) {
734                 float percent = ( t - startTime ) / length;
735                 if ( percent < 0.0 ) {
736                         percent = 0.0;
737                 }
738                 else if ( percent > 1.0 ) {
739                         percent = 1.0;
740                 }
741                 float temp = endFOV - startFOV;
742                 temp *= percent;
743                 fov = startFOV + temp;
744
745                 if ( percent == 1.0 ) {
746                         length = 0.0;
747                 }
748         }
749         return fov;
750 }
751
752 void start( long t ) {
753         startTime = t;
754 }
755
756 void reset( float startfov, float endfov, int start, float len ) {
757         startFOV = startfov;
758         endFOV = endfov;
759         startTime = start;
760         length = len * 1000;
761 }
762
763 void parse( const char *( *text ) );
764 void write( fileHandle_t file, const char *name );
765
766 protected:
767 float fov;
768 float startFOV;
769 float endFOV;
770 int startTime;
771 int time;
772 float length;
773 };
774
775
776
777
778 class idCameraEvent {
779 public:                     // parameters
780 enum eventType {
781         EVENT_NA = 0x00,
782         EVENT_WAIT,             //
783         EVENT_TARGETWAIT,       //
784         EVENT_SPEED,            //
785         EVENT_TARGET,           // char(name)
786         EVENT_SNAPTARGET,       //
787         EVENT_FOV,              // int(time), int(targetfov)
788         EVENT_CMD,              //
789         EVENT_TRIGGER,          //
790         EVENT_STOP,             //
791         EVENT_CAMERA,           //
792         EVENT_FADEOUT,          // int(time)
793         EVENT_FADEIN,           // int(time)
794         EVENT_FEATHER,          //
795         EVENT_COUNT
796 };
797
798 static const char* eventStr[EVENT_COUNT];
799
800 idCameraEvent() {
801         paramStr = "";
802         type = EVENT_NA;
803         time = 0;
804 }
805
806 idCameraEvent( eventType t, const char *param, long n ) {
807         type = t;
808         paramStr = param;
809         time = n;
810 }
811
812 ~idCameraEvent() {};
813
814 eventType getType() {
815         return type;
816 }
817
818 const char *typeStr() {
819         return eventStr[static_cast<int>( type )];
820 }
821
822 const char *getParam() {
823         return paramStr.c_str();
824 }
825
826 long getTime() {
827         return time;
828 }
829
830 void setTime( long n ) {
831         time = n;
832 }
833
834 void parse( const char *( *text ) );
835 void write( fileHandle_t file, const char *name );
836
837 void setTriggered( bool b ) {
838         triggered = b;
839 }
840
841 bool getTriggered() {
842         return triggered;
843 }
844
845 protected:
846 eventType type;
847 idStr paramStr;
848 long time;
849 bool triggered;
850
851 };
852
853 class idCameraDef {
854 public:
855
856 void clear() {
857         currentCameraPosition = 0;
858         cameraRunning = false;
859         lastDirection.Zero();
860         baseTime = 30;
861         activeTarget = 0;
862         name = "camera01";
863         fov.setFOV( 90 );
864         int i;
865         for ( i = 0; i < targetPositions.Num(); i++ ) {
866                 delete targetPositions[i];
867         }
868         for ( i = 0; i < events.Num(); i++ ) {
869                 delete events[i];
870         }
871         delete cameraPosition;
872         cameraPosition = NULL;
873         events.Clear();
874         targetPositions.Clear();
875 }
876
877 idCameraPosition *startNewCamera( idCameraPosition::positionType type ) {
878         clear();
879         if ( type == idCameraPosition::SPLINE ) {
880                 cameraPosition = new idSplinePosition();
881         }
882         else if ( type == idCameraPosition::INTERPOLATED ) {
883                 cameraPosition = new idInterpolatedPosition();
884         }
885         else {
886                 cameraPosition = new idFixedPosition();
887         }
888         return cameraPosition;
889 }
890
891 idCameraDef() {
892         cameraPosition = NULL;
893         clear();
894 }
895
896 ~idCameraDef() {
897         clear();
898 }
899
900 void addEvent( idCameraEvent::eventType t, const char *param, long time );
901
902 void addEvent( idCameraEvent *event );
903
904 void removeEvent( int index );
905
906 static int sortEvents( const void *p1, const void *p2 );
907
908 int numEvents() {
909         return events.Num();
910 }
911
912 idCameraEvent *getEvent( int index ) {
913         assert( index >= 0 && index < events.Num() );
914         return events[index];
915 }
916
917 void parse( const char *( *text ) );
918 bool load( const char *filename );
919 void save( const char *filename );
920
921 void buildCamera();
922
923 //idSplineList *getcameraPosition() {
924 //      return &cameraPosition;
925 //}
926
927 static idCameraPosition *newFromType( idCameraPosition::positionType t ) {
928         switch ( t ) {
929         case idCameraPosition::FIXED: return new idFixedPosition();
930         case idCameraPosition::INTERPOLATED: return new idInterpolatedPosition();
931         case idCameraPosition::SPLINE: return new idSplinePosition();
932         default:
933                 break;
934         };
935         return NULL;
936 }
937
938 void addTarget( const char *name, idCameraPosition::positionType type );
939
940 idCameraPosition *getActiveTarget() {
941         if ( targetPositions.Num() == 0 ) {
942                 addTarget( NULL, idCameraPosition::FIXED );
943         }
944         return targetPositions[activeTarget];
945 }
946
947 idCameraPosition *getActiveTarget( int index ) {
948         if ( targetPositions.Num() == 0 ) {
949                 addTarget( NULL, idCameraPosition::FIXED );
950                 return targetPositions[0];
951         }
952         return targetPositions[index];
953 }
954
955 int numTargets() {
956         return targetPositions.Num();
957 }
958
959
960 void setActiveTargetByName( const char *name ) {
961         for ( int i = 0; i < targetPositions.Num(); i++ ) {
962                 if ( Q_stricmp( name, targetPositions[i]->getName() ) == 0 ) {
963                         setActiveTarget( i );
964                         return;
965                 }
966         }
967 }
968
969 void setActiveTarget( int index ) {
970         assert( index >= 0 && index < targetPositions.Num() );
971         activeTarget = index;
972 }
973
974 void setRunning( bool b ) {
975         cameraRunning = b;
976 }
977
978 void setBaseTime( float f ) {
979         baseTime = f;
980 }
981
982 float getBaseTime() {
983         return baseTime;
984 }
985
986 float getTotalTime() {
987         return totalTime;
988 }
989
990 void startCamera( long t );
991 void stopCamera() {
992         cameraRunning = true;
993 }
994 void getActiveSegmentInfo( int segment, idVec3 &origin, idVec3 &direction, float *fv );
995
996 bool getCameraInfo( long time, idVec3 &origin, idVec3 &direction, float *fv );
997 bool getCameraInfo( long time, float *origin, float *direction, float *fv ) {
998         idVec3 org, dir;
999         org[0] = origin[0];
1000         org[1] = origin[1];
1001         org[2] = origin[2];
1002         dir[0] = direction[0];
1003         dir[1] = direction[1];
1004         dir[2] = direction[2];
1005         bool b = getCameraInfo( time, org, dir, fv );
1006         origin[0] = org[0];
1007         origin[1] = org[1];
1008         origin[2] = org[2];
1009         direction[0] = dir[0];
1010         direction[1] = dir[1];
1011         direction[2] = dir[2];
1012         return b;
1013 }
1014
1015 void draw( bool editMode ) {
1016         // gcc doesn't allow casting away from bools
1017         // why?  I've no idea...
1018         if ( cameraPosition ) {
1019                 cameraPosition->draw( (bool)( ( editMode || cameraRunning ) && cameraEdit ) );
1020                 int count = targetPositions.Num();
1021                 for ( int i = 0; i < count; i++ ) {
1022                         targetPositions[i]->draw( (bool)( ( editMode || cameraRunning ) && i == activeTarget && !cameraEdit ) );
1023                 }
1024         }
1025 }
1026
1027 /*
1028     int numSegments() {
1029         if (cameraEdit) {
1030             return cameraPosition.numSegments();
1031         }
1032         return getTargetSpline()->numSegments();
1033     }
1034
1035     int getActiveSegment() {
1036         if (cameraEdit) {
1037             return cameraPosition.getActiveSegment();
1038         }
1039         return getTargetSpline()->getActiveSegment();
1040     }
1041
1042     void setActiveSegment(int i) {
1043         if (cameraEdit) {
1044             cameraPosition.setActiveSegment(i);
1045         } else {
1046             getTargetSpline()->setActiveSegment(i);
1047         }
1048     }
1049  */
1050 int numPoints() {
1051         if ( cameraEdit ) {
1052                 return cameraPosition->numPoints();
1053         }
1054         return getActiveTarget()->numPoints();
1055 }
1056
1057 const idVec3 *getPoint( int index ) {
1058         if ( cameraEdit ) {
1059                 return cameraPosition->getPoint( index );
1060         }
1061         return getActiveTarget()->getPoint( index );
1062 }
1063
1064 void stopEdit() {
1065         editMode = false;
1066         if ( cameraEdit ) {
1067                 cameraPosition->stopEdit();
1068         }
1069         else {
1070                 getActiveTarget()->stopEdit();
1071         }
1072 }
1073
1074 void startEdit( bool camera ) {
1075         cameraEdit = camera;
1076         if ( camera ) {
1077                 cameraPosition->startEdit();
1078                 for ( int i = 0; i < targetPositions.Num(); i++ ) {
1079                         targetPositions[i]->stopEdit();
1080                 }
1081         }
1082         else {
1083                 getActiveTarget()->startEdit();
1084                 cameraPosition->stopEdit();
1085         }
1086         editMode = true;
1087 }
1088
1089 bool waitEvent( int index );
1090
1091 const char *getName() {
1092         return name.c_str();
1093 }
1094
1095 void setName( const char *p ) {
1096         name = p;
1097 }
1098
1099 idCameraPosition *getPositionObj() {
1100         if ( cameraPosition == NULL ) {
1101                 cameraPosition = new idFixedPosition();
1102         }
1103         return cameraPosition;
1104 }
1105
1106 protected:
1107 idStr name;
1108 int currentCameraPosition;
1109 idVec3 lastDirection;
1110 bool cameraRunning;
1111 idCameraPosition *cameraPosition;
1112 idList<idCameraPosition*> targetPositions;
1113 idList<idCameraEvent*> events;
1114 idCameraFOV fov;
1115 int activeTarget;
1116 float totalTime;
1117 float baseTime;
1118 long startTime;
1119
1120 bool cameraEdit;
1121 bool editMode;
1122 };
1123
1124 extern bool g_splineMode;
1125
1126 extern idCameraDef *g_splineList;
1127
1128
1129 #endif