mirror of https://github.com/axmolengine/axmol.git
247 lines
5.5 KiB
C++
247 lines
5.5 KiB
C++
#ifndef __DISABLED_DEFAULT_TEXTURE_LOADER__
|
|
#include "EffekseerRenderer.PngTextureLoader.h"
|
|
#include <chrono>
|
|
|
|
#ifdef __EFFEKSEER_USE_LIBPNG__
|
|
#include <png.h>
|
|
#else
|
|
#define STB_IMAGE_EFFEKSEER_IMPLEMENTATION
|
|
#include "../3rdParty/stb_effekseer/stb_image_effekseer.h"
|
|
|
|
#endif
|
|
|
|
namespace EffekseerRenderer
|
|
{
|
|
#ifdef __EFFEKSEER_USE_LIBPNG__
|
|
static void PngReadData(png_structp png_ptr, png_bytep data, png_size_t length)
|
|
{
|
|
uint8_t** d = (uint8_t**)png_get_io_ptr(png_ptr);
|
|
memcpy(data, *d, length);
|
|
(*d) += length;
|
|
}
|
|
#endif
|
|
|
|
bool PngTextureLoader::Load(const void* data, int32_t size, bool rev)
|
|
{
|
|
#ifdef __EFFEKSEER_USE_LIBPNG__
|
|
textureWidth = 0;
|
|
textureHeight = 0;
|
|
textureData.clear();
|
|
|
|
uint8_t* data_ = (uint8_t*)data;
|
|
|
|
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
|
|
|
png_set_read_fn(png, &data_, &PngReadData);
|
|
|
|
png_infop png_info = png_create_info_struct(png);
|
|
|
|
if (setjmp(png_jmpbuf(png)))
|
|
{
|
|
png_destroy_read_struct(&png, &png_info, nullptr);
|
|
return false;
|
|
}
|
|
|
|
png_read_info(png, png_info);
|
|
|
|
const auto interlaceType = png_get_interlace_type(png, png_info);
|
|
|
|
int passes = 1;
|
|
if (interlaceType != PNG_INTERLACE_NONE)
|
|
passes = png_set_interlace_handling(png);
|
|
|
|
const png_byte bit_depth = png_get_bit_depth(png, png_info);
|
|
if (bit_depth < 8)
|
|
{
|
|
png_set_packing(png);
|
|
}
|
|
else if (bit_depth == 16)
|
|
{
|
|
png_set_strip_16(png);
|
|
}
|
|
|
|
uint32_t pixelBytes = 4;
|
|
const png_byte color_type = png_get_color_type(png, png_info);
|
|
switch (color_type)
|
|
{
|
|
case PNG_COLOR_TYPE_PALETTE:
|
|
{
|
|
png_set_palette_to_rgb(png);
|
|
|
|
png_bytep trans_alpha = nullptr;
|
|
int num_trans = 0;
|
|
png_color_16p trans_color = nullptr;
|
|
|
|
png_get_tRNS(png, png_info, &trans_alpha, &num_trans, &trans_color);
|
|
if (trans_alpha != nullptr)
|
|
{
|
|
pixelBytes = 4;
|
|
}
|
|
else
|
|
{
|
|
pixelBytes = 3;
|
|
}
|
|
}
|
|
break;
|
|
case PNG_COLOR_TYPE_GRAY:
|
|
pixelBytes = 1;
|
|
break;
|
|
case PNG_COLOR_TYPE_GRAY_ALPHA:
|
|
png_set_gray_to_rgb(png);
|
|
pixelBytes = 4;
|
|
break;
|
|
case PNG_COLOR_TYPE_RGB:
|
|
pixelBytes = 3;
|
|
break;
|
|
case PNG_COLOR_TYPE_RGBA:
|
|
break;
|
|
}
|
|
|
|
textureWidth = png_get_image_width(png, png_info);
|
|
textureHeight = png_get_image_height(png, png_info);
|
|
|
|
uint8_t* image = new uint8_t[textureWidth * textureHeight * pixelBytes];
|
|
uint32_t pitch = textureWidth * pixelBytes;
|
|
|
|
for (int pass = 0; pass < passes; pass++)
|
|
{
|
|
if (rev)
|
|
{
|
|
for (int32_t i = 0; i < textureHeight; i++)
|
|
{
|
|
png_read_row(png, &image[(textureHeight - 1 - i) * pitch], nullptr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int32_t i = 0; i < textureHeight; i++)
|
|
{
|
|
png_read_row(png, &image[i * pitch], nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
textureData.resize(textureWidth * textureHeight * 4);
|
|
auto imagedst_ = textureData.data();
|
|
|
|
if (pixelBytes == 4)
|
|
{
|
|
memcpy(imagedst_, image, textureWidth * textureHeight * 4);
|
|
}
|
|
else if (pixelBytes == 1)
|
|
{
|
|
for (int32_t y = 0; y < textureHeight; y++)
|
|
{
|
|
for (int32_t x = 0; x < textureWidth; x++)
|
|
{
|
|
auto src = (x + y * textureWidth) * 1;
|
|
auto dst = (x + y * textureWidth) * 4;
|
|
imagedst_[dst + 0] = image[src + 0];
|
|
imagedst_[dst + 1] = image[src + 0];
|
|
imagedst_[dst + 2] = image[src + 0];
|
|
imagedst_[dst + 3] = 255;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int32_t y = 0; y < textureHeight; y++)
|
|
{
|
|
for (int32_t x = 0; x < textureWidth; x++)
|
|
{
|
|
auto src = (x + y * textureWidth) * 3;
|
|
auto dst = (x + y * textureWidth) * 4;
|
|
imagedst_[dst + 0] = image[src + 0];
|
|
imagedst_[dst + 1] = image[src + 1];
|
|
imagedst_[dst + 2] = image[src + 2];
|
|
imagedst_[dst + 3] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
delete[] image;
|
|
png_destroy_read_struct(&png, &png_info, nullptr);
|
|
|
|
return true;
|
|
|
|
#else
|
|
|
|
unsigned char* pixels = nullptr;
|
|
int width = 0;
|
|
int height = 0;
|
|
int bpp = 0;
|
|
|
|
auto pre = std::chrono::high_resolution_clock::now();
|
|
|
|
pixels = (uint8_t*)Effekseer::stbi_load_from_memory((Effekseer::stbi_uc const*)data, size, &width, &height, &bpp, 0);
|
|
|
|
if (width > 0)
|
|
{
|
|
textureData.resize(width * height * 4);
|
|
textureWidth = width;
|
|
textureHeight = height;
|
|
auto buf = textureData.data();
|
|
|
|
if (bpp == 4)
|
|
{
|
|
memcpy(textureData.data(), pixels, width * height * 4);
|
|
}
|
|
else if (bpp == 2)
|
|
{
|
|
// Gray+Alpha
|
|
for (int h = 0; h < height; h++)
|
|
{
|
|
for (int w = 0; w < width; w++)
|
|
{
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 0] = pixels[(w + h * width) * 2 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 1] = pixels[(w + h * width) * 2 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 2] = pixels[(w + h * width) * 2 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 3] = pixels[(w + h * width) * 2 + 1];
|
|
}
|
|
}
|
|
}
|
|
else if (bpp == 1)
|
|
{
|
|
// Gray
|
|
for (int h = 0; h < height; h++)
|
|
{
|
|
for (int w = 0; w < width; w++)
|
|
{
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 0] = pixels[(w + h * width) * 1 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 1] = pixels[(w + h * width) * 1 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 2] = pixels[(w + h * width) * 1 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 3] = 255;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int h = 0; h < height; h++)
|
|
{
|
|
for (int w = 0; w < width; w++)
|
|
{
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 0] = pixels[(w + h * width) * 3 + 0];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 1] = pixels[(w + h * width) * 3 + 1];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 2] = pixels[(w + h * width) * 3 + 2];
|
|
((uint8_t*)buf)[(w + h * width) * 4 + 3] = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
Effekseer::stbi_image_free(pixels);
|
|
return true;
|
|
}
|
|
|
|
Effekseer::stbi_image_free(pixels);
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void PngTextureLoader::Unload()
|
|
{
|
|
textureData.clear();
|
|
}
|
|
|
|
} // namespace EffekseerRenderer
|
|
|
|
#endif |