/***********************************************************************
* 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 {
private PositionAnchor currentAnchor;
//FIXME if the rectangle is rotated, the boundsZPlaneRectangle wont work anymore!
public enum PositionAnchor{
LOWER_LEFT,
LOWER_RIGHT,
UPPER_LEFT,
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);
//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.
*
* @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 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 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 com.jMT.components.visibleComponents.shapes.MTPolygon#computeDefaultBounds()
*/
@Override
protected IBoundingShape computeDefaultBounds(){
return new BoundsZPlaneRectangle(this);
}
public PositionAnchor getAnchor(){
return this.currentAnchor;
}
public void setAnchor(PositionAnchor anchor){
this.currentAnchor = anchor;
}
/* (non-Javadoc)
* @see mTouch.components.visibleComponents.shapes.AbstractShape#setPositionGlobal(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;
}
}
@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;
}
}
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 com.jMT.components.visibleComponents.shapes.MTPolygon#get2DPolygonArea()
*/
@Override
public double get2DPolygonArea() {
return (getHeightXY(TransformSpace.RELATIVE_TO_PARENT)*getWidthXY(TransformSpace.RELATIVE_TO_PARENT));
}
/* (non-Javadoc)
* @see com.jMT.components.visibleComponents.shapes.MTPolygon#getCenterOfMassObjSpace()
*/
@Override
public Vector3D getCenterOfMass2DLocal() {
Vertex[] pickVertsUntrans = this.getVerticesLocal();
Vector3D center = new Vector3D(
pickVertsUntrans[0].getX() + ((pickVertsUntrans[1].getX() - pickVertsUntrans[0].getX())/2),
pickVertsUntrans[1].getY() + ((pickVertsUntrans[2].getY() - pickVertsUntrans[1].getY())/2),
pickVertsUntrans[0].getZ());
// center.transform(this.getAbsoluteLocalToWorldMatrix());
return center;
}
/* (non-Javadoc)
* @see com.jMT.components.visibleComponents.shapes.MTPolygon#getCenterPointObjectSpace()
*/
@Override
public Vector3D getCenterPointLocal(){
return this.getCenterOfMass2DLocal();
}
/*
public float getHeight() {
Vertex[] v1 = this.getPickVerticesTrans();
Vertex bla = (Vertex)v1[2].minus(v1[1]);
return bla.magnitude();
}
public float getWidth() {
Vertex[] v = this.getPickVerticesTrans();
Vertex bla = (Vertex)v[1].minus(v[0]);
return bla.magnitude();
}
*/
//TODO wie mit local und world umgehen?
//setSize etc als "world" machen,
//evtl zus�tzliche methoden f�r setSizeLocal?
// //FIXME this actually is setSizeLOCAL!!!
// /**
// * Sets the size of the rectangle.
// * Changes the vertices themself, not the transform, to allow for hassle-free non-uniform scaling.
// * <p>Overridden because shearing will occur if the component was rotated and then scaled non-uniformly!
// * <br>This method preserves the orientation
// *
// * @param width the width
// * @param height the height
// *
// * @return true, if sets the size xy relative to parent
// */
// @Override
// public boolean setSizeXYRelativeToParent(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()),
// });
// return true;
// }else
// return false;
// }
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()),
});
}
}
// /* (non-Javadoc)
// * @see com.jMT.components.visibleComponents.shapes.MTPolygon#setHeightXYRelativeToParent(float)
// */
// @Override
// public boolean setHeightXYRelativeToParent(float height){
// if (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[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()),
// });
// return true;
// }else
// return false;
// }
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()),
});
}
// /**
// * Scales the shape to the given width.
// * Uses the bounding rectangle for calculation!
// * Aspect ratio is preserved!
// *
// * @param width the width
// *
// * @return true, if the width isnt negative
// */
// @Override
// public boolean setWidthXYRelativeToParent(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()),
// });
// return true;
// }else
// return false;
// }
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!
}