Anim_Testmodel.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 Source Code is free software: you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation, either version 3 of the License, or
  9. (at your option) any later version.
  10. Doom 3 Source Code is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU General Public License for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 Source Code. If not, please request a copy in writing from id Software at the address below.
  17. 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.
  18. ===========================================================================
  19. */
  20. /*
  21. =============================================================================
  22. MODEL TESTING
  23. Model viewing can begin with either "testmodel <modelname>"
  24. The names must be the full pathname after the basedir, like
  25. "models/weapons/v_launch/tris.md3" or "players/male/tris.md3"
  26. Extension will default to ".ase" if not specified.
  27. Testmodel will create a fake entity 100 units in front of the current view
  28. position, directly facing the viewer. It will remain immobile, so you can
  29. move around it to view it from different angles.
  30. g_testModelRotate
  31. g_testModelAnimate
  32. g_testModelBlend
  33. =============================================================================
  34. */
  35. #include "../../idlib/precompiled.h"
  36. #pragma hdrstop
  37. #include "../Game_local.h"
  38. CLASS_DECLARATION( idAnimatedEntity, idTestModel )
  39. EVENT( EV_FootstepLeft, idTestModel::Event_Footstep )
  40. EVENT( EV_FootstepRight, idTestModel::Event_Footstep )
  41. END_CLASS
  42. /*
  43. ================
  44. idTestModel::idTestModel
  45. ================
  46. */
  47. idTestModel::idTestModel() {
  48. head = NULL;
  49. headAnimator = NULL;
  50. anim = 0;
  51. headAnim = 0;
  52. starttime = 0;
  53. animtime = 0;
  54. mode = 0;
  55. frame = 0;
  56. }
  57. /*
  58. ================
  59. idTestModel::Save
  60. ================
  61. */
  62. void idTestModel::Save( idSaveGame *savefile ) {
  63. }
  64. /*
  65. ================
  66. idTestModel::Restore
  67. ================
  68. */
  69. void idTestModel::Restore( idRestoreGame *savefile ) {
  70. // FIXME: one day we may actually want to save/restore test models, but for now we'll just delete them
  71. delete this;
  72. }
  73. /*
  74. ================
  75. idTestModel::Spawn
  76. ================
  77. */
  78. void idTestModel::Spawn( void ) {
  79. idVec3 size;
  80. idBounds bounds;
  81. const char *headModel;
  82. jointHandle_t joint;
  83. idStr jointName;
  84. idVec3 origin, modelOffset;
  85. idMat3 axis;
  86. const idKeyValue *kv;
  87. copyJoints_t copyJoint;
  88. if ( renderEntity.hModel && renderEntity.hModel->IsDefaultModel() && !animator.ModelDef() ) {
  89. gameLocal.Warning( "Unable to create testmodel for '%s' : model defaulted", spawnArgs.GetString( "model" ) );
  90. PostEventMS( &EV_Remove, 0 );
  91. return;
  92. }
  93. mode = g_testModelAnimate.GetInteger();
  94. animator.RemoveOriginOffset( g_testModelAnimate.GetInteger() == 1 );
  95. physicsObj.SetSelf( this );
  96. physicsObj.SetOrigin( GetPhysics()->GetOrigin() );
  97. physicsObj.SetAxis( GetPhysics()->GetAxis() );
  98. if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) ) {
  99. spawnArgs.GetVector( "maxs", NULL, bounds[1] );
  100. physicsObj.SetClipBox( bounds, 1.0f );
  101. physicsObj.SetContents( 0 );
  102. } else if ( spawnArgs.GetVector( "size", NULL, size ) ) {
  103. bounds[ 0 ].Set( size.x * -0.5f, size.y * -0.5f, 0.0f );
  104. bounds[ 1 ].Set( size.x * 0.5f, size.y * 0.5f, size.z );
  105. physicsObj.SetClipBox( bounds, 1.0f );
  106. physicsObj.SetContents( 0 );
  107. }
  108. spawnArgs.GetVector( "offsetModel", "0 0 0", modelOffset );
  109. // add the head model if it has one
  110. headModel = spawnArgs.GetString( "def_head", "" );
  111. if ( headModel[ 0 ] ) {
  112. jointName = spawnArgs.GetString( "head_joint" );
  113. joint = animator.GetJointHandle( jointName );
  114. if ( joint == INVALID_JOINT ) {
  115. gameLocal.Warning( "Joint '%s' not found for 'head_joint'", jointName.c_str() );
  116. } else {
  117. // copy any sounds in case we have frame commands on the head
  118. idDict args;
  119. const idKeyValue *sndKV = spawnArgs.MatchPrefix( "snd_", NULL );
  120. while( sndKV ) {
  121. args.Set( sndKV->GetKey(), sndKV->GetValue() );
  122. sndKV = spawnArgs.MatchPrefix( "snd_", sndKV );
  123. }
  124. head = gameLocal.SpawnEntityType( idAnimatedEntity::Type, &args );
  125. animator.GetJointTransform( joint, gameLocal.time, origin, axis );
  126. origin = GetPhysics()->GetOrigin() + ( origin + modelOffset ) * GetPhysics()->GetAxis();
  127. head.GetEntity()->SetModel( headModel );
  128. head.GetEntity()->SetOrigin( origin );
  129. head.GetEntity()->SetAxis( GetPhysics()->GetAxis() );
  130. head.GetEntity()->BindToJoint( this, animator.GetJointName( joint ), true );
  131. headAnimator = head.GetEntity()->GetAnimator();
  132. // set up the list of joints to copy to the head
  133. for( kv = spawnArgs.MatchPrefix( "copy_joint", NULL ); kv != NULL; kv = spawnArgs.MatchPrefix( "copy_joint", kv ) ) {
  134. jointName = kv->GetKey();
  135. if ( jointName.StripLeadingOnce( "copy_joint_world " ) ) {
  136. copyJoint.mod = JOINTMOD_WORLD_OVERRIDE;
  137. } else {
  138. jointName.StripLeadingOnce( "copy_joint " );
  139. copyJoint.mod = JOINTMOD_LOCAL_OVERRIDE;
  140. }
  141. copyJoint.from = animator.GetJointHandle( jointName );
  142. if ( copyJoint.from == INVALID_JOINT ) {
  143. gameLocal.Warning( "Unknown copy_joint '%s'", jointName.c_str() );
  144. continue;
  145. }
  146. copyJoint.to = headAnimator->GetJointHandle( jointName );
  147. if ( copyJoint.to == INVALID_JOINT ) {
  148. gameLocal.Warning( "Unknown copy_joint '%s' on head", jointName.c_str() );
  149. continue;
  150. }
  151. copyJoints.Append( copyJoint );
  152. }
  153. }
  154. }
  155. // start any shader effects based off of the spawn time
  156. renderEntity.shaderParms[ SHADERPARM_TIMEOFFSET ] = -MS2SEC( gameLocal.time );
  157. SetPhysics( &physicsObj );
  158. gameLocal.Printf( "Added testmodel at origin = '%s', angles = '%s'\n", GetPhysics()->GetOrigin().ToString(), GetPhysics()->GetAxis().ToAngles().ToString() );
  159. BecomeActive( TH_THINK );
  160. }
  161. /*
  162. ================
  163. idTestModel::~idTestModel
  164. ================
  165. */
  166. idTestModel::~idTestModel() {
  167. StopSound( SND_CHANNEL_ANY, false );
  168. if ( renderEntity.hModel ) {
  169. gameLocal.Printf( "Removing testmodel %s\n", renderEntity.hModel->Name() );
  170. } else {
  171. gameLocal.Printf( "Removing testmodel\n" );
  172. }
  173. if ( gameLocal.testmodel == this ) {
  174. gameLocal.testmodel = NULL;
  175. }
  176. if ( head.GetEntity() ) {
  177. head.GetEntity()->StopSound( SND_CHANNEL_ANY, false );
  178. head.GetEntity()->PostEventMS( &EV_Remove, 0 );
  179. }
  180. }
  181. /*
  182. ===============
  183. idTestModel::Event_Footstep
  184. ===============
  185. */
  186. void idTestModel::Event_Footstep( void ) {
  187. StartSound( "snd_footstep", SND_CHANNEL_BODY, 0, false, NULL );
  188. }
  189. /*
  190. ================
  191. idTestModel::ShouldConstructScriptObjectAtSpawn
  192. Called during idEntity::Spawn to see if it should construct the script object or not.
  193. Overridden by subclasses that need to spawn the script object themselves.
  194. ================
  195. */
  196. bool idTestModel::ShouldConstructScriptObjectAtSpawn( void ) const {
  197. return false;
  198. }
  199. /*
  200. ================
  201. idTestModel::Think
  202. ================
  203. */
  204. void idTestModel::Think( void ) {
  205. idVec3 pos;
  206. idMat3 axis;
  207. idAngles ang;
  208. int i;
  209. if ( thinkFlags & TH_THINK ) {
  210. if ( anim && ( gameLocal.testmodel == this ) && ( mode != g_testModelAnimate.GetInteger() ) ) {
  211. StopSound( SND_CHANNEL_ANY, false );
  212. if ( head.GetEntity() ) {
  213. head.GetEntity()->StopSound( SND_CHANNEL_ANY, false );
  214. }
  215. switch( g_testModelAnimate.GetInteger() ) {
  216. default:
  217. case 0:
  218. // cycle anim with origin reset
  219. if ( animator.NumFrames( anim ) <= 1 ) {
  220. // single frame animations end immediately, so just cycle it since it's the same result
  221. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  222. if ( headAnim ) {
  223. headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  224. }
  225. } else {
  226. animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  227. if ( headAnim ) {
  228. headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  229. if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) {
  230. // loop the body anim when the head anim is longer
  231. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 );
  232. }
  233. }
  234. }
  235. animator.RemoveOriginOffset( false );
  236. break;
  237. case 1:
  238. // cycle anim with fixed origin
  239. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  240. animator.RemoveOriginOffset( true );
  241. if ( headAnim ) {
  242. headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  243. }
  244. break;
  245. case 2:
  246. // cycle anim with continuous origin
  247. animator.CycleAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  248. animator.RemoveOriginOffset( false );
  249. if ( headAnim ) {
  250. headAnimator->CycleAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  251. }
  252. break;
  253. case 3:
  254. // frame by frame with continuous origin
  255. animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  256. animator.RemoveOriginOffset( false );
  257. if ( headAnim ) {
  258. headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  259. }
  260. break;
  261. case 4:
  262. // play anim once
  263. animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  264. animator.RemoveOriginOffset( false );
  265. if ( headAnim ) {
  266. headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  267. }
  268. break;
  269. case 5:
  270. // frame by frame with fixed origin
  271. animator.SetFrame( ANIMCHANNEL_ALL, anim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  272. animator.RemoveOriginOffset( true );
  273. if ( headAnim ) {
  274. headAnimator->SetFrame( ANIMCHANNEL_ALL, headAnim, frame, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  275. }
  276. break;
  277. }
  278. mode = g_testModelAnimate.GetInteger();
  279. }
  280. if ( ( mode == 0 ) && ( gameLocal.time >= starttime + animtime ) ) {
  281. starttime = gameLocal.time;
  282. StopSound( SND_CHANNEL_ANY, false );
  283. animator.PlayAnim( ANIMCHANNEL_ALL, anim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  284. if ( headAnim ) {
  285. headAnimator->PlayAnim( ANIMCHANNEL_ALL, headAnim, gameLocal.time, FRAME2MS( g_testModelBlend.GetInteger() ) );
  286. if ( headAnimator->AnimLength( headAnim ) > animator.AnimLength( anim ) ) {
  287. // loop the body anim when the head anim is longer
  288. animator.CurrentAnim( ANIMCHANNEL_ALL )->SetCycleCount( -1 );
  289. }
  290. }
  291. }
  292. if ( headAnimator ) {
  293. // copy the animation from the body to the head
  294. for( i = 0; i < copyJoints.Num(); i++ ) {
  295. if ( copyJoints[ i ].mod == JOINTMOD_WORLD_OVERRIDE ) {
  296. idMat3 mat = head.GetEntity()->GetPhysics()->GetAxis().Transpose();
  297. GetJointWorldTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  298. pos -= head.GetEntity()->GetPhysics()->GetOrigin();
  299. headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos * mat );
  300. headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis * mat );
  301. } else {
  302. animator.GetJointLocalTransform( copyJoints[ i ].from, gameLocal.time, pos, axis );
  303. headAnimator->SetJointPos( copyJoints[ i ].to, copyJoints[ i ].mod, pos );
  304. headAnimator->SetJointAxis( copyJoints[ i ].to, copyJoints[ i ].mod, axis );
  305. }
  306. }
  307. }
  308. // update rotation
  309. RunPhysics();
  310. physicsObj.GetAngles( ang );
  311. physicsObj.SetAngularExtrapolation( extrapolation_t(EXTRAPOLATION_LINEAR|EXTRAPOLATION_NOSTOP), gameLocal.time, 0, ang, idAngles( 0, g_testModelRotate.GetFloat() * 360.0f / 60.0f, 0 ), ang_zero );
  312. idClipModel *clip = physicsObj.GetClipModel();
  313. if ( clip && animator.ModelDef() ) {
  314. idVec3 neworigin;
  315. idMat3 axis;
  316. jointHandle_t joint;
  317. joint = animator.GetJointHandle( "origin" );
  318. animator.GetJointTransform( joint, gameLocal.time, neworigin, axis );
  319. neworigin = ( ( neworigin - animator.ModelDef()->GetVisualOffset() ) * physicsObj.GetAxis() ) + GetPhysics()->GetOrigin();
  320. clip->Link( gameLocal.clip, this, 0, neworigin, clip->GetAxis() );
  321. }
  322. }
  323. UpdateAnimation();
  324. Present();
  325. if ( ( gameLocal.testmodel == this ) && g_showTestModelFrame.GetInteger() && anim ) {
  326. gameLocal.Printf( "^5 Anim: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n", animator.AnimFullName( anim ), animator.CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ),
  327. animator.CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - animator.CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) );
  328. if ( headAnim ) {
  329. gameLocal.Printf( "^5 Head: ^7%s ^5Frame: ^7%d/%d Time: %.3f\n\n", headAnimator->AnimFullName( headAnim ), headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetFrameNumber( gameLocal.time ),
  330. headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->NumFrames(), MS2SEC( gameLocal.time - headAnimator->CurrentAnim( ANIMCHANNEL_ALL )->GetStartTime() ) );
  331. } else {
  332. gameLocal.Printf( "\n\n" );
  333. }
  334. }
  335. }
  336. /*
  337. ================
  338. idTestModel::NextAnim
  339. ================
  340. */
  341. void idTestModel::NextAnim( const idCmdArgs &args ) {
  342. if ( !animator.NumAnims() ) {
  343. return;
  344. }
  345. anim++;
  346. if ( anim >= animator.NumAnims() ) {
  347. // anim 0 is no anim
  348. anim = 1;
  349. }
  350. starttime = gameLocal.time;
  351. animtime = animator.AnimLength( anim );
  352. animname = animator.AnimFullName( anim );
  353. headAnim = 0;
  354. if ( headAnimator ) {
  355. headAnimator->ClearAllAnims( gameLocal.time, 0 );
  356. headAnim = headAnimator->GetAnim( animname );
  357. if ( !headAnim ) {
  358. headAnim = headAnimator->GetAnim( "idle" );
  359. }
  360. if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
  361. animtime = headAnimator->AnimLength( headAnim );
  362. }
  363. }
  364. gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
  365. if ( headAnim ) {
  366. gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) );
  367. }
  368. // reset the anim
  369. mode = -1;
  370. frame = 1;
  371. }
  372. /*
  373. ================
  374. idTestModel::PrevAnim
  375. ================
  376. */
  377. void idTestModel::PrevAnim( const idCmdArgs &args ) {
  378. if ( !animator.NumAnims() ) {
  379. return;
  380. }
  381. headAnim = 0;
  382. anim--;
  383. if ( anim < 0 ) {
  384. anim = animator.NumAnims() - 1;
  385. }
  386. starttime = gameLocal.time;
  387. animtime = animator.AnimLength( anim );
  388. animname = animator.AnimFullName( anim );
  389. headAnim = 0;
  390. if ( headAnimator ) {
  391. headAnimator->ClearAllAnims( gameLocal.time, 0 );
  392. headAnim = headAnimator->GetAnim( animname );
  393. if ( !headAnim ) {
  394. headAnim = headAnimator->GetAnim( "idle" );
  395. }
  396. if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
  397. animtime = headAnimator->AnimLength( headAnim );
  398. }
  399. }
  400. gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
  401. if ( headAnim ) {
  402. gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) );
  403. }
  404. // reset the anim
  405. mode = -1;
  406. frame = 1;
  407. }
  408. /*
  409. ================
  410. idTestModel::NextFrame
  411. ================
  412. */
  413. void idTestModel::NextFrame( const idCmdArgs &args ) {
  414. if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
  415. return;
  416. }
  417. frame++;
  418. if ( frame > animator.NumFrames( anim ) ) {
  419. frame = 1;
  420. }
  421. gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
  422. // reset the anim
  423. mode = -1;
  424. }
  425. /*
  426. ================
  427. idTestModel::PrevFrame
  428. ================
  429. */
  430. void idTestModel::PrevFrame( const idCmdArgs &args ) {
  431. if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
  432. return;
  433. }
  434. frame--;
  435. if ( frame < 1 ) {
  436. frame = animator.NumFrames( anim );
  437. }
  438. gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
  439. // reset the anim
  440. mode = -1;
  441. }
  442. /*
  443. ================
  444. idTestModel::TestAnim
  445. ================
  446. */
  447. void idTestModel::TestAnim( const idCmdArgs &args ) {
  448. idStr name;
  449. int animNum;
  450. const idAnim *newanim;
  451. if ( args.Argc() < 2 ) {
  452. gameLocal.Printf( "usage: testanim <animname>\n" );
  453. return;
  454. }
  455. newanim = NULL;
  456. name = args.Argv( 1 );
  457. #if 0
  458. if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) {
  459. const idMD5Anim *md5anims[ ANIM_MaxSyncedAnims ];
  460. idModelExport exporter;
  461. exporter.ExportAnim( name );
  462. name.SetFileExtension( MD5_ANIM_EXT );
  463. md5anims[ 0 ] = animationLib.GetAnim( name );
  464. if ( md5anims[ 0 ] ) {
  465. customAnim.SetAnim( animator.ModelDef(), name, name, 1, md5anims );
  466. newanim = &customAnim;
  467. }
  468. } else {
  469. animNum = animator.GetAnim( name );
  470. }
  471. #else
  472. animNum = animator.GetAnim( name );
  473. #endif
  474. if ( !animNum ) {
  475. gameLocal.Printf( "Animation '%s' not found.\n", name.c_str() );
  476. return;
  477. }
  478. anim = animNum;
  479. starttime = gameLocal.time;
  480. animtime = animator.AnimLength( anim );
  481. headAnim = 0;
  482. if ( headAnimator ) {
  483. headAnimator->ClearAllAnims( gameLocal.time, 0 );
  484. headAnim = headAnimator->GetAnim( animname );
  485. if ( !headAnim ) {
  486. headAnim = headAnimator->GetAnim( "idle" );
  487. if ( !headAnim ) {
  488. gameLocal.Printf( "Missing 'idle' anim for head.\n" );
  489. }
  490. }
  491. if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
  492. animtime = headAnimator->AnimLength( headAnim );
  493. }
  494. }
  495. animname = name;
  496. gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
  497. // reset the anim
  498. mode = -1;
  499. }
  500. /*
  501. =====================
  502. idTestModel::BlendAnim
  503. =====================
  504. */
  505. void idTestModel::BlendAnim( const idCmdArgs &args ) {
  506. int anim1;
  507. int anim2;
  508. if ( args.Argc() < 4 ) {
  509. gameLocal.Printf( "usage: testblend <anim1> <anim2> <frames>\n" );
  510. return;
  511. }
  512. anim1 = gameLocal.testmodel->animator.GetAnim( args.Argv( 1 ) );
  513. if ( !anim1 ) {
  514. gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 1 ) );
  515. return;
  516. }
  517. anim2 = gameLocal.testmodel->animator.GetAnim( args.Argv( 2 ) );
  518. if ( !anim2 ) {
  519. gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 2 ) );
  520. return;
  521. }
  522. animname = args.Argv( 2 );
  523. animator.CycleAnim( ANIMCHANNEL_ALL, anim1, gameLocal.time, 0 );
  524. animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, FRAME2MS( atoi( args.Argv( 3 ) ) ) );
  525. anim = anim2;
  526. headAnim = 0;
  527. }
  528. /***********************************************************************
  529. Testmodel console commands
  530. ***********************************************************************/
  531. /*
  532. =================
  533. idTestModel::KeepTestModel_f
  534. Makes the current test model permanent, allowing you to place
  535. multiple test models
  536. =================
  537. */
  538. void idTestModel::KeepTestModel_f( const idCmdArgs &args ) {
  539. if ( !gameLocal.testmodel ) {
  540. gameLocal.Printf( "No active testModel.\n" );
  541. return;
  542. }
  543. gameLocal.Printf( "modelDef %p kept\n", gameLocal.testmodel->renderEntity.hModel );
  544. gameLocal.testmodel = NULL;
  545. }
  546. /*
  547. =================
  548. idTestModel::TestSkin_f
  549. Sets a skin on an existing testModel
  550. =================
  551. */
  552. void idTestModel::TestSkin_f( const idCmdArgs &args ) {
  553. idVec3 offset;
  554. idStr name;
  555. idPlayer * player;
  556. idDict dict;
  557. player = gameLocal.GetLocalPlayer();
  558. if ( !player || !gameLocal.CheatsOk() ) {
  559. return;
  560. }
  561. // delete the testModel if active
  562. if ( !gameLocal.testmodel ) {
  563. common->Printf( "No active testModel\n" );
  564. return;
  565. }
  566. if ( args.Argc() < 2 ) {
  567. common->Printf( "removing testSkin.\n" );
  568. gameLocal.testmodel->SetSkin( NULL );
  569. return;
  570. }
  571. name = args.Argv( 1 );
  572. gameLocal.testmodel->SetSkin( declManager->FindSkin( name ) );
  573. }
  574. /*
  575. =================
  576. idTestModel::TestShaderParm_f
  577. Sets a shaderParm on an existing testModel
  578. =================
  579. */
  580. void idTestModel::TestShaderParm_f( const idCmdArgs &args ) {
  581. idVec3 offset;
  582. idStr name;
  583. idPlayer * player;
  584. idDict dict;
  585. player = gameLocal.GetLocalPlayer();
  586. if ( !player || !gameLocal.CheatsOk() ) {
  587. return;
  588. }
  589. // delete the testModel if active
  590. if ( !gameLocal.testmodel ) {
  591. common->Printf( "No active testModel\n" );
  592. return;
  593. }
  594. if ( args.Argc() != 3 ) {
  595. common->Printf( "USAGE: testShaderParm <parmNum> <float | \"time\">\n" );
  596. return;
  597. }
  598. int parm = atoi( args.Argv( 1 ) );
  599. if ( parm < 0 || parm >= MAX_ENTITY_SHADER_PARMS ) {
  600. common->Printf( "parmNum %i out of range\n", parm );
  601. return;
  602. }
  603. float value;
  604. if ( !idStr::Icmp( args.Argv( 2 ), "time" ) ) {
  605. value = gameLocal.time * -0.001;
  606. } else {
  607. value = atof( args.Argv( 2 ) );
  608. }
  609. gameLocal.testmodel->SetShaderParm( parm, value );
  610. }
  611. /*
  612. =================
  613. idTestModel::TestModel_f
  614. Creates a static modelDef in front of the current position, which
  615. can then be moved around
  616. =================
  617. */
  618. void idTestModel::TestModel_f( const idCmdArgs &args ) {
  619. idVec3 offset;
  620. idStr name;
  621. idPlayer * player;
  622. const idDict * entityDef;
  623. idDict dict;
  624. player = gameLocal.GetLocalPlayer();
  625. if ( !player || !gameLocal.CheatsOk() ) {
  626. return;
  627. }
  628. // delete the testModel if active
  629. if ( gameLocal.testmodel ) {
  630. delete gameLocal.testmodel;
  631. gameLocal.testmodel = NULL;
  632. }
  633. if ( args.Argc() < 2 ) {
  634. return;
  635. }
  636. name = args.Argv( 1 );
  637. entityDef = gameLocal.FindEntityDefDict( name, false );
  638. if ( entityDef ) {
  639. dict = *entityDef;
  640. } else {
  641. if ( declManager->FindType( DECL_MODELDEF, name, false ) ) {
  642. dict.Set( "model", name );
  643. } else {
  644. // allow map models with underscore prefixes to be tested during development
  645. // without appending an ase
  646. if ( name[ 0 ] != '_' ) {
  647. name.DefaultFileExtension( ".ase" );
  648. }
  649. #ifndef _D3XP
  650. // Maya ascii format is supported natively now
  651. if ( strstr( name, ".ma" ) || strstr( name, ".mb" ) ) {
  652. idModelExport exporter;
  653. exporter.ExportModel( name );
  654. name.SetFileExtension( MD5_MESH_EXT );
  655. }
  656. #endif
  657. if ( !renderModelManager->CheckModel( name ) ) {
  658. gameLocal.Printf( "Can't register model\n" );
  659. return;
  660. }
  661. dict.Set( "model", name );
  662. }
  663. }
  664. offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f;
  665. dict.Set( "origin", offset.ToString() );
  666. dict.Set( "angle", va( "%f", player->viewAngles.yaw + 180.0f ) );
  667. gameLocal.testmodel = ( idTestModel * )gameLocal.SpawnEntityType( idTestModel::Type, &dict );
  668. gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  669. }
  670. /*
  671. =====================
  672. idTestModel::ArgCompletion_TestModel
  673. =====================
  674. */
  675. void idTestModel::ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  676. int i, num;
  677. num = declManager->GetNumDecls( DECL_ENTITYDEF );
  678. for ( i = 0; i < num; i++ ) {
  679. callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_ENTITYDEF, i , false )->GetName() );
  680. }
  681. num = declManager->GetNumDecls( DECL_MODELDEF );
  682. for ( i = 0; i < num; i++ ) {
  683. callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_MODELDEF, i , false )->GetName() );
  684. }
  685. cmdSystem->ArgCompletion_FolderExtension( args, callback, "models/", false, ".lwo", ".ase", ".md5mesh", ".ma", ".mb", NULL );
  686. }
  687. /*
  688. =====================
  689. idTestModel::TestParticleStopTime_f
  690. =====================
  691. */
  692. void idTestModel::TestParticleStopTime_f( const idCmdArgs &args ) {
  693. if ( !gameLocal.testmodel ) {
  694. gameLocal.Printf( "No testModel active.\n" );
  695. return;
  696. }
  697. gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
  698. gameLocal.testmodel->UpdateVisuals();
  699. }
  700. /*
  701. =====================
  702. idTestModel::TestAnim_f
  703. =====================
  704. */
  705. void idTestModel::TestAnim_f( const idCmdArgs &args ) {
  706. if ( !gameLocal.testmodel ) {
  707. gameLocal.Printf( "No testModel active.\n" );
  708. return;
  709. }
  710. gameLocal.testmodel->TestAnim( args );
  711. }
  712. /*
  713. =====================
  714. idTestModel::ArgCompletion_TestAnim
  715. =====================
  716. */
  717. void idTestModel::ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  718. if ( gameLocal.testmodel ) {
  719. idAnimator *animator = gameLocal.testmodel->GetAnimator();
  720. for( int i = 0; i < animator->NumAnims(); i++ ) {
  721. callback( va( "%s %s", args.Argv( 0 ), animator->AnimFullName( i ) ) );
  722. }
  723. }
  724. }
  725. /*
  726. =====================
  727. idTestModel::TestBlend_f
  728. =====================
  729. */
  730. void idTestModel::TestBlend_f( const idCmdArgs &args ) {
  731. if ( !gameLocal.testmodel ) {
  732. gameLocal.Printf( "No testModel active.\n" );
  733. return;
  734. }
  735. gameLocal.testmodel->BlendAnim( args );
  736. }
  737. /*
  738. =====================
  739. idTestModel::TestModelNextAnim_f
  740. =====================
  741. */
  742. void idTestModel::TestModelNextAnim_f( const idCmdArgs &args ) {
  743. if ( !gameLocal.testmodel ) {
  744. gameLocal.Printf( "No testModel active.\n" );
  745. return;
  746. }
  747. gameLocal.testmodel->NextAnim( args );
  748. }
  749. /*
  750. =====================
  751. idTestModel::TestModelPrevAnim_f
  752. =====================
  753. */
  754. void idTestModel::TestModelPrevAnim_f( const idCmdArgs &args ) {
  755. if ( !gameLocal.testmodel ) {
  756. gameLocal.Printf( "No testModel active.\n" );
  757. return;
  758. }
  759. gameLocal.testmodel->PrevAnim( args );
  760. }
  761. /*
  762. =====================
  763. idTestModel::TestModelNextFrame_f
  764. =====================
  765. */
  766. void idTestModel::TestModelNextFrame_f( const idCmdArgs &args ) {
  767. if ( !gameLocal.testmodel ) {
  768. gameLocal.Printf( "No testModel active.\n" );
  769. return;
  770. }
  771. gameLocal.testmodel->NextFrame( args );
  772. }
  773. /*
  774. =====================
  775. idTestModel::TestModelPrevFrame_f
  776. =====================
  777. */
  778. void idTestModel::TestModelPrevFrame_f( const idCmdArgs &args ) {
  779. if ( !gameLocal.testmodel ) {
  780. gameLocal.Printf( "No testModel active.\n" );
  781. return;
  782. }
  783. gameLocal.testmodel->PrevFrame( args );
  784. }