Translucency 3d LWJGL/JOGL windows?

JDK6 has an unofficial translucency window API and JDK7 supposed to give a public API.
http://download.oracle.com/javase/tutorial/uiswing/misc/trans_shaped_windows.html
http://java.sun.com/developer/technicalArticles/GUI/translucent_shaped_windows/
http://www.curious-creature.org/2007/09/28/translucent-shaped-windows-extreme-gui-makeover/

Demos works fine in WinXP/Win7 machine, applications use Java2D rendering. I have not tried animated j2d windows yet how its working.

But is there a way use LWJGL or JOGL app pixel-perfect translucent windows?

I have seen some DirectX 3d animated demos doing it so technically its possible in Windows.

Hi!

JOGL 1.1.1a can work with this but I have never tested this feature with JOGL 2.0 beta.

Thx, do anyone has or know a simple demo JOGL application doing it?
Would love to see LWJGL demo as well if its capable of doing it.

All LWJGL is, is a GL binding. Use AWT to manage your windows.

Cas :slight_smile:

I gave a test LWJGL-2.6 library, could not get it work. Trying to run a simple 3d animation with fully transparent background. Animation objects may have 0-100% translucency pixels.

AWTUtilities.setWindowOpaque(this, false);
If I give true its a normal undecored window and animation works properly. Giving false seems to render nothing and window is like a ghost. Its there but not really shown anything.


package fi.mbnet.akini.lwjgl;

import java.nio.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

import org.lwjgl.opengl.*;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.util.glu.*;

import com.sun.awt.AWTUtilities;

public class AWTTest extends Frame {
	private Thread renderThread;
	private GameCanvas canvas;

	public void initialize() throws LWJGLException {
		setUndecorated(true);
		setBackground(new Color(0,0,0,0));
		setTitle("AWTTest");
		setSize(640, 480);
		setLocation(40,40);

		// true  = opaque undecored window works
		// false = per-pixel transparency window does not work
		AWTUtilities.setWindowOpaque(this, false);

		setLayout(new GridLayout(1,1));

		canvas = new GameCanvas();
		add(canvas);

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				try {
					renderThread.interrupt();
					renderThread.join(5*1000);
				} catch (Exception ex) { }
				renderThread = null;
				dispose();
			}
		});

		addComponentListener(new ComponentAdapter() {
			public void componentMoved(ComponentEvent evt) {
				canvas.isInitialized = false;
				System.out.println( String.format("moved to %d,%d", getX(), getY()) );
			}
			public void componentResized(ComponentEvent evt) {
				Shape shape = new Rectangle(0, 0, getWidth(), getHeight());
				//Shape shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());

				AWTUtilities.setWindowShape(AWTTest.this, shape); 

				canvas.isInitialized = false;
				System.out.println( String.format("resized to %d,%d", getWidth(), getHeight()) );
			}
		});

		// add same listeners to frame and canvas objects
		addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent evt) {
				switch(evt.getKeyCode()) {
				case KeyEvent.VK_ESCAPE:
					Frame frm = AWTTest.this;
					frm.dispatchEvent(new WindowEvent(frm, WindowEvent.WINDOW_CLOSING));
					break;
				}
			}
		});
		for(KeyListener listener : getKeyListeners())
			canvas.addKeyListener(listener);
	
		renderThread = new Thread(new Runnable() {
			public void run() {
				while(true) {
					try {
						Thread.sleep( (long)1000/60 );
						canvas.update();
						canvas.repaint();
					} catch (InterruptedException ex) {
						break;
					} catch (Exception ex) {
						ex.printStackTrace();
						//break;
					}
				}
			}
		});
		renderThread.start();
	}

//************************************************************
//************************************************************

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				AWTTest test = new AWTTest();
				try {
					test.initialize();
					test.setResizable(true);
					test.setVisible(true);
				} catch (Exception ex) { 
					ex.printStackTrace();
				}
			}
		});
	}

