1 /**
2  * @file
3  * @brief model loading and caching
4  */
5 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
23 
24 */
25 
26 #include "r_local.h"
27 
28 static model_t r_models[MAX_MOD_KNOWN];
29 static int r_numModels;
30 static int r_numModelsStatic;
31 
32 model_t* r_mapTiles[MAX_MAPTILES];
33 int r_numMapTiles;
34 
35 /* the inline * models from the current map are kept separate */
36 model_t r_modelsInline[MAX_MOD_KNOWN];
37 int r_numModelsInline;
38 
39 static char* r_actorSkinNames[MAX_ACTORSKINNAME];
40 static int r_numActorSkinName;
41 
42 /**
43  * @brief all supported model formats
44  * @sa modtype_t
45  */
46 static char const* const mod_extensions[] = {
47 	"md2", "md3", "obj", nullptr
48 };
49 
50 /**
51  * @brief Prints all loaded models
52  */
R_ModModellist_f(void)53 void R_ModModellist_f (void)
54 {
55 	int i;
56 	model_t* mod;
57 
58 	Com_Printf("Loaded models:\n");
59 	Com_Printf("Type | #Slot | #Tris   | #Meshes | Filename\n");
60 	for (i = 0, mod = r_models; i < r_numModels; i++, mod++) {
61 		if (!mod->name[0]) {
62 			Com_Printf("Empty slot %i\n", i);
63 			continue;
64 		}
65 		switch(mod->type) {
66 		case mod_alias_md3:
67 			Com_Printf("MD3 ");
68 			break;
69 		case mod_alias_md2:
70 			Com_Printf("MD2 ");
71 			break;
72 		case mod_bsp:
73 			Com_Printf("BSP ");
74 			break;
75 		case mod_bsp_submodel:
76 			Com_Printf("SUB ");
77 			break;
78 		case mod_obj:
79 			Com_Printf("OBJ ");
80 			break;
81 		default:
82 			Com_Printf("%3i ", mod->type);
83 			break;
84 		}
85 		if (mod->alias.num_meshes) {
86 			int j;
87 			Com_Printf(" | %5i | %7i | %7i | %s (skins: %i)\n", i, mod->alias.num_meshes, mod->alias.meshes[0].num_tris, mod->name, mod->alias.meshes[0].num_skins);
88 			for (j = 0; j < mod->alias.meshes[0].num_skins; j++) {
89 				mAliasSkin_t* skin = &mod->alias.meshes[0].skins[j];
90 				Com_Printf("     \\-- skin %i: '%s' (texnum %i and image type %i)\n", j + 1, skin->name, skin->skin->texnum, skin->skin->type);
91 			}
92 		} else
93 			Com_Printf(" | %5i | %7i | unknown | %s\n", i, mod->alias.num_meshes, mod->name);
94 	}
95 	Com_Printf("%4i models loaded\n", r_numModels);
96 	Com_Printf(" - %4i static models\n", r_numModelsStatic);
97 	Com_Printf(" - %4i bsp models\n", r_numMapTiles);
98 	Com_Printf(" - %4i inline models\n", r_numModelsInline);
99 }
100 
R_AllocModelSlot(void)101 model_t* R_AllocModelSlot (void)
102 {
103 	/* get new model */
104 	if (r_numModels < 0 || r_numModels >= MAX_MOD_KNOWN)
105 		Com_Error(ERR_DROP, "R_ModAddMapTile: r_numModels >= MAX_MOD_KNOWN");
106 	return &r_models[r_numModels++];
107 }
108 
109 /**
110  * @brief Loads in a model for the given name
111  * @param[in] filename Filename relative to base dir and with extension (models/model.md2)
112  * @param[in,out] mod Structure to initialize
113  * @return True if the loading was succeed. True or false structure mod was edited.
114  */
R_LoadModel(model_t * mod,const char * filename)115 static bool R_LoadModel (model_t* mod, const char* filename)
116 {
117 	byte* buf;
118 	int modfilelen;
119 	char animname[MAX_QPATH];
120 
121 	if (filename[0] == '\0')
122 		Com_Error(ERR_FATAL, "R_ModForName: nullptr name");
123 
124 	/* load the file */
125 	modfilelen = FS_LoadFile(filename, &buf);
126 	if (!buf)
127 		return false;
128 
129 	OBJZERO(*mod);
130 	Q_strncpyz(mod->name, filename, sizeof(mod->name));
131 
132 	/* call the appropriate loader */
133 	switch (LittleLong(*(unsigned *) buf)) {
134 	case IDALIASHEADER:
135 		/* MD2 header */
136 		R_ModLoadAliasMD2Model(mod, buf, modfilelen, true);
137 		break;
138 
139 	case IDMD3HEADER:
140 		/* MD3 header */
141 		R_ModLoadAliasMD3Model(mod, buf, modfilelen);
142 		break;
143 
144 	case IDBSPHEADER:
145 		Com_Error(ERR_FATAL, "R_ModForName: don't load BSPs with this function");
146 		break;
147 
148 	default:
149 	{
150 		const char* ext = Com_GetExtension(filename);
151 		if (ext != nullptr && !Q_strcasecmp(ext, "obj"))
152 			R_LoadObjModel(mod, buf, modfilelen);
153 		else
154 			Com_Error(ERR_FATAL, "R_ModForName: unknown fileid for %s", mod->name);
155 	}
156 	}
157 
158 	/* load the animations */
159 	Com_StripExtension(mod->name, animname, sizeof(animname));
160 	Com_DefaultExtension(animname, sizeof(animname), ".anm");
161 
162 	/* try to load the animation file */
163 	if (FS_CheckFile("%s", animname) != -1) {
164 		R_ModLoadAnims(&mod->alias, animname);
165 	}
166 
167 	FS_FreeFile(buf);
168 
169 	return true;
170 }
171 
R_ModelExists(const char * name)172 bool R_ModelExists (const char* name)
173 {
174 	if (Com_GetExtension(name) == nullptr) {
175 		int i;
176 		for (i = 0; mod_extensions[i] != nullptr; i++) {
177 			if (FS_CheckFile("models/%s.%s", name, mod_extensions[i]) != -1) {
178 				return true;
179 			}
180 		}
181 		return false;
182 	}
183 
184 	return FS_CheckFile("models/%s", name) != -1;
185 }
186 
187 /**
188  * @brief Tries to load a model
189  * @param[in] name The model path or name (with or without extension) - see notes
190  * this parameter is always relative to the game base dir - it can also be relative
191  * to the models/ dir in the game folder
192  * @note trying all supported model formats is only supported when you are using
193  * a name without extension and relative to models/ dir
194  * @note if first char of name is a '*' - this is an inline model
195  * @note if there is not extension in the given filename the function will
196  * try to load one of the supported model formats
197  * @return nullptr if no model could be found with the given name, model_t otherwise
198  */
R_FindModel(const char * name)199 model_t* R_FindModel (const char* name)
200 {
201 	model_t* mod;
202 	model_t model;
203 	bool loaded = false;
204 	int i;
205 
206 	if (!name || !name[0])
207 		return nullptr;
208 
209 	/* search for existing models */
210 	mod = R_GetModel(name);
211 	if (mod != nullptr)
212 		return mod;
213 
214 	/* no inline bsp models here */
215 	if (name[0] == '*')
216 		return nullptr;
217 
218 	/* load model */
219 	if (Com_GetExtension(name) == nullptr) {
220 		char filename[MAX_QPATH];
221 
222 		for (i = 0; mod_extensions[i] != nullptr; i++) {
223 			Com_sprintf(filename, sizeof(filename), "models/%s.%s", name, mod_extensions[i]);
224 			loaded = R_LoadModel(&model, filename);
225 			if (loaded) {
226 				/* use short name */
227 				Q_strncpyz(model.name, name, sizeof(model.name));
228 				break;
229 			}
230 		}
231 	} else {
232 		/** @todo this case should be useless, do we ever use extension? */
233 		loaded = R_LoadModel(&model, name);
234 	}
235 
236 	if (!loaded) {
237 		Com_Printf("R_FindModel: Could not find: '%s'\n", name);
238 		return nullptr;
239 	}
240 
241 	/* register the new model only after the loading is finished */
242 
243 	/* find a free model slot spot */
244 	for (i = 0, mod = r_models; i < r_numModels; i++, mod++) {
245 		if (!mod->name[0])
246 			break;
247 	}
248 	if (i == r_numModels) {
249 		if (r_numModels == MAX_MOD_KNOWN)
250 			Com_Error(ERR_FATAL, "r_numModels == MAX_MOD_KNOWN");
251 		r_numModels++;
252 	}
253 
254 	/* copy the model to the slot */
255 	r_models[i] = model;
256 	return &r_models[i];
257 }
258 
259 /**
260  * @brief Get a model for the given name already loaded.
261  * @return A model for the given name, else nullptr.
262  * @sa R_FindModel
263  * @param[in] name Short name of the model relative to base dir without (models/model)
264  */
R_GetModel(const char * name)265 model_t* R_GetModel (const char* name)
266 {
267 	model_t* mod;
268 	int i;
269 
270 	if (name[0] == '\0')
271 		Com_Error(ERR_FATAL, "R_ModForName: nullptr name");
272 
273 	/* inline models are grabbed only from worldmodel */
274 	if (name[0] == '*') {
275 		i = atoi(name + 1) - 1;
276 		if (i < 0 || i >= r_numModelsInline)
277 			Com_Error(ERR_FATAL, "bad inline model number '%s' (%i/%i)", name, i, r_numModelsInline);
278 		return &r_modelsInline[i];
279 	}
280 
281 	/* search the currently loaded models */
282 	for (i = 0, mod = r_models; i < r_numModels; i++, mod++)
283 		if (Q_streq(mod->name, name))
284 			return mod;
285 	return nullptr;
286 }
287 
288 #define MEM_TAG_STATIC_MODELS 1
289 /**
290  * @brief After all static models are loaded, switch the pool tag for these models
291  * to not free them everytime R_ShutdownModels is called
292  * @sa CL_InitAfter
293  * @sa R_FreeWorldImages
294  */
R_SwitchModelMemPoolTag(void)295 void R_SwitchModelMemPoolTag (void)
296 {
297 	int i, j, k;
298 	model_t* mod;
299 
300 	r_numModelsStatic = r_numModels;
301 	Mem_ChangeTag(vid_modelPool, 0, MEM_TAG_STATIC_MODELS);
302 
303 	/* mark the static model textures as it_static, thus R_FreeWorldImages
304 	 * won't free them */
305 	for (i = 0, mod = r_models; i < r_numModelsStatic; i++, mod++) {
306 		if (!mod->alias.num_meshes)
307 			Com_Printf("Model '%s' has no meshes\n", mod->name);
308 		for (j = 0; j < mod->alias.num_meshes; j++) {
309 			mAliasMesh_t* mesh = &mod->alias.meshes[j];
310 			if (!mesh->num_skins)
311 				Com_Printf("Model '%s' has no skins\n", mod->name);
312 			for (k = 0; k < mesh->num_skins; k++) {
313 				mAliasSkin_t* modelSkin = &mesh->skins[k];
314 				if (modelSkin->skin != r_noTexture)
315 					modelSkin->skin->type = it_static;
316 				else
317 					Com_Printf("No skin for #%i of '%s'\n", j, mod->name);
318 			}
319 		}
320 	}
321 
322 	Com_Printf("%i static models loaded\n", r_numModels);
323 }
324 
325 /**
326  * @brief Register an actorskin name
327  * @return The id where the actorskin is registered
328  */
R_ModAllocateActorSkin(const char * name)329 int R_ModAllocateActorSkin (const char* name)
330 {
331 	if (r_numActorSkinName >= lengthof(r_actorSkinNames))
332 		return -1;
333 
334 	r_actorSkinNames[r_numActorSkinName] = Mem_StrDup(name);
335 
336 	return r_numActorSkinName++;
337 }
338 
R_UseActorSkin(void)339 bool R_UseActorSkin (void)
340 {
341 	return r_numActorSkinName != 0;
342 }
343 
R_GetActorSkin(int id)344 static const char* R_GetActorSkin (int id)
345 {
346 	assert(id >= 0 && id < r_numActorSkinName);
347 	return r_actorSkinNames[id];
348 }
349 
350 /**
351  * @brief Load actor skins from a default skin to a a mesh.
352  * @param outMesh Mesh target of skins
353  * @param defaultSkin Default skin of the mesh
354  */
R_LoadActorSkinsFromModel(mAliasMesh_t * outMesh,image_t * defaultSkin)355 void R_LoadActorSkinsFromModel (mAliasMesh_t* outMesh, image_t* defaultSkin)
356 {
357 	int i;
358 	assert(outMesh);
359 
360 	outMesh->num_skins = r_numActorSkinName;
361 	outMesh->skins = Mem_PoolAllocTypeN(mAliasSkin_t, outMesh->num_skins, vid_modelPool);
362 
363 	if (defaultSkin == r_noTexture)
364 		Com_Printf("R_LoadActorSkinsFromModel: No default skin found for model \"%s\"\n", outMesh->name);
365 
366 	for (i = 0; i < outMesh->num_skins; i++) {
367 		mAliasSkin_t* modelSkin = &outMesh->skins[i];
368 		if (i == 0) {
369 			modelSkin->skin = defaultSkin;
370 		} else {
371 			const char* skin = R_GetActorSkin(i);
372 			modelSkin->skin = R_AliasModelGetSkin(nullptr, va("%s_%s", defaultSkin->name, skin));
373 			/** @todo should we add warning here? */
374 			if (modelSkin->skin == r_noTexture)
375 				modelSkin->skin = defaultSkin;
376 		}
377 		Q_strncpyz(modelSkin->name, modelSkin->skin->name, sizeof(outMesh->skins[i].name));
378 	}
379 }
380 
381 /**
382  * @brief Frees the model pool
383  * @param complete If this is true the static mesh models are freed, too
384  * @sa R_SwitchModelMemPoolTag
385  */
R_ShutdownModels(bool complete)386 void R_ShutdownModels (bool complete)
387 {
388 	int i;
389 	const int start = complete ? 0 : r_numModelsStatic;
390 
391 	/* free the vertex buffer - but not for the static models
392 	 * the world, the submodels and all the misc_models are located in the
393 	 * r_models array */
394 	for (i = start; i < r_numModels; i++) {
395 		model_t* mod = &r_models[i];
396 		mBspModel_t* bsp = &mod->bsp;
397 
398 		if (bsp->vertex_buffer)
399 			qglDeleteBuffers(1, &bsp->vertex_buffer);
400 		if (bsp->texcoord_buffer)
401 			qglDeleteBuffers(1, &bsp->texcoord_buffer);
402 		if (bsp->lmtexcoord_buffer)
403 			qglDeleteBuffers(1, &bsp->lmtexcoord_buffer);
404 		if (bsp->normal_buffer)
405 			qglDeleteBuffers(1, &bsp->normal_buffer);
406 		if (bsp->tangent_buffer)
407 			qglDeleteBuffers(1, &bsp->tangent_buffer);
408 		if (bsp->index_buffer)
409 			qglDeleteBuffers(1, &bsp->index_buffer);
410 	}
411 
412 	/* don't free the static models with the tag MEM_TAG_STATIC_MODELS */
413 	if (complete) {
414 		if (vid_modelPool)
415 			Mem_FreePool(vid_modelPool);
416 		if (vid_lightPool)
417 			Mem_FreePool(vid_lightPool);
418 		r_numModels = 0;
419 		r_numModelsInline = 0;
420 		r_numMapTiles = 0;
421 		OBJZERO(r_models);
422 	} else {
423 		if (vid_modelPool)
424 			Mem_FreeTag(vid_modelPool, 0);
425 		if (vid_lightPool)
426 			Mem_FreeTag(vid_lightPool, 0);
427 		r_numModels = r_numModelsStatic;
428 	}
429 }
430