Issue: reparenting SwoglContainer

Hi Marco

Ich habe mal ein bisschen mit Swogl rumgespielt, und dabei ist mir folgendes aufgefallen: Wenn man einen SwoglContainer von einem Window in ein anderes schiebt, gehen alle Texturen verloren. Unten ist ein Program, welches bei mir den Fehler immer reproduzieren kann (einfach auf den einsamen JButton klicken…).

Getestet mit Java 1.6, Ubuntu 64 bit, LWJGL


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import de.javagl.swogl.SwoglApplication;
import de.javagl.swogl.SwoglApplications;
import de.javagl.swogl.SwoglContainer;
import de.javagl.swogl.samples.SwoglDemoComponents;

public class EmptySwoglTest {
	public static void main( String[] args ){
		final JFrame frameA = new JFrame("A");
		final JFrame frameB = new JFrame("B");
		
		frameA.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frameB.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		
		frameA.setBounds( 20, 20, 400, 320 );
		frameB.setBounds( 20, 340, 400, 300 );
		
		JButton action = new JButton( "click me" );
		final Component panel = createSwoglPanel();
		frameA.add( panel, BorderLayout.CENTER );
		
		frameA.add( action, BorderLayout.NORTH );
		action.addActionListener( new ActionListener(){
			private boolean state = true;
			
			@Override
			public void actionPerformed( ActionEvent e ){
				if( state ){
					frameB.add( panel, BorderLayout.CENTER );
				}
				else{
					frameA.add( panel, BorderLayout.CENTER );
				}
				state = !state;
			}
		});
		
		frameA.setVisible( true );
		frameB.setVisible( true );
	}
	
	private static Component createSwoglPanel(){
		JPanel panel = new JPanel( new BorderLayout() );
		
		SwoglApplication swoglApplication = SwoglApplications.createSwoglApplication();

		SwoglContainer swoglContainer = SwoglContainer.create( swoglApplication );
		Component mainComponent = swoglContainer.getMainComponent();
		panel.add( mainComponent, BorderLayout.CENTER );

		// Create the SwoglComponents for this sample and adds them to the
		// SwoglContainer
		swoglContainer.add( SwoglDemoComponents.createSwoglLogoComponent() );
		swoglContainer.add( SwoglDemoComponents.createTableComponent() );
		swoglContainer.add( SwoglDemoComponents.createTextComponent() );
		swoglContainer.add( SwoglDemoComponents.createSplitPaneComponent() );
		swoglContainer.add( SwoglDemoComponents.createTreeComponent() );
		
		return panel;
	}
}

(See below for a short english summary)

Hallo

Das konkrete Programm kann ich hier gerade nicht testen, aber falls notwendig mache ich das am Dienstag. Ich denke aber, dass das Problem schon in ähnlicher Form berichtet wurde bzw. bekannt ist: Dort ging es darum, dass bei einem Verschieben eines SwoglContainers von einem Tab eines JTabbedPane auf ein anderes Tab die Texturen verloren gingen (in diesem Fall mit JOGL, aber die Ursache ist wohl die gleiche).

Tatsächlich ist das kein Swogl-spezifisches Problem, sondern eins der üblichen OpenGL-Anbindungen: Die OpenGL-Anbindungen erstellen ein natives Fenster, das quasi als handle für den OpenGL context dient. Dieses Fenster wird lebendig sobald es auf dem Bildschirm erscheint - d.h. wenn es irgendwo in der Component-Hierarchie unter einem sichtbaren JFrame hängt (Stichworte: JComponent native peer & Co). Und das entscheidende: Wenn es von dieser sichtbaren Hierarchie entfernt wird, dann wird der OpenGL context zerstört - und damit alle Daten und Textur-IDs, die darin erzeugt wurden. (Das gleiche Problem würde also auch bei Texturen auftreten, die man selbst mit glGenTextures erstellt hätte, wenn man den GLCanvas verschieben wollte).

Allerdings sollte Swogl für reine Anwender (die sich nicht einen eigenen Renderer schreiben wollen) ja so weit wir möglich irgendwelche GL-Spezifika verstecken. Alles sollte sich so handhaben lassen wie “normales” Swing - abgesehen von der heavyweight rendering-component. Es gibt einen Workaround, der schon funktionieren würde, aber SO unschön ist, dass ich ihn ungern jemandem zumuten würde: Alle SwoglComponents neu erstellen und neu hinzufügen :suspect: . Stattdessen würde ich das lieber so weit wie möglich automatisch machen: Alle notwendigen Daten für eine neu-initialisierung der GL-IDs sind ja vorhanden. Für JOGL hatte ich das schon eingebaut (ich glaube aber noch nicht in der Version, die gerade auf der Seite steht). Bei LWJGL könnte es schwieriger sein, zu erkennen, wann der Kontext zerstört wurde, aber ich werde nächste Woche gleich mal schauen, wo man da ansetzen könnte.

Ich habe viel gebastelt in letzter Zeit, nächste Woche wird die Seite ein bißchen aktualisiert und eine neue Version hochgeladen. Vielleicht schaffe ich es da schon, diese automatische neu-Initialisierung einzubauen.

bye
Marco

— Short english summary:

When a SwoglContainer is moved from one Frame to another one, all the Textures are lost. More general, this happens when removing a SwoglContainer from the component hierarchy and adding it again. This behavior is not specific for Swogl. Instead, it’s due to the behavior of the underlying OpenGL bindings: When the rendering component is removed from its parent, then the OpenGL context is destroyed - and thus, all the textures are lost. I’ll try to integrate an functionality to automatically re-initialize the textures when a SwoglContainer is removed from its parent and added to another one.

Ich hab derzeit nicht vor wirklich was mit Swogl zu machen. Ich habe einfach irgendeine krasse native Component gebraucht um in meinem Framework was auszuprobieren.

Vielleicht nützt dir der java.awt.event.HierarchyListener was, der sollte dir sagen, wann eine Component herumgeschoben wurde.

Ja, das wäre vielleicht eine Möglichkeit. Bei JOGL ist’s relativ leicht: Dort ändert sich das GL-Objekt (auch wenn das kein wirklich zuverlässiges Kriterium ist). Aber für LWJGL muss ich mal schauen. Mit einem HierarchyListener könnte das sogar gehen.

In der aktualisierten Version (0.3.0) auf http://swogl.javagl.de/ sollte auch das reparenting funktionieren.

Supi

Irgendwann (07.02.2010) stand ja auch mal eine Swogl-DockStation im Raum - hast du die Idee wiederbelebt?
Zugegeben: So eine lange Entwicklungspause wie jetzt bei Swogl wirkt nicht gerade Vertrauenserweckend :o
Arbeitest du an DockingFrames eigentlich Vollzeit? Wenn ich mir den Umfang der Bibliothek, die Aktivität hier im Forum und die release notes da immer ansehe… :eek:

Weit weg von Vollzeit, maximal 4-5 Stunden in der Woche.

Die Idee mit der DockStation geistert noch herum, aber ich weiss immernoch nicht wie die überhaupt aussehen soll. Und bis mir nichts gescheites eingefallen ist, wird das Projekt weiterhin schlafen.