Jump to content

  • Log In with Google      Sign In   
  • Create Account


Nimajecyrb

Member Since 11 Nov 2010
Offline Last Active Jun 08 2014 08:41 PM
-----

Topics I've Started

Index Buffer Object vs. Index Array

05 June 2013 - 07:43 PM

After writing some code to load a 3ds mesh (using lib3ds) I found that rendering using indices caused problems, at least for me. After storing all the vertex data into one array. I divide each lib3dsMesh into my own Submesh subclass which stores index data.

 

My question is what are (if any) the performance differences in storing index data in an array and using it to call glDrawElements:


 

GLuint* indices;
void draw()
{
   ...
  glDrawElements(GL_TRIANGLES, submesh.i_data.size(), GL_UNSIGNED_SHORT, &indices[0]);
  ...
}
 

 

And using a BufferObject to store them

 

GLuint* indices;
...Fill array...

void build()
{
    glGenBuffers(1,&ibo);
    ...Fill buffer...
}

void draw()
{
  glBindBuffer(GL_ELEMENT_ARRAY,...);
   ...
  glDrawElements(GL_TRIANGLES, submesh.i_data.size(), GL_UNSIGNED_SHORT, <submesh offset>);
  ...
}

 

 

 


Allocator crash after alloc/dealloc

30 December 2012 - 10:58 PM

As a learning exercise I wrote my own version of several STL components, this allocator generally works however while I was testing particles with it, it crashes after a variable number of iterations with alloc's and dealloc's . I've been playing with the code for ours and I'm sure there's something I'm doing wrong. Perhaps someone can point it out to me.

 

During the loop, I save the address of particles that will need to be dealloc'd in a vector, then later dealloc the pointers.

 


The problem always occurs with a segfault at ln. 76 and happens because the MemChunk's pointers point to memory that looks like it should be NULL but is something like 0x1, 0x5, etc.

 

 

This is the allocator's code

template<class T = void>
class PoolAllocator: public AllocBase<T>
{
public:
	typedef typename AllocBase<T>::AllocType AllocType;
	typedef typename AllocBase<T>::AllocTypePtr AllocTypePtr;

	PoolAllocator(size_t sizeInUnits = 1024) :
			mMemory(NULL), mUsedSize(0), mMaxSize(sizeInUnits), mOffset(
					sizeof(MemChunk) + sizeof(T))
	{
		mMemory = new (std::nothrow) char[mMaxSize * mOffset];
		// mMemory = malloc(mMaxSize * mOffset);
		if (!mMemory)
		{
			//Do something more informational here
			throw std::bad_alloc();
			return;
		}

		for (size_t i = 0; i < mMaxSize; i++)
		{
			MemChunk *pCurUnit = (MemChunk *) ((char *) mMemory + i * mOffset);

			pCurUnit->mPrevChunk = mFreeList.mLast;
			pCurUnit->mNextChunk = NULL;

			if (mFreeList.mLast)
				mFreeList.mLast->mNextChunk = pCurUnit;
			mFreeList.mLast = pCurUnit;

			if (!mFreeList.mFirst)
				mFreeList.mFirst = pCurUnit;
		}

	}

	virtual ~PoolAllocator()
	{
		delete[] mMemory;
	}

	template<typename T1>
	struct rebind
	{
		typedef PoolAllocator<T1> other;
	};

	struct MemChunk
	{
		MemChunk* mNextChunk, *mPrevChunk;
	};

	struct ChunkList
	{
		ChunkList() :
				mFirst(0), mLast(0)
		{
		}
		MemChunk* mFirst, *mLast;
	};

	virtual AllocTypePtr allocate(size_t n, const AllocTypePtr = 0)
	{

		if ((mUsedSize + n) > (mMaxSize))
			_resize((mUsedSize * mOffset) + (mOffset * n) * 2);

		//Get the last chunk of unused memory
		MemChunk* pCurChunk = mFreeList.mLast;

		if (mFreeList.mFirst == pCurChunk)
			mFreeList.mFirst = pCurChunk->mNextChunk;

		//This shouldn't happen, since it's the back of the free list
		if (pCurChunk->mNextChunk)
			pCurChunk->mNextChunk->mPrevChunk = pCurChunk->mPrevChunk;

		//This should only _not_ happen if this is the last available piece of memory
		//When it does, the value of pCurChunk->mNextChunk should be NULL
		if (pCurChunk->mPrevChunk)
			pCurChunk->mPrevChunk->mNextChunk = NULL;

		//Set the new value of the last chunk in the free list
		mFreeList.mLast = pCurChunk->mPrevChunk;

		//Place it at the end of the AllocList
		pCurChunk->mPrevChunk = mAllocList.mLast;
		pCurChunk->mNextChunk = NULL;

		if (mAllocList.mLast)
			mAllocList.mLast->mNextChunk = pCurChunk;

		mAllocList.mLast = pCurChunk;
		if (!mAllocList.mFirst)
			mAllocList.mFirst = pCurChunk;

		mUsedSize += 1;

		return reinterpret_cast<AllocTypePtr>((reinterpret_cast<char*>(pCurChunk) + sizeof(MemChunk)));
	}

