This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Vertex Buffer Interface Submitted by

Not to take the spotlight from Warren Marshall (and Kenneth Hurley), but I felt it may be interesting to provide another Vertex Buffer implementation for discussion. I use the following implementation as a simple interface for accessing vertex buffers. The objective was to create an easy to use interface that I could code against regardless if I use OpenGL or DirectX. Although I only provide the Direct X implementation, the OpenGL uses vertex arrays... I opted not to provide the OpenGL implementation due to the previous COTD regarding Direct X. The code submitted is free to use as you please. However I request that you check the D3D implementation and modify it as needed. It is basic and does the job for my needs. I do not claim that this is the most efficient code or most elegant way to solve the problem. I'd quickly like to thank ALL of the people who have submitted COTD entries. A lot of them have proven to be useful, regardless if they had been flawed or not. There are many times someone maybe be able to find a diamond in the rough in terms of code. Somewhere, hidden deep in obscure code, there are snippets of an idea that can be extracted out and used as inspiration for other ideas. To me, it is not about showcasing the best of the best or the worst of the worst. It's about sharing and learning among our peers and advancing technology together. 'Without my peoples, I've got nothing to gain. Worst comes to worst my peoples come first.' - Dilated Peoples Enjoy. t. Editor's Note: Only the interface (vertexbuffer.h) is shown on this page. Download the zip file for the full implementation.

