Author Topic: How to Hardware Mode  (Read 19393 times)

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
How to Hardware Mode
« on: February 24, 2008, 09:04:22 pm »
I am having a little trouble getting my applet to run in SAMPLINGMODE_HARDWARE_ONLY.
The Sun Java Console shows:
Code: [Select]
Java version is: 1.6.0_03
-> support for BufferedImage
Version helper for 1.2+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
java.lang.NoClassDefFoundError: org/lwjgl/opengl/Display
at com.threed.jpct.GLHelper.findMode(Unknown Source)
at com.threed.jpct.GLHelper.init(Unknown Source)
at com.threed.jpct.GLRenderer.init(Unknown Source)
at com.threed.jpct.FrameBuffer.enableRenderer(Unknown Source)
at com.threed.jpct.FrameBuffer.enableRenderer(Unknown Source)
at com.threed.jpct.FrameBuffer.enableRenderer(Unknown Source)
at jPCTGears.init(jPCTGears.java:48)
at sun.applet.AppletPanel.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

Here is the code in question:
Code: [Select]
    // Initialize all components of the applet
    @Override
    public void init()
    {
        // sign the applet up to receive mouse messages:
        addMouseListener( this );
        addMouseMotionListener( this );
       
        world = new World();  // create a new world
       
        World.setDefaultThread(Thread.currentThread());

        // create a new buffer to draw on:
        buffer = new FrameBuffer( width, height, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY );
        buffer.enableRenderer( IRenderer.RENDERER_OPENGL );
        buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );

        // load some 3D objects and make sure they have the correct orientation:
        redGear = loadMeshFile( "RedGear.3ds" );
        redGear.rotateY( (float)Math.PI / 2.0f );
        redGear.rotateMesh();
        redGear.setRotationMatrix( new Matrix() );
        redGear.setOrigin( new SimpleVector( 0, 0, 0 ) );
        redGear.build();
        greenGear = loadMeshFile( "GreenGear.3ds" );
        greenGear.rotateY( (float)Math.PI / 2.0f );
        greenGear.rotateZ( 0.35f );
        greenGear.rotateMesh();
        greenGear.setRotationMatrix( new Matrix() );
        greenGear.setOrigin( new SimpleVector( -145.0f, 0, 0 ) );
        greenGear.build();
        blueGear = loadMeshFile( "BlueGear.3ds" );
        blueGear.rotateY( (float)Math.PI / 2.0f );
        blueGear.rotateZ( 0.40f );
        blueGear.rotateMesh();
        blueGear.setRotationMatrix( new Matrix() );
        blueGear.setOrigin( new SimpleVector( 0, 135.0f, 0 ) );
        blueGear.build();

        // Set up a pivot point for the entire gear assembly:
        //assemblyPivot = new Object3D(1);
        assemblyPivot = Object3D.createDummyObj();
        assemblyPivot.setOrigin( new SimpleVector( 0, 0, 0 ) );
        // Make the gears children to assemblyPivot.
        // Translations and rotations to assemblyPivot
        // will affect the entire gear assembly:
        assemblyPivot.addChild( redGear );
        assemblyPivot.addChild( greenGear );
        assemblyPivot.addChild( blueGear );
               
        // add the objects our world:
        world.addObject( redGear );
        world.addObject( greenGear );
        world.addObject( blueGear );
        world.buildAllObjects();
       
        lookAt( redGear );  // make sure the camera is facing towards the object
        letThereBeLight();  // create light sources for the scene
    }

