Merge branch 'po2-32x32-fix' into 'next'

Add PO2 flat cases for sizes smaller than 32x32 (resolves #624)

Closes #624

See merge request STJr/SRB2!1873
This commit is contained in:
Eidolon 2022-11-16 01:40:54 +00:00
commit 84bc03d24e
15 changed files with 351 additions and 398 deletions

View file

@ -804,45 +804,18 @@ GLMapTexture_t *HWR_GetTexture(INT32 tex)
static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum) static void HWR_CacheFlat(GLMipmap_t *grMipmap, lumpnum_t flatlumpnum)
{ {
size_t size, pflatsize; size_t size = W_LumpLength(flatlumpnum);
UINT16 pflatsize = R_GetFlatSize(size);
// setup the texture info // setup the texture info
grMipmap->format = GL_TEXFMT_P_8; grMipmap->format = GL_TEXFMT_P_8;
grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED; grMipmap->flags = TF_WRAPXY|TF_CHROMAKEYED;
size = W_LumpLength(flatlumpnum); grMipmap->width = pflatsize;
grMipmap->height = pflatsize;
switch (size)
{
case 4194304: // 2048x2048 lump
pflatsize = 2048;
break;
case 1048576: // 1024x1024 lump
pflatsize = 1024;
break;
case 262144:// 512x512 lump
pflatsize = 512;
break;
case 65536: // 256x256 lump
pflatsize = 256;
break;
case 16384: // 128x128 lump
pflatsize = 128;
break;
case 1024: // 32x32 lump
pflatsize = 32;
break;
default: // 64x64 lump
pflatsize = 64;
break;
}
grMipmap->width = (UINT16)pflatsize;
grMipmap->height = (UINT16)pflatsize;
// the flat raw data needn't be converted with palettized textures // the flat raw data needn't be converted with palettized textures
W_ReadLump(flatlumpnum, Z_Malloc(W_LumpLength(flatlumpnum), W_ReadLump(flatlumpnum, Z_Malloc(size, PU_HWRCACHE, &grMipmap->data));
PU_HWRCACHE, &grMipmap->data));
} }
static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum) static void HWR_CacheTextureAsFlat(GLMipmap_t *grMipmap, INT32 texturenum)

View file

