Flexible Vertex Format - special SVN branch is ready!!!

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post by randomMesh »

Sudi wrote:well but still the accessAttribute function shouldn't be const.
Why not? It doesn't change the state of the object. Data is already allocated.

But you're right, a cleaner solution would be to have a separate readAttribute() and writeAttribute().
"Whoops..."
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

In my first post I put the latest code with support types and Your suggestions about separate read and write operations. What do You think about current code? I also wait for dev team comment.

We can also add next constructor, when we will put pointer do data created before simple vertex (this avoid situation with 3x 'new' per vertex, by 3x 'new[]' per mesh buffer; for it we will destroy vertex data inside mesh buffer destructor).
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

I like this, vertex attributes are the way to go.

I wonder if we can provide a cleaner interface using something like:

Code: Select all


IVertexAttributeBuffer
{
public:
    virtual void* getData();
    virtual E_DATE_TYPE getDataType();
    virtual u32 getDataWidth();
}

SMeshBuffer
{
private:
    core::array<IVertexAttributeBuffer*> Buffers;
};

template <class T>
SVertexAttributeBuffer
{
    core::array<T> Data;
}
Something like that to have less void*? I don't like having too much void* in interfaces...

The actual implementation looks nice though.
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Post by 3DModelerMan »

Is this flexible vertex format for adding vertex data into shaders? Like adding another position for hardware animation morphing?
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post by shadowslair »

3DModelerMan wrote:Is this flexible vertex format for adding vertex data into shaders? Like adding another position for hardware animation morphing?
It should be used for whatever you may need. That`s why it`s called "flexible"... :P
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

OK, I prepared code more similar to BlindSide idea.

Code: Select all

#include <iostream>
#include "irrlicht.h"

// Attribute Types
enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0,
    EAT_BLEND_WEIGHT,
    EAT_BLEND_INDICES,
    EAT_NORMAL,
    EAT_TEXCOORD0,
    EAT_TEXCOORD1,
    EAT_TEXCOORD2,
    EAT_TEXCOORD3,
    EAT_TEXCOORD4,
    EAT_TEXCOORD5,
    EAT_TEXCOORD6,
    EAT_TEXCOORD7,
    EAT_TANGENT,
    EAT_BINORMAL,
    EAT_COLOR,
    EAT_XYZW,
    EAT_XYZ,
    EAT_XY,
    EAT_X
};

class IVertexAttributeBuffer
{
public:
    virtual void addAttribute(const void* vAttribute) = 0;
    virtual bool getAttribute(void* vAttribute, const irr::u32 vID) const = 0;
    virtual bool removeAttribute(const irr::u32 vID) = 0;
    virtual bool replaceAttribute(const void* vAttribute, const irr::u32 vID) = 0;
    virtual irr::u32 getAttributesCount() const = 0;

    virtual irr::u32 getAttributeSize() const = 0;
    virtual E_ATTRIBURE_TYPE getAttributeType() const = 0;

    virtual const void* getData() const = 0;
};

template <class T>
class SVertexAttributeBuffer : public IVertexAttributeBuffer
{
public:
    SVertexAttributeBuffer(E_ATTRIBURE_TYPE vAttributeType) : AttributeType(vAttributeType)
    {
        AttributeSize = sizeof(T);
    }

    ~SVertexAttributeBuffer()
    {
        Data.clear();
    }

    void addAttribute(const void* vAttribute)
    {
        T _Attribute;
        memcpy(&_Attribute, vAttribute, AttributeSize);

        Data.push_back(_Attribute);
    }

    bool getAttribute(void* vAttribute, const irr::u32 vID) const
    {
        // Check for avaiable index.
        if(vID >= Data.size())
            return false;

        memcpy(vAttribute, &Data[vID], AttributeSize);

        return true;
    }

    bool removeAttribute(const irr::u32 vID)
    {
        // Check for avaiable index.
        if(vID >= Data.size())
            return false;

        Data.erase(vID);

        return true;
    }

    bool replaceAttribute(const void* vAttribute, const irr::u32 vID)
    {
        // Check for avaiable index.
        if(!vAttribute || vID >= Data.size())
            return false;

        T _Attribute;
        memcpy(&_Attribute, vAttribute, AttributeSize);

        Data[vID] = _Attribute;

        return true;
    }

    irr::u32 getAttributesCount() const
    {
        return Data.size();
    }