The applet only works when I use SAMPLINGMODE_NORMAL and RENDERER_SOFTWARE.  I am sure it is something simple I am doing incorrectly.  I am just having a little trouble figuring out what.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #1 on: February 24, 2008, 09:14:10 pm »
You have to include the lwjgl.jar into your classpath and point the VM to the native part (dll/so/...)  by adding a -Djava.library.path=<your path to the dlls> when starting your application. When using it in an applet, it's a different story. You have to download the native parts in that applet and install them locally (the applet has to be signed to do this). LWJGL (http://lwjgl.org) comes with an utility class (http://www.lwjgl.org/javadoc/org/lwjgl/util/applet/package-summary.html) to ease this.
« Last Edit: February 24, 2008, 09:15:46 pm by EgonOlsen »

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #2 on: February 25, 2008, 02:23:26 am »
I am using the AppletLoader now, but still having some troubles.  It is making it a bit further into the program, but crashing at Paint().  Here is the output from the Java Console:
Code: [Select]
Java version is: 1.6.0_03
-> support for BufferedImage
Version helper for 1.2+ initialized!
-> using BufferedImage
Software renderer (OpenGL mode) initialized
Current mode:640 x 480 x 32 @120Hz
Driver is: ati2dvag/6.14.10.6666 on ATI Technologies Inc. / RADEON XPRESS Series x86/MMX/3DNow!/SSE2
FBO supported and used!
OpenGL renderer initialized (using 4 texture stages)
Software renderer disposed
Loading file from InputStream
File from InputStream loaded...51142 bytes
Processing new material FlatRed!
Processing object from 3DS-file: Gear
Object 'Gear_jPCT0' created using 728 polygons and 364 vertices.
Loading file from InputStream
File from InputStream loaded...29586 bytes
Processing new material FlatGreen!
Processing object from 3DS-file: Gear
Object 'Gear_jPCT1' created using 420 polygons and 210 vertices.
Loading file from InputStream
File from InputStream loaded...33504 bytes
Processing new material FlatBlue!
Processing object from 3DS-file: Gear
Object 'Gear_jPCT2' created using 476 polygons and 238 vertices.
Adding Lightsource: 0
Exception in thread "AWT-EventQueue-2" java.lang.NullPointerException
    at org.lwjgl.opengl.GL11.glClearColor(GL11.java:566)
    at com.threed.jpct.GLRenderer.execute(Unknown Source)
    at com.threed.jpct.FrameBuffer.clearHardware(Unknown Source)
    at com.threed.jpct.FrameBuffer.clear(Unknown Source)
    at com.threed.jpct.FrameBuffer.clear(Unknown Source)
    at jPCTGears.paint(jPCTGears.java:103)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)
    at javax.swing.RepaintManager.seqPaintDirtyRegions(Unknown Source)
    at javax.swing.SystemEventQueueUtilities$ComponentWorkRequest.run(Unknown Source)
    at java.awt.event.InvocationEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)

Here is the source code for my applet:
Code: [Select]
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.io.InputStream;

import javax.swing.JApplet;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import java.lang.System;

public class jPCTGears extends JApplet implements MouseListener, MouseMotionListener
{
    private Object3D redGear, greenGear, blueGear, assemblyPivot;
    private FrameBuffer buffer = null;
    private World world = null;
    private Camera camera = null;
    private int width = 640;
    private int height = 480;
    private float gear_rotation = 0.02f;
    private int prevMouseX, prevMouseY;
   
    // Initialize all components of the applet
    @Override
    public void init()
    {
        // sign the applet up to receive mouse messages:
        addMouseListener( this );
        addMouseMotionListener( this );
       
        world = new World();  // create a new world
       
        World.setDefaultThread(Thread.currentThread());

        // create a new buffer to draw on:
        buffer = new FrameBuffer( width, height, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY );
        buffer.enableRenderer( IRenderer.RENDERER_OPENGL );
        buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );

        // load some 3D objects and make sure they have the correct orientation:
        redGear = loadMeshFile( "RedGear.3ds" );
        redGear.rotateY( (float)Math.PI / 2.0f );
        redGear.rotateMesh();
        redGear.setRotationMatrix( new Matrix() );
        redGear.setOrigin( new SimpleVector( 0, 0, 0 ) );
        redGear.build();
        greenGear = loadMeshFile( "GreenGear.3ds" );
        greenGear.rotateY( (float)Math.PI / 2.0f );
        greenGear.rotateZ( 0.35f );
        greenGear.rotateMesh();
        greenGear.setRotationMatrix( new Matrix() );
        greenGear.setOrigin( new SimpleVector( -145.0f, 0, 0 ) );
        greenGear.build();
        blueGear = loadMeshFile( "BlueGear.3ds" );
        blueGear.rotateY( (float)Math.PI / 2.0f );
        //blueGear.rotateZ( 0.40f );
        blueGear.rotateMesh();
        blueGear.setRotationMatrix( new Matrix() );
        blueGear.setOrigin( new SimpleVector( 0, -140.0f, 0 ) );
        blueGear.build();

