/***********************************************************************
* mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.components.visibleComponents.shapes;
import org.mt4j.MTApplication;
import org.mt4j.components.TransformSpace;
import org.mt4j.components.bounds.BoundsZPlaneRectangle;
import org.mt4j.components.bounds.IBoundingShape;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.math.Vector3D;
import org.mt4j.util.math.Vertex;
import processing.core.PApplet;
import processing.core.PImage;
/**
* A simple rectangular shape.
*
* @author Christopher Ruff
*/
public class MTRectangle extends MTPolygon {
/** The current anchor. */
private PositionAnchor currentAnchor;
// (if the rectangle is x or y, rotated, the boundsZPlaneRectangle wont work anymore as a boundingshape!)
// actually it works..only wouldnt work if the local vertices arent lying on a z=0 parallel plane.
/**
* The Enum PositionAnchor.
*
* @author Christopher Ruff
*/
public enum PositionAnchor{
/** The LOWE r_ left. */
LOWER_LEFT,
/** The LOWE r_ right. */
LOWER_RIGHT,
/** The UPPE r_ left. */
UPPER_LEFT,
/** The CENTER. */
CENTER
}
/**
* Instantiates a new mT rectangle.
*
* @param texture the texture
* @param applet the applet
*/
public MTRectangle(PImage texture, PApplet applet) {
this(0 ,0 ,0, texture.width, texture.height, applet);
//To avoid errors if this is created in non opengl thread so the gl texture wont be created correctly when setting setTexture
this.setUseDirectGL(false);
if (applet instanceof MTApplication) {
MTApplication app = (MTApplication) applet;
if (MT4jSettings.getInstance().isOpenGlMode()){
if (app.isRenderThreadCurrent()){
this.setUseDirectGL(true);
}else{
//IF we are useing OpenGL, set useDirectGL to true
//(=>creates OpenGL texture, draws with pure OpenGL commands)
//in our main thread.
app.invokeLater(new Runnable() {
public void run() {
setUseDirectGL(true);
}
});
}
}else{
if (this.isUseDirectGL()){
this.setUseDirectGL(false);
}
}
}else{
//Cant check if we are in renderthread -> dont use direct gl mode -> dont create Gl texture object
if (this.isUseDirectGL()){
this.setUseDirectGL(false);
}
}
// //hm..this is for when we create textured rects in other threads
// //, because when we init gl texture in other thread it breaks..
// this.setUseDirectGL(false);
//
// //IF we are useing OpenGL, set useDirectGL to true
// //(=>creates OpenGL texture, draws with pure OpenGL commands)
// //in our main thread.
// if (MT4jSettings.getInstance().isOpenGlMode() && applet instanceof MTApplication){
// MTApplication app = (MTApplication)applet;
// app.invokeLater(new Runnable() {
// public void run() {
// if (!isUseDirectGL())
// setUseDirectGL(true);
// }
// });
// }
this.setTexture(texture);
this.setTextureEnabled(true);
}
/**
* Instantiates a new mT rectangle with the upper left corner at 0,0,0
*
* @param width the width
* @param height the height
* @param pApplet the applet
*/
public MTRectangle(float width, float height, PApplet pApplet) {
this(new Vertex(0,0,0,0,0),width,height,pApplet);
}
/**
* Instantiates a new mT rectangle.
*
* @param x the x
* @param y the y
* @param width the width
* @param height the height
* @param pApplet the applet
*/
public MTRectangle(float x, float y, float width, float height, PApplet pApplet) {
this(new Vertex(x,y,0,0,0),width,height,pApplet);
}
/**
* Instantiates a new mT rectangle.
*
* @param x the x
* @param y the y
* @param z the z
* @param width the width
* @param height the height
* @param pApplet the applet
*/
public MTRectangle(float x, float y, float z, float width, float height, PApplet pApplet) {
this(new Vertex(x,y,z,0,0),width,height,pApplet);
}
/**
* Instantiates a new mT rectangle.
*
* @param upperLeft the upper left
* @param width the width
* @param height the height
* @param pApplet the applet
*/
public MTRectangle(Vertex upperLeft, float width, float height, PApplet pApplet) {
super(new Vertex[]{
new Vertex(upperLeft.x, upperLeft.y, upperLeft.z, 0, 0),
new Vertex(upperLeft.x+width, upperLeft.y, upperLeft.z, 1, 0),
new Vertex(upperLeft.x+width, upperLeft.y+height, upperLeft.z, 1, 1),
new Vertex(upperLeft.x, upperLeft.y+height, upperLeft.z, 0, 1),
new Vertex(upperLeft.x, upperLeft.y, upperLeft.z, 0, 0)},
pApplet);
this.setName("unnamed rectangle");
//
this.setBoundsBehaviour(AbstractShape.BOUNDS_ONLY_CHECK);
currentAnchor = PositionAnchor.CENTER;
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.MTPolygon#computeDefaultBounds()
*/
@Override
protected IBoundingShape computeDefaultBounds(){
return new BoundsZPlaneRectangle(this);
}
/**
* Gets the Position anchor.
*
* @return the anchor
*/
public PositionAnchor getAnchor(){
return this.currentAnchor;
}
/**
* Sets the anchor. The Anchor determines which reference point
* is used at set/getPosition(). The default anchor point is the rectangle's
* center.
*
* @param anchor the new anchor
*/
public void setAnchor(PositionAnchor anchor){
this.currentAnchor = anchor;
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.AbstractShape#setPositionGlobal(org.mt4j.util.math.Vector3D)
*/
@Override
public void setPositionGlobal(Vector3D position) {
switch (this.getAnchor()) {
case CENTER:
super.setPositionGlobal(position);
break;
case LOWER_LEFT:{
Vertex[] vertices = this.getVerticesGlobal();
Vertex lowerLeft = new Vertex(vertices[3]);
this.translateGlobal(position.getSubtracted(lowerLeft));
}break;
case LOWER_RIGHT:{
Vertex[] vertices = this.getVerticesGlobal();
Vertex v = new Vertex(vertices[2]);
this.translateGlobal(position.getSubtracted(v));
}break;
case UPPER_LEFT:{
Vertex[] vertices = this.getVerticesGlobal();
Vertex upperLeft = new Vertex(vertices[0]);
this.translateGlobal(position.getSubtracted(upperLeft));
}break;
default:
break;
}
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.AbstractShape#setPositionRelativeToParent(org.mt4j.util.math.Vector3D)
*/
@Override
public void setPositionRelativeToParent(Vector3D position) {
switch (this.getAnchor()) {
case CENTER:
super.setPositionRelativeToParent(position);
break;
case LOWER_LEFT:{
Vertex[] vertices = this.getVerticesLocal();
Vertex lowerLeft = new Vertex(vertices[3]);
lowerLeft.transform(this.getLocalMatrix());
this.translate(position.getSubtracted(lowerLeft), TransformSpace.RELATIVE_TO_PARENT);
}break;
case LOWER_RIGHT:{
Vertex[] vertices = this.getVerticesLocal();
Vertex v = new Vertex(vertices[2]);
v.transform(this.getLocalMatrix());
this.translate(position.getSubtracted(v), TransformSpace.RELATIVE_TO_PARENT);
}break;
case UPPER_LEFT:{
Vertex[] vertices = this.getVerticesLocal();
Vertex v = new Vertex(vertices[0]);
v.transform(this.getLocalMatrix());
this.translate(position.getSubtracted(v), TransformSpace.RELATIVE_TO_PARENT);
}break;
default:
break;
}
}
/**
* Gets the position. The position is dependant on the
* set PositionAnchor. The default is the PositionAnchor.CENTER.
*
* @param transformSpace the transform space
* @return the position
*/
public Vector3D getPosition(TransformSpace transformSpace){
Vector3D v;
switch (transformSpace) {
case LOCAL:
switch (this.getAnchor()) {
case CENTER:
return this.getCenterPointLocal();
case LOWER_LEFT:
return new Vector3D(this.getVerticesLocal()[3]);
case LOWER_RIGHT:
return new Vector3D(this.getVerticesLocal()[2]);
case UPPER_LEFT:
return new Vector3D(this.getVerticesLocal()[0]);
default:
break;
}
break;
case RELATIVE_TO_PARENT:
switch (this.getAnchor()) {
case CENTER:
return this.getCenterPointRelativeToParent();
case LOWER_LEFT:
v = new Vector3D(this.getVerticesLocal()[3]);
v.transform(this.getLocalMatrix());
return v;
case LOWER_RIGHT:
v = new Vector3D(this.getVerticesLocal()[2]);
v.transform(this.getLocalMatrix());
return v;
case UPPER_LEFT:
v = new Vector3D(this.getVerticesLocal()[0]);
v.transform(this.getLocalMatrix());
return v;
default:
break;
}
break;
case GLOBAL:
switch (this.getAnchor()) {
case CENTER:
return this.getCenterPointGlobal();
case LOWER_LEFT:
v = new Vector3D(this.getVerticesLocal()[3]);
v.transform(this.getGlobalMatrix());
return v;
case LOWER_RIGHT:
v = new Vector3D(this.getVerticesLocal()[2]);
v.transform(this.getGlobalMatrix());
return v;
case UPPER_LEFT:
v = new Vector3D(this.getVerticesLocal()[0]);
v.transform(this.getGlobalMatrix());
return v;
default:
break;
}
break;
default:
break;
}
return null;
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.MTPolygon#get2DPolygonArea()
*/
@Override
public double get2DPolygonArea() {
return (getHeightXY(TransformSpace.RELATIVE_TO_PARENT)*getWidthXY(TransformSpace.RELATIVE_TO_PARENT));
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.MTPolygon#getCenterOfMass2DLocal()
*/
@Override
public Vector3D getCenterOfMass2DLocal() {
Vertex[] v = this.getVerticesLocal();
Vector3D center = new Vector3D(
v[0].getX() + ((v[1].getX() - v[0].getX())/2),
v[1].getY() + ((v[2].getY() - v[1].getY())/2),
v[0].getZ());
return center;
}
/* (non-Javadoc)
* @see org.mt4j.components.visibleComponents.shapes.MTPolygon#getCenterPointLocal()
*/
@Override
public Vector3D getCenterPointLocal(){
return this.getCenterOfMass2DLocal();
}
/**
* Sets the size locally, meaning that not the transformation of the rectangle is changed, (as setSize/setWidth, scale etc. would do) but the vertices
* of the rectangle themselves. This is useful if we dont want the rectangles children to be scaled as well, for example.
* <br>Note: The scaling is done from the rectangles upper left corner - not the center!
*
* @param width the width
* @param height the height
*/
public void setSizeLocal(float width, float height){
if (width > 0 && height > 0){
Vertex[] v = this.getVerticesLocal();
this.setVertices(new Vertex[]{
new Vertex(v[0].x, v[0].y, v[0].z, v[0].getTexCoordU(), v[0].getTexCoordV(), v[0].getR(), v[0].getG(), v[0].getB(), v[0].getA()),
new Vertex(v[0].x+width, v[1].y, v[1].z, v[1].getTexCoordU(), v[1].getTexCoordV(), v[1].getR(), v[1].getG(), v[1].getB(), v[1].getA()),
new Vertex(v[0].x+width, v[1].y+height, v[2].z, v[2].getTexCoordU(), v[2].getTexCoordV(), v[2].getR(), v[2].getG(), v[2].getB(), v[2].getA()),
new Vertex(v[3].x, v[0].y+height, v[3].z, v[3].getTexCoordU(), v[3].getTexCoordV(), v[3].getR(), v[3].getG(), v[3].getB(), v[3].getA()),
new Vertex(v[4].x, v[4].y, v[4].z, v[4].getTexCoordU(), v[4].getTexCoordV(), v[4].getR(), v[4].getG(), v[4].getB(), v[4].getA()),
});
}
}
/**
* Sets the height locally, meaning that not the transformation of the rectangle is changed, (as setSize/setWidth, scale etc. would do) but the vertices
* of the rectangle themselves. This is useful if we dont want the rectangles children to be scaled as well, for example.
* <br>Note: The scaling is done from the rectangles upper left corner - not the center!
*
* @param height the new height local
*/
public void setHeightLocal(float height){
Vertex[] v = this.getVerticesLocal();
this.setVertices(new Vertex[]{
new Vertex(v[0].x, v[0].y, v[0].z, v[0].getTexCoordU(), v[0].getTexCoordV(), v[0].getR(), v[0].getG(), v[0].getB(), v[0].getA()),
new Vertex(v[1].x, v[1].y, v[1].z, v[1].getTexCoordU(), v[1].getTexCoordV(), v[1].getR(), v[1].getG(), v[1].getB(), v[1].getA()),
new Vertex(v[2].x, v[1].y+height, v[2].z, v[2].getTexCoordU(), v[2].getTexCoordV(), v[2].getR(), v[2].getG(), v[2].getB(), v[2].getA()),
new Vertex(v[3].x, v[1].y+height, v[3].z, v[3].getTexCoordU(), v[3].getTexCoordV(), v[3].getR(), v[3].getG(), v[3].getB(), v[3].getA()),
new Vertex(v[4].x, v[4].y, v[4].z, v[4].getTexCoordU(), v[4].getTexCoordV(), v[4].getR(), v[4].getG(), v[4].getB(), v[4].getA()),
});
}
/**
* Sets the width locally, meaning that not the transformation of the rectangle is changed, (as setSize/setWidth, scale etc. would do) but the vertices
* of the rectangle themselves. This is useful if we dont want the rectangles children to be scaled as well, for example.
* <br>Note: The scaling is done from the rectangles upper left corner - not the center!
* @param width the new width local
*/
public void setWidthLocal(float width){
if (width > 0){
Vertex[] v = this.getVerticesLocal();
this.setVertices(new Vertex[]{
new Vertex(v[0].x, v[0].y, v[0].z, v[0].getTexCoordU(), v[0].getTexCoordV(), v[0].getR(), v[0].getG(), v[0].getB(), v[0].getA()),
new Vertex(v[0].x+width, v[1].y, v[1].z, v[1].getTexCoordU(), v[1].getTexCoordV(), v[1].getR(), v[1].getG(), v[1].getB(), v[1].getA()),
new Vertex(v[0].x+width, v[2].y, v[2].z, v[2].getTexCoordU(), v[2].getTexCoordV(), v[2].getR(), v[2].getG(), v[2].getB(), v[2].getA()),
new Vertex(v[3].x, v[3].y, v[3].z, v[3].getTexCoordU(), v[3].getTexCoordV(), v[3].getR(), v[3].getG(), v[3].getB(), v[3].getA()),
new Vertex(v[4].x, v[4].y, v[4].z, v[4].getTexCoordU(), v[4].getTexCoordV(), v[4].getR(), v[4].getG(), v[4].getB(), v[4].getA()),
});
}
}
//TODO also overRide setSizeGlobal()!!
//TODO setSize setzt obj space size nicht relative bis jetzt! einfach width vector transformen und length() holen!
}