diff --git a/.gitignore b/.gitignore index 2094115..c0602fe 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,6 @@ Doxygen/ *.exe *.out *.app + +# VSCode +.vscode diff --git a/.travis.yml b/.travis.yml index 99e6394..64f5d51 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,7 @@ script: - export CC=/usr/bin/gcc-7 - export CXX=/usr/bin/g++-7 - gcc -v && g++ -v && cmake --version + - mkdir build - cd build - cmake .. - make diff --git a/CMake/Ogre_glTF_ConfigTargets.cmake b/CMake/Ogre_glTF_ConfigTargets.cmake new file mode 100644 index 0000000..c439f44 --- /dev/null +++ b/CMake/Ogre_glTF_ConfigTargets.cmake @@ -0,0 +1,41 @@ +function(Ogre_glTF_config_sample PROJECTNAME) + file(GLOB SOURCES ./*.cpp ./*.hpp ./include/*.hpp) + + add_executable(${PROJECTNAME} WIN32 MACOSX_BUNDLE ${SAMPLES_COMMON_HEADER_FILES} ${SAMPLES_COMMON_SOURCE_FILES} ${SOURCES}) + add_dependencies(${PROJECTNAME} Ogre_glTF) + + target_include_directories( ${PROJECTNAME} PUBLIC + #Ogre and the physics based high level material system + ${OGRE_INCLUDE_DIRS} + ${OGRE_HlmsPbs_INCLUDE_DIRS} + ${OGRE_INCLUDE_DIR}/Hlms/Common + ${CMAKE_SOURCE_DIR}/Samples/Common + ) + + target_link_libraries(${PROJECTNAME} + ${OGRE_LIBRARIES} + ${OGRE_HlmsPbs_LIBRARIES} + Ogre_glTF + ) + + if (Ogre_glTF_STATIC AND UNIX) + target_link_libraries(${PROJECTNAME} + ${OGRE_RenderSystem_GL3Plus_LIBRARIES} + ) + + if (NOT APPLE) + target_link_libraries(${PROJECTNAME} + dl + pthread + Xt + X11 + Xaw + Xrandr + ) + endif () + endif () + + set_target_properties(${PROJECTNAME} PROPERTIES + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + set_property(TARGET ${PROJECTNAME} PROPERTY VS_DEBUGGER_WORKING_DIRECTORY ${PROJECT_BINARY_DIR}) +endfunction(Ogre_glTF_config_sample) diff --git a/CMakeLists.txt b/CMakeLists.txt index a84323b..c846c0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,7 @@ project(Ogre_glTF) set(CMAKE_CXX_STANDARD 14) set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_INSTALL_PREFIX "./output") -set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 -D_DEBUG=1") +set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG=1 -D_DEBUG=1") if(NOT CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX "_d") @@ -14,26 +14,28 @@ endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/CMake) -#get Ogre from your system. May need to set some variable for Windows folks +include(Ogre_glTF_ConfigTargets) + +option(Ogre_glTF_STATIC "Static build" FALSE) + +if (Ogre_glTF_STATIC) + add_definitions(-DOgre_glTF_STATIC) + set(Ogre_glTF_LIB_TYPE STATIC) + set(Ogre_glTF_LIB_SUFFIX "Static") +else () + set(Ogre_glTF_LIB_TYPE SHARED) + set(Ogre_glTF_LIB_SUFFIX "") +endif () + +#Get Ogre from your system. May need to set some variables for Windows folks find_package(OGRE COMPONENTS HlmsPbs REQUIRED) file(GLOB librarySources ./src/*.cpp ./src/private_headers/*.hpp ./include/*.hpp) -file(GLOB testSources ./test/*.cpp ./test/*.hpp ./include/*.hpp) -file(GLOB pluginTestSources ./pluginTest/*.cpp ./pluginTest/*.hpp ./include/*.hpp) -add_library(Ogre_glTF SHARED ${librarySources}) -#add_library(Ogre_glTF_static STATIC ${librarySources}) +add_library(${PROJECT_NAME} ${Ogre_glTF_LIB_TYPE} ${librarySources}) -target_compile_definitions(Ogre_glTF PUBLIC Ogre_glTF_DLL_EXPORT_CONFIG_ON) +target_compile_definitions(${PROJECT_NAME} PUBLIC Ogre_glTF_DLL_EXPORT_CONFIG_ON) -if(MSVC) - add_executable(Ogre_glTF_TEST WIN32 ${testSources}) - add_executable(Ogre_gltf_PluginTest WIN32 ${pluginTestSources}) - #add_executable(Ogre_glTF_TEST_static WIN32 ${testSources}) -else() - add_executable(Ogre_glTF_TEST ${testSources}) - add_executable(Ogre_gltf_PluginTest ${pluginTestSources}) - #add_executable(Ogre_glTF_TEST_static ${testSources}) -endif(MSVC) +set_target_properties(${PROJECT_NAME} PROPERTIES OUTPUT_NAME ${PROJECT_NAME}${Ogre_glTF_LIB_SUFFIX}) target_include_directories( Ogre_glTF PUBLIC #Ogre and the physics based high level material system @@ -46,75 +48,15 @@ target_include_directories( Ogre_glTF PUBLIC ./thirdParty/tinygltf/ ) -#target_include_directories( Ogre_glTF_static PUBLIC -# #Ogre and the physics based high level material system -# ${OGRE_INCLUDE_DIRS} -# ${OGRE_HlmsPbs_INCLUDE_DIRS} - -# #local include directory -# ./include -# ./src/private_headers -# ./thirdParty/tinygltf/ -#) - -target_include_directories( Ogre_glTF_TEST PUBLIC - #Ogre and the physics based high level material system - ${OGRE_INCLUDE_DIRS} - ${OGRE_HlmsPbs_INCLUDE_DIRS} - ${OGRE_INCLUDE_DIR}/Hlms/Common - - #local include directory - ./include -) - - -# target_include_directories( Ogre_glTF_TEST_static PUBLIC -# #Ogre and the physics based high level material system -# ${OGRE_INCLUDE_DIRS} -# ${OGRE_HlmsPbs_INCLUDE_DIRS} -# -# #local include directory -# ./include -#) - -target_include_directories(Ogre_gltf_PluginTest PUBLIC - ${OGRE_INCLUDE_DIRS} - ${OGRE_HlmsPbs_INCLUDE_DIRS} - ${OGRE_INCLUDE_DIR}/Hlms/Common - ./include -) - target_link_libraries(Ogre_glTF ${OGRE_LIBRARIES} ${OGRE_HlmsPbs_LIBRARIES} ) -target_link_libraries(Ogre_glTF_TEST - ${OGRE_LIBRARIES} - ${OGRE_HlmsPbs_LIBRARIES} - - #the library we just built - Ogre_glTF -) - -target_link_libraries(Ogre_gltf_PluginTest - ${OGRE_LIBRARIES} - ${OGRE_HlmsPbs_LIBRARIES} -) - -add_dependencies(Ogre_gltf_PluginTest Ogre_glTF) - -#target_link_libraries(Ogre_glTF_TEST_static -# ${OGRE_LIBRARIES} -# ${OGRE_HlmsPbs_LIBRARIES} -# -# #the library we just built -# Ogre_glTF_static -#) +add_subdirectory(Samples) #installation -install(TARGETS Ogre_glTF DESTINATION "bin") install(FILES ./include/Ogre_glTF.hpp ./include/Ogre_glTF_OgrePlugin.hpp @@ -122,3 +64,5 @@ install(FILES ./include/Ogre_glTF_DLL.hpp DESTINATION "include") + +install(TARGETS Ogre_glTF DESTINATION "bin") diff --git a/build/BrainStem.glb b/Media/BrainStem.glb similarity index 100% rename from build/BrainStem.glb rename to Media/BrainStem.glb diff --git a/build/CesiumMan.glb b/Media/CesiumMan.glb similarity index 100% rename from build/CesiumMan.glb rename to Media/CesiumMan.glb diff --git a/build/Corset.glb b/Media/Corset.glb similarity index 100% rename from build/Corset.glb rename to Media/Corset.glb diff --git a/build/Monster.glb b/Media/Monster.glb similarity index 100% rename from build/Monster.glb rename to Media/Monster.glb diff --git a/build/MyCube.glb b/Media/MyCube.glb similarity index 100% rename from build/MyCube.glb rename to Media/MyCube.glb diff --git a/build/RiggedFigure.glb b/Media/RiggedFigure.glb similarity index 100% rename from build/RiggedFigure.glb rename to Media/RiggedFigure.glb diff --git a/build/RiggedSimple.glb b/Media/RiggedSimple.glb similarity index 100% rename from build/RiggedSimple.glb rename to Media/RiggedSimple.glb diff --git a/Media/blob.glb b/Media/blob.glb new file mode 100644 index 0000000..8430cf7 Binary files /dev/null and b/Media/blob.glb differ diff --git a/build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_AO.jpg b/Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_AO.jpg similarity index 100% rename from build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_AO.jpg rename to Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_AO.jpg diff --git a/build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_MetalSmooth_converted_metalRoughness.jpg b/Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_MetalSmooth_converted_metalRoughness.jpg similarity index 100% rename from build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_MetalSmooth_converted_metalRoughness.jpg rename to Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_MetalSmooth_converted_metalRoughness.jpg diff --git a/build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_albedo.jpg b/Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_albedo.jpg similarity index 100% rename from build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_albedo.jpg rename to Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_albedo.jpg diff --git a/build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_emissive.jpg b/Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_emissive.jpg similarity index 100% rename from build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_emissive.jpg rename to Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_emissive.jpg diff --git a/build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_normal.jpg b/Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_normal.jpg similarity index 100% rename from build/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_normal.jpg rename to Media/damagedHelmet/Assets/Models/PBR/damagedHelmet/textures/Default_normal.jpg diff --git a/build/damagedHelmet/LICENSE.txt b/Media/damagedHelmet/LICENSE.txt similarity index 100% rename from build/damagedHelmet/LICENSE.txt rename to Media/damagedHelmet/LICENSE.txt diff --git a/build/damagedHelmet/damagedHelmet.bin b/Media/damagedHelmet/damagedHelmet.bin similarity index 100% rename from build/damagedHelmet/damagedHelmet.bin rename to Media/damagedHelmet/damagedHelmet.bin diff --git a/build/damagedHelmet/damagedHelmet.gltf b/Media/damagedHelmet/damagedHelmet.gltf similarity index 100% rename from build/damagedHelmet/damagedHelmet.gltf rename to Media/damagedHelmet/damagedHelmet.gltf diff --git a/misc/gizmo.blend b/Media/gizmo.blend similarity index 100% rename from misc/gizmo.blend rename to Media/gizmo.blend diff --git a/build/gizmo.glb b/Media/gizmo.glb similarity index 100% rename from build/gizmo.glb rename to Media/gizmo.glb diff --git a/build/gltfFiles.zip b/Media/gltfFiles.zip similarity index 100% rename from build/gltfFiles.zip rename to Media/gltfFiles.zip diff --git a/build/marker.glb b/Media/marker.glb similarity index 100% rename from build/marker.glb rename to Media/marker.glb diff --git a/Media/spring.glb b/Media/spring.glb new file mode 100644 index 0000000..b10e8d0 Binary files /dev/null and b/Media/spring.glb differ diff --git a/README.md b/README.md index dc7f864..1105be6 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ auto glTFLoader = gltfPluginAccessor::findPlugin()->getLoader(); Ogre::Item* cesiumMan = glTFLoader->getModelData("CesiumMan.glb", glTFLoaderInterface::LoadFrom::ResourceManager).makeItem(smgr); ``` +In case you cloned without `--recursive`, `cd` into the `Ogre_glTF` directory and use `git submodule update --init --recursive` to download dependencies correctly. + ## Building the source code diff --git a/Samples/CMakeLists.txt b/Samples/CMakeLists.txt new file mode 100644 index 0000000..cd3bab0 --- /dev/null +++ b/Samples/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(Common) +add_subdirectory(LoadMesh) +add_subdirectory(SkinnedMesh) + +add_custom_target(CopyHLMS ALL + ${CMAKE_COMMAND} -E copy_directory ${OGRE_MEDIA_DIR}/Hlms ${PROJECT_BINARY_DIR}/Media/Hlms +) \ No newline at end of file diff --git a/Samples/Common/CMakeLists.txt b/Samples/Common/CMakeLists.txt new file mode 100644 index 0000000..9796b01 --- /dev/null +++ b/Samples/Common/CMakeLists.txt @@ -0,0 +1,2 @@ +set(SAMPLES_COMMON_HEADER_FILES SamplesCommon.h) +set(SAMPLES_COMMON_SOURCE_FILES SamplesCommon.cpp) \ No newline at end of file diff --git a/Samples/Common/SamplesCommon.cpp b/Samples/Common/SamplesCommon.cpp new file mode 100644 index 0000000..e69de29 diff --git a/Samples/Common/SamplesCommon.h b/Samples/Common/SamplesCommon.h new file mode 100644 index 0000000..8133155 --- /dev/null +++ b/Samples/Common/SamplesCommon.h @@ -0,0 +1,95 @@ +#include +//To create workspace definitions and workspaces +#include +//To use the hlms +#include +#include +//To load Hlms +#include +//To use objects +#include +#include +#include +#include +//To play animations +#include +//To use smart pointers +#include + +//The library we are trying out in this program +#include + +#ifdef _DEBUG +const char GL_RENDER_PLUGIN[] = "RenderSystem_GL3Plus_d"; +#else +const char GL_RENDER_PLUGIN[] = "RenderSystem_GL3Plus"; +#endif + +#ifdef _WIN32 +#ifdef _DEBUG +const char D3D11_RENDER_PLUGIN[] = "RenderSystem_Direct3D11_d"; +#else +const char D3D11_RENDER_PLUGIN[] = "RenderSystem_Direct3D11"; +#endif +#endif + +#ifdef Ogre_glTF_STATIC +#include +#endif + +#ifdef _WIN32 +#define NOMINMAX +#include +#define main() WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT) +#else +#define main() main(int argc, char* argv[]) +#endif + +void DeclareHlmsLibrary(Ogre::String dataFolder) +{ + //Make sure the string we got is a valid path + if(dataFolder.empty()) + dataFolder = "./"; + else if(dataFolder[dataFolder.size() - 1] != '/') + dataFolder += '/'; + + //For retrieval of the paths to the different folders needed + Ogre::String dataFolderPath; + Ogre::StringVector libraryFoldersPaths; + +#ifdef USE_UNLIT //We are loading materials based on physics + //Get the path to all the subdirectories used by HlmsUnlit + Ogre::HlmsUnlit::getDefaultPaths(dataFolderPath, libraryFoldersPaths); + + //Create the Ogre::Archive objects needed + Ogre::Archive* archiveUnlit = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); + Ogre::ArchiveVec archiveUnlitLibraryFolders; + for(const auto& libraryFolderPath : libraryFoldersPaths) + { + Ogre::Archive* archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); + archiveUnlitLibraryFolders.push_back(archiveLibrary); + } + + //Create and register the unlit Hlms + Ogre::HlmsUnlit* hlmsUnlit = OGRE_NEW Ogre::HlmsUnlit(archiveUnlit, &archiveUnlitLibraryFolders); + Ogre::Root::getSingleton().getHlmsManager()->registerHlms(hlmsUnlit); + hlmsUnlit->setDebugOutputPath(false, false); +#endif + + //Do the same for HlmsPbs: + Ogre::HlmsPbs::getDefaultPaths(dataFolderPath, libraryFoldersPaths); + Ogre::Archive* archivePbs = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); + + //Get the library archive(s) + Ogre::ArchiveVec archivePbsLibraryFolders; + for(const auto& libraryFolderPath : libraryFoldersPaths) + { + Ogre::Archive* archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); + archivePbsLibraryFolders.push_back(archiveLibrary); + } + + //Create and register + Ogre::HlmsPbs* hlmsPbs = OGRE_NEW Ogre::HlmsPbs(archivePbs, &archivePbsLibraryFolders); + Ogre::Root::getSingleton().getHlmsManager()->registerHlms(hlmsPbs); + hlmsPbs->setDebugOutputPath(false, false); +} \ No newline at end of file diff --git a/Samples/LoadMesh/CMakeLists.txt b/Samples/LoadMesh/CMakeLists.txt new file mode 100644 index 0000000..a4e8048 --- /dev/null +++ b/Samples/LoadMesh/CMakeLists.txt @@ -0,0 +1 @@ +Ogre_glTF_config_sample(LoadMesh) \ No newline at end of file diff --git a/Samples/LoadMesh/main.cpp b/Samples/LoadMesh/main.cpp new file mode 100644 index 0000000..aef1c74 --- /dev/null +++ b/Samples/LoadMesh/main.cpp @@ -0,0 +1,117 @@ +#include "SamplesCommon.h" + +int main() +{ +#ifdef Ogre_glTF_STATIC + // Must instantiate before Root so that it'll be destroyed afterwards. + // Otherwise we get a crash on Ogre::Root::shutdownPlugins() +#if __linux__ + auto glPlugin = std::make_unique(); +#endif +#endif + + //Init Ogre + auto root = std::make_unique(); + Ogre::LogManager::getSingleton().setLogDetail(Ogre::LoggingLevel::LL_BOREME); + +#ifdef Ogre_glTF_STATIC +#if __linux__ + root->installPlugin(glPlugin.get()); +#endif +#else + root->loadPlugin(GL_RENDER_PLUGIN); +#ifdef _WIN32 + root->loadPlugin(D3D11_RENDER_PLUGIN); +#endif +#endif + root->showConfigDialog(); + root->getRenderSystem()->setConfigOption("FSAA", "16"); + root->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes"); + root->initialise(false); + + //Create a window and a scene + Ogre::NameValuePairList params; + params["FSAA"] = "16"; + const auto window = root->createRenderWindow("glTF test!", 800, 600, false, ¶ms); + + auto smgr = root->createSceneManager(Ogre::ST_GENERIC, 2, Ogre::INSTANCING_CULLING_THREADED); + smgr->showBoundingBoxes(true); + smgr->setDisplaySceneNodes(true); + auto camera = smgr->createCamera("cam"); + + //Setup rendering pipeline + auto compositor = root->getCompositorManager2(); + const char workspaceName[] = "workspace0"; + compositor->createBasicWorkspaceDef(workspaceName, Ogre::ColourValue { 0.2f, 0.3f, 0.4f }); + auto workspace = compositor->addWorkspace(smgr, window, camera, workspaceName, true); + + DeclareHlmsLibrary("./Media"); + + Ogre::ResourceGroupManager::getSingleton().addResourceLocation("../Media/gltfFiles.zip", "Zip"); + Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(true); + + auto gltf = std::make_unique(); + Ogre::SceneNode* objectNode = nullptr; + + try + { + auto adapter = gltf->loadFromFileSystem("../Media/damagedHelmet/damagedHelmet.gltf"); + objectNode = adapter.getFirstSceneNode(smgr); + + // On a scene with multiple root objects `loadMainScene` can be used to load all objects. + /* + auto root = smgr->getRootSceneNode(); + adapter.loadMainScene(root, smgr); + auto childIt = root->getChildIterator(); + while(childIt.hasMoreElements()) + { + auto child = childIt.getNext(); + if(child->getName() == "UnityGlTF_root") + { + objectNode = static_cast(child); + break; + } + }*/ + } + catch(std::exception& e) + { + Ogre::LogManager::getSingleton().logMessage(e.what()); + return -1; + } + + camera->setNearClipDistance(0.001f); + camera->setFarClipDistance(100); + camera->setPosition(2.5f, 0.6f, 2.5f); + camera->lookAt({ 0, -0.1f, 0 }); + camera->setAutoAspectRatio(true); + + auto light = smgr->createLight(); + smgr->getRootSceneNode()->createChildSceneNode()->attachObject(light); + light->setType(Ogre::Light::LT_DIRECTIONAL); + light->setDirection(Ogre::Vector3 { -1, -1, -0.5f }); + light->setPowerScale(5); + + light = smgr->createLight(); + smgr->getRootSceneNode()->createChildSceneNode()->attachObject(light); + light->setType(Ogre::Light::LT_DIRECTIONAL); + light->setDirection(Ogre::Vector3 { +1, +1, +0.5f }); + light->setPowerScale(5); + + auto last = root->getTimer()->getMilliseconds(); + auto now = last; + Ogre::Real accumulator = 0; + + while(!window->isClosed()) + { + now = root->getTimer()->getMilliseconds(); + accumulator += (now - last) / 1000.0f; + last = now; + + objectNode->setOrientation(Ogre::Quaternion(Ogre::Radian(accumulator), Ogre::Vector3::UNIT_Y)); + + root->renderOneFrame(); + Ogre::WindowEventUtilities::messagePump(); + } + + return 0; +} diff --git a/Samples/SkinnedMesh/CMakeLists.txt b/Samples/SkinnedMesh/CMakeLists.txt new file mode 100644 index 0000000..90ffb5c --- /dev/null +++ b/Samples/SkinnedMesh/CMakeLists.txt @@ -0,0 +1 @@ +Ogre_glTF_config_sample(SkinnedMesh) \ No newline at end of file diff --git a/Samples/SkinnedMesh/main.cpp b/Samples/SkinnedMesh/main.cpp new file mode 100644 index 0000000..d751350 --- /dev/null +++ b/Samples/SkinnedMesh/main.cpp @@ -0,0 +1,137 @@ +#include "SamplesCommon.h" + +Ogre::CompositorWorkspace* SetupCompositor(Ogre::Root* root, Ogre::RenderWindow* const window, Ogre::SceneManager* smgr, Ogre::Camera* camera) +{ + //Setup rendering pipeline + auto compositor = root->getCompositorManager2(); + const char workspaceName[] = "workspace0"; + compositor->createBasicWorkspaceDef(workspaceName, Ogre::ColourValue { 0.2f, 0.3f, 0.4f }); + auto workspace = compositor->addWorkspace(smgr, window, camera, workspaceName, true); + + return workspace; +} + +int main() +{ +#ifdef Ogre_glTF_STATIC + // Must instantiate before Root so that it'll be destroyed afterwards. + // Otherwise we get a crash on Ogre::Root::shutdownPlugins() +#if __linux__ + auto glPlugin = std::make_unique(); +#endif +#endif + + //Init Ogre + auto root = std::make_unique(); + Ogre::LogManager::getSingleton().setLogDetail(Ogre::LoggingLevel::LL_BOREME); + +#ifdef Ogre_glTF_STATIC +#if __linux__ + root->installPlugin(glPlugin.get()); +#endif +#else + root->loadPlugin(GL_RENDER_PLUGIN); +#ifdef _WIN32 + root->loadPlugin(D3D11_RENDER_PLUGIN); +#endif +#endif + root->showConfigDialog(); + root->getRenderSystem()->setConfigOption("FSAA", "16"); + root->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes"); + root->initialise(false); + + //Create a window and a scene + Ogre::NameValuePairList params; + params["FSAA"] = "16"; + const auto window = root->createRenderWindow("glTF test!", 800, 600, false, ¶ms); + + auto smgr = root->createSceneManager(Ogre::ST_GENERIC, 2, Ogre::INSTANCING_CULLING_THREADED); + smgr->setForward3D(true, 4, 4, 5, 96, 3, 200); + auto camera = smgr->createCamera("cam"); + camera->setNearClipDistance(0.001f); + camera->setFarClipDistance(100); + camera->setAutoAspectRatio(true); + camera->setPosition(2, 2, 2); + camera->lookAt(0, 1, 0); + + //Load workspace and hlms + auto workspace = SetupCompositor(root.get(), window, smgr, camera); + + DeclareHlmsLibrary("./Media"); + + Ogre::ResourceGroupManager::getSingleton().addResourceLocation("../Media/gltfFiles.zip", "Zip"); + Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(true); + + auto gltf = std::make_unique(); + Ogre::SceneNode* objectNode = nullptr; + + try + { + auto adapter = gltf->loadGlbResource("CesiumMan.glb"); + objectNode = adapter.getFirstSceneNode(smgr); + } + catch(std::exception& e) + { + Ogre::LogManager::getSingleton().logMessage(e.what()); + return -1; + } + + //Add light + auto light = smgr->createLight(); + light->setType(Ogre::Light::LightTypes::LT_POINT); + light->setPowerScale(5); + auto lightNode = smgr->getRootSceneNode()->createChildSceneNode(); + lightNode->attachObject(light); + lightNode->setPosition(1, 1, 1); + + //Setup animation and update it over time + Ogre::SkeletonAnimation* animation = nullptr; + // Find a node that contains an item that contains an skeleton + auto childIt = objectNode->getChildIterator(); + + while(childIt.hasMoreElements()) + { + auto sceneNode = static_cast(childIt.getNext()); + if(sceneNode->numAttachedObjects() > 0) + { + auto itemIt = sceneNode->getAttachedObjectIterator(); + + while(itemIt.hasMoreElements()) + { + auto item = static_cast(itemIt.getNext()); + auto skeleton = item->getSkeletonInstance(); + + if(skeleton) + { + const auto animationName = (skeleton->getAnimations().front().getName()); + animation = item->getSkeletonInstance()->getAnimation(animationName); + animation->setEnabled(true); + animation->setLoop(true); + break; + } + } + } + } + + + auto timer = root->getTimer(); + auto now = timer->getMilliseconds(); + auto last = now; + auto duration = now - last; + + //Update + while(!window->isClosed()) + { + //Add time to animation + now = timer->getMilliseconds(); + duration = (now - last); + animation->addTime(Ogre::Real(duration) / 1000.0f); + last = now; + + //Render + root->renderOneFrame(); + Ogre::WindowEventUtilities::messagePump(); + } + + return 0; +} diff --git a/include/Ogre_glTF.hpp b/include/Ogre_glTF.hpp index 25c6e6f..aa0c53c 100644 --- a/include/Ogre_glTF.hpp +++ b/include/Ogre_glTF.hpp @@ -11,40 +11,6 @@ namespace Ogre_glTF //Forward declare main class class glTFLoader; - ///Structure that contains the information of the model that you loaded - struct ModelInformation - { - ///Easy method to build an item to use - /// \param smgr pointer to the scene manager where to create the item - /// \param sceneType tell if it will be static or dynamic - Ogre::Item* makeItem(Ogre::SceneManager* smgr, Ogre::SceneMemoryMgrTypes sceneType = Ogre::SCENE_DYNAMIC) - { - auto item = smgr->createItem(mesh, sceneType); - for(size_t i = 0; i < item->getNumSubItems(); ++i) { item->getSubItem(i)->setDatablock(pbrMaterialList[i]); } - return item; - } - - ///Smart pointer to the loaded mesh - Ogre::MeshPtr mesh; - ///List of materials that correspond to each of the submeshes in the model - std::vector pbrMaterialList; - - ///Local transform on the glTF node this model came from - struct ModelTransform - { - Ogre::Vector3 position = Ogre::Vector3::ZERO; - Ogre::Vector3 scale = Ogre::Vector3::UNIT_SCALE; - Ogre::Quaternion orientation = Ogre::Quaternion::IDENTITY; - - void apply (Ogre::SceneNode* node) - { - node->setPosition(position); - node->setScale(scale); - node->setOrientation(orientation); - } - } transform; - }; - ///Plugin accessible interface that plugin users can use struct glTFLoaderInterface { @@ -53,12 +19,6 @@ namespace Ogre_glTF ///location where to load the data enum class LoadFrom { FileSystem, ResourceManager }; - - ///Get the model data - ///\param modelName name of the resource being loaded - ///\param loadLocation flag that signal if the model is loaded directly from the filesystem, or from Ogre's resource manager - virtual ModelInformation getModelData(const std::string& modelName, LoadFrom loadLocation) = 0; - }; ///Class that hold the loaded content of a glTF file and that can create Ogre objects from it @@ -87,9 +47,6 @@ namespace Ogre_glTF ///Deleted assignment constructor : non copyable class loaderAdapter& operator=(const loaderAdapter&) = delete; - ///Return the mesh loaded from the glTF file - Ogre::MeshPtr getMesh() const; - ///Return one of the datablocks loaded from the gltf file. ///\param index of the datablocks used. In a multi-material file, it should be one different per primitive (submesh). Ogre::HlmsDatablock* getDatablock(size_t index = 0) const; @@ -97,12 +54,15 @@ namespace Ogre_glTF ///Return the number of datablock stored size_t getDatablockCount(); - ///Get the local transform to apply to the node to align the model with what you would expect. - ModelInformation::ModelTransform getTransform(); + void loadMainScene(Ogre::SceneNode* parentNode, Ogre::SceneManager* smgr) const; ///Construct an item for this object /// \param smgr pointer to the scene manager where we are creating the item - Ogre::Item* getItem(Ogre::SceneManager* smgr) const; + Ogre::SceneNode* getFirstSceneNode(Ogre::SceneManager* smgr) const; + + Ogre::SceneNode* getSceneNode(size_t index, Ogre::SceneNode* parentSceneNode, Ogre::SceneManager* smgr) const; + + void createTagPoints(int boneIndex, Ogre::SkeletonInstance* skeletonInstance, Ogre::SceneManager* smgr) const; ///Move constructor : object is movable /// \param other object to move @@ -148,9 +108,6 @@ namespace Ogre_glTF ///Load a GLB from Ogre's resource manager loaderAdapter loadGlbResource(const std::string& name) const; - ///Get the model data. Contains everything you need to create object from the model contained on the glTF asset - ModelInformation getModelData(const std::string& modelName, LoadFrom loadLocation) override; - ///Deleted copy constructor glTFLoader(const glTFLoader&) = delete; diff --git a/pluginTest/main.cpp b/pluginTest/main.cpp deleted file mode 100644 index d0fc51c..0000000 --- a/pluginTest/main.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include -#include -#include -#include - -#include "Ogre_glTF_OgrePlugin.hpp" - -#ifdef _DEBUG -const char GL_RENDER_PLUGIN[] = "./RenderSystem_GL3Plus_d"; -#else -const char GL_RENDER_PLUGIN[] = "./RenderSystem_GL3Plus"; -#endif - -#ifdef _WIN32 -#ifdef _DEBUG -const char D3D11_RENDER_PLUGIN[] = "./RenderSystem_Direct3D11_d"; -const char Ogre_glTF_PluginPath[] = "./Debug/Ogre_glTF_d"; -#else -const char D3D11_RENDER_PLUGIN[] = "./RenderSystem_Direct3D11"; -const char Ogre_glTF_PluginPath[] = "./Release/Ogre_glTF"; -#endif -#endif - -//Redefine the entry point of the program to use int main() on Windows -#ifdef _WIN32 -#define NOMINMAX -#include -#define main() WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT) -#else -#define main() main(int argc, char* argv[]) -#endif - -using namespace Ogre; -using namespace Ogre_glTF; - -void declareHlmsLibrary(String dataFolder) -{ - //Make sure the string we got is a valid path - if(dataFolder.empty()) - dataFolder = "./"; - else if(dataFolder[dataFolder.size() - 1] != '/') - dataFolder += '/'; - - //For retrieval of the paths to the different folders needed - String dataFolderPath; - StringVector libraryFoldersPaths; - -#ifdef USE_UNLIT //We are loading materials based on physics - //Get the path to all the subdirectories used by HlmsUnlit - Ogre::HlmsUnlit::getDefaultPaths(dataFolderPath, libraryFoldersPaths); - - //Create the Ogre::Archive objects needed - Ogre::Archive* archiveUnlit = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); - Ogre::ArchiveVec archiveUnlitLibraryFolders; - for(const auto& libraryFolderPath : libraryFoldersPaths) - { - Ogre::Archive* archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); - archiveUnlitLibraryFolders.push_back(archiveLibrary); - } - - //Create and register the unlit Hlms - Ogre::HlmsUnlit* hlmsUnlit = OGRE_NEW Ogre::HlmsUnlit(archiveUnlit, &archiveUnlitLibraryFolders); - Ogre::Root::getSingleton().getHlmsManager()->registerHlms(hlmsUnlit); - hlmsUnlit->setDebugOutputPath(false, false); -#endif - - //Do the same for HlmsPbs: - HlmsPbs::getDefaultPaths(dataFolderPath, libraryFoldersPaths); - Archive* archivePbs = ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); - - //Get the library archive(s) - ArchiveVec archivePbsLibraryFolders; - for(const auto& libraryFolderPath : libraryFoldersPaths) - { - Archive* archiveLibrary = ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); - archivePbsLibraryFolders.push_back(archiveLibrary); - } - - //Create and register - HlmsPbs* hlmsPbs = OGRE_NEW HlmsPbs(archivePbs, &archivePbsLibraryFolders); - Root::getSingleton().getHlmsManager()->registerHlms(hlmsPbs); - hlmsPbs->setDebugOutputPath(false, false); -} - -CompositorWorkspace* setupCompositor(Root* root, RenderWindow* const window, SceneManager* smgr, Camera* camera) -{ - //Setup rendering pipeline - auto compositor = root->getCompositorManager2(); - const char workspaceName[] = "workspace0"; - compositor->createBasicWorkspaceDef(workspaceName, ColourValue { 0.2f, 0.3f, 0.4f }); - auto workspace = compositor->addWorkspace(smgr, window, camera, workspaceName, true); - - return workspace; -} - -int main() -{ - //Create Ogre's root, and load every plugins you normally do (could use plugin.cfg for same effect) - auto root = std::make_unique(); - LogManager::getSingleton().setLogDetail(LL_BOREME); - root->loadPlugin(GL_RENDER_PLUGIN); -#ifdef _WIN32 - root->loadPlugin(D3D11_RENDER_PLUGIN); - //Append the Ogre_glTF plugin to that list - root->loadPlugin(Ogre_glTF_PluginPath); -#else - root->loadPlugin("./libOgre_glTF.so"); -#endif - - //Startup Ogre as you would generally do it - root->showConfigDialog(); - root->getRenderSystem()->setConfigOption("FSAA", "16"); - root->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes"); - root->initialise(false); - - //Create a window and a scene - NameValuePairList params; - params["FSAA"] = "16"; - params["gamma"] = "true"; - const auto window = root->createRenderWindow("glTF test!", 800, 600, false, ¶ms); - auto smgr = root->createSceneManager(ST_GENERIC, 2, INSTANCING_CULLING_THREADED); - smgr->setForward3D(true, 4, 4, 5, 96, 3, 200); - auto camera = smgr->createCamera("cam"); - camera->setNearClipDistance(0.001f); - camera->setFarClipDistance(100); - camera->setAutoAspectRatio(true); - camera->setPosition(2, 2, 2); - camera->lookAt(0, 1, 0); - - //Load workspace and hlms - auto workspace = setupCompositor(root.get(), window, smgr, camera); - declareHlmsLibrary("./"); - - //Init resources - ResourceGroupManager::getSingleton().addResourceLocation("gltfFiles.zip", "Zip"); - ResourceGroupManager::getSingleton().initialiseAllResourceGroups(true); - - //Get access to the gltf loader, and load a GLB file in the resources to an item - auto glTFLoader = gltfPluginAccessor::findPlugin()->getLoader(); - auto model = glTFLoader->getModelData("CesiumMan.glb", glTFLoaderInterface::LoadFrom::ResourceManager); - auto item = model.makeItem(smgr); - auto itemNode = smgr->getRootSceneNode()->createChildSceneNode(); - itemNode->attachObject(item); - model.transform.apply(itemNode); - - //Add light - auto light = smgr->createLight(); - light->setType(Light::LightTypes::LT_POINT); - light->setPowerScale(5); - auto lightNode = smgr->getRootSceneNode()->createChildSceneNode(); - lightNode->attachObject(light); - lightNode->setPosition(1, 1, 1); - - //Setup animation and how to update it with time - const auto animationName = (item->getSkeletonInstance()->getAnimations().front().getName()); - auto animation = item->getSkeletonInstance()->getAnimation(animationName); - animation->setEnabled(true); - animation->setLoop(true); - auto timer = root->getTimer(); - auto now = timer->getMilliseconds(); - auto last = now; - auto duration = now - last; - - //Update - while(!window->isClosed()) - { - //Add time to animation - now = timer->getMilliseconds(); - duration = (now - last); - animation->addTime(Real(duration) / 1000.0f); - last = now; - - //Render - root->renderOneFrame(); - WindowEventUtilities::messagePump(); - } -} diff --git a/src/Ogre_glTF.cpp b/src/Ogre_glTF.cpp index 33ad591..dd14c61 100644 --- a/src/Ogre_glTF.cpp +++ b/src/Ogre_glTF.cpp @@ -7,6 +7,7 @@ #include "Ogre_glTF_skeletonImporter.hpp" #include "Ogre_glTF_common.hpp" #include "Ogre_glTF_OgreResource.hpp" +#include "Ogre_glTF_internal_utils.hpp" #define TINYGLTF_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION @@ -15,6 +16,7 @@ #include #include +#include using namespace Ogre_glTF; @@ -55,33 +57,202 @@ loaderAdapter::loaderAdapter() : pimpl { std::make_unique() } { OgreLog("C loaderAdapter::~loaderAdapter() { OgreLog("Destructed adapter object..."); } -Ogre::Item* loaderAdapter::getItem(Ogre::SceneManager* smgr) const +void loaderAdapter::loadMainScene(Ogre::SceneNode* parentNode, Ogre::SceneManager* smgr) const { - if(isOk()) - { - pimpl->textureImp.loadTextures(); - Ogre::MeshPtr Mesh = getMesh(); + if(!isOk()) + return; + + pimpl->textureImp.loadTextures(); + auto sceneIdx = pimpl->model.defaultScene >= 0 ? pimpl->model.defaultScene : 0; + const auto& scene = pimpl->model.scenes[sceneIdx]; - auto Item = smgr->createItem(Mesh); - for(size_t i = 0; i < Item->getNumSubItems(); ++i) { Item->getSubItem(i)->setDatablock(getDatablock(i)); } - return Item; + for(auto nodeIdx : scene.nodes) + { + getSceneNode(nodeIdx, parentNode, smgr); } - return nullptr; } -ModelInformation::ModelTransform loaderAdapter::getTransform() { return this->pimpl->modelConv.getTransform(); } +Ogre::SceneNode* loaderAdapter::getFirstSceneNode(Ogre::SceneManager* smgr) const +{ + if(!isOk()) + return nullptr; + + pimpl->textureImp.loadTextures(); + return getSceneNode(pimpl->model.scenes[0].nodes[0], smgr->getRootSceneNode(), smgr); +} + +Ogre::SceneNode* loaderAdapter::getSceneNode(size_t index, Ogre::SceneNode* parentSceneNode, Ogre::SceneManager* smgr) const +{ + assert(index < pimpl->model.nodes.size()); + + const auto& node = pimpl->model.nodes[index]; + // Check if node is not a bone + for(const auto& skin : pimpl->model.skins) + { + if(std::find(skin.joints.begin(), skin.joints.end(), index) != skin.joints.end()) + { + return nullptr; + } + } + + auto sceneNode = parentSceneNode->createChildSceneNode(); + sceneNode->setName(node.name); + + if(!node.translation.empty()) + sceneNode->setPosition(node.translation[0], node.translation[1], node.translation[2]); + + if(!node.rotation.empty()) + sceneNode->setOrientation(node.rotation[3], node.rotation[0], node.rotation[1], node.rotation[2]); + + if(!node.scale.empty()) + sceneNode->setScale(node.scale[0], node.scale[1], node.scale[2]); + + if(!node.matrix.empty()) + { + std::array matrixArray { 0 }; + internal_utils::container_double_to_real(node.matrix, matrixArray); + Ogre::Matrix4 matrix { matrixArray.data() }; + Ogre::Vector3 position; + Ogre::Quaternion orientation; + Ogre::Vector3 scale; + matrix.transpose().decomposition(position, scale, orientation); + sceneNode->setPosition(position); + sceneNode->setOrientation(orientation); + sceneNode->setScale(scale); + } + + if(node.mesh >= 0) + { + auto ogreMesh = pimpl->modelConv.getOgreMesh(node.mesh); + + if(node.skin >= 0) + { + auto skeleton = this->pimpl->skeletonImp.getSkeleton(node.skin); + if(skeleton) + { + ogreMesh->_notifySkeleton(skeleton); + } + } + + auto item = smgr->createItem(ogreMesh); + const auto& mesh = pimpl->model.meshes[node.mesh]; + for(size_t i = 0; i < mesh.primitives.size(); ++i) + { + auto subItem = item->getSubItem(i); + subItem->setDatablock(getDatablock(mesh.primitives[i].material)); + } + sceneNode->attachObject(item); + + // Add tag points + auto skeletonInstance = item->getSkeletonInstance(); + if(skeletonInstance) + { + // Find all root bones. Collect all children of all nodes in the skin and then find + // all nodes in the skin that are not in the set of children. Those are all nodes + // that don't have a parent because they're not a child of any other node. + std::vector rootBones; + std::vector allChildren; + const auto& skin = pimpl->model.skins[node.skin]; + + for(const auto& nodeIndex : skin.joints) + { + const auto& node = pimpl->model.nodes[nodeIndex]; + allChildren.insert(allChildren.end(), node.children.begin(), node.children.end()); + } + + for(const auto& nodeIndex : skin.joints) + { + if(std::find(allChildren.begin(), allChildren.end(), nodeIndex) == allChildren.end()) { + rootBones.push_back(nodeIndex); + } + } + + for(int boneIndex : rootBones) + { + createTagPoints(boneIndex, skeletonInstance, smgr); + } + } + } + + for(const auto& child : node.children) + { + getSceneNode(child, sceneNode, smgr); + } + + return sceneNode; +} -Ogre::MeshPtr loaderAdapter::getMesh() const +void loaderAdapter::createTagPoints(int boneIndex, Ogre::SkeletonInstance* skeletonInstance, Ogre::SceneManager* smgr) const { - auto Mesh = this->pimpl->modelConv.getOgreMesh(); + const auto& boneNode = pimpl->model.nodes[boneIndex]; - if(this->pimpl->modelConv.hasSkins()) + for(auto child : boneNode.children) { - //load skeleton information - auto skeleton = this->pimpl->skeletonImp.getSkeleton(this->adapterName); - Mesh->_notifySkeleton(skeleton); + const auto& childNode = pimpl->model.nodes[child]; + + if(childNode.mesh >= 0) + { + auto tagPoint = smgr->createTagPoint(); + tagPoint->setName(childNode.name); + + Ogre::Vector3 position; + Ogre::Quaternion orientation; + Ogre::Vector3 scale(1); + + if(!childNode.translation.empty()) + position = Ogre::Vector3(childNode.translation[0], childNode.translation[1], childNode.translation[2]); + + if(!childNode.rotation.empty()) + orientation = Ogre::Quaternion(childNode.rotation[3], childNode.rotation[0], childNode.rotation[1], childNode.rotation[2]); + + if(!childNode.scale.empty()) + scale = Ogre::Vector3(childNode.scale[0], childNode.scale[1], childNode.scale[2]); + + if(!childNode.matrix.empty()) + { + std::array matrixArray { 0 }; + internal_utils::container_double_to_real(childNode.matrix, matrixArray); + Ogre::Matrix4 matrix { matrixArray.data() }; + matrix.transpose().decomposition(position, scale, orientation); + } + + tagPoint->setPosition(position); + tagPoint->setOrientation(orientation); + tagPoint->setScale(scale); + + auto ogreMesh = pimpl->modelConv.getOgreMesh(childNode.mesh); + + if(childNode.skin >= 0) + { + auto skeleton = this->pimpl->skeletonImp.getSkeleton(childNode.skin); + if(skeleton) + { + ogreMesh->_notifySkeleton(skeleton); + } + } + + auto item = smgr->createItem(ogreMesh); + const auto& mesh = pimpl->model.meshes[childNode.mesh]; + for(size_t i = 0; i < mesh.primitives.size(); ++i) + { + auto subItem = item->getSubItem(i); + subItem->setDatablock(getDatablock(mesh.primitives[i].material)); + } + tagPoint->attachObject(item); + + auto parentBone = skeletonInstance->getBone(boneNode.name); + parentBone->addTagPoint(tagPoint); + + for(const auto& childOfChild : childNode.children) + { + getSceneNode(childOfChild, tagPoint, smgr); + } + } + else + { + createTagPoints(child, skeletonInstance, smgr); + } } - return Mesh; } Ogre::HlmsDatablock* loaderAdapter::getDatablock(size_t index) const { return pimpl->materialLoad.getDatablock(index); } @@ -210,30 +381,6 @@ loaderAdapter glTFLoader::loadGlbResource(const std::string& name) const return adapter; } -ModelInformation glTFLoader::getModelData(const std::string& modelName, LoadFrom loadLocation) -{ - auto adapter = [&] { - switch(loadLocation) - { - case LoadFrom::FileSystem: return loadFromFileSystem(modelName); - case LoadFrom::ResourceManager: return loadGlbResource(modelName); - } - - return loaderAdapter {}; - }(); - - if(!adapter.isOk()) OgreLog("adapter is signaling it isn't in \"ok\" state"); - - adapter.pimpl->textureImp.loadTextures(); - - ModelInformation model; - model.mesh = adapter.getMesh(); - model.transform = adapter.getTransform(); - for(size_t i { 0 }; i < adapter.getDatablockCount(); i++) model.pbrMaterialList.push_back(adapter.getDatablock(i)); - - return model; -} - glTFLoader::glTFLoader(glTFLoader&& other) noexcept : loaderImpl(std::move(other.loaderImpl)) {} glTFLoader& glTFLoader::operator=(glTFLoader&& other) noexcept diff --git a/src/Ogre_glTF_materialLoader.cpp b/src/Ogre_glTF_materialLoader.cpp index 101f464..70f129b 100644 --- a/src/Ogre_glTF_materialLoader.cpp +++ b/src/Ogre_glTF_materialLoader.cpp @@ -11,8 +11,8 @@ using namespace Ogre_glTF; Ogre::Vector3 materialLoader::convertColor(const tinygltf::ColorValue& color) { - std::array colorBuffer{}; - internal_utils::container_double_to_float(color, colorBuffer); + std::array colorBuffer{}; + internal_utils::container_double_to_real(color, colorBuffer); return Ogre::Vector3 { colorBuffer.data() }; } @@ -136,11 +136,8 @@ materialLoader::materialLoader(tinygltf::Model& input, textureImporter& textureI Ogre::HlmsDatablock* materialLoader::getDatablock(size_t index) const { OgreLog("Loading material..."); - //TODO this will need some modification if we support multiple meshes by glTF file auto HlmsPbs = static_cast(Ogre::Root::getSingleton().getHlmsManager()->getHlms(Ogre::HlmsTypes::HLMS_PBS)); - const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0); - const auto& mesh = model.meshes[mainMeshIndex]; - const auto material = model.materials[mesh.primitives.at(index).material]; + const auto material = model.materials[index]; auto datablock = static_cast(HlmsPbs->getDatablock(Ogre::IdString(material.name))); if(datablock) diff --git a/src/Ogre_glTF_modelConverter.cpp b/src/Ogre_glTF_modelConverter.cpp index 2145214..b672dc8 100644 --- a/src/Ogre_glTF_modelConverter.cpp +++ b/src/Ogre_glTF_modelConverter.cpp @@ -57,30 +57,50 @@ Ogre::VertexBufferPackedVec modelConverter::constructVertexBuffer(const std::vec return vec; } -//TODO make this method make the mesh id. Enumerate the meshes in the file before blindlessly loading the first one -Ogre::MeshPtr modelConverter::getOgreMesh() +Ogre::MeshPtr modelConverter::getOgreMesh(const Ogre::String& name) +{ + if(name.empty()) + { + if(!model.meshes.empty()) { + return getOgreMesh(0); + } + else + { + return Ogre::MeshPtr(); + } + } + + for(size_t meshIdx = 0; meshIdx < model.meshes.size(); ++meshIdx) { + const auto& mesh = model.meshes[meshIdx]; + if(!mesh.name.empty() && mesh.name == name) { + return getOgreMesh(meshIdx); + } + } + + return Ogre::MeshPtr(); +} + +Ogre::MeshPtr modelConverter::getOgreMesh(size_t meshIdx) { - OgreLog("Default scene" + std::to_string(model.defaultScene)); - const auto mainMeshIndex = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes.front()].mesh : 0); - const auto& mesh = model.meshes[mainMeshIndex]; Ogre::Aabb boundingBox; + auto& mesh = model.meshes[meshIdx]; OgreLog("Found mesh " + mesh.name + " in glTF file"); - auto OgreMesh = Ogre::MeshManager::getSingleton().getByName(mesh.name); - if(OgreMesh) + auto ogreMesh = Ogre::MeshManager::getSingleton().getByName(mesh.name); + if(ogreMesh) { OgreLog("Found mesh " + mesh.name + " in Ogre::MeshManager(v2)"); - return OgreMesh; + return ogreMesh; } OgreLog("Loading mesh from glTF file"); OgreLog("mesh has " + std::to_string(mesh.primitives.size()) + " primitives"); - OgreMesh = Ogre::MeshManager::getSingleton().createManual(mesh.name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); + ogreMesh = Ogre::MeshManager::getSingleton().createManual(mesh.name, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); OgreLog("Created mesh on v2 MeshManager"); for(const auto& primitive : mesh.primitives) { - auto subMesh = OgreMesh->createSubMesh(); + auto subMesh = ogreMesh->createSubMesh(); OgreLog("Created one submesh"); const auto indexBuffer = extractIndexBuffer(primitive.indices); @@ -92,7 +112,7 @@ Ogre::MeshPtr modelConverter::getOgreMesh() parts.push_back(std::move(extractVertexBuffer(atribute, boundingBox))); } - //Get (if they exists) the blend weights and bone index parts of our vertex array object content + //Get (if they exist) the blend weights and bone index parts of our vertex array object content const auto blendIndicesIt = std::find_if(std::begin(parts), std::end(parts), [](const vertexBufferPart& vertexBufferPart) { return (vertexBufferPart.semantic == Ogre::VertexElementSemantic::VES_BLEND_INDICES); }); @@ -169,10 +189,10 @@ Ogre::MeshPtr modelConverter::getOgreMesh() } } - OgreMesh->_setBounds(boundingBox, true); + ogreMesh->_setBounds(boundingBox, true); //OgreLog("Setting 'bounding sphere radius' from bounds : " + std::to_string(boundingBox.getRadius())); - return OgreMesh; + return ogreMesh; } void modelConverter::debugDump() const @@ -199,46 +219,6 @@ void modelConverter::debugDump() const bool modelConverter::hasSkins() const { return !model.skins.empty(); } -ModelInformation::ModelTransform modelConverter::getTransform() -{ - ModelInformation::ModelTransform trans; - std::array translation { 0 }, scale { 0 }; - std::array rotation { 0 }; - std::array local_matrix { 0 }; - bool set = false; - - // Just get the first one - not sure if there can be more for a model but doubt it - const auto& nodes = (model.defaultScene != 0 ? model.nodes[model.scenes[model.defaultScene].nodes[0]] : model.nodes[0]); - if(!nodes.translation.empty()) - { - internal_utils::container_double_to_float(nodes.translation, translation); - trans.position = Ogre::Vector3 { translation.data() }; - set = true; - } - if(!nodes.scale.empty()) - { - internal_utils::container_double_to_float(nodes.scale, scale); - trans.scale = Ogre::Vector3 { scale.data() }; - set = true; - } - if(!nodes.rotation.empty()) - { - internal_utils::container_double_to_float(nodes.rotation, rotation); - trans.orientation = Ogre::Quaternion { rotation[3], rotation[0], rotation[1], rotation[2] }; - set = true; - } - - if(!set && !nodes.matrix.empty()) - { - internal_utils::container_double_to_float(nodes.matrix, local_matrix); - Ogre::Matrix4 transform_matrix { local_matrix.data() }; - - transform_matrix.transpose().decomposition(trans.position, trans.scale, trans.orientation); - } - - return trans; -} - Ogre::VaoManager* modelConverter::getVaoManager() { //Our class shouldn't be able to exist if Ogre hasn't been initalized with a valid render system. This call should allways succeed. @@ -369,10 +349,10 @@ vertexBufferPart modelConverter::extractVertexBuffer(const std::pair floatVector {}; - internal_utils::container_double_to_float(accessor.minValues, floatVector); + std::array floatVector {}; + internal_utils::container_double_to_real(accessor.minValues, floatVector); const Ogre::Vector3 minBounds { floatVector.data() }; - internal_utils::container_double_to_float(accessor.maxValues, floatVector); + internal_utils::container_double_to_real(accessor.maxValues, floatVector); const Ogre::Vector3 maxBounds { floatVector.data() }; OgreLog("Updating bounding box size: "); diff --git a/src/Ogre_glTF_skeletonImporter.cpp b/src/Ogre_glTF_skeletonImporter.cpp index ced1701..0a939ad 100644 --- a/src/Ogre_glTF_skeletonImporter.cpp +++ b/src/Ogre_glTF_skeletonImporter.cpp @@ -12,13 +12,18 @@ using namespace Ogre_glTF; int skeletonImporter::skeletonID = 0; -void skeletonImporter::addChidren(const std::string& skinName, const std::vector& childs, Ogre::v1::OldBone* parent, const std::vector& joints) +void skeletonImporter::addChidren(const std::vector& childs, Ogre::v1::OldBone* parent) { for(auto child : childs) { const auto& node = model.nodes[child]; - //OgreLog("Node name is " + node.name + "!"); + + if(node.mesh >= 0) + { + // child is a mesh + continue; + } auto bone = skeleton->getBone(nodeToJointMap[child]); if(!bone) { throw InitError("could not get bone " + std::to_string(bone->getHandle())); } @@ -36,20 +41,24 @@ void skeletonImporter::addChidren(const std::string& skinName, const std::vector bone->setOrientation(parent->convertWorldToLocalOrientation(rotation)); bone->setScale(parent->_getDerivedScale() / scale); - addChidren(skinName + std::to_string(child), model.nodes[child].children, bone, joints); + addChidren(model.nodes[child].children, bone); } } -void skeletonImporter::loadBoneHierarchy(const tinygltf::Skin& skin, Ogre::v1::OldBone* rootBone, const std::string& name) +void skeletonImporter::loadBoneHierarchy(int boneIndex) { - const auto& node = model.nodes[skin.joints[0]]; - const auto& skeleton = model.nodes[skin.skeleton]; - - std::array translation { 0 }, scale { 0 }; - std::array rotation { 0 }; - internal_utils::container_double_to_float(skeleton.translation, translation); - if(skeleton.scale.size() == 3) internal_utils::container_double_to_float(skeleton.scale, scale); - internal_utils::container_double_to_float(skeleton.rotation, rotation); + const auto& node = model.nodes[boneIndex]; + Ogre::v1::OldBone* rootBone = skeleton->getBone(nodeToJointMap[boneIndex]); + + std::array translation = { 0, 0, 0 }; + std::array scale = { 1, 1, 1 }; + std::array rotation = { 0, 0, 0, 1 }; + if(!node.translation.empty()) + internal_utils::container_double_to_real(node.translation, translation); + if(!node.scale.empty()) + internal_utils::container_double_to_real(node.scale, scale); + if(!node.rotation.empty()) + internal_utils::container_double_to_real(node.rotation, rotation); Ogre::Vector3 trans = Ogre::Vector3 { translation.data() }; Ogre::Quaternion rot = Ogre::Quaternion { rotation[3], rotation[0], rotation[1], rotation[2] }; @@ -65,7 +74,7 @@ void skeletonImporter::loadBoneHierarchy(const tinygltf::Skin& skin, Ogre::v1::O rootBoneXformLog << "rootBone " << trans << " " << rot; OgreLog(rootBoneXformLog); - addChidren(name, node.children, rootBone, skin.joints); + addChidren(node.children, rootBone); } skeletonImporter::skeletonImporter(tinygltf::Model& input) : model { input } {} @@ -91,7 +100,7 @@ void skeletonImporter::loadTimepointFromSamplerToKeyFrame(int bone, int frameID, animationFrame.timePoint = data; else if(animationFrame.timePoint != data) { - throw FileIOError("Missmatch of timecode while loading an animation keyframe for bone joint " + std::to_string(bone) + throw FileIOError("Mismatch of timecode while loading an animation keyframe for bone joint " + std::to_string(bone) + "\n" "read from file : " + std::to_string(data) + " while animationFrame recorded " + std::to_string(animationFrame.timePoint)); @@ -107,16 +116,16 @@ void skeletonImporter::loadVector3FromSampler(int frameID, int& count, tinygltf: unsigned char* dataStart = buffer.data.data() + bufferView.byteOffset + output.byteOffset; const size_t byteStride = output.ByteStride(bufferView); - assert(output.type == TINYGLTF_TYPE_VEC3); //Need to be a 3D vectorsince it's a translation vector + assert(output.type == TINYGLTF_TYPE_VEC3); //Need to be a 3D vector since it's a translation vector if(output.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) { vector = Ogre::Vector3(reinterpret_cast(dataStart + frameID * byteStride)); } else if(output.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) //need double to float conversion { - std::array vectFloat {}; + std::array vectFloat {}; std::array vectDouble {}; memcpy(vectDouble.data(), reinterpret_cast(dataStart + frameID * byteStride), 3 * sizeof(double)); - internal_utils::container_double_to_float(vectDouble, vectFloat); + internal_utils::container_double_to_real(vectDouble, vectFloat); vector = Ogre::Vector3(vectFloat.data()); } @@ -131,7 +140,7 @@ void skeletonImporter::loadQuatFromSampler(int frameID, int& count, tinygltf::An unsigned char* dataStart = buffer.data.data() + bufferView.byteOffset + output.byteOffset; const size_t byteStride = output.ByteStride(bufferView); - assert(output.type == TINYGLTF_TYPE_VEC4); //Need to be a 4D vectorsince it's a translation vector + assert(output.type == TINYGLTF_TYPE_VEC4); //Need to be a 4D vector since it's a quaternion if(output.componentType == TINYGLTF_COMPONENT_TYPE_FLOAT) { @@ -140,11 +149,11 @@ void skeletonImporter::loadQuatFromSampler(int frameID, int& count, tinygltf::An } else if(output.componentType == TINYGLTF_COMPONENT_TYPE_DOUBLE) //need double to float conversion { - std::array vectFloat {}; + std::array vectFloat {}; std::array vectDouble {}; - memcpy(vectDouble.data(), reinterpret_cast(dataStart + frameID * byteStride), 3 * sizeof(double)); - internal_utils::container_double_to_float(vectDouble, vectFloat); + memcpy(vectDouble.data(), reinterpret_cast(dataStart + frameID * byteStride), 4 * sizeof(double)); + internal_utils::container_double_to_real(vectDouble, vectFloat); quat = Ogre::Quaternion(vectFloat[3], vectFloat[0], vectFloat[1], vectFloat[2]); } @@ -249,7 +258,7 @@ void skeletonImporter::loadSkeletonAnimations(const tinygltf::Skin skin, const s std::unordered_map boneIndexedKeyFrames; - const auto getAnimationLenght = [](const keyFrameList& l) { + const auto getAnimationLength = [](const keyFrameList& l) { if(l.empty()) return 0.0f; return l.back().timePoint; }; @@ -272,8 +281,8 @@ void skeletonImporter::loadSkeletonAnimations(const tinygltf::Skin skin, const s for(auto& channel : animation.channels) { const auto joint = nodeToJointMap[channel.target_node]; - const auto& boneRawAnnimationChannelIt = boneRawAnimationChannels.find(joint); - if(boneRawAnnimationChannelIt == boneRawAnimationChannels.end()) boneRawAnimationChannels[joint]; + const auto& boneRawAnimationChannelIt = boneRawAnimationChannels.find(joint); + if(boneRawAnimationChannelIt == boneRawAnimationChannels.end()) boneRawAnimationChannels[joint]; boneRawAnimationChannels[joint].push_back(channel); } @@ -296,7 +305,7 @@ void skeletonImporter::loadSkeletonAnimations(const tinygltf::Skin skin, const s //here, we have a list of all key frames for one bone boneIndexedKeyFrames[bone] = keyFrames; - maxLen = getAnimationLenght(keyFrames); + maxLen = getAnimationLength(keyFrames); } //Create animation @@ -345,15 +354,12 @@ std::vector traversal(const tinygltf::Model& m, int node) return o; } -Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(const std::string& name) +Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(size_t index) { - const auto& skins = model.skins; - assert(!skins.empty()); + assert(index < model.skins.size()); + const auto& skin = model.skins[index]; - //TODO, take the skin of a specific mesh... - const auto& firstSkin = skins.front(); - - const std::string skeletonName = name + (!firstSkin.name.empty() ? firstSkin.name : "unnamedSkeleton" + std::to_string(skeletonID++)); + const std::string skeletonName = (!skin.name.empty() ? skin.name : "unnamedSkeleton" + std::to_string(skeletonID++)); OgreLog("First skin name is " + skeletonName); //Get skeleton @@ -367,22 +373,22 @@ Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(const std::string& name) //Create new skeleton skeleton = Ogre::v1::OldSkeletonManager::getSingleton().create(skeletonName, Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true); - if(!skeleton) throw InitError("Coudn't create skeletion for skin" + skeletonName); + if(!skeleton) throw InitError("Couldn't create skeletion for skin" + skeletonName); - //OgreLog("skin.skeleton = " + std::to_string(firstSkin.skeleton)); - //OgreLog("first joint : " + std::to_string(firstSkin.joints.front())); + //OgreLog("skin.skeleton = " + std::to_string(skin.skeleton)); + //OgreLog("first joint : " + std::to_string(skin.joints.front())); { - const auto inverseBindMatricesID = firstSkin.inverseBindMatrices; + const auto inverseBindMatricesID = skin.inverseBindMatrices; const auto& inverseBindMatricesAccessor = model.accessors[inverseBindMatricesID]; const auto& bufferView = model.bufferViews[inverseBindMatricesAccessor.bufferView]; const auto byteStride = inverseBindMatricesAccessor.ByteStride(bufferView); const auto& buffer = model.buffers[bufferView.buffer]; const unsigned char* dataStart = buffer.data.data() + bufferView.byteOffset + inverseBindMatricesAccessor.byteOffset; - assert(inverseBindMatricesAccessor.count == firstSkin.joints.size()); + assert(inverseBindMatricesAccessor.count == skin.joints.size()); assert(inverseBindMatricesAccessor.type == TINYGLTF_TYPE_MAT4); - std::array floatMatrix {}; + std::array floatMatrix {}; for(int i = 0; i < inverseBindMatricesAccessor.count; ++i) { @@ -396,7 +402,7 @@ Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(const std::string& name) //Needs to do Double -> Float conversion std::array doubleMatrix {}; memcpy(doubleMatrix.data(), reinterpret_cast(dataStart + i * byteStride), 4 * 4 * sizeof(double)); - internal_utils::container_double_to_float(doubleMatrix, floatMatrix); + internal_utils::container_double_to_real(doubleMatrix, floatMatrix); } Ogre::Matrix4 inverseBindMatrixTransposed = Ogre::Matrix4(floatMatrix[0], @@ -421,14 +427,21 @@ Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(const std::string& name) } } - //Build the "node to joint map". In the vertex buffer, proprery "JOINT_0" refer to the joints that affect a particular vertex of the skined mesh. + std::vector rootBones; + std::vector allChildren; + for(const auto& nodeIndex : skin.joints) + { + const auto& node = model.nodes[nodeIndex]; + allChildren.insert(allChildren.end(), node.children.begin(), node.children.end()); + } + + //Build the "node to joint map". In the vertex buffer, property "JOINT_0" refer to the joints that affect a particular vertex of the skined mesh. //To refer to theses joints, it refer to the index of the node in the skin.joints array. //We need to be able to get the index for each of theses joints in the array easilly, so we are builind a dictionarry to be able to reverse-search them - for(int i = 0; i < firstSkin.joints.size(); ++i) + for(int i = 0; i < skin.joints.size(); ++i) { - //Get the index in the "node" array in the glTF's JSON - const auto jointNode = firstSkin.joints[i]; + const auto jointNode = skin.joints[i]; //Record in the dictionary the joint node-> index nodeToJointMap[jointNode] = i; @@ -438,11 +451,18 @@ Ogre::v1::SkeletonPtr skeletonImporter::getSkeleton(const std::string& name) //Create bone with index "i" auto bone = skeleton->createBone(!name.empty() ? name : skeletonName + std::to_string(i), i); + + if(std::find(allChildren.begin(), allChildren.end(), jointNode) == allChildren.end()) { + rootBones.push_back(jointNode); + } } - loadBoneHierarchy(firstSkin, skeleton->getBone(nodeToJointMap[firstSkin.skeleton]), skeletonName); + for(int boneIndex : rootBones) + { + loadBoneHierarchy(boneIndex); + } skeleton->setBindingPose(); - loadSkeletonAnimations(firstSkin, skeletonName); + loadSkeletonAnimations(skin, skeletonName); return skeleton; } diff --git a/src/private_headers/Ogre_glTF_internal_utils.hpp b/src/private_headers/Ogre_glTF_internal_utils.hpp index e714a16..a47ef6e 100644 --- a/src/private_headers/Ogre_glTF_internal_utils.hpp +++ b/src/private_headers/Ogre_glTF_internal_utils.hpp @@ -1,19 +1,20 @@ #pragma once #include +#include namespace Ogre_glTF { namespace internal_utils { template - void container_double_to_float(inputContainer& in, outputContainer& out) + void container_double_to_real(inputContainer& in, outputContainer& out) { std::transform(std::begin(in), std::end(in), std::begin(out), [](double n) { - return static_cast(n); + return static_cast(n); }); } } diff --git a/src/private_headers/Ogre_glTF_modelConverter.hpp b/src/private_headers/Ogre_glTF_modelConverter.hpp index f966f2f..2ab4b0e 100644 --- a/src/private_headers/Ogre_glTF_modelConverter.hpp +++ b/src/private_headers/Ogre_glTF_modelConverter.hpp @@ -1,5 +1,6 @@ #pragma once #include +#include "OgreMesh2.h" #include #include "Ogre_glTF.hpp" @@ -158,9 +159,10 @@ namespace Ogre_glTF /// \param input model we are converting into an Ogre model modelConverter(tinygltf::Model& input); - ///Return a mesh generated from the data inside the gltf model. Currently look for the mesh attached on the first node of the default scene - Ogre::MeshPtr getOgreMesh(); - + ///Returns the mesh with the given name in the glTF file. + Ogre::MeshPtr getOgreMesh(const Ogre::String& name); + Ogre::MeshPtr getOgreMesh(size_t meshIdx); + ///Print out debug information on the model structure // nodes contain transformation and scale information void debugDump() const; @@ -168,9 +170,6 @@ namespace Ogre_glTF ///Return true if the model defines skins. Skins are "vertex to bone" asignment for skeletal animation bool hasSkins() const; - /// Return the transforms. The item pointer will be a nullptr at this point - ModelInformation::ModelTransform getTransform(); - private: ///Get a pointer to the Ogre::VaoManager static Ogre::VaoManager* getVaoManager(); diff --git a/src/private_headers/Ogre_glTF_skeletonImporter.hpp b/src/private_headers/Ogre_glTF_skeletonImporter.hpp index f236122..6cc51e0 100644 --- a/src/private_headers/Ogre_glTF_skeletonImporter.hpp +++ b/src/private_headers/Ogre_glTF_skeletonImporter.hpp @@ -24,21 +24,23 @@ namespace Ogre_glTF /// \param skinName name of the skin /// \param childs array contaning the indices of the childrens /// \param parent a pointer to a bone that is part of the skeleton we are creating - void addChidren(const std::string& skinName, const std::vector& childs, Ogre::v1::OldBone* parent, const std::vector& joints); + void addChidren(const std::vector& childs, Ogre::v1::OldBone* parent); ///Get the "skeleton node" from the skin object, call add children on it /// \param skin tinigltf skin object we are loading /// \param rootBone a freshly created bone object from an Ogre::SkeletonPtr /// \param name Name of the skeleton we are loading - void loadBoneHierarchy(const tinygltf::Skin& skin, Ogre::v1::OldBone* rootBone, const std::string& name); + void loadBoneHierarchy(int boneIndex); ///Represent a keyframe as laded from tinygltf, but converted to Ogre objects struct keyFrame { - float timePoint{ -1 }; - float weights{}; - Ogre::Quaternion rotation{}; - Ogre::Vector3 position, scale{}; + float timePoint; + float weights; + Ogre::Quaternion rotation; + Ogre::Vector3 position, scale; + + keyFrame() : timePoint(-1), weights(0), position(0,0,0), scale(1,1,1) {} }; ///Vector of keyframes @@ -83,6 +85,6 @@ namespace Ogre_glTF skeletonImporter(tinygltf::Model& input); ///Return the constructed skeleton pointer - Ogre::v1::SkeletonPtr getSkeleton(const std::string& adapterName); + Ogre::v1::SkeletonPtr getSkeleton(size_t index); }; } \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp deleted file mode 100644 index 4d44445..0000000 --- a/test/main.cpp +++ /dev/null @@ -1,223 +0,0 @@ -#include -//To create workspace definitions and workspaces -#include -//To use the hlms -#include -#include -//To load Hlms -#include -//To use objects -#include -#include -#include -#include -//To play animations -#include -//To use smart pointers -#include - -//The library we are trying out in this program -#include - -#ifdef _DEBUG -const char GL_RENDER_PLUGIN[] = "RenderSystem_GL3Plus_d"; -#else -const char GL_RENDER_PLUGIN[] = "RenderSystem_GL3Plus"; -#endif - -#ifdef _WIN32 -#ifdef _DEBUG -const char D3D11_RENDER_PLUGIN[] = "RenderSystem_Direct3D11_d"; -#else -const char D3D11_RENDER_PLUGIN[] = "RenderSystem_Direct3D11"; -#endif -#endif - -#ifdef _WIN32 -#define NOMINMAX -#include -#define main() WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT) -#else -#define main() main(int argc, char* argv[]) -#endif - -void declareHlmsLibrary(Ogre::String dataFolder) -{ - //Make sure the string we got is a valid path - if(dataFolder.empty()) - dataFolder = "./"; - else if(dataFolder[dataFolder.size() - 1] != '/') - dataFolder += '/'; - - //For retrieval of the paths to the different folders needed - Ogre::String dataFolderPath; - Ogre::StringVector libraryFoldersPaths; - -#ifdef USE_UNLIT //We are loading materials based on physics - //Get the path to all the subdirectories used by HlmsUnlit - Ogre::HlmsUnlit::getDefaultPaths(dataFolderPath, libraryFoldersPaths); - - //Create the Ogre::Archive objects needed - Ogre::Archive* archiveUnlit = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); - Ogre::ArchiveVec archiveUnlitLibraryFolders; - for(const auto& libraryFolderPath : libraryFoldersPaths) - { - Ogre::Archive* archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); - archiveUnlitLibraryFolders.push_back(archiveLibrary); - } - - //Create and register the unlit Hlms - Ogre::HlmsUnlit* hlmsUnlit = OGRE_NEW Ogre::HlmsUnlit(archiveUnlit, &archiveUnlitLibraryFolders); - Ogre::Root::getSingleton().getHlmsManager()->registerHlms(hlmsUnlit); - hlmsUnlit->setDebugOutputPath(false, false); -#endif - - //Do the same for HlmsPbs: - Ogre::HlmsPbs::getDefaultPaths(dataFolderPath, libraryFoldersPaths); - Ogre::Archive* archivePbs = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + dataFolderPath, "FileSystem", true); - - //Get the library archive(s) - Ogre::ArchiveVec archivePbsLibraryFolders; - for(const auto& libraryFolderPath : libraryFoldersPaths) - { - Ogre::Archive* archiveLibrary = Ogre::ArchiveManager::getSingletonPtr()->load(dataFolder + libraryFolderPath, "FileSystem", true); - archivePbsLibraryFolders.push_back(archiveLibrary); - } - - //Create and register - Ogre::HlmsPbs* hlmsPbs = OGRE_NEW Ogre::HlmsPbs(archivePbs, &archivePbsLibraryFolders); - Ogre::Root::getSingleton().getHlmsManager()->registerHlms(hlmsPbs); - hlmsPbs->setDebugOutputPath(false, false); -} - -int main() -{ - //Init Ogre - auto root = std::make_unique(); - Ogre::LogManager::getSingleton().setLogDetail(Ogre::LoggingLevel::LL_BOREME); - - root->loadPlugin(GL_RENDER_PLUGIN); -#ifdef _WIN32 - root->loadPlugin(D3D11_RENDER_PLUGIN); -#endif - root->showConfigDialog(); - root->getRenderSystem()->setConfigOption("FSAA", "16"); - root->getRenderSystem()->setConfigOption("sRGB Gamma Conversion", "Yes"); - root->initialise(false); - - //Create a window and a scene - Ogre::NameValuePairList params; - params["FSAA"] = "16"; - const auto window = root->createRenderWindow("glTF test!", 800, 600, false, ¶ms); - - auto smgr = root->createSceneManager(Ogre::ST_GENERIC, 2, Ogre::INSTANCING_CULLING_THREADED); - smgr->showBoundingBoxes(true); - smgr->setDisplaySceneNodes(true); - auto camera = smgr->createCamera("cam"); - - //Setup rendering pipeline - auto compositor = root->getCompositorManager2(); - const char workspaceName[] = "workspace0"; - compositor->createBasicWorkspaceDef(workspaceName, Ogre::ColourValue { 0.2f, 0.3f, 0.4f }); - auto workspace = compositor->addWorkspace(smgr, window, camera, workspaceName, true); - - declareHlmsLibrary("./"); - - Ogre::ResourceGroupManager::getSingleton().addResourceLocation("gltfFiles.zip", "Zip"); - Ogre::ResourceGroupManager::getSingleton().initialiseAllResourceGroups(true); - - Ogre::Item* ObjectItem = nullptr; - Ogre::SceneNode* ObjectNode = nullptr; - - //Ogre::Item* OtherItem; - //Initialize the library - auto gltf = std::make_unique(); - ObjectNode = smgr->getRootSceneNode()->createChildSceneNode(); - - Ogre_glTF::loaderAdapter gizmoLoader; - try - { - //auto adapter = gltf->loadFromFileSystem("from_gltf_export_skinned_cylinder.glb"); - //auto adapter = gltf->loadGlbResource("CesiumMan.glb"); - - gizmoLoader = gltf->loadFromFileSystem("gizmo.glb"); - - //auto adapter = gltf->loadFromFileSystem("./Corset.glb"); - auto model = gltf->getModelData("./damagedHelmet/damagedHelmet.gltf", Ogre_glTF::glTFLoaderInterface::LoadFrom::FileSystem); - ObjectItem = model.makeItem(smgr); - model.transform.apply(ObjectNode); - //OtherItem = adapter.getItem(smgr); - } - catch(std::exception& e) - { - Ogre::LogManager::getSingleton().logMessage(e.what()); - return -1; - } - - ObjectNode->attachObject(ObjectItem); - - auto gizmoNode = ObjectNode->createChildSceneNode(); - gizmoNode->attachObject(gizmoLoader.getItem(smgr)); - - gizmoNode->getAttachedObject(0); - //auto gizmoItem = dynamic_cast(gizmoNode->getAttachedObject(0)); - - gizmoNode->setScale(1, 1, 1); - //ObjectNode->setOrientation(Ogre::Quaternion(Ogre::Degree(-90), Ogre::Vector3::UNIT_X)); - camera->setNearClipDistance(0.001f); - camera->setFarClipDistance(100); - camera->setPosition(2.5f, 0, 2.5f); - camera->lookAt({ 0, 1, 0 }); - camera->setAutoAspectRatio(true); - - auto light = smgr->createLight(); - smgr->getRootSceneNode()->createChildSceneNode()->attachObject(light); - light->setType(Ogre::Light::LT_DIRECTIONAL); - light->setDirection(Ogre::Vector3 { -1, -1, -0.5f }); - light->setPowerScale(5); - - light = smgr->createLight(); - smgr->getRootSceneNode()->createChildSceneNode()->attachObject(light); - light->setType(Ogre::Light::LT_DIRECTIONAL); - light->setDirection(Ogre::Vector3 { +1, +1, +0.5f }); - light->setPowerScale(5); - - auto skeleton = ObjectItem->getSkeletonInstance(); - - Ogre::SkeletonAnimation* anim = nullptr; - Ogre::Bone* bone = nullptr; - - auto plugins = root->getInstalledPlugins(); - - - if(skeleton) - { - bone = skeleton->getBone(1); - auto& animationList = skeleton->getAnimations(); - if(!animationList.empty()) - { - const auto name = animationList[0].getName(); - anim = skeleton->getAnimation(name); - } - - if(anim) - { - anim->setEnabled(true); - anim->setLoop(true); - } - } - - auto last = root->getTimer()->getMilliseconds(); - auto now = last; - while(!window->isClosed()) - { - now = root->getTimer()->getMilliseconds(); - if(anim) anim->addTime(float(now - last) / 1000.0f); - last = now; - - root->renderOneFrame(); - Ogre::WindowEventUtilities::messagePump(); - } - - return 0; -}