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