From 7d88bba764d4d1e16e2b32ae470076ecf3afe44c Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 1 Jul 2020 00:34:22 +1000 Subject: [PATCH] Common: Add an image helper class --- src/common/CMakeLists.txt | 4 +- src/common/common.vcxproj | 18 +++--- src/common/common.vcxproj.filters | 2 + src/common/image.cpp | 39 ++++++++++++ src/common/image.h | 98 +++++++++++++++++++++++++++++++ 5 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 src/common/image.cpp create mode 100644 src/common/image.h diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 218ac4541..513525b6b 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -28,6 +28,8 @@ add_library(common fifo_queue.h file_system.cpp file_system.h + image.cpp + image.h gl/context.cpp gl/context.h gl/program.cpp @@ -91,7 +93,7 @@ add_library(common target_include_directories(common PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(common PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") -target_link_libraries(common PRIVATE glad libcue Threads::Threads cubeb libchdr glslang vulkan-loader) +target_link_libraries(common PRIVATE glad libcue stb Threads::Threads cubeb libchdr glslang vulkan-loader) if(WIN32) target_sources(common PRIVATE diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index de0c5284b..771a21083 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -62,6 +62,7 @@ + @@ -114,6 +115,7 @@ + @@ -300,7 +302,7 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true stdcpp17 true @@ -326,7 +328,7 @@ _ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default false true @@ -355,7 +357,7 @@ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true stdcpp17 true @@ -381,7 +383,7 @@ _ITERATOR_DEBUG_LEVEL=1;WIN32;_DEBUGFAST;_DEBUG;_LIB;%(PreprocessorDefinitions) true ProgramDatabase - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) Default false true @@ -411,7 +413,7 @@ true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true stdcpp17 false @@ -441,7 +443,7 @@ true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17 @@ -471,7 +473,7 @@ true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true stdcpp17 false @@ -501,7 +503,7 @@ true WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) true - $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) + $(SolutionDir)dep\glad\include;$(SolutionDir)dep\cubeb\include;$(SolutionDir)dep\libcue\include;$(SolutionDir)dep\libchdr\include;$(SolutionDir)dep\stb\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\glslang;$(SolutionDir)src;%(AdditionalIncludeDirectories) true true stdcpp17 diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index a98013549..442f5ff09 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -98,6 +98,7 @@ vulkan + @@ -188,6 +189,7 @@ vulkan + diff --git a/src/common/image.cpp b/src/common/image.cpp new file mode 100644 index 000000000..b80e10dd5 --- /dev/null +++ b/src/common/image.cpp @@ -0,0 +1,39 @@ +#include "image.h" +#include "log.h" +#include "stb_image.h" +Log_SetChannel(Common::Image); + +namespace Common { +bool LoadImageFromFile(Common::RGBA8Image* image, const char* filename) +{ + int width, height, file_channels; + u8* pixel_data = stbi_load(filename, &width, &height, &file_channels, 4); + if (!pixel_data) + { + const char* error_reason = stbi_failure_reason(); + Log_ErrorPrintf("Failed to load image from '%s': %s", filename, error_reason ? error_reason : "unknown error"); + return false; + } + + image->SetPixels(static_cast(width), static_cast(height), reinterpret_cast(pixel_data)); + stbi_image_free(pixel_data); + return true; +} + +bool LoadImageFromBuffer(Common::RGBA8Image* image, const void* buffer, std::size_t buffer_size) +{ + int width, height, file_channels; + u8* pixel_data = stbi_load_from_memory(static_cast(buffer), static_cast(buffer_size), &width, + &height, &file_channels, 4); + if (!pixel_data) + { + const char* error_reason = stbi_failure_reason(); + Log_ErrorPrintf("Failed to load image from memory: %s", error_reason ? error_reason : "unknown error"); + return false; + } + + image->SetPixels(static_cast(width), static_cast(height), reinterpret_cast(pixel_data)); + stbi_image_free(pixel_data); + return true; +} +} // namespace Common \ No newline at end of file diff --git a/src/common/image.h b/src/common/image.h new file mode 100644 index 000000000..6054aa0f7 --- /dev/null +++ b/src/common/image.h @@ -0,0 +1,98 @@ +#pragma once +#include "assert.h" +#include "types.h" +#include +#include +#include +#include + +namespace Common { +template +class Image +{ +public: + Image() = default; + Image(u32 width, u32 height, const PixelType* pixels) { SetPixels(width, height, pixels); } + Image(const Image& copy) + { + m_width = copy.m_width; + m_height = copy.m_height; + m_pixels = copy.m_pixels; + } + Image(Image&& move) + { + m_width = move.m_width; + m_height = move.m_height; + m_pixels = std::move(move.m_width); + move.m_width = 0; + move.m_height = 0; + } + + Image& operator=(const Image& copy) + { + m_width = copy.m_width; + m_height = copy.m_height; + m_pixels = copy.m_pixels; + return *this; + } + Image& operator=(Image&& move) + { + m_width = move.m_width; + m_height = move.m_height; + m_pixels = std::move(move.m_width); + move.m_width = 0; + move.m_height = 0; + return *this; + } + + 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 GetByteStride() const { return (sizeof(PixelType) * m_width); } + ALWAYS_INLINE const PixelType* GetPixels() const { return m_pixels.data(); } + ALWAYS_INLINE PixelType* GetPixels() { return m_pixels.data(); } + ALWAYS_INLINE const PixelType* GetRowPixels(u32 y) const { return &m_pixels[y * m_width]; } + ALWAYS_INLINE PixelType* GetRowPixels(u32 y) { return &m_pixels[y * m_width]; } + 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]; } + + void Clear(PixelType fill_value = static_cast(0)) + { + std::fill(m_pixels.begin(), m_pixels.end(), fill_value); + } + + void Invalidate() + { + m_width = 0; + m_height = 0; + m_pixels.clear(); + } + + void SetSize(u32 new_width, u32 new_height, PixelType fill_value = static_cast(0)) + { + m_width = new_width; + m_height = new_height; + m_pixels.resize(new_width * new_height); + Clear(fill_value); + } + + void SetPixels(u32 width, u32 height, const PixelType* pixels) + { + m_width = width; + m_height = height; + m_pixels.resize(width * height); + std::memcpy(m_pixels.data(), pixels, width * height * sizeof(PixelType)); + } + +private: + u32 m_width = 0; + u32 m_height = 0; + std::vector m_pixels; +}; + +using RGBA8Image = Image; + +bool LoadImageFromFile(Common::RGBA8Image* image, const char* filename); +bool LoadImageFromBuffer(Common::RGBA8Image* image, const void* buffer, std::size_t buffer_size); + +} // namespace Common \ No newline at end of file