2021-05-04 16:00:45 +03:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2021, Jesse Buhagiar <jooster669@gmail.com>
|
2021-08-16 20:22:08 +03:00
|
|
|
* Copyright (c) 2021, Stephan Unverwerth <s.unverwerth@serenityos.org>
|
2022-04-17 21:51:11 +03:00
|
|
|
* Copyright (c) 2022, Jelle Raaijmakers <jelle@gmta.nl>
|
2022-01-28 03:18:07 +03:00
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
2021-05-04 16:00:45 +03:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
|
|
*/
|
|
|
|
|
2022-05-06 12:40:55 +03:00
|
|
|
#include <AK/StdLibExtras.h>
|
2022-01-28 03:18:07 +03:00
|
|
|
#include <AK/Vector.h>
|
2022-03-27 16:43:51 +03:00
|
|
|
#include <LibGPU/Vertex.h>
|
2022-01-28 03:18:07 +03:00
|
|
|
#include <LibGfx/Vector4.h>
|
2021-12-16 22:32:38 +03:00
|
|
|
#include <LibSoftGPU/Clipper.h>
|
2021-05-04 16:00:45 +03:00
|
|
|
|
2021-12-16 22:32:38 +03:00
|
|
|
namespace SoftGPU {
|
2021-08-16 20:22:08 +03:00
|
|
|
|
2022-01-28 03:18:07 +03:00
|
|
|
template<Clipper::ClipPlane plane>
|
|
|
|
static constexpr bool point_within_clip_plane(FloatVector4 const& vertex)
|
2021-05-04 16:00:45 +03:00
|
|
|
{
|
2022-05-06 12:40:55 +03:00
|
|
|
if constexpr (plane == Clipper::ClipPlane::Left)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.x() >= -vertex.w();
|
2022-05-06 12:40:55 +03:00
|
|
|
else if constexpr (plane == Clipper::ClipPlane::Right)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.x() <= vertex.w();
|
2022-05-06 12:40:55 +03:00
|
|
|
else if constexpr (plane == Clipper::ClipPlane::Top)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.y() <= vertex.w();
|
2022-05-06 12:40:55 +03:00
|
|
|
else if constexpr (plane == Clipper::ClipPlane::Bottom)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.y() >= -vertex.w();
|
2022-05-06 12:40:55 +03:00
|
|
|
else if constexpr (plane == Clipper::ClipPlane::Near)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.z() >= -vertex.w();
|
2022-05-06 12:40:55 +03:00
|
|
|
else if constexpr (plane == Clipper::ClipPlane::Far)
|
2021-12-02 02:46:32 +03:00
|
|
|
return vertex.z() <= vertex.w();
|
2021-05-04 16:00:45 +03:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-06 12:40:55 +03:00
|
|
|
static bool point_within_user_plane(FloatVector4 const& vertex, FloatVector4 const& user_plane)
|
|
|
|
{
|
|
|
|
return vertex.dot(user_plane) >= 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2022-01-28 03:18:07 +03:00
|
|
|
template<Clipper::ClipPlane plane>
|
2022-05-06 12:40:55 +03:00
|
|
|
static GPU::Vertex clip_intersection_point(GPU::Vertex const& p1, GPU::Vertex const& p2, FloatVector4 const& plane_normal)
|
2021-05-04 16:00:45 +03:00
|
|
|
{
|
2022-05-06 12:40:55 +03:00
|
|
|
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);
|
2022-04-17 21:51:11 +03:00
|
|
|
auto const a = x1 / (x1 - x2);
|
2021-05-04 16:00:45 +03:00
|
|
|
|
2022-03-27 16:43:51 +03:00
|
|
|
GPU::Vertex out;
|
2022-01-04 17:02:30 +03:00
|
|
|
out.position = mix(p1.position, p2.position, a);
|
|
|
|
out.eye_coordinates = mix(p1.eye_coordinates, p2.eye_coordinates, a);
|
|
|
|
out.clip_coordinates = mix(p1.clip_coordinates, p2.clip_coordinates, a);
|
|
|
|
out.color = mix(p1.color, p2.color, a);
|
2022-09-05 01:40:27 +03:00
|
|
|
for (size_t i = 0; i < GPU::NUM_TEXTURE_UNITS; ++i)
|
2022-01-15 20:33:55 +03:00
|
|
|
out.tex_coords[i] = mix(p1.tex_coords[i], p2.tex_coords[i], a);
|
2022-01-06 23:45:02 +03:00
|
|
|
out.normal = mix(p1.normal, p2.normal, a);
|
2021-08-16 20:22:08 +03:00
|
|
|
return out;
|
2021-05-04 16:00:45 +03:00
|
|
|
}
|
|
|
|
|
2022-01-28 03:18:07 +03:00
|
|
|
template<Clipper::ClipPlane plane>
|
2022-05-06 12:40:55 +03:00
|
|
|
FLATTEN static void clip_plane(Vector<GPU::Vertex>& input_list, Vector<GPU::Vertex>& output_list, FloatVector4 const& clip_plane)
|
2021-05-04 16:00:45 +03:00
|
|
|
{
|
2022-04-10 03:50:26 +03:00
|
|
|
output_list.clear_with_capacity();
|
2021-05-04 16:00:45 +03:00
|
|
|
|
2022-04-10 03:50:26 +03:00
|
|
|
auto input_list_size = input_list.size();
|
|
|
|
if (input_list_size == 0)
|
|
|
|
return;
|
2021-05-04 16:00:45 +03:00
|
|
|
|
2022-04-10 03:50:26 +03:00
|
|
|
auto const* prev_vec = &input_list.data()[0];
|
2022-05-06 12:40:55 +03:00
|
|
|
auto is_prev_point_within_plane = point_within_plane<plane>(*prev_vec, clip_plane);
|
2022-04-10 03:50:26 +03:00
|
|
|
|
|
|
|
for (size_t i = 1; i <= input_list_size; i++) {
|
|
|
|
auto const& curr_vec = input_list[i % input_list_size];
|
2022-05-06 12:40:55 +03:00
|
|
|
auto const is_curr_point_within_plane = point_within_plane<plane>(curr_vec, clip_plane);
|
2022-04-10 03:50:26 +03:00
|
|
|
|
2022-05-06 12:40:55 +03:00
|
|
|
if (is_curr_point_within_plane != is_prev_point_within_plane)
|
|
|
|
output_list.append(clip_intersection_point<plane>(*prev_vec, curr_vec, clip_plane));
|
2022-01-28 03:18:49 +03:00
|
|
|
|
2022-05-06 12:40:55 +03:00
|
|
|
if (is_curr_point_within_plane)
|
2022-04-10 03:50:26 +03:00
|
|
|
output_list.append(curr_vec);
|
|
|
|
|
|
|
|
prev_vec = &curr_vec;
|
2022-05-06 12:40:55 +03:00
|
|
|
is_prev_point_within_plane = is_curr_point_within_plane;
|
2022-01-08 23:55:23 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
void Clipper::clip_points_against_frustum(Vector<GPU::Vertex>& vertices)
|
|
|
|
{
|
|
|
|
m_vertex_buffer.clear_with_capacity();
|
|
|
|
|
|
|
|
for (auto& vertex : vertices) {
|
|
|
|
auto const coords = vertex.clip_coordinates;
|
2022-05-06 12:40:55 +03:00
|
|
|
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))
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
m_vertex_buffer.append(vertex);
|
|
|
|
}
|
|
|
|
|
|
|
|
vertices.clear_with_capacity();
|
|
|
|
vertices.extend(m_vertex_buffer);
|
|
|
|
}
|
|
|
|
|
2022-05-06 12:40:55 +03:00
|
|
|
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
|
|
|
|
};
|
|
|
|
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
template<Clipper::ClipPlane plane>
|
|
|
|
static constexpr bool constrain_line_within_plane(GPU::Vertex& from, GPU::Vertex& to)
|
|
|
|
{
|
2022-05-06 12:40:55 +03:00
|
|
|
constexpr auto clip_plane_eqn = clip_plane_eqns[to_underlying(plane)];
|
|
|
|
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
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)
|
2022-05-06 12:40:55 +03:00
|
|
|
from = clip_intersection_point<plane>(from, to, clip_plane_eqn);
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
else if (!to_within_plane)
|
2022-05-06 12:40:55 +03:00
|
|
|
to = clip_intersection_point<plane>(from, to, clip_plane_eqn);
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Clipper::clip_line_against_frustum(GPU::Vertex& from, GPU::Vertex& to)
|
|
|
|
{
|
2022-05-06 12:40:55 +03:00
|
|
|
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);
|
LibGL+LibGPU+LibSoftGPU: Implement point and line drawing
Implement (anti)aliased point drawing and anti-aliased line drawing.
Supported through LibGL's `GL_POINTS`, `GL_LINES`, `GL_LINE_LOOP` and
`GL_LINE_STRIP`.
In order to support this, `LibSoftGPU`s rasterization logic was
reworked. Now, any primitive can be drawn by invoking `rasterize()`
which takes care of the quad loop and fragment testing logic. Three
callbacks need to be passed:
* `set_coverage_mask`: the primitive needs to provide initial coverage
mask information so fragments can be discarded early.
* `set_quad_depth`: fragments survived stencil testing, so depth values
need to be set so depth testing can take place.
* `set_quad_attributes`: fragments survived depth testing, so fragment
shading is going to take place. All attributes like color, tex coords
and fog depth need to be set so alpha testing and eventually,
fragment rasterization can take place.
As of this commit, there are four instantiations of this function:
* Triangle rasterization
* Points - aliased
* Points - anti-aliased
* Lines - anti-aliased
In order to standardize vertex processing for all primitive types,
things like vertex transformation, lighting and tex coord generation
are now taking place before clipping.
2022-05-08 03:13:14 +03:00
|
|
|
}
|
|
|
|
|
2022-03-27 16:43:51 +03:00
|
|
|
void Clipper::clip_triangle_against_frustum(Vector<GPU::Vertex>& input_verts)
|
2022-01-08 23:55:23 +03:00
|
|
|
{
|
2022-01-28 03:18:07 +03:00
|
|
|
// FIXME C++23. Static reflection will provide looping over all enum values.
|
2022-05-06 12:40:55 +03:00
|
|
|
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);
|
|
|
|
}
|
2021-08-16 20:22:08 +03:00
|
|
|
}
|
2022-01-28 03:18:07 +03:00
|
|
|
|
2021-05-04 16:00:45 +03:00
|
|
|
}
|