        // Set up a pivot point for the entire gear assembly:
        //assemblyPivot = new Object3D(1);
        assemblyPivot = Object3D.createDummyObj();
        assemblyPivot.setOrigin( new SimpleVector( 0, 0, 0 ) );
        // Make the gears children to assemblyPivot.
        // Translations and rotations to assemblyPivot
        // will affect the entire gear assembly:
        assemblyPivot.addChild( redGear );
        assemblyPivot.addChild( greenGear );
        assemblyPivot.addChild( blueGear );
               
        // add the objects our world:
        world.addObject( redGear );
        world.addObject( greenGear );
        world.addObject( blueGear );
        world.buildAllObjects();
       
        lookAt( redGear );  // make sure the camera is facing towards the object
        letThereBeLight();  // create light sources for the scene
    }

    // Draw the scene
    @Override
    public void paint( Graphics g )
    {
        // rotate the gears:
        redGear.rotateAxis( redGear.getZAxis(), -gear_rotation );
        greenGear.rotateAxis( greenGear.getZAxis(), 2.0f * gear_rotation );
        blueGear.rotateAxis( blueGear.getZAxis(), 2.0f * gear_rotation );
       
        buffer.clear();   // erase the previous frame

        // render the world onto the buffer:
        world.renderScene( buffer );
        world.draw( buffer );
        buffer.update();

        buffer.display(g, 0, 0);  // draw the buffer onto the applet frame
       
        repaint( 200, 0, 0, width, height );  // keep the graphics auto-refreshing
    }

    // Load a 3Ds file, and return its Object3D handle
    public Object3D loadMeshFile( String filename )
    {
        Object3D newObject;
        //Object3D[] objs = Loader.load3DS( myURL, "models" + "/" + filename, 1.0f );
        Object3D[] objs = Loader.load3DS( getResource( filename ), 1.0f );

        if( objs.length==1 )
        {
            // The object loaded fine, just need to initialize it
            newObject=objs[0];
            newObject.setCulling( Object3D.CULLING_DISABLED );
            newObject.build();
        }
        else
        {
            // Didn't load anything, or loaded
            //     more than 1 object (not supposed to happen)
            System.out.println( "Unknown file format: " + filename );
            newObject = null;
        }

        return newObject;
    }
   
    private InputStream getResource( String resourceName )
    {
        return getClass().getClassLoader().getResourceAsStream( resourceName );
    }
    // point the camera toward the given object
    private void lookAt( Object3D obj )
    {
        camera = world.getCamera();  // grab a handle to the camera
        camera.setPosition( 0, 0, 500 );  // set its *relative* position
        camera.lookAt( obj.getTransformedCenter() );  // look toward the object
    }

    // create light sources for the scene
    private void letThereBeLight()
    {
        world.getLights().setOverbrightLighting (
            Lights.OVERBRIGHT_LIGHTING_DISABLED );
        world.getLights().setRGBScale( Lights.RGB_SCALE_2X );

        // Set the overall brightness of the world:
        world.setAmbientLight( 50, 50, 50 );

        // Create a main light-source:
        world.addLight( new SimpleVector( 50, -50, 300 ), 20, 20, 20 );
    }
   
    // Dragging the mouse should rotate the entire gear assembly
    public void mouseDragged( MouseEvent e )
    {
        // get the mouse's coordinates:
        int x = e.getX();
        int y = e.getY();
        Dimension size = e.getComponent().getSize();

        // Calculate the angles to rotate the assembly:
        float thetaY = (float)Math.PI * ( (float)(x-prevMouseX)/(float)size.width );
        float thetaX = (float)Math.PI * ( (float)(prevMouseY-y)/(float)size.height );
       
        // Apply the rotations to the gear assembly:
        assemblyPivot.rotateAxis( assemblyPivot.getXAxis(), thetaX );
        assemblyPivot.rotateAxis( assemblyPivot.getYAxis(), thetaY );

        // Keep track of the mouse location:
        prevMouseX = x;
        prevMouseY = y;
    }
    public void mousePressed( MouseEvent e )
    {
        // Start keeping track of the mouse location now.
        // This prevent the gear assembly from jerking to the new angle
        // whenever mouseDragged first gets called:
        prevMouseX = e.getX();
        prevMouseY = e.getY();
    }
    public void mouseReleased( MouseEvent e ){}
    public void mouseEntered( MouseEvent e ) {}
    public void mouseExited( MouseEvent e ) {}
    public void mouseClicked( MouseEvent e ) {}
    public void mouseMoved( MouseEvent e ) {}
}

