Skip to main content

svn commit: r181 - trunk/src/com/sun/scenario/scenegraph

5 replies [Last post]
Anonymous

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Joshua Smith

Josh-

Does this mean that you can save portions of the screen and do things with
it?

Is this accessible from within Java FX Script?

Josh

On Tue, Mar 11, 2008 at 8:20 PM, Joshua Marinacci
wrote:

> Woohoo! So does this mean I can render any portion of the tree to my
> own Graphics2D whenever I want?
>
> J
>
[att1.html]

Joshua Marinacci

I think that's what this means. I should be able to render a portion
of the tree to an image, for example, that I can export to a PNG. As
for access from JavaFX Script, I don't know. I believe that most of
the FX wrapper classes have a protected reference to their underlying
SGNode, so we should be able to call down to the Java level with
that. In the future I hope we will have a more official way of using
it.

- Josh

On Mar 11, 2008, at 9:10 PM, Joshua Smith wrote:

> Josh-
>
> Does this mean that you can save portions of the screen and do
> things with it?
>
> Is this accessible from within Java FX Script?
>
> Josh
>
> On Tue, Mar 11, 2008 at 8:20 PM, Joshua Marinacci > > wrote:
> Woohoo! So does this mean I can render any portion of the tree to my
> own Graphics2D whenever I want?
>
> J
>

Joshua Marinacci, Sun Engineer
http://weblogs.java.net/blog/joshy/
http://joshy.org/
joshua@marinacci.org

[att1.html]

Joshua Smith

Very cool.

Thanks,
Josh

On Wed, Mar 12, 2008 at 12:05 PM, Joshua Marinacci
wrote:

> I think that's what this means. I should be able to render a portion of
> the tree to an image, for example, that I can export to a PNG. As for
> access from JavaFX Script, I don't know. I believe that most of the FX
> wrapper classes have a protected reference to their underlying SGNode, so we
> should be able to call down to the Java level with that. In the future I
> hope we will have a more official way of using it.
>
> - Josh
>
> On Mar 11, 2008, at 9:10 PM, Joshua Smith wrote:
>
> Josh-
>
> Does this mean that you can save portions of the screen and do things with
> it?
>
> Is this accessible from within Java FX Script?
>
> Josh
>
> On Tue, Mar 11, 2008 at 8:20 PM, Joshua Marinacci
> wrote:
>
> > Woohoo! So does this mean I can render any portion of the tree to my
> > own Graphics2D whenever I want?
> >
> > J
> >
>
>
> Joshua Marinacci, Sun Engineer
> http://weblogs.java.net/blog/joshy/
> http://joshy.org/
> joshua@marinacci.org
>
>
>
>
[att1.html]

Joshua Marinacci

Woohoo! So does this mean I can render any portion of the tree to my
own Graphics2D whenever I want?

J
On Mar 11, 2008, at 4:43 PM, flar@dev.java.net wrote:

