From a0f636a69a2356dcc3f86a329be8fa4712574c8a Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Thu, 19 May 2016 02:53:18 -0600 Subject: [PATCH] light: bounce: refactor to do in a second lighting pass --- include/light/light.h | 21 ++++++++-- light/light.cc | 93 +++++++++++++++++++++++++++++++++++------ light/ltface.c | 96 +++++++++++++++++++++++++++++++++++-------- light/trace.c | 2 +- 4 files changed, 179 insertions(+), 33 deletions(-) diff --git a/include/light/light.h b/include/light/light.h index 48cb8e43..30952b7b 100644 --- a/include/light/light.h +++ b/include/light/light.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -48,6 +49,9 @@ qboolean TestSky(const vec3_t start, const vec3_t dirn, const dmodel_t *self); qboolean TestLight(const vec3_t start, const vec3_t stop, const dmodel_t *self); qboolean DirtTrace(const vec3_t start, const vec3_t stop, const dmodel_t *self, vec3_t hitpoint_out, plane_t *hitplane_out, const bsp2_dface_t **face_out); +int +SampleTexture(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point); + typedef struct { vec_t light; vec3_t color; @@ -134,6 +138,10 @@ typedef struct { /* for sphere culling */ vec3_t origin; vec_t radius; + + // for radiosity + vec3_t radiosity; + vec3_t texturecolor; /* stuff used by CalcPoint */ vec_t starts, startt, st_step; @@ -153,6 +161,8 @@ struct ltface_ctx lightmap_t lightmaps[MAXLIGHTMAPS + 1]; }; +extern struct ltface_ctx *ltface_ctxs; + /* bounce lights */ typedef struct { @@ -162,7 +172,12 @@ typedef struct { vec_t area; const bsp2_dleaf_t *leaf; } bouncelight_t; - + +void AddBounceLight(const vec3_t pos, const vec3_t color, const vec3_t surfnormal, vec_t area, const bsp2_t *bsp); +int NumBounceLights(); +const bouncelight_t *BounceLightAtIndex(int i); +winding_t *WindingFromFace (const bsp2_t *bsp, const bsp2_dface_t *f); + extern const bouncelight_t *bouncelights; extern int numbouncelights; extern byte thepalette[768]; @@ -171,11 +186,11 @@ extern byte thepalette[768]; extern const modelinfo_t *const *tracelist; extern const modelinfo_t *const *selfshadowlist; -struct ltface_ctx; -struct ltface_ctx *LightFaceInit(const bsp2_t *bsp); +void LightFaceInit(const bsp2_t *bsp, struct ltface_ctx *ctx); void LightFaceShutdown(struct ltface_ctx *ctx); const modelinfo_t *ModelInfoForFace(const bsp2_t *bsp, int facenum); void LightFace(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, struct ltface_ctx *ctx); +void LightFaceIndirect(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, struct ltface_ctx *ctx); void MakeTnodes(const bsp2_t *bsp); /* access the final phong-shaded vertex normal */ diff --git a/light/light.cc b/light/light.cc index d2c78bc4..c44ccca3 100644 --- a/light/light.cc +++ b/light/light.cc @@ -109,6 +109,8 @@ uint32_t *extended_texinfo_flags = NULL; char mapfilename[1024]; +struct ltface_ctx *ltface_ctxs; + void GetFileSpace(byte **lightdata, byte **colordata, byte **deluxdata, int size) { @@ -175,7 +177,9 @@ LightThread(void *arg) if (facenum == -1) break; - ctx = LightFaceInit(bsp); + ctx = <face_ctxs[facenum]; + + LightFaceInit(bsp, ctx); /* Find the correct model offset */ face_modelinfo = ModelInfoForFace(bsp, facenum); @@ -206,12 +210,44 @@ LightThread(void *arg) LightFace(bsp->dfaces + facenum, faces_sup + facenum, face_modelinfo, ctx); } - LightFaceShutdown(ctx); + /* If bouncing, keep lightmaps in memory because we run a second lighting pass. + * Otherwise free memory now, so only (# threads) lightmaps are in memory at a time. + */ + if (!bounce) { + LightFaceShutdown(ctx); + } } return NULL; } +static void * +LightThreadBounce(void *arg) +{ + int facenum; + const bsp2_t *bsp = (const bsp2_t *) arg; + const modelinfo_t *face_modelinfo; + struct ltface_ctx *ctx; + + while (1) { + facenum = GetThreadWork(); + if (facenum == -1) + break; + + ctx = <face_ctxs[facenum]; + + /* Find the correct model offset */ + face_modelinfo = ModelInfoForFace(bsp, facenum); + if (face_modelinfo == NULL) + continue; + + LightFaceIndirect(bsp->dfaces + facenum, NULL, face_modelinfo, ctx); + LightFaceShutdown(ctx); + } + + return NULL; +} + static void FindModelInfo(const bsp2_t *bsp, const char *lmscaleoverride) { @@ -692,9 +728,18 @@ LightWorld(bspdata_t *bspdata, qboolean forcedscale) CalcualateVertexNormals(bsp); + /* ericw -- alloc memory */ + ltface_ctxs = (struct ltface_ctx *)calloc(bsp->numfaces, sizeof(struct ltface_ctx)); + + logprint("==LightThread==\n"); RunThreadsOn(0, bsp->numfaces, LightThread, bsp); - logprint("Lighting Completed.\n\n"); + if (bounce) { + logprint("==LightThreadBounce==\n"); + RunThreadsOn(0, bsp->numfaces, LightThreadBounce, bsp); + } + + logprint("Lighting Completed.\n\n"); bsp->lightdatasize = file_p - filebase; logprint("lightdatasize: %i\n", bsp->lightdatasize); @@ -760,12 +805,11 @@ LoadExtendedTexinfoFlags(const char *sourcefilename, const bsp2_t *bsp) // radiosity + +mutex radlights_lock; map texturecolors; std::vector radlights; -// for access from C -const bouncelight_t *bouncelights; -int numbouncelights; class patch_t { public: @@ -790,6 +834,7 @@ public: } }; +#if 0 void GetDirectLighting(const vec3_t origin, const vec3_t normal, vec3_t colorout) { @@ -826,6 +871,7 @@ GetDirectLighting(const vec3_t origin, const vec3_t normal, vec3_t colorout) std::vector triangleIndexToPatch; std::unordered_map> facenumToPatches; mutex facenumToPatches_mutex; +#endif /* ============= @@ -863,7 +909,7 @@ winding_t *WindingFromFace (const bsp2_t *bsp, const bsp2_dface_t *f) return w; } - +#if 0 void SavePatch (const bsp2_t *bsp, const bsp2_dface_t *sourceface, winding_t *w) { int i = sourceface - bsp->dfaces; @@ -983,6 +1029,32 @@ MakeBounceLightsThread (void *arg) return NULL; } +#endif + +void AddBounceLight(const vec3_t pos, const vec3_t color, const vec3_t surfnormal, vec_t area, const bsp2_t *bsp) +{ + bouncelight_t l; + VectorCopy(pos, l.pos); + VectorCopy(color, l.color); + VectorCopy(surfnormal, l.surfnormal); + l.area = area; + l.leaf = Light_PointInLeaf(bsp, pos); + + unique_lock lck { radlights_lock }; + radlights.push_back(l); +} + +int NumBounceLights() +{ + return radlights.size(); +} + +const bouncelight_t *BounceLightAtIndex(int i) +{ + return &radlights.at(i); +} + +#if 0 // Returns color in [0,1] void Texture_AvgColor (const bsp2_t *bsp, const miptex_t *miptex, vec3_t color) @@ -1075,6 +1147,7 @@ void MakeBounceLights (const bsp2_t *bsp) bouncelights = radlights.data(); numbouncelights = radlights.size(); } +#endif // end radiosity @@ -1431,12 +1504,6 @@ main(int argc, const char **argv) SetupDirt(); MakeTnodes(bsp); - - if (bounce) { - MakeTextureColors(bsp); - MakeBounceLights(bsp); - } - LightWorld(&bspdata, !!lmscaleoverride); /*invalidate any bspx lighting info early*/ diff --git a/light/ltface.c b/light/ltface.c index cda69b86..bf694d7b 100644 --- a/light/ltface.c +++ b/light/ltface.c @@ -1632,8 +1632,9 @@ LightFace_Bounce(const bsp2_t *bsp, const bsp2_dface_t *face, const lightsurf_t /* use a style 0 light map */ lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); + const int numbouncelights = NumBounceLights(); for (int j=0; jpvs, vpl->leaf)) continue; @@ -1715,6 +1716,21 @@ void SetupDirt( void ) { logprint("%9d dirtmap vectors\n", numDirtVectors ); } +static const lightmap_t * +Lightmap_ForStyle_ReadOnly(const struct ltface_ctx *ctx, const int style) +{ + const lightmap_t *lightmap = ctx->lightmaps; + int i; + + for (i = 0; i < MAXLIGHTMAPS; i++, lightmap++) { + if (lightmap->style == style) + return lightmap; + if (lightmap->style == 255) + break; + } + return NULL; +} + /* * ============ * DirtForSample @@ -1945,15 +1961,18 @@ WriteLightmaps(bsp2_dface_t *face, facesup_t *facesup, const lightsurf_t *lights } } -struct ltface_ctx *LightFaceInit(const bsp2_t *bsp) +void LightFaceInit(const bsp2_t *bsp, struct ltface_ctx *ctx) { - //windows stack probes can get expensive when its 64mb... - //also, this avoids stack overflows, or the need to guess stack sizes. - struct ltface_ctx *ctx = calloc(1, sizeof(*ctx)); - if (ctx) - ctx->bsp = bsp; - return ctx; + int i; + + memset(ctx, 0, sizeof(*ctx)); + + ctx->bsp = bsp; + + for (i = 0; i < MAXLIGHTMAPS + 1; i++) + ctx->lightmaps[i].style = 255; } + void LightFaceShutdown(struct ltface_ctx *ctx) { int i; @@ -1977,8 +1996,6 @@ void LightFaceShutdown(struct ltface_ctx *ctx) if (ctx->lightsurf.pvs) free(ctx->lightsurf.pvs); - - free(ctx); } const char * @@ -2052,7 +2069,7 @@ LightFace(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, * clamp any values that may have gone negative. */ - if (!dirtDebug && !phongDebug && !bouncedebug) { + if (!dirtDebug && !phongDebug) { /* positive lights */ for (lighte = lights; (entity = *lighte); lighte++) { @@ -2084,11 +2101,6 @@ LightFace(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, LightFace_Sky (sun, lightsurf, lightmaps); } - if (!dirtDebug && !phongDebug) { - /* add indirect lighting */ - LightFace_Bounce(bsp, face, lightsurf, lightmaps); - } - /* replace lightmaps with AO for debugging */ if (dirtDebug) LightFace_DirtDebug(lightsurf, lightmaps); @@ -2120,6 +2132,58 @@ LightFace(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, Lightmap_Soften(&lightmaps[i], lightsurf); } } + + /* Calc average brightness */ + // FIXME: don't count occluded samples + VectorSet(lightsurf->radiosity, 0, 0, 0); + lightmap_t *lightmap = Lightmap_ForStyle(lightmaps, 0, lightsurf); + sample = lightmap->samples; + for (j = 0; j < lightsurf->numpoints; j++, sample++) { + vec3_t color; + VectorCopy(sample->color, color); + VectorAdd(lightsurf->radiosity, color, lightsurf->radiosity); + } + VectorScale(lightsurf->radiosity, 1.0/lightsurf->numpoints, lightsurf->radiosity); + // clamp components at 512 +// for (int i=0;i<3;i++) +// lightsurf->radiosity[i] = qmin(512.0f, lightsurf->radiosity[i]); + + /* Calc average texture color */ + VectorSet(lightsurf->texturecolor, 0, 0, 0); + for (j = 0; j < lightsurf->numpoints; j++) { + int palidx = SampleTexture(face, bsp, lightsurf->points[j]); + vec3_t texcolor = {thepalette[3*palidx], thepalette[3*palidx + 1], thepalette[3*palidx + 2]}; + VectorAdd(lightsurf->texturecolor, texcolor, lightsurf->texturecolor); + } + VectorScale(lightsurf->texturecolor, 1.0f/lightsurf->numpoints, lightsurf->texturecolor); + + // make bounce light + if (bounce) { + vec3_t emitcolor; + for (int k=0; k<3; k++) { + emitcolor[k] = (lightsurf->radiosity[k] / 255.0f) * (lightsurf->texturecolor[k] / 255.0f); + } + winding_t *w = WindingFromFace(bsp, face); + AddBounceLight(lightsurf->midpoint, emitcolor, lightsurf->plane.normal, WindingArea(w), bsp); + free(w); + } else { + WriteLightmaps(face, facesup, lightsurf, lightmaps); + } +} + +void +LightFaceIndirect(bsp2_dface_t *face, facesup_t *facesup, const modelinfo_t *modelinfo, struct ltface_ctx *ctx) +{ + lightmap_t *lightmaps = ctx->lightmaps; + lightsurf_t *lightsurf = &ctx->lightsurf; + if (bouncedebug) + { + Lightmap_ClearAll(lightmaps); + } + + /* add indirect lighting */ + LightFace_Bounce(ctx->bsp, face, lightsurf, lightmaps); + WriteLightmaps(face, facesup, lightsurf, lightmaps); } diff --git a/light/trace.c b/light/trace.c index f536ac9a..8836f429 100644 --- a/light/trace.c +++ b/light/trace.c @@ -345,7 +345,7 @@ vec_t fix_coord(vec_t in, int width) } } -static int +int SampleTexture(const bsp2_dface_t *face, const bsp2_t *bsp, const vec3_t point) { vec_t texcoord[2];