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 (!loadmodel->surfmesh.num_vertices)
2899 if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
2902 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2904 if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
2906 Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
2907 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
2912 // upload short indices as a buffer
2913 if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
2914 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);
2916 // upload int indices as a buffer
2917 if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
2918 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);
2920 // only build a vbo if one has not already been created (this is important for brush models which load specially)
2921 // we put several vertex data streams in the same buffer
2922 if (!loadmodel->surfmesh.data_vertex3f_vertexbuffer)
2927 loadmodel->surfmesh.data_vertex3f_bufferoffset = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2928 loadmodel->surfmesh.data_svector3f_bufferoffset = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2929 loadmodel->surfmesh.data_tvector3f_bufferoffset = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2930 loadmodel->surfmesh.data_normal3f_bufferoffset = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
2931 loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2932 loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
2933 loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
2934 loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2935 loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
2936 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
2937 if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.data_vertex3f_bufferoffset , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2938 if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.data_svector3f_bufferoffset , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2939 if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.data_tvector3f_bufferoffset , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2940 if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.data_normal3f_bufferoffset , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
2941 if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.data_texcoordtexture2f_bufferoffset , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
2942 if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.data_texcoordlightmap2f_bufferoffset, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
2943 if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.data_lightmapcolor4f_bufferoffset , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
2944 if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.data_skeletalindex4ub_bufferoffset , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2945 if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.data_skeletalweight4ub_bufferoffset , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
2946 loadmodel->surfmesh.data_vertex3f_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
2947 loadmodel->surfmesh.data_svector3f_vertexbuffer = loadmodel->surfmesh.data_svector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2948 loadmodel->surfmesh.data_tvector3f_vertexbuffer = loadmodel->surfmesh.data_tvector3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2949 loadmodel->surfmesh.data_normal3f_vertexbuffer = loadmodel->surfmesh.data_normal3f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2950 loadmodel->surfmesh.data_texcoordtexture2f_vertexbuffer = loadmodel->surfmesh.data_texcoordtexture2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2951 loadmodel->surfmesh.data_texcoordlightmap2f_vertexbuffer = loadmodel->surfmesh.data_texcoordlightmap2f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2952 loadmodel->surfmesh.data_lightmapcolor4f_vertexbuffer = loadmodel->surfmesh.data_lightmapcolor4f ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2953 loadmodel->surfmesh.data_skeletalindex4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalindex4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2954 loadmodel->surfmesh.data_skeletalweight4ub_vertexbuffer = loadmodel->surfmesh.data_skeletalweight4ub ? loadmodel->surfmesh.data_vertex3f_vertexbuffer : NULL;
2959 extern cvar_t mod_obj_orientation;
2960 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
2962 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
2964 const char *texname;
2966 const float *v, *vn, *vt;
2968 size_t outbufferpos = 0;
2969 size_t outbuffermax = 0x100000;
2970 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
2971 const msurface_t *surface;
2972 const int maxtextures = 256;
2973 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
2974 dp_model_t *submodel;
2976 // construct the mtllib file
2977 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
2980 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
2983 countvertices += surface->num_vertices;
2984 countfaces += surface->num_triangles;
2985 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
2986 for (textureindex = 0;textureindex < counttextures;textureindex++)
2987 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
2989 if (textureindex < counttextures)
2990 continue; // already wrote this material entry
2991 if (textureindex >= maxtextures)
2992 continue; // just a precaution
2993 textureindex = counttextures++;
2994 strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
2995 if (outbufferpos >= outbuffermax >> 1)
2998 oldbuffer = outbuffer;
2999 outbuffer = (char *) Z_Malloc(outbuffermax);
3000 memcpy(outbuffer, oldbuffer, outbufferpos);
3003 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");
3008 // write the mtllib file
3009 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3011 // construct the obj file
3013 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);
3017 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)
3019 if (outbufferpos >= outbuffermax >> 1)
3022 oldbuffer = outbuffer;
3023 outbuffer = (char *) Z_Malloc(outbuffermax);
3024 memcpy(outbuffer, oldbuffer, outbufferpos);
3027 if(mod_obj_orientation.integer)
3028 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]);
3030 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]);
3035 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3037 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3040 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3041 for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3043 surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3044 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3047 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3049 if (outbufferpos >= outbuffermax >> 1)
3052 oldbuffer = outbuffer;
3053 outbuffer = (char *) Z_Malloc(outbuffermax);
3054 memcpy(outbuffer, oldbuffer, outbufferpos);
3060 if(mod_obj_orientation.integer)
3061 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);
3063 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);
3070 // write the obj file
3071 FS_WriteFile(filename, outbuffer, outbufferpos);
3075 Z_Free(texturenames);
3078 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3081 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3083 int countnodes = 0, counttriangles = 0, countframes = 0;
3091 size_t outbufferpos = 0;
3092 size_t outbuffermax = 0x100000;
3093 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3094 const msurface_t *surface;
3095 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3098 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3100 if (outbufferpos >= outbuffermax >> 1)
3103 oldbuffer = outbuffer;
3104 outbuffer = (char *) Z_Malloc(outbuffermax);
3105 memcpy(outbuffer, oldbuffer, outbufferpos);
3109 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3113 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3116 for (poseindex = 0;poseindex < numposes;poseindex++)
3119 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3122 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3126 matrix4x4_t posematrix;
3127 if (outbufferpos >= outbuffermax >> 1)
3130 oldbuffer = outbuffer;
3131 outbuffer = (char *) Z_Malloc(outbuffermax);
3132 memcpy(outbuffer, oldbuffer, outbufferpos);
3136 // strangely the smd angles are for a transposed matrix, so we
3137 // have to generate a transposed matrix, then convert that...
3138 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3139 Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3140 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3141 if (angles[0] >= 180) angles[0] -= 360;
3142 if (angles[1] >= 180) angles[1] -= 360;
3143 if (angles[2] >= 180) angles[2] -= 360;
3147 float a = DEG2RAD(angles[ROLL]);
3148 float b = DEG2RAD(angles[PITCH]);
3149 float c = DEG2RAD(angles[YAW]);
3150 float cy, sy, cp, sp, cr, sr;
3152 // smd matrix construction, for comparing
3163 test[1][0] = sr*sp*cy+cr*-sy;
3164 test[1][1] = sr*sp*sy+cr*cy;
3166 test[2][0] = (cr*sp*cy+-sr*-sy);
3167 test[2][1] = (cr*sp*sy+-sr*cy);
3169 test[3][0] = pose[9];
3170 test[3][1] = pose[10];
3171 test[3][2] = pose[11];
3174 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]));
3179 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3184 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3187 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3189 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3192 if (outbufferpos >= outbuffermax >> 1)
3195 oldbuffer = outbuffer;
3196 outbuffer = (char *) Z_Malloc(outbuffermax);
3197 memcpy(outbuffer, oldbuffer, outbufferpos);
3200 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3203 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3205 const int index = e[2-cornerindex];
3206 const float *v = model->surfmesh.data_vertex3f + index * 3;
3207 const float *vn = model->surfmesh.data_normal3f + index * 3;
3208 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3209 const int b = model->surfmesh.blends[index];
3210 if (b < model->num_bones)
3211 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]);
3214 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3215 const unsigned char *wi = w->index;
3216 const unsigned char *wf = w->influence;
3217 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);
3218 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);
3219 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);
3220 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]);
3227 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3232 FS_WriteFile(filename, outbuffer, outbufferpos);
3235 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3242 decompiles a model to editable files
3245 static void Mod_Decompile_f(void)
3247 int i, j, k, l, first, count;
3249 char inname[MAX_QPATH];
3250 char outname[MAX_QPATH];
3251 char mtlname[MAX_QPATH];
3252 char basename[MAX_QPATH];
3253 char animname[MAX_QPATH];
3254 char animname2[MAX_QPATH];
3255 char zymtextbuffer[16384];
3256 char dpmtextbuffer[16384];
3257 char framegroupstextbuffer[16384];
3258 int zymtextsize = 0;
3259 int dpmtextsize = 0;
3260 int framegroupstextsize = 0;
3263 if (Cmd_Argc() != 2)
3265 Con_Print("usage: modeldecompile <filename>\n");
3269 strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3270 FS_StripExtension(inname, basename, sizeof(basename));
3272 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3275 Con_Print("No such model\n");
3278 if (mod->brush.submodel)
3280 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3281 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3282 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3285 if (!mod->surfmesh.num_triangles)
3287 Con_Print("Empty model (or sprite)\n");
3291 // export OBJ if possible (not on sprites)
3292 if (mod->surfmesh.num_triangles)
3294 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3295 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3296 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3299 // export SMD if possible (only for skeletal models)
3300 if (mod->surfmesh.num_triangles && mod->num_bones)
3302 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3303 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3304 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3305 if (l > 0) zymtextsize += l;
3306 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3307 if (l > 0) dpmtextsize += l;
3308 for (i = 0;i < mod->numframes;i = j)
3310 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3311 first = mod->animscenes[i].firstframe;
3312 if (mod->animscenes[i].framecount > 1)
3315 count = mod->animscenes[i].framecount;
3321 // check for additional frames with same name
3322 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3323 if(animname[l] < '0' || animname[l] > '9')
3325 if(k > 0 && animname[k-1] == '_')
3328 count = mod->num_poses - first;
3329 for (j = i + 1;j < mod->numframes;j++)
3331 strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3332 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3333 if(animname2[l] < '0' || animname2[l] > '9')
3335 if(k > 0 && animname[k-1] == '_')
3338 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3340 count = mod->animscenes[j].firstframe - first;
3344 // if it's only one frame, use the original frame name
3346 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3349 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3350 Mod_Decompile_SMD(mod, outname, first, count, false);
3351 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3353 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3354 if (l > 0) zymtextsize += l;
3356 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3358 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3359 if (l > 0) dpmtextsize += l;
3361 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3363 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3364 if (l > 0) framegroupstextsize += l;
3368 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3370 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3371 if (framegroupstextsize)
3372 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3376 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
3379 memset(state, 0, sizeof(*state));
3380 state->width = width;
3381 state->height = height;
3382 state->currentY = 0;
3383 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3384 for (y = 0;y < state->height;y++)
3386 state->rows[y].currentX = 0;
3387 state->rows[y].rowY = -1;
3391 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3394 state->currentY = 0;
3395 for (y = 0;y < state->height;y++)
3397 state->rows[y].currentX = 0;
3398 state->rows[y].rowY = -1;
3402 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3405 Mem_Free(state->rows);
3406 memset(state, 0, sizeof(*state));
3409 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3411 mod_alloclightmap_row_t *row;
3414 row = state->rows + blockheight;
3415 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3417 if (state->currentY + blockheight <= state->height)
3419 // use the current allocation position
3420 row->rowY = state->currentY;
3422 state->currentY += blockheight;
3426 // find another position
3427 for (y = blockheight;y < state->height;y++)
3429 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3431 row = state->rows + y;
3435 if (y == state->height)
3440 *outx = row->currentX;
3441 row->currentX += blockwidth;
3446 typedef struct lightmapsample_s
3450 float *vertex_color;
3451 unsigned char *lm_bgr;
3452 unsigned char *lm_dir;
3456 typedef struct lightmapvertex_s
3461 float texcoordbase[2];
3462 float texcoordlightmap[2];
3463 float lightcolor[4];
3467 typedef struct lightmaptriangle_s
3475 // 2D modelspace coordinates of min corner
3476 // snapped to lightmap grid but not in grid coordinates
3478 // 2D modelspace to lightmap coordinate scale
3486 typedef struct lightmaplight_s
3497 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3499 #define MAX_LIGHTMAPSAMPLES 64
3500 static int mod_generatelightmaps_numoffsets[3];
3501 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3503 static int mod_generatelightmaps_numlights;
3504 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3506 extern cvar_t r_shadow_lightattenuationdividebias;
3507 extern cvar_t r_shadow_lightattenuationlinearscale;
3509 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3514 float relativepoint[3];
3521 float lightorigin[3];
3525 float lightcolor[3];
3527 for (i = 0;i < 5*3;i++)
3529 for (index = 0;;index++)
3531 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3536 lightradius2 = lightradius * lightradius;
3537 VectorSubtract(lightorigin, pos, relativepoint);
3538 dist2 = VectorLength2(relativepoint);
3539 if (dist2 >= lightradius2)
3541 lightiradius = 1.0f / lightradius;
3542 dist = sqrt(dist2) * lightiradius;
3543 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3544 if (intensity <= 0.0f)
3546 if (model && model->TraceLine)
3548 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3549 if (trace.fraction < 1)
3552 // scale down intensity to add to both ambient and diffuse
3553 //intensity *= 0.5f;
3554 VectorNormalize(relativepoint);
3555 VectorScale(lightcolor, intensity, color);
3556 VectorMA(sample , 0.5f , color, sample );
3557 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3558 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3559 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3560 // calculate a weighted average light direction as well
3561 intensity *= VectorLength(color);
3562 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3564 // calculate the direction we'll use to reduce the sample to a directional light source
3565 VectorCopy(sample + 12, dir);
3566 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3567 VectorNormalize(dir);
3568 // extract the diffuse color along the chosen direction and scale it
3569 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3570 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3571 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3572 // subtract some of diffuse from ambient
3573 VectorMA(sample, -0.333f, diffuse, ambient);
3574 // store the normalized lightdir
3575 VectorCopy(dir, lightdir);
3578 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3582 const msurface_t *surface;
3583 const float *vertex3f = model->surfmesh.data_vertex3f;
3584 const int *element3i = model->surfmesh.data_element3i;
3587 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3589 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3591 if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3593 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3595 VectorCopy(vertex3f + 3*e[0], v2[0]);
3596 VectorCopy(vertex3f + 3*e[1], v2[1]);
3597 VectorCopy(vertex3f + 3*e[2], v2[2]);
3598 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3603 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3605 int maxnodes = 1<<14;
3606 svbsp_node_t *nodes;
3611 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3612 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3613 VectorCopy(lightinfo->origin, origin);
3614 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3617 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3618 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3619 if (svbsp.ranoutofnodes)
3622 if (maxnodes > 1<<22)
3628 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3633 if (svbsp.numnodes > 0)
3635 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3636 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3637 lightinfo->svbsp = svbsp;
3642 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3646 lightmaplight_t *lightinfo;
3650 mod_generatelightmaps_numlights = 0;
3651 for (index = 0;;index++)
3653 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3657 mod_generatelightmaps_numlights++;
3659 if (mod_generatelightmaps_numlights > 0)
3661 mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3662 lightinfo = mod_generatelightmaps_lightinfo;
3663 for (index = 0;;index++)
3665 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3672 for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3674 lightinfo->iradius = 1.0f / lightinfo->radius;
3675 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3676 // TODO: compute svbsp
3677 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3681 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3684 if (mod_generatelightmaps_lightinfo)
3686 for (i = 0;i < mod_generatelightmaps_numlights;i++)
3687 if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3688 Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3689 Mem_Free(mod_generatelightmaps_lightinfo);
3691 mod_generatelightmaps_lightinfo = NULL;
3692 mod_generatelightmaps_numlights = 0;
3695 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3697 const svbsp_node_t *node;
3698 const svbsp_node_t *nodes = svbsp->nodes;
3703 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3705 return num == -1; // true if empty, false if solid (shadowed)
3708 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3711 float relativepoint[3];
3720 const lightmaplight_t *lightinfo;
3722 for (i = 0;i < 5*3;i++)
3724 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3726 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3727 VectorSubtract(lightinfo->origin, pos, relativepoint);
3728 // don't accept light from behind a surface, it causes bad shading
3729 if (normal && DotProduct(relativepoint, normal) <= 0)
3731 dist2 = VectorLength2(relativepoint);
3732 if (dist2 >= lightinfo->radius2)
3734 dist = sqrt(dist2) * lightinfo->iradius;
3735 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3738 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3742 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3744 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3746 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3749 // for light grid we'd better check visibility of the offset point
3750 cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3751 if (trace.fraction < 1)
3752 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3755 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3760 // scale intensity according to how many rays succeeded
3761 // we know one test is valid, half of the rest will fail...
3762 //if (normal && tests > 1)
3763 // intensity *= (tests - 1.0f) / tests;
3764 intensity *= (float)hits / tests;
3766 // scale down intensity to add to both ambient and diffuse
3767 //intensity *= 0.5f;
3768 VectorNormalize(relativepoint);
3769 VectorScale(lightinfo->color, intensity, color);
3770 VectorMA(sample , 0.5f , color, sample );
3771 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3772 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3773 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3774 // calculate a weighted average light direction as well
3775 intensity *= VectorLength(color);
3776 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3780 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3786 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
3787 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3788 VectorCopy(sample + 12, dir);
3789 VectorNormalize(dir);
3790 //VectorAdd(dir, normal, dir);
3791 //VectorNormalize(dir);
3792 f = DotProduct(dir, normal);
3793 f = max(0, f) * 255.0f;
3794 VectorScale(sample, f, color);
3795 //VectorCopy(normal, dir);
3796 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3797 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3798 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3799 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3801 lm_dir[0] = (unsigned char)dir[2];
3802 lm_dir[1] = (unsigned char)dir[1];
3803 lm_dir[2] = (unsigned char)dir[0];
3807 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3810 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
3811 VectorCopy(sample, vertex_color);
3814 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3820 Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
3821 // calculate the direction we'll use to reduce the sample to a directional light source
3822 VectorCopy(sample + 12, dir);
3823 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3824 VectorNormalize(dir);
3825 // extract the diffuse color along the chosen direction and scale it
3826 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3827 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3828 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3829 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3830 VectorScale(sample, 127.5f, ambient);
3831 VectorMA(ambient, -0.333f, diffuse, ambient);
3832 // encode to the grid format
3833 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3834 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3835 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3836 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3837 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3838 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3839 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3840 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3841 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));}
3844 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
3849 memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
3850 mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
3851 mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
3852 mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
3853 radius[0] = mod_generatelightmaps_lightmapradius.value;
3854 radius[1] = mod_generatelightmaps_vertexradius.value;
3855 radius[2] = mod_generatelightmaps_gridradius.value;
3856 for (i = 0;i < 3;i++)
3858 for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
3861 VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
3866 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
3868 msurface_t *surface;
3871 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3873 surface = model->data_surfaces + surfaceindex;
3874 surface->lightmaptexture = NULL;
3875 surface->deluxemaptexture = NULL;
3877 if (model->brushq3.data_lightmaps)
3879 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3880 if (model->brushq3.data_lightmaps[i])
3881 R_FreeTexture(model->brushq3.data_lightmaps[i]);
3882 Mem_Free(model->brushq3.data_lightmaps);
3883 model->brushq3.data_lightmaps = NULL;
3885 if (model->brushq3.data_deluxemaps)
3887 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3888 if (model->brushq3.data_deluxemaps[i])
3889 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
3890 Mem_Free(model->brushq3.data_deluxemaps);
3891 model->brushq3.data_deluxemaps = NULL;
3895 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
3897 msurface_t *surface;
3903 surfmesh_t oldsurfmesh;
3905 unsigned char *data;
3906 oldsurfmesh = model->surfmesh;
3907 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
3908 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
3910 size += model->surfmesh.num_vertices * sizeof(float[3]);
3911 size += model->surfmesh.num_vertices * sizeof(float[3]);
3912 size += model->surfmesh.num_vertices * sizeof(float[3]);
3913 size += model->surfmesh.num_vertices * sizeof(float[3]);
3914 size += model->surfmesh.num_vertices * sizeof(float[2]);
3915 size += model->surfmesh.num_vertices * sizeof(float[2]);
3916 size += model->surfmesh.num_vertices * sizeof(float[4]);
3917 data = (unsigned char *)Mem_Alloc(model->mempool, size);
3918 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3919 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3920 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3921 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3922 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3923 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3924 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
3925 if (model->surfmesh.num_vertices > 65536)
3926 model->surfmesh.data_element3s = NULL;
3928 if (model->surfmesh.data_element3i_indexbuffer && !model->surfmesh.data_element3i_indexbuffer->isdynamic)
3929 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
3930 model->surfmesh.data_element3i_indexbuffer = NULL;
3931 if (model->surfmesh.data_element3s_indexbuffer && !model->surfmesh.data_element3s_indexbuffer->isdynamic)
3932 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
3933 model->surfmesh.data_element3s_indexbuffer = NULL;
3934 if (model->surfmesh.data_vertex3f_vertexbuffer && !model->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
3935 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_vertex3f_vertexbuffer);
3936 model->surfmesh.data_vertex3f_vertexbuffer = NULL;
3937 model->surfmesh.data_svector3f_vertexbuffer = NULL;
3938 model->surfmesh.data_tvector3f_vertexbuffer = NULL;
3939 model->surfmesh.data_normal3f_vertexbuffer = NULL;
3940 model->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
3941 model->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
3942 model->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
3943 model->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
3944 model->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
3946 // convert all triangles to unique vertex data
3948 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3950 surface = model->data_surfaces + surfaceindex;
3951 surface->num_firstvertex = outvertexindex;
3952 surface->num_vertices = surface->num_triangles*3;
3953 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
3954 for (i = 0;i < surface->num_triangles*3;i++)
3957 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
3958 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
3959 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
3960 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
3961 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
3962 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
3963 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
3964 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
3965 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
3966 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
3967 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
3968 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
3969 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
3970 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
3971 if (oldsurfmesh.data_texcoordlightmap2f)
3973 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
3974 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
3976 if (oldsurfmesh.data_lightmapcolor4f)
3978 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
3979 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
3980 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
3981 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
3984 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
3985 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
3989 if (model->surfmesh.data_element3s)
3990 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
3991 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
3993 // find and update all submodels to use this new surfmesh data
3994 for (i = 0;i < model->brush.numsubmodels;i++)
3995 model->brush.submodels[i]->surfmesh = model->surfmesh;
3998 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4000 msurface_t *surface;
4006 lightmaptriangle_t *triangle;
4007 // generate lightmap triangle structs
4008 mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4009 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4011 surface = model->data_surfaces + surfaceindex;
4012 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4013 for (i = 0;i < surface->num_triangles;i++)
4015 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4016 triangle->triangleindex = surface->num_firsttriangle+i;
4017 triangle->surfaceindex = surfaceindex;
4018 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4019 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4020 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4021 // calculate bounds of triangle
4022 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4023 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4024 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4025 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4026 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4027 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4028 // pick an axial projection based on the triangle normal
4029 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4031 if (fabs(normal[1]) > fabs(normal[axis]))
4033 if (fabs(normal[2]) > fabs(normal[axis]))
4035 triangle->axis = axis;
4040 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4042 if (mod_generatelightmaps_lightmaptriangles)
4043 Mem_Free(mod_generatelightmaps_lightmaptriangles);
4044 mod_generatelightmaps_lightmaptriangles = NULL;
4047 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4049 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4051 msurface_t *surface;
4065 float trianglenormal[3];
4066 float samplecenter[3];
4067 float samplenormal[3];
4073 float lmscalepixels;
4076 float lm_basescalepixels;
4077 int lm_borderpixels;
4081 lightmaptriangle_t *triangle;
4082 unsigned char *lightmappixels;
4083 unsigned char *deluxemappixels;
4084 mod_alloclightmap_state_t lmstate;
4087 // generate lightmap projection information for all triangles
4088 if (model->texturepool == NULL)
4089 model->texturepool = R_AllocTexturePool();
4090 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4091 lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4092 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4093 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4094 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4096 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4098 surface = model->data_surfaces + surfaceindex;
4099 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4100 lmscalepixels = lm_basescalepixels;
4101 for (retry = 0;retry < 30;retry++)
4103 // after a couple failed attempts, degrade quality to make it fit
4105 lmscalepixels *= 0.5f;
4106 for (i = 0;i < surface->num_triangles;i++)
4108 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4109 triangle->lightmapindex = lightmapnumber;
4110 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4111 // pick two planar axes for projection
4112 // lightmap coordinates here are in pixels
4113 // lightmap projections are snapped to pixel grid explicitly, such
4114 // that two neighboring triangles sharing an edge and projection
4115 // axis will have identical sample spacing along their shared edge
4117 for (j = 0;j < 3;j++)
4119 if (j == triangle->axis)
4121 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4122 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4123 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4124 triangle->lmbase[k] = lmmins/lmscalepixels;
4125 triangle->lmscale[k] = lmscalepixels;
4128 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4131 // if all fit in this texture, we're done with this surface
4132 if (i == surface->num_triangles)
4134 // if we haven't maxed out the lightmap size yet, we retry the
4135 // entire surface batch...
4136 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4138 lm_texturesize *= 2;
4141 Mod_AllocLightmap_Free(&lmstate);
4142 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4145 // if we have maxed out the lightmap size, and this triangle does
4146 // not fit in the same texture as the rest of the surface, we have
4147 // to retry the entire surface in a new texture (can only use one)
4148 // with multiple retries, the lightmap quality degrades until it
4149 // fits (or gives up)
4150 if (surfaceindex > 0)
4152 Mod_AllocLightmap_Reset(&lmstate);
4156 Mod_AllocLightmap_Free(&lmstate);
4158 // now put triangles together into lightmap textures, and do not allow
4159 // triangles of a surface to go into different textures (as that would
4160 // require rewriting the surface list)
4161 model->brushq3.deluxemapping_modelspace = true;
4162 model->brushq3.deluxemapping = true;
4163 model->brushq3.num_mergedlightmaps = lightmapnumber;
4164 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4165 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4166 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4167 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4168 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4170 surface = model->data_surfaces + surfaceindex;
4171 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4172 for (i = 0;i < surface->num_triangles;i++)
4174 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4175 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4176 VectorNormalize(trianglenormal);
4177 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4178 axis = triangle->axis;
4179 axis1 = axis == 0 ? 1 : 0;
4180 axis2 = axis == 2 ? 1 : 2;
4181 lmiscale[0] = 1.0f / triangle->lmscale[0];
4182 lmiscale[1] = 1.0f / triangle->lmscale[1];
4183 if (trianglenormal[axis] < 0)
4184 VectorNegate(trianglenormal, trianglenormal);
4185 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4186 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4187 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4188 for (j = 0;j < 3;j++)
4190 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4191 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4192 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4194 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4195 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4196 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4197 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]);
4207 forward[1] = 1.0f / triangle->lmscale[0];
4211 left[2] = 1.0f / triangle->lmscale[1];
4216 origin[1] = triangle->lmbase[0];
4217 origin[2] = triangle->lmbase[1];
4220 forward[0] = 1.0f / triangle->lmscale[0];
4225 left[2] = 1.0f / triangle->lmscale[1];
4229 origin[0] = triangle->lmbase[0];
4231 origin[2] = triangle->lmbase[1];
4234 forward[0] = 1.0f / triangle->lmscale[0];
4238 left[1] = 1.0f / triangle->lmscale[1];
4243 origin[0] = triangle->lmbase[0];
4244 origin[1] = triangle->lmbase[1];
4248 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4250 #define LM_DIST_EPSILON (1.0f / 32.0f)
4251 for (y = 0;y < triangle->lmsize[1];y++)
4253 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4254 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4256 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4257 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4258 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4259 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4260 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4266 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4268 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);
4269 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);
4273 Mem_Free(lightmappixels);
4274 if (deluxemappixels)
4275 Mem_Free(deluxemappixels);
4277 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4279 surface = model->data_surfaces + surfaceindex;
4280 if (!surface->num_triangles)
4282 lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4283 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4284 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4285 surface->lightmapinfo = NULL;
4288 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4289 model->brushq1.lightdata = NULL;
4290 model->brushq1.lightmapupdateflags = NULL;
4291 model->brushq1.firstrender = false;
4292 model->brushq1.num_lightstyles = 0;
4293 model->brushq1.data_lightstyleinfo = NULL;
4294 for (i = 0;i < model->brush.numsubmodels;i++)
4296 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4297 model->brush.submodels[i]->brushq1.firstrender = false;
4298 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4299 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4303 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4306 for (i = 0;i < model->surfmesh.num_vertices;i++)
4307 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4310 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4317 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4319 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4320 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4322 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4323 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4325 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4326 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4332 extern cvar_t mod_q3bsp_nolightmaps;
4333 static void Mod_GenerateLightmaps(dp_model_t *model)
4335 //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4336 dp_model_t *oldloadmodel = loadmodel;
4339 Mod_GenerateLightmaps_InitSampleOffsets(model);
4340 Mod_GenerateLightmaps_DestroyLightmaps(model);
4341 Mod_GenerateLightmaps_UnweldTriangles(model);
4342 Mod_GenerateLightmaps_CreateTriangleInformation(model);
4343 Mod_GenerateLightmaps_CreateLights(model);
4344 if(!mod_q3bsp_nolightmaps.integer)
4345 Mod_GenerateLightmaps_CreateLightmaps(model);
4346 Mod_GenerateLightmaps_UpdateVertexColors(model);
4347 Mod_GenerateLightmaps_UpdateLightGrid(model);
4348 Mod_GenerateLightmaps_DestroyLights(model);
4349 Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4351 loadmodel = oldloadmodel;
4354 static void Mod_GenerateLightmaps_f(void)
4356 if (Cmd_Argc() != 1)
4358 Con_Printf("usage: mod_generatelightmaps\n");
4363 Con_Printf("no worldmodel loaded\n");
4366 Mod_GenerateLightmaps(cl.worldmodel);
4369 void Mod_Mesh_Create(dp_model_t *mod, const char *name)
4371 memset(mod, 0, sizeof(*mod));
4372 strlcpy(mod->name, name, sizeof(mod->name));
4373 mod->mempool = Mem_AllocPool(name, 0, NULL);
4374 mod->texturepool = R_AllocTexturePool();
4375 mod->Draw = R_Q1BSP_Draw;
4376 mod->DrawDepth = R_Q1BSP_DrawDepth;
4377 mod->DrawDebug = R_Q1BSP_DrawDebug;
4378 mod->DrawPrepass = R_Q1BSP_DrawPrepass;
4379 mod->GetLightInfo = R_Q1BSP_GetLightInfo;
4380 mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
4381 mod->DrawLight = R_Q1BSP_DrawLight;
4384 void Mod_Mesh_Destroy(dp_model_t *mod)
4386 Mod_UnloadModel(mod);
4389 // resets the mesh model to have no geometry to render, ready for a new frame -
4390 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4391 void Mod_Mesh_Reset(dp_model_t *mod)
4393 mod->num_surfaces = 0;
4394 mod->surfmesh.num_vertices = 0;
4395 mod->surfmesh.num_triangles = 0;
4396 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4397 mod->DrawSky = NULL; // will be set if a texture needs it
4398 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4401 texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
4405 for (i = 0; i < mod->num_textures; i++)
4406 if (!strcmp(mod->data_textures[i].name, name))
4407 return mod->data_textures + i;
4408 if (mod->max_textures <= mod->num_textures)
4410 texture_t *oldtextures = mod->data_textures;
4411 mod->max_textures = max(mod->max_textures * 2, 1024);
4412 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4413 // update the pointers
4414 for (i = 0; i < mod->num_surfaces; i++)
4415 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4417 t = &mod->data_textures[mod->num_textures++];
4418 Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
4419 switch (defaultdrawflags & DRAWFLAG_MASK)
4421 case DRAWFLAG_ADDITIVE:
4422 t->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED;
4423 t->currentmaterialflags = t->basematerialflags;
4425 case DRAWFLAG_MODULATE:
4426 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4427 t->currentmaterialflags = t->basematerialflags;
4428 t->customblendfunc[0] = GL_DST_COLOR;
4429 t->customblendfunc[1] = GL_ZERO;
4431 case DRAWFLAG_2XMODULATE:
4432 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4433 t->currentmaterialflags = t->basematerialflags;
4434 t->customblendfunc[0] = GL_DST_COLOR;
4435 t->customblendfunc[1] = GL_SRC_COLOR;
4437 case DRAWFLAG_SCREEN:
4438 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4439 t->currentmaterialflags = t->basematerialflags;
4440 t->customblendfunc[0] = GL_ONE_MINUS_DST_COLOR;
4441 t->customblendfunc[1] = GL_ONE;
4449 msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface)
4452 // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
4453 if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex)
4454 return mod->data_surfaces + mod->num_surfaces - 1;
4455 // create new surface
4456 if (mod->max_surfaces == mod->num_surfaces)
4458 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4459 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4460 mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
4462 surf = mod->data_surfaces + mod->num_surfaces;
4463 mod->num_surfaces++;
4464 memset(surf, 0, sizeof(*surf));
4465 surf->texture = tex;
4466 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4467 surf->num_firstvertex = mod->surfmesh.num_vertices;
4468 if (tex->basematerialflags & (MATERIALFLAG_SKY))
4469 mod->DrawSky = R_Q1BSP_DrawSky;
4470 if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4471 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
4475 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)
4477 int hashindex, h, vnum, mask;
4478 surfmesh_t *mesh = &mod->surfmesh;
4479 if (mesh->max_vertices == mesh->num_vertices)
4481 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4482 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4483 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4484 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4485 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4486 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4487 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4488 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4489 // rebuild the hash table
4490 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4491 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4492 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4493 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4494 mask = mod->surfmesh.num_vertexhashsize - 1;
4495 // no need to hash the vertices for the entire model, the latest surface will suffice.
4496 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4498 // this uses prime numbers intentionally for computing the hash
4499 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;
4500 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4501 ; // just iterate until we find the terminator
4502 mesh->data_vertexhash[h] = vnum;
4505 mask = mod->surfmesh.num_vertexhashsize - 1;
4506 // this uses prime numbers intentionally for computing the hash
4507 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4508 // when possible find an identical vertex within the same surface and return it
4509 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4511 if (vnum >= surf->num_firstvertex
4512 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4513 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4514 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4515 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4516 && 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)
4519 // add the new vertex
4520 vnum = mesh->num_vertices++;
4521 if (surf->num_vertices > 0)
4523 if (surf->mins[0] > x) surf->mins[0] = x;
4524 if (surf->mins[1] > y) surf->mins[1] = y;
4525 if (surf->mins[2] > z) surf->mins[2] = z;
4526 if (surf->maxs[0] < x) surf->maxs[0] = x;
4527 if (surf->maxs[1] < y) surf->maxs[1] = y;
4528 if (surf->maxs[2] < z) surf->maxs[2] = z;
4532 VectorSet(surf->mins, x, y, z);
4533 VectorSet(surf->maxs, x, y, z);
4535 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4536 mesh->data_vertexhash[h] = vnum;
4537 mesh->data_vertex3f[vnum * 3 + 0] = x;
4538 mesh->data_vertex3f[vnum * 3 + 1] = y;
4539 mesh->data_vertex3f[vnum * 3 + 2] = z;
4540 mesh->data_normal3f[vnum * 3 + 0] = nx;
4541 mesh->data_normal3f[vnum * 3 + 1] = ny;
4542 mesh->data_normal3f[vnum * 3 + 2] = nz;
4543 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4544 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4545 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4546 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4547 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4548 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4549 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4550 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4554 void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4556 surfmesh_t *mesh = &mod->surfmesh;
4557 if (mesh->max_triangles == mesh->num_triangles)
4559 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4560 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4561 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4563 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4564 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4565 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4566 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4567 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4568 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4569 mesh->num_triangles++;
4570 surf->num_triangles++;
4573 static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
4577 msurface_t *surf, *surf2;
4579 // build the sorted surfaces list properly to reduce material setup
4580 // this is easy because we're just sorting on texture and don't care about the order of textures
4581 mod->nummodelsurfaces = 0;
4582 for (i = 0; i < mod->num_surfaces; i++)
4583 mod->data_surfaces[i].included = false;
4584 for (i = 0; i < mod->num_surfaces; i++)
4586 surf = mod->data_surfaces + i;
4589 tex = surf->texture;
4590 // j = i is intentional
4591 for (j = i; j < mod->num_surfaces; j++)
4593 surf2 = mod->data_surfaces + j;
4594 if (surf2->included)
4596 if (surf2->texture == tex)
4598 surf2->included = true;
4599 mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
4605 void Mod_Mesh_ComputeBounds(dp_model_t *mod)
4608 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4610 if (mod->surfmesh.num_vertices > 0)
4612 // calculate normalmins/normalmaxs
4613 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4614 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4615 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4617 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4618 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4619 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4620 // expand bounds to include this vertex
4621 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4622 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4623 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4624 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4625 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4626 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4628 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4629 // (fast but less accurate than doing it per vertex)
4630 x2a = mod->normalmins[0] * mod->normalmins[0];
4631 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4632 y2a = mod->normalmins[1] * mod->normalmins[1];
4633 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4634 z2a = mod->normalmins[2] * mod->normalmins[2];
4635 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4639 yawradius = sqrt(x2 + y2);
4640 rotatedradius = sqrt(x2 + y2 + z2);
4641 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4642 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4643 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4644 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4645 mod->radius = rotatedradius;
4646 mod->radius2 = x2 + y2 + z2;
4650 VectorClear(mod->normalmins);
4651 VectorClear(mod->normalmaxs);
4652 VectorClear(mod->yawmins);
4653 VectorClear(mod->yawmaxs);
4654 VectorClear(mod->rotatedmins);
4655 VectorClear(mod->rotatedmaxs);
4661 void Mod_Mesh_Validate(dp_model_t *mod)
4664 qboolean warned = false;
4665 for (i = 0; i < mod->num_surfaces; i++)
4667 msurface_t *surf = mod->data_surfaces + i;
4668 int *e = mod->surfmesh.data_element3i + surf->num_firsttriangle * 3;
4669 int first = surf->num_firstvertex;
4670 int end = surf->num_firstvertex + surf->num_vertices;
4672 for (j = 0;j < surf->num_triangles * 3;j++)
4674 if (e[j] < first || e[j] >= end)
4677 Con_DPrintf("Mod_Mesh_Validate: detected corrupt surface - debug me!\n");
4685 void Mod_Mesh_UploadDynamicBuffers(dp_model_t *mod)
4687 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;
4688 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;
4689 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;
4690 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;
4691 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;
4692 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;
4693 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;
4694 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;
4695 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;
4696 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;
4697 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;
4700 void Mod_Mesh_Finalize(dp_model_t *mod)
4702 if (gl_paranoid.integer)
4703 Mod_Mesh_Validate(mod);
4704 Mod_Mesh_ComputeBounds(mod);
4705 Mod_Mesh_MakeSortedSurfaces(mod);
4706 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);
4707 Mod_Mesh_UploadDynamicBuffers(mod);