diff --git a/.gitmodules b/.gitmodules index 933a71f8..206ea0a3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,3 +46,6 @@ [submodule "vendor/vulkan/Vulkan-Utility-Libraries"] path = vendor/vulkan/Vulkan-Utility-Libraries url = https://github.com/KhronosGroup/Vulkan-Utility-Libraries.git +[submodule "vendor/assimp"] + path = vendor/assimp + url = https://github.com/assimp/assimp.git diff --git a/Makefile b/Makefile index a9716893..4d3b50d5 100644 --- a/Makefile +++ b/Makefile @@ -121,6 +121,15 @@ clean: $(RM) $(call platformpth,$(outputDir)) $(RM) $(call platformpth,$(buildFlagsFile)) +clean-deps: + git submodule foreach --recursive git clean -xfd + git submodule foreach --recursive git reset --hard + $(RM) $(call platformpth,$(vendorDir)/include) + $(RM) $(call platformpth,$(vendorDir)/vulkan/include) + $(RM) $(call platformpth,$(vendorDir)/vulkan/lib) + +clean-all: clean clean-deps + # Check file formatting program across all source files format-check: $(formatScript) "$(engineDir) $(examplesDir) $(testsDir) $(packerDir)" --check diff --git a/README.md b/README.md index 997bef57..f7730e99 100644 --- a/README.md +++ b/README.md @@ -158,12 +158,14 @@ You can see examples of this in any of the application targets under `examples`. ├─[engine] │ ├─[core] <- the engine's core library │ ├─[render] <- the engine's renderer + | ├─[resources] <- the engine's resource types and loading system │ ├─[window] <- the engine's windowing and input library │ ├─[utils] <- the engine's utils library │ ├─[examples] │ ├─[game] <- an example app utilising all of the engine's libraries - │ ├─[render] <- an example app demonstrating the renderer + │ ├─[render] <- an example app demonstrating the renderer for 3D + | ├─[tilemap] <- an example app demonstrating the renderer for a tilemap │ ├─[make] <- additional Make file utilities for the build system ├─[packer] <- an asset packing app for bundling game assets in a pack file on build diff --git a/engine/core/Makefile b/engine/core/Makefile index a84b0207..16624d81 100644 --- a/engine/core/Makefile +++ b/engine/core/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -coreSrcDir := . +coreSrcDir := ./ coreBinDir := $(binDir)/engine/core coreSources := $(call rwildcard,$(coreSrcDir)/,*.cpp) coreObjects := $(call findobjs,$(coreSrcDir),$(coreBinDir),$(coreSources)) diff --git a/engine/core/entity/Entity.cpp b/engine/core/entity/Entity.cpp index 2496e979..33b35a54 100644 --- a/engine/core/entity/Entity.cpp +++ b/engine/core/entity/Entity.cpp @@ -16,12 +16,9 @@ namespace Siege { -// Static member initialisation -const String Entity::ENTITY_NAME("Entity"); - -Entity::Entity(const String& name, const Xform& transform, int zIndex) : +Entity::Entity(Token type, const Xform& transform, int zIndex) : transform(transform), - name(name), + type(type), index(GenerationalIndex()), zIndex(zIndex) {} @@ -42,9 +39,9 @@ void Entity::QueueFree() EntitySystem::QueueFree(this); } -const String& Entity::GetName() const +Token Entity::GetType() const { - return name; + return type; } const GenerationalIndex& Entity::GetIndex() const diff --git a/engine/core/entity/Entity.h b/engine/core/entity/Entity.h index e441847b..32ca3ba8 100644 --- a/engine/core/entity/Entity.h +++ b/engine/core/entity/Entity.h @@ -11,12 +11,15 @@ #define SIEGE_ENGINE_ENTITY_H #include +#include #include #include #include "EntityPtr.h" #include "IndexAllocator.h" +REGISTER_TOKEN(Entity); + namespace Siege { /** @@ -26,36 +29,30 @@ class Entity { public: - // Public constants - - static const String ENTITY_NAME; - // 'Structors /** * Zero-param constructor for Entity, initialises both - * position and rotation to zero, and name to "Entity" + * position and rotation to zero, and type to Entity */ - Entity() : Entity(ENTITY_NAME) {}; + Entity() : Entity(TOKEN_Entity) {}; /** * Single-param constructor for Entity that simply defines * a custom name for the Entity - * @param name - a const reference to the name of the - * entity as a string + * @param type - a token for the entity to use as its type */ - Entity(const String& name) : Entity(name, {Vec3::Zero(), 0.f}) {}; + Entity(Token type) : Entity(type, {Vec3::Zero(), 0.f}) {}; /** * Delegate constructor for Entity, initialises * generational index to zero - * @param name - a const reference to the name of the - * entity as a string + * @param type - a token for the entity to use as its type * @param transform - the initial transition of the entity * @param zIndex - the initial z-index of the entity, * defaults to zero */ - Entity(const String& name, const Xform& transform, int zIndex = 0); + Entity(Token type, const Xform& transform, int zIndex = 0); /** * Default virtual destructor for Entity @@ -121,11 +118,10 @@ class Entity // Public getters /** - * Getter method for the entity's vanity name - * @return a constant reference to the entity's name - * as a string + * Getter method for the entity's type + * @return a token for the entity's type */ - const String& GetName() const; + Token GetType() const; /** * Getter method for the entity's generational index @@ -234,9 +230,9 @@ class Entity // Private fields /** - * The name of the entity type + * The type of the entity type */ - const String& name; + Token type; /** * The generational index of the entity diff --git a/engine/core/entity/EntitySystem.cpp b/engine/core/entity/EntitySystem.cpp index a4d7a91a..1ad4d292 100644 --- a/engine/core/entity/EntitySystem.cpp +++ b/engine/core/entity/EntitySystem.cpp @@ -72,13 +72,13 @@ void EntitySystem::QueueFree(Entity* entity) EntitySystem* system = FindInGlobalRegister(entity); if (system) { - CC_LOG_INFO("Freeing {} at ({})", entity->GetName(), entity->GetIndex().ToString()); + CC_LOG_INFO("Freeing {} at ({})", entity->GetType(), entity->GetIndex().ToString()); system->AddToFreeQueue(entity); } else { CC_LOG_WARNING("Could not find storage for {} at {}", - entity->GetName(), + entity->GetType(), entity->GetIndex().ToString()); } } @@ -90,7 +90,7 @@ void EntitySystem::Resort(Entity* entity, int oldZIdx) else { CC_LOG_WARNING("Could not find storage for {} at {}", - entity->GetName(), + entity->GetType(), entity->GetIndex().ToString()); } } @@ -141,7 +141,7 @@ void EntitySystem::RegisterEntities() // If the entity's given index already exists then override the existing entry if (entity->GetIndex().index < entities.size()) entities[entity->GetIndex().index] = entity; else entities.push_back(entity); - CC_LOG_INFO("Registered {} at ({})", entity->GetName(), entity->GetIndex().ToString()); + CC_LOG_INFO("Registered {} at ({})", entity->GetType(), entity->GetIndex().ToString()); packedEntities.push_back(entity); AddToGlobalRegister(entity, this); diff --git a/engine/core/scene/SceneFile.cpp b/engine/core/scene/SceneFile.cpp index 18cc2a68..e9c016e3 100644 --- a/engine/core/scene/SceneFile.cpp +++ b/engine/core/scene/SceneFile.cpp @@ -12,21 +12,24 @@ #include #include #include -#include #include #include #include "SceneSystem.h" -#include "resources/GenericFileData.h" + +REGISTER_TOKEN(TYPE); +REGISTER_TOKEN(ROTATION); +REGISTER_TOKEN(Z_INDEX); +REGISTER_TOKEN(POSITION); namespace Siege { -void SceneFile::RegisterSerialisable(const String& name, +void SceneFile::RegisterSerialisable(Token type, const Serialiser& serialise, const Deserialiser& deserialise) { - GetSerialisables().emplace(name, std::make_pair(serialise, deserialise)); + GetSerialisables().emplace(type, std::make_pair(serialise, deserialise)); } bool SceneFile::Serialise(const std::vector& entities) @@ -65,14 +68,14 @@ bool SceneFile::SerialiseToString(Entity* entity, String& fileData) auto& serialisables = GetSerialisables(); // Only serialise entities that register a serialisable interface - auto it = serialisables.find(entity->GetName()); + auto it = serialisables.find(entity->GetType()); if (it == serialisables.end()) return false; // Serialise the general entity information - fileData += (entity->GetName() + LINE_SEP); - fileData += DefineField("POSITION", ToString(entity->GetPosition())); - fileData += DefineField("ROTATION", String::FromFloat(entity->GetRotation().y)); - fileData += DefineField("Z-INDEX", String::FromInt(entity->GetZIndex())); + fileData += DefineField(TOKEN_TYPE, entity->GetType().GetId()); + fileData += DefineField(TOKEN_POSITION, ToString(entity->GetPosition())); + fileData += DefineField(TOKEN_ROTATION, String::FromFloat(entity->GetRotation().y)); + fileData += DefineField(TOKEN_Z_INDEX, String::FromInt(entity->GetZIndex())); // Apply its serialiser if it Serialiser serialiser = it->second.first; @@ -141,34 +144,25 @@ bool SceneFile::Deserialise(std::vector& entities) Entity* SceneFile::DeserialiseFromString(const String& fileData) { - if (fileData.IsEmpty()) - { - CC_LOG_WARNING("Found empty entity during deserialisation"); - return nullptr; - } - - // Split the file into arguments and strip the labels from each item - std::vector args = fileData.Split(LINE_SEP); - for (String& arg : args) arg = arg.SubString((int) arg.Find(NAME_SEP) + 1); + std::map attributes = Siege::FileSystem::ParseAttributeFileData(fileData); - // Get the standard entity fields - EntityData data; - if (!(args.size() >= 4 && args[ENTITY_ROT].GetFloat(data.rotation) && - args[ENTITY_Z_IDX].GetInt(data.zIndex) && FromString(data.position, args[ENTITY_POS]))) + if (attributes.empty()) { - CC_LOG_WARNING("Failed to deserialise fields for entity \"{}\"", args[ENTITY_NAME]); + CC_LOG_WARNING("Found empty entity during deserialisation!"); + return nullptr; } // Check if the entity has a relevant serialisable interface registered auto& serialisables = GetSerialisables(); - auto it = serialisables.find(args[ENTITY_NAME]); + Token typeToken(attributes[TOKEN_TYPE]); + auto it = serialisables.find(typeToken); if (it != serialisables.end()) { // Apply its deserialiser Deserialiser deserialiser = it->second.second; - if (deserialiser) return deserialiser(data, args); + if (deserialiser) return deserialiser(attributes); } - else CC_LOG_WARNING("\"{}\" has no deserialisation protocols defined", args[ENTITY_NAME]); + else CC_LOG_WARNING("\"{}\" has no deserialisation protocols defined", attributes[TOKEN_TYPE]); return nullptr; } @@ -190,6 +184,29 @@ void SceneFile::InitialiseEntityPathMappings() } } +EntityData SceneFile::GetBaseEntityData(const std::map& attributes) +{ + EntityData data; + auto it = attributes.find(TOKEN_ROTATION); + if (it == attributes.end() || !it->second.GetFloat(data.rotation)) + { + CC_LOG_WARNING("Failed to deserialise ROTATION field for entity attributes"); + } + + it = attributes.find(TOKEN_Z_INDEX); + if (it == attributes.end() || !it->second.GetInt(data.zIndex)) + { + CC_LOG_WARNING("Failed to deserialise Z_INDEX field for entity attributes"); + } + + it = attributes.find(TOKEN_POSITION); + if (it == attributes.end() || !FromString(data.position, it->second)) + { + CC_LOG_WARNING("Failed to deserialise POSITION field for entity attributes"); + } + return data; +} + String SceneFile::GetOrCreateEntityFilepath(Entity* entity) { // Try to find the entity path amongst the deserialised @@ -212,7 +229,8 @@ String SceneFile::GetOrCreateEntityFilepath(Entity* entity) // Failed attempts to find a file index are serialised as 0 String index = result ? String::FromInt(newFileIndex) : "0"; - return MakeScenePath(sceneName) + '/' + entity->GetName() + '.' + index + ENTITY_FILE_EXT; + return MakeScenePath(sceneName) + '/' + entity->GetType().GetId() + '.' + index + + ENTITY_FILE_EXT; } String SceneFile::MakeScenePath(const String& sceneName) diff --git a/engine/core/scene/SceneFile.h b/engine/core/scene/SceneFile.h index 1d18df93..be0f2a12 100644 --- a/engine/core/scene/SceneFile.h +++ b/engine/core/scene/SceneFile.h @@ -10,6 +10,7 @@ #ifndef SIEGE_ENGINE_SCENEFILE_H #define SIEGE_ENGINE_SCENEFILE_H +#include #include #include #include @@ -29,31 +30,15 @@ namespace Siege { // Define constants -static constexpr const char LINE_SEP = ';'; -static constexpr const char NAME_SEP = ':'; static constexpr const char* SCENE_FILE_EXT = ".scene"; static constexpr const char* ENTITY_FILE_EXT = ".entity"; // Define types typedef struct EntityData EntityData; typedef const std::function Serialiser; -typedef const std::function&)> Deserialiser; +typedef const std::function&)> Deserialiser; typedef std::pair SerialisationInterface; -/** - * An enum for common serialisation field names - */ -enum SerialisationFields -{ - ENTITY_NAME = 0, - ENTITY_POS = 1, - ENTITY_ROT = 2, - ENTITY_Z_IDX = 3, - CUSTOM_FIELD_1 = 4, - CUSTOM_FIELD_2 = 5, - CUSTOM_FIELD_3 = 6, -}; - class SceneFile { public: @@ -75,11 +60,11 @@ class SceneFile /** * Registers a serialisation interface for an entity - * @param name - the name of the serialisable entity + * @param type - the type token of the serialisable entity * @param serialise - the serialise function for the entity * @param deserialise - the deserialise function for the entity */ - static void RegisterSerialisable(const String& name, + static void RegisterSerialisable(Token type, const Serialiser& serialise, const Deserialiser& deserialise); @@ -136,6 +121,8 @@ class SceneFile */ void InitialiseEntityPathMappings(); + static EntityData GetBaseEntityData(const std::map& attributes); + private: // Private methods @@ -159,11 +146,11 @@ class SceneFile /** * Getter & storage for mapped serialisation interfaces - * @return a map of string to serialisation interfaces + * @return a map of token to serialisation interfaces */ - static std::map& GetSerialisables() + static std::map& GetSerialisables() { - static std::map serialisables; + static std::map serialisables; return serialisables; } @@ -216,15 +203,15 @@ struct SerialisationInterfaceRegisterer * that registers provided serialisation interfaces at * initialisation time * @note This is supposedly 1B in size per-instantiation - * @param name - the name of the serialisable entity + * @param type - the type token of the serialisable entity * @param serialise - the serialise function for the entity * @param deserialise - the deserialise function for the entity */ - SerialisationInterfaceRegisterer(const String& name, + SerialisationInterfaceRegisterer(Token type, const Serialiser& serialise, const Deserialiser& deserialise) { - SceneFile::RegisterSerialisable(name, serialise, deserialise); + SceneFile::RegisterSerialisable(type, serialise, deserialise); } }; @@ -233,13 +220,13 @@ struct SerialisationInterfaceRegisterer /** * An inlined helper function to define the structure of the * property field in a .scene file - * @param name - the name of the property field + * @param name - the token name of the property field * @param content - the content of the property * @return the field content as a const string */ -inline String DefineField(const String& name, const String& content) +inline String DefineField(Token name, const String& content) { - return name + NAME_SEP + content + LINE_SEP; + return String(name.GetId()) + ATTR_FILE_VALUE_SEP + content + ATTR_FILE_LINE_SEP; } } // namespace Siege diff --git a/engine/render/Makefile b/engine/render/Makefile index 1ab51462..b628f597 100644 --- a/engine/render/Makefile +++ b/engine/render/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -renderSrcDir := . +renderSrcDir := ./ renderBinDir := $(binDir)/engine/render renderSources := $(call rwildcard,$(renderSrcDir)/,*.cpp) renderObjects := $(call findobjs,$(renderSrcDir),$(renderBinDir),$(renderSources)) diff --git a/engine/render/renderer/platform/vulkan/LogicalDevice.cpp b/engine/render/renderer/platform/vulkan/LogicalDevice.cpp index 6b5e8a1f..30c3c354 100644 --- a/engine/render/renderer/platform/vulkan/LogicalDevice.cpp +++ b/engine/render/renderer/platform/vulkan/LogicalDevice.cpp @@ -81,7 +81,6 @@ LogicalDevice::LogicalDevice(const Surface& surface, PhysicalDevice& physDevice) GET_UNIQUE_QUEUES(queueCreateInfos, graphicsIdx, presentIdx) auto deviceExtensions = Vulkan::Config::deviceExtensions; - auto layers = Vulkan::Config::validationLayers; CREATE_LOGICAL_DEVICE( vkPhysicalDevice, diff --git a/engine/resources/GenericFileData.h b/engine/resources/GenericFileData.h index 8bf6146e..ecf5d010 100644 --- a/engine/resources/GenericFileData.h +++ b/engine/resources/GenericFileData.h @@ -41,6 +41,7 @@ struct GenericFileData static uint32_t GetDataSize(void* objectData) { + if (!objectData) return 0; GenericFileData* fileData = reinterpret_cast(objectData); return sizeof(GenericFileData) + fileData->dataSize; } diff --git a/engine/resources/Makefile b/engine/resources/Makefile index c8f77cfa..9b279834 100644 --- a/engine/resources/Makefile +++ b/engine/resources/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set build vars -resourcesSrcDir := . +resourcesSrcDir := ./ resourcesBinDir := $(binDir)/engine/resources resourcesSources := $(call rwildcard,$(resourcesSrcDir)/,*.cpp) resourcesObjects := $(call findobjs,$(resourcesSrcDir),$(resourcesBinDir),$(resourcesSources)) diff --git a/engine/resources/PackFile.cpp b/engine/resources/PackFile.cpp index 8e62f111..4aa91d46 100644 --- a/engine/resources/PackFile.cpp +++ b/engine/resources/PackFile.cpp @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: diff --git a/engine/resources/PackFile.h b/engine/resources/PackFile.h index 5eecd749..0b96397b 100644 --- a/engine/resources/PackFile.h +++ b/engine/resources/PackFile.h @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: diff --git a/engine/resources/SceneData.h b/engine/resources/SceneData.h index 6bad1f7e..be317f3f 100644 --- a/engine/resources/SceneData.h +++ b/engine/resources/SceneData.h @@ -41,6 +41,7 @@ struct SceneData static uint32_t GetDataSize(void* objectData) { + if (!objectData) return 0; SceneData* sceneData = reinterpret_cast(objectData); return sizeof(SceneData) + sceneData->dataSize; } diff --git a/engine/resources/StaticMeshData.h b/engine/resources/StaticMeshData.h index 59cc4a01..f0180a75 100644 --- a/engine/resources/StaticMeshData.h +++ b/engine/resources/StaticMeshData.h @@ -76,6 +76,7 @@ struct StaticMeshData static uint32_t GetDataSize(void* objectData) { + if (!objectData) return 0; StaticMeshData* staticMeshData = reinterpret_cast(objectData); return sizeof(StaticMeshData) + sizeof(uint32_t) * staticMeshData->indicesCount + sizeof(BaseVertex) * staticMeshData->verticesCount; diff --git a/engine/resources/Texture2DData.h b/engine/resources/Texture2DData.h index 67050e96..8a7e38e6 100644 --- a/engine/resources/Texture2DData.h +++ b/engine/resources/Texture2DData.h @@ -60,6 +60,7 @@ struct Texture2DData static uint32_t GetDataSize(void* objectData) { + if (!objectData) return 0; Texture2DData* textureData = reinterpret_cast(objectData); return sizeof(Texture2DData) + sizeof(uint8_t) * textureData->GetImageSize(); } diff --git a/engine/utils/FileSystem.cpp b/engine/utils/FileSystem.cpp index 8a77ed3c..e1318d20 100644 --- a/engine/utils/FileSystem.cpp +++ b/engine/utils/FileSystem.cpp @@ -9,28 +9,30 @@ #include "FileSystem.h" +#include #include #include +#include "Defer.h" +#include "Logging.h" + namespace Siege::FileSystem { String Read(const String& filename) { - // Try open the file for reading FILE* file = fopen(filename, "rb"); if (!file) return ""; - // Determine file size fseek(file, 0, SEEK_END); size_t size = ftell(file); rewind(file); - // Copy the content - char content[size + 1]; + char* content = static_cast(malloc(size + 1)); + defer([&content] { free(content); }); + fread(content, sizeof(char), size, file); content[size] = '\0'; - // Close the file stream and return fclose(file); return content; } @@ -72,4 +74,43 @@ bool ForEachFileInDir(const String& path, } return true; } + +String StripNewLines(const String& string) +{ + std::string str(string); + str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend()); + str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend()); + return str.c_str(); +} + +std::map ParseAttributeFileData(const String& fileData) +{ + // Expunge any newlines characters from the file data + String sanitisedFileData = StripNewLines(fileData); + + // Split the file line contents into attributes + std::map attributes; + for (const String& line : sanitisedFileData.Split(ATTR_FILE_LINE_SEP)) + { + std::vector attribute = line.Split(ATTR_FILE_VALUE_SEP); + if (attribute.size() != 2) + { + CC_LOG_WARNING("Received wrong number of attribute value seperations for line \"{}\", " + "will not register!", + line) + continue; + } + + Token attributeToken = Token::FindToken(attribute[0]); + if (!attributeToken) + { + CC_LOG_WARNING("Failed to find token for attribute \"{}\", will not register!", + attribute[0]) + continue; + } + attributes[attributeToken] = attribute[1]; + } + + return attributes; +} } // namespace Siege::FileSystem \ No newline at end of file diff --git a/engine/utils/FileSystem.h b/engine/utils/FileSystem.h index 4b17b151..20ec364d 100644 --- a/engine/utils/FileSystem.h +++ b/engine/utils/FileSystem.h @@ -11,8 +11,14 @@ #define SIEGE_ENGINE_FILESYSTEM_H #include +#include #include "String.h" +#include "Token.h" + +// Define constants +static constexpr const char ATTR_FILE_LINE_SEP = ';'; +static constexpr const char ATTR_FILE_VALUE_SEP = ':'; namespace Siege::FileSystem { @@ -30,6 +36,10 @@ bool CreateDirectoryRecursive(const String& dirpath); bool ForEachFileInDir(const String& path, const std::function& func); +String StripNewLines(const String& string); + +std::map ParseAttributeFileData(const String& fileData); + } // namespace Siege::FileSystem #endif // SIEGE_ENGINE_FILESYSTEM_H diff --git a/engine/utils/Logging.h b/engine/utils/Logging.h index 0712bb15..0b92747d 100644 --- a/engine/utils/Logging.h +++ b/engine/utils/Logging.h @@ -17,6 +17,7 @@ #include "Macros.h" #include "String.h" +#include "Token.h" #include "math/Maths.h" #include "math/mat/Format.h" #include "math/mat/Mat2.h" @@ -97,6 +98,7 @@ class VariantContainer DEFINE_VARIANT_TYPE(unsigned long data, String::FromU32(data)); DEFINE_VARIANT_TYPE(unsigned long long data, String::FromU64(data)); DEFINE_VARIANT_TYPE(bool data, data ? "true" : "false"); + DEFINE_VARIANT_TYPE(Token data, data.GetId()); DEFINE_VARIANT_TYPE(const Vec2& data, "Vector2(" + ToString(data) + ")"); DEFINE_VARIANT_TYPE(const Vec3& data, "Vector3(" + ToString(data) + ")"); DEFINE_VARIANT_TYPE(const Vec4& data, "Vector4(" + ToString(data) + ")"); diff --git a/engine/utils/Makefile b/engine/utils/Makefile index 98f4996d..affdfb34 100644 --- a/engine/utils/Makefile +++ b/engine/utils/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set build vars -utilsSrcDir := . +utilsSrcDir := ./ utilsBinDir := $(binDir)/engine/utils utilsSources := $(call rwildcard,$(utilsSrcDir)/,*.cpp) utilsObjects := $(call findobjs,$(utilsSrcDir),$(utilsBinDir),$(utilsSources)) diff --git a/engine/utils/String.cpp b/engine/utils/String.cpp index b7fa5203..174a4bd9 100644 --- a/engine/utils/String.cpp +++ b/engine/utils/String.cpp @@ -9,6 +9,7 @@ #include "String.h" +#include #include #include #include @@ -121,10 +122,9 @@ String::String(const char* string) : memory() String::String(const wchar_t* string) : memory() { size_t size = std::wcslen(string) + 1; - char convertedStr[size]; - memset(convertedStr, 0, size + 1); + char* convertedStr = static_cast(alloca(size)); std::wcstombs(convertedStr, string, size); - convertedStr[size] = '\0'; + convertedStr[size - 1] = '\0'; Assign(convertedStr); } @@ -186,7 +186,7 @@ bool String::operator<(const String& rhs) const String String::operator+(const String& rhs) const { - return *this + (const char*) rhs.Data(); + return *this + rhs.Data(); } String String::operator+(const char* rhs) const @@ -195,7 +195,7 @@ String String::operator+(const char* rhs) const size_t lhsLength = Size(); size_t rhsLength = strlen(rhs); - char cstr[lhsLength + rhsLength + 1]; + char* cstr = static_cast(alloca(lhsLength + rhsLength + 1)); strcpy(cstr, data); strcpy(cstr + lhsLength, rhs); @@ -207,7 +207,7 @@ String String::operator+(char rhs) const const char* data = Data(); size_t lhsLength = Size(); - char cstr[lhsLength + 1 + 1]; + char* cstr = static_cast(alloca(lhsLength + 1 + 1)); strcpy(cstr, data); cstr[lhsLength] = rhs; cstr[lhsLength + 1] = '\0'; @@ -230,10 +230,9 @@ String& String::operator+=(const char* rhs) String& String::operator+=(const wchar_t* rhs) { size_t size = std::wcslen(rhs) + 1; - char convertedStr[size]; - memset(convertedStr, 0, size + 1); + char* convertedStr = static_cast(alloca(size)); std::wcstombs(convertedStr, rhs, size); - convertedStr[size] = '\0'; + convertedStr[size - 1] = '\0'; Append(convertedStr); return *this; @@ -261,6 +260,21 @@ String::operator const char*() const return Data(); } +bool String::GetBool(bool& value) const +{ + if (*this == ("0") || *this == ("false")) + { + value = false; + return true; + } + if (*this == ("1") || *this == ("true")) + { + value = true; + return true; + } + return false; +} + bool String::GetInt(int& value) const { try @@ -289,6 +303,11 @@ bool String::GetFloat(float& value) const return false; } +String String::FromBool(bool value) +{ + return value ? "true" : "false"; +} + String String::FromInt(int value) { return GetFromFormat("%d", value); @@ -378,6 +397,18 @@ size_t String::Find(char character, int startIdx) const return pos != nullptr ? pos - sstr + startIdx : -1; } +bool String::BeginsWith(const String& substring) const +{ + return BeginsWith(substring.Data()); +} + +bool String::BeginsWith(const char* substring) const +{ + const char* data = Data(); + size_t strLen = strlen(substring); + return strncmp(data, substring, strLen) == 0; +} + std::vector String::Split(const char* delimiters) const { const char* data = Data(); @@ -385,7 +416,7 @@ std::vector String::Split(const char* delimiters) const if (len == 0) return {}; // Copy over the internal string - char string[len + 1]; + char* string = static_cast(alloca(len + 1)); strcpy(string, data); // Iterate over the string while there is still a delimiter @@ -415,7 +446,7 @@ String String::SubString(int startPos, size_t length) const if (startPos >= len || (startPos + length) > len) return {}; // Copy over the substring and return it - char subString[length + 1]; + char* subString = static_cast(alloca(length + 1)); strncpy(subString, data + startPos, length); subString[length] = '\0'; // Manually add the null-termination char return subString; @@ -456,7 +487,7 @@ bool String::Shrink() char* data = Data(); if (len <= MAX_STACK_CAPACITY) { - char newStr[len + 1]; + char* newStr = static_cast(alloca(len + 1)); strcpy(newStr, data); free(str); strcpy(buffer, newStr); @@ -498,7 +529,7 @@ void String::Append(const char* string) size_t rhsLength = strlen(string); size_t fullLength = lhsLength + rhsLength; - char cstr[fullLength + 1]; + char* cstr = static_cast(alloca(fullLength + 1)); strcpy(cstr, data); strcpy(cstr + lhsLength, string); @@ -510,7 +541,7 @@ void String::Append(char character) const char* data = Data(); size_t lhsLength = Size(); - char cstr[lhsLength + 2]; + char* cstr = static_cast(alloca(lhsLength + 2)); strcpy(cstr, data); cstr[lhsLength] = character; cstr[lhsLength + 1] = '\0'; @@ -526,7 +557,7 @@ void String::Prepend(const String& string) size_t rhsLength = Size(); size_t fullLength = lhsLength + rhsLength; - char cstr[fullLength + 1]; + char* cstr = static_cast(alloca(fullLength + 1)); strcpy(cstr, string.Data()); strcpy(cstr + lhsLength, data); @@ -540,7 +571,7 @@ void String::Prepend(const char* string) size_t rhsLength = Size(); size_t fullLength = lhsLength + rhsLength; - char cstr[fullLength + 1]; + char* cstr = static_cast(alloca(fullLength + 1)); strcpy(cstr, string); strcpy(cstr + lhsLength, data); @@ -558,6 +589,13 @@ char String::PopBack() return character; } +void String::Reverse() +{ + char* data = Data(); + size_t len = Size(); + std::reverse(data, data + len); +} + void String::Erase(int startPos, size_t length) { // Perform boundary checking and set defaults @@ -574,7 +612,7 @@ void String::Erase(int startPos, size_t length) } // Copy over the non-erased portions and assign it - char newStr[newLen]; + char* newStr = static_cast(alloca(newLen)); strncpy(newStr, data, startPos); strcpy(newStr + startPos, data + startPos + length); Assign(newStr); @@ -598,7 +636,7 @@ void String::Insert(int pos, const char* string) size_t insLength = strlen(string); // Copy over the non-erased portions and assign it - char newStr[len + insLength]; + char* newStr = static_cast(alloca(len + insLength)); strncpy(newStr, data, pos); strncpy(newStr + pos, string, insLength); strcpy(newStr + pos + insLength, data + pos); @@ -620,7 +658,7 @@ bool String::Replace(const char* toReplace, const char* replacement) size_t replaceLen = strlen(replacement); size_t finalLen = (currentLen - toReplaceLen) + replaceLen; - char newStr[finalLen + 1]; + char* newStr = static_cast(alloca(finalLen + 1)); strncpy(newStr, data, pos); strncpy(newStr + pos, replacement, replaceLen); strcpy(newStr + pos + replaceLen, data + pos + toReplaceLen); @@ -676,18 +714,30 @@ String operator+(const char* lhs, const String& rhs) size_t lhsLength = strlen(lhs); size_t rhsLength = rhs.Size(); - char cstr[lhsLength + rhsLength + 1]; + char* cstr = static_cast(alloca(lhsLength + rhsLength + 1)); strcpy(cstr, lhs); strcpy(cstr + lhsLength, rhs.Str()); return {cstr}; } +String operator+(const wchar_t* lhs, const String& rhs) +{ + size_t lhsLength = std::wcslen(lhs); + size_t rhsLength = rhs.Size(); + + char* cstr = static_cast(alloca(lhsLength + rhsLength + 1)); + std::wcstombs(cstr, lhs, lhsLength); + strcpy(cstr + lhsLength, rhs.Str()); + + return {cstr}; +} + String operator+(char lhs, const String& rhs) { size_t rhsLength = rhs.Size(); - char cstr[1 + rhsLength + 1]; + char* cstr = static_cast(alloca(1 + rhsLength + 1)); cstr[0] = lhs; strcpy(cstr + 1, rhs.Str()); diff --git a/engine/utils/String.h b/engine/utils/String.h index 71a16a89..e58c76e2 100644 --- a/engine/utils/String.h +++ b/engine/utils/String.h @@ -217,6 +217,13 @@ class String // Conversion methods + /** + * Attempts to retrieve the String's value as a bool + * @param value - the bool to populate + * @return true if the conversion was successful, false otherwise + */ + bool GetBool(OUT bool& value) const; + /** * Attempts to retrieve the String's value as an integer * @param value - the integer to populate @@ -231,6 +238,13 @@ class String */ bool GetFloat(OUT float& value) const; + /** + * Conversion method for bool values + * @param value - the bool value to convert + * @return the newly created String + */ + static String FromBool(bool value); + /** * Conversion method for integer values * @param value - the integer value to convert @@ -342,6 +356,18 @@ class String */ size_t Find(char character, int startIdx = 0) const; + /** + * Returns whether the String begins with the supplied String as a substring + * @return true if the String begins with the substring, false otherwise + */ + bool BeginsWith(const String& substring) const; + + /** + * Returns whether the String begins with the supplied c-string as a substring + * @return true if the String begins with the substring, false otherwise + */ + bool BeginsWith(const char* substring) const; + /** * Splits the String by a provided list of delimiter characters * @param delimiters - a c-string of delimiter characters to split by (e.g. ",:-") @@ -426,11 +452,16 @@ class String void Prepend(const char* string); /** - * Removes the character at - * @return + * Removes the character at the end of the String and returns it + * @return the popped character */ char PopBack(); + /** + * Reverses the String in-place + */ + void Reverse(); + /** * Erases portions of the String based on position and length * @note this method supports negative indexing for reversed lookup @@ -492,7 +523,7 @@ class String { const char* data = Data(); size_t formatLen = snprintf(nullptr, 0, data, std::forward

