-/*\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-2006 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 ) {
+ glColor3fv( color );
+ glPointSize( size );
+ glBegin( GL_POINTS );
+ glVertex3fv( point );
+ glEnd();
+ idVec3 v = point;
+ v.x += 1;
+ v.y += 1;
+ v.z += 1;
+ glRasterPos3fv( v );
+ glCallLists( 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;
+ glColor3fv( color );
+ glBegin( GL_LINE_LOOP );
+ glVertex3f( mins[0],mins[1],mins[2] );
+ glVertex3f( maxs[0],mins[1],mins[2] );
+ glVertex3f( maxs[0],maxs[1],mins[2] );
+ glVertex3f( mins[0],maxs[1],mins[2] );
+ glEnd();
+ glBegin( GL_LINE_LOOP );
+ glVertex3f( mins[0],mins[1],maxs[2] );
+ glVertex3f( maxs[0],mins[1],maxs[2] );
+ glVertex3f( maxs[0],maxs[1],maxs[2] );
+ glVertex3f( mins[0],maxs[1],maxs[2] );
+ glEnd();
+
+ glBegin( GL_LINES );
+ glVertex3f( mins[0],mins[1],mins[2] );
+ glVertex3f( mins[0],mins[1],maxs[2] );
+ glVertex3f( mins[0],maxs[1],maxs[2] );
+ glVertex3f( mins[0],maxs[1],mins[2] );
+ glVertex3f( maxs[0],mins[1],mins[2] );
+ glVertex3f( maxs[0],mins[1],maxs[2] );
+ glVertex3f( maxs[0],maxs[1],maxs[2] );
+ glVertex3f( maxs[0],maxs[1],mins[2] );
+ glEnd();
+
+}
+
+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();
+ }
+
+
+ glColor3fv( controlColor );
+ glPointSize( 5 );
+
+ glBegin( GL_POINTS );
+ for ( i = 0; i < controlPoints.Num(); i++ ) {
+ glVertex3fv( *controlPoints[i] );
+ }
+ glEnd();
+
+ if ( editMode ) {
+ for ( i = 0; i < controlPoints.Num(); i++ ) {
+ glBox( activeColor, *controlPoints[i], 4 );
+ }
+ }
+
+ //Draw the curve
+ glColor3fv( pathColor );
+ glBegin( GL_LINE_STRIP );
+ int count = splinePoints.Num();
+ for ( i = 0; i < count; i++ ) {
+ glVertex3fv( *splinePoints[i] );
+ }
+ glEnd();
+
+ if ( editMode ) {
+ glColor3fv( segmentColor );
+ glPointSize( 3 );
+ glBegin( GL_POINTS );
+ for ( i = 0; i < count; i++ ) {
+ glVertex3fv( *splinePoints[i] );
+ }
+ glEnd();
+ }
+ 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;
+
+ 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;
+ 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++ ) {
+ 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;
+
+ 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 ) {
+ 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;
+
+}