1
0
mirror of synced 2024-11-27 23:50:47 +01:00

Fix translation matrix application on embedded clips, fixes placement of lots of complex animations.

This commit is contained in:
Jennifer Taylor 2021-05-21 21:32:02 +00:00
parent 2c678e60f8
commit 70f06b2b33
6 changed files with 29 additions and 34 deletions

View File

@ -114,7 +114,6 @@ except ImportError:
add_color: Tuple[int, int, int, int],
mult_color: Color,
transform: Matrix,
origin: Point,
blendfunc: int,
texture: Image.Image,
single_threaded: bool = False,
@ -126,7 +125,6 @@ except ImportError:
# If this happens, that means one of the scaling factors was zero, making
# this object invisible. We can ignore this since the object should not
# be drawn.
print(f"WARNING: Transform Matrix {transform} has zero scaling factor, making it non-invertible!")
return img
# Warn if we have an unsupported blend.
@ -142,10 +140,10 @@ except ImportError:
texheight = texture.height
# Calculate the maximum range of update this texture can possibly reside in.
pix1 = transform.multiply_point(Point.identity().subtract(origin))
pix2 = transform.multiply_point(Point.identity().subtract(origin).add(Point(texwidth, 0)))
pix3 = transform.multiply_point(Point.identity().subtract(origin).add(Point(0, texheight)))
pix4 = transform.multiply_point(Point.identity().subtract(origin).add(Point(texwidth, texheight)))
pix1 = transform.multiply_point(Point.identity())
pix2 = transform.multiply_point(Point.identity().add(Point(texwidth, 0)))
pix3 = transform.multiply_point(Point.identity().add(Point(0, texheight)))
pix4 = transform.multiply_point(Point.identity().add(Point(texwidth, texheight)))
# Map this to the rectangle we need to sweep in the rendering image.
minx = max(int(min(pix1.x, pix2.x, pix3.x, pix4.x)), 0)
@ -170,7 +168,7 @@ except ImportError:
imgoff = imgx + (imgy * imgwidth)
# Calculate what texture pixel data goes here.
texloc = inverse.multiply_point(Point(float(imgx), float(imgy))).add(origin)
texloc = inverse.multiply_point(Point(float(imgx), float(imgy)))
texx, texy = texloc.as_tuple()
# If we're out of bounds, don't update.
@ -197,7 +195,7 @@ except ImportError:
nonlocal interrupted
interrupted = True
original_handler = signal.getsignal(signal.SIGINT)
previous_handler = signal.getsignal(signal.SIGINT)
signal.signal(signal.SIGINT, ctrlc)
for _ in range(cores):
@ -212,7 +210,6 @@ except ImportError:
texwidth,
texheight,
inverse,
origin,
add_color,
mult_color,
blendfunc,
@ -244,7 +241,7 @@ except ImportError:
for proc in procs:
proc.join()
signal.signal(signal.SIGINT, original_handler)
signal.signal(signal.SIGINT, previous_handler)
if interrupted:
raise KeyboardInterrupt()
@ -260,7 +257,6 @@ except ImportError:
texwidth: int,
texheight: int,
inverse: Matrix,
origin: Point,
add_color: Tuple[int, int, int, int],
mult_color: Color,
blendfunc: int,
@ -281,7 +277,7 @@ except ImportError:
continue
# Calculate what texture pixel data goes here.
texloc = inverse.multiply_point(Point(float(imgx), float(imgy))).add(origin)
texloc = inverse.multiply_point(Point(float(imgx), float(imgy)))
texx, texy = texloc.as_tuple()
# If we're out of bounds, don't update.

View File

