Anim_Testmodel.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902
  1. /*
  2. ===========================================================================
  3. Doom 3 BFG Edition GPL Source Code
  4. Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
  6. Doom 3 BFG Edition 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 BFG Edition 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 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. 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.
  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. #pragma hdrstop
  36. #include "../../idlib/precompiled.h"
  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() {
  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() {
  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() const {
  197. return false;
  198. }
  199. /*
  200. ================
  201. idTestModel::Think
  202. ================
  203. */
  204. void idTestModel::Think() {
  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 != NULL && 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. anim--;
  382. if ( anim < 0 ) {
  383. anim = animator.NumAnims() - 1;
  384. }
  385. starttime = gameLocal.time;
  386. animtime = animator.AnimLength( anim );
  387. animname = animator.AnimFullName( anim );
  388. headAnim = 0;
  389. if ( headAnimator ) {
  390. headAnimator->ClearAllAnims( gameLocal.time, 0 );
  391. headAnim = headAnimator->GetAnim( animname );
  392. if ( !headAnim ) {
  393. headAnim = headAnimator->GetAnim( "idle" );
  394. }
  395. if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
  396. animtime = headAnimator->AnimLength( headAnim );
  397. }
  398. }
  399. gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
  400. if ( headAnim ) {
  401. gameLocal.Printf( "head '%s', %d.%03d seconds, %d frames\n", headAnimator->AnimFullName( headAnim ), headAnimator->AnimLength( headAnim ) / 1000, headAnimator->AnimLength( headAnim ) % 1000, headAnimator->NumFrames( headAnim ) );
  402. }
  403. // reset the anim
  404. mode = -1;
  405. frame = 1;
  406. }
  407. /*
  408. ================
  409. idTestModel::NextFrame
  410. ================
  411. */
  412. void idTestModel::NextFrame( const idCmdArgs &args ) {
  413. if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
  414. return;
  415. }
  416. frame++;
  417. if ( frame > animator.NumFrames( anim ) ) {
  418. frame = 1;
  419. }
  420. gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
  421. // reset the anim
  422. mode = -1;
  423. }
  424. /*
  425. ================
  426. idTestModel::PrevFrame
  427. ================
  428. */
  429. void idTestModel::PrevFrame( const idCmdArgs &args ) {
  430. if ( !anim || ( ( g_testModelAnimate.GetInteger() != 3 ) && ( g_testModelAnimate.GetInteger() != 5 ) ) ) {
  431. return;
  432. }
  433. frame--;
  434. if ( frame < 1 ) {
  435. frame = animator.NumFrames( anim );
  436. }
  437. gameLocal.Printf( "^5 Anim: ^7%s\n^5Frame: ^7%d/%d\n\n", animator.AnimFullName( anim ), frame, animator.NumFrames( anim ) );
  438. // reset the anim
  439. mode = -1;
  440. }
  441. /*
  442. ================
  443. idTestModel::TestAnim
  444. ================
  445. */
  446. void idTestModel::TestAnim( const idCmdArgs &args ) {
  447. idStr name;
  448. int animNum;
  449. const idAnim *newanim;
  450. if ( args.Argc() < 2 ) {
  451. gameLocal.Printf( "usage: testanim <animname>\n" );
  452. return;
  453. }
  454. newanim = NULL;
  455. name = args.Argv( 1 );
  456. animNum = animator.GetAnim( name );
  457. if ( !animNum ) {
  458. gameLocal.Printf( "Animation '%s' not found.\n", name.c_str() );
  459. return;
  460. }
  461. anim = animNum;
  462. starttime = gameLocal.time;
  463. animtime = animator.AnimLength( anim );
  464. headAnim = 0;
  465. if ( headAnimator ) {
  466. headAnimator->ClearAllAnims( gameLocal.time, 0 );
  467. headAnim = headAnimator->GetAnim( animname );
  468. if ( !headAnim ) {
  469. headAnim = headAnimator->GetAnim( "idle" );
  470. if ( !headAnim ) {
  471. gameLocal.Printf( "Missing 'idle' anim for head.\n" );
  472. }
  473. }
  474. if ( headAnim && ( headAnimator->AnimLength( headAnim ) > animtime ) ) {
  475. animtime = headAnimator->AnimLength( headAnim );
  476. }
  477. }
  478. animname = name;
  479. gameLocal.Printf( "anim '%s', %d.%03d seconds, %d frames\n", animname.c_str(), animator.AnimLength( anim ) / 1000, animator.AnimLength( anim ) % 1000, animator.NumFrames( anim ) );
  480. // reset the anim
  481. mode = -1;
  482. }
  483. /*
  484. =====================
  485. idTestModel::BlendAnim
  486. =====================
  487. */
  488. void idTestModel::BlendAnim( const idCmdArgs &args ) {
  489. int anim1;
  490. int anim2;
  491. if ( args.Argc() < 4 ) {
  492. gameLocal.Printf( "usage: testblend <anim1> <anim2> <frames>\n" );
  493. return;
  494. }
  495. anim1 = gameLocal.testmodel->animator.GetAnim( args.Argv( 1 ) );
  496. if ( !anim1 ) {
  497. gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 1 ) );
  498. return;
  499. }
  500. anim2 = gameLocal.testmodel->animator.GetAnim( args.Argv( 2 ) );
  501. if ( !anim2 ) {
  502. gameLocal.Printf( "Animation '%s' not found.\n", args.Argv( 2 ) );
  503. return;
  504. }
  505. animname = args.Argv( 2 );
  506. animator.CycleAnim( ANIMCHANNEL_ALL, anim1, gameLocal.time, 0 );
  507. animator.CycleAnim( ANIMCHANNEL_ALL, anim2, gameLocal.time, FRAME2MS( atoi( args.Argv( 3 ) ) ) );
  508. anim = anim2;
  509. headAnim = 0;
  510. }
  511. /***********************************************************************
  512. Testmodel console commands
  513. ***********************************************************************/
  514. /*
  515. =================
  516. idTestModel::KeepTestModel_f
  517. Makes the current test model permanent, allowing you to place
  518. multiple test models
  519. =================
  520. */
  521. void idTestModel::KeepTestModel_f( const idCmdArgs &args ) {
  522. if ( !gameLocal.testmodel ) {
  523. gameLocal.Printf( "No active testModel.\n" );
  524. return;
  525. }
  526. gameLocal.Printf( "modelDef %p kept\n", gameLocal.testmodel->renderEntity.hModel );
  527. gameLocal.testmodel = NULL;
  528. }
  529. /*
  530. =================
  531. idTestModel::TestSkin_f
  532. Sets a skin on an existing testModel
  533. =================
  534. */
  535. void idTestModel::TestSkin_f( const idCmdArgs &args ) {
  536. idVec3 offset;
  537. idStr name;
  538. idPlayer * player;
  539. idDict dict;
  540. player = gameLocal.GetLocalPlayer();
  541. if ( !player || !gameLocal.CheatsOk() ) {
  542. return;
  543. }
  544. // delete the testModel if active
  545. if ( !gameLocal.testmodel ) {
  546. common->Printf( "No active testModel\n" );
  547. return;
  548. }
  549. if ( args.Argc() < 2 ) {
  550. common->Printf( "removing testSkin.\n" );
  551. gameLocal.testmodel->SetSkin( NULL );
  552. return;
  553. }
  554. name = args.Argv( 1 );
  555. gameLocal.testmodel->SetSkin( declManager->FindSkin( name ) );
  556. }
  557. /*
  558. =================
  559. idTestModel::TestShaderParm_f
  560. Sets a shaderParm on an existing testModel
  561. =================
  562. */
  563. void idTestModel::TestShaderParm_f( const idCmdArgs &args ) {
  564. idVec3 offset;
  565. idStr name;
  566. idPlayer * player;
  567. idDict dict;
  568. player = gameLocal.GetLocalPlayer();
  569. if ( !player || !gameLocal.CheatsOk() ) {
  570. return;
  571. }
  572. // delete the testModel if active
  573. if ( !gameLocal.testmodel ) {
  574. common->Printf( "No active testModel\n" );
  575. return;
  576. }
  577. if ( args.Argc() != 3 ) {
  578. common->Printf( "USAGE: testShaderParm <parmNum> <float | \"time\">\n" );
  579. return;
  580. }
  581. int parm = atoi( args.Argv( 1 ) );
  582. if ( parm < 0 || parm >= MAX_ENTITY_SHADER_PARMS ) {
  583. common->Printf( "parmNum %i out of range\n", parm );
  584. return;
  585. }
  586. float value;
  587. if ( !idStr::Icmp( args.Argv( 2 ), "time" ) ) {
  588. value = gameLocal.time * -0.001;
  589. } else {
  590. value = atof( args.Argv( 2 ) );
  591. }
  592. gameLocal.testmodel->SetShaderParm( parm, value );
  593. }
  594. /*
  595. =================
  596. idTestModel::TestModel_f
  597. Creates a static modelDef in front of the current position, which
  598. can then be moved around
  599. =================
  600. */
  601. void idTestModel::TestModel_f( const idCmdArgs &args ) {
  602. idVec3 offset;
  603. idStr name;
  604. idPlayer * player;
  605. const idDict * entityDef;
  606. idDict dict;
  607. player = gameLocal.GetLocalPlayer();
  608. if ( !player || !gameLocal.CheatsOk() ) {
  609. return;
  610. }
  611. // delete the testModel if active
  612. if ( gameLocal.testmodel ) {
  613. delete gameLocal.testmodel;
  614. gameLocal.testmodel = NULL;
  615. }
  616. if ( args.Argc() < 2 ) {
  617. return;
  618. }
  619. name = args.Argv( 1 );
  620. entityDef = gameLocal.FindEntityDefDict( name, false );
  621. if ( entityDef ) {
  622. dict = *entityDef;
  623. } else {
  624. if ( declManager->FindType( DECL_MODELDEF, name, false ) ) {
  625. dict.Set( "model", name );
  626. } else {
  627. // allow map models with underscore prefixes to be tested during development
  628. // without appending an ase
  629. if ( name[ 0 ] != '_' ) {
  630. name.DefaultFileExtension( ".ase" );
  631. }
  632. if ( !renderModelManager->CheckModel( name ) ) {
  633. gameLocal.Printf( "Can't register model\n" );
  634. return;
  635. }
  636. dict.Set( "model", name );
  637. }
  638. }
  639. offset = player->GetPhysics()->GetOrigin() + player->viewAngles.ToForward() * 100.0f;
  640. dict.Set( "origin", offset.ToString() );
  641. dict.Set( "angle", va( "%f", player->viewAngles.yaw + 180.0f ) );
  642. gameLocal.testmodel = ( idTestModel * )gameLocal.SpawnEntityType( idTestModel::Type, &dict );
  643. gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_TIMEOFFSET] = -MS2SEC( gameLocal.time );
  644. }
  645. /*
  646. =====================
  647. idTestModel::ArgCompletion_TestModel
  648. =====================
  649. */
  650. void idTestModel::ArgCompletion_TestModel( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  651. int i, num;
  652. num = declManager->GetNumDecls( DECL_ENTITYDEF );
  653. for ( i = 0; i < num; i++ ) {
  654. callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_ENTITYDEF, i , false )->GetName() );
  655. }
  656. num = declManager->GetNumDecls( DECL_MODELDEF );
  657. for ( i = 0; i < num; i++ ) {
  658. callback( idStr( args.Argv( 0 ) ) + " " + declManager->DeclByIndex( DECL_MODELDEF, i , false )->GetName() );
  659. }
  660. cmdSystem->ArgCompletion_FolderExtension( args, callback, "models/", false, ".lwo", ".ase", ".md5mesh", ".ma", ".mb", NULL );
  661. }
  662. /*
  663. =====================
  664. idTestModel::TestParticleStopTime_f
  665. =====================
  666. */
  667. void idTestModel::TestParticleStopTime_f( const idCmdArgs &args ) {
  668. if ( !gameLocal.testmodel ) {
  669. gameLocal.Printf( "No testModel active.\n" );
  670. return;
  671. }
  672. gameLocal.testmodel->renderEntity.shaderParms[SHADERPARM_PARTICLE_STOPTIME] = MS2SEC( gameLocal.time );
  673. gameLocal.testmodel->UpdateVisuals();
  674. }
  675. /*
  676. =====================
  677. idTestModel::TestAnim_f
  678. =====================
  679. */
  680. void idTestModel::TestAnim_f( const idCmdArgs &args ) {
  681. if ( !gameLocal.testmodel ) {
  682. gameLocal.Printf( "No testModel active.\n" );
  683. return;
  684. }
  685. gameLocal.testmodel->TestAnim( args );
  686. }
  687. /*
  688. =====================
  689. idTestModel::ArgCompletion_TestAnim
  690. =====================
  691. */
  692. void idTestModel::ArgCompletion_TestAnim( const idCmdArgs &args, void(*callback)( const char *s ) ) {
  693. if ( gameLocal.testmodel ) {
  694. idAnimator *animator = gameLocal.testmodel->GetAnimator();
  695. for( int i = 0; i < animator->NumAnims(); i++ ) {
  696. callback( va( "%s %s", args.Argv( 0 ), animator->AnimFullName( i ) ) );
  697. }
  698. }
  699. }
  700. /*
  701. =====================
  702. idTestModel::TestBlend_f
  703. =====================
  704. */
  705. void idTestModel::TestBlend_f( const idCmdArgs &args ) {
  706. if ( !gameLocal.testmodel ) {
  707. gameLocal.Printf( "No testModel active.\n" );
  708. return;
  709. }
  710. gameLocal.testmodel->BlendAnim( args );
  711. }
  712. /*
  713. =====================
  714. idTestModel::TestModelNextAnim_f
  715. =====================
  716. */
  717. void idTestModel::TestModelNextAnim_f( const idCmdArgs &args ) {
  718. if ( !gameLocal.testmodel ) {
  719. gameLocal.Printf( "No testModel active.\n" );
  720. return;
  721. }
  722. gameLocal.testmodel->NextAnim( args );
  723. }
  724. /*
  725. =====================
  726. idTestModel::TestModelPrevAnim_f
  727. =====================
  728. */
  729. void idTestModel::TestModelPrevAnim_f( const idCmdArgs &args ) {
  730. if ( !gameLocal.testmodel ) {
  731. gameLocal.Printf( "No testModel active.\n" );
  732. return;
  733. }
  734. gameLocal.testmodel->PrevAnim( args );
  735. }
  736. /*
  737. =====================
  738. idTestModel::TestModelNextFrame_f
  739. =====================
  740. */
  741. void idTestModel::TestModelNextFrame_f( const idCmdArgs &args ) {
  742. if ( !gameLocal.testmodel ) {
  743. gameLocal.Printf( "No testModel active.\n" );
  744. return;
  745. }
  746. gameLocal.testmodel->NextFrame( args );
  747. }
  748. /*
  749. =====================
  750. idTestModel::TestModelPrevFrame_f
  751. =====================
  752. */
  753. void idTestModel::TestModelPrevFrame_f( const idCmdArgs &args ) {
  754. if ( !gameLocal.testmodel ) {
  755. gameLocal.Printf( "No testModel active.\n" );
  756. return;
  757. }
  758. gameLocal.testmodel->PrevFrame( args );
  759. }