I'm going to create a small 2D/3D CAD tool using Java3D. One thing that a user should 
be able to do with the tool is to draw 2D geometries (rectangle, ellipse, etc.) using 
the mouse. My idea is that the user should be able to rotate the 3D scene to an 
arbitrary view (in order to get a 2D work plane), then draw 2D geomtries using the 
mouse, having the locked 3D view as background. I have tested a couple ways of doing 
this but no way that looks good or is fast enough. Maybe someone can give me some help 
here?

My 3D scene is quite large (300-400 Shape3D nodes (using LineArray and TriangleArray) 
will be common) and I want to have rubberband effects when drawing the 2D geometries. 
Here are the different approaches I have tested:

- Java2D on Canvas3D (see HelloUniverse.java below)
Very slow. The idea was to do rubberbanding effects etc. using Java2D which is fast if 
Java3D is not present. Then when the user finishes the draw event the start and stop 
coordinates would be used to create a Shape3D node. The rubberband effect is very 
slow. Maybe I am doing something wrong?

- Start/Stop renderer and GraphicsContext3D (see MixedImmediateFront.java below)
The rubberband effects are fast but flickering. It is not easy to see the flicker with 
the example below, but when you try to something more advanced like drawing a cirle 
you can see the irritating flicker.

- MouseListeners on Canvas3D and Shape3D.setGeometry
Draw directly in to Java3D by changing the geometry of a Shape3D gives me something 
that looks nice, but unfortunately the rubberband effects become too slow when having 
large 3D scenes. If it is possible to speed this approach up I would really like to 
use it (then I could just skip using Java2D in my CAD tool). Is there a way to tell 
the renderer that most of the scene should not be rendered (most of the scene will not 
change)? Are there any other ways to speed this up?

I have seen a lot of messages on this interest group about overlays etc. I have also 
tried to figure out wheter the overlay library from Columbia University is something 
that I should use for this? Any ideas?

/Anders



/* BEGIN: HelloUniverse ------------------------------------------ */
import com.sun.j3d.utils.behaviors.mouse.MouseTranslate;
import com.sun.j3d.utils.behaviors.mouse.MouseRotate;
import com.sun.j3d.utils.behaviors.mouse.MouseZoom;
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.BufferedImage;
import java.awt.font.TextLayout;
import java.awt.font.FontRenderContext;
import java.io.*;
import java.util.*;

public class HelloUniverse extends Applet {
  private HelloCanvas3D c;

    public BranchGroup createSceneGraph(Canvas3D canvas) {
        // Create the root of the branch graph
        BranchGroup objRoot = new BranchGroup();

        // Create the transform group node and initialize it to the
        // identity.  Enable the TRANSFORM_WRITE capability so that
        // our behavior code can modify it at runtime.  Add it to the
        // root of the subgraph.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        objRoot.addChild(objTrans);

        // Create a simple shape leaf node, add it to the scene graph.
        objTrans.addChild(new ColorCube(0.4));

        BoundingSphere bounds=new BoundingSphere(new Point3d(0.0,0.0,0.0),100.0);

        // Create the rotate behavior node
        MouseRotate behavior=new MouseRotate(objTrans);
        objTrans.addChild(behavior);
        behavior.setSchedulingBounds(bounds);


        // Have Java 3D perform optimizations on this scene graph.
        objRoot.compile();

        return objRoot;
    }

    class HelloCanvas3D extends Canvas3D {
        private GraphicsContext3D gc;
        private J3DGraphics2D g2 = null;
        private Dimension     d = new Dimension(0, 0);

        public HelloCanvas3D(GraphicsConfiguration gcfg) {
            super(gcfg,false);
        }

