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