[Committed] Illegit GameTaskQueueManager usage in ModelLoader

http://www.jmonkeyengine.com/forum/index.php?topic=4735.15



Index: src/com/jmex/model/util/ModelLoader.java
===================================================================
--- src/com/jmex/model/util/ModelLoader.java   (revision 5083)
+++ src/com/jmex/model/util/ModelLoader.java   (working copy)
@@ -42,7 +42,6 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Callable;
-import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.util.prefs.Preferences;
@@ -58,7 +57,6 @@
 import com.jme.math.Vector3f;
 import com.jme.scene.Node;
 import com.jme.scene.Spatial;
-import com.jme.util.GameTaskQueueManager;
 import com.jme.util.export.Savable;
 import com.jme.util.export.binary.BinaryExporter;
 import com.jme.util.export.binary.BinaryImporter;
@@ -116,13 +114,6 @@
                     }
                     game.start();
                    
-                    GameTaskQueueManager.getManager().update(new Callable<Object>() {
-                        public Object call() throws Exception {
-                            //MouseInput.get().setCursorVisible(true);
-                            return null;
-                        }
-                    });
-                    
                     DebugGameState debug = new DebugGameState();
                     GameStateManager.getInstance().attachChild(debug);
                     debug.setActive(true);
@@ -222,8 +213,7 @@
             throw new UnsupportedOperationException( "Unknown file type: " + file );
         }
         callable.setFile( file );
-        Future<Node> future = GameTaskQueueManager.getManager().update( callable );
-        return future.get();
+        return callable.call();
     }
 
     private static String extensionOf( String file ) {

but then i think the loadModel() call in the main method, should be wrapped with a GameTaskQueue.




Index: src/com/jmex/model/util/ModelLoader.java
===================================================================
--- src/com/jmex/model/util/ModelLoader.java   (revision 5142)
+++ src/com/jmex/model/util/ModelLoader.java   (working copy)
@@ -102,7 +102,7 @@
             File directory = new File(preferences.get("StartDirectory", "."));
             chooser.setCurrentDirectory(directory);
             if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
-                File file = chooser.getSelectedFile();
+                final File file = chooser.getSelectedFile();
                 if (isValidModelFile(file)) {
                     // Set it in preferences so we remember next time
                     preferences.put("StartDirectory", file.getAbsolutePath());
@@ -116,12 +116,6 @@
                     }
                     game.start();
                    
-                    GameTaskQueueManager.getManager().update(new Callable<Object>() {
-                        public Object call() throws Exception {
-                            //MouseInput.get().setCursorVisible(true);
-                            return null;
-                        }
-                    });
                    
                     DebugGameState debug = new DebugGameState(game);
                     GameStateManager.getInstance().attachChild(debug);
@@ -138,7 +132,14 @@
                     ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, locator);
                     ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_MODEL, locator);
 
-                    final Node modelNode = loadModel(file);
+                    Future<Object> future =  GameTaskQueueManager.getManager().update(new Callable<Object>() {
+                       public Node call() throws Exception {
+                          return loadModel(file);
+                       }
+                    });
+                   
+                    Node modelNode = (Node) future.get();
+                   
                     outputElapsed(time);
                     if (modelNode != null) {
                         modelNode.updateRenderState();
@@ -222,8 +223,7 @@
             throw new UnsupportedOperationException( "Unknown file type: " + file );
         }
         callable.setFile( file );
-        Future<Node> future = GameTaskQueueManager.getManager().update( callable );
-        return future.get();
+        return callable.call();
     }
 
     private static String extensionOf( String file ) {

Just to repeat my question from the already quoted thread: Why would you want to execute loadModel using the GameTastQueueManager, anyway? We do not alter any scenes here, right?

not!an!exit said:

Just to repeat my question from the already quoted thread: Why would you want to execute loadModel using the GameTastQueueManager, anyway? We do not alter any scenes here, right?


Loading models normally results in many many calls to the renderer like creating various RenderStates and such and loading Textures and much more.

http://www.jmonkeyengine.com/wiki/doku.php?id=what_calls_must_be_made_from_the_opengl_thread

EDIT: new patch:


Index: src/com/jmex/model/util/ModelLoader.java
===================================================================
--- src/com/jmex/model/util/ModelLoader.java   (revision 5083)
+++ src/com/jmex/model/util/ModelLoader.java   (working copy)
@@ -42,6 +42,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
 import java.util.logging.Level;
 import java.util.logging.Logger;
@@ -102,7 +103,7 @@
             File directory = new File(preferences.get("StartDirectory", "."));
             chooser.setCurrentDirectory(directory);
             if (chooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
-                File file = chooser.getSelectedFile();
+                final File file = chooser.getSelectedFile();
                 if (isValidModelFile(file)) {
                     // Set it in preferences so we remember next time
                     preferences.put("StartDirectory", file.getAbsolutePath());
@@ -116,13 +117,6 @@
                     }
                     game.start();
                    
-                    GameTaskQueueManager.getManager().update(new Callable<Object>() {
-                        public Object call() throws Exception {
-                            //MouseInput.get().setCursorVisible(true);
-                            return null;
-                        }
-                    });
-                   
                     DebugGameState debug = new DebugGameState();
                     GameStateManager.getInstance().attachChild(debug);
                     debug.setActive(true);
@@ -138,7 +132,24 @@
                     ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, locator);
                     ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_MODEL, locator);
 
-                    final Node modelNode = loadModel(file);
+                    Node modelNode = null;
+                   
+                    try {
+                        Future<Node> future = GameTaskQueueManager.getManager().update(new Callable<Node>() {
+
+                          public Node call() throws Exception {
+                            return loadModel(file);
+                          }
+                        });
+                        modelNode = future.get();
+                      } catch(InterruptedException ex) {
+                        ex.printStackTrace();
+                        System.exit(1);
+                      } catch(ExecutionException ex) {
+                        ex.printStackTrace();
+                        System.exit(1);
+                      } // catch
+                   
                     outputElapsed(time);
                     if (modelNode != null) {
                         modelNode.updateRenderState();
@@ -222,8 +233,7 @@
             throw new UnsupportedOperationException( "Unknown file type: " + file );
         }
         callable.setFile( file );
-        Future<Node> future = GameTaskQueueManager.getManager().update( callable );
-        return future.get();
+        return callable.call();
     }
 
     private static String extensionOf( String file ) {

Can you also say something concerning the fact described in the thread linked in the original post that programs hang when loadModel is called? (Probably better in mentioned thread rather than here.) It has something to do with the GameTaskQueueManager, but I cannot figure out a clean explanation. Loading models appears some kind of immensly tricky, although it seems like a quite basic feature.

When you use StandardGame, there are always at least 2 threads runing.

The OpenGL thread created by StandardGame, and the main thread.



Now when you call future.get() the main thread waits until the GameTask has been executed by the opengl thread.

(the GameTaskQueueManager is running and executing the GameTasks in the OpenGl thread).



But if there is no sperate OpenGl thread running the program hangs in a deadlock.

not!an!exit said:

Can you also say something concerning the fact described in the thread linked in the original post that programs hang when loadModel is called? (Probably better in mentioned thread rather than here.) It has something to do with the GameTaskQueueManager, but I cannot figure out a clean explanation. Loading models appears some kind of immensly tricky, although it seems like a quite basic feature.

Bottom line is the GameTaskQueueManager waits for itself when used to load a model.
Now I finally found the explanation why model loading on another thread worked for me in scalaxy :D