#ifndef XNA_PIPELINE_WRITER_HPP #define XNA_PIPELINE_WRITER_HPP #include "../csharp/binary.hpp" #include "../default.hpp" #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. class ContentWriter : public BinaryWriter { public: ContentWriter( P_ContentCompiler& compiler, P_Stream const& output, TargetPlatform targetPlatform, GraphicsProfile targetProfile, bool compressContent, String const& rootDirectory, String const& referenceRelocationPath ); //Gets the content build target platform. constexpr TargetPlatform Target() const { return targetPlatform; } //Gets or sets the target graphics profile. constexpr GraphicsProfile TargetProfile() const { return targetProfile; } //Writes a single object preceded by a type identifier to the output binary. template void WriteObject(T& value); //Writes a single object to the output binary, using the specified type hint and writer worker. template void WriteObject(T& value, ContentTypeWriter& writer); //Writes a single object to the output binary as an instance of the specified type. template void WriteRawObject(T& value); //Writes a single object to the output binary using the specified writer worker. template void WriteRawObject(T& value, ContentTypeWriter& typeWriter); //Adds a shared reference to the output binary and records the object to be serialized later. template void WriteSharedResource(T& value); //Writes the name of an external file to the output binary. template void WriteExternalReference(ExternalReference& reference); using BinaryWriter::Write; //Writes a Vector2 value. void Write(Vector2 const& value); //Writes a Vector3 value. void Write(Vector3 const& value); //Writes a Vector4 value. void Write(Vector4 const& value); //Writes a Matrix value. void Write(Matrix const& value); //Writes a Quaternion value. void Write(Quaternion const& value); //Writes a Color value. void Write(Color const& value); inline void FlushOutput() { WriteSharedResources(); WriteHeader(); WriteFinalOutput(); } private: template void InvokeWriter(T& value, ContentTypeWriter& writer); P_ContentTypeWriter GetTypeWriter(Type const& type, Int& typeIndex); void WriteSharedResources(); void WriteHeader(); void WriteFinalOutput(); void WriteUncompressedOutput(); void WriteCompressedOutput(); void WriteVersionNumber(Ushort version); private: P_ContentCompiler compiler{ nullptr }; TargetPlatform targetPlatform{ TargetPlatform::Windows }; GraphicsProfile targetProfile{ GraphicsProfile::HiDef }; bool compressContent{ false }; String rootDirectory; String referenceRelocationPath; P_Stream finalOutput{ nullptr }; P_MemoryStream headerData{ nullptr }; P_MemoryStream contentData{ nullptr }; std::vector typeWriters; std::map sharedResourceNames; std::queue sharedResources; std::map typeTable; private: static constexpr Ushort XnbVersion = 5; static constexpr Ushort XnbCompressedVersion = 32773; static constexpr Ushort XnbVersionProfileMask = 32512; static constexpr Int XnbVersionProfileShift = 8; static constexpr Int XnbVersionOffset = 4; static constexpr Int XnbFileSizeOffset = 6; static constexpr Int XnbPrologueSize = 10; inline static const String FilenameExt = ".xnb"; }; // // Generics implementations // 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) { 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); } } } #endif