diff --git a/includes/pipeline/graphics.hpp b/includes/pipeline/graphics.hpp new file mode 100644 index 0000000..e87b6f6 --- /dev/null +++ b/includes/pipeline/graphics.hpp @@ -0,0 +1,121 @@ +#ifndef XNA_PIPELINE_GRAPHICS_HPP +#define XNA_PIPELINE_GRAPHICS_HPP + +#include "pipeline.hpp" +#include +#include +#include "xna/exception.hpp" +#include "xna/common/numerics.hpp" +#include "xna/graphics/shared.hpp" + +namespace xna { + class BitmapContent : public ContentItem { + public: + BitmapContent(int32_t width, int32_t height) { + if (width <= 0 || height <= 0) + Exception::Throw(Exception::INVALID_OPERATION); + + this->width = width; + this->height = height; + } + + //Gets or sets the width of the bitmap, in pixels. + constexpr int32_t Width() const { return width; } + + //Gets or sets the width of the bitmap, in pixels. + constexpr void Width(int32_t value) { + if(value <= 0) + Exception::Throw(Exception::INVALID_OPERATION); + + width = value; + } + + //Gets or sets the height of the bitmap, in pixels. + constexpr int32_t Height() const { return height; } + + //Gets or sets the height of the bitmap, in pixels. + constexpr void Height(int32_t value) { + if (value <= 0) + Exception::Throw(Exception::INVALID_OPERATION); + + height = value; + } + + //Copies one bitmap into another. + static inline void Copy(BitmapContent const& sourceBitmap, BitmapContent& destinationBitmap) { + BitmapContent::Copy(sourceBitmap, Rectangle(0, 0, sourceBitmap.Width(), sourceBitmap.Height()), + destinationBitmap, Rectangle(0, 0, destinationBitmap.Width(), destinationBitmap.Height())); + } + + //Copies one bitmap into another. + static void Copy(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, + BitmapContent& destinationBitmap, Rectangle const& destinationRegion); + + static bool InteropCopy(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, + BitmapContent& destinationBitmap, Rectangle const& destinationRegion); + + //Writes encoded bitmap content. + virtual void SetPixelData(std::vector const& sourceData) = 0; + //Reads encoded bitmap content. + virtual std::vector GetPixelData() const = 0; + //Gets the corresponding GPU texture format for the specified bitmap type. + virtual bool TryGetFormat(SurfaceFormat& format) const = 0; + + protected: + BitmapContent() = default; + + //Validates the arguments to the Copy function. + static void ValidateCopyArguments(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, + BitmapContent const& destinationBitmap, Rectangle const& destinationRegion); + + //Attempts to copy a region of the specified bitmap onto another. + virtual bool TryCopyTo(BitmapContent& destinationBitmap, Rectangle const& sourceRegion, Rectangle const& destionationRegion) const = 0; + + //Attempts to copy a region from a specified bitmap. + virtual bool TryCopyFrom(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, Rectangle const& destionationRegion) = 0; + + private: + int32_t width{ 0 }; + int32_t height{ 0 }; + }; + + template + class PixelBitmapContent : public BitmapContent { + public: + PixelBitmapContent(int32_t width, int32_t height) : BitmapContent(width, height){} + + //Writes encoded bitmap content. + void SetPixelData(std::vector const& sourceData) override {} + //Reads encoded bitmap content. + std::vector GetPixelData() const override { return {}; } + //Gets the corresponding GPU texture format for the specified bitmap type. + bool TryGetFormat(SurfaceFormat& format) const override { return false; } + + protected: + //Attempts to copy a region of the specified bitmap onto another. + bool TryCopyTo(BitmapContent& destinationBitmap, Rectangle const& sourceRegion, Rectangle const& destionationRegion) const override { return false; } + + //Attempts to copy a region from a specified bitmap. + bool TryCopyFrom(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, Rectangle const& destionationRegion) override { return false; } + }; + + + //Provides methods for accessing a mipmap chain. + class MipmapChain { + + }; + + //Provides methods for maintaining a mipmap chain. + class MipmapChainCollection { + public: + + private: + + }; + + //Provides a base class for all texture objects. + class TextureContent : public ContentItem { + }; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/importer.hpp b/includes/pipeline/importer.hpp index 1a5bcd3..032f30e 100644 --- a/includes/pipeline/importer.hpp +++ b/includes/pipeline/importer.hpp @@ -1,7 +1,7 @@ #ifndef XNA_PIPELINE_IMPORTER_HPP #define XNA_PIPELINE_IMPORTER_HPP -#include "logger.hpp" +#include "pipeline.hpp" #include #include #include @@ -29,7 +29,7 @@ namespace xna { //Implements a file format importer for use with game assets. template - struct ContentImporter_T : public IContentImporter { + struct ContentImporter : public IContentImporter { //Imports an asset from the specified file. virtual T Import(std::string const& filename, ContentImporterContext& context) = 0; @@ -75,7 +75,7 @@ namespace xna { }; - struct XmlImporter : ContentImporter_T { + struct XmlImporter : ContentImporter { std::any Import(std::string const& filename, ContentImporterContext& context) override { //TODO: XmlReader return { }; diff --git a/includes/pipeline/importers.hpp b/includes/pipeline/importers.hpp new file mode 100644 index 0000000..5ecd3c5 --- /dev/null +++ b/includes/pipeline/importers.hpp @@ -0,0 +1,13 @@ +#ifndef XNA_PIPELINE_IMPORTERS_HPP +#define XNA_PIPELINE_IMPORTERS_HPP + +#include "pipeline.hpp" +#include "importer.hpp" + +namespace xna { + class TextureImporter { + + }; +} + +#endif \ No newline at end of file diff --git a/includes/pipeline/logger.hpp b/includes/pipeline/logger.hpp deleted file mode 100644 index e68bef8..0000000 --- a/includes/pipeline/logger.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef XNA_PIPELINE_LOGGER_HPP -#define XNA_PIPELINE_LOGGER_HPP - -namespace xna { - class ContentBuilderLogger { - - }; -} - -#endif \ No newline at end of file diff --git a/includes/pipeline/pipeline.hpp b/includes/pipeline/pipeline.hpp index d7c8b42..0a129ac 100644 --- a/includes/pipeline/pipeline.hpp +++ b/includes/pipeline/pipeline.hpp @@ -1,9 +1,159 @@ #ifndef XNA_PIPELINE_PIPELINE_HPP #define XNA_PIPELINE_PIPELINE_HPP -namespace xna { - class Pipeline { +#include +#include +#include +#include "xna/exception.hpp" +#include "xna/helpers.hpp" + +namespace xna { + class ContentBuilderLogger { + + }; + + //Base class for dictionaries that map string identifiers to data values. + template + class NamedValueDictionary { + public: + void Add(std::string const& key, T const& value) { + return AddItem(key, value); + } + + void Clear() { + ClearItems(); + } + + bool ContainsKey(std::string const& key) { + return items.contains(key); + } + + size_t Count() const { + return items.size(); + } + + bool Remove(std::string const& key) { + return RemoveItem(key); + } + + bool TryGetValue(std::string const& key, T& value) { + if (items.contains(key)) + { + value = items[key]; + return true; + } + + return false; + } + + T& operator[](std::string const& key) { + return *items[key]; + } + + protected: + virtual void AddItem(std::string const& key, T const& value) { + if (key.empty()) { + Exception::Throw(Exception::INVALID_OPERATION); + } + + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) + Exception::Throw(Exception::INVALID_OPERATION); + } + + items.insert({ key, value }); + } + + virtual void ClearItems() { + items.clear(); + } + + virtual bool RemoveItem(std::string const& key) { + if (key.empty()) { + return false; + } + + const auto& search = items.find(key); + + if (search == items.end()) + return false; + + items.erase(key); + + return true; + } + + virtual void SetItem(std::string const& key, T const& value) { + if (key.empty()) { + Exception::Throw(Exception::INVALID_OPERATION); + } + + if constexpr (XnaHelper::IsSmartPoint()) { + if (value == nullptr) + Exception::Throw(Exception::INVALID_OPERATION); + } + + items[key] = value; + } + + private: + std::map items; + }; + + //Provides properties describing the origin of the game asset, such as the original source file and creation tool. + //This information is used for error reporting, and by processors that need to determine from what directory the asset was originally loaded. + struct ContentIdentity { + constexpr ContentIdentity() = default; + constexpr ContentIdentity(std::string sourceFilename) : + SourceFilename(sourceFilename) {} + constexpr ContentIdentity(std::string sourceFilename, std::string sourceTool) : + SourceFilename(sourceFilename), SourceTool(sourceTool) {} + constexpr ContentIdentity(std::string sourceFilename, std::string sourceTool, std::string fragmentIdentifier) : + SourceFilename(sourceFilename), SourceTool(sourceTool), FragmentIdentifier(fragmentIdentifier) {} + + //Gets or sets the file name of the asset source. + //Optional = true + std::string SourceFilename; + //Gets or sets the creation tool of the asset. + //Optional = true + std::string SourceTool; + //Gets or sets the specific location of the content item within the larger source file. + //Optional = true + std::string FragmentIdentifier; + }; + + //Provides properties that define opaque data for a game asset. + class OpaqueDataDictionary : NamedValueDictionary { + + }; + + //Provides properties that define various aspects of content stored using the intermediate file format of the XNA Framework. + class ContentItem { + public: + ContentItem() { + opaqueData = std::make_shared(); + } + + //Gets or sets the name of the content item. + std::string Name() const { return name; } + //Gets or sets the identity of the content item. + std::shared_ptr Identity() const { return identity; } + //Gets the opaque data of the content item. + std::shared_ptr OpaqueData() const { return opaqueData; } + + //Gets or sets the name of the content item. + void Name(std::string const& value) { name = value; } + //Gets or sets the identity of the content item. + void Identity(std::shared_ptr const& value) { identity = value; } + + private: + //Optional = true + std::string name; + //Optional = true + std::shared_ptr identity; + //Optional = true + std::shared_ptr opaqueData; }; } diff --git a/sources/pipeline/CMakeLists.txt b/sources/pipeline/CMakeLists.txt index 8bc2ed7..7ece7f7 100644 --- a/sources/pipeline/CMakeLists.txt +++ b/sources/pipeline/CMakeLists.txt @@ -6,7 +6,7 @@ add_library (Xn65Pipeline STATIC "writer.cpp" "compiler.cpp" - "importer.cpp") + "importer.cpp" "graphics.cpp") if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET Xn65Pipeline PROPERTY CXX_STANDARD 20) diff --git a/sources/pipeline/graphics.cpp b/sources/pipeline/graphics.cpp new file mode 100644 index 0000000..bd572f9 --- /dev/null +++ b/sources/pipeline/graphics.cpp @@ -0,0 +1,84 @@ +#include "pipeline/graphics.hpp" +#include + +namespace xna { + void xna::BitmapContent::Copy(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, BitmapContent& destinationBitmap, Rectangle const& destinationRegion) + { + BitmapContent::ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); + + if (sourceBitmap.TryCopyTo(destinationBitmap, sourceRegion, destinationRegion) || destinationBitmap.TryCopyFrom(sourceBitmap, sourceRegion, destinationRegion)) + return; + + auto bitmapContent1 = std::make_shared>(sourceBitmap.Width(), sourceBitmap.Height()); + auto rectangle1 = Rectangle(0, 0, bitmapContent1->Width(), bitmapContent1->Height()); + + auto bmp1 = reinterpret_pointer_cast(bitmapContent1); + + if (sourceBitmap.TryCopyTo(*bmp1, sourceRegion, rectangle1) && destinationBitmap.TryCopyFrom(*bmp1, rectangle1, destinationRegion)) + return; + + auto bitmapContent2 = std::make_shared>(sourceBitmap.Width(), sourceBitmap.Height()); + auto bitmapContent3 = std::make_shared>(destinationBitmap.Width(), destinationBitmap.Height()); + + auto rectangle2 = Rectangle(0, 0, sourceBitmap.Width(), sourceBitmap.Height()); + auto rectangle3 = Rectangle(0, 0, destinationBitmap.Width(), destinationBitmap.Height()); + + auto bmpContent2 = reinterpret_pointer_cast(bitmapContent2); + auto bmpContent3 = reinterpret_pointer_cast(bitmapContent3); + + if (!sourceBitmap.TryCopyTo(*bmpContent2, rectangle2, rectangle2) || !destinationBitmap.TryCopyTo(*bmpContent3, rectangle3, rectangle3) + || !bmpContent3->TryCopyFrom(*bmpContent2, sourceRegion, destinationRegion) || !destinationBitmap.TryCopyFrom(*bmpContent3, rectangle3, rectangle3)) + { + Exception::Throw(Exception::INVALID_OPERATION); + } + } + + bool xna::BitmapContent::InteropCopy(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, BitmapContent& destinationBitmap, Rectangle const& destinationRegion) + { + BitmapContent::ValidateCopyArguments(sourceBitmap, sourceRegion, destinationBitmap, destinationRegion); + + bool flag = false; + SurfaceFormat format1; + SurfaceFormat format2; + + if (destinationBitmap.TryGetFormat(format1) && sourceBitmap.TryGetFormat(format2)) + { + if (format2 != format1 && (format2 == SurfaceFormat::NormalizedByte2 + || format2 == SurfaceFormat::NormalizedByte4 + || format1 == SurfaceFormat::NormalizedByte2 + || format1 == SurfaceFormat::NormalizedByte4 + || format2 == SurfaceFormat::Rg32 + || format2 == SurfaceFormat::Single + || format2 == SurfaceFormat::Vector2 + || format2 == SurfaceFormat::HalfSingle + || format2 == SurfaceFormat::HalfVector2)) + return false; + + auto pixelData1 = sourceBitmap.GetPixelData(); + auto pixelData2 = destinationBitmap.GetPixelData(); + try + { + //TODO: ImageProcessor? + //ImageProcessor.Convert(sourceBitmap.Width, sourceBitmap.Height, format2, new Rectangle ? (sourceRegion), pixelData1, destinationBitmap.Width, destinationBitmap.Height, format1, new Rectangle ? (destinationRegion), pixelData2); + destinationBitmap.SetPixelData(pixelData2); + flag = true; + } + catch(std::exception& ex) + { + flag = false; + } + } + + return flag; + } + + void xna::BitmapContent::ValidateCopyArguments(BitmapContent const& sourceBitmap, Rectangle const& sourceRegion, + BitmapContent const& destinationBitmap, Rectangle const& destinationRegion) { + + if (sourceRegion.Left() < 0 || sourceRegion.Top() < 0 || sourceRegion.Width < 0 || sourceRegion.Height < 0 || sourceRegion.Right() > sourceBitmap.Width() || sourceRegion.Bottom() > sourceBitmap.Height()) + Exception::Throw(Exception::OUT_OF_BOUNDS); + + if (destinationRegion.Left() < 0 || destinationRegion.Top() < 0 || destinationRegion.Width < 0 || destinationRegion.Height < 0 || destinationRegion.Right() > destinationBitmap.Width() || destinationRegion.Bottom() > destinationBitmap.Height()) + Exception::Throw(Exception::OUT_OF_BOUNDS); + } +} \ No newline at end of file