> Author: flar
> Date: 2008-03-11 23:43:44+0000
> New Revision: 181
>
> Modified:
> trunk/src/com/sun/scenario/scenegraph/JSGPanel.java
> trunk/src/com/sun/scenario/scenegraph/SGNode.java
>
> Log:
> Move scene rendering code to a more accessible location and make it
> public
>
> Modified: trunk/src/com/sun/scenario/scenegraph/JSGPanel.java
> Url: https://scenegraph.dev.java.net/source/browse/scenegraph/trunk/src/com/s...
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- trunk/src/com/sun/scenario/scenegraph/JSGPanel.java (original)
> +++ trunk/src/com/sun/scenario/scenegraph/JSGPanel.java 2008-03-11
> 23:43:44+0000
> @@ -23,7 +23,6 @@
>
> package com.sun.scenario.scenegraph;
>
> -import com.sun.scenario.effect.Effect;
> import static java.awt.event.MouseEvent.MOUSE_ENTERED;
> import static java.awt.event.MouseEvent.MOUSE_EXITED;
>
> @@ -41,7 +40,6 @@
> import java.awt.event.MouseMotionListener;
> import java.awt.event.MouseWheelEvent;
> import java.awt.event.MouseWheelListener;
> -import java.awt.geom.AffineTransform;
> import java.awt.geom.Rectangle2D;
> import java.awt.geom.Point2D;
> import java.util.List;
> @@ -49,8 +47,6 @@
> import javax.swing.JComponent;
>
> import com.sun.scenario.scenegraph.event.SGMouseAdapter;
> -import java.awt.GraphicsConfiguration;
> -import java.awt.Image;
> import java.util.HashSet;
> import java.util.Collections;
>
> @@ -62,8 +58,6 @@
> */
> public class JSGPanel extends JComponent {
>
> - // debugging utility: displays red rectangles around node bounds
> - private static final boolean debugBounds = false;
> // debugging utility: fills dirty areas with red XOR rectangles
> private static final boolean hiliteDirty = false;
> // toggles the use of incremental repainting optimizations
> @@ -137,12 +131,12 @@
> Insets insets = getInsets();
> int dx = insets.left + insets.right;
> int dy = insets.top + insets.bottom;
> - SGNode scene = getScene(); // so that we ignore FPSData, if
> present
> - if (scene == null) {
> + SGNode root = getScene(); // so that we ignore FPSData, if
> present
> + if (root == null) {
> return new Dimension(dx + 640, dy + 480);
> }
> else {
> - Rectangle r = scene.getBounds().getBounds();
> + Rectangle r = root.getBounds().getBounds();
> return new Dimension(dx + r.width, dy + r.height);
> }
> }
> @@ -497,157 +491,10 @@
> return focusOwner;
> }
>
> -
> +
> /*
> * Rendering code below...
> */
> -
> - private void render(SGNode node, Rectangle dirtyRegion,
> Graphics2D g,
> - AffineTransform origXform)
> - {
> - if (!node.isVisible()) {
> - return;
> - }
> -
> - if (incrementalRepaintOpt) {
> - // check to see whether we need to render this node
> (including
> - // any children) at all
> - Rectangle2D bounds =
> node.getTransformedBoundsRelativeToRoot();
> - if (bounds != null && bounds.intersects(dirtyRegion)) {
> - // save the most recently painted bounds in the
> node, which
> - // will be used later when accumulating dirty regions
> - node.setLastPaintedBounds(bounds);
> - } else {
> - // no need to render this node (or any children)
> - return;
> - }
> - }
> -
> - if (node instanceof SGLeaf) {
> - SGLeaf leaf = (SGLeaf)node;
> - Graphics2D gLeaf = (Graphics2D)g.create();
> - leaf.paint(gLeaf);
> - if (debugBounds) {
> - Rectangle leafBounds =
> node.getBounds(origXform).getBounds();
> - g.setTransform(new AffineTransform());
> - g.setColor(Color.RED);
> - g.drawRect(leafBounds.x, leafBounds.y,
> - leafBounds.width-1,
> - leafBounds.height-1);
> - g.setTransform(origXform);
> - }
> - } else if (node instanceof SGFilter) {
> - SGFilter filter = (SGFilter)node;
> - SGNode child = filter.getChild();
> - if (child != null) {
> - Graphics2D gOrig = (Graphics2D)g.create();
> - AffineTransform curXform = origXform;
> - if (filter instanceof SGTransform) {
> - curXform = ((SGTransform)
> filter).createAffineTransform();
> - gOrig.transform(curXform);
> - curXform.preConcatenate(origXform);
> - }
> - if (filter.canSkipRendering()) {
> - if (!filter.canSkipChildren()) {
> - render(child, dirtyRegion, gOrig, curXform);
> - }
> - } else {
> - int sourceType = filter.needsSourceContent();
> - if (sourceType == SGFilter.NONE) {
> - filter.setupRenderGraphics(gOrig);
> - render(child, dirtyRegion, gOrig, curXform);
> - } else if (sourceType == SGFilter.CACHED) {
> - filter.renderFromCache(gOrig);
> - } else {
> - Image xformImage = null;
> - Rectangle xformBounds = null;
> - Image unxformImage = null;
> - Rectangle unxformBounds =
> child.getBounds().getBounds();
> - if (unxformBounds.isEmpty()) {
> - // nothing to render
> - return;
> - }
> - GraphicsConfiguration gc =
> getGraphicsConfiguration();
> - if ((sourceType & SGFilter.TRANSFORMED) !=
> 0) {
> - xformBounds =
> child.getBounds(curXform).getBounds();
> - int nodeX = xformBounds.x;
> - int nodeY = xformBounds.y;
> - int nodeW = xformBounds.width;
> - int nodeH = xformBounds.height;
> - // TODO: image should be constrained to
> the size of the clip
> - if (filter instanceof SGRenderCache) {
> - // SGRenderCache will hold onto the
> image
> - // for some time, so create a fresh
> one
> - // (don't use the pool)
> - xformImage =
> Effect.createCompatibleImage(gc, nodeW, nodeH);
> - } else {
> - xformImage =
> Effect.getCompatibleImage(gc, nodeW, nodeH);
> - }
> -
> - Graphics2D gFilter =
> - (Graphics2D)xformImage.getGraphics();
> - AffineTransform filterXform =
> -
> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
> - filterXform.concatenate(curXform);
> - gFilter.setTransform(filterXform);
> -
> - filter.setupRenderGraphics(gFilter);
> - render(child, dirtyRegion, gFilter,
> filterXform);
> -
> -
> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX,
> nodeY));
> - }
> - if ((sourceType & SGFilter.UNTRANSFORMED) !
> = 0) {
> - if (xformImage != null &&
> curXform.isIdentity()) {
> - // in this case there will be no
> difference
> - // between xformImage and
> unxformImage; we
> - // can reuse xformImage instead of
> creating
> - // what would essentially be a
> duplicate image
> - unxformImage = xformImage;
> - } else {
> - int nodeX = unxformBounds.x;
> - int nodeY = unxformBounds.y;
> - int nodeW = unxformBounds.width;
> - int nodeH = unxformBounds.height;
> - unxformImage =
> Effect.getCompatibleImage(gc, nodeW, nodeH);
> -
> - Graphics2D gFilter =
> -
> (Graphics2D)unxformImage.getGraphics();
> - AffineTransform filterXform =
> -
> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
> - gFilter.setTransform(filterXform);
> -
> - filter.setupRenderGraphics(gFilter);
> - render(child, dirtyRegion, gFilter,
> filterXform);
> -
> - // TODO: we have very little
> support for
> - // untransformed source effects at
> this time;
> - // this needs to be fixed asap...
> - //
> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX,
> nodeY));
> - }
> - }
> -
> - SGSourceContent sourceContent =
> - new SGSourceContent(curXform,
> - unxformImage,
> unxformBounds,
> - xformImage,
> xformBounds);
> -
> - filter.renderFinalImage(gOrig,
> sourceContent);
> -
> - if (unxformImage != null) {
> - Effect.releaseCompatibleImage(gc,
> unxformImage);
> - }
> - if (xformImage != null && xformImage !=
> unxformImage) {
> - Effect.releaseCompatibleImage(gc,
> xformImage);
> - }
> - }
> - }
> - }
> - } else if (node instanceof SGParent) {
> - for (SGNode child : ((SGParent)node).getChildren()) {
> - render(child, dirtyRegion, g, origXform);
> - }
> - }
> - }
>
> private Rectangle dmgrect;
>
> @@ -665,9 +512,10 @@
> g2.setColor(getBackground());
> g2.fill(dirtyRegion);
> }
> - if (getSceneGroup() != null) {
> + SGNode root = getSceneGroup();
> + if (root != null) {
> // render all areas of the scene that intersect the
> dirtyRegion
> - render(getSceneGroup(), dirtyRegion, g2,
> g2.getTransform());
> + root.render(g2, incrementalRepaintOpt ?
> dirtyRegion : null);
> }
> g2.dispose();
> }
>
> Modified: trunk/src/com/sun/scenario/scenegraph/SGNode.java
> Url: https://scenegraph.dev.java.net/source/browse/scenegraph/trunk/src/com/s...
> =
> =
> =
> =
> =
> =
> =
> =
> ======================================================================
> --- trunk/src/com/sun/scenario/scenegraph/SGNode.java (original)
> +++ trunk/src/com/sun/scenario/scenegraph/SGNode.java 2008-03-11
> 23:43:44+0000
> @@ -33,6 +33,11 @@
> import static java.awt.event.MouseEvent.MOUSE_WHEEL;
>
> import java.awt.Cursor;
> +import java.awt.Color;
> +import java.awt.Graphics2D;
> +import java.awt.GraphicsConfiguration;
> +import java.awt.Image;
> +import java.awt.Rectangle;
> import java.awt.event.FocusEvent;
> import java.awt.event.KeyEvent;
> import java.awt.event.MouseEvent;
> @@ -47,6 +52,7 @@
> import java.util.List;
> import java.util.Map;
>
> +import com.sun.scenario.effect.Effect;
> import com.sun.scenario.scenegraph.event.SGFocusListener;
> import com.sun.scenario.scenegraph.event.SGKeyListener;
> import com.sun.scenario.scenegraph.event.SGMouseListener;
> @@ -63,6 +69,9 @@
> * @author Hans Muller
> */
> public abstract class SGNode {
> + // debugging utility: displays red rectangles around node bounds
> + private static final boolean debugBounds = false;
> +
> private Object parent;
> private Map attributeMap;
> private List nodeListeners = null;
> @@ -123,6 +132,7 @@
> this.id = id;
> }
>
> + @Override
> public String toString() {
> return id + " " + super.toString();
> }
> @@ -667,7 +677,172 @@
> return r;
> }
>
> -
> +
> + /*
> + * Rendering code below...
> + */
> +
> + /**
> + * Render the tree of nodes to the specified {@link Graphics2D}
> object
> + * descending from this node as the root.
> + * The {@code dirtyRegion} parameter can be used to cull the
> rendering
> + * operations on the tree so that only parts of the tree that
> intersect
> + * the indicated rectangle (in device space) will be visited
> and rendered.
> + * If the {@code dirtyRegion} parameter is null then all parts
> of the
> + * tree will be visited and rendered whether they will
> eventually be
> + * visible or not.
> + *
> + * @param g the {@code Graphics2D} object to render into
> + * @param dirtyRegion a Rectangle to cull which parts of the
> tree to
> + * operate on, or null if the full tree
> should be
> + * visited and rendered
> + */
> + public final void render(Graphics2D g, Rectangle dirtyRegion) {
> + if (!isVisible()) {
> + return;
> + }
> +
> + if (dirtyRegion != null) {
> + // check to see whether we need to render this node
> (including
> + // any children) at all
> + Rectangle2D bounds =
> getTransformedBoundsRelativeToRoot();
> + if (bounds != null && bounds.intersects(dirtyRegion)) {
> + // save the most recently painted bounds in the
> node, which
> + // will be used later when accumulating dirty regions
> + setLastPaintedBounds(bounds);
> + } else {
> + // no need to render this node (or any children)
> + return;
> + }
> + }
> +
> + if (this instanceof SGLeaf) {
> + SGLeaf leaf = (SGLeaf) this;
> + Graphics2D gLeaf = (Graphics2D) g.create();
> + leaf.paint(gLeaf);
> + if (debugBounds) {
> + AffineTransform gtx = g.getTransform();
> + Rectangle leafBounds = getBounds(gtx).getBounds();
> + g.setTransform(new AffineTransform());
> + g.setColor(Color.RED);
> + g.drawRect(leafBounds.x, leafBounds.y,
> + leafBounds.width-1,
> + leafBounds.height-1);
> + g.setTransform(gtx);
> + }
> + } else if (this instanceof SGFilter) {
> + SGFilter filter = (SGFilter) this;
> + SGNode child = filter.getChild();
> + if (child != null) {
> + Graphics2D gOrig = (Graphics2D) g.create();
> + if (filter instanceof SGTransform) {
> + AffineTransform newXform =
> + ((SGTransform)
> filter).createAffineTransform();
> + gOrig.transform(newXform);
> + }
> + if (filter.canSkipRendering()) {
> + if (!filter.canSkipChildren()) {
> + child.render(gOrig, dirtyRegion);
> + }
> + } else {
> + int sourceType = filter.needsSourceContent();
> + if (sourceType == SGFilter.NONE) {
> + filter.setupRenderGraphics(gOrig);
> + child.render(gOrig, dirtyRegion);
> + } else if (sourceType == SGFilter.CACHED) {
> + filter.renderFromCache(gOrig);
> + } else {
> + Image xformImage = null;
> + Rectangle xformBounds = null;
> + Image unxformImage = null;
> + Rectangle unxformBounds =
> child.getBounds().getBounds();
> + if (unxformBounds.isEmpty()) {
> + // nothing to render
> + return;
> + }
> + GraphicsConfiguration gc =
> gOrig.getDeviceConfiguration();
> + AffineTransform gtx = gOrig.getTransform();
> + if ((sourceType & SGFilter.TRANSFORMED) !=
> 0) {
> + xformBounds =
> child.getBounds(gtx).getBounds();
> + int nodeX = xformBounds.x;
> + int nodeY = xformBounds.y;
> + int nodeW = xformBounds.width;
> + int nodeH = xformBounds.height;
> + // TODO: image should be constrained to
> the size of the clip
> + if (filter instanceof SGRenderCache) {
> + // SGRenderCache will hold onto the
> image
> + // for some time, so create a fresh
> one
> + // (don't use the pool)
> + xformImage =
> Effect.createCompatibleImage(gc, nodeW, nodeH);
> + } else {
> + xformImage =
> Effect.getCompatibleImage(gc, nodeW, nodeH);
> + }
> +
> + Graphics2D gFilter =
> + (Graphics2D)
> xformImage.getGraphics();
> + AffineTransform filterXform =
> +
> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
> + filterXform.concatenate(gtx);
> + gFilter.setTransform(filterXform);
> +
> + filter.setupRenderGraphics(gFilter);
> + child.render(gFilter, dirtyRegion);
> +
> +
> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX,
> nodeY));
> + }
> + if ((sourceType & SGFilter.UNTRANSFORMED) !
> = 0) {
> + if (xformImage != null &&
> gtx.isIdentity()) {
> + // in this case there will be no
> difference
> + // between xformImage and
> unxformImage; we
> + // can reuse xformImage instead of
> creating
> + // what would essentially be a
> duplicate image
> + unxformImage = xformImage;
> + } else {
> + int nodeX = unxformBounds.x;
> + int nodeY = unxformBounds.y;
> + int nodeW = unxformBounds.width;
> + int nodeH = unxformBounds.height;
> + unxformImage =
> Effect.getCompatibleImage(gc, nodeW, nodeH);
> +
> + Graphics2D gFilter =
> + (Graphics2D)
> unxformImage.getGraphics();
> + AffineTransform filterXform =
> +
> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
> + gFilter.setTransform(filterXform);
> +
> + filter.setupRenderGraphics(gFilter);
> + child.render(gFilter, dirtyRegion);
> +
> + // TODO: we have very little
> support for
> + // untransformed source effects at
> this time;
> + // this needs to be fixed asap...
> + //
> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX,
> nodeY));
> + }
> + }
> +
> + SGSourceContent sourceContent =
> + new SGSourceContent(gtx,
> + unxformImage,
> unxformBounds,
> + xformImage,
> xformBounds);
> +
> + filter.renderFinalImage(gOrig,
> sourceContent);
> +
> + if (unxformImage != null) {
> + Effect.releaseCompatibleImage(gc,
> unxformImage);
> + }
> + if (xformImage != null && xformImage !=
> unxformImage) {
> + Effect.releaseCompatibleImage(gc,
> xformImage);
> + }
> + }
> + }
> + }
> + } else if (this instanceof SGParent) {
> + for (SGNode child : ((SGParent) this).getChildren()) {
> + child.render(g, dirtyRegion);
> + }
> + }
> + }
> +
> /*
> * Event handling below...
> */
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: commits-unsubscribe@scenegraph.dev.java.net
> For additional commands, e-mail: commits-help@scenegraph.dev.java.net
>

