JOGL 2.0 Bug?

Friedhelm

Bekanntes Mitglied
Ich möchte einen Screenshot von meinem OPENGL Screen unter JOGL 2 machen.

Jedoch bekomme ich bei (1920 1080 60 32 / Window 1024*576) in Zeile 25 und
dem unten stehenden Quellcode folgenden Fehler:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Required 1788720 remaining bytes in buffer, only had 1769472
at com.sun.gluegen.runtime.BufferFactory.rangeCheckBytes(BufferFactory.java:311)
at com.sun.opengl.impl.gl2.GL2Impl.glReadPixels(GL2Impl.java:16274)
at com.lefutura.lfengine.glrenders.GLRenderer_JOGL_2.takeScreenshot(GLRenderer_JOGL_2.java:378)
at com.lefutura.lfengine.LFEngineLoop.receivedTouchClickedAction(LFEngineLoop.java:208)
at


Mache ich das selbe mit LWJGL (gleicher Code) funktioniert es einwandfrei.



Java:
public void takeScreenshot(int width, int height) {


		long startTime = System.currentTimeMillis();



		int[] nBits = {8, 8, 8};
		int[] bOffs = {0, 1, 2};

		BufferedImage screenshotImage;	  


		ByteBuffer pixels;			
		DataBuffer db;
		WritableRaster raster;

		ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
		ColorModel cm = new ComponentColorModel(cs, nBits, false, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);

		byte [] byteA=new byte[callbackRenderer.screenWidth*callbackRenderer.screenHeight*3];	

		pixels = ByteBuffer.allocateDirect(callbackRenderer.screenWidth*callbackRenderer.screenHeight*3);		
		gl.glReadPixels(0, 0, callbackRenderer.screenWidth, callbackRenderer.screenHeight, GL2.GL_RGB, GL2.GL_UNSIGNED_BYTE, pixels);
		
		pixels.get(byteA);		
		db = new DataBufferByte(byteA, callbackRenderer.screenWidth*callbackRenderer.screenHeight, 0);
		
		raster = Raster.createInterleavedRaster(db, callbackRenderer.screenWidth, callbackRenderer.screenHeight, callbackRenderer.screenWidth*3, 3, bOffs, null);		
		screenshotImage = new BufferedImage(cm, raster, false, null);//new java.util.Hashtable());

		 // * Flip Image Y Axis *
        AffineTransform tx = AffineTransform.getScaleInstance(1, -1); 
        tx.translate(0, -screenshotImage.getHeight(null)); 
        AffineTransformOp op = new AffineTransformOp(tx, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); 
        screenshotImage = op.filter(screenshotImage, null); 
		
		
		long endTime = System.currentTimeMillis() - startTime;		
		System.out.println("Capture Image Time: " + endTime);


		try {
			ImageIO.write(screenshotImage, "PNG", new File("test.png"));
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
 
Moin,

keine Ahnung wo der Fehler oben konkret genau liegt, aber:

Exception in thread "AWT-EventQueue-0" java.lang.IndexOutOfBoundsException: Required 1788720 remaining bytes in buffer, only had 1769472
at com.sun.gluegen.runtime.BufferFactory.rangeCheckBytes(BufferFactory.java:311)
at com.sun.opengl.impl.gl2.GL2Impl.glReadPixels(GL2Impl.java:16274)

Läst leider schon auf ein grundlegendes Problem schließen. Der Fehlermeldung nach, wird OpenGL Code aus dem AWT Thread heraus aufgerufen. Das ist so einfach nicht erlaubt. Du darfst OpenGL Befehle ausschließlich aus dem Thread heraus absetzen der auch den OpenGL Kontext erzeugt hat. Das gilt sowohl für jogl als auch für lwjgl.
(Es gibt Ausnahmen, aber die schaffen mehr Probleme als sie lösen).

Ich gehe aber davon aus, dass in Deinem Code oben noch weitere Fehler sein werden. Ein KSKB wäre hilfreich gewesen. Das das Codeäquivalent in lwjgl läuft, heißt leider noch nicht das dieses auch so korrekt ist.

Hier ein Beispiel in jogl2 (auch nur auf die schnelle hingerotzt):

Java:
import java.awt.Frame;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.io.File;
import java.io.IOException;
import java.nio.IntBuffer;

import javax.imageio.ImageIO;
import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.awt.GLCanvas;
import javax.media.opengl.glu.GLU;

import com.jogamp.opengl.util.Animator;
import com.jogamp.opengl.util.GLBuffers;


public class Read implements GLEventListener {

    private IntBuffer     buffer;
    private BufferedImage image;
    private int[]         pixels;

    private boolean       takeScreenshot;

    private GL2           gl;
    private GLU           glu;


    @Override
    public void init(final GLAutoDrawable drawable) {

        gl = drawable.getGL().getGL2();
        glu = new GLU();

        gl.glEnable(GL.GL_DEPTH_TEST);

    }


    @Override
    public void display(final GLAutoDrawable drawable) {

        gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);

        gl.glColor3f(1.0f, 1.0f, 0.0f);

        gl.glBegin(GL.GL_TRIANGLES);
        gl.glVertex3f(-1.0f, -1.0f, -5.0f);
        gl.glVertex3f(+1.0f, -1.0f, -5.0f);
        gl.glVertex3f(+0.0f, +1.0f, -5.0f);
        gl.glEnd();

        if (takeScreenshot)
            takeScreenshot();

    }


    private void takeScreenshot() {

        System.out.println("take screenshot");

        final int width = image.getWidth();
        final int height = image.getHeight();

        gl.glReadPixels(0, 0, width, height, GL2.GL_BGRA, GL2.GL_UNSIGNED_BYTE, buffer);

        for (int y = height - 1; y >= 0; y--)
            buffer.get(pixels, y * width, width);


        try {

            ImageIO.write(image, "PNG", new File("test.png"));

        } catch (final Exception e) {

            e.printStackTrace();

        }

        takeScreenshot = false;
    }


    @Override
    public void reshape(final GLAutoDrawable drawable, final int x, final int y, final int width, int height) {

        if (height <= 0)
            height = 1;

        buffer = (IntBuffer) GLBuffers.newDirectGLBuffer(GL2.GL_INT, width * height);
        image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        pixels = ((DataBufferInt) image.getRaster().getDataBuffer()).getData();

        gl.glMatrixMode(GL2.GL_PROJECTION);
        gl.glLoadIdentity();
        glu.gluPerspective(45.0f, (float) width / (float) height, 1.0, 20.0);
        gl.glMatrixMode(GL2.GL_MODELVIEW);
        gl.glLoadIdentity();

    }


    @Override
    public void dispose(final GLAutoDrawable arg0) {

    }


    public static void main(final String[] args) throws IOException {

        final Read read = new Read();
        final Frame frame = new Frame();
        final GLCanvas canvas = new GLCanvas();
        final Animator animator = new Animator(canvas);

        canvas.addGLEventListener(read);
        frame.add(canvas);
        frame.setSize(800, 600);

        frame.addKeyListener(new KeyAdapter() {

            @Override
            public void keyReleased(final KeyEvent e) {

                if (e.getKeyCode() == KeyEvent.VK_S)
                    read.takeScreenshot = true;

            }

        });

        frame.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(final WindowEvent e) {

                new Thread(new Runnable() {
                    public void run() {

                        animator.stop();
                        System.exit(0);

                    }

                }).start();
            }
        });

        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        animator.start();

    }

}


Gruß,
Fancy
 
Ok, jetzt klappts.

Ich habe einen Mouse- und Key Listener in JOGL eingebaut... jedoch ist das dann ein anderer Thread.
Nun habe ich diese Events wie bei LWJGL in einen Stapel geschoben, der in dem JOGL Display Thread gelesen wird 🙂

Im Prinzip emuliere ich unter JOGL LWJGL 🙂

Andersrum ist bei JOGL die Animation flüssiger, weil dort der Animator die Arbeit macht. Jetzt muss ich zusehen, dass ich das auch so smooth bei LWJGL hinbekomme. Jemand einen Tip?
 

Zurück
Oben