1
0
Fork 0
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:
fgenesis 2023-07-02 21:53:49 +02:00
parent 8528bfae94
commit ea156ba84f
5 changed files with 480 additions and 0 deletions

View file

@ -70,8 +70,12 @@ set(BBGE_SRCS
ReadXML.h ReadXML.h
Rect.h Rect.h
Refcounted.h Refcounted.h
RenderAPI.cpp
RenderAPI.h
RenderBase.cpp RenderBase.cpp
RenderBase.h RenderBase.h
RenderHigh.cpp
RenderHigh.h
RenderObject.cpp RenderObject.cpp
RenderObject.h RenderObject.h
RenderObject_inline.h RenderObject_inline.h

183
BBGE/RenderAPI.cpp Normal file
View 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
View 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
View 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
View 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