Make desktop core dependencies portable
This commit is contained in:
+30
-49
@@ -2,11 +2,13 @@
|
||||
|
||||
#include "vectorail/core/gl_loader.hpp"
|
||||
|
||||
#include <png.h>
|
||||
#define STBI_ONLY_PNG
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb_image.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <limits>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
@@ -35,56 +37,34 @@ bool readFile(const std::string& path, std::vector<uint8_t>& bytes) {
|
||||
return static_cast<bool>(file) || file.eof();
|
||||
}
|
||||
|
||||
struct PngMemoryReader {
|
||||
std::span<const uint8_t> bytes;
|
||||
size_t offset = 0;
|
||||
};
|
||||
|
||||
void readPngMemory(png_structp png, png_bytep destination, png_size_t length) {
|
||||
auto* reader = static_cast<PngMemoryReader*>(png_get_io_ptr(png));
|
||||
if (!reader || length > reader->bytes.size() - reader->offset) {
|
||||
png_error(png, "truncated PNG stream");
|
||||
return;
|
||||
}
|
||||
std::memcpy(destination, reader->bytes.data() + reader->offset, length);
|
||||
reader->offset += length;
|
||||
}
|
||||
|
||||
bool decodePng(std::span<const uint8_t> bytes, DdsTexture& out, std::string* error) {
|
||||
out = {};
|
||||
if (bytes.size() < 8 || png_sig_cmp(bytes.data(), 0, 8) != 0) {
|
||||
constexpr uint8_t signature[] = {0x89, 'P', 'N', 'G', 0x0d, 0x0a, 0x1a, 0x0a};
|
||||
if (bytes.size() < sizeof(signature) ||
|
||||
!std::equal(std::begin(signature), std::end(signature), bytes.begin())) {
|
||||
if (error) *error = "not a PNG stream";
|
||||
return false;
|
||||
}
|
||||
|
||||
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
png_infop info = png ? png_create_info_struct(png) : nullptr;
|
||||
if (!png || !info || setjmp(png_jmpbuf(png))) {
|
||||
if (error) *error = "could not decode PNG";
|
||||
if (png) png_destroy_read_struct(&png, info ? &info : nullptr, nullptr);
|
||||
if (bytes.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
if (error) *error = "PNG stream is too large";
|
||||
return false;
|
||||
}
|
||||
|
||||
PngMemoryReader reader{bytes};
|
||||
png_set_read_fn(png, &reader, readPngMemory);
|
||||
png_read_info(png, info);
|
||||
const png_uint_32 width = png_get_image_width(png, info);
|
||||
const png_uint_32 height = png_get_image_height(png, info);
|
||||
const int colorType = png_get_color_type(png, info);
|
||||
const int bitDepth = png_get_bit_depth(png, info);
|
||||
if (bitDepth == 16) png_set_strip_16(png);
|
||||
if (colorType == PNG_COLOR_TYPE_PALETTE) png_set_palette_to_rgb(png);
|
||||
if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) png_set_expand_gray_1_2_4_to_8(png);
|
||||
if (png_get_valid(png, info, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png);
|
||||
if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png);
|
||||
if ((colorType & PNG_COLOR_MASK_ALPHA) == 0) png_set_add_alpha(png, 0xff, PNG_FILLER_AFTER);
|
||||
png_read_update_info(png, info);
|
||||
|
||||
std::vector<uint8_t> rgba(static_cast<size_t>(width) * height * 4);
|
||||
std::vector<png_bytep> rows(height);
|
||||
for (png_uint_32 y = 0; y < height; ++y) rows[y] = rgba.data() + static_cast<size_t>(y) * width * 4;
|
||||
png_read_image(png, rows.data());
|
||||
png_destroy_read_struct(&png, &info, nullptr);
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
int sourceChannels = 0;
|
||||
stbi_uc* rgba = stbi_load_from_memory(
|
||||
bytes.data(), static_cast<int>(bytes.size()),
|
||||
&width, &height, &sourceChannels, STBI_rgb_alpha);
|
||||
if (!rgba || width <= 0 || height <= 0) {
|
||||
if (error) {
|
||||
const char* reason = stbi_failure_reason();
|
||||
*error = reason ? std::string("could not decode PNG: ") + reason
|
||||
: "could not decode PNG";
|
||||
}
|
||||
stbi_image_free(rgba);
|
||||
return false;
|
||||
}
|
||||
|
||||
glGenTextures(1, &out.id);
|
||||
glBindTexture(GL_TEXTURE_2D, out.id);
|
||||
@@ -92,11 +72,12 @@ bool decodePng(std::span<const uint8_t> bytes, DdsTexture& out, std::string* err
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, static_cast<GLsizei>(width), static_cast<GLsizei>(height),
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, rgba.data());
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height,
|
||||
0, GL_RGBA, GL_UNSIGNED_BYTE, rgba);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
out.width = static_cast<int>(width);
|
||||
out.height = static_cast<int>(height);
|
||||
stbi_image_free(rgba);
|
||||
out.width = width;
|
||||
out.height = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user