[QUOTE=Fancy]Seit OpenGL 1.2 erfolgen die OpenGL Aufrufe über Funktionszeiger.[/QUOTE]Das meinte ich so nicht. Wo du in C z.B. “glLoadIdentity()” schreibst, kannst du in LWJGL genauso “glLoadIdentity()” schreiben, wenn du entsprechende Klassen statisch importierst. In JOGL kannst du diese Funktionen nur auf ein Objekt anwenden: “gl.glLoadIdentity()”. Soweit ich weiss, kannst (bzw. musst) du in LWJGL (lediglich) einen PBuffer (ist das der Context?) pro Thread haben. Die Klasse Display ist dort nur eine Hilfsklasse, die dir neben anderen Kleinigkeiten recht einfach ein GL-Fenster hinzaubert. Mit LWJGL geht aber viel mehr, so lässt sich mit folgendem z.B. relativ einfach eine GLComponent realisieren.
import static org.lwjgl.opengl.GL11.*;
import static org.lwjgl.util.glu.GLU.*;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Set;
import java.util.TreeSet;
import javax.datatypes.utils.IdentityArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.lwjgl.LWJGLException;
import org.lwjgl.opengl.Pbuffer;
import org.lwjgl.opengl.PixelFormat;
public class KSKB {
public static void main(String[] args) {
JFrame f = new JFrame("Swing LWJGL");
GLJPanel gljp = new GLJPanel() {
private static final long serialVersionUID = -38094150939029442L;
private final float[] bg = new float[4];
@Override
protected void initGL() {
glEnable(GL_TEXTURE_2D);
glShadeModel(GL_SMOOTH);
getBackground().getColorComponents(bg);
glClearColor(bg[0], bg[1], bg[2], bg[3]);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, getWidth() / (float) getHeight(), 0.1f,
100.0f);
glMatrixMode(GL_MODELVIEW);
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
}
@Override
protected void paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(-1.5f, 0.0f, -6.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 1.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glEnd();
glTranslatef(3.0f, 0.0f, 0.0f);
glColor3f(0.5f, 0.5f, 1.0f);
glBegin(GL_QUADS);
glVertex3f(-1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, 1.0f, 0.0f);
glVertex3f(1.0f, -1.0f, 0.0f);
glVertex3f(-1.0f, -1.0f, 0.0f);
glEnd();
}
};
gljp.setSize(800, 600);
gljp.setPreferredSize(gljp.getSize());
gljp.setMaximumSize(gljp.getSize());
gljp.setMinimumSize(gljp.getSize());
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(gljp);
f.pack();
f.setVisible(true);
}
}
class PbufferMap {
private static final long IDLE_TIMEOUT = 5000;
private static final long IDLE_TIMEOUT_NANOS = IDLE_TIMEOUT * 1000000;
private static final ResourceSet REFERENCE = new ResourceSet(null);
private static final PixelFormat FORMAT = new PixelFormat();
private static final ThreadSet CACHE = new ThreadSet();
private static int cnt;
static boolean aquire(Object ressource) {
synchronized (CACHE) {
Thread t = Thread.currentThread();
ResourceSet r = CACHE.forThread(t);
if(r == null) {
r = new ResourceSet(t);
CACHE.add(r);
}
r.add(ressource);
return r.refresh();
}
}
static void release(Object ressource) {
synchronized (CACHE) {
Thread t = Thread.currentThread();
ResourceSet r = CACHE.forThread(t);
if(r != null) {
r.remove(ressource);
}
}
}
private static final class ThreadSet extends IdentityArrayList<ResourceSet> {
private static final long serialVersionUID = 8331589906165047839L;
private Thread scheduler;
synchronized ResourceSet forThread(Thread t) {
if(scheduler == null) {
scheduler = new Thread("Pbuffer Dispose Scheduler " + (cnt++)) {
private TreeSet<ResourceSet> ressources = new TreeSet<>();
{
setDaemon(true);
}
@Override
public void run() {
while(true) {
synchronized (this) {
try {
wait(IDLE_TIMEOUT);
} catch(InterruptedException e) {
break;
}
}
REFERENCE.refresh();
synchronized (CACHE) {
ressources.addAll(CACHE);
}
Set<ResourceSet> tail = new HashSet<>(ressources.tailSet(REFERENCE, false));
if(!tail.isEmpty()) {
for(ResourceSet r : tail) {
r.destroy();
ressources.remove(r);
}
synchronized (CACHE) {
CACHE.retainAll(ressources);
if(CACHE.isEmpty()) {
break;
}
}
}
}
scheduler = null;
}
};
scheduler.start();
}
for(ResourceSet r : this) {
if(r.t == t) {
return r;
}
}
return null;
}
}
private static final class ResourceSet extends IdentityHashMap<Object, Object> implements Comparable<ResourceSet> {
private static final long serialVersionUID = -3207232556780437227L;
private final Thread t;
private Pbuffer buffer;
private long nanos;
private ResourceSet(Thread t) {
this.t = t;
}
void destroy() {
if(buffer != null) {
try {
buffer.destroy();
buffer = null;
} catch(Exception e) {
// dann halt nicht
}
}
}
void add(Object ressource) {
if(get(ressource) == null) {
put(ressource, this);
}
}
boolean refresh() {
nanos = System.nanoTime();
if(this != REFERENCE) {
try {
glGetString(GL_VENDOR);
if(buffer != null && !buffer.isCurrent()) {
buffer.destroy();
buffer = null;
return true;
}
return false;
} catch(Throwable e) {
try {
if(buffer == null || buffer.isBufferLost()) {
buffer = new Pbuffer(1, 1, FORMAT, null);
buffer.makeCurrent();
return true;
}
buffer.makeCurrent();
return false;
} catch(LWJGLException ee) {
throw new RuntimeException("open gl not available");
}
}
}
nanos -= IDLE_TIMEOUT_NANOS;
return false;
}
@Override
public int compareTo(ResourceSet o) {
long n = nanos - o.nanos;
return (n > 0)? -1 : (n < 0)? 1 : 0;
}
@Override
public String toString() {
return "" + nanos;
}
}
}
class GLJPanel extends JPanel {
private static final long serialVersionUID = -6189316223432196535L;
private byte[] transBufferByte = new byte[4];
private ByteBuffer data;
private BufferedImage img;
private int fbID = -1, texID = -1;
@Override
public final void paint(Graphics g) {
super.paint(g);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
paintGL(g);
}
protected void paintGL() {
}
protected void initGL() {
}
private void paintGL(Graphics g) {
int w = getWidth();
int h = getHeight();
int c = w * h * 4;
PbufferMap.aquire(this);
if (data == null || data.capacity() != c) {
initGL(w, h, c);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbID);
glPushAttrib(GL_VIEWPORT_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, w, h);
paintGL();
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, data);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glPopAttrib();
glFlush();
int color, p;
for (; data.position() < c;) {
p = data.position() / 4;
data.get(transBufferByte);
color = ((transBufferByte[3] & 0xFF) << 24)
| ((transBufferByte[0] & 0xFF) << 16)
| ((transBufferByte[1] & 0xFF) << 8)
| (transBufferByte[2] & 0xFF);
img.setRGB(p % w, h - 1 - p / w, color);
}
data.rewind();
g.drawImage(img, 0, 0, getWidth(), getHeight(), this);
}
private void initGL(int w, int h, int c) {
data = ByteBuffer.allocateDirect(c).order(
ByteOrder.nativeOrder());
img = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
if (fbID > 0) {
glDeleteTextures(texID);
glDeleteFramebuffersEXT(fbID);
}
fbID = glGenFramebuffersEXT();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbID);
texID = glGenTextures();
glBindTexture(GL_TEXTURE_2D, texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA,
GL_UNSIGNED_BYTE, (ByteBuffer) null);
glBindTexture(GL_TEXTURE_2D, 0);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, texID, 0);
int status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT exception");
case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_FORMATS exception");
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT exception");
case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE exception");
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER exception");
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
throw new RuntimeException(
"FrameBuffer has caused a GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER exception");
default:
throw new RuntimeException(
"Unexpected reply from glCheckFramebufferStatusEXT: "
+ status);
}
initGL();
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
PbufferMap.release(this);
}
}```Die PBufferMap erstellt bei Bedarf PBuffers und entfernt diese wieder, wenn sie einen längeren Zeitraum über nicht verwendet wurden. Den GLJPanel muss man nur erweitern und "paintGL" und "intiGL()" überschreiben. Die einzige Anpassung, die bei Bedarf noch getätigt werden müsste, ist, dass man ExtFrameBuffer2D gegen entsprechende FrameBuffer2D funktionen ersetzt, sofern diese vorhanden sind, das ist afaik erst ab GL3.0 der Fall.