Example #1
0
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;
}
Example #2
0
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;
}