//************************************************************
//************************************************************

	private class GameCanvas extends AWTGLCanvas {
		private int curHeight = -1;
		private int curWidth = -1;
		private volatile float angle;
		private volatile boolean isInitialized;

		private GameCanvas() throws LWJGLException  {
			super();
		}

		private void initialize() {
			System.out.println("initialize");
			curWidth  = getWidth();
			curHeight = getHeight();
			GL11.glViewport(0, 0, curWidth, curHeight);
			GL11.glLoadIdentity();
			GLU.gluOrtho2D(0.0f, (float)curWidth, 0.0f, (float)curHeight);
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
		}

		public void update() {
			angle += 2.0f;
		}

		public void paintGL() {
			try {
				//if (getWidth() != curWidth || getHeight() != curHeight) {
				if (!isInitialized) {
					initialize();
					isInitialized = true;
				}

				// clear background
				GL11.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
				GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

				// rotate box at a center
				GL11.glPushMatrix();
				GL11.glColor3f(1f, 1f, 0f);
				GL11.glTranslatef((float)curWidth / 2.0f, (float)curHeight / 2.0f, 0.0f);
				GL11.glRotatef(angle, 0f, 0f, 1.0f);
				GL11.glRectf(-50.0f, -50.0f, 50.0f, 50.0f);
				GL11.glPopMatrix();

				swapBuffers();
			} catch (Exception ex) {
				throw new RuntimeException(ex);
			}
		}
	}

}

Some progress, using ellipse window, AWTGLCanvas and JPanel panel components, rotating rectangles. Here is a screenshot.

http://koti.mbnet.fi/akini/lwjgl/

But it is unusable at the moment, runs very slow eating CPU 100%. Lower part jpanel is transparent but lwjgl upper part is always opaque. I guess it was not that simple to use java 3d libraries as was hoping for. Working DirectX 3d demos I’ve seen might do some heavy tricks, although they run super smooth and low cpu%.


/**
 * http://koti.mbnet.fi/akini/
 * @author Aki Nieminen
 * @version $Id$
 */
package fi.mbnet.akini.lwjgl;

import java.nio.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;

import org.lwjgl.opengl.*;
import org.lwjgl.BufferUtils;
import org.lwjgl.LWJGLException;
import org.lwjgl.util.glu.*;

import com.sun.awt.AWTUtilities;

/**
 * Test translucent Java window
 * http://www.java-gaming.org/index.php/topic,23127.0.html
 */
public class AWTTest extends Frame {
	private Thread renderThread;
	private GameCanvas canvas;
	private FooPanel panel;

	public void initialize() throws LWJGLException {
		setUndecorated(true);
		setBackground(new Color(0,0,0,0));
		setTitle("AWTTest");
		setSize(640, 480);
		setLocation(40,40);

		setLayout(new GridLayout(2,1));

		canvas = new GameCanvas();
		add(canvas);

		panel = new FooPanel();
		add(panel);

		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent evt) {
				try {
					renderThread.interrupt();
					renderThread.join(5*1000);
					// set to opaque or window area may show garbage
					Shape shape = new Rectangle(0, 0, getWidth(), getHeight());
					AWTUtilities.setWindowShape(AWTTest.this, shape); 
					AWTUtilities.setWindowOpaque(AWTTest.this, true);
				} catch (Exception ex) { }
				renderThread = null;
				dispose();
			}
		});

		addComponentListener(new ComponentAdapter() {
			public void componentShown(ComponentEvent evt) {
				if (!AWTUtilities.isWindowOpaque(AWTTest.this)) 
					return;
				AWTUtilities.setWindowOpaque(AWTTest.this, false);
				System.out.println("setWindowOpaque=false");

			}
			public void componentMoved(ComponentEvent evt) {
				canvas.isInitialized = false;
				System.out.println( String.format("moved to %d,%d"
					, getX(), getY()
				));
			}
			public void componentResized(ComponentEvent evt) {
				//Shape shape = new Rectangle(0, 0, getWidth(), getHeight());
				Shape shape = new Ellipse2D.Float(0, 0, getWidth(), getHeight());
				AWTUtilities.setWindowShape(AWTTest.this, shape); 

				canvas.isInitialized = false;
				System.out.println( String.format("resized to %d,%d"
					, getWidth(), getHeight()
				));
			}
		});

		// add same listeners to frame and canvas objects
		addKeyListener(new KeyAdapter() {
			public void keyReleased(KeyEvent evt) {
				switch(evt.getKeyCode()) {
				case KeyEvent.VK_ESCAPE:
					Frame frm = AWTTest.this;
					frm.dispatchEvent(new WindowEvent(frm, WindowEvent.WINDOW_CLOSING));
					break;
				}
			}
		});
		for(KeyListener listener : getKeyListeners()) {
			canvas.addKeyListener(listener);
		}
	
		renderThread = new Thread(new Runnable() {
			public void run() {
				while(true) {
					try {
						Thread.sleep( (long)1000/15 );
						panel.update();
						canvas.update();
						//panel.repaint();
						//canvas.repaint();
						AWTTest.this.repaint();
					} catch (InterruptedException ex) {
						break;
					} catch (Exception ex) {
						ex.printStackTrace();
						//break;
					}
				}
			}
		});
		renderThread.start();
	}