    irr::u32 getAttributeSize() const
    {
        return AttributeSize;
    }

    E_ATTRIBURE_TYPE getAttributeType() const
    {
        return AttributeType;
    }

    const void* getData() const
    {
        return Data.const_pointer();
    }

private:
    irr::u32 AttributeSize;
    E_ATTRIBURE_TYPE AttributeType;

    irr::core::array<T> Data;
};

int main()
{
    // Example attributes.
    irr::core::vector3df Position[3] =
    {
        irr::core::vector3df(10.1f,11.1f,12.1f),
        irr::core::vector3df(100.1f,110.1f,120.1f),
        irr::core::vector3df(1000.1f,1100.1f,1200.1f)
    };

    irr::core::vector3df Normal[3] =
    {
        irr::core::vector3df(20.1f,21.1f,22.1f),
        irr::core::vector3df(200.1f,210.1f,220.1f),
        irr::core::vector3df(2000.1f,2100.1f,2200.1f)
    };

    irr::video::SColor Color[3] =
    {
        irr::video::SColor(10,11,12,13),
        irr::video::SColor(100,110,120,130),
        irr::video::SColor(200,210,220,230)
    };

    // Prepare vertex attribute buffers.
    IVertexAttributeBuffer* VAB_P = new SVertexAttributeBuffer<irr::core::vector3df>(EAT_POSITION);
    IVertexAttributeBuffer* VAB_N = new SVertexAttributeBuffer<irr::core::vector3df>(EAT_NORMAL);
    IVertexAttributeBuffer* VAB_C = new SVertexAttributeBuffer<irr::video::SColor>(EAT_COLOR);

    // Write attributes
    for(irr::u32 i = 0; i < 3; ++i)
    {
        VAB_P->addAttribute(&Position[i]);
        VAB_N->addAttribute(&Normal[i]);
        VAB_C->addAttribute(&Color[i]);
    }


    // Read attributes
    irr::core::vector3df PositionR[3] =
    {
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f)
    };

    irr::core::vector3df NormalR[3] =
    {
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f)
    };

    irr::video::SColor ColorR[3] =
    {
        irr::video::SColor(0,0,0,0),
        irr::video::SColor(0,0,0,0),
        irr::video::SColor(0,0,0,0)
    };

    for(irr::u32 i = 0; i < 3; ++i)
    {
        VAB_P->getAttribute(&PositionR[i], i);
        VAB_N->getAttribute(&NormalR[i], i);
        VAB_C->getAttribute(&ColorR[i], i);
    }

    // Display attributes values.
    for(irr::u32 i = 0; i < 3; ++i)
    {
        std::cout << "Position" << i << ": " << PositionR[i].X << ", " << PositionR[i].Y << ", " << PositionR[i].Z << std::endl;
        std::cout << "Normal" << i << ": " << PositionR[i].X << ", " << PositionR[i].Y << ", " << PositionR[i].Z << std::endl;
        std::cout << "Color" << i << ": " << ColorR[i].getAlpha() << ", " << ColorR[i].getRed() << ", " << ColorR[i].getGreen() <<  ", " << ColorR[i].getBlue() << std::endl << std::endl;
    }

    delete VAB_P;
    delete VAB_N;
    delete VAB_C;

    system("Pause");

    return 0;
}
As You see in this solution we haven't good vertex structure, it's replaced by IVertexAttributeBuffer packs (we'll apply these packs to SMeshBuffer). Which system is better (with vertex structure or with ivertexattributebuffer) in Your opinion?

BTW. Code is not fully tested, but I'm tired, so I can optionally improved it tomorrow.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

AFAIK, the combined vertex structures are the preferred ones for efficient GPU handling. And at least a few common vertex structures are supported by all drivers and versions currently out there. I don't know if the separated stuctures are necessary for the new DX10/GL4 driver versions. But I'd say we need at least the combined versions, if not both.
I'd also prefer reinterpret_cast over memcpy. That would also avoid the additional member in each method.
Also, dynamic allocation per vertex seems overkill, we need a template based static version to get a really good vertex format. I'm not yet sure how to achieve this (otherwise Irrlicht might already have the flexible vertex format). But I also don't know, yet, which features should be implemented in this technique. Which types should be supported, are positions of the elements arbitrary, how many types could be part of a vertex, and how many elements, are multiple types and semantics of the same type allowed, ...
3DModelerMan
Posts: 1691
Joined: Sun May 18, 2008 9:42 pm

Post by 3DModelerMan »

I don't know if the separated stuctures are necessary for the new DX10/GL4 driver versions. But I'd say we need at least the combined versions, if not both.
We're getting DX10 drivers?
That would be illogical captain...

My first full game:
http://www.kongregate.com/games/3DModel ... tor#tipjar
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Here is improved code:

Code: Select all

#include <iostream>
#include "irrlicht.h"

// Attribute Types
enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0,
    EAT_BLEND_WEIGHT,
    EAT_BLEND_INDICES,
    EAT_NORMAL,
    EAT_TEXCOORD0,
    EAT_TEXCOORD1,
    EAT_TEXCOORD2,
    EAT_TEXCOORD3,
    EAT_TEXCOORD4,
    EAT_TEXCOORD5,
    EAT_TEXCOORD6,
    EAT_TEXCOORD7,
    EAT_TANGENT,
    EAT_BINORMAL,
    EAT_COLOR,
    EAT_XYZW,
    EAT_XYZ,
    EAT_XY,
    EAT_X
};

