ClassNotFoundException for DefaultMouseEventProcessor

Hi, I am new to SWOGL.
There was a ClassNotFoundException thrown when I was trying to run “swoglContainer = SwoglContainer.create(canvas, swoglSetup);”. BTW the canvas is LWJGL canvas.
When I debugged I found that the Exception was due to “DefaultMouseEventProcessor” not found. But I could find the .class file for DefaultMouseEventProcessor in the jar. Could you please let me know if this issue is known? And what might be the possible solution?

Hello

The DefaultMouseEventProcessor, as the name implies, is a default implementation of the MouseEventProcessor interface. The interface as well as the default implementation are inner classes of the SwoglContainer. Thus, the class file is
SwoglContainer$DefaultMouseEventProcessor.class

Currently, I cannot imagine how it should find the outer class, but not the inner one. Can you describe your setup in more detail? But in doubt, I’ll have a closer look at this later today.

bye
Marco

Hi Marco,

I am using JmonkeyEngine to create an application where I want to have a popumenu on right click.
Below is the code snippet.



 public void initSWOGL()
	  {
		  swoglSetup = new SwoglSetupLWJGL();
		  canvas = ((JmeCanvasContext) this.getContext()).getCanvas();
	       
	        
	        JComponent controlPanel = createControlPanel();
	        SwoglComponent swoglComponent = 
	            SwoglComponents.create(controlPanel);
	        
	        swoglComponent.setTransform(
	                MatrixUtils.mul(
	                    MatrixUtils.translate(0,0,0), 
	                    MatrixUtils.scale(1f),
	                    MatrixUtils.rotateY(Math.toRadians(-10))));
	        **swoglContainer = SwoglContainer.create(canvas, swoglSetup);**  
	            swoglContainer.add(swoglComponent);
	        
	  }
	  
	  private JComponent createControlPanel()
	  {
	        JComponent controlPanel = new JPanel(new BorderLayout(0, 0));
	        
	        popup = new JPopupMenu();
			popup.add(new JMenuItem("click here"));
			controlPanel.add(popup);
	        return controlPanel;
	  }

The application hangs on executing “swoglContainer = SwoglContainer.create(canvas, swoglSetup);”. I debugged and fount that there was an exception when executing (SwoglContainer):

/**
     * The MouseEventProcessor, responsible for handling the mouse
     * events that happen on this SwoglContainer.
     */
    private MouseEventProcessor mouseEventProcessor = 
        new DefaultMouseEventProcessor(
            Conditions.<MouseEvent>trueCondition(), 
            Conditions.<MouseEvent>trueCondition()); 

Stack trace:

Thread [LWJGL Renderer Thread] (Suspended)
owns: Object (id=80)
owns: Object (id=81)
ClassNotFoundException(Throwable).(String, Throwable) line: 286
ClassNotFoundException(Exception).(String, Throwable) line: not available
ClassNotFoundException(ReflectiveOperationException).(String, Throwable) line: not available
ClassNotFoundException.(String) line: not available
URLClassLoader$1.run() line: not available
URLClassLoader$1.run() line: not available
AccessController.doPrivileged(PrivilegedExceptionAction, AccessControlContext) line: not available [native method]
Launcher$ExtClassLoader(URLClassLoader).findClass(String) line: not available
Launcher$ExtClassLoader(ClassLoader).loadClass(String, boolean) line: not available
Launcher$AppClassLoader(ClassLoader).loadClass(String, boolean) line: not available
Launcher$AppClassLoader.loadClass(String, boolean) line: not available
Launcher$AppClassLoader(ClassLoader).loadClass(String) line: not available
SwoglContainer.(Component, SwoglComponentHandler, PickingRayComputer) line: 177
SwoglContainer.create(Component, SwoglComponentHandler, PickingRayComputer) line: 252
SwoglContainer.create(Component, SwoglSetup) line: 209
Launcher.initSWOGL() line: 1043
Launcher$1.onAction(String, boolean, float) line: 238
InputManager.invokeActions(int, boolean) line: 169
InputManager.onMouseButtonEventQueued(MouseButtonEvent) line: 433
InputManager.processQueue() line: 831
InputManager.update(float) line: 881
Launcher(Application).update() line: 604
Launcher(SimpleApplication).update() line: 231
LwjglCanvas(LwjglAbstractDisplay).runLoop() line: 151
LwjglCanvas.runLoop() line: 229
LwjglCanvas(LwjglAbstractDisplay).run() line: 228
Thread.run() line: not available

