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.
Post Reply
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

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

Post 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/
Last edited by Nadro on Tue Mar 13, 2012 10:15 pm, edited 23 times in total.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
shadowslair
Posts: 758
Joined: Mon Mar 31, 2008 3:32 pm
Location: Bulgaria

Post 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)
"Although we walk on the ground and step in the mud... our dreams and endeavors reach the immense skies..."
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Re: Flexible Vertex Format

Post 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.
"Whoops..."
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post 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
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post 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;
}

"Whoops..."
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post 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.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
Dorth
Posts: 931
Joined: Sat May 26, 2007 11:03 pm

Post by Dorth »

An unsigned vertex position?
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post 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.
"Whoops..."
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post 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.
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post 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.
"Whoops..."
Nadro
Posts: 1648
Joined: Sun Feb 19, 2006 9:08 am
Location: Warsaw, Poland

Post by Nadro »

It's ok, this is cause by precision rounding (vector3d<f32>).
Library helping with network requests, tasks management, logger etc in desktop and mobile apps: https://github.com/GrupaPracuj/hermes
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post 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; } "
Last edited by sudi on Sun May 09, 2010 6:43 pm, edited 1 time in total.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
randomMesh
Posts: 1186
Joined: Fri Dec 29, 2006 12:04 am

Post 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:
Last edited by randomMesh on Sun May 09, 2010 6:46 pm, edited 2 times in total.
"Whoops..."
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post 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
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
sudi
Posts: 1686
Joined: Fri Aug 26, 2005 8:38 pm

Post 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.
We're programmers. Programmers are, in their hearts, architects, and the first thing they want to do when they get to a site is to bulldoze the place flat and build something grand. We're not excited by renovation:tinkering,improving,planting flower beds.
Post Reply