From a1af6b9134f95dbe34a051ced8571e7670bdc68c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 18:22:23 -0300 Subject: [PATCH 01/27] Picture formats test --- src/CMakeLists.txt | 4 +- src/Makefile | 2 +- src/dehacked.c | 2 +- src/hardware/hw_cache.c | 2 +- src/hardware/hw_main.c | 2 +- src/lua_infolib.c | 2 +- src/p_setup.c | 12 +- src/r_data.c | 2 +- src/{r_patch.c => r_picformats.c} | 940 ++++++++++++++++--------- src/{r_patch.h => r_picformats.h} | 59 +- src/r_things.c | 2 +- src/r_things.h | 2 +- src/sdl/Srb2SDL-vc10.vcxproj | 4 +- src/sdl/Srb2SDL-vc10.vcxproj.filters | 4 +- src/win32/Srb2win-vc10.vcxproj | 4 +- src/win32/Srb2win-vc10.vcxproj.filters | 4 +- src/z_zone.c | 2 +- 17 files changed, 703 insertions(+), 346 deletions(-) rename src/{r_patch.c => r_picformats.c} (67%) rename src/{r_patch.h => r_picformats.h} (62%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e8c9c3182..7a6e7871a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,7 +123,7 @@ set(SRB2_CORE_RENDER_SOURCES r_sky.c r_splats.c r_things.c - r_patch.c + r_picformats.c r_portal.c r_bsp.h @@ -138,7 +138,7 @@ set(SRB2_CORE_RENDER_SOURCES r_splats.h r_state.h r_things.h - r_patch.h + r_picformats.h r_portal.h ) diff --git a/src/Makefile b/src/Makefile index c30c236de..282ff8f4f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -471,7 +471,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_sky.o \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ - $(OBJDIR)/r_patch.o \ + $(OBJDIR)/r_picformats.o \ $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ $(OBJDIR)/v_video.o \ diff --git a/src/dehacked.c b/src/dehacked.c index 78be8b0b3..81690cde9 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -29,7 +29,7 @@ #include "p_setup.h" #include "r_data.h" #include "r_draw.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_sky.h" #include "fastcmp.h" #include "lua_script.h" diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index c47833187..90310a92f 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -30,7 +30,7 @@ #include "../z_zone.h" #include "../v_video.h" #include "../r_draw.h" -#include "../r_patch.h" +#include "../r_picformats.h" #include "../p_setup.h" // Values set after a call to HWR_ResizeBlock() diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index e8d16c092..23e52d19b 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -30,7 +30,7 @@ #include "../p_local.h" #include "../p_setup.h" #include "../r_local.h" -#include "../r_patch.h" +#include "../r_picformats.h" #include "../r_bsp.h" #include "../d_clisrv.h" #include "../w_wad.h" diff --git a/src/lua_infolib.c b/src/lua_infolib.c index b617a7a14..39c385102 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -18,7 +18,7 @@ #include "p_mobj.h" #include "p_local.h" #include "z_zone.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_things.h" #include "doomstat.h" // luabanks[] diff --git a/src/p_setup.c b/src/p_setup.c index 42a6438a0..eca5413b4 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -28,7 +28,7 @@ #include "r_data.h" #include "r_things.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_sky.h" #include "r_draw.h" @@ -574,6 +574,8 @@ Ploadflat (levelflat_t *levelflat, const char *flatname) lumpnum_t flatnum; int texturenum; + patch_t *flatpatch; + size_t lumplength; size_t i; @@ -635,7 +637,9 @@ texturefound: { flatfound: /* This could be a flat, patch, or PNG. */ - if (R_CheckIfPatch(flatnum)) + flatpatch = W_CacheLumpNum(flatnum, PU_STATIC); + lumplength = W_LumpLength(flatnum); + if (R_CheckIfPatch(flatpatch, lumplength)) levelflat->type = LEVELFLAT_PATCH; else { @@ -644,8 +648,10 @@ flatfound: Only need eight bytes for PNG headers. FIXME: Put this elsewhere. */ + if (flatpatch) + Z_Free(flatpatch); W_ReadLumpHeader(flatnum, buffer, 8, 0); - if (R_IsLumpPNG(buffer, W_LumpLength(flatnum))) + if (R_IsLumpPNG(buffer, lumplength)) levelflat->type = LEVELFLAT_PNG; else #endif/*NO_PNG_LUMPS*/ diff --git a/src/r_data.c b/src/r_data.c index 986b65dea..14c04f15e 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -19,7 +19,7 @@ #include "p_local.h" #include "m_misc.h" #include "r_data.h" -#include "r_patch.h" +#include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" #include "p_setup.h" // levelflats diff --git a/src/r_patch.c b/src/r_picformats.c similarity index 67% rename from src/r_patch.c rename to src/r_picformats.c index 18dfe523a..8e229c4a6 100644 --- a/src/r_patch.c +++ b/src/r_picformats.c @@ -2,23 +2,24 @@ //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. // Copyright (C) 2005-2009 by Andrey "entryway" Budko. -// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos. -// Copyright (C) 2019 by Sonic Team Junior. +// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos. +// Copyright (C) 2019-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file r_patch.c -/// \brief Patch generation. +/// \file r_picformats.c +/// \brief Picture generation. #include "byteptr.h" #include "dehacked.h" #include "i_video.h" #include "r_data.h" #include "r_draw.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_things.h" +#include "v_video.h" #include "z_zone.h" #include "w_wad.h" @@ -52,29 +53,549 @@ static unsigned char imgbuf[1<<26]; fixed_t cosang2rad[ROTANGLES]; fixed_t sinang2rad[ROTANGLES]; -// -// R_CheckIfPatch -// -// Returns true if the lump is a valid patch. -// -boolean R_CheckIfPatch(lumpnum_t lump) +/** Converts a picture between two formats. + * + * \param informat Input picture format. + * \param picture Input picture data. + * \param outformat Output picture format. + * \param insize Input picture size. + * \param outsize Output picture size. + * \param inwidth Input picture width. + * \param inheight Input picture height. + * \param inleftoffset Input picture left offset, for patches. + * \param intopoffset Input picture top offset, for patches. + * \param flags Input picture flags. + * \return A pointer to the converted picture. + */ +void *Picture_Convert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT32 inwidth, INT32 inheight, INT32 inleftoffset, INT32 intopoffset, + pictureflags_t flags) { - size_t size; - INT16 width, height; - patch_t *patch; - boolean result; + if (informat == outformat) // wut? + I_Error("Picture_Convert: input and output formats are the same!"); - size = W_LumpLength(lump); + if (Picture_IsPatchFormat(outformat)) + return Picture_PatchConvert(informat, picture, outformat, insize, outsize, inwidth, inheight, inleftoffset, intopoffset, flags); + else if (Picture_IsFlatFormat(outformat)) + return Picture_FlatConvert(informat, picture, outformat, insize, outsize, inwidth, inheight, inleftoffset, intopoffset, flags); + else + I_Error("Picture_Convert: unsupported input format!"); + + return NULL; +} + +/** Converts a picture to a patch. + * + * \param informat Input picture format. + * \param picture Input picture data. + * \param outformat Output picture format. + * \param insize Input picture size. + * \param outsize Output picture size. + * \param inwidth Input picture width. + * \param inheight Input picture height. + * \param inleftoffset Input picture left offset, for patches. + * \param intopoffset Input picture top offset, for patches. + * \param flags Input picture flags. + * \return A pointer to the converted picture. + */ +void *Picture_PatchConvert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset, + pictureflags_t flags) +{ + UINT32 x, y; + UINT8 *img; + UINT8 *imgptr = imgbuf; + UINT8 *colpointers, *startofspan; + size_t size = 0; + patch_t *inpatch = NULL; + INT32 inbpp = Picture_FormatBPP(informat); + + if (informat == outformat) + I_Error("Picture_PatchConvert: input and output formats are the same!"); + + if (!inbpp) + I_Error("Picture_PatchConvert: unknown input bits per pixel?!"); + + (void)insize; // ignore + + // If it's a patch, you can just figure out + // the dimensions from the header. + if (Picture_IsPatchFormat(informat)) + { + inpatch = (patch_t *)picture; + inwidth = SHORT(inpatch->width); + inheight = SHORT(inpatch->height); + inleftoffset = SHORT(inpatch->leftoffset); + intopoffset = SHORT(inpatch->topoffset); + } + + // Write image size and offset + WRITEINT16(imgptr, inwidth); + WRITEINT16(imgptr, inheight); + WRITEINT16(imgptr, inleftoffset); + WRITEINT16(imgptr, intopoffset); + + // Leave placeholder to column pointers + colpointers = imgptr; + imgptr += inwidth*4; + + // Write columns + for (x = 0; x < inwidth; x++) + { + int lastStartY = 0; + int spanSize = 0; + startofspan = NULL; + + // Write column pointer + WRITEINT32(colpointers, imgptr - imgbuf); + + // Write pixels + for (y = 0; y < inheight; y++) + { + void *input = NULL; + boolean opaque = false; + + // Read pixel + if (Picture_IsPatchFormat(informat)) + input = Picture_GetPatchPixel(inpatch, informat, x, y, flags); + else if (Picture_IsFlatFormat(informat)) + { + size_t offs = ((y * inwidth) + x); + switch (informat) + { + case PICFMT_FLAT32: + input = picture + (offs * 4); + break; + case PICFMT_FLAT16: + input = picture + (offs * 2); + break; + case PICFMT_FLAT: + input = picture + offs; + break; + default: + I_Error("Picture_PatchConvert: unsupported flat input format!"); + break; + } + } + else + I_Error("Picture_PatchConvert: unsupported input format!"); + + // Determine opacity + if (input != NULL) + { + UINT8 alpha = 0xFF; + if (inbpp == 32) + { + RGBA_t px = *(RGBA_t *)input; + alpha = px.s.alpha; + } + else if (inbpp == 16) + { + UINT16 px = *(UINT16 *)input; + alpha = (px & 0xFF00) >> 8; + } + else if (inbpp == 8) + { + UINT8 px = *(UINT8 *)input; + if (px == TRANSPARENTPIXEL) + alpha = 0; + } + opaque = (alpha > 1); + } + + // End span if we have a transparent pixel + if (!opaque) + { + if (startofspan) + WRITEUINT8(imgptr, 0); + startofspan = NULL; + continue; + } + + // Start new column if we need to + if (!startofspan || spanSize == 255) + { + int writeY = y; + + // If we reached the span size limit, finish the previous span + if (startofspan) + WRITEUINT8(imgptr, 0); + + if (y > 254) + { + // Make sure we're aligned to 254 + if (lastStartY < 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + lastStartY = 254; + } + + // Write stopgap empty spans if needed + writeY = y - lastStartY; + + while (writeY > 254) + { + WRITEUINT8(imgptr, 254); + WRITEUINT8(imgptr, 0); + imgptr += 2; + writeY -= 254; + } + } + + startofspan = imgptr; + WRITEUINT8(imgptr, writeY); + imgptr += 2; + spanSize = 0; + + lastStartY = y; + } + + // Write the pixel + switch (outformat) + { + case PICFMT_PATCH32: + { + if (inbpp == 32) + { + RGBA_t out = *(RGBA_t *)input; + WRITEUINT32(imgptr, out.rgba); + } + else if (inbpp == 16) + { + RGBA_t out = pMasterPalette[*((UINT16 *)input) & 0xFF]; + WRITEUINT32(imgptr, out.rgba); + } + else // PICFMT_PATCH + { + RGBA_t out = pMasterPalette[*((UINT8 *)input) & 0xFF]; + WRITEUINT32(imgptr, out.rgba); + } + break; + } + case PICFMT_PATCH16: + if (inbpp == 32) + { + RGBA_t in = *(RGBA_t *)input; + UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); + WRITEUINT16(imgptr, (0xFF00 | out)); + } + else if (inbpp == 16) + WRITEUINT16(imgptr, *(UINT16 *)input); + else // PICFMT_PATCH + WRITEUINT16(imgptr, (0xFF00 | (*(UINT8 *)input))); + break; + default: // PICFMT_PATCH + { + if (inbpp == 32) + { + RGBA_t in = *(RGBA_t *)input; + UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); + WRITEUINT8(imgptr, out); + } + else if (inbpp == 16) + { + UINT16 out = *(UINT16 *)input; + WRITEUINT8(imgptr, (out & 0xFF)); + } + else // PICFMT_PATCH + WRITEUINT8(imgptr, *(UINT8 *)input); + break; + } + } + + spanSize++; + startofspan[1] = spanSize; + } + + if (startofspan) + WRITEUINT8(imgptr, 0); + + WRITEUINT8(imgptr, 0xFF); + } + + size = imgptr-imgbuf; + img = Z_Malloc(size, PU_STATIC, NULL); + memcpy(img, imgbuf, size); + + if (outsize != NULL) + *outsize = size; + return img; +} + +/** Converts a picture to a flat. + * + * \param informat Input picture format. + * \param picture Input picture data. + * \param outformat Output picture format. + * \param insize Input picture size. + * \param outsize Output picture size. + * \param inwidth Input picture width. + * \param inheight Input picture height. + * \param inleftoffset Input picture left offset, for patches. + * \param intopoffset Input picture top offset, for patches. + * \param flags Input picture flags. + * \return A pointer to the converted picture. + */ +void *Picture_FlatConvert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset, + pictureflags_t flags) +{ + void *outflat; + patch_t *inpatch = NULL; + INT32 inbpp = Picture_FormatBPP(informat); + INT32 outbpp = Picture_FormatBPP(outformat); + INT32 x, y; + size_t size; + + if (informat == outformat) + I_Error("Picture_FlatConvert: input and output formats are the same!"); + + if (!inbpp) + I_Error("Picture_FlatConvert: unknown input bits per pixel?!"); + if (!outbpp) + I_Error("Picture_FlatConvert: unknown output bits per pixel?!"); + + // If it's a patch, you can just figure out + // the dimensions from the header. + if (Picture_IsPatchFormat(informat)) + { + inpatch = (patch_t *)picture; + inwidth = SHORT(inpatch->width); + inheight = SHORT(inpatch->height); + inleftoffset = SHORT(inpatch->leftoffset); + intopoffset = SHORT(inpatch->topoffset); + } + + size = (inwidth * inheight) * (outbpp / 8); + outflat = Z_Calloc(size, PU_STATIC, NULL); + if (outsize) + *outsize = size; + + // Set transparency + if (outbpp == 8) + memset(outflat, TRANSPARENTPIXEL, size); + + for (y = 0; y < inheight; y++) + for (x = 0; x < inwidth; x++) + { + void *input; + size_t offs = ((y * inwidth) + x); + + // Read pixel + if (Picture_IsPatchFormat(informat)) + input = Picture_GetPatchPixel(inpatch, informat, x, y, flags); + else if (Picture_IsFlatFormat(informat)) + input = picture + (offs * (inbpp / 8)); + else + I_Error("Picture_FlatConvert: unsupported input format!"); + + if (!input) + continue; + + switch (outformat) + { + case PICFMT_FLAT32: + { + UINT32 *f32 = (UINT32 *)outflat; + if (inbpp == 32) + { + RGBA_t out = *(RGBA_t *)input; + f32[offs] = out.rgba; + } + else if (inbpp == 16) + { + RGBA_t out = pMasterPalette[*((UINT16 *)input) & 0xFF]; + f32[offs] = out.rgba; + } + else // PICFMT_PATCH + { + RGBA_t out = pMasterPalette[*((UINT8 *)input) & 0xFF]; + f32[offs] = out.rgba; + } + break; + } + case PICFMT_FLAT16: + { + UINT16 *f16 = (UINT16 *)outflat; + if (inbpp == 32) + { + RGBA_t in = *(RGBA_t *)input; + UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); + f16[offs] = (0xFF00 | out); + } + else if (inbpp == 16) + f16[offs] = *(UINT16 *)input; + else // PICFMT_PATCH + f16[offs] = (0xFF00 | *((UINT8 *)input)); + break; + } + case PICFMT_FLAT: + { + UINT8 *f8 = (UINT8 *)outflat; + if (inbpp == 32) + { + RGBA_t in = *(RGBA_t *)input; + UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); + f8[offs] = out; + } + else if (inbpp == 16) + { + UINT16 out = *(UINT16 *)input; + f8[offs] = (out & 0xFF); + } + else // PICFMT_PATCH + f8[offs] = *(UINT8 *)input; + break; + } + default: + I_Error("Picture_FlatConvert: unsupported output format!"); + } + } + + return outflat; +} + +/** Returns a pixel from a patch. + * + * \param patch Input patch. + * \param informat Input picture format. + * \param x Pixel X position. + * \param y Pixel Y position. + * \param flags Input picture flags. + * \return A pointer to a pixel in the patch. Returns NULL if not opaque. + */ +void *Picture_GetPatchPixel( + patch_t *patch, pictureformat_t informat, + INT32 x, INT32 y, + pictureflags_t flags) +{ + fixed_t ofs; + column_t *column; + UINT8 *s8; + UINT16 *s16; + UINT32 *s32; + + if (patch == NULL) + I_Error("Picture_GetPatchPixel: patch == NULL"); + + if (x >= 0 && x < SHORT(patch->width)) + { + INT32 topdelta, prevdelta = -1; + INT32 columnofs = 0; + + if (flags & PICFLAGS_XFLIP) + columnofs = LONG(patch->columnofs[(SHORT(patch->width)-1)-x]); + else + columnofs = LONG(patch->columnofs[x]); + + // Column offsets are pointers so no casting required + column = (column_t *)((UINT8 *)patch + columnofs); + + while (column->topdelta != 0xff) + { + topdelta = column->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + s8 = (UINT8 *)(column) + 3; + if (informat == PICFMT_PATCH32) + s32 = (UINT32 *)s8; + else if (informat == PICFMT_PATCH16) + s16 = (UINT16 *)s8; + for (ofs = 0; ofs < column->length; ofs++) + { + if ((topdelta + ofs) == y) + { + if (informat == PICFMT_PATCH32) + return (s32 + ofs); + else if (informat == PICFMT_PATCH16) + return (s16 + ofs); + else // PICFMT_PATCH + return (s8 + ofs); + } + } + column = (column_t *)((UINT8 *)column + column->length + 4); + } + } + + return NULL; +} + +/** Returns the amount of bits per pixel in the specified picture format. + * + * \param format Input picture format. + * \return The bits per pixel amount of the picture format. + */ +INT32 Picture_FormatBPP(pictureformat_t format) +{ + INT32 bpp = 0; + switch (format) + { + case PICFMT_PATCH32: + case PICFMT_FLAT32: + case PICFMT_PNG: + bpp = 32; + break; + case PICFMT_PATCH16: + case PICFMT_FLAT16: + bpp = 16; + break; + case PICFMT_PATCH: + case PICFMT_FLAT: + bpp = 8; + break; + default: + break; + } + return bpp; +} + +/** Checks if the specified picture format is a patch. + * + * \param format Input picture format. + * \return True if the picture format is a patch, false if not. + */ +boolean Picture_IsPatchFormat(pictureformat_t format) +{ + return (format == PICFMT_PATCH || format == PICFMT_PATCH16 || format == PICFMT_PATCH32); +} + +/** Checks if the specified picture format is a flat. + * + * \param format Input picture format. + * \return True if the picture format is a flat, false if not. + */ +boolean Picture_IsFlatFormat(pictureformat_t format) +{ + return (format == PICFMT_FLAT || format == PICFMT_FLAT16 || format == PICFMT_FLAT32); +} + +/** Returns true if the lump is a valid patch. + * PICFMT_PATCH only, I think?? + * + * \param patch Input patch. + * \param picture Input patch size. + * \return True if the input patch is valid. + */ +boolean R_CheckIfPatch(patch_t *patch, size_t size) +{ + INT16 width, height; + boolean result; // minimum length of a valid Doom patch if (size < 13) return false; - patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); - width = SHORT(patch->width); height = SHORT(patch->height); - result = (height > 0 && height <= 16384 && width > 0 && width <= 16384 && width < (INT16)(size / 4)); if (result) @@ -168,36 +689,10 @@ void R_TextureToFlat(size_t tex, UINT8 *flat) // void R_PatchToFlat(patch_t *patch, UINT8 *flat) { - fixed_t col, ofs; - column_t *column; - UINT8 *desttop, *dest, *deststop; - UINT8 *source; - - desttop = flat; - deststop = desttop + (SHORT(patch->width) * SHORT(patch->height)); - - for (col = 0; col < SHORT(patch->width); col++, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[col])); - - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - - dest = desttop + (topdelta * SHORT(patch->width)); - source = (UINT8 *)(column) + 3; - for (ofs = 0; dest < deststop && ofs < column->length; ofs++) - { - *dest = source[ofs]; - dest += SHORT(patch->width); - } - column = (column_t *)((UINT8 *)column + column->length + 4); - } - } + size_t outsize = 0; + UINT8 *converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &outsize, 0, 0, 0, 0, 0); + M_Memcpy(flat, converted, outsize); + Z_Free(converted); } // @@ -207,34 +702,10 @@ void R_PatchToFlat(patch_t *patch, UINT8 *flat) // void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip) { - fixed_t col, ofs; - column_t *column; - UINT16 *desttop, *dest, *deststop; - UINT8 *source; - - desttop = raw; - deststop = desttop + (SHORT(patch->width) * SHORT(patch->height)); - - for (col = 0; col < SHORT(patch->width); col++, desttop++) - { - INT32 topdelta, prevdelta = -1; - column = (column_t *)((UINT8 *)patch + LONG(patch->columnofs[flip ? (patch->width-1-col) : col])); - while (column->topdelta != 0xff) - { - topdelta = column->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - dest = desttop + (topdelta * SHORT(patch->width)); - source = (UINT8 *)(column) + 3; - for (ofs = 0; dest < deststop && ofs < column->length; ofs++) - { - *dest = source[ofs]; - dest += SHORT(patch->width); - } - column = (column_t *)((UINT8 *)column + column->length + 4); - } - } + size_t outsize = 0; + UINT16 *converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, &outsize, 0, 0, 0, 0, (flip) ? PICFLAGS_XFLIP : 0); + M_Memcpy(raw, converted, outsize); + Z_Free(converted); } // @@ -244,108 +715,8 @@ void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip) // patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency) { - UINT32 x, y; - UINT8 *img; - UINT8 *imgptr = imgbuf; - UINT8 *colpointers, *startofspan; - size_t size = 0; - - // Write image size and offset - WRITEINT16(imgptr, width); - WRITEINT16(imgptr, height); - WRITEINT16(imgptr, leftoffset); - WRITEINT16(imgptr, topoffset); - - // Leave placeholder to column pointers - colpointers = imgptr; - imgptr += width*4; - - // Write columns - for (x = 0; x < width; x++) - { - int lastStartY = 0; - int spanSize = 0; - startofspan = NULL; - - // Write column pointer - WRITEINT32(colpointers, imgptr - imgbuf); - - // Write pixels - for (y = 0; y < height; y++) - { - UINT8 paletteIndex = raw[((y * width) + x)]; - boolean opaque = transparency ? (paletteIndex != TRANSPARENTPIXEL) : true; - - // End span if we have a transparent pixel - if (!opaque) - { - if (startofspan) - WRITEUINT8(imgptr, 0); - startofspan = NULL; - continue; - } - - // Start new column if we need to - if (!startofspan || spanSize == 255) - { - int writeY = y; - - // If we reached the span size limit, finish the previous span - if (startofspan) - WRITEUINT8(imgptr, 0); - - if (y > 254) - { - // Make sure we're aligned to 254 - if (lastStartY < 254) - { - WRITEUINT8(imgptr, 254); - WRITEUINT8(imgptr, 0); - imgptr += 2; - lastStartY = 254; - } - - // Write stopgap empty spans if needed - writeY = y - lastStartY; - - while (writeY > 254) - { - WRITEUINT8(imgptr, 254); - WRITEUINT8(imgptr, 0); - imgptr += 2; - writeY -= 254; - } - } - - startofspan = imgptr; - WRITEUINT8(imgptr, writeY); - imgptr += 2; - spanSize = 0; - - lastStartY = y; - } - - // Write the pixel - WRITEUINT8(imgptr, paletteIndex); - spanSize++; - startofspan[1] = spanSize; - } - - if (startofspan) - WRITEUINT8(imgptr, 0); - - WRITEUINT8(imgptr, 0xFF); - } - - size = imgptr-imgbuf; - img = Z_Malloc(size, PU_STATIC, NULL); - memcpy(img, imgbuf, size); - - Z_Free(raw); - - if (destsize != NULL) - *destsize = size; - return (patch_t *)img; + (void)transparency; + return (patch_t *)Picture_Convert(PICFMT_FLAT, raw, PICFMT_PATCH, 0, destsize, width, height, leftoffset, topoffset, 0); } // @@ -355,107 +726,7 @@ patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffse // patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size) { - UINT32 x, y; - UINT8 *img; - UINT8 *imgptr = imgbuf; - UINT8 *colpointers, *startofspan; - - if (!raw) - return NULL; - - // Write image size and offset - WRITEINT16(imgptr, width); - WRITEINT16(imgptr, height); - // no offsets - WRITEINT16(imgptr, 0); - WRITEINT16(imgptr, 0); - - // Leave placeholder to column pointers - colpointers = imgptr; - imgptr += width*4; - - // Write columns - for (x = 0; x < width; x++) - { - int lastStartY = 0; - int spanSize = 0; - startofspan = NULL; - - // Write column pointer - WRITEINT32(colpointers, imgptr - imgbuf); - - // Write pixels - for (y = 0; y < height; y++) - { - UINT16 pixel = raw[((y * width) + x)]; - UINT8 paletteIndex = (pixel & 0xFF); - UINT8 opaque = (pixel != 0xFF00); // If 1, we have a pixel - - // End span if we have a transparent pixel - if (!opaque) - { - if (startofspan) - WRITEUINT8(imgptr, 0); - startofspan = NULL; - continue; - } - - // Start new column if we need to - if (!startofspan || spanSize == 255) - { - int writeY = y; - - // If we reached the span size limit, finish the previous span - if (startofspan) - WRITEUINT8(imgptr, 0); - - if (y > 254) - { - // Make sure we're aligned to 254 - if (lastStartY < 254) - { - WRITEUINT8(imgptr, 254); - WRITEUINT8(imgptr, 0); - imgptr += 2; - lastStartY = 254; - } - - // Write stopgap empty spans if needed - writeY = y - lastStartY; - - while (writeY > 254) - { - WRITEUINT8(imgptr, 254); - WRITEUINT8(imgptr, 0); - imgptr += 2; - writeY -= 254; - } - } - - startofspan = imgptr; - WRITEUINT8(imgptr, writeY); - imgptr += 2; - spanSize = 0; - - lastStartY = y; - } - - // Write the pixel - WRITEUINT8(imgptr, paletteIndex); - spanSize++; - startofspan[1] = spanSize; - } - - if (startofspan) - WRITEUINT8(imgptr, 0); - - WRITEUINT8(imgptr, 0xFF); - } - - *size = imgptr-imgbuf; - img = Z_Malloc(*size, PU_STATIC, NULL); - memcpy(img, imgbuf, *size); - return (patch_t *)img; + return (patch_t *)Picture_Convert(PICFMT_FLAT16, raw, PICFMT_PATCH, 0, size, width, height, 0, 0, 0); } // @@ -649,19 +920,24 @@ static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoff } // Convert a PNG to a raw image. -static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +static void *PNG_Convert(const UINT8 *png, INT32 outbpp, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) { - UINT8 *flat; + void *flat; png_uint_32 x, y; png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size); png_uint_32 width = *w, height = *h; - if (!row_pointers) - I_Error("PNG_RawConvert: conversion failed"); + if (!outbpp) + I_Error("PNG_Convert: unknown output bits per pixel?!"); + + if (!row_pointers) + I_Error("PNG_Convert: conversion failed!"); + + // Convert the image + flat = Z_Malloc((width * height) * (outbpp / 8), PU_STATIC, NULL); + if (outbpp == 8) + memset(flat, TRANSPARENTPIXEL, (width * height)); - // Convert the image to 8bpp - flat = Z_Malloc(width * height, PU_LEVEL, NULL); - memset(flat, TRANSPARENTPIXEL, width * height); for (y = 0; y < height; y++) { png_bytep row = row_pointers[y]; @@ -669,7 +945,36 @@ static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topo { png_bytep px = &(row[x * 4]); if ((UINT8)px[3]) - flat[((y * width) + x)] = NearestColor((UINT8)px[0], (UINT8)px[1], (UINT8)px[2]); + { + UINT8 red = (UINT8)px[0]; + UINT8 green = (UINT8)px[1]; + UINT8 blue = (UINT8)px[2]; + UINT8 alpha = (UINT8)px[3]; + if (outbpp == 32) + { + UINT32 *outflat = (UINT32 *)flat; + RGBA_t out; + out.s.red = red; + out.s.green = green; + out.s.blue = blue; + out.s.alpha = alpha; + outflat[((y * width) + x)] = out.rgba; + } + else + { + UINT8 palidx = NearestColor(red, green, blue); + if (outbpp == 16) + { + UINT16 *outflat = (UINT16 *)flat; + outflat[((y * width) + x)] = (alpha << 8) | palidx; + } + else // 8bpp + { + UINT8 *outflat = (UINT8 *)flat; + outflat[((y * width) + x)] = palidx; + } + } + } } } free(row_pointers); @@ -684,7 +989,7 @@ static UINT8 *PNG_RawConvert(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topo // UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size) { - return PNG_RawConvert(png, width, height, NULL, NULL, size); + return PNG_Convert(png, 8, width, height, NULL, NULL, size); } // @@ -696,12 +1001,16 @@ patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean t { UINT16 width, height; INT16 topoffset = 0, leftoffset = 0; - UINT8 *raw = PNG_RawConvert(png, &width, &height, &topoffset, &leftoffset, size); + UINT8 *raw = PNG_Convert(png, 32, &width, &height, &topoffset, &leftoffset, size); + patch_t *output; + (void)transparency; if (!raw) I_Error("R_PNGToPatch: conversion failed"); - return R_FlatToPatch(raw, width, height, leftoffset, topoffset, destsize, transparency); + output = Picture_Convert(PICFMT_FLAT32, raw, PICFMT_PATCH, 0, destsize, width, height, leftoffset, topoffset, 0); + Z_Free(raw); + return output; } // @@ -1110,13 +1419,12 @@ void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps) // void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, spriteframe_t *sprframe, INT32 rot, UINT8 flip) { - UINT32 i; INT32 angle; patch_t *patch; patch_t *newpatch; - UINT16 *rawsrc, *rawdst; - size_t size, size2; - INT32 bflip = (flip != 0x00); + UINT16 *rawdst; + size_t size; + pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0; #define SPRITE_XCENTER (leftoffset) #define SPRITE_YCENTER (height / 2) @@ -1130,14 +1438,18 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp INT32 width, height, leftoffset; fixed_t ca, sa; lumpnum_t lump = sprframe->lumppat[rot]; + size_t lumplength; if (lump == LUMPERROR) return; - // Because there's something wrong with SPR_DFLM, I guess - if (!R_CheckIfPatch(lump)) - return; patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); + lumplength = W_LumpLength(lump); + + // Because there's something wrong with SPR_DFLM, I guess + if (!R_CheckIfPatch(patch, lumplength)) + return; + width = patch->width; height = patch->height; leftoffset = patch->leftoffset; @@ -1160,16 +1472,6 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp leftoffset = width - leftoffset; } - // Draw the sprite to a temporary buffer. - size = (width*height); - rawsrc = Z_Malloc(size * sizeof(UINT16), PU_STATIC, NULL); - - // can't memset here - for (i = 0; i < size; i++) - rawsrc[i] = 0xFF00; - - R_PatchToFlat_16bpp(patch, rawsrc, bflip); - // Don't cache angle = 0 for (angle = 1; angle < ROTANGLES; angle++) { @@ -1237,17 +1539,12 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp #undef BOUNDARYADJUST } - size2 = (newwidth * newheight); - if (!size2) - size2 = size; - - rawdst = Z_Malloc(size2 * sizeof(UINT16), PU_STATIC, NULL); - - // can't memset here - for (i = 0; i < size2; i++) - rawdst[i] = 0xFF00; - // Draw the rotated sprite to a temporary buffer. + size = (newwidth * newheight); + if (!size) + size = (width * height); + rawdst = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL); + for (dy = 0; dy < newheight; dy++) { for (dx = 0; dx < newwidth; dx++) @@ -1259,7 +1556,11 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp sx >>= FRACBITS; sy >>= FRACBITS; if (sx >= 0 && sy >= 0 && sx < width && sy < height) - rawdst[(dy*newwidth)+dx] = rawsrc[(sy*width)+sx]; + { + void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); + if (input != NULL) + rawdst[(dy*newwidth)+dx] = *(UINT16 *)input; + } } } @@ -1296,7 +1597,6 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp sprframe->rotsprite.cached[rot] = true; // free image data - Z_Free(rawsrc); Z_Free(patch); } #undef SPRITE_XCENTER diff --git a/src/r_patch.h b/src/r_picformats.h similarity index 62% rename from src/r_patch.h rename to src/r_picformats.h index 53d306b88..cdc64a674 100644 --- a/src/r_patch.h +++ b/src/r_picformats.h @@ -1,14 +1,14 @@ // SONIC ROBO BLAST 2 //----------------------------------------------------------------------------- // Copyright (C) 1993-1996 by id Software, Inc. -// Copyright (C) 2018-2019 by Jaime "Lactozilla" Passos. -// Copyright (C) 2019 by Sonic Team Junior. +// Copyright (C) 2018-2020 by Jaime "Lactozilla" Passos. +// Copyright (C) 2019-2020 by Sonic Team Junior. // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file r_patch.h +/// \file r_picformats.h /// \brief Patch generation. #ifndef __R_PATCH__ @@ -17,6 +17,57 @@ #include "r_defs.h" #include "doomdef.h" +typedef enum +{ + PICFMT_NONE = 0, + + // Doom formats + PICFMT_PATCH, + PICFMT_FLAT, + + // PNG + PICFMT_PNG, + + // 16bpp + PICFMT_PATCH16, + PICFMT_FLAT16, + + // 32bpp + PICFMT_PATCH32, + PICFMT_FLAT32 +} pictureformat_t; + +typedef enum +{ + PICFLAGS_XFLIP = 1, + PICFLAGS_YFLIP = 1<<1 +} pictureflags_t; + +void *Picture_Convert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT32 inwidth, INT32 inheight, INT32 inleftoffset, INT32 intopoffset, + pictureflags_t flags); + +void *Picture_PatchConvert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset, + pictureflags_t flags); +void *Picture_FlatConvert( + pictureformat_t informat, void *picture, pictureformat_t outformat, + size_t insize, size_t *outsize, + INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset, + pictureflags_t flags); +void *Picture_GetPatchPixel( + patch_t *patch, pictureformat_t informat, + INT32 x, INT32 y, + pictureflags_t flags); + +INT32 Picture_FormatBPP(pictureformat_t format); +boolean Picture_IsPatchFormat(pictureformat_t format); +boolean Picture_IsFlatFormat(pictureformat_t format); + // Structs #ifdef ROTSPRITE typedef enum @@ -42,7 +93,7 @@ typedef struct } spriteinfo_t; // Conversions between patches / flats / textures... -boolean R_CheckIfPatch(lumpnum_t lump); +boolean R_CheckIfPatch(patch_t *patch, size_t size); void R_TextureToFlat(size_t tex, UINT8 *flat); void R_PatchToFlat(patch_t *patch, UINT8 *flat); void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip); diff --git a/src/r_things.c b/src/r_things.c index 2f01ac7f6..43b64bf37 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -24,7 +24,7 @@ #include "i_video.h" // rendermode #include "i_system.h" #include "r_things.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_plane.h" #include "r_portal.h" #include "p_tick.h" diff --git a/src/r_things.h b/src/r_things.h index 8e4a543c3..706d98c4e 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -16,7 +16,7 @@ #include "sounds.h" #include "r_plane.h" -#include "r_patch.h" +#include "r_picformats.h" #include "r_portal.h" #include "r_defs.h" diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index b334f6313..7efab1bc0 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -281,7 +281,7 @@ - + @@ -443,7 +443,7 @@ - + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 3f61e8709..97be5ad5f 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -465,7 +465,7 @@ Hw_Hardware - + R_Rend @@ -928,7 +928,7 @@ Hw_Hardware - + R_Rend diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 387d65da9..91a6aa348 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -300,7 +300,7 @@ - + @@ -456,7 +456,7 @@ - + diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index 2f380c473..00040f4a1 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -472,7 +472,7 @@ Hw_Hardware - + R_Rend @@ -892,7 +892,7 @@ Hw_Hardware - + R_Rend diff --git a/src/z_zone.c b/src/z_zone.c index 5a0ff638b..d02717007 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -27,7 +27,7 @@ #include "doomdef.h" #include "doomstat.h" -#include "r_patch.h" +#include "r_picformats.h" #include "i_system.h" // I_GetFreeMem #include "i_video.h" // rendermode #include "z_zone.h" From 4407eb0c0a8ad86fc3b9d130641990a181cc40f8 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 18:31:08 -0300 Subject: [PATCH 02/27] Fix warnings --- src/r_picformats.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index 8e229c4a6..03ccf6917 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -106,7 +106,7 @@ void *Picture_PatchConvert( INT16 inwidth, INT16 inheight, INT16 inleftoffset, INT16 intopoffset, pictureflags_t flags) { - UINT32 x, y; + INT16 x, y; UINT8 *img; UINT8 *imgptr = imgbuf; UINT8 *colpointers, *startofspan; @@ -114,14 +114,14 @@ void *Picture_PatchConvert( patch_t *inpatch = NULL; INT32 inbpp = Picture_FormatBPP(informat); + (void)insize; // ignore + if (informat == outformat) I_Error("Picture_PatchConvert: input and output formats are the same!"); if (!inbpp) I_Error("Picture_PatchConvert: unknown input bits per pixel?!"); - (void)insize; // ignore - // If it's a patch, you can just figure out // the dimensions from the header. if (Picture_IsPatchFormat(informat)) @@ -168,13 +168,13 @@ void *Picture_PatchConvert( switch (informat) { case PICFMT_FLAT32: - input = picture + (offs * 4); + input = (UINT32 *)picture + offs; break; case PICFMT_FLAT16: - input = picture + (offs * 2); + input = (UINT16 *)picture + offs; break; case PICFMT_FLAT: - input = picture + offs; + input = (UINT8 *)picture + offs; break; default: I_Error("Picture_PatchConvert: unsupported flat input format!"); @@ -355,6 +355,10 @@ void *Picture_FlatConvert( INT32 x, y; size_t size; + (void)insize; // ignore + (void)inleftoffset; // ignore + (void)intopoffset; // ignore + if (informat == outformat) I_Error("Picture_FlatConvert: input and output formats are the same!"); @@ -370,8 +374,6 @@ void *Picture_FlatConvert( inpatch = (patch_t *)picture; inwidth = SHORT(inpatch->width); inheight = SHORT(inpatch->height); - inleftoffset = SHORT(inpatch->leftoffset); - intopoffset = SHORT(inpatch->topoffset); } size = (inwidth * inheight) * (outbpp / 8); @@ -393,7 +395,7 @@ void *Picture_FlatConvert( if (Picture_IsPatchFormat(informat)) input = Picture_GetPatchPixel(inpatch, informat, x, y, flags); else if (Picture_IsFlatFormat(informat)) - input = picture + (offs * (inbpp / 8)); + input = (UINT8 *)picture + (offs * (inbpp / 8)); else I_Error("Picture_FlatConvert: unsupported input format!"); @@ -489,15 +491,15 @@ void *Picture_GetPatchPixel( if (x >= 0 && x < SHORT(patch->width)) { INT32 topdelta, prevdelta = -1; - INT32 columnofs = 0; + INT32 colofs = 0; if (flags & PICFLAGS_XFLIP) - columnofs = LONG(patch->columnofs[(SHORT(patch->width)-1)-x]); + colofs = LONG(patch->columnofs[(SHORT(patch->width)-1)-x]); else - columnofs = LONG(patch->columnofs[x]); + colofs = LONG(patch->columnofs[x]); // Column offsets are pointers so no casting required - column = (column_t *)((UINT8 *)patch + columnofs); + column = (column_t *)((UINT8 *)patch + colofs); while (column->topdelta != 0xff) { From edb0bbcd6ded7b12708b47ac47bbb77b21162736 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 20:16:48 -0300 Subject: [PATCH 03/27] Cleanup, NOW --- src/hardware/hw_cache.c | 29 +++-- src/p_setup.c | 4 +- src/r_data.c | 24 ++-- src/r_picformats.c | 259 +++++++++++++++++++++------------------- src/r_picformats.h | 25 ++-- src/r_plane.c | 36 +++--- src/r_things.c | 10 +- src/w_wad.c | 18 +-- 8 files changed, 217 insertions(+), 188 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 90310a92f..6b2965846 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -653,13 +653,17 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) realpatch = (patch_t *)pdata; #ifndef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); + if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) + { + // Dummy variables. + INT32 pngwidth, pngheight; + realpatch = (patch_t *)Picture_PNGConvert(pdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0); + } else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); + realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -697,8 +701,12 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm #ifndef NO_PNG_LUMPS // lump is a png so convert it size_t len = W_LumpLengthPwad(grPatch->wadnum, grPatch->lumpnum); - if ((patch != NULL) && R_IsLumpPNG((const UINT8 *)patch, len)) - patch = R_PNGToPatch((const UINT8 *)patch, len, NULL, true); + if ((patch != NULL) && Picture_IsLumpPNG((const UINT8 *)patch, len)) + { + // Dummy variables. + INT32 pngwidth, pngheight; + patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, len, NULL, 0); + } #endif // don't do it twice (like a cache) @@ -956,6 +964,8 @@ static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) { UINT8 *flat; + UINT8 *converted; + size_t size; if (needpatchflush) W_FlushCachedPatches(); @@ -971,11 +981,12 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) grMipmap->width = (UINT16)textures[texturenum]->width; grMipmap->height = (UINT16)textures[texturenum]->height; + size = (grMipmap->width * grMipmap->height); - flat = Z_Malloc(grMipmap->width * grMipmap->height, PU_HWRCACHE, &grMipmap->grInfo.data); - memset(flat, TRANSPARENTPIXEL, grMipmap->width * grMipmap->height); - - R_TextureToFlat(texturenum, flat); + flat = Z_Malloc(size, PU_HWRCACHE, &grMipmap->grInfo.data); + converted = (UINT8 *)Picture_TextureToFlat(texturenum); + M_Memcpy(flat, converted, size); + Z_Free(converted); } // Download a Doom 'flat' to the hardware cache and make it ready for use diff --git a/src/p_setup.c b/src/p_setup.c index eca5413b4..ec9f31e2f 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -639,7 +639,7 @@ flatfound: /* This could be a flat, patch, or PNG. */ flatpatch = W_CacheLumpNum(flatnum, PU_STATIC); lumplength = W_LumpLength(flatnum); - if (R_CheckIfPatch(flatpatch, lumplength)) + if (Picture_CheckIfPatch(flatpatch, lumplength)) levelflat->type = LEVELFLAT_PATCH; else { @@ -651,7 +651,7 @@ flatfound: if (flatpatch) Z_Free(flatpatch); W_ReadLumpHeader(flatnum, buffer, 8, 0); - if (R_IsLumpPNG(buffer, lumplength)) + if (Picture_IsLumpPNG(buffer, lumplength)) levelflat->type = LEVELFLAT_PNG; else #endif/*NO_PNG_LUMPS*/ diff --git a/src/r_data.c b/src/r_data.c index 14c04f15e..c6e89d2ad 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -473,7 +473,7 @@ static UINT8 *R_GenerateTexture(size_t texnum) realpatch = (patch_t *)pdata; #ifndef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) + if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) goto multipatch; #endif #ifdef WALLFLATS @@ -570,13 +570,17 @@ static UINT8 *R_GenerateTexture(size_t texnum) dealloc = true; #ifndef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)realpatch, lumplength)) - realpatch = R_PNGToPatch((UINT8 *)realpatch, lumplength, NULL, false); + if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) + { + // Dummy variables. + INT32 pngwidth, pngheight; + realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0); + } else #endif #ifdef WALLFLATS if (texture->type == TEXTURETYPE_FLAT) - realpatch = R_FlatToPatch(pdata, texture->width, texture->height, 0, 0, NULL, false); + realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); else #endif { @@ -896,10 +900,10 @@ countflats: M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); #ifndef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)patchlump, lumplength)) + if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength)) { - INT16 width, height; - R_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength); + INT16 width = 0, height = 0; + Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength); texture->width = width; texture->height = height; } @@ -999,10 +1003,10 @@ checkflats: M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); #ifndef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)flatlump, lumplength)) + if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength)) { - INT16 width, height; - R_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength); + INT16 width = 0, height = 0; + Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength); texture->width = width; texture->height = height; } diff --git a/src/r_picformats.c b/src/r_picformats.c index 03ccf6917..cbfdc3c90 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -59,7 +59,7 @@ fixed_t sinang2rad[ROTANGLES]; * \param picture Input picture data. * \param outformat Output picture format. * \param insize Input picture size. - * \param outsize Output picture size. + * \param outsize Output picture size, as a pointer. * \param inwidth Input picture width. * \param inheight Input picture height. * \param inleftoffset Input picture left offset, for patches. @@ -73,8 +73,12 @@ void *Picture_Convert( INT32 inwidth, INT32 inheight, INT32 inleftoffset, INT32 intopoffset, pictureflags_t flags) { - if (informat == outformat) // wut? - I_Error("Picture_Convert: input and output formats are the same!"); + if (informat == PICFMT_NONE) + I_Error("Picture_Convert: input format was PICFMT_NONE!"); + else if (outformat == PICFMT_NONE) + I_Error("Picture_Convert: output format was PICFMT_NONE!"); + else if (informat == outformat) + I_Error("Picture_Convert: input and output formats were the same!"); if (Picture_IsPatchFormat(outformat)) return Picture_PatchConvert(informat, picture, outformat, insize, outsize, inwidth, inheight, inleftoffset, intopoffset, flags); @@ -92,7 +96,7 @@ void *Picture_Convert( * \param picture Input picture data. * \param outformat Output picture format. * \param insize Input picture size. - * \param outsize Output picture size. + * \param outsize Output picture size, as a pointer. * \param inwidth Input picture width. * \param inheight Input picture height. * \param inleftoffset Input picture left offset, for patches. @@ -116,8 +120,12 @@ void *Picture_PatchConvert( (void)insize; // ignore - if (informat == outformat) - I_Error("Picture_PatchConvert: input and output formats are the same!"); + if (informat == PICFMT_NONE) + I_Error("Picture_PatchConvert: input format was PICFMT_NONE!"); + else if (outformat == PICFMT_NONE) + I_Error("Picture_PatchConvert: output format was PICFMT_NONE!"); + else if (informat == outformat) + I_Error("Picture_PatchConvert: input and output formats were the same!"); if (!inbpp) I_Error("Picture_PatchConvert: unknown input bits per pixel?!"); @@ -334,7 +342,7 @@ void *Picture_PatchConvert( * \param picture Input picture data. * \param outformat Output picture format. * \param insize Input picture size. - * \param outsize Output picture size. + * \param outsize Output picture size, as a pointer. * \param inwidth Input picture width. * \param inheight Input picture height. * \param inleftoffset Input picture left offset, for patches. @@ -359,8 +367,12 @@ void *Picture_FlatConvert( (void)inleftoffset; // ignore (void)intopoffset; // ignore - if (informat == outformat) - I_Error("Picture_FlatConvert: input and output formats are the same!"); + if (informat == PICFMT_NONE) + I_Error("Picture_FlatConvert: input format was PICFMT_NONE!"); + else if (outformat == PICFMT_NONE) + I_Error("Picture_FlatConvert: output format was PICFMT_NONE!"); + else if (informat == outformat) + I_Error("Picture_FlatConvert: input and output formats were the same!"); if (!inbpp) I_Error("Picture_FlatConvert: unknown input bits per pixel?!"); @@ -587,7 +599,7 @@ boolean Picture_IsFlatFormat(pictureformat_t format) * \param picture Input patch size. * \return True if the input patch is valid. */ -boolean R_CheckIfPatch(patch_t *patch, size_t size) +boolean Picture_CheckIfPatch(patch_t *patch, size_t size) { INT16 width, height; boolean result; @@ -624,26 +636,40 @@ boolean R_CheckIfPatch(patch_t *patch, size_t size) return result; } -// -// R_TextureToFlat -// -// Convert a texture to a flat. -// -void R_TextureToFlat(size_t tex, UINT8 *flat) +/** Converts a texture to a flat. + * + * \param trickytex The texture number. + * \return The converted flat. + */ +void *Picture_TextureToFlat(size_t trickytex) { - texture_t *texture = textures[tex]; + texture_t *texture; + size_t tex; + UINT8 *converted; + size_t flatsize; fixed_t col, ofs; column_t *column; UINT8 *desttop, *dest, *deststop; UINT8 *source; - // yea + if (trickytex >= (unsigned)numtextures) + I_Error("Picture_TextureToFlat: invalid texture number!"); + + // Check the texture cache + // If the texture's not there, it'll be generated right now + tex = trickytex; + texture = textures[tex]; R_CheckTextureCache(tex); - desttop = flat; - deststop = desttop + (texture->width * texture->height); + // Allocate the flat + flatsize = (texture->width * texture->height); + converted = Z_Malloc(flatsize, PU_STATIC, NULL); + memset(converted, TRANSPARENTPIXEL, flatsize); + // Now we're gonna write to it + desttop = converted; + deststop = desttop + flatsize; for (col = 0; col < texture->width; col++, desttop++) { // no post_t info @@ -682,61 +708,17 @@ void R_TextureToFlat(size_t tex, UINT8 *flat) } } } + + return converted; } -// -// R_PatchToFlat -// -// Convert a patch to a flat. -// -void R_PatchToFlat(patch_t *patch, UINT8 *flat) -{ - size_t outsize = 0; - UINT8 *converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &outsize, 0, 0, 0, 0, 0); - M_Memcpy(flat, converted, outsize); - Z_Free(converted); -} - -// -// R_PatchToFlat_16bpp -// -// Convert a patch to a 16-bit flat. -// -void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip) -{ - size_t outsize = 0; - UINT16 *converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT16, 0, &outsize, 0, 0, 0, 0, (flip) ? PICFLAGS_XFLIP : 0); - M_Memcpy(raw, converted, outsize); - Z_Free(converted); -} - -// -// R_FlatToPatch -// -// Convert a flat to a patch. -// -patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency) -{ - (void)transparency; - return (patch_t *)Picture_Convert(PICFMT_FLAT, raw, PICFMT_PATCH, 0, destsize, width, height, leftoffset, topoffset, 0); -} - -// -// R_FlatToPatch_16bpp -// -// Convert a 16-bit flat to a patch. -// -patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size) -{ - return (patch_t *)Picture_Convert(PICFMT_FLAT16, raw, PICFMT_PATCH, 0, size, width, height, 0, 0, 0); -} - -// -// R_IsLumpPNG -// -// Returns true if the lump is a valid PNG. -// -boolean R_IsLumpPNG(const UINT8 *d, size_t s) +/** Returns true if the lump is a valid PNG. + * + * \param d The lump to be checked. + * \param s The lump size. + * \return True if the lump is a PNG image. + */ +boolean Picture_IsLumpPNG(const UINT8 *d, size_t s) { if (s < 67) // http://garethrees.org/2007/11/14/pngcrush/ return false; @@ -803,7 +785,7 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext) CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); } -static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) { png_structp png_ptr; png_infop png_info_ptr; @@ -824,17 +806,13 @@ static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoff png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) - { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); - return NULL; - } + I_Error("PNG_Load: Couldn't initialize libpng!"); png_info_ptr = png_create_info_struct(png_ptr); if (!png_info_ptr) { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); - return NULL; + I_Error("PNG_Load: libpng couldn't allocate memory!"); } #ifdef USE_FAR_KEYWORD @@ -921,22 +899,44 @@ static png_bytep *PNG_Read(const UINT8 *png, UINT16 *w, UINT16 *h, INT16 *topoff return row_pointers; } -// Convert a PNG to a raw image. -static void *PNG_Convert(const UINT8 *png, INT32 outbpp, UINT16 *w, UINT16 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +/** Converts a PNG to a picture. + * + * \param png The PNG image. + * \param outformat The output picture's format. + * \param w The output picture's width, as a pointer. + * \param h The output picture's height, as a pointer. + * \param topoffset The output picture's top offset, for sprites, as a pointer. + * \param leftoffset The output picture's left offset, for sprites, as a pointer. + * \param insize The input picture's size. + * \param outsize A pointer to the output picture's size. + * \param flags Input picture flags. + * \return A pointer to the converted picture. + */ +void *Picture_PNGConvert( + const UINT8 *png, pictureformat_t outformat, + INT32 *w, INT32 *h, + INT16 *topoffset, INT16 *leftoffset, + size_t insize, size_t *outsize, + pictureflags_t flags) { void *flat; + INT32 outbpp; + size_t flatsize; png_uint_32 x, y; - png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, size); + png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); png_uint_32 width = *w, height = *h; + outbpp = Picture_FormatBPP(outformat); if (!outbpp) - I_Error("PNG_Convert: unknown output bits per pixel?!"); + I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); - if (!row_pointers) - I_Error("PNG_Convert: conversion failed!"); + // Figure out the size + flatsize = (width * height) * (outbpp / 8); + if (outsize) + *outsize = flatsize; // Convert the image - flat = Z_Malloc((width * height) * (outbpp / 8), PU_STATIC, NULL); + flat = Z_Malloc(flatsize, PU_STATIC, NULL); if (outbpp == 8) memset(flat, TRANSPARENTPIXEL, (width * height)); @@ -979,48 +979,55 @@ static void *PNG_Convert(const UINT8 *png, INT32 outbpp, UINT16 *w, UINT16 *h, I } } } + + // Free the row pointers that libpng allocated. free(row_pointers); + // But wait, there's more! + if (Picture_IsPatchFormat(outformat)) + { + void *converted; + pictureformat_t informat = PICFMT_NONE; + INT16 patleftoffset = 0, pattopoffset = 0; + + // Figure out the input format, from the bitdepth of the input format + switch (outbpp) + { + case 32: + informat = PICFMT_FLAT32; + break; + case 16: + informat = PICFMT_FLAT16; + break; + default: + informat = PICFMT_FLAT; // Assumed 8bpp + break; + } + + // Also find out if leftoffset and topoffset aren't pointing to NULL. + if (leftoffset) + patleftoffset = *leftoffset; + if (topoffset) + pattopoffset = *topoffset; + + // Now, convert it! + converted = Picture_PatchConvert(informat, flat, outformat, insize, outsize, (INT16)width, (INT16)height, patleftoffset, pattopoffset, flags); + Z_Free(flat); + return converted; + } + return flat; } -// -// R_PNGToFlat -// -// Convert a PNG to a flat. -// -UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size) -{ - return PNG_Convert(png, 8, width, height, NULL, NULL, size); -} - -// -// R_PNGToPatch -// -// Convert a PNG to a patch. -// -patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency) -{ - UINT16 width, height; - INT16 topoffset = 0, leftoffset = 0; - UINT8 *raw = PNG_Convert(png, 32, &width, &height, &topoffset, &leftoffset, size); - patch_t *output; - - (void)transparency; - if (!raw) - I_Error("R_PNGToPatch: conversion failed"); - - output = Picture_Convert(PICFMT_FLAT32, raw, PICFMT_PATCH, 0, destsize, width, height, leftoffset, topoffset, 0); - Z_Free(raw); - return output; -} - -// -// R_PNGDimensions -// -// Get the dimensions of a PNG file. -// -boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) +/** Returns the dimensions of a PNG image, but doesn't perform any conversions. + * + * \param png The PNG image. + * \param width A pointer to the input picture's width. + * \param height A pointer to the input picture's height. + * \param size The input picture's size. + * \return True if reading the file succeeded, false if it failed. + */ +boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size) { png_structp png_ptr; png_infop png_info_ptr; @@ -1449,7 +1456,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp lumplength = W_LumpLength(lump); // Because there's something wrong with SPR_DFLM, I guess - if (!R_CheckIfPatch(patch, lumplength)) + if (!Picture_CheckIfPatch(patch, lumplength)) return; width = patch->width; @@ -1567,7 +1574,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp } // make patch - newpatch = R_FlatToPatch_16bpp(rawdst, newwidth, newheight, &size); + newpatch = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawdst, PICFMT_PATCH, 0, &size, newwidth, newheight, 0, 0, 0); { newpatch->leftoffset = (newpatch->width / 2) + (leftoffset - px); newpatch->topoffset = (newpatch->height / 2) + (patch->topoffset - py); diff --git a/src/r_picformats.h b/src/r_picformats.h index cdc64a674..0dd4340cc 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -64,9 +64,12 @@ void *Picture_GetPatchPixel( INT32 x, INT32 y, pictureflags_t flags); +void *Picture_TextureToFlat(size_t trickytex); + INT32 Picture_FormatBPP(pictureformat_t format); boolean Picture_IsPatchFormat(pictureformat_t format); boolean Picture_IsFlatFormat(pictureformat_t format); +boolean Picture_CheckIfPatch(patch_t *patch, size_t size); // Structs #ifdef ROTSPRITE @@ -92,22 +95,18 @@ typedef struct boolean available; } spriteinfo_t; -// Conversions between patches / flats / textures... -boolean R_CheckIfPatch(patch_t *patch, size_t size); -void R_TextureToFlat(size_t tex, UINT8 *flat); -void R_PatchToFlat(patch_t *patch, UINT8 *flat); -void R_PatchToFlat_16bpp(patch_t *patch, UINT16 *raw, boolean flip); -patch_t *R_FlatToPatch(UINT8 *raw, UINT16 width, UINT16 height, UINT16 leftoffset, UINT16 topoffset, size_t *destsize, boolean transparency); -patch_t *R_FlatToPatch_16bpp(UINT16 *raw, UINT16 width, UINT16 height, size_t *size); - // Portable Network Graphics -boolean R_IsLumpPNG(const UINT8 *d, size_t s); -#define W_ThrowPNGError(lumpname, wadfilename) I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .png - please convert to either Doom or Flat (raw) image format.", lumpname, wadfilename); // Fears Of LJ Sonic +boolean Picture_IsLumpPNG(const UINT8 *d, size_t s); +#define Picture_ThrowPNGError(lumpname, wadfilename) I_Error("W_Wad: Lump \"%s\" in file \"%s\" is a .png - please convert to either Doom or Flat (raw) image format.", lumpname, wadfilename); // Fears Of LJ Sonic #ifndef NO_PNG_LUMPS -UINT8 *R_PNGToFlat(UINT16 *width, UINT16 *height, UINT8 *png, size_t size); -patch_t *R_PNGToPatch(const UINT8 *png, size_t size, size_t *destsize, boolean transparency); -boolean R_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); +void *Picture_PNGConvert( + const UINT8 *png, pictureformat_t outformat, + INT32 *w, INT32 *h, + INT16 *topoffset, INT16 *leftoffset, + size_t insize, size_t *outsize, + pictureflags_t flags); +boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); #endif // SpriteInfo diff --git a/src/r_plane.c b/src/r_plane.c index 5d5e1f20d..c11aeb138 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -764,18 +764,6 @@ void R_CheckFlatLength(size_t size) } } -// -// R_GenerateFlat -// -// Generate a flat from specified width and height. -// -static UINT8 *R_GenerateFlat(UINT16 width, UINT16 height) -{ - UINT8 *flat = Z_Malloc(width * height, PU_LEVEL, NULL); - memset(flat, TRANSPARENTPIXEL, width * height); - return flat; -} - // // R_GetTextureFlat // @@ -810,12 +798,17 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo // Level texture if (leveltexture) { + UINT8 *converted; + size_t size; texture_t *texture = textures[levelflat->u.texture.num]; texflat->width = ds_flatwidth = texture->width; texflat->height = ds_flatheight = texture->height; - texflat->flat = R_GenerateFlat(ds_flatwidth, ds_flatheight); - R_TextureToFlat(levelflat->u.texture.num, texflat->flat); + size = (texflat->width * texflat->height); + texflat->flat = Z_Malloc(size, PU_LEVEL, NULL); + converted = (UINT8 *)Picture_TextureToFlat(levelflat->u.texture.num); + M_Memcpy(texflat->flat, converted, size); + Z_Free(converted); flat = texflat->flat; levelflat->flatpatch = flat; @@ -829,22 +822,31 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo #ifndef NO_PNG_LUMPS if (ispng) { - levelflat->flatpatch = R_PNGToFlat(&levelflat->width, &levelflat->height, ds_source, W_LumpLength(levelflat->u.flat.lumpnum)); + INT32 pngwidth, pngheight; + + levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT32, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); levelflat->topoffset = levelflat->leftoffset = 0; + levelflat->width = (UINT16)pngwidth; + levelflat->height = (UINT16)pngheight; + ds_flatwidth = levelflat->width; ds_flatheight = levelflat->height; } else #endif { + UINT8 *converted; + size_t size; levelflat->width = ds_flatwidth = SHORT(patch->width); levelflat->height = ds_flatheight = SHORT(patch->height); levelflat->topoffset = patch->topoffset * FRACUNIT; levelflat->leftoffset = patch->leftoffset * FRACUNIT; - levelflat->flatpatch = R_GenerateFlat(ds_flatwidth, ds_flatheight); - R_PatchToFlat(patch, levelflat->flatpatch); + levelflat->flatpatch = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); + converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + M_Memcpy(levelflat->flatpatch, converted, size); + Z_Free(converted); } flat = levelflat->flatpatch; } diff --git a/src/r_things.c b/src/r_things.c index 43b64bf37..5b4dd0633 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -282,10 +282,14 @@ static boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, patch_t *png = W_CacheLumpNumPwad(wadnum, l, PU_STATIC); size_t len = W_LumpLengthPwad(wadnum, l); // lump is a png so convert it - if (R_IsLumpPNG((UINT8 *)png, len)) + if (Picture_IsLumpPNG((UINT8 *)png, len)) { - png = R_PNGToPatch((UINT8 *)png, len, NULL, true); - M_Memcpy(&patch, png, sizeof(INT16)*4); + // Dummy variables. + INT32 pngwidth, pngheight; + INT16 topoffset, leftoffset; + patch_t *converted = (patch_t *)Picture_PNGConvert((UINT8 *)png, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0); + M_Memcpy(&patch, converted, sizeof(INT16)*4); // only copy the header because that's all we need + Z_Free(converted); } Z_Free(png); } diff --git a/src/w_wad.c b/src/w_wad.c index d8b362d49..465b5abd8 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1213,8 +1213,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si #ifdef NO_PNG_LUMPS { size_t bytesread = fread(dest, 1, size, handle); - if (R_IsLumpPNG((UINT8 *)dest, bytesread)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + if (Picture_IsLumpPNG((UINT8 *)dest, bytesread)) + Picture_ThrowPNGError(l->name2, wadfiles[wad]->filename); return bytesread; } #else @@ -1255,8 +1255,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si Z_Free(rawData); Z_Free(decData); #ifdef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)dest, size)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + if (Picture_IsLumpPNG((UINT8 *)dest, size)) + Picture_ThrowPNGError(l->name2, wadfiles[wad]->filename); #endif return size; #else @@ -1318,8 +1318,8 @@ size_t W_ReadLumpHeaderPwad(UINT16 wad, UINT16 lump, void *dest, size_t size, si Z_Free(decData); #ifdef NO_PNG_LUMPS - if (R_IsLumpPNG((UINT8 *)dest, size)) - W_ThrowPNGError(l->name2, wadfiles[wad]->filename); + if (Picture_IsLumpPNG((UINT8 *)dest, size)) + Picture_ThrowPNGError(l->name2, wadfiles[wad]->filename); #endif return size; } @@ -1538,10 +1538,12 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) #ifndef NO_PNG_LUMPS // lump is a png so convert it - if (R_IsLumpPNG((UINT8 *)lumpdata, len)) + if (Picture_IsLumpPNG((UINT8 *)lumpdata, len)) { + // Dummy variables. size_t newlen; - srcdata = R_PNGToPatch((UINT8 *)lumpdata, len, &newlen, true); + INT32 pngwidth, pngheight; + srcdata = Picture_PNGConvert((UINT8 *)lumpdata, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, len, &newlen, 0); ptr = Z_Realloc(ptr, newlen, tag, &lumpcache[lump]); M_Memcpy(ptr, srcdata, newlen); Z_Free(srcdata); From d5c44350c25d1014b8bfbb9867a0e7131079d253 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 20:20:05 -0300 Subject: [PATCH 04/27] Initialise --- src/r_picformats.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index cbfdc3c90..a8ae01f13 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -493,9 +493,9 @@ void *Picture_GetPatchPixel( { fixed_t ofs; column_t *column; - UINT8 *s8; - UINT16 *s16; - UINT32 *s32; + UINT8 *s8 = NULL; + UINT16 *s16 = NULL; + UINT32 *s32 = NULL; if (patch == NULL) I_Error("Picture_GetPatchPixel: patch == NULL"); From 218fdaeaf898d1e35072256a9be7d48ae809f177 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 20:39:38 -0300 Subject: [PATCH 05/27] Fix patch conversion --- src/r_picformats.c | 23 ++++++++++++++++------- src/r_plane.c | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index a8ae01f13..ebeb35b7b 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -926,9 +926,15 @@ void *Picture_PNGConvert( png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); png_uint_32 width = *w, height = *h; - outbpp = Picture_FormatBPP(outformat); - if (!outbpp) - I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); + // Hack for patches because you'll want to preserve transparency. + if (Picture_IsPatchFormat(outformat)) + outbpp = 16; + else + { + outbpp = Picture_FormatBPP(outformat); + if (!outbpp) + I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); + } // Figure out the size flatsize = (width * height) * (outbpp / 8); @@ -936,7 +942,9 @@ void *Picture_PNGConvert( *outsize = flatsize; // Convert the image - flat = Z_Malloc(flatsize, PU_STATIC, NULL); + flat = Z_Calloc(flatsize, PU_STATIC, NULL); + + // Set transparency if (outbpp == 8) memset(flat, TRANSPARENTPIXEL, (width * height)); @@ -980,7 +988,7 @@ void *Picture_PNGConvert( } } - // Free the row pointers that libpng allocated. + // Free the row pointers that we allocated for libpng. free(row_pointers); // But wait, there's more! @@ -990,7 +998,7 @@ void *Picture_PNGConvert( pictureformat_t informat = PICFMT_NONE; INT16 patleftoffset = 0, pattopoffset = 0; - // Figure out the input format, from the bitdepth of the input format + // Figure out the format of the flat, from the bit depth of the output format switch (outbpp) { case 32: @@ -1000,7 +1008,7 @@ void *Picture_PNGConvert( informat = PICFMT_FLAT16; break; default: - informat = PICFMT_FLAT; // Assumed 8bpp + informat = PICFMT_FLAT; break; } @@ -1016,6 +1024,7 @@ void *Picture_PNGConvert( return converted; } + // Return the converted flat! return flat; } diff --git a/src/r_plane.c b/src/r_plane.c index c11aeb138..43c097a23 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -824,7 +824,7 @@ static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boo { INT32 pngwidth, pngheight; - levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT32, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); levelflat->topoffset = levelflat->leftoffset = 0; levelflat->width = (UINT16)pngwidth; levelflat->height = (UINT16)pngheight; From 42895b2c5fa72e0e4ee90e0baa83f0ce4e81a5a6 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 20:42:46 -0300 Subject: [PATCH 06/27] Make error messages consistent --- src/r_picformats.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index ebeb35b7b..bb3abcf6a 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -806,13 +806,13 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) - I_Error("PNG_Load: Couldn't initialize libpng!"); + I_Error("PNG_Read: Couldn't initialize libpng!"); png_info_ptr = png_create_info_struct(png_ptr); if (!png_info_ptr) { png_destroy_read_struct(&png_ptr, NULL, NULL); - I_Error("PNG_Load: libpng couldn't allocate memory!"); + I_Error("PNG_Read: libpng couldn't allocate memory!"); } #ifdef USE_FAR_KEYWORD @@ -821,9 +821,8 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse if (setjmp(png_jmpbuf(png_ptr))) #endif { - //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - return NULL; + I_Error("PNG_Read: libpng load error!"); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); @@ -1053,17 +1052,13 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, PNG_error, PNG_warn); if (!png_ptr) - { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on initialize libpng\n"); - return false; - } + I_Error("Picture_PNGDimensions: Couldn't initialize libpng!"); png_info_ptr = png_create_info_struct(png_ptr); if (!png_info_ptr) { - CONS_Debug(DBG_RENDER, "PNG_Load: Error on allocate for libpng\n"); png_destroy_read_struct(&png_ptr, NULL, NULL); - return false; + I_Error("Picture_PNGDimensions: libpng couldn't allocate memory!"); } #ifdef USE_FAR_KEYWORD @@ -1072,9 +1067,8 @@ boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t si if (setjmp(png_jmpbuf(png_ptr))) #endif { - //CONS_Debug(DBG_RENDER, "libpng load error on %s\n", filename); png_destroy_read_struct(&png_ptr, &png_info_ptr, NULL); - return false; + I_Error("Picture_PNGDimensions: libpng load error!"); } #ifdef USE_FAR_KEYWORD png_memcpy(png_jmpbuf(png_ptr), jmpbuf, sizeof jmp_buf); From db8735129a9025406e7473085288a8c0132f483f Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 21:02:25 -0300 Subject: [PATCH 07/27] Don't force 16bpp if the bit depth was already higher! --- src/r_picformats.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index bb3abcf6a..b55dac5ad 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -925,16 +925,21 @@ void *Picture_PNGConvert( png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); png_uint_32 width = *w, height = *h; + // Find the output format's bits per pixel amount + outbpp = Picture_FormatBPP(outformat); + // Hack for patches because you'll want to preserve transparency. if (Picture_IsPatchFormat(outformat)) - outbpp = 16; - else { - outbpp = Picture_FormatBPP(outformat); - if (!outbpp) - I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); + // Force a higher bit depth + if (outbpp == 8) + outbpp = 16; } + // Shouldn't happen. + if (!outbpp) + I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); + // Figure out the size flatsize = (width * height) * (outbpp / 8); if (outsize) From a089863823453e65bb5d8dea8367739a4ec1ef4b Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 21:16:33 -0300 Subject: [PATCH 08/27] Missing check --- src/r_picformats.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/r_picformats.c b/src/r_picformats.c index b55dac5ad..340fd5bf6 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -129,6 +129,8 @@ void *Picture_PatchConvert( if (!inbpp) I_Error("Picture_PatchConvert: unknown input bits per pixel?!"); + if (!Picture_FormatBPP(outformat)) + I_Error("Picture_PatchConvert: unknown output bits per pixel?!"); // If it's a patch, you can just figure out // the dimensions from the header. From 9e0d28f32f8a9da22216371214cfc5c43da02834 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 6 Jan 2020 22:08:51 -0300 Subject: [PATCH 09/27] How did I mess this up? --- src/r_picformats.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index 340fd5bf6..cafe30d7e 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1578,7 +1578,7 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp { void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip); if (input != NULL) - rawdst[(dy*newwidth)+dx] = *(UINT16 *)input; + rawdst[(dy*newwidth)+dx] = (0xFF00 | (*(UINT8 *)input)); } } } From f85476c723e4e0d45a58fa3343309ba6ddd6e0e4 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 12:35:10 -0300 Subject: [PATCH 10/27] Move texture stuff to its own file --- src/CMakeLists.txt | 2 + src/Makefile | 1 + src/dehacked.c | 1 + src/hardware/hw_cache.c | 1 + src/p_maputl.c | 1 + src/p_saveg.c | 1 + src/p_setup.c | 1 + src/p_spec.c | 1 + src/r_data.c | 1462 +----------------------- src/r_data.h | 90 +- src/r_local.h | 1 + src/r_main.h | 1 + src/r_picformats.c | 3 + src/r_plane.c | 1 + src/r_plane.h | 1 + src/r_portal.h | 1 + src/r_textures.c | 1441 +++++++++++++++++++++++ src/r_textures.h | 109 ++ src/sdl/Srb2SDL-vc10.vcxproj | 6 +- src/sdl/Srb2SDL-vc10.vcxproj.filters | 6 + src/w_wad.c | 2 +- src/win32/Srb2win-vc10.vcxproj | 6 +- src/win32/Srb2win-vc10.vcxproj.filters | 3 + 23 files changed, 1594 insertions(+), 1548 deletions(-) create mode 100644 src/r_textures.c create mode 100644 src/r_textures.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7a6e7871a..9577f0e60 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -123,6 +123,7 @@ set(SRB2_CORE_RENDER_SOURCES r_sky.c r_splats.c r_things.c + r_textures.c r_picformats.c r_portal.c @@ -138,6 +139,7 @@ set(SRB2_CORE_RENDER_SOURCES r_splats.h r_state.h r_things.h + r_textures.h r_picformats.h r_portal.h ) diff --git a/src/Makefile b/src/Makefile index 282ff8f4f..878df680a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -471,6 +471,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/r_sky.o \ $(OBJDIR)/r_splats.o \ $(OBJDIR)/r_things.o \ + $(OBJDIR)/r_textures.o \ $(OBJDIR)/r_picformats.o \ $(OBJDIR)/r_portal.o \ $(OBJDIR)/screen.o \ diff --git a/src/dehacked.c b/src/dehacked.c index 81690cde9..e655e8a63 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -28,6 +28,7 @@ #include "p_local.h" // for var1 and var2, and some constants #include "p_setup.h" #include "r_data.h" +#include "r_textures.h" #include "r_draw.h" #include "r_picformats.h" #include "r_sky.h" diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 6b2965846..9bf7db1da 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -26,6 +26,7 @@ #include "../doomstat.h" //gamemode #include "../i_video.h" //rendermode #include "../r_data.h" +#include "../r_textures.h" #include "../w_wad.h" #include "../z_zone.h" #include "../v_video.h" diff --git a/src/p_maputl.c b/src/p_maputl.c index f598595e2..c6828db4a 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -18,6 +18,7 @@ #include "p_local.h" #include "r_main.h" #include "r_data.h" +#include "r_textures.h" #include "p_maputl.h" #include "p_polyobj.h" #include "p_slopes.h" diff --git a/src/p_saveg.c b/src/p_saveg.c index 89447db80..cca43db68 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -22,6 +22,7 @@ #include "p_setup.h" #include "p_saveg.h" #include "r_data.h" +#include "r_textures.h" #include "r_things.h" #include "r_state.h" #include "w_wad.h" diff --git a/src/p_setup.c b/src/p_setup.c index ec9f31e2f..0b43f76a5 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -28,6 +28,7 @@ #include "r_data.h" #include "r_things.h" +#include "r_textures.h" #include "r_picformats.h" #include "r_sky.h" #include "r_draw.h" diff --git a/src/p_spec.c b/src/p_spec.c index d7a2133c8..f19946646 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -20,6 +20,7 @@ #include "p_local.h" #include "p_setup.h" // levelflats for flat animation #include "r_data.h" +#include "r_textures.h" #include "m_random.h" #include "p_mobj.h" #include "i_system.h" diff --git a/src/r_data.c b/src/r_data.c index c6e89d2ad..db791ab16 100644 --- a/src/r_data.c +++ b/src/r_data.c @@ -19,6 +19,7 @@ #include "p_local.h" #include "m_misc.h" #include "r_data.h" +#include "r_textures.h" #include "r_picformats.h" #include "w_wad.h" #include "z_zone.h" @@ -32,64 +33,6 @@ #include // alloca(sizeof) #endif -#ifdef HWRENDER -#include "hardware/hw_main.h" // HWR_LoadTextures -#endif - -#if defined(_MSC_VER) -#pragma pack(1) -#endif - -// Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog -#if 0 -#define AVOID_ERRNO -#else -#include -#endif - -// -// Texture definition. -// Each texture is composed of one or more patches, -// with patches being lumps stored in the WAD. -// The lumps are referenced by number, and patched -// into the rectangular texture space using origin -// and possibly other attributes. -// -typedef struct -{ - INT16 originx, originy; - INT16 patch, stepdir, colormap; -} ATTRPACK mappatch_t; - -// -// Texture definition. -// An SRB2 wall texture is a list of patches -// which are to be combined in a predefined order. -// -typedef struct -{ - char name[8]; - INT32 masked; - INT16 width; - INT16 height; - INT32 columndirectory; // FIXTHIS: OBSOLETE - INT16 patchcount; - mappatch_t patches[1]; -} ATTRPACK maptexture_t; - -#if defined(_MSC_VER) -#pragma pack() -#endif - - -// Store lists of lumps for F_START/F_END etc. -typedef struct -{ - UINT16 wadfile; - UINT16 firstlump; - size_t numlumps; -} lumplist_t; - // // Graphics. // SRB2 graphics for walls and sprites @@ -100,20 +43,6 @@ typedef struct size_t numspritelumps, max_spritelumps; -// textures -INT32 numtextures = 0; // total number of textures found, -// size of following tables - -texture_t **textures = NULL; -textureflat_t *texflats = NULL; -static UINT32 **texturecolumnofs; // column offset lookup table for each texture -static UINT8 **texturecache; // graphics data for each generated full-size texture - -INT32 *texturewidth; -fixed_t *textureheight; // needed for texture pegging - -INT32 *texturetranslation; - // needed for pre rendering sprcache_t *spritecachedinfo; @@ -127,106 +56,6 @@ size_t flatmemory, spritememory, texturememory; INT16 color8to16[256]; // remap color index to highcolor rgb value INT16 *hicolormaps; // test a 32k colormap remaps high -> high -// Painfully simple texture id cacheing to make maps load faster. :3 -static struct { - char name[9]; - INT32 id; -} *tidcache = NULL; -static INT32 tidcachelen = 0; - -// -// MAPTEXTURE_T CACHING -// When a texture is first needed, it counts the number of composite columns -// required in the texture and allocates space for a column directory and -// any new columns. -// The directory will simply point inside other patches if there is only one -// patch in a given column, but any columns with multiple patches will have -// new column_ts generated. -// - -// -// R_DrawColumnInCache -// Clip and draw a column from a patch into a cached post. -// -static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) -{ - INT32 count, position; - UINT8 *source; - INT32 topdelta, prevdelta = -1; - INT32 originy = originPatch->originy; - - (void)patchheight; // This parameter is unused - - while (patch->topdelta != 0xff) - { - topdelta = patch->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (UINT8 *)patch + 3; - count = patch->length; - position = originy + topdelta; - - if (position < 0) - { - count += position; - source -= position; // start further down the column - position = 0; - } - - if (position + count > cacheheight) - count = cacheheight - position; - - if (count > 0) - M_Memcpy(cache + position, source, count); - - patch = (column_t *)((UINT8 *)patch + patch->length + 4); - } -} - -// -// R_DrawFlippedColumnInCache -// Similar to R_DrawColumnInCache; it draws the column inverted, however. -// -static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) -{ - INT32 count, position; - UINT8 *source, *dest; - INT32 topdelta, prevdelta = -1; - INT32 originy = originPatch->originy; - - while (patch->topdelta != 0xff) - { - topdelta = patch->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - topdelta = patchheight-patch->length-topdelta; - source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1) - count = patch->length; - position = originy + topdelta; - - if (position < 0) - { - count += position; - source += position; // start further UP the column - position = 0; - } - - if (position + count > cacheheight) - count = cacheheight - position; - - dest = cache + position; - if (count > 0) - { - for (; dest < cache + position + count; --source) - *dest++ = *source; - } - - patch = (column_t *)((UINT8 *)patch + patch->length + 4); - } -} - UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha) { RGBA_t output; @@ -334,1179 +163,6 @@ UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 al return background; } -// -// R_DrawBlendColumnInCache -// Draws a translucent column into the cache, applying a half-cooked equation to get a proper translucency value (Needs code in R_GenerateTexture()). -// -static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) -{ - INT32 count, position; - UINT8 *source, *dest; - INT32 topdelta, prevdelta = -1; - INT32 originy = originPatch->originy; - - (void)patchheight; // This parameter is unused - - while (patch->topdelta != 0xff) - { - topdelta = patch->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (UINT8 *)patch + 3; - count = patch->length; - position = originy + topdelta; - - if (position < 0) - { - count += position; - source -= position; // start further down the column - position = 0; - } - - if (position + count > cacheheight) - count = cacheheight - position; - - dest = cache + position; - if (count > 0) - { - for (; dest < cache + position + count; source++, dest++) - if (*source != 0xFF) - *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); - } - - patch = (column_t *)((UINT8 *)patch + patch->length + 4); - } -} - -// -// R_DrawBlendFlippedColumnInCache -// Similar to the one above except that the column is inverted. -// -static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) -{ - INT32 count, position; - UINT8 *source, *dest; - INT32 topdelta, prevdelta = -1; - INT32 originy = originPatch->originy; - - while (patch->topdelta != 0xff) - { - topdelta = patch->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - topdelta = patchheight-patch->length-topdelta; - source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1) - count = patch->length; - position = originy + topdelta; - - if (position < 0) - { - count += position; - source += position; // start further UP the column - position = 0; - } - - if (position + count > cacheheight) - count = cacheheight - position; - - dest = cache + position; - if (count > 0) - { - for (; dest < cache + position + count; --source, dest++) - if (*source != 0xFF) - *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); - } - - patch = (column_t *)((UINT8 *)patch + patch->length + 4); - } -} - -// -// R_GenerateTexture -// -// Allocate space for full size texture, either single patch or 'composite' -// Build the full textures from patches. -// The texture caching system is a little more hungry of memory, but has -// been simplified for the sake of highcolor (lol), dynamic ligthing, & speed. -// -// This is not optimised, but it's supposed to be executed only once -// per level, when enough memory is available. -// -static UINT8 *R_GenerateTexture(size_t texnum) -{ - UINT8 *block; - UINT8 *blocktex; - texture_t *texture; - texpatch_t *patch; - patch_t *realpatch; - UINT8 *pdata; - int x, x1, x2, i, width, height; - size_t blocksize; - column_t *patchcol; - UINT8 *colofs; - - UINT16 wadnum; - lumpnum_t lumpnum; - size_t lumplength; - - I_Assert(texnum <= (size_t)numtextures); - texture = textures[texnum]; - I_Assert(texture != NULL); - - // allocate texture column offset lookup - - // single-patch textures can have holes in them and may be used on - // 2sided lines so they need to be kept in 'packed' format - // BUT this is wrong for skies and walls with over 255 pixels, - // so check if there's holes and if not strip the posts. - if (texture->patchcount == 1) - { - boolean holey = false; - patch = texture->patches; - - wadnum = patch->wad; - lumpnum = patch->lump; - lumplength = W_LumpLengthPwad(wadnum, lumpnum); - pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - realpatch = (patch_t *)pdata; - -#ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - goto multipatch; -#endif -#ifdef WALLFLATS - if (texture->type == TEXTURETYPE_FLAT) - goto multipatch; -#endif - - // Check the patch for holes. - if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) - holey = true; - colofs = (UINT8 *)realpatch->columnofs; - for (x = 0; x < texture->width && !holey; x++) - { - column_t *col = (column_t *)((UINT8 *)realpatch + LONG(*(UINT32 *)&colofs[x<<2])); - INT32 topdelta, prevdelta = -1, y = 0; - while (col->topdelta != 0xff) - { - topdelta = col->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - if (topdelta > y) - break; - y = topdelta + col->length + 1; - col = (column_t *)((UINT8 *)col + col->length + 4); - } - if (y < texture->height) - holey = true; // this texture is HOLEy! D: - } - - // If the patch uses transparency, we have to save it this way. - if (holey) - { - texture->holes = true; - texture->flip = patch->flip; - blocksize = lumplength; - block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function - &texturecache[texnum]); - M_Memcpy(block, realpatch, blocksize); - texturememory += blocksize; - - // use the patch's column lookup - colofs = (block + 8); - texturecolumnofs[texnum] = (UINT32 *)colofs; - blocktex = block; - if (patch->flip & 1) // flip the patch horizontally - { - UINT8 *realcolofs = (UINT8 *)realpatch->columnofs; - for (x = 0; x < texture->width; x++) - *(UINT32 *)&colofs[x<<2] = realcolofs[( texture->width-1-x )<<2]; // swap with the offset of the other side of the texture - } - // we can't as easily flip the patch vertically sadly though, - // we have wait until the texture itself is drawn to do that - for (x = 0; x < texture->width; x++) - *(UINT32 *)&colofs[x<<2] = LONG(LONG(*(UINT32 *)&colofs[x<<2]) + 3); - goto done; - } - - // Otherwise, do multipatch format. - } - - // multi-patch textures (or 'composite') - multipatch: - texture->holes = false; - texture->flip = 0; - blocksize = (texture->width * 4) + (texture->width * texture->height); - texturememory += blocksize; - block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); - - memset(block, TRANSPARENTPIXEL, blocksize+1); // Transparency hack - - // columns lookup table - colofs = block; - texturecolumnofs[texnum] = (UINT32 *)colofs; - - // texture data after the lookup table - blocktex = block + (texture->width*4); - - // Composite the columns together. - for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) - { - boolean dealloc = true; - static void (*ColumnDrawerPointer)(column_t *, UINT8 *, texpatch_t *, INT32, INT32); // Column drawing function pointer. - if (patch->style != AST_COPY) - ColumnDrawerPointer = (patch->flip & 2) ? R_DrawBlendFlippedColumnInCache : R_DrawBlendColumnInCache; - else - ColumnDrawerPointer = (patch->flip & 2) ? R_DrawFlippedColumnInCache : R_DrawColumnInCache; - - wadnum = patch->wad; - lumpnum = patch->lump; - pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - lumplength = W_LumpLengthPwad(wadnum, lumpnum); - realpatch = (patch_t *)pdata; - dealloc = true; - -#ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) - { - // Dummy variables. - INT32 pngwidth, pngheight; - realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0); - } - else -#endif -#ifdef WALLFLATS - if (texture->type == TEXTURETYPE_FLAT) - realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); - else -#endif - { - (void)lumplength; - dealloc = false; - } - - x1 = patch->originx; - width = SHORT(realpatch->width); - height = SHORT(realpatch->height); - x2 = x1 + width; - - if (x1 > texture->width || x2 < 0) - continue; // patch not located within texture's x bounds, ignore - - if (patch->originy > texture->height || (patch->originy + height) < 0) - continue; // patch not located within texture's y bounds, ignore - - // patch is actually inside the texture! - // now check if texture is partly off-screen and adjust accordingly - - // left edge - if (x1 < 0) - x = 0; - else - x = x1; - - // right edge - if (x2 > texture->width) - x2 = texture->width; - - for (; x < x2; x++) - { - if (patch->flip & 1) - patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[(x1+width-1)-x])); - else - patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1])); - - // generate column ofset lookup - *(UINT32 *)&colofs[x<<2] = LONG((x * texture->height) + (texture->width*4)); - ColumnDrawerPointer(patchcol, block + LONG(*(UINT32 *)&colofs[x<<2]), patch, texture->height, height); - } - - if (dealloc) - Z_Free(realpatch); - } - -done: - // Now that the texture has been built in column cache, it is purgable from zone memory. - Z_ChangeTag(block, PU_CACHE); - return blocktex; -} - -// -// R_GetTextureNum -// -// Returns the actual texture id that we should use. -// This can either be texnum, the current frame for texnum's anim (if animated), -// or 0 if not valid. -// -INT32 R_GetTextureNum(INT32 texnum) -{ - if (texnum < 0 || texnum >= numtextures) - return 0; - return texturetranslation[texnum]; -} - -// -// R_CheckTextureCache -// -// Use this if you need to make sure the texture is cached before R_GetColumn calls -// e.g.: midtextures and FOF walls -// -void R_CheckTextureCache(INT32 tex) -{ - if (!texturecache[tex]) - R_GenerateTexture(tex); -} - -// -// R_GetColumn -// -UINT8 *R_GetColumn(fixed_t tex, INT32 col) -{ - UINT8 *data; - INT32 width = texturewidth[tex]; - - if (width & (width - 1)) - col = (UINT32)col % width; - else - col &= (width - 1); - - data = texturecache[tex]; - if (!data) - data = R_GenerateTexture(tex); - - return data + LONG(texturecolumnofs[tex][col]); -} - -// convert flats to hicolor as they are requested -// -UINT8 *R_GetFlat(lumpnum_t flatlumpnum) -{ - return W_CacheLumpNum(flatlumpnum, PU_CACHE); -} - -// -// Empty the texture cache (used for load wad at runtime) -// -void R_FlushTextureCache(void) -{ - INT32 i; - - if (numtextures) - for (i = 0; i < numtextures; i++) - Z_Free(texturecache[i]); -} - -// Need these prototypes for later; defining them here instead of r_data.h so they're "private" -int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum); -void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index); - -// -// R_LoadTextures -// Initializes the texture list with the textures from the world map. -// -#define TX_START "TX_START" -#define TX_END "TX_END" -void R_LoadTextures(void) -{ - INT32 i, w; - UINT16 j; - UINT16 texstart, texend, texturesLumpPos; - patch_t *patchlump; - texpatch_t *patch; - texture_t *texture; - - // Free previous memory before numtextures change. - if (numtextures) - { - for (i = 0; i < numtextures; i++) - { - Z_Free(textures[i]); - Z_Free(texturecache[i]); - } - Z_Free(texturetranslation); - Z_Free(textures); - Z_Free(texflats); - } - - // Load patches and textures. - - // Get the number of textures to check. - // NOTE: Make SURE the system does not process - // the markers. - // This system will allocate memory for all duplicate/patched textures even if it never uses them, - // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. - for (w = 0, numtextures = 0; w < numwadfiles; w++) - { - // Count the textures from TEXTURES lumps - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - while (texturesLumpPos != INT16_MAX) - { - numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); - } - - // Count single-patch textures - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) -#ifdef WALLFLATS - goto countflats; -#else - continue; -#endif - - texstart++; // Do not count the first marker - - // PK3s have subfolders, so we can't just make a simple sum - if (wadfiles[w]->type == RET_PK3) - { - for (j = texstart; j < texend; j++) - { - if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - numtextures++; - } - } - else // Add all the textures between TX_START and TX_END - { - numtextures += (UINT32)(texend - texstart); - } - -#ifdef WALLFLATS -countflats: - // Count flats - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); - texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) - continue; - - texstart++; // Do not count the first marker - - // PK3s have subfolders, so we can't just make a simple sum - if (wadfiles[w]->type == RET_PK3) - { - for (j = texstart; j < texend; j++) - { - if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it - numtextures++; - } - } - else // Add all the textures between F_START and F_END - { - numtextures += (UINT32)(texend - texstart); - } -#endif - } - - // If no textures found by this point, bomb out - if (!numtextures) - I_Error("No textures detected in any WADs!\n"); - - // Allocate memory and initialize to 0 for all the textures we are initialising. - // There are actually 5 buffers allocated in one for convenience. - textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); - texflats = Z_Calloc((numtextures * sizeof(*texflats)), PU_STATIC, NULL); - - // Allocate texture column offset table. - texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); - // Allocate texture referencing cache. - texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); - // Allocate texture width table. - texturewidth = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); - // Allocate texture height table. - textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); - // Create translation table for global animation. - texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); - - for (i = 0; i < numtextures; i++) - texturetranslation[i] = i; - - for (i = 0, w = 0; w < numwadfiles; w++) - { - // Get the lump numbers for the markers in the WAD, if they exist. - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - while (texturesLumpPos != INT16_MAX) - { - R_ParseTEXTURESLump(w, texturesLumpPos, &i); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); - } - } - else - { - texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); - texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); - texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); - if (texturesLumpPos != INT16_MAX) - R_ParseTEXTURESLump(w, texturesLumpPos, &i); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) -#ifdef WALLFLATS - goto checkflats; -#else - continue; -#endif - - texstart++; // Do not count the first marker - - // Work through each lump between the markers in the WAD. - for (j = 0; j < (texend - texstart); j++) - { - UINT16 wadnum = (UINT16)w; - lumpnum_t lumpnum = texstart + j; -#ifndef NO_PNG_LUMPS - size_t lumplength; -#endif - - if (wadfiles[w]->type == RET_PK3) - { - if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder - continue; // If it is then SKIP IT - } - - patchlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); -#ifndef NO_PNG_LUMPS - lumplength = W_LumpLengthPwad(wadnum, lumpnum); -#endif - - //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); - texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); - - // Set texture properties. - M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); - -#ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength)) - { - INT16 width = 0, height = 0; - Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength); - texture->width = width; - texture->height = height; - } - else -#endif - { - texture->width = SHORT(patchlump->width); - texture->height = SHORT(patchlump->height); - } - - texture->type = TEXTURETYPE_SINGLEPATCH; - texture->patchcount = 1; - texture->holes = false; - texture->flip = 0; - - // Allocate information for the texture's patches. - patch = &texture->patches[0]; - - patch->originx = patch->originy = 0; - patch->wad = (UINT16)w; - patch->lump = texstart + j; - patch->flip = 0; - - Z_Unlock(patchlump); - - texturewidth[i] = texture->width; - textureheight[i] = texture->height << FRACBITS; - i++; - } - -#ifdef WALLFLATS -checkflats: - // Yes - if (wadfiles[w]->type == RET_PK3) - { - texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); - texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); - } - else - { - texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); - texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); - } - - if (texstart == INT16_MAX || texend == INT16_MAX) - continue; - - texstart++; // Do not count the first marker - - // Work through each lump between the markers in the WAD. - for (j = 0; j < (texend - texstart); j++) - { - UINT8 *flatlump; - UINT16 wadnum = (UINT16)w; - lumpnum_t lumpnum = texstart + j; - size_t lumplength; - size_t flatsize = 0; - - if (wadfiles[w]->type == RET_PK3) - { - if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder - continue; // If it is then SKIP IT - } - - flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); - lumplength = W_LumpLengthPwad(wadnum, lumpnum); - - switch (lumplength) - { - case 4194304: // 2048x2048 lump - flatsize = 2048; - break; - case 1048576: // 1024x1024 lump - flatsize = 1024; - break; - case 262144:// 512x512 lump - flatsize = 512; - break; - case 65536: // 256x256 lump - flatsize = 256; - break; - case 16384: // 128x128 lump - flatsize = 128; - break; - case 1024: // 32x32 lump - flatsize = 32; - break; - default: // 64x64 lump - flatsize = 64; - break; - } - - //CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize); - texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); - - // Set texture properties. - M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); - -#ifndef NO_PNG_LUMPS - if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength)) - { - INT16 width = 0, height = 0; - Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength); - texture->width = width; - texture->height = height; - } - else -#endif - texture->width = texture->height = flatsize; - - texture->type = TEXTURETYPE_FLAT; - texture->patchcount = 1; - texture->holes = false; - texture->flip = 0; - - // Allocate information for the texture's patches. - patch = &texture->patches[0]; - - patch->originx = patch->originy = 0; - patch->wad = (UINT16)w; - patch->lump = texstart + j; - patch->flip = 0; - - Z_Unlock(flatlump); - - texturewidth[i] = texture->width; - textureheight[i] = texture->height << FRACBITS; - i++; - } -#endif - } - -#ifdef HWRENDER - if (rendermode == render_opengl) - HWR_LoadTextures(numtextures); -#endif -} - -static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) -{ - char *texturesToken; - size_t texturesTokenLength; - char *endPos; - char *patchName = NULL; - INT16 patchXPos; - INT16 patchYPos; - UINT8 flip = 0; - UINT8 alpha = 255; - enum patchalphastyle style = AST_COPY; - texpatch_t *resultPatch = NULL; - lumpnum_t patchLumpNum; - - // Patch identifier - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch name should be"); - } - texturesTokenLength = strlen(texturesToken); - if (texturesTokenLength>8) - { - I_Error("Error parsing TEXTURES lump: Patch name \"%s\" exceeds 8 characters",texturesToken); - } - else - { - if (patchName != NULL) - { - Z_Free(patchName); - } - patchName = (char *)Z_Malloc((texturesTokenLength+1)*sizeof(char),PU_STATIC,NULL); - M_Memcpy(patchName,texturesToken,texturesTokenLength*sizeof(char)); - patchName[texturesTokenLength] = '\0'; - } - - // Comma 1 - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after \"%s\"'s patch name should be",patchName); - } - if (strcmp(texturesToken,",")!=0) - { - I_Error("Error parsing TEXTURES lump: Expected \",\" after %s's patch name, got \"%s\"",patchName,texturesToken); - } - - // XPos - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s x coordinate should be",patchName); - } - endPos = NULL; -#ifndef AVOID_ERRNO - errno = 0; -#endif - patchXPos = strtol(texturesToken,&endPos,10); - (void)patchXPos; //unused for now - if (endPos == texturesToken // Empty string - || *endPos != '\0' // Not end of string -#ifndef AVOID_ERRNO - || errno == ERANGE // Number out-of-range -#endif - ) - { - I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); - } - - // Comma 2 - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after patch \"%s\"'s x coordinate should be",patchName); - } - if (strcmp(texturesToken,",")!=0) - { - I_Error("Error parsing TEXTURES lump: Expected \",\" after patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); - } - - // YPos - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s y coordinate should be",patchName); - } - endPos = NULL; -#ifndef AVOID_ERRNO - errno = 0; -#endif - patchYPos = strtol(texturesToken,&endPos,10); - (void)patchYPos; //unused for now - if (endPos == texturesToken // Empty string - || *endPos != '\0' // Not end of string -#ifndef AVOID_ERRNO - || errno == ERANGE // Number out-of-range -#endif - ) - { - I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s y coordinate, got \"%s\"",patchName,texturesToken); - } - Z_Free(texturesToken); - - // Patch parameters block (OPTIONAL) - // added by Monster Iestyn (22/10/16) - - // Left Curly Brace - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - ; // move on and ignore, R_ParseTextures will deal with this - else - { - if (strcmp(texturesToken,"{")==0) - { - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters should be",patchName); - } - while (strcmp(texturesToken,"}")!=0) - { - if (stricmp(texturesToken, "ALPHA")==0) - { - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - alpha = 255*strtof(texturesToken, NULL); - } - else if (stricmp(texturesToken, "STYLE")==0) - { - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (stricmp(texturesToken, "TRANSLUCENT")==0) - style = AST_TRANSLUCENT; - else if (stricmp(texturesToken, "ADD")==0) - style = AST_ADD; - else if (stricmp(texturesToken, "SUBTRACT")==0) - style = AST_SUBTRACT; - else if (stricmp(texturesToken, "REVERSESUBTRACT")==0) - style = AST_REVERSESUBTRACT; - else if (stricmp(texturesToken, "MODULATE")==0) - style = AST_MODULATE; - } - else if (stricmp(texturesToken, "FLIPX")==0) - flip |= 1; - else if (stricmp(texturesToken, "FLIPY")==0) - flip |= 2; - Z_Free(texturesToken); - - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters or right curly brace should be",patchName); - } - } - } - else - { - // this is not what we wanted... - // undo last read so R_ParseTextures can re-get the token for its own purposes - M_UnGetToken(); - } - Z_Free(texturesToken); - } - - if (actuallyLoadPatch == true) - { - // Check lump exists - patchLumpNum = W_GetNumForName(patchName); - // If so, allocate memory for texpatch_t and fill 'er up - resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL); - resultPatch->originx = patchXPos; - resultPatch->originy = patchYPos; - resultPatch->lump = patchLumpNum & 65535; - resultPatch->wad = patchLumpNum>>16; - resultPatch->flip = flip; - resultPatch->alpha = alpha; - resultPatch->style = style; - // Clean up a little after ourselves - Z_Free(patchName); - // Then return it - return resultPatch; - } - else - { - Z_Free(patchName); - return NULL; - } -} - -static texture_t *R_ParseTexture(boolean actuallyLoadTexture) -{ - char *texturesToken; - size_t texturesTokenLength; - char *endPos; - INT32 newTextureWidth; - INT32 newTextureHeight; - texture_t *resultTexture = NULL; - texpatch_t *newPatch; - char newTextureName[9]; // no longer dynamically allocated - - // Texture name - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture name should be"); - } - texturesTokenLength = strlen(texturesToken); - if (texturesTokenLength>8) - { - I_Error("Error parsing TEXTURES lump: Texture name \"%s\" exceeds 8 characters",texturesToken); - } - else - { - memset(&newTextureName, 0, 9); - M_Memcpy(newTextureName, texturesToken, texturesTokenLength); - // ^^ we've confirmed that the token is <= 8 characters so it will never overflow a 9 byte char buffer - strupr(newTextureName); // Just do this now so we don't have to worry about it - } - Z_Free(texturesToken); - - // Comma 1 - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after texture \"%s\"'s name should be",newTextureName); - } - else if (strcmp(texturesToken,",")!=0) - { - I_Error("Error parsing TEXTURES lump: Expected \",\" after texture \"%s\"'s name, got \"%s\"",newTextureName,texturesToken); - } - Z_Free(texturesToken); - - // Width - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture \"%s\"'s width should be",newTextureName); - } - endPos = NULL; -#ifndef AVOID_ERRNO - errno = 0; -#endif - newTextureWidth = strtol(texturesToken,&endPos,10); - if (endPos == texturesToken // Empty string - || *endPos != '\0' // Not end of string -#ifndef AVOID_ERRNO - || errno == ERANGE // Number out-of-range -#endif - || newTextureWidth < 0) // Number is not positive - { - I_Error("Error parsing TEXTURES lump: Expected a positive integer for texture \"%s\"'s width, got \"%s\"",newTextureName,texturesToken); - } - Z_Free(texturesToken); - - // Comma 2 - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after texture \"%s\"'s width should be",newTextureName); - } - if (strcmp(texturesToken,",")!=0) - { - I_Error("Error parsing TEXTURES lump: Expected \",\" after texture \"%s\"'s width, got \"%s\"",newTextureName,texturesToken); - } - Z_Free(texturesToken); - - // Height - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture \"%s\"'s height should be",newTextureName); - } - endPos = NULL; -#ifndef AVOID_ERRNO - errno = 0; -#endif - newTextureHeight = strtol(texturesToken,&endPos,10); - if (endPos == texturesToken // Empty string - || *endPos != '\0' // Not end of string -#ifndef AVOID_ERRNO - || errno == ERANGE // Number out-of-range -#endif - || newTextureHeight < 0) // Number is not positive - { - I_Error("Error parsing TEXTURES lump: Expected a positive integer for texture \"%s\"'s height, got \"%s\"",newTextureName,texturesToken); - } - Z_Free(texturesToken); - - // Left Curly Brace - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where open curly brace for texture \"%s\" should be",newTextureName); - } - if (strcmp(texturesToken,"{")==0) - { - if (actuallyLoadTexture) - { - // Allocate memory for a zero-patch texture. Obviously, we'll be adding patches momentarily. - resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t),PU_STATIC,NULL); - M_Memcpy(resultTexture->name, newTextureName, 8); - resultTexture->width = newTextureWidth; - resultTexture->height = newTextureHeight; - resultTexture->type = TEXTURETYPE_COMPOSITE; - } - Z_Free(texturesToken); - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch definition for texture \"%s\" should be",newTextureName); - } - while (strcmp(texturesToken,"}")!=0) - { - if (stricmp(texturesToken, "PATCH")==0) - { - Z_Free(texturesToken); - if (resultTexture) - { - // Get that new patch - newPatch = R_ParsePatch(true); - // Make room for the new patch - resultTexture = Z_Realloc(resultTexture, sizeof(texture_t) + (resultTexture->patchcount+1)*sizeof(texpatch_t), PU_STATIC, NULL); - // Populate the uninitialized values in the new patch entry of our array - M_Memcpy(&resultTexture->patches[resultTexture->patchcount], newPatch, sizeof(texpatch_t)); - // Account for the new number of patches in the texture - resultTexture->patchcount++; - // Then free up the memory assigned to R_ParsePatch, as it's unneeded now - Z_Free(newPatch); - } - else - { - R_ParsePatch(false); - } - } - else - { - I_Error("Error parsing TEXTURES lump: Expected \"PATCH\" in texture \"%s\", got \"%s\"",newTextureName,texturesToken); - } - - texturesToken = M_GetToken(NULL); - if (texturesToken == NULL) - { - I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch declaration or right curly brace for texture \"%s\" should be",newTextureName); - } - } - if (resultTexture && resultTexture->patchcount == 0) - { - I_Error("Error parsing TEXTURES lump: Texture \"%s\" must have at least one patch",newTextureName); - } - } - else - { - I_Error("Error parsing TEXTURES lump: Expected \"{\" for texture \"%s\", got \"%s\"",newTextureName,texturesToken); - } - Z_Free(texturesToken); - - if (actuallyLoadTexture) return resultTexture; - else return NULL; -} - -// Parses the TEXTURES lump... but just to count the number of textures. -int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum) -{ - char *texturesLump; - size_t texturesLumpLength; - char *texturesText; - UINT32 numTexturesInLump = 0; - char *texturesToken; - - // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll - // need to make a space of memory where I can ensure that it will terminate - // correctly. Start by loading the relevant data from the WAD. - texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); - // If that didn't exist, we have nothing to do here. - if (texturesLump == NULL) return 0; - // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. - texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); - texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); - // Now move the contents of the lump into this new location. - memmove(texturesText,texturesLump,texturesLumpLength); - // Make damn well sure the last character in our new memory location is \0. - texturesText[texturesLumpLength] = '\0'; - // Finally, free up the memory from the first data load, because we really - // don't need it. - Z_Free(texturesLump); - - texturesToken = M_GetToken(texturesText); - while (texturesToken != NULL) - { - if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) - { - numTexturesInLump++; - Z_Free(texturesToken); - R_ParseTexture(false); - } - else - { - I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); - } - texturesToken = M_GetToken(NULL); - } - Z_Free(texturesToken); - Z_Free((void *)texturesText); - - return numTexturesInLump; -} - -// Parses the TEXTURES lump... for real, this time. -void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex) -{ - char *texturesLump; - size_t texturesLumpLength; - char *texturesText; - char *texturesToken; - texture_t *newTexture; - - I_Assert(texindex != NULL); - - // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll - // need to make a space of memory where I can ensure that it will terminate - // correctly. Start by loading the relevant data from the WAD. - texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); - // If that didn't exist, we have nothing to do here. - if (texturesLump == NULL) return; - // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. - texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); - texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); - // Now move the contents of the lump into this new location. - memmove(texturesText,texturesLump,texturesLumpLength); - // Make damn well sure the last character in our new memory location is \0. - texturesText[texturesLumpLength] = '\0'; - // Finally, free up the memory from the first data load, because we really - // don't need it. - Z_Free(texturesLump); - - texturesToken = M_GetToken(texturesText); - while (texturesToken != NULL) - { - if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) - { - Z_Free(texturesToken); - // Get the new texture - newTexture = R_ParseTexture(true); - // Store the new texture - textures[*texindex] = newTexture; - texturewidth[*texindex] = newTexture->width; - textureheight[*texindex] = newTexture->height << FRACBITS; - // Increment i back in R_LoadTextures() - (*texindex)++; - } - else - { - I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); - } - texturesToken = M_GetToken(NULL); - } - Z_Free(texturesToken); - Z_Free((void *)texturesText); -} - #ifdef EXTRACOLORMAPLUMPS static lumplist_t *colormaplumps = NULL; ///\todo free leak static size_t numcolormaplumps = 0; @@ -1561,54 +217,6 @@ static void R_InitExtraColormaps(void) } #endif -// Search for flat name. -lumpnum_t R_GetFlatNumForName(const char *name) -{ - INT32 i; - lumpnum_t lump; - lumpnum_t start; - lumpnum_t end; - - // Scan wad files backwards so patched flats take preference. - for (i = numwadfiles - 1; i >= 0; i--) - { - switch (wadfiles[i]->type) - { - case RET_WAD: - if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) - { - if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) - continue; - else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) - continue; - } - else - if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX) - continue; - break; - case RET_PK3: - if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) - continue; - if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) - continue; - break; - default: - continue; - } - - // Now find lump with specified name in that range. - lump = W_CheckNumForNamePwad(name, (UINT16)i, start); - if (lump < end) - { - lump += (i<<16); // found it, in our constraints - break; - } - lump = LUMPERROR; - } - - return lump; -} - // // R_InitSpriteLumps // Finds the width and hoffset of all sprites in the wad, so the sprite does not need to be @@ -2566,74 +1174,6 @@ void R_InitData(void) R_InitColormaps(); } -void R_ClearTextureNumCache(boolean btell) -{ - if (tidcache) - Z_Free(tidcache); - tidcache = NULL; - if (btell) - CONS_Debug(DBG_SETUP, "Fun Fact: There are %d textures used in this map.\n", tidcachelen); - tidcachelen = 0; -} - -// -// R_CheckTextureNumForName -// -// Check whether texture is available. Filter out NoTexture indicator. -// -INT32 R_CheckTextureNumForName(const char *name) -{ - INT32 i; - - // "NoTexture" marker. - if (name[0] == '-') - return 0; - - for (i = 0; i < tidcachelen; i++) - if (!strncasecmp(tidcache[i].name, name, 8)) - return tidcache[i].id; - - // Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier - //for (i = 0; i < numtextures; i++) <- old - for (i = (numtextures - 1); i >= 0; i--) // <- new - if (!strncasecmp(textures[i]->name, name, 8)) - { - tidcachelen++; - Z_Realloc(tidcache, tidcachelen * sizeof(*tidcache), PU_STATIC, &tidcache); - strncpy(tidcache[tidcachelen-1].name, name, 8); - tidcache[tidcachelen-1].name[8] = '\0'; -#ifndef ZDEBUG - CONS_Debug(DBG_SETUP, "texture #%s: %s\n", sizeu1(tidcachelen), tidcache[tidcachelen-1].name); -#endif - tidcache[tidcachelen-1].id = i; - return i; - } - - return -1; -} - -// -// R_TextureNumForName -// -// Calls R_CheckTextureNumForName, aborts with error message. -// -INT32 R_TextureNumForName(const char *name) -{ - const INT32 i = R_CheckTextureNumForName(name); - - if (i == -1) - { - static INT32 redwall = -2; - CONS_Debug(DBG_SETUP, "WARNING: R_TextureNumForName: %.8s not found\n", name); - if (redwall == -2) - redwall = R_CheckTextureNumForName("REDWALL"); - if (redwall != -1) - return redwall; - return 1; - } - return i; -} - // // R_PrecacheLevel // diff --git a/src/r_data.h b/src/r_data.h index f028f2f5d..452f5e434 100644 --- a/src/r_data.h +++ b/src/r_data.h @@ -22,103 +22,31 @@ #pragma interface #endif +// Store lists of lumps for F_START/F_END etc. +typedef struct +{ + UINT16 wadfile; + UINT16 firstlump; + size_t numlumps; +} lumplist_t; + // Possible alpha types for a patch. enum patchalphastyle {AST_COPY, AST_TRANSLUCENT, AST_ADD, AST_SUBTRACT, AST_REVERSESUBTRACT, AST_MODULATE, AST_OVERLAY}; UINT32 ASTBlendPixel(RGBA_t background, RGBA_t foreground, int style, UINT8 alpha); UINT8 ASTBlendPixel_8bpp(UINT8 background, UINT8 foreground, int style, UINT8 alpha); -UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); - -// moved here for r_sky.c (texpatch_t is used) - -// A single patch from a texture definition, -// basically a rectangular area within -// the texture rectangle. -typedef struct -{ - // Block origin (always UL), which has already accounted for the internal origin of the patch. - INT16 originx, originy; - UINT16 wad, lump; - UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both - UINT8 alpha; // Translucency value - enum patchalphastyle style; -} texpatch_t; - -// texture type -enum -{ - TEXTURETYPE_UNKNOWN, - TEXTURETYPE_SINGLEPATCH, - TEXTURETYPE_COMPOSITE, -#ifdef WALLFLATS - TEXTURETYPE_FLAT, -#endif -}; - -// A maptexturedef_t describes a rectangular texture, -// which is composed of one or more mappatch_t structures -// that arrange graphic patches. -typedef struct -{ - // Keep name for switch changing, etc. - char name[8]; - UINT8 type; // TEXTURETYPE_ - INT16 width, height; - boolean holes; - UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both - - // All the patches[patchcount] are drawn back to front into the cached texture. - INT16 patchcount; - texpatch_t patches[0]; -} texture_t; - -typedef struct -{ - UINT8 *flat; - INT16 width, height; -} textureflat_t; - -// all loaded and prepared textures from the start of the game -extern texture_t **textures; -extern textureflat_t *texflats; - -extern INT32 *texturewidth; -extern fixed_t *textureheight; // needed for texture pegging - extern INT16 color8to16[256]; // remap color index to highcolor extern INT16 *hicolormaps; // remap high colors to high colors.. extern CV_PossibleValue_t Color_cons_t[]; -// Load TEXTURES definitions, create lookup tables -void R_LoadTextures(void); -void R_FlushTextureCache(void); - -INT32 R_GetTextureNum(INT32 texnum); -void R_CheckTextureCache(INT32 tex); - -// Retrieve column data for span blitting. -UINT8 *R_GetColumn(fixed_t tex, INT32 col); -UINT8 *R_GetFlat(lumpnum_t flatnum); - // I/O, setting up the stuff. void R_InitData(void); void R_PrecacheLevel(void); extern size_t flatmemory, spritememory, texturememory; -// Retrieval. -// Floor/ceiling opaque texture tiles, -// lookup by name. For animation? -lumpnum_t R_GetFlatNumForName(const char *name); - -// Called by P_Ticker for switches and animations, -// returns the texture number for the texture name. -void R_ClearTextureNumCache(boolean btell); -INT32 R_TextureNumForName(const char *name); -INT32 R_CheckTextureNumForName(const char *name); - // Extra Colormap lumps (C_START/C_END) are not used anywhere // Uncomment to enable //#define EXTRACOLORMAPLUMPS @@ -173,6 +101,4 @@ const char *R_NameForColormap(extracolormap_t *extra_colormap); UINT8 NearestColor(UINT8 r, UINT8 g, UINT8 b); -extern INT32 numtextures; - #endif diff --git a/src/r_local.h b/src/r_local.h index 379d55205..2c72624ff 100644 --- a/src/r_local.h +++ b/src/r_local.h @@ -31,6 +31,7 @@ #include "r_plane.h" #include "r_sky.h" #include "r_data.h" +#include "r_textures.h" #include "r_things.h" #include "r_draw.h" diff --git a/src/r_main.h b/src/r_main.h index 143cc1de0..e6f33d357 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -16,6 +16,7 @@ #include "d_player.h" #include "r_data.h" +#include "r_textures.h" // // POV related. diff --git a/src/r_picformats.c b/src/r_picformats.c index cafe30d7e..b907ac4d4 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -16,6 +16,7 @@ #include "dehacked.h" #include "i_video.h" #include "r_data.h" +#include "r_textures.h" #include "r_draw.h" #include "r_picformats.h" #include "r_things.h" @@ -66,6 +67,8 @@ fixed_t sinang2rad[ROTANGLES]; * \param intopoffset Input picture top offset, for patches. * \param flags Input picture flags. * \return A pointer to the converted picture. + * \sa Picture_PatchConvert + * \sa Picture_FlatConvert */ void *Picture_Convert( pictureformat_t informat, void *picture, pictureformat_t outformat, diff --git a/src/r_plane.c b/src/r_plane.c index 43c097a23..982354a5f 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -19,6 +19,7 @@ #include "p_setup.h" // levelflats #include "p_slopes.h" #include "r_data.h" +#include "r_textures.h" #include "r_local.h" #include "r_state.h" #include "r_splats.h" // faB(21jan):testing diff --git a/src/r_plane.h b/src/r_plane.h index d9ba5c56b..5d92d2e4b 100644 --- a/src/r_plane.h +++ b/src/r_plane.h @@ -16,6 +16,7 @@ #include "screen.h" // needs MAXVIDWIDTH/MAXVIDHEIGHT #include "r_data.h" +#include "r_textures.h" #include "p_polyobj.h" #define MAXVISPLANES 512 diff --git a/src/r_portal.h b/src/r_portal.h index c46ddfdab..642a5b211 100644 --- a/src/r_portal.h +++ b/src/r_portal.h @@ -15,6 +15,7 @@ #define __R_PORTAL__ #include "r_data.h" +#include "r_textures.h" #include "r_plane.h" // visplanes /** Portal structure for the software renderer. diff --git a/src/r_textures.c b/src/r_textures.c new file mode 100644 index 000000000..c9c8fd937 --- /dev/null +++ b/src/r_textures.c @@ -0,0 +1,1441 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_textures.c +/// \brief Texture generation. + +#include "doomdef.h" +#include "g_game.h" +#include "i_video.h" +#include "r_local.h" +#include "r_sky.h" +#include "p_local.h" +#include "m_misc.h" +#include "r_data.h" +#include "r_textures.h" +#include "r_picformats.h" +#include "w_wad.h" +#include "z_zone.h" +#include "p_setup.h" // levelflats +#include "byteptr.h" +#include "dehacked.h" + +// I don't know what this is even for, but r_data.c had it. +#ifdef _WIN32 +#include // alloca(sizeof) +#endif + +#ifdef HWRENDER +#include "hardware/hw_main.h" // HWR_LoadTextures +#endif + +#include + +// +// MAPTEXTURE_T CACHING +// When a texture is first needed, it counts the number of composite columns +// required in the texture and allocates space for a column directory and +// any new columns. +// The directory will simply point inside other patches if there is only one +// patch in a given column, but any columns with multiple patches will have +// new column_ts generated. +// + +INT32 numtextures = 0; // total number of textures found, +// size of following tables + +texture_t **textures = NULL; +textureflat_t *texflats = NULL; +UINT32 **texturecolumnofs; // column offset lookup table for each texture +UINT8 **texturecache; // graphics data for each generated full-size texture + +INT32 *texturewidth; +fixed_t *textureheight; // needed for texture pegging + +INT32 *texturetranslation; + +// Painfully simple texture id cacheing to make maps load faster. :3 +static struct { + char name[9]; + INT32 id; +} *tidcache = NULL; +static INT32 tidcachelen = 0; + +// +// R_DrawColumnInCache +// Clip and draw a column from a patch into a cached post. +// +static inline void R_DrawColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +{ + INT32 count, position; + UINT8 *source; + INT32 topdelta, prevdelta = -1; + INT32 originy = originPatch->originy; + + (void)patchheight; // This parameter is unused + + while (patch->topdelta != 0xff) + { + topdelta = patch->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (UINT8 *)patch + 3; + count = patch->length; + position = originy + topdelta; + + if (position < 0) + { + count += position; + source -= position; // start further down the column + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + if (count > 0) + M_Memcpy(cache + position, source, count); + + patch = (column_t *)((UINT8 *)patch + patch->length + 4); + } +} + +// +// R_DrawFlippedColumnInCache +// Similar to R_DrawColumnInCache; it draws the column inverted, however. +// +static inline void R_DrawFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +{ + INT32 count, position; + UINT8 *source, *dest; + INT32 topdelta, prevdelta = -1; + INT32 originy = originPatch->originy; + + while (patch->topdelta != 0xff) + { + topdelta = patch->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + topdelta = patchheight-patch->length-topdelta; + source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1) + count = patch->length; + position = originy + topdelta; + + if (position < 0) + { + count += position; + source += position; // start further UP the column + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + dest = cache + position; + if (count > 0) + { + for (; dest < cache + position + count; --source) + *dest++ = *source; + } + + patch = (column_t *)((UINT8 *)patch + patch->length + 4); + } +} + +// +// R_DrawBlendColumnInCache +// Draws a translucent column into the cache, applying a half-cooked equation to get a proper translucency value (Needs code in R_GenerateTexture()). +// +static inline void R_DrawBlendColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +{ + INT32 count, position; + UINT8 *source, *dest; + INT32 topdelta, prevdelta = -1; + INT32 originy = originPatch->originy; + + (void)patchheight; // This parameter is unused + + while (patch->topdelta != 0xff) + { + topdelta = patch->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (UINT8 *)patch + 3; + count = patch->length; + position = originy + topdelta; + + if (position < 0) + { + count += position; + source -= position; // start further down the column + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + dest = cache + position; + if (count > 0) + { + for (; dest < cache + position + count; source++, dest++) + if (*source != 0xFF) + *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); + } + + patch = (column_t *)((UINT8 *)patch + patch->length + 4); + } +} + +// +// R_DrawBlendFlippedColumnInCache +// Similar to the one above except that the column is inverted. +// +static inline void R_DrawBlendFlippedColumnInCache(column_t *patch, UINT8 *cache, texpatch_t *originPatch, INT32 cacheheight, INT32 patchheight) +{ + INT32 count, position; + UINT8 *source, *dest; + INT32 topdelta, prevdelta = -1; + INT32 originy = originPatch->originy; + + while (patch->topdelta != 0xff) + { + topdelta = patch->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + topdelta = patchheight-patch->length-topdelta; + source = (UINT8 *)patch + 2 + patch->length; // patch + 3 + (patch->length-1) + count = patch->length; + position = originy + topdelta; + + if (position < 0) + { + count += position; + source += position; // start further UP the column + position = 0; + } + + if (position + count > cacheheight) + count = cacheheight - position; + + dest = cache + position; + if (count > 0) + { + for (; dest < cache + position + count; --source, dest++) + if (*source != 0xFF) + *dest = ASTBlendPixel_8bpp(*dest, *source, originPatch->style, originPatch->alpha); + } + + patch = (column_t *)((UINT8 *)patch + patch->length + 4); + } +} + +// +// R_GenerateTexture +// +// Allocate space for full size texture, either single patch or 'composite' +// Build the full textures from patches. +// The texture caching system is a little more hungry of memory, but has +// been simplified for the sake of highcolor (lol), dynamic ligthing, & speed. +// +// This is not optimised, but it's supposed to be executed only once +// per level, when enough memory is available. +// +UINT8 *R_GenerateTexture(size_t texnum) +{ + UINT8 *block; + UINT8 *blocktex; + texture_t *texture; + texpatch_t *patch; + patch_t *realpatch; + UINT8 *pdata; + int x, x1, x2, i, width, height; + size_t blocksize; + column_t *patchcol; + UINT8 *colofs; + + UINT16 wadnum; + lumpnum_t lumpnum; + size_t lumplength; + + I_Assert(texnum <= (size_t)numtextures); + texture = textures[texnum]; + I_Assert(texture != NULL); + + // allocate texture column offset lookup + + // single-patch textures can have holes in them and may be used on + // 2sided lines so they need to be kept in 'packed' format + // BUT this is wrong for skies and walls with over 255 pixels, + // so check if there's holes and if not strip the posts. + if (texture->patchcount == 1) + { + boolean holey = false; + patch = texture->patches; + + wadnum = patch->wad; + lumpnum = patch->lump; + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + realpatch = (patch_t *)pdata; + +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) + goto multipatch; +#endif +#ifdef WALLFLATS + if (texture->type == TEXTURETYPE_FLAT) + goto multipatch; +#endif + + // Check the patch for holes. + if (texture->width > SHORT(realpatch->width) || texture->height > SHORT(realpatch->height)) + holey = true; + colofs = (UINT8 *)realpatch->columnofs; + for (x = 0; x < texture->width && !holey; x++) + { + column_t *col = (column_t *)((UINT8 *)realpatch + LONG(*(UINT32 *)&colofs[x<<2])); + INT32 topdelta, prevdelta = -1, y = 0; + while (col->topdelta != 0xff) + { + topdelta = col->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + if (topdelta > y) + break; + y = topdelta + col->length + 1; + col = (column_t *)((UINT8 *)col + col->length + 4); + } + if (y < texture->height) + holey = true; // this texture is HOLEy! D: + } + + // If the patch uses transparency, we have to save it this way. + if (holey) + { + texture->holes = true; + texture->flip = patch->flip; + blocksize = lumplength; + block = Z_Calloc(blocksize, PU_STATIC, // will change tag at end of this function + &texturecache[texnum]); + M_Memcpy(block, realpatch, blocksize); + texturememory += blocksize; + + // use the patch's column lookup + colofs = (block + 8); + texturecolumnofs[texnum] = (UINT32 *)colofs; + blocktex = block; + if (patch->flip & 1) // flip the patch horizontally + { + UINT8 *realcolofs = (UINT8 *)realpatch->columnofs; + for (x = 0; x < texture->width; x++) + *(UINT32 *)&colofs[x<<2] = realcolofs[( texture->width-1-x )<<2]; // swap with the offset of the other side of the texture + } + // we can't as easily flip the patch vertically sadly though, + // we have wait until the texture itself is drawn to do that + for (x = 0; x < texture->width; x++) + *(UINT32 *)&colofs[x<<2] = LONG(LONG(*(UINT32 *)&colofs[x<<2]) + 3); + goto done; + } + + // Otherwise, do multipatch format. + } + + // multi-patch textures (or 'composite') + multipatch: + texture->holes = false; + texture->flip = 0; + blocksize = (texture->width * 4) + (texture->width * texture->height); + texturememory += blocksize; + block = Z_Malloc(blocksize+1, PU_STATIC, &texturecache[texnum]); + + memset(block, TRANSPARENTPIXEL, blocksize+1); // Transparency hack + + // columns lookup table + colofs = block; + texturecolumnofs[texnum] = (UINT32 *)colofs; + + // texture data after the lookup table + blocktex = block + (texture->width*4); + + // Composite the columns together. + for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) + { + boolean dealloc = true; + static void (*ColumnDrawerPointer)(column_t *, UINT8 *, texpatch_t *, INT32, INT32); // Column drawing function pointer. + if (patch->style != AST_COPY) + ColumnDrawerPointer = (patch->flip & 2) ? R_DrawBlendFlippedColumnInCache : R_DrawBlendColumnInCache; + else + ColumnDrawerPointer = (patch->flip & 2) ? R_DrawFlippedColumnInCache : R_DrawColumnInCache; + + wadnum = patch->wad; + lumpnum = patch->lump; + pdata = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + realpatch = (patch_t *)pdata; + dealloc = true; + +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((UINT8 *)realpatch, lumplength)) + { + // Dummy variables. + INT32 pngwidth, pngheight; + realpatch = (patch_t *)Picture_PNGConvert((UINT8 *)realpatch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, lumplength, NULL, 0); + } + else +#endif +#ifdef WALLFLATS + if (texture->type == TEXTURETYPE_FLAT) + realpatch = (patch_t *)Picture_Convert(PICFMT_FLAT, pdata, PICFMT_PATCH, 0, NULL, texture->width, texture->height, 0, 0, 0); + else +#endif + { + (void)lumplength; + dealloc = false; + } + + x1 = patch->originx; + width = SHORT(realpatch->width); + height = SHORT(realpatch->height); + x2 = x1 + width; + + if (x1 > texture->width || x2 < 0) + continue; // patch not located within texture's x bounds, ignore + + if (patch->originy > texture->height || (patch->originy + height) < 0) + continue; // patch not located within texture's y bounds, ignore + + // patch is actually inside the texture! + // now check if texture is partly off-screen and adjust accordingly + + // left edge + if (x1 < 0) + x = 0; + else + x = x1; + + // right edge + if (x2 > texture->width) + x2 = texture->width; + + for (; x < x2; x++) + { + if (patch->flip & 1) + patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[(x1+width-1)-x])); + else + patchcol = (column_t *)((UINT8 *)realpatch + LONG(realpatch->columnofs[x-x1])); + + // generate column ofset lookup + *(UINT32 *)&colofs[x<<2] = LONG((x * texture->height) + (texture->width*4)); + ColumnDrawerPointer(patchcol, block + LONG(*(UINT32 *)&colofs[x<<2]), patch, texture->height, height); + } + + if (dealloc) + Z_Free(realpatch); + } + +done: + // Now that the texture has been built in column cache, it is purgable from zone memory. + Z_ChangeTag(block, PU_CACHE); + return blocktex; +} + +// +// R_GetTextureNum +// +// Returns the actual texture id that we should use. +// This can either be texnum, the current frame for texnum's anim (if animated), +// or 0 if not valid. +// +INT32 R_GetTextureNum(INT32 texnum) +{ + if (texnum < 0 || texnum >= numtextures) + return 0; + return texturetranslation[texnum]; +} + +// +// R_CheckTextureCache +// +// Use this if you need to make sure the texture is cached before R_GetColumn calls +// e.g.: midtextures and FOF walls +// +void R_CheckTextureCache(INT32 tex) +{ + if (!texturecache[tex]) + R_GenerateTexture(tex); +} + +// +// R_GetColumn +// +UINT8 *R_GetColumn(fixed_t tex, INT32 col) +{ + UINT8 *data; + INT32 width = texturewidth[tex]; + + if (width & (width - 1)) + col = (UINT32)col % width; + else + col &= (width - 1); + + data = texturecache[tex]; + if (!data) + data = R_GenerateTexture(tex); + + return data + LONG(texturecolumnofs[tex][col]); +} + +// convert flats to hicolor as they are requested +// +UINT8 *R_GetFlat(lumpnum_t flatlumpnum) +{ + return W_CacheLumpNum(flatlumpnum, PU_CACHE); +} + +// +// Empty the texture cache (used for load wad at runtime) +// +void R_FlushTextureCache(void) +{ + INT32 i; + + if (numtextures) + for (i = 0; i < numtextures; i++) + Z_Free(texturecache[i]); +} + +// Need these prototypes for later; defining them here instead of r_data.h so they're "private" +int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum); +void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *index); + +// +// R_LoadTextures +// Initializes the texture list with the textures from the world map. +// +#define TX_START "TX_START" +#define TX_END "TX_END" +void R_LoadTextures(void) +{ + INT32 i, w; + UINT16 j; + UINT16 texstart, texend, texturesLumpPos; + patch_t *patchlump; + texpatch_t *patch; + texture_t *texture; + + // Free previous memory before numtextures change. + if (numtextures) + { + for (i = 0; i < numtextures; i++) + { + Z_Free(textures[i]); + Z_Free(texturecache[i]); + } + Z_Free(texturetranslation); + Z_Free(textures); + Z_Free(texflats); + } + + // Load patches and textures. + + // Get the number of textures to check. + // NOTE: Make SURE the system does not process + // the markers. + // This system will allocate memory for all duplicate/patched textures even if it never uses them, + // but the alternative is to spend a ton of time checking and re-checking all previous entries just to skip any potentially patched textures. + for (w = 0, numtextures = 0; w < numwadfiles; w++) + { + // Count the textures from TEXTURES lumps + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + while (texturesLumpPos != INT16_MAX) + { + numtextures += R_CountTexturesInTEXTURESLump((UINT16)w, (UINT16)texturesLumpPos); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); + } + + // Count single-patch textures + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); + texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) +#ifdef WALLFLATS + goto countflats; +#else + continue; +#endif + + texstart++; // Do not count the first marker + + // PK3s have subfolders, so we can't just make a simple sum + if (wadfiles[w]->type == RET_PK3) + { + for (j = texstart; j < texend; j++) + { + if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it + numtextures++; + } + } + else // Add all the textures between TX_START and TX_END + { + numtextures += (UINT32)(texend - texstart); + } + +#ifdef WALLFLATS +countflats: + // Count flats + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) + continue; + + texstart++; // Do not count the first marker + + // PK3s have subfolders, so we can't just make a simple sum + if (wadfiles[w]->type == RET_PK3) + { + for (j = texstart; j < texend; j++) + { + if (!W_IsLumpFolder((UINT16)w, j)) // Check if lump is a folder; if not, then count it + numtextures++; + } + } + else // Add all the textures between F_START and F_END + { + numtextures += (UINT32)(texend - texstart); + } +#endif + } + + // If no textures found by this point, bomb out + if (!numtextures) + I_Error("No textures detected in any WADs!\n"); + + // Allocate memory and initialize to 0 for all the textures we are initialising. + // There are actually 5 buffers allocated in one for convenience. + textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); + texflats = Z_Calloc((numtextures * sizeof(*texflats)), PU_STATIC, NULL); + + // Allocate texture column offset table. + texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); + // Allocate texture referencing cache. + texturecache = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 2)); + // Allocate texture width table. + texturewidth = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 3)); + // Allocate texture height table. + textureheight = (void *)((UINT8 *)textures + ((numtextures * sizeof(void *)) * 4)); + // Create translation table for global animation. + texturetranslation = Z_Malloc((numtextures + 1) * sizeof(*texturetranslation), PU_STATIC, NULL); + + for (i = 0; i < numtextures; i++) + texturetranslation[i] = i; + + for (i = 0, w = 0; w < numwadfiles; w++) + { + // Get the lump numbers for the markers in the WAD, if they exist. + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("textures/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("textures/", (UINT16)w, texstart); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + while (texturesLumpPos != INT16_MAX) + { + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, texturesLumpPos + 1); + } + } + else + { + texstart = W_CheckNumForNamePwad(TX_START, (UINT16)w, 0); + texend = W_CheckNumForNamePwad(TX_END, (UINT16)w, 0); + texturesLumpPos = W_CheckNumForNamePwad("TEXTURES", (UINT16)w, 0); + if (texturesLumpPos != INT16_MAX) + R_ParseTEXTURESLump(w, texturesLumpPos, &i); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) +#ifdef WALLFLATS + goto checkflats; +#else + continue; +#endif + + texstart++; // Do not count the first marker + + // Work through each lump between the markers in the WAD. + for (j = 0; j < (texend - texstart); j++) + { + UINT16 wadnum = (UINT16)w; + lumpnum_t lumpnum = texstart + j; +#ifndef NO_PNG_LUMPS + size_t lumplength; +#endif + + if (wadfiles[w]->type == RET_PK3) + { + if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder + continue; // If it is then SKIP IT + } + + patchlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); +#ifndef NO_PNG_LUMPS + lumplength = W_LumpLengthPwad(wadnum, lumpnum); +#endif + + //CONS_Printf("\n\"%s\" is a single patch, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),patchlump->width, patchlump->height); + texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); + + // Set texture properties. + M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((UINT8 *)patchlump, lumplength)) + { + INT16 width = 0, height = 0; + Picture_PNGDimensions((UINT8 *)patchlump, &width, &height, lumplength); + texture->width = width; + texture->height = height; + } + else +#endif + { + texture->width = SHORT(patchlump->width); + texture->height = SHORT(patchlump->height); + } + + texture->type = TEXTURETYPE_SINGLEPATCH; + texture->patchcount = 1; + texture->holes = false; + texture->flip = 0; + + // Allocate information for the texture's patches. + patch = &texture->patches[0]; + + patch->originx = patch->originy = 0; + patch->wad = (UINT16)w; + patch->lump = texstart + j; + patch->flip = 0; + + Z_Unlock(patchlump); + + texturewidth[i] = texture->width; + textureheight[i] = texture->height << FRACBITS; + i++; + } + +#ifdef WALLFLATS +checkflats: + // Yes + if (wadfiles[w]->type == RET_PK3) + { + texstart = W_CheckNumForFolderStartPK3("flats/", (UINT16)w, 0); + texend = W_CheckNumForFolderEndPK3("flats/", (UINT16)w, texstart); + } + else + { + texstart = W_CheckNumForNamePwad("F_START", (UINT16)w, 0); + texend = W_CheckNumForNamePwad("F_END", (UINT16)w, texstart); + } + + if (texstart == INT16_MAX || texend == INT16_MAX) + continue; + + texstart++; // Do not count the first marker + + // Work through each lump between the markers in the WAD. + for (j = 0; j < (texend - texstart); j++) + { + UINT8 *flatlump; + UINT16 wadnum = (UINT16)w; + lumpnum_t lumpnum = texstart + j; + size_t lumplength; + size_t flatsize = 0; + + if (wadfiles[w]->type == RET_PK3) + { + if (W_IsLumpFolder(wadnum, lumpnum)) // Check if lump is a folder + continue; // If it is then SKIP IT + } + + flatlump = W_CacheLumpNumPwad(wadnum, lumpnum, PU_CACHE); + lumplength = W_LumpLengthPwad(wadnum, lumpnum); + + switch (lumplength) + { + case 4194304: // 2048x2048 lump + flatsize = 2048; + break; + case 1048576: // 1024x1024 lump + flatsize = 1024; + break; + case 262144:// 512x512 lump + flatsize = 512; + break; + case 65536: // 256x256 lump + flatsize = 256; + break; + case 16384: // 128x128 lump + flatsize = 128; + break; + case 1024: // 32x32 lump + flatsize = 32; + break; + default: // 64x64 lump + flatsize = 64; + break; + } + + //CONS_Printf("\n\"%s\" is a flat, dimensions %d x %d",W_CheckNameForNumPwad((UINT16)w,texstart+j),flatsize,flatsize); + texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL); + + // Set texture properties. + M_Memcpy(texture->name, W_CheckNameForNumPwad(wadnum, lumpnum), sizeof(texture->name)); + +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((UINT8 *)flatlump, lumplength)) + { + INT16 width = 0, height = 0; + Picture_PNGDimensions((UINT8 *)flatlump, &width, &height, lumplength); + texture->width = width; + texture->height = height; + } + else +#endif + texture->width = texture->height = flatsize; + + texture->type = TEXTURETYPE_FLAT; + texture->patchcount = 1; + texture->holes = false; + texture->flip = 0; + + // Allocate information for the texture's patches. + patch = &texture->patches[0]; + + patch->originx = patch->originy = 0; + patch->wad = (UINT16)w; + patch->lump = texstart + j; + patch->flip = 0; + + Z_Unlock(flatlump); + + texturewidth[i] = texture->width; + textureheight[i] = texture->height << FRACBITS; + i++; + } +#endif + } + +#ifdef HWRENDER + if (rendermode == render_opengl) + HWR_LoadTextures(numtextures); +#endif +} + +static texpatch_t *R_ParsePatch(boolean actuallyLoadPatch) +{ + char *texturesToken; + size_t texturesTokenLength; + char *endPos; + char *patchName = NULL; + INT16 patchXPos; + INT16 patchYPos; + UINT8 flip = 0; + UINT8 alpha = 255; + enum patchalphastyle style = AST_COPY; + texpatch_t *resultPatch = NULL; + lumpnum_t patchLumpNum; + + // Patch identifier + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch name should be"); + } + texturesTokenLength = strlen(texturesToken); + if (texturesTokenLength>8) + { + I_Error("Error parsing TEXTURES lump: Patch name \"%s\" exceeds 8 characters",texturesToken); + } + else + { + if (patchName != NULL) + { + Z_Free(patchName); + } + patchName = (char *)Z_Malloc((texturesTokenLength+1)*sizeof(char),PU_STATIC,NULL); + M_Memcpy(patchName,texturesToken,texturesTokenLength*sizeof(char)); + patchName[texturesTokenLength] = '\0'; + } + + // Comma 1 + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after \"%s\"'s patch name should be",patchName); + } + if (strcmp(texturesToken,",")!=0) + { + I_Error("Error parsing TEXTURES lump: Expected \",\" after %s's patch name, got \"%s\"",patchName,texturesToken); + } + + // XPos + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s x coordinate should be",patchName); + } + endPos = NULL; +#ifndef AVOID_ERRNO + errno = 0; +#endif + patchXPos = strtol(texturesToken,&endPos,10); + (void)patchXPos; //unused for now + if (endPos == texturesToken // Empty string + || *endPos != '\0' // Not end of string +#ifndef AVOID_ERRNO + || errno == ERANGE // Number out-of-range +#endif + ) + { + I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); + } + + // Comma 2 + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after patch \"%s\"'s x coordinate should be",patchName); + } + if (strcmp(texturesToken,",")!=0) + { + I_Error("Error parsing TEXTURES lump: Expected \",\" after patch \"%s\"'s x coordinate, got \"%s\"",patchName,texturesToken); + } + + // YPos + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s y coordinate should be",patchName); + } + endPos = NULL; +#ifndef AVOID_ERRNO + errno = 0; +#endif + patchYPos = strtol(texturesToken,&endPos,10); + (void)patchYPos; //unused for now + if (endPos == texturesToken // Empty string + || *endPos != '\0' // Not end of string +#ifndef AVOID_ERRNO + || errno == ERANGE // Number out-of-range +#endif + ) + { + I_Error("Error parsing TEXTURES lump: Expected an integer for patch \"%s\"'s y coordinate, got \"%s\"",patchName,texturesToken); + } + Z_Free(texturesToken); + + // Patch parameters block (OPTIONAL) + // added by Monster Iestyn (22/10/16) + + // Left Curly Brace + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + ; // move on and ignore, R_ParseTextures will deal with this + else + { + if (strcmp(texturesToken,"{")==0) + { + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters should be",patchName); + } + while (strcmp(texturesToken,"}")!=0) + { + if (stricmp(texturesToken, "ALPHA")==0) + { + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + alpha = 255*strtof(texturesToken, NULL); + } + else if (stricmp(texturesToken, "STYLE")==0) + { + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (stricmp(texturesToken, "TRANSLUCENT")==0) + style = AST_TRANSLUCENT; + else if (stricmp(texturesToken, "ADD")==0) + style = AST_ADD; + else if (stricmp(texturesToken, "SUBTRACT")==0) + style = AST_SUBTRACT; + else if (stricmp(texturesToken, "REVERSESUBTRACT")==0) + style = AST_REVERSESUBTRACT; + else if (stricmp(texturesToken, "MODULATE")==0) + style = AST_MODULATE; + } + else if (stricmp(texturesToken, "FLIPX")==0) + flip |= 1; + else if (stricmp(texturesToken, "FLIPY")==0) + flip |= 2; + Z_Free(texturesToken); + + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch \"%s\"'s parameters or right curly brace should be",patchName); + } + } + } + else + { + // this is not what we wanted... + // undo last read so R_ParseTextures can re-get the token for its own purposes + M_UnGetToken(); + } + Z_Free(texturesToken); + } + + if (actuallyLoadPatch == true) + { + // Check lump exists + patchLumpNum = W_GetNumForName(patchName); + // If so, allocate memory for texpatch_t and fill 'er up + resultPatch = (texpatch_t *)Z_Malloc(sizeof(texpatch_t),PU_STATIC,NULL); + resultPatch->originx = patchXPos; + resultPatch->originy = patchYPos; + resultPatch->lump = patchLumpNum & 65535; + resultPatch->wad = patchLumpNum>>16; + resultPatch->flip = flip; + resultPatch->alpha = alpha; + resultPatch->style = style; + // Clean up a little after ourselves + Z_Free(patchName); + // Then return it + return resultPatch; + } + else + { + Z_Free(patchName); + return NULL; + } +} + +static texture_t *R_ParseTexture(boolean actuallyLoadTexture) +{ + char *texturesToken; + size_t texturesTokenLength; + char *endPos; + INT32 newTextureWidth; + INT32 newTextureHeight; + texture_t *resultTexture = NULL; + texpatch_t *newPatch; + char newTextureName[9]; // no longer dynamically allocated + + // Texture name + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture name should be"); + } + texturesTokenLength = strlen(texturesToken); + if (texturesTokenLength>8) + { + I_Error("Error parsing TEXTURES lump: Texture name \"%s\" exceeds 8 characters",texturesToken); + } + else + { + memset(&newTextureName, 0, 9); + M_Memcpy(newTextureName, texturesToken, texturesTokenLength); + // ^^ we've confirmed that the token is <= 8 characters so it will never overflow a 9 byte char buffer + strupr(newTextureName); // Just do this now so we don't have to worry about it + } + Z_Free(texturesToken); + + // Comma 1 + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after texture \"%s\"'s name should be",newTextureName); + } + else if (strcmp(texturesToken,",")!=0) + { + I_Error("Error parsing TEXTURES lump: Expected \",\" after texture \"%s\"'s name, got \"%s\"",newTextureName,texturesToken); + } + Z_Free(texturesToken); + + // Width + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture \"%s\"'s width should be",newTextureName); + } + endPos = NULL; +#ifndef AVOID_ERRNO + errno = 0; +#endif + newTextureWidth = strtol(texturesToken,&endPos,10); + if (endPos == texturesToken // Empty string + || *endPos != '\0' // Not end of string +#ifndef AVOID_ERRNO + || errno == ERANGE // Number out-of-range +#endif + || newTextureWidth < 0) // Number is not positive + { + I_Error("Error parsing TEXTURES lump: Expected a positive integer for texture \"%s\"'s width, got \"%s\"",newTextureName,texturesToken); + } + Z_Free(texturesToken); + + // Comma 2 + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where comma after texture \"%s\"'s width should be",newTextureName); + } + if (strcmp(texturesToken,",")!=0) + { + I_Error("Error parsing TEXTURES lump: Expected \",\" after texture \"%s\"'s width, got \"%s\"",newTextureName,texturesToken); + } + Z_Free(texturesToken); + + // Height + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where texture \"%s\"'s height should be",newTextureName); + } + endPos = NULL; +#ifndef AVOID_ERRNO + errno = 0; +#endif + newTextureHeight = strtol(texturesToken,&endPos,10); + if (endPos == texturesToken // Empty string + || *endPos != '\0' // Not end of string +#ifndef AVOID_ERRNO + || errno == ERANGE // Number out-of-range +#endif + || newTextureHeight < 0) // Number is not positive + { + I_Error("Error parsing TEXTURES lump: Expected a positive integer for texture \"%s\"'s height, got \"%s\"",newTextureName,texturesToken); + } + Z_Free(texturesToken); + + // Left Curly Brace + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where open curly brace for texture \"%s\" should be",newTextureName); + } + if (strcmp(texturesToken,"{")==0) + { + if (actuallyLoadTexture) + { + // Allocate memory for a zero-patch texture. Obviously, we'll be adding patches momentarily. + resultTexture = (texture_t *)Z_Calloc(sizeof(texture_t),PU_STATIC,NULL); + M_Memcpy(resultTexture->name, newTextureName, 8); + resultTexture->width = newTextureWidth; + resultTexture->height = newTextureHeight; + resultTexture->type = TEXTURETYPE_COMPOSITE; + } + Z_Free(texturesToken); + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch definition for texture \"%s\" should be",newTextureName); + } + while (strcmp(texturesToken,"}")!=0) + { + if (stricmp(texturesToken, "PATCH")==0) + { + Z_Free(texturesToken); + if (resultTexture) + { + // Get that new patch + newPatch = R_ParsePatch(true); + // Make room for the new patch + resultTexture = Z_Realloc(resultTexture, sizeof(texture_t) + (resultTexture->patchcount+1)*sizeof(texpatch_t), PU_STATIC, NULL); + // Populate the uninitialized values in the new patch entry of our array + M_Memcpy(&resultTexture->patches[resultTexture->patchcount], newPatch, sizeof(texpatch_t)); + // Account for the new number of patches in the texture + resultTexture->patchcount++; + // Then free up the memory assigned to R_ParsePatch, as it's unneeded now + Z_Free(newPatch); + } + else + { + R_ParsePatch(false); + } + } + else + { + I_Error("Error parsing TEXTURES lump: Expected \"PATCH\" in texture \"%s\", got \"%s\"",newTextureName,texturesToken); + } + + texturesToken = M_GetToken(NULL); + if (texturesToken == NULL) + { + I_Error("Error parsing TEXTURES lump: Unexpected end of file where patch declaration or right curly brace for texture \"%s\" should be",newTextureName); + } + } + if (resultTexture && resultTexture->patchcount == 0) + { + I_Error("Error parsing TEXTURES lump: Texture \"%s\" must have at least one patch",newTextureName); + } + } + else + { + I_Error("Error parsing TEXTURES lump: Expected \"{\" for texture \"%s\", got \"%s\"",newTextureName,texturesToken); + } + Z_Free(texturesToken); + + if (actuallyLoadTexture) return resultTexture; + else return NULL; +} + +// Parses the TEXTURES lump... but just to count the number of textures. +int R_CountTexturesInTEXTURESLump(UINT16 wadNum, UINT16 lumpNum) +{ + char *texturesLump; + size_t texturesLumpLength; + char *texturesText; + UINT32 numTexturesInLump = 0; + char *texturesToken; + + // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll + // need to make a space of memory where I can ensure that it will terminate + // correctly. Start by loading the relevant data from the WAD. + texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); + // If that didn't exist, we have nothing to do here. + if (texturesLump == NULL) return 0; + // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. + texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); + texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); + // Now move the contents of the lump into this new location. + memmove(texturesText,texturesLump,texturesLumpLength); + // Make damn well sure the last character in our new memory location is \0. + texturesText[texturesLumpLength] = '\0'; + // Finally, free up the memory from the first data load, because we really + // don't need it. + Z_Free(texturesLump); + + texturesToken = M_GetToken(texturesText); + while (texturesToken != NULL) + { + if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) + { + numTexturesInLump++; + Z_Free(texturesToken); + R_ParseTexture(false); + } + else + { + I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); + } + texturesToken = M_GetToken(NULL); + } + Z_Free(texturesToken); + Z_Free((void *)texturesText); + + return numTexturesInLump; +} + +// Parses the TEXTURES lump... for real, this time. +void R_ParseTEXTURESLump(UINT16 wadNum, UINT16 lumpNum, INT32 *texindex) +{ + char *texturesLump; + size_t texturesLumpLength; + char *texturesText; + char *texturesToken; + texture_t *newTexture; + + I_Assert(texindex != NULL); + + // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll + // need to make a space of memory where I can ensure that it will terminate + // correctly. Start by loading the relevant data from the WAD. + texturesLump = (char *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC); + // If that didn't exist, we have nothing to do here. + if (texturesLump == NULL) return; + // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. + texturesLumpLength = W_LumpLengthPwad(wadNum, lumpNum); + texturesText = (char *)Z_Malloc((texturesLumpLength+1)*sizeof(char),PU_STATIC,NULL); + // Now move the contents of the lump into this new location. + memmove(texturesText,texturesLump,texturesLumpLength); + // Make damn well sure the last character in our new memory location is \0. + texturesText[texturesLumpLength] = '\0'; + // Finally, free up the memory from the first data load, because we really + // don't need it. + Z_Free(texturesLump); + + texturesToken = M_GetToken(texturesText); + while (texturesToken != NULL) + { + if (stricmp(texturesToken, "WALLTEXTURE") == 0 || stricmp(texturesToken, "TEXTURE") == 0) + { + Z_Free(texturesToken); + // Get the new texture + newTexture = R_ParseTexture(true); + // Store the new texture + textures[*texindex] = newTexture; + texturewidth[*texindex] = newTexture->width; + textureheight[*texindex] = newTexture->height << FRACBITS; + // Increment i back in R_LoadTextures() + (*texindex)++; + } + else + { + I_Error("Error parsing TEXTURES lump: Expected \"WALLTEXTURE\" or \"TEXTURE\", got \"%s\"",texturesToken); + } + texturesToken = M_GetToken(NULL); + } + Z_Free(texturesToken); + Z_Free((void *)texturesText); +} + +// Search for flat name. +lumpnum_t R_GetFlatNumForName(const char *name) +{ + INT32 i; + lumpnum_t lump; + lumpnum_t start; + lumpnum_t end; + + // Scan wad files backwards so patched flats take preference. + for (i = numwadfiles - 1; i >= 0; i--) + { + switch (wadfiles[i]->type) + { + case RET_WAD: + if ((start = W_CheckNumForNamePwad("F_START", (UINT16)i, 0)) == INT16_MAX) + { + if ((start = W_CheckNumForNamePwad("FF_START", (UINT16)i, 0)) == INT16_MAX) + continue; + else if ((end = W_CheckNumForNamePwad("FF_END", (UINT16)i, start)) == INT16_MAX) + continue; + } + else + if ((end = W_CheckNumForNamePwad("F_END", (UINT16)i, start)) == INT16_MAX) + continue; + break; + case RET_PK3: + if ((start = W_CheckNumForFolderStartPK3("Flats/", i, 0)) == INT16_MAX) + continue; + if ((end = W_CheckNumForFolderEndPK3("Flats/", i, start)) == INT16_MAX) + continue; + break; + default: + continue; + } + + // Now find lump with specified name in that range. + lump = W_CheckNumForNamePwad(name, (UINT16)i, start); + if (lump < end) + { + lump += (i<<16); // found it, in our constraints + break; + } + lump = LUMPERROR; + } + + return lump; +} + +void R_ClearTextureNumCache(boolean btell) +{ + if (tidcache) + Z_Free(tidcache); + tidcache = NULL; + if (btell) + CONS_Debug(DBG_SETUP, "Fun Fact: There are %d textures used in this map.\n", tidcachelen); + tidcachelen = 0; +} + +// +// R_CheckTextureNumForName +// +// Check whether texture is available. Filter out NoTexture indicator. +// +INT32 R_CheckTextureNumForName(const char *name) +{ + INT32 i; + + // "NoTexture" marker. + if (name[0] == '-') + return 0; + + for (i = 0; i < tidcachelen; i++) + if (!strncasecmp(tidcache[i].name, name, 8)) + return tidcache[i].id; + + // Need to parse the list backwards, so textures loaded more recently are used in lieu of ones loaded earlier + //for (i = 0; i < numtextures; i++) <- old + for (i = (numtextures - 1); i >= 0; i--) // <- new + if (!strncasecmp(textures[i]->name, name, 8)) + { + tidcachelen++; + Z_Realloc(tidcache, tidcachelen * sizeof(*tidcache), PU_STATIC, &tidcache); + strncpy(tidcache[tidcachelen-1].name, name, 8); + tidcache[tidcachelen-1].name[8] = '\0'; +#ifndef ZDEBUG + CONS_Debug(DBG_SETUP, "texture #%s: %s\n", sizeu1(tidcachelen), tidcache[tidcachelen-1].name); +#endif + tidcache[tidcachelen-1].id = i; + return i; + } + + return -1; +} + +// +// R_TextureNumForName +// +// Calls R_CheckTextureNumForName, aborts with error message. +// +INT32 R_TextureNumForName(const char *name) +{ + const INT32 i = R_CheckTextureNumForName(name); + + if (i == -1) + { + static INT32 redwall = -2; + CONS_Debug(DBG_SETUP, "WARNING: R_TextureNumForName: %.8s not found\n", name); + if (redwall == -2) + redwall = R_CheckTextureNumForName("REDWALL"); + if (redwall != -1) + return redwall; + return 1; + } + return i; +} diff --git a/src/r_textures.h b/src/r_textures.h new file mode 100644 index 000000000..d9f5e9e1d --- /dev/null +++ b/src/r_textures.h @@ -0,0 +1,109 @@ +// SONIC ROBO BLAST 2 +//----------------------------------------------------------------------------- +// Copyright (C) 1993-1996 by id Software, Inc. +// Copyright (C) 1998-2000 by DooM Legacy Team. +// Copyright (C) 1999-2020 by Sonic Team Junior. +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file r_textures.h +/// \brief Texture generation. + +#ifndef __R_TEXTURES__ +#define __R_TEXTURES__ + +#include "r_defs.h" +#include "r_state.h" +#include "p_setup.h" // levelflats +#include "r_data.h" +#include "r_textures.h" + +#ifdef __GNUG__ +#pragma interface +#endif + +// A single patch from a texture definition, +// basically a rectangular area within +// the texture rectangle. +typedef struct +{ + // Block origin (always UL), which has already accounted for the internal origin of the patch. + INT16 originx, originy; + UINT16 wad, lump; + UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both + UINT8 alpha; // Translucency value + enum patchalphastyle style; +} texpatch_t; + +// texture type +enum +{ + TEXTURETYPE_UNKNOWN, + TEXTURETYPE_SINGLEPATCH, + TEXTURETYPE_COMPOSITE, +#ifdef WALLFLATS + TEXTURETYPE_FLAT, +#endif +}; + +// A maptexturedef_t describes a rectangular texture, +// which is composed of one or more mappatch_t structures +// that arrange graphic patches. +typedef struct +{ + // Keep name for switch changing, etc. + char name[8]; + UINT8 type; // TEXTURETYPE_ + INT16 width, height; + boolean holes; + UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both + + // All the patches[patchcount] are drawn back to front into the cached texture. + INT16 patchcount; + texpatch_t patches[0]; +} texture_t; + +typedef struct +{ + UINT8 *flat; + INT16 width, height; +} textureflat_t; + +// all loaded and prepared textures from the start of the game +extern texture_t **textures; +extern textureflat_t *texflats; + +extern INT32 *texturewidth; +extern fixed_t *textureheight; // needed for texture pegging + +extern UINT32 **texturecolumnofs; // column offset lookup table for each texture +extern UINT8 **texturecache; // graphics data for each generated full-size texture + +// Load TEXTURES definitions, create lookup tables +void R_LoadTextures(void); +void R_FlushTextureCache(void); + +UINT8 *R_GenerateTexture(size_t texnum); +INT32 R_GetTextureNum(INT32 texnum); +void R_CheckTextureCache(INT32 tex); + +// Retrieve column data for span blitting. +UINT8 *R_GetColumn(fixed_t tex, INT32 col); +UINT8 *R_GetFlat(lumpnum_t flatnum); + +// Retrieval. +// Floor/ceiling opaque texture tiles, +// lookup by name. For animation? +lumpnum_t R_GetFlatNumForName(const char *name); + +// Called by P_Ticker for switches and animations, +// returns the texture number for the texture name. +void R_ClearTextureNumCache(boolean btell); +INT32 R_TextureNumForName(const char *name); +INT32 R_CheckTextureNumForName(const char *name); + +extern INT32 numtextures; + +#endif diff --git a/src/sdl/Srb2SDL-vc10.vcxproj b/src/sdl/Srb2SDL-vc10.vcxproj index 7efab1bc0..594095cbe 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj +++ b/src/sdl/Srb2SDL-vc10.vcxproj @@ -280,13 +280,14 @@ - + + @@ -442,12 +443,13 @@ true + - + diff --git a/src/sdl/Srb2SDL-vc10.vcxproj.filters b/src/sdl/Srb2SDL-vc10.vcxproj.filters index 97be5ad5f..0248908a4 100644 --- a/src/sdl/Srb2SDL-vc10.vcxproj.filters +++ b/src/sdl/Srb2SDL-vc10.vcxproj.filters @@ -465,6 +465,9 @@ Hw_Hardware + + R_Rend + R_Rend @@ -928,6 +931,9 @@ Hw_Hardware + + R_Rend + R_Rend diff --git a/src/w_wad.c b/src/w_wad.c index 465b5abd8..2916d9825 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -56,6 +56,7 @@ #include "d_clisrv.h" #include "r_defs.h" #include "r_data.h" +#include "r_textures.h" #include "i_system.h" #include "md5.h" #include "lua_script.h" @@ -65,7 +66,6 @@ #include "m_misc.h" // M_MapNumber #ifdef HWRENDER -#include "r_data.h" #include "hardware/hw_main.h" #include "hardware/hw_glob.h" #endif diff --git a/src/win32/Srb2win-vc10.vcxproj b/src/win32/Srb2win-vc10.vcxproj index 91a6aa348..69aee41e8 100644 --- a/src/win32/Srb2win-vc10.vcxproj +++ b/src/win32/Srb2win-vc10.vcxproj @@ -299,12 +299,13 @@ true - + + @@ -455,13 +456,14 @@ + - + diff --git a/src/win32/Srb2win-vc10.vcxproj.filters b/src/win32/Srb2win-vc10.vcxproj.filters index 00040f4a1..34994132e 100644 --- a/src/win32/Srb2win-vc10.vcxproj.filters +++ b/src/win32/Srb2win-vc10.vcxproj.filters @@ -892,6 +892,9 @@ Hw_Hardware + + R_Rend + R_Rend From 762ce146ebd15954b4ec0e6f2fbf4029b00c1e69 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 12:43:27 -0300 Subject: [PATCH 11/27] Organise header files, use R_GetFlat --- src/r_plane.c | 4 ++-- src/r_textures.c | 2 -- src/r_textures.h | 14 +++++--------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/r_plane.c b/src/r_plane.c index 982354a5f..cc304043e 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -1127,7 +1127,7 @@ void R_DrawSinglePlane(visplane_t *pl) case LEVELFLAT_NONE: return; case LEVELFLAT_FLAT: - ds_source = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); + ds_source = R_GetFlat(levelflat->u.flat.lumpnum); R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum)); // Raw flats always have dimensions that are powers-of-two numbers. ds_powersoftwo = true; @@ -1140,7 +1140,7 @@ void R_DrawSinglePlane(visplane_t *pl) ds_source = R_GetTextureFlat(levelflat, true, false); break; default: - ds_source = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_STATIC); + ds_source = R_GetFlat(levelflat->u.flat.lumpnum); flat = R_GetTextureFlat(levelflat, false, #ifndef NO_PNG_LUMPS ( type == LEVELFLAT_PNG ) diff --git a/src/r_textures.c b/src/r_textures.c index c9c8fd937..96f2590a6 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -497,8 +497,6 @@ UINT8 *R_GetColumn(fixed_t tex, INT32 col) return data + LONG(texturecolumnofs[tex][col]); } -// convert flats to hicolor as they are requested -// UINT8 *R_GetFlat(lumpnum_t flatlumpnum) { return W_CacheLumpNum(flatlumpnum, PU_CACHE); diff --git a/src/r_textures.h b/src/r_textures.h index d9f5e9e1d..fd35926cc 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -85,24 +85,20 @@ extern UINT8 **texturecache; // graphics data for each generated full-size textu void R_LoadTextures(void); void R_FlushTextureCache(void); +// Texture generation UINT8 *R_GenerateTexture(size_t texnum); INT32 R_GetTextureNum(INT32 texnum); void R_CheckTextureCache(INT32 tex); +void R_ClearTextureNumCache(boolean btell); -// Retrieve column data for span blitting. +// Retrieve texture data. UINT8 *R_GetColumn(fixed_t tex, INT32 col); UINT8 *R_GetFlat(lumpnum_t flatnum); -// Retrieval. -// Floor/ceiling opaque texture tiles, -// lookup by name. For animation? -lumpnum_t R_GetFlatNumForName(const char *name); - -// Called by P_Ticker for switches and animations, -// returns the texture number for the texture name. -void R_ClearTextureNumCache(boolean btell); +// Returns the texture number for the texture name. INT32 R_TextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name); +lumpnum_t R_GetFlatNumForName(const char *name); extern INT32 numtextures; From 06d6e2e027758b592221e1e4ac61ad3c60ac8a66 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 12:45:22 -0300 Subject: [PATCH 12/27] Move location of R_GetTextureFlat --- src/r_plane.c | 101 ----------------------------------------------- src/r_textures.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++ src/r_textures.h | 1 + 3 files changed, 102 insertions(+), 101 deletions(-) diff --git a/src/r_plane.c b/src/r_plane.c index cc304043e..292b5b2d4 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -765,107 +765,6 @@ void R_CheckFlatLength(size_t size) } } -// -// R_GetTextureFlat -// -// Convert a texture or patch to a flat. -// -static UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) -{ - UINT8 *flat; - textureflat_t *texflat = &texflats[levelflat->u.texture.num]; - patch_t *patch = NULL; - boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); - - (void)ispng; - - // Check if the texture changed. - if (leveltexture && (!texturechanged)) - { - if (texflat != NULL && texflat->flat) - { - flat = texflat->flat; - ds_flatwidth = texflat->width; - ds_flatheight = texflat->height; - texturechanged = false; - } - else - texturechanged = true; - } - - // If the texture changed, or the patch doesn't exist, convert either of them to a flat. - if (levelflat->flatpatch == NULL || texturechanged) - { - // Level texture - if (leveltexture) - { - UINT8 *converted; - size_t size; - texture_t *texture = textures[levelflat->u.texture.num]; - texflat->width = ds_flatwidth = texture->width; - texflat->height = ds_flatheight = texture->height; - - size = (texflat->width * texflat->height); - texflat->flat = Z_Malloc(size, PU_LEVEL, NULL); - converted = (UINT8 *)Picture_TextureToFlat(levelflat->u.texture.num); - M_Memcpy(texflat->flat, converted, size); - Z_Free(converted); - flat = texflat->flat; - - levelflat->flatpatch = flat; - levelflat->width = ds_flatwidth; - levelflat->height = ds_flatheight; - } - // Patch (never happens yet) - else - { - patch = (patch_t *)ds_source; -#ifndef NO_PNG_LUMPS - if (ispng) - { - INT32 pngwidth, pngheight; - - levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); - levelflat->topoffset = levelflat->leftoffset = 0; - levelflat->width = (UINT16)pngwidth; - levelflat->height = (UINT16)pngheight; - - ds_flatwidth = levelflat->width; - ds_flatheight = levelflat->height; - } - else -#endif - { - UINT8 *converted; - size_t size; - levelflat->width = ds_flatwidth = SHORT(patch->width); - levelflat->height = ds_flatheight = SHORT(patch->height); - - levelflat->topoffset = patch->topoffset * FRACUNIT; - levelflat->leftoffset = patch->leftoffset * FRACUNIT; - - levelflat->flatpatch = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); - converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); - M_Memcpy(levelflat->flatpatch, converted, size); - Z_Free(converted); - } - flat = levelflat->flatpatch; - } - } - else - { - flat = levelflat->flatpatch; - ds_flatwidth = levelflat->width; - ds_flatheight = levelflat->height; - } - - xoffs += levelflat->leftoffset; - yoffs += levelflat->topoffset; - - levelflat->u.texture.lastnum = levelflat->u.texture.num; - return flat; -} - #ifdef ESLOPE static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) { diff --git a/src/r_textures.c b/src/r_textures.c index 96f2590a6..9d70b9d5c 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -502,6 +502,107 @@ UINT8 *R_GetFlat(lumpnum_t flatlumpnum) return W_CacheLumpNum(flatlumpnum, PU_CACHE); } +// +// R_GetTextureFlat +// +// Convert a texture or patch to a flat. +// +UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) +{ + UINT8 *flat; + textureflat_t *texflat = &texflats[levelflat->u.texture.num]; + patch_t *patch = NULL; + boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); + + (void)ispng; + + // Check if the texture changed. + if (leveltexture && (!texturechanged)) + { + if (texflat != NULL && texflat->flat) + { + flat = texflat->flat; + ds_flatwidth = texflat->width; + ds_flatheight = texflat->height; + texturechanged = false; + } + else + texturechanged = true; + } + + // If the texture changed, or the patch doesn't exist, convert either of them to a flat. + if (levelflat->flatpatch == NULL || texturechanged) + { + // Level texture + if (leveltexture) + { + UINT8 *converted; + size_t size; + texture_t *texture = textures[levelflat->u.texture.num]; + texflat->width = ds_flatwidth = texture->width; + texflat->height = ds_flatheight = texture->height; + + size = (texflat->width * texflat->height); + texflat->flat = Z_Malloc(size, PU_LEVEL, NULL); + converted = (UINT8 *)Picture_TextureToFlat(levelflat->u.texture.num); + M_Memcpy(texflat->flat, converted, size); + Z_Free(converted); + flat = texflat->flat; + + levelflat->flatpatch = flat; + levelflat->width = ds_flatwidth; + levelflat->height = ds_flatheight; + } + // Patch (never happens yet) + else + { + patch = (patch_t *)ds_source; +#ifndef NO_PNG_LUMPS + if (ispng) + { + INT32 pngwidth, pngheight; + + levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + levelflat->topoffset = levelflat->leftoffset = 0; + levelflat->width = (UINT16)pngwidth; + levelflat->height = (UINT16)pngheight; + + ds_flatwidth = levelflat->width; + ds_flatheight = levelflat->height; + } + else +#endif + { + UINT8 *converted; + size_t size; + levelflat->width = ds_flatwidth = SHORT(patch->width); + levelflat->height = ds_flatheight = SHORT(patch->height); + + levelflat->topoffset = patch->topoffset * FRACUNIT; + levelflat->leftoffset = patch->leftoffset * FRACUNIT; + + levelflat->flatpatch = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); + converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); + M_Memcpy(levelflat->flatpatch, converted, size); + Z_Free(converted); + } + flat = levelflat->flatpatch; + } + } + else + { + flat = levelflat->flatpatch; + ds_flatwidth = levelflat->width; + ds_flatheight = levelflat->height; + } + + //xoffs += levelflat->leftoffset; + //yoffs += levelflat->topoffset; + + levelflat->u.texture.lastnum = levelflat->u.texture.num; + return flat; +} + // // Empty the texture cache (used for load wad at runtime) // diff --git a/src/r_textures.h b/src/r_textures.h index fd35926cc..d42509bdd 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -94,6 +94,7 @@ void R_ClearTextureNumCache(boolean btell); // Retrieve texture data. UINT8 *R_GetColumn(fixed_t tex, INT32 col); UINT8 *R_GetFlat(lumpnum_t flatnum); +UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng); // Returns the texture number for the texture name. INT32 R_TextureNumForName(const char *name); From 76a6710f8b1ecaf3751241f1108a28c830694a72 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 12:46:46 -0300 Subject: [PATCH 13/27] Move location of R_CheckPowersOfTwo and R_CheckFlatLength --- src/r_plane.c | 83 ------------------------------------------------ src/r_textures.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ src/r_textures.h | 3 ++ 3 files changed, 86 insertions(+), 83 deletions(-) diff --git a/src/r_plane.c b/src/r_plane.c index 292b5b2d4..8e1ddb8db 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -682,89 +682,6 @@ static void R_DrawSkyPlane(visplane_t *pl) } } -// -// R_CheckPowersOfTwo -// -// Self-explanatory? -// -boolean R_CheckPowersOfTwo(void) -{ - boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); - boolean hpow2 = (!(ds_flatheight & (ds_flatheight - 1))); - - // Initially, the flat isn't powers-of-two-sized. - ds_powersoftwo = false; - - // But if the width and height are powers of two, - // and are EQUAL, then it's okay :] - if ((ds_flatwidth == ds_flatheight) && (wpow2 && hpow2)) - ds_powersoftwo = true; - - // Just return ds_powersoftwo. - return ds_powersoftwo; -} - -// -// R_CheckFlatLength -// -// Determine the flat's dimensions from the lump length. -// -void R_CheckFlatLength(size_t size) -{ - switch (size) - { - case 4194304: // 2048x2048 lump - nflatmask = 0x3FF800; - nflatxshift = 21; - nflatyshift = 10; - nflatshiftup = 5; - ds_flatwidth = ds_flatheight = 2048; - break; - case 1048576: // 1024x1024 lump - nflatmask = 0xFFC00; - nflatxshift = 22; - nflatyshift = 12; - nflatshiftup = 6; - ds_flatwidth = ds_flatheight = 1024; - break; - case 262144:// 512x512 lump - nflatmask = 0x3FE00; - nflatxshift = 23; - nflatyshift = 14; - nflatshiftup = 7; - ds_flatwidth = ds_flatheight = 512; - break; - case 65536: // 256x256 lump - nflatmask = 0xFF00; - nflatxshift = 24; - nflatyshift = 16; - nflatshiftup = 8; - ds_flatwidth = ds_flatheight = 256; - break; - case 16384: // 128x128 lump - nflatmask = 0x3F80; - nflatxshift = 25; - nflatyshift = 18; - nflatshiftup = 9; - ds_flatwidth = ds_flatheight = 128; - break; - case 1024: // 32x32 lump - nflatmask = 0x3E0; - nflatxshift = 27; - nflatyshift = 22; - nflatshiftup = 11; - ds_flatwidth = ds_flatheight = 32; - break; - default: // 64x64 lump - nflatmask = 0xFC0; - nflatxshift = 26; - nflatyshift = 20; - nflatshiftup = 10; - ds_flatwidth = ds_flatheight = 64; - break; - } -} - #ifdef ESLOPE static void R_SlopeVectors(visplane_t *pl, INT32 i, float fudge) { diff --git a/src/r_textures.c b/src/r_textures.c index 9d70b9d5c..60d9a802e 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -603,6 +603,89 @@ UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean is return flat; } +// +// R_CheckPowersOfTwo +// +// Self-explanatory? +// +boolean R_CheckPowersOfTwo(void) +{ + boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); + boolean hpow2 = (!(ds_flatheight & (ds_flatheight - 1))); + + // Initially, the flat isn't powers-of-two-sized. + ds_powersoftwo = false; + + // But if the width and height are powers of two, + // and are EQUAL, then it's okay :] + if ((ds_flatwidth == ds_flatheight) && (wpow2 && hpow2)) + ds_powersoftwo = true; + + // Just return ds_powersoftwo. + return ds_powersoftwo; +} + +// +// R_CheckFlatLength +// +// Determine the flat's dimensions from its lump length. +// +void R_CheckFlatLength(size_t size) +{ + switch (size) + { + case 4194304: // 2048x2048 lump + nflatmask = 0x3FF800; + nflatxshift = 21; + nflatyshift = 10; + nflatshiftup = 5; + ds_flatwidth = ds_flatheight = 2048; + break; + case 1048576: // 1024x1024 lump + nflatmask = 0xFFC00; + nflatxshift = 22; + nflatyshift = 12; + nflatshiftup = 6; + ds_flatwidth = ds_flatheight = 1024; + break; + case 262144:// 512x512 lump + nflatmask = 0x3FE00; + nflatxshift = 23; + nflatyshift = 14; + nflatshiftup = 7; + ds_flatwidth = ds_flatheight = 512; + break; + case 65536: // 256x256 lump + nflatmask = 0xFF00; + nflatxshift = 24; + nflatyshift = 16; + nflatshiftup = 8; + ds_flatwidth = ds_flatheight = 256; + break; + case 16384: // 128x128 lump + nflatmask = 0x3F80; + nflatxshift = 25; + nflatyshift = 18; + nflatshiftup = 9; + ds_flatwidth = ds_flatheight = 128; + break; + case 1024: // 32x32 lump + nflatmask = 0x3E0; + nflatxshift = 27; + nflatyshift = 22; + nflatshiftup = 11; + ds_flatwidth = ds_flatheight = 32; + break; + default: // 64x64 lump + nflatmask = 0xFC0; + nflatxshift = 26; + nflatyshift = 20; + nflatshiftup = 10; + ds_flatwidth = ds_flatheight = 64; + break; + } +} + // // Empty the texture cache (used for load wad at runtime) // diff --git a/src/r_textures.h b/src/r_textures.h index d42509bdd..e2bb40274 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -96,6 +96,9 @@ UINT8 *R_GetColumn(fixed_t tex, INT32 col); UINT8 *R_GetFlat(lumpnum_t flatnum); UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng); +boolean R_CheckPowersOfTwo(void); +void R_CheckFlatLength(size_t size); + // Returns the texture number for the texture name. INT32 R_TextureNumForName(const char *name); INT32 R_CheckTextureNumForName(const char *name); From 5b5f371b0c3f5cae4258a0227b2d57b91d9b062d Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 13:27:59 -0300 Subject: [PATCH 14/27] R_GetTextureFlat -> R_GetLevelFlat --- src/p_setup.c | 2 +- src/p_setup.h | 1 - src/r_picformats.c | 5 ++++- src/r_plane.c | 26 +++++--------------------- src/r_textures.c | 42 +++++++++++++++++------------------------- src/r_textures.h | 4 ++-- 6 files changed, 29 insertions(+), 51 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 0b43f76a5..5014f0a7e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -638,7 +638,7 @@ texturefound: { flatfound: /* This could be a flat, patch, or PNG. */ - flatpatch = W_CacheLumpNum(flatnum, PU_STATIC); + flatpatch = W_CacheLumpNum(flatnum, PU_CACHE); lumplength = W_LumpLength(flatnum); if (Picture_CheckIfPatch(flatpatch, lumplength)) levelflat->type = LEVELFLAT_PATCH; diff --git a/src/p_setup.h b/src/p_setup.h index ff28e36e4..77c932afc 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -72,7 +72,6 @@ typedef struct u; UINT16 width, height; - fixed_t topoffset, leftoffset; // for flat animation INT32 animseq; // start pos. in the anim sequence diff --git a/src/r_picformats.c b/src/r_picformats.c index b907ac4d4..ec953dfe9 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -615,7 +615,7 @@ boolean Picture_CheckIfPatch(patch_t *patch, size_t size) width = SHORT(patch->width); height = SHORT(patch->height); - result = (height > 0 && height <= 16384 && width > 0 && width <= 16384 && width < (INT16)(size / 4)); + result = (height > 0 && height <= 16384 && width > 0 && width <= 16384); if (result) { @@ -930,6 +930,9 @@ void *Picture_PNGConvert( png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); png_uint_32 width = *w, height = *h; + if (png == NULL) + I_Error("Picture_PNGConvert: picture was NULL!"); + // Find the output format's bits per pixel amount outbpp = Picture_FormatBPP(outformat); diff --git a/src/r_plane.c b/src/r_plane.c index 8e1ddb8db..9e90aba15 100644 --- a/src/r_plane.c +++ b/src/r_plane.c @@ -777,12 +777,11 @@ d.z = (v1.x * v2.y) - (v1.y * v2.x) void R_DrawSinglePlane(visplane_t *pl) { - UINT8 *flat; + levelflat_t *levelflat; INT32 light = 0; INT32 x; INT32 stop, angle; ffloor_t *rover; - levelflat_t *levelflat; int type; int spanfunctype = BASEDRAWFUNC; @@ -943,30 +942,15 @@ void R_DrawSinglePlane(visplane_t *pl) case LEVELFLAT_NONE: return; case LEVELFLAT_FLAT: - ds_source = R_GetFlat(levelflat->u.flat.lumpnum); + ds_source = (UINT8 *)R_GetFlat(levelflat->u.flat.lumpnum); R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum)); // Raw flats always have dimensions that are powers-of-two numbers. ds_powersoftwo = true; break; default: - switch (type) - { - case LEVELFLAT_TEXTURE: - /* Textures get cached differently and don't need ds_source */ - ds_source = R_GetTextureFlat(levelflat, true, false); - break; - default: - ds_source = R_GetFlat(levelflat->u.flat.lumpnum); - flat = R_GetTextureFlat(levelflat, false, -#ifndef NO_PNG_LUMPS - ( type == LEVELFLAT_PNG ) -#else - false -#endif - ); - Z_ChangeTag(ds_source, PU_CACHE); - ds_source = flat; - } + ds_source = (UINT8 *)R_GetLevelFlat(levelflat); + if (!ds_source) + return; // Check if this texture or patch has power-of-two dimensions. if (R_CheckPowersOfTwo()) R_CheckFlatLength(ds_flatwidth * ds_flatheight); diff --git a/src/r_textures.c b/src/r_textures.c index 60d9a802e..5e03f57fc 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -497,31 +497,29 @@ UINT8 *R_GetColumn(fixed_t tex, INT32 col) return data + LONG(texturecolumnofs[tex][col]); } -UINT8 *R_GetFlat(lumpnum_t flatlumpnum) +void *R_GetFlat(lumpnum_t flatlumpnum) { return W_CacheLumpNum(flatlumpnum, PU_CACHE); } // -// R_GetTextureFlat +// R_GetLevelFlat // -// Convert a texture or patch to a flat. +// If needed, convert a texture or patch to a flat. // -UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng) +void *R_GetLevelFlat(levelflat_t *levelflat) { - UINT8 *flat; + UINT8 *flatdata = NULL; + boolean leveltexture = (levelflat->type == LEVELFLAT_TEXTURE); textureflat_t *texflat = &texflats[levelflat->u.texture.num]; - patch_t *patch = NULL; boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); - (void)ispng; - // Check if the texture changed. if (leveltexture && (!texturechanged)) { if (texflat != NULL && texflat->flat) { - flat = texflat->flat; + flatdata = texflat->flat; ds_flatwidth = texflat->width; ds_flatheight = texflat->height; texturechanged = false; @@ -547,23 +545,19 @@ UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean is converted = (UINT8 *)Picture_TextureToFlat(levelflat->u.texture.num); M_Memcpy(texflat->flat, converted, size); Z_Free(converted); - flat = texflat->flat; - levelflat->flatpatch = flat; + levelflat->flatpatch = texflat->flat; levelflat->width = ds_flatwidth; levelflat->height = ds_flatheight; } - // Patch (never happens yet) else { - patch = (patch_t *)ds_source; #ifndef NO_PNG_LUMPS - if (ispng) + if (levelflat->type == LEVELFLAT_PNG) { INT32 pngwidth, pngheight; - levelflat->flatpatch = Picture_PNGConvert(ds_source, PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); - levelflat->topoffset = levelflat->leftoffset = 0; + levelflat->flatpatch = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); levelflat->width = (UINT16)pngwidth; levelflat->height = (UINT16)pngheight; @@ -572,35 +566,33 @@ UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean is } else #endif + if (levelflat->type == LEVELFLAT_PATCH) { UINT8 *converted; size_t size; + patch_t *patch = W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE); + levelflat->width = ds_flatwidth = SHORT(patch->width); levelflat->height = ds_flatheight = SHORT(patch->height); - levelflat->topoffset = patch->topoffset * FRACUNIT; - levelflat->leftoffset = patch->leftoffset * FRACUNIT; - levelflat->flatpatch = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); M_Memcpy(levelflat->flatpatch, converted, size); Z_Free(converted); } - flat = levelflat->flatpatch; } } else { - flat = levelflat->flatpatch; ds_flatwidth = levelflat->width; ds_flatheight = levelflat->height; } - //xoffs += levelflat->leftoffset; - //yoffs += levelflat->topoffset; - levelflat->u.texture.lastnum = levelflat->u.texture.num; - return flat; + + if (flatdata == NULL) + flatdata = levelflat->flatpatch; + return flatdata; } // diff --git a/src/r_textures.h b/src/r_textures.h index e2bb40274..62ef523b2 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -93,8 +93,8 @@ void R_ClearTextureNumCache(boolean btell); // Retrieve texture data. UINT8 *R_GetColumn(fixed_t tex, INT32 col); -UINT8 *R_GetFlat(lumpnum_t flatnum); -UINT8 *R_GetTextureFlat(levelflat_t *levelflat, boolean leveltexture, boolean ispng); +void *R_GetFlat(lumpnum_t flatnum); +void *R_GetLevelFlat(levelflat_t *levelflat); boolean R_CheckPowersOfTwo(void); void R_CheckFlatLength(size_t size); From 13585077857cafe6ff8626b82060dab9e2a5b95c Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 14:07:14 -0300 Subject: [PATCH 15/27] Fix OpenGL --- src/hardware/hw_cache.c | 54 ++++++++++++++++++++++++++++++++++++++++- src/hardware/hw_main.c | 54 ++++++++++++++++++++++++----------------- src/p_setup.c | 4 +-- src/p_setup.h | 9 ++++--- src/r_textures.c | 12 ++++----- 5 files changed, 98 insertions(+), 35 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 9bf7db1da..df1e18f9d 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -1024,7 +1024,7 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) INT32 texturenum = levelflat->u.texture.num; #ifdef PARANOIA if ((unsigned)texturenum >= gr_numtextures) - I_Error("HWR_GetLevelFlat: texturenum >= numtextures\n"); + I_Error("HWR_GetLevelFlat: texturenum >= numtextures"); #endif // Who knows? @@ -1044,6 +1044,58 @@ void HWR_GetLevelFlat(levelflat_t *levelflat) // The system-memory data can be purged now. Z_ChangeTag(grtex->mipmap.grInfo.data, PU_HWRCACHE_UNLOCKED); } + else if (levelflat->type == LEVELFLAT_PATCH) + { + GLPatch_t *patch = W_CachePatchNum(levelflat->u.flat.lumpnum, PU_CACHE); + levelflat->width = (UINT16)SHORT(patch->width); + levelflat->height = (UINT16)SHORT(patch->height); + HWR_GetPatch(patch); + } +#ifndef NO_PNG_LUMPS + else if (levelflat->type == LEVELFLAT_PNG) + { + INT32 pngwidth, pngheight; + GLMipmap_t *mipmap = levelflat->mipmap; + UINT8 *flat; + size_t size; + + // Cache the picture. + if (!levelflat->picture) + { + levelflat->picture = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + levelflat->width = (UINT16)pngwidth; + levelflat->height = (UINT16)pngheight; + } + + // Make the mipmap. + if (mipmap == NULL) + { + mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_LEVEL, NULL); + mipmap->grInfo.format = GR_TEXFMT_P_8; + mipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; +#ifdef GLIDE_API_COMPATIBILITY + mipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; + mipmap->grInfo.largeLodLog2 = GR_LOD_LOG2_64; + mipmap->grInfo.aspectRatioLog2 = GR_ASPECT_LOG2_1x1; +#endif + levelflat->mipmap = mipmap; + } + + if (!mipmap->grInfo.data && !mipmap->downloaded) + { + mipmap->width = levelflat->width; + mipmap->height = levelflat->height; + size = (mipmap->width * mipmap->height); + flat = Z_Malloc(size, PU_LEVEL, &mipmap->grInfo.data); + if (levelflat->picture == NULL) + I_Error("HWR_GetLevelFlat: levelflat->picture == NULL"); + M_Memcpy(flat, levelflat->picture, size); + } + + // Tell the hardware driver to bind the current texture to the flat's mipmap + HWD.pfnSetTexture(mipmap); + } +#endif else // set no texture HWD.pfnSetTexture(NULL); } diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 23e52d19b..0194675b9 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -480,7 +480,6 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is float fflatwidth = 64.0f, fflatheight = 64.0f; INT32 flatflag = 63; boolean texflat = false; - size_t len; float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; FSurfaceInfo Surf; @@ -546,16 +545,9 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is // set texture for polygon if (levelflat != NULL) { - if (levelflat->type == LEVELFLAT_TEXTURE) + if (levelflat->type == LEVELFLAT_FLAT) { - fflatwidth = textures[levelflat->u.texture.num]->width; - fflatheight = textures[levelflat->u.texture.num]->height; - texflat = true; - } - else if (levelflat->type == LEVELFLAT_FLAT) - { - len = W_LumpLength(levelflat->u.flat.lumpnum); - + size_t len = W_LumpLength(levelflat->u.flat.lumpnum); switch (len) { case 4194304: // 2048x2048 lump @@ -580,9 +572,22 @@ static void HWR_RenderPlane(sector_t *sector, extrasubsector_t *xsub, boolean is fflatwidth = fflatheight = 64.0f; break; } - flatflag = ((INT32)fflatwidth)-1; } + else + { + if (levelflat->type == LEVELFLAT_TEXTURE) + { + fflatwidth = textures[levelflat->u.texture.num]->width; + fflatheight = textures[levelflat->u.texture.num]->height; + } + else if (levelflat->type == LEVELFLAT_PATCH || levelflat->type == LEVELFLAT_PNG) + { + fflatwidth = levelflat->width; + fflatheight = levelflat->height; + } + texflat = true; + } } else // set no texture HWD.pfnSetTexture(NULL); @@ -3142,7 +3147,6 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, float fflatwidth = 64.0f, fflatheight = 64.0f; INT32 flatflag = 63; boolean texflat = false; - size_t len; float scrollx = 0.0f, scrolly = 0.0f; angle_t angle = 0; FSurfaceInfo Surf; @@ -3176,16 +3180,9 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, // set texture for polygon if (levelflat != NULL) { - if (levelflat->type == LEVELFLAT_TEXTURE) + if (levelflat->type == LEVELFLAT_FLAT) { - fflatwidth = textures[levelflat->u.texture.num]->width; - fflatheight = textures[levelflat->u.texture.num]->height; - texflat = true; - } - else if (levelflat->type == LEVELFLAT_FLAT) - { - len = W_LumpLength(levelflat->u.flat.lumpnum); - + size_t len = W_LumpLength(levelflat->u.flat.lumpnum); switch (len) { case 4194304: // 2048x2048 lump @@ -3210,9 +3207,22 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling, fflatwidth = fflatheight = 64.0f; break; } - flatflag = ((INT32)fflatwidth)-1; } + else + { + if (levelflat->type == LEVELFLAT_TEXTURE) + { + fflatwidth = textures[levelflat->u.texture.num]->width; + fflatheight = textures[levelflat->u.texture.num]->height; + } + else if (levelflat->type == LEVELFLAT_PATCH || levelflat->type == LEVELFLAT_PNG) + { + fflatwidth = levelflat->width; + fflatheight = levelflat->height; + } + texflat = true; + } } else // set no texture HWD.pfnSetTexture(NULL); diff --git a/src/p_setup.c b/src/p_setup.c index 5014f0a7e..bdc979f9e 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -649,8 +649,6 @@ flatfound: Only need eight bytes for PNG headers. FIXME: Put this elsewhere. */ - if (flatpatch) - Z_Free(flatpatch); W_ReadLumpHeader(flatnum, buffer, 8, 0); if (Picture_IsLumpPNG(buffer, lumplength)) levelflat->type = LEVELFLAT_PNG; @@ -658,6 +656,8 @@ flatfound: #endif/*NO_PNG_LUMPS*/ levelflat->type = LEVELFLAT_FLAT;/* phew */ } + if (flatpatch) + Z_Free(flatpatch); levelflat->u.flat. lumpnum = flatnum; levelflat->u.flat.baselumpnum = LUMPERROR; diff --git a/src/p_setup.h b/src/p_setup.h index 77c932afc..75ba99a8f 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -37,9 +37,7 @@ enum LEVELFLAT_NONE,/* HOM time my friend */ LEVELFLAT_FLAT, LEVELFLAT_PATCH, -#ifndef NO_PNG_LUMPS LEVELFLAT_PNG, -#endif LEVELFLAT_TEXTURE, }; @@ -78,8 +76,11 @@ typedef struct INT32 numpics; INT32 speed; - // for patchflats - UINT8 *flatpatch; + // for textures + UINT8 *picture; +#ifdef HWRENDER + void *mipmap; +#endif } levelflat_t; extern size_t numlevelflats; diff --git a/src/r_textures.c b/src/r_textures.c index 5e03f57fc..2e9c65e5c 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -529,7 +529,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) } // If the texture changed, or the patch doesn't exist, convert either of them to a flat. - if (levelflat->flatpatch == NULL || texturechanged) + if (levelflat->picture == NULL || texturechanged) { // Level texture if (leveltexture) @@ -546,7 +546,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) M_Memcpy(texflat->flat, converted, size); Z_Free(converted); - levelflat->flatpatch = texflat->flat; + levelflat->picture = texflat->flat; levelflat->width = ds_flatwidth; levelflat->height = ds_flatheight; } @@ -557,7 +557,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) { INT32 pngwidth, pngheight; - levelflat->flatpatch = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); + levelflat->picture = Picture_PNGConvert(W_CacheLumpNum(levelflat->u.flat.lumpnum, PU_CACHE), PICFMT_FLAT, &pngwidth, &pngheight, NULL, NULL, W_LumpLength(levelflat->u.flat.lumpnum), NULL, 0); levelflat->width = (UINT16)pngwidth; levelflat->height = (UINT16)pngheight; @@ -575,9 +575,9 @@ void *R_GetLevelFlat(levelflat_t *levelflat) levelflat->width = ds_flatwidth = SHORT(patch->width); levelflat->height = ds_flatheight = SHORT(patch->height); - levelflat->flatpatch = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); + levelflat->picture = Z_Malloc(levelflat->width * levelflat->height, PU_LEVEL, NULL); converted = Picture_FlatConvert(PICFMT_PATCH, patch, PICFMT_FLAT, 0, &size, levelflat->width, levelflat->height, patch->topoffset, patch->leftoffset, 0); - M_Memcpy(levelflat->flatpatch, converted, size); + M_Memcpy(levelflat->picture, converted, size); Z_Free(converted); } } @@ -591,7 +591,7 @@ void *R_GetLevelFlat(levelflat_t *levelflat) levelflat->u.texture.lastnum = levelflat->u.texture.num; if (flatdata == NULL) - flatdata = levelflat->flatpatch; + flatdata = levelflat->picture; return flatdata; } From 854d31a08b3e099975673137f1b85f9693d6e840 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 14:11:57 -0300 Subject: [PATCH 16/27] How did I even manage to do this? --- src/r_textures.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/r_textures.h b/src/r_textures.h index 62ef523b2..6b7fc9f1c 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -18,7 +18,6 @@ #include "r_state.h" #include "p_setup.h" // levelflats #include "r_data.h" -#include "r_textures.h" #ifdef __GNUG__ #pragma interface From b8625d9efbe6bcb6a443c4fd1091a1ef4e018479 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Fri, 3 Jan 2020 23:25:26 -0300 Subject: [PATCH 17/27] AA trees are not needed at all for rotated patches --- src/hardware/hw_cache.c | 17 ----------------- src/hardware/hw_glob.h | 3 --- src/r_defs.h | 3 --- src/r_picformats.c | 6 ++++-- src/r_things.c | 3 --- 5 files changed, 4 insertions(+), 28 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index df1e18f9d..d8f491f48 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -1388,23 +1388,6 @@ GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum) return HWR_GetCachedGLPatchPwad(WADFILENUM(lumpnum),LUMPNUM(lumpnum)); } -#ifdef ROTSPRITE -GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch) -{ - GLPatch_t *grpatch; - - if (!(grpatch = M_AATreeGet(hwrcache, rollangle))) - { - grpatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); - grpatch->rawpatch = rawpatch; - grpatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); - M_AATreeSet(hwrcache, rollangle, grpatch); - } - - return grpatch; -} -#endif - // Need to do this because they aren't powers of 2 static void HWR_DrawFadeMaskInCache(GLMipmap_t *mipmap, INT32 pblockwidth, INT32 pblockheight, lumpnum_t fademasklumpnum, UINT16 fmwidth, UINT16 fmheight) diff --git a/src/hardware/hw_glob.h b/src/hardware/hw_glob.h index cf98e7317..a2bf79817 100644 --- a/src/hardware/hw_glob.h +++ b/src/hardware/hw_glob.h @@ -113,9 +113,6 @@ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum); void HWR_SetPalette(RGBA_t *palette); GLPatch_t *HWR_GetCachedGLPatchPwad(UINT16 wad, UINT16 lump); GLPatch_t *HWR_GetCachedGLPatch(lumpnum_t lumpnum); -#ifdef ROTSPRITE -GLPatch_t *HWR_GetCachedGLRotSprite(aatree_t *hwrcache, UINT16 rollangle, patch_t *rawpatch); -#endif void HWR_GetFadeMask(lumpnum_t fademasklumpnum); // -------- diff --git a/src/r_defs.h b/src/r_defs.h index c7c198d66..176f33c4f 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -729,9 +729,6 @@ typedef struct { patch_t *patch[8][ROTANGLES]; boolean cached[8]; -#ifdef HWRENDER - aatree_t *hardware_patch[8]; -#endif/*HWRENDER*/ } rotsprite_t; #endif/*ROTSPRITE*/ diff --git a/src/r_picformats.c b/src/r_picformats.c index 35fb0c055..e0688e31a 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1613,9 +1613,11 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp #ifdef HWRENDER if (rendermode == render_opengl) { - GLPatch_t *grPatch = HWR_GetCachedGLRotSprite(sprframe->rotsprite.hardware_patch[rot], angle, newpatch); - HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false); + GLPatch_t *grPatch = Z_Calloc(sizeof(GLPatch_t), PU_HWRPATCHINFO, NULL); + grPatch->mipmap = Z_Calloc(sizeof(GLMipmap_t), PU_HWRPATCHINFO, NULL); + grPatch->rawpatch = newpatch; sprframe->rotsprite.patch[rot][angle] = (patch_t *)grPatch; + HWR_MakePatch(newpatch, grPatch, grPatch->mipmap, false); } else #endif // HWRENDER diff --git a/src/r_things.c b/src/r_things.c index 5cd74ef7b..0f1dc87cd 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -125,9 +125,6 @@ static void R_InstallSpriteLump(UINT16 wad, // graphics patch sprtemp[frame].rotsprite.cached[r] = false; for (ang = 0; ang < ROTANGLES; ang++) sprtemp[frame].rotsprite.patch[r][ang] = NULL; -#ifdef HWRENDER - sprtemp[frame].rotsprite.hardware_patch[r] = M_AATreeAlloc(AATREE_ZUSER); -#endif/*HWRENDER*/ } #endif/*ROTSPRITE*/ From 79116ae471278e5448323bfa900fcac8e7ca89ed Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 16:51:02 -0300 Subject: [PATCH 18/27] Provide some cleaner method to generate textures as flats. R_GenerateTextureAsFlat --- src/r_textures.c | 71 ++++++++++++++++++++++++++++-------------------- src/r_textures.h | 15 ++++------ 2 files changed, 47 insertions(+), 39 deletions(-) diff --git a/src/r_textures.c b/src/r_textures.c index 2e9c65e5c..48049bc42 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -39,7 +39,7 @@ #include // -// MAPTEXTURE_T CACHING +// TEXTURE_T CACHING // When a texture is first needed, it counts the number of composite columns // required in the texture and allocates space for a column directory and // any new columns. @@ -52,7 +52,6 @@ INT32 numtextures = 0; // total number of textures found, // size of following tables texture_t **textures = NULL; -textureflat_t *texflats = NULL; UINT32 **texturecolumnofs; // column offset lookup table for each texture UINT8 **texturecache; // graphics data for each generated full-size texture @@ -451,6 +450,32 @@ done: return blocktex; } +// +// R_GenerateTextureAsFlat +// +// Generates a flat picture for a texture. +// +UINT8 *R_GenerateTextureAsFlat(size_t texnum) +{ + texture_t *texture = textures[texnum]; + UINT8 *converted = NULL; + size_t size = (texture->width * texture->height); + + // The flat picture for this texture was not generated yet. + if (!texture->flat) + { + // Well, let's do it now, then. + texture->flat = Z_Malloc(size, PU_STATIC, NULL); + + // Picture_TextureToFlat handles everything for us. + converted = (UINT8 *)Picture_TextureToFlat(texnum); + M_Memcpy(texture->flat, converted, size); + Z_Free(converted); + } + + return texture->flat; +} + // // R_GetTextureNum // @@ -509,46 +534,34 @@ void *R_GetFlat(lumpnum_t flatlumpnum) // void *R_GetLevelFlat(levelflat_t *levelflat) { + boolean isleveltexture = (levelflat->type == LEVELFLAT_TEXTURE); + texture_t *texture = (isleveltexture ? textures[levelflat->u.texture.num] : NULL); + boolean texturechanged = (isleveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); UINT8 *flatdata = NULL; - boolean leveltexture = (levelflat->type == LEVELFLAT_TEXTURE); - textureflat_t *texflat = &texflats[levelflat->u.texture.num]; - boolean texturechanged = (leveltexture ? (levelflat->u.texture.num != levelflat->u.texture.lastnum) : false); // Check if the texture changed. - if (leveltexture && (!texturechanged)) + if (isleveltexture && (!texturechanged)) { - if (texflat != NULL && texflat->flat) + if (texture->flat) { - flatdata = texflat->flat; - ds_flatwidth = texflat->width; - ds_flatheight = texflat->height; + flatdata = texture->flat; + ds_flatwidth = texture->width; + ds_flatheight = texture->height; texturechanged = false; } else texturechanged = true; } - // If the texture changed, or the patch doesn't exist, convert either of them to a flat. + // If the texture changed, or the flat wasn't generated, convert. if (levelflat->picture == NULL || texturechanged) { // Level texture - if (leveltexture) + if (isleveltexture) { - UINT8 *converted; - size_t size; - texture_t *texture = textures[levelflat->u.texture.num]; - texflat->width = ds_flatwidth = texture->width; - texflat->height = ds_flatheight = texture->height; - - size = (texflat->width * texflat->height); - texflat->flat = Z_Malloc(size, PU_LEVEL, NULL); - converted = (UINT8 *)Picture_TextureToFlat(levelflat->u.texture.num); - M_Memcpy(texflat->flat, converted, size); - Z_Free(converted); - - levelflat->picture = texflat->flat; - levelflat->width = ds_flatwidth; - levelflat->height = ds_flatheight; + levelflat->picture = R_GenerateTextureAsFlat(levelflat->u.texture.num); + ds_flatwidth = levelflat->width = texture->width; + ds_flatheight = levelflat->height = texture->height; } else { @@ -714,12 +727,13 @@ void R_LoadTextures(void) { for (i = 0; i < numtextures; i++) { + if (textures[i]->flat) + Z_Free(textures[i]->flat); Z_Free(textures[i]); Z_Free(texturecache[i]); } Z_Free(texturetranslation); Z_Free(textures); - Z_Free(texflats); } // Load patches and textures. @@ -816,7 +830,6 @@ countflats: // Allocate memory and initialize to 0 for all the textures we are initialising. // There are actually 5 buffers allocated in one for convenience. textures = Z_Calloc((numtextures * sizeof(void *)) * 5, PU_STATIC, NULL); - texflats = Z_Calloc((numtextures * sizeof(*texflats)), PU_STATIC, NULL); // Allocate texture column offset table. texturecolumnofs = (void *)((UINT8 *)textures + (numtextures * sizeof(void *))); diff --git a/src/r_textures.h b/src/r_textures.h index 6b7fc9f1c..74a94a9ed 100644 --- a/src/r_textures.h +++ b/src/r_textures.h @@ -47,8 +47,8 @@ enum #endif }; -// A maptexturedef_t describes a rectangular texture, -// which is composed of one or more mappatch_t structures +// A texture_t describes a rectangular texture, +// which is composed of one or more texpatch_t structures // that arrange graphic patches. typedef struct { @@ -58,21 +58,15 @@ typedef struct INT16 width, height; boolean holes; UINT8 flip; // 1 = flipx, 2 = flipy, 3 = both + void *flat; // The texture, as a flat. // All the patches[patchcount] are drawn back to front into the cached texture. INT16 patchcount; texpatch_t patches[0]; } texture_t; -typedef struct -{ - UINT8 *flat; - INT16 width, height; -} textureflat_t; - // all loaded and prepared textures from the start of the game extern texture_t **textures; -extern textureflat_t *texflats; extern INT32 *texturewidth; extern fixed_t *textureheight; // needed for texture pegging @@ -86,14 +80,15 @@ void R_FlushTextureCache(void); // Texture generation UINT8 *R_GenerateTexture(size_t texnum); +UINT8 *R_GenerateTextureAsFlat(size_t texnum); INT32 R_GetTextureNum(INT32 texnum); void R_CheckTextureCache(INT32 tex); void R_ClearTextureNumCache(boolean btell); // Retrieve texture data. +void *R_GetLevelFlat(levelflat_t *levelflat); UINT8 *R_GetColumn(fixed_t tex, INT32 col); void *R_GetFlat(lumpnum_t flatnum); -void *R_GetLevelFlat(levelflat_t *levelflat); boolean R_CheckPowersOfTwo(void); void R_CheckFlatLength(size_t size); From ce7f81c78db131674f460c35c1248818571b508a Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 18:52:12 -0300 Subject: [PATCH 19/27] use enum for bpp --- src/hardware/hw_cache.c | 14 +++++----- src/r_picformats.c | 60 ++++++++++++++++++++--------------------- src/r_picformats.h | 8 ++++++ 3 files changed, 46 insertions(+), 36 deletions(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index d8f491f48..c81c4bd4a 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -118,6 +118,10 @@ static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipm count--; texel = source[yfrac>>FRACBITS]; + alpha = 0xFF; + // Make pixel transparent if chroma keyed + if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)) + alpha = 0x00; //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) @@ -230,17 +234,15 @@ static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, count--; texel = source[yfrac>>FRACBITS]; + alpha = 0xFF; + // Make pixel transparent if chroma keyed + if ((mipmap->flags & TF_CHROMAKEYED) && (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX)) + alpha = 0x00; //Hurdler: 25/04/2000: now support colormap in hardware mode if (mipmap->colormap) texel = mipmap->colormap[texel]; - // transparent pixel - if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX) - alpha = 0x00; - else - alpha = 0xff; - // hope compiler will get this switch out of the loops (dreams...) // gcc do it ! but vcc not ! (why don't use cygwin gcc for win32 ?) // Alam: SRB2 uses Mingw, HUGS diff --git a/src/r_picformats.c b/src/r_picformats.c index e0688e31a..9cac5384d 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -128,9 +128,9 @@ void *Picture_PatchConvert( else if (informat == outformat) I_Error("Picture_PatchConvert: input and output formats were the same!"); - if (!inbpp) + if (inbpp == PICDEPTH_NONE) I_Error("Picture_PatchConvert: unknown input bits per pixel?!"); - if (!Picture_FormatBPP(outformat)) + if (Picture_FormatBPP(outformat) == PICDEPTH_NONE) I_Error("Picture_PatchConvert: unknown output bits per pixel?!"); // If it's a patch, you can just figure out @@ -199,17 +199,17 @@ void *Picture_PatchConvert( if (input != NULL) { UINT8 alpha = 0xFF; - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t px = *(RGBA_t *)input; alpha = px.s.alpha; } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) { UINT16 px = *(UINT16 *)input; alpha = (px & 0xFF00) >> 8; } - else if (inbpp == 8) + else if (inbpp == PICDEPTH_8BPP) { UINT8 px = *(UINT8 *)input; if (px == TRANSPARENTPIXEL) @@ -272,12 +272,12 @@ void *Picture_PatchConvert( { case PICFMT_PATCH32: { - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t out = *(RGBA_t *)input; WRITEUINT32(imgptr, out.rgba); } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) { RGBA_t out = pMasterPalette[*((UINT16 *)input) & 0xFF]; WRITEUINT32(imgptr, out.rgba); @@ -290,26 +290,26 @@ void *Picture_PatchConvert( break; } case PICFMT_PATCH16: - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); WRITEUINT16(imgptr, (0xFF00 | out)); } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) WRITEUINT16(imgptr, *(UINT16 *)input); else // PICFMT_PATCH WRITEUINT16(imgptr, (0xFF00 | (*(UINT8 *)input))); break; default: // PICFMT_PATCH { - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); WRITEUINT8(imgptr, out); } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) { UINT16 out = *(UINT16 *)input; WRITEUINT8(imgptr, (out & 0xFF)); @@ -377,9 +377,9 @@ void *Picture_FlatConvert( else if (informat == outformat) I_Error("Picture_FlatConvert: input and output formats were the same!"); - if (!inbpp) + if (inbpp == PICDEPTH_NONE) I_Error("Picture_FlatConvert: unknown input bits per pixel?!"); - if (!outbpp) + if (outbpp == PICDEPTH_NONE) I_Error("Picture_FlatConvert: unknown output bits per pixel?!"); // If it's a patch, you can just figure out @@ -397,7 +397,7 @@ void *Picture_FlatConvert( *outsize = size; // Set transparency - if (outbpp == 8) + if (outbpp == PICDEPTH_8BPP) memset(outflat, TRANSPARENTPIXEL, size); for (y = 0; y < inheight; y++) @@ -422,12 +422,12 @@ void *Picture_FlatConvert( case PICFMT_FLAT32: { UINT32 *f32 = (UINT32 *)outflat; - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t out = *(RGBA_t *)input; f32[offs] = out.rgba; } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) { RGBA_t out = pMasterPalette[*((UINT16 *)input) & 0xFF]; f32[offs] = out.rgba; @@ -442,13 +442,13 @@ void *Picture_FlatConvert( case PICFMT_FLAT16: { UINT16 *f16 = (UINT16 *)outflat; - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); f16[offs] = (0xFF00 | out); } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) f16[offs] = *(UINT16 *)input; else // PICFMT_PATCH f16[offs] = (0xFF00 | *((UINT8 *)input)); @@ -457,13 +457,13 @@ void *Picture_FlatConvert( case PICFMT_FLAT: { UINT8 *f8 = (UINT8 *)outflat; - if (inbpp == 32) + if (inbpp == PICDEPTH_32BPP) { RGBA_t in = *(RGBA_t *)input; UINT8 out = NearestColor(in.s.red, in.s.green, in.s.blue); f8[offs] = out; } - else if (inbpp == 16) + else if (inbpp == PICDEPTH_16BPP) { UINT16 out = *(UINT16 *)input; f8[offs] = (out & 0xFF); @@ -553,21 +553,21 @@ void *Picture_GetPatchPixel( */ INT32 Picture_FormatBPP(pictureformat_t format) { - INT32 bpp = 0; + INT32 bpp = PICDEPTH_NONE; switch (format) { case PICFMT_PATCH32: case PICFMT_FLAT32: case PICFMT_PNG: - bpp = 32; + bpp = PICDEPTH_32BPP; break; case PICFMT_PATCH16: case PICFMT_FLAT16: - bpp = 16; + bpp = PICDEPTH_16BPP; break; case PICFMT_PATCH: case PICFMT_FLAT: - bpp = 8; + bpp = PICDEPTH_8BPP; break; default: break; @@ -938,12 +938,12 @@ void *Picture_PNGConvert( if (Picture_IsPatchFormat(outformat)) { // Force a higher bit depth - if (outbpp == 8) - outbpp = 16; + if (outbpp == PICDEPTH_8BPP) + outbpp = PICDEPTH_16BPP; } // Shouldn't happen. - if (!outbpp) + if (outbpp == PICDEPTH_NONE) I_Error("Picture_PNGConvert: unknown output bits per pixel?!"); // Figure out the size @@ -955,7 +955,7 @@ void *Picture_PNGConvert( flat = Z_Calloc(flatsize, PU_STATIC, NULL); // Set transparency - if (outbpp == 8) + if (outbpp == PICDEPTH_8BPP) memset(flat, TRANSPARENTPIXEL, (width * height)); for (y = 0; y < height; y++) @@ -970,7 +970,7 @@ void *Picture_PNGConvert( UINT8 green = (UINT8)px[1]; UINT8 blue = (UINT8)px[2]; UINT8 alpha = (UINT8)px[3]; - if (outbpp == 32) + if (outbpp == PICDEPTH_32BPP) { UINT32 *outflat = (UINT32 *)flat; RGBA_t out; @@ -983,7 +983,7 @@ void *Picture_PNGConvert( else { UINT8 palidx = NearestColor(red, green, blue); - if (outbpp == 16) + if (outbpp == PICDEPTH_16BPP) { UINT16 *outflat = (UINT16 *)flat; outflat[((y * width) + x)] = (alpha << 8) | palidx; diff --git a/src/r_picformats.h b/src/r_picformats.h index 137ddbdd4..84a88e12f 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -43,6 +43,14 @@ typedef enum PICFLAGS_YFLIP = 1<<1 } pictureflags_t; +enum +{ + PICDEPTH_NONE = 0, + PICDEPTH_8BPP = 8, + PICDEPTH_16BPP = 16, + PICDEPTH_32BPP = 32 +}; + void *Picture_Convert( pictureformat_t informat, void *picture, pictureformat_t outformat, size_t insize, size_t *outsize, From ae748d6d5ca8ef85bfbc16047cd6a12cd3a5055d Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 19:00:57 -0300 Subject: [PATCH 20/27] Fix patch generation --- src/hardware/hw_cache.c | 3 ++- src/r_picformats.c | 9 +++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index c81c4bd4a..59504be73 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -708,7 +708,8 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm { // Dummy variables. INT32 pngwidth, pngheight; - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, NULL, NULL, len, NULL, 0); + INT16 topoffset, leftoffset; + patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, len, NULL, 0); } #endif diff --git a/src/r_picformats.c b/src/r_picformats.c index 9cac5384d..27d4c010f 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1478,6 +1478,15 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp patch = (patch_t *)W_CacheLumpNum(lump, PU_STATIC); lumplength = W_LumpLength(lump); +#ifndef NO_PNG_LUMPS + if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength)) + { + INT32 pngwidth, pngheight; + INT16 topoffset, leftoffset; + patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, lumplength, NULL, 0); + } + else +#endif // Because there's something wrong with SPR_DFLM, I guess if (!Picture_CheckIfPatch(patch, lumplength)) return; From 8202ea86b764f1f6be5a15393a7e68cdc29804b4 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 19:22:47 -0300 Subject: [PATCH 21/27] Fix Picture_GetPatchPixel --- src/r_picformats.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index 27d4c010f..cb235590a 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -532,14 +532,20 @@ void *Picture_GetPatchPixel( if ((topdelta + ofs) == y) { if (informat == PICFMT_PATCH32) - return (s32 + ofs); + return &s32[ofs]; else if (informat == PICFMT_PATCH16) - return (s16 + ofs); + return &s16[ofs]; else // PICFMT_PATCH - return (s8 + ofs); + return &s8[ofs]; } } - column = (column_t *)((UINT8 *)column + column->length + 4); + if (informat == PICFMT_PATCH32) + column = (column_t *)((UINT32 *)column + column->length); + else if (informat == PICFMT_PATCH16) + column = (column_t *)((UINT16 *)column + column->length); + else + column = (column_t *)((UINT8 *)column + column->length); + column = (column_t *)((UINT8 *)column + 4); } } From cdc2a8a923dcaaad48d549341d92bbb0e6edc384 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Tue, 7 Jan 2020 20:07:35 -0300 Subject: [PATCH 22/27] Fix shadowed declarations --- src/r_picformats.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index cb235590a..c7e54cf4e 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -1488,8 +1488,8 @@ void R_CacheRotSprite(spritenum_t sprnum, UINT8 frame, spriteinfo_t *sprinfo, sp if (Picture_IsLumpPNG((const UINT8 *)patch, lumplength)) { INT32 pngwidth, pngheight; - INT16 topoffset, leftoffset; - patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &topoffset, &leftoffset, lumplength, NULL, 0); + INT16 toffs, loffs; + patch = (patch_t *)Picture_PNGConvert((const UINT8 *)patch, PICFMT_PATCH, &pngwidth, &pngheight, &toffs, &loffs, lumplength, NULL, 0); } else #endif From 720695a6c44cb594ef38296291874bf35322f568 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Mon, 20 Jan 2020 17:03:38 -0300 Subject: [PATCH 23/27] Remove W_FlushCachedPatches --- src/console.c | 3 --- src/d_main.c | 8 -------- src/hardware/hw_cache.c | 28 ++-------------------------- src/hu_stuff.c | 3 --- src/m_menu.c | 3 --- src/r_main.c | 2 -- src/w_wad.c | 18 ------------------ src/w_wad.h | 1 - src/z_zone.c | 5 ----- 9 files changed, 2 insertions(+), 69 deletions(-) diff --git a/src/console.c b/src/console.c index ba5ba71df..890d424fa 100644 --- a/src/console.c +++ b/src/console.c @@ -1615,10 +1615,7 @@ void CON_Drawer(void) return; if (needpatchrecache) - { - W_FlushCachedPatches(); HU_LoadGraphics(); - } if (con_recalc) { diff --git a/src/d_main.c b/src/d_main.c index 15d3c8041..9891a525c 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -594,18 +594,10 @@ static void D_Display(void) needpatchrecache = false; } -// Lactozilla: Check the renderer's state -// after a possible renderer switch. void D_CheckRendererState(void) { - // flush all patches from memory - // (also frees memory tagged with PU_CACHE) - // (which are not necessarily patches but I don't care) if (needpatchflush) Z_FlushCachedPatches(); - - // some patches have been freed, - // so cache them again if (needpatchrecache) R_ReloadHUDGraphics(); } diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index b998b3360..5f364a3c5 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -971,9 +971,6 @@ static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) UINT8 *converted; size_t size; - if (needpatchflush) - W_FlushCachedPatches(); - // setup the texture info #ifdef GLIDE_API_COMPATIBILITY grMipmap->grInfo.smallLodLog2 = GR_LOD_LOG2_64; @@ -1000,9 +997,6 @@ void HWR_LiterallyGetFlat(lumpnum_t flatlumpnum) if (flatlumpnum == LUMPERROR) return; - if (needpatchflush) - W_FlushCachedPatches(); - grmip = HWR_GetCachedGLPatch(flatlumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFlat(grmip, flatlumpnum); @@ -1133,9 +1127,6 @@ static void HWR_LoadMappedPatch(GLMipmap_t *grmip, GLPatch_t *gpatch) // -----------------+ void HWR_GetPatch(GLPatch_t *gpatch) { - if (needpatchflush) - W_FlushCachedPatches(); - // is it in hardware cache if (!gpatch->mipmap->downloaded && !gpatch->mipmap->grInfo.data) { @@ -1166,9 +1157,6 @@ void HWR_GetMappedPatch(GLPatch_t *gpatch, const UINT8 *colormap) { GLMipmap_t *grmip, *newmip; - if (needpatchflush) - W_FlushCachedPatches(); - if (colormap == colormaps || colormap == NULL) { // Load the default (green) color in doom cache (temporary?) AND hardware cache @@ -1292,13 +1280,7 @@ static void HWR_DrawPicInCache(UINT8 *block, INT32 pblockwidth, INT32 pblockheig // -----------------+ GLPatch_t *HWR_GetPic(lumpnum_t lumpnum) { - GLPatch_t *grpatch; - - if (needpatchflush) - W_FlushCachedPatches(); - - grpatch = HWR_GetCachedGLPatch(lumpnum); - + GLPatch_t *grpatch = HWR_GetCachedGLPatch(lumpnum); if (!grpatch->mipmap->downloaded && !grpatch->mipmap->grInfo.data) { pic_t *pic; @@ -1481,13 +1463,7 @@ static void HWR_CacheFadeMask(GLMipmap_t *grMipmap, lumpnum_t fademasklumpnum) void HWR_GetFadeMask(lumpnum_t fademasklumpnum) { - GLMipmap_t *grmip; - - if (needpatchflush) - W_FlushCachedPatches(); - - grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; - + GLMipmap_t *grmip = HWR_GetCachedGLPatch(fademasklumpnum)->mipmap; if (!grmip->downloaded && !grmip->grInfo.data) HWR_CacheFadeMask(grmip, fademasklumpnum); diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 073b21b92..cf0204016 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -2100,9 +2100,6 @@ static void HU_DrawDemoInfo(void) // void HU_Drawer(void) { - if (needpatchrecache) - R_ReloadHUDGraphics(); - #ifndef NONET // draw chat string plus cursor if (chat_on) diff --git a/src/m_menu.c b/src/m_menu.c index 62bea7ae0..44ce674b4 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -8641,8 +8641,6 @@ void M_ForceSaveSlotSelected(INT32 sslot) // ================ // CHARACTER SELECT // ================ - -// lactozilla: sometimes the renderer changes and these patches don't exist anymore static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) { if (!(description[i].picname[0])) @@ -8874,7 +8872,6 @@ static void M_DrawSetupChoosePlayerMenu(void) INT32 x, y; INT32 w = (vid.width/vid.dupx); - // lactozilla: the renderer changed so recache patches if (needpatchrecache) M_CacheCharacterSelect(); diff --git a/src/r_main.c b/src/r_main.c index 4b044c6cc..0942d39d0 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -1176,7 +1176,6 @@ void R_RenderPlayerView(player_t *player) free(masks); } -// Lactozilla: Renderer switching #ifdef HWRENDER void R_InitHardwareMode(void) { @@ -1190,7 +1189,6 @@ void R_InitHardwareMode(void) void R_ReloadHUDGraphics(void) { - CONS_Debug(DBG_RENDER, "R_ReloadHUDGraphics()...\n"); ST_LoadGraphics(); HU_LoadGraphics(); ST_ReloadSkinFaceGraphics(); diff --git a/src/w_wad.c b/src/w_wad.c index 44a4854f8..ed98e4ad1 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1465,21 +1465,6 @@ boolean W_IsPatchCached(lumpnum_t lumpnum, void *ptr) return W_IsPatchCachedPWAD(WADFILENUM(lumpnum),LUMPNUM(lumpnum), ptr); } -void W_FlushCachedPatches(void) -{ - if (needpatchflush) - { - Z_FreeTag(PU_CACHE); - Z_FreeTag(PU_PATCH); - Z_FreeTag(PU_HUDGFX); - Z_FreeTag(PU_HWRPATCHINFO); - Z_FreeTag(PU_HWRMODELTEXTURE); - Z_FreeTag(PU_HWRCACHE); - Z_FreeTags(PU_HWRCACHE_UNLOCKED, PU_HWRPATCHINFO_UNLOCKED); - } - needpatchflush = false; -} - // ========================================================================== // W_CacheLumpName // ========================================================================== @@ -1509,9 +1494,6 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag) GLPatch_t *grPatch; #endif - if (needpatchflush) - W_FlushCachedPatches(); - if (!TestValidLump(wad, lump)) return NULL; diff --git a/src/w_wad.h b/src/w_wad.h index aca67c00f..8008a577c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -196,7 +196,6 @@ void *W_CachePatchNumPwad(UINT16 wad, UINT16 lump, INT32 tag); // return a patch void *W_CachePatchNum(lumpnum_t lumpnum, INT32 tag); // return a patch_t void W_UnlockCachedPatch(void *patch); -void W_FlushCachedPatches(void); void W_VerifyFileMD5(UINT16 wadfilenum, const char *matchmd5); diff --git a/src/z_zone.c b/src/z_zone.c index d02717007..edff5a60e 100644 --- a/src/z_zone.c +++ b/src/z_zone.c @@ -498,13 +498,9 @@ void Z_FreeTags(INT32 lowtag, INT32 hightag) // Utility functions // ----------------- -// for renderer switching, free a bunch of stuff boolean needpatchflush = false; boolean needpatchrecache = false; -// flush all patches from memory -// (also frees memory tagged with PU_CACHE) -// (which are not necessarily patches but I don't care) void Z_FlushCachedPatches(void) { CONS_Debug(DBG_RENDER, "Z_FlushCachedPatches()...\n"); @@ -518,7 +514,6 @@ void Z_FlushCachedPatches(void) Z_FreeTag(PU_HWRPATCHINFO_UNLOCKED); } -// happens before a renderer switch void Z_PreparePatchFlush(void) { CONS_Debug(DBG_RENDER, "Z_PreparePatchFlush()...\n"); From 5e28e358ad5342f9092b3daef0e9645ad6930dbf Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Fri, 15 May 2020 15:43:40 -0300 Subject: [PATCH 24/27] Fix memory leak --- src/r_textures.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/r_textures.c b/src/r_textures.c index 8ff85de43..7e3d8445d 100644 --- a/src/r_textures.c +++ b/src/r_textures.c @@ -410,10 +410,18 @@ UINT8 *R_GenerateTexture(size_t texnum) x2 = x1 + width; if (x1 > texture->width || x2 < 0) + { + if (dealloc) + Z_Free(realpatch); continue; // patch not located within texture's x bounds, ignore + } if (patch->originy > texture->height || (patch->originy + height) < 0) + { + if (dealloc) + Z_Free(realpatch); continue; // patch not located within texture's y bounds, ignore + } // patch is actually inside the texture! // now check if texture is partly off-screen and adjust accordingly From f24647dc4df0cf70be7eb684fd30c2c68b237410 Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 01:43:46 -0300 Subject: [PATCH 25/27] Change method of color look-up table generation --- src/m_anigif.c | 4 ++-- src/v_video.c | 57 ++++++++++++++++++++++++++++++++++++-------------- src/v_video.h | 15 ++++++++----- 3 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 83bc3dddc..8113e20d8 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -505,14 +505,14 @@ static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) size_t src = 0, dest = 0; size_t size = (vid.width * vid.height * 3); - InitColorLUT(gif_framepalette); + InitColorLUT(gif_framepalette, true); while (src < size) { r = (UINT8)linear[src]; g = (UINT8)linear[src + 1]; b = (UINT8)linear[src + 2]; - scr[dest] = colorlookup[r >> SHIFTCOLORBITS][g >> SHIFTCOLORBITS][b >> SHIFTCOLORBITS]; + scr[dest] = GetColorLUTDirect(r, g, b); src += (3 * scrbuf_downscaleamt); dest += scrbuf_downscaleamt; } diff --git a/src/v_video.c b/src/v_video.c index b88c4838b..3ac694dd4 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3666,28 +3666,53 @@ Unoptimized version #endif } -// Generates a color look-up table -// which has up to 64 colors at each channel -// (see the defines in v_video.h) +// Generates a RGB565 color look-up table +static colorlookup_t colorlookup; -UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; - -void InitColorLUT(RGBA_t *palette) +void InitColorLUT(RGBA_t *palette, boolean makecolors) { - UINT8 r, g, b; - static boolean clutinit = false; - static RGBA_t *lastpalette = NULL; - if ((!clutinit) || (lastpalette != palette)) + size_t palsize = (sizeof(RGBA_t) * 256); + + if (!colorlookup.init || memcmp(colorlookup.palette, palette, palsize)) { - for (r = 0; r < CLUTSIZE; r++) - for (g = 0; g < CLUTSIZE; g++) - for (b = 0; b < CLUTSIZE; b++) - colorlookup[r][g][b] = NearestPaletteColor(r << SHIFTCOLORBITS, g << SHIFTCOLORBITS, b << SHIFTCOLORBITS, palette); - clutinit = true; - lastpalette = palette; + INT32 i; + + colorlookup.init = true; + memcpy(colorlookup.palette, palette, palsize); + + for (i = 0; i < 0xFFFF; i++) + colorlookup.table[i] = 0xFFFF; + + if (makecolors) + { + UINT8 r, g, b; + + for (r = 0; r < 0xFF; r++) + for (g = 0; g < 0xFF; g++) + for (b = 0; b < 0xFF; b++) + { + i = CLUTINDEX(r, g, b); + if (colorlookup.table[i] == 0xFFFF) + colorlookup.table[i] = NearestPaletteColor(r, g, b, palette); + } + } } } +UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + if (colorlookup.table[i] == 0xFFFF) + colorlookup.table[i] = NearestPaletteColor(r << 3, g << 2, b << 3, colorlookup.palette); + return colorlookup.table[i]; +} + +UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b) +{ + INT32 i = CLUTINDEX(r, g, b); + return colorlookup.table[i]; +} + // V_Init // old software stuff, buffers are allocated at video mode setup // here we set the screens[x] pointers accordingly diff --git a/src/v_video.h b/src/v_video.h index 9f7a9a9e9..6cd10f606 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -38,13 +38,18 @@ cv_allcaps; void V_Init(void); // Color look-up table -#define COLORBITS 6 -#define SHIFTCOLORBITS (8-COLORBITS) -#define CLUTSIZE (1<> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) -extern UINT8 colorlookup[CLUTSIZE][CLUTSIZE][CLUTSIZE]; +void InitColorLUT(RGBA_t *palette, boolean makecolors); +UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b); +UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b); -void InitColorLUT(RGBA_t *palette); +typedef struct +{ + boolean init; + RGBA_t palette[256]; + UINT16 table[0xFFFF]; +} colorlookup_t; // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From 4e437076c10fd3184c5320ccaa2ca2a53834aadb Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 02:10:31 -0300 Subject: [PATCH 26/27] Use color look-up table for PNG conversion --- src/m_anigif.c | 6 ++++-- src/r_picformats.c | 13 +++++++++++++ src/r_picformats.h | 2 ++ src/v_video.c | 28 +++++++++++++--------------- src/v_video.h | 8 ++++---- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/m_anigif.c b/src/m_anigif.c index 8113e20d8..7c2bb359e 100644 --- a/src/m_anigif.c +++ b/src/m_anigif.c @@ -499,20 +499,22 @@ static size_t gifframe_size = 8192; // converts an RGB frame to a frame with a palette. // #ifdef HWRENDER +static colorlookup_t gif_colorlookup; + static void GIF_rgbconvert(UINT8 *linear, UINT8 *scr) { UINT8 r, g, b; size_t src = 0, dest = 0; size_t size = (vid.width * vid.height * 3); - InitColorLUT(gif_framepalette, true); + InitColorLUT(&gif_colorlookup, gif_framepalette, true); while (src < size) { r = (UINT8)linear[src]; g = (UINT8)linear[src + 1]; b = (UINT8)linear[src + 2]; - scr[dest] = GetColorLUTDirect(r, g, b); + scr[dest] = GetColorLUTDirect(&gif_colorlookup, r, g, b); src += (3 * scrbuf_downscaleamt); dest += scrbuf_downscaleamt; } diff --git a/src/r_picformats.c b/src/r_picformats.c index 39aaeef64..dbd090fc7 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -52,6 +52,10 @@ static unsigned char imgbuf[1<<26]; +#ifdef PICTURE_PNG_USELOOKUP +static colorlookup_t png_colorlookup; +#endif + /** Converts a picture between two formats. * * \param informat Input picture format. @@ -964,6 +968,11 @@ void *Picture_PNGConvert( if (outbpp == PICDEPTH_8BPP) memset(flat, TRANSPARENTPIXEL, (width * height)); +#ifdef PICTURE_PNG_USELOOKUP + if (outbpp != PICDEPTH_32BPP) + InitColorLUT(&png_colorlookup, pMasterPalette, false); +#endif + for (y = 0; y < height; y++) { png_bytep row = row_pointers[y]; @@ -988,7 +997,11 @@ void *Picture_PNGConvert( } else { +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else UINT8 palidx = NearestColor(red, green, blue); +#endif if (outbpp == PICDEPTH_16BPP) { UINT16 *outflat = (UINT16 *)flat; diff --git a/src/r_picformats.h b/src/r_picformats.h index 58c84b2c8..32754d64e 100644 --- a/src/r_picformats.h +++ b/src/r_picformats.h @@ -113,6 +113,8 @@ void *Picture_PNGConvert( boolean Picture_PNGDimensions(UINT8 *png, INT16 *width, INT16 *height, size_t size); #endif +#define PICTURE_PNG_USELOOKUP + // SpriteInfo extern spriteinfo_t spriteinfo[NUMSPRITES]; void R_LoadSpriteInfoLumps(UINT16 wadnum, UINT16 numlumps); diff --git a/src/v_video.c b/src/v_video.c index 3ac694dd4..26403b520 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -3667,21 +3667,19 @@ Unoptimized version } // Generates a RGB565 color look-up table -static colorlookup_t colorlookup; - -void InitColorLUT(RGBA_t *palette, boolean makecolors) +void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors) { size_t palsize = (sizeof(RGBA_t) * 256); - if (!colorlookup.init || memcmp(colorlookup.palette, palette, palsize)) + if (!lut->init || memcmp(lut->palette, palette, palsize)) { INT32 i; - colorlookup.init = true; - memcpy(colorlookup.palette, palette, palsize); + lut->init = true; + memcpy(lut->palette, palette, palsize); for (i = 0; i < 0xFFFF; i++) - colorlookup.table[i] = 0xFFFF; + lut->table[i] = 0xFFFF; if (makecolors) { @@ -3692,25 +3690,25 @@ void InitColorLUT(RGBA_t *palette, boolean makecolors) for (b = 0; b < 0xFF; b++) { i = CLUTINDEX(r, g, b); - if (colorlookup.table[i] == 0xFFFF) - colorlookup.table[i] = NearestPaletteColor(r, g, b, palette); + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, palette); } } } } -UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b) +UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) { INT32 i = CLUTINDEX(r, g, b); - if (colorlookup.table[i] == 0xFFFF) - colorlookup.table[i] = NearestPaletteColor(r << 3, g << 2, b << 3, colorlookup.palette); - return colorlookup.table[i]; + if (lut->table[i] == 0xFFFF) + lut->table[i] = NearestPaletteColor(r, g, b, lut->palette); + return lut->table[i]; } -UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b) +UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b) { INT32 i = CLUTINDEX(r, g, b); - return colorlookup.table[i]; + return lut->table[i]; } // V_Init diff --git a/src/v_video.h b/src/v_video.h index 6cd10f606..a6ca197bb 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -40,10 +40,6 @@ void V_Init(void); // Color look-up table #define CLUTINDEX(r, g, b) (((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3) -void InitColorLUT(RGBA_t *palette, boolean makecolors); -UINT8 GetColorLUT(UINT8 r, UINT8 g, UINT8 b); -UINT8 GetColorLUTDirect(UINT8 r, UINT8 g, UINT8 b); - typedef struct { boolean init; @@ -51,6 +47,10 @@ typedef struct UINT16 table[0xFFFF]; } colorlookup_t; +void InitColorLUT(colorlookup_t *lut, RGBA_t *palette, boolean makecolors); +UINT8 GetColorLUT(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); +UINT8 GetColorLUTDirect(colorlookup_t *lut, UINT8 r, UINT8 g, UINT8 b); + // Set the current RGB palette lookup to use for palettized graphics void V_SetPalette(INT32 palettenum); From 0750d273a6004ce73e9ce11f4b01c6eb7799b74e Mon Sep 17 00:00:00 2001 From: Jaime Passos Date: Thu, 10 Sep 2020 03:16:21 -0300 Subject: [PATCH 27/27] Attempt to use the PNG image's palette, if it is present --- src/r_picformats.c | 193 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 163 insertions(+), 30 deletions(-) diff --git a/src/r_picformats.c b/src/r_picformats.c index dbd090fc7..d48bbaaf2 100644 --- a/src/r_picformats.c +++ b/src/r_picformats.c @@ -798,13 +798,24 @@ static void PNG_warn(png_structp PNG, png_const_charp pngtext) CONS_Debug(DBG_RENDER, "libpng warning at %p: %s", PNG, pngtext); } -static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, size_t size) +static png_bytep *PNG_Read( + const UINT8 *png, + INT32 *w, INT32 *h, INT16 *topoffset, INT16 *leftoffset, + boolean *use_palette, size_t size) { png_structp png_ptr; png_infop png_info_ptr; png_uint_32 width, height; int bit_depth, color_type; png_uint_32 y; + + png_colorp palette; + int palette_size; + + png_bytep trans; + int trans_num; + png_color_16p trans_values; + #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD jmp_buf jmpbuf; @@ -864,10 +875,48 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse if (bit_depth == 16) png_set_strip_16(png_ptr); + palette = NULL; + *use_palette = false; + if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) png_set_gray_to_rgb(png_ptr); else if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); + { + boolean usepal = false; + + // Lactozilla: Check if the PNG has a palette, and if its color count + // matches the color count of SRB2's palette: 256 colors. + if (png_get_PLTE(png_ptr, png_info_ptr, &palette, &palette_size)) + { + if (palette_size == 256) + usepal = true; + } + + // If any of the tRNS colors have an alpha lower than 0xFF, and that + // color is present on the image, the palette flag is disabled. + png_get_tRNS(png_ptr, png_info_ptr, &trans, &trans_num, &trans_values); + + if (trans_num == 256) + { + int i; + for (i = 0; i < trans_num; i++) + { + // libpng will transform this image into RGB even if + // the transparent index does not exist in the image, + // and there is no way around that. + if (trans[i] < 0xFF) + { + usepal = false; + break; + } + } + } + + if (usepal) + *use_palette = true; + else + png_set_palette_to_rgb(png_ptr); + } if (png_get_valid(png_ptr, png_info_ptr, PNG_INFO_tRNS)) png_set_tRNS_to_alpha(png_ptr); @@ -908,6 +957,7 @@ static png_bytep *PNG_Read(const UINT8 *png, INT32 *w, INT32 *h, INT16 *topoffse *w = (INT32)width; *h = (INT32)height; + return row_pointers; } @@ -935,12 +985,17 @@ void *Picture_PNGConvert( INT32 outbpp; size_t flatsize; png_uint_32 x, y; - png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, insize); + png_bytep row; + boolean palette = false; + png_bytep *row_pointers = PNG_Read(png, w, h, topoffset, leftoffset, &palette, insize); png_uint_32 width = *w, height = *h; if (png == NULL) I_Error("Picture_PNGConvert: picture was NULL!"); + if (row_pointers == NULL) + I_Error("Picture_PNGConvert: row_pointers was NULL!"); + // Find the output format's bits per pixel amount outbpp = Picture_FormatBPP(outformat); @@ -973,43 +1028,119 @@ void *Picture_PNGConvert( InitColorLUT(&png_colorlookup, pMasterPalette, false); #endif - for (y = 0; y < height; y++) + if (outbpp == PICDEPTH_32BPP) { - png_bytep row = row_pointers[y]; - for (x = 0; x < width; x++) + RGBA_t out; + UINT32 *outflat = (UINT32 *)flat; + + if (palette) { - png_bytep px = &(row[x * 4]); - if ((UINT8)px[3]) + for (y = 0; y < height; y++) { - UINT8 red = (UINT8)px[0]; - UINT8 green = (UINT8)px[1]; - UINT8 blue = (UINT8)px[2]; - UINT8 alpha = (UINT8)px[3]; - if (outbpp == PICDEPTH_32BPP) + row = row_pointers[y]; + for (x = 0; x < width; x++) { - UINT32 *outflat = (UINT32 *)flat; - RGBA_t out; - out.s.red = red; - out.s.green = green; - out.s.blue = blue; - out.s.alpha = alpha; + out = V_GetColor(row[x]); outflat[((y * width) + x)] = out.rgba; } - else + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) { -#ifdef PICTURE_PNG_USELOOKUP - UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); -#else - UINT8 palidx = NearestColor(red, green, blue); -#endif - if (outbpp == PICDEPTH_16BPP) + png_bytep px = &(row[x * 4]); + if ((UINT8)px[3]) { - UINT16 *outflat = (UINT16 *)flat; - outflat[((y * width) + x)] = (alpha << 8) | palidx; + out.s.red = (UINT8)px[0]; + out.s.green = (UINT8)px[1]; + out.s.blue = (UINT8)px[2]; + out.s.alpha = (UINT8)px[3]; + outflat[((y * width) + x)] = out.rgba; } - else // 8bpp + else + outflat[((y * width) + x)] = 0x00000000; + } + } + } + } + else if (outbpp == PICDEPTH_16BPP) + { + UINT16 *outflat = (UINT16 *)flat; + + if (palette) + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + outflat[((y * width) + x)] = (0xFF << 8) | row[x]; + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + { + png_bytep px = &(row[x * 4]); + UINT8 red = (UINT8)px[0]; + UINT8 green = (UINT8)px[1]; + UINT8 blue = (UINT8)px[2]; + UINT8 alpha = (UINT8)px[3]; + + if (alpha) { - UINT8 *outflat = (UINT8 *)flat; +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else + UINT8 palidx = NearestColor(red, green, blue); +#endif + outflat[((y * width) + x)] = (0xFF << 8) | palidx; + } + else + outflat[((y * width) + x)] = 0x0000; + } + } + } + } + else // 8bpp + { + UINT8 *outflat = (UINT8 *)flat; + + if (palette) + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + outflat[((y * width) + x)] = row[x]; + } + } + else + { + for (y = 0; y < height; y++) + { + row = row_pointers[y]; + for (x = 0; x < width; x++) + { + png_bytep px = &(row[x * 4]); + UINT8 red = (UINT8)px[0]; + UINT8 green = (UINT8)px[1]; + UINT8 blue = (UINT8)px[2]; + UINT8 alpha = (UINT8)px[3]; + + if (alpha) + { +#ifdef PICTURE_PNG_USELOOKUP + UINT8 palidx = GetColorLUT(&png_colorlookup, red, green, blue); +#else + UINT8 palidx = NearestColor(red, green, blue); +#endif outflat[((y * width) + x)] = palidx; } } @@ -1018,6 +1149,8 @@ void *Picture_PNGConvert( } // Free the row pointers that we allocated for libpng. + for (y = 0; y < height; y++) + free(row_pointers[y]); free(row_pointers); // But wait, there's more!