The stack trace looks strange. It seems not to really throw the exception, but somehow to bail out during the creation of the Exception. It also seems like it tries to load the class via an additonal ClassLoader. JME obviously builds some larger infrastructure around every application…

However: I assume that you added the Swogl JAR to the classpath?
Can you run one of the „mini-examples“ from Swogl - Samples ?

Admittedly, I once tried to create a Swogl-Backend based on JME, because I already expected that people might want to use Swogl in JME :wink: But I failed horribly when trying to really integrate this backend into the JME infrastructure, using JME’s geometry and material classes.

So in general, I’m not sure whether and how Swogl will work together with JME. But can try to run some tests this evening, using the same approach that you tried there, and see whether I get something up and running.

Yes, I have added the jars in classpath. Please let me know the results after you test.

Thanks.

Hello

Just a short update: Until now, I did not succeed in creating a SwoglCompoent inside an JME Application.

It will be difficult in any case. JME is a complex piece of software. The few lines of code that a “SimpleApplication” consists of are hiding thousands (!) of lines of code that cover different rendering backends, settings, GL versions, input handling etc…

Originally, I tried to use the JME classes directly for a rendering backend, but this turned out to be hardly feasible. Now, I tried a different approach, based on what you sketched, namely using a JmeCanvasContext. I think that it might be possible to at least render the SwoglComponents, by bypassing some of the internals of JME.

But I still have doubts concerning a possible interaction: Swogl uses some “tricks” to obtain the Swing input events in order to forward them to the appropriate SwoglComponent. Similarly, JME uses many low-level tricks to poll keyboard an mouse events. It will be hard to combine those worlds.

However, your question showed me that my assumption that people might want to use something like Swogl in JME was right. Thus, I will have a closer look at this in the next time. But unfortunately, I can not promise that it will work.

In any case, I’ll post any updates about a possible progress here.

bye
Marco

Thanks for your time. Please do post if there is any possibility of using SWOGL with JME.

Thanks.

Hi,

I figured out the problem.

In SwoglContainer constructor:


 final JLayeredPane layeredPane = new JLayeredPane();
        
        // For debugging:
        if (DEBUG_SHOW_CONTENTS) layeredPane.setLayout(new GridLayout(2,1));
        
        layeredPane.add(containerScrollPane, Integer.valueOf(0));
       ** layeredPane.add(visibleComponent, Integer.valueOf(5000));**


When the LWJGLCanvas is added to the JLayeredPane, it is rejected because it is not a “Container”. And in the process of removing it, the LWJGLCanvas is calling wait() and the thread is getting stuck indefinitely.
Have you ever seen this issue with any LWJGLCanvas before?

Hello

I don’t see the connection to the LWJGLCanvas not being a Container, or what you mean with „rejected“.

I also experienced some problems with deadlocks during my first test. The message from the JME framework was roughly about „Canvas being removed, notifying ~something~ on the GL thread“ (I can look it up when I’m back on my development PC), but got rid of this somehow. I can clean up the code that I wrote for experimenting with this, and post it here this evening, maybe we some additional eyes will help to find a solution :slight_smile:

bye

I am sorry. I did not explain properly.

