Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.graphics.model;

import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.utils.BufferUtils;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.GraphicsObject;

/** Vertex Stream that supports individual or interleaved vertex attributes. */
public class VertexStream extends GraphicsObject
{
        /** Type of stream - single attribute or multi-attribute interleaved. */
        public enum StreamType
        {
                INDIVIDUAL,
                INTERLEAVED
        };
       
        private static List<VertexStream> mManagedStreams = new ArrayList<VertexStream>();
       
        private StreamType mStreamType;
        private String mName;
        private FloatBuffer mData = null;
        private ByteBuffer mByteBuffer = null;
       
        private boolean mIsDynamic = false;
       
        private int mVertexCount = 0;
        private int mCoordsPerElement = 0;
        private int mBytesPerElement = 0;
       
        private int mBufferID = 0;
        //private static int[] BUFFERID = new int[1];
        private static final IntBuffer BUFFERID = BufferUtils.newIntBuffer(1);
       
        private VertexAttribute[] mAttribs;
       
        /** Constructor. */
        public VertexStream(Graphics graphics, StreamType streamType, String name, VertexAttribute[] attribs, boolean isDynamic)
        {
                super(graphics);
                mStreamType = streamType;
                mName = name;
                mAttribs = attribs;
                mIsDynamic = isDynamic;
               
                mManagedStreams.add(this);
        }
       
        /** Destroy all internal data. */
        public void dispose()
        {
                mManagedStreams.remove(this);
               
                unload();
                mAttribs = null;
                mVertexCount = 0;
                mCoordsPerElement = 0;
                mBytesPerElement = 0;
               
                if (mByteBuffer != null)
                {
                        BufferUtils.disposeUnsafeByteBuffer(mByteBuffer);
                        mByteBuffer = null;
                }
                mData = null;
        }
       
        /** Reload all managed vertex streams. */
        public static void reloadManagedStreams()
        {
                for (int i = 0; i < mManagedStreams.size(); i++)
                {
                        VertexStream stream = mManagedStreams.get(i);
                        stream.upload();
                        Gdx.app.log(Consts.LOG_TAG, "VertexStream '" + stream.getName() + "' reloaded!");
                }
        }      

        /** Set the buffer data. */
        public void setData(byte[] data, int coordsPerElement, int bytesPerElement)
        {
                if (data == null)
                {
                        dispose();
                        return;
                }
               
                int newVertexCount = data.length / bytesPerElement;
                if ((mVertexCount != newVertexCount) || (mByteBuffer == null))
                {
                        // reallocate
                        allocateBuffer(data.length);
                }              
               
                mVertexCount = newVertexCount;
                mCoordsPerElement = coordsPerElement;
                mBytesPerElement = bytesPerElement;
               
                /*ByteBuffer byteBuffer = ByteBuffer.allocateDirect(data.length);
                byteBuffer.order(ByteOrder.nativeOrder());
                byteBuffer.put(data);
                byteBuffer.position(0);
                mData = byteBuffer.asFloatBuffer();*/

               
                BufferUtils.copy(data, 0, mData, data.length);
                mData.position(0);
                mData.limit(data.length);
        }
       
        /** Set the buffer data. */
        public void setData(float[] data, int coordsPerElement, int bytesPerElement)
        {
                if (data == null)
                {
                        dispose();
                        return;
                }
               
                int newVertexCount = data.length / coordsPerElement;
                if ((mVertexCount != newVertexCount) || (mByteBuffer == null))
                {
                        // reallocate
                        allocateBuffer(data.length * Consts.SIZEOF_FLOAT);
                }              
               
                mVertexCount = data.length / coordsPerElement;
                mCoordsPerElement = coordsPerElement;
                mBytesPerElement = bytesPerElement;
               
                BufferUtils.copy(data, mByteBuffer, data.length, 0);
                mData.position(0);
                mData.limit(data.length);
        }
       
       
        public void allocateBuffer(int newSize)
        {
                if (mByteBuffer != null)
                        BufferUtils.disposeUnsafeByteBuffer(mByteBuffer);
               
                mByteBuffer = BufferUtils.newUnsafeByteBuffer(newSize);
                mData = mByteBuffer.asFloatBuffer();
                mData.flip();
                mByteBuffer.flip();
        }
       
        /** Create GL handle and upload vertex data to hardware. */
        public final void upload()
        {
                if (mData == null)
                        return;
               
                Gdx.gl20.glGenBuffers(1, BUFFERID);
                mBufferID = BUFFERID.get(0);
               
                Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, mBufferID);
               
                int usage = GL20.GL_STATIC_DRAW;
                if (isDynamic())
                        usage = GL20.GL_DYNAMIC_DRAW;
               
                //Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, mData.capacity() * Consts.SIZEOF_FLOAT, mData, usage);
                Gdx.gl20.glBufferData(GL20.GL_ARRAY_BUFFER, mByteBuffer.limit(), mByteBuffer, usage);
                Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
        }
       
        /** Reupload data to hardware. */
        public final void reupload()
        {
                if (mBufferID == 0)
                {
                        // perform initial upload
                        upload();
                        return;
                }
               
                if (mData == null)
                        return;
               
                Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, mBufferID);
                Gdx.gl20.glBufferSubData(GL20.GL_ARRAY_BUFFER, 0, mData.capacity() * Consts.SIZEOF_FLOAT, mData);
                Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
        }
       
        /** Unload vertex data from hardware. */
        public final void unload()
        {
                deactivate();
                BUFFERID.put(0, mBufferID);
                Gdx.gl20.glDeleteBuffers(1, BUFFERID);
                mBufferID = 0;
        }
       
        //static int mCurrentBufferId = 0;
       
        /** Activate stream for rendering. */
        public final void activate()
        {
                // TODO: buffer state tracking
                //if (mCurrentBufferId != mBufferID)
                {
                        Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, mBufferID);
                        //mCurrentBufferId = mBufferID;
                }

                for (int i = 0; i < mAttribs.length; i++)
                {
                        VertexAttribute attrib = mAttribs[i];

                        // TODO: attrib to handle adapter
                        Gdx.gl20.glVertexAttribPointer(attrib.getAttribType(), attrib.getCoordsPerElement(), GL20.GL_FLOAT, false, getBytesPerElement(), attrib.getByteOffset());
                        Gdx.gl20.glEnableVertexAttribArray(attrib.getAttribType());
                }              

        }
       
        public final void deactivate()
        {
                for (int i = 0; i < mAttribs.length; i++)
                {
                        VertexAttribute attrib = mAttribs[i];
                       
                        // TODO: attrib to handle adapter
                        Gdx.gl20.glDisableVertexAttribArray(attrib.getAttribType());
                }              
               
                // TODO: buffer state tracking
                //Gdx.gl20.glBindBuffer(GL20.GL_ARRAY_BUFFER, 0);
        }
       
        /** Get Coords per element. */
        public final int getCoordsPerElement()
        {
                return mCoordsPerElement;
        }
       
        /** Get number of bytes per complete element (equals vertex stride). */
        public final int getBytesPerElement()
        {
                return mBytesPerElement;
        }
       
        /** Get number of elements. */
        public final int getVertexCount()
        {
                return mVertexCount;
        }
       
        /** Get name of vertex stream. */
        public final String getName()
        {
                return mName;
        }
       
        /** Get stream type. */
        public final StreamType getStreamType()
        {
                return mStreamType;
        }

        /** Check if the stream is dynamic or static. */
        public final boolean isDynamic()
        {
                return mIsDynamic;
        }
}