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