class IVertexAttributeBuffer
{
public:
    virtual irr::u32 getAttributesCount() const = 0;

    virtual irr::u32 getAttributeSize() const = 0;
    virtual E_ATTRIBURE_TYPE getAttributeType() const = 0;

    virtual const void* getData() const = 0;
};

template <class T>
class SVertexAttributeBuffer : public IVertexAttributeBuffer
{
public:
    SVertexAttributeBuffer(E_ATTRIBURE_TYPE vAttributeType) : AttributeType(vAttributeType)
    {
    }

    ~SVertexAttributeBuffer()
    {
        Data.clear();
    }

    void addAttribute(T vAttribute)
    {
        Data.push_back(vAttribute);
    }

    T getAttribute(const irr::u32 vID) const
    {
        // Check for avaiable index.
        if(vID >= Data.size())
            return (T)0;

        return Data[vID];
    }

    bool removeAttribute(const irr::u32 vID)
    {
        // Check for avaiable index.
        if(vID >= Data.size())
            return false;

        Data.erase(vID);

        return true;
    }

    bool replaceAttribute(T vAttribute, const irr::u32 vID)
    {
        // Check for avaiable index.
        if(!vAttribute || vID >= Data.size())
            return false;

        Data[vID] = _Attribute;

        return true;
    }

    irr::u32 getAttributesCount() const
    {
        return Data.size();
    }

    irr::u32 getAttributeSize() const
    {
        return sizeof(T);
    }

    E_ATTRIBURE_TYPE getAttributeType() const
    {
        return AttributeType;
    }

    const void* getData() const
    {
        return Data.const_pointer();
    }

private:
    E_ATTRIBURE_TYPE AttributeType;

    irr::core::array<T> Data;
};

class SFlexibleMesh
{
public:
    const void* getVertexAttributeData() const
    {
        return VertexAttributeBuffer.const_pointer();
    }

    irr::core::array<IVertexAttributeBuffer*> VertexAttributeBuffer;
};

int main()
{
    // Example attributes.
    irr::core::vector3df Position[3] =
    {
        irr::core::vector3df(10.1f,11.1f,12.1f),
        irr::core::vector3df(100.1f,110.1f,120.1f),
        irr::core::vector3df(1000.1f,1100.1f,1200.1f)
    };

    irr::core::vector3df Normal[3] =
    {
        irr::core::vector3df(20.1f,21.1f,22.1f),
        irr::core::vector3df(200.1f,210.1f,220.1f),
        irr::core::vector3df(2000.1f,2100.1f,2200.1f)
    };

    irr::video::SColor Color[3] =
    {
        irr::video::SColor(10,11,12,13),
        irr::video::SColor(100,110,120,130),
        irr::video::SColor(200,210,220,230)
    };

    // Prepare vertex attribute buffers.
    SVertexAttributeBuffer<irr::core::vector3df>* VAB_P = new SVertexAttributeBuffer<irr::core::vector3df>(EAT_POSITION);
    SVertexAttributeBuffer<irr::core::vector3df>* VAB_N = new SVertexAttributeBuffer<irr::core::vector3df>(EAT_NORMAL);
    SVertexAttributeBuffer<irr::video::SColor>* VAB_C = new SVertexAttributeBuffer<irr::video::SColor>(EAT_COLOR);

    SFlexibleMesh* FlexibleMesh = new SFlexibleMesh();
    FlexibleMesh->VertexAttributeBuffer.push_back(VAB_P);
    FlexibleMesh->VertexAttributeBuffer.push_back(VAB_N);
    FlexibleMesh->VertexAttributeBuffer.push_back(VAB_C);

    // Write attributes
    for(irr::u32 i = 0; i < 3; ++i)
    {
        VAB_P->addAttribute(Position[i]);
        VAB_N->addAttribute(Normal[i]);
        VAB_C->addAttribute(Color[i]);
    }

    // Read attributes
    irr::core::vector3df PositionR[3] =
    {
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f)
    };

    irr::core::vector3df NormalR[3] =
    {
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f),
        irr::core::vector3df(0.0f,0.0f,0.0f)
    };

    irr::video::SColor ColorR[3] =
    {
        irr::video::SColor(0,0,0,0),
        irr::video::SColor(0,0,0,0),
        irr::video::SColor(0,0,0,0)
    };

    for(irr::u32 i = 0; i < 3; ++i)
    {
        PositionR[i] = VAB_P->getAttribute(i);
        NormalR[i] = VAB_N->getAttribute(i);
        ColorR[i] = VAB_C->getAttribute(i);
    }

    // Display attributes values.
    for(irr::u32 i = 0; i < 3; ++i)
    {
        std::cout << "Position" << i << ": " << PositionR[i].X << ", " << PositionR[i].Y << ", " << PositionR[i].Z << std::endl;
        std::cout << "Normal" << i << ": " << PositionR[i].X << ", " << PositionR[i].Y << ", " << PositionR[i].Z << std::endl;
        std::cout << "Color" << i << ": " << ColorR[i].getAlpha() << ", " << ColorR[i].getRed() << ", " << ColorR[i].getGreen() <<  ", " << ColorR[i].getBlue() << std::endl << std::endl;
    }

    delete VAB_P;
    delete VAB_N;
    delete VAB_C;

    system("Pause");

    return 0;
}
I remove unnecessary stuff from IVertexAttributeBuffer, so I can replace void* by template type in SVertexAttributeBuffer. For OpenGL (current irr, 3.x, 4.x) we can use the same structure, I think that for D3D9,10,11 is similar, but I'm not 100% sure. This code have 1 known issue. Vertices data is stored on different arrays, so for each attribute we need different VBO and this is of course unacceptable solution. But if we move all data on one array adding new attributes will be unsafe, we will must add data in the same scheme eg:
add position, add normal, add other... // OK
add position, add normal, add other... // OK
add normal, add position, add other... // BAD
add position, add position... // BAD
So this isn't also the best solution... Some ideas? It looks like UnifiedVertex is better solution than IVertexAttributeBuffer.
Last edited by Nadro on Tue May 11, 2010 5:10 pm, edited 1 time in total.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Which one is IFlexibleVertex? My vote in the previous thread was for UnifiedVertex, at least from the basic concept. However, the attribute thing might come in handy for feedback buffers and a generalized buffer concept. So, as said, we might need both in the end, but this is pure speculation.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Yep, should be UnifiedVertex instead of IFlexibleVertex :P
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

so for each attribute we need different VBO and this is of course unacceptable solution
Why is this unacceptable? As I understand this way the user can choose to upload only certain attributes to the GPU (E.g. keep static X, Z position but update only Y position VBO).
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

Yes, that's why I mentioned the possibility for both approaches. However, the separate VBO construction would be needed for every combination of data, so even for the usual position/normal/texcoord setup you'd need multiple VBOs. Or at least non-unified access, which makes this approach definitely slower than the combined vertex version.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Maybe unacceptable is too hard word, but many too small VBO's isn't good for performance. User can set flag per attribute so he can upload all position components or none, but this is nice when we need set only position as stream, but others as static.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Here in another solution:

Code: Select all

#include <iostream>
#include "irrlicht.h"

