diff --git a/nel/src/3d/mesh_base.cpp b/nel/src/3d/mesh_base.cpp index 8a85808fad..84dbc7e35b 100644 --- a/nel/src/3d/mesh_base.cpp +++ b/nel/src/3d/mesh_base.cpp @@ -224,6 +224,25 @@ void CMeshBase::serialMeshBase(NLMISC::IStream &f) { TLightInfoMapV7 temp; f.serialCont(temp); + // Convert old format to new format when reading + if(f.isReading()) + { + _LightInfos.clear(); + for(TLightInfoMapV7::iterator it = temp.begin(); it != temp.end(); ++it) + { + CLightMapInfoList lmil; + lmil.AnimatedLight = it->first; + lmil.LightGroup = 0; + for(CLightInfoMapListV7::iterator itStage = it->second.begin(); itStage != it->second.end(); ++itStage) + { + CLightMapInfoList::CMatStage ms; + ms.MatId = itStage->nMatNb; + ms.StageId = itStage->nStageNb; + lmil.StageList.push_back(ms); + } + _LightInfos.push_back(lmil); + } + } } if(ver>=3) diff --git a/ryzom/client/src/commands.cpp b/ryzom/client/src/commands.cpp index 396b63404f..6829963b1e 100644 --- a/ryzom/client/src/commands.cpp +++ b/ryzom/client/src/commands.cpp @@ -44,6 +44,10 @@ #include "nel/3d/u_animation.h" #include "nel/3d/u_scene.h" #include "nel/3d/u_track.h" +#include "nel/3d/scene_user.h" +#include "nel/3d/mesh_base.h" +#include "nel/3d/mesh_base_instance.h" +#include "nel/3d/texture_file.h" #include "nel/ligo/primitive.h" @@ -5746,6 +5750,122 @@ NLMISC_COMMAND(dumpContinentCorners, "dump max dist for shapes", "") } +NLMISC_COMMAND(dumpLightmapInfo, "Dump lightmap info for a shape to help diagnose lightmap issues (e.g. missing sunlight)", "") +{ + if (args.size() != 1) return false; + if (!Scene) return false; + + // Access the internal scene to get light group colors + NL3D::CScene &internalScene = (static_cast(Scene))->getScene(); + + // Dump scene light group colors + nlinfo("=== Scene Light Group Colors ==="); + uint numGroups = internalScene.getNumLightGroup(); + nlinfo(" NumLightGroups: %u", numGroups); + for (uint g = 0; g < std::max(numGroups, 6u); ++g) + { + NLMISC::CRGBA col = internalScene.getLightmapGroupColor(g); + nlinfo(" LightGroup %u: R=%u G=%u B=%u A=%u%s", g, col.R, col.G, col.B, col.A, + g >= numGroups ? " (default, not explicitly set)" : ""); + } + + // Create a temporary instance to inspect its lightmap properties + NL3D::UInstance inst = Scene->createInstance(args[0]); + if (inst.empty()) + { + nlwarning("dumpLightmapInfo: cannot create instance for shape '%s'", args[0].c_str()); + return false; + } + + nlinfo("=== Lightmap Info for shape '%s' ===", args[0].c_str()); + + // Access the internal mesh base to dump lightmap data + NL3D::CMeshBaseInstance *mbi = dynamic_cast(inst.getObjectPtr()); + if (mbi) + { + NL3D::CMeshBase *mb = dynamic_cast((NL3D::IShape *)(mbi->Shape)); + if (mb) + { + nlinfo(" Shape isLightable: %s", mb->isLightable() ? "true" : "false"); + + // Dump _LightInfos + nlinfo(" --- LightInfos (animated lightmap layers) ---"); + if (mb->_LightInfos.empty()) + { + nlinfo(" (no LightInfos - lightmap factors will not be animated by day/night cycle)"); + } + for (uint li = 0; li < mb->_LightInfos.size(); ++li) + { + const NL3D::CMeshBase::CLightMapInfoList &info = mb->_LightInfos[li]; + sint animLightIdx = internalScene.getAnimatedLightNameToIndex(info.AnimatedLight); + NLMISC::CRGBA effectiveFactor = internalScene.getAnimatedLightFactor(animLightIdx, info.LightGroup); + nlinfo(" LightInfo[%u]: AnimatedLight='%s' LightGroup=%u AnimIndex=%d", li, info.AnimatedLight.c_str(), info.LightGroup, animLightIdx); + nlinfo(" EffectiveFactor: R=%u G=%u B=%u A=%u%s", effectiveFactor.R, effectiveFactor.G, effectiveFactor.B, effectiveFactor.A, + (effectiveFactor.R == 0 && effectiveFactor.G == 0 && effectiveFactor.B == 0) ? " *** ZERO - layer will be invisible! ***" : ""); + std::list::const_iterator itStage; + for (itStage = info.StageList.begin(); itStage != info.StageList.end(); ++itStage) + { + nlinfo(" MatId=%u StageId=%u", (uint)itStage->MatId, (uint)itStage->StageId); + } + } + } + + // Dump material lightmap info + // Note: _LightMaps and _LightMapsMulx2 are public members of CMaterial (for driver use) + nlinfo(" --- Materials ---"); + for (uint m = 0; m < mbi->Materials.size(); ++m) + { + NL3D::CMaterial &mat = mbi->Materials[m]; + if (mat.getShader() == NL3D::CMaterial::LightMap) + { + nlinfo(" Material[%u]: shader=LightMap, Mulx2=%s", m, mat._LightMapsMulx2 ? "true" : "false"); + uint activeLayers = 0; + for (uint lm = 0; lm < mat._LightMaps.size(); ++lm) + { + NL3D::ITexture *tex = mat._LightMaps[lm].Texture; + NLMISC::CRGBA factor = mat._LightMaps[lm].Factor; + NLMISC::CRGBA lmcAmb = mat._LightMaps[lm].LMCAmbient; + NLMISC::CRGBA lmcDiff = mat._LightMaps[lm].LMCDiffuse; + bool factorIsZero = (factor.R == 0 && factor.G == 0 && factor.B == 0); + if (!factorIsZero) activeLayers++; + std::string texName = "NULL"; + std::string texFmt = "N/A"; + if (tex) + { + NL3D::CTextureFile *tf = dynamic_cast((NL3D::ITexture *)tex); + if (tf) texName = tf->getFileName(); + if (tex->getUploadFormat() == NL3D::ITexture::Luminance) + texFmt = "Luminance(8bit)"; + else if (tex->getUploadFormat() == NL3D::ITexture::RGB565) + texFmt = "RGB565(16bit)"; + else + texFmt = NLMISC::toString("fmt(%d)", (int)tex->getUploadFormat()); + } + nlinfo(" LightMap[%u]: tex='%s' format=%s", lm, texName.c_str(), texFmt.c_str()); + nlinfo(" Factor: R=%u G=%u B=%u A=%u%s", factor.R, factor.G, factor.B, factor.A, + factorIsZero ? " *** ZERO - layer skipped by renderer! ***" : ""); + nlinfo(" LMCAmbient: R=%u G=%u B=%u A=%u", lmcAmb.R, lmcAmb.G, lmcAmb.B, lmcAmb.A); + nlinfo(" LMCDiffuse: R=%u G=%u B=%u A=%u", lmcDiff.R, lmcDiff.G, lmcDiff.B, lmcDiff.A); + } + nlinfo(" Active layers (non-zero factor): %u / %u", activeLayers, (uint)mat._LightMaps.size()); + } + else + { + nlinfo(" Material[%u]: shader=%d (not LightMap)", m, (int)mat.getShader()); + } + } + } + else + { + nlwarning(" Instance is not a CMeshBaseInstance"); + } + + Scene->deleteInstance(inst); + nlinfo("=== End Lightmap Info ==="); + + return true; +} + #if !FINAL_VERSION NLMISC_COMMAND(setMission, "locally set a mission text for test", "") {