1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 11:17:35 +00:00

LibGL+LibGPU+LibSoftGPU: Implement and expose glClipPlane

This commit implements glClipPlane and its supporting calls, backed
by new support for user-defined clip planes in the software GPU clipper.

This fixes some visual bugs seen in the Quake III port, in which mirrors
would only reflect correctly from close distances.
This commit is contained in:
RKBethke 2022-05-06 09:40:55 +00:00 committed by Linus Groh
parent bc2f738a84
commit 0836912a6d
14 changed files with 193 additions and 63 deletions

View file

@ -1,10 +1,11 @@
set(SOURCES
ClipPlanes.cpp
ContextParameter.cpp
GLAPI.cpp
GLContext.cpp
Matrix.cpp
Lighting.cpp
Lists.cpp
Matrix.cpp
Stencil.cpp
Tex/NameAllocator.cpp
Tex/Texture2D.cpp

View file

@ -0,0 +1,57 @@
/*
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
* Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
* Copyright (c) 2022, Ryan Bethke <ryanbethke11@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Debug.h>
#include <LibGL/GLContext.h>
namespace GL {
void GLContext::gl_clip_plane(GLenum plane, GLdouble const* equation)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clip_plane, plane, equation);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
RETURN_WITH_ERROR_IF((plane < GL_CLIP_PLANE0) || (plane > GL_CLIP_PLANE5), GL_INVALID_ENUM);
auto plane_idx = static_cast<size_t>(plane) - GL_CLIP_PLANE0;
auto eqn = FloatVector4(equation[0], equation[1], equation[2], equation[3]);
m_clip_plane_attributes.eye_clip_plane[plane_idx] = m_model_view_matrix * eqn;
m_clip_planes_dirty = true;
}
void GLContext::gl_get_clip_plane(GLenum plane, GLdouble* equation)
{
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
RETURN_WITH_ERROR_IF((plane < GL_CLIP_PLANE0) || (plane > GL_CLIP_PLANE5), GL_INVALID_ENUM);
auto plane_idx = static_cast<size_t>(plane) - GL_CLIP_PLANE0;
equation[0] = static_cast<GLdouble>(m_clip_plane_attributes.eye_clip_plane[plane_idx][0]);
equation[1] = static_cast<GLdouble>(m_clip_plane_attributes.eye_clip_plane[plane_idx][1]);
equation[2] = static_cast<GLdouble>(m_clip_plane_attributes.eye_clip_plane[plane_idx][2]);
equation[3] = static_cast<GLdouble>(m_clip_plane_attributes.eye_clip_plane[plane_idx][3]);
}
void GLContext::sync_clip_planes()
{
if (!m_clip_planes_dirty)
return;
m_clip_planes_dirty = false;
// TODO: Replace magic number 6 with device-dependent constant
Vector<FloatVector4, 6> user_clip_planes;
for (size_t plane_idx = 0; plane_idx < 6; ++plane_idx) {
if ((m_clip_plane_attributes.enabled & (1 << plane_idx)) != 0u) {
user_clip_planes.append(m_clip_plane_attributes.eye_clip_plane[plane_idx]);
}
}
m_rasterizer->set_clip_planes(user_clip_planes);
}
}

View file

@ -52,6 +52,8 @@ Optional<ContextParameter> GLContext::get_context_parameter(GLenum name)
return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_lighting_enabled } };
case GL_LINE_SMOOTH:
return ContextParameter { .type = GL_BOOL, .is_capability = true, .value = { .boolean_value = m_line_smooth } };
case GL_MAX_CLIP_PLANES:
return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.max_clip_planes) } };
case GL_MAX_LIGHTS:
return ContextParameter { .type = GL_INT, .value = { .integer_value = static_cast<GLint>(m_device_info.num_lights) } };
case GL_MAX_MODELVIEW_STACK_DEPTH:
@ -169,6 +171,17 @@ void GLContext::gl_disable(GLenum capability)
bool update_rasterizer_options = false;
switch (capability) {
case GL_CLIP_PLANE0:
case GL_CLIP_PLANE1:
case GL_CLIP_PLANE2:
case GL_CLIP_PLANE3:
case GL_CLIP_PLANE4:
case GL_CLIP_PLANE5: {
auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
m_clip_plane_attributes.enabled &= ~(1 << plane_idx);
m_clip_planes_dirty = true;
break;
}
case GL_COLOR_MATERIAL:
m_color_material_enabled = false;
break;
@ -308,6 +321,17 @@ void GLContext::gl_enable(GLenum capability)
bool update_rasterizer_options = false;
switch (capability) {
case GL_CLIP_PLANE0:
case GL_CLIP_PLANE1:
case GL_CLIP_PLANE2:
case GL_CLIP_PLANE3:
case GL_CLIP_PLANE4:
case GL_CLIP_PLANE5: {
auto plane_idx = static_cast<size_t>(capability) - GL_CLIP_PLANE0;
m_clip_plane_attributes.enabled |= (1 << plane_idx);
m_clip_planes_dirty = true;
break;
}
case GL_COLOR_MATERIAL:
m_color_material_enabled = true;
break;

View file

@ -481,6 +481,7 @@ extern "C" {
#define GL_ADD 0x0104
// User clipping planes
#define GL_MAX_CLIP_PLANES 0x0D32
#define GL_CLIP_PLANE0 0x3000
#define GL_CLIP_PLANE1 0x3001
#define GL_CLIP_PLANE2 0x3002
@ -682,6 +683,7 @@ GLAPI void glRecti(GLint x1, GLint y1, GLint x2, GLint y2);
GLAPI void glGetTexLevelParameteriv(GLenum target, GLint level, GLenum pname, GLint* params);
GLAPI void glPointSize(GLfloat size);
GLAPI void glClipPlane(GLenum plane, GLdouble const* equation);
GLAPI void glGetClipPlane(GLenum plane, GLdouble* equation);
GLAPI void glArrayElement(GLint i);
GLAPI void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);

View file

@ -399,6 +399,11 @@ void glGetBooleanv(GLenum pname, GLboolean* data)
g_gl_context->gl_get_booleanv(pname, data);
}
void glGetClipPlane(GLenum plane, GLdouble* equation)
{
g_gl_context->gl_get_clip_plane(plane, equation);
}
void glGetDoublev(GLenum pname, GLdouble* params)
{
g_gl_context->gl_get_doublev(pname, params);

View file

@ -794,16 +794,6 @@ void GLContext::gl_depth_mask(GLboolean flag)
m_rasterizer->set_options(options);
}
void GLContext::gl_clip_plane(GLenum plane, [[maybe_unused]] GLdouble const* equation)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_clip_plane, plane, equation);
RETURN_WITH_ERROR_IF(m_in_draw_state, GL_INVALID_OPERATION);
RETURN_WITH_ERROR_IF((plane < GL_CLIP_PLANE0) || (plane > GL_CLIP_PLANE5), GL_INVALID_ENUM);
dbgln_if(GL_DEBUG, "GLContext FIXME: implement gl_clip_plane() (equation = [{} {} {} {}])", equation[0], equation[1], equation[2], equation[3]);
}
void GLContext::gl_draw_pixels(GLsizei width, GLsizei height, GLenum format, GLenum type, void const* data)
{
APPEND_TO_CALL_LIST_AND_RETURN_IF_NEEDED(gl_draw_pixels, width, height, format, type, data);
@ -1215,6 +1205,7 @@ void GLContext::sync_device_config()
sync_device_texcoord_config();
sync_light_state();
sync_stencil_configuration();
sync_clip_planes();
}
void GLContext::build_extension_string()

View file

@ -197,6 +197,7 @@ public:
void gl_get_light(GLenum light, GLenum pname, void* params, GLenum type);
void gl_get_material(GLenum face, GLenum pname, void* params, GLenum type);
void gl_clip_plane(GLenum plane, GLdouble const* equation);
void gl_get_clip_plane(GLenum plane, GLdouble* equation);
void gl_array_element(GLint i);
void gl_copy_tex_sub_image_2d(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
void gl_point_size(GLfloat size);
@ -207,6 +208,7 @@ private:
void sync_device_texcoord_config();
void sync_light_state();
void sync_stencil_configuration();
void sync_clip_planes();
void build_extension_string();
@ -307,6 +309,13 @@ private:
GLenum m_current_read_buffer = GL_BACK;
GLenum m_current_draw_buffer = GL_BACK;
// User-defined clip planes
struct ClipPlaneAttributes {
Array<FloatVector4, 6> eye_clip_plane; // TODO: Change to use device-defined constant
GLuint enabled { 0 };
} m_clip_plane_attributes;
bool m_clip_planes_dirty { true };
// Client side arrays
bool m_client_side_vertex_array_enabled { false };
bool m_client_side_color_array_enabled { false };