/*********************************************************************** * 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! }