Work on dirty-tile rendering optimization. Added placeholder panels

to the viewer.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@187 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Walter Korman
2001-08-07 18:29:18 +00:00
parent c09986bab0
commit b3e7f12f08
10 changed files with 264 additions and 44 deletions
@@ -1,5 +1,5 @@
//
// $Id: AnimationManager.java,v 1.7 2001/08/06 18:57:39 shaper Exp $
// $Id: AnimationManager.java,v 1.8 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.sprite;
@@ -99,13 +99,17 @@ public class AnimationManager implements Interval, PerformanceObserver
// invalidate screen-rects dirtied by sprites
ArrayList rects = _spritemgr.getDirtyRects();
_view.invalidateRects(rects);
// update frame-rate information
PerformanceMonitor.tick(AnimationManager.this, "refresh");
if (rects.size() > 0) {
// pass the dirty-rects on to the scene view
_view.invalidateRects(rects);
// refresh the display
_target.paintImmediately(_target.getBounds());
}
// update refresh-rate information
//PerformanceMonitor.tick(AnimationManager.this, "refresh");
if (finishedTick()) {
// finishedTick returning true means there's been a
@@ -1,5 +1,5 @@
//
// $Id: Sprite.java,v 1.7 2001/08/04 00:36:33 shaper Exp $
// $Id: Sprite.java,v 1.8 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.sprite;
@@ -187,8 +187,10 @@ public class Sprite
Rectangle dirty = new Rectangle(
_drawx, _drawy, _curTile.width, _curTile.height);
// Log.info("Sprite invalidate [x=" + dirty.x + ", y=" + dirty.y +
// ", width=" + dirty.width + ", height=" + dirty.height + "].");
// Log.info("Sprite invalidate [x=" + x + ", y=" + y +
// ", dx=" + dirty.x + ", dy=" + dirty.y +
// ", dwidth=" + dirty.width +
// ", dheight=" + dirty.height + "].");
_spritemgr.addDirtyRect(dirty);
}
@@ -221,6 +223,9 @@ public class Sprite
*/
protected void handleMove ()
{
// dirty our rectangle since we're going to move
invalidate();
// move the sprite incrementally toward its goal
x = (int)(_movex += _incx);
y = (int)(_movey += _incy);
@@ -233,14 +238,15 @@ public class Sprite
x = _dest.loc.x;
y = _dest.loc.y;
// dirty our rectangle since we've moved
invalidate();
// move further along the path if necessary
moveAlongPath();
}
// update the draw coordinates to reflect our new position
updateDrawPosition();
// dirty our rectangle in the new position
invalidate();
}
/**
@@ -1,5 +1,5 @@
//
// $Id: IsoSceneView.java,v 1.26 2001/08/06 18:57:39 shaper Exp $
// $Id: IsoSceneView.java,v 1.27 2001/08/07 18:29:17 shaper Exp $
package com.threerings.miso.scene;
@@ -39,8 +39,9 @@ public class IsoSceneView implements EditableSceneView
// get the font used to render tile coordinates
_font = new Font("Arial", Font.PLAIN, 7);
// create the list of dirty rectangles
// create the lists of dirty tiles and rectangles
_dirty = new ArrayList();
_dirtyRects = new ArrayList();
}
/**
@@ -63,6 +64,7 @@ public class IsoSceneView implements EditableSceneView
// draw the full scene into the offscreen image buffer
//renderSceneInvalid(gfx);
renderScene(gfx);
drawDirtyRects(gfx);
// draw an outline around the highlighted tile
paintHighlightedTile(gfx, _htile.x, _htile.y);
@@ -74,6 +76,25 @@ public class IsoSceneView implements EditableSceneView
gfx.setClip(oldclip);
}
protected void drawDirtyRects (Graphics2D gfx)
{
// draw the dirty tiles
gfx.setColor(Color.cyan);
int size = _dirty.size();
for (int ii = 0; ii < size; ii++) {
int dinfo[] = (int[])_dirty.remove(0);
gfx.draw(getTilePolygon(dinfo[0], dinfo[1]));
}
// draw the dirty rectangles
gfx.setColor(Color.red);
size = _dirtyRects.size();
for (int ii = 0; ii < size; ii++) {
Rectangle rect = (Rectangle)_dirtyRects.remove(0);
gfx.draw(rect);
}
}
/**
* Render the scene to the given graphics context.
*
@@ -208,12 +229,13 @@ public class IsoSceneView implements EditableSceneView
*/
protected void paintMouseLines (Graphics2D gfx)
{
Point[] lx = _model.lineX, ly = _model.lineY;
Point[] lx = _model.lineX;
// draw the baseline x-axis line
gfx.setColor(Color.red);
gfx.drawLine(lx[0].x, lx[0].y, lx[1].x, lx[1].y);
/*
// draw line from last mouse pos to baseline
gfx.setColor(Color.yellow);
gfx.drawLine(ly[0].x, ly[0].y, ly[1].x, ly[1].y);
@@ -223,6 +245,7 @@ public class IsoSceneView implements EditableSceneView
gfx.fillRect(ly[0].x, ly[0].y, 2, 2);
gfx.setColor(Color.red);
gfx.drawRect(ly[0].x - 1, ly[0].y - 1, 3, 3);
*/
}
/**
@@ -247,11 +270,11 @@ public class IsoSceneView implements EditableSceneView
// draw x-coordinate
String str = "" + x;
gfx.drawString(str, sx + cx - fm.stringWidth(str), sy + cy);
gfx.drawString(str, sx + cx - (fm.stringWidth(str)/2), sy + cy);
// draw y-coordinate
str = "" + y;
gfx.drawString(str, sx + cx - fm.stringWidth(str), sy + cy + fhei);
gfx.drawString(str, sx + cx - (fm.stringWidth(str)/2), sy + cy + fhei);
}
/**
@@ -290,7 +313,12 @@ public class IsoSceneView implements EditableSceneView
int size = rects.size();
for (int ii = 0; ii < size; ii++) {
Rectangle r = (Rectangle)rects.get(ii);
// dirty the tiles impacted by this rectangle
invalidateScreenRect(r.x, r.y, r.width, r.height);
// save the rectangle for potential display later
_dirtyRects.add(r);
}
}
@@ -305,15 +333,91 @@ public class IsoSceneView implements EditableSceneView
*/
public void invalidateScreenRect (int x, int y, int width, int height)
{
// TODO: fix boundary conditions, store contiguous dirty tile
// row segments rather than individual tiles, use specialized
// data structure rather than allocating int[] every time.
// note that corner tiles may be included unnecessarily, but
// checking to determine whether they're actually needed
// complicates the code with likely-insufficient benefit
// determine the top-left tile impacted by this rect
Point tpos = new Point();
IsoUtil.screenToTile(_model, x, y, tpos);
// Log.info("invalidateScreenRect: mapped rect to tile " +
// "[tx=" + tpos.x + ", ty=" + tpos.y +
// ", x=" + x + ", y=" + y + ", width=" + width +
// ", height=" + height + "].");
// determine screen coordinates for top-left tile
Point topleft = new Point();
IsoUtil.tileToScreen(_model, tpos.x, tpos.y, topleft);
_dirty.add(new int[] { tpos.x, tpos.y });
// determine number of horizontal and vertical tiles for rect
int numh = (int)Math.ceil((float)width / (float)_model.tilewid);
int numv = (int)Math.ceil((float)height / (float)_model.tilehhei);
// set up iterating variables
int tx = tpos.x, ty = tpos.y, mx = tpos.x, my = tpos.y;;
// set the starting screen y-position
int screenY = topleft.y;
// add top row if rect may overlap
if (y < (screenY + _model.tilehhei)) {
ty--;
for (int ii = 0; ii < numh; ii++) {
_dirty.add(new int[] { tx++, ty-- });
}
}
// add rows to the bottom if rect may overlap
int ypos = screenY + (numv * _model.tilehhei);
if ((y + height) > ypos) {
numv += ((y + height) > (ypos + _model.tilehhei)) ? 2 : 1;
}
// add dirty tiles from each affected row
boolean isodd = false;
for (int ii = 0; ii < numv; ii++) {
// set up iterating variables for this row
tx = mx;
ty = my;
int length = numh;
// set the starting screen x-position
int screenX = topleft.x;
if (isodd) {
screenX -= _model.tilehwid;
}
// skip leftmost tile if rect doesn't overlap
if (x > screenX + _model.tilewid) {
tx++;
ty--;
screenX += _model.tilewid;
}
// add to the right edge if rect may overlap
if (x + width > (screenX + (length * _model.tilewid))) {
length++;
}
// add all tiles in the row to the dirty set
for (int jj = 0; jj < length; jj++) {
_dirty.add(new int[] { tx++, ty-- });
}
// step along the x- or y-axis appropriately
if (isodd) {
mx++;
} else {
my++;
}
// increment the screen y-position
screenY += _model.tilehhei;
// toggle whether we're drawing an odd-numbered row
isodd = !isodd;
}
}
public void setScene (Scene scene)
@@ -370,6 +474,9 @@ public class IsoSceneView implements EditableSceneView
/** The dirty tile row segments that need to be re-painted. */
protected ArrayList _dirty;
/** The dirty rectangles that need to be re-painted. */
protected ArrayList _dirtyRects;
/** The scene model data. */
protected IsoSceneModel _model;
@@ -1,5 +1,5 @@
//
// $Id: IsoSceneViewModel.java,v 1.3 2001/08/03 22:23:47 shaper Exp $
// $Id: IsoSceneViewModel.java,v 1.4 2001/08/07 18:29:17 shaper Exp $
package com.threerings.miso.scene;
@@ -44,8 +44,8 @@ public class IsoSceneModel
/** The slope of the x- and y-axis lines. */
public float slopeX, slopeY;
/** The last calculated x- and y-axis mouse position tracking lines. */
public Point lineX[], lineY[];
/** The x-axis line. */
public Point lineX[];
/** The length between fine coordinates in pixels. */
public float finelen;
@@ -160,10 +160,8 @@ public class IsoSceneModel
// create the x- and y-axis lines
lineX = new Point[2];
lineY = new Point[2];
for (int ii = 0; ii < 2; ii++) {
lineX[ii] = new Point();
lineY[ii] = new Point();
}
// determine the starting point
@@ -1,5 +1,5 @@
//
// $Id: IsoUtil.java,v 1.1 2001/08/03 22:23:47 shaper Exp $
// $Id: IsoUtil.java,v 1.2 2001/08/07 18:29:17 shaper Exp $
package com.threerings.miso.scene;
@@ -110,25 +110,21 @@ public class IsoUtil
public static void screenToTile (
IsoSceneModel model, int sx, int sy, Point tpos)
{
Point[] lx = model.lineX, ly = model.lineY;
// calculate line parallel to the y-axis (from mouse pos to x-axis)
ly[0].setLocation(sx, sy);
int bY = (int)(sy - (model.slopeY * sx));
// determine intersection of x- and y-axis lines
ly[1].x = (int)((bY - (model.bX + model.origin.y)) /
int crossx = (int)((bY - (model.bX + model.origin.y)) /
(model.slopeX - model.slopeY));
ly[1].y = (int)((model.slopeY * ly[1].x) + bY);
int crossy = (int)((model.slopeY * crossx) + bY);
// determine distance of mouse pos along the x axis
int xdist = (int) MathUtil.distance(
lx[0].x, lx[0].y, ly[1].x, ly[1].y);
int xdist = (int)MathUtil.distance(
model.origin.x, model.origin.y, crossx, crossy);
tpos.x = (int)(xdist / model.tilelen);
// determine distance of mouse pos along the y-axis
int ydist = (int) MathUtil.distance(
ly[0].x, ly[0].y, ly[1].x, ly[1].y);
int ydist = (int)MathUtil.distance(sx, sy, crossx, crossy);
tpos.y = (int)(ydist / model.tilelen);
}
@@ -0,0 +1,28 @@
//
// $Id: ChatPanel.java,v 1.1 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.viewer;
import java.awt.*;
import javax.swing.*;
import com.threerings.miso.Log;
public class ChatPanel extends JPanel
{
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor(Color.blue);
Rectangle bounds = getBounds();
g.fillRect(0, 0, bounds.width, bounds.height);
Log.info("chat panel [bounds=" + bounds + "].");
}
public Dimension getPreferredSize ()
{
return new Dimension(200, 150);
}
}
@@ -0,0 +1,28 @@
//
// $Id: ManagementPanel.java,v 1.1 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.viewer;
import java.awt.*;
import javax.swing.*;
import com.threerings.miso.Log;
public class ManagementPanel extends JPanel
{
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor(Color.red);
Rectangle bounds = getBounds();
g.fillRect(0, 0, bounds.width, bounds.height);
Log.info("mgmt panel [bounds=" + bounds + "].");
}
public Dimension getPreferredSize ()
{
return new Dimension(200, 300);
}
}
@@ -0,0 +1,28 @@
//
// $Id: StatusPanel.java,v 1.1 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.viewer;
import java.awt.*;
import javax.swing.*;
import com.threerings.miso.Log;
public class StatusPanel extends JPanel
{
public void paintComponent (Graphics g)
{
super.paintComponent(g);
g.setColor(Color.yellow);
Rectangle bounds = getBounds();
g.fillRect(0, 0, bounds.width, bounds.height);
Log.info("status panel [bounds=" + bounds + "].");
}
public Dimension getPreferredSize ()
{
return new Dimension(200, 150);
}
}
@@ -1,5 +1,5 @@
//
// $Id: ViewerFrame.java,v 1.8 2001/08/06 18:57:39 shaper Exp $
// $Id: ViewerFrame.java,v 1.9 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.viewer;
@@ -55,9 +55,24 @@ class ViewerFrame extends JFrame implements WindowListener
// set up the scene view panel with a default scene
ViewerSceneViewPanel svpanel =
new ViewerSceneViewPanel(_ctx, spritemgr, sprite);
top.add(svpanel);
top.add(svpanel, GroupLayout.FIXED);
// add the scene view panel
// create a sub-panel to hold the side panels
JPanel sub = new JPanel();
gl = new VGroupLayout(GroupLayout.STRETCH);
gl.setOffAxisPolicy(GroupLayout.STRETCH);
gl.setJustification(GroupLayout.TOP);
sub.setLayout(gl);
// add the various side-panels
sub.add(new StatusPanel(), GroupLayout.FIXED);
sub.add(new ManagementPanel());
sub.add(new ChatPanel());
// add the sub-panel to the main panel
top.add(sub);
// add the main panel to the frame
getContentPane().add(top, BorderLayout.CENTER);
}
@@ -1,5 +1,5 @@
//
// $Id: ViewerSceneViewPanel.java,v 1.2 2001/08/06 18:57:39 shaper Exp $
// $Id: ViewerSceneViewPanel.java,v 1.3 2001/08/07 18:29:18 shaper Exp $
package com.threerings.miso.viewer;
@@ -39,6 +39,10 @@ public class ViewerSceneViewPanel extends SceneViewPanel
// load up the initial scene
prepareStartingScene();
((EditableSceneView)_view).setShowCoordinates(true);
PerformanceMonitor.register(this, "paint", 1000);
}
/**
@@ -63,6 +67,12 @@ public class ViewerSceneViewPanel extends SceneViewPanel
}
}
public void paintComponent (Graphics g)
{
super.paintComponent(g);
PerformanceMonitor.tick(this, "paint");
}
public void checkpoint (String name, int ticks)
{
Log.info(name + " [ticks=" + ticks + "].");