124 lines
4.2 KiB
C
124 lines
4.2 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdbool.h>
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#define STBI_FAILURE_USERMSG
|
|
#include "stb_image.h"
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image_write.h"
|
|
|
|
struct image {
|
|
char* filename;
|
|
unsigned char* image_data;
|
|
int width;
|
|
int height;
|
|
int channels;
|
|
};
|
|
|
|
int main(int argc, char* argv[]) {
|
|
if (argc == 1) {
|
|
fprintf(stderr, "Must provide image files to pack");
|
|
exit(-1);
|
|
}
|
|
if (argc == 2) {
|
|
fprintf(stderr, "Please provide at least 2 images to pack");
|
|
exit(-1);
|
|
}
|
|
struct image* images = calloc(argc - 1, sizeof(struct image));
|
|
if (images == NULL) {
|
|
fprintf(stderr, "Failed to alloc image data array");
|
|
exit(-1);
|
|
}
|
|
//-------------------------------------
|
|
// First get the image info, make sure the file is an image and it exists
|
|
//-------------------------------------
|
|
int image_count = argc - 1;
|
|
for (int i = 0; i < argc - 1; i++) {
|
|
struct image* img = &images[i];
|
|
img->filename = argv[i+1];
|
|
|
|
int result = stbi_info(img->filename, &img->width, &img->height, &img->channels);
|
|
if (result != 1) {
|
|
char *errorMsg = "Cannot load image '%s': %s\n";
|
|
fprintf(stderr, errorMsg, img->filename, stbi_failure_reason());
|
|
exit(-1);
|
|
}
|
|
}
|
|
//-------------------------------------
|
|
// Now run the packing algorithm
|
|
// Note: How to get the minimum power of 2 texture size. Note that this is still
|
|
// very inefficient because we're just naively putting them all at 0
|
|
// x = log2(max(width, height))
|
|
// width or height = 2 ** (x + 1)
|
|
// This is super inefficient texture packing but I just want to get it working first
|
|
//-------------------------------------
|
|
|
|
int totalh = 0, maxw = 0;
|
|
for (int i = 0; i < image_count; i++) {
|
|
totalh += images[i].height;
|
|
if (images[i].width > maxw) {
|
|
maxw = images[i].width;
|
|
}
|
|
}
|
|
int max = totalh > maxw ? totalh : maxw;
|
|
int exp = (int)log2(max) + 1;
|
|
int size = (int)pow(2, exp);
|
|
unsigned char* buf = calloc(size*size*4, sizeof(char));
|
|
|
|
//-------------------------------------
|
|
// Now load the data into memory, for now, let's just load all images in one go,
|
|
// however, it would be more optimized if we loaded each image sequentially or
|
|
// better yet in parallel so that we can write to the different parts of the
|
|
// texture atlas concurrently
|
|
//-------------------------------------
|
|
|
|
for (int i = 0; i < image_count; i++) {
|
|
int w,h,c;
|
|
images[i].image_data = (unsigned char*)stbi_load(images[i].filename, &w, &h, &c, 4);
|
|
if (images[i].image_data == NULL) {
|
|
char *errorMsg = "Could not load data for image '%s': %s";
|
|
fprintf(stderr, errorMsg, images[i].filename, stbi_failure_reason());
|
|
// QUESTION: Should we clean up here?
|
|
exit(-1);
|
|
}
|
|
}
|
|
|
|
//-------------------------------------
|
|
// Just write the bytes directly for now, we don't have any "rect" data, which
|
|
// we need to make this work, since we're "hardcoding" the positions of the textures
|
|
//-------------------------------------
|
|
|
|
int atlasrow = 0;
|
|
for (int i = 0; i < image_count; i++) {
|
|
int width = images[i].width;
|
|
int length = images[i].width * images[i].height * images[i].channels;
|
|
int color_row = 0;
|
|
int color_col = 0;
|
|
int c = 0;
|
|
while (c < length) {
|
|
int bidx = atlasrow * maxw * 4 + color_row;
|
|
int iidx = color_col * width * 4 + color_row;
|
|
buf[bidx] = images[i].image_data[iidx];
|
|
color_row++;
|
|
if (color_row > width * 4) {
|
|
color_row = 0;
|
|
color_col += 1;
|
|
atlasrow += 1;
|
|
}
|
|
c++;
|
|
}
|
|
}
|
|
|
|
stbi_write_png("test.png", maxw, totalh, 4, buf, maxw * 4);
|
|
|
|
//-------------------------------------
|
|
// Free them all, but eventually we would free after we finished 1
|
|
//-------------------------------------
|
|
for (int i = 0; i < image_count; i++) {
|
|
stbi_image_free(images[i].image_data);
|
|
}
|
|
return 0;
|
|
}
|