mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-26 09:30:24 +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:
parent
bc2f738a84
commit
0836912a6d
Notes:
sideshowbarker
2024-07-17 11:04:47 +09:00
Author: https://github.com/RKBethke 🔰 Commit: https://github.com/SerenityOS/serenity/commit/0836912a6d Pull-request: https://github.com/SerenityOS/serenity/pull/13903 Reviewed-by: https://github.com/Quaker762 ✅ Reviewed-by: https://github.com/gmta ✅ Reviewed-by: https://github.com/linusg ✅
14 changed files with 193 additions and 63 deletions
|
@ -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
|
||||
|
|
57
Userland/Libraries/LibGL/ClipPlanes.cpp
Normal file
57
Userland/Libraries/LibGL/ClipPlanes.cpp
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
virtual void set_light_state(unsigned, Light const&) = 0;
|
||||
virtual void set_material_state(Face, Material const&) = 0;
|
||||
virtual void set_stencil_configuration(Face, StencilConfiguration const&) = 0;
|
||||
virtual void set_clip_planes(Vector<FloatVector4> const&) = 0;
|
||||
|
||||
virtual RasterPosition raster_position() const = 0;
|
||||
virtual void set_raster_position(RasterPosition const& raster_position) = 0;
|
||||
|
|
|
@ -15,6 +15,7 @@ struct DeviceInfo final {
|
|||
String device_name;
|
||||
unsigned num_texture_units;
|
||||
unsigned num_lights;
|
||||
unsigned max_clip_planes;
|
||||
u8 stencil_bits;
|
||||
bool supports_npot_textures;
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGPU/Vertex.h>
|
||||
#include <LibGfx/Vector4.h>
|
||||
|
@ -17,40 +18,42 @@ namespace SoftGPU {
|
|||
template<Clipper::ClipPlane plane>
|
||||
static constexpr bool point_within_clip_plane(FloatVector4 const& vertex)
|
||||
{
|
||||
if constexpr (plane == Clipper::ClipPlane::LEFT)
|
||||
if constexpr (plane == Clipper::ClipPlane::Left)
|
||||
return vertex.x() >= -vertex.w();
|
||||
else if constexpr (plane == Clipper::ClipPlane::RIGHT)
|
||||
else if constexpr (plane == Clipper::ClipPlane::Right)
|
||||
return vertex.x() <= vertex.w();
|
||||
else if constexpr (plane == Clipper::ClipPlane::TOP)
|
||||
else if constexpr (plane == Clipper::ClipPlane::Top)
|
||||
return vertex.y() <= vertex.w();
|
||||
else if constexpr (plane == Clipper::ClipPlane::BOTTOM)
|
||||
else if constexpr (plane == Clipper::ClipPlane::Bottom)
|
||||
return vertex.y() >= -vertex.w();
|
||||
else if constexpr (plane == Clipper::ClipPlane::NEAR)
|
||||
else if constexpr (plane == Clipper::ClipPlane::Near)
|
||||
return vertex.z() >= -vertex.w();
|
||||
else if constexpr (plane == Clipper::ClipPlane::FAR)
|
||||
else if constexpr (plane == Clipper::ClipPlane::Far)
|
||||
return vertex.z() <= vertex.w();
|
||||
return false;
|
||||
}
|
||||
|
||||
template<Clipper::ClipPlane plane>
|
||||
static constexpr GPU::Vertex clip_intersection_point(GPU::Vertex const& p1, GPU::Vertex const& p2)
|
||||
static bool point_within_user_plane(FloatVector4 const& vertex, FloatVector4 const& user_plane)
|
||||
{
|
||||
constexpr FloatVector4 clip_plane_normals[] = {
|
||||
{ 1, 0, 0, 1 }, // Left Plane
|
||||
{ -1, 0, 0, 1 }, // Right Plane
|
||||
{ 0, -1, 0, 1 }, // Top Plane
|
||||
{ 0, 1, 0, 1 }, // Bottom plane
|
||||
{ 0, 0, 1, 1 }, // Near Plane
|
||||
{ 0, 0, -1, 1 } // Far Plane
|
||||
};
|
||||
constexpr auto clip_plane_normal = clip_plane_normals[to_underlying(plane)];
|
||||
return vertex.dot(user_plane) >= 0;
|
||||
}
|
||||
|
||||
// See https://www.microsoft.com/en-us/research/wp-content/uploads/1978/01/p245-blinn.pdf
|
||||
// "Clipping Using Homogeneous Coordinates" Blinn/Newell, 1978
|
||||
// Clip plane normals have W=1 so the vertices' W coordinates are included in x1 and x2.
|
||||
template<Clipper::ClipPlane plane>
|
||||
bool point_within_plane(GPU::Vertex const& vertex, FloatVector4 const& user_plane)
|
||||
{
|
||||
if constexpr (plane == Clipper::ClipPlane::User)
|
||||
return point_within_user_plane(vertex.eye_coordinates, user_plane);
|
||||
else
|
||||
return point_within_clip_plane<plane>(vertex.clip_coordinates);
|
||||
}
|
||||
|
||||
auto const x1 = clip_plane_normal.dot(p1.clip_coordinates);
|
||||
auto const x2 = clip_plane_normal.dot(p2.clip_coordinates);
|
||||
template<Clipper::ClipPlane plane>
|
||||
static GPU::Vertex clip_intersection_point(GPU::Vertex const& p1, GPU::Vertex const& p2, FloatVector4 const& plane_normal)
|
||||
{
|
||||
auto p1_coordinates = (plane == Clipper::ClipPlane::User) ? p1.eye_coordinates : p1.clip_coordinates;
|
||||
auto p2_coordinates = (plane == Clipper::ClipPlane::User) ? p2.eye_coordinates : p2.clip_coordinates;
|
||||
auto x1 = plane_normal.dot(p1_coordinates);
|
||||
auto x2 = plane_normal.dot(p2_coordinates);
|
||||
auto const a = x1 / (x1 - x2);
|
||||
|
||||
GPU::Vertex out;
|
||||
|
@ -65,7 +68,7 @@ static constexpr GPU::Vertex clip_intersection_point(GPU::Vertex const& p1, GPU:
|
|||
}
|
||||
|
||||
template<Clipper::ClipPlane plane>
|
||||
FLATTEN static constexpr void clip_plane(Vector<GPU::Vertex>& input_list, Vector<GPU::Vertex>& output_list)
|
||||
FLATTEN static void clip_plane(Vector<GPU::Vertex>& input_list, Vector<GPU::Vertex>& output_list, FloatVector4 const& clip_plane)
|
||||
{
|
||||
output_list.clear_with_capacity();
|
||||
|
||||
|
@ -74,20 +77,20 @@ FLATTEN static constexpr void clip_plane(Vector<GPU::Vertex>& input_list, Vector
|
|||
return;
|
||||
|
||||
auto const* prev_vec = &input_list.data()[0];
|
||||
auto is_prev_point_within_clip_plane = point_within_clip_plane<plane>(prev_vec->clip_coordinates);
|
||||
auto is_prev_point_within_plane = point_within_plane<plane>(*prev_vec, clip_plane);
|
||||
|
||||
for (size_t i = 1; i <= input_list_size; i++) {
|
||||
auto const& curr_vec = input_list[i % input_list_size];
|
||||
auto const is_curr_point_within_clip_plane = point_within_clip_plane<plane>(curr_vec.clip_coordinates);
|
||||
auto const is_curr_point_within_plane = point_within_plane<plane>(curr_vec, clip_plane);
|
||||
|
||||
if (is_curr_point_within_clip_plane != is_prev_point_within_clip_plane)
|
||||
output_list.append(clip_intersection_point<plane>(*prev_vec, curr_vec));
|
||||
if (is_curr_point_within_plane != is_prev_point_within_plane)
|
||||
output_list.append(clip_intersection_point<plane>(*prev_vec, curr_vec, clip_plane));
|
||||
|
||||
if (is_curr_point_within_clip_plane)
|
||||
if (is_curr_point_within_plane)
|
||||
output_list.append(curr_vec);
|
||||
|
||||
prev_vec = &curr_vec;
|
||||
is_prev_point_within_clip_plane = is_curr_point_within_clip_plane;
|
||||
is_prev_point_within_plane = is_curr_point_within_plane;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -97,9 +100,9 @@ void Clipper::clip_points_against_frustum(Vector<GPU::Vertex>& vertices)
|
|||
|
||||
for (auto& vertex : vertices) {
|
||||
auto const coords = vertex.clip_coordinates;
|
||||
if (point_within_clip_plane<ClipPlane::LEFT>(coords) && point_within_clip_plane<ClipPlane::RIGHT>(coords)
|
||||
&& point_within_clip_plane<ClipPlane::TOP>(coords) && point_within_clip_plane<ClipPlane::BOTTOM>(coords)
|
||||
&& point_within_clip_plane<ClipPlane::NEAR>(coords) && point_within_clip_plane<ClipPlane::FAR>(coords))
|
||||
if (point_within_clip_plane<ClipPlane::Left>(coords) && point_within_clip_plane<ClipPlane::Right>(coords)
|
||||
&& point_within_clip_plane<ClipPlane::Top>(coords) && point_within_clip_plane<ClipPlane::Bottom>(coords)
|
||||
&& point_within_clip_plane<ClipPlane::Near>(coords) && point_within_clip_plane<ClipPlane::Far>(coords))
|
||||
m_vertex_buffer.append(vertex);
|
||||
}
|
||||
|
||||
|
@ -107,39 +110,61 @@ void Clipper::clip_points_against_frustum(Vector<GPU::Vertex>& vertices)
|
|||
vertices.extend(m_vertex_buffer);
|
||||
}
|
||||
|
||||
constexpr FloatVector4 clip_plane_eqns[] = {
|
||||
{ 1, 0, 0, 1 }, // Left Plane
|
||||
{ -1, 0, 0, 1 }, // Right Plane
|
||||
{ 0, -1, 0, 1 }, // Top Plane
|
||||
{ 0, 1, 0, 1 }, // Bottom plane
|
||||
{ 0, 0, 1, 1 }, // Near Plane
|
||||
{ 0, 0, -1, 1 } // Far Plane
|
||||
};
|
||||
|
||||
template<Clipper::ClipPlane plane>
|
||||
static constexpr bool constrain_line_within_plane(GPU::Vertex& from, GPU::Vertex& to)
|
||||
{
|
||||
constexpr auto clip_plane_eqn = clip_plane_eqns[to_underlying(plane)];
|
||||
|
||||
auto from_within_plane = point_within_clip_plane<plane>(from.clip_coordinates);
|
||||
auto to_within_plane = point_within_clip_plane<plane>(to.clip_coordinates);
|
||||
if (!from_within_plane && !to_within_plane)
|
||||
return false;
|
||||
if (!from_within_plane)
|
||||
from = clip_intersection_point<plane>(from, to);
|
||||
from = clip_intersection_point<plane>(from, to, clip_plane_eqn);
|
||||
else if (!to_within_plane)
|
||||
to = clip_intersection_point<plane>(from, to);
|
||||
to = clip_intersection_point<plane>(from, to, clip_plane_eqn);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Clipper::clip_line_against_frustum(GPU::Vertex& from, GPU::Vertex& to)
|
||||
{
|
||||
return constrain_line_within_plane<ClipPlane::LEFT>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::RIGHT>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::TOP>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::BOTTOM>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::NEAR>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::FAR>(from, to);
|
||||
return constrain_line_within_plane<ClipPlane::Left>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::Right>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::Top>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::Bottom>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::Near>(from, to)
|
||||
&& constrain_line_within_plane<ClipPlane::Far>(from, to);
|
||||
}
|
||||
|
||||
void Clipper::clip_triangle_against_frustum(Vector<GPU::Vertex>& input_verts)
|
||||
{
|
||||
// FIXME C++23. Static reflection will provide looping over all enum values.
|
||||
clip_plane<ClipPlane::LEFT>(input_verts, m_vertex_buffer);
|
||||
clip_plane<ClipPlane::RIGHT>(m_vertex_buffer, input_verts);
|
||||
clip_plane<ClipPlane::TOP>(input_verts, m_vertex_buffer);
|
||||
clip_plane<ClipPlane::BOTTOM>(m_vertex_buffer, input_verts);
|
||||
clip_plane<ClipPlane::NEAR>(input_verts, m_vertex_buffer);
|
||||
clip_plane<ClipPlane::FAR>(m_vertex_buffer, input_verts);
|
||||
clip_plane<ClipPlane::Left>(input_verts, m_vertex_buffer, clip_plane_eqns[0]);
|
||||
clip_plane<ClipPlane::Right>(m_vertex_buffer, input_verts, clip_plane_eqns[1]);
|
||||
clip_plane<ClipPlane::Top>(input_verts, m_vertex_buffer, clip_plane_eqns[2]);
|
||||
clip_plane<ClipPlane::Bottom>(m_vertex_buffer, input_verts, clip_plane_eqns[3]);
|
||||
clip_plane<ClipPlane::Near>(input_verts, m_vertex_buffer, clip_plane_eqns[4]);
|
||||
clip_plane<ClipPlane::Far>(m_vertex_buffer, input_verts, clip_plane_eqns[5]);
|
||||
}
|
||||
|
||||
void Clipper::clip_triangle_against_user_defined(Vector<GPU::Vertex>& input_verts, Vector<FloatVector4>& user_planes)
|
||||
{
|
||||
// FIXME: Also implement user plane support for points and lines
|
||||
auto& in = input_verts;
|
||||
auto& out = m_vertex_buffer;
|
||||
for (auto const& plane : user_planes) {
|
||||
clip_plane<ClipPlane::User>(in, out, plane);
|
||||
swap(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,12 +16,13 @@ namespace SoftGPU {
|
|||
class Clipper final {
|
||||
public:
|
||||
enum class ClipPlane : u8 {
|
||||
LEFT = 0,
|
||||
RIGHT,
|
||||
TOP,
|
||||
BOTTOM,
|
||||
NEAR,
|
||||
FAR
|
||||
Left = 0,
|
||||
Right,
|
||||
Top,
|
||||
Bottom,
|
||||
Near,
|
||||
Far,
|
||||
User, // Within view space
|
||||
};
|
||||
|
||||
Clipper() = default;
|
||||
|
@ -29,6 +30,7 @@ public:
|
|||
void clip_points_against_frustum(Vector<GPU::Vertex>& vertices);
|
||||
bool clip_line_against_frustum(GPU::Vertex& from, GPU::Vertex& to);
|
||||
void clip_triangle_against_frustum(Vector<GPU::Vertex>& input_vecs);
|
||||
void clip_triangle_against_user_defined(Vector<GPU::Vertex>& input_verts, Vector<FloatVector4>& user_planes);
|
||||
|
||||
private:
|
||||
Vector<GPU::Vertex> m_vertex_buffer;
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace SoftGPU {
|
|||
static constexpr bool ENABLE_STATISTICS_OVERLAY = false;
|
||||
static constexpr int MILLISECONDS_PER_STATISTICS_PERIOD = 500;
|
||||
static constexpr int NUM_LIGHTS = 8;
|
||||
static constexpr int MAX_CLIP_PLANES = 6;
|
||||
static constexpr int SUBPIXEL_BITS = 6;
|
||||
|
||||
// See: https://www.khronos.org/opengl/wiki/Common_Mistakes#Texture_edge_color_problem
|
||||
|
|
|
@ -826,6 +826,7 @@ GPU::DeviceInfo Device::info() const
|
|||
.device_name = "SoftGPU",
|
||||
.num_texture_units = GPU::NUM_SAMPLERS,
|
||||
.num_lights = NUM_LIGHTS,
|
||||
.max_clip_planes = MAX_CLIP_PLANES,
|
||||
.stencil_bits = sizeof(GPU::StencilType) * 8,
|
||||
.supports_npot_textures = true,
|
||||
};
|
||||
|
@ -1175,6 +1176,9 @@ void Device::draw_primitives(GPU::PrimitiveType primitive_type, FloatMatrix4x4 c
|
|||
m_clipped_vertices.append(triangle.vertices[2]);
|
||||
m_clipper.clip_triangle_against_frustum(m_clipped_vertices);
|
||||
|
||||
if (m_clip_planes.size() > 0)
|
||||
m_clipper.clip_triangle_against_user_defined(m_clipped_vertices, m_clip_planes);
|
||||
|
||||
if (m_clipped_vertices.size() < 3)
|
||||
continue;
|
||||
|
||||
|
@ -1497,6 +1501,11 @@ void Device::set_raster_position(GPU::RasterPosition const& raster_position)
|
|||
m_raster_position = raster_position;
|
||||
}
|
||||
|
||||
void Device::set_clip_planes(Vector<FloatVector4> const& clip_planes)
|
||||
{
|
||||
m_clip_planes = clip_planes;
|
||||
}
|
||||
|
||||
void Device::set_raster_position(FloatVector4 const& position, FloatMatrix4x4 const& model_view_transform, FloatMatrix4x4 const& projection_transform)
|
||||
{
|
||||
auto const eye_coordinates = model_view_transform * position;
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
virtual void set_light_state(unsigned, GPU::Light const&) override;
|
||||
virtual void set_material_state(GPU::Face, GPU::Material const&) override;
|
||||
virtual void set_stencil_configuration(GPU::Face, GPU::StencilConfiguration const&) override;
|
||||
virtual void set_clip_planes(Vector<FloatVector4> const&) override;
|
||||
|
||||
virtual GPU::RasterPosition raster_position() const override { return m_raster_position; }
|
||||
virtual void set_raster_position(GPU::RasterPosition const& raster_position) override;
|
||||
|
@ -107,6 +108,7 @@ private:
|
|||
Array<GPU::Light, NUM_LIGHTS> m_lights;
|
||||
Array<GPU::Material, 2u> m_materials;
|
||||
GPU::RasterPosition m_raster_position;
|
||||
Vector<FloatVector4> m_clip_planes;
|
||||
Array<GPU::StencilConfiguration, 2u> m_stencil_configuration;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue