
com.threerings.miso.client.SceneObject Maven / Gradle / Ivy
//
// Nenya library - tools for developing networked games
// Copyright (C) 2002-2012 Three Rings Design, Inc., All Rights Reserved
// https://github.com/threerings/nenya
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.miso.client;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Polygon;
import java.awt.Rectangle;
import com.samskivert.util.StringUtil;
import com.samskivert.swing.RuntimeAdjust;
import com.threerings.media.tile.NoSuchTileSetException;
import com.threerings.media.tile.ObjectTile;
import com.threerings.media.tile.TileManager;
import com.threerings.media.tile.TileUtil;
import com.threerings.media.tile.TileSet.Colorizer;
import com.threerings.miso.MisoPrefs;
import com.threerings.miso.data.ObjectInfo;
import com.threerings.miso.util.MisoSceneMetrics;
import com.threerings.miso.util.MisoUtil;
import static com.threerings.miso.Log.log;
/**
* Contains resolved information on an object in a scene.
*/
public class SceneObject
{
/** The object's info record. */
public ObjectInfo info;
/** The object tile used to display this object. */
public ObjectTile tile;
/** The screen coordinate bounds of our object tile given its position
* in the scene. */
public Rectangle bounds;
/**
* Creates a scene object for display by the specified panel. The appropriate object tile is
* resolved and the object's in-situ bounds are computed.
*/
public SceneObject (MisoScenePanel panel, ObjectInfo info)
{
this(panel.getSceneMetrics(), panel.getTileManager(), panel.getColorizer(info), info);
}
public SceneObject (MisoSceneMetrics metrics, TileManager mgr, Colorizer colorizer,
ObjectInfo info)
{
this.info = info;
// resolve our object tile
refreshObjectTile(metrics, mgr, colorizer);
}
/**
* Creates a scene object for display by the specified panel.
*/
public SceneObject (MisoScenePanel panel, ObjectInfo info, ObjectTile tile)
{
this(panel.getSceneMetrics(), info, tile);
}
/**
* Creates a scene object for display according to the supplied metrics.
*/
public SceneObject (
MisoSceneMetrics metrics, ObjectInfo info, ObjectTile tile)
{
this.info = info;
this.tile = tile;
computeInfo(metrics);
}
/**
* Used to flag overlapping scene objects that have no resolving
* object priorities.
*/
public void setWarning (boolean warning)
{
_warning = warning;
}
/**
* Requests that this scene object render itself.
*/
public void paint (Graphics2D gfx)
{
// if we're rendering footprints, paint that
boolean footpaint = _fprintDebug.getValue();
if (footpaint) {
gfx.setColor(Color.black);
gfx.draw(_footprint);
if (_hideObjects.getValue()) {
// We're in footprints but no objects mode, so let's also fill it in so we can
// see things better/tell if we have overlapping ones
Composite ocomp = gfx.getComposite();
gfx.setComposite(ALPHA_WARN);
gfx.fill(_footprint);
gfx.setComposite(ocomp);
}
}
if (_hideObjects.getValue()) {
return;
}
// if we have a warning, render an alpha'd red rectangle over our bounds
if (_warning) {
Composite ocomp = gfx.getComposite();
gfx.setComposite(ALPHA_WARN);
gfx.fill(bounds);
gfx.setComposite(ocomp);
}
// paint our tile
tile.paint(gfx, bounds.x, bounds.y);
// and possibly paint the object's spot
if (footpaint && _sspot != null) {
// translate the origin to center on the portal
gfx.translate(_sspot.x, _sspot.y);
// rotate to reflect the spot orientation
double rot = (Math.PI / 4.0f) * tile.getSpotOrient();
gfx.rotate(rot);
// draw the spot triangle
gfx.setColor(Color.green);
gfx.fill(_spotTri);
// outline the triangle in black
gfx.setColor(Color.black);
gfx.draw(_spotTri);
// restore the original transform
gfx.rotate(-rot);
gfx.translate(-_sspot.x, -_sspot.y);
}
}
/**
* Returns the location associated with this object's "spot" in fine
* coordinates or null if it has no spot.
*/
public Point getObjectSpot ()
{
return _fspot;
}
/**
* Returns the location associated with this object's "spot" in screen
* coordinates or null if it has no spot.
*/
public Point getObjectScreenSpot ()
{
return _sspot;
}
/**
* Returns true if this object's footprint overlaps that of the
* specified other object.
*/
public boolean objectFootprintOverlaps (SceneObject so)
{
return _frect.intersects(so._frect);
}
/**
* Returns true if this object's footprint overlaps the supplied tile
* coordinate rectangle.
*/
public boolean objectFootprintOverlaps (Rectangle rect)
{
return _frect.intersects(rect);
}
/**
* Returns a polygon bounding all footprint tiles of this scene
* object.
*
* @return the bounding polygon.
*/
public Polygon getObjectFootprint ()
{
return _footprint;
}
/**
* Returns the render priority of this scene object.
*/
public int getPriority ()
{
// if we have no overridden priority, return our object tile's
// default priority
return (info.priority == 0 && tile != null) ?
tile.getPriority() : info.priority;
}
/**
* Overrides the render priority of this object.
*/
public void setPriority (byte priority)
{
info.priority = (byte)Math.max(
Byte.MIN_VALUE, Math.min(Byte.MAX_VALUE, priority));
}
/**
* Informs this scene object that the mouse is now hovering over it.
* Custom objects may wish to adjust some internal state and return
* true from this method indicating that they should be repainted.
*/
public boolean setHovered (boolean hovered)
{
return false;
}
/**
* Updates this object's origin tile coordinate. Its bounds and other
* cached screen coordinate information are updated.
*/
public void relocateObject (MisoSceneMetrics metrics, int tx, int ty)
{
// Log.info("Relocating object " + this + " to " +
// StringUtil.coordsToString(tx, ty));
info.x = tx;
info.y = ty;
computeInfo(metrics);
}
/**
* Reloads and recolorizes our object tile. It is not intended for the actual object tile used
* by a scene object to change in its lifetime, only attributes of that object like its
* colorizations. So don't do anything crazy like change our {@link ObjectInfo}'s
* tileId
and call this method or things might break.
*/
public void refreshObjectTile (MisoScenePanel panel)
{
refreshObjectTile(panel.getSceneMetrics(), panel.getTileManager(),
panel.getColorizer(info));
}
/**
* Reloads and recolorizes our object tile. It is not intended for the actual object tile used
* by a scene object to change in its lifetime, only attributes of that object like its
* colorizations. So don't do anything crazy like change our {@link ObjectInfo}'s
* tileId
and call this method or things might break.
*/
public void refreshObjectTile (MisoSceneMetrics metrics, TileManager mgr, Colorizer colorizer)
{
int tsid = TileUtil.getTileSetId(info.tileId);
int tidx = TileUtil.getTileIndex(info.tileId);
try {
tile = (ObjectTile)mgr.getTile(tsid, tidx, colorizer);
computeInfo(metrics);
} catch (NoSuchTileSetException te) {
log.warning("Scene contains non-existent object tileset [info=" + info + "].");
}
}
/**
* Computes our screen bounds, tile footprint and other useful cached metrics.
*/
protected void computeInfo (MisoSceneMetrics metrics)
{
// start with the screen coordinates of our origin tile
Point tpos = MisoUtil.tileToScreen(
metrics, info.x, info.y, new Point());
// if the tile has an origin coordinate, use that, otherwise
// compute it from the tile footprint
int tox = tile.getOriginX(), toy = tile.getOriginY();
if (tox == Integer.MIN_VALUE) {
tox = tile.getBaseWidth() * metrics.tilehwid;
}
if (toy == Integer.MIN_VALUE) {
toy = tile.getHeight();
}
bounds = new Rectangle(tpos.x + metrics.tilehwid - tox,
tpos.y + metrics.tilehei - toy,
tile.getWidth(), tile.getHeight());
// compute our object footprint as well
_frect = new Rectangle(info.x - tile.getBaseWidth() + 1,
info.y - tile.getBaseHeight() + 1,
tile.getBaseWidth(), tile.getBaseHeight());
_footprint = MisoUtil.getFootprintPolygon(
metrics, _frect.x, _frect.y, _frect.width, _frect.height);
// compute our object spot if we've got one
if (tile.hasSpot()) {
_fspot = MisoUtil.tilePlusFineToFull(
metrics, info.x, info.y, tile.getSpotX(), tile.getSpotY(),
new Point());
_sspot = MisoUtil.fullToScreen(
metrics, _fspot.x, _fspot.y, new Point());
}
// Log.info("Computed object metrics " +
// "[tpos=" + StringUtil.coordsToString(tx, ty) +
// ", info=" + info +
// ", sbounds=" + StringUtil.toString(bounds) + "].");
}
@Override
public String toString ()
{
return info + "[" + StringUtil.toString(bounds) + "]";
}
/** Our object as a tile coordinate rectangle. */
protected Rectangle _frect;
/** Our object footprint as a polygon. */
protected Polygon _footprint;
/** The full-coordinates of our object spot; or null if we have none. */
protected Point _fspot;
/** The screen-coordinates of our object spot; or null if we have none. */
protected Point _sspot;
/** Used to mark objects with errors. */
protected boolean _warning;
/** A debug hook that toggles rendering of objects. */
protected static RuntimeAdjust.BooleanAdjust _hideObjects =
new RuntimeAdjust.BooleanAdjust(
"Toggles rendering of objects in the scene view.",
"narya.miso.hide_objects", MisoPrefs.config, false);
/** A debug hook that toggles rendering of object footprints. */
protected static RuntimeAdjust.BooleanAdjust _fprintDebug =
new RuntimeAdjust.BooleanAdjust(
"Toggles rendering of object footprints in the scene view.",
"narya.miso.iso_fprint_debug_render", MisoPrefs.config, false);
/** The triangle used to render an object's spot. */
protected static Polygon _spotTri;
static {
_spotTri = new Polygon();
_spotTri.addPoint(-3, -3);
_spotTri.addPoint(3, -3);
_spotTri.addPoint(0, 3);
}
/** The alpha used to fill our bounds for warning purposes. */
protected static final Composite ALPHA_WARN =
AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f);
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy