summaryrefslogtreecommitdiff
path: root/src/shared/glemu.cpp
diff options
context:
space:
mode:
authorxolatile2025-07-16 23:07:43 +0200
committerxolatile2025-07-16 23:07:43 +0200
commit7256502afa0babe60fcafbd2888cd3e33c3f9b6b (patch)
tree8a8495662a69bdadc4b5d9152656b9f02a44d668 /src/shared/glemu.cpp
parentbc596ac9d4cdd00abf537b88d3c544be161330cc (diff)
downloadxolatile-badassbug-7256502afa0babe60fcafbd2888cd3e33c3f9b6b.tar.xz
xolatile-badassbug-7256502afa0babe60fcafbd2888cd3e33c3f9b6b.tar.zst
Source code, broken...
Diffstat (limited to 'src/shared/glemu.cpp')
-rw-r--r--src/shared/glemu.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/shared/glemu.cpp b/src/shared/glemu.cpp
new file mode 100644
index 0000000..5658eb8
--- /dev/null
+++ b/src/shared/glemu.cpp
@@ -0,0 +1,355 @@
+#include "cube.h"
+
+extern int glversion;
+extern int intel_mapbufferrange_bug;
+
+namespace gle
+{
+ struct attribinfo
+ {
+ int type, size, formatsize, offset;
+ GLenum format;
+
+ attribinfo() : type(0), size(0), formatsize(0), offset(0), format(GL_FALSE) {}
+
+ bool operator==(const attribinfo &a) const
+ {
+ return type == a.type && size == a.size && format == a.format && offset == a.offset;
+ }
+ bool operator!=(const attribinfo &a) const
+ {
+ return type != a.type || size != a.size || format != a.format || offset != a.offset;
+ }
+ };
+
+ extern const char * const attribnames[MAXATTRIBS] = { "vvertex", "vcolor", "vtexcoord0", "vtexcoord1", "vnormal", "vtangent", "vboneweight", "vboneindex" };
+ ucharbuf attribbuf;
+ static uchar *attribdata;
+ static attribinfo attribdefs[MAXATTRIBS], lastattribs[MAXATTRIBS];
+ int enabled = 0;
+ static int numattribs = 0, attribmask = 0, numlastattribs = 0, lastattribmask = 0, vertexsize = 0, lastvertexsize = 0;
+ static GLenum primtype = GL_TRIANGLES;
+ static uchar *lastbuf = NULL;
+ static bool changedattribs = false;
+ static vector<GLint> multidrawstart;
+ static vector<GLsizei> multidrawcount;
+
+ #define MAXQUADS (0x10000/4)
+ static GLuint quadindexes = 0;
+ static bool quadsenabled = false;
+
+ #define MAXVBOSIZE (4*1024*1024)
+ static GLuint vbo = 0;
+ static int vbooffset = MAXVBOSIZE;
+
+ static GLuint defaultvao = 0;
+
+ void enablequads()
+ {
+ quadsenabled = true;
+
+ if(glversion < 300) return;
+
+ if(quadindexes)
+ {
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, quadindexes);
+ return;
+ }
+
+ glGenBuffers_(1, &quadindexes);
+ ushort *data = new ushort[MAXQUADS*6], *dst = data;
+ for(int idx = 0; idx < MAXQUADS*4; idx += 4, dst += 6)
+ {
+ dst[0] = idx;
+ dst[1] = idx + 1;
+ dst[2] = idx + 2;
+ dst[3] = idx + 0;
+ dst[4] = idx + 2;
+ dst[5] = idx + 3;
+ }
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, quadindexes);
+ glBufferData_(GL_ELEMENT_ARRAY_BUFFER, MAXQUADS*6*sizeof(ushort), data, GL_STATIC_DRAW);
+ delete[] data;
+ }
+
+ void disablequads()
+ {
+ quadsenabled = false;
+
+ if(glversion < 300) return;
+
+ glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ void drawquads(int offset, int count)
+ {
+ if(count <= 0) return;
+ if(glversion < 300)
+ {
+ glDrawArrays(GL_QUADS, offset*4, count*4);
+ return;
+ }
+ if(offset + count > MAXQUADS)
+ {
+ if(offset >= MAXQUADS) return;
+ count = MAXQUADS - offset;
+ }
+ glDrawRangeElements_(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, (ushort *)0 + offset*6);
+ }
+
+ void defattrib(int type, int size, int format)
+ {
+ if(type == ATTRIB_VERTEX)
+ {
+ numattribs = attribmask = 0;
+ vertexsize = 0;
+ }
+ changedattribs = true;
+ attribmask |= 1<<type;
+ attribinfo &a = attribdefs[numattribs++];
+ a.type = type;
+ a.size = size;
+ a.format = format;
+ switch(format)
+ {
+ case 'B': case GL_UNSIGNED_BYTE: a.formatsize = 1; a.format = GL_UNSIGNED_BYTE; break;
+ case 'b': case GL_BYTE: a.formatsize = 1; a.format = GL_BYTE; break;
+ case 'S': case GL_UNSIGNED_SHORT: a.formatsize = 2; a.format = GL_UNSIGNED_SHORT; break;
+ case 's': case GL_SHORT: a.formatsize = 2; a.format = GL_SHORT; break;
+ case 'I': case GL_UNSIGNED_INT: a.formatsize = 4; a.format = GL_UNSIGNED_INT; break;
+ case 'i': case GL_INT: a.formatsize = 4; a.format = GL_INT; break;
+ case 'f': case GL_FLOAT: a.formatsize = 4; a.format = GL_FLOAT; break;
+ case 'd': case GL_DOUBLE: a.formatsize = 8; a.format = GL_DOUBLE; break;
+ default: a.formatsize = 0; a.format = GL_FALSE; break;
+ }
+ a.formatsize *= size;
+ a.offset = vertexsize;
+ vertexsize += a.formatsize;
+ }
+
+ void defattribs(const char *fmt)
+ {
+ for(;; fmt += 3)
+ {
+ GLenum format;
+ switch(fmt[0])
+ {
+ case 'v': format = ATTRIB_VERTEX; break;
+ case 'c': format = ATTRIB_COLOR; break;
+ case 't': format = ATTRIB_TEXCOORD0; break;
+ case 'T': format = ATTRIB_TEXCOORD1; break;
+ case 'n': format = ATTRIB_NORMAL; break;
+ case 'x': format = ATTRIB_TANGENT; break;
+ case 'w': format = ATTRIB_BONEWEIGHT; break;
+ case 'i': format = ATTRIB_BONEINDEX; break;
+ default: return;
+ }
+ defattrib(format, fmt[1]-'0', fmt[2]);
+ }
+ }
+
+ static inline void setattrib(const attribinfo &a, uchar *buf)
+ {
+ switch(a.type)
+ {
+ case ATTRIB_VERTEX:
+ case ATTRIB_TEXCOORD0:
+ case ATTRIB_TEXCOORD1:
+ case ATTRIB_BONEINDEX:
+ glVertexAttribPointer_(a.type, a.size, a.format, GL_FALSE, vertexsize, buf);
+ break;
+ case ATTRIB_COLOR:
+ case ATTRIB_NORMAL:
+ case ATTRIB_TANGENT:
+ case ATTRIB_BONEWEIGHT:
+ glVertexAttribPointer_(a.type, a.size, a.format, GL_TRUE, vertexsize, buf);
+ break;
+ }
+ if(!(enabled&(1<<a.type)))
+ {
+ glEnableVertexAttribArray_(a.type);
+ enabled |= 1<<a.type;
+ }
+ }
+
+ static inline void unsetattrib(const attribinfo &a)
+ {
+ glDisableVertexAttribArray_(a.type);
+ enabled &= ~(1<<a.type);
+ }
+
+ static inline void setattribs(uchar *buf)
+ {
+ bool forceattribs = numattribs != numlastattribs || vertexsize != lastvertexsize || buf != lastbuf;
+ if(forceattribs || changedattribs)
+ {
+ int diffmask = enabled & lastattribmask & ~attribmask;
+ if(diffmask) loopi(numlastattribs)
+ {
+ const attribinfo &a = lastattribs[i];
+ if(diffmask & (1<<a.type)) unsetattrib(a);
+ }
+ uchar *src = buf;
+ loopi(numattribs)
+ {
+ const attribinfo &a = attribdefs[i];
+ if(forceattribs || a != lastattribs[i])
+ {
+ setattrib(a, src);
+ lastattribs[i] = a;
+ }
+ src += a.formatsize;
+ }
+ lastbuf = buf;
+ numlastattribs = numattribs;
+ lastattribmask = attribmask;
+ lastvertexsize = vertexsize;
+ changedattribs = false;
+ }
+ }
+
+ void begin(GLenum mode)
+ {
+ primtype = mode;
+ }
+
+ void begin(GLenum mode, int numverts)
+ {
+ primtype = mode;
+ if(glversion >= 300 && !intel_mapbufferrange_bug)
+ {
+ int len = numverts * vertexsize;
+ if(vbooffset + len >= MAXVBOSIZE)
+ {
+ len = min(len, MAXVBOSIZE);
+ if(!vbo) glGenBuffers_(1, &vbo);
+ glBindBuffer_(GL_ARRAY_BUFFER, vbo);
+ glBufferData_(GL_ARRAY_BUFFER, MAXVBOSIZE, NULL, GL_STREAM_DRAW);
+ vbooffset = 0;
+ }
+ else if(!lastvertexsize) glBindBuffer_(GL_ARRAY_BUFFER, vbo);
+ void *buf = glMapBufferRange_(GL_ARRAY_BUFFER, vbooffset, len, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
+ if(buf) attribbuf.reset((uchar *)buf, len);
+ }
+ }
+
+ void multidraw()
+ {
+ int start = multidrawstart.length() ? multidrawstart.last() + multidrawcount.last() : 0,
+ count = attribbuf.length()/vertexsize - start;
+ if(count > 0)
+ {
+ multidrawstart.add(start);
+ multidrawcount.add(count);
+ }
+ }
+
+ int end()
+ {
+ uchar *buf = attribbuf.getbuf();
+ if(attribbuf.empty())
+ {
+ if(buf != attribdata)
+ {
+ glUnmapBuffer_(GL_ARRAY_BUFFER);
+ attribbuf.reset(attribdata, MAXVBOSIZE);
+ }
+ return 0;
+ }
+ int start = 0;
+ if(glversion >= 300)
+ {
+ if(buf == attribdata)
+ {
+ if(vbooffset + attribbuf.length() >= MAXVBOSIZE)
+ {
+ if(!vbo) glGenBuffers_(1, &vbo);
+ glBindBuffer_(GL_ARRAY_BUFFER, vbo);
+ glBufferData_(GL_ARRAY_BUFFER, MAXVBOSIZE, NULL, GL_STREAM_DRAW);
+ vbooffset = 0;
+ }
+ else if(!lastvertexsize) glBindBuffer_(GL_ARRAY_BUFFER, vbo);
+ void *dst = intel_mapbufferrange_bug ? NULL :
+ glMapBufferRange_(GL_ARRAY_BUFFER, vbooffset, attribbuf.length(), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
+ if(dst)
+ {
+ memcpy(dst, attribbuf.getbuf(), attribbuf.length());
+ glUnmapBuffer_(GL_ARRAY_BUFFER);
+ }
+ else glBufferSubData_(GL_ARRAY_BUFFER, vbooffset, attribbuf.length(), attribbuf.getbuf());
+ }
+ else glUnmapBuffer_(GL_ARRAY_BUFFER);
+ buf = (uchar *)0 + vbooffset;
+ if(vertexsize == lastvertexsize && buf >= lastbuf)
+ {
+ start = int(buf - lastbuf)/vertexsize;
+ if(primtype == GL_QUADS && (start%4 || start + attribbuf.length()/vertexsize >= 4*MAXQUADS))
+ start = 0;
+ else buf = lastbuf;
+ }
+ vbooffset += attribbuf.length();
+ }
+ setattribs(buf);
+ int numvertexes = attribbuf.length()/vertexsize;
+ if(primtype == GL_QUADS)
+ {
+ if(!quadsenabled) enablequads();
+ for(int quads = numvertexes/4;;)
+ {
+ int count = min(quads, MAXQUADS);
+ drawquads(start/4, count);
+ quads -= count;
+ if(quads <= 0) break;
+ setattribs(buf + 4*count*vertexsize);
+ start = 0;
+ }
+ }
+ else
+ {
+ if(multidrawstart.length())
+ {
+ multidraw();
+ if(start) loopv(multidrawstart) multidrawstart[i] += start;
+ glMultiDrawArrays_(primtype, multidrawstart.getbuf(), multidrawcount.getbuf(), multidrawstart.length());
+ multidrawstart.setsize(0);
+ multidrawcount.setsize(0);
+ }
+ else glDrawArrays(primtype, start, numvertexes);
+ }
+ attribbuf.reset(attribdata, MAXVBOSIZE);
+ return numvertexes;
+ }
+
+ void forcedisable()
+ {
+ for(int i = 0; enabled; i++) if(enabled&(1<<i)) { glDisableVertexAttribArray_(i); enabled &= ~(1<<i); }
+ numlastattribs = lastattribmask = lastvertexsize = 0;
+ lastbuf = NULL;
+ if(quadsenabled) disablequads();
+ if(glversion >= 300) glBindBuffer_(GL_ARRAY_BUFFER, 0);
+ }
+
+ void setup()
+ {
+ if(glversion >= 300)
+ {
+ if(!defaultvao) glGenVertexArrays_(1, &defaultvao);
+ glBindVertexArray_(defaultvao);
+ }
+ attribdata = new uchar[MAXVBOSIZE];
+ attribbuf.reset(attribdata, MAXVBOSIZE);
+ }
+
+ void cleanup()
+ {
+ disable();
+
+ if(quadindexes) { glDeleteBuffers_(1, &quadindexes); quadindexes = 0; }
+
+ if(vbo) { glDeleteBuffers_(1, &vbo); vbo = 0; }
+ vbooffset = MAXVBOSIZE;
+
+ if(defaultvao) { glDeleteVertexArrays_(1, &defaultvao); defaultvao = 0; }
+ }
+}
+