Page 1 of 10

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

Posted: Sun May 09, 2010 1:52 am
by Nadro
How looks FVF support in Irrlicht?

In each, unified mesh buffer (IMeshBuffer), we had one vertex (in future we can will easy add support for many vertex buffers per mesh buffer) and index buffer (IVertexBuffer and IIndexBuffer). Each index buffer is now a dynamically, so You can easy switch between 16 and 32 bytes indices in each meshes. Vertex buffer require 2 elements, vertex structure eg. S3DVertex and 2 others built-in Irrlicht and compatible vertex descriptor (IVertexDescriptor), which include all important infos, about vertex structure. With a functions from a MeshManipulator convert vertices between a differences formats is really easy. It is important to use properly semantic, element count and type for an each vertex attribute when You define new vertex descriptor. Of course You must also prepare compatible vertex type (container class).

What is unfinished?
- createForsythOptimizedMesh method from IMeshManipulator.

Know bugs:
- None

Custom vertex structures are only supported in a Direct3D9 and OpenGL drivers. Other drivers, so Burning's Video, Software and Direct3D8 support only build-in Irrlicht vertex types, because FVF in these drivers isn't needed.

I hope that final patch will be ready soon and it will be included in Irrlicht 1.9.

You can download Irrlicht with FVF support from:
https://irrlicht.svn.sourceforge.net/sv ... -pipeline/

Posted: Sun May 09, 2010 10:00 am
by shadowslair
Hey, very nice, short and simple code. The only thing missing is the vertex type and/or vertex typename, giving the user the opportunity to set and get his own vertex type completely outside. The standard Irr types will be kept quite easily.

[0] vec3df Position
[1] vec3df Normal
[2] SColor Color
[3] vec2df TexCoord
[4] vec3df Tangent
[5] vec3df Binormal

STANDARD uses 0-2
TEXTURE uses 0-3
TANGENT uses 0-5
CUSTOM1
CUSTOM2

char* UnifVertexTypeName = "standard";
(...)