	//Returns a pointer to the memory at a specific offset. Do NOT modify this pointer
	inline const AllocTypePtr getPtr(unsigned i) const
	{
		return reinterpret_cast<AllocTypePtr>(reinterpret_cast<char*>(mAllocList.mFirst)
				- (mOffset * i) + sizeof(MemChunk));
	}

	virtual void dealloc(AllocTypePtr ptr, size_t = 0)
	{
		MemChunk *pCurChunk = (MemChunk*) ((char*) ptr - sizeof(MemChunk));

		std::cout << pCurChunk << "\n";
		//Remove the chunk from the AllocList
		if (pCurChunk->mNextChunk)
			pCurChunk->mNextChunk->mPrevChunk = pCurChunk->mPrevChunk;

		if (pCurChunk->mPrevChunk)
			pCurChunk->mPrevChunk->mNextChunk = pCurChunk->mNextChunk;

		if (mAllocList.mLast == pCurChunk)
			mAllocList.mLast = pCurChunk->mPrevChunk;

		if (mAllocList.mFirst == pCurChunk)
			mAllocList.mFirst = pCurChunk->mNextChunk;

		//Put it back on the FreeList
		pCurChunk->mPrevChunk = mFreeList.mLast;
		pCurChunk->mNextChunk = NULL;

		if (mFreeList.mLast)
			mFreeList.mLast->mNextChunk = pCurChunk;

		mFreeList.mLast = pCurChunk;

		if (!mFreeList.mFirst)
			mFreeList.mFirst = pCurChunk;

		mUsedSize -= 1;

	}
protected:

	/*
	 * NOTE: This is a slow operation and can be avoided by preallocating enough memory
	 * to hold your data.
	 */
	void _resize(unsigned size)
	{
		//Simple array reallocation
		size_t newSize = size;
		char* newArr = new (std::nothrow) char[newSize * mOffset];

		for (unsigned counter = 0; counter < mUsedSize; ++counter)
			newArr[counter] = mMemory[counter];

		//memcpy(newArr, mMemory, mMaxSize * mOffset);

		mMaxSize = newSize;

		delete[] mMemory;

		mMemory = newArr;

		//Relink the list
		for (size_t i = 0; i < mMaxSize; i++)
		{
			MemChunk *pCurUnit = (MemChunk *) ((char *) mMemory + i * mOffset);

			pCurUnit->mPrevChunk = mFreeList.mLast;
			pCurUnit->mNextChunk = NULL;

			if (mFreeList.mLast)
				mFreeList.mLast->mNextChunk = pCurUnit;

			mFreeList.mLast = pCurUnit;

			if (!mFreeList.mFirst)
				mFreeList.mFirst = pCurUnit;
		}
	}

protected:
	char* mMemory; //The big chunk of allocated memory from the OS

	ChunkList mFreeList;
	ChunkList mAllocList;

	size_t mUsedSize; //current used size in chunks
	size_t mMaxSize; //peak size in chunks
	size_t mOffset; //The total step in memory from one chunk to another (also equal to the sizeof(MemChunk) + sizeof(T))

};

 

Here is the loop

for (unsigned i = 0; i < mNumParticles; i++)
	{
		// Check particle's lifespan
		//Particle* pTemp = reinterpret_cast<Particle*>(mBuffer) + i;
		Particle* pTemp = mAllocator.getPtr(i);

		if (pTemp->m_Life-- < 0)
		{
			//Keep up with the particles to delete
			m_ParticleList.push_back(pTemp);
			continue;
		}

		// Update particle's position
		pTemp->m_Position.fX += pTemp->m_Velocity.fX;
		pTemp->m_Position.fY += pTemp->m_Velocity.fY;

		glColor3f(float(pTemp->m_Colour.r) / 255, float(pTemp->m_Colour.g) / 255,
				float(pTemp->m_Colour.b) / 255);
		glVertex2fv(pTemp->m_Position.ptr());
	}

	bool clear = false;
	for (unsigned i = 0; i < m_ParticleList.size(); i++)
	{
		Particle* p = m_ParticleList[i];

		mAllocator.destroy(p);
		mAllocator.dealloc(p);

		mNumParticles--;
		clear = true;
	}

	if (clear)
		m_ParticleList.clear();

	// If there are less particles than the maximum allowed create another
	if (mNumParticles < m_MaxParticles)
		createParticles(m_MaxParticles - mNumParticles);