Another issue I had, was that I was forced to put my 3ds files into the JAR, because when using the AppletLoader, it seems like the loader can't find them.

I guess I just need to do some more googling about that AppletLoader - it is certainly not as plug-and-play as it looks.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #3 on: February 25, 2008, 08:13:48 am »
jPCT offers two hardware modes. One renders into a native GL-Window, the other one into an AWT Canvas. To render directly into an applet, you have to use the latter, which can be enabled by using FrameBuffer.enableGLCanvasRenderer(); (it returns the Canvas, so that you can add it to the applet).
I can't comment about the 3ds-jar-problem, because i usually put my resources into jars...it's less troublesome and required for webstart, which is what i'm using most of the time. May be related to the AppletLoader using another class loader or something... ???

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #4 on: February 26, 2008, 01:11:34 am »
I am getting closer - now at least there are no error messages.  Unfortunately, now my applet only draws a light-grey square.  I assume this has something to do with my not using the Canvas correctly.  Here is my code, in case you can see something I've obviously done incorrectly:

Code: [Select]
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.io.InputStream;

import javax.swing.JApplet;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import java.lang.System;

public class jPCTGears extends JApplet implements MouseListener, MouseMotionListener
{
    private Object3D redGear, greenGear, blueGear, assemblyPivot;
    private FrameBuffer buffer = null;
    private World world = null;
    private Camera camera = null;
    private int width = 640;
    private int height = 480;
    private float gear_rotation = 0.02f;
    private int prevMouseX, prevMouseY;
   
    Canvas myCanvas;
   
    // Initialize all components of the applet
    @Override
    public void init()
    {
        // sign the applet up to receive mouse messages:
        addMouseListener( this );
        addMouseMotionListener( this );
       
        world = new World();  // create a new world
       
        World.setDefaultThread( Thread.currentThread() );

        // create a new buffer to draw on:
        buffer = new FrameBuffer( width, height, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY );
        buffer.enableRenderer( IRenderer.RENDERER_OPENGL );
        buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );
       
        myCanvas = buffer.enableGLCanvasRenderer();
        add( myCanvas, BorderLayout.CENTER);
        myCanvas.setVisible( true );
       
        // load some 3D objects and make sure they have the correct orientation:
        redGear = loadMeshFile( "RedGear.3ds" );
        redGear.rotateY( (float)Math.PI / 2.0f );
        redGear.rotateMesh();
        redGear.setRotationMatrix( new Matrix() );
        redGear.setOrigin( new SimpleVector( 0, 0, 0 ) );
        redGear.build();
        greenGear = loadMeshFile( "GreenGear.3ds" );
        greenGear.rotateY( (float)Math.PI / 2.0f );
        greenGear.rotateZ( 0.35f );
        greenGear.rotateMesh();
        greenGear.setRotationMatrix( new Matrix() );
        greenGear.setOrigin( new SimpleVector( -145.0f, 0, 0 ) );
        greenGear.build();
        blueGear = loadMeshFile( "BlueGear.3ds" );
        blueGear.rotateY( (float)Math.PI / 2.0f );
        //blueGear.rotateZ( 0.40f );
        blueGear.rotateMesh();
        blueGear.setRotationMatrix( new Matrix() );
        blueGear.setOrigin( new SimpleVector( 0, -140.0f, 0 ) );
        blueGear.build();

        // Set up a pivot point for the entire gear assembly:
        assemblyPivot = Object3D.createDummyObj();
        assemblyPivot.setOrigin( new SimpleVector( 0, 0, 0 ) );
        // Make the gears children to assemblyPivot.
        // Translations and rotations to assemblyPivot
        // will affect the entire gear assembly:
        assemblyPivot.addChild( redGear );
        assemblyPivot.addChild( greenGear );
        assemblyPivot.addChild( blueGear );
               
        // add the objects our world:
        world.addObject( redGear );
        world.addObject( greenGear );
        world.addObject( blueGear );
        world.buildAllObjects();
       
        lookAt( redGear );  // make sure the camera is facing towards the object
        letThereBeLight();  // create light sources for the scene
    }

    // Draw the scene
    @Override
    public void paint( Graphics g )
    {
        // rotate the gears:
        redGear.rotateAxis( redGear.getZAxis(), -gear_rotation );
        greenGear.rotateAxis( greenGear.getZAxis(), 2.0f * gear_rotation );
        blueGear.rotateAxis( blueGear.getZAxis(), 2.0f * gear_rotation );
       
        buffer.clear();   // erase the previous frame

        // render the world onto the buffer:
        world.renderScene( buffer );
        world.draw( buffer );
        buffer.update();
       
        buffer.displayGLOnly();
        myCanvas.repaint( 200, 0, 0, width, height );
    }

    // Load a 3Ds file, and return its Object3D handle
    public Object3D loadMeshFile( String filename )
    {
        Object3D newObject;
        //Object3D[] objs = Loader.load3DS( myURL, "models" + "/" + filename, 1.0f );
        Object3D[] objs = Loader.load3DS( getResource( filename ), 1.0f );

        if( objs.length==1 )
        {
            // The object loaded fine, just need to initialize it
            newObject=objs[0];
            newObject.setCulling( Object3D.CULLING_DISABLED );
            newObject.build();
        }
        else
        {
            // Didn't load anything, or loaded
            //     more than 1 object (not supposed to happen)
            System.out.println( "Unknown file format: " + filename );
            newObject = null;
        }

        return newObject;
    }
   
    private InputStream getResource( String resourceName )
    {
        return getClass().getClassLoader().getResourceAsStream( resourceName );
    }
    // point the camera toward the given object
    private void lookAt( Object3D obj )
    {
        camera = world.getCamera();  // grab a handle to the camera
        camera.setPosition( 0, 0, 500 );  // set its *relative* position
        camera.lookAt( obj.getTransformedCenter() );  // look toward the object
    }

    // create light sources for the scene
    private void letThereBeLight()
    {
        world.getLights().setOverbrightLighting (
            Lights.OVERBRIGHT_LIGHTING_DISABLED );
        world.getLights().setRGBScale( Lights.RGB_SCALE_2X );

        // Set the overall brightness of the world:
        world.setAmbientLight( 50, 50, 50 );

        // Create a main light-source:
        world.addLight( new SimpleVector( 50, -50, 300 ), 20, 20, 20 );
    }
   
    // Dragging the mouse should rotate the entire gear assembly
    public void mouseDragged( MouseEvent e )
    {
        // get the mouse's coordinates:
        int x = e.getX();
        int y = e.getY();
        Dimension size = e.getComponent().getSize();

        // Calculate the angles to rotate the assembly:
        float thetaY = (float)Math.PI * ( (float)(x-prevMouseX)/(float)size.width );
        float thetaX = (float)Math.PI * ( (float)(prevMouseY-y)/(float)size.height );
       
        // Apply the rotations to the gear assembly:
        assemblyPivot.rotateAxis( assemblyPivot.getXAxis(), thetaX );
        assemblyPivot.rotateAxis( assemblyPivot.getYAxis(), thetaY );

        // Keep track of the mouse location:
        prevMouseX = x;
        prevMouseY = y;
    }
    public void mousePressed( MouseEvent e )
    {
        // Start keeping track of the mouse location now.
        // This prevent the gear assembly from jerking to the new angle
        // whenever mouseDragged first gets called:
        prevMouseX = e.getX();
        prevMouseY = e.getY();
    }
    public void mouseReleased( MouseEvent e ){}
    public void mouseEntered( MouseEvent e ) {}
    public void mouseExited( MouseEvent e ) {}
    public void mouseClicked( MouseEvent e ) {}
    public void mouseMoved( MouseEvent e ) {}
}

BTW, I appreciate the assistance you've been giving me.

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #5 on: February 26, 2008, 08:18:08 am »
You mean that the complete canvas is grey? Or are the textures just missing? Anyway, try to remove

Code: [Select]
buffer.enableRenderer( IRenderer.RENDERER_OPENGL );

It's not needed in this case, because you don't want the native renderer anyway (which you are initializing with this call). I'm not sure if this will already fix your problem, but it should be removed.

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #6 on: February 26, 2008, 01:33:07 pm »
Removing that line helped (before the complete canvas was grey).  Now, with that line removed, I am getting a black screen (no textures are being drawn).

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #7 on: February 26, 2008, 05:06:37 pm »
The AWTGLRenderer doesn't really draw anything when you are calling draw(), but it enqueues the calls to be executed in the AWT event thread dispatch instead (i.e. in the AWTGLCanvas' paint()-method). Your code works, you just don't get any repaint events for the applet, which is why nothing moves. Maybe it's not possible in all cases to schedule a repaint() from inside paint()...i'm not sure. However, i've modified your applet slightly to start an additional thread that just makes the applet repaint itself, i.e. execute your drawing code.
Personally, i wouldn't do it that way, but make my own thread that does the calculations and leave the applets paint() alone. That way, you'll benefit from a feature of the AWTGLRenderer: It runs multithreaded, i.e. calculations in one thread, drawing in another (in the AWT event dispatch thread in this case). In your code, both operations happen in the AWT EDT. I haven't modified your code to work that way (i.e. move the code from paint into that thread's loop), because it requires some more work: Your mouse listeners are modifying jPCT objects directly, but jPCT isn't thread save, i.e. you shouldn't modify a jPCT object from another thread than the rendering thread. Instead, the listeners should just flag what they want to do and let the calculation thread execute the operations. Anyway, here's the modified example:

Code: [Select]
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;

import java.io.InputStream;

import javax.swing.JApplet;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.IRenderer;
import com.threed.jpct.Lights;
import com.threed.jpct.Loader;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.World;

import java.lang.System;

public class jPCTGears extends JApplet implements MouseListener, MouseMotionListener, Runnable
{
    private Object3D redGear, greenGear, blueGear, assemblyPivot;
    private FrameBuffer buffer = null;
    private World world = null;
    private Camera camera = null;
    private int width = 640;
    private int height = 480;
    private float gear_rotation = 0.02f;
    private int prevMouseX, prevMouseY;
    private boolean loop=true;
   
    Canvas myCanvas;
   
    // Initialize all components of the applet
    public void init()
    {
        // sign the applet up to receive mouse messages:
        world = new World();  // create a new world
       
        World.setDefaultThread( Thread.currentThread() );

        // create a new buffer to draw on:
        buffer = new FrameBuffer( width, height, FrameBuffer.SAMPLINGMODE_HARDWARE_ONLY );
        buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );
       
        myCanvas = buffer.enableGLCanvasRenderer();
        add( myCanvas, BorderLayout.CENTER);
        myCanvas.setVisible( true );
       
        // load some 3D objects and make sure they have the correct orientation:
        redGear = loadMeshFile( "RedGear.3ds" );
        redGear.rotateY( (float)Math.PI / 2.0f );
        redGear.rotateMesh();
        redGear.setRotationMatrix( new Matrix() );
        redGear.setOrigin( new SimpleVector( 0, 0, 0 ) );
        redGear.build();
        greenGear = loadMeshFile( "GreenGear.3ds" );
        greenGear.rotateY( (float)Math.PI / 2.0f );
        greenGear.rotateZ( 0.35f );
        greenGear.rotateMesh();
        greenGear.setRotationMatrix( new Matrix() );
        greenGear.setOrigin( new SimpleVector( -145.0f, 0, 0 ) );
        greenGear.build();
        blueGear = loadMeshFile( "BlueGear.3ds" );
        blueGear.rotateY( (float)Math.PI / 2.0f );
        //blueGear.rotateZ( 0.40f );
        blueGear.rotateMesh();
        blueGear.setRotationMatrix( new Matrix() );
        blueGear.setOrigin( new SimpleVector( 0, -140.0f, 0 ) );
        blueGear.build();

        // Set up a pivot point for the entire gear assembly:
        assemblyPivot = Object3D.createDummyObj();
        assemblyPivot.setOrigin( new SimpleVector( 0, 0, 0 ) );
        // Make the gears children to assemblyPivot.
        // Translations and rotations to assemblyPivot
        // will affect the entire gear assembly:
        assemblyPivot.addChild( redGear );
        assemblyPivot.addChild( greenGear );
        assemblyPivot.addChild( blueGear );
               
        // add the objects our world:
        world.addObject( redGear );
        world.addObject( greenGear );
        world.addObject( blueGear );
        world.buildAllObjects();
       
        lookAt( redGear );  // make sure the camera is facing towards the object
        letThereBeLight();  // create light sources for the scene
       
        myCanvas.addMouseListener( this );
        myCanvas.addMouseMotionListener( this );
       
