Skip to content

Commit

Permalink
[io] added tz::io library. added image loading API to read image files.
Browse files Browse the repository at this point in the history
  • Loading branch information
harrand committed Oct 21, 2024
1 parent 2382df3 commit a869b90
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 2 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,11 @@ topaz_add_library(
src/tz/core/trs.cpp
src/tz/gpu/rhi_vulkan.cpp
src/tz/os/impl_win32.cpp
src/tz/io/image.cpp
)

target_include_directories(topaz PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_link_libraries(topaz PRIVATE VulkanMemoryAllocator concurrentqueue)
target_link_libraries(topaz PRIVATE VulkanMemoryAllocator concurrentqueue stb_image)
target_link_libraries(topaz PUBLIC textc_lib)

######################
Expand Down
52 changes: 52 additions & 0 deletions include/tz/io/image.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#ifndef TOPAZ_IO_IMAGE_HPP
#define TOPAZ_IO_IMAGE_HPP
#include "tz/core/error.hpp"
#include <cstddef>
#include <span>
#include <expected>

namespace tz::io
{
/**
* @ingroup tz_io
* @brief Describes basic information about an image.
*
* Note that all images loaded are 4-component RGBA with 1 byte ber component.
*/
struct image_header
{
/// Width of the image, in pixels.
unsigned int width = 0u;
/// Height of the image, in pixels.
unsigned int height = 0u;
/// Size of the total image data, in bytes.
std::size_t data_size_bytes = 0u;
};

/**
* @ingroup tz_io
* @brief Retrieve info about an image loaded in memory
* @param img_file_data Data read directly from an image file. See below for the list of supported image file formats.
* @return A @ref image_header containing basic information about the image, or some @ref tz::error_code if the image data could not be parsed.
*
* The image file formats guaranteed are:
* - jpg
* - png
* - bmp
*
* Other file formats that aren't listed here might still work, but you should consider anything not on this list an implementation detail that could lose support suddenly in a new release.
*/
std::expected<image_header, tz::error_code> image_info(std::span<const std::byte> img_file_data);
/**
* @ingroup tz_io
* @brief Load an image from file data resident in memory.
* @param img_file_data Data read directly from an image file. See the detailsof @ref image_info for a list of supported image file formats.
* @param buffer A buffer of memory into which decoded image data will be written. It is your responsibility to provide a buffer that is of sufficient size. To decipher the size needed, see @ref image_info.
* @return @ref tz::error_code::success If the image data was successfully decoded.
* @return @ref tz::error_code::oom If the buffer you provided was not of sufficient size.
* @return @ref tz::error_code::unknown_error If image decoding failed for some other reason.
*/
tz::error_code parse_image(std::span<const std::byte> img_file_data, std::span<std::byte> buffer);
}

#endif // TOPAZ_IO_IMAGE_HPP
9 changes: 9 additions & 0 deletions include/tz/topaz.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,15 @@ namespace tz
* This library contains some pre-created high-level rendering systems used for common tasks, such as rendering 3D models, or user interface. These components are intended to be used in most Topaz games, with the goal of not needing to reinvent the wheel in every single game using the @ref tz_ren.
**/

/**
* @ingroup tz
* @defgroup tz_io IO Library
* @brief High-level library for wrangling files of various formats.
*
* This library contains support for a handful of common file formats, allowing you to import them without having to implement a parser yourself.
**/


#include "detail/debug.hpp"

#endif // TOPAZ_HPP
5 changes: 4 additions & 1 deletion lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
add_subdirectory(concurrentqueue)
add_subdirectory(VulkanMemoryAllocator)
add_subdirectory(textc)
add_subdirectory(textc)

add_library(stb_image INTERFACE)
target_include_directories(stb_image INTERFACE stb)
42 changes: 42 additions & 0 deletions src/tz/io/image.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#include "tz/io/image.hpp"
#include "tz/topaz.hpp"
#define STBI_FAILURE_USERMSG
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

namespace tz::io
{
std::expected<image_header, tz::error_code> image_info(std::span<const std::byte> img_file_data)
{
int w, h, channels;
int ok = stbi_info_from_memory(reinterpret_cast<const stbi_uc*>(img_file_data.data()), img_file_data.size_bytes(), &w, &h, &channels);
if(ok != 1)
{
UNERR(tz::error_code::precondition_failure, "bad image file data: {}", stbi_failure_reason());
}

return image_header
{
.width = static_cast<unsigned int>(w),
.height = static_cast<unsigned int>(h),
.data_size_bytes = w * h * 4u * 1u
};
}

tz::error_code parse_image(std::span<const std::byte> img_file_data, std::span<std::byte> buffer)
{
int w, h, channels;
stbi_uc* imgdata = stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(img_file_data.data()), img_file_data.size_bytes(), &w, &h, &channels, 4);
std::size_t real_image_size = w * h * 4u * 1u;
if(buffer.size_bytes() < real_image_size)
{
RETERR(tz::error_code::oom, "buffer provided to parse_image was too small ({} bytes), it needs to be at least {} bytes", buffer.size_bytes(), real_image_size);
}
if(imgdata == nullptr)
{
RETERR(tz::error_code::unknown_error, "unknown error occurred during image parsing: {}", stbi_failure_reason());
}
std::memcpy(buffer.data(), imgdata, real_image_size);
return tz::error_code::success;
}
}

0 comments on commit a869b90

Please sign in to comment.