From 46d460277a3dca4858090f2222476dca2b80db73 Mon Sep 17 00:00:00 2001 From: Eric Wasylishen Date: Mon, 14 Nov 2022 23:58:31 -0700 Subject: [PATCH] ltface: support -world_units_per_luxel without -novanilla first pass implementation - quality of vanilla LM is bad, due to nearest sampling the decoupled lightmap --- light/ltface.cc | 83 ++++++++++++++++++++++++++- testmaps/q2_lightmap_custom_scale.map | 7 +++ tests/test_ltface.cc | 4 +- 3 files changed, 89 insertions(+), 5 deletions(-) diff --git a/light/ltface.cc b/light/ltface.cc index 708055c9..b89772c7 100644 --- a/light/ltface.cc +++ b/light/ltface.cc @@ -2656,6 +2656,54 @@ static void WriteSingleLightmap(const mbsp_t *bsp, const mface_t *face, const li } } +/** + * - Writes (output_width * output_height) bytes to `out` + * - Writes (output_width * output_height * 3) bytes to `lit` + * - Writes (output_width * output_height * 3) bytes to `lux` + */ +static void WriteSingleLightmap_FromDecoupled(const mbsp_t *bsp, const mface_t *face, const lightsurf_t *lightsurf, + const lightmap_t *lm, const int output_width, const int output_height, uint8_t *out, uint8_t *lit, uint8_t *lux) +{ + // this is the lightmap data in the "decoupled" coordinate system + std::vector fullres = LightmapColorsToGLMVector(lightsurf, lm); + + for (int t = 0; t < output_height; t++) { + for (int s = 0; s < output_width; s++) { + // convert from vanilla lm coord to decoupled lm coord + qvec3f world = lightsurf->vanilla_extents.LMCoordToWorld(qvec2f(s, t)); + qvec2f decoupled_lm_coord = lightsurf->extents.worldToLMCoord(world); + + decoupled_lm_coord = decoupled_lm_coord * light_options.extra.value(); + + const int input_sample_s = clamp((int)decoupled_lm_coord[0], 0, lightsurf->width - 1); + const int input_sample_t = clamp((int)decoupled_lm_coord[1], 0, lightsurf->height - 1); + const int sampleindex = (input_sample_t * lightsurf->width) + input_sample_s; + + if (lit || out) { + const qvec4f &color = fullres.at(sampleindex); + + if (lit) { + *lit++ = color[0]; + *lit++ = color[1]; + *lit++ = color[2]; + } + + if (out) { + // FIXME: implement + *out++ = 0; + } + } + + if (lux) { + // FIXME: implement + *lux++ = 0; + *lux++ = 0; + *lux++ = 0; + } + } + } +} + void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, bspx_decoupled_lm_perface *facesup_decoupled, lightsurf_t *lightsurf, const faceextents_t &extents, const faceextents_t &output_extents) @@ -2848,11 +2896,9 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lightofs = out - filebase.data(); } - if (facesup_decoupled && light_options.novanilla.value()) { + if (facesup_decoupled) { facesup_decoupled->offset = lightofs; face->lightofs = -1; - } else if (facesup_decoupled && !light_options.novanilla.value()) { - FError("-world_units_per_luxel currently requires -novanilla"); } else if (facesup) { facesup->lightofs = lightofs; } else { @@ -2882,6 +2928,37 @@ void SaveLightmapSurface(const mbsp_t *bsp, mface_t *face, facesup_t *facesup, lux += (size * 3); } } + + // write vanilla lightmap if -world_units_per_luxel is in use but not -novanilla + if (facesup_decoupled && !light_options.novanilla.value()) { + // FIXME: duplicates some code from above + GetFileSpace(&out, &lit, &lux, lightsurf->vanilla_extents.numsamples() * numstyles); + + // Q2/HL native colored lightmaps + if (bsp->loadversion->game->has_rgb_lightmap) { + lightofs = lit - lit_filebase.data(); + } else { + lightofs = out - filebase.data(); + } + face->lightofs = lightofs; + + for (int mapnum = 0; mapnum < numstyles; mapnum++) { + const lightmap_t *lm = sorted.at(mapnum); + + WriteSingleLightmap_FromDecoupled(bsp, face, lightsurf, lm, lightsurf->vanilla_extents.width(), + lightsurf->vanilla_extents.height(), out, lit, lux); + + if (out) { + out += lightsurf->vanilla_extents.numsamples(); + } + if (lit) { + lit += (lightsurf->vanilla_extents.numsamples() * 3); + } + if (lux) { + lux += (lightsurf->vanilla_extents.numsamples() * 3); + } + } + } } std::unique_ptr CreateLightmapSurface(const mbsp_t *bsp, const mface_t *face, const facesup_t *facesup, diff --git a/testmaps/q2_lightmap_custom_scale.map b/testmaps/q2_lightmap_custom_scale.map index 6ce8e512..91d70052 100644 --- a/testmaps/q2_lightmap_custom_scale.map +++ b/testmaps/q2_lightmap_custom_scale.map @@ -977,3 +977,10 @@ "origin" "-398 -160 94" "light" "1200" } +// entity 7 +{ +"classname" "light" +"origin" "232 -248 104" +"style" "1" +"_color" "183 255 227" +} diff --git a/tests/test_ltface.cc b/tests/test_ltface.cc index 8309fccd..2ef5aba9 100644 --- a/tests/test_ltface.cc +++ b/tests/test_ltface.cc @@ -63,8 +63,8 @@ static testresults_t LoadTestmap(const std::filesystem::path &name, std::vector< } } -TEST_CASE("TestLight") { - LoadTestmap("q2_lightmap_custom_scale.map", {"-threads", "1", "-world_units_per_luxel", "8", "-novanilla"}); +TEST_CASE("-world_units_per_luxel") { + LoadTestmap("q2_lightmap_custom_scale.map", {"-world_units_per_luxel", "8"}); } TEST_CASE("emissive cube artifacts") {