streams

posted in Programmology
Published January 05, 2006
Advertisement
I need your guys opinion on something.

I'm working on implementing a flexible vertex stream system. It should be easy to add different kinds of a data, and query for certain types of data (like normal, position, etc.).

It seems easy to create a VertexStreamList class that contains a list of VertexStream classes. Each VertexStream class holds a pointer to a buffer of data, and some data about the data (what kind of data is it? what format? etc). pretty simple.

About a year ago I wrote a vertexStreamList class that instead works with one large buffer, and when adding data it expands the buffer and copies the data. It holds a vector of list descriptions containing the offsets, as well as other data about the data. It would seem that this would be more efficient, the data would have better locality, etc.

But, thinking about it, that kind of breaks down if you do something complicated like use streams from one source, and a color stream from another source. The only real advantage is the "buffering" going on, and I'm just not sure it's worth it. It's also a lot slower to add and remove streams, and the code is much more complicated. Is that implementation worth looking into?

Since I've basically written the more complicated method, I'm thinking of doing both and profiling. But it's gonna be a slight pain to port old code to my new system.

Here's the code I wrote a year ago though, if anyone wants to look through it.

.h
#if !defined(H_DATABUFFER_)#define H_DATABUFFER_/*	Class: vertexStreamList	Created By: James Long	Date: 8/3/2004	Copyable: NO	Description:  This file defines the structures and functions that deal		with vertex streams. A stream is simply a list of data that defines an attribute of a vertex, like		position or normal.  Or it can define attributes about a whole geometric chunk.  The vertex stream		was the hardest to design it must support variable vertex types.  One stream might define the position		(3 floats), the normal (3 floats) and the color (3 floats) of an object.  Another stream might define		the position (2 floats), color (3 ubytes), and texcoords (2 floats).  The data in each stream must be		in one packed array, so we have to manage writing different varialbe sizes to the same array.  However,		all that must be transparent to the application.  It should be able to upload streams, and query them		back, possibly all back in one array.		The goal is to make it as simple and convienent as possible to declare and use streams.  This will be		done a TON in the program, so it should be as simple as possible.  If anything is annoying, it's having		to allocate memory yourself, fill in the array, figure out where to store it, and then when rendering,		hardcoding it to read from your data.  Don't forget to clean up the data when your done.		The class vertexStreamList and the helpful generic stream functions make it so simple.  If an object		needs to make a new vertex attribute, this is all it needs to do:						//in the object initialization...			vertexStreamList attributeList(numVerts); //This will probably be declared in a central location			floatStream normals;			streamAdd3f(normals, 0.0f, 0.0f, 0.0f);			streamAdd3f(normals, 0.0f, 1.0f, 0.0f);			streamAdd3f(normals, 0.0f, 5.0f, 2.3f);			//... and so on			attributeList.addStream(ATT_FLOAT, ATT_NORMAL, 3, normals);		Now that it's registered with the list, all you would need to is query for a stream if you need it:			//in the shader...			unsigned char *position = attributeList.getStream(ATT_POSITION);			//and now it can do whatever it needs to with the data		Note that this will be helpful in the shaders that construct the stream to send to the GPU.  They can		choose the required streams and go with it.		There is a lot more functionality within the vertexStreamList, including index management.  It should		be pretty self explanatory.		As far as the geometry streams go, it's not so different than vertex streams.  It is a whole lot simpler		though, as we are not dealing with massive amounts of data.  A chunk can register different float or		int values and register each one as a different usage type.  For example a chunk stream could be		ATT_SHININESS registered with the value 1.4f.  In the same way as the vertex stream, it's really easy		to query chunk attributes this way.  Simply use the getStream() function with the appropriate usage		type.		Limitations/Optimizations:			- Do NOT set one stream class equal to another (using the '=' operator).  This is not				implemented.			- Since every meshChunk will have a unique attributeList, there's no way to share buffers				between objects.  Once we get more experience, this might because useful for saving memory				with common buffers.  We might have to redesign this a little bit, but it shouldn't be				anything major.			- The functionality enforces unique usages, usages being one of position, color, normal, etc.				I don't see any reason why one meshChunk would need 2 buffers for color.  This would				totally confuse the shaders as, when looking for the color stream, it would find 2 streams				and have no idea which one to use.  I don't expect to ever account that.			- One main limitation is that interleaved data is not supported yet. We				definitely need to step back and think about how to design a system that supports that. Then				again, I'm waiting because we need more experience to judge if we should actually implement				it.  I'm pretty sure it'll be worth the effort though.			- I don't think this is a limitation, but it's important to note that each				attribute must have exactly the same number of elements.  It doesn't make much sense to have				different amounts of data when we are talking about the same vertices.  But who knows, maybe				that's a limitation of some sort.			- There are a lot of memcpy()'s in this code.  I don't think these functions should be called that				often, but if we find that they are, we might have to optimize this alot.  Optimization is				definitely possible here.  One way would be to not make a new list when removing streams.  We				could simply memmove() the affected data down the list.  We would have to keep track of the				buffer's full capacity, and when adding buffers, see if it can just memcpy() the new data				onto the top of the buffer.  	Definitions:		** Generic Streams **		enumeration streamType: Describes the type of data in one attribute (int, float, etc.)		typedef objSet typeStream: These typedefs make it easy to create and modify data.  Note that they			are simply objSet variables.			floatStream			ubyteStream			ushortStream			uintStream			intStream		functions : These are helpful functions that add elements to a stream for you to made code more readable.			streamAdd1f			streamAdd2f			streamAdd3f			streamAdd1i			streamAdd2i			streamAdd3i		** Vertex Streams **		enumeration vertexStreamUsage: Describes the intended usage of the attribute for a vertex. (for color, or position, etc.)		typedef struct vertexStreamDescription: Descrbes the stream for an attribute.  This includes information about			how it is going to be used, how it maps into the buffer reserved for the object, and a couple other things.		class vertexStreamList: Described thoroughly in the main description.  Basically is a container for			all of the attributes for one meshChunk.*//*	Generic stream declarations*/enum streamType {	ATT_UBYTE = GL_UNSIGNED_BYTE,	ATT_USHORT = GL_UNSIGNED_SHORT,	ATT_UINT = GL_UNSIGNED_INT,	ATT_INT = GL_INT,	ATT_FLOAT = GL_FLOAT};typedef objSet<float> floatStream;typedef objSet<int> intStream;typedef objSet<unsigned int> uintStream;typedef objSet<unsigned short> ushortStream;typedef objSet<unsigned char> ubyteStream;void streamAdd1f(floatStream &stream, const float x);void streamAdd2f(floatStream &stream, const float x, const float y);void streamAdd3f(floatStream &stream, const float x, const float y, const float z);void streamAdd1i(intStream &stream, const int x);void streamAdd2i(intStream &stream, const int x, const int y);void streamAdd3i(intStream &stream, const int x, const int y, const int z);void streamAdd1i(uintStream &stream, const unsigned int x);void streamAdd2i(uintStream &stream, const unsigned int x, const unsigned int y);void streamAdd3i(uintStream &stream, const unsigned int x, const unsigned int y, const unsigned int z);void streamAdd1i(ushortStream &stream, const unsigned short x);void streamAdd2i(ushortStream &stream, const unsigned short x, const unsigned short y);void streamAdd3i(ushortStream &stream, const unsigned short x, const unsigned short y, const unsigned short z);void streamAdd1i(ubyteStream &stream, const unsigned char x);void streamAdd2i(ubyteStream &stream, const unsigned char x, const unsigned char y);void streamAdd3i(ubyteStream &stream, const unsigned char x, const unsigned char y, const unsigned char z);/*	Vertex stream declaration*/enum vertexStreamUsage {	VERTEXATT_POSITION = 0x1<<0,	VERTEXATT_NORMAL = 0x1<<1,	VERTEXATT_DIFFUSE = 0x1<<2,	VERTEXATT_TEXCOORD0 = 0x1<<3,	VERTEXATT_TEXCOORD1 = 0x1<<4,	VERTEXATT_TEXCOORD2 = 0x1<<5,	VERTEXATT_TEXCOORD3 = 0x1<<6,};typedef struct {	unsigned int localOffset;	int videoMemOffset;	streamType type;	vertexStreamUsage usage;	unsigned char count;} vertexStreamDescription;class vertexStreamList {private:	objSet streams;public:	vertexStreamList();	vertexStreamList(const unsigned int vertexCount);	vertexStreamList(const unsigned int vertexCount, const unsigned int indexCount);	virtual ~vertexStreamList();	void setProperties(const unsigned int vertexCount, const unsigned int indexCount) {		numIndices = indexCount;		numVerts = vertexCount;	}	void clean();	// Index buffer management	void setNumIndices(const unsigned int count) { numIndices = count; }	unsigned int getNumIndices() { return numIndices; }	unsigned int getIndexBufferSize() {		switch(indexType) {			case ATT_USHORT: return numIndices*2;			case ATT_UINT: return numIndices*4;			default: return 0;		}	}	int setIndices(void *data, const streamType type);	unsigned char* getIndices() { return indexBuffer; }	void cleanIndices();	streamType getIndexType() { return indexType; }	void setIndexElement(const unsigned int index, const unsigned int value) {		if(!indexBuffer) return;		switch(indexType) {			case ATT_UBYTE: ((unsigned char*)indexBuffer)[index] = (unsigned char)value; break;			case ATT_USHORT: ((unsigned short*)indexBuffer)[index] = (unsigned short)value; break;			case ATT_UINT: ((unsigned int*)indexBuffer)[index] = (unsigned int)value; break;			default: break;		}	}	unsigned int getIndexElement(const unsigned int index) {		if(!indexBuffer) return 0;		if(index >= numIndices) return 1;		switch(indexType) {			case ATT_UBYTE: return ((unsigned char*)indexBuffer)[index];			case ATT_USHORT: return ((unsigned short*)indexBuffer)[index];			case ATT_UINT: return ((unsigned int*)indexBuffer)[index];			default: return 0;		}	}	void* getIndexVideoMemOffset();	int uploadIndices();	int requestVideoMemoryIndex(const unsigned int bufferSize);	void releaseVideoMemoryIndex();	void lockVideoMemoryIndex();	void unlockVideoMemoryIndex();	// Vertex buffer management	void setNumVertices(const unsigned int count) { numVerts = count; }	unsigned int getNumVerts() { return numVerts; }	unsigned int getVertexBufferSize() { return vertexBufferSize; }	unsigned char * const getVertexBuffer() { return vertexBuffer; }	int addStream(const streamType _type, const vertexStreamUsage _usage, const unsigned char _count, void *data);	int removeStream(const vertexStreamUsage _usage);	void cleanVertices();	unsigned char findStream(const vertexStreamUsage _usage) {		for(unsigned int i=0; i			if(streams.usage == _usage) return 1;		}		return 0;	}	unsigned char* getStream(const vertexStreamUsage _usage);	unsigned int getStreamCount() { return streams.count(); }	unsigned int getStreamBufferSize(const vertexStreamUsage _usage);	unsigned int getStreamOffset(const vertexStreamUsage _usage) {		unsigned int i;		for(i=0; i			if(streams.usage == _usage)				break;		}		if(i == streams.count()) return 0;		return streams.localOffset;	}	void* getStreamVideoMemOffset(const vertexStreamUsage _usage);	unsigned char getStreamElementCount(const vertexStreamUsage _usage) {		unsigned int i;		for(i=0; i			if(streams.usage == _usage)				break;		}		if(i == streams.count()) return 0;		return streams.count;	}	streamType getStreamElementType(const vertexStreamUsage _usage) {		unsigned int i;		for(i=0; i			if(streams.usage == _usage)				break;		}		if(i == streams.count()) return ATT_UBYTE;		return streams.type;	}		int uploadStreams(const unsigned int attributeFlags);	int uploadStream(const vertexStreamUsage _usage);	int verticesUploaded(const unsigned int attributeFlags) {		return !(~uploadedStreams & attributeFlags);		//return (vBlock || 0);	}	int indicesUploaded() {		return (iBlock || 0);	}	int requestVideoMemoryVertex(const unsigned int bufferSize);	void releaseVideoMemoryVertex();	void lockVideoMemoryVertex();	void unlockVideoMemoryVertex();private:	unsigned char *indexBuffer;	streamType indexType;	unsigned int numIndices;	unsigned char *vertexBuffer;	unsigned int vertexBufferSize;	unsigned int numVerts;	videoMemoryBlock *vBlock;	videoMemoryBlock *iBlock;	unsigned int uploadedStreams;};#endif


