* Ogre3D mesh.xml loader is now more resilient to certain models exported using blender2ogre

* Ogre3D dotScene loader can now load spot lights
 * Added some better debugging to FBO errors
 * Fix weird explosion in TestWalkingChar
 * Added additional "canvas torture methods" in TestCanvas 
 * Several fixes to canvas:
   - Issue when size becomes 0, 0
   - Freeze if no framerate limit is imposed and canvas is closed

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8210 75d07b2b-3a1a-0410-a2c5-0572b91ccdca
3.0
sha..rd 14 years ago
parent 120a3d1e4f
commit 6d728615a3
  1. 9
      engine/src/core/com/jme3/util/xml/SAXUtil.java
  2. 125
      engine/src/lwjgl-ogl/com/jme3/renderer/lwjgl/LwjglRenderer.java
  3. 210
      engine/src/lwjgl-ogl/com/jme3/system/lwjgl/LwjglCanvas.java
  4. 146
      engine/src/ogre/com/jme3/scene/plugins/ogre/SceneLoader.java
  5. 2
      engine/src/test/jme3test/app/TestBareBonesApp.java
  6. 2
      engine/src/test/jme3test/app/state/TestAppStates.java
  7. 155
      engine/src/test/jme3test/awt/TestCanvas.java
  8. 2
      engine/src/test/jme3test/bullet/TestWalkingChar.java

@ -102,12 +102,11 @@ public final class SAXUtil {
public static boolean parseBool(String bool, boolean def) throws SAXException{ public static boolean parseBool(String bool, boolean def) throws SAXException{
if (bool == null || bool.equals("")) if (bool == null || bool.equals(""))
return def; return def;
else if (bool.equals("false"))
return false;
else if (bool.equals("true"))
return true;
else else
throw new SAXException("Expected a boolean, got'"+bool+"'"); return Boolean.valueOf(bool);
//else
//else
// throw new SAXException("Expected a boolean, got'"+bool+"'");
} }
public static String parseString(String str, String def){ public static String parseString(String str, String def){

@ -90,6 +90,7 @@ import jme3tools.converters.MipMapGenerator;
import org.lwjgl.opengl.ARBDrawBuffers; import org.lwjgl.opengl.ARBDrawBuffers;
//import org.lwjgl.opengl.ARBDrawInstanced; //import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.ARBDrawInstanced; import org.lwjgl.opengl.ARBDrawInstanced;
import org.lwjgl.opengl.ARBFramebufferObject;
import org.lwjgl.opengl.ARBMultisample; import org.lwjgl.opengl.ARBMultisample;
import org.lwjgl.opengl.ContextCapabilities; import org.lwjgl.opengl.ContextCapabilities;
import org.lwjgl.opengl.EXTTextureArray; import org.lwjgl.opengl.EXTTextureArray;
@ -427,14 +428,17 @@ public class LwjglRenderer implements Renderer {
} }
public void resetGLObjects() { public void resetGLObjects() {
logger.log(Level.INFO, "Reseting objects and invalidating state");
objManager.resetObjects(); objManager.resetObjects();
statistics.clearMemory(); statistics.clearMemory();
invalidateState(); invalidateState();
} }
public void cleanup() { public void cleanup() {
logger.log(Level.INFO, "Deleting objects and invalidating state");
objManager.deleteAllObjects(this); objManager.deleteAllObjects(this);
statistics.clearMemory(); statistics.clearMemory();
invalidateState();
} }
private void checkCap(Caps cap) { private void checkCap(Caps cap) {
@ -537,8 +541,8 @@ public class LwjglRenderer implements Renderer {
if (state.isPointSprite() && !context.pointSprite) { if (state.isPointSprite() && !context.pointSprite) {
// Only enable/disable sprite // Only enable/disable sprite
if (context.boundTextures[0] != null) { if (context.boundTextures[0] != null){
if (context.boundTextureUnit != 0) { if (context.boundTextureUnit != 0){
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
context.boundTextureUnit = 0; context.boundTextureUnit = 0;
} }
@ -547,8 +551,8 @@ public class LwjglRenderer implements Renderer {
} }
context.pointSprite = true; context.pointSprite = true;
} else if (!state.isPointSprite() && context.pointSprite) { } else if (!state.isPointSprite() && context.pointSprite) {
if (context.boundTextures[0] != null) { if (context.boundTextures[0] != null){
if (context.boundTextureUnit != 0) { if (context.boundTextureUnit != 0){
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
context.boundTextureUnit = 0; context.boundTextureUnit = 0;
} }
@ -960,7 +964,7 @@ public class LwjglRenderer implements Renderer {
} }
source.setId(id); source.setId(id);
} else { }else{
throw new RendererException("Cannot recompile shader source"); throw new RendererException("Cannot recompile shader source");
} }
@ -1278,6 +1282,85 @@ public class LwjglRenderer implements Renderer {
} }
} }
private String getTargetBufferName(int buffer){
switch (buffer){
case GL_NONE: return "NONE";
case GL_FRONT: return "GL_FRONT";
case GL_BACK: return "GL_BACK";
default:
if ( buffer >= GL_COLOR_ATTACHMENT0_EXT
&& buffer <= GL_COLOR_ATTACHMENT15_EXT){
return "GL_COLOR_ATTACHMENT" +
(buffer - GL_COLOR_ATTACHMENT0_EXT);
}else{
return "UNKNOWN? " + buffer;
}
}
}
private void printRealRenderBufferInfo(FrameBuffer fb, RenderBuffer rb, String name){
System.out.println("== Renderbuffer " + name + " ==");
System.out.println("RB ID: " + rb.getId());
System.out.println("Is proper? " + glIsRenderbufferEXT(rb.getId()));
int attachment = convertAttachmentSlot(rb.getSlot());
int type = glGetFramebufferAttachmentParameterEXT(GL_DRAW_FRAMEBUFFER_EXT,
attachment,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_EXT);
int rbName = glGetFramebufferAttachmentParameterEXT(GL_DRAW_FRAMEBUFFER_EXT,
attachment,
GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_EXT);
switch (type){
case GL_NONE:
System.out.println("Type: None");
return; // note: return from method as other queries will be invalid
case GL_TEXTURE:
System.out.println("Type: Texture");
break;
case GL_RENDERBUFFER_EXT:
System.out.println("Type: Buffer");
System.out.println("RB ID: " + rbName);
break;
}
}
private void printRealFrameBufferInfo(FrameBuffer fb) {
boolean doubleBuffer = glGetBoolean(GL_DOUBLEBUFFER);
String drawBuf = getTargetBufferName(glGetInteger(GL_DRAW_BUFFER));
String readBuf = getTargetBufferName(glGetInteger(GL_READ_BUFFER));
int fbId = fb.getId();
int curDrawBinding = glGetInteger(ARBFramebufferObject.GL_DRAW_FRAMEBUFFER_BINDING);
int curReadBinding = glGetInteger(ARBFramebufferObject.GL_READ_FRAMEBUFFER_BINDING);
System.out.println("=== OpenGL FBO State ===");
System.out.println("Context doublebuffered? " + doubleBuffer);
System.out.println("FBO ID: " + fbId);
System.out.println("Is proper? " + glIsFramebufferEXT(fbId));
System.out.println("Is bound to draw? " + (fbId == curDrawBinding));
System.out.println("Is bound to read? " + (fbId == curReadBinding));
System.out.println("Draw buffer: " + drawBuf);
System.out.println("Read buffer: " + readBuf);
if (context.boundFBO != fbId){
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbId);
context.boundFBO = fbId;
}
if (fb.getDepthBuffer() != null){
printRealRenderBufferInfo(fb, fb.getDepthBuffer(), "Depth");
}
for (int i = 0; i < fb.getNumColorBuffers(); i++){
printRealRenderBufferInfo(fb, fb.getColorBuffer(i), "Color" + i);
}
}
private void checkFrameBufferError() { private void checkFrameBufferError() {
int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT); int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch (status) { switch (status) {
@ -1290,7 +1373,7 @@ public class LwjglRenderer implements Renderer {
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT: case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
throw new IllegalStateException("Framebuffer has erronous attachment."); throw new IllegalStateException("Framebuffer has erronous attachment.");
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT: case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
throw new IllegalStateException("Framebuffer is missing required attachment."); throw new IllegalStateException("Framebuffer doesn't have any renderbuffers attached.");
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT: case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
throw new IllegalStateException("Framebuffer attachments must have same dimensions."); throw new IllegalStateException("Framebuffer attachments must have same dimensions.");
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT: case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
@ -1487,6 +1570,11 @@ public class LwjglRenderer implements Renderer {
lastFb = null; lastFb = null;
} else { } else {
if (fb.getNumColorBuffers() == 0 && fb.getDepthBuffer() == null){
throw new IllegalArgumentException("The framebuffer: " + fb +
"\nDoesn't have any color/depth buffers");
}
if (fb.isUpdateNeeded()) { if (fb.isUpdateNeeded()) {
updateFrameBuffer(fb); updateFrameBuffer(fb);
} }
@ -1544,15 +1632,16 @@ public class LwjglRenderer implements Renderer {
assert fb.getId() >= 0; assert fb.getId() >= 0;
assert context.boundFBO == fb.getId(); assert context.boundFBO == fb.getId();
lastFb = fb; lastFb = fb;
}
try { try {
checkFrameBufferError(); checkFrameBufferError();
} catch (IllegalStateException ex) { } catch (IllegalStateException ex) {
logger.log(Level.SEVERE, "Problem FBO:\n{0}", fb); logger.log(Level.SEVERE, "=== jMonkeyEngine FBO State ===\n{0}", fb);
printRealFrameBufferInfo(fb);
throw ex; throw ex;
} }
} }
}
public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) { public void readFrameBuffer(FrameBuffer fb, ByteBuffer byteBuf) {
if (fb != null) { if (fb != null) {
@ -1964,7 +2053,7 @@ public class LwjglRenderer implements Renderer {
glBindBuffer(target, bufId); glBindBuffer(target, bufId);
context.boundElementArrayVBO = bufId; context.boundElementArrayVBO = bufId;
//statistics.onVertexBufferUse(vb, true); //statistics.onVertexBufferUse(vb, true);
} else { }else{
//statistics.onVertexBufferUse(vb, false); //statistics.onVertexBufferUse(vb, false);
} }
} else { } else {
@ -1973,7 +2062,7 @@ public class LwjglRenderer implements Renderer {
glBindBuffer(target, bufId); glBindBuffer(target, bufId);
context.boundArrayVBO = bufId; context.boundArrayVBO = bufId;
//statistics.onVertexBufferUse(vb, true); //statistics.onVertexBufferUse(vb, true);
} else { }else{
//statistics.onVertexBufferUse(vb, false); //statistics.onVertexBufferUse(vb, false);
} }
} }
@ -2142,7 +2231,7 @@ public class LwjglRenderer implements Renderer {
glBindBuffer(GL_ARRAY_BUFFER, bufId); glBindBuffer(GL_ARRAY_BUFFER, bufId);
context.boundArrayVBO = bufId; context.boundArrayVBO = bufId;
//statistics.onVertexBufferUse(vb, true); //statistics.onVertexBufferUse(vb, true);
} else { }else{
//statistics.onVertexBufferUse(vb, false); //statistics.onVertexBufferUse(vb, false);
} }
@ -2189,7 +2278,7 @@ public class LwjglRenderer implements Renderer {
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufId); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufId);
context.boundElementArrayVBO = bufId; context.boundElementArrayVBO = bufId;
//statistics.onVertexBufferUse(indexBuf, true); //statistics.onVertexBufferUse(indexBuf, true);
} else { }else{
//statistics.onVertexBufferUse(indexBuf, true); //statistics.onVertexBufferUse(indexBuf, true);
} }
@ -2314,9 +2403,9 @@ public class LwjglRenderer implements Renderer {
} }
private void renderMeshVertexArray(Mesh mesh, int lod, int count) { private void renderMeshVertexArray(Mesh mesh, int lod, int count) {
if (mesh.getId() == -1) { if (mesh.getId() == -1){
updateVertexArray(mesh); updateVertexArray(mesh);
} else { }else{
// TODO: Check if it was updated // TODO: Check if it was updated
} }
@ -2359,7 +2448,7 @@ public class LwjglRenderer implements Renderer {
} }
//for (Entry<VertexBuffer> entry : buffers) { //for (Entry<VertexBuffer> entry : buffers) {
// VertexBuffer vb = entry.getValue(); // VertexBuffer vb = entry.getValue();
for (int i = 0; i < buffersList.size(); i++) { for (int i = 0; i < buffersList.size(); i++){
VertexBuffer vb = buffersList.get(i); VertexBuffer vb = buffersList.get(i);
if (vb.getBufferType() == Type.InterleavedData if (vb.getBufferType() == Type.InterleavedData
@ -2391,10 +2480,10 @@ public class LwjglRenderer implements Renderer {
return; return;
} }
if (context.pointSprite && mesh.getMode() != Mode.Points) { if (context.pointSprite && mesh.getMode() != Mode.Points){
// XXX: Hack, disable point sprite mode if mesh not in point mode // XXX: Hack, disable point sprite mode if mesh not in point mode
if (context.boundTextures[0] != null) { if (context.boundTextures[0] != null){
if (context.boundTextureUnit != 0) { if (context.boundTextureUnit != 0){
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
context.boundTextureUnit = 0; context.boundTextureUnit = 0;
} }

@ -38,13 +38,11 @@ import com.jme3.system.JmeContext.Type;
import com.jme3.system.JmeSystem; import com.jme3.system.JmeSystem;
import com.jme3.system.JmeSystem.Platform; import com.jme3.system.JmeSystem.Platform;
import java.awt.Canvas; import java.awt.Canvas;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import org.lwjgl.LWJGLException; import org.lwjgl.LWJGLException;
import org.lwjgl.LWJGLUtil;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
import org.lwjgl.input.Mouse; import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.Display; import org.lwjgl.opengl.Display;
@ -53,14 +51,23 @@ import org.lwjgl.opengl.PixelFormat;
public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext { public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContext {
protected static final int TASK_NOTHING = 0,
TASK_DESTROY_DISPLAY = 1,
TASK_CREATE_DISPLAY = 2,
TASK_COMPLETE = 3;
// protected static final boolean USE_SHARED_CONTEXT =
// Boolean.parseBoolean(System.getProperty("jme3.canvas.sharedctx", "true"));
protected static final boolean USE_SHARED_CONTEXT = false;
private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName()); private static final Logger logger = Logger.getLogger(LwjglDisplay.class.getName());
private Canvas canvas; private Canvas canvas;
private int width; private int width;
private int height; private int height;
private final AtomicBoolean needRestoreCanvas = new AtomicBoolean(false); private final Object taskLock = new Object();
private final AtomicBoolean needDestroyCanvas = new AtomicBoolean(false); private int desiredTask = TASK_NOTHING;
private final CyclicBarrier actionRequiredBarrier = new CyclicBarrier(2);
private Thread renderThread; private Thread renderThread;
private boolean runningFirstTime = true; private boolean runningFirstTime = true;
@ -95,11 +102,19 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
return; return;
} }
logger.log(Level.INFO, "EDT: Notifying OGL that canvas is visible.."); logger.log(Level.INFO, "EDT: Telling OGL to create display ..");
needRestoreCanvas.set(true); synchronized (taskLock){
desiredTask = TASK_CREATE_DISPLAY;
// NOTE: no need to wait for OGL to initialize the canvas, // while (desiredTask != TASK_COMPLETE){
// it can happen at any time. // try {
// taskLock.wait();
// } catch (InterruptedException ex) {
// return;
// }
// }
// desiredTask = TASK_NOTHING;
}
// logger.log(Level.INFO, "EDT: OGL has created the display");
} }
@Override @Override
@ -112,18 +127,19 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
// We must tell GL context to shutdown and wait for it to // We must tell GL context to shutdown and wait for it to
// shutdown, otherwise, issues will occur. // shutdown, otherwise, issues will occur.
logger.log(Level.INFO, "EDT: Notifying OGL that canvas is about to become invisible.."); logger.log(Level.INFO, "EDT: Telling OGL to destroy display ..");
needDestroyCanvas.set(true); synchronized (taskLock){
desiredTask = TASK_DESTROY_DISPLAY;
while (desiredTask != TASK_COMPLETE){
try { try {
actionRequiredBarrier.await(); taskLock.wait();
} catch (InterruptedException ex) { } catch (InterruptedException ex){
logger.log(Level.SEVERE, "EDT: Interrupted! ", ex); super.removeNotify();
} catch (BrokenBarrierException ex){ return;
logger.log(Level.SEVERE, "EDT: Broken barrier! ", ex); }
}
desiredTask = TASK_NOTHING;
} }
// Reset barrier for future use
actionRequiredBarrier.reset();
logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death"); logger.log(Level.INFO, "EDT: Acknowledged receipt of canvas death");
// GL context is dead at this point // GL context is dead at this point
@ -171,35 +187,43 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
@Override @Override
protected void runLoop(){ protected void runLoop(){
if (needDestroyCanvas.getAndSet(false)){ if (desiredTask != TASK_NOTHING){
// Destroy canvas synchronized (taskLock){
logger.log(Level.INFO, "OGL: Received destroy request! Complying.."); switch (desiredTask){
try { case TASK_CREATE_DISPLAY:
logger.log(Level.INFO, "OGL: Creating display ..");
restoreCanvas();
listener.gainFocus();
desiredTask = TASK_NOTHING;
break;
case TASK_DESTROY_DISPLAY:
logger.log(Level.INFO, "OGL: Destroying display ..");
listener.loseFocus(); listener.loseFocus();
pauseCanvas(); pauseCanvas();
} finally { break;
try {
// Required to avoid deadlock if an exception occurs
actionRequiredBarrier.await();
} catch (InterruptedException ex) {
logger.log(Level.SEVERE, "OGL: Interrupted! ", ex);
} catch (BrokenBarrierException ex) {
logger.log(Level.SEVERE, "OGL: Broken barrier! ", ex);
} }
desiredTask = TASK_COMPLETE;
taskLock.notifyAll();
} }
}else if (needRestoreCanvas.getAndSet(false)){
// Put canvas back online
logger.log(Level.INFO, "OGL: Canvas is now visible! Re-initializing..");
restoreCanvas();
listener.gainFocus();
} }
if (width != canvas.getWidth() || height != canvas.getHeight()){ if (renderable.get()){
width = canvas.getWidth(); int newWidth = Math.max(canvas.getWidth(), 1);
height = canvas.getHeight(); int newHeight = Math.max(canvas.getHeight(), 1);
if (listener != null) if (width != newWidth || height != newHeight){
width = newWidth;
height = newHeight;
if (listener != null){
listener.reshape(width, height); listener.reshape(width, height);
} }
}
}else{
if (frameRate <= 0){
// NOTE: MUST be done otherwise
// Windows OS will freeze
Display.sync(30);
}
}
super.runLoop(); super.runLoop();
} }
@ -218,8 +242,6 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
Keyboard.destroy(); Keyboard.destroy();
} }
logger.log(Level.INFO, "OGL: Canvas will become invisible! Destroying ..");
renderable.set(false); renderable.set(false);
destroyContext(); destroyContext();
} }
@ -237,7 +259,7 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
} }
} }
logger.log(Level.INFO, "OGL: Creating display.."); logger.log(Level.INFO, "OGL: Creating display context ..");
// Set renderable to true, since canvas is now displayable. // Set renderable to true, since canvas is now displayable.
renderable.set(true); renderable.set(true);
@ -306,7 +328,27 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
if (pbuffer == null) { if (pbuffer == null) {
pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null); pbuffer = new Pbuffer(1, 1, acquirePixelFormat(true), null);
pbuffer.makeCurrent();
logger.log(Level.INFO, "OGL: Pbuffer has been created"); logger.log(Level.INFO, "OGL: Pbuffer has been created");
// Any created objects are no longer valid
if (!runningFirstTime){
renderer.resetGLObjects();
}
}
pbuffer.makeCurrent();
if (!pbuffer.isCurrent()){
throw new LWJGLException("Pbuffer cannot be made current");
}
}
protected void destroyPbuffer(){
if (pbuffer != null){
if (!pbuffer.isBufferLost()){
pbuffer.destroy();
}
pbuffer = null;
} }
} }
@ -317,25 +359,9 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
*/ */
protected void destroyContext(){ protected void destroyContext(){
try { try {
// The canvas is no longer visible,
// but the context thread is still running.
if (!needClose.get()){
// MUST make sure there's still a context current here ..
// Display is dead, make pbuffer available to the system
makePbufferAvailable();
// pbuffer is now available, make it current
pbuffer.makeCurrent();
// invalidate the state so renderer can resume operation // invalidate the state so renderer can resume operation
renderer.invalidateState(); if (!USE_SHARED_CONTEXT){
}else{ renderer.cleanup();
// The context thread is no longer running.
// Destroy pbuffer.
if (pbuffer != null && !pbuffer.isBufferLost()){
pbuffer.destroy();
pbuffer = null;
}
} }
if (Display.isCreated()){ if (Display.isCreated()){
@ -353,21 +379,35 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
Keyboard.destroy(); Keyboard.destroy();
} }
try { //try {
// NOTE: On Windows XP, not calling setParent(null) // NOTE: On Windows XP, not calling setParent(null)
// freezes the application. // freezes the application.
// On Mac it freezes the application. // On Mac it freezes the application.
// On Linux it fixes a crash with X Window System. // On Linux it fixes a crash with X Window System.
if (JmeSystem.getPlatform() == Platform.Windows32 if (JmeSystem.getPlatform() == Platform.Windows32
|| JmeSystem.getPlatform() == Platform.Windows64){ || JmeSystem.getPlatform() == Platform.Windows64){
Display.setParent(null); //Display.setParent(null);
}
} catch (LWJGLException ex) {
logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);
} }
//} catch (LWJGLException ex) {
// logger.log(Level.SEVERE, "Encountered exception when setting parent to null", ex);
//}
Display.destroy(); Display.destroy();
} }
// The canvas is no longer visible,
// but the context thread is still running.
if (!needClose.get()){
// MUST make sure there's still a context current here ..
// Display is dead, make pbuffer available to the system
makePbufferAvailable();
renderer.invalidateState();
}else{
// The context thread is no longer running.
// Destroy pbuffer.
destroyPbuffer();
}
} catch (LWJGLException ex) { } catch (LWJGLException ex) {
listener.handleError("Failed make pbuffer available", ex); listener.handleError("Failed make pbuffer available", ex);
} }
@ -385,28 +425,44 @@ public class LwjglCanvas extends LwjglAbstractDisplay implements JmeCanvasContex
frameRate = settings.getFrameRate(); frameRate = settings.getFrameRate();
try { try {
// First create the pbuffer, if it is needed.
makePbufferAvailable();
if (renderable.get()){ if (renderable.get()){
if (!runningFirstTime){
// because the display is a different opengl context
// must reset the context state.
if (!USE_SHARED_CONTEXT){
renderer.cleanup();
}
}
// if the pbuffer is currently active, // if the pbuffer is currently active,
// make sure to deactivate it // make sure to deactivate it
if (pbuffer.isCurrent()){ destroyPbuffer();
pbuffer.releaseContext();
if (Keyboard.isCreated()){
Keyboard.destroy();
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
} }
Display.setVSyncEnabled(settings.isVSync()); Display.setVSyncEnabled(settings.isVSync());
Display.setParent(canvas); Display.setParent(canvas);
if (USE_SHARED_CONTEXT){
Display.create(acquirePixelFormat(false), pbuffer); Display.create(acquirePixelFormat(false), pbuffer);
}else{
Display.create(acquirePixelFormat(false));
}
// because the display is a different opengl context
// must reset the context state.
renderer.invalidateState(); renderer.invalidateState();
}else{ }else{
pbuffer.makeCurrent(); // First create the pbuffer, if it is needed.
makePbufferAvailable();
} }
// At this point, the OpenGL context is active.
// At this point, the OpenGL context is active.
if (runningFirstTime){ if (runningFirstTime){
// THIS is the part that creates the renderer. // THIS is the part that creates the renderer.
// It must always be called, now that we have the pbuffer workaround. // It must always be called, now that we have the pbuffer workaround.

@ -41,6 +41,8 @@ import com.jme3.asset.AssetNotFoundException;
import com.jme3.light.DirectionalLight; import com.jme3.light.DirectionalLight;
import com.jme3.light.Light; import com.jme3.light.Light;
import com.jme3.light.PointLight; import com.jme3.light.PointLight;
import com.jme3.light.SpotLight;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion; import com.jme3.math.Quaternion;
import com.jme3.math.Vector3f; import com.jme3.math.Vector3f;
import com.jme3.scene.Node; import com.jme3.scene.Node;
@ -104,16 +106,22 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
light = null; light = null;
} }
private void checkTopNode(String topNode) throws SAXException{
if (!elementStack.peek().equals(topNode)){
throw new SAXException("dotScene parse error: Expected parent node to be " + topNode);
}
}
private Quaternion parseQuat(Attributes attribs) throws SAXException{ private Quaternion parseQuat(Attributes attribs) throws SAXException{
if (attribs.getValue("x") != null){ if (attribs.getValue("x") != null){
// defined as quaternion // defined as quaternion
// qx, qy, qz, qw defined
float x = parseFloat(attribs.getValue("x")); float x = parseFloat(attribs.getValue("x"));
float y = parseFloat(attribs.getValue("y")); float y = parseFloat(attribs.getValue("y"));
float z = parseFloat(attribs.getValue("z")); float z = parseFloat(attribs.getValue("z"));
float w = parseFloat(attribs.getValue("w")); float w = parseFloat(attribs.getValue("w"));
return new Quaternion(x,y,z,w); return new Quaternion(x,y,z,w);
}else if (attribs.getValue("qx") != null){ }else if (attribs.getValue("qx") != null){
// defined as quaternion with prefix "q"
float x = parseFloat(attribs.getValue("qx")); float x = parseFloat(attribs.getValue("qx"));
float y = parseFloat(attribs.getValue("qy")); float y = parseFloat(attribs.getValue("qy"));
float z = parseFloat(attribs.getValue("qz")); float z = parseFloat(attribs.getValue("qz"));
@ -129,6 +137,7 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
q.fromAngleAxis(angle, new Vector3f(axisX, axisY, axisZ)); q.fromAngleAxis(angle, new Vector3f(axisX, axisY, axisZ));
return q; return q;
}else{ }else{
// defines as 3 angles along XYZ axes
float angleX = parseFloat(attribs.getValue("angleX")); float angleX = parseFloat(attribs.getValue("angleX"));
float angleY = parseFloat(attribs.getValue("angleY")); float angleY = parseFloat(attribs.getValue("angleY"));
float angleZ = parseFloat(attribs.getValue("angleZ")); float angleZ = parseFloat(attribs.getValue("angleZ"));
@ -139,19 +148,22 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
} }
private void parseLightNormal(Attributes attribs) throws SAXException { private void parseLightNormal(Attributes attribs) throws SAXException {
assert elementStack.peek().equals("light"); checkTopNode("light");
// SpotLight will be supporting a direction-normal, too. // SpotLight will be supporting a direction-normal, too.
if (light instanceof DirectionalLight) if (light instanceof DirectionalLight)
((DirectionalLight) light).setDirection(parseVector3(attribs)); ((DirectionalLight) light).setDirection(parseVector3(attribs));
else if (light instanceof SpotLight){
((SpotLight) light).setDirection(parseVector3(attribs));
}
} }
private void parseLightAttenuation(Attributes attribs) throws SAXException { private void parseLightAttenuation(Attributes attribs) throws SAXException {
// NOTE: Only radius is supported atm ( for pointlights only, since there are no spotlights, yet). // NOTE: Derives range based on "linear" if it is used solely
assert elementStack.peek().equals("light"); // for the attenuation. Otherwise derives it from "range"
checkTopNode("light");
// SpotLight will be supporting a direction-normal, too. if (light instanceof PointLight || light instanceof SpotLight){
if (light instanceof PointLight){
float range = parseFloat(attribs.getValue("range")); float range = parseFloat(attribs.getValue("range"));
float constant = parseFloat(attribs.getValue("constant")); float constant = parseFloat(attribs.getValue("constant"));
float linear = parseFloat(attribs.getValue("linear")); float linear = parseFloat(attribs.getValue("linear"));
@ -165,15 +177,36 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
if (constant == 1 && quadratic == 0 && linear > 0){ if (constant == 1 && quadratic == 0 && linear > 0){
range = 1f / linear; range = 1f / linear;
} }
if (light instanceof PointLight){
((PointLight) light).setRadius(range); ((PointLight) light).setRadius(range);
}else{
((SpotLight)light).setSpotRange(range);
}
}
}
private void parseLightSpotLightRange(Attributes attribs) throws SAXException{
checkTopNode("light");
float outer = SAXUtil.parseFloat(attribs.getValue("outer"));
float inner = SAXUtil.parseFloat(attribs.getValue("inner"));
if (!(light instanceof SpotLight)){
throw new SAXException("dotScene parse error: spotLightRange "
+ "can only appear under 'spot' light elements");
} }
SpotLight sl = (SpotLight) light;
sl.setSpotInnerAngle(inner * 0.5f);
sl.setSpotOuterAngle(outer * 0.5f);
} }
private void parseLight(Attributes attribs) throws SAXException { private void parseLight(Attributes attribs) throws SAXException {
assert node != null; if (node == null || node.getParent() == null)
assert node.getParent() != null; throw new SAXException("dotScene parse error: light can only appear under a node");
assert elementStack.peek().equals("node");
checkTopNode("node");
String lightType = parseString(attribs.getValue("type"), "point"); String lightType = parseString(attribs.getValue("type"), "point");
if(lightType.equals("point")) { if(lightType.equals("point")) {
@ -182,10 +215,8 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
light = new DirectionalLight(); light = new DirectionalLight();
// Assuming "normal" property is not provided // Assuming "normal" property is not provided
((DirectionalLight)light).setDirection(Vector3f.UNIT_Z); ((DirectionalLight)light).setDirection(Vector3f.UNIT_Z);
} else if(lightType.equals("spotLight")) { } else if(lightType.equals("spotLight") || lightType.equals("spot")) {
// TODO: SpotLight class. light = new SpotLight();
logger.warning("No SpotLight class atm, using Pointlight instead.");
light = new PointLight();
} else { } else {
logger.log(Level.WARNING, "No matching jME3 LightType found for OGRE LightType: {0}", lightType); logger.log(Level.WARNING, "No matching jME3 LightType found for OGRE LightType: {0}", lightType);
} }
@ -203,14 +234,19 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException{ public void startElement(String uri, String localName, String qName, Attributes attribs) throws SAXException{
if (qName.equals("scene")){ if (qName.equals("scene")){
assert elementStack.size() == 0; if (elementStack.size() != 0){
throw new SAXException("dotScene parse error: 'scene' element must be the root XML element");
}
String version = attribs.getValue("formatVersion"); String version = attribs.getValue("formatVersion");
if (version == null || !version.equals("1.0.0")) if (version == null && !version.equals("1.0.0") && !version.equals("1.0.1"))
logger.log(Level.WARNING, "Unrecognized version number" logger.log(Level.WARNING, "Unrecognized version number"
+ " in dotScene file: {0}", version); + " in dotScene file: {0}", version);
}else if (qName.equals("nodes")){ }else if (qName.equals("nodes")){
assert root == null; if (root != null){
throw new SAXException("dotScene parse error: nodes element was specified twice");
}
if (sceneName == null) if (sceneName == null)
root = new Node("OgreDotScene"+(++sceneIdx)); root = new Node("OgreDotScene"+(++sceneIdx));
else else
@ -218,22 +254,31 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
node = root; node = root;
}else if (qName.equals("externals")){ }else if (qName.equals("externals")){
assert elementStack.peek().equals("scene"); checkTopNode("scene");
// Not loaded currently
}else if (qName.equals("item")){ }else if (qName.equals("item")){
assert elementStack.peek().equals("externals"); checkTopNode("externals");
}else if (qName.equals("file")){ }else if (qName.equals("file")){
assert elementStack.peek().equals("item"); checkTopNode("item");
String matFile = folderName+attribs.getValue("name");
try { // XXX: Currently material file name is based
materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(matFile)); // on the scene's filename. THIS IS NOT CORRECT.
} catch (AssetNotFoundException ex){ // To solve, port SceneLoader to use DOM instead of SAX
materialList = null;
logger.log(Level.WARNING, "Cannot locate material file: {0}", matFile); //String matFile = folderName+attribs.getValue("name");
} //try {
// materialList = (MaterialList) assetManager.loadAsset(new OgreMaterialKey(matFile));
//} catch (AssetNotFoundException ex){
// materialList = null;
// logger.log(Level.WARNING, "Cannot locate material file: {0}", matFile);
//}
}else if (qName.equals("node")){ }else if (qName.equals("node")){
String curElement = elementStack.peek(); String curElement = elementStack.peek();
assert curElement.equals("nodes") || curElement.equals("node"); if (!curElement.equals("node") && !curElement.equals("nodes")){
throw new SAXException("dotScene parse error: "
+ "node element can only appear under 'node' or 'nodes'");
}
String name = attribs.getValue("name"); String name = attribs.getValue("name");
if (name == null) if (name == null)
name = "OgreNode-" + (++nodeIdx); name = "OgreNode-" + (++nodeIdx);
@ -259,7 +304,8 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
} }
} }
}else if (qName.equals("entity")){ }else if (qName.equals("entity")){
assert elementStack.peek().equals("node"); checkTopNode("node");
String name = attribs.getValue("name"); String name = attribs.getValue("name");
if (name == null) if (name == null)
name = "OgreEntity-" + (++nodeIdx); name = "OgreEntity-" + (++nodeIdx);
@ -267,32 +313,31 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
name += "-entity"; name += "-entity";
String meshFile = attribs.getValue("meshFile"); String meshFile = attribs.getValue("meshFile");
if (meshFile == null) if (meshFile == null) {
throw new SAXException("Required attribute 'meshFile' missing for 'entity' node"); throw new SAXException("Required attribute 'meshFile' missing for 'entity' node");
}
// TODO: Not currently used
String materialName = attribs.getValue("materialName"); String materialName = attribs.getValue("materialName");
// NOTE: append "xml" since its assumed mesh filse are binary in dotScene if (folderName != null) {
if (folderName != null)
meshFile = folderName + meshFile; meshFile = folderName + meshFile;
}
// NOTE: append "xml" since its assumed mesh files are binary in dotScene
meshFile += ".xml"; meshFile += ".xml";
entityNode = new Node(name); entityNode = new Node(name);
OgreMeshKey key = new OgreMeshKey(meshFile, materialList); OgreMeshKey key = new OgreMeshKey(meshFile, materialList);
Spatial ogreMesh = Spatial ogreMesh = assetManager.loadModel(key);
(Spatial) assetManager.loadAsset(key);
//TODO:workaround for meshxml / mesh.xml
if(ogreMesh==null){
meshFile = folderName + attribs.getValue("meshFile") + "xml";
key = new OgreMeshKey(meshFile, materialList);
ogreMesh = (Spatial) assetManager.loadAsset(key);
}
entityNode.attachChild(ogreMesh); entityNode.attachChild(ogreMesh);
node.attachChild(entityNode); node.attachChild(entityNode);
node = null; node = null;
}else if (qName.equals("position")){ }else if (qName.equals("position")){
if (elementStack.peek().equals("node")){
node.setLocalTranslation(SAXUtil.parseVector3(attribs)); node.setLocalTranslation(SAXUtil.parseVector3(attribs));
}
}else if (qName.equals("quaternion") || qName.equals("rotation")){ }else if (qName.equals("quaternion") || qName.equals("rotation")){
node.setLocalRotation(parseQuat(attribs)); node.setLocalRotation(parseQuat(attribs));
}else if (qName.equals("scale")){ }else if (qName.equals("scale")){
@ -305,19 +350,22 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
light.setColor(parseColor(attribs)); light.setColor(parseColor(attribs));
} }
}else{ }else{
assert elementStack.peek().equals("environment"); checkTopNode("environment");
} }
} else if (qName.equals("normal")) { } else if (qName.equals("normal") || qName.equals("direction")) {
checkTopNode("light");
parseLightNormal(attribs); parseLightNormal(attribs);
} else if (qName.equals("lightAttenuation")) { } else if (qName.equals("lightAttenuation")) {
parseLightAttenuation(attribs); parseLightAttenuation(attribs);
} else if (qName.equals("spotLightRange") || qName.equals("lightRange")) {
parseLightSpotLightRange(attribs);
} }
elementStack.push(qName); elementStack.push(qName);
} }
@Override @Override
public void endElement(String uri, String name, String qName) { public void endElement(String uri, String name, String qName) throws SAXException {
if (qName.equals("node")){ if (qName.equals("node")){
node = node.getParent(); node = node.getParent();
}else if (qName.equals("nodes")){ }else if (qName.equals("nodes")){
@ -339,11 +387,21 @@ public class SceneLoader extends DefaultHandler implements AssetLoader {
PointLight pl = (PointLight) light; PointLight pl = (PointLight) light;
Vector3f pos = node.getWorldTranslation(); Vector3f pos = node.getWorldTranslation();
pl.setPosition(pos); pl.setPosition(pos);
}else if (light instanceof SpotLight){
SpotLight sl = (SpotLight) light;
Vector3f pos = node.getWorldTranslation();
sl.setPosition(pos);
Quaternion q = node.getWorldRotation();
Vector3f dir = sl.getDirection();
q.multLocal(dir);
sl.setDirection(dir);
} }
} }
light = null; light = null;
} }
assert elementStack.peek().equals(qName); checkTopNode(qName);
elementStack.pop(); elementStack.pop();
} }