@ -705,42 +705,10 @@ void HWR_DrawPic(INT32 x, INT32 y, lumpnum_t lumpnum)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum) void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum)
{ {
FOutVector v[4]; FOutVector v[4];
double dflatsize;
INT32 flatflag;
const size_t len = W_LumpLength(flatlumpnum); const size_t len = W_LumpLength(flatlumpnum);
UINT16 flatflag = R_GetFlatSize(len) - 1;
switch (len) double dflatsize = (double)(flatflag + 1);
{
case 4194304: // 2048x2048 lump
dflatsize = 2048.0f;
flatflag = 2047;
break;
case 1048576: // 1024x1024 lump
dflatsize = 1024.0f;
flatflag = 1023;
break;
case 262144:// 512x512 lump
dflatsize = 512.0f;
flatflag = 511;
break;
case 65536: // 256x256 lump
dflatsize = 256.0f;
flatflag = 255;
break;
case 16384: // 128x128 lump
dflatsize = 128.0f;
flatflag = 127;
break;
case 1024: // 32x32 lump
dflatsize = 32.0f;
flatflag = 31;
break;
default: // 64x64 lump
dflatsize = 64.0f;
flatflag = 63;
break;
}
// 3--2 // 3--2
// | /| // | /|
@ -754,7 +722,6 @@ void HWR_DrawFlatFill (INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatlumpnum
v[0].z = v[1].z = v[2].z = v[3].z = 1.0f; v[0].z = v[1].z = v[2].z = v[3].z = 1.0f;
// flat is 64x64 lod and texture offsets are [0.0, 1.0]
v[0].s = v[3].s = (float)((x & flatflag)/dflatsize); v[0].s = v[3].s = (float)((x & flatflag)/dflatsize);
v[2].s = v[1].s = (float)(v[0].s + w/dflatsize); v[2].s = v[1].s = (float)(v[0].s + w/dflatsize);
v[0].t = v[1].t = (float)((y & flatflag)/dflatsize); v[0].t = v[1].t = (float)((y & flatflag)/dflatsize);

View file

@ -360,30 +360,39 @@ static FUINT HWR_CalcSlopeLight(FUINT lightnum, angle_t dir, fixed_t delta)
// -----------------+ // -----------------+
static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap) static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, boolean isceiling, fixed_t fixedheight, FBITFIELD PolyFlags, INT32 lightlevel, levelflat_t *levelflat, sector_t *FOFsector, UINT8 alpha, extracolormap_t *planecolormap)
{ {
polyvertex_t * pv; FSurfaceInfo Surf;
float height; //constant y for all points on the convex flat polygon FOutVector *v3d;
FOutVector *v3d; polyvertex_t *pv;
INT32 nrPlaneVerts; //verts original define of convex flat polygon
INT32 i;
float flatxref,flatyref;
float fflatwidth = 64.0f, fflatheight = 64.0f;
INT32 flatflag = 63;
boolean texflat = false;
float scrollx = 0.0f, scrolly = 0.0f, anglef = 0.0f;
angle_t angle = 0;
FSurfaceInfo Surf;
float tempxsow, tempytow;
pslope_t *slope = NULL; pslope_t *slope = NULL;
INT32 shader = SHADER_DEFAULT;
size_t nrPlaneVerts;
INT32 i;
float height; // constant y for all points on the convex flat polygon
float flatxref, flatyref, anglef = 0.0f;
float fflatwidth = 64.0f, fflatheight = 64.0f;
UINT16 flatflag = 63;
boolean texflat = false;
float tempxsow, tempytow;
float scrollx = 0.0f, scrolly = 0.0f;
angle_t angle = 0;
static FOutVector *planeVerts = NULL; static FOutVector *planeVerts = NULL;
static UINT16 numAllocedPlaneVerts = 0; static UINT16 numAllocedPlaneVerts = 0;
INT32 shader = SHADER_DEFAULT;
// no convex poly were generated for this subsector // no convex poly were generated for this subsector
if (!xsub->planepoly) if (!xsub->planepoly)
return; return;
pv = xsub->planepoly->pts;
nrPlaneVerts = xsub->planepoly->numpts;
if (nrPlaneVerts < 3) // not even a triangle?
return;
// Get the slope pointer to simplify future code // Get the slope pointer to simplify future code
if (FOFsector) if (FOFsector)
{ {
@ -406,12 +415,6 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
height = FIXED_TO_FLOAT(fixedheight); height = FIXED_TO_FLOAT(fixedheight);
pv = xsub->planepoly->pts;
nrPlaneVerts = xsub->planepoly->numpts;
if (nrPlaneVerts < 3) //not even a triangle ?
return;
// Allocate plane-vertex buffer if we need to // Allocate plane-vertex buffer if we need to
if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts) if (!planeVerts || nrPlaneVerts > numAllocedPlaneVerts)
{ {
@ -426,31 +429,8 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
if (levelflat->type == LEVELFLAT_FLAT) if (levelflat->type == LEVELFLAT_FLAT)
{ {
size_t len = W_LumpLength(levelflat->u.flat.lumpnum); size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
switch (len) flatflag = R_GetFlatSize(len) - 1;
{ fflatwidth = fflatheight = (float)(flatflag + 1);
case 4194304: // 2048x2048 lump
fflatwidth = fflatheight = 2048.0f;
break;
case 1048576: // 1024x1024 lump
fflatwidth = fflatheight = 1024.0f;
break;
case 262144:// 512x512 lump
fflatwidth = fflatheight = 512.0f;
break;
case 65536: // 256x256 lump
fflatwidth = fflatheight = 256.0f;
break;
case 16384: // 128x128 lump
fflatwidth = fflatheight = 128.0f;
break;
case 1024: // 32x32 lump
fflatwidth = fflatheight = 32.0f;
break;
default: // 64x64 lump
fflatwidth = fflatheight = 64.0f;
break;
}
flatflag = ((INT32)fflatwidth)-1;
} }
else else
{ {
@ -550,7 +530,7 @@ static void HWR_RenderPlane(subsector_t *subsector, extrasubsector_t *xsub, bool
}\ }\
} }
for (i = 0, v3d = planeVerts; i < nrPlaneVerts; i++,v3d++,pv++) for (i = 0, v3d = planeVerts; i < (INT32)nrPlaneVerts; i++,v3d++,pv++)
SETUP3DVERT(v3d, pv->x, pv->y); SETUP3DVERT(v3d, pv->x, pv->y);
if (slope) if (slope)
@ -2671,13 +2651,13 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
float height = FIXED_TO_FLOAT(fixedheight); // constant y for all points on the convex flat polygon float height = FIXED_TO_FLOAT(fixedheight); // constant y for all points on the convex flat polygon
float flatxref, flatyref; float flatxref, flatyref;
float fflatwidth = 64.0f, fflatheight = 64.0f; float fflatwidth = 64.0f, fflatheight = 64.0f;
INT32 flatflag = 63; UINT16 flatflag = 63;
boolean texflat = false; boolean texflat = false;
float scrollx = 0.0f, scrolly = 0.0f; float scrollx = 0.0f, scrolly = 0.0f;
float tempxsow, tempytow, anglef = 0.0f;
angle_t angle = 0; angle_t angle = 0;
fixed_t tempxs, tempyt;
static FOutVector *planeVerts = NULL; static FOutVector *planeVerts = NULL;
static UINT16 numAllocedPlaneVerts = 0; static UINT16 numAllocedPlaneVerts = 0;
@ -2704,31 +2684,8 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
if (levelflat->type == LEVELFLAT_FLAT) if (levelflat->type == LEVELFLAT_FLAT)
{ {
size_t len = W_LumpLength(levelflat->u.flat.lumpnum); size_t len = W_LumpLength(levelflat->u.flat.lumpnum);
switch (len) flatflag = R_GetFlatSize(len) - 1;
{ fflatwidth = fflatheight = (float)(flatflag + 1);
case 4194304: // 2048x2048 lump
fflatwidth = fflatheight = 2048.0f;
break;
case 1048576: // 1024x1024 lump
fflatwidth = fflatheight = 1024.0f;
break;
case 262144:// 512x512 lump
fflatwidth = fflatheight = 512.0f;
break;
case 65536: // 256x256 lump
fflatwidth = fflatheight = 256.0f;
break;
case 16384: // 128x128 lump
fflatwidth = fflatheight = 128.0f;
break;
case 1024: // 32x32 lump
fflatwidth = fflatheight = 32.0f;
break;
default: // 64x64 lump
fflatwidth = fflatheight = 64.0f;
break;
}
flatflag = ((INT32)fflatwidth)-1;
} }
else else
{ {
@ -2791,20 +2748,13 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
if (angle) // Only needs to be done if there's an altered angle if (angle) // Only needs to be done if there's an altered angle
{ {
angle = (InvAngle(angle))>>ANGLETOFINESHIFT; tempxsow = flatxref;
tempytow = flatyref;
// This needs to be done so that it scrolls in a different direction after rotation like software anglef = ANG2RAD(InvAngle(angle));
/*tempxs = FLOAT_TO_FIXED(scrollx);
tempyt = FLOAT_TO_FIXED(scrolly);
scrollx = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
scrolly = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));*/
// This needs to be done so everything aligns after rotation flatxref = (tempxsow * cos(anglef)) - (tempytow * sin(anglef));
// It would be done so that rotation is done, THEN the translation, but I couldn't get it to rotate AND scroll like software does flatyref = (tempxsow * sin(anglef)) + (tempytow * cos(anglef));
tempxs = FLOAT_TO_FIXED(flatxref);
tempyt = FLOAT_TO_FIXED(flatyref);
flatxref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
flatyref = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle))));
} }
for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++) for (i = 0; i < (INT32)nrPlaneVerts; i++,v3d++)
@ -2825,10 +2775,11 @@ static void HWR_RenderPolyObjectPlane(polyobj_t *polysector, boolean isceiling,
// Need to rotate before translate // Need to rotate before translate
if (angle) // Only needs to be done if there's an altered angle if (angle) // Only needs to be done if there's an altered angle
{ {
tempxs = FLOAT_TO_FIXED(v3d->s); tempxsow = v3d->s;
tempyt = FLOAT_TO_FIXED(v3d->t); tempytow = v3d->t;
v3d->s = (FIXED_TO_FLOAT(FixedMul(tempxs, FINECOSINE(angle)) - FixedMul(tempyt, FINESINE(angle))));
v3d->t = (FIXED_TO_FLOAT(FixedMul(tempxs, FINESINE(angle)) + FixedMul(tempyt, FINECOSINE(angle)))); v3d->s = (tempxsow * cos(anglef)) - (tempytow * sin(anglef));
v3d->t = (tempxsow * sin(anglef)) + (tempytow * cos(anglef));
} }
v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x); v3d->x = FIXED_TO_FLOAT(polysector->vertices[i]->x);

View file

@ -106,7 +106,7 @@ fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
INT32 ds_waterofs, ds_bgofs; INT32 ds_waterofs, ds_bgofs;
UINT16 ds_flatwidth, ds_flatheight; UINT16 ds_flatwidth, ds_flatheight;
boolean ds_powersoftwo; boolean ds_powersoftwo, ds_solidcolor;
UINT8 *ds_source; // points to the start of a flat UINT8 *ds_source; // points to the start of a flat
UINT8 *ds_transmap; // one of the translucency tables UINT8 *ds_transmap; // one of the translucency tables

View file

@ -61,7 +61,7 @@ extern fixed_t ds_xfrac, ds_yfrac, ds_xstep, ds_ystep;
extern INT32 ds_waterofs, ds_bgofs; extern INT32 ds_waterofs, ds_bgofs;
extern UINT16 ds_flatwidth, ds_flatheight; extern UINT16 ds_flatwidth, ds_flatheight;
extern boolean ds_powersoftwo; extern boolean ds_powersoftwo, ds_solidcolor;
extern UINT8 *ds_source; extern UINT8 *ds_source;
extern UINT8 *ds_transmap; extern UINT8 *ds_transmap;
@ -194,8 +194,8 @@ void R_DrawTranslucentFloorSprite_8(void);
void R_DrawTiltedFloorSprite_8(void); void R_DrawTiltedFloorSprite_8(void);
void R_DrawTiltedTranslucentFloorSprite_8(void); void R_DrawTiltedTranslucentFloorSprite_8(void);
void R_DrawTranslucentWaterSpan_8(void); void R_DrawWaterSpan_8(void);
void R_DrawTiltedTranslucentWaterSpan_8(void); void R_DrawTiltedWaterSpan_8(void);
void R_DrawFogSpan_8(void); void R_DrawFogSpan_8(void);
void R_DrawTiltedFogSpan_8(void); void R_DrawTiltedFogSpan_8(void);
@ -215,8 +215,15 @@ void R_DrawTranslucentFloorSprite_NPO2_8(void);
void R_DrawTiltedFloorSprite_NPO2_8(void); void R_DrawTiltedFloorSprite_NPO2_8(void);
void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void); void R_DrawTiltedTranslucentFloorSprite_NPO2_8(void);
void R_DrawTranslucentWaterSpan_NPO2_8(void); void R_DrawWaterSpan_NPO2_8(void);
void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void); void R_DrawTiltedWaterSpan_NPO2_8(void);
void R_DrawSolidColorSpan_8(void);
void R_DrawTransSolidColorSpan_8(void);
void R_DrawTiltedSolidColorSpan_8(void);
void R_DrawTiltedTransSolidColorSpan_8(void);
void R_DrawWaterSolidColorSpan_8(void);
void R_DrawTiltedWaterSolidColorSpan_8(void);
#ifdef USEASM #ifdef USEASM
void ASMCALL R_DrawColumn_8_ASM(void); void ASMCALL R_DrawColumn_8_ASM(void);

