Merge branch 'master' into blender2.8
This commit is contained in:
File diff suppressed because it is too large
Load Diff
17
extern/carve/carve-capi.cc
vendored
17
extern/carve/carve-capi.cc
vendored
@@ -568,6 +568,22 @@ void cleanupFaceEdgeAttrsCallback(const MeshSet<3> *left,
|
|||||||
&descr->orig_face_edge_mapping);
|
&descr->orig_face_edge_mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void copyVertexAttrsCallback(const carve::mesh::MeshSet<3>::vertex_t *orig_vert,
|
||||||
|
const carve::mesh::MeshSet<3>::vertex_t *new_vert,
|
||||||
|
void *descr_v)
|
||||||
|
{
|
||||||
|
CarveMeshDescr *descr = (CarveMeshDescr *) descr_v;
|
||||||
|
if (!descr->orig_vert_mapping.hasAttribute(orig_vert)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (descr->orig_vert_mapping.hasAttribute(new_vert)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
OrigIndex attr = descr->orig_vert_mapping.getAttribute(orig_vert);
|
||||||
|
descr->orig_vert_mapping.setAttribute(new_vert, attr);
|
||||||
|
descr->orig_vert_mapping.removeAttribute(orig_vert);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
CarveMeshDescr *carve_addMesh(struct ImportMeshData *import_data,
|
CarveMeshDescr *carve_addMesh(struct ImportMeshData *import_data,
|
||||||
@@ -751,6 +767,7 @@ bool carve_performBooleanOperation(CarveMeshDescr *left_mesh,
|
|||||||
// done properly. The only way to make such situations working is to
|
// done properly. The only way to make such situations working is to
|
||||||
// union intersecting meshes of the same operand.
|
// union intersecting meshes of the same operand.
|
||||||
carve_unionIntersections(&csg, &left, &right,
|
carve_unionIntersections(&csg, &left, &right,
|
||||||
|
copyVertexAttrsCallback,
|
||||||
cleanupFaceEdgeAttrsCallback,
|
cleanupFaceEdgeAttrsCallback,
|
||||||
(void *) output_descr);
|
(void *) output_descr);
|
||||||
|
|
||||||
|
|||||||
103
extern/carve/carve-util.cc
vendored
103
extern/carve/carve-util.cc
vendored
@@ -141,6 +141,11 @@ void carve_getRescaleMinMax(const MeshSet<3> *left,
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
struct UnionIntersectionContext {
|
||||||
|
VertexAttrsCallback vertex_attr_callback;
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
void copyMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes,
|
void copyMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes,
|
||||||
std::vector<MeshSet<3>::mesh_t*> *new_meshes)
|
std::vector<MeshSet<3>::mesh_t*> *new_meshes)
|
||||||
{
|
{
|
||||||
@@ -154,24 +159,73 @@ void copyMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshSet<3> *meshSetFromMeshes(const std::vector<MeshSet<3>::mesh_t*> &meshes)
|
struct NewMeshMapping {
|
||||||
|
std::map<const MeshSet<3>::edge_t*, MeshSet<3>::vertex_t*> orig_edge_vert;
|
||||||
|
};
|
||||||
|
|
||||||
|
void prepareNewMeshMapping(const std::vector<MeshSet<3>::mesh_t*> &meshes,
|
||||||
|
NewMeshMapping *mapping)
|
||||||
{
|
{
|
||||||
std::vector<MeshSet<3>::mesh_t*> new_meshes;
|
for (size_t m = 0; m < meshes.size(); ++m) {
|
||||||
|
MeshSet<3>::mesh_t *mesh = meshes[m];
|
||||||
copyMeshes(meshes, &new_meshes);
|
for (size_t f = 0; f < mesh->faces.size(); ++f) {
|
||||||
|
MeshSet<3>::face_t *face = mesh->faces[f];
|
||||||
return new MeshSet<3>(new_meshes);
|
MeshSet<3>::edge_t *edge = face->edge;
|
||||||
|
do {
|
||||||
|
mapping->orig_edge_vert[edge] = edge->vert;
|
||||||
|
edge = edge->next;
|
||||||
|
} while (edge != face->edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshSet<3> *meshSetFromTwoMeshes(const std::vector<MeshSet<3>::mesh_t*> &left_meshes,
|
void runNewMeshSetHooks(UnionIntersectionContext *ctx,
|
||||||
|
NewMeshMapping *mapping,
|
||||||
|
MeshSet<3> *mesh_set)
|
||||||
|
{
|
||||||
|
for (size_t m = 0; m < mesh_set->meshes.size(); ++m) {
|
||||||
|
MeshSet<3>::mesh_t *mesh = mesh_set->meshes[m];
|
||||||
|
for (size_t f = 0; f < mesh->faces.size(); ++f) {
|
||||||
|
MeshSet<3>::face_t *face = mesh->faces[f];
|
||||||
|
MeshSet<3>::edge_t *edge = face->edge;
|
||||||
|
do {
|
||||||
|
const MeshSet<3>::vertex_t *orig_vert = mapping->orig_edge_vert[edge];
|
||||||
|
const MeshSet<3>::vertex_t *new_vert = edge->vert;
|
||||||
|
ctx->vertex_attr_callback(orig_vert, new_vert, ctx->user_data);
|
||||||
|
edge = edge->next;
|
||||||
|
} while (edge != face->edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshSet<3> *newMeshSetFromMeshesWithAttrs(
|
||||||
|
UnionIntersectionContext *ctx,
|
||||||
|
std::vector<MeshSet<3>::mesh_t*> &meshes)
|
||||||
|
{
|
||||||
|
NewMeshMapping mapping;
|
||||||
|
prepareNewMeshMapping(meshes, &mapping);
|
||||||
|
MeshSet<3> *mesh_set = new MeshSet<3>(meshes);
|
||||||
|
runNewMeshSetHooks(ctx, &mapping, mesh_set);
|
||||||
|
return mesh_set;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
MeshSet<3> *meshSetFromMeshes(UnionIntersectionContext *ctx,
|
||||||
|
const std::vector<MeshSet<3>::mesh_t*> &meshes)
|
||||||
|
{
|
||||||
|
std::vector<MeshSet<3>::mesh_t*> new_meshes;
|
||||||
|
copyMeshes(meshes, &new_meshes);
|
||||||
|
return newMeshSetFromMeshesWithAttrs(ctx, new_meshes);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshSet<3> *meshSetFromTwoMeshes(UnionIntersectionContext *ctx,
|
||||||
|
const std::vector<MeshSet<3>::mesh_t*> &left_meshes,
|
||||||
const std::vector<MeshSet<3>::mesh_t*> &right_meshes)
|
const std::vector<MeshSet<3>::mesh_t*> &right_meshes)
|
||||||
{
|
{
|
||||||
std::vector<MeshSet<3>::mesh_t*> new_meshes;
|
std::vector<MeshSet<3>::mesh_t*> new_meshes;
|
||||||
|
|
||||||
copyMeshes(left_meshes, &new_meshes);
|
copyMeshes(left_meshes, &new_meshes);
|
||||||
copyMeshes(right_meshes, &new_meshes);
|
copyMeshes(right_meshes, &new_meshes);
|
||||||
|
return newMeshSetFromMeshesWithAttrs(ctx, new_meshes);
|
||||||
return new MeshSet<3>(new_meshes);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkEdgeFaceIntersections_do(Intersections &intersections,
|
bool checkEdgeFaceIntersections_do(Intersections &intersections,
|
||||||
@@ -349,7 +403,8 @@ void getIntersectedOperandMeshes(std::vector<MeshSet<3>::mesh_t*> *meshes,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshSet<3> *getIntersectedOperand(std::vector<MeshSet<3>::mesh_t*> *meshes,
|
MeshSet<3> *getIntersectedOperand(UnionIntersectionContext *ctx,
|
||||||
|
std::vector<MeshSet<3>::mesh_t*> *meshes,
|
||||||
const MeshSet<3>::aabb_t &otherAABB,
|
const MeshSet<3>::aabb_t &otherAABB,
|
||||||
RTreeCache *rtree_cache,
|
RTreeCache *rtree_cache,
|
||||||
IntersectCache *intersect_cache)
|
IntersectCache *intersect_cache)
|
||||||
@@ -360,13 +415,14 @@ MeshSet<3> *getIntersectedOperand(std::vector<MeshSet<3>::mesh_t*> *meshes,
|
|||||||
if (operandMeshes.size() == 0)
|
if (operandMeshes.size() == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return meshSetFromMeshes(operandMeshes);
|
return meshSetFromMeshes(ctx, operandMeshes);
|
||||||
}
|
}
|
||||||
|
|
||||||
MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
||||||
MeshSet<3> *poly,
|
MeshSet<3> *poly,
|
||||||
const MeshSet<3> *other_poly,
|
const MeshSet<3> *other_poly,
|
||||||
const MeshSet<3>::aabb_t &otherAABB,
|
const MeshSet<3>::aabb_t &otherAABB,
|
||||||
|
VertexAttrsCallback vertex_attr_callback,
|
||||||
UnionIntersectionsCallback callback,
|
UnionIntersectionsCallback callback,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
@@ -380,7 +436,12 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
|||||||
RTreeCache rtree_cache;
|
RTreeCache rtree_cache;
|
||||||
IntersectCache intersect_cache;
|
IntersectCache intersect_cache;
|
||||||
|
|
||||||
MeshSet<3> *left = getIntersectedOperand(&orig_meshes,
|
UnionIntersectionContext ctx;
|
||||||
|
ctx.vertex_attr_callback = vertex_attr_callback;
|
||||||
|
ctx.user_data = user_data;
|
||||||
|
|
||||||
|
MeshSet<3> *left = getIntersectedOperand(&ctx,
|
||||||
|
&orig_meshes,
|
||||||
otherAABB,
|
otherAABB,
|
||||||
&rtree_cache,
|
&rtree_cache,
|
||||||
&intersect_cache);
|
&intersect_cache);
|
||||||
@@ -391,7 +452,8 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (orig_meshes.size()) {
|
while (orig_meshes.size()) {
|
||||||
MeshSet<3> *right = getIntersectedOperand(&orig_meshes,
|
MeshSet<3> *right = getIntersectedOperand(&ctx,
|
||||||
|
&orig_meshes,
|
||||||
otherAABB,
|
otherAABB,
|
||||||
&rtree_cache,
|
&rtree_cache,
|
||||||
&intersect_cache);
|
&intersect_cache);
|
||||||
@@ -422,7 +484,9 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
|||||||
catch (carve::exception e) {
|
catch (carve::exception e) {
|
||||||
std::cerr << "CSG failed, exception " << e.str() << std::endl;
|
std::cerr << "CSG failed, exception " << e.str() << std::endl;
|
||||||
|
|
||||||
MeshSet<3> *result = meshSetFromTwoMeshes(left->meshes, right->meshes);
|
MeshSet<3> *result = meshSetFromTwoMeshes(&ctx,
|
||||||
|
left->meshes,
|
||||||
|
right->meshes);
|
||||||
|
|
||||||
callback(result, other_poly, user_data);
|
callback(result, other_poly, user_data);
|
||||||
|
|
||||||
@@ -448,7 +512,9 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
|||||||
|
|
||||||
// Append all meshes which doesn't have intersection with another operand as-is.
|
// Append all meshes which doesn't have intersection with another operand as-is.
|
||||||
if (orig_meshes.size()) {
|
if (orig_meshes.size()) {
|
||||||
MeshSet<3> *result = meshSetFromTwoMeshes(left->meshes, orig_meshes);
|
MeshSet<3> *result = meshSetFromTwoMeshes(&ctx,
|
||||||
|
left->meshes,
|
||||||
|
orig_meshes);
|
||||||
|
|
||||||
delete left;
|
delete left;
|
||||||
left = result;
|
left = result;
|
||||||
@@ -464,6 +530,7 @@ MeshSet<3> *unionIntersectingMeshes(carve::csg::CSG *csg,
|
|||||||
void carve_unionIntersections(carve::csg::CSG *csg,
|
void carve_unionIntersections(carve::csg::CSG *csg,
|
||||||
MeshSet<3> **left_r,
|
MeshSet<3> **left_r,
|
||||||
MeshSet<3> **right_r,
|
MeshSet<3> **right_r,
|
||||||
|
VertexAttrsCallback vertex_attr_callback,
|
||||||
UnionIntersectionsCallback callback,
|
UnionIntersectionsCallback callback,
|
||||||
void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
@@ -477,9 +544,9 @@ void carve_unionIntersections(carve::csg::CSG *csg,
|
|||||||
MeshSet<3>::aabb_t rightAABB = right->getAABB();;
|
MeshSet<3>::aabb_t rightAABB = right->getAABB();;
|
||||||
|
|
||||||
left = unionIntersectingMeshes(csg, left, right, rightAABB,
|
left = unionIntersectingMeshes(csg, left, right, rightAABB,
|
||||||
callback, user_data);
|
vertex_attr_callback, callback, user_data);
|
||||||
right = unionIntersectingMeshes(csg, right, left, leftAABB,
|
right = unionIntersectingMeshes(csg, right, left, leftAABB,
|
||||||
callback, user_data);
|
vertex_attr_callback, callback, user_data);
|
||||||
|
|
||||||
if (left != *left_r) {
|
if (left != *left_r) {
|
||||||
delete *left_r;
|
delete *left_r;
|
||||||
|
|||||||
12
extern/carve/carve-util.h
vendored
12
extern/carve/carve-util.h
vendored
@@ -70,6 +70,10 @@ void carve_getRescaleMinMax(const carve::mesh::MeshSet<3> *left,
|
|||||||
carve::geom3d::Vector *min,
|
carve::geom3d::Vector *min,
|
||||||
carve::geom3d::Vector *max);
|
carve::geom3d::Vector *max);
|
||||||
|
|
||||||
|
typedef void (*VertexAttrsCallback) (const carve::mesh::MeshSet<3>::vertex_t *orig_vert,
|
||||||
|
const carve::mesh::MeshSet<3>::vertex_t *new_vert,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left,
|
typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left,
|
||||||
const carve::mesh::MeshSet<3> *right,
|
const carve::mesh::MeshSet<3> *right,
|
||||||
void *userdata);
|
void *userdata);
|
||||||
@@ -77,6 +81,7 @@ typedef void (*UnionIntersectionsCallback) (const carve::mesh::MeshSet<3> *left,
|
|||||||
void carve_unionIntersections(carve::csg::CSG *csg,
|
void carve_unionIntersections(carve::csg::CSG *csg,
|
||||||
carve::mesh::MeshSet<3> **left_r,
|
carve::mesh::MeshSet<3> **left_r,
|
||||||
carve::mesh::MeshSet<3> **right_r,
|
carve::mesh::MeshSet<3> **right_r,
|
||||||
|
VertexAttrsCallback vertex_attr_callback,
|
||||||
UnionIntersectionsCallback callback,
|
UnionIntersectionsCallback callback,
|
||||||
void *user_data);
|
void *user_data);
|
||||||
|
|
||||||
@@ -148,6 +153,13 @@ namespace carve {
|
|||||||
void setAttribute(const meshset_t::vertex_t *v, const attr_t &attr) {
|
void setAttribute(const meshset_t::vertex_t *v, const attr_t &attr) {
|
||||||
attrs[v] = attr;
|
attrs[v] = attr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeAttribute(const meshset_t::vertex_t *v) {
|
||||||
|
typename attrmap_t::iterator it = attrs.find(v);
|
||||||
|
if (it != attrs.end()) {
|
||||||
|
attrs.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename attr_t>
|
template<typename attr_t>
|
||||||
|
|||||||
@@ -33,8 +33,12 @@ void BLI_polyfill_beautify(
|
|||||||
/* structs for reuse */
|
/* structs for reuse */
|
||||||
struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh);
|
struct MemArena *arena, struct Heap *eheap, struct EdgeHash *eh);
|
||||||
|
|
||||||
float BLI_polyfill_beautify_quad_rotate_calc(
|
float BLI_polyfill_beautify_quad_rotate_calc_ex(
|
||||||
const float v1[2], const float v2[2], const float v3[2], const float v4[2]);
|
const float v1[2], const float v2[2], const float v3[2], const float v4[2],
|
||||||
|
const bool lock_degenerate);
|
||||||
|
#define BLI_polyfill_beautify_quad_rotate_calc(v1, v2, v3, v4) \
|
||||||
|
BLI_polyfill_beautify_quad_rotate_calc_ex(v1, v2, v3, v4, false)
|
||||||
|
|
||||||
|
|
||||||
/* avoid realloc's when creating new structures for polyfill ngons */
|
/* avoid realloc's when creating new structures for polyfill ngons */
|
||||||
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
|
#define BLI_POLYFILL_ALLOC_NGON_RESERVE 64
|
||||||
|
|||||||
@@ -123,8 +123,9 @@ BLI_INLINE bool is_boundary_edge(unsigned int i_a, unsigned int i_b, const unsig
|
|||||||
*
|
*
|
||||||
* \return (negative number means the edge can be rotated, lager == better).
|
* \return (negative number means the edge can be rotated, lager == better).
|
||||||
*/
|
*/
|
||||||
float BLI_polyfill_beautify_quad_rotate_calc(
|
float BLI_polyfill_beautify_quad_rotate_calc_ex(
|
||||||
const float v1[2], const float v2[2], const float v3[2], const float v4[2])
|
const float v1[2], const float v2[2], const float v3[2], const float v4[2],
|
||||||
|
const bool lock_degenerate)
|
||||||
{
|
{
|
||||||
/* not a loop (only to be able to break out) */
|
/* not a loop (only to be able to break out) */
|
||||||
do {
|
do {
|
||||||
@@ -136,12 +137,12 @@ float BLI_polyfill_beautify_quad_rotate_calc(
|
|||||||
const float area_2x_123 = cross_tri_v2(v1, v2, v3);
|
const float area_2x_123 = cross_tri_v2(v1, v2, v3);
|
||||||
const float area_2x_134 = cross_tri_v2(v1, v3, v4);
|
const float area_2x_134 = cross_tri_v2(v1, v3, v4);
|
||||||
|
|
||||||
{
|
|
||||||
BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
|
BLI_assert((ELEM(v1, v2, v3, v4) == false) &&
|
||||||
(ELEM(v2, v1, v3, v4) == false) &&
|
(ELEM(v2, v1, v3, v4) == false) &&
|
||||||
(ELEM(v3, v1, v2, v4) == false) &&
|
(ELEM(v3, v1, v2, v4) == false) &&
|
||||||
(ELEM(v4, v1, v2, v3) == false));
|
(ELEM(v4, v1, v2, v3) == false));
|
||||||
|
|
||||||
|
if (lock_degenerate) {
|
||||||
is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON);
|
is_zero_a = (fabsf(area_2x_234) <= FLT_EPSILON);
|
||||||
is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON);
|
is_zero_b = (fabsf(area_2x_241) <= FLT_EPSILON);
|
||||||
|
|
||||||
|
|||||||
@@ -1517,7 +1517,25 @@ void BM_mesh_calc_tessellation_beauty(BMesh *bm, BMLoop *(*looptris)[3], int *r_
|
|||||||
BMLoop *l_v3 = l_v2->next;
|
BMLoop *l_v3 = l_v2->next;
|
||||||
BMLoop *l_v4 = l_v1->prev;
|
BMLoop *l_v4 = l_v1->prev;
|
||||||
|
|
||||||
const bool split_24 = (BM_verts_calc_rotate_beauty(l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) > 0.0f);
|
/* #BM_verts_calc_rotate_beauty performs excessive checks we don't need!
|
||||||
|
* It's meant for rotating edges, it also calculates a new normal.
|
||||||
|
*
|
||||||
|
* Use #BLI_polyfill_beautify_quad_rotate_calc since we have the normal.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
const bool split_24 = (BM_verts_calc_rotate_beauty(
|
||||||
|
l_v1->v, l_v2->v, l_v3->v, l_v4->v, 0, 0) < 0.0f);
|
||||||
|
#else
|
||||||
|
float axis_mat[3][3], v_quad[4][2];
|
||||||
|
axis_dominant_v3_to_m3(axis_mat, efa->no);
|
||||||
|
mul_v2_m3v3(v_quad[0], axis_mat, l_v1->v->co);
|
||||||
|
mul_v2_m3v3(v_quad[1], axis_mat, l_v2->v->co);
|
||||||
|
mul_v2_m3v3(v_quad[2], axis_mat, l_v3->v->co);
|
||||||
|
mul_v2_m3v3(v_quad[3], axis_mat, l_v4->v->co);
|
||||||
|
|
||||||
|
const bool split_24 = BLI_polyfill_beautify_quad_rotate_calc(
|
||||||
|
v_quad[0], v_quad[1], v_quad[2], v_quad[3]) < 0.0f;
|
||||||
|
#endif
|
||||||
|
|
||||||
BMLoop **l_ptr_a = looptris[i++];
|
BMLoop **l_ptr_a = looptris[i++];
|
||||||
BMLoop **l_ptr_b = looptris[i++];
|
BMLoop **l_ptr_b = looptris[i++];
|
||||||
|
|||||||
@@ -182,7 +182,12 @@ static float bm_edge_calc_rotate_beauty__area(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLI_polyfill_beautify_quad_rotate_calc(v1_xy, v2_xy, v3_xy, v4_xy);
|
/**
|
||||||
|
* Important to lock degenerate here,
|
||||||
|
* since the triangle pars will be projected into different 2D spaces.
|
||||||
|
* Allowing to rotate out of a degenerate state can flip the faces (when performed iteratively).
|
||||||
|
*/
|
||||||
|
return BLI_polyfill_beautify_quad_rotate_calc_ex(v1_xy, v2_xy, v3_xy, v4_xy, true);
|
||||||
} while (false);
|
} while (false);
|
||||||
|
|
||||||
return FLT_MAX;
|
return FLT_MAX;
|
||||||
|
|||||||
Reference in New Issue
Block a user