transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / plugins / entity / entity.cpp
1 /*\r
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.\r
4 \r
5 This file is part of GtkRadiant.\r
6 \r
7 GtkRadiant is free software; you can redistribute it and/or modify\r
8 it under the terms of the GNU General Public License as published by\r
9 the Free Software Foundation; either version 2 of the License, or\r
10 (at your option) any later version.\r
11 \r
12 GtkRadiant is distributed in the hope that it will be useful,\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
15 GNU General Public License for more details.\r
16 \r
17 You should have received a copy of the GNU General Public License\r
18 along with GtkRadiant; if not, write to the Free Software\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\r
20 */\r
21 \r
22 #include "plugin.h"\r
23 #include "entity.h"\r
24 #include "entity_entitymodel.h"\r
25 #include "light.h"\r
26 \r
27 int g_entityId = 1;\r
28 \r
29 \r
30 \r
31 // internal\r
32 \r
33 static void Entity_FreeEpairs(entity_t *e);\r
34 \r
35 static void SetKeyValue (epair_t *&e, const char *key, const char *value);\r
36 static void  DeleteKey (epair_t *&e, const char *key);\r
37 static const char *ValueForKey ( epair_t *&e, const char *key);\r
38 \r
39 static void Entity_OnKeyValueChanged(entity_t *e, const char* key, const char* value);\r
40 \r
41 // constructor\r
42 entity_t *Entity_Alloc()\r
43 {\r
44   entity_t *e;\r
45         e = (entity_t*)malloc (sizeof(*e));\r
46         e->entityId = g_entityId++;\r
47   VectorSet(e->origin, 0, 0, 0);\r
48   VectorSet(e->color, 1, 1, 1);\r
49   e->redoId = 0;\r
50   e->undoId = 0;\r
51   e->next = e->prev = NULL;\r
52         e->brushes.onext = e->brushes.oprev = &e->brushes;\r
53   e->epairs = NULL;\r
54   e->eclass = NULL;\r
55   e->model.pRender = NULL;\r
56   e->model.pSelect = NULL;\r
57   e->model.pEdit = NULL;\r
58   return e;\r
59 }\r
60 \r
61 // destructor\r
62 void Entity_Free (entity_t *e)\r
63 {\r
64         while (e->brushes.onext != &e->brushes)\r
65                 Brush_Free( e->brushes.onext, true );\r
66 \r
67         if (e->next)\r
68         {\r
69                 e->next->prev = e->prev;\r
70                 e->prev->next = e->next;\r
71         }\r
72 \r
73         Entity_FreeEpairs(e);\r
74 \r
75   if (e->model.pRender)\r
76   {\r
77     e->model.pRender->DecRef();\r
78     e->model.pRender = NULL;\r
79   }\r
80   if (e->model.pSelect)\r
81   {\r
82     e->model.pSelect->DecRef();\r
83     e->model.pSelect = NULL;\r
84   }\r
85   if (e->model.pEdit)\r
86   {\r
87     e->model.pEdit->DecRef();\r
88     e->model.pEdit = NULL;\r
89   }\r
90 \r
91         free (e);\r
92 }\r
93 \r
94 // construct from entity\r
95 entity_t        *Entity_Clone (entity_t *e)\r
96 {\r
97         entity_t        *n;\r
98         epair_t         *ep;\r
99 \r
100         n = Entity_Alloc();\r
101         n->eclass = e->eclass;\r
102 \r
103         for (ep = e->epairs ; ep ; ep=ep->next)\r
104     SetKeyValue(n, ep->key, ep->value);\r
105 \r
106         // copy some misc stuff as well\r
107         VectorCopy( e->origin, n->origin );\r
108 //      VectorCopy( e->vRotation, n->vRotation );\r
109 //      VectorCopy( e->vScale, n->vScale );\r
110 \r
111 //  n->bDirty = true;\r
112 \r
113         return n;\r
114 }\r
115 \r
116 \r
117 \r
118 \r
119 \r
120 const char *ValueForKey ( epair_t *&e, const char *key)\r
121 {\r
122   epair_t *ep;\r
123   for (ep=e ; ep ; ep=ep->next)\r
124   {\r
125                 if (!strcmp (ep->key, key) )\r
126     {\r
127       return ep->value;\r
128     }\r
129   }\r
130   return "";\r
131 }\r
132 \r
133 const char *ValueForKey (entity_t *ent, const char *key)\r
134 {\r
135   return ValueForKey(ent->epairs, key);\r
136 }\r
137 \r
138 void    SetKeyValue (epair_t *&e, const char *key, const char *value)\r
139 {\r
140         epair_t *ep;\r
141   for (ep=e ; ep ; ep=ep->next)\r
142   {\r
143                 if (!strcmp (ep->key, key) )\r
144                 {\r
145                         free (ep->value);\r
146                         ep->value = (char*)malloc(strlen(value)+1);\r
147                         strcpy (ep->value, value);\r
148                         return;\r
149                 }\r
150   }\r
151         ep = (epair_t*)malloc (sizeof(*ep));\r
152         ep->next = e;\r
153         e = ep;\r
154         ep->key = (char*)malloc(strlen(key)+1);\r
155         strcpy (ep->key, key);\r
156         ep->value = (char*)malloc(strlen(value)+1);\r
157         strcpy (ep->value, value);\r
158 \r
159 }\r
160 \r
161 void SetKeyValue (entity_t *ent, const char *key, const char *value)\r
162 {\r
163         if (ent == NULL)\r
164   {\r
165     Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL entity \n");\r
166                 return;\r
167   }\r
168 \r
169         if (!key || !key[0])\r
170   {\r
171     Sys_FPrintf(SYS_ERR, "ERROR: SetKeyValue: NULL or zero-length key\n");\r
172                 return;\r
173   }\r
174 \r
175   SetKeyValue(ent->epairs, key, value);\r
176   /*!\r
177   \todo TODO broadcast this through a clean messaging API ;-)\r
178   */\r
179   Entity_OnKeyValueChanged(ent, key, value);\r
180 }\r
181 \r
182 void    DeleteKey (epair_t *&e, const char *key)\r
183 {\r
184         epair_t **ep, *next;\r
185         \r
186         ep = &e;\r
187         while (*ep)\r
188         {\r
189                 next = *ep;\r
190                 if ( !strcmp (next->key, key) )\r
191                 {\r
192                         *ep = next->next;\r
193                         free(next->key);\r
194                         free(next->value);\r
195                         free(next);\r
196                         return;\r
197                 }\r
198                 ep = &next->next;\r
199         }\r
200 }\r
201 \r
202 void    DeleteKey (entity_t *ent, const char *key)\r
203 {\r
204   DeleteKey(ent->epairs, key);\r
205   Entity_OnKeyValueChanged(ent, key, "");\r
206 }\r
207 \r
208 float   FloatForKey (entity_t *ent, const char *key)\r
209 {\r
210         const char      *k;\r
211         \r
212         k = ValueForKey (ent, key);\r
213         return (float) atof(k);\r
214 }\r
215 \r
216 int IntForKey (entity_t *ent, const char *key)\r
217 {\r
218         const char      *k;\r
219         \r
220         k = ValueForKey (ent, key);\r
221         return atoi(k);\r
222 }\r
223 \r
224 void    GetVectorForKey (entity_t *ent, const char *key, vec3_t vec)\r
225 {\r
226         const char      *k;\r
227         \r
228         k = ValueForKey (ent, key);\r
229         sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]);\r
230 }\r
231 \r
232 /*\r
233 ===============\r
234 Entity_FreeEpairs\r
235 \r
236 Frees the entity epairs.\r
237 ===============\r
238 */\r
239 void Entity_FreeEpairs(entity_t *e)\r
240 {\r
241         epair_t *ep, *next;\r
242 \r
243         for (ep = e->epairs; ep; ep = next)\r
244         {\r
245                 next = ep->next;\r
246                 free (ep->key);\r
247                 free (ep->value);\r
248                 free (ep);\r
249         }\r
250         e->epairs = NULL;\r
251 }\r
252 \r
253 void Entity_AddToList(entity_t *e, entity_t *elist)\r
254 {\r
255         if (e->next || e->prev)\r
256                 Error ("Entity_AddToList: already linked");\r
257         //e->next = elist->next;\r
258         //elist->next->prev = e;\r
259         //elist->next = e;\r
260         //e->prev = elist;\r
261         e->next = elist;\r
262         e->prev = elist->prev;\r
263         elist->prev->next = e;\r
264         elist->prev = e;\r
265 }\r
266 \r
267 void Entity_RemoveFromList (entity_t *e)\r
268 {\r
269         if (!e->next || !e->prev)\r
270                 Error ("Entity_RemoveFromList: not linked");\r
271         e->next->prev = e->prev;\r
272         e->prev->next = e->next;\r
273         e->next = e->prev = NULL;\r
274 }\r
275 \r
276 void Entity_LinkBrush (entity_t *e, brush_t *b)\r
277 {\r
278         if (b->oprev || b->onext)\r
279                 Error ("Entity_LinkBrush: Already linked");\r
280         b->owner = e;\r
281 \r
282 //      b->onext = e->brushes.onext;\r
283 //      b->oprev = &e->brushes;\r
284 //      e->brushes.onext->oprev = b;\r
285 //      e->brushes.onext = b;\r
286   /*\r
287   SPoG - changed to add brushes to end of list instead of start - so this can be used by map loader.\r
288   This could concievably cause a problem if someone is traversing e->brushes while calling this function.\r
289   So don't.\r
290   */\r
291   b->onext = &e->brushes;\r
292         b->oprev = e->brushes.oprev;\r
293         e->brushes.oprev->onext = b;\r
294         e->brushes.oprev = b;\r
295 }\r
296 \r
297 void Entity_UnlinkBrush (brush_t *b)\r
298 {\r
299         if (!b->onext || !b->oprev)\r
300                 Error ("Entity_UnlinkBrush: Not currently linked");\r
301         b->onext->oprev = b->oprev;\r
302         b->oprev->onext = b->onext;\r
303         b->onext = b->oprev = NULL;\r
304         b->owner = NULL;\r
305 }\r
306 \r
307 // for undo\r
308 int Entity_MemorySize(entity_t *e)\r
309 {\r
310         epair_t *ep;\r
311         int size = 0;\r
312 \r
313         for (ep = e->epairs; ep; ep = ep->next)\r
314         {\r
315     size += strlen(ep->key);\r
316     size += strlen(ep->value);\r
317     size += sizeof(epair_t);\r
318         }\r
319   size += sizeof(entity_t);\r
320         return size;\r
321 }\r
322 \r
323 epair_t* Entity_AllocateEpair(const char *key, const char *value)\r
324 {\r
325   epair_t *ep = (epair_t*)malloc (sizeof(*ep));\r
326   ep->key = (char*)malloc(strlen(key)+1);\r
327   strcpy (ep->key, key);\r
328   ep->value = (char*)malloc(strlen(value)+1);\r
329   strcpy (ep->value, value);\r
330   ep->next = NULL;\r
331   return ep;\r
332 }\r
333 \r
334 epair_t** Entity_GetKeyValList(entity_t *e)\r
335 {\r
336   return &e->epairs;\r
337 }\r
338 \r
339 void Entity_SetKeyValList(entity_t *e, epair_t* ep)\r
340 {\r
341   if( e->epairs )\r
342     Sys_Printf( "Warning : pe->epairs != NULL in Entity_SetKeyValList, will not set\n" );\r
343   else {\r
344     e->epairs = ep;\r
345 \r
346     for (epair_t *pe_ep = e->epairs; pe_ep; pe_ep = pe_ep->next)\r
347       Entity_OnKeyValueChanged(e, pe_ep->key, pe_ep->value);\r
348   }\r
349 }\r
350 \r
351 \r
352 /*!\r
353 \todo FIXME TTimo\r
354 this is meant to raise messages instead of calling the IEdit directly\r
355 */\r
356 static void Entity_OnKeyValueChanged(entity_t *e, const char *key, const char* value)\r
357 {\r
358   if(strcmp(key,"classname") == 0)\r
359   {\r
360     e->eclass = Eclass_ForName(value, false);\r
361     Entity_UpdateClass(e, value);\r
362     if(strcmp(value,"light") == 0)\r
363       for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next)\r
364         Light_OnKeyValueChanged(e, ep->key, ep->value);\r
365     if(e->model.pEdit)\r
366       for(epair_t* ep = e->epairs; ep != NULL; ep=ep->next)\r
367         e->model.pEdit->OnKeyValueChanged(e, ep->key, ep->value);\r
368   }\r
369   else if(Entity_IsLight(e))\r
370     Light_OnKeyValueChanged(e, key, value);\r
371   else if(e->model.pEdit)\r
372     e->model.pEdit->OnKeyValueChanged(e, key, value);\r
373 \r
374   // update brush mins/maxs for legacy culling system\r
375   if(e->model.pRender && e->brushes.onext != &e->brushes)\r
376     Brush_Build( e->brushes.onext, true, true, false, true );\r
377 }\r