View file

@ -901,10 +901,10 @@ void R_DrawTiltedTranslucentSpan_8(void)
#endif #endif
} }
/** \brief The R_DrawTiltedTranslucentWaterSpan_8 function /** \brief The R_DrawTiltedWaterSpan_8 function
Like DrawTiltedTranslucentSpan, but for water Like DrawTiltedTranslucentSpan, but for water
*/ */
void R_DrawTiltedTranslucentWaterSpan_8(void) void R_DrawTiltedWaterSpan_8(void)
{ {
// x1, x2 = ds_x1, ds_x2 // x1, x2 = ds_x1, ds_x2
int width = ds_x2 - ds_x1; int width = ds_x2 - ds_x1;
@ -1893,7 +1893,7 @@ void R_DrawTranslucentSpan_8 (void)
} }
} }
void R_DrawTranslucentWaterSpan_8(void) void R_DrawWaterSpan_8(void)
{ {
UINT32 xposition; UINT32 xposition;
UINT32 yposition; UINT32 yposition;
@ -2025,6 +2025,123 @@ void R_DrawTiltedFogSpan_8(void)
} while (--width >= 0); } while (--width >= 0);
} }
/** \brief The R_DrawSolidColorSpan_8 function
Draws a solid color span.
*/
void R_DrawSolidColorSpan_8(void)
{
size_t count = (ds_x2 - ds_x1 + 1);
UINT8 source = ds_colormap[ds_source[0]];
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
memset(dest, source, count);
}
/** \brief The R_DrawTransSolidColorSpan_8 function
Draws a translucent solid color span.
*/
void R_DrawTransSolidColorSpan_8(void)
{
size_t count = (ds_x2 - ds_x1 + 1);
UINT8 source = ds_colormap[ds_source[0]];
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
while (count-- && dest <= deststop)
{
*dest = *(ds_transmap + (source << 8) + *dest);
dest++;
}
}
/** \brief The R_DrawTiltedSolidColorSpan_8 function
Draws a tilted solid color span.
*/
void R_DrawTiltedSolidColorSpan_8(void)
{
int width = ds_x2 - ds_x1;
UINT8 source = ds_source[0];
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
CALC_SLOPE_LIGHT
do
{
UINT8 *colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest++ = colormap[source];
} while (--width >= 0);
}
/** \brief The R_DrawTiltedTransSolidColorSpan_8 function
Draws a tilted and translucent solid color span.
*/
void R_DrawTiltedTransSolidColorSpan_8(void)
{
int width = ds_x2 - ds_x1;
UINT8 source = ds_source[0];
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
CALC_SLOPE_LIGHT
do
{
UINT8 *colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest = *(ds_transmap + (colormap[source] << 8) + *dest);
dest++;
} while (--width >= 0);
}
/** \brief The R_DrawWaterSolidColorSpan_8 function
Draws a water solid color span.
*/
void R_DrawWaterSolidColorSpan_8(void)
{
UINT8 source = ds_source[0];
UINT8 *colormap = ds_colormap;
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
size_t count = (ds_x2 - ds_x1 + 1);
const UINT8 *deststop = screens[0] + vid.rowbytes * vid.height;
while (count-- && dest <= deststop)
{
*dest = colormap[*(ds_transmap + (source << 8) + *dsrc++)];
dest++;
}
}
/** \brief The R_DrawTiltedWaterSolidColorSpan_8 function
Draws a tilted water solid color span.
*/
void R_DrawTiltedWaterSolidColorSpan_8(void)
{
int width = ds_x2 - ds_x1;
UINT8 source = ds_source[0];
UINT8 *dest = ylookup[ds_y] + columnofs[ds_x1];
UINT8 *dsrc = screens[1] + (ds_y+ds_bgofs)*vid.width + ds_x1;
double iz = ds_szp->z + ds_szp->y*(centery-ds_y) + ds_szp->x*(ds_x1-centerx);
CALC_SLOPE_LIGHT
do
{
UINT8 *colormap = planezlight[tiltlighting[ds_x1++]] + (ds_colormap - colormaps);
*dest++ = *(ds_transmap + (colormap[source] << 8) + *dsrc++);
} while (--width >= 0);
}
/** \brief The R_DrawFogColumn_8 function /** \brief The R_DrawFogColumn_8 function
Fog wall. Fog wall.
*/ */

