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_enableshadowvolumes = {CVAR_SAVE, "r_enableshadowvolumes", "1", "Enables use of Stencil Shadow Volume shadowing methods, saves some memory if turned off"};
31 cvar_t r_mipskins = {CVAR_SAVE, "r_mipskins", "0", "mipmaps model skins so they render faster in the distance and do not display noise artifacts, can cause discoloration of skins if they contain undesirable border colors"};
32 cvar_t r_mipnormalmaps = {CVAR_SAVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
33 cvar_t mod_generatelightmaps_unitspersample = {CVAR_SAVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
34 cvar_t mod_generatelightmaps_borderpixels = {CVAR_SAVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
35 cvar_t mod_generatelightmaps_texturesize = {CVAR_SAVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
36 cvar_t mod_generatelightmaps_lightmapsamples = {CVAR_SAVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
37 cvar_t mod_generatelightmaps_vertexsamples = {CVAR_SAVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
38 cvar_t mod_generatelightmaps_gridsamples = {CVAR_SAVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
39 cvar_t mod_generatelightmaps_lightmapradius = {CVAR_SAVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
40 cvar_t mod_generatelightmaps_vertexradius = {CVAR_SAVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
41 cvar_t mod_generatelightmaps_gridradius = {CVAR_SAVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
43 dp_model_t *loadmodel;
45 static mempool_t *mod_mempool;
46 static memexpandablearray_t models;
48 static mempool_t* q3shaders_mem;
49 typedef struct q3shader_hash_entry_s
51 q3shaderinfo_t shader;
52 struct q3shader_hash_entry_s* chain;
53 } q3shader_hash_entry_t;
54 #define Q3SHADER_HASH_SIZE 1021
55 typedef struct q3shader_data_s
57 memexpandablearray_t hash_entries;
58 q3shader_hash_entry_t hash[Q3SHADER_HASH_SIZE];
59 memexpandablearray_t char_ptrs;
61 static q3shader_data_t* q3shader_data;
63 static void mod_start(void)
66 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
69 SCR_PushLoadingScreen(false, "Loading models", 1.0);
71 for (i = 0;i < nummodels;i++)
72 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
75 for (i = 0;i < nummodels;i++)
76 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
79 SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
80 Mod_LoadModel(mod, true, false);
81 SCR_PopLoadingScreen(false);
83 SCR_PopLoadingScreen(false);
86 static void mod_shutdown(void)
89 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
92 for (i = 0;i < nummodels;i++)
93 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
97 Mod_Skeletal_FreeBuffers();
100 static void mod_newmap(void)
103 int i, j, k, l, surfacenum, ssize, tsize;
104 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
107 for (i = 0;i < nummodels;i++)
109 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
111 for (j = 0;j < mod->num_textures && mod->data_textures;j++)
113 // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them...
114 for (l = 0; l < Q3SHADER_MAXLAYERS; l++)
115 if (mod->data_textures[j].shaderpasses[l])
116 for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++)
117 R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]);
119 if (mod->brush.solidskyskinframe)
120 R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
121 if (mod->brush.alphaskyskinframe)
122 R_SkinFrame_MarkUsed(mod->brush.alphaskyskinframe);
126 if (!cl_stainmaps_clearonload.integer)
129 for (i = 0;i < nummodels;i++)
131 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
133 for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++)
135 if (surface->lightmapinfo && surface->lightmapinfo->stainsamples)
137 ssize = (surface->lightmapinfo->extents[0] >> 4) + 1;
138 tsize = (surface->lightmapinfo->extents[1] >> 4) + 1;
139 memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
140 mod->brushq1.lightmapupdateflags[surfacenum] = true;
152 static void Mod_Print(void);
153 static void Mod_Precache (void);
154 static void Mod_Decompile_f(void);
155 static void Mod_GenerateLightmaps_f(void);
158 mod_mempool = Mem_AllocPool("modelinfo", 0, NULL);
159 Mem_ExpandableArray_NewArray(&models, mod_mempool, sizeof(dp_model_t), 16);
165 Cvar_RegisterVariable(&r_enableshadowvolumes);
166 Cvar_RegisterVariable(&r_mipskins);
167 Cvar_RegisterVariable(&r_mipnormalmaps);
168 Cvar_RegisterVariable(&mod_generatelightmaps_unitspersample);
169 Cvar_RegisterVariable(&mod_generatelightmaps_borderpixels);
170 Cvar_RegisterVariable(&mod_generatelightmaps_texturesize);
172 Cvar_RegisterVariable(&mod_generatelightmaps_lightmapsamples);
173 Cvar_RegisterVariable(&mod_generatelightmaps_vertexsamples);
174 Cvar_RegisterVariable(&mod_generatelightmaps_gridsamples);
175 Cvar_RegisterVariable(&mod_generatelightmaps_lightmapradius);
176 Cvar_RegisterVariable(&mod_generatelightmaps_vertexradius);
177 Cvar_RegisterVariable(&mod_generatelightmaps_gridradius);
179 Cmd_AddCommand ("modellist", Mod_Print, "prints a list of loaded models");
180 Cmd_AddCommand ("modelprecache", Mod_Precache, "load a model");
181 Cmd_AddCommand ("modeldecompile", Mod_Decompile_f, "exports a model in several formats for editing purposes");
182 Cmd_AddCommand ("mod_generatelightmaps", Mod_GenerateLightmaps_f, "rebuilds lighting on current worldmodel");
185 void Mod_RenderInit(void)
187 R_RegisterModule("Models", mod_start, mod_shutdown, mod_newmap, NULL, NULL);
190 void Mod_UnloadModel (dp_model_t *mod)
192 char name[MAX_QPATH];
194 dp_model_t *parentmodel;
196 if (developer_loading.integer)
197 Con_Printf("unloading model %s\n", mod->name);
199 strlcpy(name, mod->name, sizeof(name));
200 parentmodel = mod->brush.parentmodel;
204 if (mod->surfmesh.data_element3i_indexbuffer)
205 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
206 mod->surfmesh.data_element3i_indexbuffer = NULL;
207 if (mod->surfmesh.data_element3s_indexbuffer)
208 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
209 mod->surfmesh.data_element3s_indexbuffer = NULL;
210 if (mod->surfmesh.vbo_vertexbuffer)
211 R_Mesh_DestroyMeshBuffer(mod->surfmesh.vbo_vertexbuffer);
212 mod->surfmesh.vbo_vertexbuffer = NULL;
214 // free textures/memory attached to the model
215 R_FreeTexturePool(&mod->texturepool);
216 Mem_FreePool(&mod->mempool);
217 // clear the struct to make it available
218 memset(mod, 0, sizeof(dp_model_t));
219 // restore the fields we want to preserve
220 strlcpy(mod->name, name, sizeof(mod->name));
221 mod->brush.parentmodel = parentmodel;
226 static void R_Model_Null_Draw(entity_render_t *ent)
232 typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass);
234 static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
249 // REQUIRED: fetch start
250 COM_ParseToken_Simple(&bufptr, true, false, true);
252 break; // end of file
253 if (!strcmp(com_token, "\n"))
254 continue; // empty line
255 start = atoi(com_token);
257 // REQUIRED: fetch length
258 COM_ParseToken_Simple(&bufptr, true, false, true);
259 if (!bufptr || !strcmp(com_token, "\n"))
261 Con_Printf("framegroups file: missing number of frames\n");
264 len = atoi(com_token);
266 // OPTIONAL args start
267 COM_ParseToken_Simple(&bufptr, true, false, true);
269 // OPTIONAL: fetch fps
271 if (bufptr && strcmp(com_token, "\n"))
273 fps = atof(com_token);
274 COM_ParseToken_Simple(&bufptr, true, false, true);
277 // OPTIONAL: fetch loopflag
279 if (bufptr && strcmp(com_token, "\n"))
281 loop = (atoi(com_token) != 0);
282 COM_ParseToken_Simple(&bufptr, true, false, true);
285 // OPTIONAL: fetch name
287 if (bufptr && strcmp(com_token, "\n"))
289 strlcpy(name, com_token, sizeof(name));
290 COM_ParseToken_Simple(&bufptr, true, false, true);
293 // OPTIONAL: remaining unsupported tokens (eat them)
294 while (bufptr && strcmp(com_token, "\n"))
295 COM_ParseToken_Simple(&bufptr, true, false, true);
297 //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name);
300 cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
307 static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qboolean loop, const char *name, void *pass)
309 dp_model_t *mod = (dp_model_t *) pass;
310 animscene_t *anim = &mod->animscenes[i];
312 strlcpy(anim->name, name, sizeof(anim[i].name));
314 dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
315 anim->firstframe = bound(0, start, mod->num_poses - 1);
316 anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
317 anim->framerate = max(1, fps);
319 //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
322 static void Mod_FrameGroupify(dp_model_t *mod, const char *buf)
327 cnt = Mod_FrameGroupify_ParseGroups(buf, NULL, NULL);
330 Con_Printf("no scene found in framegroups file, aborting\n");
333 mod->numframes = cnt;
336 // (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay)
337 mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes);
340 Mod_FrameGroupify_ParseGroups(buf, Mod_FrameGroupify_ParseGroups_Store, mod);
343 static void Mod_FindPotentialDeforms(dp_model_t *mod)
347 mod->wantnormals = false;
348 mod->wanttangents = false;
349 for (i = 0;i < mod->num_textures;i++)
351 texture = mod->data_textures + i;
352 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
353 mod->wantnormals = true;
354 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
355 mod->wantnormals = true;
356 for (j = 0;j < Q3MAXDEFORMS;j++)
358 if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
360 mod->wanttangents = true;
361 mod->wantnormals = true;
364 if (texture->deforms[j].deform != Q3DEFORM_NONE)
365 mod->wantnormals = true;
377 dp_model_t *Mod_LoadModel(dp_model_t *mod, qboolean crash, qboolean checkdisk)
382 fs_offset_t filesize = 0;
387 if (mod->name[0] == '*') // submodel
390 if (!strcmp(mod->name, "null"))
395 if (mod->loaded || mod->mempool)
396 Mod_UnloadModel(mod);
398 if (developer_loading.integer)
399 Con_Printf("loading model %s\n", mod->name);
402 mod->crc = (unsigned int)-1;
405 VectorClear(mod->normalmins);
406 VectorClear(mod->normalmaxs);
407 VectorClear(mod->yawmins);
408 VectorClear(mod->yawmaxs);
409 VectorClear(mod->rotatedmins);
410 VectorClear(mod->rotatedmaxs);
412 mod->modeldatatypestring = "null";
413 mod->type = mod_null;
414 mod->Draw = R_Model_Null_Draw;
418 // no fatal errors occurred, so this model is ready to use.
427 // even if the model is loaded it still may need reloading...
429 // if it is not loaded or checkdisk is true we need to calculate the crc
430 if (!mod->loaded || checkdisk)
432 if (checkdisk && mod->loaded)
433 Con_DPrintf("checking model %s\n", mod->name);
434 buf = FS_LoadFile (mod->name, tempmempool, false, &filesize);
437 crc = CRC_Block((unsigned char *)buf, filesize);
438 // we need to reload the model if the crc does not match
444 // if the model is already loaded and checks passed, just return
452 if (developer_loading.integer)
453 Con_Printf("loading model %s\n", mod->name);
455 SCR_PushLoadingScreen(true, mod->name, 1);
457 // LordHavoc: unload the existing model in this slot (if there is one)
458 if (mod->loaded || mod->mempool)
459 Mod_UnloadModel(mod);
464 // errors can prevent the corresponding mod->loaded = true;
467 // default lightmap scale
468 mod->lightmapscale = 1;
470 // default model radius and bounding box (mainly for missing models)
472 VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius);
473 VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius);
474 VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius);
475 VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius);
476 VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
477 VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
481 // load q3 shaders for the first time, or after a level change
487 char *bufend = (char *)buf + filesize;
489 // all models use memory, so allocate a memory pool
490 mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
492 num = LittleLong(*((int *)buf));
493 // call the apropriate loader
495 if (!strcasecmp(FS_FileExtension(mod->name), "obj")) Mod_OBJ_Load(mod, buf, bufend);
496 else if (!memcmp(buf, "IDPO", 4)) Mod_IDP0_Load(mod, buf, bufend);
497 else if (!memcmp(buf, "IDP2", 4)) Mod_IDP2_Load(mod, buf, bufend);
498 else if (!memcmp(buf, "IDP3", 4)) Mod_IDP3_Load(mod, buf, bufend);
499 else if (!memcmp(buf, "IDSP", 4)) Mod_IDSP_Load(mod, buf, bufend);
500 else if (!memcmp(buf, "IDS2", 4)) Mod_IDS2_Load(mod, buf, bufend);
501 else if (!memcmp(buf, "IBSP", 4)) Mod_IBSP_Load(mod, buf, bufend);
502 else if (!memcmp(buf, "ZYMOTICMODEL", 12)) Mod_ZYMOTICMODEL_Load(mod, buf, bufend);
503 else if (!memcmp(buf, "DARKPLACESMODEL", 16)) Mod_DARKPLACESMODEL_Load(mod, buf, bufend);
504 else if (!memcmp(buf, "ACTRHEAD", 8)) Mod_PSKMODEL_Load(mod, buf, bufend);
505 else if (!memcmp(buf, "INTERQUAKEMODEL", 16)) Mod_INTERQUAKEMODEL_Load(mod, buf, bufend);
506 else if (strlen(mod->name) >= 4 && !strcmp(mod->name + strlen(mod->name) - 4, ".map")) Mod_MAP_Load(mod, buf, bufend);
507 else if (num == BSPVERSION || num == 30 || !memcmp(buf, "BSP2", 4) || !memcmp(buf, "2PSB", 4)) Mod_Q1BSP_Load(mod, buf, bufend);
508 else Con_Printf("Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
511 Mod_FindPotentialDeforms(mod);
513 buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
516 Mod_FrameGroupify(mod, (const char *)buf);
524 // LordHavoc: Sys_Error was *ANNOYING*
525 Con_Printf ("Mod_LoadModel: %s not found\n", mod->name);
528 // no fatal errors occurred, so this model is ready to use.
531 SCR_PopLoadingScreen(false);
536 void Mod_ClearUsed(void)
539 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
541 for (i = 0;i < nummodels;i++)
542 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
546 void Mod_PurgeUnused(void)
549 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
551 for (i = 0;i < nummodels;i++)
553 if ((mod = (dp_model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
555 Mod_UnloadModel(mod);
556 Mem_ExpandableArray_FreeRecord(&models, mod);
567 dp_model_t *Mod_FindName(const char *name, const char *parentname)
576 // if we're not dedicatd, the renderer calls will crash without video
579 nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
582 Host_Error ("Mod_ForName: empty name");
584 // search the currently loaded models
585 for (i = 0;i < nummodels;i++)
587 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))))
594 // no match found, create a new one
595 mod = (dp_model_t *) Mem_ExpandableArray_AllocRecord(&models);
596 strlcpy(mod->name, name, sizeof(mod->name));
598 mod->brush.parentmodel = Mod_FindName(parentname, NULL);
600 mod->brush.parentmodel = NULL;
610 Loads in a model for the given name
613 dp_model_t *Mod_ForName(const char *name, qboolean crash, qboolean checkdisk, const char *parentname)
616 model = Mod_FindName(name, parentname);
617 if (!model->loaded || checkdisk)
618 Mod_LoadModel(model, crash, checkdisk);
626 Reloads all models if they have changed
629 void Mod_Reload(void)
632 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
635 SCR_PushLoadingScreen(false, "Reloading models", 1.0);
637 for (i = 0;i < nummodels;i++)
638 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
640 for (i = 0;i < nummodels;i++)
641 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
643 SCR_PushLoadingScreen(true, mod->name, 1.0 / count);
644 Mod_LoadModel(mod, true, true);
645 SCR_PopLoadingScreen(false);
647 SCR_PopLoadingScreen(false);
650 unsigned char *mod_base;
653 //=============================================================================
660 static void Mod_Print(void)
663 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
666 Con_Print("Loaded models:\n");
667 for (i = 0;i < nummodels;i++)
669 if ((mod = (dp_model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
671 if (mod->brush.numsubmodels)
672 Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
674 Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name);
684 static void Mod_Precache(void)
687 Mod_ForName(Cmd_Argv(1), false, true, Cmd_Argv(1)[0] == '*' ? cl.model_name[1] : NULL);
689 Con_Print("usage: modelprecache <filename>\n");
692 int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
696 used = (unsigned char *)Mem_Alloc(tempmempool, numvertices);
697 memset(used, 0, numvertices);
698 for (i = 0;i < numelements;i++)
699 used[elements[i]] = 1;
700 for (i = 0, count = 0;i < numvertices;i++)
701 remapvertices[i] = used[i] ? count++ : -1;
707 // fast way, using an edge hash
708 #define TRIANGLEEDGEHASH 8192
709 void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles)
711 int i, j, p, e1, e2, *n, hashindex, count, match;
713 typedef struct edgehashentry_s
715 struct edgehashentry_s *next;
720 static edgehashentry_t **edgehash;
721 edgehashentry_t *edgehashentries, *hash;
724 edgehash = (edgehashentry_t **)Mem_Alloc(tempmempool, TRIANGLEEDGEHASH * sizeof(*edgehash));
725 // if there are too many triangles for the stack array, allocate larger buffer
726 edgehashentries = (edgehashentry_t *)Mem_Alloc(tempmempool, numtriangles * 3 * sizeof(edgehashentry_t));
727 // find neighboring triangles
728 for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
730 for (j = 0, p = 2;j < 3;p = j, j++)
734 // this hash index works for both forward and backward edges
735 hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH;
736 hash = edgehashentries + i * 3 + j;
737 hash->next = edgehash[hashindex];
738 edgehash[hashindex] = hash;
740 hash->element[0] = e1;
741 hash->element[1] = e2;
744 for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
746 for (j = 0, p = 2;j < 3;p = j, j++)
750 // this hash index works for both forward and backward edges
751 hashindex = (unsigned int)(e1 + e2) % TRIANGLEEDGEHASH;
754 for (hash = edgehash[hashindex];hash;hash = hash->next)
756 if (hash->element[0] == e2 && hash->element[1] == e1)
758 if (hash->triangle != i)
759 match = hash->triangle;
762 else if ((hash->element[0] == e1 && hash->element[1] == e2))
765 // detect edges shared by three triangles and make them seams
771 // also send a keepalive here (this can take a while too!)
772 CL_KeepaliveMessage(false);
774 // free the allocated buffer
775 Mem_Free(edgehashentries);
779 // very slow but simple way
780 static int Mod_FindTriangleWithEdge(const int *elements, int numtriangles, int start, int end, int ignore)
785 for (i = 0;i < numtriangles;i++, elements += 3)
787 if ((elements[0] == start && elements[1] == end)
788 || (elements[1] == start && elements[2] == end)
789 || (elements[2] == start && elements[0] == end))
795 else if ((elements[1] == start && elements[0] == end)
796 || (elements[2] == start && elements[1] == end)
797 || (elements[0] == start && elements[2] == end))
800 // detect edges shared by three triangles and make them seams
806 void Mod_BuildTriangleNeighbors(int *neighbors, const int *elements, int numtriangles)
810 for (i = 0, e = elements, n = neighbors;i < numtriangles;i++, e += 3, n += 3)
812 n[0] = Mod_FindTriangleWithEdge(elements, numtriangles, e[1], e[0], i);
813 n[1] = Mod_FindTriangleWithEdge(elements, numtriangles, e[2], e[1], i);
814 n[2] = Mod_FindTriangleWithEdge(elements, numtriangles, e[0], e[2], i);
819 void Mod_ValidateElements(int *elements, int numtriangles, int firstvertex, int numverts, const char *filename, int fileline)
821 int i, warned = false, endvertex = firstvertex + numverts;
822 for (i = 0;i < numtriangles * 3;i++)
824 if (elements[i] < firstvertex || elements[i] >= endvertex)
829 Con_Printf("Mod_ValidateElements: out of bounds elements detected at %s:%d\n", filename, fileline);
831 elements[i] = firstvertex;
836 // warning: this is an expensive function!
837 void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qboolean areaweighting)
844 memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
845 // process each vertex of each triangle and accumulate the results
846 // use area-averaging, to make triangles with a big area have a bigger
847 // weighting on the vertex normal than triangles with a small area
848 // to do so, just add the 'normals' together (the bigger the area
849 // the greater the length of the normal is
851 for (i = 0; i < numtriangles; i++, element += 3)
854 vertex3f + element[0] * 3,
855 vertex3f + element[1] * 3,
856 vertex3f + element[2] * 3,
861 VectorNormalize(areaNormal);
863 for (j = 0;j < 3;j++)
865 vectorNormal = normal3f + element[j] * 3;
866 vectorNormal[0] += areaNormal[0];
867 vectorNormal[1] += areaNormal[1];
868 vectorNormal[2] += areaNormal[2];
871 // and just normalize the accumulated vertex normal in the end
872 vectorNormal = normal3f + 3 * firstvertex;
873 for (i = 0; i < numvertices; i++, vectorNormal += 3)
874 VectorNormalize(vectorNormal);
878 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)
880 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
881 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
882 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
884 // 6 multiply, 9 subtract
885 VectorSubtract(v1, v0, v10);
886 VectorSubtract(v2, v0, v20);
887 normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1];
888 normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2];
889 normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0];
890 // 12 multiply, 10 subtract
891 tc10[1] = tc1[1] - tc0[1];
892 tc20[1] = tc2[1] - tc0[1];
893 svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
894 svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
895 svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
896 tc10[0] = tc1[0] - tc0[0];
897 tc20[0] = tc2[0] - tc0[0];
898 tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
899 tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
900 tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
901 // 12 multiply, 4 add, 6 subtract
902 f = DotProduct(svector3f, normal3f);
903 svector3f[0] -= f * normal3f[0];
904 svector3f[1] -= f * normal3f[1];
905 svector3f[2] -= f * normal3f[2];
906 f = DotProduct(tvector3f, normal3f);
907 tvector3f[0] -= f * normal3f[0];
908 tvector3f[1] -= f * normal3f[1];
909 tvector3f[2] -= f * normal3f[2];
910 // if texture is mapped the wrong way (counterclockwise), the tangents
911 // have to be flipped, this is detected by calculating a normal from the
912 // two tangents, and seeing if it is opposite the surface normal
913 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
914 CrossProduct(tvector3f, svector3f, tangentcross);
915 if (DotProduct(tangentcross, normal3f) < 0)
917 VectorNegate(svector3f, svector3f);
918 VectorNegate(tvector3f, tvector3f);
923 // warning: this is a very expensive function!
924 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)
927 float sdir[3], tdir[3], normal[3], *svec, *tvec;
928 const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
929 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
932 memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
933 memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
934 // process each vertex of each triangle and accumulate the results
935 for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
937 v0 = vertex3f + e[0] * 3;
938 v1 = vertex3f + e[1] * 3;
939 v2 = vertex3f + e[2] * 3;
940 tc0 = texcoord2f + e[0] * 2;
941 tc1 = texcoord2f + e[1] * 2;
942 tc2 = texcoord2f + e[2] * 2;
944 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
945 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
947 // calculate the edge directions and surface normal
948 // 6 multiply, 9 subtract
949 VectorSubtract(v1, v0, v10);
950 VectorSubtract(v2, v0, v20);
951 normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
952 normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
953 normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
955 // calculate the tangents
956 // 12 multiply, 10 subtract
957 tc10[1] = tc1[1] - tc0[1];
958 tc20[1] = tc2[1] - tc0[1];
959 sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
960 sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
961 sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
962 tc10[0] = tc1[0] - tc0[0];
963 tc20[0] = tc2[0] - tc0[0];
964 tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
965 tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
966 tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
968 // if texture is mapped the wrong way (counterclockwise), the tangents
969 // have to be flipped, this is detected by calculating a normal from the
970 // two tangents, and seeing if it is opposite the surface normal
971 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
972 CrossProduct(tdir, sdir, tangentcross);
973 if (DotProduct(tangentcross, normal) < 0)
975 VectorNegate(sdir, sdir);
976 VectorNegate(tdir, tdir);
981 VectorNormalize(sdir);
982 VectorNormalize(tdir);
984 for (i = 0;i < 3;i++)
986 VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
987 VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
990 // make the tangents completely perpendicular to the surface normal, and
991 // then normalize them
992 // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
993 for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
995 f = -DotProduct(svec, n);
996 VectorMA(svec, f, n, svec);
997 VectorNormalize(svec);
998 f = -DotProduct(tvec, n);
999 VectorMA(tvec, f, n, tvec);
1000 VectorNormalize(tvec);
1004 void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qboolean lightmapoffsets, qboolean vertexcolors, qboolean neighbors)
1006 unsigned char *data;
1007 data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * (3 + (neighbors ? 3 : 0)) * sizeof(int) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0));
1008 loadmodel->surfmesh.num_vertices = numvertices;
1009 loadmodel->surfmesh.num_triangles = numtriangles;
1010 if (loadmodel->surfmesh.num_vertices)
1012 loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1013 loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1014 loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1015 loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
1016 loadmodel->surfmesh.data_texcoordtexture2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
1017 loadmodel->surfmesh.data_texcoordlightmap2f = (float *)data, data += sizeof(float[2]) * loadmodel->surfmesh.num_vertices;
1019 loadmodel->surfmesh.data_lightmapcolor4f = (float *)data, data += sizeof(float[4]) * loadmodel->surfmesh.num_vertices;
1020 if (lightmapoffsets)
1021 loadmodel->surfmesh.data_lightmapoffsets = (int *)data, data += sizeof(int) * loadmodel->surfmesh.num_vertices;
1023 if (loadmodel->surfmesh.num_triangles)
1025 loadmodel->surfmesh.data_element3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
1027 loadmodel->surfmesh.data_neighbor3i = (int *)data, data += sizeof(int[3]) * loadmodel->surfmesh.num_triangles;
1028 if (loadmodel->surfmesh.num_vertices <= 65536)
1029 loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles;
1033 shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
1035 shadowmesh_t *newmesh;
1036 unsigned char *data;
1038 size = sizeof(shadowmesh_t);
1039 size += maxverts * sizeof(float[3]);
1041 size += maxverts * sizeof(float[11]);
1042 size += maxtriangles * sizeof(int[3]);
1043 if (maxverts <= 65536)
1044 size += maxtriangles * sizeof(unsigned short[3]);
1046 size += maxtriangles * sizeof(int[3]);
1048 size += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *) + maxverts * sizeof(shadowmeshvertexhash_t);
1049 data = (unsigned char *)Mem_Alloc(mempool, size);
1050 newmesh = (shadowmesh_t *)data;data += sizeof(*newmesh);
1051 newmesh->map_diffuse = map_diffuse;
1052 newmesh->map_specular = map_specular;
1053 newmesh->map_normal = map_normal;
1054 newmesh->maxverts = maxverts;
1055 newmesh->maxtriangles = maxtriangles;
1056 newmesh->numverts = 0;
1057 newmesh->numtriangles = 0;
1058 memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
1059 memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
1061 newmesh->vertex3f = (float *)data;data += maxverts * sizeof(float[3]);
1064 newmesh->svector3f = (float *)data;data += maxverts * sizeof(float[3]);
1065 newmesh->tvector3f = (float *)data;data += maxverts * sizeof(float[3]);
1066 newmesh->normal3f = (float *)data;data += maxverts * sizeof(float[3]);
1067 newmesh->texcoord2f = (float *)data;data += maxverts * sizeof(float[2]);
1069 newmesh->element3i = (int *)data;data += maxtriangles * sizeof(int[3]);
1072 newmesh->neighbor3i = (int *)data;data += maxtriangles * sizeof(int[3]);
1076 newmesh->vertexhashtable = (shadowmeshvertexhash_t **)data;data += SHADOWMESHVERTEXHASH * sizeof(shadowmeshvertexhash_t *);
1077 newmesh->vertexhashentries = (shadowmeshvertexhash_t *)data;data += maxverts * sizeof(shadowmeshvertexhash_t);
1079 if (maxverts <= 65536)
1080 newmesh->element3s = (unsigned short *)data;data += maxtriangles * sizeof(unsigned short[3]);
1084 shadowmesh_t *Mod_ShadowMesh_ReAlloc(mempool_t *mempool, shadowmesh_t *oldmesh, int light, int neighbors)
1086 shadowmesh_t *newmesh;
1087 newmesh = Mod_ShadowMesh_Alloc(mempool, oldmesh->numverts, oldmesh->numtriangles, oldmesh->map_diffuse, oldmesh->map_specular, oldmesh->map_normal, light, neighbors, false);
1088 newmesh->numverts = oldmesh->numverts;
1089 newmesh->numtriangles = oldmesh->numtriangles;
1090 memcpy(newmesh->sideoffsets, oldmesh->sideoffsets, sizeof(oldmesh->sideoffsets));
1091 memcpy(newmesh->sidetotals, oldmesh->sidetotals, sizeof(oldmesh->sidetotals));
1093 memcpy(newmesh->vertex3f, oldmesh->vertex3f, oldmesh->numverts * sizeof(float[3]));
1094 if (newmesh->svector3f && oldmesh->svector3f)
1096 memcpy(newmesh->svector3f, oldmesh->svector3f, oldmesh->numverts * sizeof(float[3]));
1097 memcpy(newmesh->tvector3f, oldmesh->tvector3f, oldmesh->numverts * sizeof(float[3]));
1098 memcpy(newmesh->normal3f, oldmesh->normal3f, oldmesh->numverts * sizeof(float[3]));
1099 memcpy(newmesh->texcoord2f, oldmesh->texcoord2f, oldmesh->numverts * sizeof(float[2]));
1101 memcpy(newmesh->element3i, oldmesh->element3i, oldmesh->numtriangles * sizeof(int[3]));
1102 if (newmesh->neighbor3i && oldmesh->neighbor3i)
1103 memcpy(newmesh->neighbor3i, oldmesh->neighbor3i, oldmesh->numtriangles * sizeof(int[3]));
1107 int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, float *vertex14f)
1109 int hashindex, vnum;
1110 shadowmeshvertexhash_t *hash;
1111 // this uses prime numbers intentionally
1112 hashindex = (unsigned int) (vertex14f[0] * 2003 + vertex14f[1] * 4001 + vertex14f[2] * 7919) % SHADOWMESHVERTEXHASH;
1113 for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
1115 vnum = (hash - mesh->vertexhashentries);
1116 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]))
1117 && (mesh->svector3f == NULL || (mesh->svector3f[vnum * 3 + 0] == vertex14f[3] && mesh->svector3f[vnum * 3 + 1] == vertex14f[4] && mesh->svector3f[vnum * 3 + 2] == vertex14f[5]))
1118 && (mesh->tvector3f == NULL || (mesh->tvector3f[vnum * 3 + 0] == vertex14f[6] && mesh->tvector3f[vnum * 3 + 1] == vertex14f[7] && mesh->tvector3f[vnum * 3 + 2] == vertex14f[8]))
1119 && (mesh->normal3f == NULL || (mesh->normal3f[vnum * 3 + 0] == vertex14f[9] && mesh->normal3f[vnum * 3 + 1] == vertex14f[10] && mesh->normal3f[vnum * 3 + 2] == vertex14f[11]))
1120 && (mesh->texcoord2f == NULL || (mesh->texcoord2f[vnum * 2 + 0] == vertex14f[12] && mesh->texcoord2f[vnum * 2 + 1] == vertex14f[13])))
1121 return hash - mesh->vertexhashentries;
1123 vnum = mesh->numverts++;
1124 hash = mesh->vertexhashentries + vnum;
1125 hash->next = mesh->vertexhashtable[hashindex];
1126 mesh->vertexhashtable[hashindex] = hash;
1127 if (mesh->vertex3f) {mesh->vertex3f[vnum * 3 + 0] = vertex14f[0];mesh->vertex3f[vnum * 3 + 1] = vertex14f[1];mesh->vertex3f[vnum * 3 + 2] = vertex14f[2];}
1128 if (mesh->svector3f) {mesh->svector3f[vnum * 3 + 0] = vertex14f[3];mesh->svector3f[vnum * 3 + 1] = vertex14f[4];mesh->svector3f[vnum * 3 + 2] = vertex14f[5];}
1129 if (mesh->tvector3f) {mesh->tvector3f[vnum * 3 + 0] = vertex14f[6];mesh->tvector3f[vnum * 3 + 1] = vertex14f[7];mesh->tvector3f[vnum * 3 + 2] = vertex14f[8];}
1130 if (mesh->normal3f) {mesh->normal3f[vnum * 3 + 0] = vertex14f[9];mesh->normal3f[vnum * 3 + 1] = vertex14f[10];mesh->normal3f[vnum * 3 + 2] = vertex14f[11];}
1131 if (mesh->texcoord2f) {mesh->texcoord2f[vnum * 2 + 0] = vertex14f[12];mesh->texcoord2f[vnum * 2 + 1] = vertex14f[13];}
1135 void Mod_ShadowMesh_AddTriangle(mempool_t *mempool, shadowmesh_t *mesh, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, float *vertex14f)
1137 if (mesh->numtriangles == 0)
1139 // set the properties on this empty mesh to be more favorable...
1140 // (note: this case only occurs for the first triangle added to a new mesh chain)
1141 mesh->map_diffuse = map_diffuse;
1142 mesh->map_specular = map_specular;
1143 mesh->map_normal = map_normal;
1145 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)
1147 if (mesh->next == NULL)
1148 mesh->next = Mod_ShadowMesh_Alloc(mempool, max(mesh->maxverts, 300), max(mesh->maxtriangles, 100), map_diffuse, map_specular, map_normal, mesh->svector3f != NULL, mesh->neighbor3i != NULL, true);
1151 mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 0);
1152 mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 1);
1153 mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex14f + 14 * 2);
1154 mesh->numtriangles++;
1157 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)
1160 float vbuf[3*14], *v;
1161 memset(vbuf, 0, sizeof(vbuf));
1162 for (i = 0;i < numtris;i++)
1164 for (j = 0, v = vbuf;j < 3;j++, v += 14)
1169 v[0] = vertex3f[e * 3 + 0];
1170 v[1] = vertex3f[e * 3 + 1];
1171 v[2] = vertex3f[e * 3 + 2];
1175 v[3] = svector3f[e * 3 + 0];
1176 v[4] = svector3f[e * 3 + 1];
1177 v[5] = svector3f[e * 3 + 2];
1181 v[6] = tvector3f[e * 3 + 0];
1182 v[7] = tvector3f[e * 3 + 1];
1183 v[8] = tvector3f[e * 3 + 2];
1187 v[9] = normal3f[e * 3 + 0];
1188 v[10] = normal3f[e * 3 + 1];
1189 v[11] = normal3f[e * 3 + 2];
1193 v[12] = texcoord2f[e * 2 + 0];
1194 v[13] = texcoord2f[e * 2 + 1];
1197 Mod_ShadowMesh_AddTriangle(mempool, mesh, map_diffuse, map_specular, map_normal, vbuf);
1200 // the triangle calculation can take a while, so let's do a keepalive here
1201 CL_KeepaliveMessage(false);
1204 shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles, rtexture_t *map_diffuse, rtexture_t *map_specular, rtexture_t *map_normal, int light, int neighbors, int expandable)
1206 // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
1207 CL_KeepaliveMessage(false);
1209 return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles, map_diffuse, map_specular, map_normal, light, neighbors, expandable);
1212 static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh, mempool_t *mempool)
1214 if (!mesh->numverts)
1217 // build r_vertexmesh_t array
1218 // (compressed interleaved array for D3D)
1219 if (!mesh->vertexmesh && mesh->texcoord2f && vid.useinterleavedarrays)
1222 int numvertices = mesh->numverts;
1223 r_vertexmesh_t *vertexmesh;
1224 mesh->vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(mempool, numvertices * sizeof(*mesh->vertexmesh));
1225 for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
1227 VectorCopy(mesh->vertex3f + 3*vertexindex, vertexmesh->vertex3f);
1228 VectorScale(mesh->svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
1229 VectorScale(mesh->tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
1230 VectorScale(mesh->normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
1231 Vector2Copy(mesh->texcoord2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
1235 // upload short indices as a buffer
1236 if (mesh->element3s && !mesh->element3s_indexbuffer)
1237 mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), loadmodel->name, true, false, false, true);
1239 // upload int indices as a buffer
1240 if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
1241 mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), loadmodel->name, true, false, false, false);
1243 // vertex buffer is several arrays and we put them in the same buffer
1245 // is this wise? the texcoordtexture2f array is used with dynamic
1246 // vertex/svector/tvector/normal when rendering animated models, on the
1247 // other hand animated models don't use a lot of vertices anyway...
1248 if (!mesh->vbo_vertexbuffer && !vid.useinterleavedarrays)
1253 mesh->vbooffset_vertexmesh = size;if (mesh->vertexmesh ) size += mesh->numverts * sizeof(r_vertexmesh_t);
1254 mesh->vbooffset_vertex3f = size;if (mesh->vertex3f ) size += mesh->numverts * sizeof(float[3]);
1255 mesh->vbooffset_svector3f = size;if (mesh->svector3f ) size += mesh->numverts * sizeof(float[3]);
1256 mesh->vbooffset_tvector3f = size;if (mesh->tvector3f ) size += mesh->numverts * sizeof(float[3]);
1257 mesh->vbooffset_normal3f = size;if (mesh->normal3f ) size += mesh->numverts * sizeof(float[3]);
1258 mesh->vbooffset_texcoord2f = size;if (mesh->texcoord2f ) size += mesh->numverts * sizeof(float[2]);
1259 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
1260 if (mesh->vertexmesh ) memcpy(mem + mesh->vbooffset_vertexmesh , mesh->vertexmesh , mesh->numverts * sizeof(r_vertexmesh_t));
1261 if (mesh->vertex3f ) memcpy(mem + mesh->vbooffset_vertex3f , mesh->vertex3f , mesh->numverts * sizeof(float[3]));
1262 if (mesh->svector3f ) memcpy(mem + mesh->vbooffset_svector3f , mesh->svector3f , mesh->numverts * sizeof(float[3]));
1263 if (mesh->tvector3f ) memcpy(mem + mesh->vbooffset_tvector3f , mesh->tvector3f , mesh->numverts * sizeof(float[3]));
1264 if (mesh->normal3f ) memcpy(mem + mesh->vbooffset_normal3f , mesh->normal3f , mesh->numverts * sizeof(float[3]));
1265 if (mesh->texcoord2f ) memcpy(mem + mesh->vbooffset_texcoord2f , mesh->texcoord2f , mesh->numverts * sizeof(float[2]));
1266 mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, "shadowmesh", false, false, false, false);
1271 shadowmesh_t *Mod_ShadowMesh_Finish(mempool_t *mempool, shadowmesh_t *firstmesh, qboolean light, qboolean neighbors, qboolean createvbo)
1273 shadowmesh_t *mesh, *newmesh, *nextmesh;
1274 // reallocate meshs to conserve space
1275 for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
1277 nextmesh = mesh->next;
1278 if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
1280 newmesh = Mod_ShadowMesh_ReAlloc(mempool, mesh, light, neighbors);
1281 newmesh->next = firstmesh;
1282 firstmesh = newmesh;
1283 if (newmesh->element3s)
1286 for (i = 0;i < newmesh->numtriangles*3;i++)
1287 newmesh->element3s[i] = newmesh->element3i[i];
1290 Mod_ShadowMesh_CreateVBOs(newmesh, mempool);
1295 // this can take a while, so let's do a keepalive here
1296 CL_KeepaliveMessage(false);
1301 void Mod_ShadowMesh_CalcBBox(shadowmesh_t *firstmesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
1305 vec3_t nmins, nmaxs, ncenter, temp;
1306 float nradius2, dist2, *v;
1310 for (mesh = firstmesh;mesh;mesh = mesh->next)
1312 if (mesh == firstmesh)
1314 VectorCopy(mesh->vertex3f, nmins);
1315 VectorCopy(mesh->vertex3f, nmaxs);
1317 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1319 if (nmins[0] > v[0]) nmins[0] = v[0];if (nmaxs[0] < v[0]) nmaxs[0] = v[0];
1320 if (nmins[1] > v[1]) nmins[1] = v[1];if (nmaxs[1] < v[1]) nmaxs[1] = v[1];
1321 if (nmins[2] > v[2]) nmins[2] = v[2];if (nmaxs[2] < v[2]) nmaxs[2] = v[2];
1324 // calculate center and radius
1325 ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
1326 ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
1327 ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
1329 for (mesh = firstmesh;mesh;mesh = mesh->next)
1331 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1333 VectorSubtract(v, ncenter, temp);
1334 dist2 = DotProduct(temp, temp);
1335 if (nradius2 < dist2)
1341 VectorCopy(nmins, mins);
1343 VectorCopy(nmaxs, maxs);
1345 VectorCopy(ncenter, center);
1347 *radius = sqrt(nradius2);
1350 void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
1352 shadowmesh_t *nextmesh;
1353 for (;mesh;mesh = nextmesh)
1355 if (mesh->element3i_indexbuffer)
1356 R_Mesh_DestroyMeshBuffer(mesh->element3i_indexbuffer);
1357 if (mesh->element3s_indexbuffer)
1358 R_Mesh_DestroyMeshBuffer(mesh->element3s_indexbuffer);
1359 if (mesh->vbo_vertexbuffer)
1360 R_Mesh_DestroyMeshBuffer(mesh->vbo_vertexbuffer);
1361 nextmesh = mesh->next;
1366 void Mod_CreateCollisionMesh(dp_model_t *mod)
1368 int k, numcollisionmeshtriangles;
1369 qboolean usesinglecollisionmesh = false;
1370 const msurface_t *surface = NULL;
1372 mempool_t *mempool = mod->mempool;
1373 if (!mempool && mod->brush.parentmodel)
1374 mempool = mod->brush.parentmodel->mempool;
1375 // make a single combined collision mesh for physics engine use
1376 // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
1377 numcollisionmeshtriangles = 0;
1378 for (k = 0;k < mod->nummodelsurfaces;k++)
1380 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1381 if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
1383 usesinglecollisionmesh = true;
1384 numcollisionmeshtriangles = surface->num_triangles;
1387 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1389 numcollisionmeshtriangles += surface->num_triangles;
1391 mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles, NULL, NULL, NULL, false, false, true);
1392 if (usesinglecollisionmesh)
1393 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));
1396 for (k = 0;k < mod->nummodelsurfaces;k++)
1398 surface = mod->data_surfaces + mod->firstmodelsurface + k;
1399 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1401 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));
1404 mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mempool, mod->brush.collisionmesh, false, false, false);
1408 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)
1413 if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1414 v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1417 Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1418 Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1419 texcoord2f[0] = tc[0];
1420 texcoord2f[1] = tc[1];
1423 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)
1425 float vup[3], vdown[3], vleft[3], vright[3];
1426 float tcup[3], tcdown[3], tcleft[3], tcright[3];
1427 float sv[3], tv[3], nl[3];
1428 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1429 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1430 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1431 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1432 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1433 Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1434 Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1435 VectorAdd(svector3f, sv, svector3f);
1436 VectorAdd(tvector3f, tv, tvector3f);
1437 VectorAdd(normal3f, nl, normal3f);
1438 Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1439 VectorAdd(svector3f, sv, svector3f);
1440 VectorAdd(tvector3f, tv, tvector3f);
1441 VectorAdd(normal3f, nl, normal3f);
1442 Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1443 VectorAdd(svector3f, sv, svector3f);
1444 VectorAdd(tvector3f, tv, tvector3f);
1445 VectorAdd(normal3f, nl, normal3f);
1448 static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, int *neighbor3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1450 int x, y, ix, iy, *e;
1452 for (y = 0;y < height;y++)
1454 for (x = 0;x < width;x++)
1456 e[0] = (y + 1) * (width + 1) + (x + 0);
1457 e[1] = (y + 0) * (width + 1) + (x + 0);
1458 e[2] = (y + 1) * (width + 1) + (x + 1);
1459 e[3] = (y + 0) * (width + 1) + (x + 0);
1460 e[4] = (y + 0) * (width + 1) + (x + 1);
1461 e[5] = (y + 1) * (width + 1) + (x + 1);
1465 Mod_BuildTriangleNeighbors(neighbor3i, element3i, width*height*2);
1466 for (y = 0, iy = y1;y < height + 1;y++, iy++)
1467 for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1468 Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1473 void Mod_Terrain_SurfaceRecurseChunk(dp_model_t *model, int stepsize, int x, int y)
1477 float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1478 float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1479 float viewvector[3];
1480 unsigned int firstvertex;
1483 if (chunkwidth < 2 || chunkheight < 2)
1485 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]);
1486 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]);
1487 viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1488 viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1489 viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1490 if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1492 // too close for this stepsize, emit as 4 chunks instead
1494 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1495 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1496 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1497 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1500 // emit the geometry at stepsize into our vertex buffer / index buffer
1501 // we add two columns and two rows for skirt
1502 outwidth = chunkwidth+2;
1503 outheight = chunkheight+2;
1504 outwidth2 = outwidth-1;
1505 outheight2 = outheight-1;
1506 outwidth3 = outwidth+1;
1507 outheight3 = outheight+1;
1508 firstvertex = numvertices;
1509 e = model->terrain.element3i + numtriangles;
1510 numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1511 v = model->terrain.vertex3f + numvertices;
1512 numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1513 // emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1514 for (ty = 0;ty < outheight;ty++)
1516 for (tx = 0;tx < outwidth;tx++)
1518 *e++ = firstvertex + (ty )*outwidth3+(tx );
1519 *e++ = firstvertex + (ty )*outwidth3+(tx+1);
1520 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1521 *e++ = firstvertex + (ty )*outwidth3+(tx );
1522 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1523 *e++ = firstvertex + (ty+1)*outwidth3+(tx );
1526 // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1527 for (ty = 0;ty <= outheight;ty++)
1529 skirtrow = ty == 0 || ty == outheight;
1530 ry = y+bound(1, ty, outheight)*stepsize;
1531 for (tx = 0;tx <= outwidth;tx++)
1533 skirt = skirtrow || tx == 0 || tx == outwidth;
1534 rx = x+bound(1, tx, outwidth)*stepsize;
1537 v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1541 // TODO: emit skirt vertices
1544 void Mod_Terrain_UpdateSurfacesForViewOrigin(dp_model_t *model)
1546 for (y = 0;y < model->terrain.size[1];y += model->terrain.
1547 Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1548 Mod_Terrain_BuildChunk(model,
1552 static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
1555 if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1557 offset = bound(0, s[4] - '0', 9);
1558 offset = (offset + 1) << Q3WAVEFUNC_USER_SHIFT;
1563 if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN;
1564 if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE;
1565 if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE;
1566 if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH;
1567 if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1568 if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE;
1569 if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE;
1570 Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1571 return offset | Q3WAVEFUNC_NONE;
1574 void Mod_FreeQ3Shaders(void)
1576 Mem_FreePool(&q3shaders_mem);
1579 static void Q3Shader_AddToHash (q3shaderinfo_t* shader)
1581 unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1582 q3shader_hash_entry_t* entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
1583 q3shader_hash_entry_t* lastEntry = NULL;
1586 if (strcasecmp (entry->shader.name, shader->name) == 0)
1589 if(shader->dpshaderkill)
1591 // killed shader is a redeclarion? we can safely ignore it
1594 else if(entry->shader.dpshaderkill)
1596 // replace the old shader!
1597 // this will skip the entry allocating part
1598 // below and just replace the shader
1603 unsigned char *start, *end, *start2;
1604 start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1605 end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1606 start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1607 if(memcmp(start, start2, end - start))
1608 Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1610 Con_DPrintf("Shader '%s' already defined\n", shader->name);
1615 entry = entry->chain;
1617 while (entry != NULL);
1620 if (lastEntry->shader.name[0] != 0)
1623 q3shader_hash_entry_t* newEntry = (q3shader_hash_entry_t*)
1624 Mem_ExpandableArray_AllocRecord (&q3shader_data->hash_entries);
1626 while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1627 lastEntry->chain = newEntry;
1628 newEntry->chain = NULL;
1629 lastEntry = newEntry;
1631 /* else: head of chain, in hash entry array */
1634 memcpy (&entry->shader, shader, sizeof (q3shaderinfo_t));
1637 extern cvar_t mod_noshader_default_offsetmapping;
1638 extern cvar_t mod_q3shader_default_offsetmapping;
1639 extern cvar_t mod_q3shader_default_offsetmapping_scale;
1640 extern cvar_t mod_q3shader_default_offsetmapping_bias;
1641 extern cvar_t mod_q3shader_default_polygonoffset;
1642 extern cvar_t mod_q3shader_default_polygonfactor;
1643 extern cvar_t mod_q3shader_force_addalpha;
1644 extern cvar_t mod_q3shader_force_terrain_alphaflag;
1645 void Mod_LoadQ3Shaders(void)
1652 q3shaderinfo_t shader;
1653 q3shaderinfo_layer_t *layer;
1655 char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1656 char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1657 unsigned long custsurfaceflags[256];
1658 int numcustsurfaceflags;
1659 qboolean dpshaderkill;
1661 Mod_FreeQ3Shaders();
1663 q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1664 q3shader_data = (q3shader_data_t*)Mem_Alloc (q3shaders_mem,
1665 sizeof (q3shader_data_t));
1666 Mem_ExpandableArray_NewArray (&q3shader_data->hash_entries,
1667 q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1668 Mem_ExpandableArray_NewArray (&q3shader_data->char_ptrs,
1669 q3shaders_mem, sizeof (char**), 256);
1671 // parse custinfoparms.txt
1672 numcustsurfaceflags = 0;
1673 if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1675 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1676 Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1679 while (COM_ParseToken_QuakeC(&text, false))
1680 if (!strcasecmp(com_token, "}"))
1682 // custom surfaceflags section
1683 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1684 Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1687 while(COM_ParseToken_QuakeC(&text, false))
1689 if (!strcasecmp(com_token, "}"))
1691 // register surfaceflag
1692 if (numcustsurfaceflags >= 256)
1694 Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1698 j = (int)strlen(com_token)+1;
1699 custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1700 strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1702 if (COM_ParseToken_QuakeC(&text, false))
1703 custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1705 custsurfaceflags[numcustsurfaceflags] = 0;
1706 numcustsurfaceflags++;
1714 search = FS_Search("scripts/*.shader", true, false);
1717 for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1719 text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1722 while (COM_ParseToken_QuakeC(&text, false))
1724 memset (&shader, 0, sizeof(shader));
1726 shader.surfaceparms = 0;
1727 shader.surfaceflags = 0;
1728 shader.textureflags = 0;
1729 shader.numlayers = 0;
1730 shader.lighting = false;
1731 shader.vertexalpha = false;
1732 shader.textureblendalpha = false;
1733 shader.skyboxname[0] = 0;
1734 shader.deforms[0].deform = Q3DEFORM_NONE;
1735 shader.dpnortlight = false;
1736 shader.dpshadow = false;
1737 shader.dpnoshadow = false;
1738 shader.dpmeshcollisions = false;
1739 shader.dpshaderkill = false;
1740 shader.dpreflectcube[0] = 0;
1741 shader.reflectmin = 0;
1742 shader.reflectmax = 1;
1743 shader.refractfactor = 1;
1744 Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1745 shader.reflectfactor = 1;
1746 Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1747 shader.r_water_wateralpha = 1;
1748 shader.r_water_waterscroll[0] = 0;
1749 shader.r_water_waterscroll[1] = 0;
1750 shader.offsetmapping = (mod_q3shader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
1751 shader.offsetscale = mod_q3shader_default_offsetmapping_scale.value;
1752 shader.offsetbias = mod_q3shader_default_offsetmapping_bias.value;
1753 shader.biaspolygonoffset = mod_q3shader_default_polygonoffset.value;
1754 shader.biaspolygonfactor = mod_q3shader_default_polygonfactor.value;
1755 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
1756 shader.specularscalemod = 1;
1757 shader.specularpowermod = 1;
1758 shader.rtlightambient = 0;
1759 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1760 // JUST GREP FOR "specularscalemod = 1".
1762 strlcpy(shader.name, com_token, sizeof(shader.name));
1763 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1765 Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1768 while (COM_ParseToken_QuakeC(&text, false))
1770 if (!strcasecmp(com_token, "}"))
1772 if (!strcasecmp(com_token, "{"))
1774 static q3shaderinfo_layer_t dummy;
1775 if (shader.numlayers < Q3SHADER_MAXLAYERS)
1777 layer = shader.layers + shader.numlayers++;
1781 // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1782 memset(&dummy, 0, sizeof(dummy));
1785 layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1786 layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1787 layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1788 layer->blendfunc[0] = GL_ONE;
1789 layer->blendfunc[1] = GL_ZERO;
1790 while (COM_ParseToken_QuakeC(&text, false))
1792 if (!strcasecmp(com_token, "}"))
1794 if (!strcasecmp(com_token, "\n"))
1797 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1799 if (j < TEXTURE_MAXFRAMES + 4)
1801 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1802 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1803 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1805 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1806 numparameters = j + 1;
1808 if (!COM_ParseToken_QuakeC(&text, true))
1811 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1812 // parameter[j][0] = 0;
1813 if (developer_insane.integer)
1815 Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1816 for (j = 0;j < numparameters;j++)
1817 Con_DPrintf(" %s", parameter[j]);
1820 if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1822 if (numparameters == 2)
1824 if (!strcasecmp(parameter[1], "add"))
1826 layer->blendfunc[0] = GL_ONE;
1827 layer->blendfunc[1] = GL_ONE;
1829 else if (!strcasecmp(parameter[1], "addalpha"))
1831 layer->blendfunc[0] = GL_SRC_ALPHA;
1832 layer->blendfunc[1] = GL_ONE;
1834 else if (!strcasecmp(parameter[1], "filter"))
1836 layer->blendfunc[0] = GL_DST_COLOR;
1837 layer->blendfunc[1] = GL_ZERO;
1839 else if (!strcasecmp(parameter[1], "blend"))
1841 layer->blendfunc[0] = GL_SRC_ALPHA;
1842 layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1845 else if (numparameters == 3)
1848 for (k = 0;k < 2;k++)
1850 if (!strcasecmp(parameter[k+1], "GL_ONE"))
1851 layer->blendfunc[k] = GL_ONE;
1852 else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1853 layer->blendfunc[k] = GL_ZERO;
1854 else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1855 layer->blendfunc[k] = GL_SRC_COLOR;
1856 else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1857 layer->blendfunc[k] = GL_SRC_ALPHA;
1858 else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1859 layer->blendfunc[k] = GL_DST_COLOR;
1860 else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1861 layer->blendfunc[k] = GL_DST_ALPHA;
1862 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1863 layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1864 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1865 layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1866 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1867 layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1868 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1869 layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1871 layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1875 if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1876 layer->alphatest = true;
1877 if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1879 if (!strcasecmp(parameter[0], "clampmap"))
1880 layer->clampmap = true;
1881 layer->numframes = 1;
1882 layer->framerate = 1;
1883 layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1884 &q3shader_data->char_ptrs);
1885 layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1886 if (!strcasecmp(parameter[1], "$lightmap"))
1887 shader.lighting = true;
1889 else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1892 layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1893 layer->framerate = atof(parameter[1]);
1894 layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1895 for (i = 0;i < layer->numframes;i++)
1896 layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1898 else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1901 for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1902 layer->rgbgen.parms[i] = atof(parameter[i+2]);
1903 if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1904 else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1905 else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1906 else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1907 else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1908 else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1909 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1910 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1911 else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1912 else if (!strcasecmp(parameter[1], "wave"))
1914 layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1915 layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1916 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1917 layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1919 else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1921 else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1924 for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1925 layer->alphagen.parms[i] = atof(parameter[i+2]);
1926 if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1927 else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1928 else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1929 else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1930 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1931 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1932 else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1933 else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1934 else if (!strcasecmp(parameter[1], "wave"))
1936 layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1937 layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1938 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1939 layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1941 else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1943 else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1946 // observed values: tcgen environment
1947 // no other values have been observed in real shaders
1948 for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1949 layer->tcgen.parms[i] = atof(parameter[i+2]);
1950 if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1951 else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1952 else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1953 else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1954 else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1955 else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1957 else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1964 // tcmod stretch sin # # # #
1965 // tcmod stretch triangle # # # #
1966 // tcmod transform # # # # # #
1967 // tcmod turb # # # #
1968 // tcmod turb sin # # # # (this is bogus)
1969 // no other values have been observed in real shaders
1970 for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1971 if (!layer->tcmods[tcmodindex].tcmod)
1973 if (tcmodindex < Q3MAXTCMODS)
1975 for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1976 layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1977 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1978 else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1979 else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1980 else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1981 else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1982 else if (!strcasecmp(parameter[1], "stretch"))
1984 layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1985 layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1986 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1987 layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1989 else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1990 else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1991 else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1994 Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1996 // break out a level if it was a closing brace (not using the character here to not confuse vim)
1997 if (!strcasecmp(com_token, "}"))
2000 if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2001 shader.lighting = true;
2002 if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
2004 if (layer == shader.layers + 0)
2006 // vertex controlled transparency
2007 shader.vertexalpha = true;
2011 // multilayer terrain shader or similar
2012 shader.textureblendalpha = true;
2013 if (mod_q3shader_force_terrain_alphaflag.integer)
2014 shader.layers[0].texflags |= TEXF_ALPHA;
2018 if(mod_q3shader_force_addalpha.integer)
2020 // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
2021 // this cvar brings back this behaviour
2022 if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
2023 layer->blendfunc[0] = GL_SRC_ALPHA;
2026 layer->texflags = 0;
2027 if (layer->alphatest)
2028 layer->texflags |= TEXF_ALPHA;
2029 switch(layer->blendfunc[0])
2032 case GL_ONE_MINUS_SRC_ALPHA:
2033 layer->texflags |= TEXF_ALPHA;
2036 switch(layer->blendfunc[1])
2039 case GL_ONE_MINUS_SRC_ALPHA:
2040 layer->texflags |= TEXF_ALPHA;
2043 if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
2044 layer->texflags |= TEXF_MIPMAP;
2045 if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
2046 layer->texflags |= TEXF_PICMIP | TEXF_COMPRESS;
2047 if (layer->clampmap)
2048 layer->texflags |= TEXF_CLAMP;
2052 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
2054 if (j < TEXTURE_MAXFRAMES + 4)
2056 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
2057 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
2058 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
2060 strlcpy(parameter[j], com_token, sizeof(parameter[j]));
2061 numparameters = j + 1;
2063 if (!COM_ParseToken_QuakeC(&text, true))
2066 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
2067 // parameter[j][0] = 0;
2068 if (fileindex == 0 && !strcasecmp(com_token, "}"))
2070 if (developer_insane.integer)
2072 Con_DPrintf("%s: ", shader.name);
2073 for (j = 0;j < numparameters;j++)
2074 Con_DPrintf(" %s", parameter[j]);
2077 if (numparameters < 1)
2079 if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
2081 if (!strcasecmp(parameter[1], "alphashadow"))
2082 shader.surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
2083 else if (!strcasecmp(parameter[1], "areaportal"))
2084 shader.surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
2085 else if (!strcasecmp(parameter[1], "botclip"))
2086 shader.surfaceparms |= Q3SURFACEPARM_BOTCLIP;
2087 else if (!strcasecmp(parameter[1], "clusterportal"))
2088 shader.surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
2089 else if (!strcasecmp(parameter[1], "detail"))
2090 shader.surfaceparms |= Q3SURFACEPARM_DETAIL;
2091 else if (!strcasecmp(parameter[1], "donotenter"))
2092 shader.surfaceparms |= Q3SURFACEPARM_DONOTENTER;
2093 else if (!strcasecmp(parameter[1], "dust"))
2094 shader.surfaceparms |= Q3SURFACEPARM_DUST;
2095 else if (!strcasecmp(parameter[1], "hint"))
2096 shader.surfaceparms |= Q3SURFACEPARM_HINT;
2097 else if (!strcasecmp(parameter[1], "fog"))
2098 shader.surfaceparms |= Q3SURFACEPARM_FOG;
2099 else if (!strcasecmp(parameter[1], "lava"))
2100 shader.surfaceparms |= Q3SURFACEPARM_LAVA;
2101 else if (!strcasecmp(parameter[1], "lightfilter"))
2102 shader.surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
2103 else if (!strcasecmp(parameter[1], "lightgrid"))
2104 shader.surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
2105 else if (!strcasecmp(parameter[1], "metalsteps"))
2106 shader.surfaceparms |= Q3SURFACEPARM_METALSTEPS;
2107 else if (!strcasecmp(parameter[1], "nodamage"))
2108 shader.surfaceparms |= Q3SURFACEPARM_NODAMAGE;
2109 else if (!strcasecmp(parameter[1], "nodlight"))
2110 shader.surfaceparms |= Q3SURFACEPARM_NODLIGHT;
2111 else if (!strcasecmp(parameter[1], "nodraw"))
2112 shader.surfaceparms |= Q3SURFACEPARM_NODRAW;
2113 else if (!strcasecmp(parameter[1], "nodrop"))
2114 shader.surfaceparms |= Q3SURFACEPARM_NODROP;
2115 else if (!strcasecmp(parameter[1], "noimpact"))
2116 shader.surfaceparms |= Q3SURFACEPARM_NOIMPACT;
2117 else if (!strcasecmp(parameter[1], "nolightmap"))
2118 shader.surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
2119 else if (!strcasecmp(parameter[1], "nomarks"))
2120 shader.surfaceparms |= Q3SURFACEPARM_NOMARKS;
2121 else if (!strcasecmp(parameter[1], "nomipmaps"))
2122 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2123 else if (!strcasecmp(parameter[1], "nonsolid"))
2124 shader.surfaceparms |= Q3SURFACEPARM_NONSOLID;
2125 else if (!strcasecmp(parameter[1], "origin"))
2126 shader.surfaceparms |= Q3SURFACEPARM_ORIGIN;
2127 else if (!strcasecmp(parameter[1], "playerclip"))
2128 shader.surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
2129 else if (!strcasecmp(parameter[1], "sky"))
2130 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2131 else if (!strcasecmp(parameter[1], "slick"))
2132 shader.surfaceparms |= Q3SURFACEPARM_SLICK;
2133 else if (!strcasecmp(parameter[1], "slime"))
2134 shader.surfaceparms |= Q3SURFACEPARM_SLIME;
2135 else if (!strcasecmp(parameter[1], "structural"))
2136 shader.surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
2137 else if (!strcasecmp(parameter[1], "trans"))
2138 shader.surfaceparms |= Q3SURFACEPARM_TRANS;
2139 else if (!strcasecmp(parameter[1], "water"))
2140 shader.surfaceparms |= Q3SURFACEPARM_WATER;
2141 else if (!strcasecmp(parameter[1], "pointlight"))
2142 shader.surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
2143 else if (!strcasecmp(parameter[1], "antiportal"))
2144 shader.surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
2145 else if (!strcasecmp(parameter[1], "skip"))
2146 ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
2149 // try custom surfaceparms
2150 for (j = 0; j < numcustsurfaceflags; j++)
2152 if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
2154 shader.surfaceflags |= custsurfaceflags[j];
2159 if (j == numcustsurfaceflags)
2160 Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
2163 else if (!strcasecmp(parameter[0], "dpshadow"))
2164 shader.dpshadow = true;
2165 else if (!strcasecmp(parameter[0], "dpnoshadow"))
2166 shader.dpnoshadow = true;
2167 else if (!strcasecmp(parameter[0], "dpnortlight"))
2168 shader.dpnortlight = true;
2169 else if (!strcasecmp(parameter[0], "dpreflectcube"))
2170 strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
2171 else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
2172 shader.dpmeshcollisions = true;
2173 // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
2174 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
2176 if (Cvar_VariableValue(parameter[1]) == 0.0f)
2177 shader.dpshaderkill = dpshaderkill;
2179 // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
2180 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
2182 const char *op = NULL;
2183 if (numparameters >= 3)
2187 if (Cvar_VariableValue(parameter[1]) != 0.0f)
2188 shader.dpshaderkill = dpshaderkill;
2190 else if (numparameters >= 4 && !strcmp(op, "=="))
2192 if (Cvar_VariableValue(parameter[1]) == atof(parameter[3]))
2193 shader.dpshaderkill = dpshaderkill;
2195 else if (numparameters >= 4 && !strcmp(op, "!="))
2197 if (Cvar_VariableValue(parameter[1]) != atof(parameter[3]))
2198 shader.dpshaderkill = dpshaderkill;
2200 else if (numparameters >= 4 && !strcmp(op, ">"))
2202 if (Cvar_VariableValue(parameter[1]) > atof(parameter[3]))
2203 shader.dpshaderkill = dpshaderkill;
2205 else if (numparameters >= 4 && !strcmp(op, "<"))
2207 if (Cvar_VariableValue(parameter[1]) < atof(parameter[3]))
2208 shader.dpshaderkill = dpshaderkill;
2210 else if (numparameters >= 4 && !strcmp(op, ">="))
2212 if (Cvar_VariableValue(parameter[1]) >= atof(parameter[3]))
2213 shader.dpshaderkill = dpshaderkill;
2215 else if (numparameters >= 4 && !strcmp(op, "<="))
2217 if (Cvar_VariableValue(parameter[1]) <= atof(parameter[3]))
2218 shader.dpshaderkill = dpshaderkill;
2222 Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2225 else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2227 // some q3 skies don't have the sky parm set
2228 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2229 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2231 else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2233 // some q3 skies don't have the sky parm set
2234 shader.surfaceparms |= Q3SURFACEPARM_SKY;
2235 if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2236 strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2238 else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2240 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2241 shader.textureflags |= Q3TEXTUREFLAG_TWOSIDED;
2243 else if (!strcasecmp(parameter[0], "nomipmaps"))
2244 shader.surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
2245 else if (!strcasecmp(parameter[0], "nopicmip"))
2246 shader.textureflags |= Q3TEXTUREFLAG_NOPICMIP;
2247 else if (!strcasecmp(parameter[0], "polygonoffset"))
2248 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2249 else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2251 shader.textureflags |= Q3TEXTUREFLAG_POLYGONOFFSET;
2252 if(numparameters >= 2)
2254 shader.biaspolygonfactor = atof(parameter[1]);
2255 if(numparameters >= 3)
2256 shader.biaspolygonoffset = atof(parameter[2]);
2258 shader.biaspolygonoffset = 0;
2261 else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2263 shader.textureflags |= Q3TEXTUREFLAG_TRANSPARENTSORT;
2264 if (!strcasecmp(parameter[1], "sky"))
2265 shader.transparentsort = TRANSPARENTSORT_SKY;
2266 else if (!strcasecmp(parameter[1], "distance"))
2267 shader.transparentsort = TRANSPARENTSORT_DISTANCE;
2268 else if (!strcasecmp(parameter[1], "hud"))
2269 shader.transparentsort = TRANSPARENTSORT_HUD;
2271 Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2273 else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2275 shader.textureflags |= Q3TEXTUREFLAG_REFRACTION;
2276 shader.refractfactor = atof(parameter[1]);
2277 Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2279 else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2281 shader.textureflags |= Q3TEXTUREFLAG_REFLECTION;
2282 shader.reflectfactor = atof(parameter[1]);
2283 Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2285 else if (!strcasecmp(parameter[0], "dpcamera"))
2287 shader.textureflags |= Q3TEXTUREFLAG_CAMERA;
2289 else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2291 shader.textureflags |= Q3TEXTUREFLAG_WATERSHADER;
2292 shader.reflectmin = atof(parameter[1]);
2293 shader.reflectmax = atof(parameter[2]);
2294 shader.refractfactor = atof(parameter[3]);
2295 shader.reflectfactor = atof(parameter[4]);
2296 Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2297 Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2298 shader.r_water_wateralpha = atof(parameter[11]);
2300 else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2302 shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2303 shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2305 else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2307 shader.specularscalemod = atof(parameter[1]);
2309 else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2311 shader.specularpowermod = atof(parameter[1]);
2313 else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2315 shader.rtlightambient = atof(parameter[1]);
2317 else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2319 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2320 shader.offsetmapping = OFFSETMAPPING_OFF;
2321 else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2322 shader.offsetmapping = OFFSETMAPPING_DEFAULT;
2323 else if (!strcasecmp(parameter[1], "linear"))
2324 shader.offsetmapping = OFFSETMAPPING_LINEAR;
2325 else if (!strcasecmp(parameter[1], "relief"))
2326 shader.offsetmapping = OFFSETMAPPING_RELIEF;
2327 if (numparameters >= 3)
2328 shader.offsetscale = atof(parameter[2]);
2329 if (numparameters >= 5)
2331 if(!strcasecmp(parameter[3], "bias"))
2332 shader.offsetbias = atof(parameter[4]);
2333 else if(!strcasecmp(parameter[3], "match"))
2334 shader.offsetbias = 1.0f - atof(parameter[4]);
2335 else if(!strcasecmp(parameter[3], "match8"))
2336 shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2337 else if(!strcasecmp(parameter[3], "match16"))
2338 shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2341 else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2344 for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2345 if (!shader.deforms[deformindex].deform)
2347 if (deformindex < Q3MAXDEFORMS)
2349 for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2350 shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2351 if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2352 else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2353 else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2354 else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2355 else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2356 else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2357 else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2358 else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2359 else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2360 else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2361 else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2362 else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2363 else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2364 else if (!strcasecmp(parameter[1], "wave" ))
2366 shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2367 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2368 for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2369 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2371 else if (!strcasecmp(parameter[1], "move" ))
2373 shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2374 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2375 for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2376 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2381 // hide this shader if a cvar said it should be killed
2382 if (shader.dpshaderkill)
2383 shader.numlayers = 0;
2384 // fix up multiple reflection types
2385 if(shader.textureflags & Q3TEXTUREFLAG_WATERSHADER)
2386 shader.textureflags &= ~(Q3TEXTUREFLAG_REFRACTION | Q3TEXTUREFLAG_REFLECTION | Q3TEXTUREFLAG_CAMERA);
2388 Q3Shader_AddToHash (&shader);
2392 FS_FreeSearch(search);
2393 // free custinfoparm values
2394 for (j = 0; j < numcustsurfaceflags; j++)
2395 Mem_Free(custsurfaceparmnames[j]);
2398 q3shaderinfo_t *Mod_LookupQ3Shader(const char *name)
2400 unsigned short hash;
2401 q3shader_hash_entry_t* entry;
2403 Mod_LoadQ3Shaders();
2404 hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2405 entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2406 while (entry != NULL)
2408 if (strcasecmp (entry->shader.name, name) == 0)
2409 return &entry->shader;
2410 entry = entry->chain;
2415 texture_shaderpass_t *Mod_CreateShaderPass(skinframe_t *skinframe)
2417 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
2418 shaderpass->framerate = 0.0f;
2419 shaderpass->numframes = 1;
2420 shaderpass->blendfunc[0] = GL_ONE;
2421 shaderpass->blendfunc[1] = GL_ZERO;
2422 shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
2423 shaderpass->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
2424 shaderpass->alphatest = false;
2425 shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
2426 shaderpass->skinframes[0] = skinframe;
2430 texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
2433 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(loadmodel->mempool, sizeof(*shaderpass));
2434 shaderpass->alphatest = layer->alphatest != 0;
2435 shaderpass->framerate = layer->framerate;
2436 shaderpass->numframes = layer->numframes;
2437 shaderpass->blendfunc[0] = layer->blendfunc[0];
2438 shaderpass->blendfunc[1] = layer->blendfunc[1];
2439 shaderpass->rgbgen = layer->rgbgen;
2440 shaderpass->alphagen = layer->alphagen;
2441 shaderpass->tcgen = layer->tcgen;
2442 for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
2443 shaderpass->tcmods[j] = layer->tcmods[j];
2444 for (j = 0; j < layer->numframes; j++)
2446 if (cls.state == ca_dedicated)
2448 shaderpass->skinframes[j] = NULL;
2450 else if (!(shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false)))
2452 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"^7 (frame %i) for layer %i of shader ^2\"%s\"\n", loadmodel->name, layer->texturename[j], j, layerindex, texturename);
2453 shaderpass->skinframes[j] = R_SkinFrame_LoadMissing();
2459 qboolean Mod_LoadTextureFromQ3Shader(texture_t *texture, const char *name, qboolean warnmissing, qboolean fallback, int defaulttexflags)
2461 int texflagsmask, texflagsor;
2462 qboolean success = true;
2463 q3shaderinfo_t *shader;
2466 strlcpy(texture->name, name, sizeof(texture->name));
2467 texture->basealpha = 1.0f;
2468 shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2471 if(!(defaulttexflags & TEXF_PICMIP))
2472 texflagsmask &= ~TEXF_PICMIP;
2473 if(!(defaulttexflags & TEXF_COMPRESS))
2474 texflagsmask &= ~TEXF_COMPRESS;
2476 if(defaulttexflags & TEXF_ISWORLD)
2477 texflagsor |= TEXF_ISWORLD;
2478 if(defaulttexflags & TEXF_ISSPRITE)
2479 texflagsor |= TEXF_ISSPRITE;
2480 // unless later loaded from the shader
2481 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2482 texture->offsetscale = 1;
2483 texture->offsetbias = 0;
2484 texture->specularscalemod = 1;
2485 texture->specularpowermod = 1;
2486 texture->rtlightambient = 0;
2487 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2488 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2489 // JUST GREP FOR "specularscalemod = 1".
2493 if (developer_loading.integer)
2494 Con_Printf("%s: loaded shader for %s\n", loadmodel->name, name);
2496 // allow disabling of picmip or compression by defaulttexflags
2497 texture->textureflags = (shader->textureflags & texflagsmask) | texflagsor;
2499 if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2501 texture->basematerialflags = MATERIALFLAG_SKY;
2502 if (shader->skyboxname[0])
2504 // quake3 seems to append a _ to the skybox name, so this must do so as well
2505 dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2508 else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2509 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2511 texture->basematerialflags = MATERIALFLAG_WALL;
2513 if (shader->layers[0].alphatest)
2514 texture->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_NOSHADOW;
2515 if (shader->textureflags & Q3TEXTUREFLAG_TWOSIDED)
2516 texture->basematerialflags |= MATERIALFLAG_NOSHADOW | MATERIALFLAG_NOCULLFACE;
2517 if (shader->textureflags & Q3TEXTUREFLAG_POLYGONOFFSET)
2519 texture->biaspolygonoffset += shader->biaspolygonoffset;
2520 texture->biaspolygonfactor += shader->biaspolygonfactor;
2522 if (shader->textureflags & Q3TEXTUREFLAG_REFRACTION)
2523 texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2524 if (shader->textureflags & Q3TEXTUREFLAG_REFLECTION)
2525 texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2526 if (shader->textureflags & Q3TEXTUREFLAG_WATERSHADER)
2527 texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2528 if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2529 texture->basematerialflags |= MATERIALFLAG_CAMERA;
2530 texture->customblendfunc[0] = GL_ONE;
2531 texture->customblendfunc[1] = GL_ZERO;
2532 texture->transparentsort = shader->transparentsort;
2533 if (shader->numlayers > 0)
2535 texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2536 texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2538 Q3 shader blendfuncs actually used in the game (* = supported by DP)
2539 * additive GL_ONE GL_ONE
2540 additive weird GL_ONE GL_SRC_ALPHA
2541 additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
2542 * alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2543 alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2544 brighten GL_DST_COLOR GL_ONE
2545 brighten GL_ONE GL_SRC_COLOR
2546 brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2547 brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
2548 * modulate GL_DST_COLOR GL_ZERO
2549 * modulate GL_ZERO GL_SRC_COLOR
2550 modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
2551 modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2552 modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2553 * modulate x2 GL_DST_COLOR GL_SRC_COLOR
2554 * no blend GL_ONE GL_ZERO
2555 nothing GL_ZERO GL_ONE
2557 // if not opaque, figure out what blendfunc to use
2558 if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2560 if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2561 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2562 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2563 texture->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2564 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2565 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2567 texture->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2570 if (!shader->lighting)
2571 texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2573 // here be dragons: convert quake3 shaders to material
2574 if (shader->numlayers > 0)
2577 int terrainbackgroundlayer = -1;
2578 int lightmaplayer = -1;
2579 int alphagenspecularlayer = -1;
2580 int rgbgenvertexlayer = -1;
2581 int rgbgendiffuselayer = -1;
2582 int materiallayer = -1;
2583 int endofprelayers = 0;
2584 int firstpostlayer = 0;
2585 int shaderpassindex = 0;
2586 for (i = 0; i < shader->numlayers; i++)
2588 if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
2590 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2591 rgbgenvertexlayer = i;
2592 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE)
2593 rgbgendiffuselayer = i;
2594 if (shader->layers[i].alphagen.alphagen == Q3ALPHAGEN_LIGHTINGSPECULAR)
2595 alphagenspecularlayer = i;
2597 if (shader->numlayers >= 2
2598 && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2599 && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
2600 && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2601 || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
2603 // terrain blend or certain other effects involving alphatest over a regular layer
2604 terrainbackgroundlayer = 0;
2606 // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
2607 firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
2609 else if (lightmaplayer == 0)
2611 // ordinary texture but with $lightmap before diffuse
2613 firstpostlayer = lightmaplayer + 2;
2615 else if (lightmaplayer >= 1)
2617 // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
2618 endofprelayers = lightmaplayer - 1;
2619 materiallayer = lightmaplayer - 1;
2620 firstpostlayer = lightmaplayer + 1;
2622 else if (rgbgenvertexlayer >= 0)
2624 // map models with baked lighting
2625 materiallayer = rgbgenvertexlayer;
2626 endofprelayers = rgbgenvertexlayer;
2627 firstpostlayer = rgbgenvertexlayer + 1;
2629 else if (rgbgendiffuselayer >= 0)
2631 // entity models with dynamic lighting
2632 materiallayer = rgbgendiffuselayer;
2633 endofprelayers = rgbgendiffuselayer;
2634 firstpostlayer = rgbgendiffuselayer + 1;
2635 // 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)...
2636 if (alphagenspecularlayer >= 0)
2637 firstpostlayer = alphagenspecularlayer + 1;
2641 // special effects shaders - treat first as primary layer and do everything else as post
2646 // convert the main material layer
2647 // 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
2648 if (materiallayer >= 0)
2649 texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].texflags & texflagsmask) | texflagsor, texture->name);
2650 // convert the terrain background blend layer (if any)
2651 if (terrainbackgroundlayer >= 0)
2652 texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].texflags & texflagsmask) | texflagsor, texture->name);
2653 // convert the prepass layers (if any)
2654 texture->startpreshaderpass = shaderpassindex;
2655 for (i = 0; i < endofprelayers; i++)
2656 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
2657 texture->endpreshaderpass = shaderpassindex;
2658 texture->startpostshaderpass = shaderpassindex;
2659 // convert the postpass layers (if any)
2660 for (i = firstpostlayer; i < shader->numlayers; i++)
2661 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(&shader->layers[i], i, (shader->layers[i].texflags & texflagsmask) | texflagsor, texture->name);
2662 texture->startpostshaderpass = shaderpassindex;
2665 if (shader->dpshadow)
2666 texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2667 if (shader->dpnoshadow)
2668 texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2669 if (shader->dpnortlight)
2670 texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2671 if (shader->vertexalpha)
2672 texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2673 memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2674 texture->reflectmin = shader->reflectmin;
2675 texture->reflectmax = shader->reflectmax;
2676 texture->refractfactor = shader->refractfactor;
2677 Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2678 texture->reflectfactor = shader->reflectfactor;
2679 Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2680 texture->r_water_wateralpha = shader->r_water_wateralpha;
2681 Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2682 texture->offsetmapping = shader->offsetmapping;
2683 texture->offsetscale = shader->offsetscale;
2684 texture->offsetbias = shader->offsetbias;
2685 texture->specularscalemod = shader->specularscalemod;
2686 texture->specularpowermod = shader->specularpowermod;
2687 texture->rtlightambient = shader->rtlightambient;
2688 if (shader->dpreflectcube[0])
2689 texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2691 // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2692 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2693 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ;
2694 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ;
2695 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ;
2696 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ;
2697 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents = SUPERCONTENTS_PLAYERCLIP ;
2698 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ;
2699 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ;
2701 // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ;
2702 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ;
2703 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2704 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ;
2705 if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ;
2706 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ;
2707 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ;
2708 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ;
2709 // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ;
2710 // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ;
2711 // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ;
2712 // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ;
2713 if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ;
2714 // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ;
2715 // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ;
2716 // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ;
2717 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ;
2718 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ;
2719 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ;
2720 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ;
2721 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ;
2722 // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ;
2723 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ;
2724 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ;
2725 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ;
2726 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ;
2727 // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ;
2728 // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ;
2729 // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ;
2730 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents |= SUPERCONTENTS_BOTCLIP | SUPERCONTENTS_MONSTERCLIP;
2731 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ;
2732 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ;
2734 texture->surfaceflags = shader->surfaceflags;
2735 if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->surfaceflags |= Q3SURFACEFLAG_ALPHASHADOW ;
2736 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ;
2737 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2738 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ;
2739 // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ;
2740 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ;
2741 // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ;
2742 if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTFILTER ;
2743 if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->surfaceflags |= Q3SURFACEFLAG_METALSTEPS ;
2744 if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ;
2745 if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ;
2746 if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ;
2747 // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ;
2748 if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ;
2749 if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->surfaceflags |= Q3SURFACEFLAG_NOLIGHTMAP ;
2750 if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ;
2751 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ;
2752 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ;
2753 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ;
2754 // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ;
2755 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ;
2756 if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ;
2757 // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ;
2758 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ;
2759 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ;
2760 // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ;
2761 if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_POINTLIGHT ;
2762 if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ;
2763 if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ;
2764 // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ;
2765 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ;
2766 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ;
2768 if (shader->dpmeshcollisions)
2769 texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2770 if (shader->dpshaderkill && developer_extra.integer)
2771 Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", loadmodel->name, name);
2773 else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2775 if (developer_extra.integer)
2776 Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", loadmodel->name, name);
2777 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2779 else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2781 if (developer_extra.integer)
2782 Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", loadmodel->name, name);
2783 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2784 texture->supercontents = SUPERCONTENTS_SOLID;
2788 if (developer_extra.integer)
2789 Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", loadmodel->name, texture->name);
2790 if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2792 texture->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2793 texture->supercontents = SUPERCONTENTS_SOLID;
2795 else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2797 texture->basematerialflags |= MATERIALFLAG_SKY;
2798 texture->supercontents = SUPERCONTENTS_SKY;
2802 texture->basematerialflags |= MATERIALFLAG_WALL;
2803 texture->supercontents = SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
2805 if(cls.state == ca_dedicated)
2807 texture->materialshaderpass = NULL;
2814 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false));
2815 if (texture->materialshaderpass->skinframes[0])
2817 if (texture->materialshaderpass->skinframes[0]->hasalpha)
2818 texture->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_NOSHADOW;
2819 if (texture->q2contents)
2820 texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(loadmodel, texture->q2contents);
2827 if (!success && warnmissing)
2828 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", loadmodel->name, texture->name);
2831 // init the animation variables
2832 texture->currentframe = texture;
2833 if (!texture->materialshaderpass)
2834 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing());
2835 if (!texture->materialshaderpass->skinframes[0])
2836 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2837 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2838 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2842 void Mod_LoadCustomMaterial(texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
2844 if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
2845 Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", loadmodel->name, texture->name);
2846 strlcpy(texture->name, name, sizeof(texture->name));
2847 texture->basealpha = 1.0f;
2848 texture->basematerialflags = texture->currentmaterialflags = materialflags;
2849 texture->supercontents = supercontents;
2851 texture->offsetmapping = (mod_noshader_default_offsetmapping.value) ? OFFSETMAPPING_DEFAULT : OFFSETMAPPING_OFF;
2852 texture->offsetscale = 1;
2853 texture->offsetbias = 0;
2854 texture->specularscalemod = 1;
2855 texture->specularpowermod = 1;
2856 texture->rtlightambient = 0;
2857 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2858 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2859 // JUST GREP FOR "specularscalemod = 1".
2861 if (developer_extra.integer)
2862 Con_DPrintf("^1%s:^7 Custom texture ^3\"%s\"\n", loadmodel->name, texture->name);
2863 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(skinframe);
2865 // init the animation variables
2866 texture->currentframe = texture;
2867 if (!texture->materialshaderpass)
2868 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(R_SkinFrame_LoadMissing());
2869 if (!texture->materialshaderpass->skinframes[0])
2870 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2871 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2872 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2875 skinfile_t *Mod_LoadSkinFiles(void)
2877 int i, words, line, wordsoverflow;
2880 skinfile_t *skinfile = NULL, *first = NULL;
2881 skinfileitem_t *skinfileitem;
2882 char word[10][MAX_QPATH];
2887 U_bodyBox,models/players/Legoman/BikerA2.tga
2888 U_RArm,models/players/Legoman/BikerA1.tga
2889 U_LArm,models/players/Legoman/BikerA1.tga
2890 U_armor,common/nodraw
2891 U_sword,common/nodraw
2892 U_shield,common/nodraw
2893 U_homb,common/nodraw
2894 U_backpack,common/nodraw
2895 U_colcha,common/nodraw
2900 memset(word, 0, sizeof(word));
2901 for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2903 // If it's the first file we parse
2904 if (skinfile == NULL)
2906 skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2911 skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2912 skinfile = skinfile->next;
2914 skinfile->next = NULL;
2916 for(line = 0;;line++)
2919 if (!COM_ParseToken_QuakeC(&data, true))
2921 if (!strcmp(com_token, "\n"))
2924 wordsoverflow = false;
2928 strlcpy(word[words++], com_token, sizeof (word[0]));
2930 wordsoverflow = true;
2932 while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2935 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);
2938 // words is always >= 1
2939 if (!strcmp(word[0], "replace"))
2943 if (developer_loading.integer)
2944 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2945 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2946 skinfileitem->next = skinfile->items;
2947 skinfile->items = skinfileitem;
2948 strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2949 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2952 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]);
2954 else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2956 // tag name, like "tag_weapon,"
2957 // not used for anything (not even in Quake3)
2959 else if (words >= 2 && !strcmp(word[1], ","))
2961 // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2962 if (developer_loading.integer)
2963 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2964 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2965 skinfileitem->next = skinfile->items;
2966 skinfile->items = skinfileitem;
2967 strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2968 strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2971 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);
2976 loadmodel->numskins = i;
2980 void Mod_FreeSkinFiles(skinfile_t *skinfile)
2983 skinfileitem_t *skinfileitem, *nextitem;
2984 for (;skinfile;skinfile = next)
2986 next = skinfile->next;
2987 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2989 nextitem = skinfileitem->next;
2990 Mem_Free(skinfileitem);
2996 int Mod_CountSkinFiles(skinfile_t *skinfile)
2999 for (i = 0;skinfile;skinfile = skinfile->next, i++);
3003 void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
3006 double isnap = 1.0 / snap;
3007 for (i = 0;i < numvertices*numcomponents;i++)
3008 vertices[i] = floor(vertices[i]*isnap)*snap;
3011 int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
3013 int i, outtriangles;
3014 float edgedir1[3], edgedir2[3], temp[3];
3015 // a degenerate triangle is one with no width (thickness, surface area)
3016 // these are characterized by having all 3 points colinear (along a line)
3017 // or having two points identical
3018 // the simplest check is to calculate the triangle's area
3019 for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
3021 // calculate first edge
3022 VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
3023 VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
3024 CrossProduct(edgedir1, edgedir2, temp);
3025 if (VectorLength2(temp) < 0.001f)
3026 continue; // degenerate triangle (no area)
3027 // valid triangle (has area)
3028 VectorCopy(inelement3i, outelement3i);
3032 return outtriangles;
3035 void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
3038 int firstvertex, lastvertex;
3039 if (numelements > 0 && elements)
3041 firstvertex = lastvertex = elements[0];
3042 for (i = 1;i < numelements;i++)
3045 firstvertex = min(firstvertex, e);
3046 lastvertex = max(lastvertex, e);
3050 firstvertex = lastvertex = 0;
3051 if (firstvertexpointer)
3052 *firstvertexpointer = firstvertex;
3053 if (lastvertexpointer)
3054 *lastvertexpointer = lastvertex;
3057 void Mod_MakeSortedSurfaces(dp_model_t *mod)
3059 // make an optimal set of texture-sorted batches to draw...
3061 int *firstsurfacefortexture;
3062 int *numsurfacesfortexture;
3063 if (!mod->sortedmodelsurfaces)
3064 mod->sortedmodelsurfaces = (int *) Mem_Alloc(loadmodel->mempool, mod->nummodelsurfaces * sizeof(*mod->sortedmodelsurfaces));
3065 firstsurfacefortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*firstsurfacefortexture));
3066 numsurfacesfortexture = (int *) Mem_Alloc(tempmempool, mod->num_textures * sizeof(*numsurfacesfortexture));
3067 memset(numsurfacesfortexture, 0, mod->num_textures * sizeof(*numsurfacesfortexture));
3068 for (j = 0;j < mod->nummodelsurfaces;j++)
3070 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
3071 t = (int)(surface->texture - mod->data_textures);
3072 numsurfacesfortexture[t]++;
3075 for (t = 0;t < mod->num_textures;t++)
3077 firstsurfacefortexture[t] = j;
3078 j += numsurfacesfortexture[t];
3080 for (j = 0;j < mod->nummodelsurfaces;j++)
3082 const msurface_t *surface = mod->data_surfaces + j + mod->firstmodelsurface;
3083 t = (int)(surface->texture - mod->data_textures);
3084 mod->sortedmodelsurfaces[firstsurfacefortexture[t]++] = j + mod->firstmodelsurface;
3086 Mem_Free(firstsurfacefortexture);
3087 Mem_Free(numsurfacesfortexture);
3090 void Mod_BuildVBOs(void)
3092 if (!loadmodel->surfmesh.num_vertices)
3095 if (gl_paranoid.integer && loadmodel->surfmesh.data_element3s && loadmodel->surfmesh.data_element3i)
3098 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
3100 if (loadmodel->surfmesh.data_element3s[i] != loadmodel->surfmesh.data_element3i[i])
3102 Con_Printf("Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
3103 loadmodel->surfmesh.data_element3s[i] = loadmodel->surfmesh.data_element3i[i];
3108 // build r_vertexmesh_t array
3109 // (compressed interleaved array for D3D)
3110 if (!loadmodel->surfmesh.data_vertexmesh && vid.useinterleavedarrays)
3113 int numvertices = loadmodel->surfmesh.num_vertices;
3114 r_vertexmesh_t *vertexmesh;
3115 loadmodel->surfmesh.data_vertexmesh = vertexmesh = (r_vertexmesh_t*)Mem_Alloc(loadmodel->mempool, numvertices * sizeof(r_vertexmesh_t));
3116 for (vertexindex = 0;vertexindex < numvertices;vertexindex++, vertexmesh++)
3118 VectorCopy(loadmodel->surfmesh.data_vertex3f + 3*vertexindex, vertexmesh->vertex3f);
3119 VectorScale(loadmodel->surfmesh.data_svector3f + 3*vertexindex, 1.0f, vertexmesh->svector3f);
3120 VectorScale(loadmodel->surfmesh.data_tvector3f + 3*vertexindex, 1.0f, vertexmesh->tvector3f);
3121 VectorScale(loadmodel->surfmesh.data_normal3f + 3*vertexindex, 1.0f, vertexmesh->normal3f);
3122 if (loadmodel->surfmesh.data_lightmapcolor4f)
3123 Vector4Copy(loadmodel->surfmesh.data_lightmapcolor4f + 4*vertexindex, vertexmesh->color4f);
3124 Vector2Copy(loadmodel->surfmesh.data_texcoordtexture2f + 2*vertexindex, vertexmesh->texcoordtexture2f);
3125 if (loadmodel->surfmesh.data_texcoordlightmap2f)
3126 Vector2Scale(loadmodel->surfmesh.data_texcoordlightmap2f + 2*vertexindex, 1.0f, vertexmesh->texcoordlightmap2f);
3127 if (loadmodel->surfmesh.data_skeletalindex4ub)
3128 Vector4Copy(loadmodel->surfmesh.data_skeletalindex4ub + 4*vertexindex, vertexmesh->skeletalindex4ub);
3129 if (loadmodel->surfmesh.data_skeletalweight4ub)
3130 Vector4Copy(loadmodel->surfmesh.data_skeletalweight4ub + 4*vertexindex, vertexmesh->skeletalweight4ub);
3134 // upload short indices as a buffer
3135 if (loadmodel->surfmesh.data_element3s && !loadmodel->surfmesh.data_element3s_indexbuffer)
3136 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);
3138 // upload int indices as a buffer
3139 if (loadmodel->surfmesh.data_element3i && !loadmodel->surfmesh.data_element3i_indexbuffer && !loadmodel->surfmesh.data_element3s)
3140 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);
3142 // only build a vbo if one has not already been created (this is important for brush models which load specially)
3143 // vertex buffer is several arrays and we put them in the same buffer
3145 // is this wise? the texcoordtexture2f array is used with dynamic
3146 // vertex/svector/tvector/normal when rendering animated models, on the
3147 // other hand animated models don't use a lot of vertices anyway...
3148 if (!loadmodel->surfmesh.vbo_vertexbuffer && !vid.useinterleavedarrays)
3153 loadmodel->surfmesh.vbooffset_vertexmesh = size;if (loadmodel->surfmesh.data_vertexmesh ) size += loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t);
3154 loadmodel->surfmesh.vbooffset_vertex3f = size;if (loadmodel->surfmesh.data_vertex3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3155 loadmodel->surfmesh.vbooffset_svector3f = size;if (loadmodel->surfmesh.data_svector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3156 loadmodel->surfmesh.vbooffset_tvector3f = size;if (loadmodel->surfmesh.data_tvector3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3157 loadmodel->surfmesh.vbooffset_normal3f = size;if (loadmodel->surfmesh.data_normal3f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[3]);
3158 loadmodel->surfmesh.vbooffset_texcoordtexture2f = size;if (loadmodel->surfmesh.data_texcoordtexture2f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3159 loadmodel->surfmesh.vbooffset_texcoordlightmap2f = size;if (loadmodel->surfmesh.data_texcoordlightmap2f) size += loadmodel->surfmesh.num_vertices * sizeof(float[2]);
3160 loadmodel->surfmesh.vbooffset_lightmapcolor4f = size;if (loadmodel->surfmesh.data_lightmapcolor4f ) size += loadmodel->surfmesh.num_vertices * sizeof(float[4]);
3161 loadmodel->surfmesh.vbooffset_skeletalindex4ub = size;if (loadmodel->surfmesh.data_skeletalindex4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3162 loadmodel->surfmesh.vbooffset_skeletalweight4ub = size;if (loadmodel->surfmesh.data_skeletalweight4ub ) size += loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]);
3163 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
3164 if (loadmodel->surfmesh.data_vertexmesh ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertexmesh , loadmodel->surfmesh.data_vertexmesh , loadmodel->surfmesh.num_vertices * sizeof(r_vertexmesh_t));
3165 if (loadmodel->surfmesh.data_vertex3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_vertex3f , loadmodel->surfmesh.data_vertex3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3166 if (loadmodel->surfmesh.data_svector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_svector3f , loadmodel->surfmesh.data_svector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3167 if (loadmodel->surfmesh.data_tvector3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_tvector3f , loadmodel->surfmesh.data_tvector3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3168 if (loadmodel->surfmesh.data_normal3f ) memcpy(mem + loadmodel->surfmesh.vbooffset_normal3f , loadmodel->surfmesh.data_normal3f , loadmodel->surfmesh.num_vertices * sizeof(float[3]));
3169 if (loadmodel->surfmesh.data_texcoordtexture2f ) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordtexture2f , loadmodel->surfmesh.data_texcoordtexture2f , loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3170 if (loadmodel->surfmesh.data_texcoordlightmap2f) memcpy(mem + loadmodel->surfmesh.vbooffset_texcoordlightmap2f, loadmodel->surfmesh.data_texcoordlightmap2f, loadmodel->surfmesh.num_vertices * sizeof(float[2]));
3171 if (loadmodel->surfmesh.data_lightmapcolor4f ) memcpy(mem + loadmodel->surfmesh.vbooffset_lightmapcolor4f , loadmodel->surfmesh.data_lightmapcolor4f , loadmodel->surfmesh.num_vertices * sizeof(float[4]));
3172 if (loadmodel->surfmesh.data_skeletalindex4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalindex4ub , loadmodel->surfmesh.data_skeletalindex4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3173 if (loadmodel->surfmesh.data_skeletalweight4ub ) memcpy(mem + loadmodel->surfmesh.vbooffset_skeletalweight4ub , loadmodel->surfmesh.data_skeletalweight4ub , loadmodel->surfmesh.num_vertices * sizeof(unsigned char[4]));
3174 loadmodel->surfmesh.vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mem, size, loadmodel->name, false, false, false, false);
3179 extern cvar_t mod_obj_orientation;
3180 static void Mod_Decompile_OBJ(dp_model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
3182 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
3184 const char *texname;
3186 const float *v, *vn, *vt;
3188 size_t outbufferpos = 0;
3189 size_t outbuffermax = 0x100000;
3190 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3191 const msurface_t *surface;
3192 const int maxtextures = 256;
3193 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
3194 dp_model_t *submodel;
3196 // construct the mtllib file
3197 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
3200 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3203 countvertices += surface->num_vertices;
3204 countfaces += surface->num_triangles;
3205 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
3206 for (textureindex = 0;textureindex < counttextures;textureindex++)
3207 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
3209 if (textureindex < counttextures)
3210 continue; // already wrote this material entry
3211 if (textureindex >= maxtextures)
3212 continue; // just a precaution
3213 textureindex = counttextures++;
3214 strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
3215 if (outbufferpos >= outbuffermax >> 1)
3218 oldbuffer = outbuffer;
3219 outbuffer = (char *) Z_Malloc(outbuffermax);
3220 memcpy(outbuffer, oldbuffer, outbufferpos);
3223 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");
3228 // write the mtllib file
3229 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3231 // construct the obj file
3233 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);
3237 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)
3239 if (outbufferpos >= outbuffermax >> 1)
3242 oldbuffer = outbuffer;
3243 outbuffer = (char *) Z_Malloc(outbuffermax);
3244 memcpy(outbuffer, oldbuffer, outbufferpos);
3247 if(mod_obj_orientation.integer)
3248 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]);
3250 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]);
3255 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3257 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3260 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3261 for (surfaceindex = 0;surfaceindex < submodel->nummodelsurfaces;surfaceindex++)
3263 surface = model->data_surfaces + submodel->sortedmodelsurfaces[surfaceindex];
3264 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3267 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3269 if (outbufferpos >= outbuffermax >> 1)
3272 oldbuffer = outbuffer;
3273 outbuffer = (char *) Z_Malloc(outbuffermax);
3274 memcpy(outbuffer, oldbuffer, outbufferpos);
3280 if(mod_obj_orientation.integer)
3281 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);
3283 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);
3290 // write the obj file
3291 FS_WriteFile(filename, outbuffer, outbufferpos);
3295 Z_Free(texturenames);
3298 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3301 static void Mod_Decompile_SMD(dp_model_t *model, const char *filename, int firstpose, int numposes, qboolean writetriangles)
3303 int countnodes = 0, counttriangles = 0, countframes = 0;
3311 size_t outbufferpos = 0;
3312 size_t outbuffermax = 0x100000;
3313 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3314 const msurface_t *surface;
3315 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3318 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3320 if (outbufferpos >= outbuffermax >> 1)
3323 oldbuffer = outbuffer;
3324 outbuffer = (char *) Z_Malloc(outbuffermax);
3325 memcpy(outbuffer, oldbuffer, outbufferpos);
3329 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3333 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3336 for (poseindex = 0;poseindex < numposes;poseindex++)
3339 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3342 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3346 matrix4x4_t posematrix;
3347 if (outbufferpos >= outbuffermax >> 1)
3350 oldbuffer = outbuffer;
3351 outbuffer = (char *) Z_Malloc(outbuffermax);
3352 memcpy(outbuffer, oldbuffer, outbufferpos);
3356 // strangely the smd angles are for a transposed matrix, so we
3357 // have to generate a transposed matrix, then convert that...
3358 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3359 Matrix4x4_ToArray12FloatGL(&posematrix, mtest[0]);
3360 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3361 if (angles[0] >= 180) angles[0] -= 360;
3362 if (angles[1] >= 180) angles[1] -= 360;
3363 if (angles[2] >= 180) angles[2] -= 360;
3367 float a = DEG2RAD(angles[ROLL]);
3368 float b = DEG2RAD(angles[PITCH]);
3369 float c = DEG2RAD(angles[YAW]);
3370 float cy, sy, cp, sp, cr, sr;
3372 // smd matrix construction, for comparing
3383 test[1][0] = sr*sp*cy+cr*-sy;
3384 test[1][1] = sr*sp*sy+cr*cy;
3386 test[2][0] = (cr*sp*cy+-sr*-sy);
3387 test[2][1] = (cr*sp*sy+-sr*cy);
3389 test[3][0] = pose[9];
3390 test[3][1] = pose[10];
3391 test[3][2] = pose[11];
3394 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]));
3399 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3404 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3407 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3409 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3412 if (outbufferpos >= outbuffermax >> 1)
3415 oldbuffer = outbuffer;
3416 outbuffer = (char *) Z_Malloc(outbuffermax);
3417 memcpy(outbuffer, oldbuffer, outbufferpos);
3420 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3423 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3425 const int index = e[2-cornerindex];
3426 const float *v = model->surfmesh.data_vertex3f + index * 3;
3427 const float *vn = model->surfmesh.data_normal3f + index * 3;
3428 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3429 const int b = model->surfmesh.blends[index];
3430 if (b < model->num_bones)
3431 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]);
3434 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3435 const unsigned char *wi = w->index;
3436 const unsigned char *wf = w->influence;
3437 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);
3438 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);
3439 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);
3440 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]);
3447 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3452 FS_WriteFile(filename, outbuffer, outbufferpos);
3455 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3462 decompiles a model to editable files
3465 static void Mod_Decompile_f(void)
3467 int i, j, k, l, first, count;
3469 char inname[MAX_QPATH];
3470 char outname[MAX_QPATH];
3471 char mtlname[MAX_QPATH];
3472 char basename[MAX_QPATH];
3473 char animname[MAX_QPATH];
3474 char animname2[MAX_QPATH];
3475 char zymtextbuffer[16384];
3476 char dpmtextbuffer[16384];
3477 char framegroupstextbuffer[16384];
3478 int zymtextsize = 0;
3479 int dpmtextsize = 0;
3480 int framegroupstextsize = 0;
3483 if (Cmd_Argc() != 2)
3485 Con_Print("usage: modeldecompile <filename>\n");
3489 strlcpy(inname, Cmd_Argv(1), sizeof(inname));
3490 FS_StripExtension(inname, basename, sizeof(basename));
3492 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3495 Con_Print("No such model\n");
3498 if (mod->brush.submodel)
3500 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3501 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3502 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3505 if (!mod->surfmesh.num_triangles)
3507 Con_Print("Empty model (or sprite)\n");
3511 // export OBJ if possible (not on sprites)
3512 if (mod->surfmesh.num_triangles)
3514 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3515 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3516 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3519 // export SMD if possible (only for skeletal models)
3520 if (mod->surfmesh.num_triangles && mod->num_bones)
3522 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3523 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3524 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3525 if (l > 0) zymtextsize += l;
3526 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3527 if (l > 0) dpmtextsize += l;
3528 for (i = 0;i < mod->numframes;i = j)
3530 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3531 first = mod->animscenes[i].firstframe;
3532 if (mod->animscenes[i].framecount > 1)
3535 count = mod->animscenes[i].framecount;
3541 // check for additional frames with same name
3542 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3543 if(animname[l] < '0' || animname[l] > '9')
3545 if(k > 0 && animname[k-1] == '_')
3548 count = mod->num_poses - first;
3549 for (j = i + 1;j < mod->numframes;j++)
3551 strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3552 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3553 if(animname2[l] < '0' || animname2[l] > '9')
3555 if(k > 0 && animname[k-1] == '_')
3558 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3560 count = mod->animscenes[j].firstframe - first;
3564 // if it's only one frame, use the original frame name
3566 strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3569 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3570 Mod_Decompile_SMD(mod, outname, first, count, false);
3571 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3573 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3574 if (l > 0) zymtextsize += l;
3576 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3578 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3579 if (l > 0) dpmtextsize += l;
3581 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3583 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3584 if (l > 0) framegroupstextsize += l;
3588 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3590 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3591 if (framegroupstextsize)
3592 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3596 void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
3599 memset(state, 0, sizeof(*state));
3600 state->width = width;
3601 state->height = height;
3602 state->currentY = 0;
3603 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3604 for (y = 0;y < state->height;y++)
3606 state->rows[y].currentX = 0;
3607 state->rows[y].rowY = -1;
3611 void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
3614 state->currentY = 0;
3615 for (y = 0;y < state->height;y++)
3617 state->rows[y].currentX = 0;
3618 state->rows[y].rowY = -1;
3622 void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
3625 Mem_Free(state->rows);
3626 memset(state, 0, sizeof(*state));
3629 qboolean Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3631 mod_alloclightmap_row_t *row;
3634 row = state->rows + blockheight;
3635 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3637 if (state->currentY + blockheight <= state->height)
3639 // use the current allocation position
3640 row->rowY = state->currentY;
3642 state->currentY += blockheight;
3646 // find another position
3647 for (y = blockheight;y < state->height;y++)
3649 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3651 row = state->rows + y;
3655 if (y == state->height)
3660 *outx = row->currentX;
3661 row->currentX += blockwidth;
3666 typedef struct lightmapsample_s
3670 float *vertex_color;
3671 unsigned char *lm_bgr;
3672 unsigned char *lm_dir;
3676 typedef struct lightmapvertex_s
3681 float texcoordbase[2];
3682 float texcoordlightmap[2];
3683 float lightcolor[4];
3687 typedef struct lightmaptriangle_s
3695 // 2D modelspace coordinates of min corner
3696 // snapped to lightmap grid but not in grid coordinates
3698 // 2D modelspace to lightmap coordinate scale
3706 typedef struct lightmaplight_s
3717 lightmaptriangle_t *mod_generatelightmaps_lightmaptriangles;
3719 #define MAX_LIGHTMAPSAMPLES 64
3720 static int mod_generatelightmaps_numoffsets[3];
3721 static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3];
3723 static int mod_generatelightmaps_numlights;
3724 static lightmaplight_t *mod_generatelightmaps_lightinfo;
3726 extern cvar_t r_shadow_lightattenuationdividebias;
3727 extern cvar_t r_shadow_lightattenuationlinearscale;
3729 static void Mod_GenerateLightmaps_LightPoint(dp_model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3734 float relativepoint[3];
3741 float lightorigin[3];
3745 float lightcolor[3];
3747 for (i = 0;i < 5*3;i++)
3749 for (index = 0;;index++)
3751 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3756 lightradius2 = lightradius * lightradius;
3757 VectorSubtract(lightorigin, pos, relativepoint);
3758 dist2 = VectorLength2(relativepoint);
3759 if (dist2 >= lightradius2)
3761 lightiradius = 1.0f / lightradius;
3762 dist = sqrt(dist2) * lightiradius;
3763 intensity = (1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist);
3764 if (intensity <= 0.0f)
3766 if (model && model->TraceLine)
3768 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3769 if (trace.fraction < 1)
3772 // scale down intensity to add to both ambient and diffuse
3773 //intensity *= 0.5f;
3774 VectorNormalize(relativepoint);
3775 VectorScale(lightcolor, intensity, color);
3776 VectorMA(sample , 0.5f , color, sample );
3777 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3778 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3779 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3780 // calculate a weighted average light direction as well
3781 intensity *= VectorLength(color);
3782 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3784 // calculate the direction we'll use to reduce the sample to a directional light source
3785 VectorCopy(sample + 12, dir);
3786 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3787 VectorNormalize(dir);
3788 // extract the diffuse color along the chosen direction and scale it
3789 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3790 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3791 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3792 // subtract some of diffuse from ambient
3793 VectorMA(sample, -0.333f, diffuse, ambient);
3794 // store the normalized lightdir
3795 VectorCopy(dir, lightdir);
3798 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const dp_model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
3802 const msurface_t *surface;
3803 const float *vertex3f = model->surfmesh.data_vertex3f;
3804 const int *element3i = model->surfmesh.data_element3i;
3807 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->nummodelsurfaces;surfaceindex++, surface++)
3809 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3811 if (surface->texture->basematerialflags & MATERIALFLAG_NOSHADOW)
3813 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3815 VectorCopy(vertex3f + 3*e[0], v2[0]);
3816 VectorCopy(vertex3f + 3*e[1], v2[1]);
3817 VectorCopy(vertex3f + 3*e[2], v2[2]);
3818 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3823 static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(dp_model_t *model, lightmaplight_t *lightinfo)
3825 int maxnodes = 1<<14;
3826 svbsp_node_t *nodes;
3831 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3832 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3833 VectorCopy(lightinfo->origin, origin);
3834 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3837 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3838 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(model, &svbsp, mins, maxs);
3839 if (svbsp.ranoutofnodes)
3842 if (maxnodes > 1<<22)
3848 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3853 if (svbsp.numnodes > 0)
3855 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3856 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3857 lightinfo->svbsp = svbsp;
3862 static void Mod_GenerateLightmaps_CreateLights(dp_model_t *model)
3866 lightmaplight_t *lightinfo;
3870 mod_generatelightmaps_numlights = 0;
3871 for (index = 0;;index++)
3873 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3877 mod_generatelightmaps_numlights++;
3879 if (mod_generatelightmaps_numlights > 0)
3881 mod_generatelightmaps_lightinfo = (lightmaplight_t *)Mem_Alloc(tempmempool, mod_generatelightmaps_numlights * sizeof(*mod_generatelightmaps_lightinfo));
3882 lightinfo = mod_generatelightmaps_lightinfo;
3883 for (index = 0;;index++)
3885 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3892 for (index = 0, lightinfo = mod_generatelightmaps_lightinfo;index < mod_generatelightmaps_numlights;index++, lightinfo++)
3894 lightinfo->iradius = 1.0f / lightinfo->radius;
3895 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3896 // TODO: compute svbsp
3897 Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model, lightinfo);
3901 static void Mod_GenerateLightmaps_DestroyLights(dp_model_t *model)
3904 if (mod_generatelightmaps_lightinfo)
3906 for (i = 0;i < mod_generatelightmaps_numlights;i++)
3907 if (mod_generatelightmaps_lightinfo[i].svbsp.nodes)
3908 Mem_Free(mod_generatelightmaps_lightinfo[i].svbsp.nodes);
3909 Mem_Free(mod_generatelightmaps_lightinfo);
3911 mod_generatelightmaps_lightinfo = NULL;
3912 mod_generatelightmaps_numlights = 0;
3915 static qboolean Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3917 const svbsp_node_t *node;
3918 const svbsp_node_t *nodes = svbsp->nodes;
3923 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3925 return num == -1; // true if empty, false if solid (shadowed)
3928 static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3931 float relativepoint[3];
3940 const lightmaplight_t *lightinfo;
3942 for (i = 0;i < 5*3;i++)
3944 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3946 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3947 VectorSubtract(lightinfo->origin, pos, relativepoint);
3948 // don't accept light from behind a surface, it causes bad shading
3949 if (normal && DotProduct(relativepoint, normal) <= 0)
3951 dist2 = VectorLength2(relativepoint);
3952 if (dist2 >= lightinfo->radius2)
3954 dist = sqrt(dist2) * lightinfo->iradius;
3955 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3958 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3962 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3964 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3966 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3969 // for light grid we'd better check visibility of the offset point
3970 cl.worldmodel->TraceLine(cl.worldmodel, NULL, NULL, &trace, pos, offsetpos, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3971 if (trace.fraction < 1)
3972 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3975 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3980 // scale intensity according to how many rays succeeded
3981 // we know one test is valid, half of the rest will fail...
3982 //if (normal && tests > 1)
3983 // intensity *= (tests - 1.0f) / tests;
3984 intensity *= (float)hits / tests;
3986 // scale down intensity to add to both ambient and diffuse
3987 //intensity *= 0.5f;
3988 VectorNormalize(relativepoint);
3989 VectorScale(lightinfo->color, intensity, color);
3990 VectorMA(sample , 0.5f , color, sample );
3991 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3992 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3993 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3994 // calculate a weighted average light direction as well
3995 intensity *= VectorLength(color);
3996 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
4000 static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
4006 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[0], mod_generatelightmaps_offsets[0][0]);
4007 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
4008 VectorCopy(sample + 12, dir);
4009 VectorNormalize(dir);
4010 //VectorAdd(dir, normal, dir);
4011 //VectorNormalize(dir);
4012 f = DotProduct(dir, normal);
4013 f = max(0, f) * 255.0f;
4014 VectorScale(sample, f, color);
4015 //VectorCopy(normal, dir);
4016 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
4017 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
4018 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
4019 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
4021 lm_dir[0] = (unsigned char)dir[2];
4022 lm_dir[1] = (unsigned char)dir[1];
4023 lm_dir[2] = (unsigned char)dir[0];
4027 static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
4030 Mod_GenerateLightmaps_SamplePoint(pos, normal, sample, mod_generatelightmaps_numoffsets[1], mod_generatelightmaps_offsets[1][0]);
4031 VectorCopy(sample, vertex_color);
4034 static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
4040 Mod_GenerateLightmaps_SamplePoint(pos, NULL, sample, mod_generatelightmaps_numoffsets[2], mod_generatelightmaps_offsets[2][0]);
4041 // calculate the direction we'll use to reduce the sample to a directional light source
4042 VectorCopy(sample + 12, dir);
4043 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
4044 VectorNormalize(dir);
4045 // extract the diffuse color along the chosen direction and scale it
4046 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
4047 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
4048 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
4049 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
4050 VectorScale(sample, 127.5f, ambient);
4051 VectorMA(ambient, -0.333f, diffuse, ambient);
4052 // encode to the grid format
4053 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
4054 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
4055 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
4056 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
4057 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
4058 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
4059 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
4060 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
4061 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));}
4064 static void Mod_GenerateLightmaps_InitSampleOffsets(dp_model_t *model)
4069 memset(mod_generatelightmaps_offsets, 0, sizeof(mod_generatelightmaps_offsets));
4070 mod_generatelightmaps_numoffsets[0] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_lightmapsamples.integer);
4071 mod_generatelightmaps_numoffsets[1] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_vertexsamples.integer);
4072 mod_generatelightmaps_numoffsets[2] = min(MAX_LIGHTMAPSAMPLES, mod_generatelightmaps_gridsamples.integer);
4073 radius[0] = mod_generatelightmaps_lightmapradius.value;
4074 radius[1] = mod_generatelightmaps_vertexradius.value;
4075 radius[2] = mod_generatelightmaps_gridradius.value;
4076 for (i = 0;i < 3;i++)
4078 for (j = 1;j < mod_generatelightmaps_numoffsets[i];j++)
4081 VectorScale(temp, radius[i], mod_generatelightmaps_offsets[i][j]);
4086 static void Mod_GenerateLightmaps_DestroyLightmaps(dp_model_t *model)
4088 msurface_t *surface;
4091 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4093 surface = model->data_surfaces + surfaceindex;
4094 surface->lightmaptexture = NULL;
4095 surface->deluxemaptexture = NULL;
4097 if (model->brushq3.data_lightmaps)
4099 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4100 if (model->brushq3.data_lightmaps[i])
4101 R_FreeTexture(model->brushq3.data_lightmaps[i]);
4102 Mem_Free(model->brushq3.data_lightmaps);
4103 model->brushq3.data_lightmaps = NULL;
4105 if (model->brushq3.data_deluxemaps)
4107 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
4108 if (model->brushq3.data_deluxemaps[i])
4109 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
4110 Mem_Free(model->brushq3.data_deluxemaps);
4111 model->brushq3.data_deluxemaps = NULL;
4115 static void Mod_GenerateLightmaps_UnweldTriangles(dp_model_t *model)
4117 msurface_t *surface;
4123 surfmesh_t oldsurfmesh;
4125 unsigned char *data;
4126 oldsurfmesh = model->surfmesh;
4127 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
4128 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
4130 size += model->surfmesh.num_vertices * sizeof(float[3]);
4131 size += model->surfmesh.num_vertices * sizeof(float[3]);
4132 size += model->surfmesh.num_vertices * sizeof(float[3]);
4133 size += model->surfmesh.num_vertices * sizeof(float[3]);
4134 size += model->surfmesh.num_vertices * sizeof(float[2]);
4135 size += model->surfmesh.num_vertices * sizeof(float[2]);
4136 size += model->surfmesh.num_vertices * sizeof(float[4]);
4137 data = (unsigned char *)Mem_Alloc(model->mempool, size);
4138 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4139 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4140 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4141 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
4142 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4143 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
4144 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
4145 if (model->surfmesh.num_vertices > 65536)
4146 model->surfmesh.data_element3s = NULL;
4148 if (model->surfmesh.data_element3i_indexbuffer)
4149 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
4150 model->surfmesh.data_element3i_indexbuffer = NULL;
4151 if (model->surfmesh.data_element3s_indexbuffer)
4152 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
4153 model->surfmesh.data_element3s_indexbuffer = NULL;
4154 if (model->surfmesh.vbo_vertexbuffer)
4155 R_Mesh_DestroyMeshBuffer(model->surfmesh.vbo_vertexbuffer);
4156 model->surfmesh.vbo_vertexbuffer = 0;
4158 // convert all triangles to unique vertex data
4160 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4162 surface = model->data_surfaces + surfaceindex;
4163 surface->num_firstvertex = outvertexindex;
4164 surface->num_vertices = surface->num_triangles*3;
4165 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
4166 for (i = 0;i < surface->num_triangles*3;i++)
4169 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
4170 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
4171 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
4172 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
4173 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
4174 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
4175 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
4176 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
4177 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
4178 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
4179 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
4180 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
4181 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
4182 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
4183 if (oldsurfmesh.data_texcoordlightmap2f)
4185 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
4186 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
4188 if (oldsurfmesh.data_lightmapcolor4f)
4190 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
4191 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
4192 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
4193 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
4196 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
4197 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
4201 if (model->surfmesh.data_element3s)
4202 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
4203 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
4205 // find and update all submodels to use this new surfmesh data
4206 for (i = 0;i < model->brush.numsubmodels;i++)
4207 model->brush.submodels[i]->surfmesh = model->surfmesh;
4210 static void Mod_GenerateLightmaps_CreateTriangleInformation(dp_model_t *model)
4212 msurface_t *surface;
4218 lightmaptriangle_t *triangle;
4219 // generate lightmap triangle structs
4220 mod_generatelightmaps_lightmaptriangles = (lightmaptriangle_t *)Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4221 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4223 surface = model->data_surfaces + surfaceindex;
4224 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4225 for (i = 0;i < surface->num_triangles;i++)
4227 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4228 triangle->triangleindex = surface->num_firsttriangle+i;
4229 triangle->surfaceindex = surfaceindex;
4230 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4231 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4232 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4233 // calculate bounds of triangle
4234 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4235 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4236 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4237 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4238 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4239 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4240 // pick an axial projection based on the triangle normal
4241 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4243 if (fabs(normal[1]) > fabs(normal[axis]))
4245 if (fabs(normal[2]) > fabs(normal[axis]))
4247 triangle->axis = axis;
4252 static void Mod_GenerateLightmaps_DestroyTriangleInformation(dp_model_t *model)
4254 if (mod_generatelightmaps_lightmaptriangles)
4255 Mem_Free(mod_generatelightmaps_lightmaptriangles);
4256 mod_generatelightmaps_lightmaptriangles = NULL;
4259 float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4261 static void Mod_GenerateLightmaps_CreateLightmaps(dp_model_t *model)
4263 msurface_t *surface;
4277 float trianglenormal[3];
4278 float samplecenter[3];
4279 float samplenormal[3];
4285 float lmscalepixels;
4288 float lm_basescalepixels;
4289 int lm_borderpixels;
4293 lightmaptriangle_t *triangle;
4294 unsigned char *lightmappixels;
4295 unsigned char *deluxemappixels;
4296 mod_alloclightmap_state_t lmstate;
4299 // generate lightmap projection information for all triangles
4300 if (model->texturepool == NULL)
4301 model->texturepool = R_AllocTexturePool();
4302 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4303 lm_borderpixels = mod_generatelightmaps_borderpixels.integer;
4304 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4305 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4306 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4308 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4310 surface = model->data_surfaces + surfaceindex;
4311 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4312 lmscalepixels = lm_basescalepixels;
4313 for (retry = 0;retry < 30;retry++)
4315 // after a couple failed attempts, degrade quality to make it fit
4317 lmscalepixels *= 0.5f;
4318 for (i = 0;i < surface->num_triangles;i++)
4320 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4321 triangle->lightmapindex = lightmapnumber;
4322 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4323 // pick two planar axes for projection
4324 // lightmap coordinates here are in pixels
4325 // lightmap projections are snapped to pixel grid explicitly, such
4326 // that two neighboring triangles sharing an edge and projection
4327 // axis will have identical sampl espacing along their shared edge
4329 for (j = 0;j < 3;j++)
4331 if (j == triangle->axis)
4333 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4334 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4335 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4336 triangle->lmbase[k] = lmmins/lmscalepixels;
4337 triangle->lmscale[k] = lmscalepixels;
4340 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4343 // if all fit in this texture, we're done with this surface
4344 if (i == surface->num_triangles)
4346 // if we haven't maxed out the lightmap size yet, we retry the
4347 // entire surface batch...
4348 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4350 lm_texturesize *= 2;
4353 Mod_AllocLightmap_Free(&lmstate);
4354 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4357 // if we have maxed out the lightmap size, and this triangle does
4358 // not fit in the same texture as the rest of the surface, we have
4359 // to retry the entire surface in a new texture (can only use one)
4360 // with multiple retries, the lightmap quality degrades until it
4361 // fits (or gives up)
4362 if (surfaceindex > 0)
4364 Mod_AllocLightmap_Reset(&lmstate);
4368 Mod_AllocLightmap_Free(&lmstate);
4370 // now put triangles together into lightmap textures, and do not allow
4371 // triangles of a surface to go into different textures (as that would
4372 // require rewriting the surface list)
4373 model->brushq3.deluxemapping_modelspace = true;
4374 model->brushq3.deluxemapping = true;
4375 model->brushq3.num_mergedlightmaps = lightmapnumber;
4376 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4377 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4378 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4379 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4380 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4382 surface = model->data_surfaces + surfaceindex;
4383 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4384 for (i = 0;i < surface->num_triangles;i++)
4386 triangle = &mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle+i];
4387 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4388 VectorNormalize(trianglenormal);
4389 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4390 axis = triangle->axis;
4391 axis1 = axis == 0 ? 1 : 0;
4392 axis2 = axis == 2 ? 1 : 2;
4393 lmiscale[0] = 1.0f / triangle->lmscale[0];
4394 lmiscale[1] = 1.0f / triangle->lmscale[1];
4395 if (trianglenormal[axis] < 0)
4396 VectorNegate(trianglenormal, trianglenormal);
4397 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4398 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4399 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4400 for (j = 0;j < 3;j++)
4402 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4403 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4404 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4406 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4407 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4408 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4409 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]);
4419 forward[1] = 1.0f / triangle->lmscale[0];
4423 left[2] = 1.0f / triangle->lmscale[1];
4428 origin[1] = triangle->lmbase[0];
4429 origin[2] = triangle->lmbase[1];
4432 forward[0] = 1.0f / triangle->lmscale[0];
4437 left[2] = 1.0f / triangle->lmscale[1];
4441 origin[0] = triangle->lmbase[0];
4443 origin[2] = triangle->lmbase[1];
4446 forward[0] = 1.0f / triangle->lmscale[0];
4450 left[1] = 1.0f / triangle->lmscale[1];
4455 origin[0] = triangle->lmbase[0];
4456 origin[1] = triangle->lmbase[1];
4460 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4462 #define LM_DIST_EPSILON (1.0f / 32.0f)
4463 for (y = 0;y < triangle->lmsize[1];y++)
4465 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4466 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4468 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4469 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4470 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4471 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4472 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4478 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4480 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);
4481 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);
4485 Mem_Free(lightmappixels);
4486 if (deluxemappixels)
4487 Mem_Free(deluxemappixels);
4489 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4491 surface = model->data_surfaces + surfaceindex;
4492 if (!surface->num_triangles)
4494 lightmapindex = mod_generatelightmaps_lightmaptriangles[surface->num_firsttriangle].lightmapindex;
4495 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4496 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4497 surface->lightmapinfo = NULL;
4500 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4501 model->brushq1.lightdata = NULL;
4502 model->brushq1.lightmapupdateflags = NULL;
4503 model->brushq1.firstrender = false;
4504 model->brushq1.num_lightstyles = 0;
4505 model->brushq1.data_lightstyleinfo = NULL;
4506 for (i = 0;i < model->brush.numsubmodels;i++)
4508 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4509 model->brush.submodels[i]->brushq1.firstrender = false;
4510 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4511 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4515 static void Mod_GenerateLightmaps_UpdateVertexColors(dp_model_t *model)
4518 for (i = 0;i < model->surfmesh.num_vertices;i++)
4519 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4522 static void Mod_GenerateLightmaps_UpdateLightGrid(dp_model_t *model)
4529 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4531 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4532 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4534 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4535 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4537 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4538 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4544 extern cvar_t mod_q3bsp_nolightmaps;
4545 static void Mod_GenerateLightmaps(dp_model_t *model)
4547 //lightmaptriangle_t *lightmaptriangles = Mem_Alloc(model->mempool, model->surfmesh.num_triangles * sizeof(lightmaptriangle_t));
4548 dp_model_t *oldloadmodel = loadmodel;
4551 Mod_GenerateLightmaps_InitSampleOffsets(model);
4552 Mod_GenerateLightmaps_DestroyLightmaps(model);
4553 Mod_GenerateLightmaps_UnweldTriangles(model);
4554 Mod_GenerateLightmaps_CreateTriangleInformation(model);
4555 Mod_GenerateLightmaps_CreateLights(model);
4556 if(!mod_q3bsp_nolightmaps.integer)
4557 Mod_GenerateLightmaps_CreateLightmaps(model);
4558 Mod_GenerateLightmaps_UpdateVertexColors(model);
4559 Mod_GenerateLightmaps_UpdateLightGrid(model);
4560 Mod_GenerateLightmaps_DestroyLights(model);
4561 Mod_GenerateLightmaps_DestroyTriangleInformation(model);
4563 loadmodel = oldloadmodel;
4566 static void Mod_GenerateLightmaps_f(void)
4568 if (Cmd_Argc() != 1)
4570 Con_Printf("usage: mod_generatelightmaps\n");
4575 Con_Printf("no worldmodel loaded\n");
4578 Mod_GenerateLightmaps(cl.worldmodel);
4581 void Mod_Mesh_Create(dp_model_t *mod, const char *name)
4583 memset(mod, 0, sizeof(*mod));
4584 strlcpy(mod->name, name, sizeof(mod->name));
4585 mod->mempool = Mem_AllocPool(name, 0, NULL);
4586 mod->texturepool = R_AllocTexturePool();
4587 mod->Draw = R_Q1BSP_Draw;
4588 mod->DrawDepth = R_Q1BSP_DrawDepth;
4589 mod->DrawDebug = R_Q1BSP_DrawDebug;
4590 mod->DrawPrepass = R_Q1BSP_DrawPrepass;
4591 mod->GetLightInfo = R_Q1BSP_GetLightInfo;
4592 mod->DrawShadowMap = R_Q1BSP_DrawShadowMap;
4593 mod->DrawShadowVolume = R_Q1BSP_DrawShadowVolume;
4594 mod->DrawLight = R_Q1BSP_DrawLight;
4597 void Mod_Mesh_Destroy(dp_model_t *mod)
4599 Mod_UnloadModel(mod);
4602 // resets the mesh model to have no geometry to render, ready for a new frame -
4603 // the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4604 void Mod_Mesh_Reset(dp_model_t *mod)
4606 mod->num_surfaces = 0;
4607 mod->surfmesh.num_vertices = 0;
4608 mod->surfmesh.num_triangles = 0;
4609 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4610 mod->DrawSky = NULL; // will be set if a texture needs it
4611 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4614 texture_t *Mod_Mesh_GetTexture(dp_model_t *mod, const char *name)
4618 for (i = 0; i < mod->num_textures; i++)
4619 if (!strcmp(mod->data_textures[i].name, name))
4620 return mod->data_textures + i;
4621 if (mod->max_textures <= mod->num_textures)
4623 texture_t *oldtextures = mod->data_textures;
4624 mod->max_textures = max(mod->max_textures * 2, 1024);
4625 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4626 // update the pointers
4627 for (i = 0; i < mod->num_surfaces; i++)
4628 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4630 t = &mod->data_textures[mod->num_textures++];
4631 Mod_LoadTextureFromQ3Shader(t, name, false, true, 0);
4635 msurface_t *Mod_Mesh_AddSurface(dp_model_t *mod, texture_t *tex)
4638 // check if the proposed surface matches the last one we created
4639 if (mod->num_surfaces == 0 || mod->data_surfaces[mod->num_surfaces - 1].texture != tex)
4641 if (mod->max_surfaces == mod->num_surfaces)
4643 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4644 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4645 mod->sortedmodelsurfaces = (int *)Mem_Realloc(mod->mempool, mod->sortedmodelsurfaces, mod->max_surfaces * sizeof(*mod->sortedmodelsurfaces));
4647 surf = mod->data_surfaces + mod->num_surfaces;
4648 mod->num_surfaces++;
4649 memset(surf, 0, sizeof(*surf));
4650 surf->texture = tex;
4651 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4652 surf->num_firstvertex = mod->surfmesh.num_vertices;
4653 if (tex->basematerialflags & (MATERIALFLAG_SKY))
4654 mod->DrawSky = R_Q1BSP_DrawSky;
4655 if (tex->basematerialflags & (MATERIALFLAG_WATERSHADER | MATERIALFLAG_REFRACTION | MATERIALFLAG_REFLECTION | MATERIALFLAG_CAMERA))
4656 mod->DrawAddWaterPlanes = R_Q1BSP_DrawAddWaterPlanes;
4659 return mod->data_surfaces + mod->num_surfaces - 1;
4662 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)
4664 int hashindex, h, vnum, mask;
4665 surfmesh_t *mesh = &mod->surfmesh;
4666 if (mesh->max_vertices == mesh->num_vertices)
4668 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4669 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4670 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4671 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4672 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4673 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4674 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4675 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4676 // rebuild the hash table
4677 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4678 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4679 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4680 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4681 mask = mod->surfmesh.num_vertexhashsize - 1;
4682 // no need to hash the vertices for the entire model, the latest surface will suffice.
4683 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4685 // this uses prime numbers intentionally for computing the hash
4686 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;
4687 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4688 ; // just iterate until we find the terminator
4689 mesh->data_vertexhash[h] = vnum;
4692 mask = mod->surfmesh.num_vertexhashsize - 1;
4693 // this uses prime numbers intentionally for computing the hash
4694 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4695 // when possible find an identical vertex within the same surface and return it
4696 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4698 if (vnum >= surf->num_firstvertex
4699 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4700 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4701 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4702 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4703 && 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)
4706 // add the new vertex
4707 vnum = mesh->num_vertices++;
4708 if (surf->num_vertices > 0)
4710 if (surf->mins[0] > x) surf->mins[0] = x;
4711 if (surf->mins[1] > y) surf->mins[1] = y;
4712 if (surf->mins[2] > z) surf->mins[2] = z;
4713 if (surf->maxs[0] < x) surf->maxs[0] = x;
4714 if (surf->maxs[1] < y) surf->maxs[1] = y;
4715 if (surf->maxs[2] < z) surf->maxs[2] = z;
4719 VectorSet(surf->mins, x, y, z);
4720 VectorSet(surf->maxs, x, y, z);
4722 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4723 mesh->data_vertexhash[h] = vnum;
4724 mesh->data_vertex3f[vnum * 3 + 0] = x;
4725 mesh->data_vertex3f[vnum * 3 + 1] = y;
4726 mesh->data_vertex3f[vnum * 3 + 2] = z;
4727 mesh->data_normal3f[vnum * 3 + 0] = nx;
4728 mesh->data_normal3f[vnum * 3 + 1] = ny;
4729 mesh->data_normal3f[vnum * 3 + 2] = nz;
4730 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4731 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4732 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4733 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4734 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4735 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4736 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4737 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4741 void Mod_Mesh_AddTriangle(dp_model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4743 surfmesh_t *mesh = &mod->surfmesh;
4744 if (mesh->max_triangles == mesh->num_triangles)
4746 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4747 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4748 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4750 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4751 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4752 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4753 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4754 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4755 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4756 mesh->num_triangles++;
4757 surf->num_triangles++;
4760 static void Mod_Mesh_MakeSortedSurfaces(dp_model_t *mod)
4764 msurface_t *surf, *surf2;
4766 // build the sorted surfaces list properly to reduce material setup
4767 // this is easy because we're just sorting on texture and don't care about the order of textures
4768 mod->nummodelsurfaces = 0;
4769 for (i = 0; i < mod->num_surfaces; i++)
4770 mod->data_surfaces[i].included = false;
4771 for (i = 0; i < mod->num_surfaces; i++)
4773 surf = mod->data_surfaces + i;
4776 tex = surf->texture;
4777 // j = i is intentional
4778 for (j = i; j < mod->num_surfaces; j++)
4780 surf2 = mod->data_surfaces + j;
4781 if (surf2->included)
4783 if (surf2->texture == tex)
4785 surf2->included = true;
4786 mod->sortedmodelsurfaces[mod->nummodelsurfaces++] = j;
4792 void Mod_Mesh_ComputeBounds(dp_model_t *mod)
4795 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4797 if (mod->surfmesh.num_vertices > 0)
4799 // calculate normalmins/normalmaxs
4800 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4801 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4802 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4804 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4805 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4806 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4807 // expand bounds to include this vertex
4808 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4809 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4810 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4811 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4812 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4813 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4815 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4816 // (fast but less accurate than doing it per vertex)
4817 x2a = mod->normalmins[0] * mod->normalmins[0];
4818 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4819 y2a = mod->normalmins[1] * mod->normalmins[1];
4820 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4821 z2a = mod->normalmins[2] * mod->normalmins[2];
4822 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4826 yawradius = sqrt(x2 + y2);
4827 rotatedradius = sqrt(x2 + y2 + z2);
4828 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4829 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4830 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4831 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4832 mod->radius = rotatedradius;
4833 mod->radius2 = x2 + y2 + z2;
4837 VectorClear(mod->normalmins);
4838 VectorClear(mod->normalmaxs);
4839 VectorClear(mod->yawmins);
4840 VectorClear(mod->yawmaxs);
4841 VectorClear(mod->rotatedmins);
4842 VectorClear(mod->rotatedmaxs);
4848 void Mod_Mesh_Finalize(dp_model_t *mod)
4850 Mod_Mesh_ComputeBounds(mod);
4851 Mod_Mesh_MakeSortedSurfaces(mod);
4852 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);