Package com.ardor3d.renderer.jogl

Source Code of com.ardor3d.renderer.jogl.JoglPbufferTextureRenderer

/**
* Copyright (c) 2008-2010 Ardor Labs, Inc.
*
* This file is part of Ardor3D.
*
* Ardor3D is free software: you can redistribute it and/or modify it
* under the terms of its license which may be found in the accompanying
* LICENSE file or at <http://www.ardor3d.com/LICENSE>.
*/

package com.ardor3d.renderer.jogl;

import java.nio.IntBuffer;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.media.opengl.GL;
import javax.media.opengl.GLCapabilities;
import javax.media.opengl.GLContext;
import javax.media.opengl.GLDrawableFactory;
import javax.media.opengl.GLOffscreenAutoDrawable;
import javax.media.opengl.GLProfile;

import com.ardor3d.framework.DisplaySettings;
import com.ardor3d.framework.Scene;
import com.ardor3d.framework.jogl.CapsUtil;
import com.ardor3d.image.Texture;
import com.ardor3d.image.Texture.Type;
import com.ardor3d.renderer.AbstractPbufferTextureRenderer;
import com.ardor3d.renderer.ContextCapabilities;
import com.ardor3d.renderer.ContextManager;
import com.ardor3d.renderer.RenderContext;
import com.ardor3d.renderer.Renderer;
import com.ardor3d.renderer.TextureRendererFactory;
import com.ardor3d.renderer.state.RenderState;
import com.ardor3d.renderer.state.record.TextureRecord;
import com.ardor3d.renderer.state.record.TextureStateRecord;
import com.ardor3d.scene.state.jogl.JoglTextureStateUtil;
import com.ardor3d.scene.state.jogl.util.JoglTextureUtil;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.util.Ardor3dException;
import com.ardor3d.util.TextureKey;
import com.ardor3d.util.geom.BufferUtils;

/**
* <p>
* This class is used by Ardor3D's JOGL implementation to render textures. Users should <b>not </b> create this class
* directly.
* </p>
* N.B: This class can't work without a complete implementation of GLOffscreenAutoDrawable.PBuffer, which is currently
* missing from JOGL
*
* @see TextureRendererFactory
*/
public class JoglPbufferTextureRenderer extends AbstractPbufferTextureRenderer {
    private static final Logger logger = Logger.getLogger(JoglPbufferTextureRenderer.class.getName());

    private GLOffscreenAutoDrawable _offscreenDrawable;

    private GLContext _context;

    protected CapsUtil _capsUtil;

    // HACK: needed to get the parent context in here somehow...
    public static GLContext _parentContext;

    public JoglPbufferTextureRenderer(final DisplaySettings settings, final Renderer parentRenderer,
            final ContextCapabilities caps) {
        super(settings, parentRenderer, caps);
        _capsUtil = new CapsUtil();
        setMultipleTargets(false);
    }

    /**
     * <code>setupTexture</code> initializes a new Texture object for use with TextureRenderer. Generates a valid gl
     * texture id for this texture and inits the data type for the texture.
     */
    public void setupTexture(final Texture tex) {
        if (tex.getType() != Type.TwoDimensional) {
            throw new IllegalArgumentException("Unsupported type: " + tex.getType());
        }
        final GL gl = GLContext.getCurrentGL();

        final RenderContext context = ContextManager.getCurrentContext();
        final TextureStateRecord record = (TextureStateRecord) context.getStateRecord(RenderState.StateType.Texture);

        // check if we are already setup... if so, throw error.
        if (tex.getTextureKey() == null) {
            tex.setTextureKey(TextureKey.getRTTKey(tex.getMinificationFilter()));
        } else if (tex.getTextureIdForContext(context.getGlContextRep()) != 0) {
            throw new Ardor3dException("Texture is already setup and has id.");
        }

        // Create the texture
        final IntBuffer ibuf = BufferUtils.createIntBuffer(1);
        gl.glGenTextures(1, ibuf);
        final int textureId = ibuf.get(0);
        tex.setTextureIdForContext(context.getGlContextRep(), textureId);

        JoglTextureStateUtil.doTextureBind(tex, 0, true);

        // Initialize our texture with some default data.
        final int internalFormat = JoglTextureUtil.getGLInternalFormat(tex.getTextureStoreFormat());
        final int dataFormat = JoglTextureUtil.getGLPixelFormatFromStoreFormat(tex.getTextureStoreFormat());
        final int pixelDataType = JoglTextureUtil.getGLPixelDataType(tex.getRenderedTexturePixelDataType());

        gl.glTexImage2D(GL.GL_TEXTURE_2D, 0, internalFormat, _width, _height, 0, dataFormat, pixelDataType, null);

        // Setup filtering and wrap
        final TextureRecord texRecord = record.getTextureRecord(textureId, tex.getType());
        JoglTextureStateUtil.applyFilter(tex, texRecord, 0, record, context.getCapabilities());
        JoglTextureStateUtil.applyWrap(tex, texRecord, 0, record, context.getCapabilities());

        logger.fine("setup pbuffer tex" + textureId + ": " + _width + "," + _height);
    }

