Skip to content

Commit

Permalink
create ConvexPolygon struct
Browse files Browse the repository at this point in the history
  • Loading branch information
Desour committed Oct 10, 2024
1 parent 3d0baa2 commit 6a1c184
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 77 deletions.
28 changes: 14 additions & 14 deletions src/client/clientmap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1069,7 +1069,7 @@ int ClientMap::getBackgroundBrightness(float max_d, u32 daylight_factor,
return ret;
}

std::vector<std::pair<std::vector<v2f>, video::SColor>>
std::vector<std::pair<ConvexPolygon, video::SColor>>
ClientMap::getPostFxPolygons()
{
using mat4 = core::matrix4;
Expand Down Expand Up @@ -1168,7 +1168,7 @@ ClientMap::getPostFxPolygons()
return mat4(proj_mat * view_mat, mat4::EM4CONST_INVERSE_TRANSPOSED);
}();

std::vector<std::pair<std::vector<v2f>, video::SColor>> polygons;
std::vector<std::pair<ConvexPolygon, video::SColor>> polygons;

// Go through all 8 nodes that the near plane possibly instersects with

Expand Down Expand Up @@ -1199,12 +1199,12 @@ ClientMap::getPostFxPolygons()
if (post_color.getAlpha() == 0)
continue;

const std::vector<v2f> screen_polygon{
const ConvexPolygon screen_polygon{{
{0.0f, 0.0f}, // upper-left
{1.0f, 0.0f}, // upper-right
{1.0f, 1.0f}, // lower-right
{0.0f, 1.0f}, // lower-left
};
}};

// the (inverse and inverse transposed) world matrix for the node
// Transforms planes from node-local space to camera-offset-local world
Expand All @@ -1216,7 +1216,7 @@ ClientMap::getPostFxPolygons()

const mat4 wvp_mat_ti = vp_mat_ti * world_mat_ti;

