EditorEntity.cpp 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  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 "qe3.h"
  23. #include "../../renderer/tr_local.h"
  24. #include "../../renderer/model_local.h" // for idRenderModelMD5
  25. int g_entityId = 1;
  26. #define CURVE_TAG "curve_"
  27. extern void Brush_Resize(brush_t *b, idVec3 vMin, idVec3 vMax);
  28. int GetNumKeys(entity_t *ent)
  29. {
  30. // int iCount = 0;
  31. // for (epair_t* ep=ent->epairs ; ep ; ep=ep->next)
  32. // {
  33. // iCount++;
  34. // }
  35. int iCount = ent->epairs.GetNumKeyVals();
  36. return iCount;
  37. }
  38. const char *GetKeyString(entity_t *ent, int iIndex)
  39. {
  40. // for (epair_t* ep=ent->epairs ; ep ; ep=ep->next)
  41. // {
  42. // if (!iIndex--)
  43. // return ep->key;
  44. // }
  45. //
  46. // assert(0);
  47. // return NULL;
  48. if ( iIndex < GetNumKeys(ent) )
  49. {
  50. return ent->epairs.GetKeyVal(iIndex)->GetKey().c_str();
  51. }
  52. assert(0);
  53. return NULL;
  54. }
  55. /*
  56. =======================================================================================================================
  57. =======================================================================================================================
  58. */
  59. const char *ValueForKey(entity_t *ent, const char *key) {
  60. return ent->epairs.GetString(key);
  61. }
  62. /*
  63. =======================================================================================================================
  64. =======================================================================================================================
  65. */
  66. void TrackMD3Angles(entity_t *e, const char *key, const char *value) {
  67. if ( idStr::Icmp(key, "angle") != 0 ) {
  68. return;
  69. }
  70. if ((e->eclass->fixedsize && e->eclass->nShowFlags & ECLASS_MISCMODEL) || EntityHasModel(e)) {
  71. float a = FloatForKey(e, "angle");
  72. float b = atof(value);
  73. if (a != b) {
  74. idVec3 vAngle;
  75. vAngle[0] = vAngle[1] = 0;
  76. vAngle[2] = -a;
  77. Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
  78. vAngle[2] = b;
  79. Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
  80. }
  81. }
  82. }
  83. /*
  84. =======================================================================================================================
  85. =======================================================================================================================
  86. */
  87. void SetKeyValue(entity_t *ent, const char *key, const char *value, bool trackAngles) {
  88. if (ent == NULL) {
  89. return;
  90. }
  91. if (!key || !key[0]) {
  92. return;
  93. }
  94. if (trackAngles) {
  95. TrackMD3Angles(ent, key, value);
  96. }
  97. ent->epairs.Set(key, value);
  98. GetVectorForKey(ent, "origin", ent->origin);
  99. // update sound in case this key was relevent
  100. Entity_UpdateSoundEmitter( ent );
  101. }
  102. /*
  103. =======================================================================================================================
  104. =======================================================================================================================
  105. */
  106. void SetKeyVec3(entity_t *ent, const char *key, idVec3 v) {
  107. if (ent == NULL) {
  108. return;
  109. }
  110. if (!key || !key[0]) {
  111. return;
  112. }
  113. idStr str;
  114. sprintf(str, "%g %g %g", v.x, v.y, v.z);
  115. ent->epairs.Set(key, str);
  116. GetVectorForKey(ent, "origin", ent->origin);
  117. }
  118. /*
  119. =======================================================================================================================
  120. =======================================================================================================================
  121. */
  122. void SetKeyMat3(entity_t *ent, const char *key, idMat3 m) {
  123. if (ent == NULL) {
  124. return;
  125. }
  126. if (!key || !key[0]) {
  127. return;
  128. }
  129. idStr str;
  130. sprintf(str, "%g %g %g %g %g %g %g %g %g",m[0][0],m[0][1],m[0][2],m[1][0],m[1][1],m[1][2],m[2][0],m[2][1],m[2][2]);
  131. ent->epairs.Set(key, str);
  132. GetVectorForKey(ent, "origin", ent->origin);
  133. }
  134. /*
  135. =======================================================================================================================
  136. =======================================================================================================================
  137. */
  138. void DeleteKey(entity_t *ent, const char *key) {
  139. ent->epairs.Delete(key);
  140. if (stricmp(key, "rotation") == 0) {
  141. ent->rotation.Identity();
  142. }
  143. }
  144. /*
  145. =======================================================================================================================
  146. =======================================================================================================================
  147. */
  148. float FloatForKey(entity_t *ent, const char *key) {
  149. const char *k;
  150. k = ValueForKey(ent, key);
  151. if (k && *k) {
  152. return atof(k);
  153. }
  154. return 0.0;
  155. }
  156. /*
  157. =======================================================================================================================
  158. =======================================================================================================================
  159. */
  160. int IntForKey(entity_t *ent, const char *key) {
  161. const char *k;
  162. k = ValueForKey(ent, key);
  163. return atoi(k);
  164. }
  165. /*
  166. =======================================================================================================================
  167. =======================================================================================================================
  168. */
  169. bool GetVectorForKey(entity_t *ent, const char *key, idVec3 &vec) {
  170. const char *k;
  171. k = ValueForKey(ent, key);
  172. if (k && strlen(k) > 0) {
  173. sscanf(k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
  174. return true;
  175. }
  176. else {
  177. vec[0] = vec[1] = vec[2] = 0;
  178. }
  179. return false;
  180. }
  181. /*
  182. =======================================================================================================================
  183. =======================================================================================================================
  184. */
  185. bool GetVector4ForKey(entity_t *ent, const char *key, idVec4 &vec) {
  186. const char *k;
  187. k = ValueForKey(ent, key);
  188. if (k && strlen(k) > 0) {
  189. sscanf(k, "%f %f %f %f", &vec[0], &vec[1], &vec[2], &vec[3]);
  190. return true;
  191. }
  192. else {
  193. vec[0] = vec[1] = vec[2] = vec[3] = 0;
  194. }
  195. return false;
  196. }
  197. /*
  198. =======================================================================================================================
  199. =======================================================================================================================
  200. */
  201. bool GetFloatForKey(entity_t *ent, const char *key, float *f) {
  202. const char *k;
  203. k = ValueForKey(ent, key);
  204. if (k && strlen(k) > 0) {
  205. *f = atof(k);
  206. return true;
  207. }
  208. *f = 0;
  209. return false;
  210. }
  211. /*
  212. =======================================================================================================================
  213. =======================================================================================================================
  214. */
  215. bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat) {
  216. const char *k;
  217. k = ValueForKey(ent, key);
  218. if (k && strlen(k) > 0) {
  219. sscanf
  220. (
  221. k,
  222. "%f %f %f %f %f %f %f %f %f ",
  223. &mat[0][0],
  224. &mat[0][1],
  225. &mat[0][2],
  226. &mat[1][0],
  227. &mat[1][1],
  228. &mat[1][2],
  229. &mat[2][0],
  230. &mat[2][1],
  231. &mat[2][2]
  232. );
  233. return true;
  234. }
  235. else {
  236. mat.Identity();
  237. }
  238. return false;
  239. }
  240. /*
  241. =======================================================================================================================
  242. Entity_FreeEpairs Frees the entity epairs.
  243. =======================================================================================================================
  244. */
  245. void Entity_FreeEpairs(entity_t *e) {
  246. e->epairs.Clear();
  247. }
  248. /*
  249. =======================================================================================================================
  250. Entity_AddToList
  251. =======================================================================================================================
  252. */
  253. void Entity_AddToList(entity_t *e, entity_t *list) {
  254. if (e->next || e->prev) {
  255. Error("Entity_AddToList: allready linked");
  256. }
  257. e->next = list->next;
  258. list->next->prev = e;
  259. list->next = e;
  260. e->prev = list;
  261. }
  262. /*
  263. =======================================================================================================================
  264. Entity_RemoveFromList
  265. =======================================================================================================================
  266. */
  267. void Entity_RemoveFromList(entity_t *e) {
  268. if ( !e->next || !e->prev ) {
  269. Error("Entity_RemoveFromList: not linked");
  270. }
  271. e->next->prev = e->prev;
  272. e->prev->next = e->next;
  273. e->next = e->prev = NULL;
  274. }
  275. /*
  276. =======================================================================================================================
  277. Entity_Free Frees the entity and any brushes is has. The entity is removed from the global entities list.
  278. =======================================================================================================================
  279. */
  280. void Entity_Free( entity_t *e ) {
  281. while ( e->brushes.onext != &e->brushes ) {
  282. Brush_Free(e->brushes.onext);
  283. }
  284. if ( e->next ) {
  285. e->next->prev = e->prev;
  286. e->prev->next = e->next;
  287. }
  288. Entity_FreeEpairs( e );
  289. delete e;
  290. }
  291. /*
  292. =======================================================================================================================
  293. Entity_MemorySize
  294. =======================================================================================================================
  295. */
  296. int Entity_MemorySize( entity_t *e )
  297. {
  298. brush_t *b;
  299. int size;
  300. size = sizeof( entity_t ) + e->epairs.Size();
  301. for( b = e->brushes.onext; b != &e->brushes; b = b->onext )
  302. {
  303. size += Brush_MemorySize( b );
  304. }
  305. return( size );
  306. }
  307. /*
  308. =======================================================================================================================
  309. ParseEpair
  310. =======================================================================================================================
  311. */
  312. struct EpairFixup {
  313. const char *name;
  314. int type;
  315. };
  316. const EpairFixup FloatFixups[] = {
  317. { "origin", 1 },
  318. { "rotation", 2 },
  319. { "_color", 1 },
  320. { "falloff", 0 },
  321. { "light", 0 },
  322. { "light_target", 1 },
  323. { "light_up", 1 },
  324. { "light_right", 1 },
  325. { "light_start", 1 },
  326. { "light_center", 1 },
  327. { "light_end", 1 },
  328. { "light_radius", 1 },
  329. { "light_origin", 1 }
  330. };
  331. const int FixupCount = sizeof(FloatFixups) / sizeof(EpairFixup);
  332. void FixFloats(idDict *dict) {
  333. int count = dict->GetNumKeyVals();
  334. for (int i = 0; i < count; i++) {
  335. const idKeyValue *kv = dict->GetKeyVal(i);
  336. for (int j = 0; j < FixupCount; j++) {
  337. if (kv->GetKey().Icmp(FloatFixups[j].name) == 0) {
  338. idStr val;
  339. if (FloatFixups[j].type == 1) {
  340. idVec3 v;
  341. sscanf(kv->GetValue().c_str(), "%f %f %f", &v.x, &v.y, &v.z);
  342. sprintf(val, "%g %g %g", v.x, v.y, v.z);
  343. } else if (FloatFixups[j].type == 2) {
  344. idMat3 mat;
  345. sscanf(kv->GetValue().c_str(), "%f %f %f %f %f %f %f %f %f ",&mat[0][0],&mat[0][1],&mat[0][2],&mat[1][0],&mat[1][1],&mat[1][2],&mat[2][0],&mat[2][1],&mat[2][2]);
  346. sprintf(val, "%g %g %g %g %g %g %g %g %g",mat[0][0],mat[0][1],mat[0][2],mat[1][0],mat[1][1],mat[1][2],mat[2][0],mat[2][1],mat[2][2]);
  347. } else {
  348. float f = atof(kv->GetValue().c_str());
  349. sprintf(val, "%g", f);
  350. }
  351. dict->Set(kv->GetKey(), val);
  352. break;
  353. }
  354. }
  355. }
  356. }
  357. void ParseEpair(idDict *dict) {
  358. idStr key = token;
  359. GetToken(false);
  360. idStr val = token;
  361. if (key.Length() > 0) {
  362. dict->Set(key, val);
  363. }
  364. }
  365. /*
  366. =======================================================================================================================
  367. =======================================================================================================================
  368. */
  369. bool EntityHasModel(entity_t *ent) {
  370. if (ent) {
  371. const char *model = ValueForKey(ent, "model");
  372. const char *name = ValueForKey(ent, "name");
  373. if (model && *model) {
  374. if ( idStr::Icmp(model, name) ) {
  375. return true;
  376. }
  377. }
  378. }
  379. return false;
  380. }
  381. /*
  382. =======================================================================================================================
  383. =======================================================================================================================
  384. */
  385. entity_t *Entity_New() {
  386. entity_t *ent = new entity_t;
  387. ent->prev = ent->next = NULL;
  388. ent->brushes.prev = ent->brushes.next = NULL;
  389. ent->brushes.oprev = ent->brushes.onext = NULL;
  390. ent->brushes.owner = NULL;
  391. ent->undoId = 0;
  392. ent->redoId = 0;
  393. ent->entityId = g_entityId++;
  394. ent->origin.Zero();
  395. ent->eclass = NULL;
  396. ent->md3Class = NULL;
  397. ent->lightOrigin.Zero();
  398. ent->lightRotation.Identity();
  399. ent->trackLightOrigin = false;
  400. ent->rotation.Identity();
  401. ent->lightDef = -1;
  402. ent->modelDef = -1;
  403. ent->soundEmitter = NULL;
  404. ent->curve = NULL;
  405. return ent;
  406. }
  407. void Entity_UpdateCurveData( entity_t *ent ) {
  408. if ( ent == NULL || ent->curve == NULL ) {
  409. return;
  410. }
  411. const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
  412. if ( kv == NULL ) {
  413. if ( ent->curve ) {
  414. delete ent->curve;
  415. ent->curve = NULL;
  416. if ( g_qeglobals.d_select_mode == sel_editpoint ) {
  417. g_qeglobals.d_select_mode = sel_brush;
  418. }
  419. }
  420. return;
  421. }
  422. int c = ent->curve->GetNumValues();
  423. idStr str = va( "%i ( ", c );
  424. idVec3 v;
  425. for ( int i = 0; i < c; i++ ) {
  426. v = ent->curve->GetValue( i );
  427. str += " ";
  428. str += v.ToString();
  429. str += " ";
  430. }
  431. str += " )";
  432. ent->epairs.Set( kv->GetKey(), str );
  433. }
  434. idCurve<idVec3> *Entity_MakeCurve( entity_t *ent ) {
  435. const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
  436. if ( kv ) {
  437. idStr str = kv->GetKey().Right( kv->GetKey().Length() - strlen( CURVE_TAG ) );
  438. if ( str.Icmp( "CatmullRomSpline" ) == 0 ) {
  439. return new idCurve_CatmullRomSpline<idVec3>();
  440. } else if ( str.Icmp( "Nurbs" ) == 0 ) {
  441. return new idCurve_NURBS<idVec3>();
  442. }
  443. }
  444. return NULL;
  445. }
  446. void Entity_SetCurveData( entity_t *ent ) {
  447. ent->curve = Entity_MakeCurve( ent );
  448. const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
  449. if ( kv && ent->curve ) {
  450. idLexer lex;
  451. lex.LoadMemory( kv->GetValue(), kv->GetValue().Length(), "_curve" );
  452. int numPoints = lex.ParseInt();
  453. if ( numPoints > 0 ) {
  454. float *fp = new float[numPoints * 3];
  455. lex.Parse1DMatrix( numPoints * 3, fp );
  456. int time = 0;
  457. for ( int i = 0; i < numPoints * 3; i += 3 ) {
  458. idVec3 v;
  459. v.x = fp[i];
  460. v.y = fp[i+1];
  461. v.z = fp[i+2];
  462. ent->curve->AddValue( time, v );
  463. time += 100;
  464. }
  465. delete []fp;
  466. }
  467. }
  468. }
  469. entity_t *Entity_PostParse(entity_t *ent, brush_t *pList) {
  470. bool has_brushes;
  471. eclass_t *e;
  472. brush_t *b;
  473. idVec3 mins, maxs, zero;
  474. idBounds bo;
  475. zero.Zero();
  476. Entity_SetCurveData( ent );
  477. if (ent->brushes.onext == &ent->brushes) {
  478. has_brushes = false;
  479. }
  480. else {
  481. has_brushes = true;
  482. }
  483. bool needsOrigin = !GetVectorForKey(ent, "origin", ent->origin);
  484. const char *pModel = ValueForKey(ent, "model");
  485. const char *cp = ValueForKey(ent, "classname");
  486. if (strlen(cp)) {
  487. e = Eclass_ForName(cp, has_brushes);
  488. } else {
  489. const char *cp2 = ValueForKey(ent, "name");
  490. if (strlen(cp2)) {
  491. char buff[1024];
  492. strcpy(buff, cp2);
  493. int len = strlen(buff);
  494. while ((isdigit(buff[len-1]) || buff[len-1] == '_') && len > 0) {
  495. buff[len-1] = '\0';
  496. len--;
  497. }
  498. e = Eclass_ForName(buff, has_brushes);
  499. SetKeyValue(ent, "classname", buff, false);
  500. } else {
  501. e = Eclass_ForName("", has_brushes);
  502. }
  503. }
  504. idStr str;
  505. if (e->defArgs.GetString("model", "", str) && e->entityModel == NULL) {
  506. e->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &e->defArgs );
  507. }
  508. ent->eclass = e;
  509. bool hasModel = EntityHasModel(ent);
  510. if (hasModel) {
  511. ent->eclass->defArgs.GetString("model", "", str);
  512. if (str.Length()) {
  513. hasModel = false;
  514. ent->epairs.Delete("model");
  515. }
  516. }
  517. if (e->nShowFlags & ECLASS_WORLDSPAWN) {
  518. ent->origin.Zero();
  519. needsOrigin = false;
  520. ent->epairs.Delete( "model" );
  521. } else if (e->nShowFlags & ECLASS_LIGHT) {
  522. if (GetVectorForKey(ent, "light_origin", ent->lightOrigin)) {
  523. GetMatrixForKey(ent, "light_rotation", ent->lightRotation);
  524. ent->trackLightOrigin = true;
  525. } else if (hasModel) {
  526. SetKeyValue(ent, "light_origin", ValueForKey(ent, "origin"));
  527. ent->lightOrigin = ent->origin;
  528. if (GetMatrixForKey(ent, "rotation", ent->lightRotation)) {
  529. SetKeyValue(ent, "light_rotation", ValueForKey(ent, "rotation"));
  530. }
  531. ent->trackLightOrigin = true;
  532. }
  533. } else if ( e->nShowFlags & ECLASS_ENV ) {
  534. // need to create an origin from the bones here
  535. idVec3 org;
  536. idAngles ang;
  537. bo.Clear();
  538. bool hasBody = false;
  539. const idKeyValue *arg = ent->epairs.MatchPrefix( "body ", NULL );
  540. while ( arg ) {
  541. sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
  542. bo.AddPoint( org );
  543. arg = ent->epairs.MatchPrefix( "body ", arg );
  544. hasBody = true;
  545. }
  546. if (hasBody) {
  547. ent->origin = bo.GetCenter();
  548. }
  549. }
  550. if (e->fixedsize || hasModel) { // fixed size entity
  551. if (ent->brushes.onext != &ent->brushes) {
  552. for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
  553. b->entityModel = true;
  554. }
  555. }
  556. if (hasModel) {
  557. // model entity
  558. idRenderModel *modelHandle = renderModelManager->FindModel( pModel );
  559. if ( dynamic_cast<idRenderModelPrt*>( modelHandle ) || dynamic_cast<idRenderModelLiquid*>( modelHandle ) ) {
  560. bo.Zero();
  561. bo.ExpandSelf( 12.0f );
  562. } else {
  563. bo = modelHandle->Bounds( NULL );
  564. }
  565. VectorCopy(bo[0], mins);
  566. VectorCopy(bo[1], maxs);
  567. for (int i = 0; i < 3; i++) {
  568. if (mins[i] == maxs[i]) {
  569. mins[i]--;
  570. maxs[i]++;
  571. }
  572. }
  573. VectorAdd(mins, ent->origin, mins);
  574. VectorAdd(maxs, ent->origin, maxs);
  575. b = Brush_Create(mins, maxs, &e->texdef);
  576. b->modelHandle = modelHandle;
  577. float yaw = 0;
  578. bool convertAngles = GetFloatForKey(ent, "angle", &yaw);
  579. extern void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild);
  580. extern void Brush_Rotate(brush_t *b, idVec3 rot, idVec3 origin, bool bBuild);
  581. if (convertAngles) {
  582. idVec3 rot(0, 0, yaw);
  583. Brush_Rotate(b, rot, ent->origin, false);
  584. }
  585. if (GetMatrixForKey(ent, "rotation", ent->rotation)) {
  586. idBounds bo2;
  587. bo2.FromTransformedBounds(bo, ent->origin, ent->rotation);
  588. b->owner = ent;
  589. Brush_Resize(b, bo2[0], bo2[1]);
  590. }
  591. Entity_LinkBrush(ent, b);
  592. }
  593. if (!hasModel || (ent->eclass->nShowFlags & ECLASS_LIGHT && hasModel)) {
  594. // create a custom brush
  595. if (ent->trackLightOrigin) {
  596. mins = e->mins + ent->lightOrigin;
  597. maxs = e->maxs + ent->lightOrigin;
  598. } else {
  599. mins = e->mins + ent->origin;
  600. maxs = e->maxs + ent->origin;
  601. }
  602. b = Brush_Create(mins, maxs, &e->texdef);
  603. GetMatrixForKey(ent, "rotation", ent->rotation);
  604. Entity_LinkBrush(ent, b);
  605. b->trackLightOrigin = ent->trackLightOrigin;
  606. if ( e->texdef.name == NULL ) {
  607. brushprimit_texdef_t bp;
  608. texdef_t td;
  609. td.SetName( ent->eclass->defMaterial );
  610. Brush_SetTexture( b, &td, &bp, false );
  611. }
  612. }
  613. } else { // brush entity
  614. if (ent->brushes.next == &ent->brushes) {
  615. printf("Warning: Brush entity with no brushes\n");
  616. }
  617. if (!needsOrigin) {
  618. idStr cn = ValueForKey(ent, "classname");
  619. idStr name = ValueForKey(ent, "name");
  620. idStr model = ValueForKey(ent, "model");
  621. if (cn.Icmp("func_static") == 0) {
  622. if (name.Icmp(model) == 0) {
  623. needsOrigin = true;
  624. }
  625. }
  626. }
  627. if (needsOrigin) {
  628. idVec3 mins, maxs, mid;
  629. int i;
  630. char text[32];
  631. mins[0] = mins[1] = mins[2] = 999999;
  632. maxs[0] = maxs[1] = maxs[2] = -999999;
  633. // add in the origin
  634. for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
  635. Brush_Build(b, true, false, false);
  636. for (i = 0; i < 3; i++) {
  637. if (b->mins[i] < mins[i]) {
  638. mins[i] = b->mins[i];
  639. }
  640. if (b->maxs[i] > maxs[i]) {
  641. maxs[i] = b->maxs[i];
  642. }
  643. }
  644. }
  645. for (i = 0; i < 3; i++) {
  646. ent->origin[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
  647. }
  648. sprintf(text, "%i %i %i", (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
  649. SetKeyValue(ent, "origin", text);
  650. }
  651. if (!(e->nShowFlags & ECLASS_WORLDSPAWN)) {
  652. if (e->defArgs.FindKey("model") == NULL && (pModel == NULL || (pModel && strlen(pModel) == 0))) {
  653. SetKeyValue(ent, "model", ValueForKey(ent, "name"));
  654. }
  655. }
  656. else {
  657. DeleteKey(ent, "origin");
  658. }
  659. }
  660. // add all the brushes to the main list
  661. if (pList) {
  662. for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
  663. b->next = pList->next;
  664. pList->next->prev = b;
  665. b->prev = pList;
  666. pList->next = b;
  667. }
  668. }
  669. FixFloats(&ent->epairs);
  670. return ent;
  671. }
  672. /*
  673. =======================================================================================================================
  674. Entity_Parse If onlypairs is set, the classname info will not be looked up, and the entity will not be added to the
  675. global list. Used for parsing the project.
  676. =======================================================================================================================
  677. */
  678. entity_t *Entity_Parse(bool onlypairs, brush_t *pList) {
  679. entity_t *ent;
  680. if (!GetToken(true)) {
  681. return NULL;
  682. }
  683. if (strcmp(token, "{")) {
  684. Error("ParseEntity: { not found");
  685. }
  686. ent = Entity_New();
  687. ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
  688. ent->origin.Zero();
  689. int n = 0;
  690. do {
  691. if (!GetToken(true)) {
  692. Warning("ParseEntity: EOF without closing brace");
  693. return NULL;
  694. }
  695. if (!strcmp(token, "}")) {
  696. break;
  697. }
  698. if (!strcmp(token, "{")) {
  699. GetVectorForKey(ent, "origin", ent->origin);
  700. brush_t *b = Brush_Parse(ent->origin);
  701. if (b != NULL) {
  702. b->owner = ent;
  703. // add to the end of the entity chain
  704. b->onext = &ent->brushes;
  705. b->oprev = ent->brushes.oprev;
  706. ent->brushes.oprev->onext = b;
  707. ent->brushes.oprev = b;
  708. }
  709. else {
  710. break;
  711. }
  712. }
  713. else {
  714. ParseEpair(&ent->epairs);
  715. }
  716. } while (1);
  717. if (onlypairs) {
  718. return ent;
  719. }
  720. return Entity_PostParse(ent, pList);
  721. }
  722. /*
  723. =======================================================================================================================
  724. =======================================================================================================================
  725. */
  726. void VectorMidpoint(idVec3 va, idVec3 vb, idVec3 &out) {
  727. for (int i = 0; i < 3; i++) {
  728. out[i] = va[i] + ((vb[i] - va[i]) / 2);
  729. }
  730. }
  731. /*
  732. =======================================================================================================================
  733. Entity_Write
  734. =======================================================================================================================
  735. */
  736. void Entity_Write(entity_t *e, FILE *f, bool use_region) {
  737. brush_t *b;
  738. idVec3 origin;
  739. char text[128];
  740. int count;
  741. // if none of the entities brushes are in the region, don't write the entity at all
  742. if (use_region) {
  743. // in region mode, save the camera position as playerstart
  744. if (!strcmp(ValueForKey(e, "classname"), "info_player_start")) {
  745. fprintf(f, "{\n");
  746. fprintf(f, "\"classname\" \"info_player_start\"\n");
  747. fprintf
  748. (
  749. f,
  750. "\"origin\" \"%i %i %i\"\n",
  751. (int)g_pParentWnd->GetCamera()->Camera().origin[0],
  752. (int)g_pParentWnd->GetCamera()->Camera().origin[1],
  753. (int)g_pParentWnd->GetCamera()->Camera().origin[2]
  754. );
  755. fprintf(f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamera()->Camera().angles[YAW]);
  756. fprintf(f, "}\n");
  757. return;
  758. }
  759. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  760. if (!Map_IsBrushFiltered(b)) {
  761. break; // got one
  762. }
  763. }
  764. if (b == &e->brushes) {
  765. return; // nothing visible
  766. }
  767. }
  768. if (e->eclass->nShowFlags & ECLASS_PLUGINENTITY) {
  769. // NOTE: the whole brush placement / origin stuff is a mess
  770. VectorCopy(e->origin, origin);
  771. sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  772. SetKeyValue(e, "origin", text);
  773. }
  774. // if fixedsize, calculate a new origin based on the current brush position
  775. else if (e->eclass->fixedsize || EntityHasModel(e)) {
  776. if (!GetVectorForKey(e, "origin", origin)) {
  777. VectorSubtract(e->brushes.onext->mins, e->eclass->mins, origin);
  778. sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  779. SetKeyValue(e, "origin", text);
  780. }
  781. }
  782. fprintf(f, "{\n");
  783. count = e->epairs.GetNumKeyVals();
  784. for (int j = 0; j < count; j++) {
  785. fprintf(f, "\"%s\" \"%s\"\n", e->epairs.GetKeyVal(j)->GetKey().c_str(), e->epairs.GetKeyVal(j)->GetValue().c_str());
  786. }
  787. if (!EntityHasModel(e)) {
  788. count = 0;
  789. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  790. if (e->eclass->fixedsize && !b->entityModel) {
  791. continue;
  792. }
  793. if (!use_region || !Map_IsBrushFiltered(b)) {
  794. fprintf(f, "// brush %i\n", count);
  795. count++;
  796. Brush_Write( b, f, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
  797. }
  798. }
  799. }
  800. fprintf(f, "}\n");
  801. }
  802. /*
  803. =======================================================================================================================
  804. =======================================================================================================================
  805. */
  806. bool IsBrushSelected(brush_t *bSel) {
  807. for (brush_t * b = selected_brushes.next; b != NULL && b != &selected_brushes; b = b->next) {
  808. if (b == bSel) {
  809. return true;
  810. }
  811. }
  812. return false;
  813. }
  814. //
  815. // =======================================================================================================================
  816. // Entity_WriteSelected
  817. // =======================================================================================================================
  818. //
  819. void Entity_WriteSelected(entity_t *e, FILE *f) {
  820. brush_t *b;
  821. idVec3 origin;
  822. char text[128];
  823. int count;
  824. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  825. if (IsBrushSelected(b)) {
  826. break; // got one
  827. }
  828. }
  829. if (b == &e->brushes) {
  830. return; // nothing selected
  831. }
  832. // if fixedsize, calculate a new origin based on the current brush position
  833. if (e->eclass->fixedsize || EntityHasModel(e)) {
  834. if (!GetVectorForKey(e, "origin", origin)) {
  835. VectorSubtract(e->brushes.onext->mins, e->eclass->mins, origin);
  836. sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  837. SetKeyValue(e, "origin", text);
  838. }
  839. }
  840. fprintf(f, "{\n");
  841. count = e->epairs.GetNumKeyVals();
  842. for (int j = 0; j < count; j++) {
  843. fprintf(f, "\"%s\" \"%s\"\n", e->epairs.GetKeyVal(j)->GetKey().c_str(), e->epairs.GetKeyVal(j)->GetValue().c_str());
  844. }
  845. if (!EntityHasModel(e)) {
  846. count = 0;
  847. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  848. if (e->eclass->fixedsize && !b->entityModel) {
  849. continue;
  850. }
  851. if (IsBrushSelected(b)) {
  852. fprintf(f, "// brush %i\n", count);
  853. count++;
  854. Brush_Write( b, f, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
  855. }
  856. }
  857. }
  858. fprintf(f, "}\n");
  859. }
  860. //
  861. // =======================================================================================================================
  862. // Entity_WriteSelected to a CMemFile
  863. // =======================================================================================================================
  864. //
  865. void Entity_WriteSelected(entity_t *e, CMemFile *pMemFile) {
  866. brush_t *b;
  867. idVec3 origin;
  868. char text[128];
  869. int count;
  870. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  871. if (IsBrushSelected(b)) {
  872. break; // got one
  873. }
  874. }
  875. if (b == &e->brushes) {
  876. return; // nothing selected
  877. }
  878. // if fixedsize, calculate a new origin based on the current brush position
  879. if (e->eclass->fixedsize || EntityHasModel(e)) {
  880. if (!GetVectorForKey(e, "origin", origin)) {
  881. VectorSubtract(e->brushes.onext->mins, e->eclass->mins, origin);
  882. sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  883. SetKeyValue(e, "origin", text);
  884. }
  885. }
  886. MemFile_fprintf(pMemFile, "{\n");
  887. count = e->epairs.GetNumKeyVals();
  888. for (int j = 0; j < count; j++) {
  889. MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", e->epairs.GetKeyVal(j)->GetKey().c_str(), e->epairs.GetKeyVal(j)->GetValue().c_str());
  890. }
  891. if (!EntityHasModel(e)) {
  892. count = 0;
  893. for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
  894. if (e->eclass->fixedsize && !b->entityModel) {
  895. continue;
  896. }
  897. if (IsBrushSelected(b)) {
  898. MemFile_fprintf(pMemFile, "// brush %i\n", count);
  899. count++;
  900. Brush_Write( b, pMemFile, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
  901. }
  902. }
  903. }
  904. MemFile_fprintf(pMemFile, "}\n");
  905. }
  906. /*
  907. =======================================================================================================================
  908. =======================================================================================================================
  909. */
  910. void Entity_SetName(entity_t *e, const char *name) {
  911. CString oldName = ValueForKey(e, "name");
  912. CString oldModel = ValueForKey(e, "model");
  913. SetKeyValue(e, "name", name);
  914. if (oldName == oldModel) {
  915. SetKeyValue(e, "model", name);
  916. }
  917. }
  918. extern bool Entity_NameIsUnique(const char *name);
  919. /*
  920. =======================================================================================================================
  921. =======================================================================================================================
  922. */
  923. void Entity_Name(entity_t *e, bool force) {
  924. const char *name = ValueForKey(e, "name");
  925. if (!force && name && name[0]) {
  926. return;
  927. }
  928. if (name && name[0] && Entity_NameIsUnique(name)) {
  929. return;
  930. }
  931. bool setModel = false;
  932. if (name[0]) {
  933. const char *model = ValueForKey(e, "model");
  934. if (model[0]) {
  935. if ( idStr::Icmp(model, name) == 0 ) {
  936. setModel = true;
  937. }
  938. }
  939. }
  940. const char *eclass = ValueForKey(e, "classname");
  941. if (eclass && eclass[0]) {
  942. idStr str = cvarSystem->GetCVarString( "radiant_nameprefix" );
  943. int id = Map_GetUniqueEntityID(str, eclass);
  944. if (str.Length()) {
  945. SetKeyValue(e, "name", va("%s_%s_%i", str.c_str(), eclass, id));
  946. } else {
  947. SetKeyValue(e, "name", va("%s_%i", eclass, id));
  948. }
  949. if (setModel) {
  950. if (str.Length()) {
  951. SetKeyValue(e, "model", va("%s_%s_%i", str.c_str(), eclass, id));
  952. } else {
  953. SetKeyValue(e, "model", va("%s_%i", eclass, id));
  954. }
  955. }
  956. }
  957. }
  958. /*
  959. =======================================================================================================================
  960. Entity_Create Creates a new entity out of the selected_brushes list. If the entity class is fixed size, the brushes
  961. are only used to find a midpoint. Otherwise, the brushes have their ownership transfered to the new entity.
  962. =======================================================================================================================
  963. */
  964. entity_t *Entity_Create(eclass_t *c, bool forceFixed) {
  965. entity_t *e;
  966. brush_t *b;
  967. idVec3 mins, maxs, origin;
  968. char text[32];
  969. texdef_t td;
  970. brushprimit_texdef_t bp;
  971. // check to make sure the brushes are ok
  972. for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
  973. if (b->owner != world_entity) {
  974. Sys_Status("Entity NOT created, brushes not all from world\n");
  975. Sys_Beep();
  976. return NULL;
  977. }
  978. }
  979. idStr str;
  980. if (c->defArgs.GetString("model", "", str) && c->entityModel == NULL) {
  981. c->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &c->defArgs );
  982. }
  983. // create it
  984. e = Entity_New();
  985. e->brushes.onext = e->brushes.oprev = &e->brushes;
  986. e->eclass = c;
  987. e->epairs.Copy(c->args);
  988. SetKeyValue(e, "classname", c->name);
  989. Entity_Name(e, false);
  990. // add the entity to the entity list
  991. Entity_AddToList(e, &entities);
  992. if (c->fixedsize) {
  993. //
  994. // just use the selection for positioning b = selected_brushes.next; for (i=0 ;
  995. // i<3 ; i++) { e->origin[i] = b->mins[i] - c->mins[i]; }
  996. //
  997. Select_GetMid(e->origin);
  998. VectorCopy(e->origin, origin);
  999. // create a custom brush
  1000. VectorAdd(c->mins, e->origin, mins);
  1001. VectorAdd(c->maxs, e->origin, maxs);
  1002. b = Brush_Create(mins, maxs, &c->texdef);
  1003. Entity_LinkBrush(e, b);
  1004. if (c->defMaterial.Length()) {
  1005. td.SetName(c->defMaterial);
  1006. Brush_SetTexture(b, &td, &bp, false);
  1007. }
  1008. // delete the current selection
  1009. Select_Delete();
  1010. // select the new brush
  1011. b->next = b->prev = &selected_brushes;
  1012. selected_brushes.next = selected_brushes.prev = b;
  1013. Brush_Build(b);
  1014. }
  1015. else {
  1016. Select_GetMid(origin);
  1017. // change the selected brushes over to the new entity
  1018. for (b = selected_brushes.next; b != &selected_brushes; b = b->next) {
  1019. Entity_UnlinkBrush(b);
  1020. Entity_LinkBrush(e, b);
  1021. Brush_Build(b); // so the key brush gets a name
  1022. if (c->defMaterial.Length()) {
  1023. td.SetName(c->defMaterial);
  1024. Brush_SetTexture(b, &td, &bp, false);
  1025. }
  1026. }
  1027. //for (int i = 0; i < 3; i++) {
  1028. // origin[i] = vMin[i] + vMax[i] * 0.5;
  1029. //}
  1030. if (!forceFixed) {
  1031. SetKeyValue(e, "model", ValueForKey(e, "name"));
  1032. }
  1033. }
  1034. sprintf(text, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]);
  1035. SetKeyValue(e, "origin", text);
  1036. VectorCopy(origin, e->origin);
  1037. Sys_UpdateWindows(W_ALL);
  1038. return e;
  1039. }
  1040. void Brush_MakeDirty(brush_t *b) {
  1041. for (face_t *f = b->brush_faces; f; f = f->next) {
  1042. f->dirty = true;
  1043. }
  1044. }
  1045. /*
  1046. =======================================================================================================================
  1047. Entity_LinkBrush
  1048. =======================================================================================================================
  1049. */
  1050. void Entity_LinkBrush(entity_t *e, brush_t *b) {
  1051. if (b->oprev || b->onext) {
  1052. Error("Entity_LinkBrush: Allready linked");
  1053. }
  1054. Brush_MakeDirty(b);
  1055. b->owner = e;
  1056. b->onext = e->brushes.onext;
  1057. b->oprev = &e->brushes;
  1058. e->brushes.onext->oprev = b;
  1059. e->brushes.onext = b;
  1060. }
  1061. /*
  1062. =======================================================================================================================
  1063. Entity_UnlinkBrush
  1064. =======================================================================================================================
  1065. */
  1066. void Entity_UnlinkBrush(brush_t *b) {
  1067. // if (!b->owner || !b->onext || !b->oprev)
  1068. if (!b->onext || !b->oprev) {
  1069. Error("Entity_UnlinkBrush: Not currently linked");
  1070. }
  1071. b->onext->oprev = b->oprev;
  1072. b->oprev->onext = b->onext;
  1073. b->onext = b->oprev = NULL;
  1074. b->owner = NULL;
  1075. }
  1076. /*
  1077. =======================================================================================================================
  1078. Entity_Clone
  1079. =======================================================================================================================
  1080. */
  1081. entity_t *Entity_Clone(entity_t *e) {
  1082. entity_t *n;
  1083. n = Entity_New();
  1084. n->brushes.onext = n->brushes.oprev = &n->brushes;
  1085. n->eclass = e->eclass;
  1086. n->rotation = e->rotation;
  1087. n->origin = e->origin;
  1088. // add the entity to the entity list
  1089. Entity_AddToList(n, &entities);
  1090. n->epairs = e->epairs;
  1091. return n;
  1092. }
  1093. /*
  1094. =======================================================================================================================
  1095. =======================================================================================================================
  1096. */
  1097. int GetUniqueTargetId(int iHint) {
  1098. int iMin, iMax, i;
  1099. BOOL fFound;
  1100. entity_t *pe;
  1101. fFound = FALSE;
  1102. pe = entities.next;
  1103. iMin = 0;
  1104. iMax = 0;
  1105. for (; pe != NULL && pe != &entities; pe = pe->next) {
  1106. i = IntForKey(pe, "target");
  1107. if (i) {
  1108. iMin = Min(i, iMin);
  1109. iMax = Max(i, iMax);
  1110. if (i == iHint) {
  1111. fFound = TRUE;
  1112. }
  1113. }
  1114. }
  1115. if (fFound) {
  1116. return iMax + 1;
  1117. }
  1118. else {
  1119. return iHint;
  1120. }
  1121. }
  1122. /*
  1123. =======================================================================================================================
  1124. =======================================================================================================================
  1125. */
  1126. entity_t *FindEntity(const char *pszKey, const char *pszValue) {
  1127. entity_t *pe;
  1128. pe = entities.next;
  1129. for (; pe != NULL && pe != &entities; pe = pe->next) {
  1130. if (!strcmp(ValueForKey(pe, pszKey), pszValue)) {
  1131. return pe;
  1132. }
  1133. }
  1134. return NULL;
  1135. }
  1136. /*
  1137. =======================================================================================================================
  1138. =======================================================================================================================
  1139. */
  1140. entity_t *FindEntityInt(const char *pszKey, int iValue) {
  1141. entity_t *pe;
  1142. pe = entities.next;
  1143. for (; pe != NULL && pe != &entities; pe = pe->next) {
  1144. if (IntForKey(pe, pszKey) == iValue) {
  1145. return pe;
  1146. }
  1147. }
  1148. return NULL;
  1149. }
  1150. /*
  1151. ====================
  1152. Entity_UpdateSoundEmitter
  1153. Deletes the soundEmitter if the entity should not emit a sound due
  1154. to it not having one, being filtered away, or the sound mode being turned off.
  1155. Creates or updates the soundEmitter if needed
  1156. ====================
  1157. */
  1158. void Entity_UpdateSoundEmitter( entity_t *ent ) {
  1159. bool playing = false;
  1160. // if an entity doesn't have any brushes at all, don't do anything
  1161. // if the brush isn't displayed (filtered or culled), don't do anything
  1162. if ( g_pParentWnd->GetCamera()->GetSoundMode()
  1163. && ent->brushes.onext != &ent->brushes && !FilterBrush(ent->brushes.onext) ) {
  1164. // check for sounds
  1165. const char *v = ValueForKey( ent, "s_shader" );
  1166. if ( v[0] ) {
  1167. refSound_t sound;
  1168. gameEdit->ParseSpawnArgsToRefSound( &ent->epairs, &sound );
  1169. if ( !sound.waitfortrigger ) { // waitfortrigger will not start playing immediately
  1170. if ( !ent->soundEmitter ) {
  1171. ent->soundEmitter = g_qeglobals.sw->AllocSoundEmitter();
  1172. }
  1173. playing = true;
  1174. ent->soundEmitter->UpdateEmitter( ent->origin, 0, &sound.parms );
  1175. // always play on a single channel, so updates always override
  1176. ent->soundEmitter->StartSound( sound.shader, SCHANNEL_ONE );
  1177. }
  1178. }
  1179. }
  1180. // delete the soundEmitter if not used
  1181. if ( !playing && ent->soundEmitter ) {
  1182. ent->soundEmitter->Free( true );
  1183. ent->soundEmitter = NULL;
  1184. }
  1185. }