X-Git-Url: https://git.xonotic.org/?a=blobdiff_plain;ds=sidebyside;f=image.c;h=87c527484a6032a3b8ed2e37061e69c213f75a72;hb=1a148e8e6ea1d0aea8f1a05315a8425dfdc6c5db;hp=dbad08ff5b69231a6e8255e1faafe393b8efaa11;hpb=d57be67cb00229acb8564b92c8b7c58eeed8a0cb;p=xonotic%2Fdarkplaces.git diff --git a/image.c b/image.c index dbad08ff..87c52748 100644 --- a/image.c +++ b/image.c @@ -4,7 +4,7 @@ int image_width; int image_height; -void Image_GammaRemapRGB(byte *in, byte *out, int pixels, byte *gammar, byte *gammag, byte *gammab) +void Image_GammaRemapRGB(qbyte *in, qbyte *out, int pixels, qbyte *gammar, qbyte *gammag, qbyte *gammab) { while (pixels--) { @@ -17,7 +17,7 @@ void Image_GammaRemapRGB(byte *in, byte *out, int pixels, byte *gammar, byte *ga } // note: pal must be 32bit color -void Image_Copy8bitRGBA(byte *in, byte *out, int pixels, int *pal) +void Image_Copy8bitRGBA(qbyte *in, qbyte *out, int pixels, int *pal) { int *iout = (void *)out; while (pixels >= 8) @@ -83,11 +83,11 @@ typedef struct LoadPCX ============ */ -byte* LoadPCX (byte *f, int matchwidth, int matchheight) +qbyte* LoadPCX (qbyte *f, int matchwidth, int matchheight) { - pcx_t pcx; - byte *palette, *a, *b, *image_rgba, *fin, *pbuf, *enddata; - int x, y, x2, dataByte; + pcx_t pcx; + qbyte *palette, *a, *b, *image_rgba, *fin, *pbuf, *enddata; + int x, y, x2, dataByte; if (loadsize < sizeof(pcx) + 768) { @@ -204,10 +204,10 @@ TargaHeader targa_header; LoadTGA ============= */ -byte* LoadTGA (byte *f, int matchwidth, int matchheight) +qbyte *LoadTGA (qbyte *f, int matchwidth, int matchheight) { int columns, rows, row, column; - byte *pixbuf, *image_rgba, *fin, *enddata; + qbyte *pixbuf, *image_rgba, *fin, *enddata; if (loadsize < 18+3) return NULL; @@ -399,10 +399,10 @@ outofdata:; LoadLMP ============ */ -byte* LoadLMP (byte *f, int matchwidth, int matchheight) +qbyte *LoadLMP (qbyte *f, int matchwidth, int matchheight) { - byte *image_rgba; - int width, height; + qbyte *image_rgba; + int width, height; if (loadsize < 9) { @@ -457,10 +457,10 @@ void Image_StripImageExtension (char *in, char *out) strcpy(out, in); } -byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int matchheight) +qbyte *loadimagepixels (char *filename, qboolean complain, int matchwidth, int matchheight) { - byte *f, *data; - char basename[256], name[256], *c; + qbyte *f, *data; + char basename[256], name[256], *c; Image_StripImageExtension(filename, basename); // strip .tga, .pcx and .lmp extensions to allow replacement by other types // replace *'s with #, so commandline utils don't get confused when dealing with the external files for (c = basename;*c;c++) @@ -511,7 +511,7 @@ byte* loadimagepixels (char* filename, qboolean complain, int matchwidth, int ma return NULL; } -int image_makemask (byte *in, byte *out, int size) +int image_makemask (qbyte *in, qbyte *out, int size) { int i, count; count = 0; @@ -527,9 +527,9 @@ int image_makemask (byte *in, byte *out, int size) return count; } -byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, int matchheight) +qbyte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, int matchheight) { - byte *in, *data; + qbyte *in, *data; in = data = loadimagepixels(filename, complain, matchwidth, matchheight); if (!data) return NULL; @@ -544,7 +544,7 @@ byte* loadimagepixelsmask (char* filename, qboolean complain, int matchwidth, in rtexture_t *loadtextureimage (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache) { - byte *data; + qbyte *data; rtexture_t *rt; if (!(data = loadimagepixels (filename, complain, matchwidth, matchheight))) return 0; @@ -555,7 +555,7 @@ rtexture_t *loadtextureimage (rtexturepool_t *pool, char* filename, int matchwid rtexture_t *loadtextureimagemask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache) { - byte *data; + qbyte *data; rtexture_t *rt; if (!(data = loadimagepixelsmask (filename, complain, matchwidth, matchheight))) return 0; @@ -568,7 +568,7 @@ rtexture_t *image_masktex; rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int matchwidth, int matchheight, qboolean complain, qboolean mipmap, qboolean precache) { int count; - byte *data; + qbyte *data; char *filename2; rtexture_t *rt; image_masktex = NULL; @@ -587,9 +587,10 @@ rtexture_t *loadtextureimagewithmask (rtexturepool_t *pool, char* filename, int return rt; } -void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte *data) +qboolean Image_WriteTGARGB_preflipped (char *filename, int width, int height, qbyte *data) { - byte *buffer, *in, *out, *end; + qboolean ret; + qbyte *buffer, *in, *out, *end; buffer = Mem_Alloc(tempmempool, width*height*3 + 18); @@ -611,15 +612,16 @@ void Image_WriteTGARGB_preflipped (char *filename, int width, int height, byte * *out++ = in[1]; *out++ = in[0]; } - COM_WriteFile (filename, buffer, width*height*3 + 18 ); + ret = COM_WriteFile (filename, buffer, width*height*3 + 18 ); Mem_Free(buffer); + return ret; } -void Image_WriteTGARGB (char *filename, int width, int height, byte *data) +void Image_WriteTGARGB (char *filename, int width, int height, qbyte *data) { int y; - byte *buffer, *in, *out, *end; + qbyte *buffer, *in, *out, *end; buffer = Mem_Alloc(tempmempool, width*height*3 + 18); @@ -649,10 +651,10 @@ void Image_WriteTGARGB (char *filename, int width, int height, byte *data) Mem_Free(buffer); } -void Image_WriteTGARGBA (char *filename, int width, int height, byte *data) +void Image_WriteTGARGBA (char *filename, int width, int height, qbyte *data) { int y; - byte *buffer, *in, *out, *end; + qbyte *buffer, *in, *out, *end; buffer = Mem_Alloc(tempmempool, width*height*4 + 18); @@ -683,9 +685,9 @@ void Image_WriteTGARGBA (char *filename, int width, int height, byte *data) Mem_Free(buffer); } -qboolean Image_CheckAlpha(byte *data, int size, qboolean rgba) +qboolean Image_CheckAlpha(qbyte *data, int size, qboolean rgba) { - byte *end; + qbyte *end; if (rgba) { // check alpha bytes @@ -702,3 +704,484 @@ qboolean Image_CheckAlpha(byte *data, int size, qboolean rgba) } return 0; } + +static void Image_Resample32LerpLine (qbyte *in, qbyte *out, int inwidth, int outwidth) +{ + int j, xi, oldx = 0, f, fstep, endx, lerp; + fstep = (int) (inwidth*65536.0f/outwidth); + endx = (inwidth-1); + for (j = 0,f = 0;j < outwidth;j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 4; + oldx = xi; + } + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (qbyte) ((((in[4] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (qbyte) ((((in[5] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (qbyte) ((((in[6] - in[2]) * lerp) >> 16) + in[2]); + *out++ = (qbyte) ((((in[7] - in[3]) * lerp) >> 16) + in[3]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + *out++ = in[3]; + } + } +} + +static void Image_Resample24LerpLine (qbyte *in, qbyte *out, int inwidth, int outwidth) +{ + int j, xi, oldx = 0, f, fstep, endx, lerp; + fstep = (int) (inwidth*65536.0f/outwidth); + endx = (inwidth-1); + for (j = 0,f = 0;j < outwidth;j++, f += fstep) + { + xi = f >> 16; + if (xi != oldx) + { + in += (xi - oldx) * 3; + oldx = xi; + } + if (xi < endx) + { + lerp = f & 0xFFFF; + *out++ = (qbyte) ((((in[3] - in[0]) * lerp) >> 16) + in[0]); + *out++ = (qbyte) ((((in[4] - in[1]) * lerp) >> 16) + in[1]); + *out++ = (qbyte) ((((in[5] - in[2]) * lerp) >> 16) + in[2]); + } + else // last pixel of the line has no pixel to lerp to + { + *out++ = in[0]; + *out++ = in[1]; + *out++ = in[2]; + } + } +} + +int resamplerowsize = 0; +qbyte *resamplerow1 = NULL; +qbyte *resamplerow2 = NULL; +mempool_t *resamplemempool = NULL; + +#define LERPBYTE(i) r = resamplerow1[i];out[i] = (qbyte) ((((resamplerow2[i] - r) * lerp) >> 16) + r) +void Image_Resample32Lerp(void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth4 = inwidth*4, outwidth4 = outwidth*4; + qbyte *inrow, *out; + out = outdata; + fstep = (int) (inheight*65536.0f/outheight); + + inrow = indata; + oldy = 0; + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth); + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (qbyte *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth4); + else + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample32LerpLine (inrow + inwidth4, resamplerow2, inwidth, outwidth); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + LERPBYTE(12); + LERPBYTE(13); + LERPBYTE(14); + LERPBYTE(15); + out += 16; + resamplerow1 += 16; + resamplerow2 += 16; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + out += 8; + resamplerow1 += 8; + resamplerow2 += 8; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + out += 4; + resamplerow1 += 4; + resamplerow2 += 4; + } + resamplerow1 -= outwidth4; + resamplerow2 -= outwidth4; + } + else + { + if (yi != oldy) + { + inrow = (qbyte *)indata + inwidth4*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth4); + else + Image_Resample32LerpLine (inrow, resamplerow1, inwidth, outwidth); + oldy = yi; + } + memcpy(out, resamplerow1, outwidth4); + } + } +} + +void Image_Resample32Nearest(void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j; + unsigned frac, fracstep; + // relies on int being 4 bytes + int *inrow, *out; + out = outdata; + + fracstep = inwidth*0x10000/outwidth; + for (i = 0;i < outheight;i++) + { + inrow = (int *)indata + inwidth*(i*inheight/outheight); + frac = fracstep >> 1; + j = outwidth - 4; + while (j >= 0) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out[1] = inrow[frac >> 16];frac += fracstep; + out[2] = inrow[frac >> 16];frac += fracstep; + out[3] = inrow[frac >> 16];frac += fracstep; + out += 4; + j -= 4; + } + if (j & 2) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out[1] = inrow[frac >> 16];frac += fracstep; + out += 2; + } + if (j & 1) + { + out[0] = inrow[frac >> 16];frac += fracstep; + out += 1; + } + } +} + +void Image_Resample24Lerp(void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j, r, yi, oldy, f, fstep, lerp, endy = (inheight-1), inwidth3 = inwidth * 3, outwidth3 = outwidth * 3; + qbyte *inrow, *out; + out = outdata; + fstep = (int) (inheight*65536.0f/outheight); + + inrow = indata; + oldy = 0; + Image_Resample24LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample24LerpLine (inrow + inwidth3, resamplerow2, inwidth, outwidth); + for (i = 0, f = 0;i < outheight;i++,f += fstep) + { + yi = f >> 16; + if (yi < endy) + { + lerp = f & 0xFFFF; + if (yi != oldy) + { + inrow = (qbyte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth3); + else + Image_Resample24LerpLine (inrow, resamplerow1, inwidth, outwidth); + Image_Resample24LerpLine (inrow + inwidth3, resamplerow2, inwidth, outwidth); + oldy = yi; + } + j = outwidth - 4; + while(j >= 0) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + LERPBYTE( 6); + LERPBYTE( 7); + LERPBYTE( 8); + LERPBYTE( 9); + LERPBYTE(10); + LERPBYTE(11); + out += 12; + resamplerow1 += 12; + resamplerow2 += 12; + j -= 4; + } + if (j & 2) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + LERPBYTE( 3); + LERPBYTE( 4); + LERPBYTE( 5); + out += 6; + resamplerow1 += 6; + resamplerow2 += 6; + } + if (j & 1) + { + LERPBYTE( 0); + LERPBYTE( 1); + LERPBYTE( 2); + out += 3; + resamplerow1 += 3; + resamplerow2 += 3; + } + resamplerow1 -= outwidth3; + resamplerow2 -= outwidth3; + } + else + { + if (yi != oldy) + { + inrow = (qbyte *)indata + inwidth3*yi; + if (yi == oldy+1) + memcpy(resamplerow1, resamplerow2, outwidth3); + else + Image_Resample24LerpLine (inrow, resamplerow1, inwidth, outwidth); + oldy = yi; + } + memcpy(out, resamplerow1, outwidth3); + } + } +} + +void Image_Resample24Nolerp(void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight) +{ + int i, j, f, inwidth3 = inwidth * 3; + unsigned frac, fracstep; + qbyte *inrow, *out; + out = outdata; + + fracstep = inwidth*0x10000/outwidth; + for (i = 0;i < outheight;i++) + { + inrow = (qbyte *)indata + inwidth3*(i*inheight/outheight); + frac = fracstep >> 1; + j = outwidth - 4; + while (j >= 0) + { + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + j -= 4; + } + if (j & 2) + { + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + out += 2; + } + if (j & 1) + { + f = (frac >> 16)*3;*out++ = inrow[f+0];*out++ = inrow[f+1];*out++ = inrow[f+2];frac += fracstep; + out += 1; + } + } +} + +/* +================ +Image_Resample +================ +*/ +void Image_Resample (void *indata, int inwidth, int inheight, void *outdata, int outwidth, int outheight, int bytesperpixel, int quality) +{ + if (resamplerowsize < outwidth*4) + { + if (resamplerow1) + Mem_Free(resamplerow1); + resamplerowsize = outwidth*4; + if (!resamplemempool) + resamplemempool = Mem_AllocPool("Image Scaling Buffer"); + resamplerow1 = Mem_Alloc(resamplemempool, resamplerowsize*2); + resamplerow2 = resamplerow1 + resamplerowsize; + } + if (bytesperpixel == 4) + { + if (quality) + Image_Resample32Lerp(indata, inwidth, inheight, outdata, outwidth, outheight); + else + Image_Resample32Nearest(indata, inwidth, inheight, outdata, outwidth, outheight); + } + else if (bytesperpixel == 3) + { + if (quality) + Image_Resample24Lerp(indata, inwidth, inheight, outdata, outwidth, outheight); + else + Image_Resample24Nolerp(indata, inwidth, inheight, outdata, outwidth, outheight); + } + else + Sys_Error("Image_Resample: unsupported bytesperpixel %i\n", bytesperpixel); +} + +// in can be the same as out +void Image_MipReduce(qbyte *in, qbyte *out, int *width, int *height, int destwidth, int destheight, int bytesperpixel) +{ + int x, y, nextrow; + nextrow = *width * bytesperpixel; + if (*width > destwidth) + { + *width >>= 1; + if (*height > destheight) + { + // reduce both + *height >>= 1; + if (bytesperpixel == 4) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[4] + in[nextrow ] + in[nextrow+4]) >> 2); + out[1] = (qbyte) ((in[1] + in[5] + in[nextrow+1] + in[nextrow+5]) >> 2); + out[2] = (qbyte) ((in[2] + in[6] + in[nextrow+2] + in[nextrow+6]) >> 2); + out[3] = (qbyte) ((in[3] + in[7] + in[nextrow+3] + in[nextrow+7]) >> 2); + out += 4; + in += 8; + } + in += nextrow; // skip a line + } + } + else if (bytesperpixel == 3) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[3] + in[nextrow ] + in[nextrow+3]) >> 2); + out[1] = (qbyte) ((in[1] + in[4] + in[nextrow+1] + in[nextrow+4]) >> 2); + out[2] = (qbyte) ((in[2] + in[5] + in[nextrow+2] + in[nextrow+5]) >> 2); + out += 3; + in += 6; + } + in += nextrow; // skip a line + } + } + else + Sys_Error("Image_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel); + } + else + { + // reduce width + if (bytesperpixel == 4) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[4]) >> 1); + out[1] = (qbyte) ((in[1] + in[5]) >> 1); + out[2] = (qbyte) ((in[2] + in[6]) >> 1); + out[3] = (qbyte) ((in[3] + in[7]) >> 1); + out += 4; + in += 8; + } + } + } + else if (bytesperpixel == 3) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[3]) >> 1); + out[1] = (qbyte) ((in[1] + in[4]) >> 1); + out[2] = (qbyte) ((in[2] + in[5]) >> 1); + out += 3; + in += 6; + } + } + } + else + Sys_Error("Image_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel); + } + } + else + { + if (*height > destheight) + { + // reduce height + *height >>= 1; + if (bytesperpixel == 4) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[nextrow ]) >> 1); + out[1] = (qbyte) ((in[1] + in[nextrow+1]) >> 1); + out[2] = (qbyte) ((in[2] + in[nextrow+2]) >> 1); + out[3] = (qbyte) ((in[3] + in[nextrow+3]) >> 1); + out += 4; + in += 4; + } + in += nextrow; // skip a line + } + } + else if (bytesperpixel == 3) + { + for (y = 0;y < *height;y++) + { + for (x = 0;x < *width;x++) + { + out[0] = (qbyte) ((in[0] + in[nextrow ]) >> 1); + out[1] = (qbyte) ((in[1] + in[nextrow+1]) >> 1); + out[2] = (qbyte) ((in[2] + in[nextrow+2]) >> 1); + out += 3; + in += 3; + } + in += nextrow; // skip a line + } + } + else + Sys_Error("Image_MipReduce: unsupported bytesperpixel %i\n", bytesperpixel); + } + else + Sys_Error("Image_MipReduce: desired size already achieved\n"); + } +}