1
1
forked from 0ad/0ad

Initial revision.

This was SVN commit r410.
This commit is contained in:
notpete 2004-06-07 19:52:37 +00:00
parent bd0d3e1c36
commit 4f8ce4b1d4
4 changed files with 389 additions and 0 deletions

184
source/renderer/VertexBuffer.cpp Executable file
View File

@ -0,0 +1,184 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: VertexBuffer.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include "ogl.h"
#include "Renderer.h"
#include "VertexBuffer.h"
///////////////////////////////////////////////////////////////////////////////
// shared list of all free batch objects
std::vector<CVertexBuffer::Batch*> CVertexBuffer::m_FreeBatches;
///////////////////////////////////////////////////////////////////////////////
// CVertexBuffer constructor
CVertexBuffer::CVertexBuffer(size_t vertexSize,bool dynamic)
: m_VertexSize(vertexSize), m_Dynamic(dynamic), m_SysMem(0), m_Handle(0)
{
// store max/free vertex counts
m_MaxVertices=m_FreeVertices=MAX_VB_SIZE_BYTES/vertexSize;
// allocate raw buffer
if (g_Renderer.m_Caps.m_VBO) {
glGenBuffersARB(1,&m_Handle);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
glBufferDataARB(GL_ARRAY_BUFFER_ARB,MAX_VB_SIZE_BYTES,0,m_Dynamic ? GL_STREAM_DRAW_ARB : GL_STATIC_DRAW_ARB);
} else {
m_SysMem=new u8[MAX_VB_SIZE_BYTES];
}
// create sole free chunk
VBChunk* chunk=new VBChunk;
chunk->m_Owner=this;
chunk->m_Count=m_FreeVertices;
chunk->m_Index=0;
m_FreeList.push_front(chunk);
}
///////////////////////////////////////////////////////////////////////////////
// CVertexBuffer destructor
CVertexBuffer::~CVertexBuffer()
{
if (m_Handle) {
glDeleteBuffersARB(1,&m_Handle);
} else if (m_SysMem) {
delete[] m_SysMem;
}
}
///////////////////////////////////////////////////////////////////////////////
// Allocate: try to allocate a buffer of given number of vertices (each of
// given size), with the given type, and using the given texture - return null
// if no free chunks available
CVertexBuffer::VBChunk* CVertexBuffer::Allocate(size_t vertexSize,size_t numVertices,bool dynamic)
{
// check this is the right kind of buffer
if (dynamic!=m_Dynamic || vertexSize!=m_VertexSize) return 0;
// quick check there's enough vertices spare to allocate
if (numVertices>m_FreeVertices) return 0;
// trawl free list looking for first free chunk with enough space
VBChunk* chunk=0;
typedef std::list<VBChunk*>::iterator Iter;
for (Iter iter=m_FreeList.begin();iter!=m_FreeList.end();++iter) {
chunk=*iter;
if (numVertices<=chunk->m_Count) {
// remove this chunk from the free list
size_t size1=m_FreeList.size();
m_FreeList.erase(iter);
size_t size2=m_FreeList.size();
// no need to search further ..
break;
}
}
if (!chunk) {
// no big enough spare chunk available
return 0;
}
// split chunk into two; - allocate a new chunk using all unused vertices in the
// found chunk, and add it to the free list
VBChunk* newchunk=new VBChunk;
newchunk->m_Owner=this;
newchunk->m_Count=chunk->m_Count-numVertices;
newchunk->m_Index=chunk->m_Index+numVertices;
m_FreeList.push_front(newchunk);
// resize given chunk, resize total available free vertices
chunk->m_Count=numVertices;
m_FreeVertices-=numVertices;
// return found chunk
return chunk;
}
///////////////////////////////////////////////////////////////////////////////
// Release: return given chunk to this buffer
void CVertexBuffer::Release(VBChunk* chunk)
{
// add to free list
// TODO, RC - need to merge available chunks where possible to avoid
// excessive fragmentation of vertex buffer space
m_FreeList.push_front(chunk);
m_FreeVertices+=chunk->m_Count;
}
///////////////////////////////////////////////////////////////////////////////
// ClearBatchIndices: clear lists of all batches
void CVertexBuffer::ClearBatchIndices()
{
for (uint i=0;i<m_Batches.size();i++) {
m_Batches[i]->m_IndexData.clear();
m_FreeBatches.push_back(m_Batches[i]);
}
m_Batches.clear();
}
///////////////////////////////////////////////////////////////////////////////
// AppendBatch: add a batch to the render list for this buffer
void CVertexBuffer::AppendBatch(VBChunk* chunk,Handle texture,size_t numIndices,u16* indices)
{
// try and find a batch using this texture
size_t i;
Batch* batch=0;
for (i=0;i<m_Batches.size();++i) {
if (m_Batches[i]->m_Texture==texture) {
batch=m_Batches[i];
break;
}
}
if (!batch) {
if (m_FreeBatches.size()) {
batch=m_FreeBatches.back();
m_FreeBatches.pop_back();
} else {
batch=new Batch;
}
m_Batches.push_back(batch);
batch->m_Texture=texture;
}
// resize the chunk's batch to fit it's indices
size_t cursize=batch->m_IndexData.size();
batch->m_IndexData.resize(cursize+1);
// store batch
batch->m_IndexData[cursize]=std::pair<size_t,u16*>(numIndices,indices);
// memcpy(&batch->m_Indices[0]+cursize,indices,sizeof(u16)*numIndices);
}
///////////////////////////////////////////////////////////////////////////////
// UpdateChunkVertices: update vertex data for given chunk
void CVertexBuffer::UpdateChunkVertices(VBChunk* chunk,void* data)
{
if (g_Renderer.m_Caps.m_VBO) {
assert(m_Handle);
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
glBufferSubDataARB(GL_ARRAY_BUFFER_ARB,chunk->m_Index*m_VertexSize,chunk->m_Count*m_VertexSize,data);
} else {
assert(m_SysMem);
memcpy(m_SysMem+chunk->m_Index*m_VertexSize,data,chunk->m_Count*m_VertexSize);
}
}
///////////////////////////////////////////////////////////////////////////////
// Bind: bind to this buffer; return pointer to address required as parameter
// to glVertexPointer ( + etc) calls
u8* CVertexBuffer::Bind()
{
u8* base;
if (g_Renderer.m_Caps.m_VBO) {
glBindBufferARB(GL_ARRAY_BUFFER_ARB,m_Handle);
base=(u8*) 0;
} else {
base=(u8*) m_SysMem;
}
return base;
}