// Attribute Types.
enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0, //vector3df
    EAT_BLEND_WEIGHT, // f32[4]
    EAT_BLEND_INDICES, // f32[4]
    EAT_NORMAL, //vector3df
    EAT_TEXCOORD0, //vector2df
    EAT_TEXCOORD1, //vector2df
    EAT_TEXCOORD2, //vector2df
    EAT_TEXCOORD3, //vector2df
    EAT_TEXCOORD4, //vector2df
    EAT_TEXCOORD5, //vector2df
    EAT_TEXCOORD6, //vector2df
    EAT_TEXCOORD7, //vector2df
    EAT_TANGENT, //vector3df
    EAT_BINORMAL, //vector3df
    EAT_COLOR, //SColor
    EAT_XYZWI, // u32[4]
    EAT_XYZI, // u32[3]
    EAT_XYI, // u32[2]
    EAT_XI, // u32
    EAT_XYZWF, // f32[4]
    EAT_XYZF, // f32[3]
    EAT_XYF, // f32[2]
    EAT_XF, // f32
    EAT_UNDECLARED // s32, it tell our that with vertex attribute it's something wrong.
};

// Attribute Offset Types (more friendly for switch-case selecting, which we will use eg. for OpenGL VBO's).
enum E_ATTRIBURE_OFFSET_TYPE
{
    EAOT_XYZWI = 0, // int, 4 x 4 bytes
    EAOT_XYZI, // int, 3 x 4 bytes
    EAOT_XYI, // int, 2 x 4 bytes
    EAOT_XI, // int, 1 x 4 bytes
    EAOT_XYZWF, // float, 4 x 4 bytes
    EAOT_XYZF, // float, 3 x 4 bytes
    EAOT_XYF, // float, 2 x 4 bytes
    EAOT_XF, // float, 1 x 4 bytes
    EAOT_XU, // unsigned, 1 x 4 bytes for SColor
    EAOT_UNDECLARED // s32, it tell our that with vertex attribute it's something wrong.
};

// Flexible Vertex class. We store all vertices inside the mesh buffer in this way.
class IFlexibleVertex
{
public:
    virtual irr::u32 getAttributeOffset(const irr::u32 vID) const = 0;
    virtual E_ATTRIBURE_TYPE getAttributeType(const irr::u32 vID) const = 0;
    virtual E_ATTRIBURE_OFFSET_TYPE getAttributeOffsetType(const irr::u32 vID) const = 0;
    virtual irr::u32 getAttributesCount(const irr::u32 vID) const = 0;
};

// Our standard vertex type. Other types we will create in this way.
class SVertex : public IFlexibleVertex
{
public:
    SVertex() :
        Position(irr::core::vector3df(0.0f, 0.0f, 0.0f)),
        Normal(irr::core::vector3df(0.0f, 0.0f, 0.0f)),
        Color(irr::video::SColor(0, 0 ,0 ,0))
    {
    }

    SVertex(const irr::core::vector3df& vPosition, const irr::core::vector3df& vNormal, const irr::video::SColor& vColor) :
        Position(vPosition), Normal(vNormal), Color(vColor)
    {
    }

    irr::u32 getAttributeOffset(const irr::u32 vID) const
    {
        irr::u32 _Offset = 0;

        switch(vID)
        {
        case 0:
            _Offset = sizeof(irr::core::vector3df);
            break;
        case 1:
            _Offset = sizeof(irr::core::vector3df);
            break;
        case 2:
            _Offset = sizeof(irr::video::SColor);
            break;
        default:
            _Offset = 0;
            break;
        }

        return _Offset;
    }

    E_ATTRIBURE_TYPE getAttributeType(const irr::u32 vID) const
    {
        E_ATTRIBURE_TYPE _Type = EAT_UNDECLARED;

        switch(vID)
        {
        case 0:
            _Type = EAT_POSITION;
            break;
        case 1:
            _Type = EAT_NORMAL;
            break;
        case 2:
            _Type = EAT_COLOR;
            break;
        default:
            _Type = EAT_UNDECLARED;
            break;
        }

        return _Type;
    }

    E_ATTRIBURE_OFFSET_TYPE getAttributeOffsetType(const irr::u32 vID) const
    {
        E_ATTRIBURE_OFFSET_TYPE _Type = EAOT_UNDECLARED;

        switch(vID)
        {
        case 0:
            _Type = EAOT_XYZF;
            break;
        case 1:
            _Type = EAOT_XYZF;
            break;
        case 2:
            _Type = EAOT_XU;
            break;
        default:
            _Type = EAOT_UNDECLARED;
            break;
        }

        return _Type;
    }

    irr::u32 getAttributesCount(const irr::u32 vID) const
    {
        return 3;
    }

