rewrote memory system entirely (hunk, cache, and zone are gone, memory pools replaced...
[xonotic/darkplaces.git] / model_shared.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // models.c -- model loading and caching
21
22 // models are the only shared resource between a client and server running
23 // on the same machine.
24
25 #include "quakedef.h"
26
27 model_t *loadmodel;
28
29 // LordHavoc: increased from 512 to 2048
30 #define MAX_MOD_KNOWN   2048
31 model_t mod_known[MAX_MOD_KNOWN];
32
33 void mod_start()
34 {
35         int i;
36         for (i = 0;i < MAX_MOD_KNOWN;i++)
37                 if (mod_known[i].name[0])
38                         Mod_UnloadModel(&mod_known[i]);
39 }
40
41 void mod_shutdown()
42 {
43         int i;
44         for (i = 0;i < MAX_MOD_KNOWN;i++)
45                 if (mod_known[i].name[0])
46                         Mod_UnloadModel(&mod_known[i]);
47 }
48
49 void mod_newmap()
50 {
51 }
52
53 /*
54 ===============
55 Mod_Init
56 ===============
57 */
58 static void Mod_Print (void);
59 static void Mod_Flush (void);
60 void Mod_Init (void)
61 {
62         Mod_BrushInit();
63         Mod_AliasInit();
64         Mod_SpriteInit();
65
66         Cmd_AddCommand ("modellist", Mod_Print);
67         Cmd_AddCommand ("modelflush", Mod_Flush);
68 }
69
70 void Mod_RenderInit(void)
71 {
72         R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap);
73 }
74
75 void Mod_FreeModel (model_t *mod)
76 {
77         R_FreeTexturePool(&mod->texturepool);
78         Mem_FreePool(&mod->mempool);
79
80         // clear the struct to make it available
81         memset(mod, 0, sizeof(model_t));
82 }
83
84 void Mod_UnloadModel (model_t *mod)
85 {
86         char name[MAX_QPATH];
87         qboolean isworldmodel;
88         strcpy(name, mod->name);
89         isworldmodel = mod->isworldmodel;
90         Mod_FreeModel(mod);
91         strcpy(mod->name, name);
92         mod->isworldmodel = isworldmodel;
93         mod->needload = true;
94 }
95
96 /*
97 ==================
98 Mod_LoadModel
99
100 Loads a model
101 ==================
102 */
103 static model_t *Mod_LoadModel (model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
104 {
105         int crc;
106         void *buf;
107         char tempname[MAX_QPATH];
108
109         mod->used = true;
110
111         if (mod->name[0] == '*') // submodel
112                 return mod;
113
114         if (checkdisk)
115         {
116                 // load the file
117                 buf = COM_LoadFile (mod->name, false);
118                 if (!buf)
119                 {
120                         if (crash)
121                                 Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
122                         return NULL;
123                 }
124
125                 crc = CRC_Block(buf, com_filesize);
126
127                 if (!mod->needload && mod->crc == crc && mod->isworldmodel == isworldmodel)
128                 {
129                         Mem_Free(buf);
130                         return mod; // already loaded
131                 }
132
133                 Con_DPrintf("loading model %s\n", mod->name);
134         }
135         else
136         {
137                 if (!mod->needload && mod->isworldmodel == isworldmodel)
138                         return mod; // already loaded
139
140                 Con_DPrintf("loading model %s\n", mod->name);
141
142                 buf = COM_LoadFile (mod->name, false);
143                 if (!buf)
144                 {
145                         if (crash)
146                                 Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
147                         return NULL;
148                 }
149                 crc = CRC_Block(buf, com_filesize);
150         }
151
152         // make sure nothing got trashed
153         Mem_CheckSentinelsGlobal();
154
155         // allocate a new model
156         loadmodel = mod;
157
158         // LordHavoc: clear the model struct
159         strcpy(tempname, mod->name);
160         Mod_FreeModel(mod);
161
162         strcpy(mod->name, tempname);
163         mod->isworldmodel = isworldmodel;
164         mod->needload = false;
165         mod->used = true;
166         mod->crc = crc;
167
168         // all models use memory, so allocate a memory pool
169         mod->mempool = Mem_AllocPool(mod->name);
170         // all models load textures, so allocate a texture pool
171         mod->texturepool = R_AllocTexturePool();
172
173         // call the apropriate loader
174              if (!memcmp(buf, "IDPO"    , 4)) Mod_LoadAliasModel  (mod, buf);
175         else if (!memcmp(buf, "IDP2"    , 4)) Mod_LoadQ2AliasModel(mod, buf);
176         else if (!memcmp(buf, "ZYMOTIC" , 7)) Mod_LoadZymoticModel(mod, buf);
177         else if (!memcmp(buf, "IDSP"    , 4)) Mod_LoadSpriteModel (mod, buf);
178         else                                  Mod_LoadBrushModel  (mod, buf);
179
180         Mem_Free(buf);
181
182         // make sure nothing got trashed
183         Mem_CheckSentinelsGlobal();
184
185         return mod;
186 }
187
188 void Mod_CheckLoaded (model_t *mod)
189 {
190         if (mod)
191         {
192                 if (!mod->needload)
193                 {
194                         if (mod->type == mod_invalid)
195                                 Host_Error("Mod_CheckLoaded: invalid model\n");
196                         mod->used = true;
197                         return;
198                 }
199
200                 Mod_LoadModel(mod, true, true, mod->isworldmodel);
201         }
202 }
203
204 /*
205 ===================
206 Mod_ClearAll
207 ===================
208 */
209 void Mod_ClearAll (void)
210 {
211         /*
212         int             i;
213         model_t *mod;
214
215         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
216                 if (mod->name[0])
217                         if (mod->usesheap)
218                                 Mod_FreeModel(mod);
219         */
220 }
221
222 void Mod_ClearUsed(void)
223 {
224         int             i;
225         model_t *mod;
226
227         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
228                 if (mod->name[0])
229                         mod->used = false;
230 }
231
232 void Mod_PurgeUnused(void)
233 {
234         int             i;
235         model_t *mod;
236
237         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
238                 if (mod->name[0])
239                         if (!mod->used)
240                                 Mod_FreeModel(mod);
241 }
242
243 /*
244 ==================
245 Mod_FindName
246
247 ==================
248 */
249 model_t *Mod_FindName (char *name)
250 {
251         int             i;
252         model_t *mod, *freemod;
253
254         if (!name[0])
255                 Host_Error ("Mod_ForName: NULL name");
256
257 // search the currently loaded models
258         freemod = NULL;
259         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
260         {
261                 if (mod->name[0])
262                 {
263                         if (!strcmp (mod->name, name))
264                         {
265                                 mod->used = true;
266                                 return mod;
267                         }
268                 }
269                 else if (freemod == NULL)
270                         freemod = mod;
271         }
272
273         if (freemod)
274         {
275                 mod = freemod;
276                 strcpy (mod->name, name);
277                 mod->needload = true;
278                 mod->used = true;
279                 return mod;
280         }
281
282         Host_Error ("Mod_FindName: ran out of models\n");
283         return NULL;
284 }
285
286 /*
287 ==================
288 Mod_TouchModel
289
290 ==================
291 */
292 void Mod_TouchModel (char *name)
293 {
294         model_t *mod;
295
296         mod = Mod_FindName (name);
297         mod->used = true;
298 }
299
300 /*
301 ==================
302 Mod_ForName
303
304 Loads in a model for the given name
305 ==================
306 */
307 model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
308 {
309         model_t *mod;
310
311         mod = Mod_FindName (name);
312         mod->used = true;
313
314         return Mod_LoadModel (mod, crash, checkdisk, isworldmodel);
315 }
316
317 byte    *mod_base;
318
319 /*
320 =================
321 RadiusFromBounds
322 =================
323 */
324 /*
325 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
326 {
327         int             i;
328         vec3_t  corner;
329
330         for (i=0 ; i<3 ; i++)
331                 corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
332
333         return Length (corner);
334 }
335 */
336
337 //=============================================================================
338
339 /*
340 ================
341 Mod_Print
342 ================
343 */
344 static void Mod_Print (void)
345 {
346         int             i;
347         model_t *mod;
348
349         Con_Printf ("Loaded models:\n");
350         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
351                 if (mod->name[0])
352                         Con_Printf ("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
353 }
354
355 static void Mod_Flush (void)
356 {
357         int             i;
358
359         Con_Printf ("Unloading models\n");
360         for (i = 0;i < MAX_MOD_KNOWN;i++)
361                 if (mod_known[i].name[0])
362                         Mod_UnloadModel(&mod_known[i]);
363 }
364