View file

@ -1319,7 +1319,7 @@ void R_DrawTranslucentSpan_NPO2_8 (void)
} }
} }
void R_DrawTranslucentWaterSpan_NPO2_8(void) void R_DrawWaterSpan_NPO2_8(void)
{ {
fixed_t xposition; fixed_t xposition;
fixed_t yposition; fixed_t yposition;
@ -1382,10 +1382,10 @@ void R_DrawTranslucentWaterSpan_NPO2_8(void)
} }
} }
/** \brief The R_DrawTiltedTranslucentWaterSpan_NPO2_8 function /** \brief The R_DrawTiltedWaterSpan_NPO2_8 function
Like DrawTiltedTranslucentSpan_NPO2, but for water Like DrawTiltedTranslucentSpan_NPO2, but for water
*/ */
void R_DrawTiltedTranslucentWaterSpan_NPO2_8(void) void R_DrawTiltedWaterSpan_NPO2_8(void)
{ {
// x1, x2 = ds_x1, ds_x2 // x1, x2 = ds_x1, ds_x2
int width = ds_x2 - ds_x1; int width = ds_x2 - ds_x1;

View file

@ -36,9 +36,6 @@
// opening // opening
// //
// Quincunx antialiasing of flats!
//#define QUINCUNX
//SoM: 3/23/2000: Use Boom visplane hashing. //SoM: 3/23/2000: Use Boom visplane hashing.
visplane_t *visplanes[MAXVISPLANES]; visplane_t *visplanes[MAXVISPLANES];
@ -789,6 +786,9 @@ d->z = (v1.x * v2.y) - (v1.y * v2.x)
ds_svp->z *= focallengthf; ds_svp->z *= focallengthf;
ds_szp->z *= focallengthf; ds_szp->z *= focallengthf;
if (ds_solidcolor)
return;
// Premultiply the texture vectors with the scale factors // Premultiply the texture vectors with the scale factors
if (ds_powersoftwo) if (ds_powersoftwo)
sfmult *= (1 << nflatshiftup); sfmult *= (1 << nflatshiftup);
@ -858,7 +858,7 @@ void R_DrawSinglePlane(visplane_t *pl)
ffloor_t *rover; ffloor_t *rover;
boolean fog = false; boolean fog = false;
INT32 spanfunctype = BASEDRAWFUNC; INT32 spanfunctype = BASEDRAWFUNC;
void (*mapfunc)(INT32, INT32, INT32) = R_MapPlane; void (*mapfunc)(INT32, INT32, INT32);
if (!(pl->minx <= pl->maxx)) if (!(pl->minx <= pl->maxx))
return; return;
@ -871,7 +871,6 @@ void R_DrawSinglePlane(visplane_t *pl)
} }
planeripple.active = false; planeripple.active = false;
spanfunc = spanfuncs[BASEDRAWFUNC];
if (pl->polyobj) if (pl->polyobj)
{ {
@ -941,7 +940,7 @@ void R_DrawSinglePlane(visplane_t *pl)
} }
else light = (pl->lightlevel >> LIGHTSEGSHIFT); else light = (pl->lightlevel >> LIGHTSEGSHIFT);
if (pl->ffloor->fofflags & FOF_RIPPLE) if (pl->ffloor->fofflags & FOF_RIPPLE && !fog)
{ {
planeripple.active = true; planeripple.active = true;
@ -963,17 +962,21 @@ void R_DrawSinglePlane(visplane_t *pl)
vid.width, bottom-top, vid.width, bottom-top,
vid.width, vid.width); vid.width, vid.width);
} }
else if (fog)
planeripple.active = false;
} }
} }
else else
light = (pl->lightlevel >> LIGHTSEGSHIFT); light = (pl->lightlevel >> LIGHTSEGSHIFT);
} }
currentplane = pl; ds_powersoftwo = ds_solidcolor = false;
if (!fog) if (fog)
{
// Since all fog planes do is apply a colormap, it's not required
// to know any information about their textures.
mapfunc = R_MapFogPlane;
}
else
{ {
levelflat_t *levelflat = &levelflats[pl->picnum]; levelflat_t *levelflat = &levelflats[pl->picnum];
@ -984,28 +987,50 @@ void R_DrawSinglePlane(visplane_t *pl)
return; return;
case LEVELFLAT_FLAT: case LEVELFLAT_FLAT:
ds_source = (UINT8 *)R_GetFlat(levelflat->u.flat.lumpnum); ds_source = (UINT8 *)R_GetFlat(levelflat->u.flat.lumpnum);
R_CheckFlatLength(W_LumpLength(levelflat->u.flat.lumpnum)); R_SetFlatVars(W_LumpLength(levelflat->u.flat.lumpnum));
// Raw flats always have dimensions that are powers-of-two numbers. if (R_CheckSolidColorFlat())
ds_powersoftwo = true; ds_solidcolor = true;
else
ds_powersoftwo = true;
break; break;
default: default:
ds_source = (UINT8 *)R_GetLevelFlat(levelflat); ds_source = (UINT8 *)R_GetLevelFlat(levelflat);
if (!ds_source) if (!ds_source)
return; return;
// Check if this texture or patch has power-of-two dimensions. else if (R_CheckSolidColorFlat())
if (R_CheckPowersOfTwo()) ds_solidcolor = true;
R_CheckFlatLength(ds_flatwidth * ds_flatheight); else if (R_CheckPowersOfTwo())
{
R_SetFlatVars(ds_flatwidth * ds_flatheight);
ds_powersoftwo = true;
}
} }
if (!pl->slope // Don't mess with angle on slopes! We'll handle this ourselves later // Don't mess with angle on slopes! We'll handle this ourselves later
&& viewangle != pl->viewangle+pl->plangle) if (!pl->slope && viewangle != pl->viewangle+pl->plangle)
{ {
memset(cachedheight, 0, sizeof (cachedheight)); memset(cachedheight, 0, sizeof (cachedheight));
viewangle = pl->viewangle+pl->plangle; viewangle = pl->viewangle+pl->plangle;
} }
mapfunc = R_MapPlane;
if (ds_solidcolor)
{
switch (spanfunctype)
{
case SPANDRAWFUNC_WATER:
spanfunctype = SPANDRAWFUNC_WATERSOLID;
break;
case SPANDRAWFUNC_TRANS:
spanfunctype = SPANDRAWFUNC_TRANSSOLID;
break;
default:
spanfunctype = SPANDRAWFUNC_SOLID;
break;
}
}
} }
else
mapfunc = R_MapFogPlane;
xoffs = pl->xoffs; xoffs = pl->xoffs;
yoffs = pl->yoffs; yoffs = pl->yoffs;
@ -1024,7 +1049,7 @@ void R_DrawSinglePlane(visplane_t *pl)
{ {
mapfunc = R_MapTiltedPlane; mapfunc = R_MapTiltedPlane;
if (!pl->plangle) if (!pl->plangle && !ds_solidcolor)
{ {
if (ds_powersoftwo) if (ds_powersoftwo)
R_AdjustSlopeCoordinates(&pl->slope->o); R_AdjustSlopeCoordinates(&pl->slope->o);
@ -1060,6 +1085,15 @@ void R_DrawSinglePlane(visplane_t *pl)
case SPANDRAWFUNC_SPLAT: case SPANDRAWFUNC_SPLAT:
spanfunctype = SPANDRAWFUNC_TILTEDSPLAT; spanfunctype = SPANDRAWFUNC_TILTEDSPLAT;
break; break;
case SPANDRAWFUNC_SOLID:
spanfunctype = SPANDRAWFUNC_TILTEDSOLID;
break;
case SPANDRAWFUNC_TRANSSOLID:
spanfunctype = SPANDRAWFUNC_TILTEDTRANSSOLID;
break;
case SPANDRAWFUNC_WATERSOLID:
spanfunctype = SPANDRAWFUNC_TILTEDWATERSOLID;
break;
case SPANDRAWFUNC_FOG: case SPANDRAWFUNC_FOG:
spanfunctype = SPANDRAWFUNC_TILTEDFOG; spanfunctype = SPANDRAWFUNC_TILTEDFOG;
break; break;
@ -1076,7 +1110,7 @@ void R_DrawSinglePlane(visplane_t *pl)
planezlight = zlight[light]; planezlight = zlight[light];
} }
// Use the correct span drawer depending on the powers-of-twoness // Set the span drawer
if (!ds_powersoftwo) if (!ds_powersoftwo)
{ {
if (spanfuncs_npo2[spanfunctype]) if (spanfuncs_npo2[spanfunctype])
@ -1093,81 +1127,11 @@ void R_DrawSinglePlane(visplane_t *pl)
pl->bottom[pl->maxx+1] = 0x0000; pl->bottom[pl->maxx+1] = 0x0000;
pl->bottom[pl->minx-1] = 0x0000; pl->bottom[pl->minx-1] = 0x0000;
currentplane = pl;
stop = pl->maxx + 1; stop = pl->maxx + 1;
for (x = pl->minx; x <= stop; x++) for (x = pl->minx; x <= stop; x++)
R_MakeSpans(mapfunc, x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]); R_MakeSpans(mapfunc, x, pl->top[x-1], pl->bottom[x-1], pl->top[x], pl->bottom[x]);
/*
QUINCUNX anti-aliasing technique (sort of)
Normally, Quincunx antialiasing staggers pixels
in a 5-die pattern like so:
o o
o
o o
To simulate this, we offset the plane by
FRACUNIT/4 in each direction, and draw
at 50% translucency. The result is
a 'smoothing' of the texture while
using the palette colors.
*/
#ifdef QUINCUNX
if (spanfunc == spanfuncs[BASEDRAWFUNC])
{
INT32 i;
ds_transmap = R_GetTranslucencyTable(tr_trans50);
spanfunc = spanfuncs[SPANDRAWFUNC_TRANS];
for (i=0; i<4; i++)
{
xoffs = pl->xoffs;
yoffs = pl->yoffs;
switch(i)
{
case 0:
xoffs -= FRACUNIT/4;
yoffs -= FRACUNIT/4;
break;
case 1:
xoffs -= FRACUNIT/4;
yoffs += FRACUNIT/4;
break;
case 2:
xoffs += FRACUNIT/4;
yoffs -= FRACUNIT/4;
break;
case 3:
xoffs += FRACUNIT/4;
yoffs += FRACUNIT/4;
break;
}
planeheight = abs(pl->height - pl->viewz);
if (light >= LIGHTLEVELS)
light = LIGHTLEVELS-1;
if (light < 0)
light = 0;
planezlight = zlight[light];
// set the maximum value for unsigned
pl->top[pl->maxx+1] = 0xffff;
pl->top[pl->minx-1] = 0xffff;
pl->bottom[pl->maxx+1] = 0x0000;
pl->bottom[pl->minx-1] = 0x0000;
stop = pl->maxx + 1;
for (x = pl->minx; x <= stop; x++)
R_MakeSpans(mapfunc, x, pl->top[x-1], pl->bottom[x-1],
pl->top[x], pl->bottom[x]);
}
}
#endif
} }
void R_PlaneBounds(visplane_t *plane) void R_PlaneBounds(visplane_t *plane)

View file

@ -84,9 +84,6 @@ visplane_t *R_CheckPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop); void R_ExpandPlane(visplane_t *pl, INT32 start, INT32 stop);
void R_PlaneBounds(visplane_t *plane); void R_PlaneBounds(visplane_t *plane);
void R_CheckFlatLength(size_t size);
boolean R_CheckPowersOfTwo(void);
// Draws a single visplane. // Draws a single visplane.
void R_DrawSinglePlane(visplane_t *pl); void R_DrawSinglePlane(visplane_t *pl);