//************************************************************
//************************************************************

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				AWTTest test = new AWTTest();
				try {
					test.initialize();
					test.setResizable(true);
					test.setVisible(true);
				} catch (Exception ex) { 
					ex.printStackTrace();
				}
			}
		});
	}

//************************************************************
//************************************************************

	private class GameCanvas extends AWTGLCanvas {
		private int curHeight = -1;
		private int curWidth = -1;
		private volatile float angle;
		private volatile boolean isInitialized;

		private GameCanvas() throws LWJGLException  {
			super();
		}

		private void initialize() {
			System.out.println("initialize");
			curWidth  = getWidth();
			curHeight = getHeight();
			GL11.glViewport(0, 0, curWidth, curHeight);
			GL11.glLoadIdentity();
			GLU.gluOrtho2D(0.0f, (float)curWidth, 0.0f, (float)curHeight);
			GL11.glMatrixMode(GL11.GL_MODELVIEW);
		}

		public void update() {
			angle += 2.0f;
		}

		public void paintGL() {
			try {
				//if (getWidth() != curWidth || getHeight() != curHeight) {
				if (!isInitialized) {
					initialize();
					isInitialized = true;
				}

				// clear background
				GL11.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
				GL11.glClear(GL11.GL_COLOR_BUFFER_BIT);

				// rotate box at a center
				GL11.glPushMatrix();
				GL11.glColor3f(1f, 1f, 0f);
				GL11.glTranslatef((float)curWidth / 2.0f, (float)curHeight / 2.0f, 0.0f);
				GL11.glRotatef(angle, 0f, 0f, 1.0f);
				GL11.glRectf(-50.0f, -50.0f, 50.0f, 50.0f);
				GL11.glPopMatrix();

				swapBuffers();
			} catch (Exception ex) {
				throw new RuntimeException(ex);
			}
		}
	}


//************************************************************
//************************************************************

	private class FooPanel extends JPanel {
		double angle = 0;
		private void update() {
			angle += 2;
			if (angle >= 360) angle = 0;
		}

		protected void paintComponent(Graphics g) {
			final int R = 040;
			final int G = 140;
			final int B = 240; 
			Paint p = new GradientPaint(0.0f, 0.0f, 
				new Color(R, G, B, 0),
				getWidth(), getHeight(), 
				new Color(R, G, B, 255), 
				false
			);
			Graphics2D g2d = (Graphics2D)g;
			g2d.setPaint(p);
			g2d.fillRect(0, 0, getWidth(), getHeight());

			g2d.setColor(new Color(150,60,170,127));
			g2d.rotate(Math.toRadians(angle), getWidth()/2, getHeight()/2);
			g2d.translate(getWidth()/2-100, getHeight()/4-40);
			g2d.fillRect(50, 50, 100, 100);
		}
	}

}

Our demos are there:

If you want to use the source code you already wrote but with JOGL, replace the AWTGLCanvas by our GLCanvas. I remind you that JOGL is known for its quite good interoperability with Java2D/Swing:
http://weblogs.java.net/blog/2006/10/12/easy-2d3d-mixing-swing
This demo uses GLJPanel (Swing OpenGL panel).