|
|
|
@ -11,7 +11,9 @@ |
|
|
|
namespace OpenGL { |
|
|
|
|
|
|
|
OpenGLState OpenGLState::cur_state; |
|
|
|
|
|
|
|
bool OpenGLState::s_rgb_used; |
|
|
|
|
|
|
|
OpenGLState::OpenGLState() { |
|
|
|
// These all match default OpenGL values
|
|
|
|
geometry_shaders.enabled = false; |
|
|
|
@ -112,7 +114,6 @@ void OpenGLState::ApplyDefaultState() { |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplySRgb() const { |
|
|
|
// sRGB
|
|
|
|
if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) { |
|
|
|
if (framebuffer_srgb.enabled) { |
|
|
|
// Track if sRGB is used
|
|
|
|
@ -125,23 +126,20 @@ void OpenGLState::ApplySRgb() const { |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyCulling() const { |
|
|
|
// Culling
|
|
|
|
const bool cull_changed = cull.enabled != cur_state.cull.enabled; |
|
|
|
if (cull_changed) { |
|
|
|
if (cull.enabled != cur_state.cull.enabled) { |
|
|
|
if (cull.enabled) { |
|
|
|
glEnable(GL_CULL_FACE); |
|
|
|
} else { |
|
|
|
glDisable(GL_CULL_FACE); |
|
|
|
} |
|
|
|
} |
|
|
|
if (cull.enabled) { |
|
|
|
if (cull_changed || cull.mode != cur_state.cull.mode) { |
|
|
|
glCullFace(cull.mode); |
|
|
|
} |
|
|
|
|
|
|
|
if (cull_changed || cull.front_face != cur_state.cull.front_face) { |
|
|
|
glFrontFace(cull.front_face); |
|
|
|
} |
|
|
|
if (cull.mode != cur_state.cull.mode) { |
|
|
|
glCullFace(cull.mode); |
|
|
|
} |
|
|
|
|
|
|
|
if (cull.front_face != cur_state.cull.front_face) { |
|
|
|
glFrontFace(cull.front_face); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -172,72 +170,63 @@ void OpenGLState::ApplyColorMask() const { |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyDepth() const { |
|
|
|
// Depth test
|
|
|
|
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled; |
|
|
|
if (depth_test_changed) { |
|
|
|
if (depth.test_enabled != cur_state.depth.test_enabled) { |
|
|
|
if (depth.test_enabled) { |
|
|
|
glEnable(GL_DEPTH_TEST); |
|
|
|
} else { |
|
|
|
glDisable(GL_DEPTH_TEST); |
|
|
|
} |
|
|
|
} |
|
|
|
if (depth.test_enabled && |
|
|
|
(depth_test_changed || depth.test_func != cur_state.depth.test_func)) { |
|
|
|
|
|
|
|
if (depth.test_func != cur_state.depth.test_func) { |
|
|
|
glDepthFunc(depth.test_func); |
|
|
|
} |
|
|
|
// Depth mask
|
|
|
|
|
|
|
|
if (depth.write_mask != cur_state.depth.write_mask) { |
|
|
|
glDepthMask(depth.write_mask); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyPrimitiveRestart() const { |
|
|
|
const bool primitive_restart_changed = |
|
|
|
primitive_restart.enabled != cur_state.primitive_restart.enabled; |
|
|
|
if (primitive_restart_changed) { |
|
|
|
if (primitive_restart.enabled != cur_state.primitive_restart.enabled) { |
|
|
|
if (primitive_restart.enabled) { |
|
|
|
glEnable(GL_PRIMITIVE_RESTART); |
|
|
|
} else { |
|
|
|
glDisable(GL_PRIMITIVE_RESTART); |
|
|
|
} |
|
|
|
} |
|
|
|
if (primitive_restart_changed || |
|
|
|
(primitive_restart.enabled && |
|
|
|
primitive_restart.index != cur_state.primitive_restart.index)) { |
|
|
|
|
|
|
|
if (primitive_restart.index != cur_state.primitive_restart.index) { |
|
|
|
glPrimitiveRestartIndex(primitive_restart.index); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyStencilTest() const { |
|
|
|
const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled; |
|
|
|
if (stencil_test_changed) { |
|
|
|
if (stencil.test_enabled != cur_state.stencil.test_enabled) { |
|
|
|
if (stencil.test_enabled) { |
|
|
|
glEnable(GL_STENCIL_TEST); |
|
|
|
} else { |
|
|
|
glDisable(GL_STENCIL_TEST); |
|
|
|
} |
|
|
|
} |
|
|
|
if (stencil.test_enabled) { |
|
|
|
auto config_stencil = [stencil_test_changed](GLenum face, const auto& config, |
|
|
|
const auto& prev_config) { |
|
|
|
if (stencil_test_changed || config.test_func != prev_config.test_func || |
|
|
|
config.test_ref != prev_config.test_ref || |
|
|
|
config.test_mask != prev_config.test_mask) { |
|
|
|
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); |
|
|
|
} |
|
|
|
if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail || |
|
|
|
config.action_depth_pass != prev_config.action_depth_pass || |
|
|
|
config.action_stencil_fail != prev_config.action_stencil_fail) { |
|
|
|
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, |
|
|
|
config.action_depth_pass); |
|
|
|
} |
|
|
|
if (config.write_mask != prev_config.write_mask) { |
|
|
|
glStencilMaskSeparate(face, config.write_mask); |
|
|
|
} |
|
|
|
}; |
|
|
|
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front); |
|
|
|
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); |
|
|
|
} |
|
|
|
|
|
|
|
const auto ConfigStencil = [](GLenum face, const auto& config, const auto& prev_config) { |
|
|
|
if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref || |
|
|
|
config.test_mask != prev_config.test_mask) { |
|
|
|
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask); |
|
|
|
} |
|
|
|
if (config.action_depth_fail != prev_config.action_depth_fail || |
|
|
|
config.action_depth_pass != prev_config.action_depth_pass || |
|
|
|
config.action_stencil_fail != prev_config.action_stencil_fail) { |
|
|
|
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail, |
|
|
|
config.action_depth_pass); |
|
|
|
} |
|
|
|
if (config.write_mask != prev_config.write_mask) { |
|
|
|
glStencilMaskSeparate(face, config.write_mask); |
|
|
|
} |
|
|
|
}; |
|
|
|
ConfigStencil(GL_FRONT, stencil.front, cur_state.stencil.front); |
|
|
|
ConfigStencil(GL_BACK, stencil.back, cur_state.stencil.back); |
|
|
|
} |
|
|
|
// Viewport does not affects glClearBuffer so emulate viewport using scissor test
|
|
|
|
void OpenGLState::EmulateViewportWithScissor() { |
|
|
|
@ -278,19 +267,18 @@ void OpenGLState::ApplyViewport() const { |
|
|
|
updated.depth_range_far != current.depth_range_far) { |
|
|
|
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far); |
|
|
|
} |
|
|
|
const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; |
|
|
|
if (scissor_changed) { |
|
|
|
|
|
|
|
if (updated.scissor.enabled != current.scissor.enabled) { |
|
|
|
if (updated.scissor.enabled) { |
|
|
|
glEnablei(GL_SCISSOR_TEST, i); |
|
|
|
} else { |
|
|
|
glDisablei(GL_SCISSOR_TEST, i); |
|
|
|
} |
|
|
|
} |
|
|
|
if (updated.scissor.enabled && |
|
|
|
(scissor_changed || updated.scissor.x != current.scissor.x || |
|
|
|
updated.scissor.y != current.scissor.y || |
|
|
|
updated.scissor.width != current.scissor.width || |
|
|
|
updated.scissor.height != current.scissor.height)) { |
|
|
|
|
|
|
|
if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y || |
|
|
|
updated.scissor.width != current.scissor.width || |
|
|
|
updated.scissor.height != current.scissor.height) { |
|
|
|
glScissorIndexed(i, updated.scissor.x, updated.scissor.y, updated.scissor.width, |
|
|
|
updated.scissor.height); |
|
|
|
} |
|
|
|
@ -302,22 +290,23 @@ void OpenGLState::ApplyViewport() const { |
|
|
|
updated.height != current.height) { |
|
|
|
glViewport(updated.x, updated.y, updated.width, updated.height); |
|
|
|
} |
|
|
|
|
|
|
|
if (updated.depth_range_near != current.depth_range_near || |
|
|
|
updated.depth_range_far != current.depth_range_far) { |
|
|
|
glDepthRange(updated.depth_range_near, updated.depth_range_far); |
|
|
|
} |
|
|
|
const bool scissor_changed = updated.scissor.enabled != current.scissor.enabled; |
|
|
|
if (scissor_changed) { |
|
|
|
|
|
|
|
if (updated.scissor.enabled != current.scissor.enabled) { |
|
|
|
if (updated.scissor.enabled) { |
|
|
|
glEnable(GL_SCISSOR_TEST); |
|
|
|
} else { |
|
|
|
glDisable(GL_SCISSOR_TEST); |
|
|
|
} |
|
|
|
} |
|
|
|
if (updated.scissor.enabled && (scissor_changed || updated.scissor.x != current.scissor.x || |
|
|
|
updated.scissor.y != current.scissor.y || |
|
|
|
updated.scissor.width != current.scissor.width || |
|
|
|
updated.scissor.height != current.scissor.height)) { |
|
|
|
|
|
|
|
if (updated.scissor.x != current.scissor.x || updated.scissor.y != current.scissor.y || |
|
|
|
updated.scissor.width != current.scissor.width || |
|
|
|
updated.scissor.height != current.scissor.height) { |
|
|
|
glScissor(updated.scissor.x, updated.scissor.y, updated.scissor.width, |
|
|
|
updated.scissor.height); |
|
|
|
} |
|
|
|
@ -327,8 +316,7 @@ void OpenGLState::ApplyViewport() const { |
|
|
|
void OpenGLState::ApplyGlobalBlending() const { |
|
|
|
const Blend& current = cur_state.blend[0]; |
|
|
|
const Blend& updated = blend[0]; |
|
|
|
const bool blend_changed = updated.enabled != current.enabled; |
|
|
|
if (blend_changed) { |
|
|
|
if (updated.enabled != current.enabled) { |
|
|
|
if (updated.enabled) { |
|
|
|
glEnable(GL_BLEND); |
|
|
|
} else { |
|
|
|
@ -338,15 +326,14 @@ void OpenGLState::ApplyGlobalBlending() const { |
|
|
|
if (!updated.enabled) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (blend_changed || updated.src_rgb_func != current.src_rgb_func || |
|
|
|
if (updated.src_rgb_func != current.src_rgb_func || |
|
|
|
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || |
|
|
|
updated.dst_a_func != current.dst_a_func) { |
|
|
|
glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func, |
|
|
|
updated.dst_a_func); |
|
|
|
} |
|
|
|
|
|
|
|
if (blend_changed || updated.rgb_equation != current.rgb_equation || |
|
|
|
updated.a_equation != current.a_equation) { |
|
|
|
if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { |
|
|
|
glBlendEquationSeparate(updated.rgb_equation, updated.a_equation); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -354,26 +341,22 @@ void OpenGLState::ApplyGlobalBlending() const { |
|
|
|
void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { |
|
|
|
const Blend& updated = blend[target]; |
|
|
|
const Blend& current = cur_state.blend[target]; |
|
|
|
const bool blend_changed = updated.enabled != current.enabled || force; |
|
|
|
if (blend_changed) { |
|
|
|
if (updated.enabled != current.enabled || force) { |
|
|
|
if (updated.enabled) { |
|
|
|
glEnablei(GL_BLEND, static_cast<GLuint>(target)); |
|
|
|
} else { |
|
|
|
glDisablei(GL_BLEND, static_cast<GLuint>(target)); |
|
|
|
} |
|
|
|
} |
|
|
|
if (!updated.enabled) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (blend_changed || updated.src_rgb_func != current.src_rgb_func || |
|
|
|
|
|
|
|
if (updated.src_rgb_func != current.src_rgb_func || |
|
|
|
updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || |
|
|
|
updated.dst_a_func != current.dst_a_func) { |
|
|
|
glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, |
|
|
|
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); |
|
|
|
} |
|
|
|
|
|
|
|
if (blend_changed || updated.rgb_equation != current.rgb_equation || |
|
|
|
updated.a_equation != current.a_equation) { |
|
|
|
if (updated.rgb_equation != current.rgb_equation || updated.a_equation != current.a_equation) { |
|
|
|
glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, |
|
|
|
updated.a_equation); |
|
|
|
} |
|
|
|
@ -397,8 +380,7 @@ void OpenGLState::ApplyBlending() const { |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyLogicOp() const { |
|
|
|
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled; |
|
|
|
if (logic_op_changed) { |
|
|
|
if (logic_op.enabled != cur_state.logic_op.enabled) { |
|
|
|
if (logic_op.enabled) { |
|
|
|
glEnable(GL_COLOR_LOGIC_OP); |
|
|
|
} else { |
|
|
|
@ -406,14 +388,12 @@ void OpenGLState::ApplyLogicOp() const { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (logic_op.enabled && |
|
|
|
(logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) { |
|
|
|
if (logic_op.operation != cur_state.logic_op.operation) { |
|
|
|
glLogicOp(logic_op.operation); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void OpenGLState::ApplyPolygonOffset() const { |
|
|
|
|
|
|
|
const bool fill_enable_changed = |
|
|
|
polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; |
|
|
|
const bool line_enable_changed = |
|
|
|
@ -448,9 +428,7 @@ void OpenGLState::ApplyPolygonOffset() const { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && |
|
|
|
(factor_changed || units_changed || clamp_changed)) { |
|
|
|
|
|
|
|
if (factor_changed || units_changed || clamp_changed) { |
|
|
|
if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { |
|
|
|
glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); |
|
|
|
} else { |
|
|
|
@ -528,9 +506,9 @@ void OpenGLState::ApplyDepthClamp() const { |
|
|
|
depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { |
|
|
|
return; |
|
|
|
} |
|
|
|
if (depth_clamp.far_plane != depth_clamp.near_plane) { |
|
|
|
UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!"); |
|
|
|
} |
|
|
|
UNIMPLEMENTED_IF_MSG(depth_clamp.far_plane != depth_clamp.near_plane, |
|
|
|
"Unimplemented Depth Clamp Separation!"); |
|
|
|
|
|
|
|
if (depth_clamp.far_plane || depth_clamp.near_plane) { |
|
|
|
glEnable(GL_DEPTH_CLAMP); |
|
|
|
} else { |
|
|
|
|