Commit 5823b5d7 by Juan Linietsky

Bundled VHACD library for convex decomposition.

Modified both MeshInstance tools as well as importer to use it instead of QuickHull.
parent 07b76c03
......@@ -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);
......
......@@ -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();
......
#!/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")
def can_build(env, platform):
return True
def configure(env):
pass
/*************************************************************************/
/* 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;
}
/*************************************************************************/
/* 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();
......@@ -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() {
}
......
......@@ -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();
};
......
/*
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
/*
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
/*
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
/* 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
\ No newline at end of file
#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
\ No newline at end of file
/* 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
/* 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
\ No newline at end of file
/* 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
\ No newline at end of file
/*!
**
** 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
#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
/* 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
\ No newline at end of file
/* 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
/* 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
\ No newline at end of file
/* 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
#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"
This source diff could not be displayed because it is too large. You can view the blob instead.
#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
/*
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
/* 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;
}
}
\ No newline at end of file
#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
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment