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