diff --git a/src/hardware/hw_cache.c b/src/hardware/hw_cache.c index 395fc2e4b..6bc2c712e 100644 --- a/src/hardware/hw_cache.c +++ b/src/hardware/hw_cache.c @@ -41,37 +41,316 @@ static INT32 blocksize, blockwidth, blockheight; INT32 patchformat = GR_TEXFMT_AP_88; // use alpha for holes INT32 textureformat = GR_TEXFMT_P_8; // use chromakey for hole -// sprite, use alpha and chroma key for hole +static const INT32 format2bpp[16] = +{ + 0, //0 + 0, //1 + 1, //2 GR_TEXFMT_ALPHA_8 + 1, //3 GR_TEXFMT_INTENSITY_8 + 1, //4 GR_TEXFMT_ALPHA_INTENSITY_44 + 1, //5 GR_TEXFMT_P_8 + 4, //6 GR_RGBA + 0, //7 + 0, //8 + 0, //9 + 2, //10 GR_TEXFMT_RGB_565 + 2, //11 GR_TEXFMT_ARGB_1555 + 2, //12 GR_TEXFMT_ARGB_4444 + 2, //13 GR_TEXFMT_ALPHA_INTENSITY_88 + 2, //14 GR_TEXFMT_AP_88 +}; + + +// This code was originally placed directly in HWR_DrawPatchInCache. +// It is now split from it for my sanity! (and the sanity of others) +// -- Monster Iestyn (13/02/19) +static void HWR_DrawColumnInCache(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap, + INT32 pblockheight, INT32 blockmodulo, + fixed_t yfracstep, fixed_t scale_y, + texpatch_t *originPatch, INT32 patchheight, + INT32 bpp) +{ + fixed_t yfrac, position, count; + UINT8 *dest; + const UINT8 *source; + INT32 topdelta, prevdelta = -1; + INT32 originy = 0; + + // for writing a pixel to dest + RGBA_t colortemp; + UINT8 alpha; + UINT8 texel; + UINT16 texelu16; + + (void)patchheight; // This parameter is unused + + if (originPatch) // originPatch can be NULL here, unlike in the software version + originy = originPatch->originy; + + while (patchcol->topdelta != 0xff) + { + topdelta = patchcol->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + source = (const UINT8 *)patchcol + 3; + count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS; + position = originy + topdelta; + + yfrac = 0; + //yfracstep = (patchcol->length << FRACBITS) / count; + if (position < 0) + { + yfrac = -position<> FRACBITS); + position = 0; + } + + position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS; + + if (position < 0) + position = 0; + + if (position + count >= pblockheight) + count = pblockheight - position; + + dest = block + (position*blockmodulo); + while (count > 0) + { + count--; + + texel = source[yfrac>>FRACBITS]; + + if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel)) + alpha = 0x80; + else + alpha = 0xff; + + //Hurdler: not perfect, but better than holes + if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED)) + texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX; + //Hurdler: 25/04/2000: now support colormap in hardware mode + else if (mipmap->colormap) + texel = mipmap->colormap[texel]; + + // 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 + switch (bpp) + { + case 2 : texelu16 = (UINT16)((alpha<<8) | texel); + memcpy(dest, &texelu16, sizeof(UINT16)); + break; + case 3 : colortemp = V_GetColor(texel); + memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); + break; + case 4 : colortemp = V_GetColor(texel); + colortemp.s.alpha = alpha; + memcpy(dest, &colortemp, sizeof(RGBA_t)); + break; + // default is 1 + default: *dest = texel; + break; + } + + dest += blockmodulo; + yfrac += yfracstep; + } + patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4); + } +} + +static void HWR_DrawFlippedColumnInCache(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap, + INT32 pblockheight, INT32 blockmodulo, + fixed_t yfracstep, fixed_t scale_y, + texpatch_t *originPatch, INT32 patchheight, + INT32 bpp) +{ + fixed_t yfrac, position, count; + UINT8 *dest; + const UINT8 *source; + INT32 topdelta, prevdelta = -1; + INT32 originy = 0; + + // for writing a pixel to dest + RGBA_t colortemp; + UINT8 alpha; + UINT8 texel; + UINT16 texelu16; + + if (originPatch) // originPatch can be NULL here, unlike in the software version + originy = originPatch->originy; + + while (patchcol->topdelta != 0xff) + { + topdelta = patchcol->topdelta; + if (topdelta <= prevdelta) + topdelta += prevdelta; + prevdelta = topdelta; + topdelta = patchheight-patchcol->length-topdelta; + source = (const UINT8 *)patchcol + 3; + count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS; + position = originy + topdelta; + + yfrac = (patchcol->length-1) << FRACBITS; + + if (position < 0) + { + yfrac += position<> FRACBITS); + position = 0; + } + + position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS; + + if (position < 0) + position = 0; + + if (position + count >= pblockheight) + count = pblockheight - position; + + dest = block + (position*blockmodulo); + while (count > 0) + { + count--; + + texel = source[yfrac>>FRACBITS]; + + if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel)) + alpha = 0x80; + else + alpha = 0xff; + + //Hurdler: not perfect, but better than holes + if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED)) + texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX; + //Hurdler: 25/04/2000: now support colormap in hardware mode + else if (mipmap->colormap) + texel = mipmap->colormap[texel]; + + // 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 + switch (bpp) + { + case 2 : texelu16 = (UINT16)((alpha<<8) | texel); + memcpy(dest, &texelu16, sizeof(UINT16)); + break; + case 3 : colortemp = V_GetColor(texel); + memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); + break; + case 4 : colortemp = V_GetColor(texel); + colortemp.s.alpha = alpha; + memcpy(dest, &colortemp, sizeof(RGBA_t)); + break; + // default is 1 + default: *dest = texel; + break; + } + + dest += blockmodulo; + yfrac -= yfracstep; + } + patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4); + } +} + + +// Simplified patch caching function +// for use by sprites and other patches that are not part of a wall texture +// no alpha or flipping should be present since we do not want non-texture graphics to have them +// no offsets are used either +// -- Monster Iestyn (13/02/19) static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, - INT32 pblockwidth, INT32 pblockheight, INT32 blockmodulo, - INT32 ptexturewidth, INT32 ptextureheight, - INT32 originx, INT32 originy, // where to draw patch in surface block - const patch_t *realpatch, INT32 bpp) + INT32 pblockwidth, INT32 pblockheight, + INT32 pwidth, INT32 pheight, + const patch_t *realpatch) +{ + INT32 ncols; + fixed_t xfrac, xfracstep; + fixed_t yfracstep, scale_y; + const column_t *patchcol; + UINT8 *block = mipmap->grInfo.data; + INT32 bpp; + INT32 blockmodulo; + + if (pwidth <= 0 || pheight <= 0) + return; + + ncols = (pwidth * pblockwidth) / pwidth; + + // source advance + xfrac = 0; + xfracstep = (pwidth << FRACBITS) / pblockwidth; + yfracstep = (pheight << FRACBITS) / pblockheight; + scale_y = (pblockheight << FRACBITS) / pheight; + + bpp = format2bpp[mipmap->grInfo.format]; + + if (bpp < 1 || bpp > 4) + I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); + + // NOTE: should this actually be pblockwidth*bpp? + blockmodulo = blockwidth*bpp; + + // Draw each column to the block cache + for (; ncols--; block += bpp, xfrac += xfracstep) + { + patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS])); + + HWR_DrawColumnInCache(patchcol, block, mipmap, + pblockheight, blockmodulo, + yfracstep, scale_y, + NULL, pheight, // not that pheight is going to get used anyway... + bpp); + } +} + +// This function we use for caching patches that belong to textures +static void HWR_DrawTexturePatchInCache(GLMipmap_t *mipmap, + INT32 pblockwidth, INT32 pblockheight, + texture_t *texture, texpatch_t *patch, + const patch_t *realpatch) { INT32 x, x1, x2; INT32 col, ncols; fixed_t xfrac, xfracstep; - fixed_t yfrac, yfracstep, position, count; - fixed_t scale_y; - RGBA_t colortemp; - UINT8 *dest; - const UINT8 *source; + fixed_t yfracstep, scale_y; const column_t *patchcol; - UINT8 alpha; UINT8 *block = mipmap->grInfo.data; - UINT8 texel; - UINT16 texelu16; + INT32 bpp; + INT32 blockmodulo; + INT32 width, height; + // Column drawing function pointer. + static void (*ColumnDrawerPointer)(const column_t *patchcol, UINT8 *block, GLMipmap_t *mipmap, + INT32 pblockheight, INT32 blockmodulo, + fixed_t yfracstep, fixed_t scale_y, + texpatch_t *originPatch, INT32 patchheight, + INT32 bpp); - if (!ptexturewidth) + if (texture->width <= 0 || texture->height <= 0) return; - x1 = originx; - x2 = x1 + SHORT(realpatch->width); + /*if ((patch->style == AST_TRANSLUCENT) && (patch->alpha <= (10*255/11))) // Alpha style set to translucent? Is the alpha small enough for translucency? + { + if (patch->alpha < 255/11) // Is the patch way too translucent? Don't render then. + continue; + ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawTransFlippedColumnInCache : HWR_DrawTransColumnInCache; + } + else*/ + { + ColumnDrawerPointer = (patch->flip & 2) ? HWR_DrawFlippedColumnInCache : HWR_DrawColumnInCache; + } - if (x1 > ptexturewidth || x2 < 0) + x1 = patch->originx; + width = SHORT(realpatch->width); + height = SHORT(realpatch->height); + x2 = x1 + width; + + if (x1 > texture->width || x2 < 0) return; // patch not located within texture's x bounds, ignore - if (originy > ptextureheight || (originy + SHORT(realpatch->height)) < 0) + if (patch->originy > texture->height || (patch->originy + height) < 0) return; // patch not located within texture's y bounds, ignore // patch is actually inside the texture! @@ -84,19 +363,18 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, x = x1; // right edge - if (x2 > ptexturewidth) - x2 = ptexturewidth; + if (x2 > texture->width) + x2 = texture->width; - col = x * pblockwidth / ptexturewidth; - ncols = ((x2 - x) * pblockwidth) / ptexturewidth; + col = x * pblockwidth / texture->width; + ncols = ((x2 - x) * pblockwidth) / texture->width; /* - CONS_Debug(DBG_RENDER, "patch %dx%d texture %dx%d block %dx%d\n", SHORT(realpatch->width), - SHORT(realpatch->height), - ptexturewidth, - textureheight, - pblockwidth,pblockheight); + CONS_Debug(DBG_RENDER, "patch %dx%d texture %dx%d block %dx%d\n", + width, height, + texture->width, texture->height, + pblockwidth, pblockheight); CONS_Debug(DBG_RENDER, " col %d ncols %d x %d\n", col, ncols, x); */ @@ -105,90 +383,31 @@ static void HWR_DrawPatchInCache(GLMipmap_t *mipmap, if (x1 < 0) xfrac = -x1<width << FRACBITS) / pblockwidth; + yfracstep = (texture->height<< FRACBITS) / pblockheight; + scale_y = (pblockheight << FRACBITS) / texture->height; + + bpp = format2bpp[mipmap->grInfo.format]; + if (bpp < 1 || bpp > 4) I_Error("HWR_DrawPatchInCache: no drawer defined for this bpp (%d)\n",bpp); + // NOTE: should this actually be pblockwidth*bpp? + blockmodulo = blockwidth*bpp; + + // Draw each column to the block cache for (block += col*bpp; ncols--; block += bpp, xfrac += xfracstep) { - INT32 topdelta, prevdelta = -1; - patchcol = (const column_t *)((const UINT8 *)realpatch - + LONG(realpatch->columnofs[xfrac>>FRACBITS])); + if (patch->flip & 1) + patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[(width-1)-(xfrac>>FRACBITS)])); + else + patchcol = (const column_t *)((const UINT8 *)realpatch + LONG(realpatch->columnofs[xfrac>>FRACBITS])); - scale_y = (pblockheight << FRACBITS) / ptextureheight; - - while (patchcol->topdelta != 0xff) - { - topdelta = patchcol->topdelta; - if (topdelta <= prevdelta) - topdelta += prevdelta; - prevdelta = topdelta; - source = (const UINT8 *)patchcol + 3; - count = ((patchcol->length * scale_y) + (FRACUNIT/2)) >> FRACBITS; - position = originy + topdelta; - - yfrac = 0; - //yfracstep = (patchcol->length << FRACBITS) / count; - if (position < 0) - { - yfrac = -position<> FRACBITS); - position = 0; - } - - position = ((position * scale_y) + (FRACUNIT/2)) >> FRACBITS; - - if (position < 0) - position = 0; - - if (position + count >= pblockheight) - count = pblockheight - position; - - dest = block + (position*blockmodulo); - while (count > 0) - { - count--; - - texel = source[yfrac>>FRACBITS]; - - if (firetranslucent && (transtables[(texel<<8)+0x40000]!=texel)) - alpha = 0x80; - else - alpha = 0xff; - - //Hurdler: not perfect, but better than holes - if (texel == HWR_PATCHES_CHROMAKEY_COLORINDEX && (mipmap->flags & TF_CHROMAKEYED)) - texel = HWR_CHROMAKEY_EQUIVALENTCOLORINDEX; - //Hurdler: 25/04/2000: now support colormap in hardware mode - else if (mipmap->colormap) - texel = mipmap->colormap[texel]; - - // 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 - switch (bpp) - { - case 2 : texelu16 = (UINT16)((alpha<<8) | texel); - memcpy(dest, &texelu16, sizeof(UINT16)); - break; - case 3 : colortemp = V_GetColor(texel); - memcpy(dest, &colortemp, sizeof(RGBA_t)-sizeof(UINT8)); - break; - case 4 : colortemp = V_GetColor(texel); - colortemp.s.alpha = alpha; - memcpy(dest, &colortemp, sizeof(RGBA_t)); - break; - // default is 1 - default: *dest = texel; - break; - } - - dest += blockmodulo; - yfrac += yfracstep; - } - patchcol = (const column_t *)((const UINT8 *)patchcol + patchcol->length + 4); - } + ColumnDrawerPointer(patchcol, block, mipmap, + pblockheight, blockmodulo, + yfracstep, scale_y, + patch, height, + bpp); } } @@ -349,26 +568,6 @@ static void HWR_ResizeBlock(INT32 originalwidth, INT32 originalheight, //CONS_Debug(DBG_RENDER, "Width is %d, Height is %d\n", blockwidth, blockheight); } - -static const INT32 format2bpp[16] = -{ - 0, //0 - 0, //1 - 1, //2 GR_TEXFMT_ALPHA_8 - 1, //3 GR_TEXFMT_INTENSITY_8 - 1, //4 GR_TEXFMT_ALPHA_INTENSITY_44 - 1, //5 GR_TEXFMT_P_8 - 4, //6 GR_RGBA - 0, //7 - 0, //8 - 0, //9 - 2, //10 GR_TEXFMT_RGB_565 - 2, //11 GR_TEXFMT_ARGB_1555 - 2, //12 GR_TEXFMT_ARGB_4444 - 2, //13 GR_TEXFMT_ALPHA_INTENSITY_88 - 2, //14 GR_TEXFMT_AP_88 -}; - static UINT8 *MakeBlock(GLMipmap_t *grMipmap) { UINT8 *block; @@ -452,13 +651,10 @@ static void HWR_GenerateTexture(INT32 texnum, GLTexture_t *grtex) for (i = 0, patch = texture->patches; i < texture->patchcount; i++, patch++) { realpatch = W_CacheLumpNumPwad(patch->wad, patch->lump, PU_CACHE); - HWR_DrawPatchInCache(&grtex->mipmap, + HWR_DrawTexturePatchInCache(&grtex->mipmap, blockwidth, blockheight, - blockwidth*format2bpp[grtex->mipmap.grInfo.format], - texture->width, texture->height, - patch->originx, patch->originy, - realpatch, - format2bpp[grtex->mipmap.grInfo.format]); + texture, patch, + realpatch); Z_Unlock(realpatch); } //Hurdler: not efficient at all but I don't remember exactly how HWR_DrawPatchInCache works :( @@ -545,11 +741,8 @@ void HWR_MakePatch (const patch_t *patch, GLPatch_t *grPatch, GLMipmap_t *grMipm HWR_DrawPatchInCache(grMipmap, newwidth, newheight, - blockwidth*format2bpp[grMipmap->grInfo.format], grPatch->width, grPatch->height, - 0, 0, - patch, - format2bpp[grMipmap->grInfo.format]); + patch); } grPatch->max_s = (float)newwidth / (float)blockwidth;