From db3258c777601f3e3d9c96421960e9da63c62b21 Mon Sep 17 00:00:00 2001 From: Danilo Date: Wed, 7 Aug 2024 15:23:31 -0300 Subject: [PATCH] =?UTF-8?q?Implementa=C3=A7=C3=B5es=20em=20ContentWriter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- framework/CMakeLists.txt | 2 +- framework/pipeline/compiler.cpp | 5 ++ framework/pipeline/writer.cpp | 29 +++++++++++ inc/xna/csharp/type.hpp | 2 +- inc/xna/default.hpp | 5 ++ inc/xna/exception.hpp | 12 +++++ inc/xna/helpers.hpp | 9 ++++ inc/xna/pipeline/compiler.hpp | 3 +- inc/xna/pipeline/writer.hpp | 87 +++++++++++++++++++++++++++++++-- 9 files changed, 147 insertions(+), 7 deletions(-) create mode 100644 framework/pipeline/compiler.cpp diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index a2f677a..5d34855 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -40,7 +40,7 @@ add_library (Xn65 STATIC "platform-dx/audioengine.cpp" "graphics/gresource.cpp" "platform-dx/effect.cpp" - "exception.cpp" "platform-dx/screen.cpp" "pipeline/writer.cpp") + "exception.cpp" "platform-dx/screen.cpp" "pipeline/writer.cpp" "pipeline/compiler.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET Xn65 PROPERTY CXX_STANDARD 20) diff --git a/framework/pipeline/compiler.cpp b/framework/pipeline/compiler.cpp new file mode 100644 index 0000000..4838cd4 --- /dev/null +++ b/framework/pipeline/compiler.cpp @@ -0,0 +1,5 @@ +#include "xna/pipeline/compiler.hpp" + +namespace xna { + +} \ No newline at end of file diff --git a/framework/pipeline/writer.cpp b/framework/pipeline/writer.cpp index 0664347..5a4d8da 100644 --- a/framework/pipeline/writer.cpp +++ b/framework/pipeline/writer.cpp @@ -1,4 +1,5 @@ #include "xna/pipeline/writer.hpp" +#include "xna/pipeline/compiler.hpp" namespace xna { ContentWriter::ContentWriter( @@ -22,6 +23,34 @@ namespace xna { OutStream = reinterpret_pointer_cast(contentData); } + P_ContentTypeWriter ContentWriter::GetTypeWriter(Type const& type, Int& typeIndex) { + const auto& hash = type.GetHashCode(); + + if (typeTable.contains(hash)) { + typeIndex = typeTable[hash]; + return typeWriters[typeIndex]; + } + + std::vector dependecies; + auto typeWriter = compiler->GetTypeWriter(type, dependecies); + typeIndex = typeWriters.size(); + + typeWriters.push_back(typeWriter); + typeTable.emplace(type.GetHashCode(), typeIndex); + + for (size_t i = 0; i < dependecies.size(); ++i) { + const auto& type1 = dependecies[i]; + + if (type1 != typeof()) + { + Int _; + GetTypeWriter(*type1, _); + } + } + + return typeWriter; + } + void ContentWriter::WriteSharedResources() { while (sharedResources.size() > 0) { sharedResources.pop(); diff --git a/inc/xna/csharp/type.hpp b/inc/xna/csharp/type.hpp index 7313cc3..e204c4b 100644 --- a/inc/xna/csharp/type.hpp +++ b/inc/xna/csharp/type.hpp @@ -16,7 +16,7 @@ namespace xna { constexpr bool IsPrimitive() const { return isPrimitive; } constexpr bool IsPointer() const { return isPointer; } - size_t GetHashCode() const; + HashValue GetHashCode() const; constexpr bool operator==(const Type& other) const { return diff --git a/inc/xna/default.hpp b/inc/xna/default.hpp index 37b2f00..99f82db 100644 --- a/inc/xna/default.hpp +++ b/inc/xna/default.hpp @@ -20,6 +20,10 @@ #include "helpers.hpp" namespace xna { + // + // Util types + // + using HashValue = size_t; // //C# nameof @@ -221,6 +225,7 @@ namespace xna { using P_Stream = sptr; using P_MemoryStream = sptr; using P_FileStream = sptr; + using P_Type = sptr; //Pipeline using P_ContentWriter = sptr; using P_ContentCompiler = sptr; diff --git a/inc/xna/exception.hpp b/inc/xna/exception.hpp index 4dffea3..2e1c37e 100644 --- a/inc/xna/exception.hpp +++ b/inc/xna/exception.hpp @@ -22,6 +22,9 @@ namespace xna { static void ThrowIfNull(void const* argument, std::string const& argumentName, std::source_location const& location = std::source_location::current()); + template + static void ThrowTIsNull(T const& value, std::source_location const& location = std::source_location::current()); + inline static const std::string FAILED_TO_CREATE = "Failed to create component."; inline static const std::string FAILED_TO_APPLY = "Failed to apply component."; inline static const std::string FAILED_TO_MAKE_WINDOW_ASSOCIATION = "Failed to create association with window."; @@ -34,6 +37,15 @@ namespace xna { inline static const std::string OUT_OF_BOUNDS = "Out of bounds."; inline static const std::string END_OF_FILE = "End of file."; }; + + template + static void Exception::ThrowTIsNull(T const& value, std::source_location const& location) { + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) { + Exception::Throw(Exception::ARGUMENT_IS_NULL, location); + } + } + } } #endif \ No newline at end of file diff --git a/inc/xna/helpers.hpp b/inc/xna/helpers.hpp index 46fe92e..8256482 100644 --- a/inc/xna/helpers.hpp +++ b/inc/xna/helpers.hpp @@ -62,6 +62,15 @@ namespace xna { else Exception::Throw(Exception::UNABLE_TO_BUILD_OBJECT, location); } + + template + static inline bool TIsNull(T const& value) { + if constexpr (IsSmartPoint()) { + return value == nullptr; + } + + return false; + } }; } diff --git a/inc/xna/pipeline/compiler.hpp b/inc/xna/pipeline/compiler.hpp index bc390ca..9ca352c 100644 --- a/inc/xna/pipeline/compiler.hpp +++ b/inc/xna/pipeline/compiler.hpp @@ -5,7 +5,8 @@ namespace xna { class ContentCompiler { - + public: + P_ContentTypeWriter GetTypeWriter(Type const& type, std::vector dependencies); }; } diff --git a/inc/xna/pipeline/writer.hpp b/inc/xna/pipeline/writer.hpp index 2b47151..008bf2b 100644 --- a/inc/xna/pipeline/writer.hpp +++ b/inc/xna/pipeline/writer.hpp @@ -6,17 +6,28 @@ #include "pipeline-enums.hpp" #include "../common/numerics.hpp" #include "../common/color.hpp" +#include "../csharp/type.hpp" namespace xna { class ContentTypeWriter { public: virtual String GetRuntimeReader(TargetPlatform targetPlatform) = 0; virtual Int TypeVersion() const { return 0; } + + virtual void Write(ContentWriter& output, Object& value); + }; + + template + class ContentTypeWriter_T : public ContentTypeWriter { + public: + template + virtual void Write(ContentWriter& output, T& value); }; template class ExternalReference { - + public: + String FileName() const; }; //Provides an implementation for many of the ContentCompiler methods including compilation, state tracking for shared resources and creation of the header type manifest. @@ -73,7 +84,7 @@ namespace xna { private: template void InvokeWriter(T& value, ContentTypeWriter& writer); - sptr GetTypeWriter(Type const& type, int& typeIndex) { return nullptr; } + P_ContentTypeWriter GetTypeWriter(Type const& type, Int& typeIndex); void WriteSharedResources(); void WriteHeader(); void WriteFinalOutput(); @@ -94,6 +105,7 @@ namespace xna { std::vector typeWriters; std::map sharedResourceNames; std::queue sharedResources; + std::map typeTable; private: static constexpr Ushort XnbVersion = 5; @@ -103,6 +115,7 @@ namespace xna { static constexpr Int XnbVersionOffset = 4; static constexpr Int XnbFileSizeOffset = 6; static constexpr Int XnbPrologueSize = 10; + inline static const String FilenameExt = ".xnb"; }; // @@ -111,39 +124,105 @@ namespace xna { template void ContentWriter::WriteObject(T& value) { + Exception::ThrowTIsNull(value); + const auto type = typeof(); + Int _; + auto typeWriter = GetTypeWriter(*type, _); + + InvokeWriter(value, *typeWriter); } template void ContentWriter::WriteObject(T& value, ContentTypeWriter& writer) { + auto contentTypeWriter = reinterpret_cast*>(&writer); + if (_writer) { + contentTypeWriter->Write(*this, value); + } + else { + Object _value = value; + writer.Write(*this, _value); + } } template void ContentWriter::WriteRawObject(T& value) { + Exception::ThrowTIsNull(value); + const auto type = typeof(); + Int _; + auto typeWriter = GetTypeWriter(*type, _); + + InvokeWriter(value, *typeWriter); } template void ContentWriter::WriteRawObject(T& value, ContentTypeWriter& typeWriter) { + Exception::ThrowTIsNull(value); + InvokeWriter(value, typeWriter); } template void ContentWriter::WriteSharedResource(T& value) { + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) + Write7BitEncodedInt(0); + } + else { + Int num; + Object obj = value; + if (!sharedResourceNames.contains(value)) { + num = sharedResourceNames.size() + 1; + sharedResourceNames.emplace(obj, num); + sharedResources.push(obj); + } + else { + num = sharedResourceNames[value]; + } + + Write7BitEncodedInt(num); + } } template - void ContentWriter::WriteExternalReference(ExternalReference& reference) { + void ContentWriter::WriteExternalReference(ExternalReference& reference) { + const auto& filename1 = reference.FileName(); + if (filename1.empty()) { + Write(""); + } + else { + String filename2; + + if (filename1.ends_with(FilenameExt)) + filename2 = filename1.substr(0, filename.size() - FilenameExt.size()); + else + Exception::Throw(Exception::INVALID_OPERATION); + + if(!filename2.starts_with(rootDirectory)) + Exception::Throw(Exception::INVALID_OPERATION); + + + Exception::Throw(Exception::NOT_IMPLEMENTED); + } } template void ContentWriter::InvokeWriter(T& value, ContentTypeWriter& writer) { - + auto contentTypeWriter = reinterpret_cast*>(&writer); + + if (contentTypeWriter) { + contentTypeWriter->Write(*this, value); + } + else { + Object obj = value; + writer.Write(*this, obj); + } } }