/*********************************************************************** * 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.AbstractMTApplication; import org.mt4j.components.TransformSpace; import org.mt4j.components.bounds.BoundsZPlaneRectangle; import org.mt4j.components.bounds.IBoundingShape; import org.mt4j.components.css.style.CSSStyle; import org.mt4j.util.PlatformUtil; import org.mt4j.util.MT4jSettings; import org.mt4j.util.math.Tools3D; import org.mt4j.util.math.Vector3D; import org.mt4j.util.math.Vertex; import org.mt4j.util.opengl.GLTexture; import org.mt4j.util.opengl.GLTexture.TEXTURE_TARGET; 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; /** * 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 * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter. */ public MTRectangle(PImage texture, PApplet applet) { this(applet, texture); } /** * Instantiates a new mT rectangle. * @param applet the applet * @param texture the texture */ public MTRectangle(PApplet applet, PImage texture) { // this(applet ,0 ,0, 0, texture.width, texture.height); this(applet ,0 ,0, 0, texture.width, texture.height); //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 AbstractMTApplication) { AbstractMTApplication app = (AbstractMTApplication) 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); adaptTexCoordsForNPOTUse(); } } this.setTexture(texture); this.setTextureEnabled(true); } //FIXME TEST -> adapt tex coords for non fitting, NPOT gl texture private void adaptTexCoordsForNPOTUse(){ PImage tex = this.getTexture(); if (tex instanceof GLTexture){ Tools3D.adaptTextureCoordsNPOT(this, (GLTexture)tex); } } @Override public void setUseDirectGL(boolean drawPureGL) { super.setUseDirectGL(drawPureGL); adaptTexCoordsForNPOTUse(); } @Override public void setTexture(PImage newTexImage) { super.setTexture(newTexImage); adaptTexCoordsForNPOTUse(); } /** * Instantiates a new mT rectangle. * * @param width the width * @param height the height * @param pApplet the applet * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter. */ public MTRectangle(float width, float height, PApplet pApplet) { this(pApplet, width, height); } /** * Instantiates a new mT rectangle with the upper left corner at 0,0,0 * @param pApplet the applet * @param width the width * @param height the height */ public MTRectangle(PApplet pApplet, float width, float height) { this(pApplet,new Vertex(0,0,0,0,0),width,height); } /** * 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 * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter. */ public MTRectangle(float x, float y, float width, float height, PApplet pApplet) { this(pApplet, x, y, width, height); } /** * Instantiates a new mT rectangle. * @param pApplet the applet * @param x the x * @param y the y * @param width the width * @param height the height */ public MTRectangle(PApplet pApplet, float x, float y, float width, float height) { this(pApplet,new Vertex(x,y,0,0,0),width,height); } /** * 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 * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter. */ public MTRectangle(float x, float y, float z, float width, float height, PApplet pApplet) { this(pApplet, x, y, z, width, height); } /** * Instantiates a new mT rectangle. * @param pApplet the applet * @param x the x * @param y the y * @param z the z * @param width the width * @param height the height */ public MTRectangle(PApplet pApplet, float x, float y, float z, float width, float height) { this(pApplet,new Vertex(x,y,z,0,0),width,height); } /** * Instantiates a new mT rectangle. * * @param upperLeft the upper left * @param width the width * @param height the height * @param pApplet the applet * @deprecated constructor will be deleted! Please , use the constructor with the PApplet instance as the first parameter. */ public MTRectangle(Vertex upperLeft, float width, float height, PApplet pApplet) { this(pApplet, upperLeft, width, height); } /** * Instantiates a new mT rectangle. * @param pApplet the applet * @param upperLeft the upper left * @param width the width * @param height the height */ public MTRectangle(PApplet pApplet, Vertex upperLeft, float width, float height) { // super(pApplet, // 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)}); // // this.setName("unnamed rectangle"); // // // this.setBoundsBehaviour(AbstractShape.BOUNDS_ONLY_CHECK); // // currentAnchor = PositionAnchor.CENTER; this(pApplet, upperLeft, width, height, 1, 1); } public MTRectangle(PApplet pApplet, Vertex upperLeft, float width, float height, int textureMaxX, int textureMaxY) { super(pApplet, new Vertex[]{ new Vertex(upperLeft.x, upperLeft.y, upperLeft.z, 0, 0), new Vertex(upperLeft.x+width, upperLeft.y, upperLeft.z, textureMaxX, 0), new Vertex(upperLeft.x+width, upperLeft.y+height, upperLeft.z, textureMaxX, textureMaxY), new Vertex(upperLeft.x, upperLeft.y+height, upperLeft.z, 0, textureMaxY), new Vertex(upperLeft.x, upperLeft.y, upperLeft.z, 0, 0)}); 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(); return 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()); } /* (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()), }); } } @Override protected void applyStyleSheetCustom(CSSStyle virtualStyleSheet) { super.applyStyleSheetCustom(virtualStyleSheet); if (virtualStyleSheet.isWidthPercentage() && virtualStyleSheet.isHeightPercentage()) { if (this.getParent() != null) { if (virtualStyleSheet.getWidth() > 0) this.setWidthLocal(virtualStyleSheet.getWidth() / 100f * this.getParent().getBounds() .getWidthXY(TransformSpace.RELATIVE_TO_PARENT)); if (virtualStyleSheet.getHeight() > 0) this.setHeightLocal(virtualStyleSheet.getHeight()/ 100f * this.getParent().getBounds() .getHeightXY(TransformSpace.RELATIVE_TO_PARENT)); } } else if (virtualStyleSheet.isWidthPercentage()) { if (virtualStyleSheet.getWidth() > 0) this.setWidthLocal(virtualStyleSheet.getWidth() / 100f * this.getParent().getBounds() .getWidthXY(TransformSpace.RELATIVE_TO_PARENT)); if (virtualStyleSheet.getHeight() > 0) this.setHeightLocal(virtualStyleSheet.getHeight()); } else if (virtualStyleSheet.isHeightPercentage()) { if (virtualStyleSheet.getWidth() > 0) this.setWidthLocal(virtualStyleSheet.getWidth()); if (virtualStyleSheet.getHeight() > 0) this.setHeightLocal(virtualStyleSheet.getHeight() / 100f * this.getParent().getBounds() .getHeightXY(TransformSpace.RELATIVE_TO_PARENT)); } else { if (virtualStyleSheet.getWidth() > 0) this.setWidthLocal(virtualStyleSheet.getWidth()); if (virtualStyleSheet.getHeight() > 0) this.setHeightLocal(virtualStyleSheet.getHeight()); } } }