From 0bde11ee81abc1a57a460fc3e659f567e534d58e Mon Sep 17 00:00:00 2001 From: Michael Bayne Date: Tue, 23 Apr 2002 01:18:17 +0000 Subject: [PATCH] Major low-level rendering rethink. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@1287 542714f4-19e9-0310-aa3c-eee0fc999fb1 --- .../threerings/cast/builder/BuilderPanel.java | 9 +- .../threerings/cast/builder/SpritePanel.java | 26 +- .../threerings/miso/client/IsoSceneView.java | 261 +++++++----------- .../com/threerings/miso/client/SceneView.java | 5 +- .../miso/client/SceneViewPanel.java | 71 ++--- 5 files changed, 148 insertions(+), 224 deletions(-) diff --git a/src/java/com/threerings/cast/builder/BuilderPanel.java b/src/java/com/threerings/cast/builder/BuilderPanel.java index 1d82daecf..f5351eb5c 100644 --- a/src/java/com/threerings/cast/builder/BuilderPanel.java +++ b/src/java/com/threerings/cast/builder/BuilderPanel.java @@ -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); } } diff --git a/src/java/com/threerings/cast/builder/SpritePanel.java b/src/java/com/threerings/cast/builder/SpritePanel.java index e7e24edb6..11022b174 100644 --- a/src/java/com/threerings/cast/builder/SpritePanel.java +++ b/src/java/com/threerings/cast/builder/SpritePanel.java @@ -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; diff --git a/src/java/com/threerings/miso/client/IsoSceneView.java b/src/java/com/threerings/miso/client/IsoSceneView.java index dca31fbbc..171f428ad 100644 --- a/src/java/com/threerings/miso/client/IsoSceneView.java +++ b/src/java/com/threerings/miso/client/IsoSceneView.java @@ -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(); diff --git a/src/java/com/threerings/miso/client/SceneView.java b/src/java/com/threerings/miso/client/SceneView.java index 4a20e8cb2..3eb31131a 100644 --- a/src/java/com/threerings/miso/client/SceneView.java +++ b/src/java/com/threerings/miso/client/SceneView.java @@ -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. diff --git a/src/java/com/threerings/miso/client/SceneViewPanel.java b/src/java/com/threerings/miso/client/SceneViewPanel.java index 9aa5b19a2..c615f9ad1 100644 --- a/src/java/com/threerings/miso/client/SceneViewPanel.java +++ b/src/java/com/threerings/miso/client/SceneViewPanel.java @@ -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); } /**