Fix translation matrix application on embedded clips, fixes placement of lots of complex animations.
This commit is contained in:
parent
2c678e60f8
commit
70f06b2b33
@ -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.
|
||||||
|
@ -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,
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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")
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user