// SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin // SPDX-License-Identifier: CC-BY-NC-ND-4.0 #pragma once #include "common/align.h" #include "common/heap_array.h" #include "common/types.h" #include #include #include #include class Error; enum class ImageFormat : u8 { None, RGBA8, BGRA8, RGB565, RGBA5551, BGR8, BC1, BC2, BC3, BC7, MaxCount, }; class Image { public: static constexpr u8 DEFAULT_SAVE_QUALITY = 85; public: using PixelStorage = Common::unique_aligned_ptr; Image(); Image(u32 width, u32 height, ImageFormat format); Image(u32 width, u32 height, ImageFormat format, const void* pixels, u32 pitch); Image(u32 width, u32 height, ImageFormat format, PixelStorage pixels, u32 pitch); Image(const Image& copy); Image(Image&& move); Image& operator=(const Image& copy); Image& operator=(Image&& move); static const char* GetFormatName(ImageFormat format); static u32 GetPixelSize(ImageFormat format); static bool IsCompressedFormat(ImageFormat format); static u32 CalculatePitch(u32 width, u32 height, ImageFormat format); static u32 CalculateStorageSize(u32 width, u32 height, ImageFormat format); static u32 CalculateStorageSize(u32 width, u32 height, u32 pitch, ImageFormat format); ALWAYS_INLINE bool IsValid() const { return (m_width > 0 && m_height > 0); } ALWAYS_INLINE u32 GetWidth() const { return m_width; } ALWAYS_INLINE u32 GetHeight() const { return m_height; } ALWAYS_INLINE u32 GetPitch() const { return m_pitch; } ALWAYS_INLINE ImageFormat GetFormat() const { return m_format; } ALWAYS_INLINE const u8* GetPixels() const { return m_pixels.get(); } ALWAYS_INLINE u8* GetPixels() { return m_pixels.get(); } ALWAYS_INLINE const u8* GetRowPixels(u32 y) const { return &m_pixels[y * m_pitch]; } ALWAYS_INLINE u8* GetRowPixels(u32 y) { return &m_pixels[y * m_pitch]; } // ALWAYS_INLINE void SetPixel(u32 x, u32 y, PixelType pixel) { m_pixels[y * m_width + x] = pixel; } // ALWAYS_INLINE PixelType GetPixel(u32 x, u32 y) const { return m_pixels[y * m_width + x]; } u32 GetBlockXCount() const; u32 GetBlockYCount() const; u32 GetStorageSize() const; std::span GetPixelsSpan() const; std::span GetPixelsSpan(); void Clear(); void Invalidate(); void Resize(u32 new_width, u32 new_height, bool preserve); void Resize(u32 new_width, u32 new_height, ImageFormat format, bool preserve); void SetPixels(u32 width, u32 height, ImageFormat format, const void* pixels, u32 pitch); void SetPixels(u32 width, u32 height, ImageFormat format, PixelStorage pixels, u32 pitch); bool SetAllPixelsOpaque(); PixelStorage TakePixels(); bool LoadFromFile(const char* filename, Error* error = nullptr); bool LoadFromFile(std::string_view filename, std::FILE* fp, Error* error = nullptr); bool LoadFromBuffer(std::string_view filename, std::span data, Error* error = nullptr); bool RasterizeSVG(const std::span data, u32 width, u32 height, Error* error = nullptr); bool SaveToFile(const char* filename, u8 quality = DEFAULT_SAVE_QUALITY, Error* error = nullptr) const; bool SaveToFile(std::string_view filename, std::FILE* fp, u8 quality = DEFAULT_SAVE_QUALITY, Error* error = nullptr) const; std::optional> SaveToBuffer(std::string_view filename, u8 quality = DEFAULT_SAVE_QUALITY, Error* error = nullptr) const; std::optional ConvertToRGBA8(Error* error) const; void FlipY(); protected: u32 m_width = 0; u32 m_height = 0; u32 m_pitch = 0; ImageFormat m_format = ImageFormat::None; PixelStorage m_pixels; };