package NET.worlds.scape; import NET.worlds.console.Console; import NET.worlds.console.DefaultConsole; import java.io.IOException; public class Rect extends Surface implements MouseDownHandler, FrameHandler, Prerenderable { static BumpCalc standardPlaneBumpCalc = new PlaneBumpCalc(); Billboard _billboardAttribute = null; VideoTexture _videoAttribute = null; boolean visible = false; protected float u = 1.0F; protected float v = 1.0F; protected float uOff; protected float vOff; private static Object classCookie = new Object(); static { standardPlaneBumpCalc.setName("defaultPlaneBumpCalc"); } public Rect(float w, float h, Material material) { super(material); this.scale(w, h, h); } public Rect(float x, float y, float z, Material material) { super(material); this.setFarCorner(Point3Temp.make(x, y, z)); } public Rect(float llx, float lly, float llz, float urx, float ury, float urz, Material material) { super(material); this.moveBy(llx, lly, llz); this.setFarCorner(Point3Temp.make(urx, ury, urz)); } public Rect(Point3Temp llc, Point3Temp urc, Material material) { this(llc.x, llc.y, llc.z, urc.x, urc.y, urc.z, material); } Rect() { } public static boolean setFarCornerHelper(Transform t, Point3Temp newCorner) { t.scale(1.0F / t.getScaleX(), 1.0F / t.getScaleY(), 1.0F / t.getScaleZ()); Point3Temp lookRight = Point3Temp.make(1.0F, 0.0F, 0.0F).vectorTimes(t); Point3Temp lookOut = Point3Temp.make(0.0F, 1.0F, 0.0F).vectorTimes(t); Point3Temp lookUp = Point3Temp.make(0.0F, 0.0F, 1.0F).vectorTimes(t); Point3Temp newEndOffset = Point3Temp.make(newCorner).minus(t.getPosition()); float x = newEndOffset.dot(lookRight); float y = newEndOffset.dot(lookOut); float z = newEndOffset.dot(lookUp); if (!(z >= 0.0F)) { return false; } else { if (x != 0.0F || y != 0.0F) { t.spin(0.0F, 0.0F, 1.0F, (float)(Math.atan2(y, x) * 180.0 / Math.PI)); } t.scale((float)Math.sqrt(x * x + y * y), z, z); return true; } } public boolean setFarCorner(Point3Temp newCorner) { Transform t = this.getTransform(); if (setFarCornerHelper(t, newCorner)) { this.setTransform(t); t.recycle(); return true; } else { t.recycle(); Console.println(Console.message("cant-rot-rect")); return false; } } public Point3Temp getFarCorner() { Point3Temp ret = Point3Temp.make(1.0F, 0.0F, 1.0F); if (this.hasClump()) { Transform t = this.getObjectToWorldMatrix(); ret.times(t); t.recycle(); } else { ret.times(this); } return ret; } public Point3Temp getFarCornerLocal() { Point3Temp ret = Point3Temp.make(1.0F, 0.0F, 1.0F); if (this.hasClump()) { Transform t = this.getTransform(); ret.times(t); t.recycle(); } else { ret.times(this); } return ret; } public void setNearCorner(Point3Temp from) { Point3Temp oldEnd = this.getFarCornerLocal(); Point3Temp oldStart = this.getPosition(); this.moveTo(from); if (!this.setFarCorner(oldEnd)) { this.moveTo(oldStart); } } @Override public Point3Temp getPlaneExtent() { return Point3Temp.make(1.0F, 0.0F, 1.0F); } @Override public BumpCalc getBumpCalc(BumpEventTemp b) { return this.bumpCalc == null ? standardPlaneBumpCalc : this.bumpCalc; } public Point2 getTileSize() { return new Point2(this.u != 1.0F ? this.getScaleX() / this.u : 0.0F, this.v != 1.0F ? this.getScaleZ() / this.v : 0.0F); } void setUV(float u, float v) { this.setTileSize(this.getScaleX() / u, this.getScaleZ() / v); } public Rect setTileSize(float tx, float ty) { this.u = tx == 0.0F ? 1.0F : this.getScaleX() / tx; this.v = ty == 0.0F ? 1.0F : this.getScaleZ() / ty; this.reclump(); return this; } public void setTileOffset(Point2 p) { this.uOff = this.getScaleX() == 0.0F ? 0.0F : p.x / this.getScaleX(); this.vOff = this.getScaleZ() == 0.0F ? 0.0F : p.y / this.getScaleZ(); this.reclump(); } public Point2 getTileOffset() { return new Point2(this.uOff * this.getScaleX(), this.vOff * this.getScaleZ()); } public static Rect floor(float x, float y, Material m) { return (Rect)new Rect(x, y, m).setBumpable(false).postspin(1.0F, 0.0F, 0.0F, -90.0F); } public static Rect floor(float llx, float lly, float z, float urx, float ury, Material m) { return (Rect)floor(urx - llx, ury - lly, m).moveBy(llx, lly, z); } public static Rect ceiling(float x, float y, Material m) { return (Rect)new Rect(x, y, m).setBumpable(false).postspin(1.0F, 0.0F, 0.0F, 90.0F).moveBy(0.0F, y, 0.0F); } public static Rect ceiling(float llx, float lly, float z, float urx, float ury, Material m) { return (Rect)ceiling(urx - llx, ury - lly, m).moveBy(llx, lly, z); } public Rect hang(float pllx, float pllz, float purx, float purz, Material pic) { Rect r = (Rect)new Rect((purx - pllx) / this.getScaleX(), (purz - pllz) / this.getScaleZ(), pic) .moveBy(pllx / this.getScaleX(), 0.0F, pllz / this.getScaleZ()) .post(this); return (Rect)r.premoveBy(0.0F, -1.0F / r.getScale().length(), 0.0F); } public VideoTexture getVideoAttribute() { return this._videoAttribute; } public Billboard getBillboardAttribute() { return this._billboardAttribute; } @Override public boolean handle(MouseDownEvent event) { if (this._billboardAttribute != null && (event.key & 1) == 1) { Point2 pt = this.deproject(); this._billboardAttribute.billboardClicked(pt); } return false; } @Override public boolean handle(FrameEvent f) { if (this._billboardAttribute != null && this.getVisible() && this.visible) { this._billboardAttribute.billboardFrame(f); } if (this._videoAttribute != null && this.getVisible() && this.visible) { this._videoAttribute.videoFrame(f); } this.visible = false; return false; } @Override public void prerender(Camera cam) { if (this._billboardAttribute != null || this._videoAttribute != null) { Point3Temp p = this.inCamSpace(cam); boolean v = p != null && p.z > 1.0F && p.x < p.z && -p.x < p.z; if (v) { this.visible = true; } } } protected Point2 deproject() { Console c = Console.getActive(); if (c instanceof DefaultConsole) { DefaultConsole dc = (DefaultConsole)c; Point3Temp worldClick = dc.getRender().getCamera().lastPickSpot(); Point3Temp vWorld = Point3Temp.make(worldClick); vWorld.minus(this.getObjectToWorldMatrix().getPosition()); Transform inv = this.getObjectToWorldMatrix().invert(); Point3Temp vObj = Point3Temp.make(vWorld).vectorTimes(inv); inv.recycle(); Point2 rectPt = new Point2(); rectPt.set(vObj.x, vObj.z); return rectPt; } else { return new Point2(-1.0F, -1.0F); } } @Override protected void addRwChildren(WObject container) { this.addNewRwChild(container); float uo = this.uOff; if (uo != 0.0F) { uo *= this.u; uo = (float)(uo - 2.0 * Math.floor(uo / 2.0F)); } float vo = this.vOff; if (vo != 0.0F) { vo *= this.v; vo = (float)(vo - 2.0 * Math.floor(vo / 2.0F)); } this.addVertex(0.0F, 0.0F, 0.0F, uo, this.v + vo); this.addVertex(1.0F, 0.0F, 0.0F, this.u + uo, this.v + vo); this.addVertex(1.0F, 0.0F, 1.0F, this.u + uo, vo); this.addVertex(0.0F, 0.0F, 1.0F, uo, vo); this.doneWithEditing(); if (!(this instanceof Portal)) { this.getRoom().addPrerenderHandler(this); } } @Override protected void markVoid() { if (!(this instanceof Portal)) { this.getRoom().removePrerenderHandler(this); } super.markVoid(); } @Override public Object properties(int index, int offset, int mode, Object value) throws NoSuchPropertyException { Object ret = null; switch (index - offset) { case 0: if (mode == 0) { ret = Point2PropertyEditor.make(new Property(this, index, "Tile Size")); } else if (mode == 1) { ret = this.getTileSize(); } else if (mode == 2) { Point2 p = (Point2)value; if (!(p.x < 0.0F) && !(p.y < 0.0F)) { this.setTileSize(p.x, p.y); } else { Console.println(Console.message("Tile-size")); } } break; case 1: if (mode == 0) { ret = Point2PropertyEditor.make(new Property(this, index, "Tile Origin")); } else if (mode == 1) { ret = this.getTileOffset(); } else if (mode == 2) { this.setTileOffset((Point2)value); } break; case 2: if (mode == 0) { ret = Point3PropertyEditor.make(new Property(this, index, "From")); } else if (mode == 1) { ret = new Point3(this.getPosition()); } else if (mode == 2) { this.setNearCorner((Point3)value); } break; case 3: if (mode == 0) { ret = Point3PropertyEditor.make(new Property(this, index, "To")); } else if (mode == 1) { ret = new Point3(this.getFarCornerLocal()); } else if (mode == 2) { this.setFarCorner((Point3)value); } break; case 4: if (mode == 0) { ret = Point2PropertyEditor.make(new Property(this, index, "Extent")); } else if (mode == 1) { ret = new Point2(this.getScaleX(), this.getScaleZ()); } else if (mode == 2) { float zScale = ((Point2)value).y / this.getScaleZ(); this.scale(((Point2)value).x / this.getScaleX(), zScale, zScale); } break; case 5: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Flip Alternate U"), "No", "Yes"); } else if (mode == 1) { ret = new Boolean(this.getUFlip()); } else if (mode == 2) { this.setUFlip((Boolean)value); this.reclump(); } break; case 6: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Flip Alternate V"), "No", "Yes"); } else if (mode == 1) { ret = new Boolean(this.getVFlip()); } else if (mode == 2) { this.setVFlip((Boolean)value); this.reclump(); } break; case 7: if (mode == 0) { ret = BooleanPropertyEditor.make(new Property(this, index, "Unused"), "No", "Yes"); } else if (mode == 1) { ret = new Boolean(this.getMouseOver()); } else if (mode == 2) { this.setMouseOver((Boolean)value); } break; default: ret = super.properties(index, offset + 8, mode, value); } return ret; } @Override public void saveState(Saver s) throws IOException { s.saveVersion(4, classCookie); super.saveState(s); s.saveFloat(this.u); s.saveFloat(this.v); s.saveFloat(this.uOff); s.saveFloat(this.vOff); s.saveBoolean(false); } @Override public void restoreState(Restorer r) throws IOException, TooNewException { int vers = r.restoreVersion(classCookie); switch (vers) { case 0: case 1: super.restoreState(r); float x = r.restoreFloat(); float y = r.restoreFloat(); float z = r.restoreFloat(); r.restoreFloat(); r.restoreFloat(); r.restoreFloat(); this.u = r.restoreFloat(); this.v = r.restoreFloat(); this.spin(0.0F, 0.0F, 1.0F, (float)(Math.atan2(y, x) * 180.0 / Math.PI)); this.scale((float)Math.sqrt(x * x + y * y), z, z); break; case 2: super.restoreState(r); this.u = r.restoreFloat(); this.v = r.restoreFloat(); break; case 3: super.restoreState(r); this.u = r.restoreFloat(); this.v = r.restoreFloat(); this.uOff = r.restoreFloat(); this.vOff = r.restoreFloat(); break; case 4: super.restoreState(r); this.u = r.restoreFloat(); this.v = r.restoreFloat(); this.uOff = r.restoreFloat(); this.vOff = r.restoreFloat(); r.restoreBoolean(); break; default: throw new TooNewException(); } } @Override public String toString() { return super.toString() + "[" + this.getPosition() + "->" + this.getFarCornerLocal() + "]"; } @Override public boolean acceptsLeftClicks() { return this._billboardAttribute != null && this._billboardAttribute.getIsAdBanner() ? true : this.getMouseOver(); } }