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 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 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;
1294 void Mod_CreateCollisionMesh(dp_model_t *mod)
1296 int k, numcollisionmeshtriangles;
1297 qboolean usesinglecollisionmesh = false;
1298 const msurface_t *surface = NULL;
1300 mempool_t *mempool = mod->mempool;
1301 if (!mempool && mod->brush.parentmodel)
1302 mempool = mod->brush.parentmodel->mempool;
1303 // make a single combined collision mesh for physics engine use
1304 // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
1305 numcollisionmeshtriangles = 0;
1306 for (k = 0;k < mod->nummodelsurfaces;k++)
1308 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1309 if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
1311 usesinglecollisionmesh = true;
1312 numcollisionmeshtriangles = surface->num_triangles;
1315 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1317 numcollisionmeshtriangles += surface->num_triangles;
1319 mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, true);
1320 if (usesinglecollisionmesh)
1321 Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1324 for (k = 0;k < mod->nummodelsurfaces;k++)
1326 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1327 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1329 Mod_ShadowMesh_AddMesh(mempool, mod->brush.collisionmesh, NULL, NULL, NULL, mod->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1332 mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false);
1336 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)
1341 if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1342 v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1345 Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1346 Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1347 texcoord2f[0] = tc[0];
1348 texcoord2f[1] = tc[1];
1351 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)
1353 float vup[3], vdown[3], vleft[3], vright[3];
1354 float tcup[3], tcdown[3], tcleft[3], tcright[3];
1355 float sv[3], tv[3], nl[3];
1356 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1357 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1358 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1359 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1360 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1361 Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1362 Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1363 VectorAdd(svector3f, sv, svector3f);
1364 VectorAdd(tvector3f, tv, tvector3f);
1365 VectorAdd(normal3f, nl, normal3f);
1366 Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1367 VectorAdd(svector3f, sv, svector3f);
1368 VectorAdd(tvector3f, tv, tvector3f);
1369 VectorAdd(normal3f, nl, normal3f);
1370 Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1371 VectorAdd(svector3f, sv, svector3f);
1372 VectorAdd(tvector3f, tv, tvector3f);
1373 VectorAdd(normal3f, nl, normal3f);
1376 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)
1378 int x, y, ix, iy, *e;
1380 for (y = 0;y < height;y++)
1382 for (x = 0;x < width;x++)
1384 e[0] = (y + 1) * (width + 1) + (x + 0);
1385 e[1] = (y + 0) * (width + 1) + (x + 0);
1386 e[2] = (y + 1) * (width + 1) + (x + 1);
1387 e[3] = (y + 0) * (width + 1) + (x + 0);
1388 e[4] = (y + 0) * (width + 1) + (x + 1);
1389 e[5] = (y + 1) * (width + 1) + (x + 1);
1393 for (y = 0, iy = y1;y < height + 1;y++, iy++)
1394 for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1395 Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1400 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
1404 float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1405 float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1406 float viewvector[3];
1407 unsigned int firstvertex;
1410 if (chunkwidth < 2 || chunkheight < 2)
1412 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]);
1413 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]);
1414 viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1415 viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1416 viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1417 if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1419 // too close for this stepsize, emit as 4 chunks instead
1421 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1422 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1423 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1424 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1427 // emit the geometry at stepsize into our vertex buffer / index buffer
1428 // we add two columns and two rows for skirt
1429 outwidth = chunkwidth+2;
1430 outheight = chunkheight+2;
1431 outwidth2 = outwidth-1;
1432 outheight2 = outheight-1;
1433 outwidth3 = outwidth+1;
1434 outheight3 = outheight+1;
1435 firstvertex = numvertices;
1436 e = model->terrain.element3i + numtriangles;
1437 numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1438 v = model->terrain.vertex3f + numvertices;
1439 numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1440 // emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1441 for (ty = 0;ty < outheight;ty++)
1443 for (tx = 0;tx < outwidth;tx++)
1445 *e++ = firstvertex + (ty )*outwidth3+(tx );
1446 *e++ = firstvertex + (ty )*outwidth3+(tx+1);
1447 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1448 *e++ = firstvertex + (ty )*outwidth3+(tx );
1449 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1450 *e++ = firstvertex + (ty+1)*outwidth3+(tx );
1453 // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1454 for (ty = 0;ty <= outheight;ty++)
1456 skirtrow = ty == 0 || ty == outheight;
1457 ry = y+bound(1, ty, outheight)*stepsize;
1458 for (tx = 0;tx <= outwidth;tx++)
1460 skirt = skirtrow || tx == 0 || tx == outwidth;
1461 rx = x+bound(1, tx, outwidth)*stepsize;
1464 v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1468 // TODO: emit skirt vertices
1471 void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
1473 for (y = 0;y < model->terrain.size[1];y += model->terrain.
1474 Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1475 Mod_Terrain_BuildChunk(model,
1479 static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
1482 if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1484 offset = bound(0, s[4] - '0', 9);
1485 offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
1490 if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN;
1491 if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE;
1492 if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE;
1493 if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH;
1494 if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1495 if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE;
1496 if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE;
1497 Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1498 return offset | Q3WAVEFUNC_NONE;
1501 void Mod_FreeQ3Shaders(void)
1503 Mem_FreePool(&q3shaders_mem);
1506 static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
1508 unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1509 q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
1510 q3shader_hash_entry_t* lastEntry = NULL;
1513 if (strcasecmp (entry->shader.name, shader->name) == 0)
1516 if(shader->dpshaderkill)
1518 // killed shader is a redeclarion? we can safely ignore it
1521 else if(entry->shader.dpshaderkill)
1523 // replace the old shader!
1524 // this will skip the entry allocating part
1525 // below and just replace the shader
1530 unsigned char *start, *end, *start2;
1531 start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1532 end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1533 start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1534 if(memcmp(start, start2, end - start))
1535 Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1537 Con_DPrintf("Shader '%s' already defined\n", shader->name);
1542 entry = entry->chain;
1544 while (entry != NULL);
1547 if (lastEntry->shader.name[0] != 0)
1550 q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*)
1551 Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries);
1553 while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1554 lastEntry->chain = newEntry;
1555 newEntry->chain = NULL;
1556 lastEntry = newEntry;
1558 /* else: head of chain, in hash entry array */
1561 memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
1564 extern cvar_t mod_noshader_default_offsetmapping;
1565 extern cvar_t mod_q3shader_default_offsetmapping;
1566 extern cvar_t mod_q3shader_default_offsetmapping_scale;
1567 extern cvar_t mod_q3shader_default_offsetmapping_bias;
1568 extern cvar_t mod_q3shader_default_polygonoffset;
1569 extern cvar_t mod_q3shader_default_polygonfactor;
1570 extern cvar_t mod_q3shader_force_addalpha;
1571 extern cvar_t mod_q3shader_force_terrain_alphaflag;
1572 void Mod_LoadQ3Shaders(void)
1579 q3shaderinfo_t shader;
1580 q3shaderinfo_layer_t *layer;
1582 char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1583 char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1584 unsigned long custsurfaceflags[256];
1585 int numcustsurfaceflags;
1586 qboolean dpshaderkill;
1588 Mod_FreeQ3Shaders();
1590 q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1591 q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem,
1592 sizeof (q3shader_data_t));
1593 Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries,
1594 q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1595 Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs,
1596 q3shaders_mem, sizeof (char**), 256);
1598 // parse custinfoparms.txt
1599 numcustsurfaceflags = 0;
1600 if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1602 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1603 Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1606 while (COM_ParseToken_QuakeC(&text, false))
1607 if (!strcasecmp(com_token, "}"))
1609 // custom surfaceflags section
1610 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1611 Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1614 while(COM_ParseToken_QuakeC(&text, false))
1616 if (!strcasecmp(com_token, "}"))
1618 // register surfaceflag
1619 if (numcustsurfaceflags >= 256)
1621 Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1625 j = (int)strlen(com_token)+1;
1626 custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1627 strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1629 if (COM_ParseToken_QuakeC(&text, false))
1630 custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1632 custsurfaceflags[numcustsurfaceflags] = 0;
1633 numcustsurfaceflags++;
1641 search = FS_Search("scripts/*.shader", true, false);
1644 for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1646 text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1649 while (COM_ParseToken_QuakeC(&text, false))
1651 memset (&shader, 0, sizeof(shader));
1653 shader.surfaceparms = 0;
1654 shader.surfaceflags = 0;
1655 shader.textureflags = 0;
1656 shader.numlayers = 0;
1657 shader.lighting = false;
1658 shader.vertexalpha = false;
1659 shader.textureblendalpha = false;
1660 shader.skyboxname[0] = 0;
1661 shader.deforms[0].deform = Q3DEFORM_NONE;
1662 shader.dpnortlight = false;
1663 shader.dpshadow = false;
1664 shader.dpnoshadow = false;
1665 shader.dpmeshcollisions = false;
1666 shader.dpshaderkill = false;
1667 shader.dpreflectcube[0] = 0;
1668 shader.reflectmin = 0;
1669 shader.reflectmax = 1;
1670 shader.refractfactor = 1;
1671 Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1672 shader.reflectfactor = 1;
1673 Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1674 shader.r_water_wateralpha = 1;
1675 shader.r_water_waterscroll[0] = 0;
1676 shader.r_water_waterscroll[1] = 0;
1677 shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
1678 shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
1679 shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
1680 shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
1681 shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
1682 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
1683 shader.specularscalemod = 1;
1684 shader.specularpowermod = 1;
1685 shader.rtlightambient = 0;
1686 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1687 // JUST GREP FOR "specularscalemod = 1".
1689 strlcpy(shader.name, com_token, sizeof(shader.name));
1690 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1692 Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1695 while (COM_ParseToken_QuakeC(&text, false))
1697 if (!strcasecmp(com_token, "}"))
1699 if (!strcasecmp(com_token, "{"))
1701 static q3shaderinfo_layer_t dummy;
1702 if (shader.numlayers < Q3SHADER_MAXLAYERS)
1704 layer = shader.layers + shader.numlayers++;
1708 // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1709 memset(&dummy, 0, sizeof(dummy));
1712 layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1713 layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1714 layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1715 layer->blendfunc[0] = GL_ONE;
1716 layer->blendfunc[1] = GL_ZERO;
1717 while (COM_ParseToken_QuakeC(&text, false))
1719 if (!strcasecmp(com_token, "}"))
1721 if (!strcasecmp(com_token, "\n"))
1724 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1726 if (j < TEXTURE_MAXFRAMES + 4)
1728 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1729 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1730 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1732 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1733 numparameters = j + 1;
1735 if (!COM_ParseToken_QuakeC(&text, true))
1738 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1739 // parameter[j][0] = 0;
1740 if (developer_insane.integer)
1742 Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1743 for (j = 0;j < numparameters;j++)
1744 Con_DPrintf(" %s", parameter[j]);
1747 if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1749 if (numparameters == 2)
1751 if (!strcasecmp(parameter[1], "add"))
1753 layer->blendfunc[0] = GL_ONE;
1754 layer->blendfunc[1] = GL_ONE;
1756 else if (!strcasecmp(parameter[1], "addalpha"))
1758 layer->blendfunc[0] = GL_SRC_ALPHA;
1759 layer->blendfunc[1] = GL_ONE;
1761 else if (!strcasecmp(parameter[1], "filter"))
1763 layer->blendfunc[0] = GL_DST_COLOR;
1764 layer->blendfunc[1] = GL_ZERO;
1766 else if (!strcasecmp(parameter[1], "blend"))
1768 layer->blendfunc[0] = GL_SRC_ALPHA;
1769 layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1772 else if (numparameters == 3)
1775 for (k = 0;k < 2;k++)
1777 if (!strcasecmp(parameter[k+1], "GL_ONE"))
1778 layer->blendfunc[k] = GL_ONE;
1779 else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1780 layer->blendfunc[k] = GL_ZERO;
1781 else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1782 layer->blendfunc[k] = GL_SRC_COLOR;
1783 else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1784 layer->blendfunc[k] = GL_SRC_ALPHA;
1785 else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1786 layer->blendfunc[k] = GL_DST_COLOR;
1787 else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1788 layer->blendfunc[k] = GL_DST_ALPHA;
1789 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1790 layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1791 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1792 layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1793 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1794 layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1795 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1796 layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1798 layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1802 if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1803 layer->alphatest = true;
1804 if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1806 if (!strcasecmp(parameter[0], "clampmap"))
1807 layer->clampmap = true;
1808 layer->numframes = 1;
1809 layer->framerate = 1;
1810 layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1811 &q3shader_data->char_ptrs);
1812 layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1813 if (!strcasecmp(parameter[1], "$lightmap"))
1814 shader.lighting = true;
1816 else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1819 layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1820 layer->framerate = atof(parameter[1]);
1821 layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1822 for (i = 0;i < layer->numframes;i++)
1823 layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1825 else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1828 for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1829 layer->rgbgen.parms[i] = atof(parameter[i+2]);
1830 if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1831 else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1832 else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1833 else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1834 else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1835 else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1836 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1837 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1838 else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1839 else if (!strcasecmp(parameter[1], "wave"))
1841 layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1842 layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1843 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1844 layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1846 else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1848 else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1851 for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1852 layer->alphagen.parms[i] = atof(parameter[i+2]);
1853 if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1854 else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1855 else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1856 else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1857 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1858 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1859 else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1860 else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1861 else if (!strcasecmp(parameter[1], "wave"))
1863 layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1864 layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1865 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1866 layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1868 else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1870 else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1873 // observed values: tcgen environment
1874 // no other values have been observed in real shaders
1875 for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1876 layer->tcgen.parms[i] = atof(parameter[i+2]);
1877 if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1878 else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1879 else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1880 else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1881 else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1882 else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1884 else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1891 // tcmod stretch sin # # # #
1892 // tcmod stretch triangle # # # #
1893 // tcmod transform # # # # # #
1894 // tcmod turb # # # #
1895 // tcmod turb sin # # # # (this is bogus)
1896 // no other values have been observed in real shaders
1897 for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1898 if (!layer->tcmods[tcmodindex].tcmod)
1900 if (tcmodindex < Q3MAXTCMODS)
1902 for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1903 layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1904 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1905 else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1906 else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1907 else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1908 else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1909 else if (!strcasecmp(parameter[1], "stretch"))
1911 layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1912 layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1913 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1914 layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1916 else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1917 else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1918 else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1921 Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1923 // break out a level if it was a closing brace (not using the character here to not confuse vim)
1924 if (!strcasecmp(com_token, "}"))
1927 if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
1928 shader.lighting = true;
1929 if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
1931 if (layer == shader.layers + 0)
1933 // vertex controlled transparency
1934 shader.vertexalpha = true;
1938 // multilayer terrain shader or similar
1939 shader.textureblendalpha = true;
1940 if (mod_q3shader_force_terrain_alphaflag.integer)
1941 shader.layers[0].dptexflags |= TEXF_ALPHA;
1945 if(mod_q3shader_force_addalpha.integer)
1947 // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
1948 // this cvar brings back this behaviour
1949 if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
1950 layer->blendfunc[0] = GL_SRC_ALPHA;
1953 layer->dptexflags = 0;
1954 if (layer->alphatest)
1955 layer->dptexflags |= TEXF_ALPHA;
1956 switch(layer->blendfunc[0])
1959 case GL_ONE_MINUS_SRC_ALPHA:
1960 layer->dptexflags |= TEXF_ALPHA;
1963 switch(layer->blendfunc[1])
1966 case GL_ONE_MINUS_SRC_ALPHA:
1967 layer->dptexflags |= TEXF_ALPHA;
1970 if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
1971 layer->dptexflags |= TEXF_MIPMAP;
1972 if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
1973 layer->dptexflags |= TEXF_PICMIP | TEXF_COMPRESS;
1974 if (layer->clampmap)
1975 layer->dptexflags |= TEXF_CLAMP;
1979 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1981 if (j < TEXTURE_MAXFRAMES + 4)
1983 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1984 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1985 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1987 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1988 numparameters = j + 1;
1990 if (!COM_ParseToken_QuakeC(&text, true))
1993 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1994 // parameter[j][0] = 0;
1995 if (fileindex == 0 && !strcasecmp(com_token, "}"))
1997 if (developer_insane.integer)
1999 Con_DPrintf("%s: ", shader.name);
2000 for (j = 0;j < numparameters;j++)
2001 Con_DPrintf(" %s", parameter[j]);
2004 if (numparameters < 1)
2006 if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
2008 if (!strcasecmp(parameter[1], "alphashadow"))
2009 shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
2010 else if (!strcasecmp(parameter[1], "areaportal"))
2011 shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
2012 else if (!strcasecmp(parameter[1], "botclip"))
2013 shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP;
2014 else if (!strcasecmp(parameter[1], "clusterportal"))
2015 shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
2016 else if (!strcasecmp(parameter[1], "detail"))
2017 shader.surfaceparms |= Q3SURFACEPARM_DETAIL;
2018 else if (!strcasecmp(parameter[1], "donotenter"))
2019 shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER;
2020 else if (!strcasecmp(parameter[1], "dust"))
2021 shader.surfaceparms |= Q3SURFACEPARM_DUST;
2022 else if (!strcasecmp(parameter[1], "hint"))
2023 shader.surfaceparms |= Q3SURFACEPARM_HINT;
2024 else if (!strcasecmp(parameter[1], "fog"))
2025 shader.surfaceparms |= Q3SURFACEPARM_FOG;
2026 else if (!strcasecmp(parameter[1], "lava"))
2027 shader.surfaceparms |= Q3SURFACEPARM_LAVA;
2028 else if (!strcasecmp(parameter[1], "lightfilter"))
2029 shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
2030 else if (!strcasecmp(parameter[1], "lightgrid"))
2031 shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
2032 else if (!strcasecmp(parameter[1], "metalsteps"))
2033 shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS;
2034 else if (!strcasecmp(parameter[1], "nodamage"))
2035 shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE;
2036 else if (!strcasecmp(parameter[1], "nodlight"))
2037 shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT;
2038 else if (!strcasecmp(parameter[1], "nodraw"))
2039 shader.surfaceparms |= Q3SURFACEPARM_NODRAW;
2040 else if (!strcasecmp(parameter[1], "nodrop"))
2041 shader.surfaceparms |= Q3SURFACEPARM_NODROP;
2042 else if (!strcasecmp(parameter[1], "noimpact"))
2043 shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT;
2044 else if (!strcasecmp(parameter[1], "nolightmap"))
2045 shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
2046 else if (!strcasecmp(parameter[1], "nomarks"))
2047 shader.surfaceparms |= Q3SURFACEPARM_NOMARKS;
2048 else if (!strcasecmp(parameter[1], "nomipmaps"))
2049 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2050 else if (!strcasecmp(parameter[1], "nonsolid"))
2051 shader.surfaceparms |= Q3SURFACEPARM_NONSOLID;
2052 else if (!strcasecmp(parameter[1], "origin"))
2053 shader.surfaceparms |= Q3SURFACEPARM_ORIGIN;
2054 else if (!strcasecmp(parameter[1], "playerclip"))
2055 shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
2056 else if (!strcasecmp(parameter[1], "sky"))
2057 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2058 else if (!strcasecmp(parameter[1], "slick"))
2059 shader.surfaceparms |= Q3SURFACEPARM_SLICK;
2060 else if (!strcasecmp(parameter[1], "slime"))
2061 shader.surfaceparms |= Q3SURFACEPARM_SLIME;
2062 else if (!strcasecmp(parameter[1], "structural"))
2063 shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
2064 else if (!strcasecmp(parameter[1], "trans"))
2065 shader.surfaceparms |= Q3SURFACEPARM_TRANS;
2066 else if (!strcasecmp(parameter[1], "water"))
2067 shader.surfaceparms |= Q3SURFACEPARM_WATER;
2068 else if (!strcasecmp(parameter[1], "pointlight"))
2069 shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
2070 else if (!strcasecmp(parameter[1], "antiportal"))
2071 shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
2072 else if (!strcasecmp(parameter[1], "skip"))
2073 ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
2076 // try custom surfaceparms
2077 for (j = 0; j < numcustsurfaceflags; j++)
2079 if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
2081 shader.surfaceflags |= custsurfaceflags[j];
2086 if (j == numcustsurfaceflags)
2087 Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
2090 else if (!strcasecmp(parameter[0], "dpshadow"))
2091 shader.dpshadow = true;
2092 else if (!strcasecmp(parameter[0], "dpnoshadow"))
2093 shader.dpnoshadow = true;
2094 else if (!strcasecmp(parameter[0], "dpnortlight"))
2095 shader.dpnortlight = true;
2096 else if (!strcasecmp(parameter[0], "dpreflectcube"))
2097 strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
2098 else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
2099 shader.dpmeshcollisions = true;
2100 // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
2101 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
2103 if (Cvar_VariableValue(parameter[1]) == 0.0f)
2104 shader.dpshaderkill = dpshaderkill;
2106 // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
2107 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
2109 const char *op = NULL;
2110 if (numparameters >= 3)
2114 if (Cvar_VariableValue(parameter[1]) != 0.0f)
2115 shader.dpshaderkill = dpshaderkill;
2117 else if (numparameters >= 4 && !strcmp(op, "=="))
2119 if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
2120 shader.dpshaderkill = dpshaderkill;
2122 else if (numparameters >= 4 && !strcmp(op, "!="))
2124 if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
2125 shader.dpshaderkill = dpshaderkill;
2127 else if (numparameters >= 4 && !strcmp(op, ">"))
2129 if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
2130 shader.dpshaderkill = dpshaderkill;
2132 else if (numparameters >= 4 && !strcmp(op, "<"))
2134 if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
2135 shader.dpshaderkill = dpshaderkill;
2137 else if (numparameters >= 4 && !strcmp(op, ">="))
2139 if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
2140 shader.dpshaderkill = dpshaderkill;
2142 else if (numparameters >= 4 && !strcmp(op, "<="))
2144 if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
2145 shader.dpshaderkill = dpshaderkill;
2149 Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2152 else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2154 // some q3 skies don't have the sky parm set
2155 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2156 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2158 else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2160 // some q3 skies don't have the sky parm set
2161 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2162 if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2163 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2165 else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2167 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2168 shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED;
2170 else if (!strcasecmp(parameter[0], "nomipmaps"))
2171 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2172 else if (!strcasecmp(parameter[0], "nopicmip"))
2173 shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
2174 else if (!strcasecmp(parameter[0], "polygonoffset"))
2175 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2176 else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2178 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2179 if(numparameters >= 2)
2181 shader.biaspolygonfactor = atof(parameter[1]);
2182 if(numparameters >= 3)
2183 shader.biaspolygonoffset = atof(parameter[2]);
2185 shader.biaspolygonoffset = 0;
2188 else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2190 shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
2191 if (!strcasecmp(parameter[1], "sky"))
2192 shader.transparentsort = TRANSPARENTSORT_SKY;
2193 else if (!strcasecmp(parameter[1], "distance"))
2194 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
2195 else if (!strcasecmp(parameter[1], "hud"))
2196 shader.transparentsort = TRANSPARENTSORT_HUD;
2198 Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2200 else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2202 shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
2203 shader.refractfactor = atof(parameter[1]);
2204 Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2206 else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2208 shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
2209 shader.reflectfactor = atof(parameter[1]);
2210 Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2212 else if (!strcasecmp(parameter[0], "dpcamera"))
2214 shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
2216 else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2218 shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
2219 shader.reflectmin = atof(parameter[1]);
2220 shader.reflectmax = atof(parameter[2]);
2221 shader.refractfactor = atof(parameter[3]);
2222 shader.reflectfactor = atof(parameter[4]);
2223 Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2224 Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2225 shader.r_water_wateralpha = atof(parameter[11]);
2227 else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2229 shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2230 shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2232 else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2234 shader.specularscalemod = atof(parameter[1]);
2236 else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2238 shader.specularpowermod = atof(parameter[1]);
2240 else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2242 shader.rtlightambient = atof(parameter[1]);
2244 else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2246 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2247 shader.offsetmapping = OFFSETMAPPING_OFF;
2248 else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2249 shader.offsetmapping = OFFSETMAPPING_DEFAULT;
2250 else if (!strcasecmp(parameter[1], "linear"))
2251 shader.offsetmapping = OFFSETMAPPING_LINEAR;
2252 else if (!strcasecmp(parameter[1], "relief"))
2253 shader.offsetmapping = OFFSETMAPPING_RELIEF;
2254 if (numparameters >= 3)
2255 shader.offsetscale = atof(parameter[2]);
2256 if (numparameters >= 5)
2258 if(!strcasecmp(parameter[3], "bias"))
2259 shader.offsetbias = atof(parameter[4]);
2260 else if(!strcasecmp(parameter[3], "match"))
2261 shader.offsetbias = 1.0f - atof(parameter[4]);
2262 else if(!strcasecmp(parameter[3], "match8"))
2263 shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2264 else if(!strcasecmp(parameter[3], "match16"))
2265 shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2268 else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2271 for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2272 if (!shader.deforms[deformindex].deform)
2274 if (deformindex < Q3MAXDEFORMS)
2276 for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2277 shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2278 if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2279 else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2280 else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2281 else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2282 else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2283 else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2284 else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2285 else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2286 else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2287 else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2288 else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2289 else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2290 else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2291 else if (!strcasecmp(parameter[1], "wave" ))
2293 shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2294 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2295 for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2296 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2298 else if (!strcasecmp(parameter[1], "move" ))
2300 shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2301 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2302 for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2303 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2308 // hide this shader if a cvar said it should be killed
2309 if (shader.dpshaderkill)
2310 shader.numlayers = 0;
2311 // fix up multiple reflection types
2312 if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
2313 shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
2315 Q3Shader_AddToHash (&shader);
2319 FS_FreeSearch(search);
2320 // free custinfoparm values
2321 for (j = 0; j < numcustsurfaceflags; j++)
2322 Mem_Free(custsurfaceparmnames[j]);
2325 q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
2327 unsigned short hash;
2328 q3shader_hash_entry_t* entry;
2330 Mod_LoadQ3Shaders();
2331 hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2332 entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2333 while (entry != NULL)
2335 if (strcasecmp (entry->shader.name, name) == 0)
2336 return &entry->shader;
2337 entry = entry->chain;
2342 texture_shaderpass_t *Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe)
2344 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2345 shaderpass->framerate = 0.0f;
2346 shaderpass->numframes = 1;
2347 shaderpass->blendfunc[0] = GL_ONE;
2348 shaderpass->blendfunc[1] = GL_ZERO;
2349 shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
2350 shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
2351 shaderpass->alphatest = false;
2352 shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
2353 shaderpass->skinframes[0] = skinframe;
2357 texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
2360 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2361 shaderpass->alphatest = layer->alphatest != 0;
2362 shaderpass->framerate = layer->framerate;
2363 shaderpass->numframes = layer->numframes;
2364 shaderpass->blendfunc[0] = layer->blendfunc[0];
2365 shaderpass->blendfunc[1] = layer->blendfunc[1];
2366 shaderpass->rgbgen = layer->rgbgen;
2367 shaderpass->alphagen = layer->alphagen;
2368 shaderpass->tcgen = layer->tcgen;
2369 for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
2370 shaderpass->tcmods[j] = layer->tcmods[j];
2371 for (j = 0; j < layer->numframes; j++)
2372 shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true);
2376 qboolean Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags, int defaultmaterialflags)
2378 int texflagsmask, texflagsor;
2379 qboolean success = true;
2380 q3shaderinfo_t *shader;
2383 strlcpy(texture->name, name, sizeof(texture->name));
2384 texture->basealpha = 1.0f;
2385 shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2387 // allow disabling of picmip or compression by defaulttexflags
2389 if(!(defaulttexflags & TEXF_PICMIP))
2390 texflagsmask &= ~TEXF_PICMIP;
2391 if(!(defaulttexflags & TEXF_COMPRESS))
2392 texflagsmask &= ~TEXF_COMPRESS;
2394 if(defaulttexflags & TEXF_ISWORLD)
2395 texflagsor |= TEXF_ISWORLD;
2396 if(defaulttexflags & TEXF_ISSPRITE)
2397 texflagsor |= TEXF_ISSPRITE;
2398 // unless later loaded from the shader
2399 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2400 texture->offsetscale = 1;
2401 texture->offsetbias = 0;
2402 texture->specularscalemod = 1;
2403 texture->specularpowermod = 1;
2404 texture->rtlightambient = 0;
2405 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2406 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2407 // JUST GREP FOR "specularscalemod = 1".
2411 if (developer_loading.integer)
2412 Con_Printf("%s: loaded shader for %s\n", modelname, name);
2414 if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2416 texture->basematerialflags = MATERIALFLAG_SKY;
2417 if (shader->skyboxname[0] && loadmodel)
2419 // quake3 seems to append a _ to the skybox name, so this must do so as well
2420 dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2423 else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2424 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2426 texture->basematerialflags = MATERIALFLAG_WALL;
2428 if (shader->layers[0].alphatest)
2429 texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
2430 if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2431 texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2432 if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET)
2434 texture->biaspolygonoffset += shader->biaspolygonoffset;
2435 texture->biaspolygonfactor += shader->biaspolygonfactor;
2437 if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION)
2438 texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2439 if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION)
2440 texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2441 if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
2442 texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2443 if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2444 texture->basematerialflags |= MATERIALFLAG_CAMERA;
2445 texture->customblendfunc[0] = GL_ONE;
2446 texture->customblendfunc[1] = GL_ZERO;
2447 texture->transparentsort = shader->transparentsort;
2448 if (shader->numlayers > 0)
2450 texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2451 texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2453 Q3 shader blendfuncs actually used in the game (* = supported by DP)
2454 * additive GL_ONE GL_ONE
2455 additive weird GL_ONE GL_SRC_ALPHA
2456 additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
2457 * alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2458 alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2459 brighten GL_DST_COLOR GL_ONE
2460 brighten GL_ONE GL_SRC_COLOR
2461 brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2462 brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
2463 * modulate GL_DST_COLOR GL_ZERO
2464 * modulate GL_ZERO GL_SRC_COLOR
2465 modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
2466 modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2467 modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2468 * modulate x2 GL_DST_COLOR GL_SRC_COLOR
2469 * no blend GL_ONE GL_ZERO
2470 nothing GL_ZERO GL_ONE
2472 // if not opaque, figure out what blendfunc to use
2473 if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2475 if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2476 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2477 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2478 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2479 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2480 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2482 texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2485 if (!shader->lighting)
2486 texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2488 // here be dragons: convert quake3 shaders to material
2489 if (shader->numlayers > 0)
2492 int terrainbackgroundlayer = -1;
2493 int lightmaplayer = -1;
2494 int alphagenspecularlayer = -1;
2495 int rgbgenvertexlayer = -1;
2496 int rgbgendiffuselayer = -1;
2497 int materiallayer = -1;
2498 int endofprelayers = 0;
2499 int firstpostlayer = 0;
2500 int shaderpassindex = 0;
2501 for (i = 0; i < shader->numlayers; i++)
2503 if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
2505 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2506 rgbgenvertexlayer = i;
2507 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
2508 rgbgendiffuselayer = i;
2509 if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
2510 alphagenspecularlayer = i;
2512 if (shader->numlayers >= 2
2513 && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2514 && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
2515 && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2516 || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
2518 // terrain blend or certain other effects involving alphatest over a regular layer
2519 terrainbackgroundlayer = 0;
2521 // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
2522 firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
2524 else if (lightmaplayer == 0)
2526 // ordinary texture but with $lightmap before diffuse
2528 firstpostlayer = lightmaplayer + 2;
2530 else if (lightmaplayer >= 1)
2532 // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
2533 endofprelayers = lightmaplayer - 1;
2534 materiallayer = lightmaplayer - 1;
2535 firstpostlayer = lightmaplayer + 1;
2537 else if (rgbgenvertexlayer >= 0)
2539 // map models with baked lighting
2540 materiallayer = rgbgenvertexlayer;
2541 endofprelayers = rgbgenvertexlayer;
2542 firstpostlayer = rgbgenvertexlayer + 1;
2543 // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
2544 if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
2545 texture->basematerialflags |= MATERIALFLAG_VERTEXCOLOR;
2547 else if (rgbgendiffuselayer >= 0)
2549 // entity models with dynamic lighting
2550 materiallayer = rgbgendiffuselayer;
2551 endofprelayers = rgbgendiffuselayer;
2552 firstpostlayer = rgbgendiffuselayer + 1;
2553 // 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)...
2554 if (alphagenspecularlayer >= 0)
2555 firstpostlayer = alphagenspecularlayer + 1;
2559 // special effects shaders - treat first as primary layer and do everything else as post
2564 // convert the main material layer
2565 // 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
2566 if (materiallayer >= 0)
2567 texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2568 // convert the terrain background blend layer (if any)
2569 if (terrainbackgroundlayer >= 0)
2570 texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2571 // convert the prepass layers (if any)
2572 texture->startpreshaderpass = shaderpassindex;
2573 for (i = 0; i < endofprelayers; i++)
2574 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2575 texture->endpreshaderpass = shaderpassindex;
2576 texture->startpostshaderpass = shaderpassindex;
2577 // convert the postpass layers (if any)
2578 for (i = firstpostlayer; i < shader->numlayers; i++)
2579 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2580 texture->startpostshaderpass = shaderpassindex;
2583 if (shader->dpshadow)
2584 texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2585 if (shader->dpnoshadow)
2586 texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2587 if (shader->dpnortlight)
2588 texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2589 if (shader->vertexalpha)
2590 texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2591 memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2592 texture->reflectmin = shader->reflectmin;
2593 texture->reflectmax = shader->reflectmax;
2594 texture->refractfactor = shader->refractfactor;
2595 Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2596 texture->reflectfactor = shader->reflectfactor;
2597 Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2598 texture->r_water_wateralpha = shader->r_water_wateralpha;
2599 Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2600 texture->offsetmapping = shader->offsetmapping;
2601 texture->offsetscale = shader->offsetscale;
2602 texture->offsetbias = shader->offsetbias;
2603 texture->specularscalemod = shader->specularscalemod;
2604 texture->specularpowermod = shader->specularpowermod;
2605 texture->rtlightambient = shader->rtlightambient;
2606 if (shader->dpreflectcube[0])
2607 texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2609 // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2610 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2611 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ;
2612 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ;
2613 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ;
2614 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ;
2615 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ;
2616 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ;
2617 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ;
2619 // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ;
2620 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ;
2621 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2622 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ;
2623 if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ;
2624 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ;
2625 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ;
2626 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ;
2627 // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ;
2628 // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ;
2629 // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ;
2630 // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ;
2631 if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ;
2632 // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ;
2633 // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ;
2634 // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ;
2635 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ;
2636 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ;
2637 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ;
2638 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ;
2639 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ;
2640 // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ;
2641 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ;
2642 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ;
2643 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ;
2644 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ;
2645 // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ;
2646 // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ;
2647 // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ;
2648 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP;
2649 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ;
2650 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ;
2652 texture->surfaceflags = shader->surfaceflags;
2653 if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ;
2654 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ;
2655 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2656 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ;
2657 // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ;
2658 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ;
2659 // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ;
2660 if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ;
2661 if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ;
2662 if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ;
2663 if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ;
2664 if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ;
2665 // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ;
2666 if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ;
2667 if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ;
2668 if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ;
2669 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ;
2670 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ;
2671 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ;
2672 // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ;
2673 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ;
2674 if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ;
2675 // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ;
2676 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ;
2677 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ;
2678 // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ;
2679 if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ;
2680 if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ;
2681 if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ;
2682 // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ;
2683 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ;
2684 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ;
2686 if (shader->dpmeshcollisions)
2687 texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2688 if (shader->dpshaderkill && developer_extra.integer)
2689 Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", modelname, name);
2691 else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2693 if (developer_extra.integer)
2694 Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name);
2695 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2697 else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2699 if (developer_extra.integer)
2700 Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", modelname, name);
2701 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2702 texture->supercontents = SUPERCONTENTS_SOLID;
2706 if (developer_extra.integer)
2707 Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name);
2708 if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2710 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2711 texture->supercontents = SUPERCONTENTS_SOLID;
2713 else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2715 texture->basematerialflags = MATERIALFLAG_SKY;
2716 texture->supercontents = SUPERCONTENTS_SKY;
2720 texture->basematerialflags = defaultmaterialflags;
2721 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2723 if(cls.state == ca_dedicated)
2725 texture->materialshaderpass = NULL;
2730 skinframe_t *skinframe = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, fallback);
2733 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2734 if (texture->materialshaderpass->skinframes[0]->hasalpha)
2735 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2736 if (texture->q2contents)
2737 texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents);
2741 if (!success && warnmissing)
2742 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", modelname, texture->name);
2745 // init the animation variables
2746 texture->currentframe = texture;
2747 texture->currentmaterialflags = texture->basematerialflags;
2748 if (!texture->materialshaderpass)
2749 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadMissing());
2750 if (!texture->materialshaderpass->skinframes[0])
2751 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2752 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2753 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2757 void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
2759 if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
2760 Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name);
2762 strlcpy(texture->name, name, sizeof(texture->name));
2763 texture->basealpha = 1.0f;
2764 texture->basematerialflags = materialflags;
2765 texture->supercontents = supercontents;
2767 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2768 texture->offsetscale = 1;
2769 texture->offsetbias = 0;
2770 texture->specularscalemod = 1;
2771 texture->specularpowermod = 1;
2772 texture->rtlightambient = 0;
2773 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2774 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2775 // JUST GREP FOR "specularscalemod = 1".
2777 if (developer_extra.integer)
2778 Con_DPrintf("^1Custom texture ^3\"%s\"\n", texture->name);
2780 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2782 // init the animation variables
2783 texture->currentmaterialflags = texture->basematerialflags;
2784 texture->currentframe = texture;
2785 texture->currentskinframe = skinframe;
2786 texture->backgroundcurrentskinframe = NULL;
2789 void Mod_UnloadCustomMaterial(texture_t *texture, qboolean purgeskins)
2792 for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++)
2794 if (texture->shaderpasses[i])
2797 for (j = 0; j < sizeof(texture->shaderpasses[i]->skinframes) / sizeof(skinframe_t *);j++)
2798 if (texture->shaderpasses[i]->skinframes[j] && texture->shaderpasses[i]->skinframes[j]->base)
2799 R_SkinFrame_PurgeSkinFrame(texture->shaderpasses[i]->skinframes[j]);
2800 Mem_Free(texture->shaderpasses[i]);
2801 texture->shaderpasses[i] = NULL;
2804 texture->materialshaderpass = NULL;
2805 texture->currentskinframe = NULL;
2806 texture->backgroundcurrentskinframe = NULL;
2809 skinfile_t *Mod_LoadSkinFiles(void)
2811 int i, words, line, wordsoverflow;
2814 skinfile_t *skinfile = NULL, *first = NULL;
2815 skinfileitem_t *skinfileitem;
2816 char word[10][MAX_QPATH];
2821 U_bodyBox,models/players/Legoman/BikerA2.tga
2822 U_RArm,models/players/Legoman/BikerA1.tga
2823 U_LArm,models/players/Legoman/BikerA1.tga
2824 U_armor,common/nodraw
2825 U_sword,common/nodraw
2826 U_shield,common/nodraw
2827 U_homb,common/nodraw
2828 U_backpack,common/nodraw
2829 U_colcha,common/nodraw
2834 memset(word, 0, sizeof(word));
2835 for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2837 // If it's the first file we parse
2838 if (skinfile == NULL)
2840 skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2845 skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2846 skinfile = skinfile->next;
2848 skinfile->next = NULL;
2850 for(line = 0;;line++)
2853 if (!COM_ParseToken_QuakeC(&data, true))
2855 if (!strcmp(com_token, "\n"))
2858 wordsoverflow = false;
2862 strlcpy(word[words++], com_token, sizeof (word[0]));
2864 wordsoverflow = true;
2866 while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2869 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);
2872 // words is always >= 1
2873 if (!strcmp(word[0], "replace"))
2877 if (developer_loading.integer)
2878 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2879 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2880 skinfileitem->next = skinfile->items;
2881 skinfile->items = skinfileitem;
2882 strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2883 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2886 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]);
2888 else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2890 // tag name, like "tag_weapon,"
2891 // not used for anything (not even in Quake3)
2893 else if (words >= 2 && !strcmp(word[1], ","))
2895 // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2896 if (developer_loading.integer)
2897 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2898 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2899 skinfileitem->next = skinfile->items;
2900 skinfile->items = skinfileitem;
2901 strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2902 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2905 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);
2910 loadmodel->numskins = i;
2914 void Mod_FreeSkinFiles(skinfile_t *skinfile)
2917 skinfileitem_t *skinfileitem, *nextitem;
2918 for (;skinfile;skinfile = next)
2920 next = skinfile->next;
2921 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2923 nextitem = skinfileitem->next;
2924 Mem_Free(skinfileitem);
2930 int Mod_CountSkinFiles(skinfile_t *skinfile)
2933 for (i = 0;skinfile;skinfile = skinfile->next, i++);
2937 void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
2940 double isnap = 1.0 / snap;
2941 for (i = 0;i < numvertices*numcomponents;i++)
2942 vertices[i] = floor(vertices[i]*isnap)*snap;
2945 int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
2947 int i, outtriangles;
2948 float edgedir1[3], edgedir2[3], temp[3];
2949 // a degenerate triangle is one with no width (thickness, surface area)
2950 // these are characterized by having all 3 points colinear (along a line)
2951 // or having two points identical
2952 // the simplest check is to calculate the triangle's area
2953 for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
2955 // calculate first edge
2956 VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
2957 VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
2958 CrossProduct(edgedir1, edgedir2, temp);
2959 if (VectorLength2(temp) < 0.001f)
2960 continue; // degenerate triangle (no area)
2961 // valid triangle (has area)
2962 VectorCopy(inelement3i, outelement3i);
2966 return outtriangles;
2969 void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
2972 int firstvertex, lastvertex;
2973 if (numelements > 0 && elements)
2975 firstvertex = lastvertex = elements[0];
2976 for (i = 1;i < numelements;i++)
2979 firstvertex = min(firstvertex, e);
2980 lastvertex = max(lastvertex, e);
2984 firstvertex = lastvertex = 0;
2985 if (firstvertexpointer)
2986 *firstvertexpointer = firstvertex;
2987 if (lastvertexpointer)
2988 *lastvertexpointer = lastvertex;
2991 void Mod_MakeSortedSurfaces(dp_model_t *mod)
2993 // make an optimal set of texture-sorted batches to draw...
2995 int *firstsurfacefortexture;
2996 int *numsurfacesfortexture;
2997 if (!mod->sortedmodelsurfaces)
2998 mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
2999 firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
3000 numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
3001 memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
3002 for (j = 0;j < mod->nummodelsurfaces;j++)
3004 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
3005 t = (int)(surface->texture - mod->data_textures);
3006 numsurfacesfortexture[t]++;
3009 for (t = 0;t < mod->num_textures;t++)
3011 firstsurfacefortexture[t] = j;
3012 j += numsurfacesfortexture[t];
3014 for (j = 0;j < mod->nummodelsurfaces;j++)
3016 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
3017 t = (int)(surface->texture - mod->data_textures);
3018 mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
3020 Mem_Free(firstsurfacefortexture);
3021 Mem_Free(numsurfacesfortexture);
3024 void Mod_BuildVBOs(void)
3026 if (!loadmodel->surfmesh.num_vertices)
3029 if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
3032 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3034 if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
3036 Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
3037 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3042 // build r_vertexmesh_t array
3043 // (compressed interleaved array for D3D)
3044 if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
3047 int numvertices = loadmodel->surfmesh.num_vertices;
3048 r_vertexmesh_t *vertexmesh;
3049 loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
3050 for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
3052 VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
3053 VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
3054 VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
3055 VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
3056 if (loadmodel->surfmesh.data_lightmapcolor4f)
3057 Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f);
3058 Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
3059 if (loadmodel->surfmesh.data_texcoordlightmap2f)
3060 Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
3061 if (loadmodel->surfmesh.data_skeletalindex4ub)
3062 Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
3063 if (loadmodel->surfmesh.data_skeletalweight4ub)
3064 Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
3068 // upload short indices as a buffer
3069 if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
3070 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);
3072 // upload int indices as a buffer
3073 if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
3074 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);
3076 // only build a vbo if one has not already been created (this is important for brush models which load specially)
3077 // vertex buffer is several arrays and we put them in the same buffer
3079 // is this wise? the texcoordtexture2f array is used with dynamic
3080 // vertex/svector/tvector/normal when rendering animated models, on the
3081 // other hand animated models don't use a lot of vertices anyway...
3082 if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
3087 loadmodel->surfmesh.vbooffset_vertexmesh = size;if (loadmodel->surfmesh.data_vertexmesh ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
3088 loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3089 loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3090 loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3091 loadmodel->surfmesh.vbooffset_normal3f = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3092 loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3093 loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3094 loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3095 loadmodel->surfmesh.vbooffset_skeletalindex4ub = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3096 loadmodel->surfmesh.vbooffset_skeletalweight4ub = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3097 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
3098 if (loadmodel->surfmesh.data_vertexmesh ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh , loadmodel->surfmesh.data_vertexmesh , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
3099 if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3100 if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3101 if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3102 if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3103 if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3104 if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3105 if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
3106 if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3107 if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3108 loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
3113 extern cvar_t mod_obj_orientation;
3114 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
3116 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
3118 const char *texname;
3120 const float *v, *vn, *vt;
3122 size_t outbufferpos = 0;
3123 size_t outbuffermax = 0x100000;
3124 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3125 const msurface_t *surface;
3126 const int maxtextures = 256;
3127 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
3128 dp_model_t *submodel;
3130 // construct the mtllib file
3131 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
3134 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3137 countvertices += surface->num_vertices;
3138 countfaces += surface->num_triangles;
3139 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
3140 for (textureindex = 0;textureindex < counttextures;textureindex++)
3141 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
3143 if (textureindex < counttextures)
3144 continue; // already wrote this material entry
3145 if (textureindex >= maxtextures)
3146 continue; // just a precaution
3147 textureindex = counttextures++;
3148 strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
3149 if (outbufferpos >= outbuffermax >> 1)
3152 oldbuffer = outbuffer;
3153 outbuffer = (char *) Z_Malloc(outbuffermax);
3154 memcpy(outbuffer, oldbuffer, outbufferpos);
3157 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");
3162 // write the mtllib file
3163 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3165 // construct the obj file
3167 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);
3171 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)
3173 if (outbufferpos >= outbuffermax >> 1)
3176 oldbuffer = outbuffer;
3177 outbuffer = (char *) Z_Malloc(outbuffermax);
3178 memcpy(outbuffer, oldbuffer, outbufferpos);
3181 if(mod_obj_orientation.integer)
3182 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]);
3184 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]);
3189 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3191 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3194 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3195 for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3197 surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3198 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3201 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3203 if (outbufferpos >= outbuffermax >> 1)
3206 oldbuffer = outbuffer;
3207 outbuffer = (char *) Z_Malloc(outbuffermax);
3208 memcpy(outbuffer, oldbuffer, outbufferpos);
3214 if(mod_obj_orientation.integer)
3215 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);
3217 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);
3224 // write the obj file
3225 FS_WriteFile(filename, outbuffer, outbufferpos);
3229 Z_Free(texturenames);
3232 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3235 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3237 int countnodes = 0, counttriangles = 0, countframes = 0;
3245 size_t outbufferpos = 0;
3246 size_t outbuffermax = 0x100000;
3247 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3248 const msurface_t *surface;
3249 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3252 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3254 if (outbufferpos >= outbuffermax >> 1)
3257 oldbuffer = outbuffer;
3258 outbuffer = (char *) Z_Malloc(outbuffermax);
3259 memcpy(outbuffer, oldbuffer, outbufferpos);
3263 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3267 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3270 for (poseindex = 0;poseindex < numposes;poseindex++)
3273 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3276 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3280 matrix4x4_t posematrix;
3281 if (outbufferpos >= outbuffermax >> 1)
3284 oldbuffer = outbuffer;
3285 outbuffer = (char *) Z_Malloc(outbuffermax);
3286 memcpy(outbuffer, oldbuffer, outbufferpos);
3290 // strangely the smd angles are for a transposed matrix, so we
3291 // have to generate a transposed matrix, then convert that...
3292 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3293 Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3294 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3295 if (angles[0] >= 180) angles[0] -= 360;
3296 if (angles[1] >= 180) angles[1] -= 360;
3297 if (angles[2] >= 180) angles[2] -= 360;
3301 float a = DEG2RAD(angles[ROLL]);
3302 float b = DEG2RAD(angles[PITCH]);
3303 float c = DEG2RAD(angles[YAW]);
3304 float cy, sy, cp, sp, cr, sr;
3306 // smd matrix construction, for comparing
3317 test[1][0] = sr*sp*cy+cr*-sy;
3318 test[1][1] = sr*sp*sy+cr*cy;
3320 test[2][0] = (cr*sp*cy+-sr*-sy);
3321 test[2][1] = (cr*sp*sy+-sr*cy);
3323 test[3][0] = pose[9];
3324 test[3][1] = pose[10];
3325 test[3][2] = pose[11];
3328 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]));
3333 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3338 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3341 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3343 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3346 if (outbufferpos >= outbuffermax >> 1)
3349 oldbuffer = outbuffer;
3350 outbuffer = (char *) Z_Malloc(outbuffermax);
3351 memcpy(outbuffer, oldbuffer, outbufferpos);
3354 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3357 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3359 const int index = e[2-cornerindex];
3360 const float *v = model->surfmesh.data_vertex3f + index * 3;
3361 const float *vn = model->surfmesh.data_normal3f + index * 3;
3362 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3363 const int b = model->surfmesh.blends[index];
3364 if (b < model->num_bones)
3365 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]);
3368 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3369 const unsigned char *wi = w->index;
3370 const unsigned char *wf = w->influence;
3371 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);
3372 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);
3373 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);
3374 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]);
3381 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3386 FS_WriteFile(filename, outbuffer, outbufferpos);
3389 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3396 decompiles a model to editable files
3399 static void Mod_Decompile_f(void)
3401 int i, j, k, l, first, count;
3403 char inname[MAX_QPATH];
3404 char outname[MAX_QPATH];
3405 char mtlname[MAX_QPATH];
3406 char basename[MAX_QPATH];
3407 char animname[MAX_QPATH];
3408 char animname2[MAX_QPATH];
3409 char zymtextbuffer[16384];
3410 char dpmtextbuffer[16384];
3411 char framegroupstextbuffer[16384];
3412 int zymtextsize = 0;
3413 int dpmtextsize = 0;
3414 int framegroupstextsize = 0;
3417 if (Cmd_Argc() != 2)
3419 Con_Print("usage: modeldecompile <filename>\n");
3423 strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3424 FS_StripExtension(inname, basename, sizeof(basename));
3426 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3429 Con_Print("No such model\n");
3432 if (mod->brush.submodel)
3434 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3435 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3436 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3439 if (!mod->surfmesh.num_triangles)
3441 Con_Print("Empty model (or sprite)\n");
3445 // export OBJ if possible (not on sprites)
3446 if (mod->surfmesh.num_triangles)
3448 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3449 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3450 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3453 // export SMD if possible (only for skeletal models)
3454 if (mod->surfmesh.num_triangles && mod->num_bones)
3456 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3457 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3458 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3459 if (l > 0) zymtextsize += l;
3460 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3461 if (l > 0) dpmtextsize += l;
3462 for (i = 0;i < mod->numframes;i = j)
3464 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3465 first = mod->animscenes[i].firstframe;
3466 if (mod->animscenes[i].framecount > 1)
3469 count = mod->animscenes[i].framecount;
3475 // check for additional frames with same name
3476 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3477 if(animname[l] < '0' || animname[l] > '9')
3479 if(k > 0 && animname[k-1] == '_')
3482 count = mod->num_poses - first;
3483 for (j = i + 1;j < mod->numframes;j++)
3485 strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3486 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3487 if(animname2[l] < '0' || animname2[l] > '9')
3489 if(k > 0 && animname[k-1] == '_')
3492 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3494 count = mod->animscenes[j].firstframe - first;
3498 // if it's only one frame, use the original frame name
3500 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3503 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3504 Mod_Decompile_SMD(mod, outname, first, count, false);
3505 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3507 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3508 if (l > 0) zymtextsize += l;
3510 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3512 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3513 if (l > 0) dpmtextsize += l;
3515 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3517 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3518 if (l > 0) framegroupstextsize += l;
3522 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3524 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3525 if (framegroupstextsize)
3526 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3530 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
3533 memset(state, 0, sizeof(*state));
3534 state->width = width;
3535 state->height = height;
3536 state->currentY = 0;
3537 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3538 for (y = 0;y < state->height;y++)
3540 state->rows[y].currentX = 0;
3541 state->rows[y].rowY = -1;
3545 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3548 state->currentY = 0;
3549 for (y = 0;y < state->height;y++)
3551 state->rows[y].currentX = 0;
3552 state->rows[y].rowY = -1;
3556 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3559 Mem_Free(state->rows);
3560 memset(state, 0, sizeof(*state));
3563 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3565 mod_alloclightmap_row_t *row;
3568 row = state->rows + blockheight;
3569 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3571 if (state->currentY + blockheight <= state->height)
3573 // use the current allocation position
3574 row->rowY = state->currentY;
3576 state->currentY += blockheight;
3580 // find another position
3581 for (y = blockheight;y < state->height;y++)
3583 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3585 row = state->rows + y;
3589 if (y == state->height)
3594 *outx = row->currentX;
3595 row->currentX += blockwidth;
3600 typedef struct lightmapsample_s
3604 float *vertex_color;
3605 unsigned char *lm_bgr;
3606 unsigned char *lm_dir;
3610 typedef struct lightmapvertex_s
3615 float texcoordbase[2];
3616 float texcoordlightmap[2];
3617 float lightcolor[4];
3621 typedef struct lightmaptriangle_s
3629 // 2D modelspace coordinates of min corner
3630 // snapped to lightmap grid but not in grid coordinates
3632 // 2D modelspace to lightmap coordinate scale
3640 typedef struct lightmaplight_s
3651 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3653 #define MAX_LIGHTMAPSAMPLES 64
3654 static int mod_generatelightmaps_numoffsets[3];
3655 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3657 static int mod_generatelightmaps_numlights;
3658 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3660 extern cvar_t r_shadow_lightattenuationdividebias;
3661 extern cvar_t r_shadow_lightattenuationlinearscale;
3663 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3668 float relativepoint[3];
3675 float lightorigin[3];
3679 float lightcolor[3];
3681 for (i = 0;i < 5*3;i++)
3683 for (index = 0;;index++)
3685 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3690 lightradius2 = lightradius * lightradius;
3691 VectorSubtract(lightorigin, pos, relativepoint);
3692 dist2 = VectorLength2(relativepoint);
3693 if (dist2 >= lightradius2)
3695 lightiradius = 1.0f / lightradius;
3696 dist = sqrt(dist2) * lightiradius;
3697 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3698 if (intensity <= 0.0f)
3700 if (model && model->TraceLine)
3702 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3703 if (trace.fraction < 1)
3706 // scale down intensity to add to both ambient and diffuse
3707 //intensity *= 0.5f;
3708 VectorNormalize(relativepoint);
3709 VectorScale(lightcolor, intensity, color);
3710 VectorMA(sample , 0.5f , color, sample );
3711 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3712 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3713 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3714 // calculate a weighted average light direction as well
3715 intensity *= VectorLength(color);
3716 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3718 // calculate the direction we'll use to reduce the sample to a directional light source
3719 VectorCopy(sample + 12, dir);
3720 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3721 VectorNormalize(dir);
3722 // extract the diffuse color along the chosen direction and scale it
3723 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3724 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3725 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3726 // subtract some of diffuse from ambient
3727 VectorMA(sample, -0.333f, diffuse, ambient);
3728 // store the normalized lightdir
3729 VectorCopy(dir, lightdir);
3732 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3736 const msurface_t *surface;
3737 const float *vertex3f = model->surfmesh.data_vertex3f;
3738 const int *element3i = model->surfmesh.data_element3i;
3741 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3743 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3745 if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3747 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3749 VectorCopy(vertex3f + 3*e[0], v2[0]);
3750 VectorCopy(vertex3f + 3*e[1], v2[1]);
3751 VectorCopy(vertex3f + 3*e[2], v2[2]);
3752 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3757 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3759 int maxnodes = 1<<14;
3760 svbsp_node_t *nodes;
3765 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3766 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3767 VectorCopy(lightinfo->origin, origin);
3768 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3771 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3772 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3773 if (svbsp.ranoutofnodes)
3776 if (maxnodes > 1<<22)
3782 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3787 if (svbsp.numnodes > 0)
3789 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3790 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3791 lightinfo->svbsp = svbsp;
3796 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3800 lightmaplight_t *lightinfo;
3804 mod_generatelightmaps_numlights = 0;
3805 for (index = 0;;index++)
3807 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3811 mod_generatelightmaps_numlights++;
3813 if (mod_generatelightmaps_numlights > 0)
3815 mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3816 lightinfo = mod_generatelightmaps_lightinfo;
3817 for (index = 0;;index++)
3819 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3826 for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3828 lightinfo->iradius = 1.0f / lightinfo->radius;
3829 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3830 // TODO: compute svbsp
3831 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3835 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3838 if (mod_generatelightmaps_lightinfo)
3840 for (i = 0;i < mod_generatelightmaps_numlights;i++)
3841 if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3842 Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3843 Mem_Free(mod_generatelightmaps_lightinfo);
3845 mod_generatelightmaps_lightinfo = NULL;
3846 mod_generatelightmaps_numlights = 0;
3849 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3851 const svbsp_node_t *node;
3852 const svbsp_node_t *nodes = svbsp->nodes;
3857 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3859 return num == -1; // true if empty, false if solid (shadowed)
3862 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3865 float relativepoint[3];
3874 const lightmaplight_t *lightinfo;
3876 for (i = 0;i < 5*3;i++)
3878 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3880 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3881 VectorSubtract(lightinfo->origin, pos, relativepoint);
3882 // don't accept light from behind a surface, it causes bad shading
3883 if (normal && DotProduct(relativepoint, normal) <= 0)
3885 dist2 = VectorLength2(relativepoint);
3886 if (dist2 >= lightinfo->radius2)
3888 dist = sqrt(dist2) * lightinfo->iradius;
3889 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3892 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3896 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3898 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3900 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3903 // for light grid we'd better check visibility of the offset point
3904 cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3905 if (trace.fraction < 1)
3906 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3909 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3914 // scale intensity according to how many rays succeeded
3915 // we know one test is valid, half of the rest will fail...
3916 //if (normal && tests > 1)
3917 // intensity *= (tests - 1.0f) / tests;
3918 intensity *= (float)hits / tests;
3920 // scale down intensity to add to both ambient and diffuse
3921 //intensity *= 0.5f;
3922 VectorNormalize(relativepoint);
3923 VectorScale(lightinfo->color, intensity, color);
3924 VectorMA(sample , 0.5f , color, sample );
3925 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3926 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3927 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3928 // calculate a weighted average light direction as well
3929 intensity *= VectorLength(color);
3930 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3934 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3940 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
3941 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3942 VectorCopy(sample + 12, dir);
3943 VectorNormalize(dir);
3944 //VectorAdd(dir, normal, dir);
3945 //VectorNormalize(dir);
3946 f = DotProduct(dir, normal);
3947 f = max(0, f) * 255.0f;
3948 VectorScale(sample, f, color);
3949 //VectorCopy(normal, dir);
3950 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3951 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3952 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3953 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3955 lm_dir[0] = (unsigned char)dir[2];
3956 lm_dir[1] = (unsigned char)dir[1];
3957 lm_dir[2] = (unsigned char)dir[0];
3961 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3964 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
3965 VectorCopy(sample, vertex_color);
3968 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3974 Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
3975 // calculate the direction we'll use to reduce the sample to a directional light source
3976 VectorCopy(sample + 12, dir);
3977 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3978 VectorNormalize(dir);
3979 // extract the diffuse color along the chosen direction and scale it
3980 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3981 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3982 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3983 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3984 VectorScale(sample, 127.5f, ambient);
3985 VectorMA(ambient, -0.333f, diffuse, ambient);
3986 // encode to the grid format
3987 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3988 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3989 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3990 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3991 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3992 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3993 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3994 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3995 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));}
3998 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
4003 memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
4004 mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
4005 mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
4006 mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
4007 radius[0] = mod_generatelightmaps_lightmapradius.value;
4008 radius[1] = mod_generatelightmaps_vertexradius.value;
4009 radius[2] = mod_generatelightmaps_gridradius.value;
4010 for (i = 0;i < 3;i++)
4012 for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
4015 VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
4020 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
4022 msurface_t *surface;
4025 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4027 surface = model->data_surfaces + surfaceindex;
4028 surface->lightmaptexture = NULL;
4029 surface->deluxemaptexture = NULL;
4031 if (model->brushq3.data_lightmaps)
4033 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4034 if (model->brushq3.data_lightmaps[i])
4035 R_FreeTexture(model->brushq3.data_lightmaps[i]);
4036 Mem_Free(model->brushq3.data_lightmaps);
4037 model->brushq3.data_lightmaps = NULL;
4039 if (model->brushq3.data_deluxemaps)
4041 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4042 if (model->brushq3.data_deluxemaps[i])
4043 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
4044 Mem_Free(model->brushq3.data_deluxemaps);
4045 model->brushq3.data_deluxemaps = NULL;
4049 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
4051 msurface_t *surface;
4057 surfmesh_t oldsurfmesh;
4059 unsigned char *data;
4060 oldsurfmesh = model->surfmesh;
4061 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
4062 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
4064 size += model->surfmesh.num_vertices * sizeof(float[3]);
4065 size += model->surfmesh.num_vertices * sizeof(float[3]);
4066 size += model->surfmesh.num_vertices * sizeof(float[3]);
4067 size += model->surfmesh.num_vertices * sizeof(float[3]);
4068 size += model->surfmesh.num_vertices * sizeof(float[2]);
4069 size += model->surfmesh.num_vertices * sizeof(float[2]);
4070 size += model->surfmesh.num_vertices * sizeof(float[4]);
4071 data = (unsigned char *)Mem_Alloc(model->mempool, size);
4072 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4073 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4074 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4075 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4076 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4077 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4078 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
4079 if (model->surfmesh.num_vertices > 65536)
4080 model->surfmesh.data_element3s = NULL;
4082 if (model->surfmesh.data_element3i_indexbuffer)
4083 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
4084 model->surfmesh.data_element3i_indexbuffer = NULL;
4085 if (model->surfmesh.data_element3s_indexbuffer)
4086 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
4087 model->surfmesh.data_element3s_indexbuffer = NULL;
4088 if (model->surfmesh.vbo_vertexbuffer)
4089 R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
4090 model->surfmesh.vbo_vertexbuffer = 0;
4092 // convert all triangles to unique vertex data
4094 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4096 surface = model->data_surfaces + surfaceindex;
4097 surface->num_firstvertex = outvertexindex;
4098 surface->num_vertices = surface->num_triangles*3;
4099 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
4100 for (i = 0;i < surface->num_triangles*3;i++)
4103 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
4104 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
4105 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
4106 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
4107 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
4108 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
4109 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
4110 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
4111 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
4112 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
4113 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
4114 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
4115 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
4116 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
4117 if (oldsurfmesh.data_texcoordlightmap2f)
4119 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
4120 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
4122 if (oldsurfmesh.data_lightmapcolor4f)
4124 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
4125 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
4126 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
4127 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
4130 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
4131 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
4135 if (model->surfmesh.data_element3s)
4136 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
4137 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
4139 // find and update all submodels to use this new surfmesh data
4140 for (i = 0;i < model->brush.numsubmodels;i++)
4141 model->brush.submodels[i]->surfmesh = model->surfmesh;
4144 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4146 msurface_t *surface;
4152 lightmaptriangle_t *triangle;
4153 // generate lightmap triangle structs
4154 mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4155 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4157 surface = model->data_surfaces + surfaceindex;
4158 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4159 for (i = 0;i < surface->num_triangles;i++)
4161 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4162 triangle->triangleindex = surface->num_firsttriangle+i;
4163 triangle->surfaceindex = surfaceindex;
4164 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4165 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4166 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4167 // calculate bounds of triangle
4168 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4169 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4170 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4171 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4172 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4173 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4174 // pick an axial projection based on the triangle normal
4175 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4177 if (fabs(normal[1]) > fabs(normal[axis]))
4179 if (fabs(normal[2]) > fabs(normal[axis]))
4181 triangle->axis = axis;
4186 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4188 if (mod_generatelightmaps_lightmaptriangles)
4189 Mem_Free(mod_generatelightmaps_lightmaptriangles);
4190 mod_generatelightmaps_lightmaptriangles = NULL;
4193 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4195 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4197 msurface_t *surface;
4211 float trianglenormal[3];
4212 float samplecenter[3];
4213 float samplenormal[3];
4219 float lmscalepixels;
4222 float lm_basescalepixels;
4223 int lm_borderpixels;
4227 lightmaptriangle_t *triangle;
4228 unsigned char *lightmappixels;
4229 unsigned char *deluxemappixels;
4230 mod_alloclightmap_state_t lmstate;
4233 // generate lightmap projection information for all triangles
4234 if (model->texturepool == NULL)
4235 model->texturepool = R_AllocTexturePool();
4236 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4237 lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4238 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4239 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4240 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4242 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4244 surface = model->data_surfaces + surfaceindex;
4245 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4246 lmscalepixels = lm_basescalepixels;
4247 for (retry = 0;retry < 30;retry++)
4249 // after a couple failed attempts, degrade quality to make it fit
4251 lmscalepixels *= 0.5f;
4252 for (i = 0;i < surface->num_triangles;i++)
4254 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4255 triangle->lightmapindex = lightmapnumber;
4256 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4257 // pick two planar axes for projection
4258 // lightmap coordinates here are in pixels
4259 // lightmap projections are snapped to pixel grid explicitly, such
4260 // that two neighboring triangles sharing an edge and projection
4261 // axis will have identical sample spacing along their shared edge
4263 for (j = 0;j < 3;j++)
4265 if (j == triangle->axis)
4267 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4268 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4269 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4270 triangle->lmbase[k] = lmmins/lmscalepixels;
4271 triangle->lmscale[k] = lmscalepixels;
4274 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4277 // if all fit in this texture, we're done with this surface
4278 if (i == surface->num_triangles)
4280 // if we haven't maxed out the lightmap size yet, we retry the
4281 // entire surface batch...
4282 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4284 lm_texturesize *= 2;
4287 Mod_AllocLightmap_Free(&lmstate);
4288 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4291 // if we have maxed out the lightmap size, and this triangle does
4292 // not fit in the same texture as the rest of the surface, we have
4293 // to retry the entire surface in a new texture (can only use one)
4294 // with multiple retries, the lightmap quality degrades until it
4295 // fits (or gives up)
4296 if (surfaceindex > 0)
4298 Mod_AllocLightmap_Reset(&lmstate);
4302 Mod_AllocLightmap_Free(&lmstate);
4304 // now put triangles together into lightmap textures, and do not allow
4305 // triangles of a surface to go into different textures (as that would
4306 // require rewriting the surface list)
4307 model->brushq3.deluxemapping_modelspace = true;
4308 model->brushq3.deluxemapping = true;
4309 model->brushq3.num_mergedlightmaps = lightmapnumber;
4310 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4311 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4312 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4313 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4314 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4316 surface = model->data_surfaces + surfaceindex;
4317 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4318 for (i = 0;i < surface->num_triangles;i++)
4320 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4321 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4322 VectorNormalize(trianglenormal);
4323 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4324 axis = triangle->axis;
4325 axis1 = axis == 0 ? 1 : 0;
4326 axis2 = axis == 2 ? 1 : 2;
4327 lmiscale[0] = 1.0f / triangle->lmscale[0];
4328 lmiscale[1] = 1.0f / triangle->lmscale[1];
4329 if (trianglenormal[axis] < 0)
4330 VectorNegate(trianglenormal, trianglenormal);
4331 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4332 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4333 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4334 for (j = 0;j < 3;j++)
4336 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4337 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4338 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4340 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4341 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4342 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4343 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]);
4353 forward[1] = 1.0f / triangle->lmscale[0];
4357 left[2] = 1.0f / triangle->lmscale[1];
4362 origin[1] = triangle->lmbase[0];
4363 origin[2] = triangle->lmbase[1];
4366 forward[0] = 1.0f / triangle->lmscale[0];
4371 left[2] = 1.0f / triangle->lmscale[1];
4375 origin[0] = triangle->lmbase[0];
4377 origin[2] = triangle->lmbase[1];
4380 forward[0] = 1.0f / triangle->lmscale[0];
4384 left[1] = 1.0f / triangle->lmscale[1];
4389 origin[0] = triangle->lmbase[0];
4390 origin[1] = triangle->lmbase[1];
4394 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4396 #define LM_DIST_EPSILON (1.0f / 32.0f)
4397 for (y = 0;y < triangle->lmsize[1];y++)
4399 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4400 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4402 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4403 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4404 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4405 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4406 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4412 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4414 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);
4415 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);
4419 Mem_Free(lightmappixels);
4420 if (deluxemappixels)
4421 Mem_Free(deluxemappixels);
4423 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4425 surface = model->data_surfaces + surfaceindex;
4426 if (!surface->num_triangles)
4428 lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4429 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4430 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4431 surface->lightmapinfo = NULL;
4434 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4435 model->brushq1.lightdata = NULL;
4436 model->brushq1.lightmapupdateflags = NULL;
4437 model->brushq1.firstrender = false;
4438 model->brushq1.num_lightstyles = 0;
4439 model->brushq1.data_lightstyleinfo = NULL;
4440 for (i = 0;i < model->brush.numsubmodels;i++)
4442 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4443 model->brush.submodels[i]->brushq1.firstrender = false;
4444 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4445 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4449 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4452 for (i = 0;i < model->surfmesh.num_vertices;i++)
4453 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4456 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4463 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4465 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4466 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4468 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4469 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4471 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4472 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4478 extern cvar_t mod_q3bsp_nolightmaps;
4479 static void Mod_GenerateLightmaps(dp_model_t *model)
4481 //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4482 dp_model_t *oldloadmodel = loadmodel;
4485 Mod_GenerateLightmaps_InitSampleOffsets(model);
4486 Mod_GenerateLightmaps_DestroyLightmaps(model);
4487 Mod_GenerateLightmaps_UnweldTriangles(model);
4488 Mod_GenerateLightmaps_CreateTriangleInformation(model);
4489 Mod_GenerateLightmaps_CreateLights(model);
4490 if(!mod_q3bsp_nolightmaps.integer)
4491 Mod_GenerateLightmaps_CreateLightmaps(model);
4492 Mod_GenerateLightmaps_UpdateVertexColors(model);
4493 Mod_GenerateLightmaps_UpdateLightGrid(model);
4494 Mod_GenerateLightmaps_DestroyLights(model);
4495 Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4497 loadmodel = oldloadmodel;
4500 static void Mod_GenerateLightmaps_f(void)
4502 if (Cmd_Argc() != 1)
4504 Con_Printf("usage: mod_generatelightmaps\n");
4509 Con_Printf("no worldmodel loaded\n");
4512 Mod_GenerateLightmaps(cl.worldmodel);
4515 void Mod_Mesh_Create(dp_model_t *mod, const char *name)
4517 memset(mod, 0, sizeof(*mod));
4518 strlcpy(mod->name, name, sizeof(mod->name));
4519 mod->mempool = Mem_AllocPool(name, 0, NULL);
4520 mod->texturepool = R_AllocTexturePool();
4521 mod->Draw = R_Q1BSP_Draw;
4522 mod->DrawDepth = R_Q1BSP_DrawDepth;
4523 mod->DrawDebug = R_Q1BSP_DrawDebug;
4524 mod->DrawPrepass = R_Q1BSP_DrawPrepass;
4525 mod->GetLightInfo = R_Q1BSP_GetLightInfo;
4526 mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
4527 mod->DrawLight = R_Q1BSP_DrawLight;
4530 void Mod_Mesh_Destroy(dp_model_t *mod)
4532 Mod_UnloadModel(mod);
4535 // resets the mesh model to have no geometry to render, ready for a new frame -
4536 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4537 void Mod_Mesh_Reset(dp_model_t *mod)
4539 mod->num_surfaces = 0;
4540 mod->surfmesh.num_vertices = 0;
4541 mod->surfmesh.num_triangles = 0;
4542 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4543 mod->DrawSky = NULL; // will be set if a texture needs it
4544 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4547 texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
4551 for (i = 0; i < mod->num_textures; i++)
4552 if (!strcmp(mod->data_textures[i].name, name))
4553 return mod->data_textures + i;
4554 if (mod->max_textures <= mod->num_textures)
4556 texture_t *oldtextures = mod->data_textures;
4557 mod->max_textures = max(mod->max_textures * 2, 1024);
4558 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4559 // update the pointers
4560 for (i = 0; i < mod->num_surfaces; i++)
4561 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4563 t = &mod->data_textures[mod->num_textures++];
4564 Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, false, true, defaulttexflags, defaultmaterialflags);
4565 switch (defaultdrawflags & DRAWFLAG_MASK)
4567 case DRAWFLAG_ADDITIVE:
4568 t->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED;
4569 t->currentmaterialflags = t->basematerialflags;
4571 case DRAWFLAG_MODULATE:
4572 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4573 t->currentmaterialflags = t->basematerialflags;
4574 t->customblendfunc[0] = GL_DST_COLOR;
4575 t->customblendfunc[1] = GL_ZERO;
4577 case DRAWFLAG_2XMODULATE:
4578 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4579 t->currentmaterialflags = t->basematerialflags;
4580 t->customblendfunc[0] = GL_DST_COLOR;
4581 t->customblendfunc[1] = GL_SRC_COLOR;
4583 case DRAWFLAG_SCREEN:
4584 t->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_BLENDED;
4585 t->currentmaterialflags = t->basematerialflags;
4586 t->customblendfunc[0] = GL_ONE_MINUS_DST_COLOR;
4587 t->customblendfunc[1] = GL_ONE;
4595 msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex, qboolean batchwithprevioussurface)
4598 // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
4599 if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex)
4600 return mod->data_surfaces + mod->num_surfaces - 1;
4601 // create new surface
4602 if (mod->max_surfaces == mod->num_surfaces)
4604 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4605 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4606 mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
4608 surf = mod->data_surfaces + mod->num_surfaces;
4609 mod->num_surfaces++;
4610 memset(surf, 0, sizeof(*surf));
4611 surf->texture = tex;
4612 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4613 surf->num_firstvertex = mod->surfmesh.num_vertices;
4614 if (tex->basematerialflags & (MATERIALFLAG_SKY))
4615 mod->DrawSky = R_Q1BSP_DrawSky;
4616 if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4617 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
4621 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)
4623 int hashindex, h, vnum, mask;
4624 surfmesh_t *mesh = &mod->surfmesh;
4625 if (mesh->max_vertices == mesh->num_vertices)
4627 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4628 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4629 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4630 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4631 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4632 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4633 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4634 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4635 // rebuild the hash table
4636 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4637 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4638 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4639 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4640 mask = mod->surfmesh.num_vertexhashsize - 1;
4641 // no need to hash the vertices for the entire model, the latest surface will suffice.
4642 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4644 // this uses prime numbers intentionally for computing the hash
4645 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;
4646 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4647 ; // just iterate until we find the terminator
4648 mesh->data_vertexhash[h] = vnum;
4651 mask = mod->surfmesh.num_vertexhashsize - 1;
4652 // this uses prime numbers intentionally for computing the hash
4653 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4654 // when possible find an identical vertex within the same surface and return it
4655 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4657 if (vnum >= surf->num_firstvertex
4658 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4659 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4660 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4661 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4662 && 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)
4665 // add the new vertex
4666 vnum = mesh->num_vertices++;
4667 if (surf->num_vertices > 0)
4669 if (surf->mins[0] > x) surf->mins[0] = x;
4670 if (surf->mins[1] > y) surf->mins[1] = y;
4671 if (surf->mins[2] > z) surf->mins[2] = z;
4672 if (surf->maxs[0] < x) surf->maxs[0] = x;
4673 if (surf->maxs[1] < y) surf->maxs[1] = y;
4674 if (surf->maxs[2] < z) surf->maxs[2] = z;
4678 VectorSet(surf->mins, x, y, z);
4679 VectorSet(surf->maxs, x, y, z);
4681 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4682 mesh->data_vertexhash[h] = vnum;
4683 mesh->data_vertex3f[vnum * 3 + 0] = x;
4684 mesh->data_vertex3f[vnum * 3 + 1] = y;
4685 mesh->data_vertex3f[vnum * 3 + 2] = z;
4686 mesh->data_normal3f[vnum * 3 + 0] = nx;
4687 mesh->data_normal3f[vnum * 3 + 1] = ny;
4688 mesh->data_normal3f[vnum * 3 + 2] = nz;
4689 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4690 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4691 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4692 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4693 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4694 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4695 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4696 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4700 void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4702 surfmesh_t *mesh = &mod->surfmesh;
4703 if (mesh->max_triangles == mesh->num_triangles)
4705 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4706 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4707 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4709 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4710 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4711 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4712 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4713 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4714 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4715 mesh->num_triangles++;
4716 surf->num_triangles++;
4719 static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
4723 msurface_t *surf, *surf2;
4725 // build the sorted surfaces list properly to reduce material setup
4726 // this is easy because we're just sorting on texture and don't care about the order of textures
4727 mod->nummodelsurfaces = 0;
4728 for (i = 0; i < mod->num_surfaces; i++)
4729 mod->data_surfaces[i].included = false;
4730 for (i = 0; i < mod->num_surfaces; i++)
4732 surf = mod->data_surfaces + i;
4735 tex = surf->texture;
4736 // j = i is intentional
4737 for (j = i; j < mod->num_surfaces; j++)
4739 surf2 = mod->data_surfaces + j;
4740 if (surf2->included)
4742 if (surf2->texture == tex)
4744 surf2->included = true;
4745 mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
4751 void Mod_Mesh_ComputeBounds(dp_model_t *mod)
4754 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4756 if (mod->surfmesh.num_vertices > 0)
4758 // calculate normalmins/normalmaxs
4759 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4760 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4761 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4763 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4764 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4765 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4766 // expand bounds to include this vertex
4767 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4768 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4769 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4770 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4771 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4772 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4774 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4775 // (fast but less accurate than doing it per vertex)
4776 x2a = mod->normalmins[0] * mod->normalmins[0];
4777 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4778 y2a = mod->normalmins[1] * mod->normalmins[1];
4779 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4780 z2a = mod->normalmins[2] * mod->normalmins[2];
4781 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4785 yawradius = sqrt(x2 + y2);
4786 rotatedradius = sqrt(x2 + y2 + z2);
4787 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4788 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4789 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4790 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4791 mod->radius = rotatedradius;
4792 mod->radius2 = x2 + y2 + z2;
4796 VectorClear(mod->normalmins);
4797 VectorClear(mod->normalmaxs);
4798 VectorClear(mod->yawmins);
4799 VectorClear(mod->yawmaxs);
4800 VectorClear(mod->rotatedmins);
4801 VectorClear(mod->rotatedmaxs);
4807 void Mod_Mesh_Finalize(dp_model_t *mod)
4809 Mod_Mesh_ComputeBounds(mod);
4810 Mod_Mesh_MakeSortedSurfaces(mod);
4811 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);