Bundled VHACD library for convex decomposition.

Modified both MeshInstance tools as well as importer to use it instead of QuickHull.
This commit is contained in:
Juan Linietsky 2019-04-10 17:46:04 -03:00
parent 07b76c0376
commit 5823b5d77d
41 changed files with 18270 additions and 135 deletions

View file

@ -279,7 +279,24 @@ static String _fixstr(const String &p_what, const String &p_str) {
return what;
}
Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode) {
static void _gen_shape_list(const Ref<Mesh> &mesh, List<Ref<Shape> > &r_shape_list, bool p_convex) {
if (!p_convex) {
Ref<Shape> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
} else {
Vector<Ref<Shape> > cd = mesh->convex_decompose();
if (cd.size()) {
for (int i = 0; i < cd.size(); i++) {
r_shape_list.push_back(cd[i]);
}
}
}
}
Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode) {
// children first
for (int i = 0; i < p_node->get_child_count(); i++) {
@ -365,37 +382,52 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array
return p_node;
MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
if (mi) {
Node *col = NULL;
Ref<Mesh> mesh = mi->get_mesh();
if (_teststr(name, "colonly")) {
col = mi->create_trimesh_collision_node();
if (col == NULL) {
ERR_PRINTS("Error generating collision for mesh: " + name);
} else {
col->set_name(_fixstr(name, "colonly"));
if (mesh.is_valid()) {
List<Ref<Shape> > shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(name, "colonly")) {
_gen_shape_list(mesh, shapes, false);
collision_map[mesh] = shapes;
} else if (_teststr(name, "convcolonly")) {
_gen_shape_list(mesh, shapes, true);
collision_map[mesh] = shapes;
}
} else {
col = mi->create_convex_collision_node();
if (col == NULL) {
ERR_PRINTS("Error generating collision for mesh: " + name);
} else {
col->set_name(_fixstr(name, "convcolonly"));
if (_teststr(name, "colonly")) {
fixed_name = _fixstr(name, "colonly");
} else if (_teststr(name, "convcolonly")) {
fixed_name = _fixstr(name, "convcolonly");
}
ERR_FAIL_COND_V(fixed_name == String(), NULL);
if (shapes.size()) {
StaticBody *col = memnew(StaticBody);
col->set_transform(mi->get_transform());
col->set_name(fixed_name);
p_node->replace_by(col);
memdelete(p_node);
p_node = col;
int idx = 0;
for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(E->get());
col->add_child(cshape);
cshape->set_name("shape" + itos(idx));
cshape->set_owner(col->get_owner());
idx++;
}
}
}
if (col) {
Object::cast_to<Spatial>(col)->set_transform(mi->get_transform());
p_node->replace_by(col);
memdelete(p_node);
p_node = col;
StaticBody *sb = Object::cast_to<StaticBody>(col);
CollisionShape *colshape = Object::cast_to<CollisionShape>(sb->get_child(0));
colshape->set_name("shape");
colshape->set_owner(p_node->get_owner());
}
} else if (p_node->has_meta("empty_draw_type")) {
String empty_draw_type = String(p_node->get_meta("empty_draw_type"));
StaticBody *sb = memnew(StaticBody);
@ -434,78 +466,92 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array
if (isroot)
return p_node;
// get mesh instance and bounding box
MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
AABB aabb = mi->get_aabb();
Ref<Mesh> mesh = mi->get_mesh();
// create a new rigid body collision node
RigidBody *rigid_body = memnew(RigidBody);
Node *col = rigid_body;
ERR_FAIL_COND_V(!col, NULL);
if (mesh.is_valid()) {
List<Ref<Shape> > shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else {
_gen_shape_list(mesh, shapes, true);
}
// remove node name postfix
col->set_name(_fixstr(name, "rigid"));
// get mesh instance xform matrix to the rigid body collision node
Object::cast_to<Spatial>(col)->set_transform(mi->get_transform());
// save original node by duplicating it into a new instance and correcting the name
Node *mesh = p_node->duplicate();
mesh->set_name(_fixstr(name, "rigid"));
// reset the xform matrix of the duplicated node so it can inherit parent node xform
Object::cast_to<Spatial>(mesh)->set_transform(Transform(Basis()));
// reparent the new mesh node to the rigid body collision node
p_node->add_child(mesh);
mesh->set_owner(p_node->get_owner());
// replace the original node with the rigid body collision node
p_node->replace_by(col);
memdelete(p_node);
p_node = col;
RigidBody *rigid_body = memnew(RigidBody);
rigid_body->set_name(_fixstr(name, "rigid"));
p_node->replace_by(rigid_body);
rigid_body->set_transform(mi->get_transform());
p_node = rigid_body;
mi->set_name("mesh");
mi->set_transform(Transform());
rigid_body->add_child(mi);
mi->set_owner(rigid_body->get_owner());
// create an alias for the rigid body collision node
RigidBody *rb = Object::cast_to<RigidBody>(col);
// create a new Box collision shape and set the right extents
Ref<BoxShape> shape = memnew(BoxShape);
shape->set_extents(aabb.get_size() * 0.5);
CollisionShape *colshape = memnew(CollisionShape);
colshape->set_name("shape");
colshape->set_shape(shape);
// reparent the new collision shape to the rigid body collision node
rb->add_child(colshape);
colshape->set_owner(p_node->get_owner());
int idx = 0;
for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(E->get());
rigid_body->add_child(cshape);
cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
}
}
} else if ((_teststr(name, "col") || (_teststr(name, "convcol"))) && Object::cast_to<MeshInstance>(p_node)) {
MeshInstance *mi = Object::cast_to<MeshInstance>(p_node);
Node *col;
if (_teststr(name, "col")) {
String new_name = _fixstr(name, "col");
if (mi->get_parent() && !mi->get_parent()->has_node(new_name)) {
mi->set_name(new_name);
Ref<Mesh> mesh = mi->get_mesh();
if (mesh.is_valid()) {
List<Ref<Shape> > shapes;
String fixed_name;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(name, "col")) {
_gen_shape_list(mesh, shapes, false);
collision_map[mesh] = shapes;
} else if (_teststr(name, "convcol")) {
_gen_shape_list(mesh, shapes, true);
collision_map[mesh] = shapes;
}
col = mi->create_trimesh_collision_node();
ERR_FAIL_COND_V(!col, NULL);
col->set_name("col");
} else {
String new_name = _fixstr(name, "convcol");
if (mi->get_parent() && !mi->get_parent()->has_node(new_name)) {
mi->set_name(new_name);
if (_teststr(name, "col")) {
fixed_name = _fixstr(name, "col");
} else if (_teststr(name, "convcol")) {
fixed_name = _fixstr(name, "convcol");
}
col = mi->create_convex_collision_node();
ERR_FAIL_COND_V(!col, NULL);
col->set_name("convcol");
if (fixed_name != String()) {
if (mi->get_parent() && !mi->get_parent()->has_node(fixed_name)) {
mi->set_name(fixed_name);
}
}
if (shapes.size()) {
StaticBody *col = memnew(StaticBody);
col->set_name("static_collision");
mi->add_child(col);
col->set_owner(mi->get_owner());
int idx = 0;
for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(E->get());
col->add_child(cshape);
cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
}
}
}
p_node->add_child(col);
StaticBody *sb = Object::cast_to<StaticBody>(col);
CollisionShape *colshape = Object::cast_to<CollisionShape>(sb->get_child(0));
colshape->set_name("shape");
col->add_child(colshape);
colshape->set_owner(p_node->get_owner());
sb->set_owner(p_node->get_owner());
} else if (_teststr(name, "navmesh") && Object::cast_to<MeshInstance>(p_node)) {
if (isroot)
@ -574,48 +620,35 @@ Node *ResourceImporterScene::_fix_node(Node *p_node, Node *p_root, Map<Ref<Array
Ref<ArrayMesh> mesh = mi->get_mesh();
if (!mesh.is_null()) {
if (_teststr(mesh->get_name(), "col") || _teststr(mesh->get_name(), "convcol")) {
Ref<Shape> shape;
if (_teststr(mesh->get_name(), "col")) {
mesh->set_name(_fixstr(mesh->get_name(), "col"));
List<Ref<Shape> > shapes;
if (collision_map.has(mesh)) {
shapes = collision_map[mesh];
} else if (_teststr(mesh->get_name(), "col")) {
_gen_shape_list(mesh, shapes, false);
collision_map[mesh] = shapes;
mesh->set_name(_fixstr(mesh->get_name(), "col"));
} else if (_teststr(mesh->get_name(), "convcol")) {
_gen_shape_list(mesh, shapes, true);
collision_map[mesh] = shapes;
mesh->set_name(_fixstr(mesh->get_name(), "convcol"));
}
if (collision_map.has(mesh)) {
shape = collision_map[mesh];
if (shapes.size()) {
StaticBody *col = memnew(StaticBody);
col->set_name("static_collision");
p_node->add_child(col);
col->set_owner(p_node->get_owner());
} else {
int idx = 0;
for (List<Ref<Shape> >::Element *E = shapes.front(); E; E = E->next()) {
shape = mesh->create_trimesh_shape();
if (!shape.is_null())
collision_map[mesh] = shape;
}
} else if (_teststr(mesh->get_name(), "convcol")) {
mesh->set_name(_fixstr(mesh->get_name(), "convcol"));
if (collision_map.has(mesh)) {
shape = collision_map[mesh];
} else {
shape = mesh->create_convex_shape();
if (!shape.is_null())
collision_map[mesh] = shape;
}
}
if (!shape.is_null()) {
StaticBody *col = memnew(StaticBody);
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shape);
cshape->set_shape(E->get());
col->add_child(cshape);
col->set_transform(mi->get_transform());
col->set_name(mi->get_name());
p_node->replace_by(col);
memdelete(p_node);
p_node = col;
cshape->set_name("shape");
cshape->set_name("shape" + itos(idx));
cshape->set_owner(p_node->get_owner());
idx++;
}
}
}
@ -1269,7 +1302,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p
float anim_optimizer_maxang = p_options["animation/optimizer/max_angle"];
int light_bake_mode = p_options["meshes/light_baking"];
Map<Ref<ArrayMesh>, Ref<Shape> > collision_map;
Map<Ref<Mesh>, List<Ref<Shape> > > collision_map;
scene = _fix_node(scene, scene, collision_map, LightBakeMode(light_bake_mode));

View file

@ -146,7 +146,7 @@ public:
void _make_external_resources(Node *p_node, const String &p_base_path, bool p_make_animations, bool p_keep_animations, bool p_make_materials, bool p_keep_materials, bool p_make_meshes, Map<Ref<Animation>, Ref<Animation> > &p_animations, Map<Ref<Material>, Ref<Material> > &p_materials, Map<Ref<ArrayMesh>, Ref<ArrayMesh> > &p_meshes);
Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<ArrayMesh>, Ref<Shape> > &collision_map, LightBakeMode p_light_bake_mode);
Node *_fix_node(Node *p_node, Node *p_root, Map<Ref<Mesh>, List<Ref<Shape> > > &collision_map, LightBakeMode p_light_bake_mode);
void _create_clips(Node *scene, const Array &p_clips, bool p_bake_all);
void _filter_anim_tracks(Ref<Animation> anim, Set<String> &keep);

View file

@ -95,10 +95,7 @@ void MeshInstanceEditor::_menu_option(int p_option) {
return;
}
if (trimesh_shape)
ur->create_action(TTR("Create Static Trimesh Body"));
else
ur->create_action(TTR("Create Static Convex Body"));
ur->create_action(TTR("Create Static Trimesh Body"));
for (List<Node *>::Element *E = selection.front(); E; E = E->next()) {
@ -132,8 +129,7 @@ void MeshInstanceEditor::_menu_option(int p_option) {
} break;
case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE:
case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: {
case MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE: {
if (node == get_tree()->get_edited_scene_root()) {
err_dialog->set_text(TTR("This doesn't work on scene root!"));
@ -141,9 +137,7 @@ void MeshInstanceEditor::_menu_option(int p_option) {
return;
}
bool trimesh_shape = (p_option == MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
Ref<Shape> shape = trimesh_shape ? mesh->create_trimesh_shape() : mesh->create_convex_shape();
Ref<Shape> shape = mesh->create_trimesh_shape();
if (shape.is_null())
return;
@ -154,10 +148,7 @@ void MeshInstanceEditor::_menu_option(int p_option) {
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
if (trimesh_shape)
ur->create_action(TTR("Create Trimesh Shape"));
else
ur->create_action(TTR("Create Convex Shape"));
ur->create_action(TTR("Create Trimesh Static Shape"));
ur->add_do_method(node->get_parent(), "add_child", cshape);
ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
@ -165,6 +156,40 @@ void MeshInstanceEditor::_menu_option(int p_option) {
ur->add_do_reference(cshape);
ur->add_undo_method(node->get_parent(), "remove_child", cshape);
ur->commit_action();
} break;
case MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE: {
if (node == get_tree()->get_edited_scene_root()) {
err_dialog->set_text(TTR("This doesn't work on scene root!"));
err_dialog->popup_centered_minsize();
return;
}
Vector<Ref<Shape> > shapes = mesh->convex_decompose();
if (!shapes.size()) {
err_dialog->set_text(TTR("Failed creating shapes!"));
err_dialog->popup_centered_minsize();
return;
}
UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
ur->create_action(TTR("Create Convex Shape(s)"));
for (int i = 0; i < shapes.size(); i++) {
CollisionShape *cshape = memnew(CollisionShape);
cshape->set_shape(shapes[i]);
Node *owner = node->get_owner();
ur->add_do_method(node->get_parent(), "add_child", cshape);
ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1);
ur->add_do_method(cshape, "set_owner", owner);
ur->add_do_reference(cshape);
ur->add_undo_method(node->get_parent(), "remove_child", cshape);
}
ur->commit_action();
} break;
@ -393,10 +418,9 @@ MeshInstanceEditor::MeshInstanceEditor() {
options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("MeshInstance", "EditorIcons"));
options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
options->get_popup()->add_item(TTR("Create Convex Static Body"), MENU_OPTION_CREATE_STATIC_CONVEX_BODY);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Trimesh Collision Sibling"), MENU_OPTION_CREATE_TRIMESH_COLLISION_SHAPE);
options->get_popup()->add_item(TTR("Create Convex Collision Sibling"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE);
options->get_popup()->add_item(TTR("Create Convex Collision Sibling(s)"), MENU_OPTION_CREATE_CONVEX_COLLISION_SHAPE);
options->get_popup()->add_separator();
options->get_popup()->add_item(TTR("Create Navigation Mesh"), MENU_OPTION_CREATE_NAVMESH);
options->get_popup()->add_separator();

34
modules/vhacd/SCsub Normal file
View file

@ -0,0 +1,34 @@
#!/usr/bin/env python
Import('env')
Import('env_modules')
env_vhacd = env_modules.Clone()
# Thirdparty source files
thirdparty_dir = "#thirdparty/vhacd/"
thirdparty_sources = [
"src/vhacdManifoldMesh.cpp",
"src/FloatMath.cpp",
"src/vhacdMesh.cpp",
"src/vhacdICHull.cpp",
"src/vhacdVolume.cpp",
"src/VHACD-ASYNC.cpp",
"src/btAlignedAllocator.cpp",
"src/vhacdRaycastMesh.cpp",
"src/VHACD.cpp",
"src/btConvexHullComputer.cpp"
]
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
env_vhacd.Append(CPPPATH=[thirdparty_dir+"/inc"])
env_vhacd.Append(CPPFLAGS=["-DGODOT_ENET"])
env_thirdparty = env_vhacd.Clone()
env_thirdparty.disable_warnings()
env_thirdparty.add_source_files(env.modules_sources, thirdparty_sources)
env_vhacd.add_source_files(env.modules_sources, "*.cpp")

6
modules/vhacd/config.py Normal file
View file

@ -0,0 +1,6 @@
def can_build(env, platform):
return True
def configure(env):
pass

View file

@ -0,0 +1,88 @@
/*************************************************************************/
/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
#include "scene/resources/mesh.h"
#include "thirdparty/vhacd/public/VHACD.h"
static Vector<Vector<Face3> > convex_decompose(const Vector<Face3> &p_faces) {
Vector<float> vertices;
vertices.resize(p_faces.size() * 9);
Vector<uint32_t> indices;
indices.resize(p_faces.size() * 3);
for (int i = 0; i < p_faces.size(); i++) {
for (int j = 0; j < 3; j++) {
vertices.write[i * 9 + j * 3 + 0] = p_faces[i].vertex[j].x;
vertices.write[i * 9 + j * 3 + 1] = p_faces[i].vertex[j].y;
vertices.write[i * 9 + j * 3 + 2] = p_faces[i].vertex[j].z;
indices.write[i * 3 + j] = i * 3 + j;
}
}
VHACD::IVHACD *decomposer = VHACD::CreateVHACD();
VHACD::IVHACD::Parameters params;
decomposer->Compute(vertices.ptr(), vertices.size() / 3, indices.ptr(), indices.size() / 3, params);
int hull_count = decomposer->GetNConvexHulls();
Vector<Vector<Face3> > ret;
for (int i = 0; i < hull_count; i++) {
Vector<Face3> triangles;
VHACD::IVHACD::ConvexHull hull;
decomposer->GetConvexHull(i, hull);
triangles.resize(hull.m_nTriangles);
for (uint32_t j = 0; j < hull.m_nTriangles; j++) {
Face3 f;
for (int k = 0; k < 3; k++) {
for (int l = 0; l < 3; l++) {
f.vertex[k][l] = hull.m_points[hull.m_triangles[j * 3 + k] * 3 + l];
}
}
triangles.write[j] = f;
}
ret.push_back(triangles);
}
decomposer->Clean();
decomposer->Release();
return ret;
}
void register_vhacd_types() {
Mesh::convex_composition_function = convex_decompose;
}
void unregister_vhacd_types() {
Mesh::convex_composition_function = NULL;
}

View file

@ -0,0 +1,32 @@
/*************************************************************************/
/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
void register_vhacd_types();
void unregister_vhacd_types();

View file

@ -37,6 +37,8 @@
#include <stdlib.h>
Mesh::ConvexDecompositionFunc Mesh::convex_composition_function = NULL;
Ref<TriangleMesh> Mesh::generate_triangle_mesh() const {
if (triangle_mesh.is_valid())
@ -543,6 +545,49 @@ void Mesh::clear_cache() const {
debug_lines.clear();
}
Vector<Ref<Shape> > Mesh::convex_decompose() const {
ERR_FAIL_COND_V(!convex_composition_function, Vector<Ref<Shape> >());
PoolVector<Face3> faces = get_faces();
Vector<Face3> f3;
f3.resize(faces.size());
PoolVector<Face3>::Read f = faces.read();
for (int i = 0; i < f3.size(); i++) {
f3.write[i] = f[i];
}
Vector<Vector<Face3> > decomposed = convex_composition_function(f3);
Vector<Ref<Shape> > ret;
for (int i = 0; i < decomposed.size(); i++) {
Set<Vector3> points;
for (int j = 0; j < decomposed[i].size(); j++) {
points.insert(decomposed[i][j].vertex[0]);
points.insert(decomposed[i][j].vertex[1]);
points.insert(decomposed[i][j].vertex[2]);
}
PoolVector<Vector3> convex_points;
convex_points.resize(points.size());
{
PoolVector<Vector3>::Write w = convex_points.write();
int idx = 0;
for (Set<Vector3>::Element *E = points.front(); E; E = E->next()) {
w[idx++] = E->get();
}
}
Ref<ConvexPolygonShape> shape;
shape.instance();
shape->set_points(convex_points);
ret.push_back(shape);
}
return ret;
}
Mesh::Mesh() {
}

View file

@ -31,6 +31,7 @@
#ifndef MESH_H
#define MESH_H
#include "core/math/face3.h"
#include "core/math/triangle_mesh.h"
#include "core/resource.h"
#include "scene/resources/material.h"
@ -147,6 +148,12 @@ public:
Size2 get_lightmap_size_hint() const;
void clear_cache() const;
typedef Vector<Vector<Face3> > (*ConvexDecompositionFunc)(const Vector<Face3> &);
static ConvexDecompositionFunc convex_composition_function;
Vector<Ref<Shape> > convex_decompose() const;
Mesh();
};

525
thirdparty/vhacd/inc/FloatMath.h vendored Normal file
View file

@ -0,0 +1,525 @@
#ifndef FLOAT_MATH_LIB_H
#define FLOAT_MATH_LIB_H
#include <float.h>
#include <stdint.h>
namespace FLOAT_MATH
{
enum FM_ClipState
{
FMCS_XMIN = (1<<0),
FMCS_XMAX = (1<<1),
FMCS_YMIN = (1<<2),
FMCS_YMAX = (1<<3),
FMCS_ZMIN = (1<<4),
FMCS_ZMAX = (1<<5),
};
enum FM_Axis
{
FM_XAXIS = (1<<0),
FM_YAXIS = (1<<1),
FM_ZAXIS = (1<<2)
};
enum LineSegmentType
{
LS_START,
LS_MIDDLE,
LS_END
};
const float FM_PI = 3.1415926535897932384626433832795028841971693993751f;
const float FM_DEG_TO_RAD = ((2.0f * FM_PI) / 360.0f);
const float FM_RAD_TO_DEG = (360.0f / (2.0f * FM_PI));
//***************** Float versions
//***
//*** vectors are assumed to be 3 floats or 3 doubles representing X, Y, Z
//*** quaternions are assumed to be 4 floats or 4 doubles representing X,Y,Z,W
//*** matrices are assumed to be 16 floats or 16 doubles representing a standard D3D or OpenGL style 4x4 matrix
//*** bounding volumes are expressed as two sets of 3 floats/double representing bmin(x,y,z) and bmax(x,y,z)
//*** Plane equations are assumed to be 4 floats or 4 doubles representing Ax,By,Cz,D
FM_Axis fm_getDominantAxis(const float normal[3]);
FM_Axis fm_getDominantAxis(const double normal[3]);
void fm_decomposeTransform(const float local_transform[16],float trans[3],float rot[4],float scale[3]);
void fm_decomposeTransform(const double local_transform[16],double trans[3],double rot[4],double scale[3]);
void fm_multiplyTransform(const float *pA,const float *pB,float *pM);
void fm_multiplyTransform(const double *pA,const double *pB,double *pM);
void fm_inverseTransform(const float matrix[16],float inverse_matrix[16]);
void fm_inverseTransform(const double matrix[16],double inverse_matrix[16]);
void fm_identity(float matrix[16]); // set 4x4 matrix to identity.
void fm_identity(double matrix[16]); // set 4x4 matrix to identity.
void fm_inverseRT(const float matrix[16], const float pos[3], float t[3]); // inverse rotate translate the point.
void fm_inverseRT(const double matrix[16],const double pos[3],double t[3]); // inverse rotate translate the point.
void fm_transform(const float matrix[16], const float pos[3], float t[3]); // rotate and translate this point.
void fm_transform(const double matrix[16],const double pos[3],double t[3]); // rotate and translate this point.
float fm_getDeterminant(const float matrix[16]);
double fm_getDeterminant(const double matrix[16]);
void fm_getSubMatrix(int32_t ki,int32_t kj,float pDst[16],const float matrix[16]);
void fm_getSubMatrix(int32_t ki,int32_t kj,double pDst[16],const float matrix[16]);
void fm_rotate(const float matrix[16],const float pos[3],float t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_rotate(const double matri[16],const double pos[3],double t[3]); // only rotate the point by a 4x4 matrix, don't translate.
void fm_eulerToMatrix(float ax,float ay,float az,float matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerToMatrix(double ax,double ay,double az,double matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_getAABB(uint32_t vcount,const float *points,uint32_t pstride,float bmin[3],float bmax[3]);
void fm_getAABB(uint32_t vcount,const double *points,uint32_t pstride,double bmin[3],double bmax[3]);
void fm_getAABBCenter(const float bmin[3],const float bmax[3],float center[3]);
void fm_getAABBCenter(const double bmin[3],const double bmax[3],double center[3]);
void fm_transformAABB(const float bmin[3],const float bmax[3],const float matrix[16],float tbmin[3],float tbmax[3]);
void fm_transformAABB(const double bmin[3],const double bmax[3],const double matrix[16],double tbmin[3],double tbmax[3]);
void fm_eulerToQuat(float x,float y,float z,float quat[4]); // convert euler angles to quaternion.
void fm_eulerToQuat(double x,double y,double z,double quat[4]); // convert euler angles to quaternion.
void fm_quatToEuler(const float quat[4],float &ax,float &ay,float &az);
void fm_quatToEuler(const double quat[4],double &ax,double &ay,double &az);
void fm_eulerToQuat(const float euler[3],float quat[4]); // convert euler angles to quaternion. Angles must be radians not degrees!
void fm_eulerToQuat(const double euler[3],double quat[4]); // convert euler angles to quaternion.
void fm_scale(float x,float y,float z,float matrix[16]); // apply scale to the matrix.
void fm_scale(double x,double y,double z,double matrix[16]); // apply scale to the matrix.
void fm_eulerToQuatDX(float x,float y,float z,float quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToQuatDX(double x,double y,double z,double quat[4]); // convert euler angles to quaternion using the fucked up DirectX method
void fm_eulerToMatrixDX(float x,float y,float z,float matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_eulerToMatrixDX(double x,double y,double z,double matrix[16]); // convert euler angles to quaternion using the fucked up DirectX method.
void fm_quatToMatrix(const float quat[4],float matrix[16]); // convert quaterinion rotation to matrix, translation set to zero.
void fm_quatToMatrix(const double quat[4],double matrix[16]); // convert quaterinion rotation to matrix, translation set to zero.
void fm_quatRotate(const float quat[4],const float v[3],float r[3]); // rotate a vector directly by a quaternion.
void fm_quatRotate(const double quat[4],const double v[3],double r[3]); // rotate a vector directly by a quaternion.
void fm_getTranslation(const float matrix[16],float t[3]);
void fm_getTranslation(const double matrix[16],double t[3]);
void fm_setTranslation(const float *translation,float matrix[16]);
void fm_setTranslation(const double *translation,double matrix[16]);
void fm_multiplyQuat(const float *qa,const float *qb,float *quat);
void fm_multiplyQuat(const double *qa,const double *qb,double *quat);
void fm_matrixToQuat(const float matrix[16],float quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
void fm_matrixToQuat(const double matrix[16],double quat[4]); // convert the 3x3 portion of a 4x4 matrix into a quaterion as x,y,z,w
float fm_sphereVolume(float radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
double fm_sphereVolume(double radius); // return's the volume of a sphere of this radius (4/3 PI * R cubed )
float fm_cylinderVolume(float radius,float h);
double fm_cylinderVolume(double radius,double h);
float fm_capsuleVolume(float radius,float h);
double fm_capsuleVolume(double radius,double h);
float fm_distance(const float p1[3],const float p2[3]);
double fm_distance(const double p1[3],const double p2[3]);
float fm_distanceSquared(const float p1[3],const float p2[3]);
double fm_distanceSquared(const double p1[3],const double p2[3]);
float fm_distanceSquaredXZ(const float p1[3],const float p2[3]);
double fm_distanceSquaredXZ(const double p1[3],const double p2[3]);
float fm_computePlane(const float p1[3],const float p2[3],const float p3[3],float *n); // return D
double fm_computePlane(const double p1[3],const double p2[3],const double p3[3],double *n); // return D
float fm_distToPlane(const float plane[4],const float pos[3]); // computes the distance of this point from the plane.
double fm_distToPlane(const double plane[4],const double pos[3]); // computes the distance of this point from the plane.
float fm_dot(const float p1[3],const float p2[3]);
double fm_dot(const double p1[3],const double p2[3]);
void fm_cross(float cross[3],const float a[3],const float b[3]);
void fm_cross(double cross[3],const double a[3],const double b[3]);
float fm_computeNormalVector(float n[3],const float p1[3],const float p2[3]); // as P2-P1 normalized.
double fm_computeNormalVector(double n[3],const double p1[3],const double p2[3]); // as P2-P1 normalized.
bool fm_computeWindingOrder(const float p1[3],const float p2[3],const float p3[3]); // returns true if the triangle is clockwise.
bool fm_computeWindingOrder(const double p1[3],const double p2[3],const double p3[3]); // returns true if the triangle is clockwise.
float fm_normalize(float n[3]); // normalize this vector and return the distance
double fm_normalize(double n[3]); // normalize this vector and return the distance
float fm_normalizeQuat(float n[4]); // normalize this quat
double fm_normalizeQuat(double n[4]); // normalize this quat
void fm_matrixMultiply(const float A[16],const float B[16],float dest[16]);
void fm_matrixMultiply(const double A[16],const double B[16],double dest[16]);
void fm_composeTransform(const float position[3],const float quat[4],const float scale[3],float matrix[16]);
void fm_composeTransform(const double position[3],const double quat[4],const double scale[3],double matrix[16]);
float fm_computeArea(const float p1[3],const float p2[3],const float p3[3]);
double fm_computeArea(const double p1[3],const double p2[3],const double p3[3]);
void fm_lerp(const float p1[3],const float p2[3],float dest[3],float lerpValue);
void fm_lerp(const double p1[3],const double p2[3],double dest[3],double lerpValue);
bool fm_insideTriangleXZ(const float test[3],const float p1[3],const float p2[3],const float p3[3]);
bool fm_insideTriangleXZ(const double test[3],const double p1[3],const double p2[3],const double p3[3]);
bool fm_insideAABB(const float pos[3],const float bmin[3],const float bmax[3]);
bool fm_insideAABB(const double pos[3],const double bmin[3],const double bmax[3]);
bool fm_insideAABB(const float obmin[3],const float obmax[3],const float tbmin[3],const float tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
bool fm_insideAABB(const double obmin[3],const double obmax[3],const double tbmin[3],const double tbmax[3]); // test if bounding box tbmin/tmbax is fully inside obmin/obmax
uint32_t fm_clipTestPoint(const float bmin[3],const float bmax[3],const float pos[3]);
uint32_t fm_clipTestPoint(const double bmin[3],const double bmax[3],const double pos[3]);
uint32_t fm_clipTestPointXZ(const float bmin[3],const float bmax[3],const float pos[3]); // only tests X and Z, not Y
uint32_t fm_clipTestPointXZ(const double bmin[3],const double bmax[3],const double pos[3]); // only tests X and Z, not Y
uint32_t fm_clipTestAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],const float p3[3],uint32_t &andCode);
uint32_t fm_clipTestAABB(const double bmin[3],const double bmax[3],const double p1[3],const double p2[3],const double p3[3],uint32_t &andCode);
bool fm_lineTestAABBXZ(const float p1[3],const float p2[3],const float bmin[3],const float bmax[3],float &time);
bool fm_lineTestAABBXZ(const double p1[3],const double p2[3],const double bmin[3],const double bmax[3],double &time);
bool fm_lineTestAABB(const float p1[3],const float p2[3],const float bmin[3],const float bmax[3],float &time);
bool fm_lineTestAABB(const double p1[3],const double p2[3],const double bmin[3],const double bmax[3],double &time);
void fm_initMinMax(const float p[3],float bmin[3],float bmax[3]);
void fm_initMinMax(const double p[3],double bmin[3],double bmax[3]);
void fm_initMinMax(float bmin[3],float bmax[3]);
void fm_initMinMax(double bmin[3],double bmax[3]);
void fm_minmax(const float p[3],float bmin[3],float bmax[3]); // accumulate to a min-max value
void fm_minmax(const double p[3],double bmin[3],double bmax[3]); // accumulate to a min-max value
// Computes the diagonal length of the bounding box and then inflates the bounding box on all sides
// by the ratio provided.
void fm_inflateMinMax(float bmin[3], float bmax[3], float ratio);
void fm_inflateMinMax(double bmin[3], double bmax[3], double ratio);
float fm_solveX(const float plane[4],float y,float z); // solve for X given this plane equation and the other two components.
double fm_solveX(const double plane[4],double y,double z); // solve for X given this plane equation and the other two components.
float fm_solveY(const float plane[4],float x,float z); // solve for Y given this plane equation and the other two components.
double fm_solveY(const double plane[4],double x,double z); // solve for Y given this plane equation and the other two components.
float fm_solveZ(const float plane[4],float x,float y); // solve for Z given this plane equation and the other two components.
double fm_solveZ(const double plane[4],double x,double y); // solve for Z given this plane equation and the other two components.
bool fm_computeBestFitPlane(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
uint32_t vstride, // stride between input points.
const float *weights, // *optional point weighting values.
uint32_t wstride, // weight stride for each vertex.
float plane[4], // Best fit plane equation
float center[3]); // Best fit weighted center of input points
bool fm_computeBestFitPlane(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
uint32_t vstride, // stride between input points.
const double *weights, // *optional point weighting values.
uint32_t wstride, // weight stride for each vertex.
double plane[4],
double center[3]);
// Computes the average center of a set of data points
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
float *center);
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
double *center);
// Compute centroid of a triangle mesh; takes area of each triangle into account
// weighted average
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const float *points, // starting address of points array.
uint32_t triangleCount,
const uint32_t *indices,
float *center);
// Compute centroid of a triangle mesh; takes area of each triangle into account
// weighted average
bool fm_computeCentroid(uint32_t vcount, // number of input data points
const double *points, // starting address of points array.
uint32_t triangleCount,
const uint32_t *indices,
double *center);
float fm_computeBestFitAABB(uint32_t vcount,const float *points,uint32_t pstride,float bmin[3],float bmax[3]); // returns the diagonal distance
double fm_computeBestFitAABB(uint32_t vcount,const double *points,uint32_t pstride,double bmin[3],double bmax[3]); // returns the diagonal distance
float fm_computeBestFitSphere(uint32_t vcount,const float *points,uint32_t pstride,float center[3]);
double fm_computeBestFitSphere(uint32_t vcount,const double *points,uint32_t pstride,double center[3]);
bool fm_lineSphereIntersect(const float center[3],float radius,const float p1[3],const float p2[3],float intersect[3]);
bool fm_lineSphereIntersect(const double center[3],double radius,const double p1[3],const double p2[3],double intersect[3]);
bool fm_intersectRayAABB(const float bmin[3],const float bmax[3],const float pos[3],const float dir[3],float intersect[3]);
bool fm_intersectLineSegmentAABB(const float bmin[3],const float bmax[3],const float p1[3],const float p2[3],float intersect[3]);
bool fm_lineIntersectsTriangle(const float rayStart[3],const float rayEnd[3],const float p1[3],const float p2[3],const float p3[3],float sect[3]);
bool fm_lineIntersectsTriangle(const double rayStart[3],const double rayEnd[3],const double p1[3],const double p2[3],const double p3[3],double sect[3]);
bool fm_rayIntersectsTriangle(const float origin[3],const float dir[3],const float v0[3],const float v1[3],const float v2[3],float &t);
bool fm_rayIntersectsTriangle(const double origin[3],const double dir[3],const double v0[3],const double v1[3],const double v2[3],double &t);
bool fm_raySphereIntersect(const float center[3],float radius,const float pos[3],const float dir[3],float distance,float intersect[3]);
bool fm_raySphereIntersect(const double center[3],double radius,const double pos[3],const double dir[3],double distance,double intersect[3]);
void fm_catmullRom(float out_vector[3],const float p1[3],const float p2[3],const float p3[3],const float *p4, const float s);
void fm_catmullRom(double out_vector[3],const double p1[3],const double p2[3],const double p3[3],const double *p4, const double s);
bool fm_intersectAABB(const float bmin1[3],const float bmax1[3],const float bmin2[3],const float bmax2[3]);
bool fm_intersectAABB(const double bmin1[3],const double bmax1[3],const double bmin2[3],const double bmax2[3]);
// computes the rotation quaternion to go from unit-vector v0 to unit-vector v1
void fm_rotationArc(const float v0[3],const float v1[3],float quat[4]);
void fm_rotationArc(const double v0[3],const double v1[3],double quat[4]);
float fm_distancePointLineSegment(const float Point[3],const float LineStart[3],const float LineEnd[3],float intersection[3],LineSegmentType &type,float epsilon);
double fm_distancePointLineSegment(const double Point[3],const double LineStart[3],const double LineEnd[3],double intersection[3],LineSegmentType &type,double epsilon);
bool fm_colinear(const double p1[3],const double p2[3],const double p3[3],double epsilon=0.999); // true if these three points in a row are co-linear
bool fm_colinear(const float p1[3],const float p2[3],const float p3[3],float epsilon=0.999f);
bool fm_colinear(const float a1[3],const float a2[3],const float b1[3],const float b2[3],float epsilon=0.999f); // true if these two line segments are co-linear.
bool fm_colinear(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double epsilon=0.999); // true if these two line segments are co-linear.
enum IntersectResult
{
IR_DONT_INTERSECT,
IR_DO_INTERSECT,
IR_COINCIDENT,
IR_PARALLEL,
};
IntersectResult fm_intersectLineSegments2d(const float a1[3], const float a2[3], const float b1[3], const float b2[3], float intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2d(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double intersectionPoint[3]);
IntersectResult fm_intersectLineSegments2dTime(const float a1[3], const float a2[3], const float b1[3], const float b2[3],float &t1,float &t2);
IntersectResult fm_intersectLineSegments2dTime(const double a1[3],const double a2[3],const double b1[3],const double b2[3],double &t1,double &t2);
// Plane-Triangle splitting
enum PlaneTriResult
{
PTR_ON_PLANE,
PTR_FRONT,
PTR_BACK,
PTR_SPLIT,
};
PlaneTriResult fm_planeTriIntersection(const float plane[4], // the plane equation in Ax+By+Cz+D format
const float *triangle, // the source triangle.
uint32_t tstride, // stride in bytes of the input and output *vertices*
float epsilon, // the co-planer epsilon value.
float *front, // the triangle in front of the
uint32_t &fcount, // number of vertices in the 'front' triangle
float *back, // the triangle in back of the plane
uint32_t &bcount); // the number of vertices in the 'back' triangle.
PlaneTriResult fm_planeTriIntersection(const double plane[4], // the plane equation in Ax+By+Cz+D format
const double *triangle, // the source triangle.
uint32_t tstride, // stride in bytes of the input and output *vertices*
double epsilon, // the co-planer epsilon value.
double *front, // the triangle in front of the
uint32_t &fcount, // number of vertices in the 'front' triangle
double *back, // the triangle in back of the plane
uint32_t &bcount); // the number of vertices in the 'back' triangle.
bool fm_intersectPointPlane(const float p1[3],const float p2[3],float *split,const float plane[4]);
bool fm_intersectPointPlane(const double p1[3],const double p2[3],double *split,const double plane[4]);
PlaneTriResult fm_getSidePlane(const float p[3],const float plane[4],float epsilon);
PlaneTriResult fm_getSidePlane(const double p[3],const double plane[4],double epsilon);
void fm_computeBestFitOBB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double matrix[16],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float pos[3],float quat[4],bool bruteForce=true);
void fm_computeBestFitOBB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double pos[3],double quat[4],bool bruteForce=true);
void fm_computeBestFitABB(uint32_t vcount,const float *points,uint32_t pstride,float *sides,float pos[3]);
void fm_computeBestFitABB(uint32_t vcount,const double *points,uint32_t pstride,double *sides,double pos[3]);
//** Note, if the returned capsule height is less than zero, then you must represent it is a sphere of size radius.
void fm_computeBestFitCapsule(uint32_t vcount,const float *points,uint32_t pstride,float &radius,float &height,float matrix[16],bool bruteForce=true);
void fm_computeBestFitCapsule(uint32_t vcount,const double *points,uint32_t pstride,float &radius,float &height,double matrix[16],bool bruteForce=true);
void fm_planeToMatrix(const float plane[4],float matrix[16]); // convert a plane equation to a 4x4 rotation matrix. Reference vector is 0,1,0
void fm_planeToQuat(const float plane[4],float quat[4],float pos[3]); // convert a plane equation to a quaternion and translation
void fm_planeToMatrix(const double plane[4],double matrix[16]); // convert a plane equation to a 4x4 rotation matrix
void fm_planeToQuat(const double plane[4],double quat[4],double pos[3]); // convert a plane equation to a quaternion and translation
inline void fm_doubleToFloat3(const double p[3],float t[3]) { t[0] = (float) p[0]; t[1] = (float)p[1]; t[2] = (float)p[2]; };
inline void fm_floatToDouble3(const float p[3],double t[3]) { t[0] = (double)p[0]; t[1] = (double)p[1]; t[2] = (double)p[2]; };
void fm_eulerMatrix(float ax,float ay,float az,float matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
void fm_eulerMatrix(double ax,double ay,double az,double matrix[16]); // convert euler (in radians) to a dest 4x4 matrix (translation set to zero)
float fm_computeMeshVolume(const float *vertices,uint32_t tcount,const uint32_t *indices);
double fm_computeMeshVolume(const double *vertices,uint32_t tcount,const uint32_t *indices);
#define FM_DEFAULT_GRANULARITY 0.001f // 1 millimeter is the default granularity
class fm_VertexIndex
{
public:
virtual uint32_t getIndex(const float pos[3],bool &newPos) = 0; // get welded index for this float vector[3]
virtual uint32_t getIndex(const double pos[3],bool &newPos) = 0; // get welded index for this double vector[3]
virtual const float * getVerticesFloat(void) const = 0;
virtual const double * getVerticesDouble(void) const = 0;
virtual const float * getVertexFloat(uint32_t index) const = 0;
virtual const double * getVertexDouble(uint32_t index) const = 0;
virtual uint32_t getVcount(void) const = 0;
virtual bool isDouble(void) const = 0;
virtual bool saveAsObj(const char *fname,uint32_t tcount,uint32_t *indices) = 0;
};
fm_VertexIndex * fm_createVertexIndex(double granularity,bool snapToGrid); // create an indexed vertex system for doubles
fm_VertexIndex * fm_createVertexIndex(float granularity,bool snapToGrid); // create an indexed vertext system for floats
void fm_releaseVertexIndex(fm_VertexIndex *vindex);
class fm_Triangulate
{
public:
virtual const double * triangulate3d(uint32_t pcount,
const double *points,
uint32_t vstride,
uint32_t &tcount,
bool consolidate,
double epsilon) = 0;
virtual const float * triangulate3d(uint32_t pcount,
const float *points,
uint32_t vstride,
uint32_t &tcount,
bool consolidate,
float epsilon) = 0;
};
fm_Triangulate * fm_createTriangulate(void);
void fm_releaseTriangulate(fm_Triangulate *t);
const float * fm_getPoint(const float *points,uint32_t pstride,uint32_t index);
const double * fm_getPoint(const double *points,uint32_t pstride,uint32_t index);
bool fm_insideTriangle(float Ax, float Ay,float Bx, float By,float Cx, float Cy,float Px, float Py);
bool fm_insideTriangle(double Ax, double Ay,double Bx, double By,double Cx, double Cy,double Px, double Py);
float fm_areaPolygon2d(uint32_t pcount,const float *points,uint32_t pstride);
double fm_areaPolygon2d(uint32_t pcount,const double *points,uint32_t pstride);
bool fm_pointInsidePolygon2d(uint32_t pcount,const float *points,uint32_t pstride,const float *point,uint32_t xindex=0,uint32_t yindex=1);
bool fm_pointInsidePolygon2d(uint32_t pcount,const double *points,uint32_t pstride,const double *point,uint32_t xindex=0,uint32_t yindex=1);
uint32_t fm_consolidatePolygon(uint32_t pcount,const float *points,uint32_t pstride,float *dest,float epsilon=0.999999f); // collapses co-linear edges.
uint32_t fm_consolidatePolygon(uint32_t pcount,const double *points,uint32_t pstride,double *dest,double epsilon=0.999999); // collapses co-linear edges.
bool fm_computeSplitPlane(uint32_t vcount,const double *vertices,uint32_t tcount,const uint32_t *indices,double *plane);
bool fm_computeSplitPlane(uint32_t vcount,const float *vertices,uint32_t tcount,const uint32_t *indices,float *plane);
void fm_nearestPointInTriangle(const float *pos,const float *p1,const float *p2,const float *p3,float *nearest);
void fm_nearestPointInTriangle(const double *pos,const double *p1,const double *p2,const double *p3,double *nearest);
float fm_areaTriangle(const float *p1,const float *p2,const float *p3);
double fm_areaTriangle(const double *p1,const double *p2,const double *p3);
void fm_subtract(const float *A,const float *B,float *diff); // compute A-B and store the result in 'diff'
void fm_subtract(const double *A,const double *B,double *diff); // compute A-B and store the result in 'diff'
void fm_multiply(float *A,float scaler);
void fm_multiply(double *A,double scaler);
void fm_add(const float *A,const float *B,float *sum);
void fm_add(const double *A,const double *B,double *sum);
void fm_copy3(const float *source,float *dest);
void fm_copy3(const double *source,double *dest);
// re-indexes an indexed triangle mesh but drops unused vertices. The output_indices can be the same pointer as the input indices.
// the output_vertices can point to the input vertices if you desire. The output_vertices buffer should be at least the same size
// is the input buffer. The routine returns the new vertex count after re-indexing.
uint32_t fm_copyUniqueVertices(uint32_t vcount,const float *input_vertices,float *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices);
uint32_t fm_copyUniqueVertices(uint32_t vcount,const double *input_vertices,double *output_vertices,uint32_t tcount,const uint32_t *input_indices,uint32_t *output_indices);
bool fm_isMeshCoplanar(uint32_t tcount,const uint32_t *indices,const float *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_isMeshCoplanar(uint32_t tcount,const uint32_t *indices,const double *vertices,bool doubleSided); // returns true if this collection of indexed triangles are co-planar!
bool fm_samePlane(const float p1[4],const float p2[4],float normalEpsilon=0.01f,float dEpsilon=0.001f,bool doubleSided=false); // returns true if these two plane equations are identical within an epsilon
bool fm_samePlane(const double p1[4],const double p2[4],double normalEpsilon=0.01,double dEpsilon=0.001,bool doubleSided=false);
void fm_OBBtoAABB(const float obmin[3],const float obmax[3],const float matrix[16],float abmin[3],float abmax[3]);
// a utility class that will tessellate a mesh.
class fm_Tesselate
{
public:
virtual const uint32_t * tesselate(fm_VertexIndex *vindex,uint32_t tcount,const uint32_t *indices,float longEdge,uint32_t maxDepth,uint32_t &outcount) = 0;
};
fm_Tesselate * fm_createTesselate(void);
void fm_releaseTesselate(fm_Tesselate *t);
void fm_computeMeanNormals(uint32_t vcount, // the number of vertices
const float *vertices, // the base address of the vertex position data.
uint32_t vstride, // the stride between position data.
float *normals, // the base address of the destination for mean vector normals
uint32_t nstride, // the stride between normals
uint32_t tcount, // the number of triangles
const uint32_t *indices); // the triangle indices
void fm_computeMeanNormals(uint32_t vcount, // the number of vertices
const double *vertices, // the base address of the vertex position data.
uint32_t vstride, // the stride between position data.
double *normals, // the base address of the destination for mean vector normals
uint32_t nstride, // the stride between normals
uint32_t tcount, // the number of triangles
const uint32_t *indices); // the triangle indices
bool fm_isValidTriangle(const float *p1,const float *p2,const float *p3,float epsilon=0.00001f);
bool fm_isValidTriangle(const double *p1,const double *p2,const double *p3,double epsilon=0.00001f);
}; // end of namespace
#endif

View file

@ -0,0 +1,111 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_ALIGNED_ALLOCATOR
#define BT_ALIGNED_ALLOCATOR
///we probably replace this with our own aligned memory allocator
///so we replace _aligned_malloc and _aligned_free with our own
///that is better portable and more predictable
#include "btScalar.h"
//GODOT ADDITION
namespace VHACD {
//
//#define BT_DEBUG_MEMORY_ALLOCATIONS 1
#ifdef BT_DEBUG_MEMORY_ALLOCATIONS
#define btAlignedAlloc(a, b) \
btAlignedAllocInternal(a, b, __LINE__, __FILE__)
#define btAlignedFree(ptr) \
btAlignedFreeInternal(ptr, __LINE__, __FILE__)
void *btAlignedAllocInternal(size_t size, int32_t alignment, int32_t line, char *filename);
void btAlignedFreeInternal(void *ptr, int32_t line, char *filename);
#else
void *btAlignedAllocInternal(size_t size, int32_t alignment);
void btAlignedFreeInternal(void *ptr);
#define btAlignedAlloc(size, alignment) btAlignedAllocInternal(size, alignment)
#define btAlignedFree(ptr) btAlignedFreeInternal(ptr)
#endif
typedef int32_t size_type;
typedef void *(btAlignedAllocFunc)(size_t size, int32_t alignment);
typedef void(btAlignedFreeFunc)(void *memblock);
typedef void *(btAllocFunc)(size_t size);
typedef void(btFreeFunc)(void *memblock);
///The developer can let all Bullet memory allocations go through a custom memory allocator, using btAlignedAllocSetCustom
void btAlignedAllocSetCustom(btAllocFunc *allocFunc, btFreeFunc *freeFunc);
///If the developer has already an custom aligned allocator, then btAlignedAllocSetCustomAligned can be used. The default aligned allocator pre-allocates extra memory using the non-aligned allocator, and instruments it.
void btAlignedAllocSetCustomAligned(btAlignedAllocFunc *allocFunc, btAlignedFreeFunc *freeFunc);
///The btAlignedAllocator is a portable class for aligned memory allocations.
///Default implementations for unaligned and aligned allocations can be overridden by a custom allocator using btAlignedAllocSetCustom and btAlignedAllocSetCustomAligned.
template <typename T, unsigned Alignment>
class btAlignedAllocator {
typedef btAlignedAllocator<T, Alignment> self_type;
public:
//just going down a list:
btAlignedAllocator() {}
/*
btAlignedAllocator( const self_type & ) {}
*/
template <typename Other>
btAlignedAllocator(const btAlignedAllocator<Other, Alignment> &) {}
typedef const T *const_pointer;
typedef const T &const_reference;
typedef T *pointer;
typedef T &reference;
typedef T value_type;
pointer address(reference ref) const { return &ref; }
const_pointer address(const_reference ref) const { return &ref; }
pointer allocate(size_type n, const_pointer *hint = 0) {
(void)hint;
return reinterpret_cast<pointer>(btAlignedAlloc(sizeof(value_type) * n, Alignment));
}
void construct(pointer ptr, const value_type &value) { new (ptr) value_type(value); }
void deallocate(pointer ptr) {
btAlignedFree(reinterpret_cast<void *>(ptr));
}
void destroy(pointer ptr) { ptr->~value_type(); }
template <typename O>
struct rebind {
typedef btAlignedAllocator<O, Alignment> other;
};
template <typename O>
self_type &operator=(const btAlignedAllocator<O, Alignment> &) { return *this; }
friend bool operator==(const self_type &, const self_type &) { return true; }
};
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_ALIGNED_ALLOCATOR

View file

@ -0,0 +1,420 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_OBJECT_ARRAY__
#define BT_OBJECT_ARRAY__
#include "btAlignedAllocator.h"
#include "btScalar.h" // has definitions like SIMD_FORCE_INLINE
///If the platform doesn't support placement new, you can disable BT_USE_PLACEMENT_NEW
///then the btAlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors
///You can enable BT_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator=
///see discussion here: http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1231 and
///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240
#define BT_USE_PLACEMENT_NEW 1
//#define BT_USE_MEMCPY 1 //disable, because it is cumbersome to find out for each platform where memcpy is defined. It can be in <memory.h> or <string.h> or otherwise...
#define BT_ALLOW_ARRAY_COPY_OPERATOR // enabling this can accidently perform deep copies of data if you are not careful
#ifdef BT_USE_MEMCPY
#include <memory.h>
#include <string.h>
#endif //BT_USE_MEMCPY
#ifdef BT_USE_PLACEMENT_NEW
#include <new> //for placement new
#endif //BT_USE_PLACEMENT_NEW
//GODOT ADDITION
namespace VHACD {
//
///The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods
///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data
template <typename T>
//template <class T>
class btAlignedObjectArray {
btAlignedAllocator<T, 16> m_allocator;
int32_t m_size;
int32_t m_capacity;
T *m_data;
//PCK: added this line
bool m_ownsMemory;
#ifdef BT_ALLOW_ARRAY_COPY_OPERATOR
public:
SIMD_FORCE_INLINE btAlignedObjectArray<T> &operator=(const btAlignedObjectArray<T> &other) {
copyFromArray(other);
return *this;
}
#else //BT_ALLOW_ARRAY_COPY_OPERATOR
private:
SIMD_FORCE_INLINE btAlignedObjectArray<T> &operator=(const btAlignedObjectArray<T> &other);
#endif //BT_ALLOW_ARRAY_COPY_OPERATOR
protected:
SIMD_FORCE_INLINE int32_t allocSize(int32_t size) {
return (size ? size * 2 : 1);
}
SIMD_FORCE_INLINE void copy(int32_t start, int32_t end, T *dest) const {
int32_t i;
for (i = start; i < end; ++i)
#ifdef BT_USE_PLACEMENT_NEW
new (&dest[i]) T(m_data[i]);
#else
dest[i] = m_data[i];
#endif //BT_USE_PLACEMENT_NEW
}
SIMD_FORCE_INLINE void init() {
//PCK: added this line
m_ownsMemory = true;
m_data = 0;
m_size = 0;
m_capacity = 0;
}
SIMD_FORCE_INLINE void destroy(int32_t first, int32_t last) {
int32_t i;
for (i = first; i < last; i++) {
m_data[i].~T();
}
}
SIMD_FORCE_INLINE void *allocate(int32_t size) {
if (size)
return m_allocator.allocate(size);
return 0;
}
SIMD_FORCE_INLINE void deallocate() {
if (m_data) {
//PCK: enclosed the deallocation in this block
if (m_ownsMemory) {
m_allocator.deallocate(m_data);
}
m_data = 0;
}
}
public:
btAlignedObjectArray() {
init();
}
~btAlignedObjectArray() {
clear();
}
///Generally it is best to avoid using the copy constructor of an btAlignedObjectArray, and use a (const) reference to the array instead.
btAlignedObjectArray(const btAlignedObjectArray &otherArray) {
init();
int32_t otherSize = otherArray.size();
resize(otherSize);
otherArray.copy(0, otherSize, m_data);
}
/// return the number of elements in the array
SIMD_FORCE_INLINE int32_t size() const {
return m_size;
}
SIMD_FORCE_INLINE const T &at(int32_t n) const {
btAssert(n >= 0);
btAssert(n < size());
return m_data[n];
}
SIMD_FORCE_INLINE T &at(int32_t n) {
btAssert(n >= 0);
btAssert(n < size());
return m_data[n];
}
SIMD_FORCE_INLINE const T &operator[](int32_t n) const {
btAssert(n >= 0);
btAssert(n < size());
return m_data[n];
}
SIMD_FORCE_INLINE T &operator[](int32_t n) {
btAssert(n >= 0);
btAssert(n < size());
return m_data[n];
}
///clear the array, deallocated memory. Generally it is better to use array.resize(0), to reduce performance overhead of run-time memory (de)allocations.
SIMD_FORCE_INLINE void clear() {
destroy(0, size());
deallocate();
init();
}
SIMD_FORCE_INLINE void pop_back() {
btAssert(m_size > 0);
m_size--;
m_data[m_size].~T();
}
///resize changes the number of elements in the array. If the new size is larger, the new elements will be constructed using the optional second argument.
///when the new number of elements is smaller, the destructor will be called, but memory will not be freed, to reduce performance overhead of run-time memory (de)allocations.
SIMD_FORCE_INLINE void resize(int32_t newsize, const T &fillData = T()) {
int32_t curSize = size();
if (newsize < curSize) {
for (int32_t i = newsize; i < curSize; i++) {
m_data[i].~T();
}
} else {
if (newsize > size()) {
reserve(newsize);
}
#ifdef BT_USE_PLACEMENT_NEW
for (int32_t i = curSize; i < newsize; i++) {
new (&m_data[i]) T(fillData);
}
#endif //BT_USE_PLACEMENT_NEW
}
m_size = newsize;
}
SIMD_FORCE_INLINE T &expandNonInitializing() {
int32_t sz = size();
if (sz == capacity()) {
reserve(allocSize(size()));
}
m_size++;
return m_data[sz];
}
SIMD_FORCE_INLINE T &expand(const T &fillValue = T()) {
int32_t sz = size();
if (sz == capacity()) {
reserve(allocSize(size()));
}
m_size++;
#ifdef BT_USE_PLACEMENT_NEW
new (&m_data[sz]) T(fillValue); //use the in-place new (not really allocating heap memory)
#endif
return m_data[sz];
}
SIMD_FORCE_INLINE void push_back(const T &_Val) {
int32_t sz = size();
if (sz == capacity()) {
reserve(allocSize(size()));
}
#ifdef BT_USE_PLACEMENT_NEW
new (&m_data[m_size]) T(_Val);
#else
m_data[size()] = _Val;
#endif //BT_USE_PLACEMENT_NEW
m_size++;
}
/// return the pre-allocated (reserved) elements, this is at least as large as the total number of elements,see size() and reserve()
SIMD_FORCE_INLINE int32_t capacity() const {
return m_capacity;
}
SIMD_FORCE_INLINE void reserve(int32_t _Count) { // determine new minimum length of allocated storage
if (capacity() < _Count) { // not enough room, reallocate
T *s = (T *)allocate(_Count);
copy(0, size(), s);
destroy(0, size());
deallocate();
//PCK: added this line
m_ownsMemory = true;
m_data = s;
m_capacity = _Count;
}
}
class less {
public:
bool operator()(const T &a, const T &b) {
return (a < b);
}
};
template <typename L>
void quickSortInternal(const L &CompareFunc, int32_t lo, int32_t hi) {
// lo is the lower index, hi is the upper index
// of the region of array a that is to be sorted
int32_t i = lo, j = hi;
T x = m_data[(lo + hi) / 2];
// partition
do {
while (CompareFunc(m_data[i], x))
i++;
while (CompareFunc(x, m_data[j]))
j--;
if (i <= j) {
swap(i, j);
i++;
j--;
}
} while (i <= j);
// recursion
if (lo < j)
quickSortInternal(CompareFunc, lo, j);
if (i < hi)
quickSortInternal(CompareFunc, i, hi);
}
template <typename L>
void quickSort(const L &CompareFunc) {
//don't sort 0 or 1 elements
if (size() > 1) {
quickSortInternal(CompareFunc, 0, size() - 1);
}
}
///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/
template <typename L>
void downHeap(T *pArr, int32_t k, int32_t n, const L &CompareFunc) {
/* PRE: a[k+1..N] is a heap */
/* POST: a[k..N] is a heap */
T temp = pArr[k - 1];
/* k has child(s) */
while (k <= n / 2) {
int32_t child = 2 * k;
if ((child < n) && CompareFunc(pArr[child - 1], pArr[child])) {
child++;
}
/* pick larger child */
if (CompareFunc(temp, pArr[child - 1])) {
/* move child up */
pArr[k - 1] = pArr[child - 1];
k = child;
} else {
break;
}
}
pArr[k - 1] = temp;
} /*downHeap*/
void swap(int32_t index0, int32_t index1) {
#ifdef BT_USE_MEMCPY
char temp[sizeof(T)];
memcpy(temp, &m_data[index0], sizeof(T));
memcpy(&m_data[index0], &m_data[index1], sizeof(T));
memcpy(&m_data[index1], temp, sizeof(T));
#else
T temp = m_data[index0];
m_data[index0] = m_data[index1];
m_data[index1] = temp;
#endif //BT_USE_PLACEMENT_NEW
}
template <typename L>
void heapSort(const L &CompareFunc) {
/* sort a[0..N-1], N.B. 0 to N-1 */
int32_t k;
int32_t n = m_size;
for (k = n / 2; k > 0; k--) {
downHeap(m_data, k, n, CompareFunc);
}
/* a[1..N] is now a heap */
while (n >= 1) {
swap(0, n - 1); /* largest of a[0..n-1] */
n = n - 1;
/* restore a[1..i-1] heap */
downHeap(m_data, 1, n, CompareFunc);
}
}
///non-recursive binary search, assumes sorted array
int32_t findBinarySearch(const T &key) const {
int32_t first = 0;
int32_t last = size() - 1;
//assume sorted array
while (first <= last) {
int32_t mid = (first + last) / 2; // compute mid point.
if (key > m_data[mid])
first = mid + 1; // repeat search in top half.
else if (key < m_data[mid])
last = mid - 1; // repeat search in bottom half.
else
return mid; // found it. return position /////
}
return size(); // failed to find key
}
int32_t findLinearSearch(const T &key) const {
int32_t index = size();
int32_t i;
for (i = 0; i < size(); i++) {
if (m_data[i] == key) {
index = i;
break;
}
}
return index;
}
void remove(const T &key) {
int32_t findIndex = findLinearSearch(key);
if (findIndex < size()) {
swap(findIndex, size() - 1);
pop_back();
}
}
//PCK: whole function
void initializeFromBuffer(void *buffer, int32_t size, int32_t capacity) {
clear();
m_ownsMemory = false;
m_data = (T *)buffer;
m_size = size;
m_capacity = capacity;
}
void copyFromArray(const btAlignedObjectArray &otherArray) {
int32_t otherSize = otherArray.size();
resize(otherSize);
otherArray.copy(0, otherSize, m_data);
}
};
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_OBJECT_ARRAY__

View file

@ -0,0 +1,100 @@
/*
Copyright (c) 2011 Ole Kniemeyer, MAXON, www.maxon.net
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_CONVEX_HULL_COMPUTER_H
#define BT_CONVEX_HULL_COMPUTER_H
#include "btAlignedObjectArray.h"
#include "btVector3.h"
//GODOT ADDITION
namespace VHACD {
//
/// Convex hull implementation based on Preparata and Hong
/// See http://code.google.com/p/bullet/issues/detail?id=275
/// Ole Kniemeyer, MAXON Computer GmbH
class btConvexHullComputer {
private:
btScalar compute(const void *coords, bool doubleCoords, int32_t stride, int32_t count, btScalar shrink, btScalar shrinkClamp);
public:
class Edge {
private:
int32_t next;
int32_t reverse;
int32_t targetVertex;
friend class btConvexHullComputer;
public:
int32_t getSourceVertex() const {
return (this + reverse)->targetVertex;
}
int32_t getTargetVertex() const {
return targetVertex;
}
const Edge *getNextEdgeOfVertex() const // clockwise list of all edges of a vertex
{
return this + next;
}
const Edge *getNextEdgeOfFace() const // counter-clockwise list of all edges of a face
{
return (this + reverse)->getNextEdgeOfVertex();
}
const Edge *getReverseEdge() const {
return this + reverse;
}
};
// Vertices of the output hull
btAlignedObjectArray<btVector3> vertices;
// Edges of the output hull
btAlignedObjectArray<Edge> edges;
// Faces of the convex hull. Each entry is an index into the "edges" array pointing to an edge of the face. Faces are planar n-gons
btAlignedObjectArray<int32_t> faces;
/*
Compute convex hull of "count" vertices stored in "coords". "stride" is the difference in bytes
between the addresses of consecutive vertices. If "shrink" is positive, the convex hull is shrunken
by that amount (each face is moved by "shrink" length units towards the center along its normal).
If "shrinkClamp" is positive, "shrink" is clamped to not exceed "shrinkClamp * innerRadius", where "innerRadius"
is the minimum distance of a face to the center of the convex hull.
The returned value is the amount by which the hull has been shrunken. If it is negative, the amount was so large
that the resulting convex hull is empty.
The output convex hull can be found in the member variables "vertices", "edges", "faces".
*/
btScalar compute(const float *coords, int32_t stride, int32_t count, btScalar shrink, btScalar shrinkClamp) {
return compute(coords, false, stride, count, shrink, shrinkClamp);
}
// same as above, but double precision
btScalar compute(const double *coords, int32_t stride, int32_t count, btScalar shrink, btScalar shrinkClamp) {
return compute(coords, true, stride, count, shrink, shrinkClamp);
}
};
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_CONVEX_HULL_COMPUTER_H

66
thirdparty/vhacd/inc/btMinMax.h vendored Normal file
View file

@ -0,0 +1,66 @@
/*
Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_GEN_MINMAX_H
#define BT_GEN_MINMAX_H
#include "btScalar.h"
//GODOT ADDITION
namespace VHACD {
//
template <class T>
SIMD_FORCE_INLINE const T &btMin(const T &a, const T &b) {
return a < b ? a : b;
}
template <class T>
SIMD_FORCE_INLINE const T &btMax(const T &a, const T &b) {
return a > b ? a : b;
}
template <class T>
SIMD_FORCE_INLINE const T &btClamped(const T &a, const T &lb, const T &ub) {
return a < lb ? lb : (ub < a ? ub : a);
}
template <class T>
SIMD_FORCE_INLINE void btSetMin(T &a, const T &b) {
if (b < a) {
a = b;
}
}
template <class T>
SIMD_FORCE_INLINE void btSetMax(T &a, const T &b) {
if (a < b) {
a = b;
}
}
template <class T>
SIMD_FORCE_INLINE void btClamp(T &a, const T &lb, const T &ub) {
if (a < lb) {
a = lb;
} else if (ub < a) {
a = ub;
}
}
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_GEN_MINMAX_H

565
thirdparty/vhacd/inc/btScalar.h vendored Normal file
View file

@ -0,0 +1,565 @@
/*
Copyright (c) 2003-2009 Erwin Coumans http://bullet.googlecode.com
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_SCALAR_H
#define BT_SCALAR_H
#ifdef BT_MANAGED_CODE
//Aligned data types not supported in managed code
#pragma unmanaged
#endif
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h> //size_t for MSVC 6.0
/* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/
#define BT_BULLET_VERSION 279
//GODOT ADDITION
namespace VHACD {
//
inline int32_t btGetVersion() {
return BT_BULLET_VERSION;
}
//GODOT ADDITION
}; // namespace VHACD
//
#if defined(DEBUG) || defined(_DEBUG)
#define BT_DEBUG
#endif
#ifdef _WIN32
#if defined(__MINGW32__) || defined(__CYGWIN__) || (defined(_MSC_VER) && _MSC_VER < 1300)
#define SIMD_FORCE_INLINE inline
#define ATTRIBUTE_ALIGNED16(a) a
#define ATTRIBUTE_ALIGNED64(a) a
#define ATTRIBUTE_ALIGNED128(a) a
#else
//#define BT_HAS_ALIGNED_ALLOCATOR
#pragma warning(disable : 4324) // disable padding warning
// #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning.
// #pragma warning(disable:4996) //Turn off warnings about deprecated C routines
// #pragma warning(disable:4786) // Disable the "debug name too long" warning
#define SIMD_FORCE_INLINE __forceinline
#define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a
#define ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a
#define ATTRIBUTE_ALIGNED128(a) __declspec(align(128)) a
#ifdef _XBOX
#define BT_USE_VMX128
#include <ppcintrinsics.h>
#define BT_HAVE_NATIVE_FSEL
#define btFsel(a, b, c) __fsel((a), (b), (c))
#else
#if (defined(_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined(BT_USE_DOUBLE_PRECISION))
#define BT_USE_SSE
#include <emmintrin.h>
#endif
#endif //_XBOX
#endif //__MINGW32__
#include <assert.h>
#ifdef BT_DEBUG
#define btAssert assert
#else
#define btAssert(x)
#endif
//btFullAssert is optional, slows down a lot
#define btFullAssert(x)
#define btLikely(_c) _c
#define btUnlikely(_c) _c
#else
#if defined(__CELLOS_LV2__)
#define SIMD_FORCE_INLINE inline __attribute__((always_inline))
#define ATTRIBUTE_ALIGNED16(a) a __attribute__((aligned(16)))
#define ATTRIBUTE_ALIGNED64(a) a __attribute__((aligned(64)))
#define ATTRIBUTE_ALIGNED128(a) a __attribute__((aligned(128)))
#ifndef assert
#include <assert.h>
#endif
#ifdef BT_DEBUG
#ifdef __SPU__
#include <spu_printf.h>
#define printf spu_printf
#define btAssert(x) \
{ \
if (!(x)) { \
printf("Assert " __FILE__ ":%u (" #x ")\n", __LINE__); \
spu_hcmpeq(0, 0); \
} \
}
#else
#define btAssert assert
#endif
#else
#define btAssert(x)
#endif
//btFullAssert is optional, slows down a lot
#define btFullAssert(x)
#define btLikely(_c) _c
#define btUnlikely(_c) _c
#else
#ifdef USE_LIBSPE2
#define SIMD_FORCE_INLINE __inline
#define ATTRIBUTE_ALIGNED16(a) a __attribute__((aligned(16)))
#define ATTRIBUTE_ALIGNED64(a) a __attribute__((aligned(64)))
#define ATTRIBUTE_ALIGNED128(a) a __attribute__((aligned(128)))
#ifndef assert
#include <assert.h>
#endif
#ifdef BT_DEBUG
#define btAssert assert
#else
#define btAssert(x)
#endif
//btFullAssert is optional, slows down a lot
#define btFullAssert(x)
#define btLikely(_c) __builtin_expect((_c), 1)
#define btUnlikely(_c) __builtin_expect((_c), 0)
#else
//non-windows systems
#if (defined(__APPLE__) && defined(__i386__) && (!defined(BT_USE_DOUBLE_PRECISION)))
#define BT_USE_SSE
#include <emmintrin.h>
#define SIMD_FORCE_INLINE inline
///@todo: check out alignment methods for other platforms/compilers
#define ATTRIBUTE_ALIGNED16(a) a __attribute__((aligned(16)))
#define ATTRIBUTE_ALIGNED64(a) a __attribute__((aligned(64)))
#define ATTRIBUTE_ALIGNED128(a) a __attribute__((aligned(128)))
#ifndef assert
#include <assert.h>
#endif
#if defined(DEBUG) || defined(_DEBUG)
#define btAssert assert
#else
#define btAssert(x)
#endif
//btFullAssert is optional, slows down a lot
#define btFullAssert(x)
#define btLikely(_c) _c
#define btUnlikely(_c) _c
#else
#define SIMD_FORCE_INLINE inline
///@todo: check out alignment methods for other platforms/compilers
///#define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16)))
///#define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64)))
///#define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128)))
#define ATTRIBUTE_ALIGNED16(a) a
#define ATTRIBUTE_ALIGNED64(a) a
#define ATTRIBUTE_ALIGNED128(a) a
#ifndef assert
#include <assert.h>
#endif
#if defined(DEBUG) || defined(_DEBUG)
#define btAssert assert
#else
#define btAssert(x)
#endif
//btFullAssert is optional, slows down a lot
#define btFullAssert(x)
#define btLikely(_c) _c
#define btUnlikely(_c) _c
#endif //__APPLE__
#endif // LIBSPE2
#endif //__CELLOS_LV2__
#endif
//GODOT ADDITION
namespace VHACD {
//
///The btScalar type abstracts floating point numbers, to easily switch between double and single floating point precision.
#if defined(BT_USE_DOUBLE_PRECISION)
typedef double btScalar;
//this number could be bigger in double precision
#define BT_LARGE_FLOAT 1e30
#else
typedef float btScalar;
//keep BT_LARGE_FLOAT*BT_LARGE_FLOAT < FLT_MAX
#define BT_LARGE_FLOAT 1e18f
#endif
#define BT_DECLARE_ALIGNED_ALLOCATOR() \
SIMD_FORCE_INLINE void *operator new(size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes, 16); } \
SIMD_FORCE_INLINE void operator delete(void *ptr) { btAlignedFree(ptr); } \
SIMD_FORCE_INLINE void *operator new(size_t, void *ptr) { return ptr; } \
SIMD_FORCE_INLINE void operator delete(void *, void *) {} \
SIMD_FORCE_INLINE void *operator new[](size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes, 16); } \
SIMD_FORCE_INLINE void operator delete[](void *ptr) { btAlignedFree(ptr); } \
SIMD_FORCE_INLINE void *operator new[](size_t, void *ptr) { return ptr; } \
SIMD_FORCE_INLINE void operator delete[](void *, void *) {}
#if defined(BT_USE_DOUBLE_PRECISION) || defined(BT_FORCE_DOUBLE_FUNCTIONS)
SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) {
return sqrt(x);
}
SIMD_FORCE_INLINE btScalar btFabs(btScalar x) {
return fabs(x);
}
SIMD_FORCE_INLINE btScalar btCos(btScalar x) {
return cos(x);
}
SIMD_FORCE_INLINE btScalar btSin(btScalar x) {
return sin(x);
}
SIMD_FORCE_INLINE btScalar btTan(btScalar x) {
return tan(x);
}
SIMD_FORCE_INLINE btScalar btAcos(btScalar x) {
if (x < btScalar(-1))
x = btScalar(-1);
if (x > btScalar(1))
x = btScalar(1);
return acos(x);
}
SIMD_FORCE_INLINE btScalar btAsin(btScalar x) {
if (x < btScalar(-1))
x = btScalar(-1);
if (x > btScalar(1))
x = btScalar(1);
return asin(x);
}
SIMD_FORCE_INLINE btScalar btAtan(btScalar x) {
return atan(x);
}
SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) {
return atan2(x, y);
}
SIMD_FORCE_INLINE btScalar btExp(btScalar x) {
return exp(x);
}
SIMD_FORCE_INLINE btScalar btLog(btScalar x) {
return log(x);
}
SIMD_FORCE_INLINE btScalar btPow(btScalar x, btScalar y) {
return pow(x, y);
}
SIMD_FORCE_INLINE btScalar btFmod(btScalar x, btScalar y) {
return fmod(x, y);
}
#else
SIMD_FORCE_INLINE btScalar btSqrt(btScalar y) {
#ifdef USE_APPROXIMATION
double x, z, tempf;
unsigned long *tfptr = ((unsigned long *)&tempf) + 1;
tempf = y;
*tfptr = (0xbfcdd90a - *tfptr) >> 1; /* estimate of 1/sqrt(y) */
x = tempf;
z = y * btScalar(0.5);
x = (btScalar(1.5) * x) - (x * x) * (x * z); /* iteration formula */
x = (btScalar(1.5) * x) - (x * x) * (x * z);
x = (btScalar(1.5) * x) - (x * x) * (x * z);
x = (btScalar(1.5) * x) - (x * x) * (x * z);
x = (btScalar(1.5) * x) - (x * x) * (x * z);
return x * y;
#else
return sqrtf(y);
#endif
}
SIMD_FORCE_INLINE btScalar btFabs(btScalar x) {
return fabsf(x);
}
SIMD_FORCE_INLINE btScalar btCos(btScalar x) {
return cosf(x);
}
SIMD_FORCE_INLINE btScalar btSin(btScalar x) {
return sinf(x);
}
SIMD_FORCE_INLINE btScalar btTan(btScalar x) {
return tanf(x);
}
SIMD_FORCE_INLINE btScalar btAcos(btScalar x) {
if (x < btScalar(-1))
x = btScalar(-1);
if (x > btScalar(1))
x = btScalar(1);
return acosf(x);
}
SIMD_FORCE_INLINE btScalar btAsin(btScalar x) {
if (x < btScalar(-1))
x = btScalar(-1);
if (x > btScalar(1))
x = btScalar(1);
return asinf(x);
}
SIMD_FORCE_INLINE btScalar btAtan(btScalar x) {
return atanf(x);
}
SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) {
return atan2f(x, y);
}
SIMD_FORCE_INLINE btScalar btExp(btScalar x) {
return expf(x);
}
SIMD_FORCE_INLINE btScalar btLog(btScalar x) {
return logf(x);
}
SIMD_FORCE_INLINE btScalar btPow(btScalar x, btScalar y) {
return powf(x, y);
}
SIMD_FORCE_INLINE btScalar btFmod(btScalar x, btScalar y) {
return fmodf(x, y);
}
#endif
#define SIMD_2_PI btScalar(6.283185307179586232)
#define SIMD_PI (SIMD_2_PI * btScalar(0.5))
#define SIMD_HALF_PI (SIMD_2_PI * btScalar(0.25))
#define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0))
#define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI)
#define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490)
#define btRecipSqrt(x) ((btScalar)(btScalar(1.0) / btSqrt(btScalar(x)))) /* reciprocal square root */
#ifdef BT_USE_DOUBLE_PRECISION
#define SIMD_EPSILON DBL_EPSILON
#define SIMD_INFINITY DBL_MAX
#else
#define SIMD_EPSILON FLT_EPSILON
#define SIMD_INFINITY FLT_MAX
#endif
SIMD_FORCE_INLINE btScalar btAtan2Fast(btScalar y, btScalar x) {
btScalar coeff_1 = SIMD_PI / 4.0f;
btScalar coeff_2 = 3.0f * coeff_1;
btScalar abs_y = btFabs(y);
btScalar angle;
if (x >= 0.0f) {
btScalar r = (x - abs_y) / (x + abs_y);
angle = coeff_1 - coeff_1 * r;
} else {
btScalar r = (x + abs_y) / (abs_y - x);
angle = coeff_2 - coeff_1 * r;
}
return (y < 0.0f) ? -angle : angle;
}
SIMD_FORCE_INLINE bool btFuzzyZero(btScalar x) {
return btFabs(x) < SIMD_EPSILON;
}
SIMD_FORCE_INLINE bool btEqual(btScalar a, btScalar eps) {
return (((a) <= eps) && !((a) < -eps));
}
SIMD_FORCE_INLINE bool btGreaterEqual(btScalar a, btScalar eps) {
return (!((a) <= eps));
}
SIMD_FORCE_INLINE int32_t btIsNegative(btScalar x) {
return x < btScalar(0.0) ? 1 : 0;
}
SIMD_FORCE_INLINE btScalar btRadians(btScalar x) {
return x * SIMD_RADS_PER_DEG;
}
SIMD_FORCE_INLINE btScalar btDegrees(btScalar x) {
return x * SIMD_DEGS_PER_RAD;
}
#define BT_DECLARE_HANDLE(name) \
typedef struct name##__ { \
int32_t unused; \
} * name
#ifndef btFsel
SIMD_FORCE_INLINE btScalar btFsel(btScalar a, btScalar b, btScalar c) {
return a >= 0 ? b : c;
}
#endif
#define btFsels(a, b, c) (btScalar) btFsel(a, b, c)
SIMD_FORCE_INLINE bool btMachineIsLittleEndian() {
long int i = 1;
const char *p = (const char *)&i;
if (p[0] == 1) // Lowest address contains the least significant byte
return true;
else
return false;
}
///btSelect avoids branches, which makes performance much better for consoles like Playstation 3 and XBox 360
///Thanks Phil Knight. See also http://www.cellperformance.com/articles/2006/04/more_techniques_for_eliminatin_1.html
SIMD_FORCE_INLINE unsigned btSelect(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero) {
// Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero
// Rely on positive value or'ed with its negative having sign bit on
// and zero value or'ed with its negative (which is still zero) having sign bit off
// Use arithmetic shift right, shifting the sign bit through all 32 bits
unsigned testNz = (unsigned)(((int32_t)condition | -(int32_t)condition) >> 31);
unsigned testEqz = ~testNz;
return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz));
}
SIMD_FORCE_INLINE int32_t btSelect(unsigned condition, int32_t valueIfConditionNonZero, int32_t valueIfConditionZero) {
unsigned testNz = (unsigned)(((int32_t)condition | -(int32_t)condition) >> 31);
unsigned testEqz = ~testNz;
return static_cast<int32_t>((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz));
}
SIMD_FORCE_INLINE float btSelect(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero) {
#ifdef BT_HAVE_NATIVE_FSEL
return (float)btFsel((btScalar)condition - btScalar(1.0f), valueIfConditionNonZero, valueIfConditionZero);
#else
return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero;
#endif
}
template <typename T>
SIMD_FORCE_INLINE void btSwap(T &a, T &b) {
T tmp = a;
a = b;
b = tmp;
}
//PCK: endian swapping functions
SIMD_FORCE_INLINE unsigned btSwapEndian(unsigned val) {
return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24));
}
SIMD_FORCE_INLINE unsigned short btSwapEndian(unsigned short val) {
return static_cast<unsigned short>(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8));
}
SIMD_FORCE_INLINE unsigned btSwapEndian(int32_t val) {
return btSwapEndian((unsigned)val);
}
SIMD_FORCE_INLINE unsigned short btSwapEndian(short val) {
return btSwapEndian((unsigned short)val);
}
///btSwapFloat uses using char pointers to swap the endianness
////btSwapFloat/btSwapDouble will NOT return a float, because the machine might 'correct' invalid floating point values
///Not all values of sign/exponent/mantissa are valid floating point numbers according to IEEE 754.
///When a floating point unit is faced with an invalid value, it may actually change the value, or worse, throw an exception.
///In most systems, running user mode code, you wouldn't get an exception, but instead the hardware/os/runtime will 'fix' the number for you.
///so instead of returning a float/double, we return integer/long long integer
SIMD_FORCE_INLINE uint32_t btSwapEndianFloat(float d) {
uint32_t a = 0;
unsigned char *dst = (unsigned char *)&a;
unsigned char *src = (unsigned char *)&d;
dst[0] = src[3];
dst[1] = src[2];
dst[2] = src[1];
dst[3] = src[0];
return a;
}
// unswap using char pointers
SIMD_FORCE_INLINE float btUnswapEndianFloat(uint32_t a) {
float d = 0.0f;
unsigned char *src = (unsigned char *)&a;
unsigned char *dst = (unsigned char *)&d;
dst[0] = src[3];
dst[1] = src[2];
dst[2] = src[1];
dst[3] = src[0];
return d;
}
// swap using char pointers
SIMD_FORCE_INLINE void btSwapEndianDouble(double d, unsigned char *dst) {
unsigned char *src = (unsigned char *)&d;
dst[0] = src[7];
dst[1] = src[6];
dst[2] = src[5];
dst[3] = src[4];
dst[4] = src[3];
dst[5] = src[2];
dst[6] = src[1];
dst[7] = src[0];
}
// unswap using char pointers
SIMD_FORCE_INLINE double btUnswapEndianDouble(const unsigned char *src) {
double d = 0.0;
unsigned char *dst = (unsigned char *)&d;
dst[0] = src[7];
dst[1] = src[6];
dst[2] = src[5];
dst[3] = src[4];
dst[4] = src[3];
dst[5] = src[2];
dst[6] = src[1];
dst[7] = src[0];
return d;
}
// returns normalized value in range [-SIMD_PI, SIMD_PI]
SIMD_FORCE_INLINE btScalar btNormalizeAngle(btScalar angleInRadians) {
angleInRadians = btFmod(angleInRadians, SIMD_2_PI);
if (angleInRadians < -SIMD_PI) {
return angleInRadians + SIMD_2_PI;
} else if (angleInRadians > SIMD_PI) {
return angleInRadians - SIMD_2_PI;
} else {
return angleInRadians;
}
}
///rudimentary class to provide type info
struct btTypedObject {
btTypedObject(int32_t objectType) :
m_objectType(objectType) {
}
int32_t m_objectType;
inline int32_t getObjectType() const {
return m_objectType;
}
};
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_SCALAR_H

653
thirdparty/vhacd/inc/btVector3.h vendored Normal file
View file

@ -0,0 +1,653 @@
/*
Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifndef BT_VECTOR3_H
#define BT_VECTOR3_H
#include "btMinMax.h"
#include "btScalar.h"
#ifdef BT_USE_DOUBLE_PRECISION
#define btVector3Data btVector3DoubleData
#define btVector3DataName "btVector3DoubleData"
#else
#define btVector3Data btVector3FloatData
#define btVector3DataName "btVector3FloatData"
#endif //BT_USE_DOUBLE_PRECISION
/**@brief btVector3 can be used to represent 3D points and vectors.
* It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user
* Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers
*/
//GODOT ADDITION
namespace VHACD {
//
ATTRIBUTE_ALIGNED16(class)
btVector3 {
public:
#if defined(__SPU__) && defined(__CELLOS_LV2__)
btScalar m_floats[4];
public:
SIMD_FORCE_INLINE const vec_float4 &get128() const {
return *((const vec_float4 *)&m_floats[0]);
}
public:
#else //__CELLOS_LV2__ __SPU__
#ifdef BT_USE_SSE // _WIN32
union {
__m128 mVec128;
btScalar m_floats[4];
};
SIMD_FORCE_INLINE __m128 get128() const {
return mVec128;
}
SIMD_FORCE_INLINE void set128(__m128 v128) {
mVec128 = v128;
}
#else
btScalar m_floats[4];
#endif
#endif //__CELLOS_LV2__ __SPU__
public:
/**@brief No initialization constructor */
SIMD_FORCE_INLINE btVector3() {}
/**@brief Constructor from scalars
* @param x X value
* @param y Y value
* @param z Z value
*/
SIMD_FORCE_INLINE btVector3(const btScalar &x, const btScalar &y, const btScalar &z) {
m_floats[0] = x;
m_floats[1] = y;
m_floats[2] = z;
m_floats[3] = btScalar(0.);
}
/**@brief Add a vector to this one
* @param The vector to add to this one */
SIMD_FORCE_INLINE btVector3 &operator+=(const btVector3 &v) {
m_floats[0] += v.m_floats[0];
m_floats[1] += v.m_floats[1];
m_floats[2] += v.m_floats[2];
return *this;
}
/**@brief Subtract a vector from this one
* @param The vector to subtract */
SIMD_FORCE_INLINE btVector3 &operator-=(const btVector3 &v) {
m_floats[0] -= v.m_floats[0];
m_floats[1] -= v.m_floats[1];
m_floats[2] -= v.m_floats[2];
return *this;
}
/**@brief Scale the vector
* @param s Scale factor */
SIMD_FORCE_INLINE btVector3 &operator*=(const btScalar &s) {
m_floats[0] *= s;
m_floats[1] *= s;
m_floats[2] *= s;
return *this;
}
/**@brief Inversely scale the vector
* @param s Scale factor to divide by */
SIMD_FORCE_INLINE btVector3 &operator/=(const btScalar &s) {
btFullAssert(s != btScalar(0.0));
return *this *= btScalar(1.0) / s;
}
/**@brief Return the dot product
* @param v The other vector in the dot product */
SIMD_FORCE_INLINE btScalar dot(const btVector3 &v) const {
return m_floats[0] * v.m_floats[0] + m_floats[1] * v.m_floats[1] + m_floats[2] * v.m_floats[2];
}
/**@brief Return the length of the vector squared */
SIMD_FORCE_INLINE btScalar length2() const {
return dot(*this);
}
/**@brief Return the length of the vector */
SIMD_FORCE_INLINE btScalar length() const {
return btSqrt(length2());
}
/**@brief Return the distance squared between the ends of this and another vector
* This is symantically treating the vector like a point */
SIMD_FORCE_INLINE btScalar distance2(const btVector3 &v) const;
/**@brief Return the distance between the ends of this and another vector
* This is symantically treating the vector like a point */
SIMD_FORCE_INLINE btScalar distance(const btVector3 &v) const;
SIMD_FORCE_INLINE btVector3 &safeNormalize() {
btVector3 absVec = this->absolute();
int32_t maxIndex = absVec.maxAxis();
if (absVec[maxIndex] > 0) {
*this /= absVec[maxIndex];
return *this /= length();
}
setValue(1, 0, 0);
return *this;
}
/**@brief Normalize this vector
* x^2 + y^2 + z^2 = 1 */
SIMD_FORCE_INLINE btVector3 &normalize() {
return *this /= length();
}
/**@brief Return a normalized version of this vector */
SIMD_FORCE_INLINE btVector3 normalized() const;
/**@brief Return a rotated version of this vector
* @param wAxis The axis to rotate about
* @param angle The angle to rotate by */
SIMD_FORCE_INLINE btVector3 rotate(const btVector3 &wAxis, const btScalar angle) const;
/**@brief Return the angle between this and another vector
* @param v The other vector */
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const {
btScalar s = btSqrt(length2() * v.length2());
btFullAssert(s != btScalar(0.0));
return btAcos(dot(v) / s);
}
/**@brief Return a vector will the absolute values of each element */
SIMD_FORCE_INLINE btVector3 absolute() const {
return btVector3(
btFabs(m_floats[0]),
btFabs(m_floats[1]),
btFabs(m_floats[2]));
}
/**@brief Return the cross product between this and another vector
* @param v The other vector */
SIMD_FORCE_INLINE btVector3 cross(const btVector3 &v) const {
return btVector3(
m_floats[1] * v.m_floats[2] - m_floats[2] * v.m_floats[1],
m_floats[2] * v.m_floats[0] - m_floats[0] * v.m_floats[2],
m_floats[0] * v.m_floats[1] - m_floats[1] * v.m_floats[0]);
}
SIMD_FORCE_INLINE btScalar triple(const btVector3 &v1, const btVector3 &v2) const {
return m_floats[0] * (v1.m_floats[1] * v2.m_floats[2] - v1.m_floats[2] * v2.m_floats[1]) + m_floats[1] * (v1.m_floats[2] * v2.m_floats[0] - v1.m_floats[0] * v2.m_floats[2]) + m_floats[2] * (v1.m_floats[0] * v2.m_floats[1] - v1.m_floats[1] * v2.m_floats[0]);
}
/**@brief Return the axis with the smallest value
* Note return values are 0,1,2 for x, y, or z */
SIMD_FORCE_INLINE int32_t minAxis() const {
return m_floats[0] < m_floats[1] ? (m_floats[0] < m_floats[2] ? 0 : 2) : (m_floats[1] < m_floats[2] ? 1 : 2);
}
/**@brief Return the axis with the largest value
* Note return values are 0,1,2 for x, y, or z */
SIMD_FORCE_INLINE int32_t maxAxis() const {
return m_floats[0] < m_floats[1] ? (m_floats[1] < m_floats[2] ? 2 : 1) : (m_floats[0] < m_floats[2] ? 2 : 0);
}
SIMD_FORCE_INLINE int32_t furthestAxis() const {
return absolute().minAxis();
}
SIMD_FORCE_INLINE int32_t closestAxis() const {
return absolute().maxAxis();
}
SIMD_FORCE_INLINE void setInterpolate3(const btVector3 &v0, const btVector3 &v1, btScalar rt) {
btScalar s = btScalar(1.0) - rt;
m_floats[0] = s * v0.m_floats[0] + rt * v1.m_floats[0];
m_floats[1] = s * v0.m_floats[1] + rt * v1.m_floats[1];
m_floats[2] = s * v0.m_floats[2] + rt * v1.m_floats[2];
//don't do the unused w component
// m_co[3] = s * v0[3] + rt * v1[3];
}
/**@brief Return the linear interpolation between this and another vector
* @param v The other vector
* @param t The ration of this to v (t = 0 => return this, t=1 => return other) */
SIMD_FORCE_INLINE btVector3 lerp(const btVector3 &v, const btScalar &t) const {
return btVector3(m_floats[0] + (v.m_floats[0] - m_floats[0]) * t,
m_floats[1] + (v.m_floats[1] - m_floats[1]) * t,
m_floats[2] + (v.m_floats[2] - m_floats[2]) * t);
}
/**@brief Elementwise multiply this vector by the other
* @param v The other vector */
SIMD_FORCE_INLINE btVector3 &operator*=(const btVector3 &v) {
m_floats[0] *= v.m_floats[0];
m_floats[1] *= v.m_floats[1];
m_floats[2] *= v.m_floats[2];
return *this;
}
/**@brief Return the x value */
SIMD_FORCE_INLINE const btScalar &getX() const { return m_floats[0]; }
/**@brief Return the y value */
SIMD_FORCE_INLINE const btScalar &getY() const { return m_floats[1]; }
/**@brief Return the z value */
SIMD_FORCE_INLINE const btScalar &getZ() const { return m_floats[2]; }
/**@brief Set the x value */
SIMD_FORCE_INLINE void setX(btScalar x) { m_floats[0] = x; };
/**@brief Set the y value */
SIMD_FORCE_INLINE void setY(btScalar y) { m_floats[1] = y; };
/**@brief Set the z value */
SIMD_FORCE_INLINE void setZ(btScalar z) { m_floats[2] = z; };
/**@brief Set the w value */
SIMD_FORCE_INLINE void setW(btScalar w) { m_floats[3] = w; };
/**@brief Return the x value */
SIMD_FORCE_INLINE const btScalar &x() const { return m_floats[0]; }
/**@brief Return the y value */
SIMD_FORCE_INLINE const btScalar &y() const { return m_floats[1]; }
/**@brief Return the z value */
SIMD_FORCE_INLINE const btScalar &z() const { return m_floats[2]; }
/**@brief Return the w value */
SIMD_FORCE_INLINE const btScalar &w() const { return m_floats[3]; }
//SIMD_FORCE_INLINE btScalar& operator[](int32_t i) { return (&m_floats[0])[i]; }
//SIMD_FORCE_INLINE const btScalar& operator[](int32_t i) const { return (&m_floats[0])[i]; }
///operator btScalar*() replaces operator[], using implicit conversion. We added operator != and operator == to avoid pointer comparisons.
SIMD_FORCE_INLINE operator btScalar *() { return &m_floats[0]; }
SIMD_FORCE_INLINE operator const btScalar *() const { return &m_floats[0]; }
SIMD_FORCE_INLINE bool operator==(const btVector3 &other) const {
return ((m_floats[3] == other.m_floats[3]) && (m_floats[2] == other.m_floats[2]) && (m_floats[1] == other.m_floats[1]) && (m_floats[0] == other.m_floats[0]));
}
SIMD_FORCE_INLINE bool operator!=(const btVector3 &other) const {
return !(*this == other);
}
/**@brief Set each element to the max of the current values and the values of another btVector3
* @param other The other btVector3 to compare with
*/
SIMD_FORCE_INLINE void setMax(const btVector3 &other) {
btSetMax(m_floats[0], other.m_floats[0]);
btSetMax(m_floats[1], other.m_floats[1]);
btSetMax(m_floats[2], other.m_floats[2]);
btSetMax(m_floats[3], other.w());
}
/**@brief Set each element to the min of the current values and the values of another btVector3
* @param other The other btVector3 to compare with
*/
SIMD_FORCE_INLINE void setMin(const btVector3 &other) {
btSetMin(m_floats[0], other.m_floats[0]);
btSetMin(m_floats[1], other.m_floats[1]);
btSetMin(m_floats[2], other.m_floats[2]);
btSetMin(m_floats[3], other.w());
}
SIMD_FORCE_INLINE void setValue(const btScalar &x, const btScalar &y, const btScalar &z) {
m_floats[0] = x;
m_floats[1] = y;
m_floats[2] = z;
m_floats[3] = btScalar(0.);
}
void getSkewSymmetricMatrix(btVector3 * v0, btVector3 * v1, btVector3 * v2) const {
v0->setValue(0., -z(), y());
v1->setValue(z(), 0., -x());
v2->setValue(-y(), x(), 0.);
}
void setZero() {
setValue(btScalar(0.), btScalar(0.), btScalar(0.));
}
SIMD_FORCE_INLINE bool isZero() const {
return m_floats[0] == btScalar(0) && m_floats[1] == btScalar(0) && m_floats[2] == btScalar(0);
}
SIMD_FORCE_INLINE bool fuzzyZero() const {
return length2() < SIMD_EPSILON;
}
SIMD_FORCE_INLINE void serialize(struct btVector3Data & dataOut) const;
SIMD_FORCE_INLINE void deSerialize(const struct btVector3Data &dataIn);
SIMD_FORCE_INLINE void serializeFloat(struct btVector3FloatData & dataOut) const;
SIMD_FORCE_INLINE void deSerializeFloat(const struct btVector3FloatData &dataIn);
SIMD_FORCE_INLINE void serializeDouble(struct btVector3DoubleData & dataOut) const;
SIMD_FORCE_INLINE void deSerializeDouble(const struct btVector3DoubleData &dataIn);
};
/**@brief Return the sum of two vectors (Point symantics)*/
SIMD_FORCE_INLINE btVector3
operator+(const btVector3 &v1, const btVector3 &v2) {
return btVector3(v1.m_floats[0] + v2.m_floats[0], v1.m_floats[1] + v2.m_floats[1], v1.m_floats[2] + v2.m_floats[2]);
}
/**@brief Return the elementwise product of two vectors */
SIMD_FORCE_INLINE btVector3
operator*(const btVector3 &v1, const btVector3 &v2) {
return btVector3(v1.m_floats[0] * v2.m_floats[0], v1.m_floats[1] * v2.m_floats[1], v1.m_floats[2] * v2.m_floats[2]);
}
/**@brief Return the difference between two vectors */
SIMD_FORCE_INLINE btVector3
operator-(const btVector3 &v1, const btVector3 &v2) {
return btVector3(v1.m_floats[0] - v2.m_floats[0], v1.m_floats[1] - v2.m_floats[1], v1.m_floats[2] - v2.m_floats[2]);
}
/**@brief Return the negative of the vector */
SIMD_FORCE_INLINE btVector3
operator-(const btVector3 &v) {
return btVector3(-v.m_floats[0], -v.m_floats[1], -v.m_floats[2]);
}
/**@brief Return the vector scaled by s */
SIMD_FORCE_INLINE btVector3
operator*(const btVector3 &v, const btScalar &s) {
return btVector3(v.m_floats[0] * s, v.m_floats[1] * s, v.m_floats[2] * s);
}
/**@brief Return the vector scaled by s */
SIMD_FORCE_INLINE btVector3
operator*(const btScalar &s, const btVector3 &v) {
return v * s;
}
/**@brief Return the vector inversely scaled by s */
SIMD_FORCE_INLINE btVector3
operator/(const btVector3 &v, const btScalar &s) {
btFullAssert(s != btScalar(0.0));
return v * (btScalar(1.0) / s);
}
/**@brief Return the vector inversely scaled by s */
SIMD_FORCE_INLINE btVector3
operator/(const btVector3 &v1, const btVector3 &v2) {
return btVector3(v1.m_floats[0] / v2.m_floats[0], v1.m_floats[1] / v2.m_floats[1], v1.m_floats[2] / v2.m_floats[2]);
}
/**@brief Return the dot product between two vectors */
SIMD_FORCE_INLINE btScalar
btDot(const btVector3 &v1, const btVector3 &v2) {
return v1.dot(v2);
}
/**@brief Return the distance squared between two vectors */
SIMD_FORCE_INLINE btScalar
btDistance2(const btVector3 &v1, const btVector3 &v2) {
return v1.distance2(v2);
}
/**@brief Return the distance between two vectors */
SIMD_FORCE_INLINE btScalar
btDistance(const btVector3 &v1, const btVector3 &v2) {
return v1.distance(v2);
}
/**@brief Return the angle between two vectors */
SIMD_FORCE_INLINE btScalar
btAngle(const btVector3 &v1, const btVector3 &v2) {
return v1.angle(v2);
}
/**@brief Return the cross product of two vectors */
SIMD_FORCE_INLINE btVector3
btCross(const btVector3 &v1, const btVector3 &v2) {
return v1.cross(v2);
}
SIMD_FORCE_INLINE btScalar
btTriple(const btVector3 &v1, const btVector3 &v2, const btVector3 &v3) {
return v1.triple(v2, v3);
}
/**@brief Return the linear interpolation between two vectors
* @param v1 One vector
* @param v2 The other vector
* @param t The ration of this to v (t = 0 => return v1, t=1 => return v2) */
SIMD_FORCE_INLINE btVector3
lerp(const btVector3 &v1, const btVector3 &v2, const btScalar &t) {
return v1.lerp(v2, t);
}
SIMD_FORCE_INLINE btScalar btVector3::distance2(const btVector3 &v) const {
return (v - *this).length2();
}
SIMD_FORCE_INLINE btScalar btVector3::distance(const btVector3 &v) const {
return (v - *this).length();
}
SIMD_FORCE_INLINE btVector3 btVector3::normalized() const {
return *this / length();
}
SIMD_FORCE_INLINE btVector3 btVector3::rotate(const btVector3 &wAxis, const btScalar angle) const {
// wAxis must be a unit lenght vector
btVector3 o = wAxis * wAxis.dot(*this);
btVector3 x = *this - o;
btVector3 y;
y = wAxis.cross(*this);
return (o + x * btCos(angle) + y * btSin(angle));
}
class btVector4 : public btVector3 {
public:
SIMD_FORCE_INLINE btVector4() {}
SIMD_FORCE_INLINE btVector4(const btScalar &x, const btScalar &y, const btScalar &z, const btScalar &w) :
btVector3(x, y, z) {
m_floats[3] = w;
}
SIMD_FORCE_INLINE btVector4 absolute4() const {
return btVector4(
btFabs(m_floats[0]),
btFabs(m_floats[1]),
btFabs(m_floats[2]),
btFabs(m_floats[3]));
}
btScalar getW() const { return m_floats[3]; }
SIMD_FORCE_INLINE int32_t maxAxis4() const {
int32_t maxIndex = -1;
btScalar maxVal = btScalar(-BT_LARGE_FLOAT);
if (m_floats[0] > maxVal) {
maxIndex = 0;
maxVal = m_floats[0];
}
if (m_floats[1] > maxVal) {
maxIndex = 1;
maxVal = m_floats[1];
}
if (m_floats[2] > maxVal) {
maxIndex = 2;
maxVal = m_floats[2];
}
if (m_floats[3] > maxVal) {
maxIndex = 3;
}
return maxIndex;
}
SIMD_FORCE_INLINE int32_t minAxis4() const {
int32_t minIndex = -1;
btScalar minVal = btScalar(BT_LARGE_FLOAT);
if (m_floats[0] < minVal) {
minIndex = 0;
minVal = m_floats[0];
}
if (m_floats[1] < minVal) {
minIndex = 1;
minVal = m_floats[1];
}
if (m_floats[2] < minVal) {
minIndex = 2;
minVal = m_floats[2];
}
if (m_floats[3] < minVal) {
minIndex = 3;
}
return minIndex;
}
SIMD_FORCE_INLINE int32_t closestAxis4() const {
return absolute4().maxAxis4();
}
/**@brief Set x,y,z and zero w
* @param x Value of x
* @param y Value of y
* @param z Value of z
*/
/* void getValue(btScalar *m) const
{
m[0] = m_floats[0];
m[1] = m_floats[1];
m[2] =m_floats[2];
}
*/
/**@brief Set the values
* @param x Value of x
* @param y Value of y
* @param z Value of z
* @param w Value of w
*/
SIMD_FORCE_INLINE void setValue(const btScalar &x, const btScalar &y, const btScalar &z, const btScalar &w) {
m_floats[0] = x;
m_floats[1] = y;
m_floats[2] = z;
m_floats[3] = w;
}
};
///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btSwapScalarEndian(const btScalar &sourceVal, btScalar &destVal) {
#ifdef BT_USE_DOUBLE_PRECISION
unsigned char *dest = (unsigned char *)&destVal;
unsigned char *src = (unsigned char *)&sourceVal;
dest[0] = src[7];
dest[1] = src[6];
dest[2] = src[5];
dest[3] = src[4];
dest[4] = src[3];
dest[5] = src[2];
dest[6] = src[1];
dest[7] = src[0];
#else
unsigned char *dest = (unsigned char *)&destVal;
unsigned char *src = (unsigned char *)&sourceVal;
dest[0] = src[3];
dest[1] = src[2];
dest[2] = src[1];
dest[3] = src[0];
#endif //BT_USE_DOUBLE_PRECISION
}
///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btSwapVector3Endian(const btVector3 &sourceVec, btVector3 &destVec) {
for (int32_t i = 0; i < 4; i++) {
btSwapScalarEndian(sourceVec[i], destVec[i]);
}
}
///btUnSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization
SIMD_FORCE_INLINE void btUnSwapVector3Endian(btVector3 &vector) {
btVector3 swappedVec;
for (int32_t i = 0; i < 4; i++) {
btSwapScalarEndian(vector[i], swappedVec[i]);
}
vector = swappedVec;
}
template <class T>
SIMD_FORCE_INLINE void btPlaneSpace1(const T &n, T &p, T &q) {
if (btFabs(n[2]) > SIMDSQRT12) {
// choose p in y-z plane
btScalar a = n[1] * n[1] + n[2] * n[2];
btScalar k = btRecipSqrt(a);
p[0] = 0;
p[1] = -n[2] * k;
p[2] = n[1] * k;
// set q = n x p
q[0] = a * k;
q[1] = -n[0] * p[2];
q[2] = n[0] * p[1];
} else {
// choose p in x-y plane
btScalar a = n[0] * n[0] + n[1] * n[1];
btScalar k = btRecipSqrt(a);
p[0] = -n[1] * k;
p[1] = n[0] * k;
p[2] = 0;
// set q = n x p
q[0] = -n[2] * p[1];
q[1] = n[2] * p[0];
q[2] = a * k;
}
}
struct btVector3FloatData {
float m_floats[4];
};
struct btVector3DoubleData {
double m_floats[4];
};
SIMD_FORCE_INLINE void btVector3::serializeFloat(struct btVector3FloatData &dataOut) const {
///could also do a memcpy, check if it is worth it
for (int32_t i = 0; i < 4; i++)
dataOut.m_floats[i] = float(m_floats[i]);
}
SIMD_FORCE_INLINE void btVector3::deSerializeFloat(const struct btVector3FloatData &dataIn) {
for (int32_t i = 0; i < 4; i++)
m_floats[i] = btScalar(dataIn.m_floats[i]);
}
SIMD_FORCE_INLINE void btVector3::serializeDouble(struct btVector3DoubleData &dataOut) const {
///could also do a memcpy, check if it is worth it
for (int32_t i = 0; i < 4; i++)
dataOut.m_floats[i] = double(m_floats[i]);
}
SIMD_FORCE_INLINE void btVector3::deSerializeDouble(const struct btVector3DoubleData &dataIn) {
for (int32_t i = 0; i < 4; i++)
m_floats[i] = btScalar(dataIn.m_floats[i]);
}
SIMD_FORCE_INLINE void btVector3::serialize(struct btVector3Data &dataOut) const {
///could also do a memcpy, check if it is worth it
for (int32_t i = 0; i < 4; i++)
dataOut.m_floats[i] = m_floats[i];
}
SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3Data &dataIn) {
for (int32_t i = 0; i < 4; i++)
m_floats[i] = dataIn.m_floats[i];
}
//GODOT ADDITION
}; // namespace VHACD
//
#endif //BT_VECTOR3_H

View file

@ -0,0 +1,79 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_CIRCULAR_LIST_H
#define VHACD_CIRCULAR_LIST_H
#include <stdlib.h>
namespace VHACD {
//! CircularListElement class.
template <typename T>
class CircularListElement {
public:
T& GetData() { return m_data; }
const T& GetData() const { return m_data; }
CircularListElement<T>*& GetNext() { return m_next; }
CircularListElement<T>*& GetPrev() { return m_prev; }
const CircularListElement<T>*& GetNext() const { return m_next; }
const CircularListElement<T>*& GetPrev() const { return m_prev; }
//! Constructor
CircularListElement(const T& data) { m_data = data; }
CircularListElement(void) {}
//! Destructor
~CircularListElement(void) {}
private:
T m_data;
CircularListElement<T>* m_next;
CircularListElement<T>* m_prev;
CircularListElement(const CircularListElement& rhs);
};
//! CircularList class.
template <typename T>
class CircularList {
public:
CircularListElement<T>*& GetHead() { return m_head; }
const CircularListElement<T>* GetHead() const { return m_head; }
bool IsEmpty() const { return (m_size == 0); }
size_t GetSize() const { return m_size; }
const T& GetData() const { return m_head->GetData(); }
T& GetData() { return m_head->GetData(); }
bool Delete();
bool Delete(CircularListElement<T>* element);
CircularListElement<T>* Add(const T* data = 0);
CircularListElement<T>* Add(const T& data);
bool Next();
bool Prev();
void Clear()
{
while (Delete())
;
};
const CircularList& operator=(const CircularList& rhs);
//! Constructor
CircularList()
{
m_head = 0;
m_size = 0;
}
CircularList(const CircularList& rhs);
//! Destructor
~CircularList(void) { Clear(); };
private:
CircularListElement<T>* m_head; //!< a pointer to the head of the circular list
size_t m_size; //!< number of element in the circular list
};
}
#include "vhacdCircularList.inl"
#endif // VHACD_CIRCULAR_LIST_H

View file

@ -0,0 +1,161 @@
#pragma once
#ifndef HACD_CIRCULAR_LIST_INL
#define HACD_CIRCULAR_LIST_INL
namespace VHACD
{
template < typename T >
inline bool CircularList<T>::Delete(CircularListElement<T> * element)
{
if (!element)
{
return false;
}
if (m_size > 1)
{
CircularListElement<T> * next = element->GetNext();
CircularListElement<T> * prev = element->GetPrev();
delete element;
m_size--;
if (element == m_head)
{
m_head = next;
}
next->GetPrev() = prev;
prev->GetNext() = next;
return true;
}
else if (m_size == 1)
{
delete m_head;
m_size--;
m_head = 0;
return true;
}
else
{
return false;
}
}
template < typename T >
inline bool CircularList<T>::Delete()
{
if (m_size > 1)
{
CircularListElement<T> * next = m_head->GetNext();
CircularListElement<T> * prev = m_head->GetPrev();
delete m_head;
m_size--;
m_head = next;
next->GetPrev() = prev;
prev->GetNext() = next;
return true;
}
else if (m_size == 1)
{
delete m_head;
m_size--;
m_head = 0;
return true;
}
else
{
return false;
}
}
template < typename T >
inline CircularListElement<T> * CircularList<T>::Add(const T * data)
{
if (m_size == 0)
{
if (data)
{
m_head = new CircularListElement<T>(*data);
}
else
{
m_head = new CircularListElement<T>();
}
m_head->GetNext() = m_head->GetPrev() = m_head;
}
else
{
CircularListElement<T> * next = m_head->GetNext();
CircularListElement<T> * element = m_head;
if (data)
{
m_head = new CircularListElement<T>(*data);
}
else
{
m_head = new CircularListElement<T>();
}
m_head->GetNext() = next;
m_head->GetPrev() = element;
element->GetNext() = m_head;
next->GetPrev() = m_head;
}
m_size++;
return m_head;
}
template < typename T >
inline CircularListElement<T> * CircularList<T>::Add(const T & data)
{
const T * pData = &data;
return Add(pData);
}
template < typename T >
inline bool CircularList<T>::Next()
{
if (m_size == 0)
{
return false;
}
m_head = m_head->GetNext();
return true;
}
template < typename T >
inline bool CircularList<T>::Prev()
{
if (m_size == 0)
{
return false;
}
m_head = m_head->GetPrev();
return true;
}
template < typename T >
inline CircularList<T>::CircularList(const CircularList& rhs)
{
if (rhs.m_size > 0)
{
CircularListElement<T> * current = rhs.m_head;
do
{
current = current->GetNext();
Add(current->GetData());
}
while ( current != rhs.m_head );
}
}
template < typename T >
inline const CircularList<T>& CircularList<T>::operator=(const CircularList& rhs)
{
if (&rhs != this)
{
Clear();
if (rhs.m_size > 0)
{
CircularListElement<T> * current = rhs.m_head;
do
{
current = current->GetNext();
Add(current->GetData());
}
while ( current != rhs.m_head );
}
}
return (*this);
}
}
#endif

98
thirdparty/vhacd/inc/vhacdICHull.h vendored Normal file
View file

@ -0,0 +1,98 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_ICHULL_H
#define VHACD_ICHULL_H
#include "vhacdManifoldMesh.h"
#include "vhacdVector.h"
namespace VHACD {
//! Incremental Convex Hull algorithm (cf. http://cs.smith.edu/~orourke/books/ftp.html ).
enum ICHullError {
ICHullErrorOK = 0,
ICHullErrorCoplanarPoints,
ICHullErrorNoVolume,
ICHullErrorInconsistent,
ICHullErrorNotEnoughPoints
};
class ICHull {
public:
static const double sc_eps;
//!
bool IsFlat() { return m_isFlat; }
//! Returns the computed mesh
TMMesh& GetMesh() { return m_mesh; }
//! Add one point to the convex-hull
bool AddPoint(const Vec3<double>& point) { return AddPoints(&point, 1); }
//! Add one point to the convex-hull
bool AddPoint(const Vec3<double>& point, int32_t id);
//! Add points to the convex-hull
bool AddPoints(const Vec3<double>* points, size_t nPoints);
//!
ICHullError Process();
//!
ICHullError Process(const uint32_t nPointsCH, const double minVolume = 0.0);
//!
bool IsInside(const Vec3<double>& pt0, const double eps = 0.0);
//!
const ICHull& operator=(ICHull& rhs);
//! Constructor
ICHull();
//! Destructor
~ICHull(void){};
private:
//! DoubleTriangle builds the initial double triangle. It first finds 3 noncollinear points and makes two faces out of them, in opposite order. It then finds a fourth point that is not coplanar with that face. The vertices are stored in the face structure in counterclockwise order so that the volume between the face and the point is negative. Lastly, the 3 newfaces to the fourth point are constructed and the data structures are cleaned up.
ICHullError DoubleTriangle();
//! MakeFace creates a new face structure from three vertices (in ccw order). It returns a pointer to the face.
CircularListElement<TMMTriangle>* MakeFace(CircularListElement<TMMVertex>* v0,
CircularListElement<TMMVertex>* v1,
CircularListElement<TMMVertex>* v2,
CircularListElement<TMMTriangle>* fold);
//!
CircularListElement<TMMTriangle>* MakeConeFace(CircularListElement<TMMEdge>* e, CircularListElement<TMMVertex>* v);
//!
bool ProcessPoint();
//!
bool ComputePointVolume(double& totalVolume, bool markVisibleFaces);
//!
bool FindMaxVolumePoint(const double minVolume = 0.0);
//!
bool CleanEdges();
//!
bool CleanVertices(uint32_t& addedPoints);
//!
bool CleanTriangles();
//!
bool CleanUp(uint32_t& addedPoints);
//!
bool MakeCCW(CircularListElement<TMMTriangle>* f,
CircularListElement<TMMEdge>* e,
CircularListElement<TMMVertex>* v);
void Clear();
private:
static const int32_t sc_dummyIndex;
TMMesh m_mesh;
SArray<CircularListElement<TMMEdge>*> m_edgesToDelete;
SArray<CircularListElement<TMMEdge>*> m_edgesToUpdate;
SArray<CircularListElement<TMMTriangle>*> m_trianglesToDelete;
Vec3<double> m_normal;
bool m_isFlat;
ICHull(const ICHull& rhs);
};
}
#endif // VHACD_ICHULL_H

142
thirdparty/vhacd/inc/vhacdManifoldMesh.h vendored Normal file
View file

@ -0,0 +1,142 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_MANIFOLD_MESH_H
#define VHACD_MANIFOLD_MESH_H
#include "vhacdCircularList.h"
#include "vhacdSArray.h"
#include "vhacdVector.h"
namespace VHACD {
class TMMTriangle;
class TMMEdge;
class TMMesh;
class ICHull;
//! Vertex data structure used in a triangular manifold mesh (TMM).
class TMMVertex {
public:
void Initialize();
TMMVertex(void);
~TMMVertex(void);
private:
Vec3<double> m_pos;
int32_t m_name;
size_t m_id;
CircularListElement<TMMEdge>* m_duplicate; // pointer to incident cone edge (or NULL)
bool m_onHull;
bool m_tag;
TMMVertex(const TMMVertex& rhs);
friend class ICHull;
friend class TMMesh;
friend class TMMTriangle;
friend class TMMEdge;
};
//! Edge data structure used in a triangular manifold mesh (TMM).
class TMMEdge {
public:
void Initialize();
TMMEdge(void);
~TMMEdge(void);
private:
size_t m_id;
CircularListElement<TMMTriangle>* m_triangles[2];
CircularListElement<TMMVertex>* m_vertices[2];
CircularListElement<TMMTriangle>* m_newFace;
TMMEdge(const TMMEdge& rhs);
friend class ICHull;
friend class TMMTriangle;
friend class TMMVertex;
friend class TMMesh;
};
//! Triangle data structure used in a triangular manifold mesh (TMM).
class TMMTriangle {
public:
void Initialize();
TMMTriangle(void);
~TMMTriangle(void);
private:
size_t m_id;
CircularListElement<TMMEdge>* m_edges[3];
CircularListElement<TMMVertex>* m_vertices[3];
bool m_visible;
TMMTriangle(const TMMTriangle& rhs);
friend class ICHull;
friend class TMMesh;
friend class TMMVertex;
friend class TMMEdge;
};
//! triangular manifold mesh data structure.
class TMMesh {
public:
//! Returns the number of vertices>
inline size_t GetNVertices() const { return m_vertices.GetSize(); }
//! Returns the number of edges
inline size_t GetNEdges() const { return m_edges.GetSize(); }
//! Returns the number of triangles
inline size_t GetNTriangles() const { return m_triangles.GetSize(); }
//! Returns the vertices circular list
inline const CircularList<TMMVertex>& GetVertices() const { return m_vertices; }
//! Returns the edges circular list
inline const CircularList<TMMEdge>& GetEdges() const { return m_edges; }
//! Returns the triangles circular list
inline const CircularList<TMMTriangle>& GetTriangles() const { return m_triangles; }
//! Returns the vertices circular list
inline CircularList<TMMVertex>& GetVertices() { return m_vertices; }
//! Returns the edges circular list
inline CircularList<TMMEdge>& GetEdges() { return m_edges; }
//! Returns the triangles circular list
inline CircularList<TMMTriangle>& GetTriangles() { return m_triangles; }
//! Add vertex to the mesh
CircularListElement<TMMVertex>* AddVertex() { return m_vertices.Add(); }
//! Add vertex to the mesh
CircularListElement<TMMEdge>* AddEdge() { return m_edges.Add(); }
//! Add vertex to the mesh
CircularListElement<TMMTriangle>* AddTriangle() { return m_triangles.Add(); }
//! Print mesh information
void Print();
//!
void GetIFS(Vec3<double>* const points, Vec3<int32_t>* const triangles);
//!
void Clear();
//!
void Copy(TMMesh& mesh);
//!
bool CheckConsistancy();
//!
bool Normalize();
//!
bool Denormalize();
//! Constructor
TMMesh();
//! Destructor
virtual ~TMMesh(void);
private:
CircularList<TMMVertex> m_vertices;
CircularList<TMMEdge> m_edges;
CircularList<TMMTriangle> m_triangles;
// not defined
TMMesh(const TMMesh& rhs);
friend class ICHull;
};
}
#endif // VHACD_MANIFOLD_MESH_H

130
thirdparty/vhacd/inc/vhacdMesh.h vendored Normal file
View file

@ -0,0 +1,130 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_MESH_H
#define VHACD_MESH_H
#include "vhacdSArray.h"
#include "vhacdVector.h"
#define VHACD_DEBUG_MESH
namespace VHACD {
enum AXIS {
AXIS_X = 0,
AXIS_Y = 1,
AXIS_Z = 2
};
struct Plane {
double m_a;
double m_b;
double m_c;
double m_d;
AXIS m_axis;
short m_index;
};
#ifdef VHACD_DEBUG_MESH
struct Material {
Vec3<double> m_diffuseColor;
double m_ambientIntensity;
Vec3<double> m_specularColor;
Vec3<double> m_emissiveColor;
double m_shininess;
double m_transparency;
Material(void)
{
m_diffuseColor.X() = 0.5;
m_diffuseColor.Y() = 0.5;
m_diffuseColor.Z() = 0.5;
m_specularColor.X() = 0.5;
m_specularColor.Y() = 0.5;
m_specularColor.Z() = 0.5;
m_ambientIntensity = 0.4;
m_emissiveColor.X() = 0.0;
m_emissiveColor.Y() = 0.0;
m_emissiveColor.Z() = 0.0;
m_shininess = 0.4;
m_transparency = 0.0;
};
};
#endif // VHACD_DEBUG_MESH
//! Triangular mesh data structure
class Mesh {
public:
void AddPoint(const Vec3<double>& pt) { m_points.PushBack(pt); };
void SetPoint(size_t index, const Vec3<double>& pt) { m_points[index] = pt; };
const Vec3<double>& GetPoint(size_t index) const { return m_points[index]; };
Vec3<double>& GetPoint(size_t index) { return m_points[index]; };
size_t GetNPoints() const { return m_points.Size(); };
double* GetPoints() { return (double*)m_points.Data(); } // ugly
const double* const GetPoints() const { return (double*)m_points.Data(); } // ugly
const Vec3<double>* const GetPointsBuffer() const { return m_points.Data(); } //
Vec3<double>* const GetPointsBuffer() { return m_points.Data(); } //
void AddTriangle(const Vec3<int32_t>& tri) { m_triangles.PushBack(tri); };
void SetTriangle(size_t index, const Vec3<int32_t>& tri) { m_triangles[index] = tri; };
const Vec3<int32_t>& GetTriangle(size_t index) const { return m_triangles[index]; };
Vec3<int32_t>& GetTriangle(size_t index) { return m_triangles[index]; };
size_t GetNTriangles() const { return m_triangles.Size(); };
int32_t* GetTriangles() { return (int32_t*)m_triangles.Data(); } // ugly
const int32_t* const GetTriangles() const { return (int32_t*)m_triangles.Data(); } // ugly
const Vec3<int32_t>* const GetTrianglesBuffer() const { return m_triangles.Data(); }
Vec3<int32_t>* const GetTrianglesBuffer() { return m_triangles.Data(); }
const Vec3<double>& GetCenter() const { return m_center; }
const Vec3<double>& GetMinBB() const { return m_minBB; }
const Vec3<double>& GetMaxBB() const { return m_maxBB; }
void ClearPoints() { m_points.Clear(); }
void ClearTriangles() { m_triangles.Clear(); }
void Clear()
{
ClearPoints();
ClearTriangles();
}
void ResizePoints(size_t nPts) { m_points.Resize(nPts); }
void ResizeTriangles(size_t nTri) { m_triangles.Resize(nTri); }
void CopyPoints(SArray<Vec3<double> >& points) const { points = m_points; }
double GetDiagBB() const { return m_diag; }
double ComputeVolume() const;
void ComputeConvexHull(const double* const pts,
const size_t nPts);
void Clip(const Plane& plane,
SArray<Vec3<double> >& positivePart,
SArray<Vec3<double> >& negativePart) const;
bool IsInside(const Vec3<double>& pt) const;
double ComputeDiagBB();
Vec3<double> &ComputeCenter(void);
#ifdef VHACD_DEBUG_MESH
bool LoadOFF(const std::string& fileName, bool invert);
bool SaveVRML2(const std::string& fileName) const;
bool SaveVRML2(std::ofstream& fout, const Material& material) const;
bool SaveOFF(const std::string& fileName) const;
#endif // VHACD_DEBUG_MESH
//! Constructor.
Mesh();
//! Destructor.
~Mesh(void);
private:
SArray<Vec3<double> > m_points;
SArray<Vec3<int32_t> > m_triangles;
Vec3<double> m_minBB;
Vec3<double> m_maxBB;
Vec3<double> m_center;
double m_diag;
};
}
#endif

148
thirdparty/vhacd/inc/vhacdMutex.h vendored Normal file
View file

@ -0,0 +1,148 @@
/*!
**
** Copyright (c) 2009 by John W. Ratcliff mailto:jratcliffscarab@gmail.com
**
** Portions of this source has been released with the PhysXViewer application, as well as
** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
**
** If you find this code useful or you are feeling particularily generous I would
** ask that you please go to http://www.amillionpixels.us and make a donation
** to Troy DeMolay.
**
** DeMolay is a youth group for young men between the ages of 12 and 21.
** It teaches strong moral principles, as well as leadership skills and
** public speaking. The donations page uses the 'pay for pixels' paradigm
** where, in this case, a pixel is only a single penny. Donations can be
** made for as small as $4 or as high as a $100 block. Each person who donates
** will get a link to their own site as well as acknowledgement on the
** donations blog located here http://www.amillionpixels.blogspot.com/
**
** If you wish to contact me you can use the following methods:
**
** Skype ID: jratcliff63367
** Yahoo: jratcliff63367
** AOL: jratcliff1961
** email: jratcliffscarab@gmail.com
**
**
** The MIT license:
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
** copies of the Software, and to permit persons to whom the Software is furnished
** to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in all
** copies or substantial portions of the Software.
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#ifndef VHACD_MUTEX_H
#define VHACD_MUTEX_H
#if defined(WIN32)
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
#endif
#include <windows.h>
#pragma comment(lib, "winmm.lib")
#endif
#if defined(__linux__)
//#include <sys/time.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#define __stdcall
#endif
#if defined(__APPLE__) || defined(__linux__)
#include <pthread.h>
#endif
#if defined(__APPLE__)
#define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
#endif
#define VHACD_DEBUG
//#define VHACD_NDEBUG
#ifdef VHACD_NDEBUG
#define VHACD_VERIFY(x) (x)
#else
#define VHACD_VERIFY(x) assert((x))
#endif
namespace VHACD {
class Mutex {
public:
Mutex(void)
{
#if defined(WIN32) || defined(_XBOX)
InitializeCriticalSection(&m_mutex);
#elif defined(__APPLE__) || defined(__linux__)
pthread_mutexattr_t mutexAttr; // Mutex Attribute
VHACD_VERIFY(pthread_mutexattr_init(&mutexAttr) == 0);
VHACD_VERIFY(pthread_mutexattr_settype(&mutexAttr, PTHREAD_MUTEX_RECURSIVE_NP) == 0);
VHACD_VERIFY(pthread_mutex_init(&m_mutex, &mutexAttr) == 0);
VHACD_VERIFY(pthread_mutexattr_destroy(&mutexAttr) == 0);
#endif
}
~Mutex(void)
{
#if defined(WIN32) || defined(_XBOX)
DeleteCriticalSection(&m_mutex);
#elif defined(__APPLE__) || defined(__linux__)
VHACD_VERIFY(pthread_mutex_destroy(&m_mutex) == 0);
#endif
}
void Lock(void)
{
#if defined(WIN32) || defined(_XBOX)
EnterCriticalSection(&m_mutex);
#elif defined(__APPLE__) || defined(__linux__)
VHACD_VERIFY(pthread_mutex_lock(&m_mutex) == 0);
#endif
}
bool TryLock(void)
{
#if defined(WIN32) || defined(_XBOX)
bool bRet = false;
//assert(("TryEnterCriticalSection seems to not work on XP???", 0));
bRet = TryEnterCriticalSection(&m_mutex) ? true : false;
return bRet;
#elif defined(__APPLE__) || defined(__linux__)
int32_t result = pthread_mutex_trylock(&m_mutex);
return (result == 0);
#endif
}
void Unlock(void)
{
#if defined(WIN32) || defined(_XBOX)
LeaveCriticalSection(&m_mutex);
#elif defined(__APPLE__) || defined(__linux__)
VHACD_VERIFY(pthread_mutex_unlock(&m_mutex) == 0);
#endif
}
private:
#if defined(WIN32) || defined(_XBOX)
CRITICAL_SECTION m_mutex;
#elif defined(__APPLE__) || defined(__linux__)
pthread_mutex_t m_mutex;
#endif
};
}
#endif // VHACD_MUTEX_H

39
thirdparty/vhacd/inc/vhacdRaycastMesh.h vendored Normal file
View file

@ -0,0 +1,39 @@
#ifndef RAYCAST_MESH_H
#define RAYCAST_MESH_H
#include <stdint.h>
namespace VHACD
{
// Very simple brute force raycast against a triangle mesh. Tests every triangle; no hierachy.
// Does a deep copy, always does calculations with full double float precision
class RaycastMesh
{
public:
static RaycastMesh * createRaycastMesh(uint32_t vcount, // The number of vertices in the source triangle mesh
const double *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
uint32_t tcount, // The number of triangles in the source triangle mesh
const uint32_t *indices); // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
static RaycastMesh * createRaycastMesh(uint32_t vcount, // The number of vertices in the source triangle mesh
const float *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
uint32_t tcount, // The number of triangles in the source triangle mesh
const uint32_t *indices); // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
virtual bool raycast(const double *from, // The starting point of the raycast
const double *to, // The ending point of the raycast
const double *closestToPoint, // The point to match the nearest hit location (can just be the 'from' location of no specific point)
double *hitLocation, // The point where the ray hit nearest to the 'closestToPoint' location
double *hitDistance) = 0; // The distance the ray traveled to the hit location
virtual void release(void) = 0;
protected:
virtual ~RaycastMesh(void) { };
};
} // end of VHACD namespace
#endif

158
thirdparty/vhacd/inc/vhacdSArray.h vendored Normal file
View file

@ -0,0 +1,158 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_SARRAY_H
#define VHACD_SARRAY_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SARRAY_DEFAULT_MIN_SIZE 16
namespace VHACD {
//! SArray.
template <typename T, size_t N = 64>
class SArray {
public:
T& operator[](size_t i)
{
T* const data = Data();
return data[i];
}
const T& operator[](size_t i) const
{
const T* const data = Data();
return data[i];
}
size_t Size() const
{
return m_size;
}
T* const Data()
{
return (m_maxSize == N) ? m_data0 : m_data;
}
const T* const Data() const
{
return (m_maxSize == N) ? m_data0 : m_data;
}
void Clear()
{
m_size = 0;
delete[] m_data;
m_data = 0;
m_maxSize = N;
}
void PopBack()
{
--m_size;
}
void Allocate(size_t size)
{
if (size > m_maxSize) {
T* temp = new T[size];
memcpy(temp, Data(), m_size * sizeof(T));
delete[] m_data;
m_data = temp;
m_maxSize = size;
}
}
void Resize(size_t size)
{
Allocate(size);
m_size = size;
}
void PushBack(const T& value)
{
if (m_size == m_maxSize) {
size_t maxSize = (m_maxSize << 1);
T* temp = new T[maxSize];
memcpy(temp, Data(), m_maxSize * sizeof(T));
delete[] m_data;
m_data = temp;
m_maxSize = maxSize;
}
T* const data = Data();
data[m_size++] = value;
}
bool Find(const T& value, size_t& pos)
{
T* const data = Data();
for (pos = 0; pos < m_size; ++pos)
if (value == data[pos])
return true;
return false;
}
bool Insert(const T& value)
{
size_t pos;
if (Find(value, pos))
return false;
PushBack(value);
return true;
}
bool Erase(const T& value)
{
size_t pos;
T* const data = Data();
if (Find(value, pos)) {
for (size_t j = pos + 1; j < m_size; ++j)
data[j - 1] = data[j];
--m_size;
return true;
}
return false;
}
void operator=(const SArray& rhs)
{
if (m_maxSize < rhs.m_size) {
delete[] m_data;
m_maxSize = rhs.m_maxSize;
m_data = new T[m_maxSize];
}
m_size = rhs.m_size;
memcpy(Data(), rhs.Data(), m_size * sizeof(T));
}
void Initialize()
{
m_data = 0;
m_size = 0;
m_maxSize = N;
}
SArray(const SArray& rhs)
{
m_data = 0;
m_size = 0;
m_maxSize = N;
*this = rhs;
}
SArray()
{
Initialize();
}
~SArray()
{
delete[] m_data;
}
private:
T m_data0[N];
T* m_data;
size_t m_size;
size_t m_maxSize;
};
}
#endif

121
thirdparty/vhacd/inc/vhacdTimer.h vendored Normal file
View file

@ -0,0 +1,121 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_TIMER_H
#define VHACD_TIMER_H
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#endif
#include <windows.h>
#elif __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#else
#include <sys/time.h>
#include <time.h>
#endif
namespace VHACD {
#ifdef _WIN32
class Timer {
public:
Timer(void)
{
m_start.QuadPart = 0;
m_stop.QuadPart = 0;
QueryPerformanceFrequency(&m_freq);
};
~Timer(void){};
void Tic()
{
QueryPerformanceCounter(&m_start);
}
void Toc()
{
QueryPerformanceCounter(&m_stop);
}
double GetElapsedTime() // in ms
{
LARGE_INTEGER delta;
delta.QuadPart = m_stop.QuadPart - m_start.QuadPart;
return (1000.0 * delta.QuadPart) / (double)m_freq.QuadPart;
}
private:
LARGE_INTEGER m_start;
LARGE_INTEGER m_stop;
LARGE_INTEGER m_freq;
};
#elif __MACH__
class Timer {
public:
Timer(void)
{
memset(this, 0, sizeof(Timer));
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &m_cclock);
};
~Timer(void)
{
mach_port_deallocate(mach_task_self(), m_cclock);
};
void Tic()
{
clock_get_time(m_cclock, &m_start);
}
void Toc()
{
clock_get_time(m_cclock, &m_stop);
}
double GetElapsedTime() // in ms
{
return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
}
private:
clock_serv_t m_cclock;
mach_timespec_t m_start;
mach_timespec_t m_stop;
};
#else
class Timer {
public:
Timer(void)
{
memset(this, 0, sizeof(Timer));
};
~Timer(void){};
void Tic()
{
clock_gettime(CLOCK_REALTIME, &m_start);
}
void Toc()
{
clock_gettime(CLOCK_REALTIME, &m_stop);
}
double GetElapsedTime() // in ms
{
return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
}
private:
struct timespec m_start;
struct timespec m_stop;
};
#endif
}
#endif // VHACD_TIMER_H

371
thirdparty/vhacd/inc/vhacdVHACD.h vendored Normal file
View file

@ -0,0 +1,371 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_VHACD_H
#define VHACD_VHACD_H
#ifdef OPENCL_FOUND
#ifdef __MACH__
#include <OpenCL/cl.h>
#else
#include <CL/cl.h>
#endif
#endif //OPENCL_FOUND
#include "vhacdMutex.h"
#include "vhacdVolume.h"
#include "vhacdRaycastMesh.h"
#include <vector>
#define USE_THREAD 1
#define OCL_MIN_NUM_PRIMITIVES 4096
#define CH_APP_MIN_NUM_PRIMITIVES 64000
namespace VHACD {
class VHACD : public IVHACD {
public:
//! Constructor.
VHACD()
{
#if USE_THREAD == 1 && _OPENMP
m_ompNumProcessors = 2 * omp_get_num_procs();
omp_set_num_threads(m_ompNumProcessors);
#else //USE_THREAD == 1 && _OPENMP
m_ompNumProcessors = 1;
#endif //USE_THREAD == 1 && _OPENMP
#ifdef CL_VERSION_1_1
m_oclWorkGroupSize = 0;
m_oclDevice = 0;
m_oclQueue = 0;
m_oclKernelComputePartialVolumes = 0;
m_oclKernelComputeSum = 0;
#endif //CL_VERSION_1_1
Init();
}
//! Destructor.
~VHACD(void)
{
}
uint32_t GetNConvexHulls() const
{
return (uint32_t)m_convexHulls.Size();
}
void Cancel()
{
SetCancel(true);
}
void GetConvexHull(const uint32_t index, ConvexHull& ch) const
{
Mesh* mesh = m_convexHulls[index];
ch.m_nPoints = (uint32_t)mesh->GetNPoints();
ch.m_nTriangles = (uint32_t)mesh->GetNTriangles();
ch.m_points = mesh->GetPoints();
ch.m_triangles = (uint32_t *)mesh->GetTriangles();
ch.m_volume = mesh->ComputeVolume();
Vec3<double> &center = mesh->ComputeCenter();
ch.m_center[0] = center.X();
ch.m_center[1] = center.Y();
ch.m_center[2] = center.Z();
}
void Clean(void)
{
if (mRaycastMesh)
{
mRaycastMesh->release();
mRaycastMesh = nullptr;
}
delete m_volume;
delete m_pset;
size_t nCH = m_convexHulls.Size();
for (size_t p = 0; p < nCH; ++p) {
delete m_convexHulls[p];
}
m_convexHulls.Clear();
Init();
}
void Release(void)
{
delete this;
}
bool Compute(const float* const points,
const uint32_t nPoints,
const uint32_t* const triangles,
const uint32_t nTriangles,
const Parameters& params);
bool Compute(const double* const points,
const uint32_t nPoints,
const uint32_t* const triangles,
const uint32_t nTriangles,
const Parameters& params);
bool OCLInit(void* const oclDevice,
IUserLogger* const logger = 0);
bool OCLRelease(IUserLogger* const logger = 0);
virtual bool ComputeCenterOfMass(double centerOfMass[3]) const;
private:
void SetCancel(bool cancel)
{
m_cancelMutex.Lock();
m_cancel = cancel;
m_cancelMutex.Unlock();
}
bool GetCancel()
{
m_cancelMutex.Lock();
bool cancel = m_cancel;
m_cancelMutex.Unlock();
return cancel;
}
void Update(const double stageProgress,
const double operationProgress,
const Parameters& params)
{
m_stageProgress = stageProgress;
m_operationProgress = operationProgress;
if (params.m_callback) {
params.m_callback->Update(m_overallProgress,
m_stageProgress,
m_operationProgress,
m_stage.c_str(),
m_operation.c_str());
}
}
void Init()
{
if (mRaycastMesh)
{
mRaycastMesh->release();
mRaycastMesh = nullptr;
}
memset(m_rot, 0, sizeof(double) * 9);
m_dim = 64;
m_volume = 0;
m_volumeCH0 = 0.0;
m_pset = 0;
m_overallProgress = 0.0;
m_stageProgress = 0.0;
m_operationProgress = 0.0;
m_stage = "";
m_operation = "";
m_barycenter[0] = m_barycenter[1] = m_barycenter[2] = 0.0;
m_rot[0][0] = m_rot[1][1] = m_rot[2][2] = 1.0;
SetCancel(false);
}
void ComputePrimitiveSet(const Parameters& params);
void ComputeACD(const Parameters& params);
void MergeConvexHulls(const Parameters& params);
void SimplifyConvexHull(Mesh* const ch, const size_t nvertices, const double minVolume);
void SimplifyConvexHulls(const Parameters& params);
void ComputeBestClippingPlane(const PrimitiveSet* inputPSet,
const double volume,
const SArray<Plane>& planes,
const Vec3<double>& preferredCuttingDirection,
const double w,
const double alpha,
const double beta,
const int32_t convexhullDownsampling,
const double progress0,
const double progress1,
Plane& bestPlane,
double& minConcavity,
const Parameters& params);
template <class T>
void AlignMesh(const T* const points,
const uint32_t stridePoints,
const uint32_t nPoints,
const int32_t* const triangles,
const uint32_t strideTriangles,
const uint32_t nTriangles,
const Parameters& params)
{
if (GetCancel() || !params.m_pca) {
return;
}
m_timer.Tic();
m_stage = "Align mesh";
m_operation = "Voxelization";
std::ostringstream msg;
if (params.m_logger) {
msg << "+ " << m_stage << std::endl;
params.m_logger->Log(msg.str().c_str());
}
Update(0.0, 0.0, params);
if (GetCancel()) {
return;
}
m_dim = (size_t)(pow((double)params.m_resolution, 1.0 / 3.0) + 0.5);
Volume volume;
volume.Voxelize(points, stridePoints, nPoints,
triangles, strideTriangles, nTriangles,
m_dim, m_barycenter, m_rot);
size_t n = volume.GetNPrimitivesOnSurf() + volume.GetNPrimitivesInsideSurf();
Update(50.0, 100.0, params);
if (params.m_logger) {
msg.str("");
msg << "\t dim = " << m_dim << "\t-> " << n << " voxels" << std::endl;
params.m_logger->Log(msg.str().c_str());
}
if (GetCancel()) {
return;
}
m_operation = "PCA";
Update(50.0, 0.0, params);
volume.AlignToPrincipalAxes(m_rot);
m_overallProgress = 1.0;
Update(100.0, 100.0, params);
m_timer.Toc();
if (params.m_logger) {
msg.str("");
msg << "\t time " << m_timer.GetElapsedTime() / 1000.0 << "s" << std::endl;
params.m_logger->Log(msg.str().c_str());
}
}
template <class T>
void VoxelizeMesh(const T* const points,
const uint32_t stridePoints,
const uint32_t nPoints,
const int32_t* const triangles,
const uint32_t strideTriangles,
const uint32_t nTriangles,
const Parameters& params)
{
if (GetCancel()) {
return;
}
m_timer.Tic();
m_stage = "Voxelization";
std::ostringstream msg;
if (params.m_logger) {
msg << "+ " << m_stage << std::endl;
params.m_logger->Log(msg.str().c_str());
}
delete m_volume;
m_volume = 0;
int32_t iteration = 0;
const int32_t maxIteration = 5;
double progress = 0.0;
while (iteration++ < maxIteration && !m_cancel) {
msg.str("");
msg << "Iteration " << iteration;
m_operation = msg.str();
progress = iteration * 100.0 / maxIteration;
Update(progress, 0.0, params);
m_volume = new Volume;
m_volume->Voxelize(points, stridePoints, nPoints,
triangles, strideTriangles, nTriangles,
m_dim, m_barycenter, m_rot);
Update(progress, 100.0, params);
size_t n = m_volume->GetNPrimitivesOnSurf() + m_volume->GetNPrimitivesInsideSurf();
if (params.m_logger) {
msg.str("");
msg << "\t dim = " << m_dim << "\t-> " << n << " voxels" << std::endl;
params.m_logger->Log(msg.str().c_str());
}
double a = pow((double)(params.m_resolution) / n, 0.33);
size_t dim_next = (size_t)(m_dim * a + 0.5);
if (n < params.m_resolution && iteration < maxIteration && m_volume->GetNPrimitivesOnSurf() < params.m_resolution / 8 && m_dim != dim_next) {
delete m_volume;
m_volume = 0;
m_dim = dim_next;
}
else {
break;
}
}
m_overallProgress = 10.0;
Update(100.0, 100.0, params);
m_timer.Toc();
if (params.m_logger) {
msg.str("");
msg << "\t time " << m_timer.GetElapsedTime() / 1000.0 << "s" << std::endl;
params.m_logger->Log(msg.str().c_str());
}
}
template <class T>
bool ComputeACD(const T* const points,
const uint32_t nPoints,
const uint32_t* const triangles,
const uint32_t nTriangles,
const Parameters& params)
{
Init();
if (params.m_projectHullVertices)
{
mRaycastMesh = RaycastMesh::createRaycastMesh(nPoints, points, nTriangles, (const uint32_t *)triangles);
}
if (params.m_oclAcceleration) {
// build kernels
}
AlignMesh(points, 3, nPoints, (int32_t *)triangles, 3, nTriangles, params);
VoxelizeMesh(points, 3, nPoints, (int32_t *)triangles, 3, nTriangles, params);
ComputePrimitiveSet(params);
ComputeACD(params);
MergeConvexHulls(params);
SimplifyConvexHulls(params);
if (params.m_oclAcceleration) {
// Release kernels
}
if (GetCancel()) {
Clean();
return false;
}
return true;
}
private:
RaycastMesh *mRaycastMesh{ nullptr };
SArray<Mesh*> m_convexHulls;
std::string m_stage;
std::string m_operation;
double m_overallProgress;
double m_stageProgress;
double m_operationProgress;
double m_rot[3][3];
double m_volumeCH0;
Vec3<double> m_barycenter;
Timer m_timer;
size_t m_dim;
Volume* m_volume;
PrimitiveSet* m_pset;
Mutex m_cancelMutex;
bool m_cancel;
int32_t m_ompNumProcessors;
#ifdef CL_VERSION_1_1
cl_device_id* m_oclDevice;
cl_context m_oclContext;
cl_program m_oclProgram;
cl_command_queue* m_oclQueue;
cl_kernel* m_oclKernelComputePartialVolumes;
cl_kernel* m_oclKernelComputeSum;
size_t m_oclWorkGroupSize;
#endif //CL_VERSION_1_1
};
}
#endif // VHACD_VHACD_H

168
thirdparty/vhacd/inc/vhacdVector.h vendored Normal file
View file

@ -0,0 +1,168 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_VECTOR_H
#define VHACD_VECTOR_H
#include <iostream>
#include <math.h>
namespace VHACD {
//! Vector dim 3.
template <typename T>
class Vec3 {
public:
T& operator[](size_t i) { return m_data[i]; }
const T& operator[](size_t i) const { return m_data[i]; }
T& X();
T& Y();
T& Z();
const T& X() const;
const T& Y() const;
const T& Z() const;
void Normalize();
T GetNorm() const;
void operator=(const Vec3& rhs);
void operator+=(const Vec3& rhs);
void operator-=(const Vec3& rhs);
void operator-=(T a);
void operator+=(T a);
void operator/=(T a);
void operator*=(T a);
Vec3 operator^(const Vec3& rhs) const;
T operator*(const Vec3& rhs) const;
Vec3 operator+(const Vec3& rhs) const;
Vec3 operator-(const Vec3& rhs) const;
Vec3 operator-() const;
Vec3 operator*(T rhs) const;
Vec3 operator/(T rhs) const;
bool operator<(const Vec3& rhs) const;
bool operator>(const Vec3& rhs) const;
Vec3();
Vec3(T a);
Vec3(T x, T y, T z);
Vec3(const Vec3& rhs);
/*virtual*/ ~Vec3(void);
// Compute the center of this bounding box and return the diagonal length
T GetCenter(const Vec3 &bmin, const Vec3 &bmax)
{
X() = (bmin.X() + bmax.X())*0.5;
Y() = (bmin.Y() + bmax.Y())*0.5;
Z() = (bmin.Z() + bmax.Z())*0.5;
T dx = bmax.X() - bmin.X();
T dy = bmax.Y() - bmin.Y();
T dz = bmax.Z() - bmin.Z();
T diagonal = T(sqrt(dx*dx + dy*dy + dz*dz));
return diagonal;
}
// Update the min/max values relative to this point
void UpdateMinMax(Vec3 &bmin,Vec3 &bmax) const
{
if (X() < bmin.X())
{
bmin.X() = X();
}
if (Y() < bmin.Y())
{
bmin.Y() = Y();
}
if (Z() < bmin.Z())
{
bmin.Z() = Z();
}
if (X() > bmax.X())
{
bmax.X() = X();
}
if (X() > bmax.X())
{
bmax.X() = X();
}
if (Y() > bmax.Y())
{
bmax.Y() = Y();
}
if (Z() > bmax.Z())
{
bmax.Z() = Z();
}
}
// Returns the squared distance between these two points
T GetDistanceSquared(const Vec3 &p) const
{
T dx = X() - p.X();
T dy = Y() - p.Y();
T dz = Z() - p.Z();
return dx*dx + dy*dy + dz*dz;
}
T GetDistance(const Vec3 &p) const
{
return sqrt(GetDistanceSquared(p));
}
// Returns the raw vector data as a pointer
T* GetData(void)
{
return m_data;
}
private:
T m_data[3];
};
//! Vector dim 2.
template <typename T>
class Vec2 {
public:
T& operator[](size_t i) { return m_data[i]; }
const T& operator[](size_t i) const { return m_data[i]; }
T& X();
T& Y();
const T& X() const;
const T& Y() const;
void Normalize();
T GetNorm() const;
void operator=(const Vec2& rhs);
void operator+=(const Vec2& rhs);
void operator-=(const Vec2& rhs);
void operator-=(T a);
void operator+=(T a);
void operator/=(T a);
void operator*=(T a);
T operator^(const Vec2& rhs) const;
T operator*(const Vec2& rhs) const;
Vec2 operator+(const Vec2& rhs) const;
Vec2 operator-(const Vec2& rhs) const;
Vec2 operator-() const;
Vec2 operator*(T rhs) const;
Vec2 operator/(T rhs) const;
Vec2();
Vec2(T a);
Vec2(T x, T y);
Vec2(const Vec2& rhs);
/*virtual*/ ~Vec2(void);
private:
T m_data[2];
};
template <typename T>
const bool Colinear(const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c);
template <typename T>
const T ComputeVolume4(const Vec3<T>& a, const Vec3<T>& b, const Vec3<T>& c, const Vec3<T>& d);
}
#include "vhacdVector.inl" // template implementation
#endif

362
thirdparty/vhacd/inc/vhacdVector.inl vendored Normal file
View file

@ -0,0 +1,362 @@
#pragma once
#ifndef VHACD_VECTOR_INL
#define VHACD_VECTOR_INL
namespace VHACD
{
template <typename T>
inline Vec3<T> operator*(T lhs, const Vec3<T> & rhs)
{
return Vec3<T>(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z());
}
template <typename T>
inline T & Vec3<T>::X()
{
return m_data[0];
}
template <typename T>
inline T & Vec3<T>::Y()
{
return m_data[1];
}
template <typename T>
inline T & Vec3<T>::Z()
{
return m_data[2];
}
template <typename T>
inline const T & Vec3<T>::X() const
{
return m_data[0];
}
template <typename T>
inline const T & Vec3<T>::Y() const
{
return m_data[1];
}
template <typename T>
inline const T & Vec3<T>::Z() const
{
return m_data[2];
}
template <typename T>
inline void Vec3<T>::Normalize()
{
T n = sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
if (n != 0.0) (*this) /= n;
}
template <typename T>
inline T Vec3<T>::GetNorm() const
{
return sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]+m_data[2]*m_data[2]);
}
template <typename T>
inline void Vec3<T>::operator= (const Vec3 & rhs)
{
this->m_data[0] = rhs.m_data[0];
this->m_data[1] = rhs.m_data[1];
this->m_data[2] = rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator+=(const Vec3 & rhs)
{
this->m_data[0] += rhs.m_data[0];
this->m_data[1] += rhs.m_data[1];
this->m_data[2] += rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(const Vec3 & rhs)
{
this->m_data[0] -= rhs.m_data[0];
this->m_data[1] -= rhs.m_data[1];
this->m_data[2] -= rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(T a)
{
this->m_data[0] -= a;
this->m_data[1] -= a;
this->m_data[2] -= a;
}
template <typename T>
inline void Vec3<T>::operator+=(T a)
{
this->m_data[0] += a;
this->m_data[1] += a;
this->m_data[2] += a;
}
template <typename T>
inline void Vec3<T>::operator/=(T a)
{
this->m_data[0] /= a;
this->m_data[1] /= a;
this->m_data[2] /= a;
}
template <typename T>
inline void Vec3<T>::operator*=(T a)
{
this->m_data[0] *= a;
this->m_data[1] *= a;
this->m_data[2] *= a;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator^ (const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1],
m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2],
m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]);
}
template <typename T>
inline T Vec3<T>::operator*(const Vec3<T> & rhs) const
{
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator+(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]) ;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-() const
{
return Vec3<T>(-m_data[0],-m_data[1],-m_data[2]) ;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator*(T rhs) const
{
return Vec3<T>(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator/ (T rhs) const
{
return Vec3<T>(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs);
}
template <typename T>
inline Vec3<T>::Vec3(T a)
{
m_data[0] = m_data[1] = m_data[2] = a;
}
template <typename T>
inline Vec3<T>::Vec3(T x, T y, T z)
{
m_data[0] = x;
m_data[1] = y;
m_data[2] = z;
}
template <typename T>
inline Vec3<T>::Vec3(const Vec3 & rhs)
{
m_data[0] = rhs.m_data[0];
m_data[1] = rhs.m_data[1];
m_data[2] = rhs.m_data[2];
}
template <typename T>
inline Vec3<T>::~Vec3(void){};
template <typename T>
inline Vec3<T>::Vec3() {}
template<typename T>
inline const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c)
{
return ((c.Z() - a.Z()) * (b.Y() - a.Y()) - (b.Z() - a.Z()) * (c.Y() - a.Y()) == 0.0 /*EPS*/) &&
((b.Z() - a.Z()) * (c.X() - a.X()) - (b.X() - a.X()) * (c.Z() - a.Z()) == 0.0 /*EPS*/) &&
((b.X() - a.X()) * (c.Y() - a.Y()) - (b.Y() - a.Y()) * (c.X() - a.X()) == 0.0 /*EPS*/);
}
template<typename T>
inline const T ComputeVolume4(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d)
{
return (a-d) * ((b-d) ^ (c-d));
}
template <typename T>
inline bool Vec3<T>::operator<(const Vec3 & rhs) const
{
if (X() == rhs[0])
{
if (Y() == rhs[1])
{
return (Z()<rhs[2]);
}
return (Y()<rhs[1]);
}
return (X()<rhs[0]);
}
template <typename T>
inline bool Vec3<T>::operator>(const Vec3 & rhs) const
{
if (X() == rhs[0])
{
if (Y() == rhs[1])
{
return (Z()>rhs[2]);
}
return (Y()>rhs[1]);
}
return (X()>rhs[0]);
}
template <typename T>
inline Vec2<T> operator*(T lhs, const Vec2<T> & rhs)
{
return Vec2<T>(lhs * rhs.X(), lhs * rhs.Y());
}
template <typename T>
inline T & Vec2<T>::X()
{
return m_data[0];
}
template <typename T>
inline T & Vec2<T>::Y()
{
return m_data[1];
}
template <typename T>
inline const T & Vec2<T>::X() const
{
return m_data[0];
}
template <typename T>
inline const T & Vec2<T>::Y() const
{
return m_data[1];
}
template <typename T>
inline void Vec2<T>::Normalize()
{
T n = sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]);
if (n != 0.0) (*this) /= n;
}
template <typename T>
inline T Vec2<T>::GetNorm() const
{
return sqrt(m_data[0]*m_data[0]+m_data[1]*m_data[1]);
}
template <typename T>
inline void Vec2<T>::operator= (const Vec2 & rhs)
{
this->m_data[0] = rhs.m_data[0];
this->m_data[1] = rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator+=(const Vec2 & rhs)
{
this->m_data[0] += rhs.m_data[0];
this->m_data[1] += rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator-=(const Vec2 & rhs)
{
this->m_data[0] -= rhs.m_data[0];
this->m_data[1] -= rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator-=(T a)
{
this->m_data[0] -= a;
this->m_data[1] -= a;
}
template <typename T>
inline void Vec2<T>::operator+=(T a)
{
this->m_data[0] += a;
this->m_data[1] += a;
}
template <typename T>
inline void Vec2<T>::operator/=(T a)
{
this->m_data[0] /= a;
this->m_data[1] /= a;
}
template <typename T>
inline void Vec2<T>::operator*=(T a)
{
this->m_data[0] *= a;
this->m_data[1] *= a;
}
template <typename T>
inline T Vec2<T>::operator^ (const Vec2<T> & rhs) const
{
return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0];
}
template <typename T>
inline T Vec2<T>::operator*(const Vec2<T> & rhs) const
{
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator+(const Vec2<T> & rhs) const
{
return Vec2<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator-(const Vec2<T> & rhs) const
{
return Vec2<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator-() const
{
return Vec2<T>(-m_data[0],-m_data[1]) ;
}
template <typename T>
inline Vec2<T> Vec2<T>::operator*(T rhs) const
{
return Vec2<T>(rhs * this->m_data[0], rhs * this->m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator/ (T rhs) const
{
return Vec2<T>(m_data[0] / rhs, m_data[1] / rhs);
}
template <typename T>
inline Vec2<T>::Vec2(T a)
{
m_data[0] = m_data[1] = a;
}
template <typename T>
inline Vec2<T>::Vec2(T x, T y)
{
m_data[0] = x;
m_data[1] = y;
}
template <typename T>
inline Vec2<T>::Vec2(const Vec2 & rhs)
{
m_data[0] = rhs.m_data[0];
m_data[1] = rhs.m_data[1];
}
template <typename T>
inline Vec2<T>::~Vec2(void){};
template <typename T>
inline Vec2<T>::Vec2() {}
/*
InsideTriangle decides if a point P is Inside of the triangle
defined by A, B, C.
*/
template<typename T>
inline const bool InsideTriangle(const Vec2<T> & a, const Vec2<T> & b, const Vec2<T> & c, const Vec2<T> & p)
{
T ax, ay, bx, by, cx, cy, apx, apy, bpx, bpy, cpx, cpy;
T cCROSSap, bCROSScp, aCROSSbp;
ax = c.X() - b.X(); ay = c.Y() - b.Y();
bx = a.X() - c.X(); by = a.Y() - c.Y();
cx = b.X() - a.X(); cy = b.Y() - a.Y();
apx= p.X() - a.X(); apy= p.Y() - a.Y();
bpx= p.X() - b.X(); bpy= p.Y() - b.Y();
cpx= p.X() - c.X(); cpy= p.Y() - c.Y();
aCROSSbp = ax*bpy - ay*bpx;
cCROSSap = cx*apy - cy*apx;
bCROSScp = bx*cpy - by*cpx;
return ((aCROSSbp >= 0.0) && (bCROSScp >= 0.0) && (cCROSSap >= 0.0));
}
}
#endif //VHACD_VECTOR_INL

430
thirdparty/vhacd/inc/vhacdVolume.h vendored Normal file
View file

@ -0,0 +1,430 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_VOLUME_H
#define VHACD_VOLUME_H
#include "vhacdMesh.h"
#include "vhacdVector.h"
#include <assert.h>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4456 4701)
#endif
namespace VHACD {
enum VOXEL_VALUE {
PRIMITIVE_UNDEFINED = 0,
PRIMITIVE_OUTSIDE_SURFACE = 1,
PRIMITIVE_INSIDE_SURFACE = 2,
PRIMITIVE_ON_SURFACE = 3
};
struct Voxel {
public:
short m_coord[3];
short m_data;
};
class PrimitiveSet {
public:
virtual ~PrimitiveSet(){};
virtual PrimitiveSet* Create() const = 0;
virtual const size_t GetNPrimitives() const = 0;
virtual const size_t GetNPrimitivesOnSurf() const = 0;
virtual const size_t GetNPrimitivesInsideSurf() const = 0;
virtual const double GetEigenValue(AXIS axis) const = 0;
virtual const double ComputeMaxVolumeError() const = 0;
virtual const double ComputeVolume() const = 0;
virtual void Clip(const Plane& plane, PrimitiveSet* const positivePart,
PrimitiveSet* const negativePart) const = 0;
virtual void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
SArray<Vec3<double> >* const negativePts, const size_t sampling) const = 0;
virtual void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
SArray<Vec3<double> >* const exteriorPts) const = 0;
virtual void ComputeClippedVolumes(const Plane& plane, double& positiveVolume,
double& negativeVolume) const = 0;
virtual void SelectOnSurface(PrimitiveSet* const onSurfP) const = 0;
virtual void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const = 0;
virtual void ComputeBB() = 0;
virtual void ComputePrincipalAxes() = 0;
virtual void AlignToPrincipalAxes() = 0;
virtual void RevertAlignToPrincipalAxes() = 0;
virtual void Convert(Mesh& mesh, const VOXEL_VALUE value) const = 0;
const Mesh& GetConvexHull() const { return m_convexHull; };
Mesh& GetConvexHull() { return m_convexHull; };
private:
Mesh m_convexHull;
};
//!
class VoxelSet : public PrimitiveSet {
friend class Volume;
public:
//! Destructor.
~VoxelSet(void);
//! Constructor.
VoxelSet();
const size_t GetNPrimitives() const { return m_voxels.Size(); }
const size_t GetNPrimitivesOnSurf() const { return m_numVoxelsOnSurface; }
const size_t GetNPrimitivesInsideSurf() const { return m_numVoxelsInsideSurface; }
const double GetEigenValue(AXIS axis) const { return m_D[axis][axis]; }
const double ComputeVolume() const { return m_unitVolume * m_voxels.Size(); }
const double ComputeMaxVolumeError() const { return m_unitVolume * m_numVoxelsOnSurface; }
const Vec3<short>& GetMinBBVoxels() const { return m_minBBVoxels; }
const Vec3<short>& GetMaxBBVoxels() const { return m_maxBBVoxels; }
const Vec3<double>& GetMinBB() const { return m_minBB; }
const double& GetScale() const { return m_scale; }
const double& GetUnitVolume() const { return m_unitVolume; }
Vec3<double> GetPoint(Vec3<short> voxel) const
{
return Vec3<double>(voxel[0] * m_scale + m_minBB[0],
voxel[1] * m_scale + m_minBB[1],
voxel[2] * m_scale + m_minBB[2]);
}
Vec3<double> GetPoint(const Voxel& voxel) const
{
return Vec3<double>(voxel.m_coord[0] * m_scale + m_minBB[0],
voxel.m_coord[1] * m_scale + m_minBB[1],
voxel.m_coord[2] * m_scale + m_minBB[2]);
}
Vec3<double> GetPoint(Vec3<double> voxel) const
{
return Vec3<double>(voxel[0] * m_scale + m_minBB[0],
voxel[1] * m_scale + m_minBB[1],
voxel[2] * m_scale + m_minBB[2]);
}
void GetPoints(const Voxel& voxel, Vec3<double>* const pts) const;
void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const;
void Clip(const Plane& plane, PrimitiveSet* const positivePart, PrimitiveSet* const negativePart) const;
void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
SArray<Vec3<double> >* const negativePts, const size_t sampling) const;
void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
SArray<Vec3<double> >* const exteriorPts) const;
void ComputeClippedVolumes(const Plane& plane, double& positiveVolume, double& negativeVolume) const;
void SelectOnSurface(PrimitiveSet* const onSurfP) const;
void ComputeBB();
void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
void ComputePrincipalAxes();
PrimitiveSet* Create() const
{
return new VoxelSet();
}
void AlignToPrincipalAxes(){};
void RevertAlignToPrincipalAxes(){};
Voxel* const GetVoxels() { return m_voxels.Data(); }
const Voxel* const GetVoxels() const { return m_voxels.Data(); }
private:
size_t m_numVoxelsOnSurface;
size_t m_numVoxelsInsideSurface;
Vec3<double> m_minBB;
double m_scale;
SArray<Voxel, 8> m_voxels;
double m_unitVolume;
Vec3<double> m_minBBPts;
Vec3<double> m_maxBBPts;
Vec3<short> m_minBBVoxels;
Vec3<short> m_maxBBVoxels;
Vec3<short> m_barycenter;
double m_Q[3][3];
double m_D[3][3];
Vec3<double> m_barycenterPCA;
};
struct Tetrahedron {
public:
Vec3<double> m_pts[4];
unsigned char m_data;
};
//!
class TetrahedronSet : public PrimitiveSet {
friend class Volume;
public:
//! Destructor.
~TetrahedronSet(void);
//! Constructor.
TetrahedronSet();
const size_t GetNPrimitives() const { return m_tetrahedra.Size(); }
const size_t GetNPrimitivesOnSurf() const { return m_numTetrahedraOnSurface; }
const size_t GetNPrimitivesInsideSurf() const { return m_numTetrahedraInsideSurface; }
const Vec3<double>& GetMinBB() const { return m_minBB; }
const Vec3<double>& GetMaxBB() const { return m_maxBB; }
const Vec3<double>& GetBarycenter() const { return m_barycenter; }
const double GetEigenValue(AXIS axis) const { return m_D[axis][axis]; }
const double GetSacle() const { return m_scale; }
const double ComputeVolume() const;
const double ComputeMaxVolumeError() const;
void ComputeConvexHull(Mesh& meshCH, const size_t sampling = 1) const;
void ComputePrincipalAxes();
void AlignToPrincipalAxes();
void RevertAlignToPrincipalAxes();
void Clip(const Plane& plane, PrimitiveSet* const positivePart, PrimitiveSet* const negativePart) const;
void Intersect(const Plane& plane, SArray<Vec3<double> >* const positivePts,
SArray<Vec3<double> >* const negativePts, const size_t sampling) const;
void ComputeExteriorPoints(const Plane& plane, const Mesh& mesh,
SArray<Vec3<double> >* const exteriorPts) const;
void ComputeClippedVolumes(const Plane& plane, double& positiveVolume, double& negativeVolume) const;
void SelectOnSurface(PrimitiveSet* const onSurfP) const;
void ComputeBB();
void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
inline bool Add(Tetrahedron& tetrahedron);
PrimitiveSet* Create() const
{
return new TetrahedronSet();
}
static const double EPS;
private:
void AddClippedTetrahedra(const Vec3<double> (&pts)[10], const int32_t nPts);
size_t m_numTetrahedraOnSurface;
size_t m_numTetrahedraInsideSurface;
double m_scale;
Vec3<double> m_minBB;
Vec3<double> m_maxBB;
Vec3<double> m_barycenter;
SArray<Tetrahedron, 8> m_tetrahedra;
double m_Q[3][3];
double m_D[3][3];
};
//!
class Volume {
public:
//! Destructor.
~Volume(void);
//! Constructor.
Volume();
//! Voxelize
template <class T>
void Voxelize(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
const int32_t* const triangles, const uint32_t strideTriangles, const uint32_t nTriangles,
const size_t dim, const Vec3<double>& barycenter, const double (&rot)[3][3]);
unsigned char& GetVoxel(const size_t i, const size_t j, const size_t k)
{
assert(i < m_dim[0] || i >= 0);
assert(j < m_dim[0] || j >= 0);
assert(k < m_dim[0] || k >= 0);
return m_data[i + j * m_dim[0] + k * m_dim[0] * m_dim[1]];
}
const unsigned char& GetVoxel(const size_t i, const size_t j, const size_t k) const
{
assert(i < m_dim[0] || i >= 0);
assert(j < m_dim[0] || j >= 0);
assert(k < m_dim[0] || k >= 0);
return m_data[i + j * m_dim[0] + k * m_dim[0] * m_dim[1]];
}
const size_t GetNPrimitivesOnSurf() const { return m_numVoxelsOnSurface; }
const size_t GetNPrimitivesInsideSurf() const { return m_numVoxelsInsideSurface; }
void Convert(Mesh& mesh, const VOXEL_VALUE value) const;
void Convert(VoxelSet& vset) const;
void Convert(TetrahedronSet& tset) const;
void AlignToPrincipalAxes(double (&rot)[3][3]) const;
private:
void FillOutsideSurface(const size_t i0, const size_t j0, const size_t k0, const size_t i1,
const size_t j1, const size_t k1);
void FillInsideSurface();
template <class T>
void ComputeBB(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
const Vec3<double>& barycenter, const double (&rot)[3][3]);
void Allocate();
void Free();
Vec3<double> m_minBB;
Vec3<double> m_maxBB;
double m_scale;
size_t m_dim[3]; //>! dim
size_t m_numVoxelsOnSurface;
size_t m_numVoxelsInsideSurface;
size_t m_numVoxelsOutsideSurface;
unsigned char* m_data;
};
int32_t TriBoxOverlap(const Vec3<double>& boxcenter, const Vec3<double>& boxhalfsize, const Vec3<double>& triver0,
const Vec3<double>& triver1, const Vec3<double>& triver2);
template <class T>
inline void ComputeAlignedPoint(const T* const points, const uint32_t idx, const Vec3<double>& barycenter,
const double (&rot)[3][3], Vec3<double>& pt){};
template <>
inline void ComputeAlignedPoint<float>(const float* const points, const uint32_t idx, const Vec3<double>& barycenter, const double (&rot)[3][3], Vec3<double>& pt)
{
double x = points[idx + 0] - barycenter[0];
double y = points[idx + 1] - barycenter[1];
double z = points[idx + 2] - barycenter[2];
pt[0] = rot[0][0] * x + rot[1][0] * y + rot[2][0] * z;
pt[1] = rot[0][1] * x + rot[1][1] * y + rot[2][1] * z;
pt[2] = rot[0][2] * x + rot[1][2] * y + rot[2][2] * z;
}
template <>
inline void ComputeAlignedPoint<double>(const double* const points, const uint32_t idx, const Vec3<double>& barycenter, const double (&rot)[3][3], Vec3<double>& pt)
{
double x = points[idx + 0] - barycenter[0];
double y = points[idx + 1] - barycenter[1];
double z = points[idx + 2] - barycenter[2];
pt[0] = rot[0][0] * x + rot[1][0] * y + rot[2][0] * z;
pt[1] = rot[0][1] * x + rot[1][1] * y + rot[2][1] * z;
pt[2] = rot[0][2] * x + rot[1][2] * y + rot[2][2] * z;
}
template <class T>
void Volume::ComputeBB(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
const Vec3<double>& barycenter, const double (&rot)[3][3])
{
Vec3<double> pt;
ComputeAlignedPoint(points, 0, barycenter, rot, pt);
m_maxBB = pt;
m_minBB = pt;
for (uint32_t v = 1; v < nPoints; ++v) {
ComputeAlignedPoint(points, v * stridePoints, barycenter, rot, pt);
for (int32_t i = 0; i < 3; ++i) {
if (pt[i] < m_minBB[i])
m_minBB[i] = pt[i];
else if (pt[i] > m_maxBB[i])
m_maxBB[i] = pt[i];
}
}
}
template <class T>
void Volume::Voxelize(const T* const points, const uint32_t stridePoints, const uint32_t nPoints,
const int32_t* const triangles, const uint32_t strideTriangles, const uint32_t nTriangles,
const size_t dim, const Vec3<double>& barycenter, const double (&rot)[3][3])
{
if (nPoints == 0) {
return;
}
ComputeBB(points, stridePoints, nPoints, barycenter, rot);
double d[3] = { m_maxBB[0] - m_minBB[0], m_maxBB[1] - m_minBB[1], m_maxBB[2] - m_minBB[2] };
double r;
if (d[0] > d[1] && d[0] > d[2]) {
r = d[0];
m_dim[0] = dim;
m_dim[1] = 2 + static_cast<size_t>(dim * d[1] / d[0]);
m_dim[2] = 2 + static_cast<size_t>(dim * d[2] / d[0]);
}
else if (d[1] > d[0] && d[1] > d[2]) {
r = d[1];
m_dim[1] = dim;
m_dim[0] = 2 + static_cast<size_t>(dim * d[0] / d[1]);
m_dim[2] = 2 + static_cast<size_t>(dim * d[2] / d[1]);
}
else {
r = d[2];
m_dim[2] = dim;
m_dim[0] = 2 + static_cast<size_t>(dim * d[0] / d[2]);
m_dim[1] = 2 + static_cast<size_t>(dim * d[1] / d[2]);
}
m_scale = r / (dim - 1);
double invScale = (dim - 1) / r;
Allocate();
m_numVoxelsOnSurface = 0;
m_numVoxelsInsideSurface = 0;
m_numVoxelsOutsideSurface = 0;
Vec3<double> p[3];
size_t i, j, k;
size_t i0, j0, k0;
size_t i1, j1, k1;
Vec3<double> boxcenter;
Vec3<double> pt;
const Vec3<double> boxhalfsize(0.5, 0.5, 0.5);
for (size_t t = 0, ti = 0; t < nTriangles; ++t, ti += strideTriangles) {
Vec3<int32_t> tri(triangles[ti + 0],
triangles[ti + 1],
triangles[ti + 2]);
for (int32_t c = 0; c < 3; ++c) {
ComputeAlignedPoint(points, tri[c] * stridePoints, barycenter, rot, pt);
p[c][0] = (pt[0] - m_minBB[0]) * invScale;
p[c][1] = (pt[1] - m_minBB[1]) * invScale;
p[c][2] = (pt[2] - m_minBB[2]) * invScale;
i = static_cast<size_t>(p[c][0] + 0.5);
j = static_cast<size_t>(p[c][1] + 0.5);
k = static_cast<size_t>(p[c][2] + 0.5);
assert(i < m_dim[0] && i >= 0 && j < m_dim[1] && j >= 0 && k < m_dim[2] && k >= 0);
if (c == 0) {
i0 = i1 = i;
j0 = j1 = j;
k0 = k1 = k;
}
else {
if (i < i0)
i0 = i;
if (j < j0)
j0 = j;
if (k < k0)
k0 = k;
if (i > i1)
i1 = i;
if (j > j1)
j1 = j;
if (k > k1)
k1 = k;
}
}
if (i0 > 0)
--i0;
if (j0 > 0)
--j0;
if (k0 > 0)
--k0;
if (i1 < m_dim[0])
++i1;
if (j1 < m_dim[1])
++j1;
if (k1 < m_dim[2])
++k1;
for (size_t i = i0; i < i1; ++i) {
boxcenter[0] = (double)i;
for (size_t j = j0; j < j1; ++j) {
boxcenter[1] = (double)j;
for (size_t k = k0; k < k1; ++k) {
boxcenter[2] = (double)k;
int32_t res = TriBoxOverlap(boxcenter, boxhalfsize, p[0], p[1], p[2]);
unsigned char& value = GetVoxel(i, j, k);
if (res == 1 && value == PRIMITIVE_UNDEFINED) {
value = PRIMITIVE_ON_SURFACE;
++m_numVoxelsOnSurface;
}
}
}
}
}
FillOutsideSurface(0, 0, 0, m_dim[0], m_dim[1], 1);
FillOutsideSurface(0, 0, m_dim[2] - 1, m_dim[0], m_dim[1], m_dim[2]);
FillOutsideSurface(0, 0, 0, m_dim[0], 1, m_dim[2]);
FillOutsideSurface(0, m_dim[1] - 1, 0, m_dim[0], m_dim[1], m_dim[2]);
FillOutsideSurface(0, 0, 0, 1, m_dim[1], m_dim[2]);
FillOutsideSurface(m_dim[0] - 1, 0, 0, m_dim[0], m_dim[1], m_dim[2]);
FillInsideSurface();
}
}
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // VHACD_VOLUME_H

153
thirdparty/vhacd/public/VHACD.h vendored Normal file
View file

@ -0,0 +1,153 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#ifndef VHACD_H
#define VHACD_H
#define VHACD_VERSION_MAJOR 2
#define VHACD_VERSION_MINOR 3
// Changes for version 2.3
//
// m_gamma : Has been removed. This used to control the error metric to merge convex hulls. Now it uses the 'm_maxConvexHulls' value instead.
// m_maxConvexHulls : This is the maximum number of convex hulls to produce from the merge operation; replaces 'm_gamma'.
//
// Note that decomposition depth is no longer a user provided value. It is now derived from the
// maximum number of hulls requested.
//
// As a convenience to the user, each convex hull produced now includes the volume of the hull as well as it's center.
//
// This version supports a convenience method to automatically make V-HACD run asynchronously in a background thread.
// To get a fully asynchronous version, call 'CreateVHACD_ASYNC' instead of 'CreateVHACD'. You get the same interface however,
// now when computing convex hulls, it is no longer a blocking operation. All callback messages are still returned
// in the application's thread so you don't need to worry about mutex locks or anything in that case.
// To tell if the operation is complete, the application should call 'IsReady'. This will return true if
// the last approximation operation is complete and will dispatch any pending messages.
// If you call 'Compute' while a previous operation was still running, it will automatically cancel the last request
// and begin a new one. To cancel a currently running approximation just call 'Cancel'.
#include <stdint.h>
namespace VHACD {
class IVHACD {
public:
class IUserCallback {
public:
virtual ~IUserCallback(){};
virtual void Update(const double overallProgress,
const double stageProgress,
const double operationProgress,
const char* const stage,
const char* const operation)
= 0;
};
class IUserLogger {
public:
virtual ~IUserLogger(){};
virtual void Log(const char* const msg) = 0;
};
class ConvexHull {
public:
double* m_points;
uint32_t* m_triangles;
uint32_t m_nPoints;
uint32_t m_nTriangles;
double m_volume;
double m_center[3];
};
class Parameters {
public:
Parameters(void) { Init(); }
void Init(void)
{
m_resolution = 100000;
m_concavity = 0.001;
m_planeDownsampling = 4;
m_convexhullDownsampling = 4;
m_alpha = 0.05;
m_beta = 0.05;
m_pca = 0;
m_mode = 0; // 0: voxel-based (recommended), 1: tetrahedron-based
m_maxNumVerticesPerCH = 64;
m_minVolumePerCH = 0.0001;
m_callback = 0;
m_logger = 0;
m_convexhullApproximation = true;
m_oclAcceleration = true;
m_maxConvexHulls = 1024;
m_projectHullVertices = true; // This will project the output convex hull vertices onto the original source mesh to increase the floating point accuracy of the results
}
double m_concavity;
double m_alpha;
double m_beta;
double m_minVolumePerCH;
IUserCallback* m_callback;
IUserLogger* m_logger;
uint32_t m_resolution;
uint32_t m_maxNumVerticesPerCH;
uint32_t m_planeDownsampling;
uint32_t m_convexhullDownsampling;
uint32_t m_pca;
uint32_t m_mode;
uint32_t m_convexhullApproximation;
uint32_t m_oclAcceleration;
uint32_t m_maxConvexHulls;
bool m_projectHullVertices;
};
virtual void Cancel() = 0;
virtual bool Compute(const float* const points,
const uint32_t countPoints,
const uint32_t* const triangles,
const uint32_t countTriangles,
const Parameters& params)
= 0;
virtual bool Compute(const double* const points,
const uint32_t countPoints,
const uint32_t* const triangles,
const uint32_t countTriangles,
const Parameters& params)
= 0;
virtual uint32_t GetNConvexHulls() const = 0;
virtual void GetConvexHull(const uint32_t index, ConvexHull& ch) const = 0;
virtual void Clean(void) = 0; // release internally allocated memory
virtual void Release(void) = 0; // release IVHACD
virtual bool OCLInit(void* const oclDevice,
IUserLogger* const logger = 0)
= 0;
virtual bool OCLRelease(IUserLogger* const logger = 0) = 0;
// Will compute the center of mass of the convex hull decomposition results and return it
// in 'centerOfMass'. Returns false if the center of mass could not be computed.
virtual bool ComputeCenterOfMass(double centerOfMass[3]) const = 0;
// In synchronous mode (non-multi-threaded) the state is always 'ready'
// In asynchronous mode, this returns true if the background thread is not still actively computing
// a new solution. In an asynchronous config the 'IsReady' call will report any update or log
// messages in the caller's current thread.
virtual bool IsReady(void) const
{
return true;
}
protected:
virtual ~IVHACD(void) {}
};
IVHACD* CreateVHACD(void);
IVHACD* CreateVHACD_ASYNC(void);
}
#endif // VHACD_H

17
thirdparty/vhacd/src/FloatMath.cpp vendored Normal file
View file

@ -0,0 +1,17 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include "FloatMath.h"
#include <vector>
#define REAL float
#include "FloatMath.inl"
#undef REAL
#define REAL double
#include "FloatMath.inl"

5276
thirdparty/vhacd/src/FloatMath.inl vendored Normal file

File diff suppressed because it is too large Load diff

334
thirdparty/vhacd/src/VHACD-ASYNC.cpp vendored Normal file
View file

@ -0,0 +1,334 @@
#include "../public/VHACD.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <thread>
#include <atomic>
#include <mutex>
#include <string>
#include <float.h>
#define ENABLE_ASYNC 1
#define HACD_ALLOC(x) malloc(x)
#define HACD_FREE(x) free(x)
#define HACD_ASSERT(x) assert(x)
namespace VHACD
{
class MyHACD_API : public VHACD::IVHACD, public VHACD::IVHACD::IUserCallback, VHACD::IVHACD::IUserLogger
{
public:
MyHACD_API(void)
{
mVHACD = VHACD::CreateVHACD();
}
virtual ~MyHACD_API(void)
{
releaseHACD();
Cancel();
mVHACD->Release();
}
virtual bool Compute(const double* const _points,
const uint32_t countPoints,
const uint32_t* const _triangles,
const uint32_t countTriangles,
const Parameters& _desc) final
{
#if ENABLE_ASYNC
Cancel(); // if we previously had a solution running; cancel it.
releaseHACD();
// We need to copy the input vertices and triangles into our own buffers so we can operate
// on them safely from the background thread.
mVertices = (double *)HACD_ALLOC(sizeof(double)*countPoints * 3);
mIndices = (uint32_t *)HACD_ALLOC(sizeof(uint32_t)*countTriangles * 3);
memcpy(mVertices, _points, sizeof(double)*countPoints * 3);
memcpy(mIndices, _triangles, sizeof(uint32_t)*countTriangles * 3);
mRunning = true;
mThread = new std::thread([this, countPoints, countTriangles, _desc]()
{
ComputeNow(mVertices, countPoints, mIndices, countTriangles, _desc);
mRunning = false;
});
#else
releaseHACD();
ComputeNow(_points, countPoints, _triangles, countTriangles, _desc);
#endif
return true;
}
bool ComputeNow(const double* const points,
const uint32_t countPoints,
const uint32_t* const triangles,
const uint32_t countTriangles,
const Parameters& _desc)
{
uint32_t ret = 0;
mHullCount = 0;
mCallback = _desc.m_callback;
mLogger = _desc.m_logger;
IVHACD::Parameters desc = _desc;
// Set our intercepting callback interfaces if non-null
desc.m_callback = desc.m_callback ? this : nullptr;
desc.m_logger = desc.m_logger ? this : nullptr;
if ( countPoints )
{
bool ok = mVHACD->Compute(points, countPoints, triangles, countTriangles, desc);
if (ok)
{
ret = mVHACD->GetNConvexHulls();
mHulls = new IVHACD::ConvexHull[ret];
for (uint32_t i = 0; i < ret; i++)
{
VHACD::IVHACD::ConvexHull vhull;
mVHACD->GetConvexHull(i, vhull);
VHACD::IVHACD::ConvexHull h;
h.m_nPoints = vhull.m_nPoints;
h.m_points = (double *)HACD_ALLOC(sizeof(double) * 3 * h.m_nPoints);
memcpy(h.m_points, vhull.m_points, sizeof(double) * 3 * h.m_nPoints);
h.m_nTriangles = vhull.m_nTriangles;
h.m_triangles = (uint32_t *)HACD_ALLOC(sizeof(uint32_t) * 3 * h.m_nTriangles);
memcpy(h.m_triangles, vhull.m_triangles, sizeof(uint32_t) * 3 * h.m_nTriangles);
h.m_volume = vhull.m_volume;
h.m_center[0] = vhull.m_center[0];
h.m_center[1] = vhull.m_center[1];
h.m_center[2] = vhull.m_center[2];
mHulls[i] = h;
if (mCancel)
{
ret = 0;
break;
}
}
}
}
mHullCount = ret;
return ret ? true : false;
}
void releaseHull(VHACD::IVHACD::ConvexHull &h)
{
HACD_FREE((void *)h.m_triangles);
HACD_FREE((void *)h.m_points);
h.m_triangles = nullptr;
h.m_points = nullptr;
}
virtual void GetConvexHull(const uint32_t index, VHACD::IVHACD::ConvexHull& ch) const final
{
if ( index < mHullCount )
{
ch = mHulls[index];
}
}
void releaseHACD(void) // release memory associated with the last HACD request
{
for (uint32_t i=0; i<mHullCount; i++)
{
releaseHull(mHulls[i]);
}
delete[]mHulls;
mHulls = nullptr;
mHullCount = 0;
HACD_FREE(mVertices);
mVertices = nullptr;
HACD_FREE(mIndices);
mIndices = nullptr;
}
virtual void release(void) // release the HACD_API interface
{
delete this;
}
virtual uint32_t getHullCount(void)
{
return mHullCount;
}
virtual void Cancel() final
{
if (mRunning)
{
mVHACD->Cancel(); // Set the cancel signal to the base VHACD
}
if (mThread)
{
mThread->join(); // Wait for the thread to fully exit before we delete the instance
delete mThread;
mThread = nullptr;
Log("Convex Decomposition thread canceled\n");
}
mCancel = false; // clear the cancel semaphore
}
virtual bool Compute(const float* const points,
const uint32_t countPoints,
const uint32_t* const triangles,
const uint32_t countTriangles,
const Parameters& params) final
{
double *vertices = (double *)HACD_ALLOC(sizeof(double)*countPoints * 3);
const float *source = points;
double *dest = vertices;
for (uint32_t i = 0; i < countPoints; i++)
{
dest[0] = source[0];
dest[1] = source[1];
dest[2] = source[2];
dest += 3;
source += 3;
}
bool ret = Compute(vertices, countPoints, triangles, countTriangles, params);
HACD_FREE(vertices);
return ret;
}
virtual uint32_t GetNConvexHulls() const final
{
processPendingMessages();
return mHullCount;
}
virtual void Clean(void) final // release internally allocated memory
{
Cancel();
releaseHACD();
mVHACD->Clean();
}
virtual void Release(void) final // release IVHACD
{
delete this;
}
virtual bool OCLInit(void* const oclDevice,
IVHACD::IUserLogger* const logger = 0) final
{
return mVHACD->OCLInit(oclDevice, logger);
}
virtual bool OCLRelease(IVHACD::IUserLogger* const logger = 0) final
{
return mVHACD->OCLRelease(logger);
}
virtual void Update(const double overallProgress,
const double stageProgress,
const double operationProgress,
const char* const stage,
const char* const operation) final
{
mMessageMutex.lock();
mHaveUpdateMessage = true;
mOverallProgress = overallProgress;
mStageProgress = stageProgress;
mOperationProgress = operationProgress;
mStage = std::string(stage);
mOperation = std::string(operation);
mMessageMutex.unlock();
}
virtual void Log(const char* const msg) final
{
mMessageMutex.lock();
mHaveLogMessage = true;
mMessage = std::string(msg);
mMessageMutex.unlock();
}
virtual bool IsReady(void) const final
{
processPendingMessages();
return !mRunning;
}
// As a convenience for the calling application we only send it update and log messages from it's own main
// thread. This reduces the complexity burden on the caller by making sure it only has to deal with log
// messages in it's main application thread.
void processPendingMessages(void) const
{
// If we have a new update message and the user has specified a callback we send the message and clear the semaphore
if (mHaveUpdateMessage && mCallback)
{
mMessageMutex.lock();
mCallback->Update(mOverallProgress, mStageProgress, mOperationProgress, mStage.c_str(), mOperation.c_str());
mHaveUpdateMessage = false;
mMessageMutex.unlock();
}
// If we have a new log message and the user has specified a callback we send the message and clear the semaphore
if (mHaveLogMessage && mLogger)
{
mMessageMutex.lock();
mLogger->Log(mMessage.c_str());
mHaveLogMessage = false;
mMessageMutex.unlock();
}
}
// Will compute the center of mass of the convex hull decomposition results and return it
// in 'centerOfMass'. Returns false if the center of mass could not be computed.
virtual bool ComputeCenterOfMass(double centerOfMass[3]) const
{
bool ret = false;
centerOfMass[0] = 0;
centerOfMass[1] = 0;
centerOfMass[2] = 0;
if (mVHACD && IsReady() )
{
ret = mVHACD->ComputeCenterOfMass(centerOfMass);
}
return ret;
}
private:
double *mVertices{ nullptr };
uint32_t *mIndices{ nullptr };
std::atomic< uint32_t> mHullCount{ 0 };
VHACD::IVHACD::ConvexHull *mHulls{ nullptr };
VHACD::IVHACD::IUserCallback *mCallback{ nullptr };
VHACD::IVHACD::IUserLogger *mLogger{ nullptr };
VHACD::IVHACD *mVHACD{ nullptr };
std::thread *mThread{ nullptr };
std::atomic< bool > mRunning{ false };
std::atomic<bool> mCancel{ false };
// Thread safe caching mechanism for messages and update status.
// This is so that caller always gets messages in his own thread
// Member variables are marked as 'mutable' since the message dispatch function
// is called from const query methods.
mutable std::mutex mMessageMutex;
mutable std::atomic< bool > mHaveUpdateMessage{ false };
mutable std::atomic< bool > mHaveLogMessage{ false };
mutable double mOverallProgress{ 0 };
mutable double mStageProgress{ 0 };
mutable double mOperationProgress{ 0 };
mutable std::string mStage;
mutable std::string mOperation;
mutable std::string mMessage;
};
IVHACD* CreateVHACD_ASYNC(void)
{
MyHACD_API *m = new MyHACD_API;
return static_cast<IVHACD *>(m);
}
}; // end of VHACD namespace

1589
thirdparty/vhacd/src/VHACD.cpp vendored Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,171 @@
/*
Bullet Continuous Collision Detection and Physics Library
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it freely,
subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "btAlignedAllocator.h"
//GODOT ADDITION
namespace VHACD {
//
#ifdef _MSC_VER
#pragma warning(disable : 4311 4302)
#endif
int32_t gNumAlignedAllocs = 0;
int32_t gNumAlignedFree = 0;
int32_t gTotalBytesAlignedAllocs = 0; //detect memory leaks
static void *btAllocDefault(size_t size) {
return malloc(size);
}
static void btFreeDefault(void *ptr) {
free(ptr);
}
static btAllocFunc *sAllocFunc = btAllocDefault;
static btFreeFunc *sFreeFunc = btFreeDefault;
#if defined(BT_HAS_ALIGNED_ALLOCATOR)
#include <malloc.h>
static void *btAlignedAllocDefault(size_t size, int32_t alignment) {
return _aligned_malloc(size, (size_t)alignment);
}
static void btAlignedFreeDefault(void *ptr) {
_aligned_free(ptr);
}
#elif defined(__CELLOS_LV2__)
#include <stdlib.h>
static inline void *btAlignedAllocDefault(size_t size, int32_t alignment) {
return memalign(alignment, size);
}
static inline void btAlignedFreeDefault(void *ptr) {
free(ptr);
}
#else
static inline void *btAlignedAllocDefault(size_t size, int32_t alignment) {
void *ret;
char *real;
unsigned long offset;
real = (char *)sAllocFunc(size + sizeof(void *) + (alignment - 1));
if (real) {
offset = (alignment - (unsigned long)(real + sizeof(void *))) & (alignment - 1);
ret = (void *)((real + sizeof(void *)) + offset);
*((void **)(ret)-1) = (void *)(real);
} else {
ret = (void *)(real);
}
return (ret);
}
static inline void btAlignedFreeDefault(void *ptr) {
void *real;
if (ptr) {
real = *((void **)(ptr)-1);
sFreeFunc(real);
}
}
#endif
static btAlignedAllocFunc *sAlignedAllocFunc = btAlignedAllocDefault;
static btAlignedFreeFunc *sAlignedFreeFunc = btAlignedFreeDefault;
void btAlignedAllocSetCustomAligned(btAlignedAllocFunc *allocFunc, btAlignedFreeFunc *freeFunc) {
sAlignedAllocFunc = allocFunc ? allocFunc : btAlignedAllocDefault;
sAlignedFreeFunc = freeFunc ? freeFunc : btAlignedFreeDefault;
}
void btAlignedAllocSetCustom(btAllocFunc *allocFunc, btFreeFunc *freeFunc) {
sAllocFunc = allocFunc ? allocFunc : btAllocDefault;
sFreeFunc = freeFunc ? freeFunc : btFreeDefault;
}
#ifdef BT_DEBUG_MEMORY_ALLOCATIONS
//this generic allocator provides the total allocated number of bytes
#include <stdio.h>
void *btAlignedAllocInternal(size_t size, int32_t alignment, int32_t line, char *filename) {
void *ret;
char *real;
unsigned long offset;
gTotalBytesAlignedAllocs += size;
gNumAlignedAllocs++;
real = (char *)sAllocFunc(size + 2 * sizeof(void *) + (alignment - 1));
if (real) {
offset = (alignment - (unsigned long)(real + 2 * sizeof(void *))) & (alignment - 1);
ret = (void *)((real + 2 * sizeof(void *)) + offset);
*((void **)(ret)-1) = (void *)(real);
*((int32_t *)(ret)-2) = size;
} else {
ret = (void *)(real); //??
}
printf("allocation#%d at address %x, from %s,line %d, size %d\n", gNumAlignedAllocs, real, filename, line, size);
int32_t *ptr = (int32_t *)ret;
*ptr = 12;
return (ret);
}
void btAlignedFreeInternal(void *ptr, int32_t line, char *filename) {
void *real;
gNumAlignedFree++;
if (ptr) {
real = *((void **)(ptr)-1);
int32_t size = *((int32_t *)(ptr)-2);
gTotalBytesAlignedAllocs -= size;
printf("free #%d at address %x, from %s,line %d, size %d\n", gNumAlignedFree, real, filename, line, size);
sFreeFunc(real);
} else {
printf("NULL ptr\n");
}
}
#else //BT_DEBUG_MEMORY_ALLOCATIONS
void *btAlignedAllocInternal(size_t size, int32_t alignment) {
gNumAlignedAllocs++;
void *ptr;
ptr = sAlignedAllocFunc(size, alignment);
// printf("btAlignedAllocInternal %d, %x\n",size,ptr);
return ptr;
}
void btAlignedFreeInternal(void *ptr) {
if (!ptr) {
return;
}
gNumAlignedFree++;
// printf("btAlignedFreeInternal %x\n",ptr);
sAlignedFreeFunc(ptr);
}
//GODOT ADDITION
};
//
#endif //BT_DEBUG_MEMORY_ALLOCATIONS

File diff suppressed because it is too large Load diff

731
thirdparty/vhacd/src/vhacdICHull.cpp vendored Normal file
View file

@ -0,0 +1,731 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "vhacdICHull.h"
#include <limits>
#ifdef _MSC_VER
#pragma warning(disable:4456 4706)
#endif
namespace VHACD {
const double ICHull::sc_eps = 1.0e-15;
const int32_t ICHull::sc_dummyIndex = std::numeric_limits<int32_t>::max();
ICHull::ICHull()
{
m_isFlat = false;
}
bool ICHull::AddPoints(const Vec3<double>* points, size_t nPoints)
{
if (!points) {
return false;
}
CircularListElement<TMMVertex>* vertex = NULL;
for (size_t i = 0; i < nPoints; i++) {
vertex = m_mesh.AddVertex();
vertex->GetData().m_pos.X() = points[i].X();
vertex->GetData().m_pos.Y() = points[i].Y();
vertex->GetData().m_pos.Z() = points[i].Z();
vertex->GetData().m_name = static_cast<int32_t>(i);
}
return true;
}
bool ICHull::AddPoint(const Vec3<double>& point, int32_t id)
{
if (AddPoints(&point, 1)) {
m_mesh.m_vertices.GetData().m_name = id;
return true;
}
return false;
}
ICHullError ICHull::Process()
{
uint32_t addedPoints = 0;
if (m_mesh.GetNVertices() < 3) {
return ICHullErrorNotEnoughPoints;
}
if (m_mesh.GetNVertices() == 3) {
m_isFlat = true;
CircularListElement<TMMTriangle>* t1 = m_mesh.AddTriangle();
CircularListElement<TMMTriangle>* t2 = m_mesh.AddTriangle();
CircularListElement<TMMVertex>* v0 = m_mesh.m_vertices.GetHead();
CircularListElement<TMMVertex>* v1 = v0->GetNext();
CircularListElement<TMMVertex>* v2 = v1->GetNext();
// Compute the normal to the plane
Vec3<double> p0 = v0->GetData().m_pos;
Vec3<double> p1 = v1->GetData().m_pos;
Vec3<double> p2 = v2->GetData().m_pos;
m_normal = (p1 - p0) ^ (p2 - p0);
m_normal.Normalize();
t1->GetData().m_vertices[0] = v0;
t1->GetData().m_vertices[1] = v1;
t1->GetData().m_vertices[2] = v2;
t2->GetData().m_vertices[0] = v1;
t2->GetData().m_vertices[1] = v2;
t2->GetData().m_vertices[2] = v2;
return ICHullErrorOK;
}
if (m_isFlat) {
m_mesh.m_edges.Clear();
m_mesh.m_triangles.Clear();
m_isFlat = false;
}
if (m_mesh.GetNTriangles() == 0) // we have to create the first polyhedron
{
ICHullError res = DoubleTriangle();
if (res != ICHullErrorOK) {
return res;
}
else {
addedPoints += 3;
}
}
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
// go to the first added and not processed vertex
while (!(vertices.GetHead()->GetPrev()->GetData().m_tag)) {
vertices.Prev();
}
while (!vertices.GetData().m_tag) // not processed
{
vertices.GetData().m_tag = true;
if (ProcessPoint()) {
addedPoints++;
CleanUp(addedPoints);
vertices.Next();
if (!GetMesh().CheckConsistancy()) {
size_t nV = m_mesh.GetNVertices();
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
for (size_t v = 0; v < nV; ++v) {
if (vertices.GetData().m_name == sc_dummyIndex) {
vertices.Delete();
break;
}
vertices.Next();
}
return ICHullErrorInconsistent;
}
}
}
if (m_isFlat) {
SArray<CircularListElement<TMMTriangle>*> trianglesToDuplicate;
size_t nT = m_mesh.GetNTriangles();
for (size_t f = 0; f < nT; f++) {
TMMTriangle& currentTriangle = m_mesh.m_triangles.GetHead()->GetData();
if (currentTriangle.m_vertices[0]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[1]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[2]->GetData().m_name == sc_dummyIndex) {
m_trianglesToDelete.PushBack(m_mesh.m_triangles.GetHead());
for (int32_t k = 0; k < 3; k++) {
for (int32_t h = 0; h < 2; h++) {
if (currentTriangle.m_edges[k]->GetData().m_triangles[h] == m_mesh.m_triangles.GetHead()) {
currentTriangle.m_edges[k]->GetData().m_triangles[h] = 0;
break;
}
}
}
}
else {
trianglesToDuplicate.PushBack(m_mesh.m_triangles.GetHead());
}
m_mesh.m_triangles.Next();
}
size_t nE = m_mesh.GetNEdges();
for (size_t e = 0; e < nE; e++) {
TMMEdge& currentEdge = m_mesh.m_edges.GetHead()->GetData();
if (currentEdge.m_triangles[0] == 0 && currentEdge.m_triangles[1] == 0) {
m_edgesToDelete.PushBack(m_mesh.m_edges.GetHead());
}
m_mesh.m_edges.Next();
}
size_t nV = m_mesh.GetNVertices();
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
for (size_t v = 0; v < nV; ++v) {
if (vertices.GetData().m_name == sc_dummyIndex) {
vertices.Delete();
}
else {
vertices.GetData().m_tag = false;
vertices.Next();
}
}
CleanEdges();
CleanTriangles();
CircularListElement<TMMTriangle>* newTriangle;
for (size_t t = 0; t < trianglesToDuplicate.Size(); t++) {
newTriangle = m_mesh.AddTriangle();
newTriangle->GetData().m_vertices[0] = trianglesToDuplicate[t]->GetData().m_vertices[1];
newTriangle->GetData().m_vertices[1] = trianglesToDuplicate[t]->GetData().m_vertices[0];
newTriangle->GetData().m_vertices[2] = trianglesToDuplicate[t]->GetData().m_vertices[2];
}
}
return ICHullErrorOK;
}
ICHullError ICHull::Process(const uint32_t nPointsCH,
const double minVolume)
{
uint32_t addedPoints = 0;
if (nPointsCH < 3 || m_mesh.GetNVertices() < 3) {
return ICHullErrorNotEnoughPoints;
}
if (m_mesh.GetNVertices() == 3) {
m_isFlat = true;
CircularListElement<TMMTriangle>* t1 = m_mesh.AddTriangle();
CircularListElement<TMMTriangle>* t2 = m_mesh.AddTriangle();
CircularListElement<TMMVertex>* v0 = m_mesh.m_vertices.GetHead();
CircularListElement<TMMVertex>* v1 = v0->GetNext();
CircularListElement<TMMVertex>* v2 = v1->GetNext();
// Compute the normal to the plane
Vec3<double> p0 = v0->GetData().m_pos;
Vec3<double> p1 = v1->GetData().m_pos;
Vec3<double> p2 = v2->GetData().m_pos;
m_normal = (p1 - p0) ^ (p2 - p0);
m_normal.Normalize();
t1->GetData().m_vertices[0] = v0;
t1->GetData().m_vertices[1] = v1;
t1->GetData().m_vertices[2] = v2;
t2->GetData().m_vertices[0] = v1;
t2->GetData().m_vertices[1] = v0;
t2->GetData().m_vertices[2] = v2;
return ICHullErrorOK;
}
if (m_isFlat) {
m_mesh.m_triangles.Clear();
m_mesh.m_edges.Clear();
m_isFlat = false;
}
if (m_mesh.GetNTriangles() == 0) // we have to create the first polyhedron
{
ICHullError res = DoubleTriangle();
if (res != ICHullErrorOK) {
return res;
}
else {
addedPoints += 3;
}
}
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
while (!vertices.GetData().m_tag && addedPoints < nPointsCH) // not processed
{
if (!FindMaxVolumePoint((addedPoints > 4) ? minVolume : 0.0)) {
break;
}
vertices.GetData().m_tag = true;
if (ProcessPoint()) {
addedPoints++;
CleanUp(addedPoints);
if (!GetMesh().CheckConsistancy()) {
size_t nV = m_mesh.GetNVertices();
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
for (size_t v = 0; v < nV; ++v) {
if (vertices.GetData().m_name == sc_dummyIndex) {
vertices.Delete();
break;
}
vertices.Next();
}
return ICHullErrorInconsistent;
}
vertices.Next();
}
}
// delete remaining points
while (!vertices.GetData().m_tag) {
vertices.Delete();
}
if (m_isFlat) {
SArray<CircularListElement<TMMTriangle>*> trianglesToDuplicate;
size_t nT = m_mesh.GetNTriangles();
for (size_t f = 0; f < nT; f++) {
TMMTriangle& currentTriangle = m_mesh.m_triangles.GetHead()->GetData();
if (currentTriangle.m_vertices[0]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[1]->GetData().m_name == sc_dummyIndex || currentTriangle.m_vertices[2]->GetData().m_name == sc_dummyIndex) {
m_trianglesToDelete.PushBack(m_mesh.m_triangles.GetHead());
for (int32_t k = 0; k < 3; k++) {
for (int32_t h = 0; h < 2; h++) {
if (currentTriangle.m_edges[k]->GetData().m_triangles[h] == m_mesh.m_triangles.GetHead()) {
currentTriangle.m_edges[k]->GetData().m_triangles[h] = 0;
break;
}
}
}
}
else {
trianglesToDuplicate.PushBack(m_mesh.m_triangles.GetHead());
}
m_mesh.m_triangles.Next();
}
size_t nE = m_mesh.GetNEdges();
for (size_t e = 0; e < nE; e++) {
TMMEdge& currentEdge = m_mesh.m_edges.GetHead()->GetData();
if (currentEdge.m_triangles[0] == 0 && currentEdge.m_triangles[1] == 0) {
m_edgesToDelete.PushBack(m_mesh.m_edges.GetHead());
}
m_mesh.m_edges.Next();
}
size_t nV = m_mesh.GetNVertices();
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
for (size_t v = 0; v < nV; ++v) {
if (vertices.GetData().m_name == sc_dummyIndex) {
vertices.Delete();
}
else {
vertices.GetData().m_tag = false;
vertices.Next();
}
}
CleanEdges();
CleanTriangles();
CircularListElement<TMMTriangle>* newTriangle;
for (size_t t = 0; t < trianglesToDuplicate.Size(); t++) {
newTriangle = m_mesh.AddTriangle();
newTriangle->GetData().m_vertices[0] = trianglesToDuplicate[t]->GetData().m_vertices[1];
newTriangle->GetData().m_vertices[1] = trianglesToDuplicate[t]->GetData().m_vertices[0];
newTriangle->GetData().m_vertices[2] = trianglesToDuplicate[t]->GetData().m_vertices[2];
}
}
return ICHullErrorOK;
}
bool ICHull::FindMaxVolumePoint(const double minVolume)
{
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
CircularListElement<TMMVertex>* vMaxVolume = 0;
CircularListElement<TMMVertex>* vHeadPrev = vertices.GetHead()->GetPrev();
double maxVolume = minVolume;
double volume = 0.0;
while (!vertices.GetData().m_tag) // not processed
{
if (ComputePointVolume(volume, false)) {
if (maxVolume < volume) {
maxVolume = volume;
vMaxVolume = vertices.GetHead();
}
vertices.Next();
}
}
CircularListElement<TMMVertex>* vHead = vHeadPrev->GetNext();
vertices.GetHead() = vHead;
if (!vMaxVolume) {
return false;
}
if (vMaxVolume != vHead) {
Vec3<double> pos = vHead->GetData().m_pos;
int32_t id = vHead->GetData().m_name;
vHead->GetData().m_pos = vMaxVolume->GetData().m_pos;
vHead->GetData().m_name = vMaxVolume->GetData().m_name;
vMaxVolume->GetData().m_pos = pos;
vHead->GetData().m_name = id;
}
return true;
}
ICHullError ICHull::DoubleTriangle()
{
// find three non colinear points
m_isFlat = false;
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
CircularListElement<TMMVertex>* v0 = vertices.GetHead();
while (Colinear(v0->GetData().m_pos,
v0->GetNext()->GetData().m_pos,
v0->GetNext()->GetNext()->GetData().m_pos)) {
if ((v0 = v0->GetNext()) == vertices.GetHead()) {
return ICHullErrorCoplanarPoints;
}
}
CircularListElement<TMMVertex>* v1 = v0->GetNext();
CircularListElement<TMMVertex>* v2 = v1->GetNext();
// mark points as processed
v0->GetData().m_tag = v1->GetData().m_tag = v2->GetData().m_tag = true;
// create two triangles
CircularListElement<TMMTriangle>* f0 = MakeFace(v0, v1, v2, 0);
MakeFace(v2, v1, v0, f0);
// find a fourth non-coplanar point to form tetrahedron
CircularListElement<TMMVertex>* v3 = v2->GetNext();
vertices.GetHead() = v3;
double vol = ComputeVolume4(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos);
while (fabs(vol) < sc_eps && !v3->GetNext()->GetData().m_tag) {
v3 = v3->GetNext();
vol = ComputeVolume4(v0->GetData().m_pos, v1->GetData().m_pos, v2->GetData().m_pos, v3->GetData().m_pos);
}
if (fabs(vol) < sc_eps) {
// compute the barycenter
Vec3<double> bary(0.0, 0.0, 0.0);
CircularListElement<TMMVertex>* vBary = v0;
do {
bary += vBary->GetData().m_pos;
} while ((vBary = vBary->GetNext()) != v0);
bary /= static_cast<double>(vertices.GetSize());
// Compute the normal to the plane
Vec3<double> p0 = v0->GetData().m_pos;
Vec3<double> p1 = v1->GetData().m_pos;
Vec3<double> p2 = v2->GetData().m_pos;
m_normal = (p1 - p0) ^ (p2 - p0);
m_normal.Normalize();
// add dummy vertex placed at (bary + normal)
vertices.GetHead() = v2;
Vec3<double> newPt = bary + m_normal;
AddPoint(newPt, sc_dummyIndex);
m_isFlat = true;
return ICHullErrorOK;
}
else if (v3 != vertices.GetHead()) {
TMMVertex temp;
temp.m_name = v3->GetData().m_name;
temp.m_pos = v3->GetData().m_pos;
v3->GetData().m_name = vertices.GetHead()->GetData().m_name;
v3->GetData().m_pos = vertices.GetHead()->GetData().m_pos;
vertices.GetHead()->GetData().m_name = temp.m_name;
vertices.GetHead()->GetData().m_pos = temp.m_pos;
}
return ICHullErrorOK;
}
CircularListElement<TMMTriangle>* ICHull::MakeFace(CircularListElement<TMMVertex>* v0,
CircularListElement<TMMVertex>* v1,
CircularListElement<TMMVertex>* v2,
CircularListElement<TMMTriangle>* fold)
{
CircularListElement<TMMEdge>* e0;
CircularListElement<TMMEdge>* e1;
CircularListElement<TMMEdge>* e2;
int32_t index = 0;
if (!fold) // if first face to be created
{
e0 = m_mesh.AddEdge(); // create the three edges
e1 = m_mesh.AddEdge();
e2 = m_mesh.AddEdge();
}
else // otherwise re-use existing edges (in reverse order)
{
e0 = fold->GetData().m_edges[2];
e1 = fold->GetData().m_edges[1];
e2 = fold->GetData().m_edges[0];
index = 1;
}
e0->GetData().m_vertices[0] = v0;
e0->GetData().m_vertices[1] = v1;
e1->GetData().m_vertices[0] = v1;
e1->GetData().m_vertices[1] = v2;
e2->GetData().m_vertices[0] = v2;
e2->GetData().m_vertices[1] = v0;
// create the new face
CircularListElement<TMMTriangle>* f = m_mesh.AddTriangle();
f->GetData().m_edges[0] = e0;
f->GetData().m_edges[1] = e1;
f->GetData().m_edges[2] = e2;
f->GetData().m_vertices[0] = v0;
f->GetData().m_vertices[1] = v1;
f->GetData().m_vertices[2] = v2;
// link edges to face f
e0->GetData().m_triangles[index] = e1->GetData().m_triangles[index] = e2->GetData().m_triangles[index] = f;
return f;
}
CircularListElement<TMMTriangle>* ICHull::MakeConeFace(CircularListElement<TMMEdge>* e, CircularListElement<TMMVertex>* p)
{
// create two new edges if they don't already exist
CircularListElement<TMMEdge>* newEdges[2];
for (int32_t i = 0; i < 2; ++i) {
if (!(newEdges[i] = e->GetData().m_vertices[i]->GetData().m_duplicate)) { // if the edge doesn't exits add it and mark the vertex as duplicated
newEdges[i] = m_mesh.AddEdge();
newEdges[i]->GetData().m_vertices[0] = e->GetData().m_vertices[i];
newEdges[i]->GetData().m_vertices[1] = p;
e->GetData().m_vertices[i]->GetData().m_duplicate = newEdges[i];
}
}
// make the new face
CircularListElement<TMMTriangle>* newFace = m_mesh.AddTriangle();
newFace->GetData().m_edges[0] = e;
newFace->GetData().m_edges[1] = newEdges[0];
newFace->GetData().m_edges[2] = newEdges[1];
MakeCCW(newFace, e, p);
for (int32_t i = 0; i < 2; ++i) {
for (int32_t j = 0; j < 2; ++j) {
if (!newEdges[i]->GetData().m_triangles[j]) {
newEdges[i]->GetData().m_triangles[j] = newFace;
break;
}
}
}
return newFace;
}
bool ICHull::ComputePointVolume(double& totalVolume, bool markVisibleFaces)
{
// mark visible faces
CircularListElement<TMMTriangle>* fHead = m_mesh.GetTriangles().GetHead();
CircularListElement<TMMTriangle>* f = fHead;
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
CircularListElement<TMMVertex>* vertex0 = vertices.GetHead();
bool visible = false;
Vec3<double> pos0 = Vec3<double>(vertex0->GetData().m_pos.X(),
vertex0->GetData().m_pos.Y(),
vertex0->GetData().m_pos.Z());
double vol = 0.0;
totalVolume = 0.0;
Vec3<double> ver0, ver1, ver2;
do {
ver0.X() = f->GetData().m_vertices[0]->GetData().m_pos.X();
ver0.Y() = f->GetData().m_vertices[0]->GetData().m_pos.Y();
ver0.Z() = f->GetData().m_vertices[0]->GetData().m_pos.Z();
ver1.X() = f->GetData().m_vertices[1]->GetData().m_pos.X();
ver1.Y() = f->GetData().m_vertices[1]->GetData().m_pos.Y();
ver1.Z() = f->GetData().m_vertices[1]->GetData().m_pos.Z();
ver2.X() = f->GetData().m_vertices[2]->GetData().m_pos.X();
ver2.Y() = f->GetData().m_vertices[2]->GetData().m_pos.Y();
ver2.Z() = f->GetData().m_vertices[2]->GetData().m_pos.Z();
vol = ComputeVolume4(ver0, ver1, ver2, pos0);
if (vol < -sc_eps) {
vol = fabs(vol);
totalVolume += vol;
if (markVisibleFaces) {
f->GetData().m_visible = true;
m_trianglesToDelete.PushBack(f);
}
visible = true;
}
f = f->GetNext();
} while (f != fHead);
if (m_trianglesToDelete.Size() == m_mesh.m_triangles.GetSize()) {
for (size_t i = 0; i < m_trianglesToDelete.Size(); i++) {
m_trianglesToDelete[i]->GetData().m_visible = false;
}
visible = false;
}
// if no faces visible from p then p is inside the hull
if (!visible && markVisibleFaces) {
vertices.Delete();
m_trianglesToDelete.Resize(0);
return false;
}
return true;
}
bool ICHull::ProcessPoint()
{
double totalVolume = 0.0;
if (!ComputePointVolume(totalVolume, true)) {
return false;
}
// Mark edges in interior of visible region for deletion.
// Create a new face based on each border edge
CircularListElement<TMMVertex>* v0 = m_mesh.GetVertices().GetHead();
CircularListElement<TMMEdge>* eHead = m_mesh.GetEdges().GetHead();
CircularListElement<TMMEdge>* e = eHead;
CircularListElement<TMMEdge>* tmp = 0;
int32_t nvisible = 0;
m_edgesToDelete.Resize(0);
m_edgesToUpdate.Resize(0);
do {
tmp = e->GetNext();
nvisible = 0;
for (int32_t k = 0; k < 2; k++) {
if (e->GetData().m_triangles[k]->GetData().m_visible) {
nvisible++;
}
}
if (nvisible == 2) {
m_edgesToDelete.PushBack(e);
}
else if (nvisible == 1) {
e->GetData().m_newFace = MakeConeFace(e, v0);
m_edgesToUpdate.PushBack(e);
}
e = tmp;
} while (e != eHead);
return true;
}
bool ICHull::MakeCCW(CircularListElement<TMMTriangle>* f,
CircularListElement<TMMEdge>* e,
CircularListElement<TMMVertex>* v)
{
// the visible face adjacent to e
CircularListElement<TMMTriangle>* fv;
if (e->GetData().m_triangles[0]->GetData().m_visible) {
fv = e->GetData().m_triangles[0];
}
else {
fv = e->GetData().m_triangles[1];
}
// set vertex[0] and vertex[1] to have the same orientation as the corresponding vertices of fv.
int32_t i; // index of e->m_vertices[0] in fv
CircularListElement<TMMVertex>* v0 = e->GetData().m_vertices[0];
CircularListElement<TMMVertex>* v1 = e->GetData().m_vertices[1];
for (i = 0; fv->GetData().m_vertices[i] != v0; i++)
;
if (fv->GetData().m_vertices[(i + 1) % 3] != e->GetData().m_vertices[1]) {
f->GetData().m_vertices[0] = v1;
f->GetData().m_vertices[1] = v0;
}
else {
f->GetData().m_vertices[0] = v0;
f->GetData().m_vertices[1] = v1;
// swap edges
CircularListElement<TMMEdge>* tmp = f->GetData().m_edges[0];
f->GetData().m_edges[0] = f->GetData().m_edges[1];
f->GetData().m_edges[1] = tmp;
}
f->GetData().m_vertices[2] = v;
return true;
}
bool ICHull::CleanUp(uint32_t& addedPoints)
{
bool r0 = CleanEdges();
bool r1 = CleanTriangles();
bool r2 = CleanVertices(addedPoints);
return r0 && r1 && r2;
}
bool ICHull::CleanEdges()
{
// integrate the new faces into the data structure
CircularListElement<TMMEdge>* e;
const size_t ne_update = m_edgesToUpdate.Size();
for (size_t i = 0; i < ne_update; ++i) {
e = m_edgesToUpdate[i];
if (e->GetData().m_newFace) {
if (e->GetData().m_triangles[0]->GetData().m_visible) {
e->GetData().m_triangles[0] = e->GetData().m_newFace;
}
else {
e->GetData().m_triangles[1] = e->GetData().m_newFace;
}
e->GetData().m_newFace = 0;
}
}
// delete edges maked for deletion
CircularList<TMMEdge>& edges = m_mesh.GetEdges();
const size_t ne_delete = m_edgesToDelete.Size();
for (size_t i = 0; i < ne_delete; ++i) {
edges.Delete(m_edgesToDelete[i]);
}
m_edgesToDelete.Resize(0);
m_edgesToUpdate.Resize(0);
return true;
}
bool ICHull::CleanTriangles()
{
CircularList<TMMTriangle>& triangles = m_mesh.GetTriangles();
const size_t nt_delete = m_trianglesToDelete.Size();
for (size_t i = 0; i < nt_delete; ++i) {
triangles.Delete(m_trianglesToDelete[i]);
}
m_trianglesToDelete.Resize(0);
return true;
}
bool ICHull::CleanVertices(uint32_t& addedPoints)
{
// mark all vertices incident to some undeleted edge as on the hull
CircularList<TMMEdge>& edges = m_mesh.GetEdges();
CircularListElement<TMMEdge>* e = edges.GetHead();
size_t nE = edges.GetSize();
for (size_t i = 0; i < nE; i++) {
e->GetData().m_vertices[0]->GetData().m_onHull = true;
e->GetData().m_vertices[1]->GetData().m_onHull = true;
e = e->GetNext();
}
// delete all the vertices that have been processed but are not on the hull
CircularList<TMMVertex>& vertices = m_mesh.GetVertices();
CircularListElement<TMMVertex>* vHead = vertices.GetHead();
CircularListElement<TMMVertex>* v = vHead;
v = v->GetPrev();
do {
if (v->GetData().m_tag && !v->GetData().m_onHull) {
CircularListElement<TMMVertex>* tmp = v->GetPrev();
vertices.Delete(v);
v = tmp;
addedPoints--;
}
else {
v->GetData().m_duplicate = 0;
v->GetData().m_onHull = false;
v = v->GetPrev();
}
} while (v->GetData().m_tag && v != vHead);
return true;
}
void ICHull::Clear()
{
m_mesh.Clear();
m_edgesToDelete.Resize(0);
m_edgesToUpdate.Resize(0);
m_trianglesToDelete.Resize(0);
m_isFlat = false;
}
const ICHull& ICHull::operator=(ICHull& rhs)
{
if (&rhs != this) {
m_mesh.Copy(rhs.m_mesh);
m_edgesToDelete = rhs.m_edgesToDelete;
m_edgesToUpdate = rhs.m_edgesToUpdate;
m_trianglesToDelete = rhs.m_trianglesToDelete;
m_isFlat = rhs.m_isFlat;
}
return (*this);
}
bool ICHull::IsInside(const Vec3<double>& pt0, const double eps)
{
const Vec3<double> pt(pt0.X(), pt0.Y(), pt0.Z());
if (m_isFlat) {
size_t nT = m_mesh.m_triangles.GetSize();
Vec3<double> ver0, ver1, ver2, a, b, c;
double u, v;
for (size_t t = 0; t < nT; t++) {
ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X();
ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y();
ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z();
ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X();
ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y();
ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z();
ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X();
ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y();
ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z();
a = ver1 - ver0;
b = ver2 - ver0;
c = pt - ver0;
u = c * a;
v = c * b;
if (u >= 0.0 && u <= 1.0 && v >= 0.0 && u + v <= 1.0) {
return true;
}
m_mesh.m_triangles.Next();
}
return false;
}
else {
size_t nT = m_mesh.m_triangles.GetSize();
Vec3<double> ver0, ver1, ver2;
double vol;
for (size_t t = 0; t < nT; t++) {
ver0.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.X();
ver0.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Y();
ver0.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[0]->GetData().m_pos.Z();
ver1.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.X();
ver1.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Y();
ver1.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[1]->GetData().m_pos.Z();
ver2.X() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.X();
ver2.Y() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Y();
ver2.Z() = m_mesh.m_triangles.GetHead()->GetData().m_vertices[2]->GetData().m_pos.Z();
vol = ComputeVolume4(ver0, ver1, ver2, pt);
if (vol < eps) {
return false;
}
m_mesh.m_triangles.Next();
}
return true;
}
}
}

View file

@ -0,0 +1,202 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "vhacdManifoldMesh.h"
namespace VHACD {
TMMVertex::TMMVertex(void)
{
Initialize();
}
void TMMVertex::Initialize()
{
m_name = 0;
m_id = 0;
m_duplicate = 0;
m_onHull = false;
m_tag = false;
}
TMMVertex::~TMMVertex(void)
{
}
TMMEdge::TMMEdge(void)
{
Initialize();
}
void TMMEdge::Initialize()
{
m_id = 0;
m_triangles[0] = m_triangles[1] = m_newFace = 0;
m_vertices[0] = m_vertices[1] = 0;
}
TMMEdge::~TMMEdge(void)
{
}
void TMMTriangle::Initialize()
{
m_id = 0;
for (int32_t i = 0; i < 3; i++) {
m_edges[i] = 0;
m_vertices[0] = 0;
}
m_visible = false;
}
TMMTriangle::TMMTriangle(void)
{
Initialize();
}
TMMTriangle::~TMMTriangle(void)
{
}
TMMesh::TMMesh()
{
}
TMMesh::~TMMesh(void)
{
}
void TMMesh::GetIFS(Vec3<double>* const points, Vec3<int32_t>* const triangles)
{
size_t nV = m_vertices.GetSize();
size_t nT = m_triangles.GetSize();
for (size_t v = 0; v < nV; v++) {
points[v] = m_vertices.GetData().m_pos;
m_vertices.GetData().m_id = v;
m_vertices.Next();
}
for (size_t f = 0; f < nT; f++) {
TMMTriangle& currentTriangle = m_triangles.GetData();
triangles[f].X() = static_cast<int32_t>(currentTriangle.m_vertices[0]->GetData().m_id);
triangles[f].Y() = static_cast<int32_t>(currentTriangle.m_vertices[1]->GetData().m_id);
triangles[f].Z() = static_cast<int32_t>(currentTriangle.m_vertices[2]->GetData().m_id);
m_triangles.Next();
}
}
void TMMesh::Clear()
{
m_vertices.Clear();
m_edges.Clear();
m_triangles.Clear();
}
void TMMesh::Copy(TMMesh& mesh)
{
Clear();
// updating the id's
size_t nV = mesh.m_vertices.GetSize();
size_t nE = mesh.m_edges.GetSize();
size_t nT = mesh.m_triangles.GetSize();
for (size_t v = 0; v < nV; v++) {
mesh.m_vertices.GetData().m_id = v;
mesh.m_vertices.Next();
}
for (size_t e = 0; e < nE; e++) {
mesh.m_edges.GetData().m_id = e;
mesh.m_edges.Next();
}
for (size_t f = 0; f < nT; f++) {
mesh.m_triangles.GetData().m_id = f;
mesh.m_triangles.Next();
}
// copying data
m_vertices = mesh.m_vertices;
m_edges = mesh.m_edges;
m_triangles = mesh.m_triangles;
// generate mapping
CircularListElement<TMMVertex>** vertexMap = new CircularListElement<TMMVertex>*[nV];
CircularListElement<TMMEdge>** edgeMap = new CircularListElement<TMMEdge>*[nE];
CircularListElement<TMMTriangle>** triangleMap = new CircularListElement<TMMTriangle>*[nT];
for (size_t v = 0; v < nV; v++) {
vertexMap[v] = m_vertices.GetHead();
m_vertices.Next();
}
for (size_t e = 0; e < nE; e++) {
edgeMap[e] = m_edges.GetHead();
m_edges.Next();
}
for (size_t f = 0; f < nT; f++) {
triangleMap[f] = m_triangles.GetHead();
m_triangles.Next();
}
// updating pointers
for (size_t v = 0; v < nV; v++) {
if (vertexMap[v]->GetData().m_duplicate) {
vertexMap[v]->GetData().m_duplicate = edgeMap[vertexMap[v]->GetData().m_duplicate->GetData().m_id];
}
}
for (size_t e = 0; e < nE; e++) {
if (edgeMap[e]->GetData().m_newFace) {
edgeMap[e]->GetData().m_newFace = triangleMap[edgeMap[e]->GetData().m_newFace->GetData().m_id];
}
if (nT > 0) {
for (int32_t f = 0; f < 2; f++) {
if (edgeMap[e]->GetData().m_triangles[f]) {
edgeMap[e]->GetData().m_triangles[f] = triangleMap[edgeMap[e]->GetData().m_triangles[f]->GetData().m_id];
}
}
}
for (int32_t v = 0; v < 2; v++) {
if (edgeMap[e]->GetData().m_vertices[v]) {
edgeMap[e]->GetData().m_vertices[v] = vertexMap[edgeMap[e]->GetData().m_vertices[v]->GetData().m_id];
}
}
}
for (size_t f = 0; f < nT; f++) {
if (nE > 0) {
for (int32_t e = 0; e < 3; e++) {
if (triangleMap[f]->GetData().m_edges[e]) {
triangleMap[f]->GetData().m_edges[e] = edgeMap[triangleMap[f]->GetData().m_edges[e]->GetData().m_id];
}
}
}
for (int32_t v = 0; v < 3; v++) {
if (triangleMap[f]->GetData().m_vertices[v]) {
triangleMap[f]->GetData().m_vertices[v] = vertexMap[triangleMap[f]->GetData().m_vertices[v]->GetData().m_id];
}
}
}
delete[] vertexMap;
delete[] edgeMap;
delete[] triangleMap;
}
bool TMMesh::CheckConsistancy()
{
size_t nE = m_edges.GetSize();
size_t nT = m_triangles.GetSize();
for (size_t e = 0; e < nE; e++) {
for (int32_t f = 0; f < 2; f++) {
if (!m_edges.GetHead()->GetData().m_triangles[f]) {
return false;
}
}
m_edges.Next();
}
for (size_t f = 0; f < nT; f++) {
for (int32_t e = 0; e < 3; e++) {
int32_t found = 0;
for (int32_t k = 0; k < 2; k++) {
if (m_triangles.GetHead()->GetData().m_edges[e]->GetData().m_triangles[k] == m_triangles.GetHead()) {
found++;
}
}
if (found != 1) {
return false;
}
}
m_triangles.Next();
}
return true;
}
}

376
thirdparty/vhacd/src/vhacdMesh.cpp vendored Normal file
View file

@ -0,0 +1,376 @@
/* Copyright (c) 2011 Khaled Mamou (kmamou at gmail dot com)
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. The names of the contributors may not be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "btConvexHullComputer.h"
#include "vhacdMesh.h"
#include "FloatMath.h"
#include <fstream>
#include <iosfwd>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
namespace VHACD {
Mesh::Mesh()
{
m_diag = 1.0;
}
Mesh::~Mesh()
{
}
Vec3<double>& Mesh::ComputeCenter(void)
{
const size_t nV = GetNPoints();
if (nV)
{
double center[3];
uint32_t pcount = uint32_t(GetNPoints());
const double *points = GetPoints();
uint32_t tcount = uint32_t(GetNTriangles());
const uint32_t *indices = (const uint32_t *)GetTriangles();
FLOAT_MATH::fm_computeCentroid(pcount, points, tcount, indices, center);
m_center.X() = center[0];
m_center.Y() = center[1];
m_center.Z() = center[2];
m_minBB = GetPoint(0);
m_maxBB = GetPoint(0);
for (size_t v = 1; v < nV; v++)
{
Vec3<double> p = GetPoint(v);
if (p.X() < m_minBB.X())
{
m_minBB.X() = p.X();
}
if (p.Y() < m_minBB.Y())
{
m_minBB.Y() = p.Y();
}
if (p.Z() < m_minBB.Z())
{
m_minBB.Z() = p.Z();
}
if (p.X() > m_maxBB.X())
{
m_maxBB.X() = p.X();
}
if (p.Y() > m_maxBB.Y())
{
m_maxBB.Y() = p.Y();
}
if (p.Z() > m_maxBB.Z())
{
m_maxBB.Z() = p.Z();
}
}
}
return m_center;
}
double Mesh::ComputeVolume() const
{
const size_t nV = GetNPoints();
const size_t nT = GetNTriangles();
if (nV == 0 || nT == 0) {
return 0.0;
}
Vec3<double> bary(0.0, 0.0, 0.0);
for (size_t v = 0; v < nV; v++) {
bary += GetPoint(v);
}
bary /= static_cast<double>(nV);
Vec3<double> ver0, ver1, ver2;
double totalVolume = 0.0;
for (int32_t t = 0; t < int32_t(nT); t++) {
const Vec3<int32_t>& tri = GetTriangle(t);
ver0 = GetPoint(tri[0]);
ver1 = GetPoint(tri[1]);
ver2 = GetPoint(tri[2]);
totalVolume += ComputeVolume4(ver0, ver1, ver2, bary);
}
return totalVolume / 6.0;
}
void Mesh::ComputeConvexHull(const double* const pts,
const size_t nPts)
{
ResizePoints(0);
ResizeTriangles(0);
btConvexHullComputer ch;
ch.compute(pts, 3 * sizeof(double), (int32_t)nPts, -1.0, -1.0);
for (int32_t v = 0; v < ch.vertices.size(); v++) {
AddPoint(Vec3<double>(ch.vertices[v].getX(), ch.vertices[v].getY(), ch.vertices[v].getZ()));
}
const int32_t nt = ch.faces.size();
for (int32_t t = 0; t < nt; ++t) {
const btConvexHullComputer::Edge* sourceEdge = &(ch.edges[ch.faces[t]]);
int32_t a = sourceEdge->getSourceVertex();
int32_t b = sourceEdge->getTargetVertex();
const btConvexHullComputer::Edge* edge = sourceEdge->getNextEdgeOfFace();
int32_t c = edge->getTargetVertex();
while (c != a) {
AddTriangle(Vec3<int32_t>(a, b, c));
edge = edge->getNextEdgeOfFace();
b = c;
c = edge->getTargetVertex();
}
}
}
void Mesh::Clip(const Plane& plane,
SArray<Vec3<double> >& positivePart,
SArray<Vec3<double> >& negativePart) const
{
const size_t nV = GetNPoints();
if (nV == 0) {
return;
}
double d;
for (size_t v = 0; v < nV; v++) {
const Vec3<double>& pt = GetPoint(v);
d = plane.m_a * pt[0] + plane.m_b * pt[1] + plane.m_c * pt[2] + plane.m_d;
if (d > 0.0) {
positivePart.PushBack(pt);
}
else if (d < 0.0) {
negativePart.PushBack(pt);
}
else {
positivePart.PushBack(pt);
negativePart.PushBack(pt);
}
}
}
bool Mesh::IsInside(const Vec3<double>& pt) const
{
const size_t nV = GetNPoints();
const size_t nT = GetNTriangles();
if (nV == 0 || nT == 0) {
return false;
}
Vec3<double> ver0, ver1, ver2;
double volume;
for (int32_t t = 0; t < int32_t(nT); t++) {
const Vec3<int32_t>& tri = GetTriangle(t);
ver0 = GetPoint(tri[0]);
ver1 = GetPoint(tri[1]);
ver2 = GetPoint(tri[2]);
volume = ComputeVolume4(ver0, ver1, ver2, pt);
if (volume < 0.0) {
return false;
}
}
return true;
}
double Mesh::ComputeDiagBB()
{
const size_t nPoints = GetNPoints();
if (nPoints == 0)
return 0.0;
Vec3<double> minBB = m_points[0];
Vec3<double> maxBB = m_points[0];
double x, y, z;
for (size_t v = 1; v < nPoints; v++) {
x = m_points[v][0];
y = m_points[v][1];
z = m_points[v][2];
if (x < minBB[0])
minBB[0] = x;
else if (x > maxBB[0])
maxBB[0] = x;
if (y < minBB[1])
minBB[1] = y;
else if (y > maxBB[1])
maxBB[1] = y;
if (z < minBB[2])
minBB[2] = z;
else if (z > maxBB[2])
maxBB[2] = z;
}
return (m_diag = (maxBB - minBB).GetNorm());
}
#ifdef VHACD_DEBUG_MESH
bool Mesh::SaveVRML2(const std::string& fileName) const
{
std::ofstream fout(fileName.c_str());
if (fout.is_open()) {
const Material material;
if (SaveVRML2(fout, material)) {
fout.close();
return true;
}
return false;
}
return false;
}
bool Mesh::SaveVRML2(std::ofstream& fout, const Material& material) const
{
if (fout.is_open()) {
fout.setf(std::ios::fixed, std::ios::floatfield);
fout.setf(std::ios::showpoint);
fout.precision(6);
size_t nV = m_points.Size();
size_t nT = m_triangles.Size();
fout << "#VRML V2.0 utf8" << std::endl;
fout << "" << std::endl;
fout << "# Vertices: " << nV << std::endl;
fout << "# Triangles: " << nT << std::endl;
fout << "" << std::endl;
fout << "Group {" << std::endl;
fout << " children [" << std::endl;
fout << " Shape {" << std::endl;
fout << " appearance Appearance {" << std::endl;
fout << " material Material {" << std::endl;
fout << " diffuseColor " << material.m_diffuseColor[0] << " "
<< material.m_diffuseColor[1] << " "
<< material.m_diffuseColor[2] << std::endl;
fout << " ambientIntensity " << material.m_ambientIntensity << std::endl;
fout << " specularColor " << material.m_specularColor[0] << " "
<< material.m_specularColor[1] << " "
<< material.m_specularColor[2] << std::endl;
fout << " emissiveColor " << material.m_emissiveColor[0] << " "
<< material.m_emissiveColor[1] << " "
<< material.m_emissiveColor[2] << std::endl;
fout << " shininess " << material.m_shininess << std::endl;
fout << " transparency " << material.m_transparency << std::endl;
fout << " }" << std::endl;
fout << " }" << std::endl;
fout << " geometry IndexedFaceSet {" << std::endl;
fout << " ccw TRUE" << std::endl;
fout << " solid TRUE" << std::endl;
fout << " convex TRUE" << std::endl;
if (nV > 0) {
fout << " coord DEF co Coordinate {" << std::endl;
fout << " point [" << std::endl;
for (size_t v = 0; v < nV; v++) {
fout << " " << m_points[v][0] << " "
<< m_points[v][1] << " "
<< m_points[v][2] << "," << std::endl;
}
fout << " ]" << std::endl;
fout << " }" << std::endl;
}
if (nT > 0) {
fout << " coordIndex [ " << std::endl;
for (size_t f = 0; f < nT; f++) {
fout << " " << m_triangles[f][0] << ", "
<< m_triangles[f][1] << ", "
<< m_triangles[f][2] << ", -1," << std::endl;
}
fout << " ]" << std::endl;
}
fout << " }" << std::endl;
fout << " }" << std::endl;
fout << " ]" << std::endl;
fout << "}" << std::endl;
return true;
}
return false;
}
bool Mesh::SaveOFF(const std::string& fileName) const
{
std::ofstream fout(fileName.c_str());
if (fout.is_open()) {
size_t nV = m_points.Size();
size_t nT = m_triangles.Size();
fout << "OFF" << std::endl;
fout << nV << " " << nT << " " << 0 << std::endl;
for (size_t v = 0; v < nV; v++) {
fout << m_points[v][0] << " "
<< m_points[v][1] << " "
<< m_points[v][2] << std::endl;
}
for (size_t f = 0; f < nT; f++) {
fout << "3 " << m_triangles[f][0] << " "
<< m_triangles[f][1] << " "
<< m_triangles[f][2] << std::endl;
}
fout.close();
return true;
}
return false;
}
bool Mesh::LoadOFF(const std::string& fileName, bool invert)
{
FILE* fid = fopen(fileName.c_str(), "r");
if (fid) {
const std::string strOFF("OFF");
char temp[1024];
fscanf(fid, "%s", temp);
if (std::string(temp) != strOFF) {
fclose(fid);
return false;
}
else {
int32_t nv = 0;
int32_t nf = 0;
int32_t ne = 0;
fscanf(fid, "%i", &nv);
fscanf(fid, "%i", &nf);
fscanf(fid, "%i", &ne);
m_points.Resize(nv);
m_triangles.Resize(nf);
Vec3<double> coord;
float x, y, z;
for (int32_t p = 0; p < nv; p++) {
fscanf(fid, "%f", &x);
fscanf(fid, "%f", &y);
fscanf(fid, "%f", &z);
m_points[p][0] = x;
m_points[p][1] = y;
m_points[p][2] = z;
}
int32_t i, j, k, s;
for (int32_t t = 0; t < nf; ++t) {
fscanf(fid, "%i", &s);
if (s == 3) {
fscanf(fid, "%i", &i);
fscanf(fid, "%i", &j);
fscanf(fid, "%i", &k);
m_triangles[t][0] = i;
if (invert) {
m_triangles[t][1] = k;
m_triangles[t][2] = j;
}
else {
m_triangles[t][1] = j;
m_triangles[t][2] = k;
}
}
else // Fix me: support only triangular meshes
{
for (int32_t h = 0; h < s; ++h)
fscanf(fid, "%i", &s);
}
}
fclose(fid);
}
}
else {
return false;
}
return true;
}
#endif // VHACD_DEBUG_MESH
}

View file

@ -0,0 +1,208 @@
#include "vhacdRaycastMesh.h"
#include <math.h>
#include <assert.h>
namespace RAYCAST_MESH
{
/* a = b - c */
#define vector(a,b,c) \
(a)[0] = (b)[0] - (c)[0]; \
(a)[1] = (b)[1] - (c)[1]; \
(a)[2] = (b)[2] - (c)[2];
#define innerProduct(v,q) \
((v)[0] * (q)[0] + \
(v)[1] * (q)[1] + \
(v)[2] * (q)[2])
#define crossProduct(a,b,c) \
(a)[0] = (b)[1] * (c)[2] - (c)[1] * (b)[2]; \
(a)[1] = (b)[2] * (c)[0] - (c)[2] * (b)[0]; \
(a)[2] = (b)[0] * (c)[1] - (c)[0] * (b)[1];
static inline bool rayIntersectsTriangle(const double *p,const double *d,const double *v0,const double *v1,const double *v2,double &t)
{
double e1[3],e2[3],h[3],s[3],q[3];
double a,f,u,v;
vector(e1,v1,v0);
vector(e2,v2,v0);
crossProduct(h,d,e2);
a = innerProduct(e1,h);
if (a > -0.00001 && a < 0.00001)
return(false);
f = 1/a;
vector(s,p,v0);
u = f * (innerProduct(s,h));
if (u < 0.0 || u > 1.0)
return(false);
crossProduct(q,s,e1);
v = f * innerProduct(d,q);
if (v < 0.0 || u + v > 1.0)
return(false);
// at this stage we can compute t to find out where
// the intersection point is on the line
t = f * innerProduct(e2,q);
if (t > 0) // ray intersection
return(true);
else // this means that there is a line intersection
// but not a ray intersection
return (false);
}
static double getPointDistance(const double *p1, const double *p2)
{
double dx = p1[0] - p2[0];
double dy = p1[1] - p2[1];
double dz = p1[2] - p2[2];
return sqrt(dx*dx + dy*dy + dz*dz);
}
class MyRaycastMesh : public VHACD::RaycastMesh
{
public:
template <class T>
MyRaycastMesh(uint32_t vcount,
const T *vertices,
uint32_t tcount,
const uint32_t *indices)
{
mVcount = vcount;
mVertices = new double[mVcount * 3];
for (uint32_t i = 0; i < mVcount; i++)
{
mVertices[i * 3 + 0] = vertices[0];
mVertices[i * 3 + 1] = vertices[1];
mVertices[i * 3 + 2] = vertices[2];
vertices += 3;
}
mTcount = tcount;
mIndices = new uint32_t[mTcount * 3];
for (uint32_t i = 0; i < mTcount; i++)
{
mIndices[i * 3 + 0] = indices[0];
mIndices[i * 3 + 1] = indices[1];
mIndices[i * 3 + 2] = indices[2];
indices += 3;
}
}
~MyRaycastMesh(void)
{
delete[]mVertices;
delete[]mIndices;
}
virtual void release(void)
{
delete this;
}
virtual bool raycast(const double *from, // The starting point of the raycast
const double *to, // The ending point of the raycast
const double *closestToPoint, // The point to match the nearest hit location (can just be the 'from' location of no specific point)
double *hitLocation, // The point where the ray hit nearest to the 'closestToPoint' location
double *hitDistance) final // The distance the ray traveled to the hit location
{
bool ret = false;
double dir[3];
dir[0] = to[0] - from[0];
dir[1] = to[1] - from[1];
dir[2] = to[2] - from[2];
double distance = sqrt( dir[0]*dir[0] + dir[1]*dir[1]+dir[2]*dir[2] );
if ( distance < 0.0000000001f ) return false;
double recipDistance = 1.0f / distance;
dir[0]*=recipDistance;
dir[1]*=recipDistance;
dir[2]*=recipDistance;
const uint32_t *indices = mIndices;
const double *vertices = mVertices;
double nearestDistance = distance;
for (uint32_t tri=0; tri<mTcount; tri++)
{
uint32_t i1 = indices[tri*3+0];
uint32_t i2 = indices[tri*3+1];
uint32_t i3 = indices[tri*3+2];
const double *p1 = &vertices[i1*3];
const double *p2 = &vertices[i2*3];
const double *p3 = &vertices[i3*3];
double t;
if ( rayIntersectsTriangle(from,dir,p1,p2,p3,t))
{
double hitPos[3];
hitPos[0] = from[0] + dir[0] * t;
hitPos[1] = from[1] + dir[1] * t;
hitPos[2] = from[2] + dir[2] * t;
double pointDistance = getPointDistance(hitPos, closestToPoint);
if (pointDistance < nearestDistance )
{
nearestDistance = pointDistance;
if ( hitLocation )
{
hitLocation[0] = hitPos[0];
hitLocation[1] = hitPos[1];
hitLocation[2] = hitPos[2];
}
if ( hitDistance )
{
*hitDistance = pointDistance;
}
ret = true;
}
}
}
return ret;
}
uint32_t mVcount;
double *mVertices;
uint32_t mTcount;
uint32_t *mIndices;
};
};
using namespace RAYCAST_MESH;
namespace VHACD
{
RaycastMesh * RaycastMesh::createRaycastMesh(uint32_t vcount, // The number of vertices in the source triangle mesh
const double *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
uint32_t tcount, // The number of triangles in the source triangle mesh
const uint32_t *indices) // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
{
MyRaycastMesh *m = new MyRaycastMesh(vcount, vertices, tcount, indices);
return static_cast<RaycastMesh *>(m);
}
RaycastMesh * RaycastMesh::createRaycastMesh(uint32_t vcount, // The number of vertices in the source triangle mesh
const float *vertices, // The array of vertex positions in the format x1,y1,z1..x2,y2,z2.. etc.
uint32_t tcount, // The number of triangles in the source triangle mesh
const uint32_t *indices) // The triangle indices in the format of i1,i2,i3 ... i4,i5,i6, ...
{
MyRaycastMesh *m = new MyRaycastMesh(vcount, vertices, tcount, indices);
return static_cast<RaycastMesh *>(m);
}
} // end of VHACD namespace

1626
thirdparty/vhacd/src/vhacdVolume.cpp vendored Normal file

File diff suppressed because it is too large Load diff