voxelcore/src/graphics/ImageData.cpp
2023-11-13 15:01:41 +03:00

119 lines
4.3 KiB
C++

#include "ImageData.h"
#include <assert.h>
#include <stdexcept>
inline int min(int a, int b) {
return (a < b) ? a : b;
}
inline int max(int a, int b) {
return (a > b) ? a : b;
}
ImageData::ImageData(ImageFormat format, uint width, uint height, void* data)
: format(format), width(width), height(height), data(data) {
}
ImageData::~ImageData() {
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888:
delete[] (ubyte*)data;
break;
}
}
void ImageData::flipX() {
uint size;
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888: {
size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height; y++) {
for (uint x = 0; x < width/2; x++) {
for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] = pixels[(y * width + (width - x - 1)) * size + c];
pixels[(y * width + (width - x - 1)) * size + c] = temp;
}
}
}
break;
}
default:
throw std::runtime_error("format is not supported");
}
}
void ImageData::flipY() {
uint size;
switch (format) {
case ImageFormat::rgb888:
case ImageFormat::rgba8888: {
size = (format == ImageFormat::rgba8888) ? 4 : 3;
ubyte* pixels = (ubyte*)data;
for (uint y = 0; y < height/2; y++) {
for (uint x = 0; x < width; x++) {
for (uint c = 0; c < size; c++) {
ubyte temp = pixels[(y * width + x) * size + c];
pixels[(y * width + x) * size + c] = pixels[((height-y-1) * width + x) * size + c];
pixels[((height-y-1) * width + x) * size + c] = temp;
}
}
}
break;
}
default:
throw std::runtime_error("format is not supported");
}
}
ImageData* add_atlas_margins(ImageData* image, int grid_size) {
// RGBA is only supported
assert(image->getFormat() == ImageFormat::rgba8888);
assert(image->getWidth() == image->getHeight());
int srcwidth = image->getWidth();
int srcheight = image->getHeight();
int dstwidth = srcwidth + grid_size * 2;
int dstheight = srcheight + grid_size * 2;
const ubyte* srcdata = (const ubyte*)image->getData();
ubyte* dstdata = new ubyte[dstwidth*dstheight * 4];
int imgres = image->getWidth() / grid_size;
for (int row = 0; row < grid_size; row++) {
for (int col = 0; col < grid_size; col++) {
int sox = col * imgres;
int soy = row * imgres;
int dox = 1 + col * (imgres + 2);
int doy = 1 + row * (imgres + 2);
for (int ly = -1; ly <= imgres; ly++) {
for (int lx = -1; lx <= imgres; lx++) {
int sy = max(min(ly, imgres-1), 0);
int sx = max(min(lx, imgres-1), 0);
for (int c = 0; c < 4; c++)
dstdata[((doy+ly) * dstwidth + dox + lx) * 4 + c] = srcdata[((soy+sy) * srcwidth + sox + sx) * 4 + c];
}
}
// Fixing black transparent pixels for Mip-Mapping
for (int ly = 0; ly < imgres; ly++) {
for (int lx = 0; lx < imgres; lx++) {
if (srcdata[((soy+ly) * srcwidth + sox + lx) * 4 + 3]) {
for (int c = 0; c < 3; c++) {
int val = srcdata[((soy+ly) * srcwidth + sox + lx) * 4 + c];
if (dstdata[((doy+ly) * dstwidth + dox + lx + 1) * 4 + 3] == 0)
dstdata[((doy+ly) * dstwidth + dox + lx + 1) * 4 + c] = val;
if (dstdata[((doy+ly + 1) * dstwidth + dox + lx) * 4 + 3] == 0)
dstdata[((doy+ly + 1) * dstwidth + dox + lx) * 4 + c] = val;
}
}
}
}
}
}
return new ImageData(image->getFormat(), dstwidth, dstheight, dstdata);
}