From: Shaun Ren sren@codeweavers.com
Required by games such as "Zwei: The Arges Adventure". --- dlls/ir50_32/ir50.c | 103 +++++++++++++++++++++++++++++++++++-- dlls/ir50_32/ir50_compat.h | 4 ++ 2 files changed, 103 insertions(+), 4 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index b68bd6feeb0..9acc0c5aea7 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -44,12 +44,29 @@ static HINSTANCE IR50_32_hModule; static void decode_close( AVCodecContext *avctx ) { ff_ivi_decode_close( avctx ); + free( avctx->out_buf ); + free( avctx->dither_buf ); memset( avctx, 0, sizeof(*avctx) ); }
static LRESULT decode_init( AVCodecContext *avctx ) { - return indeo5_decode_init( avctx ); + int result; + + if ( (result = indeo5_decode_init( avctx )) ) + return result; + + if ( avctx->out_bitcount == 16 ) + { + if ( !(avctx->out_buf = malloc( 3 * avctx->width * avctx->height )) || + !(avctx->dither_buf = malloc( 3 * (avctx->width + 1) * (avctx->height + 1) )) ) + { + decode_close( avctx ); + return ICERR_MEMORY; + } + } + + return ICERR_OK; }
@@ -107,6 +124,72 @@ static void yuv410p_to_bgr24( AVFrame *frame, uint8_t *out ) } }
+/* c5 = round(c8 * 31 / 255), clipped. The table starts at c8 = -8. */ +static const uint8_t rgb8_to_5[256 + 8*2] = { + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, + 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, + 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31 +}; +/* c8 = round(c5 * 255 / 31) */ +static const uint8_t rgb5_to_8[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 +}; + +static void bgr24_to_bgr555( int width, int height, uint8_t *out24, int8_t *dither_buf, uint16_t *out ) +{ + int i, j; + int dither_linesz = 3 * (width + 1); + + memset( dither_buf, 0, dither_linesz * height ); + for ( j = 0; j < height; j++ ) + { + for ( i = 0; i < width; i++ ) + { +#define DITHER_PIXEL(ix) ((out24[ix] << 4) + dither_buf[ix]) +#define TO5(c) rgb8_to_5[(((c)+8) >> 4) + 8] +#define PIXEL_ERROR(c, c5) ((c) - (rgb5_to_8[c5] << 4)) + int b = DITHER_PIXEL(3*i), g = DITHER_PIXEL(3*i + 1), r = DITHER_PIXEL(3*i + 2); + uint16_t b5 = TO5(b), g5 = TO5(g), r5 = TO5(r); + int berr = PIXEL_ERROR(b, b5), gerr = PIXEL_ERROR(g, g5), rerr = PIXEL_ERROR(r, r5); + +#define DIFFUSE_ERROR(ix, f) \ + do { \ + dither_buf[(ix) ] += ((f) * berr + 8) >> 4; \ + dither_buf[(ix) + 1] += ((f) * gerr + 8) >> 4; \ + dither_buf[(ix) + 2] += ((f) * rerr + 8) >> 4; \ + } while (0) + + DIFFUSE_ERROR(3*(i+1), 7); + DIFFUSE_ERROR(dither_linesz + 3*(i-1), 3); + DIFFUSE_ERROR(dither_linesz + 3*i , 5); + DIFFUSE_ERROR(dither_linesz + 3*(i+1), 1); + + out[i] = b5 | g5 << 5 | r5 << 10; + } + out24 += 3 * width; + dither_buf += dither_linesz; + out += width; + } +} +
static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) @@ -146,7 +229,7 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) return ICERR_BADFORMAT; }
- if ( out->bmiHeader.biBitCount != 24 ) + if ( out->bmiHeader.biBitCount != 24 && out->bmiHeader.biBitCount != 16 ) { TRACE("incompatible depth requested\n"); return ICERR_BADFORMAT; @@ -205,13 +288,15 @@ static LRESULT IV50_DecompressBegin( AVCodecContext *avctx, LPBITMAPINFO in, LPB TRACE("out->width = %d\n", out->bmiHeader.biWidth); TRACE("out->compr = %#x\n", out->bmiHeader.biCompression);
- if ( in->bmiHeader.biBitCount != 24 || out->bmiHeader.biBitCount != 24 ) + if ( in->bmiHeader.biBitCount != 24 || + (out->bmiHeader.biBitCount != 24 && out->bmiHeader.biBitCount != 16) ) return ICERR_BADFORMAT;
decode_close( avctx );
avctx->width = in->bmiHeader.biWidth; avctx->height = in->bmiHeader.biHeight; + avctx->out_bitcount = out->bmiHeader.biBitCount;
return decode_init( avctx ); } @@ -246,7 +331,17 @@ static LRESULT IV50_Decompress( AVCodecContext *avctx, ICDECOMPRESS *icd, DWORD return ICERR_BADFORMAT; }
- yuv410p_to_bgr24( &frame, icd->lpOutput ); + if ( icd->lpbiOutput->biBitCount == 24 ) + { + yuv410p_to_bgr24( &frame, icd->lpOutput ); + } + else if ( icd->lpbiOutput->biBitCount == 16 ) + { + yuv410p_to_bgr24( &frame, avctx->out_buf ); + bgr24_to_bgr555( frame.width, frame.height, avctx->out_buf, avctx->dither_buf, icd->lpOutput ); + } + else + return ICERR_BADFORMAT;
return ICERR_OK; } diff --git a/dlls/ir50_32/ir50_compat.h b/dlls/ir50_32/ir50_compat.h index 3d4a0930554..64fdbe5c960 100644 --- a/dlls/ir50_32/ir50_compat.h +++ b/dlls/ir50_32/ir50_compat.h @@ -87,6 +87,10 @@ typedef struct AVFrame { typedef struct AVCodecContext { int width, height; void *priv_data; + + int out_bitcount; + uint8_t *out_buf; + int8_t *dither_buf; } AVCodecContext;
#endif /* __IR50_COMPAT_H */