        public void postRender() {
          if (g2 == null) {
            g2 = this.getGraphics2D();
            g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
                            RenderingHints.VALUE_ANTIALIAS_ON);
          }
          this.getSize(d);
          drawDemo(d.width, d.height, g2);
            g2.flush(false);
        }
}

    public void drawDemo(int w, int h, J3DGraphics2D g2) {
        g2.setColor(new Color(1.0f,1.0f,1.0f));
        g2.drawString("abc 123", 50, 50);
    }



    public HelloUniverse() {
        setLayout(new BorderLayout());
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        c = new HelloCanvas3D(config);
        add("Center", c);


        // Create a simple scene and attach it to the virtual universe
        BranchGroup scene = createSceneGraph(c);
        SimpleUniverse u = new SimpleUniverse(c);

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        u.getViewingPlatform().setNominalViewingTransform();

        u.addBranchGraph(scene);
    }

    //
    // The following allows HelloUniverse to be run as an application
    // as well as an applet
    //
    public static void main(String[] args) {
        new MainFrame(new HelloUniverse(), 256, 256);
    }
}
/* END: HelloUniverse ------------------------------------------ */


/* BEGIN: MixedImmediateFront ----------------------------------- */
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.GraphicsConfiguration;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;
import java.awt.image.DataBufferInt;
import java.awt.image.BufferedImage;
import java.util.Enumeration;
import java.text.NumberFormat;

/**
 * An example of mixing immediate mode rendering with normal rendering.  The
 * "HelloUniverse" spinning cube is draw until there is a mouse button pressed.
 * Then a rubber-band line is drawn in immediate mode in front of the existing
 * image by making updates to the front buffer.  The previous lines (if any)
 * are "undrawn" by drawing them with the XOR raster op.
 */
public class MixedImmediateFront extends Applet {

    Canvas3D            canvas;

    GraphicsContext3D   gc = null;
    LineArray           line = null;
    Transform3D         sphereTransform = new Transform3D();

    WakeupCriterion[]   mouseEvents;
    WakeupOr            mouseCriterion;
    boolean             rendererRunning = true;

    Point3d             coords[] = new Point3d[2];
    Point3d             baseMouse = new Point3d();
    Point3d             curMouse = new Point3d();
    Transform3D         ipToVworld = new Transform3D();

    Appearance          whiteAppearance;

    // only works in single buffer mode right now
    static final boolean singleBuffer = false;

    public void setBase(int x, int y) {
        canvas.getPixelLocationInImagePlate(x, y, baseMouse);
        canvas.getImagePlateToVworld(ipToVworld);
        ipToVworld.transform(baseMouse);
    }

    public void render(int x, int y) {
        if (line != null) {
            gc.draw(line);
        }

        canvas.getPixelLocationInImagePlate(x, y, curMouse);
        canvas.getImagePlateToVworld(ipToVworld);
        ipToVworld.transform(curMouse);

        line = new LineArray(2, LineArray.COORDINATES);
        coords[0] = baseMouse;
        coords[1] = curMouse;
        line.setCoordinates(0, coords);

        // Render the geometry for this frame
        gc.draw(line);

        // flush to make sure the display is correct
        gc.flush(false);

    }



    //
    //Applet init routine (called by browser or by MainFrame)
    //
    public void init() {
        setLayout(new BorderLayout());

        canvas = new Canvas3D(SimpleUniverse.getPreferredConfiguration());

        if (singleBuffer) {
            canvas.setDoubleBufferEnable(false);
        }

        add("Center", canvas);

        // set up the graphics context
        gc = canvas.getGraphicsContext3D();
        gc.setBufferOverride(true);

        // set up the appearances
        RenderingAttributes ra = new RenderingAttributes();
        ra.setDepthBufferEnable(false);
        ra.setRasterOpEnable(true);
        ra.setRasterOp(RenderingAttributes.ROP_XOR);
        whiteAppearance = new Appearance();
        whiteAppearance.setRenderingAttributes(ra);

        gc.setAppearance(whiteAppearance);

        // Create a simple scene and attach it to the virtual universe
        SimpleUniverse u = new SimpleUniverse(canvas);

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        u.getViewingPlatform().setNominalViewingTransform();

        BranchGroup scene = createSceneGraph();
        u.addBranchGraph(scene);

        BranchGroup behaviorRoot = new BranchGroup();
        behaviorRoot.addChild(new Callback());
        u.addBranchGraph(behaviorRoot);
    }


