diff --git a/code/__HELPERS/matrices.dm b/code/__HELPERS/matrices.dm index e12d753d20f..4b430d9c61c 100644 --- a/code/__HELPERS/matrices.dm +++ b/code/__HELPERS/matrices.dm @@ -1,3 +1,36 @@ +/// Datum which stores information about a matrix decomposed with decompose(). +/datum/decompose_matrix + ///? + var/scale_x = 1 + ///? + var/scale_y = 1 + ///? + var/rotation = 0 + ///? + var/shift_x = 0 + ///? + var/shift_y = 0 + +/// Decomposes a matrix into scale, shift and rotation. +/// +/// If other operations were applied on the matrix, such as shearing, the result +/// will not be precise. +/// +/// Negative scales are not supported. +/matrix/proc/decompose() + var/datum/decompose_matrix/decompose_matrix = new + . = decompose_matrix + decompose_matrix.scale_x = sqrt(a * a + d * d) + decompose_matrix.scale_y = sqrt(b * b + e * e) + decompose_matrix.shift_x = c + decompose_matrix.shift_y = f + if(!decompose_matrix.scale_x || !decompose_matrix.scale_y) + return + // If only translated, scaled and rotated, a/xs == e/ys and -d/xs == b/xy + var/cossine = (a/decompose_matrix.scale_x + e/decompose_matrix.scale_y) / 2 + var/sine = (b/decompose_matrix.scale_y - d/decompose_matrix.scale_x) / 2 + decompose_matrix.rotation = arctan(cossine, sine) + /matrix/proc/TurnTo(old_angle, new_angle) . = new_angle - old_angle Turn(.) //BYOND handles cases such as -270, 360, 540 etc. DOES NOT HANDLE 180 TURNS WELL, THEY TWEEN AND LOOK LIKE SHIT @@ -55,30 +88,14 @@ . += f . += 1 -//The X pixel offset of this matrix +///The X pixel offset of this matrix /matrix/proc/get_x_shift() . = c -//The Y pixel offset of this matrix +///The Y pixel offset of this matrix /matrix/proc/get_y_shift() . = f -/matrix/proc/get_x_skew() - . = b - -/matrix/proc/get_y_skew() - . = d - -//Skews a matrix in a particular direction -//Missing arguments are treated as no skew in that direction - -//As Rotation is defined as a scale+skew, these procs will break any existing rotation -//Unless the result is multiplied against the current matrix -/matrix/proc/set_skew(x = 0, y = 0) - b = x - d = y - - ///////////////////// // COLOUR MATRICES // ///////////////////// diff --git a/code/modules/photography/camera/camera_image_capturing.dm b/code/modules/photography/camera/camera_image_capturing.dm index 63a2b810355..95966711a4f 100644 --- a/code/modules/photography/camera/camera_image_capturing.dm +++ b/code/modules/photography/camera/camera_image_capturing.dm @@ -1,5 +1,4 @@ /obj/effect/appearance_clone - var/turn_angle = 0 /obj/effect/appearance_clone/New(loc, atom/A) //Intentionally not Initialize(), to make sure the clone assumes the intended appearance in time for the camera getFlatIcon. if(istype(A)) @@ -9,9 +8,6 @@ var/atom/movable/AM = A step_x = AM.step_x step_y = AM.step_y - if(iscarbon(A)) - var/mob/living/carbon/C = A - UNLINT(turn_angle = C.lying_angle) // this is the only place its okay to read lying directly . = ..() /obj/item/camera/proc/camera_get_icon(list/turfs, turf/center, psize_x = 96, psize_y = 96, datum/turf_reservation/clone_area, size_x, size_y, total_x, total_y) @@ -82,14 +78,29 @@ else for(var/X in sorted) //these are clones var/obj/effect/appearance_clone/clone = X - var/xo = (clone.x - center.x) * world.icon_size + clone.pixel_x + xcomp - var/yo = (clone.y - center.y) * world.icon_size + clone.pixel_y + ycomp - xo += clone.step_x - yo += clone.step_y var/icon/img = getFlatIcon(clone, no_anim = TRUE) if(img) - if(clone.turn_angle) //the cheapest (so best, considering cams don't need to be laggier) way of doing this, considering getFlatIcon doesn't give a snot about transforms.' - img.Turn(clone.turn_angle) + // Center of the image in X + var/xo = (clone.x - center.x) * world.icon_size + clone.pixel_x + xcomp + clone.step_x + // Center of the image in Y + var/yo = (clone.y - center.y) * world.icon_size + clone.pixel_y + ycomp + clone.step_y + + if(clone.transform) // getFlatIcon doesn't give a snot about transforms. + var/datum/decompose_matrix/decompose = clone.transform.decompose() + // Scale in X, Y + if(decompose.scale_x != 1 || decompose.scale_y != 1) + var/base_w = img.Width() + var/base_h = img.Height() + img.Scale(base_w * decompose.scale_x, base_h * decompose.scale_y) + xo -= base_w * (decompose.scale_x - 1) / 2 + yo -= base_h * (decompose.scale_y - 1) / 2 + // Rotation + if(decompose.rotation != 0) + img.Turn(decompose.rotation) + // Shift + xo += decompose.shift_x + yo += decompose.shift_y + res.Blend(img, blendMode2iconMode(clone.blend_mode), xo, yo) CHECK_TICK