From 43c93c6edf2dc67b6315ebddc7a71c7f8c0597d8 Mon Sep 17 00:00:00 2001 From: havoc Date: Sun, 22 Feb 2004 18:56:51 +0000 Subject: [PATCH] fixed GL_Scissor call in rtlight code (apparently I need to feed it a top to bottom rectangle... ? must be something weird in the transform math as GL uses bottom to top) made q1bsp and q3bsp a little more alike (regarding pvs clusters), now q3bsp has all the same pvs cluster fields as q3bsp added fake lightgrid and pvs data to q3bsp loading when map is unlit or unvised respectively, this should improve internal consistency git-svn-id: svn://svn.icculus.org/twilight/trunk/darkplaces@3922 d7cf8633-e32d-0410-b094-e92efae38249 --- gl_rmain.c | 7 ++- gl_rsurf.c | 16 +++-- model_brush.c | 164 ++++++++++++++++++++++++++++++------------------- model_brush.h | 8 ++- model_shared.h | 16 ++--- portals.c | 2 +- r_light.c | 8 +-- r_shadow.c | 63 ++++++++++++++++--- r_shadow.h | 4 ++ todo | 1 + 10 files changed, 190 insertions(+), 99 deletions(-) diff --git a/gl_rmain.c b/gl_rmain.c index fef43b34..c79d1595 100644 --- a/gl_rmain.c +++ b/gl_rmain.c @@ -559,7 +559,12 @@ void R_ShadowVolumeLighting(int visiblevolumes) { if (d_lightstylevalue[wl->style] <= 0) continue; - if (VIS_CullBox(wl->mins, wl->maxs)) + if (R_CullBox(wl->mins, wl->maxs)) + continue; + for (i = 0;i < wl->numclusters;i++) + if (CHECKPVSBIT(r_pvsbits, wl->clusterindices[i])) + break; + if (i == wl->numclusters) continue; if (r_shadow_debuglight.integer >= 0 && lnum != r_shadow_debuglight.integer) continue; diff --git a/gl_rsurf.c b/gl_rsurf.c index a3ddc491..75daf710 100644 --- a/gl_rsurf.c +++ b/gl_rsurf.c @@ -1654,7 +1654,7 @@ void R_SurfaceWorldNode (entity_render_t *ent) static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { - int c, leafstackpos, *mark, *surfacevisframes, bitnum; + int c, leafstackpos, *mark, *surfacevisframes; #if WORLDNODECULLBACKFACES int n; msurface_t *surf; @@ -1718,8 +1718,7 @@ static void R_PortalWorldNode(entity_render_t *ent, mleaf_t *viewleaf) { leaf->worldnodeframe = r_framecount; // FIXME: R_CullBox is absolute, should be done relative - bitnum = (leaf - ent->model->brushq1.leafs) - 1; - if ((r_pvsbits[bitnum >> 3] & (1 << (bitnum & 7))) && !R_CullBox(leaf->mins, leaf->maxs)) + if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex) && !R_CullBox(leaf->mins, leaf->maxs)) leafstack[leafstackpos++] = leaf; } } @@ -1744,11 +1743,10 @@ void R_PVSUpdate (entity_render_t *ent, mleaf_t *viewleaf) if (viewleaf) { surfacepvsframes = model->brushq1.surfacepvsframes; - for (j = 0;j < model->brushq1.visleafs;j++) + for (j = 0, leaf = model->brushq1.data_leafs;j < model->brushq1.num_leafs;j++, leaf++) { - if (r_pvsbits[j >> 3] & (1 << (j & 7))) + if (CHECKPVSBIT(r_pvsbits, leaf->clusterindex)) { - leaf = model->brushq1.leafs + j + 1; leaf->pvsframe = model->brushq1.pvsframecount; leaf->pvschain = model->brushq1.pvsleafchain; model->brushq1.pvsleafchain = leaf; @@ -1784,7 +1782,7 @@ void R_DrawWorld(entity_render_t *ent) { if (ent->model == NULL) return; - if (!ent->model->brushq1.numleafs) + if (!ent->model->brushq1.num_leafs) { if (ent->model->DrawSky) ent->model->DrawSky(ent); @@ -2263,7 +2261,7 @@ void R_Q3BSP_RecursiveWorldNode(entity_render_t *ent, q3mnode_t *node, const vec node = node->children[1]; } leaf = (q3mleaf_t *)node; - if (pvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7))) + if (CHECKPVSBIT(pvs, leaf->clusterindex)) { c_leafs++; for (i = 0;i < leaf->numleaffaces;i++) @@ -2281,7 +2279,7 @@ void R_Q3BSP_MarkLeafPVS(entity_render_t *ent, qbyte *pvs, int markframe) q3mleaf_t *leaf; for (j = 0, leaf = ent->model->brushq3.data_leafs;j < ent->model->brushq3.num_leafs;j++, leaf++) { - if (pvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7))) + if (CHECKPVSBIT(pvs, leaf->clusterindex)) { c_leafs++; for (i = 0;i < leaf->numleaffaces;i++) diff --git a/model_brush.c b/model_brush.c index cea8a34e..1f034987 100644 --- a/model_brush.c +++ b/model_brush.c @@ -119,8 +119,8 @@ static int Mod_Q1BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3 else { // leaf - check cluster bit - clusterindex = (mleaf_t *)node - model->brushq1.leafs - 1; - if (clusterindex >= 0 && pvs[clusterindex >> 3] & (1 << (clusterindex & 7))) + clusterindex = ((mleaf_t *)node)->clusterindex; + if (CHECKPVSBIT(pvs, clusterindex)) { // it is visible, return immediately with the news return true; @@ -1963,7 +1963,7 @@ static void Mod_Q1BSP_LoadNodes(lump_t *l) if (p >= 0) out->children[j] = loadmodel->brushq1.nodes + p; else - out->children[j] = (mnode_t *)(loadmodel->brushq1.leafs + (-1 - p)); + out->children[j] = (mnode_t *)(loadmodel->brushq1.data_leafs + (-1 - p)); } } @@ -1974,8 +1974,7 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) { dleaf_t *in; mleaf_t *out; - int i, j, count, p, pvschainbytes; - qbyte *pvs; + int i, j, count, p; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -1983,11 +1982,13 @@ static void Mod_Q1BSP_LoadLeafs(lump_t *l) count = l->filelen / sizeof(*in); out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out)); - loadmodel->brushq1.leafs = out; - loadmodel->brushq1.numleafs = count; + loadmodel->brushq1.data_leafs = out; + loadmodel->brushq1.num_leafs = count; // get visleafs from the submodel data - pvschainbytes = (loadmodel->brushq1.submodels[0].visleafs+7)>>3; - loadmodel->brushq1.data_decompressedpvs = pvs = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numleafs * pvschainbytes); + loadmodel->brushq1.num_pvsclusters = loadmodel->brushq1.submodels[0].visleafs; + loadmodel->brushq1.num_pvsclusterbytes = (loadmodel->brushq1.num_pvsclusters+7)>>3; + loadmodel->brushq1.data_pvsclusters = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.num_pvsclusters * loadmodel->brushq1.num_pvsclusterbytes); + memset(loadmodel->brushq1.data_pvsclusters, 0xFF, loadmodel->brushq1.num_pvsclusters * loadmodel->brushq1.num_pvsclusterbytes); for ( i=0 ; inummarksurfaces = 0; } - out->pvsdata = pvs; - memset(out->pvsdata, 0xFF, pvschainbytes); - pvs += pvschainbytes; + out->clusterindex = i - 1; + if (out->clusterindex >= loadmodel->brushq1.num_pvsclusters) + out->clusterindex = -1; p = LittleLong(in->visofs); - if (p >= 0 && i > 0) // ignore visofs errors on leaf 0 (solid) + // ignore visofs errors on leaf 0 (solid) + if (p >= 0 && out->clusterindex >= 0) { if (p >= loadmodel->brushq1.num_compressedpvs) Con_Printf("Mod_Q1BSP_LoadLeafs: invalid visofs\n"); else - Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, out->pvsdata, out->pvsdata + pvschainbytes); + Mod_Q1BSP_DecompressVis(loadmodel->brushq1.data_compressedpvs + p, loadmodel->brushq1.data_compressedpvs + loadmodel->brushq1.num_compressedpvs, loadmodel->brushq1.data_pvsclusters + out->clusterindex * loadmodel->brushq1.num_pvsclusterbytes, loadmodel->brushq1.data_pvsclusters + (out->clusterindex + 1) * loadmodel->brushq1.num_pvsclusterbytes); } for (j = 0;j < 4;j++) @@ -2269,8 +2271,8 @@ static void Mod_Q1BSP_FinalizePortals(void) winding_t *w; // recalculate bounding boxes for all leafs(because qbsp is very sloppy) - leaf = loadmodel->brushq1.leafs; - endleaf = leaf + loadmodel->brushq1.numleafs; + leaf = loadmodel->brushq1.data_leafs; + endleaf = leaf + loadmodel->brushq1.num_leafs; for (;leaf < endleaf;leaf++) { VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000); @@ -2323,8 +2325,8 @@ static void Mod_Q1BSP_FinalizePortals(void) loadmodel->brushq1.portalpoints = (void *)((qbyte *) loadmodel->brushq1.portals + numportals * sizeof(mportal_t)); loadmodel->brushq1.numportalpoints = numpoints; // clear all leaf portal chains - for (i = 0;i < loadmodel->brushq1.numleafs;i++) - loadmodel->brushq1.leafs[i].portals = NULL; + for (i = 0;i < loadmodel->brushq1.num_leafs;i++) + loadmodel->brushq1.data_leafs[i].portals = NULL; // process all portals in the global portal chain, while freeing them portal = loadmodel->brushq1.portals; point = loadmodel->brushq1.portalpoints; @@ -2729,12 +2731,9 @@ static void Mod_Q1BSP_BuildPVSTextureChains(model_t *model) static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, mnode_t *node) { - int i; - float d; - - while (node->contents >= 0) + while (node->plane) { - d = PlaneDiff(org, node->plane); + float d = PlaneDiff(org, node->plane); if (d > radius) node = node->children[0]; else if (d < -radius) @@ -2746,18 +2745,21 @@ static void Mod_Q1BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, node = node->children[1]; } } - // FIXME: code! - // if this is a leaf, accumulate the pvs bits - if (/*node->contents != CONTENTS_SOLID && */((mleaf_t *)node)->pvsdata) + // if this leaf is in a cluster, accumulate the pvs bits + if (((mleaf_t *)node)->clusterindex >= 0) + { + int i; + qbyte *pvs = model->brushq1.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes; for (i = 0;i < pvsbytes;i++) - pvsbuffer[i] |= ((mleaf_t *)node)->pvsdata[i]; + pvsbuffer[i] |= pvs[i]; + } } //Calculates a PVS that is the inclusive or of all leafs within radius pixels //of the given point. static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength) { - int bytes = ((model->brushq1.numleafs - 1) + 7) >> 3; + int bytes = ((model->brushq1.num_leafs - 1) + 7) >> 3; bytes = min(bytes, pvsbufferlength); if (r_novis.integer) { @@ -2770,17 +2772,18 @@ static int Mod_Q1BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyt } //Returns PVS data for a given point -//(note: always returns valid data, never NULL) +//(note: can return NULL) static qbyte *Mod_Q1BSP_GetPVS(model_t *model, const vec3_t p) { mnode_t *node; Mod_CheckLoaded(model); - // LordHavoc: modified to start at first clip node, - // in other words: first node of the (sub)model - node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode; - while (node->contents == 0) + node = model->brushq1.nodes; + while (node->plane) node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; - return ((mleaf_t *)node)->pvsdata; + if (((mleaf_t *)node)->clusterindex >= 0) + return model->brushq1.data_pvsclusters + ((mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes; + else + return NULL; } static void Mod_Q1BSP_RoundUpToHullSize(model_t *cmodel, const vec3_t inmins, const vec3_t inmaxs, vec3_t outmins, vec3_t outmaxs) @@ -2927,6 +2930,14 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) mod->Draw = R_Model_Brush_Draw; mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; mod->DrawLight = R_Model_Brush_DrawLight; + if (i != 0) + { + mod->brush.GetPVS = NULL; + mod->brush.FatPVS = NULL; + mod->brush.BoxTouchingPVS = NULL; + mod->brush.LightPoint = NULL; + mod->brush.AmbientSoundLevelsForPoint = NULL; + } mod->brushq1.pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(msurface_t **)); mod->brushq1.pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool,(mod->brushq1.nummodelsurfaces + mod->brushq1.numtextures) * sizeof(msurface_t *)); mod->brushq1.pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(int)); @@ -2981,7 +2992,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) } Mod_Q1BSP_BuildSurfaceNeighbors(mod->brushq1.surfaces + mod->brushq1.firstmodelsurface, mod->brushq1.nummodelsurfaces, originalloadmodel->mempool); - mod->brushq1.visleafs = bm->visleafs; + mod->brushq1.num_visleafs = bm->visleafs; // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) @@ -3004,7 +3015,7 @@ void Mod_Q1BSP_Load(model_t *mod, void *buffer) //Mod_Q1BSP_ProcessLightList(); if (developer.integer) - Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.numleafs, loadmodel->brushq1.visleafs, loadmodel->brushq1.numportals); + Con_Printf("Some stats for q1bsp model \"%s\": %i faces, %i nodes, %i leafs, %i visleafs, %i visleafportals\n", loadmodel->name, loadmodel->brushq1.numsurfaces, loadmodel->brushq1.numnodes, loadmodel->brushq1.num_leafs, loadmodel->brushq1.num_visleafs, loadmodel->brushq1.numportals); } static void Mod_Q2BSP_LoadEntities(lump_t *l) @@ -4424,9 +4435,6 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) q3dlightgrid_t *out; int count; - if (l->filelen == 0) - return; - in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name); @@ -4443,17 +4451,37 @@ static void Mod_Q3BSP_LoadLightGrid(lump_t *l) 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; count = loadmodel->brushq3.num_lightgrid_isize[0] * loadmodel->brushq3.num_lightgrid_isize[1] * loadmodel->brushq3.num_lightgrid_isize[2]; - 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)\n", l->filelen, 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\n", count * sizeof(*in), l->filelen); + 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)\n", l->filelen, 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\n", count * sizeof(*in), l->filelen); + } out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out)); loadmodel->brushq3.data_lightgrid = out; loadmodel->brushq3.num_lightgrid = count; // no swapping or validation necessary - memcpy(out, in, count * (int)sizeof(*out)); + if (l->filelen) + memcpy(out, in, count * (int)sizeof(*out)); + else + { + // no data, fill with white + int i; + for (i = 0;i < count;i++) + { + out[i].ambientrgb[0] = 128; + out[i].ambientrgb[1] = 128; + out[i].ambientrgb[2] = 128; + out[i].diffusergb[0] = 0; + out[i].diffusergb[1] = 0; + out[i].diffusergb[2] = 0; + out[i].diffusepitch = 0; + out[i].diffuseyaw = 0; + } + } Matrix4x4_CreateScale3(&loadmodel->brushq3.num_lightgrid_indexfromworld, loadmodel->brushq3.num_lightgrid_scale[0], loadmodel->brushq3.num_lightgrid_scale[1], loadmodel->brushq3.num_lightgrid_scale[2]); Matrix4x4_ConcatTranslate(&loadmodel->brushq3.num_lightgrid_indexfromworld, -loadmodel->brushq3.num_lightgrid_imins[0] * loadmodel->brushq3.num_lightgrid_cellsize[0], -loadmodel->brushq3.num_lightgrid_imins[1] * loadmodel->brushq3.num_lightgrid_cellsize[1], -loadmodel->brushq3.num_lightgrid_imins[2] * loadmodel->brushq3.num_lightgrid_cellsize[2]); @@ -4465,22 +4493,36 @@ static void Mod_Q3BSP_LoadPVS(lump_t *l) int totalchains; if (l->filelen == 0) + { + int i; + // unvised maps often have cluster indices even without pvs, so check + // leafs to find real number of clusters + loadmodel->brushq3.num_pvsclusters = 1; + for (i = 0;i < loadmodel->brushq3.num_leafs;i++) + loadmodel->brushq3.num_pvsclusters = min(loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.data_leafs[i].clusterindex + 1); + + // create clusters + loadmodel->brushq3.num_pvsclusterbytes = (loadmodel->brushq3.num_pvsclusters + 7) / 8; + totalchains = loadmodel->brushq3.num_pvsclusterbytes * loadmodel->brushq3.num_pvsclusters; + loadmodel->brushq3.data_pvsclusters = Mem_Alloc(loadmodel->mempool, totalchains); + memset(loadmodel->brushq3.data_pvsclusters, 0xFF, totalchains); return; + } in = (void *)(mod_base + l->fileofs); if (l->filelen < 9) Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name); loadmodel->brushq3.num_pvsclusters = LittleLong(in->numclusters); - loadmodel->brushq3.num_pvschainlength = LittleLong(in->chainlength); - if (loadmodel->brushq3.num_pvschainlength < ((loadmodel->brushq3.num_pvsclusters + 7) / 8)) - Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvschainlength, loadmodel->brushq3.num_pvsclusters); - totalchains = loadmodel->brushq3.num_pvschainlength * loadmodel->brushq3.num_pvsclusters; + loadmodel->brushq3.num_pvsclusterbytes = LittleLong(in->chainlength); + if (loadmodel->brushq3.num_pvsclusterbytes < ((loadmodel->brushq3.num_pvsclusters + 7) / 8)) + Host_Error("Mod_Q3BSP_LoadPVS: (chainlength = %i) < ((numclusters = %i) + 7) / 8\n", loadmodel->brushq3.num_pvsclusterbytes, loadmodel->brushq3.num_pvsclusters); + totalchains = loadmodel->brushq3.num_pvsclusterbytes * loadmodel->brushq3.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)\n", loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvschainlength, 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)\n", loadmodel->brushq3.num_pvsclusters, loadmodel->brushq3.num_pvsclusterbytes, totalchains + sizeof(*in), l->filelen); - loadmodel->brushq3.data_pvschains = Mem_Alloc(loadmodel->mempool, totalchains); - memcpy(loadmodel->brushq3.data_pvschains, (qbyte *)(in + 1), totalchains); + loadmodel->brushq3.data_pvsclusters = Mem_Alloc(loadmodel->mempool, totalchains); + memcpy(loadmodel->brushq3.data_pvsclusters, (qbyte *)(in + 1), totalchains); } static void Mod_Q3BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, vec_t radius) @@ -5146,7 +5188,7 @@ static int Mod_Q3BSP_BoxTouchingPVS(model_t *model, const qbyte *pvs, const vec3 return true; } #endif - if (clusterindex < 0 || (pvs[clusterindex >> 3] & (1 << (clusterindex & 7)))) + if (CHECKPVSBIT(pvs, clusterindex)) { // it is visible, return immediately with the news return true; @@ -5174,20 +5216,16 @@ static qbyte *Mod_Q3BSP_GetPVS(model_t *model, const vec3_t p) while (node->plane) node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist]; if (((q3mleaf_t *)node)->clusterindex >= 0) - return model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength; + return model->brushq3.data_pvsclusters + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvsclusterbytes; else return NULL; } static void Mod_Q3BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbytes, q3mnode_t *node) { - int i; - float d; - qbyte *pvs; - while (node->plane) { - d = PlaneDiff(org, node->plane); + float d = PlaneDiff(org, node->plane); if (d > radius) node = node->children[0]; else if (d < -radius) @@ -5199,23 +5237,21 @@ static void Mod_Q3BSP_FatPVS_RecursiveBSPNode(model_t *model, const vec3_t org, node = node->children[1]; } } - // if this is a leaf with a pvs, accumulate the pvs bits + // if this leaf is in a cluster, accumulate the pvs bits if (((q3mleaf_t *)node)->clusterindex >= 0) { - pvs = model->brushq3.data_pvschains + ((q3mleaf_t *)node)->clusterindex * model->brushq3.num_pvschainlength; + int i; + qbyte *pvs = model->brushq1.data_pvsclusters + ((q3mleaf_t *)node)->clusterindex * model->brushq1.num_pvsclusterbytes; for (i = 0;i < pvsbytes;i++) pvsbuffer[i] |= pvs[i]; } - else - memset(pvsbuffer, 0xFF, pvsbytes); - return; } //Calculates a PVS that is the inclusive or of all leafs within radius pixels //of the given point. static int Mod_Q3BSP_FatPVS(model_t *model, const vec3_t org, vec_t radius, qbyte *pvsbuffer, int pvsbufferlength) { - int bytes = model->brushq3.num_pvschainlength; + int bytes = model->brushq3.num_pvsclusterbytes; bytes = min(bytes, pvsbufferlength); if (r_novis.integer || !loadmodel->brushq3.num_pvsclusters) { diff --git a/model_brush.h b/model_brush.h index 08686dfe..f812fdb8 100644 --- a/model_brush.h +++ b/model_brush.h @@ -275,9 +275,8 @@ typedef struct mleaf_s // used by polygon-through-portals visibility checker int portalmarkid; - // decompressed pvs bits (potentially visible set) - // note: never NULL, always present, may be full of 0xFF though - qbyte *pvsdata; + // -1 is not in pvs, >= 0 is pvs bit number + int clusterindex; int *firstmarksurface; int nummarksurfaces; @@ -767,5 +766,8 @@ typedef struct } q3dpvs_t; +#define CHECKPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] & (1 << ((b) & 7))) : false) +#define SETPVSBIT(pvs,b) ((b) >= 0 ? ((pvs)[(b) >> 3] |= (1 << ((b) & 7))) : false) + #endif diff --git a/model_shared.h b/model_shared.h index 18462985..268873cf 100644 --- a/model_shared.h +++ b/model_shared.h @@ -192,10 +192,10 @@ typedef struct model_brushq1_s mplane_t *planes; // number of actual leafs (including 0 which is solid) - int numleafs; + int num_leafs; // visible leafs, not counting 0 (solid) - int visleafs; - mleaf_t *leafs; + int num_visleafs; + mleaf_t *data_leafs; int numvertexes; mvertex_t *vertexes; @@ -232,7 +232,9 @@ typedef struct model_brushq1_s int num_compressedpvs; qbyte *data_compressedpvs; - qbyte *data_decompressedpvs; + int num_pvsclusters; + int num_pvsclusterbytes; + unsigned char *data_pvsclusters; int num_lightdata; qbyte *lightdata; @@ -517,10 +519,10 @@ typedef struct model_brushq3_s // pvs int num_pvsclusters; - int num_pvschainlength; - unsigned char *data_pvschains; + int num_pvsclusterbytes; + unsigned char *data_pvsclusters; // example - //pvschain = model->brushq3.data_pvschains + mycluster * model->brushq3.num_pvschainlength; + //pvschain = model->brushq3.data_pvsclusters + mycluster * model->brushq3.num_pvsclusterbytes; //if (pvschain[thatcluster >> 3] & (1 << (thatcluster & 7))) } model_brushq3_t; diff --git a/portals.c b/portals.c index da91b8f4..bf6f2744 100644 --- a/portals.c +++ b/portals.c @@ -402,7 +402,7 @@ void Portal_RecursiveFlow (portalrecursioninfo_t *info, mleaf_t *leaf, int first } if (info->leafmark) - info->leafmark[leaf - info->model->brushq1.leafs] = true; + info->leafmark[leaf - info->model->brushq1.data_leafs] = true; // mark surfaces in leaf that can be seen through portal if (leaf->nummarksurfaces && info->surfacemark) diff --git a/r_light.c b/r_light.c index af11fd06..89f36ad0 100644 --- a/r_light.c +++ b/r_light.c @@ -224,8 +224,8 @@ static void R_RecursiveMarkLights(entity_render_t *ent, vec3_t lightorigin, rdli // check if leaf is visible according to pvs leaf = (mleaf_t *)node; - i = (leaf - ent->model->brushq1.leafs) - 1; - if (leaf->nummarksurfaces && (i >= pvsbits || pvs[i >> 3] & (1 << (i & 7)))) + i = leaf->clusterindex; + if (leaf->nummarksurfaces && (i >= pvsbits || CHECKPVSBIT(pvs, i))) { int *surfacepvsframes, d, impacts, impactt; float sdist, maxdist, dist2, impact[3]; @@ -285,7 +285,7 @@ void R_MarkLights(entity_render_t *ent) int i, bit, bitindex; rdlight_t *rd; vec3_t lightorigin; - if (!gl_flashblend.integer && r_dynamic.integer && ent->model && ent->model->brushq1.numleafs) + if (!gl_flashblend.integer && r_dynamic.integer && ent->model && ent->model->brushq1.num_leafs) { for (i = 0, rd = r_dlight;i < r_numdlights;i++, rd++) { @@ -295,7 +295,7 @@ void R_MarkLights(entity_render_t *ent) lightpvsbytes = 0; if (r_vismarklights.integer && ent->model->brush.FatPVS) lightpvsbytes = ent->model->brush.FatPVS(ent->model, lightorigin, 0, lightpvs, sizeof(lightpvs)); - R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brushq1.visleafs)); + R_RecursiveMarkLights(ent, lightorigin, rd, bit, bitindex, ent->model->brushq1.nodes + ent->model->brushq1.hulls[0].firstclipnode, lightpvs, min(lightpvsbytes * 8, ent->model->brushq1.num_pvsclusters)); } } } diff --git a/r_shadow.c b/r_shadow.c index ce3cc8dc..f5d07e31 100644 --- a/r_shadow.c +++ b/r_shadow.c @@ -1153,7 +1153,7 @@ int R_Shadow_ScissorForBBox(const float *mins, const float *maxs) if (ix2 <= ix1 || iy2 <= iy1) return true; // set up the scissor rectangle - GL_Scissor(ix1, iy1, ix2 - ix1, iy2 - iy1); + GL_Scissor(ix1, vid.realheight - iy2, ix2 - ix1, iy2 - iy1); //qglScissor(ix1, iy1, ix2 - ix1, iy2 - iy1); //qglEnable(GL_SCISSOR_TEST); c_rt_scissored++; @@ -1863,6 +1863,7 @@ vec3_t r_editlights_cursorlocation; static int lightpvsbytes; static qbyte lightpvs[(MAX_MAP_LEAFS + 7)/ 8]; +static qbyte lightfullpvs[(MAX_MAP_LEAFS + 7)/ 8]; typedef struct cubemapinfo_s { @@ -2037,18 +2038,34 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra e->meshchain_light = Mod_ShadowMesh_Begin(r_shadow_mempool, 32768, 32768, NULL, NULL, NULL, true, false, true); if (cl.worldmodel) { + lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightfullpvs, sizeof(lightfullpvs)); + memset(lightpvs, 0, lightpvsbytes); if (cl.worldmodel->brushq3.num_leafs) { q3mleaf_t *leaf; q3mface_t *face; - lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs)); + + // make a pvs that only includes things within the box + for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++) + if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) + SETPVSBIT(lightpvs, leaf->clusterindex); + + // make a cluster list for fast visibility checking during rendering + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq3.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->numclusters++; + e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq3.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->clusterindices[e->numclusters++] = i; + VectorCopy(e->origin, e->mins); VectorCopy(e->origin, e->maxs); for (i = 0, face = cl.worldmodel->brushq3.data_thismodel->firstface;i < cl.worldmodel->brushq3.data_thismodel->numfaces;i++, face++) face->lighttemp_castshadow = false; for (i = 0, leaf = cl.worldmodel->brushq3.data_leafs;i < cl.worldmodel->brushq3.num_leafs;i++, leaf++) { - if ((leaf->clusterindex < 0 || lightpvs[leaf->clusterindex >> 3] & (1 << (leaf->clusterindex & 7))) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) + if (CHECKPVSBIT(lightpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) { for (k = 0;k < 3;k++) { @@ -2081,7 +2098,7 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra } } } - else if (cl.worldmodel->brushq1.numleafs) + else if (cl.worldmodel->brushq1.num_leafs) { mleaf_t *leaf; msurface_t *surf; @@ -2097,15 +2114,17 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra qbyte *byteleafpvs; qbyte *bytesurfacepvs; - byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numleafs); + byteleafpvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.num_leafs); bytesurfacepvs = Mem_Alloc(tempmempool, cl.worldmodel->brushq1.numsurfaces); Portal_Visibility(cl.worldmodel, e->origin, byteleafpvs, bytesurfacepvs, NULL, 0, true, mins, maxs, e->mins, e->maxs); - for (i = 0, leaf = cl.worldmodel->brushq1.leafs;i < cl.worldmodel->brushq1.numleafs;i++, leaf++) + // make a pvs that only includes things within the box + for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++) { if (byteleafpvs[i] && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) { + SETPVSBIT(lightpvs, leaf->clusterindex); for (k = 0;k < 3;k++) { if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; @@ -2113,21 +2132,31 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra } } } - + for (i = 0, surf = cl.worldmodel->brushq1.surfaces;i < cl.worldmodel->brushq1.numsurfaces;i++, surf++) if (bytesurfacepvs[i] && BoxesOverlap(surf->poly_mins, surf->poly_maxs, mins, maxs)) surf->lighttemp_castshadow = true; Mem_Free(byteleafpvs); Mem_Free(bytesurfacepvs); + + // make a cluster list for fast visibility checking during rendering + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq1.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->numclusters++; + e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq1.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->clusterindices[e->numclusters++] = i; } else { - lightpvsbytes = cl.worldmodel->brush.FatPVS(cl.worldmodel, origin, 0, lightpvs, sizeof(lightpvs)); - for (i = 0, leaf = cl.worldmodel->brushq1.leafs + 1;i < cl.worldmodel->brushq1.visleafs;i++, leaf++) + for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++) { - if (lightpvs[i >> 3] & (1 << (i & 7)) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) + if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) { + // make a pvs that only includes things within the box + SETPVSBIT(lightpvs, leaf->clusterindex); for (k = 0;k < 3;k++) { if (e->mins[k] > leaf->mins[k]) e->mins[k] = leaf->mins[k]; @@ -2141,6 +2170,20 @@ void R_Shadow_NewWorldLight(vec3_t origin, vec3_t angles, vec3_t color, vec_t ra } } } + + // make a pvs that only includes things within the box + for (i = 0, leaf = cl.worldmodel->brushq1.data_leafs;i < cl.worldmodel->brushq1.num_leafs;i++, leaf++) + if (CHECKPVSBIT(lightfullpvs, leaf->clusterindex) && BoxesOverlap(leaf->mins, leaf->maxs, mins, maxs)) + SETPVSBIT(lightpvs, leaf->clusterindex); + + // make a cluster list for fast visibility checking during rendering + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq1.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->numclusters++; + e->clusterindices = Mem_Alloc(r_shadow_mempool, e->numclusters * sizeof(int)); + for (i = 0, e->numclusters = 0;i < cl.worldmodel->brushq1.num_pvsclusters;i++) + if (CHECKPVSBIT(lightpvs, i)) + e->clusterindices[e->numclusters++] = i; } // add surfaces to shadow casting mesh and light mesh diff --git a/r_shadow.h b/r_shadow.h index 953c883c..4e1349a3 100644 --- a/r_shadow.h +++ b/r_shadow.h @@ -76,6 +76,10 @@ typedef struct worldlight_s // premade shadow volumes and lit surfaces to render shadowmesh_t *meshchain_shadow; shadowmesh_t *meshchain_light; + + // used for visibility testing + int numclusters; + int *clusterindices; } worldlight_t; diff --git a/todo b/todo index bd6e06e5..f8f0c158 100644 --- a/todo +++ b/todo @@ -34,6 +34,7 @@ -n darkplaces: segfault reading memory in windows when starting a new server from menu (yummyluv) -n darkplaces: server is starting before the "port" cvar is set by commandline and scripts? (yummyluv) -n darkplaces: typing ip in join game menu should show 'trying' and 'no response' after a while, or 'no network' if networking is not initialized (yummyluv) +0 darkplaces: add procedural ripple distortion texture of some sort for use with envmap reflections (FrikaC) 0 darkplaces: fix q3bsp fogging (Sajt) 0 darkplaces: add fov to menu d darkplaces: fov limit now 1-170, was 10-170 -- 2.39.2