@ -8,7 +8,6 @@ def affine_composite(
add_color: Tuple[int, int, int, int],
mult_color: Color,
transform: Matrix,
origin: Point,
blendfunc: int,
texture: Image.Image,
single_threaded: bool = False,

View File

@ -39,7 +39,6 @@ cdef extern int affine_composite_fast(
intcolor_t add_color,
floatcolor_t mult_color,
matrix_t inverse,
point_t origin,
int blendfunc,
unsigned char *texdata,
unsigned int texwidth,
@ -52,7 +51,6 @@ def affine_composite(
add_color: Tuple[int, int, int, int],
mult_color: Color,
transform: Matrix,
origin: Point,
blendfunc: int,
texture: Image.Image,
single_threaded: bool = False,
@ -64,7 +62,6 @@ def affine_composite(
# If this happens, that means one of the scaling factors was zero, making
# this object invisible. We can ignore this since the object should not
# be drawn.
print(f"WARNING: Transform Matrix {transform} has zero scaling factor, making it non-invertible!")
return img
if blendfunc not in {0, 2, 3, 8, 9, 70}:
@ -79,10 +76,10 @@ def affine_composite(
texheight = texture.height
# Calculate the maximum range of update this texture can possibly reside in.
pix1 = transform.multiply_point(Point.identity().subtract(origin))
pix2 = transform.multiply_point(Point.identity().subtract(origin).add(Point(texwidth, 0)))
pix3 = transform.multiply_point(Point.identity().subtract(origin).add(Point(0, texheight)))
pix4 = transform.multiply_point(Point.identity().subtract(origin).add(Point(texwidth, texheight)))
pix1 = transform.multiply_point(Point.identity())
pix2 = transform.multiply_point(Point.identity().add(Point(texwidth, 0)))
pix3 = transform.multiply_point(Point.identity().add(Point(0, texheight)))
pix4 = transform.multiply_point(Point.identity().add(Point(texwidth, texheight)))
# Map this to the rectangle we need to sweep in the rendering image.
minx = max(int(min(pix1.x, pix2.x, pix3.x, pix4.x)), 0)
@ -102,7 +99,6 @@ def affine_composite(
cdef intcolor_t c_addcolor = intcolor_t(r=add_color[0], g=add_color[1], b=add_color[2], a=add_color[3])
cdef floatcolor_t c_multcolor = floatcolor_t(r=mult_color.r, g=mult_color.g, b=mult_color.b, a=mult_color.a)
cdef matrix_t c_inverse = matrix_t(a=inverse.a, b=inverse.b, c=inverse.c, d=inverse.d, tx=inverse.tx, ty=inverse.ty)
cdef point_t c_origin = point_t(x=origin.x, y=origin.y)
cdef unsigned int threads = 1 if single_threaded else multiprocessing.cpu_count()
# Call the C++ function.
@ -117,7 +113,6 @@ def affine_composite(
c_addcolor,
c_multcolor,
c_inverse,
c_origin,
blendfunc,
texbytes,
texwidth,

View File

@ -60,7 +60,6 @@ extern "C"
unsigned int texwidth;
unsigned int texheight;
matrix_t inverse;
point_t origin;
intcolor_t add_color;
floatcolor_t mult_color;
int blendfunc;
@ -213,7 +212,7 @@ extern "C"
unsigned int imgoff = imgx + (imgy * work->imgwidth);
// Calculate what texture pixel data goes here.
point_t texloc = work->inverse.multiply_point((point_t){(float)imgx, (float)imgy}).add(work->origin);
point_t texloc = work->inverse.multiply_point((point_t){(float)imgx, (float)imgy});
int texx = roundf(texloc.x);
int texy = roundf(texloc.y);
@ -246,7 +245,6 @@ extern "C"
intcolor_t add_color,
floatcolor_t mult_color,
matrix_t inverse,
point_t origin,
int blendfunc,
unsigned char *texbytes,
unsigned int texwidth,
@ -270,7 +268,6 @@ extern "C"
work.texwidth = texwidth;
work.texheight = texheight;
work.inverse = inverse;
work.origin = origin;
work.add_color = add_color;
work.mult_color = mult_color;
work.blendfunc = blendfunc;
@ -312,7 +309,6 @@ extern "C"
work->texwidth = texwidth;
work->texheight = texheight;
work->inverse = inverse;
work->origin = origin;
work->add_color = add_color;
work->mult_color = mult_color;
work->blendfunc = blendfunc;

View File

@ -434,15 +434,13 @@ class AFPRenderer(VerboseOutput):
img: Image.Image,
renderable: PlacedObject,
parent_transform: Matrix,
parent_origin: Point,
only_depths: Optional[List[int]] = None,
prefix: str="",
) -> Image.Image:
self.vprint(f"{prefix} Rendering placed object ID {renderable.object_id} from sprite {renderable.source.tag_id} onto Depth {renderable.depth}")
# Compute the affine transformation matrix for this object.
transform = parent_transform.multiply(renderable.transform)
origin = parent_origin.add(renderable.rotation_offset)
transform = renderable.transform.multiply(parent_transform).translate(Point.identity().subtract(renderable.rotation_offset))
# Render individual shapes if this is a sprite.
if isinstance(renderable, PlacedClip):
@ -452,7 +450,7 @@ class AFPRenderer(VerboseOutput):
key=lambda obj: obj.depth,
)
for obj in objs:
img = self.__render_object(img, obj, transform, origin, only_depths=only_depths, prefix=prefix + " ")
img = self.__render_object(img, obj, transform, only_depths=only_depths, prefix=prefix + " ")
elif isinstance(renderable, PlacedShape):
# This is a shape draw reference.
shape = renderable.source
@ -515,7 +513,7 @@ class AFPRenderer(VerboseOutput):
(blend == 0 or blend == 2)
):
# We can!
cutin = transform.multiply_point(Point.identity().subtract(origin))
cutin = transform.multiply_point(Point.identity())
cutoff = Point.identity()
if cutin.x < 0:
cutoff.x = -cutin.x
@ -527,7 +525,7 @@ class AFPRenderer(VerboseOutput):
img.alpha_composite(texture, cutin.as_tuple(), cutoff.as_tuple())
else:
# We can't, so do the slow render that's correct.
img = affine_composite(img, add_color, mult_color, transform, origin, blend, texture, single_threaded=self.__single_threaded)
img = affine_composite(img, add_color, mult_color, transform, blend, texture, single_threaded=self.__single_threaded)
elif isinstance(renderable, PlacedDummy):
# Nothing to do!
pass
@ -699,7 +697,7 @@ class AFPRenderer(VerboseOutput):
# get the layering correct, but its important to preserve the original
# insertion order for delete requests.
curimage = Image.new("RGBA", actual_size, color=color.as_tuple())
curimage = self.__render_object(curimage, root_clip, root_clip.transform, root_clip.rotation_offset, only_depths=only_depths)
curimage = self.__render_object(curimage, root_clip, root_clip.transform, only_depths=only_depths)
else:
# Nothing changed, make a copy of the previous render.
self.vprint(" Using previous frame render")

View File

@ -120,6 +120,17 @@ class Matrix:
y=(self.b * point.x) + (self.d * point.y) + self.ty,
)
def translate(self, point: Point) -> "Matrix":
new_point = self.multiply_point(point)
return Matrix(
a=self.a,
b=self.b,
c=self.c,
d=self.d,
tx=new_point.x,
ty=new_point.y,
)
def multiply(self, other: "Matrix") -> "Matrix":
return Matrix(
a=self.a * other.a + self.b * other.c,