lots of old code cleanup (camera, image, glyph, atlas, etc.), reintroduced un-staged buffers (to test if this solved the immediate mode jitter but it was the camera)
This commit is contained in:
parent
a6875adf13
commit
f8da959ffd
@ -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,
|
||||
|
||||
@ -12,35 +12,28 @@
|
||||
|
||||
#include <uf/utils/string/string.h>
|
||||
|
||||
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& );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<Buffer> 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 );
|
||||
|
||||
@ -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();
|
||||
};
|
||||
}
|
||||
@ -3,31 +3,49 @@
|
||||
#include <uf/utils/image/image.h>
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
|
||||
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<uf::Image> images_t;
|
||||
typedef uf::stl::vector<pod::Image> images_t;
|
||||
typedef uf::stl::unordered_map<hash_t, Tile> 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<pod::Image>& 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<uf::Image>&, float padding = 1);
|
||||
void generate( const uf::stl::vector<pod::Image>&, 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<hash_t, uf::Image> images_t;
|
||||
typedef uf::stl::unordered_map<hash_t, pod::Image> images_t;
|
||||
|
||||
struct Identifier {
|
||||
hash_t hash;
|
||||
@ -54,23 +72,23 @@ namespace uf {
|
||||
typedef Identifier identifier_t;
|
||||
typedef BinPack2D::CanvasArray<identifier_t> 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;
|
||||
};
|
||||
|
||||
@ -4,27 +4,56 @@
|
||||
#include <uf/utils/math/vector.h>
|
||||
#include <uf/utils/memory/vector.h>
|
||||
|
||||
#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<pixel_t::type_t> 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 );
|
||||
};
|
||||
}
|
||||
@ -1,124 +0,0 @@
|
||||
#pragma once
|
||||
#if 0
|
||||
#include <uf/config.h>
|
||||
|
||||
namespace pod {
|
||||
// Simple Pixels (designed [to store in arrays] with minimal headaches)
|
||||
template<typename T = pod::Math::num_t, std::size_t N = 4>
|
||||
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<T,N> operator-() const; // Negation
|
||||
inline Pixel<T,N> operator*( const Pixel<T,N>& Pixel ) const; // Multiplication between two Pixels
|
||||
inline Pixel<T,N> operator/( const Pixel<T,N>& Pixel ) const; // Divison between two Pixels
|
||||
inline Pixel<T,N> operator*( T scalar ) const; // Multiplication with scalar
|
||||
inline Pixel<T,N> operator/( T scalar ) const; // Divison with scalar
|
||||
inline Pixel<T,N>& operator *=( const Pixel<T,N>& Pixel ); // Multiplication set between two Pixels
|
||||
inline Pixel<T,N>& operator /=( const Pixel<T,N>& Pixel ); // Divison set between two Pixels
|
||||
inline Pixel<T,N>& operator *=( T scalar ); // Multiplication set with scalar
|
||||
inline Pixel<T,N>& operator /=( T scalar ); // Divison set with scalar
|
||||
inline bool operator==( const Pixel<T,N>& Pixel ) const; // Equality check between two Pixels (equals)
|
||||
inline bool operator!=( const Pixel<T,N>& Pixel ) const; // Equality check between two Pixels (not equals)
|
||||
};
|
||||
template<typename T>
|
||||
struct /*UF_API*/ Pixel<T,3> {
|
||||
// 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<T,3> operator-() const; // Negation
|
||||
inline Pixel<T,3> operator*( const Pixel<T,3>& Pixel ) const; // Multiplication between two Pixels
|
||||
inline Pixel<T,3> operator/( const Pixel<T,3>& Pixel ) const; // Divison between two Pixels
|
||||
inline Pixel<T,3> operator*( T scalar ) const; // Multiplication with scalar
|
||||
inline Pixel<T,3> operator/( T scalar ) const; // Divison with scalar
|
||||
inline Pixel<T,3>& operator *=( const Pixel<T,3>& Pixel ); // Multiplication set between two Pixels
|
||||
inline Pixel<T,3>& operator /=( const Pixel<T,3>& Pixel ); // Divison set between two Pixels
|
||||
inline Pixel<T,3>& operator *=( T scalar ); // Multiplication set with scalar
|
||||
inline Pixel<T,3>& operator /=( T scalar ); // Divison set with scalar
|
||||
inline bool operator==( const Pixel<T,3>& Pixel ) const; // Equality check between two Pixels (equals)
|
||||
inline bool operator!=( const Pixel<T,3>& Pixel ) const; // Equality check between two Pixels (not equals)
|
||||
};
|
||||
template<typename T>
|
||||
struct /*UF_API*/ Pixel<T,4> {
|
||||
// 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<T,4> operator-() const; // Negation
|
||||
inline Pixel<T,4> operator*( const Pixel<T,4>& Pixel ) const; // Multiplication between two Pixels
|
||||
inline Pixel<T,4> operator/( const Pixel<T,4>& Pixel ) const; // Divison between two Pixels
|
||||
inline Pixel<T,4> operator*( T scalar ) const; // Multiplication with scalar
|
||||
inline Pixel<T,4> operator/( T scalar ) const; // Divison with scalar
|
||||
inline Pixel<T,4>& operator *=( const Pixel<T,4>& Pixel ); // Multiplication set between two Pixels
|
||||
inline Pixel<T,4>& operator /=( const Pixel<T,4>& Pixel ); // Divison set between two Pixels
|
||||
inline Pixel<T,4>& operator *=( T scalar ); // Multiplication set with scalar
|
||||
inline Pixel<T,4>& operator /=( T scalar ); // Divison set with scalar
|
||||
inline bool operator==( const Pixel<T,4>& Pixel ) const; // Equality check between two Pixels (equals)
|
||||
inline bool operator!=( const Pixel<T,4>& Pixel ) const; // Equality check between two Pixels (not equals)
|
||||
};
|
||||
|
||||
template<typename T = pod::Math::num_t> using Pixel3t = Pixel<T,3>;
|
||||
typedef Pixel<float> Pixel3f;
|
||||
typedef Pixel<double> Pixel3d;
|
||||
typedef Pixel<uint8_t> PixelRgb8;
|
||||
|
||||
template<typename T = pod::Math::num_t> using Pixel4t = Pixel<T,4>;
|
||||
typedef Pixel<float> Pixel4f;
|
||||
typedef Pixel<double> Pixel4d;
|
||||
typedef Pixel<uint8_t> PixelRgba8;
|
||||
}
|
||||
|
||||
// POD pixel accessing/manipulation
|
||||
namespace uf {
|
||||
namespace pixel {
|
||||
// Equality checking
|
||||
template<typename T> std::size_t /*UF_API*/ compareTo( const T& left, const T& right ); // Equality check between two pixels (less than)
|
||||
template<typename T> bool /*UF_API*/ equals( const T& left, const T& right ); // Equality check between two pixels (equals)
|
||||
// Basic arithmetic
|
||||
template<typename T> T /*UF_API*/ multiply( const T& left, const T& right ); // Multiplies two pixels of same type and size together
|
||||
template<typename T> T /*UF_API*/ multiply( const T& pixel, const typename T::type_t& scalar ); // Multiplies this pixel by a scalar
|
||||
template<typename T> T /*UF_API*/ divide( const T& left, const T& right ); // Divides two pixels of same type and size together
|
||||
template<typename T> T /*UF_API*/ divide( const T& left, const typename T::type_t& scalar ); // Divides this pixel by a scalar
|
||||
template<typename T> T /*UF_API*/ negate( const T& pixel ); // Flip sign of all components
|
||||
// Writes to first value
|
||||
template<typename T> T& /*UF_API*/ multiply( T& left, const T& right ); // Multiplies two pixels of same type and size together
|
||||
template<typename T> T& /*UF_API*/ multiply( T& pixel, const typename T::type_t& scalar ); // Multiplies this pixel by a scalar
|
||||
template<typename T> T& /*UF_API*/ divide( T& left, const T& right ); // Divides two pixels of same type and size together
|
||||
template<typename T> T& /*UF_API*/ divide( T& left, const typename T::type_t& scalar ); // Divides this pixel by a scalar
|
||||
template<typename T> T& /*UF_API*/ negate( T& pixel ); // Flip sign of all components
|
||||
}
|
||||
}
|
||||
#include "pixel.inl"
|
||||
#endif
|
||||
@ -1,128 +0,0 @@
|
||||
#include <uf/config.h>
|
||||
#include <cstring> // memcmp
|
||||
|
||||
// Equality checking
|
||||
template<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T> // 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<typename T, std::size_t N>
|
||||
T& pod::Pixel<T,N>::operator[](std::size_t i) {
|
||||
return this->components[i];
|
||||
}
|
||||
template<typename T, std::size_t N>
|
||||
const T& pod::Pixel<T,N>::operator[](std::size_t i) const {
|
||||
return this->components[i];
|
||||
}
|
||||
// Arithmetic
|
||||
template<typename T, std::size_t N> // Negation
|
||||
inline pod::Pixel<T,N> pod::Pixel<T,N>::operator-() const {
|
||||
return uf::pixel::negate( *this );
|
||||
}
|
||||
template<typename T, std::size_t N> // Multiplication between two pixels
|
||||
inline pod::Pixel<T,N> pod::Pixel<T,N>::operator*( const pod::Pixel<T,N>& pixel ) const {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T, std::size_t N> // Division between two pixels
|
||||
inline pod::Pixel<T,N> pod::Pixel<T,N>::operator/( const pod::Pixel<T,N>& pixel ) const {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T, std::size_t N> // Multiplication with scalar
|
||||
inline pod::Pixel<T,N> pod::Pixel<T,N>::operator*( T scalar ) const {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T, std::size_t N> // Division with scalar
|
||||
inline pod::Pixel<T,N> pod::Pixel<T,N>::operator/( T scalar ) const {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T, std::size_t N> // Multiplication set between two pixels
|
||||
inline pod::Pixel<T,N>& pod::Pixel<T,N>::operator *=( const pod::Pixel<T,N>& pixel ) {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T, std::size_t N> // Division set between two pixels
|
||||
inline pod::Pixel<T,N>& pod::Pixel<T,N>::operator /=( const pod::Pixel<T,N>& pixel ) {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T, std::size_t N> // Multiplication set with scalar
|
||||
inline pod::Pixel<T,N>& pod::Pixel<T,N>::operator *=( T scalar ) {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T, std::size_t N> // Division set with scalar
|
||||
inline pod::Pixel<T,N>& pod::Pixel<T,N>::operator /=( T scalar ) {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T, std::size_t N> // Equality check between two pixels (equals)
|
||||
inline bool pod::Pixel<T,N>::operator==( const pod::Pixel<T,N>& pixel ) const {
|
||||
return uf::pixel::equals(pixel);
|
||||
}
|
||||
template<typename T, std::size_t N> // Equality check between two pixels (not equals)
|
||||
inline bool pod::Pixel<T,N>::operator!=( const pod::Pixel<T,N>& pixel ) const {
|
||||
return !uf::pixel::equals(pixel);
|
||||
}
|
||||
#include "redundancy.inl"
|
||||
@ -1,109 +0,0 @@
|
||||
//
|
||||
template<typename T>
|
||||
T& pod::Pixel<T,3>::operator[](std::size_t i) {
|
||||
return this->components[i];
|
||||
}
|
||||
template<typename T>
|
||||
const T& pod::Pixel<T,3>::operator[](std::size_t i) const {
|
||||
return this->components[i];
|
||||
}
|
||||
// Arithmetic
|
||||
template<typename T> // Negation
|
||||
inline pod::Pixel<T,3> pod::Pixel<T,3>::operator-() const {
|
||||
return uf::pixel::negate( *this );
|
||||
}
|
||||
template<typename T> // Multiplication between two pixels
|
||||
inline pod::Pixel<T,3> pod::Pixel<T,3>::operator*( const pod::Pixel<T,3>& pixel ) const {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T> // Division between two pixels
|
||||
inline pod::Pixel<T,3> pod::Pixel<T,3>::operator/( const pod::Pixel<T,3>& pixel ) const {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T> // Multiplication with scalar
|
||||
inline pod::Pixel<T,3> pod::Pixel<T,3>::operator*( T scalar ) const {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T> // Division with scalar
|
||||
inline pod::Pixel<T,3> pod::Pixel<T,3>::operator/( T scalar ) const {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T> // Multiplication set between two pixels
|
||||
inline pod::Pixel<T,3>& pod::Pixel<T,3>::operator *=( const pod::Pixel<T,3>& pixel ) {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T> // Division set between two pixels
|
||||
inline pod::Pixel<T,3>& pod::Pixel<T,3>::operator /=( const pod::Pixel<T,3>& pixel ) {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T> // Multiplication set with scalar
|
||||
inline pod::Pixel<T,3>& pod::Pixel<T,3>::operator *=( T scalar ) {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T> // Division set with scalar
|
||||
inline pod::Pixel<T,3>& pod::Pixel<T,3>::operator /=( T scalar ) {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T> // Equality check between two pixels (equals)
|
||||
inline bool pod::Pixel<T,3>::operator==( const pod::Pixel<T,3>& pixel ) const {
|
||||
return uf::pixel::equals(pixel);
|
||||
}
|
||||
template<typename T> // Equality check between two pixels (not equals)
|
||||
inline bool pod::Pixel<T,3>::operator!=( const pod::Pixel<T,3>& pixel ) const {
|
||||
return !uf::pixel::equals(pixel);
|
||||
}
|
||||
|
||||
//
|
||||
template<typename T>
|
||||
T& pod::Pixel<T,4>::operator[](std::size_t i) {
|
||||
return this->components[i];
|
||||
}
|
||||
template<typename T>
|
||||
const T& pod::Pixel<T,4>::operator[](std::size_t i) const {
|
||||
return this->components[i];
|
||||
}
|
||||
// Arithmetic
|
||||
template<typename T> // Negation
|
||||
inline pod::Pixel<T,4> pod::Pixel<T,4>::operator-() const {
|
||||
return uf::pixel::negate( *this );
|
||||
}
|
||||
template<typename T> // Multiplication between two pixels
|
||||
inline pod::Pixel<T,4> pod::Pixel<T,4>::operator*( const pod::Pixel<T,4>& pixel ) const {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T> // Division between two pixels
|
||||
inline pod::Pixel<T,4> pod::Pixel<T,4>::operator/( const pod::Pixel<T,4>& pixel ) const {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T> // Multiplication with scalar
|
||||
inline pod::Pixel<T,4> pod::Pixel<T,4>::operator*( T scalar ) const {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T> // Division with scalar
|
||||
inline pod::Pixel<T,4> pod::Pixel<T,4>::operator/( T scalar ) const {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T> // Multiplication set between two pixels
|
||||
inline pod::Pixel<T,4>& pod::Pixel<T,4>::operator *=( const pod::Pixel<T,4>& pixel ) {
|
||||
return uf::pixel::multiply( *this, pixel );
|
||||
}
|
||||
template<typename T> // Division set between two pixels
|
||||
inline pod::Pixel<T,4>& pod::Pixel<T,4>::operator /=( const pod::Pixel<T,4>& pixel ) {
|
||||
return uf::pixel::divide( *this, pixel );
|
||||
}
|
||||
template<typename T> // Multiplication set with scalar
|
||||
inline pod::Pixel<T,4>& pod::Pixel<T,4>::operator *=( T scalar ) {
|
||||
return uf::pixel::multiply( *this, scalar );
|
||||
}
|
||||
template<typename T> // Division set with scalar
|
||||
inline pod::Pixel<T,4>& pod::Pixel<T,4>::operator /=( T scalar ) {
|
||||
return uf::pixel::divide( *this, scalar );
|
||||
}
|
||||
template<typename T> // Equality check between two pixels (equals)
|
||||
inline bool pod::Pixel<T,4>::operator==( const pod::Pixel<T,4>& pixel ) const {
|
||||
return uf::pixel::equals(pixel);
|
||||
}
|
||||
template<typename T> // Equality check between two pixels (not equals)
|
||||
inline bool pod::Pixel<T,4>::operator!=( const pod::Pixel<T,4>& pixel ) const {
|
||||
return !uf::pixel::equals(pixel);
|
||||
}
|
||||
@ -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)
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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<typename T> T& uf::MemoryPool::alloc( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( m_pod, data/*, alignment*/ ); }
|
||||
template<typename T> pod::Allocation uf::MemoryPool::allocate( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::allocate( m_pod, data/*, alignment*/ ); }
|
||||
template<typename T> bool uf::MemoryPool::exists( const T& data ) { return uf::memoryPool::exists( m_pod, data ); }
|
||||
template<typename T> bool uf::MemoryPool::free( const T& data ) { return uf::memoryPool::free( m_pod, data ); }
|
||||
template<typename T> T& uf::MemoryPool::alloc( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::alloc( *this, data/*, alignment*/ ); }
|
||||
template<typename T> pod::Allocation uf::MemoryPool::allocate( const T& data/*, size_t alignment*/ ) { return uf::memoryPool::allocate( *this, data/*, alignment*/ ); }
|
||||
template<typename T> bool uf::MemoryPool::exists( const T& data ) { return uf::memoryPool::exists( *this, data ); }
|
||||
template<typename T> bool uf::MemoryPool::free( const T& data ) { return uf::memoryPool::free( *this, data ); }
|
||||
@ -198,11 +198,12 @@ namespace uf {
|
||||
|
||||
uf::stl::unordered_map<uf::stl::string, uf::Mesh::AttributeView> 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
|
||||
|
||||
@ -6,46 +6,31 @@
|
||||
|
||||
#include <uf/utils/math/vector.h>
|
||||
#include <uf/ext/freetype/freetype.h>
|
||||
#include <uf/utils/memory/vector.h>
|
||||
#include <uf/utils/image/atlas.h>
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
|
||||
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<uint8_t> 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
|
||||
@ -5,7 +5,6 @@
|
||||
#include <uf/utils/image/atlas.h>
|
||||
#include <uf/utils/mesh/mesh.h>
|
||||
|
||||
|
||||
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 };
|
||||
};
|
||||
}
|
||||
@ -38,6 +38,7 @@
|
||||
|
||||
#include <uf/ext/ext.h>
|
||||
#include <uf/ext/openal/openal.h>
|
||||
#include <uf/ext/freetype/freetype.h>
|
||||
#include <uf/ext/discord/discord.h>
|
||||
#include <uf/ext/openvr/openvr.h>
|
||||
#include <uf/ext/lua/lua.h>
|
||||
@ -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();
|
||||
|
||||
@ -37,7 +37,10 @@ namespace {
|
||||
#else
|
||||
pod::Vector4b color;
|
||||
#endif
|
||||
|
||||
#if !UF_USE_OPENGL
|
||||
pod::Vector2f offset;
|
||||
#endif
|
||||
|
||||
static uf::stl::vector<uf::renderer::AttributeDescriptor> 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<uint16_t>({
|
||||
0, 1, 2, 3, 4, 5
|
||||
@ -553,26 +566,21 @@ void ext::GuiBehavior::tick( uf::Object& self ) {
|
||||
pod::Vector2f min = { std::numeric_limits<float>::max(), std::numeric_limits<float>::max() };
|
||||
pod::Vector2f max = { -std::numeric_limits<float>::max(), -std::numeric_limits<float>::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<uint8_t*>(positionAttribute.pointer) + i * positionAttribute.stride );
|
||||
float* o = (float*) (static_cast<uint8_t*>(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<float>( 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;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
#include <uf/utils/string/ext.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/text/glyph.h>
|
||||
#include <uf/utils/text/glyph_.h>
|
||||
#include <uf/utils/text/graphic.h>
|
||||
#include <uf/engine/asset/asset.h>
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/utils/memory/unordered_map.h>
|
||||
@ -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,
|
||||
});
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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<uf::Image> images(filenames.size());
|
||||
|
||||
pod::Vector2ui size = {0,0};
|
||||
|
||||
@ -82,8 +82,8 @@ uf::Camera& uf::Scene::getCamera( uf::Entity& controller ) {
|
||||
|
||||
if ( lastFrame != uf::time::frame ) {
|
||||
auto& sourceCamera = controller.getComponent<uf::Camera>();
|
||||
// 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);
|
||||
|
||||
@ -2,13 +2,34 @@
|
||||
#if UF_USE_FREETYPE
|
||||
#include <uf/ext/freetype/freetype.h>
|
||||
|
||||
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<const unsigned char*>(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<const uint8_t*>(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<uf::locale::Utf32>().at(0);
|
||||
uint64_t c = string.translate<uf::locale::Utf32>().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
|
||||
@ -40,8 +40,8 @@ namespace binds {
|
||||
self.setProjection(matrix);
|
||||
}
|
||||
}
|
||||
void update( uf::Camera& self, sol::optional<bool> force ) {
|
||||
self.update(force.value_or(true));
|
||||
void update( uf::Camera& self ) {
|
||||
self.update();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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<ext::vulkan::Buffer*>(this);
|
||||
void* map = self->map(length);
|
||||
for ( const auto& region : regions ) memcpy(static_cast<char*>(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;
|
||||
}
|
||||
|
||||
@ -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 ) {
|
||||
|
||||
@ -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 );
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
#include <uf/engine/scene/scene.h>
|
||||
#include <uf/engine/graph/graph.h>
|
||||
#include <uf/utils/math/physics.h>
|
||||
#include <uf/utils/text/glyph_.h>
|
||||
#include <uf/utils/text/graphic.h>
|
||||
|
||||
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;
|
||||
|
||||
@ -3,38 +3,32 @@
|
||||
#include <iostream>
|
||||
#include <bit>
|
||||
|
||||
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<Identifier> internalAtlas;
|
||||
BinPack2D::ContentAccumulator<uf::Atlas::Identifier> 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<pod::Atlas::hash_t> internalAtlas;
|
||||
BinPack2D::ContentAccumulator<pod::Atlas::hash_t> 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<uf::Atlas::Identifier>(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<pod::Atlas::hash_t>(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<uf::Atlas::Identifier>(size.x, size.y, 1).Build();
|
||||
internalAtlas = BinPack2D::UniformCanvasArrayBuilder<pod::Atlas::hash_t>(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<pod::Image>& 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;
|
||||
}
|
||||
@ -13,73 +13,8 @@
|
||||
#include <uf/utils/renderer/renderer.h>
|
||||
#include <uf/utils/string/ext.h>
|
||||
|
||||
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<uint8_t>( (1-alpha)*out.m_pixels[dstIdx+c] +
|
||||
alpha*top.m_pixels[srcIdx+c] );
|
||||
out.pixels[dstIdx+c] =
|
||||
static_cast<uint8_t>( (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<float>(m_dimensions.x) / newSize.x;
|
||||
float yRatio = static_cast<float>(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<float>(size.x) / newSize.x;
|
||||
float yRatio = static_cast<float>(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<size_t>(i * xRatio);
|
||||
size_t srcY = static_cast<size_t>(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<size_t>(gx);
|
||||
size_t y0 = static_cast<size_t>(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<m_channels; ++c) {
|
||||
auto p00 = m_pixels[(y0*m_dimensions.x + x0)*m_channels + c];
|
||||
auto p10 = m_pixels[(y0*m_dimensions.x + x1)*m_channels + c];
|
||||
auto p01 = m_pixels[(y1*m_dimensions.x + x0)*m_channels + c];
|
||||
auto p11 = m_pixels[(y1*m_dimensions.x + x1)*m_channels + c];
|
||||
for (size_t c=0; c<channels; ++c) {
|
||||
auto p00 = pixels[(y0*size.x + x0)*channels + c];
|
||||
auto p10 = pixels[(y0*size.x + x1)*channels + c];
|
||||
auto p01 = pixels[(y1*size.x + x0)*channels + c];
|
||||
auto p11 = pixels[(y1*size.x + x1)*channels + c];
|
||||
float val = (1-u)*(1-v)*p00 + u*(1-v)*p10 + (1-u)*v*p01 + u*v*p11;
|
||||
outPixels[dstIdx+c] = static_cast<uint8_t>(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 );
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -1,108 +1,54 @@
|
||||
#include <uf/utils/text/glyph.h>
|
||||
#include <iostream>
|
||||
#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<int>(glyph.face->glyph->metrics.width) >> 6, static_cast<int>(glyph.face->glyph->metrics.height) >> 6 } );
|
||||
this->setSize( { static_cast<int>(glyph.face->glyph->bitmap.width), static_cast<int>(glyph.face->glyph->bitmap.rows) } );
|
||||
this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } );
|
||||
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x) >> 6, static_cast<int>(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<int>(glyph.face->glyph->bitmap.width), static_cast<int>(glyph.face->glyph->bitmap.rows) } );
|
||||
this->setBearing( { glyph.face->glyph->bitmap_left, glyph.face->glyph->bitmap_top } );
|
||||
this->setAdvance( {static_cast<int>(glyph.face->glyph->advance.x) >> 6, static_cast<int>(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
|
||||
@ -1,5 +1,5 @@
|
||||
#include <uf/utils/text/glyph.h>
|
||||
#include <uf/utils/text/glyph_.h>
|
||||
#include <uf/utils/text/graphic.h>
|
||||
|
||||
#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<uf::renderer::AttributeDescriptor> descriptor;
|
||||
};
|
||||
@ -48,8 +50,8 @@ UF_VERTEX_DESCRIPTOR(GlyphVertex,
|
||||
namespace {
|
||||
struct {
|
||||
#if UF_USE_FREETYPE
|
||||
ext::freetype::Glyph glyph;
|
||||
uf::stl::unordered_map<uf::stl::string, uf::stl::unordered_map<size_t, uf::Glyph>> cache;
|
||||
pod::FT_Glyph face;
|
||||
uf::stl::unordered_map<uf::stl::string, uf::stl::unordered_map<size_t, pod::Glyph>> cache;
|
||||
#else
|
||||
char glyph;
|
||||
uf::stl::unordered_map<uf::stl::string, uf::stl::unordered_map<size_t, char>> 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<pod::TextToken> uf::glyph::parseTextTokens( const uf::stl::strin
|
||||
// compute the boxes for a given string and settings
|
||||
uf::stl::vector<pod::GlyphBox> uf::glyph::calculateLayout( const uf::stl::vector<pod::TextToken>& tokens, const pod::GlyphSettings& metadata ) {
|
||||
uf::stl::vector<pod::GlyphBox> 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<pod::GlyphBox> 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<pod::GlyphBox> 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<pod::GlyphBox> 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<pod::GlyphBox>& 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<pod::GlyphBox>& 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<pod::GlyphBox>& 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);
|
||||
Loading…
Reference in New Issue
Block a user