(params)...); - char newStr[formatLen + 1]; + char* newStr = static_cast(alloca(formatLen + 1)); snprintf(newStr, formatLen + 1, data, std::forward

(params)...); Assign(newStr); } @@ -625,6 +656,14 @@ bool operator!=(const char* lhs, const String& rhs); */ String operator+(const char* lhs, const String& rhs); +/** + * Reversed wide c-string addition operator overload for prepending strings + * @param lhs - the string to append to + * @param rhs - the string to append + * @return a new string object with the appended value + */ +String operator+(const wchar_t* lhs, const String& rhs); + /** * Reversed character addition operator overload for prepending characters * @param lhs - the character to append to diff --git a/engine/utils/Token.cpp b/engine/utils/Token.cpp new file mode 100644 index 00000000..3063aa0b --- /dev/null +++ b/engine/utils/Token.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#include "Token.h" + +#include "Logging.h" + +namespace Siege +{ +Token::Token() : tokenId(nullptr) {} + +Token::Token(const char* name) : tokenId(FindTokenId(name)) {} + +bool Token::operator==(Token rhs) const +{ + return tokenId == rhs.tokenId; +} + +bool Token::operator!=(Token rhs) const +{ + return tokenId != rhs.tokenId; +} + +bool Token::operator<(Token rhs) const +{ + return tokenId < rhs.tokenId; +} + +Token::operator bool() const +{ + return IsValid(); +} + +const char* Token::GetId() const +{ + return tokenId; +} + +bool Token::IsValid() const +{ + return tokenId != nullptr; +} + +std::unordered_set& Token::GetGlobalTokenRegister() +{ + static std::unordered_set tokenRegister; + return tokenRegister; +} + +Token Token::FindToken(const String& name) +{ + return Token(FindTokenId(name)); +} + +Token Token::FindOrRegisterToken(const String& name) +{ + if (name.IsEmpty()) return {}; + + std::unordered_set& tokenRegister = GetGlobalTokenRegister(); + auto it = tokenRegister.insert(name); + if (it.second) CC_LOG_INFO("Registered new token \"{}\"", name); + + return Token(it.first->Str()); +} + +const char* Token::FindTokenId(const String& name) +{ + const std::unordered_set& tokenRegister = GetGlobalTokenRegister(); + auto it = tokenRegister.find(name); + + return it != tokenRegister.end() ? it->Str() : nullptr; +} +} // namespace Siege \ No newline at end of file diff --git a/engine/utils/Token.h b/engine/utils/Token.h new file mode 100644 index 00000000..d434d6e0 --- /dev/null +++ b/engine/utils/Token.h @@ -0,0 +1,142 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#ifndef SIEGE_ENGINE_TOKEN_H +#define SIEGE_ENGINE_TOKEN_H + +#include + +#include "String.h" + +// Define macros +#define REGISTER_TOKEN(name) \ + static const Siege::Token CONCAT_SYMBOL(TOKEN_, name)( \ + Siege::Token::FindOrRegisterToken(TOSTRING(name))) + +namespace Siege +{ +/** + * The Token class provides a tokenised strings type along utility functions for looking up and + * creating new string tokens. + * + * The Tokens wrap a c-string pointer to a string entry in a global unordered_set, populated with + * valid, canonical token names. Tokens use their pointer to the canonical set as a means of + * comparison, where a Token wrapping a null pointer is considered invalid. + */ +class Token +{ +public: + + // 'Structors + + /** + * Zero-param constructor for initialising empty Tokens + */ + Token(); + + /** + * C-string constructor for initialising by search of the + * canonical set for the requested Token + * @param name - the c-string to search + */ + explicit Token(const char* name); + + // Operator overloads + + /** + * Equality operator overload for checking equality with another + * @note tokens are compared on the basis of their wrapped pointer + * @param rhs - the Token to check + * @return true if the Tokens are equal, false otherwise + */ + bool operator==(Token rhs) const; + + /** + * Inequality operator overload for checking inequality with another + * @param rhs - the Token to check + * @return true if the Tokens are not equal, false otherwise + */ + bool operator!=(Token rhs) const; + + /** + * Less-than comparison operator overload for Token identity comparison + * @note this is used by standard template types requiring a key comparator + * and is implemented via a comparison of the wrapped pointer address + * @param rhs - the Token to compare to + * @return true if the Token's comparison index is lower, false otherwise + */ + bool operator<(Token rhs) const; + + // Conversion overloads + + /** + * Boolean conversion operator overload for checking validity + * @return true if the Token is valid, false otherwise + */ + operator bool() const; + + // Public methods + + /** + * Gets the wrapped pointer of the Token + * @return the Token c-string + */ + const char* GetId() const; + + /** + * Returns whether the Token is valid or not + * @note Tokens are considered invalid if they wrap a nullptr, but those + * of pointers outside the canonical set are considered malformed + * @return true if the Token is valid, false otherwise + */ + bool IsValid() const; + + // Public static functions + + /** + * Retrieves the canonical set of valid token strings + * @return an unordered set of Strings + */ + static std::unordered_set& GetGlobalTokenRegister(); + + /** + * Finds the Token for a given String + * @param name - the String to search for + * @return the requested Token if found in the canonical set, else an invalid Token + */ + static Token FindToken(const String& name); + + /** + * Finds or registers a new Token for a given String + * @param name - the String to search for + * @return the requested Token + */ + static Token FindOrRegisterToken(const String& name); + +private: + + // Private static functions + + /** + * Finds the wrapped pointer for a given String + * @param name - the String to search for + * @return the Token c-string + */ + static const char* FindTokenId(const String& name); + + // Private fields + + /** + * Wrapped pointer to the start of the canonical String + */ + const char* tokenId; +}; +} // namespace Siege + +#endif // SIEGE_ENGINE_TOKEN_H diff --git a/engine/utils/math/mat/Mat4.h b/engine/utils/math/mat/Mat4.h index db076486..d4e20d8f 100644 --- a/engine/utils/math/mat/Mat4.h +++ b/engine/utils/math/mat/Mat4.h @@ -214,6 +214,15 @@ struct Mat {matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]}}; } + static inline constexpr Mat Scale(const Vec& scale) + { + Mat mat = Mat::Identity(); + mat[0][0] = scale.x; + mat[1][1] = scale.y; + mat[2][2] = scale.z; + return mat; + } + // 'Structors /** diff --git a/engine/window/Makefile b/engine/window/Makefile index 75073712..68754bc7 100644 --- a/engine/window/Makefile +++ b/engine/window/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -windowSrcDir := . +windowSrcDir := ./ windowBinDir := $(binDir)/engine/window windowSources := $(call rwildcard,$(windowSrcDir)/,*.cpp) windowObjects := $(call findobjs,$(windowSrcDir),$(windowBinDir),$(windowSources)) diff --git a/examples/game/Makefile b/examples/game/Makefile index c7c237fe..50fcc890 100644 --- a/examples/game/Makefile +++ b/examples/game/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -exampleGameSrcDir := . +exampleGameSrcDir := ./ exampleGameBinDir := $(binDir)/examples/game exampleGameSources := $(call rwildcard,$(exampleGameSrcDir)/,*.cpp) exampleGameObjects := $(call findobjs,$(exampleGameSrcDir),$(exampleGameBinDir),$(exampleGameSources)) @@ -29,7 +29,7 @@ else ifeq ($(platform), macos) export VK_ICD_FILENAMES='./lib/icd.d/MoltenVK_icd.json' endif engineRenderBuildDir := $(binDir)/engine/render/build -exampleGameAssets := $(patsubst ./%,%, $(call rwildcard,$(exampleGameSrcDir),*.obj)) +exampleGameAssets := $(patsubst ./%,%, $(call rwildcard,$(exampleGameSrcDir),*.sm)) exampleGameAssets += $(patsubst ./%,%, $(call rwildcard,$(exampleGameSrcDir),*.png)) exampleGameAssets += $(patsubst ./%,%, $(call rwildcard,$(exampleGameSrcDir),*.jpg)) exampleGameAssets += $(patsubst $(engineRenderBuildDir)/%,%, $(call rwildcard,$(engineRenderBuildDir),*.spv)) diff --git a/examples/game/assets/models/cube/cube.sm b/examples/game/assets/models/cube/cube.sm new file mode 100644 index 00000000..5e64995b --- /dev/null +++ b/examples/game/assets/models/cube/cube.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/models/cube/cube.obj; +MATERIAL_PATH:assets/models/cube/cube.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/examples/game/assets/scenes/collide.scene/Geometry.2.entity b/examples/game/assets/scenes/collide.scene/Geometry.2.entity index cb4cc039..6c144596 100644 --- a/examples/game/assets/scenes/collide.scene/Geometry.2.entity +++ b/examples/game/assets/scenes/collide.scene/Geometry.2.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:-0.00,0.00,-6.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:5.00,0.10,5.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_1.png; diff --git a/examples/game/assets/scenes/collide.scene/Geometry.3.entity b/examples/game/assets/scenes/collide.scene/Geometry.3.entity index 15b852a9..c9455ad5 100644 --- a/examples/game/assets/scenes/collide.scene/Geometry.3.entity +++ b/examples/game/assets/scenes/collide.scene/Geometry.3.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:-6.00,-1.00,-6.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:1.00,1.00,5.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_1.png; diff --git a/examples/game/assets/scenes/collide.scene/Player.1.entity b/examples/game/assets/scenes/collide.scene/Player.1.entity index 2ce7184a..9a159011 100644 --- a/examples/game/assets/scenes/collide.scene/Player.1.entity +++ b/examples/game/assets/scenes/collide.scene/Player.1.entity @@ -1,4 +1,4 @@ -Player; +TYPE:Player; POSITION:0.00,-3.00,-5.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; diff --git a/examples/game/assets/scenes/main.scene/Geometry.2.entity b/examples/game/assets/scenes/main.scene/Geometry.2.entity index 26a60699..dabc870e 100644 --- a/examples/game/assets/scenes/main.scene/Geometry.2.entity +++ b/examples/game/assets/scenes/main.scene/Geometry.2.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:-4.50,0.00,-1.50; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_2.png; diff --git a/examples/game/assets/scenes/main.scene/Geometry.3.entity b/examples/game/assets/scenes/main.scene/Geometry.3.entity index 988644e9..3b574ac5 100644 --- a/examples/game/assets/scenes/main.scene/Geometry.3.entity +++ b/examples/game/assets/scenes/main.scene/Geometry.3.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:-6.50,0.00,3.50; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_2.png; diff --git a/examples/game/assets/scenes/main.scene/Geometry.4.entity b/examples/game/assets/scenes/main.scene/Geometry.4.entity index cfc3959c..e011c60e 100644 --- a/examples/game/assets/scenes/main.scene/Geometry.4.entity +++ b/examples/game/assets/scenes/main.scene/Geometry.4.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:2.50,0.00,1.50; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_2.png; diff --git a/examples/game/assets/scenes/main.scene/Geometry.5.entity b/examples/game/assets/scenes/main.scene/Geometry.5.entity index 8fea0ec4..cd7a2533 100644 --- a/examples/game/assets/scenes/main.scene/Geometry.5.entity +++ b/examples/game/assets/scenes/main.scene/Geometry.5.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:0.50,0.00,-3.50; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_2.png; diff --git a/examples/game/assets/scenes/main.scene/Geometry.6.entity b/examples/game/assets/scenes/main.scene/Geometry.6.entity index d1c0e289..8b08f514 100644 --- a/examples/game/assets/scenes/main.scene/Geometry.6.entity +++ b/examples/game/assets/scenes/main.scene/Geometry.6.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:7.50,0.00,-0.50; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_2.png; diff --git a/examples/game/assets/scenes/main.scene/Player.1.entity b/examples/game/assets/scenes/main.scene/Player.1.entity index 46e72c83..06ddddc4 100644 --- a/examples/game/assets/scenes/main.scene/Player.1.entity +++ b/examples/game/assets/scenes/main.scene/Player.1.entity @@ -1,4 +1,4 @@ -Player; +TYPE:Player; POSITION:0.00,-4.00,0.76; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; diff --git a/examples/game/assets/scenes/test.scene/Geometry.1.entity b/examples/game/assets/scenes/test.scene/Geometry.1.entity index 19088a6f..8ac509e5 100644 --- a/examples/game/assets/scenes/test.scene/Geometry.1.entity +++ b/examples/game/assets/scenes/test.scene/Geometry.1.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:2.10,0.00,2.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_1.png; diff --git a/examples/game/assets/scenes/test.scene/Geometry.2.entity b/examples/game/assets/scenes/test.scene/Geometry.2.entity index cf49f935..f9f12f3e 100644 --- a/examples/game/assets/scenes/test.scene/Geometry.2.entity +++ b/examples/game/assets/scenes/test.scene/Geometry.2.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:-10.50,0.00,-7.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_1.png; diff --git a/examples/game/assets/scenes/test.scene/Geometry.3.entity b/examples/game/assets/scenes/test.scene/Geometry.3.entity index 998b0cfe..db82aabc 100644 --- a/examples/game/assets/scenes/test.scene/Geometry.3.entity +++ b/examples/game/assets/scenes/test.scene/Geometry.3.entity @@ -1,7 +1,7 @@ -Geometry; +TYPE:Geometry; POSITION:8.10,0.00,-7.00; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; DIMENSIONS:2.00,0.10,2.00; -MODEL_PATH:assets/models/cube/cube.obj; +MODEL_PATH:assets/models/cube/cube.sm; TEXTURE_PATH:models/cube/cube_1.png; diff --git a/examples/game/src/RenderResources.cpp b/examples/game/src/RenderResources.cpp index 432007d7..920c2ed3 100644 --- a/examples/game/src/RenderResources.cpp +++ b/examples/game/src/RenderResources.cpp @@ -30,7 +30,7 @@ RenderResources::RenderResources() .WithGlobalData3DUniform() .Build()); - cubeMesh = Siege::Vulkan::StaticMesh("assets/models/cube/cube.obj", &cubeMaterial); + cubeMesh = Siege::Vulkan::StaticMesh("assets/models/cube/cube.sm", &cubeMaterial); defaultFont = Siege::Vulkan::Font("assets/fonts/PublicPixel.ttf"); } diff --git a/examples/game/src/entities/Geometry.cpp b/examples/game/src/entities/Geometry.cpp index cd02376b..db212331 100644 --- a/examples/game/src/entities/Geometry.cpp +++ b/examples/game/src/entities/Geometry.cpp @@ -16,8 +16,9 @@ #include "../ServiceLocator.h" -// Static member initialisation -const Siege::String Geometry::ENTITY_NAME("Geometry"); +REGISTER_TOKEN(DIMENSIONS); +REGISTER_TOKEN(MODEL_PATH); +REGISTER_TOKEN(TEXTURE_PATH); void Geometry::OnStart() { @@ -71,26 +72,34 @@ static Siege::String Serialise(Siege::Entity* entity) { Siege::String fileData; auto geometry = dynamic_cast(entity); - fileData += DefineField("DIMENSIONS", Siege::ToString(geometry->GetDimensions())); + fileData += DefineField(TOKEN_DIMENSIONS, Siege::ToString(geometry->GetDimensions())); - fileData += DefineField("MODEL_PATH", geometry->GetModelPath()); - fileData += DefineField("TEXTURE_PATH", geometry->GetTexturePath()); + fileData += DefineField(TOKEN_MODEL_PATH, geometry->GetModelPath()); + fileData += DefineField(TOKEN_TEXTURE_PATH, geometry->GetTexturePath()); return fileData; } -static Siege::Entity* Deserialise(const Siege::EntityData& data, - const std::vector& args) +static Siege::Entity* Deserialise(const std::map& attributes) { + Siege::EntityData data = Siege::SceneFile::GetBaseEntityData(attributes); + Siege::Vec3 dimensions; - if (!Siege::FromString(dimensions, args[Siege::CUSTOM_FIELD_1])) + auto it = attributes.find(TOKEN_DIMENSIONS); + if (it != attributes.end()) { - CC_LOG_WARNING("Failed to deserialise dimensions with value {}", - args[Siege::CUSTOM_FIELD_1]); + if (!Siege::FromString(dimensions, it->second)) + { + CC_LOG_WARNING("Failed to deserialise dimensions with value {}", it->second); + } } - Siege::String modelPath = args[Siege::CUSTOM_FIELD_2]; - Siege::String texturePath = args[Siege::CUSTOM_FIELD_3]; + + it = attributes.find(TOKEN_MODEL_PATH); + Siege::String modelPath = it != attributes.end() ? it->second : ""; + + it = attributes.find(TOKEN_TEXTURE_PATH); + Siege::String texturePath = it != attributes.end() ? it->second : ""; return new Geometry({data.position, data.rotation, dimensions}, modelPath, texturePath); } -REGISTER_SERIALISATION_INTERFACE(Geometry::ENTITY_NAME, Serialise, Deserialise); +REGISTER_SERIALISATION_INTERFACE(TOKEN_Geometry, Serialise, Deserialise); diff --git a/examples/game/src/entities/Geometry.h b/examples/game/src/entities/Geometry.h index 8076c187..080403f8 100644 --- a/examples/game/src/entities/Geometry.h +++ b/examples/game/src/entities/Geometry.h @@ -11,26 +11,25 @@ #define SIEGE_ENGINE_GEOMETRY_H #include +#include #include +REGISTER_TOKEN(Geometry); + class Geometry : public Siege::Entity { public: - // Public constants - - static const Siege::String ENTITY_NAME; - // 'Structors Geometry() : Geometry({Siege::Vec3::Zero(), 0.f}) {}; explicit Geometry(const Siege::Xform& transform) : - Geometry(transform, "assets/models/cube/cube.obj", "assets/models/cube/cube.png") {}; + Geometry(transform, "assets/models/cube/cube.sm", "assets/models/cube/cube.png") {}; Geometry(const Siege::Xform& transform, Siege::String modelPath, Siege::String texturePath) : - Entity(ENTITY_NAME, transform), + Entity(TOKEN_Geometry, transform), modelPath(std::move(modelPath)), texturePath(std::move(texturePath)) {}; diff --git a/examples/game/src/entities/Player.cpp b/examples/game/src/entities/Player.cpp index bd8f4e50..ce60e65a 100644 --- a/examples/game/src/entities/Player.cpp +++ b/examples/game/src/entities/Player.cpp @@ -16,9 +16,6 @@ #include "../ServiceLocator.h" -// Static member initialisation -const Siege::String Player::ENTITY_NAME("Player"); - void Player::OnUpdate() { // Get move axes as vector @@ -67,10 +64,10 @@ void Player::OnDraw3D() GetRotation()); } -static Siege::Entity* Deserialise(const Siege::EntityData& data, - const std::vector& args) +static Siege::Entity* Deserialise(const std::map& attributes) { + Siege::EntityData data = Siege::SceneFile::GetBaseEntityData(attributes); return new Player({data.position, data.rotation}); } -REGISTER_SERIALISATION_INTERFACE(Player::ENTITY_NAME, nullptr, Deserialise); +REGISTER_SERIALISATION_INTERFACE(TOKEN_Player, nullptr, Deserialise); diff --git a/examples/game/src/entities/Player.h b/examples/game/src/entities/Player.h index e01a1054..0ae24660 100644 --- a/examples/game/src/entities/Player.h +++ b/examples/game/src/entities/Player.h @@ -11,21 +11,20 @@ #define SIEGE_ENGINE_PLAYER_H #include +#include + +REGISTER_TOKEN(Player); class Player : public Siege::Entity { public: - // Public constants - - static const Siege::String ENTITY_NAME; - // 'Structors Player() : Player({Siege::Vec3::Zero(), 0.f}) {}; explicit Player(const Siege::Xform& transform) : - Entity(ENTITY_NAME, transform), + Entity(TOKEN_Player, transform), speed(1.5f), velocity(Siege::Vec3::Zero()) {}; diff --git a/examples/game/src/tools/EditorController.cpp b/examples/game/src/tools/EditorController.cpp index 1a625bf2..e7220ada 100644 --- a/examples/game/src/tools/EditorController.cpp +++ b/examples/game/src/tools/EditorController.cpp @@ -23,9 +23,6 @@ static float MOVE_LEVELS[] = {.01f, .1f, 1.f, 5.f, 10.f, 50.f, 100.f}; static float ROTATE_LEVELS[] = {.01f, .1f, 1.f, 15.f, 45.f, 90.f}; -// Define colours -static Siege::IColour BRIGHT_PINK(255, 5, 146); - void EditorController::OnUpdate() { // The editor should not be able to receive input while the console is open @@ -177,7 +174,7 @@ void EditorController::OnDraw2D() window->GetHeight()); // Format display text on the selected entity - Siege::String nameLabel = Siege::String("%s").Formatted(selectedEntity->GetName().Str()); + Siege::String nameLabel = Siege::String("%s").Formatted(selectedEntity->GetType()); Siege::String posLabel = Siege::String("Position: <%.2f, %.2f, %.2f>") .Formatted(selectedEntity->GetPosition().x, selectedEntity->GetPosition().y, diff --git a/examples/render/Makefile b/examples/render/Makefile index f23cd629..09a9464d 100644 --- a/examples/render/Makefile +++ b/examples/render/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -exampleRenderSrcDir := . +exampleRenderSrcDir := ./ exampleRenderBinDir := $(binDir)/examples/render exampleRenderSources := $(call rwildcard,$(exampleRenderSrcDir)/,*.cpp) exampleRenderObjects := $(call findobjs,$(exampleRenderSrcDir),$(exampleRenderBinDir),$(exampleRenderSources)) @@ -29,7 +29,7 @@ else ifeq ($(platform), macos) export VK_ICD_FILENAMES='./lib/icd.d/MoltenVK_icd.json' endif engineRenderBuildDir := $(binDir)/engine/render/build -exampleRenderAssets := $(patsubst ./%,%, $(call rwildcard,$(exampleRenderSrcDir),*.obj)) +exampleRenderAssets := $(patsubst ./%,%, $(call rwildcard,$(exampleRenderSrcDir),*.sm)) exampleRenderAssets += $(patsubst ./%,%, $(call rwildcard,$(exampleRenderSrcDir),*.png)) exampleRenderAssets += $(patsubst ./%,%, $(call rwildcard,$(exampleRenderSrcDir),*.jpg)) exampleRenderAssets += $(patsubst $(engineRenderBuildDir)/%,%, $(call rwildcard,$(engineRenderBuildDir),*.spv)) diff --git a/examples/render/assets/models/colored_cube.sm b/examples/render/assets/models/colored_cube.sm new file mode 100644 index 00000000..51701b5a --- /dev/null +++ b/examples/render/assets/models/colored_cube.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/models/colored_cube.obj; +MATERIAL_PATH:assets/models/colored_cube.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/examples/render/assets/models/cube.glb b/examples/render/assets/models/cube.glb new file mode 100644 index 00000000..86a16e58 Binary files /dev/null and b/examples/render/assets/models/cube.glb differ diff --git a/examples/render/assets/models/cube.sm b/examples/render/assets/models/cube.sm new file mode 100644 index 00000000..d8ffb0e5 --- /dev/null +++ b/examples/render/assets/models/cube.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/models/cube.glb; +MATERIAL_PATH:assets/models/cube.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/examples/render/assets/models/cube_set.glb b/examples/render/assets/models/cube_set.glb new file mode 100644 index 00000000..c544c6d2 Binary files /dev/null and b/examples/render/assets/models/cube_set.glb differ diff --git a/examples/render/assets/models/cube_set.sm b/examples/render/assets/models/cube_set.sm new file mode 100644 index 00000000..6e68652d --- /dev/null +++ b/examples/render/assets/models/cube_set.sm @@ -0,0 +1,4 @@ +SOURCE_PATH:assets/models/cube_set.glb; +MATERIAL_PATH:assets/models/cube.mat; +NODE_PATH:/; +FLIP_AXES:yz; \ No newline at end of file diff --git a/examples/render/assets/models/flat_vase.sm b/examples/render/assets/models/flat_vase.sm new file mode 100644 index 00000000..285ffaab --- /dev/null +++ b/examples/render/assets/models/flat_vase.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/models/flat_vase.obj; +MATERIAL_PATH:assets/models/flat_vase.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/examples/render/assets/models/gizmo.glb b/examples/render/assets/models/gizmo.glb new file mode 100644 index 00000000..c480143c Binary files /dev/null and b/examples/render/assets/models/gizmo.glb differ diff --git a/examples/render/assets/models/gizmo.sm b/examples/render/assets/models/gizmo.sm new file mode 100644 index 00000000..6af9a07d --- /dev/null +++ b/examples/render/assets/models/gizmo.sm @@ -0,0 +1,4 @@ +SOURCE_PATH:assets/models/gizmo.glb; +MATERIAL_PATH:assets/models/cube.mat; +NODE_PATH:/; +FLIP_AXES:zy; \ No newline at end of file diff --git a/examples/render/assets/models/smooth_vase.sm b/examples/render/assets/models/smooth_vase.sm new file mode 100644 index 00000000..a043802d --- /dev/null +++ b/examples/render/assets/models/smooth_vase.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/models/smooth_vase.obj; +MATERIAL_PATH:assets/models/smooth_vase.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/examples/render/src/main.cpp b/examples/render/src/main.cpp index ccd2196b..aeff1716 100644 --- a/examples/render/src/main.cpp +++ b/examples/render/src/main.cpp @@ -84,15 +84,19 @@ int main() .Build()); // Generate models - Siege::Vulkan::StaticMesh cubeObjModel("assets/models/cube.obj", &testMaterial); - Siege::Vulkan::StaticMesh vaseObjModel("assets/models/smooth_vase.obj", &testMaterial); + Siege::Vulkan::StaticMesh cubeObjModel("assets/models/cube.sm", &testMaterial); + Siege::Vulkan::StaticMesh vaseObjModel("assets/models/smooth_vase.sm", &testMaterial); + Siege::Vulkan::StaticMesh cubeSetObjModel("assets/models/cube_set.sm", &testMaterial); + Siege::Vulkan::StaticMesh gizmoObjModel("assets/models/gizmo.sm", &testMaterial); // Create shapes for use Siege::MHArray objects3D = {GameObject(&cubeObjModel), GameObject(&cubeObjModel), GameObject(&cubeObjModel), GameObject(&cubeObjModel), - GameObject(&vaseObjModel)}; + GameObject(&vaseObjModel), + GameObject(&cubeSetObjModel), + GameObject(&gizmoObjModel)}; objects3D[0].SetPosition({0.f, -.5f, 0.f}); objects3D[0].SetScale({.5f, .5f, .5f}); @@ -117,6 +121,14 @@ int main() objects3D[4].SetScale({2.f, 2.f, 2.f}); objects3D[4].SetColour({128, 0, 0, 255}); + objects3D[5].SetPosition({-8.f, 0.f, 0.f}); + objects3D[5].SetScale({1.f, 1.f, 1.f}); + objects3D[5].SetColour({0, 0, 128, 255}); + + objects3D[6].SetPosition({-5.f, 0.f, 0.f}); + objects3D[6].SetScale({1.f, 1.f, 1.f}); + objects3D[6].SetColour({0, 0, 128, 255}); + FPSCamera camera3D = FPSCamera({0.f, -1.f, -2.5f}, {0.f, 0.f, 1.f}, Siege::Float::Radians(60.f), diff --git a/examples/tilemap/Makefile b/examples/tilemap/Makefile index c824944a..2f9f8051 100644 --- a/examples/tilemap/Makefile +++ b/examples/tilemap/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -exampleTilemapSrcDir := . +exampleTilemapSrcDir := ./ exampleTilemapBinDir := $(binDir)/examples/tilemap exampleTilemapSources := $(call rwildcard,$(exampleTilemapSrcDir)/,*.cpp) exampleTilemapObjects := $(call findobjs,$(exampleTilemapSrcDir),$(exampleTilemapBinDir),$(exampleTilemapSources)) diff --git a/packer/Makefile b/packer/Makefile index 0db216d3..96029355 100644 --- a/packer/Makefile +++ b/packer/Makefile @@ -9,7 +9,7 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -packerSrcDir := . +packerSrcDir := ./ packerBinDir := $(binDir)/packer packerSources := $(call rwildcard,$(packerSrcDir)/,*.cpp) packerObjects := $(call findobjs,$(packerSrcDir),$(packerBinDir),$(packerSources)) @@ -17,8 +17,8 @@ packerDepends := $(patsubst %.o, %.d, $(call rwildcard,$(packerBinDir)/,*.o)) packerBuildDir := $(packerBinDir)/build # Set build vars -linkFlags += -l resources -l utils -compileFlags += -I $(vendorDir)/tinyobjloader -I $(vendorDir)/stb_image +linkFlags += -l resources -l utils -L $(vendorDir)/zlib/build/lib -L $(vendorDir)/assimp/build/lib -l assimp -l z -l stdc++ +compileFlags += -I $(vendorDir)/stb_image -I $(vendorDir)/assimp/include -I $(vendorDir)/assimp/build/include .PHONY: all diff --git a/packer/src/PackerUtils.h b/packer/src/PackerUtils.h new file mode 100644 index 00000000..69d4f69f --- /dev/null +++ b/packer/src/PackerUtils.h @@ -0,0 +1,24 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#ifndef SIEGE_ENGINE_PACKER_PACKERUTILS_H +#define SIEGE_ENGINE_PACKER_PACKERUTILS_H + +#include +#include + +static constexpr Siege::Mat4 AssimpMat4ToMat4(const aiMatrix4x4& matrix) +{ + return {{matrix.a1, matrix.b1, matrix.c1, matrix.d1}, + {matrix.a2, matrix.b2, matrix.c2, matrix.d2}, + {matrix.a3, matrix.b3, matrix.c3, matrix.d3}, + {matrix.a4, matrix.b4, matrix.c4, matrix.d4}}; +} + +#endif // SIEGE_ENGINE_PACKER_PACKERUTILS_H diff --git a/packer/main.cpp b/packer/src/main.cpp similarity index 97% rename from packer/main.cpp rename to packer/src/main.cpp index 73dd6cd6..ebfa87d4 100644 --- a/packer/main.cpp +++ b/packer/src/main.cpp @@ -19,8 +19,8 @@ #include "types/GenericFileDataPacker.h" #include "types/SceneDataPacker.h" +#include "types/StaticMeshDataPacker.h" #include "types/Texture2DDataPacker.h" -#include "types/WavefrontDataPacker.h" using Siege::PackFile; @@ -58,14 +58,15 @@ int main(int argc, char* argv[]) for (auto& file : inputFiles) { if (file.empty()) continue; + CC_LOG_INFO("Reading asset at path {}", file.c_str()) void* data = nullptr; uint32_t bodyDataSize = 0; Siege::String fullPath = assetsDir + "/" + Siege::String(file.c_str()); std::filesystem::path extension = file.extension(); - if (extension == ".obj") + if (extension == ".sm") { - data = PackWavefrontFile(fullPath); + data = PackStaticMeshFile(fullPath, assetsDir); bodyDataSize = Siege::StaticMeshData::GetDataSize(data); } else if (extension == ".jpg" || extension == ".jpeg" || extension == ".png") diff --git a/packer/types/GenericFileDataPacker.cpp b/packer/src/types/GenericFileDataPacker.cpp similarity index 72% rename from packer/types/GenericFileDataPacker.cpp rename to packer/src/types/GenericFileDataPacker.cpp index c77cee85..6e7cee75 100644 --- a/packer/types/GenericFileDataPacker.cpp +++ b/packer/src/types/GenericFileDataPacker.cpp @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: @@ -9,12 +10,15 @@ #include "GenericFileDataPacker.h" #include +#include #include #include void* PackGenericFile(const Siege::String& filePath) { + CC_LOG_INFO("Reading file data as generic binary asset") + // Read the file as binary and consume the entire file. std::ifstream file {filePath.Str(), std::ios::ate | std::ios::binary}; @@ -22,9 +26,11 @@ void* PackGenericFile(const Siege::String& filePath) // Since we consumed the entire file, we can tell the size by checking where // the file stream is reading from (which presumably is at the end of the file). - uint32_t fileSize = static_cast(file.tellg()); + uint32_t fileSize = file.tellg(); + + char* data = static_cast(malloc(fileSize)); + defer([&data] { free(data); }); - char data[fileSize]; file.seekg(0); // Move to the beginning of the file. file.read(data, fileSize); file.close(); diff --git a/packer/types/GenericFileDataPacker.h b/packer/src/types/GenericFileDataPacker.h similarity index 73% rename from packer/types/GenericFileDataPacker.h rename to packer/src/types/GenericFileDataPacker.h index 3d7c98f0..8698e9d9 100644 --- a/packer/types/GenericFileDataPacker.h +++ b/packer/src/types/GenericFileDataPacker.h @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: diff --git a/packer/types/SceneDataPacker.cpp b/packer/src/types/SceneDataPacker.cpp similarity index 72% rename from packer/types/SceneDataPacker.cpp rename to packer/src/types/SceneDataPacker.cpp index 8854e7ca..05548192 100644 --- a/packer/types/SceneDataPacker.cpp +++ b/packer/src/types/SceneDataPacker.cpp @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: @@ -9,6 +10,7 @@ #include "SceneDataPacker.h" #include +#include #include #include @@ -20,6 +22,7 @@ void* PackSceneFile(const Siege::String& filePath) Siege::String bodyString; auto appendFile = [&bodyString](const std::filesystem::path& path) { if (path.extension() != ".entity") return; + CC_LOG_INFO("Reading entity file {}", path.filename().c_str()) bodyString += Siege::FileSystem::Read(path.c_str()); bodyString += '|'; }; @@ -31,13 +34,12 @@ void* PackSceneFile(const Siege::String& filePath) return nullptr; } - std::string str(bodyString); - str.erase(std::remove(str.begin(), str.end(), '\n'), str.cend()); - str.erase(std::remove(str.begin(), str.end(), '\r'), str.cend()); - bodyString = str.c_str(); + bodyString = Siege::FileSystem::StripNewLines(bodyString); uint32_t fileSize = bodyString.Size() + 1; - char data[fileSize]; + char* data = static_cast(malloc(fileSize)); + defer([&data] { free(data); }); + memcpy(data, bodyString.Str(), fileSize); Siege::SceneData* sceneData = Siege::SceneData::Create(&data[0], fileSize); diff --git a/packer/types/SceneDataPacker.h b/packer/src/types/SceneDataPacker.h similarity index 72% rename from packer/types/SceneDataPacker.h rename to packer/src/types/SceneDataPacker.h index 1d3577a2..862f2434 100644 --- a/packer/types/SceneDataPacker.h +++ b/packer/src/types/SceneDataPacker.h @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: diff --git a/packer/src/types/StaticMeshDataPacker.cpp b/packer/src/types/StaticMeshDataPacker.cpp new file mode 100644 index 00000000..3f36c37b --- /dev/null +++ b/packer/src/types/StaticMeshDataPacker.cpp @@ -0,0 +1,217 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#include "StaticMeshDataPacker.h" + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "../PackerUtils.h" + +enum RequestPathStage +{ + PARENT, + CHILD, + SELF, + NONE, +}; + +static RequestPathStage GetRequestPathStage(const Siege::String& requestPath, + const Siege::String& currentPath) +{ + if (currentPath.Size() == requestPath.Size()) + { + return SELF; + } + + if (requestPath.BeginsWith(currentPath)) + { + return PARENT; + } + + if (currentPath.BeginsWith(requestPath)) + { + return CHILD; + } + + return NONE; +} + +static void GetMeshData(const aiScene* scene, + const aiMesh* mesh, + const Siege::Mat4& mat, + OUT std::vector& vertices, + OUT std::vector& indices) +{ + for (uint32_t i = 0; i < mesh->mNumVertices; i++) + { + Siege::BaseVertex vertex {}; + + aiVector3t vert = mesh->mVertices[i]; + vertex.position = mat * Siege::Vec4(vert.x, vert.y, vert.z, 1.f); + + aiVector3t norm = mesh->mNormals[i]; + vertex.normal = {norm.x, norm.y, norm.z}; + + const aiColor4t* color = mesh->mColors[0]; + vertex.color = color ? Siege::FColour {color[i].r, color[i].g, color[i].b, color[i].a} : + Siege::FColour::White; + + if (aiVector3t* uv = mesh->mTextureCoords[0]) + { + vertex.uv = {uv[i].x, uv[i].y}; + } + + vertices.push_back(vertex); + } + + const auto it = std::max_element(indices.begin(), indices.end()); + const uint32_t indexOffset = it != indices.end() ? *it + 1 : 0; + for (uint32_t i = 0; i < mesh->mNumFaces; i++) + { + const aiFace face = mesh->mFaces[i]; + for (uint32_t j = 0; j < face.mNumIndices; j++) + { + indices.push_back(indexOffset + face.mIndices[j]); + } + } +} + +static void GetMeshesForNode(const aiScene* scene, + const aiNode* node, + const Siege::String& requestPath, + Siege::String currentPath, + Siege::Mat4 matrix, + OUT std::vector& vertices, + OUT std::vector& indices) +{ + currentPath = currentPath + node->mName.C_Str(); + + const RequestPathStage nodePathStage = GetRequestPathStage(requestPath, currentPath); + if (nodePathStage == NONE) + { + return; + } + + CC_LOG_INFO("Reading node at {}", currentPath) + + if (nodePathStage == CHILD || nodePathStage == SELF) + { + matrix *= AssimpMat4ToMat4(node->mTransformation); + } + + for (uint32_t i = 0; i < node->mNumMeshes; i++) + { + const aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; + + Siege::String currentMeshPath = currentPath + '/' + mesh->mName.C_Str(); + const RequestPathStage meshPathStage = GetRequestPathStage(requestPath, currentMeshPath); + if (meshPathStage == NONE) + { + continue; + } + + CC_LOG_INFO("Reading mesh at {}", currentMeshPath) + GetMeshData(scene, mesh, matrix, vertices, indices); + } + + for (uint32_t i = 0; i < node->mNumChildren; i++) + { + GetMeshesForNode(scene, + node->mChildren[i], + requestPath, + currentPath + '/', + matrix, + vertices, + indices); + } +}; + +void* PackStaticMeshFile(const Siege::String& filePath, const Siege::String& assetsPath) +{ + Siege::String contents = Siege::FileSystem::Read(filePath); + std::map attributes = + Siege::FileSystem::ParseAttributeFileData(contents); + + if (attributes.empty()) + { + CC_LOG_WARNING("Received empty static mesh file at path \"{}\"", filePath); + return nullptr; + } + + auto it = attributes.find(TOKEN_SOURCE_PATH); + if (it == attributes.end()) + { + CC_LOG_WARNING("Failed to find SOURCE_PATH attribute in .sm file at path \"{}\"", filePath) + return nullptr; + } + + Siege::String modelPath = assetsPath + '/' + it->second; + Assimp::Importer importer; + const aiScene* scene = + importer.ReadFile(modelPath, + aiProcess_CalcTangentSpace | aiProcess_Triangulate | + aiProcess_JoinIdenticalVertices | aiProcess_SortByPType); + if (!scene) + { + CC_LOG_WARNING("Failed to read file at path \"{}\"", modelPath) + return nullptr; + } + + auto nodePathIt = attributes.find(TOKEN_NODE_PATH); + Siege::String requestedNodePath = nodePathIt != attributes.end() ? nodePathIt->second : "/"; + + CC_LOG_INFO("Reading static mesh for file {} with node path {}", it->second, requestedNodePath) + + Siege::Mat4 baseXform = Siege::Mat4::Identity(); + auto flipAxesIt = attributes.find(TOKEN_FLIP_AXES); + if (flipAxesIt != attributes.end()) + { + if (flipAxesIt->second.Size() < 1 || flipAxesIt->second.Size() > 3) + { + CC_LOG_WARNING("FLIP_AXES attribute in .sm file contains invalid number of axes") + } + + for (int32_t i = 0; i < flipAxesIt->second.Size(); ++i) + { + Siege::Vec4 scale = {1.f, 1.f, 1.f, 1.f}; + switch (flipAxesIt->second[i]) + { + case 'x': + scale.x *= -1; + break; + case 'y': + scale.y *= -1; + break; + case 'z': + scale.z *= -1; + break; + default: + CC_LOG_WARNING("Found invalid axis \"{}\" in FLIP_AXES attribute, ignoring", + flipAxesIt->second[i]) + break; + } + baseXform *= Siege::Mat4::Scale(scale); + } + } + + std::vector vertices; + std::vector indices; + GetMeshesForNode(scene, scene->mRootNode, requestedNodePath, '/', baseXform, vertices, indices); + + Siege::StaticMeshData* staticMeshData = Siege::StaticMeshData::Create(indices, vertices); + return staticMeshData; +} diff --git a/packer/src/types/StaticMeshDataPacker.h b/packer/src/types/StaticMeshDataPacker.h new file mode 100644 index 00000000..8d2cf9cb --- /dev/null +++ b/packer/src/types/StaticMeshDataPacker.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#ifndef SIEGE_ENGINE_STATICMESHDATAPACKER_H +#define SIEGE_ENGINE_STATICMESHDATAPACKER_H + +#include +#include + +REGISTER_TOKEN(SOURCE_PATH); +REGISTER_TOKEN(NODE_PATH); +REGISTER_TOKEN(FLIP_AXES); + +void* PackStaticMeshFile(const Siege::String& filePath, const Siege::String& assetsPath); + +#endif // SIEGE_ENGINE_STATICMESHDATAPACKER_H diff --git a/packer/types/Texture2DDataPacker.cpp b/packer/src/types/Texture2DDataPacker.cpp similarity index 72% rename from packer/types/Texture2DDataPacker.cpp rename to packer/src/types/Texture2DDataPacker.cpp index 3912d47b..528d8316 100644 --- a/packer/types/Texture2DDataPacker.cpp +++ b/packer/src/types/Texture2DDataPacker.cpp @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: @@ -21,6 +22,11 @@ void* PackTexture2DFile(const Siege::String& filePath) defer([pixels] { stbi_image_free(pixels); }); CC_ASSERT(pixels, "Failed to load image file!") + CC_LOG_INFO("Reading 2D texture with dimensions {} by {} over {} channels", + texWidth, + texHeight, + texChannels) + Siege::Texture2DData* texture2dData = Siege::Texture2DData::Create(pixels, texWidth, texHeight, texChannels); return texture2dData; diff --git a/packer/types/Texture2DDataPacker.h b/packer/src/types/Texture2DDataPacker.h similarity index 73% rename from packer/types/Texture2DDataPacker.h rename to packer/src/types/Texture2DDataPacker.h index 7530632c..f029386c 100644 --- a/packer/types/Texture2DDataPacker.h +++ b/packer/src/types/Texture2DDataPacker.h @@ -1,5 +1,6 @@ // -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) // // This code is released under an unmodified zlib license. // For conditions of distribution and use, please see: diff --git a/packer/types/WavefrontDataPacker.cpp b/packer/types/WavefrontDataPacker.cpp deleted file mode 100644 index 334c4d35..00000000 --- a/packer/types/WavefrontDataPacker.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) -// -// This code is released under an unmodified zlib license. -// For conditions of distribution and use, please see: -// https://opensource.org/licenses/Zlib -// - -#include "WavefrontDataPacker.h" - -#define TINYOBJLOADER_IMPLEMENTATION -#include -#include -#include - -#include - -using Siege::BaseVertex; -using Siege::FColour; -using Siege::Vec2; -using Siege::Vec3; - -void* PackWavefrontFile(const Siege::String& filePath) -{ - tinyobj::attrib_t attrib; - std::vector shapes; - std::vector materials; - std::string warn, err; - - std::vector objVertices; - std::vector objIndices; - std::unordered_map uniqueVertices {}; - - CC_ASSERT(tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filePath), - (warn + err).c_str()) - - for (const auto& shape : shapes) - { - for (const auto& index : shape.mesh.indices) - { - BaseVertex vertex {}; - - if (index.vertex_index >= 0) - { - vertex.position = Vec3 {attrib.vertices[3 * index.vertex_index + 0], - attrib.vertices[3 * index.vertex_index + 1], - attrib.vertices[3 * index.vertex_index + 2]}; - - vertex.color = FColour {attrib.colors[3 * index.vertex_index + 0], - attrib.colors[3 * index.vertex_index + 1], - attrib.colors[3 * index.vertex_index + 2], - 1.f}; - } - - if (index.normal_index >= 0) - { - vertex.normal = Vec3 {attrib.normals[3 * index.normal_index + 0], - attrib.normals[3 * index.normal_index + 1], - attrib.normals[3 * index.normal_index + 2]}; - } - - if (index.texcoord_index >= 0) - { - vertex.uv = Vec2 {attrib.texcoords[2 * index.texcoord_index + 0], - attrib.texcoords[2 * index.texcoord_index + 1]}; - } - - if (uniqueVertices.count(vertex) == 0) - { - uniqueVertices[vertex] = static_cast(objVertices.size()); - objVertices.push_back(vertex); - } - objIndices.push_back(uniqueVertices[vertex]); - } - } - - Siege::StaticMeshData* staticMeshData = Siege::StaticMeshData::Create(objIndices, objVertices); - return staticMeshData; -} diff --git a/packer/types/WavefrontDataPacker.h b/packer/types/WavefrontDataPacker.h deleted file mode 100644 index bd69b3c5..00000000 --- a/packer/types/WavefrontDataPacker.h +++ /dev/null @@ -1,16 +0,0 @@ -// -// Copyright (c) 2020-present Jonathan Moallem (@J-Mo63) & Aryeh Zinn (@Raelr) -// -// This code is released under an unmodified zlib license. -// For conditions of distribution and use, please see: -// https://opensource.org/licenses/Zlib -// - -#ifndef SIEGE_ENGINE_WAVEFRONTDATAPACKER_H -#define SIEGE_ENGINE_WAVEFRONTDATAPACKER_H - -#include - -void* PackWavefrontFile(const Siege::String& filePath); - -#endif // SIEGE_ENGINE_WAVEFRONTDATAPACKER_H diff --git a/scripts/setup.ps1 b/scripts/setup.ps1 index b80063b4..c13b1323 100644 --- a/scripts/setup.ps1 +++ b/scripts/setup.ps1 @@ -9,24 +9,33 @@ param ( [switch] $Include_Validation_Layers ) -[string] $Root_Dir=(pwd) -[string] $Vulkan_Version= "vulkan-sdk-1.3.296.0" -[string] $Spirv_Version="vulkan-sdk-1.3.296.0" -[string] $Glslang_Version="vulkan-sdk-1.3.296.0" +# Dependency versions +[string] $Vulkan_Version= "vulkan-sdk-1.4.313" +[string] $Spirv_Version="vulkan-sdk-1.4.313" +[string] $Glslang_Version="vulkan-sdk-1.4.313" [string] $Robin_Hood_Hashing_Version="3.11.5" +[string] $FreeType_Version="VER-2-13-3" +[string] $LibPng_Version="v1.6.50" +[string] $Zlib_Version="v1.3.1" +[string] $Assimp_Version="v6.0.2" +[string] $Glfw_Version="3.4" + +# Build configurations [string] $Generator="MinGW Makefiles" -[string] $Vendor_Dir="$Root_Dir/vendor".Replace('\','/') +[string] $CMAKE_COMPILERS="-DCMAKE_C_COMPILER=`"gcc.exe`" -DCMAKE_CXX_COMPILER=`"g++.exe`"" +# Standard directories +[string] $Root_Dir=(pwd) +[string] $Vendor_Dir="$Root_Dir/vendor".Replace('\','/') [string] $Bin_Dir="$Root_Dir/bin".Replace('\','/') [string] $Build_Dir="examples/render/build" +# Vulkan directories [string] $Vulkan_Vendor_Dir="$Vendor_Dir/vulkan".Replace('\','/') [string] $Vulkan_Lib_Dir="$Vulkan_Vendor_Dir/lib".Replace('\','/') [string] $Vulkan_Include_Dir="$Vulkan_Vendor_Dir/include".Replace('\','/') [string] $Volk_Include_Dir="$Vulkan_Vendor_Dir/include/volk".Replace('\','/') -[string] $CMAKE_COMPILERS="-DCMAKE_C_COMPILER=`"gcc.exe`" -DCMAKE_CXX_COMPILER=`"g++.exe`"" - function Make-Dir { param ( [string] $Dir_Path ) if (!(Test-Path $Dir_Path)) { New-Item -Path $Dir_Path -ItemType directory } @@ -41,12 +50,12 @@ function Get-Files { function Update-Submodule { param ([string] $Submodule) - git submodule update --init --recursive --depth 1 $Vendor_Dir/$Submodule + git submodule update --init --recursive $Vendor_Dir/$Submodule } function Checkout-Tags { param([string] $Path=@(), [string] $Tag=@()) - git -C "$Path" fetch --all --tags --force ; git -C "$Path" checkout tags/"$Tag" + git -C "$Path" fetch --all --tags --force ; git -C "$Path" checkout "$Tag" } function Setup-Utest { @@ -59,22 +68,17 @@ function Setup-Zlib { Write-Output "Setting up zlib..." Write-Output "Cloning zlib..." Update-Submodule zlib + Checkout-Tags "$Vendor_Dir/zlib" $Zlib_Version Write-Output "Building zlib..." [string] $build_dir = "$Vendor_Dir/zlib/build" - Make-Dir $build_dir - - cmake ` - -G "$Generator" ` - "$Vendor_Dir/zlib" ` - $CMAKE_COMPILER ` + cmake -G "$Generator" "$Vendor_Dir/zlib" $CMAKE_COMPILER ` -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -S"$Vendor_Dir/zlib" ` + -S"$Vendor_Dir/zlib" ` -B"$build_dir" mingw32-make -C "$Build_Dir" install -j"$env:NUMBER_OF_PROCESSORS" - if(!(Test-Path "$build_dir/lib/libz.a")) {Rename-Item -Path "$build_dir/lib/libzlibstatic.a" -NewName "libz.a"} } @@ -82,22 +86,18 @@ function Setup-LibPng { Write-Output "Setting up libpng..." Write-Output "Cloning libpng..." Update-Submodule libpng + Checkout-Tags "$Vendor_Dir/libpng" $LibPng_Version Write-Output "Building libpng..." [string] $build_dir = "$Vendor_Dir/libpng/build" [string] $zlib_dir = "$Vendor_Dir/zlib/build" - Make-Dir $build_dir - - cmake ` - -G "$Generator" ` - "$Vendor_Dir/libpng" ` - $CMAKE_COMPILER ` - -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -DPNG_BUILD_ZLIB=ON ` - -DZLIB_INCLUDE_DIRS="$zlib_dir/include" ` - -DZLIB_LIBRARIES="$zlib_dir/lib/libz.a" ` - -S"$Vendor_Dir/libpng" ` + cmake -G "$Generator" "$Vendor_Dir/libpng" $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -DZLIB_HOME=$Vendor_Dir/zlib/build ` + -DZLIB_INCLUDE_DIR="$zlib_dir/include" ` + -DZLIB_LIBRARY="$zlib_dir/lib/libz.a" ` + -S"$Vendor_Dir/libpng" ` -B"$build_dir" mingw32-make -C "$Build_Dir" install -j"$env:NUMBER_OF_PROCESSORS" @@ -107,48 +107,131 @@ function Setup-FreeType { Write-Output "Setting up freetype..." Write-Output "Cloning freetype..." Update-Submodule freetype + Checkout-Tags "$Vendor_Dir/freetype" $FreeType_Version Write-Output "Building freetype..." [string] $build_dir = "$Vendor_Dir/freetype/build" [string] $zlib_build_dir = "$Vendor_Dir/zlib/build" [string] $libpng_build_dir = "$Vendor_Dir/libpng/build" - Make-Dir $build_dir + cmake -G "$Generator" $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -DFT_DISABLE_BROTLI=TRUE ` + -DFT_DISABLE_BZIP2=TRUE ` + -DFT_DISABLE_HARFBUZZ=TRUE ` + -DZLIB_LIBRARY="$zlib_build_dir/lib/libz.a" ` + -DZLIB_INCLUDE_DIR="$zlib_build_dir/include" ` + -DPNG_LIBRARY="$libpng_build_dir/lib/libpng.a" ` + -DPNG_PNG_INCLUDE_DIR="$libpng_build_dir/include" ` + -S"$Vendor_Dir"/freetype ` + -B"$build_dir" - cmake ` - -G "$Generator" ` - $CMAKE_COMPILER ` - -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -DFT_DISABLE_BROTLI=TRUE ` - -DFT_DISABLE_BZIP2=TRUE ` - -DFT_DISABLE_HARFBUZZ=TRUE ` - -DZLIB_LIBRARY="$zlib_build_dir/lib/libz.a" ` - -DZLIB_INCLUDE_DIR="$zlib_build_dir/include" ` - -DPNG_LIBRARY="$libpng_build_dir/lib/libpng.a" ` - -DPNG_PNG_INCLUDE_DIR="$libpng_build_dir/include" ` - -B"$build_dir" ` - -S"$Vendor_Dir"/freetype + mingw32-make -C "$build_dir" install -j"$env:NUMBER_OF_PROCESSORS" + Make-Dir "$Vendor_Dir/include/freetype" + Get-ChildItem "$Vendor_Dir/freetype/include" | Copy-Item -Destination "$Vendor_Dir/include/freetype" -Recurse +} - mingw32-make -C "$Build_Dir" install -j"$env:NUMBER_OF_PROCESSORS" +function Setup-Assimp { + Write-Output "Setting up assimp..." + Write-Output "Cloning assimp..." + Update-Submodule assimp + Checkout-Tags "$Vendor_Dir/assimp" $Assimp_Version - Make-Dir "$Vendor_Dir/include/freetype" + Write-Output "Building assimp..." + [string] $build_dir = "$Vendor_Dir/assimp/build" + [string] $zlib_build_dir = "$Vendor_Dir/zlib/build" + Make-Dir $build_dir + cmake -G "$Generator" $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -DBUILD_SHARED_LIBS=OFF ` + -DZLIB_FOUND=1 ` + -DZLIB_LIBRARIES="$Vendor_Dir/zlib/build/lib/libz.a" ` + -DZLIB_INCLUDE_DIR="$Vendor_Dir/zlib/build/include" ` + -DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT=OFF ` + -DASSIMP_BUILD_TESTS=OFF ` + -DASSIMP_INSTALL=OFF ` + -DASSIMP_BUILD_ZLIB=OFF ` + -DASSIMP_WARNINGS_AS_ERRORS=OFF ` + -S"$Vendor_Dir/assimp" ` + -B"$build_dir" - Get-ChildItem "$Vendor_Dir/freetype/include" | Copy-Item -Destination "$Vendor_Dir/include/freetype" -Recurse + mingw32-make -C "$build_dir" -j"$env:NUMBER_OF_PROCESSORS" } function Setup-Glfw { Write-Output "Setting up glfw..." Write-Output "Cloning glfw..." Update-Submodule glfw + Checkout-Tags "$Vendor_Dir/glfw" $Glfw_Version Write-Output "Building glfw..." [string] $build_dir = "$Vendor_Dir/glfw/build" - - cmake -G"$Generator" $CMAKE_COMPILER -DCMAKE_INSTALL_PREFIX="$build_dir" -B"$build_dir" -S"$Vendor_Dir/glfw" + Make-Dir $build_dir + cmake -G"$Generator" $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -S"$Vendor_Dir/glfw" ` + -B"$build_dir" mingw32-make -C "$build_dir" -j"$env:NUMBER_OF_PROCESSORS" } +function Setup-Vulkan-Headers { + Write-Output "Setting up Vulkan Headers..." + Write-Output "Cloning Vulkan Headers..." + Update-Submodule vulkan/Vulkan-Headers + Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-Headers" "$Vulkan_Version.0" + + Write-Output "Building Vulkan Headers..." + [string] $build_dir = "$Vulkan_Vendor_Dir/Vulkan-Headers/build" + Make-Dir $build_dir + cmake $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir/install" ` + -S"$Vulkan_Vendor_Dir/Vulkan-Headers" ` + -B"$build_dir" + + cmake --build "$build_dir" --target install + Make-Dir $Vulkan_Include_Dir + Get-ChildItem "$Vulkan_Vendor_Dir/Vulkan-Headers/build/install/include" | Copy-Item -Destination $Vulkan_Include_Dir -Recurse -Force +} + +function Setup-Spirv-Headers { + Write-Output "Setting up SPIRV Headers..." + Write-Output "Cloning SPIRV Headers..." + Update-Submodule vulkan/SPIRV-Headers + Checkout-Tags "$Vulkan_Vendor_Dir/SPIRV-Headers" "$Spirv_Version.0" + + Write-Output "Building SPIRV Headers..." + [string] $build_dir = "$Vulkan_Vendor_Dir/SPIRV-Headers/build" + Make-Dir $build_dir + cmake -G "$Generator" $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir/install" ` + -S"$Vulkan_Vendor_Dir/SPIRV-Headers" ` + -B"$build_dir" + + mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" +} + +function Setup-Spirv-Tools { + Write-Output "Setting up Spirv Tools..." + Write-Output "Cloning SPIRV Tools..." + Update-Submodule vulkan/SPIRV-Tools + Checkout-Tags "$Vulkan_Vendor_Dir/SPIRV-Tools" "$Spirv_Version.0" + + Write-Output "Building SPIRV Tools..." + [string] $build_dir = "$Vulkan_Vendor_Dir/SPIRV-Tools/build" + Make-Dir $build_dir + cmake -G "$Generator" $CMAKE_COMPILER ` + -DCMAKE_BUILD_TYPE=Release ` + -DSPIRV_SKIP_TESTS=ON ` + -DSPIRV_WERROR=OFF ` + -DSPIRV-Headers_SOURCE_DIR="$Vulkan_Vendor_Dir/SPIRV-Headers" ` + -DCMAKE_INSTALL_PREFIX="$build_dir/install" ` + -S"$Vulkan_Vendor_Dir/SPIRV-Tools" ` + -B"$build_dir" + + mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" +} + function Setup-Glslang { Write-Output "Setting up glslang..." Write-Output "Cloning glslang..." @@ -157,21 +240,18 @@ function Setup-Glslang { Write-Output "Building glslang..." [string] $build_dir = "$Vendor_Dir/glslang/build" - Make-Dir $build_dir - - cmake ` - -G "$Generator" ` - $CMAKE_COMPILER ` - -DBUILD_EXTERNAL=OFF ` + cmake -G "$Generator" $CMAKE_COMPILER ` -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -DCMAKE_BUILD_TYPE=Release ` ` - -DSPIRV-Tools-opt_INCLUDE_DIRS="$Vulkan_Vendor_Dir\SPIRV-Tools\build\install\include" ` - -DALLOW_EXTERNAL_SPIRV_TOOLS=1 ` - -S"$Vendor_Dir/glslang" ` + -DSPIRV-Tools-opt_DIR="$Vulkan_Vendor_Dir/SPIRV-Tools/build/install/lib/cmake/SPIRV-Tools-opt" ` + -DSPIRV-Tools_DIR="$Vulkan_Vendor_Dir/SPIRV-Tools/build/install/lib/cmake/SPIRV-Tools" ` + -DCMAKE_BUILD_TYPE=Release ` + -DENABLE_OPT=ON ` + -DALLOW_EXTERNAL_SPIRV_TOOLS=1 ` + -S"$Vendor_Dir/glslang" ` -B"$build_dir" - mingw32-make -C "$build_dir" install -j"$env:NUMBER_OF_PROCESSORS" + mingw32-make -C "$build_dir" -j"$env:NUMBER_OF_PROCESSORS" } function Setup-Volk { @@ -186,52 +266,23 @@ function Setup-Volk { Copy-Item -Path "$Vulkan_Vendor_Dir/volk/volk.c" -Destination $Volk_Include_Dir } -function Setup-Vulkan-Headers { - Write-Output "Setting up Vulkan Headers..." - Write-Output "Cloning Vulkan Headers..." - Update-Submodule vulkan/Vulkan-Headers - Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-Headers" $Vulkan_Version - - Write-Output "Building Vulkan Headers..." - [string] $build_dir = "$Vulkan_Vendor_Dir/Vulkan-Headers/build" - - Make-Dir $build_dir - - cmake ` - $CMAKE_COMPILER ` - -DCMAKE_INSTALL_PREFIX="$build_dir/install" ` - -B"$build_dir" ` - -S"$Vulkan_Vendor_Dir/Vulkan-Headers" - - cmake --build "$build_dir" --target install - - Make-Dir $Vulkan_Include_Dir - - Get-ChildItem "$Vulkan_Vendor_Dir/Vulkan-Headers/build/install/include" | Copy-Item -Destination $Vulkan_Include_Dir -Recurse -Force -} - function Setup-Vulkan-Loader { Write-Output "Setting up Vulkan Loader..." Write-Output "Cloning Vulkan Loader..." Update-Submodule vulkan/Vulkan-Loader - - Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-Loader" $Vulkan_Version + Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-Loader" "$Vulkan_Version.0" Write-Output "Building Vulkan Loader..." [string] $build_dir = "$Vulkan_Vendor_Dir/Vulkan-Loader/build" - - cmake ` - $CMAKE_COMPILER ` - -G "$Generator" ` - -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Headers/build/install" ` - -S"$Vulkan_Vendor_Dir/Vulkan-Loader" ` + Make-Dir $build_dir + cmake $CMAKE_COMPILER -G "$Generator" ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Headers/build/install" ` + -S"$Vulkan_Vendor_Dir/Vulkan-Loader" ` -B"$build_dir" cmake --build "$build_dir" --parallel $env:NUMBER_OF_PROCESSORS - Make-Dir $Vulkan_Lib_Dir - Copy-Item -Path "$build_dir/loader/*" -Destination "$Vulkan_Lib_Dir" -Include "*.dll" -Recurse } @@ -243,119 +294,60 @@ function Setup-Robin-Hood-Hashing { Write-Output "Building Robin Hood Hashing..." [string] $build_dir = "$Vulkan_Vendor_Dir/robin-hood-hashing/build" - - cmake ` - -G "$Generator" "$Vulkan_Vendor_Dir"/robin-hood-hashing ` - $CMAKE_COMPILER ` - -DCMAKE_INSTALL_PREFIX="$build_dir"/install ` - -DRH_STANDALONE_PROJECT=OFF ` - -DCMAKE_BUILD_TYPE=Release ` - -S"$Vulkan_Vendor_Dir"/robin-hood-hashing ` - -B"$build_dir" - - mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" -} - -function Setup-Spirv-Headers { - Write-Output "Setting up SPIRV Headers..." - Write-Output "Cloning SPIRV Headers..." - Update-Submodule vulkan/SPIRV-Headers - - Checkout-Tags "$Vulkan_Vendor_Dir/SPIRV-Headers" "$Spirv_Version" - - Write-Output "Building SPIRV Headers..." - [string] $build_dir = "$Vulkan_Vendor_Dir/SPIRV-Headers/build" - Make-Dir $build_dir - - cmake ` - $CMAKE_COMPILER ` - -DCMAKE_BUILD_TYPE=Release ` - -DCMAKE_INSTALL_PREFIX="$build_dir/install" ` - -S"$Vulkan_Vendor_Dir/SPIRV-Headers" ` + cmake -G "$Generator" "$Vulkan_Vendor_Dir"/robin-hood-hashing $CMAKE_COMPILER ` + -DCMAKE_INSTALL_PREFIX="$build_dir"/install ` + -DRH_STANDALONE_PROJECT=OFF ` + -DCMAKE_BUILD_TYPE=Release ` + -S"$Vulkan_Vendor_Dir"/robin-hood-hashing ` -B"$build_dir" - cmake --build "$build_dir" --target install --config Release --parallel $env:NUMBER_OF_PROCESSORS -} - -function Setup-Spirv-Tools { - Write-Output "Setting up Spirv Tools..." - Write-Output "Cloning SPIRV Tools..." - Update-Submodule vulkan/SPIRV-Tools - - Checkout-Tags "$Vulkan_Vendor_Dir/SPIRV-Tools" "$Spirv_Version" - - Write-Output "Building SPIRV Tools..." - [string] $build_dir = "$Vulkan_Vendor_Dir/SPIRV-Tools/build" - - Make-Dir $build_dir - - cmake ` - $CMAKE_COMPILER ` - -DCMAKE_BUILD_TYPE=Release ` - -DSPIRV_SKIP_TESTS=ON ` - -DSPIRV_WERROR=OFF ` - -DSPIRV-Headers_SOURCE_DIR="$Vulkan_Vendor_Dir\\SPIRV-Headers" ` - -DCMAKE_INSTALL_PREFIX="$build_dir\\install" ` - -S"$Vulkan_Vendor_Dir\\SPIRV-Tools" ` - -B"$build_dir" - - cmake --build $build_dir --parallel $env:NUMBER_OF_PROCESSORS --target install --config Release + mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" } function Setup-Vulkan-Utility-Libraries { Write-Output "Setting up Vulkan Utility Libraries..." Write-Output "Cloning Vulkan Utility Libraries..." - Update-Submodule vulkan\Vulkan-Utility-Libraries - - Checkout-Tags "$Vulkan_Vendor_Dir\Vulkan-Utility-Libraries" "$Vulkan_Version" + Checkout-Tags "$Vulkan_Vendor_Dir\Vulkan-Utility-Libraries" "$Vulkan_Version.0" Write-Output "Building Vulkan Validation Layers..." [string] $build_dir = "$Vulkan_Vendor_Dir\Vulkan-Utility-Libraries/build" + cmake -G "$Generator" $CMAKE_COMPILER ` + -DCMAKE_BUILD_TYPE=Release ` + -DUPDATE_DEPS=OFF ` + -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir\Vulkan-Headers\build\install" ` + -DCMAKE_INSTALL_PREFIX="$build_dir\install" ` + -S "${Vulkan_Vendor_Dir}\Vulkan-Utility-Libraries" ` + -B "$build_dir" - cmake ` - $CMAKE_COMPILER ` - -S "${Vulkan_Vendor_Dir}\Vulkan-Utility-Libraries" ` - -B "$build_dir" ` - -DCMAKE_BUILD_TYPE=Release ` - -DUPDATE_DEPS=OFF ` - -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir\Vulkan-Headers\build\install" ` - -DCMAKE_INSTALL_PREFIX="$build_dir\install" - - cmake --build $build_dir --target install --config Release --parallel $env:NUMBER_OF_PROCESSORS + mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" } function Setup-Validation-Layers { Write-Output "Setting up Vulkan Validation Layers..." Write-Output "Cloning Vulkan ValidationLayers..." Update-Submodule vulkan/Vulkan-ValidationLayers - - Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-ValidationLayers" "$Vulkan_Version" + Checkout-Tags "$Vulkan_Vendor_Dir/Vulkan-ValidationLayers" "$Vulkan_Version.0" Write-Output "Building Vulkan Validation Layers..." [string] $build_dir = "$Vulkan_Vendor_Dir/Vulkan-ValidationLayers/build" - Make-Dir $build_dir - - cmake ` - $CMAKE_COMPILER ` - -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Headers/build/install" ` - -DGLSLANG_INSTALL_DIR="$Vulkan_Vendor_Dir/glslang/build" ` - -DSPIRV_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/SPIRV-Headers/build/install" ` - -DSPIRV_TOOLS_INSTALL_DIR="$Vulkan_Vendor_Dir/SPIRV-Tools/build/install" ` - -DROBIN_HOOD_HASHING_INSTALL_DIR="$Vulkan_Vendor_Dir/robin-hood-hashing/build/install" ` - -DVULKAN_UTILITY_LIBRARIES_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Utility-Libraries/build/install" ` - -DCMAKE_INSTALL_PREFIX="$build_dir" ` - -DBUILD_TESTS=OFF ` --S"$Vulkan_Vendor_Dir/Vulkan-ValidationLayers" ` + cmake -G "$Generator" $CMAKE_COMPILER ` + -DVULKAN_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Headers/build/install" ` + -DGLSLANG_INSTALL_DIR="$Vulkan_Vendor_Dir/glslang/build" ` + -DSPIRV_HEADERS_INSTALL_DIR="$Vulkan_Vendor_Dir/SPIRV-Headers/build/install" ` + -DSPIRV_TOOLS_INSTALL_DIR="$Vulkan_Vendor_Dir/SPIRV-Tools/build/install" ` + -DROBIN_HOOD_HASHING_INSTALL_DIR="$Vulkan_Vendor_Dir/robin-hood-hashing/build/install" ` + -DVULKAN_UTILITY_LIBRARIES_INSTALL_DIR="$Vulkan_Vendor_Dir/Vulkan-Utility-Libraries/build/install" ` + -DCMAKE_INSTALL_PREFIX="$build_dir" ` + -DBUILD_TESTS=OFF ` + -S"$Vulkan_Vendor_Dir/Vulkan-ValidationLayers" ` -B"$build_dir" - cmake --build $build_dir --parallel $env:NUMBER_OF_PROCESSORS --target install --config Release - + mingw32-make -C $build_dir install -j"$env:NUMBER_OF_PROCESSORS" Make-Dir "$Vulkan_Lib_Dir/explicit_layer.d" - Copy-Item -Path "$build_dir/bin/*" -Destination "$Vulkan_Lib_Dir/explicit_layer.d" -Include "*.json" -Recurse Copy-Item -Path "$build_dir/bin/*" -Destination "$Vulkan_Lib_Dir/explicit_layer.d" -Include "*.dll" -Recurse } @@ -370,6 +362,7 @@ Setup-Utest Setup-Zlib Setup-LibPng Setup-FreeType +Setup-Assimp Setup-Glfw Setup-Vulkan-Headers Setup-Spirv-Headers diff --git a/scripts/setup.sh b/scripts/setup.sh index 4f1fd1a7..efd6903f 100755 --- a/scripts/setup.sh +++ b/scripts/setup.sh @@ -7,10 +7,32 @@ # For conditions of distribution and use, please see: # https://opensource.org/licenses/Zlib -# Find repo root +# Dependency versions +VULKAN_VERSION="vulkan-sdk-1.3.296.0" +SPIRV_VERSION="vulkan-sdk-1.3.296.0" +GLSLANG_VERSION="vulkan-sdk-1.3.296.0" +ROBIN_HOOD_HASHING_VERSION="3.11.5" +MOLTENVK_VERSION="v1.2.11" +FREETYPE_VERSION="VER-2-13-3" +LIBPNG_VERSION="v1.6.50" +ZLIB_VERSION="v1.3.1" +ASSIMP_VERSION="v6.0.2" +GLFW_VERSION="3.4" + +# Build configurations +GENERATOR="Unix Makefiles" + +# Standard directories SCRIPT_DIR=$(dirname "${BASH_SOURCE[0]}") -cd "$SCRIPT_DIR/.." || exit +cd "$SCRIPT_DIR/.." || exit # Find and navigate to repo root ROOT_DIR=$(pwd -P) +VENDOR_DIR="${ROOT_DIR}/vendor" + +# Vulkan directories +VULKAN_VENDOR_DIR="${VENDOR_DIR}/vulkan" +VULKAN_LIB_DIR="${VULKAN_VENDOR_DIR}/lib" +VULKAN_INCLUDE_DIR="${VULKAN_VENDOR_DIR}/include" +VOLK_INCLUDE_DIR="${VULKAN_VENDOR_DIR}/include/volk" # Find the current OS if [ "$(uname)" == "Darwin" ]; then @@ -25,22 +47,7 @@ else LOADER_INSTALL_DIR=build/share/vulkan/explicit_layer.d fi -# Set setup details -VULKAN_VERSION="vulkan-sdk-1.3.296.0" -SPIRV_VERSION="vulkan-sdk-1.3.296.0" -GLSLANG_VERSION="vulkan-sdk-1.3.296.0" -ROBIN_HOOD_HASHING_VERSION="3.11.5" -MOLTENVK_VERSION="v1.2.11" -GENERATOR="Unix Makefiles" -VENDOR_DIR="${ROOT_DIR}/vendor" - -# Vulkan dependency variables -VULKAN_VENDOR_DIR="${VENDOR_DIR}/vulkan" -VULKAN_LIB_DIR="${VULKAN_VENDOR_DIR}/lib" -VULKAN_INCLUDE_DIR="${VULKAN_VENDOR_DIR}/include" -VOLK_INCLUDE_DIR="${VULKAN_VENDOR_DIR}/include/volk" - -update_submodules() { +update_submodule() { git submodule update --init --recursive --depth 1 "${VENDOR_DIR}"/"$1" } @@ -51,53 +58,196 @@ checkout_tags() { setup_utest() { echo "Setting up utest..." echo "Cloning utest..." - update_submodules utest.h + update_submodule utest.h +} + +setup_zlib() { + echo "Setting up zlib..." + echo "Cloning zlib..." + update_submodule zlib + checkout_tags "${VENDOR_DIR}"/zlib ${ZLIB_VERSION} + + echo "Building zlib..." + local BUILD_DIR="${VENDOR_DIR}"/zlib/build + mkdir -p "${BUILD_DIR}" + (cd "${VENDOR_DIR}"/zlib && ./configure --prefix="${BUILD_DIR}" --static) + make -f "${VENDOR_DIR}"/zlib/Makefile -C "${VENDOR_DIR}"/zlib install prefix="${BUILD_DIR}" -j"${NUMBER_OF_PROCESSORS}" +} + +setup_libpng() { + echo "Setting up libpng..." + echo "Cloning libpng..." + update_submodule libpng + checkout_tags "${VENDOR_DIR}"/libpng ${LIBPNG_VERSION} + + echo "Building libpng..." + local BUILD_DIR="${VENDOR_DIR}"/libpng/build + local ZLIB_BUILD_DIR="${VENDOR_DIR}"/zlib/build + mkdir -p "${BUILD_DIR}" + cmake "${VENDOR_DIR}"/libpng \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ + -DZLIB_INCLUDE_DIRS="${ZLIB_BUILD_DIR}"/include \ + -DZLIB_LIBRARIES="${ZLIB_BUILD_DIR}"/lib/libz.a \ + -S "${VENDOR_DIR}"/libpng \ + -B"${BUILD_DIR}" + make -C "${BUILD_DIR}" install -j"${NUMBER_OF_PROCESSORS}" +} + +setup_freetype() { + echo "Setting up freetype..." + echo "Cloning freetype..." + update_submodule freetype + checkout_tags "${VENDOR_DIR}"/freetype ${FREETYPE_VERSION} + + echo "Building freetype..." + local BUILD_DIR="${VENDOR_DIR}"/freetype/build + local ZLIB_BUILD_DIR="${VENDOR_DIR}"/zlib/build + local LIBPNG_BUILD_DIR="${VENDOR_DIR}"/libpng/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ + -DFT_DISABLE_BROTLI=TRUE \ + -DFT_DISABLE_BZIP2=TRUE \ + -DFT_DISABLE_HARFBUZZ=TRUE \ + -DZLIB_LIBRARY="${ZLIB_BUILD_DIR}"/lib/libz.a \ + -DZLIB_INCLUDE_DIR="${ZLIB_BUILD_DIR}"/include \ + -DPNG_LIBRARY="${LIBPNG_BUILD_DIR}"/lib/libpng.a \ + -DPNG_PNG_INCLUDE_DIR="${LIBPNG_BUILD_DIR}"/include \ + -S"${VENDOR_DIR}"/freetype \ + -B"${BUILD_DIR}" + + make -C "${BUILD_DIR}" -j"${NUMBER_OF_PROCESSORS}" + + mkdir -p "${VENDOR_DIR}"/include/freetype + cp -R "${VENDOR_DIR}"/freetype/include/** "${VENDOR_DIR}"/include/freetype +} + +setup_assimp() { + echo "Setting up assimp..." + echo "Cloning assimp..." + update_submodule assimp + checkout_tags "${VENDOR_DIR}"/assimp ${ASSIMP_VERSION} + + echo "Building assimp..." + local BUILD_DIR="${VENDOR_DIR}"/assimp/build + mkdir -p "${BUILD_DIR}" + cmake "${VENDOR_DIR}"/assimp \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ + -DBUILD_SHARED_LIBS=OFF \ + -DZLIB_FOUND=1 \ + -DZLIB_LIBRARIES="${ZLIB_BUILD_DIR}"/lib/libz.a \ + -DZLIB_INCLUDE_DIR="${ZLIB_BUILD_DIR}"/include \ + -DASSIMP_BUILD_ALL_EXPORTERS_BY_DEFAULT=OFF \ + -DASSIMP_BUILD_TESTS=OFF \ + -DASSIMP_INSTALL=OFF \ + -DASSIMP_BUILD_ZLIB=OFF \ + -S "${VENDOR_DIR}"/assimp \ + -B"${BUILD_DIR}" + make -C "${BUILD_DIR}" -j"${NUMBER_OF_PROCESSORS}" } setup_glfw() { echo "Setting up glfw..." echo "Cloning glfw..." - update_submodules glfw + update_submodule glfw + checkout_tags "${VENDOR_DIR}"/glfw "$GLFW_VERSION" + echo "Building glfw..." local BUILD_DIR="${VENDOR_DIR}"/glfw/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ + -S"${VENDOR_DIR}"/glfw \ + -B"${BUILD_DIR}" - echo "Building glfw..." - cmake -G "${GENERATOR}" -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" -B"${BUILD_DIR}" -S"${VENDOR_DIR}"/glfw make -C "${BUILD_DIR}" -j"${NUMBER_OF_PROCESSORS}" } +setup_vulkan_headers() { + echo "Setting up Vulkan Headers..." + echo "Cloning Vulkan Headers..." + update_submodule vulkan/Vulkan-Headers + checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-Headers "$VULKAN_VERSION" + + echo "Building Vulkan Headers..." + local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ + -S"${VULKAN_VENDOR_DIR}"/Vulkan-Headers \ + -B"${BUILD_DIR}" + cmake --build "${BUILD_DIR}" --target install + mkdir -p "${VULKAN_INCLUDE_DIR}" + cp -r "${BUILD_DIR}"/install/include/** "${VULKAN_INCLUDE_DIR}" +} + +setup_spirv_headers() { + echo "Setting up SPIRV Headers..." + echo "Cloning SPIRV Headers..." + update_submodule vulkan/SPIRV-Headers + + checkout_tags "${VULKAN_VENDOR_DIR}"/SPIRV-Headers "${SPIRV_VERSION}" + + echo "Building SPIRV Headers..." + local BUILD_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Headers/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ + -S"${VULKAN_VENDOR_DIR}"/SPIRV-Headers \ + -B"${BUILD_DIR}" + cmake --build "${BUILD_DIR}" --target install --config Release +} + +setup_spirv_tools() { + echo "Setting up SPIRV Tools..." + echo "Cloning SPIRV Tools..." + update_submodule vulkan/SPIRV-Tools + checkout_tags "${VULKAN_VENDOR_DIR}"/SPIRV-Tools "$SPIRV_VERSION" + + echo "Building SPIRV Tools..." + local BUILD_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Tools/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DSPIRV_SKIP_TESTS=ON \ + -DSPIRV_WERROR=OFF \ + -DSPIRV-Headers_SOURCE_DIR="${VULKAN_VENDOR_DIR}/SPIRV-Headers" \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ + -S"${VULKAN_VENDOR_DIR}"/SPIRV-Tools \ + -B"${BUILD_DIR}" + cmake --build "${BUILD_DIR}" --target install --config Release -j"${NUMBER_OF_PROCESSORS}" + + ln -sfn "${VULKAN_VENDOR_DIR}"/SPIRV-Headers "${VULKAN_VENDOR_DIR}"/SPIRV-Tools/external/spirv-headers +} + setup_glslang() { echo "Setting up glslang..." echo "Cloning glslang..." - update_submodules glslang + update_submodule glslang checkout_tags "${VENDOR_DIR}"/glslang "$GLSLANG_VERSION" echo "Building glslang..." - mkdir -p "${VENDOR_DIR}"/glslang/build - cmake \ - -DCMAKE_INSTALL_PREFIX="${VENDOR_DIR}"/glslang/build \ - -G "${GENERATOR}" -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="${VENDOR_DIR}"/glslang/build/install \ + local BUILD_DIR="${VENDOR_DIR}"/glslang/build + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ -DALLOW_EXTERNAL_SPIRV_TOOLS=1 \ -DSPIRV-Tools-opt_INCLUDE_DIRS="${VULKAN_VENDOR_DIR}"/SPIRV-Tools/build/install/include \ -S"${VENDOR_DIR}"/glslang \ - -B"${VENDOR_DIR}"/glslang/build + -B"${BUILD_DIR}" ln -sfn "${VULKAN_VENDOR_DIR}"/SPIRV-Tools "${VENDOR_DIR}"/glslang/External/spirv-tools - cmake --build "${VENDOR_DIR}"/glslang/build --target install -- -j"${NUMBER_OF_PROCESSORS}" -} - -setup_glm() { - echo "Setting up glm..." - echo "Cloning glm..." - update_submodules glm + cmake --build "${BUILD_DIR}" --target install -- -j"${NUMBER_OF_PROCESSORS}" } setup_volk() { echo "Setting up volk..." echo "Cloning volk..." - update_submodules vulkan/volk + update_submodule vulkan/volk echo "Building volk..." mkdir -p "${VOLK_INCLUDE_DIR}" @@ -105,31 +255,16 @@ setup_volk() { cp "${VULKAN_VENDOR_DIR}"/volk/volk.c "${VOLK_INCLUDE_DIR}" } -setup_vulkan_headers() { - echo "Setting up Vulkan Headers..." - echo "Cloning Vulkan Headers..." - update_submodules vulkan/Vulkan-Headers - checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-Headers "$VULKAN_VERSION" - - echo "Building Vulkan Headers..." - local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build - mkdir -p "${BUILD_DIR}" - cmake -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install -G "${GENERATOR}" -B"${BUILD_DIR}" -S"${VULKAN_VENDOR_DIR}"/Vulkan-Headers - cmake --build "${BUILD_DIR}" --target install - mkdir -p "${VULKAN_INCLUDE_DIR}" - cp -r "${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install/include/** "${VULKAN_INCLUDE_DIR}" -} - setup_vulkan_loader() { echo "Setting up Vulkan Loader..." echo "Cloning Vulkan Loader..." - update_submodules vulkan/Vulkan-Loader + update_submodule vulkan/Vulkan-Loader checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-Loader "$VULKAN_VERSION" echo "Building Vulkan Loader..." local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Loader/build mkdir -p "${BUILD_DIR}" - cmake \ + cmake -G "${GENERATOR}" \ -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ -DVULKAN_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install \ -S"${VULKAN_VENDOR_DIR}"/Vulkan-Loader \ @@ -142,7 +277,7 @@ setup_vulkan_loader() { setup_moltenVk() { echo "Setting up MoltenVk..." echo "Cloning MoltenVk..." - update_submodules vulkan/MoltenVK + update_submodule vulkan/MoltenVK checkout_tags "${VULKAN_VENDOR_DIR}"/MoltenVK ${MOLTENVK_VERSION} echo "Building MoltenVk..." @@ -156,13 +291,13 @@ setup_moltenVk() { setup_robin_hood_hashing() { echo "Setting up Robin Hood Hashing..." echo "Cloning Robin Hood Hashing..." - update_submodules vulkan/robin-hood-hashing + update_submodule vulkan/robin-hood-hashing checkout_tags "${VULKAN_VENDOR_DIR}"/robin-hood-hashing ${ROBIN_HOOD_HASHING_VERSION} echo "Building Robin Hood Hashing..." local BUILD_DIR="${VULKAN_VENDOR_DIR}"/robin-hood-hashing/build - cmake \ - -G "${GENERATOR}" "${VULKAN_VENDOR_DIR}"/robin-hood-hashing \ + mkdir -p "${BUILD_DIR}" + cmake -G "${GENERATOR}" "${VULKAN_VENDOR_DIR}"/robin-hood-hashing \ -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ -DRH_STANDALONE_PROJECT=OFF \ -DCMAKE_BUILD_TYPE=Release \ @@ -171,128 +306,66 @@ setup_robin_hood_hashing() { cmake --build "${BUILD_DIR}" --target install -- -j"${NUMBER_OF_PROCESSORS}" } -setup_spirv_headers() { - echo "Setting up SPIRV Headers..." - echo "Cloning SPIRV Headers..." - update_submodules vulkan/SPIRV-Headers - - checkout_tags "${VULKAN_VENDOR_DIR}"/SPIRV-Headers "${SPIRV_VERSION}" - - echo "Building SPIRV Headers..." - local BUILD_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Headers/build - mkdir -p "${BUILD_DIR}" - cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install -S"${VULKAN_VENDOR_DIR}"/SPIRV-Headers -B"${BUILD_DIR}" - cmake --build "${BUILD_DIR}" --target install --config Release -} - -setup_spirv_tools() { - echo "Setting up SPIRV Tools..." - echo "Cloning SPIRV Tools..." - update_submodules vulkan/SPIRV-Tools - checkout_tags "${VULKAN_VENDOR_DIR}"/SPIRV-Tools "$SPIRV_VERSION" +setup_vulkan_utility_libraries() { + echo "Setting up Vulkan Utility Libraries..." + echo "Cloning Vulkan Utility Libraries..." + update_submodule vulkan/Vulkan-Utility-Libraries + checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries "$VULKAN_VERSION" - echo "Building SPIRV Tools..." - local BUILD_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Tools/build + echo "Building Vulkan Utility Libraries..." + local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries/build mkdir -p "${BUILD_DIR}" - cmake -DCMAKE_BUILD_TYPE=Release -DSPIRV_SKIP_TESTS=ON -DSPIRV_WERROR=OFF -DSPIRV-Headers_SOURCE_DIR="${VULKAN_VENDOR_DIR}/SPIRV-Headers" -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install -S"${VULKAN_VENDOR_DIR}"/SPIRV-Tools -B"${BUILD_DIR}" + cmake -G "${GENERATOR}" \ + -DCMAKE_BUILD_TYPE=Release \ + -DUPDATE_DEPS=OFF \ + -DVULKAN_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install \ + -S"${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries \ + -B"${BUILD_DIR}" cmake --build "${BUILD_DIR}" --target install --config Release -j"${NUMBER_OF_PROCESSORS}" - - ln -sfn "${VULKAN_VENDOR_DIR}"/SPIRV-Headers "${VULKAN_VENDOR_DIR}"/SPIRV-Tools/external/spirv-headers -} - -setup_vulkan_utility_libraries() { - echo "Setting up Vulkan Utility Libraries..." - echo "Cloning Vulkan Utility Libraries..." - - update_submodules vulkan/Vulkan-Utility-Libraries - checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries "$VULKAN_VERSION" - - echo "Building Vulkan Utility Libraries..." - local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries/build - mkdir -p "${BUILD_DIR}" - - cmake -S "${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries -B "${BUILD_DIR}" -DCMAKE_BUILD_TYPE=Release -DUPDATE_DEPS=OFF -DVULKAN_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"/install - cmake --build "${BUILD_DIR}" --target install --config Release -j"${NUMBER_OF_PROCESSORS}" } setup_validation_layers() { echo "Setting up Vulkan Validation Layers..." echo "Cloning Vulkan Validation Layers..." - update_submodules vulkan/Vulkan-ValidationLayers + update_submodule vulkan/Vulkan-ValidationLayers checkout_tags "${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers "$VULKAN_VERSION" echo "Building Vulkan Validation Layers..." local BUILD_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers/build mkdir -p "${BUILD_DIR}" - cmake \ - -DVULKAN_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install \ - -DGLSLANG_INSTALL_DIR="${VENDOR_DIR}"/glslang/build/install \ - -DSPIRV_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Headers/build/install \ - -DSPIRV_TOOLS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Tools/build/install \ - -DROBIN_HOOD_HASHING_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/robin-hood-hashing/build/install \ - -DVULKAN_UTILITY_LIBRARIES_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries/build/install \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}" \ - -DBUILD_TESTS=OFF \ - -S"${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers \ + cmake G "${GENERATOR}" \ + -DVULKAN_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Headers/build/install \ + -DGLSLANG_INSTALL_DIR="${VENDOR_DIR}"/glslang/build/install \ + -DSPIRV_HEADERS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Headers/build/install \ + -DSPIRV_TOOLS_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/SPIRV-Tools/build/install \ + -DROBIN_HOOD_HASHING_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/robin-hood-hashing/build/install \ + -DVULKAN_UTILITY_LIBRARIES_INSTALL_DIR="${VULKAN_VENDOR_DIR}"/Vulkan-Utility-Libraries/build/install \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX="${BUILD_DIR}"\ + -DBUILD_TESTS=OFF \ + -S"${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers \ -B"${BUILD_DIR}" cmake --build "${BUILD_DIR}" --config Release --target install -j"${NUMBER_OF_PROCESSORS}" mkdir -p "${VULKAN_LIB_DIR}"/explicit_layer.d cp "${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers/"${LOADER_INSTALL_DIR}"/**.json "${VULKAN_LIB_DIR}"/explicit_layer.d - cp "${VULKAN_VENDOR_DIR}"/Vulkan-ValidationLayers/build/layers/**${LIB_SUFFIX} "${VULKAN_LIB_DIR}"/explicit_layer.d -} - -setup_zlib() { - echo "Setting up zlib..." - echo "Cloning zlib..." - update_submodules zlib - - echo "Building zlib..." - mkdir -p "${VENDOR_DIR}"/zlib/build - (cd "${VENDOR_DIR}"/zlib && ./configure --prefix="${VENDOR_DIR}"/zlib/build --static) - make -f "${VENDOR_DIR}"/zlib/Makefile -C "${VENDOR_DIR}"/zlib install prefix="${VENDOR_DIR}"/zlib/build -j"${NUMBER_OF_PROCESSORS}" -} - -setup_libpng() { - echo "Setting up libpng..." - echo "Cloning libpng..." - update_submodules libpng - - echo "Building libpng..." - mkdir -p "${VENDOR_DIR}"/libpng/build - cmake "${VENDOR_DIR}"/libpng -DCMAKE_INSTALL_PREFIX="${VENDOR_DIR}"/libpng/build -S "${VENDOR_DIR}"/libpng -B"${VENDOR_DIR}"/libpng/build - make -C "${VENDOR_DIR}"/libpng/build install -j"${NUMBER_OF_PROCESSORS}" -} - -setup_freetype() { - echo "Setting up freetype..." - echo "Cloning freetype..." - update_submodules freetype - - echo "Building freetype..." - local BUILD_DIR="${VULKAN_DIR}"/freetype - mkdir -p "${BUILD_DIR}" - cmake -G "${GENERATOR}" -DFT_DISABLE_BROTLI=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -B"${VENDOR_DIR}"/freetype/build -S"${VENDOR_DIR}"/freetype - make -C "${VENDOR_DIR}"/freetype/build -j"${NUMBER_OF_PROCESSORS}" - - mkdir -p "${VENDOR_DIR}"/include/freetype - cp -R "${VENDOR_DIR}"/freetype/include/** "${VENDOR_DIR}"/include/freetype + cp "${BUILD_DIR}"/layers/**${LIB_SUFFIX} "${VULKAN_LIB_DIR}"/explicit_layer.d } echo "OS detected: ${OS}" echo "Setting up dependencies..." setup_utest +setup_zlib +setup_libpng +setup_freetype +setup_assimp setup_glfw +setup_vulkan_headers setup_spirv_headers setup_spirv_tools setup_glslang -setup_glm setup_volk -setup_vulkan_headers -setup_zlib -setup_libpng -setup_freetype setup_vulkan_loader if [[ "${OS}" == "macos" ]]; then diff --git a/tests/Makefile b/tests/Makefile index daf75414..37fd3930 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -9,14 +9,14 @@ include $(makeDir)/Functions.mk include $(makeDir)/Platform.mk # Set source build vars -testSrcDir := . +testSrcDir := ./ testBinDir := $(binDir)/tests testSources := $(call rwildcard,$(testSrcDir)/,*.cpp) testObjects := $(call findobjs,$(testSrcDir),$(testBinDir),$(testSources)) testDepends := $(patsubst %.o, %.d, $(call rwildcard,$(testBinDir)/,*.o)) testBuildDir := $(testBinDir)/build -testAssets := $(patsubst ./%,%, $(call rwildcard,$(testSrcDir),*.obj)) +testAssets := $(patsubst ./%,%, $(call rwildcard,$(testSrcDir),*.sm)) testAssets += $(patsubst ./%,%, $(call rwildcard,$(testSrcDir),*.png)) testAssets += $(patsubst ./%,%, $(call rwildcard,$(testSrcDir),*.ttf)) testAssets += $(patsubst ./%,%, $(call rwildcard,$(testSrcDir),*.scene)) @@ -49,6 +49,6 @@ $(utestIncludeDir): # Copy the assets directory to the build directory, and pack them pack-assets: - $(call MKDIR,$(call platformpth,$(testBuildDir)/data)) - $(call COPY,$(testSrcDir)/data,$(testBuildDir)/data,$(RWCARDGLOB)) + $(call MKDIR,$(call platformpth,$(testBuildDir)/assets)) + $(call COPY,$(testSrcDir)/assets,$(testBuildDir)/assets,$(RWCARDGLOB)) $(packerApp) $(testBuildDir)/app.pck $(testBuildDir) $(testAssets) diff --git a/tests/data/PublicPixel.ttf b/tests/assets/PublicPixel.ttf similarity index 100% rename from tests/data/PublicPixel.ttf rename to tests/assets/PublicPixel.ttf diff --git a/tests/data/cappy.png b/tests/assets/cappy.png similarity index 100% rename from tests/data/cappy.png rename to tests/assets/cappy.png diff --git a/tests/data/cube.obj b/tests/assets/cube.obj similarity index 100% rename from tests/data/cube.obj rename to tests/assets/cube.obj diff --git a/tests/assets/cube.sm b/tests/assets/cube.sm new file mode 100644 index 00000000..98a201e7 --- /dev/null +++ b/tests/assets/cube.sm @@ -0,0 +1,3 @@ +SOURCE_PATH:assets/cube.obj; +MATERIAL_PATH:assets/cube.mat; +NODE_PATH:/; \ No newline at end of file diff --git a/tests/data/garbage.scene/TestEntity.1.entity b/tests/assets/garbage.scene/TestEntity.1.entity similarity index 100% rename from tests/data/garbage.scene/TestEntity.1.entity rename to tests/assets/garbage.scene/TestEntity.1.entity diff --git a/tests/data/nopackfile/.gitkeep b/tests/assets/nopackfile/.gitkeep similarity index 100% rename from tests/data/nopackfile/.gitkeep rename to tests/assets/nopackfile/.gitkeep diff --git a/tests/data/scene2.scene/TestEntity.1.entity b/tests/assets/scene1.scene/TestEntity.1.entity similarity index 65% rename from tests/data/scene2.scene/TestEntity.1.entity rename to tests/assets/scene1.scene/TestEntity.1.entity index 866f5f48..1b01b0bc 100644 --- a/tests/data/scene2.scene/TestEntity.1.entity +++ b/tests/assets/scene1.scene/TestEntity.1.entity @@ -1,4 +1,5 @@ -TestEntity; +TYPE:TestEntity; POSITION:0.000000,0.000000,0.000000; ROTATION:0.000000; -Z-INDEX:0; \ No newline at end of file +Z_INDEX:0; + diff --git a/tests/data/scene1.scene/TestEntity.2.entity b/tests/assets/scene1.scene/TestEntity.2.entity similarity index 66% rename from tests/data/scene1.scene/TestEntity.2.entity rename to tests/assets/scene1.scene/TestEntity.2.entity index 96ed7fba..cf363b28 100644 --- a/tests/data/scene1.scene/TestEntity.2.entity +++ b/tests/assets/scene1.scene/TestEntity.2.entity @@ -1,4 +1,4 @@ -TestEntity; +TYPE:TestEntity; POSITION:0.000000,0.000000,0.000000; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; diff --git a/tests/data/scene1.scene/TestEntity.3.entity b/tests/assets/scene1.scene/TestEntity.3.entity similarity index 66% rename from tests/data/scene1.scene/TestEntity.3.entity rename to tests/assets/scene1.scene/TestEntity.3.entity index 96ed7fba..cf363b28 100644 --- a/tests/data/scene1.scene/TestEntity.3.entity +++ b/tests/assets/scene1.scene/TestEntity.3.entity @@ -1,4 +1,4 @@ -TestEntity; +TYPE:TestEntity; POSITION:0.000000,0.000000,0.000000; ROTATION:0.000000; -Z-INDEX:0; +Z_INDEX:0; diff --git a/tests/data/scene1.scene/TestEntity.1.entity b/tests/assets/scene2.scene/TestEntity.1.entity similarity index 67% rename from tests/data/scene1.scene/TestEntity.1.entity rename to tests/assets/scene2.scene/TestEntity.1.entity index 1e55285d..6aff8f6c 100644 --- a/tests/data/scene1.scene/TestEntity.1.entity +++ b/tests/assets/scene2.scene/TestEntity.1.entity @@ -1,5 +1,4 @@ -TestEntity; +TYPE:TestEntity; POSITION:0.000000,0.000000,0.000000; ROTATION:0.000000; -Z-INDEX:0; - +Z_INDEX:0; \ No newline at end of file diff --git a/tests/core/test_EntitySystem.cpp b/tests/src/core/test_EntitySystem.cpp similarity index 84% rename from tests/core/test_EntitySystem.cpp rename to tests/src/core/test_EntitySystem.cpp index e79abff4..c0d34206 100644 --- a/tests/core/test_EntitySystem.cpp +++ b/tests/src/core/test_EntitySystem.cpp @@ -43,16 +43,14 @@ UTEST(test_EntitySystem, AddEntities) system.RegisterEntities(); ASSERT_EQ(3, system.GetEntities().size()); - // TODO: Change the Entity constructor to be able to take in string temporaries. - String e4Name = "e4"; - String e5Name = "e5"; + Siege::Token e4Token = Siege::Token::FindOrRegisterToken("e4"); + Siege::Token e5Token = Siege::Token::FindOrRegisterToken("e5"); - // TODO: If this takes in a string temporary it will break Linux. - auto e4 = new Entity(e4Name); - auto e5 = new Entity(e5Name); + auto e4 = new Entity(e4Token); + auto e5 = new Entity(e5Token); - ASSERT_STREQ("e4", e4->GetName().Str()); - ASSERT_STREQ("e5", e5->GetName().Str()); + ASSERT_STREQ("e4", e4->GetType().GetId()); + ASSERT_STREQ("e5", e5->GetType().GetId()); } UTEST(test_EntitySystem, FreeEntities) @@ -145,20 +143,20 @@ UTEST(test_EntitySystem, SortEntitiesByZIndex) // Entities in storage should stay sorted by z-index EntitySystem system; - String e1Name = "e1"; - String e2Name = "e2"; - String e3Name = "e3"; - String e4Name = "e4"; + Siege::Token e1Token = Siege::Token::FindOrRegisterToken("e1"); + Siege::Token e2Token = Siege::Token::FindOrRegisterToken("e2"); + Siege::Token e3Token = Siege::Token::FindOrRegisterToken("e3"); + Siege::Token e4Token = Siege::Token::FindOrRegisterToken("e4"); - auto* e1 = new Entity(e1Name, Xform(), 2); - auto* e2 = new Entity(e2Name, Xform(), 5); - auto* e3 = new Entity(e3Name, Xform(), 1); - auto* e4 = new Entity(e4Name, Xform(), 3); + auto* e1 = new Entity(e1Token, Xform(), 2); + auto* e2 = new Entity(e2Token, Xform(), 5); + auto* e3 = new Entity(e3Token, Xform(), 1); + auto* e4 = new Entity(e4Token, Xform(), 3); - ASSERT_STREQ(e1->GetName().Str(), "e1"); - ASSERT_STREQ(e2->GetName().Str(), "e2"); - ASSERT_STREQ(e3->GetName().Str(), "e3"); - ASSERT_STREQ(e4->GetName().Str(), "e4"); + ASSERT_STREQ("e1", e1->GetType().GetId()); + ASSERT_STREQ("e2", e2->GetType().GetId()); + ASSERT_STREQ("e3", e3->GetType().GetId()); + ASSERT_STREQ("e4", e4->GetType().GetId()); system.Add({e1, e2, e3, e4}); diff --git a/tests/core/test_SceneFile.cpp b/tests/src/core/test_SceneFile.cpp similarity index 76% rename from tests/core/test_SceneFile.cpp rename to tests/src/core/test_SceneFile.cpp index 7c408d27..e9cd2e85 100644 --- a/tests/core/test_SceneFile.cpp +++ b/tests/src/core/test_SceneFile.cpp @@ -10,72 +10,70 @@ #include #include #include +#include #include using namespace Siege; +REGISTER_TOKEN(TestEntity1); class TestEntity1 : public Entity { public: - static const String ENTITY_NAME; + TestEntity1() : Entity(TOKEN_TestEntity1) {}; - TestEntity1() : Entity(ENTITY_NAME) {}; - - TestEntity1(Xform transform, int zIndex) : Entity(ENTITY_NAME, transform, zIndex) {}; + TestEntity1(Xform transform, int zIndex) : Entity(TOKEN_TestEntity1, transform, zIndex) {}; }; -const String TestEntity1::ENTITY_NAME("TestEntity1"); +REGISTER_TOKEN(TestEntity2); class TestEntity2 : public Entity { public: - static const String ENTITY_NAME; - - TestEntity2() : Entity(ENTITY_NAME) {}; + TestEntity2() : Entity(TOKEN_TestEntity2) {}; explicit TestEntity2(String customData) : - Entity(ENTITY_NAME), + Entity(TOKEN_TestEntity2), customData(std::move(customData)) {}; String customData; }; -const String TestEntity2::ENTITY_NAME("TestEntity2"); +REGISTER_TOKEN(TestEntity3); class TestEntity3 : public Entity { public: - static const String ENTITY_NAME; - - TestEntity3() : Entity(ENTITY_NAME) {}; + TestEntity3() : Entity(TOKEN_TestEntity3) {}; }; -const String TestEntity3::ENTITY_NAME("TestEntity3"); // Define test fixture +REGISTER_TOKEN(CUSTOM_DATA); struct test_SceneFile { test_SceneFile() { // Register all serialisables for the fixture SceneFile::RegisterSerialisable( - TestEntity1::ENTITY_NAME, + TOKEN_TestEntity1, [](Entity* entity) -> String { - return DefineField("CUSTOM_DATA", "this is some custom data"); + return DefineField(TOKEN_CUSTOM_DATA, "this is some custom data"); }, - [](const EntityData& data, const std::vector& args) -> Entity* { + [](const std::map& attributes) -> Entity* { + Siege::EntityData data = Siege::SceneFile::GetBaseEntityData(attributes); return new TestEntity1(Xform(data.position, data.rotation), data.zIndex); }); SceneFile::RegisterSerialisable( - TestEntity2::ENTITY_NAME, + TOKEN_TestEntity2, [](Entity* entity) -> String { - return DefineField("CUSTOM_DATA", "this is some other custom data"); + return DefineField(TOKEN_CUSTOM_DATA, "this is some other custom data"); }, - [](const EntityData& data, const std::vector& args) -> Entity* { - return new TestEntity2(args[CUSTOM_FIELD_1]); + [](const std::map& attributes) -> Entity* { + auto it = attributes.find(TOKEN_CUSTOM_DATA); + return new TestEntity2(it != attributes.end() ? it->second : ""); }); - SceneFile::RegisterSerialisable(TestEntity3::ENTITY_NAME, nullptr, nullptr); + SceneFile::RegisterSerialisable(TOKEN_TestEntity3, nullptr, nullptr); } // Entity storage with cleanup @@ -104,10 +102,10 @@ UTEST_F(test_SceneFile, SerialiseEntityToString) TestEntity1 e1; String sceneData; ASSERT_TRUE(SceneFile::SerialiseToString(&e1, sceneData)); - ASSERT_STREQ("TestEntity1;" + ASSERT_STREQ("TYPE:TestEntity1;" "POSITION:0.00,0.00,0.00;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "CUSTOM_DATA:this is some custom data;", sceneData.Str()); @@ -117,10 +115,10 @@ UTEST_F(test_SceneFile, SerialiseEntityToString) e1.SetRotation({0.f, 25.f, 0.f}); e1.SetZIndex(-3); ASSERT_TRUE(SceneFile::SerialiseToString(&e1, sceneData)); - ASSERT_STREQ("TestEntity1;" + ASSERT_STREQ("TYPE:TestEntity1;" "POSITION:1.00,2.00,3.00;" "ROTATION:25.000000;" - "Z-INDEX:-3;" + "Z_INDEX:-3;" "CUSTOM_DATA:this is some custom data;", sceneData.Str()); } @@ -131,10 +129,10 @@ UTEST_F(test_SceneFile, SerialiseEntityToStringWithoutSerialiser) TestEntity3 e3; String sceneData; ASSERT_TRUE(SceneFile::SerialiseToString(&e3, sceneData)); - ASSERT_STREQ("TestEntity3;" + ASSERT_STREQ("TYPE:TestEntity3;" "POSITION:0.00,0.00,0.00;" "ROTATION:0.000000;" - "Z-INDEX:0;", + "Z_INDEX:0;", sceneData.Str()); } @@ -168,17 +166,17 @@ UTEST_F(test_SceneFile, DeserialiseEntityFromStringGarbageData) UTEST_F(test_SceneFile, DeserialiseEntityFromString) { // When deserialising a scene with a single entity it should deserialise correctly - String fileData = "TestEntity1;" + String fileData = "TYPE:TestEntity1;" "POSITION:1.00,2.00,3.00;" "ROTATION:25.000000;" - "Z-INDEX:-3;" + "Z_INDEX:-3;" "CUSTOM_DATA:this is some custom data;"; Entity* e1 = SceneFile::DeserialiseFromString(fileData); ASSERT_TRUE(e1); ASSERT_TRUE(dynamic_cast(e1)); // It should retain its standard field values - ASSERT_STREQ("TestEntity1", e1->GetName().Str()); + ASSERT_STREQ("TestEntity1", e1->GetType().GetId()); Vec3 pos(e1->GetPosition()); Vec3 rot(e1->GetRotation()); ASSERT_EQ(1.f, pos.x); @@ -191,16 +189,16 @@ UTEST_F(test_SceneFile, DeserialiseEntityFromString) delete e1; // It should retain its custom data - fileData = "TestEntity2;" + fileData = "TYPE:TestEntity2;" "POSITION:0.00,0.00,0.00;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "CUSTOM_DATA:this is some other custom data;"; Entity* e2 = SceneFile::DeserialiseFromString(fileData); ASSERT_TRUE(e2); auto* e2Cast = dynamic_cast(e2); ASSERT_TRUE(e2Cast); - ASSERT_STREQ("TestEntity2", e2Cast->GetName().Str()); + ASSERT_STREQ("TestEntity2", e2Cast->GetType().GetId()); ASSERT_STREQ("this is some other custom data", e2Cast->customData.Str()); delete e2; } @@ -208,10 +206,10 @@ UTEST_F(test_SceneFile, DeserialiseEntityFromString) UTEST_F(test_SceneFile, DeserialiseEntityFromStringWithoutDeserialiser) { // When deserialising entities that do not define a deserialiser, it should do nothing - String fileData = "TestEntity3;" + String fileData = "TYPE:TestEntity3;" "POSITION:0.00,0.00,0.00;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "CUSTOM_DATA:this is some other custom data;"; Entity* e1 = SceneFile::DeserialiseFromString(fileData); ASSERT_FALSE(e1); @@ -220,10 +218,10 @@ UTEST_F(test_SceneFile, DeserialiseEntityFromStringWithoutDeserialiser) UTEST_F(test_SceneFile, DeserialiseEntityFromStringWithoutInterface) { // Entities that do not define a serialisation interface should not deserialise - String fileData = "Entity;" + String fileData = "TYPE:Entity;" "POSITION:0.00,0.00,0.00;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "CUSTOM_DATA:this is some other custom data;"; Entity* e1 = SceneFile::DeserialiseFromString(fileData); ASSERT_FALSE(e1); diff --git a/tests/core/test_SceneSystem.cpp b/tests/src/core/test_SceneSystem.cpp similarity index 95% rename from tests/core/test_SceneSystem.cpp rename to tests/src/core/test_SceneSystem.cpp index 7352bc01..bec701d7 100644 --- a/tests/core/test_SceneSystem.cpp +++ b/tests/src/core/test_SceneSystem.cpp @@ -18,7 +18,7 @@ using namespace Siege; // Const declarations -static constexpr const char* SCENE_DIR = "data/"; +static constexpr const char* SCENE_DIR = "assets/"; static constexpr const char* TEST_SCENE_FILE = "test.scene"; static constexpr const char* UNTITLED_SCENE_FILE = "untitled.scene"; static constexpr const char* GARBAGE_SCENE_FILE = "garbage.scene"; @@ -39,23 +39,21 @@ void GetContainedEntityFiles(const String& filepath, OUT std::vector& en } // Test entity +REGISTER_TOKEN(TestEntity); class TestEntity : public Entity { public: - static const String ENTITY_NAME; + TestEntity() : Entity(TOKEN_TestEntity) {} - TestEntity() : Entity(ENTITY_NAME) {} - - explicit TestEntity(Xform transform) : Entity(ENTITY_NAME, transform) {} + explicit TestEntity(Xform transform) : Entity(TOKEN_TestEntity, transform) {} }; -const String TestEntity::ENTITY_NAME("TestEntity"); - REGISTER_SERIALISATION_INTERFACE( - TestEntity::ENTITY_NAME, + TOKEN_TestEntity, [](Entity* entity) -> String { return ""; }, - [](const EntityData& data, const std::vector& args) -> Entity* { + [](const std::map& attributes) -> Entity* { + Siege::EntityData data = Siege::SceneFile::GetBaseEntityData(attributes); return new TestEntity(Xform(data.position, data.rotation)); }); diff --git a/tests/main.cpp b/tests/src/main.cpp similarity index 100% rename from tests/main.cpp rename to tests/src/main.cpp diff --git a/tests/resources/test_ResourceSystem.cpp b/tests/src/resources/test_ResourceSystem.cpp similarity index 85% rename from tests/resources/test_ResourceSystem.cpp rename to tests/src/resources/test_ResourceSystem.cpp index cdb7214a..b1adc154 100644 --- a/tests/resources/test_ResourceSystem.cpp +++ b/tests/src/resources/test_ResourceSystem.cpp @@ -15,6 +15,8 @@ #include #include +#include "utils/Logging.h" + using namespace Siege; // Define test fixture @@ -40,7 +42,7 @@ UTEST_F_TEARDOWN(test_ResourceSystem) UTEST(test_ResourceSystem, LoadNonExistentPackFile) { ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); - bool result = resourceSystem.MountPackFile("data/nopackfile"); + bool result = resourceSystem.MountPackFile("assets/nopackfile"); ASSERT_FALSE(result); PackFile* packFile = resourceSystem.GetPackFile(); @@ -55,15 +57,15 @@ UTEST_F(test_ResourceSystem, ReadAllPackedEntries) const PackFile::Header& header = packFile->GetHeader(); ASSERT_STREQ("pck", header.magic.string); - ASSERT_EQ(259384, header.bodySize); - ASSERT_EQ(259227, header.tocOffset); + ASSERT_EQ(259415, header.bodySize); + ASSERT_EQ(259247, header.tocOffset); - std::vector packedFilepaths {"data/scene2.scene", - "data/scene1.scene", - "data/garbage.scene", - "data/cube.obj", - "data/cappy.png", - "data/PublicPixel.ttf"}; + std::vector packedFilepaths {"assets/scene2.scene", + "assets/scene1.scene", + "assets/garbage.scene", + "assets/cube.sm", + "assets/cappy.png", + "assets/PublicPixel.ttf"}; for (const String& filepath : packedFilepaths) { @@ -77,7 +79,7 @@ UTEST_F(test_ResourceSystem, LoadNonExistentData) ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); PackFile* packFile = resourceSystem.GetPackFile(); - GenericFileData* data = packFile->FindData("data/nonexistent.filetype"); + GenericFileData* data = packFile->FindData("assets/nonexistent.filetype"); ASSERT_FALSE(data); } @@ -86,7 +88,7 @@ UTEST_F(test_ResourceSystem, LoadGenericFileData) ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); PackFile* packFile = resourceSystem.GetPackFile(); - GenericFileData* data = packFile->FindData("data/PublicPixel.ttf"); + GenericFileData* data = packFile->FindData("assets/PublicPixel.ttf"); ASSERT_TRUE(data); ASSERT_EQ(97456, data->dataSize); } @@ -96,7 +98,7 @@ UTEST_F(test_ResourceSystem, LoadStaticMeshData) ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); PackFile* packFile = resourceSystem.GetPackFile(); - StaticMeshData* data = packFile->FindData("data/cube.obj"); + StaticMeshData* data = packFile->FindData("assets/cube.sm"); ASSERT_TRUE(data); ASSERT_EQ(36, data->indicesCount); ASSERT_EQ(24, data->verticesCount); @@ -162,7 +164,7 @@ UTEST_F(test_ResourceSystem, LoadTextureData) ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); PackFile* packFile = resourceSystem.GetPackFile(); - Texture2DData* data = packFile->FindData("data/cappy.png"); + Texture2DData* data = packFile->FindData("assets/cappy.png"); ASSERT_TRUE(data); ASSERT_EQ(160000, data->GetImageSize()); @@ -175,23 +177,23 @@ UTEST_F(test_ResourceSystem, LoadSceneData) ResourceSystem& resourceSystem = ResourceSystem::GetInstance(); PackFile* packFile = resourceSystem.GetPackFile(); - const char* expectedSceneData = "TestEntity;" + const char* expectedSceneData = "TYPE:TestEntity;" "POSITION:0.000000,0.000000,0.000000;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "|" - "TestEntity;" + "TYPE:TestEntity;" "POSITION:0.000000,0.000000,0.000000;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "|" - "TestEntity;" + "TYPE:TestEntity;" "POSITION:0.000000,0.000000,0.000000;" "ROTATION:0.000000;" - "Z-INDEX:0;" + "Z_INDEX:0;" "|"; - SceneData* data = packFile->FindData("data/scene1.scene"); + SceneData* data = packFile->FindData("assets/scene1.scene"); ASSERT_TRUE(data); ASSERT_STREQ(expectedSceneData, data->GetData()); } \ No newline at end of file diff --git a/tests/utils/test_BitMaskField.cpp b/tests/src/utils/test_BitMaskField.cpp similarity index 100% rename from tests/utils/test_BitMaskField.cpp rename to tests/src/utils/test_BitMaskField.cpp diff --git a/tests/utils/test_Colour.cpp b/tests/src/utils/test_Colour.cpp similarity index 100% rename from tests/utils/test_Colour.cpp rename to tests/src/utils/test_Colour.cpp diff --git a/tests/utils/test_Defer.cpp b/tests/src/utils/test_Defer.cpp similarity index 100% rename from tests/utils/test_Defer.cpp rename to tests/src/utils/test_Defer.cpp diff --git a/tests/utils/test_Float.cpp b/tests/src/utils/test_Float.cpp similarity index 100% rename from tests/utils/test_Float.cpp rename to tests/src/utils/test_Float.cpp diff --git a/tests/utils/test_Logging.cpp b/tests/src/utils/test_Logging.cpp similarity index 100% rename from tests/utils/test_Logging.cpp rename to tests/src/utils/test_Logging.cpp diff --git a/tests/utils/test_MHArray.cpp b/tests/src/utils/test_MHArray.cpp similarity index 100% rename from tests/utils/test_MHArray.cpp rename to tests/src/utils/test_MHArray.cpp diff --git a/tests/utils/test_MSArray.cpp b/tests/src/utils/test_MSArray.cpp similarity index 100% rename from tests/utils/test_MSArray.cpp rename to tests/src/utils/test_MSArray.cpp diff --git a/tests/utils/test_Mat2.cpp b/tests/src/utils/test_Mat2.cpp similarity index 100% rename from tests/utils/test_Mat2.cpp rename to tests/src/utils/test_Mat2.cpp diff --git a/tests/utils/test_Mat3.cpp b/tests/src/utils/test_Mat3.cpp similarity index 100% rename from tests/utils/test_Mat3.cpp rename to tests/src/utils/test_Mat3.cpp diff --git a/tests/utils/test_Mat4.cpp b/tests/src/utils/test_Mat4.cpp similarity index 100% rename from tests/utils/test_Mat4.cpp rename to tests/src/utils/test_Mat4.cpp diff --git a/tests/utils/test_Projection.cpp b/tests/src/utils/test_Projection.cpp similarity index 100% rename from tests/utils/test_Projection.cpp rename to tests/src/utils/test_Projection.cpp diff --git a/tests/utils/test_SArray.cpp b/tests/src/utils/test_SArray.cpp similarity index 100% rename from tests/utils/test_SArray.cpp rename to tests/src/utils/test_SArray.cpp diff --git a/tests/utils/test_String.cpp b/tests/src/utils/test_String.cpp similarity index 95% rename from tests/utils/test_String.cpp rename to tests/src/utils/test_String.cpp index d599a0b9..f2223bb8 100644 --- a/tests/utils/test_String.cpp +++ b/tests/src/utils/test_String.cpp @@ -37,6 +37,13 @@ UTEST(test_String, DefaultConstruct) ASSERT_EQ(5, s.Size()); ASSERT_STREQ("hello", s.Str()); ASSERT_EQ(0, std::strcmp(s.Str(), "hello")); + + // Assignment of wide c-strings via assignment operator should apply + s = L"hello"; + ASSERT_FALSE(s.IsEmpty()); + ASSERT_EQ(5, s.Size()); + ASSERT_STREQ("hello", s.Str()); + ASSERT_EQ(0, std::strcmp(s.Str(), "hello")); } UTEST(test_String, CopyConstruct) @@ -148,6 +155,16 @@ UTEST(test_String, Append) ASSERT_STREQ("goodbyehellogoodbye", s2.Str()); ASSERT_EQ(19, s2.Size()); + // The string should correctly append wide c-strings + Siege::String s6; + s6 += L"hello"; + ASSERT_STREQ("hello", s6.Str()); + Siege::String s7 = L"goodbye" + s6; + ASSERT_STREQ("goodbyehello", s7.Str()); + s7.Append(L"goodbye"); + ASSERT_STREQ("goodbyehellogoodbye", s7.Str()); + ASSERT_EQ(19, s7.Size()); + // The string should correctly append characters Siege::String s5; s5 += 'h'; @@ -330,6 +347,23 @@ UTEST(test_String, Find) ASSERT_EQ(26, s.Find("a", -11)); } +UTEST(test_String, BeginsWith) +{ + // The string can be checked whether it begins with substrings + Siege::String s("ruSt Is a MuCH SafEr lANgUagE..."); + ASSERT_TRUE(s.BeginsWith("")); + ASSERT_TRUE(s.BeginsWith('r')); + ASSERT_TRUE(s.BeginsWith("ruSt")); + ASSERT_TRUE(s.BeginsWith("ruSt Is a MuCH SafEr ")); + ASSERT_FALSE(s.BeginsWith("Is")); + ASSERT_FALSE(s.BeginsWith("lANgUagE...")); + + Siege::String s2("ruSt"); + Siege::String s3("uSt"); + ASSERT_TRUE(s.BeginsWith(s2)); + ASSERT_FALSE(s.BeginsWith(s3)); +} + UTEST(test_String, Replace) { // The string can replace by substring diff --git a/tests/src/utils/test_Token.cpp b/tests/src/utils/test_Token.cpp new file mode 100644 index 00000000..960a4862 --- /dev/null +++ b/tests/src/utils/test_Token.cpp @@ -0,0 +1,97 @@ +// +// Copyright (c) 2020-present Caps Collective & contributors +// Originally authored by Jonathan Moallem (@jonjondev) & Aryeh Zinn (@Raelr) +// +// This code is released under an unmodified zlib license. +// For conditions of distribution and use, please see: +// https://opensource.org/licenses/Zlib +// + +#include +#include + +REGISTER_TOKEN(HelloWorld); +REGISTER_TOKEN(NewOne); +REGISTER_TOKEN(GoodbyeWorld); +REGISTER_TOKEN(ReallyLongHeapAllocatedStringTokenName); + +UTEST(test_Token, StaticallyRegistered) +{ + Siege::Token tk1 = TOKEN_HelloWorld; + Siege::Token tk2 = TOKEN_NewOne; + Siege::Token tk3 = TOKEN_GoodbyeWorld; + Siege::Token tk4 = TOKEN_HelloWorld; + Siege::Token tk5("Hi"); + Siege::Token tk6("HelloWorld"); + Siege::Token tk7 = TOKEN_ReallyLongHeapAllocatedStringTokenName; + + ASSERT_TRUE(tk1.IsValid()); + ASSERT_TRUE(tk2.IsValid()); + ASSERT_TRUE(tk3.IsValid()); + ASSERT_TRUE(tk4.IsValid()); + ASSERT_FALSE(tk5.IsValid()); + ASSERT_TRUE(tk6.IsValid()); + ASSERT_TRUE(tk7.IsValid()); + + ASSERT_STREQ("HelloWorld", tk1.GetId()); + ASSERT_STREQ("NewOne", tk2.GetId()); + ASSERT_STREQ("GoodbyeWorld", tk3.GetId()); + ASSERT_STREQ("HelloWorld", tk4.GetId()); + ASSERT_STREQ("HelloWorld", tk6.GetId()); + ASSERT_STREQ("ReallyLongHeapAllocatedStringTokenName", tk7.GetId()); + + ASSERT_TRUE(tk1 != tk2); + ASSERT_TRUE(tk1 != tk3); + ASSERT_TRUE(tk1 == tk4); + ASSERT_TRUE(tk1 == tk6); + ASSERT_TRUE(tk1 != tk7); + ASSERT_TRUE(tk2 != tk3); + ASSERT_TRUE(tk2 != tk4); + ASSERT_TRUE(tk2 != tk7); + ASSERT_TRUE(tk3 != tk4); + ASSERT_TRUE(tk3 != tk7); + ASSERT_TRUE(tk6 != tk7); +} + +UTEST(test_Token, DynamicallyRegistered) +{ + Siege::Token tk1 = Siege::Token::FindToken("HelloWorld"); + Siege::Token tk2 = Siege::Token::FindToken("NewOne"); + Siege::Token tk3 = Siege::Token::FindToken("GoodbyeWorld"); + Siege::Token tk4 = Siege::Token::FindOrRegisterToken("HelloWorld"); + + ASSERT_TRUE(tk1.IsValid()); + ASSERT_TRUE(tk2.IsValid()); + ASSERT_TRUE(tk3.IsValid()); + ASSERT_TRUE(tk4.IsValid()); + + ASSERT_STREQ("HelloWorld", tk1.GetId()); + ASSERT_STREQ("NewOne", tk2.GetId()); + ASSERT_STREQ("GoodbyeWorld", tk3.GetId()); + ASSERT_STREQ("HelloWorld", tk4.GetId()); + + ASSERT_TRUE(tk1 != tk2); + ASSERT_TRUE(tk1 != tk3); + ASSERT_TRUE(tk1 == tk4); + ASSERT_TRUE(tk2 != tk3); + ASSERT_TRUE(tk2 != tk4); + ASSERT_TRUE(tk3 != tk4); + + Siege::Token tk5 = Siege::Token::FindOrRegisterToken("a"); + Siege::Token tk6 = Siege::Token::FindOrRegisterToken("c"); + Siege::Token tk7 = Siege::Token::FindOrRegisterToken("b"); + + ASSERT_STREQ("a", tk5.GetId()); + ASSERT_STREQ("c", tk6.GetId()); + ASSERT_STREQ("b", tk7.GetId()); + + Siege::Token tk8 = Siege::Token::FindToken("GoodbyeWorld"); + Siege::Token tk9 = Siege::Token::FindToken("FooBar"); + + ASSERT_TRUE(tk8.IsValid()); + ASSERT_FALSE(tk9.IsValid()); + + ASSERT_STREQ("GoodbyeWorld", tk8.GetId()); + + ASSERT_TRUE(tk8 == tk3); +} diff --git a/tests/utils/test_Transform.cpp b/tests/src/utils/test_Transform.cpp similarity index 100% rename from tests/utils/test_Transform.cpp rename to tests/src/utils/test_Transform.cpp diff --git a/tests/utils/test_Vec2.cpp b/tests/src/utils/test_Vec2.cpp similarity index 100% rename from tests/utils/test_Vec2.cpp rename to tests/src/utils/test_Vec2.cpp diff --git a/tests/utils/test_Vec3.cpp b/tests/src/utils/test_Vec3.cpp similarity index 100% rename from tests/utils/test_Vec3.cpp rename to tests/src/utils/test_Vec3.cpp diff --git a/tests/utils/test_Vec4.cpp b/tests/src/utils/test_Vec4.cpp similarity index 100% rename from tests/utils/test_Vec4.cpp rename to tests/src/utils/test_Vec4.cpp diff --git a/vendor/assimp b/vendor/assimp new file mode 160000 index 00000000..fb375dd8 --- /dev/null +++ b/vendor/assimp @@ -0,0 +1 @@ +Subproject commit fb375dd8c0a032106a2122815fb18dffe0283721 diff --git a/vendor/freetype b/vendor/freetype index dd91f6e7..42608f77 160000 --- a/vendor/freetype +++ b/vendor/freetype @@ -1 +1 @@ -Subproject commit dd91f6e7f5a051818070c49715125fb72074023e +Subproject commit 42608f77f20749dd6ddc9e0536788eaad70ea4b5 diff --git a/vendor/glfw b/vendor/glfw index 6876cf8d..7b6aead9 160000 --- a/vendor/glfw +++ b/vendor/glfw @@ -1 +1 @@ -Subproject commit 6876cf8d7e0e70dc3e4d7b0224d08312c9f78099 +Subproject commit 7b6aead9fb88b3623e3b3725ebb42670cbe4c579 diff --git a/vendor/glm b/vendor/glm deleted file mode 160000 index 06ed280d..00000000 --- a/vendor/glm +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 06ed280db4e274fa5e1f36d5ea4f7dfd654ff9b0 diff --git a/vendor/glslang b/vendor/glslang index 46ef757e..fc9889c8 160000 --- a/vendor/glslang +++ b/vendor/glslang @@ -1 +1 @@ -Subproject commit 46ef757e048e760b46601e6e77ae0cb72c97bd2f +Subproject commit fc9889c889561c5882e83819dcaffef5ed45529b diff --git a/vendor/libpng b/vendor/libpng index 61bfdb0c..2b978915 160000 --- a/vendor/libpng +++ b/vendor/libpng @@ -1 +1 @@ -Subproject commit 61bfdb0cb02a6f3a62c929dbc9e832894c0a8df2 +Subproject commit 2b978915d82377df13fcbb1fb56660195ded868a diff --git a/vendor/tinyobjloader/tiny_obj_loader.h b/vendor/tinyobjloader/tiny_obj_loader.h deleted file mode 100644 index 77f86b2d..00000000 --- a/vendor/tinyobjloader/tiny_obj_loader.h +++ /dev/null @@ -1,3317 +0,0 @@ -/* -The MIT License (MIT) - -Copyright (c) 2012-Present, Syoyo Fujita and many contributors. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ - -// -// version 2.0.0 : Add new object oriented API. 1.x API is still provided. -// * Support line primitive. -// * Support points primitive. -// * Support multiple search path for .mtl(v1 API). -// * Support vertex weight `vw`(as an tinyobj extension) -// * Support escaped whitespece in mtllib -// * Add robust triangulation using Mapbox earcut(TINYOBJLOADER_USE_MAPBOX_EARCUT). -// version 1.4.0 : Modifed ParseTextureNameAndOption API -// version 1.3.1 : Make ParseTextureNameAndOption API public -// version 1.3.0 : Separate warning and error message(breaking API of LoadObj) -// version 1.2.3 : Added color space extension('-colorspace') to tex opts. -// version 1.2.2 : Parse multiple group names. -// version 1.2.1 : Added initial support for line('l') primitive(PR #178) -// version 1.2.0 : Hardened implementation(#175) -// version 1.1.1 : Support smoothing groups(#162) -// version 1.1.0 : Support parsing vertex color(#144) -// version 1.0.8 : Fix parsing `g` tag just after `usemtl`(#138) -// version 1.0.7 : Support multiple tex options(#126) -// version 1.0.6 : Add TINYOBJLOADER_USE_DOUBLE option(#124) -// version 1.0.5 : Ignore `Tr` when `d` exists in MTL(#43) -// version 1.0.4 : Support multiple filenames for 'mtllib'(#112) -// version 1.0.3 : Support parsing texture options(#85) -// version 1.0.2 : Improve parsing speed by about a factor of 2 for large -// files(#105) -// version 1.0.1 : Fixes a shape is lost if obj ends with a 'usemtl'(#104) -// version 1.0.0 : Change data structure. Change license from BSD to MIT. -// - -// -// Use this in *one* .cc -// #define TINYOBJLOADER_IMPLEMENTATION -// #include "tiny_obj_loader.h" -// - -#ifndef TINY_OBJ_LOADER_H_ -#define TINY_OBJ_LOADER_H_ - -#include -#include -#include - -namespace tinyobj { - -// TODO(syoyo): Better C++11 detection for older compiler -#if __cplusplus > 199711L -#define TINYOBJ_OVERRIDE override -#else -#define TINYOBJ_OVERRIDE -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#if __has_warning("-Wzero-as-null-pointer-constant") -#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant" -#endif - -#pragma clang diagnostic ignored "-Wpadded" - -#endif - -// https://en.wikipedia.org/wiki/Wavefront_.obj_file says ... -// -// -blendu on | off # set horizontal texture blending -// (default on) -// -blendv on | off # set vertical texture blending -// (default on) -// -boost real_value # boost mip-map sharpness -// -mm base_value gain_value # modify texture map values (default -// 0 1) -// # base_value = brightness, -// gain_value = contrast -// -o u [v [w]] # Origin offset (default -// 0 0 0) -// -s u [v [w]] # Scale (default -// 1 1 1) -// -t u [v [w]] # Turbulence (default -// 0 0 0) -// -texres resolution # texture resolution to create -// -clamp on | off # only render texels in the clamped -// 0-1 range (default off) -// # When unclamped, textures are -// repeated across a surface, -// # when clamped, only texels which -// fall within the 0-1 -// # range are rendered. -// -bm mult_value # bump multiplier (for bump maps -// only) -// -// -imfchan r | g | b | m | l | z # specifies which channel of the file -// is used to -// # create a scalar or bump texture. -// r:red, g:green, -// # b:blue, m:matte, l:luminance, -// z:z-depth.. -// # (the default for bump is 'l' and -// for decal is 'm') -// bump -imfchan r bumpmap.tga # says to use the red channel of -// bumpmap.tga as the bumpmap -// -// For reflection maps... -// -// -type sphere # specifies a sphere for a "refl" -// reflection map -// -type cube_top | cube_bottom | # when using a cube map, the texture -// file for each -// cube_front | cube_back | # side of the cube is specified -// separately -// cube_left | cube_right -// -// TinyObjLoader extension. -// -// -colorspace SPACE # Color space of the texture. e.g. -// 'sRGB` or 'linear' -// - -#ifdef TINYOBJLOADER_USE_DOUBLE -//#pragma message "using double" -typedef double real_t; -#else -//#pragma message "using float" -typedef float real_t; -#endif - -typedef enum { - TEXTURE_TYPE_NONE, // default - TEXTURE_TYPE_SPHERE, - TEXTURE_TYPE_CUBE_TOP, - TEXTURE_TYPE_CUBE_BOTTOM, - TEXTURE_TYPE_CUBE_FRONT, - TEXTURE_TYPE_CUBE_BACK, - TEXTURE_TYPE_CUBE_LEFT, - TEXTURE_TYPE_CUBE_RIGHT -} texture_type_t; - -struct texture_option_t { - texture_type_t type; // -type (default TEXTURE_TYPE_NONE) - real_t sharpness; // -boost (default 1.0?) - real_t brightness; // base_value in -mm option (default 0) - real_t contrast; // gain_value in -mm option (default 1) - real_t origin_offset[3]; // -o u [v [w]] (default 0 0 0) - real_t scale[3]; // -s u [v [w]] (default 1 1 1) - real_t turbulence[3]; // -t u [v [w]] (default 0 0 0) - int texture_resolution; // -texres resolution (No default value in the spec. - // We'll use -1) - bool clamp; // -clamp (default false) - char imfchan; // -imfchan (the default for bump is 'l' and for decal is 'm') - bool blendu; // -blendu (default on) - bool blendv; // -blendv (default on) - real_t bump_multiplier; // -bm (for bump maps only, default 1.0) - - // extension - std::string colorspace; // Explicitly specify color space of stored texel - // value. Usually `sRGB` or `linear` (default empty). -}; - -struct material_t { - std::string name; - - real_t ambient[3]; - real_t diffuse[3]; - real_t specular[3]; - real_t transmittance[3]; - real_t emission[3]; - real_t shininess; - real_t ior; // index of refraction - real_t dissolve; // 1 == opaque; 0 == fully transparent - // illumination model (see http://www.fileformat.info/format/material/) - int illum; - - int dummy; // Suppress padding warning. - - std::string ambient_texname; // map_Ka - std::string diffuse_texname; // map_Kd - std::string specular_texname; // map_Ks - std::string specular_highlight_texname; // map_Ns - std::string bump_texname; // map_bump, map_Bump, bump - std::string displacement_texname; // disp - std::string alpha_texname; // map_d - std::string reflection_texname; // refl - - texture_option_t ambient_texopt; - texture_option_t diffuse_texopt; - texture_option_t specular_texopt; - texture_option_t specular_highlight_texopt; - texture_option_t bump_texopt; - texture_option_t displacement_texopt; - texture_option_t alpha_texopt; - texture_option_t reflection_texopt; - - // PBR extension - // http://exocortex.com/blog/extending_wavefront_mtl_to_support_pbr - real_t roughness; // [0, 1] default 0 - real_t metallic; // [0, 1] default 0 - real_t sheen; // [0, 1] default 0 - real_t clearcoat_thickness; // [0, 1] default 0 - real_t clearcoat_roughness; // [0, 1] default 0 - real_t anisotropy; // aniso. [0, 1] default 0 - real_t anisotropy_rotation; // anisor. [0, 1] default 0 - real_t pad0; - std::string roughness_texname; // map_Pr - std::string metallic_texname; // map_Pm - std::string sheen_texname; // map_Ps - std::string emissive_texname; // map_Ke - std::string normal_texname; // norm. For normal mapping. - - texture_option_t roughness_texopt; - texture_option_t metallic_texopt; - texture_option_t sheen_texopt; - texture_option_t emissive_texopt; - texture_option_t normal_texopt; - - int pad2; - - std::map unknown_parameter; - -#ifdef TINY_OBJ_LOADER_PYTHON_BINDING - // For pybind11 - std::array GetDiffuse() { - std::array values; - values[0] = double(diffuse[0]); - values[1] = double(diffuse[1]); - values[2] = double(diffuse[2]); - - return values; - } - - std::array GetSpecular() { - std::array values; - values[0] = double(specular[0]); - values[1] = double(specular[1]); - values[2] = double(specular[2]); - - return values; - } - - std::array GetTransmittance() { - std::array values; - values[0] = double(transmittance[0]); - values[1] = double(transmittance[1]); - values[2] = double(transmittance[2]); - - return values; - } - - std::array GetEmission() { - std::array values; - values[0] = double(emission[0]); - values[1] = double(emission[1]); - values[2] = double(emission[2]); - - return values; - } - - std::array GetAmbient() { - std::array values; - values[0] = double(ambient[0]); - values[1] = double(ambient[1]); - values[2] = double(ambient[2]); - - return values; - } - - void SetDiffuse(std::array &a) { - diffuse[0] = real_t(a[0]); - diffuse[1] = real_t(a[1]); - diffuse[2] = real_t(a[2]); - } - - void SetAmbient(std::array &a) { - ambient[0] = real_t(a[0]); - ambient[1] = real_t(a[1]); - ambient[2] = real_t(a[2]); - } - - void SetSpecular(std::array &a) { - specular[0] = real_t(a[0]); - specular[1] = real_t(a[1]); - specular[2] = real_t(a[2]); - } - - void SetTransmittance(std::array &a) { - transmittance[0] = real_t(a[0]); - transmittance[1] = real_t(a[1]); - transmittance[2] = real_t(a[2]); - } - - std::string GetCustomParameter(const std::string &key) { - std::map::const_iterator it = - unknown_parameter.find(key); - - if (it != unknown_parameter.end()) { - return it->second; - } - return std::string(); - } - -#endif -}; - -struct tag_t { - std::string name; - - std::vector intValues; - std::vector floatValues; - std::vector stringValues; -}; - -struct joint_and_weight_t { - int joint_id; - real_t weight; -}; - -struct skin_weight_t { - int vertex_id; // Corresponding vertex index in `attrib_t::vertices`. - // Compared to `index_t`, this index must be positive and - // start with 0(does not allow relative indexing) - std::vector weightValues; -}; - -// Index struct to support different indices for vtx/normal/texcoord. -// -1 means not used. -struct index_t { - int vertex_index; - int normal_index; - int texcoord_index; -}; - -struct mesh_t { - std::vector indices; - std::vector - num_face_vertices; // The number of vertices per - // face. 3 = triangle, 4 = quad, - // ... Up to 255 vertices per face. - std::vector material_ids; // per-face material ID - std::vector smoothing_group_ids; // per-face smoothing group - // ID(0 = off. positive value - // = group id) - std::vector tags; // SubD tag -}; - -// struct path_t { -// std::vector indices; // pairs of indices for lines -//}; - -struct lines_t { - // Linear flattened indices. - std::vector indices; // indices for vertices(poly lines) - std::vector num_line_vertices; // The number of vertices per line. -}; - -struct points_t { - std::vector indices; // indices for points -}; - -struct shape_t { - std::string name; - mesh_t mesh; - lines_t lines; - points_t points; -}; - -// Vertex attributes -struct attrib_t { - std::vector vertices; // 'v'(xyz) - - // For backward compatibility, we store vertex weight in separate array. - std::vector vertex_weights; // 'v'(w) - std::vector normals; // 'vn' - std::vector texcoords; // 'vt'(uv) - - // For backward compatibility, we store texture coordinate 'w' in separate - // array. - std::vector texcoord_ws; // 'vt'(w) - std::vector colors; // extension: vertex colors - - // - // TinyObj extension. - // - - // NOTE(syoyo): array index is based on the appearance order. - // To get a corresponding skin weight for a specific vertex id `vid`, - // Need to reconstruct a look up table: `skin_weight_t::vertex_id` == `vid` - // (e.g. using std::map, std::unordered_map) - std::vector skin_weights; - - attrib_t() {} - - // - // For pybind11 - // - const std::vector &GetVertices() const { return vertices; } - - const std::vector &GetVertexWeights() const { return vertex_weights; } -}; - -struct callback_t { - // W is optional and set to 1 if there is no `w` item in `v` line - void (*vertex_cb)(void *user_data, real_t x, real_t y, real_t z, real_t w); - void (*normal_cb)(void *user_data, real_t x, real_t y, real_t z); - - // y and z are optional and set to 0 if there is no `y` and/or `z` item(s) in - // `vt` line. - void (*texcoord_cb)(void *user_data, real_t x, real_t y, real_t z); - - // called per 'f' line. num_indices is the number of face indices(e.g. 3 for - // triangle, 4 for quad) - // 0 will be passed for undefined index in index_t members. - void (*index_cb)(void *user_data, index_t *indices, int num_indices); - // `name` material name, `material_id` = the array index of material_t[]. -1 - // if - // a material not found in .mtl - void (*usemtl_cb)(void *user_data, const char *name, int material_id); - // `materials` = parsed material data. - void (*mtllib_cb)(void *user_data, const material_t *materials, - int num_materials); - // There may be multiple group names - void (*group_cb)(void *user_data, const char **names, int num_names); - void (*object_cb)(void *user_data, const char *name); - - callback_t() - : vertex_cb(NULL), - normal_cb(NULL), - texcoord_cb(NULL), - index_cb(NULL), - usemtl_cb(NULL), - mtllib_cb(NULL), - group_cb(NULL), - object_cb(NULL) {} -}; - -class MaterialReader { - public: - MaterialReader() {} - virtual ~MaterialReader(); - - virtual bool operator()(const std::string &matId, - std::vector *materials, - std::map *matMap, std::string *warn, - std::string *err) = 0; -}; - -/// -/// Read .mtl from a file. -/// -class MaterialFileReader : public MaterialReader { - public: - // Path could contain separator(';' in Windows, ':' in Posix) - explicit MaterialFileReader(const std::string &mtl_basedir) - : m_mtlBaseDir(mtl_basedir) {} - virtual ~MaterialFileReader() TINYOBJ_OVERRIDE {} - virtual bool operator()(const std::string &matId, - std::vector *materials, - std::map *matMap, std::string *warn, - std::string *err) TINYOBJ_OVERRIDE; - - private: - std::string m_mtlBaseDir; -}; - -/// -/// Read .mtl from a stream. -/// -class MaterialStreamReader : public MaterialReader { - public: - explicit MaterialStreamReader(std::istream &inStream) - : m_inStream(inStream) {} - virtual ~MaterialStreamReader() TINYOBJ_OVERRIDE {} - virtual bool operator()(const std::string &matId, - std::vector *materials, - std::map *matMap, std::string *warn, - std::string *err) TINYOBJ_OVERRIDE; - - private: - std::istream &m_inStream; -}; - -// v2 API -struct ObjReaderConfig { - bool triangulate; // triangulate polygon? - - // Currently not used. - // "simple" or empty: Create triangle fan - // "earcut": Use the algorithm based on Ear clipping - std::string triangulation_method; - - /// Parse vertex color. - /// If vertex color is not present, its filled with default value. - /// false = no vertex color - /// This will increase memory of parsed .obj - bool vertex_color; - - /// - /// Search path to .mtl file. - /// Default = "" = search from the same directory of .obj file. - /// Valid only when loading .obj from a file. - /// - std::string mtl_search_path; - - ObjReaderConfig() - : triangulate(true), triangulation_method("simple"), vertex_color(true) {} -}; - -/// -/// Wavefront .obj reader class(v2 API) -/// -class ObjReader { - public: - ObjReader() : valid_(false) {} - ~ObjReader() {} - - /// - /// Load .obj and .mtl from a file. - /// - /// @param[in] filename wavefront .obj filename - /// @param[in] config Reader configuration - /// - bool ParseFromFile(const std::string &filename, - const ObjReaderConfig &config = ObjReaderConfig()); - - /// - /// Parse .obj from a text string. - /// Need to supply .mtl text string by `mtl_text`. - /// This function ignores `mtllib` line in .obj text. - /// - /// @param[in] obj_text wavefront .obj filename - /// @param[in] mtl_text wavefront .mtl filename - /// @param[in] config Reader configuration - /// - bool ParseFromString(const std::string &obj_text, const std::string &mtl_text, - const ObjReaderConfig &config = ObjReaderConfig()); - - /// - /// .obj was loaded or parsed correctly. - /// - bool Valid() const { return valid_; } - - const attrib_t &GetAttrib() const { return attrib_; } - - const std::vector &GetShapes() const { return shapes_; } - - const std::vector &GetMaterials() const { return materials_; } - - /// - /// Warning message(may be filled after `Load` or `Parse`) - /// - const std::string &Warning() const { return warning_; } - - /// - /// Error message(filled when `Load` or `Parse` failed) - /// - const std::string &Error() const { return error_; } - - private: - bool valid_; - - attrib_t attrib_; - std::vector shapes_; - std::vector materials_; - - std::string warning_; - std::string error_; -}; - -/// ==>>========= Legacy v1 API ============================================= - -/// Loads .obj from a file. -/// 'attrib', 'shapes' and 'materials' will be filled with parsed shape data -/// 'shapes' will be filled with parsed shape data -/// Returns true when loading .obj become success. -/// Returns warning message into `warn`, and error message into `err` -/// 'mtl_basedir' is optional, and used for base directory for .mtl file. -/// In default(`NULL'), .mtl file is searched from an application's working -/// directory. -/// 'triangulate' is optional, and used whether triangulate polygon face in .obj -/// or not. -/// Option 'default_vcols_fallback' specifies whether vertex colors should -/// always be defined, even if no colors are given (fallback to white). -bool LoadObj(attrib_t *attrib, std::vector *shapes, - std::vector *materials, std::string *warn, - std::string *err, const char *filename, - const char *mtl_basedir = NULL, bool triangulate = true, - bool default_vcols_fallback = true); - -/// Loads .obj from a file with custom user callback. -/// .mtl is loaded as usual and parsed material_t data will be passed to -/// `callback.mtllib_cb`. -/// Returns true when loading .obj/.mtl become success. -/// Returns warning message into `warn`, and error message into `err` -/// See `examples/callback_api/` for how to use this function. -bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, - void *user_data = NULL, - MaterialReader *readMatFn = NULL, - std::string *warn = NULL, std::string *err = NULL); - -/// Loads object from a std::istream, uses `readMatFn` to retrieve -/// std::istream for materials. -/// Returns true when loading .obj become success. -/// Returns warning and error message into `err` -bool LoadObj(attrib_t *attrib, std::vector *shapes, - std::vector *materials, std::string *warn, - std::string *err, std::istream *inStream, - MaterialReader *readMatFn = NULL, bool triangulate = true, - bool default_vcols_fallback = true); - -/// Loads materials into std::map -void LoadMtl(std::map *material_map, - std::vector *materials, std::istream *inStream, - std::string *warning, std::string *err); - -/// -/// Parse texture name and texture option for custom texture parameter through -/// material::unknown_parameter -/// -/// @param[out] texname Parsed texture name -/// @param[out] texopt Parsed texopt -/// @param[in] linebuf Input string -/// -bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, - const char *linebuf); - -/// =<<========== Legacy v1 API ============================================= - -} // namespace tinyobj - -#endif // TINY_OBJ_LOADER_H_ - -#ifdef TINYOBJLOADER_IMPLEMENTATION -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT - -#ifdef TINYOBJLOADER_DONOT_INCLUDE_MAPBOX_EARCUT -// Assume earcut.hpp is included outside of tiny_obj_loader.h -#else - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Weverything" -#endif - -#include -#include "mapbox/earcut.hpp" - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#endif - -#endif // TINYOBJLOADER_USE_MAPBOX_EARCUT - -namespace tinyobj { - -MaterialReader::~MaterialReader() {} - -struct vertex_index_t { - int v_idx, vt_idx, vn_idx; - vertex_index_t() : v_idx(-1), vt_idx(-1), vn_idx(-1) {} - explicit vertex_index_t(int idx) : v_idx(idx), vt_idx(idx), vn_idx(idx) {} - vertex_index_t(int vidx, int vtidx, int vnidx) - : v_idx(vidx), vt_idx(vtidx), vn_idx(vnidx) {} -}; - -// Internal data structure for face representation -// index + smoothing group. -struct face_t { - unsigned int - smoothing_group_id; // smoothing group id. 0 = smoothing groupd is off. - int pad_; - std::vector vertex_indices; // face vertex indices. - - face_t() : smoothing_group_id(0), pad_(0) {} -}; - -// Internal data structure for line representation -struct __line_t { - // l v1/vt1 v2/vt2 ... - // In the specification, line primitrive does not have normal index, but - // TinyObjLoader allow it - std::vector vertex_indices; -}; - -// Internal data structure for points representation -struct __points_t { - // p v1 v2 ... - // In the specification, point primitrive does not have normal index and - // texture coord index, but TinyObjLoader allow it. - std::vector vertex_indices; -}; - -struct tag_sizes { - tag_sizes() : num_ints(0), num_reals(0), num_strings(0) {} - int num_ints; - int num_reals; - int num_strings; -}; - -struct obj_shape { - std::vector v; - std::vector vn; - std::vector vt; -}; - -// -// Manages group of primitives(face, line, points, ...) -struct PrimGroup { - std::vector faceGroup; - std::vector<__line_t> lineGroup; - std::vector<__points_t> pointsGroup; - - void clear() { - faceGroup.clear(); - lineGroup.clear(); - pointsGroup.clear(); - } - - bool IsEmpty() const { - return faceGroup.empty() && lineGroup.empty() && pointsGroup.empty(); - } - - // TODO(syoyo): bspline, surface, ... -}; - -// See -// http://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf -static std::istream &safeGetline(std::istream &is, std::string &t) { - t.clear(); - - // The characters in the stream are read one-by-one using a std::streambuf. - // That is faster than reading them one-by-one using the std::istream. - // Code that uses streambuf this way must be guarded by a sentry object. - // The sentry object performs various tasks, - // such as thread synchronization and updating the stream state. - - std::istream::sentry se(is, true); - std::streambuf *sb = is.rdbuf(); - - if (se) { - for (;;) { - int c = sb->sbumpc(); - switch (c) { - case '\n': - return is; - case '\r': - if (sb->sgetc() == '\n') sb->sbumpc(); - return is; - case EOF: - // Also handle the case when the last line has no line ending - if (t.empty()) is.setstate(std::ios::eofbit); - return is; - default: - t += static_cast(c); - } - } - } - - return is; -} - -#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) -#define IS_DIGIT(x) \ - (static_cast((x) - '0') < static_cast(10)) -#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) - -// Make index zero-base, and also support relative index. -static inline bool fixIndex(int idx, int n, int *ret) { - if (!ret) { - return false; - } - - if (idx > 0) { - (*ret) = idx - 1; - return true; - } - - if (idx == 0) { - // zero is not allowed according to the spec. - return false; - } - - if (idx < 0) { - (*ret) = n + idx; // negative value = relative - return true; - } - - return false; // never reach here. -} - -static inline std::string parseString(const char **token) { - std::string s; - (*token) += strspn((*token), " \t"); - size_t e = strcspn((*token), " \t\r"); - s = std::string((*token), &(*token)[e]); - (*token) += e; - return s; -} - -static inline int parseInt(const char **token) { - (*token) += strspn((*token), " \t"); - int i = atoi((*token)); - (*token) += strcspn((*token), " \t\r"); - return i; -} - -// Tries to parse a floating point number located at s. -// -// s_end should be a location in the string where reading should absolutely -// stop. For example at the end of the string, to prevent buffer overflows. -// -// Parses the following EBNF grammar: -// sign = "+" | "-" ; -// END = ? anything not in digit ? -// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; -// integer = [sign] , digit , {digit} ; -// decimal = integer , ["." , integer] ; -// float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; -// -// Valid strings are for example: -// -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 -// -// If the parsing is a success, result is set to the parsed value and true -// is returned. -// -// The function is greedy and will parse until any of the following happens: -// - a non-conforming character is encountered. -// - s_end is reached. -// -// The following situations triggers a failure: -// - s >= s_end. -// - parse failure. -// -static bool tryParseDouble(const char *s, const char *s_end, double *result) { - if (s >= s_end) { - return false; - } - - double mantissa = 0.0; - // This exponent is base 2 rather than 10. - // However the exponent we parse is supposed to be one of ten, - // thus we must take care to convert the exponent/and or the - // mantissa to a * 2^E, where a is the mantissa and E is the - // exponent. - // To get the final double we will use ldexp, it requires the - // exponent to be in base 2. - int exponent = 0; - - // NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED - // TO JUMP OVER DEFINITIONS. - char sign = '+'; - char exp_sign = '+'; - char const *curr = s; - - // How many characters were read in a loop. - int read = 0; - // Tells whether a loop terminated due to reaching s_end. - bool end_not_reached = false; - bool leading_decimal_dots = false; - - /* - BEGIN PARSING. - */ - - // Find out what sign we've got. - if (*curr == '+' || *curr == '-') { - sign = *curr; - curr++; - if ((curr != s_end) && (*curr == '.')) { - // accept. Somethig like `.7e+2`, `-.5234` - leading_decimal_dots = true; - } - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else if (*curr == '.') { - // accept. Somethig like `.7e+2`, `-.5234` - leading_decimal_dots = true; - } else { - goto fail; - } - - // Read the integer part. - end_not_reached = (curr != s_end); - if (!leading_decimal_dots) { - while (end_not_reached && IS_DIGIT(*curr)) { - mantissa *= 10; - mantissa += static_cast(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - - // We must make sure we actually got something. - if (read == 0) goto fail; - } - - // We allow numbers of form "#", "###" etc. - if (!end_not_reached) goto assemble; - - // Read the decimal part. - if (*curr == '.') { - curr++; - read = 1; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - static const double pow_lut[] = { - 1.0, 0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, - }; - const int lut_entries = sizeof pow_lut / sizeof pow_lut[0]; - - // NOTE: Don't use powf here, it will absolutely murder precision. - mantissa += static_cast(*curr - 0x30) * - (read < lut_entries ? pow_lut[read] : std::pow(10.0, -read)); - read++; - curr++; - end_not_reached = (curr != s_end); - } - } else if (*curr == 'e' || *curr == 'E') { - } else { - goto assemble; - } - - if (!end_not_reached) goto assemble; - - // Read the exponent part. - if (*curr == 'e' || *curr == 'E') { - curr++; - // Figure out if a sign is present and if it is. - end_not_reached = (curr != s_end); - if (end_not_reached && (*curr == '+' || *curr == '-')) { - exp_sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - // Empty E is not allowed. - goto fail; - } - - read = 0; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - if (exponent > std::numeric_limits::max()/10) { - // Integer overflow - goto fail; - } - exponent *= 10; - exponent += static_cast(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - exponent *= (exp_sign == '+' ? 1 : -1); - if (read == 0) goto fail; - } - -assemble: - *result = (sign == '+' ? 1 : -1) * - (exponent ? std::ldexp(mantissa * std::pow(5.0, exponent), exponent) - : mantissa); - return true; -fail: - return false; -} - -static inline real_t parseReal(const char **token, double default_value = 0.0) { - (*token) += strspn((*token), " \t"); - const char *end = (*token) + strcspn((*token), " \t\r"); - double val = default_value; - tryParseDouble((*token), end, &val); - real_t f = static_cast(val); - (*token) = end; - return f; -} - -static inline bool parseReal(const char **token, real_t *out) { - (*token) += strspn((*token), " \t"); - const char *end = (*token) + strcspn((*token), " \t\r"); - double val; - bool ret = tryParseDouble((*token), end, &val); - if (ret) { - real_t f = static_cast(val); - (*out) = f; - } - (*token) = end; - return ret; -} - -static inline void parseReal2(real_t *x, real_t *y, const char **token, - const double default_x = 0.0, - const double default_y = 0.0) { - (*x) = parseReal(token, default_x); - (*y) = parseReal(token, default_y); -} - -static inline void parseReal3(real_t *x, real_t *y, real_t *z, - const char **token, const double default_x = 0.0, - const double default_y = 0.0, - const double default_z = 0.0) { - (*x) = parseReal(token, default_x); - (*y) = parseReal(token, default_y); - (*z) = parseReal(token, default_z); -} - -static inline void parseV(real_t *x, real_t *y, real_t *z, real_t *w, - const char **token, const double default_x = 0.0, - const double default_y = 0.0, - const double default_z = 0.0, - const double default_w = 1.0) { - (*x) = parseReal(token, default_x); - (*y) = parseReal(token, default_y); - (*z) = parseReal(token, default_z); - (*w) = parseReal(token, default_w); -} - -// Extension: parse vertex with colors(6 items) -static inline bool parseVertexWithColor(real_t *x, real_t *y, real_t *z, - real_t *r, real_t *g, real_t *b, - const char **token, - const double default_x = 0.0, - const double default_y = 0.0, - const double default_z = 0.0) { - (*x) = parseReal(token, default_x); - (*y) = parseReal(token, default_y); - (*z) = parseReal(token, default_z); - - const bool found_color = - parseReal(token, r) && parseReal(token, g) && parseReal(token, b); - - if (!found_color) { - (*r) = (*g) = (*b) = 1.0; - } - - return found_color; -} - -static inline bool parseOnOff(const char **token, bool default_value = true) { - (*token) += strspn((*token), " \t"); - const char *end = (*token) + strcspn((*token), " \t\r"); - - bool ret = default_value; - if ((0 == strncmp((*token), "on", 2))) { - ret = true; - } else if ((0 == strncmp((*token), "off", 3))) { - ret = false; - } - - (*token) = end; - return ret; -} - -static inline texture_type_t parseTextureType( - const char **token, texture_type_t default_value = TEXTURE_TYPE_NONE) { - (*token) += strspn((*token), " \t"); - const char *end = (*token) + strcspn((*token), " \t\r"); - texture_type_t ty = default_value; - - if ((0 == strncmp((*token), "cube_top", strlen("cube_top")))) { - ty = TEXTURE_TYPE_CUBE_TOP; - } else if ((0 == strncmp((*token), "cube_bottom", strlen("cube_bottom")))) { - ty = TEXTURE_TYPE_CUBE_BOTTOM; - } else if ((0 == strncmp((*token), "cube_left", strlen("cube_left")))) { - ty = TEXTURE_TYPE_CUBE_LEFT; - } else if ((0 == strncmp((*token), "cube_right", strlen("cube_right")))) { - ty = TEXTURE_TYPE_CUBE_RIGHT; - } else if ((0 == strncmp((*token), "cube_front", strlen("cube_front")))) { - ty = TEXTURE_TYPE_CUBE_FRONT; - } else if ((0 == strncmp((*token), "cube_back", strlen("cube_back")))) { - ty = TEXTURE_TYPE_CUBE_BACK; - } else if ((0 == strncmp((*token), "sphere", strlen("sphere")))) { - ty = TEXTURE_TYPE_SPHERE; - } - - (*token) = end; - return ty; -} - -static tag_sizes parseTagTriple(const char **token) { - tag_sizes ts; - - (*token) += strspn((*token), " \t"); - ts.num_ints = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - return ts; - } - - (*token)++; // Skip '/' - - (*token) += strspn((*token), " \t"); - ts.num_reals = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - return ts; - } - (*token)++; // Skip '/' - - ts.num_strings = parseInt(token); - - return ts; -} - -// Parse triples with index offsets: i, i/j/k, i//k, i/j -static bool parseTriple(const char **token, int vsize, int vnsize, int vtsize, - vertex_index_t *ret) { - if (!ret) { - return false; - } - - vertex_index_t vi(-1); - - if (!fixIndex(atoi((*token)), vsize, &(vi.v_idx))) { - return false; - } - - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - (*ret) = vi; - return true; - } - (*token)++; - - // i//k - if ((*token)[0] == '/') { - (*token)++; - if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { - return false; - } - (*token) += strcspn((*token), "/ \t\r"); - (*ret) = vi; - return true; - } - - // i/j/k or i/j - if (!fixIndex(atoi((*token)), vtsize, &(vi.vt_idx))) { - return false; - } - - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - (*ret) = vi; - return true; - } - - // i/j/k - (*token)++; // skip '/' - if (!fixIndex(atoi((*token)), vnsize, &(vi.vn_idx))) { - return false; - } - (*token) += strcspn((*token), "/ \t\r"); - - (*ret) = vi; - - return true; -} - -// Parse raw triples: i, i/j/k, i//k, i/j -static vertex_index_t parseRawTriple(const char **token) { - vertex_index_t vi(static_cast(0)); // 0 is an invalid index in OBJ - - vi.v_idx = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - return vi; - } - (*token)++; - - // i//k - if ((*token)[0] == '/') { - (*token)++; - vi.vn_idx = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - return vi; - } - - // i/j/k or i/j - vi.vt_idx = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - if ((*token)[0] != '/') { - return vi; - } - - // i/j/k - (*token)++; // skip '/' - vi.vn_idx = atoi((*token)); - (*token) += strcspn((*token), "/ \t\r"); - return vi; -} - -bool ParseTextureNameAndOption(std::string *texname, texture_option_t *texopt, - const char *linebuf) { - // @todo { write more robust lexer and parser. } - bool found_texname = false; - std::string texture_name; - - const char *token = linebuf; // Assume line ends with NULL - - while (!IS_NEW_LINE((*token))) { - token += strspn(token, " \t"); // skip space - if ((0 == strncmp(token, "-blendu", 7)) && IS_SPACE((token[7]))) { - token += 8; - texopt->blendu = parseOnOff(&token, /* default */ true); - } else if ((0 == strncmp(token, "-blendv", 7)) && IS_SPACE((token[7]))) { - token += 8; - texopt->blendv = parseOnOff(&token, /* default */ true); - } else if ((0 == strncmp(token, "-clamp", 6)) && IS_SPACE((token[6]))) { - token += 7; - texopt->clamp = parseOnOff(&token, /* default */ true); - } else if ((0 == strncmp(token, "-boost", 6)) && IS_SPACE((token[6]))) { - token += 7; - texopt->sharpness = parseReal(&token, 1.0); - } else if ((0 == strncmp(token, "-bm", 3)) && IS_SPACE((token[3]))) { - token += 4; - texopt->bump_multiplier = parseReal(&token, 1.0); - } else if ((0 == strncmp(token, "-o", 2)) && IS_SPACE((token[2]))) { - token += 3; - parseReal3(&(texopt->origin_offset[0]), &(texopt->origin_offset[1]), - &(texopt->origin_offset[2]), &token); - } else if ((0 == strncmp(token, "-s", 2)) && IS_SPACE((token[2]))) { - token += 3; - parseReal3(&(texopt->scale[0]), &(texopt->scale[1]), &(texopt->scale[2]), - &token, 1.0, 1.0, 1.0); - } else if ((0 == strncmp(token, "-t", 2)) && IS_SPACE((token[2]))) { - token += 3; - parseReal3(&(texopt->turbulence[0]), &(texopt->turbulence[1]), - &(texopt->turbulence[2]), &token); - } else if ((0 == strncmp(token, "-type", 5)) && IS_SPACE((token[5]))) { - token += 5; - texopt->type = parseTextureType((&token), TEXTURE_TYPE_NONE); - } else if ((0 == strncmp(token, "-texres", 7)) && IS_SPACE((token[7]))) { - token += 7; - // TODO(syoyo): Check if arg is int type. - texopt->texture_resolution = parseInt(&token); - } else if ((0 == strncmp(token, "-imfchan", 8)) && IS_SPACE((token[8]))) { - token += 9; - token += strspn(token, " \t"); - const char *end = token + strcspn(token, " \t\r"); - if ((end - token) == 1) { // Assume one char for -imfchan - texopt->imfchan = (*token); - } - token = end; - } else if ((0 == strncmp(token, "-mm", 3)) && IS_SPACE((token[3]))) { - token += 4; - parseReal2(&(texopt->brightness), &(texopt->contrast), &token, 0.0, 1.0); - } else if ((0 == strncmp(token, "-colorspace", 11)) && - IS_SPACE((token[11]))) { - token += 12; - texopt->colorspace = parseString(&token); - } else { -// Assume texture filename -#if 0 - size_t len = strcspn(token, " \t\r"); // untile next space - texture_name = std::string(token, token + len); - token += len; - - token += strspn(token, " \t"); // skip space -#else - // Read filename until line end to parse filename containing whitespace - // TODO(syoyo): Support parsing texture option flag after the filename. - texture_name = std::string(token); - token += texture_name.length(); -#endif - - found_texname = true; - } - } - - if (found_texname) { - (*texname) = texture_name; - return true; - } else { - return false; - } -} - -static void InitTexOpt(texture_option_t *texopt, const bool is_bump) { - if (is_bump) { - texopt->imfchan = 'l'; - } else { - texopt->imfchan = 'm'; - } - texopt->bump_multiplier = static_cast(1.0); - texopt->clamp = false; - texopt->blendu = true; - texopt->blendv = true; - texopt->sharpness = static_cast(1.0); - texopt->brightness = static_cast(0.0); - texopt->contrast = static_cast(1.0); - texopt->origin_offset[0] = static_cast(0.0); - texopt->origin_offset[1] = static_cast(0.0); - texopt->origin_offset[2] = static_cast(0.0); - texopt->scale[0] = static_cast(1.0); - texopt->scale[1] = static_cast(1.0); - texopt->scale[2] = static_cast(1.0); - texopt->turbulence[0] = static_cast(0.0); - texopt->turbulence[1] = static_cast(0.0); - texopt->turbulence[2] = static_cast(0.0); - texopt->texture_resolution = -1; - texopt->type = TEXTURE_TYPE_NONE; -} - -static void InitMaterial(material_t *material) { - InitTexOpt(&material->ambient_texopt, /* is_bump */ false); - InitTexOpt(&material->diffuse_texopt, /* is_bump */ false); - InitTexOpt(&material->specular_texopt, /* is_bump */ false); - InitTexOpt(&material->specular_highlight_texopt, /* is_bump */ false); - InitTexOpt(&material->bump_texopt, /* is_bump */ true); - InitTexOpt(&material->displacement_texopt, /* is_bump */ false); - InitTexOpt(&material->alpha_texopt, /* is_bump */ false); - InitTexOpt(&material->reflection_texopt, /* is_bump */ false); - InitTexOpt(&material->roughness_texopt, /* is_bump */ false); - InitTexOpt(&material->metallic_texopt, /* is_bump */ false); - InitTexOpt(&material->sheen_texopt, /* is_bump */ false); - InitTexOpt(&material->emissive_texopt, /* is_bump */ false); - InitTexOpt(&material->normal_texopt, - /* is_bump */ false); // @fixme { is_bump will be true? } - material->name = ""; - material->ambient_texname = ""; - material->diffuse_texname = ""; - material->specular_texname = ""; - material->specular_highlight_texname = ""; - material->bump_texname = ""; - material->displacement_texname = ""; - material->reflection_texname = ""; - material->alpha_texname = ""; - for (int i = 0; i < 3; i++) { - material->ambient[i] = static_cast(0.0); - material->diffuse[i] = static_cast(0.0); - material->specular[i] = static_cast(0.0); - material->transmittance[i] = static_cast(0.0); - material->emission[i] = static_cast(0.0); - } - material->illum = 0; - material->dissolve = static_cast(1.0); - material->shininess = static_cast(1.0); - material->ior = static_cast(1.0); - - material->roughness = static_cast(0.0); - material->metallic = static_cast(0.0); - material->sheen = static_cast(0.0); - material->clearcoat_thickness = static_cast(0.0); - material->clearcoat_roughness = static_cast(0.0); - material->anisotropy_rotation = static_cast(0.0); - material->anisotropy = static_cast(0.0); - material->roughness_texname = ""; - material->metallic_texname = ""; - material->sheen_texname = ""; - material->emissive_texname = ""; - material->normal_texname = ""; - - material->unknown_parameter.clear(); -} - -// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html -template -static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) { - int i, j, c = 0; - for (i = 0, j = nvert - 1; i < nvert; j = i++) { - if (((verty[i] > testy) != (verty[j] > testy)) && - (testx < - (vertx[j] - vertx[i]) * (testy - verty[i]) / (verty[j] - verty[i]) + - vertx[i])) - c = !c; - } - return c; -} - -// TODO(syoyo): refactor function. -static bool exportGroupsToShape(shape_t *shape, const PrimGroup &prim_group, - const std::vector &tags, - const int material_id, const std::string &name, - bool triangulate, const std::vector &v, - std::string *warn) { - if (prim_group.IsEmpty()) { - return false; - } - - shape->name = name; - - // polygon - if (!prim_group.faceGroup.empty()) { - // Flatten vertices and indices - for (size_t i = 0; i < prim_group.faceGroup.size(); i++) { - const face_t &face = prim_group.faceGroup[i]; - - size_t npolys = face.vertex_indices.size(); - - if (npolys < 3) { - // Face must have 3+ vertices. - if (warn) { - (*warn) += "Degenerated face found\n."; - } - continue; - } - - if (triangulate) { - if (npolys == 4) { - vertex_index_t i0 = face.vertex_indices[0]; - vertex_index_t i1 = face.vertex_indices[1]; - vertex_index_t i2 = face.vertex_indices[2]; - vertex_index_t i3 = face.vertex_indices[3]; - - size_t vi0 = size_t(i0.v_idx); - size_t vi1 = size_t(i1.v_idx); - size_t vi2 = size_t(i2.v_idx); - size_t vi3 = size_t(i3.v_idx); - - if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || - ((3 * vi2 + 2) >= v.size()) || ((3 * vi3 + 2) >= v.size())) { - // Invalid triangle. - // FIXME(syoyo): Is it ok to simply skip this invalid triangle? - if (warn) { - (*warn) += "Face with invalid vertex index found.\n"; - } - continue; - } - - real_t v0x = v[vi0 * 3 + 0]; - real_t v0y = v[vi0 * 3 + 1]; - real_t v0z = v[vi0 * 3 + 2]; - real_t v1x = v[vi1 * 3 + 0]; - real_t v1y = v[vi1 * 3 + 1]; - real_t v1z = v[vi1 * 3 + 2]; - real_t v2x = v[vi2 * 3 + 0]; - real_t v2y = v[vi2 * 3 + 1]; - real_t v2z = v[vi2 * 3 + 2]; - real_t v3x = v[vi3 * 3 + 0]; - real_t v3y = v[vi3 * 3 + 1]; - real_t v3z = v[vi3 * 3 + 2]; - - // There are two candidates to split the quad into two triangles. - // - // Choose the shortest edge. - // TODO: Is it better to determine the edge to split by calculating - // the area of each triangle? - // - // +---+ - // |\ | - // | \ | - // | \| - // +---+ - // - // +---+ - // | /| - // | / | - // |/ | - // +---+ - - real_t e02x = v2x - v0x; - real_t e02y = v2y - v0y; - real_t e02z = v2z - v0z; - real_t e13x = v3x - v1x; - real_t e13y = v3y - v1y; - real_t e13z = v3z - v1z; - - real_t sqr02 = e02x * e02x + e02y * e02y + e02z * e02z; - real_t sqr13 = e13x * e13x + e13y * e13y + e13z * e13z; - - index_t idx0, idx1, idx2, idx3; - - idx0.vertex_index = i0.v_idx; - idx0.normal_index = i0.vn_idx; - idx0.texcoord_index = i0.vt_idx; - idx1.vertex_index = i1.v_idx; - idx1.normal_index = i1.vn_idx; - idx1.texcoord_index = i1.vt_idx; - idx2.vertex_index = i2.v_idx; - idx2.normal_index = i2.vn_idx; - idx2.texcoord_index = i2.vt_idx; - idx3.vertex_index = i3.v_idx; - idx3.normal_index = i3.vn_idx; - idx3.texcoord_index = i3.vt_idx; - - if (sqr02 < sqr13) { - // [0, 1, 2], [0, 2, 3] - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); - - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx2); - shape->mesh.indices.push_back(idx3); - } else { - // [0, 1, 3], [1, 2, 3] - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx3); - - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); - shape->mesh.indices.push_back(idx3); - } - - // Two triangle faces - shape->mesh.num_face_vertices.push_back(3); - shape->mesh.num_face_vertices.push_back(3); - - shape->mesh.material_ids.push_back(material_id); - shape->mesh.material_ids.push_back(material_id); - - shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); - shape->mesh.smoothing_group_ids.push_back(face.smoothing_group_id); - - } else { - vertex_index_t i0 = face.vertex_indices[0]; - vertex_index_t i1(-1); - vertex_index_t i2 = face.vertex_indices[1]; - - // find the two axes to work in - size_t axes[2] = {1, 2}; - for (size_t k = 0; k < npolys; ++k) { - i0 = face.vertex_indices[(k + 0) % npolys]; - i1 = face.vertex_indices[(k + 1) % npolys]; - i2 = face.vertex_indices[(k + 2) % npolys]; - size_t vi0 = size_t(i0.v_idx); - size_t vi1 = size_t(i1.v_idx); - size_t vi2 = size_t(i2.v_idx); - - if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) || - ((3 * vi2 + 2) >= v.size())) { - // Invalid triangle. - // FIXME(syoyo): Is it ok to simply skip this invalid triangle? - continue; - } - real_t v0x = v[vi0 * 3 + 0]; - real_t v0y = v[vi0 * 3 + 1]; - real_t v0z = v[vi0 * 3 + 2]; - real_t v1x = v[vi1 * 3 + 0]; - real_t v1y = v[vi1 * 3 + 1]; - real_t v1z = v[vi1 * 3 + 2]; - real_t v2x = v[vi2 * 3 + 0]; - real_t v2y = v[vi2 * 3 + 1]; - real_t v2z = v[vi2 * 3 + 2]; - real_t e0x = v1x - v0x; - real_t e0y = v1y - v0y; - real_t e0z = v1z - v0z; - real_t e1x = v2x - v1x; - real_t e1y = v2y - v1y; - real_t e1z = v2z - v1z; - real_t cx = std::fabs(e0y * e1z - e0z * e1y); - real_t cy = std::fabs(e0z * e1x - e0x * e1z); - real_t cz = std::fabs(e0x * e1y - e0y * e1x); - const real_t epsilon = std::numeric_limits::epsilon(); - // std::cout << "cx " << cx << ", cy " << cy << ", cz " << cz << - // "\n"; - if (cx > epsilon || cy > epsilon || cz > epsilon) { - // std::cout << "corner\n"; - // found a corner - if (cx > cy && cx > cz) { - // std::cout << "pattern0\n"; - } else { - // std::cout << "axes[0] = 0\n"; - axes[0] = 0; - if (cz > cx && cz > cy) { - // std::cout << "axes[1] = 1\n"; - axes[1] = 1; - } - } - break; - } - } - -#ifdef TINYOBJLOADER_USE_MAPBOX_EARCUT - using Point = std::array; - - // first polyline define the main polygon. - // following polylines define holes(not used in tinyobj). - std::vector > polygon; - - std::vector polyline; - - // Fill polygon data(facevarying vertices). - for (size_t k = 0; k < npolys; k++) { - i0 = face.vertex_indices[k]; - size_t vi0 = size_t(i0.v_idx); - - assert(((3 * vi0 + 2) < v.size())); - - real_t v0x = v[vi0 * 3 + axes[0]]; - real_t v0y = v[vi0 * 3 + axes[1]]; - - polyline.push_back({v0x, v0y}); - } - - polygon.push_back(polyline); - std::vector indices = mapbox::earcut(polygon); - // => result = 3 * faces, clockwise - - assert(indices.size() % 3 == 0); - - // Reconstruct vertex_index_t - for (size_t k = 0; k < indices.size() / 3; k++) { - { - index_t idx0, idx1, idx2; - idx0.vertex_index = face.vertex_indices[indices[3 * k + 0]].v_idx; - idx0.normal_index = - face.vertex_indices[indices[3 * k + 0]].vn_idx; - idx0.texcoord_index = - face.vertex_indices[indices[3 * k + 0]].vt_idx; - idx1.vertex_index = face.vertex_indices[indices[3 * k + 1]].v_idx; - idx1.normal_index = - face.vertex_indices[indices[3 * k + 1]].vn_idx; - idx1.texcoord_index = - face.vertex_indices[indices[3 * k + 1]].vt_idx; - idx2.vertex_index = face.vertex_indices[indices[3 * k + 2]].v_idx; - idx2.normal_index = - face.vertex_indices[indices[3 * k + 2]].vn_idx; - idx2.texcoord_index = - face.vertex_indices[indices[3 * k + 2]].vt_idx; - - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); - - shape->mesh.num_face_vertices.push_back(3); - shape->mesh.material_ids.push_back(material_id); - shape->mesh.smoothing_group_ids.push_back( - face.smoothing_group_id); - } - } - -#else // Built-in ear clipping triangulation - - - face_t remainingFace = face; // copy - size_t guess_vert = 0; - vertex_index_t ind[3]; - real_t vx[3]; - real_t vy[3]; - - // How many iterations can we do without decreasing the remaining - // vertices. - size_t remainingIterations = face.vertex_indices.size(); - size_t previousRemainingVertices = - remainingFace.vertex_indices.size(); - - while (remainingFace.vertex_indices.size() > 3 && - remainingIterations > 0) { - // std::cout << "remainingIterations " << remainingIterations << - // "\n"; - - npolys = remainingFace.vertex_indices.size(); - if (guess_vert >= npolys) { - guess_vert -= npolys; - } - - if (previousRemainingVertices != npolys) { - // The number of remaining vertices decreased. Reset counters. - previousRemainingVertices = npolys; - remainingIterations = npolys; - } else { - // We didn't consume a vertex on previous iteration, reduce the - // available iterations. - remainingIterations--; - } - - for (size_t k = 0; k < 3; k++) { - ind[k] = remainingFace.vertex_indices[(guess_vert + k) % npolys]; - size_t vi = size_t(ind[k].v_idx); - if (((vi * 3 + axes[0]) >= v.size()) || - ((vi * 3 + axes[1]) >= v.size())) { - // ??? - vx[k] = static_cast(0.0); - vy[k] = static_cast(0.0); - } else { - vx[k] = v[vi * 3 + axes[0]]; - vy[k] = v[vi * 3 + axes[1]]; - } - } - - // - // area is calculated per face - // - real_t e0x = vx[1] - vx[0]; - real_t e0y = vy[1] - vy[0]; - real_t e1x = vx[2] - vx[1]; - real_t e1y = vy[2] - vy[1]; - real_t cross = e0x * e1y - e0y * e1x; - // std::cout << "axes = " << axes[0] << ", " << axes[1] << "\n"; - // std::cout << "e0x, e0y, e1x, e1y " << e0x << ", " << e0y << ", " - // << e1x << ", " << e1y << "\n"; - - real_t area = (vx[0] * vy[1] - vy[0] * vx[1]) * static_cast(0.5); - // std::cout << "cross " << cross << ", area " << area << "\n"; - // if an internal angle - if (cross * area < static_cast(0.0)) { - // std::cout << "internal \n"; - guess_vert += 1; - // std::cout << "guess vert : " << guess_vert << "\n"; - continue; - } - - // check all other verts in case they are inside this triangle - bool overlap = false; - for (size_t otherVert = 3; otherVert < npolys; ++otherVert) { - size_t idx = (guess_vert + otherVert) % npolys; - - if (idx >= remainingFace.vertex_indices.size()) { - // std::cout << "???0\n"; - // ??? - continue; - } - - size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx); - - if (((ovi * 3 + axes[0]) >= v.size()) || - ((ovi * 3 + axes[1]) >= v.size())) { - // std::cout << "???1\n"; - // ??? - continue; - } - real_t tx = v[ovi * 3 + axes[0]]; - real_t ty = v[ovi * 3 + axes[1]]; - if (pnpoly(3, vx, vy, tx, ty)) { - // std::cout << "overlap\n"; - overlap = true; - break; - } - } - - if (overlap) { - // std::cout << "overlap2\n"; - guess_vert += 1; - continue; - } - - // this triangle is an ear - { - index_t idx0, idx1, idx2; - idx0.vertex_index = ind[0].v_idx; - idx0.normal_index = ind[0].vn_idx; - idx0.texcoord_index = ind[0].vt_idx; - idx1.vertex_index = ind[1].v_idx; - idx1.normal_index = ind[1].vn_idx; - idx1.texcoord_index = ind[1].vt_idx; - idx2.vertex_index = ind[2].v_idx; - idx2.normal_index = ind[2].vn_idx; - idx2.texcoord_index = ind[2].vt_idx; - - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); - - shape->mesh.num_face_vertices.push_back(3); - shape->mesh.material_ids.push_back(material_id); - shape->mesh.smoothing_group_ids.push_back( - face.smoothing_group_id); - } - - // remove v1 from the list - size_t removed_vert_index = (guess_vert + 1) % npolys; - while (removed_vert_index + 1 < npolys) { - remainingFace.vertex_indices[removed_vert_index] = - remainingFace.vertex_indices[removed_vert_index + 1]; - removed_vert_index += 1; - } - remainingFace.vertex_indices.pop_back(); - } - - // std::cout << "remainingFace.vi.size = " << - // remainingFace.vertex_indices.size() << "\n"; - if (remainingFace.vertex_indices.size() == 3) { - i0 = remainingFace.vertex_indices[0]; - i1 = remainingFace.vertex_indices[1]; - i2 = remainingFace.vertex_indices[2]; - { - index_t idx0, idx1, idx2; - idx0.vertex_index = i0.v_idx; - idx0.normal_index = i0.vn_idx; - idx0.texcoord_index = i0.vt_idx; - idx1.vertex_index = i1.v_idx; - idx1.normal_index = i1.vn_idx; - idx1.texcoord_index = i1.vt_idx; - idx2.vertex_index = i2.v_idx; - idx2.normal_index = i2.vn_idx; - idx2.texcoord_index = i2.vt_idx; - - shape->mesh.indices.push_back(idx0); - shape->mesh.indices.push_back(idx1); - shape->mesh.indices.push_back(idx2); - - shape->mesh.num_face_vertices.push_back(3); - shape->mesh.material_ids.push_back(material_id); - shape->mesh.smoothing_group_ids.push_back( - face.smoothing_group_id); - } - } -#endif - } // npolys - } else { - for (size_t k = 0; k < npolys; k++) { - index_t idx; - idx.vertex_index = face.vertex_indices[k].v_idx; - idx.normal_index = face.vertex_indices[k].vn_idx; - idx.texcoord_index = face.vertex_indices[k].vt_idx; - shape->mesh.indices.push_back(idx); - } - - shape->mesh.num_face_vertices.push_back( - static_cast(npolys)); - shape->mesh.material_ids.push_back(material_id); // per face - shape->mesh.smoothing_group_ids.push_back( - face.smoothing_group_id); // per face - } - } - - shape->mesh.tags = tags; - } - - // line - if (!prim_group.lineGroup.empty()) { - // Flatten indices - for (size_t i = 0; i < prim_group.lineGroup.size(); i++) { - for (size_t j = 0; j < prim_group.lineGroup[i].vertex_indices.size(); - j++) { - const vertex_index_t &vi = prim_group.lineGroup[i].vertex_indices[j]; - - index_t idx; - idx.vertex_index = vi.v_idx; - idx.normal_index = vi.vn_idx; - idx.texcoord_index = vi.vt_idx; - - shape->lines.indices.push_back(idx); - } - - shape->lines.num_line_vertices.push_back( - int(prim_group.lineGroup[i].vertex_indices.size())); - } - } - - // points - if (!prim_group.pointsGroup.empty()) { - // Flatten & convert indices - for (size_t i = 0; i < prim_group.pointsGroup.size(); i++) { - for (size_t j = 0; j < prim_group.pointsGroup[i].vertex_indices.size(); - j++) { - const vertex_index_t &vi = prim_group.pointsGroup[i].vertex_indices[j]; - - index_t idx; - idx.vertex_index = vi.v_idx; - idx.normal_index = vi.vn_idx; - idx.texcoord_index = vi.vt_idx; - - shape->points.indices.push_back(idx); - } - } - } - - return true; -} - -// Split a string with specified delimiter character and escape character. -// https://rosettacode.org/wiki/Tokenize_a_string_with_escaping#C.2B.2B -static void SplitString(const std::string &s, char delim, char escape, - std::vector &elems) { - std::string token; - - bool escaping = false; - for (size_t i = 0; i < s.size(); ++i) { - char ch = s[i]; - if (escaping) { - escaping = false; - } else if (ch == escape) { - escaping = true; - continue; - } else if (ch == delim) { - if (!token.empty()) { - elems.push_back(token); - } - token.clear(); - continue; - } - token += ch; - } - - elems.push_back(token); -} - -static std::string JoinPath(const std::string &dir, - const std::string &filename) { - if (dir.empty()) { - return filename; - } else { - // check '/' - char lastChar = *dir.rbegin(); - if (lastChar != '/') { - return dir + std::string("/") + filename; - } else { - return dir + filename; - } - } -} - -void LoadMtl(std::map *material_map, - std::vector *materials, std::istream *inStream, - std::string *warning, std::string *err) { - (void)err; - - // Create a default material anyway. - material_t material; - InitMaterial(&material); - - // Issue 43. `d` wins against `Tr` since `Tr` is not in the MTL specification. - bool has_d = false; - bool has_tr = false; - - // has_kd is used to set a default diffuse value when map_Kd is present - // and Kd is not. - bool has_kd = false; - - std::stringstream warn_ss; - - size_t line_no = 0; - std::string linebuf; - while (inStream->peek() != -1) { - safeGetline(*inStream, linebuf); - line_no++; - - // Trim trailing whitespace. - if (linebuf.size() > 0) { - linebuf = linebuf.substr(0, linebuf.find_last_not_of(" \t") + 1); - } - - // Trim newline '\r\n' or '\n' - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\n') - linebuf.erase(linebuf.size() - 1); - } - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\r') - linebuf.erase(linebuf.size() - 1); - } - - // Skip if empty line. - if (linebuf.empty()) { - continue; - } - - // Skip leading space. - const char *token = linebuf.c_str(); - token += strspn(token, " \t"); - - assert(token); - if (token[0] == '\0') continue; // empty line - - if (token[0] == '#') continue; // comment line - - // new mtl - if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { - // flush previous material. - if (!material.name.empty()) { - material_map->insert(std::pair( - material.name, static_cast(materials->size()))); - materials->push_back(material); - } - - // initial temporary material - InitMaterial(&material); - - has_d = false; - has_tr = false; - - // set new mtl name - token += 7; - { - std::stringstream sstr; - sstr << token; - material.name = sstr.str(); - } - continue; - } - - // ambient - if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { - token += 2; - real_t r, g, b; - parseReal3(&r, &g, &b, &token); - material.ambient[0] = r; - material.ambient[1] = g; - material.ambient[2] = b; - continue; - } - - // diffuse - if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { - token += 2; - real_t r, g, b; - parseReal3(&r, &g, &b, &token); - material.diffuse[0] = r; - material.diffuse[1] = g; - material.diffuse[2] = b; - has_kd = true; - continue; - } - - // specular - if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { - token += 2; - real_t r, g, b; - parseReal3(&r, &g, &b, &token); - material.specular[0] = r; - material.specular[1] = g; - material.specular[2] = b; - continue; - } - - // transmittance - if ((token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) || - (token[0] == 'T' && token[1] == 'f' && IS_SPACE((token[2])))) { - token += 2; - real_t r, g, b; - parseReal3(&r, &g, &b, &token); - material.transmittance[0] = r; - material.transmittance[1] = g; - material.transmittance[2] = b; - continue; - } - - // ior(index of refraction) - if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { - token += 2; - material.ior = parseReal(&token); - continue; - } - - // emission - if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { - token += 2; - real_t r, g, b; - parseReal3(&r, &g, &b, &token); - material.emission[0] = r; - material.emission[1] = g; - material.emission[2] = b; - continue; - } - - // shininess - if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { - token += 2; - material.shininess = parseReal(&token); - continue; - } - - // illum model - if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { - token += 6; - material.illum = parseInt(&token); - continue; - } - - // dissolve - if ((token[0] == 'd' && IS_SPACE(token[1]))) { - token += 1; - material.dissolve = parseReal(&token); - - if (has_tr) { - warn_ss << "Both `d` and `Tr` parameters defined for \"" - << material.name - << "\". Use the value of `d` for dissolve (line " << line_no - << " in .mtl.)\n"; - } - has_d = true; - continue; - } - if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { - token += 2; - if (has_d) { - // `d` wins. Ignore `Tr` value. - warn_ss << "Both `d` and `Tr` parameters defined for \"" - << material.name - << "\". Use the value of `d` for dissolve (line " << line_no - << " in .mtl.)\n"; - } else { - // We invert value of Tr(assume Tr is in range [0, 1]) - // NOTE: Interpretation of Tr is application(exporter) dependent. For - // some application(e.g. 3ds max obj exporter), Tr = d(Issue 43) - material.dissolve = static_cast(1.0) - parseReal(&token); - } - has_tr = true; - continue; - } - - // PBR: roughness - if (token[0] == 'P' && token[1] == 'r' && IS_SPACE(token[2])) { - token += 2; - material.roughness = parseReal(&token); - continue; - } - - // PBR: metallic - if (token[0] == 'P' && token[1] == 'm' && IS_SPACE(token[2])) { - token += 2; - material.metallic = parseReal(&token); - continue; - } - - // PBR: sheen - if (token[0] == 'P' && token[1] == 's' && IS_SPACE(token[2])) { - token += 2; - material.sheen = parseReal(&token); - continue; - } - - // PBR: clearcoat thickness - if (token[0] == 'P' && token[1] == 'c' && IS_SPACE(token[2])) { - token += 2; - material.clearcoat_thickness = parseReal(&token); - continue; - } - - // PBR: clearcoat roughness - if ((0 == strncmp(token, "Pcr", 3)) && IS_SPACE(token[3])) { - token += 4; - material.clearcoat_roughness = parseReal(&token); - continue; - } - - // PBR: anisotropy - if ((0 == strncmp(token, "aniso", 5)) && IS_SPACE(token[5])) { - token += 6; - material.anisotropy = parseReal(&token); - continue; - } - - // PBR: anisotropy rotation - if ((0 == strncmp(token, "anisor", 6)) && IS_SPACE(token[6])) { - token += 7; - material.anisotropy_rotation = parseReal(&token); - continue; - } - - // ambient texture - if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.ambient_texname), - &(material.ambient_texopt), token); - continue; - } - - // diffuse texture - if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.diffuse_texname), - &(material.diffuse_texopt), token); - - // Set a decent diffuse default value if a diffuse texture is specified - // without a matching Kd value. - if (!has_kd) { - material.diffuse[0] = static_cast(0.6); - material.diffuse[1] = static_cast(0.6); - material.diffuse[2] = static_cast(0.6); - } - - continue; - } - - // specular texture - if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.specular_texname), - &(material.specular_texopt), token); - continue; - } - - // specular highlight texture - if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.specular_highlight_texname), - &(material.specular_highlight_texopt), token); - continue; - } - - // bump texture - if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { - token += 9; - ParseTextureNameAndOption(&(material.bump_texname), - &(material.bump_texopt), token); - continue; - } - - // bump texture - if ((0 == strncmp(token, "map_Bump", 8)) && IS_SPACE(token[8])) { - token += 9; - ParseTextureNameAndOption(&(material.bump_texname), - &(material.bump_texopt), token); - continue; - } - - // bump texture - if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { - token += 5; - ParseTextureNameAndOption(&(material.bump_texname), - &(material.bump_texopt), token); - continue; - } - - // alpha texture - if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { - token += 6; - material.alpha_texname = token; - ParseTextureNameAndOption(&(material.alpha_texname), - &(material.alpha_texopt), token); - continue; - } - - // displacement texture - if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { - token += 5; - ParseTextureNameAndOption(&(material.displacement_texname), - &(material.displacement_texopt), token); - continue; - } - - // reflection map - if ((0 == strncmp(token, "refl", 4)) && IS_SPACE(token[4])) { - token += 5; - ParseTextureNameAndOption(&(material.reflection_texname), - &(material.reflection_texopt), token); - continue; - } - - // PBR: roughness texture - if ((0 == strncmp(token, "map_Pr", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.roughness_texname), - &(material.roughness_texopt), token); - continue; - } - - // PBR: metallic texture - if ((0 == strncmp(token, "map_Pm", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.metallic_texname), - &(material.metallic_texopt), token); - continue; - } - - // PBR: sheen texture - if ((0 == strncmp(token, "map_Ps", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.sheen_texname), - &(material.sheen_texopt), token); - continue; - } - - // PBR: emissive texture - if ((0 == strncmp(token, "map_Ke", 6)) && IS_SPACE(token[6])) { - token += 7; - ParseTextureNameAndOption(&(material.emissive_texname), - &(material.emissive_texopt), token); - continue; - } - - // PBR: normal map texture - if ((0 == strncmp(token, "norm", 4)) && IS_SPACE(token[4])) { - token += 5; - ParseTextureNameAndOption(&(material.normal_texname), - &(material.normal_texopt), token); - continue; - } - - // unknown parameter - const char *_space = strchr(token, ' '); - if (!_space) { - _space = strchr(token, '\t'); - } - if (_space) { - std::ptrdiff_t len = _space - token; - std::string key(token, static_cast(len)); - std::string value = _space + 1; - material.unknown_parameter.insert( - std::pair(key, value)); - } - } - // flush last material. - material_map->insert(std::pair( - material.name, static_cast(materials->size()))); - materials->push_back(material); - - if (warning) { - (*warning) = warn_ss.str(); - } -} - -bool MaterialFileReader::operator()(const std::string &matId, - std::vector *materials, - std::map *matMap, - std::string *warn, std::string *err) { - if (!m_mtlBaseDir.empty()) { -#ifdef _WIN32 - char sep = ';'; -#else - char sep = ':'; -#endif - - // https://stackoverflow.com/questions/5167625/splitting-a-c-stdstring-using-tokens-e-g - std::vector paths; - std::istringstream f(m_mtlBaseDir); - - std::string s; - while (getline(f, s, sep)) { - paths.push_back(s); - } - - for (size_t i = 0; i < paths.size(); i++) { - std::string filepath = JoinPath(paths[i], matId); - - std::ifstream matIStream(filepath.c_str()); - if (matIStream) { - LoadMtl(matMap, materials, &matIStream, warn, err); - - return true; - } - } - - std::stringstream ss; - ss << "Material file [ " << matId - << " ] not found in a path : " << m_mtlBaseDir << "\n"; - if (warn) { - (*warn) += ss.str(); - } - return false; - - } else { - std::string filepath = matId; - std::ifstream matIStream(filepath.c_str()); - if (matIStream) { - LoadMtl(matMap, materials, &matIStream, warn, err); - - return true; - } - - std::stringstream ss; - ss << "Material file [ " << filepath - << " ] not found in a path : " << m_mtlBaseDir << "\n"; - if (warn) { - (*warn) += ss.str(); - } - - return false; - } -} - -bool MaterialStreamReader::operator()(const std::string &matId, - std::vector *materials, - std::map *matMap, - std::string *warn, std::string *err) { - (void)err; - (void)matId; - if (!m_inStream) { - std::stringstream ss; - ss << "Material stream in error state. \n"; - if (warn) { - (*warn) += ss.str(); - } - return false; - } - - LoadMtl(matMap, materials, &m_inStream, warn, err); - - return true; -} - -bool LoadObj(attrib_t *attrib, std::vector *shapes, - std::vector *materials, std::string *warn, - std::string *err, const char *filename, const char *mtl_basedir, - bool triangulate, bool default_vcols_fallback) { - attrib->vertices.clear(); - attrib->normals.clear(); - attrib->texcoords.clear(); - attrib->colors.clear(); - shapes->clear(); - - std::stringstream errss; - - std::ifstream ifs(filename); - if (!ifs) { - errss << "Cannot open file [" << filename << "]\n"; - if (err) { - (*err) = errss.str(); - } - return false; - } - - std::string baseDir = mtl_basedir ? mtl_basedir : ""; - if (!baseDir.empty()) { -#ifndef _WIN32 - const char dirsep = '/'; -#else - const char dirsep = '\\'; -#endif - if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep; - } - MaterialFileReader matFileReader(baseDir); - - return LoadObj(attrib, shapes, materials, warn, err, &ifs, &matFileReader, - triangulate, default_vcols_fallback); -} - -bool LoadObj(attrib_t *attrib, std::vector *shapes, - std::vector *materials, std::string *warn, - std::string *err, std::istream *inStream, - MaterialReader *readMatFn /*= NULL*/, bool triangulate, - bool default_vcols_fallback) { - std::stringstream errss; - - std::vector v; - std::vector vn; - std::vector vt; - std::vector vc; - std::vector vw; - std::vector tags; - PrimGroup prim_group; - std::string name; - - // material - std::map material_map; - int material = -1; - - // smoothing group id - unsigned int current_smoothing_id = - 0; // Initial value. 0 means no smoothing. - - int greatest_v_idx = -1; - int greatest_vn_idx = -1; - int greatest_vt_idx = -1; - - shape_t shape; - - bool found_all_colors = true; - - size_t line_num = 0; - std::string linebuf; - while (inStream->peek() != -1) { - safeGetline(*inStream, linebuf); - - line_num++; - - // Trim newline '\r\n' or '\n' - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\n') - linebuf.erase(linebuf.size() - 1); - } - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\r') - linebuf.erase(linebuf.size() - 1); - } - - // Skip if empty line. - if (linebuf.empty()) { - continue; - } - - // Skip leading space. - const char *token = linebuf.c_str(); - token += strspn(token, " \t"); - - assert(token); - if (token[0] == '\0') continue; // empty line - - if (token[0] == '#') continue; // comment line - - // vertex - if (token[0] == 'v' && IS_SPACE((token[1]))) { - token += 2; - real_t x, y, z; - real_t r, g, b; - - found_all_colors &= parseVertexWithColor(&x, &y, &z, &r, &g, &b, &token); - - v.push_back(x); - v.push_back(y); - v.push_back(z); - - if (found_all_colors || default_vcols_fallback) { - vc.push_back(r); - vc.push_back(g); - vc.push_back(b); - } - - continue; - } - - // normal - if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { - token += 3; - real_t x, y, z; - parseReal3(&x, &y, &z, &token); - vn.push_back(x); - vn.push_back(y); - vn.push_back(z); - continue; - } - - // texcoord - if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { - token += 3; - real_t x, y; - parseReal2(&x, &y, &token); - vt.push_back(x); - vt.push_back(y); - continue; - } - - // skin weight. tinyobj extension - if (token[0] == 'v' && token[1] == 'w' && IS_SPACE((token[2]))) { - token += 3; - - // vw ... - // example: - // vw 0 0 0.25 1 0.25 2 0.5 - - // TODO(syoyo): Add syntax check - int vid = 0; - vid = parseInt(&token); - - skin_weight_t sw; - - sw.vertex_id = vid; - - while (!IS_NEW_LINE(token[0])) { - real_t j, w; - // joint_id should not be negative, weight may be negative - // TODO(syoyo): # of elements check - parseReal2(&j, &w, &token, -1.0); - - if (j < static_cast(0)) { - if (err) { - std::stringstream ss; - ss << "Failed parse `vw' line. joint_id is negative. " - "line " - << line_num << ".)\n"; - (*err) += ss.str(); - } - return false; - } - - joint_and_weight_t jw; - - jw.joint_id = int(j); - jw.weight = w; - - sw.weightValues.push_back(jw); - - size_t n = strspn(token, " \t\r"); - token += n; - } - - vw.push_back(sw); - } - - // line - if (token[0] == 'l' && IS_SPACE((token[1]))) { - token += 2; - - __line_t line; - - while (!IS_NEW_LINE(token[0])) { - vertex_index_t vi; - if (!parseTriple(&token, static_cast(v.size() / 3), - static_cast(vn.size() / 3), - static_cast(vt.size() / 2), &vi)) { - if (err) { - std::stringstream ss; - ss << "Failed parse `l' line(e.g. zero value for vertex index. " - "line " - << line_num << ".)\n"; - (*err) += ss.str(); - } - return false; - } - - line.vertex_indices.push_back(vi); - - size_t n = strspn(token, " \t\r"); - token += n; - } - - prim_group.lineGroup.push_back(line); - - continue; - } - - // points - if (token[0] == 'p' && IS_SPACE((token[1]))) { - token += 2; - - __points_t pts; - - while (!IS_NEW_LINE(token[0])) { - vertex_index_t vi; - if (!parseTriple(&token, static_cast(v.size() / 3), - static_cast(vn.size() / 3), - static_cast(vt.size() / 2), &vi)) { - if (err) { - std::stringstream ss; - ss << "Failed parse `p' line(e.g. zero value for vertex index. " - "line " - << line_num << ".)\n"; - (*err) += ss.str(); - } - return false; - } - - pts.vertex_indices.push_back(vi); - - size_t n = strspn(token, " \t\r"); - token += n; - } - - prim_group.pointsGroup.push_back(pts); - - continue; - } - - // face - if (token[0] == 'f' && IS_SPACE((token[1]))) { - token += 2; - token += strspn(token, " \t"); - - face_t face; - - face.smoothing_group_id = current_smoothing_id; - face.vertex_indices.reserve(3); - - while (!IS_NEW_LINE(token[0])) { - vertex_index_t vi; - if (!parseTriple(&token, static_cast(v.size() / 3), - static_cast(vn.size() / 3), - static_cast(vt.size() / 2), &vi)) { - if (err) { - std::stringstream ss; - ss << "Failed parse `f' line(e.g. zero value for face index. line " - << line_num << ".)\n"; - (*err) += ss.str(); - } - return false; - } - - greatest_v_idx = greatest_v_idx > vi.v_idx ? greatest_v_idx : vi.v_idx; - greatest_vn_idx = - greatest_vn_idx > vi.vn_idx ? greatest_vn_idx : vi.vn_idx; - greatest_vt_idx = - greatest_vt_idx > vi.vt_idx ? greatest_vt_idx : vi.vt_idx; - - face.vertex_indices.push_back(vi); - size_t n = strspn(token, " \t\r"); - token += n; - } - - // replace with emplace_back + std::move on C++11 - prim_group.faceGroup.push_back(face); - - continue; - } - - // use mtl - if ((0 == strncmp(token, "usemtl", 6))) { - token += 6; - std::string namebuf = parseString(&token); - - int newMaterialId = -1; - std::map::const_iterator it = - material_map.find(namebuf); - if (it != material_map.end()) { - newMaterialId = it->second; - } else { - // { error!! material not found } - if (warn) { - (*warn) += "material [ '" + namebuf + "' ] not found in .mtl\n"; - } - } - - if (newMaterialId != material) { - // Create per-face material. Thus we don't add `shape` to `shapes` at - // this time. - // just clear `faceGroup` after `exportGroupsToShape()` call. - exportGroupsToShape(&shape, prim_group, tags, material, name, - triangulate, v, warn); - prim_group.faceGroup.clear(); - material = newMaterialId; - } - - continue; - } - - // load mtl - if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { - if (readMatFn) { - token += 7; - - std::vector filenames; - SplitString(std::string(token), ' ', '\\', filenames); - - if (filenames.empty()) { - if (warn) { - std::stringstream ss; - ss << "Looks like empty filename for mtllib. Use default " - "material (line " - << line_num << ".)\n"; - - (*warn) += ss.str(); - } - } else { - bool found = false; - for (size_t s = 0; s < filenames.size(); s++) { - std::string warn_mtl; - std::string err_mtl; - bool ok = (*readMatFn)(filenames[s].c_str(), materials, - &material_map, &warn_mtl, &err_mtl); - if (warn && (!warn_mtl.empty())) { - (*warn) += warn_mtl; - } - - if (err && (!err_mtl.empty())) { - (*err) += err_mtl; - } - - if (ok) { - found = true; - break; - } - } - - if (!found) { - if (warn) { - (*warn) += - "Failed to load material file(s). Use default " - "material.\n"; - } - } - } - } - - continue; - } - - // group name - if (token[0] == 'g' && IS_SPACE((token[1]))) { - // flush previous face group. - bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, - triangulate, v, warn); - (void)ret; // return value not used. - - if (shape.mesh.indices.size() > 0) { - shapes->push_back(shape); - } - - shape = shape_t(); - - // material = -1; - prim_group.clear(); - - std::vector names; - - while (!IS_NEW_LINE(token[0])) { - std::string str = parseString(&token); - names.push_back(str); - token += strspn(token, " \t\r"); // skip tag - } - - // names[0] must be 'g' - - if (names.size() < 2) { - // 'g' with empty names - if (warn) { - std::stringstream ss; - ss << "Empty group name. line: " << line_num << "\n"; - (*warn) += ss.str(); - name = ""; - } - } else { - std::stringstream ss; - ss << names[1]; - - // tinyobjloader does not support multiple groups for a primitive. - // Currently we concatinate multiple group names with a space to get - // single group name. - - for (size_t i = 2; i < names.size(); i++) { - ss << " " << names[i]; - } - - name = ss.str(); - } - - continue; - } - - // object name - if (token[0] == 'o' && IS_SPACE((token[1]))) { - // flush previous face group. - bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, - triangulate, v, warn); - (void)ret; // return value not used. - - if (shape.mesh.indices.size() > 0 || shape.lines.indices.size() > 0 || - shape.points.indices.size() > 0) { - shapes->push_back(shape); - } - - // material = -1; - prim_group.clear(); - shape = shape_t(); - - // @todo { multiple object name? } - token += 2; - std::stringstream ss; - ss << token; - name = ss.str(); - - continue; - } - - if (token[0] == 't' && IS_SPACE(token[1])) { - const int max_tag_nums = 8192; // FIXME(syoyo): Parameterize. - tag_t tag; - - token += 2; - - tag.name = parseString(&token); - - tag_sizes ts = parseTagTriple(&token); - - if (ts.num_ints < 0) { - ts.num_ints = 0; - } - if (ts.num_ints > max_tag_nums) { - ts.num_ints = max_tag_nums; - } - - if (ts.num_reals < 0) { - ts.num_reals = 0; - } - if (ts.num_reals > max_tag_nums) { - ts.num_reals = max_tag_nums; - } - - if (ts.num_strings < 0) { - ts.num_strings = 0; - } - if (ts.num_strings > max_tag_nums) { - ts.num_strings = max_tag_nums; - } - - tag.intValues.resize(static_cast(ts.num_ints)); - - for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { - tag.intValues[i] = parseInt(&token); - } - - tag.floatValues.resize(static_cast(ts.num_reals)); - for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { - tag.floatValues[i] = parseReal(&token); - } - - tag.stringValues.resize(static_cast(ts.num_strings)); - for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { - tag.stringValues[i] = parseString(&token); - } - - tags.push_back(tag); - - continue; - } - - if (token[0] == 's' && IS_SPACE(token[1])) { - // smoothing group id - token += 2; - - // skip space. - token += strspn(token, " \t"); // skip space - - if (token[0] == '\0') { - continue; - } - - if (token[0] == '\r' || token[1] == '\n') { - continue; - } - - if (strlen(token) >= 3 && token[0] == 'o' && token[1] == 'f' && - token[2] == 'f') { - current_smoothing_id = 0; - } else { - // assume number - int smGroupId = parseInt(&token); - if (smGroupId < 0) { - // parse error. force set to 0. - // FIXME(syoyo): Report warning. - current_smoothing_id = 0; - } else { - current_smoothing_id = static_cast(smGroupId); - } - } - - continue; - } // smoothing group id - - // Ignore unknown command. - } - - // not all vertices have colors, no default colors desired? -> clear colors - if (!found_all_colors && !default_vcols_fallback) { - vc.clear(); - } - - if (greatest_v_idx >= static_cast(v.size() / 3)) { - if (warn) { - std::stringstream ss; - ss << "Vertex indices out of bounds (line " << line_num << ".)\n\n"; - (*warn) += ss.str(); - } - } - if (greatest_vn_idx >= static_cast(vn.size() / 3)) { - if (warn) { - std::stringstream ss; - ss << "Vertex normal indices out of bounds (line " << line_num << ".)\n\n"; - (*warn) += ss.str(); - } - } - if (greatest_vt_idx >= static_cast(vt.size() / 2)) { - if (warn) { - std::stringstream ss; - ss << "Vertex texcoord indices out of bounds (line " << line_num << ".)\n\n"; - (*warn) += ss.str(); - } - } - - bool ret = exportGroupsToShape(&shape, prim_group, tags, material, name, - triangulate, v, warn); - // exportGroupsToShape return false when `usemtl` is called in the last - // line. - // we also add `shape` to `shapes` when `shape.mesh` has already some - // faces(indices) - if (ret || shape.mesh.indices - .size()) { // FIXME(syoyo): Support other prims(e.g. lines) - shapes->push_back(shape); - } - prim_group.clear(); // for safety - - if (err) { - (*err) += errss.str(); - } - - attrib->vertices.swap(v); - attrib->vertex_weights.swap(v); - attrib->normals.swap(vn); - attrib->texcoords.swap(vt); - attrib->texcoord_ws.swap(vt); - attrib->colors.swap(vc); - attrib->skin_weights.swap(vw); - - return true; -} - -bool LoadObjWithCallback(std::istream &inStream, const callback_t &callback, - void *user_data /*= NULL*/, - MaterialReader *readMatFn /*= NULL*/, - std::string *warn, /* = NULL*/ - std::string *err /*= NULL*/) { - std::stringstream errss; - - // material - std::map material_map; - int material_id = -1; // -1 = invalid - - std::vector indices; - std::vector materials; - std::vector names; - names.reserve(2); - std::vector names_out; - - std::string linebuf; - while (inStream.peek() != -1) { - safeGetline(inStream, linebuf); - - // Trim newline '\r\n' or '\n' - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\n') - linebuf.erase(linebuf.size() - 1); - } - if (linebuf.size() > 0) { - if (linebuf[linebuf.size() - 1] == '\r') - linebuf.erase(linebuf.size() - 1); - } - - // Skip if empty line. - if (linebuf.empty()) { - continue; - } - - // Skip leading space. - const char *token = linebuf.c_str(); - token += strspn(token, " \t"); - - assert(token); - if (token[0] == '\0') continue; // empty line - - if (token[0] == '#') continue; // comment line - - // vertex - if (token[0] == 'v' && IS_SPACE((token[1]))) { - token += 2; - // TODO(syoyo): Support parsing vertex color extension. - real_t x, y, z, w; // w is optional. default = 1.0 - parseV(&x, &y, &z, &w, &token); - if (callback.vertex_cb) { - callback.vertex_cb(user_data, x, y, z, w); - } - continue; - } - - // normal - if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { - token += 3; - real_t x, y, z; - parseReal3(&x, &y, &z, &token); - if (callback.normal_cb) { - callback.normal_cb(user_data, x, y, z); - } - continue; - } - - // texcoord - if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { - token += 3; - real_t x, y, z; // y and z are optional. default = 0.0 - parseReal3(&x, &y, &z, &token); - if (callback.texcoord_cb) { - callback.texcoord_cb(user_data, x, y, z); - } - continue; - } - - // face - if (token[0] == 'f' && IS_SPACE((token[1]))) { - token += 2; - token += strspn(token, " \t"); - - indices.clear(); - while (!IS_NEW_LINE(token[0])) { - vertex_index_t vi = parseRawTriple(&token); - - index_t idx; - idx.vertex_index = vi.v_idx; - idx.normal_index = vi.vn_idx; - idx.texcoord_index = vi.vt_idx; - - indices.push_back(idx); - size_t n = strspn(token, " \t\r"); - token += n; - } - - if (callback.index_cb && indices.size() > 0) { - callback.index_cb(user_data, &indices.at(0), - static_cast(indices.size())); - } - - continue; - } - - // use mtl - if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { - token += 7; - std::stringstream ss; - ss << token; - std::string namebuf = ss.str(); - - int newMaterialId = -1; - std::map::const_iterator it = - material_map.find(namebuf); - if (it != material_map.end()) { - newMaterialId = it->second; - } else { - // { warn!! material not found } - if (warn && (!callback.usemtl_cb)) { - (*warn) += "material [ " + namebuf + " ] not found in .mtl\n"; - } - } - - if (newMaterialId != material_id) { - material_id = newMaterialId; - } - - if (callback.usemtl_cb) { - callback.usemtl_cb(user_data, namebuf.c_str(), material_id); - } - - continue; - } - - // load mtl - if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { - if (readMatFn) { - token += 7; - - std::vector filenames; - SplitString(std::string(token), ' ', '\\', filenames); - - if (filenames.empty()) { - if (warn) { - (*warn) += - "Looks like empty filename for mtllib. Use default " - "material. \n"; - } - } else { - bool found = false; - for (size_t s = 0; s < filenames.size(); s++) { - std::string warn_mtl; - std::string err_mtl; - bool ok = (*readMatFn)(filenames[s].c_str(), &materials, - &material_map, &warn_mtl, &err_mtl); - - if (warn && (!warn_mtl.empty())) { - (*warn) += warn_mtl; // This should be warn message. - } - - if (err && (!err_mtl.empty())) { - (*err) += err_mtl; - } - - if (ok) { - found = true; - break; - } - } - - if (!found) { - if (warn) { - (*warn) += - "Failed to load material file(s). Use default " - "material.\n"; - } - } else { - if (callback.mtllib_cb) { - callback.mtllib_cb(user_data, &materials.at(0), - static_cast(materials.size())); - } - } - } - } - - continue; - } - - // group name - if (token[0] == 'g' && IS_SPACE((token[1]))) { - names.clear(); - - while (!IS_NEW_LINE(token[0])) { - std::string str = parseString(&token); - names.push_back(str); - token += strspn(token, " \t\r"); // skip tag - } - - assert(names.size() > 0); - - if (callback.group_cb) { - if (names.size() > 1) { - // create const char* array. - names_out.resize(names.size() - 1); - for (size_t j = 0; j < names_out.size(); j++) { - names_out[j] = names[j + 1].c_str(); - } - callback.group_cb(user_data, &names_out.at(0), - static_cast(names_out.size())); - - } else { - callback.group_cb(user_data, NULL, 0); - } - } - - continue; - } - - // object name - if (token[0] == 'o' && IS_SPACE((token[1]))) { - // @todo { multiple object name? } - token += 2; - - std::stringstream ss; - ss << token; - std::string object_name = ss.str(); - - if (callback.object_cb) { - callback.object_cb(user_data, object_name.c_str()); - } - - continue; - } - -#if 0 // @todo - if (token[0] == 't' && IS_SPACE(token[1])) { - tag_t tag; - - token += 2; - std::stringstream ss; - ss << token; - tag.name = ss.str(); - - token += tag.name.size() + 1; - - tag_sizes ts = parseTagTriple(&token); - - tag.intValues.resize(static_cast(ts.num_ints)); - - for (size_t i = 0; i < static_cast(ts.num_ints); ++i) { - tag.intValues[i] = atoi(token); - token += strcspn(token, "/ \t\r") + 1; - } - - tag.floatValues.resize(static_cast(ts.num_reals)); - for (size_t i = 0; i < static_cast(ts.num_reals); ++i) { - tag.floatValues[i] = parseReal(&token); - token += strcspn(token, "/ \t\r") + 1; - } - - tag.stringValues.resize(static_cast(ts.num_strings)); - for (size_t i = 0; i < static_cast(ts.num_strings); ++i) { - std::stringstream ss; - ss << token; - tag.stringValues[i] = ss.str(); - token += tag.stringValues[i].size() + 1; - } - - tags.push_back(tag); - } -#endif - - // Ignore unknown command. - } - - if (err) { - (*err) += errss.str(); - } - - return true; -} - -bool ObjReader::ParseFromFile(const std::string &filename, - const ObjReaderConfig &config) { - std::string mtl_search_path; - - if (config.mtl_search_path.empty()) { - // - // split at last '/'(for unixish system) or '\\'(for windows) to get - // the base directory of .obj file - // - size_t pos = filename.find_last_of("/\\"); - if (pos != std::string::npos) { - mtl_search_path = filename.substr(0, pos); - } - } else { - mtl_search_path = config.mtl_search_path; - } - - valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, - filename.c_str(), mtl_search_path.c_str(), - config.triangulate, config.vertex_color); - - return valid_; -} - -bool ObjReader::ParseFromString(const std::string &obj_text, - const std::string &mtl_text, - const ObjReaderConfig &config) { - std::stringbuf obj_buf(obj_text); - std::stringbuf mtl_buf(mtl_text); - - std::istream obj_ifs(&obj_buf); - std::istream mtl_ifs(&mtl_buf); - - MaterialStreamReader mtl_ss(mtl_ifs); - - valid_ = LoadObj(&attrib_, &shapes_, &materials_, &warning_, &error_, - &obj_ifs, &mtl_ss, config.triangulate, config.vertex_color); - - return valid_; -} - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif -} // namespace tinyobj - -#endif diff --git a/vendor/vulkan/SPIRV-Headers b/vendor/vulkan/SPIRV-Headers index 2a9b6f95..aa6cef19 160000 --- a/vendor/vulkan/SPIRV-Headers +++ b/vendor/vulkan/SPIRV-Headers @@ -1 +1 @@ -Subproject commit 2a9b6f951c7d6b04b6c21fe1bf3f475b68b84801 +Subproject commit aa6cef192b8e693916eb713e7a9ccadf06062ceb diff --git a/vendor/vulkan/SPIRV-Tools b/vendor/vulkan/SPIRV-Tools index 6dcc7e35..a62abcb4 160000 --- a/vendor/vulkan/SPIRV-Tools +++ b/vendor/vulkan/SPIRV-Tools @@ -1 +1 @@ -Subproject commit 6dcc7e350a0b9871a825414d42329e44b0eb8109 +Subproject commit a62abcb402009b9ca5975e6167c09f237f630e0e diff --git a/vendor/vulkan/Vulkan-Headers b/vendor/vulkan/Vulkan-Headers index 29f979ee..409c16be 160000 --- a/vendor/vulkan/Vulkan-Headers +++ b/vendor/vulkan/Vulkan-Headers @@ -1 +1 @@ -Subproject commit 29f979ee5aa58b7b005f805ea8df7a855c39ff37 +Subproject commit 409c16be502e39fe70dd6fe2d9ad4842ef2c9a53 diff --git a/vendor/vulkan/Vulkan-Loader b/vendor/vulkan/Vulkan-Loader index 7aeb5e43..fb786074 160000 --- a/vendor/vulkan/Vulkan-Loader +++ b/vendor/vulkan/Vulkan-Loader @@ -1 +1 @@ -Subproject commit 7aeb5e4324957b6f60dac5c8cedb955df4fecbfb +Subproject commit fb78607414e154c7a5c01b23177ba719c8a44909 diff --git a/vendor/vulkan/Vulkan-Utility-Libraries b/vendor/vulkan/Vulkan-Utility-Libraries index 0a786ee3..4e246c56 160000 --- a/vendor/vulkan/Vulkan-Utility-Libraries +++ b/vendor/vulkan/Vulkan-Utility-Libraries @@ -1 +1 @@ -Subproject commit 0a786ee3e4fd3602f68ff0ffd9fdcb12e0efb646 +Subproject commit 4e246c56ec5afb5ad66b9b04374d39ac04675c8e diff --git a/vendor/vulkan/Vulkan-ValidationLayers b/vendor/vulkan/Vulkan-ValidationLayers index 9935cdd6..50b87dd4 160000 --- a/vendor/vulkan/Vulkan-ValidationLayers +++ b/vendor/vulkan/Vulkan-ValidationLayers @@ -1 +1 @@ -Subproject commit 9935cdd6f9524b1da1e140393fa69a0a1b72125d +Subproject commit 50b87dd4be883b63c10e3c4f7b9c5aac0c82efd3 diff --git a/vendor/zlib b/vendor/zlib index 04f42cec..51b7f2ab 160000 --- a/vendor/zlib +++ b/vendor/zlib @@ -1 +1 @@ -Subproject commit 04f42ceca40f73e2978b50e93806c2a18c1281fc +Subproject commit 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf