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.
BlindSide
Admin
Posts: 2821
Joined: Thu Dec 08, 2005 9:09 am
Location: NZ!

Post by BlindSide »

Code: Select all

irr::u32 getAttributesCount(const irr::u32 vID) const 
I guess this is supposed to have no params?

Anyway Nadro thanks for this awesome stuff, I'm looking forward to having FVF in Irrlicht.

I still think that having seperate meshbuffers is the best solution because if the performance loss is not that big than the ease of use more than makes up for it, and you don't have to define a new vertex type really, just a new attribute.

What I'd like to do when I have some time is run some tests (On old and new GPUs) and compare the performance of the methods. I suppose on really old GPUs (Before PS 2.0) we will find a big performance decrease.

In the end a combination approach is best I guess.

Your last solution looks good overall, I wouldn't mind including it right away after some cleaning up. Although I don't like E_ATTRIBURE_OFFSET_TYPE , I think that we already have the attribute type and offset length. You can see that already you are missing XYZU and maybe a few other ones, so having all the combinations might need a really big list of enums. If we keep the enums to make OpenGL calls easier then maybe make the default implementation of getAttributeOffsetType() calculate it automatically from the other info?

Also I would want to rename IFlexibleVertex to IFlexibleVertexType or IFlexibleVertexDescriptor as the actual driver will not be accessing it as an actual vertex but more as a description of the content (The main reason for this naming is because of all the virtual methods, we don't want to confuse someone into thinking of this class as something to be used like a basic Struct).

Cheers
ShadowMapping for Irrlicht!: Get it here
Need help? Come on the IRC!: #irrlicht on irc://irc.freenode.net
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

Thanks BlindSide for comment.

Yes, getAttributesCount with param was copy-paste "effect", of course this function shouldn't have any params.

I'm very interesting how will be performance each method on both old and new hardware, but I hope that performance will be good on both platforms compare to current Irrlicht vertex system.

I replaced E_ATTRIBURE_OFFSET_TYPE members to more usefull (especially for GL 3.x VAO's; this list based on OpenGL types list):

Code: Select all

enum E_ATTRIBURE_OFFSET_TYPE
{
    EAOT_BYTE,
    EAOT_UNSIGNED_BYTE,
    EAOT_SHORT,
    EAOT_UNSIGNED_SHORT,
    EAOT_INT,
    EAOT_UNSIGNED_INT,
    EAOT_FLOAT,
    EAOT_DOUBLE
};
I also rebuilded E_ATTRIBURE_TYPE list:

Code: Select all

enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0,
    EAT_NORMAL,
    EAT_TEXCOORD,
    EAT_COLOR,
    EAT_TANGENT,
    EAT_BINORMAL,
    EAT_BLEND_WEIGHT,
    EAT_BLEND_INDICES,
    EAT_XYZW,
    EAT_XYZ,
    EAT_XY,
    EAT_X,
    EAT_UNDECLARED // it tell our that with vertex attribute it's something wrong.
};
I removed TEXCOORD0-7 because it was too more similar with fixed pipeline. If 2 or more attributes will be use EAT_TEXCOORD, we will map first attribute as texcoord0, second as texcoord1 etc...

I agree that rename IFlexibleVertex to IFlexibleVertexDescriptor is a good idea.

I cleaned my first post and I put in them the latest version of each solution.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
sio2
Competition winner
Posts: 1003
Joined: Thu Sep 21, 2006 5:33 pm
Location: UK

Post by sio2 »

Just my $0.02

I'm implementing a buffer system in my own version of Spintz's 3Demon engine. I've already added the Direct3D11 driver and I'm now in the process of adding flexible buffer formats. [I'm very busy at work at the moment, so I'm only planning things and trying things out in source.]

From my point of view at the core I'm only creating buffers of data. Buffers are made of elements and have a stride and data type. A resource access type gives the buffer meaning - vertex data, index data, constant buffer, stream-out, Compute Shader buffer, OpenCL buffer, etc. I have predefined data for creating the three "standard" Irrlicht vertex types: standard, 2texcoord and tangent for backward compatibility. So I can, for example, create a buffer of data, pass it to a Compute Shader and then re-cast it as a vertex buffer or texture.

Something that's taking time is going through the engine and replacing code that operates on the standard vertex types, such as the Mesh Manipulator.
fmx

Post by fmx »

Is progress being made to add support for FVF into irrlicht?
The last post was almost 5 months ago

The Unified Vertex Solution seems the most logical and easy to understand (from a casual irrlicht user's POV), but Flexible Vertex Descriptor and Mesh Buffer solution is probably most ideal overall

I noticed this in one of Nadro's earlier code listings
EAT_BLEND_INDICES, // f32[4]
Just be aware that Bone Indices should really be stored as integers, possibly even unsigned bytes.
Although I now see that any types can be set so it isn't an issue anymore

Personally i think the generic S3DVertex format should be kept as it is, alongside any FVF implementation in the future.

Most casual uses of irrlicht dont require complex vertex formats (particularly on older machines and mobile devices) so they would have the most to lose from FVFs
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

feature reqest

Post by REDDemon »

I think also older machine can gain some advantage from a flexible vertex format.

Actually I need for a world editor a vertex format like that: (and i use opengl 2.1 with 1.2 shaders so this can be really compatible with "old" machines).

texture coord 0 (first texture layer)
texture coord 1 (second texture layer)
texture coord 2 (third texture layer)
texture coord 3 (fourth texture layer)
normal (normal, for lighting)
colors (just to have color data, but i don't interpolate colors with textures, i use them to store data that are used in the shaders)


I started developing the editor with the idea of vertex like vertices in opengl in mind so with multiple textures coordinates. So I become disappointed when i find that irrlicht support at max a vertex with 2 texture coordinates (and no normals?)

I tried to import this code but i have no idea on how to draw it. (ok i theorically have a data struct that contains the correct data, but now i have also the need to draw this list of new vertices. and i'm not sure on how to get the irrlicht drivers to draw this new flexible meshbuffer)

If you want I can add a preview of the editor as test case for your flexible vertex format. I will use it massively :)

this will (theorically) improve the speed of rendering. actually i have to render multiple layers using alpha vertex and multiple pass but FPS go down drastically.

Or alternatively i need some hints on where modify irrlicht to get what i want.
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
fmx

Post by fmx »

Its not implemented yet, Nadro was just suggesting possible schemes.

Implementing a new vertex framework would require extensive changes all across the whole of irrlicht, from mesh loading to octrees to particles, etc etc etc.

I would guess at roughly 3/4 of the irrlicht source would require some kind of modification in order to get FVFs fully implemented.
Its no small task for even one or two persons, it would require all the combined efforts of the devs at the very least.

We are still waiting for them to reach a decision on how to go about it (if at all).
Most likely not until irrlicht-2.x or something, so dont hold your breath

Look into S3DTangent vertex format in the meantime, it has enough floats available to cater for 4 UV sets + normal
REDDemon
Developer
Posts: 1044
Joined: Tue Aug 31, 2010 8:06 pm
Location: Genova (Italy)

Post by REDDemon »

Ok I suppose i have to wait if i want to give full power to my editor so :(.
maybe a little preview on my project can help to decide about vertex doom :)
Junior Irrlicht Developer.
Real value in social networks is not about "increasing" number of followers, but about getting in touch with Amazing people.
- by Me
evandromillian
Posts: 40
Joined: Wed Apr 01, 2009 11:45 am
Location: São Paulo - Brazil

Post by evandromillian »

Hi people.

In DX 11 driver project, I implemented a FVF in a simple way, only exposing one additional method and one struct, as well as some enumerations:

SVertexElement:

Code: Select all

#ifndef __S_VERTEX_ELEMENT_H_INCLUDED__
#define __S_VERTEX_ELEMENT_H_INCLUDED__

#include "irrTypes.h"
#include "irrString.h"

namespace irr
{
namespace video
{

//! Enumeration for all vertex types there are.
enum E_VERTEX_ELEMENT_SEMANTIC
{
	EVES_POSITION = 0,
	EVES_NORMAL,
	EVES_TEXTURE_COORD,
	EVES_COLOR,
	EVES_TANGENT,
	EVES_BINORMAL,
	EVES_BLEND_WEIGHTS,
	EVES_BLEND_INDICES,
	EVES_COUNT = 0x7fffffff
};

enum E_VERTEX_ELEMENT_TYPE
{
	EVET_FLOAT1 = 0,
	EVET_FLOAT2,
	EVET_FLOAT3,
	EVET_FLOAT4,

	EVET_UINT1,
	EVET_UINT2,
	EVET_UINT3,
	EVET_UINT4,
	
	EVET_SHORT2,
	EVET_SHORT4,
	
	EVET_UBYTE4,
	
	EVET_COLOUR,
	
	EVET_COUNT = 0x7fffffff
};

struct SVertexElement
{
	// Constructor
	SVertexElement(E_VERTEX_ELEMENT_SEMANTIC semanticType, E_VERTEX_ELEMENT_TYPE type,
				   u32 semanticIndex = 0, u32 slotIndex = 0, 
				   u32 instanceStep = 0, bool perInstance = false)
	: SemanticType(semanticType)
	, Type(type)
	, SemanticIndex(semanticIndex)
	, SlotIndex(slotIndex)
	, InstanceStep(instanceStep)
	, PerInstance(perInstance) {}

	// Choose one of these to name the semantic
	E_VERTEX_ELEMENT_SEMANTIC SemanticType;
	
	// Type of data
	E_VERTEX_ELEMENT_TYPE Type;
	
	// How much elements with this semantic
	u32 SemanticIndex;
	
	// Element provided by which input buffer?
	u32 SlotIndex;

	// Index of instance
	u32 InstanceStep;

	// Is this element per instance?
	bool PerInstance;
};

}
}

#endif
IVideoDriver::registerVertexType method:

Code: Select all

virtual E_VERTEX_TYPE registerVertexType(core::array<SVertexElement>& elements) = 0;
This way, I think that the impact in current interface is minimum, cause the handle to a new vertex type is the same old E_VERTEX_TYPE enumeration, and not a new class/struct (same solution for custom material types). And probably the methods that query information about vertex type should be moved to IVideoDriver (getVertexPitchFromType, etc).

But maybe the implementation for drivers will change to much. In case of DirectX 9, we shall use vertex declaration class to enable instancing, and OpenGL probably requires more effort.
Next generation for Irrlicht!!!!!
fmx

Post by fmx »

Out of curiosity, do any of the irrlicht devs have a plan yet for implementing FVFs in the (possibly distant) future?

I would think some kind of implementation would have to exist by irrlicht 2.0, but 1.8 isn't far now and 1.9 would then have to act as a bridge towards any major API changes in 2.0 and easing the transition
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

I'd like to revive this thread since there have been a lot of problems on these forums the last couple of weeks related to the set vertex formats irrlicht has right now

I have implemented my own variant of the attribute buffer design discussed in this thread for my own rendering engine, and when done correctly it becomes very easy to add or remove components to a vertex declaration without any performance hits
Irrlicht could, at this point, certainly benefit from such an implementation
fmx

Post by fmx »

I'm sure the irrlicht devs are well aware of the need for this already, without us constantly reminding them :P

All I want to hear from hybrid et al is their proposed timescale, I'm sure it wont happen suddenly overnight but will be (should be) a gradual process to phase out the current system.

I'm not just waiting for it to "happen", I am very interested in helping out once the devs actually decide to go ahead with it.
Which is why I keep checking this topic, and for any mention of FVFs, with an eagle eye 8)

If you have already implemented flexible vertex formats in your engine then it might be useful if you could post your thoughts and findings on the implementation;
assuming your engine is based on irrlicht source, roughly how much work did it involve and how much of the original source did you have to edit in order to achieve it?
Radikalizm
Posts: 1215
Joined: Tue Jan 09, 2007 7:03 pm
Location: Leuven, Belgium

Post by Radikalizm »

My engine is not irrlicht based, it's built from the ground up, so I can't directly make any statements on how long it should take to implement it, but it shouldn't be too difficult porting it over to irrlicht since it doesn't depend on any complex systems

I would also be interested in helping with the development of such a system if a decision is made, I have the feeling that I should get involved more with the actual development of irrlicht
hybrid
Admin
Posts: 14143
Joined: Wed Apr 19, 2006 9:20 pm
Location: Oldenburg(Oldb), Germany
Contact:

Post by hybrid »

These changes are all scheduled for Irrlicht 2.0, which will not happen this year I guess.
fmx

Post by fmx »

Thanks for clearing that up hybrid.
Give us a shout when you devs actually decide to start on it, a number of us members are willing to help get it done quickly.

@Radikalizm
I use irrlicht on PC but I wrote my iOS engine from the ground up too; currently I'm using a fixed vertex format but I intend to have a go at implementing flexible vertexes over the coming week.
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Re: Flexible Vertex Format

Post by Nadro »

This is an original "first post" from FVF "talking" stage. I pasted if here, because maybe somebody will wanna check how ideas we had before for FVF.
Nadro wrote:In this topic we talk about Flexible Vertex Format for Irrlicht. Currently we have a following solutions for this problem:


------------------------------------------------------------------------------------


Unified Vertex solution
-require many 'new' calls

Code: Select all

#include <iostream>
#include "irrlicht.h"
 
// Unified Vertex class.
class UnifiedVertex
{
public:
 
    // Attribute Types.
    enum E_ATTRIBURE_TYPE
    {
        EAT_POSITION = 0,
        EAT_NORMAL,
        EAT_TEXCOORD,
        EAT_COLOR,
        EAT_TANGENT,
        EAT_BINORMAL,
        EAT_BLEND_WEIGHT,
        EAT_BLEND_INDICES,
        EAT_XYZW,
        EAT_XYZ,
        EAT_XY,
        EAT_X,
        EAT_UNDECLARED // it tell our that with vertex attribute it's something wrong.
    };
 
    // Constructor. (Safely method)
    UnifiedVertex(const irr::core::array<irr::u32>& vOffset, const irr::core::array<E_ATTRIBURE_TYPE>& vType) :
        AttributesCount(vOffset.size())
    {
        irr::u32 _Size = 0;
 
        // Allocate offsets and indices array.
        Offset = new irr::u32[AttributesCount];
        Type = new irr::u8[AttributesCount];
 
        for(irr::u32 i = 0; i < AttributesCount; ++i)
        {
            Offset[i] = vOffset[i];
            _Size += Offset[i];
 
            if(i < vType.size())
                Type[i] = (irr::u8)vType[i];
            else
                Type[i] = (irr::u8)EAT_UNDECLARED;
        }
 
        // Allocate memory for data.
        Data = new irr::u8[_Size];
    }
 
    // Constructor.
    UnifiedVertex(const irr::u32* vOffset, const E_ATTRIBURE_TYPE* vType, const irr::u32 AttributeCount) :
        AttributesCount(AttributeCount)
    {
        irr::u32 _Size = 0;
 
        // Allocate offsets and indices array.
        Offset = new irr::u32[AttributesCount];
        Type = new irr::u8[AttributesCount];
 
        for(irr::u32 i = 0; i < AttributesCount; ++i)
        {
            Offset[i] = vOffset[i];
            _Size += Offset[i];
 
            Type[i] = (irr::u8)vType[i];
        }
 
        // Allocate memory for data.
        Data = new irr::u8[_Size];
    }
 
    // Destructor.
    ~UnifiedVertex()
    {
        // Release allocated memory.
        delete[] Offset;
        delete[] Type;
        delete[] Data;
    }
 
    // Read attribute data.
    bool readAttribute(void* vData, const irr::u32 vPosition) const
    {
        // Check avaiable offsets.
        if(vPosition >= AttributesCount || !vData)
            return false;
 
        irr::u32 _Size = 0;
 
        for(irr::u32 i = 0; i < vPosition; ++i)
        _Size += Offset[i];
 
        // Read data.
        memcpy(vData, Data + _Size, Offset[vPosition]);
 
        return true;
    }
 
    // Write attribute data.
    bool writeAttribute(const void* vData, const irr::u32 vPosition)
    {
        // Check avaiable offsets.
        if(vPosition >= AttributesCount || !vData)
            return false;
 
        irr::u32 _Size = 0;
 
        for(irr::u32 i = 0; i < vPosition; ++i)
        _Size += Offset[i];
 
        // Write data.
        memcpy(Data + _Size, vData, Offset[vPosition]);
 
        return true;
    }
 
    // Get selected attribute offset.
    irr::u32 getAttributeOffset(const irr::u32 vPosition) const
    {
        irr::u32 _Offset = 0;
 
        if(vPosition < AttributesCount)
            _Offset = Offset[vPosition];
 
        return _Offset;
    }
 
    // Get offset index by type.
    irr::s32 getOffsetIndex(const E_ATTRIBURE_TYPE vType) const
    {
        irr::s32 _OffsetIndex = -1;
 
        // get index.
        if(vType != EAT_UNDECLARED)
            for(irr::u32 i = 0; i < AttributesCount; ++i)
                if((irr::u32)Type[i] == (irr::u32)vType)
                    _OffsetIndex = i;
 
        return _OffsetIndex;
    }
 
    // Get attributes count.
    irr::u32 getAttributesCount() const { return AttributesCount; }
 
    // Get data.
    irr::u8* getData() const { return Data; }
 
private:
 
    // Array with offsets sizes.
    irr::u32* Offset;
 
    // Array with type index.
    irr::u8* Type;
 
    // Attributes count.
    irr::u32 AttributesCount;
 
    // Data.
    irr::u8* Data;
};
 
int main()
{
    // Example attributes.
    irr::core::vector3df Position0(10.1,11.1,12.1);
    irr::core::vector3df Normal0(20.1,21.1,22.1);
    irr::video::SColor Color0(10,11,12,13);
 
    // Prepare vertex structure.
    irr::core::array<irr::u32> AttributeOffset;
    AttributeOffset.push_back(sizeof(irr::core::vector3df));
    AttributeOffset.push_back(sizeof(irr::core::vector3df));
    AttributeOffset.push_back(sizeof(irr::video::SColor));
 
    irr::core::array<UnifiedVertex::E_ATTRIBURE_TYPE> AttributeType;
    AttributeType.push_back(UnifiedVertex::EAT_POSITION);
    AttributeType.push_back(UnifiedVertex::EAT_NORMAL);
    AttributeType.push_back(UnifiedVertex::EAT_COLOR);
 
    UnifiedVertex* UV = new UnifiedVertex(AttributeOffset, AttributeType);
 
    // Alternative method.
    /*
    irr::u32 AttributeOffset[3] =
    {
        sizeof(irr::core::vector3df),
        sizeof(irr::core::vector3df),
        sizeof(irr::video::SColor)
    };
 
    UnifiedVertex::E_ATTRIBURE_TYPE AttributeType[3] =
    {
        UnifiedVertex::EAT_POSITION,
        UnifiedVertex::EAT_NORMAL,
        UnifiedVertex::EAT_COLOR
    };
 
    UnifiedVertex* UV = new UnifiedVertex(AttributeOffset, AttributeType, 3);
    */
 
    // Attributes indices.
    irr::u32 PositionID = 0;
    irr::u32 NormalID = 1;
    irr::u32 ColorID = 2;
 
    // When we don't know offsets indices.
    /*
    PositionID = UV->getOffsetIndex(UnifiedVertex::EAT_POSITION);
    NormalID = UV->getOffsetIndex(UnifiedVertex::EAT_NORMAL);
    ColorID = UV->getOffsetIndex(UnifiedVertex::EAT_COLOR);
    */
 
    // Write attibutes values.
    UV->writeAttribute(&Position0, PositionID);
    UV->writeAttribute(&Normal0, NormalID);
    UV->writeAttribute(&Color0, ColorID);
 
    // Read attributes values.
    irr::core::vector3df PositionR(0,0,0);
    irr::core::vector3df NormalR(0,0,0);
    irr::video::SColor ColorR(0,0,0,0);
 
    UV->readAttribute(&PositionR, PositionID);
    UV->readAttribute(&NormalR, NormalID);
    UV->readAttribute(&ColorR, ColorID);
 
    // Display attributes values.
    std::cout <<
        "Position: " << PositionR.X << ", " << PositionR.Y << ", " << PositionR.Z << "\n" <<
        "Normal: " << NormalR.X << ", " << NormalR.Y << ", " << NormalR.Z << "\n" <<
        "Color: " << ColorR.getAlpha() << ", " << ColorR.getRed() << ", " << ColorR.getGreen() << ", " << ColorR.getBlue() <<
    std::endl;
 
    delete UV;
 
    system("Pause");
 
    return 0;
}
 

------------------------------------------------------------------------------------


Vertex Attribute Buffer solution
-require independent VBO for each attribute

Code: Select all

#include <iostream>
#include "irrlicht.h"
 
// Attribute Types.
enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0,
    EAT_NORMAL,
    EAT_TEXCOORD,
    EAT_COLOR,
    EAT_TANGENT,
    EAT_BINORMAL,
    EAT_BLEND_WEIGHT,
    EAT_BLEND_INDICES,
    EAT_XYZW,
    EAT_XYZ,
    EAT_XY,
    EAT_X,
    EAT_UNDECLARED // it tell our that with vertex attribute it's something wrong.
};
 
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;
}
 

