org.spout.engine.filesystem.resource.ClientRenderTexture.java Source code

Java tutorial

Introduction

Here is the source code for org.spout.engine.filesystem.resource.ClientRenderTexture.java

Source

/*
 * This file is part of Spout.
 *
 * Copyright (c) 2011 Spout LLC <http://www.spout.org/>
 * Spout is licensed under the Spout License Version 1.
 *
 * Spout is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option)
 * any later version.
 *
 * In addition, 180 days after any changes are published, you can use the
 * software, incorporating those changes, under the terms of the MIT license,
 * as described in the Spout License Version 1.
 *
 * Spout is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
 * more details.
 *
 * You should have received a copy of the GNU Lesser General Public License,
 * the MIT license and the Spout License Version 1 along with this program.
 * If not, see <http://www.gnu.org/licenses/> for the GNU Lesser General Public
 * License and see <http://spout.in/licensev1> for the full license, including
 * the MIT license.
 */
package org.spout.engine.filesystem.resource;

import java.nio.ByteBuffer;
import java.nio.IntBuffer;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.EXTFramebufferObject;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL20;
import org.lwjgl.opengl.GL30;
import org.lwjgl.opengl.GLContext;

import org.spout.api.Spout;
import org.spout.api.exception.ComputerIsPotatoException;
import org.spout.api.render.RenderMode;
import org.spout.api.render.Texture;
import org.spout.engine.SpoutClient;
import org.spout.engine.SpoutRenderer;

public class ClientRenderTexture extends ClientTexture {
    public static final int INVALID_BUFFER = -1;
    public static final int SCREEN_BUFFER = 0;
    public static ByteBuffer EMPTY_BUFFER = BufferUtils.createByteBuffer(0);
    private int framebuffer = INVALID_BUFFER;
    private boolean useDepthBuffer = false;
    private boolean useStencilBuffer = false;
    private boolean useNormalBuffer = false;
    int depthTarget = INVALID_BUFFER;
    int stencilTarget = INVALID_BUFFER; //TODO: Implement stencil component
    int normalTarget = INVALID_BUFFER;
    ClientTextureHandle depthTexture = null;
    ClientTextureHandle stencilTexture = null;
    ClientTextureHandle normalTexture = null;
    boolean useEXT = false;

    public ClientRenderTexture() {
        super(null, (int) ((SpoutClient) Spout.getEngine()).getResolution().getX(),
                (int) ((SpoutClient) Spout.getEngine()).getResolution().getY());

        //Detect which path we should use to create framebuffers.
        //if all 3 are false, we cannot use framebuffers so throw an exception
        boolean gl30 = GLContext.getCapabilities().OpenGL30;
        boolean arb = GLContext.getCapabilities().GL_ARB_framebuffer_object;
        boolean ext = GLContext.getCapabilities().GL_EXT_framebuffer_object;

        if (gl30) {
            useEXT = false;
        } else if (arb) {
            useEXT = false;
        } else if (ext) {
            useEXT = true;
        } else {
            throw new ComputerIsPotatoException("Does not support Framebuffers");
        }

        Spout.log("Using EXT: " + useEXT);
    }

    public ClientRenderTexture(boolean depth) {
        this(true, false, false);
    }

    public ClientRenderTexture(boolean depth, boolean stencil, boolean normals) {
        this();
        useDepthBuffer = depth;
        useStencilBuffer = stencil;
        useNormalBuffer = normals;
    }

    @Override
    public Texture subTexture(int x, int y, int w, int h) {
        // TODO Auto-generated method stub
        return null;
    }

