DeclAF.cpp (46763B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #include "../idlib/precompiled.h" 30 #pragma hdrstop 31 32 /* 33 =============================================================================== 34 35 idDeclAF 36 37 =============================================================================== 38 */ 39 40 /* 41 ================ 42 idAFVector::idAFVector 43 ================ 44 */ 45 idAFVector::idAFVector() { 46 type = VEC_COORDS; 47 vec.Zero(); 48 negate = false; 49 } 50 51 /* 52 ================ 53 idAFVector::Parse 54 ================ 55 */ 56 bool idAFVector::Parse( idLexer &src ) { 57 idToken token; 58 59 if ( !src.ReadToken( &token ) ) { 60 return false; 61 } 62 63 if ( token == "-" ) { 64 negate = true; 65 if ( !src.ReadToken( &token ) ) { 66 return false; 67 } 68 } 69 else { 70 negate = false; 71 } 72 73 if ( token == "(" ) { 74 type = idAFVector::VEC_COORDS; 75 vec.x = src.ParseFloat(); 76 src.ExpectTokenString( "," ); 77 vec.y = src.ParseFloat(); 78 src.ExpectTokenString( "," ); 79 vec.z = src.ParseFloat(); 80 src.ExpectTokenString( ")" ); 81 } 82 else if ( token == "joint" ) { 83 type = idAFVector::VEC_JOINT; 84 src.ExpectTokenString( "(" ); 85 src.ReadToken( &token ); 86 joint1 = token; 87 src.ExpectTokenString( ")" ); 88 } 89 else if ( token == "bonecenter" ) { 90 type = idAFVector::VEC_BONECENTER; 91 src.ExpectTokenString( "(" ); 92 src.ReadToken( &token ); 93 joint1 = token; 94 src.ExpectTokenString( "," ); 95 src.ReadToken( &token ); 96 joint2 = token; 97 src.ExpectTokenString( ")" ); 98 } 99 else if ( token == "bonedir" ) { 100 type = idAFVector::VEC_BONEDIR; 101 src.ExpectTokenString( "(" ); 102 src.ReadToken( &token ); 103 joint1 = token; 104 src.ExpectTokenString( "," ); 105 src.ReadToken( &token ); 106 joint2 = token; 107 src.ExpectTokenString( ")" ); 108 } 109 else { 110 src.Error( "unknown token %s in vector", token.c_str() ); 111 return false; 112 } 113 114 return true; 115 } 116 117 /* 118 ================ 119 idAFVector::Finish 120 ================ 121 */ 122 bool idAFVector::Finish( const char *fileName, const getJointTransform_t GetJointTransform, const idJointMat *frame, void *model ) const { 123 idMat3 axis; 124 idVec3 start, end; 125 126 switch( type ) { 127 case idAFVector::VEC_COORDS: { 128 break; 129 } 130 case idAFVector::VEC_JOINT: { 131 if ( !GetJointTransform( model, frame, joint1, vec, axis ) ) { 132 common->Warning( "invalid joint %s in joint() in '%s'", joint1.c_str(), fileName ); 133 vec.Zero(); 134 } 135 break; 136 } 137 case idAFVector::VEC_BONECENTER: { 138 if ( !GetJointTransform( model, frame, joint1, start, axis ) ) { 139 common->Warning( "invalid joint %s in bonecenter() in '%s'", joint1.c_str(), fileName ); 140 start.Zero(); 141 } 142 if ( !GetJointTransform( model, frame, joint2, end, axis ) ) { 143 common->Warning( "invalid joint %s in bonecenter() in '%s'", joint2.c_str(), fileName ); 144 end.Zero(); 145 } 146 vec = ( start + end ) * 0.5f; 147 break; 148 } 149 case idAFVector::VEC_BONEDIR: { 150 if ( !GetJointTransform( model, frame, joint1, start, axis ) ) { 151 common->Warning( "invalid joint %s in bonedir() in '%s'", joint1.c_str(), fileName ); 152 start.Zero(); 153 } 154 if ( !GetJointTransform( model, frame, joint2, end, axis ) ) { 155 common->Warning( "invalid joint %s in bonedir() in '%s'", joint2.c_str(), fileName ); 156 end.Zero(); 157 } 158 vec = ( end - start ); 159 break; 160 } 161 default: { 162 vec.Zero(); 163 break; 164 } 165 } 166 167 if ( negate ) { 168 vec = -vec; 169 } 170 171 return true; 172 } 173 174 /* 175 ================ 176 idAFVector::Write 177 ================ 178 */ 179 bool idAFVector::Write( idFile *f ) const { 180 181 if ( negate ) { 182 f->WriteFloatString( "-" ); 183 } 184 switch( type ) { 185 case idAFVector::VEC_COORDS: { 186 f->WriteFloatString( "( %f, %f, %f )", vec.x, vec.y, vec.z ); 187 break; 188 } 189 case idAFVector::VEC_JOINT: { 190 f->WriteFloatString( "joint( \"%s\" )", joint1.c_str() ); 191 break; 192 } 193 case idAFVector::VEC_BONECENTER: { 194 f->WriteFloatString( "bonecenter( \"%s\", \"%s\" )", joint1.c_str(), joint2.c_str() ); 195 break; 196 } 197 case idAFVector::VEC_BONEDIR: { 198 f->WriteFloatString( "bonedir( \"%s\", \"%s\" )", joint1.c_str(), joint2.c_str() ); 199 break; 200 } 201 default: { 202 break; 203 } 204 } 205 return true; 206 } 207 208 /* 209 ================ 210 idAFVector::ToString 211 ================ 212 */ 213 const char *idAFVector::ToString( idStr &str, const int precision ) { 214 215 switch( type ) { 216 case idAFVector::VEC_COORDS: { 217 char format[128]; 218 sprintf( format, "( %%.%df, %%.%df, %%.%df )", precision, precision, precision ); 219 sprintf( str, format, vec.x, vec.y, vec.z ); 220 break; 221 } 222 case idAFVector::VEC_JOINT: { 223 sprintf( str, "joint( \"%s\" )", joint1.c_str() ); 224 break; 225 } 226 case idAFVector::VEC_BONECENTER: { 227 sprintf( str, "bonecenter( \"%s\", \"%s\" )", joint1.c_str(), joint2.c_str() ); 228 break; 229 } 230 case idAFVector::VEC_BONEDIR: { 231 sprintf( str, "bonedir( \"%s\", \"%s\" )", joint1.c_str(), joint2.c_str() ); 232 break; 233 } 234 default: { 235 break; 236 } 237 } 238 if ( negate ) { 239 str = "-" + str; 240 } 241 return str.c_str(); 242 } 243 244 /* 245 ================ 246 idDeclAF_Body::SetDefault 247 ================ 248 */ 249 void idDeclAF_Body::SetDefault( const idDeclAF *file ) { 250 name = "noname"; 251 modelType = TRM_BOX; 252 v1.type = idAFVector::VEC_COORDS; 253 v1.ToVec3().x = v1.ToVec3().y = v1.ToVec3().z = -10.0f; 254 v2.type = idAFVector::VEC_COORDS; 255 v2.ToVec3().x = v2.ToVec3().y = v2.ToVec3().z = 10.0f; 256 numSides = 3; 257 origin.ToVec3().Zero(); 258 angles.Zero(); 259 density = 0.2f; 260 inertiaScale.Identity(); 261 linearFriction = file->defaultLinearFriction; 262 angularFriction = file->defaultAngularFriction; 263 contactFriction = file->defaultContactFriction; 264 contents = file->contents; 265 clipMask = file->clipMask; 266 selfCollision = file->selfCollision; 267 frictionDirection.ToVec3().Zero(); 268 contactMotorDirection.ToVec3().Zero(); 269 jointName = "origin"; 270 jointMod = DECLAF_JOINTMOD_AXIS; 271 containedJoints = "*origin"; 272 } 273 274 /* 275 ================ 276 idDeclAF_Constraint::SetDefault 277 ================ 278 */ 279 void idDeclAF_Constraint::SetDefault( const idDeclAF *file ) { 280 name = "noname"; 281 type = DECLAF_CONSTRAINT_UNIVERSALJOINT; 282 if ( file->bodies.Num() ) { 283 body1 = file->bodies[0]->name; 284 } 285 else { 286 body1 = "world"; 287 } 288 body2 = "world"; 289 friction = file->defaultConstraintFriction; 290 anchor.ToVec3().Zero(); 291 anchor2.ToVec3().Zero(); 292 axis.ToVec3().Set( 1.0f, 0.0f, 0.0f ); 293 shaft[0].ToVec3().Set( 0.0f, 0.0f, -1.0f ); 294 shaft[1].ToVec3().Set( 0.0f, 0.0f, 1.0f ); 295 limit = idDeclAF_Constraint::LIMIT_NONE; 296 limitAngles[0] = 297 limitAngles[1] = 298 limitAngles[2] = 0.0f; 299 limitAxis.ToVec3().Set( 0.0f, 0.0f, -1.0f ); 300 } 301 302 /* 303 ================ 304 idDeclAF::WriteBody 305 ================ 306 */ 307 bool idDeclAF::WriteBody( idFile *f, const idDeclAF_Body &body ) const { 308 idStr str; 309 310 f->WriteFloatString( "\nbody \"%s\" {\n", body.name.c_str() ); 311 f->WriteFloatString( "\tjoint \"%s\"\n", body.jointName.c_str() ); 312 f->WriteFloatString( "\tmod %s\n", JointModToString( body.jointMod ) ); 313 switch( body.modelType ) { 314 case TRM_BOX: { 315 f->WriteFloatString( "\tmodel box( " ); 316 body.v1.Write( f ); 317 f->WriteFloatString( ", " ); 318 body.v2.Write( f ); 319 f->WriteFloatString( " )\n" ); 320 break; 321 } 322 case TRM_OCTAHEDRON: { 323 f->WriteFloatString( "\tmodel octahedron( " ); 324 body.v1.Write( f ); 325 f->WriteFloatString( ", " ); 326 body.v2.Write( f ); 327 f->WriteFloatString( " )\n" ); 328 break; 329 } 330 case TRM_DODECAHEDRON: { 331 f->WriteFloatString( "\tmodel dodecahedron( " ); 332 body.v1.Write( f ); 333 f->WriteFloatString( ", " ); 334 body.v2.Write( f ); 335 f->WriteFloatString( " )\n" ); 336 break; 337 } 338 case TRM_CYLINDER: { 339 f->WriteFloatString( "\tmodel cylinder( " ); 340 body.v1.Write( f ); 341 f->WriteFloatString( ", " ); 342 body.v2.Write( f ); 343 f->WriteFloatString( ", %d )\n", body.numSides ); 344 break; 345 } 346 case TRM_CONE: { 347 f->WriteFloatString( "\tmodel cone( " ); 348 body.v1.Write( f ); 349 f->WriteFloatString( ", " ); 350 body.v2.Write( f ); 351 f->WriteFloatString( ", %d )\n", body.numSides ); 352 break; 353 } 354 case TRM_BONE: { 355 f->WriteFloatString( "\tmodel bone( " ); 356 body.v1.Write( f ); 357 f->WriteFloatString( ", " ); 358 body.v2.Write( f ); 359 f->WriteFloatString( ", %f )\n", body.width ); 360 break; 361 } 362 default: 363 assert( 0 ); 364 break; 365 } 366 f->WriteFloatString( "\torigin " ); 367 body.origin.Write( f ); 368 f->WriteFloatString( "\n" ); 369 if ( body.angles != ang_zero ) { 370 f->WriteFloatString( "\tangles ( %f, %f, %f )\n", body.angles.pitch, body.angles.yaw, body.angles.roll ); 371 } 372 f->WriteFloatString( "\tdensity %f\n", body.density ); 373 if ( body.inertiaScale != mat3_identity ) { 374 const idMat3 &ic = body.inertiaScale; 375 f->WriteFloatString( "\tinertiaScale (%f %f %f %f %f %f %f %f %f)\n", 376 ic[0][0], ic[0][1], ic[0][2], 377 ic[1][0], ic[1][1], ic[1][2], 378 ic[2][0], ic[2][1], ic[2][2] ); 379 } 380 if ( body.linearFriction != -1 ) { 381 f->WriteFloatString( "\tfriction %f, %f, %f\n", body.linearFriction, body.angularFriction, body.contactFriction ); 382 } 383 f->WriteFloatString( "\tcontents %s\n", ContentsToString( body.contents, str ) ); 384 f->WriteFloatString( "\tclipMask %s\n", ContentsToString( body.clipMask, str ) ); 385 f->WriteFloatString( "\tselfCollision %d\n", body.selfCollision ); 386 if ( body.frictionDirection.ToVec3() != vec3_origin ) { 387 f->WriteFloatString( "\tfrictionDirection " ); 388 body.frictionDirection.Write( f ); 389 f->WriteFloatString( "\n" ); 390 } 391 if ( body.contactMotorDirection.ToVec3() != vec3_origin ) { 392 f->WriteFloatString( "\tcontactMotorDirection " ); 393 body.contactMotorDirection.Write( f ); 394 f->WriteFloatString( "\n" ); 395 } 396 f->WriteFloatString( "\tcontainedJoints \"%s\"\n", body.containedJoints.c_str() ); 397 f->WriteFloatString( "}\n" ); 398 return true; 399 } 400 401 /* 402 ================ 403 idDeclAF::WriteFixed 404 ================ 405 */ 406 bool idDeclAF::WriteFixed( idFile *f, const idDeclAF_Constraint &c ) const { 407 f->WriteFloatString( "\nfixed \"%s\" {\n", c.name.c_str() ); 408 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 409 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 410 f->WriteFloatString( "}\n" ); 411 return true; 412 } 413 414 /* 415 ================ 416 idDeclAF::WriteBallAndSocketJoint 417 ================ 418 */ 419 bool idDeclAF::WriteBallAndSocketJoint( idFile *f, const idDeclAF_Constraint &c ) const { 420 f->WriteFloatString( "\nballAndSocketJoint \"%s\" {\n", c.name.c_str() ); 421 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 422 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 423 f->WriteFloatString( "\tanchor " ); 424 c.anchor.Write( f ); 425 f->WriteFloatString( "\n" ); 426 f->WriteFloatString( "\tfriction %f\n", c.friction ); 427 if ( c.limit == idDeclAF_Constraint::LIMIT_CONE ) { 428 f->WriteFloatString( "\tconeLimit " ); 429 c.limitAxis.Write( f ); 430 f->WriteFloatString( ", %f, ", c.limitAngles[0] ); 431 c.shaft[0].Write( f ); 432 f->WriteFloatString( "\n" ); 433 } 434 else if ( c.limit == idDeclAF_Constraint::LIMIT_PYRAMID ) { 435 f->WriteFloatString( "\tpyramidLimit " ); 436 c.limitAxis.Write( f ); 437 f->WriteFloatString( ", %f, %f, %f, ", c.limitAngles[0], c.limitAngles[1], c.limitAngles[2] ); 438 c.shaft[0].Write( f ); 439 f->WriteFloatString( "\n" ); 440 } 441 f->WriteFloatString( "}\n" ); 442 return true; 443 } 444 445 /* 446 ================ 447 idDeclAF::WriteUniversalJoint 448 ================ 449 */ 450 bool idDeclAF::WriteUniversalJoint( idFile *f, const idDeclAF_Constraint &c ) const { 451 f->WriteFloatString( "\nuniversalJoint \"%s\" {\n", c.name.c_str() ); 452 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 453 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 454 f->WriteFloatString( "\tanchor " ); 455 c.anchor.Write( f ); 456 f->WriteFloatString( "\n" ); 457 f->WriteFloatString( "\tshafts " ); 458 c.shaft[0].Write( f ); 459 f->WriteFloatString( ", " ); 460 c.shaft[1].Write( f ); 461 f->WriteFloatString( "\n" ); 462 f->WriteFloatString( "\tfriction %f\n", c.friction ); 463 if ( c.limit == idDeclAF_Constraint::LIMIT_CONE ) { 464 f->WriteFloatString( "\tconeLimit " ); 465 c.limitAxis.Write( f ); 466 f->WriteFloatString( ", %f\n", c.limitAngles[0] ); 467 } 468 else if ( c.limit == idDeclAF_Constraint::LIMIT_PYRAMID ) { 469 f->WriteFloatString( "\tpyramidLimit " ); 470 c.limitAxis.Write( f ); 471 f->WriteFloatString( ", %f, %f, %f\n", c.limitAngles[0], c.limitAngles[1], c.limitAngles[2] ); 472 } 473 f->WriteFloatString( "}\n" ); 474 return true; 475 } 476 477 /* 478 ================ 479 idDeclAF::WriteHinge 480 ================ 481 */ 482 bool idDeclAF::WriteHinge( idFile *f, const idDeclAF_Constraint &c ) const { 483 f->WriteFloatString( "\nhinge \"%s\" {\n", c.name.c_str() ); 484 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 485 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 486 f->WriteFloatString( "\tanchor " ); 487 c.anchor.Write( f ); 488 f->WriteFloatString( "\n" ); 489 f->WriteFloatString( "\taxis " ); 490 c.axis.Write( f ); 491 f->WriteFloatString( "\n" ); 492 f->WriteFloatString( "\tfriction %f\n", c.friction ); 493 if ( c.limit == idDeclAF_Constraint::LIMIT_CONE ) { 494 f->WriteFloatString( "\tlimit " ); 495 f->WriteFloatString( "%f, %f, %f", c.limitAngles[0], c.limitAngles[1], c.limitAngles[2] ); 496 f->WriteFloatString( "\n" ); 497 } 498 f->WriteFloatString( "}\n" ); 499 return true; 500 } 501 502 /* 503 ================ 504 idDeclAF::WriteSlider 505 ================ 506 */ 507 bool idDeclAF::WriteSlider( idFile *f, const idDeclAF_Constraint &c ) const { 508 f->WriteFloatString( "\nslider \"%s\" {\n", c.name.c_str() ); 509 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 510 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 511 f->WriteFloatString( "\taxis " ); 512 c.axis.Write( f ); 513 f->WriteFloatString( "\n" ); 514 f->WriteFloatString( "\tfriction %f\n", c.friction ); 515 f->WriteFloatString( "}\n" ); 516 return true; 517 } 518 519 /* 520 ================ 521 idDeclAF::WriteSpring 522 ================ 523 */ 524 bool idDeclAF::WriteSpring( idFile *f, const idDeclAF_Constraint &c ) const { 525 f->WriteFloatString( "\nspring \"%s\" {\n", c.name.c_str() ); 526 f->WriteFloatString( "\tbody1 \"%s\"\n", c.body1.c_str() ); 527 f->WriteFloatString( "\tbody2 \"%s\"\n", c.body2.c_str() ); 528 f->WriteFloatString( "\tanchor1 " ); 529 c.anchor.Write( f ); 530 f->WriteFloatString( "\n" ); 531 f->WriteFloatString( "\tanchor2 " ); 532 c.anchor2.Write( f ); 533 f->WriteFloatString( "\n" ); 534 f->WriteFloatString( "\tfriction %f\n", c.friction ); 535 f->WriteFloatString( "\tstretch %f\n", c.stretch ); 536 f->WriteFloatString( "\tcompress %f\n", c.compress ); 537 f->WriteFloatString( "\tdamping %f\n", c.damping ); 538 f->WriteFloatString( "\trestLength %f\n", c.restLength ); 539 f->WriteFloatString( "\tminLength %f\n", c.minLength ); 540 f->WriteFloatString( "\tmaxLength %f\n", c.maxLength ); 541 f->WriteFloatString( "}\n" ); 542 return true; 543 } 544 545 /* 546 ================ 547 idDeclAF::WriteConstraint 548 ================ 549 */ 550 bool idDeclAF::WriteConstraint( idFile *f, const idDeclAF_Constraint &c ) const { 551 switch( c.type ) { 552 case DECLAF_CONSTRAINT_FIXED: 553 return WriteFixed( f, c ); 554 case DECLAF_CONSTRAINT_BALLANDSOCKETJOINT: 555 return WriteBallAndSocketJoint( f, c ); 556 case DECLAF_CONSTRAINT_UNIVERSALJOINT: 557 return WriteUniversalJoint( f, c ); 558 case DECLAF_CONSTRAINT_HINGE: 559 return WriteHinge( f, c ); 560 case DECLAF_CONSTRAINT_SLIDER: 561 return WriteSlider( f, c ); 562 case DECLAF_CONSTRAINT_SPRING: 563 return WriteSpring( f, c ); 564 default: 565 break; 566 } 567 return false; 568 } 569 570 /* 571 ================ 572 idDeclAF::WriteSettings 573 ================ 574 */ 575 bool idDeclAF::WriteSettings( idFile *f ) const { 576 idStr str; 577 578 f->WriteFloatString( "\nsettings {\n" ); 579 f->WriteFloatString( "\tmodel \"%s\"\n", model.c_str() ); 580 f->WriteFloatString( "\tskin \"%s\"\n", skin.c_str() ); 581 f->WriteFloatString( "\tfriction %f, %f, %f, %f\n", defaultLinearFriction, defaultAngularFriction, defaultContactFriction, defaultConstraintFriction ); 582 f->WriteFloatString( "\tsuspendSpeed %f, %f, %f, %f\n", suspendVelocity[0], suspendVelocity[1], suspendAcceleration[0], suspendAcceleration[1] ); 583 f->WriteFloatString( "\tnoMoveTime %f\n", noMoveTime ); 584 f->WriteFloatString( "\tnoMoveTranslation %f\n", noMoveTranslation ); 585 f->WriteFloatString( "\tnoMoveRotation %f\n", noMoveRotation ); 586 f->WriteFloatString( "\tminMoveTime %f\n", minMoveTime ); 587 f->WriteFloatString( "\tmaxMoveTime %f\n", maxMoveTime ); 588 f->WriteFloatString( "\ttotalMass %f\n", totalMass ); 589 f->WriteFloatString( "\tcontents %s\n", ContentsToString( contents, str ) ); 590 f->WriteFloatString( "\tclipMask %s\n", ContentsToString( clipMask, str ) ); 591 f->WriteFloatString( "\tselfCollision %d\n", selfCollision ); 592 f->WriteFloatString( "}\n" ); 593 return true; 594 } 595 596 597 /* 598 ================ 599 idDeclAF::RebuildTextSource 600 ================ 601 */ 602 bool idDeclAF::RebuildTextSource() { 603 int i; 604 idFile_Memory f; 605 606 f.WriteFloatString("\n\n/*\n" 607 "\tGenerated by the Articulated Figure Editor.\n" 608 "\tDo not edit directly but launch the game and type 'editAFs' on the console.\n" 609 "*/\n" ); 610 611 f.WriteFloatString( "\narticulatedFigure %s {\n", GetName() ); 612 613 if ( !WriteSettings( &f ) ) { 614 return false; 615 } 616 617 for ( i = 0; i < bodies.Num(); i++ ) { 618 if ( !WriteBody( &f, *bodies[i] ) ) { 619 return false; 620 } 621 } 622 623 for ( i = 0; i < constraints.Num(); i++ ) { 624 if ( !WriteConstraint( &f, *constraints[i] ) ) { 625 return false; 626 } 627 } 628 629 f.WriteFloatString( "\n}" ); 630 631 SetText( f.GetDataPtr() ); 632 633 return true; 634 } 635 636 /* 637 ================ 638 idDeclAF::Save 639 ================ 640 */ 641 bool idDeclAF::Save() { 642 RebuildTextSource(); 643 ReplaceSourceFileText(); 644 modified = false; 645 return true; 646 } 647 648 /* 649 ================ 650 idDeclAF::ContentsFromString 651 ================ 652 */ 653 int idDeclAF::ContentsFromString( const char *str ) { 654 int c; 655 idToken token; 656 idLexer src( str, idStr::Length( str ), "idDeclAF::ContentsFromString" ); 657 658 c = 0; 659 while( src.ReadToken( &token ) ) { 660 if ( token.Icmp( "none" ) == 0 ) { 661 c = 0; 662 } 663 else if ( token.Icmp( "solid" ) == 0 ) { 664 c |= CONTENTS_SOLID; 665 } 666 else if ( token.Icmp( "body" ) == 0 ) { 667 c |= CONTENTS_BODY; 668 } 669 else if ( token.Icmp( "corpse" ) == 0 ) { 670 c |= CONTENTS_CORPSE; 671 } 672 else if ( token.Icmp( "playerclip" ) == 0 ) { 673 c |= CONTENTS_PLAYERCLIP; 674 } 675 else if ( token.Icmp( "monsterclip" ) == 0 ) { 676 c |= CONTENTS_MONSTERCLIP; 677 } 678 else if ( token == "," ) { 679 continue; 680 } 681 else { 682 return c; 683 } 684 } 685 return c; 686 } 687 688 /* 689 ================ 690 idDeclAF::ContentsToString 691 ================ 692 */ 693 const char *idDeclAF::ContentsToString( const int contents, idStr &str ) { 694 str = ""; 695 if ( contents & CONTENTS_SOLID ) { 696 if ( str.Length() ) str += ", "; 697 str += "solid"; 698 } 699 if ( contents & CONTENTS_BODY ) { 700 if ( str.Length() ) str += ", "; 701 str += "body"; 702 } 703 if ( contents & CONTENTS_CORPSE ) { 704 if ( str.Length() ) str += ", "; 705 str += "corpse"; 706 } 707 if ( contents & CONTENTS_PLAYERCLIP ) { 708 if ( str.Length() ) str += ", "; 709 str += "playerclip"; 710 } 711 if ( contents & CONTENTS_MONSTERCLIP ) { 712 if ( str.Length() ) str += ", "; 713 str += "monsterclip"; 714 } 715 if ( str[0] == '\0' ) { 716 str = "none"; 717 } 718 return str.c_str(); 719 } 720 721 /* 722 ================ 723 idDeclAF::JointModFromString 724 ================ 725 */ 726 declAFJointMod_t idDeclAF::JointModFromString( const char *str ) { 727 if ( idStr::Icmp( str, "orientation" ) == 0 ) { 728 return DECLAF_JOINTMOD_AXIS; 729 } 730 if ( idStr::Icmp( str, "position" ) == 0 ) { 731 return DECLAF_JOINTMOD_ORIGIN; 732 } 733 if ( idStr::Icmp( str, "both" ) == 0 ) { 734 return DECLAF_JOINTMOD_BOTH; 735 } 736 return DECLAF_JOINTMOD_AXIS; 737 } 738 739 /* 740 ================ 741 idDeclAF::JointModToString 742 ================ 743 */ 744 const char * idDeclAF::JointModToString( declAFJointMod_t jointMod ) { 745 switch( jointMod ) { 746 case DECLAF_JOINTMOD_AXIS: { 747 return "orientation"; 748 } 749 case DECLAF_JOINTMOD_ORIGIN: { 750 return "position"; 751 } 752 case DECLAF_JOINTMOD_BOTH: { 753 return "both"; 754 } 755 } 756 return "orientation"; 757 } 758 759 /* 760 ================= 761 idDeclAF::Size 762 ================= 763 */ 764 size_t idDeclAF::Size() const { 765 return sizeof( idDeclAF ); 766 } 767 768 /* 769 ================ 770 idDeclAF::ParseContents 771 ================ 772 */ 773 bool idDeclAF::ParseContents( idLexer &src, int &c ) const { 774 idToken token; 775 idStr str; 776 777 while( src.ReadToken( &token ) ) { 778 str += token; 779 if ( !src.CheckTokenString( "," ) ) { 780 break; 781 } 782 str += ","; 783 } 784 c = ContentsFromString( str ); 785 return true; 786 } 787 788 /* 789 ================ 790 idDeclAF::ParseBody 791 ================ 792 */ 793 bool idDeclAF::ParseBody( idLexer &src ) { 794 bool hasJoint = false; 795 idToken token; 796 idAFVector angles; 797 idDeclAF_Body *body = new (TAG_DECL) idDeclAF_Body; 798 799 bodies.Alloc() = body; 800 801 body->SetDefault( this ); 802 803 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 804 !src.ExpectTokenString( "{" ) ) { 805 return false; 806 } 807 808 body->name = token; 809 if ( !body->name.Icmp( "origin" ) || !body->name.Icmp( "world" ) ) { 810 src.Error( "a body may not be named \"origin\" or \"world\"" ); 811 return false; 812 } 813 814 while( src.ReadToken( &token ) ) { 815 816 if ( !token.Icmp( "model" ) ) { 817 if ( !src.ExpectTokenType( TT_NAME, 0, &token ) ) { 818 return false; 819 } 820 if ( !token.Icmp( "box" ) ) { 821 body->modelType = TRM_BOX; 822 if ( !src.ExpectTokenString( "(" ) || 823 !body->v1.Parse( src ) || 824 !src.ExpectTokenString( "," ) || 825 !body->v2.Parse( src ) || 826 !src.ExpectTokenString( ")" ) ) { 827 return false; 828 } 829 } else if ( !token.Icmp( "octahedron" ) ) { 830 body->modelType = TRM_OCTAHEDRON; 831 if ( !src.ExpectTokenString( "(" ) || 832 !body->v1.Parse( src ) || 833 !src.ExpectTokenString( "," ) || 834 !body->v2.Parse( src ) || 835 !src.ExpectTokenString( ")" ) ) { 836 return false; 837 } 838 } else if ( !token.Icmp( "dodecahedron" ) ) { 839 body->modelType = TRM_DODECAHEDRON; 840 if ( !src.ExpectTokenString( "(" ) || 841 !body->v1.Parse( src ) || 842 !src.ExpectTokenString( "," ) || 843 !body->v2.Parse( src ) || 844 !src.ExpectTokenString( ")" ) ) { 845 return false; 846 } 847 } else if ( !token.Icmp( "cylinder" ) ) { 848 body->modelType = TRM_CYLINDER; 849 if ( !src.ExpectTokenString( "(" ) || 850 !body->v1.Parse( src ) || 851 !src.ExpectTokenString( "," ) || 852 !body->v2.Parse( src ) || 853 !src.ExpectTokenString( "," ) ) { 854 return false; 855 } 856 body->numSides = src.ParseInt(); 857 if ( !src.ExpectTokenString( ")" ) ) { 858 return false; 859 } 860 } else if ( !token.Icmp( "cone" ) ) { 861 body->modelType = TRM_CONE; 862 if ( !src.ExpectTokenString( "(" ) || 863 !body->v1.Parse( src ) || 864 !src.ExpectTokenString( "," ) || 865 !body->v2.Parse( src ) || 866 !src.ExpectTokenString( "," ) ) { 867 return false; 868 } 869 body->numSides = src.ParseInt(); 870 if ( !src.ExpectTokenString( ")" ) ) { 871 return false; 872 } 873 } else if ( !token.Icmp( "bone" ) ) { 874 body->modelType = TRM_BONE; 875 if ( !src.ExpectTokenString( "(" ) || 876 !body->v1.Parse( src ) || 877 !src.ExpectTokenString( "," ) || 878 !body->v2.Parse( src ) || 879 !src.ExpectTokenString( "," ) ) { 880 return false; 881 } 882 body->width = src.ParseFloat(); 883 if ( !src.ExpectTokenString( ")" ) ) { 884 return false; 885 } 886 } else if ( !token.Icmp( "custom" ) ) { 887 src.Error( "custom models not yet implemented" ); 888 return false; 889 } else { 890 src.Error( "unkown model type %s", token.c_str() ); 891 return false; 892 } 893 } else if ( !token.Icmp( "origin" ) ) { 894 if ( !body->origin.Parse( src ) ) { 895 return false; 896 } 897 } else if ( !token.Icmp( "angles" ) ) { 898 if ( !angles.Parse( src ) ) { 899 return false; 900 } 901 body->angles = idAngles( angles.ToVec3().x, angles.ToVec3().y, angles.ToVec3().z ); 902 } else if ( !token.Icmp( "joint" ) ) { 903 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 904 return false; 905 } 906 body->jointName = token; 907 hasJoint = true; 908 } else if ( !token.Icmp( "mod" ) ) { 909 if ( !src.ExpectAnyToken( &token ) ) { 910 return false; 911 } 912 body->jointMod = JointModFromString( token.c_str() ); 913 } else if ( !token.Icmp( "density" ) ) { 914 body->density = src.ParseFloat(); 915 } else if ( !token.Icmp( "inertiaScale" ) ) { 916 src.Parse1DMatrix( 9, body->inertiaScale[0].ToFloatPtr() ); 917 } else if ( !token.Icmp( "friction" ) ) { 918 body->linearFriction = src.ParseFloat(); 919 src.ExpectTokenString( "," ); 920 body->angularFriction = src.ParseFloat(); 921 src.ExpectTokenString( "," ); 922 body->contactFriction = src.ParseFloat(); 923 } else if ( !token.Icmp( "contents" ) ) { 924 ParseContents( src, body->contents ); 925 } else if ( !token.Icmp( "clipMask" ) ) { 926 ParseContents( src, body->clipMask ); 927 body->clipMask &= ~CONTENTS_CORPSE; // never allow collisions against corpses 928 } else if ( !token.Icmp( "selfCollision" ) ) { 929 body->selfCollision = src.ParseBool(); 930 } else if ( !token.Icmp( "containedjoints" ) ) { 931 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 932 return false; 933 } 934 body->containedJoints = token; 935 } else if ( !token.Icmp( "frictionDirection" ) ) { 936 if ( !body->frictionDirection.Parse( src ) ) { 937 return false; 938 } 939 } else if ( !token.Icmp( "contactMotorDirection" ) ) { 940 if ( !body->contactMotorDirection.Parse( src ) ) { 941 return false; 942 } 943 } else if ( token == "}" ) { 944 break; 945 } else { 946 src.Error( "unknown token %s in body", token.c_str() ); 947 return false; 948 } 949 } 950 951 if ( body->modelType == TRM_INVALID ) { 952 src.Error( "no model set for body" ); 953 return false; 954 } 955 956 if ( !hasJoint ) { 957 src.Error( "no joint set for body" ); 958 return false; 959 } 960 961 body->clipMask |= CONTENTS_MOVEABLECLIP; 962 963 return true; 964 } 965 966 /* 967 ================ 968 idDeclAF::ParseFixed 969 ================ 970 */ 971 bool idDeclAF::ParseFixed( idLexer &src ) { 972 idToken token; 973 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 974 975 constraint->SetDefault( this ); 976 constraints.Alloc() = constraint; 977 978 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 979 !src.ExpectTokenString( "{" ) ) { 980 return false; 981 } 982 983 constraint->type = DECLAF_CONSTRAINT_FIXED; 984 constraint->name = token; 985 986 while( src.ReadToken( &token ) ) { 987 988 if ( !token.Icmp( "body1" ) ) { 989 src.ExpectTokenType( TT_STRING, 0, &token ); 990 constraint->body1 = token; 991 } else if ( !token.Icmp( "body2" ) ) { 992 src.ExpectTokenType( TT_STRING, 0, &token ); 993 constraint->body2 = token; 994 } else if ( token == "}" ) { 995 break; 996 } else { 997 src.Error( "unknown token %s in ball and socket joint", token.c_str() ); 998 return false; 999 } 1000 } 1001 1002 return true; 1003 } 1004 1005 /* 1006 ================ 1007 idDeclAF::ParseBallAndSocketJoint 1008 ================ 1009 */ 1010 bool idDeclAF::ParseBallAndSocketJoint( idLexer &src ) { 1011 idToken token; 1012 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 1013 1014 constraint->SetDefault( this ); 1015 constraints.Alloc() = constraint; 1016 1017 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 1018 !src.ExpectTokenString( "{" ) ) { 1019 return false; 1020 } 1021 1022 constraint->type = DECLAF_CONSTRAINT_BALLANDSOCKETJOINT; 1023 constraint->limit = idDeclAF_Constraint::LIMIT_NONE; 1024 constraint->name = token; 1025 constraint->friction = 0.5f; 1026 constraint->anchor.ToVec3().Zero(); 1027 constraint->shaft[0].ToVec3().Zero(); 1028 1029 while( src.ReadToken( &token ) ) { 1030 1031 if ( !token.Icmp( "body1" ) ) { 1032 src.ExpectTokenType( TT_STRING, 0, &token ); 1033 constraint->body1 = token; 1034 } else if ( !token.Icmp( "body2" ) ) { 1035 src.ExpectTokenType( TT_STRING, 0, &token ); 1036 constraint->body2 = token; 1037 } else if ( !token.Icmp( "anchor" ) ) { 1038 if ( !constraint->anchor.Parse( src ) ) { 1039 return false; 1040 } 1041 } else if ( !token.Icmp( "conelimit" ) ) { 1042 if ( !constraint->limitAxis.Parse( src ) || 1043 !src.ExpectTokenString( "," ) ) { 1044 return false; 1045 } 1046 constraint->limitAngles[0] = src.ParseFloat(); 1047 if ( !src.ExpectTokenString( "," ) || 1048 !constraint->shaft[0].Parse( src ) ) { 1049 return false; 1050 } 1051 constraint->limit = idDeclAF_Constraint::LIMIT_CONE; 1052 } else if ( !token.Icmp( "pyramidlimit" ) ) { 1053 if ( !constraint->limitAxis.Parse( src ) || 1054 !src.ExpectTokenString( "," ) ) { 1055 return false; 1056 } 1057 constraint->limitAngles[0] = src.ParseFloat(); 1058 if ( !src.ExpectTokenString( "," ) ) { 1059 return false; 1060 } 1061 constraint->limitAngles[1] = src.ParseFloat(); 1062 if ( !src.ExpectTokenString( "," ) ) { 1063 return false; 1064 } 1065 constraint->limitAngles[2] = src.ParseFloat(); 1066 if ( !src.ExpectTokenString( "," ) || 1067 !constraint->shaft[0].Parse( src ) ) { 1068 return false; 1069 } 1070 constraint->limit = idDeclAF_Constraint::LIMIT_PYRAMID; 1071 } else if ( !token.Icmp( "friction" ) ) { 1072 constraint->friction = src.ParseFloat(); 1073 } else if ( token == "}" ) { 1074 break; 1075 } else { 1076 src.Error( "unknown token %s in ball and socket joint", token.c_str() ); 1077 return false; 1078 } 1079 } 1080 1081 return true; 1082 } 1083 1084 /* 1085 ================ 1086 idDeclAF::ParseUniversalJoint 1087 ================ 1088 */ 1089 bool idDeclAF::ParseUniversalJoint( idLexer &src ) { 1090 idToken token; 1091 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 1092 1093 constraint->SetDefault( this ); 1094 constraints.Alloc() = constraint; 1095 1096 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 1097 !src.ExpectTokenString( "{" ) ) { 1098 return false; 1099 } 1100 1101 constraint->type = DECLAF_CONSTRAINT_UNIVERSALJOINT; 1102 constraint->limit = idDeclAF_Constraint::LIMIT_NONE; 1103 constraint->name = token; 1104 constraint->friction = 0.5f; 1105 constraint->anchor.ToVec3().Zero(); 1106 constraint->shaft[0].ToVec3().Zero(); 1107 constraint->shaft[1].ToVec3().Zero(); 1108 1109 while( src.ReadToken( &token ) ) { 1110 1111 if ( !token.Icmp( "body1" ) ) { 1112 src.ExpectTokenType( TT_STRING, 0, &token ); 1113 constraint->body1 = token; 1114 } else if ( !token.Icmp( "body2" ) ) { 1115 src.ExpectTokenType( TT_STRING, 0, &token ); 1116 constraint->body2 = token; 1117 } else if ( !token.Icmp( "anchor" ) ) { 1118 if ( !constraint->anchor.Parse( src ) ) { 1119 return false; 1120 } 1121 } else if ( !token.Icmp( "shafts" ) ) { 1122 if ( !constraint->shaft[0].Parse( src ) || 1123 !src.ExpectTokenString( "," ) || 1124 !constraint->shaft[1].Parse( src ) ) { 1125 return false; 1126 } 1127 } else if ( !token.Icmp( "conelimit" ) ) { 1128 if ( !constraint->limitAxis.Parse( src ) || 1129 !src.ExpectTokenString( "," ) ) { 1130 return false; 1131 } 1132 constraint->limitAngles[0] = src.ParseFloat(); 1133 constraint->limit = idDeclAF_Constraint::LIMIT_CONE; 1134 } else if ( !token.Icmp( "pyramidlimit" ) ) { 1135 if ( !constraint->limitAxis.Parse( src ) || 1136 !src.ExpectTokenString( "," ) ) { 1137 return false; 1138 } 1139 constraint->limitAngles[0] = src.ParseFloat(); 1140 if ( !src.ExpectTokenString( "," ) ) { 1141 return false; 1142 } 1143 constraint->limitAngles[1] = src.ParseFloat(); 1144 if ( !src.ExpectTokenString( "," ) ) { 1145 return false; 1146 } 1147 constraint->limitAngles[2] = src.ParseFloat(); 1148 constraint->limit = idDeclAF_Constraint::LIMIT_PYRAMID; 1149 } else if ( !token.Icmp( "friction" ) ) { 1150 constraint->friction = src.ParseFloat(); 1151 } else if ( token == "}" ) { 1152 break; 1153 } else { 1154 src.Error( "unknown token %s in universal joint", token.c_str() ); 1155 return false; 1156 } 1157 } 1158 1159 return true; 1160 } 1161 1162 /* 1163 ================ 1164 idDeclAF::ParseHinge 1165 ================ 1166 */ 1167 bool idDeclAF::ParseHinge( idLexer &src ) { 1168 idToken token; 1169 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 1170 1171 constraint->SetDefault( this ); 1172 constraints.Alloc() = constraint; 1173 1174 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 1175 !src.ExpectTokenString( "{" ) ) { 1176 return false; 1177 } 1178 1179 constraint->type = DECLAF_CONSTRAINT_HINGE; 1180 constraint->limit = idDeclAF_Constraint::LIMIT_NONE; 1181 constraint->name = token; 1182 constraint->friction = 0.5f; 1183 constraint->anchor.ToVec3().Zero(); 1184 constraint->axis.ToVec3().Zero(); 1185 1186 while( src.ReadToken( &token ) ) { 1187 1188 if ( !token.Icmp( "body1" ) ) { 1189 src.ExpectTokenType( TT_STRING, 0, &token ); 1190 constraint->body1 = token; 1191 } else if ( !token.Icmp( "body2" ) ) { 1192 src.ExpectTokenType( TT_STRING, 0, &token ); 1193 constraint->body2 = token; 1194 } else if ( !token.Icmp( "anchor" ) ) { 1195 if ( !constraint->anchor.Parse( src ) ) { 1196 return false; 1197 } 1198 } else if ( !token.Icmp( "axis" ) ) { 1199 if ( !constraint->axis.Parse( src ) ) { 1200 return false; 1201 } 1202 } else if ( !token.Icmp( "limit" ) ) { 1203 constraint->limitAngles[0] = src.ParseFloat(); 1204 if ( !src.ExpectTokenString( "," ) ) { 1205 return false; 1206 } 1207 constraint->limitAngles[1] = src.ParseFloat(); 1208 if ( !src.ExpectTokenString( "," ) ) { 1209 return false; 1210 } 1211 constraint->limitAngles[2] = src.ParseFloat(); 1212 constraint->limit = idDeclAF_Constraint::LIMIT_CONE; 1213 } else if ( !token.Icmp( "friction" ) ) { 1214 constraint->friction = src.ParseFloat(); 1215 } else if ( token == "}" ) { 1216 break; 1217 } else { 1218 src.Error( "unknown token %s in hinge", token.c_str() ); 1219 return false; 1220 } 1221 } 1222 1223 return true; 1224 } 1225 1226 /* 1227 ================ 1228 idDeclAF::ParseSlider 1229 ================ 1230 */ 1231 bool idDeclAF::ParseSlider( idLexer &src ) { 1232 idToken token; 1233 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 1234 1235 constraint->SetDefault( this ); 1236 constraints.Alloc() = constraint; 1237 1238 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 1239 !src.ExpectTokenString( "{" ) ) { 1240 return false; 1241 } 1242 1243 constraint->type = DECLAF_CONSTRAINT_SLIDER; 1244 constraint->limit = idDeclAF_Constraint::LIMIT_NONE; 1245 constraint->name = token; 1246 constraint->friction = 0.5f; 1247 1248 while( src.ReadToken( &token ) ) { 1249 1250 if ( !token.Icmp( "body1" ) ) { 1251 src.ExpectTokenType( TT_STRING, 0, &token ); 1252 constraint->body1 = token; 1253 } else if ( !token.Icmp( "body2" ) ) { 1254 src.ExpectTokenType( TT_STRING, 0, &token ); 1255 constraint->body2 = token; 1256 } else if ( !token.Icmp( "axis" ) ) { 1257 if ( !constraint->axis.Parse( src ) ) { 1258 return false; 1259 } 1260 } else if ( !token.Icmp( "friction" ) ) { 1261 constraint->friction = src.ParseFloat(); 1262 } else if ( token == "}" ) { 1263 break; 1264 } else { 1265 src.Error( "unknown token %s in slider", token.c_str() ); 1266 return false; 1267 } 1268 } 1269 1270 return true; 1271 } 1272 1273 /* 1274 ================ 1275 idDeclAF::ParseSpring 1276 ================ 1277 */ 1278 bool idDeclAF::ParseSpring( idLexer &src ) { 1279 idToken token; 1280 idDeclAF_Constraint *constraint = new (TAG_DECL) idDeclAF_Constraint; 1281 1282 constraint->SetDefault( this ); 1283 constraints.Alloc() = constraint; 1284 1285 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) || 1286 !src.ExpectTokenString( "{" ) ) { 1287 return false; 1288 } 1289 1290 constraint->type = DECLAF_CONSTRAINT_SPRING; 1291 constraint->limit = idDeclAF_Constraint::LIMIT_NONE; 1292 constraint->name = token; 1293 constraint->friction = 0.5f; 1294 1295 while( src.ReadToken( &token ) ) { 1296 1297 if ( !token.Icmp( "body1" ) ) { 1298 src.ExpectTokenType( TT_STRING, 0, &token ); 1299 constraint->body1 = token; 1300 } else if ( !token.Icmp( "body2" ) ) { 1301 src.ExpectTokenType( TT_STRING, 0, &token ); 1302 constraint->body2 = token; 1303 } else if ( !token.Icmp( "anchor1" ) ) { 1304 if ( !constraint->anchor.Parse( src ) ) { 1305 return false; 1306 } 1307 } else if ( !token.Icmp( "anchor2" ) ) { 1308 if ( !constraint->anchor2.Parse( src ) ) { 1309 return false; 1310 } 1311 } else if ( !token.Icmp( "friction" ) ) { 1312 constraint->friction = src.ParseFloat(); 1313 } else if ( !token.Icmp( "stretch" ) ) { 1314 constraint->stretch = src.ParseFloat(); 1315 } else if ( !token.Icmp( "compress" ) ) { 1316 constraint->compress = src.ParseFloat(); 1317 } else if ( !token.Icmp( "damping" ) ) { 1318 constraint->damping = src.ParseFloat(); 1319 } else if ( !token.Icmp( "restLength" ) ) { 1320 constraint->restLength = src.ParseFloat(); 1321 } else if ( !token.Icmp( "minLength" ) ) { 1322 constraint->minLength = src.ParseFloat(); 1323 } else if ( !token.Icmp( "maxLength" ) ) { 1324 constraint->maxLength = src.ParseFloat(); 1325 } else if ( token == "}" ) { 1326 break; 1327 } else { 1328 src.Error( "unknown token %s in spring", token.c_str() ); 1329 return false; 1330 } 1331 } 1332 1333 return true; 1334 } 1335 1336 /* 1337 ================ 1338 idDeclAF::ParseSettings 1339 ================ 1340 */ 1341 bool idDeclAF::ParseSettings( idLexer &src ) { 1342 idToken token; 1343 1344 if ( !src.ExpectTokenString( "{" ) ) { 1345 return false; 1346 } 1347 1348 while( src.ReadToken( &token ) ) { 1349 1350 if ( !token.Icmp( "mesh" ) ) { 1351 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 1352 return false; 1353 } 1354 } else if ( !token.Icmp( "anim" ) ) { 1355 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 1356 return false; 1357 } 1358 } else if ( !token.Icmp( "model" ) ) { 1359 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 1360 return false; 1361 } 1362 model = token; 1363 } else if ( !token.Icmp( "skin" ) ) { 1364 if ( !src.ExpectTokenType( TT_STRING, 0, &token ) ) { 1365 return false; 1366 } 1367 skin = token; 1368 } else if ( !token.Icmp( "friction" ) ) { 1369 1370 defaultLinearFriction = src.ParseFloat(); 1371 if ( !src.ExpectTokenString( "," ) ) { 1372 return false; 1373 } 1374 defaultAngularFriction = src.ParseFloat(); 1375 if ( !src.ExpectTokenString( "," ) ) { 1376 return false; 1377 } 1378 defaultContactFriction = src.ParseFloat(); 1379 if ( src.CheckTokenString( "," ) ) { 1380 defaultConstraintFriction = src.ParseFloat(); 1381 } 1382 } else if ( !token.Icmp( "totalMass" ) ) { 1383 totalMass = src.ParseFloat(); 1384 } else if ( !token.Icmp( "suspendSpeed" ) ) { 1385 1386 suspendVelocity[0] = src.ParseFloat(); 1387 if ( !src.ExpectTokenString( "," ) ) { 1388 return false; 1389 } 1390 suspendVelocity[1] = src.ParseFloat(); 1391 if ( !src.ExpectTokenString( "," ) ) { 1392 return false; 1393 } 1394 suspendAcceleration[0] = src.ParseFloat(); 1395 if ( !src.ExpectTokenString( "," ) ) { 1396 return false; 1397 } 1398 suspendAcceleration[1] = src.ParseFloat(); 1399 } else if ( !token.Icmp( "noMoveTime" ) ) { 1400 noMoveTime = src.ParseFloat(); 1401 } else if ( !token.Icmp( "noMoveTranslation" ) ) { 1402 noMoveTranslation = src.ParseFloat(); 1403 } else if ( !token.Icmp( "noMoveRotation" ) ) { 1404 noMoveRotation = src.ParseFloat(); 1405 } else if ( !token.Icmp( "minMoveTime" ) ) { 1406 minMoveTime = src.ParseFloat(); 1407 } else if ( !token.Icmp( "maxMoveTime" ) ) { 1408 maxMoveTime = src.ParseFloat(); 1409 } else if ( !token.Icmp( "contents" ) ) { 1410 ParseContents( src, contents ); 1411 } else if ( !token.Icmp( "clipMask" ) ) { 1412 ParseContents( src, clipMask ); 1413 clipMask &= ~CONTENTS_CORPSE; // never allow collisions against corpses 1414 } else if ( !token.Icmp( "selfCollision" ) ) { 1415 selfCollision = src.ParseBool(); 1416 } else if ( token == "}" ) { 1417 break; 1418 } else { 1419 src.Error( "unknown token %s in settings", token.c_str() ); 1420 return false; 1421 } 1422 } 1423 1424 return true; 1425 } 1426 1427 /* 1428 ================ 1429 idDeclAF::Parse 1430 ================ 1431 */ 1432 bool idDeclAF::Parse( const char *text, const int textLength, bool allowBinaryVersion ) { 1433 int i, j; 1434 idLexer src; 1435 idToken token; 1436 1437 src.LoadMemory( text, textLength, GetFileName(), GetLineNum() ); 1438 src.SetFlags( DECL_LEXER_FLAGS ); 1439 src.SkipUntilString( "{" ); 1440 1441 while( src.ReadToken( &token ) ) { 1442 1443 if ( !token.Icmp( "settings" ) ) { 1444 if ( !ParseSettings( src ) ) { 1445 return false; 1446 } 1447 } else if ( !token.Icmp( "body" ) ) { 1448 if ( !ParseBody( src ) ) { 1449 return false; 1450 } 1451 } else if ( !token.Icmp( "fixed" ) ) { 1452 if ( !ParseFixed( src ) ) { 1453 return false; 1454 } 1455 } else if ( !token.Icmp( "ballAndSocketJoint" ) ) { 1456 if ( !ParseBallAndSocketJoint( src ) ) { 1457 return false; 1458 } 1459 } else if ( !token.Icmp( "universalJoint" ) ) { 1460 if ( !ParseUniversalJoint( src ) ) { 1461 return false; 1462 } 1463 } else if ( !token.Icmp( "hinge" ) ) { 1464 if ( !ParseHinge( src ) ) { 1465 return false; 1466 } 1467 } else if ( !token.Icmp( "slider" ) ) { 1468 if ( !ParseSlider( src ) ) { 1469 return false; 1470 } 1471 } else if ( !token.Icmp( "spring" ) ) { 1472 if ( !ParseSpring( src ) ) { 1473 return false; 1474 } 1475 } else if ( token == "}" ) { 1476 break; 1477 } else { 1478 src.Error( "unknown keyword %s", token.c_str() ); 1479 return false; 1480 } 1481 } 1482 1483 for ( i = 0; i < bodies.Num(); i++ ) { 1484 // check for multiple bodies with the same name 1485 for ( j = i+1; j < bodies.Num(); j++ ) { 1486 if ( bodies[i]->name == bodies[j]->name ) { 1487 src.Error( "two bodies with the same name \"%s\"", bodies[i]->name.c_str() ); 1488 } 1489 } 1490 } 1491 1492 for ( i = 0; i < constraints.Num(); i++ ) { 1493 // check for multiple constraints with the same name 1494 for ( j = i+1; j < constraints.Num(); j++ ) { 1495 if ( constraints[i]->name == constraints[j]->name ) { 1496 src.Error( "two constraints with the same name \"%s\"", constraints[i]->name.c_str() ); 1497 } 1498 } 1499 // check if there are two valid bodies set 1500 if ( constraints[i]->body1 == "" ) { 1501 src.Error( "no valid body1 specified for constraint '%s'", constraints[i]->name.c_str() ); 1502 } 1503 if ( constraints[i]->body2 == "" ) { 1504 src.Error( "no valid body2 specified for constraint '%s'", constraints[i]->name.c_str() ); 1505 } 1506 } 1507 1508 // make sure the body which modifies the origin comes first 1509 for ( i = 0; i < bodies.Num(); i++ ) { 1510 if ( bodies[i]->jointName == "origin" ) { 1511 if ( i != 0 ) { 1512 idDeclAF_Body *b = bodies[0]; 1513 bodies[0] = bodies[i]; 1514 bodies[i] = b; 1515 } 1516 break; 1517 } 1518 } 1519 1520 return true; 1521 } 1522 1523 /* 1524 ================ 1525 idDeclAF::DefaultDefinition 1526 ================ 1527 */ 1528 const char *idDeclAF::DefaultDefinition() const { 1529 return 1530 "{\n" 1531 "\t" "settings {\n" 1532 "\t\t" "model \"\"\n" 1533 "\t\t" "skin \"\"\n" 1534 "\t\t" "friction 0.01, 0.01, 0.8, 0.5\n" 1535 "\t\t" "suspendSpeed 20, 30, 40, 60\n" 1536 "\t\t" "noMoveTime 1\n" 1537 "\t\t" "noMoveTranslation 10\n" 1538 "\t\t" "noMoveRotation 10\n" 1539 "\t\t" "minMoveTime -1\n" 1540 "\t\t" "maxMoveTime -1\n" 1541 "\t\t" "totalMass -1\n" 1542 "\t\t" "contents corpse\n" 1543 "\t\t" "clipMask solid, corpse\n" 1544 "\t\t" "selfCollision 1\n" 1545 "\t" "}\n" 1546 "\t" "body \"body\" {\n" 1547 "\t\t" "joint \"origin\"\n" 1548 "\t\t" "mod orientation\n" 1549 "\t\t" "model box( ( -10, -10, -10 ), ( 10, 10, 10 ) )\n" 1550 "\t\t" "origin ( 0, 0, 0 )\n" 1551 "\t\t" "density 0.2\n" 1552 "\t\t" "friction 0.01, 0.01, 0.8\n" 1553 "\t\t" "contents corpse\n" 1554 "\t\t" "clipMask solid, corpse\n" 1555 "\t\t" "selfCollision 1\n" 1556 "\t\t" "containedJoints \"*origin\"\n" 1557 "\t" "}\n" 1558 "}\n"; 1559 } 1560 1561 /* 1562 ================ 1563 idDeclAF::FreeData 1564 ================ 1565 */ 1566 void idDeclAF::FreeData() { 1567 modified = false; 1568 defaultLinearFriction = 0.01f; 1569 defaultAngularFriction = 0.01f; 1570 defaultContactFriction = 0.8f; 1571 defaultConstraintFriction = 0.5f; 1572 totalMass = -1; 1573 suspendVelocity.Set( 20.0f, 30.0f ); 1574 suspendAcceleration.Set( 40.0f, 60.0f ); 1575 noMoveTime = 1.0f; 1576 noMoveTranslation = 10.0f; 1577 noMoveRotation = 10.0f; 1578 minMoveTime = -1.0f; 1579 maxMoveTime = -1.0f; 1580 selfCollision = true; 1581 contents = CONTENTS_CORPSE; 1582 clipMask = CONTENTS_SOLID; 1583 bodies.DeleteContents( true ); 1584 constraints.DeleteContents( true ); 1585 } 1586 1587 /* 1588 ================ 1589 idDeclAF::Finish 1590 ================ 1591 */ 1592 void idDeclAF::Finish( const getJointTransform_t GetJointTransform, const idJointMat *frame, void *model ) const { 1593 int i; 1594 1595 const char *name = GetName(); 1596 for ( i = 0; i < bodies.Num(); i++ ) { 1597 idDeclAF_Body *body = bodies[i]; 1598 body->v1.Finish( name, GetJointTransform, frame, model ); 1599 body->v2.Finish( name, GetJointTransform, frame, model ); 1600 body->origin.Finish( name, GetJointTransform, frame, model ); 1601 body->frictionDirection.Finish( name, GetJointTransform, frame, model ); 1602 body->contactMotorDirection.Finish( name, GetJointTransform, frame, model ); 1603 } 1604 for ( i = 0; i < constraints.Num(); i++ ) { 1605 idDeclAF_Constraint *constraint = constraints[i]; 1606 constraint->anchor.Finish( name, GetJointTransform, frame, model ); 1607 constraint->anchor2.Finish( name, GetJointTransform, frame, model ); 1608 constraint->shaft[0].Finish( name, GetJointTransform, frame, model ); 1609 constraint->shaft[1].Finish( name, GetJointTransform, frame, model ); 1610 constraint->axis.Finish( name, GetJointTransform, frame, model ); 1611 constraint->limitAxis.Finish( name, GetJointTransform, frame, model ); 1612 } 1613 } 1614 1615 /* 1616 ================ 1617 idDeclAF::NewBody 1618 ================ 1619 */ 1620 void idDeclAF::NewBody( const char *name ) { 1621 idDeclAF_Body *body; 1622 1623 body = new (TAG_DECL) idDeclAF_Body(); 1624 body->SetDefault( this ); 1625 body->name = name; 1626 bodies.Append( body ); 1627 } 1628 1629 /* 1630 ================ 1631 idDeclAF::RenameBody 1632 1633 rename the body with the given name and rename 1634 all constraint body references 1635 ================ 1636 */ 1637 void idDeclAF::RenameBody( const char *oldName, const char *newName ) { 1638 int i; 1639 1640 for ( i = 0; i < bodies.Num(); i++ ) { 1641 if ( bodies[i]->name.Icmp( oldName ) == 0 ) { 1642 bodies[i]->name = newName; 1643 break; 1644 } 1645 } 1646 for ( i = 0; i < constraints.Num(); i++ ) { 1647 if ( constraints[i]->body1.Icmp( oldName ) == 0 ) { 1648 constraints[i]->body1 = newName; 1649 } else if ( constraints[i]->body2.Icmp( oldName ) == 0 ) { 1650 constraints[i]->body2 = newName; 1651 } 1652 } 1653 } 1654 1655 /* 1656 ================ 1657 idDeclAF::DeleteBody 1658 1659 delete the body with the given name and delete 1660 all constraints that reference the body 1661 ================ 1662 */ 1663 void idDeclAF::DeleteBody( const char *name ) { 1664 int i; 1665 1666 for ( i = 0; i < bodies.Num(); i++ ) { 1667 if ( bodies[i]->name.Icmp( name ) == 0 ) { 1668 delete bodies[i]; 1669 bodies.RemoveIndex( i ); 1670 break; 1671 } 1672 } 1673 for ( i = 0; i < constraints.Num(); i++ ) { 1674 if ( constraints[i]->body1.Icmp( name ) == 0 || 1675 constraints[i]->body2.Icmp( name ) == 0 ) { 1676 delete constraints[i]; 1677 constraints.RemoveIndex( i ); 1678 i--; 1679 } 1680 } 1681 } 1682 1683 /* 1684 ================ 1685 idDeclAF::NewConstraint 1686 ================ 1687 */ 1688 void idDeclAF::NewConstraint( const char *name ) { 1689 idDeclAF_Constraint *constraint; 1690 1691 constraint = new (TAG_DECL) idDeclAF_Constraint; 1692 constraint->SetDefault( this ); 1693 constraint->name = name; 1694 constraints.Append( constraint ); 1695 } 1696 1697 /* 1698 ================ 1699 idDeclAF::RenameConstraint 1700 ================ 1701 */ 1702 void idDeclAF::RenameConstraint( const char *oldName, const char *newName ) { 1703 int i; 1704 1705 for ( i = 0; i < constraints.Num(); i++ ) { 1706 if ( constraints[i]->name.Icmp( oldName ) == 0 ) { 1707 constraints[i]->name = newName; 1708 return; 1709 } 1710 } 1711 } 1712 1713 /* 1714 ================ 1715 idDeclAF::DeleteConstraint 1716 ================ 1717 */ 1718 void idDeclAF::DeleteConstraint( const char *name ) { 1719 int i; 1720 1721 for ( i = 0; i < constraints.Num(); i++ ) { 1722 if ( constraints[i]->name.Icmp( name ) == 0 ) { 1723 delete constraints[i]; 1724 constraints.RemoveIndex( i ); 1725 return; 1726 } 1727 } 1728 } 1729 1730 /* 1731 ================ 1732 idDeclAF::idDeclAF 1733 ================ 1734 */ 1735 idDeclAF::idDeclAF() { 1736 FreeData(); 1737 } 1738 1739 /* 1740 ================ 1741 idDeclAF::~idDeclAF 1742 ================ 1743 */ 1744 idDeclAF::~idDeclAF() { 1745 bodies.DeleteContents( true ); 1746 constraints.DeleteContents( true ); 1747 }