    public void render(final Spatial spat, final Texture tex, final int clear) {
        render(null, spat, null, tex, clear);
    }

    public void render(final List<? extends Spatial> spat, final Texture tex, final int clear) {
        render(spat, null, null, tex, clear);
    }

    public void render(final Scene scene, final Texture tex, final int clear) {
        render(null, null, scene, tex, clear);
    }

    private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
            final Texture tex, final int clear) {
        try {
            if (_offscreenDrawable == null) {
                initPbuffer();
            }

            if (_useDirectRender && !tex.getTextureStoreFormat().isDepthFormat()) {
                // setup and render directly to a 2d texture.
                releaseTexture();
                activate();
                switchCameraIn(clear);

                if (toDrawA != null) {
                    doDraw(toDrawA);
                } else {
                    doDraw(toDrawB);
                }

                deactivate();
                switchCameraOut();
                JoglTextureStateUtil.doTextureBind(tex, 0, true);
                bindTexture();
            } else {
                // render and copy to a texture
                activate();
                switchCameraIn(clear);

                if (toDrawA != null) {
                    doDraw(toDrawA);
                } else if (toDrawB != null) {
                    doDraw(toDrawB);
                } else {
                    doDraw(toDrawC);
                }

                switchCameraOut();

                copyToTexture(tex, 0, 0, _width, _height, 0, 0);

                deactivate();
            }

        } catch (final Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e);
        }
    }

    private void bindTexture() {
        // FIXME The class PBuffer is going to be removed from JOGL very soon and GLOffscreenAutoDrawable.PBuffer is not
        // yet ready
    }

    private void releaseTexture() {
        // FIXME
    }

    public void render(final Spatial spat, final List<Texture> texs, final int clear) {
        render(null, spat, null, texs, clear);
    }

    public void render(final List<? extends Spatial> spat, final List<Texture> texs, final int clear) {
        render(spat, null, null, texs, clear);
    }

    public void render(final Scene scene, final List<Texture> texs, final int clear) {
        render(null, null, scene, texs, clear);
    }

    private void render(final List<? extends Spatial> toDrawA, final Spatial toDrawB, final Scene toDrawC,
            final List<Texture> texs, final int clear) {
        try {
            if (_offscreenDrawable == null) {
                initPbuffer();
            }

            if (texs.size() == 1 && _useDirectRender && !texs.get(0).getTextureStoreFormat().isDepthFormat()) {
                // setup and render directly to a 2d texture.
                JoglTextureStateUtil.doTextureBind(texs.get(0), 0, true);
                activate();
                switchCameraIn(clear);
                releaseTexture();

                if (toDrawA != null) {
                    doDraw(toDrawA);
                } else if (toDrawB != null) {
                    doDraw(toDrawB);
                } else {
                    doDraw(toDrawC);
                }

                switchCameraOut();

                deactivate();
                bindTexture();
            } else {
                // render and copy to a texture
                activate();
                switchCameraIn(clear);

                if (toDrawA != null) {
                    doDraw(toDrawA);
                } else {
                    doDraw(toDrawB);
                }

                switchCameraOut();

                for (int i = 0; i < texs.size(); i++) {
                    copyToTexture(texs.get(i), 0, 0, _width, _height, 0, 0);
                }

                deactivate();
            }

        } catch (final Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e);
        }
    }

    public void copyToTexture(final Texture tex, final int x, final int y, final int width, final int height,
            final int xoffset, final int yoffset) {
        final GL gl = GLContext.getCurrentGL();

        JoglTextureStateUtil.doTextureBind(tex, 0, true);

        gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, xoffset, yoffset, x, y, width, height);
    }

    @Override
    protected void clearBuffers(final int clear) {
        final GL gl = GLContext.getCurrentGL();

        gl.glDisable(GL.GL_SCISSOR_TEST);
        _parentRenderer.clearBuffers(clear);
    }

    private void initPbuffer() {

        try {
            if (_offscreenDrawable != null) {
                _context.destroy();
                _offscreenDrawable.destroy();
                giveBackContext();
                ContextManager.removeContext(_offscreenDrawable.getContext());
            }

            // Make our GLPbuffer...
            final GLProfile profile = _capsUtil.getProfile();
            final GLDrawableFactory fac = GLDrawableFactory.getFactory(profile);
            final GLCapabilities caps = new GLCapabilities(profile);
            caps.setHardwareAccelerated(true);
            caps.setDoubleBuffered(true);
            caps.setAlphaBits(_settings.getAlphaBits());
            caps.setDepthBits(_settings.getDepthBits());
            caps.setNumSamples(_settings.getSamples());
            caps.setSampleBuffers(_settings.getSamples() != 0);
            caps.setStencilBits(_settings.getStencilBits());
            caps.setDoubleBuffered(false);
            caps.setOnscreen(false);
            caps.setPBuffer(true);
            _offscreenDrawable = fac.createOffscreenAutoDrawable(null, caps, null, _width, _height, _parentContext);
            _context = _offscreenDrawable.getContext();

            _context.makeCurrent();

            final JoglContextCapabilities contextCaps = new JoglContextCapabilities(_offscreenDrawable.getGL());
            ContextManager.addContext(_context,
                    new JoglRenderContext(_context, contextCaps, ContextManager.getCurrentContext()));

        } catch (final Exception e) {
            logger.logp(Level.SEVERE, this.getClass().toString(), "initPbuffer()", "Exception", e);

            if (_useDirectRender) {
                logger.warning("Your card claims to support Render to Texture but fails to enact it.  Updating your driver might solve this problem.");
                logger.warning("Attempting to fall back to Copy Texture.");
                _useDirectRender = false;
                initPbuffer();
                return;
            }

            logger.log(Level.WARNING, "Failed to create Pbuffer.", e);
            return;
        }

        try {
            activate();

            _width = _offscreenDrawable.getWidth();
            _height = _offscreenDrawable.getHeight();

            deactivate();
        } catch (final Exception e) {
            logger.log(Level.WARNING, "Failed to initialize created Pbuffer.", e);
            return;
        }
    }

    private void activate() {
        if (_active == 0) {
            _oldContext = ContextManager.getCurrentContext();
            _context.makeCurrent();

            ContextManager.switchContext(_context);

            ContextManager.getCurrentContext().clearEnforcedStates();
            ContextManager.getCurrentContext().enforceStates(_enforcedStates);

            if (_bgColorDirty) {
                final GL gl = GLContext.getCurrentGL();

                gl.glClearColor(_backgroundColor.getRed(), _backgroundColor.getGreen(), _backgroundColor.getBlue(),
                        _backgroundColor.getAlpha());
                _bgColorDirty = false;
            }
        }
        _active++;
    }

    private void deactivate() {
        if (_active == 1) {
            giveBackContext();
        }
        _active--;
    }

    private void giveBackContext() {
        _parentContext.makeCurrent();
        ContextManager.switchContext(_oldContext.getContextKey());
    }

    public void cleanup() {
        ContextManager.removeContext(_offscreenDrawable.getContext());
        _offscreenDrawable.destroy();
    }

    public void setMultipleTargets(final boolean force) {
        if (force) {
            logger.fine("Copy Texture Pbuffer used!");
            _useDirectRender = false;
            if (_offscreenDrawable != null) {
                giveBackContext();
                ContextManager.removeContext(_offscreenDrawable.getContext());
            }
        } else {
            // XXX: Is this WGL specific query right?
            if (GLContext.getCurrentGL().isExtensionAvailable("WGL_ARB_render_texture")) {
                logger.fine("Render to Texture Pbuffer supported!");
                _useDirectRender = true;
            } else {
                logger.fine("Copy Texture Pbuffer supported!");
            }
        }
    }
}
TOP

Related Classes of com.ardor3d.renderer.jogl.JoglPbufferTextureRenderer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.