//this function takes in 2 struct v4l2_format and a libvideo palette index //it will try and see if the chosen palette can be obtained, either straight //from the driver or after conversion using libv4lconvert //it returns the libvideo palette to use in order to get the requested //libvideo palette, or -1 upon return, src * dst will contain meaningful values static int try_image_format(struct capture_device *c, struct v4l2_format *src, struct v4l2_format *dst, int palette_idx){ int index = -1; CLEAR(*src); CLEAR(*dst); dst->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; dst->fmt.pix.width = c->width; dst->fmt.pix.height = c->height; dst->fmt.pix.field = V4L2_FIELD_ANY; dst->fmt.pix.pixelformat = libvideo_palettes[palette_idx].v4l2_palette; if(0 == v4lconvert_try_format(c->convert->priv, dst, src)){ dprint(LIBVIDEO_SOURCE_CAP, LIBVIDEO_LOG_DEBUG1, "CAP: For dest palette %#x (%s - %d) %dx%d - ...\n",\ dst->fmt.pix.pixelformat, libvideo_palettes[palette_idx].name, palette_idx, dst->fmt.pix.width, dst->fmt.pix.height); dprint(LIBVIDEO_SOURCE_CAP, LIBVIDEO_LOG_DEBUG1, "CAP: libv4lconvert said to use palette %#x %dx%d - ...\n",\ src->fmt.pix.pixelformat, src->fmt.pix.width, src->fmt.pix.height); if((index = get_palette_index(src->fmt.pix.pixelformat))!= -1){ dprint(LIBVIDEO_SOURCE_CAP, LIBVIDEO_LOG_DEBUG1, "CAP: which is libvideo index %d, palette %s\n",\ index, libvideo_palettes[index].name); dprint(LIBVIDEO_SOURCE_CAP, LIBVIDEO_LOG_DEBUG, "CAP: libv4lconvert required ? %s\n", (v4lconvert_needs_conversion( c->convert->priv, src, dst)==0?"No":"Yes" ) ); } else { dprint(LIBVIDEO_SOURCE_CAP, LIBVIDEO_LOG_DEBUG1, "CAP: palette returned by libv4lconvert is unknown to " "libvideo\n"); info("The source image format returned by libv4l_convert is "); info("unknown\nPlease, let the author known about this error:\n"); info("Destination palette: %#x (%s)\n",\ libvideo_palettes[palette_idx].v4l2_palette, libvideo_palettes[palette_idx].name); info("libv4l_convert source palette: %#x", src->fmt.pix.pixelformat); info("See the README file on how to submit bug reports."); } } return index; }
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; }