add transform mode and tollbar button, implement polygon clipping with uvs interpolation and cube faces projection with near plane clipping, add duplicate points removal template function, implement Spere mesh surface section creation.
This commit is contained in:
173
src/util.cpp
173
src/util.cpp
@@ -2,6 +2,18 @@
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
|
||||
template<>
|
||||
std::vector<vertex_t> poly_remove_duplicate<vertex_t>(const std::vector<vertex_t>& v, const float tollerance)
|
||||
{
|
||||
std::vector<vertex_t> ret;
|
||||
for (size_t i = 0; i < v.size(); i++)
|
||||
{
|
||||
if (glm::distance2(v[i].pos, v[(i + 1) % v.size()].pos) > tollerance)
|
||||
ret.push_back(v[i]);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool point_in_rect(const glm::vec2& p, const glm::vec4& r)
|
||||
{
|
||||
return p.x > r.x && p.x < r.x+r.z && p.y > r.y && p.y < r.y+r.w;
|
||||
@@ -33,9 +45,25 @@ glm::vec4 rect_union(glm::vec4 a, glm::vec4 b)
|
||||
return o;
|
||||
}
|
||||
|
||||
bool ray_intersect(glm::vec3 ray_origin, glm::vec3 ray_dir, glm::vec3 plane_origin,
|
||||
glm::vec3 plane_normal, glm::vec3 plane_tangent, glm::vec3& out_hit, float& out_t)
|
||||
{
|
||||
float den = glm::dot(ray_dir, plane_normal);
|
||||
if (den == 0)
|
||||
return false; // no intersection
|
||||
float num = glm::dot(plane_origin - ray_origin, plane_normal);
|
||||
out_t = num / den;
|
||||
if (out_t > 0)
|
||||
out_hit = ray_origin + ray_dir * out_t;
|
||||
else
|
||||
// negative intersection
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
// see: https://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
|
||||
bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b,
|
||||
const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt)
|
||||
const glm::vec2& p1a, const glm::vec2& p1b, glm::vec2& out_pt, glm::vec2& out_hit_uv)
|
||||
{
|
||||
auto cross2d = [](const glm::vec2& v, const glm::vec2& w)
|
||||
{ return (v.x * w.y) - (v.y * w.x); };
|
||||
@@ -50,16 +78,151 @@ bool segments_intersect(const glm::vec2& p0a, const glm::vec2& p0b,
|
||||
out_pt = xy(is) + zw(is) * 0.5f;
|
||||
return glm::all(glm::greaterThan(zw(is), glm::vec2(0, 0)));
|
||||
}
|
||||
float t = cross2d(q - p, s) / den;
|
||||
float u = cross2d(q - p, r) / den;
|
||||
if (t >= 0 && t <= 1 && u >= 0 && u <= 1)
|
||||
out_hit_uv.x = cross2d(q - p, s) / den;
|
||||
out_hit_uv.y = cross2d(q - p, r) / den;
|
||||
out_pt = p + out_hit_uv.x * r;
|
||||
if (out_hit_uv.x >= 0 && out_hit_uv.x <= 1 && out_hit_uv.y >= 0 && out_hit_uv.y <= 1)
|
||||
{
|
||||
out_pt = p + t * r;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true if the point p in the right halfspace of the ab line
|
||||
// computed using the 2d cross product
|
||||
bool point_side(glm::vec2 a, glm::vec2 b, glm::vec2 p)
|
||||
{
|
||||
return (b.x - a.x) * (p.y - a.y) - (b.y - a.y) * (p.x - a.x) >= 0.f;
|
||||
}
|
||||
|
||||
// intersect 2 closed polygons
|
||||
// a is a convex polygon
|
||||
// a and b are a list of non repeating points
|
||||
// returns the resulting intersection polygon points
|
||||
std::vector<vertex_t> poly_intersect(const std::vector<vertex_t>& poly, const std::vector<glm::vec2>& clip)
|
||||
{
|
||||
// implementing the Sutherland-Hodgman algorithm
|
||||
// see https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
|
||||
std::vector<vertex_t> ret = poly;
|
||||
for (int i = 0; i < clip.size(); i++)
|
||||
{
|
||||
std::vector<vertex_t> tmp;
|
||||
glm::vec2 edge[2] = { clip[i], clip[(i + 1) % clip.size()] };
|
||||
for (int j = 0; j < ret.size(); j++)
|
||||
{
|
||||
vertex_t s[2] = { ret[j], ret[(j + 1) % ret.size()] };
|
||||
bool side0 = point_side(edge[0], edge[1], s[0].pos);
|
||||
bool side1 = point_side(edge[0], edge[1], s[1].pos);
|
||||
if (side0 != side1) // intersecting
|
||||
{
|
||||
glm::vec2 pt;
|
||||
glm::vec2 hit_uv;
|
||||
segments_intersect(edge[0], edge[1], s[0].pos, s[1].pos, pt, hit_uv);
|
||||
vertex_t v;
|
||||
v.pos = glm::vec4(pt, 0, 1);
|
||||
v.uvs = glm::lerp(s[0].uvs, s[1].uvs, hit_uv.y);
|
||||
v.uvs2 = glm::lerp(s[0].uvs2, s[1].uvs2, hit_uv.y);
|
||||
if (side0) // outgoing
|
||||
{
|
||||
tmp.push_back(s[0]);
|
||||
tmp.push_back(v);
|
||||
}
|
||||
else // ingoing
|
||||
{
|
||||
tmp.push_back(v);
|
||||
}
|
||||
}
|
||||
else if (side0 && side1)
|
||||
{
|
||||
tmp.push_back(s[0]);
|
||||
}
|
||||
}
|
||||
ret = std::move(tmp);
|
||||
}
|
||||
return poly_remove_duplicate(ret);
|
||||
}
|
||||
|
||||
std::vector<glm::vec2> poly_intersect(const std::vector<glm::vec2>& poly, const std::vector<glm::vec2>& clip)
|
||||
{
|
||||
// implementing the Sutherland-Hodgman algorithm
|
||||
// see https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
|
||||
std::vector<glm::vec2> ret = poly;
|
||||
for (int i = 0; i < clip.size(); i++)
|
||||
{
|
||||
std::vector<glm::vec2> tmp;
|
||||
glm::vec2 edge[2] = { clip[i], clip[(i + 1) % clip.size()] };
|
||||
for (int j = 0; j < ret.size(); j++)
|
||||
{
|
||||
glm::vec2 s[2] = { ret[j], ret[(j + 1) % ret.size()] };
|
||||
bool side0 = point_side(edge[0], edge[1], s[0]);
|
||||
bool side1 = point_side(edge[0], edge[1], s[1]);
|
||||
if (side0 != side1) // intersecting
|
||||
{
|
||||
glm::vec2 pt;
|
||||
glm::vec2 hit_uv;
|
||||
segments_intersect(edge[0], edge[1], s[0], s[1], pt, hit_uv);
|
||||
if (side0) // outgoing
|
||||
{
|
||||
tmp.push_back(s[0]);
|
||||
tmp.push_back(pt);
|
||||
}
|
||||
else // ingoing
|
||||
{
|
||||
tmp.push_back(pt);
|
||||
}
|
||||
}
|
||||
else if (side0 && side1)
|
||||
{
|
||||
tmp.push_back(s[0]);
|
||||
}
|
||||
}
|
||||
ret = std::move(tmp);
|
||||
}
|
||||
return poly_remove_duplicate(ret);
|
||||
}
|
||||
|
||||
// clip the polygon to the near clip plane
|
||||
// poly is the polygon in camera coordinates
|
||||
std::vector<glm::vec3> poly_clip_near(const std::vector<glm::vec3>& poly, float near_plane_distance)
|
||||
{
|
||||
// implementing the Sutherland-Hodgman algorithm in 3D
|
||||
// see https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm
|
||||
|
||||
auto o = glm::vec3(0, 0, -near_plane_distance);
|
||||
auto n = glm::vec3(0, 0, -1);
|
||||
auto t = glm::vec3(0, 1, 0);
|
||||
std::vector<glm::vec3> ret;
|
||||
for (int j = 0; j < poly.size(); j++)
|
||||
{
|
||||
glm::vec3 s[2] = { poly[j], poly[(j + 1) % poly.size()] };
|
||||
bool side0 = glm::dot(n, s[0] - o) >= 0.f;
|
||||
bool side1 = glm::dot(n, s[1] - o) >= 0.f;
|
||||
if (side0 != side1) // intersecting
|
||||
{
|
||||
glm::vec3 pt;
|
||||
float hit_t;
|
||||
if (!ray_intersect(s[0], glm::normalize(s[1] - s[0]), o, n, t, pt, hit_t))
|
||||
{
|
||||
LOG("error ray_intersect");
|
||||
}
|
||||
if (side0) // outgoing
|
||||
{
|
||||
ret.push_back(s[0]);
|
||||
ret.push_back(pt);
|
||||
}
|
||||
else // ingoing
|
||||
{
|
||||
ret.push_back(pt);
|
||||
}
|
||||
}
|
||||
else if (side0 && side1)
|
||||
{
|
||||
ret.push_back(s[0]);
|
||||
}
|
||||
}
|
||||
return poly_remove_duplicate(ret);
|
||||
}
|
||||
|
||||
glm::vec4 rand_color()
|
||||
{
|
||||
float r = (rand() % 256) / 256.f;
|
||||
|
||||
Reference in New Issue
Block a user