2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
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.
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.
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/>.
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.
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.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
33 #include "../../renderer/tr_local.h"
34 #include "../../renderer/model_local.h" // for idRenderModelMD5
37 #define CURVE_TAG "curve_"
39 extern void Brush_Resize(brush_t *b, idVec3 vMin, idVec3 vMax);
41 int GetNumKeys(entity_t *ent)
44 // for (epair_t* ep=ent->epairs ; ep ; ep=ep->next)
49 int iCount = ent->epairs.GetNumKeyVals();
53 const char *GetKeyString(entity_t *ent, int iIndex)
55 // for (epair_t* ep=ent->epairs ; ep ; ep=ep->next)
64 if ( iIndex < GetNumKeys(ent) )
66 return ent->epairs.GetKeyVal(iIndex)->GetKey().c_str();
75 =======================================================================================================================
76 =======================================================================================================================
78 const char *ValueForKey(entity_t *ent, const char *key) {
79 return ent->epairs.GetString(key);
83 =======================================================================================================================
84 =======================================================================================================================
86 void TrackMD3Angles(entity_t *e, const char *key, const char *value) {
87 if ( idStr::Icmp(key, "angle") != 0 ) {
91 if ((e->eclass->fixedsize && e->eclass->nShowFlags & ECLASS_MISCMODEL) || EntityHasModel(e)) {
92 float a = FloatForKey(e, "angle");
93 float b = atof(value);
96 vAngle[0] = vAngle[1] = 0;
98 Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
100 Brush_Rotate(e->brushes.onext, vAngle, e->origin, true);
106 =======================================================================================================================
107 =======================================================================================================================
109 void SetKeyValue(entity_t *ent, const char *key, const char *value, bool trackAngles) {
114 if (!key || !key[0]) {
119 TrackMD3Angles(ent, key, value);
122 ent->epairs.Set(key, value);
123 GetVectorForKey(ent, "origin", ent->origin);
125 // update sound in case this key was relevent
126 Entity_UpdateSoundEmitter( ent );
130 =======================================================================================================================
131 =======================================================================================================================
133 void SetKeyVec3(entity_t *ent, const char *key, idVec3 v) {
138 if (!key || !key[0]) {
143 sprintf(str, "%g %g %g", v.x, v.y, v.z);
144 ent->epairs.Set(key, str);
145 GetVectorForKey(ent, "origin", ent->origin);
149 =======================================================================================================================
150 =======================================================================================================================
152 void SetKeyMat3(entity_t *ent, const char *key, idMat3 m) {
157 if (!key || !key[0]) {
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]);
165 ent->epairs.Set(key, str);
166 GetVectorForKey(ent, "origin", ent->origin);
172 =======================================================================================================================
173 =======================================================================================================================
175 void DeleteKey(entity_t *ent, const char *key) {
176 ent->epairs.Delete(key);
177 if (stricmp(key, "rotation") == 0) {
178 ent->rotation.Identity();
183 =======================================================================================================================
184 =======================================================================================================================
186 float FloatForKey(entity_t *ent, const char *key) {
189 k = ValueForKey(ent, key);
198 =======================================================================================================================
199 =======================================================================================================================
201 int IntForKey(entity_t *ent, const char *key) {
204 k = ValueForKey(ent, key);
209 =======================================================================================================================
210 =======================================================================================================================
212 bool GetVectorForKey(entity_t *ent, const char *key, idVec3 &vec) {
214 k = ValueForKey(ent, key);
215 if (k && strlen(k) > 0) {
216 sscanf(k, "%f %f %f", &vec[0], &vec[1], &vec[2]);
220 vec[0] = vec[1] = vec[2] = 0;
227 =======================================================================================================================
228 =======================================================================================================================
230 bool GetVector4ForKey(entity_t *ent, const char *key, idVec4 &vec) {
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]);
238 vec[0] = vec[1] = vec[2] = vec[3] = 0;
245 =======================================================================================================================
246 =======================================================================================================================
248 bool GetFloatForKey(entity_t *ent, const char *key, float *f) {
250 k = ValueForKey(ent, key);
251 if (k && strlen(k) > 0) {
261 =======================================================================================================================
262 =======================================================================================================================
264 bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat) {
266 k = ValueForKey(ent, key);
267 if (k && strlen(k) > 0) {
271 "%f %f %f %f %f %f %f %f %f ",
292 =======================================================================================================================
293 Entity_FreeEpairs Frees the entity epairs.
294 =======================================================================================================================
296 void Entity_FreeEpairs(entity_t *e) {
301 =======================================================================================================================
303 =======================================================================================================================
305 void Entity_AddToList(entity_t *e, entity_t *list) {
306 if (e->next || e->prev) {
307 Error("Entity_AddToList: allready linked");
310 e->next = list->next;
311 list->next->prev = e;
317 =======================================================================================================================
318 Entity_RemoveFromList
319 =======================================================================================================================
321 void Entity_RemoveFromList(entity_t *e) {
322 if ( !e->next || !e->prev ) {
323 Error("Entity_RemoveFromList: not linked");
326 e->next->prev = e->prev;
327 e->prev->next = e->next;
328 e->next = e->prev = NULL;
332 =======================================================================================================================
333 Entity_Free Frees the entity and any brushes is has. The entity is removed from the global entities list.
334 =======================================================================================================================
336 void Entity_Free( entity_t *e ) {
338 while ( e->brushes.onext != &e->brushes ) {
339 Brush_Free(e->brushes.onext);
343 e->next->prev = e->prev;
344 e->prev->next = e->next;
347 Entity_FreeEpairs( e );
353 =======================================================================================================================
355 =======================================================================================================================
358 int Entity_MemorySize( entity_t *e )
363 size = sizeof( entity_t ) + e->epairs.Size();
364 for( b = e->brushes.onext; b != &e->brushes; b = b->onext )
366 size += Brush_MemorySize( b );
372 =======================================================================================================================
374 =======================================================================================================================
383 const EpairFixup FloatFixups[] = {
389 { "light_target", 1 },
391 { "light_right", 1 },
392 { "light_start", 1 },
393 { "light_center", 1 },
395 { "light_radius", 1 },
396 { "light_origin", 1 }
399 const int FixupCount = sizeof(FloatFixups) / sizeof(EpairFixup);
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) {
408 if (FloatFixups[j].type == 1) {
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) {
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]);
417 float f = atof(kv->GetValue().c_str());
418 sprintf(val, "%g", f);
420 dict->Set(kv->GetKey(), val);
427 void ParseEpair(idDict *dict) {
432 if (key.Length() > 0) {
438 =======================================================================================================================
439 =======================================================================================================================
441 bool EntityHasModel(entity_t *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) ) {
456 =======================================================================================================================
457 =======================================================================================================================
459 entity_t *Entity_New() {
460 entity_t *ent = new entity_t;
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;
468 ent->entityId = g_entityId++;
471 ent->md3Class = NULL;
472 ent->lightOrigin.Zero();
473 ent->lightRotation.Identity();
474 ent->trackLightOrigin = false;
475 ent->rotation.Identity();
478 ent->soundEmitter = NULL;
483 void Entity_UpdateCurveData( entity_t *ent ) {
485 if ( ent == NULL || ent->curve == NULL ) {
489 const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
494 if ( g_qeglobals.d_select_mode == sel_editpoint ) {
495 g_qeglobals.d_select_mode = sel_brush;
501 int c = ent->curve->GetNumValues();
502 idStr str = va( "%i ( ", c );
504 for ( int i = 0; i < c; i++ ) {
505 v = ent->curve->GetValue( i );
512 ent->epairs.Set( kv->GetKey(), str );
516 idCurve<idVec3> *Entity_MakeCurve( entity_t *ent ) {
517 const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
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>();
529 void Entity_SetCurveData( entity_t *ent ) {
531 ent->curve = Entity_MakeCurve( ent );
532 const idKeyValue *kv = ent->epairs.MatchPrefix( CURVE_TAG );
533 if ( kv && ent->curve ) {
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 );
541 for ( int i = 0; i < numPoints * 3; i += 3 ) {
546 ent->curve->AddValue( time, v );
555 entity_t *Entity_PostParse(entity_t *ent, brush_t *pList) {
559 idVec3 mins, maxs, zero;
564 Entity_SetCurveData( ent );
566 if (ent->brushes.onext == &ent->brushes) {
573 bool needsOrigin = !GetVectorForKey(ent, "origin", ent->origin);
574 const char *pModel = ValueForKey(ent, "model");
576 const char *cp = ValueForKey(ent, "classname");
579 e = Eclass_ForName(cp, has_brushes);
581 const char *cp2 = ValueForKey(ent, "name");
585 int len = strlen(buff);
586 while ((isdigit(buff[len-1]) || buff[len-1] == '_') && len > 0) {
590 e = Eclass_ForName(buff, has_brushes);
591 SetKeyValue(ent, "classname", buff, false);
593 e = Eclass_ForName("", has_brushes);
599 if (e->defArgs.GetString("model", "", str) && e->entityModel == NULL) {
600 e->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &e->defArgs );
605 bool hasModel = EntityHasModel(ent);
608 ent->eclass->defArgs.GetString("model", "", str);
611 ent->epairs.Delete("model");
615 if (e->nShowFlags & ECLASS_WORLDSPAWN) {
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"));
629 ent->trackLightOrigin = true;
631 } else if ( e->nShowFlags & ECLASS_ENV ) {
632 // need to create an origin from the bones here
636 bool hasBody = false;
637 const idKeyValue *arg = ent->epairs.MatchPrefix( "body ", NULL );
639 sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
641 arg = ent->epairs.MatchPrefix( "body ", arg );
645 ent->origin = bo.GetCenter();
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;
658 idRenderModel *modelHandle = renderModelManager->FindModel( pModel );
660 if ( dynamic_cast<idRenderModelPrt*>( modelHandle ) || dynamic_cast<idRenderModelLiquid*>( modelHandle ) ) {
662 bo.ExpandSelf( 12.0f );
664 bo = modelHandle->Bounds( NULL );
667 VectorCopy(bo[0], mins);
668 VectorCopy(bo[1], maxs);
669 for (int i = 0; i < 3; i++) {
670 if (mins[i] == maxs[i]) {
675 VectorAdd(mins, ent->origin, mins);
676 VectorAdd(maxs, ent->origin, maxs);
677 b = Brush_Create(mins, maxs, &e->texdef);
678 b->modelHandle = modelHandle;
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);
686 idVec3 rot(0, 0, yaw);
687 Brush_Rotate(b, rot, ent->origin, false);
690 if (GetMatrixForKey(ent, "rotation", ent->rotation)) {
692 bo2.FromTransformedBounds(bo, ent->origin, ent->rotation);
694 Brush_Resize(b, bo2[0], bo2[1]);
696 Entity_LinkBrush(ent, b);
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;
705 mins = e->mins + ent->origin;
706 maxs = e->maxs + ent->origin;
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;
716 td.SetName( ent->eclass->defMaterial );
717 Brush_SetTexture( b, &td, &bp, false );
720 } else { // brush entity
721 if (ent->brushes.next == &ent->brushes) {
722 printf("Warning: Brush entity with no brushes\n");
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) {
737 idVec3 mins, maxs, mid;
740 mins[0] = mins[1] = mins[2] = 999999;
741 maxs[0] = maxs[1] = maxs[2] = -999999;
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];
751 if (b->maxs[i] > maxs[i]) {
752 maxs[i] = b->maxs[i];
757 for (i = 0; i < 3; i++) {
758 ent->origin[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
761 sprintf(text, "%i %i %i", (int)ent->origin[0], (int)ent->origin[1], (int)ent->origin[2]);
762 SetKeyValue(ent, "origin", text);
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"));
771 DeleteKey(ent, "origin");
775 // add all the brushes to the main list
777 for (b = ent->brushes.onext; b != &ent->brushes; b = b->onext) {
778 b->next = pList->next;
779 pList->next->prev = b;
785 FixFloats(&ent->epairs);
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 =======================================================================================================================
797 entity_t *Entity_Parse(bool onlypairs, brush_t *pList) {
800 if (!GetToken(true)) {
804 if (strcmp(token, "{")) {
805 Error("ParseEntity: { not found");
809 ent->brushes.onext = ent->brushes.oprev = &ent->brushes;
814 if (!GetToken(true)) {
815 Warning("ParseEntity: EOF without closing brace");
819 if (!strcmp(token, "}")) {
823 if (!strcmp(token, "{")) {
824 GetVectorForKey(ent, "origin", ent->origin);
825 brush_t *b = Brush_Parse(ent->origin);
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;
840 ParseEpair(&ent->epairs);
848 return Entity_PostParse(ent, pList);
852 =======================================================================================================================
853 =======================================================================================================================
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);
862 =======================================================================================================================
864 =======================================================================================================================
866 void Entity_Write(entity_t *e, FILE *f, bool use_region) {
872 // if none of the entities brushes are in the region, don't write the entity at all
874 // in region mode, save the camera position as playerstart
875 if (!strcmp(ValueForKey(e, "classname"), "info_player_start")) {
877 fprintf(f, "\"classname\" \"info_player_start\"\n");
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]
886 fprintf(f, "\"angle\" \"%i\"\n", (int)g_pParentWnd->GetCamera()->Camera().angles[YAW]);
891 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
892 if (!Map_IsBrushFiltered(b)) {
897 if (b == &e->brushes) {
898 return; // nothing visible
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);
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);
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());
925 if (!EntityHasModel(e)) {
927 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
928 if (e->eclass->fixedsize && !b->entityModel) {
931 if (!use_region || !Map_IsBrushFiltered(b)) {
932 fprintf(f, "// brush %i\n", count);
934 Brush_Write( b, f, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
943 =======================================================================================================================
944 =======================================================================================================================
946 bool IsBrushSelected(brush_t *bSel) {
947 for (brush_t * b = selected_brushes.next; b != NULL && b != &selected_brushes; b = b->next) {
957 // =======================================================================================================================
958 // Entity_WriteSelected
959 // =======================================================================================================================
961 void Entity_WriteSelected(entity_t *e, FILE *f) {
967 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
968 if (IsBrushSelected(b)) {
973 if (b == &e->brushes) {
974 return; // nothing selected
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);
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());
993 if (!EntityHasModel(e)) {
995 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
996 if (e->eclass->fixedsize && !b->entityModel) {
999 if (IsBrushSelected(b)) {
1000 fprintf(f, "// brush %i\n", count);
1002 Brush_Write( b, f, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
1011 // =======================================================================================================================
1012 // Entity_WriteSelected to a CMemFile
1013 // =======================================================================================================================
1015 void Entity_WriteSelected(entity_t *e, CMemFile *pMemFile) {
1021 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
1022 if (IsBrushSelected(b)) {
1027 if (b == &e->brushes) {
1028 return; // nothing selected
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);
1040 MemFile_fprintf(pMemFile, "{\n");
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());
1047 if (!EntityHasModel(e)) {
1049 for (b = e->brushes.onext; b != &e->brushes; b = b->onext) {
1050 if (e->eclass->fixedsize && !b->entityModel) {
1053 if (IsBrushSelected(b)) {
1054 MemFile_fprintf(pMemFile, "// brush %i\n", count);
1056 Brush_Write( b, pMemFile, e->origin, ( g_PrefsDlg.m_bNewMapFormat != FALSE ) );
1061 MemFile_fprintf(pMemFile, "}\n");
1065 =======================================================================================================================
1066 =======================================================================================================================
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);
1077 extern bool Entity_NameIsUnique(const char *name);
1080 =======================================================================================================================
1081 =======================================================================================================================
1083 void Entity_Name(entity_t *e, bool force) {
1084 const char *name = ValueForKey(e, "name");
1086 if (!force && name && name[0]) {
1090 if (name && name[0] && Entity_NameIsUnique(name)) {
1094 bool setModel = false;
1096 const char *model = ValueForKey(e, "model");
1098 if ( idStr::Icmp(model, name) == 0 ) {
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);
1109 SetKeyValue(e, "name", va("%s_%s_%i", str.c_str(), eclass, id));
1111 SetKeyValue(e, "name", va("%s_%i", eclass, id));
1115 SetKeyValue(e, "model", va("%s_%s_%i", str.c_str(), eclass, id));
1117 SetKeyValue(e, "model", va("%s_%i", eclass, id));
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 =======================================================================================================================
1129 entity_t *Entity_Create(eclass_t *c, bool forceFixed) {
1132 idVec3 mins, maxs, origin;
1135 brushprimit_texdef_t bp;
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");
1147 if (c->defArgs.GetString("model", "", str) && c->entityModel == NULL) {
1148 c->entityModel = gameEdit->ANIM_GetModelFromEntityDef( &c->defArgs );
1153 e->brushes.onext = e->brushes.oprev = &e->brushes;
1155 e->epairs.Copy(c->args);
1156 SetKeyValue(e, "classname", c->name);
1157 Entity_Name(e, false);
1159 // add the entity to the entity list
1160 Entity_AddToList(e, &entities);
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]; }
1167 Select_GetMid(e->origin);
1168 VectorCopy(e->origin, origin);
1170 // create a custom brush
1171 VectorAdd(c->mins, e->origin, mins);
1172 VectorAdd(c->maxs, e->origin, maxs);
1174 b = Brush_Create(mins, maxs, &c->texdef);
1176 Entity_LinkBrush(e, b);
1178 if (c->defMaterial.Length()) {
1179 td.SetName(c->defMaterial);
1180 Brush_SetTexture(b, &td, &bp, false);
1184 // delete the current selection
1187 // select the new brush
1188 b->next = b->prev = &selected_brushes;
1189 selected_brushes.next = selected_brushes.prev = b;
1195 Select_GetMid(origin);
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);
1209 //for (int i = 0; i < 3; i++) {
1210 // origin[i] = vMin[i] + vMax[i] * 0.5;
1214 SetKeyValue(e, "model", ValueForKey(e, "name"));
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);
1222 Sys_UpdateWindows(W_ALL);
1226 void Brush_MakeDirty(brush_t *b) {
1227 for (face_t *f = b->brush_faces; f; f = f->next) {
1232 =======================================================================================================================
1234 =======================================================================================================================
1236 void Entity_LinkBrush(entity_t *e, brush_t *b) {
1237 if (b->oprev || b->onext) {
1238 Error("Entity_LinkBrush: Allready linked");
1245 b->onext = e->brushes.onext;
1246 b->oprev = &e->brushes;
1247 e->brushes.onext->oprev = b;
1248 e->brushes.onext = b;
1252 =======================================================================================================================
1254 =======================================================================================================================
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");
1262 b->onext->oprev = b->oprev;
1263 b->oprev->onext = b->onext;
1264 b->onext = b->oprev = NULL;
1269 =======================================================================================================================
1271 =======================================================================================================================
1273 entity_t *Entity_Clone(entity_t *e) {
1277 n->brushes.onext = n->brushes.oprev = &n->brushes;
1278 n->eclass = e->eclass;
1279 n->rotation = e->rotation;
1280 n->origin = e->origin;
1282 // add the entity to the entity list
1283 Entity_AddToList(n, &entities);
1285 n->epairs = e->epairs;
1291 =======================================================================================================================
1292 =======================================================================================================================
1294 int GetUniqueTargetId(int iHint) {
1304 for (; pe != NULL && pe != &entities; pe = pe->next) {
1305 i = IntForKey(pe, "target");
1307 iMin = Min(i, iMin);
1308 iMax = Max(i, iMax);
1324 =======================================================================================================================
1325 =======================================================================================================================
1327 entity_t *FindEntity(const char *pszKey, const char *pszValue) {
1332 for (; pe != NULL && pe != &entities; pe = pe->next) {
1333 if (!strcmp(ValueForKey(pe, pszKey), pszValue)) {
1342 =======================================================================================================================
1343 =======================================================================================================================
1345 entity_t *FindEntityInt(const char *pszKey, int iValue) {
1350 for (; pe != NULL && pe != &entities; pe = pe->next) {
1351 if (IntForKey(pe, pszKey) == iValue) {
1360 ====================
1361 Entity_UpdateSoundEmitter
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.
1366 Creates or updates the soundEmitter if needed
1367 ====================
1369 void Entity_UpdateSoundEmitter( entity_t *ent ) {
1370 bool playing = false;
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) ) {
1377 const char *v = ValueForKey( ent, "s_shader" );
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();
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 );
1394 // delete the soundEmitter if not used
1395 if ( !playing && ent->soundEmitter ) {
1396 ent->soundEmitter->Free( true );
1397 ent->soundEmitter = NULL;