diff --git a/code/nel/tools/3d/mesh_utils/assimp_material.cpp b/code/nel/tools/3d/mesh_utils/assimp_material.cpp index b2fd78868..5dbe8643c 100644 --- a/code/nel/tools/3d/mesh_utils/assimp_material.cpp +++ b/code/nel/tools/3d/mesh_utils/assimp_material.cpp @@ -31,6 +31,7 @@ #include #include +#include using namespace std; using namespace NLMISC; @@ -50,6 +51,10 @@ inline CRGBA convColor(const aiColor4D &ac) void assimpMaterial(NL3D::CMaterial &mat, CMeshUtilsContext &context, const aiMaterial *am) { + aiString amname; + if (am->Get(AI_MATKEY_NAME, amname) != aiReturn_SUCCESS) + amname = ""; + mat.initLighted(); mat.setShader(CMaterial::Normal); @@ -99,6 +104,78 @@ void assimpMaterial(NL3D::CMaterial &mat, CMeshUtilsContext &context, const aiMa if (am->Get(AI_MATKEY_COLOR_EMISSIVE, c3) == aiReturn_SUCCESS) mat.setEmissive(convColor(c3)); + + // Textures + unsigned int texCount = am->GetTextureCount(aiTextureType_DIFFUSE); + if (texCount > IDRV_MAT_MAXTEXTURES) + { + tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(), + "Material '%s' has more than %i textures (%i textures found)", amname.C_Str(), IDRV_MAT_MAXTEXTURES, texCount); + texCount = IDRV_MAT_MAXTEXTURES; + } + + for (unsigned int ti = 0; ti < texCount; ++ti) + { + aiString path; + aiTextureMapping mapping; + unsigned int uvindex; + float blend; // Partially supported + aiTextureOp op; + aiTextureMapMode mapmode; + if (am->GetTexture(aiTextureType_DIFFUSE, ti, &path, &mapping, &uvindex, &blend, &op, &mapmode) != aiReturn_SUCCESS) + { + tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(), + "Failed to get texture %i in material '%s'", ti, amname.C_Str()); + break; + } + + std::string fileName = CFile::getFilename(CPath::standardizePath(path.C_Str(), false)); + std::string knownPath = CPath::lookup(fileName, false, false, false); + if (knownPath.empty()) + { + tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(), + "Texture '%s' referenced in material '%s' but not found in the database search paths", fileName.c_str(), amname.C_Str()); + } + + // NeL supports bitmap and cubemap, but we import only basic bitmap here. Cubemap can be inserted from the mesh editor tool + // NeL also has fancy multi-bitmap thing to switch between summer and winter and so on. Same story + CSmartPtr tex = new CTextureFile(); + tex->setFileName(fileName); + tex->setWrapS(mapmode == aiTextureMapMode_Clamp ? ITexture::Clamp : ITexture::Repeat); + tex->setWrapT(mapmode == aiTextureMapMode_Clamp ? ITexture::Clamp : ITexture::Repeat); + mat.setTexture(ti, tex); + + // TODO uvindex for uv routing (probably necessary during shape import - if so also need to also ask the uv channel in the editor and store in meta) + + // TODO aiTextureMapping texcoordgen if useful to import + + mat.texEnvArg0Alpha(ti, CMaterial::Texture, CMaterial::SrcAlpha); + mat.texEnvArg0RGB(ti, CMaterial::Texture, CMaterial::SrcColor); + mat.texEnvArg1Alpha(ti, ti == 0 ? CMaterial::Diffuse : CMaterial::Previous, CMaterial::SrcAlpha); + mat.texEnvArg1RGB(ti, ti == 0 ? CMaterial::Diffuse : CMaterial::Previous, CMaterial::SrcColor); + switch (op) + { + case aiTextureOp_Multiply: + default: + mat.texEnvOpAlpha(ti, CMaterial::Modulate); + mat.texEnvOpRGB(ti, CMaterial::Modulate); + break; + case aiTextureOp_Add: + mat.texEnvOpAlpha(ti, CMaterial::Add); + mat.texEnvOpRGB(ti, CMaterial::Add); + break; + case aiTextureOp_Subtract: + mat.texEnvArg0Alpha(ti, CMaterial::Texture, CMaterial::InvSrcAlpha); + mat.texEnvArg0RGB(ti, CMaterial::Texture, CMaterial::InvSrcColor); + mat.texEnvOpAlpha(ti, CMaterial::Add); + mat.texEnvOpRGB(ti, CMaterial::Add); + break; + case aiTextureOp_SignedAdd: + mat.texEnvOpAlpha(ti, CMaterial::AddSigned); + mat.texEnvOpRGB(ti, CMaterial::AddSigned); + break; + } + } } CSmartPtr assimpMaterial(CMeshUtilsContext &context, const aiMaterial *am) diff --git a/code/nel/tools/3d/mesh_utils/mesh_utils.cpp b/code/nel/tools/3d/mesh_utils/mesh_utils.cpp index 3d9b6c42a..bfda6e63f 100644 --- a/code/nel/tools/3d/mesh_utils/mesh_utils.cpp +++ b/code/nel/tools/3d/mesh_utils/mesh_utils.cpp @@ -22,8 +22,11 @@ #include #include #include +#include #include +#include +#include #include "database_config.h" #include "scene_meta.h" @@ -227,7 +230,7 @@ void exportShapes(CMeshUtilsContext &context) CNodeContext &nodeContext = it->second; if (nodeContext.Shape) { - std::string shapePath = context.Settings.DestinationDirectoryPath + "/" + it->first + ".shape"; + std::string shapePath = NLMISC::CPath::standardizePath(context.Settings.DestinationDirectoryPath, true) + it->first + ".shape"; context.ToolLogger.writeDepend(NLMISC::BUILD, shapePath.c_str(), "*"); NLMISC::COFile f; if (f.open(shapePath, false, false, true)) @@ -244,6 +247,34 @@ void exportShapes(CMeshUtilsContext &context) "Shape '%s' serialization failed!", it->first.c_str()); } } + if (NL3D::CMesh *mesh = dynamic_cast(nodeContext.Shape.getPtr())) + { + for (uint mi = 0; mi < mesh->getNbMaterial(); ++mi) + { + NL3D::CMaterial &mat = mesh->getMaterial(mi); + for (uint ti = 0; ti < NL3D::IDRV_MAT_MAXTEXTURES; ++ti) + { + if (NL3D::ITexture *itex = mat.getTexture(ti)) + { + if (NL3D::CTextureFile *tex = dynamic_cast(itex)) + { + std::string fileName = tex->getFileName(); + std::string knownPath = NLMISC::CPath::lookup(fileName, false, false, false); + if (!knownPath.empty()) + { + context.ToolLogger.writeDepend(NLMISC::RUNTIME, shapePath.c_str(), knownPath.c_str()); + } + else + { + // TODO: Move this warning into nelmeta serialization so it's shown before export + tlwarning(context.ToolLogger, context.Settings.SourceFilePath.c_str(), + "Texture '%s' referenced in material but not found in the database search paths", fileName.c_str()); + } + } + } + } + } + } } } } @@ -258,7 +289,7 @@ int exportScene(const CMeshUtilsSettings &settings) context.ToolLogger.initDepend(settings.ToolDependLog); if (!settings.ToolErrorLog.empty()) context.ToolLogger.initError(settings.ToolErrorLog); - context.ToolLogger.writeDepend(NLMISC::BUILD, "*", context.Settings.SourceFilePath.c_str()); // Base input file + context.ToolLogger.writeDepend(NLMISC::BUILD, "*", NLMISC::CPath::standardizePath(context.Settings.SourceFilePath, false).c_str()); // Base input file // Apply database configuration CDatabaseConfig::init(settings.SourceFilePath); diff --git a/code/nel/tools/3d/mesh_utils/scene_meta.cpp b/code/nel/tools/3d/mesh_utils/scene_meta.cpp index 3c72207cf..dd7ea0686 100644 --- a/code/nel/tools/3d/mesh_utils/scene_meta.cpp +++ b/code/nel/tools/3d/mesh_utils/scene_meta.cpp @@ -49,6 +49,11 @@ void CNodeMeta::serial(NLMISC::IStream &s) } CSceneMeta::CSceneMeta() : + ImportShape(true), + ImportSkel(true), + ImportAnim(true), + ImportCmb(true), + ImportIG(true), ExportDefaultIG(false), SkeletonMode(TSkelRoot) { @@ -57,7 +62,7 @@ CSceneMeta::CSceneMeta() : bool CSceneMeta::load(const std::string &filePath) { - m_MetaFilePath = filePath + ".nelmeta"; + m_MetaFilePath = NLMISC::CPath::standardizePath(filePath + ".nelmeta", false); if (CFile::fileExists(m_MetaFilePath)) { CIFile f(m_MetaFilePath); @@ -79,6 +84,12 @@ void CSceneMeta::serial(NLMISC::IStream &s) { uint version = s.serialVersion(1); + s.serial(ImportShape); + s.serial(ImportSkel); + s.serial(ImportAnim); + s.serial(ImportCmb); + s.serial(ImportIG); + s.serial(ExportDefaultIG); s.serial((uint32 &)SkeletonMode); diff --git a/code/nel/tools/3d/mesh_utils/scene_meta.h b/code/nel/tools/3d/mesh_utils/scene_meta.h index 43f309557..62c185ee4 100644 --- a/code/nel/tools/3d/mesh_utils/scene_meta.h +++ b/code/nel/tools/3d/mesh_utils/scene_meta.h @@ -80,6 +80,12 @@ struct CSceneMeta { CSceneMeta(); + bool ImportShape; + bool ImportSkel; + bool ImportAnim; + bool ImportCmb; + bool ImportIG; + bool ExportDefaultIG; // Export a default instance group from nodes the scene that do not have an instance group set TSkel SkeletonMode;