/* * Copyright (C) 2010-2016 JPEXS, All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3.0 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. */ package com.jpexs.decompiler.flash.types; import com.jpexs.decompiler.flash.types.annotations.Calculated; import com.jpexs.decompiler.flash.types.annotations.Conditional; import com.jpexs.decompiler.flash.types.annotations.SWFType; import java.awt.Point; import java.io.Serializable; /** * Represents a standard 2x3 transformation matrix of the sort commonly used in * 2D graphics * * @author JPEXS */ public class MATRIX implements Serializable { /** * Has scale values */ public boolean hasScale; /** * X scale value */ @Conditional("hasScale") @SWFType(value = BasicType.FB, countField = "nScaleBits") public int scaleX; /** * Y scale value */ @Conditional("hasScale") @SWFType(value = BasicType.FB, countField = "nScaleBits") public int scaleY; /** * Has rotate and skew values */ public boolean hasRotate; /** * First rotate and skew value */ @Conditional("hasRotate") @SWFType(value = BasicType.FB, countField = "nRotateBits") public int rotateSkew0; /** * Second rotate and skew value */ @Conditional("hasRotate") @SWFType(value = BasicType.FB, countField = "nRotateBits") public int rotateSkew1; /** * X translate value in twips */ @SWFType(value = BasicType.SB, countField = "nTranslateBits") public int translateX; /** * Y translate value in twips */ @SWFType(value = BasicType.SB, countField = "nTranslateBits") public int translateY; @Calculated @SWFType(value = BasicType.UB, count = 5) public int nTranslateBits; @Calculated @SWFType(value = BasicType.UB, count = 5) public int nRotateBits; @Calculated @SWFType(value = BasicType.UB, count = 5) public int nScaleBits; public MATRIX() { } public MATRIX(MATRIX m) { if (m == null) { return; } hasScale = m.hasScale; hasRotate = m.hasRotate; scaleX = m.scaleX; scaleY = m.scaleY; rotateSkew0 = m.rotateSkew0; rotateSkew1 = m.rotateSkew1; translateX = m.translateX; translateY = m.translateY; } @Override public String toString() { return "[MATRIX scale:" + getScaleXFloat() + "," + getScaleYFloat() + ", rotate:" + getRotateSkew0Float() + "," + getRotateSkew1Float() + ", translate:" + translateX + "," + translateY + "]"; } private float toFloat(int i) { return ((float) i) / (1 << 16); } public Point apply(Point p) { Point ret = new Point(); ret.x = (int) (p.x * (hasScale ? toFloat(scaleX) : 1) + p.y * (hasRotate ? toFloat(rotateSkew1) : 0) + translateX); ret.y = (int) (p.x * (hasRotate ? toFloat(rotateSkew0) : 0) + p.y * (hasScale ? toFloat(scaleY) : 1) + translateY); return ret; } public RECT apply(RECT r) { Point topLeft = apply(r.getTopLeft()); Point bottomRight = apply(r.getBottomRight()); int Xmin = Math.min(topLeft.x, bottomRight.x); int Ymin = Math.min(topLeft.y, bottomRight.y); int Xmax = Math.max(topLeft.x, bottomRight.x); int Ymax = Math.max(topLeft.y, bottomRight.y); return new RECT(Xmin, Xmax, Ymin, Ymax); } public int getRotateSkew0() { return hasRotate ? rotateSkew0 : 0; } public int getRotateSkew1() { return hasRotate ? rotateSkew1 : 0; } public float getRotateSkew0Float() { return (hasRotate ? toFloat(rotateSkew0) : 0); } public float getRotateSkew1Float() { return (hasRotate ? toFloat(rotateSkew1) : 0); } public float getScaleXFloat() { return (hasScale ? toFloat(scaleX) : 1); } public float getScaleYFloat() { return (hasScale ? toFloat(scaleY) : 1); } public int getScaleX() { return (hasScale ? (scaleX) : (1 << 16)); } public int getScaleY() { return (hasScale ? (scaleY) : (1 << 16)); } public boolean isEmpty() { return (translateX == 0) && (translateY == 0) && (!hasRotate) && (!hasScale); } @Override public int hashCode() { int hash = 7; hash = 37 * hash + getScaleX(); hash = 37 * hash + getScaleY(); hash = 37 * hash + getRotateSkew0(); hash = 37 * hash + getRotateSkew1(); hash = 37 * hash + translateX; hash = 37 * hash + translateY; return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MATRIX other = (MATRIX) obj; if (getScaleX() != other.getScaleX()) { return false; } if (getScaleY() != other.getScaleY()) { return false; } if (getRotateSkew0() != other.getRotateSkew0()) { return false; } if (getRotateSkew1() != other.getRotateSkew1()) { return false; } if (translateX != other.translateX) { return false; } if (translateY != other.translateY) { return false; } return true; } }