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