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

View File

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

View File

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

View File

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