Files
ReImage/src/rTexture.cpp
2024-06-11 13:21:41 -04:00

148 lines
4.7 KiB
C++

#include <fstream>
#include <algorithm>
#include <ReTexture/rTexture.h>
#include <iostream>
void RTexture::load(const std::string& file) {
std::ifstream ifStream(file, std::ios::in | std::ios::binary);
unsigned char bmpFileHeader[14];
ifStream.read(reinterpret_cast<char*>(bmpFileHeader), 14);
if (bmpFileHeader[0] == 'B' && bmpFileHeader[1] == 'M') {
ifStream.close();
loadBMP(file);
return;
}
//TODO
if (file.ends_with(".png"))
loadPNG(file);
}
void RTexture::loadBMP(const std::string& file) {
std::ifstream bmpFile(file, std::ios::in | std::ios::binary);
if (!bmpFile.is_open())
return;
unsigned char bmpFileHeader[14];
unsigned char bmpInfoHeader[40];
bmpFile.read(reinterpret_cast<char*>(bmpFileHeader), 14);
bmpFile.read(reinterpret_cast<char*>(bmpInfoHeader), 40);
width = bmpInfoHeader[4] + (bmpInfoHeader[5] << 8) + (bmpInfoHeader[6] << 16) + (bmpInfoHeader[7] << 24);
height = bmpInfoHeader[8] + (bmpInfoHeader[9] << 8) + (bmpInfoHeader[10] << 16) + (bmpInfoHeader[11] << 24);
int rowPadded = (width * 3 + 3) & (~3);
pixelData.resize(width * height * 3);
std::vector<unsigned char> rowData(rowPadded);
for (int y = height - 1; y >= 0; --y) {
bmpFile.read(reinterpret_cast<char*>(rowData.data()), rowPadded);
for (int x = 0; x < width; ++x) {
pixelData[(y * width + x) * 3 + 2] = rowData[x * 3 + 0];
pixelData[(y * width + x) * 3 + 1] = rowData[x * 3 + 1];
pixelData[(y * width + x) * 3 + 0] = rowData[x * 3 + 2];
}
}
bmpFile.close();
format = RTextureFormat::RGB;
}
void RTexture::loadPNG(const std::string &file) {
FILE *fp = fopen(file.c_str(), "rb");
if (!fp) {
fprintf(stderr, "Could not open file %s for reading\n", file.c_str());
return;
}
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
if (!png) {
fprintf(stderr, "Could not create png read struct\n");
fclose(fp);
return;
}
png_infop info = png_create_info_struct(png);
if (!info) {
fprintf(stderr, "Could not create png info struct\n");
png_destroy_read_struct(&png, nullptr, nullptr);
fclose(fp);
return;
}
if (setjmp(png_jmpbuf(png))) {
fprintf(stderr, "Error during png creation\n");
png_destroy_read_struct(&png, &info, nullptr);
fclose(fp);
return;
}
png_init_io(png, fp);
png_read_info(png, info);
width = png_get_image_width(png, info);
height = png_get_image_height(png, info);
png_byte color_type = png_get_color_type(png, info);
png_byte bit_depth = png_get_bit_depth(png, info);
if (bit_depth == 16)
png_set_strip_16(png);
if (color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(png);
if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 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 (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)
png_set_filler(png, 0xFF, PNG_FILLER_AFTER);
if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
png_set_gray_to_rgb(png);
png_read_update_info(png, info);
pixelData.resize(png_get_rowbytes(png, info) * height);
std::vector<png_bytep> row_pointers(height);
for (unsigned y = 0; y < height; ++y) {
row_pointers[y] = pixelData.data() + y * png_get_rowbytes(png, info);
}
png_read_image(png, row_pointers.data());
fclose(fp);
png_destroy_read_struct(&png, &info, nullptr);
if (color_type & PNG_COLOR_MASK_ALPHA)
format = RTextureFormat::RGBA;
if (!(color_type & PNG_COLOR_MASK_ALPHA))
format = RTextureFormat::RGB;
}
RTexture::RTexture(const std::string &file, const std::vector<RTextureFlag> &args) {
load(file);
if (std::find(args.begin(), args.end(), RTextureFlag::INVERT_Y) != args.end())
invertY();
}
void RTexture::invertY() {
unsigned int rowSize;
if (format == RTextureFormat::RGB)
rowSize = width * 3;
if (format == RTextureFormat::RGBA)
rowSize = width * 4;
std::vector<unsigned char> temp(rowSize);
for (uint y = 0; y < height / 2; ++y) {
unsigned char* topRow = &pixelData[y * rowSize];
unsigned char* bottomRow = &pixelData[(height - y - 1) * rowSize];
std::copy(bottomRow, bottomRow + rowSize, temp.begin());
std::copy(topRow, topRow + rowSize, bottomRow);
std::copy(temp.begin(), temp.end(), topRow);
}
}