diff --git a/bin/data/config.json b/bin/data/config.json index e47537ca..95e199e9 100644 --- a/bin/data/config.json +++ b/bin/data/config.json @@ -110,7 +110,7 @@ "invariant": { "default stage buffers": true, "default defer buffer destroy": true, - "default command buffer immediate": true, + "default command buffer immediate": false, "n-buffered uniform": false, "multithreaded recording": true }, @@ -357,9 +357,10 @@ "rays": false, "depthTest": false }, + "async": false, "fixed step": true, "substeps": 4, - "flatten transforms": true + "flatten transforms": false }, "audio": { "mute": false, diff --git a/engine/inc/uf/ext/freetype/freetype.h b/engine/inc/uf/ext/freetype/freetype.h index c0625a96..09e65acc 100644 --- a/engine/inc/uf/ext/freetype/freetype.h +++ b/engine/inc/uf/ext/freetype/freetype.h @@ -12,35 +12,28 @@ #include +namespace pod { + struct FT_Glyph { + FT_Face face; + ~FT_Glyph(); + }; +} + namespace ext { namespace freetype { - struct UF_API Library { - bool loaded; - FT_Library library; - Library(); - ~Library(); - }; - struct UF_API Glyph { - FT_Face face; - ~Glyph(); - }; - extern UF_API ext::freetype::Library library; - UF_API bool initialize(); - UF_API bool initialized(); - UF_API void terminate(); + bool UF_API initialize(); + void UF_API terminate(); - UF_API ext::freetype::Glyph initialize( const uf::stl::string& ); - UF_API bool initialize( ext::freetype::Glyph&, const uf::stl::string& ); - UF_API void destroy( ext::freetype::Glyph& ); + pod::FT_Glyph UF_API initialize( const uf::stl::string& ); + bool UF_API initialize( pod::FT_Glyph&, const uf::stl::string& ); + void UF_API destroy( pod::FT_Glyph& ); - UF_API void setPixelSizes( ext::freetype::Glyph&, int ); - UF_API void setPixelSizes( ext::freetype::Glyph&, int, int ); - UF_API void setRenderMode( ext::freetype::Glyph&, decltype(FT_RENDER_MODE_NORMAL) = FT_RENDER_MODE_NORMAL ); + void UF_API setPixelSizes( pod::FT_Glyph&, size_t ); + void UF_API setPixelSizes( pod::FT_Glyph&, size_t, size_t ); + void UF_API setRenderMode( pod::FT_Glyph&, FT_Render_Mode = FT_RENDER_MODE_NORMAL ); - UF_API bool load( ext::freetype::Glyph&, unsigned long ); - UF_API bool load( ext::freetype::Glyph&, const uf::stl::string& ); - - UF_API uf::stl::string getError( int ); + bool UF_API load( pod::FT_Glyph&, uint64_t ); + bool UF_API load( pod::FT_Glyph&, const uf::stl::string& ); } } diff --git a/engine/inc/uf/ext/vulkan/buffer.h b/engine/inc/uf/ext/vulkan/buffer.h index 5b7a7130..37dce8cb 100644 --- a/engine/inc/uf/ext/vulkan/buffer.h +++ b/engine/inc/uf/ext/vulkan/buffer.h @@ -8,7 +8,6 @@ namespace ext { struct Device; struct UF_API Buffer { - bool aliased = false; ext::vulkan::Device* device = NULL; VkBuffer buffer = VK_NULL_HANDLE; VkDeviceMemory memory = VK_NULL_HANDLE; @@ -18,10 +17,12 @@ namespace ext { 0 }; VkDeviceSize alignment = 0; - mutable size_t address = {}; void* mapped = nullptr; + mutable size_t address = {}; + mutable bool written = false; // could technically be deduced with the address being set int32_t count = 1; - mutable bool written = false; + bool staged = false; + bool aliased = false; VkBufferUsageFlags usage = 0; VkMemoryPropertyFlags memoryProperties = 0; @@ -41,7 +42,7 @@ namespace ext { VkDeviceSize getOffset( size_t = 0 ) const; // returns the offset / stride / length of one object within the buffer ~Buffer(); - void initialize( ext::vulkan::Device& device, size_t = {} ); + void initialize( ext::vulkan::Device& device, size_t = {}, bool = VK_DEFAULT_STAGE_BUFFERS ); void initialize( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); bool update( const void*, VkDeviceSize ) const; // returns true if a reallocation occurred (to signal rebuilding command buffers) void destroy(bool = VK_DEFAULT_DEFER_BUFFER_DESTROY); @@ -54,11 +55,12 @@ namespace ext { size_t requestedAlignment{}; uf::stl::vector buffers; Device* device = NULL; + bool staged; // ~Buffers(); // - void initialize( Device& device ); - void destroy(bool = VK_DEFAULT_DEFER_BUFFER_DESTROY); + void initialize( Device& device, bool = VK_DEFAULT_STAGE_BUFFERS ); + void destroy( bool = VK_DEFAULT_DEFER_BUFFER_DESTROY ); // size_t initializeBuffer( const void*, VkDeviceSize, VkBufferUsageFlags, VkMemoryPropertyFlags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ); diff --git a/engine/inc/uf/utils/camera/camera.h b/engine/inc/uf/utils/camera/camera.h index 54c287d5..48992189 100644 --- a/engine/inc/uf/utils/camera/camera.h +++ b/engine/inc/uf/utils/camera/camera.h @@ -9,48 +9,36 @@ namespace uf { namespace camera { extern UF_API bool reverseInfiniteProjection; - constexpr const uint_fast8_t maxViews = 6; + constexpr const size_t maxViews = 6; } } namespace pod { struct UF_API Camera { - // bool modified = false; - bool stereoscopic = false; - size_t ttl{}; - pod::Transform<> transform; - + pod::Transform<> transform; struct Viewports { struct Matrices{ pod::Matrix4f view; pod::Matrix4f projection; } matrices[uf::camera::maxViews]; + size_t views = uf::camera::maxViews; } viewport; - - // pod::Matrix4f previous[uf::camera::maxViews]; - /* - struct Metadata { - float fov; - pod::Vector2f bounds; - }; - */ + bool stereoscopic = false; }; } namespace uf { namespace camera { - pod::Vector3f UF_API eye( const pod::Camera&, uint_fast8_t = 0 ); - void UF_API view( pod::Camera&, const pod::Matrix4&, uint_fast8_t = 255 ); - void UF_API projection( pod::Camera&, const pod::Matrix4&, uint_fast8_t = 255 ); - void UF_API update( pod::Camera&, bool = true ); + pod::Vector3f UF_API eye( const pod::Camera&, size_t = 0 ); + void UF_API view( pod::Camera&, const pod::Matrix4&, size_t = uf::camera::maxViews ); + void UF_API projection( pod::Camera&, const pod::Matrix4&, size_t = uf::camera::maxViews ); + void UF_API update( pod::Camera& ); } } namespace uf { - class UF_API Camera { - protected: - pod::Camera m_pod; + class UF_API Camera : protected pod::Camera { public: Camera(); @@ -61,22 +49,20 @@ namespace uf { const pod::Transform<>& getTransform() const; void setTransform( const pod::Transform<>& transform ); - pod::Matrix4& getView( uint_fast8_t = 0 ); - const pod::Matrix4& getView( uint_fast8_t = 0 ) const; + pod::Matrix4& getView( size_t = 0 ); + const pod::Matrix4& getView( size_t = 0 ) const; - pod::Matrix4& getProjection( uint_fast8_t = 0 ); - const pod::Matrix4& getProjection( uint_fast8_t = 0 ) const; + pod::Matrix4& getProjection( size_t = 0 ); + const pod::Matrix4& getProjection( size_t = 0 ) const; - pod::Matrix4& getPrevious( uint_fast8_t = 0 ); - const pod::Matrix4& getPrevious( uint_fast8_t = 0 ) const; + pod::Matrix4& getPrevious( size_t = 0 ); + const pod::Matrix4& getPrevious( size_t = 0 ) const; - bool modified() const; - void setStereoscopic( bool ); - - pod::Vector3f getEye( uint_fast8_t = 0 ) const; + pod::Vector3f getEye( size_t = 0 ) const; + void setStereoscopic( bool ); - void setView( const pod::Matrix4& mat, uint_fast8_t = 255 ); - void setProjection( const pod::Matrix4& mat, uint_fast8_t = 255 ); - void update(bool = false); + void setView( const pod::Matrix4& mat, size_t = uf::camera::maxViews ); + void setProjection( const pod::Matrix4& mat, size_t = uf::camera::maxViews ); + void update(); }; } \ No newline at end of file diff --git a/engine/inc/uf/utils/image/atlas.h b/engine/inc/uf/utils/image/atlas.h index 41ddef7c..cd3126df 100644 --- a/engine/inc/uf/utils/image/atlas.h +++ b/engine/inc/uf/utils/image/atlas.h @@ -3,31 +3,49 @@ #include #include -namespace uf { - class UF_API Atlas { - public: +namespace pod { + struct UF_API Atlas { typedef uf::stl::string hash_t; - struct Identifier { - size_t index; - hash_t hash; - }; struct Tile { - uf::Image image; - Identifier identifier = {0,""}; + pod::Image image; pod::Vector2ui size = {}; pod::Vector2ui coord = {}; }; - typedef uf::stl::vector images_t; + typedef uf::stl::vector images_t; typedef uf::stl::unordered_map atlas_t; - protected: - uf::Image m_atlas; - atlas_t m_tiles; + + pod::Image image; + pod::Atlas::atlas_t tiles; + }; +} + +namespace uf { + namespace atlas { + pod::Atlas::hash_t UF_API add( pod::Atlas& atlas, const pod::Image& image, const pod::Atlas::hash_t& hash ); + pod::Atlas::hash_t UF_API add( pod::Atlas& atlas, const pod::Image& image ); + + void UF_API generate( pod::Atlas& atlas, float padding = 1 ); + void UF_API generate( pod::Atlas& atlas, const uf::stl::vector& images, float padding = 1 ); + void UF_API clear( pod::Atlas& atlas, bool full = true ); + bool UF_API has( const pod::Atlas& atlas, const pod::Atlas::hash_t& hash ); + + pod::Vector2f UF_API mapUv( const pod::Atlas& atlas, const pod::Vector2f& uv, const pod::Atlas::hash_t& hash ); + pod::Image& UF_API get( pod::Atlas& atlas ); + const pod::Image& UF_API get( const pod::Atlas& atlas ); + } +} + +namespace uf { + class UF_API Atlas : public pod::Atlas { public: - hash_t addImage( const uf::Image&, const hash_t& hash ); - hash_t addImage( const uf::Image& ); + Atlas() = default; + Atlas( const pod::Atlas& atlas ) : pod::Atlas(atlas) {} + + hash_t addImage( const pod::Image&, const hash_t& hash ); + hash_t addImage( const pod::Image& ); void generate(float padding = 1); - void generate( const uf::stl::vector&, float padding = 1); + void generate( const uf::stl::vector&, float padding = 1); void clear(bool = true); bool generated() const; bool has( const hash_t& ) const; @@ -36,8 +54,8 @@ namespace uf { pod::Vector2f mapUv( const pod::Vector2f&, size_t ) const; pod::Vector3f mapUv( const pod::Vector3f& ) const; - uf::Image& getAtlas(); - const uf::Image& getAtlas() const; + pod::Image& getAtlas(); + const pod::Image& getAtlas() const; atlas_t& getImages(); const atlas_t& getImages() const; @@ -46,7 +64,7 @@ namespace uf { class UF_API HashAtlas { public: typedef uf::stl::string hash_t; - typedef uf::stl::unordered_map images_t; + typedef uf::stl::unordered_map images_t; struct Identifier { hash_t hash; @@ -54,23 +72,23 @@ namespace uf { typedef Identifier identifier_t; typedef BinPack2D::CanvasArray atlas_t; protected: - uf::Image m_image; + pod::Image m_image; images_t m_images; atlas_t m_atlas; public: - hash_t addImage( const uf::Image&, bool = false ); - hash_t addImage( uf::Image&&, bool = false ); + hash_t addImage( const pod::Image&, bool = false ); + hash_t addImage( pod::Image&&, bool = false ); hash_t addImage( const uint8_t*, const pod::Vector2ui&, std::size_t, std::size_t, bool = false, bool = false ); void generate(float padding = 1); void generate( const images_t&, float padding = 1); void clear(); - bool has( const uf::Image& ) const; + bool has( const pod::Image& ) const; bool has( const uf::stl::string& ) const; pod::Vector2f mapUv( const pod::Vector2f&, const hash_t& ); - uf::Image& getAtlas(); + pod::Image& getAtlas(); images_t& getImages(); const images_t& getImages() const; }; diff --git a/engine/inc/uf/utils/image/image.h b/engine/inc/uf/utils/image/image.h index 62f87545..568559cf 100644 --- a/engine/inc/uf/utils/image/image.h +++ b/engine/inc/uf/utils/image/image.h @@ -4,27 +4,56 @@ #include #include -#include "pixel.h" - -namespace uf { - class UF_API Image { - public: - typedef pod::Vector2ui vec2_t; +namespace pod { + struct UF_API Image { typedef pod::Vector4b pixel_t; typedef uf::stl::vector container_t; - protected: - uf::stl::string m_filename; - Image::container_t m_pixels; - Image::vec2_t m_dimensions; - std::size_t m_bpp; - std::size_t m_channels; - std::size_t m_format; + + uf::stl::string filename; + pod::Image::container_t pixels; + pod::Vector2ui size = {}; + size_t bpp = 8; + size_t channels = 4; + size_t format = 0; + }; +} + +namespace uf { + namespace image { + bool UF_API open( pod::Image&, const uf::stl::string&, bool = true ); + void UF_API clear( pod::Image& ); + + void UF_API load( pod::Image&, const pod::Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip = false ); + void UF_API load( pod::Image&, const pod::Image::container_t& container, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip = false ); + + bool UF_API save( const pod::Image&, const uf::stl::string& filename, bool flip = false ); + void UF_API save( const pod::Image&, std::ostream& stream ); + + pod::Image::pixel_t UF_API at( pod::Image&, const pod::Vector2ui& at ); + uf::stl::string UF_API hash( const pod::Image& ); + + void UF_API flip( pod::Image& ); + void UF_API padToPowerOfTwo( pod::Image& ); + void UF_API convert( pod::Image&, const uf::stl::string&, const uf::stl::string& = "rgba" ); + + pod::Image UF_API overlay( const pod::Image&, const pod::Image& top, const pod::Vector2ui& corner = {} ); + pod::Image UF_API replace( const pod::Image&, const pod::Image::pixel_t& from, const pod::Image::pixel_t& to ); + pod::Image UF_API subImage( const pod::Image&, const pod::Vector2ui& start, const pod::Vector2ui& end ); + pod::Image UF_API scale( const pod::Image&, const pod::Vector2ui& size, bool nearest = false ); + } +} + +namespace uf { + class UF_API Image : public pod::Image { public: // C-tor + Image() = default; + Image( const pod::Image& image ) : pod::Image(image) {} + /* Image(); - explicit Image(const vec2_t& size); - Image(container_t&& move, const vec2_t& size); - Image(const container_t& copy, const vec2_t& size); + explicit Image(const pod::Vector2ui& size); + Image(container_t&& move, const pod::Vector2ui& size); + Image(const container_t& copy, const pod::Vector2ui& size); Image(const Image& copy); Image(Image&& move) noexcept; @@ -33,17 +62,19 @@ namespace uf { // Assignment Image& operator=(const Image& copy); Image& operator=(Image&& move) noexcept; + */ bool open( const uf::stl::string& filename, bool = true ); // from file void open( const std::istream& stream ); // from stream - void move( Image::container_t&& move, const Image::vec2_t& size ); // move from vector of pixels - void copy( const Image::container_t& copy, const Image::vec2_t& size ); // copy from vector of pixels + void move( Image::container_t&& move, const pod::Vector2ui& size ); // move from vector of pixels + void move( uf::Image&& ); // move from image object + void copy( const Image::container_t& copy, const pod::Vector2ui& size ); // copy from vector of pixels void copy( const uf::Image& ); // copy from image object // D-tor void clear(); // empties pixel container // Getters - void loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false ); - void loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bpp, std::size_t channels, bool flip = false ); + void loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip = false ); + void loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip = false ); uf::stl::string getFilename() const; void setFilename( const uf::stl::string& ); @@ -54,19 +85,19 @@ namespace uf { Image::pixel_t::type_t* getPixelsPtr(); const Image::pixel_t::type_t* getPixelsPtr() const; - Image::vec2_t& getDimensions(); - const Image::vec2_t& getDimensions() const; + pod::Vector2ui& getDimensions(); + const pod::Vector2ui& getDimensions() const; - std::size_t& getBpp(); - std::size_t getBpp() const; + size_t& getBpp(); + size_t getBpp() const; - std::size_t& getChannels(); - std::size_t getChannels() const; + size_t& getChannels(); + size_t getChannels() const; uf::stl::string getHash() const; size_t getFormat() const; - Image::pixel_t at( const Image::vec2_t& at ); + Image::pixel_t at( const pod::Vector2ui& at ); // Modifiers void flip(); @@ -74,9 +105,9 @@ namespace uf { bool save( const uf::stl::string& filename, bool flip = false ) const; // to file void save( std::ostream& stream ) const; // to stream void convert( const uf::stl::string&, const uf::stl::string& = "rgba" ); - Image overlay(const Image& top, const Image::vec2_t& corner = {} ) const; // Merges one image on top of another + Image overlay(const Image& top, const pod::Vector2ui& corner = {} ) const; // Merges one image on top of another Image replace(const Image::pixel_t& from, const Image::pixel_t& to ) const; // Changes all pixel from one color (from), to another (to) - Image subImage( const Image::vec2_t& start, const Image::vec2_t& end) const; // Crops an image - Image scale( const Image::vec2_t& size, bool nearest ); + Image subImage( const pod::Vector2ui& start, const pod::Vector2ui& end) const; // Crops an image + Image scale( const pod::Vector2ui& size, bool nearest ); }; } \ No newline at end of file diff --git a/engine/inc/uf/utils/image/pixel.h b/engine/inc/uf/utils/image/pixel.h deleted file mode 100644 index 194edf73..00000000 --- a/engine/inc/uf/utils/image/pixel.h +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once -#if 0 -#include - -namespace pod { - // Simple Pixels (designed [to store in arrays] with minimal headaches) - template - struct /*UF_API*/ Pixel { - // n-dimensional/unspecialized Pixel access - T components[N]; - // POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = N; - // Overload access - // Accessing Pia subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Pixel operator-() const; // Negation - inline Pixel operator*( const Pixel& Pixel ) const; // Multiplication between two Pixels - inline Pixel operator/( const Pixel& Pixel ) const; // Divison between two Pixels - inline Pixel operator*( T scalar ) const; // Multiplication with scalar - inline Pixel operator/( T scalar ) const; // Divison with scalar - inline Pixel& operator *=( const Pixel& Pixel ); // Multiplication set between two Pixels - inline Pixel& operator /=( const Pixel& Pixel ); // Divison set between two Pixels - inline Pixel& operator *=( T scalar ); // Multiplication set with scalar - inline Pixel& operator /=( T scalar ); // Divison set with scalar - inline bool operator==( const Pixel& Pixel ) const; // Equality check between two Pixels (equals) - inline bool operator!=( const Pixel& Pixel ) const; // Equality check between two Pixels (not equals) - }; - template - struct /*UF_API*/ Pixel { - // XYZ access - T r = 0; - T g = 0; - T b = 0; - // n-dimensional/unspecialized Pixel access - T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 3; - // Overload access - // Accessing Pia subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Pixel operator-() const; // Negation - inline Pixel operator*( const Pixel& Pixel ) const; // Multiplication between two Pixels - inline Pixel operator/( const Pixel& Pixel ) const; // Divison between two Pixels - inline Pixel operator*( T scalar ) const; // Multiplication with scalar - inline Pixel operator/( T scalar ) const; // Divison with scalar - inline Pixel& operator *=( const Pixel& Pixel ); // Multiplication set between two Pixels - inline Pixel& operator /=( const Pixel& Pixel ); // Divison set between two Pixels - inline Pixel& operator *=( T scalar ); // Multiplication set with scalar - inline Pixel& operator /=( T scalar ); // Divison set with scalar - inline bool operator==( const Pixel& Pixel ) const; // Equality check between two Pixels (equals) - inline bool operator!=( const Pixel& Pixel ) const; // Equality check between two Pixels (not equals) - }; - template - struct /*UF_API*/ Pixel { - // XYZW access - T r = 0; - T g = 0; - T b = 0; - T a = 0; - // n-dimensional/unspecialized Pixel access - T* components = (T*) this; - // POD information - typedef T type_t; - typedef T* container_t; - static const std::size_t size = 4; - // Overload access - // Accessing Pia subscripts - T& operator[](std::size_t i); - const T& operator[](std::size_t i) const; - // Arithmetic - inline Pixel operator-() const; // Negation - inline Pixel operator*( const Pixel& Pixel ) const; // Multiplication between two Pixels - inline Pixel operator/( const Pixel& Pixel ) const; // Divison between two Pixels - inline Pixel operator*( T scalar ) const; // Multiplication with scalar - inline Pixel operator/( T scalar ) const; // Divison with scalar - inline Pixel& operator *=( const Pixel& Pixel ); // Multiplication set between two Pixels - inline Pixel& operator /=( const Pixel& Pixel ); // Divison set between two Pixels - inline Pixel& operator *=( T scalar ); // Multiplication set with scalar - inline Pixel& operator /=( T scalar ); // Divison set with scalar - inline bool operator==( const Pixel& Pixel ) const; // Equality check between two Pixels (equals) - inline bool operator!=( const Pixel& Pixel ) const; // Equality check between two Pixels (not equals) - }; - - template using Pixel3t = Pixel; - typedef Pixel Pixel3f; - typedef Pixel Pixel3d; - typedef Pixel PixelRgb8; - - template using Pixel4t = Pixel; - typedef Pixel Pixel4f; - typedef Pixel Pixel4d; - typedef Pixel PixelRgba8; -} - -// POD pixel accessing/manipulation -namespace uf { - namespace pixel { - // Equality checking - template std::size_t /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two pixels (less than) - template bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two pixels (equals) - // Basic arithmetic - template T /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two pixels of same type and size together - template T /*UF_API*/ multiply( const T& pixel, const typename T::type_t& scalar ); // Multiplies this pixel by a scalar - template T /*UF_API*/ divide( const T& left, const T& right ); // Divides two pixels of same type and size together - template T /*UF_API*/ divide( const T& left, const typename T::type_t& scalar ); // Divides this pixel by a scalar - template T /*UF_API*/ negate( const T& pixel ); // Flip sign of all components - // Writes to first value - template T& /*UF_API*/ multiply( T& left, const T& right ); // Multiplies two pixels of same type and size together - template T& /*UF_API*/ multiply( T& pixel, const typename T::type_t& scalar ); // Multiplies this pixel by a scalar - template T& /*UF_API*/ divide( T& left, const T& right ); // Divides two pixels of same type and size together - template T& /*UF_API*/ divide( T& left, const typename T::type_t& scalar ); // Divides this pixel by a scalar - template T& /*UF_API*/ negate( T& pixel ); // Flip sign of all components - } -} -#include "pixel.inl" -#endif \ No newline at end of file diff --git a/engine/inc/uf/utils/image/pixel.inl b/engine/inc/uf/utils/image/pixel.inl deleted file mode 100644 index 963c45bc..00000000 --- a/engine/inc/uf/utils/image/pixel.inl +++ /dev/null @@ -1,128 +0,0 @@ -#include -#include // memcmp - -// Equality checking -template // Equality check between two pixels (less than) -std::size_t /*UF_API*/ uf::pixel::compareTo( const T& left, const T& right ) { - return memcmp( &left, &right, T::size ); -} -template // Equality check between two pixels (equals) -bool /*UF_API*/ uf::pixel::equals( const T& left, const T& right ) { - return !compareTo(left, right); -} -// Basic arithmetic -template // Multiplies two pixels of same type and size together -T /*UF_API*/ uf::pixel::multiply( const T& left, const T& right ) { - T res; - for ( std::size_t i = 0; i < T::size; ++i ) res[i] = left[i] * right[i]; - return res; -} -template // Multiplies this pixel by a scalar -T /*UF_API*/ uf::pixel::multiply( const T& pixel, const typename T::type_t& scalar ) { - T res; - for ( std::size_t i = 0; i < T::size; ++i ) res[i] = pixel[i] * scalar; - return res; -} -template // Divides two pixels of same type and size together -T /*UF_API*/ uf::pixel::divide( const T& left, const T& right ) { - T res; - for ( std::size_t i = 0; i < T::size; ++i ) res[i] = left[i] / right[i]; - return res; -} -template // Divides this pixel by a scalar -T /*UF_API*/ uf::pixel::divide( const T& pixel, const typename T::type_t& scalar ) { - T res; - for ( std::size_t i = 0; i < T::size; ++i ) res[i] = pixel[i] / scalar; - return res; -} -template // Invert the color -T /*UF_API*/ uf::pixel::negate( const T& pixel ) { - typename T::type_t max = 0; - max = ~0; - typename T::type_t res = 0; - for ( std::size_t i = 0; i < T::size; ++i ) res[i] = max - res[i]; - return res; -} -// Writes to first value -template // Multiplies two pixels of same type and size together -T& /*UF_API*/ uf::pixel::multiply( T& left, const T& right ) { - for ( std::size_t i = 0; i < T::size; ++i ) left[i] *= right[i]; - return left; -} -template // Multiplies this pixel by a scalar -T& /*UF_API*/ uf::pixel::multiply( T& pixel, const typename T::type_t& scalar ) { - for ( std::size_t i = 0; i < T::size; ++i ) pixel[i] * scalar; - return pixel; -} -template // Divides two pixels of same type and size together -T& /*UF_API*/ uf::pixel::divide( T& left, const T& right ) { - for ( std::size_t i = 0; i < T::size; ++i ) left[i] /= right[i]; - return left; -} -template // Divides this pixel by a scalar -T& /*UF_API*/ uf::pixel::divide( T& pixel, const typename T::type_t& scalar ) { - for ( std::size_t i = 0; i < T::size; ++i ) pixel[i] /= scalar; - return pixel; -} -template // Flip sign of all components -T& /*UF_API*/ uf::pixel::negate( T& pixel ) { - for ( std::size_t i = 0; i < T::size; ++i ) pixel[i] = -pixel[i]; - return pixel; -} - - -// -template -T& pod::Pixel::operator[](std::size_t i) { - return this->components[i]; -} -template -const T& pod::Pixel::operator[](std::size_t i) const { - return this->components[i]; -} -// Arithmetic -template // Negation -inline pod::Pixel pod::Pixel::operator-() const { - return uf::pixel::negate( *this ); -} -template // Multiplication between two pixels -inline pod::Pixel pod::Pixel::operator*( const pod::Pixel& pixel ) const { - return uf::pixel::multiply( *this, pixel ); -} -template // Division between two pixels -inline pod::Pixel pod::Pixel::operator/( const pod::Pixel& pixel ) const { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication with scalar -inline pod::Pixel pod::Pixel::operator*( T scalar ) const { - return uf::pixel::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Pixel pod::Pixel::operator/( T scalar ) const { - return uf::pixel::divide( *this, scalar ); -} -template // Multiplication set between two pixels -inline pod::Pixel& pod::Pixel::operator *=( const pod::Pixel& pixel ) { - return uf::pixel::multiply( *this, pixel ); -} -template // Division set between two pixels -inline pod::Pixel& pod::Pixel::operator /=( const pod::Pixel& pixel ) { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication set with scalar -inline pod::Pixel& pod::Pixel::operator *=( T scalar ) { - return uf::pixel::multiply( *this, scalar ); -} -template // Division set with scalar -inline pod::Pixel& pod::Pixel::operator /=( T scalar ) { - return uf::pixel::divide( *this, scalar ); -} -template // Equality check between two pixels (equals) -inline bool pod::Pixel::operator==( const pod::Pixel& pixel ) const { - return uf::pixel::equals(pixel); -} -template // Equality check between two pixels (not equals) -inline bool pod::Pixel::operator!=( const pod::Pixel& pixel ) const { - return !uf::pixel::equals(pixel); -} -#include "redundancy.inl" \ No newline at end of file diff --git a/engine/inc/uf/utils/image/redundancy.inl b/engine/inc/uf/utils/image/redundancy.inl deleted file mode 100644 index 7e4e6ebc..00000000 --- a/engine/inc/uf/utils/image/redundancy.inl +++ /dev/null @@ -1,109 +0,0 @@ -// -template -T& pod::Pixel::operator[](std::size_t i) { - return this->components[i]; -} -template -const T& pod::Pixel::operator[](std::size_t i) const { - return this->components[i]; -} -// Arithmetic -template // Negation -inline pod::Pixel pod::Pixel::operator-() const { - return uf::pixel::negate( *this ); -} -template // Multiplication between two pixels -inline pod::Pixel pod::Pixel::operator*( const pod::Pixel& pixel ) const { - return uf::pixel::multiply( *this, pixel ); -} -template // Division between two pixels -inline pod::Pixel pod::Pixel::operator/( const pod::Pixel& pixel ) const { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication with scalar -inline pod::Pixel pod::Pixel::operator*( T scalar ) const { - return uf::pixel::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Pixel pod::Pixel::operator/( T scalar ) const { - return uf::pixel::divide( *this, scalar ); -} -template // Multiplication set between two pixels -inline pod::Pixel& pod::Pixel::operator *=( const pod::Pixel& pixel ) { - return uf::pixel::multiply( *this, pixel ); -} -template // Division set between two pixels -inline pod::Pixel& pod::Pixel::operator /=( const pod::Pixel& pixel ) { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication set with scalar -inline pod::Pixel& pod::Pixel::operator *=( T scalar ) { - return uf::pixel::multiply( *this, scalar ); -} -template // Division set with scalar -inline pod::Pixel& pod::Pixel::operator /=( T scalar ) { - return uf::pixel::divide( *this, scalar ); -} -template // Equality check between two pixels (equals) -inline bool pod::Pixel::operator==( const pod::Pixel& pixel ) const { - return uf::pixel::equals(pixel); -} -template // Equality check between two pixels (not equals) -inline bool pod::Pixel::operator!=( const pod::Pixel& pixel ) const { - return !uf::pixel::equals(pixel); -} - -// -template -T& pod::Pixel::operator[](std::size_t i) { - return this->components[i]; -} -template -const T& pod::Pixel::operator[](std::size_t i) const { - return this->components[i]; -} -// Arithmetic -template // Negation -inline pod::Pixel pod::Pixel::operator-() const { - return uf::pixel::negate( *this ); -} -template // Multiplication between two pixels -inline pod::Pixel pod::Pixel::operator*( const pod::Pixel& pixel ) const { - return uf::pixel::multiply( *this, pixel ); -} -template // Division between two pixels -inline pod::Pixel pod::Pixel::operator/( const pod::Pixel& pixel ) const { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication with scalar -inline pod::Pixel pod::Pixel::operator*( T scalar ) const { - return uf::pixel::multiply( *this, scalar ); -} -template // Division with scalar -inline pod::Pixel pod::Pixel::operator/( T scalar ) const { - return uf::pixel::divide( *this, scalar ); -} -template // Multiplication set between two pixels -inline pod::Pixel& pod::Pixel::operator *=( const pod::Pixel& pixel ) { - return uf::pixel::multiply( *this, pixel ); -} -template // Division set between two pixels -inline pod::Pixel& pod::Pixel::operator /=( const pod::Pixel& pixel ) { - return uf::pixel::divide( *this, pixel ); -} -template // Multiplication set with scalar -inline pod::Pixel& pod::Pixel::operator *=( T scalar ) { - return uf::pixel::multiply( *this, scalar ); -} -template // Division set with scalar -inline pod::Pixel& pod::Pixel::operator /=( T scalar ) { - return uf::pixel::divide( *this, scalar ); -} -template // Equality check between two pixels (equals) -inline bool pod::Pixel::operator==( const pod::Pixel& pixel ) const { - return uf::pixel::equals(pixel); -} -template // Equality check between two pixels (not equals) -inline bool pod::Pixel::operator!=( const pod::Pixel& pixel ) const { - return !uf::pixel::equals(pixel); -} \ No newline at end of file diff --git a/engine/inc/uf/utils/math/angle.h b/engine/inc/uf/utils/math/angle.h index ced677f1..046b0373 100644 --- a/engine/inc/uf/utils/math/angle.h +++ b/engine/inc/uf/utils/math/angle.h @@ -21,41 +21,5 @@ namespace pod { Angle::type_t angle; // Angle measure Angle::Unit unit; // Unit angle is stored as - }; -} - -namespace uf { - // Provides operations for POD angle - class UF_API Angle { - public: - // Easily access POD's type - typedef pod::Angle pod_t; - // Replicate POD information - typedef Angle::pod_t::Unit Unit; - typedef Angle::pod_t::type_t type_t; - protected: - // POD storage - Angle::pod_t m_pod; - public: - // C-tor - Angle(const Angle::type_t& def = 0, Angle::Unit unit = Angle::Unit::DEFAULT); // initializes POD to 'def' - Angle(const Angle::pod_t& pod); // copies POD altogether - // D-tor - // Unneccesary - // POD access - Angle::pod_t& data(); // Returns a reference of POD - const Angle::pod_t& data() const; // Returns a const-reference of POD - // Alternative POD access - Angle::type_t& get(); // Returns a pointer to the angle measure - const Angle::type_t& get() const; // Returns a const-pointer to the angle measure - // POD manipulation - Angle::type_t& set(const Angle& angle); // Sets the angle measure (from Angle object) - Angle::type_t& set(const Angle::type_t& val = 0); // Sets the angle measure (from POD Angle) - Angle::type_t& set(const Angle::pod_t& pod); // Sets the angle measure (from value) (performs no conversion) - Angle::type_t& set(const Angle::type_t& val = 0, Angle::Unit unit = Angle::Unit::DEFAULT); // Sets the angle measure (from value and enum) (performs conversion (if necessary)) - // POD manipulation - Angle& convert( Angle::Unit unit ); // Converts from current unit to desired unit (does nothing if current == desired) - - }; } \ No newline at end of file diff --git a/engine/inc/uf/utils/memory/pool.h b/engine/inc/uf/utils/memory/pool.h index 5a91fef3..b44c1166 100644 --- a/engine/inc/uf/utils/memory/pool.h +++ b/engine/inc/uf/utils/memory/pool.h @@ -38,23 +38,21 @@ namespace pod { Strategy strategy = Strategy::BUDDY; union State { - // linear - struct { size_t offset; } linear; - - // pool - struct { void* freeListHead; size_t fixedChunkSize; } pool; - - // segregated + struct { + size_t offset; + } linear; + struct { + void* freeListHead; + size_t fixedChunkSize; + } pool; struct { void* freeListHeads[UF_MAX_BUCKETS]; - size_t offset; // To carve new memory when a bucket is empty - size_t minChunkSize; // Base size, e.g., 16 bytes + size_t offset; + size_t minChunkSize; } segregated; - - // buddy struct { - void* freeLists[32]; // Max 32 levels for powers of two up to 4GB - uint8_t* splitBlockBitset; // Tracks if a block was split + void* freeLists[32]; + uint8_t* splitBlockBitset; size_t maxLevel; size_t minBlockSize; } buddy; @@ -102,9 +100,7 @@ namespace uf { } namespace uf { - class UF_API MemoryPool { - protected: - pod::MemoryPool m_pod; + class UF_API MemoryPool : protected pod::MemoryPool { public: MemoryPool( size_t = 0 ); ~MemoryPool(); diff --git a/engine/inc/uf/utils/memory/pool.inl b/engine/inc/uf/utils/memory/pool.inl index 8fb58e1e..952d5904 100644 --- a/engine/inc/uf/utils/memory/pool.inl +++ b/engine/inc/uf/utils/memory/pool.inl @@ -40,26 +40,26 @@ bool uf::memoryPool::free( pod::MemoryPool& pool, const T& data ) { #endif } -size_t uf::MemoryPool::size() const { return uf::memoryPool::size( m_pod ); } -size_t uf::MemoryPool::allocated() const { return uf::memoryPool::allocated( m_pod ); } -uf::stl::string uf::MemoryPool::stats() const { return uf::memoryPool::stats( m_pod ); } -void uf::MemoryPool::initialize( size_t size, pod::MemoryPool::Strategy strategy, size_t chunkSize ) { return uf::memoryPool::initialize( m_pod, size, strategy, chunkSize ); } -void uf::MemoryPool::destroy() { return uf::memoryPool::destroy( m_pod ); } +size_t uf::MemoryPool::size() const { return uf::memoryPool::size( *this ); } +size_t uf::MemoryPool::allocated() const { return uf::memoryPool::allocated( *this ); } +uf::stl::string uf::MemoryPool::stats() const { return uf::memoryPool::stats( *this ); } +void uf::MemoryPool::initialize( size_t size, pod::MemoryPool::Strategy strategy, size_t chunkSize ) { return uf::memoryPool::initialize( *this, size, strategy, chunkSize ); } +void uf::MemoryPool::destroy() { return uf::memoryPool::destroy( *this ); } -//pod::Allocation uf::MemoryPool::allocate( void* data, size_t size/*, size_t alignment*/ ) { return uf::memoryPool::allocate( m_pod, data, size/*, alignment*/ ); } -//void* uf::MemoryPool::alloc( void* data, size_t size/*, size_t alignment*/ ) { return uf::memoryPool::alloc( m_pod, data, size/*, alignment*/ ); } -//void* uf::MemoryPool::alloc( size_t size, void* data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( m_pod, data, size/*, alignment*/ ); } -pod::Allocation uf::MemoryPool::allocate( size_t size/*, size_t alignment*/ ) { return uf::memoryPool::allocate( m_pod, size/*, alignment*/ ); } -void* uf::MemoryPool::alloc( size_t size/*, size_t alignment*/ ) { return uf::memoryPool::alloc( m_pod, size/*, alignment*/ ); } -//pod::Allocation& uf::MemoryPool::fetch( void* data, size_t size ) { return uf::memoryPool::fetch( m_pod, data, size ); } -bool uf::MemoryPool::exists( void* data, size_t size ) { return uf::memoryPool::exists( m_pod, data, size ); } -bool uf::MemoryPool::free( void* data, size_t size ) { return uf::memoryPool::free( m_pod, data, size ); } +//pod::Allocation uf::MemoryPool::allocate( void* data, size_t size/*, size_t alignment*/ ) { return uf::memoryPool::allocate( *this, data, size/*, alignment*/ ); } +//void* uf::MemoryPool::alloc( void* data, size_t size/*, size_t alignment*/ ) { return uf::memoryPool::alloc( *this, data, size/*, alignment*/ ); } +//void* uf::MemoryPool::alloc( size_t size, void* data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( *this, data, size/*, alignment*/ ); } +pod::Allocation uf::MemoryPool::allocate( size_t size/*, size_t alignment*/ ) { return uf::memoryPool::allocate( *this, size/*, alignment*/ ); } +void* uf::MemoryPool::alloc( size_t size/*, size_t alignment*/ ) { return uf::memoryPool::alloc( *this, size/*, alignment*/ ); } +//pod::Allocation& uf::MemoryPool::fetch( void* data, size_t size ) { return uf::memoryPool::fetch( *this, data, size ); } +bool uf::MemoryPool::exists( void* data, size_t size ) { return uf::memoryPool::exists( *this, data, size ); } +bool uf::MemoryPool::free( void* data, size_t size ) { return uf::memoryPool::free( *this, data, size ); } -//const pod::MemoryPool::allocations_t& uf::MemoryPool::allocations() const { return uf::memoryPool::allocations( m_pod ); } -inline pod::MemoryPool& uf::MemoryPool::data() { return m_pod; } -inline const pod::MemoryPool& uf::MemoryPool::data() const { return m_pod; } +//const pod::MemoryPool::allocations_t& uf::MemoryPool::allocations() const { return uf::memoryPool::allocations( *this ); } +inline pod::MemoryPool& uf::MemoryPool::data() { return *this; } +inline const pod::MemoryPool& uf::MemoryPool::data() const { return *this; } -template T& uf::MemoryPool::alloc( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( m_pod, data/*, alignment*/ ); } -template pod::Allocation uf::MemoryPool::allocate( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::allocate( m_pod, data/*, alignment*/ ); } -template bool uf::MemoryPool::exists( const T& data ) { return uf::memoryPool::exists( m_pod, data ); } -template bool uf::MemoryPool::free( const T& data ) { return uf::memoryPool::free( m_pod, data ); } \ No newline at end of file +template T& uf::MemoryPool::alloc( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( *this, data/*, alignment*/ ); } +template pod::Allocation uf::MemoryPool::allocate( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::allocate( *this, data/*, alignment*/ ); } +template bool uf::MemoryPool::exists( const T& data ) { return uf::memoryPool::exists( *this, data ); } +template bool uf::MemoryPool::free( const T& data ) { return uf::memoryPool::free( *this, data ); } \ No newline at end of file diff --git a/engine/inc/uf/utils/mesh/mesh.h b/engine/inc/uf/utils/mesh/mesh.h index a77e8c99..42a42365 100644 --- a/engine/inc/uf/utils/mesh/mesh.h +++ b/engine/inc/uf/utils/mesh/mesh.h @@ -198,11 +198,12 @@ namespace uf { uf::stl::unordered_map attributes; - const AttributeView& operator[](const uf::stl::string& name) const { - //static AttributeView null{}; + bool has( const uf::stl::string& name ) const { + return attributes.count( name ) > 0; + } + const AttributeView& operator[]( const uf::stl::string& name ) const { if ( auto it = attributes.find(name); it != attributes.end() ) return it->second; UF_EXCEPTION("invalid view: {}", name); - //return null; } // to-do: resolve dependency order hell diff --git a/engine/inc/uf/utils/text/glyph.h b/engine/inc/uf/utils/text/glyph.h index 4df6b6ea..4ec2eda2 100644 --- a/engine/inc/uf/utils/text/glyph.h +++ b/engine/inc/uf/utils/text/glyph.h @@ -6,46 +6,31 @@ #include #include +#include +#include +#include -namespace uf { - class UF_API Glyph { - protected: - pod::Vector2ui m_size = { 0, 0 }; - pod::Vector2i m_bearing = { 0, 0 }; - pod::Vector2i m_advance = { 0, 0 }; - - pod::Vector2i m_padding = { 0, 0 }; - - bool m_sdf = false; - int m_spread = 0; - uint8_t* m_buffer; - public: - ~Glyph(); +namespace pod { + struct Glyph { + pod::Vector2ui size = {}; + pod::Vector2i bearing = {}; + pod::Vector2i advance = {}; + pod::Vector2i padding = {}; + size_t spread = 0; // 0 if not-SDF - bool generated(); - uint8_t* generate( const uf::stl::string&, unsigned long, uint = 48 ); - uint8_t* generate( ext::freetype::Glyph&, unsigned long, uint = 48 ); - uint8_t* generate( const uf::stl::string&, const uf::stl::string&, uint = 48 ); - uint8_t* generate( ext::freetype::Glyph&, const uf::stl::string&, uint = 48 ); - - void generateSdf( uint8_t* ); - // Get - const pod::Vector2ui& getSize() const; - const pod::Vector2i& getBearing() const; - const pod::Vector2i& getAdvance() const; - const pod::Vector2i& getPadding() const; - const uint8_t* getBuffer() const; - - bool isSdf() const; - int getSpread() const; - // Set - void setSize( const pod::Vector2ui& ); - void setBearing( const pod::Vector2i& ); - void setAdvance( const pod::Vector2i& ); - void setPadding( const pod::Vector2i& ); - - void useSdf( bool = true ); - void setSpread( int ); + uf::stl::vector buffer; }; } + +namespace uf { + namespace glyph { + pod::FT_Glyph UF_API initialize( const uf::stl::string& font ); + uint8_t* UF_API generate( pod::Glyph& glyph, pod::FT_Glyph& face, uint64_t c, size_t size = 48 ); + uint8_t* UF_API generate( pod::Glyph& glyph, pod::FT_Glyph& face, const uf::stl::string& s, size_t size = 48 ); + uint8_t* UF_API generate( pod::Glyph& glyph, pod::FT_Glyph& face ); + + void UF_API generateSdf( pod::Glyph& glyph ); + } +} + #endif \ No newline at end of file diff --git a/engine/inc/uf/utils/text/glyph_.h b/engine/inc/uf/utils/text/graphic.h similarity index 93% rename from engine/inc/uf/utils/text/glyph_.h rename to engine/inc/uf/utils/text/graphic.h index 3e91fe15..5e633d92 100644 --- a/engine/inc/uf/utils/text/glyph_.h +++ b/engine/inc/uf/utils/text/graphic.h @@ -5,7 +5,6 @@ #include #include - namespace pod { struct GlyphBox { struct { @@ -16,16 +15,17 @@ namespace pod { pod::Vector3f anchor = { 0, 0, 0 }; uint64_t code = 0; }; + struct TextToken { uf::stl::string text; pod::Vector4f color; }; + struct GlyphSettings { uf::stl::string alignment = ""; uf::stl::string font = "Coolvetica.ttf"; - float size = 96; - bool sdf = true; - float spread = 8; + size_t size = 96; + size_t spread = 0; pod::Vector2ui padding = { 8, 8 }; }; } diff --git a/engine/src/engine/ext/ext.cpp b/engine/src/engine/ext/ext.cpp index 120b8d4b..3ce04598 100644 --- a/engine/src/engine/ext/ext.cpp +++ b/engine/src/engine/ext/ext.cpp @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -743,6 +744,11 @@ void UF_API uf::initialize() { } pod::Thread& threadMain = uf::thread::get(uf::thread::mainThreadName); +#if UF_USE_FREETYPE + { + ext::freetype::initialize(); + } +#endif #if UF_USE_DISCORD /* Discord */ if ( /*global*/::config.engine.ext.discord.enabled ) { ext::discord::initialize(); @@ -1075,6 +1081,11 @@ void UF_API uf::terminate() { { ext::lua::terminate(); } +#endif +#if UF_USE_FREETYPE + { + ext::freetype::terminate(); + } #endif { uf::graph::destroy(); diff --git a/engine/src/engine/ext/gui/behavior.cpp b/engine/src/engine/ext/gui/behavior.cpp index fbc84f0e..c847765e 100644 --- a/engine/src/engine/ext/gui/behavior.cpp +++ b/engine/src/engine/ext/gui/behavior.cpp @@ -37,7 +37,10 @@ namespace { #else pod::Vector4b color; #endif + + #if !UF_USE_OPENGL pod::Vector2f offset; + #endif static uf::stl::vector descriptor; }; @@ -91,6 +94,15 @@ namespace { uf::Mesh& generateMesh( uf::Mesh& mesh, const pod::Vector4f& color, const pod::Vector2f& center ) { mesh.bind<::GuiVertex, uint16_t>(); mesh.insertVertices<::GuiVertex>({ + #if UF_USE_OPENGL + { pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color }, + { pod::Vector3f{-1.0f, -1.0f, 0.0f} - center, pod::Vector2f{0.0f, 1.0f}, color }, + { pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color }, + + { pod::Vector3f{ 1.0f, -1.0f, 0.0f} - center, pod::Vector2f{1.0f, 1.0f}, color }, + { pod::Vector3f{ 1.0f, 1.0f, 0.0f} - center, pod::Vector2f{1.0f, 0.0f}, color }, + { pod::Vector3f{-1.0f, 1.0f, 0.0f} - center, pod::Vector2f{0.0f, 0.0f}, color }, + #else { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color, center }, { pod::Vector3f{-1.0f, -1.0f, 0.0f}, pod::Vector2f{0.0f, 1.0f}, color, center }, { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color, center }, @@ -98,6 +110,7 @@ namespace { { pod::Vector3f{ 1.0f, -1.0f, 0.0f}, pod::Vector2f{1.0f, 1.0f}, color, center }, { pod::Vector3f{ 1.0f, 1.0f, 0.0f}, pod::Vector2f{1.0f, 0.0f}, color, center }, { pod::Vector3f{-1.0f, 1.0f, 0.0f}, pod::Vector2f{0.0f, 0.0f}, color, center }, + #endif }); mesh.insertIndices({ 0, 1, 2, 3, 4, 5 @@ -553,26 +566,21 @@ void ext::GuiBehavior::tick( uf::Object& self ) { pod::Vector2f min = { std::numeric_limits::max(), std::numeric_limits::max() }; pod::Vector2f max = { -std::numeric_limits::max(), -std::numeric_limits::max() }; - uf::Mesh::Attribute positionAttribute; - uf::Mesh::Attribute offsetAttribute; - for ( auto& attribute : mesh.vertex.attributes ) { - if ( attribute.descriptor.name == "position" ) positionAttribute = attribute; - if ( attribute.descriptor.name == "offset" ) offsetAttribute = attribute; - } - UF_ASSERT( positionAttribute.descriptor.name == "position" ); + for ( const auto& view : mesh.buffer_views ) { + auto posView = view["position"]; + auto offView = view.has("offset") ? view["offset"] : uf::Mesh::AttributeView{}; + for ( auto i = 0; i < view.vertex.count; ++i ) { + auto pos = uf::mesh::fetchVertex( view, posView, i ); + auto off = offView.valid() ? uf::mesh::fetchVertex( view, offView, i ) : pod::Vector3f{}; + auto position = pod::Vector4f{ pos.x + off.x, pos.y + off.y, /*pos.z + off.z*/ 0, 1 }; - for ( auto i = 0; i < mesh.vertex.count; ++i ) { - float* p = (float*) (static_cast(positionAttribute.pointer) + i * positionAttribute.stride ); - float* o = (float*) (static_cast(offsetAttribute.pointer) + i * offsetAttribute.stride ); - // pod::Vector4f position = { p[0], p[1], p[2], 1 }; - pod::Vector4f position = { p[0] + o[0], p[1] + o[1], 0, 1 }; - - pod::Vector4f translated = uf::matrix::multiply( model, position ); - min.x = std::min( min.x, translated.x ); - max.x = std::max( max.x, translated.x ); - - min.y = std::min( min.y, translated.y ); - max.y = std::max( max.y, translated.y ); + auto translated = uf::matrix::multiply( model, position ); + min.x = std::min( min.x, translated.x ); + max.x = std::max( max.x, translated.x ); + + min.y = std::min( min.y, translated.y ); + max.y = std::max( max.y, translated.y ); + } } metadata.boxMin.x = min.x; diff --git a/engine/src/engine/ext/gui/glyph/behavior.cpp b/engine/src/engine/ext/gui/glyph/behavior.cpp index e73668de..8edfbc63 100644 --- a/engine/src/engine/ext/gui/glyph/behavior.cpp +++ b/engine/src/engine/ext/gui/glyph/behavior.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -45,7 +45,7 @@ void ext::GuiGlyphBehavior::initialize( uf::Object& self ) { // override #if UF_USE_OPENGL - metadata.sdf = false; + metadata.spread = 0; #endif metadataGui.scaling = "none"; @@ -60,7 +60,6 @@ void ext::GuiGlyphBehavior::initialize( uf::Object& self ) { .alignment = metadataGui.alignment, .font = font, .size = metadata.size, - .sdf = metadata.sdf, .spread = metadata.spread, .padding = metadata.padding, }; @@ -70,7 +69,7 @@ void ext::GuiGlyphBehavior::initialize( uf::Object& self ) { uf::glyph::generateMesh( layout, settings, atlas, mesh ); // set proper shaders - if ( metadata.sdf ) { + if ( metadata.spread > 0 ) { metadataJson["shaders"]["vertex"] = uf::io::root+"/shaders/gui/text/vert.spv"; metadataJson["shaders"]["fragment"] = uf::io::root+"/shaders/gui/text/frag.spv"; } @@ -143,7 +142,6 @@ void ext::GuiGlyphBehavior::destroy( uf::Object& self ){} void ext::GuiGlyphBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ){ serializer["string"] = /*this->*/string; serializer["font"] = /*this->*/font; - serializer["sdf"] = /*this->*/sdf; serializer["spread"] = /*this->*/spread; serializer["padding"] = uf::vector::encode( /*this->*/padding); @@ -158,14 +156,12 @@ void ext::GuiGlyphBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali .alignment = "", .font = /*this->*/font, .size = /*this->*/size, - .sdf = /*this->*/sdf, .spread = /*this->*/spread, .padding = /*this->*/padding, }); /*this->*/string = serializer["string"].as(/*this->*/string); /*this->*/font = serializer["font"].as(/*this->*/font); - /*this->*/sdf = serializer["sdf"].as(/*this->*/sdf); /*this->*/spread = serializer["spread"].as(/*this->*/spread); /*this->*/padding = uf::vector::decode(serializer["padding"], /*this->*/padding); @@ -179,7 +175,6 @@ void ext::GuiGlyphBehavior::Metadata::deserialize( uf::Object& self, uf::Seriali .alignment = "", .font = /*this->*/font, .size = /*this->*/size, - .sdf = /*this->*/sdf, .spread = /*this->*/spread, .padding = /*this->*/padding, }); diff --git a/engine/src/engine/ext/gui/glyph/behavior.h b/engine/src/engine/ext/gui/glyph/behavior.h index 6c4b1b63..aff54a56 100644 --- a/engine/src/engine/ext/gui/glyph/behavior.h +++ b/engine/src/engine/ext/gui/glyph/behavior.h @@ -11,17 +11,12 @@ namespace ext { EXT_BEHAVIOR_DEFINE_TRAITS(); EXT_BEHAVIOR_DEFINE_FUNCTIONS(); UF_BEHAVIOR_DEFINE_METADATA( - uf::stl::string font = "Coolvetica.ttf"; uf::stl::string string = ""; - - bool sdf = true; - float size = 96; - float spread = 8; - + uf::stl::string font = "Coolvetica.ttf"; + size_t size = 96; + size_t spread = 8; pod::Vector2ui padding = { 8, 8 }; - size_t reserve = 128; - struct { float scale = 1.5; float weight = 0.45; diff --git a/engine/src/engine/ext/light/behavior.cpp b/engine/src/engine/ext/light/behavior.cpp index 9a638ce8..15441c41 100644 --- a/engine/src/engine/ext/light/behavior.cpp +++ b/engine/src/engine/ext/light/behavior.cpp @@ -95,7 +95,7 @@ void ext::LightBehavior::initialize( uf::Object& self ) { } if ( radius.y < radius.x ) radius.y = 2048; camera.setProjection( uf::matrix::perspective( fov, (float) size.x / (float) size.y, radius.x, radius.y ) ); - camera.update(true); + camera.update(); uf::stl::string name = "RT:" + std::to_string((int) this->getUid()); renderMode.blitter.process = false; @@ -226,7 +226,7 @@ void ext::LightBehavior::tick( uf::Object& self ) { camera.setView( uf::matrix::inverse( model ), i ); } } else { - // camera.update(true); + // camera.update(); } } } diff --git a/engine/src/engine/ext/player/behavior.cpp b/engine/src/engine/ext/player/behavior.cpp index e14f241e..618e9a72 100644 --- a/engine/src/engine/ext/player/behavior.cpp +++ b/engine/src/engine/ext/player/behavior.cpp @@ -75,7 +75,7 @@ void ext::PlayerBehavior::initialize( uf::Object& self ) { } camera.setProjection( uf::matrix::perspective( fov, raidou, range.x, range.y ) ); } - camera.update(true); + camera.update(); } // sloppy @@ -682,7 +682,7 @@ void ext::PlayerBehavior::tick( uf::Object& self ) { } } #endif - camera.update(true); + camera.update(); #if UF_ENTITY_METADATA_USE_JSON metadata.serialize(self, metadataJson); diff --git a/engine/src/engine/ext/scene/behavior.cpp b/engine/src/engine/ext/scene/behavior.cpp index 513a889b..34bab9f0 100644 --- a/engine/src/engine/ext/scene/behavior.cpp +++ b/engine/src/engine/ext/scene/behavior.cpp @@ -254,7 +254,7 @@ void ext::ExtSceneBehavior::initialize( uf::Object& self ) { "right", "left", }; - uf::Image::container_t pixels; + pod::Image::container_t pixels; uf::stl::vector images(filenames.size()); pod::Vector2ui size = {0,0}; diff --git a/engine/src/engine/scene/scene.cpp b/engine/src/engine/scene/scene.cpp index ecbb0834..846a41a0 100644 --- a/engine/src/engine/scene/scene.cpp +++ b/engine/src/engine/scene/scene.cpp @@ -82,8 +82,8 @@ uf::Camera& uf::Scene::getCamera( uf::Entity& controller ) { if ( lastFrame != uf::time::frame ) { auto& sourceCamera = controller.getComponent(); - // update if camera wasn't already updated - //sourceCamera.update(true); + // update not + if ( controller.getName() == "Player" ) sourceCamera.update(); // copy all matrices for ( auto i = 0; i < uf::camera::maxViews; ++i ) { cachedCamera.setView(sourceCamera.getView(i), i); diff --git a/engine/src/ext/freetype/freetype.cpp b/engine/src/ext/freetype/freetype.cpp index 94143d54..35ee3abc 100644 --- a/engine/src/ext/freetype/freetype.cpp +++ b/engine/src/ext/freetype/freetype.cpp @@ -2,13 +2,34 @@ #if UF_USE_FREETYPE #include -namespace { - unsigned long first_codepoint(const std::u8string& str) { - if (str.empty()) UF_EXCEPTION("Empty string"); +namespace impl { + FT_Library library; - const unsigned char* bytes = reinterpret_cast(str.data()); - unsigned char b0 = bytes[0]; - unsigned long codepoint = 0; + uf::stl::string error( int error ) { + #undef FTERRORS_H_ + #define FT_ERRORDEF( e, v, s ) { e, s }, + #define FT_ERROR_START_LIST { + #define FT_ERROR_END_LIST { 0, NULL } }; + + const struct FTErrors { + int err_code; + const char* err_msg; + } ft_errors[] = + #include FT_ERRORS_H + + for ( int i = 0; i < sizeof(ft_errors) / sizeof(FTErrors); ++i ) { + if ( ft_errors[i].err_code == error ) return ft_errors[i].err_msg; + } + + return ft_errors[0].err_msg; + } + + uint64_t first_codepoint(const std::u8string& str) { + if ( str.empty() ) UF_EXCEPTION("Empty string"); + + const uint8_t* bytes = reinterpret_cast(str.data()); + uint8_t b0 = bytes[0]; + uint64_t codepoint = 0; int extra_bytes = 0; if (b0 < 0x80) { @@ -27,7 +48,7 @@ namespace { } for (int i = 0; i < extra_bytes; ++i) { - unsigned char bx = bytes[i+1]; + uint8_t bx = bytes[i+1]; if ((bx >> 6) != 0x2) UF_EXCEPTION("Invalid continuation byte"); codepoint = (codepoint << 6) | (bx & 0x3F); } @@ -36,117 +57,70 @@ namespace { } } -ext::freetype::Library ext::freetype::library; - -ext::freetype::Library::Library() : loaded(false) { - ext::freetype::initialize(); -} -ext::freetype::Library::~Library() { - this->loaded = false; - ext::freetype::terminate(); -} -ext::freetype::Glyph::~Glyph() { - ext::freetype::destroy(*this); +pod::FT_Glyph::~FT_Glyph() { + ext::freetype::destroy( *this ); } bool ext::freetype::initialize() { - int error = 0; - if ( (error = FT_Init_FreeType( &ext::freetype::library.library ) )) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to initialize" << std::endl; + if ( auto error = FT_Init_FreeType( &impl::library ) ) { + UF_MSG_ERROR("FreeType failed to initialize: {}", impl::error( error )); return false; } - ext::freetype::library.loaded = true; return true; } -bool ext::freetype::initialized() { - return ext::freetype::library.loaded; -} void ext::freetype::terminate() { - if ( !ext::freetype::library.loaded ) return; - FT_Done_FreeType(ext::freetype::library.library); - ext::freetype::library.loaded = false; + FT_Done_FreeType( impl::library ); } -ext::freetype::Glyph ext::freetype::initialize( const uf::stl::string& font ) { - if ( !ext::freetype::initialized() ) ext::freetype::initialize(); - ext::freetype::Glyph glyph; - int error = 0; - if ( (error = FT_New_Face( ext::freetype::library.library, font.c_str(), 0, &glyph.face )) ) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load file `" << font << "`" << std::endl; +pod::FT_Glyph ext::freetype::initialize( const uf::stl::string& font ) { + pod::FT_Glyph g; + if ( auto error = FT_New_Face( impl::library, font.c_str(), 0, &g.face ) ) { + UF_MSG_ERROR("FreeType failed to load file '{}': {}", font, impl::error( error )); } - if ( (error = FT_Select_Charmap( glyph.face, FT_ENCODING_UNICODE )) ) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load file `" << font << "`" << std::endl; + if ( auto error = FT_Select_Charmap( g.face, FT_ENCODING_UNICODE ) ) { + UF_MSG_ERROR("FreeType failed to load file '{}': {}", font, impl::error( error )); } - return glyph; + return g; } -bool ext::freetype::initialize( ext::freetype::Glyph& glyph, const uf::stl::string& font ) { - if ( !ext::freetype::initialized() ) ext::freetype::initialize(); - int error = 0; - if ( (error = FT_New_Face( ext::freetype::library.library, font.c_str(), 0, &glyph.face )) ) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load file `" << font << "`" << std::endl; +bool ext::freetype::initialize( pod::FT_Glyph& g, const uf::stl::string& font ) { + if ( auto error = FT_New_Face( impl::library, font.c_str(), 0, &g.face ) ) { + UF_MSG_ERROR("FreeType failed to load file '{}': {}", font, impl::error( error )); return false; } - if ( (error = FT_Select_Charmap( glyph.face, FT_ENCODING_UNICODE )) ) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load file `" << font << "`" << std::endl; + if ( auto error = FT_Select_Charmap( g.face, FT_ENCODING_UNICODE ) ) { + UF_MSG_ERROR("FreeType failed to load file '{}': {}", font, impl::error( error )); return false; } return true; } -void ext::freetype::destroy( ext::freetype::Glyph& glyph ) { - FT_Done_Face( glyph.face ); +void ext::freetype::destroy( pod::FT_Glyph& g ) { + FT_Done_Face( g.face ); } -void ext::freetype::setPixelSizes( ext::freetype::Glyph& glyph, int height ) { - FT_Set_Pixel_Sizes( glyph.face, 0, height ); +void ext::freetype::setPixelSizes( pod::FT_Glyph& g, size_t height ) { + FT_Set_Pixel_Sizes( g.face, 0, height ); } -void ext::freetype::setPixelSizes( ext::freetype::Glyph& glyph, int width, int height ) { - FT_Set_Pixel_Sizes( glyph.face, width, height ); +void ext::freetype::setPixelSizes( pod::FT_Glyph& g, size_t width, size_t height ) { + FT_Set_Pixel_Sizes( g.face, width, height ); } -void ext::freetype::setRenderMode( ext::freetype::Glyph& glyph, decltype(FT_RENDER_MODE_NORMAL) mode ) { - FT_Render_Glyph( glyph.face->glyph, mode ); +void ext::freetype::setRenderMode( pod::FT_Glyph& g, FT_Render_Mode mode ) { + FT_Render_Glyph( g.face->glyph, mode ); } -bool ext::freetype::load( ext::freetype::Glyph& glyph, unsigned long c ) { - int error = 0; - if ( (error = FT_Load_Char(glyph.face, c, FT_LOAD_RENDER) )) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load glyph `" << c << "`" << std::endl; +bool ext::freetype::load( pod::FT_Glyph& g, uint64_t c ) { + if ( auto error = FT_Load_Char(g.face, c, FT_LOAD_RENDER) ) { + UF_MSG_ERROR("FreeType failed to load glyph '{}': {}", c, impl::error( error )); return false; } return true; } -bool ext::freetype::load( ext::freetype::Glyph& glyph, const uf::stl::string& string ) { +bool ext::freetype::load( pod::FT_Glyph& g, const uf::stl::string& string ) { #if UF_USE_DEPRECATED_STRING - unsigned long c = string.translate().at(0); + uint64_t c = string.translate().at(0); #else - unsigned long c = first_codepoint( std::u8string( string.begin(), string.end() ) ); + uint64_t c = impl::first_codepoint( std::u8string( string.begin(), string.end() ) ); #endif - int error = 0; - if ( (error = FT_Load_Char(glyph.face, FT_Get_Char_Index(glyph.face, c), FT_LOAD_RENDER) )) { - std::cout << "Error #" << ext::freetype::getError(error) << ": FreeType failed to load glyph `" << c << "`" << std::endl; - return false; - } - return true; -} - -uf::stl::string ext::freetype::getError( int error ) { - #undef FTERRORS_H_ - #define FT_ERRORDEF( e, v, s ) { e, s }, - #define FT_ERROR_START_LIST { - #define FT_ERROR_END_LIST { 0, NULL } }; - - const struct FTErrors { - int err_code; - const char* err_msg; - } ft_errors[] = - #include FT_ERRORS_H - - for ( int i = 0; i < sizeof(ft_errors) / sizeof(FTErrors); ++i ) { - // std::cout << ft_errors[i].err_msg << std::endl; - if ( ft_errors[i].err_code == error ) - return ft_errors[i].err_msg; - } - - return ft_errors[0].err_msg; + return ext::freetype::load( g, c ); } #endif \ No newline at end of file diff --git a/engine/src/ext/lua/usertypes/camera.cpp b/engine/src/ext/lua/usertypes/camera.cpp index 3cbf8a24..202e54d9 100644 --- a/engine/src/ext/lua/usertypes/camera.cpp +++ b/engine/src/ext/lua/usertypes/camera.cpp @@ -40,8 +40,8 @@ namespace binds { self.setProjection(matrix); } } - void update( uf::Camera& self, sol::optional force ) { - self.update(force.value_or(true)); + void update( uf::Camera& self ) { + self.update(); } } diff --git a/engine/src/ext/texconv/texconv.cpp b/engine/src/ext/texconv/texconv.cpp index 3cab8806..9de786e1 100644 --- a/engine/src/ext/texconv/texconv.cpp +++ b/engine/src/ext/texconv/texconv.cpp @@ -49,17 +49,17 @@ namespace { auto height = image.height(); auto& pixels = image.pixels(); - uf::Image::container_t buffer; - buffer.reserve(width * height * 4); + pod::Image out; + out.pixels.reserve(width * height * 4); for (auto& pixel : pixels) { - buffer.emplace_back(pixel.r); - buffer.emplace_back(pixel.g); - buffer.emplace_back(pixel.b); - buffer.emplace_back(pixel.a); + out.pixels.emplace_back(pixel.r); + out.pixels.emplace_back(pixel.g); + out.pixels.emplace_back(pixel.b); + out.pixels.emplace_back(pixel.a); } - return uf::Image{ std::move(buffer), { width, height } }; + return out; } } diff --git a/engine/src/ext/vulkan/buffer.cpp b/engine/src/ext/vulkan/buffer.cpp index cc039322..2a3374f6 100644 --- a/engine/src/ext/vulkan/buffer.cpp +++ b/engine/src/ext/vulkan/buffer.cpp @@ -23,6 +23,7 @@ void ext::vulkan::Buffer::swap( ext::vulkan::Buffer& buffer ) { std::swap(this->allocationInfo, buffer.allocationInfo); std::swap(this->count, buffer.count); std::swap(this->written, buffer.written); + std::swap(this->staged, buffer.staged); } ext::vulkan::Buffer ext::vulkan::Buffer::alias() const { ext::vulkan::Buffer buffer; @@ -44,6 +45,7 @@ void ext::vulkan::Buffer::aliasBuffer( const ext::vulkan::Buffer& buffer ) { this->allocationInfo = buffer.allocationInfo; this->count = buffer.count; this->written = buffer.written; + this->staged = buffer.staged; } void* ext::vulkan::Buffer::map( VkDeviceSize size, VkDeviceSize offset ) { @@ -95,9 +97,10 @@ size_t ext::vulkan::Buffer::getOffset( size_t i ) const { ext::vulkan::Buffer::~Buffer() { // this->destroy(); // bad, will get called every time a vector gets resized, buffer owners will clean it up in their own destructors } -void ext::vulkan::Buffer::initialize( ext::vulkan::Device& device, size_t alignment ) { +void ext::vulkan::Buffer::initialize( ext::vulkan::Device& device, size_t alignment, bool staged ) { this->device = &device; this->alignment = alignment; + this->staged = staged; } void ext::vulkan::Buffer::destroy(bool defer) { if ( !device || aliased ) return; @@ -122,10 +125,11 @@ void ext::vulkan::Buffer::destroy(bool defer) { this->allocationInfo = {}; this->count = 1; this->written = false; + this->staged = VK_DEFAULT_STAGE_BUFFERS; } void ext::vulkan::Buffer::initialize( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties ) { if ( !device ) device = &ext::vulkan::device; - if ( VK_DEFAULT_STAGE_BUFFERS ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties + if ( this->staged ) usage |= VK_BUFFER_USAGE_TRANSFER_DST_BIT; // implicitly set properties // assume all UBOs are dynamic auto totalLength = length; @@ -184,7 +188,7 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length ) const } } - if ( !VK_DEFAULT_STAGE_BUFFERS ) { + if ( !this->staged ) { auto* self = const_cast(this); void* map = self->map(length); for ( const auto& region : regions ) memcpy(static_cast(map) + region.dstOffset, data, length); @@ -198,7 +202,7 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length ) const data, length, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT ); - auto commandBuffer = device->fetchCommandBuffer(QueueEnum::TRANSFER); // waits on finish + auto commandBuffer = device->fetchCommandBuffer( QueueEnum::TRANSFER ); // waits on finish device->UF_CHECKPOINT_MARK( commandBuffer, pod::Checkpoint::GENERIC, "copyBuffer" ); vkCmdCopyBuffer(commandBuffer, staging.buffer, buffer, regions.size(), regions.data()); device->flushCommandBuffer(commandBuffer); @@ -207,8 +211,9 @@ bool ext::vulkan::Buffer::update( const void* data, VkDeviceSize length ) const // // Buffers -void ext::vulkan::Buffers::initialize( Device& device ) { +void ext::vulkan::Buffers::initialize( Device& device, bool staged ) { this->device = &device; + this->staged = staged; } /* ext::vulkan::Buffers::~Buffers() { @@ -224,7 +229,7 @@ void ext::vulkan::Buffers::destroy(bool defer) { size_t ext::vulkan::Buffers::initializeBuffer( const void* data, VkDeviceSize length, VkBufferUsageFlags usage, VkMemoryPropertyFlags memoryProperties ) { size_t index = buffers.size(); auto& buffer = buffers.emplace_back(); - buffer.initialize( *device, requestedAlignment ); + buffer.initialize( *device, requestedAlignment, this->staged ); buffer.initialize( data, length, usage, memoryProperties ); return index; } diff --git a/engine/src/ext/vulkan/graphic.cpp b/engine/src/ext/vulkan/graphic.cpp index c954f8c7..57435245 100644 --- a/engine/src/ext/vulkan/graphic.cpp +++ b/engine/src/ext/vulkan/graphic.cpp @@ -1695,18 +1695,16 @@ void ext::vulkan::Graphic::generateTopAccelerationStructure( const uf::stl::vect size_t tlasBufferIndex{}; size_t tlasBackBufferIndex{}; - // do not stage, because apparently vkQueueWaitIdle doesn't actually wait for the transfer to complete - // manually copy because I can't be assed to expose an un-staged API now + // do not stage to avoid needing to wait for the transfer if ( !update ) { - instanceIndex = this->buffers.size(); - auto& buffer = this->buffers.emplace_back(); - buffer.alignment = 16; - device.createBuffer( + this->requestedAlignment = 16; + this->staged = false; + instanceIndex = this->initializeBuffer( (const void*) instancesVK.data(), instancesVK.size() * sizeof(VkAccelerationStructureInstanceKHR), - VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR, - VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, - buffer + VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT | VK_BUFFER_USAGE_ACCELERATION_STRUCTURE_BUILD_INPUT_READ_ONLY_BIT_KHR ); + this->staged = true; + this->requestedAlignment = 0; this->metadata.buffers["tlasInstance"] = instanceIndex; } else { if ( this->metadata.buffers.count("tlasInstance") > 0 ) { diff --git a/engine/src/utils/camera/camera.cpp b/engine/src/utils/camera/camera.cpp index 9ff17e08..2fbc5b06 100644 --- a/engine/src/utils/camera/camera.cpp +++ b/engine/src/utils/camera/camera.cpp @@ -8,9 +8,8 @@ #else bool uf::matrix::reverseInfiniteProjection = true; #endif -// const uint_fast8_t uf::camera::maxViews = 6; -pod::Vector3f uf::camera::eye( const pod::Camera& camera, uint_fast8_t i ) { +pod::Vector3f uf::camera::eye( const pod::Camera& camera, size_t i ) { pod::Vector3f position = uf::transform::flatten( camera.transform ).position; #if UF_USE_OPENVR if ( camera.stereoscopic && ext::openvr::context ) { @@ -19,32 +18,27 @@ pod::Vector3f uf::camera::eye( const pod::Camera& camera, uint_fast8_t i ) { #endif return position; } -void uf::camera::view( pod::Camera& camera, const pod::Matrix4f& mat, uint_fast8_t i ) { - camera.ttl = uf::time::frame + 1; +void uf::camera::view( pod::Camera& camera, const pod::Matrix4f& mat, size_t i ) { if ( i >= uf::camera::maxViews ) { for ( i = 0; i < uf::camera::maxViews; ++i ) { -// camera.previous[i] = camera.viewport.matrices[i].projection * camera.viewport.matrices[i].view; camera.viewport.matrices[i].view = mat; } return; } -// camera.previous[i] = camera.viewport.matrices[i].projection * camera.viewport.matrices[i].view; camera.viewport.matrices[i].view = mat; } -void uf::camera::projection( pod::Camera& camera, const pod::Matrix4f& mat, uint_fast8_t i ) { - camera.ttl = uf::time::frame + 1; +void uf::camera::projection( pod::Camera& camera, const pod::Matrix4f& mat, size_t i ) { if ( i >= uf::camera::maxViews ) { for ( i = 0; i < uf::camera::maxViews; ++i ) camera.viewport.matrices[i].projection = mat; return; } camera.viewport.matrices[i].projection = mat; } -void uf::camera::update( pod::Camera& camera, bool override ) { - if ( !override && uf::time::frame <= camera.ttl ) return; // skip updating the view matrices if it was already updated +void uf::camera::update( pod::Camera& camera ) { #if UF_USE_OPENVR - if ( this->m_pod.stereoscopic && ext::openvr::context ) { + if ( this->stereoscopic && ext::openvr::context ) { camera.transform.orientation = uf::quaternion::identity(); - pod::Matrix4t<> view = uf::matrix::inverse( uf::transform::model( camera.transform ) ); + auto view = uf::matrix::inverse( uf::transform::model( camera.transform ) ); camera.transform.orientation = ext::openvr::hmdQuaternion(); uf::camera::view( camera, ext::openvr::hmdViewMatrix(vr::Eye_Left, view ), 0 ); @@ -52,51 +46,44 @@ void uf::camera::update( pod::Camera& camera, bool override ) { } else #endif { - pod::Matrix4t<> view = uf::matrix::inverse( uf::transform::model( camera.transform ) ); + auto view = uf::matrix::inverse( uf::transform::model( camera.transform ) ); uf::camera::view( camera, view ); } } // uf::Camera::Camera() { - this->m_pod.ttl = {}; - this->m_pod.stereoscopic = true; - - this->m_pod.transform = uf::transform::initialize(this->m_pod.transform); - for ( uint_fast8_t i = 0; i < uf::camera::maxViews; ++i ) { - this->m_pod.viewport.matrices[i].view = uf::matrix::identity(); - this->m_pod.viewport.matrices[i].projection = uf::matrix::identity(); - // this->m_pod.previous[i] = uf::matrix::identity(); + this->stereoscopic = true; + this->transform = uf::transform::initialize(this->transform); + for ( auto i = 0; i < uf::camera::maxViews; ++i ) { + this->viewport.matrices[i].view = uf::matrix::identity(); + this->viewport.matrices[i].projection = uf::matrix::identity(); } } -pod::Camera& uf::Camera::data() { return this->m_pod; } -const pod::Camera& uf::Camera::data() const { return this->m_pod; } +pod::Camera& uf::Camera::data() { return *this; } +const pod::Camera& uf::Camera::data() const { return *this; } -pod::Transform<>& uf::Camera::getTransform() { return this->m_pod.transform; } -const pod::Transform<>& uf::Camera::getTransform() const { return this->m_pod.transform; } -void uf::Camera::setTransform( const pod::Transform<>& transform ) { this->m_pod.transform = transform; } +pod::Transform<>& uf::Camera::getTransform() { return this->transform; } +const pod::Transform<>& uf::Camera::getTransform() const { return this->transform; } +void uf::Camera::setTransform( const pod::Transform<>& transform ) { this->transform = transform; } -pod::Matrix4& uf::Camera::getView( uint_fast8_t i ) { return this->m_pod.viewport.matrices[MIN(i, uf::camera::maxViews)].view; } -const pod::Matrix4& uf::Camera::getView( uint_fast8_t i ) const { return this->m_pod.viewport.matrices[MIN(i, uf::camera::maxViews)].view; } +pod::Matrix4& uf::Camera::getView( size_t i ) { return this->viewport.matrices[MIN(i, uf::camera::maxViews)].view; } +const pod::Matrix4& uf::Camera::getView( size_t i ) const { return this->viewport.matrices[MIN(i, uf::camera::maxViews)].view; } -pod::Matrix4& uf::Camera::getProjection( uint_fast8_t i ) { return this->m_pod.viewport.matrices[MIN(i, uf::camera::maxViews)].projection; } -const pod::Matrix4& uf::Camera::getProjection( uint_fast8_t i ) const { return this->m_pod.viewport.matrices[MIN(i, uf::camera::maxViews)].projection; } +pod::Matrix4& uf::Camera::getProjection( size_t i ) { return this->viewport.matrices[MIN(i, uf::camera::maxViews)].projection; } +const pod::Matrix4& uf::Camera::getProjection( size_t i ) const { return this->viewport.matrices[MIN(i, uf::camera::maxViews)].projection; } -// pod::Matrix4& uf::Camera::getPrevious( uint_fast8_t i ) { return this->m_pod.previous[MIN(i, uf::camera::maxViews)]; } -// const pod::Matrix4& uf::Camera::getPrevious( uint_fast8_t i ) const { return this->m_pod.previous[MIN(i, uf::camera::maxViews)]; } - -bool uf::Camera::modified() const { return uf::time::frame <= this->m_pod.ttl; } -void uf::Camera::setStereoscopic( bool b ) { this->m_pod.stereoscopic = b; } -pod::Vector3f uf::Camera::getEye( uint_fast8_t i ) const { - return uf::camera::eye( this->m_pod, i ); +void uf::Camera::setStereoscopic( bool b ) { this->stereoscopic = b; } +pod::Vector3f uf::Camera::getEye( size_t i ) const { + return uf::camera::eye( *this, i ); } -void uf::Camera::setView( const pod::Matrix4& mat, uint_fast8_t i ) { - uf::camera::view( this->m_pod, mat, i ); +void uf::Camera::setView( const pod::Matrix4& mat, size_t i ) { + uf::camera::view( *this, mat, i ); } -void uf::Camera::setProjection( const pod::Matrix4& mat, uint_fast8_t i ) { - uf::camera::projection( this->m_pod, mat, i ); +void uf::Camera::setProjection( const pod::Matrix4& mat, size_t i ) { + uf::camera::projection( *this, mat, i ); } -void uf::Camera::update( bool override ) { - uf::camera::update( this->m_pod, override ); +void uf::Camera::update() { + uf::camera::update( *this ); } \ No newline at end of file diff --git a/engine/src/utils/debug/draw.cpp b/engine/src/utils/debug/draw.cpp index d120577c..7d6a04f9 100644 --- a/engine/src/utils/debug/draw.cpp +++ b/engine/src/utils/debug/draw.cpp @@ -3,7 +3,7 @@ #include #include #include -#include +#include namespace impl { struct Vertex { @@ -41,7 +41,7 @@ namespace impl { .alignment = "center", .font = "FragmentMono.ttf", .size = 48, - .sdf = false, + .spread = 0, }; } @@ -242,6 +242,7 @@ void uf::debug::drawLines( float dt ) { if ( !graphic.initialized ) { graphic.device = &uf::renderer::device; + graphic.staged = false; graphic.material.device = &uf::renderer::device; // to-do: bin by descriptor instead of one global set @@ -323,6 +324,7 @@ void uf::debug::drawTexts( float dt ) { auto& graphic = graphics["immediate:texts"]; if ( !graphic.initialized ) { graphic.device = &uf::renderer::device; + graphic.staged = false; graphic.material.device = &uf::renderer::device; graphic.descriptor.depth.test = uf::physics::settings.debugDraw.depthTest; diff --git a/engine/src/utils/image/atlas.cpp b/engine/src/utils/image/atlas.cpp index 1e7dacf4..879badd3 100644 --- a/engine/src/utils/image/atlas.cpp +++ b/engine/src/utils/image/atlas.cpp @@ -3,38 +3,32 @@ #include #include -uf::Atlas::hash_t uf::Atlas::addImage( const uf::Image& image, const uf::Atlas::hash_t& hash ) { - size_t index = this->m_tiles.size(); - if ( this->m_tiles.count( hash ) > 0 ) return hash; +pod::Atlas::hash_t uf::atlas::add( pod::Atlas& atlas, const pod::Image& image, const pod::Atlas::hash_t& hash ) { + size_t index = atlas.tiles.size(); + if ( atlas.tiles.count( hash ) > 0 ) return hash; - auto& tile = this->m_tiles[hash]; + auto& tile = atlas.tiles[hash]; tile.image = image; - tile.identifier.hash = hash; - tile.identifier.index = index; return hash; } -uf::Atlas::hash_t uf::Atlas::addImage( const uf::Image& image ) { - return this->addImage( image, image.getHash() ); +pod::Atlas::hash_t uf::atlas::add( pod::Atlas& atlas, const pod::Image& image ) { + return uf::atlas::add( atlas, image, uf::image::hash( image ) ); } -void uf::Atlas::generate( const uf::Atlas::images_t& images, float padding ) { - for ( auto& image : images ) this->addImage( image ); - generate( padding ); -} -void uf::Atlas::generate( float padding ) { - if ( this->m_tiles.empty() ) return; - BinPack2D::CanvasArray internalAtlas; - BinPack2D::ContentAccumulator queue, stored, remainder; - pod::Vector2ui size = {0,0}; - pod::Vector3ui largest = {0,0,0}; +void uf::atlas::generate( pod::Atlas& atlas, float padding ) { + if ( atlas.tiles.empty() ) return; + + BinPack2D::CanvasArray internalAtlas; + BinPack2D::ContentAccumulator queue, stored, remainder; + pod::Vector2ui size = {}; + pod::Vector3ui largest = {}; size_t index = 0; size_t area = 0; size_t channels = 1; - for ( auto pair : this->m_tiles ) { - auto& tile = pair.second; - auto& dim = tile.image.getDimensions(); - channels = std::max( channels, tile.image.getChannels() ); - queue += BinPack2D::Content(tile.identifier, BinPack2D::Coord(), BinPack2D::Size(dim.x, dim.y), false ); + for ( auto& [ hash, tile ] : atlas.tiles ) { + auto& dim = tile.image.size; + channels = std::max( channels, tile.image.channels ); + queue += BinPack2D::Content(hash, BinPack2D::Coord(), BinPack2D::Size(dim.x, dim.y), false ); size += dim; area += dim.x * dim.y; if ( area >= largest.z ) { @@ -47,7 +41,7 @@ void uf::Atlas::generate( float padding ) { size_t side = std::sqrt( area ) * padding; size = { std::bit_ceil(side), std::bit_ceil(side) }; // to-do: non-C++20 method queue.Sort(); - internalAtlas = BinPack2D::UniformCanvasArrayBuilder(size.x, size.y, 1).Build(); + internalAtlas = BinPack2D::UniformCanvasArrayBuilder(size.x, size.y, 1).Build(); bool success = internalAtlas.Place( queue, remainder ); if ( success && remainder.Get().empty() ) break; // increase padding @@ -55,21 +49,17 @@ void uf::Atlas::generate( float padding ) { } while ( --tries ); internalAtlas.CollectContent( stored ); - this->m_atlas.loadFromBuffer( NULL, size, 8, channels ); - auto& dstBuffer = this->m_atlas.getPixels(); + uf::image::load( atlas.image, NULL, size, 8, channels ); + auto& dstBuffer = atlas.image.pixels; for ( size_t i = 0; i < size.x * size.y * channels; ++i ) dstBuffer[i] = 0; for ( auto& it : stored.Get() ) { - auto& tile = this->m_tiles[it.content.hash]; + auto& tile = atlas.tiles[it.content]; tile.coord = { it.coord.x, it.coord.y }; tile.size = { it.size.w, it.size.h }; -/* - } - for ( auto pair : this->m_tiles ) { - auto& tile = pair.second; -*/ + auto& image = tile.image; - auto& srcBuffer = image.getPixels(); - auto srcChannels = image.getChannels(); + auto& srcBuffer = image.pixels; + auto srcChannels = image.channels; for ( size_t y = 0; y < tile.size.y; ++y ) { for ( size_t x = 0; x < tile.size.x; ++x ) { @@ -82,25 +72,27 @@ void uf::Atlas::generate( float padding ) { } } } -bool uf::Atlas::has( const uf::Atlas::hash_t& hash ) const { - return this->m_tiles.count( hash ) > 0; +void uf::atlas::generate( pod::Atlas& atlas, const uf::stl::vector& images, float padding ) { + for ( auto& image : images ) uf::atlas::add( atlas, image ); + uf::atlas::generate( atlas, padding ); } -bool uf::Atlas::generated() const { - return !this->m_atlas.getPixels().empty(); -} -void uf::Atlas::clear( bool full ) { +void uf::atlas::clear( pod::Atlas& atlas, bool full ) { if ( !full ) { - for ( auto pair : this->m_tiles ) pair.second.image.clear(); + for ( auto& [ hash, tile ] : atlas.tiles ) tile.image.pixels.clear(); return; } - this->m_tiles.clear(); - this->m_atlas.clear(); + atlas.tiles.clear(); + atlas.image.pixels.clear(); } -pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, const uf::Atlas::hash_t& hash ) const { - auto it = this->m_tiles.find(hash); - if ( it != this->m_tiles.end() ) { +bool uf::atlas::has( const pod::Atlas& atlas, const pod::Atlas::hash_t& hash ) { + return atlas.tiles.count( hash ) > 0; +} + +pod::Vector2f uf::atlas::mapUv( const pod::Atlas& atlas, const pod::Vector2f& uv, const pod::Atlas::hash_t& hash ) { + auto it = atlas.tiles.find(hash); + if ( it != atlas.tiles.end() ) { auto& tile = it->second; - auto& size = this->m_atlas.getDimensions(); + auto& size = atlas.image.size; pod::Vector2ui coord = { uv.x * tile.size.x + tile.coord.x, uv.y * tile.size.y + tile.coord.y @@ -109,29 +101,46 @@ pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, const uf::Atlas::hash_t } return uv; } -pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, size_t index ) const { - auto& size = this->m_atlas.getDimensions(); - for ( auto pair : this->m_tiles ) { - auto& tile = pair.second; - if ( tile.identifier.index != index ) continue; - pod::Vector2ui coord = { uv.x * tile.size.x + tile.coord.x, uv.y * tile.size.y + tile.coord.y }; - return pod::Vector2f{ (float) coord.x / (float) size.x, (float) coord.y / (float) size.y }; - } - return uv; +pod::Image& uf::atlas::get( pod::Atlas& atlas ) { + return atlas.image; } -pod::Vector3f uf::Atlas::mapUv( const pod::Vector3f& uv ) const { - pod::Vector2f nuv = mapUv( { uv.x, uv.y }, uv.z ); - return { nuv.x, nuv.y, uv.z }; +const pod::Image& uf::atlas::get( const pod::Atlas& atlas ) { + return atlas.image; } -uf::Image& uf::Atlas::getAtlas() { - return this->m_atlas; + +pod::Atlas::hash_t uf::Atlas::addImage( const pod::Image& image, const pod::Atlas::hash_t& hash ) { + return uf::atlas::add( *this, image, hash ); } -const uf::Image& uf::Atlas::getAtlas() const { - return this->m_atlas; +pod::Atlas::hash_t uf::Atlas::addImage( const pod::Image& image ) { + return uf::atlas::add( *this, image, uf::image::hash( image ) ); +} +void uf::Atlas::generate( const uf::Atlas::images_t& images, float padding ) { + uf::atlas::generate( *this, images, padding ); +} +void uf::Atlas::generate( float padding ) { + uf::atlas::generate( *this, padding ); +} +bool uf::Atlas::has( const pod::Atlas::hash_t& hash ) const { + return uf::atlas::has( *this, hash ); +} +bool uf::Atlas::generated() const { + return !this->image.pixels.empty(); +} +void uf::Atlas::clear( bool full ) { + uf::atlas::clear( *this, full ); +} +pod::Vector2f uf::Atlas::mapUv( const pod::Vector2f& uv, const pod::Atlas::hash_t& hash ) const { + return uf::atlas::mapUv( *this, uv, hash ); +} +pod::Image& uf::Atlas::getAtlas() { + return uf::atlas::get( *this ); +} +const pod::Image& uf::Atlas::getAtlas() const { + return uf::atlas::get( *this ); } uf::Atlas::atlas_t& uf::Atlas::getImages() { - return this->m_tiles; + return this->tiles; } const uf::Atlas::atlas_t& uf::Atlas::getImages() const { - return this->m_tiles; + return this->tiles; } \ No newline at end of file diff --git a/engine/src/utils/image/image.cpp b/engine/src/utils/image/image.cpp index b44ad1e0..df97fa17 100644 --- a/engine/src/utils/image/image.cpp +++ b/engine/src/utils/image/image.cpp @@ -13,73 +13,8 @@ #include #include -uf::Image::Image() : m_bpp(8), m_channels(4), m_format(0) { - m_dimensions = {0,0}; -} -uf::Image::Image(const vec2_t& size) : m_dimensions(size), m_bpp(8), m_channels(4), m_format(0) { - m_pixels.resize(size.x * size.y * m_channels); -} - -uf::Image::Image(container_t&& move, const vec2_t& size) : m_pixels(std::move(move)), m_dimensions(size), - m_bpp(8), m_channels(4), m_format(0) {} - -uf::Image::Image(const container_t& copy, const vec2_t& size) : m_pixels(copy), m_dimensions(size), - m_bpp(8), m_channels(4), m_format(0) {} - -uf::Image::Image(const Image& copy) : m_pixels(copy.m_pixels), - m_dimensions(copy.m_dimensions), - m_bpp(copy.m_bpp), m_channels(copy.m_channels), - m_filename(copy.m_filename), m_format(copy.m_format) {} - -uf::Image::Image(Image&& move) noexcept : m_pixels(std::move(move.m_pixels)), - m_dimensions(move.m_dimensions), - m_bpp(move.m_bpp), m_channels(move.m_channels), - m_filename(std::move(move.m_filename)), - m_format(move.m_format) {} - -uf::Image& uf::Image::operator=(const Image& copy) { - if ( this != © ) { - m_pixels = copy.m_pixels; - m_dimensions = copy.m_dimensions; - m_bpp = copy.m_bpp; - m_channels = copy.m_channels; - m_filename = copy.m_filename; - m_format = copy.m_format; - } - return *this; -} - -uf::Image& uf::Image::operator=(Image&& move) noexcept { - if ( this != &move ) { - m_pixels = std::move(move.m_pixels); - m_dimensions = move.m_dimensions; - m_bpp = move.m_bpp; - m_channels = move.m_channels; - m_filename = std::move(move.m_filename); - m_format = move.m_format; - } - return *this; -} - -uf::stl::string uf::Image::getFilename() const { - return this->m_filename; -} -void uf::Image::setFilename( const uf::stl::string& filename ) { - this->m_filename = filename; -} - -#define _PACK4(v) ((v * 0xF) / 0xFF) -#define PACK_ARGB4444(a,r,g,b) (_PACK4(a) << 12) | (_PACK4(r) << 8) | (_PACK4(g) << 4) | (_PACK4(b)) -#define PACK_ARGB8888(a,r,g,b) ( ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | (b & 0xFF) ) -#define PACK_ARGB1555(a,r,g,b) \ - (((uint16_t)(a > 0) << 15) | (((uint16_t) r >> 3) << 10) | (((uint16_t)g >> 3) << 5) | ((uint16_t)b >> 3)) - -#define PACK_RGB565(r,g,b) \ - ((((uint16_t)r & 0xf8) << 8) | (((uint16_t) g & 0xfc) << 3) | ((uint16_t) b >> 3)) - -// from file -bool uf::Image::open( const uf::stl::string& _filename, bool flip ) { +bool uf::image::open( pod::Image& image, const uf::stl::string& _filename, bool flip ) { // to-do: use preferred uf::stl::string filename = uf::io::preferred( _filename ); if ( !uf::io::exists(filename) ) UF_EXCEPTION("IO error: file does not exist: {}", filename); @@ -88,9 +23,9 @@ bool uf::Image::open( const uf::stl::string& _filename, bool flip ) { if ( extension != "dtex" ) UF_MSG_WARNING("non-dtex loading is highly discouraged on this platform: {}", filename); #endif - this->m_filename = filename; - this->m_pixels.clear(); - int width = 0, height = 0, channelsDud = 0, bit_depth = 8, channels = 4; + image.filename = filename; + image.pixels.clear(); + int width = 0, height = 0, channelsDud = 0, bpp = 8, channels = 4; #if UF_USE_OPENGL_GLDC if ( extension == "dtex" ) { struct { @@ -104,8 +39,8 @@ bool uf::Image::open( const uf::stl::string& _filename, bool flip ) { FILE* file = NULL; file = fopen(filename.c_str(), "rb"); fread(&header, sizeof(header), 1, file); - this->m_pixels.resize(header.size); - fread(this->m_pixels.data(), header.size, 1, file); + image.pixels.resize(header.size); + fread(image.pixels.data(), header.size, 1, file); fclose(file); bool twiddled = (header.type & (1 << 26)) < 1; @@ -118,21 +53,21 @@ bool uf::Image::open( const uf::stl::string& _filename, bool flip ) { uint32_t expected = 2 * header.width * header.height; uint32_t ratio = (uint32_t) (((float) expected) / ((float) header.size)); - bit_depth = 4; - this->m_format = format; + bpp = 4; + image.format = format; if ( compressed ) { if ( twiddled ) { switch ( format ) { - case 1: this->m_format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_RGB_565_VQ_TWID_KOS; channels = 3; break; - case 0: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; break; - case 2: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; break; + case 1: image.format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_RGB_565_VQ_TWID_KOS; channels = 3; break; + case 0: image.format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_1555_VQ_TWID_KOS; break; + case 2: image.format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_TWID_KOS : GL_COMPRESSED_ARGB_4444_VQ_TWID_KOS; break; default: UF_EXCEPTION("Image error: invalid texture format: {}", filename); return false; } } else { switch ( format ) { - case 1: this->m_format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS : GL_COMPRESSED_RGB_565_VQ_KOS; channels = 3; break; - case 0: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_1555_VQ_KOS; break; - case 2: this->m_format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_4444_VQ_KOS; break; + case 1: image.format = mipmapped ? GL_COMPRESSED_RGB_565_VQ_MIPMAP_KOS : GL_COMPRESSED_RGB_565_VQ_KOS; channels = 3; break; + case 0: image.format = mipmapped ? GL_COMPRESSED_ARGB_1555_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_1555_VQ_KOS; break; + case 2: image.format = mipmapped ? GL_COMPRESSED_ARGB_4444_VQ_MIPMAP_KOS : GL_COMPRESSED_ARGB_4444_VQ_KOS; break; default: UF_EXCEPTION("Image error: invalid texture format: {}", filename); return false; } } @@ -143,57 +78,97 @@ bool uf::Image::open( const uf::stl::string& _filename, bool flip ) { stbi_set_flip_vertically_on_load(flip); uint8_t* buffer = stbi_load( filename.c_str(), &width, &height, &channelsDud, STBI_rgb_alpha ); size_t len = width * height * channels; - this->m_pixels.resize( len ); - memcpy( &this->m_pixels[0], buffer, len ); - // this->m_pixels.insert( this->m_pixels.end(), (uint8_t*) buffer, buffer + len ); + image.pixels.resize( len ); + memcpy( &image.pixels[0], buffer, len ); + // image.pixels.insert( image.pixels.end(), (uint8_t*) buffer, buffer + len ); stbi_image_free(buffer); } - this->m_dimensions.x = width; - this->m_dimensions.y = height; - this->m_bpp = bit_depth * channels; - this->m_channels = channels; + image.size.x = width; + image.size.y = height; + image.bpp = bpp * channels; + image.channels = channels; return true; } -void uf::Image::loadFromBuffer( const Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) { - this->m_dimensions = size; - this->m_bpp = bit_depth * channels; - this->m_channels = channels; +void uf::image::clear( pod::Image& image ) { + image.pixels.clear(); +#if UF_ENV_DREAMCAST + image.pixels.shrink_to_fit(); +#endif +} + +void uf::image::load( pod::Image& image, const pod::Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip ) { + image.size = size; + image.bpp = bpp * channels; + image.channels = channels; size_t len = size.x * size.y * channels; - this->m_pixels.clear(); - this->m_pixels.resize( len ); + image.pixels.clear(); + image.pixels.resize( len ); - if ( pointer ) memcpy( &this->m_pixels[0], pointer, len ); - else memset( &this->m_pixels[0], 0, len ); + if ( pointer ) memcpy( &image.pixels[0], pointer, len ); + else memset( &image.pixels[0], 0, len ); - if ( flip ) this->flip(); + if ( flip ) uf::image::flip( image ); } -void uf::Image::loadFromBuffer( const Image::container_t& container, const pod::Vector2ui& size, std::size_t bit_depth, std::size_t channels, bool flip ) { - this->m_dimensions = size; - this->m_bpp = bit_depth * channels; - this->m_channels = channels; - this->m_pixels = container; +void uf::image::load( pod::Image& image, const pod::Image::container_t& container, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip ) { + image.size = size; + image.bpp = bpp * channels; + image.channels = channels; + image.pixels = container; - if ( flip ) this->flip(); + if ( flip ) uf::image::flip( image ); } -void uf::Image::flip() { - auto w = this->m_dimensions.x; - auto h = this->m_dimensions.y; - uint8_t* pixels = &this->m_pixels[0]; - for (uint j = 0; j * 2 < h; ++j) { - uint x = j * w * this->m_bpp/8; - uint y = (h - 1 - j) * w * this->m_bpp/8; - for (uint i = w * this->m_bpp/8; i > 0; --i) { +bool uf::image::save( const pod::Image& image, const uf::stl::string& filename, bool flip ) { + if ( image.pixels.empty() ) return false; + + uint w = image.size.x; + uint h = image.size.y; + auto* pixels = &image.pixels[0]; + uf::stl::string extension = uf::io::extension(filename); + stbi_flip_vertically_on_write(flip); + if ( extension == "png" ) { + stbi_write_png(filename.c_str(), w, h, image.channels, &pixels[0], w * image.channels); + } else if ( extension == "jpg" || extension == "jpeg" ) { + stbi_write_jpg(filename.c_str(), w, h, image.channels, &pixels[0], w * image.channels); + } + return true; +} +void uf::image::save( const pod::Image& image, std::ostream& stream ) { + +} + +pod::Image::pixel_t uf::image::at( pod::Image& image, const pod::Vector2ui& at ) { + size_t i = at.x * image.channels + image.size.x * image.channels * at.y; + return { + image.pixels[i++], + image.pixels[i++], + image.pixels[i++], + image.pixels[i++], + }; +} + +uf::stl::string uf::image::hash( const pod::Image& image ) { + return uf::string::sha256( image.pixels ); +} + +void uf::image::flip( pod::Image& image ) { + auto w = image.size.x; + auto h = image.size.y; + uint8_t* pixels = &image.pixels[0]; + for ( uint j = 0; j * 2 < h; ++j ) { + uint x = j * w * image.bpp/8; + uint y = (h - 1 - j) * w * image.bpp/8; + for ( uint i = w * image.bpp/8; i > 0; --i ) { std::swap( pixels[x], pixels[y] ); ++x, ++y; } } } -void uf::Image::padToPowerOfTwo( ) { +void uf::image::padToPowerOfTwo( pod::Image& image ) { pod::Vector2ui next = { - this->m_dimensions.x, - this->m_dimensions.y + image.size.x, + image.size.y }; { next.x--; next.x |= next.x >> 1; @@ -211,244 +186,150 @@ void uf::Image::padToPowerOfTwo( ) { next.y++; } // no point in repadding - if ( this->m_dimensions.x == next.x && this->m_dimensions.y == next.y ) { + if ( image.size.x == next.x && image.size.y == next.y ) { return; } - uint len = next.x * next.y * this->m_bpp / 8; + uint len = next.x * next.y * image.bpp / 8; uint8_t* buffer = new uint8_t[len]; for ( size_t i = 0; i < len; ++i ) buffer[i] = 0; - for ( size_t y = 0; y < this->m_dimensions.y; ++y ) { - for ( size_t x = 0; x < this->m_dimensions.x; ++x ) { - size_t src = x * this->m_channels + this->m_dimensions.x * this->m_channels * y; - size_t dst = x * this->m_channels + next.x * this->m_channels * y; - for ( size_t i = 0; i < this->m_channels; ++i ) { - buffer[dst+i] = this->m_pixels[src+i]; + for ( size_t y = 0; y < image.size.y; ++y ) { + for ( size_t x = 0; x < image.size.x; ++x ) { + size_t src = x * image.channels + image.size.x * image.channels * y; + size_t dst = x * image.channels + next.x * image.channels * y; + for ( size_t i = 0; i < image.channels; ++i ) { + buffer[dst+i] = image.pixels[src+i]; } } } - this->m_dimensions.x = next.x; - this->m_dimensions.y = next.y; + image.size.x = next.x; + image.size.y = next.y; - this->m_pixels.clear(); - this->m_pixels.insert( this->m_pixels.end(), (uint8_t*) buffer, buffer + len ); + image.pixels.clear(); + image.pixels.insert( image.pixels.end(), (uint8_t*) buffer, buffer + len ); delete[] buffer; } -// from stream -void uf::Image::open( const std::istream& stream ) { - // ? -} -// move from vector of pixels -void uf::Image::move( Image::container_t&& move, const Image::vec2_t& size ) { - this->m_pixels = std::move(move); - this->m_dimensions = size; -} -// copy from vector of pixels -void uf::Image::copy( const Image::container_t& copy, const Image::vec2_t& size ) { - this->m_pixels = copy; - this->m_dimensions = size; -} -void uf::Image::copy( const uf::Image& copy ) { - this->m_pixels = copy.m_pixels; - this->m_dimensions = copy.m_dimensions; - this->m_bpp = copy.m_bpp; - this->m_channels = copy.m_channels; - this->m_filename = copy.m_filename; - this->m_format = copy.m_format; -} -// D-tor -// empties pixel container -void uf::Image::clear() { - this->m_pixels.clear(); -#if UF_ENV_DREAMCAST - this->m_pixels.shrink_to_fit(); -#endif -} -uf::Image::container_t& uf::Image::getPixels() { - return this->m_pixels; -} -const uf::Image::container_t& uf::Image::getPixels() const { - return this->m_pixels; -} -uf::Image::pixel_t::type_t* uf::Image::getPixelsPtr() { -// return (this->m_pixels.empty() ? NULL : &this->m_pixels[0]); - return ( this->m_pixels.empty() ) ? NULL : &this->m_pixels[0]; -} -const uf::Image::pixel_t::type_t* uf::Image::getPixelsPtr() const { -// return (this->m_pixels.empty() ? NULL : &this->m_pixels[0]); - return ( this->m_pixels.empty() ) ? NULL : &this->m_pixels[0]; -} -uf::Image::vec2_t& uf::Image::getDimensions() { - return this->m_dimensions; -} -const uf::Image::vec2_t& uf::Image::getDimensions() const { - return this->m_dimensions; -} -std::size_t& uf::Image::getBpp() { - return this->m_bpp; -} -std::size_t uf::Image::getBpp() const { - return this->m_bpp; -} -std::size_t& uf::Image::getChannels() { - return this->m_channels; -} -std::size_t uf::Image::getChannels() const { - return this->m_channels; -} -std::size_t uf::Image::getFormat() const { - return this->m_format; -} -uf::stl::string uf::Image::getHash() const { - return uf::string::sha256( this->m_pixels ); -} -uf::Image::pixel_t uf::Image::at( const uf::Image::vec2_t& at ) { - std::size_t i = at.x * this->m_channels + this->m_dimensions.x*this->m_channels*at.y; - return { - this->m_pixels[i++], - this->m_pixels[i++], - this->m_pixels[i++], - this->m_pixels[i++], - }; -} - -// Modifiers -// to file -bool uf::Image::save( const uf::stl::string& filename, bool flip ) const { - if ( this->m_pixels.empty() ) return false; - - uint w = this->m_dimensions.x; - uint h = this->m_dimensions.y; - auto* pixels = &this->m_pixels[0]; - uf::stl::string extension = uf::io::extension(filename); - stbi_flip_vertically_on_write(flip); - if ( extension == "png" ) { - stbi_write_png(filename.c_str(), w, h, this->m_channels, &pixels[0], w * this->m_channels); - } else if ( extension == "jpg" || extension == "jpeg" ) { - stbi_write_jpg(filename.c_str(), w, h, this->m_channels, &pixels[0], w * this->m_channels); - } - return true; -} -// to stream -void uf::Image::save( std::ostream& stream ) const { - -} -void uf::Image::convert( const uf::stl::string& from, const uf::stl::string& to ) { - uf::Image::container_t pixels = std::move(this->m_pixels); +void uf::image::convert( pod::Image& image, const uf::stl::string& from, const uf::stl::string& to ) { +/* + pod::Image::container_t pixels = std::move(image.pixels); if ( uf::string::lowercase(to) != "rgba" ) { } else { - this->m_pixels.reserve(this->m_dimensions.x * this->m_dimensions.y * 4); - for ( size_t i = 0; i < this->m_dimensions.x * this->m_dimensions.y * this->m_channels; i += this->m_channels ) { + image.pixels.reserve(image.size.x * image.size.y * 4); + for ( size_t i = 0; i < image.size.x * image.size.y * image.channels; i += image.channels ) { if ( uf::string::lowercase(from) == "r" ) { - this->m_pixels.emplace_back( pixels[i] ); - this->m_pixels.emplace_back( pixels[i] ); - this->m_pixels.emplace_back( pixels[i] ); - this->m_pixels.emplace_back( 0xFF ); + image.pixels.emplace_back( pixels[i] ); + image.pixels.emplace_back( pixels[i] ); + image.pixels.emplace_back( pixels[i] ); + image.pixels.emplace_back( 0xFF ); } else if ( uf::string::lowercase(from) == "ra" ) { - this->m_pixels.emplace_back( pixels[i+0] ); - this->m_pixels.emplace_back( pixels[i+0] ); - this->m_pixels.emplace_back( pixels[i+0] ); - this->m_pixels.emplace_back( pixels[i+1] ); + image.pixels.emplace_back( pixels[i+0] ); + image.pixels.emplace_back( pixels[i+0] ); + image.pixels.emplace_back( pixels[i+0] ); + image.pixels.emplace_back( pixels[i+1] ); } else if ( uf::string::lowercase(from) == "rgba" ) { - this->m_pixels.emplace_back( pixels[i+0] ); - this->m_pixels.emplace_back( pixels[i+1] ); - this->m_pixels.emplace_back( pixels[i+2] ); - this->m_pixels.emplace_back( 0xFF ); + image.pixels.emplace_back( pixels[i+0] ); + image.pixels.emplace_back( pixels[i+1] ); + image.pixels.emplace_back( pixels[i+2] ); + image.pixels.emplace_back( 0xFF ); } } } - if ( !this->m_pixels.empty() ) { - this->m_channels = 4; - this->m_bpp = 8 * this->m_channels; + if ( !image.pixels.empty() ) { + image.channels = 4; + image.bpp = 8 * image.channels; } else { - this->m_pixels = std::move(pixels); + image.pixels = std::move(pixels); } +*/ } -// Merges one image on top of another -uf::Image uf::Image::overlay(const Image& top, const Image::vec2_t& corner) const { - Image out(*this); - for (size_t y = 0; y < top.m_dimensions.y; ++y) { - for (size_t x = 0; x < top.m_dimensions.x; ++x) { +pod::Image uf::image::overlay( const pod::Image& image, const pod::Image& top, const pod::Vector2ui& corner ) { +/* + Image out = image; + for (size_t y = 0; y < top.size.y; ++y) { + for (size_t x = 0; x < top.size.x; ++x) { size_t dstX = corner.x + x; size_t dstY = corner.y + y; - if (dstX >= m_dimensions.x || dstY >= m_dimensions.y) continue; - size_t dstIdx = (dstY*m_dimensions.x + dstX) * m_channels; - size_t srcIdx = (y*top.m_dimensions.x + x) * top.m_channels; + if (dstX >= size.x || dstY >= size.y) continue; + size_t dstIdx = (dstY*size.x + dstX) * channels; + size_t srcIdx = (y*top.size.x + x) * top.channels; - float alpha = top.m_pixels[srcIdx+3] / 255.0f; + float alpha = top.pixels[srcIdx+3] / 255.0f; for (size_t c = 0; c < 3; ++c) { - out.m_pixels[dstIdx+c] = - static_cast( (1-alpha)*out.m_pixels[dstIdx+c] + - alpha*top.m_pixels[srcIdx+c] ); + out.pixels[dstIdx+c] = + static_cast( (1-alpha)*out.pixels[dstIdx+c] + + alpha*top.pixels[srcIdx+c] ); } - out.m_pixels[dstIdx+3] = 255; + out.pixels[dstIdx+3] = 255; } } return out; +*/ } -// Changes all pixel from one color (from), to another (to) -uf::Image uf::Image::replace(const Image::pixel_t& from, const Image::pixel_t& to ) const { +pod::Image uf::image::replace( const pod::Image& image, const pod::Image::pixel_t& from, const pod::Image::pixel_t& to ) { +/* Image out(*this); - for (size_t i = 0; i < out.m_pixels.size(); i+=out.m_channels) { - if (out.m_pixels[i] == from[0] && - out.m_pixels[i+1] == from[1] && - out.m_pixels[i+2] == from[2] && - out.m_pixels[i+3] == from[3]) { - out.m_pixels[i] = to[0]; - out.m_pixels[i+1] = to[1]; - out.m_pixels[i+2] = to[2]; - out.m_pixels[i+3] = to[3]; + for ( auto i = 0; i < out.pixels.size(); i += out.channels ) { + if (out.pixels[i] == from[0] && + out.pixels[i+1] == from[1] && + out.pixels[i+2] == from[2] && + out.pixels[i+3] == from[3]) { + out.pixels[i] = to[0]; + out.pixels[i+1] = to[1]; + out.pixels[i+2] = to[2]; + out.pixels[i+3] = to[3]; } } return out; +*/ } -// Crops an image -uf::Image uf::Image::subImage( const Image::vec2_t& start, const Image::vec2_t& end) const { - vec2_t size = { end.x - start.x, end.y - start.y }; - container_t outPixels(size.x * size.y * m_channels); +pod::Image uf::image::subImage( const pod::Image& image, const pod::Vector2ui& start, const pod::Vector2ui& end ) { +/* + pod::Vector2ui size = { end.x - start.x, end.y - start.y }; + pod::Image::container_t outPixels(size.x * size.y * channels); for (size_t y = 0; y < size.y; ++y) { for (size_t x = 0; x < size.x; ++x) { - size_t dstIdx = (y*size.x + x) * m_channels; - size_t srcIdx = ((start.y+y)*m_dimensions.x + (start.x+x)) * m_channels; - for (size_t c = 0; c < m_channels; ++c) - outPixels[dstIdx+c] = m_pixels[srcIdx+c]; + size_t dstIdx = (y*size.x + x) * channels; + size_t srcIdx = ((start.y+y)*size.x + (start.x+x)) * channels; + for (size_t c = 0; c < channels; ++c) + outPixels[dstIdx+c] = image.pixels[srcIdx+c]; } } - return Image(std::move(outPixels), size); + return pod::Image(std::move(outPixels), size); +*/ } -// Scales an image, nearest = true does nearest neighbor, nearest = false does bilinear interpolation -uf::Image uf::Image::scale( const uf::Image::vec2_t& newSize, bool nearest ) { - container_t outPixels(newSize.x * newSize.y * m_channels); - float xRatio = static_cast(m_dimensions.x) / newSize.x; - float yRatio = static_cast(m_dimensions.y) / newSize.y; +pod::Image uf::image::scale( const pod::Image& image, const pod::Vector2ui& size, bool nearest ) { +/* + pod::Image::container_t outPixels(newSize.x * newSize.y * channels); + float xRatio = static_cast(size.x) / newSize.x; + float yRatio = static_cast(size.y) / newSize.y; for (size_t j = 0; j < newSize.y; ++j) { for (size_t i = 0; i < newSize.x; ++i) { if (nearest) { size_t srcX = static_cast(i * xRatio); size_t srcY = static_cast(j * yRatio); - size_t srcIdx = (srcY*m_dimensions.x + srcX) * m_channels; - size_t dstIdx = (j*newSize.x + i) * m_channels; - for (size_t c = 0; c < m_channels; ++c) - outPixels[dstIdx+c] = m_pixels[srcIdx+c]; + size_t srcIdx = (srcY*size.x + srcX) * channels; + size_t dstIdx = (j*newSize.x + i) * channels; + for (size_t c = 0; c < channels; ++c) + outPixels[dstIdx+c] = pixels[srcIdx+c]; } else { float gx = i * xRatio; float gy = j * yRatio; size_t x0 = static_cast(gx); size_t y0 = static_cast(gy); - size_t x1 = std::min(x0+1, (size_t)m_dimensions.x-1); - size_t y1 = std::min(y0+1, (size_t)m_dimensions.y-1); + size_t x1 = std::min(x0+1, (size_t)size.x-1); + size_t y1 = std::min(y0+1, (size_t)size.y-1); float u = gx - x0; float v = gy - y0; - size_t dstIdx = (j*newSize.x + i) * m_channels; + size_t dstIdx = (j*newSize.x + i) * channels; - for (size_t c=0; c(val); } @@ -456,4 +337,193 @@ uf::Image uf::Image::scale( const uf::Image::vec2_t& newSize, bool nearest ) { } } return Image(std::move(outPixels), newSize); +*/ +} +/* +uf::Image::Image() { + size = {0,0}; + bpp = 8; + channels = 4; + format = 0; +} + +uf::Image::Image(const pod::Vector2ui& s) { + size = s; + bpp = 8; + channels = 4; + format = 0; + pixels.resize(size.x * size.y * channels); +} + +uf::Image::Image( pod::Image::container_t&& move, const pod::Vector2ui& s ) { + pixels = std::move( move ); + size = s; + bpp = 8; + channels = 4; + format = 0; +} + +uf::Image::Image( const pod::Image::container_t& copy, const pod::Vector2ui& s ) { + pixels = copy; + size = s; + bpp = 8; + channels = 4; + format = 0; +} + +uf::Image::Image( const uf::Image& copy ) { + this->copy( copy ); +} + +uf::Image::Image( uf::Image&& move ) noexcept { + //this->move( move ); + pixels = std::move( move.pixels ); + size = move.size; + bpp = move.bpp; + channels = move.channels; + format = move.format; +} + +uf::Image& uf::Image::operator=( const uf::Image& copy ) { + this->copy( copy ); + return *this; +} + +uf::Image& uf::Image::operator=( uf::Image&& move ) noexcept { + //this->move( move ); + pixels = std::move( move.pixels ); + size = move.size; + bpp = move.bpp; + channels = move.channels; + format = move.format; + return *this; +} +*/ +uf::stl::string uf::Image::getFilename() const { + return this->filename; +} +void uf::Image::setFilename( const uf::stl::string& filename ) { + this->filename = filename; +} + +// from file +bool uf::Image::open( const uf::stl::string& filename, bool flip ) { + return uf::image::open( *this, filename, flip ); +} +void uf::Image::loadFromBuffer( const pod::Image::pixel_t::type_t* pointer, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip ) { + return uf::image::load( *this, pointer, size, bpp, channels, flip ); +} +void uf::Image::loadFromBuffer( const pod::Image::container_t& container, const pod::Vector2ui& size, size_t bpp, size_t channels, bool flip ) { + return uf::image::load( *this, container, size, bpp, channels, flip ); +} +void uf::Image::flip() { + return uf::image::flip( *this ); +} +void uf::Image::padToPowerOfTwo( ) { + return uf::image::padToPowerOfTwo( *this ); +} +// from stream +void uf::Image::open( const std::istream& stream ) { + //return uf::image::open( *this, stream ); +} +// move from vector of pixels +void uf::Image::move( pod::Image::container_t&& move, const pod::Vector2ui& size ) { + this->pixels = std::move(move); + this->size = size; +} +void uf::Image::move( uf::Image&& move ) { + this->pixels = std::move(move.pixels); + this->size = move.size; + this->bpp = move.bpp; + this->channels = move.channels; + this->filename = move.filename; + this->format = move.format; +} +// copy from vector of pixels +void uf::Image::copy( const pod::Image::container_t& copy, const pod::Vector2ui& size ) { + this->pixels = copy; + this->size = size; +} +void uf::Image::copy( const uf::Image& copy ) { + this->pixels = copy.pixels; + this->size = copy.size; + this->bpp = copy.bpp; + this->channels = copy.channels; + this->filename = copy.filename; + this->format = copy.format; +} +// D-tor +// empties pixel container +void uf::Image::clear() { + uf::image::clear( *this ); +} +pod::Image::container_t& uf::Image::getPixels() { + return this->pixels; +} +const pod::Image::container_t& uf::Image::getPixels() const { + return this->pixels; +} +pod::Image::pixel_t::type_t* uf::Image::getPixelsPtr() { +// return (this->pixels.empty() ? NULL : &this->pixels[0]); + return ( this->pixels.empty() ) ? NULL : &this->pixels[0]; +} +const pod::Image::pixel_t::type_t* uf::Image::getPixelsPtr() const { +// return (this->pixels.empty() ? NULL : &this->pixels[0]); + return ( this->pixels.empty() ) ? NULL : &this->pixels[0]; +} +pod::Vector2ui& uf::Image::getDimensions() { + return this->size; +} +const pod::Vector2ui& uf::Image::getDimensions() const { + return this->size; +} +size_t& uf::Image::getBpp() { + return this->bpp; +} +size_t uf::Image::getBpp() const { + return this->bpp; +} +size_t& uf::Image::getChannels() { + return this->channels; +} +size_t uf::Image::getChannels() const { + return this->channels; +} +size_t uf::Image::getFormat() const { + return this->format; +} +uf::stl::string uf::Image::getHash() const { + return uf::image::hash( *this ); +} +pod::Image::pixel_t uf::Image::at( const pod::Vector2ui& at ) { + return uf::image::at( *this, at ); +} + +// Modifiers +// to file +bool uf::Image::save( const uf::stl::string& filename, bool flip ) const { + return uf::image::save( *this, filename, flip ); +} +// to stream +void uf::Image::save( std::ostream& stream ) const { + return uf::image::save( *this, stream ); +} +void uf::Image::convert( const uf::stl::string& from, const uf::stl::string& to ) { + return uf::image::convert( *this, from, to ); +} +// Merges one image on top of another +uf::Image uf::Image::overlay(const Image& top, const pod::Vector2ui& corner) const { + //return uf::image::overlay( *this, top, corner ); +} +// Changes all pixel from one color (from), to another (to) +uf::Image uf::Image::replace(const pod::Image::pixel_t& from, const pod::Image::pixel_t& to ) const { + //return uf::image::replace( *this, from, to ); +} +// Crops an image +uf::Image uf::Image::subImage( const pod::Vector2ui& start, const pod::Vector2ui& end) const { + //return uf::image::subImage( *this, start, end ); +} +// Scales an image, nearest = true does nearest neighbor, nearest = false does bilinear interpolation +uf::Image uf::Image::scale( const pod::Vector2ui& newSize, bool nearest ) { + //return uf::image::scale( *this, newSize, nearest ); } \ No newline at end of file diff --git a/engine/src/utils/math/physics/draw.cpp b/engine/src/utils/math/physics/draw.cpp index bb5f8008..bb0603c4 100644 --- a/engine/src/utils/math/physics/draw.cpp +++ b/engine/src/utils/math/physics/draw.cpp @@ -58,6 +58,8 @@ void impl::drawBody( const pod::PhysicsBody& body ) { auto angleThreshold = std::cos(fov * 1.5f); auto viewThresholdSq = std::pow(10, 2); + cameraTransform.position.y -= 1; + // continuously pick the closest point on the AABB auto position = impl::closestPointOnAABB( cameraTransform.position, bounds ); auto dir = position - cameraTransform.position; diff --git a/engine/src/utils/text/glyph.cpp b/engine/src/utils/text/glyph.cpp index 4e0fb2d7..e444f6d0 100644 --- a/engine/src/utils/text/glyph.cpp +++ b/engine/src/utils/text/glyph.cpp @@ -1,108 +1,54 @@ #include #include #if UF_USE_FREETYPE -uf::Glyph::~Glyph() { - delete[] this->m_buffer; + +pod::FT_Glyph uf::glyph::initialize( const uf::stl::string& font ) { + return ext::freetype::initialize( font ); +} +uint8_t* uf::glyph::generate( pod::Glyph& glyph, pod::FT_Glyph& g, uint64_t c, size_t size ) { + ext::freetype::setPixelSizes( g, size ); + if ( !ext::freetype::load( g, c ) ) return NULL; + return uf::glyph::generate( glyph, g ); } -// OpenGL ops -uint8_t* uf::Glyph::generate( const uf::stl::string& font, unsigned long c, uint size ) { - ext::freetype::Glyph glyph = ext::freetype::initialize(font); - return this->generate( glyph, c ); +uint8_t* uf::glyph::generate( pod::Glyph& glyph, pod::FT_Glyph& g, const uf::stl::string& s, size_t size ) { + ext::freetype::setPixelSizes( g, size ); + if ( !ext::freetype::load( g, s ) ) return NULL; + return uf::glyph::generate( glyph, g ); } -uint8_t* uf::Glyph::generate( ext::freetype::Glyph& glyph, unsigned long c, uint size ) { - ext::freetype::setPixelSizes( glyph, size ); - if ( !ext::freetype::load( glyph, c ) ) return NULL; - if ( this->m_buffer ) { - delete[] this->m_buffer; - } -// this->m_sdf = false; -// this->setSize( { static_cast(glyph.face->glyph->metrics.width) >> 6, static_cast(glyph.face->glyph->metrics.height) >> 6 } ); - this->setSize( { static_cast(glyph.face->glyph->bitmap.width), static_cast(glyph.face->glyph->bitmap.rows) } ); - this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } ); - this->setAdvance( {static_cast(glyph.face->glyph->advance.x) >> 6, static_cast(glyph.face->glyph->advance.y) >> 6} ); -// this->setPadding( {4, 4} ); +uint8_t* uf::glyph::generate( pod::Glyph& glyph, pod::FT_Glyph& g ) { + if ( glyph.spread ) ext::freetype::setRenderMode( g, FT_RENDER_MODE_SDF ); - uint8_t* bitmap = glyph.face->glyph->bitmap.buffer; - - pod::Vector2i padding = this->getPadding(); - if ( padding.x > 0 && padding.y > 0 ) { - uint8_t unheadache[this->m_size.x + padding.x * 2][this->m_size.y + padding.y * 2]; - this->m_buffer = new uint8_t[ ( this->m_size.x + padding.x * 2 ) * ( this->m_size.y + padding.y * 2 ) ]; + glyph.size = { g.face->glyph->bitmap.width, g.face->glyph->bitmap.rows }; + glyph.bearing = { g.face->glyph->bitmap_left, g.face->glyph->bitmap_top }; + glyph.advance = { g.face->glyph->advance.x >> 6, g.face->glyph->advance.y >> 6 }; - // Zero out - for ( uint y = 0; y < this->m_size.y + padding.y * 2; ++y ) { - for ( uint x = 0; x < this->m_size.x + padding.x * 2; ++x ) { - unheadache[x][y] = 0; - } + glyph.buffer.clear(); + + const uint8_t* buffer = g.face->glyph->bitmap.buffer; + + auto size = glyph.size + glyph.padding * 2; + glyph.buffer.assign(size.x * size.y, 0); + for ( size_t y = 0; y < glyph.size.y; ++y ) { + const uint8_t* src = buffer + y * g.face->glyph->bitmap.pitch; + for ( size_t x = 0; x < glyph.size.x; ++x ) { + size_t dst = (y + glyph.padding.y) * size.x + (x + glyph.padding.x); + glyph.buffer[dst] = src[x]; } - // Fill - for ( uint y = 0; y < this->m_size.y; ++y ) { - for ( uint x = 0; x < this->m_size.x; ++x ) { - unheadache[x + padding.x][y + padding.y] = bitmap[y * this->m_size.x + x]; - } - } - // Migrate - this->setSize( pod::Vector2ui{ this->m_size.x + padding.x * 2, this->m_size.y + padding.y * 2 } ); - for ( uint y = 0; y < this->m_size.y; ++y ) { - for ( uint x = 0; x < this->m_size.x; ++x ) { - this->m_buffer[y * this->m_size.x + x] = unheadache[x][y]; - } - } - } else { - std::size_t len = this->m_size.x * this->m_size.y; - this->m_buffer = new uint8_t[len]; - memcpy(this->m_buffer, bitmap, len); } - if ( this->isSdf() ) this->generateSdf(this->m_buffer); - return this->m_buffer; + glyph.size = size; + + return glyph.buffer.data(); } -uint8_t* uf::Glyph::generate( const uf::stl::string& font, const uf::stl::string& c, uint size ) { - ext::freetype::Glyph glyph = ext::freetype::initialize(font); - return this->generate( glyph, c ); -} -uint8_t* uf::Glyph::generate( ext::freetype::Glyph& glyph, const uf::stl::string& c, uint size ) { - ext::freetype::setPixelSizes( glyph, size ); - if ( !ext::freetype::load( glyph, c ) ) return NULL; - if ( this->m_buffer ) { - delete[] this->m_buffer; - } - this->setSize( { static_cast(glyph.face->glyph->bitmap.width), static_cast(glyph.face->glyph->bitmap.rows) } ); - this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } ); - this->setAdvance( {static_cast(glyph.face->glyph->advance.x) >> 6, static_cast(glyph.face->glyph->advance.y) >> 6} ); +void uf::glyph::generateSdf( pod::Glyph& glyph ) { + auto* buffer = glyph.buffer.data(); + auto size = glyph.size; - if ( this->isSdf() ) { - ext::freetype::setRenderMode( glyph, FT_RENDER_MODE_NORMAL ); - ext::freetype::setRenderMode( glyph, FT_RENDER_MODE_SDF ); - } - - uint8_t* bitmap = glyph.face->glyph->bitmap.buffer; - std::size_t len = this->m_size.x * this->m_size.y; - this->m_buffer = new uint8_t[len]; - memcpy(this->m_buffer, bitmap, len); - -/* - uint8_t* bitmap = glyph.face->glyph->bitmap.buffer; - std::size_t len = this->m_size.x * this->m_size.y; - this->m_buffer = new uint8_t[len]; - memcpy(this->m_buffer, bitmap, len); - - if ( this->isSdf() ) this->generateSdf(this->m_buffer); -*/ - - return this->m_buffer; -} -bool uf::Glyph::generated() { - return this->m_buffer != NULL; -} -void uf::Glyph::generateSdf( uint8_t* buffer ) { if ( !buffer ) return; - pod::Vector2ui size = this->getSize(); - this->m_sdf = true; - - int HEIGHT = size.y; int WIDTH = size.x; + int HEIGHT = size.y; + int WIDTH = size.x; struct Point { int dx, dy; int DistSq() const { return dx*dx + dy*dy; } @@ -110,17 +56,12 @@ void uf::Glyph::generateSdf( uint8_t* buffer ) { if ( !buffer ) return; struct Grid { int w, h; Point grid[128][128]; - /* - Point** grid; - Grid( int w, int h ) { this->w = w; this->h = h; this->grid = new Point*[h]; for (int y = 0; y < h; ++y ) this->grid[y] = new Point[w]; } - ~Grid() { std::cout << this->grid << std::endl; for ( int y = 0; y < this->w; ++y ) if ( this->grid[y] ) delete[] this->grid[y]; if ( this->grid ) delete[] this->grid; } - */ }; Point inside = { 0, 0 }; Point empty = { 9999, 9999 }; - Grid grid1; //( WIDTH, HEIGHT ); - Grid grid2; //( WIDTH, HEIGHT ); + Grid grid1; + Grid grid2; auto Get = [&]( Grid &g, int x, int y )->Point{ return ( x >= 0 && y >= 0 && x < WIDTH && y < HEIGHT ) ? g.grid[y][x] : empty; @@ -170,9 +111,9 @@ void uf::Glyph::generateSdf( uint8_t* buffer ) { if ( !buffer ) return; }; - for ( int y = 0; y < this->m_size.y; ++y ) { - for ( int x = 0; x < this->m_size.x; ++x ) { - int a = buffer[y * this->m_size.x + x]; + for ( int y = 0; y < HEIGHT; ++y ) { + for ( int x = 0; x < WIDTH; ++x ) { + int a = buffer[y * WIDTH + x]; Put( grid1, x, y, a < 128 ? inside : empty ); Put( grid2, x, y, a < 128 ? empty : inside ); } @@ -183,8 +124,8 @@ void uf::Glyph::generateSdf( uint8_t* buffer ) { if ( !buffer ) return; int lowest = 255; int highest = 0; - for ( uint y = 0; y < this->m_size.y; ++y ) { - for ( uint x = 0; x < this->m_size.x; ++x ) { + for ( uint y = 0; y < HEIGHT; ++y ) { + for ( uint x = 0; x < WIDTH; ++x ) { int dist1 = (int)( sqrt( (double)Get( grid1, x, y ).DistSq() ) ); int dist2 = (int)( sqrt( (double)Get( grid2, x, y ).DistSq() ) ); int dist = dist1 - dist2; @@ -193,61 +134,11 @@ void uf::Glyph::generateSdf( uint8_t* buffer ) { if ( !buffer ) return; highest = std::max( highest, dist ); { - int value = dist * this->getSpread() + 128; + int value = dist * glyph.spread + 128; uint8_t uvalue = std::max( 0, std::min(255, value) ); - buffer[y * this->m_size.x + x] = uvalue; + buffer[y * WIDTH + x] = uvalue; } - - /* - { - float value = 0.5f + 0.5f * ((float) dist / (float) this->getSpread()); - value = std::max( 0.0f, std::min(1.0f, value) ); - uint8_t uvalue = value * 256; - buffer[y * this->m_size.x + x] = uvalue; - } - */ } } } -// Get -const pod::Vector2ui& uf::Glyph::getSize() const { - return this->m_size; -} -const pod::Vector2i& uf::Glyph::getBearing() const { - return this->m_bearing; -} -const pod::Vector2i& uf::Glyph::getAdvance() const { - return this->m_advance; -} -const pod::Vector2i& uf::Glyph::getPadding() const { - return this->m_padding; -} -const uint8_t* uf::Glyph::getBuffer() const { - return this->m_buffer; -} -int uf::Glyph::getSpread() const { - return this->m_spread; -} -bool uf::Glyph::isSdf() const { - return this->m_sdf; -} -// Set -void uf::Glyph::setSize( const pod::Vector2ui& size ) { - this->m_size = size; -} -void uf::Glyph::setBearing( const pod::Vector2i& bearing ) { - this->m_bearing = bearing; -} -void uf::Glyph::setAdvance( const pod::Vector2i& advance ) { - this->m_advance = advance; -} -void uf::Glyph::setPadding( const pod::Vector2i& padding ) { - this->m_padding = padding; -} -void uf::Glyph::setSpread( int spread ) { - this->m_spread = spread; -} -void uf::Glyph::useSdf( bool b ) { - this->m_sdf = b; -} #endif \ No newline at end of file diff --git a/engine/src/utils/text/glyph_.cpp b/engine/src/utils/text/graphic.cpp similarity index 79% rename from engine/src/utils/text/glyph_.cpp rename to engine/src/utils/text/graphic.cpp index a68ed376..58afea41 100644 --- a/engine/src/utils/text/glyph_.cpp +++ b/engine/src/utils/text/graphic.cpp @@ -1,5 +1,5 @@ #include -#include +#include #if UF_USE_OPENGL #define EXT_COLOR_FLOATS 0 @@ -28,7 +28,9 @@ namespace { pod::Vector4b color; #endif + #if !UF_USE_OPENGL pod::Vector3f offset; + #endif static uf::stl::vector descriptor; }; @@ -48,8 +50,8 @@ UF_VERTEX_DESCRIPTOR(GlyphVertex, namespace { struct { #if UF_USE_FREETYPE - ext::freetype::Glyph glyph; - uf::stl::unordered_map> cache; + pod::FT_Glyph face; + uf::stl::unordered_map> cache; #else char glyph; uf::stl::unordered_map> cache; @@ -84,12 +86,12 @@ namespace { size_t uf::glyph::hashSettings( uint64_t c, const pod::GlyphSettings& metadata ) { size_t seed{}; - uf::hash( seed, c, metadata.padding[0], metadata.padding[1], metadata.spread, metadata.size, metadata.font, metadata.sdf ); + uf::hash( seed, c, metadata.padding[0], metadata.padding[1], metadata.spread, metadata.size, metadata.font ); return seed; } size_t uf::glyph::hashSettings( const uf::stl::string& c, const pod::GlyphSettings& metadata ) { size_t seed{}; - uf::hash( seed, c, metadata.padding[0], metadata.padding[1], metadata.spread, metadata.size, metadata.font, metadata.sdf ); + uf::hash( seed, c, metadata.padding[0], metadata.padding[1], metadata.spread, metadata.size, metadata.font ); return seed; } @@ -149,10 +151,10 @@ uf::stl::vector uf::glyph::parseTextTokens( const uf::stl::strin // compute the boxes for a given string and settings uf::stl::vector uf::glyph::calculateLayout( const uf::stl::vector& tokens, const pod::GlyphSettings& metadata ) { uf::stl::vector layout; - auto& glyphsCache = ::glyphs.cache[metadata.font]; + auto& cache = ::glyphs.cache[metadata.font]; - if ( glyphsCache.empty() ) { - ext::freetype::initialize( ::glyphs.glyph, uf::io::root + "/fonts/" + metadata.font ); + if ( cache.empty() ) { + ext::freetype::initialize( ::glyphs.face, uf::io::root + "/fonts/" + metadata.font ); } pod::Vector2f anchor = ::parseAnchor( metadata.alignment ); @@ -171,18 +173,18 @@ uf::stl::vector uf::glyph::calculateLayout( const uf::stl::vector if ( c == '\n' || c == '\t' ) continue; // special characters auto key = uf::glyph::hashSettings(c, metadata); - auto& glyph = glyphsCache[key]; + auto& glyph = cache[key]; // generate glyph - if ( !glyph.generated() ) { - glyph.setPadding({ metadata.padding[0], metadata.padding[1] }); - glyph.setSpread(metadata.spread); - glyph.useSdf(metadata.sdf); - glyph.generate(::glyphs.glyph, c, metadata.size); + if ( glyph.buffer.empty() ) { + glyph.padding = { metadata.padding[0], metadata.padding[1] }; + glyph.spread = metadata.spread; + + uf::glyph::generate( glyph, ::glyphs.face, c, metadata.size ); } - tallestGlyphY = std::max(tallestGlyphY, (float) glyph.getSize().y); - totalWidth += glyph.getSize().x; // should probably be reset on new-line to find the widest line + tallestGlyphY = std::max(tallestGlyphY, (float) glyph.size.y); + totalWidth += glyph.size.x; // should probably be reset on new-line to find the widest line charCount++; } } @@ -209,13 +211,13 @@ uf::stl::vector uf::glyph::calculateLayout( const uf::stl::vector // retrieve glyph auto key = uf::glyph::hashSettings(c, metadata); - auto& glyph = glyphsCache[key]; + auto& glyph = cache[key]; auto& g = layout.emplace_back(pod::GlyphBox{ .box = { - .x = cursor.x + glyph.getBearing().x, - .y = cursor.y - glyph.getBearing().y, - .w = glyph.getSize().x, - .h = glyph.getSize().y, + .x = cursor.x + glyph.bearing.x, + .y = cursor.y - glyph.bearing.y, + .w = glyph.size.x, + .h = glyph.size.y, .z = 0, }, .color = token.color, @@ -224,7 +226,7 @@ uf::stl::vector uf::glyph::calculateLayout( const uf::stl::vector }); // advance cursor - cursor.x += glyph.getAdvance().x; + cursor.x += glyph.advance.x; // advance bounding box maxTextWidth = std::max(maxTextWidth, g.box.x + g.box.w); @@ -268,13 +270,12 @@ bool uf::glyph::generateAtlas( const uf::stl::vector& layout, con dirty = true; uf::Image image; - const uint8_t* buffer = glyph.getBuffer(); - - if ( metadata.sdf ) { - image.loadFromBuffer( glyph.getBuffer(), glyph.getSize(), 8, 1, true ); + if ( metadata.spread > 0 ) { + image.loadFromBuffer( glyph.buffer.data(), glyph.size, 8, 1 ); } else { - uf::Image::container_t pixels; - size_t len = glyph.getSize().x * glyph.getSize().y; + const uint8_t* buffer = glyph.buffer.data(); + pod::Image::container_t pixels; + size_t len = glyph.size.x * glyph.size.y; pixels.resize(len * 4); for ( auto i = 0; i < len; ++i ) { pixels[i * 4 + 0] = buffer[i]; // R @@ -282,11 +283,10 @@ bool uf::glyph::generateAtlas( const uf::stl::vector& layout, con pixels[i * 4 + 2] = buffer[i]; // B pixels[i * 4 + 3] = buffer[i]; // A } - image.loadFromBuffer( &pixels[0], glyph.getSize(), 8, 4, true ); + image.loadFromBuffer( &pixels[0], glyph.size, 8, 4 ); } atlas.addImage( image, hash ); } - atlas.generate(); #endif return dirty; @@ -324,10 +324,17 @@ void uf::glyph::generateMesh( const uf::stl::vector& layout, cons auto p2 = pod::Vector2f{ g.box.x + g.box.w, g.box.y }; auto p3 = pod::Vector2f{ g.box.x + g.box.w, g.box.y + g.box.h }; - vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color, p0}); - vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color, p1}); - vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color, p2}); - vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color, p3}); + #if UF_USE_OPENGL + vertices.emplace_back(::GlyphVertex{g.anchor + p0, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color}); + vertices.emplace_back(::GlyphVertex{g.anchor + p1, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color}); + vertices.emplace_back(::GlyphVertex{g.anchor + p2, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color}); + vertices.emplace_back(::GlyphVertex{g.anchor + p3, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color}); + #else + vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 1.0f }, hash), color, p0}); + vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 0.0f, 0.0f }, hash), color, p1}); + vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 0.0f }, hash), color, p2}); + vertices.emplace_back(::GlyphVertex{g.anchor, atlas.mapUv(pod::Vector2f{ 1.0f, 1.0f }, hash), color, p3}); + #endif } mesh.insertVertices(vertices);