Joshua Marinacci, Sun Engineer
http://weblogs.java.net/blog/joshy/
http://joshy.org/
joshua@marinacci.org

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@scenegraph.dev.java.net
For additional commands, e-mail: dev-help@scenegraph.dev.java.net

Jim Graham

That's basically the intention, though there is still one last piece of
the puzzle that will be flaky for a while until we decide which
direction to take things...

Right now there is a small piece of logic in the render() method which
records the 'last painted bounds' so that when bounds change we can make
sure we render both the old bounds and the new bounds. Ideally this
would only ever be recorded when the JSGPanel does the painting, but we
don't really know who is calling us so we record it anyway. As a result
you might accidentally cause the wrong "old bounds" to be recorded in
the node by your actions until we fix this.

One work around is to not pass in the dirtyRegion rectangle since the
last painted bounds is only ever recorded when that rectangle is
non-null and so if you only ever pass in null for that parameter then
you won't interfere with anything.

Another workaround is that a JSGPanel.repaint() call should (untested)
repair all problems that might arise from such interference, but YMMV.

Eventually we want to move that "last painted bounds" processing out of
the render method so that it is tied more tightly into the dirty region
accumulation of the JSGPanel. However - we also want to eventually
enable non JSGPanel users to be able to roll their own dirty region
management using the same mechanisms so the new mechanism remains TBD
until we figure out how to make that work both for JSGPanel and "roll
your own"ers in a responsible way.

