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