@ -78,7 +78,7 @@ public class TestBareBonesApp extends Application {
boxGeom.updateGeometricState(); boxGeom.updateGeometricState();
// render the viewports // render the viewports
renderManager.render(tpf, true); renderManager.render(tpf, context.isRenderable());
} }
@Override @Override

@ -88,7 +88,7 @@ public class TestAppStates extends Application {
stateManager.render(renderManager); stateManager.render(renderManager);
// render the viewports // render the viewports
renderManager.render(tpf, true); renderManager.render(tpf, context.isRenderable());
} }
@Override @Override

@ -37,7 +37,10 @@ import com.jme3.app.SimpleApplication;
import com.jme3.system.AppSettings; import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext; import com.jme3.system.JmeCanvasContext;
import com.jme3.util.JmeFormatter; import com.jme3.util.JmeFormatter;
import java.awt.BorderLayout;
import java.awt.Canvas; import java.awt.Canvas;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
@ -50,8 +53,11 @@ import javax.swing.JFrame;
import javax.swing.JMenu; import javax.swing.JMenu;
import javax.swing.JMenuBar; import javax.swing.JMenuBar;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu; import javax.swing.JPopupMenu;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class TestCanvas { public class TestCanvas {
@ -59,87 +65,149 @@ public class TestCanvas {
private static Canvas canvas; private static Canvas canvas;
private static Application app; private static Application app;
private static JFrame frame; private static JFrame frame;
private static final String appClass = "jme3test.post.TestMultiplesFilters"; private static Container canvasPanel1, canvasPanel2;
private static Container currentPanel;
private static JTabbedPane tabbedPane;
private static final String appClass = "jme3test.post.TestRenderToTexture";
private static void createFrame(){ private static void createTabs(){
frame = new JFrame("Test"); tabbedPane = new JTabbedPane();
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter(){ canvasPanel1 = new JPanel();
@Override canvasPanel1.setLayout(new BorderLayout());
public void windowClosed(WindowEvent e) { tabbedPane.addTab("jME3 Canvas 1", canvasPanel1);
app.stop();
canvasPanel2 = new JPanel();
canvasPanel2.setLayout(new BorderLayout());
tabbedPane.addTab("jME3 Canvas 2", canvasPanel2);
frame.getContentPane().add(tabbedPane);
currentPanel = canvasPanel1;
} }
});
private static void createMenu(){
JMenuBar menuBar = new JMenuBar(); JMenuBar menuBar = new JMenuBar();
frame.setJMenuBar(menuBar); frame.setJMenuBar(menuBar);
JMenu menuFile = new JMenu("File"); JMenu menuTortureMethods = new JMenu("Canvas Torture Methods");
menuBar.add(menuFile); menuBar.add(menuTortureMethods);
final JMenuItem itemRemoveCanvas = new JMenuItem("Remove Canvas"); final JMenuItem itemRemoveCanvas = new JMenuItem("Remove Canvas");
menuFile.add(itemRemoveCanvas); menuTortureMethods.add(itemRemoveCanvas);
itemRemoveCanvas.addActionListener(new ActionListener() { itemRemoveCanvas.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (itemRemoveCanvas.getText().equals("Remove Canvas")){ if (itemRemoveCanvas.getText().equals("Remove Canvas")){
frame.getContentPane().remove(canvas); currentPanel.remove(canvas);
// force OS to repaint over canvas ..
// this is needed since AWT does not handle
// that when a heavy-weight component is removed.
frame.setVisible(false);
frame.setVisible(true);
frame.requestFocus();
itemRemoveCanvas.setText("Add Canvas"); itemRemoveCanvas.setText("Add Canvas");
}else if (itemRemoveCanvas.getText().equals("Add Canvas")){ }else if (itemRemoveCanvas.getText().equals("Add Canvas")){
frame.getContentPane().add(canvas); currentPanel.add(canvas, BorderLayout.CENTER);
itemRemoveCanvas.setText("Remove Canvas"); itemRemoveCanvas.setText("Remove Canvas");
} }
} }
}); });
final JMenuItem itemHideCanvas = new JMenuItem("Hide Canvas");
menuTortureMethods.add(itemHideCanvas);
itemHideCanvas.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (itemHideCanvas.getText().equals("Hide Canvas")){
canvas.setVisible(false);
itemHideCanvas.setText("Show Canvas");
}else if (itemHideCanvas.getText().equals("Show Canvas")){
canvas.setVisible(true);
itemHideCanvas.setText("Hide Canvas");
}
}
});
final JMenuItem itemSwitchTab = new JMenuItem("Switch to tab #2");
menuTortureMethods.add(itemSwitchTab);
itemSwitchTab.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
if (itemSwitchTab.getText().equals("Switch to tab #2")){
canvasPanel1.remove(canvas);
canvasPanel2.add(canvas, BorderLayout.CENTER);
currentPanel = canvasPanel2;
itemSwitchTab.setText("Switch to tab #1");
}else if (itemSwitchTab.getText().equals("Switch to tab #1")){
canvasPanel2.remove(canvas);
canvasPanel1.add(canvas, BorderLayout.CENTER);
currentPanel = canvasPanel1;
itemSwitchTab.setText("Switch to tab #2");
}
}
});
JMenuItem itemSwitchLaf = new JMenuItem("Switch Look and Feel");
menuTortureMethods.add(itemSwitchLaf);
itemSwitchLaf.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Throwable t){
t.printStackTrace();
}
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
}
});
JMenuItem itemSmallSize = new JMenuItem("Set size to (0, 0)");
menuTortureMethods.add(itemSmallSize);
itemSmallSize.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
Dimension preferred = frame.getPreferredSize();
frame.setPreferredSize(new Dimension(0, 0));
frame.pack();
frame.setPreferredSize(preferred);
}
});
JMenuItem itemKillCanvas = new JMenuItem("Stop/Start Canvas"); JMenuItem itemKillCanvas = new JMenuItem("Stop/Start Canvas");
menuFile.add(itemKillCanvas); menuTortureMethods.add(itemKillCanvas);
itemKillCanvas.addActionListener(new ActionListener() { itemKillCanvas.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
frame.getContentPane().remove(canvas); currentPanel.remove(canvas);
app.stop(true); app.stop(true);
createCanvas(appClass); createCanvas(appClass);
frame.getContentPane().add(canvas); currentPanel.add(canvas, BorderLayout.CENTER);
frame.pack(); frame.pack();
startApp(); startApp();
} }
}); });
JMenuItem itemExit = new JMenuItem("Exit"); JMenuItem itemExit = new JMenuItem("Exit");
menuFile.add(itemExit); menuTortureMethods.add(itemExit);
itemExit.addActionListener(new ActionListener() { itemExit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) { public void actionPerformed(ActionEvent ae) {
frame.dispose(); frame.dispose();
app.stop(); app.stop();
} }
}); });
}
JMenu menuEdit = new JMenu("Edit"); private static void createFrame(){
menuBar.add(menuEdit); frame = new JFrame("Test");
JMenuItem itemDelete = new JMenuItem("Delete"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
menuEdit.add(itemDelete); frame.addWindowListener(new WindowAdapter(){
@Override
JMenu menuView = new JMenu("View"); public void windowClosed(WindowEvent e) {
menuBar.add(menuView); app.stop();
JMenuItem itemSetting = new JMenuItem("Settings"); }
menuView.add(itemSetting); });
JMenu menuHelp = new JMenu("Help"); createTabs();
menuBar.add(menuHelp); createMenu();
} }
public static void createCanvas(String appClass){ public static void createCanvas(String appClass){
AppSettings settings = new AppSettings(true); AppSettings settings = new AppSettings(true);
settings.setWidth( Math.max(640, frame.getContentPane().getWidth()) ); settings.setWidth(640);
settings.setHeight( Math.max(480, frame.getContentPane().getHeight()) ); settings.setHeight(480);
try{ try{
Class<? extends Application> clazz = (Class<? extends Application>) Class.forName(appClass); Class<? extends Application> clazz = (Class<? extends Application>) Class.forName(appClass);
@ -155,6 +223,7 @@ public class TestCanvas {
app.setPauseOnLostFocus(false); app.setPauseOnLostFocus(false);
app.setSettings(settings); app.setSettings(settings);
app.createCanvas(); app.createCanvas();
app.startCanvas();
context = (JmeCanvasContext) app.getContext(); context = (JmeCanvasContext) app.getContext();
canvas = context.getCanvas(); canvas = context.getCanvas();
@ -184,14 +253,20 @@ public class TestCanvas {
Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]); Logger.getLogger("").removeHandler(Logger.getLogger("").getHandlers()[0]);
Logger.getLogger("").addHandler(consoleHandler); Logger.getLogger("").addHandler(consoleHandler);
createCanvas(appClass);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
SwingUtilities.invokeLater(new Runnable(){ SwingUtilities.invokeLater(new Runnable(){
public void run(){ public void run(){
JPopupMenu.setDefaultLightWeightPopupEnabled(false); JPopupMenu.setDefaultLightWeightPopupEnabled(false);
createFrame(); createFrame();
createCanvas(appClass);
frame.getContentPane().add(canvas); currentPanel.add(canvas, BorderLayout.CENTER);
frame.pack(); frame.pack();
startApp(); startApp();
frame.setLocationRelativeTo(null); frame.setLocationRelativeTo(null);

@ -225,7 +225,7 @@ public class TestWalkingChar extends SimpleApplication implements ActionListener
Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md"); Material mat = new Material(assetManager, "Common/MatDefs/Misc/Particle.j3md");
mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png")); mat.setTexture("Texture", assetManager.loadTexture("Effects/Explosion/flame.png"));
effect.setMaterial(mat); effect.setMaterial(mat);
effect.setLocalScale(100); // effect.setLocalScale(100);
rootNode.attachChild(effect); rootNode.attachChild(effect);
} }

Loading…
Cancel
Save