Currently browsing [d3dvertexbuffer.zip] (5,129 bytes) - [vertexbuffer.h] - (7,450 bytes)

    /* ************************************************************************** */
    // File       : vertexbuffer.h
    // Programmer : Tobin Schwaiger-Hastanan
    // Copyright (c) 1997-2002 Tobin Schwaiger-Hastanan
    // Notes      : for flipcode.com's COTD.
    /* ************************************************************************** */
    #ifndef _VERTEXBUFFER_DAWT_H_INCLUDED_
    #define _VERTEXBUFFER_DAWT_H_INCLUDED_

    /**
     * This is an abstract class that provides an interface on top of various
     * implementations of vertex buffers or similar structures.  I currently
     * use this class for interfacing with D3D Vertex Buffers and OpenGL
     * vertex arrays.
     *
     * @author Tobin Schwaiger-Hastanan
     */
    class CVertexBuffer
    {
    public:
        enum
        {
            FORMAT_XYZ           = 0x0001, /** Untransformed XYZ value set. */
            FORMAT_NORMAL        = 0x0002, /** XYZ normal value set */
            FORMAT_DIFFUSE       = 0x0004, /** RGBA diffuse color value set */
            FORMAT_SPECULAR      = 0x0008, /** RGBA specular color value set */
            FORMAT_XYZRHW        = 0x0010, /** transformed XYZRHW value set. */
            FORMAT_TEXVERTEXFLAG = 0x8000, /** Texture vertex flag. */
        };

        /**
          * This method should be provided with the vertex format when creating the
          * vertex buffer.  This will include FORMAT_TEXVERTEXFORMAT and encode
          * the number of texture vertex needed by the developer.
          * example: FORMAT_XYZ | FORMAT_NORMAL | FORMAT_DIFFUSE | FORMAT_TEXVERTEX( 1 )
          */
        int FORMAT_TEXVERTEX( int nTexVertex )
        {
            return FORMAT_TEXVERTEXFLAG | (nTexVertex << 8 );
        }

        /**
          * supported primitives
          */
        enum PRIMITIVE
        {
            PRIMITIVE_POINTLIST,     /** Specifies a point list  */
            PRIMITIVE_LINELIST,      /** Specifies a line list   */
            PRIMITIVE_LINESTRIP,     /** Specifies a line strip  */
            PRIMITIVE_TRIANGLELIST,  /** Specifies a triangle list  */
            PRIMITIVE_TRIANGLESTRIP, /** Specifies a triangle strip */
            PRIMITIVE_TRIANGLEFAN,   /** Specifies a triangle fan   */
        };

    public:
        virtual ~CVertexBuffer() { } // I'm sure I will get some flak for this.

        /**
          * Allows the developer to specify the primitive type for rendering.
          * @param primitive Primitive type assigned to vertex buffer.
          */
        virtual void setPrimitive( PRIMITIVE& primitive ) = 0;

        /**
          * Returns the primitive type associated to the vertex buffer.
          * @return Primitive type associated to the vertex buffer.
          */
        virtual PRIMITIVE getPrimitive() = 0;

        /**
          * Locks the vertex buffer (usually for writing)...
          * @return reference to current vertex buffer object.
          */
        virtual CVertexBuffer& lock()   = 0;

        /**
          * Unlocks the vertex buffer.
          * @return reference to current vertex buffer object.
          */
        virtual CVertexBuffer& unlock() = 0;

        /**
          * Determines if the vertex buffer is locked or not.
          * @return boolean value specifying if vertex buffer is locked or not.
          */
        virtual bool isLocked() = 0;

        /**
          * Tells the vertex buffer it will be sent vertex data. (ala OpenGL)
          *
          * @param primitive primitive that describes incoming data.
          *                  [Default: PRIMITIVE_PPINTLIST]
          * @return boolean value specifying if vertex buffer is locked or not.
          */
        virtual CVertexBuffer& begin( PRIMITIVE primitive = PRIMITIVE_POINTLIST ) = 0;

        /**
          * Tells the vertex buffer no more vertex data will be sent. (ala OpenGL)
          *
          * @param primitive primitive that describes incoming data.
          *                  [Default: PRIMITIVE_PPINTLIST]
          * @return boolean value specifying if vertex buffer is locked or not.
          */
        virtual CVertexBuffer& end()   = 0;

        /**
          * Returns a pointer to the raw vertex data.
          * This should only be called when vertex buffer is locked.
          * @return pointer to raw vertex data.
          */
        virtual void* getVertexData() = 0;

        /**
          * returns the number of vertex currently in the vertex buffer
          * @return number of vertex in vertex buffer.
          */
        virtual int getVertexCount()     = 0;

        /**
          * returns the maximum number of vertex the vertex buffer can handle.
          * @return maximum number of vertex the vertex buffer can handle.
          */
        virtual int getMaxVertexCount()  = 0;

        /**
          * returns the vertex format of the vertex buffer. (see FORMAT enumeration)
          * @return vertex format of the vertex buffer.
          */
        virtual unsigned long getVertexFormat() = 0;

        /**
          * returns the width in bytes of a single vertex described by the format.
          * @return width in bytes of a single vertex described by the format.
          */
        virtual unsigned long getVertexStride() = 0;

        /**
          * Specifies untransformed vertex data. Should be last call
          * for each vertex. That is after the normal, color, and
          * texture coordinate calls are made for the vertex.
          * Note: should be used when format includes FORMAT_XYZ
          *
          * @param x x coordinate.
          * @param y y coordinate.
          * @param z z coordinate.
          */
        virtual CVertexBuffer& vertex( float x, float y, float z ) = 0;

        /**
          * Specifies transformed vertex data. Should be last call
          * for each vertex. That is after the normal, color, and
          * texture coordinate calls are made for the vertex.
          * Note: should be used when format includes FORMAT_XYZRHW
          *
          * @param x x coordinate.
          * @param y y coordinate.
          * @param z z coordinate.
          * @param w w coordinate.
          */
        virtual CVertexBuffer& vertex( float x, float y, float z, float w ) = 0;

        /**
          * Specifies vertex normal data.
          * Note: should be used when format includes FORMAT_NORMAL
          *
          * @param x Normal x value.
          * @param y Normal y value.
          * @param z Normal z value.
          */
        virtual CVertexBuffer& normal( float x, float y, float z ) = 0;

        /**
          * Specifies diffuse color data.
          * Note: should be used when format includes FORMAT_DIFFUSE
          *
          * @param r Red color value.
          * @param g Green color value.
          * @param b Blue color value.
          * @param a Alpha color value.
          */
        virtual CVertexBuffer& diffuse( float r, float g, float b, float a = 1.0f )  = 0;

        /**
          * Specifies specular color data.
          * Note: should be used when format includes FORMAT_SPECULAR
          *
          * @param r Red color value.
          * @param g Green color value.
          * @param b Blue color value.
          * @param a Alpha color value.
          */
        virtual CVertexBuffer& specular( float r, float g, float b, float a = 1.0f ) = 0;

        /**
          * Specifies texture vertex. Successive calls should be made to this
          * method if more than one set of texture coordinates need to be
          * specified.
          * Note: should be used when format includes FORMAT_TEXTUREFLAG
          *
          * @param u U texture coordinate.
          * @param v V texture coordinate.
          */
        virtual CVertexBuffer& texvertex( float u, float v ) = 0;
    };

    #endif

