package javaforce.gl; /** * GL Offscreen rendering buffer. */ import java.awt.Image; import javaforce.JFImage; import static javaforce.gl.GL.*; public class GLOffscreen { //offscreen data private int os_fb, os_clr_rb, os_depth_rb; private int os_width, os_height; private int os_px[], os_fpx[]; //pixels, flipped pixels private JFImage os_img; //basically a BufferedImage /** Get offscreen buffer in a java.awt.Image */ public Image getOffscreen() { //TODO : the image is trippled here - need to optimize!!! glReadPixels(0, 0, os_width, os_height, GL_BGRA, GL_UNSIGNED_BYTE, os_px); //invert and fix alpha (pixel by pixel - slow - OUCH!) //OpenGL makes black pixels transparent which causes unwanted trailing effects int src = (os_height - 1) * os_width; int dst = 0; for(int y=0;y<os_height;y++) { for(int x=0;x<os_width;x++) { os_fpx[dst++] = os_px[src++] | 0xff000000; } src -= os_width * 2; } os_img.putPixels(os_fpx, 0, 0, os_width, os_height, 0); return os_img.getImage(); } /** Get offscreen buffer pixels (leaving alpha channel as is) * Pixels that are not rendered to are usually transparent. */ public int[] getOffscreenPixels() { glReadPixels(0, 0, os_width, os_height, GL_BGRA, GL_UNSIGNED_BYTE, os_px); //invert and fix alpha (pixel by pixel - slow - OUCH!) //OpenGL makes black pixels transparent which causes unwanted trailing effects int src = (os_height - 1) * os_width; int dst = 0; for(int y=0;y<os_height;y++) { System.arraycopy(os_px, src, os_fpx, dst, os_width); src -= os_width; dst += os_width; } return os_fpx; } /** Resize offscreen buffer dimensions. */ public void resizeOffscreen(int width, int height) { os_width = width; os_height = height; os_px = new int[os_width * os_height]; os_fpx = new int[os_width * os_height]; os_img = new JFImage(os_width, os_height); glBindFramebuffer(GL_FRAMEBUFFER, os_fb); int ids[] = {os_clr_rb, os_depth_rb}; glDeleteRenderbuffers(2, ids); glGenRenderbuffers(1, ids); os_clr_rb = ids[0]; glBindRenderbuffer(GL_RENDERBUFFER, os_clr_rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, os_clr_rb); glGenRenderbuffers(1, ids); os_depth_rb = ids[0]; glBindRenderbuffer(GL_RENDERBUFFER, os_depth_rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, os_depth_rb); } /** Creates an offscreen buffer to where rendering is directly to. */ public void createOffscreen(int width, int height) { if (os_fb != 0) return; //already done int ids[] = new int[1]; glGenFramebuffers(1, ids); os_fb = ids[0]; glBindFramebuffer(GL_FRAMEBUFFER, os_fb); glGenRenderbuffers(1, ids); os_clr_rb = ids[0]; glBindRenderbuffer(GL_RENDERBUFFER, os_clr_rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, os_clr_rb); glGenRenderbuffers(1, ids); os_depth_rb = ids[0]; glBindRenderbuffer(GL_RENDERBUFFER, os_depth_rb); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, os_depth_rb); glBindFramebuffer(GL_FRAMEBUFFER, os_fb); os_width = width; os_height = height; os_px = new int[os_width * os_height]; os_fpx = new int[os_width * os_height]; os_img = new JFImage(os_width, os_height); } public void setRenderToOffscreen(boolean state) { glBindFramebuffer(GL_FRAMEBUFFER, state ? os_fb : 0); } }