You`re simply a genious... 8)

Re: Flexible Vertex Format

Posted: Sun May 09, 2010 10:14 am
by randomMesh
Hi Nadro,

interesting code, but there's an issue.

Code: Select all

../source/main.cpp: In destructor 'UnifiedVertex::~UnifiedVertex()':
../source/main.cpp:64: warning: deleting 'void*' is undefined
This seems to be ok on windows using the msvc compiler. On Linux,
however, using gcc 4.4.3, the code actually generated uses plain delete, so at best there will be a memory leak and at worst undefined behaviour.

Edit: After deleting UV, the memory leak was gone. But still scary.

Posted: Sun May 09, 2010 10:55 am
by sudi
i would simply replace the void* with a unsigned char*. that should solve the problem. actually when i think about it. what is the size of void? lol

Posted: Sun May 09, 2010 11:03 am
by randomMesh
Sudi wrote:i would simply replace the void* with a unsigned char*. that should solve the problem. actually when i think about it. what is the size of void? lol
Yes, this solves the problem.

Another improment would be to make the code const-correct.

Code: Select all

bool accessAttribute(void* const vData, const unsigned int vPosition, const E_ACCESS_TYPE& vAccessType) const
vs.

Code: Select all

bool accessAttribute(void* vData, int vPosition, E_ACCESS_TYPE vAccessType)
etc.

Thumps up!

Edit:

Here's the updated code. I made some changes:
- it is now const-correct
- it uses Irrlichts types for POD data (u32 vs int)
- uses unsigned types vs signed types, this simplifies some checks
- i moved the E_ACCESS_TYPE enum inside the class
- the using namespace directive is bad, so removed them
- delete uv, to prevent memory leak in example code
- system("Pause"); doesn't work on Linux.

Code: Select all

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

// Unified Vertex class.
class UnifiedVertex
{
public:

	// Access types.
	enum E_ACCESS_TYPE
	{
		EAT_READ = 0,
		EAT_WRITE
	};

	// Constructor.
	UnifiedVertex(const irr::core::array<irr::u32>& vAttribute) :
		AttributesCount(vAttribute.size())
	{
		irr::u32 _Size = 0;

		// Allocate offsets array.
		Offset = new irr::u32[AttributesCount];

		for(irr::u32 i = 0; i < AttributesCount; ++i)
		{
			Offset[i] = vAttribute[i];
			_Size += Offset[i];
		}

		// Allocate memory for data.
		Data = new irr::u8[_Size];
	}

	// Constructor.
	UnifiedVertex(const irr::u32* vAttribute, const irr::u32 AttributeCount) :
		AttributesCount(AttributeCount)
	{
		irr::u32 _Size = 0;

		// Allocate offsets array.
		Offset = new irr::u32[AttributesCount];

		for(irr::u32 i = 0; i < AttributesCount; ++i)
		{
			Offset[i] = vAttribute[i];
			_Size += Offset[i];
		}

		// Allocate memory for data.
		Data = new irr::u8[_Size];
	}

	// Destructor.
	~UnifiedVertex()
	{
		// Release allocated memory.
		delete[] Offset;
		delete[] Data;
	}

	// Access to data (write or read selected attribute).
	bool accessAttribute(void* const vData, const irr::u32 vPosition, const E_ACCESS_TYPE& vAccessType) 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];

		// Write or read data.
		if(vAccessType == EAT_WRITE)
			memcpy((irr::u8*)Data + _Size, vData, Offset[vPosition]);
		else
			memcpy(vData, (irr::u8*)Data + _Size, 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 attributes count.
	irr::u32 getAttributesCount() const { return AttributesCount; }

private:

	// Data.
	irr::u8* Data;

	// Array with offsets sizes.
	irr::u32* Offset;

	// Attributes count.
	irr::u32 AttributesCount;
};

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> Attribute;
	Attribute.push_back(sizeof(irr::core::vector3df));
	Attribute.push_back(sizeof(irr::core::vector3df));
	Attribute.push_back(sizeof(irr::video::SColor));

	UnifiedVertex* const uv = new UnifiedVertex(Attribute);

	// Alternative method.
/*
    irr::u32 Attribute[3] =
    {
        sizeof(irr::core::vector3df),
        sizeof(irr::core::vector3df),
        sizeof(irr::video::SColor)
    };

    UnifiedVertex* const uv = new UnifiedVertex(Attribute, 3);
*/

	// Write attributes values.
	uv->accessAttribute(&Position0, 0, UnifiedVertex::EAT_WRITE);
	uv->accessAttribute(&Normal0, 1, UnifiedVertex::EAT_WRITE);
	uv->accessAttribute(&Color0, 2, UnifiedVertex::EAT_WRITE);

	// 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->accessAttribute(&PositionR, 0, UnifiedVertex::EAT_READ);
	uv->accessAttribute(&NormalR, 1, UnifiedVertex::EAT_READ);
	uv->accessAttribute(&ColorR, 2, UnifiedVertex::EAT_READ);

	// 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;

	return 0;
}


Posted: Sun May 09, 2010 2:18 pm
by Nadro
Thanks for interesting of this code. Improvments are very good, I thinked about it for final code version, but apply it to current version also is ok. Now, we can also remove casting to (irr::u8*) in memcpy code. What do You think about put the latest code at my first post? (if topic will be longer, searching the latest code will be waste of time). I put the latest code in first post, I also add getData function.

Now it's time for discussion about vertex type started by shadowslair, today I will prepare some code for it.

Posted: Sun May 09, 2010 2:30 pm
by Dorth
An unsigned vertex position?

Posted: Sun May 09, 2010 2:43 pm
by randomMesh
Dorth wrote:An unsigned vertex position?
Ok, storing the data this way is a problem indeed.

Code: Select all

irr::core::vector3df Position0(-123456789.4, -11.1, -12.1);
will output

Code: Select all

Position: -1.23457e+08, -11.1, -12.1
and -1.23457e+08 is −12345700000000.

Too bad. :cry:

But this hasn't got something to do with unsigned/signed, the original code shows the same problem.

Posted: Sun May 09, 2010 3:14 pm
by Nadro
@Dorth
What do You mean?

@randomMesh
Code is ok, You get the same effect when You call:

Code: Select all

irr::core::vector3df PositionTest(123456789.4,11.1,12.1);
std::cout << "Position: " << PositionTest.X << ", " << PositionTest.Y << ", " << PositionTest.Z << std::endl;
So data is store properly.

Posted: Sun May 09, 2010 3:17 pm
by randomMesh
Nadro wrote:Code is ok, You get the same effect when You call:

Code: Select all

irr::core::vector3df PositionTest(123456789.4,11.1,12.1);
std::cout << "Position: " << PositionTest.X << ", " << PositionTest.Y << ", " << PositionTest.Z << std::endl;
So data is store properly.
I am afraid it is not stored properly, since −12345700000000 is a different number than -123456789.4.

Posted: Sun May 09, 2010 3:41 pm
by Nadro
It's ok, this is cause by precision rounding (vector3d<f32>).

Posted: Sun May 09, 2010 6:36 pm
by sudi
Hey there seams to be an error in the code.

Code: Select all

bool accessAttribute(void* const vData, const irr::u32 vPosition, const E_ACCESS_TYPE& vAccessType) const 
this just seams wrong to me. correct me if i am.
when a function is declared const it means that it WON'T modify data of the object right? so this is wrong when u call the function with EAT_WRITE.

Then again "void* const vData" didn't try it but is there a difference between const void* and void* const? anyway writing to that data is actually not allowed.
EDIT: nevermind read it up....its a const pointer....totaly useless :D

while we are at it.
"const irr::u32 vPosition" should be "const irr::u32& vPosition"
"const irr::u32 AttributeCount" should be "const irr::u32& AttributeCount"
"irr::u32 getAttributesCount() const { return AttributesCount; } " should be "const irr::u32& getAttributesCount() const { return AttributesCount; } "

Posted: Sun May 09, 2010 6:40 pm
by randomMesh
Sudi wrote:is there a difference between const void* and void* const?
Of course.

Code: Select all

int* foo; //pointer to an int
const int* foo; //pointer to a constant int
int* const foo; //constant pointer to an int
const int* const foo; // constant pointer to a constant int
Sudi wrote: "const irr::u32 vPosition" should be "const irr::u32& vPosition"
"const irr::u32 AttributeCount" should be "const irr::u32& AttributeCount"
...
No. You don't need references when dealing with POT, only for own data types.
Sudi wrote: EDIT: nevermind read it up....its a const pointer....totaly useless :D
Being const-correct is not useless. :roll:

Posted: Sun May 09, 2010 6:44 pm
by sudi
yeah just found that same article...
randomMesh wrote: No. You don't need references when dealing with POT, only for own data types.
well when i don't use a reference then the const is pointless. i can't change the var from the outside anyway. ok i could change it inside the call but yeah...well

Posted: Sun May 09, 2010 6:49 pm
by sudi
randomMesh wrote:
Sudi wrote:is there a difference between const void* and void* const?
Being const-correct is not useless. :roll:
well but still the accessAttribute function shouldn't be const.