static void create_mesh() { par_msquares_meshlist* mlist = 0; float threshold = 0; int flags = 0; if (state == STATE_GRAY_DEFAULT) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_SIMPLIFY) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_SIMPLIFY; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_INVERT) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_INVERT; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DUAL) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_HEIGHTS) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_HEIGHTS; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DHS) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_DHSC) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT; mlist = par_msquares_grayscale( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, threshold, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_GRAY_MULTI) { float const* graydata = parg_buffer_lock(graybuf, PARG_READ); float thresholds[] = {0.0, 0.1}; flags = PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT; mlist = par_msquares_grayscale_multi( graydata, IMGWIDTH, IMGHEIGHT, CELLSIZE, thresholds, 2, flags); parg_buffer_unlock(graybuf); } else if (state == STATE_COLOR_DEFAULT) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_COLOR_IH) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; flags = PAR_MSQUARES_INVERT | PAR_MSQUARES_HEIGHTS; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_COLOR_DHSCSI) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; flags = PAR_MSQUARES_DUAL | PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_SNAP | PAR_MSQUARES_CONNECT | PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_INVERT; mlist = par_msquares_color( rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 0x214562, 4, flags); parg_buffer_unlock(colorbuf); } else if (state == STATE_MULTI_RGB) { unsigned dims[2] = {0, 0}; unsigned char* pixels; lodepng_decode_file( &pixels, &dims[0], &dims[1], "extern/par/test/rgb.png", LCT_RGB, 8); mlist = par_msquares_color_multi( pixels, dims[0], dims[1], 16, 3, PAR_MSQUARES_SIMPLIFY); free(pixels); } else if (state == STATE_MULTI_RGBA) { unsigned dims[2] = {0, 0}; unsigned char* pixels; lodepng_decode_file(&pixels, &dims[0], &dims[1], "extern/par/test/rgba.png", LCT_RGBA, 8); mlist = par_msquares_color_multi(pixels, dims[0], dims[1], 16, 4, PAR_MSQUARES_HEIGHTS | PAR_MSQUARES_CONNECT | PAR_MSQUARES_SIMPLIFY); free(pixels); } else if (state == STATE_MULTI_DIAGRAM) { parg_byte const* rgbadata = parg_buffer_lock(colorbuf, PARG_READ); rgbadata += sizeof(int) * 3; mlist = par_msquares_color_multi(rgbadata, IMGWIDTH, IMGHEIGHT, CELLSIZE, 4, PAR_MSQUARES_SIMPLIFY | PAR_MSQUARES_HEIGHTS); parg_buffer_unlock(colorbuf); } nmeshes = par_msquares_get_count(mlist); printf("%d meshes\n", nmeshes); for (int imesh = 0; imesh < nmeshes; imesh++) { par_msquares_mesh const* mesh = par_msquares_get_mesh(mlist, imesh); // mquares_mesh might have dimensionality of 2 or 3, while parg_mesh // only // supports the latter. So, we potentially need to expand the data from // vec2 to vec3. float* points = mesh->points; if (mesh->dim == 2) { points = malloc(mesh->npoints * sizeof(float) * 3); for (int i = 0; i < mesh->npoints; i++) { points[i * 3] = mesh->points[i * 2]; points[i * 3 + 1] = mesh->points[i * 2 + 1]; points[i * 3 + 2] = 0; } } meshcolors[imesh] = mesh->color; trimesh[imesh] = parg_mesh_create( points, mesh->npoints, mesh->triangles, mesh->ntriangles); if (mesh->dim == 2) { free(points); } } par_msquares_free(mlist); }
bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, int mode) { unsigned char *pixels; unsigned int width, height; unsigned int pngError; memcpy(spriteFilePalette, _standardPalette, 256 * 4); pngError = lodepng_decode_file(&pixels, &width, &height, path, LCT_RGBA, 8); if (pngError != 0) { fprintf(stderr, "Error creating PNG data, %u: %s", pngError, lodepng_error_text(pngError)); return false; } if (width > 256 || height > 256) { fprintf(stderr, "Only images 256x256 or less are supported."); free(pixels); return false; } uint8 *buffer = malloc((height * 2) + (width * height * 16)); uint16 *yOffsets = (uint16*)buffer; // A larger range is needed for proper dithering sint16 *src = malloc(height * width * 4 * 2); for (uint32 x = 0; x < height * width * 4; x++){ src[x] = (sint16) pixels[x]; } uint8 *dst = buffer + (height * 2); for (unsigned int y = 0; y < height; y++) { rle_code *previousCode, *currentCode; yOffsets[y] = (dst - buffer); previousCode = NULL; currentCode = (rle_code*)dst; dst += 2; int startX = 0; int pixels = 0; bool pushRun = false; for (unsigned int x = 0; x < width; x++) { int paletteIndex = get_palette_index(src); if (mode == MODE_CLOSEST || mode == MODE_DITHERING) if (paletteIndex == -1 && !is_transparent_pixel(src)) paletteIndex = get_closest_palette_index(src); if (mode == MODE_DITHERING) if (!is_transparent_pixel(src) && is_changable_pixel(get_palette_index(src))){ sint16 dr = src[0] - (sint16)(spriteFilePalette[paletteIndex].r); sint16 dg = src[1] - (sint16)(spriteFilePalette[paletteIndex].g); sint16 db = src[2] - (sint16)(spriteFilePalette[paletteIndex].b); if (x + 1 < width){ if (!is_transparent_pixel(src + 4) && is_changable_pixel(get_palette_index(src + 4))){ // Right src[4] += dr * 7 / 16; src[5] += dg * 7 / 16; src[6] += db * 7 / 16; } } if (y + 1 < height){ if (x > 0){ if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width - 1)))){ // Bottom left src[4 * (width - 1)] += dr * 3 / 16; src[4 * (width - 1) + 1] += dg * 3 / 16; src[4 * (width - 1) + 2] += db * 3 / 16; } } // Bottom if (!is_transparent_pixel(src + 4 * width) && is_changable_pixel(get_palette_index(src + 4 * width))){ src[4 * width] += dr * 5 / 16; src[4 * width + 1] += dg * 5 / 16; src[4 * width + 2] += db * 5 / 16; } if (x + 1 < width){ if (!is_transparent_pixel(src + 4 * (width - 1)) && is_changable_pixel(get_palette_index(src + 4 * (width + 1)))){ // Bottom right src[4 * (width + 1)] += dr * 1 / 16; src[4 * (width + 1) + 1] += dg * 1 / 16; src[4 * (width + 1) + 2] += db * 1 / 16; } } } } src += 4; if (paletteIndex == -1) { if (pixels != 0) { x--; src -= 4; pushRun = true; } } else { if (pixels == 0) startX = x; pixels++; *dst++ = (uint8)paletteIndex; } if (pixels == 127 || x == width - 1) pushRun = true; if (pushRun) { if (pixels > 0) { previousCode = currentCode; currentCode->num_pixels = pixels; currentCode->offset_x = startX; if (x == width - 1) currentCode->num_pixels |= 0x80; currentCode = (rle_code*)dst; dst += 2; } else { if (previousCode == NULL) { currentCode->num_pixels = 0x80; currentCode->offset_x = 0; } else { previousCode->num_pixels |= 0x80; dst -= 2; } } startX = 0; pixels = 0; pushRun = false; } } } free(pixels); int bufferLength = (int)(dst - buffer); buffer = realloc(buffer, bufferLength); outElement->offset = buffer; outElement->width = width; outElement->height = height; outElement->flags = G1_FLAG_RLE_COMPRESSION; outElement->x_offset = 0; outElement->y_offset = 0; outElement->zoomed_offset = 0; *outBuffer = buffer; *outBufferLength = bufferLength; return true; }
int main(int argc, char **argv) { int compressed_len; int pixels; int w,h; unsigned char *bmp = NULL; unsigned char *bmp0 = NULL; unsigned char *bmp1 = NULL; int result; int rawlen; int x, y; int row,bit; char prefix[256] = "out"; if (argc < 2) { printf("usage: cabi in.png [array_name_prefix]\n"); } if (argc >= 3) strcpy(prefix, argv[2]); result = lodepng_decode_file(&bmp, &w, &h, argv[1], 6, 8); if (result != 0) { printf("could not load %s\n", argv[1]); exit(0); } // generate sprite and mask rawlen = w * (h+7) / 8; bmp0 = malloc(rawlen); memset(bmp0, 0, rawlen); bmp1 = malloc(rawlen); memset(bmp1, 0, rawlen); printf("// %s width: %d height: %d\n", argv[1], w, h); for (y = 0; y < h; y++) { for (x = 0; x < w; x++) { row = y/8; bit = y&7; if (bmp[(x+y*w)*4 + 3] > 128) // need to be opaque to count if (bmp[(x+y*w)*4 + 0] > 128) { // set sprite bmp0[x + (row*w)] |= (1 << bit); } if (bmp[(x+y*w)*4 + 3] > 128) { // set mask bmp1[x + (row*w)] |= (1 << bit); } } } compressed_len = compress_rle(bmp0, w, h, prefix, ""); printf("// bytes:%d ratio: %3.3f\n\n", compressed_len, (float)(compressed_len * 8)/ (float)(w*h)); compressed_len = compress_rle(bmp1, w, h, prefix, "_mask"); printf("// bytes:%d ratio: %3.3f\n\n", compressed_len, (float)(compressed_len * 8)/ (float)(w*h)); free(bmp0); free(bmp1); return 0; }