diff --git a/code/nel/tools/3d/mesh_utils/database_config.h b/code/nel/include/nel/pipeline/database_config.h similarity index 97% rename from code/nel/tools/3d/mesh_utils/database_config.h rename to code/nel/include/nel/pipeline/database_config.h index 25bcc2a00..ec9bb6ec6 100644 --- a/code/nel/tools/3d/mesh_utils/database_config.h +++ b/code/nel/include/nel/pipeline/database_config.h @@ -28,6 +28,8 @@ typedef NLMISC::CSString TPathString; typedef std::string TPathString; #endif +namespace NLPIPELINE { + /// Asset database configuration class CDatabaseConfig { @@ -55,4 +57,6 @@ private: }; +} /* namespace NLPIPELINE */ + /* end of file */ diff --git a/code/nel/include/nel/pipeline/project_config.h b/code/nel/include/nel/pipeline/project_config.h new file mode 100644 index 000000000..11210d5e8 --- /dev/null +++ b/code/nel/include/nel/pipeline/project_config.h @@ -0,0 +1,79 @@ +// NeL - MMORPG Framework +// Copyright (C) 2015 Winch Gate Property Limited +// Author: Jan Boon +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#ifndef NLPIPELINE_PROJECT_CONFIG_H +#define NLPIPELINE_PROJECT_CONFIG_H +#include + +namespace NLMISC { + class CConfigFile; +} + +#ifdef NL_OS_WINDOWS +#include +typedef NLMISC::CSString TPathString; +#else +typedef std::string TPathString; +#endif + +namespace NLPIPELINE { + +/// Asset project configuration. Used to configure lookup directories for tools and buildsite specific setup. Do not use for pipeline build settings +class CProjectConfig +{ +public: + enum Flags + { + DatabaseTextureSearchPaths = 0x0001, + DatabaseMaterialSearchPaths = 0x0002, + RuntimeTextureSearchPaths = 0x0100, + RuntimeShapeSearchPaths = 0x0200, + }; + +public: + ~CProjectConfig(); + + /// Searches for the configuration for the specified asset path by recursively going through all parent directories looking for 'nel.cfg', matches it to a project cfg if partial is not set, initializes and applies the configuration. + static bool init(const std::string &asset, Flags flags, bool partial = false); + /// Undo init + static void release(); + +private: + static void cleanup(); + static void searchDirectories(const char *var); + + static CProjectConfig s_Instance; + + static uint32 s_AssetConfigModification; + static uint32 s_ProjectConfigModification; + + static TPathString s_AssetConfigPath; + static TPathString s_ProjectConfigPath; + + static std::string s_ProjectName; + static CProjectConfig::Flags CProjectConfig::s_InitFlags; + + static std::vector s_ConfigPaths; + static std::vector s_ConfigFiles; + +}; + +} /* namespace NLPIPELINE */ + +#endif /* #ifndef NLPIPELINE_PROJECT_CONFIG_H */ + +/* end of file */ diff --git a/code/nel/include/nel/misc/tool_logger.h b/code/nel/include/nel/pipeline/tool_logger.h similarity index 89% rename from code/nel/include/nel/misc/tool_logger.h rename to code/nel/include/nel/pipeline/tool_logger.h index ff78a6afa..55b3b2455 100644 --- a/code/nel/include/nel/misc/tool_logger.h +++ b/code/nel/include/nel/pipeline/tool_logger.h @@ -27,8 +27,8 @@ * . */ -#ifndef NLMISC_TOOL_LOGGER_H -#define NLMISC_TOOL_LOGGER_H +#ifndef NLPIPELINE_TOOL_LOGGER_H +#define NLPIPELINE_TOOL_LOGGER_H #include // STL includes @@ -47,16 +47,16 @@ #endif #ifdef NL_DEBUG_H -#define tlerror(toolLogger, path, error, ...) nlwarning(error, ## __VA_ARGS__), toolLogger.writeError(NLMISC::ERROR, path, error, ## __VA_ARGS__) -#define tlwarning(toolLogger, path, error, ...) nlwarning(error, ## __VA_ARGS__), toolLogger.writeError(NLMISC::WARNING, path, error, ## __VA_ARGS__) -#define tlmessage(toolLogger, path, error, ...) nlinfo(error, ## __VA_ARGS__), toolLogger.writeError(NLMISC::MESSAGE, path, error, ## __VA_ARGS__) +#define tlerror(toolLogger, path, error, ...) nlwarning(error, ## __VA_ARGS__), toolLogger.writeError(NLPIPELINE::ERROR, path, error, ## __VA_ARGS__) +#define tlwarning(toolLogger, path, error, ...) nlwarning(error, ## __VA_ARGS__), toolLogger.writeError(NLPIPELINE::WARNING, path, error, ## __VA_ARGS__) +#define tlmessage(toolLogger, path, error, ...) nlinfo(error, ## __VA_ARGS__), toolLogger.writeError(NLPIPELINE::MESSAGE, path, error, ## __VA_ARGS__) #else -#define tlerror(toolLogger, path, error, ...) toolLogger.writeError(NLMISC::ERROR, path, error, ## __VA_ARGS__) -#define tlwarning(toolLogger, path, error, ...) toolLogger.writeError(NLMISC::WARNING, path, error, ## __VA_ARGS__) -#define tlmessage(toolLogger, path, error, ...) toolLogger.writeError(NLMISC::MESSAGE, path, error, ## __VA_ARGS__) +#define tlerror(toolLogger, path, error, ...) toolLogger.writeError(NLPIPELINE::ERROR, path, error, ## __VA_ARGS__) +#define tlwarning(toolLogger, path, error, ...) toolLogger.writeError(NLPIPELINE::WARNING, path, error, ## __VA_ARGS__) +#define tlmessage(toolLogger, path, error, ...) toolLogger.writeError(NLPIPELINE::MESSAGE, path, error, ## __VA_ARGS__) #endif -namespace NLMISC { +namespace NLPIPELINE { enum TError { @@ -203,8 +203,8 @@ public: } }; /* class CToolLogger */ -} /* namespace NLMISC */ +} /* namespace NLPIPELINE */ -#endif /* #ifndef NLMISC_TOOL_LOGGER_H */ +#endif /* #ifndef NLPIPELINE_TOOL_LOGGER_H */ /* end of file */ diff --git a/code/nel/src/CMakeLists.txt b/code/nel/src/CMakeLists.txt index 06faa5251..60e5afccb 100644 --- a/code/nel/src/CMakeLists.txt +++ b/code/nel/src/CMakeLists.txt @@ -35,3 +35,7 @@ ENDIF(WITH_NEL_CEGUI) IF(WITH_PACS) ADD_SUBDIRECTORY(pacs) ENDIF(WITH_PACS) + +IF(WITH_NEL_TOOLS) + ADD_SUBDIRECTORY(pipeline) +ENDIF(WITH_NEL_TOOLS) diff --git a/code/nel/src/pipeline/CMakeLists.txt b/code/nel/src/pipeline/CMakeLists.txt new file mode 100644 index 000000000..47ab9a376 --- /dev/null +++ b/code/nel/src/pipeline/CMakeLists.txt @@ -0,0 +1,18 @@ +FILE(GLOB SRC *.cpp *.h) +FILE(GLOB HEADERS ../../include/nel/pipeline/*.h) + +SOURCE_GROUP("" FILES ${HEADERS} ${SRC}) + +NL_TARGET_LIB(nelpipeline ${HEADERS} ${SRC}) + +INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR}) + +TARGET_LINK_LIBRARIES(nelpipeline nelmisc) +NL_DEFAULT_PROPS(nelpipeline "NeL, Library: NeL Pipeline") +NL_ADD_RUNTIME_FLAGS(nelpipeline) + +NL_ADD_LIB_SUFFIX(nelpipeline) + +IF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) + INSTALL(TARGETS nelpipeline LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT libraries) +ENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC) diff --git a/code/nel/tools/3d/mesh_utils/database_config.cpp b/code/nel/src/pipeline/database_config.cpp similarity index 96% rename from code/nel/tools/3d/mesh_utils/database_config.cpp rename to code/nel/src/pipeline/database_config.cpp index 7e6ea5b37..b326a2888 100644 --- a/code/nel/tools/3d/mesh_utils/database_config.cpp +++ b/code/nel/src/pipeline/database_config.cpp @@ -16,7 +16,7 @@ // along with this program. If not, see . #include -#include "database_config.h" +#include "nel/pipeline/database_config.h" #include #include @@ -25,6 +25,8 @@ using namespace std; using namespace NLMISC; +namespace NLPIPELINE { + TPathString CDatabaseConfig::s_RootPath; NLMISC::CConfigFile *CDatabaseConfig::s_ConfigFile = NULL; CDatabaseConfig CDatabaseConfig::s_Instance; @@ -104,4 +106,6 @@ void CDatabaseConfig::release() cleanup(); } +} /* namespace NLPIPELINE */ + /* end of file */ diff --git a/code/nel/src/pipeline/project_config.cpp b/code/nel/src/pipeline/project_config.cpp new file mode 100644 index 000000000..995f92fd4 --- /dev/null +++ b/code/nel/src/pipeline/project_config.cpp @@ -0,0 +1,238 @@ +// NeL - MMORPG Framework +// Copyright (C) 2015 Winch Gate Property Limited +// Author: Jan Boon +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as +// published by the Free Software Foundation, either version 3 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +#include +#include "nel/pipeline/project_config.h" + +#ifdef NL_OS_WINDOWS +# include +#else +# include +#endif + +#include + +#include +#include +#include + +using namespace std; +using namespace NLMISC; + +namespace NLPIPELINE { + +TPathString CProjectConfig::s_AssetConfigPath; +TPathString CProjectConfig::s_ProjectConfigPath; +std::vector CProjectConfig::s_ConfigFiles; +std::vector CProjectConfig::s_ConfigPaths; +CProjectConfig CProjectConfig::s_Instance; +uint32 CProjectConfig::s_AssetConfigModification; +uint32 CProjectConfig::s_ProjectConfigModification; +CProjectConfig::Flags CProjectConfig::s_InitFlags = (CProjectConfig::Flags)0; +std::string CProjectConfig::s_ProjectName; + +static std::set s_SearchPaths; + +void CProjectConfig::cleanup() +{ + for (std::vector::iterator it(s_ConfigFiles.begin()), end(s_ConfigFiles.end()); it != end; ++it) + delete *it; + s_ConfigFiles.clear(); +} + +CProjectConfig::~CProjectConfig() +{ + cleanup(); +} + +bool CProjectConfig::init(const std::string &asset, Flags flags, bool partial) +{ + TPathString rootPath = NLMISC::CPath::standardizePath(asset, false); + TPathString configPath = rootPath + "/nel.cfg"; + while (!CFile::fileExists(configPath)) + { + int sep = CFile::getLastSeparator(rootPath); + if (sep == string::npos) + return false; + + rootPath = rootPath.substr(0, sep); + if (rootPath.empty()) + return false; + + configPath = rootPath + "/nel.cfg"; + } + + rootPath += "/"; + uint32 configFileModification = CFile::getFileModificationDate(configPath); + bool assetConfigSame = configPath == s_AssetConfigPath && s_AssetConfigModification == configFileModification && s_InitFlags == flags; + + std::vector configRootPaths; + TPathString projectConfigPath; + uint32 projectConfigModification; + std::string projectName; + if (partial) + { + if (assetConfigSame && s_ProjectConfigPath.empty()) + return true; // Do not reload + } + else + { + if (assetConfigSame && !s_ProjectConfigPath.empty() && CFile::fileExists(s_ProjectConfigPath)) + { + projectConfigModification = CFile::getFileModificationDate(s_ProjectConfigPath); + + if (s_ProjectConfigModification == projectConfigModification) + return true; // Do not reload + } + + // Search for project and load up all root paths + std::vector files; + CPath::getPathContent(CPath::getApplicationDirectory("NeL", true) + "/projects", false, false, true, files); + for (std::vector::iterator it(files.begin()), end(files.end()); it != end; ++it) + { + const std::string& file = *it; + if (file.length() >= 4 && (file.compare(file.length() - 4, 4, ".cfg") == 0)) + { + CConfigFile project; + project.load(file); + CConfigFile::CVar &directories = project.getVar("Directories"); + bool isProject = false; + for (uint i = 0; i < directories.size(); ++i) + { + if (rootPath == CPath::standardizePath(directories.asString(i), true)) + { + isProject = true; + break; + } + } + if (isProject) + { + projectConfigModification = CFile::getFileModificationDate(file); + projectConfigPath = file; + + for (uint i = 0; i < directories.size(); ++i) + { + std::string dir = CPath::standardizePath(directories.asString(i), true); + std::string cfgPath = dir + "nel.cfg"; + if (CFile::fileExists(cfgPath)) + configRootPaths.push_back(dir); + } + + projectName = project.getVar("ProjectName").asString(); + + break; + } + } + } + } + + if (projectConfigPath.empty()) + { + projectName = "NeL Project"; + configRootPaths.push_back(rootPath); + projectConfigModification = 0; + } + + nldebug("Initializing project config '%s'", projectConfigPath.empty() ? configPath.c_str() : projectConfigPath.c_str()); + release(); + + s_InitFlags = flags; + s_AssetConfigPath = configPath; + s_AssetConfigModification = configFileModification; + s_ProjectConfigPath = projectConfigPath; + s_ProjectConfigModification = projectConfigModification; + s_ProjectName = projectName; + s_ConfigPaths = configRootPaths; + + std::map configFiles; + for (std::vector::iterator it(configRootPaths.begin()), end(configRootPaths.end()); it != end; ++it) + { + const std::string &dir = *it; + const std::string &cfgPath = *it + "nel.cfg"; + CConfigFile *cfgFile = new CConfigFile(); + cfgFile->load(cfgPath); + std::string identifier = cfgFile->getVar("Identifier").asString(); + if (configFiles.find(identifier) != configFiles.end()) // Identifier already exists + { + if (dir == rootPath) + { + // Replace config that was already added, asset root gets priority + std::vector::iterator old = std::find(s_ConfigFiles.begin(), s_ConfigFiles.end(), configFiles[identifier]); + uint idx = old - s_ConfigFiles.begin(); + s_ConfigFiles.erase(old); + s_ConfigPaths.erase(s_ConfigPaths.begin() + idx); + } + else + { + // Skip, first listed config gets priority + s_ConfigPaths.erase(s_ConfigPaths.begin() + s_ConfigFiles.size()); + continue; + } + } +#ifdef NL_OS_WINDOWS + SetEnvironmentVariableA(identifier.c_str(), dir.c_str()); +#else + setenv(identifier.c_str(), dir.c_str(), 1); +#endif + configFiles[identifier] = cfgFile; + s_ConfigFiles.push_back(cfgFile); + } + + nlassert(s_ConfigFiles.size() == s_ConfigPaths.size()); + + if (flags & DatabaseTextureSearchPaths) + { + searchDirectories("DatabaseTextureSearchPaths"); + } + + return true; +} + +void CProjectConfig::searchDirectories(const char *var) +{ + for (uint i = 0; i < s_ConfigFiles.size(); ++i) + { + CConfigFile *cfg = s_ConfigFiles[i]; + const TPathString &dir = s_ConfigPaths[i]; + CConfigFile::CVar *paths = cfg->getVarPtr(var); + if (paths) + { + for (uint i = 0; i < paths->size(); i++) + { + TPathString path = paths->asString(i); + if (!CPath::isAbsolutePath(path)) path = dir + path; + path = CPath::standardizePath(path); + if (s_SearchPaths.find(path) == s_SearchPaths.end()) + { + CPath::addSearchPath(path); + s_SearchPaths.insert(path); + } + } + } + } +} + +void CProjectConfig::release() +{ + s_SearchPaths.clear(); + CPath::clearMap(); + cleanup(); +} + +} /* namespace NLPIPELINE */ + +/* end of file */ diff --git a/code/nel/src/misc/tool_logger.cpp b/code/nel/src/pipeline/tool_logger.cpp similarity index 92% rename from code/nel/src/misc/tool_logger.cpp rename to code/nel/src/pipeline/tool_logger.cpp index e6a9fbf36..064e25f77 100644 --- a/code/nel/src/misc/tool_logger.cpp +++ b/code/nel/src/pipeline/tool_logger.cpp @@ -25,8 +25,7 @@ * . */ -#include "stdmisc.h" -#include "nel/misc/tool_logger.h" +#include "nel/pipeline/tool_logger.h" // STL includes @@ -35,11 +34,11 @@ // Project includes -namespace NLMISC { +namespace NLPIPELINE { // Tool logger is fully implemented in header so small tools do not need to link to this library unnecessarily. void dummy_tool_logger_cpp() { } -} /* namespace NLMISC */ +} /* namespace NLPIPELINE */ /* end of file */ diff --git a/code/nel/tools/3d/mesh_utils/CMakeLists.txt b/code/nel/tools/3d/mesh_utils/CMakeLists.txt index a5a9fa952..c8390587c 100644 --- a/code/nel/tools/3d/mesh_utils/CMakeLists.txt +++ b/code/nel/tools/3d/mesh_utils/CMakeLists.txt @@ -7,7 +7,7 @@ INCLUDE_DIRECTORIES(${assimp_INCLUDE_DIRS}) NL_TARGET_LIB(mesh_utils ${SRCS} ${HDRS}) -TARGET_LINK_LIBRARIES(mesh_utils ${assimp_LIBRARIES} nelmisc nel3d) +TARGET_LINK_LIBRARIES(mesh_utils ${assimp_LIBRARIES} nelmisc nelpipeline nel3d) NL_DEFAULT_PROPS(mesh_utils "NeL, Tools, 3D: Mesh Utils") NL_ADD_RUNTIME_FLAGS(mesh_utils) diff --git a/code/nel/tools/3d/mesh_utils/assimp_material.cpp b/code/nel/tools/3d/mesh_utils/assimp_material.cpp index 5dbe8643c..4830d1b33 100644 --- a/code/nel/tools/3d/mesh_utils/assimp_material.cpp +++ b/code/nel/tools/3d/mesh_utils/assimp_material.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include #include diff --git a/code/nel/tools/3d/mesh_utils/assimp_shape.cpp b/code/nel/tools/3d/mesh_utils/assimp_shape.cpp index 7b404d1e2..7ab0729ae 100644 --- a/code/nel/tools/3d/mesh_utils/assimp_shape.cpp +++ b/code/nel/tools/3d/mesh_utils/assimp_shape.cpp @@ -28,7 +28,7 @@ #include #include -#include +#include #include diff --git a/code/nel/tools/3d/mesh_utils/mesh_utils.cpp b/code/nel/tools/3d/mesh_utils/mesh_utils.cpp index b8d70660e..8765e3960 100644 --- a/code/nel/tools/3d/mesh_utils/mesh_utils.cpp +++ b/code/nel/tools/3d/mesh_utils/mesh_utils.cpp @@ -19,7 +19,8 @@ #include "mesh_utils.h" #include -#include +#include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include -#include "database_config.h" #include "scene_meta.h" #include @@ -231,7 +231,7 @@ void exportShapes(CMeshUtilsContext &context) if (nodeContext.Shape) { std::string shapePath = NLMISC::CPath::standardizePath(context.Settings.DestinationDirectoryPath, true) + it->first + ".shape"; - context.ToolLogger.writeDepend(NLMISC::BUILD, shapePath.c_str(), "*"); + context.ToolLogger.writeDepend(NLPIPELINE::BUILD, shapePath.c_str(), "*"); NLMISC::COFile f; if (f.open(shapePath, false, false, true)) { @@ -262,7 +262,7 @@ void exportShapes(CMeshUtilsContext &context) std::string knownPath = NLMISC::CPath::lookup(fileName, false, false, false); if (!knownPath.empty()) { - context.ToolLogger.writeDepend(NLMISC::RUNTIME, shapePath.c_str(), knownPath.c_str()); + context.ToolLogger.writeDepend(NLPIPELINE::RUNTIME, shapePath.c_str(), knownPath.c_str()); } else { @@ -289,17 +289,17 @@ int exportScene(const CMeshUtilsSettings &settings) context.ToolLogger.initDepend(settings.ToolDependLog); if (!settings.ToolErrorLog.empty()) context.ToolLogger.initError(settings.ToolErrorLog); - context.ToolLogger.writeDepend(NLMISC::BUILD, "*", NLMISC::CPath::standardizePath(context.Settings.SourceFilePath, false).c_str()); // Base input file + context.ToolLogger.writeDepend(NLPIPELINE::BUILD, "*", NLMISC::CPath::standardizePath(context.Settings.SourceFilePath, false).c_str()); // Base input file // Apply database configuration - if (!CDatabaseConfig::init(settings.SourceFilePath)) + if (!NLPIPELINE::CProjectConfig::init(settings.SourceFilePath, + NLPIPELINE::CProjectConfig::DatabaseTextureSearchPaths, + true)) { tlerror(context.ToolLogger, context.Settings.SourceFilePath.c_str(), "Unable to find database.cfg in input path or any of its parents."); - return EXIT_FAILURE; + // return EXIT_FAILURE; We can continue but the output will not be guaranteed... } - CDatabaseConfig::initTextureSearchDirectories(); - Assimp::Importer importer; const aiScene *scene = importer.ReadFile(settings.SourceFilePath, 0 | aiProcess_Triangulate @@ -321,7 +321,7 @@ int exportScene(const CMeshUtilsSettings &settings) context.InternalScene = scene; if (context.SceneMeta.load(context.Settings.SourceFilePath)) - context.ToolLogger.writeDepend(NLMISC::BUILD, "*", context.SceneMeta.metaFilePath().c_str()); // Meta input file + context.ToolLogger.writeDepend(NLPIPELINE::BUILD, "*", context.SceneMeta.metaFilePath().c_str()); // Meta input file validateInternalNodeNames(context, context.InternalScene->mRootNode); diff --git a/code/nel/tools/3d/mesh_utils/scene_context.cpp b/code/nel/tools/3d/mesh_utils/scene_context.cpp index 6812a312a..243f13482 100644 --- a/code/nel/tools/3d/mesh_utils/scene_context.cpp +++ b/code/nel/tools/3d/mesh_utils/scene_context.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include using namespace std; using namespace NLMISC; diff --git a/code/nel/tools/3d/mesh_utils/scene_context.h b/code/nel/tools/3d/mesh_utils/scene_context.h index 714e3ff54..10fa55e46 100644 --- a/code/nel/tools/3d/mesh_utils/scene_context.h +++ b/code/nel/tools/3d/mesh_utils/scene_context.h @@ -23,7 +23,7 @@ #include "scene_meta.h" #include -#include +#include #include #include @@ -67,7 +67,7 @@ struct CMeshUtilsContext const CMeshUtilsSettings &Settings; - NLMISC::CToolLogger ToolLogger; + NLPIPELINE::CToolLogger ToolLogger; const NL_SCENE_INTERNAL_TYPE *InternalScene; CSceneMeta SceneMeta;