DarkPlaces
Game engine based on the Quake 1 engine by id Software, developed by LadyHavoc
 
model_shared.c
Go to the documentation of this file.
1/*
2Copyright (C) 1996-1997 Id Software, Inc.
3
4This program is free software; you can redistribute it and/or
5modify it under the terms of the GNU General Public License
6as published by the Free Software Foundation; either version 2
7of the License, or (at your option) any later version.
8
9This program is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13See the GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19*/
20// models.c -- model loading and caching
21
22// models are the only shared resource between a client and server running
23// on the same machine.
24
25#include "quakedef.h"
26#include "image.h"
27#include "r_shadow.h"
28#include "polygon.h"
29
30cvar_t r_mipskins = {CF_CLIENT | CF_ARCHIVE, "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"};
31cvar_t r_mipnormalmaps = {CF_CLIENT | CF_ARCHIVE, "r_mipnormalmaps", "1", "mipmaps normalmaps (turning it off looks sharper but may have aliasing)"};
32cvar_t mod_generatelightmaps_unitspersample = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_unitspersample", "8", "lightmap resolution"};
33cvar_t mod_generatelightmaps_borderpixels = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_borderpixels", "2", "extra space around polygons to prevent sampling artifacts"};
34cvar_t mod_generatelightmaps_texturesize = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_texturesize", "1024", "size of lightmap textures"};
35cvar_t mod_generatelightmaps_lightmapsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_lightmapsamples", "16", "number of shadow tests done per lightmap pixel"};
36cvar_t mod_generatelightmaps_vertexsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_vertexsamples", "16", "number of shadow tests done per vertex"};
37cvar_t mod_generatelightmaps_gridsamples = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_gridsamples", "64", "number of shadow tests done per lightgrid cell"};
38cvar_t mod_generatelightmaps_lightmapradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_lightmapradius", "16", "sampling area around each lightmap pixel"};
39cvar_t mod_generatelightmaps_vertexradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_vertexradius", "16", "sampling area around each vertex"};
40cvar_t mod_generatelightmaps_gridradius = {CF_CLIENT | CF_ARCHIVE, "mod_generatelightmaps_gridradius", "64", "sampling area around each lightgrid cell center"};
41
43
44// Supported model formats
46{
47 {"obj", NULL, 0, Mod_OBJ_Load},
48 {NULL, "IDPO", 4, Mod_IDP0_Load},
49 {NULL, "IDP2", 4, Mod_IDP2_Load},
50 {NULL, "IDP3", 4, Mod_IDP3_Load},
51 {NULL, "IDSP", 4, Mod_IDSP_Load},
52 {NULL, "IDS2", 4, Mod_IDS2_Load},
53 {NULL, "\035", 1, Mod_Q1BSP_Load},
54 {NULL, "\036", 1, Mod_HLBSP_Load},
55 {NULL, "BSP2", 4, Mod_BSP2_Load},
56 {NULL, "2PSB", 4, Mod_2PSB_Load},
57 {NULL, "IBSP", 4, Mod_IBSP_Load},
58 {NULL, "VBSP", 4, Mod_VBSP_Load},
59 {NULL, "ZYMOTICMODEL", 13, Mod_ZYMOTICMODEL_Load},
60 {NULL, "DARKPLACESMODEL", 16, Mod_DARKPLACESMODEL_Load},
61 {NULL, "PSKMODEL", 9, Mod_PSKMODEL_Load},
62 {NULL, "INTERQUAKEMODEL", 16, Mod_INTERQUAKEMODEL_Load},
63 {"map", NULL, 0, Mod_MAP_Load},
64 {NULL, NULL, 0, NULL}
65};
66
69
71typedef struct q3shader_hash_entry_s
72{
74 struct q3shader_hash_entry_s* chain;
76#define Q3SHADER_HASH_SIZE 1021
84
85static void mod_start(void)
86{
87 int i, count;
88 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
89 model_t *mod;
90
91 SCR_PushLoadingScreen("Loading models", 1.0);
92 count = 0;
93 for (i = 0;i < nummodels;i++)
94 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
95 if (mod->used)
96 ++count;
97 for (i = 0;i < nummodels;i++)
98 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
99 if (mod->used)
100 {
101 SCR_PushLoadingScreen(mod->name, 1.0 / count);
102 Mod_LoadModel(mod, true, false);
104 }
106}
107
108static void mod_shutdown(void)
109{
110 int i;
111 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
112 model_t *mod;
113
114 for (i = 0;i < nummodels;i++)
115 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && (mod->loaded || mod->mempool))
117
120}
121
122static void mod_newmap(void)
123{
124 msurface_t *surface;
125 int i, j, k, l, surfacenum, ssize, tsize;
126 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
127 model_t *mod;
128
129 for (i = 0;i < nummodels;i++)
130 {
131 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool)
132 {
133 for (j = 0;j < mod->num_textures && mod->data_textures;j++)
134 {
135 // note that materialshaderpass and backgroundshaderpass point to shaderpasses[] and so do the pre/post shader ranges, so this catches all of them...
136 for (l = 0; l < Q3SHADER_MAXLAYERS; l++)
137 if (mod->data_textures[j].shaderpasses[l])
138 for (k = 0; k < mod->data_textures[j].shaderpasses[l]->numframes; k++)
139 R_SkinFrame_MarkUsed(mod->data_textures[j].shaderpasses[l]->skinframes[k]);
140 }
141 if (mod->brush.solidskyskinframe)
142 R_SkinFrame_MarkUsed(mod->brush.solidskyskinframe);
143 if (mod->brush.alphaskyskinframe)
144 R_SkinFrame_MarkUsed(mod->brush.alphaskyskinframe);
145 }
146 }
147
149 return;
150
151 for (i = 0;i < nummodels;i++)
152 {
153 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->mempool && mod->data_surfaces)
154 {
155 for (surfacenum = 0, surface = mod->data_surfaces;surfacenum < mod->num_surfaces;surfacenum++, surface++)
156 {
157 if (surface->lightmapinfo && surface->lightmapinfo->stainsamples)
158 {
159 ssize = (surface->lightmapinfo->extents[0] >> 4) + 1;
160 tsize = (surface->lightmapinfo->extents[1] >> 4) + 1;
161 memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
162 mod->brushq1.lightmapupdateflags[surfacenum] = true;
163 }
164 }
165 }
166 }
167}
168
169/*
170===============
171Mod_Init
172===============
173*/
174static void Mod_Print_f(cmd_state_t *cmd);
175static void Mod_Precache_f(cmd_state_t *cmd);
176static void Mod_Decompile_f(cmd_state_t *cmd);
205
210
212{
213 char name[MAX_QPATH];
214 qbool used;
215 model_t *parentmodel;
216
218 Con_Printf("unloading model %s\n", mod->name);
219
220 dp_strlcpy(name, mod->name, sizeof(name));
221 parentmodel = mod->brush.parentmodel;
222 used = mod->used;
223 if (mod->mempool)
224 {
225 if (mod->surfmesh.data_element3i_indexbuffer && !mod->surfmesh.data_element3i_indexbuffer->isdynamic)
226 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3i_indexbuffer);
227 mod->surfmesh.data_element3i_indexbuffer = NULL;
228 if (mod->surfmesh.data_element3s_indexbuffer && !mod->surfmesh.data_element3s_indexbuffer->isdynamic)
229 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_element3s_indexbuffer);
230 mod->surfmesh.data_element3s_indexbuffer = NULL;
231 if (mod->surfmesh.data_vertex3f_vertexbuffer && !mod->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
232 R_Mesh_DestroyMeshBuffer(mod->surfmesh.data_vertex3f_vertexbuffer);
233 mod->surfmesh.data_vertex3f_vertexbuffer = NULL;
234 mod->surfmesh.data_svector3f_vertexbuffer = NULL;
235 mod->surfmesh.data_tvector3f_vertexbuffer = NULL;
236 mod->surfmesh.data_normal3f_vertexbuffer = NULL;
237 mod->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
238 mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
239 mod->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
240 mod->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
241 mod->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
242 }
243 // free textures/memory attached to the model
244 R_FreeTexturePool(&mod->texturepool);
245 Mem_FreePool(&mod->mempool);
246 // clear the struct to make it available
247 memset(mod, 0, sizeof(model_t));
248 // restore the fields we want to preserve
249 dp_strlcpy(mod->name, name, sizeof(mod->name));
250 mod->brush.parentmodel = parentmodel;
251 mod->used = used;
252 mod->loaded = false;
253}
254
256{
257 return;
258}
259
260
261typedef void (*mod_framegroupify_parsegroups_t) (unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass);
262
264{
265 const char *bufptr;
266 int start, len;
267 float fps;
268 unsigned int i;
269 qbool loop;
270 char name[64];
271
272 bufptr = buf;
273 i = 0;
274 while(bufptr)
275 {
276 // an anim scene!
277
278 // REQUIRED: fetch start
279 COM_ParseToken_Simple(&bufptr, true, false, true);
280 if (!bufptr)
281 break; // end of file
282 if (!strcmp(com_token, "\n"))
283 continue; // empty line
284 start = atoi(com_token);
285
286 // REQUIRED: fetch length
287 COM_ParseToken_Simple(&bufptr, true, false, true);
288 if (!bufptr || !strcmp(com_token, "\n"))
289 {
290 Con_Printf("framegroups file: missing number of frames\n");
291 continue;
292 }
293 len = atoi(com_token);
294
295 // OPTIONAL args start
296 COM_ParseToken_Simple(&bufptr, true, false, true);
297
298 // OPTIONAL: fetch fps
299 fps = 20;
300 if (bufptr && strcmp(com_token, "\n"))
301 {
302 fps = atof(com_token);
303 COM_ParseToken_Simple(&bufptr, true, false, true);
304 }
305
306 // OPTIONAL: fetch loopflag
307 loop = true;
308 if (bufptr && strcmp(com_token, "\n"))
309 {
310 loop = (atoi(com_token) != 0);
311 COM_ParseToken_Simple(&bufptr, true, false, true);
312 }
313
314 // OPTIONAL: fetch name
315 name[0] = 0;
316 if (bufptr && strcmp(com_token, "\n"))
317 {
318 dp_strlcpy(name, com_token, sizeof(name));
319 COM_ParseToken_Simple(&bufptr, true, false, true);
320 }
321
322 // OPTIONAL: remaining unsupported tokens (eat them)
323 while (bufptr && strcmp(com_token, "\n"))
324 COM_ParseToken_Simple(&bufptr, true, false, true);
325
326 //Con_Printf("data: %d %d %d %f %d (%s)\n", i, start, len, fps, loop, name);
327
328 if(cb)
329 cb(i, start, len, fps, loop, (name[0] ? name : NULL), pass);
330 ++i;
331 }
332
333 return i;
334}
335
336static void Mod_FrameGroupify_ParseGroups_Store (unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass)
337{
338 model_t *mod = (model_t *) pass;
339 animscene_t *anim = &mod->animscenes[i];
340 if(name)
341 dp_strlcpy(anim->name, name, sizeof(anim[i].name));
342 else
343 dpsnprintf(anim->name, sizeof(anim[i].name), "groupified_%d_anim", i);
344 anim->firstframe = bound(0, start, mod->num_poses - 1);
345 anim->framecount = bound(1, len, mod->num_poses - anim->firstframe);
346 anim->framerate = max(1, fps);
347 anim->loop = !!loop;
348 //Con_Printf("frame group %d is %d %d %f %d\n", i, start, len, fps, loop);
349}
350
351static void Mod_FrameGroupify(model_t *mod, const char *buf)
352{
353 unsigned int cnt;
354
355 // 0. count
357 if(!cnt)
358 {
359 Con_Printf("no scene found in framegroups file, aborting\n");
360 return;
361 }
362 mod->numframes = cnt;
363
364 // 1. reallocate
365 // (we do not free the previous animscenes, but model unloading will free the pool owning them, so it's okay)
366 mod->animscenes = (animscene_t *) Mem_Alloc(mod->mempool, sizeof(animscene_t) * mod->numframes);
367
368 // 2. parse
370}
371
373{
374 int i, j;
376 mod->wantnormals = false;
377 mod->wanttangents = false;
378 for (i = 0;i < mod->num_textures;i++)
379 {
380 texture = mod->data_textures + i;
381 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
382 mod->wantnormals = true;
383 if (texture->materialshaderpass && texture->materialshaderpass->tcgen.tcgen == Q3TCGEN_ENVIRONMENT)
384 mod->wantnormals = true;
385 for (j = 0;j < Q3MAXDEFORMS;j++)
386 {
387 if (texture->deforms[j].deform == Q3DEFORM_AUTOSPRITE)
388 {
389 mod->wanttangents = true;
390 mod->wantnormals = true;
391 break;
392 }
393 if (texture->deforms[j].deform != Q3DEFORM_NONE)
394 mod->wantnormals = true;
395 }
396 }
397}
398
399/*
400==================
401Mod_LoadModel
402
403Loads a model
404==================
405*/
407{
408 unsigned int crc;
409 void *buf;
410 fs_offset_t filesize = 0;
411 char vabuf[1024];
412
413 mod->used = true;
414
415 if (mod->name[0] == '*') // submodel
416 return mod;
417
418 if (!strcmp(mod->name, "null"))
419 {
420 if(mod->loaded)
421 return mod;
422
423 if (mod->loaded || mod->mempool)
425
427 Con_Printf("loading model %s\n", mod->name);
428
429 mod->used = true;
430 mod->crc = (unsigned int)-1;
431 mod->loaded = false;
432
433 VectorClear(mod->normalmins);
434 VectorClear(mod->normalmaxs);
435 VectorClear(mod->yawmins);
436 VectorClear(mod->yawmaxs);
437 VectorClear(mod->rotatedmins);
438 VectorClear(mod->rotatedmaxs);
439
440 mod->modeldatatypestring = "null";
441 mod->type = mod_null;
442 mod->Draw = R_Model_Null_Draw;
443 mod->numframes = 2;
444 mod->numskins = 1;
445
446 // no fatal errors occurred, so this model is ready to use.
447 mod->loaded = true;
448
449 return mod;
450 }
451
452 crc = 0;
453 buf = NULL;
454
455 // even if the model is loaded it still may need reloading...
456
457 // if it is not loaded or checkdisk is true we need to calculate the crc
458 if (!mod->loaded || checkdisk)
459 {
460 if (checkdisk && mod->loaded)
461 Con_DPrintf("checking model %s\n", mod->name);
462 buf = FS_LoadFile (mod->name, tempmempool, false, &filesize);
463 if (buf)
464 {
465 crc = CRC_Block((unsigned char *)buf, filesize);
466 // we need to reload the model if the crc does not match
467 if (mod->crc != crc)
468 mod->loaded = false;
469 }
470 }
471
472 // if the model is already loaded and checks passed, just return
473 if (mod->loaded)
474 {
475 if (buf)
476 Mem_Free(buf);
477 return mod;
478 }
479
481 Con_Printf("loading model %s\n", mod->name);
482
483 SCR_PushLoadingScreen(mod->name, 1);
484
485 // LadyHavoc: unload the existing model in this slot (if there is one)
486 if (mod->loaded || mod->mempool)
488
489 // load the model
490 mod->used = true;
491 mod->crc = crc;
492 // errors can prevent the corresponding mod->loaded = true;
493 mod->loaded = false;
494
495 // default lightmap scale
496 mod->lightmapscale = 1;
497
498 // default model radius and bounding box (mainly for missing models)
499 mod->radius = 16;
500 VectorSet(mod->normalmins, -mod->radius, -mod->radius, -mod->radius);
501 VectorSet(mod->normalmaxs, mod->radius, mod->radius, mod->radius);
502 VectorSet(mod->yawmins, -mod->radius, -mod->radius, -mod->radius);
503 VectorSet(mod->yawmaxs, mod->radius, mod->radius, mod->radius);
504 VectorSet(mod->rotatedmins, -mod->radius, -mod->radius, -mod->radius);
505 VectorSet(mod->rotatedmaxs, mod->radius, mod->radius, mod->radius);
506
507 if (!q3shaders_mem)
508 {
509 // load q3 shaders for the first time, or after a level change
511 }
512
513 if (buf)
514 {
515 int i;
516 const char *ext = FS_FileExtension(mod->name);
517 char *bufend = (char *)buf + filesize;
518 // all models use memory, so allocate a memory pool
519 mod->mempool = Mem_AllocPool(mod->name, 0, NULL);
520
521 // We need to have a reference to the base model in case we're parsing submodels
522 loadmodel = mod;
523
524 // Call the appropriate loader. Try matching magic bytes.
525 for (i = 0; loader[i].Load; i++)
526 {
527 // Headerless formats can just load based on extension. Otherwise match the magic string.
528 if((loader[i].extension && !strcasecmp(ext, loader[i].extension) && !loader[i].header) ||
529 (loader[i].header && !memcmp(buf, loader[i].header, loader[i].headersize)))
530 {
531 // Matched. Load it.
532 loader[i].Load(mod, buf, bufend);
533 Mem_Free(buf);
534
536
537 buf = FS_LoadFile(va(vabuf, sizeof(vabuf), "%s.framegroups", mod->name), tempmempool, false, &filesize);
538 if(buf)
539 {
540 Mod_FrameGroupify(mod, (const char *)buf);
541 Mem_Free(buf);
542 }
543
546 break;
547 }
548 }
549 if(!loader[i].Load)
550 Con_Printf(CON_ERROR "Mod_LoadModel: model \"%s\" is of unknown/unsupported type\n", mod->name);
551 }
552 else if (crash)
553 // LadyHavoc: Sys_Error was *ANNOYING*
554 Con_Printf (CON_ERROR "Mod_LoadModel: %s not found\n", mod->name);
555
556 // no fatal errors occurred, so this model is ready to use.
557 mod->loaded = true;
558
560
561 return mod;
562}
563
565{
566 int i;
567 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
568 model_t *mod;
569 for (i = 0;i < nummodels;i++)
570 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0])
571 mod->used = false;
572}
573
575{
576 int i;
577 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
578 model_t *mod;
579 for (i = 0;i < nummodels;i++)
580 {
581 if ((mod = (model_t*) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && !mod->used)
582 {
585 }
586 }
587}
588
589/*
590==================
591Mod_FindName
592
593==================
594*/
595model_t *Mod_FindName(const char *name, const char *parentname)
596{
597 int i;
598 int nummodels;
599 model_t *mod;
600
601 if (!parentname)
602 parentname = "";
603
605
606 if (!name[0])
607 Host_Error ("Mod_ForName: empty name");
608
609 // search the currently loaded models
610 for (i = 0;i < nummodels;i++)
611 {
612 if ((mod = (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))))
613 {
614 mod->used = true;
615 return mod;
616 }
617 }
618
619 // no match found, create a new one
621 dp_strlcpy(mod->name, name, sizeof(mod->name));
622 if (parentname[0])
623 mod->brush.parentmodel = Mod_FindName(parentname, NULL);
624 else
625 mod->brush.parentmodel = NULL;
626 mod->loaded = false;
627 mod->used = true;
628 return mod;
629}
630
631extern qbool vid_opened;
632
633/*
634==================
635Mod_ForName
636
637Loads in a model for the given name
638==================
639*/
640model_t *Mod_ForName(const char *name, qbool crash, qbool checkdisk, const char *parentname)
641{
642 model_t *model;
643
644 // FIXME: So we don't crash if a server is started early.
645 if(!vid_opened)
647
648 model = Mod_FindName(name, parentname);
649 if (!model->loaded || checkdisk)
650 Mod_LoadModel(model, crash, checkdisk);
651 return model;
652}
653
654/*
655==================
656Mod_Reload
657
658Reloads all models if they have changed
659==================
660*/
661void Mod_Reload(void)
662{
663 int i, count;
664 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
665 model_t *mod;
666
667 SCR_PushLoadingScreen("Reloading models", 1.0);
668 count = 0;
669 for (i = 0;i < nummodels;i++)
670 if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
671 ++count;
672 for (i = 0;i < nummodels;i++)
673 if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*' && mod->used)
674 {
675 SCR_PushLoadingScreen(mod->name, 1.0 / count);
676 Mod_LoadModel(mod, true, true);
678 }
680}
681
682unsigned char *mod_base;
683
684
685//=============================================================================
686
687/*
688================
689Mod_Print
690================
691*/
693{
694 int i;
695 int nummodels = (int)Mem_ExpandableArray_IndexRange(&models);
696 model_t *mod;
697
698 Con_Print("Loaded models:\n");
699 for (i = 0;i < nummodels;i++)
700 {
701 if ((mod = (model_t *) Mem_ExpandableArray_RecordAtIndex(&models, i)) && mod->name[0] && mod->name[0] != '*')
702 {
703 if (mod->brush.numsubmodels)
704 Con_Printf("%4iK %s (%i submodels)\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name, mod->brush.numsubmodels);
705 else
706 Con_Printf("%4iK %s\n", mod->mempool ? (int)((mod->mempool->totalsize + 1023) / 1024) : 0, mod->name);
707 }
708 }
709}
710
711/*
712================
713Mod_Precache
714================
715*/
717{
718 if (Cmd_Argc(cmd) == 2)
719 Mod_ForName(Cmd_Argv(cmd, 1), false, true, Cmd_Argv(cmd, 1)[0] == '*' ? cl.model_name[1] : NULL);
720 else
721 Con_Print("usage: modelprecache <filename>\n");
722}
723
724int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
725{
726 int i, count;
727 unsigned char *used;
728 used = (unsigned char *)Mem_Alloc(tempmempool, numvertices);
729 memset(used, 0, numvertices);
730 for (i = 0;i < numelements;i++)
731 used[elements[i]] = 1;
732 for (i = 0, count = 0;i < numvertices;i++)
733 remapvertices[i] = used[i] ? count++ : -1;
734 Mem_Free(used);
735 return count;
736}
737
738qbool Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
739{
740 int first = firstvertex, last = first + numvertices - 1, numelements = numtriangles * 3;
741 int i;
742 int invalidintcount = 0, invalidintexample = 0;
743 int invalidshortcount = 0, invalidshortexample = 0;
744 int invalidmismatchcount = 0, invalidmismatchexample = 0;
745 if (element3i)
746 {
747 for (i = 0; i < numelements; i++)
748 {
749 if (element3i[i] < first || element3i[i] > last)
750 {
751 invalidintcount++;
752 invalidintexample = i;
753 }
754 }
755 }
756 if (element3s)
757 {
758 for (i = 0; i < numelements; i++)
759 {
760 if (element3s[i] < first || element3s[i] > last)
761 {
762 invalidintcount++;
763 invalidintexample = i;
764 }
765 }
766 }
767 if (element3i && element3s)
768 {
769 for (i = 0; i < numelements; i++)
770 {
771 if (element3s[i] != element3i[i])
772 {
773 invalidmismatchcount++;
774 invalidmismatchexample = i;
775 }
776 }
777 }
778 if (invalidintcount || invalidshortcount || invalidmismatchcount)
779 {
780 Con_Printf("Mod_ValidateElements(%i, %i, %i, %p, %p) called at %s:%d", numelements, first, last, (void *)element3i, (void *)element3s, filename, fileline);
781 Con_Printf(", %i elements are invalid in element3i (example: element3i[%i] == %i)", invalidintcount, invalidintexample, element3i ? element3i[invalidintexample] : 0);
782 Con_Printf(", %i elements are invalid in element3s (example: element3s[%i] == %i)", invalidshortcount, invalidshortexample, element3s ? element3s[invalidshortexample] : 0);
783 Con_Printf(", %i elements mismatch between element3i and element3s (example: element3s[%i] is %i and element3i[%i] is %i)", invalidmismatchcount, invalidmismatchexample, element3s ? element3s[invalidmismatchexample] : 0, invalidmismatchexample, element3i ? element3i[invalidmismatchexample] : 0);
784 Con_Print(". Please debug the engine code - these elements have been modified to not crash, but nothing more.\n");
785
786 // edit the elements to make them safer, as the driver will crash otherwise
787 if (element3i)
788 for (i = 0; i < numelements; i++)
789 if (element3i[i] < first || element3i[i] > last)
790 element3i[i] = first;
791 if (element3s)
792 for (i = 0; i < numelements; i++)
793 if (element3s[i] < first || element3s[i] > last)
794 element3s[i] = first;
795 if (element3i && element3s)
796 for (i = 0; i < numelements; i++)
797 if (element3s[i] != element3i[i])
798 element3s[i] = element3i[i];
799
800 return false;
801 }
802 return true;
803}
804
805// warning: this is an expensive function!
806void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qbool areaweighting)
807{
808 int i, j;
809 const int *element;
810 float *vectorNormal;
811 float areaNormal[3];
812 // clear the vectors
813 memset(normal3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
814 // process each vertex of each triangle and accumulate the results
815 // use area-averaging, to make triangles with a big area have a bigger
816 // weighting on the vertex normal than triangles with a small area
817 // to do so, just add the 'normals' together (the bigger the area
818 // the greater the length of the normal is
819 element = elements;
820 for (i = 0; i < numtriangles; i++, element += 3)
821 {
823 vertex3f + element[0] * 3,
824 vertex3f + element[1] * 3,
825 vertex3f + element[2] * 3,
826 areaNormal
827 );
828
829 if (!areaweighting)
830 VectorNormalize(areaNormal);
831
832 for (j = 0;j < 3;j++)
833 {
834 vectorNormal = normal3f + element[j] * 3;
835 vectorNormal[0] += areaNormal[0];
836 vectorNormal[1] += areaNormal[1];
837 vectorNormal[2] += areaNormal[2];
838 }
839 }
840 // and just normalize the accumulated vertex normal in the end
841 vectorNormal = normal3f + 3 * firstvertex;
842 for (i = 0; i < numvertices; i++, vectorNormal += 3)
843 VectorNormalize(vectorNormal);
844}
845
846#if 0
847static 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)
848{
849 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
850 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
851 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
852
853 // 6 multiply, 9 subtract
854 VectorSubtract(v1, v0, v10);
855 VectorSubtract(v2, v0, v20);
856 normal3f[0] = v20[1] * v10[2] - v20[2] * v10[1];
857 normal3f[1] = v20[2] * v10[0] - v20[0] * v10[2];
858 normal3f[2] = v20[0] * v10[1] - v20[1] * v10[0];
859 // 12 multiply, 10 subtract
860 tc10[1] = tc1[1] - tc0[1];
861 tc20[1] = tc2[1] - tc0[1];
862 svector3f[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
863 svector3f[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
864 svector3f[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
865 tc10[0] = tc1[0] - tc0[0];
866 tc20[0] = tc2[0] - tc0[0];
867 tvector3f[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
868 tvector3f[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
869 tvector3f[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
870 // 12 multiply, 4 add, 6 subtract
871 f = DotProduct(svector3f, normal3f);
872 svector3f[0] -= f * normal3f[0];
873 svector3f[1] -= f * normal3f[1];
874 svector3f[2] -= f * normal3f[2];
875 f = DotProduct(tvector3f, normal3f);
876 tvector3f[0] -= f * normal3f[0];
877 tvector3f[1] -= f * normal3f[1];
878 tvector3f[2] -= f * normal3f[2];
879 // if texture is mapped the wrong way (counterclockwise), the tangents
880 // have to be flipped, this is detected by calculating a normal from the
881 // two tangents, and seeing if it is opposite the surface normal
882 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
883 CrossProduct(tvector3f, svector3f, tangentcross);
884 if (DotProduct(tangentcross, normal3f) < 0)
885 {
886 VectorNegate(svector3f, svector3f);
887 VectorNegate(tvector3f, tvector3f);
888 }
889}
890#endif
891
892// warning: this is a very expensive function!
893void Mod_BuildTextureVectorsFromNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const float *texcoord2f, const float *normal3f, const int *elements, float *svector3f, float *tvector3f, qbool areaweighting)
894{
895 int i, tnum;
896 float sdir[3], tdir[3], normal[3], *svec, *tvec;
897 const float *v0, *v1, *v2, *tc0, *tc1, *tc2, *n;
898 float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
899 const int *e;
900 // clear the vectors
901 memset(svector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
902 memset(tvector3f + 3 * firstvertex, 0, numvertices * sizeof(float[3]));
903 // process each vertex of each triangle and accumulate the results
904 for (tnum = 0, e = elements;tnum < numtriangles;tnum++, e += 3)
905 {
906 v0 = vertex3f + e[0] * 3;
907 v1 = vertex3f + e[1] * 3;
908 v2 = vertex3f + e[2] * 3;
909 tc0 = texcoord2f + e[0] * 2;
910 tc1 = texcoord2f + e[1] * 2;
911 tc2 = texcoord2f + e[2] * 2;
912
913 // 79 add/sub/negate/multiply (1 cycle), 1 compare (3 cycle?), total cycles not counting load/store/exchange roughly 82 cycles
914 // 6 add, 28 subtract, 39 multiply, 1 compare, 50% chance of 6 negates
915
916 // calculate the edge directions and surface normal
917 // 6 multiply, 9 subtract
918 VectorSubtract(v1, v0, v10);
919 VectorSubtract(v2, v0, v20);
920 normal[0] = v20[1] * v10[2] - v20[2] * v10[1];
921 normal[1] = v20[2] * v10[0] - v20[0] * v10[2];
922 normal[2] = v20[0] * v10[1] - v20[1] * v10[0];
923
924 // calculate the tangents
925 // 12 multiply, 10 subtract
926 tc10[1] = tc1[1] - tc0[1];
927 tc20[1] = tc2[1] - tc0[1];
928 sdir[0] = tc10[1] * v20[0] - tc20[1] * v10[0];
929 sdir[1] = tc10[1] * v20[1] - tc20[1] * v10[1];
930 sdir[2] = tc10[1] * v20[2] - tc20[1] * v10[2];
931 tc10[0] = tc1[0] - tc0[0];
932 tc20[0] = tc2[0] - tc0[0];
933 tdir[0] = tc10[0] * v20[0] - tc20[0] * v10[0];
934 tdir[1] = tc10[0] * v20[1] - tc20[0] * v10[1];
935 tdir[2] = tc10[0] * v20[2] - tc20[0] * v10[2];
936
937 // if texture is mapped the wrong way (counterclockwise), the tangents
938 // have to be flipped, this is detected by calculating a normal from the
939 // two tangents, and seeing if it is opposite the surface normal
940 // 9 multiply, 2 add, 3 subtract, 1 compare, 50% chance of: 6 negates
941 CrossProduct(tdir, sdir, tangentcross);
942 if (DotProduct(tangentcross, normal) < 0)
943 {
944 VectorNegate(sdir, sdir);
945 VectorNegate(tdir, tdir);
946 }
947
948 if (!areaweighting)
949 {
950 VectorNormalize(sdir);
951 VectorNormalize(tdir);
952 }
953 for (i = 0;i < 3;i++)
954 {
955 VectorAdd(svector3f + e[i]*3, sdir, svector3f + e[i]*3);
956 VectorAdd(tvector3f + e[i]*3, tdir, tvector3f + e[i]*3);
957 }
958 }
959 // make the tangents completely perpendicular to the surface normal, and
960 // then normalize them
961 // 16 assignments, 2 divide, 2 sqrt, 2 negates, 14 adds, 24 multiplies
962 for (i = 0, svec = svector3f + 3 * firstvertex, tvec = tvector3f + 3 * firstvertex, n = normal3f + 3 * firstvertex;i < numvertices;i++, svec += 3, tvec += 3, n += 3)
963 {
964 f = -DotProduct(svec, n);
965 VectorMA(svec, f, n, svec);
966 VectorNormalize(svec);
967 f = -DotProduct(tvec, n);
968 VectorMA(tvec, f, n, tvec);
969 VectorNormalize(tvec);
970 }
971}
972
973void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qbool lightmapoffsets, qbool vertexcolors)
974{
975 unsigned char *data;
976 data = (unsigned char *)Mem_Alloc(mempool, numvertices * (3 + 3 + 3 + 3 + 2 + 2 + (vertexcolors ? 4 : 0)) * sizeof(float) + numvertices * (lightmapoffsets ? 1 : 0) * sizeof(int) + numtriangles * sizeof(int[3]) + (numvertices <= 65536 ? numtriangles * sizeof(unsigned short[3]) : 0));
977 loadmodel->surfmesh.num_vertices = numvertices;
978 loadmodel->surfmesh.num_triangles = numtriangles;
980 {
981 loadmodel->surfmesh.data_vertex3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
982 loadmodel->surfmesh.data_svector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
983 loadmodel->surfmesh.data_tvector3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
984 loadmodel->surfmesh.data_normal3f = (float *)data, data += sizeof(float[3]) * loadmodel->surfmesh.num_vertices;
987 if (vertexcolors)
989 if (lightmapoffsets)
991 }
993 {
995 if (loadmodel->surfmesh.num_vertices <= 65536)
996 loadmodel->surfmesh.data_element3s = (unsigned short *)data, data += sizeof(unsigned short[3]) * loadmodel->surfmesh.num_triangles;
997 }
998}
999
1000shadowmesh_t *Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles)
1001{
1002 shadowmesh_t *newmesh;
1003 newmesh = (shadowmesh_t *)Mem_Alloc(mempool, sizeof(shadowmesh_t));
1004 newmesh->mempool = mempool;
1005 newmesh->maxverts = maxverts;
1006 newmesh->maxtriangles = maxtriangles;
1007 newmesh->numverts = 0;
1008 newmesh->numtriangles = 0;
1009 memset(newmesh->sideoffsets, 0, sizeof(newmesh->sideoffsets));
1010 memset(newmesh->sidetotals, 0, sizeof(newmesh->sidetotals));
1011
1012 newmesh->vertex3f = (float *)Mem_Alloc(mempool, maxverts * sizeof(float[3]));
1013 newmesh->element3i = (int *)Mem_Alloc(mempool, maxtriangles * sizeof(int[3]));
1015 newmesh->vertexhashentries = (shadowmeshvertexhash_t *)Mem_Alloc(mempool, maxverts * sizeof(shadowmeshvertexhash_t));
1016 return newmesh;
1017}
1018
1019int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, const float *vertex3f)
1020{
1021 int hashindex, vnum;
1023 // this uses prime numbers intentionally
1024 hashindex = (unsigned int) (vertex3f[0] * 2003 + vertex3f[1] * 4001 + vertex3f[2] * 7919) % SHADOWMESHVERTEXHASH;
1025 for (hash = mesh->vertexhashtable[hashindex];hash;hash = hash->next)
1026 {
1027 vnum = (hash - mesh->vertexhashentries);
1028 if (mesh->vertex3f[vnum * 3 + 0] == vertex3f[0] && mesh->vertex3f[vnum * 3 + 1] == vertex3f[1] && mesh->vertex3f[vnum * 3 + 2] == vertex3f[2])
1029 return hash - mesh->vertexhashentries;
1030 }
1031 vnum = mesh->numverts++;
1032 hash = mesh->vertexhashentries + vnum;
1033 hash->next = mesh->vertexhashtable[hashindex];
1034 mesh->vertexhashtable[hashindex] = hash;
1035 mesh->vertex3f[vnum * 3 + 0] = vertex3f[0];
1036 mesh->vertex3f[vnum * 3 + 1] = vertex3f[1];
1037 mesh->vertex3f[vnum * 3 + 2] = vertex3f[2];
1038 return vnum;
1039}
1040
1041void Mod_ShadowMesh_AddMesh(shadowmesh_t *mesh, const float *vertex3f, int numtris, const int *element3i)
1042{
1043 int i;
1044
1045 for (i = 0;i < numtris;i++)
1046 {
1047 if ((mesh->numtriangles * 3 + 2) * sizeof(int) + 1 >= Mem_Size(mesh->element3i))
1048 {
1049 // FIXME: we didn't allocate enough space for all the tris, see R_Mod_CompileShadowMap
1050 Con_Print(CON_WARN "Mod_ShadowMesh_AddMesh: insufficient memory allocated!\n");
1051 return;
1052 }
1053 mesh->element3i[mesh->numtriangles * 3 + 0] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 0]);
1054 mesh->element3i[mesh->numtriangles * 3 + 1] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 1]);
1055 mesh->element3i[mesh->numtriangles * 3 + 2] = Mod_ShadowMesh_AddVertex(mesh, vertex3f + 3 * element3i[i * 3 + 2]);
1056 mesh->numtriangles++;
1057 }
1058
1059 // the triangle calculation can take a while, so let's do a keepalive here
1060 CL_KeepaliveMessage(false);
1061}
1062
1063shadowmesh_t *Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles)
1064{
1065 // the preparation before shadow mesh initialization can take a while, so let's do a keepalive here
1066 CL_KeepaliveMessage(false);
1067
1068 return Mod_ShadowMesh_Alloc(mempool, maxverts, maxtriangles);
1069}
1070
1072{
1073 if (!mesh->numverts)
1074 return;
1075
1076 // make sure we don't crash inside the driver if something went wrong, as it's annoying to debug
1077 Mod_ValidateElements(mesh->element3i, mesh->element3s, mesh->numtriangles, 0, mesh->numverts, __FILE__, __LINE__);
1078
1079 // upload short indices as a buffer
1080 if (mesh->element3s && !mesh->element3s_indexbuffer)
1081 mesh->element3s_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3s, mesh->numtriangles * sizeof(short[3]), "shadowmesh", true, false, false, true);
1082
1083 // upload int indices as a buffer
1084 if (mesh->element3i && !mesh->element3i_indexbuffer && !mesh->element3s)
1085 mesh->element3i_indexbuffer = R_Mesh_CreateMeshBuffer(mesh->element3i, mesh->numtriangles * sizeof(int[3]), "shadowmesh", true, false, false, false);
1086
1087 // vertex buffer is several arrays and we put them in the same buffer
1088 //
1089 // is this wise? the texcoordtexture2f array is used with dynamic
1090 // vertex/svector/tvector/normal when rendering animated models, on the
1091 // other hand animated models don't use a lot of vertices anyway...
1092 if (!mesh->vbo_vertexbuffer)
1093 {
1094 mesh->vbooffset_vertex3f = 0;
1095 mesh->vbo_vertexbuffer = R_Mesh_CreateMeshBuffer(mesh->vertex3f, mesh->numverts * sizeof(float[3]), "shadowmesh", false, false, false, false);
1096 }
1097}
1098
1100{
1101 if (mesh->numverts >= 3 && mesh->numtriangles >= 1)
1102 {
1103 if (mesh->vertexhashentries)
1105 mesh->vertexhashentries = NULL;
1106 if (mesh->vertexhashtable)
1108 mesh->vertexhashtable = NULL;
1109 if (mesh->maxverts > mesh->numverts)
1110 {
1111 mesh->vertex3f = (float *)Mem_Realloc(mesh->mempool, mesh->vertex3f, mesh->numverts * sizeof(float[3]));
1112 mesh->maxverts = mesh->numverts;
1113 }
1114 if (mesh->maxtriangles > mesh->numtriangles)
1115 {
1116 mesh->element3i = (int *)Mem_Realloc(mesh->mempool, mesh->element3i, mesh->numtriangles * sizeof(int[3]));
1117 mesh->maxtriangles = mesh->numtriangles;
1118 }
1119 if (mesh->numverts <= 65536)
1120 {
1121 int i;
1122 mesh->element3s = (unsigned short *)Mem_Alloc(mesh->mempool, mesh->numtriangles * sizeof(unsigned short[3]));
1123 for (i = 0;i < mesh->numtriangles*3;i++)
1124 mesh->element3s[i] = mesh->element3i[i];
1125 }
1126 if (createvbo)
1128 }
1129
1130 // this can take a while, so let's do a keepalive here
1131 CL_KeepaliveMessage(false);
1132
1133 return mesh;
1134}
1135
1137{
1138 int i;
1139 vec3_t nmins, nmaxs, ncenter, temp;
1140 float nradius2, dist2, *v;
1141 VectorClear(nmins);
1142 VectorClear(nmaxs);
1143 // calculate bbox
1144 VectorCopy(mesh->vertex3f, nmins);
1145 VectorCopy(mesh->vertex3f, nmaxs);
1146 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1147 {
1148 if (nmins[0] > v[0]) { nmins[0] = v[0]; } if (nmaxs[0] < v[0]) { nmaxs[0] = v[0]; }
1149 if (nmins[1] > v[1]) { nmins[1] = v[1]; } if (nmaxs[1] < v[1]) { nmaxs[1] = v[1]; }
1150 if (nmins[2] > v[2]) { nmins[2] = v[2]; } if (nmaxs[2] < v[2]) { nmaxs[2] = v[2]; }
1151 }
1152 // calculate center and radius
1153 ncenter[0] = (nmins[0] + nmaxs[0]) * 0.5f;
1154 ncenter[1] = (nmins[1] + nmaxs[1]) * 0.5f;
1155 ncenter[2] = (nmins[2] + nmaxs[2]) * 0.5f;
1156 nradius2 = 0;
1157 for (i = 0, v = mesh->vertex3f;i < mesh->numverts;i++, v += 3)
1158 {
1159 VectorSubtract(v, ncenter, temp);
1160 dist2 = DotProduct(temp, temp);
1161 if (nradius2 < dist2)
1162 nradius2 = dist2;
1163 }
1164 // return data
1165 if (mins)
1166 VectorCopy(nmins, mins);
1167 if (maxs)
1168 VectorCopy(nmaxs, maxs);
1169 if (center)
1170 VectorCopy(ncenter, center);
1171 if (radius)
1172 *radius = sqrt(nradius2);
1173}
1174
1176{
1177 if (mesh->element3i_indexbuffer)
1179 if (mesh->element3s_indexbuffer)
1181 if (mesh->vbo_vertexbuffer)
1183 if (mesh->vertex3f)
1184 Mem_Free(mesh->vertex3f);
1185 if (mesh->element3i)
1186 Mem_Free(mesh->element3i);
1187 if (mesh->element3s)
1188 Mem_Free(mesh->element3s);
1189 if (mesh->vertexhashentries)
1191 if (mesh->vertexhashtable)
1193 Mem_Free(mesh);
1194}
1195
1197{
1198 int k, numcollisionmeshtriangles;
1199 qbool usesinglecollisionmesh = false;
1200 const msurface_t *surface = NULL;
1201
1202 mempool_t *mempool = mod->mempool;
1203 if (!mempool && mod->brush.parentmodel)
1204 mempool = mod->brush.parentmodel->mempool;
1205 // make a single combined collision mesh for physics engine use
1206 // TODO rewrite this to use the collision brushes as source, to fix issues with e.g. common/caulk which creates no drawsurface
1207 numcollisionmeshtriangles = 0;
1208 for (k = mod->submodelsurfaces_start;k < mod->submodelsurfaces_end;k++)
1209 {
1210 surface = mod->data_surfaces + k;
1211 if (!strcmp(surface->texture->name, "collision") || !strcmp(surface->texture->name, "collisionconvex")) // found collision mesh
1212 {
1213 usesinglecollisionmesh = true;
1214 numcollisionmeshtriangles = surface->num_triangles;
1215 break;
1216 }
1217 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1218 continue;
1219 numcollisionmeshtriangles += surface->num_triangles;
1220 }
1221 mod->brush.collisionmesh = Mod_ShadowMesh_Begin(mempool, numcollisionmeshtriangles * 3, numcollisionmeshtriangles);
1222 if (usesinglecollisionmesh)
1223 Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1224 else
1225 {
1226 for (k = mod->submodelsurfaces_start; k < mod->submodelsurfaces_end; k++)
1227 {
1228 surface = mod->data_surfaces + k;
1229 if (!(surface->texture->supercontents & SUPERCONTENTS_SOLID))
1230 continue;
1231 Mod_ShadowMesh_AddMesh(mod->brush.collisionmesh, mod->surfmesh.data_vertex3f, surface->num_triangles, (mod->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
1232 }
1233 }
1234 mod->brush.collisionmesh = Mod_ShadowMesh_Finish(mod->brush.collisionmesh, false);
1235}
1236
1237#if 0
1238static 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)
1239{
1240 float v[3], tc[3];
1241 v[0] = ix;
1242 v[1] = iy;
1243 if (ix >= 0 && iy >= 0 && ix < imagewidth && iy < imageheight)
1244 v[2] = (imagepixels[((iy*imagewidth)+ix)*4+0] + imagepixels[((iy*imagewidth)+ix)*4+1] + imagepixels[((iy*imagewidth)+ix)*4+2]) * (1.0f / 765.0f);
1245 else
1246 v[2] = 0;
1247 Matrix4x4_Transform(pixelstepmatrix, v, vertex3f);
1248 Matrix4x4_Transform(pixeltexturestepmatrix, v, tc);
1249 texcoord2f[0] = tc[0];
1250 texcoord2f[1] = tc[1];
1251}
1252
1253static 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)
1254{
1255 float vup[3], vdown[3], vleft[3], vright[3];
1256 float tcup[3], tcdown[3], tcleft[3], tcright[3];
1257 float sv[3], tv[3], nl[3];
1258 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, pixelstepmatrix, pixeltexturestepmatrix);
1259 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy - 1, vup, tcup, pixelstepmatrix, pixeltexturestepmatrix);
1260 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix, iy + 1, vdown, tcdown, pixelstepmatrix, pixeltexturestepmatrix);
1261 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix - 1, iy, vleft, tcleft, pixelstepmatrix, pixeltexturestepmatrix);
1262 Mod_GetTerrainVertex3fTexCoord2fFromBGRA(imagepixels, imagewidth, imageheight, ix + 1, iy, vright, tcright, pixelstepmatrix, pixeltexturestepmatrix);
1263 Mod_BuildBumpVectors(vertex3f, vup, vright, texcoord2f, tcup, tcright, svector3f, tvector3f, normal3f);
1264 Mod_BuildBumpVectors(vertex3f, vright, vdown, texcoord2f, tcright, tcdown, sv, tv, nl);
1265 VectorAdd(svector3f, sv, svector3f);
1266 VectorAdd(tvector3f, tv, tvector3f);
1267 VectorAdd(normal3f, nl, normal3f);
1268 Mod_BuildBumpVectors(vertex3f, vdown, vleft, texcoord2f, tcdown, tcleft, sv, tv, nl);
1269 VectorAdd(svector3f, sv, svector3f);
1270 VectorAdd(tvector3f, tv, tvector3f);
1271 VectorAdd(normal3f, nl, normal3f);
1272 Mod_BuildBumpVectors(vertex3f, vleft, vup, texcoord2f, tcleft, tcup, sv, tv, nl);
1273 VectorAdd(svector3f, sv, svector3f);
1274 VectorAdd(tvector3f, tv, tvector3f);
1275 VectorAdd(normal3f, nl, normal3f);
1276}
1277
1278static void Mod_ConstructTerrainPatchFromBGRA(const unsigned char *imagepixels, int imagewidth, int imageheight, int x1, int y1, int width, int height, int *element3i, float *vertex3f, float *svector3f, float *tvector3f, float *normal3f, float *texcoord2f, matrix4x4_t *pixelstepmatrix, matrix4x4_t *pixeltexturestepmatrix)
1279{
1280 int x, y, ix, iy, *e;
1281 e = element3i;
1282 for (y = 0;y < height;y++)
1283 {
1284 for (x = 0;x < width;x++)
1285 {
1286 e[0] = (y + 1) * (width + 1) + (x + 0);
1287 e[1] = (y + 0) * (width + 1) + (x + 0);
1288 e[2] = (y + 1) * (width + 1) + (x + 1);
1289 e[3] = (y + 0) * (width + 1) + (x + 0);
1290 e[4] = (y + 0) * (width + 1) + (x + 1);
1291 e[5] = (y + 1) * (width + 1) + (x + 1);
1292 e += 6;
1293 }
1294 }
1295 for (y = 0, iy = y1;y < height + 1;y++, iy++)
1296 for (x = 0, ix = x1;x < width + 1;x++, ix++, vertex3f += 3, texcoord2f += 2, svector3f += 3, tvector3f += 3, normal3f += 3)
1297 Mod_GetTerrainVertexFromBGRA(imagepixels, imagewidth, imageheight, ix, iy, vertex3f, texcoord2f, svector3f, tvector3f, normal3f, pixelstepmatrix, pixeltexturestepmatrix);
1298}
1299#endif
1300
1301#if 0
1302void Mod_Terrain_SurfaceRecurseChunk(model_t *model, int stepsize, int x, int y)
1303{
1304 float mins[3];
1305 float maxs[3];
1306 float chunkwidth = min(stepsize, model->terrain.width - 1 - x);
1307 float chunkheight = min(stepsize, model->terrain.height - 1 - y);
1308 float viewvector[3];
1309 unsigned int firstvertex;
1310 unsigned int *e;
1311 float *v;
1312 if (chunkwidth < 2 || chunkheight < 2)
1313 return;
1314 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]);
1315 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]);
1316 viewvector[0] = bound(mins[0], localvieworigin, maxs[0]) - model->terrain.vieworigin[0];
1317 viewvector[1] = bound(mins[1], localvieworigin, maxs[1]) - model->terrain.vieworigin[1];
1318 viewvector[2] = bound(mins[2], localvieworigin, maxs[2]) - model->terrain.vieworigin[2];
1319 if (stepsize > 1 && VectorLength(viewvector) < stepsize*model->terrain.scale[0]*r_terrain_lodscale.value)
1320 {
1321 // too close for this stepsize, emit as 4 chunks instead
1322 stepsize /= 2;
1323 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y);
1324 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y);
1325 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x, y+stepsize);
1326 Mod_Terrain_SurfaceRecurseChunk(model, stepsize, x+stepsize, y+stepsize);
1327 return;
1328 }
1329 // emit the geometry at stepsize into our vertex buffer / index buffer
1330 // we add two columns and two rows for skirt
1331 outwidth = chunkwidth+2;
1332 outheight = chunkheight+2;
1333 outwidth2 = outwidth-1;
1334 outheight2 = outheight-1;
1335 outwidth3 = outwidth+1;
1336 outheight3 = outheight+1;
1337 firstvertex = numvertices;
1338 e = model->terrain.element3i + numtriangles;
1339 numtriangles += chunkwidth*chunkheight*2+chunkwidth*2*2+chunkheight*2*2;
1340 v = model->terrain.vertex3f + numvertices;
1341 numvertices += (chunkwidth+1)*(chunkheight+1)+(chunkwidth+1)*2+(chunkheight+1)*2;
1342 // emit the triangles (note: the skirt is treated as two extra rows and two extra columns)
1343 for (ty = 0;ty < outheight;ty++)
1344 {
1345 for (tx = 0;tx < outwidth;tx++)
1346 {
1347 *e++ = firstvertex + (ty )*outwidth3+(tx );
1348 *e++ = firstvertex + (ty )*outwidth3+(tx+1);
1349 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1350 *e++ = firstvertex + (ty )*outwidth3+(tx );
1351 *e++ = firstvertex + (ty+1)*outwidth3+(tx+1);
1352 *e++ = firstvertex + (ty+1)*outwidth3+(tx );
1353 }
1354 }
1355 // TODO: emit surface vertices (x+tx*stepsize, y+ty*stepsize)
1356 for (ty = 0;ty <= outheight;ty++)
1357 {
1358 skirtrow = ty == 0 || ty == outheight;
1359 ry = y+bound(1, ty, outheight)*stepsize;
1360 for (tx = 0;tx <= outwidth;tx++)
1361 {
1362 skirt = skirtrow || tx == 0 || tx == outwidth;
1363 rx = x+bound(1, tx, outwidth)*stepsize;
1364 v[0] = rx*scale[0];
1365 v[1] = ry*scale[1];
1366 v[2] = heightmap[ry*terrainwidth+rx]*scale[2];
1367 v += 3;
1368 }
1369 }
1370 // TODO: emit skirt vertices
1371}
1372
1373void Mod_Terrain_UpdateSurfacesForViewOrigin(model_t *model)
1374{
1375 for (y = 0;y < model->terrain.size[1];y += model->terrain.
1376 Mod_Terrain_SurfaceRecurseChunk(model, model->terrain.maxstepsize, x, y);
1377 Mod_Terrain_BuildChunk(model,
1378}
1379#endif
1380
1382{
1383 int offset = 0;
1384 if (!strncasecmp(s, "user", 4)) // parse stuff like "user1sin", always user<n>func
1385 {
1386 offset = bound(0, s[4] - '0', 9);
1388 s += 4;
1389 if(*s)
1390 ++s;
1391 }
1392 if (!strcasecmp(s, "sin")) return offset | Q3WAVEFUNC_SIN;
1393 if (!strcasecmp(s, "square")) return offset | Q3WAVEFUNC_SQUARE;
1394 if (!strcasecmp(s, "triangle")) return offset | Q3WAVEFUNC_TRIANGLE;
1395 if (!strcasecmp(s, "sawtooth")) return offset | Q3WAVEFUNC_SAWTOOTH;
1396 if (!strcasecmp(s, "inversesawtooth")) return offset | Q3WAVEFUNC_INVERSESAWTOOTH;
1397 if (!strcasecmp(s, "noise")) return offset | Q3WAVEFUNC_NOISE;
1398 if (!strcasecmp(s, "none")) return offset | Q3WAVEFUNC_NONE;
1399 Con_DPrintf("Mod_LoadQ3Shaders: unknown wavefunc %s\n", s);
1400 return offset | Q3WAVEFUNC_NONE;
1401}
1402
1404{
1406}
1407
1408static void Q3Shader_AddToHash (shader_t* shader)
1409{
1410 unsigned short hash = CRC_Block_CaseInsensitive ((const unsigned char *)shader->name, strlen (shader->name));
1412 q3shader_hash_entry_t* lastEntry = NULL;
1413 do
1414 {
1415 if (strcasecmp (entry->shader.name, shader->name) == 0)
1416 {
1417 // redeclaration
1418 if(shader->dpshaderkill)
1419 {
1420 // killed shader is a redeclarion? we can safely ignore it
1421 return;
1422 }
1423 else if(entry->shader.dpshaderkill)
1424 {
1425 // replace the old shader!
1426 // this will skip the entry allocating part
1427 // below and just replace the shader
1428 break;
1429 }
1430 else
1431 {
1432 unsigned char *start, *end, *start2;
1433 start = (unsigned char *) (&shader->Q3SHADERINFO_COMPARE_START);
1434 end = ((unsigned char *) (&shader->Q3SHADERINFO_COMPARE_END)) + sizeof(shader->Q3SHADERINFO_COMPARE_END);
1435 start2 = (unsigned char *) (&entry->shader.Q3SHADERINFO_COMPARE_START);
1436 if(memcmp(start, start2, end - start))
1437 Con_DPrintf("Shader '%s' already defined, ignoring mismatching redeclaration\n", shader->name);
1438 else
1439 Con_DPrintf("Shader '%s' already defined\n", shader->name);
1440 return;
1441 }
1442 }
1443 lastEntry = entry;
1444 entry = entry->chain;
1445 }
1446 while (entry != NULL);
1447 if (entry == NULL)
1448 {
1449 if (lastEntry->shader.name[0] != 0)
1450 {
1451 /* Add to chain */
1454
1455 while (lastEntry->chain != NULL) lastEntry = lastEntry->chain;
1456 lastEntry->chain = newEntry;
1457 newEntry->chain = NULL;
1458 lastEntry = newEntry;
1459 }
1460 /* else: head of chain, in hash entry array */
1461 entry = lastEntry;
1462 }
1463 memcpy (&entry->shader, shader, sizeof (shader_t));
1464}
1465
1467{
1468 int j;
1469 int fileindex;
1470 fssearch_t *search;
1471 char *f;
1472 const char *text;
1473 shader_t shader;
1475 int numparameters;
1476 char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
1477 char *custsurfaceparmnames[256]; // VorteX: q3map2 has 64 but well, someone will need more
1478 unsigned long custsurfaceflags[256];
1479 int numcustsurfaceflags;
1480 qbool dpshaderkill;
1481
1483
1484 q3shaders_mem = Mem_AllocPool("q3shaders", 0, NULL);
1486 sizeof (q3shader_data_t));
1488 q3shaders_mem, sizeof (q3shader_hash_entry_t), 256);
1490 q3shaders_mem, sizeof (char**), 256);
1491
1492 // parse custinfoparms.txt
1493 numcustsurfaceflags = 0;
1494 if ((text = f = (char *)FS_LoadFile("scripts/custinfoparms.txt", tempmempool, false, NULL)) != NULL)
1495 {
1496 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1497 Con_DPrintf("scripts/custinfoparms.txt: contentflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1498 else
1499 {
1500 while (COM_ParseToken_QuakeC(&text, false))
1501 if (!strcasecmp(com_token, "}"))
1502 break;
1503 // custom surfaceflags section
1504 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1505 Con_DPrintf("scripts/custinfoparms.txt: surfaceflags section parsing error - expected \"{\", found \"%s\"\n", com_token);
1506 else
1507 {
1508 while(COM_ParseToken_QuakeC(&text, false))
1509 {
1510 if (!strcasecmp(com_token, "}"))
1511 break;
1512 // register surfaceflag
1513 if (numcustsurfaceflags >= 256)
1514 {
1515 Con_Printf("scripts/custinfoparms.txt: surfaceflags section parsing error - max 256 surfaceflags exceeded\n");
1516 break;
1517 }
1518 // name
1519 j = (int)strlen(com_token)+1;
1520 custsurfaceparmnames[numcustsurfaceflags] = (char *)Mem_Alloc(tempmempool, j);
1521 dp_strlcpy(custsurfaceparmnames[numcustsurfaceflags], com_token, j+1);
1522 // value
1523 if (COM_ParseToken_QuakeC(&text, false))
1524 custsurfaceflags[numcustsurfaceflags] = strtol(com_token, NULL, 0);
1525 else
1526 custsurfaceflags[numcustsurfaceflags] = 0;
1527 numcustsurfaceflags++;
1528 }
1529 }
1530 }
1531 Mem_Free(f);
1532 }
1533
1534 // parse shaders
1535 search = FS_Search("scripts/*.shader", true, false, NULL);
1536 if (!search)
1537 return;
1538 for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
1539 {
1540 text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
1541 if (!f)
1542 continue;
1543 while (COM_ParseToken_QuakeC(&text, false))
1544 {
1545 memset (&shader, 0, sizeof(shader));
1546 shader.name[0] = 0;
1547 shader.surfaceparms = 0;
1548 shader.surfaceflags = 0;
1549 shader.textureflags = 0;
1550 shader.numlayers = 0;
1551 shader.lighting = false;
1552 shader.vertexalpha = false;
1553 shader.textureblendalpha = false;
1554 shader.skyboxname[0] = 0;
1555 shader.deforms[0].deform = Q3DEFORM_NONE;
1556 shader.dpnortlight = false;
1557 shader.dpshadow = false;
1558 shader.dpnoshadow = false;
1559 shader.dpmeshcollisions = false;
1560 shader.dpshaderkill = false;
1561 shader.dpreflectcube[0] = 0;
1562 shader.reflectmin = 0;
1563 shader.reflectmax = 1;
1564 shader.refractfactor = 1;
1565 Vector4Set(shader.refractcolor4f, 1, 1, 1, 1);
1566 shader.reflectfactor = 1;
1567 Vector4Set(shader.reflectcolor4f, 1, 1, 1, 1);
1568 shader.r_water_wateralpha = 1;
1569 shader.r_water_waterscroll[0] = 0;
1570 shader.r_water_waterscroll[1] = 0;
1577 shader.specularscalemod = 1;
1578 shader.specularpowermod = 1;
1579 shader.rtlightambient = 0;
1580 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
1581 // JUST GREP FOR "specularscalemod = 1".
1582
1583 dp_strlcpy(shader.name, com_token, sizeof(shader.name));
1584 if (!COM_ParseToken_QuakeC(&text, false) || strcasecmp(com_token, "{"))
1585 {
1586 Con_DPrintf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
1587 break;
1588 }
1589 while (COM_ParseToken_QuakeC(&text, false))
1590 {
1591 if (!strcasecmp(com_token, "}"))
1592 break;
1593 if (!strcasecmp(com_token, "{"))
1594 {
1595 static q3shaderinfo_layer_t dummy;
1596 if (shader.numlayers < Q3SHADER_MAXLAYERS)
1597 {
1598 layer = shader.layers + shader.numlayers++;
1599 }
1600 else
1601 {
1602 // parse and process it anyway, just don't store it (so a map $lightmap or such stuff still is found)
1603 memset(&dummy, 0, sizeof(dummy));
1604 layer = &dummy;
1605 }
1606 layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1607 layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1608 layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1609 layer->blendfunc[0] = GL_ONE;
1610 layer->blendfunc[1] = GL_ZERO;
1611 while (COM_ParseToken_QuakeC(&text, false))
1612 {
1613 if (!strcasecmp(com_token, "}"))
1614 break;
1615 if (!strcasecmp(com_token, "\n"))
1616 continue;
1617 numparameters = 0;
1618 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1619 {
1620 if (j < TEXTURE_MAXFRAMES + 4)
1621 {
1622 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1623 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1624 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1625 else
1626 dp_strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1627 numparameters = j + 1;
1628 }
1629 if (!COM_ParseToken_QuakeC(&text, true))
1630 break;
1631 }
1632 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1633 // parameter[j][0] = 0;
1635 {
1636 Con_DPrintf("%s %i: ", shader.name, shader.numlayers - 1);
1637 for (j = 0;j < numparameters;j++)
1638 Con_DPrintf(" %s", parameter[j]);
1639 Con_DPrint("\n");
1640 }
1641 if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
1642 {
1643 if (numparameters == 2)
1644 {
1645 if (!strcasecmp(parameter[1], "add"))
1646 {
1647 layer->blendfunc[0] = GL_ONE;
1648 layer->blendfunc[1] = GL_ONE;
1649 }
1650 else if (!strcasecmp(parameter[1], "addalpha"))
1651 {
1652 layer->blendfunc[0] = GL_SRC_ALPHA;
1653 layer->blendfunc[1] = GL_ONE;
1654 }
1655 else if (!strcasecmp(parameter[1], "filter"))
1656 {
1657 layer->blendfunc[0] = GL_DST_COLOR;
1658 layer->blendfunc[1] = GL_ZERO;
1659 }
1660 else if (!strcasecmp(parameter[1], "blend"))
1661 {
1662 layer->blendfunc[0] = GL_SRC_ALPHA;
1663 layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
1664 }
1665 }
1666 else if (numparameters == 3)
1667 {
1668 int k;
1669 for (k = 0;k < 2;k++)
1670 {
1671 if (!strcasecmp(parameter[k+1], "GL_ONE"))
1672 layer->blendfunc[k] = GL_ONE;
1673 else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
1674 layer->blendfunc[k] = GL_ZERO;
1675 else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
1676 layer->blendfunc[k] = GL_SRC_COLOR;
1677 else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
1678 layer->blendfunc[k] = GL_SRC_ALPHA;
1679 else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
1680 layer->blendfunc[k] = GL_DST_COLOR;
1681 else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
1682 layer->blendfunc[k] = GL_DST_ALPHA;
1683 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
1684 layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
1685 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
1686 layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
1687 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
1688 layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
1689 else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
1690 layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
1691 else
1692 layer->blendfunc[k] = GL_ONE; // default in case of parsing error
1693 }
1694 }
1695 }
1696 if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
1697 layer->alphatest = true;
1698 if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
1699 {
1700 if (!strcasecmp(parameter[0], "clampmap"))
1701 layer->clampmap = true;
1702 layer->numframes = 1;
1703 layer->framerate = 1;
1704 layer->texturename = (char**)Mem_ExpandableArray_AllocRecord (
1706 layer->texturename[0] = Mem_strdup (q3shaders_mem, parameter[1]);
1707 if (!strcasecmp(parameter[1], "$lightmap"))
1708 shader.lighting = true;
1709 }
1710 else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
1711 {
1712 int i;
1713 layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
1714 layer->framerate = atof(parameter[1]);
1715 layer->texturename = (char **) Mem_Alloc (q3shaders_mem, sizeof (char*) * layer->numframes);
1716 for (i = 0;i < layer->numframes;i++)
1717 layer->texturename[i] = Mem_strdup (q3shaders_mem, parameter[i + 2]);
1718 }
1719 else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen"))
1720 {
1721 int i;
1722 for (i = 0;i < numparameters - 2 && i < Q3RGBGEN_MAXPARMS;i++)
1723 layer->rgbgen.parms[i] = atof(parameter[i+2]);
1724 if (!strcasecmp(parameter[1], "identity")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
1725 else if (!strcasecmp(parameter[1], "const")) layer->rgbgen.rgbgen = Q3RGBGEN_CONST;
1726 else if (!strcasecmp(parameter[1], "entity")) layer->rgbgen.rgbgen = Q3RGBGEN_ENTITY;
1727 else if (!strcasecmp(parameter[1], "exactvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_EXACTVERTEX;
1728 else if (!strcasecmp(parameter[1], "identitylighting")) layer->rgbgen.rgbgen = Q3RGBGEN_IDENTITYLIGHTING;
1729 else if (!strcasecmp(parameter[1], "lightingdiffuse")) layer->rgbgen.rgbgen = Q3RGBGEN_LIGHTINGDIFFUSE;
1730 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSENTITY;
1731 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->rgbgen.rgbgen = Q3RGBGEN_ONEMINUSVERTEX;
1732 else if (!strcasecmp(parameter[1], "vertex")) layer->rgbgen.rgbgen = Q3RGBGEN_VERTEX;
1733 else if (!strcasecmp(parameter[1], "wave"))
1734 {
1735 layer->rgbgen.rgbgen = Q3RGBGEN_WAVE;
1736 layer->rgbgen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1737 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1738 layer->rgbgen.waveparms[i] = atof(parameter[i+3]);
1739 }
1740 else Con_DPrintf("%s parsing warning: unknown rgbgen %s\n", search->filenames[fileindex], parameter[1]);
1741 }
1742 else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen"))
1743 {
1744 int i;
1745 for (i = 0;i < numparameters - 2 && i < Q3ALPHAGEN_MAXPARMS;i++)
1746 layer->alphagen.parms[i] = atof(parameter[i+2]);
1747 if (!strcasecmp(parameter[1], "identity")) layer->alphagen.alphagen = Q3ALPHAGEN_IDENTITY;
1748 else if (!strcasecmp(parameter[1], "const")) layer->alphagen.alphagen = Q3ALPHAGEN_CONST;
1749 else if (!strcasecmp(parameter[1], "entity")) layer->alphagen.alphagen = Q3ALPHAGEN_ENTITY;
1750 else if (!strcasecmp(parameter[1], "lightingspecular")) layer->alphagen.alphagen = Q3ALPHAGEN_LIGHTINGSPECULAR;
1751 else if (!strcasecmp(parameter[1], "oneminusentity")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSENTITY;
1752 else if (!strcasecmp(parameter[1], "oneminusvertex")) layer->alphagen.alphagen = Q3ALPHAGEN_ONEMINUSVERTEX;
1753 else if (!strcasecmp(parameter[1], "portal")) layer->alphagen.alphagen = Q3ALPHAGEN_PORTAL;
1754 else if (!strcasecmp(parameter[1], "vertex")) layer->alphagen.alphagen = Q3ALPHAGEN_VERTEX;
1755 else if (!strcasecmp(parameter[1], "wave"))
1756 {
1757 layer->alphagen.alphagen = Q3ALPHAGEN_WAVE;
1758 layer->alphagen.wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1759 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1760 layer->alphagen.waveparms[i] = atof(parameter[i+3]);
1761 }
1762 else Con_DPrintf("%s parsing warning: unknown alphagen %s\n", search->filenames[fileindex], parameter[1]);
1763 }
1764 else if (numparameters >= 2 && (!strcasecmp(parameter[0], "texgen") || !strcasecmp(parameter[0], "tcgen")))
1765 {
1766 int i;
1767 // observed values: tcgen environment
1768 // no other values have been observed in real shaders
1769 for (i = 0;i < numparameters - 2 && i < Q3TCGEN_MAXPARMS;i++)
1770 layer->tcgen.parms[i] = atof(parameter[i+2]);
1771 if (!strcasecmp(parameter[1], "base")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1772 else if (!strcasecmp(parameter[1], "texture")) layer->tcgen.tcgen = Q3TCGEN_TEXTURE;
1773 else if (!strcasecmp(parameter[1], "environment")) layer->tcgen.tcgen = Q3TCGEN_ENVIRONMENT;
1774 else if (!strcasecmp(parameter[1], "lightmap")) layer->tcgen.tcgen = Q3TCGEN_LIGHTMAP;
1775 else if (!strcasecmp(parameter[1], "vector")) layer->tcgen.tcgen = Q3TCGEN_VECTOR;
1776 else Con_DPrintf("%s parsing warning: unknown tcgen mode %s\n", search->filenames[fileindex], parameter[1]);
1777 }
1778 else if (numparameters >= 2 && !strcasecmp(parameter[0], "tcmod"))
1779 {
1780 int i, tcmodindex;
1781 // observed values:
1782 // tcmod rotate #
1783 // tcmod scale # #
1784 // tcmod scroll # #
1785 // tcmod stretch sin # # # #
1786 // tcmod stretch triangle # # # #
1787 // tcmod transform # # # # # #
1788 // tcmod turb # # # #
1789 // tcmod turb sin # # # # (this is bogus)
1790 // no other values have been observed in real shaders
1791 for (tcmodindex = 0;tcmodindex < Q3MAXTCMODS;tcmodindex++)
1792 if (!layer->tcmods[tcmodindex].tcmod)
1793 break;
1794 if (tcmodindex < Q3MAXTCMODS)
1795 {
1796 for (i = 0;i < numparameters - 2 && i < Q3TCMOD_MAXPARMS;i++)
1797 layer->tcmods[tcmodindex].parms[i] = atof(parameter[i+2]);
1798 if (!strcasecmp(parameter[1], "entitytranslate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ENTITYTRANSLATE;
1799 else if (!strcasecmp(parameter[1], "rotate")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_ROTATE;
1800 else if (!strcasecmp(parameter[1], "scale")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCALE;
1801 else if (!strcasecmp(parameter[1], "scroll")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_SCROLL;
1802 else if (!strcasecmp(parameter[1], "page")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_PAGE;
1803 else if (!strcasecmp(parameter[1], "stretch"))
1804 {
1805 layer->tcmods[tcmodindex].tcmod = Q3TCMOD_STRETCH;
1806 layer->tcmods[tcmodindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[2]);
1807 for (i = 0;i < numparameters - 3 && i < Q3WAVEPARMS;i++)
1808 layer->tcmods[tcmodindex].waveparms[i] = atof(parameter[i+3]);
1809 }
1810 else if (!strcasecmp(parameter[1], "transform")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TRANSFORM;
1811 else if (!strcasecmp(parameter[1], "turb")) layer->tcmods[tcmodindex].tcmod = Q3TCMOD_TURBULENT;
1812 else Con_DPrintf("%s parsing warning: unknown tcmod mode %s\n", search->filenames[fileindex], parameter[1]);
1813 }
1814 else
1815 Con_DPrintf("%s parsing warning: too many tcmods on one layer\n", search->filenames[fileindex]);
1816 }
1817 // break out a level if it was a closing brace (not using the character here to not confuse vim)
1818 if (!strcasecmp(com_token, "}"))
1819 break;
1820 }
1821 if (layer->rgbgen.rgbgen == Q3RGBGEN_LIGHTINGDIFFUSE || layer->rgbgen.rgbgen == Q3RGBGEN_VERTEX)
1822 shader.lighting = true;
1823 if (layer->alphagen.alphagen == Q3ALPHAGEN_VERTEX)
1824 {
1825 if (layer == shader.layers + 0)
1826 {
1827 // vertex controlled transparency
1828 shader.vertexalpha = true;
1829 }
1830 else
1831 {
1832 // multilayer terrain shader or similar
1833 shader.textureblendalpha = true;
1835 shader.layers[0].dptexflags |= TEXF_ALPHA;
1836 }
1837 }
1838
1840 {
1841 // for a long while, DP treated GL_ONE GL_ONE as GL_SRC_ALPHA GL_ONE
1842 // this cvar brings back this behaviour
1843 if(layer->blendfunc[0] == GL_ONE && layer->blendfunc[1] == GL_ONE)
1844 layer->blendfunc[0] = GL_SRC_ALPHA;
1845 }
1846
1847 layer->dptexflags = 0;
1848 if (layer->alphatest)
1849 layer->dptexflags |= TEXF_ALPHA;
1850 switch(layer->blendfunc[0])
1851 {
1852 case GL_SRC_ALPHA:
1854 layer->dptexflags |= TEXF_ALPHA;
1855 break;
1856 }
1857 switch(layer->blendfunc[1])
1858 {
1859 case GL_SRC_ALPHA:
1861 layer->dptexflags |= TEXF_ALPHA;
1862 break;
1863 }
1864 if (!(shader.surfaceparms & Q3SURFACEPARM_NOMIPMAPS))
1865 layer->dptexflags |= TEXF_MIPMAP;
1866 if (!(shader.textureflags & Q3TEXTUREFLAG_NOPICMIP))
1867 layer->dptexflags |= TEXF_PICMIP | TEXF_COMPRESS;
1868 if (layer->clampmap)
1869 layer->dptexflags |= TEXF_CLAMP;
1870 continue;
1871 }
1872 numparameters = 0;
1873 for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
1874 {
1875 if (j < TEXTURE_MAXFRAMES + 4)
1876 {
1877 // remap dp_water to dpwater, dp_reflect to dpreflect, etc.
1878 if(j == 0 && !strncasecmp(com_token, "dp_", 3))
1879 dpsnprintf(parameter[j], sizeof(parameter[j]), "dp%s", &com_token[3]);
1880 else
1881 dp_strlcpy(parameter[j], com_token, sizeof(parameter[j]));
1882 numparameters = j + 1;
1883 }
1884 if (!COM_ParseToken_QuakeC(&text, true))
1885 break;
1886 }
1887 //for (j = numparameters;j < TEXTURE_MAXFRAMES + 4;j++)
1888 // parameter[j][0] = 0;
1889 if (fileindex == 0 && !strcasecmp(com_token, "}"))
1890 break;
1892 {
1893 Con_DPrintf("%s: ", shader.name);
1894 for (j = 0;j < numparameters;j++)
1895 Con_DPrintf(" %s", parameter[j]);
1896 Con_DPrint("\n");
1897 }
1898 if (numparameters < 1)
1899 continue;
1900 if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
1901 {
1902 if (!strcasecmp(parameter[1], "alphashadow"))
1904 else if (!strcasecmp(parameter[1], "areaportal"))
1906 else if (!strcasecmp(parameter[1], "botclip"))
1908 else if (!strcasecmp(parameter[1], "clusterportal"))
1910 else if (!strcasecmp(parameter[1], "detail"))
1912 else if (!strcasecmp(parameter[1], "donotenter"))
1914 else if (!strcasecmp(parameter[1], "dust"))
1916 else if (!strcasecmp(parameter[1], "hint"))
1918 else if (!strcasecmp(parameter[1], "fog"))
1920 else if (!strcasecmp(parameter[1], "lava"))
1922 else if (!strcasecmp(parameter[1], "lightfilter"))
1924 else if (!strcasecmp(parameter[1], "lightgrid"))
1926 else if (!strcasecmp(parameter[1], "metalsteps"))
1928 else if (!strcasecmp(parameter[1], "nodamage"))
1930 else if (!strcasecmp(parameter[1], "nodlight"))
1932 else if (!strcasecmp(parameter[1], "nodraw"))
1934 else if (!strcasecmp(parameter[1], "nodrop"))
1936 else if (!strcasecmp(parameter[1], "noimpact"))
1938 else if (!strcasecmp(parameter[1], "nolightmap"))
1940 else if (!strcasecmp(parameter[1], "nomarks"))
1942 else if (!strcasecmp(parameter[1], "nomipmaps"))
1944 else if (!strcasecmp(parameter[1], "nonsolid"))
1946 else if (!strcasecmp(parameter[1], "origin"))
1948 else if (!strcasecmp(parameter[1], "playerclip"))
1950 else if (!strcasecmp(parameter[1], "sky"))
1952 else if (!strcasecmp(parameter[1], "slick"))
1954 else if (!strcasecmp(parameter[1], "slime"))
1956 else if (!strcasecmp(parameter[1], "structural"))
1958 else if (!strcasecmp(parameter[1], "trans"))
1960 else if (!strcasecmp(parameter[1], "water"))
1962 else if (!strcasecmp(parameter[1], "pointlight"))
1964 else if (!strcasecmp(parameter[1], "antiportal"))
1966 else if (!strcasecmp(parameter[1], "skip"))
1967 ; // shader.surfaceparms |= Q3SURFACEPARM_SKIP; FIXME we don't have enough #defines for this any more, and the engine doesn't need this one anyway
1968 else
1969 {
1970 // try custom surfaceparms
1971 for (j = 0; j < numcustsurfaceflags; j++)
1972 {
1973 if (!strcasecmp(custsurfaceparmnames[j], parameter[1]))
1974 {
1975 shader.surfaceflags |= custsurfaceflags[j];
1976 break;
1977 }
1978 }
1979 // failed all
1980 if (j == numcustsurfaceflags)
1981 Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
1982 }
1983 }
1984 else if (!strcasecmp(parameter[0], "dpshadow"))
1985 shader.dpshadow = true;
1986 else if (!strcasecmp(parameter[0], "dpnoshadow"))
1987 shader.dpnoshadow = true;
1988 else if (!strcasecmp(parameter[0], "dpnortlight"))
1989 shader.dpnortlight = true;
1990 else if (!strcasecmp(parameter[0], "dpreflectcube"))
1991 dp_strlcpy(shader.dpreflectcube, parameter[1], sizeof(shader.dpreflectcube));
1992 else if (!strcasecmp(parameter[0], "dpmeshcollisions"))
1993 shader.dpmeshcollisions = true;
1994 // this sets dpshaderkill to true if dpshaderkillifcvarzero was used, and to false if dpnoshaderkillifcvarzero was used
1995 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvarzero")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvarzero")) && numparameters >= 2)
1996 {
1997 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) == 0.0f)
1998 shader.dpshaderkill = dpshaderkill;
1999 }
2000 // this sets dpshaderkill to true if dpshaderkillifcvar was used, and to false if dpnoshaderkillifcvar was used
2001 else if (((dpshaderkill = !strcasecmp(parameter[0], "dpshaderkillifcvar")) || !strcasecmp(parameter[0], "dpnoshaderkillifcvar")) && numparameters >= 2)
2002 {
2003 const char *op = NULL;
2004 if (numparameters >= 3)
2005 op = parameter[2];
2006 if(!op)
2007 {
2008 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) != 0.0f)
2009 shader.dpshaderkill = dpshaderkill;
2010 }
2011 else if (numparameters >= 4 && !strcmp(op, "=="))
2012 {
2013 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) == atof(parameter[3]))
2014 shader.dpshaderkill = dpshaderkill;
2015 }
2016 else if (numparameters >= 4 && !strcmp(op, "!="))
2017 {
2018 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) != atof(parameter[3]))
2019 shader.dpshaderkill = dpshaderkill;
2020 }
2021 else if (numparameters >= 4 && !strcmp(op, ">"))
2022 {
2023 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) > atof(parameter[3]))
2024 shader.dpshaderkill = dpshaderkill;
2025 }
2026 else if (numparameters >= 4 && !strcmp(op, "<"))
2027 {
2028 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) < atof(parameter[3]))
2029 shader.dpshaderkill = dpshaderkill;
2030 }
2031 else if (numparameters >= 4 && !strcmp(op, ">="))
2032 {
2033 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) >= atof(parameter[3]))
2034 shader.dpshaderkill = dpshaderkill;
2035 }
2036 else if (numparameters >= 4 && !strcmp(op, "<="))
2037 {
2038 if (Cvar_VariableValue(&cvars_all, parameter[1], ~0) <= atof(parameter[3]))
2039 shader.dpshaderkill = dpshaderkill;
2040 }
2041 else
2042 {
2043 Con_DPrintf("%s parsing warning: unknown dpshaderkillifcvar op \"%s\", or not enough arguments\n", search->filenames[fileindex], op);
2044 }
2045 }
2046 else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
2047 {
2048 // some q3 skies don't have the sky parm set
2050 dp_strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2051 }
2052 else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
2053 {
2054 // some q3 skies don't have the sky parm set
2056 if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
2057 dp_strlcpy(shader.skyboxname, parameter[1], sizeof(shader.skyboxname));
2058 }
2059 else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
2060 {
2061 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
2063 }
2064 else if (!strcasecmp(parameter[0], "nomipmaps"))
2066 else if (!strcasecmp(parameter[0], "nopicmip"))
2068 else if (!strcasecmp(parameter[0], "polygonoffset"))
2070 else if (!strcasecmp(parameter[0], "dppolygonoffset"))
2071 {
2073 if(numparameters >= 2)
2074 {
2075 shader.biaspolygonfactor = atof(parameter[1]);
2076 if(numparameters >= 3)
2077 shader.biaspolygonoffset = atof(parameter[2]);
2078 else
2079 shader.biaspolygonoffset = 0;
2080 }
2081 }
2082 else if (!strcasecmp(parameter[0], "dptransparentsort") && numparameters >= 2)
2083 {
2085 if (!strcasecmp(parameter[1], "sky"))
2087 else if (!strcasecmp(parameter[1], "distance"))
2089 else if (!strcasecmp(parameter[1], "hud"))
2091 else
2092 Con_DPrintf("%s parsing warning: unknown dptransparentsort category \"%s\", or not enough arguments\n", search->filenames[fileindex], parameter[1]);
2093 }
2094 else if (!strcasecmp(parameter[0], "dprefract") && numparameters >= 5)
2095 {
2097 shader.refractfactor = atof(parameter[1]);
2098 Vector4Set(shader.refractcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), 1);
2099 }
2100 else if (!strcasecmp(parameter[0], "dpreflect") && numparameters >= 6)
2101 {
2103 shader.reflectfactor = atof(parameter[1]);
2104 Vector4Set(shader.reflectcolor4f, atof(parameter[2]), atof(parameter[3]), atof(parameter[4]), atof(parameter[5]));
2105 }
2106 else if (!strcasecmp(parameter[0], "dpcamera"))
2107 {
2109 }
2110 else if (!strcasecmp(parameter[0], "dpwater") && numparameters >= 12)
2111 {
2113 shader.reflectmin = atof(parameter[1]);
2114 shader.reflectmax = atof(parameter[2]);
2115 shader.refractfactor = atof(parameter[3]);
2116 shader.reflectfactor = atof(parameter[4]);
2117 Vector4Set(shader.refractcolor4f, atof(parameter[5]), atof(parameter[6]), atof(parameter[7]), 1);
2118 Vector4Set(shader.reflectcolor4f, atof(parameter[8]), atof(parameter[9]), atof(parameter[10]), 1);
2119 shader.r_water_wateralpha = atof(parameter[11]);
2120 }
2121 else if (!strcasecmp(parameter[0], "dpwaterscroll") && numparameters >= 3)
2122 {
2123 shader.r_water_waterscroll[0] = 1/atof(parameter[1]);
2124 shader.r_water_waterscroll[1] = 1/atof(parameter[2]);
2125 }
2126 else if (!strcasecmp(parameter[0], "dpglossintensitymod") && numparameters >= 2)
2127 {
2128 shader.specularscalemod = atof(parameter[1]);
2129 }
2130 else if (!strcasecmp(parameter[0], "dpglossexponentmod") && numparameters >= 2)
2131 {
2132 shader.specularpowermod = atof(parameter[1]);
2133 }
2134 else if (!strcasecmp(parameter[0], "dprtlightambient") && numparameters >= 2)
2135 {
2136 shader.rtlightambient = atof(parameter[1]);
2137 }
2138 else if (!strcasecmp(parameter[0], "dpoffsetmapping") && numparameters >= 2)
2139 {
2140 if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "off"))
2142 else if (!strcasecmp(parameter[1], "default") || !strcasecmp(parameter[1], "normal"))
2144 else if (!strcasecmp(parameter[1], "linear"))
2146 else if (!strcasecmp(parameter[1], "relief"))
2148 if (numparameters >= 3)
2149 shader.offsetscale = atof(parameter[2]);
2150 if (numparameters >= 5)
2151 {
2152 if(!strcasecmp(parameter[3], "bias"))
2153 shader.offsetbias = atof(parameter[4]);
2154 else if(!strcasecmp(parameter[3], "match"))
2155 shader.offsetbias = 1.0f - atof(parameter[4]);
2156 else if(!strcasecmp(parameter[3], "match8"))
2157 shader.offsetbias = 1.0f - atof(parameter[4]) / 255.0f;
2158 else if(!strcasecmp(parameter[3], "match16"))
2159 shader.offsetbias = 1.0f - atof(parameter[4]) / 65535.0f;
2160 }
2161 }
2162 else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
2163 {
2164 int i, deformindex;
2165 for (deformindex = 0;deformindex < Q3MAXDEFORMS;deformindex++)
2166 if (!shader.deforms[deformindex].deform)
2167 break;
2168 if (deformindex < Q3MAXDEFORMS)
2169 {
2170 for (i = 0;i < numparameters - 2 && i < Q3DEFORM_MAXPARMS;i++)
2171 shader.deforms[deformindex].parms[i] = atof(parameter[i+2]);
2172 if (!strcasecmp(parameter[1], "projectionshadow")) shader.deforms[deformindex].deform = Q3DEFORM_PROJECTIONSHADOW;
2173 else if (!strcasecmp(parameter[1], "autosprite" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE;
2174 else if (!strcasecmp(parameter[1], "autosprite2" )) shader.deforms[deformindex].deform = Q3DEFORM_AUTOSPRITE2;
2175 else if (!strcasecmp(parameter[1], "text0" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT0;
2176 else if (!strcasecmp(parameter[1], "text1" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT1;
2177 else if (!strcasecmp(parameter[1], "text2" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT2;
2178 else if (!strcasecmp(parameter[1], "text3" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT3;
2179 else if (!strcasecmp(parameter[1], "text4" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT4;
2180 else if (!strcasecmp(parameter[1], "text5" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT5;
2181 else if (!strcasecmp(parameter[1], "text6" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT6;
2182 else if (!strcasecmp(parameter[1], "text7" )) shader.deforms[deformindex].deform = Q3DEFORM_TEXT7;
2183 else if (!strcasecmp(parameter[1], "bulge" )) shader.deforms[deformindex].deform = Q3DEFORM_BULGE;
2184 else if (!strcasecmp(parameter[1], "normal" )) shader.deforms[deformindex].deform = Q3DEFORM_NORMAL;
2185 else if (!strcasecmp(parameter[1], "wave" ))
2186 {
2187 shader.deforms[deformindex].deform = Q3DEFORM_WAVE;
2188 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[3]);
2189 for (i = 0;i < numparameters - 4 && i < Q3WAVEPARMS;i++)
2190 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+4]);
2191 }
2192 else if (!strcasecmp(parameter[1], "move" ))
2193 {
2194 shader.deforms[deformindex].deform = Q3DEFORM_MOVE;
2195 shader.deforms[deformindex].wavefunc = Mod_LoadQ3Shaders_EnumerateWaveFunc(parameter[5]);
2196 for (i = 0;i < numparameters - 6 && i < Q3WAVEPARMS;i++)
2197 shader.deforms[deformindex].waveparms[i] = atof(parameter[i+6]);
2198 }
2199 }
2200 }
2201 }
2202 // hide this shader if a cvar said it should be killed
2203 if (shader.dpshaderkill)
2204 shader.numlayers = 0;
2205 // fix up multiple reflection types
2208
2209 Q3Shader_AddToHash (&shader);
2210 }
2211 Mem_Free(f);
2212 }
2213 FS_FreeSearch(search);
2214 // free custinfoparm values
2215 for (j = 0; j < numcustsurfaceflags; j++)
2216 Mem_Free(custsurfaceparmnames[j]);
2217}
2218
2220{
2221 unsigned short hash;
2222 q3shader_hash_entry_t* entry;
2223 if (!q3shaders_mem)
2225 hash = CRC_Block_CaseInsensitive ((const unsigned char *)name, strlen (name));
2226 entry = q3shader_data->hash + (hash % Q3SHADER_HASH_SIZE);
2227 while (entry != NULL)
2228 {
2229 if (strcasecmp (entry->shader.name, name) == 0)
2230 return &entry->shader;
2231 entry = entry->chain;
2232 }
2233 return NULL;
2234}
2235
2237{
2238 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2239 shaderpass->framerate = 0.0f;
2240 shaderpass->numframes = 1;
2241 shaderpass->blendfunc[0] = GL_ONE;
2242 shaderpass->blendfunc[1] = GL_ZERO;
2243 shaderpass->rgbgen.rgbgen = Q3RGBGEN_IDENTITY;
2245 shaderpass->alphatest = false;
2246 shaderpass->tcgen.tcgen = Q3TCGEN_TEXTURE;
2247 shaderpass->skinframes[0] = skinframe;
2248 return shaderpass;
2249}
2250
2251texture_shaderpass_t *Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
2252{
2253 int j;
2254 texture_shaderpass_t *shaderpass = (texture_shaderpass_t *)Mem_Alloc(mempool, sizeof(*shaderpass));
2255 shaderpass->alphatest = layer->alphatest != 0;
2256 shaderpass->framerate = layer->framerate;
2257 shaderpass->numframes = layer->numframes;
2258 shaderpass->blendfunc[0] = layer->blendfunc[0];
2259 shaderpass->blendfunc[1] = layer->blendfunc[1];
2260 shaderpass->rgbgen = layer->rgbgen;
2261 shaderpass->alphagen = layer->alphagen;
2262 shaderpass->tcgen = layer->tcgen;
2263 for (j = 0; j < Q3MAXTCMODS && layer->tcmods[j].tcmod != Q3TCMOD_NONE; j++)
2264 shaderpass->tcmods[j] = layer->tcmods[j];
2265 for (j = 0; j < layer->numframes; j++)
2266 shaderpass->skinframes[j] = R_SkinFrame_LoadExternal(layer->texturename[j], texflags, false, true);
2267 return shaderpass;
2268}
2269
2270qbool Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qbool warnmissing, qbool fallback, int defaulttexflags, int defaultmaterialflags)
2271{
2272 int texflagsmask, texflagsor;
2273 qbool success = true;
2274 shader_t *shader;
2275 if (!name)
2276 name = "";
2277 dp_strlcpy(texture->name, name, sizeof(texture->name));
2278 texture->basealpha = 1.0f;
2279 shader = name[0] ? Mod_LookupQ3Shader(name) : NULL;
2280
2281 // allow disabling of picmip or compression by defaulttexflags
2282 texflagsmask = ~0;
2283 if(!(defaulttexflags & TEXF_PICMIP))
2284 texflagsmask &= ~TEXF_PICMIP;
2285 if(!(defaulttexflags & TEXF_COMPRESS))
2286 texflagsmask &= ~TEXF_COMPRESS;
2287 texflagsor = 0;
2288 if(defaulttexflags & TEXF_ISWORLD)
2289 texflagsor |= TEXF_ISWORLD;
2290 if(defaulttexflags & TEXF_ISSPRITE)
2291 texflagsor |= TEXF_ISSPRITE;
2292 // unless later loaded from the shader
2294 texture->offsetscale = 1;
2295 texture->offsetbias = 0;
2296 texture->specularscalemod = 1;
2297 texture->specularpowermod = 1;
2298 texture->rtlightambient = 0;
2299 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2300 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2301 // JUST GREP FOR "specularscalemod = 1".
2302
2303 if (shader)
2304 {
2306 Con_Printf("%s: loaded shader for %s\n", modelname, name);
2307
2308 if (shader->surfaceparms & Q3SURFACEPARM_SKY)
2309 {
2310 texture->basematerialflags = MATERIALFLAG_SKY;
2311 if (shader->skyboxname[0] && loadmodel)
2312 {
2313 // quake3 seems to append a _ to the skybox name, so this must do so as well
2314 dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
2315 }
2316 }
2317 else if ((texture->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
2318 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2319 else
2320 texture->basematerialflags = MATERIALFLAG_WALL;
2321
2322 if (shader->layers[0].alphatest)
2327 {
2328 texture->biaspolygonoffset += shader->biaspolygonoffset;
2329 texture->biaspolygonfactor += shader->biaspolygonfactor;
2330 }
2332 texture->basematerialflags |= MATERIALFLAG_REFRACTION;
2334 texture->basematerialflags |= MATERIALFLAG_REFLECTION;
2336 texture->basematerialflags |= MATERIALFLAG_WATERSHADER;
2337 if (shader->textureflags & Q3TEXTUREFLAG_CAMERA)
2338 texture->basematerialflags |= MATERIALFLAG_CAMERA;
2339 texture->customblendfunc[0] = GL_ONE;
2340 texture->customblendfunc[1] = GL_ZERO;
2341 texture->transparentsort = shader->transparentsort;
2342 if (shader->numlayers > 0)
2343 {
2344 texture->customblendfunc[0] = shader->layers[0].blendfunc[0];
2345 texture->customblendfunc[1] = shader->layers[0].blendfunc[1];
2346/*
2347Q3 shader blendfuncs actually used in the game (* = supported by DP)
2348* additive GL_ONE GL_ONE
2349additive weird GL_ONE GL_SRC_ALPHA
2350additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
2351* alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
2352alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
2353brighten GL_DST_COLOR GL_ONE
2354brighten GL_ONE GL_SRC_COLOR
2355brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
2356brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
2357* modulate GL_DST_COLOR GL_ZERO
2358* modulate GL_ZERO GL_SRC_COLOR
2359modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
2360modulate inverse alpha GL_ZERO GL_SRC_ALPHA
2361modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
2362* modulate x2 GL_DST_COLOR GL_SRC_COLOR
2363* no blend GL_ONE GL_ZERO
2364nothing GL_ZERO GL_ONE
2365*/
2366 // if not opaque, figure out what blendfunc to use
2367 if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
2368 {
2369 if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
2371 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
2373 else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2375 else
2377 }
2378 }
2379 if (!shader->lighting)
2380 texture->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
2381
2382 // here be dragons: convert quake3 shaders to material
2383 if (shader->numlayers > 0)
2384 {
2385 int i;
2386 int terrainbackgroundlayer = -1;
2387 int lightmaplayer = -1;
2388 int alphagenspecularlayer = -1;
2389 int rgbgenvertexlayer = -1;
2390 int rgbgendiffuselayer = -1;
2391 int materiallayer = -1;
2392 int endofprelayers = 0;
2393 int firstpostlayer = 0;
2394 int shaderpassindex = 0;
2395 for (i = 0; i < shader->numlayers; i++)
2396 {
2397 if (shader->layers[i].texturename != NULL && !strcasecmp(shader->layers[i].texturename[0], "$lightmap"))
2398 lightmaplayer = i;
2399 if (shader->layers[i].rgbgen.rgbgen == Q3RGBGEN_VERTEX)
2400 rgbgenvertexlayer = i;
2402 rgbgendiffuselayer = i;
2404 alphagenspecularlayer = i;
2405 }
2406 if (shader->numlayers >= 2
2407 && shader->layers[1].alphagen.alphagen == Q3ALPHAGEN_VERTEX
2408 && (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ZERO && !shader->layers[0].alphatest)
2409 && ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
2410 || (shader->layers[1].blendfunc[0] == GL_ONE && shader->layers[1].blendfunc[1] == GL_ZERO && shader->layers[1].alphatest)))
2411 {
2412 // terrain blend or certain other effects involving alphatest over a regular layer
2413 terrainbackgroundlayer = 0;
2414 materiallayer = 1;
2415 // terrain may be vertex lit (in which case both layers are rgbGen vertex) or lightmapped (in which ase the third layer is lightmap)
2416 firstpostlayer = lightmaplayer >= 0 ? lightmaplayer + 1 : materiallayer + 1;
2417 }
2418 else if (lightmaplayer == 0)
2419 {
2420 // ordinary texture but with $lightmap before diffuse
2421 materiallayer = 1;
2422 firstpostlayer = lightmaplayer + 2;
2423 }
2424 else if (lightmaplayer >= 1)
2425 {
2426 // ordinary texture - we don't properly apply lighting to the prelayers, but oh well...
2427 endofprelayers = lightmaplayer - 1;
2428 materiallayer = lightmaplayer - 1;
2429 firstpostlayer = lightmaplayer + 1;
2430 }
2431 else if (rgbgenvertexlayer >= 0)
2432 {
2433 // map models with baked lighting
2434 materiallayer = rgbgenvertexlayer;
2435 endofprelayers = rgbgenvertexlayer;
2436 firstpostlayer = rgbgenvertexlayer + 1;
2437 // special case for rgbgen vertex if MATERIALFLAG_VERTEXCOLOR is expected on this material
2438 if (defaultmaterialflags & MATERIALFLAG_VERTEXCOLOR)
2440 }
2441 else if (rgbgendiffuselayer >= 0)
2442 {
2443 // entity models with dynamic lighting
2444 materiallayer = rgbgendiffuselayer;
2445 endofprelayers = rgbgendiffuselayer;
2446 firstpostlayer = rgbgendiffuselayer + 1;
2447 // 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)...
2448 if (alphagenspecularlayer >= 0)
2449 firstpostlayer = alphagenspecularlayer + 1;
2450 }
2451 else
2452 {
2453 // special effects shaders - treat first as primary layer and do everything else as post
2454 endofprelayers = 0;
2455 materiallayer = 0;
2456 firstpostlayer = 1;
2457 }
2458 // convert the main material layer
2459 // 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
2460 if (materiallayer >= 0)
2461 texture->materialshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[materiallayer], materiallayer, (shader->layers[materiallayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2462 // convert the terrain background blend layer (if any)
2463 if (terrainbackgroundlayer >= 0)
2464 texture->backgroundshaderpass = texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[terrainbackgroundlayer], terrainbackgroundlayer, (shader->layers[terrainbackgroundlayer].dptexflags & texflagsmask) | texflagsor, texture->name);
2465 // convert the prepass layers (if any)
2466 texture->startpreshaderpass = shaderpassindex;
2467 for (i = 0; i < endofprelayers; i++)
2468 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2469 texture->endpreshaderpass = shaderpassindex;
2470 texture->startpostshaderpass = shaderpassindex;
2471 // convert the postpass layers (if any)
2472 for (i = firstpostlayer; i < shader->numlayers; i++)
2473 texture->shaderpasses[shaderpassindex++] = Mod_CreateShaderPassFromQ3ShaderLayer(mempool, modelname, &shader->layers[i], i, (shader->layers[i].dptexflags & texflagsmask) | texflagsor, texture->name);
2474 texture->startpostshaderpass = shaderpassindex;
2475 }
2476
2477 if (shader->dpshadow)
2478 texture->basematerialflags &= ~MATERIALFLAG_NOSHADOW;
2479 if (shader->dpnoshadow)
2480 texture->basematerialflags |= MATERIALFLAG_NOSHADOW;
2481 if (shader->dpnortlight)
2482 texture->basematerialflags |= MATERIALFLAG_NORTLIGHT;
2483 if (shader->vertexalpha)
2484 texture->basematerialflags |= MATERIALFLAG_ALPHAGEN_VERTEX;
2485 memcpy(texture->deforms, shader->deforms, sizeof(texture->deforms));
2486 texture->reflectmin = shader->reflectmin;
2487 texture->reflectmax = shader->reflectmax;
2488 texture->refractfactor = shader->refractfactor;
2489 Vector4Copy(shader->refractcolor4f, texture->refractcolor4f);
2490 texture->reflectfactor = shader->reflectfactor;
2491 Vector4Copy(shader->reflectcolor4f, texture->reflectcolor4f);
2492 texture->r_water_wateralpha = shader->r_water_wateralpha;
2493 Vector2Copy(shader->r_water_waterscroll, texture->r_water_waterscroll);
2494 texture->offsetmapping = shader->offsetmapping;
2495 texture->offsetscale = shader->offsetscale;
2496 texture->offsetbias = shader->offsetbias;
2497 texture->specularscalemod = shader->specularscalemod;
2498 texture->specularpowermod = shader->specularpowermod;
2499 texture->rtlightambient = shader->rtlightambient;
2501 if (shader->dpreflectcube[0])
2502 texture->reflectcubetexture = R_GetCubemap(shader->dpreflectcube);
2503
2504 // set up default supercontents (on q3bsp this is overridden by the q3bsp loader)
2506 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents = SUPERCONTENTS_LAVA ;
2507 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents = SUPERCONTENTS_SLIME ;
2508 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents = SUPERCONTENTS_WATER ;
2509 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents = 0 ;
2511 if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->supercontents = SUPERCONTENTS_MONSTERCLIP ;
2512 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents = SUPERCONTENTS_SKY ;
2513
2514 // if (shader->surfaceparms & Q3SURFACEPARM_ALPHASHADOW ) texture->supercontents |= SUPERCONTENTS_ALPHASHADOW ;
2515 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->supercontents |= SUPERCONTENTS_AREAPORTAL ;
2516 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->supercontents |= SUPERCONTENTS_CLUSTERPORTAL;
2517 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->supercontents |= SUPERCONTENTS_DETAIL ;
2518 if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->supercontents |= SUPERCONTENTS_DONOTENTER ;
2519 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->supercontents |= SUPERCONTENTS_FOG ;
2520 if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->supercontents |= SUPERCONTENTS_LAVA ;
2521 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTFILTER ) texture->supercontents |= SUPERCONTENTS_LIGHTFILTER ;
2522 // if (shader->surfaceparms & Q3SURFACEPARM_METALSTEPS ) texture->supercontents |= SUPERCONTENTS_METALSTEPS ;
2523 // if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->supercontents |= SUPERCONTENTS_NODAMAGE ;
2524 // if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->supercontents |= SUPERCONTENTS_NODLIGHT ;
2525 // if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->supercontents |= SUPERCONTENTS_NODRAW ;
2526 if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->supercontents |= SUPERCONTENTS_NODROP ;
2527 // if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->supercontents |= SUPERCONTENTS_NOIMPACT ;
2528 // if (shader->surfaceparms & Q3SURFACEPARM_NOLIGHTMAP ) texture->supercontents |= SUPERCONTENTS_NOLIGHTMAP ;
2529 // if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->supercontents |= SUPERCONTENTS_NOMARKS ;
2530 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->supercontents |= SUPERCONTENTS_NOMIPMAPS ;
2531 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->supercontents &=~SUPERCONTENTS_SOLID ;
2532 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->supercontents |= SUPERCONTENTS_ORIGIN ;
2533 if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->supercontents |= SUPERCONTENTS_PLAYERCLIP ;
2534 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->supercontents |= SUPERCONTENTS_SKY ;
2535 // if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->supercontents |= SUPERCONTENTS_SLICK ;
2536 if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->supercontents |= SUPERCONTENTS_SLIME ;
2537 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->supercontents |= SUPERCONTENTS_STRUCTURAL ;
2538 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->supercontents |= SUPERCONTENTS_TRANS ;
2539 if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->supercontents |= SUPERCONTENTS_WATER ;
2540 // if (shader->surfaceparms & Q3SURFACEPARM_POINTLIGHT ) texture->supercontents |= SUPERCONTENTS_POINTLIGHT ;
2541 // if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->supercontents |= SUPERCONTENTS_HINT ;
2542 // if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->supercontents |= SUPERCONTENTS_DUST ;
2544 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->supercontents |= SUPERCONTENTS_LIGHTGRID ;
2545 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->supercontents |= SUPERCONTENTS_ANTIPORTAL ;
2546
2547 texture->surfaceflags = shader->surfaceflags;
2549 // if (shader->surfaceparms & Q3SURFACEPARM_AREAPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_AREAPORTAL ;
2550 // if (shader->surfaceparms & Q3SURFACEPARM_CLUSTERPORTAL) texture->surfaceflags |= Q3SURFACEFLAG_CLUSTERPORTAL;
2551 // if (shader->surfaceparms & Q3SURFACEPARM_DETAIL ) texture->surfaceflags |= Q3SURFACEFLAG_DETAIL ;
2552 // if (shader->surfaceparms & Q3SURFACEPARM_DONOTENTER ) texture->surfaceflags |= Q3SURFACEFLAG_DONOTENTER ;
2553 // if (shader->surfaceparms & Q3SURFACEPARM_FOG ) texture->surfaceflags |= Q3SURFACEFLAG_FOG ;
2554 // if (shader->surfaceparms & Q3SURFACEPARM_LAVA ) texture->surfaceflags |= Q3SURFACEFLAG_LAVA ;
2557 if (shader->surfaceparms & Q3SURFACEPARM_NODAMAGE ) texture->surfaceflags |= Q3SURFACEFLAG_NODAMAGE ;
2558 if (shader->surfaceparms & Q3SURFACEPARM_NODLIGHT ) texture->surfaceflags |= Q3SURFACEFLAG_NODLIGHT ;
2559 if (shader->surfaceparms & Q3SURFACEPARM_NODRAW ) texture->surfaceflags |= Q3SURFACEFLAG_NODRAW ;
2560 // if (shader->surfaceparms & Q3SURFACEPARM_NODROP ) texture->surfaceflags |= Q3SURFACEFLAG_NODROP ;
2561 if (shader->surfaceparms & Q3SURFACEPARM_NOIMPACT ) texture->surfaceflags |= Q3SURFACEFLAG_NOIMPACT ;
2563 if (shader->surfaceparms & Q3SURFACEPARM_NOMARKS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMARKS ;
2564 // if (shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS ) texture->surfaceflags |= Q3SURFACEFLAG_NOMIPMAPS ;
2565 if (shader->surfaceparms & Q3SURFACEPARM_NONSOLID ) texture->surfaceflags |= Q3SURFACEFLAG_NONSOLID ;
2566 // if (shader->surfaceparms & Q3SURFACEPARM_ORIGIN ) texture->surfaceflags |= Q3SURFACEFLAG_ORIGIN ;
2567 // if (shader->surfaceparms & Q3SURFACEPARM_PLAYERCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_PLAYERCLIP ;
2568 if (shader->surfaceparms & Q3SURFACEPARM_SKY ) texture->surfaceflags |= Q3SURFACEFLAG_SKY ;
2569 if (shader->surfaceparms & Q3SURFACEPARM_SLICK ) texture->surfaceflags |= Q3SURFACEFLAG_SLICK ;
2570 // if (shader->surfaceparms & Q3SURFACEPARM_SLIME ) texture->surfaceflags |= Q3SURFACEFLAG_SLIME ;
2571 // if (shader->surfaceparms & Q3SURFACEPARM_STRUCTURAL ) texture->surfaceflags |= Q3SURFACEFLAG_STRUCTURAL ;
2572 // if (shader->surfaceparms & Q3SURFACEPARM_TRANS ) texture->surfaceflags |= Q3SURFACEFLAG_TRANS ;
2573 // if (shader->surfaceparms & Q3SURFACEPARM_WATER ) texture->surfaceflags |= Q3SURFACEFLAG_WATER ;
2575 if (shader->surfaceparms & Q3SURFACEPARM_HINT ) texture->surfaceflags |= Q3SURFACEFLAG_HINT ;
2576 if (shader->surfaceparms & Q3SURFACEPARM_DUST ) texture->surfaceflags |= Q3SURFACEFLAG_DUST ;
2577 // if (shader->surfaceparms & Q3SURFACEPARM_BOTCLIP ) texture->surfaceflags |= Q3SURFACEFLAG_BOTCLIP ;
2578 // if (shader->surfaceparms & Q3SURFACEPARM_LIGHTGRID ) texture->surfaceflags |= Q3SURFACEFLAG_LIGHTGRID ;
2579 // if (shader->surfaceparms & Q3SURFACEPARM_ANTIPORTAL ) texture->surfaceflags |= Q3SURFACEFLAG_ANTIPORTAL ;
2580
2581 if (shader->dpmeshcollisions)
2582 texture->basematerialflags |= MATERIALFLAG_MESHCOLLISIONS;
2583 if (shader->dpshaderkill && developer_extra.integer)
2584 Con_DPrintf("^1%s:^7 killing shader ^3\"%s\" because of cvar\n", modelname, name);
2585 }
2586 else if (!strcmp(texture->name, "noshader") || !texture->name[0])
2587 {
2589 Con_DPrintf("^1%s:^7 using fallback noshader material for ^3\"%s\"\n", modelname, name);
2590 texture->basematerialflags = defaultmaterialflags;
2592 }
2593 else if (!strcmp(texture->name, "common/nodraw") || !strcmp(texture->name, "textures/common/nodraw"))
2594 {
2596 Con_DPrintf("^1%s:^7 using fallback nodraw material for ^3\"%s\"\n", modelname, name);
2597 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2598 texture->supercontents = SUPERCONTENTS_SOLID;
2599 }
2600 else
2601 {
2603 Con_DPrintf("^1%s:^7 No shader found for texture ^3\"%s\"\n", modelname, texture->name);
2604 if (texture->surfaceflags & Q3SURFACEFLAG_NODRAW)
2605 {
2606 texture->basematerialflags = MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
2607 texture->supercontents = SUPERCONTENTS_SOLID;
2608 }
2609 else if (texture->surfaceflags & Q3SURFACEFLAG_SKY)
2610 {
2611 texture->basematerialflags = MATERIALFLAG_SKY;
2612 texture->supercontents = SUPERCONTENTS_SKY;
2613 }
2614 else
2615 {
2616 texture->basematerialflags = defaultmaterialflags;
2618 }
2619 if(cls.state == ca_dedicated)
2620 {
2621 texture->materialshaderpass = NULL;
2622 success = false;
2623 }
2624 else
2625 {
2626 skinframe_t *skinframe = R_SkinFrame_LoadExternal(texture->name, defaulttexflags, false, fallback);
2627 if (skinframe)
2628 {
2629 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2630 if (texture->materialshaderpass->skinframes[0]->hasalpha)
2632 if (texture->q2contents)
2633 texture->supercontents = Mod_Q2BSP_SuperContentsFromNativeContents(texture->q2contents);
2634 }
2635 else
2636 success = false;
2637 if (!success && warnmissing)
2638 Con_Printf("^1%s:^7 could not load texture ^3\"%s\"\n", modelname, texture->name);
2639 }
2640 }
2641 // init the animation variables
2642 texture->currentframe = texture;
2643 texture->currentmaterialflags = texture->basematerialflags;
2644 if (!texture->materialshaderpass)
2645 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, R_SkinFrame_LoadMissing());
2646 if (!texture->materialshaderpass->skinframes[0])
2647 texture->materialshaderpass->skinframes[0] = R_SkinFrame_LoadMissing();
2648 texture->currentskinframe = texture->materialshaderpass ? texture->materialshaderpass->skinframes[0] : NULL;
2649 texture->backgroundcurrentskinframe = texture->backgroundshaderpass ? texture->backgroundshaderpass->skinframes[0] : NULL;
2650 return success;
2651}
2652
2653void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
2654{
2655 if (!(materialflags & (MATERIALFLAG_WALL | MATERIALFLAG_SKY)))
2656 Con_DPrintf("^1Custom texture ^3\"%s\" does not have MATERIALFLAG_WALL set\n", texture->name);
2657
2658 dp_strlcpy(texture->name, name, sizeof(texture->name));
2659 texture->basealpha = 1.0f;
2660 texture->basematerialflags = materialflags;
2661 texture->supercontents = supercontents;
2662
2664 texture->offsetscale = 1;
2665 texture->offsetbias = 0;
2666 texture->specularscalemod = 1;
2667 texture->specularpowermod = 1;
2668 texture->rtlightambient = 0;
2669 texture->transparentsort = TRANSPARENTSORT_DISTANCE;
2670 // WHEN ADDING DEFAULTS HERE, REMEMBER TO PUT DEFAULTS IN ALL LOADERS
2671 // JUST GREP FOR "specularscalemod = 1".
2672
2674 Con_DPrintf("^1Custom texture ^3\"%s\"\n", texture->name);
2675 if (skinframe)
2676 texture->materialshaderpass = texture->shaderpasses[0] = Mod_CreateShaderPass(mempool, skinframe);
2677
2678 // init the animation variables
2679 texture->currentmaterialflags = texture->basematerialflags;
2680 texture->currentframe = texture;
2681 texture->currentskinframe = skinframe;
2682 texture->backgroundcurrentskinframe = NULL;
2683}
2684
2686{
2687 long unsigned int i, j;
2688 for (i = 0; i < sizeof(texture->shaderpasses) / sizeof(texture->shaderpasses[0]); i++)
2689 {
2690 if (texture->shaderpasses[i])
2691 {
2692 if (purgeskins)
2693 for (j = 0; j < sizeof(texture->shaderpasses[i]->skinframes) / sizeof(skinframe_t *);j++)
2694 if (texture->shaderpasses[i]->skinframes[j] && texture->shaderpasses[i]->skinframes[j]->base)
2695 R_SkinFrame_PurgeSkinFrame(texture->shaderpasses[i]->skinframes[j]);
2696 Mem_Free(texture->shaderpasses[i]);
2697 texture->shaderpasses[i] = NULL;
2698 }
2699 }
2700 texture->materialshaderpass = NULL;
2701 texture->currentskinframe = NULL;
2702 texture->backgroundcurrentskinframe = NULL;
2703}
2704
2706{
2707 int i, words, line, wordsoverflow;
2708 char *text;
2709 const char *data;
2710 skinfile_t *skinfile = NULL, *first = NULL;
2711 skinfileitem_t *skinfileitem;
2712 char word[10][MAX_QPATH];
2713 char vabuf[1024];
2714
2715/*
2716sample file:
2717U_bodyBox,models/players/Legoman/BikerA2.tga
2718U_RArm,models/players/Legoman/BikerA1.tga
2719U_LArm,models/players/Legoman/BikerA1.tga
2720U_armor,common/nodraw
2721U_sword,common/nodraw
2722U_shield,common/nodraw
2723U_homb,common/nodraw
2724U_backpack,common/nodraw
2725U_colcha,common/nodraw
2726tag_head,
2727tag_weapon,
2728tag_torso,
2729*/
2730 memset(word, 0, sizeof(word));
2731 for (i = 0;i < 256 && (data = text = (char *)FS_LoadFile(va(vabuf, sizeof(vabuf), "%s_%i.skin", loadmodel->name, i), tempmempool, true, NULL));i++)
2732 {
2733 // If it's the first file we parse
2734 if (skinfile == NULL)
2735 {
2736 skinfile = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2737 first = skinfile;
2738 }
2739 else
2740 {
2741 skinfile->next = (skinfile_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfile_t));
2742 skinfile = skinfile->next;
2743 }
2744 skinfile->next = NULL;
2745
2746 for(line = 0;;line++)
2747 {
2748 // parse line
2749 if (!COM_ParseToken_QuakeC(&data, true))
2750 break;
2751 if (!strcmp(com_token, "\n"))
2752 continue;
2753 words = 0;
2754 wordsoverflow = false;
2755 do
2756 {
2757 if (words < 10)
2758 dp_strlcpy(word[words++], com_token, sizeof (word[0]));
2759 else
2760 wordsoverflow = true;
2761 }
2762 while (COM_ParseToken_QuakeC(&data, true) && strcmp(com_token, "\n"));
2763 if (wordsoverflow)
2764 {
2765 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);
2766 continue;
2767 }
2768 // words is always >= 1
2769 if (!strcmp(word[0], "replace"))
2770 {
2771 if (words == 3)
2772 {
2774 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[1], word[2]);
2775 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2776 skinfileitem->next = skinfile->items;
2777 skinfile->items = skinfileitem;
2778 dp_strlcpy (skinfileitem->name, word[1], sizeof (skinfileitem->name));
2779 dp_strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2780 }
2781 else
2782 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]);
2783 }
2784 else if (words >= 2 && !strncmp(word[0], "tag_", 4))
2785 {
2786 // tag name, like "tag_weapon,"
2787 // not used for anything (not even in Quake3)
2788 }
2789 else if (words >= 2 && !strcmp(word[1], ","))
2790 {
2791 // mesh shader name, like "U_RArm,models/players/Legoman/BikerA1.tga"
2793 Con_Printf("Mod_LoadSkinFiles: parsed mesh \"%s\" shader replacement \"%s\"\n", word[0], word[2]);
2794 skinfileitem = (skinfileitem_t *)Mem_Alloc(loadmodel->mempool, sizeof(skinfileitem_t));
2795 skinfileitem->next = skinfile->items;
2796 skinfile->items = skinfileitem;
2797 dp_strlcpy (skinfileitem->name, word[0], sizeof (skinfileitem->name));
2798 dp_strlcpy (skinfileitem->replacement, word[2], sizeof (skinfileitem->replacement));
2799 }
2800 else
2801 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);
2802 }
2803 Mem_Free(text);
2804 }
2805 if (i)
2806 loadmodel->numskins = i;
2807 return first;
2808}
2809
2811{
2812 skinfile_t *next;
2813 skinfileitem_t *skinfileitem, *nextitem;
2814 for (;skinfile;skinfile = next)
2815 {
2816 next = skinfile->next;
2817 for (skinfileitem = skinfile->items;skinfileitem;skinfileitem = nextitem)
2818 {
2819 nextitem = skinfileitem->next;
2820 Mem_Free(skinfileitem);
2821 }
2822 Mem_Free(skinfile);
2823 }
2824}
2825
2827{
2828 int i;
2829 for (i = 0;skinfile;skinfile = skinfile->next, i++);
2830 return i;
2831}
2832
2833void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
2834{
2835 int i;
2836 double isnap = 1.0 / snap;
2837 for (i = 0;i < numvertices*numcomponents;i++)
2838 vertices[i] = floor(vertices[i]*isnap)*snap;
2839}
2840
2841int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
2842{
2843 int i, outtriangles;
2844 float edgedir1[3], edgedir2[3], temp[3];
2845 // a degenerate triangle is one with no width (thickness, surface area)
2846 // these are characterized by having all 3 points colinear (along a line)
2847 // or having two points identical
2848 // the simplest check is to calculate the triangle's area
2849 for (i = 0, outtriangles = 0;i < numtriangles;i++, inelement3i += 3)
2850 {
2851 // calculate first edge
2852 VectorSubtract(vertex3f + inelement3i[1] * 3, vertex3f + inelement3i[0] * 3, edgedir1);
2853 VectorSubtract(vertex3f + inelement3i[2] * 3, vertex3f + inelement3i[0] * 3, edgedir2);
2854 CrossProduct(edgedir1, edgedir2, temp);
2855 if (VectorLength2(temp) < 0.001f)
2856 continue; // degenerate triangle (no area)
2857 // valid triangle (has area)
2858 VectorCopy(inelement3i, outelement3i);
2859 outelement3i += 3;
2860 outtriangles++;
2861 }
2862 return outtriangles;
2863}
2864
2865void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
2866{
2867 int i, e;
2868 int firstvertex, lastvertex;
2869 if (numelements > 0 && elements)
2870 {
2871 firstvertex = lastvertex = elements[0];
2872 for (i = 1;i < numelements;i++)
2873 {
2874 e = elements[i];
2875 firstvertex = min(firstvertex, e);
2876 lastvertex = max(lastvertex, e);
2877 }
2878 }
2879 else
2880 firstvertex = lastvertex = 0;
2881 if (firstvertexpointer)
2882 *firstvertexpointer = firstvertex;
2883 if (lastvertexpointer)
2884 *lastvertexpointer = lastvertex;
2885}
2886
2888{
2889 int j;
2890 uint64_t basematerialflags = 0;
2891 // by default assume there is no sky or water used in this model
2892 mod->DrawSky = NULL;
2893 mod->DrawAddWaterPlanes = NULL;
2894 // combine all basematerialflags observed in the submodelsurfaces range, then check for special flags
2895 for (j = mod->submodelsurfaces_start; j < mod->submodelsurfaces_end; j++)
2896 if (mod->data_surfaces[j].texture)
2897 basematerialflags |= mod->data_surfaces[j].texture->basematerialflags;
2898 if (basematerialflags & MATERIALFLAG_SKY)
2899 mod->DrawSky = R_Mod_DrawSky;
2901 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
2902}
2903
2904typedef struct Mod_MakeSortedSurfaces_qsortsurface_s
2905{
2910}
2912
2913static int Mod_MakeSortedSurfaces_qsortfunc(const void *a, const void *b)
2914{
2917 if (l->effect < r->effect)
2918 return -1;
2919 if (l->effect > r->effect)
2920 return 1;
2921 if (l->texture < r->texture)
2922 return -1;
2923 if (l->texture > r->texture)
2924 return 1;
2925 if (l->lightmaptexture < r->lightmaptexture)
2926 return -1;
2927 if (l->lightmaptexture > r->lightmaptexture)
2928 return 1;
2929 if (l->surfaceindex < r->surfaceindex)
2930 return -1;
2931 if (l->surfaceindex > r->surfaceindex)
2932 return 1;
2933 return 0;
2934}
2935
2937{
2938 // make an optimal set of texture-sorted batches to draw...
2939 int j, k;
2941
2942 if(cls.state == ca_dedicated)
2943 return;
2944
2945 info = (Mod_MakeSortedSurfaces_qsortsurface_t*)Mem_Alloc(loadmodel->mempool, mod->num_surfaces * sizeof(*info));
2946 if (!mod->modelsurfaces_sorted)
2947 mod->modelsurfaces_sorted = (int *) Mem_Alloc(loadmodel->mempool, mod->num_surfaces * sizeof(*mod->modelsurfaces_sorted));
2948 // the goal is to sort by submodel (can't change which submodel a surface belongs to), and then by effects and textures
2949 for (j = 0; j < mod->num_surfaces; j++)
2950 {
2951 info[j].surfaceindex = j;
2952 info[j].effect = mod->data_surfaces[j].effect;
2953 info[j].texture = mod->data_surfaces[j].texture;
2954 info[j].lightmaptexture = mod->data_surfaces[j].lightmaptexture;
2955 }
2956 for (k = 0; k < mod->brush.numsubmodels; k++)
2957 if (mod->brush.submodels[k]->submodelsurfaces_end > mod->brush.submodels[k]->submodelsurfaces_start + 1)
2958 qsort(info + mod->brush.submodels[k]->submodelsurfaces_start, (size_t)mod->brush.submodels[k]->submodelsurfaces_end - mod->brush.submodels[k]->submodelsurfaces_start, sizeof(*info), Mod_MakeSortedSurfaces_qsortfunc);
2959 for (j = 0; j < mod->num_surfaces; j++)
2960 mod->modelsurfaces_sorted[j] = info[j].surfaceindex;
2961 Mem_Free(info);
2962}
2963
2965{
2966 if(cls.state == ca_dedicated)
2967 return;
2968
2970 return;
2971
2973 {
2974 int i;
2975 for (i = 0;i < loadmodel->surfmesh.num_triangles*3;i++)
2976 {
2978 {
2979 Con_Printf(CON_WARN "Mod_BuildVBOs: element %u is incorrect (%u should be %u)\n", i, loadmodel->surfmesh.data_element3s[i], loadmodel->surfmesh.data_element3i[i]);
2981 }
2982 }
2983 }
2984
2985 // upload short indices as a buffer
2988
2989 // upload int indices as a buffer
2992
2993 // only build a vbo if one has not already been created (this is important for brush models which load specially)
2994 // we put several vertex data streams in the same buffer
2996 {
2997 int size;
2998 unsigned char *mem;
2999 size = 0;
3009 mem = (unsigned char *)Mem_Alloc(tempmempool, size);
3028 Mem_Free(mem);
3029 }
3030}
3031
3033static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
3034{
3035 int submodelindex, vertexindex, surfaceindex, triangleindex, textureindex, countvertices = 0, countsurfaces = 0, countfaces = 0, counttextures = 0;
3036 int a, b, c;
3037 const char *texname;
3038 const int *e;
3039 const float *v, *vn, *vt;
3040 size_t l;
3041 size_t outbufferpos = 0;
3042 size_t outbuffermax = 0x100000;
3043 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3044 const msurface_t *surface;
3045 const int maxtextures = 256;
3046 char *texturenames = (char *) Z_Malloc(maxtextures * MAX_QPATH);
3047 model_t *submodel;
3048
3049 // construct the mtllib file
3050 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "# mtllib for %s exported by darkplaces engine\n", originalfilename);
3051 if (l > 0)
3052 outbufferpos += l;
3053 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3054 {
3055 countsurfaces++;
3056 countvertices += surface->num_vertices;
3057 countfaces += surface->num_triangles;
3058 texname = (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default";
3059 for (textureindex = 0;textureindex < counttextures;textureindex++)
3060 if (!strcmp(texturenames + textureindex * MAX_QPATH, texname))
3061 break;
3062 if (textureindex < counttextures)
3063 continue; // already wrote this material entry
3064 if (textureindex >= maxtextures)
3065 continue; // just a precaution
3066 textureindex = counttextures++;
3067 dp_strlcpy(texturenames + textureindex * MAX_QPATH, texname, MAX_QPATH);
3068 if (outbufferpos >= outbuffermax >> 1)
3069 {
3070 outbuffermax *= 2;
3071 oldbuffer = outbuffer;
3072 outbuffer = (char *) Z_Malloc(outbuffermax);
3073 memcpy(outbuffer, oldbuffer, outbufferpos);
3074 Z_Free(oldbuffer);
3075 }
3076 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");
3077 if (l > 0)
3078 outbufferpos += l;
3079 }
3080
3081 // write the mtllib file
3082 FS_WriteFile(mtlfilename, outbuffer, outbufferpos);
3083
3084 // construct the obj file
3085 outbufferpos = 0;
3086 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);
3087 if (l > 0)
3088 outbufferpos += l;
3089
3090 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)
3091 {
3092 if (outbufferpos >= outbuffermax >> 1)
3093 {
3094 outbuffermax *= 2;
3095 oldbuffer = outbuffer;
3096 outbuffer = (char *) Z_Malloc(outbuffermax);
3097 memcpy(outbuffer, oldbuffer, outbufferpos);
3098 Z_Free(oldbuffer);
3099 }
3101 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]);
3102 else
3103 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]);
3104 if (l > 0)
3105 outbufferpos += l;
3106 }
3107
3108 for (submodelindex = 0;submodelindex < max(1, model->brush.numsubmodels);submodelindex++)
3109 {
3110 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "o %i\n", submodelindex);
3111 if (l > 0)
3112 outbufferpos += l;
3113 submodel = model->brush.numsubmodels ? model->brush.submodels[submodelindex] : model;
3114 for (surfaceindex = submodel->submodelsurfaces_start;surfaceindex < submodel->submodelsurfaces_end;surfaceindex++)
3115 {
3116 surface = model->data_surfaces + surfaceindex;
3117 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "usemtl %s\n", (surface->texture && surface->texture->name[0]) ? surface->texture->name : "default");
3118 if (l > 0)
3119 outbufferpos += l;
3120 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3121 {
3122 if (outbufferpos >= outbuffermax >> 1)
3123 {
3124 outbuffermax *= 2;
3125 oldbuffer = outbuffer;
3126 outbuffer = (char *) Z_Malloc(outbuffermax);
3127 memcpy(outbuffer, oldbuffer, outbufferpos);
3128 Z_Free(oldbuffer);
3129 }
3130 a = e[0]+1;
3131 b = e[1]+1;
3132 c = e[2]+1;
3134 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);
3135 else
3136 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);
3137 if (l > 0)
3138 outbufferpos += l;
3139 }
3140 }
3141 }
3142
3143 // write the obj file
3144 FS_WriteFile(filename, outbuffer, outbufferpos);
3145
3146 // clean up
3147 Z_Free(outbuffer);
3148 Z_Free(texturenames);
3149
3150 // print some stats
3151 Con_Printf("Wrote %s (%i bytes, %i vertices, %i faces, %i surfaces with %i distinct textures)\n", filename, (int)outbufferpos, countvertices, countfaces, countsurfaces, counttextures);
3152}
3153
3154static void Mod_Decompile_SMD(model_t *model, const char *filename, int firstpose, int numposes, qbool writetriangles)
3155{
3156 int countnodes = 0, counttriangles = 0, countframes = 0;
3157 int surfaceindex;
3158 int triangleindex;
3159 int transformindex;
3160 int poseindex;
3161 int cornerindex;
3162 const int *e;
3163 size_t l;
3164 size_t outbufferpos = 0;
3165 size_t outbuffermax = 0x100000;
3166 char *outbuffer = (char *) Z_Malloc(outbuffermax), *oldbuffer;
3167 const msurface_t *surface;
3168 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "version 1\nnodes\n");
3169 if (l > 0)
3170 outbufferpos += l;
3171 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3172 {
3173 if (outbufferpos >= outbuffermax >> 1)
3174 {
3175 outbuffermax *= 2;
3176 oldbuffer = outbuffer;
3177 outbuffer = (char *) Z_Malloc(outbuffermax);
3178 memcpy(outbuffer, oldbuffer, outbufferpos);
3179 Z_Free(oldbuffer);
3180 }
3181 countnodes++;
3182 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%3i \"%s\" %3i\n", transformindex, model->data_bones[transformindex].name, model->data_bones[transformindex].parent);
3183 if (l > 0)
3184 outbufferpos += l;
3185 }
3186 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\nskeleton\n");
3187 if (l > 0)
3188 outbufferpos += l;
3189 for (poseindex = 0;poseindex < numposes;poseindex++)
3190 {
3191 countframes++;
3192 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "time %i\n", poseindex);
3193 if (l > 0)
3194 outbufferpos += l;
3195 for (transformindex = 0;transformindex < model->num_bones;transformindex++)
3196 {
3197 float angles[3];
3198 float mtest[4][3];
3199 matrix4x4_t posematrix;
3200 if (outbufferpos >= outbuffermax >> 1)
3201 {
3202 outbuffermax *= 2;
3203 oldbuffer = outbuffer;
3204 outbuffer = (char *) Z_Malloc(outbuffermax);
3205 memcpy(outbuffer, oldbuffer, outbufferpos);
3206 Z_Free(oldbuffer);
3207 }
3208
3209 // strangely the smd angles are for a transposed matrix, so we
3210 // have to generate a transposed matrix, then convert that...
3211 Matrix4x4_FromBonePose7s(&posematrix, model->num_posescale, model->data_poses7s + 7*(model->num_bones * poseindex + transformindex));
3212 Matrix4x4_ToArray12FloatGL(&posematrix, mtest);
3213 AnglesFromVectors(angles, mtest[0], mtest[2], false);
3214 if (angles[0] >= 180) angles[0] -= 360;
3215 if (angles[1] >= 180) angles[1] -= 360;
3216 if (angles[2] >= 180) angles[2] -= 360;
3217
3218#if 0
3219{
3220 float a = DEG2RAD(angles[ROLL]);
3221 float b = DEG2RAD(angles[PITCH]);
3222 float c = DEG2RAD(angles[YAW]);
3223 float cy, sy, cp, sp, cr, sr;
3224 float test[4][3];
3225 // smd matrix construction, for comparing
3226 sy = sin(c);
3227 cy = cos(c);
3228 sp = sin(b);
3229 cp = cos(b);
3230 sr = sin(a);
3231 cr = cos(a);
3232
3233 test[0][0] = cp*cy;
3234 test[0][1] = cp*sy;
3235 test[0][2] = -sp;
3236 test[1][0] = sr*sp*cy+cr*-sy;
3237 test[1][1] = sr*sp*sy+cr*cy;
3238 test[1][2] = sr*cp;
3239 test[2][0] = (cr*sp*cy+-sr*-sy);
3240 test[2][1] = (cr*sp*sy+-sr*cy);
3241 test[2][2] = cr*cp;
3242 test[3][0] = pose[9];
3243 test[3][1] = pose[10];
3244 test[3][2] = pose[11];
3245}
3246#endif
3247 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]));
3248 if (l > 0)
3249 outbufferpos += l;
3250 }
3251 }
3252 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3253 if (l > 0)
3254 outbufferpos += l;
3255 if (writetriangles)
3256 {
3257 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "triangles\n");
3258 if (l > 0)
3259 outbufferpos += l;
3260 for (surfaceindex = 0, surface = model->data_surfaces;surfaceindex < model->num_surfaces;surfaceindex++, surface++)
3261 {
3262 for (triangleindex = 0, e = model->surfmesh.data_element3i + surface->num_firsttriangle * 3;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3263 {
3264 counttriangles++;
3265 if (outbufferpos >= outbuffermax >> 1)
3266 {
3267 outbuffermax *= 2;
3268 oldbuffer = outbuffer;
3269 outbuffer = (char *) Z_Malloc(outbuffermax);
3270 memcpy(outbuffer, oldbuffer, outbufferpos);
3271 Z_Free(oldbuffer);
3272 }
3273 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "%s\n", surface->texture && surface->texture->name[0] ? surface->texture->name : "default.bmp");
3274 if (l > 0)
3275 outbufferpos += l;
3276 for (cornerindex = 0;cornerindex < 3;cornerindex++)
3277 {
3278 const int index = e[2-cornerindex];
3279 const float *v = model->surfmesh.data_vertex3f + index * 3;
3280 const float *vn = model->surfmesh.data_normal3f + index * 3;
3281 const float *vt = model->surfmesh.data_texcoordtexture2f + index * 2;
3282 const int b = model->surfmesh.blends[index];
3283 if (b < model->num_bones)
3284 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]);
3285 else
3286 {
3287 const blendweights_t *w = model->surfmesh.data_blendweights + b - model->num_bones;
3288 const unsigned char *wi = w->index;
3289 const unsigned char *wf = w->influence;
3290 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);
3291 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);
3292 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);
3293 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]);
3294 }
3295 if (l > 0)
3296 outbufferpos += l;
3297 }
3298 }
3299 }
3300 l = dpsnprintf(outbuffer + outbufferpos, outbuffermax - outbufferpos, "end\n");
3301 if (l > 0)
3302 outbufferpos += l;
3303 }
3304
3305 FS_WriteFile(filename, outbuffer, outbufferpos);
3306 Z_Free(outbuffer);
3307
3308 Con_Printf("Wrote %s (%i bytes, %i nodes, %i frames, %i triangles)\n", filename, (int)outbufferpos, countnodes, countframes, counttriangles);
3309}
3310
3311/*
3312================
3313Mod_Decompile_f
3314
3315decompiles a model to editable files
3316================
3317*/
3319{
3320 int i, j, k, l, first, count;
3321 model_t *mod;
3322 char inname[MAX_QPATH];
3323 char outname[MAX_QPATH];
3324 char mtlname[MAX_QPATH];
3325 char basename[MAX_QPATH];
3326 char animname[MAX_QPATH];
3327 char animname2[MAX_QPATH];
3328 char zymtextbuffer[16384];
3329 char dpmtextbuffer[16384];
3330 char framegroupstextbuffer[16384];
3331 int zymtextsize = 0;
3332 int dpmtextsize = 0;
3333 int framegroupstextsize = 0;
3334 char vabuf[1024];
3335
3336 if (Cmd_Argc(cmd) != 2)
3337 {
3338 Con_Print("usage: modeldecompile <filename>\n");
3339 return;
3340 }
3341
3342 dp_strlcpy(inname, Cmd_Argv(cmd, 1), sizeof(inname));
3343 FS_StripExtension(inname, basename, sizeof(basename));
3344
3345 mod = Mod_ForName(inname, false, true, inname[0] == '*' ? cl.model_name[1] : NULL);
3346 if (!mod)
3347 {
3348 Con_Print("No such model\n");
3349 return;
3350 }
3351 if (mod->brush.submodel)
3352 {
3353 // if we're decompiling a submodel, be sure to give it a proper name based on its parent
3354 FS_StripExtension(cl.model_name[1], outname, sizeof(outname));
3355 dpsnprintf(basename, sizeof(basename), "%s/%s", outname, mod->name);
3356 outname[0] = 0;
3357 }
3358 if (!mod->surfmesh.num_triangles)
3359 {
3360 Con_Print("Empty model (or sprite)\n");
3361 return;
3362 }
3363
3364 // export OBJ if possible (not on sprites)
3365 if (mod->surfmesh.num_triangles)
3366 {
3367 dpsnprintf(outname, sizeof(outname), "%s_decompiled.obj", basename);
3368 dpsnprintf(mtlname, sizeof(mtlname), "%s_decompiled.mtl", basename);
3369 Mod_Decompile_OBJ(mod, outname, mtlname, inname);
3370 }
3371
3372 // export SMD if possible (only for skeletal models)
3373 if (mod->surfmesh.num_triangles && mod->num_bones)
3374 {
3375 dpsnprintf(outname, sizeof(outname), "%s_decompiled/ref1.smd", basename);
3376 Mod_Decompile_SMD(mod, outname, 0, 1, true);
3377 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "output out.zym\nscale 1\norigin 0 0 0\nmesh ref1.smd\n");
3378 if (l > 0) zymtextsize += l;
3379 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "outputdir .\nmodel out\nscale 1\norigin 0 0 0\nscene ref1.smd\n");
3380 if (l > 0) dpmtextsize += l;
3381 for (i = 0;i < mod->numframes;i = j)
3382 {
3383 dp_strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3384 first = mod->animscenes[i].firstframe;
3385 if (mod->animscenes[i].framecount > 1)
3386 {
3387 // framegroup anim
3388 count = mod->animscenes[i].framecount;
3389 j = i + 1;
3390 }
3391 else
3392 {
3393 // individual frame
3394 // check for additional frames with same name
3395 for (l = 0, k = (int)strlen(animname);animname[l];l++)
3396 if(animname[l] < '0' || animname[l] > '9')
3397 k = l + 1;
3398 if(k > 0 && animname[k-1] == '_')
3399 --k;
3400 animname[k] = 0;
3401 count = mod->num_poses - first;
3402 for (j = i + 1;j < mod->numframes;j++)
3403 {
3404 dp_strlcpy(animname2, mod->animscenes[j].name, sizeof(animname2));
3405 for (l = 0, k = (int)strlen(animname2);animname2[l];l++)
3406 if(animname2[l] < '0' || animname2[l] > '9')
3407 k = l + 1;
3408 if(k > 0 && animname[k-1] == '_')
3409 --k;
3410 animname2[k] = 0;
3411 if (strcmp(animname2, animname) || mod->animscenes[j].framecount > 1)
3412 {
3413 count = mod->animscenes[j].firstframe - first;
3414 break;
3415 }
3416 }
3417 // if it's only one frame, use the original frame name
3418 if (j == i + 1)
3419 dp_strlcpy(animname, mod->animscenes[i].name, sizeof(animname));
3420
3421 }
3422 dpsnprintf(outname, sizeof(outname), "%s_decompiled/%s.smd", basename, animname);
3423 Mod_Decompile_SMD(mod, outname, first, count, false);
3424 if (zymtextsize < (int)sizeof(zymtextbuffer) - 100)
3425 {
3426 l = dpsnprintf(zymtextbuffer + zymtextsize, sizeof(zymtextbuffer) - zymtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3427 if (l > 0) zymtextsize += l;
3428 }
3429 if (dpmtextsize < (int)sizeof(dpmtextbuffer) - 100)
3430 {
3431 l = dpsnprintf(dpmtextbuffer + dpmtextsize, sizeof(dpmtextbuffer) - dpmtextsize, "scene %s.smd fps %g %s\n", animname, mod->animscenes[i].framerate, mod->animscenes[i].loop ? "" : " noloop");
3432 if (l > 0) dpmtextsize += l;
3433 }
3434 if (framegroupstextsize < (int)sizeof(framegroupstextbuffer) - 100)
3435 {
3436 l = dpsnprintf(framegroupstextbuffer + framegroupstextsize, sizeof(framegroupstextbuffer) - framegroupstextsize, "%d %d %f %d // %s\n", first, count, mod->animscenes[i].framerate, mod->animscenes[i].loop, animname);
3437 if (l > 0) framegroupstextsize += l;
3438 }
3439 }
3440 if (zymtextsize)
3441 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_zym.txt", basename), zymtextbuffer, (fs_offset_t)zymtextsize);
3442 if (dpmtextsize)
3443 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled/out_dpm.txt", basename), dpmtextbuffer, (fs_offset_t)dpmtextsize);
3444 if (framegroupstextsize)
3445 FS_WriteFile(va(vabuf, sizeof(vabuf), "%s_decompiled.framegroups", basename), framegroupstextbuffer, (fs_offset_t)framegroupstextsize);
3446 }
3447}
3448
3450{
3451 int y;
3452 memset(state, 0, sizeof(*state));
3453 state->width = width;
3454 state->height = height;
3455 state->currentY = 0;
3456 state->rows = (mod_alloclightmap_row_t *)Mem_Alloc(mempool, state->height * sizeof(*state->rows));
3457 for (y = 0;y < state->height;y++)
3458 {
3459 state->rows[y].currentX = 0;
3460 state->rows[y].rowY = -1;
3461 }
3462}
3463
3465{
3466 int y;
3467 state->currentY = 0;
3468 for (y = 0;y < state->height;y++)
3469 {
3470 state->rows[y].currentX = 0;
3471 state->rows[y].rowY = -1;
3472 }
3473}
3474
3476{
3477 if (state->rows)
3478 Mem_Free(state->rows);
3479 memset(state, 0, sizeof(*state));
3480}
3481
3482qbool Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
3483{
3485 int y;
3486
3487 row = state->rows + blockheight;
3488 if ((row->rowY < 0) || (row->currentX + blockwidth > state->width))
3489 {
3490 if (state->currentY + blockheight <= state->height)
3491 {
3492 // use the current allocation position
3493 row->rowY = state->currentY;
3494 row->currentX = 0;
3495 state->currentY += blockheight;
3496 }
3497 else
3498 {
3499 // find another position
3500 for (y = blockheight;y < state->height;y++)
3501 {
3502 if ((state->rows[y].rowY >= 0) && (state->rows[y].currentX + blockwidth <= state->width))
3503 {
3504 row = state->rows + y;
3505 break;
3506 }
3507 }
3508 if (y == state->height)
3509 return false;
3510 }
3511 }
3512 *outy = row->rowY;
3513 *outx = row->currentX;
3514 row->currentX += blockwidth;
3515
3516 return true;
3517}
3518
3519typedef struct lightmapsample_s
3520{
3521 float pos[3];
3522 float sh1[4][3];
3524 unsigned char *lm_bgr;
3525 unsigned char *lm_dir;
3526}
3528
3529typedef struct lightmapvertex_s
3530{
3532 float pos[3];
3533 float normal[3];
3534 float texcoordbase[2];
3535 float texcoordlightmap[2];
3536 float lightcolor[4];
3537}
3539
3540typedef struct lightmaptriangle_s
3541{
3545 int axis;
3546 int lmoffset[2];
3547 int lmsize[2];
3548 // 2D modelspace coordinates of min corner
3549 // snapped to lightmap grid but not in grid coordinates
3550 float lmbase[2];
3551 // 2D modelspace to lightmap coordinate scale
3552 float lmscale[2];
3553 float vertex[3][3];
3554 float mins[3];
3555 float maxs[3];
3556}
3558
3559typedef struct lightmaplight_s
3560{
3561 float origin[3];
3562 float radius;
3563 float iradius;
3564 float radius2;
3565 float color[3];
3567}
3569
3571
3572#define MAX_LIGHTMAPSAMPLES 64
3575
3578
3581
3582static void Mod_GenerateLightmaps_LightPoint(model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
3583{
3584 int i;
3585 int index;
3586 int result;
3587 float relativepoint[3];
3588 float color[3];
3589 float dir[3];
3590 float dist;
3591 float dist2;
3592 float intensity;
3593 float sample[5*3];
3594 float lightorigin[3];
3595 float lightradius;
3596 float lightradius2;
3597 float lightiradius;
3598 float lightcolor[3];
3599 trace_t trace;
3600 for (i = 0;i < 5*3;i++)
3601 sample[i] = 0.0f;
3602 for (index = 0;;index++)
3603 {
3604 result = R_Shadow_GetRTLightInfo(index, lightorigin, &lightradius, lightcolor);
3605 if (result < 0)
3606 break;
3607 if (result == 0)
3608 continue;
3609 lightradius2 = lightradius * lightradius;
3610 VectorSubtract(lightorigin, pos, relativepoint);
3611 dist2 = VectorLength2(relativepoint);
3612 if (dist2 >= lightradius2)
3613 continue;
3614 lightiradius = 1.0f / lightradius;
3615 dist = sqrt(dist2) * lightiradius;
3617 if (intensity <= 0.0f)
3618 continue;
3619 if (model && model->TraceLine)
3620 {
3621 model->TraceLine(model, NULL, NULL, &trace, pos, lightorigin, SUPERCONTENTS_SOLID, 0, MATERIALFLAGMASK_TRANSLUCENT | MATERIALFLAG_NOSHADOW);
3622 if (trace.fraction < 1)
3623 continue;
3624 }
3625 // scale down intensity to add to both ambient and diffuse
3626 //intensity *= 0.5f;
3627 VectorNormalize(relativepoint);
3628 VectorScale(lightcolor, intensity, color);
3629 VectorMA(sample , 0.5f , color, sample );
3630 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3631 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3632 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3633 // calculate a weighted average light direction as well
3635 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3636 }
3637 // calculate the direction we'll use to reduce the sample to a directional light source
3638 VectorCopy(sample + 12, dir);
3639 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3641 // extract the diffuse color along the chosen direction and scale it
3642 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]);
3643 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]);
3644 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]);
3645 // subtract some of diffuse from ambient
3646 VectorMA(sample, -0.333f, diffuse, ambient);
3647 // store the normalized lightdir
3648 VectorCopy(dir, lightdir);
3649}
3650
3652{
3653 int surfaceindex;
3654 int triangleindex;
3655 const msurface_t *surface;
3656 const float *vertex3f = model->surfmesh.data_vertex3f;
3657 const int *element3i = model->surfmesh.data_element3i;
3658 const int *e;
3659 float v2[3][3];
3660 for (surfaceindex = model->submodelsurfaces_start;surfaceindex < model->submodelsurfaces_end;surfaceindex++)
3661 {
3662 surface = model->data_surfaces + surfaceindex;
3663 if (!BoxesOverlap(surface->mins, surface->maxs, mins, maxs))
3664 continue;
3666 continue;
3667 for (triangleindex = 0, e = element3i + 3*surface->num_firsttriangle;triangleindex < surface->num_triangles;triangleindex++, e += 3)
3668 {
3669 VectorCopy(vertex3f + 3*e[0], v2[0]);
3670 VectorCopy(vertex3f + 3*e[1], v2[1]);
3671 VectorCopy(vertex3f + 3*e[2], v2[2]);
3672 SVBSP_AddPolygon(svbsp, 3, v2[0], true, NULL, NULL, 0);
3673 }
3674 }
3675}
3676
3678{
3679 int maxnodes = 1<<14;
3680 svbsp_node_t *nodes;
3681 float origin[3];
3682 float mins[3];
3683 float maxs[3];
3684 svbsp_t svbsp;
3685 VectorSet(mins, lightinfo->origin[0] - lightinfo->radius, lightinfo->origin[1] - lightinfo->radius, lightinfo->origin[2] - lightinfo->radius);
3686 VectorSet(maxs, lightinfo->origin[0] + lightinfo->radius, lightinfo->origin[1] + lightinfo->radius, lightinfo->origin[2] + lightinfo->radius);
3687 VectorCopy(lightinfo->origin, origin);
3688 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3689 for (;;)
3690 {
3691 SVBSP_Init(&svbsp, origin, maxnodes, nodes);
3693 if (svbsp.ranoutofnodes)
3694 {
3695 maxnodes *= 16;
3696 if (maxnodes > 1<<22)
3697 {
3698 Mem_Free(nodes);
3699 return;
3700 }
3701 Mem_Free(nodes);
3702 nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, maxnodes * sizeof(*nodes));
3703 }
3704 else
3705 break;
3706 }
3707 if (svbsp.numnodes > 0)
3708 {
3709 svbsp.nodes = (svbsp_node_t *)Mem_Alloc(tempmempool, svbsp.numnodes * sizeof(*nodes));
3710 memcpy(svbsp.nodes, nodes, svbsp.numnodes * sizeof(*nodes));
3711 lightinfo->svbsp = svbsp;
3712 }
3713 Mem_Free(nodes);
3714}
3715
3717{
3718 int index;
3719 int result;
3720 lightmaplight_t *lightinfo;
3721 float origin[3];
3722 float radius;
3723 float color[3];
3725 for (index = 0;;index++)
3726 {
3727 result = R_Shadow_GetRTLightInfo(index, origin, &radius, color);
3728 if (result < 0)
3729 break;
3730 if (result > 0)
3732 }
3734 {
3737 for (index = 0;;index++)
3738 {
3739 result = R_Shadow_GetRTLightInfo(index, lightinfo->origin, &lightinfo->radius, lightinfo->color);
3740 if (result < 0)
3741 break;
3742 if (result > 0)
3743 lightinfo++;
3744 }
3745 }
3747 {
3748 lightinfo->iradius = 1.0f / lightinfo->radius;
3749 lightinfo->radius2 = lightinfo->radius * lightinfo->radius;
3750 // TODO: compute svbsp
3752 }
3753}
3754
3768
3769static qbool Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
3770{
3771 const svbsp_node_t *node;
3772 const svbsp_node_t *nodes = svbsp->nodes;
3773 int num = 0;
3774 while (num >= 0)
3775 {
3776 node = nodes + num;
3777 num = node->children[DotProduct(node->plane, pos) < node->plane[3]];
3778 }
3779 return num == -1; // true if empty, false if solid (shadowed)
3780}
3781
3782static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
3783{
3784 int i;
3785 float relativepoint[3];
3786 float color[3];
3787 float offsetpos[3];
3788 float dist;
3789 float dist2;
3790 float intensity;
3791 int offsetindex;
3792 int hits;
3793 int tests;
3794 const lightmaplight_t *lightinfo;
3795 trace_t trace;
3796 for (i = 0;i < 5*3;i++)
3797 sample[i] = 0.0f;
3798 for (i = 0, lightinfo = mod_generatelightmaps_lightinfo;i < mod_generatelightmaps_numlights;i++, lightinfo++)
3799 {
3800 //R_SampleRTLights(pos, sample, numoffsets, offsets);
3801 VectorSubtract(lightinfo->origin, pos, relativepoint);
3802 // don't accept light from behind a surface, it causes bad shading
3803 if (normal && DotProduct(relativepoint, normal) <= 0)
3804 continue;
3805 dist2 = VectorLength2(relativepoint);
3806 if (dist2 >= lightinfo->radius2)
3807 continue;
3808 dist = sqrt(dist2) * lightinfo->iradius;
3809 intensity = dist < 1 ? ((1.0f - dist) * r_shadow_lightattenuationlinearscale.value / (r_shadow_lightattenuationdividebias.value + dist*dist)) : 0;
3810 if (intensity <= 0)
3811 continue;
3812 if (cl.worldmodel && cl.worldmodel->TraceLine && numoffsets > 0)
3813 {
3814 hits = 0;
3815 tests = 1;
3816 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, pos))
3817 hits++;
3818 for (offsetindex = 1;offsetindex < numoffsets;offsetindex++)
3819 {
3820 VectorAdd(pos, offsets + 3*offsetindex, offsetpos);
3821 if (!normal)
3822 {
3823 // for light grid we'd better check visibility of the offset point
3825 if (trace.fraction < 1)
3826 VectorLerp(pos, trace.fraction, offsetpos, offsetpos);
3827 }
3828 tests++;
3829 if (Mod_GenerateLightmaps_SamplePoint_SVBSP(&lightinfo->svbsp, offsetpos))
3830 hits++;
3831 }
3832 if (!hits)
3833 continue;
3834 // scale intensity according to how many rays succeeded
3835 // we know one test is valid, half of the rest will fail...
3836 //if (normal && tests > 1)
3837 // intensity *= (tests - 1.0f) / tests;
3838 intensity *= (float)hits / tests;
3839 }
3840 // scale down intensity to add to both ambient and diffuse
3841 //intensity *= 0.5f;
3842 VectorNormalize(relativepoint);
3843 VectorScale(lightinfo->color, intensity, color);
3844 VectorMA(sample , 0.5f , color, sample );
3845 VectorMA(sample + 3, relativepoint[0], color, sample + 3);
3846 VectorMA(sample + 6, relativepoint[1], color, sample + 6);
3847 VectorMA(sample + 9, relativepoint[2], color, sample + 9);
3848 // calculate a weighted average light direction as well
3850 VectorMA(sample + 12, intensity, relativepoint, sample + 12);
3851 }
3852}
3853
3854static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
3855{
3856 float sample[5*3];
3857 float color[3];
3858 float dir[3];
3859 float f;
3861 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3862 VectorCopy(sample + 12, dir);
3864 //VectorAdd(dir, normal, dir);
3865 //VectorNormalize(dir);
3866 f = DotProduct(dir, normal);
3867 f = max(0, f) * 255.0f;
3868 VectorScale(sample, f, color);
3869 //VectorCopy(normal, dir);
3870 VectorSet(dir, (dir[0]+1.0f)*127.5f, (dir[1]+1.0f)*127.5f, (dir[2]+1.0f)*127.5f);
3871 lm_bgr[0] = (unsigned char)bound(0.0f, color[2], 255.0f);
3872 lm_bgr[1] = (unsigned char)bound(0.0f, color[1], 255.0f);
3873 lm_bgr[2] = (unsigned char)bound(0.0f, color[0], 255.0f);
3874 lm_bgr[3] = 255;
3875 lm_dir[0] = (unsigned char)dir[2];
3876 lm_dir[1] = (unsigned char)dir[1];
3877 lm_dir[2] = (unsigned char)dir[0];
3878 lm_dir[3] = 255;
3879}
3880
3881static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
3882{
3883 float sample[5*3];
3885 VectorCopy(sample, vertex_color);
3886}
3887
3888static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
3889{
3890 float sample[5*3];
3891 float ambient[3];
3892 float diffuse[3];
3893 float dir[3];
3895 // calculate the direction we'll use to reduce the sample to a directional light source
3896 VectorCopy(sample + 12, dir);
3897 //VectorSet(dir, sample[3] + sample[4] + sample[5], sample[6] + sample[7] + sample[8], sample[9] + sample[10] + sample[11]);
3899 // extract the diffuse color along the chosen direction and scale it
3900 diffuse[0] = (dir[0]*sample[3] + dir[1]*sample[6] + dir[2]*sample[ 9] + sample[ 0]) * 127.5f;
3901 diffuse[1] = (dir[0]*sample[4] + dir[1]*sample[7] + dir[2]*sample[10] + sample[ 1]) * 127.5f;
3902 diffuse[2] = (dir[0]*sample[5] + dir[1]*sample[8] + dir[2]*sample[11] + sample[ 2]) * 127.5f;
3903 // scale the ambient from 0-2 to 0-255 and subtract some of diffuse
3904 VectorScale(sample, 127.5f, ambient);
3905 VectorMA(ambient, -0.333f, diffuse, ambient);
3906 // encode to the grid format
3907 s->ambientrgb[0] = (unsigned char)bound(0.0f, ambient[0], 255.0f);
3908 s->ambientrgb[1] = (unsigned char)bound(0.0f, ambient[1], 255.0f);
3909 s->ambientrgb[2] = (unsigned char)bound(0.0f, ambient[2], 255.0f);
3910 s->diffusergb[0] = (unsigned char)bound(0.0f, diffuse[0], 255.0f);
3911 s->diffusergb[1] = (unsigned char)bound(0.0f, diffuse[1], 255.0f);
3912 s->diffusergb[2] = (unsigned char)bound(0.0f, diffuse[2], 255.0f);
3913 if (dir[2] >= 0.99f) {s->diffusepitch = 0;s->diffuseyaw = 0;}
3914 else if (dir[2] <= -0.99f) {s->diffusepitch = 128;s->diffuseyaw = 0;}
3915 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));}
3916}
3917
3939
3941{
3942 msurface_t *surface;
3943 int surfaceindex;
3944 int i;
3945 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
3946 {
3947 surface = model->data_surfaces + surfaceindex;
3948 surface->lightmaptexture = NULL;
3949 surface->deluxemaptexture = NULL;
3950 }
3951 if (model->brushq3.data_lightmaps)
3952 {
3953 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3954 if (model->brushq3.data_lightmaps[i])
3955 R_FreeTexture(model->brushq3.data_lightmaps[i]);
3956 Mem_Free(model->brushq3.data_lightmaps);
3957 model->brushq3.data_lightmaps = NULL;
3958 }
3959 if (model->brushq3.data_deluxemaps)
3960 {
3961 for (i = 0;i < model->brushq3.num_mergedlightmaps;i++)
3962 if (model->brushq3.data_deluxemaps[i])
3963 R_FreeTexture(model->brushq3.data_deluxemaps[i]);
3964 Mem_Free(model->brushq3.data_deluxemaps);
3965 model->brushq3.data_deluxemaps = NULL;
3966 }
3967}
3968
3970{
3971 msurface_t *surface;
3972 int surfaceindex;
3973 int vertexindex;
3974 int outvertexindex;
3975 int i;
3976 const int *e;
3977 surfmesh_t oldsurfmesh;
3978 size_t size;
3979 unsigned char *data;
3980 oldsurfmesh = model->surfmesh;
3981 model->surfmesh.num_triangles = oldsurfmesh.num_triangles;
3982 model->surfmesh.num_vertices = oldsurfmesh.num_triangles * 3;
3983 size = 0;
3984 size += model->surfmesh.num_vertices * sizeof(float[3]);
3985 size += model->surfmesh.num_vertices * sizeof(float[3]);
3986 size += model->surfmesh.num_vertices * sizeof(float[3]);
3987 size += model->surfmesh.num_vertices * sizeof(float[3]);
3988 size += model->surfmesh.num_vertices * sizeof(float[2]);
3989 size += model->surfmesh.num_vertices * sizeof(float[2]);
3990 size += model->surfmesh.num_vertices * sizeof(float[4]);
3991 data = (unsigned char *)Mem_Alloc(model->mempool, size);
3992 model->surfmesh.data_vertex3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3993 model->surfmesh.data_normal3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3994 model->surfmesh.data_svector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3995 model->surfmesh.data_tvector3f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[3]);
3996 model->surfmesh.data_texcoordtexture2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3997 model->surfmesh.data_texcoordlightmap2f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[2]);
3998 model->surfmesh.data_lightmapcolor4f = (float *)data;data += model->surfmesh.num_vertices * sizeof(float[4]);
3999 if (model->surfmesh.num_vertices > 65536)
4000 model->surfmesh.data_element3s = NULL;
4001
4002 if (model->surfmesh.data_element3i_indexbuffer && !model->surfmesh.data_element3i_indexbuffer->isdynamic)
4003 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3i_indexbuffer);
4004 model->surfmesh.data_element3i_indexbuffer = NULL;
4005 if (model->surfmesh.data_element3s_indexbuffer && !model->surfmesh.data_element3s_indexbuffer->isdynamic)
4006 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_element3s_indexbuffer);
4007 model->surfmesh.data_element3s_indexbuffer = NULL;
4008 if (model->surfmesh.data_vertex3f_vertexbuffer && !model->surfmesh.data_vertex3f_vertexbuffer->isdynamic)
4009 R_Mesh_DestroyMeshBuffer(model->surfmesh.data_vertex3f_vertexbuffer);
4010 model->surfmesh.data_vertex3f_vertexbuffer = NULL;
4011 model->surfmesh.data_svector3f_vertexbuffer = NULL;
4012 model->surfmesh.data_tvector3f_vertexbuffer = NULL;
4013 model->surfmesh.data_normal3f_vertexbuffer = NULL;
4014 model->surfmesh.data_texcoordtexture2f_vertexbuffer = NULL;
4015 model->surfmesh.data_texcoordlightmap2f_vertexbuffer = NULL;
4016 model->surfmesh.data_lightmapcolor4f_vertexbuffer = NULL;
4017 model->surfmesh.data_skeletalindex4ub_vertexbuffer = NULL;
4018 model->surfmesh.data_skeletalweight4ub_vertexbuffer = NULL;
4019
4020 // convert all triangles to unique vertex data
4021 outvertexindex = 0;
4022 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4023 {
4024 surface = model->data_surfaces + surfaceindex;
4025 surface->num_firstvertex = outvertexindex;
4026 surface->num_vertices = surface->num_triangles*3;
4027 e = oldsurfmesh.data_element3i + surface->num_firsttriangle*3;
4028 for (i = 0;i < surface->num_triangles*3;i++)
4029 {
4030 vertexindex = e[i];
4031 model->surfmesh.data_vertex3f[outvertexindex*3+0] = oldsurfmesh.data_vertex3f[vertexindex*3+0];
4032 model->surfmesh.data_vertex3f[outvertexindex*3+1] = oldsurfmesh.data_vertex3f[vertexindex*3+1];
4033 model->surfmesh.data_vertex3f[outvertexindex*3+2] = oldsurfmesh.data_vertex3f[vertexindex*3+2];
4034 model->surfmesh.data_normal3f[outvertexindex*3+0] = oldsurfmesh.data_normal3f[vertexindex*3+0];
4035 model->surfmesh.data_normal3f[outvertexindex*3+1] = oldsurfmesh.data_normal3f[vertexindex*3+1];
4036 model->surfmesh.data_normal3f[outvertexindex*3+2] = oldsurfmesh.data_normal3f[vertexindex*3+2];
4037 model->surfmesh.data_svector3f[outvertexindex*3+0] = oldsurfmesh.data_svector3f[vertexindex*3+0];
4038 model->surfmesh.data_svector3f[outvertexindex*3+1] = oldsurfmesh.data_svector3f[vertexindex*3+1];
4039 model->surfmesh.data_svector3f[outvertexindex*3+2] = oldsurfmesh.data_svector3f[vertexindex*3+2];
4040 model->surfmesh.data_tvector3f[outvertexindex*3+0] = oldsurfmesh.data_tvector3f[vertexindex*3+0];
4041 model->surfmesh.data_tvector3f[outvertexindex*3+1] = oldsurfmesh.data_tvector3f[vertexindex*3+1];
4042 model->surfmesh.data_tvector3f[outvertexindex*3+2] = oldsurfmesh.data_tvector3f[vertexindex*3+2];
4043 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+0];
4044 model->surfmesh.data_texcoordtexture2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordtexture2f[vertexindex*2+1];
4045 if (oldsurfmesh.data_texcoordlightmap2f)
4046 {
4047 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+0] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+0];
4048 model->surfmesh.data_texcoordlightmap2f[outvertexindex*2+1] = oldsurfmesh.data_texcoordlightmap2f[vertexindex*2+1];
4049 }
4050 if (oldsurfmesh.data_lightmapcolor4f)
4051 {
4052 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+0] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+0];
4053 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+1] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+1];
4054 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+2] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+2];
4055 model->surfmesh.data_lightmapcolor4f[outvertexindex*4+3] = oldsurfmesh.data_lightmapcolor4f[vertexindex*4+3];
4056 }
4057 else
4058 Vector4Set(model->surfmesh.data_lightmapcolor4f + 4*outvertexindex, 1, 1, 1, 1);
4059 model->surfmesh.data_element3i[surface->num_firsttriangle*3+i] = outvertexindex;
4060 outvertexindex++;
4061 }
4062 }
4063 if (model->surfmesh.data_element3s)
4064 for (i = 0;i < model->surfmesh.num_triangles*3;i++)
4065 model->surfmesh.data_element3s[i] = model->surfmesh.data_element3i[i];
4066
4067 // find and update all submodels to use this new surfmesh data
4068 for (i = 0;i < model->brush.numsubmodels;i++)
4069 model->brush.submodels[i]->surfmesh = model->surfmesh;
4070}
4071
4073{
4074 msurface_t *surface;
4075 int surfaceindex;
4076 int i;
4077 int axis;
4078 float normal[3];
4079 const int *e;
4080 lightmaptriangle_t *triangle;
4081 // generate lightmap triangle structs
4083 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4084 {
4085 surface = model->data_surfaces + surfaceindex;
4086 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4087 for (i = 0;i < surface->num_triangles;i++)
4088 {
4090 triangle->triangleindex = surface->num_firsttriangle+i;
4091 triangle->surfaceindex = surfaceindex;
4092 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+0], triangle->vertex[0]);
4093 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+1], triangle->vertex[1]);
4094 VectorCopy(model->surfmesh.data_vertex3f + 3*e[i*3+2], triangle->vertex[2]);
4095 // calculate bounds of triangle
4096 triangle->mins[0] = min(triangle->vertex[0][0], min(triangle->vertex[1][0], triangle->vertex[2][0]));
4097 triangle->mins[1] = min(triangle->vertex[0][1], min(triangle->vertex[1][1], triangle->vertex[2][1]));
4098 triangle->mins[2] = min(triangle->vertex[0][2], min(triangle->vertex[1][2], triangle->vertex[2][2]));
4099 triangle->maxs[0] = max(triangle->vertex[0][0], max(triangle->vertex[1][0], triangle->vertex[2][0]));
4100 triangle->maxs[1] = max(triangle->vertex[0][1], max(triangle->vertex[1][1], triangle->vertex[2][1]));
4101 triangle->maxs[2] = max(triangle->vertex[0][2], max(triangle->vertex[1][2], triangle->vertex[2][2]));
4102 // pick an axial projection based on the triangle normal
4103 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], normal);
4104 axis = 0;
4105 if (fabs(normal[1]) > fabs(normal[axis]))
4106 axis = 1;
4107 if (fabs(normal[2]) > fabs(normal[axis]))
4108 axis = 2;
4109 triangle->axis = axis;
4110 }
4111 }
4112}
4113
4120
4121float lmaxis[3][3] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
4122
4124{
4125 msurface_t *surface;
4126 int surfaceindex;
4127 int lightmapindex;
4128 int lightmapnumber;
4129 int i;
4130 int j;
4131 int k;
4132 int x;
4133 int y;
4134 int axis;
4135 int axis1;
4136 int axis2;
4137 int retry;
4138 int pixeloffset;
4139 float trianglenormal[3];
4140 float samplecenter[3];
4141 float samplenormal[3];
4142 float temp[3];
4143 float lmiscale[2];
4144 float slopex;
4145 float slopey;
4146 float slopebase;
4147 float lmscalepixels;
4148 float lmmins;
4149 float lmmaxs;
4150 float lm_basescalepixels;
4151 int lm_borderpixels;
4152 int lm_texturesize;
4153 //int lm_maxpixels;
4154 const int *e;
4155 lightmaptriangle_t *triangle;
4156 unsigned char *lightmappixels;
4157 unsigned char *deluxemappixels;
4159 char vabuf[1024];
4160
4161 // generate lightmap projection information for all triangles
4162 if (model->texturepool == NULL)
4163 model->texturepool = R_AllocTexturePool();
4164 lm_basescalepixels = 1.0f / max(0.0001f, mod_generatelightmaps_unitspersample.value);
4166 lm_texturesize = bound(lm_borderpixels*2+1, 64, (int)vid.maxtexturesize_2d);
4167 //lm_maxpixels = lm_texturesize-(lm_borderpixels*2+1);
4168 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4169 lightmapnumber = 0;
4170 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4171 {
4172 surface = model->data_surfaces + surfaceindex;
4173 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4174 lmscalepixels = lm_basescalepixels;
4175 for (retry = 0;retry < 30;retry++)
4176 {
4177 // after a couple failed attempts, degrade quality to make it fit
4178 if (retry > 1)
4179 lmscalepixels *= 0.5f;
4180 for (i = 0;i < surface->num_triangles;i++)
4181 {
4183 triangle->lightmapindex = lightmapnumber;
4184 // calculate lightmap bounds in 3D pixel coordinates, limit size,
4185 // pick two planar axes for projection
4186 // lightmap coordinates here are in pixels
4187 // lightmap projections are snapped to pixel grid explicitly, such
4188 // that two neighboring triangles sharing an edge and projection
4189 // axis will have identical sample spacing along their shared edge
4190 k = 0;
4191 for (j = 0;j < 3;j++)
4192 {
4193 if (j == triangle->axis)
4194 continue;
4195 lmmins = floor(triangle->mins[j]*lmscalepixels)-lm_borderpixels;
4196 lmmaxs = floor(triangle->maxs[j]*lmscalepixels)+lm_borderpixels;
4197 triangle->lmsize[k] = (int)(lmmaxs-lmmins);
4198 triangle->lmbase[k] = lmmins/lmscalepixels;
4199 triangle->lmscale[k] = lmscalepixels;
4200 k++;
4201 }
4202 if (!Mod_AllocLightmap_Block(&lmstate, triangle->lmsize[0], triangle->lmsize[1], &triangle->lmoffset[0], &triangle->lmoffset[1]))
4203 break;
4204 }
4205 // if all fit in this texture, we're done with this surface
4206 if (i == surface->num_triangles)
4207 break;
4208 // if we haven't maxed out the lightmap size yet, we retry the
4209 // entire surface batch...
4210 if (lm_texturesize * 2 <= min(mod_generatelightmaps_texturesize.integer, (int)vid.maxtexturesize_2d))
4211 {
4212 lm_texturesize *= 2;
4213 surfaceindex = -1;
4214 lightmapnumber = 0;
4215 Mod_AllocLightmap_Free(&lmstate);
4216 Mod_AllocLightmap_Init(&lmstate, loadmodel->mempool, lm_texturesize, lm_texturesize);
4217 break;
4218 }
4219 // if we have maxed out the lightmap size, and this triangle does
4220 // not fit in the same texture as the rest of the surface, we have
4221 // to retry the entire surface in a new texture (can only use one)
4222 // with multiple retries, the lightmap quality degrades until it
4223 // fits (or gives up)
4224 if (surfaceindex > 0)
4225 lightmapnumber++;
4226 Mod_AllocLightmap_Reset(&lmstate);
4227 }
4228 }
4229 lightmapnumber++;
4230 Mod_AllocLightmap_Free(&lmstate);
4231
4232 // now put triangles together into lightmap textures, and do not allow
4233 // triangles of a surface to go into different textures (as that would
4234 // require rewriting the surface list)
4235 model->brushq3.deluxemapping_modelspace = true;
4236 model->brushq3.deluxemapping = true;
4237 model->brushq3.num_mergedlightmaps = lightmapnumber;
4238 model->brushq3.data_lightmaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4239 model->brushq3.data_deluxemaps = (rtexture_t **)Mem_Alloc(model->mempool, model->brushq3.num_mergedlightmaps * sizeof(rtexture_t *));
4240 lightmappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4241 deluxemappixels = (unsigned char *)Mem_Alloc(tempmempool, model->brushq3.num_mergedlightmaps * lm_texturesize * lm_texturesize * 4);
4242 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4243 {
4244 surface = model->data_surfaces + surfaceindex;
4245 e = model->surfmesh.data_element3i + surface->num_firsttriangle*3;
4246 for (i = 0;i < surface->num_triangles;i++)
4247 {
4249 TriangleNormal(triangle->vertex[0], triangle->vertex[1], triangle->vertex[2], trianglenormal);
4250 VectorNormalize(trianglenormal);
4251 VectorCopy(trianglenormal, samplenormal); // FIXME: this is supposed to be interpolated per pixel from vertices
4252 axis = triangle->axis;
4253 axis1 = axis == 0 ? 1 : 0;
4254 axis2 = axis == 2 ? 1 : 2;
4255 lmiscale[0] = 1.0f / triangle->lmscale[0];
4256 lmiscale[1] = 1.0f / triangle->lmscale[1];
4257 if (trianglenormal[axis] < 0)
4258 VectorNegate(trianglenormal, trianglenormal);
4259 CrossProduct(lmaxis[axis2], trianglenormal, temp);slopex = temp[axis] / temp[axis1];
4260 CrossProduct(lmaxis[axis1], trianglenormal, temp);slopey = temp[axis] / temp[axis2];
4261 slopebase = triangle->vertex[0][axis] - triangle->vertex[0][axis1]*slopex - triangle->vertex[0][axis2]*slopey;
4262 for (j = 0;j < 3;j++)
4263 {
4264 float *t2f = model->surfmesh.data_texcoordlightmap2f + e[i*3+j]*2;
4265 t2f[0] = ((triangle->vertex[j][axis1] - triangle->lmbase[0]) * triangle->lmscale[0] + triangle->lmoffset[0]) / lm_texturesize;
4266 t2f[1] = ((triangle->vertex[j][axis2] - triangle->lmbase[1]) * triangle->lmscale[1] + triangle->lmoffset[1]) / lm_texturesize;
4267#if 0
4268 samplecenter[axis1] = (t2f[0]*lm_texturesize-triangle->lmoffset[0])*lmiscale[0] + triangle->lmbase[0];
4269 samplecenter[axis2] = (t2f[1]*lm_texturesize-triangle->lmoffset[1])*lmiscale[1] + triangle->lmbase[1];
4270 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4271 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]);
4272#endif
4273 }
4274
4275#if 0
4276 switch (axis)
4277 {
4278 default:
4279 case 0:
4280 forward[0] = 0;
4281 forward[1] = 1.0f / triangle->lmscale[0];
4282 forward[2] = 0;
4283 left[0] = 0;
4284 left[1] = 0;
4285 left[2] = 1.0f / triangle->lmscale[1];
4286 up[0] = 1.0f;
4287 up[1] = 0;
4288 up[2] = 0;
4289 origin[0] = 0;
4290 origin[1] = triangle->lmbase[0];
4291 origin[2] = triangle->lmbase[1];
4292 break;
4293 case 1:
4294 forward[0] = 1.0f / triangle->lmscale[0];
4295 forward[1] = 0;
4296 forward[2] = 0;
4297 left[0] = 0;
4298 left[1] = 0;
4299 left[2] = 1.0f / triangle->lmscale[1];
4300 up[0] = 0;
4301 up[1] = 1.0f;
4302 up[2] = 0;
4303 origin[0] = triangle->lmbase[0];
4304 origin[1] = 0;
4305 origin[2] = triangle->lmbase[1];
4306 break;
4307 case 2:
4308 forward[0] = 1.0f / triangle->lmscale[0];
4309 forward[1] = 0;
4310 forward[2] = 0;
4311 left[0] = 0;
4312 left[1] = 1.0f / triangle->lmscale[1];
4313 left[2] = 0;
4314 up[0] = 0;
4315 up[1] = 0;
4316 up[2] = 1.0f;
4317 origin[0] = triangle->lmbase[0];
4318 origin[1] = triangle->lmbase[1];
4319 origin[2] = 0;
4320 break;
4321 }
4322 Matrix4x4_FromVectors(&backmatrix, forward, left, up, origin);
4323#endif
4324#define LM_DIST_EPSILON (1.0f / 32.0f)
4325 for (y = 0;y < triangle->lmsize[1];y++)
4326 {
4327 pixeloffset = ((triangle->lightmapindex * lm_texturesize + y + triangle->lmoffset[1]) * lm_texturesize + triangle->lmoffset[0]) * 4;
4328 for (x = 0;x < triangle->lmsize[0];x++, pixeloffset += 4)
4329 {
4330 samplecenter[axis1] = (x+0.5f)*lmiscale[0] + triangle->lmbase[0];
4331 samplecenter[axis2] = (y+0.5f)*lmiscale[1] + triangle->lmbase[1];
4332 samplecenter[axis] = samplecenter[axis1]*slopex + samplecenter[axis2]*slopey + slopebase;
4333 VectorMA(samplecenter, 0.125f, samplenormal, samplecenter);
4334 Mod_GenerateLightmaps_LightmapSample(samplecenter, samplenormal, lightmappixels + pixeloffset, deluxemappixels + pixeloffset);
4335 }
4336 }
4337 }
4338 }
4339
4340 for (lightmapindex = 0;lightmapindex < model->brushq3.num_mergedlightmaps;lightmapindex++)
4341 {
4342 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);
4343 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);
4344 }
4345
4346 if (lightmappixels)
4347 Mem_Free(lightmappixels);
4348 if (deluxemappixels)
4349 Mem_Free(deluxemappixels);
4350
4351 for (surfaceindex = 0;surfaceindex < model->num_surfaces;surfaceindex++)
4352 {
4353 surface = model->data_surfaces + surfaceindex;
4354 if (!surface->num_triangles)
4355 continue;
4357 surface->lightmaptexture = model->brushq3.data_lightmaps[lightmapindex];
4358 surface->deluxemaptexture = model->brushq3.data_deluxemaps[lightmapindex];
4359 surface->lightmapinfo = NULL;
4360 }
4361
4362 model->brush.LightPoint = Mod_GenerateLightmaps_LightPoint;
4363 model->brushq1.lightdata = NULL;
4364 model->brushq1.lightmapupdateflags = NULL;
4365 model->brushq1.firstrender = false;
4366 model->brushq1.num_lightstyles = 0;
4367 model->brushq1.data_lightstyleinfo = NULL;
4368 for (i = 0;i < model->brush.numsubmodels;i++)
4369 {
4370 model->brush.submodels[i]->brushq1.lightmapupdateflags = NULL;
4371 model->brush.submodels[i]->brushq1.firstrender = false;
4372 model->brush.submodels[i]->brushq1.num_lightstyles = 0;
4373 model->brush.submodels[i]->brushq1.data_lightstyleinfo = NULL;
4374 }
4375}
4376
4378{
4379 int i;
4380 for (i = 0;i < model->surfmesh.num_vertices;i++)
4381 Mod_GenerateLightmaps_VertexSample(model->surfmesh.data_vertex3f + 3*i, model->surfmesh.data_normal3f + 3*i, model->surfmesh.data_lightmapcolor4f + 4*i);
4382}
4383
4385{
4386 int x;
4387 int y;
4388 int z;
4389 int index = 0;
4390 float pos[3];
4391 for (z = 0;z < model->brushq3.num_lightgrid_isize[2];z++)
4392 {
4393 pos[2] = (model->brushq3.num_lightgrid_imins[2] + z + 0.5f) * model->brushq3.num_lightgrid_cellsize[2];
4394 for (y = 0;y < model->brushq3.num_lightgrid_isize[1];y++)
4395 {
4396 pos[1] = (model->brushq3.num_lightgrid_imins[1] + y + 0.5f) * model->brushq3.num_lightgrid_cellsize[1];
4397 for (x = 0;x < model->brushq3.num_lightgrid_isize[0];x++, index++)
4398 {
4399 pos[0] = (model->brushq3.num_lightgrid_imins[0] + x + 0.5f) * model->brushq3.num_lightgrid_cellsize[0];
4400 Mod_GenerateLightmaps_GridSample(pos, model->brushq3.data_lightgrid + index);
4401 }
4402 }
4403 }
4404}
4405
4427
4429{
4430 if (Cmd_Argc(cmd) != 1)
4431 {
4432 Con_Printf("usage: mod_generatelightmaps\n");
4433 return;
4434 }
4435 if (!cl.worldmodel)
4436 {
4437 Con_Printf("no worldmodel loaded\n");
4438 return;
4439 }
4441}
4442
4443void Mod_Mesh_Create(model_t *mod, const char *name)
4444{
4445 memset(mod, 0, sizeof(*mod));
4446 dp_strlcpy(mod->name, name, sizeof(mod->name));
4447 mod->mempool = Mem_AllocPool(name, 0, NULL);
4448 mod->texturepool = R_AllocTexturePool();
4449 mod->Draw = R_Mod_Draw;
4450 mod->DrawDepth = R_Mod_DrawDepth;
4451 mod->DrawDebug = R_Mod_DrawDebug;
4452 mod->DrawPrepass = R_Mod_DrawPrepass;
4453 mod->GetLightInfo = R_Mod_GetLightInfo;
4454 mod->DrawShadowMap = R_Mod_DrawShadowMap;
4455 mod->DrawLight = R_Mod_DrawLight;
4456}
4457
4462
4463// resets the mesh model to have no geometry to render, ready for a new frame -
4464// the mesh will be prepared for rendering later using Mod_Mesh_Finalize
4466{
4467 mod->num_surfaces = 0;
4468 mod->surfmesh.num_vertices = 0;
4469 mod->surfmesh.num_triangles = 0;
4470 if (mod->surfmesh.data_vertexhash) // UBSan: memset arg 1 isn't allowed to be null, but sometimes this is NULL.
4471 memset(mod->surfmesh.data_vertexhash, -1, mod->surfmesh.num_vertexhashsize * sizeof(*mod->surfmesh.data_vertexhash));
4472 mod->DrawSky = NULL; // will be set if a texture needs it
4473 mod->DrawAddWaterPlanes = NULL; // will be set if a texture needs it
4474}
4475
4476texture_t *Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
4477{
4478 int i;
4479 texture_t *t;
4480 int drawflag = defaultdrawflags & DRAWFLAG_MASK;
4481 for (i = 0, t = mod->data_textures; i < mod->num_textures; i++, t++)
4482 if (!strcmp(t->name, name) && t->mesh_drawflag == drawflag && t->mesh_defaulttexflags == defaulttexflags && t->mesh_defaultmaterialflags == defaultmaterialflags)
4483 return t;
4484 if (mod->max_textures <= mod->num_textures)
4485 {
4486 texture_t *oldtextures = mod->data_textures;
4487 mod->max_textures = max(mod->max_textures * 2, 1024);
4488 mod->data_textures = (texture_t *)Mem_Realloc(mod->mempool, mod->data_textures, mod->max_textures * sizeof(*mod->data_textures));
4489 // update the pointers
4490 for (i = 0; i < mod->num_surfaces; i++)
4491 mod->data_surfaces[i].texture = mod->data_textures + (mod->data_surfaces[i].texture - oldtextures);
4492 }
4493 t = &mod->data_textures[mod->num_textures++];
4494 Mod_LoadTextureFromQ3Shader(mod->mempool, mod->name, t, name, true, true, defaulttexflags, defaultmaterialflags);
4495 t->mesh_drawflag = drawflag;
4496 t->mesh_defaulttexflags = defaulttexflags;
4497 t->mesh_defaultmaterialflags = defaultmaterialflags;
4498 switch (defaultdrawflags & DRAWFLAG_MASK)
4499 {
4500 case DRAWFLAG_ADDITIVE:
4503 break;
4504 case DRAWFLAG_MODULATE:
4508 t->customblendfunc[1] = GL_ZERO;
4509 break;
4515 break;
4516 case DRAWFLAG_SCREEN:
4520 t->customblendfunc[1] = GL_ONE;
4521 break;
4522 default:
4523 break;
4524 }
4525 return t;
4526}
4527
4528msurface_t *Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithprevioussurface)
4529{
4530 msurface_t *surf;
4531 // batch if possible; primarily useful for UI rendering where bounding boxes don't matter
4532 if (batchwithprevioussurface && mod->num_surfaces > 0 && mod->data_surfaces[mod->num_surfaces - 1].texture == tex)
4533 return mod->data_surfaces + mod->num_surfaces - 1;
4534 // create new surface
4535 if (mod->max_surfaces == mod->num_surfaces)
4536 {
4537 mod->max_surfaces = 2 * max(mod->num_surfaces, 64);
4538 mod->data_surfaces = (msurface_t *)Mem_Realloc(mod->mempool, mod->data_surfaces, mod->max_surfaces * sizeof(*mod->data_surfaces));
4539 mod->modelsurfaces_sorted = (int *)Mem_Realloc(mod->mempool, mod->modelsurfaces_sorted, mod->max_surfaces * sizeof(*mod->modelsurfaces_sorted));
4540 }
4541 surf = mod->data_surfaces + mod->num_surfaces;
4542 mod->num_surfaces++;
4543 memset(surf, 0, sizeof(*surf));
4544 surf->texture = tex;
4545 surf->num_firsttriangle = mod->surfmesh.num_triangles;
4546 surf->num_firstvertex = mod->surfmesh.num_vertices;
4548 mod->DrawSky = R_Mod_DrawSky;
4550 mod->DrawAddWaterPlanes = R_Mod_DrawAddWaterPlanes;
4551 return surf;
4552}
4553
4554int Mod_Mesh_IndexForVertex(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)
4555{
4556 int hashindex, h, vnum, mask;
4557 surfmesh_t *mesh = &mod->surfmesh;
4558 if (mesh->max_vertices == mesh->num_vertices)
4559 {
4560 mesh->max_vertices = max(mesh->num_vertices * 2, 256);
4561 mesh->data_vertex3f = (float *)Mem_Realloc(mod->mempool, mesh->data_vertex3f, mesh->max_vertices * sizeof(float[3]));
4562 mesh->data_svector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_svector3f, mesh->max_vertices * sizeof(float[3]));
4563 mesh->data_tvector3f = (float *)Mem_Realloc(mod->mempool, mesh->data_tvector3f, mesh->max_vertices * sizeof(float[3]));
4564 mesh->data_normal3f = (float *)Mem_Realloc(mod->mempool, mesh->data_normal3f, mesh->max_vertices * sizeof(float[3]));
4565 mesh->data_texcoordtexture2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordtexture2f, mesh->max_vertices * sizeof(float[2]));
4566 mesh->data_texcoordlightmap2f = (float *)Mem_Realloc(mod->mempool, mesh->data_texcoordlightmap2f, mesh->max_vertices * sizeof(float[2]));
4567 mesh->data_lightmapcolor4f = (float *)Mem_Realloc(mod->mempool, mesh->data_lightmapcolor4f, mesh->max_vertices * sizeof(float[4]));
4568 // rebuild the hash table
4569 mesh->num_vertexhashsize = 4 * mesh->max_vertices;
4570 mesh->num_vertexhashsize &= ~(mesh->num_vertexhashsize - 1); // round down to pow2
4571 mesh->data_vertexhash = (int *)Mem_Realloc(mod->mempool, mesh->data_vertexhash, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4572 memset(mesh->data_vertexhash, -1, mesh->num_vertexhashsize * sizeof(*mesh->data_vertexhash));
4573 mask = mod->surfmesh.num_vertexhashsize - 1;
4574 // no need to hash the vertices for the entire model, the latest surface will suffice.
4575 for (vnum = surf ? surf->num_firstvertex : 0; vnum < mesh->num_vertices; vnum++)
4576 {
4577 // this uses prime numbers intentionally for computing the hash
4578 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;
4579 for (h = hashindex; mesh->data_vertexhash[h] >= 0; h = (h + 1) & mask)
4580 ; // just iterate until we find the terminator
4581 mesh->data_vertexhash[h] = vnum;
4582 }
4583 }
4584 mask = mod->surfmesh.num_vertexhashsize - 1;
4585 // this uses prime numbers intentionally for computing the hash
4586 hashindex = (unsigned int)(x * 2003 + y * 4001 + z * 7919 + nx * 4097 + ny * 257 + nz * 17) & mask;
4587 // when possible find an identical vertex within the same surface and return it
4588 for(h = hashindex;(vnum = mesh->data_vertexhash[h]) >= 0;h = (h + 1) & mask)
4589 {
4590 if (vnum >= surf->num_firstvertex
4591 && mesh->data_vertex3f[vnum * 3 + 0] == x && mesh->data_vertex3f[vnum * 3 + 1] == y && mesh->data_vertex3f[vnum * 3 + 2] == z
4592 && mesh->data_normal3f[vnum * 3 + 0] == nx && mesh->data_normal3f[vnum * 3 + 1] == ny && mesh->data_normal3f[vnum * 3 + 2] == nz
4593 && mesh->data_texcoordtexture2f[vnum * 2 + 0] == s && mesh->data_texcoordtexture2f[vnum * 2 + 1] == t
4594 && mesh->data_texcoordlightmap2f[vnum * 2 + 0] == u && mesh->data_texcoordlightmap2f[vnum * 2 + 1] == v
4595 && 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)
4596 return vnum;
4597 }
4598 // add the new vertex
4599 vnum = mesh->num_vertices++;
4600 if (surf->num_vertices > 0)
4601 {
4602 if (surf->mins[0] > x) surf->mins[0] = x;
4603 if (surf->mins[1] > y) surf->mins[1] = y;
4604 if (surf->mins[2] > z) surf->mins[2] = z;
4605 if (surf->maxs[0] < x) surf->maxs[0] = x;
4606 if (surf->maxs[1] < y) surf->maxs[1] = y;
4607 if (surf->maxs[2] < z) surf->maxs[2] = z;
4608 }
4609 else
4610 {
4611 VectorSet(surf->mins, x, y, z);
4612 VectorSet(surf->maxs, x, y, z);
4613 }
4614 surf->num_vertices = mesh->num_vertices - surf->num_firstvertex;
4615 mesh->data_vertexhash[h] = vnum;
4616 mesh->data_vertex3f[vnum * 3 + 0] = x;
4617 mesh->data_vertex3f[vnum * 3 + 1] = y;
4618 mesh->data_vertex3f[vnum * 3 + 2] = z;
4619 mesh->data_normal3f[vnum * 3 + 0] = nx;
4620 mesh->data_normal3f[vnum * 3 + 1] = ny;
4621 mesh->data_normal3f[vnum * 3 + 2] = nz;
4622 mesh->data_texcoordtexture2f[vnum * 2 + 0] = s;
4623 mesh->data_texcoordtexture2f[vnum * 2 + 1] = t;
4624 mesh->data_texcoordlightmap2f[vnum * 2 + 0] = u;
4625 mesh->data_texcoordlightmap2f[vnum * 2 + 1] = v;
4626 mesh->data_lightmapcolor4f[vnum * 4 + 0] = r;
4627 mesh->data_lightmapcolor4f[vnum * 4 + 1] = g;
4628 mesh->data_lightmapcolor4f[vnum * 4 + 2] = b;
4629 mesh->data_lightmapcolor4f[vnum * 4 + 3] = a;
4630 return vnum;
4631}
4632
4633void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2)
4634{
4635 surfmesh_t *mesh = &mod->surfmesh;
4636 if (mesh->max_triangles == mesh->num_triangles)
4637 {
4638 mesh->max_triangles = 2 * max(mesh->num_triangles, 128);
4639 mesh->data_element3s = (unsigned short *)Mem_Realloc(mod->mempool, mesh->data_element3s, mesh->max_triangles * sizeof(unsigned short[3]));
4640 mesh->data_element3i = (int *)Mem_Realloc(mod->mempool, mesh->data_element3i, mesh->max_triangles * sizeof(int[3]));
4641 }
4642 mesh->data_element3s[mesh->num_triangles * 3 + 0] = e0;
4643 mesh->data_element3s[mesh->num_triangles * 3 + 1] = e1;
4644 mesh->data_element3s[mesh->num_triangles * 3 + 2] = e2;
4645 mesh->data_element3i[mesh->num_triangles * 3 + 0] = e0;
4646 mesh->data_element3i[mesh->num_triangles * 3 + 1] = e1;
4647 mesh->data_element3i[mesh->num_triangles * 3 + 2] = e2;
4648 mesh->num_triangles++;
4649 surf->num_triangles++;
4650}
4651
4653{
4654 int i, j;
4655 texture_t *tex;
4656
4657 // build the sorted surfaces list properly to reduce material setup
4658 // this is easy because we're just sorting on texture and don't care about the order of textures
4659 mod->submodelsurfaces_start = 0;
4660 mod->submodelsurfaces_end = 0;
4661 for (i = 0; i < mod->num_surfaces; i++)
4662 mod->data_surfaces[i].included = false;
4663 for (i = 0; i < mod->num_surfaces; i++)
4664 {
4665 if (mod->data_surfaces[i].included)
4666 continue;
4667 tex = mod->data_surfaces[i].texture;
4668 // j = i is intentional
4669 for (j = i; j < mod->num_surfaces; j++)
4670 {
4671 if (!mod->data_surfaces[j].included && mod->data_surfaces[j].texture == tex)
4672 {
4673 mod->data_surfaces[j].included = 1;
4674 mod->modelsurfaces_sorted[mod->submodelsurfaces_end++] = j;
4675 }
4676 }
4677 }
4678}
4679
4681{
4682 int i;
4683 vec_t x2a, x2b, y2a, y2b, z2a, z2b, x2, y2, z2, yawradius, rotatedradius;
4684
4685 if (mod->surfmesh.num_vertices > 0)
4686 {
4687 // calculate normalmins/normalmaxs
4688 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmins);
4689 VectorCopy(mod->surfmesh.data_vertex3f, mod->normalmaxs);
4690 for (i = 1; i < mod->surfmesh.num_vertices; i++)
4691 {
4692 float x = mod->surfmesh.data_vertex3f[i * 3 + 0];
4693 float y = mod->surfmesh.data_vertex3f[i * 3 + 1];
4694 float z = mod->surfmesh.data_vertex3f[i * 3 + 2];
4695 // expand bounds to include this vertex
4696 if (mod->normalmins[0] > x) mod->normalmins[0] = x;
4697 if (mod->normalmins[1] > y) mod->normalmins[1] = y;
4698 if (mod->normalmins[2] > z) mod->normalmins[2] = z;
4699 if (mod->normalmaxs[0] < x) mod->normalmaxs[0] = x;
4700 if (mod->normalmaxs[1] < y) mod->normalmaxs[1] = y;
4701 if (mod->normalmaxs[2] < z) mod->normalmaxs[2] = z;
4702 }
4703 // calculate yawmins/yawmaxs, rotatedmins/maxs from normalmins/maxs
4704 // (fast but less accurate than doing it per vertex)
4705 x2a = mod->normalmins[0] * mod->normalmins[0];
4706 x2b = mod->normalmaxs[0] * mod->normalmaxs[0];
4707 y2a = mod->normalmins[1] * mod->normalmins[1];
4708 y2b = mod->normalmaxs[1] * mod->normalmaxs[1];
4709 z2a = mod->normalmins[2] * mod->normalmins[2];
4710 z2b = mod->normalmaxs[2] * mod->normalmaxs[2];
4711 x2 = max(x2a, x2b);
4712 y2 = max(y2a, y2b);
4713 z2 = max(z2a, z2b);
4714 yawradius = sqrt(x2 + y2);
4715 rotatedradius = sqrt(x2 + y2 + z2);
4716 VectorSet(mod->yawmins, -yawradius, -yawradius, mod->normalmins[2]);
4717 VectorSet(mod->yawmaxs, yawradius, yawradius, mod->normalmaxs[2]);
4718 VectorSet(mod->rotatedmins, -rotatedradius, -rotatedradius, -rotatedradius);
4719 VectorSet(mod->rotatedmaxs, rotatedradius, rotatedradius, rotatedradius);
4720 mod->radius = rotatedradius;
4721 mod->radius2 = x2 + y2 + z2;
4722 }
4723 else
4724 {
4725 VectorClear(mod->normalmins);
4726 VectorClear(mod->normalmaxs);
4727 VectorClear(mod->yawmins);
4728 VectorClear(mod->yawmaxs);
4729 VectorClear(mod->rotatedmins);
4730 VectorClear(mod->rotatedmaxs);
4731 mod->radius = 0;
4732 mod->radius2 = 0;
4733 }
4734}
4735
4737{
4738 int i;
4739 qbool warned = false;
4740 for (i = 0; i < mod->num_surfaces; i++)
4741 {
4742 msurface_t *surf = mod->data_surfaces + i;
4743 int *e = mod->surfmesh.data_element3i + surf->num_firsttriangle * 3;
4744 int first = surf->num_firstvertex;
4745 int end = surf->num_firstvertex + surf->num_vertices;
4746 int j;
4747 for (j = 0;j < surf->num_triangles * 3;j++)
4748 {
4749 if (e[j] < first || e[j] >= end)
4750 {
4751 if (!warned)
4752 Con_DPrintf(CON_WARN "Mod_Mesh_Validate: detected corrupt surface - debug me!\n");
4753 warned = true;
4754 e[j] = first;
4755 }
4756 }
4757 }
4758}
4759
4761{
4762 mod->surfmesh.data_element3s_indexbuffer = mod->surfmesh.data_element3s ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(short[3]), mod->surfmesh.data_element3s, R_BUFFERDATA_INDEX16, &mod->surfmesh.data_element3s_bufferoffset) : NULL;
4763 mod->surfmesh.data_element3i_indexbuffer = mod->surfmesh.data_element3i ? R_BufferData_Store(mod->surfmesh.num_triangles * sizeof(int[3]), mod->surfmesh.data_element3i, R_BUFFERDATA_INDEX32, &mod->surfmesh.data_element3i_bufferoffset) : NULL;
4764 mod->surfmesh.data_vertex3f_vertexbuffer = mod->surfmesh.data_vertex3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_vertex3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_vertex3f_bufferoffset) : NULL;
4765 mod->surfmesh.data_svector3f_vertexbuffer = mod->surfmesh.data_svector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_svector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_svector3f_bufferoffset) : NULL;
4766 mod->surfmesh.data_tvector3f_vertexbuffer = mod->surfmesh.data_tvector3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_tvector3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_tvector3f_bufferoffset) : NULL;
4767 mod->surfmesh.data_normal3f_vertexbuffer = mod->surfmesh.data_normal3f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[3]), mod->surfmesh.data_normal3f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_normal3f_bufferoffset) : NULL;
4768 mod->surfmesh.data_texcoordtexture2f_vertexbuffer = mod->surfmesh.data_texcoordtexture2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordtexture2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordtexture2f_bufferoffset) : NULL;
4769 mod->surfmesh.data_texcoordlightmap2f_vertexbuffer = mod->surfmesh.data_texcoordlightmap2f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[2]), mod->surfmesh.data_texcoordlightmap2f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_texcoordlightmap2f_bufferoffset) : NULL;
4770 mod->surfmesh.data_lightmapcolor4f_vertexbuffer = mod->surfmesh.data_lightmapcolor4f ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(float[4]), mod->surfmesh.data_lightmapcolor4f, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_lightmapcolor4f_bufferoffset) : NULL;
4771 mod->surfmesh.data_skeletalindex4ub_vertexbuffer = mod->surfmesh.data_skeletalindex4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalindex4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalindex4ub_bufferoffset) : NULL;
4772 mod->surfmesh.data_skeletalweight4ub_vertexbuffer = mod->surfmesh.data_skeletalweight4ub ? R_BufferData_Store(mod->surfmesh.num_vertices * sizeof(unsigned char[4]), mod->surfmesh.data_skeletalweight4ub, R_BUFFERDATA_VERTEX, &mod->surfmesh.data_skeletalweight4ub_bufferoffset) : NULL;
4773}
4774
4776{
4777 if (gl_paranoid.integer)
4782 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);
4784}
#define SUPERCONTENTS_SKY
Definition bspfile.h:200
#define SUPERCONTENTS_OPAQUE
Definition bspfile.h:208
#define SUPERCONTENTS_LAVA
Definition bspfile.h:199
#define SUPERCONTENTS_DONOTENTER
Definition bspfile.h:206
#define SUPERCONTENTS_MONSTERCLIP
Definition bspfile.h:205
#define SUPERCONTENTS_BOTCLIP
Definition bspfile.h:207
#define SUPERCONTENTS_SLIME
Definition bspfile.h:198
#define SUPERCONTENTS_SOLID
Definition bspfile.h:196
#define SUPERCONTENTS_PLAYERCLIP
Definition bspfile.h:204
#define SUPERCONTENTS_NODROP
Definition bspfile.h:203
#define SUPERCONTENTS_WATER
Definition bspfile.h:197
static vec3_t offsets[NUMOFFSETS]
Definition cl_input.c:838
cvar_t cl_stainmaps_clearonload
Definition cl_main.c:76
void CL_StartVideo(void)
Definition cl_main.c:2786
client_state_t cl
Definition cl_main.c:117
client_static_t cls
Definition cl_main.c:116
void CL_KeepaliveMessage(qbool readmessages)
Definition cl_parse.c:314
void SCR_PopLoadingScreen(qbool redraw)
Definition cl_screen.c:1899
void SCR_PushLoadingScreen(const char *msg, float len_in_parent)
Definition cl_screen.c:1873
@ ca_dedicated
Definition client.h:530
void Cmd_AddCommand(unsigned flags, const char *cmd_name, xcommand_t function, const char *description)
called by the init functions of other parts of the program to register commands and functions to call...
Definition cmd.c:1661
static int Cmd_Argc(cmd_state_t *cmd)
Definition cmd.h:249
static const char * Cmd_Argv(cmd_state_t *cmd, int arg)
Cmd_Argv(cmd, ) will return an empty string (not a NULL) if arg > argc, so string operations are alwa...
Definition cmd.h:254
#define CF_CLIENT
cvar/command that only the client can change/execute
Definition cmd.h:48
#define CF_ARCHIVE
cvar should have its set value saved to config.cfg and persist across sessions
Definition cmd.h:53
unsigned short CRC_Block(const unsigned char *data, size_t size)
Definition com_crc16.c:75
unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
Definition com_crc16.c:83
char com_token[MAX_INPUTLINE]
Definition common.c:39
char * va(char *buf, size_t buflen, const char *format,...)
Definition common.c:972
qbool COM_ParseToken_QuakeC(const char **datapointer, qbool returnnewline)
Definition common.c:581
qbool COM_ParseToken_Simple(const char **datapointer, qbool returnnewline, qbool parsebackslash, qbool parsecomments)
Definition common.c:463
int dpsnprintf(char *buffer, size_t buffersize, const char *format,...)
Returns the number of printed characters, excluding the final '\0' or returns -1 if the buffer isn't ...
Definition common.c:997
#define dp_strlcpy(dst, src, dsize)
Definition common.h:303
void Con_Print(const char *msg)
Prints to all appropriate console targets, and adds timestamps.
Definition console.c:1504
void Con_DPrintf(const char *fmt,...)
A Con_Printf that only shows up if the "developer" cvar is set.
Definition console.c:1544
void Con_Printf(const char *fmt,...)
Prints to all appropriate console targets.
Definition console.c:1514
void Con_DPrint(const char *msg)
A Con_Print that only shows up if the "developer" cvar is set.
Definition console.c:1531
#define CON_WARN
Definition console.h:101
#define CON_ERROR
Definition console.h:102
vector size
const float DRAWFLAG_ADDITIVE
const float DRAWFLAG_2XMODULATE
float mod(float dividend, float divisor)
vector mins
const float DRAWFLAG_SCREEN
void() predraw
vector maxs
vector angles
const float DRAWFLAG_MODULATE
vector origin
string model
float Cvar_VariableValue(cvar_state_t *cvars, const char *var_name, unsigned neededflags)
Definition cvar.c:129
cvar_state_t cvars_all
Definition cvar.c:28
void Cvar_RegisterVariable(cvar_t *variable)
registers a cvar that already has the name, string, and optionally the archive elements set.
Definition cvar.c:599
float scale
vector color
@ DRAWFLAG_MASK
Definition draw.h:80
#define n(x, y)
const char * FS_FileExtension(const char *in)
Definition fs.c:1403
qbool FS_WriteFile(const char *filename, const void *data, fs_offset_t len)
Definition fs.c:3592
unsigned char * FS_LoadFile(const char *path, mempool_t *pool, qbool quiet, fs_offset_t *filesizepointer)
Definition fs.c:3540
void FS_FreeSearch(fssearch_t *search)
Definition fs.c:3963
fssearch_t * FS_Search(const char *pattern, int caseinsensitive, int quiet, const char *packfile)
Definition fs.c:3756
static int(ZEXPORT *qz_inflate)(z_stream *strm
void FS_StripExtension(const char *in, char *out, size_t size_out)
Definition fs.c:3611
int64_t fs_offset_t
Definition fs.h:37
r_meshbuffer_t * R_Mesh_CreateMeshBuffer(const void *data, size_t size, const char *name, qbool isindexbuffer, qbool isuniformbuffer, qbool isdynamic, qbool isindex16)
void R_Mesh_DestroyMeshBuffer(r_meshbuffer_t *buffer)
cvar_t gl_paranoid
Definition gl_backend.c:8
skinframe_t * R_SkinFrame_LoadExternal(const char *name, int textureflags, qbool complain, qbool fallbacknotexture)
Definition gl_rmain.c:2314
rtexture_t * R_GetCubemap(const char *basename)
Definition gl_rmain.c:2982
void R_SkinFrame_PurgeSkinFrame(skinframe_t *s)
Definition gl_rmain.c:2184
skinframe_t * R_SkinFrame_LoadMissing(void)
Definition gl_rmain.c:2804
void R_SkinFrame_MarkUsed(skinframe_t *skinframe)
Definition gl_rmain.c:2176
r_refdef_t r_refdef
Definition gl_rmain.c:57
r_meshbuffer_t * R_BufferData_Store(size_t datasize, const void *data, r_bufferdata_type_t type, int *returnbufferoffset)
request space in a vertex/index/uniform buffer for the chosen data, returns the buffer pointer and of...
Definition gl_rmain.c:3707
void R_Mod_DrawSky(entity_render_t *ent)
Definition gl_rsurf.c:596
void R_Mod_GetLightInfo(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, vec3_t outmins, vec3_t outmaxs, int *outleaflist, unsigned char *outleafpvs, int *outnumleafspointer, int *outsurfacelist, unsigned char *outsurfacepvs, int *outnumsurfacespointer, unsigned char *outshadowtrispvs, unsigned char *outlighttrispvs, unsigned char *visitingleafpvs, int numfrustumplanes, const mplane_t *frustumplanes, qbool noocclusion)
Definition gl_rsurf.c:1202
void R_Mod_DrawDebug(entity_render_t *ent)
Definition gl_rsurf.c:660
void R_Mod_DrawLight(entity_render_t *ent, int numsurfaces, const int *surfacelist, const unsigned char *lighttrispvs)
Definition gl_rsurf.c:1399
void R_Mod_Draw(entity_render_t *ent)
Definition gl_rsurf.c:637
void R_Mod_DrawShadowMap(int side, entity_render_t *ent, const vec3_t relativelightorigin, const vec3_t relativelightdirection, float lightradius, int modelnumsurfaces, const int *modelsurfacelist, const unsigned char *surfacesides, const vec3_t lightmins, const vec3_t lightmaxs)
Definition gl_rsurf.c:1320
void R_Mod_DrawAddWaterPlanes(entity_render_t *ent)
Definition gl_rsurf.c:603
void R_Mod_DrawDepth(entity_render_t *ent)
Definition gl_rsurf.c:645
void R_Mod_DrawPrepass(entity_render_t *ent)
Definition gl_rsurf.c:667
void R_FreeTexturePool(rtexturepool_t **rtexturepool)
rtexturepool_t * R_AllocTexturePool(void)
void R_FreeTexture(rtexture_t *rt)
rtexture_t * R_LoadTexture2D(rtexturepool_t *rtexturepool, const char *identifier, int width, int height, const unsigned char *data, textype_t textype, int flags, int miplevel, const unsigned int *palette)
GLubyte GLubyte GLubyte z
Definition glquake.h:782
GLenum GLenum GLuint texture
Definition glquake.h:613
GLenum GLsizei width
Definition glquake.h:622
GLenum GLsizei GLsizei height
Definition glquake.h:622
GLfloat GLfloat GLfloat v2
Definition glquake.h:747
GLubyte GLubyte GLubyte GLubyte w
Definition glquake.h:782
GLenum GLenum GLuint GLint GLint layer
Definition glquake.h:615
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
Definition glquake.h:609
#define GL_ONE_MINUS_DST_ALPHA
Definition glquake.h:82
#define GL_ONE_MINUS_DST_COLOR
Definition glquake.h:78
const GLdouble * v
Definition glquake.h:762
GLenum GLenum GLsizei count
Definition glquake.h:656
#define GL_SRC_ALPHA
Definition glquake.h:79
GLint GLenum GLint GLint y
Definition glquake.h:651
#define GL_SRC_COLOR
Definition glquake.h:75
#define GL_ZERO
Definition glquake.h:73
GLint GLenum GLint x
Definition glquake.h:651
GLsizeiptr const GLvoid * data
Definition glquake.h:639
GLfloat v0
Definition glquake.h:739
GLfloat GLfloat v1
Definition glquake.h:743
GLint first
Definition glquake.h:671
GLuint GLuint GLintptr offset
Definition glquake.h:632
#define GL_ONE_MINUS_SRC_ALPHA
Definition glquake.h:80
#define GL_ONE
Definition glquake.h:74
#define GL_DST_ALPHA
Definition glquake.h:81
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition glquake.h:657
const GLchar * name
Definition glquake.h:601
#define GL_DST_COLOR
Definition glquake.h:77
GLuint index
Definition glquake.h:629
#define GL_ONE_MINUS_SRC_COLOR
Definition glquake.h:76
cvar_t developer_insane
Definition host.c:50
cvar_t developer_extra
Definition host.c:49
void Host_Error(const char *error,...)
Definition host.c:85
cvar_t developer_loading
Definition host.c:52
void AnglesFromVectors(vec3_t angles, const vec3_t forward, const vec3_t up, qbool flippitch)
LadyHavoc: calculates pitch/yaw/roll angles from forward and up vectors.
Definition mathlib.c:650
#define VectorLerp(v1, lerp, v2, out)
Definition mathlib.h:120
#define Vector2Copy(in, out)
Definition mathlib.h:74
#define max(A, B)
Definition mathlib.h:38
#define VectorRandom(v)
Definition mathlib.h:119
#define VectorNegate(a, b)
Definition mathlib.h:95
#define min(A, B)
Definition mathlib.h:37
#define BoxesOverlap(a, b, c, d)
Definition mathlib.h:122
#define VectorNormalize(v)
Definition mathlib.h:104
#define DEG2RAD(a)
Definition mathlib.h:65
#define VectorClear(a)
Definition mathlib.h:97
#define bound(min, num, max)
Definition mathlib.h:34
#define VectorLength(a)
Definition mathlib.h:109
#define Vector4Set(vec, r, g, b, a)
Definition mathlib.h:86
#define VectorLength2(a)
Definition mathlib.h:110
#define VectorSet(vec, x, y, z)
Definition mathlib.h:96
#define Vector4Copy(in, out)
Definition mathlib.h:84
#define VectorSubtract(a, b, out)
Definition mathlib.h:99
#define CrossProduct(a, b, out)
Definition mathlib.h:103
#define TriangleNormal(a, b, c, n)
Definition mathlib.h:126
#define DotProduct(a, b)
Definition mathlib.h:98
#define VectorCopy(in, out)
Definition mathlib.h:101
#define VectorScale(in, scale, out)
Definition mathlib.h:111
#define VectorAdd(a, b, out)
Definition mathlib.h:100
#define M_PI
Definition mathlib.h:28
#define VectorMA(a, scale, b, out)
Definition mathlib.h:114
void Matrix4x4_FromBonePose7s(matrix4x4_t *m, float originscale, const short *pose7s)
Definition matrixlib.c:1599
void Matrix4x4_Transform(const matrix4x4_t *in, const float v[3], float out[3])
Definition matrixlib.c:1657
void Matrix4x4_ToArray12FloatGL(const matrix4x4_t *in, float out[4][3])
Definition matrixlib.c:1321
void Matrix4x4_FromVectors(matrix4x4_t *out, const float vx[3], const float vy[3], const float vz[3], const float t[3])
Definition matrixlib.c:970
float strlen(string s)
float cos(float f)
float sqrt(float f)
void cmd(string command,...)
float sin(float f)
void crash(void)
float fabs(float f)
float floor(float f)
void Mod_AliasInit(void)
void Mod_ZYMOTICMODEL_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_PSKMODEL_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_Skeletal_FreeBuffers(void)
Definition model_alias.c:46
void Mod_INTERQUAKEMODEL_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_IDP0_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_IDP3_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_DARKPLACESMODEL_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_IDP2_Load(model_t *mod, void *buffer, void *bufferend)
cvar_t mod_q3shader_force_addalpha
Definition model_brush.c:58
void Mod_OBJ_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_BrushInit(void)
Definition model_brush.c:80
cvar_t mod_q3shader_default_polygonfactor
Definition model_brush.c:55
void Mod_HLBSP_Load(model_t *mod, void *buffer, void *bufferend)
cvar_t mod_noshader_default_offsetmapping
Definition model_brush.c:51
void Mod_IBSP_Load(model_t *mod, void *buffer, void *bufferend)
int Mod_Q2BSP_SuperContentsFromNativeContents(int nativecontents)
cvar_t mod_q3shader_default_offsetmapping_scale
Definition model_brush.c:53
cvar_t mod_q3shader_default_polygonoffset
Definition model_brush.c:56
cvar_t mod_q3shader_default_offsetmapping_bias
Definition model_brush.c:54
void Mod_2PSB_Load(model_t *mod, void *buffer, void *bufferend)
cvar_t mod_q3shader_default_offsetmapping
Definition model_brush.c:52
void Mod_VBSP_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_Q1BSP_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_BSP2_Load(model_t *mod, void *buffer, void *bufferend)
cvar_t mod_q3shader_force_terrain_alphaflag
Definition model_brush.c:59
void Mod_MAP_Load(model_t *mod, void *buffer, void *bufferend)
cvar_t mod_q3shader_default_refractive_index
Definition model_brush.c:57
#define MATERIALFLAG_ADD
Definition model_brush.h:81
#define MATERIALFLAG_SKY
Definition model_brush.h:92
#define MATERIALFLAG_VERTEXCOLOR
#define MATERIALFLAG_FULLBRIGHT
Definition model_brush.h:87
#define MATERIALFLAG_ALPHA
Definition model_brush.h:79
#define MATERIALFLAG_REFRACTION
#define MATERIALFLAG_NODRAW
Definition model_brush.h:96
#define MATERIALFLAG_ALPHATEST
#define MATERIALFLAG_BLENDED
#define MATERIALFLAG_ALPHAGEN_VERTEX
#define MATERIALFLAG_WATERSHADER
#define MATERIALFLAG_CAMERA
#define MATERIALFLAGMASK_TRANSLUCENT
#define MATERIALFLAG_WALL
Definition model_brush.h:89
#define MATERIALFLAG_NOSHADOW
#define MATERIALFLAG_MESHCOLLISIONS
Definition model_brush.h:77
#define MATERIALFLAG_REFLECTION
#define MATERIALFLAG_NOCULLFACE
#define MATERIALFLAG_CUSTOMBLEND
#define MATERIALFLAG_NORTLIGHT
#define Q3SURFACEPARM_PLAYERCLIP
#define Q3SURFACEPARM_NOIMPACT
#define Q3SURFACEPARM_STRUCTURAL
#define Q3SURFACEPARM_NONSOLID
#define Q3SURFACEFLAG_SKY
#define Q3SURFACEPARM_TRANS
#define Q3SURFACEPARM_FOG
#define Q3SURFACEPARM_NODROP
#define Q3SURFACEPARM_NOMIPMAPS
#define Q3SURFACEFLAG_NOMARKS
#define Q3SURFACEPARM_CLUSTERPORTAL
#define Q3SURFACEFLAG_SLICK
#define Q3SURFACEPARM_NODAMAGE
#define Q3SURFACEFLAG_METALSTEPS
#define Q3SURFACEPARM_SLICK
#define Q3SURFACEFLAG_ALPHASHADOW
#define Q3SURFACEPARM_METALSTEPS
#define Q3SURFACEPARM_NODRAW
#define Q3SURFACEPARM_NOLIGHTMAP
#define Q3SURFACEFLAG_NOIMPACT
#define Q3SURFACEFLAG_LIGHTFILTER
#define Q3SURFACEPARM_LAVA
#define Q3SURFACEFLAG_NOLIGHTMAP
#define Q3SURFACEPARM_SLIME
#define Q3SURFACEFLAG_HINT
#define Q3SURFACEFLAG_DUST
#define Q3SURFACEPARM_SKY
#define Q3SURFACEPARM_LIGHTFILTER
#define Q3SURFACEPARM_ANTIPORTAL
#define Q3SURFACEPARM_NOMARKS
#define Q3SURFACEPARM_ORIGIN
#define Q3SURFACEFLAG_NODRAW
#define Q3SURFACEPARM_ALPHASHADOW
#define Q3SURFACEFLAG_POINTLIGHT
#define Q3SURFACEPARM_BOTCLIP
#define Q3SURFACEPARM_DUST
#define Q3SURFACEPARM_WATER
#define Q3SURFACEFLAG_NONSOLID
#define Q3SURFACEPARM_DETAIL
#define Q3SURFACEPARM_POINTLIGHT
#define Q3SURFACEFLAG_NODLIGHT
#define Q3SURFACEFLAG_NODAMAGE
#define Q3SURFACEPARM_DONOTENTER
#define Q3SURFACEPARM_AREAPORTAL
#define Q3SURFACEPARM_NODLIGHT
#define Q3SURFACEPARM_LIGHTGRID
#define Q3SURFACEPARM_HINT
static void Mod_Print_f(cmd_state_t *cmd)
void Mod_Reload(void)
static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP(model_t *model, lightmaplight_t *lightinfo)
void Mod_ClearUsed(void)
cvar_t r_shadow_lightattenuationdividebias
Definition r_shadow.c:153
shader_t * Mod_LookupQ3Shader(const char *name)
qbool Mod_LoadTextureFromQ3Shader(mempool_t *mempool, const char *modelname, texture_t *texture, const char *name, qbool warnmissing, qbool fallback, int defaulttexflags, int defaultmaterialflags)
void Mod_Mesh_Create(model_t *mod, const char *name)
void Mod_Mesh_Reset(model_t *mod)
qbool vid_opened
Definition cl_main.c:2785
void Mod_AllocLightmap_Reset(mod_alloclightmap_state_t *state)
static void Q3Shader_AddToHash(shader_t *shader)
cvar_t mod_generatelightmaps_borderpixels
static void Mod_Mesh_ComputeBounds(model_t *mod)
msurface_t * Mod_Mesh_AddSurface(model_t *mod, texture_t *tex, qbool batchwithprevioussurface)
void Mod_AllocLightmap_Init(mod_alloclightmap_state_t *state, mempool_t *mempool, int width, int height)
texture_shaderpass_t * Mod_CreateShaderPassFromQ3ShaderLayer(mempool_t *mempool, const char *modelname, q3shaderinfo_layer_t *layer, int layerindex, int texflags, const char *texturename)
void Mod_AllocLightmap_Free(mod_alloclightmap_state_t *state)
static void Mod_GenerateLightmaps_SamplePoint(const float *pos, const float *normal, float *sample, int numoffsets, const float *offsets)
int Mod_Mesh_IndexForVertex(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)
static void Mod_ShadowMesh_CreateVBOs(shadowmesh_t *mesh)
static void Mod_GenerateLightmaps_LightPoint(model_t *model, const vec3_t pos, vec3_t ambient, vec3_t diffuse, vec3_t lightdir)
static void mod_newmap(void)
skinfile_t * Mod_LoadSkinFiles(void)
cvar_t mod_generatelightmaps_gridsamples
static void Mod_GenerateLightmaps_CreateLights_ComputeSVBSP_InsertSurfaces(const model_t *model, svbsp_t *svbsp, const float *mins, const float *maxs)
static void R_Model_Null_Draw(entity_render_t *ent)
void Mod_BuildNormals(int firstvertex, int numvertices, int numtriangles, const float *vertex3f, const int *elements, float *normal3f, qbool areaweighting)
model_t * loadmodel
void Mod_Mesh_Validate(model_t *mod)
texture_shaderpass_t * Mod_CreateShaderPass(mempool_t *mempool, skinframe_t *skinframe)
model_t * Mod_ForName(const char *name, qbool crash, qbool checkdisk, const char *parentname)
void Mod_ShadowMesh_Free(shadowmesh_t *mesh)
cvar_t r_mipnormalmaps
void Mod_AllocSurfMesh(mempool_t *mempool, int numvertices, int numtriangles, qbool lightmapoffsets, qbool vertexcolors)
texture_t * Mod_Mesh_GetTexture(model_t *mod, const char *name, int defaultdrawflags, int defaulttexflags, int defaultmaterialflags)
cvar_t mod_generatelightmaps_texturesize
static void Mod_FindPotentialDeforms(model_t *mod)
static void Mod_GenerateLightmaps_f(cmd_state_t *cmd)
#define Q3SHADER_HASH_SIZE
void Mod_Mesh_AddTriangle(model_t *mod, msurface_t *surf, int e0, int e1, int e2)
void Mod_PurgeUnused(void)
static void Mod_Mesh_UploadDynamicBuffers(model_t *mod)
int Mod_CountSkinFiles(skinfile_t *skinfile)
int Mod_BuildVertexRemapTableFromElements(int numelements, const int *elements, int numvertices, int *remapvertices)
static modloader_t loader[]
static void Mod_GenerateLightmaps_UnweldTriangles(model_t *model)
static void Mod_GenerateLightmaps_VertexSample(const float *pos, const float *normal, float *vertex_color)
int Mod_ShadowMesh_AddVertex(shadowmesh_t *mesh, const float *vertex3f)
#define MAX_LIGHTMAPSAMPLES
static void Mod_GenerateLightmaps_GridSample(const float *pos, q3dlightgrid_t *s)
static void Mod_GenerateLightmaps_InitSampleOffsets(model_t *model)
shadowmesh_t * Mod_ShadowMesh_Finish(shadowmesh_t *mesh, qbool createvbo)
void Mod_Mesh_Destroy(model_t *mod)
cvar_t mod_q3bsp_nolightmaps
Definition model_brush.c:45
void Mod_BuildVBOs(void)
static void Mod_GenerateLightmaps_CreateLightmaps(model_t *model)
static void Mod_FrameGroupify_ParseGroups_Store(unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass)
static memexpandablearray_t models
qbool Mod_AllocLightmap_Block(mod_alloclightmap_state_t *state, int blockwidth, int blockheight, int *outx, int *outy)
static q3shader_data_t * q3shader_data
static void Mod_GenerateLightmaps_LightmapSample(const float *pos, const float *normal, unsigned char *lm_bgr, unsigned char *lm_dir)
cvar_t mod_generatelightmaps_lightmapradius
static lightmaplight_t * mod_generatelightmaps_lightinfo
static int Mod_MakeSortedSurfaces_qsortfunc(const void *a, const void *b)
void Mod_SnapVertices(int numcomponents, int numvertices, float *vertices, float snap)
int Mod_RemoveDegenerateTriangles(int numtriangles, const int *inelement3i, int *outelement3i, const float *vertex3f)
model_t * Mod_FindName(const char *name, const char *parentname)
lightmaptriangle_t * mod_generatelightmaps_lightmaptriangles
static void mod_start(void)
static void Mod_GenerateLightmaps(model_t *model)
static void mod_shutdown(void)
static void Mod_GenerateLightmaps_CreateLights(model_t *model)
unsigned char * mod_base
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, qbool areaweighting)
void Mod_ShadowMesh_CalcBBox(shadowmesh_t *mesh, vec3_t mins, vec3_t maxs, vec3_t center, float *radius)
void Mod_FreeSkinFiles(skinfile_t *skinfile)
void Mod_MakeSortedSurfaces(model_t *mod)
static float mod_generatelightmaps_offsets[3][MAX_LIGHTMAPSAMPLES][3]
static void Mod_Decompile_f(cmd_state_t *cmd)
static int mod_generatelightmaps_numoffsets[3]
static mempool_t * q3shaders_mem
void Mod_CreateCollisionMesh(model_t *mod)
static int Mod_LoadQ3Shaders_EnumerateWaveFunc(const char *s)
static int mod_generatelightmaps_numlights
static void Mod_GenerateLightmaps_DestroyLights(model_t *model)
void Mod_UnloadModel(model_t *mod)
cvar_t mod_generatelightmaps_vertexsamples
void Mod_ShadowMesh_AddMesh(shadowmesh_t *mesh, const float *vertex3f, int numtris, const int *element3i)
static void Mod_GenerateLightmaps_CreateTriangleInformation(model_t *model)
void Mod_FreeQ3Shaders(void)
qbool Mod_ValidateElements(int *element3i, unsigned short *element3s, int numtriangles, int firstvertex, int numvertices, const char *filename, int fileline)
shadowmesh_t * Mod_ShadowMesh_Alloc(mempool_t *mempool, int maxverts, int maxtriangles)
model_t * Mod_LoadModel(model_t *mod, qbool crash, qbool checkdisk)
void Mod_LoadCustomMaterial(mempool_t *mempool, texture_t *texture, const char *name, int supercontents, int materialflags, skinframe_t *skinframe)
cvar_t r_shadow_lightattenuationlinearscale
Definition r_shadow.c:154
cvar_t r_mipskins
static mempool_t * mod_mempool
void Mod_RenderInit(void)
static int Mod_FrameGroupify_ParseGroups(const char *buf, mod_framegroupify_parsegroups_t cb, void *pass)
void Mod_Mesh_Finalize(model_t *mod)
void Mod_LoadQ3Shaders(void)
cvar_t mod_generatelightmaps_lightmapsamples
void Mod_UnloadCustomMaterial(texture_t *texture, qbool purgeskins)
Removes all shaderpasses from material, and optionally deletes the textures in the skinframes.
static void Mod_GenerateLightmaps_DestroyLightmaps(model_t *model)
shadowmesh_t * Mod_ShadowMesh_Begin(mempool_t *mempool, int maxverts, int maxtriangles)
static void Mod_GenerateLightmaps_DestroyTriangleInformation(model_t *model)
cvar_t mod_generatelightmaps_unitspersample
static void Mod_Mesh_MakeSortedSurfaces(model_t *mod)
static void Mod_GenerateLightmaps_UpdateVertexColors(model_t *model)
static qbool Mod_GenerateLightmaps_SamplePoint_SVBSP(const svbsp_t *svbsp, const float *pos)
static void Mod_GenerateLightmaps_UpdateLightGrid(model_t *model)
static void Mod_Precache_f(cmd_state_t *cmd)
void Mod_VertexRangeFromElements(int numelements, const int *elements, int *firstvertexpointer, int *lastvertexpointer)
static void Mod_FrameGroupify(model_t *mod, const char *buf)
float lmaxis[3][3]
static void Mod_Decompile_SMD(model_t *model, const char *filename, int firstpose, int numposes, qbool writetriangles)
void Mod_SetDrawSkyAndWater(model_t *mod)
Sets the mod->DrawSky and mod->DrawAddWaterPlanes pointers conditionally based on whether surfaces in...
static void Mod_Decompile_OBJ(model_t *model, const char *filename, const char *mtlfilename, const char *originalfilename)
void(* mod_framegroupify_parsegroups_t)(unsigned int i, int start, int len, float fps, qbool loop, const char *name, void *pass)
cvar_t mod_generatelightmaps_vertexradius
void Mod_Init(void)
cvar_t mod_obj_orientation
Definition model_brush.c:70
cvar_t mod_generatelightmaps_gridradius
#define SHADOWMESHVERTEXHASH
void Mod_IDSP_Load(model_t *mod, void *buffer, void *bufferend)
void Mod_SpriteInit(void)
@ mod_null
void Mod_IDS2_Load(model_t *mod, void *buffer, void *bufferend)
int i
#define MAX_QPATH
max length of a quake game pathname
Definition qdefs.h:169
#define NULL
Definition qtypes.h:12
float vec_t
Definition qtypes.h:68
vec_t vec3_t[3]
Definition qtypes.h:71
bool qbool
Definition qtypes.h:9
#define YAW
Definition qtypes.h:19
#define PITCH
Definition qtypes.h:16
#define ROLL
Definition qtypes.h:22
void R_RegisterModule(const char *name, void(*start)(void), void(*shutdown)(void), void(*newmap)(void), void(*devicelost)(void), void(*devicerestored)(void))
Definition r_modules.c:25
#define Q3TEXTUREFLAG_WATERSHADER
Definition r_qshader.h:13
#define Q3PATHLENGTH
Definition r_qshader.h:17
#define Q3TCMOD_MAXPARMS
Definition r_qshader.h:25
#define Q3TEXTUREFLAG_NOPICMIP
Definition r_qshader.h:9
#define TEXTURE_MAXFRAMES
Definition r_qshader.h:18
#define Q3WAVEPARMS
Definition r_qshader.h:19
#define Q3ALPHAGEN_MAXPARMS
Definition r_qshader.h:23
#define Q3MAXTCMODS
Definition r_qshader.h:26
#define Q3MAXDEFORMS
Definition r_qshader.h:27
#define Q3RGBGEN_MAXPARMS
Definition r_qshader.h:22
@ Q3RGBGEN_VERTEX
Definition r_qshader.h:77
@ Q3RGBGEN_LIGHTINGDIFFUSE
Definition r_qshader.h:74
@ Q3RGBGEN_CONST
Definition r_qshader.h:70
@ Q3RGBGEN_WAVE
Definition r_qshader.h:78
@ Q3RGBGEN_IDENTITYLIGHTING
Definition r_qshader.h:73
@ Q3RGBGEN_ONEMINUSENTITY
Definition r_qshader.h:75
@ Q3RGBGEN_IDENTITY
Definition r_qshader.h:69
@ Q3RGBGEN_ONEMINUSVERTEX
Definition r_qshader.h:76
@ Q3RGBGEN_ENTITY
Definition r_qshader.h:71
@ Q3RGBGEN_EXACTVERTEX
Definition r_qshader.h:72
#define Q3TEXTUREFLAG_POLYGONOFFSET
Definition r_qshader.h:10
@ Q3DEFORM_NORMAL
Definition r_qshader.h:61
@ Q3DEFORM_TEXT3
Definition r_qshader.h:54
@ Q3DEFORM_TEXT5
Definition r_qshader.h:56
@ Q3DEFORM_TEXT0
Definition r_qshader.h:51
@ Q3DEFORM_AUTOSPRITE
Definition r_qshader.h:49
@ Q3DEFORM_PROJECTIONSHADOW
Definition r_qshader.h:48
@ Q3DEFORM_WAVE
Definition r_qshader.h:60
@ Q3DEFORM_TEXT1
Definition r_qshader.h:52
@ Q3DEFORM_TEXT2
Definition r_qshader.h:53
@ Q3DEFORM_NONE
Definition r_qshader.h:47
@ Q3DEFORM_AUTOSPRITE2
Definition r_qshader.h:50
@ Q3DEFORM_TEXT7
Definition r_qshader.h:58
@ Q3DEFORM_MOVE
Definition r_qshader.h:62
@ Q3DEFORM_TEXT6
Definition r_qshader.h:57
@ Q3DEFORM_TEXT4
Definition r_qshader.h:55
@ Q3DEFORM_BULGE
Definition r_qshader.h:59
#define Q3SHADER_MAXLAYERS
Definition r_qshader.h:21
@ TRANSPARENTSORT_DISTANCE
Definition r_qshader.h:194
@ TRANSPARENTSORT_SKY
Definition r_qshader.h:193
@ TRANSPARENTSORT_HUD
Definition r_qshader.h:195
#define Q3WAVEFUNC_USER_SHIFT
Definition r_qshader.h:43
#define Q3TEXTUREFLAG_TRANSPARENTSORT
Definition r_qshader.h:15
@ Q3TCMOD_SCALE
Definition r_qshader.h:114
@ Q3TCMOD_ROTATE
Definition r_qshader.h:113
@ Q3TCMOD_ENTITYTRANSLATE
Definition r_qshader.h:112
@ Q3TCMOD_TRANSFORM
Definition r_qshader.h:117
@ Q3TCMOD_SCROLL
Definition r_qshader.h:115
@ Q3TCMOD_PAGE
Definition r_qshader.h:119
@ Q3TCMOD_TURBULENT
Definition r_qshader.h:118
@ Q3TCMOD_STRETCH
Definition r_qshader.h:116
@ Q3TCMOD_NONE
Definition r_qshader.h:111
@ OFFSETMAPPING_DEFAULT
Definition r_qshader.h:186
@ OFFSETMAPPING_OFF
Definition r_qshader.h:185
@ OFFSETMAPPING_LINEAR
Definition r_qshader.h:187
@ OFFSETMAPPING_RELIEF
Definition r_qshader.h:188
@ Q3TCGEN_VECTOR
Definition r_qshader.h:104
@ Q3TCGEN_ENVIRONMENT
Definition r_qshader.h:102
@ Q3TCGEN_LIGHTMAP
Definition r_qshader.h:103
@ Q3TCGEN_TEXTURE
Definition r_qshader.h:101
#define Q3TEXTUREFLAG_CAMERA
Definition r_qshader.h:14
#define Q3TCGEN_MAXPARMS
Definition r_qshader.h:24
@ Q3ALPHAGEN_LIGHTINGSPECULAR
Definition r_qshader.h:88
@ Q3ALPHAGEN_ONEMINUSENTITY
Definition r_qshader.h:89
@ Q3ALPHAGEN_WAVE
Definition r_qshader.h:93
@ Q3ALPHAGEN_ONEMINUSVERTEX
Definition r_qshader.h:90
@ Q3ALPHAGEN_IDENTITY
Definition r_qshader.h:85
@ Q3ALPHAGEN_VERTEX
Definition r_qshader.h:92
@ Q3ALPHAGEN_PORTAL
Definition r_qshader.h:91
@ Q3ALPHAGEN_CONST
Definition r_qshader.h:86
@ Q3ALPHAGEN_ENTITY
Definition r_qshader.h:87
#define Q3DEFORM_MAXPARMS
Definition r_qshader.h:20
#define Q3TEXTUREFLAG_REFLECTION
Definition r_qshader.h:12
#define Q3TEXTUREFLAG_TWOSIDED
Definition r_qshader.h:8
#define Q3TEXTUREFLAG_REFRACTION
Definition r_qshader.h:11
@ Q3WAVEFUNC_INVERSESAWTOOTH
Definition r_qshader.h:32
@ Q3WAVEFUNC_SAWTOOTH
Definition r_qshader.h:34
@ Q3WAVEFUNC_TRIANGLE
Definition r_qshader.h:37
@ Q3WAVEFUNC_NOISE
Definition r_qshader.h:33
@ Q3WAVEFUNC_NONE
Definition r_qshader.h:31
@ Q3WAVEFUNC_SIN
Definition r_qshader.h:35
@ Q3WAVEFUNC_SQUARE
Definition r_qshader.h:36
int R_Shadow_GetRTLightInfo(unsigned int lightindex, float *origin, float *radius, float *color)
Definition r_shadow.c:4777
#define TEXF_PICMIP
Definition r_textures.h:21
#define TEXF_ALPHA
Definition r_textures.h:9
#define TEXF_FORCELINEAR
Definition r_textures.h:19
#define TEXF_MIPMAP
Definition r_textures.h:11
#define TEXF_ISWORLD
Definition r_textures.h:33
#define TEXF_ISSPRITE
Definition r_textures.h:35
#define TEXF_COMPRESS
Definition r_textures.h:23
@ TEXTYPE_BGRA
Definition r_textures.h:53
#define TEXF_CLAMP
Definition r_textures.h:15
@ R_BUFFERDATA_VERTEX
Definition render.h:525
@ R_BUFFERDATA_INDEX32
index buffer - 16bit (because D3D cares)
Definition render.h:527
@ R_BUFFERDATA_INDEX16
vertex buffer
Definition render.h:526
server_t sv
local server
Definition sv_main.c:223
dp_FragColor r
vec2 dir
dp_FragColor g
precision highp float
Definition shader_glsl.h:53
float f
vec3 y2
vec3 x2
vec3 normal
dp_FragColor b
vec3 x1
void vec2 tc
ret a
float intensity
Definition snd_mix.c:314
char name[32]
float framerate
unsigned char index[4]
struct model_s * worldmodel
Definition client.h:934
char model_name[MAX_MODELS][MAX_QPATH]
Definition client.h:892
cactive_t state
Definition client.h:568
command interpreter state - the tokenizing and execution of commands, as well as pointers to which cv...
Definition cmd.h:127
Definition cvar.h:66
float value
Definition cvar.h:74
int integer
Definition cvar.h:73
char ** filenames
Definition fs.h:117
int numfilenames
Definition fs.h:116
unsigned char * lm_bgr
unsigned char * lm_dir
mod_alloclightmap_row_t * rows
char skybox[MAX_QPATH]
model_brush_t brush
surfmesh_t surfmesh
int submodelsurfaces_start
struct mempool_s * mempool
char name[MAX_QPATH]
void(* Load)(model_t *, void *, void *)
unsigned char * stainsamples
describes the textures to use on a range of triangles in the model, and mins/maxs (AABB) for culling.
msurface_lightmapinfo_t * lightmapinfo
lightmaptexture rebuild information not used in q3bsp
int num_firsttriangle
int num_triangles
range of triangles and vertices in model->surfmesh
texture_t * texture
the texture to use on the surface
int num_firstvertex
vec3_t mins
bounding box for onscreen checks
struct rtexture_s * deluxemaptexture
the lighting direction texture fragment to use on the rendering mesh
struct rtexture_s * lightmaptexture
the lightmap texture fragment to use on the rendering mesh
unsigned char diffusergb[3]
unsigned char ambientrgb[3]
unsigned char diffuseyaw
unsigned char diffusepitch
q3shader_hash_entry_t hash[Q3SHADER_HASH_SIZE]
memexpandablearray_t char_ptrs
memexpandablearray_t hash_entries
struct q3shader_hash_entry_s * chain
shader_t shader
q3wavefunc_t wavefunc
Definition r_qshader.h:178
float parms[Q3DEFORM_MAXPARMS]
Definition r_qshader.h:177
float waveparms[Q3WAVEPARMS]
Definition r_qshader.h:179
q3shaderinfo_layer_alphagen_t alphagen
Definition r_qshader.h:168
q3shaderinfo_layer_rgbgen_t rgbgen
Definition r_qshader.h:167
int draw2dstage
Definition render.h:452
qbool dpnortlight
Definition r_qshader.h:216
char name[Q3PATHLENGTH]
Definition r_qshader.h:200
float r_water_waterscroll[2]
Definition r_qshader.h:237
float biaspolygonfactor
Definition r_qshader.h:245
qbool dpnoshadow
Definition r_qshader.h:218
qbool vertexalpha
Definition r_qshader.h:207
q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS]
Definition r_qshader.h:209
float offsetscale
Definition r_qshader.h:241
dptransparentsortcategory_t transparentsort
Definition r_qshader.h:248
vec4_t refractcolor4f
Definition r_qshader.h:233
q3shaderinfo_deform_t deforms[Q3MAXDEFORMS]
Definition r_qshader.h:211
float r_water_wateralpha
Definition r_qshader.h:236
char skyboxname[Q3PATHLENGTH]
Definition r_qshader.h:210
qbool dpshadow
Definition r_qshader.h:217
qbool lighting
Definition r_qshader.h:206
float reflectmin
Definition r_qshader.h:230
float reflectfactor
Definition r_qshader.h:234
dpoffsetmapping_technique_t offsetmapping
Definition r_qshader.h:240
char dpreflectcube[Q3PATHLENGTH]
Definition r_qshader.h:227
float specularscalemod
Definition r_qshader.h:251
qbool dpmeshcollisions
Definition r_qshader.h:221
float offsetbias
Definition r_qshader.h:242
vec4_t reflectcolor4f
Definition r_qshader.h:235
int textureflags
Definition r_qshader.h:204
qbool dpshaderkill
Definition r_qshader.h:224
int numlayers
Definition r_qshader.h:205
float specularpowermod
Definition r_qshader.h:252
int surfaceflags
Definition r_qshader.h:203
qbool textureblendalpha
Definition r_qshader.h:208
float refractfactor
Definition r_qshader.h:232
int surfaceparms
Definition r_qshader.h:202
float biaspolygonoffset
Definition r_qshader.h:245
float reflectmax
Definition r_qshader.h:231
float rtlightambient
Definition r_qshader.h:255
int sidetotals[6]
shadowmeshvertexhash_t ** vertexhashtable
r_meshbuffer_t * element3s_indexbuffer
struct mempool_s * mempool
r_meshbuffer_t * vbo_vertexbuffer
int sideoffsets[6]
float * vertex3f
r_meshbuffer_t * element3i_indexbuffer
unsigned short * element3s
shadowmeshvertexhash_t * vertexhashentries
struct shadowmeshvertexhash_s * next
struct skinfile_s * next
skinfileitem_t * items
char name[MAX_QPATH]
char replacement[MAX_QPATH]
struct skinfileitem_s * next
r_meshbuffer_t * data_svector3f_vertexbuffer
int data_normal3f_bufferoffset
int data_skeletalweight4ub_bufferoffset
r_meshbuffer_t * data_lightmapcolor4f_vertexbuffer
r_meshbuffer_t * data_normal3f_vertexbuffer
int data_texcoordlightmap2f_bufferoffset
int * data_vertexhash
int data_skeletalindex4ub_bufferoffset
int data_svector3f_bufferoffset
float * data_lightmapcolor4f
unsigned char * data_skeletalweight4ub
float * data_svector3f
unsigned char * data_skeletalindex4ub
int * data_element3i
unsigned short * data_element3s
r_meshbuffer_t * data_texcoordtexture2f_vertexbuffer
r_meshbuffer_t * data_skeletalindex4ub_vertexbuffer
float * data_vertex3f
r_meshbuffer_t * data_tvector3f_vertexbuffer
r_meshbuffer_t * data_element3i_indexbuffer
float * data_tvector3f
int * data_lightmapoffsets
int num_vertexhashsize
int data_texcoordtexture2f_bufferoffset
int num_triangles
int data_tvector3f_bufferoffset
r_meshbuffer_t * data_texcoordlightmap2f_vertexbuffer
r_meshbuffer_t * data_skeletalweight4ub_vertexbuffer
int data_vertex3f_bufferoffset
int data_lightmapcolor4f_bufferoffset
float * data_texcoordtexture2f
r_meshbuffer_t * data_element3s_indexbuffer
float * data_normal3f
float * data_texcoordlightmap2f
r_meshbuffer_t * data_vertex3f_vertexbuffer
int children[2]
Definition svbsp.h:15
float plane[4]
Definition svbsp.h:17
int numnodes
Definition svbsp.h:26
int ranoutofnodes
Definition svbsp.h:32
svbsp_node_t * nodes
Definition svbsp.h:30
q3shaderinfo_layer_tcmod_t tcmods[Q3MAXTCMODS]
Definition r_qshader.h:270
q3shaderinfo_layer_rgbgen_t rgbgen
Definition r_qshader.h:267
q3shaderinfo_layer_alphagen_t alphagen
Definition r_qshader.h:268
struct skinframe_s * skinframes[TEXTURE_MAXFRAMES]
Definition r_qshader.h:265
q3shaderinfo_layer_tcgen_t tcgen
Definition r_qshader.h:269
int currentmaterialflags
int basematerialflags
char name[64]
int mesh_drawflag
int supercontents
int mesh_defaulttexflags
int mesh_defaultmaterialflags
int customblendfunc[2]
double fraction
Definition collision.h:40
unsigned int maxtexturesize_2d
Definition vid.h:83
static vec3_t forward
Definition sv_user.c:305
static vec3_t up
Definition sv_user.c:305
void SVBSP_Init(svbsp_t *b, const float *origin, int maxnodes, svbsp_node_t *nodes)
Definition svbsp.c:99
int SVBSP_AddPolygon(svbsp_t *b, int numpoints, const float *points, int insertoccluder, void(*fragmentcallback)(void *fragmentcallback_pointer1, int fragmentcallback_number1, svbsp_t *b, int numpoints, const float *points), void *fragmentcallback_pointer1, int fragmentcallback_number1)
Definition svbsp.c:403
viddef_t vid
global video state
Definition vid_shared.c:64
size_t Mem_ExpandableArray_IndexRange(const memexpandablearray_t *l)
Definition zone.c:763
void Mem_ExpandableArray_NewArray(memexpandablearray_t *l, mempool_t *mempool, size_t recordsize, int numrecordsperarray)
Definition zone.c:675
void Mem_ExpandableArray_FreeRecord(memexpandablearray_t *l, void *record)
Definition zone.c:743
void * Mem_ExpandableArray_AllocRecord(memexpandablearray_t *l)
Definition zone.c:695
void * Mem_ExpandableArray_RecordAtIndex(const memexpandablearray_t *l, size_t index)
Definition zone.c:780
mempool_t * tempmempool
Definition zone.c:794
#define Mem_Free(mem)
Definition zone.h:96
#define Mem_FreePool(pool)
Definition zone.h:105
#define Mem_Alloc(pool, size)
Definition zone.h:92
#define Z_Malloc(size)
Definition zone.h:161
static size_t Mem_Size(void *data)
Returns the current size of an allocation.
Definition zone.h:122
#define Mem_strdup(pool, s)
Definition zone.h:97
#define Mem_AllocPool(name, flags, parent)
Definition zone.h:104
#define Mem_Realloc(pool, data, size)
Definition zone.h:94
#define Z_Free(data)
Definition zone.h:164