/*****************************************************************************
 *                       Yumetech, Inc Copyright (c) 2006
 *                               Java Source
 *
 * This source is licensed under the BSD-style License
 * Please read http://www.opensource.org/licenses/bsd-license.php for more
 * information or docs/BSD.txt in the downloaded code.
 *
 * This software comes with the standard NO WARRANTY disclaimer for any
 * purpose. Use it at your own risk. If there's a problem you get to fix it.
 *
 ****************************************************************************/

package org.j3d.opengl.swt.internal.ri.osx;

// External imports
import javax.media.opengl.*;
import com.sun.opengl.impl.*;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.LongBuffer;
import java.util.ArrayList;

import com.sun.opengl.impl.macosx.agl.AGL;

// Local imports
// None

public class MacPbufferGLDrawable extends MacGLDrawable
{
    private int initWidth;
    private int initHeight;

    private long pBufferID;

    private int width;
    private int height;

    public MacPbufferGLDrawable(GLCapabilities capabilities,
                                int initialWidth,
                                int initialHeight)
    {
        super(capabilities, null);
        this.initWidth    = initialWidth;
        this.initHeight = initialHeight;

        createPbuffer();
    }

    public GLContext createContext(GLContext shareWith)
    {
        return new MacPbufferGLContext(this, shareWith, pBufferID);
    }

    public void destroy()
    {
        if(pBufferID != 0)
            AGL.aglDestroyPBuffer(pBufferID);

        pBufferID = 0;
    }

    public void setSize(int width, int height)
    {
        // FIXME
        throw new GLException("Not yet implemented");
    }

    public int getWidth()
    {
        return width;
    }

    public int getHeight()
    {
        return height;
    }

    public GLCapabilities getCapabilities()
    {
        return capabilities;
    }

    public long getPbuffer()
    {
        return pBufferID;
    }

    public void swapBuffers() throws GLException
    {
        // FIXME: do we need to do anything if the pbuffer is double-buffered?
    }

    protected void createPbuffer()
    {
        int renderTarget;
        if (capabilities.getPbufferRenderToTextureRectangle())
        {
            width = initWidth;
            height = initHeight;
            renderTarget = GL.GL_TEXTURE_RECTANGLE_EXT;
        }
        else
        {
            width = getNextPowerOf2(initWidth);
            height = getNextPowerOf2(initHeight);
            renderTarget = GL.GL_TEXTURE_2D;
        }

        int internalFormat = GL.GL_RGBA;
        if (capabilities.getPbufferFloatingPointBuffers())
        {
            // FIXME: want to check availability of GL_APPLE_float_pixels
            // extension, but need valid OpenGL context in order to do so --
            // in worst case would need to create dummy window / GLCanvas
            // (undesirable) -- could maybe also do this with pbuffers
            /*
            if (!gl.isExtensionAvailable("GL_APPLE_float_pixels")) {
        throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available");
            }
            */
            switch (capabilities.getRedBits())
            {
                case 16:
                    internalFormat = GL.GL_RGBA_FLOAT16_APPLE;
                    break;

                case 32:
                    internalFormat = GL.GL_RGBA_FLOAT32_APPLE;
                    break;

                default:
                    throw new GLException("Invalid floating-point bit depth (only 16 and 32 supported)");
            }
        }

        // Problem here. We really need that last param to be passing the pbuffer pointer
        // back to the Java code.
        ByteBuffer buf = ByteBuffer.allocateDirect(8);
        buf.order(ByteOrder.nativeOrder());
        LongBuffer id_buf = buf.asLongBuffer();
        
        if(!AGL.aglCreatePBuffer(width,
                                 height,
                                 renderTarget,
                                 internalFormat,
                                 0,
                                 id_buf))
            throw new GLException("pbuffer creation error: AGL.createPBuffer() failed");
        id_buf.rewind();
        pBufferID = id_buf.get();
    }

    private int getNextPowerOf2(int number)
    {
        if(((number-1) & number) == 0) {
            //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0
            return number;
        }

        int power = 0;
        while(number > 0) {
            number = number>>1;
            power++;
        }

        return (1 << power);
    }
}