the createParticles method calls allocate.


Resorting binary heaps

10 December 2011 - 01:59 AM

I have a minimum ordered binary heap. (I'm using A* pathfinding) at one point or another I come to a point where I must modify a node that may or may not be the top or bottom of the tree.
How would I go about resorting the entire array (since, I don't know the exact position within the heap of the node i modified)?

Data transfer into VBO

22 February 2011 - 06:18 AM

I've had working VBOs for a while now. And Now im trying to load a terrain into and array of heights and then load them into my vertex structure to be rendered from the VBO, however when i run the code in immediate mode, it looks good and when its through the VBO. All the points don't connect.

In immediate mode this is the code

for (int i = 0; i < terrainGridLength - 1; i++)
				{
					glBegin(GL_TRIANGLE_STRIP);
					for (int j = 0; j < terrainGridWidth; j++)
					{
						glVertex3f(startW + j + xOffset, mHeights[(i + 1)
						        * terrainGridWidth + (j)] + yOffset, startL - (i + 1)
						        + zOffset);

						glVertex3f(startW + j + xOffset, mHeights[(i) * terrainGridWidth
						        + j] + yOffset, startL - i + zOffset);
					}
					glEnd();
				}


But if I transfer the data with this

//Now lets copy the terrain data into our vertex structure so we can render;
		for (int i = 0, marker = 0; i < mWidth; i++)
		{
			for (int j = 0; j < mHeight; j++, marker++)
			{

				mVertexData[marker].positions[0] = startW + j + xOffset;
				mVertexData[marker].positions[1] = mHeights[(i + 1) * terrainGridWidth
				        + (j)] + yOffset;
				mVertexData[marker].positions[2] = startL - (i + 1) + zOffset;

				mVertexData[marker + 1].positions[0] = startW + j + xOffset;

				mVertexData[marker + 1].positions[1] = mHeights[(i) * terrainGridWidth
				        + j] + yOffset;
				mVertexData[marker + 1].positions[2] = startL - i + zOffset;
			}
		}

I fail to see the difference rendering with:

mVBO->Bind();
		// Set the state of what we are drawing (I don't think order matters here, but I like to do it in the same
		// order I set the pointers
		glEnableClientState(GL_TEXTURE_COORD_ARRAY);
		glEnableClientState(GL_COLOR_ARRAY);
		glEnableClientState(GL_NORMAL_ARRAY);
		glEnableClientState(GL_VERTEX_ARRAY);

		// Resetup our pointers. This doesn't reinitialise any data, only how we walk through it
		glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
		glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
		glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
		glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));

		glDrawArrays(GL_TRIANGLE_STRIP, 0, mTerrainSize);

		// Disable our client state back to normal drawing
		glDisableClientState(GL_TEXTURE_COORD_ARRAY);
		glDisableClientState(GL_COLOR_ARRAY);
		glDisableClientState(GL_NORMAL_ARRAY);
		glDisableClientState(GL_VERTEX_ARRAY);

		mVBO->disable();


Any thoughts ?

Wavefront .Obj File Rendering

20 February 2011 - 10:11 PM

I've been working for about the past week attempting to write a parser for the .obj format. My engine already supports a custom type of file format so my idea was to simply try and convert the .obj into the type that my engine recognizes and can load and render.

So the example file is a file called xmas-ball.obj
http://pastebin.com/RKbQTX5R

And when converted to my format its something like this
http://pastebin.com/EcxqV5bM


The file format is simple. First it writes the vertex x,y,z followed by its normal x,y,z and texture coords u,v. Then at the bottom is a list of vertex indices.

Problem is something isn't right with the indices so that when rendered with GL_TRIANGLES (or any other variation) it becomes a big mess of connected points.

i.e.

Posted Image
However when rendered with GL_POINTS you can see what it should look like. That tells me that the vertices are right.

i.e.

Posted Image
The question is how to extract the indices (I just take the first from every triplet or duplet) so that they are pointing to the right vertices?

PARTNERS