added r_sortsurfaces cvar, default off, sorting them seems to be a very minor slowdow...
[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 rtexture_t *r_notexture;
34 rtexturepool_t *r_notexturepool;
35
36 texture_t r_surf_notexture;
37
38 void Mod_SetupNoTexture(void)
39 {
40         int x, y;
41         qbyte pix[16][16][4];
42
43         // this makes a light grey/dark grey checkerboard texture
44         for (y = 0;y < 16;y++)
45         {
46                 for (x = 0;x < 16;x++)
47                 {
48                         if ((y < 8) ^ (x < 8))
49                         {
50                                 pix[y][x][0] = 128;
51                                 pix[y][x][1] = 128;
52                                 pix[y][x][2] = 128;
53                                 pix[y][x][3] = 255;
54                         }
55                         else
56                         {
57                                 pix[y][x][0] = 64;
58                                 pix[y][x][1] = 64;
59                                 pix[y][x][2] = 64;
60                                 pix[y][x][3] = 255;
61                         }
62                 }
63         }
64
65         r_notexturepool = R_AllocTexturePool();
66         r_notexture = R_LoadTexture(r_notexturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP);
67 }
68
69 static void mod_start(void)
70 {
71         int i;
72         for (i = 0;i < MAX_MOD_KNOWN;i++)
73                 if (mod_known[i].name[0])
74                         Mod_UnloadModel(&mod_known[i]);
75
76         Mod_SetupNoTexture();
77 }
78
79 static void mod_shutdown(void)
80 {
81         int i;
82         for (i = 0;i < MAX_MOD_KNOWN;i++)
83                 if (mod_known[i].name[0])
84                         Mod_UnloadModel(&mod_known[i]);
85
86         R_FreeTexturePool(&r_notexturepool);
87 }
88
89 static void mod_newmap(void)
90 {
91 }
92
93 /*
94 ===============
95 Mod_Init
96 ===============
97 */
98 static void Mod_Print (void);
99 static void Mod_Flush (void);
100 void Mod_Init (void)
101 {
102         Mod_BrushInit();
103         Mod_AliasInit();
104         Mod_SpriteInit();
105
106         Cmd_AddCommand ("modellist", Mod_Print);
107         Cmd_AddCommand ("modelflush", Mod_Flush);
108 }
109
110 void Mod_RenderInit(void)
111 {
112         R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap);
113 }
114
115 void Mod_FreeModel (model_t *mod)
116 {
117         R_FreeTexturePool(&mod->texturepool);
118         Mem_FreePool(&mod->mempool);
119
120         // clear the struct to make it available
121         memset(mod, 0, sizeof(model_t));
122 }
123
124 void Mod_UnloadModel (model_t *mod)
125 {
126         char name[MAX_QPATH];
127         qboolean isworldmodel;
128         strcpy(name, mod->name);
129         isworldmodel = mod->isworldmodel;
130         Mod_FreeModel(mod);
131         strcpy(mod->name, name);
132         mod->isworldmodel = isworldmodel;
133         mod->needload = true;
134 }
135
136 /*
137 ==================
138 Mod_LoadModel
139
140 Loads a model
141 ==================
142 */
143 static model_t *Mod_LoadModel (model_t *mod, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
144 {
145         int crc;
146         void *buf;
147
148         mod->used = true;
149
150         if (mod->name[0] == '*') // submodel
151                 return mod;
152
153         crc = 0;
154         buf = NULL;
155         if (!mod->needload)
156         {
157                 if (checkdisk)
158                 {
159                         buf = COM_LoadFile (mod->name, false);
160                         if (!buf)
161                         {
162                                 if (crash)
163                                         Host_Error ("Mod_LoadModel: %s not found", mod->name); // LordHavoc: Sys_Error was *ANNOYING*
164                                 return NULL;
165                         }
166
167                         crc = CRC_Block(buf, com_filesize);
168                 }
169                 else
170                         crc = mod->crc;
171
172                 if (mod->crc == crc && mod->isworldmodel == isworldmodel)
173                 {
174                         if (buf)
175                                 Mem_Free(buf);
176                         return mod; // already loaded
177                 }
178         }
179
180         Con_DPrintf("loading model %s\n", mod->name);
181
182         if (!buf)
183         {
184                 buf = COM_LoadFile (mod->name, false);
185                 if (!buf)
186                 {
187                         if (crash)
188                                 Host_Error ("Mod_LoadModel: %s not found", mod->name);
189                         return NULL;
190                 }
191                 crc = CRC_Block(buf, com_filesize);
192         }
193
194         // allocate a new model
195         loadmodel = mod;
196
197         // LordHavoc: unload the existing model in this slot (if there is one)
198         Mod_UnloadModel(mod);
199         mod->isworldmodel = isworldmodel;
200         mod->needload = false;
201         mod->used = true;
202         mod->crc = crc;
203
204         // all models use memory, so allocate a memory pool
205         mod->mempool = Mem_AllocPool(mod->name);
206         // all models load textures, so allocate a texture pool
207         if (cls.state != ca_dedicated)
208                 mod->texturepool = R_AllocTexturePool();
209
210         // call the apropriate loader
211              if (!memcmp(buf, "IDPO"    , 4)) Mod_LoadAliasModel  (mod, buf);
212         else if (!memcmp(buf, "IDP2"    , 4)) Mod_LoadQ2AliasModel(mod, buf);
213         else if (!memcmp(buf, "ZYMOTIC" , 7)) Mod_LoadZymoticModel(mod, buf);
214         else if (!memcmp(buf, "IDSP"    , 4)) Mod_LoadSpriteModel (mod, buf);
215         else                                  Mod_LoadBrushModel  (mod, buf);
216
217         Mem_Free(buf);
218
219         return mod;
220 }
221
222 void Mod_CheckLoaded (model_t *mod)
223 {
224         if (mod)
225         {
226                 if (mod->needload)
227                         Mod_LoadModel(mod, true, true, mod->isworldmodel);
228                 else
229                 {
230                         if (mod->type == mod_invalid)
231                                 Host_Error("Mod_CheckLoaded: invalid model\n");
232                         mod->used = true;
233                         return;
234                 }
235         }
236 }
237
238 /*
239 ===================
240 Mod_ClearAll
241 ===================
242 */
243 void Mod_ClearAll (void)
244 {
245 }
246
247 void Mod_ClearUsed(void)
248 {
249         int             i;
250         model_t *mod;
251
252         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
253                 if (mod->name[0])
254                         mod->used = false;
255 }
256
257 void Mod_PurgeUnused(void)
258 {
259         int             i;
260         model_t *mod;
261
262         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
263                 if (mod->name[0])
264                         if (!mod->used)
265                                 Mod_FreeModel(mod);
266 }
267
268 /*
269 ==================
270 Mod_FindName
271
272 ==================
273 */
274 model_t *Mod_FindName (char *name)
275 {
276         int             i;
277         model_t *mod, *freemod;
278
279         if (!name[0])
280                 Host_Error ("Mod_ForName: NULL name");
281
282 // search the currently loaded models
283         freemod = NULL;
284         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
285         {
286                 if (mod->name[0])
287                 {
288                         if (!strcmp (mod->name, name))
289                         {
290                                 mod->used = true;
291                                 return mod;
292                         }
293                 }
294                 else if (freemod == NULL)
295                         freemod = mod;
296         }
297
298         if (freemod)
299         {
300                 mod = freemod;
301                 strcpy (mod->name, name);
302                 mod->needload = true;
303                 mod->used = true;
304                 return mod;
305         }
306
307         Host_Error ("Mod_FindName: ran out of models\n");
308         return NULL;
309 }
310
311 /*
312 ==================
313 Mod_TouchModel
314
315 ==================
316 */
317 void Mod_TouchModel (char *name)
318 {
319         model_t *mod;
320
321         mod = Mod_FindName (name);
322         mod->used = true;
323 }
324
325 /*
326 ==================
327 Mod_ForName
328
329 Loads in a model for the given name
330 ==================
331 */
332 model_t *Mod_ForName (char *name, qboolean crash, qboolean checkdisk, qboolean isworldmodel)
333 {
334         return Mod_LoadModel (Mod_FindName (name), crash, checkdisk, isworldmodel);
335 }
336
337 qbyte *mod_base;
338
339
340 //=============================================================================
341
342 /*
343 ================
344 Mod_Print
345 ================
346 */
347 static void Mod_Print (void)
348 {
349         int             i;
350         model_t *mod;
351
352         Con_Printf ("Loaded models:\n");
353         for (i = 0, mod = mod_known;i < MAX_MOD_KNOWN;i++, mod++)
354                 if (mod->name[0])
355                         Con_Printf ("%4iK %s\n", mod->mempool ? (mod->mempool->totalsize + 1023) / 1024 : 0, mod->name);
356 }
357
358 static void Mod_Flush (void)
359 {
360         int             i;
361
362         Con_Printf ("Unloading models\n");
363         for (i = 0;i < MAX_MOD_KNOWN;i++)
364                 if (mod_known[i].name[0])
365                         Mod_UnloadModel(&mod_known[i]);
366 }
367