    public class Callback extends Behavior {
        public void initialize() {
            mouseEvents = new WakeupCriterion[3];
            mouseEvents[0] = new WakeupOnAWTEvent(MouseEvent.MOUSE_DRAGGED);
            mouseEvents[1] = new WakeupOnAWTEvent(MouseEvent.MOUSE_PRESSED);
            mouseEvents[2] = new WakeupOnAWTEvent(MouseEvent.MOUSE_RELEASED);
            mouseCriterion = new WakeupOr(mouseEvents);
            wakeupOn (mouseCriterion);
            setSchedulingBounds(new BoundingSphere(new Point3d(),1000));
        }

        public void processStimulus (Enumeration criteria) {
            WakeupCriterion wakeup;
            AWTEvent[] event;
            int id;
            int dx, dy;

            while (criteria.hasMoreElements()) {
                wakeup = (WakeupCriterion) criteria.nextElement();
                if (wakeup instanceof WakeupOnAWTEvent) {
                    event = ((WakeupOnAWTEvent)wakeup).getAWTEvent();
                    for (int i=0; i<event.length; i++) {
                        MouseEvent mevent = (MouseEvent) event[i];
                        if (!mevent.isMetaDown() &&
                            !mevent.isAltDown()){

                            id = event[i].getID();

                            switch (id) {
                              case MouseEvent.MOUSE_PRESSED:
                                setBase(mevent.getX(), mevent.getY());
                                // no break here on purpose, fall through to
                                // drag case
                              case MouseEvent.MOUSE_DRAGGED:
                                if (rendererRunning) {
                                    canvas.stopRenderer();
                                    rendererRunning = false;
                                    gc.setFrontBufferRendering(true);

                                }
                                render(mevent.getX(), mevent.getY());
                                break;
                              case MouseEvent.MOUSE_RELEASED:
                                //System.out.println("start renderer");
                                if (!singleBuffer) {
                                    gc.setFrontBufferRendering(false);
                                }
                                canvas.startRenderer();
                                rendererRunning = true;

                                // no need to undraw previous anymore
                                line = null;
                                break;
                            }
                        }
                    }
                }
            }
            wakeupOn (mouseCriterion);
        }
    }

    public BranchGroup createSceneGraph() {
        // Create the root of the branch graph
        BranchGroup objRoot = new BranchGroup();

        // Create the transform group node and initialize it to the
        // identity.  Enable the TRANSFORM_WRITE capability so that
        // our behavior code can modify it at runtime.  Add it to the
        // root of the subgraph.
        TransformGroup objTrans = new TransformGroup();
        objTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
        objRoot.addChild(objTrans);

        // Create a simple shape leaf node, add it to the scene graph.
        objTrans.addChild(new ColorCube(0.4));

        // Create a new Behavior object that will perform the desired
        // operation on the specified transform object and add it into
        // the scene graph.
        Transform3D yAxis = new Transform3D();
        Alpha rotationAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,
                                        0, 0,
                                        4000, 0, 0,
                                        0, 0, 0);

        RotationInterpolator rotator =
            new RotationInterpolator(rotationAlpha, objTrans, yAxis,
                                     0.0f, (float) Math.PI*2.0f);
        BoundingSphere bounds =
            new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
        rotator.setSchedulingBounds(bounds);
        objTrans.addChild(rotator);

        // Have Java 3D perform optimizations on this scene graph.
        objRoot.compile();

        return objRoot;
    }

    //
    // The following allows MixedImmediateFront to be run as an application
    // as well as an applet
    //
    public static void main(String[] args) {
        new MainFrame(new MixedImmediateFront(), 600, 600);
    }
}
/* END: MixedImmediateFront ----------------------------------- */

===========================================================================
To unsubscribe, send email to [EMAIL PROTECTED] and include in the body
of the message "signoff JAVA3D-INTEREST".  For general help, send email to
[EMAIL PROTECTED] and include in the body of the message "help".

Reply via email to