    irr::core::vector3df Position;
    irr::core::vector3df Normal;
    irr::video::SColor Color;
};

class IFlexibleMeshBuffer
{
public:
    virtual void* getArray() = 0;
    virtual void* getData() = 0;
    virtual irr::u32 getVerticesCount() const = 0;
};

template <class T>
class SFlexibleMeshBuffer : public IFlexibleMeshBuffer
{
public:
    ~SFlexibleMeshBuffer()
    {
        Vertices.clear();
    }

    void* getArray()
    {
        return &Vertices;
    };

    void* getData()
    {
        return Vertices.pointer();
    };

    irr::u32 getVerticesCount() const
    {
        return Vertices.size();
    }

private:
    irr::core::array<T> Vertices;
};

// Write attributes.
void writeAttributes(IFlexibleMeshBuffer* MeshBuffer)
{
    irr::core::vector3df Position[3] =
    {
        irr::core::vector3df(10.1f,11.1f,12.1f),
        irr::core::vector3df(100.1f,110.1f,120.1f),
        irr::core::vector3df(1000.1f,1100.1f,1200.1f)
    };

    irr::core::vector3df Normal[3] =
    {
        irr::core::vector3df(20.1f,21.1f,22.1f),
        irr::core::vector3df(200.1f,210.1f,220.1f),
        irr::core::vector3df(2000.1f,2100.1f,2200.1f)
    };

    irr::video::SColor Color[3] =
    {
        irr::video::SColor(10,11,12,13),
        irr::video::SColor(100,110,120,130),
        irr::video::SColor(200,210,220,230)
    };

    // Get array.
    irr::core::array<SVertex>* Vertices = (irr::core::array<SVertex>*)MeshBuffer->getArray();

    // Add vertex to our array.
    for(irr::u32 i = 0; i < 3; ++i)
    {
        SVertex Vertex(Position[i], Normal[i], Color[i]);
        Vertices->push_back(Vertex);
    }
}

// Read and display attributes.
void readAndDisplayAttributes(IFlexibleMeshBuffer* MeshBuffer)
{
    // Get data.
    void* Data = MeshBuffer->getData();

    for(irr::u32 i = 0; i < MeshBuffer->getVerticesCount(); ++i)
    {
        // We can also select properly types thanks to IFlexibleVertex functions, but it will be more costly (switch-case).
        irr::core::vector3df Position(0.0f,0.0f,0.0f);
        irr::core::vector3df Normal(0.0f,0.0f,0.0f);
        irr::video::SColor Color(0,0,0,0);

        // Mostly time we needn't acces to simple vertex attribute (for send data to GPU we will use pointer to vertices array with offsets), but we can do it in this way:
        SVertex* Vertex = ((SVertex*)Data +i);

        Position = Vertex->Position;
        Normal = Vertex->Normal;
        Color = Vertex->Color;

        // Display
        std::cout << "Position" << i << ": " << Position.X << ", " << Position.Y << ", " << Position.Z << std::endl;
        std::cout << "Normal" << i << ": " << Normal.X << ", " << Normal.Y << ", " << Normal.Z << std::endl;
        std::cout << "Color" << i << ": " << Color.getAlpha() << ", " << Color.getRed() << ", " << Color.getGreen() <<  ", " << Color.getBlue() << std::endl << std::endl;
    }
}

int main()
{
    // Create Mesh Buffer.
    IFlexibleMeshBuffer* MeshBuffer = new SFlexibleMeshBuffer<SVertex>();

    // Write attributes.
    writeAttributes(MeshBuffer);

    // Read and display attributes.
    readAndDisplayAttributes(MeshBuffer);

    // Delete Mesh Buffer;
    delete MeshBuffer;

    system("Pause");

    return 0;
}
In this solution create new vertex type need some more programmer work (see SVertex class), but memory mangament is very similar to current Irrlicht system. Inside engine we will use IFlexibleMeshBuffer and IFlexibleVertex and at loader stage predefined S3DVertex or others. I think that this solution is very similar to our current vertex, but programmer can add Your own vertex types in easy way.

I showed implementation for 3 different solution about flexible vertex problem. Now we must compare each and select the best.

We need talk about E_ATTRIBURE_TYPE and E_ATTRIBURE_OFFSET_TYPE members (these enums will be usefull also for previous systems).
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Post Reply