/model_brush.c
C | 8790 lines | 7317 code | 714 blank | 759 comment | 1736 complexity | bdcd1e0e15402d0330593af75e6a1f84 MD5 | raw file
Possible License(s): GPL-2.0
Large files files are truncated, but you can click here to view the full file
- /*
- Copyright (C) 1996-1997 Id Software, Inc.
- This program is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- #include "quakedef.h"
- #include "image.h"
- #include "r_shadow.h"
- #include "polygon.h"
- #include "curves.h"
- #include "wad.h"
- //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128", "how large water polygons should be (smaller values produce more polygons which give better warping effects)"};
- cvar_t mod_bsp_portalize = {0, "mod_bsp_portalize", "1", "enables portal generation from BSP tree (may take several seconds per map), used by r_drawportals, r_useportalculling, r_shadow_realtime_world_compileportalculling, sv_cullentities_portal"};
- cvar_t r_novis = {0, "r_novis", "0", "draws whole level, see also sv_cullentities_pvs 0"};
- 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 r_subdivisions_mintess = {0, "r_subdivisions_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
- cvar_t r_subdivisions_maxtess = {0, "r_subdivisions_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
- cvar_t r_subdivisions_maxvertices = {0, "r_subdivisions_maxvertices", "65536", "maximum vertices allowed per subdivided curve"};
- cvar_t r_subdivisions_collision_tolerance = {0, "r_subdivisions_collision_tolerance", "15", "maximum error tolerance on curve subdivision for collision purposes (usually a larger error tolerance than for rendering)"};
- cvar_t r_subdivisions_collision_mintess = {0, "r_subdivisions_collision_mintess", "0", "minimum number of subdivisions (values above 0 will smooth curves that don't need it)"};
- cvar_t r_subdivisions_collision_maxtess = {0, "r_subdivisions_collision_maxtess", "1024", "maximum number of subdivisions (prevents curves beyond a certain detail level, limits smoothing)"};
- cvar_t r_subdivisions_collision_maxvertices = {0, "r_subdivisions_collision_maxvertices", "4225", "maximum vertices allowed per subdivided curve"};
- cvar_t r_trippy = {0, "r_trippy", "0", "easter egg"};
- cvar_t r_fxaa = {CVAR_SAVE, "r_fxaa", "0", "fast approximate anti aliasing"};
- cvar_t mod_noshader_default_offsetmapping = {CVAR_SAVE, "mod_noshader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are not using q3 shader files"};
- cvar_t mod_obj_orientation = {0, "mod_obj_orientation", "1", "fix orientation of OBJ models to the usual conventions (if zero, use coordinates as is)"};
- cvar_t mod_q2bsp_littransparentsurfaces = {0, "mod_q2bsp_littransparentsurfaces", "0", "allows lighting on rain in 3v3gloom3 and other cases of transparent surfaces that have lightmaps that were ignored by quake2"};
- cvar_t mod_q3bsp_curves_collisions = {0, "mod_q3bsp_curves_collisions", "1", "enables collisions with curves (SLOW)"};
- cvar_t mod_q3bsp_curves_collisions_stride = {0, "mod_q3bsp_curves_collisions_stride", "16", "collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
- cvar_t mod_q3bsp_curves_stride = {0, "mod_q3bsp_curves_stride", "16", "particle effect collisions against curves: optimize performance by doing a combined collision check for this triangle amount first (-1 avoids any box tests)"};
- 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)"};
- cvar_t mod_q3bsp_lightmapmergepower = {CVAR_SAVE, "mod_q3bsp_lightmapmergepower", "4", "merges the quake3 128x128 lightmap textures into larger lightmap group textures to speed up rendering, 1 = 256x256, 2 = 512x512, 3 = 1024x1024, 4 = 2048x2048, 5 = 4096x4096, ..."};
- cvar_t mod_q3bsp_nolightmaps = {CVAR_SAVE, "mod_q3bsp_nolightmaps", "0", "do not load lightmaps in Q3BSP maps (to save video RAM, but be warned: it looks ugly)"};
- cvar_t mod_q3bsp_tracelineofsight_brushes = {0, "mod_q3bsp_tracelineofsight_brushes", "0", "enables culling of entities behind detail brushes, curves, etc"};
- cvar_t mod_q3bsp_sRGBlightmaps = {0, "mod_q3bsp_sRGBlightmaps", "0", "treat lightmaps from Q3 maps as sRGB when vid_sRGB is active"};
- cvar_t mod_q3shader_default_offsetmapping = {CVAR_SAVE, "mod_q3shader_default_offsetmapping", "1", "use offsetmapping by default on all surfaces that are using q3 shader files"};
- cvar_t mod_q3shader_default_offsetmapping_scale = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_scale", "1", "default scale used for offsetmapping"};
- cvar_t mod_q3shader_default_offsetmapping_bias = {CVAR_SAVE, "mod_q3shader_default_offsetmapping_bias", "0", "default bias used for offsetmapping"};
- cvar_t mod_q3shader_default_polygonfactor = {0, "mod_q3shader_default_polygonfactor", "0", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
- cvar_t mod_q3shader_default_polygonoffset = {0, "mod_q3shader_default_polygonoffset", "-2", "biases depth values of 'polygonoffset' shaders to prevent z-fighting artifacts"};
- cvar_t mod_q3shader_force_addalpha = {0, "mod_q3shader_force_addalpha", "0", "treat GL_ONE GL_ONE (or add) blendfunc as GL_SRC_ALPHA GL_ONE for compatibility with older DarkPlaces releases"};
- cvar_t mod_q3shader_force_terrain_alphaflag = {0, "mod_q3shader_force_terrain_alphaflag", "0", "for multilayered terrain shaders force TEXF_ALPHA flag on both layers"};
- cvar_t mod_q1bsp_polygoncollisions = {0, "mod_q1bsp_polygoncollisions", "0", "disables use of precomputed cliphulls and instead collides with polygons (uses Bounding Interval Hierarchy optimizations)"};
- cvar_t mod_collision_bih = {0, "mod_collision_bih", "1", "enables use of generated Bounding Interval Hierarchy tree instead of compiled bsp tree in collision code"};
- cvar_t mod_recalculatenodeboxes = {0, "mod_recalculatenodeboxes", "1", "enables use of generated node bounding boxes based on BSP tree portal reconstruction, rather than the node boxes supplied by the map compiler"};
- 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;
- static qboolean Mod_Q3BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs);
- void Mod_BrushInit(void)
- {
- // Cvar_RegisterVariable(&r_subdivide_size);
- Cvar_RegisterVariable(&mod_bsp_portalize);
- Cvar_RegisterVariable(&r_novis);
- Cvar_RegisterVariable(&r_nosurftextures);
- Cvar_RegisterVariable(&r_subdivisions_tolerance);
- Cvar_RegisterVariable(&r_subdivisions_mintess);
- Cvar_RegisterVariable(&r_subdivisions_maxtess);
- Cvar_RegisterVariable(&r_subdivisions_maxvertices);
- Cvar_RegisterVariable(&r_subdivisions_collision_tolerance);
- Cvar_RegisterVariable(&r_subdivisions_collision_mintess);
- Cvar_RegisterVariable(&r_subdivisions_collision_maxtess);
- Cvar_RegisterVariable(&r_subdivisions_collision_maxvertices);
- Cvar_RegisterVariable(&r_trippy);
- Cvar_RegisterVariable(&r_fxaa);
- Cvar_RegisterVariable(&mod_noshader_default_offsetmapping);
- Cvar_RegisterVariable(&mod_obj_orientation);
- Cvar_RegisterVariable(&mod_q2bsp_littransparentsurfaces);
- Cvar_RegisterVariable(&mod_q3bsp_curves_collisions);
- Cvar_RegisterVariable(&mod_q3bsp_curves_collisions_stride);
- Cvar_RegisterVariable(&mod_q3bsp_curves_stride);
- Cvar_RegisterVariable(&mod_q3bsp_optimizedtraceline);
- Cvar_RegisterVariable(&mod_q3bsp_debugtracebrush);
- Cvar_RegisterVariable(&mod_q3bsp_lightmapmergepower);
- Cvar_RegisterVariable(&mod_q3bsp_nolightmaps);
- Cvar_RegisterVariable(&mod_q3bsp_sRGBlightmaps);
- Cvar_RegisterVariable(&mod_q3bsp_tracelineofsight_brushes);
- Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping);
- Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping_scale);
- Cvar_RegisterVariable(&mod_q3shader_default_offsetmapping_bias);
- Cvar_RegisterVariable(&mod_q3shader_default_polygonfactor);
- Cvar_RegisterVariable(&mod_q3shader_default_polygonoffset);
- Cvar_RegisterVariable(&mod_q3shader_force_addalpha);
- Cvar_RegisterVariable(&mod_q3shader_force_terrain_alphaflag);
- Cvar_RegisterVariable(&mod_q1bsp_polygoncollisions);
- Cvar_RegisterVariable(&mod_collision_bih);
- Cvar_RegisterVariable(&mod_recalculatenodeboxes);
- // these games were made for older DP engines and are no longer
- // maintained; use this hack to show their textures properly
- if(gamemode == GAME_NEXUIZ)
- Cvar_SetQuick(&mod_q3shader_force_addalpha, "1");
- 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(dp_model_t *model, const vec3_t p)
- {
- mnode_t *node;
- if (model == NULL)
- return NULL;
- // LordHavoc: modified to start at first clip node,
- // in other words: first node of the (sub)model
- node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
- 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;
- }
- static void Mod_Q1BSP_AmbientSoundLevelsForPoint(dp_model_t *model, const vec3_t p, unsigned char *out, int outsize)
- {
- int i;
- mleaf_t *leaf;
- leaf = Mod_Q1BSP_PointInLeaf(model, p);
- if (leaf)
- {
- i = min(outsize, (int)sizeof(leaf->ambient_sound_level));
- if (i)
- {
- memcpy(out, leaf->ambient_sound_level, i);
- out += i;
- outsize -= i;
- }
- }
- if (outsize)
- memset(out, 0, outsize);
- }
- static int Mod_Q1BSP_FindBoxClusters(dp_model_t *model, const vec3_t mins, const vec3_t maxs, int maxclusters, int *clusterlist)
- {
- int numclusters = 0;
- int nodestackindex = 0;
- mnode_t *node, *nodestack[1024];
- if (!model->brush.num_pvsclusters)
- return -1;
- node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
- for (;;)
- {
- #if 1
- if (node->plane)
- {
- // node - recurse down the BSP tree
- int sides = BoxOnPlaneSide(mins, maxs, node->plane);
- if (sides < 3)
- {
- if (sides == 0)
- return -1; // ERROR: NAN bounding box!
- // box is on one side of plane, take that path
- node = node->children[sides-1];
- }
- else
- {
- // box crosses plane, take one path and remember the other
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- }
- continue;
- }
- else
- {
- // leaf - add clusterindex to list
- if (numclusters < maxclusters)
- clusterlist[numclusters] = ((mleaf_t *)node)->clusterindex;
- numclusters++;
- }
- #else
- if (BoxesOverlap(mins, maxs, node->mins, node->maxs))
- {
- if (node->plane)
- {
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- continue;
- }
- else
- {
- // leaf - add clusterindex to list
- if (numclusters < maxclusters)
- clusterlist[numclusters] = ((mleaf_t *)node)->clusterindex;
- numclusters++;
- }
- }
- #endif
- // try another path we didn't take earlier
- if (nodestackindex == 0)
- break;
- node = nodestack[--nodestackindex];
- }
- // return number of clusters found (even if more than the maxclusters)
- return numclusters;
- }
- static int Mod_Q1BSP_BoxTouchingPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
- {
- int nodestackindex = 0;
- mnode_t *node, *nodestack[1024];
- if (!model->brush.num_pvsclusters)
- return true;
- node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
- for (;;)
- {
- #if 1
- if (node->plane)
- {
- // node - recurse down the BSP tree
- int sides = BoxOnPlaneSide(mins, maxs, node->plane);
- if (sides < 3)
- {
- if (sides == 0)
- return -1; // ERROR: NAN bounding box!
- // box is on one side of plane, take that path
- node = node->children[sides-1];
- }
- else
- {
- // box crosses plane, take one path and remember the other
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- }
- continue;
- }
- else
- {
- // leaf - check cluster bit
- int clusterindex = ((mleaf_t *)node)->clusterindex;
- if (CHECKPVSBIT(pvs, clusterindex))
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- #else
- if (BoxesOverlap(mins, maxs, node->mins, node->maxs))
- {
- if (node->plane)
- {
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- continue;
- }
- else
- {
- // leaf - check cluster bit
- int clusterindex = ((mleaf_t *)node)->clusterindex;
- if (CHECKPVSBIT(pvs, clusterindex))
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- }
- #endif
- // nothing to see here, try another path we didn't take earlier
- if (nodestackindex == 0)
- break;
- node = nodestack[--nodestackindex];
- }
- // it is not visible
- return false;
- }
- static int Mod_Q1BSP_BoxTouchingLeafPVS(dp_model_t *model, const unsigned char *pvs, const vec3_t mins, const vec3_t maxs)
- {
- int nodestackindex = 0;
- mnode_t *node, *nodestack[1024];
- if (!model->brush.num_leafs)
- return true;
- node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
- for (;;)
- {
- #if 1
- if (node->plane)
- {
- // node - recurse down the BSP tree
- int sides = BoxOnPlaneSide(mins, maxs, node->plane);
- if (sides < 3)
- {
- if (sides == 0)
- return -1; // ERROR: NAN bounding box!
- // box is on one side of plane, take that path
- node = node->children[sides-1];
- }
- else
- {
- // box crosses plane, take one path and remember the other
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- }
- continue;
- }
- else
- {
- // leaf - check cluster bit
- int clusterindex = ((mleaf_t *)node) - model->brush.data_leafs;
- if (CHECKPVSBIT(pvs, clusterindex))
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- #else
- if (BoxesOverlap(mins, maxs, node->mins, node->maxs))
- {
- if (node->plane)
- {
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- continue;
- }
- else
- {
- // leaf - check cluster bit
- int clusterindex = ((mleaf_t *)node) - model->brush.data_leafs;
- if (CHECKPVSBIT(pvs, clusterindex))
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- }
- #endif
- // nothing to see here, try another path we didn't take earlier
- if (nodestackindex == 0)
- break;
- node = nodestack[--nodestackindex];
- }
- // it is not visible
- return false;
- }
- static int Mod_Q1BSP_BoxTouchingVisibleLeafs(dp_model_t *model, const unsigned char *visibleleafs, const vec3_t mins, const vec3_t maxs)
- {
- int nodestackindex = 0;
- mnode_t *node, *nodestack[1024];
- if (!model->brush.num_leafs)
- return true;
- node = model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode;
- for (;;)
- {
- #if 1
- if (node->plane)
- {
- // node - recurse down the BSP tree
- int sides = BoxOnPlaneSide(mins, maxs, node->plane);
- if (sides < 3)
- {
- if (sides == 0)
- return -1; // ERROR: NAN bounding box!
- // box is on one side of plane, take that path
- node = node->children[sides-1];
- }
- else
- {
- // box crosses plane, take one path and remember the other
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- }
- continue;
- }
- else
- {
- // leaf - check if it is visible
- if (visibleleafs[(mleaf_t *)node - model->brush.data_leafs])
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- #else
- if (BoxesOverlap(mins, maxs, node->mins, node->maxs))
- {
- if (node->plane)
- {
- if (nodestackindex < 1024)
- nodestack[nodestackindex++] = node->children[0];
- node = node->children[1];
- continue;
- }
- else
- {
- // leaf - check if it is visible
- if (visibleleafs[(mleaf_t *)node - model->brush.data_leafs])
- {
- // it is visible, return immediately with the news
- return true;
- }
- }
- }
- #endif
- // nothing to see here, try another path we didn't take earlier
- if (nodestackindex == 0)
- break;
- node = nodestack[--nodestackindex];
- }
- // it is not visible
- return false;
- }
- typedef struct findnonsolidlocationinfo_s
- {
- vec3_t center;
- vec3_t absmin, absmax;
- vec_t radius;
- vec3_t nudge;
- vec_t bestdist;
- dp_model_t *model;
- }
- findnonsolidlocationinfo_t;
- static void Mod_Q1BSP_FindNonSolidLocation_r_Triangle(findnonsolidlocationinfo_t *info, msurface_t *surface, int k)
- {
- int i, *tri;
- float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3];
- 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);
- if (facenormal[0] || facenormal[1] || facenormal[2])
- {
- VectorNormalize(facenormal);
- f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
- if (f <= info->bestdist && f >= -info->bestdist)
- {
- VectorSubtract(vert[0], vert[2], edge[2]);
- VectorNormalize(edge[0]);
- VectorNormalize(edge[1]);
- VectorNormalize(edge[2]);
- CrossProduct(facenormal, edge[0], edgenormal[0]);
- CrossProduct(facenormal, edge[1], edgenormal[1]);
- CrossProduct(facenormal, edge[2], edgenormal[2]);
- // face distance
- if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0])
- && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1])
- && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2]))
- {
- // we got lucky, the center is within the face
- dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
- if (dist < 0)
- {
- dist = -dist;
- if (info->bestdist > dist)
- {
- info->bestdist = dist;
- VectorScale(facenormal, (info->radius - -dist), info->nudge);
- }
- }
- else
- {
- if (info->bestdist > dist)
- {
- info->bestdist = dist;
- VectorScale(facenormal, (info->radius - dist), info->nudge);
- }
- }
- }
- else
- {
- // check which edge or vertex the center is nearest
- for (i = 0;i < 3;i++)
- {
- f = DotProduct(info->center, edge[i]);
- if (f >= DotProduct(vert[0], edge[i])
- && f <= DotProduct(vert[1], edge[i]))
- {
- // on edge
- VectorMA(info->center, -f, edge[i], point);
- dist = sqrt(DotProduct(point, point));
- if (info->bestdist > dist)
- {
- info->bestdist = dist;
- VectorScale(point, (info->radius / dist), info->nudge);
- }
- // skip both vertex checks
- // (both are further away than this edge)
- i++;
- }
- else
- {
- // not on edge, check first vertex of edge
- VectorSubtract(info->center, vert[i], point);
- dist = sqrt(DotProduct(point, point));
- if (info->bestdist > dist)
- {
- info->bestdist = dist;
- VectorScale(point, (info->radius / dist), info->nudge);
- }
- }
- }
- }
- }
- }
- }
- static void Mod_Q1BSP_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf)
- {
- int surfacenum, k, *mark;
- msurface_t *surface;
- for (surfacenum = 0, mark = leaf->firstleafsurface;surfacenum < leaf->numleafsurfaces;surfacenum++, mark++)
- {
- surface = info->model->data_surfaces + *mark;
- if (surface->texture->supercontents & SUPERCONTENTS_SOLID)
- {
- if(surface->deprecatedq3num_bboxstride > 0)
- {
- int i, cnt, tri;
- cnt = (surface->num_triangles + surface->deprecatedq3num_bboxstride - 1) / surface->deprecatedq3num_bboxstride;
- for(i = 0; i < cnt; ++i)
- {
- if(BoxesOverlap(surface->deprecatedq3data_bbox6f + i * 6, surface->deprecatedq3data_bbox6f + i * 6 + 3, info->absmin, info->absmax))
- {
- for(k = 0; k < surface->deprecatedq3num_bboxstride; ++k)
- {
- tri = i * surface->deprecatedq3num_bboxstride + k;
- if(tri >= surface->num_triangles)
- break;
- Mod_Q1BSP_FindNonSolidLocation_r_Triangle(info, surface, tri);
- }
- }
- }
- }
- else
- {
- for (k = 0;k < surface->num_triangles;k++)
- {
- Mod_Q1BSP_FindNonSolidLocation_r_Triangle(info, surface, k);
- }
- }
- }
- }
- }
- static void Mod_Q1BSP_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node)
- {
- if (node->plane)
- {
- float f = PlaneDiff(info->center, node->plane);
- if (f >= -info->bestdist)
- Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[0]);
- if (f <= info->bestdist)
- Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[1]);
- }
- else
- {
- if (((mleaf_t *)node)->numleafsurfaces)
- Mod_Q1BSP_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node);
- }
- }
- static void Mod_Q1BSP_FindNonSolidLocation(dp_model_t *model, const vec3_t in, vec3_t out, float radius)
- {
- int i;
- findnonsolidlocationinfo_t info;
- if (model == NULL)
- {
- VectorCopy(in, out);
- return;
- }
- VectorCopy(in, info.center);
- info.radius = radius;
- info.model = model;
- i = 0;
- do
- {
- VectorClear(info.nudge);
- info.bestdist = radius;
- VectorCopy(info.center, info.absmin);
- VectorCopy(info.center, info.absmax);
- info.absmin[0] -= info.radius + 1;
- info.absmin[1] -= info.radius + 1;
- info.absmin[2] -= info.radius + 1;
- info.absmax[0] += info.radius + 1;
- info.absmax[1] += info.radius + 1;
- info.absmax[2] += info.radius + 1;
- Mod_Q1BSP_FindNonSolidLocation_r(&info, model->brush.data_nodes + model->brushq1.hulls[0].firstclipnode);
- VectorAdd(info.center, info.nudge, info.center);
- }
- while (info.bestdist < radius && ++i < 10);
- VectorCopy(info.center, out);
- }
- int Mod_Q1BSP_SuperContentsFromNativeContents(int nativecontents)
- {
- switch(nativecontents)
- {
- case CONTENTS_EMPTY:
- return 0;
- case CONTENTS_SOLID:
- return SUPERCONTENTS_SOLID | SUPERCONTENTS_OPAQUE;
- case CONTENTS_WATER:
- return SUPERCONTENTS_WATER;
- case CONTENTS_SLIME:
- return SUPERCONTENTS_SLIME;
- case CONTENTS_LAVA:
- return SUPERCONTENTS_LAVA | SUPERCONTENTS_NODROP;
- case CONTENTS_SKY:
- return SUPERCONTENTS_SKY | SUPERCONTENTS_NODROP | SUPERCONTENTS_OPAQUE; // to match behaviour of Q3 maps, let sky count as opaque
- }
- return 0;
- }
- int Mod_Q1BSP_NativeContentsFromSuperContents(int supercontents)
- {
- if (supercontents & (SUPERCONTENTS_SOLID | SUPERCONTENTS_BODY))
- return CONTENTS_SOLID;
- if (supercontents & SUPERCONTENTS_SKY)
- return CONTENTS_SKY;
- if (supercontents & SUPERCONTENTS_LAVA)
- return CONTENTS_LAVA;
- if (supercontents & SUPERCONTENTS_SLIME)
- return CONTENTS_SLIME;
- if (supercontents & SUPERCONTENTS_WATER)
- return CONTENTS_WATER;
- return CONTENTS_EMPTY;
- }
- typedef struct RecursiveHullCheckTraceInfo_s
- {
- // the hull we're tracing through
- const hull_t *hull;
- // the trace structure to fill in
- trace_t *trace;
- // start, end, and end - start (in model space)
- double start[3];
- double end[3];
- double dist[3];
- }
- RecursiveHullCheckTraceInfo_t;
- // 1/32 epsilon to keep floating point happy
- #define DIST_EPSILON (0.03125)
- #define HULLCHECKSTATE_EMPTY 0
- #define HULLCHECKSTATE_SOLID 1
- #define HULLCHECKSTATE_DONE 2
- 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
- // recursing... but are because this should be thread-safe
- // (note: tracing against a bbox is not thread-safe, yet)
- int ret;
- mplane_t *plane;
- double t1, t2;
- // variables that need to be stored on the stack when recursing
- mclipnode_t *node;
- int p1side, p2side;
- double midf, mid[3];
- // keep looping until we hit a leaf
- while (num >= 0)
- {
- // find the point distances
- node = t->hull->clipnodes + num;
- plane = t->hull->planes + node->planenum;
- // axial planes can be calculated more quickly without the DotProduct
- 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;
- }
- // negative plane distances indicate children[1] (behind plane)
- p1side = t1 < 0;
- p2side = t2 < 0;
- // if the line starts and ends on the same side of the plane, recurse
- // into that child instantly
- if (p1side == p2side)
- {
- #if COLLISIONPARANOID >= 3
- if (p1side)
- Con_Print("<");
- else
- Con_Print(">");
- #endif
- // loop back and process the start child
- num = node->children[p1side];
- }
- else
- {
- // find the midpoint where the line crosses the plane, use the
- // original line for best accuracy
- #if COLLISIONPARANOID >= 3
- Con_Print("M");
- #endif
- if (plane->type < 3)
- {
- t1 = t->start[plane->type] - plane->dist;
- t2 = t->end[plane->type] - plane->dist;
- }
- else
- {
- t1 = DotProduct (plane->normal, t->start) - plane->dist;
- t2 = DotProduct (plane->normal, t->end) - plane->dist;
- }
- midf = t1 / (t1 - t2);
- midf = bound(p1f, midf, p2f);
- VectorMA(t->start, midf, t->dist, mid);
- // we now have a mid point, essentially splitting the line into
- // the segments in the near child and the far child, we can now
- // recurse those in order and get their results
- // recurse both sides, front side first
- ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p1side], p1f, midf, p1, mid);
- // if this side is not empty, return what it is (solid or done)
- if (ret != HULLCHECKSTATE_EMPTY)
- return ret;
- ret = Mod_Q1BSP_RecursiveHullCheck(t, node->children[p2side], midf, p2f, mid, p2);
- // if other side is not solid, return what it is (empty or done)
- if (ret != HULLCHECKSTATE_SOLID)
- return ret;
- // front is air and back is solid, this is the impact point...
- // copy the plane information, flipping it if needed
- if (p1side)
- {
- t->trace->plane.dist = -plane->dist;
- VectorNegate (plane->normal, t->trace->plane.normal);
- }
- else
- {
- t->trace->plane.dist = plane->dist;
- VectorCopy (plane->normal, t->trace->plane.normal);
- }
- // calculate the return fraction which is nudged off the surface a bit
- t1 = DotProduct(t->trace->plane.normal, t->start) - t->trace->plane.dist;
- t2 = DotProduct(t->trace->plane.normal, t->end) - t->trace->plane.dist;
- midf = (t1 - collision_impactnudge.value) / (t1 - t2);
- t->trace->fraction = bound(0, midf, 1);
- #if COLLISIONPARANOID >= 3
- Con_Print("D");
- #endif
- return HULLCHECKSTATE_DONE;
- }
- }
- // we reached a leaf contents
- // check for empty
- num = Mod_Q1BSP_SuperContentsFromNativeContents(num);
- if (!t->trace->startfound)
- {
- t->trace->startfound = true;
- t->trace->startsupercontents |= num;
- }
- if (num & SUPERCONTENTS_LIQUIDSMASK)
- 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
- if (t->trace->allsolid)
- t->trace->startsolid = true;
- #if COLLISIONPARANOID >= 3
- Con_Print("S");
- #endif
- return HULLCHECKSTATE_SOLID;
- }
- else
- {
- t->trace->allsolid = false;
- #if COLLISIONPARANOID >= 3
- Con_Print("E");
- #endif
- return HULLCHECKSTATE_EMPTY;
- }
- }
- //#if COLLISIONPARANOID < 2
- static int Mod_Q1BSP_RecursiveHullCheckPoint(RecursiveHullCheckTraceInfo_t *t, int num)
- {
- mplane_t *plane;
- mclipnode_t *nodes = t->hull->clipnodes;
- mplane_t *planes = t->hull->planes;
- vec3_t point;
- VectorCopy(t->start, point);
- while (num >= 0)
- {
- plane = planes + nodes[num].planenum;
- num = nodes[num].children[(plane->type < 3 ? point[plane->type] : DotProduct(plane->normal, point)) < plane->dist];
- }
- num = Mod_Q1BSP_SuperContentsFromNativeContents(num);
- t->trace->startsupercontents |= num;
- if (num & SUPERCONTENTS_LIQUIDSMASK)
- t->trace->inwater = true;
- if (num == 0)
- t->trace->inopen = true;
- if (num & t->trace->hitsupercontentsmask)
- {
- t->trace->allsolid = t->trace->startsolid = true;
- return HULLCHECKSTATE_SOLID;
- }
- else
- {
- t->trace->allsolid = t->trace->startsolid = false;
- return HULLCHECKSTATE_EMPTY;
- }
- }
- //#endif
- static void Mod_Q1BSP_TracePoint(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
- {
- RecursiveHullCheckTraceInfo_t rhc;
- memset(&rhc, 0, sizeof(rhc));
- memset(trace, 0, sizeof(trace_t));
- rhc.trace = trace;
- rhc.trace->fraction = 1;
- rhc.trace->allsolid = true;
- rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
- VectorCopy(start, rhc.start);
- VectorCopy(start, rhc.end);
- Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
- }
- static void Mod_Q1BSP_TraceLineAgainstSurfaces(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask);
- static void Mod_Q1BSP_TraceLine(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
- {
- RecursiveHullCheckTraceInfo_t rhc;
- if (VectorCompare(start, end))
- {
- Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
- return;
- }
- // sometimes we want to traceline against polygons so we can report the texture that was hit rather than merely a contents, but using this method breaks one of negke's maps so it must be a cvar check...
- if (sv_gameplayfix_q1bsptracelinereportstexture.integer)
- {
- Mod_Q1BSP_TraceLineAgainstSurfaces(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
- return;
- }
- memset(&rhc, 0, sizeof(rhc));
- memset(trace, 0, sizeof(trace_t));
- rhc.trace = trace;
- rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
- rhc.trace->skipsupercontentsmask = skipsupercontentsmask;
- rhc.trace->skipmaterialflagsmask = skipmaterialflagsmask;
- rhc.trace->fraction = 1;
- rhc.trace->allsolid = true;
- rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
- VectorCopy(start, rhc.start);
- VectorCopy(end, rhc.end);
- VectorSubtract(rhc.end, rhc.start, rhc.dist);
- #if COLLISIONPARANOID >= 2
- Con_Printf("t(%f %f %f,%f %f %f)", rhc.start[0], rhc.start[1], rhc.start[2], rhc.end[0], rhc.end[1], rhc.end[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->skipsupercontentsmask = skipsupercontentsmask;
- rhc.trace->skipmaterialflagsmask = skipmaterialflagsmask;
- rhc.trace->fraction = 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))
- Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- else
- Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
- #endif
- }
- static void Mod_Q1BSP_TraceBox(struct model_s *model, const frameblend_t *frameblend, const skeleton_t *skeleton, trace_t *trace, const vec3_t start, const vec3_t boxmins, const vec3_t boxmaxs, const vec3_t end, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask)
- {
- // this function currently only supports same size start and end
- double boxsize[3];
- RecursiveHullCheckTraceInfo_t rhc;
- if (VectorCompare(boxmins, boxmaxs))
- {
- if (VectorCompare(start, end))
- Mod_Q1BSP_TracePoint(model, frameblend, skeleton, trace, start, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
- else
- Mod_Q1BSP_TraceLine(model, frameblend, skeleton, trace, start, end, hitsupercontentsmask, skipsupercontentsmask, skipmaterialflagsmask);
- return;
- }
- memset(&rhc, 0, sizeof(rhc));
- memset(trace, 0, sizeof(trace_t));
- rhc.trace = trace;
- rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
- rhc.trace->skipsupercontentsmask = skipsupercontentsmask;
- rhc.trace->skipmaterialflagsmask = skipmaterialflagsmask;
- rhc.trace->fraction = 1;
- rhc.trace->allsolid = true;
- VectorSubtract(boxmaxs, boxmins, boxsize);
- if (boxsize[0] < 3)
- rhc.hull = &model->brushq1.hulls[0]; // 0x0x0
- else if (model->brush.ishlbsp)
- {
- // LordHavoc: this has to have a minor tolerance (the .1) because of
- // minor float precision errors from the box being transformed around
- if (boxsize[0] < 32.1)
- {
- if (boxsize[2] < 54) // pick the nearest of 36 or 72
- rhc.hull = &model->brushq1.hulls[3]; // 32x32x36
- else
- rhc.hull = &model->brushq1.hulls[1]; // 32x32x72
- }
- else
- rhc.hull = &model->brushq1.hulls[2]; // 64x64x64
- }
- else
- {
- // LordHavoc: this has to have a minor tolerance (the .1) because of
- // minor float precision errors from the box being transformed around
- if (boxsize[0] < 32.1)
- rhc.hull = &model->brushq1.hulls[1]; // 32x32x56
- else
- rhc.hull = &model->brushq1.hulls[2]; // 64x64x88
- }
- VectorMAMAM(1, start, 1, boxmins, -1, rhc.hull->clip_mins, rhc.start);
- VectorMAMAM(1, end, 1, boxmins, -1, rhc.hull->clip_mins, rhc.end);
- VectorSubtract(rhc.end, rhc.start, rhc.dist);
- #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->skipsupercontentsmask = skipsupercontentsmask;
- rhc.trace->skipmaterialflagsmask = skipmaterialflagsmask;
- rhc.trace->fraction = 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))
- Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- else
- Mod_Q1BSP_RecursiveHullCheckPoint(&rhc, rhc.hull->firstclipnode);
- #endif
- }
- static int Mod_Q1BSP_PointSuperContents(struct model_s *model, int frame, const vec3_t point)
- {
- int num = model->brushq1.hulls[0].firstclipnode;
- mplane_t *plane;
- mclipnode_t *nodes = model->brushq1.hulls[0].clipnodes;
- mplane_t *planes = model->brushq1.hulls[0].planes;
- while (num >= 0)
- {
- plane = planes + nodes[num].planenum;
- num = nodes[num].children[(plane->type < 3 ? point[plane->type] : DotProduct(plane->normal, point)) < plane->dist];
- }
- return Mod_Q1BSP_SuperContentsFromNativeContents(num);
- }
- 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 skipsupercontentsmask, int skipmaterialflagsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture)
- {
- #if 1
- colbrushf_t cbox;
- colplanef_t cbox_planes[6];
- cbox.isaabb = true;
- cbox.hasaabbplanes = true;
- cbox.supercontents = boxsupercontents;
- cbox.numplanes = 6;
- cbox.numpoints = 0;
- cbox.numtriangles = 0;
- cbox.planes = cbox_planes;
- cbox.points = NULL;
- cbox.elements = NULL;
- cbox.markframe = 0;
- cbox.mins[0] = 0;
- cbox.mins[1] = 0;
- cbox.mins[2] = 0;
- cbox.maxs[0] = 0;
- cbox.maxs[1] = 0;
- cbox.maxs[2] = 0;
- cbox_planes[0].normal[0] = 1;cbox_planes[0].normal[1] = 0;cbox_planes[0].normal[2] = 0;cbox_planes[0].dist = cmaxs[0] - mins[0];
- cbox_planes[1].normal[0] = -1;cbox_planes[1].normal[1] = 0;cbox_planes[1].normal[2] = 0;cbox_planes[1].dist = maxs[0] - cmins[0];
- cbox_planes[2].normal[0] = 0;cbox_planes[2].normal[1] = 1;cbox_planes[2].normal[2] = 0;cbox_planes[2].dist = cmaxs[1] - mins[1];
- 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->skipsupercontentsmask = skipsupercontentsmask;
- trace->skipmaterialflagsmask = skipmaterialflagsmask;
- trace->fraction = 1;
- Collision_TraceLineBrushFloat(trace, start, end, &cbox, &cbox);
- #else
- RecursiveHullCheckTraceInfo_t rhc;
- static hull_t box_hull;
- static mclipnode_t box_clipnodes[6];
- static mplane_t box_planes[6];
- // fill in a default trace
- memset(&rhc, 0, sizeof(rhc));
- memset(trace, 0, sizeof(trace_t));
- //To keep everything totally uniform, bounding boxes are turned into small
- //BSP trees instead of being compared directly.
- // create a temp hull from bounding box sizes
- box_planes[0].dist = cmaxs[0] - mins[0];
- box_planes[1].dist = cmins[0] - maxs[0];
- box_planes[2].dist = cmaxs[1] - mins[1];
- box_planes[3].dist = cmins[1] - maxs[1];
- box_planes[4].dist = cmaxs[2] - mins[2];
- box_planes[5].dist = cmins[2] - maxs[2];
- #if COLLISIONPARANOID >= 3
- Con_Printf("box_planes %f:%f %f:%f %f:%f\ncbox %f %f %f:%f %f %f\nbox %f %f %f:%f %f %f\n", box_planes[0].dist, box_planes[1].dist, box_planes[2].dist, box_planes[3].dist, box_planes[4].dist, box_planes[5].dist, cmins[0], cmins[1], cmins[2], cmaxs[0], cmaxs[1], cmaxs[2], mins[0], mins[1], mins[2], maxs[0], maxs[1], maxs[2]);
- #endif
- if (box_hull.clipnodes == NULL)
- {
- int i, side;
- //Set up the planes and clipnodes so that the six floats of a bounding box
- //can just be stored out and get a proper hull_t structure.
- box_hull.clipnodes = box_clipnodes;
- box_hull.planes = box_planes;
- box_hull.firstclipnode = 0;
- box_hull.lastclipnode = 5;
- for (i = 0;i < 6;i++)
- {
- box_clipnodes[i].planenum = i;
- side = i&1;
- box_clipnodes[i].children[side] = CONTENTS_EMPTY;
- if (i != 5)
- box_clipnodes[i].children[side^1] = i + 1;
- else
- box_clipnodes[i].children[side^1] = CONTENTS_SOLID;
- box_planes[i].type = i>>1;
- box_planes[i].normal[i>>1] = 1;
- }
- }
- // trace a line through the generated clipping hull
- //rhc.boxsupercontents = boxsupercontents;
- rhc.hull = &box_hull;
- rhc.trace = trace;
- rhc.trace->hitsupercontentsmask = hitsupercontentsmask;
- rhc.trace->skipsupercontentsmask = skipsupercontentsmask;
- rhc.trace->skipmaterialflagsmask = skipmaterialflagsmask;
- rhc.trace->fraction = 1;
- rhc.trace->allsolid = true;
- VectorCopy(start, rhc.start);
- VectorCopy(end, rhc.end);
- VectorSubtract(rhc.end, rhc.start, rhc.dist);
- Mod_Q1BSP_RecursiveHullCheck(&rhc, rhc.hull->firstclipnode, 0, 1, rhc.start, rhc.end);
- //VectorMA(rhc.start, rhc.trace->fraction, rhc.dist, rhc.trace->endpos);
- if (rhc.trace->startsupercontents)
- rhc.trace->startsupercontents = boxsupercontents;
- #endif
- }
- void Collision_ClipTrace_Point(trace_t *trace, const vec3_t cmins, const vec3_t cmaxs, const vec3_t start, int hitsupercontentsmask, int skipsupercontentsmask, int skipmaterialflagsmask, int boxsupercontents, int boxq3surfaceflags, const texture_t *boxtexture)
- {
- memset(trace, 0, sizeof(trace_t));
- trace->fraction = 1;
- trace->hitsupercontentsmask = hitsupercontentsmask;
- trace->skipsupercontentsmask = skipsupercontentsmask;
- trace->skipmaterialflagsmask = skipmaterialflagsmask;
- if (BoxesOverlap(start, start, cmins, cmaxs))
- {
- trace->startsupercontents |= boxsupercontents;
- if ((hitsupercontentsmask & boxsupercontents) && !(skipsupercontentsmask & boxsupercontents))
- {
- trace->startsolid = true;
- trace->allsolid = true;
- }
- }
- }
- static qboolean Mod_Q1BSP_TraceLineOfSight(struct model_s *model, const vec3_t start, const vec3_t end, const vec3_t acceptmins, const vec3_t acceptmaxs)
- {
- trace_t trace;
- Mod_Q1BSP_TraceLine(model, NULL, NULL, &trace, start, end, SUPERCONTENTS_VISBLOCKERMASK, 0, MATERIALFLAGMASK_TRANSLUCENT);
- return trace.fraction == 1 || BoxesOverlap(trace.endpos, trace.endpos, acceptmins, acceptmaxs);
- }
- static int Mod_Q1BSP_LightPoint_RecursiveBSPNode(dp_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;
- float front, back;
- float mid, distz = endz - startz;
- while (node->plane)
- {
- switch (node->plane->type)
- {
- case PLANE_X:
- node = node->children[x < node->plane->dist];
- continue; // loop back and process the new node
- case PLANE_Y:
- node = node->children[y < node->plane->dist];
- continue; // loop back and process the new node
- case PLANE_Z:
- side = startz < node->plane->dist;
- if ((endz < node->plane->dist) == side)
- {
- node = node->children[side];
- continue; // loop back and process the new node
- }
- // found an intersection
- mid = node->plane->dist;
- break;
- default:
- back = front = x * node->plane->normal[0] + y * node->plane->normal[1];
- front += startz * node->plane->normal[2];
- back += endz * node->plane->normal[2];
- side = front < node->plane->dist;
- if ((back < node->plane->dist) == side)
- {
- node = node->children[side];
- continue; // loop back and process the new node
- }
- // found an intersection
- mid = startz + distz * (front - node->plane->dist) / (front - back);
- break;
- }
- // go down front side
- if (node->children[side]->plane && Mod_Q1BSP_LightPoint_RecursiveBSPNode(model, ambientcolor, diffusecolor, diffusenormal, node->children[side], x, y, startz, mid))
- return true; // hit something
- // check for impact on this node
- if (node->numsurfaces)
- {
- unsigned int i;
- int dsi, dti, lmwidth, lmheight;
- float ds, dt;
- msurface_t *surface;
- unsigned char *lightmap;
- int maps, line3, size3;
- float dsfrac;
- float dtfrac;
- float scale, w, w00, w01, w10, w11;
- surface = model->data_surfaces + node->firstsurface;
- for (i = 0;i < node->numsurfaces;i++, surface++)
- {
- if (!(surface->texture->basematerialflags & MATERIALFLAG_WALL) || !surface->lightmapinfo || !surface->lightmapinfo->samples)
- continue; // no lightmaps
- // location we want to sample in the lightmap
- ds = ((x * surface->lightmapinfo->texinfo->vecs[0][0] + y * surface->lightmapinfo->texinfo->vecs[0][1] + mid * surface->lightmapinfo->texinfo->vecs[0][2] + surface->lightmapinfo->texinfo->vecs[0][3]) - surface->lightmapinfo->texturemins[0]) * 0.0625f;
- dt = ((x * surface->lightmapinfo->texinfo->vecs[1][0] + y * surface->lightmapinfo->texinfo->vecs[1][1] + mid * surface->lightmapinfo->texinfo->vecs[1][2] + surface->lightmapinfo->texinfo->vecs[1][3]) - surface->lightmapinfo->texturemins[1]) * 0.0625f;
- // check the bounds
- // thanks to jitspoe for pointing out that this int cast was
- // rounding toward zero, so we floor it
- dsi = (int)floor(ds);
- dti = (int)floor(dt);
- lmwidth = ((surface->lightmapinfo->extents[0]>>4)+1);
- lmheight = ((surface->lightmapinfo->extents[1]>>4)+1);
- // is it in bounds?
- // we have to tolerate a position of lmwidth-1 for some rare
- // cases - in which case the sampling position still gets
- // clamped but the color gets interpolated to that edge.
- if (dsi >= 0 && dsi < lmwidth && dti >= 0 && dti < lmheight)
- {
- // in the rare cases where we're sampling slightly off
- // the polygon, clamp the sampling position (we can still
- // interpolate outside it, where it becomes extrapolation)
- if (dsi < 0)
- dsi = 0;
- if (dti < 0)
- dti = 0;
- if (dsi > lmwidth-2)
- dsi = lmwidth-2;
- if (dti > lmheight-2)
- dti = lmheight-2;
-
- // calculate bilinear interpolation factors
- // and also multiply by fixedpoint conversion factors to
- // compensate for lightmaps being 0-255 (as 0-2), we use
- // r_refdef.scene.rtlightstylevalue here which is already
- // 0.000-2.148 range
- // (if we used r_refdef.scene.lightstylevalue this
- // divisor would be 32768 rather than 128)
- dsfrac = ds - dsi;
- dtfrac = dt - dti;
- w00 = (1 - dsfrac) * (1 - dtfrac) * (1.0f / 128.0f);
- w01 = ( dsfrac) * (1 - dtfrac) * (1.0f / 128.0f);
- w10 = (1 - dsfrac) * ( dtfrac) * (1.0f / 128.0f);
- w11 = ( dsfrac) * ( dtfrac) * (1.0f / 128.0f);
- // values for pointer math
- line3 = lmwidth * 3; // LordHavoc: *3 for colored lighting
- size3 = lmwidth * lmheight * 3; // LordHavoc: *3 for colored lighting
- // look up the pixel
- lightmap = surface->lightmapinfo->samples + dti * line3 + dsi*3; // LordHavoc: *3 for colored lighting
- // bilinear filter each lightmap style, and sum them
- for (maps = 0;maps < MAXLIGHTMAPS && surface->lightmapinfo->styles[maps] != 255;maps++)
- {
- scale = r_refdef.scene.rtlightstylevalue[surface->lightmapinfo->styles[maps]];
- w = w00 * scale;VectorMA(ambientcolor, w, lightmap , ambientcolor);
- w = w01 * scale;VectorMA(ambientcolor, w, lightmap + 3 , ambientcolor);
- w = w10 * scale;VectorMA(ambientcolor, w, lightmap + line3 , ambientcolor);
- w = w11 * scale;VectorMA(ambientcolor, w, lightmap + line3 + 3, ambientcolor);
- lightmap += size3;
- }
- return true; // success
- }
- }
- }
- // go down back side
- node = node->children[side ^ 1];
- startz = mid;
- distz = endz - startz;
- // loop back and process the new node
- }
- // did not hit anything
- return false;
- }
- static void Mod_Q1BSP_LightPoint(dp_model_t *model, const vec3_t p, vec3_t ambientcolor, vec3_t diffusecolor, vec3_t diffusenormal)
- {
- // pretend lighting is coming down fro…
Large files files are truncated, but you can click here to view the full file