        new Thread(this).start();
    }

    // Draw the scene
    public void paint( Graphics g )
    {
    redGear.rotateAxis( redGear.getZAxis(), -gear_rotation );
        greenGear.rotateAxis( greenGear.getZAxis(), 2.0f * gear_rotation );
        blueGear.rotateAxis( blueGear.getZAxis(), 2.0f * gear_rotation );
       
        buffer.clear();   // erase the previous frame

        // render the world onto the buffer:
        world.renderScene( buffer );
        world.draw( buffer );
        buffer.update();
       
        buffer.displayGLOnly();
        myCanvas.repaint();
    }
   
    public void destroy() {
    loop=false;
    }
   
    public void run() {
    while (loop) {
    this.repaint();
        try {
        Thread.sleep(10);
        } catch(Exception e) {
        //Don't care...
        }
    }
    }

    // Load a 3Ds file, and return its Object3D handle
    public Object3D loadMeshFile( String filename )
    {
        Object3D newObject;
        //Object3D[] objs = Loader.load3DS( myURL, "models" + "/" + filename, 1.0f );
        Object3D[] objs = Loader.load3DS( getResource( filename ), 1.0f );

        if( objs.length==1 )
        {
            // The object loaded fine, just need to initialize it
            newObject=objs[0];
            newObject.setCulling( Object3D.CULLING_DISABLED );
            newObject.build();
        }
        else
        {
            // Didn't load anything, or loaded
            //     more than 1 object (not supposed to happen)
            System.out.println( "Unknown file format: " + filename );
            newObject = null;
        }

        return newObject;
    }
   
    private InputStream getResource( String resourceName )
    {
        return getClass().getClassLoader().getResourceAsStream( resourceName );
    }
    // point the camera toward the given object
    private void lookAt( Object3D obj )
    {
        camera = world.getCamera();  // grab a handle to the camera
        camera.setPosition( 0, 0, 500 );  // set its *relative* position
        camera.lookAt( obj.getTransformedCenter() );  // look toward the object
    }

    // create light sources for the scene
    private void letThereBeLight()
    {
        world.getLights().setOverbrightLighting (
            Lights.OVERBRIGHT_LIGHTING_DISABLED );
        world.getLights().setRGBScale( Lights.RGB_SCALE_2X );

        // Set the overall brightness of the world:
        world.setAmbientLight( 50, 50, 50 );

        // Create a main light-source:
        world.addLight( new SimpleVector( 50, -50, 300 ), 20, 20, 20 );
    }
   
    // Dragging the mouse should rotate the entire gear assembly
    public void mouseDragged( MouseEvent e )
    {
        // get the mouse's coordinates:
        int x = e.getX();
        int y = e.getY();
        Dimension size = e.getComponent().getSize();

        // Calculate the angles to rotate the assembly:
        float thetaY = (float)Math.PI * ( (float)(x-prevMouseX)/(float)size.width );
        float thetaX = (float)Math.PI * ( (float)(prevMouseY-y)/(float)size.height );
       
        // Apply the rotations to the gear assembly:
        assemblyPivot.rotateAxis( assemblyPivot.getXAxis(), thetaX );
        assemblyPivot.rotateAxis( assemblyPivot.getYAxis(), thetaY );

        // Keep track of the mouse location:
        prevMouseX = x;
        prevMouseY = y;
    }
    public void mousePressed( MouseEvent e )
    {
        // Start keeping track of the mouse location now.
        // This prevent the gear assembly from jerking to the new angle
        // whenever mouseDragged first gets called:
        prevMouseX = e.getX();
        prevMouseY = e.getY();
    }
    public void mouseReleased( MouseEvent e ){}
    public void mouseEntered( MouseEvent e ) {}
    public void mouseExited( MouseEvent e ) {}
    public void mouseClicked( MouseEvent e ) {}
    public void mouseMoved( MouseEvent e ) {}
}
« Last Edit: February 26, 2008, 05:23:18 pm by EgonOlsen »

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #8 on: February 26, 2008, 10:02:28 pm »
Ah, that is a smart way for telling the applet to keep repainting itself.  Unfortunately, there still seems to be another problem - the applet is still showing up black even with these additions.

