Line data Source code
1 : /**
2 : * @file glemu.cpp
3 : * @brief GL immediate mode EMUlation layer (glemu).
4 : *
5 : * This file replicates some of the functionality of the long since removed glBegin/glEnd
6 : * features from extremely outdated versions of OpenGL.
7 : */
8 :
9 : #include <cstring>
10 : #include <algorithm>
11 : #include <vector>
12 : #include <string>
13 : #include <cmath>
14 : #include <array>
15 :
16 : #include <SDL.h>
17 :
18 : #include <GL/glew.h>
19 : #include <GL/gl.h>
20 :
21 : #include <zlib.h>
22 :
23 : #include "../libprimis-headers/tools.h"
24 : #include "../libprimis-headers/geom.h"
25 :
26 : #include "glemu.h"
27 : #include "glexts.h"
28 : namespace gle
29 : {
30 : struct attribinfo final
31 : {
32 : int type, size, formatsize, offset;
33 : GLenum format;
34 :
35 16 : attribinfo() : type(0), size(0), formatsize(0), offset(0), format(GL_FALSE) {}
36 :
37 : bool operator==(const attribinfo &a) const
38 : {
39 : return type == a.type && size == a.size && format == a.format && offset == a.offset;
40 : }
41 0 : bool operator!=(const attribinfo &a) const
42 : {
43 0 : return type != a.type || size != a.size || format != a.format || offset != a.offset;
44 : }
45 : };
46 : ucharbuf attribbuf;
47 : static uchar *attribdata;
48 : static std::array<attribinfo, Attribute_NumAttributes> attribdefs,
49 : lastattribs;
50 : static int enabled = 0;
51 : static int numattribs = 0,
52 : attribmask = 0,
53 : numlastattribs = 0,
54 : lastattribmask = 0,
55 : vertexsize = 0,
56 : lastvertexsize = 0;
57 : static GLenum primtype = GL_TRIANGLES;
58 : static uchar *lastbuf = nullptr;
59 : static bool changedattribs = false;
60 : static std::vector<GLint> multidrawstart;
61 : static std::vector<GLsizei> multidrawcount;
62 :
63 : static constexpr int maxquads = (0x10000/4); //65635/4 = 16384
64 : static GLuint quadindexes = 0;
65 : static bool quadsenabled = false;
66 :
67 : static constexpr int maxvbosize = (1024*1024*4);
68 : static GLuint vbo = 0;
69 : static int vbooffset = maxvbosize;
70 :
71 : static GLuint defaultvao = 0;
72 :
73 0 : void enablequads()
74 : {
75 0 : quadsenabled = true;
76 0 : if(quadindexes)
77 : {
78 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadindexes);
79 0 : return;
80 : }
81 :
82 0 : glGenBuffers(1, &quadindexes);
83 0 : ushort *data = new ushort[maxquads*6],
84 0 : *dst = data;
85 0 : for(int idx = 0; idx < maxquads*4; idx += 4, dst += 6)
86 : {
87 0 : dst[0] = idx;
88 0 : dst[1] = idx + 1;
89 0 : dst[2] = idx + 2;
90 0 : dst[3] = idx + 0;
91 0 : dst[4] = idx + 2;
92 0 : dst[5] = idx + 3;
93 : }
94 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, quadindexes);
95 0 : glBufferData(GL_ELEMENT_ARRAY_BUFFER, maxquads*6*sizeof(ushort), data, GL_STATIC_DRAW);
96 0 : delete[] data;
97 : }
98 :
99 0 : void disablequads()
100 : {
101 0 : quadsenabled = false;
102 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
103 0 : }
104 :
105 0 : void drawquads(int offset, int count)
106 : {
107 0 : if(count <= 0)
108 : {
109 0 : return;
110 : }
111 0 : if(offset + count > maxquads)
112 : {
113 0 : if(offset >= maxquads)
114 : {
115 0 : return;
116 : }
117 0 : count = maxquads - offset;
118 : }
119 0 : glDrawRangeElements(GL_TRIANGLES, offset*4, (offset + count)*4-1, count*6, GL_UNSIGNED_SHORT, static_cast<ushort *>(nullptr) + offset*6);
120 : }
121 :
122 0 : static void defattrib(int type, int size, int format)
123 : {
124 0 : if(type == Attribute_Vertex)
125 : {
126 0 : numattribs = attribmask = 0;
127 0 : vertexsize = 0;
128 : }
129 0 : changedattribs = true;
130 0 : attribmask |= 1<<type;
131 0 : attribinfo &a = attribdefs[numattribs++];
132 0 : a.type = type;
133 0 : a.size = size;
134 0 : a.format = format;
135 0 : switch(format)
136 : {
137 0 : case 'B':
138 : case GL_UNSIGNED_BYTE:
139 : {
140 0 : a.formatsize = 1;
141 0 : a.format = GL_UNSIGNED_BYTE;
142 0 : break;
143 : }
144 0 : case 'b':
145 : case GL_BYTE:
146 : {
147 0 : a.formatsize = 1;
148 0 : a.format = GL_BYTE;
149 0 : break;
150 : }
151 0 : case 'S':
152 : case GL_UNSIGNED_SHORT:
153 : {
154 0 : a.formatsize = 2;
155 0 : a.format = GL_UNSIGNED_SHORT;
156 0 : break;
157 : }
158 0 : case 's':
159 : case GL_SHORT:
160 : {
161 0 : a.formatsize = 2;
162 0 : a.format = GL_SHORT;
163 0 : break;
164 : }
165 0 : case 'I':
166 : case GL_UNSIGNED_INT:
167 : {
168 0 : a.formatsize = 4;
169 0 : a.format = GL_UNSIGNED_INT;
170 0 : break;
171 : }
172 0 : case 'i':
173 : case GL_INT:
174 : {
175 0 : a.formatsize = 4;
176 0 : a.format = GL_INT;
177 0 : break;
178 : }
179 0 : case 'f':
180 : case GL_FLOAT:
181 : {
182 0 : a.formatsize = 4;
183 0 : a.format = GL_FLOAT;
184 0 : break;
185 : }
186 0 : case 'd':
187 : case GL_DOUBLE:
188 : {
189 0 : a.formatsize = 8;
190 0 : a.format = GL_DOUBLE;
191 0 : break;
192 : }
193 0 : default:
194 : {
195 0 : a.formatsize = 0;
196 0 : a.format = GL_FALSE;
197 0 : break;
198 : }
199 : }
200 0 : a.formatsize *= size;
201 0 : a.offset = vertexsize;
202 0 : vertexsize += a.formatsize;
203 0 : }
204 :
205 0 : static void setattrib(const attribinfo &a, uchar *buf)
206 : {
207 0 : switch(a.type)
208 : {
209 0 : case Attribute_Vertex:
210 : case Attribute_TexCoord0:
211 : case Attribute_TexCoord1:
212 : case Attribute_BoneIndex:
213 : {
214 0 : glVertexAttribPointer(a.type, a.size, a.format, GL_FALSE, vertexsize, buf);
215 0 : break;
216 : }
217 0 : case Attribute_Color:
218 : case Attribute_Normal:
219 : case Attribute_Tangent:
220 : case Attribute_BoneWeight:
221 : {
222 0 : glVertexAttribPointer(a.type, a.size, a.format, GL_TRUE, vertexsize, buf);
223 0 : break;
224 : }
225 : }
226 0 : if(!(enabled&(1<<a.type)))
227 : {
228 0 : glEnableVertexAttribArray(a.type);
229 0 : enabled |= 1<<a.type;
230 : }
231 0 : }
232 :
233 0 : static void unsetattrib(const attribinfo &a)
234 : {
235 0 : glDisableVertexAttribArray(a.type);
236 0 : enabled &= ~(1<<a.type);
237 0 : }
238 :
239 0 : static void setattribs(uchar *buf)
240 : {
241 0 : bool forceattribs = numattribs != numlastattribs || vertexsize != lastvertexsize || buf != lastbuf;
242 0 : if(forceattribs || changedattribs)
243 : {
244 : //bitwise AND of attribs
245 0 : int diffmask = enabled & lastattribmask & ~attribmask;
246 0 : if(diffmask)
247 : {
248 0 : for(int i = 0; i < numlastattribs; ++i)
249 : {
250 0 : const attribinfo &a = lastattribs[i];
251 0 : if(diffmask & (1<<a.type))
252 : {
253 0 : unsetattrib(a);
254 : }
255 : }
256 : }
257 0 : uchar *src = buf;
258 0 : for(int i = 0; i < numattribs; ++i)
259 : {
260 0 : const attribinfo &a = attribdefs[i];
261 0 : if(forceattribs || a != lastattribs[i])
262 : {
263 0 : setattrib(a, src);
264 0 : lastattribs[i] = a;
265 : }
266 0 : src += a.formatsize;
267 : }
268 0 : lastbuf = buf;
269 0 : numlastattribs = numattribs;
270 0 : lastattribmask = attribmask;
271 0 : lastvertexsize = vertexsize;
272 0 : changedattribs = false;
273 : }
274 0 : }
275 :
276 0 : void begin(GLenum mode)
277 : {
278 0 : primtype = mode;
279 0 : }
280 :
281 0 : void begin(GLenum mode, int numverts)
282 : {
283 0 : primtype = mode;
284 0 : int len = numverts * vertexsize;
285 0 : if(vbooffset + len >= maxvbosize)
286 : {
287 0 : len = std::min<int>(len, maxvbosize);
288 0 : if(!vbo)
289 : {
290 0 : glGenBuffers(1, &vbo);
291 : }
292 0 : glBindBuffer(GL_ARRAY_BUFFER, vbo);
293 0 : glBufferData(GL_ARRAY_BUFFER, maxvbosize, nullptr, GL_STREAM_DRAW);
294 0 : vbooffset = 0;
295 : }
296 0 : else if(!lastvertexsize)
297 : {
298 0 : glBindBuffer(GL_ARRAY_BUFFER, vbo);
299 : }
300 0 : void *buf = glMapBufferRange(GL_ARRAY_BUFFER, vbooffset, len, GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
301 0 : if(buf)
302 : {
303 0 : attribbuf.reset(static_cast<uchar *>(buf), len);
304 : }
305 0 : }
306 :
307 0 : void multidraw()
308 : {
309 0 : int start = multidrawstart.size() ? multidrawstart.back() + multidrawcount.back() : 0,
310 0 : count = attribbuf.length()/vertexsize - start;
311 0 : if(count > 0)
312 : {
313 0 : multidrawstart.push_back(start);
314 0 : multidrawcount.push_back(count);
315 : }
316 0 : }
317 :
318 0 : int end()
319 : {
320 0 : uchar *buf = attribbuf.getbuf();
321 0 : if(attribbuf.empty())
322 : {
323 0 : if(buf != attribdata)
324 : {
325 0 : glUnmapBuffer(GL_ARRAY_BUFFER);
326 0 : attribbuf.reset(attribdata, maxvbosize);
327 : }
328 0 : return 0;
329 : }
330 0 : int start = 0;
331 0 : if(buf == attribdata)
332 : {
333 0 : if(vbooffset + attribbuf.length() >= maxvbosize)
334 : {
335 0 : if(!vbo)
336 : {
337 0 : glGenBuffers(1, &vbo);
338 : }
339 0 : glBindBuffer(GL_ARRAY_BUFFER, vbo);
340 0 : glBufferData(GL_ARRAY_BUFFER, maxvbosize, nullptr, GL_STREAM_DRAW);
341 0 : vbooffset = 0;
342 : }
343 0 : else if(!lastvertexsize)
344 : {
345 0 : glBindBuffer(GL_ARRAY_BUFFER, vbo);
346 : }
347 : //void pointer warning!
348 0 : void *dst = glMapBufferRange(GL_ARRAY_BUFFER, vbooffset, attribbuf.length(), GL_MAP_WRITE_BIT|GL_MAP_INVALIDATE_RANGE_BIT|GL_MAP_UNSYNCHRONIZED_BIT);
349 0 : std::memcpy(dst, attribbuf.getbuf(), attribbuf.length());
350 0 : glUnmapBuffer(GL_ARRAY_BUFFER);
351 : }
352 : else
353 : {
354 0 : glUnmapBuffer(GL_ARRAY_BUFFER);
355 : }
356 0 : buf = static_cast<uchar *>(nullptr) + vbooffset;
357 0 : if(vertexsize == lastvertexsize && buf >= lastbuf)
358 : {
359 0 : start = static_cast<int>(buf - lastbuf)/vertexsize;
360 0 : buf = lastbuf;
361 : }
362 0 : vbooffset += attribbuf.length();
363 0 : setattribs(buf);
364 0 : int numvertexes = attribbuf.length()/vertexsize;
365 0 : if(multidrawstart.size())
366 : {
367 0 : multidraw();
368 0 : if(start)
369 : {
370 : //offset the buffer indices by start point
371 0 : for(GLint &i : multidrawstart)
372 : {
373 0 : i += start;
374 : }
375 : }
376 0 : glMultiDrawArrays(primtype, multidrawstart.data(), multidrawcount.data(), multidrawstart.size());
377 0 : multidrawstart.clear();
378 0 : multidrawcount.clear();
379 : }
380 : else
381 : {
382 0 : glDrawArrays(primtype, start, numvertexes);
383 : }
384 0 : attribbuf.reset(attribdata, maxvbosize);
385 0 : return numvertexes;
386 : }
387 :
388 0 : static void forcedisable()
389 : {
390 0 : for(int i = 0; enabled; i++)
391 : {
392 0 : if(enabled&(1<<i))
393 : {
394 0 : glDisableVertexAttribArray(i);
395 0 : enabled &= ~(1<<i);
396 : }
397 : }
398 0 : numlastattribs = lastattribmask = lastvertexsize = 0;
399 0 : lastbuf = nullptr;
400 0 : if(quadsenabled)
401 : {
402 0 : disablequads();
403 : }
404 0 : glBindBuffer(GL_ARRAY_BUFFER, 0);
405 0 : }
406 :
407 0 : void disable()
408 : {
409 0 : if(enabled)
410 : {
411 0 : forcedisable();
412 : }
413 0 : }
414 :
415 0 : void setup()
416 : {
417 0 : if(!defaultvao)
418 : {
419 0 : glGenVertexArrays(1, &defaultvao);
420 : }
421 0 : glBindVertexArray(defaultvao);
422 0 : attribdata = new uchar[maxvbosize];
423 0 : attribbuf.reset(attribdata, maxvbosize);
424 0 : }
425 :
426 0 : void cleanup()
427 : {
428 0 : disable();
429 0 : if(quadindexes)
430 : {
431 0 : glDeleteBuffers(1, &quadindexes);
432 0 : quadindexes = 0;
433 : }
434 0 : if(vbo)
435 : {
436 0 : glDeleteBuffers(1, &vbo);
437 0 : vbo = 0;
438 : }
439 0 : vbooffset = maxvbosize;
440 0 : if(defaultvao)
441 : {
442 0 : glDeleteVertexArrays(1, &defaultvao);
443 0 : defaultvao = 0;
444 : }
445 0 : }
446 :
447 0 : void defvertex(int size, int format)
448 : {
449 0 : defattrib(Attribute_Vertex, size, format);
450 0 : }
451 :
452 0 : void defcolor(int size, int format)
453 : {
454 0 : defattrib(Attribute_Color, size, format);
455 0 : }
456 :
457 0 : void deftexcoord0(int size, int format)
458 : {
459 0 : defattrib(Attribute_TexCoord0, size, format);
460 0 : }
461 :
462 0 : void defnormal(int size, int format)
463 : {
464 0 : defattrib(Attribute_Normal, size, format);
465 0 : }
466 :
467 0 : void colorf(float x, float y, float z, float w)
468 : {
469 0 : if(w != 0.0f)
470 : {
471 0 : glVertexAttrib4f(Attribute_Color, x, y, z, w);
472 : }
473 : else
474 : {
475 0 : glVertexAttrib3f(Attribute_Color, x, y, z);
476 : }
477 0 : }
478 :
479 0 : void color(const vec &v)
480 : {
481 0 : glVertexAttrib3fv(Attribute_Color, v.data());
482 0 : }
483 :
484 0 : void color(const vec &v, float w)
485 : {
486 0 : glVertexAttrib4f(Attribute_Color, v.x, v.y, v.z, w);
487 0 : }
488 :
489 0 : void colorub(uchar x, uchar y, uchar z, uchar w)
490 : {
491 0 : glVertexAttrib4Nub(Attribute_Color, x, y, z, w);
492 0 : }
493 :
494 0 : void color(const bvec &v, uchar alpha)
495 : {
496 0 : glVertexAttrib4Nub(Attribute_Color, v.x, v.y, v.z, alpha);
497 0 : }
498 :
499 0 : void enablevertex()
500 : {
501 0 : disable();
502 0 : glEnableVertexAttribArray(Attribute_Vertex);
503 0 : }
504 :
505 0 : void disablevertex()
506 : {
507 0 : glDisableVertexAttribArray(Attribute_Vertex);
508 0 : }
509 0 : void vertexpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
510 : {
511 0 : disable();
512 0 : glVertexAttribPointer(Attribute_Vertex, size, type, normalized, stride, data);
513 0 : }
514 0 : void enablecolor()
515 : {
516 0 : glEnableVertexAttribArray(Attribute_Color);
517 0 : }
518 0 : void disablecolor()
519 : {
520 0 : glDisableVertexAttribArray(Attribute_Color);
521 0 : }
522 0 : void colorpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
523 : {
524 0 : glVertexAttribPointer(Attribute_Color, size, type, normalized, stride, data);
525 0 : }
526 :
527 0 : void enabletexcoord0()
528 : {
529 0 : glEnableVertexAttribArray(Attribute_TexCoord0);
530 0 : }
531 :
532 0 : void disabletexcoord0()
533 : {
534 0 : glDisableVertexAttribArray(Attribute_TexCoord0);
535 0 : }
536 :
537 0 : void texcoord0pointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
538 : {
539 0 : glVertexAttribPointer(Attribute_TexCoord0, size, type, normalized, stride, data);
540 0 : }
541 :
542 0 : void enablenormal()
543 : {
544 0 : glEnableVertexAttribArray(Attribute_Normal);
545 0 : }
546 :
547 0 : void disablenormal()
548 : {
549 0 : glDisableVertexAttribArray(Attribute_Normal);
550 0 : }
551 :
552 0 : void normalpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
553 : {
554 0 : glVertexAttribPointer(Attribute_Normal, size, type, normalized, stride, data);
555 0 : }
556 :
557 0 : void enabletangent()
558 : {
559 0 : glEnableVertexAttribArray(Attribute_Tangent);
560 0 : }
561 :
562 0 : void disabletangent()
563 : {
564 0 : glDisableVertexAttribArray(Attribute_Tangent);
565 0 : }
566 :
567 0 : void tangentpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
568 : {
569 0 : glVertexAttribPointer(Attribute_Tangent, size, type, normalized, stride, data);
570 0 : }
571 :
572 0 : void enableboneweight()
573 : {
574 0 : glEnableVertexAttribArray(Attribute_BoneWeight);
575 0 : }
576 :
577 0 : void disableboneweight()
578 : {
579 0 : glDisableVertexAttribArray(Attribute_BoneWeight);
580 0 : }
581 :
582 0 : void boneweightpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
583 : {
584 0 : glVertexAttribPointer(Attribute_BoneWeight, size, type, normalized, stride, data);
585 0 : }
586 :
587 0 : void enableboneindex()
588 : {
589 0 : glEnableVertexAttribArray(Attribute_BoneIndex);
590 0 : }
591 :
592 0 : void disableboneindex()
593 : {
594 0 : glDisableVertexAttribArray(Attribute_BoneIndex);
595 0 : }
596 :
597 0 : void boneindexpointer(int stride, const void *data, GLenum type, int size, GLenum normalized)
598 : {
599 0 : glVertexAttribPointer(Attribute_BoneIndex, size, type, normalized, stride, data);
600 0 : }
601 :
602 0 : void bindebo(GLuint ebo)
603 : {
604 0 : disable();
605 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
606 0 : }
607 :
608 0 : void clearebo()
609 : {
610 0 : glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
611 0 : }
612 :
613 0 : void bindvbo(GLuint bindvbo)
614 : {
615 0 : disable();
616 0 : glBindBuffer(GL_ARRAY_BUFFER, bindvbo);
617 0 : }
618 :
619 0 : void clearvbo()
620 : {
621 0 : glBindBuffer(GL_ARRAY_BUFFER, 0);
622 0 : }
623 :
624 : template<class T>
625 0 : void attrib(T x, T y)
626 : {
627 0 : if(attribbuf.check(2*sizeof(T)))
628 : {
629 0 : T *buf = reinterpret_cast<T *>(attribbuf.pad(2*sizeof(T)));
630 0 : buf[0] = x;
631 0 : buf[1] = y;
632 : }
633 0 : }
634 :
635 : template<class T>
636 0 : void attrib(T x, T y, T z)
637 : {
638 0 : if(attribbuf.check(3*sizeof(T)))
639 : {
640 0 : T *buf = reinterpret_cast<T *>(attribbuf.pad(3*sizeof(T)));
641 0 : buf[0] = x;
642 0 : buf[1] = y;
643 0 : buf[2] = z;
644 : }
645 0 : }
646 :
647 : template<class T>
648 0 : void attrib(T x, T y, T z, T w)
649 : {
650 0 : if(attribbuf.check(4*sizeof(T)))
651 : {
652 0 : T *buf = reinterpret_cast<T *>(attribbuf.pad(4*sizeof(T)));
653 0 : buf[0] = x;
654 0 : buf[1] = y;
655 0 : buf[2] = z;
656 0 : buf[3] = w;
657 : }
658 0 : }
659 :
660 0 : void attribf(float x, float y)
661 : {
662 0 : attrib<float>(x, y);
663 0 : }
664 :
665 0 : void attribf(float x, float y, float z)
666 : {
667 0 : attrib<float>(x, y, z);
668 0 : }
669 :
670 0 : void attribub(uchar x, uchar y, uchar z, uchar w)
671 : {
672 0 : attrib<uchar>(x, y, z, w);
673 0 : }
674 :
675 0 : void attrib(const vec &v)
676 : {
677 0 : attrib<float>(v.x, v.y, v.z);
678 0 : }
679 :
680 0 : void attrib(const vec &v, float w)
681 : {
682 0 : attrib<float>(v.x, v.y, v.z, w);
683 0 : }
684 :
685 0 : void attrib(const vec2 &v)
686 : {
687 0 : attrib<float>(v.x, v.y);
688 0 : }
689 : }
690 :
|