mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-08 17:48:46 -10:00
875 lines
20 KiB
C++
875 lines
20 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "gropenglshader.h"
|
|
#include "graphics/material.h"
|
|
#include "gropenglstate.h"
|
|
#include "math/vecmat.h"
|
|
|
|
extern GLfloat GL_max_anisotropy;
|
|
|
|
|
|
opengl_state GL_state;
|
|
|
|
|
|
opengl_texture_state::~opengl_texture_state()
|
|
{
|
|
if (units != NULL) {
|
|
vm_free(units);
|
|
}
|
|
}
|
|
|
|
void opengl_texture_state::init(GLuint n_units)
|
|
{
|
|
Assert( n_units > 0 );
|
|
units = (opengl_texture_unit*) vm_malloc(n_units * sizeof(opengl_texture_unit));
|
|
num_texture_units = n_units;
|
|
|
|
for (unsigned int unit = 0; unit < num_texture_units; unit++) {
|
|
units[unit].enabled = GL_FALSE;
|
|
|
|
default_values(unit);
|
|
|
|
glActiveTexture(GL_TEXTURE0 + unit);
|
|
}
|
|
|
|
SetActiveUnit();
|
|
}
|
|
|
|
void opengl_texture_state::default_values(GLint unit, GLenum target)
|
|
{
|
|
glActiveTexture(GL_TEXTURE0 + unit);
|
|
|
|
if (target == GL_INVALID_ENUM) {
|
|
|
|
glBindTexture(GL_TEXTURE_2D, 0);
|
|
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
|
|
|
|
units[unit].texture_target = GL_TEXTURE_2D;
|
|
units[unit].texture_id = 0;
|
|
}
|
|
}
|
|
|
|
void opengl_texture_state::SetTarget(GLenum tex_target)
|
|
{
|
|
if (units[active_texture_unit].texture_target != tex_target) {
|
|
|
|
if (units[active_texture_unit].texture_id) {
|
|
glBindTexture(units[active_texture_unit].texture_target, 0);
|
|
units[active_texture_unit].texture_id = 0;
|
|
}
|
|
|
|
// reset modes, since those were only valid for the previous texture target
|
|
default_values(active_texture_unit, tex_target);
|
|
units[active_texture_unit].texture_target = tex_target;
|
|
}
|
|
}
|
|
|
|
void opengl_texture_state::SetActiveUnit(GLuint id)
|
|
{
|
|
if (id >= num_texture_units) {
|
|
Int3();
|
|
id = 0;
|
|
}
|
|
|
|
glActiveTexture(GL_TEXTURE0 + id);
|
|
|
|
active_texture_unit = id;
|
|
}
|
|
|
|
void opengl_texture_state::Enable(GLuint tex_id)
|
|
{
|
|
if ( units[active_texture_unit].texture_id == tex_id ) {
|
|
return;
|
|
}
|
|
|
|
if (units[active_texture_unit].texture_id != tex_id) {
|
|
glBindTexture(units[active_texture_unit].texture_target, tex_id);
|
|
units[active_texture_unit].texture_id = tex_id;
|
|
}
|
|
}
|
|
|
|
void opengl_texture_state::Enable(GLuint unit, GLenum tex_target, GLuint tex_id) {
|
|
Assertion(unit < num_texture_units, "Invalid texture unit value!");
|
|
|
|
if (units[unit].texture_target == tex_target && units[unit].texture_id == tex_id) {
|
|
// The texture unit already uses this texture. There is no need to change it
|
|
return;
|
|
}
|
|
|
|
// Go the standard route
|
|
SetActiveUnit(unit);
|
|
SetTarget(tex_target);
|
|
Enable(tex_id);
|
|
}
|
|
|
|
void opengl_texture_state::Delete(GLuint tex_id)
|
|
{
|
|
if (tex_id == 0) {
|
|
Int3();
|
|
return;
|
|
}
|
|
|
|
GLuint atu_save = active_texture_unit;
|
|
|
|
for (unsigned int i = 0; i < num_texture_units; i++) {
|
|
if (units[i].texture_id == tex_id) {
|
|
SetActiveUnit(i);
|
|
|
|
glBindTexture(units[i].texture_target, 0);
|
|
units[i].texture_id = 0;
|
|
|
|
default_values(i, units[i].texture_target);
|
|
|
|
if (i == atu_save) {
|
|
atu_save = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
SetActiveUnit(atu_save);
|
|
}
|
|
|
|
void opengl_state::init()
|
|
{
|
|
int i;
|
|
|
|
glDisable(GL_BLEND);
|
|
blend_Status = GL_FALSE;
|
|
|
|
glDisable(GL_DEPTH_TEST);
|
|
depthtest_Status = GL_FALSE;
|
|
|
|
glDisable(GL_SCISSOR_TEST);
|
|
scissortest_Status = GL_FALSE;
|
|
|
|
glDisable(GL_CULL_FACE);
|
|
cullface_Status = GL_FALSE;
|
|
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
polygonoffsetfill_Status = GL_FALSE;
|
|
|
|
polygon_offset_Factor = 0.0f;
|
|
polygon_offset_Unit = 0.0f;
|
|
|
|
normalize_Status = GL_FALSE;
|
|
|
|
for (i = 0; i < (int)(sizeof(clipplane_Status) / sizeof(GLboolean)); i++) {
|
|
//glDisable(GL_CLIP_PLANE0+i);
|
|
clipplane_Status[i] = GL_FALSE;
|
|
}
|
|
|
|
for (i = 0; i < (int)(sizeof(clipdistance_Status) / sizeof(GLboolean)); i++) {
|
|
//glDisable(GL_CLIP_DISTANCE0+i);
|
|
clipdistance_Status[i] = GL_FALSE;
|
|
}
|
|
|
|
glDepthMask(GL_FALSE);
|
|
depthmask_Status = GL_FALSE;
|
|
|
|
glFrontFace(GL_CCW);
|
|
frontface_Value = GL_CCW;
|
|
|
|
glCullFace(GL_BACK);
|
|
cullface_Value = GL_BACK;
|
|
|
|
glBlendFunc(GL_ONE, GL_ZERO);
|
|
blendfunc_Value.first = GL_ONE;
|
|
blendfunc_Value.first = GL_ZERO;
|
|
buffer_blendfunc_Value.fill(blendfunc_Value);
|
|
|
|
glDepthFunc(GL_LESS);
|
|
depthfunc_Value = GL_LESS;
|
|
|
|
glGetFloatv(GL_LINE_WIDTH, &line_width_Value);
|
|
|
|
current_program = 0;
|
|
glUseProgram(0);
|
|
|
|
current_framebuffer = 0;
|
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
|
|
|
framebuffer_stack.clear();
|
|
|
|
stencilFunc = GL_ALWAYS;
|
|
stencilFuncRef = 0;
|
|
stencilFuncMask = 0xFFFFFFFF;
|
|
glStencilFunc(stencilFunc, stencilFuncRef, stencilFuncMask);
|
|
|
|
stencilMask = 0xFFFFFFFF;
|
|
glStencilMask(stencilMask);
|
|
|
|
stencilOpFrontStencilFail = GL_KEEP;
|
|
stencilOpFrontDepthFail = GL_KEEP;
|
|
stencilOpFrontPass = GL_KEEP;
|
|
|
|
stencilOpBackStencilFail = GL_KEEP;
|
|
stencilOpBackDepthFail = GL_KEEP;
|
|
stencilOpBackPass = GL_KEEP;
|
|
|
|
glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
|
|
|
|
colormask_Status.x = true;
|
|
colormask_Status.y = true;
|
|
colormask_Status.z = true;
|
|
colormask_Status.w = true;
|
|
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
|
}
|
|
|
|
GLboolean opengl_state::Blend(GLint state)
|
|
{
|
|
GLboolean save_state = blend_Status;
|
|
|
|
if ( !((state == -1) || (state == blend_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_BLEND);
|
|
blend_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_BLEND);
|
|
blend_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::DepthTest(GLint state)
|
|
{
|
|
GLboolean save_state = depthtest_Status;
|
|
|
|
if ( !((state == -1) || (state == depthtest_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_DEPTH_TEST);
|
|
depthtest_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_DEPTH_TEST);
|
|
depthtest_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::ScissorTest(GLint state)
|
|
{
|
|
GLboolean save_state = scissortest_Status;
|
|
|
|
if ( !((state == -1) || (state == scissortest_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_SCISSOR_TEST);
|
|
scissortest_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_SCISSOR_TEST);
|
|
scissortest_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::StencilTest(GLint state)
|
|
{
|
|
GLboolean save_state = stenciltest_Status;
|
|
|
|
if ( !((state == -1) || (state == stenciltest_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_STENCIL_TEST);
|
|
stenciltest_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_STENCIL_TEST);
|
|
stenciltest_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::CullFace(GLint state)
|
|
{
|
|
GLboolean save_state = cullface_Status;
|
|
|
|
if ( !((state == -1) || (state == cullface_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_CULL_FACE);
|
|
cullface_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_CULL_FACE);
|
|
cullface_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
void opengl_state::SetPolygonMode(GLenum face, GLenum mode)
|
|
{
|
|
if ( polygon_mode_Face != face || polygon_mode_Mode != mode ) {
|
|
glPolygonMode(face, mode);
|
|
|
|
polygon_mode_Face = face;
|
|
polygon_mode_Mode = mode;
|
|
}
|
|
}
|
|
|
|
void opengl_state::SetPolygonOffset(GLfloat factor, GLfloat units)
|
|
{
|
|
if ( polygon_offset_Factor != factor || polygon_offset_Unit != units) {
|
|
glPolygonOffset(factor, units);
|
|
|
|
polygon_offset_Factor = factor;
|
|
polygon_offset_Unit = units;
|
|
}
|
|
}
|
|
|
|
GLboolean opengl_state::PolygonOffsetFill(GLint state)
|
|
{
|
|
GLboolean save_state = polygonoffsetfill_Status;
|
|
|
|
if ( !((state == -1) || (state == polygonoffsetfill_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glEnable(GL_POLYGON_OFFSET_FILL);
|
|
polygonoffsetfill_Status = GL_TRUE;
|
|
} else {
|
|
glDisable(GL_POLYGON_OFFSET_FILL);
|
|
polygonoffsetfill_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::ClipDistance(GLint num, bool state)
|
|
{
|
|
Assert( (num >= 0) && (num < (int)(sizeof(clipdistance_Status) / sizeof(GLboolean))) );
|
|
|
|
GLboolean save_state = clipdistance_Status[num];
|
|
|
|
if (state != clipdistance_Status[num]) {
|
|
if (state) {
|
|
glEnable(GL_CLIP_DISTANCE0+num);
|
|
} else {
|
|
glDisable(GL_CLIP_DISTANCE0+num);
|
|
}
|
|
clipdistance_Status[num] = state;
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
GLboolean opengl_state::DepthMask(GLint state)
|
|
{
|
|
GLboolean save_state = depthmask_Status;
|
|
|
|
if ( !((state == -1) || (state == depthmask_Status)) ) {
|
|
if (state) {
|
|
Assert( state == GL_TRUE );
|
|
glDepthMask(GL_TRUE);
|
|
depthmask_Status = GL_TRUE;
|
|
} else {
|
|
glDepthMask(GL_FALSE);
|
|
depthmask_Status = GL_FALSE;
|
|
}
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
bvec4 opengl_state::ColorMask(bool red, bool green, bool blue, bool alpha)
|
|
{
|
|
auto save_state = colormask_Status;
|
|
|
|
if (colormask_Status.x != red || colormask_Status.y != green || colormask_Status.z != blue
|
|
|| colormask_Status.w != alpha) {
|
|
glColorMask(red ? GL_TRUE : GL_FALSE,
|
|
green ? GL_TRUE : GL_FALSE,
|
|
blue ? GL_TRUE : GL_FALSE,
|
|
alpha ? GL_TRUE : GL_FALSE);
|
|
colormask_Status = { red, green, blue, alpha };
|
|
}
|
|
|
|
return save_state;
|
|
}
|
|
|
|
void opengl_state::BlendFunc(GLenum s_val, GLenum d_val)
|
|
{
|
|
if (s_val != blendfunc_Value.first || d_val != blendfunc_Value.second) {
|
|
glBlendFunc(s_val, d_val);
|
|
blendfunc_Value.first = s_val;
|
|
blendfunc_Value.second = d_val;
|
|
|
|
// This has set all the buffer blend modes as well
|
|
buffer_blendfunc_Value.fill(blendfunc_Value);
|
|
}
|
|
}
|
|
void opengl_state::BlendFunci(int buffer, GLenum s_val, GLenum d_val) {
|
|
Assertion(GLAD_GL_ARB_draw_buffers_blend != 0, "Buffer blend modes are not supported by this OpenGL implementation!");
|
|
Assertion(buffer >= 0 && buffer < (int) buffer_blendfunc_Value.size(), "Unsupported index %d specified for buffer blend mode!", buffer);
|
|
|
|
auto& state = buffer_blendfunc_Value[buffer];
|
|
if (state.first == s_val && state.second == d_val) {
|
|
// Already uses the correct blend mode
|
|
return;
|
|
}
|
|
|
|
glBlendFunciARB(buffer, s_val, d_val);
|
|
|
|
// Update the saved state
|
|
state.first = s_val;
|
|
state.second = d_val;
|
|
// Set the non-buffer values to an invalid value to make sure that the next call to BlendFunc resets the state.
|
|
blendfunc_Value.first = GL_INVALID_ENUM;
|
|
blendfunc_Value.second = GL_INVALID_ENUM;
|
|
}
|
|
|
|
void opengl_state::SetAlphaBlendMode(gr_alpha_blend ab)
|
|
{
|
|
switch (ab) {
|
|
case ALPHA_BLEND_ALPHA_BLEND_ALPHA:
|
|
GL_state.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
|
|
case ALPHA_BLEND_NONE:
|
|
GL_state.BlendFunc(GL_ONE, GL_ZERO);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ADDITIVE:
|
|
GL_state.BlendFunc(GL_ONE, GL_ONE);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ALPHA_ADDITIVE:
|
|
GL_state.BlendFunc(GL_SRC_ALPHA, GL_ONE);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR:
|
|
GL_state.BlendFunc(/*GL_SRC_COLOR*/GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
|
|
break;
|
|
|
|
case ALPHA_BLEND_PREMULTIPLIED:
|
|
GL_state.BlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GL_state.Blend( (ab == ALPHA_BLEND_NONE) ? GL_FALSE : GL_TRUE );
|
|
}
|
|
|
|
void opengl_state::SetAlphaBlendModei(int buffer, gr_alpha_blend ab)
|
|
{
|
|
switch (ab) {
|
|
case ALPHA_BLEND_ALPHA_BLEND_ALPHA:
|
|
GL_state.BlendFunci(buffer, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
|
|
case ALPHA_BLEND_NONE:
|
|
GL_state.BlendFunci(buffer, GL_ONE, GL_ZERO);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ADDITIVE:
|
|
GL_state.BlendFunci(buffer, GL_ONE, GL_ONE);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ALPHA_ADDITIVE:
|
|
GL_state.BlendFunci(buffer, GL_SRC_ALPHA, GL_ONE);
|
|
break;
|
|
|
|
case ALPHA_BLEND_ALPHA_BLEND_SRC_COLOR:
|
|
GL_state.BlendFunci(buffer, /*GL_SRC_COLOR*/GL_SRC_ALPHA, GL_ONE_MINUS_SRC_COLOR);
|
|
break;
|
|
|
|
case ALPHA_BLEND_PREMULTIPLIED:
|
|
GL_state.BlendFunci(buffer, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void opengl_state::SetZbufferType(gr_zbuffer_type zt)
|
|
{
|
|
switch (zt) {
|
|
case ZBUFFER_TYPE_NONE:
|
|
GL_state.DepthFunc(GL_ALWAYS);
|
|
GL_state.DepthMask(GL_FALSE);
|
|
break;
|
|
|
|
case ZBUFFER_TYPE_READ:
|
|
GL_state.DepthFunc(GL_LESS);
|
|
GL_state.DepthMask(GL_FALSE);
|
|
break;
|
|
|
|
case ZBUFFER_TYPE_WRITE:
|
|
GL_state.DepthFunc(GL_ALWAYS);
|
|
GL_state.DepthMask(GL_TRUE);
|
|
break;
|
|
|
|
case ZBUFFER_TYPE_FULL:
|
|
GL_state.DepthFunc(GL_LESS);
|
|
GL_state.DepthMask(GL_TRUE);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
GL_state.DepthTest( (zt == ZBUFFER_TYPE_NONE) ? GL_FALSE : GL_TRUE );
|
|
}
|
|
|
|
void opengl_state::SetLineWidth(GLfloat width)
|
|
{
|
|
if ( width == line_width_Value ) {
|
|
return;
|
|
}
|
|
|
|
glLineWidth(width);
|
|
line_width_Value = width;
|
|
}
|
|
void opengl_state::UseProgram(GLuint program)
|
|
{
|
|
if (current_program == program) {
|
|
return;
|
|
}
|
|
|
|
current_program = program;
|
|
glUseProgram(program);
|
|
}
|
|
bool opengl_state::IsCurrentProgram(GLuint program) {
|
|
return current_program == program;
|
|
}
|
|
void opengl_state::BindFrameBuffer(GLuint name) {
|
|
if (current_framebuffer != name) {
|
|
glBindFramebuffer(GL_FRAMEBUFFER, name);
|
|
current_framebuffer = name;
|
|
}
|
|
}
|
|
void opengl_state::PushFramebufferState() {
|
|
framebuffer_stack.push_back(current_framebuffer);
|
|
}
|
|
void opengl_state::PopFramebufferState() {
|
|
Assertion(framebuffer_stack.size() > 0, "Tried to pop the framebuffer state stack while it was empty!");
|
|
|
|
auto restoreBuffer = framebuffer_stack.back();
|
|
framebuffer_stack.pop_back();
|
|
|
|
BindFrameBuffer(restoreBuffer);
|
|
}
|
|
void opengl_state::BindVertexArray(GLuint vao) {
|
|
if (current_vao == vao) {
|
|
return;
|
|
}
|
|
|
|
glBindVertexArray(vao);
|
|
current_vao = vao;
|
|
|
|
Array.VertexArrayChanged();
|
|
}
|
|
void opengl_state::StencilFunc(GLenum func, GLint ref, GLuint mask) {
|
|
if (stencilFunc == func && stencilFuncRef == ref && stencilFuncMask == mask) {
|
|
return;
|
|
}
|
|
|
|
glStencilFunc(func, ref, mask);
|
|
|
|
stencilFunc = func;
|
|
stencilFuncRef = ref;
|
|
stencilFuncMask = mask;
|
|
}
|
|
void opengl_state::StencilOpSeparate(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) {
|
|
if (face == GL_FRONT_AND_BACK) {
|
|
StencilOpSeparate(GL_FRONT, sfail, dpfail, dppass);
|
|
StencilOpSeparate(GL_BACK, sfail, dpfail, dppass);
|
|
return;
|
|
}
|
|
|
|
if (face == GL_FRONT) {
|
|
if (stencilOpFrontStencilFail == sfail && stencilOpFrontDepthFail == dpfail && stencilOpFrontPass == dppass) {
|
|
return;
|
|
}
|
|
|
|
glStencilOpSeparate(GL_FRONT, sfail, dpfail, dppass);
|
|
|
|
stencilOpFrontStencilFail = sfail;
|
|
stencilOpFrontDepthFail = dpfail;
|
|
stencilOpFrontPass = dppass;
|
|
} else {
|
|
if (stencilOpBackStencilFail == sfail && stencilOpBackDepthFail == dpfail && stencilOpBackPass == dppass) {
|
|
return;
|
|
}
|
|
|
|
glStencilOpSeparate(GL_BACK, sfail, dpfail, dppass);
|
|
|
|
stencilOpBackStencilFail = sfail;
|
|
stencilOpBackDepthFail = dpfail;
|
|
stencilOpBackPass = dppass;
|
|
}
|
|
}
|
|
void opengl_state::StencilMask(GLuint mask) {
|
|
if (stencilMask == mask) {
|
|
return;
|
|
}
|
|
|
|
glStencilMask(mask);
|
|
stencilMask = mask;
|
|
}
|
|
|
|
opengl_array_state::~opengl_array_state()
|
|
{
|
|
if ( client_texture_units != NULL ) {
|
|
vm_free(client_texture_units);
|
|
}
|
|
}
|
|
|
|
void opengl_array_state::init(GLuint n_units)
|
|
{
|
|
Assert( n_units > 0 );
|
|
client_texture_units = (opengl_client_texture_unit*) vm_malloc(n_units * sizeof(opengl_client_texture_unit));
|
|
num_client_texture_units = n_units;
|
|
active_client_texture_unit = 0;
|
|
|
|
for (unsigned int i = 0; i < num_client_texture_units; i++) {
|
|
client_texture_units[i].pointer = 0;
|
|
client_texture_units[i].size = 4;
|
|
client_texture_units[i].status = GL_FALSE;
|
|
client_texture_units[i].stride = 0;
|
|
client_texture_units[i].type = GL_FLOAT;
|
|
client_texture_units[i].buffer = 0;
|
|
client_texture_units[i].reset_ptr = false;
|
|
client_texture_units[i].used_for_draw = false;
|
|
}
|
|
|
|
array_buffer = 0;
|
|
element_array_buffer = 0;
|
|
texture_array_buffer = 0;
|
|
uniform_buffer = 0;
|
|
}
|
|
|
|
void opengl_array_state::EnableVertexAttrib(GLuint index)
|
|
{
|
|
opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
|
|
|
|
va_unit->used_for_draw = true;
|
|
|
|
if ( va_unit->status_init && va_unit->status == GL_TRUE ) {
|
|
return;
|
|
}
|
|
|
|
glEnableVertexAttribArray(index);
|
|
va_unit->status = GL_TRUE;
|
|
va_unit->status_init = true;
|
|
}
|
|
|
|
void opengl_array_state::DisableVertexAttrib(GLuint index)
|
|
{
|
|
opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
|
|
|
|
if ( va_unit->status_init && va_unit->status == GL_FALSE ) {
|
|
return;
|
|
}
|
|
|
|
glDisableVertexAttribArray(index);
|
|
va_unit->status = GL_FALSE;
|
|
va_unit->status_init = true;
|
|
}
|
|
|
|
void opengl_array_state::VertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLvoid *pointer)
|
|
{
|
|
opengl_vertex_attrib_unit *va_unit = &vertex_attrib_units[index];
|
|
|
|
if (
|
|
!va_unit->reset_ptr
|
|
&& va_unit->ptr_init
|
|
&& va_unit->normalized == normalized
|
|
&& va_unit->pointer == pointer
|
|
&& va_unit->size == size
|
|
&& va_unit->stride == stride
|
|
&& va_unit->type == type
|
|
&& va_unit->buffer == array_buffer
|
|
) {
|
|
return;
|
|
}
|
|
|
|
glVertexAttribPointer(index, size, type, normalized, stride, pointer);
|
|
|
|
va_unit->normalized = normalized;
|
|
va_unit->pointer = pointer;
|
|
va_unit->size = size;
|
|
va_unit->stride = stride;
|
|
va_unit->type = type;
|
|
va_unit->buffer = array_buffer;
|
|
va_unit->reset_ptr = false;
|
|
|
|
va_unit->ptr_init = true;
|
|
}
|
|
|
|
void opengl_array_state::ResetVertexAttribs()
|
|
{
|
|
for (auto &it : vertex_attrib_units) {
|
|
DisableVertexAttrib(it.first);
|
|
}
|
|
|
|
vertex_attrib_units.clear();
|
|
}
|
|
|
|
void opengl_array_state::BindPointersBegin()
|
|
{
|
|
for (unsigned int i = 0; i < num_client_texture_units; i++) {
|
|
client_texture_units[i].used_for_draw = false;
|
|
}
|
|
|
|
for (auto &it : vertex_attrib_units) {
|
|
it.second.used_for_draw = false;
|
|
}
|
|
}
|
|
|
|
void opengl_array_state::BindPointersEnd()
|
|
{
|
|
for (auto &it : vertex_attrib_units) {
|
|
if (!it.second.used_for_draw) {
|
|
DisableVertexAttrib(it.first);
|
|
}
|
|
}
|
|
}
|
|
|
|
void opengl_array_state::BindArrayBuffer(GLuint id)
|
|
{
|
|
if ( array_buffer_valid && array_buffer == id ) {
|
|
return;
|
|
}
|
|
|
|
glBindBuffer(GL_ARRAY_BUFFER, id);
|
|
|
|
array_buffer = id;
|
|
array_buffer_valid = true;
|
|
|
|
for (unsigned int i = 0; i < num_client_texture_units; i++) {
|
|
client_texture_units[i].reset_ptr = true;
|
|
}
|
|
|
|
for (auto &it : vertex_attrib_units) {
|
|
it.second.reset_ptr = true;
|
|
}
|
|
}
|
|
|
|
void opengl_array_state::BindElementBuffer(GLuint id)
|
|
{
|
|
if ( element_array_buffer_valid && element_array_buffer == id ) {
|
|
return;
|
|
}
|
|
|
|
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, id);
|
|
|
|
element_array_buffer = id;
|
|
element_array_buffer_valid = true;
|
|
}
|
|
|
|
void opengl_array_state::BindTextureBuffer(GLuint id)
|
|
{
|
|
if ( texture_array_buffer == id ) {
|
|
return;
|
|
}
|
|
|
|
glBindBuffer(GL_TEXTURE_BUFFER, id);
|
|
|
|
texture_array_buffer = id;
|
|
}
|
|
|
|
void opengl_array_state::BindUniformBufferBindingIndex(GLuint id, GLuint index)
|
|
{
|
|
if ( uniform_buffer_index_bindings[index] == id ) {
|
|
return;
|
|
}
|
|
|
|
glBindBufferBase(GL_UNIFORM_BUFFER, index, id);
|
|
|
|
uniform_buffer_index_bindings[index] = id;
|
|
}
|
|
|
|
void opengl_array_state::BindUniformBuffer(GLuint id)
|
|
{
|
|
if ( uniform_buffer == id ) {
|
|
return;
|
|
}
|
|
|
|
glBindBuffer(GL_UNIFORM_BUFFER, id);
|
|
|
|
uniform_buffer = id;
|
|
}
|
|
void opengl_array_state::VertexArrayChanged() {
|
|
array_buffer_valid = false;
|
|
element_array_buffer_valid = false;
|
|
|
|
for (auto& bindingInfo : vertex_buffer_bindings) {
|
|
bindingInfo.valid_data = false;
|
|
}
|
|
}
|
|
void opengl_array_state::BindVertexBuffer(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride) {
|
|
if (bindingindex >= vertex_buffer_bindings.size()) {
|
|
// Make sure that we have the place for this information
|
|
vertex_buffer_bindings.resize(bindingindex + 1);
|
|
}
|
|
|
|
auto& bindingInfo = vertex_buffer_bindings[bindingindex];
|
|
|
|
if (bindingInfo.valid_data && bindingInfo.buffer == buffer && bindingInfo.offset == offset
|
|
&& bindingInfo.stride == stride) {
|
|
return;
|
|
}
|
|
|
|
glBindVertexBuffer(bindingindex, buffer, offset, stride);
|
|
|
|
bindingInfo.valid_data = true;
|
|
bindingInfo.buffer = buffer;
|
|
bindingInfo.stride = stride;
|
|
bindingInfo.offset = offset;
|
|
}
|
|
opengl_constant_state::opengl_constant_state() {
|
|
}
|
|
void opengl_constant_state::init() {
|
|
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &_uniform_buffer_offset_alignment);
|
|
glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &_max_uniform_block_size);
|
|
glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &_max_uniform_block_bindings);
|
|
|
|
if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
|
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &_max_anisotropy);
|
|
} else {
|
|
_max_anisotropy = -1.0f;
|
|
}
|
|
}
|
|
GLint opengl_constant_state::GetUniformBufferOffsetAlignment() {
|
|
return _uniform_buffer_offset_alignment;
|
|
}
|
|
GLint opengl_constant_state::GetMaxUniformBlockSize() {
|
|
return _max_uniform_block_size;
|
|
}
|
|
GLint opengl_constant_state::GetMaxUniformBlockBindings() {
|
|
return _max_uniform_block_bindings;
|
|
}
|
|
GLfloat opengl_constant_state::GetMaxAnisotropy() {
|
|
return _max_anisotropy;
|
|
}
|
|
|
|
void gr_opengl_clear_states()
|
|
{
|
|
gr_zbias(0);
|
|
gr_zbuffer_set(ZBUFFER_TYPE_READ);
|
|
gr_set_cull(0);
|
|
gr_set_fill_mode(GR_FILL_MODE_SOLID);
|
|
|
|
opengl_shader_set_current();
|
|
}
|