    public void activate() {

        if (framebuffer == INVALID_BUFFER) {
            return; //Can't set this to active if it's not created yet
        }

        if (useEXT) {
            EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, framebuffer);
        } else {
            GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, framebuffer);
        }
        SpoutRenderer.checkGLError();

        GL11.glViewport(0, 0, width, height);
        SpoutRenderer.checkGLError();
    }

    public void release() {

        if (framebuffer != INVALID_BUFFER) {
            if (useEXT) {
                EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, SCREEN_BUFFER);
            } else {
                GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, SCREEN_BUFFER);
            }
            SpoutRenderer.checkGLError();

            GL11.glViewport(0, 0, width, height);
            SpoutRenderer.checkGLError();

            GL11.glDrawBuffer(GL11.GL_BACK);
        }
    }

    @Override
    public void writeGPU() {
        if (framebuffer != INVALID_BUFFER) {
            throw new IllegalStateException("Framebuffer already created!");
        }

        int buffers = 1;

        //Create the color buffer for this renderTexture
        textureID = GL11.glGenTextures();
        SpoutRenderer.checkGLError();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
        SpoutRenderer.checkGLError();

        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
        SpoutRenderer.checkGLError();
        GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
        SpoutRenderer.checkGLError();
        GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA, GL11.GL_INT,
                (ByteBuffer) null); // Create the texture data
        SpoutRenderer.checkGLError();

        if (useNormalBuffer) {
            //Create the color buffer for this renderTexture
            normalTarget = GL11.glGenTextures();
            SpoutRenderer.checkGLError();
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, normalTarget);
            SpoutRenderer.checkGLError();

            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
            SpoutRenderer.checkGLError();
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
            SpoutRenderer.checkGLError();
            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_RGBA8, width, height, 0, GL11.GL_RGBA,
                    GL11.GL_UNSIGNED_BYTE, (ByteBuffer) null); // Create the texture data
            SpoutRenderer.checkGLError();
            buffers++;
        }

        if (useDepthBuffer) {
            //Create the color buffer for this renderTexture
            depthTarget = GL11.glGenTextures();
            SpoutRenderer.checkGLError();
            GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTarget);
            SpoutRenderer.checkGLError();

            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST);
            SpoutRenderer.checkGLError();
            GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST);
            SpoutRenderer.checkGLError();
            GL11.glTexImage2D(GL11.GL_TEXTURE_2D, 0, GL11.GL_DEPTH_COMPONENT, width, height, 0,
                    GL11.GL_DEPTH_COMPONENT, GL11.GL_FLOAT, (ByteBuffer) null); // Create the texture data
            SpoutRenderer.checkGLError();
            buffers++;
        }

        if (useEXT) {
            framebuffer = EXTFramebufferObject.glGenFramebuffersEXT();
            SpoutRenderer.checkGLError();

            EXTFramebufferObject.glBindFramebufferEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT, framebuffer);
            SpoutRenderer.checkGLError();

            GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
            SpoutRenderer.checkGLError();

            EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                    EXTFramebufferObject.GL_COLOR_ATTACHMENT0_EXT, GL11.GL_TEXTURE_2D, textureID, 0);
            SpoutRenderer.checkGLError();

            if (useDepthBuffer) {
                GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTarget);
                SpoutRenderer.checkGLError();

                EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                        EXTFramebufferObject.GL_DEPTH_ATTACHMENT_EXT, GL11.GL_TEXTURE_2D, depthTarget, 0);
                SpoutRenderer.checkGLError();
            }

            if (useNormalBuffer) {

                GL11.glBindTexture(GL11.GL_TEXTURE_2D, normalTarget);
                SpoutRenderer.checkGLError();

                EXTFramebufferObject.glFramebufferTexture2DEXT(EXTFramebufferObject.GL_FRAMEBUFFER_EXT,
                        EXTFramebufferObject.GL_COLOR_ATTACHMENT1_EXT, GL11.GL_TEXTURE_2D, normalTarget, 0);
                SpoutRenderer.checkGLError();
            }

            if (EXTFramebufferObject.glCheckFramebufferStatusEXT(
                    EXTFramebufferObject.GL_FRAMEBUFFER_EXT) != EXTFramebufferObject.GL_FRAMEBUFFER_COMPLETE_EXT) {
                System.out.println("ERROR: Framebuffer not complete");
                throw new ComputerIsPotatoException("Framebuffer not complete");
            }
            SpoutRenderer.checkGLError();
        } else {
            framebuffer = GL30.glGenFramebuffers();
            SpoutRenderer.checkGLError();

            GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, framebuffer);
            SpoutRenderer.checkGLError();

            IntBuffer drawBuffers = BufferUtils.createIntBuffer(buffers);
            drawBuffers.put(GL30.GL_COLOR_ATTACHMENT0);
            if (useNormalBuffer) {
                drawBuffers.put(GL30.GL_COLOR_ATTACHMENT1);
            }
            drawBuffers.flip();
            GL20.glDrawBuffers(drawBuffers);
            SpoutRenderer.checkGLError();

            GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureID);
            SpoutRenderer.checkGLError();

            GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT0, GL11.GL_TEXTURE_2D,
                    textureID, 0);
            SpoutRenderer.checkGLError();

            if (useDepthBuffer) {
                GL11.glBindTexture(GL11.GL_TEXTURE_2D, depthTarget);
                SpoutRenderer.checkGLError();

                GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_DEPTH_ATTACHMENT, GL11.GL_TEXTURE_2D,
                        depthTarget, 0);
                SpoutRenderer.checkGLError();
            }
            if (useNormalBuffer) {
                GL11.glBindTexture(GL11.GL_TEXTURE_2D, normalTarget);
                SpoutRenderer.checkGLError();

                GL30.glFramebufferTexture2D(GL30.GL_FRAMEBUFFER, GL30.GL_COLOR_ATTACHMENT1, GL11.GL_TEXTURE_2D,
                        normalTarget, 0);
                SpoutRenderer.checkGLError();
            }

            int status = GL30.glCheckFramebufferStatus(GL30.GL_FRAMEBUFFER);
            if (status != GL30.GL_FRAMEBUFFER_COMPLETE) {
                System.out.println("ERROR: Framebuffer not complete.  Status: " + status);
                throw new ComputerIsPotatoException("Framebuffer not complete");
            }
            SpoutRenderer.checkGLError();

            GL30.glBindFramebuffer(GL30.GL_FRAMEBUFFER, SCREEN_BUFFER);
            SpoutRenderer.checkGLError();
        }
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, 0);
        SpoutRenderer.checkGLError();
    }

    public Texture getDepthTexture() {
        if (depthTexture == null) {
            depthTexture = new ClientTextureHandle(depthTarget, width, height);
        }
        return depthTexture;
    }

    public Texture getStencilTexture() {
        if (stencilTexture == null) {
            stencilTexture = new ClientTextureHandle(stencilTarget, width, height);
        }
        return stencilTexture;
    }

    public Texture getNormalTexture() {
        if (normalTexture == null) {
            normalTexture = new ClientTextureHandle(normalTarget, width, height);
        }
        return normalTexture;
    }

    protected boolean isGL30() {
        return ((SpoutClient) Spout.getEngine()).getRenderMode() == RenderMode.GL30
                || ((SpoutClient) Spout.getEngine()).getRenderMode() == RenderMode.GL40;
    }

    @Override
    public boolean isLoaded() {
        return framebuffer != INVALID_BUFFER;
    }
}