added in_pitch_min and in_pitch_max cvars to limit pitch (default: -90 to +90)
[divverent/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 static model_t mod_known[MAX_MOD_KNOWN];
32
33 static void mod_start(void)
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 static void mod_shutdown(void)
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 static void mod_newmap(void)
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
108         mod->used = true;
109
110         if (mod->name[0] == '*') // submodel
111                 return mod;
112
113         crc = 0;
114         buf = NULL;
115         if (!mod->needload)
116         {
117                 if (checkdisk)
118                 {
119                         buf = COM_LoadFile (mod->name, false);
120                         if (!buf)
121                         {
122                                 if (crash)
123                                         Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
124                                 return NULL;
125                         }
126
127                         crc = CRC_Block(buf, com_filesize);
128                 }
129                 else
130                         crc = mod->crc;
131
132                 if (mod->crc == crc && mod->isworldmodel == isworldmodel)
133                 {
134                         if (buf)
135                                 Mem_Free(buf);
136                         return mod; // already loaded
137                 }
138         }
139
140         Con_DPrintf("loading model %s\n", mod->name);
141
142         if (!buf)
143         {
144                 buf = COM_LoadFile (mod->name, false);
145                 if (!buf)
146                 {
147                         if (crash)
148                                 Host_Error ("Mod_LoadModel: %s not found", mod->name);
149                         return NULL;
150                 }
151                 crc = CRC_Block(buf, com_filesize);
152         }
153
154         // make sure nothing got trashed
155         Mem_CheckSentinelsGlobal();
156
157         // allocate a new model
158         loadmodel = mod;
159
160         // LordHavoc: unload the existing model in this slot (if there is one)
161         Mod_UnloadModel(mod);
162         mod->isworldmodel = isworldmodel;
163         mod->needload = false;
164         mod->used = true;
165         mod->crc = crc;
166
167         // all models use memory, so allocate a memory pool
168         mod->mempool = Mem_AllocPool(mod->name);
169         // all models load textures, so allocate a texture pool
170         if (cls.state != ca_dedicated)
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                         Mod_LoadModel(mod, true, true, mod->isworldmodel);
194                 else
195                 {
196                         if (mod->type == mod_invalid)
197                                 Host_Error("Mod_CheckLoaded: invalid model\n");
198                         mod->used = true;
199                         return;
200                 }
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         return Mod_LoadModel (Mod_FindName (name), crash, checkdisk, isworldmodel);
310 }
311
312 byte    *mod_base;
313
314 /*
315 =================
316 RadiusFromBounds
317 =================
318 */
319 /*
320 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
321 {
322         int             i;
323         vec3_t  corner;
324
325         for (i=0 ; i<3 ; i++)
326                 corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
327
328         return Length (corner);
329 }
330 */
331
332 //=============================================================================
333
334 /*
335 ================
336 Mod_Print
337 ================
338 */
339 static void Mod_Print (void)
340 {
341         int             i;
342         model_t *mod;
343
344         Con_Printf ("Loaded models:\n");
345         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
346                 if (mod->name[0])
347                         Con_Printf ("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
348 }
349
350 static void Mod_Flush (void)
351 {
352         int             i;
353
354         Con_Printf ("Unloading models\n");
355         for (i = 0;i < MAX_MOD_KNOWN;i++)
356                 if (mod_known[i].name[0])
357                         Mod_UnloadModel(&mod_known[i]);
358 }
359