View file

@ -390,9 +390,13 @@ static void R_RasterizeFloorSplat(floorsplat_t *pSplat, vector2_t *verts, visspr
ds_source = (UINT8 *)pSplat->pic; ds_source = (UINT8 *)pSplat->pic;
ds_flatwidth = pSplat->width; ds_flatwidth = pSplat->width;
ds_flatheight = pSplat->height; ds_flatheight = pSplat->height;
ds_powersoftwo = false;
if (R_CheckPowersOfTwo()) if (R_CheckPowersOfTwo())
R_CheckFlatLength(ds_flatwidth * ds_flatheight); {
R_SetFlatVars(ds_flatwidth * ds_flatheight);
ds_powersoftwo = true;
}
if (pSplat->slope) if (pSplat->slope)
{ {

View file

@ -620,88 +620,99 @@ void *R_GetLevelFlat(levelflat_t *levelflat)
} }
// //
// R_CheckPowersOfTwo // Checks if the current flat's dimensions are powers of two
//
// Sets ds_powersoftwo true if the flat's dimensions are powers of two, and returns that.
// //
boolean R_CheckPowersOfTwo(void) boolean R_CheckPowersOfTwo(void)
{ {
boolean wpow2 = (!(ds_flatwidth & (ds_flatwidth - 1))); boolean wpow2 = !(ds_flatwidth & (ds_flatwidth - 1));
boolean hpow2 = (!(ds_flatheight & (ds_flatheight - 1))); boolean hpow2 = !(ds_flatheight & (ds_flatheight - 1));
// Initially, the flat isn't powers-of-two-sized. if (ds_flatwidth > 2048 || ds_flatheight > 2048)
ds_powersoftwo = false; return false;
// But if the width and height are powers of two, return ds_flatwidth == ds_flatheight && wpow2 && hpow2;
// 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 // Checks if the current flat's dimensions are 1x1
// //
// Determine the flat's dimensions from its lump length. boolean R_CheckSolidColorFlat(void)
{
return ds_flatwidth == 1 && ds_flatheight == 1;
}
// //
void R_CheckFlatLength(size_t size) // Returns the flat size corresponding to the length of a lump
//
UINT16 R_GetFlatSize(size_t length)
{
switch (length)
{
case 4194304: // 2048x2048 lump
return 2048;
case 1048576: // 1024x1024 lump
return 1024;
case 262144:// 512x512 lump
return 512;
case 65536: // 256x256 lump
return 256;
case 16384: // 128x128 lump
return 128;
case 1024: // 32x32 lump
return 32;
case 256: // 16x16 lump
return 16;
case 64: // 8x8 lump
return 8;
case 16: // 4x4 lump
return 4;
case 4: // 2x2 lump
return 2;
case 1: // 1x1 lump
return 1;
default: // 64x64 lump
return 64;
}
}
//
// Determines a flat's width bits from its size
//
UINT8 R_GetFlatBits(INT32 size)
{ {
switch (size) switch (size)
{ {
case 4194304: // 2048x2048 lump case 2048: return 11;
nflatmask = 0x3FF800; case 1024: return 10;
nflatxshift = 21; case 512: return 9;
nflatyshift = 10; case 256: return 8;
nflatshiftup = 5; case 128: return 7;
ds_flatwidth = ds_flatheight = 2048; case 32: return 5;
break; case 16: return 4;
case 1048576: // 1024x1024 lump case 8: return 3;
nflatmask = 0xFFC00; case 4: return 2;
nflatxshift = 22; case 2: return 1;
nflatyshift = 12; case 1: return 0;
nflatshiftup = 6; default: return 6; // 64x64
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;
} }
} }
void R_SetFlatVars(size_t length)
{
UINT16 size = R_GetFlatSize(length);
UINT8 bits = R_GetFlatBits(size);
ds_flatwidth = ds_flatheight = size;
if (bits == 0)
return;
nflatshiftup = 16 - bits;
nflatxshift = 16 + nflatshiftup;
nflatyshift = nflatxshift - bits;
nflatmask = (size - 1) * size;
}
// //
// Empty the texture cache (used for load wad at runtime) // Empty the texture cache (used for load wad at runtime)
// //
@ -748,7 +759,7 @@ Rloadflats (INT32 i, INT32 w)
UINT16 wadnum = (UINT16)w; UINT16 wadnum = (UINT16)w;
lumpnum_t lumpnum = texstart + j; lumpnum_t lumpnum = texstart + j;
size_t lumplength; size_t lumplength;
size_t flatsize = 0; size_t flatsize;
if (W_FileHasFolders(wadfiles[w])) if (W_FileHasFolders(wadfiles[w]))
{ {
@ -758,31 +769,7 @@ Rloadflats (INT32 i, INT32 w)
W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0); W_ReadLumpHeaderPwad(wadnum, lumpnum, header, sizeof header, 0);
lumplength = W_LumpLengthPwad(wadnum, lumpnum); lumplength = W_LumpLengthPwad(wadnum, lumpnum);
flatsize = R_GetFlatSize(lumplength);
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); //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); texture = textures[i] = Z_Calloc(sizeof(texture_t) + sizeof(texpatch_t), PU_STATIC, NULL);

View file

@ -93,7 +93,11 @@ UINT8 *R_GetColumn(fixed_t tex, INT32 col);
void *R_GetFlat(lumpnum_t flatnum); void *R_GetFlat(lumpnum_t flatnum);
boolean R_CheckPowersOfTwo(void); boolean R_CheckPowersOfTwo(void);
void R_CheckFlatLength(size_t size); boolean R_CheckSolidColorFlat(void);
UINT16 R_GetFlatSize(size_t length);
UINT8 R_GetFlatBits(INT32 size);
void R_SetFlatVars(size_t length);
// Returns the texture number for the texture name. // Returns the texture number for the texture name.
INT32 R_TextureNumForName(const char *name); INT32 R_TextureNumForName(const char *name);

View file

@ -141,8 +141,14 @@ void SCR_SetDrawFuncs(void)
spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8; spanfuncs[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_8;
spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8; spanfuncs[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_8;
spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8; spanfuncs[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_8;
spanfuncs[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_8; spanfuncs[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_8;
spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_8; spanfuncs[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_8;
spanfuncs[SPANDRAWFUNC_SOLID] = R_DrawSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_TRANSSOLID] = R_DrawTransSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_TILTEDSOLID] = R_DrawTiltedSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_TILTEDTRANSSOLID] = R_DrawTiltedTransSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_WATERSOLID] = R_DrawWaterSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_TILTEDWATERSOLID] = R_DrawTiltedWaterSolidColorSpan_8;
spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8; spanfuncs[SPANDRAWFUNC_FOG] = R_DrawFogSpan_8;
spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8; spanfuncs[SPANDRAWFUNC_TILTEDFOG] = R_DrawTiltedFogSpan_8;
@ -158,8 +164,8 @@ void SCR_SetDrawFuncs(void)
spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TRANSSPRITE] = R_DrawTranslucentFloorSprite_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDSPRITE] = R_DrawTiltedFloorSprite_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDTRANSSPRITE] = R_DrawTiltedTranslucentFloorSprite_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawTranslucentWaterSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_WATER] = R_DrawWaterSpan_NPO2_8;
spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedTranslucentWaterSpan_NPO2_8; spanfuncs_npo2[SPANDRAWFUNC_TILTEDWATER] = R_DrawTiltedWaterSpan_NPO2_8;
#ifdef RUSEASM #ifdef RUSEASM
if (R_ASM) if (R_ASM)

