summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/refresh/gl/images.c225
-rw-r--r--src/refresh/images.c499
-rw-r--r--src/refresh/sw/image.c56
3 files changed, 349 insertions, 431 deletions
diff --git a/src/refresh/gl/images.c b/src/refresh/gl/images.c
index 37a08e6..bf3a712 100644
--- a/src/refresh/gl/images.c
+++ b/src/refresh/gl/images.c
@@ -233,85 +233,6 @@ void Scrap_Upload(void)
scrap_dirty = qfalse;
}
-/*
-====================================================================
-
-IMAGE FLOOD FILLING
-
-====================================================================
-*/
-
-typedef struct {
- short x, y;
-} floodfill_t;
-
-// must be a power of 2
-#define FLOODFILL_FIFO_SIZE 0x1000
-#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
-
-#define FLOODFILL_STEP(off, dx, dy) \
- do { \
- if (pos[off] == fillcolor) { \
- pos[off] = 255; \
- fifo[inpt].x = x + (dx); \
- fifo[inpt].y = y + (dy); \
- inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
- } else if (pos[off] != 255) { \
- fdc = pos[off]; \
- } \
- } while(0)
-
-/*
-=================
-Mod_FloodFillSkin
-
-Fill background pixels so mipmapping doesn't have haloes
-=================
-*/
-static void R_FloodFillSkin(byte *skin, int skinwidth, int skinheight)
-{
- byte fillcolor = *skin; // assume this is the pixel to fill
- floodfill_t fifo[FLOODFILL_FIFO_SIZE];
- int inpt = 0, outpt = 0;
- int filledcolor = -1;
- int i;
-
- if (filledcolor == -1) {
- filledcolor = 0;
- // attempt to find opaque black
- for (i = 0; i < 256; ++i)
- if (d_8to24table[i] == 255) {
- // alpha 1.0
- filledcolor = i;
- break;
- }
- }
-
- // can't fill to filled color or to transparent color
- // (used as visited marker)
- if ((fillcolor == filledcolor) || (fillcolor == 255)) {
- return;
- }
-
- fifo[inpt].x = 0, fifo[inpt].y = 0;
- inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
-
- while (outpt != inpt) {
- int x = fifo[outpt].x, y = fifo[outpt].y;
- int fdc = filledcolor;
- byte *pos = &skin[x + skinwidth * y];
-
- outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
-
- if (x > 0) FLOODFILL_STEP(-1, -1, 0);
- if (x < skinwidth - 1) FLOODFILL_STEP(1, 1, 0);
- if (y > 0) FLOODFILL_STEP(-skinwidth, 0, -1);
- if (y < skinheight - 1) FLOODFILL_STEP(skinwidth, 0, 1);
-
- skin[x + skinwidth * y] = fdc;
- }
-}
-
//=======================================================
static byte gammatable[256];
@@ -513,8 +434,15 @@ static void GL_Upload32(byte *data, int width, int height, int baselevel, imaget
scaled_width, scaled_height);
}
- // scan the texture for any non-255 alpha
- upload_alpha = GL_TextureHasAlpha(scaled, scaled_width, scaled_height);
+ if (flags & IF_TRANSPARENT) {
+ upload_alpha = qtrue;
+ } else if (flags & IF_OPAQUE) {
+ upload_alpha = qfalse;
+ } else {
+ // scan the texture for any non-255 alpha
+ upload_alpha = GL_TextureHasAlpha(scaled, scaled_width, scaled_height);
+ }
+
if (upload_alpha) {
comp = gl_tex_alpha_format;
}
@@ -546,53 +474,6 @@ static void GL_Upload32(byte *data, int width, int height, int baselevel, imaget
}
}
-/*
-===============
-GL_Unpack8
-===============
-*/
-static void GL_Unpack8(byte *output, int outpitch, const byte *input, int width, int height)
-{
- uint32_t *out;
- int x, y, p;
-
- for (y = 0; y < height; y++) {
- out = (uint32_t *)output + y * outpitch;
- for (x = 0; x < width; x++) {
- p = *input;
- if (p == 255) {
- // transparent, so scan around for another color
- // to avoid alpha fringes
- // FIXME: do a full flood fill so mips work...
- if (y > 0 && *(input - width) != 255)
- p = *(input - width);
- else if (y < height - 1 && *(input + width) != 255)
- p = *(input + width);
- else if (x > 0 && *(input - 1) != 255)
- p = *(input - 1);
- else if (x < width - 1 && *(input + 1) != 255)
- p = *(input + 1);
- else if (y > 0 && x > 0 && *(input - width - 1) != 255)
- p = *(input - width - 1);
- else if (y > 0 && x < width - 1 && *(input - width + 1) != 255)
- p = *(input - width + 1);
- else if (y < height - 1 && x > 0 && *(input + width - 1) != 255)
- p = *(input + width - 1);
- else if (y < height - 1 && x < width - 1 && *(input + width + 1) != 255)
- p = *(input + width + 1);
- else
- p = 0;
- // copy rgb components
- *out = d_8to24table[p] & U32_RGB;
- } else {
- *out = d_8to24table[p];
- }
- input++;
- out++;
- }
- }
-}
-
static int GL_UpscaleLevel(int width, int height, imagetype_t type, imageflags_t flags)
{
int maxlevel;
@@ -717,42 +598,32 @@ static void GL_SetFilterAndRepeat(imagetype_t type, imageflags_t flags)
}
}
-#define MAX_STACK_PIXELS (256 * 256)
-
/*
================
IMG_Load
================
*/
-void IMG_Load(image_t *image, byte *pic, int width, int height)
+void IMG_Load(image_t *image, byte *pic)
{
- byte stackbuf[MAX_STACK_PIXELS * 4];
- byte *buffer;
byte *src, *dst;
int i, s, t, maxlevel;
+ int width, height;
- if (!pic) {
- Com_Error(ERR_FATAL, "%s: NULL", __func__);
- }
+ width = image->upload_width;
+ height = image->upload_height;
// load small pics onto the scrap
if (image->type == IT_PIC && width < 64 && height < 64 &&
gl_noscrap->integer == 0 && Scrap_AllocBlock(width, height, &s, &t)) {
+ src = pic;
dst = &scrap_data[(t * SCRAP_BLOCK_WIDTH + s) * 4];
- if (image->flags & IF_PALETTED) {
- GL_Unpack8(dst, SCRAP_BLOCK_WIDTH, pic, width, height);
- } else {
- src = pic;
- for (i = 0; i < height; i++) {
- memcpy(dst, src, width * 4);
- src += width * 4;
- dst += SCRAP_BLOCK_WIDTH * 4;
- }
+ for (i = 0; i < height; i++) {
+ memcpy(dst, src, width * 4);
+ src += width * 4;
+ dst += SCRAP_BLOCK_WIDTH * 4;
}
image->texnum = TEXNUM_SCRAP;
- image->upload_width = width;
- image->upload_height = height;
image->flags |= IF_SCRAP | IF_TRANSPARENT;
image->sl = (s + 0.01f) / (float)SCRAP_BLOCK_WIDTH;
image->sh = (s + width - 0.01f) / (float)SCRAP_BLOCK_WIDTH;
@@ -764,49 +635,33 @@ void IMG_Load(image_t *image, byte *pic, int width, int height)
image->flags |= IF_UPSCALED;
scrap_dirty = qtrue;
- return;
- }
-
- if (image->type == IT_SKIN && (image->flags & IF_PALETTED))
- R_FloodFillSkin(pic, width, height);
-
- if (image->flags & IF_PALETTED) {
- s = width * height;
- if (s > MAX_STACK_PIXELS)
- buffer = FS_AllocTempMem(s * 4);
- else
- buffer = stackbuf;
- GL_Unpack8(buffer, width, pic, width, height);
} else {
- s = 0;
- buffer = pic;
- }
+ qglGenTextures(1, &image->texnum);
+ GL_ForceTexture(0, image->texnum);
- qglGenTextures(1, &image->texnum);
- GL_ForceTexture(0, image->texnum);
-
- maxlevel = GL_UpscaleLevel(width, height, image->type, image->flags);
- if (maxlevel) {
- GL_Upscale32(buffer, width, height, maxlevel, image->type, image->flags);
- image->flags |= IF_UPSCALED;
- } else {
- GL_Upload32(buffer, width, height, maxlevel, image->type, image->flags);
- }
+ maxlevel = GL_UpscaleLevel(width, height, image->type, image->flags);
+ if (maxlevel) {
+ GL_Upscale32(pic, width, height, maxlevel, image->type, image->flags);
+ image->flags |= IF_UPSCALED;
+ } else {
+ GL_Upload32(pic, width, height, maxlevel, image->type, image->flags);
+ }
- GL_SetFilterAndRepeat(image->type, image->flags);
+ GL_SetFilterAndRepeat(image->type, image->flags);
- if (upload_alpha) {
- image->flags |= IF_TRANSPARENT;
+ if (upload_alpha) {
+ image->flags |= IF_TRANSPARENT;
+ }
+ image->upload_width = upload_width << maxlevel; // after power of 2 and scales
+ image->upload_height = upload_height << maxlevel;
+ image->sl = 0;
+ image->sh = 1;
+ image->tl = 0;
+ image->th = 1;
}
- image->upload_width = upload_width << maxlevel; // after power of 2 and scales
- image->upload_height = upload_height << maxlevel;
- image->sl = 0;
- image->sh = 1;
- image->tl = 0;
- image->th = 1;
-
- if (s > MAX_STACK_PIXELS)
- FS_FreeTempMem(buffer);
+
+ // don't need pics in memory after GL upload
+ Z_Free(pic);
}
void IMG_Unload(image_t *image)
diff --git a/src/refresh/images.c b/src/refresh/images.c
index 2fa8579..be98ed0 100644
--- a/src/refresh/images.c
+++ b/src/refresh/images.c
@@ -32,24 +32,90 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#if USE_PNG
#define PNG_SKIP_SETJMP_CHECK
#include <png.h>
-#if USE_ZLIB
-#include <zlib.h>
-#endif
#endif // USE_PNG
#if USE_JPG
#include <jpeglib.h>
#endif
+#define R_COLORMAP_PCX "pics/colormap.pcx"
+
#define IMG_LOAD(x) \
static qerror_t IMG_Load##x(byte *rawdata, size_t rawlen, \
- const char *filename, byte **pic, int *width, int *height)
+ image_t *image, byte **pic)
#define IMG_SAVE(x) \
static qerror_t IMG_Save##x(qhandle_t f, const char *filename, \
const byte *pic, int width, int height, int param)
/*
+====================================================================
+
+IMAGE FLOOD FILLING
+
+====================================================================
+*/
+
+typedef struct {
+ short x, y;
+} floodfill_t;
+
+// must be a power of 2
+#define FLOODFILL_FIFO_SIZE 0x1000
+#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
+
+#define FLOODFILL_STEP(off, dx, dy) \
+ do { \
+ if (pos[off] == fillcolor) { \
+ pos[off] = 255; \
+ fifo[inpt].x = x + (dx); \
+ fifo[inpt].y = y + (dy); \
+ inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
+ } else if (pos[off] != 255) { \
+ fdc = pos[off]; \
+ } \
+ } while(0)
+
+/*
+=================
+IMG_FloodFill
+
+Fill background pixels so mipmapping doesn't have haloes
+=================
+*/
+static void IMG_FloodFill(byte *skin, int skinwidth, int skinheight)
+{
+ byte fillcolor = *skin; // assume this is the pixel to fill
+ floodfill_t fifo[FLOODFILL_FIFO_SIZE];
+ int inpt = 0, outpt = 0;
+ int filledcolor = 0; // FIXME: fixed black
+
+ // can't fill to filled color or to transparent color
+ // (used as visited marker)
+ if (fillcolor == filledcolor || fillcolor == 255) {
+ return;
+ }
+
+ fifo[inpt].x = 0, fifo[inpt].y = 0;
+ inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
+
+ while (outpt != inpt) {
+ int x = fifo[outpt].x, y = fifo[outpt].y;
+ int fdc = filledcolor;
+ byte *pos = &skin[x + skinwidth * y];
+
+ outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
+
+ if (x > 0) FLOODFILL_STEP(-1, -1, 0);
+ if (x < skinwidth - 1) FLOODFILL_STEP(1, 1, 0);
+ if (y > 0) FLOODFILL_STEP(-skinwidth, 0, -1);
+ if (y < skinheight - 1) FLOODFILL_STEP(skinwidth, 0, 1);
+
+ skin[x + skinwidth * y] = fdc;
+ }
+}
+
+/*
=================================================================
PCX LOADING
@@ -57,18 +123,13 @@ PCX LOADING
=================================================================
*/
-static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen,
- byte **pic, byte *palette, int *width, int *height)
+static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen, byte *pixels,
+ byte *palette, int *width, int *height)
{
byte *raw, *end;
dpcx_t *pcx;
int x, y, w, h, scan;
int dataByte, runLength;
- byte *out, *pix;
-
- if (pic) {
- *pic = NULL;
- }
//
// parse the PCX file
@@ -89,7 +150,7 @@ static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen,
w = (LittleShort(pcx->xmax) - LittleShort(pcx->xmin)) + 1;
h = (LittleShort(pcx->ymax) - LittleShort(pcx->ymin)) + 1;
- if (w > 640 || h > 480) {
+ if (w < 1 || h < 1 || w > 640 || h > 480) {
return Q_ERR_INVALID_FORMAT;
}
@@ -115,24 +176,21 @@ static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen,
//
// get pixels
//
- if (pic) {
- pix = out = IMG_AllocPixels(w * h);
-
+ if (pixels) {
raw = pcx->data;
end = (byte *)pcx + rawlen;
-
- for (y = 0; y < h; y++, pix += w) {
+ for (y = 0; y < h; y++, pixels += w) {
for (x = 0; x < scan;) {
if (raw >= end)
- goto fail;
+ return Q_ERR_BAD_RLE_PACKET;
dataByte = *raw++;
if ((dataByte & 0xC0) == 0xC0) {
runLength = dataByte & 0x3F;
if (x + runLength > scan)
- goto fail;
+ return Q_ERR_BAD_RLE_PACKET;
if (raw >= end)
- goto fail;
+ return Q_ERR_BAD_RLE_PACKET;
dataByte = *raw++;
} else {
runLength = 1;
@@ -140,13 +198,11 @@ static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen,
while (runLength--) {
if (x < w)
- pix[x] = dataByte;
+ pixels[x] = dataByte;
x++;
}
}
}
-
- *pic = out;
}
if (width)
@@ -155,15 +211,79 @@ static qerror_t _IMG_LoadPCX(byte *rawdata, size_t rawlen,
*height = h;
return Q_ERR_SUCCESS;
+}
-fail:
- IMG_FreePixels(out);
- return Q_ERR_BAD_RLE_PACKET;
+/*
+===============
+IMG_Unpack8
+===============
+*/
+static int IMG_Unpack8(uint32_t *out, const uint8_t *in, int width, int height)
+{
+ int x, y, p;
+ qboolean has_alpha = qfalse;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ p = *in;
+ if (p == 255) {
+ has_alpha = qtrue;
+ // transparent, so scan around for another color
+ // to avoid alpha fringes
+ if (y > 0 && *(in - width) != 255)
+ p = *(in - width);
+ else if (y < height - 1 && *(in + width) != 255)
+ p = *(in + width);
+ else if (x > 0 && *(in - 1) != 255)
+ p = *(in - 1);
+ else if (x < width - 1 && *(in + 1) != 255)
+ p = *(in + 1);
+ else if (y > 0 && x > 0 && *(in - width - 1) != 255)
+ p = *(in - width - 1);
+ else if (y > 0 && x < width - 1 && *(in - width + 1) != 255)
+ p = *(in - width + 1);
+ else if (y < height - 1 && x > 0 && *(in + width - 1) != 255)
+ p = *(in + width - 1);
+ else if (y < height - 1 && x < width - 1 && *(in + width + 1) != 255)
+ p = *(in + width + 1);
+ else
+ p = 0;
+ // copy rgb components
+ *out = d_8to24table[p] & U32_RGB;
+ } else {
+ *out = d_8to24table[p];
+ }
+ in++;
+ out++;
+ }
+ }
+
+ if (has_alpha)
+ return IF_PALETTED | IF_TRANSPARENT;
+
+ return IF_PALETTED | IF_OPAQUE;
}
IMG_LOAD(PCX)
{
- return _IMG_LoadPCX(rawdata, rawlen, pic, NULL, width, height);
+ byte buffer[640 * 480];
+ int w, h;
+ qerror_t ret;
+
+ ret = _IMG_LoadPCX(rawdata, rawlen, buffer, NULL, &w, &h);
+ if (ret < 0)
+ return ret;
+
+ if (image->type == IT_SKIN)
+ IMG_FloodFill(buffer, w, h);
+
+ *pic = IMG_AllocPixels(w * h * 4);
+
+ image->upload_width = image->width = w;
+ image->upload_height = image->height = h;
+ image->flags |= IMG_Unpack8((uint32_t *)*pic, buffer, w, h);
+
+ return Q_ERR_SUCCESS;
}
@@ -188,23 +308,23 @@ IMG_LOAD(WAL)
w = LittleLong(mt->width);
h = LittleLong(mt->height);
- offset = LittleLong(mt->offsets[0]);
-
if (w < 1 || h < 1 || w > 512 || h > 512) {
return Q_ERR_INVALID_FORMAT;
}
- size = MIPSIZE(w * h);
+ size = w * h;
+
+ offset = LittleLong(mt->offsets[0]);
endpos = offset + size;
if (endpos < offset || endpos > rawlen) {
return Q_ERR_BAD_EXTENT;
}
- // WAL is special, pixels are not reallocated but are
- // taken from the file directly as an optimization
- *width = w;
- *height = h;
- *pic = (byte *)mt + offset;
+ *pic = IMG_AllocPixels(size * 4);
+
+ image->upload_width = image->width = w;
+ image->upload_height = image->height = h;
+ image->flags |= IMG_Unpack8((uint32_t *)*pic, (uint8_t *)mt + offset, w, h);
return Q_ERR_SUCCESS;
}
@@ -395,8 +515,6 @@ IMG_LOAD(TGA)
tga_decode_t decode;
qerror_t ret;
- *pic = NULL;
-
if (rawlen < TARGA_HEADER_SIZE) {
return Q_ERR_FILE_TOO_SMALL;
}
@@ -416,7 +534,7 @@ IMG_LOAD(TGA)
}
if (colormap_type) {
- Com_DPrintf("%s: %s: color mapped images are not supported\n", __func__, filename);
+ Com_DPrintf("%s: %s: color mapped images are not supported\n", __func__, image->name);
return Q_ERR_INVALID_FORMAT;
}
@@ -425,12 +543,12 @@ IMG_LOAD(TGA)
} else if (pixel_size == 24) {
bpp = 3;
} else {
- Com_DPrintf("%s: %s: only 32 and 24 bit targa RGB images supported\n", __func__, filename);
+ Com_DPrintf("%s: %s: only 32 and 24 bit targa RGB images supported\n", __func__, image->name);
return Q_ERR_INVALID_FORMAT;
}
if (w < 1 || h < 1 || w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) {
- Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, filename);
+ Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, image->name);
return Q_ERR_INVALID_FORMAT;
}
@@ -450,7 +568,7 @@ IMG_LOAD(TGA)
decode = tga_decode_bgr_rle;
}
} else {
- Com_DPrintf("%s: %s: only type 2 and 10 targa RGB images supported\n", __func__, filename);
+ Com_DPrintf("%s: %s: only type 2 and 10 targa RGB images supported\n", __func__, image->name);
return Q_ERR_INVALID_FORMAT;
}
@@ -472,8 +590,12 @@ IMG_LOAD(TGA)
}
*pic = pixels;
- *width = w;
- *height = h;
+
+ image->upload_width = image->width = w;
+ image->upload_height = image->height = h;
+
+ if (pixel_size == 24)
+ image->flags |= IF_OPAQUE;
return Q_ERR_SUCCESS;
}
@@ -607,12 +729,10 @@ IMG_LOAD(JPG)
int i;
qerror_t ret;
- *pic = NULL;
-
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
jerr.pub.output_message = my_output_message;
- jerr.filename = filename;
+ jerr.filename = image->name;
jerr.error = Q_ERR_FAILURE;
if (setjmp(jerr.setjmp_buffer)) {
@@ -626,7 +746,7 @@ IMG_LOAD(JPG)
jpeg_read_header(&cinfo, TRUE);
if (cinfo.out_color_space != JCS_RGB && cinfo.out_color_space != JCS_GRAYSCALE) {
- Com_DPrintf("%s: %s: invalid image color space\n", __func__, filename);
+ Com_DPrintf("%s: %s: invalid image color space\n", __func__, image->name);
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
@@ -634,13 +754,13 @@ IMG_LOAD(JPG)
jpeg_start_decompress(&cinfo);
if (cinfo.output_components != 3 && cinfo.output_components != 1) {
- Com_DPrintf("%s: %s: invalid number of color components\n", __func__, filename);
+ Com_DPrintf("%s: %s: invalid number of color components\n", __func__, image->name);
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
if (cinfo.output_width > MAX_TEXTURE_SIZE || cinfo.output_height > MAX_TEXTURE_SIZE) {
- Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, filename);
+ Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, image->name);
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
@@ -678,8 +798,9 @@ IMG_LOAD(JPG)
}
}
- *width = cinfo.output_width;
- *height = cinfo.output_height;
+ image->upload_width = image->width = cinfo.output_width;
+ image->upload_height = image->height = cinfo.output_height;
+ image->flags |= IF_OPAQUE;
jpeg_finish_decompress(&cinfo);
@@ -878,7 +999,7 @@ IMG_LOAD(PNG)
{
byte *pixels;
png_bytep row_pointers[MAX_TEXTURE_SIZE];
- png_uint_32 w, h, rowbytes, row;
+ png_uint_32 w, h, rowbytes, row, has_tRNS;
int bitdepth, colortype;
png_structp png_ptr;
png_infop info_ptr;
@@ -886,9 +1007,7 @@ IMG_LOAD(PNG)
my_png_error my_err;
qerror_t ret;
- *pic = NULL;
-
- my_err.filename = filename;
+ my_err.filename = image->name;
my_err.error = Q_ERR_LIBRARY_ERROR;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
@@ -920,7 +1039,7 @@ IMG_LOAD(PNG)
}
if (w > MAX_TEXTURE_SIZE || h > MAX_TEXTURE_SIZE) {
- Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, filename);
+ Com_DPrintf("%s: %s: invalid image dimensions\n", __func__, image->name);
ret = Q_ERR_INVALID_FORMAT;
goto fail;
}
@@ -945,7 +1064,8 @@ IMG_LOAD(PNG)
png_set_strip_16(png_ptr);
}
- if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
+ has_tRNS = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
+ if (has_tRNS) {
png_set_tRNS_to_alpha(png_ptr);
}
@@ -973,8 +1093,16 @@ IMG_LOAD(PNG)
png_read_end(png_ptr, info_ptr);
*pic = pixels;
- *width = w;
- *height = h;
+
+ image->upload_width = image->width = w;
+ image->upload_height = image->height = h;
+
+ if (colortype == PNG_COLOR_TYPE_PALETTE)
+ image->flags |= IF_PALETTED;
+
+ if (has_tRNS == 0)
+ image->flags |= IF_OPAQUE;
+
ret = Q_ERR_SUCCESS;
fail:
@@ -994,7 +1122,9 @@ static void my_png_write_fn(png_structp png_ptr, png_bytep buf, png_size_t size)
}
}
-static void my_png_flush_fn(png_structp png_ptr) { }
+static void my_png_flush_fn(png_structp png_ptr)
+{
+}
IMG_SAVE(PNG)
{
@@ -1031,10 +1161,7 @@ IMG_SAVE(PNG)
png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGB,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
-#if USE_ZLIB
- png_set_compression_level(png_ptr,
- clamp(param, Z_NO_COMPRESSION, Z_BEST_COMPRESSION));
-#endif
+ png_set_compression_level(png_ptr, clamp(param, 0, 9));
row_pointers = FS_AllocTempMem(sizeof(png_bytep) * height);
row_stride = width * 3;
@@ -1081,7 +1208,7 @@ static cvar_t *r_screenshot_quality;
static cvar_t *r_screenshot_compression;
#endif
-#if USE_TGA || USE_JPG || USE_PNG || USE_REF == REF_SOFT
+#if USE_TGA || USE_JPG || USE_PNG
static qhandle_t create_screenshot(char *buffer, size_t size,
const char *name, const char *ext)
{
@@ -1140,7 +1267,7 @@ static void make_screenshot(const char *name, const char *ext,
Com_Printf("Wrote %s\n", buffer);
}
}
-#endif // USE_TGA || USE_JPG || USE_PNG || USE_REF == REF_SOFT
+#endif // USE_TGA || USE_JPG || USE_PNG
/*
==================
@@ -1333,11 +1460,6 @@ IMAGE MANAGER
#define RIMAGES_HASH 256
-typedef struct {
- char ext[4];
- qerror_t (*load)(byte *, size_t, const char *, byte **, int *, int *);
-} imageloader_t;
-
static list_t r_imageHash[RIMAGES_HASH];
image_t r_images[MAX_RIMAGES];
@@ -1345,7 +1467,10 @@ int r_numImages;
uint32_t d_8to24table[256];
-static const imageloader_t img_loaders[IM_MAX] = {
+static const struct {
+ char ext[4];
+ qerror_t (*load)(byte *, size_t, image_t *, byte **);
+} img_loaders[IM_MAX] = {
{ "pcx", IMG_LoadPCX },
{ "wal", IMG_LoadWAL },
#if USE_TGA
@@ -1446,98 +1571,79 @@ static image_t *lookup_image(const char *name,
return NULL;
}
-static imageformat_t try_image_format(const imageloader_t *ldr,
- const char *filename, byte **pic,
- byte **tmp, int *width, int *height)
+static int _try_image_format(imageformat_t fmt, image_t *image, byte **pic)
{
- byte *data;
- ssize_t len;
- qerror_t ret;
+ byte *data;
+ ssize_t len;
+ qerror_t ret;
// load the file
- len = FS_LoadFile(filename, (void **)&data);
+ len = FS_LoadFile(image->name, (void **)&data);
if (!data) {
return len;
}
// decompress the image
- ret = ldr->load(data, len, filename, pic, width, height);
- if (ret < 0) {
- FS_FreeFile(data);
- return ret;
- }
+ ret = img_loaders[fmt].load(data, len, image, pic);
- // TODO: guess real image format on file contents
- ret = ldr - img_loaders;
+ FS_FreeFile(data);
- // unless this is a WAL texture, raw image data is
- // no longer needed, free it now
- if (ret != IM_WAL) {
- FS_FreeFile(data);
- *tmp = NULL;
- } else {
- *tmp = data;
- }
+ return ret < 0 ? ret : fmt;
+}
- return ret;
+static int try_image_format(imageformat_t fmt, image_t *image, byte **pic)
+{
+ // replace the extension
+ memcpy(image->name + image->baselen + 1, img_loaders[fmt].ext, 4);
+ return _try_image_format(fmt, image, pic);
}
+
#if USE_PNG || USE_JPG || USE_TGA
// tries to load the image with a different extension
-static qerror_t try_other_formats(imageformat_t orig, imagetype_t type,
- char *buffer, char *ext, byte **pic,
- byte **tmp, int *width, int *height)
+static int try_other_formats(imageformat_t orig, image_t *image, byte **pic)
{
- const imageloader_t *ldr;
- imageformat_t fmt;
- qerror_t ret;
- int i;
+ imageformat_t fmt;
+ qerror_t ret;
+ int i;
// search through all the 32-bit formats
for (i = 0; i < img_total; i++) {
fmt = img_search[i];
if (fmt == orig) {
- // don't retry twice
- continue;
+ continue; // don't retry twice
}
- // replace the extension
- ldr = &img_loaders[fmt];
- memcpy(ext, ldr->ext, 4);
-
- ret = try_image_format(ldr, buffer, pic, tmp, width, height);
+ ret = try_image_format(fmt, image, pic);
if (ret != Q_ERR_NOENT) {
- // found something
- return ret;
+ return ret; // found something
}
}
// fall back to 8-bit formats
- fmt = type == IT_WALL ? IM_WAL : IM_PCX;
+ fmt = (image->type == IT_WALL) ? IM_WAL : IM_PCX;
if (fmt == orig) {
- // don't retry twice
- return Q_ERR_NOENT;
+ return Q_ERR_NOENT; // don't retry twice
}
- ldr = &img_loaders[fmt];
- memcpy(ext, ldr->ext, 4);
-
- return try_image_format(ldr, buffer, pic, tmp, width, height);
+ return try_image_format(fmt, image, pic);
}
-static void get_image_dimensions(image_t *image,
- imageformat_t fmt, char *buffer, char *ext)
+static void get_image_dimensions(imageformat_t fmt, image_t *image)
{
- ssize_t len;
- miptex_t mt;
- dpcx_t pcx;
- qhandle_t f;
- unsigned w, h;
+ char buffer[MAX_QPATH];
+ ssize_t len;
+ miptex_t mt;
+ dpcx_t pcx;
+ qhandle_t f;
+ unsigned w, h;
+
+ memcpy(buffer, image->name, image->baselen + 1);
w = h = 0;
if (fmt == IM_WAL) {
- memcpy(ext, "wal", 4);
+ memcpy(buffer + image->baselen + 1, "wal", 4);
FS_FOpenFile(buffer, &f, FS_MODE_READ);
if (f) {
len = FS_Read(&mt, sizeof(mt), f);
@@ -1548,7 +1654,7 @@ static void get_image_dimensions(image_t *image,
FS_FCloseFile(f);
}
} else {
- memcpy(ext, "pcx", 4);
+ memcpy(buffer + image->baselen + 1, "pcx", 4);
FS_FOpenFile(buffer, &f, FS_MODE_READ);
if (f) {
len = FS_Read(&pcx, sizeof(pcx), f);
@@ -1571,7 +1677,7 @@ static void get_image_dimensions(image_t *image,
static void r_texture_formats_changed(cvar_t *self)
{
char *s;
- int i;
+ int i, j;
// reset the search order
img_total = 0;
@@ -1591,6 +1697,13 @@ static void r_texture_formats_changed(cvar_t *self)
default: continue;
}
+ // don't let format to be specified more than once
+ for (j = 0; j < img_total; j++)
+ if (img_search[j] == i)
+ break;
+ if (j != img_total)
+ continue;
+
img_search[img_total++] = i;
if (img_total == IM_MAX) {
break;
@@ -1605,14 +1718,11 @@ static qerror_t find_or_load_image(const char *name, size_t len,
imagetype_t type, imageflags_t flags,
image_t **image_p)
{
- image_t *image;
- byte *pic, *tmp;
- int width, height;
- char buffer[MAX_QPATH], *ext;
- unsigned hash;
- const imageloader_t *ldr;
- imageformat_t fmt;
- qerror_t ret;
+ image_t *image;
+ byte *pic;
+ unsigned hash;
+ imageformat_t fmt;
+ qerror_t ret;
*image_p = NULL;
@@ -1634,99 +1744,73 @@ static qerror_t find_or_load_image(const char *name, size_t len,
return Q_ERR_SUCCESS;
}
- // copy filename off
- memcpy(buffer, name, len + 1);
- ext = buffer + len - 3;
+ // allocate image slot
+ image = alloc_image();
+ if (!image) {
+ return Q_ERR_OUT_OF_SLOTS;
+ }
+
+ // fill in some basic info
+ memcpy(image->name, name, len + 1);
+ image->baselen = len - 4;
+ image->type = type;
+ image->flags = flags;
+ image->registration_sequence = registration_sequence;
// find out original extension
for (fmt = 0; fmt < IM_MAX; fmt++) {
- ldr = &img_loaders[fmt];
- if (!Q_stricmp(ext, ldr->ext)) {
+ if (!Q_stricmp(image->name + image->baselen + 1, img_loaders[fmt].ext)) {
break;
}
}
// load the pic from disk
- pic = tmp = NULL;
+ pic = NULL;
+
#if USE_PNG || USE_JPG || USE_TGA
if (fmt == IM_MAX) {
// unknown extension, but give it a chance to load anyway
- ret = try_other_formats(IM_MAX, type,
- buffer, ext, &pic, &tmp, &width, &height);
+ ret = try_other_formats(IM_MAX, image, &pic);
if (ret == Q_ERR_NOENT) {
// not found, change error to invalid path
ret = Q_ERR_INVALID_PATH;
}
} else if (r_override_textures->integer) {
// forcibly replace the extension
- ret = try_other_formats(IM_MAX, type,
- buffer, ext, &pic, &tmp, &width, &height);
+ ret = try_other_formats(IM_MAX, image, &pic);
} else {
// first try with original extension
- ret = try_image_format(ldr, buffer, &pic, &tmp, &width, &height);
+ ret = _try_image_format(fmt, image, &pic);
if (ret == Q_ERR_NOENT) {
// retry with remaining extensions
- ret = try_other_formats(fmt, type,
- buffer, ext, &pic, &tmp, &width, &height);
+ ret = try_other_formats(fmt, image, &pic);
}
}
+
+ // if we are replacing 8-bit texture with a higher resolution 32-bit
+ // texture, we need to recover original image dimensions
+ if (fmt <= IM_WAL && ret > IM_WAL) {
+ get_image_dimensions(fmt, image);
+ }
#else
if (fmt == IM_MAX) {
- return Q_ERR_INVALID_PATH;
+ ret = Q_ERR_INVALID_PATH;
+ } else {
+ ret = _try_image_format(fmt, image, &pic);
}
- ret = try_image_format(ldr, buffer, &pic, &tmp, &width, &height);
#endif
if (ret < 0) {
+ memset(image, 0, sizeof(*image));
return ret;
}
- // allocate image slot
- image = alloc_image();
- if (!image) {
- FS_FreeFile(tmp ? tmp : pic);
- return Q_ERR_OUT_OF_SLOTS;
- }
-
- // fill in some basic info
- memcpy(image->name, buffer, len + 1);
- image->baselen = len - 4;
- image->type = type;
- image->flags = flags;
- image->width = width;
- image->height = height;
- image->registration_sequence = registration_sequence;
-
List_Append(&r_imageHash[hash], &image->entry);
- if (ret <= IM_WAL) {
- image->flags |= IF_PALETTED;
- }
-
-#if USE_PNG || USE_JPG || USE_TGA
- // if we are replacing 8-bit texture with a higher resolution 32-bit
- // texture, we need to recover original image dimensions for proper
- // texture alignment
- if (fmt <= IM_WAL && ret > IM_WAL) {
- get_image_dimensions(image, fmt, buffer, ext);
- }
-#endif
-
- // upload the image to card
- IMG_Load(image, pic, width, height);
-
-#if USE_REF == REF_GL
- // don't need pics in memory after GL upload
- if (!tmp) {
- tmp = pic;
- }
-#endif
-
- // free any temp memory still remaining
- FS_FreeFile(tmp);
+ // upload the image
+ IMG_Load(image, pic);
*image_p = image;
-
return Q_ERR_SUCCESS;
}
@@ -1781,10 +1865,10 @@ R_RegisterImage
qhandle_t R_RegisterImage(const char *name, imagetype_t type,
imageflags_t flags, qerror_t *err_p)
{
- image_t *image;
- char fullname[MAX_QPATH];
- size_t len;
- qerror_t err;
+ image_t *image;
+ char fullname[MAX_QPATH];
+ size_t len;
+ qerror_t err;
// empty names are legal, silently ignore them
if (!*name) {
@@ -1795,8 +1879,9 @@ qhandle_t R_RegisterImage(const char *name, imagetype_t type,
// no images = not initialized
if (!r_numImages) {
- err = Q_ERR_AGAIN;
- goto fail;
+ if (err_p)
+ *err_p = Q_ERR_AGAIN;
+ return 0;
}
if (type == IT_SKIN) {
@@ -1830,7 +1915,7 @@ fail:
if (err_p)
*err_p = err;
else if (err != Q_ERR_NOENT)
- Com_EPrintf("Couldn't load %s: %s\n", name, Q_ErrorString(err));
+ Com_EPrintf("Couldn't load %s: %s\n", fullname, Q_ErrorString(err));
return 0;
}
@@ -1929,14 +2014,13 @@ R_GetPalette
*/
void IMG_GetPalette(void)
{
- static const char colormap[] = "pics/colormap.pcx";
- byte pal[768], *src, *data;
- qerror_t ret;
- ssize_t len;
- int i;
+ byte pal[768], *src, *data;
+ qerror_t ret;
+ ssize_t len;
+ int i;
// get the palette
- len = FS_LoadFile(colormap, (void **)&data);
+ len = FS_LoadFile(R_COLORMAP_PCX, (void **)&data);
if (!data) {
ret = len;
goto fail;
@@ -1959,7 +2043,7 @@ void IMG_GetPalette(void)
return;
fail:
- Com_Error(ERR_FATAL, "Couldn't load %s: %s", colormap, Q_ErrorString(ret));
+ Com_Error(ERR_FATAL, "Couldn't load %s: %s", R_COLORMAP_PCX, Q_ErrorString(ret));
}
static const cmdreg_t img_cmd[] = {
@@ -2031,4 +2115,3 @@ void IMG_Shutdown(void)
Cmd_Deregister(img_cmd);
r_numImages = 0;
}
-
diff --git a/src/refresh/sw/image.c b/src/refresh/sw/image.c
index 29a3a80..6757542 100644
--- a/src/refresh/sw/image.c
+++ b/src/refresh/sw/image.c
@@ -51,48 +51,23 @@ static void R_LightScaleTexture(byte *in, int inwidth, int inheight)
IMG_Load
================
*/
-void IMG_Load(image_t *image, byte *pic, int width, int height)
+void IMG_Load(image_t *image, byte *pic)
{
- int i, c, b;
+ int i, c, b;
+ int width, height;
+
+ width = image->upload_width;
+ height = image->upload_height;
if (image->flags & IF_TURBULENT) {
image->width = TURB_SIZE;
image->height = TURB_SIZE;
}
- image->upload_width = width;
- image->upload_height = height;
-
b = image->width * image->height;
c = width * height;
- if (image->flags & IF_PALETTED) {
- if (image->type == IT_WALL) {
- image->pixels[0] = R_Malloc(MIPSIZE(c) * TEX_BYTES);
- image->pixels[1] = image->pixels[0] + c * TEX_BYTES;
- image->pixels[2] = image->pixels[1] + c * TEX_BYTES / 4;
- image->pixels[3] = image->pixels[2] + c * TEX_BYTES / 16;
-
- for (i = 0; i < MIPSIZE(c); i++) {
- ((uint32_t *)image->pixels[0])[i] = d_8to24table[pic[i]];
- }
-
- if (!(r_config.flags & QVF_GAMMARAMP))
- R_LightScaleTexture(image->pixels[0], MIPSIZE(c), 1);
- } else {
- image->pixels[0] = R_Malloc(c * TEX_BYTES);
- for (i = 0; i < c; i++) {
- ((uint32_t *)image->pixels[0])[i] = d_8to24table[pic[i]];
- if (pic[i] == 255) {
- image->flags |= IF_TRANSPARENT;
- }
- }
- Z_Free(pic);
- }
- } else if (image->type == IT_WALL) {
- image->upload_width = image->width;
- image->upload_height = image->height;
-
+ if (image->type == IT_WALL) {
image->pixels[0] = R_Malloc(MIPSIZE(b) * TEX_BYTES);
image->pixels[1] = image->pixels[0] + b * TEX_BYTES;
image->pixels[2] = image->pixels[1] + b * TEX_BYTES / 4;
@@ -101,10 +76,13 @@ void IMG_Load(image_t *image, byte *pic, int width, int height)
if (!(r_config.flags & QVF_GAMMARAMP))
R_LightScaleTexture(pic, width, height);
- if (width == image->width && height == image->height)
+ if (width == image->width && height == image->height) {
memcpy(image->pixels[0], pic, width * height * TEX_BYTES);
- else
+ } else {
IMG_ResampleTexture(pic, width, height, image->pixels[0], image->width, image->height);
+ image->upload_width = image->width;
+ image->upload_height = image->height;
+ }
IMG_MipMap(image->pixels[1], image->pixels[0], image->width >> 0, image->height >> 0);
IMG_MipMap(image->pixels[2], image->pixels[1], image->width >> 1, image->height >> 1);
@@ -114,10 +92,12 @@ void IMG_Load(image_t *image, byte *pic, int width, int height)
} else {
image->pixels[0] = pic;
- for (i = 0; i < c; i++) {
- b = pic[i * TEX_BYTES + 3];
- if (b != 255) {
- image->flags |= IF_TRANSPARENT;
+ if (!(image->flags & IF_OPAQUE)) {
+ for (i = 0; i < c; i++) {
+ b = pic[i * TEX_BYTES + 3];
+ if (b != 255) {
+ image->flags |= IF_TRANSPARENT;
+ }
}
}
}