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 #include "image.h"
27 #include "r_shadow.h"
28 #include "polygon.h"
29 
30 cvar_t r_enableshadowvolumes = {CVAR_SAVE, "r_enableshadowvolumes", "1", "Enables use of Stencil Shadow Volume shadowing methods, saves some memory if turned off"};
31 cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"};
32 cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
33 cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
34 cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
35 cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
36 cvar_t mod_generatelightmaps_lightmapsamples = {CVAR_SAVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
37 cvar_t mod_generatelightmaps_vertexsamples = {CVAR_SAVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
38 cvar_t mod_generatelightmaps_gridsamples = {CVAR_SAVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
39 cvar_t mod_generatelightmaps_lightmapradius = {CVAR_SAVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
40 cvar_t mod_generatelightmaps_vertexradius = {CVAR_SAVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
41 cvar_t mod_generatelightmaps_gridradius = {CVAR_SAVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
42 
43 dp_model_t *loadmodel;
44 
45 static mempool_t *mod_mempool;
46 static memexpandablearray_t models;
47 
48 static mempool_t* q3shaders_mem;
49 typedef struct q3shader_hash_entry_s
50 {
51   q3shaderinfo_t shader;
52   struct q3shader_hash_entry_s* chain;
53 } q3shader_hash_entry_t;
54 #define Q3SHADER_HASH_SIZE  1021
55 typedef struct q3shader_data_s
56 {
57   memexpandablearray_t hash_entries;
58   q3shader_hash_entry_t hash[Q3SHADER_HASH_SIZE];
59   memexpandablearray_t char_ptrs;
60 } q3shader_data_t;
61 static q3shader_data_t* q3shader_data;
62 
mod_start(void)63 static void mod_start(void)
64 {
65 	int i, count;
66 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
67 	dp_model_t *mod;
68 
69 	SCR_PushLoadingScreen(false, "Loading models", 1.0);
70 	count = 0;
71 	for (i = 0;i < nummodels;i++)
72 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
73 			if (mod->used)
74 				++count;
75 	for (i = 0;i < nummodels;i++)
76 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
77 			if (mod->used)
78 			{
79 				SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
80 				Mod_LoadModel(mod, true, false);
81 				SCR_PopLoadingScreen(false);
82 			}
83 	SCR_PopLoadingScreen(false);
84 }
85 
mod_shutdown(void)86 static void mod_shutdown(void)
87 {
88 	int i;
89 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
90 	dp_model_t *mod;
91 
92 	for (i = 0;i < nummodels;i++)
93 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
94 			Mod_UnloadModel(mod);
95 
96 	Mod_FreeQ3Shaders();
97 	Mod_Skeletal_FreeBuffers();
98 }
99 
mod_newmap(void)100 static void mod_newmap(void)
101 {
102 	msurface_t *surface;
103 	int i, j, k, surfacenum, ssize, tsize;
104 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
105 	dp_model_t *mod;
106 
107 	for (i = 0;i < nummodels;i++)
108 	{
109 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
110 		{
111 			for (j = 0;j < mod->num_textures && mod->data_textures;j++)
112 			{
113 				for (k = 0;k < mod->data_textures[j].numskinframes;k++)
114 					R_SkinFrame_MarkUsed(mod->data_textures[j].skinframes[k]);
115 				for (k = 0;k < mod->data_textures[j].backgroundnumskinframes;k++)
116 					R_SkinFrame_MarkUsed(mod->data_textures[j].backgroundskinframes[k]);
117 			}
118 			if (mod->brush.solidskyskinframe)
119 				R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
120 			if (mod->brush.alphaskyskinframe)
121 				R_SkinFrame_MarkUsed(mod->brush.alphaskyskinframe);
122 		}
123 	}
124 
125 	if (!cl_stainmaps_clearonload.integer)
126 		return;
127 
128 	for (i = 0;i < nummodels;i++)
129 	{
130 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
131 		{
132 			for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++)
133 			{
134 				if (surface->lightmapinfo && surface->lightmapinfo->stainsamples)
135 				{
136 					ssize = (surface->lightmapinfo->extents[0] >> 4) + 1;
137 					tsize = (surface->lightmapinfo->extents[1] >> 4) + 1;
138 					memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
139 					mod->brushq1.lightmapupdateflags[surfacenum] = true;
140 				}
141 			}
142 		}
143 	}
144 }
145 
146 /*
147 ===============
148 Mod_Init
149 ===============
150 */
151 static void Mod_Print(void);
152 static void Mod_Precache (void);
153 static void Mod_Decompile_f(void);
154 static void Mod_GenerateLightmaps_f(void);
Mod_Init(void)155 void Mod_Init (void)
156 {
157 	mod_mempool = Mem_AllocPool("modelinfo", 0, NULL);
158 	Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16);
159 
160 	Mod_BrushInit();
161 	Mod_AliasInit();
162 	Mod_SpriteInit();
163 
164 	Cvar_RegisterVariable(&r_enableshadowvolumes);
165 	Cvar_RegisterVariable(&r_mipskins);
166 	Cvar_RegisterVariable(&r_mipnormalmaps);
167 	Cvar_RegisterVariable(&mod_generatelightmaps_unitspersample);
168 	Cvar_RegisterVariable(&mod_generatelightmaps_borderpixels);
169 	Cvar_RegisterVariable(&mod_generatelightmaps_texturesize);
170 
171 	Cvar_RegisterVariable(&mod_generatelightmaps_lightmapsamples);
172 	Cvar_RegisterVariable(&mod_generatelightmaps_vertexsamples);
173 	Cvar_RegisterVariable(&mod_generatelightmaps_gridsamples);
174 	Cvar_RegisterVariable(&mod_generatelightmaps_lightmapradius);
175 	Cvar_RegisterVariable(&mod_generatelightmaps_vertexradius);
176 	Cvar_RegisterVariable(&mod_generatelightmaps_gridradius);
177 
178 	Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models");
179 	Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model");
180 	Cmd_AddCommand ("modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes");
181 	Cmd_AddCommand ("mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel");
182 }
183 
Mod_RenderInit(void)184 void Mod_RenderInit(void)
185 {
186 	R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL);
187 }
188 
Mod_UnloadModel(dp_model_t * mod)189 void Mod_UnloadModel (dp_model_t *mod)
190 {
191 	char name[MAX_QPATH];
192 	qboolean used;
193 	dp_model_t *parentmodel;
194 
195 	if (developer_loading.integer)
196 		Con_Printf("unloading model %s\n", mod->name);
197 
198 	strlcpy(name, mod->name, sizeof(name));
199 	parentmodel = mod->brush.parentmodel;
200 	used = mod->used;
201 	if (mod->mempool)
202 	{
203 		if (mod->surfmesh.data_element3i_indexbuffer)
204 			R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
205 		mod->surfmesh.data_element3i_indexbuffer = NULL;
206 		if (mod->surfmesh.data_element3s_indexbuffer)
207 			R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
208 		mod->surfmesh.data_element3s_indexbuffer = NULL;
209 		if (mod->surfmesh.vbo_vertexbuffer)
210 			R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer);
211 		mod->surfmesh.vbo_vertexbuffer = NULL;
212 	}
213 	// free textures/memory attached to the model
214 	R_FreeTexturePool(&mod->texturepool);
215 	Mem_FreePool(&mod->mempool);
216 	// clear the struct to make it available
217 	memset(mod, 0, sizeof(dp_model_t));
218 	// restore the fields we want to preserve
219 	strlcpy(mod->name, name, sizeof(mod->name));
220 	mod->brush.parentmodel = parentmodel;
221 	mod->used = used;
222 	mod->loaded = false;
223 }
224 
R_Model_Null_Draw(entity_render_t * ent)225 static void R_Model_Null_Draw(entity_render_t *ent)
226 {
227 	return;
228 }
229 
230 
231 typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
232 
Mod_FrameGroupify_ParseGroups(const char * buf,mod_framegroupify_parsegroups_t cb,void * pass)233 static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
234 {
235 	const char *bufptr;
236 	int start, len;
237 	float fps;
238 	unsigned int i;
239 	qboolean loop;
240 	char name[64];
241 
242 	bufptr = buf;
243 	i = 0;
244 	while(bufptr)
245 	{
246 		// an anim scene!
247 
248 		// REQUIRED: fetch start
249 		COM_ParseToken_Simple(&bufptr, true, false, true);
250 		if (!bufptr)
251 			break; // end of file
252 		if (!strcmp(com_token, "\n"))
253 			continue; // empty line
254 		start = atoi(com_token);
255 
256 		// REQUIRED: fetch length
257 		COM_ParseToken_Simple(&bufptr, true, false, true);
258 		if (!bufptr || !strcmp(com_token, "\n"))
259 		{
260 			Con_Printf("framegroups file: missing number of frames\n");
261 			continue;
262 		}
263 		len = atoi(com_token);
264 
265 		// OPTIONAL args start
266 		COM_ParseToken_Simple(&bufptr, true, false, true);
267 
268 		// OPTIONAL: fetch fps
269 		fps = 20;
270 		if (bufptr && strcmp(com_token, "\n"))
271 		{
272 			fps = atof(com_token);
273 			COM_ParseToken_Simple(&bufptr, true, false, true);
274 		}
275 
276 		// OPTIONAL: fetch loopflag
277 		loop = true;
278 		if (bufptr && strcmp(com_token, "\n"))
279 		{
280 			loop = (atoi(com_token) != 0);
281 			COM_ParseToken_Simple(&bufptr, true, false, true);
282 		}
283 
284 		// OPTIONAL: fetch name
285 		name[0] = 0;
286 		if (bufptr && strcmp(com_token, "\n"))
287 		{
288 			strlcpy(name, com_token, sizeof(name));
289 			COM_ParseToken_Simple(&bufptr, true, false, true);
290 		}
291 
292 		// OPTIONAL: remaining unsupported tokens (eat them)
293 		while (bufptr && strcmp(com_token, "\n"))
294 			COM_ParseToken_Simple(&bufptr, true, false, true);
295 
296 		//Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name);
297 
298 		if(cb)
299 			cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
300 		++i;
301 	}
302 
303 	return i;
304 }
305 
Mod_FrameGroupify_ParseGroups_Store(unsigned int i,int start,int len,float fps,qboolean loop,const char * name,void * pass)306 static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass)
307 {
308 	dp_model_t *mod = (dp_model_t *) pass;
309 	animscene_t *anim = &mod->animscenes[i];
310 	if(name)
311 		strlcpy(anim->name, name, sizeof(anim[i].name));
312 	else
313 		dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
314 	anim->firstframe = bound(0, start, mod->num_poses - 1);
315 	anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
316 	anim->framerate = max(1, fps);
317 	anim->loop = !!loop;
318 	//Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
319 }
320 
Mod_FrameGroupify(dp_model_t * mod,const char * buf)321 static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
322 {
323 	unsigned int cnt;
324 
325 	// 0. count
326 	cnt = Mod_FrameGroupify_ParseGroups(buf, NULL, NULL);
327 	if(!cnt)
328 	{
329 		Con_Printf("no scene found in framegroups file, aborting\n");
330 		return;
331 	}
332 	mod->numframes = cnt;
333 
334 	// 1. reallocate
335 	// (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay)
336 	mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes);
337 
338 	// 2. parse
339 	Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
340 }
341 
Mod_FindPotentialDeforms(dp_model_t * mod)342 static void Mod_FindPotentialDeforms(dp_model_t *mod)
343 {
344 	int i, j;
345 	texture_t *texture;
346 	mod->wantnormals = false;
347 	mod->wanttangents = false;
348 	for (i = 0;i < mod->num_textures;i++)
349 	{
350 		texture = mod->data_textures + i;
351 		if (texture->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
352 			mod->wantnormals = true;
353 		for (j = 0;j < Q3MAXDEFORMS;j++)
354 		{
355 			if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
356 			{
357 				mod->wanttangents = true;
358 				mod->wantnormals = true;
359 				break;
360 			}
361 			if (texture->deforms[j].deform != Q3DEFORM_NONE)
362 				mod->wantnormals = true;
363 		}
364 	}
365 }
366 
367 /*
368 ==================
369 Mod_LoadModel
370 
371 Loads a model
372 ==================
373 */
Mod_LoadModel(dp_model_t * mod,qboolean crash,qboolean checkdisk)374 dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
375 {
376 	int num;
377 	unsigned int crc;
378 	void *buf;
379 	fs_offset_t filesize = 0;
380 	char vabuf[1024];
381 
382 	mod->used = true;
383 
384 	if (mod->name[0] == '*') // submodel
385 		return mod;
386 
387 	if (!strcmp(mod->name, "null"))
388 	{
389 		if(mod->loaded)
390 			return mod;
391 
392 		if (mod->loaded || mod->mempool)
393 			Mod_UnloadModel(mod);
394 
395 		if (developer_loading.integer)
396 			Con_Printf("loading model %s\n", mod->name);
397 
398 		mod->used = true;
399 		mod->crc = (unsigned int)-1;
400 		mod->loaded = false;
401 
402 		VectorClear(mod->normalmins);
403 		VectorClear(mod->normalmaxs);
404 		VectorClear(mod->yawmins);
405 		VectorClear(mod->yawmaxs);
406 		VectorClear(mod->rotatedmins);
407 		VectorClear(mod->rotatedmaxs);
408 
409 		mod->modeldatatypestring = "null";
410 		mod->type = mod_null;
411 		mod->Draw = R_Model_Null_Draw;
412 		mod->numframes = 2;
413 		mod->numskins = 1;
414 
415 		// no fatal errors occurred, so this model is ready to use.
416 		mod->loaded = true;
417 
418 		return mod;
419 	}
420 
421 	crc = 0;
422 	buf = NULL;
423 
424 	// even if the model is loaded it still may need reloading...
425 
426 	// if it is not loaded or checkdisk is true we need to calculate the crc
427 	if (!mod->loaded || checkdisk)
428 	{
429 		if (checkdisk && mod->loaded)
430 			Con_DPrintf("checking model %s\n", mod->name);
431 		buf = FS_LoadFile (mod->name, tempmempool, false, &filesize);
432 		if (buf)
433 		{
434 			crc = CRC_Block((unsigned char *)buf, filesize);
435 			// we need to reload the model if the crc does not match
436 			if (mod->crc != crc)
437 				mod->loaded = false;
438 		}
439 	}
440 
441 	// if the model is already loaded and checks passed, just return
442 	if (mod->loaded)
443 	{
444 		if (buf)
445 			Mem_Free(buf);
446 		return mod;
447 	}
448 
449 	if (developer_loading.integer)
450 		Con_Printf("loading model %s\n", mod->name);
451 
452 	SCR_PushLoadingScreen(true, mod->name, 1);
453 
454 	// LordHavoc: unload the existing model in this slot (if there is one)
455 	if (mod->loaded || mod->mempool)
456 		Mod_UnloadModel(mod);
457 
458 	// load the model
459 	mod->used = true;
460 	mod->crc = crc;
461 	// errors can prevent the corresponding mod->loaded = true;
462 	mod->loaded = false;
463 
464 	// default lightmap scale
465 	mod->lightmapscale = 1;
466 
467 	// default model radius and bounding box (mainly for missing models)
468 	mod->radius = 16;
469 	VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius);
470 	VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius);
471 	VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius);
472 	VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius);
473 	VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
474 	VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
475 
476 	if (!q3shaders_mem)
477 	{
478 		// load q3 shaders for the first time, or after a level change
479 		Mod_LoadQ3Shaders();
480 	}
481 
482 	if (buf)
483 	{
484 		char *bufend = (char *)buf + filesize;
485 
486 		// all models use memory, so allocate a memory pool
487 		mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
488 
489 		num = LittleLong(*((int *)buf));
490 		// call the apropriate loader
491 		loadmodel = mod;
492 		if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
493 		else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
494 		else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
495 		else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
496 		else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend);
497 		else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend);
498 		else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend);
499 		else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
500 		else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
501 		else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
502 		else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
503 		else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
504 		else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
505 		else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
506 		Mem_Free(buf);
507 
508 		Mod_FindPotentialDeforms(mod);
509 
510 		buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
511 		if(buf)
512 		{
513 			Mod_FrameGroupify(mod, (const char *)buf);
514 			Mem_Free(buf);
515 		}
516 
517 		Mod_BuildVBOs();
518 	}
519 	else if (crash)
520 	{
521 		// LordHavoc: Sys_Error was *ANNOYING*
522 		Con_Printf ("Mod_LoadModel: %s not found\n", mod->name);
523 	}
524 
525 	// no fatal errors occurred, so this model is ready to use.
526 	mod->loaded = true;
527 
528 	SCR_PopLoadingScreen(false);
529 
530 	return mod;
531 }
532 
Mod_ClearUsed(void)533 void Mod_ClearUsed(void)
534 {
535 	int i;
536 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
537 	dp_model_t *mod;
538 	for (i = 0;i < nummodels;i++)
539 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
540 			mod->used = false;
541 }
542 
Mod_PurgeUnused(void)543 void Mod_PurgeUnused(void)
544 {
545 	int i;
546 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
547 	dp_model_t *mod;
548 	for (i = 0;i < nummodels;i++)
549 	{
550 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
551 		{
552 			Mod_UnloadModel(mod);
553 			Mem_ExpandableArray_FreeRecord(&models, mod);
554 		}
555 	}
556 }
557 
558 /*
559 ==================
560 Mod_FindName
561 
562 ==================
563 */
Mod_FindName(const char * name,const char * parentname)564 dp_model_t *Mod_FindName(const char *name, const char *parentname)
565 {
566 	int i;
567 	int nummodels;
568 	dp_model_t *mod;
569 
570 	if (!parentname)
571 		parentname = "";
572 
573 	// if we're not dedicatd, the renderer calls will crash without video
574 	Host_StartVideo();
575 
576 	nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
577 
578 	if (!name[0])
579 		Host_Error ("Mod_ForName: empty name");
580 
581 	// search the currently loaded models
582 	for (i = 0;i < nummodels;i++)
583 	{
584 		if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !strcmp(mod->name, name) && ((!mod->brush.parentmodel && !parentname[0]) || (mod->brush.parentmodel && parentname[0] && !strcmp(mod->brush.parentmodel->name, parentname))))
585 		{
586 			mod->used = true;
587 			return mod;
588 		}
589 	}
590 
591 	// no match found, create a new one
592 	mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models);
593 	strlcpy(mod->name, name, sizeof(mod->name));
594 	if (parentname[0])
595 		mod->brush.parentmodel = Mod_FindName(parentname, NULL);
596 	else
597 		mod->brush.parentmodel = NULL;
598 	mod->loaded = false;
599 	mod->used = true;
600 	return mod;
601 }
602 
603 /*
604 ==================
605 Mod_ForName
606 
607 Loads in a model for the given name
608 ==================
609 */
Mod_ForName(const char * name,qboolean crash,qboolean checkdisk,const char * parentname)610 dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname)
611 {
612 	dp_model_t *model;
613 	model = Mod_FindName(name, parentname);
614 	if (!model->loaded || checkdisk)
615 		Mod_LoadModel(model, crash, checkdisk);
616 	return model;
617 }
618 
619 /*
620 ==================
621 Mod_Reload
622 
623 Reloads all models if they have changed
624 ==================
625 */
Mod_Reload(void)626 void Mod_Reload(void)
627 {
628 	int i, count;
629 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
630 	dp_model_t *mod;
631 
632 	SCR_PushLoadingScreen(false, "Reloading models", 1.0);
633 	count = 0;
634 	for (i = 0;i < nummodels;i++)
635 		if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
636 			++count;
637 	for (i = 0;i < nummodels;i++)
638 		if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
639 		{
640 			SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
641 			Mod_LoadModel(mod, true, true);
642 			SCR_PopLoadingScreen(false);
643 		}
644 	SCR_PopLoadingScreen(false);
645 }
646 
647 unsigned char *mod_base;
648 
649 
650 //=============================================================================
651 
652 /*
653 ================
654 Mod_Print
655 ================
656 */
Mod_Print(void)657 static void Mod_Print(void)
658 {
659 	int i;
660 	int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
661 	dp_model_t *mod;
662 
663 	Con_Print("Loaded models:\n");
664 	for (i = 0;i < nummodels;i++)
665 	{
666 		if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
667 		{
668 			if (mod->brush.numsubmodels)
669 				Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
670 			else
671 				Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name);
672 		}
673 	}
674 }
675 
676 /*
677 ================
678 Mod_Precache
679 ================
680 */
Mod_Precache(void)681 static void Mod_Precache(void)
682 {
683 	if (Cmd_Argc() == 2)
684 		Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL);
685 	else
686 		Con_Print("usage: modelprecache <filename>\n");
687 }
688 
Mod_BuildVertexRemapTableFromElements(int numelements,const int * elements,int numvertices,int * remapvertices)689 int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
690 {
691 	int i, count;
692 	unsigned char *used;
693 	used = (unsigned char *)Mem_Alloc(tempmempool, numvertices);
694 	memset(used, 0, numvertices);
695 	for (i = 0;i < numelements;i++)
696 		used[elements[i]] = 1;
697 	for (i = 0, count = 0;i < numvertices;i++)
698 		remapvertices[i] = used[i] ? count++ : -1;
699 	Mem_Free(used);
700 	return count;
701 }
702 
703 #if 1
704 // fast way, using an edge hash
705 #define TRIANGLEEDGEHASH 8192
Mod_BuildTriangleNeighbors(int * neighbors,const int * elements,int numtriangles)706 void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles)
707 {
708 	int i, j, p, e1, e2, *n, hashindex, count, match;
709 	const int *e;
710 	typedef struct edgehashentry_s
711 	{
712 		struct edgehashentry_s *next;
713 		int triangle;
714 		int element[2];
715 	}
716 	edgehashentry_t;
717 	static edgehashentry_t **edgehash;
718 	edgehashentry_t *edgehashentries, *hash;
719 	if (!numtriangles)
720 		return;
721 	edgehash = (edgehashentry_t **)Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash));
722 	// if there are too many triangles for the stack array, allocate larger buffer
723 	edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t));
724 	// find neighboring triangles
725 	for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
726 	{
727 		for (j = 0, p = 2;j < 3;p = j, j++)
728 		{
729 			e1 = e[p];
730 			e2 = e[j];
731 			// this hash index works for both forward and backward edges
732 			hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH;
733 			hash = edgehashentries + i * 3 + j;
734 			hash->next = edgehash[hashindex];
735 			edgehash[hashindex] = hash;
736 			hash->triangle = i;
737 			hash->element[0] = e1;
738 			hash->element[1] = e2;
739 		}
740 	}
741 	for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
742 	{
743 		for (j = 0, p = 2;j < 3;p = j, j++)
744 		{
745 			e1 = e[p];
746 			e2 = e[j];
747 			// this hash index works for both forward and backward edges
748 			hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH;
749 			count = 0;
750 			match = -1;
751 			for (hash = edgehash[hashindex];hash;hash = hash->next)
752 			{
753 				if (hash->element[0] == e2 && hash->element[1] == e1)
754 				{
755 					if (hash->triangle != i)
756 						match = hash->triangle;
757 					count++;
758 				}
759 				else if ((hash->element[0] == e1 && hash->element[1] == e2))
760 					count++;
761 			}
762 			// detect edges shared by three triangles and make them seams
763 			if (count > 2)
764 				match = -1;
765 			n[p] = match;
766 		}
767 
768 		// also send a keepalive here (this can take a while too!)
769 		CL_KeepaliveMessage(false);
770 	}
771 	// free the allocated buffer
772 	Mem_Free(edgehashentries);
773 	Mem_Free(edgehash);
774 }
775 #else
776 // very slow but simple way
Mod_FindTriangleWithEdge(const int * elements,int numtriangles,int start,int end,int ignore)777 static int Mod_FindTriangleWithEdge(const int *elements, int numtriangles, int start, int end, int ignore)
778 {
779 	int i, match, count;
780 	count = 0;
781 	match = -1;
782 	for (i = 0;i < numtriangles;i++, elements += 3)
783 	{
784 		     if ((elements[0] == start && elements[1] == end)
785 		      || (elements[1] == start && elements[2] == end)
786 		      || (elements[2] == start && elements[0] == end))
787 		{
788 			if (i != ignore)
789 				match = i;
790 			count++;
791 		}
792 		else if ((elements[1] == start && elements[0] == end)
793 		      || (elements[2] == start && elements[1] == end)
794 		      || (elements[0] == start && elements[2] == end))
795 			count++;
796 	}
797 	// detect edges shared by three triangles and make them seams
798 	if (count > 2)
799 		match = -1;
800 	return match;
801 }
802 
Mod_BuildTriangleNeighbors(int * neighbors,const int * elements,int numtriangles)803 void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles)
804 {
805 	int i, *n;
806 	const int *e;
807 	for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
808 	{
809 		n[0] = Mod_FindTriangleWithEdge(elements, numtriangles, e[1], e[0], i);
810 		n[1] = Mod_FindTriangleWithEdge(elements, numtriangles, e[2], e[1], i);
811 		n[2] = Mod_FindTriangleWithEdge(elements, numtriangles, e[0], e[2], i);
812 	}
813 }
814 #endif
815 
Mod_ValidateElements(int * elements,int numtriangles,int firstvertex,int numverts,const char * filename,int fileline)816 void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline)
817 {
818 	int i, warned = false, endvertex = firstvertex + numverts;
819 	for (i = 0;i < numtriangles * 3;i++)
820 	{
821 		if (elements[i] < firstvertex || elements[i] >= endvertex)
822 		{
823 			if (!warned)
824 			{
825 				warned = true;
826 				Con_Printf("Mod_ValidateElements: out of bounds elements detected at %s:%d\n", filename, fileline);
827 			}
828 			elements[i] = firstvertex;
829 		}
830 	}
831 }
832 
833 // warning: this is an expensive function!
Mod_BuildNormals(int firstvertex,int numvertices,int numtriangles,const float * vertex3f,const int * elements,float * normal3f,qboolean areaweighting)834 void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting)
835 {
836 	int i, j;
837 	const int *element;
838 	float *vectorNormal;
839 	float areaNormal[3];
840 	// clear the vectors
841 	memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
842 	// process each vertex of each triangle and accumulate the results
843 	// use area-averaging, to make triangles with a big area have a bigger
844 	// weighting on the vertex normal than triangles with a small area
845 	// to do so, just add the 'normals' together (the bigger the area
846 	// the greater the length of the normal is
847 	element = elements;
848 	for (i = 0; i < numtriangles; i++, element += 3)
849 	{
850 		TriangleNormal(
851 			vertex3f + element[0] * 3,
852 			vertex3f + element[1] * 3,
853 			vertex3f + element[2] * 3,
854 			areaNormal
855 			);
856 
857 		if (!areaweighting)
858 			VectorNormalize(areaNormal);
859 
860 		for (j = 0;j < 3;j++)
861 		{
862 			vectorNormal = normal3f + element[j] * 3;
863 			vectorNormal[0] += areaNormal[0];
864 			vectorNormal[1] += areaNormal[1];
865 			vectorNormal[2] += areaNormal[2];
866 		}
867 	}
868 	// and just normalize the accumulated vertex normal in the end
869 	vectorNormal = normal3f + 3 * firstvertex;
870 	for (i = 0; i < numvertices; i++, vectorNormal += 3)
871 		VectorNormalize(vectorNormal);
872 }
873 
874 #if 0
875 static void Mod_BuildBumpVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f)
876 {
877 	float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
878 	// 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
879 	// 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
880 
881 	// 6 multiply, 9 subtract
882 	VectorSubtract(v1, v0, v10);
883 	VectorSubtract(v2, v0, v20);
884 	normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1];
885 	normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2];
886 	normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0];
887 	// 12 multiply, 10 subtract
888 	tc10[1] = tc1[1] - tc0[1];
889 	tc20[1] = tc2[1] - tc0[1];
890 	svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
891 	svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
892 	svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
893 	tc10[0] = tc1[0] - tc0[0];
894 	tc20[0] = tc2[0] - tc0[0];
895 	tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
896 	tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
897 	tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
898 	// 12 multiply, 4 add, 6 subtract
899 	f = DotProduct(svector3f, normal3f);
900 	svector3f[0] -= f * normal3f[0];
901 	svector3f[1] -= f * normal3f[1];
902 	svector3f[2] -= f * normal3f[2];
903 	f = DotProduct(tvector3f, normal3f);
904 	tvector3f[0] -= f * normal3f[0];
905 	tvector3f[1] -= f * normal3f[1];
906 	tvector3f[2] -= f * normal3f[2];
907 	// if texture is mapped the wrong way (counterclockwise), the tangents
908 	// have to be flipped, this is detected by calculating a normal from the
909 	// two tangents, and seeing if it is opposite the surface normal
910 	// 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
911 	CrossProduct(tvector3f, svector3f, tangentcross);
912 	if (DotProduct(tangentcross, normal3f) < 0)
913 	{
914 		VectorNegate(svector3f, svector3f);
915 		VectorNegate(tvector3f, tvector3f);
916 	}
917 }
918 #endif
919 
920 // warning: this is a very expensive function!
Mod_BuildTextureVectorsFromNormals(int firstvertex,int numvertices,int numtriangles,const float * vertex3f,const float * texcoord2f,const float * normal3f,const int * elements,float * svector3f,float * tvector3f,qboolean areaweighting)921 void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qboolean areaweighting)
922 {
923 	int i, tnum;
924 	float sdir[3], tdir[3], normal[3], *svec, *tvec;
925 	const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
926 	float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
927 	const int *e;
928 	// clear the vectors
929 	memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
930 	memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
931 	// process each vertex of each triangle and accumulate the results
932 	for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
933 	{
934 		v0 = vertex3f + e[0] * 3;
935 		v1 = vertex3f + e[1] * 3;
936 		v2 = vertex3f + e[2] * 3;
937 		tc0 = texcoord2f + e[0] * 2;
938 		tc1 = texcoord2f + e[1] * 2;
939 		tc2 = texcoord2f + e[2] * 2;
940 
941 		// 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
942 		// 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
943 
944 		// calculate the edge directions and surface normal
945 		// 6 multiply, 9 subtract
946 		VectorSubtract(v1, v0, v10);
947 		VectorSubtract(v2, v0, v20);
948 		normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
949 		normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
950 		normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
951 
952 		// calculate the tangents
953 		// 12 multiply, 10 subtract
954 		tc10[1] = tc1[1] - tc0[1];
955 		tc20[1] = tc2[1] - tc0[1];
956 		sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
957 		sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
958 		sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
959 		tc10[0] = tc1[0] - tc0[0];
960 		tc20[0] = tc2[0] - tc0[0];
961 		tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
962 		tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
963 		tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
964 
965 		// if texture is mapped the wrong way (counterclockwise), the tangents
966 		// have to be flipped, this is detected by calculating a normal from the
967 		// two tangents, and seeing if it is opposite the surface normal
968 		// 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
969 		CrossProduct(tdir, sdir, tangentcross);
970 		if (DotProduct(tangentcross, normal) < 0)
971 		{
972 			VectorNegate(sdir, sdir);
973 			VectorNegate(tdir, tdir);
974 		}
975 
976 		if (!areaweighting)
977 		{
978 			VectorNormalize(sdir);
979 			VectorNormalize(tdir);
980 		}
981 		for (i = 0;i < 3;i++)
982 		{
983 			VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
984 			VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
985 		}
986 	}
987 	// make the tangents completely perpendicular to the surface normal, and
988 	// then normalize them
989 	// 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
990 	for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
991 	{
992 		f = -DotProduct(svec, n);
993 		VectorMA(svec, f, n, svec);
994 		VectorNormalize(svec);
995 		f = -DotProduct(tvec, n);
996 		VectorMA(tvec, f, n, tvec);
997 		VectorNormalize(tvec);
998 	}
999 }
1000 
Mod_AllocSurfMesh(mempool_t * mempool,int numvertices,int numtriangles,qboolean lightmapoffsets,qboolean vertexcolors,qboolean neighbors)1001 void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors)
1002 {
1003 	unsigned char *data;
1004 	data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * (3 + (neighbors ? 3 : 0)) * sizeof(int) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0));
1005 	loadmodel->surfmesh.num_vertices = numvertices;
1006 	loadmodel->surfmesh.num_triangles = numtriangles;
1007 	if (loadmodel->surfmesh.num_vertices)
1008 	{
1009 		loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1010 		loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1011 		loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1012 		loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1013 		loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
1014 		loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
1015 		if (vertexcolors)
1016 			loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices;
1017 		if (lightmapoffsets)
1018 			loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices;
1019 	}
1020 	if (loadmodel->surfmesh.num_triangles)
1021 	{
1022 		loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
1023 		if (neighbors)
1024 			loadmodel->surfmesh.data_neighbor3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
1025 		if (loadmodel->surfmesh.num_vertices <= 65536)
1026 			loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles;
1027 	}
1028 }
1029 
Mod_ShadowMesh_Alloc(mempool_t * mempool,int maxverts,int maxtriangles,rtexture_t * map_diffuse,rtexture_t * map_specular,rtexture_t * map_normal,int light,int neighbors,int expandable)1030 shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
1031 {
1032 	shadowmesh_t *newmesh;
1033 	unsigned char *data;
1034 	int size;
1035 	size = sizeof(shadowmesh_t);
1036 	size += maxverts * sizeof(float[3]);
1037 	if (light)
1038 		size += maxverts * sizeof(float[11]);
1039 	size += maxtriangles * sizeof(int[3]);
1040 	if (maxverts <= 65536)
1041 		size += maxtriangles * sizeof(unsigned short[3]);
1042 	if (neighbors)
1043 		size += maxtriangles * sizeof(int[3]);
1044 	if (expandable)
1045 		size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t);
1046 	data = (unsigned char *)Mem_Alloc(mempool, size);
1047 	newmesh = (shadowmesh_t *)data;data += sizeof(*newmesh);
1048 	newmesh->map_diffuse = map_diffuse;
1049 	newmesh->map_specular = map_specular;
1050 	newmesh->map_normal = map_normal;
1051 	newmesh->maxverts = maxverts;
1052 	newmesh->maxtriangles = maxtriangles;
1053 	newmesh->numverts = 0;
1054 	newmesh->numtriangles = 0;
1055 	memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
1056 	memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
1057 
1058 	newmesh->vertex3f = (float *)data;data += maxverts * sizeof(float[3]);
1059 	if (light)
1060 	{
1061 		newmesh->svector3f = (float *)data;data += maxverts * sizeof(float[3]);
1062 		newmesh->tvector3f = (float *)data;data += maxverts * sizeof(float[3]);
1063 		newmesh->normal3f = (float *)data;data += maxverts * sizeof(float[3]);
1064 		newmesh->texcoord2f = (float *)data;data += maxverts * sizeof(float[2]);
1065 	}
1066 	newmesh->element3i = (int *)data;data += maxtriangles * sizeof(int[3]);
1067 	if (neighbors)
1068 	{
1069 		newmesh->neighbor3i = (int *)data;data += maxtriangles * sizeof(int[3]);
1070 	}
1071 	if (expandable)
1072 	{
1073 		newmesh->vertexhashtable = (shadowmeshvertexhash_t **)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *);
1074 		newmesh->vertexhashentries = (shadowmeshvertexhash_t *)data;data += maxverts * sizeof(shadowmeshvertexhash_t);
1075 	}
1076 	if (maxverts <= 65536)
1077 		newmesh->element3s = (unsigned short *)data;data += maxtriangles * sizeof(unsigned short[3]);
1078 	return newmesh;
1079 }
1080 
Mod_ShadowMesh_ReAlloc(mempool_t * mempool,shadowmesh_t * oldmesh,int light,int neighbors)1081 shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors)
1082 {
1083 	shadowmesh_t *newmesh;
1084 	newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, neighbors, false);
1085 	newmesh->numverts = oldmesh->numverts;
1086 	newmesh->numtriangles = oldmesh->numtriangles;
1087 	memcpy(newmesh->sideoffsets, oldmesh->sideoffsets, sizeof(oldmesh->sideoffsets));
1088 	memcpy(newmesh->sidetotals, oldmesh->sidetotals, sizeof(oldmesh->sidetotals));
1089 
1090 	memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3]));
1091 	if (newmesh->svector3f && oldmesh->svector3f)
1092 	{
1093 		memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3]));
1094 		memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3]));
1095 		memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3]));
1096 		memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2]));
1097 	}
1098 	memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3]));
1099 	if (newmesh->neighbor3i && oldmesh->neighbor3i)
1100 		memcpy(newmesh->neighbor3i, oldmesh->neighbor3i, oldmesh->numtriangles * sizeof(int[3]));
1101 	return newmesh;
1102 }
1103 
Mod_ShadowMesh_AddVertex(shadowmesh_t * mesh,float * vertex14f)1104 int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f)
1105 {
1106 	int hashindex, vnum;
1107 	shadowmeshvertexhash_t *hash;
1108 	// this uses prime numbers intentionally
1109 	hashindex = (unsigned int) (vertex14f[0] * 2003 + vertex14f[1] * 4001 + vertex14f[2] * 7919) % SHADOWMESHVERTEXHASH;
1110 	for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
1111 	{
1112 		vnum = (hash - mesh->vertexhashentries);
1113 		if ((mesh->vertex3f == NULL || (mesh->vertex3f[vnum * 3 + 0] == vertex14f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex14f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex14f[2]))
1114 		 && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5]))
1115 		 && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8]))
1116 		 && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11]))
1117 		 && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13])))
1118 			return hash - mesh->vertexhashentries;
1119 	}
1120 	vnum = mesh->numverts++;
1121 	hash = mesh->vertexhashentries + vnum;
1122 	hash->next = mesh->vertexhashtable[hashindex];
1123 	mesh->vertexhashtable[hashindex] = hash;
1124 	if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];}
1125 	if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];}
1126 	if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];}
1127 	if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];}
1128 	if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];}
1129 	return vnum;
1130 }
1131 
Mod_ShadowMesh_AddTriangle(mempool_t * mempool,shadowmesh_t * mesh,rtexture_t * map_diffuse,rtexture_t * map_specular,rtexture_t * map_normal,float * vertex14f)1132 void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f)
1133 {
1134 	if (mesh->numtriangles == 0)
1135 	{
1136 		// set the properties on this empty mesh to be more favorable...
1137 		// (note: this case only occurs for the first triangle added to a new mesh chain)
1138 		mesh->map_diffuse = map_diffuse;
1139 		mesh->map_specular = map_specular;
1140 		mesh->map_normal = map_normal;
1141 	}
1142 	while (mesh->map_diffuse != map_diffuse || mesh->map_specular != map_specular || mesh->map_normal != map_normal || mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
1143 	{
1144 		if (mesh->next == NULL)
1145 			mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, mesh->neighbor3i != NULL, true);
1146 		mesh = mesh->next;
1147 	}
1148 	mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0);
1149 	mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1);
1150 	mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2);
1151 	mesh->numtriangles++;
1152 }
1153 
Mod_ShadowMesh_AddMesh(mempool_t * mempool,shadowmesh_t * mesh,rtexture_t * map_diffuse,rtexture_t * map_specular,rtexture_t * map_normal,const float * vertex3f,const float * svector3f,const float * tvector3f,const float * normal3f,const float * texcoord2f,int numtris,const int * element3i)1154 void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i)
1155 {
1156 	int i, j, e;
1157 	float vbuf[3*14], *v;
1158 	memset(vbuf, 0, sizeof(vbuf));
1159 	for (i = 0;i < numtris;i++)
1160 	{
1161 		for (j = 0, v = vbuf;j < 3;j++, v += 14)
1162 		{
1163 			e = *element3i++;
1164 			if (vertex3f)
1165 			{
1166 				v[0] = vertex3f[e * 3 + 0];
1167 				v[1] = vertex3f[e * 3 + 1];
1168 				v[2] = vertex3f[e * 3 + 2];
1169 			}
1170 			if (svector3f)
1171 			{
1172 				v[3] = svector3f[e * 3 + 0];
1173 				v[4] = svector3f[e * 3 + 1];
1174 				v[5] = svector3f[e * 3 + 2];
1175 			}
1176 			if (tvector3f)
1177 			{
1178 				v[6] = tvector3f[e * 3 + 0];
1179 				v[7] = tvector3f[e * 3 + 1];
1180 				v[8] = tvector3f[e * 3 + 2];
1181 			}
1182 			if (normal3f)
1183 			{
1184 				v[9] = normal3f[e * 3 + 0];
1185 				v[10] = normal3f[e * 3 + 1];
1186 				v[11] = normal3f[e * 3 + 2];
1187 			}
1188 			if (texcoord2f)
1189 			{
1190 				v[12] = texcoord2f[e * 2 + 0];
1191 				v[13] = texcoord2f[e * 2 + 1];
1192 			}
1193 		}
1194 		Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf);
1195 	}
1196 
1197 	// the triangle calculation can take a while, so let's do a keepalive here
1198 	CL_KeepaliveMessage(false);
1199 }
1200 
Mod_ShadowMesh_Begin(mempool_t * mempool,int maxverts,int maxtriangles,rtexture_t * map_diffuse,rtexture_t * map_specular,rtexture_t * map_normal,int light,int neighbors,int expandable)1201 shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
1202 {
1203 	// the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
1204 	CL_KeepaliveMessage(false);
1205 
1206 	return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable);
1207 }
1208 
Mod_ShadowMesh_CreateVBOs(shadowmesh_t * mesh,mempool_t * mempool)1209 static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
1210 {
1211 	if (!mesh->numverts)
1212 		return;
1213 
1214 	// build r_vertexmesh_t array
1215 	// (compressed interleaved array for D3D)
1216 	if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays)
1217 	{
1218 		int vertexindex;
1219 		int numvertices = mesh->numverts;
1220 		r_vertexmesh_t *vertexmesh;
1221 		mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(mempool, numvertices * sizeof(*mesh->vertexmesh));
1222 		for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
1223 		{
1224 			VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f);
1225 			VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
1226 			VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
1227 			VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
1228 			Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
1229 		}
1230 	}
1231 
1232 	// upload short indices as a buffer
1233 	if (mesh->element3s && !mesh->element3s_indexbuffer)
1234 		mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
1235 
1236 	// upload int indices as a buffer
1237 	if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
1238 		mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
1239 
1240 	// vertex buffer is several arrays and we put them in the same buffer
1241 	//
1242 	// is this wise?  the texcoordtexture2f array is used with dynamic
1243 	// vertex/svector/tvector/normal when rendering animated models, on the
1244 	// other hand animated models don't use a lot of vertices anyway...
1245 	if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays)
1246 	{
1247 		int size;
1248 		unsigned char *mem;
1249 		size = 0;
1250 		mesh->vbooffset_vertexmesh         = size;if (mesh->vertexmesh        ) size += mesh->numverts * sizeof(r_vertexmesh_t);
1251 		mesh->vbooffset_vertex3f           = size;if (mesh->vertex3f          ) size += mesh->numverts * sizeof(float[3]);
1252 		mesh->vbooffset_svector3f          = size;if (mesh->svector3f         ) size += mesh->numverts * sizeof(float[3]);
1253 		mesh->vbooffset_tvector3f          = size;if (mesh->tvector3f         ) size += mesh->numverts * sizeof(float[3]);
1254 		mesh->vbooffset_normal3f           = size;if (mesh->normal3f          ) size += mesh->numverts * sizeof(float[3]);
1255 		mesh->vbooffset_texcoord2f         = size;if (mesh->texcoord2f        ) size += mesh->numverts * sizeof(float[2]);
1256 		mem = (unsigned char *)Mem_Alloc(tempmempool, size);
1257 		if (mesh->vertexmesh        ) memcpy(mem + mesh->vbooffset_vertexmesh        , mesh->vertexmesh        , mesh->numverts * sizeof(r_vertexmesh_t));
1258 		if (mesh->vertex3f          ) memcpy(mem + mesh->vbooffset_vertex3f          , mesh->vertex3f          , mesh->numverts * sizeof(float[3]));
1259 		if (mesh->svector3f         ) memcpy(mem + mesh->vbooffset_svector3f         , mesh->svector3f         , mesh->numverts * sizeof(float[3]));
1260 		if (mesh->tvector3f         ) memcpy(mem + mesh->vbooffset_tvector3f         , mesh->tvector3f         , mesh->numverts * sizeof(float[3]));
1261 		if (mesh->normal3f          ) memcpy(mem + mesh->vbooffset_normal3f          , mesh->normal3f          , mesh->numverts * sizeof(float[3]));
1262 		if (mesh->texcoord2f        ) memcpy(mem + mesh->vbooffset_texcoord2f        , mesh->texcoord2f        , mesh->numverts * sizeof(float[2]));
1263 		mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false);
1264 		Mem_Free(mem);
1265 	}
1266 }
1267 
Mod_ShadowMesh_Finish(mempool_t * mempool,shadowmesh_t * firstmesh,qboolean light,qboolean neighbors,qboolean createvbo)1268 shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo)
1269 {
1270 	shadowmesh_t *mesh, *newmesh, *nextmesh;
1271 	// reallocate meshs to conserve space
1272 	for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
1273 	{
1274 		nextmesh = mesh->next;
1275 		if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
1276 		{
1277 			newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light, neighbors);
1278 			newmesh->next = firstmesh;
1279 			firstmesh = newmesh;
1280 			if (newmesh->element3s)
1281 			{
1282 				int i;
1283 				for (i = 0;i < newmesh->numtriangles*3;i++)
1284 					newmesh->element3s[i] = newmesh->element3i[i];
1285 			}
1286 			if (createvbo)
1287 				Mod_ShadowMesh_CreateVBOs(newmesh, mempool);
1288 		}
1289 		Mem_Free(mesh);
1290 	}
1291 
1292 	// this can take a while, so let's do a keepalive here
1293 	CL_KeepaliveMessage(false);
1294 
1295 	return firstmesh;
1296 }
1297 
Mod_ShadowMesh_CalcBBox(shadowmesh_t * firstmesh,vec3_t mins,vec3_t maxs,vec3_t center,float * radius)1298 void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
1299 {
1300 	int i;
1301 	shadowmesh_t *mesh;
1302 	vec3_t nmins, nmaxs, ncenter, temp;
1303 	float nradius2, dist2, *v;
1304 	VectorClear(nmins);
1305 	VectorClear(nmaxs);
1306 	// calculate bbox
1307 	for (mesh = firstmesh;mesh;mesh = mesh->next)
1308 	{
1309 		if (mesh == firstmesh)
1310 		{
1311 			VectorCopy(mesh->vertex3f, nmins);
1312 			VectorCopy(mesh->vertex3f, nmaxs);
1313 		}
1314 		for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1315 		{
1316 			if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0];
1317 			if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1];
1318 			if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2];
1319 		}
1320 	}
1321 	// calculate center and radius
1322 	ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
1323 	ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
1324 	ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
1325 	nradius2 = 0;
1326 	for (mesh = firstmesh;mesh;mesh = mesh->next)
1327 	{
1328 		for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1329 		{
1330 			VectorSubtract(v, ncenter, temp);
1331 			dist2 = DotProduct(temp, temp);
1332 			if (nradius2 < dist2)
1333 				nradius2 = dist2;
1334 		}
1335 	}
1336 	// return data
1337 	if (mins)
1338 		VectorCopy(nmins, mins);
1339 	if (maxs)
1340 		VectorCopy(nmaxs, maxs);
1341 	if (center)
1342 		VectorCopy(ncenter, center);
1343 	if (radius)
1344 		*radius = sqrt(nradius2);
1345 }
1346 
Mod_ShadowMesh_Free(shadowmesh_t * mesh)1347 void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
1348 {
1349 	shadowmesh_t *nextmesh;
1350 	for (;mesh;mesh = nextmesh)
1351 	{
1352 		if (mesh->element3i_indexbuffer)
1353 			R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
1354 		if (mesh->element3s_indexbuffer)
1355 			R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
1356 		if (mesh->vbo_vertexbuffer)
1357 			R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
1358 		nextmesh = mesh->next;
1359 		Mem_Free(mesh);
1360 	}
1361 }
1362 
Mod_CreateCollisionMesh(dp_model_t * mod)1363 void Mod_CreateCollisionMesh(dp_model_t *mod)
1364 {
1365 	int k, numcollisionmeshtriangles;
1366 	qboolean usesinglecollisionmesh = false;
1367 	const msurface_t *surface = NULL;
1368 
1369 	mempool_t *mempool = mod->mempool;
1370 	if (!mempool && mod->brush.parentmodel)
1371 		mempool = mod->brush.parentmodel->mempool;
1372 	// make a single combined collision mesh for physics engine use
1373 	// TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
1374 	numcollisionmeshtriangles = 0;
1375 	for (k = 0;k < mod->nummodelsurfaces;k++)
1376 	{
1377 		surface = mod->data_surfaces + mod->firstmodelsurface + k;
1378 		if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
1379 		{
1380 			usesinglecollisionmesh = true;
1381 			numcollisionmeshtriangles = surface->num_triangles;
1382 			break;
1383 		}
1384 		if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1385 			continue;
1386 		numcollisionmeshtriangles += surface->num_triangles;
1387 	}
1388 	mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, false, true);
1389 	if (usesinglecollisionmesh)
1390 		Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1391 	else
1392 	{
1393 		for (k = 0;k < mod->nummodelsurfaces;k++)
1394 		{
1395 			surface = mod->data_surfaces + mod->firstmodelsurface + k;
1396 			if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1397 				continue;
1398 			Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1399 		}
1400 	}
1401 	mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false, false);
1402 }
1403 
1404 #if 0
1405 static void Mod_GetTerrainVertex3fTexCoord2fFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1406 {
1407 	float v[3], tc[3];
1408 	v[0] = ix;
1409 	v[1] = iy;
1410 	if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1411 		v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1412 	else
1413 		v[2] = 0;
1414 	Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1415 	Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1416 	texcoord2f[0] = tc[0];
1417 	texcoord2f[1] = tc[1];
1418 }
1419 
1420 static void Mod_GetTerrainVertexFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int ix, int iy, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1421 {
1422 	float vup[3], vdown[3], vleft[3], vright[3];
1423 	float tcup[3], tcdown[3], tcleft[3], tcright[3];
1424 	float sv[3], tv[3], nl[3];
1425 	Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1426 	Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1427 	Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1428 	Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1429 	Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1430 	Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1431 	Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1432 	VectorAdd(svector3f, sv, svector3f);
1433 	VectorAdd(tvector3f, tv, tvector3f);
1434 	VectorAdd(normal3f, nl, normal3f);
1435 	Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1436 	VectorAdd(svector3f, sv, svector3f);
1437 	VectorAdd(tvector3f, tv, tvector3f);
1438 	VectorAdd(normal3f, nl, normal3f);
1439 	Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1440 	VectorAdd(svector3f, sv, svector3f);
1441 	VectorAdd(tvector3f, tv, tvector3f);
1442 	VectorAdd(normal3f, nl, normal3f);
1443 }
1444 
1445 static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, int *neighbor3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1446 {
1447 	int x, y, ix, iy, *e;
1448 	e = element3i;
1449 	for (y = 0;y < height;y++)
1450 	{
1451 		for (x = 0;x < width;x++)
1452 		{
1453 			e[0] = (y + 1) * (width + 1) + (x + 0);
1454 			e[1] = (y + 0) * (width + 1) + (x + 0);
1455 			e[2] = (y + 1) * (width + 1) + (x + 1);
1456 			e[3] = (y + 0) * (width + 1) + (x + 0);
1457 			e[4] = (y + 0) * (width + 1) + (x + 1);
1458 			e[5] = (y + 1) * (width + 1) + (x + 1);
1459 			e += 6;
1460 		}
1461 	}
1462 	Mod_BuildTriangleNeighbors(neighbor3i, element3i, width*height*2);
1463 	for (y = 0, iy = y1;y < height + 1;y++, iy++)
1464 		for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1465 			Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1466 }
1467 #endif
1468 
1469 #if 0
1470 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
1471 {
1472 	float mins[3];
1473 	float maxs[3];
1474 	float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1475 	float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1476 	float viewvector[3];
1477 	unsigned int firstvertex;
1478 	unsigned int *e;
1479 	float *v;
1480 	if (chunkwidth < 2 || chunkheight < 2)
1481 		return;
1482 	VectorSet(mins, model->terrain.mins[0] +  x    * stepsize * model->terrain.scale[0], model->terrain.mins[1] +  y    * stepsize * model->terrain.scale[1], model->terrain.mins[2]);
1483 	VectorSet(maxs, model->terrain.mins[0] + (x+1) * stepsize * model->terrain.scale[0], model->terrain.mins[1] + (y+1) * stepsize * model->terrain.scale[1], model->terrain.maxs[2]);
1484 	viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1485 	viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1486 	viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1487 	if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1488 	{
1489 		// too close for this stepsize, emit as 4 chunks instead
1490 		stepsize /= 2;
1491 		Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1492 		Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1493 		Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1494 		Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1495 		return;
1496 	}
1497 	// emit the geometry at stepsize into our vertex buffer / index buffer
1498 	// we add two columns and two rows for skirt
1499 	outwidth = chunkwidth+2;
1500 	outheight = chunkheight+2;
1501 	outwidth2 = outwidth-1;
1502 	outheight2 = outheight-1;
1503 	outwidth3 = outwidth+1;
1504 	outheight3 = outheight+1;
1505 	firstvertex = numvertices;
1506 	e = model->terrain.element3i + numtriangles;
1507 	numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1508 	v = model->terrain.vertex3f + numvertices;
1509 	numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1510 	// emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1511 	for (ty = 0;ty < outheight;ty++)
1512 	{
1513 		for (tx = 0;tx < outwidth;tx++)
1514 		{
1515 			*e++ = firstvertex + (ty  )*outwidth3+(tx  );
1516 			*e++ = firstvertex + (ty  )*outwidth3+(tx+1);
1517 			*e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1518 			*e++ = firstvertex + (ty  )*outwidth3+(tx  );
1519 			*e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1520 			*e++ = firstvertex + (ty+1)*outwidth3+(tx  );
1521 		}
1522 	}
1523 	// TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1524 	for (ty = 0;ty <= outheight;ty++)
1525 	{
1526 		skirtrow = ty == 0 || ty == outheight;
1527 		ry = y+bound(1, ty, outheight)*stepsize;
1528 		for (tx = 0;tx <= outwidth;tx++)
1529 		{
1530 			skirt = skirtrow || tx == 0 || tx == outwidth;
1531 			rx = x+bound(1, tx, outwidth)*stepsize;
1532 			v[0] = rx*scale[0];
1533 			v[1] = ry*scale[1];
1534 			v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1535 			v += 3;
1536 		}
1537 	}
1538 	// TODO: emit skirt vertices
1539 }
1540 
1541 void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
1542 {
1543 	for (y = 0;y < model->terrain.size[1];y += model->terrain.
1544 	Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1545 	Mod_Terrain_BuildChunk(model,
1546 }
1547 #endif
1548 
Mod_LoadQ3Shaders_EnumerateWaveFunc(const char * s)1549 static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
1550 {
1551 	int offset = 0;
1552 	if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1553 	{
1554 		offset = bound(0, s[4] - '0', 9);
1555 		offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
1556 		s += 4;
1557 		if(*s)
1558 			++s;
1559 	}
1560 	if (!strcasecmp(s, "sin"))             return offset | Q3WAVEFUNC_SIN;
1561 	if (!strcasecmp(s, "square"))          return offset | Q3WAVEFUNC_SQUARE;
1562 	if (!strcasecmp(s, "triangle"))        return offset | Q3WAVEFUNC_TRIANGLE;
1563 	if (!strcasecmp(s, "sawtooth"))        return offset | Q3WAVEFUNC_SAWTOOTH;
1564 	if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1565 	if (!strcasecmp(s, "noise"))           return offset | Q3WAVEFUNC_NOISE;
1566 	if (!strcasecmp(s, "none"))            return offset | Q3WAVEFUNC_NONE;
1567 	Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1568 	return offset | Q3WAVEFUNC_NONE;
1569 }
1570 
Mod_FreeQ3Shaders(void)1571 void Mod_FreeQ3Shaders(void)
1572 {
1573 	Mem_FreePool(&q3shaders_mem);
1574 }
1575 
Q3Shader_AddToHash(q3shaderinfo_t * shader)1576 static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
1577 {
1578 	unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1579 	q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
1580 	q3shader_hash_entry_t* lastEntry = NULL;
1581 	do
1582 	{
1583 		if (strcasecmp (entry->shader.name, shader->name) == 0)
1584 		{
1585 			// redeclaration
1586 			if(shader->dpshaderkill)
1587 			{
1588 				// killed shader is a redeclarion? we can safely ignore it
1589 				return;
1590 			}
1591 			else if(entry->shader.dpshaderkill)
1592 			{
1593 				// replace the old shader!
1594 				// this will skip the entry allocating part
1595 				// below and just replace the shader
1596 				break;
1597 			}
1598 			else
1599 			{
1600 				unsigned char *start, *end, *start2;
1601 				start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1602 				end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1603 				start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1604 				if(memcmp(start, start2, end - start))
1605 					Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1606 				else
1607 					Con_DPrintf("Shader '%s' already defined\n", shader->name);
1608 				return;
1609 			}
1610 		}
1611 		lastEntry = entry;
1612 		entry = entry->chain;
1613 	}
1614 	while (entry != NULL);
1615 	if (entry == NULL)
1616 	{
1617 		if (lastEntry->shader.name[0] != 0)
1618 		{
1619 			/* Add to chain */
1620 			q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*)
1621 			  Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries);
1622 
1623 			while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1624 			lastEntry->chain = newEntry;
1625 			newEntry->chain = NULL;
1626 			lastEntry = newEntry;
1627 		}
1628 		/* else: head of chain, in hash entry array */
1629 		entry = lastEntry;
1630 	}
1631 	memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
1632 }
1633 
1634 extern cvar_t mod_noshader_default_offsetmapping;
1635 extern cvar_t mod_q3shader_default_offsetmapping;
1636 extern cvar_t mod_q3shader_default_offsetmapping_scale;
1637 extern cvar_t mod_q3shader_default_offsetmapping_bias;
1638 extern cvar_t mod_q3shader_default_polygonoffset;
1639 extern cvar_t mod_q3shader_default_polygonfactor;
1640 extern cvar_t mod_q3shader_force_addalpha;
1641 extern cvar_t mod_q3shader_force_terrain_alphaflag;
Mod_LoadQ3Shaders(void)1642 void Mod_LoadQ3Shaders(void)
1643 {
1644 	int j;
1645 	int fileindex;
1646 	fssearch_t *search;
1647 	char *f;
1648 	const char *text;
1649 	q3shaderinfo_t shader;
1650 	q3shaderinfo_layer_t *layer;
1651 	int numparameters;
1652 	char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1653 	char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1654 	unsigned long custsurfaceflags[256];
1655 	int numcustsurfaceflags;
1656 	qboolean dpshaderkill;
1657 
1658 	Mod_FreeQ3Shaders();
1659 
1660 	q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1661 	q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem,
1662 		sizeof (q3shader_data_t));
1663 	Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries,
1664 		q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1665 	Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs,
1666 		q3shaders_mem, sizeof (char**), 256);
1667 
1668 	// parse custinfoparms.txt
1669 	numcustsurfaceflags = 0;
1670 	if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1671 	{
1672 		if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1673 			Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1674 		else
1675 		{
1676 			while (COM_ParseToken_QuakeC(&text, false))
1677 				if (!strcasecmp(com_token, "}"))
1678 					break;
1679 			// custom surfaceflags section
1680 			if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1681 				Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1682 			else
1683 			{
1684 				while(COM_ParseToken_QuakeC(&text, false))
1685 				{
1686 					if (!strcasecmp(com_token, "}"))
1687 						break;
1688 					// register surfaceflag
1689 					if (numcustsurfaceflags >= 256)
1690 					{
1691 						Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1692 						break;
1693 					}
1694 					// name
1695 					j = (int)strlen(com_token)+1;
1696 					custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1697 					strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1698 					// value
1699 					if (COM_ParseToken_QuakeC(&text, false))
1700 						custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1701 					else
1702 						custsurfaceflags[numcustsurfaceflags] = 0;
1703 					numcustsurfaceflags++;
1704 				}
1705 			}
1706 		}
1707 		Mem_Free(f);
1708 	}
1709 
1710 	// parse shaders
1711 	search = FS_Search("scripts/*.shader", true, false);
1712 	if (!search)
1713 		return;
1714 	for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1715 	{
1716 		text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1717 		if (!f)
1718 			continue;
1719 		while (COM_ParseToken_QuakeC(&text, false))
1720 		{
1721 			memset (&shader, 0, sizeof(shader));
1722 			shader.name[0] = 0;
1723 			shader.surfaceparms = 0;
1724 			shader.surfaceflags = 0;
1725 			shader.textureflags = 0;
1726 			shader.numlayers = 0;
1727 			shader.lighting = false;
1728 			shader.vertexalpha = false;
1729 			shader.textureblendalpha = false;
1730 			shader.primarylayer = 0;
1731 			shader.backgroundlayer = 0;
1732 			shader.skyboxname[0] = 0;
1733 			shader.deforms[0].deform = Q3DEFORM_NONE;
1734 			shader.dpnortlight = false;
1735 			shader.dpshadow = false;
1736 			shader.dpnoshadow = false;
1737 			shader.dpmeshcollisions = false;
1738 			shader.dpshaderkill = false;
1739 			shader.dpreflectcube[0] = 0;
1740 			shader.reflectmin = 0;
1741 			shader.reflectmax = 1;
1742 			shader.refractfactor = 1;
1743 			Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1744 			shader.reflectfactor = 1;
1745 			Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1746 			shader.r_water_wateralpha = 1;
1747 			shader.r_water_waterscroll[0] = 0;
1748 			shader.r_water_waterscroll[1] = 0;
1749 			shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
1750 			shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
1751 			shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
1752 			shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
1753 			shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
1754 			shader.transparentsort = TRANSPARENTSORT_DISTANCE;
1755 			shader.specularscalemod = 1;
1756 			shader.specularpowermod = 1;
1757 			shader.rtlightambient = 0;
1758 			// WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1759 			// JUST GREP FOR "specularscalemod = 1".
1760 
1761 			strlcpy(shader.name, com_token, sizeof(shader.name));
1762 			if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1763 			{
1764 				Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1765 				break;
1766 			}
1767 			while (COM_ParseToken_QuakeC(&text, false))
1768 			{
1769 				if (!strcasecmp(com_token, "}"))
1770 					break;
1771 				if (!strcasecmp(com_token, "{"))
1772 				{
1773 					static q3shaderinfo_layer_t dummy;
1774 					if (shader.numlayers < Q3SHADER_MAXLAYERS)
1775 					{
1776 						layer = shader.layers + shader.numlayers++;
1777 					}
1778 					else
1779 					{
1780 						// parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1781 						memset(&dummy, 0, sizeof(dummy));
1782 						layer = &dummy;
1783 					}
1784 					layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1785 					layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1786 					layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1787 					layer->blendfunc[0] = GL_ONE;
1788 					layer->blendfunc[1] = GL_ZERO;
1789 					while (COM_ParseToken_QuakeC(&text, false))
1790 					{
1791 						if (!strcasecmp(com_token, "}"))
1792 							break;
1793 						if (!strcasecmp(com_token, "\n"))
1794 							continue;
1795 						numparameters = 0;
1796 						for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1797 						{
1798 							if (j < TEXTURE_MAXFRAMES + 4)
1799 							{
1800 								// remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1801 								if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1802 									dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1803 								else
1804 									strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1805 								numparameters = j + 1;
1806 							}
1807 							if (!COM_ParseToken_QuakeC(&text, true))
1808 								break;
1809 						}
1810 						//for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1811 						//	parameter[j][0] = 0;
1812 						if (developer_insane.integer)
1813 						{
1814 							Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1815 							for (j = 0;j < numparameters;j++)
1816 								Con_DPrintf(" %s", parameter[j]);
1817 							Con_DPrint("\n");
1818 						}
1819 						if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1820 						{
1821 							if (numparameters == 2)
1822 							{
1823 								if (!strcasecmp(parameter[1], "add"))
1824 								{
1825 									layer->blendfunc[0] = GL_ONE;
1826 									layer->blendfunc[1] = GL_ONE;
1827 								}
1828 								else if (!strcasecmp(parameter[1], "addalpha"))
1829 								{
1830 									layer->blendfunc[0] = GL_SRC_ALPHA;
1831 									layer->blendfunc[1] = GL_ONE;
1832 								}
1833 								else if (!strcasecmp(parameter[1], "filter"))
1834 								{
1835 									layer->blendfunc[0] = GL_DST_COLOR;
1836 									layer->blendfunc[1] = GL_ZERO;
1837 								}
1838 								else if (!strcasecmp(parameter[1], "blend"))
1839 								{
1840 									layer->blendfunc[0] = GL_SRC_ALPHA;
1841 									layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1842 								}
1843 							}
1844 							else if (numparameters == 3)
1845 							{
1846 								int k;
1847 								for (k = 0;k < 2;k++)
1848 								{
1849 									if (!strcasecmp(parameter[k+1], "GL_ONE"))
1850 										layer->blendfunc[k] = GL_ONE;
1851 									else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1852 										layer->blendfunc[k] = GL_ZERO;
1853 									else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1854 										layer->blendfunc[k] = GL_SRC_COLOR;
1855 									else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1856 										layer->blendfunc[k] = GL_SRC_ALPHA;
1857 									else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1858 										layer->blendfunc[k] = GL_DST_COLOR;
1859 									else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1860 										layer->blendfunc[k] = GL_DST_ALPHA;
1861 									else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1862 										layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1863 									else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1864 										layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1865 									else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1866 										layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1867 									else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1868 										layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1869 									else
1870 										layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1871 								}
1872 							}
1873 						}
1874 						if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1875 							layer->alphatest = true;
1876 						if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1877 						{
1878 							if (!strcasecmp(parameter[0], "clampmap"))
1879 								layer->clampmap = true;
1880 							layer->numframes = 1;
1881 							layer->framerate = 1;
1882 							layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1883 								&q3shader_data->char_ptrs);
1884 							layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1885 							if (!strcasecmp(parameter[1], "$lightmap"))
1886 								shader.lighting = true;
1887 						}
1888 						else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1889 						{
1890 							int i;
1891 							layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1892 							layer->framerate = atof(parameter[1]);
1893 							layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1894 							for (i = 0;i < layer->numframes;i++)
1895 								layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1896 						}
1897 						else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1898 						{
1899 							int i;
1900 							for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1901 								layer->rgbgen.parms[i] = atof(parameter[i+2]);
1902 							     if (!strcasecmp(parameter[1], "identity"))         layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1903 							else if (!strcasecmp(parameter[1], "const"))            layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1904 							else if (!strcasecmp(parameter[1], "entity"))           layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1905 							else if (!strcasecmp(parameter[1], "exactvertex"))      layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1906 							else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1907 							else if (!strcasecmp(parameter[1], "lightingdiffuse"))  layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1908 							else if (!strcasecmp(parameter[1], "oneminusentity"))   layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1909 							else if (!strcasecmp(parameter[1], "oneminusvertex"))   layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1910 							else if (!strcasecmp(parameter[1], "vertex"))           layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1911 							else if (!strcasecmp(parameter[1], "wave"))
1912 							{
1913 								layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1914 								layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1915 								for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1916 									layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1917 							}
1918 							else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1919 						}
1920 						else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1921 						{
1922 							int i;
1923 							for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1924 								layer->alphagen.parms[i] = atof(parameter[i+2]);
1925 							     if (!strcasecmp(parameter[1], "identity"))         layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1926 							else if (!strcasecmp(parameter[1], "const"))            layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1927 							else if (!strcasecmp(parameter[1], "entity"))           layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1928 							else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1929 							else if (!strcasecmp(parameter[1], "oneminusentity"))   layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1930 							else if (!strcasecmp(parameter[1], "oneminusvertex"))   layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1931 							else if (!strcasecmp(parameter[1], "portal"))           layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1932 							else if (!strcasecmp(parameter[1], "vertex"))           layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1933 							else if (!strcasecmp(parameter[1], "wave"))
1934 							{
1935 								layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1936 								layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1937 								for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1938 									layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1939 							}
1940 							else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1941 						}
1942 						else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1943 						{
1944 							int i;
1945 							// observed values: tcgen environment
1946 							// no other values have been observed in real shaders
1947 							for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1948 								layer->tcgen.parms[i] = atof(parameter[i+2]);
1949 							     if (!strcasecmp(parameter[1], "base"))        layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1950 							else if (!strcasecmp(parameter[1], "texture"))     layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1951 							else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1952 							else if (!strcasecmp(parameter[1], "lightmap"))    layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1953 							else if (!strcasecmp(parameter[1], "vector"))      layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1954 							else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1955 						}
1956 						else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1957 						{
1958 							int i, tcmodindex;
1959 							// observed values:
1960 							// tcmod rotate #
1961 							// tcmod scale # #
1962 							// tcmod scroll # #
1963 							// tcmod stretch sin # # # #
1964 							// tcmod stretch triangle # # # #
1965 							// tcmod transform # # # # # #
1966 							// tcmod turb # # # #
1967 							// tcmod turb sin # # # #  (this is bogus)
1968 							// no other values have been observed in real shaders
1969 							for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1970 								if (!layer->tcmods[tcmodindex].tcmod)
1971 									break;
1972 							if (tcmodindex < Q3MAXTCMODS)
1973 							{
1974 								for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1975 									layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1976 									 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1977 								else if (!strcasecmp(parameter[1], "rotate"))          layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1978 								else if (!strcasecmp(parameter[1], "scale"))           layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1979 								else if (!strcasecmp(parameter[1], "scroll"))          layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1980 								else if (!strcasecmp(parameter[1], "page"))            layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1981 								else if (!strcasecmp(parameter[1], "stretch"))
1982 								{
1983 									layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1984 									layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1985 									for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1986 										layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1987 								}
1988 								else if (!strcasecmp(parameter[1], "transform"))       layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1989 								else if (!strcasecmp(parameter[1], "turb"))            layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1990 								else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1991 							}
1992 							else
1993 								Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1994 						}
1995 						// break out a level if it was a closing brace (not using the character here to not confuse vim)
1996 						if (!strcasecmp(com_token, "}"))
1997 							break;
1998 					}
1999 					if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2000 						shader.lighting = true;
2001 					if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
2002 					{
2003 						if (layer == shader.layers + 0)
2004 						{
2005 							// vertex controlled transparency
2006 							shader.vertexalpha = true;
2007 						}
2008 						else
2009 						{
2010 							// multilayer terrain shader or similar
2011 							shader.textureblendalpha = true;
2012 							if (mod_q3shader_force_terrain_alphaflag.integer)
2013 								shader.layers[0].texflags |= TEXF_ALPHA;
2014 						}
2015 					}
2016 
2017 					if(mod_q3shader_force_addalpha.integer)
2018 					{
2019 						// for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
2020 						// this cvar brings back this behaviour
2021 						if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
2022 							layer->blendfunc[0] = GL_SRC_ALPHA;
2023 					}
2024 
2025 					layer->texflags = 0;
2026 					if (layer->alphatest)
2027 						layer->texflags |= TEXF_ALPHA;
2028 					switch(layer->blendfunc[0])
2029 					{
2030 						case GL_SRC_ALPHA:
2031 						case GL_ONE_MINUS_SRC_ALPHA:
2032 							layer->texflags |= TEXF_ALPHA;
2033 							break;
2034 					}
2035 					switch(layer->blendfunc[1])
2036 					{
2037 						case GL_SRC_ALPHA:
2038 						case GL_ONE_MINUS_SRC_ALPHA:
2039 							layer->texflags |= TEXF_ALPHA;
2040 							break;
2041 					}
2042 					if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
2043 						layer->texflags |= TEXF_MIPMAP;
2044 					if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
2045 						layer->texflags |= TEXF_PICMIP | TEXF_COMPRESS;
2046 					if (layer->clampmap)
2047 						layer->texflags |= TEXF_CLAMP;
2048 					continue;
2049 				}
2050 				numparameters = 0;
2051 				for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
2052 				{
2053 					if (j < TEXTURE_MAXFRAMES + 4)
2054 					{
2055 						// remap dp_water to dpwater, dp_reflect to dpreflect, etc.
2056 						if(j == 0 && !strncasecmp(com_token, "dp_", 3))
2057 							dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
2058 						else
2059 							strlcpy(parameter[j], com_token, sizeof(parameter[j]));
2060 						numparameters = j + 1;
2061 					}
2062 					if (!COM_ParseToken_QuakeC(&text, true))
2063 						break;
2064 				}
2065 				//for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
2066 				//	parameter[j][0] = 0;
2067 				if (fileindex == 0 && !strcasecmp(com_token, "}"))
2068 					break;
2069 				if (developer_insane.integer)
2070 				{
2071 					Con_DPrintf("%s: ", shader.name);
2072 					for (j = 0;j < numparameters;j++)
2073 						Con_DPrintf(" %s", parameter[j]);
2074 					Con_DPrint("\n");
2075 				}
2076 				if (numparameters < 1)
2077 					continue;
2078 				if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
2079 				{
2080 					if (!strcasecmp(parameter[1], "alphashadow"))
2081 						shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
2082 					else if (!strcasecmp(parameter[1], "areaportal"))
2083 						shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
2084 					else if (!strcasecmp(parameter[1], "botclip"))
2085 						shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP;
2086 					else if (!strcasecmp(parameter[1], "clusterportal"))
2087 						shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
2088 					else if (!strcasecmp(parameter[1], "detail"))
2089 						shader.surfaceparms |= Q3SURFACEPARM_DETAIL;
2090 					else if (!strcasecmp(parameter[1], "donotenter"))
2091 						shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER;
2092 					else if (!strcasecmp(parameter[1], "dust"))
2093 						shader.surfaceparms |= Q3SURFACEPARM_DUST;
2094 					else if (!strcasecmp(parameter[1], "hint"))
2095 						shader.surfaceparms |= Q3SURFACEPARM_HINT;
2096 					else if (!strcasecmp(parameter[1], "fog"))
2097 						shader.surfaceparms |= Q3SURFACEPARM_FOG;
2098 					else if (!strcasecmp(parameter[1], "lava"))
2099 						shader.surfaceparms |= Q3SURFACEPARM_LAVA;
2100 					else if (!strcasecmp(parameter[1], "lightfilter"))
2101 						shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
2102 					else if (!strcasecmp(parameter[1], "lightgrid"))
2103 						shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
2104 					else if (!strcasecmp(parameter[1], "metalsteps"))
2105 						shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS;
2106 					else if (!strcasecmp(parameter[1], "nodamage"))
2107 						shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE;
2108 					else if (!strcasecmp(parameter[1], "nodlight"))
2109 						shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT;
2110 					else if (!strcasecmp(parameter[1], "nodraw"))
2111 						shader.surfaceparms |= Q3SURFACEPARM_NODRAW;
2112 					else if (!strcasecmp(parameter[1], "nodrop"))
2113 						shader.surfaceparms |= Q3SURFACEPARM_NODROP;
2114 					else if (!strcasecmp(parameter[1], "noimpact"))
2115 						shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT;
2116 					else if (!strcasecmp(parameter[1], "nolightmap"))
2117 						shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
2118 					else if (!strcasecmp(parameter[1], "nomarks"))
2119 						shader.surfaceparms |= Q3SURFACEPARM_NOMARKS;
2120 					else if (!strcasecmp(parameter[1], "nomipmaps"))
2121 						shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2122 					else if (!strcasecmp(parameter[1], "nonsolid"))
2123 						shader.surfaceparms |= Q3SURFACEPARM_NONSOLID;
2124 					else if (!strcasecmp(parameter[1], "origin"))
2125 						shader.surfaceparms |= Q3SURFACEPARM_ORIGIN;
2126 					else if (!strcasecmp(parameter[1], "playerclip"))
2127 						shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
2128 					else if (!strcasecmp(parameter[1], "sky"))
2129 						shader.surfaceparms |= Q3SURFACEPARM_SKY;
2130 					else if (!strcasecmp(parameter[1], "slick"))
2131 						shader.surfaceparms |= Q3SURFACEPARM_SLICK;
2132 					else if (!strcasecmp(parameter[1], "slime"))
2133 						shader.surfaceparms |= Q3SURFACEPARM_SLIME;
2134 					else if (!strcasecmp(parameter[1], "structural"))
2135 						shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
2136 					else if (!strcasecmp(parameter[1], "trans"))
2137 						shader.surfaceparms |= Q3SURFACEPARM_TRANS;
2138 					else if (!strcasecmp(parameter[1], "water"))
2139 						shader.surfaceparms |= Q3SURFACEPARM_WATER;
2140 					else if (!strcasecmp(parameter[1], "pointlight"))
2141 						shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
2142 					else if (!strcasecmp(parameter[1], "antiportal"))
2143 						shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
2144 					else if (!strcasecmp(parameter[1], "skip"))
2145 						; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
2146 					else
2147 					{
2148 						// try custom surfaceparms
2149 						for (j = 0; j < numcustsurfaceflags; j++)
2150 						{
2151 							if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
2152 							{
2153 								shader.surfaceflags |= custsurfaceflags[j];
2154 								break;
2155 							}
2156 						}
2157 						// failed all
2158 						if (j == numcustsurfaceflags)
2159 							Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
2160 					}
2161 				}
2162 				else if (!strcasecmp(parameter[0], "dpshadow"))
2163 					shader.dpshadow = true;
2164 				else if (!strcasecmp(parameter[0], "dpnoshadow"))
2165 					shader.dpnoshadow = true;
2166 				else if (!strcasecmp(parameter[0], "dpnortlight"))
2167 					shader.dpnortlight = true;
2168 				else if (!strcasecmp(parameter[0], "dpreflectcube"))
2169 					strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
2170 				else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
2171 					shader.dpmeshcollisions = true;
2172 				// this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
2173 				else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
2174 				{
2175 					if (Cvar_VariableValue(parameter[1]) == 0.0f)
2176 						shader.dpshaderkill = dpshaderkill;
2177 				}
2178 				// this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
2179 				else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
2180 				{
2181 					const char *op = NULL;
2182 					if (numparameters >= 3)
2183 						op = parameter[2];
2184 					if(!op)
2185 					{
2186 						if (Cvar_VariableValue(parameter[1]) != 0.0f)
2187 							shader.dpshaderkill = dpshaderkill;
2188 					}
2189 					else if (numparameters >= 4 && !strcmp(op, "=="))
2190 					{
2191 						if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
2192 							shader.dpshaderkill = dpshaderkill;
2193 					}
2194 					else if (numparameters >= 4 && !strcmp(op, "!="))
2195 					{
2196 						if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
2197 							shader.dpshaderkill = dpshaderkill;
2198 					}
2199 					else if (numparameters >= 4 && !strcmp(op, ">"))
2200 					{
2201 						if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
2202 							shader.dpshaderkill = dpshaderkill;
2203 					}
2204 					else if (numparameters >= 4 && !strcmp(op, "<"))
2205 					{
2206 						if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
2207 							shader.dpshaderkill = dpshaderkill;
2208 					}
2209 					else if (numparameters >= 4 && !strcmp(op, ">="))
2210 					{
2211 						if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
2212 							shader.dpshaderkill = dpshaderkill;
2213 					}
2214 					else if (numparameters >= 4 && !strcmp(op, "<="))
2215 					{
2216 						if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
2217 							shader.dpshaderkill = dpshaderkill;
2218 					}
2219 					else
2220 					{
2221 						Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2222 					}
2223 				}
2224 				else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2225 				{
2226 					// some q3 skies don't have the sky parm set
2227 					shader.surfaceparms |= Q3SURFACEPARM_SKY;
2228 					strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2229 				}
2230 				else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2231 				{
2232 					// some q3 skies don't have the sky parm set
2233 					shader.surfaceparms |= Q3SURFACEPARM_SKY;
2234 					if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2235 						strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2236 				}
2237 				else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2238 				{
2239 					if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2240 						shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED;
2241 				}
2242 				else if (!strcasecmp(parameter[0], "nomipmaps"))
2243 					shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2244 				else if (!strcasecmp(parameter[0], "nopicmip"))
2245 					shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
2246 				else if (!strcasecmp(parameter[0], "polygonoffset"))
2247 					shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2248 				else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2249 				{
2250 					shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2251 					if(numparameters >= 2)
2252 					{
2253 						shader.biaspolygonfactor = atof(parameter[1]);
2254 						if(numparameters >= 3)
2255 							shader.biaspolygonoffset = atof(parameter[2]);
2256 						else
2257 							shader.biaspolygonoffset = 0;
2258 					}
2259 				}
2260 				else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2261 				{
2262 					shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
2263 					if (!strcasecmp(parameter[1], "sky"))
2264 						shader.transparentsort = TRANSPARENTSORT_SKY;
2265 					else if (!strcasecmp(parameter[1], "distance"))
2266 						shader.transparentsort = TRANSPARENTSORT_DISTANCE;
2267 					else if (!strcasecmp(parameter[1], "hud"))
2268 						shader.transparentsort = TRANSPARENTSORT_HUD;
2269 					else
2270 						Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2271 				}
2272 				else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2273 				{
2274 					shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
2275 					shader.refractfactor = atof(parameter[1]);
2276 					Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2277 				}
2278 				else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2279 				{
2280 					shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
2281 					shader.reflectfactor = atof(parameter[1]);
2282 					Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2283 				}
2284 				else if (!strcasecmp(parameter[0], "dpcamera"))
2285 				{
2286 					shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
2287 				}
2288 				else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2289 				{
2290 					shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
2291 					shader.reflectmin = atof(parameter[1]);
2292 					shader.reflectmax = atof(parameter[2]);
2293 					shader.refractfactor = atof(parameter[3]);
2294 					shader.reflectfactor = atof(parameter[4]);
2295 					Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2296 					Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2297 					shader.r_water_wateralpha = atof(parameter[11]);
2298 				}
2299 				else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2300 				{
2301 					shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2302 					shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2303 				}
2304 				else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2305 				{
2306 					shader.specularscalemod = atof(parameter[1]);
2307 				}
2308 				else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2309 				{
2310 					shader.specularpowermod = atof(parameter[1]);
2311 				}
2312 				else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2313 				{
2314 					shader.rtlightambient = atof(parameter[1]);
2315 				}
2316 				else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2317 				{
2318 					if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2319 						shader.offsetmapping = OFFSETMAPPING_OFF;
2320 					else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2321 						shader.offsetmapping = OFFSETMAPPING_DEFAULT;
2322 					else if (!strcasecmp(parameter[1], "linear"))
2323 						shader.offsetmapping = OFFSETMAPPING_LINEAR;
2324 					else if (!strcasecmp(parameter[1], "relief"))
2325 						shader.offsetmapping = OFFSETMAPPING_RELIEF;
2326 					if (numparameters >= 3)
2327 						shader.offsetscale = atof(parameter[2]);
2328 					if (numparameters >= 5)
2329 					{
2330 						if(!strcasecmp(parameter[3], "bias"))
2331 							shader.offsetbias = atof(parameter[4]);
2332 						else if(!strcasecmp(parameter[3], "match"))
2333 							shader.offsetbias = 1.0f - atof(parameter[4]);
2334 						else if(!strcasecmp(parameter[3], "match8"))
2335 							shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2336 						else if(!strcasecmp(parameter[3], "match16"))
2337 							shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2338 					}
2339 				}
2340 				else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2341 				{
2342 					int i, deformindex;
2343 					for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2344 						if (!shader.deforms[deformindex].deform)
2345 							break;
2346 					if (deformindex < Q3MAXDEFORMS)
2347 					{
2348 						for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2349 							shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2350 						     if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2351 						else if (!strcasecmp(parameter[1], "autosprite"      )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2352 						else if (!strcasecmp(parameter[1], "autosprite2"     )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2353 						else if (!strcasecmp(parameter[1], "text0"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2354 						else if (!strcasecmp(parameter[1], "text1"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2355 						else if (!strcasecmp(parameter[1], "text2"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2356 						else if (!strcasecmp(parameter[1], "text3"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2357 						else if (!strcasecmp(parameter[1], "text4"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2358 						else if (!strcasecmp(parameter[1], "text5"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2359 						else if (!strcasecmp(parameter[1], "text6"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2360 						else if (!strcasecmp(parameter[1], "text7"           )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2361 						else if (!strcasecmp(parameter[1], "bulge"           )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2362 						else if (!strcasecmp(parameter[1], "normal"          )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2363 						else if (!strcasecmp(parameter[1], "wave"            ))
2364 						{
2365 							shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2366 							shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2367 							for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2368 								shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2369 						}
2370 						else if (!strcasecmp(parameter[1], "move"            ))
2371 						{
2372 							shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2373 							shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2374 							for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2375 								shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2376 						}
2377 					}
2378 				}
2379 			}
2380 			// hide this shader if a cvar said it should be killed
2381 			if (shader.dpshaderkill)
2382 				shader.numlayers = 0;
2383 			// pick the primary layer to render with
2384 			if (shader.numlayers)
2385 			{
2386 				shader.backgroundlayer = -1;
2387 				shader.primarylayer = 0;
2388 				// if lightmap comes first this is definitely an ordinary texture
2389 				// if the first two layers have the correct blendfuncs and use vertex alpha, it is a blended terrain shader
2390 				if ((shader.layers[shader.primarylayer].texturename != NULL)
2391 				  && !strcasecmp(shader.layers[shader.primarylayer].texturename[0], "$lightmap"))
2392 				{
2393 					shader.backgroundlayer = -1;
2394 					shader.primarylayer = 1;
2395 				}
2396 				else if (shader.numlayers >= 2
2397 				&&   shader.layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2398 				&&  (shader.layers[0].blendfunc[0] == GL_ONE       && shader.layers[0].blendfunc[1] == GL_ZERO                && !shader.layers[0].alphatest)
2399 				&& ((shader.layers[1].blendfunc[0] == GL_SRC_ALPHA && shader.layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2400 				||  (shader.layers[1].blendfunc[0] == GL_ONE       && shader.layers[1].blendfunc[1] == GL_ZERO                &&  shader.layers[1].alphatest)))
2401 				{
2402 					// terrain blending or other effects
2403 					shader.backgroundlayer = 0;
2404 					shader.primarylayer = 1;
2405 				}
2406 			}
2407 			// fix up multiple reflection types
2408 			if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
2409 				shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
2410 
2411 			Q3Shader_AddToHash (&shader);
2412 		}
2413 		Mem_Free(f);
2414 	}
2415 	FS_FreeSearch(search);
2416 	// free custinfoparm values
2417 	for (j = 0; j < numcustsurfaceflags; j++)
2418 		Mem_Free(custsurfaceparmnames[j]);
2419 }
2420 
Mod_LookupQ3Shader(const char * name)2421 q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
2422 {
2423 	unsigned short hash;
2424 	q3shader_hash_entry_t* entry;
2425 	if (!q3shaders_mem)
2426 		Mod_LoadQ3Shaders();
2427 	hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2428 	entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2429 	while (entry != NULL)
2430 	{
2431 		if (strcasecmp (entry->shader.name, name) == 0)
2432 			return &entry->shader;
2433 		entry = entry->chain;
2434 	}
2435 	return NULL;
2436 }
2437 
Mod_LoadTextureFromQ3Shader(texture_t * texture,const char * name,qboolean warnmissing,qboolean fallback,int defaulttexflags)2438 qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
2439 {
2440 	int j;
2441 	int texflagsmask, texflagsor;
2442 	qboolean success = true;
2443 	q3shaderinfo_t *shader;
2444 	if (!name)
2445 		name = "";
2446 	strlcpy(texture->name, name, sizeof(texture->name));
2447 	texture->basealpha = 1.0f;
2448 	shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2449 
2450 	texflagsmask = ~0;
2451 	if(!(defaulttexflags & TEXF_PICMIP))
2452 		texflagsmask &= ~TEXF_PICMIP;
2453 	if(!(defaulttexflags & TEXF_COMPRESS))
2454 		texflagsmask &= ~TEXF_COMPRESS;
2455 	texflagsor = 0;
2456 	if(defaulttexflags & TEXF_ISWORLD)
2457 		texflagsor |= TEXF_ISWORLD;
2458 	if(defaulttexflags & TEXF_ISSPRITE)
2459 		texflagsor |= TEXF_ISSPRITE;
2460 	// unless later loaded from the shader
2461 	texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2462 	texture->offsetscale = 1;
2463 	texture->offsetbias = 0;
2464 	texture->specularscalemod = 1;
2465 	texture->specularpowermod = 1;
2466 	texture->rtlightambient = 0;
2467 	texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2468 	// WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2469 	// JUST GREP FOR "specularscalemod = 1".
2470 
2471 	if (shader)
2472 	{
2473 		if (developer_loading.integer)
2474 			Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name);
2475 
2476 		// allow disabling of picmip or compression by defaulttexflags
2477 		texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor;
2478 
2479 		if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2480 		{
2481 			texture->basematerialflags = MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
2482 			if (shader->skyboxname[0])
2483 			{
2484 				// quake3 seems to append a _ to the skybox name, so this must do so as well
2485 				dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2486 			}
2487 		}
2488 		else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2489 			texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2490 		else
2491 			texture->basematerialflags = MATERIALFLAG_WALL;
2492 
2493 		if (shader->layers[0].alphatest)
2494 			texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
2495 		if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2496 			texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2497 		if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET)
2498 		{
2499 			texture->biaspolygonoffset += shader->biaspolygonoffset;
2500 			texture->biaspolygonfactor += shader->biaspolygonfactor;
2501 		}
2502 		if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION)
2503 			texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2504 		if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION)
2505 			texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2506 		if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
2507 			texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2508 		if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2509 			texture->basematerialflags |= MATERIALFLAG_CAMERA;
2510 		texture->customblendfunc[0] = GL_ONE;
2511 		texture->customblendfunc[1] = GL_ZERO;
2512 		texture->transparentsort = shader->transparentsort;
2513 		if (shader->numlayers > 0)
2514 		{
2515 			texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2516 			texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2517 /*
2518 Q3 shader blendfuncs actually used in the game (* = supported by DP)
2519 * additive               GL_ONE GL_ONE
2520 additive weird         GL_ONE GL_SRC_ALPHA
2521 additive weird 2       GL_ONE GL_ONE_MINUS_SRC_ALPHA
2522 * alpha                  GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2523 alpha inverse          GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2524 brighten               GL_DST_COLOR GL_ONE
2525 brighten               GL_ONE GL_SRC_COLOR
2526 brighten weird         GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2527 brighten weird 2       GL_DST_COLOR GL_SRC_ALPHA
2528 * modulate               GL_DST_COLOR GL_ZERO
2529 * modulate               GL_ZERO GL_SRC_COLOR
2530 modulate inverse       GL_ZERO GL_ONE_MINUS_SRC_COLOR
2531 modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2532 modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2533 * modulate x2            GL_DST_COLOR GL_SRC_COLOR
2534 * no blend               GL_ONE GL_ZERO
2535 nothing                GL_ZERO GL_ONE
2536 */
2537 			// if not opaque, figure out what blendfunc to use
2538 			if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2539 			{
2540 				if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2541 					texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2542 				else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2543 					texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2544 				else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2545 					texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2546 				else
2547 					texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2548 			}
2549 		}
2550 		if (!shader->lighting)
2551 			texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2552 		if (shader->primarylayer >= 0)
2553 		{
2554 			q3shaderinfo_layer_t* primarylayer = shader->layers + shader->primarylayer;
2555 			// copy over many primarylayer parameters
2556 			texture->rgbgen = primarylayer->rgbgen;
2557 			texture->alphagen = primarylayer->alphagen;
2558 			texture->tcgen = primarylayer->tcgen;
2559 			memcpy(texture->tcmods, primarylayer->tcmods, sizeof(texture->tcmods));
2560 			// load the textures
2561 			texture->numskinframes = primarylayer->numframes;
2562 			texture->skinframerate = primarylayer->framerate;
2563 			for (j = 0;j < primarylayer->numframes;j++)
2564 			{
2565 				if(cls.state == ca_dedicated)
2566 				{
2567 					texture->skinframes[j] = NULL;
2568 				}
2569 				else if (!(texture->skinframes[j] = R_SkinFrame_LoadExternal(primarylayer->texturename[j], (primarylayer->texflags & texflagsmask) | texflagsor, false)))
2570 				{
2571 					Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for shader ^2\"%s\"\n", loadmodel->name, primarylayer->texturename[j], j, texture->name);
2572 					texture->skinframes[j] = R_SkinFrame_LoadMissing();
2573 				}
2574 			}
2575 		}
2576 		if (shader->backgroundlayer >= 0)
2577 		{
2578 			q3shaderinfo_layer_t* backgroundlayer = shader->layers + shader->backgroundlayer;
2579 			// copy over one secondarylayer parameter
2580 			memcpy(texture->backgroundtcmods, backgroundlayer->tcmods, sizeof(texture->backgroundtcmods));
2581 			// load the textures
2582 			texture->backgroundnumskinframes = backgroundlayer->numframes;
2583 			texture->backgroundskinframerate = backgroundlayer->framerate;
2584 			for (j = 0;j < backgroundlayer->numframes;j++)
2585 			{
2586 				if(cls.state == ca_dedicated)
2587 				{
2588 					texture->skinframes[j] = NULL;
2589 				}
2590 				else if (!(texture->backgroundskinframes[j] = R_SkinFrame_LoadExternal(backgroundlayer->texturename[j], (backgroundlayer->texflags & texflagsmask) | texflagsor, false)))
2591 				{
2592 					Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (background frame %i) for shader ^2\"%s\"\n", loadmodel->name, backgroundlayer->texturename[j], j, texture->name);
2593 					texture->backgroundskinframes[j] = R_SkinFrame_LoadMissing();
2594 				}
2595 			}
2596 		}
2597 		if (shader->dpshadow)
2598 			texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2599 		if (shader->dpnoshadow)
2600 			texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2601 		if (shader->dpnortlight)
2602 			texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2603 		if (shader->vertexalpha)
2604 			texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2605 		memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2606 		texture->reflectmin = shader->reflectmin;
2607 		texture->reflectmax = shader->reflectmax;
2608 		texture->refractfactor = shader->refractfactor;
2609 		Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2610 		texture->reflectfactor = shader->reflectfactor;
2611 		Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2612 		texture->r_water_wateralpha = shader->r_water_wateralpha;
2613 		Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2614 		texture->offsetmapping = shader->offsetmapping;
2615 		texture->offsetscale = shader->offsetscale;
2616 		texture->offsetbias = shader->offsetbias;
2617 		texture->specularscalemod = shader->specularscalemod;
2618 		texture->specularpowermod = shader->specularpowermod;
2619 		texture->rtlightambient = shader->rtlightambient;
2620 		if (shader->dpreflectcube[0])
2621 			texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2622 
2623 		// set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2624 		texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2625 		if (shader->surfaceparms & Q3SURFACEPARM_LAVA         ) texture->supercontents  = SUPERCONTENTS_LAVA         ;
2626 		if (shader->surfaceparms & Q3SURFACEPARM_SLIME        ) texture->supercontents  = SUPERCONTENTS_SLIME        ;
2627 		if (shader->surfaceparms & Q3SURFACEPARM_WATER        ) texture->supercontents  = SUPERCONTENTS_WATER        ;
2628 		if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID     ) texture->supercontents  = 0                          ;
2629 		if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP   ) texture->supercontents  = SUPERCONTENTS_PLAYERCLIP   ;
2630 		if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP      ) texture->supercontents  = SUPERCONTENTS_MONSTERCLIP  ;
2631 		if (shader->surfaceparms & Q3SURFACEPARM_SKY          ) texture->supercontents  = SUPERCONTENTS_SKY          ;
2632 
2633 	//	if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW  ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW  ;
2634 	//	if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL   ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL   ;
2635 	//	if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2636 	//	if (shader->surfaceparms & Q3SURFACEPARM_DETAIL       ) texture->supercontents |= SUPERCONTENTS_DETAIL       ;
2637 		if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER   ) texture->supercontents |= SUPERCONTENTS_DONOTENTER   ;
2638 	//	if (shader->surfaceparms & Q3SURFACEPARM_FOG          ) texture->supercontents |= SUPERCONTENTS_FOG          ;
2639 		if (shader->surfaceparms & Q3SURFACEPARM_LAVA         ) texture->supercontents |= SUPERCONTENTS_LAVA         ;
2640 	//	if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER  ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER  ;
2641 	//	if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS   ) texture->supercontents |= SUPERCONTENTS_METALSTEPS   ;
2642 	//	if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE     ) texture->supercontents |= SUPERCONTENTS_NODAMAGE     ;
2643 	//	if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT     ) texture->supercontents |= SUPERCONTENTS_NODLIGHT     ;
2644 	//	if (shader->surfaceparms & Q3SURFACEPARM_NODRAW       ) texture->supercontents |= SUPERCONTENTS_NODRAW       ;
2645 		if (shader->surfaceparms & Q3SURFACEPARM_NODROP       ) texture->supercontents |= SUPERCONTENTS_NODROP       ;
2646 	//	if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT     ) texture->supercontents |= SUPERCONTENTS_NOIMPACT     ;
2647 	//	if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP   ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP   ;
2648 	//	if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS      ) texture->supercontents |= SUPERCONTENTS_NOMARKS      ;
2649 	//	if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS    ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS    ;
2650 		if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID     ) texture->supercontents &=~SUPERCONTENTS_SOLID        ;
2651 	//	if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN       ) texture->supercontents |= SUPERCONTENTS_ORIGIN       ;
2652 		if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP   ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP   ;
2653 		if (shader->surfaceparms & Q3SURFACEPARM_SKY          ) texture->supercontents |= SUPERCONTENTS_SKY          ;
2654 	//	if (shader->surfaceparms & Q3SURFACEPARM_SLICK        ) texture->supercontents |= SUPERCONTENTS_SLICK        ;
2655 		if (shader->surfaceparms & Q3SURFACEPARM_SLIME        ) texture->supercontents |= SUPERCONTENTS_SLIME        ;
2656 	//	if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL   ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL   ;
2657 	//	if (shader->surfaceparms & Q3SURFACEPARM_TRANS        ) texture->supercontents |= SUPERCONTENTS_TRANS        ;
2658 		if (shader->surfaceparms & Q3SURFACEPARM_WATER        ) texture->supercontents |= SUPERCONTENTS_WATER        ;
2659 	//	if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT   ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT   ;
2660 	//	if (shader->surfaceparms & Q3SURFACEPARM_HINT         ) texture->supercontents |= SUPERCONTENTS_HINT         ;
2661 	//	if (shader->surfaceparms & Q3SURFACEPARM_DUST         ) texture->supercontents |= SUPERCONTENTS_DUST         ;
2662 		if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP      ) texture->supercontents |= SUPERCONTENTS_BOTCLIP      | SUPERCONTENTS_MONSTERCLIP;
2663 	//	if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID    ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID    ;
2664 	//	if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL   ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL   ;
2665 
2666 		texture->surfaceflags = shader->surfaceflags;
2667 		if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW  ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW  ;
2668 	//	if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL   ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL   ;
2669 	//	if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2670 	//	if (shader->surfaceparms & Q3SURFACEPARM_DETAIL       ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL       ;
2671 	//	if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER   ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER   ;
2672 	//	if (shader->surfaceparms & Q3SURFACEPARM_FOG          ) texture->surfaceflags |= Q3SURFACEFLAG_FOG          ;
2673 	//	if (shader->surfaceparms & Q3SURFACEPARM_LAVA         ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA         ;
2674 		if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER  ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER  ;
2675 		if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS   ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS   ;
2676 		if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE     ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE     ;
2677 		if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT     ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT     ;
2678 		if (shader->surfaceparms & Q3SURFACEPARM_NODRAW       ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW       ;
2679 	//	if (shader->surfaceparms & Q3SURFACEPARM_NODROP       ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP       ;
2680 		if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT     ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT     ;
2681 		if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP   ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP   ;
2682 		if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS      ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS      ;
2683 	//	if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS    ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS    ;
2684 		if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID     ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID     ;
2685 	//	if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN       ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN       ;
2686 	//	if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP   ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP   ;
2687 		if (shader->surfaceparms & Q3SURFACEPARM_SKY          ) texture->surfaceflags |= Q3SURFACEFLAG_SKY          ;
2688 		if (shader->surfaceparms & Q3SURFACEPARM_SLICK        ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK        ;
2689 	//	if (shader->surfaceparms & Q3SURFACEPARM_SLIME        ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME        ;
2690 	//	if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL   ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL   ;
2691 	//	if (shader->surfaceparms & Q3SURFACEPARM_TRANS        ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS        ;
2692 	//	if (shader->surfaceparms & Q3SURFACEPARM_WATER        ) texture->surfaceflags |= Q3SURFACEFLAG_WATER        ;
2693 		if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT   ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT   ;
2694 		if (shader->surfaceparms & Q3SURFACEPARM_HINT         ) texture->surfaceflags |= Q3SURFACEFLAG_HINT         ;
2695 		if (shader->surfaceparms & Q3SURFACEPARM_DUST         ) texture->surfaceflags |= Q3SURFACEFLAG_DUST         ;
2696 	//	if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP      ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP      ;
2697 	//	if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID    ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID    ;
2698 	//	if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL   ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL   ;
2699 
2700 		if (shader->dpmeshcollisions)
2701 			texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2702 		if (shader->dpshaderkill && developer_extra.integer)
2703 			Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", loadmodel->name, name);
2704 	}
2705 	else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2706 	{
2707 		if (developer_extra.integer)
2708 			Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name);
2709 		texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2710 	}
2711 	else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2712 	{
2713 		if (developer_extra.integer)
2714 			Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name);
2715 		texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2716 		texture->supercontents = SUPERCONTENTS_SOLID;
2717 	}
2718 	else
2719 	{
2720 		if (developer_extra.integer)
2721 			Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name);
2722 		if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2723 		{
2724 			texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2725 			texture->supercontents = SUPERCONTENTS_SOLID;
2726 		}
2727 		else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2728 		{
2729 			texture->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
2730 			texture->supercontents = SUPERCONTENTS_SKY;
2731 		}
2732 		else
2733 		{
2734 			texture->basematerialflags |= MATERIALFLAG_WALL;
2735 			texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2736 		}
2737 		texture->numskinframes = 1;
2738 		if(cls.state == ca_dedicated)
2739 		{
2740 			texture->skinframes[0] = NULL;
2741 			success = false;
2742 		}
2743 		else
2744 		{
2745 			if (fallback)
2746 			{
2747 				if ((texture->skinframes[0] = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false)))
2748 				{
2749 					if(texture->skinframes[0]->hasalpha)
2750 						texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2751 					if (texture->q2contents)
2752 						texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, texture->q2contents);
2753 				}
2754 				else
2755 					success = false;
2756 			}
2757 			else
2758 				success = false;
2759 			if (!success && warnmissing)
2760 				Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", loadmodel->name, texture->name);
2761 		}
2762 	}
2763 	// init the animation variables
2764 	texture->currentframe = texture;
2765 	if (texture->numskinframes < 1)
2766 		texture->numskinframes = 1;
2767 	if (!texture->skinframes[0])
2768 		texture->skinframes[0] = R_SkinFrame_LoadMissing();
2769 	texture->currentskinframe = texture->skinframes[0];
2770 	texture->backgroundcurrentskinframe = texture->backgroundskinframes[0];
2771 	return success;
2772 }
2773 
Mod_LoadSkinFiles(void)2774 skinfile_t *Mod_LoadSkinFiles(void)
2775 {
2776 	int i, words, line, wordsoverflow;
2777 	char *text;
2778 	const char *data;
2779 	skinfile_t *skinfile = NULL, *first = NULL;
2780 	skinfileitem_t *skinfileitem;
2781 	char word[10][MAX_QPATH];
2782 	char vabuf[1024];
2783 
2784 /*
2785 sample file:
2786 U_bodyBox,models/players/Legoman/BikerA2.tga
2787 U_RArm,models/players/Legoman/BikerA1.tga
2788 U_LArm,models/players/Legoman/BikerA1.tga
2789 U_armor,common/nodraw
2790 U_sword,common/nodraw
2791 U_shield,common/nodraw
2792 U_homb,common/nodraw
2793 U_backpack,common/nodraw
2794 U_colcha,common/nodraw
2795 tag_head,
2796 tag_weapon,
2797 tag_torso,
2798 */
2799 	memset(word, 0, sizeof(word));
2800 	for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2801 	{
2802 		// If it's the first file we parse
2803 		if (skinfile == NULL)
2804 		{
2805 			skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2806 			first = skinfile;
2807 		}
2808 		else
2809 		{
2810 			skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2811 			skinfile = skinfile->next;
2812 		}
2813 		skinfile->next = NULL;
2814 
2815 		for(line = 0;;line++)
2816 		{
2817 			// parse line
2818 			if (!COM_ParseToken_QuakeC(&data, true))
2819 				break;
2820 			if (!strcmp(com_token, "\n"))
2821 				continue;
2822 			words = 0;
2823 			wordsoverflow = false;
2824 			do
2825 			{
2826 				if (words < 10)
2827 					strlcpy(word[words++], com_token, sizeof (word[0]));
2828 				else
2829 					wordsoverflow = true;
2830 			}
2831 			while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2832 			if (wordsoverflow)
2833 			{
2834 				Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: line with too many statements, skipping\n", loadmodel->name, i, line);
2835 				continue;
2836 			}
2837 			// words is always >= 1
2838 			if (!strcmp(word[0], "replace"))
2839 			{
2840 				if (words == 3)
2841 				{
2842 					if (developer_loading.integer)
2843 						Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2844 					skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2845 					skinfileitem->next = skinfile->items;
2846 					skinfile->items = skinfileitem;
2847 					strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2848 					strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2849 				}
2850 				else
2851 					Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: wrong number of parameters to command \"%s\", see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line, word[0]);
2852 			}
2853 			else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2854 			{
2855 				// tag name, like "tag_weapon,"
2856 				// not used for anything (not even in Quake3)
2857 			}
2858 			else if (words >= 2 && !strcmp(word[1], ","))
2859 			{
2860 				// mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2861 				if (developer_loading.integer)
2862 					Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2863 				skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2864 				skinfileitem->next = skinfile->items;
2865 				skinfile->items = skinfileitem;
2866 				strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2867 				strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2868 			}
2869 			else
2870 				Con_Printf("Mod_LoadSkinFiles: parsing error in file \"%s_%i.skin\" on line #%i: does not look like tag or mesh specification, or replace command, see documentation in DP_GFX_SKINFILES extension in dpextensions.qc\n", loadmodel->name, i, line);
2871 		}
2872 		Mem_Free(text);
2873 	}
2874 	if (i)
2875 		loadmodel->numskins = i;
2876 	return first;
2877 }
2878 
Mod_FreeSkinFiles(skinfile_t * skinfile)2879 void Mod_FreeSkinFiles(skinfile_t *skinfile)
2880 {
2881 	skinfile_t *next;
2882 	skinfileitem_t *skinfileitem, *nextitem;
2883 	for (;skinfile;skinfile = next)
2884 	{
2885 		next = skinfile->next;
2886 		for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2887 		{
2888 			nextitem = skinfileitem->next;
2889 			Mem_Free(skinfileitem);
2890 		}
2891 		Mem_Free(skinfile);
2892 	}
2893 }
2894 
Mod_CountSkinFiles(skinfile_t * skinfile)2895 int Mod_CountSkinFiles(skinfile_t *skinfile)
2896 {
2897 	int i;
2898 	for (i = 0;skinfile;skinfile = skinfile->next, i++);
2899 	return i;
2900 }
2901 
Mod_SnapVertices(int numcomponents,int numvertices,float * vertices,float snap)2902 void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
2903 {
2904 	int i;
2905 	double isnap = 1.0 / snap;
2906 	for (i = 0;i < numvertices*numcomponents;i++)
2907 		vertices[i] = floor(vertices[i]*isnap)*snap;
2908 }
2909 
Mod_RemoveDegenerateTriangles(int numtriangles,const int * inelement3i,int * outelement3i,const float * vertex3f)2910 int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
2911 {
2912 	int i, outtriangles;
2913 	float edgedir1[3], edgedir2[3], temp[3];
2914 	// a degenerate triangle is one with no width (thickness, surface area)
2915 	// these are characterized by having all 3 points colinear (along a line)
2916 	// or having two points identical
2917 	// the simplest check is to calculate the triangle's area
2918 	for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
2919 	{
2920 		// calculate first edge
2921 		VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
2922 		VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
2923 		CrossProduct(edgedir1, edgedir2, temp);
2924 		if (VectorLength2(temp) < 0.001f)
2925 			continue; // degenerate triangle (no area)
2926 		// valid triangle (has area)
2927 		VectorCopy(inelement3i, outelement3i);
2928 		outelement3i += 3;
2929 		outtriangles++;
2930 	}
2931 	return outtriangles;
2932 }
2933 
Mod_VertexRangeFromElements(int numelements,const int * elements,int * firstvertexpointer,int * lastvertexpointer)2934 void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
2935 {
2936 	int i, e;
2937 	int firstvertex, lastvertex;
2938 	if (numelements > 0 && elements)
2939 	{
2940 		firstvertex = lastvertex = elements[0];
2941 		for (i = 1;i < numelements;i++)
2942 		{
2943 			e = elements[i];
2944 			firstvertex = min(firstvertex, e);
2945 			lastvertex = max(lastvertex, e);
2946 		}
2947 	}
2948 	else
2949 		firstvertex = lastvertex = 0;
2950 	if (firstvertexpointer)
2951 		*firstvertexpointer = firstvertex;
2952 	if (lastvertexpointer)
2953 		*lastvertexpointer = lastvertex;
2954 }
2955 
Mod_MakeSortedSurfaces(dp_model_t * mod)2956 void Mod_MakeSortedSurfaces(dp_model_t *mod)
2957 {
2958 	// make an optimal set of texture-sorted batches to draw...
2959 	int j, t;
2960 	int *firstsurfacefortexture;
2961 	int *numsurfacesfortexture;
2962 	if (!mod->sortedmodelsurfaces)
2963 		mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
2964 	firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
2965 	numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
2966 	memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
2967 	for (j = 0;j < mod->nummodelsurfaces;j++)
2968 	{
2969 		const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2970 		t = (int)(surface->texture - mod->data_textures);
2971 		numsurfacesfortexture[t]++;
2972 	}
2973 	j = 0;
2974 	for (t = 0;t < mod->num_textures;t++)
2975 	{
2976 		firstsurfacefortexture[t] = j;
2977 		j += numsurfacesfortexture[t];
2978 	}
2979 	for (j = 0;j < mod->nummodelsurfaces;j++)
2980 	{
2981 		const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2982 		t = (int)(surface->texture - mod->data_textures);
2983 		mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
2984 	}
2985 	Mem_Free(firstsurfacefortexture);
2986 	Mem_Free(numsurfacesfortexture);
2987 }
2988 
Mod_BuildVBOs(void)2989 void Mod_BuildVBOs(void)
2990 {
2991 	if (!loadmodel->surfmesh.num_vertices)
2992 		return;
2993 
2994 	if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
2995 	{
2996 		int i;
2997 		for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2998 		{
2999 			if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
3000 			{
3001 				Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
3002 				loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3003 			}
3004 		}
3005 	}
3006 
3007 	// build r_vertexmesh_t array
3008 	// (compressed interleaved array for D3D)
3009 	if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
3010 	{
3011 		int vertexindex;
3012 		int numvertices = loadmodel->surfmesh.num_vertices;
3013 		r_vertexmesh_t *vertexmesh;
3014 		loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
3015 		for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
3016 		{
3017 			VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
3018 			VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
3019 			VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
3020 			VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
3021 			if (loadmodel->surfmesh.data_lightmapcolor4f)
3022 				Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f);
3023 			Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
3024 			if (loadmodel->surfmesh.data_texcoordlightmap2f)
3025 				Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
3026 			if (loadmodel->surfmesh.data_skeletalindex4ub)
3027 				Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
3028 			if (loadmodel->surfmesh.data_skeletalweight4ub)
3029 				Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
3030 		}
3031 	}
3032 
3033 	// upload short indices as a buffer
3034 	if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
3035 		loadmodel->surfmesh.data_element3s_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3s, loadmodel->surfmesh.num_triangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
3036 
3037 	// upload int indices as a buffer
3038 	if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
3039 		loadmodel->surfmesh.data_element3i_indexbuffer = R_Mesh_CreateMeshBuffer(loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.num_triangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
3040 
3041 	// only build a vbo if one has not already been created (this is important for brush models which load specially)
3042 	// vertex buffer is several arrays and we put them in the same buffer
3043 	//
3044 	// is this wise?  the texcoordtexture2f array is used with dynamic
3045 	// vertex/svector/tvector/normal when rendering animated models, on the
3046 	// other hand animated models don't use a lot of vertices anyway...
3047 	if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
3048 	{
3049 		int size;
3050 		unsigned char *mem;
3051 		size = 0;
3052 		loadmodel->surfmesh.vbooffset_vertexmesh         = size;if (loadmodel->surfmesh.data_vertexmesh        ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
3053 		loadmodel->surfmesh.vbooffset_vertex3f           = size;if (loadmodel->surfmesh.data_vertex3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3054 		loadmodel->surfmesh.vbooffset_svector3f          = size;if (loadmodel->surfmesh.data_svector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3055 		loadmodel->surfmesh.vbooffset_tvector3f          = size;if (loadmodel->surfmesh.data_tvector3f         ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3056 		loadmodel->surfmesh.vbooffset_normal3f           = size;if (loadmodel->surfmesh.data_normal3f          ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3057 		loadmodel->surfmesh.vbooffset_texcoordtexture2f  = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3058 		loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3059 		loadmodel->surfmesh.vbooffset_lightmapcolor4f    = size;if (loadmodel->surfmesh.data_lightmapcolor4f   ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3060 		loadmodel->surfmesh.vbooffset_skeletalindex4ub   = size;if (loadmodel->surfmesh.data_skeletalindex4ub  ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3061 		loadmodel->surfmesh.vbooffset_skeletalweight4ub  = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3062 		mem = (unsigned char *)Mem_Alloc(tempmempool, size);
3063 		if (loadmodel->surfmesh.data_vertexmesh        ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh        , loadmodel->surfmesh.data_vertexmesh        , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
3064 		if (loadmodel->surfmesh.data_vertex3f          ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f          , loadmodel->surfmesh.data_vertex3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3065 		if (loadmodel->surfmesh.data_svector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f         , loadmodel->surfmesh.data_svector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3066 		if (loadmodel->surfmesh.data_tvector3f         ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f         , loadmodel->surfmesh.data_tvector3f         , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3067 		if (loadmodel->surfmesh.data_normal3f          ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f          , loadmodel->surfmesh.data_normal3f          , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3068 		if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3069 		if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3070 		if (loadmodel->surfmesh.data_lightmapcolor4f   ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f   , loadmodel->surfmesh.data_lightmapcolor4f   , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
3071 		if (loadmodel->surfmesh.data_skeletalindex4ub  ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub  , loadmodel->surfmesh.data_skeletalindex4ub  , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3072 		if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3073 		loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
3074 		Mem_Free(mem);
3075 	}
3076 }
3077 
3078 extern cvar_t mod_obj_orientation;
Mod_Decompile_OBJ(dp_model_t * model,const char * filename,const char * mtlfilename,const char * originalfilename)3079 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
3080 {
3081 	int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
3082 	int a, b, c;
3083 	const char *texname;
3084 	const int *e;
3085 	const float *v, *vn, *vt;
3086 	size_t l;
3087 	size_t outbufferpos = 0;
3088 	size_t outbuffermax = 0x100000;
3089 	char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3090 	const msurface_t *surface;
3091 	const int maxtextures = 256;
3092 	char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
3093 	dp_model_t *submodel;
3094 
3095 	// construct the mtllib file
3096 	l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
3097 	if (l > 0)
3098 		outbufferpos += l;
3099 	for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3100 	{
3101 		countsurfaces++;
3102 		countvertices += surface->num_vertices;
3103 		countfaces += surface->num_triangles;
3104 		texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
3105 		for (textureindex = 0;textureindex < counttextures;textureindex++)
3106 			if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
3107 				break;
3108 		if (textureindex < counttextures)
3109 			continue; // already wrote this material entry
3110 		if (textureindex >= maxtextures)
3111 			continue; // just a precaution
3112 		textureindex = counttextures++;
3113 		strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
3114 		if (outbufferpos >= outbuffermax >> 1)
3115 		{
3116 			outbuffermax *= 2;
3117 			oldbuffer = outbuffer;
3118 			outbuffer = (char *) Z_Malloc(outbuffermax);
3119 			memcpy(outbuffer, oldbuffer, outbufferpos);
3120 			Z_Free(oldbuffer);
3121 		}
3122 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "newmtl %s\nNs 96.078431\nKa 0 0 0\nKd 0.64 0.64 0.64\nKs 0.5 0.5 0.5\nNi 1\nd 1\nillum 2\nmap_Kd %s%s\n\n", texname, texname, strstr(texname, ".tga") ? "" : ".tga");
3123 		if (l > 0)
3124 			outbufferpos += l;
3125 	}
3126 
3127 	// write the mtllib file
3128 	FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3129 
3130 	// construct the obj file
3131 	outbufferpos = 0;
3132 	l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# model exported from %s by darkplaces engine\n# %i vertices, %i faces, %i surfaces\nmtllib %s\n", originalfilename, countvertices, countfaces, countsurfaces, mtlfilename);
3133 	if (l > 0)
3134 		outbufferpos += l;
3135 
3136 	for (vertexindex = 0, v = model->surfmesh.data_vertex3f, vn = model->surfmesh.data_normal3f, vt = model->surfmesh.data_texcoordtexture2f;vertexindex < model->surfmesh.num_vertices;vertexindex++, v += 3, vn += 3, vt += 2)
3137 	{
3138 		if (outbufferpos >= outbuffermax >> 1)
3139 		{
3140 			outbuffermax *= 2;
3141 			oldbuffer = outbuffer;
3142 			outbuffer = (char *) Z_Malloc(outbuffermax);
3143 			memcpy(outbuffer, oldbuffer, outbufferpos);
3144 			Z_Free(oldbuffer);
3145 		}
3146 		if(mod_obj_orientation.integer)
3147 			l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[2], v[1], vn[0], vn[2], vn[1], vt[0], 1-vt[1]);
3148 		else
3149 			l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "v %f %f %f\nvn %f %f %f\nvt %f %f\n", v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1-vt[1]);
3150 		if (l > 0)
3151 			outbufferpos += l;
3152 	}
3153 
3154 	for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3155 	{
3156 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3157 		if (l > 0)
3158 			outbufferpos += l;
3159 		submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3160 		for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3161 		{
3162 			surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3163 			l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3164 			if (l > 0)
3165 				outbufferpos += l;
3166 			for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3167 			{
3168 				if (outbufferpos >= outbuffermax >> 1)
3169 				{
3170 					outbuffermax *= 2;
3171 					oldbuffer = outbuffer;
3172 					outbuffer = (char *) Z_Malloc(outbuffermax);
3173 					memcpy(outbuffer, oldbuffer, outbufferpos);
3174 					Z_Free(oldbuffer);
3175 				}
3176 				a = e[0]+1;
3177 				b = e[1]+1;
3178 				c = e[2]+1;
3179 				if(mod_obj_orientation.integer)
3180 					l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,b,b,b,c,c,c);
3181 				else
3182 					l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b);
3183 				if (l > 0)
3184 					outbufferpos += l;
3185 			}
3186 		}
3187 	}
3188 
3189 	// write the obj file
3190 	FS_WriteFile(filename, outbuffer, outbufferpos);
3191 
3192 	// clean up
3193 	Z_Free(outbuffer);
3194 	Z_Free(texturenames);
3195 
3196 	// print some stats
3197 	Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3198 }
3199 
Mod_Decompile_SMD(dp_model_t * model,const char * filename,int firstpose,int numposes,qboolean writetriangles)3200 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3201 {
3202 	int countnodes = 0, counttriangles = 0, countframes = 0;
3203 	int surfaceindex;
3204 	int triangleindex;
3205 	int transformindex;
3206 	int poseindex;
3207 	int cornerindex;
3208 	const int *e;
3209 	size_t l;
3210 	size_t outbufferpos = 0;
3211 	size_t outbuffermax = 0x100000;
3212 	char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3213 	const msurface_t *surface;
3214 	l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3215 	if (l > 0)
3216 		outbufferpos += l;
3217 	for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3218 	{
3219 		if (outbufferpos >= outbuffermax >> 1)
3220 		{
3221 			outbuffermax *= 2;
3222 			oldbuffer = outbuffer;
3223 			outbuffer = (char *) Z_Malloc(outbuffermax);
3224 			memcpy(outbuffer, oldbuffer, outbufferpos);
3225 			Z_Free(oldbuffer);
3226 		}
3227 		countnodes++;
3228 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3229 		if (l > 0)
3230 			outbufferpos += l;
3231 	}
3232 	l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3233 	if (l > 0)
3234 		outbufferpos += l;
3235 	for (poseindex = 0;poseindex < numposes;poseindex++)
3236 	{
3237 		countframes++;
3238 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3239 		if (l > 0)
3240 			outbufferpos += l;
3241 		for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3242 		{
3243 			float angles[3];
3244 			float mtest[4][3];
3245 			matrix4x4_t posematrix;
3246 			if (outbufferpos >= outbuffermax >> 1)
3247 			{
3248 				outbuffermax *= 2;
3249 				oldbuffer = outbuffer;
3250 				outbuffer = (char *) Z_Malloc(outbuffermax);
3251 				memcpy(outbuffer, oldbuffer, outbufferpos);
3252 				Z_Free(oldbuffer);
3253 			}
3254 
3255 			// strangely the smd angles are for a transposed matrix, so we
3256 			// have to generate a transposed matrix, then convert that...
3257 			Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3258 			Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3259 			AnglesFromVectors(angles, mtest[0], mtest[2], false);
3260 			if (angles[0] >= 180) angles[0] -= 360;
3261 			if (angles[1] >= 180) angles[1] -= 360;
3262 			if (angles[2] >= 180) angles[2] -= 360;
3263 
3264 #if 0
3265 {
3266 			float a = DEG2RAD(angles[ROLL]);
3267 			float b = DEG2RAD(angles[PITCH]);
3268 			float c = DEG2RAD(angles[YAW]);
3269 			float cy, sy, cp, sp, cr, sr;
3270 			float test[4][3];
3271 			// smd matrix construction, for comparing
3272 			sy = sin(c);
3273 			cy = cos(c);
3274 			sp = sin(b);
3275 			cp = cos(b);
3276 			sr = sin(a);
3277 			cr = cos(a);
3278 
3279 			test[0][0] = cp*cy;
3280 			test[0][1] = cp*sy;
3281 			test[0][2] = -sp;
3282 			test[1][0] = sr*sp*cy+cr*-sy;
3283 			test[1][1] = sr*sp*sy+cr*cy;
3284 			test[1][2] = sr*cp;
3285 			test[2][0] = (cr*sp*cy+-sr*-sy);
3286 			test[2][1] = (cr*sp*sy+-sr*cy);
3287 			test[2][2] = cr*cp;
3288 			test[3][0] = pose[9];
3289 			test[3][1] = pose[10];
3290 			test[3][2] = pose[11];
3291 }
3292 #endif
3293 			l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f\n", transformindex, mtest[3][0], mtest[3][1], mtest[3][2], DEG2RAD(angles[ROLL]), DEG2RAD(angles[PITCH]), DEG2RAD(angles[YAW]));
3294 			if (l > 0)
3295 				outbufferpos += l;
3296 		}
3297 	}
3298 	l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3299 	if (l > 0)
3300 		outbufferpos += l;
3301 	if (writetriangles)
3302 	{
3303 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3304 		if (l > 0)
3305 			outbufferpos += l;
3306 		for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3307 		{
3308 			for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3309 			{
3310 				counttriangles++;
3311 				if (outbufferpos >= outbuffermax >> 1)
3312 				{
3313 					outbuffermax *= 2;
3314 					oldbuffer = outbuffer;
3315 					outbuffer = (char *) Z_Malloc(outbuffermax);
3316 					memcpy(outbuffer, oldbuffer, outbufferpos);
3317 					Z_Free(oldbuffer);
3318 				}
3319 				l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3320 				if (l > 0)
3321 					outbufferpos += l;
3322 				for (cornerindex = 0;cornerindex < 3;cornerindex++)
3323 				{
3324 					const int index = e[2-cornerindex];
3325 					const float *v = model->surfmesh.data_vertex3f + index * 3;
3326 					const float *vn = model->surfmesh.data_normal3f + index * 3;
3327 					const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3328 					const int b = model->surfmesh.blends[index];
3329 					if (b < model->num_bones)
3330 						l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n"                          , b, v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
3331 					else
3332 					{
3333 						const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3334 						const unsigned char *wi = w->index;
3335 						const unsigned char *wf = w->influence;
3336 					    if (wf[3]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 4 %i %f %i %f %i %f %i %f\n", wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f, wi[3], wf[3]/255.0f);
3337 						else if (wf[2]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 3 %i %f %i %f %i %f\n"      , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f, wi[2], wf[2]/255.0f);
3338 						else if (wf[1]) l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f 2 %i %f %i %f\n"            , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1], wi[0], wf[0]/255.0f, wi[1], wf[1]/255.0f);
3339 						else            l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n"                          , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
3340 					}
3341 					if (l > 0)
3342 						outbufferpos += l;
3343 				}
3344 			}
3345 		}
3346 		l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3347 		if (l > 0)
3348 			outbufferpos += l;
3349 	}
3350 
3351 	FS_WriteFile(filename, outbuffer, outbufferpos);
3352 	Z_Free(outbuffer);
3353 
3354 	Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3355 }
3356 
3357 /*
3358 ================
3359 Mod_Decompile_f
3360 
3361 decompiles a model to editable files
3362 ================
3363 */
Mod_Decompile_f(void)3364 static void Mod_Decompile_f(void)
3365 {
3366 	int i, j, k, l, first, count;
3367 	dp_model_t *mod;
3368 	char inname[MAX_QPATH];
3369 	char outname[MAX_QPATH];
3370 	char mtlname[MAX_QPATH];
3371 	char basename[MAX_QPATH];
3372 	char animname[MAX_QPATH];
3373 	char animname2[MAX_QPATH];
3374 	char zymtextbuffer[16384];
3375 	char dpmtextbuffer[16384];
3376 	char framegroupstextbuffer[16384];
3377 	int zymtextsize = 0;
3378 	int dpmtextsize = 0;
3379 	int framegroupstextsize = 0;
3380 	char vabuf[1024];
3381 
3382 	if (Cmd_Argc() != 2)
3383 	{
3384 		Con_Print("usage: modeldecompile <filename>\n");
3385 		return;
3386 	}
3387 
3388 	strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3389 	FS_StripExtension(inname, basename, sizeof(basename));
3390 
3391 	mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3392 	if (!mod)
3393 	{
3394 		Con_Print("No such model\n");
3395 		return;
3396 	}
3397 	if (mod->brush.submodel)
3398 	{
3399 		// if we're decompiling a submodel, be sure to give it a proper name based on its parent
3400 		FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3401 		dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3402 		outname[0] = 0;
3403 	}
3404 	if (!mod->surfmesh.num_triangles)
3405 	{
3406 		Con_Print("Empty model (or sprite)\n");
3407 		return;
3408 	}
3409 
3410 	// export OBJ if possible (not on sprites)
3411 	if (mod->surfmesh.num_triangles)
3412 	{
3413 		dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3414 		dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3415 		Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3416 	}
3417 
3418 	// export SMD if possible (only for skeletal models)
3419 	if (mod->surfmesh.num_triangles && mod->num_bones)
3420 	{
3421 		dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3422 		Mod_Decompile_SMD(mod, outname, 0, 1, true);
3423 		l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3424 		if (l > 0) zymtextsize += l;
3425 		l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3426 		if (l > 0) dpmtextsize += l;
3427 		for (i = 0;i < mod->numframes;i = j)
3428 		{
3429 			strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3430 			first = mod->animscenes[i].firstframe;
3431 			if (mod->animscenes[i].framecount > 1)
3432 			{
3433 				// framegroup anim
3434 				count = mod->animscenes[i].framecount;
3435 				j = i + 1;
3436 			}
3437 			else
3438 			{
3439 				// individual frame
3440 				// check for additional frames with same name
3441 				for (l = 0, k = (int)strlen(animname);animname[l];l++)
3442 					if(animname[l] < '0' || animname[l] > '9')
3443 						k = l + 1;
3444 				if(k > 0 && animname[k-1] == '_')
3445 					--k;
3446 				animname[k] = 0;
3447 				count = mod->num_poses - first;
3448 				for (j = i + 1;j < mod->numframes;j++)
3449 				{
3450 					strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3451 					for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3452 						if(animname2[l] < '0' || animname2[l] > '9')
3453 							k = l + 1;
3454 					if(k > 0 && animname[k-1] == '_')
3455 						--k;
3456 					animname2[k] = 0;
3457 					if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3458 					{
3459 						count = mod->animscenes[j].firstframe - first;
3460 						break;
3461 					}
3462 				}
3463 				// if it's only one frame, use the original frame name
3464 				if (j == i + 1)
3465 					strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3466 
3467 			}
3468 			dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3469 			Mod_Decompile_SMD(mod, outname, first, count, false);
3470 			if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3471 			{
3472 				l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3473 				if (l > 0) zymtextsize += l;
3474 			}
3475 			if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3476 			{
3477 				l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3478 				if (l > 0) dpmtextsize += l;
3479 			}
3480 			if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3481 			{
3482 				l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3483 				if (l > 0) framegroupstextsize += l;
3484 			}
3485 		}
3486 		if (zymtextsize)
3487 			FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3488 		if (dpmtextsize)
3489 			FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3490 		if (framegroupstextsize)
3491 			FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3492 	}
3493 }
3494 
Mod_AllocLightmap_Init(mod_alloclightmap_state_t * state,int width,int height)3495 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, int width, int height)
3496 {
3497 	int y;
3498 	memset(state, 0, sizeof(*state));
3499 	state->width = width;
3500 	state->height = height;
3501 	state->currentY = 0;
3502 	state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(loadmodel->mempool, state->height * sizeof(*state->rows));
3503 	for (y = 0;y < state->height;y++)
3504 	{
3505 		state->rows[y].currentX = 0;
3506 		state->rows[y].rowY = -1;
3507 	}
3508 }
3509 
Mod_AllocLightmap_Reset(mod_alloclightmap_state_t * state)3510 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3511 {
3512 	int y;
3513 	state->currentY = 0;
3514 	for (y = 0;y < state->height;y++)
3515 	{
3516 		state->rows[y].currentX = 0;
3517 		state->rows[y].rowY = -1;
3518 	}
3519 }
3520 
Mod_AllocLightmap_Free(mod_alloclightmap_state_t * state)3521 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3522 {
3523 	if (state->rows)
3524 		Mem_Free(state->rows);
3525 	memset(state, 0, sizeof(*state));
3526 }
3527 
Mod_AllocLightmap_Block(mod_alloclightmap_state_t * state,int blockwidth,int blockheight,int * outx,int * outy)3528 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3529 {
3530 	mod_alloclightmap_row_t *row;
3531 	int y;
3532 
3533 	row = state->rows + blockheight;
3534 	if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3535 	{
3536 		if (state->currentY + blockheight <= state->height)
3537 		{
3538 			// use the current allocation position
3539 			row->rowY = state->currentY;
3540 			row->currentX = 0;
3541 			state->currentY += blockheight;
3542 		}
3543 		else
3544 		{
3545 			// find another position
3546 			for (y = blockheight;y < state->height;y++)
3547 			{
3548 				if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3549 				{
3550 					row = state->rows + y;
3551 					break;
3552 				}
3553 			}
3554 			if (y == state->height)
3555 				return false;
3556 		}
3557 	}
3558 	*outy = row->rowY;
3559 	*outx = row->currentX;
3560 	row->currentX += blockwidth;
3561 
3562 	return true;
3563 }
3564 
3565 typedef struct lightmapsample_s
3566 {
3567 	float pos[3];
3568 	float sh1[4][3];
3569 	float *vertex_color;
3570 	unsigned char *lm_bgr;
3571 	unsigned char *lm_dir;
3572 }
3573 lightmapsample_t;
3574 
3575 typedef struct lightmapvertex_s
3576 {
3577 	int index;
3578 	float pos[3];
3579 	float normal[3];
3580 	float texcoordbase[2];
3581 	float texcoordlightmap[2];
3582 	float lightcolor[4];
3583 }
3584 lightmapvertex_t;
3585 
3586 typedef struct lightmaptriangle_s
3587 {
3588 	int triangleindex;
3589 	int surfaceindex;
3590 	int lightmapindex;
3591 	int axis;
3592 	int lmoffset[2];
3593 	int lmsize[2];
3594 	// 2D modelspace coordinates of min corner
3595 	// snapped to lightmap grid but not in grid coordinates
3596 	float lmbase[2];
3597 	// 2D modelspace to lightmap coordinate scale
3598 	float lmscale[2];
3599 	float vertex[3][3];
3600 	float mins[3];
3601 	float maxs[3];
3602 }
3603 lightmaptriangle_t;
3604 
3605 typedef struct lightmaplight_s
3606 {
3607 	float origin[3];
3608 	float radius;
3609 	float iradius;
3610 	float radius2;
3611 	float color[3];
3612 	svbsp_t svbsp;
3613 }
3614 lightmaplight_t;
3615 
3616 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3617 
3618 #define MAX_LIGHTMAPSAMPLES 64
3619 static int mod_generatelightmaps_numoffsets[3];
3620 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3621 
3622 static int mod_generatelightmaps_numlights;
3623 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3624 
3625 extern cvar_t r_shadow_lightattenuationdividebias;
3626 extern cvar_t r_shadow_lightattenuationlinearscale;
3627 
Mod_GenerateLightmaps_LightPoint(dp_model_t * model,const vec3_t pos,vec3_t ambient,vec3_t diffuse,vec3_t lightdir)3628 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3629 {
3630 	int i;
3631 	int index;
3632 	int result;
3633 	float relativepoint[3];
3634 	float color[3];
3635 	float dir[3];
3636 	float dist;
3637 	float dist2;
3638 	float intensity;
3639 	float sample[5*3];
3640 	float lightorigin[3];
3641 	float lightradius;
3642 	float lightradius2;
3643 	float lightiradius;
3644 	float lightcolor[3];
3645 	trace_t trace;
3646 	for (i = 0;i < 5*3;i++)
3647 		sample[i] = 0.0f;
3648 	for (index = 0;;index++)
3649 	{
3650 		result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3651 		if (result < 0)
3652 			break;
3653 		if (result == 0)
3654 			continue;
3655 		lightradius2 = lightradius * lightradius;
3656 		VectorSubtract(lightorigin, pos, relativepoint);
3657 		dist2 = VectorLength2(relativepoint);
3658 		if (dist2 >= lightradius2)
3659 			continue;
3660 		lightiradius = 1.0f / lightradius;
3661 		dist = sqrt(dist2) * lightiradius;
3662 		intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3663 		if (intensity <= 0.0f)
3664 			continue;
3665 		if (model && model->TraceLine)
3666 		{
3667 			model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY);
3668 			if (trace.fraction < 1)
3669 				continue;
3670 		}
3671 		// scale down intensity to add to both ambient and diffuse
3672 		//intensity *= 0.5f;
3673 		VectorNormalize(relativepoint);
3674 		VectorScale(lightcolor, intensity, color);
3675 		VectorMA(sample    , 0.5f            , color, sample    );
3676 		VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3677 		VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3678 		VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3679 		// calculate a weighted average light direction as well
3680 		intensity *= VectorLength(color);
3681 		VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3682 	}
3683 	// calculate the direction we'll use to reduce the sample to a directional light source
3684 	VectorCopy(sample + 12, dir);
3685 	//VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3686 	VectorNormalize(dir);
3687 	// extract the diffuse color along the chosen direction and scale it
3688 	diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3689 	diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3690 	diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3691 	// subtract some of diffuse from ambient
3692 	VectorMA(sample, -0.333f, diffuse, ambient);
3693 	// store the normalized lightdir
3694 	VectorCopy(dir, lightdir);
3695 }
3696 
Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t * model,svbsp_t * svbsp,const float * mins,const float * maxs)3697 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3698 {
3699 	int surfaceindex;
3700 	int triangleindex;
3701 	const msurface_t *surface;
3702 	const float *vertex3f = model->surfmesh.data_vertex3f;
3703 	const int *element3i = model->surfmesh.data_element3i;
3704 	const int *e;
3705 	float v2[3][3];
3706 	for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3707 	{
3708 		if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3709 			continue;
3710 		if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3711 			continue;
3712 		for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3713 		{
3714 			VectorCopy(vertex3f + 3*e[0], v2[0]);
3715 			VectorCopy(vertex3f + 3*e[1], v2[1]);
3716 			VectorCopy(vertex3f + 3*e[2], v2[2]);
3717 			SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3718 		}
3719 	}
3720 }
3721 
Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t * model,lightmaplight_t * lightinfo)3722 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3723 {
3724 	int maxnodes = 1<<14;
3725 	svbsp_node_t *nodes;
3726 	float origin[3];
3727 	float mins[3];
3728 	float maxs[3];
3729 	svbsp_t svbsp;
3730 	VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3731 	VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3732 	VectorCopy(lightinfo->origin, origin);
3733 	nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3734 	for (;;)
3735 	{
3736 		SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3737 		Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3738 		if (svbsp.ranoutofnodes)
3739 		{
3740 			maxnodes *= 16;
3741 			if (maxnodes > 1<<22)
3742 			{
3743 				Mem_Free(nodes);
3744 				return;
3745 			}
3746 			Mem_Free(nodes);
3747 			nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3748 		}
3749 		else
3750 			break;
3751 	}
3752 	if (svbsp.numnodes > 0)
3753 	{
3754 		svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3755 		memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3756 		lightinfo->svbsp = svbsp;
3757 	}
3758 	Mem_Free(nodes);
3759 }
3760 
Mod_GenerateLightmaps_CreateLights(dp_model_t * model)3761 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3762 {
3763 	int index;
3764 	int result;
3765 	lightmaplight_t *lightinfo;
3766 	float origin[3];
3767 	float radius;
3768 	float color[3];
3769 	mod_generatelightmaps_numlights = 0;
3770 	for (index = 0;;index++)
3771 	{
3772 		result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3773 		if (result < 0)
3774 			break;
3775 		if (result > 0)
3776 			mod_generatelightmaps_numlights++;
3777 	}
3778 	if (mod_generatelightmaps_numlights > 0)
3779 	{
3780 		mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3781 		lightinfo = mod_generatelightmaps_lightinfo;
3782 		for (index = 0;;index++)
3783 		{
3784 			result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3785 			if (result < 0)
3786 				break;
3787 			if (result > 0)
3788 				lightinfo++;
3789 		}
3790 	}
3791 	for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3792 	{
3793 		lightinfo->iradius = 1.0f / lightinfo->radius;
3794 		lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3795 		// TODO: compute svbsp
3796 		Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3797 	}
3798 }
3799 
Mod_GenerateLightmaps_DestroyLights(dp_model_t * model)3800 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3801 {
3802 	int i;
3803 	if (mod_generatelightmaps_lightinfo)
3804 	{
3805 		for (i = 0;i < mod_generatelightmaps_numlights;i++)
3806 			if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3807 				Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3808 		Mem_Free(mod_generatelightmaps_lightinfo);
3809 	}
3810 	mod_generatelightmaps_lightinfo = NULL;
3811 	mod_generatelightmaps_numlights = 0;
3812 }
3813 
Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t * svbsp,const float * pos)3814 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3815 {
3816 	const svbsp_node_t *node;
3817 	const svbsp_node_t *nodes = svbsp->nodes;
3818 	int num = 0;
3819 	while (num >= 0)
3820 	{
3821 		node = nodes + num;
3822 		num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3823 	}
3824 	return num == -1; // true if empty, false if solid (shadowed)
3825 }
3826 
Mod_GenerateLightmaps_SamplePoint(const float * pos,const float * normal,float * sample,int numoffsets,const float * offsets)3827 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3828 {
3829 	int i;
3830 	float relativepoint[3];
3831 	float color[3];
3832 	float offsetpos[3];
3833 	float dist;
3834 	float dist2;
3835 	float intensity;
3836 	int offsetindex;
3837 	int hits;
3838 	int tests;
3839 	const lightmaplight_t *lightinfo;
3840 	trace_t trace;
3841 	for (i = 0;i < 5*3;i++)
3842 		sample[i] = 0.0f;
3843 	for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3844 	{
3845 		//R_SampleRTLights(pos, sample, numoffsets, offsets);
3846 		VectorSubtract(lightinfo->origin, pos, relativepoint);
3847 		// don't accept light from behind a surface, it causes bad shading
3848 		if (normal && DotProduct(relativepoint, normal) <= 0)
3849 			continue;
3850 		dist2 = VectorLength2(relativepoint);
3851 		if (dist2 >= lightinfo->radius2)
3852 			continue;
3853 		dist = sqrt(dist2) * lightinfo->iradius;
3854 		intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3855 		if (intensity <= 0)
3856 			continue;
3857 		if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3858 		{
3859 			hits = 0;
3860 			tests = 1;
3861 			if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3862 				hits++;
3863 			for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3864 			{
3865 				VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3866 				if (!normal)
3867 				{
3868 					// for light grid we'd better check visibility of the offset point
3869 					cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_VISBLOCKERMASK, SUPERCONTENTS_SKY);
3870 					if (trace.fraction < 1)
3871 						VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3872 				}
3873 				tests++;
3874 				if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3875 					hits++;
3876 			}
3877 			if (!hits)
3878 				continue;
3879 			// scale intensity according to how many rays succeeded
3880 			// we know one test is valid, half of the rest will fail...
3881 			//if (normal && tests > 1)
3882 			//	intensity *= (tests - 1.0f) / tests;
3883 			intensity *= (float)hits / tests;
3884 		}
3885 		// scale down intensity to add to both ambient and diffuse
3886 		//intensity *= 0.5f;
3887 		VectorNormalize(relativepoint);
3888 		VectorScale(lightinfo->color, intensity, color);
3889 		VectorMA(sample    , 0.5f            , color, sample    );
3890 		VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3891 		VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3892 		VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3893 		// calculate a weighted average light direction as well
3894 		intensity *= VectorLength(color);
3895 		VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3896 	}
3897 }
3898 
Mod_GenerateLightmaps_LightmapSample(const float * pos,const float * normal,unsigned char * lm_bgr,unsigned char * lm_dir)3899 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3900 {
3901 	float sample[5*3];
3902 	float color[3];
3903 	float dir[3];
3904 	float f;
3905 	Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
3906 	//VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3907 	VectorCopy(sample + 12, dir);
3908 	VectorNormalize(dir);
3909 	//VectorAdd(dir, normal, dir);
3910 	//VectorNormalize(dir);
3911 	f = DotProduct(dir, normal);
3912 	f = max(0, f) * 255.0f;
3913 	VectorScale(sample, f, color);
3914 	//VectorCopy(normal, dir);
3915 	VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3916 	lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3917 	lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3918 	lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3919 	lm_bgr[3] = 255;
3920 	lm_dir[0] = (unsigned char)dir[2];
3921 	lm_dir[1] = (unsigned char)dir[1];
3922 	lm_dir[2] = (unsigned char)dir[0];
3923 	lm_dir[3] = 255;
3924 }
3925 
Mod_GenerateLightmaps_VertexSample(const float * pos,const float * normal,float * vertex_color)3926 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3927 {
3928 	float sample[5*3];
3929 	Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
3930 	VectorCopy(sample, vertex_color);
3931 }
3932 
Mod_GenerateLightmaps_GridSample(const float * pos,q3dlightgrid_t * s)3933 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3934 {
3935 	float sample[5*3];
3936 	float ambient[3];
3937 	float diffuse[3];
3938 	float dir[3];
3939 	Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
3940 	// calculate the direction we'll use to reduce the sample to a directional light source
3941 	VectorCopy(sample + 12, dir);
3942 	//VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3943 	VectorNormalize(dir);
3944 	// extract the diffuse color along the chosen direction and scale it
3945 	diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3946 	diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3947 	diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3948 	// scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3949 	VectorScale(sample, 127.5f, ambient);
3950 	VectorMA(ambient, -0.333f, diffuse, ambient);
3951 	// encode to the grid format
3952 	s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3953 	s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3954 	s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3955 	s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3956 	s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3957 	s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3958 	if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3959 	else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3960 	else {s->diffusepitch = (unsigned char)(acos(dir[2]) * (127.5f/M_PI));s->diffuseyaw = (unsigned char)(atan2(dir[1], dir[0]) * (127.5f/M_PI));}
3961 }
3962 
Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t * model)3963 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
3964 {
3965 	float radius[3];
3966 	float temp[3];
3967 	int i, j;
3968 	memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
3969 	mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
3970 	mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
3971 	mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
3972 	radius[0] = mod_generatelightmaps_lightmapradius.value;
3973 	radius[1] = mod_generatelightmaps_vertexradius.value;
3974 	radius[2] = mod_generatelightmaps_gridradius.value;
3975 	for (i = 0;i < 3;i++)
3976 	{
3977 		for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
3978 		{
3979 			VectorRandom(temp);
3980 			VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
3981 		}
3982 	}
3983 }
3984 
Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t * model)3985 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
3986 {
3987 	msurface_t *surface;
3988 	int surfaceindex;
3989 	int i;
3990 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3991 	{
3992 		surface = model->data_surfaces + surfaceindex;
3993 		surface->lightmaptexture = NULL;
3994 		surface->deluxemaptexture = NULL;
3995 	}
3996 	if (model->brushq3.data_lightmaps)
3997 	{
3998 		for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3999 			if (model->brushq3.data_lightmaps[i])
4000 				R_FreeTexture(model->brushq3.data_lightmaps[i]);
4001 		Mem_Free(model->brushq3.data_lightmaps);
4002 		model->brushq3.data_lightmaps = NULL;
4003 	}
4004 	if (model->brushq3.data_deluxemaps)
4005 	{
4006 		for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4007 			if (model->brushq3.data_deluxemaps[i])
4008 				R_FreeTexture(model->brushq3.data_deluxemaps[i]);
4009 		Mem_Free(model->brushq3.data_deluxemaps);
4010 		model->brushq3.data_deluxemaps = NULL;
4011 	}
4012 }
4013 
Mod_GenerateLightmaps_UnweldTriangles(dp_model_t * model)4014 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
4015 {
4016 	msurface_t *surface;
4017 	int surfaceindex;
4018 	int vertexindex;
4019 	int outvertexindex;
4020 	int i;
4021 	const int *e;
4022 	surfmesh_t oldsurfmesh;
4023 	size_t size;
4024 	unsigned char *data;
4025 	oldsurfmesh = model->surfmesh;
4026 	model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
4027 	model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
4028 	size = 0;
4029 	size += model->surfmesh.num_vertices * sizeof(float[3]);
4030 	size += model->surfmesh.num_vertices * sizeof(float[3]);
4031 	size += model->surfmesh.num_vertices * sizeof(float[3]);
4032 	size += model->surfmesh.num_vertices * sizeof(float[3]);
4033 	size += model->surfmesh.num_vertices * sizeof(float[2]);
4034 	size += model->surfmesh.num_vertices * sizeof(float[2]);
4035 	size += model->surfmesh.num_vertices * sizeof(float[4]);
4036 	data = (unsigned char *)Mem_Alloc(model->mempool, size);
4037 	model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4038 	model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4039 	model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4040 	model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4041 	model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4042 	model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4043 	model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
4044 	if (model->surfmesh.num_vertices > 65536)
4045 		model->surfmesh.data_element3s = NULL;
4046 
4047 	if (model->surfmesh.data_element3i_indexbuffer)
4048 		R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
4049 	model->surfmesh.data_element3i_indexbuffer = NULL;
4050 	if (model->surfmesh.data_element3s_indexbuffer)
4051 		R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
4052 	model->surfmesh.data_element3s_indexbuffer = NULL;
4053 	if (model->surfmesh.vbo_vertexbuffer)
4054 		R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
4055 	model->surfmesh.vbo_vertexbuffer = 0;
4056 
4057 	// convert all triangles to unique vertex data
4058 	outvertexindex = 0;
4059 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4060 	{
4061 		surface = model->data_surfaces + surfaceindex;
4062 		surface->num_firstvertex = outvertexindex;
4063 		surface->num_vertices = surface->num_triangles*3;
4064 		e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
4065 		for (i = 0;i < surface->num_triangles*3;i++)
4066 		{
4067 			vertexindex = e[i];
4068 			model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
4069 			model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
4070 			model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
4071 			model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
4072 			model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
4073 			model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
4074 			model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
4075 			model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
4076 			model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
4077 			model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
4078 			model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
4079 			model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
4080 			model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
4081 			model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
4082 			if (oldsurfmesh.data_texcoordlightmap2f)
4083 			{
4084 				model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
4085 				model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
4086 			}
4087 			if (oldsurfmesh.data_lightmapcolor4f)
4088 			{
4089 				model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
4090 				model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
4091 				model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
4092 				model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
4093 			}
4094 			else
4095 				Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
4096 			model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
4097 			outvertexindex++;
4098 		}
4099 	}
4100 	if (model->surfmesh.data_element3s)
4101 		for (i = 0;i < model->surfmesh.num_triangles*3;i++)
4102 			model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
4103 
4104 	// find and update all submodels to use this new surfmesh data
4105 	for (i = 0;i < model->brush.numsubmodels;i++)
4106 		model->brush.submodels[i]->surfmesh = model->surfmesh;
4107 }
4108 
Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t * model)4109 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4110 {
4111 	msurface_t *surface;
4112 	int surfaceindex;
4113 	int i;
4114 	int axis;
4115 	float normal[3];
4116 	const int *e;
4117 	lightmaptriangle_t *triangle;
4118 	// generate lightmap triangle structs
4119 	mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4120 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4121 	{
4122 		surface = model->data_surfaces + surfaceindex;
4123 		e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4124 		for (i = 0;i < surface->num_triangles;i++)
4125 		{
4126 			triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4127 			triangle->triangleindex = surface->num_firsttriangle+i;
4128 			triangle->surfaceindex = surfaceindex;
4129 			VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4130 			VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4131 			VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4132 			// calculate bounds of triangle
4133 			triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4134 			triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4135 			triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4136 			triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4137 			triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4138 			triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4139 			// pick an axial projection based on the triangle normal
4140 			TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4141 			axis = 0;
4142 			if (fabs(normal[1]) > fabs(normal[axis]))
4143 				axis = 1;
4144 			if (fabs(normal[2]) > fabs(normal[axis]))
4145 				axis = 2;
4146 			triangle->axis = axis;
4147 		}
4148 	}
4149 }
4150 
Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t * model)4151 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4152 {
4153 	if (mod_generatelightmaps_lightmaptriangles)
4154 		Mem_Free(mod_generatelightmaps_lightmaptriangles);
4155 	mod_generatelightmaps_lightmaptriangles = NULL;
4156 }
4157 
4158 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4159 
Mod_GenerateLightmaps_CreateLightmaps(dp_model_t * model)4160 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4161 {
4162 	msurface_t *surface;
4163 	int surfaceindex;
4164 	int lightmapindex;
4165 	int lightmapnumber;
4166 	int i;
4167 	int j;
4168 	int k;
4169 	int x;
4170 	int y;
4171 	int axis;
4172 	int axis1;
4173 	int axis2;
4174 	int retry;
4175 	int pixeloffset;
4176 	float trianglenormal[3];
4177 	float samplecenter[3];
4178 	float samplenormal[3];
4179 	float temp[3];
4180 	float lmiscale[2];
4181 	float slopex;
4182 	float slopey;
4183 	float slopebase;
4184 	float lmscalepixels;
4185 	float lmmins;
4186 	float lmmaxs;
4187 	float lm_basescalepixels;
4188 	int lm_borderpixels;
4189 	int lm_texturesize;
4190 	//int lm_maxpixels;
4191 	const int *e;
4192 	lightmaptriangle_t *triangle;
4193 	unsigned char *lightmappixels;
4194 	unsigned char *deluxemappixels;
4195 	mod_alloclightmap_state_t lmstate;
4196 	char vabuf[1024];
4197 
4198 	// generate lightmap projection information for all triangles
4199 	if (model->texturepool == NULL)
4200 		model->texturepool = R_AllocTexturePool();
4201 	lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4202 	lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4203 	lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4204 	//lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4205 	Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
4206 	lightmapnumber = 0;
4207 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4208 	{
4209 		surface = model->data_surfaces + surfaceindex;
4210 		e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4211 		lmscalepixels = lm_basescalepixels;
4212 		for (retry = 0;retry < 30;retry++)
4213 		{
4214 			// after a couple failed attempts, degrade quality to make it fit
4215 			if (retry > 1)
4216 				lmscalepixels *= 0.5f;
4217 			for (i = 0;i < surface->num_triangles;i++)
4218 			{
4219 				triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4220 				triangle->lightmapindex = lightmapnumber;
4221 				// calculate lightmap bounds in 3D pixel coordinates, limit size,
4222 				// pick two planar axes for projection
4223 				// lightmap coordinates here are in pixels
4224 				// lightmap projections are snapped to pixel grid explicitly, such
4225 				// that two neighboring triangles sharing an edge and projection
4226 				// axis will have identical sampl espacing along their shared edge
4227 				k = 0;
4228 				for (j = 0;j < 3;j++)
4229 				{
4230 					if (j == triangle->axis)
4231 						continue;
4232 					lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4233 					lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4234 					triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4235 					triangle->lmbase[k] = lmmins/lmscalepixels;
4236 					triangle->lmscale[k] = lmscalepixels;
4237 					k++;
4238 				}
4239 				if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4240 					break;
4241 			}
4242 			// if all fit in this texture, we're done with this surface
4243 			if (i == surface->num_triangles)
4244 				break;
4245 			// if we haven't maxed out the lightmap size yet, we retry the
4246 			// entire surface batch...
4247 			if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4248 			{
4249 				lm_texturesize *= 2;
4250 				surfaceindex = -1;
4251 				lightmapnumber = 0;
4252 				Mod_AllocLightmap_Free(&lmstate);
4253 				Mod_AllocLightmap_Init(&lmstate, lm_texturesize, lm_texturesize);
4254 				break;
4255 			}
4256 			// if we have maxed out the lightmap size, and this triangle does
4257 			// not fit in the same texture as the rest of the surface, we have
4258 			// to retry the entire surface in a new texture (can only use one)
4259 			// with multiple retries, the lightmap quality degrades until it
4260 			// fits (or gives up)
4261 			if (surfaceindex > 0)
4262 				lightmapnumber++;
4263 			Mod_AllocLightmap_Reset(&lmstate);
4264 		}
4265 	}
4266 	lightmapnumber++;
4267 	Mod_AllocLightmap_Free(&lmstate);
4268 
4269 	// now put triangles together into lightmap textures, and do not allow
4270 	// triangles of a surface to go into different textures (as that would
4271 	// require rewriting the surface list)
4272 	model->brushq3.deluxemapping_modelspace = true;
4273 	model->brushq3.deluxemapping = true;
4274 	model->brushq3.num_mergedlightmaps = lightmapnumber;
4275 	model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4276 	model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4277 	lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4278 	deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4279 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4280 	{
4281 		surface = model->data_surfaces + surfaceindex;
4282 		e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4283 		for (i = 0;i < surface->num_triangles;i++)
4284 		{
4285 			triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4286 			TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4287 			VectorNormalize(trianglenormal);
4288 			VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4289 			axis = triangle->axis;
4290 			axis1 = axis == 0 ? 1 : 0;
4291 			axis2 = axis == 2 ? 1 : 2;
4292 			lmiscale[0] = 1.0f / triangle->lmscale[0];
4293 			lmiscale[1] = 1.0f / triangle->lmscale[1];
4294 			if (trianglenormal[axis] < 0)
4295 				VectorNegate(trianglenormal, trianglenormal);
4296 			CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4297 			CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4298 			slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4299 			for (j = 0;j < 3;j++)
4300 			{
4301 				float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4302 				t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4303 				t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4304 #if 0
4305 				samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4306 				samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4307 				samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4308 				Con_Printf("%f:%f %f:%f %f:%f = %f %f\n", triangle->vertex[j][axis1], samplecenter[axis1], triangle->vertex[j][axis2], samplecenter[axis2], triangle->vertex[j][axis], samplecenter[axis], t2f[0], t2f[1]);
4309 #endif
4310 			}
4311 
4312 #if 0
4313 			switch (axis)
4314 			{
4315 			default:
4316 			case 0:
4317 				forward[0] = 0;
4318 				forward[1] = 1.0f / triangle->lmscale[0];
4319 				forward[2] = 0;
4320 				left[0] = 0;
4321 				left[1] = 0;
4322 				left[2] = 1.0f / triangle->lmscale[1];
4323 				up[0] = 1.0f;
4324 				up[1] = 0;
4325 				up[2] = 0;
4326 				origin[0] = 0;
4327 				origin[1] = triangle->lmbase[0];
4328 				origin[2] = triangle->lmbase[1];
4329 				break;
4330 			case 1:
4331 				forward[0] = 1.0f / triangle->lmscale[0];
4332 				forward[1] = 0;
4333 				forward[2] = 0;
4334 				left[0] = 0;
4335 				left[1] = 0;
4336 				left[2] = 1.0f / triangle->lmscale[1];
4337 				up[0] = 0;
4338 				up[1] = 1.0f;
4339 				up[2] = 0;
4340 				origin[0] = triangle->lmbase[0];
4341 				origin[1] = 0;
4342 				origin[2] = triangle->lmbase[1];
4343 				break;
4344 			case 2:
4345 				forward[0] = 1.0f / triangle->lmscale[0];
4346 				forward[1] = 0;
4347 				forward[2] = 0;
4348 				left[0] = 0;
4349 				left[1] = 1.0f / triangle->lmscale[1];
4350 				left[2] = 0;
4351 				up[0] = 0;
4352 				up[1] = 0;
4353 				up[2] = 1.0f;
4354 				origin[0] = triangle->lmbase[0];
4355 				origin[1] = triangle->lmbase[1];
4356 				origin[2] = 0;
4357 				break;
4358 			}
4359 			Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4360 #endif
4361 #define LM_DIST_EPSILON (1.0f / 32.0f)
4362 			for (y = 0;y < triangle->lmsize[1];y++)
4363 			{
4364 				pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4365 				for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4366 				{
4367 					samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4368 					samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4369 					samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4370 					VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4371 					Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4372 				}
4373 			}
4374 		}
4375 	}
4376 
4377 	for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4378 	{
4379 		model->brushq3.data_lightmaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va(vabuf, sizeof(vabuf), "lightmap%i", lightmapindex), lm_texturesize, lm_texturesize, lightmappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL);
4380 		model->brushq3.data_deluxemaps[lightmapindex] = R_LoadTexture2D(model->texturepool, va(vabuf, sizeof(vabuf), "deluxemap%i", lightmapindex), lm_texturesize, lm_texturesize, deluxemappixels + lightmapindex * lm_texturesize * lm_texturesize * 4, TEXTYPE_BGRA, TEXF_FORCELINEAR, -1, NULL);
4381 	}
4382 
4383 	if (lightmappixels)
4384 		Mem_Free(lightmappixels);
4385 	if (deluxemappixels)
4386 		Mem_Free(deluxemappixels);
4387 
4388 	for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4389 	{
4390 		surface = model->data_surfaces + surfaceindex;
4391 		if (!surface->num_triangles)
4392 			continue;
4393 		lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4394 		surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4395 		surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4396 		surface->lightmapinfo = NULL;
4397 	}
4398 
4399 	model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4400 	model->brushq1.lightdata = NULL;
4401 	model->brushq1.lightmapupdateflags = NULL;
4402 	model->brushq1.firstrender = false;
4403 	model->brushq1.num_lightstyles = 0;
4404 	model->brushq1.data_lightstyleinfo = NULL;
4405 	for (i = 0;i < model->brush.numsubmodels;i++)
4406 	{
4407 		model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4408 		model->brush.submodels[i]->brushq1.firstrender = false;
4409 		model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4410 		model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4411 	}
4412 }
4413 
Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t * model)4414 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4415 {
4416 	int i;
4417 	for (i = 0;i < model->surfmesh.num_vertices;i++)
4418 		Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4419 }
4420 
Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t * model)4421 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4422 {
4423 	int x;
4424 	int y;
4425 	int z;
4426 	int index = 0;
4427 	float pos[3];
4428 	for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4429 	{
4430 		pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4431 		for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4432 		{
4433 			pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4434 			for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4435 			{
4436 				pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4437 				Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4438 			}
4439 		}
4440 	}
4441 }
4442 
4443 extern cvar_t mod_q3bsp_nolightmaps;
Mod_GenerateLightmaps(dp_model_t * model)4444 static void Mod_GenerateLightmaps(dp_model_t *model)
4445 {
4446 	//lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4447 	dp_model_t *oldloadmodel = loadmodel;
4448 	loadmodel = model;
4449 
4450 	Mod_GenerateLightmaps_InitSampleOffsets(model);
4451 	Mod_GenerateLightmaps_DestroyLightmaps(model);
4452 	Mod_GenerateLightmaps_UnweldTriangles(model);
4453 	Mod_GenerateLightmaps_CreateTriangleInformation(model);
4454 	Mod_GenerateLightmaps_CreateLights(model);
4455 	if(!mod_q3bsp_nolightmaps.integer)
4456 		Mod_GenerateLightmaps_CreateLightmaps(model);
4457 	Mod_GenerateLightmaps_UpdateVertexColors(model);
4458 	Mod_GenerateLightmaps_UpdateLightGrid(model);
4459 	Mod_GenerateLightmaps_DestroyLights(model);
4460 	Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4461 
4462 	loadmodel = oldloadmodel;
4463 }
4464 
Mod_GenerateLightmaps_f(void)4465 static void Mod_GenerateLightmaps_f(void)
4466 {
4467 	if (Cmd_Argc() != 1)
4468 	{
4469 		Con_Printf("usage: mod_generatelightmaps\n");
4470 		return;
4471 	}
4472 	if (!cl.worldmodel)
4473 	{
4474 		Con_Printf("no worldmodel loaded\n");
4475 		return;
4476 	}
4477 	Mod_GenerateLightmaps(cl.worldmodel);
4478 }
4479