View file

@ -155,6 +155,13 @@ enum
SPANDRAWFUNC_WATER, SPANDRAWFUNC_WATER,
SPANDRAWFUNC_TILTEDWATER, SPANDRAWFUNC_TILTEDWATER,
SPANDRAWFUNC_SOLID,
SPANDRAWFUNC_TRANSSOLID,
SPANDRAWFUNC_TILTEDSOLID,
SPANDRAWFUNC_TILTEDTRANSSOLID,
SPANDRAWFUNC_WATERSOLID,
SPANDRAWFUNC_TILTEDWATERSOLID,
SPANDRAWFUNC_FOG, SPANDRAWFUNC_FOG,
SPANDRAWFUNC_TILTEDFOG, SPANDRAWFUNC_TILTEDFOG,

View file

@ -1748,7 +1748,7 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum)
fixed_t dx, dy, xfrac, yfrac; fixed_t dx, dy, xfrac, yfrac;
const UINT8 *src, *deststop; const UINT8 *src, *deststop;
UINT8 *flat, *dest; UINT8 *flat, *dest;
size_t size, lflatsize, flatshift; size_t lflatsize, flatshift;
#ifdef HWRENDER #ifdef HWRENDER
if (rendermode == render_opengl) if (rendermode == render_opengl)
@ -1758,39 +1758,8 @@ void V_DrawFlatFill(INT32 x, INT32 y, INT32 w, INT32 h, lumpnum_t flatnum)
} }
#endif #endif
size = W_LumpLength(flatnum); lflatsize = R_GetFlatSize(W_LumpLength(flatnum));
flatshift = R_GetFlatBits(lflatsize);
switch (size)
{
case 4194304: // 2048x2048 lump
lflatsize = 2048;
flatshift = 10;
break;
case 1048576: // 1024x1024 lump
lflatsize = 1024;
flatshift = 9;
break;
case 262144:// 512x512 lump
lflatsize = 512;
flatshift = 8;
break;
case 65536: // 256x256 lump
lflatsize = 256;
flatshift = 7;
break;
case 16384: // 128x128 lump
lflatsize = 128;
flatshift = 7;
break;
case 1024: // 32x32 lump
lflatsize = 32;
flatshift = 5;
break;
default: // 64x64 lump
lflatsize = 64;
flatshift = 6;
break;
}
flat = W_CacheLumpNum(flatnum, PU_CACHE); flat = W_CacheLumpNum(flatnum, PU_CACHE);