auto clip_polygon_by_objsp_plane = [&](std::vector<v2f> &polyg,
auto clip_polygon_by_objsp_plane = [&](ConvexPolygon &polyg,
const v4f &clip_plane) -> bool {
v4f clip_plane_clipspace = mat4_mult_v4f(wvp_mat_ti, clip_plane);

Expand All @@ -1225,11 +1225,11 @@ ClientMap::getPostFxPolygons()
// a*p.X + b*p.Y + c*p.Z + d >= 0
v3f clip_line(clip_plane_clipspace[0], clip_plane_clipspace[1], clip_plane_clipspace[3]);

polyg = clip_convex_polygon(polyg, clip_line);
return polyg.size() >= 3;
polyg = polyg.clip(clip_line);
return polyg.vertices.size() >= 3;
};

auto clip_polygon_by_objsp_planes = [&](std::vector<v2f> &polyg,
auto clip_polygon_by_objsp_planes = [&](ConvexPolygon &polyg,
const std::vector<v4f> &clip_planes) -> bool {
for (const v4f &clip_plane : clip_planes)
if (!clip_polygon_by_objsp_plane(polyg, clip_plane))
Expand All @@ -1239,7 +1239,7 @@ ClientMap::getPostFxPolygons()

if (features.drawtype == NDT_NORMAL) {
// draw full cube
std::vector<v2f> polygon = screen_polygon;
ConvexPolygon polygon = screen_polygon;
if (!clip_polygon_by_objsp_planes(polygon, {
{ 2.0f, 0.0f, 0.0f, 1.0f},
{-2.0f, 0.0f, 0.0f, 1.0f},
Expand All @@ -1253,7 +1253,7 @@ ClientMap::getPostFxPolygons()

} else if (features.drawtype == NDT_LIQUID
|| features.drawtype == NDT_FLOWINGLIQUID) {
std::vector<v2f> polygon = screen_polygon;
ConvexPolygon polygon = screen_polygon;
// clip by all but top
if (!clip_polygon_by_objsp_planes(polygon, {
{ 2.0f, 0.0f, 0.0f, 1.0f},
Expand Down Expand Up @@ -1311,8 +1311,8 @@ ClientMap::getPostFxPolygons()
indices = {0, 1, 3, 0, 3, 2};
}

std::vector<v2f> polygon1 = polygon;
std::vector<v2f> &polygon2 = polygon;
ConvexPolygon polygon1 = polygon;
ConvexPolygon &polygon2 = polygon;

if (clip_polygon_by_objsp_plane(polygon1, triangle_split_plane)
&& clip_polygon_by_objsp_plane(polygon1,
Expand Down Expand Up @@ -1346,7 +1346,7 @@ video::SColorf ClientMap::renderPostFx()
video::IVideoDriver *driver = SceneManager->getVideoDriver();

for (const auto &[polygon, post_color] : polygons) {
draw_convex_polygon(driver, polygon, post_color);
polygon.draw(driver, post_color);
}

// Color for wield item
Expand All @@ -1358,7 +1358,7 @@ video::SColorf ClientMap::renderPostFx()
video::SColorf color = post_color;

// (screen size and aspect ratio don't matter for relative screen area)
f32 area = get_convex_polygon_area(polygon);
f32 area = polygon.area();
color.a *= area;

color_sum.r += color.a * color.r;
Expand Down
5 changes: 3 additions & 2 deletions src/client/clientmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <set>
#include <map>

struct ConvexPolygon;

struct MapDrawControl
{
// Wanted drawing range
Expand Down Expand Up @@ -158,10 +160,9 @@ class ClientMap : public Map, public scene::ISceneNode
void updateTransparentMeshBuffers();

// helper for renderPostFx
std::vector<std::pair<std::vector<v2f>, video::SColor>>
std::vector<std::pair<ConvexPolygon, video::SColor>>
getPostFxPolygons();


// Orders blocks by distance to the camera
class MapBlockComparer
{
Expand Down
83 changes: 43 additions & 40 deletions src/util/convex_polygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@

#include <IVideoDriver.h>

void draw_convex_polygon(video::IVideoDriver *driver, const std::vector<v2f> &polygon,
const video::SColor &color)
void ConvexPolygon::draw(video::IVideoDriver *driver, const video::SColor &color) const
{
if (polygon.size() < 3)
if (vertices.size() < 3)
return;

auto new_2d_vertex = [&color](const v2f &pos) -> video::S3DVertex {
Expand All @@ -21,14 +20,14 @@ void draw_convex_polygon(video::IVideoDriver *driver, const std::vector<v2f> &po
v3f(), color, v2f());
};

std::vector<video::S3DVertex> vertices;
vertices.reserve(polygon.size());
for (const v2f &v : polygon)
vertices.push_back(new_2d_vertex(v));
std::vector<video::S3DVertex> s3d_vertices;
s3d_vertices.reserve(vertices.size());
for (const v2f &v : vertices)
s3d_vertices.push_back(new_2d_vertex(v));

std::vector<u16> index_list;
index_list.reserve(polygon.size());
for (size_t i = 0; i < polygon.size(); ++i)
index_list.reserve(vertices.size());
for (size_t i = 0; i < vertices.size(); ++i)
index_list.push_back(i);

video::SMaterial material;
Expand All @@ -40,7 +39,7 @@ void draw_convex_polygon(video::IVideoDriver *driver, const std::vector<v2f> &po
driver->setTransform(video::ETS_VIEW, core::matrix4::EM4CONST_IDENTITY);
driver->setTransform(video::ETS_WORLD, core::matrix4::EM4CONST_IDENTITY);

driver->drawVertexPrimitiveList((void *)&vertices[0], (u32)vertices.size(),
driver->drawVertexPrimitiveList((void *)&s3d_vertices[0], (u32)s3d_vertices.size(),
(void *)&index_list[0], (u32)index_list.size() - 2,
video::EVT_STANDARD, // S3DVertex vertices
scene::EPT_TRIANGLE_FAN,
Expand All @@ -49,16 +48,16 @@ void draw_convex_polygon(video::IVideoDriver *driver, const std::vector<v2f> &po

#endif // !def(SERVER)

f32 get_convex_polygon_area(const std::vector<v2f> &polygon)
f32 ConvexPolygon::area() const
{
if (polygon.size() < 3)
if (vertices.size() < 3)
return 0.0f;
// sum up the areas of all triangles
f32 area = 0.0f;
const v2f &v1 = polygon[0];
for (size_t i = 2; i < polygon.size(); ++i) {
const v2f &v2 = polygon[i-1];
const v2f &v3 = polygon[i];
const v2f &v1 = vertices[0];
for (size_t i = 2; i < vertices.size(); ++i) {
const v2f &v2 = vertices[i-1];
const v2f &v3 = vertices[i];
// area of the triangle v1 v2 v3: 0.5 * det(d1 d2)
// (winding order matters, for sign)
v2f d1 = v2 - v1;
Expand All @@ -68,12 +67,16 @@ f32 get_convex_polygon_area(const std::vector<v2f> &polygon)
return area;
}

std::vector<v2f> clip_convex_polygon(const std::vector<v2f> &polygon, v3f clip_line)
ConvexPolygon ConvexPolygon::clip(v3f clip_line) const
{
using polygon_iterator = std::vector<v2f>::const_iterator;

// the return value
std::vector<v2f> polygon_clipped;
ConvexPolygon clipped;
auto &vertices_out = clipped.vertices;

if (vertices.empty())
return clipped; // emtpty

// returns whether pos is in the not clipped half-space
auto is_in = [&](const v2f &pos) {
Expand Down Expand Up @@ -102,39 +105,39 @@ std::vector<v2f> clip_convex_polygon(const std::vector<v2f> &polygon, v3f clip_l
// before
polygon_iterator first_in, first_out;
polygon_iterator last_out, last_in;
if (is_in(polygon[0])) {
first_out = std::find_if(polygon.begin() + 1, polygon.end(), is_out);
if (first_out == polygon.end()) {
if (is_in(vertices[0])) {
first_out = std::find_if(vertices.begin() + 1, vertices.end(), is_out);
if (first_out == vertices.end()) {
// all are in
polygon_clipped = polygon;
return polygon_clipped;
clipped = {vertices};
return clipped;
}
last_in = first_out - 1;
first_in = std::find_if(first_out + 1, polygon.end(), is_in);
first_in = std::find_if(first_out + 1, vertices.end(), is_in);
last_out = first_in - 1;
if (first_in == polygon.end())
first_in = polygon.begin(); // we already checked that the 0th is in
if (first_in == vertices.end())
first_in = vertices.begin(); // we already checked that the 0th is in
} else {
first_in = std::find_if(polygon.begin() + 1, polygon.end(), is_in);
if (first_in == polygon.end()) {
first_in = std::find_if(vertices.begin() + 1, vertices.end(), is_in);
if (first_in == vertices.end()) {
// all are out
return polygon_clipped; // empty
return clipped; // empty
}
last_out = first_in - 1;
first_out = std::find_if(first_in + 1, polygon.end(), is_out);
first_out = std::find_if(first_in + 1, vertices.end(), is_out);
last_in = first_out - 1;
if (first_out == polygon.end())
first_out = polygon.begin(); // we already checked that the 0th is out
if (first_out == vertices.end())
first_out = vertices.begin(); // we already checked that the 0th is out
}

// copy all vertices that are in
if (first_in <= last_in) {
polygon_clipped.reserve((last_in - first_in) + 1 + 2);
polygon_clipped.insert(polygon_clipped.end(), first_in, last_in + 1);
vertices_out.reserve((last_in - first_in) + 1 + 2);
vertices_out.insert(vertices_out.end(), first_in, last_in + 1);
} else {
polygon_clipped.reserve((polygon.end() - first_in) + (last_in - polygon.begin()) + 1 + 2);
polygon_clipped.insert(polygon_clipped.end(), first_in, polygon.end());
polygon_clipped.insert(polygon_clipped.end(), polygon.begin(), last_in + 1);
vertices_out.reserve((vertices.end() - first_in) + (last_in - vertices.begin()) + 1 + 2);
vertices_out.insert(vertices_out.end(), first_in, vertices.end());
vertices_out.insert(vertices_out.end(), vertices.begin(), last_in + 1);
}

auto split_edge = [&](const v2f &p1, const v2f &p2) {
Expand All @@ -147,10 +150,10 @@ std::vector<v2f> clip_convex_polygon(const std::vector<v2f> &polygon, v3f clip_l
};

// split in-out pair
polygon_clipped.push_back(split_edge(*last_in, *first_out));
vertices_out.push_back(split_edge(*last_in, *first_out));

// split out-in pair
polygon_clipped.push_back(split_edge(*last_out, *first_in));
vertices_out.push_back(split_edge(*last_out, *first_in));

return polygon_clipped;
return clipped;
}
52 changes: 31 additions & 21 deletions src/util/convex_polygon.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,29 +12,39 @@
#ifndef SERVER

namespace irr::video { class IVideoDriver; }
#endif // !def(SERVER)

/** Draws a convex polygon over the whole screen.
* @param polygon Ordered list of corner vertices.
* X coordinates go from 0 (left) to 1 (right), Y from 0 (up) to
* 1 (down).
/**
* A polygon, stored as closed polyonal chain (ordered vertex list).
* The functions assume it's convex.
*/
void draw_convex_polygon(video::IVideoDriver *driver, const std::vector<v2f> &polygon,
const video::SColor &color);
struct ConvexPolygon
{
std::vector<v2f> vertices;

#ifndef SERVER

/** Draws the polygon over the whole screen.
*
* X coordinates go from 0 (left) to 1 (right), Y from 0 (up) to 1 (down).
*/
void draw(video::IVideoDriver *driver, const video::SColor &color) const;

#endif // !def(SERVER)

/** Calculates the area of a convex polygon, given by its corners
* @param polygon Ordered list of corner vertices.
* @return The area.
*/
f32 get_convex_polygon_area(const std::vector<v2f> &polygon);

/** Clips away the parts of a convex polygon that are on the wrong side of the
* given clip line.
* @param polygon Nonempty list of vertices that form a convex polygon if you connect
* them in order.
* @param clip_line The homogeneous coordinates of an oriented 2D line. Clips
* away all points p for which dot(clip_line, p) < 0 holds.
* @return The clipped polygon.
*/
std::vector<v2f> clip_convex_polygon(const std::vector<v2f> &polygon, v3f clip_line);
/** Calculates the area.
*
* @return The area.
*/
[[nodiscard]]
f32 area() const;

/** Clips away the parts of the polygon that are on the wrong side of the
* given clip line.
* @param clip_line The homogeneous coordinates of an oriented 2D line. Clips
* away all points p for which dot(clip_line, p) < 0 holds.
* @return The clipped polygon.
*/
[[nodiscard]]
ConvexPolygon clip(v3f clip_line) const;
};

0 comments on commit 6a1c184

Please sign in to comment.