Currently browsing [d3dvertexbuffer.zip] (5,129 bytes) - [d3dvertexbuffer.cpp] - (7,431 bytes)

    /* ************************************************************************** */
    // File       : d3dvertexbuffer.cpp
    // Programmer : Tobin Schwaiger-Hastanan
    // Copyright (c) 1997-2002 Tobin Schwaiger-Hastanan
    // Notes      : for flipcode.com's COTD.
    /* ************************************************************************** */
    #include <string>
    using namespace std;

    #include <windows.h>
    #include <d3d8.h>

    #include "d3dvertexbuffer.h"

    CD3DVertexBuffer::CD3DVertexBuffer( LPDIRECT3DDEVICE8 pD3DDevice, int count, unsigned long format, bool isDynamic )
    {
        unsigned long size = 0;

        m_pD3DDevice       = pD3DDevice;
        m_pD3DVertexBuffer = NULL;
        m_primitiveType    = D3DPT_POINTLIST;

        m_FVF        = 0;
        m_format     = format;
    	m_nMaxVertex = count;

        if( format & FORMAT_XYZ )
        {
            m_FVF |= D3DFVF_XYZ;
            size += sizeof( float ) * 3;
            m_offsetVertex = 0;
        }
        else if( format & FORMAT_XYZRHW )
        {
            m_FVF |= D3DFVF_XYZRHW;
            size += sizeof( float ) * 4;
            m_offsetVertex = 0;
        }

        if( format & FORMAT_NORMAL )
        {
            m_FVF |= D3DFVF_NORMAL;
            m_offsetNormal = size;
            size += sizeof( float ) * 3;
        }

        if( format & FORMAT_DIFFUSE )
        {
            m_FVF |= D3DFVF_DIFFUSE;
            m_offsetDiffuse = size;
            size += sizeof( DWORD );
        }

        if( format & FORMAT_SPECULAR )
        {
            m_FVF |= D3DFVF_SPECULAR;
            m_offsetSpecular = size;
            size += sizeof( DWORD );
        }

        if( format & FORMAT_TEXVERTEXFLAG )
        {
            // fix this
            int nTexVertex = (format & ~FORMAT_TEXVERTEXFLAG ) >> 8;

            switch( nTexVertex )
            {
            case 0:
                m_FVF |= D3DFVF_TEX0;
                break;
            case 1:
                m_FVF |= D3DFVF_TEX1;
                break;
            case 2:
                m_FVF |= D3DFVF_TEX2;
                break;
            case 3:
                m_FVF |= D3DFVF_TEX3;
                break;
            case 4:
                m_FVF |= D3DFVF_TEX4;
                break;
            case 5:
                m_FVF |= D3DFVF_TEX5;
                break;
            case 6:
                m_FVF |= D3DFVF_TEX6;
                break;
            case 7:
                m_FVF |= D3DFVF_TEX7;
                break;
            case 8:
                m_FVF |= D3DFVF_TEX8;
                break;
            default:
                throw CException( __FILE__, __LINE__, "CD3DVertexBuffer::CD3DVertexBuffer() --> Number of texture vertex not supported." );
                break;
            }

            m_offsetTexVertex = size;
            m_strideTexVertex = sizeof( float ) * 2;

            size += m_strideTexVertex * nTexVertex;
        }

        m_strideVertex = size;

        DWORD flags = isDynamic?D3DUSAGE_DYNAMIC:0;
        unsigned long rc;
        if( (rc = m_pD3DDevice->CreateVertexBuffer( m_strideVertex * count, D3DUSAGE_WRITEONLY|flags , m_FVF, D3DPOOL_DEFAULT, &m_pD3DVertexBuffer ) ) != D3D_OK )
            throw CException( __FILE__, __LINE__, "CD3DVertexBuffer::CD3DVertexBuffer() --> Unable to create D3D Vertex Buffer." );

        m_isLocked = false;
    }

    CD3DVertexBuffer::~CD3DVertexBuffer()
    {
        if( m_pD3DVertexBuffer != NULL )
            m_pD3DVertexBuffer->Release();
    }

    void CD3DVertexBuffer::setPrimitive( PRIMITIVE& primitive )
    {
        switch( primitive )
        {
        case PRIMITIVE_POINTLIST:
            m_primitiveType = D3DPT_POINTLIST;
            break;
        case PRIMITIVE_LINELIST:
            m_primitiveType = D3DPT_LINELIST;
            break;
        case PRIMITIVE_LINESTRIP:
            m_primitiveType = D3DPT_LINESTRIP;
            break;
        case PRIMITIVE_TRIANGLELIST:
            m_primitiveType = D3DPT_TRIANGLELIST;
            break;
        case PRIMITIVE_TRIANGLESTRIP:
            m_primitiveType = D3DPT_TRIANGLESTRIP;
            break;
        case PRIMITIVE_TRIANGLEFAN:
            m_primitiveType = D3DPT_TRIANGLEFAN;
            break;
        }
    }

    CVertexBuffer::PRIMITIVE CD3DVertexBuffer::getPrimitive()
    {
        PRIMITIVE primitive;

        switch( m_primitiveType )
        {
        case D3DPT_POINTLIST:
            primitive = PRIMITIVE_POINTLIST;
            break;
        case D3DPT_LINELIST:
            primitive = PRIMITIVE_LINELIST;
            break;
        case D3DPT_LINESTRIP:
            primitive = PRIMITIVE_LINESTRIP;
            break;
        case D3DPT_TRIANGLELIST:
            primitive = PRIMITIVE_TRIANGLELIST;
            break;
        case D3DPT_TRIANGLESTRIP:
            primitive = PRIMITIVE_TRIANGLESTRIP;
            break;
        case D3DPT_TRIANGLEFAN:
            primitive = PRIMITIVE_TRIANGLEFAN;
            break;
        }

        return primitive;
    }

    CVertexBuffer& CD3DVertexBuffer::begin( PRIMITIVE primitive )
    {
        setPrimitive( primitive );

        m_pvertex = (unsigned char*) lock().getVertexData();
        m_nTexVertex = 0;

    	return *this;
    }

    CVertexBuffer& CD3DVertexBuffer::end()
    {
        unlock();
    	return *this;
    }

    CVertexBuffer& CD3DVertexBuffer::lock()
    {
        if( m_pD3DVertexBuffer->Lock( 0, 0, (BYTE**) &m_pbuffer, D3DLOCK_DISCARD ) != D3D_OK )
            throw CException( __FILE__, __LINE__, "CD3DVertexBuffer::lock() --> Unable to lock D3D Vertex Buffer." );

        m_isLocked = true;
        return *this;
    }

    CVertexBuffer& CD3DVertexBuffer::unlock()
    {
        if( m_pD3DVertexBuffer->Unlock() != D3D_OK )
            throw CException( __FILE__, __LINE__, "CD3DVertexBuffer::unlock() --> Unable to unlock D3D Vertex Buffer." );

        m_isLocked = false;
        m_pbuffer = NULL;
        return *this;
    }

    bool CD3DVertexBuffer::isLocked()
    {
        return m_isLocked;
    }

    void* CD3DVertexBuffer::getVertexData()
    {
        return m_pbuffer;
    }

    int CD3DVertexBuffer::getVertexCount()
    {
        return m_nVertex;
    }

    int CD3DVertexBuffer::getMaxVertexCount()
    {
        return m_nMaxVertex;
    }

    unsigned long CD3DVertexBuffer::getVertexFormat()
    {
        return m_format;
    }

    void CD3DVertexBuffer::vertex( float x, float y, float z )
    {
        float* vertex = (float*)(m_pvertex + m_offsetVertex);

        vertex[ 0 ] = x;
        vertex[ 1 ] = y;
        vertex[ 2 ] = z;

        m_nTexVertex = 0;
        m_pvertex += m_strideVertex;
        m_nVertex ++;
    }

    void CD3DVertexBuffer::vertex( float x, float y, float z, float w )
    {
        float* vertex = (float*)(m_pvertex + m_offsetVertex);

        vertex[ 0 ] = x;
        vertex[ 1 ] = y;
        vertex[ 2 ] = z;
        vertex[ 3 ] = w;

        m_nTexVertex = 0;
        m_pvertex += m_strideVertex;
        m_nVertex ++;
    }
    void CD3DVertexBuffer::normal( float x, float y, float z )
    {
        float* normal = (float*)( m_pvertex + m_offsetNormal );

        normal[ 0 ] = x;
        normal[ 1 ] = y;
        normal[ 2 ] = z;
    }

    void CD3DVertexBuffer::diffuse( float r, float g, float b, float a  )
    {
        DWORD* diffuse = (DWORD*)( m_pvertex + m_offsetDiffuse );

        *diffuse = D3DCOLOR_COLORVALUE( r, g, b, a );
    }

    void CD3DVertexBuffer::specular( float r, float g, float b, float a  )
    {
        DWORD* specular = (DWORD*)( m_pvertex + m_offsetSpecular );

        *specular = D3DCOLOR_COLORVALUE( r, g, b, a );
    }

    void CD3DVertexBuffer::texvertex( float u, float v )
    {
        float* texvertex = (float*)( m_pvertex + m_offsetTexVertex );

        texvertex += m_strideTexVertex * m_nTexVertex;
        texvertex[ 0 ] = u;
        texvertex[ 1 ] = v;
        m_nTexVertex ++;
    }

