static bool sprite_file_import(const char *path, rct_g1_element *outElement, uint8 **outBuffer, int *outBufferLength, int mode) { uint8 *pixels; uint32 width, height; if (!image_io_png_read(&pixels, &width, &height, path)) { fprintf(stderr, "Error reading PNG"); return false; } if (width > 256 || height > 256) { fprintf(stderr, "Only images 256x256 or less are supported."); free(pixels); return false; } memcpy(spriteFilePalette, _standardPalette, 256 * 4); uint8 *buffer = malloc((height * 2) + (width * height * 16)); memset(buffer, 0, (height * 2) + (width * height * 16)); uint16 *yOffsets = (uint16*)buffer; // A larger range is needed for proper dithering sint16 *src = malloc(height * width * 4 * 2); sint16 *src_orig = src; 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] = (uint16)(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); free(src_orig); 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; }
bool mapgen_load_heightmap(const utf8 *path) { const char* extension = path_get_extension(path); uint8 *pixels; size_t pitch; uint32 numChannels; uint32 width, height; if (strcicmp(extension, ".png") == 0) { if (!image_io_png_read(&pixels, &width, &height, path)) { log_warning("Error reading PNG"); window_error_open(STR_HEIGHT_MAP_ERROR, STR_ERROR_READING_PNG); return false; } numChannels = 4; pitch = width * numChannels; } else if (strcicmp(extension, ".bmp") == 0) { if (!context_read_bmp((void *)&pixels, &width, &height, path)) { // ReadBMP contains window_error_open calls return false; } numChannels = 4; pitch = width * numChannels; } else { openrct2_assert(false, "A file with an invalid file extension was selected."); return false; } if (width != height) { window_error_open(STR_HEIGHT_MAP_ERROR, STR_ERROR_WIDTH_AND_HEIGHT_DO_NOT_MATCH); free(pixels); return false; } if (width > MAXIMUM_MAP_SIZE_PRACTICAL) { window_error_open(STR_HEIGHT_MAP_ERROR, STR_ERROR_HEIHGT_MAP_TOO_BIG); width = height = min(height, MAXIMUM_MAP_SIZE_PRACTICAL); } // Allocate memory for the height map values, one byte pixel free(_heightMapData.mono_bitmap); _heightMapData.mono_bitmap = (uint8*)malloc(width * height); _heightMapData.width = width; _heightMapData.height = height; // Copy average RGB value to mono bitmap for (uint32 x = 0; x < _heightMapData.width; x++) { for (uint32 y = 0; y < _heightMapData.height; y++) { const uint8 red = pixels[x * numChannels + y * pitch]; const uint8 green = pixels[x * numChannels + y * pitch + 1]; const uint8 blue = pixels[x * numChannels + y * pitch + 2]; _heightMapData.mono_bitmap[x + y * _heightMapData.width] = (red + green + blue) / 3; } } free(pixels); return true; }