100
source/renderer/VertexBuffer.h Executable file
View File

@ -0,0 +1,100 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: VertexBuffer.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _VERTEXBUFFER_H
#define _VERTEXBUFFER_H
#include "lib.h"
#include "res/tex.h"
#include <list>
#include <vector>
// absolute maximum (bytewise) size of each GL vertex buffer object
#define MAX_VB_SIZE_BYTES (32*8192)
///////////////////////////////////////////////////////////////////////////////
// CVertexBuffer: encapsulation of ARB_vertex_buffer_object, also supplying
// some additional functionality for batching and sharing buffers between
// multiple objects
class CVertexBuffer
{
public:
// Batch: batch definition - defines indices into the VB to use when rendering,
// and the texture used when doing so
struct Batch {
// list of indices into the vertex buffer of primitives within the batch
std::vector<std::pair<size_t,u16*> > m_IndexData;
// texture to apply when rendering batch
Handle m_Texture;
};
// VBChunk: describes a portion of this vertex buffer
struct VBChunk
{
// owning buffer
CVertexBuffer* m_Owner;
// start index of this chunk in owner
size_t m_Index;
// number of vertices used by chunk
size_t m_Count;
};
public:
// constructor, destructor
CVertexBuffer(size_t vertexSize,bool dynamic);
~CVertexBuffer();
// bind to this buffer; return pointer to address required as parameter
// to glVertexPointer ( + etc) calls
u8* Bind();
// clear lists of all batches
void ClearBatchIndices();
// add a batch to the render list for this buffer
void AppendBatch(VBChunk* chunk,Handle texture,size_t numIndices,u16* indices);
// update vertex data for given chunk
void UpdateChunkVertices(VBChunk* chunk,void* data);
// return this VBs batch list
const std::vector<Batch*>& GetBatches() const { return m_Batches; }
protected:
friend class CVertexBufferManager; // allow allocate only via CVertexBufferManager
// try to allocate a buffer of given number of vertices (each of given size),
// and with the given type - return null if no free chunks available
VBChunk* Allocate(size_t vertexSize,size_t numVertices,bool dynamic);
// return given chunk to this buffer
void Release(VBChunk* chunk);
private:
// set of all possible batches that can be used by this VB
std::vector<Batch*> m_Batches;
// vertex size of this vertex buffer
size_t m_VertexSize;
// number of vertices of above size in this buffer
size_t m_MaxVertices;
// list of free chunks in this buffer
std::list<VBChunk*> m_FreeList;
// available free vertices - total of all free vertices in the free list
size_t m_FreeVertices;
// handle to the actual GL vertex buffer object
GLuint m_Handle;
// raw system memory for systems not supporting VBOs
u8* m_SysMem;
// type of the buffer - dynamic?
bool m_Dynamic;
// list of all spare batches, shared between all vbs
static std::vector<Batch*> m_FreeBatches;
};
#endif

