2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
26 int FS_Write( const void *buffer, int len, fileHandle_t h );
27 int FS_ReadFile( const char *qpath, void **buffer );
28 void FS_FreeFile( void *buffer );
29 fileHandle_t FS_FOpenFileWrite( const char *filename );
30 void FS_FCloseFile( fileHandle_t f );
31 void Cbuf_AddText( const char *text );
32 void Cbuf_Execute (void);
35 float Q_fabs( float f ) {
36 int tmp = * ( int * ) &f;
38 return * ( float * ) &tmp;
41 // (SA) making a list of cameras so I can use
42 // the splines as targets for other things.
43 // Certainly better ways to do this, but this lets
44 // me get underway quickly with ents that need spline
46 #define MAX_CAMERAS 64
48 idCameraDef camera[MAX_CAMERAS];
51 qboolean loadCamera(int camNum, const char *name) {
52 if(camNum < 0 || camNum >= MAX_CAMERAS )
54 camera[camNum].clear();
55 return (qboolean)camera[camNum].load(name);
58 qboolean getCameraInfo(int camNum, int time, float *origin, float *angles, float *fov) {
60 if(camNum < 0 || camNum >= MAX_CAMERAS )
65 if (camera[camNum].getCameraInfo(time, org, dir, fov)) {
69 angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
70 angles[0] = asin (dir[2])*180/3.14159;
76 void startCamera(int camNum, int time) {
77 if(camNum < 0 || camNum >= MAX_CAMERAS )
79 camera[camNum].startCamera(time);
85 //#include "../shared/windings.h"
86 //#include "../qcommon/qcommon.h"
87 //#include "../sys/sys_public.h"
88 //#include "../game/game_entity.h"
90 idCameraDef splineList;
91 idCameraDef *g_splineList = &splineList;
93 idVec3 idSplineList::zero(0,0,0);
95 void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label) {
106 glCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
110 void glBox(idVec3 &color, idVec3 &point, float size) {
120 glBegin(GL_LINE_LOOP);
121 glVertex3f(mins[0],mins[1],mins[2]);
122 glVertex3f(maxs[0],mins[1],mins[2]);
123 glVertex3f(maxs[0],maxs[1],mins[2]);
124 glVertex3f(mins[0],maxs[1],mins[2]);
126 glBegin(GL_LINE_LOOP);
127 glVertex3f(mins[0],mins[1],maxs[2]);
128 glVertex3f(maxs[0],mins[1],maxs[2]);
129 glVertex3f(maxs[0],maxs[1],maxs[2]);
130 glVertex3f(mins[0],maxs[1],maxs[2]);
134 glVertex3f(mins[0],mins[1],mins[2]);
135 glVertex3f(mins[0],mins[1],maxs[2]);
136 glVertex3f(mins[0],maxs[1],maxs[2]);
137 glVertex3f(mins[0],maxs[1],mins[2]);
138 glVertex3f(maxs[0],mins[1],mins[2]);
139 glVertex3f(maxs[0],mins[1],maxs[2]);
140 glVertex3f(maxs[0],maxs[1],maxs[2]);
141 glVertex3f(maxs[0],maxs[1],mins[2]);
147 //g_splineList->load("p:/doom/base/maps/test_base1.camera");
151 //g_splineList->addToRenderer();
155 //extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end );
157 void debugLine(idVec3 &color, float x, float y, float z, float x2, float y2, float z2) {
158 idVec3 from(x, y, z);
159 idVec3 to(x2, y2, z2);
160 //D_DebugLine(color, from, to);
163 void idSplineList::addToRenderer() {
165 if (controlPoints.Num() == 0) {
170 idVec3 yellow(1.0, 1.0, 0);
171 idVec3 white(1.0, 1.0, 1.0);
174 for(i = 0; i < controlPoints.Num(); i++) {
175 VectorCopy(*controlPoints[i], mins);
176 VectorCopy(mins, maxs);
183 debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
184 debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
185 debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
186 debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
188 debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
189 debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
190 debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
191 debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
197 for(i = 3; i < controlPoints.Num(); i++) {
198 for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
202 for (int j = 0; j < 4; j++) {
203 x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
204 y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
205 z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
213 debugLine( white, step1[0], step1[1], step1[2], x, y, z);
221 void idSplineList::buildSpline() {
222 //int start = Sys_Milliseconds();
224 for(int i = 3; i < controlPoints.Num(); i++) {
225 for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
229 for (int j = 0; j < 4; j++) {
230 x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
231 y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
232 z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
234 splinePoints.Append(new idVec3(x, y, z));
238 //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
242 void idSplineList::draw(bool editMode) {
244 idVec4 yellow(1, 1, 0, 1);
246 if (controlPoints.Num() == 0) {
255 glColor3fv(controlColor);
259 for (i = 0; i < controlPoints.Num(); i++) {
260 glVertex3fv(*controlPoints[i]);
265 for(i = 0; i < controlPoints.Num(); i++) {
266 glBox(activeColor, *controlPoints[i], 4);
271 glColor3fv(pathColor);
272 glBegin(GL_LINE_STRIP);
273 int count = splinePoints.Num();
274 for (i = 0; i < count; i++) {
275 glVertex3fv(*splinePoints[i]);
280 glColor3fv(segmentColor);
283 for (i = 0; i < count; i++) {
284 glVertex3fv(*splinePoints[i]);
289 //assert(activeSegment >=0 && activeSegment < count);
290 if (activeSegment >=0 && activeSegment < count) {
291 glBox(activeColor, *splinePoints[activeSegment], 6);
292 glBox(yellow, *splinePoints[activeSegment], 8);
298 float idSplineList::totalDistance() {
300 // FIXME: save dist and return
302 if (controlPoints.Num() == 0) {
312 int count = splinePoints.Num();
313 for(int i = 1; i < count; i++) {
314 temp = *splinePoints[i-1];
315 temp -= *splinePoints[i];
316 dist += temp.Length();
321 void idSplineList::initPosition(long bt, long totalTime) {
327 if (splinePoints.Num() == 0) {
334 // calc distance to travel ( this will soon be broken into time segments )
336 splineTime.Append(bt);
337 double dist = totalDistance();
338 double distSoFar = 0.0;
340 int count = splinePoints.Num();
341 //for(int i = 2; i < count - 1; i++) {
342 for(int i = 1; i < count; i++) {
343 temp = *splinePoints[i-1];
344 temp -= *splinePoints[i];
345 distSoFar += temp.Length();
346 double percent = distSoFar / dist;
347 percent *= totalTime;
348 splineTime.Append(percent + bt);
350 assert(splineTime.Num() == splinePoints.Num());
356 float idSplineList::calcSpline(int step, float tension) {
358 case 0: return (pow(1 - tension, 3)) / 6;
359 case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
360 case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
361 case 3: return pow(tension, 3) / 6;
368 void idSplineList::updateSelection(const idVec3 &move) {
371 VectorAdd(*selected, move, *selected);
376 void idSplineList::setSelectedPoint(idVec3 *p) {
379 for(int i = 0; i < controlPoints.Num(); i++) {
380 if (*p == *controlPoints[i]) {
381 selected = controlPoints[i];
389 const idVec3 *idSplineList::getPosition(long t) {
390 static idVec3 interpolatedPos;
391 static long lastTime = -1;
393 int count = splineTime.Num();
398 // Com_Printf("Time: %d\n", t);
399 assert(splineTime.Num() == splinePoints.Num());
401 while (activeSegment < count) {
402 if (splineTime[activeSegment] >= t) {
403 if (activeSegment > 0 && activeSegment < count - 1) {
404 double timeHi = splineTime[activeSegment + 1];
405 double timeLo = splineTime[activeSegment - 1];
406 double percent = (timeHi - t) / (timeHi - timeLo);
407 // pick two bounding points
408 idVec3 v1 = *splinePoints[activeSegment-1];
409 idVec3 v2 = *splinePoints[activeSegment+1];
410 v2 *= (1.0 - percent);
413 interpolatedPos = v2;
414 return &interpolatedPos;
416 return splinePoints[activeSegment];
421 return splinePoints[count-1];
424 void idSplineList::parse(const char *(*text) ) {
426 //Com_MatchToken( text, "{" );
428 token = Com_Parse( text );
433 if ( !Q_stricmp (token, "}") ) {
438 // if token is not a brace, it is a key for a key/value pair
439 if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {
444 idStr key = Com_ParseOnLine(text);
445 const char *token = Com_Parse(text);
446 if (Q_stricmp(key.c_str(), "granularity") == 0) {
447 granularity = atof(token);
448 } else if (Q_stricmp(key.c_str(), "name") == 0) {
451 token = Com_Parse(text);
455 if ( !Q_stricmp (token, "}") ) {
460 // read the control point
462 Com_Parse1DMatrix( text, 3, point );
463 addPoint(point.x, point.y, point.z);
467 //Com_MatchToken( text, "}" );
471 void idSplineList::write(fileHandle_t file, const char *p) {
472 idStr s = va("\t\t%s {\n", p);
473 FS_Write(s.c_str(), s.length(), file);
474 //s = va("\t\tname %s\n", name.c_str());
475 //FS_Write(s.c_str(), s.length(), file);
476 s = va("\t\t\tgranularity %f\n", granularity);
477 FS_Write(s.c_str(), s.length(), file);
478 int count = controlPoints.Num();
479 for (int i = 0; i < count; i++) {
480 s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z);
481 FS_Write(s.c_str(), s.length(), file);
484 FS_Write(s.c_str(), s.length(), file);
488 void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) {
490 if (!cameraSpline.validTime()) {
493 double d = (double)segment / numSegments();
494 getCameraInfo(d * totalTime * 1000, origin, direction, fov);
497 if (!cameraSpline.validTime()) {
500 origin = *cameraSpline.getSegmentPoint(segment);
505 int numTargets = getTargetSpline()->controlPoints.Num();
506 int count = cameraSpline.splineTime.Num();
507 if (numTargets == 0) {
509 if (cameraSpline.getActiveSegment() < count - 1) {
510 temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
512 } else if (numTargets == 1) {
513 temp = *getTargetSpline()->controlPoints[0];
515 temp = *getTargetSpline()->getSegmentPoint(segment);
524 bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) {
528 if ((time - startTime) / 1000 > totalTime) {
533 for (int i = 0; i < events.Num(); i++) {
534 if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {
535 events[i]->setTriggered(true);
536 if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {
537 setActiveTargetByName(events[i]->getParam());
538 getActiveTarget()->start(startTime + events[i]->getTime());
539 //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
540 } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {
541 //idEntity *ent = NULL;
542 //ent = level.FindTarget( ent, events[i]->getParam());
544 // ent->signal( SIG_TRIGGER );
545 // ent->ProcessEvent( &EV_Activate, world );
547 } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {
548 memset(buff, 0, sizeof(buff));
549 strcpy(buff, events[i]->getParam());
550 const char *param1 = strtok(buff, " \t,\0");
551 const char *param2 = strtok(NULL, " \t,\0");
552 float len = (param2) ? atof(param2) : 0;
553 float newfov = (param1) ? atof(param1) : 90;
554 fov.reset(fov.getFOV(time), newfov, time, len);
555 //*fv = fov = atof(events[i]->getParam());
556 } else if (events[i]->getType() == idCameraEvent::EVENT_FADEIN) {
557 float time = atof(events[i]->getParam());
558 Cbuf_AddText(va("fade 0 0 0 0 %f", time));
560 } else if (events[i]->getType() == idCameraEvent::EVENT_FADEOUT) {
561 float time = atof(events[i]->getParam());
562 Cbuf_AddText(va("fade 0 0 0 255 %f", time));
564 } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) {
565 memset(buff, 0, sizeof(buff));
566 strcpy(buff, events[i]->getParam());
567 const char *param1 = strtok(buff, " \t,\0");
568 const char *param2 = strtok(NULL, " \t,\0");
571 loadCamera(atoi(param1), va("cameras/%s.camera", param2));
574 loadCamera(0, va("cameras/%s.camera", events[i]->getParam()));
578 } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {
584 origin = *cameraPosition->getPosition(time);
586 *fv = fov.getFOV(time);
588 idVec3 temp = origin;
590 int numTargets = targetPositions.Num();
591 if (numTargets == 0) {
594 if (cameraSpline.getActiveSegment() < count - 1) {
595 temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
596 if (temp == origin) {
597 int index = cameraSpline.getActiveSegment() + 2;
598 while (temp == origin && index < count - 1) {
599 temp = *cameraSpline.splinePoints[index++];
605 if( getActiveTarget()->numPoints() > 0 ) {
606 temp = *getActiveTarget()->getPosition(time);
617 bool idCameraDef::waitEvent(int index) {
618 //for (int i = 0; i < events.Num(); i++) {
619 // if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
627 #define NUM_CCELERATION_SEGS 10
630 void idCameraDef::buildCamera() {
636 totalTime = baseTime;
637 cameraPosition->setTime((long)totalTime * 1000);
638 // we have a base time layout for the path and the target path
639 // now we need to layer on any wait or speed changes
640 for (i = 0; i < events.Num(); i++) {
641 idCameraEvent *ev = events[i];
642 events[i]->setTriggered(false);
643 switch (events[i]->getType()) {
644 case idCameraEvent::EVENT_TARGET : {
648 case idCameraEvent::EVENT_FEATHER : {
652 float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime);
653 while (startTime <= 1000) {
654 cameraPosition->addVelocity(startTime, loopTime, speed);
656 if (speed > cameraPosition->getBaseVelocity()) {
657 speed = cameraPosition->getBaseVelocity();
659 startTime += loopTime;
662 startTime = (long)(totalTime * 1000 - 1000);
663 long endTime = startTime + 1000;
664 speed = cameraPosition->getBaseVelocity();
665 while (startTime < endTime) {
670 cameraPosition->addVelocity(startTime, loopTime, speed);
671 startTime += loopTime;
676 case idCameraEvent::EVENT_WAIT : {
677 waits.Append(atof(events[i]->getParam()));
679 //FIXME: this is quite hacky for Wolf E3, accel and decel needs
680 // do be parameter based etc..
681 long startTime = events[i]->getTime() - 1000;
685 float speed = cameraPosition->getBaseVelocity();
687 float steps = speed / ((events[i]->getTime() - startTime) / loopTime);
688 while (startTime <= events[i]->getTime() - loopTime) {
689 cameraPosition->addVelocity(startTime, loopTime, speed);
691 startTime += loopTime;
693 cameraPosition->addVelocity(events[i]->getTime(), (long)atof(events[i]->getParam()) * 1000, 0);
695 startTime = (long)(events[i]->getTime() + atof(events[i]->getParam()) * 1000);
696 long endTime = startTime + 1000;
698 while (startTime <= endTime) {
699 cameraPosition->addVelocity(startTime, loopTime, speed);
701 startTime += loopTime;
705 case idCameraEvent::EVENT_TARGETWAIT : {
706 //targetWaits.Append(i);
709 case idCameraEvent::EVENT_SPEED : {
711 // take the average delay between up to the next five segments
712 float adjust = atof(events[i]->getParam());
713 int index = events[i]->getSegment();
717 // get total amount of time over the remainder of the segment
718 for (j = index; j < cameraSpline.numSegments() - 1; j++) {
719 total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
723 // multiply that by the adjustment
724 double newTotal = total * adjust;
725 // what is the difference..
727 totalTime += newTotal / 1000;
729 // per segment difference
731 int additive = newTotal;
733 // now propogate that difference out to each segment
734 for (j = index; j < cameraSpline.numSegments(); j++) {
735 cameraSpline.addSegmentTime(j, additive);
736 additive += newTotal;
745 for (i = 0; i < waits.Num(); i++) {
746 totalTime += waits[i];
749 // on a new target switch, we need to take time to this point ( since last target switch )
750 // and allocate it across the active target, then reset time to this point
752 long total = (long)(totalTime * 1000);
753 for (i = 0; i < targets.Num(); i++) {
755 if (i < targets.Num() - 1) {
756 t = events[targets[i+1]]->getTime();
758 t = total - timeSoFar;
760 // t is how much time to use for this target
761 setActiveTargetByName(events[targets[i]]->getParam());
762 getActiveTarget()->setTime(t);
769 void idCameraDef::startCamera(long t) {
770 cameraPosition->clearVelocities();
771 cameraPosition->start(t);
773 fov.reset(90, 90, t, 0);
774 //for (int i = 0; i < targetPositions.Num(); i++) {
775 // targetPositions[i]->
778 cameraRunning = true;
782 void idCameraDef::parse(const char *(*text) ) {
786 token = Com_Parse( text );
791 if ( !Q_stricmp (token, "}") ) {
795 if (Q_stricmp(token, "time") == 0) {
796 baseTime = Com_ParseFloat(text);
798 else if (Q_stricmp(token, "camera_fixed") == 0) {
799 cameraPosition = new idFixedPosition();
800 cameraPosition->parse(text);
802 else if (Q_stricmp(token, "camera_interpolated") == 0) {
803 cameraPosition = new idInterpolatedPosition();
804 cameraPosition->parse(text);
806 else if (Q_stricmp(token, "camera_spline") == 0) {
807 cameraPosition = new idSplinePosition();
808 cameraPosition->parse(text);
810 else if (Q_stricmp(token, "target_fixed") == 0) {
811 idFixedPosition *pos = new idFixedPosition();
813 targetPositions.Append(pos);
815 else if (Q_stricmp(token, "target_interpolated") == 0) {
816 idInterpolatedPosition *pos = new idInterpolatedPosition();
818 targetPositions.Append(pos);
820 else if (Q_stricmp(token, "target_spline") == 0) {
821 idSplinePosition *pos = new idSplinePosition();
823 targetPositions.Append(pos);
825 else if (Q_stricmp(token, "fov") == 0) {
828 else if (Q_stricmp(token, "event") == 0) {
829 idCameraEvent *event = new idCameraEvent();
837 if ( !cameraPosition ) {
838 Com_Printf( "no camera position specified\n" );
839 // prevent a crash later on
840 cameraPosition = new idFixedPosition();
844 Com_MatchToken( text, "}" );
848 bool idCameraDef::load(const char *filename) {
851 int length = FS_ReadFile( filename, (void **)&buf );
857 Com_BeginParseSession( filename );
860 Com_EndParseSession();
866 void idCameraDef::save(const char *filename) {
867 fileHandle_t file = FS_FOpenFileWrite(filename);
870 idStr s = "cameraPathDef { \n";
871 FS_Write(s.c_str(), s.length(), file);
872 s = va("\ttime %f\n", baseTime);
873 FS_Write(s.c_str(), s.length(), file);
875 cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr()));
877 for (i = 0; i < numTargets(); i++) {
878 targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr()));
881 for (i = 0; i < events.Num(); i++) {
882 events[i]->write(file, "event");
885 fov.write(file, "fov");
888 FS_Write(s.c_str(), s.length(), file);
893 int idCameraDef::sortEvents(const void *p1, const void *p2) {
894 idCameraEvent *ev1 = (idCameraEvent*)(p1);
895 idCameraEvent *ev2 = (idCameraEvent*)(p2);
897 if (ev1->getTime() > ev2->getTime()) {
900 if (ev1->getTime() < ev2->getTime()) {
906 void idCameraDef::addEvent(idCameraEvent *event) {
907 events.Append(event);
908 //events.Sort(&sortEvents);
911 void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {
912 addEvent(new idCameraEvent(t, param, time));
916 void idCameraDef::removeEvent(int index) {
917 events.RemoveIndex(index);
922 const char *idCameraEvent::eventStr[] = {
939 void idCameraEvent::parse(const char *(*text) ) {
941 Com_MatchToken( text, "{" );
943 token = Com_Parse( text );
948 if ( !strcmp (token, "}") ) {
952 // here we may have to jump over brush epairs ( only used in editor )
954 // if token is not a brace, it is a key for a key/value pair
955 if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
960 idStr key = Com_ParseOnLine(text);
961 const char *token = Com_Parse(text);
962 if (Q_stricmp(key.c_str(), "type") == 0) {
963 type = static_cast<idCameraEvent::eventType>(atoi(token));
964 } else if (Q_stricmp(key.c_str(), "param") == 0) {
966 } else if (Q_stricmp(key.c_str(), "time") == 0) {
969 token = Com_Parse(text);
973 if ( !strcmp (token, "}") ) {
980 Com_MatchToken( text, "}" );
983 void idCameraEvent::write(fileHandle_t file, const char *name) {
984 idStr s = va("\t%s {\n", name);
985 FS_Write(s.c_str(), s.length(), file);
986 s = va("\t\ttype %d\n", static_cast<int>(type));
987 FS_Write(s.c_str(), s.length(), file);
988 s = va("\t\tparam \"%s\"\n", paramStr.c_str());
989 FS_Write(s.c_str(), s.length(), file);
990 s = va("\t\ttime %d\n", time);
991 FS_Write(s.c_str(), s.length(), file);
993 FS_Write(s.c_str(), s.length(), file);
997 const char *idCameraPosition::positionStr[] = {
1005 const idVec3 *idInterpolatedPosition::getPosition(long t) {
1006 static idVec3 interpolatedPos;
1008 float velocity = getVelocity(t);
1009 float timePassed = t - lastTime;
1012 // convert to seconds
1015 float distToTravel = timePassed * velocity;
1017 idVec3 temp = startPos;
1019 float distance = temp.Length();
1021 distSoFar += distToTravel;
1022 float percent = (float)(distSoFar) / distance;
1024 if (percent > 1.0) {
1026 } else if (percent < 0.0) {
1030 // the following line does a straigt calc on percentage of time
1031 // float percent = (float)(startTime + time - t) / time;
1033 idVec3 v1 = startPos;
1035 v1 *= (1.0 - percent);
1038 interpolatedPos = v1;
1039 return &interpolatedPos;
1043 void idCameraFOV::parse(const char *(*text) ) {
1045 Com_MatchToken( text, "{" );
1047 token = Com_Parse( text );
1052 if ( !strcmp (token, "}") ) {
1056 // here we may have to jump over brush epairs ( only used in editor )
1058 // if token is not a brace, it is a key for a key/value pair
1059 if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
1064 idStr key = Com_ParseOnLine(text);
1065 const char *token = Com_Parse(text);
1066 if (Q_stricmp(key.c_str(), "fov") == 0) {
1068 } else if (Q_stricmp(key.c_str(), "startFOV") == 0) {
1069 startFOV = atof(token);
1070 } else if (Q_stricmp(key.c_str(), "endFOV") == 0) {
1071 endFOV = atof(token);
1072 } else if (Q_stricmp(key.c_str(), "time") == 0) {
1075 token = Com_Parse(text);
1079 if ( !strcmp (token, "}") ) {
1086 Com_MatchToken( text, "}" );
1089 bool idCameraPosition::parseToken(const char *key, const char *(*text)) {
1090 const char *token = Com_Parse(text);
1091 if (Q_stricmp(key, "time") == 0) {
1094 } else if (Q_stricmp(key, "type") == 0) {
1095 type = static_cast<idCameraPosition::positionType>(atoi(token));
1097 } else if (Q_stricmp(key, "velocity") == 0) {
1098 long t = atol(token);
1099 token = Com_Parse(text);
1100 long d = atol(token);
1101 token = Com_Parse(text);
1102 float s = atof(token);
1103 addVelocity(t, d, s);
1105 } else if (Q_stricmp(key, "baseVelocity") == 0) {
1106 baseVelocity = atof(token);
1108 } else if (Q_stricmp(key, "name") == 0) {
1111 } else if (Q_stricmp(key, "time") == 0) {
1121 void idFixedPosition::parse(const char *(*text) ) {
1123 Com_MatchToken( text, "{" );
1125 token = Com_Parse( text );
1130 if ( !strcmp (token, "}") ) {
1134 // here we may have to jump over brush epairs ( only used in editor )
1136 // if token is not a brace, it is a key for a key/value pair
1137 if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
1142 idStr key = Com_ParseOnLine(text);
1144 const char *token = Com_Parse(text);
1145 if (Q_stricmp(key.c_str(), "pos") == 0) {
1147 Com_Parse1DMatrix( text, 3, pos );
1150 idCameraPosition::parseToken(key.c_str(), text);
1152 token = Com_Parse(text);
1156 if ( !strcmp (token, "}") ) {
1163 Com_MatchToken( text, "}" );
1166 void idInterpolatedPosition::parse(const char *(*text) ) {
1168 Com_MatchToken( text, "{" );
1170 token = Com_Parse( text );
1175 if ( !strcmp (token, "}") ) {
1179 // here we may have to jump over brush epairs ( only used in editor )
1181 // if token is not a brace, it is a key for a key/value pair
1182 if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
1187 idStr key = Com_ParseOnLine(text);
1189 const char *token = Com_Parse(text);
1190 if (Q_stricmp(key.c_str(), "startPos") == 0) {
1192 Com_Parse1DMatrix( text, 3, startPos );
1193 } else if (Q_stricmp(key.c_str(), "endPos") == 0) {
1195 Com_Parse1DMatrix( text, 3, endPos );
1198 idCameraPosition::parseToken(key.c_str(), text);
1200 token = Com_Parse(text);
1204 if ( !strcmp (token, "}") ) {
1211 Com_MatchToken( text, "}" );
1215 void idSplinePosition::parse(const char *(*text) ) {
1217 Com_MatchToken( text, "{" );
1219 token = Com_Parse( text );
1224 if ( !strcmp (token, "}") ) {
1228 // here we may have to jump over brush epairs ( only used in editor )
1230 // if token is not a brace, it is a key for a key/value pair
1231 if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
1236 idStr key = Com_ParseOnLine(text);
1238 const char *token = Com_Parse(text);
1239 if (Q_stricmp(key.c_str(), "target") == 0) {
1243 idCameraPosition::parseToken(key.c_str(), text);
1245 token = Com_Parse(text);
1249 if ( !strcmp (token, "}") ) {
1256 Com_MatchToken( text, "}" );
1261 void idCameraFOV::write(fileHandle_t file, const char *p) {
1262 idStr s = va("\t%s {\n", p);
1263 FS_Write(s.c_str(), s.length(), file);
1265 s = va("\t\tfov %f\n", fov);
1266 FS_Write(s.c_str(), s.length(), file);
1268 s = va("\t\tstartFOV %f\n", startFOV);
1269 FS_Write(s.c_str(), s.length(), file);
1271 s = va("\t\tendFOV %f\n", endFOV);
1272 FS_Write(s.c_str(), s.length(), file);
1274 s = va("\t\ttime %i\n", time);
1275 FS_Write(s.c_str(), s.length(), file);
1278 FS_Write(s.c_str(), s.length(), file);
1282 void idCameraPosition::write(fileHandle_t file, const char *p) {
1284 idStr s = va("\t\ttime %i\n", time);
1285 FS_Write(s.c_str(), s.length(), file);
1287 s = va("\t\ttype %i\n", static_cast<int>(type));
1288 FS_Write(s.c_str(), s.length(), file);
1290 s = va("\t\tname %s\n", name.c_str());
1291 FS_Write(s.c_str(), s.length(), file);
1293 s = va("\t\tbaseVelocity %f\n", baseVelocity);
1294 FS_Write(s.c_str(), s.length(), file);
1296 for (int i = 0; i < velocities.Num(); i++) {
1297 s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed);
1298 FS_Write(s.c_str(), s.length(), file);
1303 void idFixedPosition::write(fileHandle_t file, const char *p) {
1304 idStr s = va("\t%s {\n", p);
1305 FS_Write(s.c_str(), s.length(), file);
1306 idCameraPosition::write(file, p);
1307 s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z);
1308 FS_Write(s.c_str(), s.length(), file);
1310 FS_Write(s.c_str(), s.length(), file);
1313 void idInterpolatedPosition::write(fileHandle_t file, const char *p) {
1314 idStr s = va("\t%s {\n", p);
1315 FS_Write(s.c_str(), s.length(), file);
1316 idCameraPosition::write(file, p);
1317 s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z);
1318 FS_Write(s.c_str(), s.length(), file);
1319 s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z);
1320 FS_Write(s.c_str(), s.length(), file);
1322 FS_Write(s.c_str(), s.length(), file);
1325 void idSplinePosition::write(fileHandle_t file, const char *p) {
1326 idStr s = va("\t%s {\n", p);
1327 FS_Write(s.c_str(), s.length(), file);
1328 idCameraPosition::write(file, p);
1329 target.write(file, "target");
1331 FS_Write(s.c_str(), s.length(), file);
1334 void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {
1335 const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;
1336 idCameraPosition *pos = newFromType(type);
1339 targetPositions.Append(pos);
1340 activeTarget = numTargets()-1;
1341 if (activeTarget == 0) {
1343 addEvent(idCameraEvent::EVENT_TARGET, name, 0);
1348 const idVec3 *idSplinePosition::getPosition(long t) {
1349 static idVec3 interpolatedPos;
1351 float velocity = getVelocity(t);
1352 float timePassed = t - lastTime;
1355 // convert to seconds
1358 float distToTravel = timePassed * velocity;
1360 distSoFar += distToTravel;
1361 double tempDistance = target.totalDistance();
1363 double percent = (double)(distSoFar) / tempDistance;
1365 double targetDistance = percent * tempDistance;
1368 double lastDistance1,lastDistance2;
1369 lastDistance1 = lastDistance2 = 0;
1371 int count = target.numSegments();
1373 for(i = 1; i < count; i++) {
1374 temp = *target.getSegmentPoint(i-1);
1375 temp -= *target.getSegmentPoint(i);
1376 tempDistance += temp.Length();
1378 lastDistance1 = tempDistance;
1380 lastDistance2 = tempDistance;
1382 if (tempDistance >= targetDistance) {
1387 if ( i >= count - 1) {
1388 interpolatedPos = *target.getSegmentPoint(i-1);
1391 double timeHi = target.getSegmentTime(i + 1);
1392 double timeLo = target.getSegmentTime(i - 1);
1393 double percent = (timeHi - t) / (timeHi - timeLo);
1394 idVec3 v1 = *target.getSegmentPoint(i - 1);
1395 idVec3 v2 = *target.getSegmentPoint(i + 1);
1396 v2 *= (1.0 - percent);
1399 interpolatedPos = v2;
1401 if (lastDistance1 > lastDistance2) {
1402 double d = lastDistance2;
1403 lastDistance2 = lastDistance1;
1407 idVec3 v1 = *target.getSegmentPoint(i - 1);
1408 idVec3 v2 = *target.getSegmentPoint(i);
1409 double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1);
1410 v2 *= (1.0 - percent);
1413 interpolatedPos = v2;
1416 return &interpolatedPos;