diff --git a/include/light/light.hh b/include/light/light.hh index 32cd48fc..57dc4a70 100644 --- a/include/light/light.hh +++ b/include/light/light.hh @@ -410,12 +410,6 @@ extern qboolean novisapprox; extern bool nolights; extern bool litonly; -typedef enum { - backend_bsp, - backend_embree -} backend_t; - -extern backend_t rtbackend; extern qboolean surflight_dump; extern char mapfilename[1024]; diff --git a/include/light/trace.hh b/include/light/trace.hh index 83be679e..36e70d49 100644 --- a/include/light/trace.hh +++ b/include/light/trace.hh @@ -43,8 +43,6 @@ enum class hittype_t : uint8_t { SKY = 2 }; -const mleaf_t *Light_PointInLeaf( const mbsp_t *bsp, const vec3_t point ); -int Light_PointContents( const mbsp_t *bsp, const vec3_t point ); uint32_t clamp_texcoord(vec_t in, uint32_t width); color_rgba SampleTexture(const bsp2_dface_t *face, const mbsp_t *bsp, const vec3_t point); //mxd. Palette index -> RGBA @@ -68,9 +66,6 @@ struct hitresult_t { */ hitresult_t TestSky(const vec3_t start, const vec3_t dirn, const modelinfo_t *self, const bsp2_dface_t **face_out); hitresult_t TestLight(const vec3_t start, const vec3_t stop, const modelinfo_t *self); -#if 0 -hittype_t DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const modelinfo_t *self, vec_t *hitdist_out, plane_t *hitplane_out, const bsp2_dface_t **face_out); -#endif class modelinfo_t; diff --git a/light/light.cc b/light/light.cc index 3c226ff9..7e23d040 100644 --- a/light/light.cc +++ b/light/light.cc @@ -100,7 +100,6 @@ int write_luxfile = 0; /* 0 for none, 1 for .lux, 2 for bspx, 3 for both */ qboolean onlyents = false; qboolean novisapprox = false; bool nolights = false; -backend_t rtbackend = backend_embree; bool debug_highlightseams = false; debugmode_t debugmode = debugmode_none; bool verbose_log = false; @@ -1041,15 +1040,6 @@ light_main(int argc, const char **argv) } else if ( !strcmp( argv[ i ], "-nolights" ) ) { nolights = true; logprint( "Skipping all light entities (sunlight / minlight only)\n" ); - } else if ( !strcmp( argv[ i ], "-backend" ) ) { - const char *requested = ParseString(&i, argc, argv); - if (!strcmp(requested, "bsp")) { - rtbackend = backend_bsp; - } else if (!strcmp(requested, "embree")) { - rtbackend = backend_embree; - } else { - Error("unknown backend %s", requested); - } } else if ( !strcmp( argv[ i ], "-debugface" ) ) { ParseVec3(dump_face_point, &i, argc, argv); dump_face = true; @@ -1118,19 +1108,7 @@ light_main(int argc, const char **argv) if (debugmode != debugmode_none) { write_litfile |= 1; } - -#ifndef HAVE_EMBREE - if (rtbackend == backend_embree) { - rtbackend = backend_bsp; - } -#endif - - logprint("Raytracing backend: "); - switch (rtbackend) { - case backend_bsp: logprint("BSP\n"); break; - case backend_embree: logprint("Embree\n"); break; - } - + if (numthreads > 1) logprint("running with %d threads\n", numthreads); diff --git a/light/trace.cc b/light/trace.cc index 0e0876f8..a18bfa32 100644 --- a/light/trace.cc +++ b/light/trace.cc @@ -26,259 +26,6 @@ #endif #include -#define TRACE_HIT_NONE 0 -#define TRACE_HIT_SOLID (1 << 0) -#define TRACE_HIT_WATER (1 << 1) -#define TRACE_HIT_SLIME (1 << 2) -#define TRACE_HIT_LAVA (1 << 3) -#define TRACE_HIT_SKY (1 << 4) - -typedef struct traceinfo_s { - vec3_t point; - const bsp2_dface_t *face; - plane_t hitplane; - /* returns true if sky was hit. */ - bool hitsky; - bool hitback; - - // internal - vec3_t dir; -} traceinfo_t; - -/* Stopped by solid and sky */ -static bool TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end); - -/* - * --------- - * TraceLine - * --------- - * Generic BSP model ray tracing function. Traces a ray from start towards - * stop. If the trace line hits one of the flagged contents along the way, the - * corresponding TRACE flag will be returned. - * - * model - The bsp model to trace against - * flags - contents which will stop the trace (must be > 0) - * start - coordinates to start trace - * stop - coordinates to end the trace - * - * TraceLine will return a negative traceflag if the point 'start' resides - * inside a leaf with one of the contents types which stop the trace. - * - * ericw -- note, this should only be used for testing occlusion. - * the hitpoint is not accurate, imagine a solid cube floating in a room, - * only one of the 6 sides will be a node with a solid leaf child. - * Yet, which side is the node with the solid leaf child determines - * what the hit point will be. - */ -static int TraceLine(const dmodel_t *model, const int traceflags, - const vec3_t start, const vec3_t end); - -typedef struct tnode_s { - vec3_t normal; - vec_t dist; - int type; - int children[2]; - const dplane_t *plane; - const mleaf_t *childleafs[2]; - const bsp2_dnode_t *node; -} tnode_t; - -typedef struct faceinfo_s { - int numedges; - plane_t *edgeplanes; - - // sphere culling - vec3_t origin; - vec_t radiusSquared; - - int content_or_surf_flags; - plane_t plane; - - const char *texturename; - const bsp2_dface_t *face; -} faceinfo_t; - -static tnode_t *tnodes; -static const mbsp_t *bsp_static; - -static faceinfo_t *faceinfos; -static bool *fence_dmodels; // bsp_static->nummodels bools, true if model contains a fence texture - -// from hmap2 -#define PlaneDiff(point,plane) (((plane)->type < 3 ? (point)[(plane)->type] : DotProduct((point), (plane)->normal)) - (plane)->dist) - -/* -============== -Light_PointInLeaf - -from hmap2 -============== -*/ -const mleaf_t * -Light_PointInLeaf( const mbsp_t *bsp, const vec3_t point ) -{ - int num = 0; - - while( num >= 0 ) - num = bsp->dnodes[num].children[PlaneDiff(point, &bsp->dplanes[bsp->dnodes[num].planenum]) < 0]; - - return bsp->dleafs + (-1 - num); -} - -/* -============== -Light_PointContents - -from hmap2 -============== -*/ -int Light_PointContents( const mbsp_t *bsp, const vec3_t point ) -{ - return Light_PointInLeaf(bsp, point)->contents; -} - -/* - * ============== - * MakeTnodes - * Converts the disk node structure into the efficient tracing structure - * ============== - */ -static void -MakeTnodes_r(int nodenum, const mbsp_t *bsp) -{ - tnode_t *tnode; - int i; - bsp2_dnode_t *node; - mleaf_t *leaf; - - Q_assert(nodenum >= 0); - Q_assert(nodenum < bsp->numnodes); - tnode = &tnodes[nodenum]; - - node = bsp->dnodes + nodenum; - tnode->plane = bsp->dplanes + node->planenum; - tnode->node = node; - - tnode->type = tnode->plane->type; - VectorCopy(tnode->plane->normal, tnode->normal); - tnode->dist = tnode->plane->dist; - - for (i = 0; i < 2; i++) { - int childnum = node->children[i]; - if (childnum < 0) { - leaf = &bsp->dleafs[-childnum - 1]; - tnode->children[i] = leaf->contents; - tnode->childleafs[i] = leaf; - } else { - tnode->children[i] = childnum; - MakeTnodes_r(childnum, bsp); - } - } -} - -static inline bool SphereCullPoint(const faceinfo_t *info, const vec3_t point) -{ - vec3_t delta; - vec_t deltaLengthSquared; - VectorSubtract(point, info->origin, delta); - deltaLengthSquared = DotProduct(delta, delta); - return deltaLengthSquared > info->radiusSquared; -} - -static void -MakeFaceInfo(const mbsp_t *bsp, const bsp2_dface_t *face, faceinfo_t *info) -{ - info->face = face; - info->numedges = face->numedges; - info->edgeplanes = Face_AllocInwardFacingEdgePlanes(bsp, face); - - info->plane = Face_Plane(bsp, face); - - // make sphere that bounds the face - vec3_t centroid = {0,0,0}; - for (int i=0; inumedges; i++) - { - const vec_t *v = GetSurfaceVertexPoint(bsp, face, i); - VectorAdd(centroid, v, centroid); - } - VectorScale(centroid, 1.0f/face->numedges, centroid); - VectorCopy(centroid, info->origin); - - // calculate radius - vec_t maxRadiusSq = 0; - for (int i=0; inumedges; i++) - { - vec3_t delta; - vec_t radiusSq; - const vec_t *v = GetSurfaceVertexPoint(bsp, face, i); - VectorSubtract(v, centroid, delta); - radiusSq = DotProduct(delta, delta); - if (radiusSq > maxRadiusSq) - maxRadiusSq = radiusSq; - } - info->radiusSquared = maxRadiusSq; - - info->content_or_surf_flags = Face_ContentsOrSurfaceFlags(bsp, face); - - info->texturename = Face_TextureName(bsp, face); - -#if 0 - //test - for (int i=0; inumedges; i++) - { - const vec_t *v = GetSurfaceVertexPoint(bsp, face, i); - Q_assert(!SphereCullPoint(info, v)); - } - //test - { - vec_t radius = sqrt(maxRadiusSq); - radius ++; - - vec3_t test; - vec3_t n = {1, 0, 0}; - VectorMA(centroid, radius, n, test); - - Q_assert(SphereCullPoint(info, test)); - } -#endif -} - -static bool -Model_HasFence(const mbsp_t *bsp, const dmodel_t *model) -{ - for (int j = model->firstface; j < model->firstface + model->numfaces; j++) { - const bsp2_dface_t *face = BSP_GetFace(bsp, j); - if (Face_TextureName(bsp, face)[0] == '{') { - return true; - } - } - return false; -} - -static void -MakeFenceInfo(const mbsp_t *bsp) -{ - fence_dmodels = (bool *) calloc(bsp->nummodels, sizeof(bool)); - for (int i = 0; i < bsp->nummodels; i++) { - fence_dmodels[i] = Model_HasFence(bsp, &bsp->dmodels[i]); - } -} - -static void -BSP_MakeTnodes(const mbsp_t *bsp) -{ - bsp_static = bsp; - tnodes = (tnode_t *) malloc(bsp->numnodes * sizeof(tnode_t)); - for (int i = 0; i < bsp->nummodels; i++) - MakeTnodes_r(bsp->dmodels[i].headnode[0], bsp); - - faceinfos = (faceinfo_t *) malloc(bsp->numfaces * sizeof(faceinfo_t)); - for (int i = 0; i < bsp->numfaces; i++) - MakeFaceInfo(bsp, BSP_GetFace(bsp, i), &faceinfos[i]); - - MakeFenceInfo(bsp); -} - /* * ============================================================================ * FENCE TEXTURE TESTING @@ -337,464 +84,14 @@ SampleTexture(const bsp2_dface_t *face, const mbsp_t *bsp, const vec3_t point) #endif } -/* assumes point is on the same plane as face */ -static inline qboolean -TestHitFace(const faceinfo_t *fi, const vec3_t point) -{ - return EdgePlanes_PointInside(fi->face, fi->edgeplanes, point); -} - -static inline bsp2_dface_t * -SearchNodeForHitFace(const bsp2_dnode_t *bspnode, const vec3_t point) -{ - // search the faces on this node - int i; - for (i=0; inumfaces; i++) - { - int facenum = bspnode->firstface + i; - const faceinfo_t *fi = &faceinfos[facenum]; - - if (SphereCullPoint(fi, point)) - continue; - - if (TestHitFace(fi, point)) { - return &bsp_static->dfaces[facenum]; - } - } - return NULL; -} - -/* - * ============================================================================ - * LINE TRACING - * The major lighting operation is a point to point visibility test, performed - * by recursive subdivision of the line by the BSP tree. - * ============================================================================ - */ - -typedef struct { - vec3_t back; - vec3_t front; - int node; - int side; - const dplane_t *plane; -} tracestack_t; - -/* - * ============== - * TraceLine - * ============== - */ -#define MAX_TSTACK 256 -static int -TraceLine(const dmodel_t *model, const int traceflags, - const vec3_t start, const vec3_t stop) -{ - int node, side, tracehit; - vec3_t front, back; - vec_t frontdist, backdist; - tracestack_t tracestack[MAX_TSTACK]; - tracestack_t *tstack, *crossnode; - tnode_t *tnode; - - // Special case for bmodels with fence textures - const int modelnum = model - &bsp_static->dmodels[0]; - if (modelnum != 0 && fence_dmodels[modelnum]) { - traceinfo_t ti = {0}; - bool hit = TraceFaces(&ti, model->headnode[0], start, stop); - if (hit && ti.hitsky && (traceflags & TRACE_HIT_SKY)) { - return TRACE_HIT_SKY; - } else if (hit && !ti.hitsky && (traceflags & TRACE_HIT_SOLID)) { - return TRACE_HIT_SOLID; - } - return TRACE_HIT_NONE; - } - - // FIXME: check for stack overflow -// const tracestack_t *const tstack_max = tracestack + MAX_TSTACK; - - if (traceflags <= 0) - Error("Internal error: %s - bad traceflags (%d)", - __func__, traceflags); - - VectorCopy(start, front); - VectorCopy(stop, back); - - tstack = tracestack; - node = model->headnode[0]; - crossnode = NULL; - tracehit = TRACE_HIT_NONE; - - while (1) { - while (node < 0) { - switch (node) { - case CONTENTS_SOLID: - if (traceflags & TRACE_HIT_SOLID) - tracehit = TRACE_HIT_SOLID; - break; - case CONTENTS_WATER: - if (traceflags & TRACE_HIT_WATER) - tracehit = TRACE_HIT_WATER; - break; - case CONTENTS_SLIME: - if (traceflags & TRACE_HIT_SLIME) - tracehit = TRACE_HIT_SLIME; - break; - case CONTENTS_LAVA: - if (traceflags & TRACE_HIT_LAVA) - tracehit = TRACE_HIT_LAVA; - break; - case CONTENTS_SKY: - if (traceflags & TRACE_HIT_SKY) - tracehit = TRACE_HIT_SKY; - break; - default: - break; - } - if (tracehit != TRACE_HIT_NONE) { - /* If we haven't crossed, start was inside flagged contents */ - if (!crossnode) - return -tracehit; - - return tracehit; - } - - /* If the stack is empty, no obstructions were hit */ - if (tstack == tracestack) - return TRACE_HIT_NONE; - - /* Pop the stack and go down the back side */ - crossnode = --tstack; - VectorCopy(tstack->front, front); - VectorCopy(tstack->back, back); - node = tnodes[tstack->node].children[!tstack->side]; - } - - tnode = &tnodes[node]; - switch (tnode->type) { - case PLANE_X: - frontdist = front[0] - tnode->dist; - backdist = back[0] - tnode->dist; - break; - case PLANE_Y: - frontdist = front[1] - tnode->dist; - backdist = back[1] - tnode->dist; - break; - case PLANE_Z: - frontdist = front[2] - tnode->dist; - backdist = back[2] - tnode->dist; - break; - default: - frontdist = DotProduct(front, tnode->normal) - tnode->dist; - backdist = DotProduct(back, tnode->normal) - tnode->dist; - break; - } - - if (frontdist >= -ON_EPSILON && backdist >= -ON_EPSILON) { - node = tnode->children[0]; - continue; - } - if (frontdist < ON_EPSILON && backdist < ON_EPSILON) { - node = tnode->children[1]; - continue; - } - - /* - * If we get here, we have a clean split with front and back on - * opposite sides. The new back is the intersection point with the - * node plane. Push the other segment onto the stack and continue. - */ - side = frontdist < 0; - tstack->node = node; - tstack->side = side; - tstack->plane = tnode->plane; - VectorCopy(back, tstack->back); - VectorSubtract(back, front, back); - VectorMA(front, frontdist / (frontdist - backdist), back, back); - VectorCopy(back, tstack->front); - crossnode = tstack++; - node = tnode->children[side]; - } -} - -static qboolean -BSP_TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self) -{ - const int traceflags = TRACE_HIT_SOLID; - int result = TRACE_HIT_NONE; - - /* Check against the list of global shadow casters */ - for (const modelinfo_t *model : tracelist) { - if (model->model == self) - continue; - result = TraceLine(model->model, traceflags, start, stop); - if (result != TRACE_HIT_NONE) - break; - } - - /* If not yet obscured, check against the self-shadow model */ - if (result == TRACE_HIT_NONE && self) - result = TraceLine(self, traceflags, start, stop); - - return (result == TRACE_HIT_NONE); -} - -static qboolean -BSP_TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self) -{ - //const modelinfo_t *const *model; - int traceflags = TRACE_HIT_SKY | TRACE_HIT_SOLID; - int result = TRACE_HIT_NONE; - vec3_t stop; - - /* Trace towards the sunlight for a sky brush */ - VectorAdd(dirn, start, stop); - result = TraceLine(tracelist[0]->model, traceflags, start, stop); - if (result != TRACE_HIT_SKY) - return false; - - /* If good, check it isn't shadowed by another model */ - traceflags = TRACE_HIT_SOLID; - for (const modelinfo_t *model : tracelist) { - if (model == tracelist.at(0)) - continue; - if (model->model == self) - continue; - result = TraceLine(model->model, traceflags, start, stop); - if (result != TRACE_HIT_NONE) - return false; - } - - /* Check for self-shadowing */ - if (self) { - result = TraceLine(self, traceflags, start, stop); - if (result != TRACE_HIT_NONE) - return false; - } - - return true; -} - -/* - * ============ - * DirtTrace - * - * returns true if the trace from start to stop hits something solid, - * or if it started in the void. - * ============ - */ -static hittype_t -BSP_DirtTrace(const vec3_t start, const vec3_t dirn, const vec_t dist, const dmodel_t *self, vec_t *hitdist_out, plane_t *hitplane_out, const bsp2_dface_t **face_out) -{ - vec3_t stop; - VectorMA(start, dist, dirn, stop); - - traceinfo_t ti = {0}; - VectorCopy(dirn, ti.dir); - - if (self) { - if (TraceFaces (&ti, self->headnode[0], start, stop)) { - if (hitdist_out) { - vec3_t delta; - VectorSubtract(ti.point, start, delta); - *hitdist_out = VectorLength(delta); - } - if (hitplane_out) { - *hitplane_out = ti.hitplane; - } - if (face_out) { - *face_out = ti.face; - } - return ti.hitsky ? hittype_t::SKY : hittype_t::SOLID; - } - } - - /* Check against the list of global shadow casters */ - for (const modelinfo_t *model : tracelist) { - if (model->model == self) - continue; - if (TraceFaces (&ti, model->model->headnode[0], start, stop)) { - if (hitdist_out) { - vec3_t delta; - VectorSubtract(ti.point, start, delta); - *hitdist_out = VectorLength(delta); - } - if (hitplane_out) { - *hitplane_out = ti.hitplane; - } - if (face_out) { - *face_out = ti.face; - } - return ti.hitsky ? hittype_t::SKY : hittype_t::SOLID; - } - } - - return hittype_t::NONE; -} - -static bool -BSP_IntersectSingleModel(const vec3_t start, const vec3_t dirn, vec_t dist, const dmodel_t *self, vec_t *hitdist_out) -{ - vec3_t stop; - VectorMA(start, dist, dirn, stop); - - traceinfo_t ti = {0}; - VectorCopy(dirn, ti.dir); - - if (TraceFaces (&ti, self->headnode[0], start, stop)) { - if (hitdist_out) { - vec3_t delta; - VectorSubtract(ti.point, start, delta); - *hitdist_out = VectorLength(delta); - } - return true; - } - return false; -} - -/* -============= -TraceFaces - -From lordhavoc, johnfitz (RecursiveLightPoint) -============= -*/ -static bool -TraceFaces (traceinfo_t *ti, int node, const vec3_t start, const vec3_t end) -{ - float front, back, frac; - vec3_t mid; - tnode_t *tnode; - - if (node < 0) - return false; // didn't hit anything - - tnode = &tnodes[node]; //ericw - - // calculate mid point - if (tnode->type < 3) - { - front = start[tnode->type] - tnode->dist; - back = end[tnode->type] - tnode->dist; - } - else - { - front = DotProduct(start, tnode->normal) - tnode->dist; - back = DotProduct(end, tnode->normal) - tnode->dist; - } - - if ((back < 0) == (front < 0)) - return TraceFaces (ti, tnode->children[front < 0], start, end); - - frac = front / (front-back); - mid[0] = start[0] + (end[0] - start[0])*frac; - mid[1] = start[1] + (end[1] - start[1])*frac; - mid[2] = start[2] + (end[2] - start[2])*frac; - - // go down front side - if (TraceFaces (ti, tnode->children[front < 0], start, mid)) - return true; // hit something - else - { - // check for impact on this node - VectorCopy (mid, ti->point); - //ti->lightplane = tnode->plane; - - bsp2_dface_t *face = SearchNodeForHitFace(tnode->node, mid); - if (face) { - const int facenum = face - bsp_static->dfaces; - const faceinfo_t *fi = &faceinfos[facenum]; - - // check fence - bool passedThroughFence = false; - if (fi->texturename[0] == '{') { - const color_rgba sample = SampleTexture(face, bsp_static, mid); //mxd. Palette index -> RGBA - if (sample.a < 255) { - passedThroughFence = true; - } - } - - // only solid and sky faces stop the trace. - bool issolid, issky; //mxd - if(bsp_static->loadversion->game->id == GAME_QUAKE_II) { - issolid = !(fi->content_or_surf_flags & Q2_SURF_TRANSLUCENT); - issky = (fi->content_or_surf_flags & Q2_SURF_SKY); - } else { - issolid = (fi->content_or_surf_flags == CONTENTS_SOLID); - issky = (fi->content_or_surf_flags == CONTENTS_SKY); - } - - if (!passedThroughFence && (issolid || issky)) { - ti->face = face; - ti->hitsky = issky; - VectorCopy(fi->plane.normal, ti->hitplane.normal); - ti->hitplane.dist = fi->plane.dist; - - // check if we hit the back side - ti->hitback = (DotProduct(ti->dir, fi->plane.normal) >= 0); - - return true; - } - } - - //ericw -- no impact found on this node. - - // go down back side - return TraceFaces (ti, tnode->children[front >= 0], mid, end); - } -} - -// -// Embree wrappers -// - hitresult_t TestSky(const vec3_t start, const vec3_t dirn, const modelinfo_t *self, const bsp2_dface_t **face_out) { -#ifdef HAVE_EMBREE - if (rtbackend == backend_embree) { - return Embree_TestSky(start, dirn, self, face_out); - } -#endif -#if 0 - if (rtbackend == backend_bsp) { - return BSP_TestSky(start, dirn, self); - } -#endif - Error("no backend available"); - throw; //mxd. Silences compiler warning + return Embree_TestSky(start, dirn, self, face_out); } hitresult_t TestLight(const vec3_t start, const vec3_t stop, const modelinfo_t *self) { -#ifdef HAVE_EMBREE - if (rtbackend == backend_embree) { - return Embree_TestLight(start, stop, self); - } -#endif -#if 0 - if (rtbackend == backend_bsp) { - return BSP_TestLight(start, stop, self); - } -#endif - Error("no backend available"); - throw; //mxd. Silences compiler warning -} - - -hittype_t DirtTrace(const vec3_t start, const vec3_t dirn, vec_t dist, const modelinfo_t *self, vec_t *hitdist_out, plane_t *hitplane_out, const bsp2_dface_t **face_out) -{ -#ifdef HAVE_EMBREE - if (rtbackend == backend_embree) { - return Embree_DirtTrace(start, dirn, dist, self, hitdist_out, hitplane_out, face_out); - } -#endif -#if 0 - if (rtbackend == backend_bsp) { - return BSP_DirtTrace(start, dirn, dist, self, hitdist_out, hitplane_out, face_out); - } -#endif - Error("no backend available"); - throw; //mxd. Silences compiler warning + return Embree_TestLight(start, stop, self); } raystream_intersection_t *MakeIntersectionRayStream(int maxrays) {