View File

@ -0,0 +1,64 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: VertexBufferManager.cpp
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#include <assert.h>
#include "ogl.h"
#include "VertexBufferManager.h"
CVertexBufferManager g_VBMan;
///////////////////////////////////////////////////////////////////////////////
// Allocate: try to allocate a buffer of given number of vertices (each of
// given size), with the given type, and using the given texture - return null
// if no free chunks available
CVertexBuffer::VBChunk* CVertexBufferManager::Allocate(size_t vertexSize,size_t numVertices,bool dynamic)
{
CVertexBuffer::VBChunk* result=0;
// TODO, RC - run some sanity checks on allocation request
// iterate through all existing buffers testing for one that'll
// satisfy the allocation
typedef std::list<CVertexBuffer*>::iterator Iter;
for (Iter iter=m_Buffers.begin();iter!=m_Buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
result=buffer->Allocate(vertexSize,numVertices,dynamic);
if (result) return result;
}
// got this far; need to allocate a new buffer
CVertexBuffer* buffer=new CVertexBuffer(vertexSize,dynamic);
m_Buffers.push_front(buffer);
result=buffer->Allocate(vertexSize,numVertices,dynamic);
// TODO, RC - assert not really suitable? probably need to handle "failed to create
// VBO case" better
assert(result);
return result;
}
///////////////////////////////////////////////////////////////////////////////
// Release: return given chunk to it's owner
void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk)
{
assert(chunk);
chunk->m_Owner->Release(chunk);
}
///////////////////////////////////////////////////////////////////////////////
// ClearBatchIndices: empty out the batch lists of all vertex buffers
void CVertexBufferManager::ClearBatchIndices()
{
typedef std::list<CVertexBuffer*>::iterator Iter;
for (Iter iter=m_Buffers.begin();iter!=m_Buffers.end();++iter) {
CVertexBuffer* buffer=*iter;
buffer->ClearBatchIndices();
}
}

View File

@ -0,0 +1,41 @@
///////////////////////////////////////////////////////////////////////////////
//
// Name: VertexBufferManager.h
// Author: Rich Cross
// Contact: rich@wildfiregames.com
//
///////////////////////////////////////////////////////////////////////////////
#ifndef _VERTEXBUFFERMANAGER_H
#define _VERTEXBUFFERMANAGER_H
#include "VertexBuffer.h"
///////////////////////////////////////////////////////////////////////////////
// CVertexBufferManager: owner object for CVertexBuffer objects; acts as
// 'front end' for their allocation and destruction
class CVertexBufferManager
{
public:
// try to allocate a buffer of given number of vertices (each of given size),
// and with the given type - return null if no free chunks available
CVertexBuffer::VBChunk* Allocate(size_t vertexSize,size_t numVertices,bool dynamic);
// return given chunk to it's owner
void CVertexBufferManager::Release(CVertexBuffer::VBChunk* chunk);
// empty out the batch lists of all vertex buffers
void ClearBatchIndices();
// return list of all buffers
const std::list<CVertexBuffer*>& GetBufferList() const { return m_Buffers; }
private:
// list of all known vertex buffers
std::list<CVertexBuffer*> m_Buffers;
};
extern CVertexBufferManager g_VBMan;
#endif