.cpp
#include "stdinc.h"/*	Generic stream implementation*/void streamAdd1f(floatStream &stream, const float x) { stream.add(x); }void streamAdd2f(floatStream &stream, const float x, const float y) { stream.add(x); stream.add(y); }void streamAdd3f(floatStream &stream, const float x, const float y, const float z) { stream.add(x); stream.add(y); stream.add(z); }void streamAdd1i(intStream &stream, const int x) { stream.add(x); }void streamAdd2i(intStream &stream, const int x, const int y) { stream.add(x); stream.add(y); }void streamAdd3i(intStream &stream, const int x, const int y, const int z) { stream.add(x); stream.add(y); stream.add(z); }void streamAdd1i(uintStream &stream, const unsigned int x) { stream.add(x); }void streamAdd2i(uintStream &stream, const unsigned int x, const unsigned int y) { stream.add(x); stream.add(y); }void streamAdd3i(uintStream &stream, const unsigned int x, const unsigned int y, const unsigned int z) { stream.add(x); stream.add(y); stream.add(z); }void streamAdd1i(ushortStream &stream, const unsigned short x) { stream.add(x); }void streamAdd2i(ushortStream &stream, const unsigned short x, const unsigned short y) { stream.add(x); stream.add(y); }void streamAdd3i(ushortStream &stream, const unsigned short x, const unsigned short y, const unsigned short z) { stream.add(x); stream.add(y); stream.add(z); }void streamAdd1i(ubyteStream &stream, const unsigned char x) { stream.add(x); }void streamAdd2i(ubyteStream &stream, const unsigned char x, const unsigned char y) { stream.add(x); stream.add(y); }void streamAdd3i(ubyteStream &stream, const unsigned char x, const unsigned char y, const unsigned char z) { stream.add(x); stream.add(y); stream.add(z); }/*	Vertex stream implementation*/vertexStreamList::vertexStreamList() : indexBuffer(NULL), numIndices(0), vertexBuffer(NULL), numVerts(0), vertexBufferSize(0), vBlock(NULL), iBlock(NULL), uploadedStreams(0) {}vertexStreamList::vertexStreamList(const unsigned int vertexCount) : indexBuffer(NULL), numIndices(0), vertexBuffer(NULL), numVerts(vertexCount), vertexBufferSize(0), vBlock(NULL), iBlock(NULL), uploadedStreams(0) {}vertexStreamList::vertexStreamList(const unsigned int vertexCount, const unsigned int indexCount) : indexBuffer(NULL), numIndices(indexCount), vertexBuffer(NULL), numVerts(vertexCount), vertexBufferSize(0), vBlock(NULL), iBlock(NULL), uploadedStreams(0) {}vertexStreamList::~vertexStreamList() {	resourceMGR->freeVertexMemoryBlock(vBlock);	resourceMGR->freeIndexMemoryBlock(iBlock);	SafeDeleteArr(vertexBuffer);	SafeDeleteArr(indexBuffer);}void vertexStreamList::clean() {	cleanIndices();	cleanVertices();}void vertexStreamList::cleanIndices() {	SafeDeleteArr(indexBuffer);}void vertexStreamList::cleanVertices() {	SafeDeleteArr(vertexBuffer);	vertexBufferSize = 0;	streams.clear();}int vertexStreamList::setIndices(void *data, const streamType type) {	if(!numIndices) return 1;	if(indexBuffer) SafeDeleteArr(indexBuffer);	unsigned int indexBufferSize;	switch(type) {		case ATT_UBYTE: indexBufferSize = numIndices * sizeof(unsigned char); break;		case ATT_USHORT: indexBufferSize = numIndices * sizeof(unsigned short); break;		case ATT_UINT: indexBufferSize = numIndices * sizeof(unsigned int); break;		default: return 3;	}		indexBuffer = new unsigned char[indexBufferSize];	memcpy(indexBuffer, data, indexBufferSize);	indexType = type;	return 0;}int vertexStreamList::addStream(const streamType _type, const vertexStreamUsage _usage, const unsigned char _count, void *data) {	if(!data) { printErrorMessage("Error adding stream - data is NULL"); return 1; }	if(!numVerts) { printErrorMessage("Error adding stream - number of vertices not defined"); return 2; }	if(findStream(_usage)) { printErrorMessage("Error adding stream - usage already exists"); return 3; }	vertexStreamDescription newStream;	newStream.count = _count;	newStream.type = _type;	newStream.usage = _usage;	newStream.localOffset = vertexBufferSize;	newStream.videoMemOffset = -1;	unsigned int newDataSize;	switch(newStream.type) {		case ATT_UBYTE: newDataSize = numVerts*newStream.count*sizeof(unsigned char); break;		case ATT_USHORT: newDataSize = numVerts*newStream.count*sizeof(unsigned short); break;		case ATT_UINT: newDataSize = numVerts*newStream.count*sizeof(unsigned int); break;		case ATT_INT: newDataSize = numVerts*newStream.count*sizeof(int); break;		case ATT_FLOAT: newDataSize = numVerts*newStream.count*sizeof(float); break;	}	unsigned char *newData = new unsigned char[vertexBufferSize+newDataSize];	memcpy(newData, vertexBuffer, vertexBufferSize); 	memcpy(newData+vertexBufferSize, data, newDataSize);	SafeDeleteArr(vertexBuffer);	vertexBuffer = newData;	vertexBufferSize += newDataSize;	streams.add(newStream);	return 0;        }int vertexStreamList::removeStream(const vertexStreamUsage _usage) {	if(!findStream(_usage)) { printWarningMessage("Error removing stream - usage doesn't exist"); return 1; }	if(streams.count() == 1) {		SafeDeleteArr(vertexBuffer);		streams.clear();		vertexBufferSize = 0;		return 0;	}	unsigned int i;	unsigned int attBufferSize;	unsigned char *newData;	//Find the stream's index	for(i=0; i		if(streams.usage == _usage)			break;	}	if(i == streams.count()) return 1;	//Calculate the stream's buffer size	attBufferSize = getStreamBufferSize(streams.usage);	//Update the vertex buffer	newData = new unsigned char[vertexBufferSize-attBufferSize];	memcpy(newData, vertexBuffer, streams.localOffset);	memcpy(newData+streams.localOffset, vertexBuffer+streams.localOffset+attBufferSize, vertexBufferSize - (streams.localOffset+attBufferSize));	SafeDeleteArr(vertexBuffer);	vertexBuffer = newData;	//Update the buffer size	vertexBufferSize = vertexBufferSize - attBufferSize;	//Update the affected streams	for(unsigned int j=0; j		if(streams[j].localOffset > streams.localOffset) {			streams[j].localOffset -= attBufferSize;		}	}	//Update the stream list	streams.remove(i);	return 0;}unsigned char* vertexStreamList::getStream(const vertexStreamUsage _usage) {	unsigned int i;	for(i=0; i		if(streams.usage == _usage)			break;	}	if(i == streams.count()) return NULL;	return vertexBuffer+streams.localOffset;}unsigned int vertexStreamList::getStreamBufferSize(const vertexStreamUsage _usage) {	unsigned int i;	for(i=0; i		if(streams.usage == _usage)			break;	}	if(i == streams.count()) return 0;	switch(streams.type) {		case ATT_UBYTE: return numVerts*streams.count*sizeof(unsigned char);		case ATT_USHORT: return numVerts*streams.count*sizeof(unsigned short);		case ATT_UINT: return numVerts*streams.count*sizeof(unsigned int);		case ATT_INT: return numVerts*streams.count*sizeof(int);		case ATT_FLOAT: return numVerts*streams.count*sizeof(float);		default:	break;	}	return 0;}int vertexStreamList::uploadStreams(const unsigned int attributeFlags) {	unsigned int bufferSize = 0;	unsigned int i;	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		for(i=0; i			if(streams.usage & attributeFlags)				bufferSize += getStreamBufferSize(streams.usage);		}		if(!vBlock) {			if(requestVideoMemoryVertex(bufferSize)) return 1;		}		else if(bufferSize > vBlock->capacity) {			releaseVideoMemoryVertex();			if(requestVideoMemoryVertex(bufferSize)) return 1;		}		else {			lockVideoMemoryVertex();		}				for(i=0; i			if((attributeFlags & streams.usage) && !(uploadedStreams & streams.usage)) {				if(uploadStream(streams.usage)) {					printErrorMessage("Failed uploading stream.");				}				else {					uploadedStreams |= streams.usage;				}			}			else {				printWarningMessage("Didn't upload stream, it's already uploaded.");			}		}		unlockVideoMemoryVertex();	}	return 0;}int vertexStreamList::uploadStream(const vertexStreamUsage _usage) {	unsigned int i;	for(i=0; i		if(streams.usage == _usage)			break;	}	if(i == streams.count()) return 1;	unsigned int bufferSize;  	switch(streams.type) {		case ATT_UBYTE: bufferSize = numVerts*streams.count*sizeof(unsigned char); break;		case ATT_USHORT: bufferSize = numVerts*streams.count*sizeof(unsigned short); break;		case ATT_UINT: bufferSize = numVerts*streams.count*sizeof(unsigned int); break;		case ATT_INT: bufferSize = numVerts*streams.count*sizeof(int); break;		case ATT_FLOAT: bufferSize = numVerts*streams.count*sizeof(float); break;		default:	break;	}	if(!vBlock && !vBlock->buffer) return 2;  //there is no video block or it has not been locked	if(streams.videoMemOffset >= 0) return 3;  //this stream has already been uploaded	if(vBlock->numFilled+bufferSize > vBlock->capacity)		return 4;  //this video block is out of memory	memcpy(vBlock->buffer + vBlock->numFilled, vertexBuffer + streams.localOffset, bufferSize);	streams.videoMemOffset = vBlock->numFilled;	vBlock->numFilled += bufferSize;		return 0;}void* vertexStreamList::getStreamVideoMemOffset(const vertexStreamUsage _usage) {	unsigned int i;	for(i=0; i		if(streams.usage == _usage)			break;	}	if(i == streams.count()) return 0;	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		if(!vBlock) return NULL;  //doesn't have an associated video memory block		if(streams.videoMemOffset < 0) return NULL;  //stream hasn't been uploaded		return (char*)NULL + streams.videoMemOffset + vBlock->offset;	}	else {		return vertexBuffer + streams.localOffset;	}}int vertexStreamList::requestVideoMemoryVertex(const unsigned int bufferSize) {	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		if(vBlock) {			printWarningMessage("Vertex video memory block has already been assigned.");			return 1;		}		if(!(vBlock = resourceMGR->lockVideoMemoryVertex(bufferSize))) {			printErrorMessage("Request for vertex memory block failed.");			return 1;		}		vBlock->mc = this;	}	return 0;}void vertexStreamList::releaseVideoMemoryVertex() {	vBlock = NULL;	for(unsigned int i=0; i		streams.videoMemOffset = -1;}void vertexStreamList::lockVideoMemoryVertex() {	if(vBlock) {		resourceMGR->lockVideoMemoryVertex(vBlock);	}}void vertexStreamList::unlockVideoMemoryVertex() {	if(vBlock) {		resourceMGR->unlockVideoMemoryVertex(vBlock);	}}int vertexStreamList::uploadIndices() {	if(!indexBuffer) return 1;	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		unsigned int bufferSize = getIndexBufferSize();		if(!iBlock) {			if(requestVideoMemoryIndex(bufferSize)) return 1;		}		else {			lockVideoMemoryIndex();		}				memcpy(iBlock->buffer, indexBuffer, bufferSize);		unlockVideoMemoryIndex();	}	return 0;}void* vertexStreamList::getIndexVideoMemOffset() {	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		if(!iBlock) return NULL;		return (char*)NULL + iBlock->offset;	}	else {		return indexBuffer;	}}int vertexStreamList::requestVideoMemoryIndex(const unsigned int bufferSize) {	if(resourceMGR->isExtensionSupported(EXTENSION_VBO)) {		if(iBlock) {			printWarningMessage("Index video memory block has already been assigned.");			return 1;		}		if(!(iBlock = resourceMGR->lockVideoMemoryIndex(bufferSize))) {			printErrorMessage("Request for index memory block failed.");			return 1;		}		iBlock->mc = this;	}	return 0;}void vertexStreamList::releaseVideoMemoryIndex() {	iBlock = NULL;}void vertexStreamList::lockVideoMemoryIndex() {	if(iBlock) {		resourceMGR->lockVideoMemoryIndex(iBlock);	}}void vertexStreamList::unlockVideoMemoryIndex() {	if(iBlock) {		resourceMGR->unlockVideoMemoryIndex(iBlock);	}}	// NOTE:  I coded these functions, but it is not recommended for use.  Use the getStream function	//			and use the stream directly.  These functions are slow and useless, but I don't want to delete it yet.	//unsigned char* vertexStreamList::getStreams(unsigned int _usageFlags) {	//	if(!_usageFlags) _usageFlags = ~_usageFlags;	//	//	unsigned int newBufferSize = 0;	//	for(unsigned int i=0; i	//		if(streams.usage & _usageFlags) {	//			newBufferSize += getStreamBufferSize(streams.usage);	//		}	//	}	//	//	unsigned char *buffer = new unsigned char[newBufferSize];	//	unsigned int bufferIndex = 0;	//	for(unsigned int i=0; i	//		if(streams.usage & _usageFlags) {	//			unsigned int bufferSize = getStreamBufferSize(streams.usage);	//			memcpy(buffer+bufferIndex, vertexBuffer+streams.localOffset, bufferSize);	//			bufferIndex += bufferSize;	//		}	//	}	//	return buffer;	//}	//float getStreamElement(const vertexStreamUsage _usage, const unsigned int index) {	//	for(unsigned int i=0; i	//		if(streams.usage == _usage)	//			break;	//	}	//	if(i == streams.count()) return 0.0f;	//	switch(streams.type) {	//		case ATT_UBYTE: *((unsigned char*)(vertexBuffer + streams.localOffset) + index*streams.count); break;	//		case ATT_USHORT: *((unsigned short*)(vertexBuffer + streams.localOffset) + index*streams.count); break;	//		case ATT_UINT: *((unsigned int*)(vertexBuffer + streams.localOffset) + index*streams.count); break;	//		case ATT_INT: *((int*)(vertexBuffer + streams.localOffset) + index*streams.count); break;	//		case ATT_FLOAT: *((float*)(vertexBuffer + streams.localOffset) + index*streams.count); break;	//		default: return 0.0f;	//	}	//}


Note that this is rather old code and does not reflect at all my current coding techniques... I've long since moved to STL and other better programming techniques.
Previous Entry christmas cookies
0 likes 1 comments

Comments

NickGeorgia
It's all STL to me (notice my attempt at being funny).
January 05, 2006 11:21 PM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement
Advertisement