Hmmm... Until I fix this, maybe I should make this method package
private with a public method:

public void render(Graphics2D g) {
renderInternal(g, null);
}

That way JSGPanel can continue to do its dirty region management in a
way that can't be muddled by external users. I think I'll check that in
soon to avoid complications...

...jim

Joshua Marinacci wrote:
> Woohoo! So does this mean I can render any portion of the tree to my
> own Graphics2D whenever I want?
>
> J
> On Mar 11, 2008, at 4:43 PM, flar@dev.java.net wrote:
>
>> Author: flar
>> Date: 2008-03-11 23:43:44+0000
>> New Revision: 181
>>
>> Modified:
>> trunk/src/com/sun/scenario/scenegraph/JSGPanel.java
>> trunk/src/com/sun/scenario/scenegraph/SGNode.java
>>
>> Log:
>> Move scene rendering code to a more accessible location and make it
>> public
>>
>> Modified: trunk/src/com/sun/scenario/scenegraph/JSGPanel.java
>> Url:
>> https://scenegraph.dev.java.net/source/browse/scenegraph/trunk/src/com/s...
>>
>> ==============================================================================
>>
>> --- trunk/src/com/sun/scenario/scenegraph/JSGPanel.java (original)
>> +++ trunk/src/com/sun/scenario/scenegraph/JSGPanel.java 2008-03-11
>> 23:43:44+0000
>> @@ -23,7 +23,6 @@
>>
>> package com.sun.scenario.scenegraph;
>>
>> -import com.sun.scenario.effect.Effect;
>> import static java.awt.event.MouseEvent.MOUSE_ENTERED;
>> import static java.awt.event.MouseEvent.MOUSE_EXITED;
>>
>> @@ -41,7 +40,6 @@
>> import java.awt.event.MouseMotionListener;
>> import java.awt.event.MouseWheelEvent;
>> import java.awt.event.MouseWheelListener;
>> -import java.awt.geom.AffineTransform;
>> import java.awt.geom.Rectangle2D;
>> import java.awt.geom.Point2D;
>> import java.util.List;
>> @@ -49,8 +47,6 @@
>> import javax.swing.JComponent;
>>
>> import com.sun.scenario.scenegraph.event.SGMouseAdapter;
>> -import java.awt.GraphicsConfiguration;
>> -import java.awt.Image;
>> import java.util.HashSet;
>> import java.util.Collections;
>>
>> @@ -62,8 +58,6 @@
>> */
>> public class JSGPanel extends JComponent {
>>
>> - // debugging utility: displays red rectangles around node bounds
>> - private static final boolean debugBounds = false;
>> // debugging utility: fills dirty areas with red XOR rectangles
>> private static final boolean hiliteDirty = false;
>> // toggles the use of incremental repainting optimizations
>> @@ -137,12 +131,12 @@
>> Insets insets = getInsets();
>> int dx = insets.left + insets.right;
>> int dy = insets.top + insets.bottom;
>> - SGNode scene = getScene(); // so that we ignore FPSData, if
>> present
>> - if (scene == null) {
>> + SGNode root = getScene(); // so that we ignore FPSData, if
>> present
>> + if (root == null) {
>> return new Dimension(dx + 640, dy + 480);
>> }
>> else {
>> - Rectangle r = scene.getBounds().getBounds();
>> + Rectangle r = root.getBounds().getBounds();
>> return new Dimension(dx + r.width, dy + r.height);
>> }
>> }
>> @@ -497,157 +491,10 @@
>> return focusOwner;
>> }
>>
>> -
>> +
>> /*
>> * Rendering code below...
>> */
>> -
>> - private void render(SGNode node, Rectangle dirtyRegion,
>> Graphics2D g,
>> - AffineTransform origXform)
>> - {
>> - if (!node.isVisible()) {
>> - return;
>> - }
>> -
>> - if (incrementalRepaintOpt) {
>> - // check to see whether we need to render this node
>> (including
>> - // any children) at all
>> - Rectangle2D bounds =
>> node.getTransformedBoundsRelativeToRoot();
>> - if (bounds != null && bounds.intersects(dirtyRegion)) {
>> - // save the most recently painted bounds in the node,
>> which
>> - // will be used later when accumulating dirty regions
>> - node.setLastPaintedBounds(bounds);
>> - } else {
>> - // no need to render this node (or any children)
>> - return;
>> - }
>> - }
>> -
>> - if (node instanceof SGLeaf) {
>> - SGLeaf leaf = (SGLeaf)node;
>> - Graphics2D gLeaf = (Graphics2D)g.create();
>> - leaf.paint(gLeaf);
>> - if (debugBounds) {
>> - Rectangle leafBounds =
>> node.getBounds(origXform).getBounds();
>> - g.setTransform(new AffineTransform());
>> - g.setColor(Color.RED);
>> - g.drawRect(leafBounds.x, leafBounds.y,
>> - leafBounds.width-1,
>> - leafBounds.height-1);
>> - g.setTransform(origXform);
>> - }
>> - } else if (node instanceof SGFilter) {
>> - SGFilter filter = (SGFilter)node;
>> - SGNode child = filter.getChild();
>> - if (child != null) {
>> - Graphics2D gOrig = (Graphics2D)g.create();
>> - AffineTransform curXform = origXform;
>> - if (filter instanceof SGTransform) {
>> - curXform = ((SGTransform)
>> filter).createAffineTransform();
>> - gOrig.transform(curXform);
>> - curXform.preConcatenate(origXform);
>> - }
>> - if (filter.canSkipRendering()) {
>> - if (!filter.canSkipChildren()) {
>> - render(child, dirtyRegion, gOrig, curXform);
>> - }
>> - } else {
>> - int sourceType = filter.needsSourceContent();
>> - if (sourceType == SGFilter.NONE) {
>> - filter.setupRenderGraphics(gOrig);
>> - render(child, dirtyRegion, gOrig, curXform);
>> - } else if (sourceType == SGFilter.CACHED) {
>> - filter.renderFromCache(gOrig);
>> - } else {
>> - Image xformImage = null;
>> - Rectangle xformBounds = null;
>> - Image unxformImage = null;
>> - Rectangle unxformBounds =
>> child.getBounds().getBounds();
>> - if (unxformBounds.isEmpty()) {
>> - // nothing to render
>> - return;
>> - }
>> - GraphicsConfiguration gc =
>> getGraphicsConfiguration();
>> - if ((sourceType & SGFilter.TRANSFORMED) != 0) {
>> - xformBounds =
>> child.getBounds(curXform).getBounds();
>> - int nodeX = xformBounds.x;
>> - int nodeY = xformBounds.y;
>> - int nodeW = xformBounds.width;
>> - int nodeH = xformBounds.height;
>> - // TODO: image should be constrained to
>> the size of the clip
>> - if (filter instanceof SGRenderCache) {
>> - // SGRenderCache will hold onto the
>> image
>> - // for some time, so create a fresh one
>> - // (don't use the pool)
>> - xformImage =
>> Effect.createCompatibleImage(gc, nodeW, nodeH);
>> - } else {
>> - xformImage =
>> Effect.getCompatibleImage(gc, nodeW, nodeH);
>> - }
>> -
>> - Graphics2D gFilter =
>> - (Graphics2D)xformImage.getGraphics();
>> - AffineTransform filterXform =
>> -
>> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
>> - filterXform.concatenate(curXform);
>> - gFilter.setTransform(filterXform);
>> -
>> - filter.setupRenderGraphics(gFilter);
>> - render(child, dirtyRegion, gFilter,
>> filterXform);
>> -
>> -
>> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX, nodeY));
>> - }
>> - if ((sourceType & SGFilter.UNTRANSFORMED) !=
>> 0) {
>> - if (xformImage != null &&
>> curXform.isIdentity()) {
>> - // in this case there will be no
>> difference
>> - // between xformImage and
>> unxformImage; we
>> - // can reuse xformImage instead of
>> creating
>> - // what would essentially be a
>> duplicate image
>> - unxformImage = xformImage;
>> - } else {
>> - int nodeX = unxformBounds.x;
>> - int nodeY = unxformBounds.y;
>> - int nodeW = unxformBounds.width;
>> - int nodeH = unxformBounds.height;
>> - unxformImage =
>> Effect.getCompatibleImage(gc, nodeW, nodeH);
>> -
>> - Graphics2D gFilter =
>> -
>> (Graphics2D)unxformImage.getGraphics();
>> - AffineTransform filterXform =
>> -
>> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
>> - gFilter.setTransform(filterXform);
>> -
>> - filter.setupRenderGraphics(gFilter);
>> - render(child, dirtyRegion, gFilter,
>> filterXform);
>> -
>> - // TODO: we have very little support for
>> - // untransformed source effects at
>> this time;
>> - // this needs to be fixed asap...
>> -
>> //gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX, nodeY));
>> - }
>> - }
>> -
>> - SGSourceContent sourceContent =
>> - new SGSourceContent(curXform,
>> - unxformImage,
>> unxformBounds,
>> - xformImage,
>> xformBounds);
>> -
>> - filter.renderFinalImage(gOrig, sourceContent);
>> -
>> - if (unxformImage != null) {
>> - Effect.releaseCompatibleImage(gc,
>> unxformImage);
>> - }
>> - if (xformImage != null && xformImage !=
>> unxformImage) {
>> - Effect.releaseCompatibleImage(gc,
>> xformImage);
>> - }
>> - }
>> - }
>> - }
>> - } else if (node instanceof SGParent) {
>> - for (SGNode child : ((SGParent)node).getChildren()) {
>> - render(child, dirtyRegion, g, origXform);
>> - }
>> - }
>> - }
>>
>> private Rectangle dmgrect;
>>
>> @@ -665,9 +512,10 @@
>> g2.setColor(getBackground());
>> g2.fill(dirtyRegion);
>> }
>> - if (getSceneGroup() != null) {
>> + SGNode root = getSceneGroup();
>> + if (root != null) {
>> // render all areas of the scene that intersect the
>> dirtyRegion
>> - render(getSceneGroup(), dirtyRegion, g2,
>> g2.getTransform());
>> + root.render(g2, incrementalRepaintOpt ? dirtyRegion :
>> null);
>> }
>> g2.dispose();
>> }
>>
>> Modified: trunk/src/com/sun/scenario/scenegraph/SGNode.java
>> Url:
>> https://scenegraph.dev.java.net/source/browse/scenegraph/trunk/src/com/s...
>>
>> ==============================================================================
>>
>> --- trunk/src/com/sun/scenario/scenegraph/SGNode.java (original)
>> +++ trunk/src/com/sun/scenario/scenegraph/SGNode.java 2008-03-11
>> 23:43:44+0000
>> @@ -33,6 +33,11 @@
>> import static java.awt.event.MouseEvent.MOUSE_WHEEL;
>>
>> import java.awt.Cursor;
>> +import java.awt.Color;
>> +import java.awt.Graphics2D;
>> +import java.awt.GraphicsConfiguration;
>> +import java.awt.Image;
>> +import java.awt.Rectangle;
>> import java.awt.event.FocusEvent;
>> import java.awt.event.KeyEvent;
>> import java.awt.event.MouseEvent;
>> @@ -47,6 +52,7 @@
>> import java.util.List;
>> import java.util.Map;
>>
>> +import com.sun.scenario.effect.Effect;
>> import com.sun.scenario.scenegraph.event.SGFocusListener;
>> import com.sun.scenario.scenegraph.event.SGKeyListener;
>> import com.sun.scenario.scenegraph.event.SGMouseListener;
>> @@ -63,6 +69,9 @@
>> * @author Hans Muller
>> */
>> public abstract class SGNode {
>> + // debugging utility: displays red rectangles around node bounds
>> + private static final boolean debugBounds = false;
>> +
>> private Object parent;
>> private Map attributeMap;
>> private List nodeListeners = null;
>> @@ -123,6 +132,7 @@
>> this.id = id;
>> }
>>
>> + @Override
>> public String toString() {
>> return id + " " + super.toString();
>> }
>> @@ -667,7 +677,172 @@
>> return r;
>> }
>>
>> -
>> +
>> + /*
>> + * Rendering code below...
>> + */
>> +
>> + /**
>> + * Render the tree of nodes to the specified {@link Graphics2D}
>> object
>> + * descending from this node as the root.
>> + * The {@code dirtyRegion} parameter can be used to cull the
>> rendering
>> + * operations on the tree so that only parts of the tree that
>> intersect
>> + * the indicated rectangle (in device space) will be visited and
>> rendered.
>> + * If the {@code dirtyRegion} parameter is null then all parts of
>> the
>> + * tree will be visited and rendered whether they will eventually be
>> + * visible or not.
>> + *
>> + * @param g the {@code Graphics2D} object to render into
>> + * @param dirtyRegion a Rectangle to cull which parts of the tree to
>> + * operate on, or null if the full tree should be
>> + * visited and rendered
>> + */
>> + public final void render(Graphics2D g, Rectangle dirtyRegion) {
>> + if (!isVisible()) {
>> + return;
>> + }
>> +
>> + if (dirtyRegion != null) {
>> + // check to see whether we need to render this node
>> (including
>> + // any children) at all
>> + Rectangle2D bounds = getTransformedBoundsRelativeToRoot();
>> + if (bounds != null && bounds.intersects(dirtyRegion)) {
>> + // save the most recently painted bounds in the node,
>> which
>> + // will be used later when accumulating dirty regions
>> + setLastPaintedBounds(bounds);
>> + } else {
>> + // no need to render this node (or any children)
>> + return;
>> + }
>> + }
>> +
>> + if (this instanceof SGLeaf) {
>> + SGLeaf leaf = (SGLeaf) this;
>> + Graphics2D gLeaf = (Graphics2D) g.create();
>> + leaf.paint(gLeaf);
>> + if (debugBounds) {
>> + AffineTransform gtx = g.getTransform();
>> + Rectangle leafBounds = getBounds(gtx).getBounds();
>> + g.setTransform(new AffineTransform());
>> + g.setColor(Color.RED);
>> + g.drawRect(leafBounds.x, leafBounds.y,
>> + leafBounds.width-1,
>> + leafBounds.height-1);
>> + g.setTransform(gtx);
>> + }
>> + } else if (this instanceof SGFilter) {
>> + SGFilter filter = (SGFilter) this;
>> + SGNode child = filter.getChild();
>> + if (child != null) {
>> + Graphics2D gOrig = (Graphics2D) g.create();
>> + if (filter instanceof SGTransform) {
>> + AffineTransform newXform =
>> + ((SGTransform) filter).createAffineTransform();
>> + gOrig.transform(newXform);
>> + }
>> + if (filter.canSkipRendering()) {
>> + if (!filter.canSkipChildren()) {
>> + child.render(gOrig, dirtyRegion);
>> + }
>> + } else {
>> + int sourceType = filter.needsSourceContent();
>> + if (sourceType == SGFilter.NONE) {
>> + filter.setupRenderGraphics(gOrig);
>> + child.render(gOrig, dirtyRegion);
>> + } else if (sourceType == SGFilter.CACHED) {
>> + filter.renderFromCache(gOrig);
>> + } else {
>> + Image xformImage = null;
>> + Rectangle xformBounds = null;
>> + Image unxformImage = null;
>> + Rectangle unxformBounds =
>> child.getBounds().getBounds();
>> + if (unxformBounds.isEmpty()) {
>> + // nothing to render
>> + return;
>> + }
>> + GraphicsConfiguration gc =
>> gOrig.getDeviceConfiguration();
>> + AffineTransform gtx = gOrig.getTransform();
>> + if ((sourceType & SGFilter.TRANSFORMED) != 0) {
>> + xformBounds =
>> child.getBounds(gtx).getBounds();
>> + int nodeX = xformBounds.x;
>> + int nodeY = xformBounds.y;
>> + int nodeW = xformBounds.width;
>> + int nodeH = xformBounds.height;
>> + // TODO: image should be constrained to
>> the size of the clip
>> + if (filter instanceof SGRenderCache) {
>> + // SGRenderCache will hold onto the
>> image
>> + // for some time, so create a fresh one
>> + // (don't use the pool)
>> + xformImage =
>> Effect.createCompatibleImage(gc, nodeW, nodeH);
>> + } else {
>> + xformImage =
>> Effect.getCompatibleImage(gc, nodeW, nodeH);
>> + }
>> +
>> + Graphics2D gFilter =
>> + (Graphics2D) xformImage.getGraphics();
>> + AffineTransform filterXform =
>> +
>> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
>> + filterXform.concatenate(gtx);
>> + gFilter.setTransform(filterXform);
>> +
>> + filter.setupRenderGraphics(gFilter);
>> + child.render(gFilter, dirtyRegion);
>> +
>> +
>> gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX, nodeY));
>> + }
>> + if ((sourceType & SGFilter.UNTRANSFORMED) !=
>> 0) {
>> + if (xformImage != null &&
>> gtx.isIdentity()) {
>> + // in this case there will be no
>> difference
>> + // between xformImage and
>> unxformImage; we
>> + // can reuse xformImage instead of
>> creating
>> + // what would essentially be a
>> duplicate image
>> + unxformImage = xformImage;
>> + } else {
>> + int nodeX = unxformBounds.x;
>> + int nodeY = unxformBounds.y;
>> + int nodeW = unxformBounds.width;
>> + int nodeH = unxformBounds.height;
>> + unxformImage =
>> Effect.getCompatibleImage(gc, nodeW, nodeH);
>> +
>> + Graphics2D gFilter =
>> + (Graphics2D)
>> unxformImage.getGraphics();
>> + AffineTransform filterXform =
>> +
>> AffineTransform.getTranslateInstance(-nodeX, -nodeY);
>> + gFilter.setTransform(filterXform);
>> +
>> + filter.setupRenderGraphics(gFilter);
>> + child.render(gFilter, dirtyRegion);
>> +
>> + // TODO: we have very little support for
>> + // untransformed source effects at
>> this time;
>> + // this needs to be fixed asap...
>> +
>> //gOrig.setTransform(AffineTransform.getTranslateInstance(nodeX, nodeY));
>> + }
>> + }
>> +
>> + SGSourceContent sourceContent =
>> + new SGSourceContent(gtx,
>> + unxformImage,
>> unxformBounds,
>> + xformImage,
>> xformBounds);
>> +
>> + filter.renderFinalImage(gOrig, sourceContent);
>> +
>> + if (unxformImage != null) {
>> + Effect.releaseCompatibleImage(gc,
>> unxformImage);
>> + }
>> + if (xformImage != null && xformImage !=
>> unxformImage) {
>> + Effect.releaseCompatibleImage(gc,
>> xformImage);
>> + }
>> + }
>> + }
>> + }
>> + } else if (this instanceof SGParent) {
>> + for (SGNode child : ((SGParent) this).getChildren()) {
>> + child.render(g, dirtyRegion);
>> + }
>> + }
>> + }
>> +
>> /*
>> * Event handling below...
>> */
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: commits-unsubscribe@scenegraph.dev.java.net
>> For additional commands, e-mail: commits-help@scenegraph.dev.java.net
>>
>
> Joshua Marinacci, Sun Engineer
> http://weblogs.java.net/blog/joshy/
> http://joshy.org/
> joshua@marinacci.org
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscribe@scenegraph.dev.java.net
> For additional commands, e-mail: dev-help@scenegraph.dev.java.net
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@scenegraph.dev.java.net
For additional commands, e-mail: dev-help@scenegraph.dev.java.net