GameEdit.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143
  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. #include "../idlib/precompiled.h"
  21. #pragma hdrstop
  22. #include "Game_local.h"
  23. /*
  24. ===============================================================================
  25. Ingame cursor.
  26. ===============================================================================
  27. */
  28. CLASS_DECLARATION( idEntity, idCursor3D )
  29. END_CLASS
  30. /*
  31. ===============
  32. idCursor3D::idCursor3D
  33. ===============
  34. */
  35. idCursor3D::idCursor3D( void ) {
  36. draggedPosition.Zero();
  37. }
  38. /*
  39. ===============
  40. idCursor3D::~idCursor3D
  41. ===============
  42. */
  43. idCursor3D::~idCursor3D( void ) {
  44. }
  45. /*
  46. ===============
  47. idCursor3D::Spawn
  48. ===============
  49. */
  50. void idCursor3D::Spawn( void ) {
  51. }
  52. /*
  53. ===============
  54. idCursor3D::Present
  55. ===============
  56. */
  57. void idCursor3D::Present( void ) {
  58. // don't present to the renderer if the entity hasn't changed
  59. if ( !( thinkFlags & TH_UPDATEVISUALS ) ) {
  60. return;
  61. }
  62. BecomeInactive( TH_UPDATEVISUALS );
  63. const idVec3 &origin = GetPhysics()->GetOrigin();
  64. const idMat3 &axis = GetPhysics()->GetAxis();
  65. gameRenderWorld->DebugArrow( colorYellow, origin + axis[1] * -5.0f + axis[2] * 5.0f, origin, 2 );
  66. gameRenderWorld->DebugArrow( colorRed, origin, draggedPosition, 2 );
  67. }
  68. /*
  69. ===============
  70. idCursor3D::Think
  71. ===============
  72. */
  73. void idCursor3D::Think( void ) {
  74. if ( thinkFlags & TH_THINK ) {
  75. drag.Evaluate( gameLocal.time );
  76. }
  77. Present();
  78. }
  79. /*
  80. ===============================================================================
  81. Allows entities to be dragged through the world with physics.
  82. ===============================================================================
  83. */
  84. #define MAX_DRAG_TRACE_DISTANCE 2048.0f
  85. /*
  86. ==============
  87. idDragEntity::idDragEntity
  88. ==============
  89. */
  90. idDragEntity::idDragEntity( void ) {
  91. cursor = NULL;
  92. Clear();
  93. }
  94. /*
  95. ==============
  96. idDragEntity::~idDragEntity
  97. ==============
  98. */
  99. idDragEntity::~idDragEntity( void ) {
  100. StopDrag();
  101. selected = NULL;
  102. delete cursor;
  103. cursor = NULL;
  104. }
  105. /*
  106. ==============
  107. idDragEntity::Clear
  108. ==============
  109. */
  110. void idDragEntity::Clear() {
  111. dragEnt = NULL;
  112. joint = INVALID_JOINT;
  113. id = 0;
  114. localEntityPoint.Zero();
  115. localPlayerPoint.Zero();
  116. bodyName.Clear();
  117. selected = NULL;
  118. }
  119. /*
  120. ==============
  121. idDragEntity::StopDrag
  122. ==============
  123. */
  124. void idDragEntity::StopDrag( void ) {
  125. dragEnt = NULL;
  126. if ( cursor ) {
  127. cursor->BecomeInactive( TH_THINK );
  128. }
  129. }
  130. /*
  131. ==============
  132. idDragEntity::Update
  133. ==============
  134. */
  135. void idDragEntity::Update( idPlayer *player ) {
  136. idVec3 viewPoint, origin;
  137. idMat3 viewAxis, axis;
  138. trace_t trace;
  139. idEntity *newEnt;
  140. idAngles angles;
  141. jointHandle_t newJoint;
  142. idStr newBodyName;
  143. player->GetViewPos( viewPoint, viewAxis );
  144. // if no entity selected for dragging
  145. if ( !dragEnt.GetEntity() ) {
  146. if ( player->usercmd.buttons & BUTTON_ATTACK ) {
  147. gameLocal.clip.TracePoint( trace, viewPoint, viewPoint + viewAxis[0] * MAX_DRAG_TRACE_DISTANCE, (CONTENTS_SOLID|CONTENTS_RENDERMODEL|CONTENTS_BODY), player );
  148. if ( trace.fraction < 1.0f ) {
  149. newEnt = gameLocal.entities[ trace.c.entityNum ];
  150. if ( newEnt ) {
  151. if ( newEnt->GetBindMaster() ) {
  152. if ( newEnt->GetBindJoint() ) {
  153. trace.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( newEnt->GetBindJoint() );
  154. } else {
  155. trace.c.id = newEnt->GetBindBody();
  156. }
  157. newEnt = newEnt->GetBindMaster();
  158. }
  159. if ( newEnt->IsType( idAFEntity_Base::Type ) && static_cast<idAFEntity_Base *>(newEnt)->IsActiveAF() ) {
  160. idAFEntity_Base *af = static_cast<idAFEntity_Base *>(newEnt);
  161. // joint being dragged
  162. newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id );
  163. // get the body id from the trace model id which might be a joint handle
  164. trace.c.id = af->BodyForClipModelId( trace.c.id );
  165. // get the name of the body being dragged
  166. newBodyName = af->GetAFPhysics()->GetBody( trace.c.id )->GetName();
  167. } else if ( !newEnt->IsType( idWorldspawn::Type ) ) {
  168. if ( trace.c.id < 0 ) {
  169. newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id );
  170. } else {
  171. newJoint = INVALID_JOINT;
  172. }
  173. newBodyName = "";
  174. } else {
  175. newJoint = INVALID_JOINT;
  176. newEnt = NULL;
  177. }
  178. }
  179. if ( newEnt ) {
  180. dragEnt = newEnt;
  181. selected = newEnt;
  182. joint = newJoint;
  183. id = trace.c.id;
  184. bodyName = newBodyName;
  185. if ( !cursor ) {
  186. cursor = ( idCursor3D * )gameLocal.SpawnEntityType( idCursor3D::Type );
  187. }
  188. idPhysics *phys = dragEnt.GetEntity()->GetPhysics();
  189. localPlayerPoint = ( trace.c.point - viewPoint ) * viewAxis.Transpose();
  190. origin = phys->GetOrigin( id );
  191. axis = phys->GetAxis( id );
  192. localEntityPoint = ( trace.c.point - origin ) * axis.Transpose();
  193. cursor->drag.Init( g_dragDamping.GetFloat() );
  194. cursor->drag.SetPhysics( phys, id, localEntityPoint );
  195. cursor->Show();
  196. if ( phys->IsType( idPhysics_AF::Type ) ||
  197. phys->IsType( idPhysics_RigidBody::Type ) ||
  198. phys->IsType( idPhysics_Monster::Type ) ) {
  199. cursor->BecomeActive( TH_THINK );
  200. }
  201. }
  202. }
  203. }
  204. }
  205. // if there is an entity selected for dragging
  206. idEntity *drag = dragEnt.GetEntity();
  207. if ( drag ) {
  208. if ( !( player->usercmd.buttons & BUTTON_ATTACK ) ) {
  209. StopDrag();
  210. return;
  211. }
  212. cursor->SetOrigin( viewPoint + localPlayerPoint * viewAxis );
  213. cursor->SetAxis( viewAxis );
  214. cursor->drag.SetDragPosition( cursor->GetPhysics()->GetOrigin() );
  215. renderEntity_t *renderEntity = drag->GetRenderEntity();
  216. idAnimator *dragAnimator = drag->GetAnimator();
  217. if ( joint != INVALID_JOINT && renderEntity && dragAnimator ) {
  218. dragAnimator->GetJointTransform( joint, gameLocal.time, cursor->draggedPosition, axis );
  219. cursor->draggedPosition = renderEntity->origin + cursor->draggedPosition * renderEntity->axis;
  220. gameRenderWorld->DrawText( va( "%s\n%s\n%s, %s", drag->GetName(), drag->GetType()->classname, dragAnimator->GetJointName( joint ), bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 );
  221. } else {
  222. cursor->draggedPosition = cursor->GetPhysics()->GetOrigin();
  223. gameRenderWorld->DrawText( va( "%s\n%s\n%s", drag->GetName(), drag->GetType()->classname, bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 );
  224. }
  225. }
  226. // if there is a selected entity
  227. if ( selected.GetEntity() && g_dragShowSelection.GetBool() ) {
  228. // draw the bbox of the selected entity
  229. renderEntity_t *renderEntity = selected.GetEntity()->GetRenderEntity();
  230. if ( renderEntity ) {
  231. gameRenderWorld->DebugBox( colorYellow, idBox( renderEntity->bounds, renderEntity->origin, renderEntity->axis ) );
  232. }
  233. }
  234. }
  235. /*
  236. ==============
  237. idDragEntity::SetSelected
  238. ==============
  239. */
  240. void idDragEntity::SetSelected( idEntity *ent ) {
  241. selected = ent;
  242. StopDrag();
  243. }
  244. /*
  245. ==============
  246. idDragEntity::DeleteSelected
  247. ==============
  248. */
  249. void idDragEntity::DeleteSelected( void ) {
  250. delete selected.GetEntity();
  251. selected = NULL;
  252. StopDrag();
  253. }
  254. /*
  255. ==============
  256. idDragEntity::BindSelected
  257. ==============
  258. */
  259. void idDragEntity::BindSelected( void ) {
  260. int num, largestNum;
  261. idLexer lexer;
  262. idToken type, bodyName;
  263. idStr key, value, bindBodyName;
  264. const idKeyValue *kv;
  265. idAFEntity_Base *af;
  266. af = static_cast<idAFEntity_Base *>(dragEnt.GetEntity());
  267. if ( !af || !af->IsType( idAFEntity_Base::Type ) || !af->IsActiveAF() ) {
  268. return;
  269. }
  270. bindBodyName = af->GetAFPhysics()->GetBody( id )->GetName();
  271. largestNum = 1;
  272. // parse all the bind constraints
  273. kv = af->spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  274. while ( kv ) {
  275. key = kv->GetKey();
  276. key.Strip( "bindConstraint " );
  277. if ( sscanf( key, "bind%d", &num ) ) {
  278. if ( num >= largestNum ) {
  279. largestNum = num + 1;
  280. }
  281. }
  282. lexer.LoadMemory( kv->GetValue(), kv->GetValue().Length(), kv->GetKey() );
  283. lexer.ReadToken( &type );
  284. lexer.ReadToken( &bodyName );
  285. lexer.FreeSource();
  286. // if there already exists a bind constraint for this body
  287. if ( bodyName.Icmp( bindBodyName ) == 0 ) {
  288. // delete the bind constraint
  289. af->spawnArgs.Delete( kv->GetKey() );
  290. kv = NULL;
  291. }
  292. kv = af->spawnArgs.MatchPrefix( "bindConstraint ", kv );
  293. }
  294. sprintf( key, "bindConstraint bind%d", largestNum );
  295. sprintf( value, "ballAndSocket %s %s", bindBodyName.c_str(), af->GetAnimator()->GetJointName( joint ) );
  296. af->spawnArgs.Set( key, value );
  297. af->spawnArgs.Set( "bind", "worldspawn" );
  298. af->Bind( gameLocal.world, true );
  299. }
  300. /*
  301. ==============
  302. idDragEntity::UnbindSelected
  303. ==============
  304. */
  305. void idDragEntity::UnbindSelected( void ) {
  306. const idKeyValue *kv;
  307. idAFEntity_Base *af;
  308. af = static_cast<idAFEntity_Base *>(selected.GetEntity());
  309. if ( !af || !af->IsType( idAFEntity_Base::Type ) || !af->IsActiveAF() ) {
  310. return;
  311. }
  312. // unbind the selected entity
  313. af->Unbind();
  314. // delete all the bind constraints
  315. kv = selected.GetEntity()->spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  316. while ( kv ) {
  317. selected.GetEntity()->spawnArgs.Delete( kv->GetKey() );
  318. kv = selected.GetEntity()->spawnArgs.MatchPrefix( "bindConstraint ", NULL );
  319. }
  320. // delete any bind information
  321. af->spawnArgs.Delete( "bind" );
  322. af->spawnArgs.Delete( "bindToJoint" );
  323. af->spawnArgs.Delete( "bindToBody" );
  324. }
  325. /*
  326. ===============================================================================
  327. Handles ingame entity editing.
  328. ===============================================================================
  329. */
  330. /*
  331. ==============
  332. idEditEntities::idEditEntities
  333. ==============
  334. */
  335. idEditEntities::idEditEntities( void ) {
  336. selectableEntityClasses.Clear();
  337. nextSelectTime = 0;
  338. }
  339. /*
  340. =============
  341. idEditEntities::SelectEntity
  342. =============
  343. */
  344. bool idEditEntities::SelectEntity( const idVec3 &origin, const idVec3 &dir, const idEntity *skip ) {
  345. idVec3 end;
  346. idEntity *ent;
  347. if ( !g_editEntityMode.GetInteger() || selectableEntityClasses.Num() == 0 ) {
  348. return false;
  349. }
  350. if ( gameLocal.time < nextSelectTime ) {
  351. return true;
  352. }
  353. nextSelectTime = gameLocal.time + 300;
  354. end = origin + dir * 4096.0f;
  355. ent = NULL;
  356. for ( int i = 0; i < selectableEntityClasses.Num(); i++ ) {
  357. ent = gameLocal.FindTraceEntity( origin, end, *selectableEntityClasses[i].typeInfo, skip );
  358. if ( ent ) {
  359. break;
  360. }
  361. }
  362. if ( ent ) {
  363. ClearSelectedEntities();
  364. if ( EntityIsSelectable( ent ) ) {
  365. AddSelectedEntity( ent );
  366. gameLocal.Printf( "entity #%d: %s '%s'\n", ent->entityNumber, ent->GetClassname(), ent->name.c_str() );
  367. ent->ShowEditingDialog();
  368. return true;
  369. }
  370. }
  371. return false;
  372. }
  373. /*
  374. =============
  375. idEditEntities::AddSelectedEntity
  376. =============
  377. */
  378. void idEditEntities::AddSelectedEntity(idEntity *ent) {
  379. ent->fl.selected = true;
  380. selectedEntities.AddUnique(ent);
  381. }
  382. /*
  383. ==============
  384. idEditEntities::RemoveSelectedEntity
  385. ==============
  386. */
  387. void idEditEntities::RemoveSelectedEntity( idEntity *ent ) {
  388. if ( selectedEntities.Find( ent ) ) {
  389. selectedEntities.Remove( ent );
  390. }
  391. }
  392. /*
  393. =============
  394. idEditEntities::ClearSelectedEntities
  395. =============
  396. */
  397. void idEditEntities::ClearSelectedEntities() {
  398. int i, count;
  399. count = selectedEntities.Num();
  400. for ( i = 0; i < count; i++ ) {
  401. selectedEntities[i]->fl.selected = false;
  402. }
  403. selectedEntities.Clear();
  404. }
  405. /*
  406. =============
  407. idEditEntities::EntityIsSelectable
  408. =============
  409. */
  410. bool idEditEntities::EntityIsSelectable( idEntity *ent, idVec4 *color, idStr *text ) {
  411. for ( int i = 0; i < selectableEntityClasses.Num(); i++ ) {
  412. if ( ent->GetType() == selectableEntityClasses[i].typeInfo ) {
  413. if ( text ) {
  414. *text = selectableEntityClasses[i].textKey;
  415. }
  416. if ( color ) {
  417. if ( ent->fl.selected ) {
  418. *color = colorRed;
  419. } else {
  420. switch( i ) {
  421. case 1 :
  422. *color = colorYellow;
  423. break;
  424. case 2 :
  425. *color = colorBlue;
  426. break;
  427. default:
  428. *color = colorGreen;
  429. }
  430. }
  431. }
  432. return true;
  433. }
  434. }
  435. return false;
  436. }
  437. /*
  438. =============
  439. idEditEntities::DisplayEntities
  440. =============
  441. */
  442. void idEditEntities::DisplayEntities( void ) {
  443. idEntity *ent;
  444. if ( !gameLocal.GetLocalPlayer() ) {
  445. return;
  446. }
  447. selectableEntityClasses.Clear();
  448. selectedTypeInfo_t sit;
  449. switch( g_editEntityMode.GetInteger() ) {
  450. case 1:
  451. sit.typeInfo = &idLight::Type;
  452. sit.textKey = "texture";
  453. selectableEntityClasses.Append( sit );
  454. break;
  455. case 2:
  456. sit.typeInfo = &idSound::Type;
  457. sit.textKey = "s_shader";
  458. selectableEntityClasses.Append( sit );
  459. sit.typeInfo = &idLight::Type;
  460. sit.textKey = "texture";
  461. selectableEntityClasses.Append( sit );
  462. break;
  463. case 3:
  464. sit.typeInfo = &idAFEntity_Base::Type;
  465. sit.textKey = "articulatedFigure";
  466. selectableEntityClasses.Append( sit );
  467. break;
  468. case 4:
  469. sit.typeInfo = &idFuncEmitter::Type;
  470. sit.textKey = "model";
  471. selectableEntityClasses.Append( sit );
  472. break;
  473. case 5:
  474. sit.typeInfo = &idAI::Type;
  475. sit.textKey = "name";
  476. selectableEntityClasses.Append( sit );
  477. break;
  478. case 6:
  479. sit.typeInfo = &idEntity::Type;
  480. sit.textKey = "name";
  481. selectableEntityClasses.Append( sit );
  482. break;
  483. case 7:
  484. sit.typeInfo = &idEntity::Type;
  485. sit.textKey = "model";
  486. selectableEntityClasses.Append( sit );
  487. break;
  488. default:
  489. return;
  490. }
  491. idBounds viewBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
  492. idBounds viewTextBounds( gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin() );
  493. idMat3 axis = gameLocal.GetLocalPlayer()->viewAngles.ToMat3();
  494. viewBounds.ExpandSelf( 512 );
  495. viewTextBounds.ExpandSelf( 128 );
  496. idStr textKey;
  497. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  498. idVec4 color;
  499. textKey = "";
  500. if ( !EntityIsSelectable( ent, &color, &textKey ) ) {
  501. continue;
  502. }
  503. bool drawArrows = false;
  504. if ( ent->GetType() == &idAFEntity_Base::Type ) {
  505. if ( !static_cast<idAFEntity_Base *>(ent)->IsActiveAF() ) {
  506. continue;
  507. }
  508. } else if ( ent->GetType() == &idSound::Type ) {
  509. if ( ent->fl.selected ) {
  510. drawArrows = true;
  511. }
  512. const idSoundShader * ss = declManager->FindSound( ent->spawnArgs.GetString( textKey ) );
  513. if ( ss->HasDefaultSound() || ss->base->GetState() == DS_DEFAULTED ) {
  514. color.Set( 1.0f, 0.0f, 1.0f, 1.0f );
  515. }
  516. } else if ( ent->GetType() == &idFuncEmitter::Type ) {
  517. if ( ent->fl.selected ) {
  518. drawArrows = true;
  519. }
  520. }
  521. if ( !viewBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) {
  522. continue;
  523. }
  524. gameRenderWorld->DebugBounds( color, idBounds( ent->GetPhysics()->GetOrigin() ).Expand( 8 ) );
  525. if ( drawArrows ) {
  526. idVec3 start = ent->GetPhysics()->GetOrigin();
  527. idVec3 end = start + idVec3( 1, 0, 0 ) * 20.0f;
  528. gameRenderWorld->DebugArrow( colorWhite, start, end, 2 );
  529. gameRenderWorld->DrawText( "x+", end + idVec3( 4, 0, 0 ), 0.15f, colorWhite, axis );
  530. end = start + idVec3( 1, 0, 0 ) * -20.0f;
  531. gameRenderWorld->DebugArrow( colorWhite, start, end, 2 );
  532. gameRenderWorld->DrawText( "x-", end + idVec3( -4, 0, 0 ), 0.15f, colorWhite, axis );
  533. end = start + idVec3( 0, 1, 0 ) * +20.0f;
  534. gameRenderWorld->DebugArrow( colorGreen, start, end, 2 );
  535. gameRenderWorld->DrawText( "y+", end + idVec3( 0, 4, 0 ), 0.15f, colorWhite, axis );
  536. end = start + idVec3( 0, 1, 0 ) * -20.0f;
  537. gameRenderWorld->DebugArrow( colorGreen, start, end, 2 );
  538. gameRenderWorld->DrawText( "y-", end + idVec3( 0, -4, 0 ), 0.15f, colorWhite, axis );
  539. end = start + idVec3( 0, 0, 1 ) * +20.0f;
  540. gameRenderWorld->DebugArrow( colorBlue, start, end, 2 );
  541. gameRenderWorld->DrawText( "z+", end + idVec3( 0, 0, 4 ), 0.15f, colorWhite, axis );
  542. end = start + idVec3( 0, 0, 1 ) * -20.0f;
  543. gameRenderWorld->DebugArrow( colorBlue, start, end, 2 );
  544. gameRenderWorld->DrawText( "z-", end + idVec3( 0, 0, -4 ), 0.15f, colorWhite, axis );
  545. }
  546. if ( textKey.Length() ) {
  547. const char *text = ent->spawnArgs.GetString( textKey );
  548. if ( viewTextBounds.ContainsPoint( ent->GetPhysics()->GetOrigin() ) ) {
  549. gameRenderWorld->DrawText( text, ent->GetPhysics()->GetOrigin() + idVec3(0, 0, 12), 0.25, colorWhite, axis, 1 );
  550. }
  551. }
  552. }
  553. }
  554. /*
  555. ===============================================================================
  556. idGameEdit
  557. ===============================================================================
  558. */
  559. idGameEdit gameEditLocal;
  560. idGameEdit * gameEdit = &gameEditLocal;
  561. /*
  562. =============
  563. idGameEdit::GetSelectedEntities
  564. =============
  565. */
  566. int idGameEdit::GetSelectedEntities( idEntity *list[], int max ) {
  567. int num = 0;
  568. idEntity *ent;
  569. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  570. if ( ent->fl.selected ) {
  571. list[num++] = ent;
  572. if ( num >= max ) {
  573. break;
  574. }
  575. }
  576. }
  577. return num;
  578. }
  579. /*
  580. =============
  581. idGameEdit::TriggerSelected
  582. =============
  583. */
  584. void idGameEdit::TriggerSelected() {
  585. idEntity *ent;
  586. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  587. if ( ent->fl.selected ) {
  588. ent->ProcessEvent( &EV_Activate, gameLocal.GetLocalPlayer() );
  589. }
  590. }
  591. }
  592. /*
  593. ================
  594. idGameEdit::ClearEntitySelection
  595. ================
  596. */
  597. void idGameEdit::ClearEntitySelection() {
  598. idEntity *ent;
  599. for( ent = gameLocal.spawnedEntities.Next(); ent != NULL; ent = ent->spawnNode.Next() ) {
  600. ent->fl.selected = false;
  601. }
  602. gameLocal.editEntities->ClearSelectedEntities();
  603. }
  604. /*
  605. ================
  606. idGameEdit::AddSelectedEntity
  607. ================
  608. */
  609. void idGameEdit::AddSelectedEntity( idEntity *ent ) {
  610. if ( ent ) {
  611. gameLocal.editEntities->AddSelectedEntity( ent );
  612. }
  613. }
  614. /*
  615. ================
  616. idGameEdit::FindEntityDefDict
  617. ================
  618. */
  619. const idDict *idGameEdit::FindEntityDefDict( const char *name, bool makeDefault ) const {
  620. return gameLocal.FindEntityDefDict( name, makeDefault );
  621. }
  622. /*
  623. ================
  624. idGameEdit::SpawnEntityDef
  625. ================
  626. */
  627. void idGameEdit::SpawnEntityDef( const idDict &args, idEntity **ent ) {
  628. gameLocal.SpawnEntityDef( args, ent );
  629. }
  630. /*
  631. ================
  632. idGameEdit::FindEntity
  633. ================
  634. */
  635. idEntity *idGameEdit::FindEntity( const char *name ) const {
  636. return gameLocal.FindEntity( name );
  637. }
  638. /*
  639. =============
  640. idGameEdit::GetUniqueEntityName
  641. generates a unique name for a given classname
  642. =============
  643. */
  644. const char *idGameEdit::GetUniqueEntityName( const char *classname ) const {
  645. int id;
  646. static char name[1024];
  647. // can only have MAX_GENTITIES, so if we have a spot available, we're guaranteed to find one
  648. for( id = 0; id < MAX_GENTITIES; id++ ) {
  649. idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id );
  650. if ( !gameLocal.FindEntity( name ) ) {
  651. return name;
  652. }
  653. }
  654. // id == MAX_GENTITIES + 1, which can't be in use if we get here
  655. idStr::snPrintf( name, sizeof( name ), "%s_%d", classname, id );
  656. return name;
  657. }
  658. /*
  659. ================
  660. idGameEdit::EntityGetOrigin
  661. ================
  662. */
  663. void idGameEdit::EntityGetOrigin( idEntity *ent, idVec3 &org ) const {
  664. if ( ent ) {
  665. org = ent->GetPhysics()->GetOrigin();
  666. }
  667. }
  668. /*
  669. ================
  670. idGameEdit::EntityGetAxis
  671. ================
  672. */
  673. void idGameEdit::EntityGetAxis( idEntity *ent, idMat3 &axis ) const {
  674. if ( ent ) {
  675. axis = ent->GetPhysics()->GetAxis();
  676. }
  677. }
  678. /*
  679. ================
  680. idGameEdit::EntitySetOrigin
  681. ================
  682. */
  683. void idGameEdit::EntitySetOrigin( idEntity *ent, const idVec3 &org ) {
  684. if ( ent ) {
  685. ent->SetOrigin( org );
  686. }
  687. }
  688. /*
  689. ================
  690. idGameEdit::EntitySetAxis
  691. ================
  692. */
  693. void idGameEdit::EntitySetAxis( idEntity *ent, const idMat3 &axis ) {
  694. if ( ent ) {
  695. ent->SetAxis( axis );
  696. }
  697. }
  698. /*
  699. ================
  700. idGameEdit::EntitySetColor
  701. ================
  702. */
  703. void idGameEdit::EntitySetColor( idEntity *ent, const idVec3 color ) {
  704. if ( ent ) {
  705. ent->SetColor( color );
  706. }
  707. }
  708. /*
  709. ================
  710. idGameEdit::EntityTranslate
  711. ================
  712. */
  713. void idGameEdit::EntityTranslate( idEntity *ent, const idVec3 &org ) {
  714. if ( ent ) {
  715. ent->GetPhysics()->Translate( org );
  716. }
  717. }
  718. /*
  719. ================
  720. idGameEdit::EntityGetSpawnArgs
  721. ================
  722. */
  723. const idDict *idGameEdit::EntityGetSpawnArgs( idEntity *ent ) const {
  724. if ( ent ) {
  725. return &ent->spawnArgs;
  726. }
  727. return NULL;
  728. }
  729. /*
  730. ================
  731. idGameEdit::EntityUpdateChangeableSpawnArgs
  732. ================
  733. */
  734. void idGameEdit::EntityUpdateChangeableSpawnArgs( idEntity *ent, const idDict *dict ) {
  735. if ( ent ) {
  736. ent->UpdateChangeableSpawnArgs( dict );
  737. }
  738. }
  739. /*
  740. ================
  741. idGameEdit::EntityChangeSpawnArgs
  742. ================
  743. */
  744. void idGameEdit::EntityChangeSpawnArgs( idEntity *ent, const idDict *newArgs ) {
  745. if ( ent ) {
  746. for ( int i = 0 ; i < newArgs->GetNumKeyVals () ; i ++ ) {
  747. const idKeyValue *kv = newArgs->GetKeyVal( i );
  748. if ( kv->GetValue().Length() > 0 ) {
  749. ent->spawnArgs.Set ( kv->GetKey() ,kv->GetValue() );
  750. } else {
  751. ent->spawnArgs.Delete ( kv->GetKey() );
  752. }
  753. }
  754. }
  755. }
  756. /*
  757. ================
  758. idGameEdit::EntityUpdateVisuals
  759. ================
  760. */
  761. void idGameEdit::EntityUpdateVisuals( idEntity *ent ) {
  762. if ( ent ) {
  763. ent->UpdateVisuals();
  764. }
  765. }
  766. /*
  767. ================
  768. idGameEdit::EntitySetModel
  769. ================
  770. */
  771. void idGameEdit::EntitySetModel( idEntity *ent, const char *val ) {
  772. if ( ent ) {
  773. ent->spawnArgs.Set( "model", val );
  774. ent->SetModel( val );
  775. }
  776. }
  777. /*
  778. ================
  779. idGameEdit::EntityStopSound
  780. ================
  781. */
  782. void idGameEdit::EntityStopSound( idEntity *ent ) {
  783. if ( ent ) {
  784. ent->StopSound( SND_CHANNEL_ANY, false );
  785. }
  786. }
  787. /*
  788. ================
  789. idGameEdit::EntityDelete
  790. ================
  791. */
  792. void idGameEdit::EntityDelete( idEntity *ent ) {
  793. delete ent;
  794. }
  795. /*
  796. ================
  797. idGameEdit::PlayerIsValid
  798. ================
  799. */
  800. bool idGameEdit::PlayerIsValid() const {
  801. return ( gameLocal.GetLocalPlayer() != NULL );
  802. }
  803. /*
  804. ================
  805. idGameEdit::PlayerGetOrigin
  806. ================
  807. */
  808. void idGameEdit::PlayerGetOrigin( idVec3 &org ) const {
  809. org = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin();
  810. }
  811. /*
  812. ================
  813. idGameEdit::PlayerGetAxis
  814. ================
  815. */
  816. void idGameEdit::PlayerGetAxis( idMat3 &axis ) const {
  817. axis = gameLocal.GetLocalPlayer()->GetPhysics()->GetAxis();
  818. }
  819. /*
  820. ================
  821. idGameEdit::PlayerGetViewAngles
  822. ================
  823. */
  824. void idGameEdit::PlayerGetViewAngles( idAngles &angles ) const {
  825. angles = gameLocal.GetLocalPlayer()->viewAngles;
  826. }
  827. /*
  828. ================
  829. idGameEdit::PlayerGetEyePosition
  830. ================
  831. */
  832. void idGameEdit::PlayerGetEyePosition( idVec3 &org ) const {
  833. org = gameLocal.GetLocalPlayer()->GetEyePosition();
  834. }
  835. /*
  836. ================
  837. idGameEdit::MapGetEntityDict
  838. ================
  839. */
  840. const idDict *idGameEdit::MapGetEntityDict( const char *name ) const {
  841. idMapFile *mapFile = gameLocal.GetLevelMap();
  842. if ( mapFile && name && *name ) {
  843. idMapEntity *mapent = mapFile->FindEntity( name );
  844. if ( mapent ) {
  845. return &mapent->epairs;
  846. }
  847. }
  848. return NULL;
  849. }
  850. /*
  851. ================
  852. idGameEdit::MapSave
  853. ================
  854. */
  855. void idGameEdit::MapSave( const char *path ) const {
  856. idMapFile *mapFile = gameLocal.GetLevelMap();
  857. if (mapFile) {
  858. mapFile->Write( (path) ? path : mapFile->GetName(), ".map");
  859. }
  860. }
  861. /*
  862. ================
  863. idGameEdit::MapSetEntityKeyVal
  864. ================
  865. */
  866. void idGameEdit::MapSetEntityKeyVal( const char *name, const char *key, const char *val ) const {
  867. idMapFile *mapFile = gameLocal.GetLevelMap();
  868. if ( mapFile && name && *name ) {
  869. idMapEntity *mapent = mapFile->FindEntity( name );
  870. if ( mapent ) {
  871. mapent->epairs.Set( key, val );
  872. }
  873. }
  874. }
  875. /*
  876. ================
  877. idGameEdit::MapCopyDictToEntity
  878. ================
  879. */
  880. void idGameEdit::MapCopyDictToEntity( const char *name, const idDict *dict ) const {
  881. idMapFile *mapFile = gameLocal.GetLevelMap();
  882. if ( mapFile && name && *name ) {
  883. idMapEntity *mapent = mapFile->FindEntity( name );
  884. if ( mapent ) {
  885. for ( int i = 0; i < dict->GetNumKeyVals(); i++ ) {
  886. const idKeyValue *kv = dict->GetKeyVal( i );
  887. const char *key = kv->GetKey();
  888. const char *val = kv->GetValue();
  889. mapent->epairs.Set( key, val );
  890. }
  891. }
  892. }
  893. }
  894. /*
  895. ================
  896. idGameEdit::MapGetUniqueMatchingKeyVals
  897. ================
  898. */
  899. int idGameEdit::MapGetUniqueMatchingKeyVals( const char *key, const char *list[], int max ) const {
  900. idMapFile *mapFile = gameLocal.GetLevelMap();
  901. int count = 0;
  902. if ( mapFile ) {
  903. for ( int i = 0; i < mapFile->GetNumEntities(); i++ ) {
  904. idMapEntity *ent = mapFile->GetEntity( i );
  905. if ( ent ) {
  906. const char *k = ent->epairs.GetString( key );
  907. if ( k && *k && count < max ) {
  908. list[count++] = k;
  909. }
  910. }
  911. }
  912. }
  913. return count;
  914. }
  915. /*
  916. ================
  917. idGameEdit::MapAddEntity
  918. ================
  919. */
  920. void idGameEdit::MapAddEntity( const idDict *dict ) const {
  921. idMapFile *mapFile = gameLocal.GetLevelMap();
  922. if ( mapFile ) {
  923. idMapEntity *ent = new idMapEntity();
  924. ent->epairs = *dict;
  925. mapFile->AddEntity( ent );
  926. }
  927. }
  928. /*
  929. ================
  930. idGameEdit::MapRemoveEntity
  931. ================
  932. */
  933. void idGameEdit::MapRemoveEntity( const char *name ) const {
  934. idMapFile *mapFile = gameLocal.GetLevelMap();
  935. if ( mapFile ) {
  936. idMapEntity *ent = mapFile->FindEntity( name );
  937. if ( ent ) {
  938. mapFile->RemoveEntity( ent );
  939. }
  940. }
  941. }
  942. /*
  943. ================
  944. idGameEdit::MapGetEntitiesMatchignClassWithString
  945. ================
  946. */
  947. int idGameEdit::MapGetEntitiesMatchingClassWithString( const char *classname, const char *match, const char *list[], const int max ) const {
  948. idMapFile *mapFile = gameLocal.GetLevelMap();
  949. int count = 0;
  950. if ( mapFile ) {
  951. int entCount = mapFile->GetNumEntities();
  952. for ( int i = 0 ; i < entCount; i++ ) {
  953. idMapEntity *ent = mapFile->GetEntity(i);
  954. if (ent) {
  955. idStr work = ent->epairs.GetString("classname");
  956. if ( work.Icmp( classname ) == 0 ) {
  957. if ( match && *match ) {
  958. work = ent->epairs.GetString( "soundgroup" );
  959. if ( count < max && work.Icmp( match ) == 0 ) {
  960. list[count++] = ent->epairs.GetString( "name" );
  961. }
  962. } else if ( count < max ) {
  963. list[count++] = ent->epairs.GetString( "name" );
  964. }
  965. }
  966. }
  967. }
  968. }
  969. return count;
  970. }
  971. /*
  972. ================
  973. idGameEdit::MapEntityTranslate
  974. ================
  975. */
  976. void idGameEdit::MapEntityTranslate( const char *name, const idVec3 &v ) const {
  977. idMapFile *mapFile = gameLocal.GetLevelMap();
  978. if ( mapFile && name && *name ) {
  979. idMapEntity *mapent = mapFile->FindEntity( name );
  980. if ( mapent ) {
  981. idVec3 origin;
  982. mapent->epairs.GetVector( "origin", "", origin );
  983. origin += v;
  984. mapent->epairs.SetVector( "origin", origin );
  985. }
  986. }
  987. }