/*
* @(#)Transition2DInstruction.java
*
* $Date: 2014-03-13 09:15:48 +0100 (Cs, 13 márc. 2014) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* https://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software. (See the SVN repository for more details.)
*/
package com.bric.image.transition;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.Area;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.Vector;
import com.bric.geom.EmptyPathException;
import com.bric.geom.ShapeBounds;
/** This represents one "layer" of a frame of a transition.
* <P>The goal of keeping these instructions abstract is that
* they can be interpreted by other mechanisms (such as a Flash encoder).
* <P>Any one frame of a Transition2D object is defined as a list
* of instructions. When these instructions are painted (in order,
* on top of each other) they create the desired effect.
*/
public abstract class Transition2DInstruction {
/** This renders this instruction. */
public abstract void paint(Graphics2D g,BufferedImage frameA,BufferedImage frameB);
/** This examines the instructions provided and returns only those instructions
* that are guaranteed to be visible.
* <P>It is recommended that this method be called by encoders and not by Transition2D
* objects directly. For example, it may be advantageous to always include 20
* instructions, even if some instructions do not make a visual difference, because some
* day an encoder might be more interested in tweening those instructions than writing
* separate frames.
*
* @param instr the list of instructions to filter
* @param frameSize the dimensions the transition
* @return the subset of instructions that are guaranteed to be visible
*/
public static Transition2DInstruction[] filterVisibleInstructions(Transition2DInstruction[] instr,Dimension frameSize) {
Vector<Transition2DInstruction> v = new Vector<Transition2DInstruction>();
Rectangle2D movieRect = new Rectangle(0,0,frameSize.width,frameSize.height);
Area movieArea = new Area(movieRect);
for(int a = 0; a<instr.length; a++) {
Transition2DInstruction i = instr[a];
//check #1: if it's a shape instruction: are its elements visible?
if(i instanceof ShapeInstruction) {
ShapeInstruction i2 = (ShapeInstruction)i;
if( (i2.fillColor==null || i2.fillColor.getAlpha()<5) &&
(i2.strokeColor==null || i2.strokeWidth==0 || i2.strokeColor.getAlpha()<5)) {
//this instruction is invisible:
i = null;
}
}
//check #2: if it's a translucent image: is it visible?
if(i instanceof ImageInstruction) {
ImageInstruction i2 = (ImageInstruction)i;
if( i2.opacity<.05f ) {
//this instruction is invisible:
i = null;
}
}
//check #3: is this instruction on screen? If not, let's not write it.
//this saves space.
//However, to save time (against the infamously slow Area class), we'll
//break this into a couple of different checks:
Shape instructionShape = null;
if(i instanceof ImageInstruction) {
ImageInstruction i2 = (ImageInstruction)i;
instructionShape = i2.clipping;
//this is a special case, indicating that there is no clipping,
//so everything should be drawn:
if(instructionShape==null) {
v.add(i);
break;
}
} else if(i instanceof ShapeInstruction) {
ShapeInstruction i2 = (ShapeInstruction)i;
instructionShape = i2.shape;
}
if(instructionShape!=null) {
try {
Rectangle2D instructionRect = ShapeBounds.getBounds(instructionShape);
if(movieRect.contains(instructionRect)) {
//definitely add
v.add(i);
} else if(!movieRect.intersects(instructionRect)) {
//definitely do not add: nothing to do here.
} else {
//further examination is necessary:
Area instructionArea = new Area(instructionShape);
instructionArea.intersect(movieArea);
if(instructionArea.isEmpty()==false) {
v.add(i);
}
}
} catch(EmptyPathException e) {
//we're good... no need to add this instruction since it has no shape
}
}
}
return v.toArray(new Transition2DInstruction[v.size()]);
}
}