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