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