Skip to content
Snippets Groups Projects
Commit b808b3ef authored by Lactozilla's avatar Lactozilla :speech_balloon:
Browse files

Move calculation of rotated patch dimensions into its own function

Simplify rotation code when the pivot isn't in the center
parent 6145442a
No related branches found
No related tags found
1 merge request!1257New sprite features
......@@ -47,11 +47,11 @@ patch_t *Patch_Create(softwarepatch_t *source, size_t srcsize, void *dest)
}
if (!srcsize)
I_Error("R_CreatePatch: no source size!");
I_Error("Patch_Create: no source size!");
colsize = (INT32)(srcsize) - (INT32)offs;
if (colsize <= 0)
I_Error("R_CreatePatch: no column data!");
I_Error("Patch_Create: no column data!");
patch->columns = Z_Calloc(colsize, PU_PATCH_DATA, NULL);
M_Memcpy(patch->columns, ((UINT8 *)source + LONG(source->columnofs[0])), colsize);
......
......@@ -82,6 +82,9 @@ patch_t *Patch_GetRotatedSprite(spriteframe_t *sprite, size_t frame, size_t spri
}
RotatedPatch_DoRotation(rotsprite, patch, rotationangle, xpivot, ypivot, flip);
//BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
((patch_t *)rotsprite->patches[idx])->topoffset += FEETADJUST>>FRACBITS;
}
return rotsprite->patches[idx];
......@@ -102,10 +105,32 @@ rotsprite_t *RotatedPatch_Create(INT32 numangles)
return rotsprite;
}
static void RotatedPatch_CalculateDimensions(
INT32 width, INT32 height,
fixed_t ca, fixed_t sa,
INT32 *newwidth, INT32 *newheight)
{
fixed_t fixedwidth = (width * FRACUNIT);
fixed_t fixedheight = (height * FRACUNIT);
fixed_t w1 = abs(FixedMul(fixedwidth, ca) - FixedMul(fixedheight, sa));
fixed_t w2 = abs(FixedMul(-fixedwidth, ca) - FixedMul(fixedheight, sa));
fixed_t h1 = abs(FixedMul(fixedwidth, sa) + FixedMul(fixedheight, ca));
fixed_t h2 = abs(FixedMul(-fixedwidth, sa) + FixedMul(fixedheight, ca));
w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2)));
w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2)));
h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2)));
h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2)));
*newwidth = max(width, max(w1, w2));
*newheight = max(height, max(h1, h2));
}
void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle, INT32 xpivot, INT32 ypivot, boolean flip)
{
patch_t *rotated;
UINT16 *rawdst;
UINT16 *rawdst, *rawconv;
size_t size;
pictureflags_t bflip = (flip) ? PICFLAGS_XFLIP : 0;
......@@ -114,18 +139,20 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
INT32 leftoffset = patch->leftoffset;
INT32 newwidth, newheight;
INT32 dx, dy;
fixed_t ca = rollcosang[angle];
fixed_t sa = rollsinang[angle];
fixed_t xcenter, ycenter;
INT32 idx = angle;
INT32 x, y;
INT32 sx, sy;
INT32 dx, dy;
INT32 ox, oy;
INT32 minx, miny, maxx, maxy;
// Don't cache angle = 0
if (angle < 1 || angle >= ROTANGLES)
return;
#define ROTSPRITE_XCENTER (newwidth / 2)
#define ROTSPRITE_YCENTER (newheight / 2)
if (flip)
{
idx += rotsprite->angles;
......@@ -137,64 +164,22 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
return;
// Find the dimensions of the rotated patch.
{
INT32 w1 = abs(FixedMul(width << FRACBITS, ca) - FixedMul(height << FRACBITS, sa));
INT32 w2 = abs(FixedMul(-(width << FRACBITS), ca) - FixedMul(height << FRACBITS, sa));
INT32 h1 = abs(FixedMul(width << FRACBITS, sa) + FixedMul(height << FRACBITS, ca));
INT32 h2 = abs(FixedMul(-(width << FRACBITS), sa) + FixedMul(height << FRACBITS, ca));
w1 = FixedInt(FixedCeil(w1 + (FRACUNIT/2)));
w2 = FixedInt(FixedCeil(w2 + (FRACUNIT/2)));
h1 = FixedInt(FixedCeil(h1 + (FRACUNIT/2)));
h2 = FixedInt(FixedCeil(h2 + (FRACUNIT/2)));
newwidth = max(width, max(w1, w2));
newheight = max(height, max(h1, h2));
}
RotatedPatch_CalculateDimensions(width, height, ca, sa, &newwidth, &newheight);
xcenter = (xpivot * FRACUNIT);
ycenter = (ypivot * FRACUNIT);
// check boundaries
if (xpivot != width / 2 || ypivot != height / 2)
{
fixed_t top[2][2];
fixed_t bottom[2][2];
top[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (xpivot << FRACBITS);
top[0][1] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (ypivot << FRACBITS);
top[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, sa) + (xpivot << FRACBITS);
top[1][1] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((-ROTSPRITE_YCENTER) << FRACBITS, ca) + (ypivot << FRACBITS);
bottom[0][0] = FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (xpivot << FRACBITS);
bottom[0][1] = -FixedMul((-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (ypivot << FRACBITS);
bottom[1][0] = FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, ca) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, sa) + (xpivot << FRACBITS);
bottom[1][1] = -FixedMul((newwidth-ROTSPRITE_XCENTER) << FRACBITS, sa) + FixedMul((newheight-ROTSPRITE_YCENTER) << FRACBITS, ca) + (ypivot << FRACBITS);
top[0][0] >>= FRACBITS;
top[0][1] >>= FRACBITS;
top[1][0] >>= FRACBITS;
top[1][1] >>= FRACBITS;
bottom[0][0] >>= FRACBITS;
bottom[0][1] >>= FRACBITS;
bottom[1][0] >>= FRACBITS;
bottom[1][1] >>= FRACBITS;
#define BOUNDARYWCHECK(b) (b[0] < 0 || b[0] >= width)
#define BOUNDARYHCHECK(b) (b[1] < 0 || b[1] >= height)
#define BOUNDARYADJUST(x) x *= 2
// top left/right
if (BOUNDARYWCHECK(top[0]) || BOUNDARYWCHECK(top[1]))
BOUNDARYADJUST(newwidth);
// bottom left/right
else if (BOUNDARYWCHECK(bottom[0]) || BOUNDARYWCHECK(bottom[1]))
BOUNDARYADJUST(newwidth);
// top left/right
if (BOUNDARYHCHECK(top[0]) || BOUNDARYHCHECK(top[1]))
BOUNDARYADJUST(newheight);
// bottom left/right
else if (BOUNDARYHCHECK(bottom[0]) || BOUNDARYHCHECK(bottom[1]))
BOUNDARYADJUST(newheight);
#undef BOUNDARYWCHECK
#undef BOUNDARYHCHECK
#undef BOUNDARYADJUST
newwidth *= 2;
newheight *= 2;
}
minx = newwidth;
miny = newheight;
maxx = 0;
maxy = 0;
// Draw the rotated sprite to a temporary buffer.
size = (newwidth * newheight);
if (!size)
......@@ -205,37 +190,76 @@ void RotatedPatch_DoRotation(rotsprite_t *rotsprite, patch_t *patch, INT32 angle
{
for (dx = 0; dx < newwidth; dx++)
{
INT32 x = (dx-ROTSPRITE_XCENTER) << FRACBITS;
INT32 y = (dy-ROTSPRITE_YCENTER) << FRACBITS;
INT32 sx = FixedMul(x, ca) + FixedMul(y, sa) + (xpivot << FRACBITS);
INT32 sy = -FixedMul(x, sa) + FixedMul(y, ca) + (ypivot << FRACBITS);
x = (dx - (newwidth / 2)) * FRACUNIT;
y = (dy - (newheight / 2)) * FRACUNIT;
sx = FixedMul(x, ca) + FixedMul(y, sa) + xcenter;
sy = -FixedMul(x, sa) + FixedMul(y, ca) + ycenter;
sx >>= FRACBITS;
sy >>= FRACBITS;
if (sx >= 0 && sy >= 0 && sx < width && sy < height)
{
void *input = Picture_GetPatchPixel(patch, PICFMT_PATCH, sx, sy, bflip);
if (input != NULL)
rawdst[(dy*newwidth)+dx] = (0xFF00 | (*(UINT8 *)input));
{
rawdst[(dy * newwidth) + dx] = (0xFF00 | (*(UINT8 *)input));
if (dx < minx)
minx = dx;
if (dy < miny)
miny = dy;
if (dx > maxx)
maxx = dx;
if (dy > maxy)
maxy = dy;
}
}
}
}
// make patch
rotated = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawdst, PICFMT_PATCH, 0, &size, newwidth, newheight, 0, 0, 0);
ox = (newwidth / 2) + (leftoffset - xpivot);
oy = (newheight / 2) + (patch->topoffset - ypivot);
width = (maxx - minx);
height = (maxy - miny);
Z_ChangeTag(rotated, PU_PATCH_ROTATED);
Z_SetUser(rotated, (void **)(&rotsprite->patches[idx]));
if ((unsigned)(width * height) != size)
{
UINT16 *src, *dest;
size = (width * height);
rawconv = Z_Calloc(size * sizeof(UINT16), PU_STATIC, NULL);
src = &rawdst[(miny * newwidth) + minx];
dest = rawconv;
dy = height;
while (dy--)
{
M_Memcpy(dest, src, width * sizeof(UINT16));
dest += width;
src += newwidth;
}
ox -= minx;
oy -= miny;
rotated->leftoffset = (rotated->width / 2) + (leftoffset - xpivot);
rotated->topoffset = (rotated->height / 2) + (patch->topoffset - ypivot);
Z_Free(rawdst);
}
else
{
rawconv = rawdst;
width = newwidth;
height = newheight;
}
//BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
rotated->topoffset += FEETADJUST>>FRACBITS;
// make patch
rotated = (patch_t *)Picture_Convert(PICFMT_FLAT16, rawconv, PICFMT_PATCH, 0, NULL, width, height, 0, 0, 0);
// free rotated image data
Z_Free(rawdst);
Z_ChangeTag(rotated, PU_PATCH_ROTATED);
Z_SetUser(rotated, (void **)(&rotsprite->patches[idx]));
Z_Free(rawconv);
#undef ROTSPRITE_XCENTER
#undef ROTSPRITE_YCENTER
rotated->leftoffset = ox;
rotated->topoffset = oy;
}
#endif
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment