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)
203 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
204 mod->surfmesh.data_element3i_indexbuffer = NULL;
205 if (mod->surfmesh.data_element3s_indexbuffer)
206 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
207 mod->surfmesh.data_element3s_indexbuffer = NULL;
208 if (mod->surfmesh.vbo_vertexbuffer)
209 R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer);
210 mod->surfmesh.vbo_vertexbuffer = NULL;
212 // free textures/memory attached to the model
213 R_FreeTexturePool(&mod->texturepool);
214 Mem_FreePool(&mod->mempool);
215 // clear the struct to make it available
216 memset(mod, 0, sizeof(dp_model_t));
217 // restore the fields we want to preserve
218 strlcpy(mod->name, name, sizeof(mod->name));
219 mod->brush.parentmodel = parentmodel;
224 static void R_Model_Null_Draw(entity_render_t *ent)
230 typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
232 static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
247 // REQUIRED: fetch start
248 COM_ParseToken_Simple(&bufptr, true, false, true);
250 break; // end of file
251 if (!strcmp(com_token, "\n"))
252 continue; // empty line
253 start = atoi(com_token);
255 // REQUIRED: fetch length
256 COM_ParseToken_Simple(&bufptr, true, false, true);
257 if (!bufptr || !strcmp(com_token, "\n"))
259 Con_Printf("framegroups file: missing number of frames\n");
262 len = atoi(com_token);
264 // OPTIONAL args start
265 COM_ParseToken_Simple(&bufptr, true, false, true);
267 // OPTIONAL: fetch fps
269 if (bufptr && strcmp(com_token, "\n"))
271 fps = atof(com_token);
272 COM_ParseToken_Simple(&bufptr, true, false, true);
275 // OPTIONAL: fetch loopflag
277 if (bufptr && strcmp(com_token, "\n"))
279 loop = (atoi(com_token) != 0);
280 COM_ParseToken_Simple(&bufptr, true, false, true);
283 // OPTIONAL: fetch name
285 if (bufptr && strcmp(com_token, "\n"))
287 strlcpy(name, com_token, sizeof(name));
288 COM_ParseToken_Simple(&bufptr, true, false, true);
291 // OPTIONAL: remaining unsupported tokens (eat them)
292 while (bufptr && strcmp(com_token, "\n"))
293 COM_ParseToken_Simple(&bufptr, true, false, true);
295 //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name);
298 cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
305 static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass)
307 dp_model_t *mod = (dp_model_t *) pass;
308 animscene_t *anim = &mod->animscenes[i];
310 strlcpy(anim->name, name, sizeof(anim[i].name));
312 dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
313 anim->firstframe = bound(0, start, mod->num_poses - 1);
314 anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
315 anim->framerate = max(1, fps);
317 //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
320 static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
325 cnt = Mod_FrameGroupify_ParseGroups(buf, NULL, NULL);
328 Con_Printf("no scene found in framegroups file, aborting\n");
331 mod->numframes = cnt;
334 // (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay)
335 mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes);
338 Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
341 static void Mod_FindPotentialDeforms(dp_model_t *mod)
345 mod->wantnormals = false;
346 mod->wanttangents = false;
347 for (i = 0;i < mod->num_textures;i++)
349 texture = mod->data_textures + i;
350 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
351 mod->wantnormals = true;
352 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
353 mod->wantnormals = true;
354 for (j = 0;j < Q3MAXDEFORMS;j++)
356 if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
358 mod->wanttangents = true;
359 mod->wantnormals = true;
362 if (texture->deforms[j].deform != Q3DEFORM_NONE)
363 mod->wantnormals = true;
375 dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
380 fs_offset_t filesize = 0;
385 if (mod->name[0] == '*') // submodel
388 if (!strcmp(mod->name, "null"))
393 if (mod->loaded || mod->mempool)
394 Mod_UnloadModel(mod);
396 if (developer_loading.integer)
397 Con_Printf("loading model %s\n", mod->name);
400 mod->crc = (unsigned int)-1;
403 VectorClear(mod->normalmins);
404 VectorClear(mod->normalmaxs);
405 VectorClear(mod->yawmins);
406 VectorClear(mod->yawmaxs);
407 VectorClear(mod->rotatedmins);
408 VectorClear(mod->rotatedmaxs);
410 mod->modeldatatypestring = "null";
411 mod->type = mod_null;
412 mod->Draw = R_Model_Null_Draw;
416 // no fatal errors occurred, so this model is ready to use.
425 // even if the model is loaded it still may need reloading...
427 // if it is not loaded or checkdisk is true we need to calculate the crc
428 if (!mod->loaded || checkdisk)
430 if (checkdisk && mod->loaded)
431 Con_DPrintf("checking model %s\n", mod->name);
432 buf = FS_LoadFile (mod->name, tempmempool, false, &filesize);
435 crc = CRC_Block((unsigned char *)buf, filesize);
436 // we need to reload the model if the crc does not match
442 // if the model is already loaded and checks passed, just return
450 if (developer_loading.integer)
451 Con_Printf("loading model %s\n", mod->name);
453 SCR_PushLoadingScreen(true, mod->name, 1);
455 // LordHavoc: unload the existing model in this slot (if there is one)
456 if (mod->loaded || mod->mempool)
457 Mod_UnloadModel(mod);
462 // errors can prevent the corresponding mod->loaded = true;
465 // default lightmap scale
466 mod->lightmapscale = 1;
468 // default model radius and bounding box (mainly for missing models)
470 VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius);
471 VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius);
472 VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius);
473 VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius);
474 VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
475 VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
479 // load q3 shaders for the first time, or after a level change
485 char *bufend = (char *)buf + filesize;
487 // all models use memory, so allocate a memory pool
488 mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
490 num = LittleLong(*((int *)buf));
491 // call the apropriate loader
493 if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
494 else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
495 else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
496 else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
497 else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend);
498 else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend);
499 else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend);
500 else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
501 else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
502 else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
503 else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
504 else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
505 else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
506 else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
509 Mod_FindPotentialDeforms(mod);
511 buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
514 Mod_FrameGroupify(mod, (const char *)buf);
522 // LordHavoc: Sys_Error was *ANNOYING*
523 Con_Printf ("Mod_LoadModel: %s not found\n", mod->name);
526 // no fatal errors occurred, so this model is ready to use.
529 SCR_PopLoadingScreen(false);
534 void Mod_ClearUsed(void)
537 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
539 for (i = 0;i < nummodels;i++)
540 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
544 void Mod_PurgeUnused(void)
547 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
549 for (i = 0;i < nummodels;i++)
551 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
553 Mod_UnloadModel(mod);
554 Mem_ExpandableArray_FreeRecord(&models, mod);
565 dp_model_t *Mod_FindName(const char *name, const char *parentname)
574 // if we're not dedicatd, the renderer calls will crash without video
577 nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
580 Host_Error ("Mod_ForName: empty name");
582 // search the currently loaded models
583 for (i = 0;i < nummodels;i++)
585 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))))
592 // no match found, create a new one
593 mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models);
594 strlcpy(mod->name, name, sizeof(mod->name));
596 mod->brush.parentmodel = Mod_FindName(parentname, NULL);
598 mod->brush.parentmodel = NULL;
608 Loads in a model for the given name
611 dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname)
614 model = Mod_FindName(name, parentname);
615 if (!model->loaded || checkdisk)
616 Mod_LoadModel(model, crash, checkdisk);
624 Reloads all models if they have changed
627 void Mod_Reload(void)
630 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
633 SCR_PushLoadingScreen(false, "Reloading models", 1.0);
635 for (i = 0;i < nummodels;i++)
636 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
638 for (i = 0;i < nummodels;i++)
639 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
641 SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
642 Mod_LoadModel(mod, true, true);
643 SCR_PopLoadingScreen(false);
645 SCR_PopLoadingScreen(false);
648 unsigned char *mod_base;
651 //=============================================================================
658 static void Mod_Print(void)
661 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
664 Con_Print("Loaded models:\n");
665 for (i = 0;i < nummodels;i++)
667 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
669 if (mod->brush.numsubmodels)
670 Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
672 Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name);
682 static void Mod_Precache(void)
685 Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL);
687 Con_Print("usage: modelprecache <filename>\n");
690 int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
694 used = (unsigned char *)Mem_Alloc(tempmempool, numvertices);
695 memset(used, 0, numvertices);
696 for (i = 0;i < numelements;i++)
697 used[elements[i]] = 1;
698 for (i = 0, count = 0;i < numvertices;i++)
699 remapvertices[i] = used[i] ? count++ : -1;
704 qboolean Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
706 int first = firstvertex, last = first + numvertices - 1, numelements = numtriangles * 3;
708 int invalidintcount = 0, invalidintexample = 0;
709 int invalidshortcount = 0, invalidshortexample = 0;
710 int invalidmismatchcount = 0, invalidmismatchexample = 0;
713 for (i = 0; i < numelements; i++)
715 if (element3i[i] < first || element3i[i] > last)
718 invalidintexample = i;
724 for (i = 0; i < numelements; i++)
726 if (element3s[i] < first || element3s[i] > last)
729 invalidintexample = i;
733 if (element3i && element3s)
735 for (i = 0; i < numelements; i++)
737 if (element3s[i] != element3i[i])
739 invalidmismatchcount++;
740 invalidmismatchexample = i;
744 if (invalidintcount || invalidshortcount || invalidmismatchcount)
746 Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, element3i, element3s, filename, fileline);
747 Con_Printf(", %i elements are invalid in element3i (example: element3i[%i] == %i)", invalidintcount, invalidintexample, element3i ? element3i[invalidintexample] : 0);
748 Con_Printf(", %i elements are invalid in element3s (example: element3s[%i] == %i)", invalidshortcount, invalidshortexample, element3s ? element3s[invalidshortexample] : 0);
749 Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[i] is %i)", invalidmismatchcount, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0);
750 Con_Print(". Please debug the engine code - these elements have been modified to not crash, but nothing more.\n");
752 // edit the elements to make them safer, as the driver will crash otherwise
754 for (i = 0; i < numelements; i++)
755 if (element3i[i] < first || element3i[i] > last)
756 element3i[i] = first;
758 for (i = 0; i < numelements; i++)
759 if (element3s[i] < first || element3s[i] > last)
760 element3s[i] = first;
761 if (element3i && element3s)
762 for (i = 0; i < numelements; i++)
763 if (element3s[i] != element3i[i])
764 element3s[i] = element3i[i];
771 // warning: this is an expensive function!
772 void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting)
779 memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
780 // process each vertex of each triangle and accumulate the results
781 // use area-averaging, to make triangles with a big area have a bigger
782 // weighting on the vertex normal than triangles with a small area
783 // to do so, just add the 'normals' together (the bigger the area
784 // the greater the length of the normal is
786 for (i = 0; i < numtriangles; i++, element += 3)
789 vertex3f + element[0] * 3,
790 vertex3f + element[1] * 3,
791 vertex3f + element[2] * 3,
796 VectorNormalize(areaNormal);
798 for (j = 0;j < 3;j++)
800 vectorNormal = normal3f + element[j] * 3;
801 vectorNormal[0] += areaNormal[0];
802 vectorNormal[1] += areaNormal[1];
803 vectorNormal[2] += areaNormal[2];
806 // and just normalize the accumulated vertex normal in the end
807 vectorNormal = normal3f + 3 * firstvertex;
808 for (i = 0; i < numvertices; i++, vectorNormal += 3)
809 VectorNormalize(vectorNormal);
813 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)
815 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
816 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
817 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
819 // 6 multiply, 9 subtract
820 VectorSubtract(v1, v0, v10);
821 VectorSubtract(v2, v0, v20);
822 normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1];
823 normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2];
824 normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0];
825 // 12 multiply, 10 subtract
826 tc10[1] = tc1[1] - tc0[1];
827 tc20[1] = tc2[1] - tc0[1];
828 svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
829 svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
830 svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
831 tc10[0] = tc1[0] - tc0[0];
832 tc20[0] = tc2[0] - tc0[0];
833 tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
834 tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
835 tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
836 // 12 multiply, 4 add, 6 subtract
837 f = DotProduct(svector3f, normal3f);
838 svector3f[0] -= f * normal3f[0];
839 svector3f[1] -= f * normal3f[1];
840 svector3f[2] -= f * normal3f[2];
841 f = DotProduct(tvector3f, normal3f);
842 tvector3f[0] -= f * normal3f[0];
843 tvector3f[1] -= f * normal3f[1];
844 tvector3f[2] -= f * normal3f[2];
845 // if texture is mapped the wrong way (counterclockwise), the tangents
846 // have to be flipped, this is detected by calculating a normal from the
847 // two tangents, and seeing if it is opposite the surface normal
848 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
849 CrossProduct(tvector3f, svector3f, tangentcross);
850 if (DotProduct(tangentcross, normal3f) < 0)
852 VectorNegate(svector3f, svector3f);
853 VectorNegate(tvector3f, tvector3f);
858 // warning: this is a very expensive function!
859 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)
862 float sdir[3], tdir[3], normal[3], *svec, *tvec;
863 const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
864 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
867 memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
868 memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
869 // process each vertex of each triangle and accumulate the results
870 for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
872 v0 = vertex3f + e[0] * 3;
873 v1 = vertex3f + e[1] * 3;
874 v2 = vertex3f + e[2] * 3;
875 tc0 = texcoord2f + e[0] * 2;
876 tc1 = texcoord2f + e[1] * 2;
877 tc2 = texcoord2f + e[2] * 2;
879 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
880 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
882 // calculate the edge directions and surface normal
883 // 6 multiply, 9 subtract
884 VectorSubtract(v1, v0, v10);
885 VectorSubtract(v2, v0, v20);
886 normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
887 normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
888 normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
890 // calculate the tangents
891 // 12 multiply, 10 subtract
892 tc10[1] = tc1[1] - tc0[1];
893 tc20[1] = tc2[1] - tc0[1];
894 sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
895 sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
896 sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
897 tc10[0] = tc1[0] - tc0[0];
898 tc20[0] = tc2[0] - tc0[0];
899 tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
900 tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
901 tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
903 // if texture is mapped the wrong way (counterclockwise), the tangents
904 // have to be flipped, this is detected by calculating a normal from the
905 // two tangents, and seeing if it is opposite the surface normal
906 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
907 CrossProduct(tdir, sdir, tangentcross);
908 if (DotProduct(tangentcross, normal) < 0)
910 VectorNegate(sdir, sdir);
911 VectorNegate(tdir, tdir);
916 VectorNormalize(sdir);
917 VectorNormalize(tdir);
919 for (i = 0;i < 3;i++)
921 VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
922 VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
925 // make the tangents completely perpendicular to the surface normal, and
926 // then normalize them
927 // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
928 for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
930 f = -DotProduct(svec, n);
931 VectorMA(svec, f, n, svec);
932 VectorNormalize(svec);
933 f = -DotProduct(tvec, n);
934 VectorMA(tvec, f, n, tvec);
935 VectorNormalize(tvec);
939 void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors)
942 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));
943 loadmodel->surfmesh.num_vertices = numvertices;
944 loadmodel->surfmesh.num_triangles = numtriangles;
945 if (loadmodel->surfmesh.num_vertices)
947 loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
948 loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
949 loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
950 loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
951 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
952 loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
954 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices;
956 loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices;
958 if (loadmodel->surfmesh.num_triangles)
960 loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
961 if (loadmodel->surfmesh.num_vertices <= 65536)
962 loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles;
966 shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int expandable)
968 shadowmesh_t *newmesh;
971 size = sizeof(shadowmesh_t);
972 size += maxverts * sizeof(float[3]);
974 size += maxverts * sizeof(float[11]);
975 size += maxtriangles * sizeof(int[3]);
976 if (maxverts <= 65536)
977 size += maxtriangles * sizeof(unsigned short[3]);
979 size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t);
980 data = (unsigned char *)Mem_Alloc(mempool, size);
981 newmesh = (shadowmesh_t *)data;data += sizeof(*newmesh);
982 newmesh->map_diffuse = map_diffuse;
983 newmesh->map_specular = map_specular;
984 newmesh->map_normal = map_normal;
985 newmesh->maxverts = maxverts;
986 newmesh->maxtriangles = maxtriangles;
987 newmesh->numverts = 0;
988 newmesh->numtriangles = 0;
989 memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
990 memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
992 newmesh->vertex3f = (float *)data;data += maxverts * sizeof(float[3]);
995 newmesh->svector3f = (float *)data;data += maxverts * sizeof(float[3]);
996 newmesh->tvector3f = (float *)data;data += maxverts * sizeof(float[3]);
997 newmesh->normal3f = (float *)data;data += maxverts * sizeof(float[3]);
998 newmesh->texcoord2f = (float *)data;data += maxverts * sizeof(float[2]);
1000 newmesh->element3i = (int *)data;data += maxtriangles * sizeof(int[3]);
1003 newmesh->vertexhashtable = (shadowmeshvertexhash_t **)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *);
1004 newmesh->vertexhashentries = (shadowmeshvertexhash_t *)data;data += maxverts * sizeof(shadowmeshvertexhash_t);
1006 if (maxverts <= 65536)
1007 newmesh->element3s = (unsigned short *)data;data += maxtriangles * sizeof(unsigned short[3]);
1011 shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light)
1013 shadowmesh_t *newmesh;
1014 newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, false);
1015 newmesh->numverts = oldmesh->numverts;
1016 newmesh->numtriangles = oldmesh->numtriangles;
1017 memcpy(newmesh->sideoffsets, oldmesh->sideoffsets, sizeof(oldmesh->sideoffsets));
1018 memcpy(newmesh->sidetotals, oldmesh->sidetotals, sizeof(oldmesh->sidetotals));
1020 memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3]));
1021 if (newmesh->svector3f && oldmesh->svector3f)
1023 memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3]));
1024 memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3]));
1025 memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3]));
1026 memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2]));
1028 memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3]));
1032 static int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f)
1034 int hashindex, vnum;
1035 shadowmeshvertexhash_t *hash;
1036 // this uses prime numbers intentionally
1037 hashindex = (unsigned int) (vertex14f[0] * 2003 + vertex14f[1] * 4001 + vertex14f[2] * 7919) % SHADOWMESHVERTEXHASH;
1038 for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
1040 vnum = (hash - mesh->vertexhashentries);
1041 if ((mesh->vertex3f == NULL || (mesh->vertex3f[vnum * 3 + 0] == vertex14f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex14f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex14f[2]))
1042 && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5]))
1043 && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8]))
1044 && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11]))
1045 && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13])))
1046 return hash - mesh->vertexhashentries;
1048 vnum = mesh->numverts++;
1049 hash = mesh->vertexhashentries + vnum;
1050 hash->next = mesh->vertexhashtable[hashindex];
1051 mesh->vertexhashtable[hashindex] = hash;
1052 if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];}
1053 if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];}
1054 if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];}
1055 if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];}
1056 if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];}
1060 static void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f)
1062 if (mesh->numtriangles == 0)
1064 // set the properties on this empty mesh to be more favorable...
1065 // (note: this case only occurs for the first triangle added to a new mesh chain)
1066 mesh->map_diffuse = map_diffuse;
1067 mesh->map_specular = map_specular;
1068 mesh->map_normal = map_normal;
1070 while (mesh->map_diffuse != map_diffuse || mesh->map_specular != map_specular || mesh->map_normal != map_normal || mesh->numverts + 3 > mesh->maxverts || mesh->numtriangles + 1 > mesh->maxtriangles)
1072 if (mesh->next == NULL)
1073 mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, true);
1076 mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0);
1077 mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1);
1078 mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2);
1079 mesh->numtriangles++;
1082 void Mod_ShadowMesh_AddMesh(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, const float *vertex3f, const float *svector3f, const float *tvector3f, const float *normal3f, const float *texcoord2f, int numtris, const int *element3i)
1085 float vbuf[3*14], *v;
1086 memset(vbuf, 0, sizeof(vbuf));
1087 for (i = 0;i < numtris;i++)
1089 for (j = 0, v = vbuf;j < 3;j++, v += 14)
1094 v[0] = vertex3f[e * 3 + 0];
1095 v[1] = vertex3f[e * 3 + 1];
1096 v[2] = vertex3f[e * 3 + 2];
1100 v[3] = svector3f[e * 3 + 0];
1101 v[4] = svector3f[e * 3 + 1];
1102 v[5] = svector3f[e * 3 + 2];
1106 v[6] = tvector3f[e * 3 + 0];
1107 v[7] = tvector3f[e * 3 + 1];
1108 v[8] = tvector3f[e * 3 + 2];
1112 v[9] = normal3f[e * 3 + 0];
1113 v[10] = normal3f[e * 3 + 1];
1114 v[11] = normal3f[e * 3 + 2];
1118 v[12] = texcoord2f[e * 2 + 0];
1119 v[13] = texcoord2f[e * 2 + 1];
1122 Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf);
1125 // the triangle calculation can take a while, so let's do a keepalive here
1126 CL_KeepaliveMessage(false);
1129 shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int expandable)
1131 // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
1132 CL_KeepaliveMessage(false);
1134 return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, expandable);
1137 static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
1139 if (!mesh->numverts)
1142 // make sure we don't crash inside the driver if something went wrong, as it's annoying to debug
1143 Mod_ValidateElements(mesh->element3i, mesh->element3s, mesh->numtriangles, 0, mesh->numverts, __FILE__, __LINE__);
1145 // build r_vertexmesh_t array
1146 // (compressed interleaved array for D3D)
1147 if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays)
1150 int numvertices = mesh->numverts;
1151 r_vertexmesh_t *vertexmesh;
1152 mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(mempool, numvertices * sizeof(*mesh->vertexmesh));
1153 for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
1155 VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f);
1156 VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
1157 VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
1158 VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
1159 Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
1163 // upload short indices as a buffer
1164 if (mesh->element3s && !mesh->element3s_indexbuffer)
1165 mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), "shadowmesh", true, false, false, true);
1167 // upload int indices as a buffer
1168 if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
1169 mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), "shadowmesh", true, false, false, false);
1171 // vertex buffer is several arrays and we put them in the same buffer
1173 // is this wise? the texcoordtexture2f array is used with dynamic
1174 // vertex/svector/tvector/normal when rendering animated models, on the
1175 // other hand animated models don't use a lot of vertices anyway...
1176 if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays)
1181 mesh->vbooffset_vertexmesh = size;if (mesh->vertexmesh ) size += mesh->numverts * sizeof(r_vertexmesh_t);
1182 mesh->vbooffset_vertex3f = size;if (mesh->vertex3f ) size += mesh->numverts * sizeof(float[3]);
1183 mesh->vbooffset_svector3f = size;if (mesh->svector3f ) size += mesh->numverts * sizeof(float[3]);
1184 mesh->vbooffset_tvector3f = size;if (mesh->tvector3f ) size += mesh->numverts * sizeof(float[3]);
1185 mesh->vbooffset_normal3f = size;if (mesh->normal3f ) size += mesh->numverts * sizeof(float[3]);
1186 mesh->vbooffset_texcoord2f = size;if (mesh->texcoord2f ) size += mesh->numverts * sizeof(float[2]);
1187 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
1188 if (mesh->vertexmesh ) memcpy(mem + mesh->vbooffset_vertexmesh , mesh->vertexmesh , mesh->numverts * sizeof(r_vertexmesh_t));
1189 if (mesh->vertex3f ) memcpy(mem + mesh->vbooffset_vertex3f , mesh->vertex3f , mesh->numverts * sizeof(float[3]));
1190 if (mesh->svector3f ) memcpy(mem + mesh->vbooffset_svector3f , mesh->svector3f , mesh->numverts * sizeof(float[3]));
1191 if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3]));
1192 if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3]));
1193 if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2]));
1194 mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false);
1199 shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean createvbo)
1201 shadowmesh_t *mesh, *newmesh, *nextmesh;
1202 // reallocate meshs to conserve space
1203 for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
1205 nextmesh = mesh->next;
1206 if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
1208 newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light);
1209 newmesh->next = firstmesh;
1210 firstmesh = newmesh;
1211 if (newmesh->element3s)
1214 for (i = 0;i < newmesh->numtriangles*3;i++)
1215 newmesh->element3s[i] = newmesh->element3i[i];
1218 Mod_ShadowMesh_CreateVBOs(newmesh, mempool);
1223 // this can take a while, so let's do a keepalive here
1224 CL_KeepaliveMessage(false);
1229 void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
1233 vec3_t nmins, nmaxs, ncenter, temp;
1234 float nradius2, dist2, *v;
1238 for (mesh = firstmesh;mesh;mesh = mesh->next)
1240 if (mesh == firstmesh)
1242 VectorCopy(mesh->vertex3f, nmins);
1243 VectorCopy(mesh->vertex3f, nmaxs);
1245 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1247 if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0];
1248 if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1];
1249 if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2];
1252 // calculate center and radius
1253 ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
1254 ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
1255 ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
1257 for (mesh = firstmesh;mesh;mesh = mesh->next)
1259 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1261 VectorSubtract(v, ncenter, temp);
1262 dist2 = DotProduct(temp, temp);
1263 if (nradius2 < dist2)
1269 VectorCopy(nmins, mins);
1271 VectorCopy(nmaxs, maxs);
1273 VectorCopy(ncenter, center);
1275 *radius = sqrt(nradius2);
1278 void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
1280 shadowmesh_t *nextmesh;
1281 for (;mesh;mesh = nextmesh)
1283 if (mesh->element3i_indexbuffer)
1284 R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
1285 if (mesh->element3s_indexbuffer)
1286 R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
1287 if (mesh->vbo_vertexbuffer)
1288 R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
1289 nextmesh = mesh->next;
1295 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)
1300 if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1301 v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1304 Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1305 Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1306 texcoord2f[0] = tc[0];
1307 texcoord2f[1] = tc[1];
1310 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)
1312 float vup[3], vdown[3], vleft[3], vright[3];
1313 float tcup[3], tcdown[3], tcleft[3], tcright[3];
1314 float sv[3], tv[3], nl[3];
1315 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1316 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1317 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1318 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1319 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1320 Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1321 Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1322 VectorAdd(svector3f, sv, svector3f);
1323 VectorAdd(tvector3f, tv, tvector3f);
1324 VectorAdd(normal3f, nl, normal3f);
1325 Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1326 VectorAdd(svector3f, sv, svector3f);
1327 VectorAdd(tvector3f, tv, tvector3f);
1328 VectorAdd(normal3f, nl, normal3f);
1329 Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1330 VectorAdd(svector3f, sv, svector3f);
1331 VectorAdd(tvector3f, tv, tvector3f);
1332 VectorAdd(normal3f, nl, normal3f);
1335 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)
1337 int x, y, ix, iy, *e;
1339 for (y = 0;y < height;y++)
1341 for (x = 0;x < width;x++)
1343 e[0] = (y + 1) * (width + 1) + (x + 0);
1344 e[1] = (y + 0) * (width + 1) + (x + 0);
1345 e[2] = (y + 1) * (width + 1) + (x + 1);
1346 e[3] = (y + 0) * (width + 1) + (x + 0);
1347 e[4] = (y + 0) * (width + 1) + (x + 1);
1348 e[5] = (y + 1) * (width + 1) + (x + 1);
1352 for (y = 0, iy = y1;y < height + 1;y++, iy++)
1353 for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1354 Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1359 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
1363 float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1364 float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1365 float viewvector[3];
1366 unsigned int firstvertex;
1369 if (chunkwidth < 2 || chunkheight < 2)
1371 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]);
1372 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]);
1373 viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1374 viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1375 viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1376 if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1378 // too close for this stepsize, emit as 4 chunks instead
1380 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1381 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1382 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1383 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1386 // emit the geometry at stepsize into our vertex buffer / index buffer
1387 // we add two columns and two rows for skirt
1388 outwidth = chunkwidth+2;
1389 outheight = chunkheight+2;
1390 outwidth2 = outwidth-1;
1391 outheight2 = outheight-1;
1392 outwidth3 = outwidth+1;
1393 outheight3 = outheight+1;
1394 firstvertex = numvertices;
1395 e = model->terrain.element3i + numtriangles;
1396 numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1397 v = model->terrain.vertex3f + numvertices;
1398 numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1399 // emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1400 for (ty = 0;ty < outheight;ty++)
1402 for (tx = 0;tx < outwidth;tx++)
1404 *e++ = firstvertex + (ty )*outwidth3+(tx );
1405 *e++ = firstvertex + (ty )*outwidth3+(tx+1);
1406 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1407 *e++ = firstvertex + (ty )*outwidth3+(tx );
1408 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1409 *e++ = firstvertex + (ty+1)*outwidth3+(tx );
1412 // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1413 for (ty = 0;ty <= outheight;ty++)
1415 skirtrow = ty == 0 || ty == outheight;
1416 ry = y+bound(1, ty, outheight)*stepsize;
1417 for (tx = 0;tx <= outwidth;tx++)
1419 skirt = skirtrow || tx == 0 || tx == outwidth;
1420 rx = x+bound(1, tx, outwidth)*stepsize;
1423 v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1427 // TODO: emit skirt vertices
1430 void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
1432 for (y = 0;y < model->terrain.size[1];y += model->terrain.
1433 Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1434 Mod_Terrain_BuildChunk(model,
1438 static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
1441 if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1443 offset = bound(0, s[4] - '0', 9);
1444 offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
1449 if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN;
1450 if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE;
1451 if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE;
1452 if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH;
1453 if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1454 if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE;
1455 if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE;
1456 Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1457 return offset | Q3WAVEFUNC_NONE;
1460 void Mod_FreeQ3Shaders(void)
1462 Mem_FreePool(&q3shaders_mem);
1465 static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
1467 unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1468 q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
1469 q3shader_hash_entry_t* lastEntry = NULL;
1472 if (strcasecmp (entry->shader.name, shader->name) == 0)
1475 if(shader->dpshaderkill)
1477 // killed shader is a redeclarion? we can safely ignore it
1480 else if(entry->shader.dpshaderkill)
1482 // replace the old shader!
1483 // this will skip the entry allocating part
1484 // below and just replace the shader
1489 unsigned char *start, *end, *start2;
1490 start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1491 end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1492 start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1493 if(memcmp(start, start2, end - start))
1494 Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1496 Con_DPrintf("Shader '%s' already defined\n", shader->name);
1501 entry = entry->chain;
1503 while (entry != NULL);
1506 if (lastEntry->shader.name[0] != 0)
1509 q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*)
1510 Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries);
1512 while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1513 lastEntry->chain = newEntry;
1514 newEntry->chain = NULL;
1515 lastEntry = newEntry;
1517 /* else: head of chain, in hash entry array */
1520 memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
1523 extern cvar_t mod_noshader_default_offsetmapping;
1524 extern cvar_t mod_q3shader_default_offsetmapping;
1525 extern cvar_t mod_q3shader_default_offsetmapping_scale;
1526 extern cvar_t mod_q3shader_default_offsetmapping_bias;
1527 extern cvar_t mod_q3shader_default_polygonoffset;
1528 extern cvar_t mod_q3shader_default_polygonfactor;
1529 extern cvar_t mod_q3shader_force_addalpha;
1530 extern cvar_t mod_q3shader_force_terrain_alphaflag;
1531 void Mod_LoadQ3Shaders(void)
1538 q3shaderinfo_t shader;
1539 q3shaderinfo_layer_t *layer;
1541 char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1542 char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1543 unsigned long custsurfaceflags[256];
1544 int numcustsurfaceflags;
1545 qboolean dpshaderkill;
1547 Mod_FreeQ3Shaders();
1549 q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1550 q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem,
1551 sizeof (q3shader_data_t));
1552 Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries,
1553 q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1554 Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs,
1555 q3shaders_mem, sizeof (char**), 256);
1557 // parse custinfoparms.txt
1558 numcustsurfaceflags = 0;
1559 if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1561 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1562 Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1565 while (COM_ParseToken_QuakeC(&text, false))
1566 if (!strcasecmp(com_token, "}"))
1568 // custom surfaceflags section
1569 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1570 Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1573 while(COM_ParseToken_QuakeC(&text, false))
1575 if (!strcasecmp(com_token, "}"))
1577 // register surfaceflag
1578 if (numcustsurfaceflags >= 256)
1580 Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1584 j = (int)strlen(com_token)+1;
1585 custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1586 strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1588 if (COM_ParseToken_QuakeC(&text, false))
1589 custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1591 custsurfaceflags[numcustsurfaceflags] = 0;
1592 numcustsurfaceflags++;
1600 search = FS_Search("scripts/*.shader", true, false);
1603 for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1605 text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1608 while (COM_ParseToken_QuakeC(&text, false))
1610 memset (&shader, 0, sizeof(shader));
1612 shader.surfaceparms = 0;
1613 shader.surfaceflags = 0;
1614 shader.textureflags = 0;
1615 shader.numlayers = 0;
1616 shader.lighting = false;
1617 shader.vertexalpha = false;
1618 shader.textureblendalpha = false;
1619 shader.skyboxname[0] = 0;
1620 shader.deforms[0].deform = Q3DEFORM_NONE;
1621 shader.dpnortlight = false;
1622 shader.dpshadow = false;
1623 shader.dpnoshadow = false;
1624 shader.dpmeshcollisions = false;
1625 shader.dpshaderkill = false;
1626 shader.dpreflectcube[0] = 0;
1627 shader.reflectmin = 0;
1628 shader.reflectmax = 1;
1629 shader.refractfactor = 1;
1630 Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1631 shader.reflectfactor = 1;
1632 Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1633 shader.r_water_wateralpha = 1;
1634 shader.r_water_waterscroll[0] = 0;
1635 shader.r_water_waterscroll[1] = 0;
1636 shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
1637 shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
1638 shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
1639 shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
1640 shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
1641 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
1642 shader.specularscalemod = 1;
1643 shader.specularpowermod = 1;
1644 shader.rtlightambient = 0;
1645 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1646 // JUST GREP FOR "specularscalemod = 1".
1648 strlcpy(shader.name, com_token, sizeof(shader.name));
1649 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1651 Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1654 while (COM_ParseToken_QuakeC(&text, false))
1656 if (!strcasecmp(com_token, "}"))
1658 if (!strcasecmp(com_token, "{"))
1660 static q3shaderinfo_layer_t dummy;
1661 if (shader.numlayers < Q3SHADER_MAXLAYERS)
1663 layer = shader.layers + shader.numlayers++;
1667 // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1668 memset(&dummy, 0, sizeof(dummy));
1671 layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1672 layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1673 layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1674 layer->blendfunc[0] = GL_ONE;
1675 layer->blendfunc[1] = GL_ZERO;
1676 while (COM_ParseToken_QuakeC(&text, false))
1678 if (!strcasecmp(com_token, "}"))
1680 if (!strcasecmp(com_token, "\n"))
1683 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1685 if (j < TEXTURE_MAXFRAMES + 4)
1687 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1688 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1689 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1691 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1692 numparameters = j + 1;
1694 if (!COM_ParseToken_QuakeC(&text, true))
1697 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1698 // parameter[j][0] = 0;
1699 if (developer_insane.integer)
1701 Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1702 for (j = 0;j < numparameters;j++)
1703 Con_DPrintf(" %s", parameter[j]);
1706 if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1708 if (numparameters == 2)
1710 if (!strcasecmp(parameter[1], "add"))
1712 layer->blendfunc[0] = GL_ONE;
1713 layer->blendfunc[1] = GL_ONE;
1715 else if (!strcasecmp(parameter[1], "addalpha"))
1717 layer->blendfunc[0] = GL_SRC_ALPHA;
1718 layer->blendfunc[1] = GL_ONE;
1720 else if (!strcasecmp(parameter[1], "filter"))
1722 layer->blendfunc[0] = GL_DST_COLOR;
1723 layer->blendfunc[1] = GL_ZERO;
1725 else if (!strcasecmp(parameter[1], "blend"))
1727 layer->blendfunc[0] = GL_SRC_ALPHA;
1728 layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1731 else if (numparameters == 3)
1734 for (k = 0;k < 2;k++)
1736 if (!strcasecmp(parameter[k+1], "GL_ONE"))
1737 layer->blendfunc[k] = GL_ONE;
1738 else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1739 layer->blendfunc[k] = GL_ZERO;
1740 else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1741 layer->blendfunc[k] = GL_SRC_COLOR;
1742 else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1743 layer->blendfunc[k] = GL_SRC_ALPHA;
1744 else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1745 layer->blendfunc[k] = GL_DST_COLOR;
1746 else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1747 layer->blendfunc[k] = GL_DST_ALPHA;
1748 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1749 layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1750 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1751 layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1752 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1753 layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1754 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1755 layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1757 layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1761 if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1762 layer->alphatest = true;
1763 if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1765 if (!strcasecmp(parameter[0], "clampmap"))
1766 layer->clampmap = true;
1767 layer->numframes = 1;
1768 layer->framerate = 1;
1769 layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1770 &q3shader_data->char_ptrs);
1771 layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1772 if (!strcasecmp(parameter[1], "$lightmap"))
1773 shader.lighting = true;
1775 else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1778 layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1779 layer->framerate = atof(parameter[1]);
1780 layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1781 for (i = 0;i < layer->numframes;i++)
1782 layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1784 else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1787 for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1788 layer->rgbgen.parms[i] = atof(parameter[i+2]);
1789 if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1790 else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1791 else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1792 else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1793 else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1794 else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1795 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1796 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1797 else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1798 else if (!strcasecmp(parameter[1], "wave"))
1800 layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1801 layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1802 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1803 layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1805 else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1807 else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1810 for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1811 layer->alphagen.parms[i] = atof(parameter[i+2]);
1812 if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1813 else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1814 else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1815 else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1816 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1817 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1818 else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1819 else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1820 else if (!strcasecmp(parameter[1], "wave"))
1822 layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1823 layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1824 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1825 layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1827 else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1829 else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1832 // observed values: tcgen environment
1833 // no other values have been observed in real shaders
1834 for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1835 layer->tcgen.parms[i] = atof(parameter[i+2]);
1836 if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1837 else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1838 else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1839 else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1840 else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1841 else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1843 else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1850 // tcmod stretch sin # # # #
1851 // tcmod stretch triangle # # # #
1852 // tcmod transform # # # # # #
1853 // tcmod turb # # # #
1854 // tcmod turb sin # # # # (this is bogus)
1855 // no other values have been observed in real shaders
1856 for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1857 if (!layer->tcmods[tcmodindex].tcmod)
1859 if (tcmodindex < Q3MAXTCMODS)
1861 for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1862 layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1863 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1864 else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1865 else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1866 else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1867 else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1868 else if (!strcasecmp(parameter[1], "stretch"))
1870 layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1871 layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1872 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1873 layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1875 else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1876 else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1877 else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1880 Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1882 // break out a level if it was a closing brace (not using the character here to not confuse vim)
1883 if (!strcasecmp(com_token, "}"))
1886 if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
1887 shader.lighting = true;
1888 if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
1890 if (layer == shader.layers + 0)
1892 // vertex controlled transparency
1893 shader.vertexalpha = true;
1897 // multilayer terrain shader or similar
1898 shader.textureblendalpha = true;
1899 if (mod_q3shader_force_terrain_alphaflag.integer)
1900 shader.layers[0].dptexflags |= TEXF_ALPHA;
1904 if(mod_q3shader_force_addalpha.integer)
1906 // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
1907 // this cvar brings back this behaviour
1908 if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
1909 layer->blendfunc[0] = GL_SRC_ALPHA;
1912 layer->dptexflags = 0;
1913 if (layer->alphatest)
1914 layer->dptexflags |= TEXF_ALPHA;
1915 switch(layer->blendfunc[0])
1918 case GL_ONE_MINUS_SRC_ALPHA:
1919 layer->dptexflags |= TEXF_ALPHA;
1922 switch(layer->blendfunc[1])
1925 case GL_ONE_MINUS_SRC_ALPHA:
1926 layer->dptexflags |= TEXF_ALPHA;
1929 if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
1930 layer->dptexflags |= TEXF_MIPMAP;
1931 if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
1932 layer->dptexflags |= TEXF_PICMIP | TEXF_COMPRESS;
1933 if (layer->clampmap)
1934 layer->dptexflags |= TEXF_CLAMP;
1938 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1940 if (j < TEXTURE_MAXFRAMES + 4)
1942 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1943 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1944 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1946 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1947 numparameters = j + 1;
1949 if (!COM_ParseToken_QuakeC(&text, true))
1952 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1953 // parameter[j][0] = 0;
1954 if (fileindex == 0 && !strcasecmp(com_token, "}"))
1956 if (developer_insane.integer)
1958 Con_DPrintf("%s: ", shader.name);
1959 for (j = 0;j < numparameters;j++)
1960 Con_DPrintf(" %s", parameter[j]);
1963 if (numparameters < 1)
1965 if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
1967 if (!strcasecmp(parameter[1], "alphashadow"))
1968 shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
1969 else if (!strcasecmp(parameter[1], "areaportal"))
1970 shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
1971 else if (!strcasecmp(parameter[1], "botclip"))
1972 shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP;
1973 else if (!strcasecmp(parameter[1], "clusterportal"))
1974 shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
1975 else if (!strcasecmp(parameter[1], "detail"))
1976 shader.surfaceparms |= Q3SURFACEPARM_DETAIL;
1977 else if (!strcasecmp(parameter[1], "donotenter"))
1978 shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER;
1979 else if (!strcasecmp(parameter[1], "dust"))
1980 shader.surfaceparms |= Q3SURFACEPARM_DUST;
1981 else if (!strcasecmp(parameter[1], "hint"))
1982 shader.surfaceparms |= Q3SURFACEPARM_HINT;
1983 else if (!strcasecmp(parameter[1], "fog"))
1984 shader.surfaceparms |= Q3SURFACEPARM_FOG;
1985 else if (!strcasecmp(parameter[1], "lava"))
1986 shader.surfaceparms |= Q3SURFACEPARM_LAVA;
1987 else if (!strcasecmp(parameter[1], "lightfilter"))
1988 shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
1989 else if (!strcasecmp(parameter[1], "lightgrid"))
1990 shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
1991 else if (!strcasecmp(parameter[1], "metalsteps"))
1992 shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS;
1993 else if (!strcasecmp(parameter[1], "nodamage"))
1994 shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE;
1995 else if (!strcasecmp(parameter[1], "nodlight"))
1996 shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT;
1997 else if (!strcasecmp(parameter[1], "nodraw"))
1998 shader.surfaceparms |= Q3SURFACEPARM_NODRAW;
1999 else if (!strcasecmp(parameter[1], "nodrop"))
2000 shader.surfaceparms |= Q3SURFACEPARM_NODROP;
2001 else if (!strcasecmp(parameter[1], "noimpact"))
2002 shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT;
2003 else if (!strcasecmp(parameter[1], "nolightmap"))
2004 shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
2005 else if (!strcasecmp(parameter[1], "nomarks"))
2006 shader.surfaceparms |= Q3SURFACEPARM_NOMARKS;
2007 else if (!strcasecmp(parameter[1], "nomipmaps"))
2008 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2009 else if (!strcasecmp(parameter[1], "nonsolid"))
2010 shader.surfaceparms |= Q3SURFACEPARM_NONSOLID;
2011 else if (!strcasecmp(parameter[1], "origin"))
2012 shader.surfaceparms |= Q3SURFACEPARM_ORIGIN;
2013 else if (!strcasecmp(parameter[1], "playerclip"))
2014 shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
2015 else if (!strcasecmp(parameter[1], "sky"))
2016 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2017 else if (!strcasecmp(parameter[1], "slick"))
2018 shader.surfaceparms |= Q3SURFACEPARM_SLICK;
2019 else if (!strcasecmp(parameter[1], "slime"))
2020 shader.surfaceparms |= Q3SURFACEPARM_SLIME;
2021 else if (!strcasecmp(parameter[1], "structural"))
2022 shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
2023 else if (!strcasecmp(parameter[1], "trans"))
2024 shader.surfaceparms |= Q3SURFACEPARM_TRANS;
2025 else if (!strcasecmp(parameter[1], "water"))
2026 shader.surfaceparms |= Q3SURFACEPARM_WATER;
2027 else if (!strcasecmp(parameter[1], "pointlight"))
2028 shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
2029 else if (!strcasecmp(parameter[1], "antiportal"))
2030 shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
2031 else if (!strcasecmp(parameter[1], "skip"))
2032 ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
2035 // try custom surfaceparms
2036 for (j = 0; j < numcustsurfaceflags; j++)
2038 if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
2040 shader.surfaceflags |= custsurfaceflags[j];
2045 if (j == numcustsurfaceflags)
2046 Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
2049 else if (!strcasecmp(parameter[0], "dpshadow"))
2050 shader.dpshadow = true;
2051 else if (!strcasecmp(parameter[0], "dpnoshadow"))
2052 shader.dpnoshadow = true;
2053 else if (!strcasecmp(parameter[0], "dpnortlight"))
2054 shader.dpnortlight = true;
2055 else if (!strcasecmp(parameter[0], "dpreflectcube"))
2056 strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
2057 else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
2058 shader.dpmeshcollisions = true;
2059 // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
2060 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
2062 if (Cvar_VariableValue(parameter[1]) == 0.0f)
2063 shader.dpshaderkill = dpshaderkill;
2065 // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
2066 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
2068 const char *op = NULL;
2069 if (numparameters >= 3)
2073 if (Cvar_VariableValue(parameter[1]) != 0.0f)
2074 shader.dpshaderkill = dpshaderkill;
2076 else if (numparameters >= 4 && !strcmp(op, "=="))
2078 if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
2079 shader.dpshaderkill = dpshaderkill;
2081 else if (numparameters >= 4 && !strcmp(op, "!="))
2083 if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
2084 shader.dpshaderkill = dpshaderkill;
2086 else if (numparameters >= 4 && !strcmp(op, ">"))
2088 if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
2089 shader.dpshaderkill = dpshaderkill;
2091 else if (numparameters >= 4 && !strcmp(op, "<"))
2093 if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
2094 shader.dpshaderkill = dpshaderkill;
2096 else if (numparameters >= 4 && !strcmp(op, ">="))
2098 if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
2099 shader.dpshaderkill = dpshaderkill;
2101 else if (numparameters >= 4 && !strcmp(op, "<="))
2103 if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
2104 shader.dpshaderkill = dpshaderkill;
2108 Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2111 else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2113 // some q3 skies don't have the sky parm set
2114 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2115 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2117 else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2119 // some q3 skies don't have the sky parm set
2120 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2121 if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2122 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2124 else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2126 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2127 shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED;
2129 else if (!strcasecmp(parameter[0], "nomipmaps"))
2130 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2131 else if (!strcasecmp(parameter[0], "nopicmip"))
2132 shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
2133 else if (!strcasecmp(parameter[0], "polygonoffset"))
2134 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2135 else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2137 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2138 if(numparameters >= 2)
2140 shader.biaspolygonfactor = atof(parameter[1]);
2141 if(numparameters >= 3)
2142 shader.biaspolygonoffset = atof(parameter[2]);
2144 shader.biaspolygonoffset = 0;
2147 else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2149 shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
2150 if (!strcasecmp(parameter[1], "sky"))
2151 shader.transparentsort = TRANSPARENTSORT_SKY;
2152 else if (!strcasecmp(parameter[1], "distance"))
2153 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
2154 else if (!strcasecmp(parameter[1], "hud"))
2155 shader.transparentsort = TRANSPARENTSORT_HUD;
2157 Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2159 else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2161 shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
2162 shader.refractfactor = atof(parameter[1]);
2163 Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2165 else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2167 shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
2168 shader.reflectfactor = atof(parameter[1]);
2169 Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2171 else if (!strcasecmp(parameter[0], "dpcamera"))
2173 shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
2175 else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2177 shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
2178 shader.reflectmin = atof(parameter[1]);
2179 shader.reflectmax = atof(parameter[2]);
2180 shader.refractfactor = atof(parameter[3]);
2181 shader.reflectfactor = atof(parameter[4]);
2182 Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2183 Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2184 shader.r_water_wateralpha = atof(parameter[11]);
2186 else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2188 shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2189 shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2191 else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2193 shader.specularscalemod = atof(parameter[1]);
2195 else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2197 shader.specularpowermod = atof(parameter[1]);
2199 else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2201 shader.rtlightambient = atof(parameter[1]);
2203 else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2205 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2206 shader.offsetmapping = OFFSETMAPPING_OFF;
2207 else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2208 shader.offsetmapping = OFFSETMAPPING_DEFAULT;
2209 else if (!strcasecmp(parameter[1], "linear"))
2210 shader.offsetmapping = OFFSETMAPPING_LINEAR;
2211 else if (!strcasecmp(parameter[1], "relief"))
2212 shader.offsetmapping = OFFSETMAPPING_RELIEF;
2213 if (numparameters >= 3)
2214 shader.offsetscale = atof(parameter[2]);
2215 if (numparameters >= 5)
2217 if(!strcasecmp(parameter[3], "bias"))
2218 shader.offsetbias = atof(parameter[4]);
2219 else if(!strcasecmp(parameter[3], "match"))
2220 shader.offsetbias = 1.0f - atof(parameter[4]);
2221 else if(!strcasecmp(parameter[3], "match8"))
2222 shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2223 else if(!strcasecmp(parameter[3], "match16"))
2224 shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2227 else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2230 for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2231 if (!shader.deforms[deformindex].deform)
2233 if (deformindex < Q3MAXDEFORMS)
2235 for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2236 shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2237 if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2238 else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2239 else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2240 else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2241 else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2242 else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2243 else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2244 else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2245 else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2246 else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2247 else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2248 else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2249 else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2250 else if (!strcasecmp(parameter[1], "wave" ))
2252 shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2253 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2254 for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2255 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2257 else if (!strcasecmp(parameter[1], "move" ))
2259 shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2260 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2261 for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2262 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2267 // hide this shader if a cvar said it should be killed
2268 if (shader.dpshaderkill)
2269 shader.numlayers = 0;
2270 // fix up multiple reflection types
2271 if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
2272 shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
2274 Q3Shader_AddToHash (&shader);
2278 FS_FreeSearch(search);
2279 // free custinfoparm values
2280 for (j = 0; j < numcustsurfaceflags; j++)
2281 Mem_Free(custsurfaceparmnames[j]);
2284 q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
2286 unsigned short hash;
2287 q3shader_hash_entry_t* entry;
2289 Mod_LoadQ3Shaders();
2290 hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2291 entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2292 while (entry != NULL)
2294 if (strcasecmp (entry->shader.name, name) == 0)
2295 return &entry->shader;
2296 entry = entry->chain;
2301 texture_shaderpass_t *Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe)
2303 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2304 shaderpass->framerate = 0.0f;
2305 shaderpass->numframes = 1;
2306 shaderpass->blendfunc[0] = GL_ONE;
2307 shaderpass->blendfunc[1] = GL_ZERO;
2308 shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
2309 shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
2310 shaderpass->alphatest = false;
2311 shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
2312 shaderpass->skinframes[0] = skinframe;
2316 texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
2319 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2320 shaderpass->alphatest = layer->alphatest != 0;
2321 shaderpass->framerate = layer->framerate;
2322 shaderpass->numframes = layer->numframes;
2323 shaderpass->blendfunc[0] = layer->blendfunc[0];
2324 shaderpass->blendfunc[1] = layer->blendfunc[1];
2325 shaderpass->rgbgen = layer->rgbgen;
2326 shaderpass->alphagen = layer->alphagen;
2327 shaderpass->tcgen = layer->tcgen;
2328 for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
2329 shaderpass->tcmods[j] = layer->tcmods[j];
2330 for (j = 0; j < layer->numframes; j++)
2331 shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true);
2335 qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags, int defaultmaterialflags)
2337 int texflagsmask, texflagsor;
2338 qboolean success = true;
2339 q3shaderinfo_t *shader;
2342 strlcpy(texture->name, name, sizeof(texture->name));
2343 texture->basealpha = 1.0f;
2344 shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2346 // allow disabling of picmip or compression by defaulttexflags
2348 if(!(defaulttexflags & TEXF_PICMIP))
2349 texflagsmask &= ~TEXF_PICMIP;
2350 if(!(defaulttexflags & TEXF_COMPRESS))
2351 texflagsmask &= ~TEXF_COMPRESS;
2353 if(defaulttexflags & TEXF_ISWORLD)
2354 texflagsor |= TEXF_ISWORLD;
2355 if(defaulttexflags & TEXF_ISSPRITE)
2356 texflagsor |= TEXF_ISSPRITE;
2357 // unless later loaded from the shader
2358 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2359 texture->offsetscale = 1;
2360 texture->offsetbias = 0;
2361 texture->specularscalemod = 1;
2362 texture->specularpowermod = 1;
2363 texture->rtlightambient = 0;
2364 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2365 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2366 // JUST GREP FOR "specularscalemod = 1".
2370 if (developer_loading.integer)
2371 Con_Printf("%s: loaded shader for %s\n", modelname, name);
2373 if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2375 texture->basematerialflags = MATERIALFLAG_SKY;
2376 if (shader->skyboxname[0] && loadmodel)
2378 // quake3 seems to append a _ to the skybox name, so this must do so as well
2379 dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2382 else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2383 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2385 texture->basematerialflags = MATERIALFLAG_WALL;
2387 if (shader->layers[0].alphatest)
2388 texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
2389 if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2390 texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2391 if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET)
2393 texture->biaspolygonoffset += shader->biaspolygonoffset;
2394 texture->biaspolygonfactor += shader->biaspolygonfactor;
2396 if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION)
2397 texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2398 if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION)
2399 texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2400 if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
2401 texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2402 if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2403 texture->basematerialflags |= MATERIALFLAG_CAMERA;
2404 texture->customblendfunc[0] = GL_ONE;
2405 texture->customblendfunc[1] = GL_ZERO;
2406 texture->transparentsort = shader->transparentsort;
2407 if (shader->numlayers > 0)
2409 texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2410 texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2412 Q3 shader blendfuncs actually used in the game (* = supported by DP)
2413 * additive GL_ONE GL_ONE
2414 additive weird GL_ONE GL_SRC_ALPHA
2415 additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
2416 * alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2417 alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2418 brighten GL_DST_COLOR GL_ONE
2419 brighten GL_ONE GL_SRC_COLOR
2420 brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2421 brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
2422 * modulate GL_DST_COLOR GL_ZERO
2423 * modulate GL_ZERO GL_SRC_COLOR
2424 modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
2425 modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2426 modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2427 * modulate x2 GL_DST_COLOR GL_SRC_COLOR
2428 * no blend GL_ONE GL_ZERO
2429 nothing GL_ZERO GL_ONE
2431 // if not opaque, figure out what blendfunc to use
2432 if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2434 if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2435 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2436 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2437 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2438 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2439 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2441 texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2444 if (!shader->lighting)
2445 texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2447 // here be dragons: convert quake3 shaders to material
2448 if (shader->numlayers > 0)
2451 int terrainbackgroundlayer = -1;
2452 int lightmaplayer = -1;
2453 int alphagenspecularlayer = -1;
2454 int rgbgenvertexlayer = -1;
2455 int rgbgendiffuselayer = -1;
2456 int materiallayer = -1;
2457 int endofprelayers = 0;
2458 int firstpostlayer = 0;
2459 int shaderpassindex = 0;
2460 for (i = 0; i < shader->numlayers; i++)
2462 if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
2464 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2465 rgbgenvertexlayer = i;
2466 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
2467 rgbgendiffuselayer = i;
2468 if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
2469 alphagenspecularlayer = i;
2471 if (shader->numlayers >= 2
2472 && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2473 && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
2474 && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2475 || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
2477 // terrain blend or certain other effects involving alphatest over a regular layer
2478 terrainbackgroundlayer = 0;
2480 // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
2481 firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
2483 else if (lightmaplayer == 0)
2485 // ordinary texture but with $lightmap before diffuse
2487 firstpostlayer = lightmaplayer + 2;
2489 else if (lightmaplayer >= 1)
2491 // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
2492 endofprelayers = lightmaplayer - 1;
2493 materiallayer = lightmaplayer - 1;
2494 firstpostlayer = lightmaplayer + 1;
2496 else if (rgbgenvertexlayer >= 0)
2498 // map models with baked lighting
2499 materiallayer = rgbgenvertexlayer;
2500 endofprelayers = rgbgenvertexlayer;
2501 firstpostlayer = rgbgenvertexlayer + 1;
2502 // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
2503 if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
2504 texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR;
2506 else if (rgbgendiffuselayer >= 0)
2508 // entity models with dynamic lighting
2509 materiallayer = rgbgendiffuselayer;
2510 endofprelayers = rgbgendiffuselayer;
2511 firstpostlayer = rgbgendiffuselayer + 1;
2512 // 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)...
2513 if (alphagenspecularlayer >= 0)
2514 firstpostlayer = alphagenspecularlayer + 1;
2518 // special effects shaders - treat first as primary layer and do everything else as post
2523 // convert the main material layer
2524 // 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
2525 if (materiallayer >= 0)
2526 texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2527 // convert the terrain background blend layer (if any)
2528 if (terrainbackgroundlayer >= 0)
2529 texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2530 // convert the prepass layers (if any)
2531 texture->startpreshaderpass = shaderpassindex;
2532 for (i = 0; i < endofprelayers; i++)
2533 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2534 texture->endpreshaderpass = shaderpassindex;
2535 texture->startpostshaderpass = shaderpassindex;
2536 // convert the postpass layers (if any)
2537 for (i = firstpostlayer; i < shader->numlayers; i++)
2538 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2539 texture->startpostshaderpass = shaderpassindex;
2542 if (shader->dpshadow)
2543 texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2544 if (shader->dpnoshadow)
2545 texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2546 if (shader->dpnortlight)
2547 texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2548 if (shader->vertexalpha)
2549 texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2550 memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2551 texture->reflectmin = shader->reflectmin;
2552 texture->reflectmax = shader->reflectmax;
2553 texture->refractfactor = shader->refractfactor;
2554 Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2555 texture->reflectfactor = shader->reflectfactor;
2556 Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2557 texture->r_water_wateralpha = shader->r_water_wateralpha;
2558 Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2559 texture->offsetmapping = shader->offsetmapping;
2560 texture->offsetscale = shader->offsetscale;
2561 texture->offsetbias = shader->offsetbias;
2562 texture->specularscalemod = shader->specularscalemod;
2563 texture->specularpowermod = shader->specularpowermod;
2564 texture->rtlightambient = shader->rtlightambient;
2565 if (shader->dpreflectcube[0])
2566 texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2568 // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2569 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2570 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ;
2571 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ;
2572 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ;
2573 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ;
2574 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ;
2575 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ;
2576 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ;
2578 // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ;
2579 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ;
2580 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2581 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ;
2582 if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ;
2583 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ;
2584 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ;
2585 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ;
2586 // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ;
2587 // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ;
2588 // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ;
2589 // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ;
2590 if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ;
2591 // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ;
2592 // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ;
2593 // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ;
2594 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ;
2595 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ;
2596 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ;
2597 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ;
2598 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ;
2599 // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ;
2600 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ;
2601 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ;
2602 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ;
2603 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ;
2604 // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ;
2605 // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ;
2606 // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ;
2607 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP;
2608 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ;
2609 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ;
2611 texture->surfaceflags = shader->surfaceflags;
2612 if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ;
2613 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ;
2614 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2615 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ;
2616 // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ;
2617 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ;
2618 // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ;
2619 if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ;
2620 if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ;
2621 if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ;
2622 if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ;
2623 if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ;
2624 // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ;
2625 if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ;
2626 if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ;
2627 if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ;
2628 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ;
2629 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ;
2630 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ;
2631 // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ;
2632 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ;
2633 if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ;
2634 // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ;
2635 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ;
2636 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ;
2637 // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ;
2638 if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ;
2639 if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ;
2640 if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ;
2641 // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ;
2642 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ;
2643 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ;
2645 if (shader->dpmeshcollisions)
2646 texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2647 if (shader->dpshaderkill && developer_extra.integer)
2648 Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", modelname, name);
2650 else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2652 if (developer_extra.integer)
2653 Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name);
2654 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2656 else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2658 if (developer_extra.integer)
2659 Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", modelname, name);
2660 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2661 texture->supercontents = SUPERCONTENTS_SOLID;
2665 if (developer_extra.integer)
2666 Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name);
2667 if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2669 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2670 texture->supercontents = SUPERCONTENTS_SOLID;
2672 else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2674 texture->basematerialflags = MATERIALFLAG_SKY;
2675 texture->supercontents = SUPERCONTENTS_SKY;
2679 texture->basematerialflags = defaultmaterialflags;
2680 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2682 if(cls.state == ca_dedicated)
2684 texture->materialshaderpass = NULL;
2689 skinframe_t *skinframe = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, fallback);
2692 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2693 if (texture->materialshaderpass->skinframes[0]->hasalpha)
2694 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2695 if (texture->q2contents)
2696 texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents);
2700 if (!success && warnmissing)
2701 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", modelname, texture->name);
2704 // init the animation variables
2705 texture->currentframe = texture;
2706 texture->currentmaterialflags = texture->basematerialflags;
2707 if (!texture->materialshaderpass)
2708 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadMissing());
2709 if (!texture->materialshaderpass->skinframes[0])
2710 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2711 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2712 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2716 void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
2718 if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
2719 Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name);
2721 strlcpy(texture->name, name, sizeof(texture->name));
2722 texture->basealpha = 1.0f;
2723 texture->basematerialflags = materialflags;
2724 texture->supercontents = supercontents;
2726 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2727 texture->offsetscale = 1;
2728 texture->offsetbias = 0;
2729 texture->specularscalemod = 1;
2730 texture->specularpowermod = 1;
2731 texture->rtlightambient = 0;
2732 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2733 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2734 // JUST GREP FOR "specularscalemod = 1".
2736 if (developer_extra.integer)
2737 Con_DPrintf("^1Custom texture ^3\"%s\"\n", texture->name);
2739 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2741 // init the animation variables
2742 texture->currentmaterialflags = texture->basematerialflags;
2743 texture->currentframe = texture;
2744 texture->currentskinframe = skinframe;
2745 texture->backgroundcurrentskinframe = NULL;
2748 void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins)
2751 for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++)
2753 if (texture->shaderpasses[i])
2756 for (j = 0; j < sizeof(texture->shaderpasses[i]->skinframes) / sizeof(skinframe_t *);j++)
2757 if (texture->shaderpasses[i]->skinframes[j] && texture->shaderpasses[i]->skinframes[j]->base)
2758 R_SkinFrame_PurgeSkinFrame(texture->shaderpasses[i]->skinframes[j]);
2759 Mem_Free(texture->shaderpasses[i]);
2760 texture->shaderpasses[i] = NULL;
2763 texture->materialshaderpass = NULL;
2764 texture->currentskinframe = NULL;
2765 texture->backgroundcurrentskinframe = NULL;
2768 skinfile_t *Mod_LoadSkinFiles(void)
2770 int i, words, line, wordsoverflow;
2773 skinfile_t *skinfile = NULL, *first = NULL;
2774 skinfileitem_t *skinfileitem;
2775 char word[10][MAX_QPATH];
2780 U_bodyBox,models/players/Legoman/BikerA2.tga
2781 U_RArm,models/players/Legoman/BikerA1.tga
2782 U_LArm,models/players/Legoman/BikerA1.tga
2783 U_armor,common/nodraw
2784 U_sword,common/nodraw
2785 U_shield,common/nodraw
2786 U_homb,common/nodraw
2787 U_backpack,common/nodraw
2788 U_colcha,common/nodraw
2793 memset(word, 0, sizeof(word));
2794 for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2796 // If it's the first file we parse
2797 if (skinfile == NULL)
2799 skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2804 skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2805 skinfile = skinfile->next;
2807 skinfile->next = NULL;
2809 for(line = 0;;line++)
2812 if (!COM_ParseToken_QuakeC(&data, true))
2814 if (!strcmp(com_token, "\n"))
2817 wordsoverflow = false;
2821 strlcpy(word[words++], com_token, sizeof (word[0]));
2823 wordsoverflow = true;
2825 while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2828 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);
2831 // words is always >= 1
2832 if (!strcmp(word[0], "replace"))
2836 if (developer_loading.integer)
2837 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2838 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2839 skinfileitem->next = skinfile->items;
2840 skinfile->items = skinfileitem;
2841 strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2842 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2845 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]);
2847 else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2849 // tag name, like "tag_weapon,"
2850 // not used for anything (not even in Quake3)
2852 else if (words >= 2 && !strcmp(word[1], ","))
2854 // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2855 if (developer_loading.integer)
2856 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2857 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2858 skinfileitem->next = skinfile->items;
2859 skinfile->items = skinfileitem;
2860 strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2861 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2864 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);
2869 loadmodel->numskins = i;
2873 void Mod_FreeSkinFiles(skinfile_t *skinfile)
2876 skinfileitem_t *skinfileitem, *nextitem;
2877 for (;skinfile;skinfile = next)
2879 next = skinfile->next;
2880 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2882 nextitem = skinfileitem->next;
2883 Mem_Free(skinfileitem);
2889 int Mod_CountSkinFiles(skinfile_t *skinfile)
2892 for (i = 0;skinfile;skinfile = skinfile->next, i++);
2896 void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
2899 double isnap = 1.0 / snap;
2900 for (i = 0;i < numvertices*numcomponents;i++)
2901 vertices[i] = floor(vertices[i]*isnap)*snap;
2904 int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
2906 int i, outtriangles;
2907 float edgedir1[3], edgedir2[3], temp[3];
2908 // a degenerate triangle is one with no width (thickness, surface area)
2909 // these are characterized by having all 3 points colinear (along a line)
2910 // or having two points identical
2911 // the simplest check is to calculate the triangle's area
2912 for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
2914 // calculate first edge
2915 VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
2916 VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
2917 CrossProduct(edgedir1, edgedir2, temp);
2918 if (VectorLength2(temp) < 0.001f)
2919 continue; // degenerate triangle (no area)
2920 // valid triangle (has area)
2921 VectorCopy(inelement3i, outelement3i);
2925 return outtriangles;
2928 void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
2931 int firstvertex, lastvertex;
2932 if (numelements > 0 && elements)
2934 firstvertex = lastvertex = elements[0];
2935 for (i = 1;i < numelements;i++)
2938 firstvertex = min(firstvertex, e);
2939 lastvertex = max(lastvertex, e);
2943 firstvertex = lastvertex = 0;
2944 if (firstvertexpointer)
2945 *firstvertexpointer = firstvertex;
2946 if (lastvertexpointer)
2947 *lastvertexpointer = lastvertex;
2950 void Mod_MakeSortedSurfaces(dp_model_t *mod)
2952 // make an optimal set of texture-sorted batches to draw...
2954 int *firstsurfacefortexture;
2955 int *numsurfacesfortexture;
2956 if (!mod->sortedmodelsurfaces)
2957 mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
2958 firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
2959 numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
2960 memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
2961 for (j = 0;j < mod->nummodelsurfaces;j++)
2963 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2964 t = (int)(surface->texture - mod->data_textures);
2965 numsurfacesfortexture[t]++;
2968 for (t = 0;t < mod->num_textures;t++)
2970 firstsurfacefortexture[t] = j;
2971 j += numsurfacesfortexture[t];
2973 for (j = 0;j < mod->nummodelsurfaces;j++)
2975 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
2976 t = (int)(surface->texture - mod->data_textures);
2977 mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
2979 Mem_Free(firstsurfacefortexture);
2980 Mem_Free(numsurfacesfortexture);
2983 void Mod_BuildVBOs(void)
2985 if (!loadmodel->surfmesh.num_vertices)
2988 if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
2991 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2993 if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
2995 Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
2996 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3001 // build r_vertexmesh_t array
3002 // (compressed interleaved array for D3D)
3003 if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
3006 int numvertices = loadmodel->surfmesh.num_vertices;
3007 r_vertexmesh_t *vertexmesh;
3008 loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
3009 for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
3011 VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
3012 VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
3013 VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
3014 VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
3015 if (loadmodel->surfmesh.data_lightmapcolor4f)
3016 Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f);
3017 Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
3018 if (loadmodel->surfmesh.data_texcoordlightmap2f)
3019 Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
3020 if (loadmodel->surfmesh.data_skeletalindex4ub)
3021 Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
3022 if (loadmodel->surfmesh.data_skeletalweight4ub)
3023 Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
3027 // upload short indices as a buffer
3028 if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
3029 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);
3031 // upload int indices as a buffer
3032 if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
3033 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);
3035 // only build a vbo if one has not already been created (this is important for brush models which load specially)
3036 // vertex buffer is several arrays and we put them in the same buffer
3038 // is this wise? the texcoordtexture2f array is used with dynamic
3039 // vertex/svector/tvector/normal when rendering animated models, on the
3040 // other hand animated models don't use a lot of vertices anyway...
3041 if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
3046 loadmodel->surfmesh.vbooffset_vertexmesh = size;if (loadmodel->surfmesh.data_vertexmesh ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
3047 loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3048 loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3049 loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3050 loadmodel->surfmesh.vbooffset_normal3f = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3051 loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3052 loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3053 loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3054 loadmodel->surfmesh.vbooffset_skeletalindex4ub = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3055 loadmodel->surfmesh.vbooffset_skeletalweight4ub = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3056 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
3057 if (loadmodel->surfmesh.data_vertexmesh ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh , loadmodel->surfmesh.data_vertexmesh , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
3058 if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3059 if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3060 if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3061 if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3062 if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3063 if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3064 if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
3065 if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3066 if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3067 loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
3072 extern cvar_t mod_obj_orientation;
3073 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
3075 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
3077 const char *texname;
3079 const float *v, *vn, *vt;
3081 size_t outbufferpos = 0;
3082 size_t outbuffermax = 0x100000;
3083 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3084 const msurface_t *surface;
3085 const int maxtextures = 256;
3086 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
3087 dp_model_t *submodel;
3089 // construct the mtllib file
3090 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
3093 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3096 countvertices += surface->num_vertices;
3097 countfaces += surface->num_triangles;
3098 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
3099 for (textureindex = 0;textureindex < counttextures;textureindex++)
3100 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
3102 if (textureindex < counttextures)
3103 continue; // already wrote this material entry
3104 if (textureindex >= maxtextures)
3105 continue; // just a precaution
3106 textureindex = counttextures++;
3107 strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
3108 if (outbufferpos >= outbuffermax >> 1)
3111 oldbuffer = outbuffer;
3112 outbuffer = (char *) Z_Malloc(outbuffermax);
3113 memcpy(outbuffer, oldbuffer, outbufferpos);
3116 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");
3121 // write the mtllib file
3122 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3124 // construct the obj file
3126 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);
3130 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)
3132 if (outbufferpos >= outbuffermax >> 1)
3135 oldbuffer = outbuffer;
3136 outbuffer = (char *) Z_Malloc(outbuffermax);
3137 memcpy(outbuffer, oldbuffer, outbufferpos);
3140 if(mod_obj_orientation.integer)
3141 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]);
3143 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]);
3148 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3150 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3153 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3154 for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3156 surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3157 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3160 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3162 if (outbufferpos >= outbuffermax >> 1)
3165 oldbuffer = outbuffer;
3166 outbuffer = (char *) Z_Malloc(outbuffermax);
3167 memcpy(outbuffer, oldbuffer, outbufferpos);
3173 if(mod_obj_orientation.integer)
3174 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);
3176 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "f %i/%i/%i %i/%i/%i %i/%i/%i\n", a,a,a,c,c,c,b,b,b);
3183 // write the obj file
3184 FS_WriteFile(filename, outbuffer, outbufferpos);
3188 Z_Free(texturenames);
3191 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3194 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3196 int countnodes = 0, counttriangles = 0, countframes = 0;
3204 size_t outbufferpos = 0;
3205 size_t outbuffermax = 0x100000;
3206 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3207 const msurface_t *surface;
3208 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3211 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3213 if (outbufferpos >= outbuffermax >> 1)
3216 oldbuffer = outbuffer;
3217 outbuffer = (char *) Z_Malloc(outbuffermax);
3218 memcpy(outbuffer, oldbuffer, outbufferpos);
3222 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3226 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3229 for (poseindex = 0;poseindex < numposes;poseindex++)
3232 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3235 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3239 matrix4x4_t posematrix;
3240 if (outbufferpos >= outbuffermax >> 1)
3243 oldbuffer = outbuffer;
3244 outbuffer = (char *) Z_Malloc(outbuffermax);
3245 memcpy(outbuffer, oldbuffer, outbufferpos);
3249 // strangely the smd angles are for a transposed matrix, so we
3250 // have to generate a transposed matrix, then convert that...
3251 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3252 Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3253 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3254 if (angles[0] >= 180) angles[0] -= 360;
3255 if (angles[1] >= 180) angles[1] -= 360;
3256 if (angles[2] >= 180) angles[2] -= 360;
3260 float a = DEG2RAD(angles[ROLL]);
3261 float b = DEG2RAD(angles[PITCH]);
3262 float c = DEG2RAD(angles[YAW]);
3263 float cy, sy, cp, sp, cr, sr;
3265 // smd matrix construction, for comparing
3276 test[1][0] = sr*sp*cy+cr*-sy;
3277 test[1][1] = sr*sp*sy+cr*cy;
3279 test[2][0] = (cr*sp*cy+-sr*-sy);
3280 test[2][1] = (cr*sp*sy+-sr*cy);
3282 test[3][0] = pose[9];
3283 test[3][1] = pose[10];
3284 test[3][2] = pose[11];
3287 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]));
3292 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3297 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3300 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3302 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3305 if (outbufferpos >= outbuffermax >> 1)
3308 oldbuffer = outbuffer;
3309 outbuffer = (char *) Z_Malloc(outbuffermax);
3310 memcpy(outbuffer, oldbuffer, outbufferpos);
3313 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3316 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3318 const int index = e[2-cornerindex];
3319 const float *v = model->surfmesh.data_vertex3f + index * 3;
3320 const float *vn = model->surfmesh.data_normal3f + index * 3;
3321 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3322 const int b = model->surfmesh.blends[index];
3323 if (b < model->num_bones)
3324 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]);
3327 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3328 const unsigned char *wi = w->index;
3329 const unsigned char *wf = w->influence;
3330 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);
3331 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);
3332 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);
3333 else l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i %f %f %f %f %f %f %f %f\n" , wi[0], v[0], v[1], v[2], vn[0], vn[1], vn[2], vt[0], 1 - vt[1]);
3340 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3345 FS_WriteFile(filename, outbuffer, outbufferpos);
3348 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3355 decompiles a model to editable files
3358 static void Mod_Decompile_f(void)
3360 int i, j, k, l, first, count;
3362 char inname[MAX_QPATH];
3363 char outname[MAX_QPATH];
3364 char mtlname[MAX_QPATH];
3365 char basename[MAX_QPATH];
3366 char animname[MAX_QPATH];
3367 char animname2[MAX_QPATH];
3368 char zymtextbuffer[16384];
3369 char dpmtextbuffer[16384];
3370 char framegroupstextbuffer[16384];
3371 int zymtextsize = 0;
3372 int dpmtextsize = 0;
3373 int framegroupstextsize = 0;
3376 if (Cmd_Argc() != 2)
3378 Con_Print("usage: modeldecompile <filename>\n");
3382 strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3383 FS_StripExtension(inname, basename, sizeof(basename));
3385 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3388 Con_Print("No such model\n");
3391 if (mod->brush.submodel)
3393 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3394 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3395 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3398 if (!mod->surfmesh.num_triangles)
3400 Con_Print("Empty model (or sprite)\n");
3404 // export OBJ if possible (not on sprites)
3405 if (mod->surfmesh.num_triangles)
3407 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3408 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3409 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3412 // export SMD if possible (only for skeletal models)
3413 if (mod->surfmesh.num_triangles && mod->num_bones)
3415 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3416 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3417 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3418 if (l > 0) zymtextsize += l;
3419 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3420 if (l > 0) dpmtextsize += l;
3421 for (i = 0;i < mod->numframes;i = j)
3423 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3424 first = mod->animscenes[i].firstframe;
3425 if (mod->animscenes[i].framecount > 1)
3428 count = mod->animscenes[i].framecount;
3434 // check for additional frames with same name
3435 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3436 if(animname[l] < '0' || animname[l] > '9')
3438 if(k > 0 && animname[k-1] == '_')
3441 count = mod->num_poses - first;
3442 for (j = i + 1;j < mod->numframes;j++)
3444 strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3445 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3446 if(animname2[l] < '0' || animname2[l] > '9')
3448 if(k > 0 && animname[k-1] == '_')
3451 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3453 count = mod->animscenes[j].firstframe - first;
3457 // if it's only one frame, use the original frame name
3459 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3462 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3463 Mod_Decompile_SMD(mod, outname, first, count, false);
3464 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3466 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3467 if (l > 0) zymtextsize += l;
3469 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3471 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3472 if (l > 0) dpmtextsize += l;
3474 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3476 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3477 if (l > 0) framegroupstextsize += l;
3481 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3483 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3484 if (framegroupstextsize)
3485 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3489 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
3492 memset(state, 0, sizeof(*state));
3493 state->width = width;
3494 state->height = height;
3495 state->currentY = 0;
3496 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3497 for (y = 0;y < state->height;y++)
3499 state->rows[y].currentX = 0;
3500 state->rows[y].rowY = -1;
3504 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3507 state->currentY = 0;
3508 for (y = 0;y < state->height;y++)
3510 state->rows[y].currentX = 0;
3511 state->rows[y].rowY = -1;
3515 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3518 Mem_Free(state->rows);
3519 memset(state, 0, sizeof(*state));
3522 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3524 mod_alloclightmap_row_t *row;
3527 row = state->rows + blockheight;
3528 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3530 if (state->currentY + blockheight <= state->height)
3532 // use the current allocation position
3533 row->rowY = state->currentY;
3535 state->currentY += blockheight;
3539 // find another position
3540 for (y = blockheight;y < state->height;y++)
3542 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3544 row = state->rows + y;
3548 if (y == state->height)
3553 *outx = row->currentX;
3554 row->currentX += blockwidth;
3559 typedef struct lightmapsample_s
3563 float *vertex_color;
3564 unsigned char *lm_bgr;
3565 unsigned char *lm_dir;
3569 typedef struct lightmapvertex_s
3574 float texcoordbase[2];
3575 float texcoordlightmap[2];
3576 float lightcolor[4];
3580 typedef struct lightmaptriangle_s
3588 // 2D modelspace coordinates of min corner
3589 // snapped to lightmap grid but not in grid coordinates
3591 // 2D modelspace to lightmap coordinate scale
3599 typedef struct lightmaplight_s
3610 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3612 #define MAX_LIGHTMAPSAMPLES 64
3613 static int mod_generatelightmaps_numoffsets[3];
3614 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3616 static int mod_generatelightmaps_numlights;
3617 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3619 extern cvar_t r_shadow_lightattenuationdividebias;
3620 extern cvar_t r_shadow_lightattenuationlinearscale;
3622 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3627 float relativepoint[3];
3634 float lightorigin[3];
3638 float lightcolor[3];
3640 for (i = 0;i < 5*3;i++)
3642 for (index = 0;;index++)
3644 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3649 lightradius2 = lightradius * lightradius;
3650 VectorSubtract(lightorigin, pos, relativepoint);
3651 dist2 = VectorLength2(relativepoint);
3652 if (dist2 >= lightradius2)
3654 lightiradius = 1.0f / lightradius;
3655 dist = sqrt(dist2) * lightiradius;
3656 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3657 if (intensity <= 0.0f)
3659 if (model && model->TraceLine)
3661 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3662 if (trace.fraction < 1)
3665 // scale down intensity to add to both ambient and diffuse
3666 //intensity *= 0.5f;
3667 VectorNormalize(relativepoint);
3668 VectorScale(lightcolor, intensity, color);
3669 VectorMA(sample , 0.5f , color, sample );
3670 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3671 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3672 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3673 // calculate a weighted average light direction as well
3674 intensity *= VectorLength(color);
3675 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3677 // calculate the direction we'll use to reduce the sample to a directional light source
3678 VectorCopy(sample + 12, dir);
3679 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3680 VectorNormalize(dir);
3681 // extract the diffuse color along the chosen direction and scale it
3682 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3683 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3684 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3685 // subtract some of diffuse from ambient
3686 VectorMA(sample, -0.333f, diffuse, ambient);
3687 // store the normalized lightdir
3688 VectorCopy(dir, lightdir);
3691 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3695 const msurface_t *surface;
3696 const float *vertex3f = model->surfmesh.data_vertex3f;
3697 const int *element3i = model->surfmesh.data_element3i;
3700 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3702 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3704 if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3706 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3708 VectorCopy(vertex3f + 3*e[0], v2[0]);
3709 VectorCopy(vertex3f + 3*e[1], v2[1]);
3710 VectorCopy(vertex3f + 3*e[2], v2[2]);
3711 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3716 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3718 int maxnodes = 1<<14;
3719 svbsp_node_t *nodes;
3724 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3725 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3726 VectorCopy(lightinfo->origin, origin);
3727 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3730 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3731 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3732 if (svbsp.ranoutofnodes)
3735 if (maxnodes > 1<<22)
3741 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3746 if (svbsp.numnodes > 0)
3748 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3749 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3750 lightinfo->svbsp = svbsp;
3755 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3759 lightmaplight_t *lightinfo;
3763 mod_generatelightmaps_numlights = 0;
3764 for (index = 0;;index++)
3766 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3770 mod_generatelightmaps_numlights++;
3772 if (mod_generatelightmaps_numlights > 0)
3774 mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3775 lightinfo = mod_generatelightmaps_lightinfo;
3776 for (index = 0;;index++)
3778 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3785 for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3787 lightinfo->iradius = 1.0f / lightinfo->radius;
3788 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3789 // TODO: compute svbsp
3790 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3794 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3797 if (mod_generatelightmaps_lightinfo)
3799 for (i = 0;i < mod_generatelightmaps_numlights;i++)
3800 if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3801 Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3802 Mem_Free(mod_generatelightmaps_lightinfo);
3804 mod_generatelightmaps_lightinfo = NULL;
3805 mod_generatelightmaps_numlights = 0;
3808 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3810 const svbsp_node_t *node;
3811 const svbsp_node_t *nodes = svbsp->nodes;
3816 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3818 return num == -1; // true if empty, false if solid (shadowed)
3821 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3824 float relativepoint[3];
3833 const lightmaplight_t *lightinfo;
3835 for (i = 0;i < 5*3;i++)
3837 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3839 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3840 VectorSubtract(lightinfo->origin, pos, relativepoint);
3841 // don't accept light from behind a surface, it causes bad shading
3842 if (normal && DotProduct(relativepoint, normal) <= 0)
3844 dist2 = VectorLength2(relativepoint);
3845 if (dist2 >= lightinfo->radius2)
3847 dist = sqrt(dist2) * lightinfo->iradius;
3848 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3851 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3855 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3857 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3859 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3862 // for light grid we'd better check visibility of the offset point
3863 cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3864 if (trace.fraction < 1)
3865 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3868 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3873 // scale intensity according to how many rays succeeded
3874 // we know one test is valid, half of the rest will fail...
3875 //if (normal && tests > 1)
3876 // intensity *= (tests - 1.0f) / tests;
3877 intensity *= (float)hits / tests;
3879 // scale down intensity to add to both ambient and diffuse
3880 //intensity *= 0.5f;
3881 VectorNormalize(relativepoint);
3882 VectorScale(lightinfo->color, intensity, color);
3883 VectorMA(sample , 0.5f , color, sample );
3884 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3885 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3886 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3887 // calculate a weighted average light direction as well
3888 intensity *= VectorLength(color);
3889 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3893 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3899 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
3900 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3901 VectorCopy(sample + 12, dir);
3902 VectorNormalize(dir);
3903 //VectorAdd(dir, normal, dir);
3904 //VectorNormalize(dir);
3905 f = DotProduct(dir, normal);
3906 f = max(0, f) * 255.0f;
3907 VectorScale(sample, f, color);
3908 //VectorCopy(normal, dir);
3909 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3910 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3911 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3912 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3914 lm_dir[0] = (unsigned char)dir[2];
3915 lm_dir[1] = (unsigned char)dir[1];
3916 lm_dir[2] = (unsigned char)dir[0];
3920 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3923 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
3924 VectorCopy(sample, vertex_color);
3927 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3933 Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
3934 // calculate the direction we'll use to reduce the sample to a directional light source
3935 VectorCopy(sample + 12, dir);
3936 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3937 VectorNormalize(dir);
3938 // extract the diffuse color along the chosen direction and scale it
3939 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3940 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3941 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3942 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3943 VectorScale(sample, 127.5f, ambient);
3944 VectorMA(ambient, -0.333f, diffuse, ambient);
3945 // encode to the grid format
3946 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3947 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3948 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3949 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3950 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3951 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3952 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3953 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3954 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));}
3957 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
3962 memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
3963 mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
3964 mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
3965 mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
3966 radius[0] = mod_generatelightmaps_lightmapradius.value;
3967 radius[1] = mod_generatelightmaps_vertexradius.value;
3968 radius[2] = mod_generatelightmaps_gridradius.value;
3969 for (i = 0;i < 3;i++)
3971 for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
3974 VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
3979 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
3981 msurface_t *surface;
3984 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3986 surface = model->data_surfaces + surfaceindex;
3987 surface->lightmaptexture = NULL;
3988 surface->deluxemaptexture = NULL;
3990 if (model->brushq3.data_lightmaps)
3992 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3993 if (model->brushq3.data_lightmaps[i])
3994 R_FreeTexture(model->brushq3.data_lightmaps[i]);
3995 Mem_Free(model->brushq3.data_lightmaps);
3996 model->brushq3.data_lightmaps = NULL;
3998 if (model->brushq3.data_deluxemaps)
4000 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4001 if (model->brushq3.data_deluxemaps[i])
4002 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
4003 Mem_Free(model->brushq3.data_deluxemaps);
4004 model->brushq3.data_deluxemaps = NULL;
4008 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
4010 msurface_t *surface;
4016 surfmesh_t oldsurfmesh;
4018 unsigned char *data;
4019 oldsurfmesh = model->surfmesh;
4020 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
4021 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
4023 size += model->surfmesh.num_vertices * sizeof(float[3]);
4024 size += model->surfmesh.num_vertices * sizeof(float[3]);
4025 size += model->surfmesh.num_vertices * sizeof(float[3]);
4026 size += model->surfmesh.num_vertices * sizeof(float[3]);
4027 size += model->surfmesh.num_vertices * sizeof(float[2]);
4028 size += model->surfmesh.num_vertices * sizeof(float[2]);
4029 size += model->surfmesh.num_vertices * sizeof(float[4]);
4030 data = (unsigned char *)Mem_Alloc(model->mempool, size);
4031 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4032 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4033 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4034 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4035 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4036 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4037 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
4038 if (model->surfmesh.num_vertices > 65536)
4039 model->surfmesh.data_element3s = NULL;
4041 if (model->surfmesh.data_element3i_indexbuffer)
4042 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
4043 model->surfmesh.data_element3i_indexbuffer = NULL;
4044 if (model->surfmesh.data_element3s_indexbuffer)
4045 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
4046 model->surfmesh.data_element3s_indexbuffer = NULL;
4047 if (model->surfmesh.vbo_vertexbuffer)
4048 R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
4049 model->surfmesh.vbo_vertexbuffer = 0;
4051 // convert all triangles to unique vertex data
4053 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4055 surface = model->data_surfaces + surfaceindex;
4056 surface->num_firstvertex = outvertexindex;
4057 surface->num_vertices = surface->num_triangles*3;
4058 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
4059 for (i = 0;i < surface->num_triangles*3;i++)
4062 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
4063 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
4064 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
4065 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
4066 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
4067 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
4068 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
4069 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
4070 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
4071 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
4072 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
4073 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
4074 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
4075 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
4076 if (oldsurfmesh.data_texcoordlightmap2f)
4078 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
4079 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
4081 if (oldsurfmesh.data_lightmapcolor4f)
4083 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
4084 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
4085 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
4086 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
4089 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
4090 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
4094 if (model->surfmesh.data_element3s)
4095 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
4096 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
4098 // find and update all submodels to use this new surfmesh data
4099 for (i = 0;i < model->brush.numsubmodels;i++)
4100 model->brush.submodels[i]->surfmesh = model->surfmesh;
4103 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4105 msurface_t *surface;
4111 lightmaptriangle_t *triangle;
4112 // generate lightmap triangle structs
4113 mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4114 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4116 surface = model->data_surfaces + surfaceindex;
4117 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4118 for (i = 0;i < surface->num_triangles;i++)
4120 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4121 triangle->triangleindex = surface->num_firsttriangle+i;
4122 triangle->surfaceindex = surfaceindex;
4123 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4124 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4125 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4126 // calculate bounds of triangle
4127 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4128 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4129 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4130 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4131 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4132 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4133 // pick an axial projection based on the triangle normal
4134 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4136 if (fabs(normal[1]) > fabs(normal[axis]))
4138 if (fabs(normal[2]) > fabs(normal[axis]))
4140 triangle->axis = axis;
4145 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4147 if (mod_generatelightmaps_lightmaptriangles)
4148 Mem_Free(mod_generatelightmaps_lightmaptriangles);
4149 mod_generatelightmaps_lightmaptriangles = NULL;
4152 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4154 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4156 msurface_t *surface;
4170 float trianglenormal[3];
4171 float samplecenter[3];
4172 float samplenormal[3];
4178 float lmscalepixels;
4181 float lm_basescalepixels;
4182 int lm_borderpixels;
4186 lightmaptriangle_t *triangle;
4187 unsigned char *lightmappixels;
4188 unsigned char *deluxemappixels;
4189 mod_alloclightmap_state_t lmstate;
4192 // generate lightmap projection information for all triangles
4193 if (model->texturepool == NULL)
4194 model->texturepool = R_AllocTexturePool();
4195 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4196 lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4197 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4198 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4199 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4201 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4203 surface = model->data_surfaces + surfaceindex;
4204 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4205 lmscalepixels = lm_basescalepixels;
4206 for (retry = 0;retry < 30;retry++)
4208 // after a couple failed attempts, degrade quality to make it fit
4210 lmscalepixels *= 0.5f;
4211 for (i = 0;i < surface->num_triangles;i++)
4213 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4214 triangle->lightmapindex = lightmapnumber;
4215 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4216 // pick two planar axes for projection
4217 // lightmap coordinates here are in pixels
4218 // lightmap projections are snapped to pixel grid explicitly, such
4219 // that two neighboring triangles sharing an edge and projection
4220 // axis will have identical sample spacing along their shared edge
4222 for (j = 0;j < 3;j++)
4224 if (j == triangle->axis)
4226 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4227 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4228 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4229 triangle->lmbase[k] = lmmins/lmscalepixels;
4230 triangle->lmscale[k] = lmscalepixels;
4233 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4236 // if all fit in this texture, we're done with this surface
4237 if (i == surface->num_triangles)
4239 // if we haven't maxed out the lightmap size yet, we retry the
4240 // entire surface batch...
4241 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4243 lm_texturesize *= 2;
4246 Mod_AllocLightmap_Free(&lmstate);
4247 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4250 // if we have maxed out the lightmap size, and this triangle does
4251 // not fit in the same texture as the rest of the surface, we have
4252 // to retry the entire surface in a new texture (can only use one)
4253 // with multiple retries, the lightmap quality degrades until it
4254 // fits (or gives up)
4255 if (surfaceindex > 0)
4257 Mod_AllocLightmap_Reset(&lmstate);
4261 Mod_AllocLightmap_Free(&lmstate);
4263 // now put triangles together into lightmap textures, and do not allow
4264 // triangles of a surface to go into different textures (as that would
4265 // require rewriting the surface list)
4266 model->brushq3.deluxemapping_modelspace = true;
4267 model->brushq3.deluxemapping = true;
4268 model->brushq3.num_mergedlightmaps = lightmapnumber;
4269 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4270 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4271 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4272 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4273 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4275 surface = model->data_surfaces + surfaceindex;
4276 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4277 for (i = 0;i < surface->num_triangles;i++)
4279 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4280 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4281 VectorNormalize(trianglenormal);
4282 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4283 axis = triangle->axis;
4284 axis1 = axis == 0 ? 1 : 0;
4285 axis2 = axis == 2 ? 1 : 2;
4286 lmiscale[0] = 1.0f / triangle->lmscale[0];
4287 lmiscale[1] = 1.0f / triangle->lmscale[1];
4288 if (trianglenormal[axis] < 0)
4289 VectorNegate(trianglenormal, trianglenormal);
4290 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4291 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4292 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4293 for (j = 0;j < 3;j++)
4295 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4296 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4297 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4299 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4300 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4301 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4302 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]);
4312 forward[1] = 1.0f / triangle->lmscale[0];
4316 left[2] = 1.0f / triangle->lmscale[1];
4321 origin[1] = triangle->lmbase[0];
4322 origin[2] = triangle->lmbase[1];
4325 forward[0] = 1.0f / triangle->lmscale[0];
4330 left[2] = 1.0f / triangle->lmscale[1];
4334 origin[0] = triangle->lmbase[0];
4336 origin[2] = triangle->lmbase[1];
4339 forward[0] = 1.0f / triangle->lmscale[0];
4343 left[1] = 1.0f / triangle->lmscale[1];
4348 origin[0] = triangle->lmbase[0];
4349 origin[1] = triangle->lmbase[1];
4353 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4355 #define LM_DIST_EPSILON (1.0f / 32.0f)
4356 for (y = 0;y < triangle->lmsize[1];y++)
4358 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4359 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4361 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4362 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4363 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4364 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4365 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4371 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4373 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);
4374 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);
4378 Mem_Free(lightmappixels);
4379 if (deluxemappixels)
4380 Mem_Free(deluxemappixels);
4382 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4384 surface = model->data_surfaces + surfaceindex;
4385 if (!surface->num_triangles)
4387 lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4388 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4389 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4390 surface->lightmapinfo = NULL;
4393 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4394 model->brushq1.lightdata = NULL;
4395 model->brushq1.lightmapupdateflags = NULL;
4396 model->brushq1.firstrender = false;
4397 model->brushq1.num_lightstyles = 0;
4398 model->brushq1.data_lightstyleinfo = NULL;
4399 for (i = 0;i < model->brush.numsubmodels;i++)
4401 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4402 model->brush.submodels[i]->brushq1.firstrender = false;
4403 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4404 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4408 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4411 for (i = 0;i < model->surfmesh.num_vertices;i++)
4412 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4415 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4422 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4424 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4425 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4427 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4428 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4430 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4431 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4437 extern cvar_t mod_q3bsp_nolightmaps;
4438 static void Mod_GenerateLightmaps(dp_model_t *model)
4440 //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4441 dp_model_t *oldloadmodel = loadmodel;
4444 Mod_GenerateLightmaps_InitSampleOffsets(model);
4445 Mod_GenerateLightmaps_DestroyLightmaps(model);
4446 Mod_GenerateLightmaps_UnweldTriangles(model);
4447 Mod_GenerateLightmaps_CreateTriangleInformation(model);
4448 Mod_GenerateLightmaps_CreateLights(model);
4449 if(!mod_q3bsp_nolightmaps.integer)
4450 Mod_GenerateLightmaps_CreateLightmaps(model);
4451 Mod_GenerateLightmaps_UpdateVertexColors(model);
4452 Mod_GenerateLightmaps_UpdateLightGrid(model);
4453 Mod_GenerateLightmaps_DestroyLights(model);
4454 Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4456 loadmodel = oldloadmodel;
4459 static void Mod_GenerateLightmaps_f(void)
4461 if (Cmd_Argc() != 1)
4463 Con_Printf("usage: mod_generatelightmaps\n");
4468 Con_Printf("no worldmodel loaded\n");
4471 Mod_GenerateLightmaps(cl.worldmodel);
4474 void Mod_Mesh_Create(dp_model_t *mod, const char *name)
4476 memset(mod, 0, sizeof(*mod));
4477 strlcpy(mod->name, name, sizeof(mod->name));
4478 mod->mempool = Mem_AllocPool(name, 0, NULL);
4479 mod->texturepool = R_AllocTexturePool();
4480 mod->Draw = R_Q1BSP_Draw;
4481 mod->DrawDepth = R_Q1BSP_DrawDepth;
4482 mod->DrawDebug = R_Q1BSP_DrawDebug;
4483 mod->DrawPrepass = R_Q1BSP_DrawPrepass;
4484 mod->GetLightInfo = R_Q1BSP_GetLightInfo;
4485 mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
4486 mod->DrawLight = R_Q1BSP_DrawLight;
4489 void Mod_Mesh_Destroy(dp_model_t *mod)
4491 Mod_UnloadModel(mod);
4494 // resets the mesh model to have no geometry to render, ready for a new frame -
4495 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4496 void Mod_Mesh_Reset(dp_model_t *mod)
4498 mod->num_surfaces = 0;
4499 mod->surfmesh.num_vertices = 0;
4500 mod->surfmesh.num_triangles = 0;
4501 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4502 mod->DrawSky = NULL; // will be set if a texture needs it
4503 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4506 texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
4510 for (i = 0; i < mod->num_textures; i++)
4511 if (!strcmp(mod->data_textures[i].name, name))
4512 return mod->data_textures + i;
4513 if (mod->max_textures <= mod->num_textures)
4515 texture_t *oldtextures = mod->data_textures;
4516 mod->max_textures = max(mod->max_textures * 2, 1024);
4517 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4518 // update the pointers
4519 for (i = 0; i < mod->num_surfaces; i++)
4520 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4522 t = &mod->data_textures[mod->num_textures++];
4523 Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
4524 switch (defaultdrawflags & DRAWFLAG_MASK)
4526 case DRAWFLAG_ADDITIVE:
4527 t->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED;
4528 t->currentmaterialflags = t->basematerialflags;
4530 case DRAWFLAG_MODULATE:
4531 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4532 t->currentmaterialflags = t->basematerialflags;
4533 t->customblendfunc[0] = GL_DST_COLOR;
4534 t->customblendfunc[1] = GL_ZERO;
4536 case DRAWFLAG_2XMODULATE:
4537 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4538 t->currentmaterialflags = t->basematerialflags;
4539 t->customblendfunc[0] = GL_DST_COLOR;
4540 t->customblendfunc[1] = GL_SRC_COLOR;
4542 case DRAWFLAG_SCREEN:
4543 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4544 t->currentmaterialflags = t->basematerialflags;
4545 t->customblendfunc[0] = GL_ONE_MINUS_DST_COLOR;
4546 t->customblendfunc[1] = GL_ONE;
4554 msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface)
4557 // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
4558 if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex)
4559 return mod->data_surfaces + mod->num_surfaces - 1;
4560 // create new surface
4561 if (mod->max_surfaces == mod->num_surfaces)
4563 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4564 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4565 mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
4567 surf = mod->data_surfaces + mod->num_surfaces;
4568 mod->num_surfaces++;
4569 memset(surf, 0, sizeof(*surf));
4570 surf->texture = tex;
4571 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4572 surf->num_firstvertex = mod->surfmesh.num_vertices;
4573 if (tex->basematerialflags & (MATERIALFLAG_SKY))
4574 mod->DrawSky = R_Q1BSP_DrawSky;
4575 if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4576 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
4580 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)
4582 int hashindex, h, vnum, mask;
4583 surfmesh_t *mesh = &mod->surfmesh;
4584 if (mesh->max_vertices == mesh->num_vertices)
4586 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4587 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4588 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4589 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4590 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4591 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4592 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4593 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4594 // rebuild the hash table
4595 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4596 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4597 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4598 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4599 mask = mod->surfmesh.num_vertexhashsize - 1;
4600 // no need to hash the vertices for the entire model, the latest surface will suffice.
4601 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4603 // this uses prime numbers intentionally for computing the hash
4604 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;
4605 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4606 ; // just iterate until we find the terminator
4607 mesh->data_vertexhash[h] = vnum;
4610 mask = mod->surfmesh.num_vertexhashsize - 1;
4611 // this uses prime numbers intentionally for computing the hash
4612 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4613 // when possible find an identical vertex within the same surface and return it
4614 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4616 if (vnum >= surf->num_firstvertex
4617 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4618 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4619 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4620 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4621 && 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)
4624 // add the new vertex
4625 vnum = mesh->num_vertices++;
4626 if (surf->num_vertices > 0)
4628 if (surf->mins[0] > x) surf->mins[0] = x;
4629 if (surf->mins[1] > y) surf->mins[1] = y;
4630 if (surf->mins[2] > z) surf->mins[2] = z;
4631 if (surf->maxs[0] < x) surf->maxs[0] = x;
4632 if (surf->maxs[1] < y) surf->maxs[1] = y;
4633 if (surf->maxs[2] < z) surf->maxs[2] = z;
4637 VectorSet(surf->mins, x, y, z);
4638 VectorSet(surf->maxs, x, y, z);
4640 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4641 mesh->data_vertexhash[h] = vnum;
4642 mesh->data_vertex3f[vnum * 3 + 0] = x;
4643 mesh->data_vertex3f[vnum * 3 + 1] = y;
4644 mesh->data_vertex3f[vnum * 3 + 2] = z;
4645 mesh->data_normal3f[vnum * 3 + 0] = nx;
4646 mesh->data_normal3f[vnum * 3 + 1] = ny;
4647 mesh->data_normal3f[vnum * 3 + 2] = nz;
4648 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4649 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4650 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4651 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4652 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4653 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4654 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4655 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4659 void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4661 surfmesh_t *mesh = &mod->surfmesh;
4662 if (mesh->max_triangles == mesh->num_triangles)
4664 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4665 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4666 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4668 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4669 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4670 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4671 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4672 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4673 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4674 mesh->num_triangles++;
4675 surf->num_triangles++;
4678 static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
4682 msurface_t *surf, *surf2;
4684 // build the sorted surfaces list properly to reduce material setup
4685 // this is easy because we're just sorting on texture and don't care about the order of textures
4686 mod->nummodelsurfaces = 0;
4687 for (i = 0; i < mod->num_surfaces; i++)
4688 mod->data_surfaces[i].included = false;
4689 for (i = 0; i < mod->num_surfaces; i++)
4691 surf = mod->data_surfaces + i;
4694 tex = surf->texture;
4695 // j = i is intentional
4696 for (j = i; j < mod->num_surfaces; j++)
4698 surf2 = mod->data_surfaces + j;
4699 if (surf2->included)
4701 if (surf2->texture == tex)
4703 surf2->included = true;
4704 mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
4710 void Mod_Mesh_ComputeBounds(dp_model_t *mod)
4713 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4715 if (mod->surfmesh.num_vertices > 0)
4717 // calculate normalmins/normalmaxs
4718 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4719 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4720 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4722 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4723 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4724 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4725 // expand bounds to include this vertex
4726 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4727 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4728 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4729 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4730 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4731 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4733 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4734 // (fast but less accurate than doing it per vertex)
4735 x2a = mod->normalmins[0] * mod->normalmins[0];
4736 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4737 y2a = mod->normalmins[1] * mod->normalmins[1];
4738 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4739 z2a = mod->normalmins[2] * mod->normalmins[2];
4740 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4744 yawradius = sqrt(x2 + y2);
4745 rotatedradius = sqrt(x2 + y2 + z2);
4746 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4747 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4748 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4749 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4750 mod->radius = rotatedradius;
4751 mod->radius2 = x2 + y2 + z2;
4755 VectorClear(mod->normalmins);
4756 VectorClear(mod->normalmaxs);
4757 VectorClear(mod->yawmins);
4758 VectorClear(mod->yawmaxs);
4759 VectorClear(mod->rotatedmins);
4760 VectorClear(mod->rotatedmaxs);
4766 void Mod_Mesh_Finalize(dp_model_t *mod)
4768 Mod_Mesh_ComputeBounds(mod);
4769 Mod_Mesh_MakeSortedSurfaces(mod);
4770 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);