2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // models.c -- model loading and caching
22 // models are the only shared resource between a client and server running
23 // on the same machine.
30 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"};
31 cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
32 cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
33 cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
34 cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
35 cvar_t mod_generatelightmaps_lightmapsamples = {CVAR_SAVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
36 cvar_t mod_generatelightmaps_vertexsamples = {CVAR_SAVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
37 cvar_t mod_generatelightmaps_gridsamples = {CVAR_SAVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
38 cvar_t mod_generatelightmaps_lightmapradius = {CVAR_SAVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
39 cvar_t mod_generatelightmaps_vertexradius = {CVAR_SAVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
40 cvar_t mod_generatelightmaps_gridradius = {CVAR_SAVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
42 dp_model_t *loadmodel;
44 static mempool_t *mod_mempool;
45 static memexpandablearray_t models;
47 static mempool_t* q3shaders_mem;
48 typedef struct q3shader_hash_entry_s
50 q3shaderinfo_t shader;
51 struct q3shader_hash_entry_s* chain;
52 } q3shader_hash_entry_t;
53 #define Q3SHADER_HASH_SIZE 1021
54 typedef struct q3shader_data_s
56 memexpandablearray_t hash_entries;
57 q3shader_hash_entry_t hash[Q3SHADER_HASH_SIZE];
58 memexpandablearray_t char_ptrs;
60 static q3shader_data_t* q3shader_data;
62 static void mod_start(void)
65 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
68 SCR_PushLoadingScreen(false, "Loading models", 1.0);
70 for (i = 0;i < nummodels;i++)
71 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
74 for (i = 0;i < nummodels;i++)
75 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
78 SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
79 Mod_LoadModel(mod, true, false);
80 SCR_PopLoadingScreen(false);
82 SCR_PopLoadingScreen(false);
85 static void mod_shutdown(void)
88 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
91 for (i = 0;i < nummodels;i++)
92 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
96 Mod_Skeletal_FreeBuffers();
99 static void mod_newmap(void)
102 int i, j, k, l, surfacenum, ssize, tsize;
103 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
106 for (i = 0;i < nummodels;i++)
108 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
110 for (j = 0;j < mod->num_textures && mod->data_textures;j++)
112 // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them...
113 for (l = 0; l < Q3SHADER_MAXLAYERS; l++)
114 if (mod->data_textures[j].shaderpasses[l])
115 for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++)
116 R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]);
118 if (mod->brush.solidskyskinframe)
119 R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
120 if (mod->brush.alphaskyskinframe)
121 R_SkinFrame_MarkUsed(mod->brush.alphaskyskinframe);
125 if (!cl_stainmaps_clearonload.integer)
128 for (i = 0;i < nummodels;i++)
130 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
132 for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++)
134 if (surface->lightmapinfo && surface->lightmapinfo->stainsamples)
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;
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);
157 mod_mempool = Mem_AllocPool("modelinfo", 0, NULL);
158 Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16);
164 Cvar_RegisterVariable(&r_mipskins);
165 Cvar_RegisterVariable(&r_mipnormalmaps);
166 Cvar_RegisterVariable(&mod_generatelightmaps_unitspersample);
167 Cvar_RegisterVariable(&mod_generatelightmaps_borderpixels);
168 Cvar_RegisterVariable(&mod_generatelightmaps_texturesize);
170 Cvar_RegisterVariable(&mod_generatelightmaps_lightmapsamples);
171 Cvar_RegisterVariable(&mod_generatelightmaps_vertexsamples);
172 Cvar_RegisterVariable(&mod_generatelightmaps_gridsamples);
173 Cvar_RegisterVariable(&mod_generatelightmaps_lightmapradius);
174 Cvar_RegisterVariable(&mod_generatelightmaps_vertexradius);
175 Cvar_RegisterVariable(&mod_generatelightmaps_gridradius);
177 Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models");
178 Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model");
179 Cmd_AddCommand ("modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes");
180 Cmd_AddCommand ("mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel");
183 void Mod_RenderInit(void)
185 R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL);
188 void Mod_UnloadModel (dp_model_t *mod)
190 char name[MAX_QPATH];
192 dp_model_t *parentmodel;
194 if (developer_loading.integer)
195 Con_Printf("unloading model %s\n", mod->name);
197 strlcpy(name, mod->name, sizeof(name));
198 parentmodel = mod->brush.parentmodel;
202 if (mod->surfmesh.data_element3i_indexbuffer && !mod->surfmesh.data_element3i_indexbuffer->isdynamic)
203 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
204 mod->surfmesh.data_element3i_indexbuffer = NULL;
205 if (mod->surfmesh.data_element3s_indexbuffer && !mod->surfmesh.data_element3s_indexbuffer->isdynamic)
206 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
207 mod->surfmesh.data_element3s_indexbuffer = NULL;
208 if (mod->surfmesh.data_vertex3f_vertexbuffer && !mod->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
209 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_vertex3f_vertexbuffer);
210 mod->surfmesh.data_vertex3f_vertexbuffer = NULL;
211 mod->surfmesh.data_svector3f_vertexbuffer = NULL;
212 mod->surfmesh.data_tvector3f_vertexbuffer = NULL;
213 mod->surfmesh.data_normal3f_vertexbuffer = NULL;
214 mod->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
215 mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
216 mod->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
217 mod->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
218 mod->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
220 // free textures/memory attached to the model
221 R_FreeTexturePool(&mod->texturepool);
222 Mem_FreePool(&mod->mempool);
223 // clear the struct to make it available
224 memset(mod, 0, sizeof(dp_model_t));
225 // restore the fields we want to preserve
226 strlcpy(mod->name, name, sizeof(mod->name));
227 mod->brush.parentmodel = parentmodel;
232 static void R_Model_Null_Draw(entity_render_t *ent)
238 typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
240 static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
255 // REQUIRED: fetch start
256 COM_ParseToken_Simple(&bufptr, true, false, true);
258 break; // end of file
259 if (!strcmp(com_token, "\n"))
260 continue; // empty line
261 start = atoi(com_token);
263 // REQUIRED: fetch length
264 COM_ParseToken_Simple(&bufptr, true, false, true);
265 if (!bufptr || !strcmp(com_token, "\n"))
267 Con_Printf("framegroups file: missing number of frames\n");
270 len = atoi(com_token);
272 // OPTIONAL args start
273 COM_ParseToken_Simple(&bufptr, true, false, true);
275 // OPTIONAL: fetch fps
277 if (bufptr && strcmp(com_token, "\n"))
279 fps = atof(com_token);
280 COM_ParseToken_Simple(&bufptr, true, false, true);
283 // OPTIONAL: fetch loopflag
285 if (bufptr && strcmp(com_token, "\n"))
287 loop = (atoi(com_token) != 0);
288 COM_ParseToken_Simple(&bufptr, true, false, true);
291 // OPTIONAL: fetch name
293 if (bufptr && strcmp(com_token, "\n"))
295 strlcpy(name, com_token, sizeof(name));
296 COM_ParseToken_Simple(&bufptr, true, false, true);
299 // OPTIONAL: remaining unsupported tokens (eat them)
300 while (bufptr && strcmp(com_token, "\n"))
301 COM_ParseToken_Simple(&bufptr, true, false, true);
303 //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name);
306 cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
313 static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass)
315 dp_model_t *mod = (dp_model_t *) pass;
316 animscene_t *anim = &mod->animscenes[i];
318 strlcpy(anim->name, name, sizeof(anim[i].name));
320 dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
321 anim->firstframe = bound(0, start, mod->num_poses - 1);
322 anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
323 anim->framerate = max(1, fps);
325 //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
328 static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
333 cnt = Mod_FrameGroupify_ParseGroups(buf, NULL, NULL);
336 Con_Printf("no scene found in framegroups file, aborting\n");
339 mod->numframes = cnt;
342 // (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay)
343 mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes);
346 Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
349 static void Mod_FindPotentialDeforms(dp_model_t *mod)
353 mod->wantnormals = false;
354 mod->wanttangents = false;
355 for (i = 0;i < mod->num_textures;i++)
357 texture = mod->data_textures + i;
358 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
359 mod->wantnormals = true;
360 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
361 mod->wantnormals = true;
362 for (j = 0;j < Q3MAXDEFORMS;j++)
364 if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
366 mod->wanttangents = true;
367 mod->wantnormals = true;
370 if (texture->deforms[j].deform != Q3DEFORM_NONE)
371 mod->wantnormals = true;
383 dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
388 fs_offset_t filesize = 0;
393 if (mod->name[0] == '*') // submodel
396 if (!strcmp(mod->name, "null"))
401 if (mod->loaded || mod->mempool)
402 Mod_UnloadModel(mod);
404 if (developer_loading.integer)
405 Con_Printf("loading model %s\n", mod->name);
408 mod->crc = (unsigned int)-1;
411 VectorClear(mod->normalmins);
412 VectorClear(mod->normalmaxs);
413 VectorClear(mod->yawmins);
414 VectorClear(mod->yawmaxs);
415 VectorClear(mod->rotatedmins);
416 VectorClear(mod->rotatedmaxs);
418 mod->modeldatatypestring = "null";
419 mod->type = mod_null;
420 mod->Draw = R_Model_Null_Draw;
424 // no fatal errors occurred, so this model is ready to use.
433 // even if the model is loaded it still may need reloading...
435 // if it is not loaded or checkdisk is true we need to calculate the crc
436 if (!mod->loaded || checkdisk)
438 if (checkdisk && mod->loaded)
439 Con_DPrintf("checking model %s\n", mod->name);
440 buf = FS_LoadFile (mod->name, tempmempool, false, &filesize);
443 crc = CRC_Block((unsigned char *)buf, filesize);
444 // we need to reload the model if the crc does not match
450 // if the model is already loaded and checks passed, just return
458 if (developer_loading.integer)
459 Con_Printf("loading model %s\n", mod->name);
461 SCR_PushLoadingScreen(true, mod->name, 1);
463 // LordHavoc: unload the existing model in this slot (if there is one)
464 if (mod->loaded || mod->mempool)
465 Mod_UnloadModel(mod);
470 // errors can prevent the corresponding mod->loaded = true;
473 // default lightmap scale
474 mod->lightmapscale = 1;
476 // default model radius and bounding box (mainly for missing models)
478 VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius);
479 VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius);
480 VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius);
481 VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius);
482 VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
483 VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
487 // load q3 shaders for the first time, or after a level change
493 char *bufend = (char *)buf + filesize;
495 // all models use memory, so allocate a memory pool
496 mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
498 num = LittleLong(*((int *)buf));
499 // call the apropriate loader
501 if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
502 else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
503 else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
504 else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
505 else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend);
506 else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend);
507 else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend);
508 else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
509 else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
510 else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
511 else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
512 else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
513 else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
514 else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
517 Mod_FindPotentialDeforms(mod);
519 buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
522 Mod_FrameGroupify(mod, (const char *)buf);
530 // LordHavoc: Sys_Error was *ANNOYING*
531 Con_Printf ("Mod_LoadModel: %s not found\n", mod->name);
534 // no fatal errors occurred, so this model is ready to use.
537 SCR_PopLoadingScreen(false);
542 void Mod_ClearUsed(void)
545 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
547 for (i = 0;i < nummodels;i++)
548 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
552 void Mod_PurgeUnused(void)
555 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
557 for (i = 0;i < nummodels;i++)
559 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
561 Mod_UnloadModel(mod);
562 Mem_ExpandableArray_FreeRecord(&models, mod);
573 dp_model_t *Mod_FindName(const char *name, const char *parentname)
582 // if we're not dedicatd, the renderer calls will crash without video
585 nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
588 Host_Error ("Mod_ForName: empty name");
590 // search the currently loaded models
591 for (i = 0;i < nummodels;i++)
593 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))))
600 // no match found, create a new one
601 mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models);
602 strlcpy(mod->name, name, sizeof(mod->name));
604 mod->brush.parentmodel = Mod_FindName(parentname, NULL);
606 mod->brush.parentmodel = NULL;
616 Loads in a model for the given name
619 dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname)
622 model = Mod_FindName(name, parentname);
623 if (!model->loaded || checkdisk)
624 Mod_LoadModel(model, crash, checkdisk);
632 Reloads all models if they have changed
635 void Mod_Reload(void)
638 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
641 SCR_PushLoadingScreen(false, "Reloading models", 1.0);
643 for (i = 0;i < nummodels;i++)
644 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
646 for (i = 0;i < nummodels;i++)
647 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
649 SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
650 Mod_LoadModel(mod, true, true);
651 SCR_PopLoadingScreen(false);
653 SCR_PopLoadingScreen(false);
656 unsigned char *mod_base;
659 //=============================================================================
666 static void Mod_Print(void)
669 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
672 Con_Print("Loaded models:\n");
673 for (i = 0;i < nummodels;i++)
675 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
677 if (mod->brush.numsubmodels)
678 Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
680 Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name);
690 static void Mod_Precache(void)
693 Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL);
695 Con_Print("usage: modelprecache <filename>\n");
698 int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
702 used = (unsigned char *)Mem_Alloc(tempmempool, numvertices);
703 memset(used, 0, numvertices);
704 for (i = 0;i < numelements;i++)
705 used[elements[i]] = 1;
706 for (i = 0, count = 0;i < numvertices;i++)
707 remapvertices[i] = used[i] ? count++ : -1;
712 qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
714 int first = firstvertex, last = first + numvertices - 1, numelements = numtriangles * 3;
716 int invalidintcount = 0, invalidintexample = 0;
717 int invalidshortcount = 0, invalidshortexample = 0;
718 int invalidmismatchcount = 0, invalidmismatchexample = 0;
721 for (i = 0; i < numelements; i++)
723 if (element3i[i] < first || element3i[i] > last)
726 invalidintexample = i;
732 for (i = 0; i < numelements; i++)
734 if (element3s[i] < first || element3s[i] > last)
737 invalidintexample = i;
741 if (element3i && element3s)
743 for (i = 0; i < numelements; i++)
745 if (element3s[i] != element3i[i])
747 invalidmismatchcount++;
748 invalidmismatchexample = i;
752 if (invalidintcount || invalidshortcount || invalidmismatchcount)
754 Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, element3i, element3s, filename, fileline);
755 Con_Printf(", %i elements are invalid in element3i (example: element3i[%i] == %i)", invalidintcount, invalidintexample, element3i ? element3i[invalidintexample] : 0);
756 Con_Printf(", %i elements are invalid in element3s (example: element3s[%i] == %i)", invalidshortcount, invalidshortexample, element3s ? element3s[invalidshortexample] : 0);
757 Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[%i] is %i)", invalidmismatchcount, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0);
758 Con_Print(". Please debug the engine code - these elements have been modified to not crash, but nothing more.\n");
760 // edit the elements to make them safer, as the driver will crash otherwise
762 for (i = 0; i < numelements; i++)
763 if (element3i[i] < first || element3i[i] > last)
764 element3i[i] = first;
766 for (i = 0; i < numelements; i++)
767 if (element3s[i] < first || element3s[i] > last)
768 element3s[i] = first;
769 if (element3i && element3s)
770 for (i = 0; i < numelements; i++)
771 if (element3s[i] != element3i[i])
772 element3s[i] = element3i[i];
779 // warning: this is an expensive function!
780 void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting)
787 memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
788 // process each vertex of each triangle and accumulate the results
789 // use area-averaging, to make triangles with a big area have a bigger
790 // weighting on the vertex normal than triangles with a small area
791 // to do so, just add the 'normals' together (the bigger the area
792 // the greater the length of the normal is
794 for (i = 0; i < numtriangles; i++, element += 3)
797 vertex3f + element[0] * 3,
798 vertex3f + element[1] * 3,
799 vertex3f + element[2] * 3,
804 VectorNormalize(areaNormal);
806 for (j = 0;j < 3;j++)
808 vectorNormal = normal3f + element[j] * 3;
809 vectorNormal[0] += areaNormal[0];
810 vectorNormal[1] += areaNormal[1];
811 vectorNormal[2] += areaNormal[2];
814 // and just normalize the accumulated vertex normal in the end
815 vectorNormal = normal3f + 3 * firstvertex;
816 for (i = 0; i < numvertices; i++, vectorNormal += 3)
817 VectorNormalize(vectorNormal);
821 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)
823 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
824 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
825 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
827 // 6 multiply, 9 subtract
828 VectorSubtract(v1, v0, v10);
829 VectorSubtract(v2, v0, v20);
830 normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1];
831 normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2];
832 normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0];
833 // 12 multiply, 10 subtract
834 tc10[1] = tc1[1] - tc0[1];
835 tc20[1] = tc2[1] - tc0[1];
836 svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
837 svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
838 svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
839 tc10[0] = tc1[0] - tc0[0];
840 tc20[0] = tc2[0] - tc0[0];
841 tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
842 tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
843 tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
844 // 12 multiply, 4 add, 6 subtract
845 f = DotProduct(svector3f, normal3f);
846 svector3f[0] -= f * normal3f[0];
847 svector3f[1] -= f * normal3f[1];
848 svector3f[2] -= f * normal3f[2];
849 f = DotProduct(tvector3f, normal3f);
850 tvector3f[0] -= f * normal3f[0];
851 tvector3f[1] -= f * normal3f[1];
852 tvector3f[2] -= f * normal3f[2];
853 // if texture is mapped the wrong way (counterclockwise), the tangents
854 // have to be flipped, this is detected by calculating a normal from the
855 // two tangents, and seeing if it is opposite the surface normal
856 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
857 CrossProduct(tvector3f, svector3f, tangentcross);
858 if (DotProduct(tangentcross, normal3f) < 0)
860 VectorNegate(svector3f, svector3f);
861 VectorNegate(tvector3f, tvector3f);
866 // warning: this is a very expensive function!
867 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)
870 float sdir[3], tdir[3], normal[3], *svec, *tvec;
871 const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
872 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
875 memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
876 memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
877 // process each vertex of each triangle and accumulate the results
878 for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
880 v0 = vertex3f + e[0] * 3;
881 v1 = vertex3f + e[1] * 3;
882 v2 = vertex3f + e[2] * 3;
883 tc0 = texcoord2f + e[0] * 2;
884 tc1 = texcoord2f + e[1] * 2;
885 tc2 = texcoord2f + e[2] * 2;
887 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
888 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
890 // calculate the edge directions and surface normal
891 // 6 multiply, 9 subtract
892 VectorSubtract(v1, v0, v10);
893 VectorSubtract(v2, v0, v20);
894 normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
895 normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
896 normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
898 // calculate the tangents
899 // 12 multiply, 10 subtract
900 tc10[1] = tc1[1] - tc0[1];
901 tc20[1] = tc2[1] - tc0[1];
902 sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
903 sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
904 sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
905 tc10[0] = tc1[0] - tc0[0];
906 tc20[0] = tc2[0] - tc0[0];
907 tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
908 tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
909 tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
911 // if texture is mapped the wrong way (counterclockwise), the tangents
912 // have to be flipped, this is detected by calculating a normal from the
913 // two tangents, and seeing if it is opposite the surface normal
914 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
915 CrossProduct(tdir, sdir, tangentcross);
916 if (DotProduct(tangentcross, normal) < 0)
918 VectorNegate(sdir, sdir);
919 VectorNegate(tdir, tdir);
924 VectorNormalize(sdir);
925 VectorNormalize(tdir);
927 for (i = 0;i < 3;i++)
929 VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
930 VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
933 // make the tangents completely perpendicular to the surface normal, and
934 // then normalize them
935 // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
936 for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
938 f = -DotProduct(svec, n);
939 VectorMA(svec, f, n, svec);
940 VectorNormalize(svec);
941 f = -DotProduct(tvec, n);
942 VectorMA(tvec, f, n, tvec);
943 VectorNormalize(tvec);
947 void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors)
950 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 * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0));
951 loadmodel->surfmesh.num_vertices = numvertices;
952 loadmodel->surfmesh.num_triangles = numtriangles;
953 if (loadmodel->surfmesh.num_vertices)
955 loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
956 loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
957 loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
958 loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
959 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
960 loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
962 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices;
964 loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices;
966 if (loadmodel->surfmesh.num_triangles)
968 loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
969 if (loadmodel->surfmesh.num_vertices <= 65536)
970 loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles;
974 shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles)
976 shadowmesh_t *newmesh;
977 newmesh = (shadowmesh_t *)Mem_Alloc(mempool, sizeof(shadowmesh_t));
978 newmesh->mempool = mempool;
979 newmesh->maxverts = maxverts;
980 newmesh->maxtriangles = maxtriangles;
981 newmesh->numverts = 0;
982 newmesh->numtriangles = 0;
983 memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
984 memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
986 newmesh->vertex3f = (float *)Mem_Alloc(mempool, maxverts * sizeof(float[3]));
987 newmesh->element3i = (int *)Mem_Alloc(mempool, maxtriangles * sizeof(int[3]));
988 newmesh->vertexhashtable = (shadowmeshvertexhash_t **)Mem_Alloc(mempool, SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *));
989 newmesh->vertexhashentries = (shadowmeshvertexhash_t *)Mem_Alloc(mempool, maxverts * sizeof(shadowmeshvertexhash_t));
993 int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, const float *vertex3f)
996 shadowmeshvertexhash_t *hash;
997 // this uses prime numbers intentionally
998 hashindex = (unsigned int) (vertex3f[0] * 2003 + vertex3f[1] * 4001 + vertex3f[2] * 7919) % SHADOWMESHVERTEXHASH;
999 for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
1001 vnum = (hash - mesh->vertexhashentries);
1002 if (mesh->vertex3f[vnum * 3 + 0] == vertex3f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex3f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex3f[2])
1003 return hash - mesh->vertexhashentries;
1005 vnum = mesh->numverts++;
1006 hash = mesh->vertexhashentries + vnum;
1007 hash->next = mesh->vertexhashtable[hashindex];
1008 mesh->vertexhashtable[hashindex] = hash;
1009 mesh->vertex3f[vnum * 3 + 0] = vertex3f[0];
1010 mesh->vertex3f[vnum * 3 + 1] = vertex3f[1];
1011 mesh->vertex3f[vnum * 3 + 2] = vertex3f[2];
1015 void Mod_ShadowMesh_AddMesh(shadowmesh_t *mesh, const float *vertex3f, int numtris, const int *element3i)
1019 for (i = 0;i < numtris;i++)
1021 mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 0]);
1022 mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 1]);
1023 mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 2]);
1024 mesh->numtriangles++;
1027 // the triangle calculation can take a while, so let's do a keepalive here
1028 CL_KeepaliveMessage(false);
1031 shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles)
1033 // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
1034 CL_KeepaliveMessage(false);
1036 return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles);
1039 static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
1041 if (!mesh->numverts)
1044 // make sure we don't crash inside the driver if something went wrong, as it's annoying to debug
1045 Mod_ValidateElements(mesh->element3i, mesh->element3s, mesh->numtriangles, 0, mesh->numverts, __FILE__, __LINE__);
1047 // upload short indices as a buffer
1048 if (mesh->element3s && !mesh->element3s_indexbuffer)
1049 mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), "shadowmesh", true, false, false, true);
1051 // upload int indices as a buffer
1052 if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
1053 mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), "shadowmesh", true, false, false, false);
1055 // vertex buffer is several arrays and we put them in the same buffer
1057 // is this wise? the texcoordtexture2f array is used with dynamic
1058 // vertex/svector/tvector/normal when rendering animated models, on the
1059 // other hand animated models don't use a lot of vertices anyway...
1060 if (!mesh->vbo_vertexbuffer)
1062 mesh->vbooffset_vertex3f = 0;
1063 mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mesh->vertex3f, mesh->numverts * sizeof(float[3]), "shadowmesh", false, false, false, false);
1067 shadowmesh_t *Mod_ShadowMesh_Finish(shadowmesh_t *mesh, qboolean createvbo)
1069 if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
1071 if (mesh->vertexhashentries)
1072 Mem_Free(mesh->vertexhashentries);
1073 mesh->vertexhashentries = NULL;
1074 if (mesh->vertexhashtable)
1075 Mem_Free(mesh->vertexhashtable);
1076 mesh->vertexhashtable = NULL;
1077 if (mesh->maxverts > mesh->numverts)
1079 mesh->vertex3f = (float *)Mem_Realloc(mesh->mempool, mesh->vertex3f, mesh->numverts * sizeof(float[3]));
1080 mesh->maxverts = mesh->numverts;
1082 if (mesh->maxtriangles > mesh->numtriangles)
1084 mesh->element3i = (int *)Mem_Realloc(mesh->mempool, mesh->element3i, mesh->numtriangles * sizeof(int[3]));
1085 mesh->maxtriangles = mesh->numtriangles;
1087 if (mesh->numverts <= 65536)
1090 mesh->element3s = (unsigned short *)Mem_Alloc(mesh->mempool, mesh->numtriangles * sizeof(unsigned short[3]));
1091 for (i = 0;i < mesh->numtriangles*3;i++)
1092 mesh->element3s[i] = mesh->element3i[i];
1095 Mod_ShadowMesh_CreateVBOs(mesh);
1098 // this can take a while, so let's do a keepalive here
1099 CL_KeepaliveMessage(false);
1104 void Mod_ShadowMesh_CalcBBox(shadowmesh_t *mesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
1107 vec3_t nmins, nmaxs, ncenter, temp;
1108 float nradius2, dist2, *v;
1112 VectorCopy(mesh->vertex3f, nmins);
1113 VectorCopy(mesh->vertex3f, nmaxs);
1114 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1116 if (nmins[0] > v[0]) { nmins[0] = v[0]; } if (nmaxs[0] < v[0]) { nmaxs[0] = v[0]; }
1117 if (nmins[1] > v[1]) { nmins[1] = v[1]; } if (nmaxs[1] < v[1]) { nmaxs[1] = v[1]; }
1118 if (nmins[2] > v[2]) { nmins[2] = v[2]; } if (nmaxs[2] < v[2]) { nmaxs[2] = v[2]; }
1120 // calculate center and radius
1121 ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
1122 ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
1123 ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
1125 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1127 VectorSubtract(v, ncenter, temp);
1128 dist2 = DotProduct(temp, temp);
1129 if (nradius2 < dist2)
1134 VectorCopy(nmins, mins);
1136 VectorCopy(nmaxs, maxs);
1138 VectorCopy(ncenter, center);
1140 *radius = sqrt(nradius2);
1143 void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
1145 if (mesh->element3i_indexbuffer)
1146 R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
1147 if (mesh->element3s_indexbuffer)
1148 R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
1149 if (mesh->vbo_vertexbuffer)
1150 R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
1152 Mem_Free(mesh->vertex3f);
1153 if (mesh->element3i)
1154 Mem_Free(mesh->element3i);
1155 if (mesh->element3s)
1156 Mem_Free(mesh->element3s);
1157 if (mesh->vertexhashentries)
1158 Mem_Free(mesh->vertexhashentries);
1159 if (mesh->vertexhashtable)
1160 Mem_Free(mesh->vertexhashtable);
1164 void Mod_CreateCollisionMesh(dp_model_t *mod)
1166 int k, numcollisionmeshtriangles;
1167 qboolean usesinglecollisionmesh = false;
1168 const msurface_t *surface = NULL;
1170 mempool_t *mempool = mod->mempool;
1171 if (!mempool && mod->brush.parentmodel)
1172 mempool = mod->brush.parentmodel->mempool;
1173 // make a single combined collision mesh for physics engine use
1174 // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
1175 numcollisionmeshtriangles = 0;
1176 for (k = 0;k < mod->nummodelsurfaces;k++)
1178 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1179 if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
1181 usesinglecollisionmesh = true;
1182 numcollisionmeshtriangles = surface->num_triangles;
1185 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1187 numcollisionmeshtriangles += surface->num_triangles;
1189 mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles);
1190 if (usesinglecollisionmesh)
1191 Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1194 for (k = 0;k < mod->nummodelsurfaces;k++)
1196 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1197 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1199 Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1202 mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mod->brush.collisionmesh, false);
1206 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)
1211 if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1212 v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1215 Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1216 Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1217 texcoord2f[0] = tc[0];
1218 texcoord2f[1] = tc[1];
1221 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)
1223 float vup[3], vdown[3], vleft[3], vright[3];
1224 float tcup[3], tcdown[3], tcleft[3], tcright[3];
1225 float sv[3], tv[3], nl[3];
1226 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1227 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1228 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1229 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1230 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1231 Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1232 Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1233 VectorAdd(svector3f, sv, svector3f);
1234 VectorAdd(tvector3f, tv, tvector3f);
1235 VectorAdd(normal3f, nl, normal3f);
1236 Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1237 VectorAdd(svector3f, sv, svector3f);
1238 VectorAdd(tvector3f, tv, tvector3f);
1239 VectorAdd(normal3f, nl, normal3f);
1240 Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1241 VectorAdd(svector3f, sv, svector3f);
1242 VectorAdd(tvector3f, tv, tvector3f);
1243 VectorAdd(normal3f, nl, normal3f);
1246 static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1248 int x, y, ix, iy, *e;
1250 for (y = 0;y < height;y++)
1252 for (x = 0;x < width;x++)
1254 e[0] = (y + 1) * (width + 1) + (x + 0);
1255 e[1] = (y + 0) * (width + 1) + (x + 0);
1256 e[2] = (y + 1) * (width + 1) + (x + 1);
1257 e[3] = (y + 0) * (width + 1) + (x + 0);
1258 e[4] = (y + 0) * (width + 1) + (x + 1);
1259 e[5] = (y + 1) * (width + 1) + (x + 1);
1263 for (y = 0, iy = y1;y < height + 1;y++, iy++)
1264 for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1265 Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1270 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
1274 float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1275 float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1276 float viewvector[3];
1277 unsigned int firstvertex;
1280 if (chunkwidth < 2 || chunkheight < 2)
1282 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]);
1283 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]);
1284 viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1285 viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1286 viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1287 if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1289 // too close for this stepsize, emit as 4 chunks instead
1291 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1292 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1293 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1294 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1297 // emit the geometry at stepsize into our vertex buffer / index buffer
1298 // we add two columns and two rows for skirt
1299 outwidth = chunkwidth+2;
1300 outheight = chunkheight+2;
1301 outwidth2 = outwidth-1;
1302 outheight2 = outheight-1;
1303 outwidth3 = outwidth+1;
1304 outheight3 = outheight+1;
1305 firstvertex = numvertices;
1306 e = model->terrain.element3i + numtriangles;
1307 numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1308 v = model->terrain.vertex3f + numvertices;
1309 numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1310 // emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1311 for (ty = 0;ty < outheight;ty++)
1313 for (tx = 0;tx < outwidth;tx++)
1315 *e++ = firstvertex + (ty )*outwidth3+(tx );
1316 *e++ = firstvertex + (ty )*outwidth3+(tx+1);
1317 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1318 *e++ = firstvertex + (ty )*outwidth3+(tx );
1319 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1320 *e++ = firstvertex + (ty+1)*outwidth3+(tx );
1323 // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1324 for (ty = 0;ty <= outheight;ty++)
1326 skirtrow = ty == 0 || ty == outheight;
1327 ry = y+bound(1, ty, outheight)*stepsize;
1328 for (tx = 0;tx <= outwidth;tx++)
1330 skirt = skirtrow || tx == 0 || tx == outwidth;
1331 rx = x+bound(1, tx, outwidth)*stepsize;
1334 v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1338 // TODO: emit skirt vertices
1341 void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
1343 for (y = 0;y < model->terrain.size[1];y += model->terrain.
1344 Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1345 Mod_Terrain_BuildChunk(model,
1349 static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
1352 if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1354 offset = bound(0, s[4] - '0', 9);
1355 offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
1360 if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN;
1361 if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE;
1362 if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE;
1363 if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH;
1364 if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1365 if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE;
1366 if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE;
1367 Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1368 return offset | Q3WAVEFUNC_NONE;
1371 void Mod_FreeQ3Shaders(void)
1373 Mem_FreePool(&q3shaders_mem);
1376 static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
1378 unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1379 q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
1380 q3shader_hash_entry_t* lastEntry = NULL;
1383 if (strcasecmp (entry->shader.name, shader->name) == 0)
1386 if(shader->dpshaderkill)
1388 // killed shader is a redeclarion? we can safely ignore it
1391 else if(entry->shader.dpshaderkill)
1393 // replace the old shader!
1394 // this will skip the entry allocating part
1395 // below and just replace the shader
1400 unsigned char *start, *end, *start2;
1401 start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1402 end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1403 start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1404 if(memcmp(start, start2, end - start))
1405 Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1407 Con_DPrintf("Shader '%s' already defined\n", shader->name);
1412 entry = entry->chain;
1414 while (entry != NULL);
1417 if (lastEntry->shader.name[0] != 0)
1420 q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*)
1421 Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries);
1423 while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1424 lastEntry->chain = newEntry;
1425 newEntry->chain = NULL;
1426 lastEntry = newEntry;
1428 /* else: head of chain, in hash entry array */
1431 memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
1434 extern cvar_t mod_noshader_default_offsetmapping;
1435 extern cvar_t mod_q3shader_default_offsetmapping;
1436 extern cvar_t mod_q3shader_default_offsetmapping_scale;
1437 extern cvar_t mod_q3shader_default_offsetmapping_bias;
1438 extern cvar_t mod_q3shader_default_polygonoffset;
1439 extern cvar_t mod_q3shader_default_polygonfactor;
1440 extern cvar_t mod_q3shader_force_addalpha;
1441 extern cvar_t mod_q3shader_force_terrain_alphaflag;
1442 void Mod_LoadQ3Shaders(void)
1449 q3shaderinfo_t shader;
1450 q3shaderinfo_layer_t *layer;
1452 char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1453 char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1454 unsigned long custsurfaceflags[256];
1455 int numcustsurfaceflags;
1456 qboolean dpshaderkill;
1458 Mod_FreeQ3Shaders();
1460 q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1461 q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem,
1462 sizeof (q3shader_data_t));
1463 Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries,
1464 q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1465 Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs,
1466 q3shaders_mem, sizeof (char**), 256);
1468 // parse custinfoparms.txt
1469 numcustsurfaceflags = 0;
1470 if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1472 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1473 Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1476 while (COM_ParseToken_QuakeC(&text, false))
1477 if (!strcasecmp(com_token, "}"))
1479 // custom surfaceflags section
1480 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1481 Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1484 while(COM_ParseToken_QuakeC(&text, false))
1486 if (!strcasecmp(com_token, "}"))
1488 // register surfaceflag
1489 if (numcustsurfaceflags >= 256)
1491 Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1495 j = (int)strlen(com_token)+1;
1496 custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1497 strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1499 if (COM_ParseToken_QuakeC(&text, false))
1500 custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1502 custsurfaceflags[numcustsurfaceflags] = 0;
1503 numcustsurfaceflags++;
1511 search = FS_Search("scripts/*.shader", true, false);
1514 for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1516 text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1519 while (COM_ParseToken_QuakeC(&text, false))
1521 memset (&shader, 0, sizeof(shader));
1523 shader.surfaceparms = 0;
1524 shader.surfaceflags = 0;
1525 shader.textureflags = 0;
1526 shader.numlayers = 0;
1527 shader.lighting = false;
1528 shader.vertexalpha = false;
1529 shader.textureblendalpha = false;
1530 shader.skyboxname[0] = 0;
1531 shader.deforms[0].deform = Q3DEFORM_NONE;
1532 shader.dpnortlight = false;
1533 shader.dpshadow = false;
1534 shader.dpnoshadow = false;
1535 shader.dpmeshcollisions = false;
1536 shader.dpshaderkill = false;
1537 shader.dpreflectcube[0] = 0;
1538 shader.reflectmin = 0;
1539 shader.reflectmax = 1;
1540 shader.refractfactor = 1;
1541 Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1542 shader.reflectfactor = 1;
1543 Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1544 shader.r_water_wateralpha = 1;
1545 shader.r_water_waterscroll[0] = 0;
1546 shader.r_water_waterscroll[1] = 0;
1547 shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
1548 shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
1549 shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
1550 shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
1551 shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
1552 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
1553 shader.specularscalemod = 1;
1554 shader.specularpowermod = 1;
1555 shader.rtlightambient = 0;
1556 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1557 // JUST GREP FOR "specularscalemod = 1".
1559 strlcpy(shader.name, com_token, sizeof(shader.name));
1560 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1562 Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1565 while (COM_ParseToken_QuakeC(&text, false))
1567 if (!strcasecmp(com_token, "}"))
1569 if (!strcasecmp(com_token, "{"))
1571 static q3shaderinfo_layer_t dummy;
1572 if (shader.numlayers < Q3SHADER_MAXLAYERS)
1574 layer = shader.layers + shader.numlayers++;
1578 // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1579 memset(&dummy, 0, sizeof(dummy));
1582 layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1583 layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1584 layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1585 layer->blendfunc[0] = GL_ONE;
1586 layer->blendfunc[1] = GL_ZERO;
1587 while (COM_ParseToken_QuakeC(&text, false))
1589 if (!strcasecmp(com_token, "}"))
1591 if (!strcasecmp(com_token, "\n"))
1594 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1596 if (j < TEXTURE_MAXFRAMES + 4)
1598 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1599 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1600 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1602 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1603 numparameters = j + 1;
1605 if (!COM_ParseToken_QuakeC(&text, true))
1608 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1609 // parameter[j][0] = 0;
1610 if (developer_insane.integer)
1612 Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1613 for (j = 0;j < numparameters;j++)
1614 Con_DPrintf(" %s", parameter[j]);
1617 if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1619 if (numparameters == 2)
1621 if (!strcasecmp(parameter[1], "add"))
1623 layer->blendfunc[0] = GL_ONE;
1624 layer->blendfunc[1] = GL_ONE;
1626 else if (!strcasecmp(parameter[1], "addalpha"))
1628 layer->blendfunc[0] = GL_SRC_ALPHA;
1629 layer->blendfunc[1] = GL_ONE;
1631 else if (!strcasecmp(parameter[1], "filter"))
1633 layer->blendfunc[0] = GL_DST_COLOR;
1634 layer->blendfunc[1] = GL_ZERO;
1636 else if (!strcasecmp(parameter[1], "blend"))
1638 layer->blendfunc[0] = GL_SRC_ALPHA;
1639 layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1642 else if (numparameters == 3)
1645 for (k = 0;k < 2;k++)
1647 if (!strcasecmp(parameter[k+1], "GL_ONE"))
1648 layer->blendfunc[k] = GL_ONE;
1649 else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1650 layer->blendfunc[k] = GL_ZERO;
1651 else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1652 layer->blendfunc[k] = GL_SRC_COLOR;
1653 else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1654 layer->blendfunc[k] = GL_SRC_ALPHA;
1655 else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1656 layer->blendfunc[k] = GL_DST_COLOR;
1657 else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1658 layer->blendfunc[k] = GL_DST_ALPHA;
1659 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1660 layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1661 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1662 layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1663 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1664 layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1665 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1666 layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1668 layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1672 if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1673 layer->alphatest = true;
1674 if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1676 if (!strcasecmp(parameter[0], "clampmap"))
1677 layer->clampmap = true;
1678 layer->numframes = 1;
1679 layer->framerate = 1;
1680 layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1681 &q3shader_data->char_ptrs);
1682 layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1683 if (!strcasecmp(parameter[1], "$lightmap"))
1684 shader.lighting = true;
1686 else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1689 layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1690 layer->framerate = atof(parameter[1]);
1691 layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1692 for (i = 0;i < layer->numframes;i++)
1693 layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1695 else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1698 for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1699 layer->rgbgen.parms[i] = atof(parameter[i+2]);
1700 if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1701 else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1702 else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1703 else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1704 else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1705 else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1706 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1707 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1708 else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1709 else if (!strcasecmp(parameter[1], "wave"))
1711 layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1712 layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1713 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1714 layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1716 else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1718 else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1721 for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1722 layer->alphagen.parms[i] = atof(parameter[i+2]);
1723 if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1724 else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1725 else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1726 else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1727 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1728 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1729 else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1730 else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1731 else if (!strcasecmp(parameter[1], "wave"))
1733 layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1734 layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1735 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1736 layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1738 else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1740 else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1743 // observed values: tcgen environment
1744 // no other values have been observed in real shaders
1745 for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1746 layer->tcgen.parms[i] = atof(parameter[i+2]);
1747 if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1748 else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1749 else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1750 else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1751 else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1752 else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1754 else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1761 // tcmod stretch sin # # # #
1762 // tcmod stretch triangle # # # #
1763 // tcmod transform # # # # # #
1764 // tcmod turb # # # #
1765 // tcmod turb sin # # # # (this is bogus)
1766 // no other values have been observed in real shaders
1767 for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1768 if (!layer->tcmods[tcmodindex].tcmod)
1770 if (tcmodindex < Q3MAXTCMODS)
1772 for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1773 layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1774 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1775 else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1776 else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1777 else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1778 else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1779 else if (!strcasecmp(parameter[1], "stretch"))
1781 layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1782 layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1783 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1784 layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1786 else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1787 else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1788 else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1791 Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1793 // break out a level if it was a closing brace (not using the character here to not confuse vim)
1794 if (!strcasecmp(com_token, "}"))
1797 if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
1798 shader.lighting = true;
1799 if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
1801 if (layer == shader.layers + 0)
1803 // vertex controlled transparency
1804 shader.vertexalpha = true;
1808 // multilayer terrain shader or similar
1809 shader.textureblendalpha = true;
1810 if (mod_q3shader_force_terrain_alphaflag.integer)
1811 shader.layers[0].dptexflags |= TEXF_ALPHA;
1815 if(mod_q3shader_force_addalpha.integer)
1817 // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
1818 // this cvar brings back this behaviour
1819 if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
1820 layer->blendfunc[0] = GL_SRC_ALPHA;
1823 layer->dptexflags = 0;
1824 if (layer->alphatest)
1825 layer->dptexflags |= TEXF_ALPHA;
1826 switch(layer->blendfunc[0])
1829 case GL_ONE_MINUS_SRC_ALPHA:
1830 layer->dptexflags |= TEXF_ALPHA;
1833 switch(layer->blendfunc[1])
1836 case GL_ONE_MINUS_SRC_ALPHA:
1837 layer->dptexflags |= TEXF_ALPHA;
1840 if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
1841 layer->dptexflags |= TEXF_MIPMAP;
1842 if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
1843 layer->dptexflags |= TEXF_PICMIP | TEXF_COMPRESS;
1844 if (layer->clampmap)
1845 layer->dptexflags |= TEXF_CLAMP;
1849 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1851 if (j < TEXTURE_MAXFRAMES + 4)
1853 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1854 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1855 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1857 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1858 numparameters = j + 1;
1860 if (!COM_ParseToken_QuakeC(&text, true))
1863 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1864 // parameter[j][0] = 0;
1865 if (fileindex == 0 && !strcasecmp(com_token, "}"))
1867 if (developer_insane.integer)
1869 Con_DPrintf("%s: ", shader.name);
1870 for (j = 0;j < numparameters;j++)
1871 Con_DPrintf(" %s", parameter[j]);
1874 if (numparameters < 1)
1876 if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
1878 if (!strcasecmp(parameter[1], "alphashadow"))
1879 shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
1880 else if (!strcasecmp(parameter[1], "areaportal"))
1881 shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
1882 else if (!strcasecmp(parameter[1], "botclip"))
1883 shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP;
1884 else if (!strcasecmp(parameter[1], "clusterportal"))
1885 shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
1886 else if (!strcasecmp(parameter[1], "detail"))
1887 shader.surfaceparms |= Q3SURFACEPARM_DETAIL;
1888 else if (!strcasecmp(parameter[1], "donotenter"))
1889 shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER;
1890 else if (!strcasecmp(parameter[1], "dust"))
1891 shader.surfaceparms |= Q3SURFACEPARM_DUST;
1892 else if (!strcasecmp(parameter[1], "hint"))
1893 shader.surfaceparms |= Q3SURFACEPARM_HINT;
1894 else if (!strcasecmp(parameter[1], "fog"))
1895 shader.surfaceparms |= Q3SURFACEPARM_FOG;
1896 else if (!strcasecmp(parameter[1], "lava"))
1897 shader.surfaceparms |= Q3SURFACEPARM_LAVA;
1898 else if (!strcasecmp(parameter[1], "lightfilter"))
1899 shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
1900 else if (!strcasecmp(parameter[1], "lightgrid"))
1901 shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
1902 else if (!strcasecmp(parameter[1], "metalsteps"))
1903 shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS;
1904 else if (!strcasecmp(parameter[1], "nodamage"))
1905 shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE;
1906 else if (!strcasecmp(parameter[1], "nodlight"))
1907 shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT;
1908 else if (!strcasecmp(parameter[1], "nodraw"))
1909 shader.surfaceparms |= Q3SURFACEPARM_NODRAW;
1910 else if (!strcasecmp(parameter[1], "nodrop"))
1911 shader.surfaceparms |= Q3SURFACEPARM_NODROP;
1912 else if (!strcasecmp(parameter[1], "noimpact"))
1913 shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT;
1914 else if (!strcasecmp(parameter[1], "nolightmap"))
1915 shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
1916 else if (!strcasecmp(parameter[1], "nomarks"))
1917 shader.surfaceparms |= Q3SURFACEPARM_NOMARKS;
1918 else if (!strcasecmp(parameter[1], "nomipmaps"))
1919 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
1920 else if (!strcasecmp(parameter[1], "nonsolid"))
1921 shader.surfaceparms |= Q3SURFACEPARM_NONSOLID;
1922 else if (!strcasecmp(parameter[1], "origin"))
1923 shader.surfaceparms |= Q3SURFACEPARM_ORIGIN;
1924 else if (!strcasecmp(parameter[1], "playerclip"))
1925 shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
1926 else if (!strcasecmp(parameter[1], "sky"))
1927 shader.surfaceparms |= Q3SURFACEPARM_SKY;
1928 else if (!strcasecmp(parameter[1], "slick"))
1929 shader.surfaceparms |= Q3SURFACEPARM_SLICK;
1930 else if (!strcasecmp(parameter[1], "slime"))
1931 shader.surfaceparms |= Q3SURFACEPARM_SLIME;
1932 else if (!strcasecmp(parameter[1], "structural"))
1933 shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
1934 else if (!strcasecmp(parameter[1], "trans"))
1935 shader.surfaceparms |= Q3SURFACEPARM_TRANS;
1936 else if (!strcasecmp(parameter[1], "water"))
1937 shader.surfaceparms |= Q3SURFACEPARM_WATER;
1938 else if (!strcasecmp(parameter[1], "pointlight"))
1939 shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
1940 else if (!strcasecmp(parameter[1], "antiportal"))
1941 shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
1942 else if (!strcasecmp(parameter[1], "skip"))
1943 ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
1946 // try custom surfaceparms
1947 for (j = 0; j < numcustsurfaceflags; j++)
1949 if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
1951 shader.surfaceflags |= custsurfaceflags[j];
1956 if (j == numcustsurfaceflags)
1957 Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
1960 else if (!strcasecmp(parameter[0], "dpshadow"))
1961 shader.dpshadow = true;
1962 else if (!strcasecmp(parameter[0], "dpnoshadow"))
1963 shader.dpnoshadow = true;
1964 else if (!strcasecmp(parameter[0], "dpnortlight"))
1965 shader.dpnortlight = true;
1966 else if (!strcasecmp(parameter[0], "dpreflectcube"))
1967 strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
1968 else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
1969 shader.dpmeshcollisions = true;
1970 // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
1971 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
1973 if (Cvar_VariableValue(parameter[1]) == 0.0f)
1974 shader.dpshaderkill = dpshaderkill;
1976 // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
1977 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
1979 const char *op = NULL;
1980 if (numparameters >= 3)
1984 if (Cvar_VariableValue(parameter[1]) != 0.0f)
1985 shader.dpshaderkill = dpshaderkill;
1987 else if (numparameters >= 4 && !strcmp(op, "=="))
1989 if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
1990 shader.dpshaderkill = dpshaderkill;
1992 else if (numparameters >= 4 && !strcmp(op, "!="))
1994 if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
1995 shader.dpshaderkill = dpshaderkill;
1997 else if (numparameters >= 4 && !strcmp(op, ">"))
1999 if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
2000 shader.dpshaderkill = dpshaderkill;
2002 else if (numparameters >= 4 && !strcmp(op, "<"))
2004 if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
2005 shader.dpshaderkill = dpshaderkill;
2007 else if (numparameters >= 4 && !strcmp(op, ">="))
2009 if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
2010 shader.dpshaderkill = dpshaderkill;
2012 else if (numparameters >= 4 && !strcmp(op, "<="))
2014 if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
2015 shader.dpshaderkill = dpshaderkill;
2019 Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2022 else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2024 // some q3 skies don't have the sky parm set
2025 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2026 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2028 else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2030 // some q3 skies don't have the sky parm set
2031 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2032 if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2033 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2035 else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2037 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2038 shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED;
2040 else if (!strcasecmp(parameter[0], "nomipmaps"))
2041 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2042 else if (!strcasecmp(parameter[0], "nopicmip"))
2043 shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
2044 else if (!strcasecmp(parameter[0], "polygonoffset"))
2045 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2046 else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2048 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2049 if(numparameters >= 2)
2051 shader.biaspolygonfactor = atof(parameter[1]);
2052 if(numparameters >= 3)
2053 shader.biaspolygonoffset = atof(parameter[2]);
2055 shader.biaspolygonoffset = 0;
2058 else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2060 shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
2061 if (!strcasecmp(parameter[1], "sky"))
2062 shader.transparentsort = TRANSPARENTSORT_SKY;
2063 else if (!strcasecmp(parameter[1], "distance"))
2064 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
2065 else if (!strcasecmp(parameter[1], "hud"))
2066 shader.transparentsort = TRANSPARENTSORT_HUD;
2068 Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2070 else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2072 shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
2073 shader.refractfactor = atof(parameter[1]);
2074 Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2076 else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2078 shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
2079 shader.reflectfactor = atof(parameter[1]);
2080 Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2082 else if (!strcasecmp(parameter[0], "dpcamera"))
2084 shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
2086 else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2088 shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
2089 shader.reflectmin = atof(parameter[1]);
2090 shader.reflectmax = atof(parameter[2]);
2091 shader.refractfactor = atof(parameter[3]);
2092 shader.reflectfactor = atof(parameter[4]);
2093 Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2094 Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2095 shader.r_water_wateralpha = atof(parameter[11]);
2097 else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2099 shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2100 shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2102 else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2104 shader.specularscalemod = atof(parameter[1]);
2106 else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2108 shader.specularpowermod = atof(parameter[1]);
2110 else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2112 shader.rtlightambient = atof(parameter[1]);
2114 else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2116 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2117 shader.offsetmapping = OFFSETMAPPING_OFF;
2118 else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2119 shader.offsetmapping = OFFSETMAPPING_DEFAULT;
2120 else if (!strcasecmp(parameter[1], "linear"))
2121 shader.offsetmapping = OFFSETMAPPING_LINEAR;
2122 else if (!strcasecmp(parameter[1], "relief"))
2123 shader.offsetmapping = OFFSETMAPPING_RELIEF;
2124 if (numparameters >= 3)
2125 shader.offsetscale = atof(parameter[2]);
2126 if (numparameters >= 5)
2128 if(!strcasecmp(parameter[3], "bias"))
2129 shader.offsetbias = atof(parameter[4]);
2130 else if(!strcasecmp(parameter[3], "match"))
2131 shader.offsetbias = 1.0f - atof(parameter[4]);
2132 else if(!strcasecmp(parameter[3], "match8"))
2133 shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2134 else if(!strcasecmp(parameter[3], "match16"))
2135 shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2138 else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2141 for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2142 if (!shader.deforms[deformindex].deform)
2144 if (deformindex < Q3MAXDEFORMS)
2146 for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2147 shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2148 if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2149 else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2150 else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2151 else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2152 else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2153 else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2154 else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2155 else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2156 else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2157 else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2158 else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2159 else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2160 else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2161 else if (!strcasecmp(parameter[1], "wave" ))
2163 shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2164 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2165 for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2166 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2168 else if (!strcasecmp(parameter[1], "move" ))
2170 shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2171 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2172 for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2173 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2178 // hide this shader if a cvar said it should be killed
2179 if (shader.dpshaderkill)
2180 shader.numlayers = 0;
2181 // fix up multiple reflection types
2182 if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
2183 shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
2185 Q3Shader_AddToHash (&shader);
2189 FS_FreeSearch(search);
2190 // free custinfoparm values
2191 for (j = 0; j < numcustsurfaceflags; j++)
2192 Mem_Free(custsurfaceparmnames[j]);
2195 q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
2197 unsigned short hash;
2198 q3shader_hash_entry_t* entry;
2200 Mod_LoadQ3Shaders();
2201 hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2202 entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2203 while (entry != NULL)
2205 if (strcasecmp (entry->shader.name, name) == 0)
2206 return &entry->shader;
2207 entry = entry->chain;
2212 texture_shaderpass_t *Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe)
2214 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2215 shaderpass->framerate = 0.0f;
2216 shaderpass->numframes = 1;
2217 shaderpass->blendfunc[0] = GL_ONE;
2218 shaderpass->blendfunc[1] = GL_ZERO;
2219 shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
2220 shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
2221 shaderpass->alphatest = false;
2222 shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
2223 shaderpass->skinframes[0] = skinframe;
2227 texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
2230 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2231 shaderpass->alphatest = layer->alphatest != 0;
2232 shaderpass->framerate = layer->framerate;
2233 shaderpass->numframes = layer->numframes;
2234 shaderpass->blendfunc[0] = layer->blendfunc[0];
2235 shaderpass->blendfunc[1] = layer->blendfunc[1];
2236 shaderpass->rgbgen = layer->rgbgen;
2237 shaderpass->alphagen = layer->alphagen;
2238 shaderpass->tcgen = layer->tcgen;
2239 for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
2240 shaderpass->tcmods[j] = layer->tcmods[j];
2241 for (j = 0; j < layer->numframes; j++)
2242 shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true);
2246 qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags, int defaultmaterialflags)
2248 int texflagsmask, texflagsor;
2249 qboolean success = true;
2250 q3shaderinfo_t *shader;
2253 strlcpy(texture->name, name, sizeof(texture->name));
2254 texture->basealpha = 1.0f;
2255 shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2257 // allow disabling of picmip or compression by defaulttexflags
2259 if(!(defaulttexflags & TEXF_PICMIP))
2260 texflagsmask &= ~TEXF_PICMIP;
2261 if(!(defaulttexflags & TEXF_COMPRESS))
2262 texflagsmask &= ~TEXF_COMPRESS;
2264 if(defaulttexflags & TEXF_ISWORLD)
2265 texflagsor |= TEXF_ISWORLD;
2266 if(defaulttexflags & TEXF_ISSPRITE)
2267 texflagsor |= TEXF_ISSPRITE;
2268 // unless later loaded from the shader
2269 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2270 texture->offsetscale = 1;
2271 texture->offsetbias = 0;
2272 texture->specularscalemod = 1;
2273 texture->specularpowermod = 1;
2274 texture->rtlightambient = 0;
2275 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2276 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2277 // JUST GREP FOR "specularscalemod = 1".
2281 if (developer_loading.integer)
2282 Con_Printf("%s: loaded shader for %s\n", modelname, name);
2284 if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2286 texture->basematerialflags = MATERIALFLAG_SKY;
2287 if (shader->skyboxname[0] && loadmodel)
2289 // quake3 seems to append a _ to the skybox name, so this must do so as well
2290 dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2293 else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2294 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2296 texture->basematerialflags = MATERIALFLAG_WALL;
2298 if (shader->layers[0].alphatest)
2299 texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
2300 if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2301 texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2302 if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET)
2304 texture->biaspolygonoffset += shader->biaspolygonoffset;
2305 texture->biaspolygonfactor += shader->biaspolygonfactor;
2307 if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION)
2308 texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2309 if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION)
2310 texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2311 if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
2312 texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2313 if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2314 texture->basematerialflags |= MATERIALFLAG_CAMERA;
2315 texture->customblendfunc[0] = GL_ONE;
2316 texture->customblendfunc[1] = GL_ZERO;
2317 texture->transparentsort = shader->transparentsort;
2318 if (shader->numlayers > 0)
2320 texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2321 texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2323 Q3 shader blendfuncs actually used in the game (* = supported by DP)
2324 * additive GL_ONE GL_ONE
2325 additive weird GL_ONE GL_SRC_ALPHA
2326 additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
2327 * alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2328 alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2329 brighten GL_DST_COLOR GL_ONE
2330 brighten GL_ONE GL_SRC_COLOR
2331 brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2332 brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
2333 * modulate GL_DST_COLOR GL_ZERO
2334 * modulate GL_ZERO GL_SRC_COLOR
2335 modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
2336 modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2337 modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2338 * modulate x2 GL_DST_COLOR GL_SRC_COLOR
2339 * no blend GL_ONE GL_ZERO
2340 nothing GL_ZERO GL_ONE
2342 // if not opaque, figure out what blendfunc to use
2343 if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2345 if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2346 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2347 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2348 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2349 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2350 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2352 texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2355 if (!shader->lighting)
2356 texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2358 // here be dragons: convert quake3 shaders to material
2359 if (shader->numlayers > 0)
2362 int terrainbackgroundlayer = -1;
2363 int lightmaplayer = -1;
2364 int alphagenspecularlayer = -1;
2365 int rgbgenvertexlayer = -1;
2366 int rgbgendiffuselayer = -1;
2367 int materiallayer = -1;
2368 int endofprelayers = 0;
2369 int firstpostlayer = 0;
2370 int shaderpassindex = 0;
2371 for (i = 0; i < shader->numlayers; i++)
2373 if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
2375 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2376 rgbgenvertexlayer = i;
2377 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
2378 rgbgendiffuselayer = i;
2379 if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
2380 alphagenspecularlayer = i;
2382 if (shader->numlayers >= 2
2383 && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2384 && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
2385 && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2386 || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
2388 // terrain blend or certain other effects involving alphatest over a regular layer
2389 terrainbackgroundlayer = 0;
2391 // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
2392 firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
2394 else if (lightmaplayer == 0)
2396 // ordinary texture but with $lightmap before diffuse
2398 firstpostlayer = lightmaplayer + 2;
2400 else if (lightmaplayer >= 1)
2402 // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
2403 endofprelayers = lightmaplayer - 1;
2404 materiallayer = lightmaplayer - 1;
2405 firstpostlayer = lightmaplayer + 1;
2407 else if (rgbgenvertexlayer >= 0)
2409 // map models with baked lighting
2410 materiallayer = rgbgenvertexlayer;
2411 endofprelayers = rgbgenvertexlayer;
2412 firstpostlayer = rgbgenvertexlayer + 1;
2413 // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
2414 if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
2415 texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR | MATERIALFLAG_ALPHAGEN_VERTEX;
2417 else if (rgbgendiffuselayer >= 0)
2419 // entity models with dynamic lighting
2420 materiallayer = rgbgendiffuselayer;
2421 endofprelayers = rgbgendiffuselayer;
2422 firstpostlayer = rgbgendiffuselayer + 1;
2423 // player models often have specular as a pass after diffuse - we don't currently make use of that specular texture (would need to meld it into the skinframe)...
2424 if (alphagenspecularlayer >= 0)
2425 firstpostlayer = alphagenspecularlayer + 1;
2429 // special effects shaders - treat first as primary layer and do everything else as post
2434 // convert the main material layer
2435 // FIXME: if alphagenspecularlayer is used, we should pass a specular texture name to R_SkinFrame_LoadExternal and have it load that texture instead of the assumed name for _gloss texture
2436 if (materiallayer >= 0)
2437 texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2438 // convert the terrain background blend layer (if any)
2439 if (terrainbackgroundlayer >= 0)
2440 texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2441 // convert the prepass layers (if any)
2442 texture->startpreshaderpass = shaderpassindex;
2443 for (i = 0; i < endofprelayers; i++)
2444 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2445 texture->endpreshaderpass = shaderpassindex;
2446 texture->startpostshaderpass = shaderpassindex;
2447 // convert the postpass layers (if any)
2448 for (i = firstpostlayer; i < shader->numlayers; i++)
2449 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2450 texture->startpostshaderpass = shaderpassindex;
2453 if (shader->dpshadow)
2454 texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2455 if (shader->dpnoshadow)
2456 texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2457 if (shader->dpnortlight)
2458 texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2459 if (shader->vertexalpha)
2460 texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2461 memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2462 texture->reflectmin = shader->reflectmin;
2463 texture->reflectmax = shader->reflectmax;
2464 texture->refractfactor = shader->refractfactor;
2465 Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2466 texture->reflectfactor = shader->reflectfactor;
2467 Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2468 texture->r_water_wateralpha = shader->r_water_wateralpha;
2469 Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2470 texture->offsetmapping = shader->offsetmapping;
2471 texture->offsetscale = shader->offsetscale;
2472 texture->offsetbias = shader->offsetbias;
2473 texture->specularscalemod = shader->specularscalemod;
2474 texture->specularpowermod = shader->specularpowermod;
2475 texture->rtlightambient = shader->rtlightambient;
2476 if (shader->dpreflectcube[0])
2477 texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2479 // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2480 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2481 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ;
2482 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ;
2483 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ;
2484 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ;
2485 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ;
2486 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ;
2487 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ;
2489 // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ;
2490 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ;
2491 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2492 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ;
2493 if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ;
2494 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ;
2495 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ;
2496 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ;
2497 // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ;
2498 // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ;
2499 // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ;
2500 // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ;
2501 if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ;
2502 // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ;
2503 // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ;
2504 // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ;
2505 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ;
2506 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ;
2507 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ;
2508 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ;
2509 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ;
2510 // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ;
2511 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ;
2512 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ;
2513 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ;
2514 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ;
2515 // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ;
2516 // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ;
2517 // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ;
2518 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP;
2519 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ;
2520 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ;
2522 texture->surfaceflags = shader->surfaceflags;
2523 if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ;
2524 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ;
2525 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2526 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ;
2527 // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ;
2528 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ;
2529 // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ;
2530 if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ;
2531 if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ;
2532 if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ;
2533 if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ;
2534 if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ;
2535 // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ;
2536 if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ;
2537 if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ;
2538 if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ;
2539 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ;
2540 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ;
2541 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ;
2542 // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ;
2543 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ;
2544 if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ;
2545 // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ;
2546 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ;
2547 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ;
2548 // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ;
2549 if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ;
2550 if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ;
2551 if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ;
2552 // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ;
2553 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ;
2554 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ;
2556 if (shader->dpmeshcollisions)
2557 texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2558 if (shader->dpshaderkill && developer_extra.integer)
2559 Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", modelname, name);
2561 else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2563 if (developer_extra.integer)
2564 Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name);
2565 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2567 else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2569 if (developer_extra.integer)
2570 Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", modelname, name);
2571 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2572 texture->supercontents = SUPERCONTENTS_SOLID;
2576 if (developer_extra.integer)
2577 Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name);
2578 if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2580 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2581 texture->supercontents = SUPERCONTENTS_SOLID;
2583 else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2585 texture->basematerialflags = MATERIALFLAG_SKY;
2586 texture->supercontents = SUPERCONTENTS_SKY;
2590 texture->basematerialflags = defaultmaterialflags;
2591 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2593 if(cls.state == ca_dedicated)
2595 texture->materialshaderpass = NULL;
2600 skinframe_t *skinframe = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, fallback);
2603 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2604 if (texture->materialshaderpass->skinframes[0]->hasalpha)
2605 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2606 if (texture->q2contents)
2607 texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents);
2611 if (!success && warnmissing)
2612 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", modelname, texture->name);
2615 // init the animation variables
2616 texture->currentframe = texture;
2617 texture->currentmaterialflags = texture->basematerialflags;
2618 if (!texture->materialshaderpass)
2619 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadMissing());
2620 if (!texture->materialshaderpass->skinframes[0])
2621 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2622 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2623 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2627 void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
2629 if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
2630 Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name);
2632 strlcpy(texture->name, name, sizeof(texture->name));
2633 texture->basealpha = 1.0f;
2634 texture->basematerialflags = materialflags;
2635 texture->supercontents = supercontents;
2637 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2638 texture->offsetscale = 1;
2639 texture->offsetbias = 0;
2640 texture->specularscalemod = 1;
2641 texture->specularpowermod = 1;
2642 texture->rtlightambient = 0;
2643 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2644 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2645 // JUST GREP FOR "specularscalemod = 1".
2647 if (developer_extra.integer)
2648 Con_DPrintf("^1Custom texture ^3\"%s\"\n", texture->name);
2650 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2652 // init the animation variables
2653 texture->currentmaterialflags = texture->basematerialflags;
2654 texture->currentframe = texture;
2655 texture->currentskinframe = skinframe;
2656 texture->backgroundcurrentskinframe = NULL;
2659 void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins)
2662 for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++)
2664 if (texture->shaderpasses[i])
2667 for (j = 0; j < sizeof(texture->shaderpasses[i]->skinframes) / sizeof(skinframe_t *);j++)
2668 if (texture->shaderpasses[i]->skinframes[j] && texture->shaderpasses[i]->skinframes[j]->base)
2669 R_SkinFrame_PurgeSkinFrame(texture->shaderpasses[i]->skinframes[j]);
2670 Mem_Free(texture->shaderpasses[i]);
2671 texture->shaderpasses[i] = NULL;
2674 texture->materialshaderpass = NULL;
2675 texture->currentskinframe = NULL;
2676 texture->backgroundcurrentskinframe = NULL;
2679 skinfile_t *Mod_LoadSkinFiles(void)
2681 int i, words, line, wordsoverflow;
2684 skinfile_t *skinfile = NULL, *first = NULL;
2685 skinfileitem_t *skinfileitem;
2686 char word[10][MAX_QPATH];
2691 U_bodyBox,models/players/Legoman/BikerA2.tga
2692 U_RArm,models/players/Legoman/BikerA1.tga
2693 U_LArm,models/players/Legoman/BikerA1.tga
2694 U_armor,common/nodraw
2695 U_sword,common/nodraw
2696 U_shield,common/nodraw
2697 U_homb,common/nodraw
2698 U_backpack,common/nodraw
2699 U_colcha,common/nodraw
2704 memset(word, 0, sizeof(word));
2705 for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2707 // If it's the first file we parse
2708 if (skinfile == NULL)
2710 skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2715 skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2716 skinfile = skinfile->next;
2718 skinfile->next = NULL;
2720 for(line = 0;;line++)
2723 if (!COM_ParseToken_QuakeC(&data, true))
2725 if (!strcmp(com_token, "\n"))
2728 wordsoverflow = false;
2732 strlcpy(word[words++], com_token, sizeof (word[0]));
2734 wordsoverflow = true;
2736 while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2739 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);
2742 // words is always >= 1
2743 if (!strcmp(word[0], "replace"))
2747 if (developer_loading.integer)
2748 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2749 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2750 skinfileitem->next = skinfile->items;
2751 skinfile->items = skinfileitem;
2752 strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2753 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2756 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]);
2758 else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2760 // tag name, like "tag_weapon,"
2761 // not used for anything (not even in Quake3)
2763 else if (words >= 2 && !strcmp(word[1], ","))
2765 // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2766 if (developer_loading.integer)
2767 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2768 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2769 skinfileitem->next = skinfile->items;
2770 skinfile->items = skinfileitem;
2771 strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2772 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2775 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);
2780 loadmodel->numskins = i;
2784 void Mod_FreeSkinFiles(skinfile_t *skinfile)
2787 skinfileitem_t *skinfileitem, *nextitem;
2788 for (;skinfile;skinfile = next)
2790 next = skinfile->next;
2791 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2793 nextitem = skinfileitem->next;
2794 Mem_Free(skinfileitem);
2800 int Mod_CountSkinFiles(skinfile_t *skinfile)
2803 for (i = 0;skinfile;skinfile = skinfile->next, i++);
2807 void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
2810 double isnap = 1.0 / snap;
2811 for (i = 0;i < numvertices*numcomponents;i++)
2812 vertices[i] = floor(vertices[i]*isnap)*snap;
2815 int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
2817 int i, outtriangles;
2818 float edgedir1[3], edgedir2[3], temp[3];
2819 // a degenerate triangle is one with no width (thickness, surface area)
2820 // these are characterized by having all 3 points colinear (along a line)
2821 // or having two points identical
2822 // the simplest check is to calculate the triangle's area
2823 for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
2825 // calculate first edge
2826 VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
2827 VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
2828 CrossProduct(edgedir1, edgedir2, temp);
2829 if (VectorLength2(temp) < 0.001f)
2830 continue; // degenerate triangle (no area)
2831 // valid triangle (has area)
2832 VectorCopy(inelement3i, outelement3i);
2836 return outtriangles;
2839 void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
2842 int firstvertex, lastvertex;
2843 if (numelements > 0 && elements)
2845 firstvertex = lastvertex = elements[0];
2846 for (i = 1;i < numelements;i++)
2849 firstvertex = min(firstvertex, e);
2850 lastvertex = max(lastvertex, e);
2854 firstvertex = lastvertex = 0;
2855 if (firstvertexpointer)
2856 *firstvertexpointer = firstvertex;
2857 if (lastvertexpointer)
2858 *lastvertexpointer = lastvertex;
2861 void Mod_MakeSortedSurfaces(dp_model_t *mod)
2863 // make an optimal set of texture-sorted batches to draw...
2865 int *firstsurfacefortexture;
2866 int *numsurfacesfortexture;
2867 if (!mod->sortedmodelsurfaces)
2868 mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
2869 firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
2870 numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
2871 memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
2872 for (j = 0;j < mod->nummodelsurfaces;j++)
2874 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2875 t = (int)(surface->texture - mod->data_textures);
2876 numsurfacesfortexture[t]++;
2879 for (t = 0;t < mod->num_textures;t++)
2881 firstsurfacefortexture[t] = j;
2882 j += numsurfacesfortexture[t];
2884 for (j = 0;j < mod->nummodelsurfaces;j++)
2886 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2887 t = (int)(surface->texture - mod->data_textures);
2888 mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
2890 Mem_Free(firstsurfacefortexture);
2891 Mem_Free(numsurfacesfortexture);
2894 void Mod_BuildVBOs(void)
2896 if(cls.state == ca_dedicated)
2899 if (!loadmodel->surfmesh.num_vertices)
2902 if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
2905 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2907 if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
2909 Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
2910 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2915 // upload short indices as a buffer
2916 if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
2917 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);
2919 // upload int indices as a buffer
2920 if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
2921 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);
2923 // only build a vbo if one has not already been created (this is important for brush models which load specially)
2924 // we put several vertex data streams in the same buffer
2925 if (!loadmodel->surfmesh.data_vertex3f_vertexbuffer)
2930 loadmodel->surfmesh.data_vertex3f_bufferoffset = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2931 loadmodel->surfmesh.data_svector3f_bufferoffset = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2932 loadmodel->surfmesh.data_tvector3f_bufferoffset = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2933 loadmodel->surfmesh.data_normal3f_bufferoffset = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2934 loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2935 loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2936 loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2937 loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2938 loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2939 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
2940 if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.data_vertex3f_bufferoffset , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2941 if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.data_svector3f_bufferoffset , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2942 if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.data_tvector3f_bufferoffset , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2943 if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.data_normal3f_bufferoffset , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2944 if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
2945 if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
2946 if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
2947 if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2948 if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2949 loadmodel->surfmesh.data_vertex3f_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
2950 loadmodel->surfmesh.data_svector3f_vertexbuffer = loadmodel->surfmesh.data_svector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2951 loadmodel->surfmesh.data_tvector3f_vertexbuffer = loadmodel->surfmesh.data_tvector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2952 loadmodel->surfmesh.data_normal3f_vertexbuffer = loadmodel->surfmesh.data_normal3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2953 loadmodel->surfmesh.data_texcoordtexture2f_vertexbuffer = loadmodel->surfmesh.data_texcoordtexture2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2954 loadmodel->surfmesh.data_texcoordlightmap2f_vertexbuffer = loadmodel->surfmesh.data_texcoordlightmap2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2955 loadmodel->surfmesh.data_lightmapcolor4f_vertexbuffer = loadmodel->surfmesh.data_lightmapcolor4f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2956 loadmodel->surfmesh.data_skeletalindex4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalindex4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2957 loadmodel->surfmesh.data_skeletalweight4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalweight4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2962 extern cvar_t mod_obj_orientation;
2963 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
2965 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
2967 const char *texname;
2969 const float *v, *vn, *vt;
2971 size_t outbufferpos = 0;
2972 size_t outbuffermax = 0x100000;
2973 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
2974 const msurface_t *surface;
2975 const int maxtextures = 256;
2976 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
2977 dp_model_t *submodel;
2979 // construct the mtllib file
2980 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
2983 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
2986 countvertices += surface->num_vertices;
2987 countfaces += surface->num_triangles;
2988 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
2989 for (textureindex = 0;textureindex < counttextures;textureindex++)
2990 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
2992 if (textureindex < counttextures)
2993 continue; // already wrote this material entry
2994 if (textureindex >= maxtextures)
2995 continue; // just a precaution
2996 textureindex = counttextures++;
2997 strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
2998 if (outbufferpos >= outbuffermax >> 1)
3001 oldbuffer = outbuffer;
3002 outbuffer = (char *) Z_Malloc(outbuffermax);
3003 memcpy(outbuffer, oldbuffer, outbufferpos);
3006 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");
3011 // write the mtllib file
3012 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3014 // construct the obj file
3016 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);
3020 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)
3022 if (outbufferpos >= outbuffermax >> 1)
3025 oldbuffer = outbuffer;
3026 outbuffer = (char *) Z_Malloc(outbuffermax);
3027 memcpy(outbuffer, oldbuffer, outbufferpos);
3030 if(mod_obj_orientation.integer)
3031 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]);
3033 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]);
3038 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3040 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3043 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3044 for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3046 surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3047 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3050 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3052 if (outbufferpos >= outbuffermax >> 1)
3055 oldbuffer = outbuffer;
3056 outbuffer = (char *) Z_Malloc(outbuffermax);
3057 memcpy(outbuffer, oldbuffer, outbufferpos);
3063 if(mod_obj_orientation.integer)
3064 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);
3066 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);
3073 // write the obj file
3074 FS_WriteFile(filename, outbuffer, outbufferpos);
3078 Z_Free(texturenames);
3081 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3084 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3086 int countnodes = 0, counttriangles = 0, countframes = 0;
3094 size_t outbufferpos = 0;
3095 size_t outbuffermax = 0x100000;
3096 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3097 const msurface_t *surface;
3098 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3101 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3103 if (outbufferpos >= outbuffermax >> 1)
3106 oldbuffer = outbuffer;
3107 outbuffer = (char *) Z_Malloc(outbuffermax);
3108 memcpy(outbuffer, oldbuffer, outbufferpos);
3112 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3116 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3119 for (poseindex = 0;poseindex < numposes;poseindex++)
3122 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3125 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3129 matrix4x4_t posematrix;
3130 if (outbufferpos >= outbuffermax >> 1)
3133 oldbuffer = outbuffer;
3134 outbuffer = (char *) Z_Malloc(outbuffermax);
3135 memcpy(outbuffer, oldbuffer, outbufferpos);
3139 // strangely the smd angles are for a transposed matrix, so we
3140 // have to generate a transposed matrix, then convert that...
3141 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3142 Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3143 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3144 if (angles[0] >= 180) angles[0] -= 360;
3145 if (angles[1] >= 180) angles[1] -= 360;
3146 if (angles[2] >= 180) angles[2] -= 360;
3150 float a = DEG2RAD(angles[ROLL]);
3151 float b = DEG2RAD(angles[PITCH]);
3152 float c = DEG2RAD(angles[YAW]);
3153 float cy, sy, cp, sp, cr, sr;
3155 // smd matrix construction, for comparing
3166 test[1][0] = sr*sp*cy+cr*-sy;
3167 test[1][1] = sr*sp*sy+cr*cy;
3169 test[2][0] = (cr*sp*cy+-sr*-sy);
3170 test[2][1] = (cr*sp*sy+-sr*cy);
3172 test[3][0] = pose[9];
3173 test[3][1] = pose[10];
3174 test[3][2] = pose[11];
3177 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]));
3182 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3187 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3190 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3192 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3195 if (outbufferpos >= outbuffermax >> 1)
3198 oldbuffer = outbuffer;
3199 outbuffer = (char *) Z_Malloc(outbuffermax);
3200 memcpy(outbuffer, oldbuffer, outbufferpos);
3203 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3206 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3208 const int index = e[2-cornerindex];
3209 const float *v = model->surfmesh.data_vertex3f + index * 3;
3210 const float *vn = model->surfmesh.data_normal3f + index * 3;
3211 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3212 const int b = model->surfmesh.blends[index];
3213 if (b < model->num_bones)
3214 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]);
3217 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3218 const unsigned char *wi = w->index;
3219 const unsigned char *wf = w->influence;
3220 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);
3221 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);
3222 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);
3223 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]);
3230 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3235 FS_WriteFile(filename, outbuffer, outbufferpos);
3238 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3245 decompiles a model to editable files
3248 static void Mod_Decompile_f(void)
3250 int i, j, k, l, first, count;
3252 char inname[MAX_QPATH];
3253 char outname[MAX_QPATH];
3254 char mtlname[MAX_QPATH];
3255 char basename[MAX_QPATH];
3256 char animname[MAX_QPATH];
3257 char animname2[MAX_QPATH];
3258 char zymtextbuffer[16384];
3259 char dpmtextbuffer[16384];
3260 char framegroupstextbuffer[16384];
3261 int zymtextsize = 0;
3262 int dpmtextsize = 0;
3263 int framegroupstextsize = 0;
3266 if (Cmd_Argc() != 2)
3268 Con_Print("usage: modeldecompile <filename>\n");
3272 strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3273 FS_StripExtension(inname, basename, sizeof(basename));
3275 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3278 Con_Print("No such model\n");
3281 if (mod->brush.submodel)
3283 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3284 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3285 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3288 if (!mod->surfmesh.num_triangles)
3290 Con_Print("Empty model (or sprite)\n");
3294 // export OBJ if possible (not on sprites)
3295 if (mod->surfmesh.num_triangles)
3297 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3298 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3299 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3302 // export SMD if possible (only for skeletal models)
3303 if (mod->surfmesh.num_triangles && mod->num_bones)
3305 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3306 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3307 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3308 if (l > 0) zymtextsize += l;
3309 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3310 if (l > 0) dpmtextsize += l;
3311 for (i = 0;i < mod->numframes;i = j)
3313 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3314 first = mod->animscenes[i].firstframe;
3315 if (mod->animscenes[i].framecount > 1)
3318 count = mod->animscenes[i].framecount;
3324 // check for additional frames with same name
3325 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3326 if(animname[l] < '0' || animname[l] > '9')
3328 if(k > 0 && animname[k-1] == '_')
3331 count = mod->num_poses - first;
3332 for (j = i + 1;j < mod->numframes;j++)
3334 strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3335 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3336 if(animname2[l] < '0' || animname2[l] > '9')
3338 if(k > 0 && animname[k-1] == '_')
3341 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3343 count = mod->animscenes[j].firstframe - first;
3347 // if it's only one frame, use the original frame name
3349 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3352 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3353 Mod_Decompile_SMD(mod, outname, first, count, false);
3354 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3356 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3357 if (l > 0) zymtextsize += l;
3359 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3361 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3362 if (l > 0) dpmtextsize += l;
3364 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3366 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3367 if (l > 0) framegroupstextsize += l;
3371 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3373 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3374 if (framegroupstextsize)
3375 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3379 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
3382 memset(state, 0, sizeof(*state));
3383 state->width = width;
3384 state->height = height;
3385 state->currentY = 0;
3386 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3387 for (y = 0;y < state->height;y++)
3389 state->rows[y].currentX = 0;
3390 state->rows[y].rowY = -1;
3394 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3397 state->currentY = 0;
3398 for (y = 0;y < state->height;y++)
3400 state->rows[y].currentX = 0;
3401 state->rows[y].rowY = -1;
3405 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3408 Mem_Free(state->rows);
3409 memset(state, 0, sizeof(*state));
3412 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3414 mod_alloclightmap_row_t *row;
3417 row = state->rows + blockheight;
3418 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3420 if (state->currentY + blockheight <= state->height)
3422 // use the current allocation position
3423 row->rowY = state->currentY;
3425 state->currentY += blockheight;
3429 // find another position
3430 for (y = blockheight;y < state->height;y++)
3432 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3434 row = state->rows + y;
3438 if (y == state->height)
3443 *outx = row->currentX;
3444 row->currentX += blockwidth;
3449 typedef struct lightmapsample_s
3453 float *vertex_color;
3454 unsigned char *lm_bgr;
3455 unsigned char *lm_dir;
3459 typedef struct lightmapvertex_s
3464 float texcoordbase[2];
3465 float texcoordlightmap[2];
3466 float lightcolor[4];
3470 typedef struct lightmaptriangle_s
3478 // 2D modelspace coordinates of min corner
3479 // snapped to lightmap grid but not in grid coordinates
3481 // 2D modelspace to lightmap coordinate scale
3489 typedef struct lightmaplight_s
3500 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3502 #define MAX_LIGHTMAPSAMPLES 64
3503 static int mod_generatelightmaps_numoffsets[3];
3504 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3506 static int mod_generatelightmaps_numlights;
3507 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3509 extern cvar_t r_shadow_lightattenuationdividebias;
3510 extern cvar_t r_shadow_lightattenuationlinearscale;
3512 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3517 float relativepoint[3];
3524 float lightorigin[3];
3528 float lightcolor[3];
3530 for (i = 0;i < 5*3;i++)
3532 for (index = 0;;index++)
3534 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3539 lightradius2 = lightradius * lightradius;
3540 VectorSubtract(lightorigin, pos, relativepoint);
3541 dist2 = VectorLength2(relativepoint);
3542 if (dist2 >= lightradius2)
3544 lightiradius = 1.0f / lightradius;
3545 dist = sqrt(dist2) * lightiradius;
3546 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3547 if (intensity <= 0.0f)
3549 if (model && model->TraceLine)
3551 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3552 if (trace.fraction < 1)
3555 // scale down intensity to add to both ambient and diffuse
3556 //intensity *= 0.5f;
3557 VectorNormalize(relativepoint);
3558 VectorScale(lightcolor, intensity, color);
3559 VectorMA(sample , 0.5f , color, sample );
3560 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3561 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3562 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3563 // calculate a weighted average light direction as well
3564 intensity *= VectorLength(color);
3565 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3567 // calculate the direction we'll use to reduce the sample to a directional light source
3568 VectorCopy(sample + 12, dir);
3569 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3570 VectorNormalize(dir);
3571 // extract the diffuse color along the chosen direction and scale it
3572 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3573 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3574 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3575 // subtract some of diffuse from ambient
3576 VectorMA(sample, -0.333f, diffuse, ambient);
3577 // store the normalized lightdir
3578 VectorCopy(dir, lightdir);
3581 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3585 const msurface_t *surface;
3586 const float *vertex3f = model->surfmesh.data_vertex3f;
3587 const int *element3i = model->surfmesh.data_element3i;
3590 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3592 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3594 if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3596 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3598 VectorCopy(vertex3f + 3*e[0], v2[0]);
3599 VectorCopy(vertex3f + 3*e[1], v2[1]);
3600 VectorCopy(vertex3f + 3*e[2], v2[2]);
3601 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3606 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3608 int maxnodes = 1<<14;
3609 svbsp_node_t *nodes;
3614 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3615 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3616 VectorCopy(lightinfo->origin, origin);
3617 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3620 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3621 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3622 if (svbsp.ranoutofnodes)
3625 if (maxnodes > 1<<22)
3631 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3636 if (svbsp.numnodes > 0)
3638 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3639 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3640 lightinfo->svbsp = svbsp;
3645 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3649 lightmaplight_t *lightinfo;
3653 mod_generatelightmaps_numlights = 0;
3654 for (index = 0;;index++)
3656 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3660 mod_generatelightmaps_numlights++;
3662 if (mod_generatelightmaps_numlights > 0)
3664 mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3665 lightinfo = mod_generatelightmaps_lightinfo;
3666 for (index = 0;;index++)
3668 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3675 for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3677 lightinfo->iradius = 1.0f / lightinfo->radius;
3678 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3679 // TODO: compute svbsp
3680 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3684 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3687 if (mod_generatelightmaps_lightinfo)
3689 for (i = 0;i < mod_generatelightmaps_numlights;i++)
3690 if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3691 Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3692 Mem_Free(mod_generatelightmaps_lightinfo);
3694 mod_generatelightmaps_lightinfo = NULL;
3695 mod_generatelightmaps_numlights = 0;
3698 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3700 const svbsp_node_t *node;
3701 const svbsp_node_t *nodes = svbsp->nodes;
3706 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3708 return num == -1; // true if empty, false if solid (shadowed)
3711 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3714 float relativepoint[3];
3723 const lightmaplight_t *lightinfo;
3725 for (i = 0;i < 5*3;i++)
3727 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3729 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3730 VectorSubtract(lightinfo->origin, pos, relativepoint);
3731 // don't accept light from behind a surface, it causes bad shading
3732 if (normal && DotProduct(relativepoint, normal) <= 0)
3734 dist2 = VectorLength2(relativepoint);
3735 if (dist2 >= lightinfo->radius2)
3737 dist = sqrt(dist2) * lightinfo->iradius;
3738 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3741 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3745 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3747 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3749 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3752 // for light grid we'd better check visibility of the offset point
3753 cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3754 if (trace.fraction < 1)
3755 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3758 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3763 // scale intensity according to how many rays succeeded
3764 // we know one test is valid, half of the rest will fail...
3765 //if (normal && tests > 1)
3766 // intensity *= (tests - 1.0f) / tests;
3767 intensity *= (float)hits / tests;
3769 // scale down intensity to add to both ambient and diffuse
3770 //intensity *= 0.5f;
3771 VectorNormalize(relativepoint);
3772 VectorScale(lightinfo->color, intensity, color);
3773 VectorMA(sample , 0.5f , color, sample );
3774 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3775 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3776 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3777 // calculate a weighted average light direction as well
3778 intensity *= VectorLength(color);
3779 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3783 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3789 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
3790 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3791 VectorCopy(sample + 12, dir);
3792 VectorNormalize(dir);
3793 //VectorAdd(dir, normal, dir);
3794 //VectorNormalize(dir);
3795 f = DotProduct(dir, normal);
3796 f = max(0, f) * 255.0f;
3797 VectorScale(sample, f, color);
3798 //VectorCopy(normal, dir);
3799 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3800 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3801 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3802 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3804 lm_dir[0] = (unsigned char)dir[2];
3805 lm_dir[1] = (unsigned char)dir[1];
3806 lm_dir[2] = (unsigned char)dir[0];
3810 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3813 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
3814 VectorCopy(sample, vertex_color);
3817 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3823 Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
3824 // calculate the direction we'll use to reduce the sample to a directional light source
3825 VectorCopy(sample + 12, dir);
3826 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3827 VectorNormalize(dir);
3828 // extract the diffuse color along the chosen direction and scale it
3829 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3830 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3831 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3832 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3833 VectorScale(sample, 127.5f, ambient);
3834 VectorMA(ambient, -0.333f, diffuse, ambient);
3835 // encode to the grid format
3836 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3837 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3838 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3839 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3840 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3841 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3842 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3843 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3844 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));}
3847 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
3852 memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
3853 mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
3854 mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
3855 mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
3856 radius[0] = mod_generatelightmaps_lightmapradius.value;
3857 radius[1] = mod_generatelightmaps_vertexradius.value;
3858 radius[2] = mod_generatelightmaps_gridradius.value;
3859 for (i = 0;i < 3;i++)
3861 for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
3864 VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
3869 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
3871 msurface_t *surface;
3874 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3876 surface = model->data_surfaces + surfaceindex;
3877 surface->lightmaptexture = NULL;
3878 surface->deluxemaptexture = NULL;
3880 if (model->brushq3.data_lightmaps)
3882 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3883 if (model->brushq3.data_lightmaps[i])
3884 R_FreeTexture(model->brushq3.data_lightmaps[i]);
3885 Mem_Free(model->brushq3.data_lightmaps);
3886 model->brushq3.data_lightmaps = NULL;
3888 if (model->brushq3.data_deluxemaps)
3890 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3891 if (model->brushq3.data_deluxemaps[i])
3892 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
3893 Mem_Free(model->brushq3.data_deluxemaps);
3894 model->brushq3.data_deluxemaps = NULL;
3898 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
3900 msurface_t *surface;
3906 surfmesh_t oldsurfmesh;
3908 unsigned char *data;
3909 oldsurfmesh = model->surfmesh;
3910 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
3911 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
3913 size += model->surfmesh.num_vertices * sizeof(float[3]);
3914 size += model->surfmesh.num_vertices * sizeof(float[3]);
3915 size += model->surfmesh.num_vertices * sizeof(float[3]);
3916 size += model->surfmesh.num_vertices * sizeof(float[3]);
3917 size += model->surfmesh.num_vertices * sizeof(float[2]);
3918 size += model->surfmesh.num_vertices * sizeof(float[2]);
3919 size += model->surfmesh.num_vertices * sizeof(float[4]);
3920 data = (unsigned char *)Mem_Alloc(model->mempool, size);
3921 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3922 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3923 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3924 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3925 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3926 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3927 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
3928 if (model->surfmesh.num_vertices > 65536)
3929 model->surfmesh.data_element3s = NULL;
3931 if (model->surfmesh.data_element3i_indexbuffer && !model->surfmesh.data_element3i_indexbuffer->isdynamic)
3932 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
3933 model->surfmesh.data_element3i_indexbuffer = NULL;
3934 if (model->surfmesh.data_element3s_indexbuffer && !model->surfmesh.data_element3s_indexbuffer->isdynamic)
3935 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
3936 model->surfmesh.data_element3s_indexbuffer = NULL;
3937 if (model->surfmesh.data_vertex3f_vertexbuffer && !model->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
3938 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_vertex3f_vertexbuffer);
3939 model->surfmesh.data_vertex3f_vertexbuffer = NULL;
3940 model->surfmesh.data_svector3f_vertexbuffer = NULL;
3941 model->surfmesh.data_tvector3f_vertexbuffer = NULL;
3942 model->surfmesh.data_normal3f_vertexbuffer = NULL;
3943 model->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
3944 model->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
3945 model->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
3946 model->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
3947 model->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
3949 // convert all triangles to unique vertex data
3951 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3953 surface = model->data_surfaces + surfaceindex;
3954 surface->num_firstvertex = outvertexindex;
3955 surface->num_vertices = surface->num_triangles*3;
3956 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
3957 for (i = 0;i < surface->num_triangles*3;i++)
3960 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
3961 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
3962 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
3963 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
3964 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
3965 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
3966 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
3967 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
3968 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
3969 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
3970 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
3971 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
3972 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
3973 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
3974 if (oldsurfmesh.data_texcoordlightmap2f)
3976 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
3977 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
3979 if (oldsurfmesh.data_lightmapcolor4f)
3981 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
3982 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
3983 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
3984 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
3987 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
3988 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
3992 if (model->surfmesh.data_element3s)
3993 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
3994 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
3996 // find and update all submodels to use this new surfmesh data
3997 for (i = 0;i < model->brush.numsubmodels;i++)
3998 model->brush.submodels[i]->surfmesh = model->surfmesh;
4001 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4003 msurface_t *surface;
4009 lightmaptriangle_t *triangle;
4010 // generate lightmap triangle structs
4011 mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4012 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4014 surface = model->data_surfaces + surfaceindex;
4015 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4016 for (i = 0;i < surface->num_triangles;i++)
4018 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4019 triangle->triangleindex = surface->num_firsttriangle+i;
4020 triangle->surfaceindex = surfaceindex;
4021 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4022 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4023 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4024 // calculate bounds of triangle
4025 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4026 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4027 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4028 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4029 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4030 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4031 // pick an axial projection based on the triangle normal
4032 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4034 if (fabs(normal[1]) > fabs(normal[axis]))
4036 if (fabs(normal[2]) > fabs(normal[axis]))
4038 triangle->axis = axis;
4043 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4045 if (mod_generatelightmaps_lightmaptriangles)
4046 Mem_Free(mod_generatelightmaps_lightmaptriangles);
4047 mod_generatelightmaps_lightmaptriangles = NULL;
4050 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4052 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4054 msurface_t *surface;
4068 float trianglenormal[3];
4069 float samplecenter[3];
4070 float samplenormal[3];
4076 float lmscalepixels;
4079 float lm_basescalepixels;
4080 int lm_borderpixels;
4084 lightmaptriangle_t *triangle;
4085 unsigned char *lightmappixels;
4086 unsigned char *deluxemappixels;
4087 mod_alloclightmap_state_t lmstate;
4090 // generate lightmap projection information for all triangles
4091 if (model->texturepool == NULL)
4092 model->texturepool = R_AllocTexturePool();
4093 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4094 lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4095 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4096 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4097 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4099 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4101 surface = model->data_surfaces + surfaceindex;
4102 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4103 lmscalepixels = lm_basescalepixels;
4104 for (retry = 0;retry < 30;retry++)
4106 // after a couple failed attempts, degrade quality to make it fit
4108 lmscalepixels *= 0.5f;
4109 for (i = 0;i < surface->num_triangles;i++)
4111 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4112 triangle->lightmapindex = lightmapnumber;
4113 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4114 // pick two planar axes for projection
4115 // lightmap coordinates here are in pixels
4116 // lightmap projections are snapped to pixel grid explicitly, such
4117 // that two neighboring triangles sharing an edge and projection
4118 // axis will have identical sample spacing along their shared edge
4120 for (j = 0;j < 3;j++)
4122 if (j == triangle->axis)
4124 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4125 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4126 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4127 triangle->lmbase[k] = lmmins/lmscalepixels;
4128 triangle->lmscale[k] = lmscalepixels;
4131 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4134 // if all fit in this texture, we're done with this surface
4135 if (i == surface->num_triangles)
4137 // if we haven't maxed out the lightmap size yet, we retry the
4138 // entire surface batch...
4139 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4141 lm_texturesize *= 2;
4144 Mod_AllocLightmap_Free(&lmstate);
4145 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4148 // if we have maxed out the lightmap size, and this triangle does
4149 // not fit in the same texture as the rest of the surface, we have
4150 // to retry the entire surface in a new texture (can only use one)
4151 // with multiple retries, the lightmap quality degrades until it
4152 // fits (or gives up)
4153 if (surfaceindex > 0)
4155 Mod_AllocLightmap_Reset(&lmstate);
4159 Mod_AllocLightmap_Free(&lmstate);
4161 // now put triangles together into lightmap textures, and do not allow
4162 // triangles of a surface to go into different textures (as that would
4163 // require rewriting the surface list)
4164 model->brushq3.deluxemapping_modelspace = true;
4165 model->brushq3.deluxemapping = true;
4166 model->brushq3.num_mergedlightmaps = lightmapnumber;
4167 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4168 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4169 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4170 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4171 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4173 surface = model->data_surfaces + surfaceindex;
4174 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4175 for (i = 0;i < surface->num_triangles;i++)
4177 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4178 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4179 VectorNormalize(trianglenormal);
4180 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4181 axis = triangle->axis;
4182 axis1 = axis == 0 ? 1 : 0;
4183 axis2 = axis == 2 ? 1 : 2;
4184 lmiscale[0] = 1.0f / triangle->lmscale[0];
4185 lmiscale[1] = 1.0f / triangle->lmscale[1];
4186 if (trianglenormal[axis] < 0)
4187 VectorNegate(trianglenormal, trianglenormal);
4188 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4189 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4190 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4191 for (j = 0;j < 3;j++)
4193 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4194 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4195 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4197 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4198 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4199 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4200 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]);
4210 forward[1] = 1.0f / triangle->lmscale[0];
4214 left[2] = 1.0f / triangle->lmscale[1];
4219 origin[1] = triangle->lmbase[0];
4220 origin[2] = triangle->lmbase[1];
4223 forward[0] = 1.0f / triangle->lmscale[0];
4228 left[2] = 1.0f / triangle->lmscale[1];
4232 origin[0] = triangle->lmbase[0];
4234 origin[2] = triangle->lmbase[1];
4237 forward[0] = 1.0f / triangle->lmscale[0];
4241 left[1] = 1.0f / triangle->lmscale[1];
4246 origin[0] = triangle->lmbase[0];
4247 origin[1] = triangle->lmbase[1];
4251 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4253 #define LM_DIST_EPSILON (1.0f / 32.0f)
4254 for (y = 0;y < triangle->lmsize[1];y++)
4256 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4257 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4259 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4260 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4261 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4262 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4263 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4269 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4271 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);
4272 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);
4276 Mem_Free(lightmappixels);
4277 if (deluxemappixels)
4278 Mem_Free(deluxemappixels);
4280 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4282 surface = model->data_surfaces + surfaceindex;
4283 if (!surface->num_triangles)
4285 lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4286 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4287 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4288 surface->lightmapinfo = NULL;
4291 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4292 model->brushq1.lightdata = NULL;
4293 model->brushq1.lightmapupdateflags = NULL;
4294 model->brushq1.firstrender = false;
4295 model->brushq1.num_lightstyles = 0;
4296 model->brushq1.data_lightstyleinfo = NULL;
4297 for (i = 0;i < model->brush.numsubmodels;i++)
4299 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4300 model->brush.submodels[i]->brushq1.firstrender = false;
4301 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4302 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4306 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4309 for (i = 0;i < model->surfmesh.num_vertices;i++)
4310 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4313 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4320 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4322 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4323 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4325 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4326 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4328 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4329 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4335 extern cvar_t mod_q3bsp_nolightmaps;
4336 static void Mod_GenerateLightmaps(dp_model_t *model)
4338 //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4339 dp_model_t *oldloadmodel = loadmodel;
4342 Mod_GenerateLightmaps_InitSampleOffsets(model);
4343 Mod_GenerateLightmaps_DestroyLightmaps(model);
4344 Mod_GenerateLightmaps_UnweldTriangles(model);
4345 Mod_GenerateLightmaps_CreateTriangleInformation(model);
4346 Mod_GenerateLightmaps_CreateLights(model);
4347 if(!mod_q3bsp_nolightmaps.integer)
4348 Mod_GenerateLightmaps_CreateLightmaps(model);
4349 Mod_GenerateLightmaps_UpdateVertexColors(model);
4350 Mod_GenerateLightmaps_UpdateLightGrid(model);
4351 Mod_GenerateLightmaps_DestroyLights(model);
4352 Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4354 loadmodel = oldloadmodel;
4357 static void Mod_GenerateLightmaps_f(void)
4359 if (Cmd_Argc() != 1)
4361 Con_Printf("usage: mod_generatelightmaps\n");
4366 Con_Printf("no worldmodel loaded\n");
4369 Mod_GenerateLightmaps(cl.worldmodel);
4372 void Mod_Mesh_Create(dp_model_t *mod, const char *name)
4374 memset(mod, 0, sizeof(*mod));
4375 strlcpy(mod->name, name, sizeof(mod->name));
4376 mod->mempool = Mem_AllocPool(name, 0, NULL);
4377 mod->texturepool = R_AllocTexturePool();
4378 mod->Draw = R_Q1BSP_Draw;
4379 mod->DrawDepth = R_Q1BSP_DrawDepth;
4380 mod->DrawDebug = R_Q1BSP_DrawDebug;
4381 mod->DrawPrepass = R_Q1BSP_DrawPrepass;
4382 mod->GetLightInfo = R_Q1BSP_GetLightInfo;
4383 mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
4384 mod->DrawLight = R_Q1BSP_DrawLight;
4387 void Mod_Mesh_Destroy(dp_model_t *mod)
4389 Mod_UnloadModel(mod);
4392 // resets the mesh model to have no geometry to render, ready for a new frame -
4393 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4394 void Mod_Mesh_Reset(dp_model_t *mod)
4396 mod->num_surfaces = 0;
4397 mod->surfmesh.num_vertices = 0;
4398 mod->surfmesh.num_triangles = 0;
4399 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4400 mod->DrawSky = NULL; // will be set if a texture needs it
4401 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4404 texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
4408 for (i = 0; i < mod->num_textures; i++)
4409 if (!strcmp(mod->data_textures[i].name, name))
4410 return mod->data_textures + i;
4411 if (mod->max_textures <= mod->num_textures)
4413 texture_t *oldtextures = mod->data_textures;
4414 mod->max_textures = max(mod->max_textures * 2, 1024);
4415 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4416 // update the pointers
4417 for (i = 0; i < mod->num_surfaces; i++)
4418 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4420 t = &mod->data_textures[mod->num_textures++];
4421 Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
4422 switch (defaultdrawflags & DRAWFLAG_MASK)
4424 case DRAWFLAG_ADDITIVE:
4425 t->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED;
4426 t->currentmaterialflags = t->basematerialflags;
4428 case DRAWFLAG_MODULATE:
4429 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4430 t->currentmaterialflags = t->basematerialflags;
4431 t->customblendfunc[0] = GL_DST_COLOR;
4432 t->customblendfunc[1] = GL_ZERO;
4434 case DRAWFLAG_2XMODULATE:
4435 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4436 t->currentmaterialflags = t->basematerialflags;
4437 t->customblendfunc[0] = GL_DST_COLOR;
4438 t->customblendfunc[1] = GL_SRC_COLOR;
4440 case DRAWFLAG_SCREEN:
4441 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4442 t->currentmaterialflags = t->basematerialflags;
4443 t->customblendfunc[0] = GL_ONE_MINUS_DST_COLOR;
4444 t->customblendfunc[1] = GL_ONE;
4452 msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface)
4455 // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
4456 if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex)
4457 return mod->data_surfaces + mod->num_surfaces - 1;
4458 // create new surface
4459 if (mod->max_surfaces == mod->num_surfaces)
4461 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4462 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4463 mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
4465 surf = mod->data_surfaces + mod->num_surfaces;
4466 mod->num_surfaces++;
4467 memset(surf, 0, sizeof(*surf));
4468 surf->texture = tex;
4469 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4470 surf->num_firstvertex = mod->surfmesh.num_vertices;
4471 if (tex->basematerialflags & (MATERIALFLAG_SKY))
4472 mod->DrawSky = R_Q1BSP_DrawSky;
4473 if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4474 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
4478 int Mod_Mesh_IndexForVertex(dp_model_t *mod, msurface_t *surf, float x, float y, float z, float nx, float ny, float nz, float s, float t, float u, float v, float r, float g, float b, float a)
4480 int hashindex, h, vnum, mask;
4481 surfmesh_t *mesh = &mod->surfmesh;
4482 if (mesh->max_vertices == mesh->num_vertices)
4484 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4485 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4486 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4487 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4488 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4489 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4490 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4491 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4492 // rebuild the hash table
4493 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4494 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4495 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4496 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4497 mask = mod->surfmesh.num_vertexhashsize - 1;
4498 // no need to hash the vertices for the entire model, the latest surface will suffice.
4499 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4501 // this uses prime numbers intentionally for computing the hash
4502 hashindex = (unsigned int)(mesh->data_vertex3f[vnum * 3 + 0] * 2003 + mesh->data_vertex3f[vnum * 3 + 1] * 4001 + mesh->data_vertex3f[vnum * 3 + 2] * 7919 + mesh->data_normal3f[vnum * 3 + 0] * 4097 + mesh->data_normal3f[vnum * 3 + 1] * 257 + mesh->data_normal3f[vnum * 3 + 2] * 17) & mask;
4503 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4504 ; // just iterate until we find the terminator
4505 mesh->data_vertexhash[h] = vnum;
4508 mask = mod->surfmesh.num_vertexhashsize - 1;
4509 // this uses prime numbers intentionally for computing the hash
4510 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4511 // when possible find an identical vertex within the same surface and return it
4512 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4514 if (vnum >= surf->num_firstvertex
4515 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4516 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4517 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4518 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4519 && mesh->data_lightmapcolor4f[vnum * 4 + 0] == r && mesh->data_lightmapcolor4f[vnum * 4 + 1] == g && mesh->data_lightmapcolor4f[vnum * 4 + 2] == b && mesh->data_lightmapcolor4f[vnum * 4 + 3] == a)
4522 // add the new vertex
4523 vnum = mesh->num_vertices++;
4524 if (surf->num_vertices > 0)
4526 if (surf->mins[0] > x) surf->mins[0] = x;
4527 if (surf->mins[1] > y) surf->mins[1] = y;
4528 if (surf->mins[2] > z) surf->mins[2] = z;
4529 if (surf->maxs[0] < x) surf->maxs[0] = x;
4530 if (surf->maxs[1] < y) surf->maxs[1] = y;
4531 if (surf->maxs[2] < z) surf->maxs[2] = z;
4535 VectorSet(surf->mins, x, y, z);
4536 VectorSet(surf->maxs, x, y, z);
4538 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4539 mesh->data_vertexhash[h] = vnum;
4540 mesh->data_vertex3f[vnum * 3 + 0] = x;
4541 mesh->data_vertex3f[vnum * 3 + 1] = y;
4542 mesh->data_vertex3f[vnum * 3 + 2] = z;
4543 mesh->data_normal3f[vnum * 3 + 0] = nx;
4544 mesh->data_normal3f[vnum * 3 + 1] = ny;
4545 mesh->data_normal3f[vnum * 3 + 2] = nz;
4546 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4547 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4548 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4549 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4550 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4551 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4552 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4553 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4557 void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4559 surfmesh_t *mesh = &mod->surfmesh;
4560 if (mesh->max_triangles == mesh->num_triangles)
4562 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4563 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4564 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4566 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4567 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4568 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4569 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4570 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4571 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4572 mesh->num_triangles++;
4573 surf->num_triangles++;
4576 static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
4580 msurface_t *surf, *surf2;
4582 // build the sorted surfaces list properly to reduce material setup
4583 // this is easy because we're just sorting on texture and don't care about the order of textures
4584 mod->nummodelsurfaces = 0;
4585 for (i = 0; i < mod->num_surfaces; i++)
4586 mod->data_surfaces[i].included = false;
4587 for (i = 0; i < mod->num_surfaces; i++)
4589 surf = mod->data_surfaces + i;
4592 tex = surf->texture;
4593 // j = i is intentional
4594 for (j = i; j < mod->num_surfaces; j++)
4596 surf2 = mod->data_surfaces + j;
4597 if (surf2->included)
4599 if (surf2->texture == tex)
4601 surf2->included = true;
4602 mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
4608 void Mod_Mesh_ComputeBounds(dp_model_t *mod)
4611 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4613 if (mod->surfmesh.num_vertices > 0)
4615 // calculate normalmins/normalmaxs
4616 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4617 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4618 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4620 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4621 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4622 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4623 // expand bounds to include this vertex
4624 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4625 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4626 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4627 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4628 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4629 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4631 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4632 // (fast but less accurate than doing it per vertex)
4633 x2a = mod->normalmins[0] * mod->normalmins[0];
4634 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4635 y2a = mod->normalmins[1] * mod->normalmins[1];
4636 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4637 z2a = mod->normalmins[2] * mod->normalmins[2];
4638 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4642 yawradius = sqrt(x2 + y2);
4643 rotatedradius = sqrt(x2 + y2 + z2);
4644 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4645 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4646 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4647 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4648 mod->radius = rotatedradius;
4649 mod->radius2 = x2 + y2 + z2;
4653 VectorClear(mod->normalmins);
4654 VectorClear(mod->normalmaxs);
4655 VectorClear(mod->yawmins);
4656 VectorClear(mod->yawmaxs);
4657 VectorClear(mod->rotatedmins);
4658 VectorClear(mod->rotatedmaxs);
4664 void Mod_Mesh_Validate(dp_model_t *mod)
4667 qboolean warned = false;
4668 for (i = 0; i < mod->num_surfaces; i++)
4670 msurface_t *surf = mod->data_surfaces + i;
4671 int *e = mod->surfmesh.data_element3i + surf->num_firsttriangle * 3;
4672 int first = surf->num_firstvertex;
4673 int end = surf->num_firstvertex + surf->num_vertices;
4675 for (j = 0;j < surf->num_triangles * 3;j++)
4677 if (e[j] < first || e[j] >= end)
4680 Con_DPrintf("Mod_Mesh_Validate: detected corrupt surface - debug me!\n");
4688 void Mod_Mesh_UploadDynamicBuffers(dp_model_t *mod)
4690 mod->surfmesh.data_element3s_indexbuffer = mod->surfmesh.data_element3s ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(short[3]), mod->surfmesh.data_element3s, R_BUFFERDATA_INDEX16, &mod->surfmesh.data_element3s_bufferoffset) : NULL;
4691 mod->surfmesh.data_element3i_indexbuffer = mod->surfmesh.data_element3i ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(int[3]), mod->surfmesh.data_element3i, R_BUFFERDATA_INDEX32, &mod->surfmesh.data_element3i_bufferoffset) : NULL;
4692 mod->surfmesh.data_vertex3f_vertexbuffer = mod->surfmesh.data_vertex3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_vertex3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_vertex3f_bufferoffset) : NULL;
4693 mod->surfmesh.data_svector3f_vertexbuffer = mod->surfmesh.data_svector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_svector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_svector3f_bufferoffset) : NULL;
4694 mod->surfmesh.data_tvector3f_vertexbuffer = mod->surfmesh.data_tvector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_tvector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_tvector3f_bufferoffset) : NULL;
4695 mod->surfmesh.data_normal3f_vertexbuffer = mod->surfmesh.data_normal3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_normal3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_normal3f_bufferoffset) : NULL;
4696 mod->surfmesh.data_texcoordtexture2f_vertexbuffer = mod->surfmesh.data_texcoordtexture2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordtexture2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordtexture2f_bufferoffset) : NULL;
4697 mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = mod->surfmesh.data_texcoordlightmap2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordlightmap2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordlightmap2f_bufferoffset) : NULL;
4698 mod->surfmesh.data_lightmapcolor4f_vertexbuffer = mod->surfmesh.data_lightmapcolor4f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[4]), mod->surfmesh.data_lightmapcolor4f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_lightmapcolor4f_bufferoffset) : NULL;
4699 mod->surfmesh.data_skeletalindex4ub_vertexbuffer = mod->surfmesh.data_skeletalindex4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalindex4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalindex4ub_bufferoffset) : NULL;
4700 mod->surfmesh.data_skeletalweight4ub_vertexbuffer = mod->surfmesh.data_skeletalweight4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalweight4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalweight4ub_bufferoffset) : NULL;
4703 void Mod_Mesh_Finalize(dp_model_t *mod)
4705 if (gl_paranoid.integer)
4706 Mod_Mesh_Validate(mod);
4707 Mod_Mesh_ComputeBounds(mod);
4708 Mod_Mesh_MakeSortedSurfaces(mod);
4709 Mod_BuildTextureVectorsFromNormals(0, mod->surfmesh.num_vertices, mod->surfmesh.num_triangles, mod->surfmesh.data_vertex3f, mod->surfmesh.data_texcoordtexture2f, mod->surfmesh.data_normal3f, mod->surfmesh.data_element3i, mod->surfmesh.data_svector3f, mod->surfmesh.data_tvector3f, true);
4710 Mod_Mesh_UploadDynamicBuffers(mod);