layeredPane.add(visibleComponent, Integer.valueOf(5000)); calls JlayeredPane.addImpl() internally.
The [Oracle Doc](http://docs.oracle.com/javase/7/docs/api/javax/swing/JLayeredPane.html#addImpl(java.awt.Component, java.lang.Object, int)) for addImpl says “If the component is not an ancestor of this container and has a non-null parent, it is removed from its current parent before it is added to this container.” In our case the component is the LWJGL canvas, which is not inheriting from java.awt.Container. This is the reason why the the canvas was being removed and LWJGLCanvas.removeNotify() is being invoked and it is waiting there indefinitely.

Thanks

Hm… I’m not sure, but the fact that the LWJGL Canvas is not a Container should not be related to this.

The documentation says: If the component … has a non-null parent, it is removed from its current parent before it is added to this container.

This means that IF the Canvas already HAD a parent (for example, if it already was added to some Frame), then something like
canvasParent.removeChild(canvas);
will be performed. Afterwards,
layeredPane.addChild(canvas);
will be performed (Pseudocode!). And the ‘removeChild’ method will cause ‘removeNotify’ to be called eventually. For an OpenGL canvas, this will usually cause the OpenGL context to be destroyed, that’s why there are some cleanup operations performed.

Or to put it that way: “this container” refers to the LayeredPane, and not to the component being added.

By the way, the “visibleComponent” at this place is practically always only a Canvas, and not a Container: For JOGL it is a GLCanvas, and for LWJGL it is an AWTGLCanvas. JME seems to have another Canvas type.

I’ll post some code later today, but again: It’s rather experimental…

This won’t compile for you, because the „contextChanged“ method is not public, but it might show what I intended to do: Bypass all of the JME mechanisms and just „hack in“ another rendering step - namely that of rendering the SwoglComponents. But as expected, it does not work. Whatever JME is doing there in the background, it is neither „normal rendering“, nor is there any possibility to perform custom rendering. Maybe I’ll do some more tests later, but I think that without some support from the JME team, it will hardly be possible to achieve anything there - unless I simply did not yet find the right place to initialize the shaders and/or issue own GL calls. Actually, it can’t be that hard, but IF it is possible, they managed to hide the appropriate place pretty well :wink:

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Dimension;

import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.Vector3f;
import com.jme3.renderer.lwjgl.LwjglRenderer;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeCanvasContext;
import com.jme3.system.SystemListener;
import com.jme3.system.lwjgl.LwjglCanvas;
import com.jme3.texture.Texture;

import de.javagl.swogl.MatrixUtils;
import de.javagl.swogl.SwoglComponent;
import de.javagl.swogl.SwoglComponents;
import de.javagl.swogl.SwoglContainer;
import de.javagl.swogl.rendering.SwoglSetupLWJGL;

public class JMESwoglTest extends SimpleApplication
{
    public static void main(String[] args)
    {
        //System.setProperty("org.lwjgl.util.Debug", "true");

        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                createAndShowGUI();
            }
        });
    }

    SwoglSetupLWJGL swoglSetup = null;
    SwoglContainer swoglContainer = null;
    SwoglComponent swoglComponent = null;

    private static void createAndShowGUI()
    {
        // Create the application
        JMESwoglTest application = new JMESwoglTest();
        AppSettings settings = new AppSettings(true);
        settings.setWidth(640);
        settings.setHeight(480);
        //settings.setUseInput(false);
        application.setSettings(settings);
        application.createCanvas();
        
        // Set up the canvas
        Dimension dim = new Dimension(640, 480);
        JmeCanvasContext canvasContext = 
            (JmeCanvasContext)application.getContext();
        canvasContext.getCanvas().setPreferredSize(dim);

        application.initSwogl();

        // Create the main frame and add the Swogl main component
        JFrame frame = new JFrame("Application");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(application.swoglContainer.getMainComponent());
        frame.setSize(600, 600);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        application.startCanvas(true);
    }
    
    /**
     * Create the SwoglSetup, SwoglContainer and a 
     * SwoglComponent
     */
    public void initSwogl()
    {
        swoglSetup = new SwoglSetupLWJGL();

        JComponent controlPanel = createControlPanel();
        swoglComponent = SwoglComponents.create(controlPanel, 200, 200);

        swoglComponent.setTransform(
            MatrixUtils.mul(
                MatrixUtils.translate(0, 0, 0), 
                MatrixUtils.scale(1.0f), 
                MatrixUtils.rotateX(Math.toRadians(-10))));

        Canvas canvas = ((JmeCanvasContext)this.getContext()).getCanvas();
        swoglContainer = SwoglContainer.create(canvas, swoglSetup);
        swoglContainer.add(swoglComponent);
    }

    /**
     * Create the contents of the SwoglComponent
     * @return The component
     */
    private JComponent createControlPanel()
    {
        JComponent controlPanel = new JPanel(new BorderLayout(0, 0));
        JPopupMenu popup = new JPopupMenu();
        popup.add(new JMenuItem("click here"));
        controlPanel.add(popup);
        return controlPanel;
    }
    

    // Overridden method from 'Application'
    @Override
    public void createCanvas()
    {
        System.out.println("createCanvas");
        if (context != null && context.isCreated())
        {
            System.err.println("createCanvas() called when application already created!");
            return;
        }

        if (settings == null)
        {
            settings = new AppSettings(true);
        }

        // Directly creating the desired canvas here
        // context = JmeSystem.newContext(settings, JmeContext.Type.Canvas);
        context = new SwoglLwjglCanvas();
        context.setSystemListener(new DelegatingSystemListener(this)
        {
            @Override
            public void update()
            {
                super.update();
                System.out.println("update");
                swoglSetup.getSwoglComponentHandler().renderAllSwoglComponents();
            }
        });
        
    }
    
    
    private class DelegatingSystemListener implements SystemListener
    {
        private SystemListener delegate;
        DelegatingSystemListener(SystemListener delegate)
        {
            this.delegate = delegate;
        }
            
        @Override
        public void update()
        {
            delegate.update();
        }

        @Override
        public void reshape(int width, int height)
        {
            delegate.reshape(width, height);
        }

        @Override
        public void requestClose(boolean esc)
        {
            delegate.requestClose(esc);
        }

        @Override
        public void loseFocus()
        {
            delegate.loseFocus();
        }

        @Override
        public void initialize()
        {
            delegate.initialize();
        }

        @Override
        public void handleError(String errorMsg, Throwable t)
        {
            delegate.handleError(errorMsg, t);
        }

        @Override
        public void gainFocus()
        {
            delegate.gainFocus();
        }

        @Override
        public void destroy()
        {
            delegate.destroy();
        }
    }



    @Override
    public void simpleInitApp()
    {
        Box boxshape1 = new Box(new Vector3f(0f, 2.1f, 0f), 1f, 1f, 1f);
        Geometry cube = new Geometry("My Textured Box", boxshape1);
        Material mat_stl = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        Texture tex_ml = assetManager.loadTexture("Interface/Logo/Monkey.jpg");
        mat_stl.setTexture("ColorMap", tex_ml);
        cube.setMaterial(mat_stl);
        rootNode.attachChild(cube);
    }

    /**
     * Extension of LwjglCanvas that created a SwoglLwjglRenderer
     * instead of a LwjglRenderer, and updates the context in
     * the SwoglSetup
     */
    private class SwoglLwjglCanvas extends LwjglCanvas
    {
        @Override
        protected void createContext(AppSettings settings)
        {
            super.createContext(settings);

            System.out.println("Context changed");
            swoglSetup.getSwoglComponentHandler().contextChanged();
        }

        @Override
        protected void initContextFirstTime()
        {
            super.initContextFirstTime();

            // Overwriting the renderer that is
            // created in the super-method
            System.out.println("Initializing context");
            renderer = new SwoglLwjglRenderer();
            ((LwjglRenderer)renderer).initialize();
        }
    }

    private class SwoglLwjglRenderer extends LwjglRenderer
    {
        @Override
        public void onFrame()
        {
            super.onFrame();
            //System.out.println("onFrame");
            //swoglSetup.getSwoglComponentHandler().renderAllSwoglComponents();
        }
    }
    

}