Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    73
  • comments
    131
  • views
    55000

streams

Sign in to follow this  
okonomiyaki

351 views

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.
Sign in to follow this  


1 Comment


Recommended Comments

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!