]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - libs/splines/splines.cpp
more eol-style
[xonotic/netradiant.git] / libs / splines / splines.cpp
index 321f1fd9795d5a6d052f096b4457bb57ace4e96d..885dbc1048c0ea19cce36b315c70597d056e0899 100644 (file)
-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
-*/\r
-\r
-#include "q_shared.h"\r
-#include "splines.h"\r
-\r
-extern "C" {\r
-int FS_Write( const void *buffer, int len, fileHandle_t h );\r
-int FS_ReadFile( const char *qpath, void **buffer );\r
-void FS_FreeFile( void *buffer );\r
-fileHandle_t FS_FOpenFileWrite( const char *filename );\r
-void FS_FCloseFile( fileHandle_t f );\r
-void Cbuf_AddText( const char *text );\r
-void Cbuf_Execute (void);\r
-}\r
-\r
-float Q_fabs( float f ) {\r
-       int tmp = * ( int * ) &f;\r
-       tmp &= 0x7FFFFFFF;\r
-       return * ( float * ) &tmp;\r
-}\r
-\r
-// (SA) making a list of cameras so I can use\r
-//             the splines as targets for other things.\r
-//             Certainly better ways to do this, but this lets\r
-//             me get underway quickly with ents that need spline\r
-//             targets.\r
-#define MAX_CAMERAS 64\r
-\r
-idCameraDef camera[MAX_CAMERAS];\r
-\r
-extern "C" {\r
-qboolean loadCamera(int camNum, const char *name) {\r
-       if(camNum < 0 || camNum >= MAX_CAMERAS )\r
-               return qfalse;\r
-       camera[camNum].clear();\r
-       return (qboolean)camera[camNum].load(name);\r
-}\r
-\r
-qboolean getCameraInfo(int camNum, int time, float *origin, float *angles, float *fov) {\r
-       idVec3 dir, org;\r
-       if(camNum < 0 || camNum >= MAX_CAMERAS )\r
-               return qfalse;\r
-       org[0] = origin[0];\r
-       org[1] = origin[1];\r
-       org[2] = origin[2];\r
-       if (camera[camNum].getCameraInfo(time, org, dir, fov)) {\r
-               origin[0] = org[0];\r
-               origin[1] = org[1];\r
-               origin[2] = org[2];\r
-               angles[1] = atan2 (dir[1], dir[0])*180/3.14159;\r
-               angles[0] = asin (dir[2])*180/3.14159;\r
-               return qtrue;\r
-       }\r
-       return qfalse;\r
-}\r
-\r
-void startCamera(int camNum, int time) {\r
-       if(camNum < 0 || camNum >= MAX_CAMERAS )\r
-               return;\r
-       camera[camNum].startCamera(time);\r
-}\r
-\r
-}\r
-\r
-\r
-//#include "../shared/windings.h"\r
-//#include "../qcommon/qcommon.h"\r
-//#include "../sys/sys_public.h"\r
-//#include "../game/game_entity.h"\r
-\r
-idCameraDef splineList;\r
-idCameraDef *g_splineList = &splineList;\r
-\r
-idVec3 idSplineList::zero(0,0,0);\r
-\r
-void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label) {\r
-       qglColor3fv(color);\r
-       qglPointSize(size);\r
-       qglBegin(GL_POINTS);\r
-       qglVertex3fv(point);\r
-       qglEnd();\r
-       idVec3 v = point;\r
-       v.x += 1;\r
-       v.y += 1;\r
-       v.z += 1;\r
-       qglRasterPos3fv (v);\r
-       qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);\r
-}\r
-\r
-\r
-void glBox(idVec3 &color, idVec3 &point, float size) {\r
-       idVec3 mins(point);\r
-       idVec3 maxs(point);\r
-       mins[0] -= size;\r
-       mins[1] += size;\r
-       mins[2] -= size;\r
-       maxs[0] += size;\r
-       maxs[1] -= size;\r
-       maxs[2] += size;\r
-       qglColor3fv(color);\r
-       qglBegin(GL_LINE_LOOP);\r
-       qglVertex3f(mins[0],mins[1],mins[2]);\r
-       qglVertex3f(maxs[0],mins[1],mins[2]);\r
-       qglVertex3f(maxs[0],maxs[1],mins[2]);\r
-       qglVertex3f(mins[0],maxs[1],mins[2]);\r
-       qglEnd();\r
-       qglBegin(GL_LINE_LOOP);\r
-       qglVertex3f(mins[0],mins[1],maxs[2]);\r
-       qglVertex3f(maxs[0],mins[1],maxs[2]);\r
-       qglVertex3f(maxs[0],maxs[1],maxs[2]);\r
-       qglVertex3f(mins[0],maxs[1],maxs[2]);\r
-       qglEnd();\r
-\r
-       qglBegin(GL_LINES);\r
-       qglVertex3f(mins[0],mins[1],mins[2]);\r
-       qglVertex3f(mins[0],mins[1],maxs[2]);\r
-       qglVertex3f(mins[0],maxs[1],maxs[2]);\r
-       qglVertex3f(mins[0],maxs[1],mins[2]);\r
-       qglVertex3f(maxs[0],mins[1],mins[2]);\r
-       qglVertex3f(maxs[0],mins[1],maxs[2]);\r
-       qglVertex3f(maxs[0],maxs[1],maxs[2]);\r
-       qglVertex3f(maxs[0],maxs[1],mins[2]);\r
-       qglEnd();\r
-\r
-}\r
-\r
-void splineTest() {\r
-       //g_splineList->load("p:/doom/base/maps/test_base1.camera");\r
-}\r
-\r
-void splineDraw() {\r
-       //g_splineList->addToRenderer();\r
-}\r
-\r
-\r
-//extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end );\r
-\r
-void debugLine(idVec3 &color, float x, float y, float z, float x2, float y2, float z2) {\r
-       idVec3 from(x, y, z);\r
-       idVec3 to(x2, y2, z2);\r
-       //D_DebugLine(color, from, to);\r
-}\r
-\r
-void idSplineList::addToRenderer() {\r
-\r
-       if (controlPoints.Num() == 0) {\r
-               return;\r
-       }\r
-\r
-       idVec3 mins, maxs;\r
-       idVec3 yellow(1.0, 1.0, 0);\r
-       idVec3 white(1.0, 1.0, 1.0);\r
-        int i;\r
-        \r
-       for(i = 0; i < controlPoints.Num(); i++) {\r
-               VectorCopy(*controlPoints[i], mins);\r
-               VectorCopy(mins, maxs);\r
-               mins[0] -= 8;\r
-               mins[1] += 8;\r
-               mins[2] -= 8;\r
-               maxs[0] += 8;\r
-               maxs[1] -= 8;\r
-               maxs[2] += 8;\r
-               debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);\r
-               debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);\r
-               debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);\r
-               debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);\r
-               \r
-               debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);\r
-               debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);\r
-               debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);\r
-               debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);\r
-           \r
-       }\r
-\r
-       int step = 0;\r
-       idVec3 step1;\r
-       for(i = 3; i < controlPoints.Num(); i++) {\r
-               for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {\r
-                       float x = 0;\r
-                       float y = 0;\r
-                       float z = 0;\r
-                       for (int j = 0; j < 4; j++) {\r
-                               x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);\r
-                               y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);\r
-                               z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);\r
-                       }\r
-                       if (step == 0) {\r
-                               step1[0] = x;\r
-                               step1[1] = y;\r
-                               step1[2] = z;\r
-                               step = 1;\r
-                       } else {\r
-                               debugLine( white, step1[0], step1[1], step1[2], x, y, z);\r
-                               step = 0;\r
-                       }\r
-\r
-               }\r
-       }\r
-}\r
-\r
-void idSplineList::buildSpline() {\r
-       //int start = Sys_Milliseconds();\r
-       clearSpline();\r
-       for(int i = 3; i < controlPoints.Num(); i++) {\r
-               for (float tension = 0.0f; tension < 1.001f; tension += granularity) {\r
-                       float x = 0;\r
-                       float y = 0;\r
-                       float z = 0;\r
-                       for (int j = 0; j < 4; j++) {\r
-                               x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);\r
-                               y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);\r
-                               z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);\r
-                       }\r
-                       splinePoints.Append(new idVec3(x, y, z));\r
-               }\r
-       }\r
-       dirty = false;\r
-       //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);\r
-}\r
-\r
-\r
-void idSplineList::draw(bool editMode) {\r
-       int i;\r
-       idVec4 yellow(1, 1, 0, 1);\r
-        \r
-       if (controlPoints.Num() == 0) {\r
-               return;\r
-       }\r
-\r
-       if (dirty) {\r
-               buildSpline();\r
-       }\r
-\r
-\r
-       qglColor3fv(controlColor);\r
-       qglPointSize(5);\r
-       \r
-       qglBegin(GL_POINTS);\r
-       for (i = 0; i < controlPoints.Num(); i++) {\r
-               qglVertex3fv(*controlPoints[i]);\r
-       }\r
-       qglEnd();\r
-       \r
-       if (editMode) {\r
-               for(i = 0; i < controlPoints.Num(); i++) {\r
-                       glBox(activeColor, *controlPoints[i], 4);\r
-               }\r
-       }\r
-\r
-       //Draw the curve\r
-       qglColor3fv(pathColor);\r
-       qglBegin(GL_LINE_STRIP);\r
-       int count = splinePoints.Num();\r
-       for (i = 0; i < count; i++) {\r
-               qglVertex3fv(*splinePoints[i]);\r
-       }\r
-       qglEnd();\r
-\r
-       if (editMode) {\r
-               qglColor3fv(segmentColor);\r
-               qglPointSize(3);\r
-               qglBegin(GL_POINTS);\r
-               for (i = 0; i < count; i++) {\r
-                       qglVertex3fv(*splinePoints[i]);\r
-               }\r
-               qglEnd();\r
-       }\r
-       if (count > 0) {\r
-               //assert(activeSegment >=0 && activeSegment < count);\r
-               if (activeSegment >=0 && activeSegment < count) {\r
-                       glBox(activeColor, *splinePoints[activeSegment], 6);\r
-                       glBox(yellow, *splinePoints[activeSegment], 8);\r
-               }\r
-       }\r
-\r
-}\r
-\r
-float idSplineList::totalDistance() {\r
-\r
-       // FIXME: save dist and return\r
-       // \r
-       if (controlPoints.Num() == 0) {\r
-               return 0.0;\r
-       }\r
-\r
-       if (dirty) {\r
-               buildSpline();\r
-       }\r
-\r
-       float dist = 0.0;\r
-       idVec3 temp;\r
-       int count = splinePoints.Num();\r
-       for(int i = 1; i < count; i++) {\r
-               temp = *splinePoints[i-1];\r
-               temp -= *splinePoints[i];\r
-               dist += temp.Length();\r
-       }\r
-       return dist;\r
-}\r
-\r
-void idSplineList::initPosition(long bt, long totalTime) {\r
-\r
-       if (dirty) {\r
-               buildSpline();\r
-       }\r
-\r
-       if (splinePoints.Num() == 0) {\r
-               return;\r
-       }\r
-\r
-       baseTime = bt;\r
-       time = totalTime;\r
-\r
-       // calc distance to travel ( this will soon be broken into time segments )\r
-       splineTime.Clear();\r
-       splineTime.Append(bt);\r
-       double dist = totalDistance();\r
-       double distSoFar = 0.0;\r
-       idVec3 temp;\r
-       int count = splinePoints.Num();\r
-       //for(int i = 2; i < count - 1; i++) {\r
-       for(int i = 1; i < count; i++) {\r
-               temp = *splinePoints[i-1];\r
-               temp -= *splinePoints[i];\r
-               distSoFar += temp.Length();\r
-               double percent = distSoFar / dist;\r
-               percent *= totalTime;\r
-               splineTime.Append(percent + bt);\r
-       }\r
-       assert(splineTime.Num() == splinePoints.Num());\r
-       activeSegment = 0;\r
-}\r
-\r
-\r
-\r
-float idSplineList::calcSpline(int step, float tension) {\r
-       switch(step) {\r
-               case 0: return (pow(1 - tension, 3)) / 6;\r
-               case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;\r
-               case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;\r
-               case 3: return pow(tension, 3) / 6;\r
-       }\r
-       return 0.0;\r
-}\r
-\r
-\r
-\r
-void idSplineList::updateSelection(const idVec3 &move) {\r
-       if (selected) {\r
-               dirty = true;\r
-               VectorAdd(*selected, move, *selected);\r
-       }\r
-}\r
-\r
-\r
-void idSplineList::setSelectedPoint(idVec3 *p) {\r
-       if (p) {\r
-               p->Snap();\r
-               for(int i = 0; i < controlPoints.Num(); i++) {\r
-                       if (*p == *controlPoints[i]) {\r
-                               selected = controlPoints[i];\r
-                       }\r
-               }\r
-       } else {\r
-               selected = NULL;\r
-       }\r
-}\r
-\r
-const idVec3 *idSplineList::getPosition(long t) {\r
-       static idVec3 interpolatedPos;\r
-       static long lastTime = -1;\r
-\r
-       int count = splineTime.Num();\r
-       if (count == 0) {\r
-               return &zero;\r
-       }\r
-\r
-//     Com_Printf("Time: %d\n", t);\r
-       assert(splineTime.Num() == splinePoints.Num());\r
-\r
-       while (activeSegment < count) {\r
-               if (splineTime[activeSegment] >= t) {\r
-                       if (activeSegment > 0 && activeSegment < count - 1) {\r
-                               double timeHi = splineTime[activeSegment + 1];\r
-                               double timeLo = splineTime[activeSegment - 1];\r
-                               double percent = (timeHi - t) / (timeHi - timeLo); \r
-                               // pick two bounding points\r
-                               idVec3 v1 = *splinePoints[activeSegment-1];\r
-                               idVec3 v2 = *splinePoints[activeSegment+1];\r
-                               v2 *= (1.0 - percent);\r
-                               v1 *= percent;\r
-                               v2 += v1;\r
-                               interpolatedPos = v2;\r
-                               return &interpolatedPos;\r
-                       }\r
-                       return splinePoints[activeSegment];\r
-               } else {\r
-                       activeSegment++;\r
-               }\r
-       }\r
-       return splinePoints[count-1];\r
-}\r
-\r
-void idSplineList::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       //Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !Q_stricmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "granularity") == 0) {\r
-                               granularity = atof(token);\r
-                       } else if (Q_stricmp(key.c_str(), "name") == 0) {\r
-                               name = token;\r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !Q_stricmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               Com_UngetToken();\r
-               // read the control point\r
-               idVec3 point;\r
-               Com_Parse1DMatrix( text, 3, point );\r
-               addPoint(point.x, point.y, point.z);\r
-       } while (1);\r
\r
-       //Com_UngetToken();\r
-       //Com_MatchToken( text, "}" );\r
-       dirty = true;\r
-}\r
-\r
-void idSplineList::write(fileHandle_t file, const char *p) {\r
-       idStr s = va("\t\t%s {\n", p);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       //s = va("\t\tname %s\n", name.c_str());\r
-       //FS_Write(s.c_str(), s.length(), file);\r
-       s = va("\t\t\tgranularity %f\n", granularity);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       int count = controlPoints.Num();\r
-       for (int i = 0; i < count; i++) {\r
-               s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z);\r
-               FS_Write(s.c_str(), s.length(), file);\r
-       }\r
-       s = "\t\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-\r
-void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) {\r
-#if 0\r
-       if (!cameraSpline.validTime()) {\r
-               buildCamera();\r
-       }\r
-       double d = (double)segment / numSegments();\r
-       getCameraInfo(d * totalTime * 1000, origin, direction, fov);\r
-#endif\r
-/*\r
-       if (!cameraSpline.validTime()) {\r
-               buildCamera();\r
-       }\r
-       origin = *cameraSpline.getSegmentPoint(segment);\r
-       \r
-\r
-       idVec3 temp;\r
-\r
-       int numTargets = getTargetSpline()->controlPoints.Num();\r
-       int count = cameraSpline.splineTime.Num();\r
-       if (numTargets == 0) {\r
-               // follow the path\r
-               if (cameraSpline.getActiveSegment() < count - 1) {\r
-                       temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];\r
-               }\r
-       } else if (numTargets == 1) {\r
-               temp = *getTargetSpline()->controlPoints[0];\r
-       } else {\r
-               temp = *getTargetSpline()->getSegmentPoint(segment);\r
-       }\r
-\r
-       temp -= origin;\r
-       temp.Normalize();\r
-       direction = temp;\r
-*/\r
-}\r
-\r
-bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) {\r
-\r
-       char buff[1024];\r
-\r
-       if ((time - startTime) / 1000 > totalTime) {\r
-               return false;\r
-       }\r
-\r
-\r
-       for (int i = 0; i < events.Num(); i++) {\r
-               if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {\r
-                       events[i]->setTriggered(true);\r
-                       if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {\r
-                               setActiveTargetByName(events[i]->getParam());\r
-                               getActiveTarget()->start(startTime + events[i]->getTime());\r
-                               //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {\r
-                               //idEntity *ent = NULL;\r
-                               //ent = level.FindTarget( ent, events[i]->getParam());\r
-                               //if (ent) {\r
-                               //      ent->signal( SIG_TRIGGER );\r
-                               //      ent->ProcessEvent( &EV_Activate, world );\r
-                               //}\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {\r
-                               memset(buff, 0, sizeof(buff));\r
-                               strcpy(buff, events[i]->getParam());\r
-                               const char *param1 = strtok(buff, " \t,\0");\r
-                               const char *param2 = strtok(NULL, " \t,\0");\r
-                               float len = (param2) ? atof(param2) : 0;\r
-                               float newfov = (param1) ? atof(param1) : 90;\r
-                               fov.reset(fov.getFOV(time), newfov, time, len); \r
-                               //*fv = fov = atof(events[i]->getParam());\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_FADEIN) {\r
-                               float time = atof(events[i]->getParam());\r
-                               Cbuf_AddText(va("fade 0 0 0 0 %f", time));\r
-                               Cbuf_Execute();\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_FADEOUT) {\r
-                               float time = atof(events[i]->getParam());\r
-                               Cbuf_AddText(va("fade 0 0 0 255 %f", time));\r
-                               Cbuf_Execute();\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) {\r
-                               memset(buff, 0, sizeof(buff));\r
-                               strcpy(buff, events[i]->getParam());\r
-                               const char *param1 = strtok(buff, " \t,\0");\r
-                               const char *param2 = strtok(NULL, " \t,\0");\r
-\r
-                               if(param2) {\r
-                                       loadCamera(atoi(param1), va("cameras/%s.camera", param2));\r
-                                       startCamera(time);\r
-                               } else {\r
-                                       loadCamera(0, va("cameras/%s.camera", events[i]->getParam()));\r
-                                       startCamera(time);\r
-                               }\r
-                               return true;\r
-                       } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {\r
-                               return false;\r
-                       }\r
-               }\r
-       }\r
-\r
-       origin = *cameraPosition->getPosition(time);\r
-       \r
-       *fv = fov.getFOV(time);\r
-\r
-       idVec3 temp = origin;\r
-\r
-       int numTargets = targetPositions.Num();\r
-       if (numTargets == 0) {\r
-/*\r
-               // follow the path\r
-               if (cameraSpline.getActiveSegment() < count - 1) {\r
-                       temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];\r
-                       if (temp == origin) {\r
-                               int index = cameraSpline.getActiveSegment() + 2;\r
-                               while (temp == origin && index < count - 1) {\r
-                                       temp = *cameraSpline.splinePoints[index++];\r
-                               }\r
-                       }\r
-               }\r
-*/\r
-       } else {\r
-    if( getActiveTarget()->numPoints() > 0 ) {\r
-                 temp = *getActiveTarget()->getPosition(time);\r
-    }\r
-       }\r
-       \r
-       temp -= origin;\r
-       temp.Normalize();\r
-       direction = temp;\r
-\r
-       return true;\r
-}\r
-\r
-bool idCameraDef::waitEvent(int index) {\r
-       //for (int i = 0; i < events.Num(); i++) {\r
-       //      if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {\r
-       //              return true;\r
-       //      }\r
-    //}\r
-       return false;\r
-}\r
-\r
-\r
-#define NUM_CCELERATION_SEGS 10\r
-#define CELL_AMT 5\r
-\r
-void idCameraDef::buildCamera() {\r
-       int i;\r
-       int lastSwitch = 0;\r
-       idList<float> waits;\r
-       idList<int> targets;\r
-\r
-       totalTime = baseTime;\r
-       cameraPosition->setTime((long)totalTime * 1000);\r
-       // we have a base time layout for the path and the target path\r
-       // now we need to layer on any wait or speed changes\r
-       for (i = 0; i < events.Num(); i++) {\r
-               idCameraEvent *ev = events[i];\r
-               events[i]->setTriggered(false);\r
-               switch (events[i]->getType()) {\r
-                       case idCameraEvent::EVENT_TARGET : {\r
-                               targets.Append(i);\r
-                               break;\r
-                       }\r
-                       case idCameraEvent::EVENT_FEATHER : {\r
-                               long startTime = 0;\r
-                               float speed = 0;\r
-                               long loopTime = 10;\r
-                               float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime);\r
-                               while (startTime <= 1000) {\r
-                                       cameraPosition->addVelocity(startTime, loopTime, speed);\r
-                                       speed += stepGoal;\r
-                                       if (speed > cameraPosition->getBaseVelocity()) {\r
-                                               speed = cameraPosition->getBaseVelocity();\r
-                                       }\r
-                                       startTime += loopTime;\r
-                               }\r
-\r
-                               startTime = (long)(totalTime * 1000 - 1000);\r
-                               long endTime = startTime + 1000;\r
-                               speed = cameraPosition->getBaseVelocity();\r
-                               while (startTime < endTime) {\r
-                                       speed -= stepGoal;\r
-                                       if (speed < 0) {\r
-                                               speed = 0;\r
-                                       }\r
-                                       cameraPosition->addVelocity(startTime, loopTime, speed);\r
-                                       startTime += loopTime;\r
-                               }\r
-                               break;\r
-\r
-                       }\r
-                       case idCameraEvent::EVENT_WAIT : {\r
-                               waits.Append(atof(events[i]->getParam()));\r
-\r
-                               //FIXME: this is quite hacky for Wolf E3, accel and decel needs\r
-                               // do be parameter based etc.. \r
-                               long startTime = events[i]->getTime() - 1000;\r
-                               if (startTime < 0) {\r
-                                       startTime = 0;\r
-                               }\r
-                               float speed = cameraPosition->getBaseVelocity();\r
-                               long loopTime = 10;\r
-                               float steps = speed / ((events[i]->getTime() - startTime) / loopTime);\r
-                               while (startTime <= events[i]->getTime() - loopTime) {\r
-                                       cameraPosition->addVelocity(startTime, loopTime, speed);\r
-                                       speed -= steps;\r
-                                       startTime += loopTime;\r
-                               }\r
-                               cameraPosition->addVelocity(events[i]->getTime(), (long)atof(events[i]->getParam()) * 1000, 0);\r
-\r
-                               startTime = (long)(events[i]->getTime() + atof(events[i]->getParam()) * 1000);\r
-                               long endTime = startTime + 1000;\r
-                               speed = 0;\r
-                               while (startTime <= endTime) {\r
-                                       cameraPosition->addVelocity(startTime, loopTime, speed);\r
-                                       speed += steps;\r
-                                       startTime += loopTime;\r
-                               }\r
-                               break;\r
-                       }\r
-                       case idCameraEvent::EVENT_TARGETWAIT : {\r
-                               //targetWaits.Append(i);\r
-                               break;\r
-                       }\r
-                       case idCameraEvent::EVENT_SPEED : {\r
-/*\r
-                               // take the average delay between up to the next five segments\r
-                               float adjust = atof(events[i]->getParam());\r
-                               int index = events[i]->getSegment();\r
-                               total = 0;\r
-                               count = 0;\r
-\r
-                               // get total amount of time over the remainder of the segment\r
-                               for (j = index; j < cameraSpline.numSegments() - 1; j++) {\r
-                                       total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);\r
-                                       count++;\r
-                               }\r
-\r
-                               // multiply that by the adjustment\r
-                               double newTotal = total * adjust;\r
-                               // what is the difference.. \r
-                               newTotal -= total;\r
-                               totalTime += newTotal / 1000;\r
-\r
-                               // per segment difference\r
-                               newTotal /= count;\r
-                               int additive = newTotal;\r
-\r
-                               // now propogate that difference out to each segment\r
-                               for (j = index; j < cameraSpline.numSegments(); j++) {\r
-                                       cameraSpline.addSegmentTime(j, additive);\r
-                                       additive += newTotal;\r
-                               }\r
-                               break;\r
-*/\r
-                       }\r
-               }\r
-       }\r
-\r
-\r
-       for (i = 0; i < waits.Num(); i++) {\r
-               totalTime += waits[i];\r
-       }\r
-\r
-       // on a new target switch, we need to take time to this point ( since last target switch ) \r
-       // and allocate it across the active target, then reset time to this point\r
-       long timeSoFar = 0;\r
-       long total = (long)(totalTime * 1000);\r
-       for (i = 0; i < targets.Num(); i++) {\r
-               long t;\r
-               if (i < targets.Num() - 1) {\r
-                       t = events[targets[i+1]]->getTime();\r
-               } else {\r
-                       t = total - timeSoFar;\r
-               }\r
-               // t is how much time to use for this target\r
-               setActiveTargetByName(events[targets[i]]->getParam());\r
-               getActiveTarget()->setTime(t);\r
-               timeSoFar += t;\r
-       }\r
-\r
-       \r
-}\r
-\r
-void idCameraDef::startCamera(long t) {\r
-       cameraPosition->clearVelocities();\r
-       cameraPosition->start(t);\r
-       buildCamera();\r
-       fov.reset(90, 90, t, 0);\r
-       //for (int i = 0; i < targetPositions.Num(); i++) {\r
-       //      targetPositions[i]->\r
-       //}\r
-       startTime = t;\r
-       cameraRunning = true;\r
-}\r
-\r
-\r
-void idCameraDef::parse(const char *(*text)  ) {\r
-\r
-       const char      *token;\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !Q_stricmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               if (Q_stricmp(token, "time") == 0) {\r
-                       baseTime = Com_ParseFloat(text);\r
-               }\r
-               else if (Q_stricmp(token, "camera_fixed") == 0) {\r
-                       cameraPosition = new idFixedPosition();\r
-                       cameraPosition->parse(text);\r
-               }\r
-               else if (Q_stricmp(token, "camera_interpolated") == 0) {\r
-                       cameraPosition = new idInterpolatedPosition();\r
-                       cameraPosition->parse(text);\r
-               }\r
-               else if (Q_stricmp(token, "camera_spline") == 0) {\r
-                       cameraPosition = new idSplinePosition();\r
-                       cameraPosition->parse(text);\r
-               }\r
-               else if (Q_stricmp(token, "target_fixed") == 0) {\r
-                       idFixedPosition *pos = new idFixedPosition();\r
-                       pos->parse(text);\r
-                       targetPositions.Append(pos);\r
-               }\r
-               else if (Q_stricmp(token, "target_interpolated") == 0) {\r
-                       idInterpolatedPosition *pos = new idInterpolatedPosition();\r
-                       pos->parse(text);\r
-                       targetPositions.Append(pos);\r
-               }\r
-               else if (Q_stricmp(token, "target_spline") == 0) {\r
-                       idSplinePosition *pos = new idSplinePosition();\r
-                       pos->parse(text);\r
-                       targetPositions.Append(pos);\r
-               }\r
-               else if (Q_stricmp(token, "fov") == 0) {\r
-                       fov.parse(text);\r
-               }\r
-               else if (Q_stricmp(token, "event") == 0) {\r
-                       idCameraEvent *event = new idCameraEvent();\r
-                       event->parse(text);\r
-                       addEvent(event);\r
-               }\r
-\r
-\r
-       } while (1);\r
-\r
-       if ( !cameraPosition ) {\r
-               Com_Printf( "no camera position specified\n" );\r
-               // prevent a crash later on\r
-               cameraPosition = new idFixedPosition();\r
-       }\r
-\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-\r
-}\r
-\r
-bool idCameraDef::load(const char *filename) {\r
-       char *buf;\r
-       const char *buf_p;\r
-       int length = FS_ReadFile( filename, (void **)&buf );\r
-       if ( !buf ) {\r
-               return false;\r
-       }\r
-\r
-       clear();\r
-       Com_BeginParseSession( filename );\r
-       buf_p = buf;\r
-       parse(&buf_p);\r
-       Com_EndParseSession();\r
-       FS_FreeFile( buf );\r
-\r
-       return true;\r
-}\r
-\r
-void idCameraDef::save(const char *filename) {\r
-       fileHandle_t file = FS_FOpenFileWrite(filename);\r
-       if (file) {\r
-               int i;\r
-               idStr s = "cameraPathDef { \n"; \r
-               FS_Write(s.c_str(), s.length(), file);\r
-               s = va("\ttime %f\n", baseTime);\r
-               FS_Write(s.c_str(), s.length(), file);\r
-\r
-               cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr()));\r
-\r
-               for (i = 0; i < numTargets(); i++) {\r
-                       targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr()));\r
-               }\r
-\r
-               for (i = 0; i < events.Num(); i++) {\r
-                       events[i]->write(file, "event");\r
-               }\r
-\r
-               fov.write(file, "fov");\r
-\r
-               s = "}\n";\r
-               FS_Write(s.c_str(), s.length(), file);\r
-       }\r
-       FS_FCloseFile(file);\r
-}\r
-\r
-int idCameraDef::sortEvents(const void *p1, const void *p2) {\r
-       idCameraEvent *ev1 = (idCameraEvent*)(p1);\r
-       idCameraEvent *ev2 = (idCameraEvent*)(p2);\r
-\r
-       if (ev1->getTime() > ev2->getTime()) {\r
-               return -1;\r
-       }\r
-       if (ev1->getTime() < ev2->getTime()) {\r
-               return 1;\r
-       }\r
-       return 0; \r
-}\r
-\r
-void idCameraDef::addEvent(idCameraEvent *event) {\r
-       events.Append(event);\r
-       //events.Sort(&sortEvents);\r
-\r
-}\r
-void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {\r
-       addEvent(new idCameraEvent(t, param, time));\r
-       buildCamera();\r
-}\r
-\r
-void idCameraDef::removeEvent(int index) {\r
-       events.RemoveIndex(index);\r
-       buildCamera();\r
-}\r
-\r
-\r
-const char *idCameraEvent::eventStr[] = {\r
-       "NA",\r
-       "WAIT",\r
-       "TARGETWAIT",\r
-       "SPEED",\r
-       "TARGET",\r
-       "SNAPTARGET",\r
-       "FOV",\r
-       "CMD",\r
-       "TRIGGER",\r
-       "STOP",\r
-       "CAMERA",\r
-       "FADEOUT",\r
-       "FADEIN",\r
-       "FEATHER"\r
-};\r
-\r
-void idCameraEvent::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               // here we may have to jump over brush epairs ( only used in editor )\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "type") == 0) {\r
-                               type = static_cast<idCameraEvent::eventType>(atoi(token));\r
-                       } else if (Q_stricmp(key.c_str(), "param") == 0) {\r
-                               paramStr = token;\r
-                       } else if (Q_stricmp(key.c_str(), "time") == 0) {\r
-                               time = atoi(token);\r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-       } while (1);\r
\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-}\r
-\r
-void idCameraEvent::write(fileHandle_t file, const char *name) {\r
-       idStr s = va("\t%s {\n", name);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = va("\t\ttype %d\n", static_cast<int>(type));\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = va("\t\tparam \"%s\"\n", paramStr.c_str());\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = va("\t\ttime %d\n", time);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = "\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-\r
-const char *idCameraPosition::positionStr[] = {\r
-       "Fixed",\r
-       "Interpolated",\r
-       "Spline",\r
-};\r
-\r
-\r
-\r
-const idVec3 *idInterpolatedPosition::getPosition(long t) { \r
-       static idVec3 interpolatedPos;\r
-\r
-       float velocity = getVelocity(t);\r
-       float timePassed = t - lastTime;\r
-       lastTime = t;\r
-\r
-       // convert to seconds   \r
-       timePassed /= 1000;\r
-\r
-       float distToTravel = timePassed * velocity;\r
-\r
-       idVec3 temp = startPos;\r
-       temp -= endPos;\r
-       float distance = temp.Length();\r
-\r
-       distSoFar += distToTravel;\r
-       float percent = (float)(distSoFar) / distance;\r
-\r
-       if (percent > 1.0) {\r
-               percent = 1.0;\r
-       } else if (percent < 0.0) {\r
-               percent = 0.0;\r
-       }\r
-\r
-       // the following line does a straigt calc on percentage of time\r
-       // float percent = (float)(startTime + time - t) / time;\r
-\r
-       idVec3 v1 = startPos;\r
-       idVec3 v2 = endPos;\r
-       v1 *= (1.0 - percent);\r
-       v2 *= percent;\r
-       v1 += v2;\r
-       interpolatedPos = v1;\r
-       return &interpolatedPos;\r
-}\r
-\r
-\r
-void idCameraFOV::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               // here we may have to jump over brush epairs ( only used in editor )\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "fov") == 0) {\r
-                               fov = atof(token);\r
-                       } else if (Q_stricmp(key.c_str(), "startFOV") == 0) {\r
-                               startFOV = atof(token);\r
-                       } else if (Q_stricmp(key.c_str(), "endFOV") == 0) {\r
-                               endFOV = atof(token);\r
-                       } else if (Q_stricmp(key.c_str(), "time") == 0) {\r
-                               time = atoi(token);\r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-       } while (1);\r
\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-}\r
-\r
-bool idCameraPosition::parseToken(const char *key, const char *(*text)) {\r
-       const char *token = Com_Parse(text);\r
-       if (Q_stricmp(key, "time") == 0) {\r
-               time = atol(token);\r
-               return true;\r
-       } else if (Q_stricmp(key, "type") == 0) {\r
-               type = static_cast<idCameraPosition::positionType>(atoi(token));\r
-               return true;\r
-       } else if (Q_stricmp(key, "velocity") == 0) {\r
-               long t = atol(token);\r
-               token = Com_Parse(text);\r
-               long d = atol(token);\r
-               token = Com_Parse(text);\r
-               float s = atof(token);\r
-               addVelocity(t, d, s);\r
-               return true;\r
-       } else if (Q_stricmp(key, "baseVelocity") == 0) {\r
-               baseVelocity = atof(token);\r
-               return true;\r
-       } else if (Q_stricmp(key, "name") == 0) {\r
-               name = token;\r
-               return true;\r
-       } else if (Q_stricmp(key, "time") == 0) {\r
-               time = atoi(token);\r
-               return true;\r
-       }\r
-       Com_UngetToken();\r
-       return false;\r
-}\r
-\r
-\r
-\r
-void idFixedPosition::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               // here we may have to jump over brush epairs ( only used in editor )\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       \r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "pos") == 0) {\r
-                               Com_UngetToken();\r
-                               Com_Parse1DMatrix( text, 3, pos );\r
-                       } else {\r
-                               Com_UngetToken();\r
-                               idCameraPosition::parseToken(key.c_str(), text);        \r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-       } while (1);\r
\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-}\r
-\r
-void idInterpolatedPosition::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               // here we may have to jump over brush epairs ( only used in editor )\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       \r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "startPos") == 0) {\r
-                               Com_UngetToken();\r
-                               Com_Parse1DMatrix( text, 3, startPos );\r
-                       } else if (Q_stricmp(key.c_str(), "endPos") == 0) {\r
-                               Com_UngetToken();\r
-                               Com_Parse1DMatrix( text, 3, endPos );\r
-                       } else {\r
-                               Com_UngetToken();\r
-                               idCameraPosition::parseToken(key.c_str(), text);        \r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-       } while (1);\r
\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-}\r
-\r
-\r
-void idSplinePosition::parse(const char *(*text)  ) {\r
-       const char *token;\r
-       Com_MatchToken( text, "{" );\r
-       do {\r
-               token = Com_Parse( text );\r
-       \r
-               if ( !token[0] ) {\r
-                       break;\r
-               }\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-               // here we may have to jump over brush epairs ( only used in editor )\r
-               do {\r
-                       // if token is not a brace, it is a key for a key/value pair\r
-                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {\r
-                               break;\r
-                       }\r
-\r
-                       Com_UngetToken();\r
-                       idStr key = Com_ParseOnLine(text);\r
-                       \r
-                       const char *token = Com_Parse(text);\r
-                       if (Q_stricmp(key.c_str(), "target") == 0) {\r
-                               target.parse(text);\r
-                       } else {\r
-                               Com_UngetToken();\r
-                               idCameraPosition::parseToken(key.c_str(), text);        \r
-                       }\r
-                       token = Com_Parse(text);\r
-\r
-               } while (1);\r
-\r
-               if ( !strcmp (token, "}") ) {\r
-                       break;\r
-               }\r
-\r
-       } while (1);\r
\r
-       Com_UngetToken();\r
-       Com_MatchToken( text, "}" );\r
-}\r
-\r
-\r
-\r
-void idCameraFOV::write(fileHandle_t file, const char *p) {\r
-       idStr s = va("\t%s {\n", p);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       \r
-       s = va("\t\tfov %f\n", fov);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\tstartFOV %f\n", startFOV);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\tendFOV %f\n", endFOV);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\ttime %i\n", time);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = "\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-\r
-void idCameraPosition::write(fileHandle_t file, const char *p) {\r
-       \r
-       idStr s = va("\t\ttime %i\n", time);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\ttype %i\n", static_cast<int>(type));\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\tname %s\n", name.c_str());\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       s = va("\t\tbaseVelocity %f\n", baseVelocity);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-\r
-       for (int i = 0; i < velocities.Num(); i++) {\r
-               s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed);\r
-               FS_Write(s.c_str(), s.length(), file);\r
-       }\r
-\r
-}\r
-\r
-void idFixedPosition::write(fileHandle_t file, const char *p) {\r
-       idStr s = va("\t%s {\n", p);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       idCameraPosition::write(file, p);\r
-       s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = "\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-void idInterpolatedPosition::write(fileHandle_t file, const char *p) {\r
-       idStr s = va("\t%s {\n", p);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       idCameraPosition::write(file, p);\r
-       s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       s = "\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-void idSplinePosition::write(fileHandle_t file, const char *p) {\r
-       idStr s = va("\t%s {\n", p);\r
-       FS_Write(s.c_str(), s.length(), file);\r
-       idCameraPosition::write(file, p);\r
-       target.write(file, "target");\r
-       s = "\t}\n";\r
-       FS_Write(s.c_str(), s.length(), file);\r
-}\r
-\r
-void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {\r
-       const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;\r
-       idCameraPosition *pos = newFromType(type);\r
-       if (pos) {\r
-               pos->setName(name);\r
-               targetPositions.Append(pos);\r
-               activeTarget = numTargets()-1;\r
-               if (activeTarget == 0) {\r
-                       // first one\r
-                       addEvent(idCameraEvent::EVENT_TARGET, name, 0);\r
-               }\r
-       }\r
-}\r
-\r
-const idVec3 *idSplinePosition::getPosition(long t) {\r
-       static idVec3 interpolatedPos;\r
-\r
-       float velocity = getVelocity(t);\r
-       float timePassed = t - lastTime;\r
-       lastTime = t;\r
-\r
-       // convert to seconds   \r
-       timePassed /= 1000;\r
-\r
-       float distToTravel = timePassed * velocity;\r
-\r
-       distSoFar += distToTravel;\r
-       double tempDistance = target.totalDistance();\r
-\r
-       double percent = (double)(distSoFar) / tempDistance;\r
-\r
-       double targetDistance = percent * tempDistance;\r
-       tempDistance = 0;\r
-\r
-       double lastDistance1,lastDistance2;\r
-       lastDistance1 = lastDistance2 = 0;\r
-       idVec3 temp;\r
-       int count = target.numSegments();\r
-       int i;\r
-       for(i = 1; i < count; i++) {\r
-               temp = *target.getSegmentPoint(i-1);\r
-               temp -= *target.getSegmentPoint(i);\r
-               tempDistance += temp.Length();\r
-               if (i & 1) {\r
-                       lastDistance1 = tempDistance;\r
-               } else {\r
-                       lastDistance2 = tempDistance;\r
-               }\r
-               if (tempDistance >= targetDistance) {\r
-                       break;\r
-               }\r
-       }\r
-\r
-       if ( i >= count - 1) {\r
-               interpolatedPos = *target.getSegmentPoint(i-1);\r
-       } else {\r
-#if 0\r
-               double timeHi = target.getSegmentTime(i + 1);\r
-               double timeLo = target.getSegmentTime(i - 1);\r
-               double percent = (timeHi - t) / (timeHi - timeLo); \r
-               idVec3 v1 = *target.getSegmentPoint(i - 1);\r
-               idVec3 v2 = *target.getSegmentPoint(i + 1);\r
-               v2 *= (1.0 - percent);\r
-               v1 *= percent;\r
-               v2 += v1;\r
-               interpolatedPos = v2;\r
-#else\r
-               if (lastDistance1 > lastDistance2) {\r
-                       double d = lastDistance2;\r
-                       lastDistance2 = lastDistance1;\r
-                       lastDistance1 = d;\r
-               }\r
-\r
-               idVec3 v1 = *target.getSegmentPoint(i - 1);\r
-               idVec3 v2 = *target.getSegmentPoint(i);\r
-               double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1); \r
-               v2 *= (1.0 - percent);\r
-               v1 *= percent;\r
-               v2 += v1;\r
-               interpolatedPos = v2;\r
-#endif\r
-       }\r
-       return &interpolatedPos;\r
-\r
-}\r
-\r
-\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+*/
+
+#include "q_shared.h"
+#include "splines.h"
+
+extern "C" {
+int FS_Write( const void *buffer, int len, fileHandle_t h );
+int FS_ReadFile( const char *qpath, void **buffer );
+void FS_FreeFile( void *buffer );
+fileHandle_t FS_FOpenFileWrite( const char *filename );
+void FS_FCloseFile( fileHandle_t f );
+void Cbuf_AddText( const char *text );
+void Cbuf_Execute (void);
+}
+
+float Q_fabs( float f ) {
+       int tmp = * ( int * ) &f;
+       tmp &= 0x7FFFFFFF;
+       return * ( float * ) &tmp;
+}
+
+// (SA) making a list of cameras so I can use
+//             the splines as targets for other things.
+//             Certainly better ways to do this, but this lets
+//             me get underway quickly with ents that need spline
+//             targets.
+#define MAX_CAMERAS 64
+
+idCameraDef camera[MAX_CAMERAS];
+
+extern "C" {
+qboolean loadCamera(int camNum, const char *name) {
+       if(camNum < 0 || camNum >= MAX_CAMERAS )
+               return qfalse;
+       camera[camNum].clear();
+       return (qboolean)camera[camNum].load(name);
+}
+
+qboolean getCameraInfo(int camNum, int time, float *origin, float *angles, float *fov) {
+       idVec3 dir, org;
+       if(camNum < 0 || camNum >= MAX_CAMERAS )
+               return qfalse;
+       org[0] = origin[0];
+       org[1] = origin[1];
+       org[2] = origin[2];
+       if (camera[camNum].getCameraInfo(time, org, dir, fov)) {
+               origin[0] = org[0];
+               origin[1] = org[1];
+               origin[2] = org[2];
+               angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
+               angles[0] = asin (dir[2])*180/3.14159;
+               return qtrue;
+       }
+       return qfalse;
+}
+
+void startCamera(int camNum, int time) {
+       if(camNum < 0 || camNum >= MAX_CAMERAS )
+               return;
+       camera[camNum].startCamera(time);
+}
+
+}
+
+
+//#include "../shared/windings.h"
+//#include "../qcommon/qcommon.h"
+//#include "../sys/sys_public.h"
+//#include "../game/game_entity.h"
+
+idCameraDef splineList;
+idCameraDef *g_splineList = &splineList;
+
+idVec3 idSplineList::zero(0,0,0);
+
+void glLabeledPoint(idVec3 &color, idVec3 &point, float size, const char *label) {
+       qglColor3fv(color);
+       qglPointSize(size);
+       qglBegin(GL_POINTS);
+       qglVertex3fv(point);
+       qglEnd();
+       idVec3 v = point;
+       v.x += 1;
+       v.y += 1;
+       v.z += 1;
+       qglRasterPos3fv (v);
+       qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
+}
+
+
+void glBox(idVec3 &color, idVec3 &point, float size) {
+       idVec3 mins(point);
+       idVec3 maxs(point);
+       mins[0] -= size;
+       mins[1] += size;
+       mins[2] -= size;
+       maxs[0] += size;
+       maxs[1] -= size;
+       maxs[2] += size;
+       qglColor3fv(color);
+       qglBegin(GL_LINE_LOOP);
+       qglVertex3f(mins[0],mins[1],mins[2]);
+       qglVertex3f(maxs[0],mins[1],mins[2]);
+       qglVertex3f(maxs[0],maxs[1],mins[2]);
+       qglVertex3f(mins[0],maxs[1],mins[2]);
+       qglEnd();
+       qglBegin(GL_LINE_LOOP);
+       qglVertex3f(mins[0],mins[1],maxs[2]);
+       qglVertex3f(maxs[0],mins[1],maxs[2]);
+       qglVertex3f(maxs[0],maxs[1],maxs[2]);
+       qglVertex3f(mins[0],maxs[1],maxs[2]);
+       qglEnd();
+
+       qglBegin(GL_LINES);
+       qglVertex3f(mins[0],mins[1],mins[2]);
+       qglVertex3f(mins[0],mins[1],maxs[2]);
+       qglVertex3f(mins[0],maxs[1],maxs[2]);
+       qglVertex3f(mins[0],maxs[1],mins[2]);
+       qglVertex3f(maxs[0],mins[1],mins[2]);
+       qglVertex3f(maxs[0],mins[1],maxs[2]);
+       qglVertex3f(maxs[0],maxs[1],maxs[2]);
+       qglVertex3f(maxs[0],maxs[1],mins[2]);
+       qglEnd();
+
+}
+
+void splineTest() {
+       //g_splineList->load("p:/doom/base/maps/test_base1.camera");
+}
+
+void splineDraw() {
+       //g_splineList->addToRenderer();
+}
+
+
+//extern void D_DebugLine( const idVec3 &color, const idVec3 &start, const idVec3 &end );
+
+void debugLine(idVec3 &color, float x, float y, float z, float x2, float y2, float z2) {
+       idVec3 from(x, y, z);
+       idVec3 to(x2, y2, z2);
+       //D_DebugLine(color, from, to);
+}
+
+void idSplineList::addToRenderer() {
+
+       if (controlPoints.Num() == 0) {
+               return;
+       }
+
+       idVec3 mins, maxs;
+       idVec3 yellow(1.0, 1.0, 0);
+       idVec3 white(1.0, 1.0, 1.0);
+        int i;
+        
+       for(i = 0; i < controlPoints.Num(); i++) {
+               VectorCopy(*controlPoints[i], mins);
+               VectorCopy(mins, maxs);
+               mins[0] -= 8;
+               mins[1] += 8;
+               mins[2] -= 8;
+               maxs[0] += 8;
+               maxs[1] -= 8;
+               maxs[2] += 8;
+               debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
+               debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
+               debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
+               debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
+               
+               debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
+               debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
+               debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
+               debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
+           
+       }
+
+       int step = 0;
+       idVec3 step1;
+       for(i = 3; i < controlPoints.Num(); i++) {
+               for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
+                       float x = 0;
+                       float y = 0;
+                       float z = 0;
+                       for (int j = 0; j < 4; j++) {
+                               x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
+                               y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
+                               z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
+                       }
+                       if (step == 0) {
+                               step1[0] = x;
+                               step1[1] = y;
+                               step1[2] = z;
+                               step = 1;
+                       } else {
+                               debugLine( white, step1[0], step1[1], step1[2], x, y, z);
+                               step = 0;
+                       }
+
+               }
+       }
+}
+
+void idSplineList::buildSpline() {
+       //int start = Sys_Milliseconds();
+       clearSpline();
+       for(int i = 3; i < controlPoints.Num(); i++) {
+               for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
+                       float x = 0;
+                       float y = 0;
+                       float z = 0;
+                       for (int j = 0; j < 4; j++) {
+                               x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
+                               y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
+                               z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
+                       }
+                       splinePoints.Append(new idVec3(x, y, z));
+               }
+       }
+       dirty = false;
+       //Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
+}
+
+
+void idSplineList::draw(bool editMode) {
+       int i;
+       idVec4 yellow(1, 1, 0, 1);
+        
+       if (controlPoints.Num() == 0) {
+               return;
+       }
+
+       if (dirty) {
+               buildSpline();
+       }
+
+
+       qglColor3fv(controlColor);
+       qglPointSize(5);
+       
+       qglBegin(GL_POINTS);
+       for (i = 0; i < controlPoints.Num(); i++) {
+               qglVertex3fv(*controlPoints[i]);
+       }
+       qglEnd();
+       
+       if (editMode) {
+               for(i = 0; i < controlPoints.Num(); i++) {
+                       glBox(activeColor, *controlPoints[i], 4);
+               }
+       }
+
+       //Draw the curve
+       qglColor3fv(pathColor);
+       qglBegin(GL_LINE_STRIP);
+       int count = splinePoints.Num();
+       for (i = 0; i < count; i++) {
+               qglVertex3fv(*splinePoints[i]);
+       }
+       qglEnd();
+
+       if (editMode) {
+               qglColor3fv(segmentColor);
+               qglPointSize(3);
+               qglBegin(GL_POINTS);
+               for (i = 0; i < count; i++) {
+                       qglVertex3fv(*splinePoints[i]);
+               }
+               qglEnd();
+       }
+       if (count > 0) {
+               //assert(activeSegment >=0 && activeSegment < count);
+               if (activeSegment >=0 && activeSegment < count) {
+                       glBox(activeColor, *splinePoints[activeSegment], 6);
+                       glBox(yellow, *splinePoints[activeSegment], 8);
+               }
+       }
+
+}
+
+float idSplineList::totalDistance() {
+
+       // FIXME: save dist and return
+       // 
+       if (controlPoints.Num() == 0) {
+               return 0.0;
+       }
+
+       if (dirty) {
+               buildSpline();
+       }
+
+       float dist = 0.0;
+       idVec3 temp;
+       int count = splinePoints.Num();
+       for(int i = 1; i < count; i++) {
+               temp = *splinePoints[i-1];
+               temp -= *splinePoints[i];
+               dist += temp.Length();
+       }
+       return dist;
+}
+
+void idSplineList::initPosition(long bt, long totalTime) {
+
+       if (dirty) {
+               buildSpline();
+       }
+
+       if (splinePoints.Num() == 0) {
+               return;
+       }
+
+       baseTime = bt;
+       time = totalTime;
+
+       // calc distance to travel ( this will soon be broken into time segments )
+       splineTime.Clear();
+       splineTime.Append(bt);
+       double dist = totalDistance();
+       double distSoFar = 0.0;
+       idVec3 temp;
+       int count = splinePoints.Num();
+       //for(int i = 2; i < count - 1; i++) {
+       for(int i = 1; i < count; i++) {
+               temp = *splinePoints[i-1];
+               temp -= *splinePoints[i];
+               distSoFar += temp.Length();
+               double percent = distSoFar / dist;
+               percent *= totalTime;
+               splineTime.Append(percent + bt);
+       }
+       assert(splineTime.Num() == splinePoints.Num());
+       activeSegment = 0;
+}
+
+
+
+float idSplineList::calcSpline(int step, float tension) {
+       switch(step) {
+               case 0: return (pow(1 - tension, 3)) / 6;
+               case 1: return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
+               case 2: return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
+               case 3: return pow(tension, 3) / 6;
+       }
+       return 0.0;
+}
+
+
+
+void idSplineList::updateSelection(const idVec3 &move) {
+       if (selected) {
+               dirty = true;
+               VectorAdd(*selected, move, *selected);
+       }
+}
+
+
+void idSplineList::setSelectedPoint(idVec3 *p) {
+       if (p) {
+               p->Snap();
+               for(int i = 0; i < controlPoints.Num(); i++) {
+                       if (*p == *controlPoints[i]) {
+                               selected = controlPoints[i];
+                       }
+               }
+       } else {
+               selected = NULL;
+       }
+}
+
+const idVec3 *idSplineList::getPosition(long t) {
+       static idVec3 interpolatedPos;
+       static long lastTime = -1;
+
+       int count = splineTime.Num();
+       if (count == 0) {
+               return &zero;
+       }
+
+//     Com_Printf("Time: %d\n", t);
+       assert(splineTime.Num() == splinePoints.Num());
+
+       while (activeSegment < count) {
+               if (splineTime[activeSegment] >= t) {
+                       if (activeSegment > 0 && activeSegment < count - 1) {
+                               double timeHi = splineTime[activeSegment + 1];
+                               double timeLo = splineTime[activeSegment - 1];
+                               double percent = (timeHi - t) / (timeHi - timeLo); 
+                               // pick two bounding points
+                               idVec3 v1 = *splinePoints[activeSegment-1];
+                               idVec3 v2 = *splinePoints[activeSegment+1];
+                               v2 *= (1.0 - percent);
+                               v1 *= percent;
+                               v2 += v1;
+                               interpolatedPos = v2;
+                               return &interpolatedPos;
+                       }
+                       return splinePoints[activeSegment];
+               } else {
+                       activeSegment++;
+               }
+       }
+       return splinePoints[count-1];
+}
+
+void idSplineList::parse(const char *(*text)  ) {
+       const char *token;
+       //Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !Q_stricmp (token, "}") ) {
+                       break;
+               }
+
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "granularity") == 0) {
+                               granularity = atof(token);
+                       } else if (Q_stricmp(key.c_str(), "name") == 0) {
+                               name = token;
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !Q_stricmp (token, "}") ) {
+                       break;
+               }
+
+               Com_UngetToken();
+               // read the control point
+               idVec3 point;
+               Com_Parse1DMatrix( text, 3, point );
+               addPoint(point.x, point.y, point.z);
+       } while (1);
+       //Com_UngetToken();
+       //Com_MatchToken( text, "}" );
+       dirty = true;
+}
+
+void idSplineList::write(fileHandle_t file, const char *p) {
+       idStr s = va("\t\t%s {\n", p);
+       FS_Write(s.c_str(), s.length(), file);
+       //s = va("\t\tname %s\n", name.c_str());
+       //FS_Write(s.c_str(), s.length(), file);
+       s = va("\t\t\tgranularity %f\n", granularity);
+       FS_Write(s.c_str(), s.length(), file);
+       int count = controlPoints.Num();
+       for (int i = 0; i < count; i++) {
+               s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z);
+               FS_Write(s.c_str(), s.length(), file);
+       }
+       s = "\t\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+
+void idCameraDef::getActiveSegmentInfo(int segment, idVec3 &origin, idVec3 &direction, float *fov) {
+#if 0
+       if (!cameraSpline.validTime()) {
+               buildCamera();
+       }
+       double d = (double)segment / numSegments();
+       getCameraInfo(d * totalTime * 1000, origin, direction, fov);
+#endif
+/*
+       if (!cameraSpline.validTime()) {
+               buildCamera();
+       }
+       origin = *cameraSpline.getSegmentPoint(segment);
+       
+
+       idVec3 temp;
+
+       int numTargets = getTargetSpline()->controlPoints.Num();
+       int count = cameraSpline.splineTime.Num();
+       if (numTargets == 0) {
+               // follow the path
+               if (cameraSpline.getActiveSegment() < count - 1) {
+                       temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
+               }
+       } else if (numTargets == 1) {
+               temp = *getTargetSpline()->controlPoints[0];
+       } else {
+               temp = *getTargetSpline()->getSegmentPoint(segment);
+       }
+
+       temp -= origin;
+       temp.Normalize();
+       direction = temp;
+*/
+}
+
+bool idCameraDef::getCameraInfo(long time, idVec3 &origin, idVec3 &direction, float *fv) {
+
+       char buff[1024];
+
+       if ((time - startTime) / 1000 > totalTime) {
+               return false;
+       }
+
+
+       for (int i = 0; i < events.Num(); i++) {
+               if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {
+                       events[i]->setTriggered(true);
+                       if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {
+                               setActiveTargetByName(events[i]->getParam());
+                               getActiveTarget()->start(startTime + events[i]->getTime());
+                               //Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {
+                               //idEntity *ent = NULL;
+                               //ent = level.FindTarget( ent, events[i]->getParam());
+                               //if (ent) {
+                               //      ent->signal( SIG_TRIGGER );
+                               //      ent->ProcessEvent( &EV_Activate, world );
+                               //}
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {
+                               memset(buff, 0, sizeof(buff));
+                               strcpy(buff, events[i]->getParam());
+                               const char *param1 = strtok(buff, " \t,\0");
+                               const char *param2 = strtok(NULL, " \t,\0");
+                               float len = (param2) ? atof(param2) : 0;
+                               float newfov = (param1) ? atof(param1) : 90;
+                               fov.reset(fov.getFOV(time), newfov, time, len); 
+                               //*fv = fov = atof(events[i]->getParam());
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_FADEIN) {
+                               float time = atof(events[i]->getParam());
+                               Cbuf_AddText(va("fade 0 0 0 0 %f", time));
+                               Cbuf_Execute();
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_FADEOUT) {
+                               float time = atof(events[i]->getParam());
+                               Cbuf_AddText(va("fade 0 0 0 255 %f", time));
+                               Cbuf_Execute();
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_CAMERA) {
+                               memset(buff, 0, sizeof(buff));
+                               strcpy(buff, events[i]->getParam());
+                               const char *param1 = strtok(buff, " \t,\0");
+                               const char *param2 = strtok(NULL, " \t,\0");
+
+                               if(param2) {
+                                       loadCamera(atoi(param1), va("cameras/%s.camera", param2));
+                                       startCamera(time);
+                               } else {
+                                       loadCamera(0, va("cameras/%s.camera", events[i]->getParam()));
+                                       startCamera(time);
+                               }
+                               return true;
+                       } else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {
+                               return false;
+                       }
+               }
+       }
+
+       origin = *cameraPosition->getPosition(time);
+       
+       *fv = fov.getFOV(time);
+
+       idVec3 temp = origin;
+
+       int numTargets = targetPositions.Num();
+       if (numTargets == 0) {
+/*
+               // follow the path
+               if (cameraSpline.getActiveSegment() < count - 1) {
+                       temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
+                       if (temp == origin) {
+                               int index = cameraSpline.getActiveSegment() + 2;
+                               while (temp == origin && index < count - 1) {
+                                       temp = *cameraSpline.splinePoints[index++];
+                               }
+                       }
+               }
+*/
+       } else {
+    if( getActiveTarget()->numPoints() > 0 ) {
+                 temp = *getActiveTarget()->getPosition(time);
+    }
+       }
+       
+       temp -= origin;
+       temp.Normalize();
+       direction = temp;
+
+       return true;
+}
+
+bool idCameraDef::waitEvent(int index) {
+       //for (int i = 0; i < events.Num(); i++) {
+       //      if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
+       //              return true;
+       //      }
+    //}
+       return false;
+}
+
+
+#define NUM_CCELERATION_SEGS 10
+#define CELL_AMT 5
+
+void idCameraDef::buildCamera() {
+       int i;
+       int lastSwitch = 0;
+       idList<float> waits;
+       idList<int> targets;
+
+       totalTime = baseTime;
+       cameraPosition->setTime((long)totalTime * 1000);
+       // we have a base time layout for the path and the target path
+       // now we need to layer on any wait or speed changes
+       for (i = 0; i < events.Num(); i++) {
+               idCameraEvent *ev = events[i];
+               events[i]->setTriggered(false);
+               switch (events[i]->getType()) {
+                       case idCameraEvent::EVENT_TARGET : {
+                               targets.Append(i);
+                               break;
+                       }
+                       case idCameraEvent::EVENT_FEATHER : {
+                               long startTime = 0;
+                               float speed = 0;
+                               long loopTime = 10;
+                               float stepGoal = cameraPosition->getBaseVelocity() / (1000 / loopTime);
+                               while (startTime <= 1000) {
+                                       cameraPosition->addVelocity(startTime, loopTime, speed);
+                                       speed += stepGoal;
+                                       if (speed > cameraPosition->getBaseVelocity()) {
+                                               speed = cameraPosition->getBaseVelocity();
+                                       }
+                                       startTime += loopTime;
+                               }
+
+                               startTime = (long)(totalTime * 1000 - 1000);
+                               long endTime = startTime + 1000;
+                               speed = cameraPosition->getBaseVelocity();
+                               while (startTime < endTime) {
+                                       speed -= stepGoal;
+                                       if (speed < 0) {
+                                               speed = 0;
+                                       }
+                                       cameraPosition->addVelocity(startTime, loopTime, speed);
+                                       startTime += loopTime;
+                               }
+                               break;
+
+                       }
+                       case idCameraEvent::EVENT_WAIT : {
+                               waits.Append(atof(events[i]->getParam()));
+
+                               //FIXME: this is quite hacky for Wolf E3, accel and decel needs
+                               // do be parameter based etc.. 
+                               long startTime = events[i]->getTime() - 1000;
+                               if (startTime < 0) {
+                                       startTime = 0;
+                               }
+                               float speed = cameraPosition->getBaseVelocity();
+                               long loopTime = 10;
+                               float steps = speed / ((events[i]->getTime() - startTime) / loopTime);
+                               while (startTime <= events[i]->getTime() - loopTime) {
+                                       cameraPosition->addVelocity(startTime, loopTime, speed);
+                                       speed -= steps;
+                                       startTime += loopTime;
+                               }
+                               cameraPosition->addVelocity(events[i]->getTime(), (long)atof(events[i]->getParam()) * 1000, 0);
+
+                               startTime = (long)(events[i]->getTime() + atof(events[i]->getParam()) * 1000);
+                               long endTime = startTime + 1000;
+                               speed = 0;
+                               while (startTime <= endTime) {
+                                       cameraPosition->addVelocity(startTime, loopTime, speed);
+                                       speed += steps;
+                                       startTime += loopTime;
+                               }
+                               break;
+                       }
+                       case idCameraEvent::EVENT_TARGETWAIT : {
+                               //targetWaits.Append(i);
+                               break;
+                       }
+                       case idCameraEvent::EVENT_SPEED : {
+/*
+                               // take the average delay between up to the next five segments
+                               float adjust = atof(events[i]->getParam());
+                               int index = events[i]->getSegment();
+                               total = 0;
+                               count = 0;
+
+                               // get total amount of time over the remainder of the segment
+                               for (j = index; j < cameraSpline.numSegments() - 1; j++) {
+                                       total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
+                                       count++;
+                               }
+
+                               // multiply that by the adjustment
+                               double newTotal = total * adjust;
+                               // what is the difference.. 
+                               newTotal -= total;
+                               totalTime += newTotal / 1000;
+
+                               // per segment difference
+                               newTotal /= count;
+                               int additive = newTotal;
+
+                               // now propogate that difference out to each segment
+                               for (j = index; j < cameraSpline.numSegments(); j++) {
+                                       cameraSpline.addSegmentTime(j, additive);
+                                       additive += newTotal;
+                               }
+                               break;
+*/
+                       }
+               }
+       }
+
+
+       for (i = 0; i < waits.Num(); i++) {
+               totalTime += waits[i];
+       }
+
+       // on a new target switch, we need to take time to this point ( since last target switch ) 
+       // and allocate it across the active target, then reset time to this point
+       long timeSoFar = 0;
+       long total = (long)(totalTime * 1000);
+       for (i = 0; i < targets.Num(); i++) {
+               long t;
+               if (i < targets.Num() - 1) {
+                       t = events[targets[i+1]]->getTime();
+               } else {
+                       t = total - timeSoFar;
+               }
+               // t is how much time to use for this target
+               setActiveTargetByName(events[targets[i]]->getParam());
+               getActiveTarget()->setTime(t);
+               timeSoFar += t;
+       }
+
+       
+}
+
+void idCameraDef::startCamera(long t) {
+       cameraPosition->clearVelocities();
+       cameraPosition->start(t);
+       buildCamera();
+       fov.reset(90, 90, t, 0);
+       //for (int i = 0; i < targetPositions.Num(); i++) {
+       //      targetPositions[i]->
+       //}
+       startTime = t;
+       cameraRunning = true;
+}
+
+
+void idCameraDef::parse(const char *(*text)  ) {
+
+       const char      *token;
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !Q_stricmp (token, "}") ) {
+                       break;
+               }
+
+               if (Q_stricmp(token, "time") == 0) {
+                       baseTime = Com_ParseFloat(text);
+               }
+               else if (Q_stricmp(token, "camera_fixed") == 0) {
+                       cameraPosition = new idFixedPosition();
+                       cameraPosition->parse(text);
+               }
+               else if (Q_stricmp(token, "camera_interpolated") == 0) {
+                       cameraPosition = new idInterpolatedPosition();
+                       cameraPosition->parse(text);
+               }
+               else if (Q_stricmp(token, "camera_spline") == 0) {
+                       cameraPosition = new idSplinePosition();
+                       cameraPosition->parse(text);
+               }
+               else if (Q_stricmp(token, "target_fixed") == 0) {
+                       idFixedPosition *pos = new idFixedPosition();
+                       pos->parse(text);
+                       targetPositions.Append(pos);
+               }
+               else if (Q_stricmp(token, "target_interpolated") == 0) {
+                       idInterpolatedPosition *pos = new idInterpolatedPosition();
+                       pos->parse(text);
+                       targetPositions.Append(pos);
+               }
+               else if (Q_stricmp(token, "target_spline") == 0) {
+                       idSplinePosition *pos = new idSplinePosition();
+                       pos->parse(text);
+                       targetPositions.Append(pos);
+               }
+               else if (Q_stricmp(token, "fov") == 0) {
+                       fov.parse(text);
+               }
+               else if (Q_stricmp(token, "event") == 0) {
+                       idCameraEvent *event = new idCameraEvent();
+                       event->parse(text);
+                       addEvent(event);
+               }
+
+
+       } while (1);
+
+       if ( !cameraPosition ) {
+               Com_Printf( "no camera position specified\n" );
+               // prevent a crash later on
+               cameraPosition = new idFixedPosition();
+       }
+
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+
+}
+
+bool idCameraDef::load(const char *filename) {
+       char *buf;
+       const char *buf_p;
+       int length = FS_ReadFile( filename, (void **)&buf );
+       if ( !buf ) {
+               return false;
+       }
+
+       clear();
+       Com_BeginParseSession( filename );
+       buf_p = buf;
+       parse(&buf_p);
+       Com_EndParseSession();
+       FS_FreeFile( buf );
+
+       return true;
+}
+
+void idCameraDef::save(const char *filename) {
+       fileHandle_t file = FS_FOpenFileWrite(filename);
+       if (file) {
+               int i;
+               idStr s = "cameraPathDef { \n"; 
+               FS_Write(s.c_str(), s.length(), file);
+               s = va("\ttime %f\n", baseTime);
+               FS_Write(s.c_str(), s.length(), file);
+
+               cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr()));
+
+               for (i = 0; i < numTargets(); i++) {
+                       targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr()));
+               }
+
+               for (i = 0; i < events.Num(); i++) {
+                       events[i]->write(file, "event");
+               }
+
+               fov.write(file, "fov");
+
+               s = "}\n";
+               FS_Write(s.c_str(), s.length(), file);
+       }
+       FS_FCloseFile(file);
+}
+
+int idCameraDef::sortEvents(const void *p1, const void *p2) {
+       idCameraEvent *ev1 = (idCameraEvent*)(p1);
+       idCameraEvent *ev2 = (idCameraEvent*)(p2);
+
+       if (ev1->getTime() > ev2->getTime()) {
+               return -1;
+       }
+       if (ev1->getTime() < ev2->getTime()) {
+               return 1;
+       }
+       return 0; 
+}
+
+void idCameraDef::addEvent(idCameraEvent *event) {
+       events.Append(event);
+       //events.Sort(&sortEvents);
+
+}
+void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {
+       addEvent(new idCameraEvent(t, param, time));
+       buildCamera();
+}
+
+void idCameraDef::removeEvent(int index) {
+       events.RemoveIndex(index);
+       buildCamera();
+}
+
+
+const char *idCameraEvent::eventStr[] = {
+       "NA",
+       "WAIT",
+       "TARGETWAIT",
+       "SPEED",
+       "TARGET",
+       "SNAPTARGET",
+       "FOV",
+       "CMD",
+       "TRIGGER",
+       "STOP",
+       "CAMERA",
+       "FADEOUT",
+       "FADEIN",
+       "FEATHER"
+};
+
+void idCameraEvent::parse(const char *(*text)  ) {
+       const char *token;
+       Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+               // here we may have to jump over brush epairs ( only used in editor )
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "type") == 0) {
+                               type = static_cast<idCameraEvent::eventType>(atoi(token));
+                       } else if (Q_stricmp(key.c_str(), "param") == 0) {
+                               paramStr = token;
+                       } else if (Q_stricmp(key.c_str(), "time") == 0) {
+                               time = atoi(token);
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+       } while (1);
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+}
+
+void idCameraEvent::write(fileHandle_t file, const char *name) {
+       idStr s = va("\t%s {\n", name);
+       FS_Write(s.c_str(), s.length(), file);
+       s = va("\t\ttype %d\n", static_cast<int>(type));
+       FS_Write(s.c_str(), s.length(), file);
+       s = va("\t\tparam \"%s\"\n", paramStr.c_str());
+       FS_Write(s.c_str(), s.length(), file);
+       s = va("\t\ttime %d\n", time);
+       FS_Write(s.c_str(), s.length(), file);
+       s = "\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+
+const char *idCameraPosition::positionStr[] = {
+       "Fixed",
+       "Interpolated",
+       "Spline",
+};
+
+
+
+const idVec3 *idInterpolatedPosition::getPosition(long t) { 
+       static idVec3 interpolatedPos;
+
+       float velocity = getVelocity(t);
+       float timePassed = t - lastTime;
+       lastTime = t;
+
+       // convert to seconds   
+       timePassed /= 1000;
+
+       float distToTravel = timePassed * velocity;
+
+       idVec3 temp = startPos;
+       temp -= endPos;
+       float distance = temp.Length();
+
+       distSoFar += distToTravel;
+       float percent = (float)(distSoFar) / distance;
+
+       if (percent > 1.0) {
+               percent = 1.0;
+       } else if (percent < 0.0) {
+               percent = 0.0;
+       }
+
+       // the following line does a straigt calc on percentage of time
+       // float percent = (float)(startTime + time - t) / time;
+
+       idVec3 v1 = startPos;
+       idVec3 v2 = endPos;
+       v1 *= (1.0 - percent);
+       v2 *= percent;
+       v1 += v2;
+       interpolatedPos = v1;
+       return &interpolatedPos;
+}
+
+
+void idCameraFOV::parse(const char *(*text)  ) {
+       const char *token;
+       Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+               // here we may have to jump over brush epairs ( only used in editor )
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "fov") == 0) {
+                               fov = atof(token);
+                       } else if (Q_stricmp(key.c_str(), "startFOV") == 0) {
+                               startFOV = atof(token);
+                       } else if (Q_stricmp(key.c_str(), "endFOV") == 0) {
+                               endFOV = atof(token);
+                       } else if (Q_stricmp(key.c_str(), "time") == 0) {
+                               time = atoi(token);
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+       } while (1);
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+}
+
+bool idCameraPosition::parseToken(const char *key, const char *(*text)) {
+       const char *token = Com_Parse(text);
+       if (Q_stricmp(key, "time") == 0) {
+               time = atol(token);
+               return true;
+       } else if (Q_stricmp(key, "type") == 0) {
+               type = static_cast<idCameraPosition::positionType>(atoi(token));
+               return true;
+       } else if (Q_stricmp(key, "velocity") == 0) {
+               long t = atol(token);
+               token = Com_Parse(text);
+               long d = atol(token);
+               token = Com_Parse(text);
+               float s = atof(token);
+               addVelocity(t, d, s);
+               return true;
+       } else if (Q_stricmp(key, "baseVelocity") == 0) {
+               baseVelocity = atof(token);
+               return true;
+       } else if (Q_stricmp(key, "name") == 0) {
+               name = token;
+               return true;
+       } else if (Q_stricmp(key, "time") == 0) {
+               time = atoi(token);
+               return true;
+       }
+       Com_UngetToken();
+       return false;
+}
+
+
+
+void idFixedPosition::parse(const char *(*text)  ) {
+       const char *token;
+       Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+               // here we may have to jump over brush epairs ( only used in editor )
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "pos") == 0) {
+                               Com_UngetToken();
+                               Com_Parse1DMatrix( text, 3, pos );
+                       } else {
+                               Com_UngetToken();
+                               idCameraPosition::parseToken(key.c_str(), text);        
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+       } while (1);
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+}
+
+void idInterpolatedPosition::parse(const char *(*text)  ) {
+       const char *token;
+       Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+               // here we may have to jump over brush epairs ( only used in editor )
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "startPos") == 0) {
+                               Com_UngetToken();
+                               Com_Parse1DMatrix( text, 3, startPos );
+                       } else if (Q_stricmp(key.c_str(), "endPos") == 0) {
+                               Com_UngetToken();
+                               Com_Parse1DMatrix( text, 3, endPos );
+                       } else {
+                               Com_UngetToken();
+                               idCameraPosition::parseToken(key.c_str(), text);        
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+       } while (1);
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+}
+
+
+void idSplinePosition::parse(const char *(*text)  ) {
+       const char *token;
+       Com_MatchToken( text, "{" );
+       do {
+               token = Com_Parse( text );
+       
+               if ( !token[0] ) {
+                       break;
+               }
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+               // here we may have to jump over brush epairs ( only used in editor )
+               do {
+                       // if token is not a brace, it is a key for a key/value pair
+                       if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
+                               break;
+                       }
+
+                       Com_UngetToken();
+                       idStr key = Com_ParseOnLine(text);
+                       
+                       const char *token = Com_Parse(text);
+                       if (Q_stricmp(key.c_str(), "target") == 0) {
+                               target.parse(text);
+                       } else {
+                               Com_UngetToken();
+                               idCameraPosition::parseToken(key.c_str(), text);        
+                       }
+                       token = Com_Parse(text);
+
+               } while (1);
+
+               if ( !strcmp (token, "}") ) {
+                       break;
+               }
+
+       } while (1);
+       Com_UngetToken();
+       Com_MatchToken( text, "}" );
+}
+
+
+
+void idCameraFOV::write(fileHandle_t file, const char *p) {
+       idStr s = va("\t%s {\n", p);
+       FS_Write(s.c_str(), s.length(), file);
+       
+       s = va("\t\tfov %f\n", fov);
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\tstartFOV %f\n", startFOV);
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\tendFOV %f\n", endFOV);
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\ttime %i\n", time);
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = "\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+
+void idCameraPosition::write(fileHandle_t file, const char *p) {
+       
+       idStr s = va("\t\ttime %i\n", time);
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\ttype %i\n", static_cast<int>(type));
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\tname %s\n", name.c_str());
+       FS_Write(s.c_str(), s.length(), file);
+
+       s = va("\t\tbaseVelocity %f\n", baseVelocity);
+       FS_Write(s.c_str(), s.length(), file);
+
+       for (int i = 0; i < velocities.Num(); i++) {
+               s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed);
+               FS_Write(s.c_str(), s.length(), file);
+       }
+
+}
+
+void idFixedPosition::write(fileHandle_t file, const char *p) {
+       idStr s = va("\t%s {\n", p);
+       FS_Write(s.c_str(), s.length(), file);
+       idCameraPosition::write(file, p);
+       s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z);
+       FS_Write(s.c_str(), s.length(), file);
+       s = "\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+void idInterpolatedPosition::write(fileHandle_t file, const char *p) {
+       idStr s = va("\t%s {\n", p);
+       FS_Write(s.c_str(), s.length(), file);
+       idCameraPosition::write(file, p);
+       s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z);
+       FS_Write(s.c_str(), s.length(), file);
+       s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z);
+       FS_Write(s.c_str(), s.length(), file);
+       s = "\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+void idSplinePosition::write(fileHandle_t file, const char *p) {
+       idStr s = va("\t%s {\n", p);
+       FS_Write(s.c_str(), s.length(), file);
+       idCameraPosition::write(file, p);
+       target.write(file, "target");
+       s = "\t}\n";
+       FS_Write(s.c_str(), s.length(), file);
+}
+
+void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {
+       const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name;
+       idCameraPosition *pos = newFromType(type);
+       if (pos) {
+               pos->setName(name);
+               targetPositions.Append(pos);
+               activeTarget = numTargets()-1;
+               if (activeTarget == 0) {
+                       // first one
+                       addEvent(idCameraEvent::EVENT_TARGET, name, 0);
+               }
+       }
+}
+
+const idVec3 *idSplinePosition::getPosition(long t) {
+       static idVec3 interpolatedPos;
+
+       float velocity = getVelocity(t);
+       float timePassed = t - lastTime;
+       lastTime = t;
+
+       // convert to seconds   
+       timePassed /= 1000;
+
+       float distToTravel = timePassed * velocity;
+
+       distSoFar += distToTravel;
+       double tempDistance = target.totalDistance();
+
+       double percent = (double)(distSoFar) / tempDistance;
+
+       double targetDistance = percent * tempDistance;
+       tempDistance = 0;
+
+       double lastDistance1,lastDistance2;
+       lastDistance1 = lastDistance2 = 0;
+       idVec3 temp;
+       int count = target.numSegments();
+       int i;
+       for(i = 1; i < count; i++) {
+               temp = *target.getSegmentPoint(i-1);
+               temp -= *target.getSegmentPoint(i);
+               tempDistance += temp.Length();
+               if (i & 1) {
+                       lastDistance1 = tempDistance;
+               } else {
+                       lastDistance2 = tempDistance;
+               }
+               if (tempDistance >= targetDistance) {
+                       break;
+               }
+       }
+
+       if ( i >= count - 1) {
+               interpolatedPos = *target.getSegmentPoint(i-1);
+       } else {
+#if 0
+               double timeHi = target.getSegmentTime(i + 1);
+               double timeLo = target.getSegmentTime(i - 1);
+               double percent = (timeHi - t) / (timeHi - timeLo); 
+               idVec3 v1 = *target.getSegmentPoint(i - 1);
+               idVec3 v2 = *target.getSegmentPoint(i + 1);
+               v2 *= (1.0 - percent);
+               v1 *= percent;
+               v2 += v1;
+               interpolatedPos = v2;
+#else
+               if (lastDistance1 > lastDistance2) {
+                       double d = lastDistance2;
+                       lastDistance2 = lastDistance1;
+                       lastDistance1 = d;
+               }
+
+               idVec3 v1 = *target.getSegmentPoint(i - 1);
+               idVec3 v2 = *target.getSegmentPoint(i);
+               double percent = (lastDistance2 - targetDistance) / (lastDistance2 - lastDistance1); 
+               v2 *= (1.0 - percent);
+               v1 *= percent;
+               v2 += v1;
+               interpolatedPos = v2;
+#endif
+       }
+       return &interpolatedPos;
+
+}
+
+
+