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