mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2024-11-25 09:44:02 +00:00
planning for internal render API and some wip
This commit is contained in:
parent
8528bfae94
commit
ea156ba84f
5 changed files with 480 additions and 0 deletions
|
@ -70,8 +70,12 @@ set(BBGE_SRCS
|
|||
ReadXML.h
|
||||
Rect.h
|
||||
Refcounted.h
|
||||
RenderAPI.cpp
|
||||
RenderAPI.h
|
||||
RenderBase.cpp
|
||||
RenderBase.h
|
||||
RenderHigh.cpp
|
||||
RenderHigh.h
|
||||
RenderObject.cpp
|
||||
RenderObject.h
|
||||
RenderObject_inline.h
|
||||
|
|
183
BBGE/RenderAPI.cpp
Normal file
183
BBGE/RenderAPI.cpp
Normal file
|
@ -0,0 +1,183 @@
|
|||
#include "RenderAPI.h"
|
||||
#include "Base.h"
|
||||
|
||||
#include "RenderBase.h"
|
||||
|
||||
namespace RenderAPI {
|
||||
|
||||
void BufferBase::destroy()
|
||||
{
|
||||
deleteBuffer(&_bufid);
|
||||
}
|
||||
|
||||
void BufferBase::upload(Hint usage)
|
||||
{
|
||||
updateBuffer(&_bufid, _data, _bytes, usage);
|
||||
}
|
||||
|
||||
|
||||
// ----- GL backend starts here -----
|
||||
// TODO: move backend to separate file once finalized
|
||||
|
||||
struct BlendParams
|
||||
{
|
||||
GLenum src, dst;
|
||||
};
|
||||
static const BlendParams s_blendParams[] =
|
||||
{
|
||||
{ GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
|
||||
{ GL_SRC_ALPHA, GL_ONE },
|
||||
{ GL_ZERO, GL_SRC_ALPHA },
|
||||
{ GL_ZERO, GL_SRC_COLOR },
|
||||
};
|
||||
|
||||
static const GLenum s_primTypes[] =
|
||||
{
|
||||
GL_POINTS,
|
||||
GL_LINES,
|
||||
GL_LINE_STRIP,
|
||||
GL_QUADS,
|
||||
GL_QUAD_STRIP
|
||||
};
|
||||
|
||||
|
||||
static void renderNonIndexed(const ObjectData& d)
|
||||
{
|
||||
switch(d.layout)
|
||||
{
|
||||
case RAPI_LAYOUT_2D:
|
||||
{
|
||||
::glColor4fv(&d.color.r);
|
||||
const size_t n = d.verts->bytes() / sizeof(float);
|
||||
const float *p = (const float*)d.verts->data();
|
||||
const float * const end = p + n;
|
||||
for( ; p < end; p += 4) // Vertex2D
|
||||
{
|
||||
::glTexCoord2f(p[0], p[1]);
|
||||
::glVertex2f(p[2], p[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RAPI_LAYOUT_2D_COLOR:
|
||||
{
|
||||
const size_t n = d.verts->bytes() / sizeof(float);
|
||||
const float *p = (const float*)d.verts->data();
|
||||
const float * const end = p + n;
|
||||
for( ; p < end; p += 8) // Vertex2DColor
|
||||
{
|
||||
::glColor4fv(&p[4]);
|
||||
::glTexCoord2f(p[0], p[1]);
|
||||
::glVertex2f(p[2], p[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void renderIndexed(const ObjectData& d)
|
||||
{
|
||||
switch(d.layout)
|
||||
{
|
||||
case RAPI_LAYOUT_2D:
|
||||
{
|
||||
::glColor4fv(&d.color.r);
|
||||
const size_t n = d.indices->bytes() / sizeof(unsigned short);
|
||||
const unsigned short *idx = (const unsigned short*)d.indices->data();
|
||||
const float * const pbase = (const float*)d.verts->data();
|
||||
const unsigned short * const end = idx + n;
|
||||
for( ; idx < end; ++idx)
|
||||
{
|
||||
const float *p = pbase + *idx;
|
||||
::glTexCoord2f(p[0], p[1]);
|
||||
::glVertex2f(p[2], p[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case RAPI_LAYOUT_2D_COLOR:
|
||||
{
|
||||
const size_t n = d.indices->bytes() / sizeof(unsigned short);
|
||||
const unsigned short *idx = (const unsigned short*)d.indices->data();
|
||||
const float * const pbase = (const float*)d.verts->data();
|
||||
const unsigned short * const end = idx + n;
|
||||
for( ; idx < end; ++idx)
|
||||
{
|
||||
const float *p = pbase + *idx;
|
||||
::glColor4fv(&p[4]);
|
||||
::glTexCoord2f(p[0], p[1]);
|
||||
::glVertex2f(p[2], p[3]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void render(const ObjectData* objs, size_t n)
|
||||
{
|
||||
::glPushMatrix();
|
||||
char lastblend = BLEND_DISABLED - 1; // always fail the first check
|
||||
unsigned lasttex = unsigned(-1);
|
||||
const ObjectData* const end = objs + n;
|
||||
for( ; objs < end; ++objs)
|
||||
{
|
||||
const ObjectData& d = *objs;
|
||||
if(lastblend != d.blend)
|
||||
{
|
||||
lastblend = d.blend;
|
||||
unsigned ublend = unsigned(int(d.blend)); // this underflows if BLEND_DISABLED
|
||||
if (ublend < Countof(s_blendParams))
|
||||
{
|
||||
::glEnable(GL_BLEND);
|
||||
const BlendParams& bp = s_blendParams[ublend];
|
||||
::glBlendFunc(bp.src, bp.dst);
|
||||
}
|
||||
else
|
||||
{
|
||||
::glDisable(GL_BLEND);
|
||||
::glDisable(GL_ALPHA_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
::glLoadMatrixf(d.pmat);
|
||||
|
||||
|
||||
const unsigned prim = d.prim;
|
||||
switch(prim)
|
||||
{
|
||||
case RAPI_PRIM_POINTS:
|
||||
::glPointSize(d.u.linewidth);
|
||||
break;
|
||||
case RAPI_PRIM_LINES:
|
||||
case RAPI_PRIM_LINE_STRIP:
|
||||
::glLineWidth(d.u.linewidth);
|
||||
break;
|
||||
|
||||
default:
|
||||
if(d.u.texid != lasttex)
|
||||
{
|
||||
lasttex = d.u.texid;
|
||||
::glBindTexture(GL_TEXTURE_2D, d.u.texid);
|
||||
}
|
||||
}
|
||||
|
||||
::glBegin(s_primTypes[prim]);
|
||||
if(!d.indices)
|
||||
renderNonIndexed(d);
|
||||
else
|
||||
renderIndexed(d);
|
||||
::glEnd();
|
||||
}
|
||||
::glPopMatrix();
|
||||
}
|
||||
|
||||
void updateBuffer(unsigned* pbufid, const void* data, size_t bytes, RenderAPI::BufferBase::Hint usage)
|
||||
{
|
||||
}
|
||||
|
||||
void deleteBuffer(unsigned* pbufid)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
81
BBGE/RenderAPI.h
Normal file
81
BBGE/RenderAPI.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
#ifndef BBGE_RENDER_API_H
|
||||
#define BBGE_RENDER_API_H
|
||||
|
||||
#include "EngineEnums.h"
|
||||
|
||||
enum RenderAPIConstants
|
||||
{
|
||||
//-- primitives to draw
|
||||
RAPI_PRIM_POINTS = 0,
|
||||
RAPI_PRIM_LINES = 1,
|
||||
RAPI_PRIM_LINE_STRIP = 2,
|
||||
RAPI_PRIM_QUADS = 3,
|
||||
RAPI_PRIM_QUAD_STRIP = 4,
|
||||
|
||||
//-- per-vertex layout
|
||||
RAPI_LAYOUT_2D = 0, // (u,v,x,y) aka Vertex2D
|
||||
RAPI_LAYOUT_2D_COLOR = 1 // (u,v,x,y,r,g,b,a) aka Vertex2DColor
|
||||
};
|
||||
|
||||
namespace RenderAPI {
|
||||
|
||||
struct Vertex2D
|
||||
{
|
||||
float u, v, x, y;
|
||||
};
|
||||
struct Vertex2DColor : public Vertex2D
|
||||
{
|
||||
float r, g, b, a;
|
||||
};
|
||||
|
||||
|
||||
class BufferBase
|
||||
{
|
||||
public:
|
||||
enum Hint
|
||||
{
|
||||
BUFFER_STATIC,
|
||||
BUFFER_DYNAMIC
|
||||
};
|
||||
|
||||
unsigned bufid() const { return _bufid; }
|
||||
const void *data() const { return _data; }
|
||||
size_t bytes() const { return _bytes; }
|
||||
void destroy();
|
||||
void upload(Hint usage);
|
||||
|
||||
protected:
|
||||
|
||||
unsigned _bufid;
|
||||
void *_data; // pointer to data
|
||||
size_t _bytes;
|
||||
};
|
||||
|
||||
// real POD struct
|
||||
struct ObjectData
|
||||
{
|
||||
const float *pmat; // pointer to float[16]
|
||||
struct
|
||||
{
|
||||
float r, g, b, a; // used only when no per-vertex colors are used
|
||||
} color;
|
||||
const BufferBase *verts;
|
||||
const BufferBase *indices; // always uint16 if present
|
||||
union
|
||||
{
|
||||
unsigned texid; // if tris/quads
|
||||
float linewidth; // if lines/points: point size or line width
|
||||
} u;
|
||||
char blend;
|
||||
unsigned char prim;
|
||||
unsigned char layout;
|
||||
};
|
||||
|
||||
|
||||
void render(const ObjectData *objs, size_t n);
|
||||
void updateBuffer(unsigned *pbufid, const void *data, size_t bytes, BufferBase::Hint usage);
|
||||
void deleteBuffer(unsigned *pbufid);
|
||||
|
||||
}
|
||||
|
||||
#endif // BBGE_RENDER_API_H
|
97
BBGE/RenderHigh.cpp
Normal file
97
BBGE/RenderHigh.cpp
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include "RenderHigh.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
ObjectList::ObjectList(size_t minsize)
|
||||
: _ptr(NULL), _size(0), _cap(0), _minsize(minsize)
|
||||
{
|
||||
}
|
||||
|
||||
ObjectList::~ObjectList()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
RenderAPI::ObjectData* ObjectList::reserve(size_t n)
|
||||
{
|
||||
return _ensure(n) + _size;
|
||||
}
|
||||
|
||||
void ObjectList::commit(size_t n)
|
||||
{
|
||||
_size += n;
|
||||
assert(_size <= _cap);
|
||||
}
|
||||
|
||||
RenderAPI::ObjectData& ObjectList::push(const RenderAPI::ObjectData& a)
|
||||
{
|
||||
size_t cursize = _size;
|
||||
size_t newsize = _size + 1;
|
||||
_size = newsize;
|
||||
return (_ensure(newsize)[cursize] = a);
|
||||
}
|
||||
|
||||
void ObjectList::reset()
|
||||
{
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
void ObjectList::clear()
|
||||
{
|
||||
free(_ptr);
|
||||
_ptr = NULL;
|
||||
_size = 0;
|
||||
_cap = 0;
|
||||
}
|
||||
|
||||
RenderAPI::ObjectData* ObjectList::_ensure(size_t n)
|
||||
{
|
||||
if(n < _cap)
|
||||
return _ptr;
|
||||
|
||||
size_t newsize = 2 * _cap;
|
||||
if(newsize < n)
|
||||
newsize += n;
|
||||
if(newsize < _minsize)
|
||||
newsize = _minsize;
|
||||
|
||||
RenderAPI::ObjectData *p = (RenderAPI::ObjectData*)realloc(_ptr, sizeof(RenderAPI::ObjectData) * newsize);
|
||||
if(!p)
|
||||
return NULL;
|
||||
|
||||
_ptr = p;
|
||||
_cap = newsize;
|
||||
return p;
|
||||
}
|
||||
|
||||
DynamicBuffer::DynamicBuffer()
|
||||
: usage(BUFFER_DYNAMIC)
|
||||
{
|
||||
_bufid = 0;
|
||||
_data = NULL;
|
||||
_bytes = 0;
|
||||
}
|
||||
|
||||
DynamicBuffer::~DynamicBuffer()
|
||||
{
|
||||
free(_data);
|
||||
}
|
||||
|
||||
void* DynamicBuffer::resizeBytes(size_t bytes)
|
||||
{
|
||||
_bytes = bytes;
|
||||
return realloc(_data, bytes);
|
||||
}
|
||||
|
||||
void* DynamicBuffer::_ensureBytes(size_t bytes)
|
||||
{
|
||||
if(bytes < _bytes)
|
||||
return _data;
|
||||
|
||||
size_t newsize = 2 * _bytes;
|
||||
if(newsize < bytes)
|
||||
newsize += bytes;
|
||||
|
||||
return resizeBytes(newsize);
|
||||
}
|
115
BBGE/RenderHigh.h
Normal file
115
BBGE/RenderHigh.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
#ifndef BBGE_RENDER_HIGH_H
|
||||
#define BBGE_RENDER_HIGH_H
|
||||
|
||||
// High-level API for the renderer
|
||||
|
||||
#include "RenderAPI.h"
|
||||
#include "Base.h"
|
||||
#include <assert.h>
|
||||
|
||||
// Stores data for later submission to the renderer.
|
||||
// Workflow:
|
||||
// Either: reserve() some, then commit()
|
||||
// Or: add() some
|
||||
// Finally: pass (data(), size()) to the renderer
|
||||
class ObjectList
|
||||
{
|
||||
public:
|
||||
ObjectList(size_t minsize);
|
||||
~ObjectList();
|
||||
|
||||
RenderAPI::ObjectData *reserve(size_t n); // reserve at least n elements and return pointer to writable area
|
||||
void commit(size_t n); // acknowledge writing n elements to previously reserve()d
|
||||
|
||||
RenderAPI::ObjectData& push(const RenderAPI::ObjectData& a); // add one element
|
||||
void reset();
|
||||
void clear();
|
||||
|
||||
const RenderAPI::ObjectData *data() const { return _ptr; }
|
||||
size_t size() const { return _size; }
|
||||
|
||||
private:
|
||||
RenderAPI::ObjectData *_ptr;
|
||||
size_t _size, _cap;
|
||||
size_t _minsize;
|
||||
|
||||
RenderAPI::ObjectData *_ensure(size_t n); // ensures that there's space for at least n entries in total
|
||||
};
|
||||
|
||||
template<typename T, unsigned N>
|
||||
class StaticMesh : public RenderAPI::BufferBase
|
||||
{
|
||||
public:
|
||||
StaticMesh()
|
||||
{
|
||||
this->_bufid = 0;
|
||||
this->_data = &data[0];
|
||||
this->_size = sizeof(data);
|
||||
}
|
||||
T data[N];
|
||||
|
||||
inline T& operator[](size_t i) { assert(i < Countof(data)); return data[i]; }
|
||||
inline const T& operator[](size_t i) const { assert(i < Countof(data)); return data[i]; }
|
||||
|
||||
inline void upload() { this->upload(BUFFER_STATIC); }
|
||||
};
|
||||
|
||||
class DynamicBuffer : public RenderAPI::BufferBase
|
||||
{
|
||||
public:
|
||||
typedef RenderAPI::BufferBase Base;
|
||||
DynamicBuffer();
|
||||
~DynamicBuffer();
|
||||
Hint usage;
|
||||
inline void upload() { Base::upload(usage); }
|
||||
void *resizeBytes(size_t bytes); // resize to exactly this size
|
||||
protected:
|
||||
void *_ensureBytes(size_t bytes); // ensures that there's space for at least that many bytes
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class DynamicMesh : public DynamicBuffer
|
||||
{
|
||||
public:
|
||||
T& push(const T& val)
|
||||
{
|
||||
size_t sz = _size;
|
||||
T *p = _ensure(sz + 1);
|
||||
_size = sz + 1
|
||||
return (p[sz] = val);
|
||||
}
|
||||
|
||||
inline T *resize(size_t n) // ptr to start
|
||||
{
|
||||
return (T*)this->resizeBytes(n);
|
||||
}
|
||||
|
||||
inline T *reserve(size_t n) // ptr to writable region of n elems
|
||||
{
|
||||
return _ensure(n) + _size;
|
||||
}
|
||||
|
||||
inline void commit(size_t n) // commit prev. reserve()d
|
||||
{
|
||||
_size += n;
|
||||
}
|
||||
|
||||
inline void reset()
|
||||
{
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
inline T& operator[](size_t i) { assert(i < _size); return (( T*)_data)[i]; }
|
||||
inline const T& operator[](size_t i) const { assert(i < _size); return ((const T*)_data)[i]; }
|
||||
|
||||
private:
|
||||
T *_ensure(size_t n)
|
||||
{
|
||||
return (T*)this->_ensureBytes(n * sizeof(T));
|
||||
}
|
||||
|
||||
size_t _size; // in elements
|
||||
};
|
||||
|
||||
|
||||
#endif // BBGE_RENDER_HIGH_H
|
Loading…
Reference in a new issue