cvar_t halflifebsp = {0, "halflifebsp", "0", "indicates the current map is hlbsp format (useful to know because of different bounding box sizes)"};
cvar_t mcbsp = {0, "mcbsp", "0", "indicates the current map is mcbsp format (useful to know because of different bounding box sizes)"};
cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
-cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0", "mipmaps lightmaps on upload, also expanding them to power of 2 sizes, this runs slower"};
cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1", "whether to use RGBA (32bit) or RGB (24bit) lightmaps"};
cvar_t r_nosurftextures = {0, "r_nosurftextures", "0", "pretends there was no texture lump found in the q1bsp/hlbsp loading (useful for debugging this rare case)"};
cvar_t r_subdivisions_tolerance = {0, "r_subdivisions_tolerance", "4", "maximum error tolerance on curve subdivision for rendering purposes (in other words, the curves will be given as many polygons as necessary to represent curves at this quality)"};
cvar_t mod_q3bsp_optimizedtraceline = {0, "mod_q3bsp_optimizedtraceline", "1", "whether to use optimized traceline code for line traces (as opposed to tracebox code)"};
cvar_t mod_q3bsp_debugtracebrush = {0, "mod_q3bsp_debugtracebrush", "0", "selects different tracebrush bsp recursion algorithms (for debugging purposes only)"};
+static texture_t mod_q1bsp_texture_solid;
+static texture_t mod_q1bsp_texture_sky;
+static texture_t mod_q1bsp_texture_lava;
+static texture_t mod_q1bsp_texture_slime;
+static texture_t mod_q1bsp_texture_water;
+
void Mod_BrushInit(void)
{
// Cvar_RegisterVariable(&r_subdivide_size);
Cvar_RegisterVariable(&halflifebsp);
Cvar_RegisterVariable(&mcbsp);
Cvar_RegisterVariable(&r_novis);
- Cvar_RegisterVariable(&r_miplightmaps);
Cvar_RegisterVariable(&r_lightmaprgba);
Cvar_RegisterVariable(&r_nosurftextures);
Cvar_RegisterVariable(&r_subdivisions_tolerance);
Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
+
+ memset(&mod_q1bsp_texture_solid, 0, sizeof(mod_q1bsp_texture_solid));
+ strlcpy(mod_q1bsp_texture_solid.name, "solid" , sizeof(mod_q1bsp_texture_solid.name));
+ mod_q1bsp_texture_solid.surfaceflags = 0;
+ mod_q1bsp_texture_solid.supercontents = SUPERCONTENTS_SOLID;
+
+ mod_q1bsp_texture_sky = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_sky.name, "sky", sizeof(mod_q1bsp_texture_sky.name));
+ mod_q1bsp_texture_sky.surfaceflags = Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT | Q3SURFACEFLAG_NOMARKS | Q3SURFACEFLAG_NODLIGHT | Q3SURFACEFLAG_NOLIGHTMAP;
+ mod_q1bsp_texture_sky.supercontents = SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP;
+
+ mod_q1bsp_texture_lava = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_lava.name, "*lava", sizeof(mod_q1bsp_texture_lava.name));
+ mod_q1bsp_texture_lava.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_lava.supercontents = SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
+
+ mod_q1bsp_texture_slime = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_slime.name, "*slime", sizeof(mod_q1bsp_texture_slime.name));
+ mod_q1bsp_texture_slime.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_slime.supercontents = SUPERCONTENTS_SLIME;
+
+ mod_q1bsp_texture_water = mod_q1bsp_texture_solid;
+ strlcpy(mod_q1bsp_texture_water.name, "*water", sizeof(mod_q1bsp_texture_water.name));
+ mod_q1bsp_texture_water.surfaceflags = Q3SURFACEFLAG_NOMARKS;
+ mod_q1bsp_texture_water.supercontents = SUPERCONTENTS_WATER;
}
static mleaf_t *Mod_Q1BSP_PointInLeaf(model_t *model, const vec3_t p)
{
for (k = 0;k < surface->num_triangles;k++)
{
- tri = (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle) + k * 3;
- VectorCopy((surface->groupmesh->data_vertex3f + tri[0] * 3), vert[0]);
- VectorCopy((surface->groupmesh->data_vertex3f + tri[1] * 3), vert[1]);
- VectorCopy((surface->groupmesh->data_vertex3f + tri[2] * 3), vert[2]);
+ tri = (info->model->surfmesh.data_element3i + 3 * surface->num_firsttriangle) + k * 3;
+ VectorCopy((info->model->surfmesh.data_vertex3f + tri[0] * 3), vert[0]);
+ VectorCopy((info->model->surfmesh.data_vertex3f + tri[1] * 3), vert[1]);
+ VectorCopy((info->model->surfmesh.data_vertex3f + tri[2] * 3), vert[2]);
VectorSubtract(vert[1], vert[0], edge[0]);
VectorSubtract(vert[2], vert[1], edge[1]);
CrossProduct(edge[1], edge[0], facenormal);
case CONTENTS_SLIME:
return SUPERCONTENTS_SLIME;
case CONTENTS_LAVA:
- return SUPERCONTENTS_LAVA;
+ return SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
case CONTENTS_SKY:
- return SUPERCONTENTS_SKY;
+ return SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP;
}
return 0;
}
int Mod_Q1BSP_NativeContentsFromSuperContents(model_t *model, int supercontents)
{
- if (supercontents & SUPERCONTENTS_SOLID)
+ if (supercontents & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY))
return CONTENTS_SOLID;
if (supercontents & SUPERCONTENTS_SKY)
return CONTENTS_SKY;
#define HULLCHECKSTATE_SOLID 1
#define HULLCHECKSTATE_DONE 2
+extern cvar_t collision_prefernudgedfraction;
static int Mod_Q1BSP_RecursiveHullCheck(RecursiveHullCheckTraceInfo_t *t, int num, double p1f, double p2f, double p1[3], double p2[3])
{
// status variables, these don't need to be saved on the stack when
t->trace->inwater = true;
if (num == 0)
t->trace->inopen = true;
+ if (num & SUPERCONTENTS_SOLID)
+ t->trace->hittexture = &mod_q1bsp_texture_solid;
+ else if (num & SUPERCONTENTS_SKY)
+ t->trace->hittexture = &mod_q1bsp_texture_sky;
+ else if (num & SUPERCONTENTS_LAVA)
+ t->trace->hittexture = &mod_q1bsp_texture_lava;
+ else if (num & SUPERCONTENTS_SLIME)
+ t->trace->hittexture = &mod_q1bsp_texture_slime;
+ else
+ t->trace->hittexture = &mod_q1bsp_texture_water;
+ t->trace->hitq3surfaceflags = t->trace->hittexture->surfaceflags;
+ t->trace->hitsupercontents = num;
if (num & t->trace->hitsupercontentsmask)
{
// if the first leaf is solid, set startsolid
midf = (t1 - DIST_EPSILON) / (t1 - t2);
t->trace->fraction = bound(0, midf, 1);
+ if (collision_prefernudgedfraction.integer)
+ t->trace->realfraction = t->trace->fraction;
+
#if COLLISIONPARANOID >= 3
Con_Print("D");
#endif
return HULLCHECKSTATE_DONE;
}
-#if COLLISIONPARANOID < 2
+//#if COLLISIONPARANOID < 2
static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, int num)
{
while (num >= 0)
return HULLCHECKSTATE_EMPTY;
}
}
-#endif
+//#endif
static void Mod_Q1BSP_TraceBox(struct model_s *model, int frame, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask)
{
#if COLLISIONPARANOID >= 2
Con_Printf("t(%f %f %f,%f %f %f,%i %f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[2], rhc.hull - model->brushq1.hulls, rhc.hull->clip_mins[0], rhc.hull->clip_mins[1], rhc.hull->clip_mins[2]);
Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
+ {
+
+ double test[3];
+ trace_t testtrace;
+ VectorLerp(rhc.start, rhc.trace->fraction, rhc.end, test);
+ memset(&testtrace, 0, sizeof(trace_t));
+ rhc.trace = &testtrace;
+ rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
+ rhc.trace->fraction = 1;
+ rhc.trace->realfraction = 1;
+ rhc.trace->allsolid = true;
+ VectorCopy(test, rhc.start);
+ VectorCopy(test, rhc.end);
+ VectorClear(rhc.dist);
+ Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
+ //Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, test, test);
+ if (!trace->startsolid && testtrace.startsolid)
+ Con_Printf(" - ended in solid!\n");
+ }
Con_Print("\n");
#else
if (VectorLength2(rhc.dist))
#endif
}
-void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents)
+void Collision_ClipTrace_Box(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int hitsupercontentsmask, int boxsupercontents, int boxq3surfaceflags, texture_t *boxtexture)
{
#if 1
colbrushf_t cbox;
cbox_planes[3].normal[0] = 0;cbox_planes[3].normal[1] = -1;cbox_planes[3].normal[2] = 0;cbox_planes[3].dist = maxs[1] - cmins[1];
cbox_planes[4].normal[0] = 0;cbox_planes[4].normal[1] = 0;cbox_planes[4].normal[2] = 1;cbox_planes[4].dist = cmaxs[2] - mins[2];
cbox_planes[5].normal[0] = 0;cbox_planes[5].normal[1] = 0;cbox_planes[5].normal[2] = -1;cbox_planes[5].dist = maxs[2] - cmins[2];
+ cbox_planes[0].q3surfaceflags = boxq3surfaceflags;cbox_planes[0].texture = boxtexture;
+ cbox_planes[1].q3surfaceflags = boxq3surfaceflags;cbox_planes[1].texture = boxtexture;
+ cbox_planes[2].q3surfaceflags = boxq3surfaceflags;cbox_planes[2].texture = boxtexture;
+ cbox_planes[3].q3surfaceflags = boxq3surfaceflags;cbox_planes[3].texture = boxtexture;
+ cbox_planes[4].q3surfaceflags = boxq3surfaceflags;cbox_planes[4].texture = boxtexture;
+ cbox_planes[5].q3surfaceflags = boxq3surfaceflags;cbox_planes[5].texture = boxtexture;
memset(trace, 0, sizeof(trace_t));
trace->hitsupercontentsmask = hitsupercontentsmask;
trace->fraction = 1;
static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(model_t *model, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal, const mnode_t *node, float x, float y, float startz, float endz)
{
- int side, distz = endz - startz;
+ int side;
float front, back;
- float mid;
+ float mid, distz = endz - startz;
loc0:
if (!node->plane)
void Mod_Q1BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
{
- Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2], p[2] - 65536);
- VectorSet(diffusenormal, 0, 0, -1);
+ Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode, p[0], p[1], p[2] + 0.125, p[2] - 65536);
+ // pretend lighting is coming down from above (due to lack of a lightgrid to know primary lighting direction)
+ VectorSet(diffusenormal, 0, 0, 1);
}
static void Mod_Q1BSP_DecompressVis(const unsigned char *in, const unsigned char *inend, unsigned char *out, unsigned char *outend)
{
if (in == inend)
{
- Con_Printf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
+ Con_Printf("Mod_Q1BSP_DecompressVis: input underrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
return;
}
c = *in++;
{
if (in == inend)
{
- Con_Printf("Mod_Q1BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
+ Con_Printf("Mod_Q1BSP_DecompressVis: input underrun (during zero-run) on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
return;
}
for (c = *in++;c > 0;c--)
{
if (out == outend)
{
- Con_Printf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, out - outstart, outend - outstart);
+ Con_Printf("Mod_Q1BSP_DecompressVis: output overrun on model \"%s\" (decompressed %i of %i output bytes)\n", loadmodel->name, (int)(out - outstart), (int)(outend - outstart));
return;
}
*out++ = 0;
texture_t *tx, *tx2, *anims[10], *altanims[10];
dmiptexlump_t *m;
unsigned char *data, *mtdata;
- char name[MAX_QPATH];
+ const char *s;
+ char mapname[MAX_QPATH], name[MAX_QPATH];
loadmodel->data_textures = NULL;
// fill out all slots with notexture
for (i = 0, tx = loadmodel->data_textures;i < loadmodel->num_textures;i++, tx++)
{
- strcpy(tx->name, "NO TEXTURE FOUND");
+ strlcpy(tx->name, "NO TEXTURE FOUND", sizeof(tx->name));
tx->width = 16;
tx->height = 16;
- tx->skin.base = r_texture_notexture;
+ tx->numskinframes = 1;
+ tx->skinframerate = 1;
+ tx->currentskinframe = tx->skinframes;
+ tx->skinframes[0].base = r_texture_notexture;
+ tx->backgroundcurrentskinframe = tx->backgroundskinframes;
tx->basematerialflags = 0;
if (i == loadmodel->num_textures - 1)
{
- tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
- tx->supercontents = SUPERCONTENTS_WATER;
+ tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
+ tx->supercontents = mod_q1bsp_texture_water.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
}
else
{
tx->basematerialflags |= MATERIALFLAG_WALL;
- tx->supercontents = SUPERCONTENTS_SOLID;
+ tx->supercontents = mod_q1bsp_texture_solid.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags;
}
tx->currentframe = tx;
}
if (!m)
return;
+ s = loadmodel->name;
+ if (!strncasecmp(s, "maps/", 5))
+ s += 5;
+ FS_StripExtension(s, mapname, sizeof(mapname));
+
// just to work around bounds checking when debugging with it (array index out of bounds error thing)
dofs = m->dataofs;
// LordHavoc: mostly rewritten map texture loader
name[j] += 'a' - 'A';
tx = loadmodel->data_textures + i;
- strcpy(tx->name, name);
+ strlcpy(tx->name, name, sizeof(tx->name));
tx->width = mtwidth;
tx->height = mtheight;
}
else
{
- if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
+ if (!Mod_LoadSkinFrame(&tx->skinframes[0], gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s/%s", mapname, tx->name), TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true)
+ && !Mod_LoadSkinFrame(&tx->skinframes[0], gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", tx->name), TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
{
// did not find external texture, load it from the bsp or wad3
if (loadmodel->brush.ishlbsp)
{
tx->width = image_width;
tx->height = image_height;
- Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, false, pixels, image_width, image_height, 32, NULL, NULL);
+ Mod_LoadSkinFrame_Internal(&tx->skinframes[0], tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, false, pixels, image_width, image_height, 32, NULL, NULL);
}
if (freepixels)
Mem_Free(freepixels);
}
else if (mtdata) // texture included
- Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL);
+ Mod_LoadSkinFrame_Internal(&tx->skinframes[0], tx->name, TEXF_MIPMAP | TEXF_PRECACHE | TEXF_PICMIP, false, r_fullbrights.integer, mtdata, tx->width, tx->height, 8, NULL, NULL);
}
}
- if (tx->skin.base == NULL)
+ if (tx->skinframes[0].base == NULL)
{
// no texture found
tx->width = 16;
tx->height = 16;
- tx->skin.base = r_texture_notexture;
+ tx->skinframes[0].base = r_texture_notexture;
}
}
tx->basematerialflags = 0;
if (tx->name[0] == '*')
{
- // turb does not block movement
- tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
// LordHavoc: some turbulent textures should not be affected by wateralpha
if (strncmp(tx->name,"*lava",5)
&& strncmp(tx->name,"*teleport",9)
&& strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
- tx->basematerialflags |= MATERIALFLAG_WATERALPHA;
+ tx->basematerialflags |= MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
if (!strncmp(tx->name, "*lava", 5))
- tx->supercontents = SUPERCONTENTS_LAVA;
+ {
+ tx->supercontents = mod_q1bsp_texture_lava.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_lava.surfaceflags;
+ }
else if (!strncmp(tx->name, "*slime", 6))
- tx->supercontents = SUPERCONTENTS_SLIME;
+ {
+ tx->supercontents = mod_q1bsp_texture_slime.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_slime.surfaceflags;
+ }
else
- tx->supercontents = SUPERCONTENTS_WATER;
+ {
+ tx->supercontents = mod_q1bsp_texture_water.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
+ }
+ tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
}
else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
{
- tx->supercontents = SUPERCONTENTS_SKY;
- tx->basematerialflags |= MATERIALFLAG_SKY;
+ tx->supercontents = mod_q1bsp_texture_sky.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags;
+ tx->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
}
else
{
- tx->supercontents = SUPERCONTENTS_SOLID;
+ tx->supercontents = mod_q1bsp_texture_solid.supercontents;
+ tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags;
tx->basematerialflags |= MATERIALFLAG_WALL;
}
- if (tx->skin.fog)
- tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+ if (tx->skinframes[0].fog)
+ tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
// start out with no animation
tx->currentframe = tx;
{
int i;
unsigned char *in, *out, *data, d;
- char litfilename[1024];
+ char litfilename[MAX_QPATH];
+ char dlitfilename[MAX_QPATH];
fs_offset_t filesize;
- loadmodel->brushq1.lightdata = NULL;
if (loadmodel->brush.ishlbsp) // LordHavoc: load the colored lighting data straight
{
loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen);
// LordHavoc: hope is not lost yet, check for a .lit file to load
strlcpy (litfilename, loadmodel->name, sizeof (litfilename));
FS_StripExtension (litfilename, litfilename, sizeof (litfilename));
+ strlcpy (dlitfilename, litfilename, sizeof (dlitfilename));
strlcat (litfilename, ".lit", sizeof (litfilename));
+ strlcat (dlitfilename, ".dlit", sizeof (dlitfilename));
data = (unsigned char*) FS_LoadFile(litfilename, tempmempool, false, &filesize);
if (data)
{
loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8);
memcpy(loadmodel->brushq1.lightdata, data + 8, filesize - 8);
Mem_Free(data);
+ data = (unsigned char*) FS_LoadFile(dlitfilename, tempmempool, false, &filesize);
+ if (data)
+ {
+ if (filesize == (fs_offset_t)(8 + l->filelen * 3) && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
+ {
+ i = LittleLong(((int *)data)[1]);
+ if (i == 1)
+ {
+ Con_DPrintf("loaded %s\n", dlitfilename);
+ loadmodel->brushq1.nmaplightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, filesize - 8);
+ memcpy(loadmodel->brushq1.nmaplightdata, data + 8, filesize - 8);
+ loadmodel->brushq3.deluxemapping_modelspace = false;
+ loadmodel->brushq3.deluxemapping = true;
+ }
+ }
+ Mem_Free(data);
+ data = NULL;
+ }
return;
}
else
- {
Con_Printf("Unknown .lit file version (%d)\n", i);
- Mem_Free(data);
- }
}
+ else if (filesize == 8)
+ Con_Print("Empty .lit file, ignoring\n");
else
+ Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", (int) filesize, (int) (8 + l->filelen * 3));
+ if (data)
{
- if (filesize == 8)
- Con_Print("Empty .lit file, ignoring\n");
- else
- Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", filesize, 8 + l->filelen * 3);
Mem_Free(data);
+ data = NULL;
}
}
// LordHavoc: oh well, expand the white lighting data
if (!l->filelen)
return;
loadmodel->brushq1.lightdata = (unsigned char *)Mem_Alloc(loadmodel->mempool, l->filelen*3);
- in = loadmodel->brushq1.lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
+ in = mod_base + l->fileofs;
out = loadmodel->brushq1.lightdata;
- memcpy(in, mod_base + l->fileofs, l->filelen);
for (i = 0;i < l->filelen;i++)
{
d = *in++;
int i, j, k;
if (!data)
return;
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
if (com_token[0] != '{')
return; // error
while (1)
{
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
- strcpy(key, com_token + 1);
+ strlcpy(key, com_token + 1, sizeof(key));
else
- strcpy(key, com_token);
+ strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
dpsnprintf(value, sizeof(value), "%s", com_token);
if (!strcmp("wad", key)) // for HalfLife maps
{
k = value[i];
value[i] = 0;
- strcpy(wadname, "textures/");
- strcat(wadname, &value[j]);
+ strlcpy(wadname, "textures/", sizeof(wadname));
+ strlcat(wadname, &value[j], sizeof(wadname));
W_LoadTextureWadFile(wadname, false);
j = i+1;
if (!k)
subdivpolytriangles = 0;
subdivpolyverts = 0;
- SubdividePolygon(surface->num_vertices, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex));
+ SubdividePolygon(surface->num_vertices, (surface->mesh->data_vertex3f + 3 * surface->num_firstvertex));
if (subdivpolytriangles < 1)
Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?");
}
#endif
+static qboolean Mod_Q1BSP_AllocLightmapBlock(int *lineused, int totalwidth, int totalheight, int blockwidth, int blockheight, int *outx, int *outy)
+{
+ int y, x2, y2;
+ int bestx = totalwidth, besty = 0;
+ // find the left-most space we can find
+ for (y = 0;y <= totalheight - blockheight;y++)
+ {
+ x2 = 0;
+ for (y2 = 0;y2 < blockheight;y2++)
+ x2 = max(x2, lineused[y+y2]);
+ if (bestx > x2)
+ {
+ bestx = x2;
+ besty = y;
+ }
+ }
+ // if the best was not good enough, return failure
+ if (bestx > totalwidth - blockwidth)
+ return false;
+ // we found a good spot
+ if (outx)
+ *outx = bestx;
+ if (outy)
+ *outy = besty;
+ // now mark the space used
+ for (y2 = 0;y2 < blockheight;y2++)
+ lineused[besty+y2] = bestx + blockwidth;
+ // return success
+ return true;
+}
+
static void Mod_Q1BSP_LoadFaces(lump_t *l)
{
dface_t *in;
msurface_t *surface;
- int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris;
- float texmins[2], texmaxs[2], val;
+ int i, j, count, surfacenum, planenum, smax, tmax, ssize, tsize, firstedge, numedges, totalverts, totaltris, lightmapnumber;
+ float texmins[2], texmaxs[2], val, lightmaptexcoordscale;
+#define LIGHTMAPSIZE 256
+ rtexture_t *lightmaptexture, *deluxemaptexture;
+ int lightmap_lineused[LIGHTMAPSIZE];
in = (dface_t *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
totaltris += numedges - 2;
}
- // TODO: split up into multiple meshes as needed to avoid exceeding 65536
- // vertex limit
- loadmodel->nummeshes = 1;
- loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *));
- loadmodel->meshlist[0] = Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false);
+ Mod_AllocSurfMesh(loadmodel->mempool, totalverts, totaltris, true, false, false);
+
+ lightmaptexture = NULL;
+ deluxemaptexture = r_texture_blanknormalmap;
+ lightmapnumber = 1;
+ lightmaptexcoordscale = 1.0f / (float)LIGHTMAPSIZE;
totalverts = 0;
totaltris = 0;
// surface->flags |= SURF_PLANEBACK;
//surface->plane = loadmodel->brush.data_planes + planenum;
- surface->groupmesh = loadmodel->meshlist[0];
surface->num_firstvertex = totalverts;
surface->num_vertices = numedges;
surface->num_firsttriangle = totaltris;
int lindex = loadmodel->brushq1.surfedges[firstedge + i];
float s, t;
if (lindex > 0)
- VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
+ VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
else
- VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
- s = DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
- t = DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
- (surface->groupmesh->data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 0] = s / surface->texture->width;
- (surface->groupmesh->data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 1] = t / surface->texture->height;
- (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = 0;
- (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = 0;
- (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i] = 0;
+ VectorCopy(loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3);
+ s = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+ t = DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
+ (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 0] = s / surface->texture->width;
+ (loadmodel->surfmesh.data_texcoordtexture2f + 2 * surface->num_firstvertex)[i * 2 + 1] = t / surface->texture->height;
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = 0;
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = 0;
+ (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = 0;
}
for (i = 0;i < surface->num_triangles;i++)
{
- (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] = 0 + surface->num_firstvertex;
- (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] = i + 1 + surface->num_firstvertex;
- (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] = i + 2 + surface->num_firstvertex;
+ (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 0] = 0 + surface->num_firstvertex;
+ (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 1] = i + 1 + surface->num_firstvertex;
+ (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle)[i * 3 + 2] = i + 2 + surface->num_firstvertex;
}
// compile additional data about the surface geometry
- Mod_BuildTextureVectorsAndNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, surface->groupmesh->data_vertex3f, surface->groupmesh->data_texcoordtexture2f, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle), surface->groupmesh->data_svector3f, surface->groupmesh->data_tvector3f, surface->groupmesh->data_normal3f, true);
- BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex));
+ Mod_BuildNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_normal3f, true);
+ Mod_BuildTextureVectorsFromNormals(surface->num_firstvertex, surface->num_vertices, surface->num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle), loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
+ BoxFromPoints(surface->mins, surface->maxs, surface->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex));
// generate surface extents information
- texmins[0] = texmaxs[0] = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
- texmins[1] = texmaxs[1] = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
+ texmins[0] = texmaxs[0] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3];
+ texmins[1] = texmaxs[1] = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3];
for (i = 1;i < surface->num_vertices;i++)
{
for (j = 0;j < 2;j++)
{
- val = DotProduct((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3, surface->lightmapinfo->texinfo->vecs[j]) + surface->lightmapinfo->texinfo->vecs[j][3];
+ val = DotProduct((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3, surface->lightmapinfo->texinfo->vecs[j]) + surface->lightmapinfo->texinfo->vecs[j][3];
texmins[j] = min(texmins[j], val);
texmaxs[j] = max(texmaxs[j], val);
}
// lighting info
for (i = 0;i < MAXLIGHTMAPS;i++)
surface->lightmapinfo->styles[i] = in->styles[i];
- surface->lightmapinfo->lightmaptexturestride = 0;
surface->lightmaptexture = NULL;
+ surface->deluxemaptexture = r_texture_blanknormalmap;
i = LittleLong(in->lightofs);
if (i == -1)
{
else if (loadmodel->brush.ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + i;
else // LordHavoc: white lighting (bsp version 29)
+ {
surface->lightmapinfo->samples = loadmodel->brushq1.lightdata + (i * 3);
+ if (loadmodel->brushq1.nmaplightdata)
+ surface->lightmapinfo->nmapsamples = loadmodel->brushq1.nmaplightdata + (i * 3);
+ }
// check if we should apply a lightmap to this
if (!(surface->lightmapinfo->texinfo->flags & TEX_SPECIAL) || surface->lightmapinfo->samples)
{
- int i, iu, iv;
+ int i, iu, iv, lightmapx, lightmapy;
float u, v, ubase, vbase, uscale, vscale;
if (ssize > 256 || tsize > 256)
// clear to white
memset(surface->lightmapinfo->stainsamples, 255, ssize * tsize * 3);
- if (r_miplightmaps.integer)
- {
- surface->lightmapinfo->lightmaptexturestride = ssize;
- surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
- }
- else
+ // find a place for this lightmap
+ if (!lightmaptexture || !Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy))
{
- surface->lightmapinfo->lightmaptexturestride = R_CompatibleFragmentWidth(ssize, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
- surface->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surface->lightmapinfo->lightmaptexturestride, tsize, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ // could not find room, make a new lightmap
+ lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%i", lightmapnumber), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ if (loadmodel->brushq1.nmaplightdata)
+ deluxemaptexture = R_LoadTexture2D(loadmodel->texturepool, va("deluxemap%i", lightmapnumber), LIGHTMAPSIZE, LIGHTMAPSIZE, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
+ lightmapnumber++;
+ memset(lightmap_lineused, 0, sizeof(lightmap_lineused));
+ Mod_Q1BSP_AllocLightmapBlock(lightmap_lineused, LIGHTMAPSIZE, LIGHTMAPSIZE, ssize, tsize, &lightmapx, &lightmapy);
}
- R_FragmentLocation(surface->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
- uscale = (uscale - ubase) / ssize;
- vscale = (vscale - vbase) / tsize;
+
+ surface->lightmaptexture = lightmaptexture;
+ surface->deluxemaptexture = deluxemaptexture;
+ surface->lightmapinfo->lightmaporigin[0] = lightmapx;
+ surface->lightmapinfo->lightmaporigin[1] = lightmapy;
+
+ ubase = lightmapx * lightmaptexcoordscale;
+ vbase = lightmapy * lightmaptexcoordscale;
+ uscale = lightmaptexcoordscale;
+ vscale = lightmaptexcoordscale;
for (i = 0;i < surface->num_vertices;i++)
{
- u = ((DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]) + 8 - surface->lightmapinfo->texturemins[0]) * (1.0 / 16.0);
- v = ((DotProduct(((surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0);
- (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = u * uscale + ubase;
- (surface->groupmesh->data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = v * vscale + vbase;
+ u = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[0]) + surface->lightmapinfo->texinfo->vecs[0][3]) + 8 - surface->lightmapinfo->texturemins[0]) * (1.0 / 16.0);
+ v = ((DotProduct(((loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex) + i * 3), surface->lightmapinfo->texinfo->vecs[1]) + surface->lightmapinfo->texinfo->vecs[1][3]) + 8 - surface->lightmapinfo->texturemins[1]) * (1.0 / 16.0);
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 0] = u * uscale + ubase;
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * surface->num_firstvertex)[i * 2 + 1] = v * vscale + vbase;
// LordHavoc: calc lightmap data offset for vertex lighting to use
iu = (int) u;
iv = (int) v;
- (surface->groupmesh->data_lightmapoffsets + surface->num_firstvertex)[i] = (bound(0, iv, tmax) * ssize + bound(0, iu, smax)) * 3;
+ (loadmodel->surfmesh.data_lightmapoffsets + surface->num_firstvertex)[i] = (bound(0, iv, tmax) * ssize + bound(0, iu, smax)) * 3;
}
}
}
out->numleafsurfaces = LittleShort(in->nummarksurfaces);
if (out->firstleafsurface < 0 || LittleShort(in->firstmarksurface) + out->numleafsurfaces > loadmodel->brush.num_leafsurfaces)
{
- Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", out->firstleafsurface, out->firstleafsurface + out->numleafsurfaces, 0, loadmodel->brush.num_leafsurfaces);
+ Con_Printf("Mod_Q1BSP_LoadLeafs: invalid leafsurface range %i:%i outside range %i:%i\n", (int)(out->firstleafsurface - loadmodel->brush.data_leafsurfaces), (int)(out->firstleafsurface + out->numleafsurfaces - loadmodel->brush.data_leafsurfaces), 0, loadmodel->brush.num_leafsurfaces);
out->firstleafsurface = NULL;
out->numleafsurfaces = 0;
}
}
}
+qboolean Mod_Q1BSP_CheckWaterAlphaSupport(void)
+{
+ int i, j;
+ mleaf_t *leaf;
+ const unsigned char *pvs;
+ // check all liquid leafs to see if they can see into empty leafs, if any
+ // can we can assume this map supports r_wateralpha
+ for (i = 0, leaf = loadmodel->brush.data_leafs;i < loadmodel->brush.num_leafs;i++, leaf++)
+ {
+ if ((leaf->contents == CONTENTS_WATER || leaf->contents == CONTENTS_SLIME) && (leaf->clusterindex >= 0 && loadmodel->brush.data_pvsclusters))
+ {
+ pvs = loadmodel->brush.data_pvsclusters + leaf->clusterindex * loadmodel->brush.num_pvsclusterbytes;
+ for (j = 0;j < loadmodel->brush.num_leafs;j++)
+ if (CHECKPVSBIT(pvs, loadmodel->brush.data_leafs[j].clusterindex) && loadmodel->brush.data_leafs[j].contents == CONTENTS_EMPTY)
+ return true;
+ }
+ }
+ return false;
+}
+
static void Mod_Q1BSP_LoadClipnodes(lump_t *l, hullinfo_t *hullinfo)
{
dclipnode_t *in, *out;
out->planenum = LittleLong(in->planenum);
out->children[0] = LittleShort(in->children[0]);
out->children[1] = LittleShort(in->children[1]);
+ if (out->planenum < 0 || out->planenum >= loadmodel->brush.num_planes)
+ Host_Error("Corrupt clipping hull(out of range planenum)");
if (out->children[0] >= count || out->children[1] >= count)
Host_Error("Corrupt clipping hull(out of range child)");
}
if (!maptext)
return;
text = maptext;
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
submodel = 0;
for (;;)
{
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
break;
if (com_token[0] != '{')
return; // error
brushes = Mem_Alloc(loadmodel->mempool, maxbrushes * sizeof(mbrush_t));
for (;;)
{
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
if (com_token[0] == '}')
break; // end of entity
}
for (;;)
{
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
return; // error
if (com_token[0] == '}')
break; // end of brush
// FIXME: support hl .map format
for (pointnum = 0;pointnum < 3;pointnum++)
{
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
for (componentnum = 0;componentnum < 3;componentnum++)
{
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
point[pointnum][componentnum] = atof(com_token);
}
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
}
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
strlcpy(facetexture, com_token, sizeof(facetexture));
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
//scroll_s = atof(com_token);
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
//scroll_t = atof(com_token);
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
//rotate = atof(com_token);
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
//scale_s = atof(com_token);
- COM_ParseToken(&data, false);
+ COM_ParseTokenConsole(&data);
//scale_t = atof(com_token);
TriangleNormal(point[0], point[1], point[2], planenormal);
VectorNormalizeDouble(planenormal);
}
}
+#define PORTAL_DIST_EPSILON (1.0 / 32.0)
static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
{
int i, side;
nodeportal = AllocPortal();
nodeportal->plane = *plane;
+ // TODO: calculate node bounding boxes during recursion and calculate a maximum plane size accordingly to improve precision (as most maps do not need 1 billion unit plane polygons)
PolygonD_QuadForPlane(nodeportal->points, nodeportal->plane.normal[0], nodeportal->plane.normal[1], nodeportal->plane.normal[2], nodeportal->plane.dist, 1024.0*1024.0*1024.0);
nodeportal->numpoints = 4;
side = 0; // shut up compiler warning
for (i = 0;i < nodeportal->numpoints*3;i++)
frontpoints[i] = nodeportal->points[i];
- PolygonD_Divide(nodeportal->numpoints, frontpoints, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, 1.0/32.0, MAX_PORTALPOINTS, nodeportal->points, &nodeportal->numpoints, 0, NULL, NULL, NULL);
+ PolygonD_Divide(nodeportal->numpoints, frontpoints, clipplane.normal[0], clipplane.normal[1], clipplane.normal[2], clipplane.dist, PORTAL_DIST_EPSILON, MAX_PORTALPOINTS, nodeportal->points, &nodeportal->numpoints, 0, NULL, NULL, NULL);
if (nodeportal->numpoints <= 0 || nodeportal->numpoints >= MAX_PORTALPOINTS)
break;
}
RemovePortalFromNodes(portal);
// cut the portal into two portals, one on each side of the node plane
- PolygonD_Divide(portal->numpoints, portal->points, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, 1.0/32.0, MAX_PORTALPOINTS, frontpoints, &numfrontpoints, MAX_PORTALPOINTS, backpoints, &numbackpoints, NULL);
+ PolygonD_Divide(portal->numpoints, portal->points, plane->normal[0], plane->normal[1], plane->normal[2], plane->dist, PORTAL_DIST_EPSILON, MAX_PORTALPOINTS, frontpoints, &numfrontpoints, MAX_PORTALPOINTS, backpoints, &numbackpoints, NULL);
if (!numfrontpoints)
{
Mod_Q1BSP_LoadNodes(&header->lumps[LUMP_NODES]);
Mod_Q1BSP_LoadClipnodes(&header->lumps[LUMP_CLIPNODES], &hullinfo);
+ // check if the map supports transparent water rendering
+ loadmodel->brush.supportwateralpha = Mod_Q1BSP_CheckWaterAlphaSupport();
+
if (!mod->brushq1.lightdata)
mod->brush.LightPoint = NULL;
}
loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
- Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surface->groupmesh->data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);
// copy the base model to this one
*mod = *loadmodel;
// rename the clone back to its proper name
- strcpy(mod->name, name);
+ strlcpy(mod->name, name, sizeof(mod->name));
// textures and memory belong to the main model
mod->texturepool = NULL;
mod->mempool = NULL;
if (surface->texture->basematerialflags & MATERIALFLAG_SKY)
mod->DrawSky = R_Q1BSP_DrawSky;
// calculate bounding shapes
- for (k = 0, vec = (surface->groupmesh->data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3)
+ for (k = 0, vec = (loadmodel->surfmesh.data_vertex3f + 3 * surface->num_firstvertex);k < surface->num_vertices;k++, vec += 3)
{
if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
//Mod_Q1BSP_ProcessLightList();
- if (developer.integer)
+ if (developer.integer >= 10)
Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->num_surfaces, loadmodel->brush.num_nodes, loadmodel->brush.num_leafs, mod->brush.num_pvsclusters, loadmodel->brush.num_portals);
}
memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
data = loadmodel->brush.entities;
// some Q3 maps override the lightgrid_cellsize with a worldspawn key
- if (data && COM_ParseToken(&data, false) && com_token[0] == '{')
+ if (data && COM_ParseTokenConsole(&data) && com_token[0] == '{')
{
while (1)
{
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
break; // error
if (com_token[0] == '}')
break; // end of worldspawn
if (com_token[0] == '_')
- strcpy(key, com_token + 1);
+ strlcpy(key, com_token + 1, sizeof(key));
else
- strcpy(key, com_token);
+ strlcpy(key, com_token, sizeof(key));
while (key[strlen(key)-1] == ' ') // remove trailing spaces
key[strlen(key)-1] = 0;
- if (!COM_ParseToken(&data, false))
+ if (!COM_ParseTokenConsole(&data))
break; // error
- strcpy(value, com_token);
+ strlcpy(value, com_token, sizeof(value));
if (!strcmp("gridsize", key))
{
if (sscanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3 && v[0] != 0 && v[1] != 0 && v[2] != 0)
}
}
-static void Mod_Q3BSP_LoadTextures(lump_t *l)
-{
- q3dtexture_t *in;
- texture_t *out;
- int i, count;
- int j, c;
- fssearch_t *search;
- char *f;
- const char *text;
- int flags, flags2, numparameters, passnumber;
- char shadername[Q3PATHLENGTH];
- char sky[Q3PATHLENGTH];
- char firstpasstexturename[Q3PATHLENGTH];
- char parameter[4][Q3PATHLENGTH];
+// FIXME: make MAXSHADERS dynamic
+#define Q3SHADER_MAXSHADERS 4096
+#define Q3SHADER_MAXLAYERS 8
- in = (q3dtexture_t *)(mod_base + l->fileofs);
- if (l->filelen % sizeof(*in))
- Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
- count = l->filelen / sizeof(*in);
- out = (texture_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+typedef struct q3shaderinfo_layer_s
+{
+ int alphatest;
+ int clampmap;
+ float framerate;
+ int numframes;
+ char texturename[TEXTURE_MAXFRAMES][Q3PATHLENGTH];
+ int blendfunc[2];
+ qboolean rgbgenvertex;
+ qboolean alphagenvertex;
+}
+q3shaderinfo_layer_t;
- loadmodel->data_textures = out;
- loadmodel->num_textures = count;
+typedef struct q3shaderinfo_s
+{
+ char name[Q3PATHLENGTH];
+ int surfaceparms;
+ int textureflags;
+ int numlayers;
+ qboolean lighting;
+ qboolean vertexalpha;
+ qboolean textureblendalpha;
+ q3shaderinfo_layer_t *primarylayer, *backgroundlayer;
+ q3shaderinfo_layer_t layers[Q3SHADER_MAXLAYERS];
+ char skyboxname[Q3PATHLENGTH];
+}
+q3shaderinfo_t;
- for (i = 0;i < count;i++, in++, out++)
- {
- strlcpy (out->name, in->name, sizeof (out->name));
- out->surfaceflags = LittleLong(in->surfaceflags);
- out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in->contents));
- out->surfaceparms = -1;
- }
+int q3shaders_numshaders;
+q3shaderinfo_t q3shaders_shaders[Q3SHADER_MAXSHADERS];
- // do a quick parse of shader files to get surfaceparms
- if ((search = FS_Search("scripts/*.shader", true, false)))
+static void Mod_Q3BSP_LoadShaders(void)
+{
+ int j;
+ int fileindex;
+ fssearch_t *search;
+ char *f;
+ const char *text;
+ q3shaderinfo_t *shader;
+ q3shaderinfo_layer_t *layer;
+ int numparameters;
+ char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
+ search = FS_Search("scripts/*.shader", true, false);
+ if (!search)
+ return;
+ q3shaders_numshaders = 0;
+ for (fileindex = 0;fileindex < search->numfilenames;fileindex++)
{
- for (i = 0;i < search->numfilenames;i++)
+ text = f = (char *)FS_LoadFile(search->filenames[fileindex], tempmempool, false, NULL);
+ if (!f)
+ continue;
+ while (COM_ParseToken(&text, false))
{
- if ((f = (char *)FS_LoadFile(search->filenames[i], tempmempool, false, NULL)))
+ if (q3shaders_numshaders >= Q3SHADER_MAXSHADERS)
{
- text = f;
- while (COM_ParseToken(&text, false))
+ Con_Printf("Mod_Q3BSP_LoadShaders: too many shaders!\n");
+ break;
+ }
+ shader = q3shaders_shaders + q3shaders_numshaders++;
+ memset(shader, 0, sizeof(*shader));
+ strlcpy(shader->name, com_token, sizeof(shader->name));
+ if (!COM_ParseToken(&text, false) || strcasecmp(com_token, "{"))
+ {
+ Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[fileindex], com_token);
+ break;
+ }
+ while (COM_ParseToken(&text, false))
+ {
+ if (!strcasecmp(com_token, "}"))
+ break;
+ if (!strcasecmp(com_token, "{"))
{
- strlcpy (shadername, com_token, sizeof (shadername));
- flags = 0;
- flags2 = 0;
- sky[0] = 0;
- passnumber = 0;
- firstpasstexturename[0] = 0;
- if (COM_ParseToken(&text, false) && !strcasecmp(com_token, "{"))
+ if (shader->numlayers < Q3SHADER_MAXLAYERS)
{
- while (COM_ParseToken(&text, false))
+ layer = shader->layers + shader->numlayers++;
+ layer->rgbgenvertex = false;
+ layer->alphagenvertex = false;
+ layer->blendfunc[0] = GL_ONE;
+ layer->blendfunc[1] = GL_ZERO;
+ }
+ else
+ layer = NULL;
+ while (COM_ParseToken(&text, false))
+ {
+ if (!strcasecmp(com_token, "}"))
+ break;
+ if (!strcasecmp(com_token, "\n"))
+ continue;
+ if (layer == NULL)
+ continue;
+ numparameters = 0;
+ for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
{
- if (!strcasecmp(com_token, "}"))
- break;
- else if (!strcasecmp(com_token, "{"))
- {
- while (COM_ParseToken(&text, false))
- {
- if (!strcasecmp(com_token, "}"))
- break;
- if (!strcasecmp(com_token, "\n"))
- continue;
- numparameters = 0;
- for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
- {
- if (j < 4)
- {
- strlcpy(parameter[j], com_token, sizeof(parameter[j]));
- numparameters = j + 1;
- }
- if (!COM_ParseToken(&text, true))
- break;
- }
- if (developer.integer >= 2)
- {
- Con_Printf("%s %i: ", shadername, passnumber);
- for (j = 0;j < numparameters;j++)
- Con_Printf(" %s", parameter[j]);
- Con_Print("\n");
- }
- if (passnumber == 0 && numparameters >= 1)
- {
- if (!strcasecmp(parameter[0], "blendfunc") && (flags & Q3SURFACEPARM_TRANS))
- {
- if (numparameters == 2 && !strcasecmp(parameter[1], "add"))
- flags2 |= Q3TEXTUREFLAG_ADDITIVE;
- else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_one") && !strcasecmp(parameter[2], "gl_one"))
- flags2 |= Q3TEXTUREFLAG_ADDITIVE;
- else if (numparameters == 3 && !strcasecmp(parameter[1], "gl_src_alpha") && !strcasecmp(parameter[2], "gl_one"))
- flags2 |= Q3TEXTUREFLAG_ADDITIVE;
- }
- else if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
- strlcpy(firstpasstexturename, parameter[1], sizeof(firstpasstexturename));
- else if (numparameters >= 3 && !strcasecmp(parameter[0], "animmap"))
- strlcpy(firstpasstexturename, parameter[2], sizeof(firstpasstexturename));
- else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
- flags2 |= Q3TEXTUREFLAG_ALPHATEST;
- }
- // break out a level if it was }
- if (!strcasecmp(com_token, "}"))
- break;
- }
- passnumber++;
- continue;
- }
- numparameters = 0;
- for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
+ if (j < TEXTURE_MAXFRAMES + 4)
{
- if (j < 4)
- {
- strlcpy(parameter[j], com_token, sizeof(parameter[j]));
- numparameters = j + 1;
- }
- if (!COM_ParseToken(&text, true))
- break;
+ strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+ numparameters = j + 1;
}
- if (i == 0 && !strcasecmp(com_token, "}"))
+ if (!COM_ParseToken(&text, true))
break;
- if (developer.integer >= 2)
- {
- Con_Printf("%s: ", shadername);
- for (j = 0;j < numparameters;j++)
- Con_Printf(" %s", parameter[j]);
- Con_Print("\n");
- }
- if (numparameters < 1)
- continue;
- if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
- {
- if (!strcasecmp(parameter[1], "alphashadow"))
- flags |= Q3SURFACEPARM_ALPHASHADOW;
- else if (!strcasecmp(parameter[1], "areaportal"))
- flags |= Q3SURFACEPARM_AREAPORTAL;
- else if (!strcasecmp(parameter[1], "clusterportal"))
- flags |= Q3SURFACEPARM_CLUSTERPORTAL;
- else if (!strcasecmp(parameter[1], "detail"))
- flags |= Q3SURFACEPARM_DETAIL;
- else if (!strcasecmp(parameter[1], "donotenter"))
- flags |= Q3SURFACEPARM_DONOTENTER;
- else if (!strcasecmp(parameter[1], "fog"))
- flags |= Q3SURFACEPARM_FOG;
- else if (!strcasecmp(parameter[1], "lava"))
- flags |= Q3SURFACEPARM_LAVA;
- else if (!strcasecmp(parameter[1], "lightfilter"))
- flags |= Q3SURFACEPARM_LIGHTFILTER;
- else if (!strcasecmp(parameter[1], "metalsteps"))
- flags |= Q3SURFACEPARM_METALSTEPS;
- else if (!strcasecmp(parameter[1], "nodamage"))
- flags |= Q3SURFACEPARM_NODAMAGE;
- else if (!strcasecmp(parameter[1], "nodlight"))
- flags |= Q3SURFACEPARM_NODLIGHT;
- else if (!strcasecmp(parameter[1], "nodraw"))
- flags |= Q3SURFACEPARM_NODRAW;
- else if (!strcasecmp(parameter[1], "nodrop"))
- flags |= Q3SURFACEPARM_NODROP;
- else if (!strcasecmp(parameter[1], "noimpact"))
- flags |= Q3SURFACEPARM_NOIMPACT;
- else if (!strcasecmp(parameter[1], "nolightmap"))
- flags |= Q3SURFACEPARM_NOLIGHTMAP;
- else if (!strcasecmp(parameter[1], "nomarks"))
- flags |= Q3SURFACEPARM_NOMARKS;
- else if (!strcasecmp(parameter[1], "nomipmaps"))
- flags |= Q3SURFACEPARM_NOMIPMAPS;
- else if (!strcasecmp(parameter[1], "nonsolid"))
- flags |= Q3SURFACEPARM_NONSOLID;
- else if (!strcasecmp(parameter[1], "origin"))
- flags |= Q3SURFACEPARM_ORIGIN;
- else if (!strcasecmp(parameter[1], "playerclip"))
- flags |= Q3SURFACEPARM_PLAYERCLIP;
- else if (!strcasecmp(parameter[1], "sky"))
- flags |= Q3SURFACEPARM_SKY;
- else if (!strcasecmp(parameter[1], "slick"))
- flags |= Q3SURFACEPARM_SLICK;
- else if (!strcasecmp(parameter[1], "slime"))
- flags |= Q3SURFACEPARM_SLIME;
- else if (!strcasecmp(parameter[1], "structural"))
- flags |= Q3SURFACEPARM_STRUCTURAL;
- else if (!strcasecmp(parameter[1], "trans"))
- flags |= Q3SURFACEPARM_TRANS;
- else if (!strcasecmp(parameter[1], "water"))
- flags |= Q3SURFACEPARM_WATER;
- else if (!strcasecmp(parameter[1], "pointlight"))
- flags |= Q3SURFACEPARM_POINTLIGHT;
- else
- Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[i], parameter[1]);
- }
- else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
- strlcpy(sky, parameter[1], sizeof(sky));
- else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
- {
- if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
- strlcpy(sky, parameter[1], sizeof(sky));
- }
- else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
- {
- if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
- flags2 |= Q3TEXTUREFLAG_TWOSIDED;
- }
- else if (!strcasecmp(parameter[0], "nomipmaps"))
- flags2 |= Q3TEXTUREFLAG_NOMIPMAPS;
- else if (!strcasecmp(parameter[0], "nopicmip"))
- flags2 |= Q3TEXTUREFLAG_NOPICMIP;
- else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
- {
- if (!strcasecmp(parameter[1], "autosprite") && numparameters == 2)
- flags2 |= Q3TEXTUREFLAG_AUTOSPRITE;
- if (!strcasecmp(parameter[1], "autosprite2") && numparameters == 2)
- flags2 |= Q3TEXTUREFLAG_AUTOSPRITE2;
- }
}
- // add shader to list (shadername and flags)
- // actually here we just poke into the texture settings
- for (j = 0, out = loadmodel->data_textures;j < loadmodel->num_textures;j++, out++)
+ if (developer.integer >= 100)
{
- if (!strcasecmp(out->name, shadername))
+ Con_Printf("%s %i: ", shader->name, shader->numlayers - 1);
+ for (j = 0;j < numparameters;j++)
+ Con_Printf(" %s", parameter[j]);
+ Con_Print("\n");
+ }
+ if (numparameters >= 2 && !strcasecmp(parameter[0], "blendfunc"))
+ {
+ if (numparameters == 2)
{
- out->surfaceparms = flags;
- out->textureflags = flags2;
- out->basematerialflags = 0;
- if (out->surfaceparms & Q3SURFACEPARM_NODRAW)
- out->basematerialflags |= MATERIALFLAG_NODRAW;
- else if (out->surfaceparms & Q3SURFACEPARM_SKY)
- out->basematerialflags |= MATERIALFLAG_SKY;
- else if (out->surfaceparms & Q3SURFACEPARM_LAVA)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_FULLBRIGHT;
- else if (out->surfaceparms & Q3SURFACEPARM_SLIME)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
- else if (out->surfaceparms & Q3SURFACEPARM_WATER)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
- else
- out->basematerialflags |= MATERIALFLAG_WALL;
- if (out->textureflags & Q3TEXTUREFLAG_ALPHATEST)
+ if (!strcasecmp(parameter[1], "add"))
{
- // FIXME: support alpha test?
- out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+ layer->blendfunc[0] = GL_ONE;
+ layer->blendfunc[1] = GL_ONE;
}
- else if (out->surfaceparms & Q3SURFACEPARM_TRANS)
+ else if (!strcasecmp(parameter[1], "filter"))
{
- if (out->textureflags & Q3TEXTUREFLAG_ADDITIVE)
- out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_TRANSPARENT;
- else
- out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_TRANSPARENT;
+ layer->blendfunc[0] = GL_DST_COLOR;
+ layer->blendfunc[1] = GL_ZERO;
}
- strlcpy(out->firstpasstexturename, firstpasstexturename, sizeof(out->firstpasstexturename));
- if ((flags & Q3SURFACEPARM_SKY) && sky[0])
+ else if (!strcasecmp(parameter[1], "blend"))
{
- // quake3 seems to append a _ to the skybox name, so this must do so as well
- dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", sky);
+ layer->blendfunc[0] = GL_SRC_ALPHA;
+ layer->blendfunc[1] = GL_ONE_MINUS_SRC_ALPHA;
}
}
+ else if (numparameters == 3)
+ {
+ int k;
+ for (k = 0;k < 2;k++)
+ {
+ if (!strcasecmp(parameter[k+1], "GL_ONE"))
+ layer->blendfunc[k] = GL_ONE;
+ else if (!strcasecmp(parameter[k+1], "GL_ZERO"))
+ layer->blendfunc[k] = GL_ZERO;
+ else if (!strcasecmp(parameter[k+1], "GL_SRC_COLOR"))
+ layer->blendfunc[k] = GL_SRC_COLOR;
+ else if (!strcasecmp(parameter[k+1], "GL_SRC_ALPHA"))
+ layer->blendfunc[k] = GL_SRC_ALPHA;
+ else if (!strcasecmp(parameter[k+1], "GL_DST_COLOR"))
+ layer->blendfunc[k] = GL_DST_COLOR;
+ else if (!strcasecmp(parameter[k+1], "GL_DST_ALPHA"))
+ layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
+ else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_COLOR"))
+ layer->blendfunc[k] = GL_ONE_MINUS_SRC_COLOR;
+ else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_SRC_ALPHA"))
+ layer->blendfunc[k] = GL_ONE_MINUS_SRC_ALPHA;
+ else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_COLOR"))
+ layer->blendfunc[k] = GL_ONE_MINUS_DST_COLOR;
+ else if (!strcasecmp(parameter[k+1], "GL_ONE_MINUS_DST_ALPHA"))
+ layer->blendfunc[k] = GL_ONE_MINUS_DST_ALPHA;
+ else
+ layer->blendfunc[k] = GL_ONE; // default in case of parsing error
+ }
+ }
+ }
+ if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
+ layer->alphatest = true;
+ if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
+ {
+ if (!strcasecmp(parameter[0], "clampmap"))
+ layer->clampmap = true;
+ layer->numframes = 1;
+ layer->framerate = 1;
+ strlcpy(layer->texturename[0], parameter[1], sizeof(layer->texturename));
+ if (!strcasecmp(parameter[1], "$lightmap"))
+ shader->lighting = true;
}
+ else if (numparameters >= 3 && (!strcasecmp(parameter[0], "animmap") || !strcasecmp(parameter[0], "animclampmap")))
+ {
+ int i;
+ layer->numframes = min(numparameters - 2, TEXTURE_MAXFRAMES);
+ layer->framerate = atof(parameter[1]);
+ for (i = 0;i < layer->numframes;i++)
+ strlcpy(layer->texturename[i], parameter[i + 2], sizeof(layer->texturename));
+ }
+ else if (numparameters >= 2 && !strcasecmp(parameter[0], "rgbgen") && !strcasecmp(parameter[1], "vertex"))
+ layer->rgbgenvertex = true;
+ else if (numparameters >= 2 && !strcasecmp(parameter[0], "alphagen") && !strcasecmp(parameter[1], "vertex"))
+ layer->alphagenvertex = true;
+ // break out a level if it was }
+ if (!strcasecmp(com_token, "}"))
+ break;
}
- else
+ if (layer->rgbgenvertex)
+ shader->lighting = true;
+ if (layer->alphagenvertex)
{
- Con_Printf("%s parsing error - expected \"{\", found \"%s\"\n", search->filenames[i], com_token);
- goto parseerror;
+ if (layer == shader->layers + 0)
+ {
+ // vertex controlled transparency
+ shader->vertexalpha = true;
+ }
+ else
+ {
+ // multilayer terrain shader or similar
+ shader->textureblendalpha = true;
+ }
+ }
+ continue;
+ }
+ numparameters = 0;
+ for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
+ {
+ if (j < TEXTURE_MAXFRAMES + 4)
+ {
+ strlcpy(parameter[j], com_token, sizeof(parameter[j]));
+ numparameters = j + 1;
}
+ if (!COM_ParseToken(&text, true))
+ break;
}
-parseerror:
- Mem_Free(f);
+ if (fileindex == 0 && !strcasecmp(com_token, "}"))
+ break;
+ if (developer.integer >= 100)
+ {
+ Con_Printf("%s: ", shader->name);
+ for (j = 0;j < numparameters;j++)
+ Con_Printf(" %s", parameter[j]);
+ Con_Print("\n");
+ }
+ if (numparameters < 1)
+ continue;
+ if (!strcasecmp(parameter[0], "surfaceparm") && numparameters >= 2)
+ {
+ if (!strcasecmp(parameter[1], "alphashadow"))
+ shader->surfaceparms |= Q3SURFACEPARM_ALPHASHADOW;
+ else if (!strcasecmp(parameter[1], "areaportal"))
+ shader->surfaceparms |= Q3SURFACEPARM_AREAPORTAL;
+ else if (!strcasecmp(parameter[1], "botclip"))
+ shader->surfaceparms |= Q3SURFACEPARM_BOTCLIP;
+ else if (!strcasecmp(parameter[1], "clusterportal"))
+ shader->surfaceparms |= Q3SURFACEPARM_CLUSTERPORTAL;
+ else if (!strcasecmp(parameter[1], "detail"))
+ shader->surfaceparms |= Q3SURFACEPARM_DETAIL;
+ else if (!strcasecmp(parameter[1], "donotenter"))
+ shader->surfaceparms |= Q3SURFACEPARM_DONOTENTER;
+ else if (!strcasecmp(parameter[1], "dust"))
+ shader->surfaceparms |= Q3SURFACEPARM_DUST;
+ else if (!strcasecmp(parameter[1], "hint"))
+ shader->surfaceparms |= Q3SURFACEPARM_HINT;
+ else if (!strcasecmp(parameter[1], "fog"))
+ shader->surfaceparms |= Q3SURFACEPARM_FOG;
+ else if (!strcasecmp(parameter[1], "lava"))
+ shader->surfaceparms |= Q3SURFACEPARM_LAVA;
+ else if (!strcasecmp(parameter[1], "lightfilter"))
+ shader->surfaceparms |= Q3SURFACEPARM_LIGHTFILTER;
+ else if (!strcasecmp(parameter[1], "lightgrid"))
+ shader->surfaceparms |= Q3SURFACEPARM_LIGHTGRID;
+ else if (!strcasecmp(parameter[1], "metalsteps"))
+ shader->surfaceparms |= Q3SURFACEPARM_METALSTEPS;
+ else if (!strcasecmp(parameter[1], "nodamage"))
+ shader->surfaceparms |= Q3SURFACEPARM_NODAMAGE;
+ else if (!strcasecmp(parameter[1], "nodlight"))
+ shader->surfaceparms |= Q3SURFACEPARM_NODLIGHT;
+ else if (!strcasecmp(parameter[1], "nodraw"))
+ shader->surfaceparms |= Q3SURFACEPARM_NODRAW;
+ else if (!strcasecmp(parameter[1], "nodrop"))
+ shader->surfaceparms |= Q3SURFACEPARM_NODROP;
+ else if (!strcasecmp(parameter[1], "noimpact"))
+ shader->surfaceparms |= Q3SURFACEPARM_NOIMPACT;
+ else if (!strcasecmp(parameter[1], "nolightmap"))
+ shader->surfaceparms |= Q3SURFACEPARM_NOLIGHTMAP;
+ else if (!strcasecmp(parameter[1], "nomarks"))
+ shader->surfaceparms |= Q3SURFACEPARM_NOMARKS;
+ else if (!strcasecmp(parameter[1], "nomipmaps"))
+ shader->surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
+ else if (!strcasecmp(parameter[1], "nonsolid"))
+ shader->surfaceparms |= Q3SURFACEPARM_NONSOLID;
+ else if (!strcasecmp(parameter[1], "origin"))
+ shader->surfaceparms |= Q3SURFACEPARM_ORIGIN;
+ else if (!strcasecmp(parameter[1], "playerclip"))
+ shader->surfaceparms |= Q3SURFACEPARM_PLAYERCLIP;
+ else if (!strcasecmp(parameter[1], "sky"))
+ shader->surfaceparms |= Q3SURFACEPARM_SKY;
+ else if (!strcasecmp(parameter[1], "slick"))
+ shader->surfaceparms |= Q3SURFACEPARM_SLICK;
+ else if (!strcasecmp(parameter[1], "slime"))
+ shader->surfaceparms |= Q3SURFACEPARM_SLIME;
+ else if (!strcasecmp(parameter[1], "structural"))
+ shader->surfaceparms |= Q3SURFACEPARM_STRUCTURAL;
+ else if (!strcasecmp(parameter[1], "trans"))
+ shader->surfaceparms |= Q3SURFACEPARM_TRANS;
+ else if (!strcasecmp(parameter[1], "water"))
+ shader->surfaceparms |= Q3SURFACEPARM_WATER;
+ else if (!strcasecmp(parameter[1], "pointlight"))
+ shader->surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
+ else
+ Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
+ }
+ else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
+ {
+ // some q3 skies don't have the sky parm set
+ shader->surfaceparms |= Q3SURFACEPARM_SKY;
+ strlcpy(shader->skyboxname, parameter[1], sizeof(shader->skyboxname));
+ }
+ else if (!strcasecmp(parameter[0], "skyparms") && numparameters >= 2)
+ {
+ // some q3 skies don't have the sky parm set
+ shader->surfaceparms |= Q3SURFACEPARM_SKY;
+ if (!atoi(parameter[1]) && strcasecmp(parameter[1], "-"))
+ strlcpy(shader->skyboxname, parameter[1], sizeof(shader->skyboxname));
+ }
+ else if (!strcasecmp(parameter[0], "cull") && numparameters >= 2)
+ {
+ if (!strcasecmp(parameter[1], "disable") || !strcasecmp(parameter[1], "none") || !strcasecmp(parameter[1], "twosided"))
+ shader->textureflags |= Q3TEXTUREFLAG_TWOSIDED;
+ }
+ else if (!strcasecmp(parameter[0], "nomipmaps"))
+ shader->surfaceparms |= Q3SURFACEPARM_NOMIPMAPS;
+ else if (!strcasecmp(parameter[0], "nopicmip"))
+ shader->textureflags |= Q3TEXTUREFLAG_NOPICMIP;
+ else if (!strcasecmp(parameter[0], "deformvertexes") && numparameters >= 2)
+ {
+ if (!strcasecmp(parameter[1], "autosprite") && numparameters == 2)
+ shader->textureflags |= Q3TEXTUREFLAG_AUTOSPRITE;
+ if (!strcasecmp(parameter[1], "autosprite2") && numparameters == 2)
+ shader->textureflags |= Q3TEXTUREFLAG_AUTOSPRITE2;
+ }
+ }
+ // identify if this is a blended terrain shader or similar
+ if (shader->numlayers)
+ {
+ shader->primarylayer = shader->layers + 0;
+ if ((shader->layers[1].blendfunc[0] == GL_SRC_ALPHA && shader->layers[1].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA) || shader->layers[1].alphatest)
+ {
+ // terrain blending or other effects
+ shader->backgroundlayer = shader->layers + 0;
+ shader->primarylayer = shader->layers + 1;
+ }
+ // now see if the lightmap came first, and if so choose the second texture instead
+ if (!strcasecmp(shader->primarylayer->texturename[0], "$lightmap"))
+ shader->primarylayer = shader->layers + 1;
}
}
+ Mem_Free(f);
}
+}
+
+q3shaderinfo_t *Mod_Q3BSP_LookupShader(const char *name)
+{
+ int i;
+ for (i = 0;i < Q3SHADER_MAXSHADERS;i++)
+ if (!strcasecmp(q3shaders_shaders[i].name, name))
+ return q3shaders_shaders + i;
+ return NULL;
+}
+
+static void Mod_Q3BSP_LoadTextures(lump_t *l)
+{
+ q3dtexture_t *in;
+ texture_t *out;
+ int i, count, c;
+
+ in = (q3dtexture_t *)(mod_base + l->fileofs);
+ if (l->filelen % sizeof(*in))
+ Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
+ count = l->filelen / sizeof(*in);
+ out = (texture_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
+
+ loadmodel->data_textures = out;
+ loadmodel->num_textures = count;
+
+ // parse the Q3 shader files
+ Mod_Q3BSP_LoadShaders();
c = 0;
- for (j = 0, out = loadmodel->data_textures;j < loadmodel->num_textures;j++, out++)
+ for (i = 0;i < count;i++, in++, out++)
{
- if (out->surfaceparms == -1)
+ q3shaderinfo_t *shader;
+ strlcpy (out->name, in->name, sizeof (out->name));
+ out->surfaceflags = LittleLong(in->surfaceflags);
+ out->supercontents = Mod_Q3BSP_SuperContentsFromNativeContents(loadmodel, LittleLong(in->contents));
+ shader = Mod_Q3BSP_LookupShader(out->name);
+ if (shader)
+ {
+ out->surfaceparms = shader->surfaceparms;
+ out->textureflags = shader->textureflags;
+ out->basematerialflags = 0;
+ if (shader->surfaceparms & Q3SURFACEPARM_SKY)
+ {
+ out->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
+ if (shader->skyboxname[0])
+ {
+ // quake3 seems to append a _ to the skybox name, so this must do so as well
+ dpsnprintf(loadmodel->brush.skybox, sizeof(loadmodel->brush.skybox), "%s_", shader->skyboxname);
+ }
+ }
+ else if ((out->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
+ out->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_LAVA)
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_SLIME)
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
+ else if (shader->surfaceparms & Q3SURFACEPARM_WATER)
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
+ else
+ out->basematerialflags |= MATERIALFLAG_WALL;
+ if (shader->layers[0].alphatest)
+ out->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ if (shader->textureflags & (Q3TEXTUREFLAG_TWOSIDED | Q3TEXTUREFLAG_AUTOSPRITE | Q3TEXTUREFLAG_AUTOSPRITE2))
+ out->basematerialflags |= MATERIALFLAG_NOSHADOW;
+ out->customblendfunc[0] = GL_ONE;
+ out->customblendfunc[1] = GL_ZERO;
+ if (shader->numlayers > 0)
+ {
+ out->customblendfunc[0] = shader->layers[0].blendfunc[0];
+ out->customblendfunc[1] = shader->layers[0].blendfunc[1];
+/*
+Q3 shader blendfuncs actually used in the game (* = supported by DP)
+* additive GL_ONE GL_ONE
+ additive weird GL_ONE GL_SRC_ALPHA
+ additive weird 2 GL_ONE GL_ONE_MINUS_SRC_ALPHA
+* alpha GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+ alpha inverse GL_ONE_MINUS_SRC_ALPHA GL_SRC_ALPHA
+ brighten GL_DST_COLOR GL_ONE
+ brighten GL_ONE GL_SRC_COLOR
+ brighten weird GL_DST_COLOR GL_ONE_MINUS_DST_ALPHA
+ brighten weird 2 GL_DST_COLOR GL_SRC_ALPHA
+* modulate GL_DST_COLOR GL_ZERO
+* modulate GL_ZERO GL_SRC_COLOR
+ modulate inverse GL_ZERO GL_ONE_MINUS_SRC_COLOR
+ modulate inverse alpha GL_ZERO GL_SRC_ALPHA
+ modulate weird inverse GL_ONE_MINUS_DST_COLOR GL_ZERO
+* modulate x2 GL_DST_COLOR GL_SRC_COLOR
+* no blend GL_ONE GL_ZERO
+ nothing GL_ZERO GL_ONE
+*/
+ // if not opaque, figure out what blendfunc to use
+ if (shader->layers[0].blendfunc[0] != GL_ONE || shader->layers[0].blendfunc[1] != GL_ZERO)
+ {
+ if (shader->layers[0].blendfunc[0] == GL_ONE && shader->layers[0].blendfunc[1] == GL_ONE)
+ out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE)
+ out->basematerialflags |= MATERIALFLAG_ADD | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ else if (shader->layers[0].blendfunc[0] == GL_SRC_ALPHA && shader->layers[0].blendfunc[1] == GL_ONE_MINUS_SRC_ALPHA)
+ out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ else
+ out->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
+ }
+ }
+ if (!shader->lighting)
+ out->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
+ if (shader->primarylayer && cls.state != ca_dedicated)
+ {
+ int j;
+ out->numskinframes = shader->primarylayer->numframes;
+ out->skinframerate = shader->primarylayer->framerate;
+ for (j = 0;j < shader->primarylayer->numframes;j++)
+ if (!Mod_LoadSkinFrame(&out->skinframes[j], shader->primarylayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->primarylayer->clampmap ? TEXF_CLAMP : 0), false, true))
+ Con_Printf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename[j], j, out->name);
+ }
+ if (shader->backgroundlayer && cls.state != ca_dedicated)
+ {
+ int j;
+ out->backgroundnumskinframes = shader->backgroundlayer->numframes;
+ out->backgroundskinframerate = shader->backgroundlayer->framerate;
+ for (j = 0;j < shader->backgroundlayer->numframes;j++)
+ if (!Mod_LoadSkinFrame(&out->backgroundskinframes[j], shader->backgroundlayer->texturename[j], ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP) | (shader->backgroundlayer->clampmap ? TEXF_CLAMP : 0), false, true))
+ Con_Printf("%s: could not load texture \"%s\" (frame %i) for shader \"%s\"\n", loadmodel->name, shader->backgroundlayer->texturename[j], j, out->name);
+ }
+ }
+ else
{
c++;
Con_DPrintf("%s: No shader found for texture \"%s\"\n", loadmodel->name, out->name);
out->surfaceparms = 0;
if (out->surfaceflags & Q3SURFACEFLAG_NODRAW)
- out->basematerialflags |= MATERIALFLAG_NODRAW;
+ out->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
else if (out->surfaceflags & Q3SURFACEFLAG_SKY)
- out->basematerialflags |= MATERIALFLAG_SKY;
+ out->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
else
out->basematerialflags |= MATERIALFLAG_WALL;
// these are defaults
//if (!strcmp(out->name, "caulk") || !strcmp(out->name, "common/caulk") || !strcmp(out->name, "textures/common/caulk")
// || !strcmp(out->name, "nodraw") || !strcmp(out->name, "common/nodraw") || !strcmp(out->name, "textures/common/nodraw"))
// out->surfaceparms |= Q3SURFACEPARM_NODRAW;
- //if (R_TextureHasAlpha(out->skin.base))
+ //if (R_TextureHasAlpha(out->skinframes[0].base))
// out->surfaceparms |= Q3SURFACEPARM_TRANS;
+ if (cls.state != ca_dedicated)
+ if (!Mod_LoadSkinFrame(&out->skinframes[0], out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
+ Con_Printf("%s: could not load texture for missing shader \"%s\"\n", loadmodel->name, out->name);
}
- if (cls.state != ca_dedicated)
- if (!Mod_LoadSkinFrame(&out->skin, out->name, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
- if (!Mod_LoadSkinFrame(&out->skin, out->firstpasstexturename, (((out->textureflags & Q3TEXTUREFLAG_NOMIPMAPS) || (out->surfaceparms & Q3SURFACEPARM_NOMIPMAPS)) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (out->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
- Con_Printf("%s: texture loading for shader \"%s\" failed (first layer \"%s\" not found either)\n", loadmodel->name, out->name, out->firstpasstexturename);
- // no animation
+ // init the animation variables
out->currentframe = out;
+ out->currentskinframe = &out->skinframes[0];
+ out->backgroundcurrentskinframe = &out->backgroundskinframes[0];
}
if (c)
Con_DPrintf("%s: %i textures missing shaders\n", loadmodel->name, c);
q3dbrush_t *in;
q3mbrush_t *out;
int i, j, n, c, count, maxplanes;
- mplane_t *planes;
+ colplanef_t *planes;
in = (q3dbrush_t *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
maxplanes = out->numbrushsides;
if (planes)
Mem_Free(planes);
- planes = (mplane_t *)Mem_Alloc(tempmempool, sizeof(mplane_t) * maxplanes);
+ planes = (colplanef_t *)Mem_Alloc(tempmempool, sizeof(colplanef_t) * maxplanes);
}
for (j = 0;j < out->numbrushsides;j++)
{
VectorCopy(out->firstbrushside[j].plane->normal, planes[j].normal);
planes[j].dist = out->firstbrushside[j].plane->dist;
+ planes[j].q3surfaceflags = out->firstbrushside[j].texture->surfaceflags;
+ planes[j].texture = out->firstbrushside[j].texture;
}
// make the colbrush from the planes
out->colbrushf = Collision_NewBrushFromPlanes(loadmodel->mempool, out->numbrushsides, planes, out->texture->supercontents);
if (l->filelen % sizeof(*in))
Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name);
loadmodel->brushq3.num_vertices = count = l->filelen / sizeof(*in);
- loadmodel->brushq3.data_vertex3f = (float *)Mem_Alloc(loadmodel->mempool, count * (sizeof(float) * (3 + 2 + 2 + 4)));
- loadmodel->brushq3.data_texcoordtexture2f = loadmodel->brushq3.data_vertex3f + count * 3;
+ loadmodel->brushq3.data_vertex3f = (float *)Mem_Alloc(loadmodel->mempool, count * (sizeof(float) * (3 + 3 + 2 + 2 + 4)));
+ loadmodel->brushq3.data_normal3f = loadmodel->brushq3.data_vertex3f + count * 3;
+ loadmodel->brushq3.data_texcoordtexture2f = loadmodel->brushq3.data_normal3f + count * 3;
loadmodel->brushq3.data_texcoordlightmap2f = loadmodel->brushq3.data_texcoordtexture2f + count * 2;
loadmodel->brushq3.data_color4f = loadmodel->brushq3.data_texcoordlightmap2f + count * 2;
loadmodel->brushq3.data_vertex3f[i * 3 + 0] = LittleFloat(in->origin3f[0]);
loadmodel->brushq3.data_vertex3f[i * 3 + 1] = LittleFloat(in->origin3f[1]);
loadmodel->brushq3.data_vertex3f[i * 3 + 2] = LittleFloat(in->origin3f[2]);
+ loadmodel->brushq3.data_normal3f[i * 3 + 0] = LittleFloat(in->normal3f[0]);
+ loadmodel->brushq3.data_normal3f[i * 3 + 1] = LittleFloat(in->normal3f[1]);
+ loadmodel->brushq3.data_normal3f[i * 3 + 2] = LittleFloat(in->normal3f[2]);
loadmodel->brushq3.data_texcoordtexture2f[i * 2 + 0] = LittleFloat(in->texcoord2f[0]);
loadmodel->brushq3.data_texcoordtexture2f[i * 2 + 1] = LittleFloat(in->texcoord2f[1]);
loadmodel->brushq3.data_texcoordlightmap2f[i * 2 + 0] = LittleFloat(in->lightmap2f[0]);
q3dlightmap_t *in;
rtexture_t **out;
int i, count;
+ unsigned char *c;
if (!l->filelen)
return;
loadmodel->brushq3.data_lightmaps = out;
loadmodel->brushq3.num_lightmaps = count;
- for (i = 0;i < count;i++, in++, out++)
- *out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
- // deluxemapped bsp files have an even number of lightmaps, and surfaces
+ // deluxemapped q3bsp files have an even number of lightmaps, and surfaces
// always index even numbered ones (0, 2, 4, ...), the odd numbered
// lightmaps are the deluxemaps (light direction textures), so if we
// encounter any odd numbered lightmaps it is not a deluxemapped bsp, it
// is also not a deluxemapped bsp if it has an odd number of lightmaps or
// less than 2
loadmodel->brushq3.deluxemapping = true;
- if ((count & 1) || count < 2)
+ loadmodel->brushq3.deluxemapping_modelspace = true;
+ if (count < 2 || (count & 1))
loadmodel->brushq3.deluxemapping = false;
+
+ // q3map2 sometimes (or always?) makes a second blank lightmap for no
+ // reason when only one lightmap is used, which can throw off the
+ // deluxemapping detection method, so check 2-lightmap bsp's specifically
+ // to see if the second lightmap is blank, if so it is not deluxemapped.
+ if (count == 2)
+ {
+ c = in[count - 1].rgb;
+ for (i = 0;i < 128*128*3;i++)
+ if (c[i])
+ break;
+ if (i == 128*128*3)
+ {
+ // all pixels in the unused lightmap were black...
+ loadmodel->brushq3.deluxemapping = false;
+ }
+ }
+
+ // further deluxemapping detection is done in Mod_Q3BSP_LoadFaces
+
+ for (i = 0;i < count;i++, in++, out++)
+ *out = R_LoadTexture2D(loadmodel->texturepool, va("lightmap%04i", i), 128, 128, in->rgb, TEXTYPE_RGB, TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
}
static void Mod_Q3BSP_LoadFaces(lump_t *l)
{
q3dface_t *in, *oldin;
msurface_t *out, *oldout;
- int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshnum, meshvertices, meshtriangles, numvertices, numtriangles;
+ int i, oldi, j, n, count, invalidelements, patchsize[2], finalwidth, finalheight, xtess, ytess, finalvertices, finaltriangles, firstvertex, firstelement, type, oldnumtriangles, oldnumtriangles2, meshvertices, meshtriangles, numvertices, numtriangles;
//int *originalelement3i;
//int *originalneighbor3i;
float *originalvertex3f;
//float *originalsvector3f;
//float *originaltvector3f;
- //float *originalnormal3f;
+ float *originalnormal3f;
float *originalcolor4f;
float *originaltexcoordtexture2f;
float *originaltexcoordlightmap2f;
float *v;
- surfmesh_t *mesh, *tempmeshlist[1024];
in = (q3dface_t *)(mod_base + l->fileofs);
if (l->filelen % sizeof(*in))
loadmodel->data_surfaces = out;
loadmodel->num_surfaces = count;
- i = 0;
- for (meshnum = 0;i < count;meshnum++)
- {
- oldi = i;
- oldin = in;
- oldout = out;
- meshvertices = 0;
- meshtriangles = 0;
- for (;i < count;i++, in++, out++)
- {
- // check face type first
- type = LittleLong(in->type);
- if (type != Q3FACETYPE_POLYGON
- && type != Q3FACETYPE_PATCH
- && type != Q3FACETYPE_MESH
- && type != Q3FACETYPE_FLARE)
+ // now that we have surfaces to look at, see if any of them index an odd numbered lightmap, if so this is not a deluxemapped bsp file
+ if (loadmodel->brushq3.deluxemapping)
+ {
+ for (i = 0;i < count;i++)
+ {
+ n = LittleLong(in[i].lightmapindex);
+ if (n >= 0 && ((n & 1) || n + 1 >= loadmodel->brushq3.num_lightmaps))
{
- Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type);
- continue;
+ loadmodel->brushq3.deluxemapping = false;
+ break;
}
+ }
+ }
+ Con_DPrintf("%s is %sdeluxemapped\n", loadmodel->name, loadmodel->brushq3.deluxemapping ? "" : "not ");
- n = LittleLong(in->textureindex);
- if (n < 0 || n >= loadmodel->num_textures)
- {
- Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->num_textures);
- continue;
- }
- out->texture = loadmodel->data_textures + n;
- n = LittleLong(in->effectindex);
- if (n < -1 || n >= loadmodel->brushq3.num_effects)
- {
- if (developer.integer >= 2)
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
- n = -1;
- }
- if (n == -1)
- out->effect = NULL;
+ i = 0;
+ oldi = i;
+ oldin = in;
+ oldout = out;
+ meshvertices = 0;
+ meshtriangles = 0;
+ for (;i < count;i++, in++, out++)
+ {
+ // check face type first
+ type = LittleLong(in->type);
+ if (type != Q3FACETYPE_POLYGON
+ && type != Q3FACETYPE_PATCH
+ && type != Q3FACETYPE_MESH
+ && type != Q3FACETYPE_FLARE)
+ {
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: unknown face type %i\n", i, type);
+ continue;
+ }
+
+ n = LittleLong(in->textureindex);
+ if (n < 0 || n >= loadmodel->num_textures)
+ {
+ Con_DPrintf("Mod_Q3BSP_LoadFaces: face #%i: invalid textureindex %i (%i textures)\n", i, n, loadmodel->num_textures);
+ continue;
+ }
+ out->texture = loadmodel->data_textures + n;
+ n = LittleLong(in->effectindex);
+ if (n < -1 || n >= loadmodel->brushq3.num_effects)
+ {
+ if (developer.integer >= 100)
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid effectindex %i (%i effects)\n", i, out->texture->name, n, loadmodel->brushq3.num_effects);
+ n = -1;
+ }
+ if (n == -1)
+ out->effect = NULL;
+ else
+ out->effect = loadmodel->brushq3.data_effects + n;
+ n = LittleLong(in->lightmapindex);
+ if (n >= loadmodel->brushq3.num_lightmaps)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
+ n = -1;
+ }
+ else if (n < 0)
+ n = -1;
+ if (n == -1)
+ {
+ out->lightmaptexture = NULL;
+ out->deluxemaptexture = r_texture_blanknormalmap;
+ }
+ else
+ {
+ out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+ if (loadmodel->brushq3.deluxemapping)
+ out->deluxemaptexture = loadmodel->brushq3.data_lightmaps[n+1];
else
- out->effect = loadmodel->brushq3.data_effects + n;
- n = LittleLong(in->lightmapindex);
- if (n >= loadmodel->brushq3.num_lightmaps)
+ out->deluxemaptexture = r_texture_blanknormalmap;
+ }
+
+ firstvertex = LittleLong(in->firstvertex);
+ numvertices = LittleLong(in->numvertices);
+ firstelement = LittleLong(in->firstelement);
+ numtriangles = LittleLong(in->numelements) / 3;
+ if (numtriangles * 3 != LittleLong(in->numelements))
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements));
+ continue;
+ }
+ if (firstvertex < 0 || firstvertex + numvertices > loadmodel->brushq3.num_vertices)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + numvertices, loadmodel->brushq3.num_vertices);
+ continue;
+ }
+ if (firstelement < 0 || firstelement + numtriangles * 3 > loadmodel->brushq3.num_triangles * 3)
+ {
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + numtriangles * 3, loadmodel->brushq3.num_triangles * 3);
+ continue;
+ }
+ switch(type)
+ {
+ case Q3FACETYPE_POLYGON:
+ case Q3FACETYPE_MESH:
+ // no processing necessary
+ break;
+ case Q3FACETYPE_PATCH:
+ patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
+ patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
+ if (numvertices != (patchsize[0] * patchsize[1]) || patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer))
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid lightmapindex %i (%i lightmaps)\n", i, out->texture->name, n, loadmodel->brushq3.num_lightmaps);
- n = -1;
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
+ continue;
}
- else if (n < 0)
- n = -1;
- if (n == -1)
- out->lightmaptexture = NULL;
- else
+ originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+ // convert patch to Q3FACETYPE_MESH
+ xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+ ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+ // bound to user settings
+ xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
+ ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
+ // bound to sanity settings
+ xtess = bound(1, xtess, 1024);
+ ytess = bound(1, ytess, 1024);
+ // bound to user limit on vertices
+ while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
{
- // deluxemapped q3bsp files have lightmaps and deluxemaps in
- // pairs, no odd numbers ever appear, so if we encounter an
- // odd lightmap index, it's not deluxemapped.
- if (n & 1)
- loadmodel->brushq3.deluxemapping = false;
- out->lightmaptexture = loadmodel->brushq3.data_lightmaps[n];
+ if (xtess > ytess)
+ xtess--;
+ else
+ ytess--;
}
+ finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+ finalheight = ((patchsize[1] - 1) * ytess) + 1;
+ numvertices = finalwidth * finalheight;
+ numtriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+ break;
+ case Q3FACETYPE_FLARE:
+ if (developer.integer >= 100)
+ Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
+ // don't render it
+ continue;
+ }
+ out->num_vertices = numvertices;
+ out->num_triangles = numtriangles;
+ meshvertices += out->num_vertices;
+ meshtriangles += out->num_triangles;
+ }
- firstvertex = LittleLong(in->firstvertex);
- numvertices = LittleLong(in->numvertices);
- firstelement = LittleLong(in->firstelement);
- numtriangles = LittleLong(in->numelements) / 3;
- if (numtriangles * 3 != LittleLong(in->numelements))
+ i = oldi;
+ in = oldin;
+ out = oldout;
+ Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, true, false);
+ meshvertices = 0;
+ meshtriangles = 0;
+ for (;i < count && meshvertices + out->num_vertices <= loadmodel->surfmesh.num_vertices;i++, in++, out++)
+ {
+ if (out->num_vertices < 3 || out->num_triangles < 1)
+ continue;
+
+ type = LittleLong(in->type);
+ firstvertex = LittleLong(in->firstvertex);
+ firstelement = LittleLong(in->firstelement);
+ out->num_firstvertex = meshvertices;
+ out->num_firsttriangle = meshtriangles;
+ switch(type)
+ {
+ case Q3FACETYPE_POLYGON:
+ case Q3FACETYPE_MESH:
+ // no processing necessary
+ for (j = 0;j < out->num_vertices;j++)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): numelements %i is not a multiple of 3\n", i, out->texture->name, LittleLong(in->numelements));
- continue;
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 0];
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 1];
+ (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 2];
+ (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 0];
+ (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 1];
+ (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_normal3f[(firstvertex + j) * 3 + 2];
+ (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 0];
+ (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 1];
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 0];
+ (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 1];
+ (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 0] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 0];
+ (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 1] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 1];
+ (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 2] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 2];
+ (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 3] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 3];
}
- if (firstvertex < 0 || firstvertex + numvertices > loadmodel->brushq3.num_vertices)
+ for (j = 0;j < out->num_triangles*3;j++)
+ (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = loadmodel->brushq3.data_element3i[firstelement + j] + out->num_firstvertex;
+ break;
+ case Q3FACETYPE_PATCH:
+ patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
+ patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
+ originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
+ originalnormal3f = loadmodel->brushq3.data_normal3f + firstvertex * 3;
+ originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
+ originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
+ originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
+ // convert patch to Q3FACETYPE_MESH
+ xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+ ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
+ // bound to user settings
+ xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
+ ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
+ // bound to sanity settings
+ xtess = bound(1, xtess, 1024);
+ ytess = bound(1, ytess, 1024);
+ // bound to user limit on vertices
+ while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid vertex range %i : %i (%i vertices)\n", i, out->texture->name, firstvertex, firstvertex + numvertices, loadmodel->brushq3.num_vertices);
- continue;
+ if (xtess > ytess)
+ xtess--;
+ else
+ ytess--;
}
- if (firstelement < 0 || firstelement + numtriangles * 3 > loadmodel->brushq3.num_triangles * 3)
+ finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+ finalheight = ((patchsize[1] - 1) * ytess) + 1;
+ finalvertices = finalwidth * finalheight;
+ finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+ type = Q3FACETYPE_MESH;
+ // generate geometry
+ // (note: normals are skipped because they get recalculated)
+ Q3PatchTesselateFloat(3, sizeof(float[3]), (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+ Q3PatchTesselateFloat(3, sizeof(float[3]), (loadmodel->surfmesh.data_normal3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalnormal3f, xtess, ytess);
+ Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordtexture2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess);
+ Q3PatchTesselateFloat(2, sizeof(float[2]), (loadmodel->surfmesh.data_texcoordlightmap2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess);
+ Q3PatchTesselateFloat(4, sizeof(float[4]), (loadmodel->surfmesh.data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
+ Q3PatchTriangleElements((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex);
+ out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle), loadmodel->surfmesh.data_vertex3f);
+ if (developer.integer >= 100)
{
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid element range %i : %i (%i elements)\n", i, out->texture->name, firstelement, firstelement + numtriangles * 3, loadmodel->brushq3.num_triangles * 3);
- continue;
+ if (out->num_triangles < finaltriangles)
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
+ else
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles);
}
- switch(type)
+ // q3map does not put in collision brushes for curves... ugh
+ // build the lower quality collision geometry
+ xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
+ ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
+ // bound to user settings
+ xtess = bound(r_subdivisions_collision_mintess.integer, xtess, r_subdivisions_collision_maxtess.integer);
+ ytess = bound(r_subdivisions_collision_mintess.integer, ytess, r_subdivisions_collision_maxtess.integer);
+ // bound to sanity settings
+ xtess = bound(1, xtess, 1024);
+ ytess = bound(1, ytess, 1024);
+ // bound to user limit on vertices
+ while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
{
- case Q3FACETYPE_POLYGON:
- case Q3FACETYPE_MESH:
- // no processing necessary
- break;
- case Q3FACETYPE_PATCH:
- patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
- patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
- if (numvertices != (patchsize[0] * patchsize[1]) || patchsize[0] < 3 || patchsize[1] < 3 || !(patchsize[0] & 1) || !(patchsize[1] & 1) || patchsize[0] * patchsize[1] >= min(r_subdivisions_maxvertices.integer, r_subdivisions_collision_maxvertices.integer))
- {
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): invalid patchsize %ix%i\n", i, out->texture->name, patchsize[0], patchsize[1]);
- continue;
- }
- originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
- // convert patch to Q3FACETYPE_MESH
- xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
- ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
- // bound to user settings
- xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
- ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
- // bound to sanity settings
- xtess = bound(1, xtess, 1024);
- ytess = bound(1, ytess, 1024);
- // bound to user limit on vertices
- while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
- {
- if (xtess > ytess)
- xtess--;
- else
- ytess--;
- }
- finalwidth = ((patchsize[0] - 1) * xtess) + 1;
- finalheight = ((patchsize[1] - 1) * ytess) + 1;
- numvertices = finalwidth * finalheight;
- numtriangles = (finalwidth - 1) * (finalheight - 1) * 2;
- break;
- case Q3FACETYPE_FLARE:
- if (developer.integer >= 2)
- Con_Printf("Mod_Q3BSP_LoadFaces: face #%i (texture \"%s\"): Q3FACETYPE_FLARE not supported (yet)\n", i, out->texture->name);
- // don't render it
- continue;
+ if (xtess > ytess)
+ xtess--;
+ else
+ ytess--;
}
- out->num_vertices = numvertices;
- out->num_triangles = numtriangles;
- if (meshvertices + out->num_vertices > 65536)
- break;
- meshvertices += out->num_vertices;
- meshtriangles += out->num_triangles;
+ finalwidth = ((patchsize[0] - 1) * xtess) + 1;
+ finalheight = ((patchsize[1] - 1) * ytess) + 1;
+ finalvertices = finalwidth * finalheight;
+ finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
+
+ out->data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
+ out->data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
+ out->num_collisionvertices = finalvertices;
+ out->num_collisiontriangles = finaltriangles;
+ Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
+ Q3PatchTriangleElements(out->data_collisionelement3i, finalwidth, finalheight, 0);
+
+ //Mod_SnapVertices(3, out->num_vertices, (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), 0.25);
+ Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
+
+ oldnumtriangles = out->num_triangles;
+ oldnumtriangles2 = out->num_collisiontriangles;
+ out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
+ if (developer.integer >= 100)
+ Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
+ break;
+ default:
+ break;
}
-
- i = oldi;
- in = oldin;
- out = oldout;
- mesh = tempmeshlist[meshnum] = Mod_AllocSurfMesh(loadmodel->mempool, meshvertices, meshtriangles, false, true, false);
- meshvertices = 0;
- meshtriangles = 0;
- for (;i < count && meshvertices + out->num_vertices <= mesh->num_vertices;i++, in++, out++)
+ meshvertices += out->num_vertices;
+ meshtriangles += out->num_triangles;
+ for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++)
+ if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
+ invalidelements++;
+ if (invalidelements)
{
- if (out->num_vertices < 3 || out->num_triangles < 1)
- continue;
-
- type = LittleLong(in->type);
- firstvertex = LittleLong(in->firstvertex);
- firstelement = LittleLong(in->firstelement);
- out->groupmesh = mesh;
- out->num_firstvertex = meshvertices;
- out->num_firsttriangle = meshtriangles;
- switch(type)
+ Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3);
+ for (j = 0;j < out->num_triangles * 3;j++)
{
- case Q3FACETYPE_POLYGON:
- case Q3FACETYPE_MESH:
- // no processing necessary
- for (j = 0;j < out->num_vertices;j++)
- {
- (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 0] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 0];
- (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 1] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 1];
- (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex)[j * 3 + 2] = loadmodel->brushq3.data_vertex3f[(firstvertex + j) * 3 + 2];
- (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 0];
- (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordtexture2f[(firstvertex + j) * 2 + 1];
- (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 0] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 0];
- (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex)[j * 2 + 1] = loadmodel->brushq3.data_texcoordlightmap2f[(firstvertex + j) * 2 + 1];
- (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 0] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 0];
- (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 1] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 1];
- (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 2] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 2];
- (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex)[j * 4 + 3] = loadmodel->brushq3.data_color4f[(firstvertex + j) * 4 + 3];
- }
- for (j = 0;j < out->num_triangles*3;j++)
- (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] = loadmodel->brushq3.data_element3i[firstelement + j] + out->num_firstvertex;
- break;
- case Q3FACETYPE_PATCH:
- patchsize[0] = LittleLong(in->specific.patch.patchsize[0]);
- patchsize[1] = LittleLong(in->specific.patch.patchsize[1]);
- originalvertex3f = loadmodel->brushq3.data_vertex3f + firstvertex * 3;
- originaltexcoordtexture2f = loadmodel->brushq3.data_texcoordtexture2f + firstvertex * 2;
- originaltexcoordlightmap2f = loadmodel->brushq3.data_texcoordlightmap2f + firstvertex * 2;
- originalcolor4f = loadmodel->brushq3.data_color4f + firstvertex * 4;
- // convert patch to Q3FACETYPE_MESH
- xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
- ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_tolerance.value);
- // bound to user settings
- xtess = bound(r_subdivisions_mintess.integer, xtess, r_subdivisions_maxtess.integer);
- ytess = bound(r_subdivisions_mintess.integer, ytess, r_subdivisions_maxtess.integer);
- // bound to sanity settings
- xtess = bound(1, xtess, 1024);
- ytess = bound(1, ytess, 1024);
- // bound to user limit on vertices
- while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_maxvertices.integer, 262144))
- {
- if (xtess > ytess)
- xtess--;
- else
- ytess--;
- }
- finalwidth = ((patchsize[0] - 1) * xtess) + 1;
- finalheight = ((patchsize[1] - 1) * ytess) + 1;
- finalvertices = finalwidth * finalheight;
- finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
- type = Q3FACETYPE_MESH;
- // generate geometry
- // (note: normals are skipped because they get recalculated)
- Q3PatchTesselateFloat(3, sizeof(float[3]), (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
- Q3PatchTesselateFloat(2, sizeof(float[2]), (out->groupmesh->data_texcoordtexture2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordtexture2f, xtess, ytess);
- Q3PatchTesselateFloat(2, sizeof(float[2]), (out->groupmesh->data_texcoordlightmap2f + 2 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[2]), originaltexcoordlightmap2f, xtess, ytess);
- Q3PatchTesselateFloat(4, sizeof(float[4]), (out->groupmesh->data_lightmapcolor4f + 4 * out->num_firstvertex), patchsize[0], patchsize[1], sizeof(float[4]), originalcolor4f, xtess, ytess);
- Q3PatchTriangleElements((out->groupmesh->data_element3i + 3 * out->num_firsttriangle), finalwidth, finalheight, out->num_firstvertex);
- out->num_triangles = Mod_RemoveDegenerateTriangles(out->num_triangles, (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), out->groupmesh->data_vertex3f);
- if (developer.integer >= 2)
- {
- if (out->num_triangles < finaltriangles)
- Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles, %i degenerate triangles removed (leaving %i)\n", patchsize[0], patchsize[1], out->num_vertices, finaltriangles, finaltriangles - out->num_triangles, out->num_triangles);
- else
- Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve subdivided to %i vertices / %i triangles\n", patchsize[0], patchsize[1], out->num_vertices, out->num_triangles);
- }
- // q3map does not put in collision brushes for curves... ugh
- // build the lower quality collision geometry
- xtess = Q3PatchTesselationOnX(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
- ytess = Q3PatchTesselationOnY(patchsize[0], patchsize[1], 3, originalvertex3f, r_subdivisions_collision_tolerance.value);
- // bound to user settings
- xtess = bound(r_subdivisions_collision_mintess.integer, xtess, r_subdivisions_collision_maxtess.integer);
- ytess = bound(r_subdivisions_collision_mintess.integer, ytess, r_subdivisions_collision_maxtess.integer);
- // bound to sanity settings
- xtess = bound(1, xtess, 1024);
- ytess = bound(1, ytess, 1024);
- // bound to user limit on vertices
- while ((xtess > 1 || ytess > 1) && (((patchsize[0] - 1) * xtess) + 1) * (((patchsize[1] - 1) * ytess) + 1) > min(r_subdivisions_collision_maxvertices.integer, 262144))
- {
- if (xtess > ytess)
- xtess--;
- else
- ytess--;
- }
- finalwidth = ((patchsize[0] - 1) * xtess) + 1;
- finalheight = ((patchsize[1] - 1) * ytess) + 1;
- finalvertices = finalwidth * finalheight;
- finaltriangles = (finalwidth - 1) * (finalheight - 1) * 2;
-
- out->data_collisionvertex3f = (float *)Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * finalvertices);
- out->data_collisionelement3i = (int *)Mem_Alloc(loadmodel->mempool, sizeof(int[3]) * finaltriangles);
- out->num_collisionvertices = finalvertices;
- out->num_collisiontriangles = finaltriangles;
- Q3PatchTesselateFloat(3, sizeof(float[3]), out->data_collisionvertex3f, patchsize[0], patchsize[1], sizeof(float[3]), originalvertex3f, xtess, ytess);
- Q3PatchTriangleElements(out->data_collisionelement3i, finalwidth, finalheight, 0);
-
- //Mod_SnapVertices(3, out->num_vertices, (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), 0.25);
- Mod_SnapVertices(3, out->num_collisionvertices, out->data_collisionvertex3f, 1);
-
- oldnumtriangles = out->num_triangles;
- oldnumtriangles2 = out->num_collisiontriangles;
- out->num_collisiontriangles = Mod_RemoveDegenerateTriangles(out->num_collisiontriangles, out->data_collisionelement3i, out->data_collisionelement3i, out->data_collisionvertex3f);
- if (developer.integer)
- Con_Printf("Mod_Q3BSP_LoadFaces: %ix%i curve became %i:%i vertices / %i:%i triangles (%i:%i degenerate)\n", patchsize[0], patchsize[1], out->num_vertices, out->num_collisionvertices, oldnumtriangles, oldnumtriangles2, oldnumtriangles - out->num_triangles, oldnumtriangles2 - out->num_collisiontriangles);
- break;
- default:
- break;
- }
- meshvertices += out->num_vertices;
- meshtriangles += out->num_triangles;
- for (j = 0, invalidelements = 0;j < out->num_triangles * 3;j++)
- if ((out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
- invalidelements++;
- if (invalidelements)
- {
- Con_Printf("Mod_Q3BSP_LoadFaces: Warning: face #%i has %i invalid elements, type = %i, texture->name = \"%s\", texture->surfaceflags = %i, firstvertex = %i, numvertices = %i, firstelement = %i, numelements = %i, elements list:\n", i, invalidelements, type, out->texture->name, out->texture->surfaceflags, firstvertex, out->num_vertices, firstelement, out->num_triangles * 3);
- for (j = 0;j < out->num_triangles * 3;j++)
- {
- Con_Printf(" %i", (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] - out->num_firstvertex);
- if ((out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
- (out->groupmesh->data_element3i + 3 * out->num_firsttriangle)[j] = out->num_firstvertex;
- }
- Con_Print("\n");
+ Con_Printf(" %i", (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] - out->num_firstvertex);
+ if ((loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] < out->num_firstvertex || (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] >= out->num_firstvertex + out->num_vertices)
+ (loadmodel->surfmesh.data_element3i + 3 * out->num_firsttriangle)[j] = out->num_firstvertex;
}
- // for per pixel lighting
- Mod_BuildTextureVectorsAndNormals(out->num_firstvertex, out->num_vertices, out->num_triangles, out->groupmesh->data_vertex3f, out->groupmesh->data_texcoordtexture2f, (out->groupmesh->data_element3i + 3 * out->num_firsttriangle), out->groupmesh->data_svector3f, out->groupmesh->data_tvector3f, out->groupmesh->data_normal3f, true);
- // calculate a bounding box
- VectorClear(out->mins);
- VectorClear(out->maxs);
- if (out->num_vertices)
+ Con_Print("\n");
+ }
+ // calculate a bounding box
+ VectorClear(out->mins);
+ VectorClear(out->maxs);
+ if (out->num_vertices)
+ {
+ VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->mins);
+ VectorCopy((loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex), out->maxs);
+ for (j = 1, v = (loadmodel->surfmesh.data_vertex3f + 3 * out->num_firstvertex) + 3;j < out->num_vertices;j++, v += 3)
{
- VectorCopy((out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), out->mins);
- VectorCopy((out->groupmesh->data_vertex3f + 3 * out->num_firstvertex), out->maxs);
- for (j = 1, v = (out->groupmesh->data_vertex3f + 3 * out->num_firstvertex) + 3;j < out->num_vertices;j++, v += 3)
- {
- out->mins[0] = min(out->mins[0], v[0]);
- out->maxs[0] = max(out->maxs[0], v[0]);
- out->mins[1] = min(out->mins[1], v[1]);
- out->maxs[1] = max(out->maxs[1], v[1]);
- out->mins[2] = min(out->mins[2], v[2]);
- out->maxs[2] = max(out->maxs[2], v[2]);
- }
- out->mins[0] -= 1.0f;
- out->mins[1] -= 1.0f;
- out->mins[2] -= 1.0f;
- out->maxs[0] += 1.0f;
- out->maxs[1] += 1.0f;
- out->maxs[2] += 1.0f;
+ out->mins[0] = min(out->mins[0], v[0]);
+ out->maxs[0] = max(out->maxs[0], v[0]);
+ out->mins[1] = min(out->mins[1], v[1]);
+ out->maxs[1] = max(out->maxs[1], v[1]);
+ out->mins[2] = min(out->mins[2], v[2]);
+ out->maxs[2] = max(out->maxs[2], v[2]);
}
- // set lightmap styles for consistency with q1bsp
- //out->lightmapinfo->styles[0] = 0;
- //out->lightmapinfo->styles[1] = 255;
- //out->lightmapinfo->styles[2] = 255;
- //out->lightmapinfo->styles[3] = 255;
+ out->mins[0] -= 1.0f;
+ out->mins[1] -= 1.0f;
+ out->mins[2] -= 1.0f;
+ out->maxs[0] += 1.0f;
+ out->maxs[1] += 1.0f;
+ out->maxs[2] += 1.0f;
}
+ // set lightmap styles for consistency with q1bsp
+ //out->lightmapinfo->styles[0] = 0;
+ //out->lightmapinfo->styles[1] = 255;
+ //out->lightmapinfo->styles[2] = 255;
+ //out->lightmapinfo->styles[3] = 255;
}
- // now store the completed list of meshes
- loadmodel->nummeshes = meshnum;
- if (loadmodel->nummeshes)
- {
- loadmodel->meshlist = (surfmesh_t **)Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t *) * loadmodel->nummeshes);
- memcpy(loadmodel->meshlist, tempmeshlist, sizeof(surfmesh_t *) * loadmodel->nummeshes);
- }
+ // for per pixel lighting
+ Mod_BuildTextureVectorsFromNormals(0, loadmodel->surfmesh.num_vertices, loadmodel->surfmesh.num_triangles, loadmodel->surfmesh.data_vertex3f, loadmodel->surfmesh.data_texcoordtexture2f, loadmodel->surfmesh.data_normal3f, loadmodel->surfmesh.data_element3i, loadmodel->surfmesh.data_svector3f, loadmodel->surfmesh.data_tvector3f, true);
// free the no longer needed vertex data
loadmodel->brushq3.num_vertices = 0;
- Mem_Free(loadmodel->brushq3.data_vertex3f);
+ if (loadmodel->brushq3.data_vertex3f)
+ Mem_Free(loadmodel->brushq3.data_vertex3f);
loadmodel->brushq3.data_vertex3f = NULL;
+ loadmodel->brushq3.data_normal3f = NULL;
loadmodel->brushq3.data_texcoordtexture2f = NULL;
loadmodel->brushq3.data_texcoordlightmap2f = NULL;
loadmodel->brushq3.data_color4f = NULL;
// free the no longer needed triangle data
loadmodel->brushq3.num_triangles = 0;
- Mem_Free(loadmodel->brushq3.data_element3i);
+ if (loadmodel->brushq3.data_element3i)
+ Mem_Free(loadmodel->brushq3.data_element3i);
loadmodel->brushq3.data_element3i = NULL;
}
loadmodel->brushq3.num_lightgrid_scale[0] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[0];
loadmodel->brushq3.num_lightgrid_scale[1] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[1];
loadmodel->brushq3.num_lightgrid_scale[2] = 1.0f / loadmodel->brushq3.num_lightgrid_cellsize[2];
- loadmodel->brushq3.num_lightgrid_imins[0] = ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
- loadmodel->brushq3.num_lightgrid_imins[1] = ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
- loadmodel->brushq3.num_lightgrid_imins[2] = ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
- loadmodel->brushq3.num_lightgrid_imaxs[0] = floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
- loadmodel->brushq3.num_lightgrid_imaxs[1] = floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
- loadmodel->brushq3.num_lightgrid_imaxs[2] = floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+ loadmodel->brushq3.num_lightgrid_imins[0] = (int)ceil(loadmodel->brushq3.data_models->mins[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+ loadmodel->brushq3.num_lightgrid_imins[1] = (int)ceil(loadmodel->brushq3.data_models->mins[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+ loadmodel->brushq3.num_lightgrid_imins[2] = (int)ceil(loadmodel->brushq3.data_models->mins[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
+ loadmodel->brushq3.num_lightgrid_imaxs[0] = (int)floor(loadmodel->brushq3.data_models->maxs[0] * loadmodel->brushq3.num_lightgrid_scale[0]);
+ loadmodel->brushq3.num_lightgrid_imaxs[1] = (int)floor(loadmodel->brushq3.data_models->maxs[1] * loadmodel->brushq3.num_lightgrid_scale[1]);
+ loadmodel->brushq3.num_lightgrid_imaxs[2] = (int)floor(loadmodel->brushq3.data_models->maxs[2] * loadmodel->brushq3.num_lightgrid_scale[2]);
loadmodel->brushq3.num_lightgrid_isize[0] = loadmodel->brushq3.num_lightgrid_imaxs[0] - loadmodel->brushq3.num_lightgrid_imins[0] + 1;
loadmodel->brushq3.num_lightgrid_isize[1] = loadmodel->brushq3.num_lightgrid_imaxs[1] - loadmodel->brushq3.num_lightgrid_imins[1] + 1;
loadmodel->brushq3.num_lightgrid_isize[2] = loadmodel->brushq3.num_lightgrid_imaxs[2] - loadmodel->brushq3.num_lightgrid_imins[2] + 1;
if (l->filelen)
{
if (l->filelen < count * (int)sizeof(*in))
- Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, count * sizeof(*in), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]);
+ Host_Error("Mod_Q3BSP_LoadLightGrid: invalid lightgrid lump size %i bytes, should be %i bytes (%ix%ix%i)", l->filelen, (int)(count * sizeof(*in)), loadmodel->brushq3.num_lightgrid_dimensions[0], loadmodel->brushq3.num_lightgrid_dimensions[1], loadmodel->brushq3.num_lightgrid_dimensions[2]);
if (l->filelen != count * (int)sizeof(*in))
- Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i", count * sizeof(*in), l->filelen);
+ Con_Printf("Mod_Q3BSP_LoadLightGrid: Warning: calculated lightgrid size %i bytes does not match lump size %i\n", (int)(count * sizeof(*in)), l->filelen);
out = (q3dlightgrid_t *)Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
loadmodel->brushq3.data_lightgrid = out;
loadmodel->brushq3.num_lightgrid = count;
Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8", loadmodel->brush.num_pvsclusterbytes, loadmodel->brush.num_pvsclusters);
totalchains = loadmodel->brush.num_pvsclusterbytes * loadmodel->brush.num_pvsclusters;
if (l->filelen < totalchains + (int)sizeof(*in))
- Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)", loadmodel->brush.num_pvsclusters, loadmodel->brush.num_pvsclusterbytes, totalchains + sizeof(*in), l->filelen);
+ Host_Error("Mod_Q3BSP_LoadPVS: lump too small ((numclusters = %i) * (chainlength = %i) + sizeof(q3dpvs_t) == %i bytes, lump is %i bytes)", loadmodel->brush.num_pvsclusters, loadmodel->brush.num_pvsclusterbytes, (int)(totalchains + sizeof(*in)), l->filelen);
loadmodel->brush.data_pvsclusters = (unsigned char *)Mem_Alloc(loadmodel->mempool, totalchains);
memcpy(loadmodel->brush.data_pvsclusters, (unsigned char *)(in + 1), totalchains);
static void Mod_Q3BSP_LightPoint(model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
{
int i, j, k, index[3];
- float transformed[3], blend1, blend2, blend, yaw, pitch, sinpitch;
+ float transformed[3], blend1, blend2, blend, yaw, pitch, sinpitch, stylescale;
q3dlightgrid_t *a, *s;
+
+ // scale lighting by lightstyle[0] so that darkmode in dpmod works properly
+ stylescale = r_refdef.lightstylevalue[0] * (1.0f / 264.0f);
+
if (!model->brushq3.num_lightgrid)
{
- ambientcolor[0] = 1;
- ambientcolor[1] = 1;
- ambientcolor[2] = 1;
+ ambientcolor[0] = stylescale;
+ ambientcolor[1] = stylescale;
+ ambientcolor[2] = stylescale;
return;
}
+
Matrix4x4_Transform(&model->brushq3.num_lightgrid_indexfromworld, p, transformed);
//Matrix4x4_Print(&model->brushq3.num_lightgrid_indexfromworld);
//Con_Printf("%f %f %f transformed %f %f %f clamped ", p[0], p[1], p[2], transformed[0], transformed[1], transformed[2]);
index[1] = (int)floor(transformed[1]);
index[2] = (int)floor(transformed[2]);
//Con_Printf("%f %f %f index %i %i %i:\n", transformed[0], transformed[1], transformed[2], index[0], index[1], index[2]);
+
// now lerp the values
VectorClear(diffusenormal);
a = &model->brushq3.data_lightgrid[(index[2] * model->brushq3.num_lightgrid_isize[1] + index[1]) * model->brushq3.num_lightgrid_isize[0] + index[0]];
continue;
for (i = 0;i < 2;i++)
{
- blend = blend2 * (i ? (transformed[0] - index[0]) : (1 - (transformed[0] - index[0])));
+ blend = blend2 * (i ? (transformed[0] - index[0]) : (1 - (transformed[0] - index[0]))) * stylescale;
if (blend < 0.001f || index[0] + i >= model->brushq3.num_lightgrid_isize[0])
continue;
s = a + (k * model->brushq3.num_lightgrid_isize[1] + j) * model->brushq3.num_lightgrid_isize[0] + i;
}
}
}
+
+ // normalize the light direction before turning
VectorNormalize(diffusenormal);
//Con_Printf("result: ambient %f %f %f diffuse %f %f %f diffusenormal %f %f %f\n", ambientcolor[0], ambientcolor[1], ambientcolor[2], diffusecolor[0], diffusecolor[1], diffusecolor[2], diffusenormal[0], diffusenormal[1], diffusenormal[2]);
}
if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
{
surface->collisionmarkframe = markframe;
- Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceLineTriangleMeshFloat(trace, linestart, lineend, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
}
}
if (surface->num_collisiontriangles && surface->collisionmarkframe != markframe && BoxesOverlap(nodesegmentmins, nodesegmentmaxs, surface->mins, surface->maxs))
{
surface->collisionmarkframe = markframe;
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
}
}
if (mod_q3bsp_curves_collisions.integer)
for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
if (surface->num_collisiontriangles)
- Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceLineTriangleMeshFloat(trace, start, end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
else
Mod_Q3BSP_TraceLine_RecursiveBSPNode(trace, model, model->brush.data_nodes, start, end, 0, 1, start, end, ++markframe, segmentmins, segmentmaxs);
VectorAdd(start, boxmaxs, boxstartmaxs);
VectorAdd(end, boxmins, boxendmins);
VectorAdd(end, boxmaxs, boxendmaxs);
- thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs);
- thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs);
+ thisbrush_start = Collision_BrushForBox(&identitymatrix, boxstartmins, boxstartmaxs, 0, 0, NULL);
+ thisbrush_end = Collision_BrushForBox(&identitymatrix, boxendmins, boxendmaxs, 0, 0, NULL);
if (model->brush.submodel)
{
for (i = 0, brush = model->brush.data_brushes + model->firstmodelbrush;i < model->nummodelbrushes;i++, brush++)
if (mod_q3bsp_curves_collisions.integer)
for (i = 0, surface = model->data_surfaces + model->firstmodelsurface;i < model->nummodelsurfaces;i++, surface++)
if (surface->num_collisiontriangles)
- Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, segmentmins, segmentmaxs);
+ Collision_TraceBrushTriangleMeshFloat(trace, thisbrush_start, thisbrush_end, surface->num_collisiontriangles, surface->data_collisionelement3i, surface->data_collisionvertex3f, surface->texture->supercontents, surface->texture->surfaceflags, surface->texture, segmentmins, segmentmaxs);
}
else
Mod_Q3BSP_TraceBrush_RecursiveBSPNode(trace, model, model->brush.data_nodes, thisbrush_start, thisbrush_end, ++markframe, segmentmins, segmentmaxs);
// the MakePortals code works fine on the q3bsp data as well
Mod_Q1BSP_MakePortals();
+ // FIXME: shader alpha should replace r_wateralpha support in q3bsp
+ loadmodel->brush.supportwateralpha = true;
+
// make a single combined shadow mesh to allow optimized shadow volume creation
numshadowmeshtriangles = 0;
for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
}
loadmodel->brush.shadowmesh = Mod_ShadowMesh_Begin(loadmodel->mempool, numshadowmeshtriangles * 3, numshadowmeshtriangles, NULL, NULL, NULL, false, false, true);
for (j = 0, surface = loadmodel->data_surfaces;j < loadmodel->num_surfaces;j++, surface++)
- if (surface->groupmesh)
- Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, surface->groupmesh->data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (surface->groupmesh->data_element3i + 3 * surface->num_firsttriangle));
+ if (surface->num_triangles > 0)
+ Mod_ShadowMesh_AddMesh(loadmodel->mempool, loadmodel->brush.shadowmesh, NULL, NULL, NULL, loadmodel->surfmesh.data_vertex3f, NULL, NULL, NULL, NULL, surface->num_triangles, (loadmodel->surfmesh.data_element3i + 3 * surface->num_firsttriangle));
loadmodel->brush.shadowmesh = Mod_ShadowMesh_Finish(loadmodel->mempool, loadmodel->brush.shadowmesh, false, true);
Mod_BuildTriangleNeighbors(loadmodel->brush.shadowmesh->neighbor3i, loadmodel->brush.shadowmesh->element3i, loadmodel->brush.shadowmesh->numtriangles);
sprintf(name, "*%i", i);
mod = Mod_FindName(name);
*mod = *loadmodel;
- strcpy(mod->name, name);
+ strlcpy(mod->name, name, sizeof(mod->name));
// textures and memory belong to the main model
mod->texturepool = NULL;
mod->mempool = NULL;
break;
if (j < mod->nummodelsurfaces)
mod->DrawSky = R_Q1BSP_DrawSky;
+ else
+ mod->DrawSky = NULL;
}
}