Ok, I tried it in an application, and am having the same problem - no painting when switching back to hardware mode. Here is the code I am using for the application:
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.event.KeyEvent;
import java.io.InputStream;
import javax.swing.JFrame;
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 com.threed.jpct.util.KeyMapper;
import com.threed.jpct.util.KeyState;
import java.lang.System;
public class jPCTGearsApplication extends JFrame
{
private int width = 640;
private int height = 480;
private int titleBarHeight;
private int leftBorderWidth;
private Object3D redGear, greenGear, blueGear, assemblyPivot;
private float gear_rotation = 0.02f;
private boolean rotateLeft = false;
private boolean rotateRight = false;
private FrameBuffer buffer = null;
private World world = null;
private Camera camera = null;
private KeyMapper keyMapper;
private Graphics g = null;
private Canvas myCanvas;
private boolean exit = false;
public static void main( String[] args )
{
jPCTGearsApplication h = new jPCTGearsApplication();
}
// Draw the scene
@Override
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();
if( buffer.usesRenderer( IRenderer.RENDERER_SOFTWARE ) )
{
buffer.display( g, leftBorderWidth, titleBarHeight ); // Paint this frame
}
else
{
buffer.displayGLOnly();
myCanvas.repaint(); // Paint the canvas
}
}
private void mainLoop()
{
while( !exit )
{
poll();
rotateAssembly();
this.repaint();
try
{
Thread.sleep( 10 );
}
catch( Exception e ){} //Don't care...
}
System.exit(0);
}
public jPCTGearsApplication()
{
initFrame();
init3D();
mainLoop();
}
private void initFrame()
{
setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
setTitle( "Gears Demo in jPCT!" );
pack();
Insets insets = getInsets();
titleBarHeight = insets.top;
leftBorderWidth = insets.left;
setSize( width + leftBorderWidth + insets.right, height + titleBarHeight
+ insets.bottom );
setResizable( false );
setLocationRelativeTo( null );
setVisible( true );
g = getGraphics();
}
private void init3D()
{
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 );
keyMapper = new KeyMapper( myCanvas );
// 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
}
// 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 );
}
private void rotateAssembly()
{
float thetaX = 0;
float thetaY = 0;
float speed = 0.02f;
if( rotateLeft )
{
thetaX = speed;
thetaY = speed;
}
if( rotateRight )
{
thetaX = -speed;
thetaY = -speed;
}
// Apply the rotations to the gear assembly:
assemblyPivot.rotateAxis( assemblyPivot.getXAxis(), thetaX );
assemblyPivot.rotateAxis( assemblyPivot.getYAxis(), thetaY );
}
// Use the KeyMapper to poll the keyboard
private void poll()
{
KeyState state = null;
do
{
state = keyMapper.poll();
if( state != KeyState.NONE )
{
keyAffected( state );
}
} while( state != KeyState.NONE );
}
private void keyAffected( KeyState state )
{
int code = state.getKeyCode();
boolean event = state.getState();
switch( code )
{
case( KeyEvent.VK_ESCAPE ):
{
exit = event;
break;
}
case( KeyEvent.VK_LEFT ):
{
rotateLeft = !rotateLeft;
break;
}
case( KeyEvent.VK_RIGHT ):
{
rotateRight = !rotateRight;
break;
}
case( KeyEvent.VK_SPACE ):
{
if( event )
{
if( buffer.usesRenderer( IRenderer.RENDERER_SOFTWARE ) )
{
// Switch to hardware mode
buffer.disableRenderer( IRenderer.RENDERER_SOFTWARE );
myCanvas = buffer.enableGLCanvasRenderer();
add( myCanvas, BorderLayout.CENTER);
validate();
myCanvas.setVisible( true );
// get keyboard input from the canvas:
keyMapper = new KeyMapper( myCanvas );
}
else
{
// Switch to software mode
buffer.disableRenderer( IRenderer.RENDERER_OPENGL );
buffer.enableRenderer(IRenderer.RENDERER_SOFTWARE );
removeAll();
validate();
// get keyboard input from the "this"
keyMapper = new KeyMapper( this );
}
}
break;
}
}
}
}
As you can see, in this case, I am using keyboard inputs instead of mouse input, and only listening to keyboard input from either the canvas (when in hardware mode) or the main JFrame (when in software mode). The interesting thing about that is: whenever the application tries to switch back to hardware mode and has the problem, it stops getting keyboard inputs. That is exactly what I would expect in a case where the canvas were either not added or not visible. That's a little more confirmation of what we suspected earlier.
[UPDATE]
I have been doing some various tests, and found that adding the following into paint():
myCanvas.getGraphics().fillRoundRect( 0, 0, 100, 100, 10, 10 );
Causes a "null pointer exception". I thought this might be important.
[UPDATE #2]
Important breakthrough: In both places in my code, I tried replacing:
myCanvas = buffer.enableGLCanvasRenderer();
with:
buffer.enableGLCanvasRenderer();
myCanvas = new Canvas();
And I'm drawing a rectangle in paint(). The canvas is drawing the rectangle fine the first time, but when I right-click (remove the canvas), then right-click again (add a new canvas), it does not refresh. Then, when paint() tries to access myCanvas.getGraphics(), it throws the "null pointer exception".
This means there is not a bug with jPCT. As you suspected, I am somehow adding the canvas incorrectly. I just can't seem to figure out what I am doing wrong, lol. I'll try digging around on some different forums to see if anyone else has had a similar problem dynamically adding and deleting canvases before. I really appreciate the help!