Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

splines.cpp (29708B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 
     23 //#include "stdafx.h"
     24 //#include "qe3.h"
     25 
     26 #include "q_shared.hpp"
     27 #include "splines.h"
     28 
     29 extern "C" {
     30 int FS_Write( const void *buffer, int len, fileHandle_t h );
     31 int FS_ReadFile( const char *qpath, void **buffer );
     32 void FS_FreeFile( void *buffer );
     33 fileHandle_t FS_FOpenFileWrite( const char *filename );
     34 void FS_FCloseFile( fileHandle_t f );
     35 }
     36 
     37 float Q_fabs( float f ) {
     38 	int tmp = * ( int * ) &f;
     39 	tmp &= 0x7FFFFFFF;
     40 	return * ( float * ) &tmp;
     41 }
     42 
     43 
     44 //#include "../shared/windings.h"
     45 //#include "../qcommon/qcommon.h"
     46 //#include "../sys/sys_public.h"
     47 //#include "../game/game_entity.h"
     48 
     49 idCameraDef splineList;
     50 idCameraDef *g_splineList = &splineList;
     51 
     52 idVec3_t idSplineList::zero(0,0,0);
     53 /*
     54 void glLabeledPoint(idVec3_t &color, idVec3_t &point, float size, const char *label) {
     55 	qglColor3fv(color);
     56 	qglPointSize(size);
     57 	qglBegin(GL_POINTS);
     58 	qglVertex3fv(point);
     59 	qglEnd();
     60 	idVec3_t v = point;
     61 	v.x += 1;
     62 	v.y += 1;
     63 	v.z += 1;
     64 	qglRasterPos3fv (v);
     65 	qglCallLists (strlen(label), GL_UNSIGNED_BYTE, label);
     66 }
     67 
     68 
     69 void glBox(idVec3_t &color, idVec3_t &point, float size) {
     70 	idVec3_t mins(point);
     71 	idVec3_t maxs(point);
     72 	mins[0] -= size;
     73 	mins[1] += size;
     74 	mins[2] -= size;
     75 	maxs[0] += size;
     76 	maxs[1] -= size;
     77 	maxs[2] += size;
     78 	qglColor3fv(color);
     79 	qglBegin(GL_LINE_LOOP);
     80 	qglVertex3f(mins[0],mins[1],mins[2]);
     81 	qglVertex3f(maxs[0],mins[1],mins[2]);
     82 	qglVertex3f(maxs[0],maxs[1],mins[2]);
     83 	qglVertex3f(mins[0],maxs[1],mins[2]);
     84 	qglEnd();
     85 	qglBegin(GL_LINE_LOOP);
     86 	qglVertex3f(mins[0],mins[1],maxs[2]);
     87 	qglVertex3f(maxs[0],mins[1],maxs[2]);
     88 	qglVertex3f(maxs[0],maxs[1],maxs[2]);
     89 	qglVertex3f(mins[0],maxs[1],maxs[2]);
     90 	qglEnd();
     91 
     92 	qglBegin(GL_LINES);
     93   	qglVertex3f(mins[0],mins[1],mins[2]);
     94 	qglVertex3f(mins[0],mins[1],maxs[2]);
     95 	qglVertex3f(mins[0],maxs[1],maxs[2]);
     96 	qglVertex3f(mins[0],maxs[1],mins[2]);
     97 	qglVertex3f(maxs[0],mins[1],mins[2]);
     98 	qglVertex3f(maxs[0],mins[1],maxs[2]);
     99 	qglVertex3f(maxs[0],maxs[1],maxs[2]);
    100 	qglVertex3f(maxs[0],maxs[1],mins[2]);
    101 	qglEnd();
    102 
    103 }
    104 
    105 void splineTest() {
    106 	//g_splineList->load("p:/doom/base/maps/test_base1.camera");
    107 }
    108 
    109 void splineDraw() {
    110 	//g_splineList->addToRenderer();
    111 }
    112 
    113 
    114 //extern void D_DebugLine( const idVec3_t &color, const idVec3_t &start, const idVec3_t &end );
    115 
    116 void debugLine(idVec3_t &color, float x, float y, float z, float x2, float y2, float z2) {
    117 	//idVec3_t from(x, y, z);
    118 	//idVec3_t to(x2, y2, z2);
    119 	//D_DebugLine(color, from, to);
    120 }
    121 
    122 
    123 void idSplineList::addToRenderer() {
    124 
    125 	if (controlPoints.Num() == 0) {
    126 		return;
    127 	}
    128 
    129 	idVec3_t mins, maxs;
    130 	idVec3_t yellow(1.0, 1.0, 0);
    131 	idVec3_t white(1.0, 1.0, 1.0);
    132         int i;
    133         
    134 	for(i = 0; i < controlPoints.Num(); i++) {
    135 		VectorCopy(*controlPoints[i], mins);
    136 		VectorCopy(mins, maxs);
    137 		mins[0] -= 8;
    138 		mins[1] += 8;
    139 		mins[2] -= 8;
    140 		maxs[0] += 8;
    141 		maxs[1] -= 8;
    142 		maxs[2] += 8;
    143 		debugLine( yellow, mins[0], mins[1], mins[2], maxs[0], mins[1], mins[2]);
    144 		debugLine( yellow, maxs[0], mins[1], mins[2], maxs[0], maxs[1], mins[2]);
    145 		debugLine( yellow, maxs[0], maxs[1], mins[2], mins[0], maxs[1], mins[2]);
    146 		debugLine( yellow, mins[0], maxs[1], mins[2], mins[0], mins[1], mins[2]);
    147 		
    148 		debugLine( yellow, mins[0], mins[1], maxs[2], maxs[0], mins[1], maxs[2]);
    149 		debugLine( yellow, maxs[0], mins[1], maxs[2], maxs[0], maxs[1], maxs[2]);
    150 		debugLine( yellow, maxs[0], maxs[1], maxs[2], mins[0], maxs[1], maxs[2]);
    151 		debugLine( yellow, mins[0], maxs[1], maxs[2], mins[0], mins[1], maxs[2]);
    152 	    
    153 	}
    154 
    155 	int step = 0;
    156 	idVec3_t step1;
    157 	for(i = 3; i < controlPoints.Num(); i++) {
    158 		for (float tension = 0.0f; tension < 1.001f; tension += 0.1f) {
    159 			float x = 0;
    160 			float y = 0;
    161 			float z = 0;
    162 			for (int j = 0; j < 4; j++) {
    163 				x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
    164 				y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
    165 				z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
    166 			}
    167 			if (step == 0) {
    168 				step1[0] = x;
    169 				step1[1] = y;
    170 				step1[2] = z;
    171 				step = 1;
    172 			} else {
    173 				debugLine( white, step1[0], step1[1], step1[2], x, y, z);
    174 				step = 0;
    175 			}
    176 
    177 		}
    178 	}
    179 }
    180 */
    181 
    182 void idSplineList::buildSpline() {
    183 	//int start = Sys_Milliseconds();
    184 	clearSpline();
    185 	for(int i = 3; i < controlPoints.Num(); i++) {
    186 		for (float tension = 0.0f; tension < 1.001f; tension += granularity) {
    187 			float x = 0;
    188 			float y = 0;
    189 			float z = 0;
    190 			for (int j = 0; j < 4; j++) {
    191 				x += controlPoints[i - (3 - j)]->x * calcSpline(j, tension);
    192 				y += controlPoints[i - (3 - j)]->y * calcSpline(j, tension);
    193 				z += controlPoints[i - (3 - j)]->z * calcSpline(j, tension);
    194 			}
    195 			splinePoints.Append(new idVec3_t(x, y, z));
    196 		}
    197 	}
    198 	dirty = false;
    199 	//Com_Printf("Spline build took %f seconds\n", (float)(Sys_Milliseconds() - start) / 1000);
    200 }
    201 
    202 /*
    203 void idSplineList::draw(bool editMode) {
    204 	int i;
    205 	vec4_t yellow(1, 1, 0, 1);
    206         
    207 	if (controlPoints.Num() == 0) {
    208 		return;
    209 	}
    210 
    211 	if (dirty) {
    212 		buildSpline();
    213 	}
    214 
    215 
    216 	qglColor3fv(controlColor);
    217 	qglPointSize(5);
    218 	
    219 	qglBegin(GL_POINTS);
    220 	for (i = 0; i < controlPoints.Num(); i++) {
    221 		qglVertex3fv(*controlPoints[i]);
    222 	}
    223 	qglEnd();
    224 	
    225 	if (editMode) {
    226 		for(i = 0; i < controlPoints.Num(); i++) {
    227 			glBox(activeColor, *controlPoints[i], 4);
    228 		}
    229 	}
    230 
    231 	//Draw the curve
    232 	qglColor3fv(pathColor);
    233 	qglBegin(GL_LINE_STRIP);
    234 	int count = splinePoints.Num();
    235 	for (i = 0; i < count; i++) {
    236 		qglVertex3fv(*splinePoints[i]);
    237 	}
    238 	qglEnd();
    239 
    240 	if (editMode) {
    241 		qglColor3fv(segmentColor);
    242 		qglPointSize(3);
    243 		qglBegin(GL_POINTS);
    244 		for (i = 0; i < count; i++) {
    245 			qglVertex3fv(*splinePoints[i]);
    246 		}
    247 		qglEnd();
    248 	}
    249 	if (count > 0) {
    250 		//assert(activeSegment >=0 && activeSegment < count);
    251 		if (activeSegment >=0 && activeSegment < count) {
    252 			glBox(activeColor, *splinePoints[activeSegment], 6);
    253 			glBox(yellow, *splinePoints[activeSegment], 8);
    254 		}
    255 	}
    256 
    257 }
    258 */
    259 
    260 float idSplineList::totalDistance() {
    261 
    262 	if (controlPoints.Num() == 0) {
    263 		return 0.0;
    264 	}
    265 
    266 	if (dirty) {
    267 		buildSpline();
    268 	}
    269 
    270 	float dist = 0.0;
    271 	idVec3_t temp;
    272 	int count = splinePoints.Num();
    273 	for(int i = 1; i < count; i++) {
    274 		temp = *splinePoints[i-1];
    275 		temp -= *splinePoints[i];
    276 		dist += temp.Length();
    277 	}
    278 	return dist;
    279 }
    280 
    281 void idSplineList::initPosition(long bt, long totalTime) {
    282 
    283 	if (dirty) {
    284 		buildSpline();
    285 	}
    286 
    287 	if (splinePoints.Num() == 0) {
    288 		return;
    289 	}
    290 
    291 	baseTime = bt;
    292 	time = totalTime;
    293 
    294 	// calc distance to travel ( this will soon be broken into time segments )
    295 	splineTime.Clear();
    296 	splineTime.Append(bt);
    297 	double dist = totalDistance();
    298 	double distSoFar = 0.0;
    299 	idVec3_t temp;
    300 	int count = splinePoints.Num();
    301 	//for(int i = 2; i < count - 1; i++) {
    302 	for(int i = 1; i < count; i++) {
    303 		temp = *splinePoints[i-1];
    304 		temp -= *splinePoints[i];
    305 		distSoFar += temp.Length();
    306 		double percent = distSoFar / dist;
    307 		percent *= totalTime;
    308 		splineTime.Append(percent + bt);
    309 	}
    310 	assert(splineTime.Num() == splinePoints.Num());
    311 	activeSegment = 0;
    312 }
    313 
    314 
    315 
    316 float idSplineList::calcSpline(int step, float tension) {
    317 	switch(step) {
    318 		case 0:	return (pow(1 - tension, 3)) / 6;
    319 		case 1:	return (3 * pow(tension, 3) - 6 * pow(tension, 2) + 4) / 6;
    320 		case 2:	return (-3 * pow(tension, 3) + 3 * pow(tension, 2) + 3 * tension + 1) / 6;
    321 		case 3:	return pow(tension, 3) / 6;
    322 	}
    323 	return 0.0;
    324 }
    325 
    326 
    327 
    328 void idSplineList::updateSelection(const idVec3_t &move) {
    329 	if (selected) {
    330 		dirty = true;
    331 		VectorAdd(*selected, move, *selected);
    332 	}
    333 }
    334 
    335 
    336 void idSplineList::setSelectedPoint(idVec3_t *p) {
    337 	if (p) {
    338 		p->Snap();
    339 		for(int i = 0; i < controlPoints.Num(); i++) {
    340 			if (*p == *controlPoints[i]) {
    341 				selected = controlPoints[i];
    342 			}
    343 		}
    344 	} else {
    345 		selected = NULL;
    346 	}
    347 }
    348 
    349 const idVec3_t *idSplineList::getPosition(long t) {
    350 	static idVec3_t interpolatedPos;
    351 	//static long lastTime = -1;
    352 
    353 	int count = splineTime.Num();
    354 	if (count == 0) {
    355 		return &zero;
    356 	}
    357 
    358 	Com_Printf("Time: %d\n", t);
    359 	assert(splineTime.Num() == splinePoints.Num());
    360 
    361 	while (activeSegment < count) {
    362 		if (splineTime[activeSegment] >= t) {
    363 			if (activeSegment > 0 && activeSegment < count - 1) {
    364 				double timeHi = splineTime[activeSegment + 1];
    365 				double timeLo = splineTime[activeSegment - 1];
    366 				double percent = (timeHi - t) / (timeHi - timeLo); 
    367 				// pick two bounding points
    368 				idVec3_t v1 = *splinePoints[activeSegment-1];
    369 				idVec3_t v2 = *splinePoints[activeSegment+1];
    370 				v2 *= (1.0 - percent);
    371 				v1 *= percent;
    372 				v2 += v1;
    373 				interpolatedPos = v2;
    374 				return &interpolatedPos;
    375 			}
    376 			return splinePoints[activeSegment];
    377 		} else {
    378 			activeSegment++;
    379 		}
    380 	}
    381 	return splinePoints[count-1];
    382 }
    383 
    384 void idSplineList::parse(const char *(*text)  ) {
    385 	const char *token;
    386 	//Com_MatchToken( text, "{" );
    387 	do {
    388 		token = Com_Parse( text );
    389 	
    390 		if ( !token[0] ) {
    391 			break;
    392 		}
    393 		if ( !Q_stricmp (token, "}") ) {
    394 			break;
    395 		}
    396 
    397 		do {
    398 			// if token is not a brace, it is a key for a key/value pair
    399 			if ( !token[0] || !Q_stricmp (token, "(") || !Q_stricmp(token, "}")) {
    400 				break;
    401 			}
    402 
    403 			Com_UngetToken();
    404 			idStr key = Com_ParseOnLine(text);
    405 			const char *token = Com_Parse(text);
    406 			if (Q_stricmp(key.c_str(), "granularity") == 0) {
    407 				granularity = atof(token);
    408 			} else if (Q_stricmp(key.c_str(), "name") == 0) {
    409 				name = token;
    410 			}
    411 			token = Com_Parse(text);
    412 
    413 		} while (1);
    414 
    415 		if ( !Q_stricmp (token, "}") ) {
    416 			break;
    417 		}
    418 
    419 		Com_UngetToken();
    420 		// read the control point
    421 		idVec3_t point;
    422 		Com_Parse1DMatrix( text, 3, point );
    423 		addPoint(point.x, point.y, point.z);
    424 	} while (1);
    425  
    426 	//Com_UngetToken();
    427 	//Com_MatchToken( text, "}" );
    428 	dirty = true;
    429 }
    430 
    431 void idSplineList::write(fileHandle_t file, const char *p) {
    432 	idStr s = va("\t\t%s {\n", p);
    433 	FS_Write(s.c_str(), s.length(), file);
    434 	//s = va("\t\tname %s\n", name.c_str());
    435 	//FS_Write(s.c_str(), s.length(), file);
    436 	s = va("\t\t\tgranularity %f\n", granularity);
    437 	FS_Write(s.c_str(), s.length(), file);
    438 	int count = controlPoints.Num();
    439 	for (int i = 0; i < count; i++) {
    440 		s = va("\t\t\t( %f %f %f )\n", controlPoints[i]->x, controlPoints[i]->y, controlPoints[i]->z);
    441 		FS_Write(s.c_str(), s.length(), file);
    442 	}
    443 	s = "\t\t}\n";
    444 	FS_Write(s.c_str(), s.length(), file);
    445 }
    446 
    447 
    448 void idCameraDef::getActiveSegmentInfo(int segment, idVec3_t &origin, idVec3_t &direction, float *fov) {
    449 #if 0
    450 	if (!cameraSpline.validTime()) {
    451 		buildCamera();
    452 	}
    453 	double d = (double)segment / numSegments();
    454 	getCameraInfo(d * totalTime * 1000, origin, direction, fov);
    455 #endif
    456 /*
    457 	if (!cameraSpline.validTime()) {
    458 		buildCamera();
    459 	}
    460 	origin = *cameraSpline.getSegmentPoint(segment);
    461 	
    462 
    463 	idVec3_t temp;
    464 
    465 	int numTargets = getTargetSpline()->controlPoints.Num();
    466 	int count = cameraSpline.splineTime.Num();
    467 	if (numTargets == 0) {
    468 		// follow the path
    469 		if (cameraSpline.getActiveSegment() < count - 1) {
    470 			temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
    471 		}
    472 	} else if (numTargets == 1) {
    473 		temp = *getTargetSpline()->controlPoints[0];
    474 	} else {
    475 		temp = *getTargetSpline()->getSegmentPoint(segment);
    476 	}
    477 
    478 	temp -= origin;
    479 	temp.Normalize();
    480 	direction = temp;
    481 */
    482 }
    483 
    484 bool idCameraDef::getCameraInfo(long time, idVec3_t &origin, idVec3_t &direction, float *fv) {
    485 
    486 
    487 	if ((time - startTime) / 1000 > totalTime) {
    488 		return false;
    489 	}
    490 
    491 
    492 	for (int i = 0; i < events.Num(); i++) {
    493 		if (time >= startTime + events[i]->getTime() && !events[i]->getTriggered()) {
    494 			events[i]->setTriggered(true);
    495 			if (events[i]->getType() == idCameraEvent::EVENT_TARGET) {
    496 				setActiveTargetByName(events[i]->getParam());
    497 				getActiveTarget()->start(startTime + events[i]->getTime());
    498 				//Com_Printf("Triggered event switch to target: %s\n",events[i]->getParam());
    499 			} else if (events[i]->getType() == idCameraEvent::EVENT_TRIGGER) {
    500 				//idEntity *ent = NULL;
    501 				//ent = level.FindTarget( ent, events[i]->getParam());
    502 				//if (ent) {
    503 				//	ent->signal( SIG_TRIGGER );
    504 				//	ent->ProcessEvent( &EV_Activate, world );
    505 				//}
    506 			} else if (events[i]->getType() == idCameraEvent::EVENT_FOV) {
    507 				//*fv = fov = atof(events[i]->getParam());
    508 			} else if (events[i]->getType() == idCameraEvent::EVENT_STOP) {
    509 				return false;
    510 			}
    511 		}
    512 	}
    513 
    514 	origin = *cameraPosition->getPosition(time);
    515 	
    516 	*fv = fov.getFOV(time);
    517 
    518 	idVec3_t temp = origin;
    519 
    520 	int numTargets = targetPositions.Num();
    521 	if (numTargets == 0) {
    522 /*
    523 		// follow the path
    524 		if (cameraSpline.getActiveSegment() < count - 1) {
    525 			temp = *cameraSpline.splinePoints[cameraSpline.getActiveSegment()+1];
    526 			if (temp == origin) {
    527 				int index = cameraSpline.getActiveSegment() + 2;
    528 				while (temp == origin && index < count - 1) {
    529 					temp = *cameraSpline.splinePoints[index++];
    530 				}
    531 			}
    532 		}
    533 */
    534 	} else {
    535 		temp = *getActiveTarget()->getPosition(time);
    536 	}
    537 	
    538 	temp -= origin;
    539 	temp.Normalize();
    540 	direction = temp;
    541 
    542 	return true;
    543 }
    544 
    545 bool idCameraDef::waitEvent(int index) {
    546 	//for (int i = 0; i < events.Num(); i++) {
    547 	//	if (events[i]->getSegment() == index && events[i]->getType() == idCameraEvent::EVENT_WAIT) {
    548 	//		return true;
    549 	//	}
    550     //}
    551 	return false;
    552 }
    553 
    554 
    555 #define NUM_CCELERATION_SEGS 10
    556 #define CELL_AMT 5
    557 
    558 void idCameraDef::buildCamera() {
    559 	int i;
    560 	//int lastSwitch = 0;
    561 	idList<float> waits;
    562 	idList<int> targets;
    563 
    564 	totalTime = baseTime;
    565 	cameraPosition->setTime(totalTime * 1000);
    566 	// we have a base time layout for the path and the target path
    567 	// now we need to layer on any wait or speed changes
    568 	for (i = 0; i < events.Num(); i++) {
    569 		//idCameraEvent *ev = events[i];
    570 		events[i]->setTriggered(false);
    571 		switch (events[i]->getType()) {
    572 			case idCameraEvent::EVENT_TARGET : {
    573 				targets.Append(i);
    574 				break;
    575 			}
    576 			case idCameraEvent::EVENT_WAIT : {
    577 				waits.Append(atof(events[i]->getParam()));
    578 				cameraPosition->addVelocity(events[i]->getTime(), atof(events[i]->getParam()) * 1000, 0);
    579 				break;
    580 			}
    581 			case idCameraEvent::EVENT_TARGETWAIT : {
    582 				//targetWaits.Append(i);
    583 				break;
    584 			}
    585 			case idCameraEvent::EVENT_SPEED : {
    586 /*
    587 				// take the average delay between up to the next five segments
    588 				float adjust = atof(events[i]->getParam());
    589 				int index = events[i]->getSegment();
    590 				total = 0;
    591 				count = 0;
    592 
    593 				// get total amount of time over the remainder of the segment
    594 				for (j = index; j < cameraSpline.numSegments() - 1; j++) {
    595 					total += cameraSpline.getSegmentTime(j + 1) - cameraSpline.getSegmentTime(j);
    596 					count++;
    597 				}
    598 
    599 				// multiply that by the adjustment
    600 				double newTotal = total * adjust;
    601 				// what is the difference.. 
    602 				newTotal -= total;
    603 				totalTime += newTotal / 1000;
    604 
    605 				// per segment difference
    606 				newTotal /= count;
    607 				int additive = newTotal;
    608 
    609 				// now propogate that difference out to each segment
    610 				for (j = index; j < cameraSpline.numSegments(); j++) {
    611 					cameraSpline.addSegmentTime(j, additive);
    612 					additive += newTotal;
    613 				}
    614 				break;
    615 */
    616 			}
    617     default: break; // FIXME: what about other idCameraEvent?
    618 		}
    619 	}
    620 
    621 
    622 	for (i = 0; i < waits.Num(); i++) {
    623 		totalTime += waits[i];
    624 	}
    625 
    626 	// on a new target switch, we need to take time to this point ( since last target switch ) 
    627 	// and allocate it across the active target, then reset time to this point
    628 	long timeSoFar = 0;
    629 	long total = (int)(totalTime * 1000);
    630 	for (i = 0; i < targets.Num(); i++) {
    631 		long t;
    632 		if (i < targets.Num() - 1) {
    633 			t = events[targets[i+1]]->getTime();
    634 		} else {
    635 			t = total - timeSoFar;
    636 		}
    637 		// t is how much time to use for this target
    638 		setActiveTargetByName(events[targets[i]]->getParam());
    639 		getActiveTarget()->setTime(t);
    640 		timeSoFar += t;
    641 	}
    642 
    643 	
    644 }
    645 
    646 void idCameraDef::startCamera(long t) {
    647 	buildCamera();
    648 	cameraPosition->start(t);
    649 	//for (int i = 0; i < targetPositions.Num(); i++) {
    650 	//	targetPositions[i]->
    651 	//}
    652 	startTime = t;
    653 	cameraRunning = true;
    654 }
    655 
    656 
    657 void idCameraDef::parse(const char *(*text)  ) {
    658 
    659 	const char	*token;
    660 	do {
    661 		token = Com_Parse( text );
    662 	
    663 		if ( !token[0] ) {
    664 			break;
    665 		}
    666 		if ( !Q_stricmp (token, "}") ) {
    667 			break;
    668 		}
    669 
    670 		if (Q_stricmp(token, "time") == 0) {
    671 			baseTime = Com_ParseFloat(text);
    672 		}
    673 
    674 		if (Q_stricmp(token, "camera_fixed") == 0) {
    675 			cameraPosition = new idFixedPosition();
    676 			cameraPosition->parse(text);
    677 		}
    678 
    679 		if (Q_stricmp(token, "camera_interpolated") == 0) {
    680 			cameraPosition = new idInterpolatedPosition();
    681 			cameraPosition->parse(text);
    682 		}
    683 
    684 		if (Q_stricmp(token, "camera_spline") == 0) {
    685 			cameraPosition = new idSplinePosition();
    686 			cameraPosition->parse(text);
    687 		}
    688 
    689 		if (Q_stricmp(token, "target_fixed") == 0) {
    690 			idFixedPosition *pos = new idFixedPosition();
    691 			pos->parse(text);
    692 			targetPositions.Append(pos);
    693 		}
    694 		
    695 		if (Q_stricmp(token, "target_interpolated") == 0) {
    696 			idInterpolatedPosition *pos = new idInterpolatedPosition();
    697 			pos->parse(text);
    698 			targetPositions.Append(pos);
    699 		}
    700 
    701 		if (Q_stricmp(token, "target_spline") == 0) {
    702 			idSplinePosition *pos = new idSplinePosition();
    703 			pos->parse(text);
    704 			targetPositions.Append(pos);
    705 		}
    706 
    707 		if (Q_stricmp(token, "fov") == 0) {
    708 			fov.parse(text);
    709 		}
    710 
    711 		if (Q_stricmp(token, "event") == 0) {
    712 			idCameraEvent *event = new idCameraEvent();
    713 			event->parse(text);
    714 			addEvent(event);
    715 		}
    716 
    717 
    718 	} while (1);
    719 
    720 	Com_UngetToken();
    721 	Com_MatchToken( text, "}" );
    722 
    723 }
    724 
    725 qboolean idCameraDef::load(const char *filename) {
    726 	char *buf;
    727 	const char *buf_p;
    728 	//int length = 
    729   FS_ReadFile( filename, (void **)&buf );
    730 	if ( !buf ) {
    731 		return qfalse;
    732 	}
    733 
    734 	clear();
    735 	Com_BeginParseSession( filename );
    736 	buf_p = buf;
    737 	parse(&buf_p);
    738 	Com_EndParseSession();
    739 	FS_FreeFile( buf );
    740 
    741 	return qtrue;
    742 }
    743 
    744 void idCameraDef::save(const char *filename) {
    745 	fileHandle_t file = FS_FOpenFileWrite(filename);
    746 	if (file) {
    747 		int i;
    748 		idStr s = "cameraPathDef { \n"; 
    749 		FS_Write(s.c_str(), s.length(), file);
    750 		s = va("\ttime %f\n", baseTime);
    751 		FS_Write(s.c_str(), s.length(), file);
    752 
    753 		cameraPosition->write(file, va("camera_%s",cameraPosition->typeStr()));
    754 
    755 		for (i = 0; i < numTargets(); i++) {
    756 			targetPositions[i]->write(file, va("target_%s", targetPositions[i]->typeStr()));
    757 		}
    758 
    759 		for (i = 0; i < events.Num(); i++) {
    760 			events[i]->write(file, "event");
    761 		}
    762 
    763 		fov.write(file, "fov");
    764 
    765 		s = "}\n";
    766 		FS_Write(s.c_str(), s.length(), file);
    767 	}
    768 	FS_FCloseFile(file);
    769 }
    770 
    771 int idCameraDef::sortEvents(const void *p1, const void *p2) {
    772 	idCameraEvent *ev1 = (idCameraEvent*)(p1);
    773 	idCameraEvent *ev2 = (idCameraEvent*)(p2);
    774 
    775 	if (ev1->getTime() > ev2->getTime()) {
    776 		return -1;
    777 	}
    778 	if (ev1->getTime() < ev2->getTime()) {
    779 		return 1;
    780 	}
    781 	return 0; 
    782 }
    783 
    784 void idCameraDef::addEvent(idCameraEvent *event) {
    785 	events.Append(event);
    786 	//events.Sort(&sortEvents);
    787 
    788 }
    789 void idCameraDef::addEvent(idCameraEvent::eventType t, const char *param, long time) {
    790 	addEvent(new idCameraEvent(t, param, time));
    791 	buildCamera();
    792 }
    793 
    794 
    795 const char *idCameraEvent::eventStr[] = {
    796 	"NA",
    797 	"WAIT",
    798 	"TARGETWAIT",
    799 	"SPEED",
    800 	"TARGET",
    801 	"SNAPTARGET",
    802 	"FOV",
    803 	"SCRIPT",
    804 	"TRIGGER",
    805 	"STOP"
    806 };
    807 
    808 void idCameraEvent::parse(const char *(*text)  ) {
    809 	const char *token;
    810 	Com_MatchToken( text, "{" );
    811 	do {
    812 		token = Com_Parse( text );
    813 	
    814 		if ( !token[0] ) {
    815 			break;
    816 		}
    817 		if ( !strcmp (token, "}") ) {
    818 			break;
    819 		}
    820 
    821 		// here we may have to jump over brush epairs ( only used in editor )
    822 		do {
    823 			// if token is not a brace, it is a key for a key/value pair
    824 			if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
    825 				break;
    826 			}
    827 
    828 			Com_UngetToken();
    829 			idStr key = Com_ParseOnLine(text);
    830 			const char *token = Com_Parse(text);
    831 			if (Q_stricmp(key.c_str(), "type") == 0) {
    832 				type = static_cast<idCameraEvent::eventType>(atoi(token));
    833 			} else if (Q_stricmp(key.c_str(), "param") == 0) {
    834 				paramStr = token;
    835 			} else if (Q_stricmp(key.c_str(), "time") == 0) {
    836 				time = atoi(token);
    837 			}
    838 			token = Com_Parse(text);
    839 
    840 		} while (1);
    841 
    842 		if ( !strcmp (token, "}") ) {
    843 			break;
    844 		}
    845 
    846 	} while (1);
    847  
    848 	Com_UngetToken();
    849 	Com_MatchToken( text, "}" );
    850 }
    851 
    852 void idCameraEvent::write(fileHandle_t file, const char *name) {
    853 	idStr s = va("\t%s {\n", name);
    854 	FS_Write(s.c_str(), s.length(), file);
    855 	s = va("\t\ttype %d\n", static_cast<int>(type));
    856 	FS_Write(s.c_str(), s.length(), file);
    857 	s = va("\t\tparam %s\n", paramStr.c_str());
    858 	FS_Write(s.c_str(), s.length(), file);
    859 	s = va("\t\ttime %d\n", time);
    860 	FS_Write(s.c_str(), s.length(), file);
    861 	s = "\t}\n";
    862 	FS_Write(s.c_str(), s.length(), file);
    863 }
    864 
    865 
    866 const char *idCameraPosition::positionStr[] = {
    867 	"Fixed",
    868 	"Interpolated",
    869 	"Spline",
    870 };
    871 
    872 
    873 
    874 const idVec3_t *idInterpolatedPosition::getPosition(long t) { 
    875 	static idVec3_t interpolatedPos;
    876 
    877 	float velocity = getVelocity(t);
    878 	float timePassed = t - lastTime;
    879 	lastTime = t;
    880 
    881 	// convert to seconds	
    882 	timePassed /= 1000;
    883 
    884 	float distToTravel = timePassed *= velocity;
    885 
    886 	idVec3_t temp = startPos;
    887 	temp -= endPos;
    888 	float distance = temp.Length();
    889 
    890 	distSoFar += distToTravel;
    891 	float percent = (float)(distSoFar) / distance;
    892 
    893 	if (percent > 1.0) {
    894 		percent = 1.0;
    895 	} else if (percent < 0.0) {
    896 		percent = 0.0;
    897 	}
    898 
    899 	// the following line does a straigt calc on percentage of time
    900 	// float percent = (float)(startTime + time - t) / time;
    901 
    902 	idVec3_t v1 = startPos;
    903 	idVec3_t v2 = endPos;
    904 	v1 *= (1.0 - percent);
    905 	v2 *= percent;
    906 	v1 += v2;
    907 	interpolatedPos = v1;
    908 	return &interpolatedPos;
    909 }
    910 
    911 
    912 void idCameraFOV::parse(const char *(*text)  ) {
    913 	const char *token;
    914 	Com_MatchToken( text, "{" );
    915 	do {
    916 		token = Com_Parse( text );
    917 	
    918 		if ( !token[0] ) {
    919 			break;
    920 		}
    921 		if ( !strcmp (token, "}") ) {
    922 			break;
    923 		}
    924 
    925 		// here we may have to jump over brush epairs ( only used in editor )
    926 		do {
    927 			// if token is not a brace, it is a key for a key/value pair
    928 			if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
    929 				break;
    930 			}
    931 
    932 			Com_UngetToken();
    933 			idStr key = Com_ParseOnLine(text);
    934 			const char *token = Com_Parse(text);
    935 			if (Q_stricmp(key.c_str(), "fov") == 0) {
    936 				fov = atof(token);
    937 			} else if (Q_stricmp(key.c_str(), "startFOV") == 0) {
    938 				startFOV = atof(token);
    939 			} else if (Q_stricmp(key.c_str(), "endFOV") == 0) {
    940 				endFOV = atof(token);
    941 			} else if (Q_stricmp(key.c_str(), "time") == 0) {
    942 				time = atoi(token);
    943 			}
    944 			token = Com_Parse(text);
    945 
    946 		} while (1);
    947 
    948 		if ( !strcmp (token, "}") ) {
    949 			break;
    950 		}
    951 
    952 	} while (1);
    953  
    954 	Com_UngetToken();
    955 	Com_MatchToken( text, "}" );
    956 }
    957 
    958 bool idCameraPosition::parseToken(const char *key, const char *(*text)) {
    959 	const char *token = Com_Parse(text);
    960 	if (Q_stricmp(key, "time") == 0) {
    961 		time = atol(token);
    962 		return true;
    963 	} else if (Q_stricmp(key, "type") == 0) {
    964 		type = static_cast<idCameraPosition::positionType>(atoi(token));
    965 		return true;
    966 	} else if (Q_stricmp(key, "velocity") == 0) {
    967 		long t = atol(token);
    968 		token = Com_Parse(text);
    969 		long d = atol(token);
    970 		token = Com_Parse(text);
    971 		float s = atof(token);
    972 		addVelocity(t, d, s);
    973 		return true;
    974 	} else if (Q_stricmp(key, "baseVelocity") == 0) {
    975 		baseVelocity = atof(token);
    976 		return true;
    977 	} else if (Q_stricmp(key, "name") == 0) {
    978 		name = token;
    979 		return true;
    980 	} else if (Q_stricmp(key, "time") == 0) {
    981 		time = atoi(token);
    982 		return true;
    983 	}
    984 	Com_UngetToken();
    985 	return false;
    986 }
    987 
    988 
    989 
    990 void idFixedPosition::parse(const char *(*text)  ) {
    991 	const char *token;
    992 	Com_MatchToken( text, "{" );
    993 	do {
    994 		token = Com_Parse( text );
    995 	
    996 		if ( !token[0] ) {
    997 			break;
    998 		}
    999 		if ( !strcmp (token, "}") ) {
   1000 			break;
   1001 		}
   1002 
   1003 		// here we may have to jump over brush epairs ( only used in editor )
   1004 		do {
   1005 			// if token is not a brace, it is a key for a key/value pair
   1006 			if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
   1007 				break;
   1008 			}
   1009 
   1010 			Com_UngetToken();
   1011 			idStr key = Com_ParseOnLine(text);
   1012 			
   1013 			const char *token = Com_Parse(text);
   1014 			if (Q_stricmp(key.c_str(), "pos") == 0) {
   1015 				Com_UngetToken();
   1016 				Com_Parse1DMatrix( text, 3, pos );
   1017 			} else {
   1018 				Com_UngetToken();
   1019 				idCameraPosition::parseToken(key.c_str(), text);	
   1020 			}
   1021 			token = Com_Parse(text);
   1022 
   1023 		} while (1);
   1024 
   1025 		if ( !strcmp (token, "}") ) {
   1026 			break;
   1027 		}
   1028 
   1029 	} while (1);
   1030  
   1031 	Com_UngetToken();
   1032 	Com_MatchToken( text, "}" );
   1033 }
   1034 
   1035 void idInterpolatedPosition::parse(const char *(*text)  ) {
   1036 	const char *token;
   1037 	Com_MatchToken( text, "{" );
   1038 	do {
   1039 		token = Com_Parse( text );
   1040 	
   1041 		if ( !token[0] ) {
   1042 			break;
   1043 		}
   1044 		if ( !strcmp (token, "}") ) {
   1045 			break;
   1046 		}
   1047 
   1048 		// here we may have to jump over brush epairs ( only used in editor )
   1049 		do {
   1050 			// if token is not a brace, it is a key for a key/value pair
   1051 			if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
   1052 				break;
   1053 			}
   1054 
   1055 			Com_UngetToken();
   1056 			idStr key = Com_ParseOnLine(text);
   1057 			
   1058 			const char *token = Com_Parse(text);
   1059 			if (Q_stricmp(key.c_str(), "startPos") == 0) {
   1060 				Com_UngetToken();
   1061 				Com_Parse1DMatrix( text, 3, startPos );
   1062 			} else if (Q_stricmp(key.c_str(), "endPos") == 0) {
   1063 				Com_UngetToken();
   1064 				Com_Parse1DMatrix( text, 3, endPos );
   1065 			} else {
   1066 				Com_UngetToken();
   1067 				idCameraPosition::parseToken(key.c_str(), text);	
   1068 			}
   1069 			token = Com_Parse(text);
   1070 
   1071 		} while (1);
   1072 
   1073 		if ( !strcmp (token, "}") ) {
   1074 			break;
   1075 		}
   1076 
   1077 	} while (1);
   1078  
   1079 	Com_UngetToken();
   1080 	Com_MatchToken( text, "}" );
   1081 }
   1082 
   1083 
   1084 void idSplinePosition::parse(const char *(*text)  ) {
   1085 	const char *token;
   1086 	Com_MatchToken( text, "{" );
   1087 	do {
   1088 		token = Com_Parse( text );
   1089 	
   1090 		if ( !token[0] ) {
   1091 			break;
   1092 		}
   1093 		if ( !strcmp (token, "}") ) {
   1094 			break;
   1095 		}
   1096 
   1097 		// here we may have to jump over brush epairs ( only used in editor )
   1098 		do {
   1099 			// if token is not a brace, it is a key for a key/value pair
   1100 			if ( !token[0] || !strcmp (token, "(") || !strcmp(token, "}")) {
   1101 				break;
   1102 			}
   1103 
   1104 			Com_UngetToken();
   1105 			idStr key = Com_ParseOnLine(text);
   1106 			
   1107 			const char *token = Com_Parse(text);
   1108 			if (Q_stricmp(key.c_str(), "target") == 0) {
   1109 				target.parse(text);
   1110 			} else {
   1111 				Com_UngetToken();
   1112 				idCameraPosition::parseToken(key.c_str(), text);	
   1113 			}
   1114 			token = Com_Parse(text);
   1115 
   1116 		} while (1);
   1117 
   1118 		if ( !strcmp (token, "}") ) {
   1119 			break;
   1120 		}
   1121 
   1122 	} while (1);
   1123  
   1124 	Com_UngetToken();
   1125 	Com_MatchToken( text, "}" );
   1126 }
   1127 
   1128 
   1129 
   1130 void idCameraFOV::write(fileHandle_t file, const char *p) {
   1131 	idStr s = va("\t%s {\n", p);
   1132 	FS_Write(s.c_str(), s.length(), file);
   1133 	
   1134 	s = va("\t\tfov %f\n", fov);
   1135 	FS_Write(s.c_str(), s.length(), file);
   1136 
   1137 	s = va("\t\tstartFOV %f\n", startFOV);
   1138 	FS_Write(s.c_str(), s.length(), file);
   1139 
   1140 	s = va("\t\tendFOV %f\n", endFOV);
   1141 	FS_Write(s.c_str(), s.length(), file);
   1142 
   1143 	s = va("\t\ttime %i\n", time);
   1144 	FS_Write(s.c_str(), s.length(), file);
   1145 
   1146 	s = "\t}\n";
   1147 	FS_Write(s.c_str(), s.length(), file);
   1148 }
   1149 
   1150 
   1151 void idCameraPosition::write(fileHandle_t file, const char *p) {
   1152 	
   1153 	idStr s = va("\t\ttime %i\n", time);
   1154 	FS_Write(s.c_str(), s.length(), file);
   1155 
   1156 	s = va("\t\ttype %i\n", static_cast<int>(type));
   1157 	FS_Write(s.c_str(), s.length(), file);
   1158 
   1159 	s = va("\t\tname %s\n", name.c_str());
   1160 	FS_Write(s.c_str(), s.length(), file);
   1161 
   1162 	s = va("\t\tbaseVelocity %f\n", baseVelocity);
   1163 	FS_Write(s.c_str(), s.length(), file);
   1164 
   1165 	for (int i = 0; i < velocities.Num(); i++) {
   1166 		s = va("\t\tvelocity %i %i %f\n", velocities[i]->startTime, velocities[i]->time, velocities[i]->speed);
   1167 		FS_Write(s.c_str(), s.length(), file);
   1168 	}
   1169 
   1170 }
   1171 
   1172 void idFixedPosition::write(fileHandle_t file, const char *p) {
   1173 	idStr s = va("\t%s {\n", p);
   1174 	FS_Write(s.c_str(), s.length(), file);
   1175 	idCameraPosition::write(file, p);
   1176 	s = va("\t\tpos ( %f %f %f )\n", pos.x, pos.y, pos.z);
   1177 	FS_Write(s.c_str(), s.length(), file);
   1178 	s = "\t}\n";
   1179 	FS_Write(s.c_str(), s.length(), file);
   1180 }
   1181 
   1182 void idInterpolatedPosition::write(fileHandle_t file, const char *p) {
   1183 	idStr s = va("\t%s {\n", p);
   1184 	FS_Write(s.c_str(), s.length(), file);
   1185 	idCameraPosition::write(file, p);
   1186 	s = va("\t\tstartPos ( %f %f %f )\n", startPos.x, startPos.y, startPos.z);
   1187 	FS_Write(s.c_str(), s.length(), file);
   1188 	s = va("\t\tendPos ( %f %f %f )\n", endPos.x, endPos.y, endPos.z);
   1189 	FS_Write(s.c_str(), s.length(), file);
   1190 	s = "\t}\n";
   1191 	FS_Write(s.c_str(), s.length(), file);
   1192 }
   1193 
   1194 void idSplinePosition::write(fileHandle_t file, const char *p) {
   1195 	idStr s = va("\t%s {\n", p);
   1196 	FS_Write(s.c_str(), s.length(), file);
   1197 	idCameraPosition::write(file, p);
   1198 	target.write(file, "target");
   1199 	s = "\t}\n";
   1200 	FS_Write(s.c_str(), s.length(), file);
   1201 }
   1202 
   1203 void idCameraDef::addTarget(const char *name, idCameraPosition::positionType type) {
   1204 	//const char *text = (name == NULL) ? va("target0%d", numTargets()+1) : name; // TTimo: unused
   1205 	idCameraPosition *pos = newFromType(type);
   1206 	if (pos) {
   1207 		pos->setName(name);
   1208 		targetPositions.Append(pos);
   1209 		activeTarget = numTargets()-1;
   1210 		if (activeTarget == 0) {
   1211 			// first one
   1212 			addEvent(idCameraEvent::EVENT_TARGET, name, 0);
   1213 		}
   1214 	}
   1215 }
   1216 
   1217 
   1218 
   1219 idCameraDef camera;
   1220 
   1221 extern "C" {
   1222 qboolean loadCamera(const char *name) {
   1223   camera.clear();
   1224   return static_cast<qboolean>(camera.load(name));
   1225 }
   1226 
   1227 qboolean getCameraInfo(int time, float *origin, float*angles) {
   1228 	idVec3_t dir, org;
   1229 	org[0] = origin[0];
   1230 	org[1] = origin[1];
   1231 	org[2] = origin[2];
   1232 	float fov = 90;
   1233 	if (camera.getCameraInfo(time, org, dir, &fov)) {
   1234 		origin[0] = org[0];
   1235 		origin[1] = org[1];
   1236 		origin[2] = org[2];
   1237 		angles[1] = atan2 (dir[1], dir[0])*180/3.14159;
   1238 		angles[0] = asin (dir[2])*180/3.14159;
   1239 		return qtrue;
   1240 	}
   1241 	return qfalse;
   1242 }
   1243 
   1244 void startCamera(int time) {
   1245 	camera.startCamera(time);
   1246 }
   1247 
   1248 }
   1249 
   1250