mirror of
https://github.com/enduro2d/enduro2d.git
synced 2025-12-14 16:09:06 +07:00
Merge pull request #85 from enduro2d/hotfix/fix_image_noexcepts
Hotfix/fix image loading noexcept issues
This commit is contained in:
@@ -147,26 +147,16 @@ namespace e2d
|
||||
switch ( format_ ) {
|
||||
case image_data_format::g8:
|
||||
E2D_ASSERT(bytes_per_pixel == 1);
|
||||
return color32(pixel[0],
|
||||
pixel[0],
|
||||
pixel[0]);
|
||||
return color32(pixel[0], pixel[0], pixel[0]);
|
||||
case image_data_format::ga8:
|
||||
E2D_ASSERT(bytes_per_pixel == 2);
|
||||
return color32(pixel[0],
|
||||
pixel[0],
|
||||
pixel[0],
|
||||
pixel[1]);
|
||||
return color32(pixel[0], pixel[0], pixel[0], pixel[1]);
|
||||
case image_data_format::rgb8:
|
||||
E2D_ASSERT(bytes_per_pixel == 3);
|
||||
return color32(pixel[0],
|
||||
pixel[1],
|
||||
pixel[2]);
|
||||
return color32(pixel[0], pixel[1], pixel[2]);
|
||||
case image_data_format::rgba8:
|
||||
E2D_ASSERT(bytes_per_pixel == 4);
|
||||
return color32(pixel[0],
|
||||
pixel[1],
|
||||
pixel[2],
|
||||
pixel[3]);
|
||||
return color32(pixel[0], pixel[1], pixel[2], pixel[3]);
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected image data format");
|
||||
throw bad_image_access();
|
||||
@@ -213,9 +203,13 @@ namespace e2d::images
|
||||
image& dst,
|
||||
const buffer& src) noexcept
|
||||
{
|
||||
return impl::try_load_image_dds(dst, src)
|
||||
|| impl::try_load_image_pvr(dst, src)
|
||||
|| impl::try_load_image_stb(dst, src);
|
||||
try {
|
||||
return impl::load_image_dds(dst, src)
|
||||
|| impl::load_image_pvr(dst, src)
|
||||
|| impl::load_image_stb(dst, src);
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool try_load_image(
|
||||
@@ -232,20 +226,24 @@ namespace e2d::images
|
||||
image_file_format format,
|
||||
buffer& dst) noexcept
|
||||
{
|
||||
switch ( format ) {
|
||||
case image_file_format::dds:
|
||||
return impl::try_save_image_dds(src, dst);
|
||||
case image_file_format::jpg:
|
||||
return impl::try_save_image_jpg(src, dst);
|
||||
case image_file_format::png:
|
||||
return impl::try_save_image_png(src, dst);
|
||||
case image_file_format::pvr:
|
||||
return impl::try_save_image_pvr(src, dst);
|
||||
case image_file_format::tga:
|
||||
return impl::try_save_image_tga(src, dst);
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected image file format");
|
||||
return false;
|
||||
try {
|
||||
switch ( format ) {
|
||||
case image_file_format::dds:
|
||||
return impl::save_image_dds(src, dst);
|
||||
case image_file_format::jpg:
|
||||
return impl::save_image_jpg(src, dst);
|
||||
case image_file_format::png:
|
||||
return impl::save_image_png(src, dst);
|
||||
case image_file_format::pvr:
|
||||
return impl::save_image_pvr(src, dst);
|
||||
case image_file_format::tga:
|
||||
return impl::save_image_tga(src, dst);
|
||||
default:
|
||||
E2D_ASSERT_MSG(false, "unexpected image file format");
|
||||
return false;
|
||||
}
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_load_image_dds(image& dst, const buffer& src) noexcept;
|
||||
bool try_load_image_pvr(image& dst, const buffer& src) noexcept;
|
||||
bool try_load_image_stb(image& dst, const buffer& src) noexcept;
|
||||
bool load_image_dds(image& dst, const buffer& src);
|
||||
bool load_image_pvr(image& dst, const buffer& src);
|
||||
bool load_image_stb(image& dst, const buffer& src);
|
||||
|
||||
bool try_save_image_dds(const image& src, buffer& dst) noexcept;
|
||||
bool try_save_image_jpg(const image& src, buffer& dst) noexcept;
|
||||
bool try_save_image_png(const image& src, buffer& dst) noexcept;
|
||||
bool try_save_image_pvr(const image& src, buffer& dst) noexcept;
|
||||
bool try_save_image_tga(const image& src, buffer& dst) noexcept;
|
||||
bool save_image_dds(const image& src, buffer& dst);
|
||||
bool save_image_jpg(const image& src, buffer& dst);
|
||||
bool save_image_png(const image& src, buffer& dst);
|
||||
bool save_image_pvr(const image& src, buffer& dst);
|
||||
bool save_image_tga(const image& src, buffer& dst);
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@ namespace
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_load_image_dds(image& dst, const buffer& src) noexcept {
|
||||
bool load_image_dds(image& dst, const buffer& src) {
|
||||
if ( !is_dds(src.data(), src.size()) ) {
|
||||
return false;
|
||||
}
|
||||
@@ -139,6 +139,7 @@ namespace e2d::images::impl
|
||||
|
||||
const v2u dimension = v2u(hdr.dwWidth, hdr.dwHeight);
|
||||
std::size_t size;
|
||||
|
||||
switch ( format ) {
|
||||
case image_data_format::rgb_dxt1:
|
||||
case image_data_format::rgba_dxt3:
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace
|
||||
|
||||
static_assert(sizeof(pvr_header) == 52, "invalid PVR header size");
|
||||
|
||||
bool is_pvr(const void* data, std::size_t byte_size) {
|
||||
bool is_pvr(const void* data, std::size_t byte_size) noexcept {
|
||||
if ( byte_size > sizeof(pvr_header) ) {
|
||||
const pvr_header* hdr = reinterpret_cast<const pvr_header*>(data);
|
||||
return hdr->version == 0x03525650;
|
||||
@@ -116,11 +116,17 @@ namespace
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_pvr_format(const pvr_header& hdr, image_data_format& out_format, u32& out_bytes_per_block, v2u& out_block_size) {
|
||||
bool get_pvr_format(
|
||||
const pvr_header& hdr,
|
||||
image_data_format& out_format,
|
||||
u32& out_bytes_per_block,
|
||||
v2u& out_block_size) noexcept
|
||||
{
|
||||
if ( pvr_color_space(hdr.colorSpace) != pvr_color_space::linear ) {
|
||||
return false;
|
||||
}
|
||||
const pvr_pixel_format fmt = pvr_pixel_format(hdr.pixelFormat0 | (u64(hdr.pixelFormat1) << 32));
|
||||
const pvr_pixel_format fmt = pvr_pixel_format(
|
||||
hdr.pixelFormat0 | (u64(hdr.pixelFormat1) << 32));
|
||||
switch (fmt)
|
||||
{
|
||||
case pvr_pixel_format::pvrtc_2bpp_rgb:
|
||||
@@ -197,25 +203,30 @@ namespace
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_load_image_pvr(image& dst, const buffer& src) noexcept {
|
||||
bool load_image_pvr(image& dst, const buffer& src) {
|
||||
if ( !is_pvr(src.data(), src.size()) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const pvr_header& hdr = *reinterpret_cast<const pvr_header*>(src.data());
|
||||
const u8* content = src.data() + sizeof(pvr_header) + hdr.metaDataSize;
|
||||
|
||||
if ( hdr.numSurfaces != 1 || hdr.numFaces != 1 || hdr.depth > 1 ) {
|
||||
return false; // cubemap and volume textures are not supported
|
||||
}
|
||||
|
||||
image_data_format format = image_data_format(-1);
|
||||
u32 bytes_per_block = 0;
|
||||
v2u block_size = v2u(1,1);
|
||||
if ( !get_pvr_format(hdr, format, bytes_per_block, block_size) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
v2u dimension = v2u(hdr.width, hdr.height);
|
||||
std::size_t size = bytes_per_block *
|
||||
(dimension.x + block_size.x - 1) / block_size.x *
|
||||
(dimension.y + block_size.y - 1) / block_size.y;
|
||||
|
||||
dst = image(dimension, format, buffer(content, size));
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -57,33 +57,22 @@ namespace
|
||||
return image_data_format::rgba8;
|
||||
}
|
||||
}
|
||||
|
||||
bool image_from_stb_description(
|
||||
image& dst, const stbi_img_uptr& img, const v2u& img_size, u32 img_channels) noexcept
|
||||
{
|
||||
try {
|
||||
const image_data_format img_format = image_format_from_stb_channels(img_channels);
|
||||
if ( img && img_size.x > 0 && img_size.y > 0 ) {
|
||||
buffer img_buffer(
|
||||
img.get(),
|
||||
math::numeric_cast<std::size_t>(img_size.x * img_size.y * img_channels));
|
||||
dst.assign(img_size, img_format, std::move(img_buffer));
|
||||
return true;
|
||||
}
|
||||
} catch (...) {
|
||||
// nothing
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_load_image_stb(image& dst, const buffer& src) noexcept {
|
||||
bool load_image_stb(image& dst, const buffer& src) {
|
||||
v2u img_size;
|
||||
u32 img_channels = 0;
|
||||
const stbi_img_uptr img_ptr = load_stb_image(src, img_size, img_channels);
|
||||
return img_ptr
|
||||
&& image_from_stb_description(dst, img_ptr, img_size, img_channels);
|
||||
if ( !img_ptr || !img_size.x || !img_size.y ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const image_data_format img_format = image_format_from_stb_channels(img_channels);
|
||||
const std::size_t img_buffer_size = img_size.x * img_size.y * img_channels;
|
||||
|
||||
dst = image(img_size, img_format, buffer(img_ptr.get(), img_buffer_size));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_save_image_dds(const image& src, buffer& dst) noexcept {
|
||||
bool save_image_dds(const image& src, buffer& dst) {
|
||||
E2D_UNUSED(src, dst);
|
||||
if ( is_save_image_dds_supported(src.format()) ) {
|
||||
//TODO(BlackMat): implme
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_save_image_pvr(const image& src, buffer& dst) noexcept {
|
||||
bool save_image_pvr(const image& src, buffer& dst) {
|
||||
E2D_UNUSED(src, dst);
|
||||
if ( is_save_image_pvr_supported(src.format()) ) {
|
||||
//TODO(BlackMat): implme
|
||||
|
||||
@@ -21,6 +21,27 @@ namespace
|
||||
{
|
||||
using namespace e2d;
|
||||
|
||||
struct stb_write_context {
|
||||
vector<u8> data;
|
||||
std::exception_ptr exception{nullptr};
|
||||
};
|
||||
|
||||
void stb_write_callback(void *context, void *data, int size) {
|
||||
E2D_ASSERT(context && data && size > 0);
|
||||
stb_write_context& ctx = *static_cast<stb_write_context*>(context);
|
||||
if ( ctx.exception ) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ctx.data.insert(
|
||||
ctx.data.cend(),
|
||||
reinterpret_cast<u8*>(data),
|
||||
reinterpret_cast<u8*>(data) + math::numeric_cast<std::size_t>(size));
|
||||
} catch (...) {
|
||||
ctx.exception = std::current_exception();
|
||||
}
|
||||
}
|
||||
|
||||
int stb_channels_from_image_format(image_data_format format) noexcept {
|
||||
switch ( format ) {
|
||||
case image_data_format::g8: return 1;
|
||||
@@ -30,70 +51,85 @@ namespace
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void stb_write_callback(void *context, void *data, int size) {
|
||||
E2D_ASSERT(context && data && size > 0);
|
||||
vector<u8>& ctx = *static_cast<vector<u8>*>(context);
|
||||
ctx.insert(
|
||||
ctx.cend(),
|
||||
reinterpret_cast<u8*>(data),
|
||||
reinterpret_cast<u8*>(data) + math::numeric_cast<std::size_t>(size));
|
||||
}
|
||||
}
|
||||
|
||||
namespace e2d::images::impl
|
||||
{
|
||||
bool try_save_image_jpg(const image& src, buffer& dst) noexcept {
|
||||
bool save_image_jpg(const image& src, buffer& dst) {
|
||||
int img_w = math::numeric_cast<int>(src.size().x);
|
||||
int img_h = math::numeric_cast<int>(src.size().y);
|
||||
int img_c = stb_channels_from_image_format(src.format());
|
||||
try {
|
||||
vector<u8> data;
|
||||
if ( 0 != stbi_write_jpg_to_func(
|
||||
stb_write_callback, &data, img_w, img_h, img_c, src.data().data(), 80) )
|
||||
{
|
||||
dst.assign(data.data(), data.size());
|
||||
return true;
|
||||
}
|
||||
} catch (...) {
|
||||
// nothing
|
||||
const auto write_ctx = std::make_unique<stb_write_context>();
|
||||
|
||||
if ( !stbi_write_jpg_to_func(
|
||||
stb_write_callback,
|
||||
write_ctx.get(),
|
||||
img_w,
|
||||
img_h,
|
||||
img_c,
|
||||
src.data().data(),
|
||||
80) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
if ( write_ctx->exception ) {
|
||||
std::rethrow_exception(write_ctx->exception);
|
||||
}
|
||||
|
||||
dst.assign(write_ctx->data.data(), write_ctx->data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_save_image_png(const image& src, buffer& dst) noexcept {
|
||||
bool save_image_png(const image& src, buffer& dst) {
|
||||
int img_w = math::numeric_cast<int>(src.size().x);
|
||||
int img_h = math::numeric_cast<int>(src.size().y);
|
||||
int img_c = stb_channels_from_image_format(src.format());
|
||||
try {
|
||||
vector<u8> data;
|
||||
if ( 0 != stbi_write_png_to_func(
|
||||
stb_write_callback, &data, img_w, img_h, img_c, src.data().data(), img_w * img_c) )
|
||||
{
|
||||
dst.assign(data.data(), data.size());
|
||||
return true;
|
||||
}
|
||||
} catch (...) {
|
||||
// nothing
|
||||
const auto write_ctx = std::make_unique<stb_write_context>();
|
||||
|
||||
if ( !stbi_write_png_to_func(
|
||||
stb_write_callback,
|
||||
write_ctx.get(),
|
||||
img_w,
|
||||
img_h,
|
||||
img_c,
|
||||
src.data().data(),
|
||||
img_w * img_c) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
if ( write_ctx->exception ) {
|
||||
std::rethrow_exception(write_ctx->exception);
|
||||
}
|
||||
|
||||
dst.assign(write_ctx->data.data(), write_ctx->data.size());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool try_save_image_tga(const image& src, buffer& dst) noexcept {
|
||||
bool save_image_tga(const image& src, buffer& dst) {
|
||||
int img_w = math::numeric_cast<int>(src.size().x);
|
||||
int img_h = math::numeric_cast<int>(src.size().y);
|
||||
int img_c = stb_channels_from_image_format(src.format());
|
||||
try {
|
||||
vector<u8> data;
|
||||
if ( 0 != stbi_write_tga_to_func(
|
||||
stb_write_callback, &data, img_w, img_h, img_c, src.data().data()) )
|
||||
{
|
||||
dst.assign(data.data(), data.size());
|
||||
return true;
|
||||
}
|
||||
} catch (...) {
|
||||
// nothing
|
||||
const auto write_ctx = std::make_unique<stb_write_context>();
|
||||
|
||||
vector<u8> data;
|
||||
if ( !stbi_write_tga_to_func(
|
||||
stb_write_callback,
|
||||
write_ctx.get(),
|
||||
img_w,
|
||||
img_h,
|
||||
img_c,
|
||||
src.data().data()) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
|
||||
if ( write_ctx->exception ) {
|
||||
std::rethrow_exception(write_ctx->exception);
|
||||
}
|
||||
|
||||
dst.assign(write_ctx->data.data(), write_ctx->data.size());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user