Major low-level rendering rethink.

git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1287 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2002-04-23 01:18:17 +00:00
parent cc6a9d00ef
commit 0bde11ee81
5 changed files with 148 additions and 224 deletions
@@ -1,11 +1,13 @@
//
// $Id: BuilderPanel.java,v 1.5 2001/11/27 08:09:35 mdb Exp $
// $Id: BuilderPanel.java,v 1.6 2002/04/23 01:17:28 mdb Exp $
package com.threerings.cast.builder;
import javax.swing.*;
import com.samskivert.swing.*;
import com.threerings.media.FrameManager;
import com.threerings.cast.CharacterManager;
import com.threerings.cast.ComponentRepository;
@@ -19,7 +21,8 @@ public class BuilderPanel extends JPanel
/**
* Constructs the builder panel.
*/
public BuilderPanel (CharacterManager charmgr, ComponentRepository crepo)
public BuilderPanel (FrameManager framemgr, CharacterManager charmgr,
ComponentRepository crepo)
{
setLayout(new VGroupLayout());
@@ -35,7 +38,7 @@ public class BuilderPanel extends JPanel
// create the component selection and sprite display panels
JPanel sub = new JPanel(gl);
sub.add(new ComponentPanel(model));
sub.add(new SpritePanel(charmgr, model));
sub.add(new SpritePanel(framemgr, charmgr, model));
add(sub);
}
}
@@ -1,5 +1,5 @@
//
// $Id: SpritePanel.java,v 1.12 2002/03/16 03:15:04 shaper Exp $
// $Id: SpritePanel.java,v 1.13 2002/04/23 01:17:28 mdb Exp $
package com.threerings.cast.builder;
@@ -11,9 +11,8 @@ import java.awt.Rectangle;
import java.util.List;
import com.threerings.media.animation.AnimatedPanel;
import com.threerings.media.animation.AnimationManager;
import com.threerings.media.sprite.SpriteManager;
import com.threerings.media.FrameManager;
import com.threerings.media.MediaPanel;
import com.threerings.util.DirectionCodes;
@@ -27,29 +26,28 @@ import com.threerings.cast.StandardActions;
* The sprite panel displays a character sprite centered in the panel
* suitable for user perusal.
*/
public class SpritePanel extends AnimatedPanel
public class SpritePanel extends MediaPanel
implements DirectionCodes, BuilderModelListener
{
/**
* Constructs the sprite panel.
*/
public SpritePanel (CharacterManager charmgr, BuilderModel model)
public SpritePanel (FrameManager framemgr, CharacterManager charmgr,
BuilderModel model)
{
super(framemgr);
// save off references
_charmgr = charmgr;
_model = model;
// create managers
_spritemgr = new SpriteManager();
_animmgr = new AnimationManager(_spritemgr, this);
// listen to the builder model so that we can update the
// sprite when a new component is selected
_model.addListener(this);
}
// documentation inherited
protected void render (Graphics2D gfx, List invalidRects)
protected void paintMiddle (Graphics2D gfx, List invalidRects)
{
// clear the background
gfx.setColor(Color.lightGray);
@@ -122,12 +120,6 @@ public class SpritePanel extends AnimatedPanel
/** The sprite displayed by the panel. */
protected CharacterSprite _sprite;
/** The animation manager. */
protected AnimationManager _animmgr;
/** The sprite manager. */
protected SpriteManager _spritemgr;
/** The character manager. */
protected CharacterManager _charmgr;
@@ -1,5 +1,5 @@
//
// $Id: IsoSceneView.java,v 1.105 2002/04/02 01:06:46 mdb Exp $
// $Id: IsoSceneView.java,v 1.106 2002/04/23 01:18:17 mdb Exp $
package com.threerings.miso.scene;
@@ -24,7 +24,8 @@ import java.util.List;
import com.samskivert.util.StringUtil;
import com.samskivert.util.HashIntMap;
import com.threerings.media.animation.AnimationManager;
import com.threerings.media.RegionManager;
import com.threerings.media.sprite.Path;
import com.threerings.media.sprite.SpriteManager;
@@ -64,17 +65,18 @@ public class IsoSceneView implements SceneView
/**
* Constructs an iso scene view.
*
* @param animmgr the animation manager.
* @param spritemgr the sprite manager.
* @param model the data model.
* @param remgr the region manager that is collecting invalid regions
* for this view.
*/
public IsoSceneView (AnimationManager animmgr, SpriteManager spritemgr,
IsoSceneViewModel model)
public IsoSceneView (SpriteManager spritemgr, IsoSceneViewModel model,
RegionManager remgr)
{
// save off references
_animmgr = animmgr;
_spritemgr = spritemgr;
_model = model;
_remgr = remgr;
// create our polygon arrays, these will be populated with the
// tile polygons as they are requested
@@ -111,9 +113,6 @@ public class IsoSceneView implements SceneView
{
_scene = scene;
// clear all dirty lists and tile array
clearDirtyRegions();
// obtain a list of the objects in the scene and generate records
// for each of them that contain precomputed metrics
prepareObjectList();
@@ -122,6 +121,14 @@ public class IsoSceneView implements SceneView
invalidate();
}
/**
* Invalidate the entire visible scene view.
*/
public void invalidate ()
{
_remgr.invalidateRegion(_model.bounds);
}
// documentation inherited from interface
public void viewWillScroll (int dx, int dy)
{
@@ -155,44 +162,48 @@ public class IsoSceneView implements SceneView
}
// documentation inherited from interface
public void paint (Graphics2D gfx, List invalidRects)
public void paint (Graphics2D gfx, Rectangle[] dirtyRects)
{
if (_scene == null) {
Log.warning("Scene view painted with null scene.");
return;
}
// invalidate the invalid rectangles
int rsize = invalidRects.size();
for (int ii = 0; ii < rsize; ii++) {
invalidateRect((Rectangle)invalidRects.get(ii));
}
// Log.info("Rendering: " + StringUtil.toString(dirtyRects) +
// ", clip: " + StringUtil.toString(gfx.getClip()));
// // invalidate the invalid rectangles
// int rsize = dirtyRects.length;
// for (int ii = 0; ii < rsize; ii++) {
// invalidateRect(dirtyRects[ii]);
// }
// translate according to our scroll parameters
gfx.translate(-_xoff, -_yoff);
// render the scrolling part of the scene
renderScrollingScene(gfx);
// draw tile coordinates
if (_model.showCoords) {
paintCoordinates(gfx);
int rcount = dirtyRects.length;
for (int ii = 0; ii < rcount; ii++) {
Rectangle rect = dirtyRects[ii];
rect.translate(_xoff, _yoff);
Shape oclip = gfx.getClip();
gfx.clipRect(rect.x, rect.y, rect.width, rect.height);
renderScrollingScene(gfx, rect);
gfx.setClip(oclip);
rect.translate(-_xoff, -_yoff);
}
// untranslate according to our scroll parameters
gfx.translate(_xoff, _yoff);
// render the fixed part of the scene
renderFixedScene(gfx);
// draw frames of dirty tiles and rectangles
// drawDirtyRegions(gfx);
// render any animations
_animmgr.renderAnimations(gfx, AnimationManager.ALL);
// clear out the dirty tiles and rectangles
clearDirtyRegions();
for (int ii = 0; ii < rcount; ii++) {
Rectangle rect = dirtyRects[ii];
Shape oclip = gfx.getClip();
gfx.clipRect(rect.x, rect.y, rect.width, rect.height);
renderFixedScene(gfx, rect);
gfx.setClip(oclip);
}
// draw sprite paths
if (_model.showPaths) {
@@ -264,73 +275,19 @@ public class IsoSceneView implements SceneView
// nothing for now
}
/**
* Invalidate the entire visible scene view.
*/
protected void invalidate ()
{
invalidateRect(_model.bounds);
}
/**
* Clears the dirty rectangles and items lists, and the array of
* dirty tiles.
*/
protected void clearDirtyRegions ()
{
_dirtyRects.clear();
_dirtyItems.clear();
_numDirty = 0;
for (int xx = 0; xx < _model.scenewid; xx++) {
Arrays.fill(_dirty[xx], false);
}
}
/**
* Draws highlights around the dirty tiles and rectangles.
*/
protected void drawDirtyRegions (Graphics2D gfx)
{
// draw the dirty tiles
gfx.setColor(Color.cyan);
for (int xx = 0; xx < _model.scenewid; xx++) {
for (int yy = 0; yy < _model.scenehei; yy++) {
if (_dirty[xx][yy]) {
gfx.draw(getTilePoly(xx, yy));
}
}
}
// draw the dirty rectangles
Stroke ostroke = gfx.getStroke();
gfx.setStroke(DIRTY_RECT_STROKE);
gfx.setColor(Color.red);
int size = _dirtyRects.size();
for (int ii = 0; ii < size; ii++) {
Rectangle rect = (Rectangle)_dirtyRects.get(ii);
gfx.draw(rect);
}
gfx.setStroke(ostroke);
// draw the dirty item rectangles
gfx.setColor(Color.yellow);
size = _dirtyItems.size();
for (int ii = 0; ii < size; ii++) {
Rectangle rect = _dirtyItems.get(ii).dirtyRect;
gfx.draw(rect);
}
}
/**
* Renders the scrolling part of the scene to the given graphics
* context.
*
* @param gfx the graphics context.
*/
protected void renderScrollingScene (Graphics2D gfx)
protected void renderScrollingScene (Graphics2D gfx, Rectangle clip)
{
renderTiles(gfx);
renderBaseDecorations(gfx);
// render any intersecting tiles
renderTiles(gfx, clip);
// render anything that goes on top of the tiles
renderBaseDecorations(gfx, clip);
}
/**
@@ -339,21 +296,32 @@ public class IsoSceneView implements SceneView
*
* @param gfx the graphics context.
*/
protected void renderFixedScene (Graphics2D gfx)
protected void renderFixedScene (Graphics2D gfx, Rectangle clip)
{
renderDirtyItems(gfx);
renderDirtyItems(gfx, clip);
}
/**
* Renders the base and fringe layer tiles to the given graphics
* context.
* Renders the base and fringe layer tiles that intersect the
* specified clipping rectangle.
*/
protected void renderTiles (Graphics2D gfx)
protected void renderTiles (Graphics2D gfx, Rectangle clip)
{
// render the base and fringe layers
FontMetrics fm = gfx.getFontMetrics(_font);
int fhei = fm.getAscent();
int cx = _model.tilehwid, cy = _model.tilehhei;
if (_model.showCoords) {
gfx.setFont(_font);
gfx.setColor(Color.white);
}
for (int yy = 0; yy < _model.scenehei; yy++) {
for (int xx = 0; xx < _model.scenewid; xx++) {
if (!_dirty[xx][yy]) {
Polygon tpoly = getTilePoly(xx, yy);
// skip non-intersecting tiles
if (!tpoly.intersects(clip)) {
continue;
}
@@ -363,15 +331,30 @@ public class IsoSceneView implements SceneView
// draw the base and fringe tile images
Tile tile;
if ((tile = _scene.getBaseTile(tx, ty)) != null) {
tile.paint(gfx, getTilePoly(xx, yy));
tile.paint(gfx, tpoly);
}
if ((tile = _scene.getFringeTile(tx, ty)) != null) {
tile.paint(gfx, getTilePoly(xx, yy));
tile.paint(gfx, tpoly);
}
// if we're showing coordinates, outline the tiles as well
// if we're showing coordinates, do that
if (_model.showCoords) {
gfx.draw(getTilePoly(xx, yy));
// outline the tile
gfx.draw(tpoly);
// get the top-left screen coordinates of the tile
Rectangle bounds = tpoly.getBounds();
int sx = bounds.x, sy = bounds.y;
// draw x-coordinate
String str = String.valueOf(xx + _tiledx);
int xpos = sx + cx - (fm.stringWidth(str) / 2);
gfx.drawString(str, xpos, sy + cy);
// draw y-coordinate
str = String.valueOf(yy + _tiledy);
xpos = sx + cx - (fm.stringWidth(str) / 2);
gfx.drawString(str, xpos, sy + cy + fhei);
}
}
}
@@ -382,7 +365,7 @@ public class IsoSceneView implements SceneView
* tiles have been rendered but before anything else has been rendered
* (so that whatever is painted appears to be on the ground).
*/
protected void renderBaseDecorations (Graphics2D gfx)
protected void renderBaseDecorations (Graphics2D gfx, Rectangle clip)
{
// nothing for now
}
@@ -391,10 +374,11 @@ public class IsoSceneView implements SceneView
* Renders the dirty sprites and objects in the scene to the given
* graphics context.
*/
protected void renderDirtyItems (Graphics2D gfx)
protected void renderDirtyItems (Graphics2D gfx, Rectangle clip)
{
// Log.info("renderDirtyItems [rects=" + _dirtyRects.size() +
// ", items=" + _dirtyItems.size() + "].");
invalidateItems(clip);
// Log.info("renderDirtyItems [items=" + _dirtyItems.size() + "].");
// sort the dirty sprites and objects visually back-to-front
DirtyItem items[] = _dirtyItems.sort();
@@ -402,47 +386,10 @@ public class IsoSceneView implements SceneView
// render each item clipping to its dirty rectangle
for (int ii = 0; ii < items.length; ii++) {
items[ii].paint(gfx, items[ii].dirtyRect);
// Log.info("Painting item [item=" + items[ii] + "].");
// Log.info("Painting item [item=" + items[ii] + "].");
}
}
/**
* Paints tile coordinate numbers on all dirty tiles.
*
* @param gfx the graphics context.
*/
protected void paintCoordinates (Graphics2D gfx)
{
FontMetrics fm = gfx.getFontMetrics(_font);
gfx.setFont(_font);
gfx.setColor(Color.white);
int cx = _model.tilehwid, cy = _model.tilehhei;
int fhei = fm.getAscent();
for (int yy = 0; yy < _model.scenehei; yy++) {
for (int xx = 0; xx < _model.scenewid; xx++) {
// if the tile's not dirty, don't paint the coordinates
if (!_dirty[xx][yy]) {
continue;
}
// get the top-left screen coordinates of the tile
Rectangle bounds = getTilePoly(xx, yy).getBounds();
int sx = bounds.x, sy = bounds.y;
// draw x-coordinate
String str = String.valueOf(xx + _tiledx);
int xpos = sx + cx - (fm.stringWidth(str) / 2);
gfx.drawString(str, xpos, sy + cy);
// draw y-coordinate
str = String.valueOf(yy + _tiledy);
xpos = sx + cx - (fm.stringWidth(str) / 2);
gfx.drawString(str, xpos, sy + cy + fhei);
}
}
_dirtyItems.clear();
}
/**
@@ -513,23 +460,6 @@ public class IsoSceneView implements SceneView
return poly;
}
/**
* Invalidates the specified rectangle in preparation for
* rendering. Items that overlap the rectangle as well as tiles that
* overlap the rectangle will be marked as needing to be rerendered.
*/
protected void invalidateRect (Rectangle rect)
{
// dirty the tiles impacted by this rectangle
Rectangle tileBounds = invalidateScreenRect(rect);
// dirty any sprites or objects impacted by this rectangle
invalidateItems(tileBounds);
// save the rectangle for potential display later
_dirtyRects.add(rect);
}
/**
* Invalidates the given rectangle in screen pixel coordinates in the
* view. Returns a rectangle that bounds all tiles that were dirtied.
@@ -927,12 +857,12 @@ public class IsoSceneView implements SceneView
/** The sprite manager. */
protected SpriteManager _spritemgr;
/** The animation manager. */
protected AnimationManager _animmgr;
/** The scene view model data. */
protected IsoSceneViewModel _model;
/** Our region manager. */
protected RegionManager _remgr;
/** The scene to be displayed. */
protected DisplayMisoScene _scene;
@@ -955,9 +885,6 @@ public class IsoSceneView implements SceneView
/** The number of dirty tiles. */
protected int _numDirty;
/** The dirty rectangles that need to be re-painted. */
protected ArrayList _dirtyRects = new ArrayList();
/** The dirty sprites and objects that need to be re-painted. */
protected DirtyItemList _dirtyItems = new DirtyItemList();
@@ -1,5 +1,5 @@
//
// $Id: SceneView.java,v 1.26 2002/02/19 05:03:17 mdb Exp $
// $Id: SceneView.java,v 1.27 2002/04/23 01:18:17 mdb Exp $
package com.threerings.miso.scene;
@@ -7,7 +7,6 @@ import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.List;
import com.threerings.media.sprite.Path;
@@ -33,7 +32,7 @@ public interface SceneView
* @param gfx the graphics context.
* @param invalidRects the list of invalid regions to be repainted.
*/
public void paint (Graphics2D gfx, List invalidRects);
public void paint (Graphics2D gfx, Rectangle[] invalidRects);
/**
* Sets the scene that we're rendering.
@@ -1,11 +1,12 @@
//
// $Id: SceneViewPanel.java,v 1.38 2002/04/15 23:10:40 mdb Exp $
// $Id: SceneViewPanel.java,v 1.39 2002/04/23 01:18:17 mdb Exp $
package com.threerings.miso.scene;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
@@ -13,8 +14,10 @@ import java.awt.event.MouseMotionAdapter;
import java.util.List;
import com.threerings.media.animation.AnimatedPanel;
import com.threerings.media.animation.AnimationManager;
import com.threerings.media.FrameManager;
import com.threerings.media.MediaPanel;
import com.threerings.media.sprite.Sprite;
import com.threerings.media.sprite.SpriteManager;
import com.threerings.miso.Log;
@@ -25,14 +28,19 @@ import com.threerings.miso.scene.util.IsoUtil;
* SceneView}, rendering it to the screen, and handling view-related
* UI events.
*/
public class SceneViewPanel extends AnimatedPanel
public class SceneViewPanel extends MediaPanel
implements IsoSceneViewModelListener
{
/**
* Constructs the scene view panel with the supplied view model.
*/
public SceneViewPanel (IsoSceneViewModel model)
public SceneViewPanel (FrameManager framemgr, IsoSceneViewModel model)
{
super(framemgr);
// we're going to want to be opaque
setOpaque(true);
// create the data model for the scene view
_viewmodel = model;
@@ -41,7 +49,7 @@ public class SceneViewPanel extends AnimatedPanel
_viewmodel.addListener(this);
// create the scene view
_view = newSceneView(_animmgr, _spritemgr, _viewmodel);
_view = newSceneView(_spritemgr, _viewmodel);
// listen to mouse...
addMouseListener(new MouseAdapter() {
@@ -78,9 +86,9 @@ public class SceneViewPanel extends AnimatedPanel
* Constructs the underlying scene view implementation.
*/
protected SceneView newSceneView (
AnimationManager amgr, SpriteManager smgr, IsoSceneViewModel model)
SpriteManager smgr, IsoSceneViewModel model)
{
return new IsoSceneView(amgr, smgr, model);
return new IsoSceneView(smgr, model, _remgr);
}
/**
@@ -100,29 +108,24 @@ public class SceneViewPanel extends AnimatedPanel
}
/**
* Adds the supplied sprite to the scene.
* Adds the supplied sprite to the scene, setting up its scene
* coordinates if it is a {@link MisoCharacterSprite}.
*/
public void addSprite (MisoCharacterSprite sprite)
public void addSprite (Sprite sprite)
{
// set up the sprite's tile coordinates
IsoUtil.setSpriteSceneLocation(_viewmodel, sprite);
if (sprite instanceof MisoCharacterSprite) {
// set up the sprite's tile coordinates
IsoUtil.setSpriteSceneLocation(
_viewmodel, (MisoCharacterSprite)sprite);
}
// and add it to the sprite manager
_spritemgr.addSprite(sprite);
}
/**
* Removes the supplied sprite from the screen.
*/
public void removeSprite (MisoCharacterSprite sprite)
{
_spritemgr.removeSprite(sprite);
super.addSprite(sprite);
}
/**
* If we're scrolling, we need to pass the word on to our scene view.
*/
protected void viewWillScroll (int dx, int dy, long now, List invalidRects)
protected void viewWillScroll (int dx, int dy, long now)
{
_view.viewWillScroll(dx, dy);
}
@@ -159,23 +162,23 @@ public class SceneViewPanel extends AnimatedPanel
}
// documentation inherited
protected void render (Graphics2D gfx, List invalidRects)
protected void paintBetween (Graphics2D gfx, Rectangle[] dirtyRects)
{
// render the view
_view.paint(gfx, invalidRects);
// give derived classes a chance to render on top of the view
renderOnView(gfx, invalidRects);
// render the isometric view
_view.paint(gfx, dirtyRects);
}
/**
* Provides an opportunity for derived classes to render things while
* under the influence of the proper coordinate translations. This is
* called after the view is rendered, so things drawn here appear on
* top of the scene view.
* We don't want sprites rendered using the standard mechanism because
* we intersperse them with objects in our scene and need to manage
* their z-order.
*/
protected void renderOnView (Graphics2D gfx, List invalidRects)
protected void paintBits (Graphics2D gfx, int layer, Rectangle clip)
{
Shape oclip = gfx.getClip();
gfx.setClip(clip);
_animmgr.renderAnimations(gfx, layer, clip);
gfx.setClip(oclip);
}
/**