1 /*
2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
3 *
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on the
6 * source.
7 *
8 */
9
10
11 #include "gropenglshader.h"
12 #include "graphics/material.h"
13 #include "gropenglstate.h"
14 #include "math/vecmat.h"
15
16 extern GLfloat GL_max_anisotropy;
17
18
19 opengl_state GL_state;
20
21
~opengl_texture_state()22 opengl_texture_state::~opengl_texture_state()
23 {
24 if (units != NULL) {
25 vm_free(units);
26 }
27 }
28
init(GLuint n_units)29 void opengl_texture_state::init(GLuint n_units)
30 {
31 Assert( n_units > 0 );
32 units = (opengl_texture_unit*) vm_malloc(n_units * sizeof(opengl_texture_unit));
33 num_texture_units = n_units;
34
35 for (unsigned int unit = 0; unit < num_texture_units; unit++) {
36 units[unit].enabled = GL_FALSE;
37
38 default_values(unit);
39
40 glActiveTexture(GL_TEXTURE0 + unit);
41 }
42
43 SetActiveUnit();
44 }
45
default_values(GLint unit,GLenum target)46 void opengl_texture_state::default_values(GLint unit, GLenum target)
47 {
48 glActiveTexture(GL_TEXTURE0 + unit);
49
50 if (target == GL_INVALID_ENUM) {
51
52 glBindTexture(GL_TEXTURE_2D, 0);
53 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
54
55 units[unit].texture_target = GL_TEXTURE_2D;
56 units[unit].texture_id = 0;
57 }
58 }
59
SetTarget(GLenum tex_target)60 void opengl_texture_state::SetTarget(GLenum tex_target)
61 {
62 if (units[active_texture_unit].texture_target != tex_target) {
63
64 if (units[active_texture_unit].texture_id) {
65 glBindTexture(units[active_texture_unit].texture_target, 0);
66 units[active_texture_unit].texture_id = 0;
67 }
68
69 // reset modes, since those were only valid for the previous texture target
70 default_values(active_texture_unit, tex_target);
71 units[active_texture_unit].texture_target = tex_target;
72 }
73 }
74
SetActiveUnit(GLuint id)75 void opengl_texture_state::SetActiveUnit(GLuint id)
76 {
77 if (id >= num_texture_units) {
78 Int3();
79 id = 0;
80 }
81
82 glActiveTexture(GL_TEXTURE0 + id);
83
84 active_texture_unit = id;
85 }
86
Enable(GLuint tex_id)87 void opengl_texture_state::Enable(GLuint tex_id)
88 {
89 if ( units[active_texture_unit].texture_id == tex_id ) {
90 return;
91 }
92
93 if (units[active_texture_unit].texture_id != tex_id) {
94 glBindTexture(units[active_texture_unit].texture_target, tex_id);
95 units[active_texture_unit].texture_id = tex_id;
96 }
97 }
98
Enable(GLuint unit,GLenum tex_target,GLuint tex_id)99 void opengl_texture_state::Enable(GLuint unit, GLenum tex_target, GLuint tex_id) {
100 Assertion(unit < num_texture_units, "Invalid texture unit value!");
101
102 if (units[unit].texture_target == tex_target && units[unit].texture_id == tex_id) {
103 // The texture unit already uses this texture. There is no need to change it
104 return;
105 }
106
107 // Go the standard route
108 SetActiveUnit(unit);
109 SetTarget(tex_target);
110 Enable(tex_id);
111 }
112
Delete(GLuint tex_id)113 void opengl_texture_state::Delete(GLuint tex_id)
114 {
115 if (tex_id == 0) {
116 Int3();
117 return;
118 }
119
120 GLuint atu_save = active_texture_unit;
121
122 for (unsigned int i = 0; i < num_texture_units; i++) {
123 if (units[i].texture_id == tex_id) {
124 SetActiveUnit(i);
125
126 glBindTexture(units[i].texture_target, 0);
127 units[i].texture_id = 0;
128
129 default_values(i, units[i].texture_target);
130
131 if (i == atu_save) {
132 atu_save = 0;
133 }
134 }
135 }
136
137 SetActiveUnit(atu_save);
138 }
139
init()140 void opengl_state::init()
141 {
142 int i;
143
144 glDisable(GL_BLEND);
145 blend_Status = GL_FALSE;
146
147 glDisable(GL_DEPTH_TEST);
148 depthtest_Status = GL_FALSE;
149
150 glDisable(GL_SCISSOR_TEST);
151 scissortest_Status = GL_FALSE;
152
153 glDisable(GL_CULL_FACE);
154 cullface_Status = GL_FALSE;
155
156 glDisable(GL_POLYGON_OFFSET_FILL);
157 polygonoffsetfill_Status = GL_FALSE;
158
159 polygon_offset_Factor = 0.0f;
160 polygon_offset_Unit = 0.0f;
161
162 normalize_Status = GL_FALSE;
163
164 for (i = 0; i < (int)(sizeof(clipplane_Status) / sizeof(GLboolean)); i++) {
165 //glDisable(GL_CLIP_PLANE0+i);
166 clipplane_Status[i] = GL_FALSE;
167 }
168
169 for (i = 0; i < (int)(sizeof(clipdistance_Status) / sizeof(GLboolean)); i++) {
170 //glDisable(GL_CLIP_DISTANCE0+i);
171 clipdistance_Status[i] = GL_FALSE;
172 }
173
174 glDepthMask(GL_FALSE);
175 depthmask_Status = GL_FALSE;
176
177 glFrontFace(GL_CCW);
178 frontface_Value = GL_CCW;
179
180 glCullFace(GL_BACK);
181 cullface_Value = GL_BACK;
182
183 glBlendFunc(GL_ONE, GL_ZERO);
184 blendfunc_Value.first = GL_ONE;
185 blendfunc_Value.first = GL_ZERO;
186 buffer_blendfunc_Value.fill(blendfunc_Value);
187
188 glDepthFunc(GL_LESS);
189 depthfunc_Value = GL_LESS;
190
191 glGetFloatv(GL_LINE_WIDTH, &line_width_Value);
192
193 current_program = 0;
194 glUseProgram(0);
195
196 current_framebuffer = 0;
197 glBindFramebuffer(GL_FRAMEBUFFER, 0);
198
199 framebuffer_stack.clear();
200
201 stencilFunc = GL_ALWAYS;
202 stencilFuncRef = 0;
203 stencilFuncMask = 0xFFFFFFFF;
204 glStencilFunc(stencilFunc, stencilFuncRef, stencilFuncMask);
205
206 stencilMask = 0xFFFFFFFF;
207 glStencilMask(stencilMask);
208
209 stencilOpFrontStencilFail = GL_KEEP;
210 stencilOpFrontDepthFail = GL_KEEP;
211 stencilOpFrontPass = GL_KEEP;
212
213 stencilOpBackStencilFail = GL_KEEP;
214 stencilOpBackDepthFail = GL_KEEP;
215 stencilOpBackPass = GL_KEEP;
216
217 glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
218
219 colormask_Status.x = true;
220 colormask_Status.y = true;
221 colormask_Status.z = true;
222 colormask_Status.w = true;
223 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
224 }
225
Blend(GLint state)226 GLboolean opengl_state::Blend(GLint state)
227 {
228 GLboolean save_state = blend_Status;
229
230 if ( !((state == -1) || (state == blend_Status)) ) {
231 if (state) {
232 Assert( state == GL_TRUE );
233 glEnable(GL_BLEND);
234 blend_Status = GL_TRUE;
235 } else {
236 glDisable(GL_BLEND);
237 blend_Status = GL_FALSE;
238 }
239 }
240
241 return save_state;
242 }
243
DepthTest(GLint state)244 GLboolean opengl_state::DepthTest(GLint state)
245 {
246 GLboolean save_state = depthtest_Status;
247
248 if ( !((state == -1) || (state == depthtest_Status)) ) {
249 if (state) {
250 Assert( state == GL_TRUE );
251 glEnable(GL_DEPTH_TEST);
252 depthtest_Status = GL_TRUE;
253 } else {
254 glDisable(GL_DEPTH_TEST);
255 depthtest_Status = GL_FALSE;
256 }
257 }
258
259 return save_state;
260 }
261
ScissorTest(GLint state)262 GLboolean opengl_state::ScissorTest(GLint state)
263 {
264 GLboolean save_state = scissortest_Status;
265
266 if ( !((state == -1) || (state == scissortest_Status)) ) {
267 if (state) {
268 Assert( state == GL_TRUE );
269 glEnable(GL_SCISSOR_TEST);
270 scissortest_Status = GL_TRUE;
271 } else {
272 glDisable(GL_SCISSOR_TEST);
273 scissortest_Status = GL_FALSE;
274 }
275 }
276
277 return save_state;
278 }
279
StencilTest(GLint state)280 GLboolean opengl_state::StencilTest(GLint state)
281 {
282 GLboolean save_state = stenciltest_Status;
283
284 if ( !((state == -1) || (state == stenciltest_Status)) ) {
285 if (state) {
286 Assert( state == GL_TRUE );
287 glEnable(GL_STENCIL_TEST);
288 stenciltest_Status = GL_TRUE;
289 } else {
290 glDisable(GL_STENCIL_TEST);
291 stenciltest_Status = GL_FALSE;
292 }
293 }
294
295 return save_state;
296 }
297
CullFace(GLint state)298 GLboolean opengl_state::CullFace(GLint state)
299 {
300 GLboolean save_state = cullface_Status;
301
302 if ( !((state == -1) || (state == cullface_Status)) ) {
303 if (state) {
304 Assert( state == GL_TRUE );
305 glEnable(GL_CULL_FACE);
306 cullface_Status = GL_TRUE;
307 } else {
308 glDisable(GL_CULL_FACE);
309 cullface_Status = GL_FALSE;
310 }
311 }
312
313 return save_state;
314 }
315
SetPolygonMode(GLenum face,GLenum mode)316 void opengl_state::SetPolygonMode(GLenum face, GLenum mode)
317 {
318 if ( polygon_mode_Face != face || polygon_mode_Mode != mode ) {
319 glPolygonMode(face, mode);
320
321 polygon_mode_Face = face;
322 polygon_mode_Mode = mode;
323 }
324 }
325
SetPolygonOffset(GLfloat factor,GLfloat units)326 void opengl_state::SetPolygonOffset(GLfloat factor, GLfloat units)
327 {
328 if ( polygon_offset_Factor != factor || polygon_offset_Unit != units) {
329 glPolygonOffset(factor, units);
330
331 polygon_offset_Factor = factor;
332 polygon_offset_Unit = units;
333 }
334 }
335
PolygonOffsetFill(GLint state)336 GLboolean opengl_state::PolygonOffsetFill(GLint state)
337 {
338 GLboolean save_state = polygonoffsetfill_Status;
339
340 if ( !((state == -1) || (state == polygonoffsetfill_Status)) ) {
341 if (state) {
342 Assert( state == GL_TRUE );
343 glEnable(GL_POLYGON_OFFSET_FILL);
344 polygonoffsetfill_Status = GL_TRUE;
345 } else {
346 glDisable(GL_POLYGON_OFFSET_FILL);
347 polygonoffsetfill_Status = GL_FALSE;
348 }
349 }
350
351 return save_state;
352 }
353
ClipDistance(GLint num,bool state)354 GLboolean opengl_state::ClipDistance(GLint num, bool state)
355 {
356 Assert( (num >= 0) && (num < (int)(sizeof(clipdistance_Status) / sizeof(GLboolean))) );
357
358 GLboolean save_state = clipdistance_Status[num];
359
360 if (state != clipdistance_Status[num]) {
361 if (state) {
362 glEnable(GL_CLIP_DISTANCE0+num);
363 } else {
364 glDisable(GL_CLIP_DISTANCE0+num);
365 }
366 clipdistance_Status[num] = state;
367 }
368
369 return save_state;
370 }
371
DepthMask(GLint state)372 GLboolean opengl_state::DepthMask(GLint state)
373 {
374 GLboolean save_state = depthmask_Status;
375
376 if ( !((state == -1) || (state == depthmask_Status)) ) {
377 if (state) {
378 Assert( state == GL_TRUE );
379 glDepthMask(GL_TRUE);
380 depthmask_Status = GL_TRUE;
381 } else {
382 glDepthMask(GL_FALSE);
383 depthmask_Status = GL_FALSE;
384 }
385 }
386
387 return save_state;
388 }
389
ColorMask(bool red,bool green,bool blue,bool alpha)390 bvec4 opengl_state::ColorMask(bool red, bool green, bool blue, bool alpha)
391 {
392 auto save_state = colormask_Status;
393
394 if (colormask_Status.x != red || colormask_Status.y != green || colormask_Status.z != blue
395 || colormask_Status.w != alpha) {
396 glColorMask(red ? GL_TRUE : GL_FALSE,
397 green ? GL_TRUE : GL_FALSE,
398 blue ? GL_TRUE : GL_FALSE,
399 alpha ? GL_TRUE : GL_FALSE);
400 colormask_Status = { red, green, blue, alpha };
401 }
402
403 return save_state;
404 }
405
BlendFunc(GLenum s_val,GLenum d_val)406 void opengl_state::BlendFunc(GLenum s_val, GLenum d_val)
407 {
408 if (s_val != blendfunc_Value.first || d_val != blendfunc_Value.second) {
409 glBlendFunc(s_val, d_val);
410 blendfunc_Value.first = s_val;
411 blendfunc_Value.second = d_val;
412
413 // This has set all the buffer blend modes as well
414 buffer_blendfunc_Value.fill(blendfunc_Value);
415 }
416 }
BlendFunci(int buffer,GLenum s_val,GLenum d_val)417 void opengl_state::BlendFunci(int buffer, GLenum s_val, GLenum d_val) {
418 Assertion(GLAD_GL_ARB_draw_buffers_blend != 0, "Buffer blend modes are not supported by this OpenGL implementation!");
419 Assertion(buffer >= 0 && buffer < (int) buffer_blendfunc_Value.size(), "Unsupported index %d specified for buffer blend mode!", buffer);
420
421 auto& state = buffer_blendfunc_Value[buffer];
422 if (state.first == s_val && state.second == d_val) {
423 // Already uses the correct blend mode
424 return;
425 }
426
427 glBlendFunciARB(buffer, s_val, d_val);
428
429 // Update the saved state
430 state.first = s_val;
431 state.second = d_val;
432 // Set the non-buffer values to an invalid value to make sure that the next call to BlendFunc resets the state.
433 blendfunc_Value.first = GL_INVALID_ENUM;
434 blendfunc_Value.second = GL_INVALID_ENUM;
435 }
436
SetAlphaBlendMode(gr_alpha_blend ab)437 void opengl_state::SetAlphaBlendMode(gr_alpha_blend ab)
438 {
439 switch (ab) {
440 case ALPHA_BLEND_ALPHA_BLEND_ALPHA:
441 GL_state.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
442 break;
443
444 case ALPHA_BLEND_NONE:
445 GL_state.BlendFunc(GL_ONE, GL_ZERO);
446 break;
447
448 case ALPHA_BLEND_ADDITIVE:
449 GL_state.BlendFunc(GL_ONE, GL_ONE);
450 break;
451
452 case ALPHA_BLEND_ALPHA_ADDITIVE:
453 GL_state.BlendFunc(GL_SRC_ALPHA, GL_ONE);
454 break;
455
456 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR:
457 GL_state.BlendFunc(/*GL_SRC_COLOR*/GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
458 break;
459
460 case ALPHA_BLEND_PREMULTIPLIED:
461 GL_state.BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
462 break;
463
464 default:
465 break;
466 }
467
468 GL_state.Blend( (ab == ALPHA_BLEND_NONE) ? GL_FALSE : GL_TRUE );
469 }
470
SetAlphaBlendModei(int buffer,gr_alpha_blend ab)471 void opengl_state::SetAlphaBlendModei(int buffer, gr_alpha_blend ab)
472 {
473 switch (ab) {
474 case ALPHA_BLEND_ALPHA_BLEND_ALPHA:
475 GL_state.BlendFunci(buffer, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
476 break;
477
478 case ALPHA_BLEND_NONE:
479 GL_state.BlendFunci(buffer, GL_ONE, GL_ZERO);
480 break;
481
482 case ALPHA_BLEND_ADDITIVE:
483 GL_state.BlendFunci(buffer, GL_ONE, GL_ONE);
484 break;
485
486 case ALPHA_BLEND_ALPHA_ADDITIVE:
487 GL_state.BlendFunci(buffer, GL_SRC_ALPHA, GL_ONE);
488 break;
489
490 case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR:
491 GL_state.BlendFunci(buffer, /*GL_SRC_COLOR*/GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
492 break;
493
494 case ALPHA_BLEND_PREMULTIPLIED:
495 GL_state.BlendFunci(buffer, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
496 break;
497
498 default:
499 break;
500 }
501 }
502
SetZbufferType(gr_zbuffer_type zt)503 void opengl_state::SetZbufferType(gr_zbuffer_type zt)
504 {
505 switch (zt) {
506 case ZBUFFER_TYPE_NONE:
507 GL_state.DepthFunc(GL_ALWAYS);
508 GL_state.DepthMask(GL_FALSE);
509 break;
510
511 case ZBUFFER_TYPE_READ:
512 GL_state.DepthFunc(GL_LESS);
513 GL_state.DepthMask(GL_FALSE);
514 break;
515
516 case ZBUFFER_TYPE_WRITE:
517 GL_state.DepthFunc(GL_ALWAYS);
518 GL_state.DepthMask(GL_TRUE);
519 break;
520
521 case ZBUFFER_TYPE_FULL:
522 GL_state.DepthFunc(GL_LESS);
523 GL_state.DepthMask(GL_TRUE);
524 break;
525
526 default:
527 break;
528 }
529
530 GL_state.DepthTest( (zt == ZBUFFER_TYPE_NONE) ? GL_FALSE : GL_TRUE );
531 }
532
SetLineWidth(GLfloat width)533 void opengl_state::SetLineWidth(GLfloat width)
534 {
535 if ( width == line_width_Value ) {
536 return;
537 }
538
539 glLineWidth(width);
540 line_width_Value = width;
541 }
UseProgram(GLuint program)542 void opengl_state::UseProgram(GLuint program)
543 {
544 if (current_program == program) {
545 return;
546 }
547
548 current_program = program;
549 glUseProgram(program);
550 }
IsCurrentProgram(GLuint program)551 bool opengl_state::IsCurrentProgram(GLuint program) {
552 return current_program == program;
553 }
BindFrameBuffer(GLuint name)554 void opengl_state::BindFrameBuffer(GLuint name) {
555 if (current_framebuffer != name) {
556 glBindFramebuffer(GL_FRAMEBUFFER, name);
557 current_framebuffer = name;
558 }
559 }
PushFramebufferState()560 void opengl_state::PushFramebufferState() {
561 framebuffer_stack.push_back(current_framebuffer);
562 }
PopFramebufferState()563 void opengl_state::PopFramebufferState() {
564 Assertion(framebuffer_stack.size() > 0, "Tried to pop the framebuffer state stack while it was empty!");
565
566 auto restoreBuffer = framebuffer_stack.back();
567 framebuffer_stack.pop_back();
568
569 BindFrameBuffer(restoreBuffer);
570 }
BindVertexArray(GLuint vao)571 void opengl_state::BindVertexArray(GLuint vao) {
572 if (current_vao == vao) {
573 return;
574 }
575
576 glBindVertexArray(vao);
577 current_vao = vao;
578
579 Array.VertexArrayChanged();
580 }
StencilFunc(GLenum func,GLint ref,GLuint mask)581 void opengl_state::StencilFunc(GLenum func, GLint ref, GLuint mask) {
582 if (stencilFunc == func && stencilFuncRef == ref && stencilFuncMask == mask) {
583 return;
584 }
585
586 glStencilFunc(func, ref, mask);
587
588 stencilFunc = func;
589 stencilFuncRef = ref;
590 stencilFuncMask = mask;
591 }
StencilOpSeparate(GLenum face,GLenum sfail,GLenum dpfail,GLenum dppass)592 void opengl_state::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
593 if (face == GL_FRONT_AND_BACK) {
594 StencilOpSeparate(GL_FRONT, sfail, dpfail, dppass);
595 StencilOpSeparate(GL_BACK, sfail, dpfail, dppass);
596 return;
597 }
598
599 if (face == GL_FRONT) {
600 if (stencilOpFrontStencilFail == sfail && stencilOpFrontDepthFail == dpfail && stencilOpFrontPass == dppass) {
601 return;
602 }
603
604 glStencilOpSeparate(GL_FRONT, sfail, dpfail, dppass);
605
606 stencilOpFrontStencilFail = sfail;
607 stencilOpFrontDepthFail = dpfail;
608 stencilOpFrontPass = dppass;
609 } else {
610 if (stencilOpBackStencilFail == sfail && stencilOpBackDepthFail == dpfail && stencilOpBackPass == dppass) {
611 return;
612 }
613
614 glStencilOpSeparate(GL_BACK, sfail, dpfail, dppass);
615
616 stencilOpBackStencilFail = sfail;
617 stencilOpBackDepthFail = dpfail;
618 stencilOpBackPass = dppass;
619 }
620 }
StencilMask(GLuint mask)621 void opengl_state::StencilMask(GLuint mask) {
622 if (stencilMask == mask) {
623 return;
624 }
625
626 glStencilMask(mask);
627 stencilMask = mask;
628 }
629
~opengl_array_state()630 opengl_array_state::~opengl_array_state()
631 {
632 if ( client_texture_units != NULL ) {
633 vm_free(client_texture_units);
634 }
635 }
636
init(GLuint n_units)637 void opengl_array_state::init(GLuint n_units)
638 {
639 Assert( n_units > 0 );
640 client_texture_units = (opengl_client_texture_unit*) vm_malloc(n_units * sizeof(opengl_client_texture_unit));
641 num_client_texture_units = n_units;
642 active_client_texture_unit = 0;
643
644 for (unsigned int i = 0; i < num_client_texture_units; i++) {
645 client_texture_units[i].pointer = 0;
646 client_texture_units[i].size = 4;
647 client_texture_units[i].status = GL_FALSE;
648 client_texture_units[i].stride = 0;
649 client_texture_units[i].type = GL_FLOAT;
650 client_texture_units[i].buffer = 0;
651 client_texture_units[i].reset_ptr = false;
652 client_texture_units[i].used_for_draw = false;
653 }
654
655 array_buffer = 0;
656 element_array_buffer = 0;
657 texture_array_buffer = 0;
658 uniform_buffer = 0;
659 }
660
EnableVertexAttrib(GLuint index)661 void opengl_array_state::EnableVertexAttrib(GLuint index)
662 {
663 opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
664
665 va_unit->used_for_draw = true;
666
667 if ( va_unit->status_init && va_unit->status == GL_TRUE ) {
668 return;
669 }
670
671 glEnableVertexAttribArray(index);
672 va_unit->status = GL_TRUE;
673 va_unit->status_init = true;
674 }
675
DisableVertexAttrib(GLuint index)676 void opengl_array_state::DisableVertexAttrib(GLuint index)
677 {
678 opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
679
680 if ( va_unit->status_init && va_unit->status == GL_FALSE ) {
681 return;
682 }
683
684 glDisableVertexAttribArray(index);
685 va_unit->status = GL_FALSE;
686 va_unit->status_init = true;
687 }
688
VertexAttribPointer(GLuint index,GLint size,GLenum type,GLboolean normalized,GLsizei stride,GLvoid * pointer)689 void opengl_array_state::VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid *pointer)
690 {
691 opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
692
693 if (
694 !va_unit->reset_ptr
695 && va_unit->ptr_init
696 && va_unit->normalized == normalized
697 && va_unit->pointer == pointer
698 && va_unit->size == size
699 && va_unit->stride == stride
700 && va_unit->type == type
701 && va_unit->buffer == array_buffer
702 ) {
703 return;
704 }
705
706 glVertexAttribPointer(index, size, type, normalized, stride, pointer);
707
708 va_unit->normalized = normalized;
709 va_unit->pointer = pointer;
710 va_unit->size = size;
711 va_unit->stride = stride;
712 va_unit->type = type;
713 va_unit->buffer = array_buffer;
714 va_unit->reset_ptr = false;
715
716 va_unit->ptr_init = true;
717 }
718
ResetVertexAttribs()719 void opengl_array_state::ResetVertexAttribs()
720 {
721 for (auto &it : vertex_attrib_units) {
722 DisableVertexAttrib(it.first);
723 }
724
725 vertex_attrib_units.clear();
726 }
727
BindPointersBegin()728 void opengl_array_state::BindPointersBegin()
729 {
730 for (unsigned int i = 0; i < num_client_texture_units; i++) {
731 client_texture_units[i].used_for_draw = false;
732 }
733
734 for (auto &it : vertex_attrib_units) {
735 it.second.used_for_draw = false;
736 }
737 }
738
BindPointersEnd()739 void opengl_array_state::BindPointersEnd()
740 {
741 for (auto &it : vertex_attrib_units) {
742 if (!it.second.used_for_draw) {
743 DisableVertexAttrib(it.first);
744 }
745 }
746 }
747
BindArrayBuffer(GLuint id)748 void opengl_array_state::BindArrayBuffer(GLuint id)
749 {
750 if ( array_buffer_valid && array_buffer == id ) {
751 return;
752 }
753
754 glBindBuffer(GL_ARRAY_BUFFER, id);
755
756 array_buffer = id;
757 array_buffer_valid = true;
758
759 for (unsigned int i = 0; i < num_client_texture_units; i++) {
760 client_texture_units[i].reset_ptr = true;
761 }
762
763 for (auto &it : vertex_attrib_units) {
764 it.second.reset_ptr = true;
765 }
766 }
767
BindElementBuffer(GLuint id)768 void opengl_array_state::BindElementBuffer(GLuint id)
769 {
770 if ( element_array_buffer_valid && element_array_buffer == id ) {
771 return;
772 }
773
774 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
775
776 element_array_buffer = id;
777 element_array_buffer_valid = true;
778 }
779
BindTextureBuffer(GLuint id)780 void opengl_array_state::BindTextureBuffer(GLuint id)
781 {
782 if ( texture_array_buffer == id ) {
783 return;
784 }
785
786 glBindBuffer(GL_TEXTURE_BUFFER, id);
787
788 texture_array_buffer = id;
789 }
790
BindUniformBufferBindingIndex(GLuint id,GLuint index)791 void opengl_array_state::BindUniformBufferBindingIndex(GLuint id, GLuint index)
792 {
793 if ( uniform_buffer_index_bindings[index] == id ) {
794 return;
795 }
796
797 glBindBufferBase(GL_UNIFORM_BUFFER, index, id);
798
799 uniform_buffer_index_bindings[index] = id;
800 }
801
BindUniformBuffer(GLuint id)802 void opengl_array_state::BindUniformBuffer(GLuint id)
803 {
804 if ( uniform_buffer == id ) {
805 return;
806 }
807
808 glBindBuffer(GL_UNIFORM_BUFFER, id);
809
810 uniform_buffer = id;
811 }
VertexArrayChanged()812 void opengl_array_state::VertexArrayChanged() {
813 array_buffer_valid = false;
814 element_array_buffer_valid = false;
815
816 for (auto& bindingInfo : vertex_buffer_bindings) {
817 bindingInfo.valid_data = false;
818 }
819 }
BindVertexBuffer(GLuint bindingindex,GLuint buffer,GLintptr offset,GLsizei stride)820 void opengl_array_state::BindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) {
821 if (bindingindex >= vertex_buffer_bindings.size()) {
822 // Make sure that we have the place for this information
823 vertex_buffer_bindings.resize(bindingindex + 1);
824 }
825
826 auto& bindingInfo = vertex_buffer_bindings[bindingindex];
827
828 if (bindingInfo.valid_data && bindingInfo.buffer == buffer && bindingInfo.offset == offset
829 && bindingInfo.stride == stride) {
830 return;
831 }
832
833 glBindVertexBuffer(bindingindex, buffer, offset, stride);
834
835 bindingInfo.valid_data = true;
836 bindingInfo.buffer = buffer;
837 bindingInfo.stride = stride;
838 bindingInfo.offset = offset;
839 }
opengl_constant_state()840 opengl_constant_state::opengl_constant_state() {
841 }
init()842 void opengl_constant_state::init() {
843 glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uniform_buffer_offset_alignment);
844 glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &_max_uniform_block_size);
845 glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &_max_uniform_block_bindings);
846
847 if (GLAD_GL_EXT_texture_filter_anisotropic) {
848 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &_max_anisotropy);
849 } else {
850 _max_anisotropy = -1.0f;
851 }
852 }
GetUniformBufferOffsetAlignment()853 GLint opengl_constant_state::GetUniformBufferOffsetAlignment() {
854 return _uniform_buffer_offset_alignment;
855 }
GetMaxUniformBlockSize()856 GLint opengl_constant_state::GetMaxUniformBlockSize() {
857 return _max_uniform_block_size;
858 }
GetMaxUniformBlockBindings()859 GLint opengl_constant_state::GetMaxUniformBlockBindings() {
860 return _max_uniform_block_bindings;
861 }
GetMaxAnisotropy()862 GLfloat opengl_constant_state::GetMaxAnisotropy() {
863 return _max_anisotropy;
864 }
865
gr_opengl_clear_states()866 void gr_opengl_clear_states()
867 {
868 gr_zbias(0);
869 gr_zbuffer_set(ZBUFFER_TYPE_READ);
870 gr_set_cull(0);
871 gr_set_fill_mode(GR_FILL_MODE_SOLID);
872
873 opengl_shader_set_current();
874 }
875