------------------------------------------------------------------------------------


Flexible Vertex Descriptor and Mesh Buffer solution
-require more programmer work to define new vertex type
-mesh buffer is integrated with vertex type

Code: Select all

#include <iostream>
#include "irrlicht.h"
 
// Attribute Types.
enum E_ATTRIBURE_TYPE
{
    EAT_POSITION = 0,
    EAT_NORMAL,
    EAT_TEXCOORD,
    EAT_COLOR,
    EAT_TANGENT,
    EAT_BINORMAL,
    EAT_BLEND_WEIGHT,
    EAT_BLEND_INDICES,
    EAT_XYZW,
    EAT_XYZ,
    EAT_XY,
    EAT_X,
    EAT_UNDECLARED // 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_BYTE,
    EAOT_UNSIGNED_BYTE,
    EAOT_SHORT,
    EAOT_UNSIGNED_SHORT,
    EAOT_INT,
    EAOT_UNSIGNED_INT,
    EAOT_FLOAT,
    EAOT_DOUBLE
};
 
// Flexible Vertex Descriptor class.
class IFlexibleVertexDescriptor
{
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 = 0;
};
 
// Our standard vertex type. Other types we will create in this way.
class SVertex : public IFlexibleVertexDescriptor
{
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_FLOAT;
 
        switch(vID)
        {
        /*case 0:
            _Type = EAOT_FLOAT;
            break;
        case 1:
            _Type = EAOT_FLOAT;
            break;*/
        case 2:
            _Type = EAOT_UNSIGNED_BYTE;
            break;
        default:
            _Type = EAOT_FLOAT;
            break;
        }
 
        return _Type;
    }
 
    irr::u32 getAttributesCount() 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;
}
 

------------------------------------------------------------------------------------


Please comment each solution, we need the best option. Remember that existing codes are in preview version and need some clean up.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Post Reply