On another note, about the applet needing to repaint itself.  I had that problem when I started writing my first jPCT applet.  Originally, I had fixed this by sticking:
Code: [Select]
repaint( 200, 0, 0, width, height );
At the bottom of the paint() function.  Supposedly, this tells the applet to repaint itself "within 200 miliseconds" (I arbitrarily chose the number 200), and it works well for me when I am doing the applet in software-rendering mode (see my previous thread "Switching Between Pivot Points").  It is a bit cleaner, but essentially, I think this does the same thing as repainting from the loop ( in your case, you are waiting 10 miliseconds between calls to paint() ).

Unfortunately, neither of these two methods are working for the applet in question - still just getting a black screen, so I am guessing there is another problem in addition to telling the applet to repaint itself.

At least I am one problem closer to the solution  ;D

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #9 on: February 26, 2008, 10:18:48 pm »
Hmm...the applet works for me in the AppletViewer with exactly the code that i've posted. I haven't tried it in a browser though.
About repaint(): Personally, i don't like the fact that repaint() doesn't really paint anything. It's a just a suggestion to the underlying graphics subsystem that the component needs repainting. The system decides when...i dislike this when it comes to smooth animation and such stuff.

As proof:


« Last Edit: February 26, 2008, 10:30:16 pm by EgonOlsen »

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #10 on: February 26, 2008, 10:54:49 pm »
Wow.  Here is something odd for you:  I thought the problem might be related to there not being enough light, so I vamped up the ambient light to 150.  It worked then (Insanely bright, of course).  I then tried slowly adjusting the ambient light down to a good level, and reached 50 ( where i started ??? ) and now the thing works.  Darndest thing I ever saw.

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #11 on: February 26, 2008, 10:59:26 pm »
ROFL  -- Only me.  I am at a complete loss.  Well, anyway, I guess it works now...

Thanks for you help!

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #12 on: February 27, 2008, 12:08:38 am »
I hate to beat a dead horse, but I tend to be really thorough when learning a new concept.  So now I know how to run in either software mode or hardware mode from within an applet.  Now my ultimate goal with this concept is the ability to switch between the two modes dynamically.  Here are the changes I made to my code:

In init(), (so I still get mouse input when the canvas gets deleted):
Code: [Select]
        // receive mouse input from the main applet:
        addMouseListener( this );
        addMouseMotionListener( this );

        // also get mouse input picked up by the canvas:
        myCanvas.addMouseListener( this );
        myCanvas.addMouseMotionListener( this );       

In paint():
Code: [Select]
        if( buffer.usesRenderer( IRenderer.RENDERER_SOFTWARE ) )
        {
            buffer.display( g, 0, 0);  // Paint this frame onto the applet
        }
        else
        {
            buffer.displayGLOnly();
            myCanvas.repaint();    // Paint the canvas onto the applet
        }

And finally, in mouseClicked() (The "dynamic switching" code):
Code: [Select]
    public void mouseClicked( MouseEvent e )
    {
        if( (e.getModifiers() & e.BUTTON3_MASK) != 0 )
        {
            if( buffer.usesRenderer( IRenderer.RENDERER_SOFTWARE ) )
            {
                // Switch to hardware mode
                buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );
                myCanvas = buffer.enableGLCanvasRenderer();
                add( myCanvas, BorderLayout.CENTER);
                myCanvas.setVisible( true );
                validate();
                // get mouse input picked up by the canvas:
                myCanvas.addMouseListener( this );
                myCanvas.addMouseMotionListener( this );
            }
            else
            {
                // Switch to software mode
                buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE );
                removeAll();
                validate();
            }
        }
    }

The idea here is to switch dynamically between modes when the right mouse-button is clicked.  This code works when going from hardware mode to software mode, but not the other way around.  I assume my problem has something to do with the threads, perhaps?

Offline EgonOlsen

  • Administrator
  • quad
  • *****
  • Posts: 12295
    • View Profile
    • http://www.jpct.net
Re: How to Hardware Mode
« Reply #13 on: February 27, 2008, 08:08:18 am »
Maybe...what exactly is the problem you are getting?

Offline paulscode

  • double
  • *****
  • Posts: 863
    • View Profile
    • PaulsCode.Com
Re: How to Hardware Mode
« Reply #14 on: February 27, 2008, 01:30:28 pm »
The applet freezes (no refreshing).  The JAVA Console says "OpenGL (AWTGLCanvas) renderer disposed" immediately before the crash.  No error messages after that, though.