Currently browsing [d3dvertexbuffer.zip] (5,129 bytes) - [d3dvertexbuffer.h] - (4,654 bytes)

    /* ************************************************************************** */
    // File       : d3dvertexbuffer.h
    // Programmer : Tobin Schwaiger-Hastanan
    // Copyright (c) 1997-2002 Tobin Schwaiger-Hastanan
    // Notes      : for flipcode.com's COTD.
    /* ************************************************************************** */
    #ifndef _D3DVERTEXBUFFER_DAWT_H_INCLUDED_
    #define _D3DVERTEXBUFFER_DAWT_H_INCLUDED_

    /**
      * This is Direct 3D 8.1 implementation of CVertexBuffer.
      *
      * @see    CVertexBuffer
      * @author Tobin Schwaiger-Hastanan
      */
    class CD3DVertexBuffer:public CVertexBuffer
    {
    protected:
        CD3DVertexBuffer();                          // disable default constructor
        CD3DVertexBuffer( const CD3DVertexBuffer& ); // disable copy constructor
        CD3DVertexBuffer& operator =( const CD3DVertexBuffer& ); // disable assignment operator
    public:
        /**
          * Constructor used to create vertex buffer.
          * @param pD3DDevice Direct 3D Device
          * @param count number of vertex to be created
          * @param format format of vertex buffer ( See format flags in CVertexBuffer)
          * @param isDynamic specifies that vertex buffer is dynamic. [default: true]
          */
        CD3DVertexBuffer( LPDIRECT3DDEVICE8 pD3DDevice, int count, unsigned long format,
                          bool isDynamic = true );

        // destructor
        ~CD3DVertexBuffer();

        // for the following methods, see CVertexBuffer
        virtual CVertexBuffer& lock();
        virtual CVertexBuffer& unlock();
        virtual bool isLocked();

        virtual void setPrimitive( PRIMITIVE& primitive );
        virtual PRIMITIVE getPrimitive();

        virtual CVertexBuffer& begin( PRIMITIVE primitive = PRIMITIVE_POINTLIST );
        virtual CVertexBuffer& end();

        virtual void* getVertexData();

        virtual int getVertexCount();
        virtual int getMaxVertexCount();
        virtual unsigned long getVertexFormat();
        virtual unsigned long getVertexStride() { return m_strideVertex; }

        virtual CVertexBuffer& vertex( float x, float y, float z );
        virtual CVertexBuffer& vertex( float x, float y, float z, float w );
        virtual CVertexBuffer& normal( float x, float y, float z );
        virtual CVertexBuffer& diffuse( float r, float g, float b, float a = 1.0f );
        virtual CVertexBuffer& specular( float r, float g, float b, float a = 1.0f );
        virtual CVertexBuffer& texvertex( float u, float v );

        /* d3d related methods */
        /**
          * Returns the D3D Primitive type.
          * This is a CD3DVertexBuffer specific method.
          *
          * @return Direct 3D primitive type.
          */
        D3DPRIMITIVETYPE        getD3DPrimitiveType() { return m_primitiveType;    }

        /**
          * Returns the D3D Vertex buffer created by this class.
          * This is a CD3DVertexBuffer specific method.
          *
          * @return pointer to a Direct 3D Vertex Buffer.
          */
        LPDIRECT3DVERTEXBUFFER8 getD3DVertexBuffer()  { return m_pD3DVertexBuffer; }
        /**
          * Returns the D3D Vertex buffer format.
          * This is a CD3DVertexBuffer specific method.
          *
          * @return pointer to a Direct 3D Vertex Buffer Format.
          */
        DWORD                   getD3DVertexFormat()  { return m_FVF; }

    private:

        bool          m_isLocked;   // flag to specify if buffer is locked
        int           m_nMaxVertex; // maximum vertex in buffer.
        int           m_nVertex;    // number of vertex currently in buffer
        unsigned long m_format;     // vertex format
        void*         m_pbuffer;    // pointer to vertex data

        unsigned char* m_pvertex;    // pointer to head of current vertex

        unsigned long m_offsetVertex;   // offset of vertex data start of vertex
        unsigned long m_strideVertex;   // stride of entire vertex data
        unsigned long m_offsetNormal;   // offset of normal data from start of vertex
        unsigned long m_offsetDiffuse;  // offset of diffuse data from start of vertex
        unsigned long m_offsetSpecular; // offset of specular data from start of vertex
        unsigned long m_offsetTexVertex; // offset of TexVertex data from start of vertex
        unsigned long m_strideTexVertex; // stride of a single texture vertex entry
        int m_nTexVertex; // number of texture vertex

        /* d3d related members */
        D3DPRIMITIVETYPE        m_primitiveType;    // d3d primitive type
        LPDIRECT3DVERTEXBUFFER8 m_pD3DVertexBuffer; // d3d vertex buffer
        LPDIRECT3DDEVICE8       m_pD3DDevice;        // d3d device
        DWORD                   m_FVF;                // d3d vertex format
    };
    #endif

The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.