#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
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
#endif
}
+static int Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(mnode_t *node, double p1[3], double p2[3])
+{
+ double t1, t2;
+ double midf, mid[3];
+ int ret, side;
+
+ // check for empty
+ while (node->plane)
+ {
+ // find the point distances
+ mplane_t *plane = node->plane;
+ if (plane->type < 3)
+ {
+ t1 = p1[plane->type] - plane->dist;
+ t2 = p2[plane->type] - plane->dist;
+ }
+ else
+ {
+ t1 = DotProduct (plane->normal, p1) - plane->dist;
+ t2 = DotProduct (plane->normal, p2) - plane->dist;
+ }
+
+ if (t1 < 0)
+ {
+ if (t2 < 0)
+ {
+ node = node->children[1];
+ continue;
+ }
+ side = 1;
+ }
+ else
+ {
+ if (t2 >= 0)
+ {
+ node = node->children[0];
+ continue;
+ }
+ side = 0;
+ }
+
+ midf = t1 / (t1 - t2);
+ VectorLerp(p1, midf, p2, mid);
+
+ // recurse both sides, front side first
+ // return 2 if empty is followed by solid (hit something)
+ // do not return 2 if both are solid or both empty,
+ // or if start is solid and end is empty
+ // as these degenerate cases usually indicate the eye is in solid and
+ // should see the target point anyway
+ ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ], p1, mid);
+ if (ret != 0)
+ return ret;
+ ret = Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(node->children[side ^ 1], mid, p2);
+ if (ret != 1)
+ return ret;
+ return 2;
+ }
+ return ((mleaf_t *)node)->clusterindex < 0;
+}
+
+static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end)
+{
+ // this function currently only supports same size start and end
+ double tracestart[3], traceend[3];
+ VectorCopy(start, tracestart);
+ VectorCopy(end, traceend);
+ return Mod_Q1BSP_TraceLineOfSight_RecursiveNodeCheck(model->brush.data_nodes, tracestart, traceend) != 2;
+}
+
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;
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] + 0.125, p[2] - 65536);
- VectorSet(diffusenormal, 0, 0, -1);
+ // 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;
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->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
tx->supercontents = mod_q1bsp_texture_water.supercontents;
tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
}
}
else
{
- if (!Mod_LoadSkinFrame(&tx->skin, 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->skin, gamemode == GAME_TENEBRAE ? tx->name : va("textures/%s", 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, 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;
}
}
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 = mod_q1bsp_texture_lava.supercontents;
tx->supercontents = mod_q1bsp_texture_water.supercontents;
tx->surfaceflags = mod_q1bsp_texture_water.surfaceflags;
}
- tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES;
+ tx->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_NOSHADOW;
}
else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
{
tx->supercontents = mod_q1bsp_texture_sky.supercontents;
tx->surfaceflags = mod_q1bsp_texture_sky.surfaceflags;
- tx->basematerialflags |= MATERIALFLAG_SKY;
+ tx->basematerialflags |= MATERIALFLAG_SKY | MATERIALFLAG_NOSHADOW;
}
else
{
tx->surfaceflags = mod_q1bsp_texture_solid.surfaceflags;
tx->basematerialflags |= MATERIALFLAG_WALL;
}
- if (tx->skin.fog)
- tx->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | 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;
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", filesize, 8 + l->filelen * 3);
+ Con_Printf("Corrupt .lit file (file size %i bytes, should be %i bytes), ignoring\n", (int) filesize, (int) (8 + l->filelen * 3));
if (data)
{
Mem_Free(data);
node->parent = parent;
if (node->plane)
{
+ // this is a node, recurse to children
Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[0], node);
Mod_Q1BSP_LoadNodes_RecursiveSetParent(node->children[1], node);
+ // combine supercontents of children
+ node->combinedsupercontents = node->children[0]->combinedsupercontents | node->children[1]->combinedsupercontents;
+ }
+ else
+ {
+ int j;
+ mleaf_t *leaf = (mleaf_t *)node;
+ // if this is a leaf, calculate supercontents mask from all collidable
+ // primitives in the leaf (brushes and collision surfaces)
+ // also flag if the leaf contains any collision surfaces
+ leaf->combinedsupercontents = 0;
+ // combine the supercontents values of all brushes in this leaf
+ for (j = 0;j < leaf->numleafbrushes;j++)
+ leaf->combinedsupercontents |= loadmodel->brush.data_brushes[leaf->firstleafbrush[j]].texture->supercontents;
+ // check if this leaf contains any collision surfaces (q3 patches)
+ for (j = 0;j < leaf->numleafsurfaces;j++)
+ {
+ msurface_t *surface = loadmodel->data_surfaces + leaf->firstleafsurface[j];
+ if (surface->num_collisiontriangles)
+ {
+ leaf->containscollisionsurfaces = true;
+ leaf->combinedsupercontents |= surface->texture->supercontents;
+ }
+ }
}
}
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;
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q1BSP_TraceBox;
+ mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight;
mod->brush.SuperContentsFromNativeContents = Mod_Q1BSP_SuperContentsFromNativeContents;
mod->brush.NativeContentsFromSuperContents = Mod_Q1BSP_NativeContentsFromSuperContents;
mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
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;
mod->DrawLight = R_Q1BSP_DrawLight;
if (i != 0)
{
+ mod->brush.TraceLineOfSight = NULL;
mod->brush.GetPVS = NULL;
mod->brush.FatPVS = NULL;
mod->brush.BoxTouchingPVS = NULL;
typedef struct q3shaderinfo_layer_s
{
- char texturename[Q3PATHLENGTH];
+ int alphatest;
+ int clampmap;
+ float framerate;
+ int numframes;
+ char texturename[TEXTURE_MAXFRAMES][Q3PATHLENGTH];
int blendfunc[2];
qboolean rgbgenvertex;
qboolean alphagenvertex;
q3shaderinfo_t *shader;
q3shaderinfo_layer_t *layer;
int numparameters;
- char parameter[4][Q3PATHLENGTH];
+ char parameter[TEXTURE_MAXFRAMES + 4][Q3PATHLENGTH];
search = FS_Search("scripts/*.shader", true, false);
if (!search)
return;
numparameters = 0;
for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
{
- if (j < 4)
+ if (j < TEXTURE_MAXFRAMES + 4)
{
strlcpy(parameter[j], com_token, sizeof(parameter[j]));
numparameters = j + 1;
}
}
}
- if (layer == shader->layers + 0)
- {
- if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
- shader->textureflags |= Q3TEXTUREFLAG_ALPHATEST;
- }
+ if (numparameters >= 2 && !strcasecmp(parameter[0], "alphafunc"))
+ layer->alphatest = true;
if (numparameters >= 2 && (!strcasecmp(parameter[0], "map") || !strcasecmp(parameter[0], "clampmap")))
{
- strlcpy(layer->texturename, parameter[1], sizeof(layer->texturename));
+ 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"))
- strlcpy(layer->texturename, parameter[2], sizeof(layer->texturename));
+ 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"))
numparameters = 0;
for (j = 0;strcasecmp(com_token, "\n") && strcasecmp(com_token, "}");j++)
{
- if (j < 4)
+ if (j < TEXTURE_MAXFRAMES + 4)
{
strlcpy(parameter[j], com_token, sizeof(parameter[j]));
numparameters = j + 1;
shader->surfaceparms |= Q3SURFACEPARM_WATER;
else if (!strcasecmp(parameter[1], "pointlight"))
shader->surfaceparms |= Q3SURFACEPARM_POINTLIGHT;
+ else if (!strcasecmp(parameter[1], "antiportal"))
+ shader->surfaceparms |= Q3SURFACEPARM_ANTIPORTAL;
else
- Con_Printf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
+ Con_DPrintf("%s parsing warning: unknown surfaceparm \"%s\"\n", search->filenames[fileindex], parameter[1]);
}
else if (!strcasecmp(parameter[0], "sky") && numparameters >= 2)
{
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)
+ 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, "$lightmap"))
+ if (!strcasecmp(shader->primarylayer->texturename[0], "$lightmap"))
shader->primarylayer = shader->layers + 1;
}
}
out->basematerialflags = 0;
if (shader->surfaceparms & Q3SURFACEPARM_SKY)
{
- out->basematerialflags |= MATERIALFLAG_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
}
}
else if ((out->surfaceflags & Q3SURFACEFLAG_NODRAW) || shader->numlayers == 0)
- out->basematerialflags |= MATERIALFLAG_NODRAW;
+ out->basematerialflags |= MATERIALFLAG_NODRAW | MATERIALFLAG_NOSHADOW;
else if (shader->surfaceparms & Q3SURFACEPARM_LAVA)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_FULLBRIGHT;
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_NOSHADOW;
else if (shader->surfaceparms & Q3SURFACEPARM_SLIME)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
else if (shader->surfaceparms & Q3SURFACEPARM_WATER)
- out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_WATERALPHA;
+ out->basematerialflags |= MATERIALFLAG_WATER | MATERIALFLAG_LIGHTBOTHSIDES | MATERIALFLAG_WATERALPHA | MATERIALFLAG_NOSHADOW;
else
out->basematerialflags |= MATERIALFLAG_WALL;
- if (shader->textureflags & Q3TEXTUREFLAG_ALPHATEST)
- out->basematerialflags |= MATERIALFLAG_ALPHATEST | MATERIALFLAG_TRANSPARENT;
+ 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)
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;
+ 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;
+ 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;
+ out->basematerialflags |= MATERIALFLAG_ALPHA | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
else
- out->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT;
+ out->basematerialflags |= MATERIALFLAG_CUSTOMBLEND | MATERIALFLAG_FULLBRIGHT | MATERIALFLAG_BLENDED | MATERIALFLAG_TRANSPARENT | MATERIALFLAG_NOSHADOW;
}
}
if (!shader->lighting)
out->basematerialflags |= MATERIALFLAG_FULLBRIGHT;
- if (cls.state != ca_dedicated)
- if (shader->primarylayer && !Mod_LoadSkinFrame(&out->skin, shader->primarylayer->texturename, ((shader->surfaceparms & Q3SURFACEPARM_NOMIPMAPS) ? 0 : TEXF_MIPMAP) | TEXF_ALPHA | TEXF_PRECACHE | (shader->textureflags & Q3TEXTUREFLAG_NOPICMIP ? 0 : TEXF_PICMIP), false, true))
- Con_Printf("%s: could not load texture \"%s\" for shader \"%s\"\n", loadmodel->name, shader->primarylayer->texturename, out->name);
+ 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 if (!strcmp(out->name, "noshader"))
+ out->surfaceparms = 0;
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->skin, out->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE | TEXF_PICMIP, false, true))
+ 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);
}
- // 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);
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]);
}
// walk the tree until we hit a leaf, recursing for any split cases
while (node->plane)
{
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
return;
}
}
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
// hit a leaf
nodesegmentmins[0] = min(start[0], end[0]) - 1;
nodesegmentmins[1] = min(start[1], end[1]) - 1;
}
}
// can't do point traces on curves (they have no thickness)
- if (mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
+ if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer && !VectorCompare(start, end))
{
// line trace the curves
for (i = 0;i < leaf->numleafsurfaces;i++)
// walk the tree until we hit a leaf, recursing for any split cases
while (node->plane)
{
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
plane = node->plane;
// axial planes are much more common than non-axial, so an optimized
// axial case pays off here
// take whichever side the segment box is on
node = node->children[sides - 1];
}
+ // abort if this part of the bsp tree can not be hit by this trace
+// if (!(node->combinedsupercontents & trace->hitsupercontentsmask))
+// return;
nodesegmentmins[0] = max(segmentmins[0], node->mins[0] - 1);
nodesegmentmins[1] = max(segmentmins[1], node->mins[1] - 1);
nodesegmentmins[2] = max(segmentmins[2], node->mins[2] - 1);
Collision_TraceBrushBrushFloat(trace, thisbrush_start, thisbrush_end, brush, brush);
}
}
- if (mod_q3bsp_curves_collisions.integer)
+ if (leaf->containscollisionsurfaces && mod_q3bsp_curves_collisions.integer)
{
for (i = 0;i < leaf->numleafsurfaces;i++)
{
mod->soundfromcenter = true;
mod->TraceBox = Mod_Q3BSP_TraceBox;
+ mod->brush.TraceLineOfSight = Mod_Q1BSP_TraceLineOfSight;
mod->brush.SuperContentsFromNativeContents = Mod_Q3BSP_SuperContentsFromNativeContents;
mod->brush.NativeContentsFromSuperContents = Mod_Q3BSP_NativeContentsFromSuperContents;
mod->brush.GetPVS = Mod_Q1BSP_GetPVS;
// 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++)
// textures and memory belong to the main model
mod->texturepool = NULL;
mod->mempool = NULL;
+ mod->brush.TraceLineOfSight = NULL;
mod->brush.GetPVS = NULL;
mod->brush.FatPVS = NULL;
mod->brush.BoxTouchingPVS = NULL;
break;
if (j < mod->nummodelsurfaces)
mod->DrawSky = R_Q1BSP_DrawSky;
+ else
+ mod->DrawSky = NULL;
}
}