Compare commits
70 Commits
temp-virtu
...
soc-2013-r
Author | SHA1 | Date | |
---|---|---|---|
39dc956f59 | |||
5d5176095e | |||
bcbf976b48 | |||
8259ccd508 | |||
da453676ce | |||
bfb34b22f7 | |||
e4f5cfc508 | |||
2bc0422e08 | |||
ce510086fc | |||
a6b95d34e2 | |||
00abe28109 | |||
e3c285582c | |||
9c5c60c2a3 | |||
414329815b | |||
b10c869faf | |||
a98a32e6c8 | |||
46b995e691 | |||
22a3f8b751 | |||
c22a365b1b | |||
f6d12c86db | |||
8ce4109597 | |||
6b20b94953 | |||
d1e5eb4a1f | |||
5fecbda461 | |||
7b281b3ae4 | |||
b2388aa8e3 | |||
817f08be38 | |||
9088d62702 | |||
40c8bf395d | |||
094445f973 | |||
f21f340185 | |||
59d22634e0 | |||
c6f3614329 | |||
bf2d4f55de | |||
6cdc6bf60a | |||
d911109fb4 | |||
c858206f75 | |||
005ab5cbe4 | |||
ce726474e6 | |||
d1781c8f7e | |||
15aeb1d714 | |||
17accbd408 | |||
3977df582d | |||
ac4dccec1d | |||
942264da64 | |||
776a201fd7 | |||
a5ac14aab5 | |||
1d9ba24129 | |||
8e4890b536 | |||
c8ca998e2b | |||
36e6bddb5c | |||
df3974b6d1 | |||
57051902b5 | |||
4acb76734f | |||
41e9166164 | |||
7331164531 | |||
6005ba52f5 | |||
c4c2185850 | |||
773b7bb673 | |||
0a50b75fe5 | |||
a475b5f702 | |||
0866d5d2e2 | |||
c565541517 | |||
65d9a24db5 | |||
880fe69dc7 | |||
fbdf015c3a | |||
c28e76cf3f | |||
f64bb323a8 | |||
c726312325 | |||
f131b583d6 |
1
extern/CMakeLists.txt
vendored
1
extern/CMakeLists.txt
vendored
@@ -35,6 +35,7 @@ if(WITH_BULLET)
|
||||
if(NOT WITH_SYSTEM_BULLET)
|
||||
add_subdirectory(bullet2)
|
||||
endif()
|
||||
add_subdirectory(HACD)
|
||||
endif()
|
||||
|
||||
# now only available in a branch
|
||||
|
47
extern/HACD/CMakeLists.txt
vendored
Normal file
47
extern/HACD/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# The Original Code is Copyright (C) 2006, Blender Foundation
|
||||
# All rights reserved.
|
||||
#
|
||||
# The Original Code is: all of this file.
|
||||
#
|
||||
# Contributor(s): Sergej Reich
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
SET(SRC
|
||||
hacdGraph.cpp
|
||||
hacdHACD.cpp
|
||||
hacdICHull.cpp
|
||||
hacdManifoldMesh.cpp
|
||||
|
||||
hacdCircularList.h
|
||||
hacdGraph.h
|
||||
hacdHACD.h
|
||||
hacdICHull.h
|
||||
hacdManifoldMesh.h
|
||||
hacdVector.h
|
||||
hacdVersion.h
|
||||
hacdCircularList.inl
|
||||
hacdVector.inl
|
||||
)
|
||||
|
||||
SET(INC
|
||||
.
|
||||
)
|
||||
|
||||
blender_add_lib(extern_hacd "${SRC}" "${INC}" "${INC_SYS}")
|
80
extern/HACD/hacdCircularList.h
vendored
Normal file
80
extern/HACD/hacdCircularList.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
/* 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 HACD_CIRCULAR_LIST_H
|
||||
#define HACD_CIRCULAR_LIST_H
|
||||
#include<stdlib.h>
|
||||
#include "hacdVersion.h"
|
||||
namespace HACD
|
||||
{
|
||||
//! 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
|
||||
virtual ~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 "hacdCircularList.inl"
|
||||
#endif
|
163
extern/HACD/hacdCircularList.inl
vendored
Normal file
163
extern/HACD/hacdCircularList.inl
vendored
Normal file
@@ -0,0 +1,163 @@
|
||||
#pragma once
|
||||
#ifndef HACD_CIRCULAR_LIST_INL
|
||||
#define HACD_CIRCULAR_LIST_INL
|
||||
#include<stdlib.h>
|
||||
#include "hacdVersion.h"
|
||||
namespace HACD
|
||||
{
|
||||
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
|
292
extern/HACD/hacdGraph.cpp
vendored
Normal file
292
extern/HACD/hacdGraph.cpp
vendored
Normal file
@@ -0,0 +1,292 @@
|
||||
/* 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 "hacdGraph.h"
|
||||
namespace HACD
|
||||
{
|
||||
|
||||
GraphEdge::GraphEdge()
|
||||
{
|
||||
m_convexHull = 0;
|
||||
m_v1 = -1;
|
||||
m_v2 = -1;
|
||||
m_name = -1;
|
||||
m_error = 0;
|
||||
m_surf = 0;
|
||||
m_perimeter = 0;
|
||||
m_concavity = 0;
|
||||
m_volume = 0;
|
||||
m_deleted = false;
|
||||
}
|
||||
|
||||
GraphVertex::GraphVertex()
|
||||
{
|
||||
m_convexHull = 0;
|
||||
m_name = -1;
|
||||
m_cc = -1;
|
||||
m_error = 0;
|
||||
m_surf = 0;
|
||||
m_perimeter = 0;
|
||||
m_concavity = 0;
|
||||
m_volume = 0;
|
||||
m_deleted = false;
|
||||
}
|
||||
|
||||
bool GraphVertex::DeleteEdge(long name)
|
||||
{
|
||||
std::set<long>::iterator it = m_edges.find(name);
|
||||
if (it != m_edges.end() )
|
||||
{
|
||||
m_edges.erase(it);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Graph::Graph()
|
||||
{
|
||||
m_nV = 0;
|
||||
m_nE = 0;
|
||||
m_nCCs = 0;
|
||||
}
|
||||
|
||||
Graph::~Graph()
|
||||
{
|
||||
}
|
||||
|
||||
void Graph::Allocate(size_t nV, size_t nE)
|
||||
{
|
||||
m_nV = nV;
|
||||
m_edges.reserve(nE);
|
||||
m_vertices.resize(nV);
|
||||
for(size_t i = 0; i < nV; i++)
|
||||
{
|
||||
m_vertices[i].m_name = static_cast<long>(i);
|
||||
}
|
||||
}
|
||||
|
||||
long Graph::AddVertex()
|
||||
{
|
||||
size_t name = m_vertices.size();
|
||||
m_vertices.resize(name+1);
|
||||
m_vertices[name].m_name = static_cast<long>(name);
|
||||
m_nV++;
|
||||
return static_cast<long>(name);
|
||||
}
|
||||
|
||||
long Graph::AddEdge(long v1, long v2)
|
||||
{
|
||||
size_t name = m_edges.size();
|
||||
m_edges.push_back(GraphEdge());
|
||||
m_edges[name].m_name = static_cast<long>(name);
|
||||
m_edges[name].m_v1 = v1;
|
||||
m_edges[name].m_v2 = v2;
|
||||
m_vertices[v1].AddEdge(static_cast<long>(name));
|
||||
m_vertices[v2].AddEdge(static_cast<long>(name));
|
||||
m_nE++;
|
||||
return static_cast<long>(name);
|
||||
}
|
||||
|
||||
bool Graph::DeleteEdge(long name)
|
||||
{
|
||||
if (name < static_cast<long>(m_edges.size()))
|
||||
{
|
||||
long v1 = m_edges[name].m_v1;
|
||||
long v2 = m_edges[name].m_v2;
|
||||
m_edges[name].m_deleted = true;
|
||||
m_vertices[v1].DeleteEdge(name);
|
||||
m_vertices[v2].DeleteEdge(name);
|
||||
delete m_edges[name].m_convexHull;
|
||||
m_edges[name].m_distPoints.clear();
|
||||
m_edges[name].m_boudaryEdges.clear();
|
||||
m_edges[name].m_convexHull = 0;
|
||||
m_nE--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Graph::DeleteVertex(long name)
|
||||
{
|
||||
if (name < static_cast<long>(m_vertices.size()))
|
||||
{
|
||||
m_vertices[name].m_deleted = true;
|
||||
m_vertices[name].m_edges.clear();
|
||||
m_vertices[name].m_ancestors = std::vector<long>();
|
||||
delete m_vertices[name].m_convexHull;
|
||||
m_vertices[name].m_distPoints.clear();
|
||||
m_vertices[name].m_boudaryEdges.clear();
|
||||
m_vertices[name].m_convexHull = 0;
|
||||
m_nV--;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool Graph::EdgeCollapse(long v1, long v2)
|
||||
{
|
||||
long edgeToDelete = GetEdgeID(v1, v2);
|
||||
if (edgeToDelete >= 0)
|
||||
{
|
||||
// delete the edge (v1, v2)
|
||||
DeleteEdge(edgeToDelete);
|
||||
// add v2 to v1 ancestors
|
||||
m_vertices[v1].m_ancestors.push_back(v2);
|
||||
// add v2's ancestors to v1's ancestors
|
||||
m_vertices[v1].m_ancestors.insert(m_vertices[v1].m_ancestors.begin(),
|
||||
m_vertices[v2].m_ancestors.begin(),
|
||||
m_vertices[v2].m_ancestors.end());
|
||||
// update adjacency information
|
||||
std::set<long> & v1Edges = m_vertices[v1].m_edges;
|
||||
std::set<long>::const_iterator ed(m_vertices[v2].m_edges.begin());
|
||||
std::set<long>::const_iterator itEnd(m_vertices[v2].m_edges.end());
|
||||
long b = -1;
|
||||
for(; ed != itEnd; ++ed)
|
||||
{
|
||||
if (m_edges[*ed].m_v1 == v2)
|
||||
{
|
||||
b = m_edges[*ed].m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
b = m_edges[*ed].m_v1;
|
||||
}
|
||||
if (GetEdgeID(v1, b) >= 0)
|
||||
{
|
||||
m_edges[*ed].m_deleted = true;
|
||||
m_vertices[b].DeleteEdge(*ed);
|
||||
m_nE--;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_edges[*ed].m_v1 = v1;
|
||||
m_edges[*ed].m_v2 = b;
|
||||
v1Edges.insert(*ed);
|
||||
}
|
||||
}
|
||||
// delete the vertex v2
|
||||
DeleteVertex(v2);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
long Graph::GetEdgeID(long v1, long v2) const
|
||||
{
|
||||
if (v1 < static_cast<long>(m_vertices.size()) && !m_vertices[v1].m_deleted)
|
||||
{
|
||||
std::set<long>::const_iterator ed(m_vertices[v1].m_edges.begin());
|
||||
std::set<long>::const_iterator itEnd(m_vertices[v1].m_edges.end());
|
||||
for(; ed != itEnd; ++ed)
|
||||
{
|
||||
if ( (m_edges[*ed].m_v1 == v2) ||
|
||||
(m_edges[*ed].m_v2 == v2) )
|
||||
{
|
||||
return m_edges[*ed].m_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Graph::Print() const
|
||||
{
|
||||
std::cout << "-----------------------------" << std::endl;
|
||||
std::cout << "vertices (" << m_nV << ")" << std::endl;
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
const GraphVertex & currentVertex = m_vertices[v];
|
||||
if (!m_vertices[v].m_deleted)
|
||||
{
|
||||
|
||||
std::cout << currentVertex.m_name << "\t";
|
||||
std::set<long>::const_iterator ed(currentVertex.m_edges.begin());
|
||||
std::set<long>::const_iterator itEnd(currentVertex.m_edges.end());
|
||||
for(; ed != itEnd; ++ed)
|
||||
{
|
||||
std::cout << "(" << m_edges[*ed].m_v1 << "," << m_edges[*ed].m_v2 << ") ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "vertices (" << m_nE << ")" << std::endl;
|
||||
for (size_t e = 0; e < m_edges.size(); ++e)
|
||||
{
|
||||
const GraphEdge & currentEdge = m_edges[e];
|
||||
if (!m_edges[e].m_deleted)
|
||||
{
|
||||
std::cout << currentEdge.m_name << "\t("
|
||||
<< m_edges[e].m_v1 << ","
|
||||
<< m_edges[e].m_v2 << ") "<< std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
void Graph::Clear()
|
||||
{
|
||||
m_vertices.clear();
|
||||
m_edges.clear();
|
||||
m_nV = 0;
|
||||
m_nE = 0;
|
||||
}
|
||||
|
||||
long Graph::ExtractCCs()
|
||||
{
|
||||
// all CCs to -1
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
if (!m_vertices[v].m_deleted)
|
||||
{
|
||||
m_vertices[v].m_cc = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// we get the CCs
|
||||
m_nCCs = 0;
|
||||
long v2 = -1;
|
||||
std::vector<long> temp;
|
||||
for (size_t v = 0; v < m_vertices.size(); ++v)
|
||||
{
|
||||
if (!m_vertices[v].m_deleted && m_vertices[v].m_cc == -1)
|
||||
{
|
||||
m_vertices[v].m_cc = static_cast<long>(m_nCCs);
|
||||
temp.clear();
|
||||
temp.push_back(m_vertices[v].m_name);
|
||||
while (temp.size())
|
||||
{
|
||||
long vertex = temp[temp.size()-1];
|
||||
temp.pop_back();
|
||||
std::set<long>::const_iterator ed(m_vertices[vertex].m_edges.begin());
|
||||
std::set<long>::const_iterator itEnd(m_vertices[vertex].m_edges.end());
|
||||
for(; ed != itEnd; ++ed)
|
||||
{
|
||||
if (m_edges[*ed].m_v1 == vertex)
|
||||
{
|
||||
v2 = m_edges[*ed].m_v2;
|
||||
}
|
||||
else
|
||||
{
|
||||
v2 = m_edges[*ed].m_v1;
|
||||
}
|
||||
if ( !m_vertices[v2].m_deleted && m_vertices[v2].m_cc == -1)
|
||||
{
|
||||
m_vertices[v2].m_cc = static_cast<long>(m_nCCs);
|
||||
temp.push_back(v2);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_nCCs++;
|
||||
}
|
||||
}
|
||||
return static_cast<long>(m_nCCs);
|
||||
}
|
||||
}
|
120
extern/HACD/hacdGraph.h
vendored
Normal file
120
extern/HACD/hacdGraph.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 HACD_GRAPH_H
|
||||
#define HACD_GRAPH_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdICHull.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
class GraphVertex;
|
||||
class GraphEdge;
|
||||
class Graph;
|
||||
class HACD;
|
||||
|
||||
class GraphVertex
|
||||
{
|
||||
public:
|
||||
bool AddEdge(long name)
|
||||
{
|
||||
m_edges.insert(name);
|
||||
return true;
|
||||
}
|
||||
bool DeleteEdge(long name);
|
||||
GraphVertex();
|
||||
~GraphVertex(){ delete m_convexHull;};
|
||||
private:
|
||||
long m_name;
|
||||
long m_cc;
|
||||
std::set<long> m_edges;
|
||||
bool m_deleted;
|
||||
std::vector<long> m_ancestors;
|
||||
std::map<long, DPoint> m_distPoints;
|
||||
|
||||
Real m_error;
|
||||
double m_surf;
|
||||
double m_volume;
|
||||
double m_perimeter;
|
||||
double m_concavity;
|
||||
ICHull * m_convexHull;
|
||||
std::set<unsigned long long> m_boudaryEdges;
|
||||
|
||||
|
||||
friend class GraphEdge;
|
||||
friend class Graph;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
class GraphEdge
|
||||
{
|
||||
public:
|
||||
GraphEdge();
|
||||
~GraphEdge(){delete m_convexHull;};
|
||||
private:
|
||||
long m_name;
|
||||
long m_v1;
|
||||
long m_v2;
|
||||
std::map<long, DPoint> m_distPoints;
|
||||
Real m_error;
|
||||
double m_surf;
|
||||
double m_volume;
|
||||
double m_perimeter;
|
||||
double m_concavity;
|
||||
ICHull * m_convexHull;
|
||||
std::set<unsigned long long> m_boudaryEdges;
|
||||
bool m_deleted;
|
||||
|
||||
|
||||
|
||||
friend class GraphVertex;
|
||||
friend class Graph;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
class Graph
|
||||
{
|
||||
public:
|
||||
size_t GetNEdges() const { return m_nE;}
|
||||
size_t GetNVertices() const { return m_nV;}
|
||||
bool EdgeCollapse(long v1, long v2);
|
||||
long AddVertex();
|
||||
long AddEdge(long v1, long v2);
|
||||
bool DeleteEdge(long name);
|
||||
bool DeleteVertex(long name);
|
||||
long GetEdgeID(long v1, long v2) const;
|
||||
void Clear();
|
||||
void Print() const;
|
||||
long ExtractCCs();
|
||||
|
||||
Graph();
|
||||
virtual ~Graph();
|
||||
void Allocate(size_t nV, size_t nE);
|
||||
|
||||
private:
|
||||
size_t m_nCCs;
|
||||
size_t m_nV;
|
||||
size_t m_nE;
|
||||
std::vector<GraphEdge> m_edges;
|
||||
std::vector<GraphVertex> m_vertices;
|
||||
|
||||
friend class HACD;
|
||||
};
|
||||
}
|
||||
#endif
|
847
extern/HACD/hacdHACD.cpp
vendored
Normal file
847
extern/HACD/hacdHACD.cpp
vendored
Normal file
@@ -0,0 +1,847 @@
|
||||
/* 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 //_CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <sstream>
|
||||
#include "hacdGraph.h"
|
||||
#include "hacdHACD.h"
|
||||
#include "hacdICHull.h"
|
||||
#include <string.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
bool gCancelRequest=false;
|
||||
namespace HACD
|
||||
{
|
||||
double HACD::Concavity(ICHull & ch, std::map<long, DPoint> & distPoints)
|
||||
{
|
||||
double concavity = 0.0;
|
||||
double distance = 0.0;
|
||||
std::map<long, DPoint>::iterator itDP(distPoints.begin());
|
||||
std::map<long, DPoint>::iterator itDPEnd(distPoints.end());
|
||||
for(; itDP != itDPEnd; ++itDP)
|
||||
{
|
||||
if (!(itDP->second).m_computed)
|
||||
{
|
||||
if (itDP->first >= 0)
|
||||
{
|
||||
distance = ch.ComputeDistance(itDP->first, m_points[itDP->first], m_normals[itDP->first], (itDP->second).m_computed, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = ch.ComputeDistance(itDP->first, m_facePoints[-itDP->first-1], m_faceNormals[-itDP->first-1], (itDP->second).m_computed, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
distance = (itDP->second).m_dist;
|
||||
}
|
||||
if (concavity < distance)
|
||||
{
|
||||
concavity = distance;
|
||||
}
|
||||
}
|
||||
return concavity;
|
||||
}
|
||||
|
||||
void HACD::CreateGraph()
|
||||
{
|
||||
// vertex to triangle adjacency information
|
||||
std::vector< std::set<long> > vertexToTriangles;
|
||||
vertexToTriangles.resize(m_nPoints);
|
||||
for(size_t t = 0; t < m_nTriangles; ++t)
|
||||
{
|
||||
vertexToTriangles[m_triangles[t].X()].insert(static_cast<long>(t));
|
||||
vertexToTriangles[m_triangles[t].Y()].insert(static_cast<long>(t));
|
||||
vertexToTriangles[m_triangles[t].Z()].insert(static_cast<long>(t));
|
||||
}
|
||||
|
||||
m_graph.Clear();
|
||||
m_graph.Allocate(m_nTriangles, 5 * m_nTriangles);
|
||||
unsigned long long tr1[3];
|
||||
unsigned long long tr2[3];
|
||||
long i1, j1, k1, i2, j2, k2;
|
||||
long t1, t2;
|
||||
for (size_t v = 0; v < m_nPoints; v++)
|
||||
{
|
||||
std::set<long>::const_iterator it1(vertexToTriangles[v].begin()), itEnd(vertexToTriangles[v].end());
|
||||
for(; it1 != itEnd; ++it1)
|
||||
{
|
||||
t1 = *it1;
|
||||
i1 = m_triangles[t1].X();
|
||||
j1 = m_triangles[t1].Y();
|
||||
k1 = m_triangles[t1].Z();
|
||||
tr1[0] = GetEdgeIndex(i1, j1);
|
||||
tr1[1] = GetEdgeIndex(j1, k1);
|
||||
tr1[2] = GetEdgeIndex(k1, i1);
|
||||
std::set<long>::const_iterator it2(it1);
|
||||
for(++it2; it2 != itEnd; ++it2)
|
||||
{
|
||||
t2 = *it2;
|
||||
i2 = m_triangles[t2].X();
|
||||
j2 = m_triangles[t2].Y();
|
||||
k2 = m_triangles[t2].Z();
|
||||
tr2[0] = GetEdgeIndex(i2, j2);
|
||||
tr2[1] = GetEdgeIndex(j2, k2);
|
||||
tr2[2] = GetEdgeIndex(k2, i2);
|
||||
int shared = 0;
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
for(int j = 0; j < 3; ++j)
|
||||
{
|
||||
if (tr1[i] == tr2[j])
|
||||
{
|
||||
shared++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (shared == 1) // two triangles are connected if they share exactly one edge
|
||||
{
|
||||
m_graph.AddEdge(t1, t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_ccConnectDist >= 0.0)
|
||||
{
|
||||
m_graph.ExtractCCs();
|
||||
if (m_graph.m_nCCs > 1)
|
||||
{
|
||||
std::vector< std::set<long> > cc2V;
|
||||
cc2V.resize(m_graph.m_nCCs);
|
||||
long cc;
|
||||
for(size_t t = 0; t < m_nTriangles; ++t)
|
||||
{
|
||||
cc = m_graph.m_vertices[t].m_cc;
|
||||
cc2V[cc].insert(m_triangles[t].X());
|
||||
cc2V[cc].insert(m_triangles[t].Y());
|
||||
cc2V[cc].insert(m_triangles[t].Z());
|
||||
}
|
||||
|
||||
for(size_t cc1 = 0; cc1 < m_graph.m_nCCs; ++cc1)
|
||||
{
|
||||
for(size_t cc2 = cc1+1; cc2 < m_graph.m_nCCs; ++cc2)
|
||||
{
|
||||
std::set<long>::const_iterator itV1(cc2V[cc1].begin()), itVEnd1(cc2V[cc1].end());
|
||||
for(; itV1 != itVEnd1; ++itV1)
|
||||
{
|
||||
double distC1C2 = std::numeric_limits<double>::max();
|
||||
double dist;
|
||||
t1 = -1;
|
||||
t2 = -1;
|
||||
std::set<long>::const_iterator itV2(cc2V[cc2].begin()), itVEnd2(cc2V[cc2].end());
|
||||
for(; itV2 != itVEnd2; ++itV2)
|
||||
{
|
||||
dist = (m_points[*itV1] - m_points[*itV2]).GetNorm();
|
||||
if (dist < distC1C2)
|
||||
{
|
||||
distC1C2 = dist;
|
||||
t1 = *vertexToTriangles[*itV1].begin();
|
||||
|
||||
std::set<long>::const_iterator it2(vertexToTriangles[*itV2].begin()),
|
||||
it2End(vertexToTriangles[*itV2].end());
|
||||
t2 = -1;
|
||||
for(; it2 != it2End; ++it2)
|
||||
{
|
||||
if (*it2 != t1)
|
||||
{
|
||||
t2 = *it2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (distC1C2 <= m_ccConnectDist && t1 > 0 && t2 > 0)
|
||||
{
|
||||
|
||||
m_graph.AddEdge(t1, t2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void HACD::InitializeDualGraph()
|
||||
{
|
||||
long i, j, k;
|
||||
Vec3<Real> u, v, w, normal;
|
||||
delete [] m_normals;
|
||||
m_normals = new Vec3<Real>[m_nPoints];
|
||||
if (m_addFacesPoints)
|
||||
{
|
||||
delete [] m_facePoints;
|
||||
delete [] m_faceNormals;
|
||||
m_facePoints = new Vec3<Real>[m_nTriangles];
|
||||
m_faceNormals = new Vec3<Real>[m_nTriangles];
|
||||
}
|
||||
memset(m_normals, 0, sizeof(Vec3<Real>) * m_nPoints);
|
||||
for(unsigned long f = 0; f < m_nTriangles; f++)
|
||||
{
|
||||
if (m_callBack) (*m_callBack)("+ InitializeDualGraph\n", f, m_nTriangles, 0);
|
||||
|
||||
if (gCancelRequest)
|
||||
return;
|
||||
|
||||
i = m_triangles[f].X();
|
||||
j = m_triangles[f].Y();
|
||||
k = m_triangles[f].Z();
|
||||
|
||||
m_graph.m_vertices[f].m_distPoints[i].m_distOnly = false;
|
||||
m_graph.m_vertices[f].m_distPoints[j].m_distOnly = false;
|
||||
m_graph.m_vertices[f].m_distPoints[k].m_distOnly = false;
|
||||
|
||||
ICHull * ch = new ICHull;
|
||||
m_graph.m_vertices[f].m_convexHull = ch;
|
||||
ch->AddPoint(m_points[i], i);
|
||||
ch->AddPoint(m_points[j], j);
|
||||
ch->AddPoint(m_points[k], k);
|
||||
ch->SetDistPoints(&m_graph.m_vertices[f].m_distPoints);
|
||||
|
||||
u = m_points[j] - m_points[i];
|
||||
v = m_points[k] - m_points[i];
|
||||
w = m_points[k] - m_points[j];
|
||||
normal = u ^ v;
|
||||
|
||||
m_normals[i] += normal;
|
||||
m_normals[j] += normal;
|
||||
m_normals[k] += normal;
|
||||
|
||||
m_graph.m_vertices[f].m_surf = normal.GetNorm();
|
||||
m_graph.m_vertices[f].m_perimeter = u.GetNorm() + v.GetNorm() + w.GetNorm();
|
||||
|
||||
normal.Normalize();
|
||||
|
||||
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(i,j));
|
||||
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(j,k));
|
||||
m_graph.m_vertices[f].m_boudaryEdges.insert(GetEdgeIndex(k,i));
|
||||
if(m_addFacesPoints)
|
||||
{
|
||||
m_faceNormals[f] = normal;
|
||||
m_facePoints[f] = (m_points[i] + m_points[j] + m_points[k]) / 3.0;
|
||||
m_graph.m_vertices[f].m_distPoints[-static_cast<long>(f)-1].m_distOnly = true;
|
||||
}
|
||||
if (m_addExtraDistPoints)
|
||||
{// we need a kd-tree structure to accelerate this part!
|
||||
long i1, j1, k1;
|
||||
Vec3<Real> u1, v1, normal1;
|
||||
normal = -normal;
|
||||
double distance = 0.0;
|
||||
double distMin = 0.0;
|
||||
size_t faceIndex = m_nTriangles;
|
||||
Vec3<Real> seedPoint((m_points[i] + m_points[j] + m_points[k]) / 3.0);
|
||||
long nhit = 0;
|
||||
for(size_t f1 = 0; f1 < m_nTriangles; f1++)
|
||||
{
|
||||
i1 = m_triangles[f1].X();
|
||||
j1 = m_triangles[f1].Y();
|
||||
k1 = m_triangles[f1].Z();
|
||||
u1 = m_points[j1] - m_points[i1];
|
||||
v1 = m_points[k1] - m_points[i1];
|
||||
normal1 = (u1 ^ v1);
|
||||
if (normal * normal1 > 0.0)
|
||||
{
|
||||
nhit = IntersectRayTriangle(Vec3<double>(seedPoint.X(), seedPoint.Y(), seedPoint.Z()),
|
||||
Vec3<double>(normal.X(), normal.Y(), normal.Z()),
|
||||
Vec3<double>(m_points[i1].X(), m_points[i1].Y(), m_points[i1].Z()),
|
||||
Vec3<double>(m_points[j1].X(), m_points[j1].Y(), m_points[j1].Z()),
|
||||
Vec3<double>(m_points[k1].X(), m_points[k1].Y(), m_points[k1].Z()),
|
||||
distance);
|
||||
if ((nhit==1) && ((distMin > distance) || (faceIndex == m_nTriangles)))
|
||||
{
|
||||
distMin = distance;
|
||||
faceIndex = f1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (faceIndex < m_nTriangles )
|
||||
{
|
||||
i1 = m_triangles[faceIndex].X();
|
||||
j1 = m_triangles[faceIndex].Y();
|
||||
k1 = m_triangles[faceIndex].Z();
|
||||
m_graph.m_vertices[f].m_distPoints[i1].m_distOnly = true;
|
||||
m_graph.m_vertices[f].m_distPoints[j1].m_distOnly = true;
|
||||
m_graph.m_vertices[f].m_distPoints[k1].m_distOnly = true;
|
||||
if (m_addFacesPoints)
|
||||
{
|
||||
m_graph.m_vertices[f].m_distPoints[-static_cast<long>(faceIndex)-1].m_distOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t v = 0; v < m_nPoints; v++)
|
||||
{
|
||||
m_normals[v].Normalize();
|
||||
}
|
||||
}
|
||||
|
||||
void HACD::NormalizeData()
|
||||
{
|
||||
if (m_nPoints == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_barycenter = m_points[0];
|
||||
Vec3<Real> min = m_points[0];
|
||||
Vec3<Real> max = m_points[0];
|
||||
Real x, y, z;
|
||||
for (size_t v = 1; v < m_nPoints ; v++)
|
||||
{
|
||||
m_barycenter += m_points[v];
|
||||
x = m_points[v].X();
|
||||
y = m_points[v].Y();
|
||||
z = m_points[v].Z();
|
||||
if ( x < min.X()) min.X() = x;
|
||||
else if ( x > max.X()) max.X() = x;
|
||||
if ( y < min.Y()) min.Y() = y;
|
||||
else if ( y > max.Y()) max.Y() = y;
|
||||
if ( z < min.Z()) min.Z() = z;
|
||||
else if ( z > max.Z()) max.Z() = z;
|
||||
}
|
||||
m_barycenter /= static_cast<Real>(m_nPoints);
|
||||
m_diag = (max-min).GetNorm();
|
||||
const Real invDiag = static_cast<Real>(2.0 * m_scale / m_diag);
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
for (size_t v = 0; v < m_nPoints ; v++)
|
||||
{
|
||||
m_points[v] = (m_points[v] - m_barycenter) * invDiag;
|
||||
}
|
||||
}
|
||||
}
|
||||
void HACD::DenormalizeData()
|
||||
{
|
||||
if (m_nPoints == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
const Real diag = static_cast<Real>(m_diag / (2.0 * m_scale));
|
||||
for (size_t v = 0; v < m_nPoints ; v++)
|
||||
{
|
||||
m_points[v] = m_points[v] * diag + m_barycenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
HACD::HACD(void)
|
||||
{
|
||||
m_convexHulls = 0;
|
||||
m_triangles = 0;
|
||||
m_points = 0;
|
||||
m_normals = 0;
|
||||
m_nTriangles = 0;
|
||||
m_nPoints = 0;
|
||||
m_nClusters = 0;
|
||||
m_concavity = 0.0;
|
||||
m_diag = 1.0;
|
||||
m_barycenter = Vec3<Real>(0.0, 0.0,0.0);
|
||||
m_alpha = 0.1;
|
||||
m_beta = 0.1;
|
||||
m_nVerticesPerCH = 30;
|
||||
m_callBack = 0;
|
||||
m_addExtraDistPoints = false;
|
||||
m_addNeighboursDistPoints = false;
|
||||
m_scale = 1000.0;
|
||||
m_partition = 0;
|
||||
m_nMinClusters = 3;
|
||||
m_facePoints = 0;
|
||||
m_faceNormals = 0;
|
||||
m_ccConnectDist = 30;
|
||||
}
|
||||
HACD::~HACD(void)
|
||||
{
|
||||
delete [] m_normals;
|
||||
delete [] m_convexHulls;
|
||||
delete [] m_partition;
|
||||
delete [] m_facePoints;
|
||||
delete [] m_faceNormals;
|
||||
}
|
||||
int iteration = 0;
|
||||
void HACD::ComputeEdgeCost(size_t e)
|
||||
{
|
||||
GraphEdge & gE = m_graph.m_edges[e];
|
||||
long v1 = gE.m_v1;
|
||||
long v2 = gE.m_v2;
|
||||
|
||||
if (m_graph.m_vertices[v2].m_distPoints.size()>m_graph.m_vertices[v1].m_distPoints.size())
|
||||
{
|
||||
gE.m_v1 = v2;
|
||||
gE.m_v2 = v1;
|
||||
//std::swap<long>(v1, v2);
|
||||
std::swap(v1, v2);
|
||||
}
|
||||
GraphVertex & gV1 = m_graph.m_vertices[v1];
|
||||
GraphVertex & gV2 = m_graph.m_vertices[v2];
|
||||
|
||||
// delete old convex-hull
|
||||
delete gE.m_convexHull;
|
||||
// create the edge's convex-hull
|
||||
ICHull * ch = new ICHull;
|
||||
gE.m_convexHull = ch;
|
||||
(*ch) = (*gV1.m_convexHull);
|
||||
|
||||
// update distPoints
|
||||
gE.m_distPoints = gV1.m_distPoints;
|
||||
std::map<long, DPoint>::iterator itDP(gV2.m_distPoints.begin());
|
||||
std::map<long, DPoint>::iterator itDPEnd(gV2.m_distPoints.end());
|
||||
std::map<long, DPoint>::iterator itDP1;
|
||||
|
||||
for(; itDP != itDPEnd; ++itDP)
|
||||
{
|
||||
itDP1 = gE.m_distPoints.find(itDP->first);
|
||||
if (itDP1 == gE.m_distPoints.end())
|
||||
{
|
||||
gE.m_distPoints[itDP->first].m_distOnly = (itDP->second).m_distOnly;
|
||||
if ( !(itDP->second).m_distOnly )
|
||||
{
|
||||
ch->AddPoint(m_points[itDP->first], itDP->first);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( (itDP1->second).m_distOnly && !(itDP->second).m_distOnly)
|
||||
{
|
||||
gE.m_distPoints[itDP->first].m_distOnly = false;
|
||||
ch->AddPoint(m_points[itDP->first], itDP->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ch->SetDistPoints(&gE.m_distPoints);
|
||||
// create the convex-hull
|
||||
while (ch->Process() == ICHullErrorInconsistent) // if we face problems when constructing the visual-hull. really ugly!!!!
|
||||
{
|
||||
// if (m_callBack) (*m_callBack)("\t Problem with convex-hull construction [HACD::ComputeEdgeCost]\n", 0.0, 0.0, 0);
|
||||
ch = new ICHull;
|
||||
CircularList<TMMVertex> & verticesCH = (gE.m_convexHull)->GetMesh().m_vertices;
|
||||
size_t nV = verticesCH.GetSize();
|
||||
long ptIndex = 0;
|
||||
verticesCH.Next();
|
||||
for(size_t v = 1; v < nV; ++v)
|
||||
{
|
||||
ptIndex = verticesCH.GetHead()->GetData().m_name;
|
||||
ch->AddPoint(m_points[ptIndex], ptIndex);
|
||||
verticesCH.Next();
|
||||
}
|
||||
delete gE.m_convexHull;
|
||||
gE.m_convexHull = ch;
|
||||
}
|
||||
double volume = 0.0;
|
||||
double concavity = 0.0;
|
||||
if (ch->IsFlat())
|
||||
{
|
||||
bool insideHull;
|
||||
std::map<long, DPoint>::iterator itDP(gE.m_distPoints.begin());
|
||||
std::map<long, DPoint>::iterator itDPEnd(gE.m_distPoints.end());
|
||||
for(; itDP != itDPEnd; ++itDP)
|
||||
{
|
||||
if (itDP->first >= 0)
|
||||
{
|
||||
concavity = std::max<double>(concavity, ch->ComputeDistance(itDP->first, m_points[itDP->first], m_normals[itDP->first], insideHull, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_addNeighboursDistPoints)
|
||||
{ // add distance points from adjacent clusters
|
||||
std::set<long> eEdges;
|
||||
std::set_union(gV1.m_edges.begin(),
|
||||
gV1.m_edges.end(),
|
||||
gV2.m_edges.begin(),
|
||||
gV2.m_edges.end(),
|
||||
std::inserter( eEdges, eEdges.begin() ) );
|
||||
|
||||
std::set<long>::const_iterator ed(eEdges.begin());
|
||||
std::set<long>::const_iterator itEnd(eEdges.end());
|
||||
long a, b, c;
|
||||
for(; ed != itEnd; ++ed)
|
||||
{
|
||||
a = m_graph.m_edges[*ed].m_v1;
|
||||
b = m_graph.m_edges[*ed].m_v2;
|
||||
if ( a != v2 && a != v1)
|
||||
{
|
||||
c = a;
|
||||
}
|
||||
else if ( b != v2 && b != v1)
|
||||
{
|
||||
c = b;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = -1;
|
||||
}
|
||||
if ( c > 0)
|
||||
{
|
||||
GraphVertex & gVC = m_graph.m_vertices[c];
|
||||
std::map<long, DPoint>::iterator itDP(gVC.m_distPoints.begin());
|
||||
std::map<long, DPoint>::iterator itDPEnd(gVC.m_distPoints.end());
|
||||
std::map<long, DPoint>::iterator itDP1;
|
||||
for(; itDP != itDPEnd; ++itDP)
|
||||
{
|
||||
itDP1 = gE.m_distPoints.find(itDP->first);
|
||||
if (itDP1 == gE.m_distPoints.end())
|
||||
{
|
||||
if (itDP->first >= 0 && itDP1 == gE.m_distPoints.end() && ch->IsInside(m_points[itDP->first]))
|
||||
{
|
||||
gE.m_distPoints[itDP->first].m_distOnly = true;
|
||||
}
|
||||
else if (itDP->first < 0 && ch->IsInside(m_facePoints[-itDP->first-1]))
|
||||
{
|
||||
gE.m_distPoints[itDP->first].m_distOnly = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
concavity = Concavity(*ch, gE.m_distPoints);
|
||||
}
|
||||
|
||||
// compute boudary edges
|
||||
double perimeter = 0.0;
|
||||
double surf = 1.0;
|
||||
if (m_alpha > 0.0)
|
||||
{
|
||||
gE.m_boudaryEdges.clear();
|
||||
std::set_symmetric_difference (gV1.m_boudaryEdges.begin(),
|
||||
gV1.m_boudaryEdges.end(),
|
||||
gV2.m_boudaryEdges.begin(),
|
||||
gV2.m_boudaryEdges.end(),
|
||||
std::inserter( gE.m_boudaryEdges,
|
||||
gE.m_boudaryEdges.begin() ) );
|
||||
|
||||
std::set<unsigned long long>::const_iterator itBE(gE.m_boudaryEdges.begin());
|
||||
std::set<unsigned long long>::const_iterator itBEEnd(gE.m_boudaryEdges.end());
|
||||
for(; itBE != itBEEnd; ++itBE)
|
||||
{
|
||||
perimeter += (m_points[static_cast<long>((*itBE) >> 32)] -
|
||||
m_points[static_cast<long>((*itBE) & 0xFFFFFFFFULL)]).GetNorm();
|
||||
}
|
||||
surf = gV1.m_surf + gV2.m_surf;
|
||||
}
|
||||
double ratio = perimeter * perimeter / (4.0 * sc_pi * surf);
|
||||
gE.m_volume = (m_beta == 0.0)?0.0:ch->ComputeVolume()/pow(m_scale, 3.0); // cluster's volume
|
||||
gE.m_surf = surf; // cluster's area
|
||||
gE.m_perimeter = perimeter; // cluster's perimeter
|
||||
gE.m_concavity = concavity; // cluster's concavity
|
||||
gE.m_error = static_cast<Real>(concavity + m_alpha * ratio + m_beta * volume); // cluster's priority
|
||||
}
|
||||
bool HACD::InitializePriorityQueue()
|
||||
{
|
||||
m_pqueue.reserve(m_graph.m_nE + 100);
|
||||
for (size_t e=0; e < m_graph.m_nE; ++e)
|
||||
{
|
||||
ComputeEdgeCost(static_cast<long>(e));
|
||||
m_pqueue.push(GraphEdgePriorityQueue(static_cast<long>(e), m_graph.m_edges[e].m_error));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void HACD::Simplify()
|
||||
{
|
||||
long v1 = -1;
|
||||
long v2 = -1;
|
||||
double progressOld = -1.0;
|
||||
double progress = 0.0;
|
||||
double globalConcavity = 0.0;
|
||||
char msg[1024];
|
||||
double ptgStep = 1.0;
|
||||
while ( (globalConcavity < m_concavity) &&
|
||||
(m_graph.GetNVertices() > m_nMinClusters) &&
|
||||
(m_graph.GetNEdges() > 0))
|
||||
{
|
||||
progress = 100.0-m_graph.GetNVertices() * 100.0 / m_nTriangles;
|
||||
if (fabs(progress-progressOld) > ptgStep && m_callBack)
|
||||
{
|
||||
sprintf(msg, "%3.2f %% V = %lu \t C = %f \t \t \r", progress, static_cast<unsigned long>(m_graph.GetNVertices()), globalConcavity);
|
||||
(*m_callBack)(msg, progress, globalConcavity, m_graph.GetNVertices());
|
||||
progressOld = progress;
|
||||
if (progress > 99.0)
|
||||
{
|
||||
ptgStep = 0.01;
|
||||
}
|
||||
else if (progress > 90.0)
|
||||
{
|
||||
ptgStep = 0.1;
|
||||
}
|
||||
}
|
||||
|
||||
GraphEdgePriorityQueue currentEdge(0,0.0);
|
||||
bool done = false;
|
||||
do
|
||||
{
|
||||
done = false;
|
||||
if (m_pqueue.size() == 0)
|
||||
{
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
currentEdge = m_pqueue.top();
|
||||
m_pqueue.pop();
|
||||
}
|
||||
while ( m_graph.m_edges[currentEdge.m_name].m_deleted ||
|
||||
m_graph.m_edges[currentEdge.m_name].m_error != currentEdge.m_priority);
|
||||
|
||||
|
||||
if (m_graph.m_edges[currentEdge.m_name].m_concavity < m_concavity && !done)
|
||||
{
|
||||
globalConcavity = std::max<double>(globalConcavity ,m_graph.m_edges[currentEdge.m_name].m_concavity);
|
||||
v1 = m_graph.m_edges[currentEdge.m_name].m_v1;
|
||||
v2 = m_graph.m_edges[currentEdge.m_name].m_v2;
|
||||
// update vertex info
|
||||
m_graph.m_vertices[v1].m_error = m_graph.m_edges[currentEdge.m_name].m_error;
|
||||
m_graph.m_vertices[v1].m_surf = m_graph.m_edges[currentEdge.m_name].m_surf;
|
||||
m_graph.m_vertices[v1].m_volume = m_graph.m_edges[currentEdge.m_name].m_volume;
|
||||
m_graph.m_vertices[v1].m_concavity = m_graph.m_edges[currentEdge.m_name].m_concavity;
|
||||
m_graph.m_vertices[v1].m_perimeter = m_graph.m_edges[currentEdge.m_name].m_perimeter;
|
||||
m_graph.m_vertices[v1].m_distPoints = m_graph.m_edges[currentEdge.m_name].m_distPoints;
|
||||
(*m_graph.m_vertices[v1].m_convexHull) = (*m_graph.m_edges[currentEdge.m_name].m_convexHull);
|
||||
(m_graph.m_vertices[v1].m_convexHull)->SetDistPoints(&(m_graph.m_vertices[v1].m_distPoints));
|
||||
m_graph.m_vertices[v1].m_boudaryEdges = m_graph.m_edges[currentEdge.m_name].m_boudaryEdges;
|
||||
|
||||
// We apply the optimal ecol
|
||||
// std::cout << "v1 " << v1 << " v2 " << v2 << std::endl;
|
||||
m_graph.EdgeCollapse(v1, v2);
|
||||
// recompute the adjacent edges costs
|
||||
std::set<long>::const_iterator itE(m_graph.m_vertices[v1].m_edges.begin()),
|
||||
itEEnd(m_graph.m_vertices[v1].m_edges.end());
|
||||
for(; itE != itEEnd; ++itE)
|
||||
{
|
||||
size_t e = *itE;
|
||||
ComputeEdgeCost(static_cast<long>(e));
|
||||
m_pqueue.push(GraphEdgePriorityQueue(static_cast<long>(e), m_graph.m_edges[e].m_error));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (!m_pqueue.empty())
|
||||
{
|
||||
m_pqueue.pop();
|
||||
}
|
||||
|
||||
m_cVertices.clear();
|
||||
m_nClusters = m_graph.GetNVertices();
|
||||
m_cVertices.reserve(m_nClusters);
|
||||
for (size_t p=0, v = 0; v != m_graph.m_vertices.size(); ++v)
|
||||
{
|
||||
if (!m_graph.m_vertices[v].m_deleted)
|
||||
{
|
||||
if (m_callBack)
|
||||
{
|
||||
char msg[1024];
|
||||
sprintf(msg, "\t CH \t %lu \t %lf \t %lf\n", static_cast<unsigned long>(p), m_graph.m_vertices[v].m_concavity, m_graph.m_vertices[v].m_error);
|
||||
(*m_callBack)(msg, 0.0, 0.0, m_nClusters);
|
||||
p++;
|
||||
}
|
||||
m_cVertices.push_back(static_cast<long>(v));
|
||||
}
|
||||
}
|
||||
if (m_callBack)
|
||||
{
|
||||
sprintf(msg, "# clusters = %lu \t C = %f\n", static_cast<unsigned long>(m_nClusters), globalConcavity);
|
||||
(*m_callBack)(msg, progress, globalConcavity, m_graph.GetNVertices());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool HACD::Compute(bool fullCH, bool exportDistPoints)
|
||||
{
|
||||
gCancelRequest = false;
|
||||
|
||||
if ( !m_points || !m_triangles || !m_nPoints || !m_nTriangles)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
size_t nV = m_nTriangles;
|
||||
if (m_callBack)
|
||||
{
|
||||
std::ostringstream msg;
|
||||
msg << "+ Mesh" << std::endl;
|
||||
msg << "\t # vertices \t" << m_nPoints << std::endl;
|
||||
msg << "\t # triangles \t" << m_nTriangles << std::endl;
|
||||
msg << "+ Parameters" << std::endl;
|
||||
msg << "\t min # of clusters \t" << m_nMinClusters << std::endl;
|
||||
msg << "\t max concavity \t" << m_concavity << std::endl;
|
||||
msg << "\t compacity weigth \t" << m_alpha << std::endl;
|
||||
msg << "\t volume weigth \t" << m_beta << std::endl;
|
||||
msg << "\t # vertices per convex-hull \t" << m_nVerticesPerCH << std::endl;
|
||||
msg << "\t scale \t" << m_scale << std::endl;
|
||||
msg << "\t add extra distance points \t" << m_addExtraDistPoints << std::endl;
|
||||
msg << "\t add neighbours distance points \t" << m_addNeighboursDistPoints << std::endl;
|
||||
msg << "\t add face distance points \t" << m_addFacesPoints << std::endl;
|
||||
msg << "\t produce full convex-hulls \t" << fullCH << std::endl;
|
||||
msg << "\t max. distance to connect CCs \t" << m_ccConnectDist << std::endl;
|
||||
(*m_callBack)(msg.str().c_str(), 0.0, 0.0, nV);
|
||||
}
|
||||
if (m_callBack) (*m_callBack)("+ Normalizing Data\n", 0.0, 0.0, nV);
|
||||
NormalizeData();
|
||||
if (m_callBack) (*m_callBack)("+ Creating Graph\n", 0.0, 0.0, nV);
|
||||
CreateGraph();
|
||||
// Compute the surfaces and perimeters of all the faces
|
||||
if (m_callBack) (*m_callBack)("+ Initializing Dual Graph\n", 0.0, 0.0, nV);
|
||||
if (gCancelRequest)
|
||||
return false;
|
||||
|
||||
InitializeDualGraph();
|
||||
if (m_callBack) (*m_callBack)("+ Initializing Priority Queue\n", 0.0, 0.0, nV);
|
||||
if (gCancelRequest)
|
||||
return false;
|
||||
|
||||
InitializePriorityQueue();
|
||||
// we simplify the graph
|
||||
if (m_callBack) (*m_callBack)("+ Simplification ...\n", 0.0, 0.0, m_nTriangles);
|
||||
Simplify();
|
||||
if (m_callBack) (*m_callBack)("+ Denormalizing Data\n", 0.0, 0.0, m_nClusters);
|
||||
DenormalizeData();
|
||||
if (m_callBack) (*m_callBack)("+ Computing final convex-hulls\n", 0.0, 0.0, m_nClusters);
|
||||
delete [] m_convexHulls;
|
||||
m_convexHulls = new ICHull[m_nClusters];
|
||||
delete [] m_partition;
|
||||
m_partition = new long [m_nTriangles];
|
||||
for (size_t p = 0; p != m_cVertices.size(); ++p)
|
||||
{
|
||||
size_t v = m_cVertices[p];
|
||||
m_partition[v] = static_cast<long>(p);
|
||||
for(size_t a = 0; a < m_graph.m_vertices[v].m_ancestors.size(); a++)
|
||||
{
|
||||
m_partition[m_graph.m_vertices[v].m_ancestors[a]] = static_cast<long>(p);
|
||||
}
|
||||
// compute the convex-hull
|
||||
const std::map<long, DPoint> & pointsCH = m_graph.m_vertices[v].m_distPoints;
|
||||
std::map<long, DPoint>::const_iterator itCH(pointsCH.begin());
|
||||
std::map<long, DPoint>::const_iterator itCHEnd(pointsCH.end());
|
||||
for(; itCH != itCHEnd; ++itCH)
|
||||
{
|
||||
if (!(itCH->second).m_distOnly)
|
||||
{
|
||||
m_convexHulls[p].AddPoint(m_points[itCH->first], itCH->first);
|
||||
}
|
||||
}
|
||||
m_convexHulls[p].SetDistPoints(&m_graph.m_vertices[v].m_distPoints);
|
||||
if (fullCH)
|
||||
{
|
||||
m_convexHulls[p].Process();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_convexHulls[p].Process(static_cast<unsigned long>(m_nVerticesPerCH));
|
||||
}
|
||||
if (exportDistPoints)
|
||||
{
|
||||
itCH = pointsCH.begin();
|
||||
for(; itCH != itCHEnd; ++itCH)
|
||||
{
|
||||
if ((itCH->second).m_distOnly)
|
||||
{
|
||||
if (itCH->first >= 0)
|
||||
{
|
||||
m_convexHulls[p].AddPoint(m_points[itCH->first], itCH->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_convexHulls[p].AddPoint(m_facePoints[-itCH->first-1], itCH->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t HACD::GetNTrianglesCH(size_t numCH) const
|
||||
{
|
||||
if (numCH >= m_nClusters)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return m_convexHulls[numCH].GetMesh().GetNTriangles();
|
||||
}
|
||||
size_t HACD::GetNPointsCH(size_t numCH) const
|
||||
{
|
||||
if (numCH >= m_nClusters)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return m_convexHulls[numCH].GetMesh().GetNVertices();
|
||||
}
|
||||
|
||||
bool HACD::GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles)
|
||||
{
|
||||
if (numCH >= m_nClusters)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_convexHulls[numCH].GetMesh().GetIFS(points, triangles);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HACD::Save(const char * fileName, bool uniColor, long numCluster) const
|
||||
{
|
||||
std::ofstream fout(fileName);
|
||||
if (fout.is_open())
|
||||
{
|
||||
if (m_callBack)
|
||||
{
|
||||
char msg[1024];
|
||||
sprintf(msg, "Saving %s\n", fileName);
|
||||
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
|
||||
}
|
||||
Material mat;
|
||||
if (numCluster < 0)
|
||||
{
|
||||
for (size_t p = 0; p != m_nClusters; ++p)
|
||||
{
|
||||
if (!uniColor)
|
||||
{
|
||||
mat.m_diffuseColor.X() = mat.m_diffuseColor.Y() = mat.m_diffuseColor.Z() = 0.0;
|
||||
while (mat.m_diffuseColor.X() == mat.m_diffuseColor.Y() ||
|
||||
mat.m_diffuseColor.Z() == mat.m_diffuseColor.Y() ||
|
||||
mat.m_diffuseColor.Z() == mat.m_diffuseColor.X() )
|
||||
{
|
||||
mat.m_diffuseColor.X() = (rand()%100) / 100.0;
|
||||
mat.m_diffuseColor.Y() = (rand()%100) / 100.0;
|
||||
mat.m_diffuseColor.Z() = (rand()%100) / 100.0;
|
||||
}
|
||||
}
|
||||
m_convexHulls[p].GetMesh().SaveVRML2(fout, mat);
|
||||
}
|
||||
}
|
||||
else if (numCluster < static_cast<long>(m_cVertices.size()))
|
||||
{
|
||||
m_convexHulls[numCluster].GetMesh().SaveVRML2(fout, mat);
|
||||
}
|
||||
fout.close();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_callBack)
|
||||
{
|
||||
char msg[1024];
|
||||
sprintf(msg, "Error saving %s\n", fileName);
|
||||
(*m_callBack)(msg, 0.0, 0.0, m_graph.GetNVertices());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
282
extern/HACD/hacdHACD.h
vendored
Normal file
282
extern/HACD/hacdHACD.h
vendored
Normal file
@@ -0,0 +1,282 @@
|
||||
/* 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 HACD_HACD_H
|
||||
#define HACD_HACD_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdVector.h"
|
||||
#include "hacdGraph.h"
|
||||
#include "hacdICHull.h"
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <functional>
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
const double sc_pi = 3.14159265;
|
||||
class HACD;
|
||||
|
||||
// just to be able to set the capcity of the container
|
||||
|
||||
template<class _Ty, class _Container = std::vector<_Ty>, class _Pr = std::less<typename _Container::value_type> >
|
||||
class reservable_priority_queue: public std::priority_queue<_Ty, _Container, _Pr>
|
||||
{
|
||||
typedef typename std::priority_queue<_Ty, _Container, _Pr>::size_type size_type;
|
||||
public:
|
||||
reservable_priority_queue(size_type capacity = 0) { reserve(capacity); };
|
||||
void reserve(size_type capacity) { this->c.reserve(capacity); }
|
||||
size_type capacity() const { return this->c.capacity(); }
|
||||
};
|
||||
|
||||
//! priority queque element
|
||||
class GraphEdgePriorityQueue
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
//! @param name edge's id
|
||||
//! @param priority edge's priority
|
||||
GraphEdgePriorityQueue(long name, Real priority)
|
||||
{
|
||||
m_name = name;
|
||||
m_priority = priority;
|
||||
}
|
||||
//! Destructor
|
||||
~GraphEdgePriorityQueue(void){}
|
||||
private:
|
||||
long m_name; //!< edge name
|
||||
Real m_priority; //!< priority
|
||||
//! Operator < for GraphEdgePQ
|
||||
friend bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
|
||||
//! Operator > for GraphEdgePQ
|
||||
friend bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs);
|
||||
friend class HACD;
|
||||
};
|
||||
inline bool operator<(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
|
||||
{
|
||||
return lhs.m_priority<rhs.m_priority;
|
||||
}
|
||||
inline bool operator>(const GraphEdgePriorityQueue & lhs, const GraphEdgePriorityQueue & rhs)
|
||||
{
|
||||
return lhs.m_priority>rhs.m_priority;
|
||||
}
|
||||
typedef bool (*CallBackFunction)(const char *, double, double, size_t);
|
||||
|
||||
//! Provides an implementation of the Hierarchical Approximate Convex Decomposition (HACD) technique described in "A Simple and Efficient Approach for 3D Mesh Approximate Convex Decomposition" Game Programming Gems 8 - Chapter 2.8, p.202. A short version of the chapter was published in ICIP09 and is available at ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf
|
||||
class HACD
|
||||
{
|
||||
public:
|
||||
|
||||
//! Gives the triangles partitionas an array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
|
||||
//! @return triangles partition
|
||||
const long * const GetPartition() const { return m_partition;}
|
||||
//! Sets the scale factor
|
||||
//! @param scale scale factor
|
||||
void SetScaleFactor(double scale) { m_scale = scale;}
|
||||
//! Gives the scale factor
|
||||
//! @return scale factor
|
||||
const double GetScaleFactor() const { return m_scale;}
|
||||
//! Sets the call-back function
|
||||
//! @param callBack pointer to the call-back function
|
||||
void SetCallBack(CallBackFunction callBack) { m_callBack = callBack;}
|
||||
//! Gives the call-back function
|
||||
//! @return pointer to the call-back function
|
||||
const CallBackFunction GetCallBack() const { return m_callBack;}
|
||||
|
||||
//! Specifies whether faces points should be added when computing the concavity
|
||||
//! @param addFacesPoints true = faces points should be added
|
||||
void SetAddFacesPoints(bool addFacesPoints) { m_addFacesPoints = addFacesPoints;}
|
||||
//! Specifies wheter faces points should be added when computing the concavity
|
||||
//! @return true = faces points should be added
|
||||
const bool GetAddFacesPoints() const { return m_addFacesPoints;}
|
||||
//! Specifies whether extra points should be added when computing the concavity
|
||||
//! @param addExteraDistPoints true = extra points should be added
|
||||
void SetAddExtraDistPoints(bool addExtraDistPoints) { m_addExtraDistPoints = addExtraDistPoints;}
|
||||
//! Specifies wheter extra points should be added when computing the concavity
|
||||
//! @return true = extra points should be added
|
||||
const bool GetAddExtraDistPoints() const { return m_addExtraDistPoints;}
|
||||
//! Specifies whether extra points should be added when computing the concavity
|
||||
//! @param addExteraDistPoints true = extra points should be added
|
||||
void SetAddNeighboursDistPoints(bool addNeighboursDistPoints) { m_addNeighboursDistPoints = addNeighboursDistPoints;}
|
||||
//! Specifies wheter extra points should be added when computing the concavity
|
||||
//! @return true = extra points should be added
|
||||
const bool GetAddNeighboursDistPoints() const { return m_addNeighboursDistPoints;}
|
||||
//! Sets the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
|
||||
//! @param points pointer to the input points
|
||||
void SetPoints(Vec3<Real> * points) { m_points = points;}
|
||||
//! Gives the points of the input mesh (Remark: the input points will be scaled and shifted. Use DenormalizeData() to invert those operations)
|
||||
//! @return pointer to the input points
|
||||
const Vec3<Real> * GetPoints() const { return m_points;}
|
||||
//! Sets the triangles of the input mesh.
|
||||
//! @param triangles points pointer to the input points
|
||||
void SetTriangles(Vec3<long> * triangles) { m_triangles = triangles;}
|
||||
//! Gives the triangles in the input mesh
|
||||
//! @return pointer to the input triangles
|
||||
const Vec3<long> * GetTriangles() const { return m_triangles;}
|
||||
//! Sets the number of points in the input mesh.
|
||||
//! @param nPoints number of points the input mesh
|
||||
void SetNPoints(size_t nPoints) { m_nPoints = nPoints;}
|
||||
//! Gives the number of points in the input mesh.
|
||||
//! @return number of points the input mesh
|
||||
const size_t GetNPoints() const { return m_nPoints;}
|
||||
//! Sets the number of triangles in the input mesh.
|
||||
//! @param nTriangles number of triangles in the input mesh
|
||||
void SetNTriangles(size_t nTriangles) { m_nTriangles = nTriangles;}
|
||||
//! Gives the number of triangles in the input mesh.
|
||||
//! @return number of triangles the input mesh
|
||||
const size_t GetNTriangles() const { return m_nTriangles;}
|
||||
//! Sets the minimum number of clusters to be generated.
|
||||
//! @param nClusters minimum number of clusters
|
||||
void SetNClusters(size_t nClusters) { m_nMinClusters = nClusters;}
|
||||
//! Gives the number of generated clusters.
|
||||
//! @return number of generated clusters
|
||||
const size_t GetNClusters() const { return m_nClusters;}
|
||||
//! Sets the maximum allowed concavity.
|
||||
//! @param concavity maximum concavity
|
||||
void SetConcavity(double concavity) { m_concavity = concavity;}
|
||||
//! Gives the maximum allowed concavity.
|
||||
//! @return maximum concavity
|
||||
double GetConcavity() const { return m_concavity;}
|
||||
//! Sets the maximum allowed distance to get CCs connected.
|
||||
//! @param concavity maximum distance to get CCs connected
|
||||
void SetConnectDist(double ccConnectDist) { m_ccConnectDist = ccConnectDist;}
|
||||
//! Gives the maximum allowed distance to get CCs connected.
|
||||
//! @return maximum distance to get CCs connected
|
||||
double GetConnectDist() const { return m_ccConnectDist;}
|
||||
//! Sets the volume weight.
|
||||
//! @param beta volume weight
|
||||
void SetVolumeWeight(double beta) { m_beta = beta;}
|
||||
//! Gives the volume weight.
|
||||
//! @return volume weight
|
||||
double GetVolumeWeight() const { return m_beta;}
|
||||
//! Sets the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
|
||||
//! @param alpha compacity weight
|
||||
void SetCompacityWeight(double alpha) { m_alpha = alpha;}
|
||||
//! Gives the compacity weight (i.e. parameter alpha in ftp://ftp.elet.polimi.it/users/Stefano.Tubaro/ICIP_USB_Proceedings_v2/pdfs/0003501.pdf).
|
||||
//! @return compacity weight
|
||||
double GetCompacityWeight() const { return m_alpha;}
|
||||
//! Sets the maximum number of vertices for each generated convex-hull.
|
||||
//! @param nVerticesPerCH maximum # vertices per CH
|
||||
void SetNVerticesPerCH(size_t nVerticesPerCH) { m_nVerticesPerCH = nVerticesPerCH;}
|
||||
//! Gives the maximum number of vertices for each generated convex-hull.
|
||||
//! @return maximum # vertices per CH
|
||||
const size_t GetNVerticesPerCH() const { return m_nVerticesPerCH;}
|
||||
//! Gives the number of vertices for the cluster number numCH.
|
||||
//! @return number of vertices
|
||||
size_t GetNPointsCH(size_t numCH) const;
|
||||
//! Gives the number of triangles for the cluster number numCH.
|
||||
//! @param numCH cluster's number
|
||||
//! @return number of triangles
|
||||
size_t GetNTrianglesCH(size_t numCH) const;
|
||||
//! Gives the vertices and the triangles of the cluster number numCH.
|
||||
//! @param numCH cluster's number
|
||||
//! @param points pointer to the vector of points to be filled
|
||||
//! @param triangles pointer to the vector of triangles to be filled
|
||||
//! @return true if sucess
|
||||
bool GetCH(size_t numCH, Vec3<Real> * const points, Vec3<long> * const triangles);
|
||||
//! Computes the HACD decomposition.
|
||||
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
|
||||
//! @param exportDistPoints specifies wheter distance points should ne exported or not (used only for debugging).
|
||||
//! @return true if sucess
|
||||
bool Compute(bool fullCH=false, bool exportDistPoints=false);
|
||||
//! Saves the generated convex-hulls in a VRML 2.0 file.
|
||||
//! @param fileName the output file name
|
||||
//! @param uniColor specifies whether the different convex-hulls should have the same color or not
|
||||
//! @param numCluster specifies the cluster to be saved, if numCluster < 0 export all clusters
|
||||
//! @return true if sucess
|
||||
bool Save(const char * fileName, bool uniColor, long numCluster=-1) const;
|
||||
//! Shifts and scales to the data to have all the coordinates between 0.0 and 1000.0.
|
||||
void NormalizeData();
|
||||
//! Inverse the operations applied by NormalizeData().
|
||||
void DenormalizeData();
|
||||
//! Constructor.
|
||||
HACD(void);
|
||||
//! Destructor.
|
||||
~HACD(void);
|
||||
|
||||
private:
|
||||
//! Gives the edge index.
|
||||
//! @param a first vertex id
|
||||
//! @param b second vertex id
|
||||
//! @return edge's index
|
||||
static unsigned long long GetEdgeIndex(unsigned long long a, unsigned long long b)
|
||||
{
|
||||
if (a > b) return (a << 32) + b;
|
||||
else return (b << 32) + a;
|
||||
}
|
||||
//! Computes the concavity of a cluster.
|
||||
//! @param ch the cluster's convex-hull
|
||||
//! @param distPoints the cluster's points
|
||||
//! @return cluster's concavity
|
||||
double Concavity(ICHull & ch, std::map<long, DPoint> & distPoints);
|
||||
//! Computes the perimeter of a cluster.
|
||||
//! @param triIndices the cluster's triangles
|
||||
//! @param distPoints the cluster's points
|
||||
//! @return cluster's perimeter
|
||||
double ComputePerimeter(const std::vector<long> & triIndices) const;
|
||||
//! Creates the Graph by associating to each mesh triangle a vertex in the graph and to each couple of adjacent triangles an edge in the graph.
|
||||
void CreateGraph();
|
||||
//! Initializes the graph costs and computes the vertices normals
|
||||
void InitializeDualGraph();
|
||||
//! Computes the cost of an edge
|
||||
//! @param e edge's id
|
||||
void ComputeEdgeCost(size_t e);
|
||||
//! Initializes the priority queue
|
||||
//! @param fast specifies whether fast mode is used
|
||||
//! @return true if success
|
||||
bool InitializePriorityQueue();
|
||||
//! Cleans the intersection between convex-hulls
|
||||
void CleanClusters();
|
||||
//! Computes convex-hulls from partition information
|
||||
//! @param fullCH specifies whether to generate convex-hulls with a full or limited (i.e. < m_nVerticesPerCH) number of vertices
|
||||
void ComputeConvexHulls(bool fullCH);
|
||||
//! Simplifies the graph
|
||||
//! @param fast specifies whether fast mode is used
|
||||
void Simplify();
|
||||
|
||||
private:
|
||||
double m_scale; //>! scale factor used for NormalizeData() and DenormalizeData()
|
||||
Vec3<long> * m_triangles; //>! pointer the triangles array
|
||||
Vec3<Real> * m_points; //>! pointer the points array
|
||||
Vec3<Real> * m_facePoints; //>! pointer to the faces points array
|
||||
Vec3<Real> * m_faceNormals; //>! pointer to the faces normals array
|
||||
Vec3<Real> * m_normals; //>! pointer the normals array
|
||||
size_t m_nTriangles; //>! number of triangles in the original mesh
|
||||
size_t m_nPoints; //>! number of vertices in the original mesh
|
||||
size_t m_nClusters; //>! number of clusters
|
||||
size_t m_nMinClusters; //>! minimum number of clusters
|
||||
double m_ccConnectDist; //>! maximum allowed distance to connect CCs
|
||||
double m_concavity; //>! maximum concavity
|
||||
double m_alpha; //>! compacity weigth
|
||||
double m_beta; //>! volume weigth
|
||||
double m_diag; //>! length of the BB diagonal
|
||||
Vec3<Real> m_barycenter; //>! barycenter of the mesh
|
||||
std::vector< long > m_cVertices; //>! array of vertices each belonging to a different cluster
|
||||
ICHull * m_convexHulls; //>! convex-hulls associated with the final HACD clusters
|
||||
Graph m_graph; //>! simplification graph
|
||||
size_t m_nVerticesPerCH; //>! maximum number of vertices per convex-hull
|
||||
reservable_priority_queue<GraphEdgePriorityQueue,
|
||||
std::vector<GraphEdgePriorityQueue>,
|
||||
std::greater<std::vector<GraphEdgePriorityQueue>::value_type> > m_pqueue; //!> priority queue
|
||||
HACD(const HACD & rhs);
|
||||
CallBackFunction m_callBack; //>! call-back function
|
||||
long * m_partition; //>! array of size m_nTriangles where the i-th element specifies the cluster to which belong the i-th triangle
|
||||
bool m_addFacesPoints; //>! specifies whether to add faces points or not
|
||||
bool m_addExtraDistPoints; //>! specifies whether to add extra points for concave shapes or not
|
||||
bool m_addNeighboursDistPoints; //>! specifies whether to add extra points from adjacent clusters or not
|
||||
|
||||
};
|
||||
}
|
||||
#endif
|
1010
extern/HACD/hacdICHull.cpp
vendored
Normal file
1010
extern/HACD/hacdICHull.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
120
extern/HACD/hacdICHull.h
vendored
Normal file
120
extern/HACD/hacdICHull.h
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
/* 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 HACD_ICHULL_H
|
||||
#define HACD_ICHULL_H
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdManifoldMesh.h"
|
||||
#include "hacdVector.h"
|
||||
#include <vector>
|
||||
#include <map>
|
||||
namespace HACD
|
||||
{
|
||||
class DPoint;
|
||||
class HACD;
|
||||
//! Incremental Convex Hull algorithm (cf. http://maven.smith.edu/~orourke/books/ftp.html ).
|
||||
enum ICHullError
|
||||
{
|
||||
ICHullErrorOK = 0,
|
||||
ICHullErrorCoplanarPoints,
|
||||
ICHullErrorNoVolume,
|
||||
ICHullErrorInconsistent,
|
||||
ICHullErrorNotEnoughPoints
|
||||
};
|
||||
class ICHull
|
||||
{
|
||||
public:
|
||||
//!
|
||||
bool IsFlat() { return m_isFlat;}
|
||||
//!
|
||||
std::map<long, DPoint> * GetDistPoints() const { return m_distPoints;}
|
||||
//!
|
||||
void SetDistPoints(std::map<long, DPoint> * distPoints) { m_distPoints = distPoints;}
|
||||
//! Returns the computed mesh
|
||||
TMMesh & GetMesh() { return m_mesh;}
|
||||
//! Add one point to the convex-hull
|
||||
bool AddPoint(const Vec3<Real> & point) {return AddPoints(&point, 1);}
|
||||
//! Add one point to the convex-hull
|
||||
bool AddPoint(const Vec3<Real> & point, long id);
|
||||
//! Add points to the convex-hull
|
||||
bool AddPoints(const Vec3<Real> * points, size_t nPoints);
|
||||
bool AddPoints(std::vector< Vec3<Real> > points);
|
||||
//!
|
||||
ICHullError Process();
|
||||
//!
|
||||
ICHullError Process(unsigned long nPointsCH);
|
||||
//!
|
||||
double ComputeVolume();
|
||||
//!
|
||||
bool IsInside(const Vec3<Real> & pt0);
|
||||
//!
|
||||
double ComputeDistance(long name, const Vec3<Real> & pt, const Vec3<Real> & normal, bool & insideHull, bool updateIncidentPoints);
|
||||
//!
|
||||
const ICHull & operator=(ICHull & rhs);
|
||||
|
||||
//! Constructor
|
||||
ICHull(void);
|
||||
//! Destructor
|
||||
virtual ~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();
|
||||
//!
|
||||
bool CleanEdges();
|
||||
//!
|
||||
bool CleanVertices(unsigned long & addedPoints);
|
||||
//!
|
||||
bool CleanTriangles();
|
||||
//!
|
||||
bool CleanUp(unsigned long & addedPoints);
|
||||
//!
|
||||
bool MakeCCW(CircularListElement<TMMTriangle> * f,
|
||||
CircularListElement<TMMEdge> * e,
|
||||
CircularListElement<TMMVertex> * v);
|
||||
void Clear();
|
||||
private:
|
||||
static const long sc_dummyIndex;
|
||||
static const double sc_distMin;
|
||||
TMMesh m_mesh;
|
||||
std::vector<CircularListElement<TMMEdge> *> m_edgesToDelete;
|
||||
std::vector<CircularListElement<TMMEdge> *> m_edgesToUpdate;
|
||||
std::vector<CircularListElement<TMMTriangle> *> m_trianglesToDelete;
|
||||
std::map<long, DPoint> * m_distPoints;
|
||||
CircularListElement<TMMVertex> * m_dummyVertex;
|
||||
Vec3<Real> m_normal;
|
||||
bool m_isFlat;
|
||||
|
||||
|
||||
ICHull(const ICHull & rhs);
|
||||
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
577
extern/HACD/hacdManifoldMesh.cpp
vendored
Normal file
577
extern/HACD/hacdManifoldMesh.cpp
vendored
Normal file
@@ -0,0 +1,577 @@
|
||||
/* 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 "hacdManifoldMesh.h"
|
||||
using namespace std;
|
||||
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
Material::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;
|
||||
}
|
||||
|
||||
TMMVertex::TMMVertex(void)
|
||||
{
|
||||
m_name = 0;
|
||||
m_id = 0;
|
||||
m_duplicate = 0;
|
||||
m_onHull = false;
|
||||
m_tag = false;
|
||||
}
|
||||
TMMVertex::~TMMVertex(void)
|
||||
{
|
||||
}
|
||||
TMMEdge::TMMEdge(void)
|
||||
{
|
||||
m_id = 0;
|
||||
m_triangles[0] = m_triangles[1] = m_newFace = 0;
|
||||
m_vertices[0] = m_vertices[1] = 0;
|
||||
}
|
||||
TMMEdge::~TMMEdge(void)
|
||||
{
|
||||
}
|
||||
TMMTriangle::TMMTriangle(void)
|
||||
{
|
||||
m_id = 0;
|
||||
for(int i = 0; i < 3; i++)
|
||||
{
|
||||
m_edges[i] = 0;
|
||||
m_vertices[0] = 0;
|
||||
}
|
||||
m_visible = false;
|
||||
}
|
||||
TMMTriangle::~TMMTriangle(void)
|
||||
{
|
||||
}
|
||||
TMMesh::TMMesh(void)
|
||||
{
|
||||
m_barycenter = Vec3<Real>(0,0,0);
|
||||
m_diag = 1;
|
||||
}
|
||||
TMMesh::~TMMesh(void)
|
||||
{
|
||||
}
|
||||
|
||||
void TMMesh::Print()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
std::cout << "-----------------------------" << std::endl;
|
||||
std::cout << "vertices (" << nV << ")" << std::endl;
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
const TMMVertex & currentVertex = m_vertices.GetData();
|
||||
std::cout << currentVertex.m_id << ", "
|
||||
<< currentVertex.m_pos.X() << ", "
|
||||
<< currentVertex.m_pos.Y() << ", "
|
||||
<< currentVertex.m_pos.Z() << std::endl;
|
||||
m_vertices.Next();
|
||||
}
|
||||
|
||||
|
||||
size_t nE = m_edges.GetSize();
|
||||
std::cout << "edges (" << nE << ")" << std::endl;
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
const TMMEdge & currentEdge = m_edges.GetData();
|
||||
const CircularListElement<TMMVertex> * v0 = currentEdge.m_vertices[0];
|
||||
const CircularListElement<TMMVertex> * v1 = currentEdge.m_vertices[1];
|
||||
const CircularListElement<TMMTriangle> * f0 = currentEdge.m_triangles[0];
|
||||
const CircularListElement<TMMTriangle> * f1 = currentEdge.m_triangles[1];
|
||||
|
||||
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> F0 (" << f0->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< f0->GetData().m_vertices[1]->GetData().m_name << ", "
|
||||
<< f0->GetData().m_vertices[2]->GetData().m_name <<")" << std::endl;
|
||||
std::cout << "-> F1 (" << f1->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< f1->GetData().m_vertices[1]->GetData().m_name << ", "
|
||||
<< f1->GetData().m_vertices[2]->GetData().m_name << ")" << std::endl;
|
||||
m_edges.Next();
|
||||
}
|
||||
size_t nT = m_triangles.GetSize();
|
||||
std::cout << "triangles (" << nT << ")" << std::endl;
|
||||
for(size_t t = 0; t < nT; t++)
|
||||
{
|
||||
const TMMTriangle & currentTriangle = m_triangles.GetData();
|
||||
const CircularListElement<TMMVertex> * v0 = currentTriangle.m_vertices[0];
|
||||
const CircularListElement<TMMVertex> * v1 = currentTriangle.m_vertices[1];
|
||||
const CircularListElement<TMMVertex> * v2 = currentTriangle.m_vertices[2];
|
||||
const CircularListElement<TMMEdge> * e0 = currentTriangle.m_edges[0];
|
||||
const CircularListElement<TMMEdge> * e1 = currentTriangle.m_edges[1];
|
||||
const CircularListElement<TMMEdge> * e2 = currentTriangle.m_edges[2];
|
||||
|
||||
std::cout << "-> (" << v0->GetData().m_name << ", " << v1->GetData().m_name << ", "<< v2->GetData().m_name << ")" << std::endl;
|
||||
|
||||
std::cout << "-> E0 (" << e0->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e0->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> E1 (" << e1->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e1->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
std::cout << "-> E2 (" << e2->GetData().m_vertices[0]->GetData().m_name << ", "
|
||||
<< e2->GetData().m_vertices[1]->GetData().m_name << ")" << std::endl;
|
||||
m_triangles.Next();
|
||||
}
|
||||
}
|
||||
bool TMMesh::Save(const char *fileName)
|
||||
{
|
||||
std::ofstream fout(fileName);
|
||||
std::cout << "Saving " << fileName << std::endl;
|
||||
if (SaveVRML2(fout))
|
||||
{
|
||||
fout.close();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool TMMesh::SaveVRML2(std::ofstream &fout)
|
||||
{
|
||||
return SaveVRML2(fout, Material());
|
||||
}
|
||||
bool TMMesh::SaveVRML2(std::ofstream &fout, const Material & material)
|
||||
{
|
||||
if (fout.is_open())
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
size_t nT = m_triangles.GetSize();
|
||||
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.X() << " "
|
||||
<< material.m_diffuseColor.Y() << " "
|
||||
<< material.m_diffuseColor.Z() << std::endl;
|
||||
fout <<" ambientIntensity " << material.m_ambientIntensity << std::endl;
|
||||
fout <<" specularColor " << material.m_specularColor.X() << " "
|
||||
<< material.m_specularColor.Y() << " "
|
||||
<< material.m_specularColor.Z() << std::endl;
|
||||
fout <<" emissiveColor " << material.m_emissiveColor.X() << " "
|
||||
<< material.m_emissiveColor.Y() << " "
|
||||
<< material.m_emissiveColor.Z() << 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 (GetNVertices() > 0) {
|
||||
fout <<" coord DEF co Coordinate {" << std::endl;
|
||||
fout <<" point [" << std::endl;
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
TMMVertex & currentVertex = m_vertices.GetData();
|
||||
fout <<" " << currentVertex.m_pos.X() << " "
|
||||
<< currentVertex.m_pos.Y() << " "
|
||||
<< currentVertex.m_pos.Z() << "," << std::endl;
|
||||
currentVertex.m_id = v;
|
||||
m_vertices.Next();
|
||||
}
|
||||
fout <<" ]" << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
}
|
||||
if (GetNTriangles() > 0) {
|
||||
fout <<" coordIndex [ " << std::endl;
|
||||
for(size_t f = 0; f < nT; f++)
|
||||
{
|
||||
TMMTriangle & currentTriangle = m_triangles.GetData();
|
||||
fout <<" " << currentTriangle.m_vertices[0]->GetData().m_id << ", "
|
||||
<< currentTriangle.m_vertices[1]->GetData().m_id << ", "
|
||||
<< currentTriangle.m_vertices[2]->GetData().m_id << ", -1," << std::endl;
|
||||
m_triangles.Next();
|
||||
}
|
||||
fout <<" ]" << std::endl;
|
||||
}
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" }" << std::endl;
|
||||
fout <<" ]" << std::endl;
|
||||
fout <<"}" << std::endl;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void TMMesh::GetIFS(Vec3<Real> * const points, Vec3<long> * 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<long>(currentTriangle.m_vertices[0]->GetData().m_id);
|
||||
triangles[f].Y() = static_cast<long>(currentTriangle.m_vertices[1]->GetData().m_id);
|
||||
triangles[f].Z() = static_cast<long>(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;
|
||||
|
||||
// generating 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(int 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(int 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(int 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(int 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;
|
||||
|
||||
}
|
||||
long IntersectRayTriangle(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &t)
|
||||
{
|
||||
Vec3<double> edge1, edge2, edge3;
|
||||
double det, invDet;
|
||||
edge1 = V1 - V2;
|
||||
edge2 = V2 - V0;
|
||||
Vec3<double> pvec = dir ^ edge2;
|
||||
det = edge1 * pvec;
|
||||
if (det == 0.0)
|
||||
return 0;
|
||||
invDet = 1.0/det;
|
||||
Vec3<double> tvec = P0 - V0;
|
||||
Vec3<double> qvec = tvec ^ edge1;
|
||||
t = (edge2 * qvec) * invDet;
|
||||
if (t < 0.0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
edge3 = V0 - V1;
|
||||
Vec3<double> I(P0 + t * dir);
|
||||
Vec3<double> s0 = (I-V0) ^ edge3;
|
||||
Vec3<double> s1 = (I-V1) ^ edge1;
|
||||
Vec3<double> s2 = (I-V2) ^ edge2;
|
||||
if (s0*s1 > -1e-9 && s2*s1 > -1e-9)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
|
||||
const Vec3<double> & p3, const Vec3<double> & p4,
|
||||
Vec3<double> & pa, Vec3<double> & pb,
|
||||
double & mua, double & mub)
|
||||
{
|
||||
Vec3<double> p13,p43,p21;
|
||||
double d1343,d4321,d1321,d4343,d2121;
|
||||
double numer,denom;
|
||||
|
||||
p13.X() = p1.X() - p3.X();
|
||||
p13.Y() = p1.Y() - p3.Y();
|
||||
p13.Z() = p1.Z() - p3.Z();
|
||||
p43.X() = p4.X() - p3.X();
|
||||
p43.Y() = p4.Y() - p3.Y();
|
||||
p43.Z() = p4.Z() - p3.Z();
|
||||
if (p43.X()==0.0 && p43.Y()==0.0 && p43.Z()==0.0)
|
||||
return false;
|
||||
p21.X() = p2.X() - p1.X();
|
||||
p21.Y() = p2.Y() - p1.Y();
|
||||
p21.Z() = p2.Z() - p1.Z();
|
||||
if (p21.X()==0.0 && p21.Y()==0.0 && p21.Z()==0.0)
|
||||
return false;
|
||||
|
||||
d1343 = p13.X() * p43.X() + p13.Y() * p43.Y() + p13.Z() * p43.Z();
|
||||
d4321 = p43.X() * p21.X() + p43.Y() * p21.Y() + p43.Z() * p21.Z();
|
||||
d1321 = p13.X() * p21.X() + p13.Y() * p21.Y() + p13.Z() * p21.Z();
|
||||
d4343 = p43.X() * p43.X() + p43.Y() * p43.Y() + p43.Z() * p43.Z();
|
||||
d2121 = p21.X() * p21.X() + p21.Y() * p21.Y() + p21.Z() * p21.Z();
|
||||
|
||||
denom = d2121 * d4343 - d4321 * d4321;
|
||||
if (denom==0.0)
|
||||
return false;
|
||||
numer = d1343 * d4321 - d1321 * d4343;
|
||||
|
||||
mua = numer / denom;
|
||||
mub = (d1343 + d4321 * (mua)) / d4343;
|
||||
|
||||
pa.X() = p1.X() + mua * p21.X();
|
||||
pa.Y() = p1.Y() + mua * p21.Y();
|
||||
pa.Z() = p1.Z() + mua * p21.Z();
|
||||
pb.X() = p3.X() + mub * p43.X();
|
||||
pb.Y() = p3.Y() + mub * p43.Y();
|
||||
pb.Z() = p3.Z() + mub * p43.Z();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &r)
|
||||
{
|
||||
Vec3<double> u, v, n; // triangle vectors
|
||||
Vec3<double> w0, w; // ray vectors
|
||||
double a, b; // params to calc ray-plane intersect
|
||||
|
||||
// get triangle edge vectors and plane normal
|
||||
u = V1 - V0;
|
||||
v = V2 - V0;
|
||||
n = u ^ v; // cross product
|
||||
if (n.GetNorm() == 0.0) // triangle is degenerate
|
||||
return -1; // do not deal with this case
|
||||
|
||||
w0 = P0 - V0;
|
||||
a = - n * w0;
|
||||
b = n * dir;
|
||||
if (fabs(b) <= 0.0) { // ray is parallel to triangle plane
|
||||
if (a == 0.0) // ray lies in triangle plane
|
||||
return 2;
|
||||
else return 0; // ray disjoint from plane
|
||||
}
|
||||
|
||||
// get intersect point of ray with triangle plane
|
||||
r = a / b;
|
||||
if (r < 0.0) // ray goes away from triangle
|
||||
return 0; // => no intersect
|
||||
// for a segment, also test if (r > 1.0) => no intersect
|
||||
|
||||
Vec3<double> I = P0 + r * dir; // intersect point of ray and plane
|
||||
|
||||
// is I inside T?
|
||||
double uu, uv, vv, wu, wv, D;
|
||||
uu = u * u;
|
||||
uv = u * v;
|
||||
vv = v * v;
|
||||
w = I - V0;
|
||||
wu = w * u;
|
||||
wv = w * v;
|
||||
D = uv * uv - uu * vv;
|
||||
|
||||
// get and test parametric coords
|
||||
double s, t;
|
||||
s = (uv * wv - vv * wu) / D;
|
||||
if (s < 0.0 || s > 1.0) // I is outside T
|
||||
return 0;
|
||||
t = (uv * wu - uu * wv) / D;
|
||||
if (t < 0.0 || (s + t) > 1.0) // I is outside T
|
||||
return 0;
|
||||
return 1; // I is in T
|
||||
}
|
||||
|
||||
|
||||
bool TMMesh::CheckConsistancy()
|
||||
{
|
||||
size_t nE = m_edges.GetSize();
|
||||
size_t nT = m_triangles.GetSize();
|
||||
for(size_t e = 0; e < nE; e++)
|
||||
{
|
||||
for(int 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(int e = 0; e < 3; e++)
|
||||
{
|
||||
int found = 0;
|
||||
for(int 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;
|
||||
}
|
||||
bool TMMesh::Normalize()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
if (nV == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_barycenter = m_vertices.GetHead()->GetData().m_pos;
|
||||
Vec3<Real> min = m_barycenter;
|
||||
Vec3<Real> max = m_barycenter;
|
||||
Real x, y, z;
|
||||
for(size_t v = 1; v < nV; v++)
|
||||
{
|
||||
m_barycenter += m_vertices.GetHead()->GetData().m_pos;
|
||||
x = m_vertices.GetHead()->GetData().m_pos.X();
|
||||
y = m_vertices.GetHead()->GetData().m_pos.Y();
|
||||
z = m_vertices.GetHead()->GetData().m_pos.Z();
|
||||
if ( x < min.X()) min.X() = x;
|
||||
else if ( x > max.X()) max.X() = x;
|
||||
if ( y < min.Y()) min.Y() = y;
|
||||
else if ( y > max.Y()) max.Y() = y;
|
||||
if ( z < min.Z()) min.Z() = z;
|
||||
else if ( z > max.Z()) max.Z() = z;
|
||||
m_vertices.Next();
|
||||
}
|
||||
m_barycenter /= static_cast<Real>(nV);
|
||||
m_diag = static_cast<Real>(0.001 * (max-min).GetNorm());
|
||||
const Real invDiag = static_cast<Real>(1.0 / m_diag);
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
m_vertices.GetHead()->GetData().m_pos = (m_vertices.GetHead()->GetData().m_pos - m_barycenter) * invDiag;
|
||||
m_vertices.Next();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool TMMesh::Denormalize()
|
||||
{
|
||||
size_t nV = m_vertices.GetSize();
|
||||
if (nV == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_diag != 0.0)
|
||||
{
|
||||
for(size_t v = 0; v < nV; v++)
|
||||
{
|
||||
m_vertices.GetHead()->GetData().m_pos = m_vertices.GetHead()->GetData().m_pos * m_diag + m_barycenter;
|
||||
m_vertices.Next();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
250
extern/HACD/hacdManifoldMesh.h
vendored
Normal file
250
extern/HACD/hacdManifoldMesh.h
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
/* 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 HACD_MANIFOLD_MESH_H
|
||||
#define HACD_MANIFOLD_MESH_H
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "hacdVersion.h"
|
||||
#include "hacdCircularList.h"
|
||||
#include "hacdVector.h"
|
||||
#include <set>
|
||||
namespace HACD
|
||||
{
|
||||
class TMMTriangle;
|
||||
class TMMEdge;
|
||||
class TMMesh;
|
||||
class ICHull;
|
||||
class HACD;
|
||||
|
||||
class DPoint
|
||||
{
|
||||
public:
|
||||
DPoint(Real dist=0, bool computed=false, bool distOnly=false)
|
||||
:m_dist(dist),
|
||||
m_computed(computed),
|
||||
m_distOnly(distOnly){};
|
||||
~DPoint(){};
|
||||
private:
|
||||
Real m_dist;
|
||||
bool m_computed;
|
||||
bool m_distOnly;
|
||||
friend class TMMTriangle;
|
||||
friend class TMMesh;
|
||||
friend class GraphVertex;
|
||||
friend class GraphEdge;
|
||||
friend class Graph;
|
||||
friend class ICHull;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
//! Vertex data structure used in a triangular manifold mesh (TMM).
|
||||
class TMMVertex
|
||||
{
|
||||
public:
|
||||
TMMVertex(void);
|
||||
~TMMVertex(void);
|
||||
|
||||
private:
|
||||
Vec3<Real> m_pos;
|
||||
long 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 HACD;
|
||||
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:
|
||||
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 HACD;
|
||||
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:
|
||||
TMMTriangle(void);
|
||||
~TMMTriangle(void);
|
||||
private:
|
||||
size_t m_id;
|
||||
CircularListElement<TMMEdge> * m_edges[3];
|
||||
CircularListElement<TMMVertex> * m_vertices[3];
|
||||
std::set<long> m_incidentPoints;
|
||||
bool m_visible;
|
||||
|
||||
TMMTriangle(const TMMTriangle & rhs);
|
||||
|
||||
friend class HACD;
|
||||
friend class ICHull;
|
||||
friend class TMMesh;
|
||||
friend class TMMVertex;
|
||||
friend class TMMEdge;
|
||||
};
|
||||
|
||||
class Material
|
||||
{
|
||||
public:
|
||||
Material(void);
|
||||
~Material(void){}
|
||||
// private:
|
||||
Vec3<double> m_diffuseColor;
|
||||
double m_ambientIntensity;
|
||||
Vec3<double> m_specularColor;
|
||||
Vec3<double> m_emissiveColor;
|
||||
double m_shininess;
|
||||
double m_transparency;
|
||||
|
||||
friend class TMMesh;
|
||||
friend class HACD;
|
||||
};
|
||||
|
||||
//! 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<Real> * const points, Vec3<long> * const triangles);
|
||||
//! Save mesh
|
||||
bool Save(const char *fileName);
|
||||
//! Save mesh to VRML 2.0 format
|
||||
bool SaveVRML2(std::ofstream &fout);
|
||||
//! Save mesh to VRML 2.0 format
|
||||
bool SaveVRML2(std::ofstream &fout, const Material & material);
|
||||
//!
|
||||
void Clear();
|
||||
//!
|
||||
void Copy(TMMesh & mesh);
|
||||
//!
|
||||
bool CheckConsistancy();
|
||||
//!
|
||||
bool Normalize();
|
||||
//!
|
||||
bool Denormalize();
|
||||
//! Constructor
|
||||
TMMesh(void);
|
||||
//! Destructor
|
||||
virtual ~TMMesh(void);
|
||||
|
||||
private:
|
||||
CircularList<TMMVertex> m_vertices;
|
||||
CircularList<TMMEdge> m_edges;
|
||||
CircularList<TMMTriangle> m_triangles;
|
||||
Real m_diag; //>! length of the BB diagonal
|
||||
Vec3<Real> m_barycenter; //>! barycenter of the mesh
|
||||
|
||||
// not defined
|
||||
TMMesh(const TMMesh & rhs);
|
||||
friend class ICHull;
|
||||
friend class HACD;
|
||||
};
|
||||
//! IntersectRayTriangle(): intersect a ray with a 3D triangle
|
||||
//! Input: a ray R, and a triangle T
|
||||
//! Output: *I = intersection point (when it exists)
|
||||
//! 0 = disjoint (no intersect)
|
||||
//! 1 = intersect in unique point I1
|
||||
long IntersectRayTriangle( const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &t);
|
||||
|
||||
// intersect_RayTriangle(): intersect a ray with a 3D triangle
|
||||
// Input: a ray R, and a triangle T
|
||||
// Output: *I = intersection point (when it exists)
|
||||
// Return: -1 = triangle is degenerate (a segment or point)
|
||||
// 0 = disjoint (no intersect)
|
||||
// 1 = intersect in unique point I1
|
||||
// 2 = are in the same plane
|
||||
long IntersectRayTriangle2(const Vec3<double> & P0, const Vec3<double> & dir,
|
||||
const Vec3<double> & V0, const Vec3<double> & V1,
|
||||
const Vec3<double> & V2, double &r);
|
||||
|
||||
/*
|
||||
Calculate the line segment PaPb that is the shortest route between
|
||||
two lines P1P2 and P3P4. Calculate also the values of mua and mub where
|
||||
Pa = P1 + mua (P2 - P1)
|
||||
Pb = P3 + mub (P4 - P3)
|
||||
Return FALSE if no solution exists.
|
||||
*/
|
||||
bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2,
|
||||
const Vec3<double> & p3, const Vec3<double> & p4,
|
||||
Vec3<double> & pa, Vec3<double> & pb,
|
||||
double & mua, double &mub);
|
||||
}
|
||||
#endif
|
67
extern/HACD/hacdVector.h
vendored
Normal file
67
extern/HACD/hacdVector.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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 HACD_VECTOR_H
|
||||
#define HACD_VECTOR_H
|
||||
#include<math.h>
|
||||
#include<iostream>
|
||||
#include "hacdVersion.h"
|
||||
|
||||
namespace HACD
|
||||
{
|
||||
typedef double Real;
|
||||
//! Vector dim 3.
|
||||
template < typename T > class Vec3
|
||||
{
|
||||
public:
|
||||
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;
|
||||
Vec3();
|
||||
Vec3(T a);
|
||||
Vec3(T x, T y, T z);
|
||||
Vec3(const Vec3 & rhs);
|
||||
/*virtual*/ ~Vec3(void);
|
||||
|
||||
private:
|
||||
T m_data[3];
|
||||
};
|
||||
template<typename T>
|
||||
const bool Colinear(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c);
|
||||
template<typename T>
|
||||
const T Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d);
|
||||
|
||||
}
|
||||
#include "hacdVector.inl" // template implementation
|
||||
#endif
|
178
extern/HACD/hacdVector.inl
vendored
Normal file
178
extern/HACD/hacdVector.inl
vendored
Normal file
@@ -0,0 +1,178 @@
|
||||
#pragma once
|
||||
#ifndef HACD_VECTOR_INL
|
||||
#define HACD_VECTOR_INL
|
||||
namespace HACD
|
||||
{
|
||||
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 Volume(const Vec3<T> & a, const Vec3<T> & b, const Vec3<T> & c, const Vec3<T> & d)
|
||||
{
|
||||
return (a-d) * ((b-d) ^ (c-d));
|
||||
}
|
||||
}
|
||||
#endif //HACD_VECTOR_INL
|
20
extern/HACD/hacdVersion.h
vendored
Normal file
20
extern/HACD/hacdVersion.h
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/* 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 HACD_VERSION_H
|
||||
#define HACD_VERSION_H
|
||||
#define HACD_VERSION_MAJOR 0
|
||||
#define HACD_VERSION_MINOR 0
|
||||
#endif
|
@@ -23,6 +23,8 @@
|
||||
|
||||
set(INC
|
||||
.
|
||||
../../source/blender/gpu
|
||||
../../extern/HACD
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
@@ -62,6 +62,7 @@ typedef struct rbCollisionShape rbCollisionShape;
|
||||
|
||||
/* Mesh Data (for Collision Shapes of Meshes) */
|
||||
typedef struct rbMeshData rbMeshData;
|
||||
typedef struct rbHACDMeshData rbHACDMeshData;
|
||||
|
||||
/* Constraint */
|
||||
typedef struct rbConstraint rbConstraint;
|
||||
@@ -181,6 +182,15 @@ extern void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, fl
|
||||
/* Kinematic State */
|
||||
extern void RB_body_set_kinematic_state(rbRigidBody *body, int kinematic);
|
||||
|
||||
extern void RB_body_suspend(rbRigidBody *object);
|
||||
|
||||
extern void RB_body_set_trigger(rbRigidBody *object, int trigger);
|
||||
extern void RB_body_set_ghost(rbRigidBody *object, int ghost);
|
||||
extern void RB_body_set_activation_type(rbRigidBody *object, int type);
|
||||
extern void RB_body_set_activation_time(rbRigidBody *object, double time);
|
||||
extern void RB_body_set_activation_impulse(rbRigidBody *object, float impulse);
|
||||
extern void RB_body_try_activation(rbRigidBody *object);
|
||||
|
||||
/* RigidBody Interface - Rigid Body Activation States */
|
||||
extern int RB_body_get_activation_state(rbRigidBody *body);
|
||||
extern void RB_body_set_activation_state(rbRigidBody *body, int use_deactivation);
|
||||
@@ -202,8 +212,10 @@ extern void RB_body_set_scale(rbRigidBody *body, const float scale[3]);
|
||||
|
||||
/* Get RigidBody's position as vector */
|
||||
void RB_body_get_position(rbRigidBody *body, float v_out[3]);
|
||||
/* Get RigidBody's orientation as quaternion */
|
||||
void RB_body_get_orientation(rbRigidBody *body, float v_out[4]);
|
||||
|
||||
void RB_body_get_pos_orn(rbRigidBody *object, float pos_out[3], float orn_out[4]);
|
||||
|
||||
void RB_body_get_compound_pos_orn(rbRigidBody *parent_object, rbCollisionShape *child_shape, float pos_out[3], float orn_out[4]);
|
||||
|
||||
/* ............ */
|
||||
|
||||
@@ -214,11 +226,11 @@ extern void RB_body_apply_central_force(rbRigidBody *body, const float v_in[3]);
|
||||
|
||||
/* Setup (Standard Shapes) ----------- */
|
||||
|
||||
extern rbCollisionShape *RB_shape_new_box(float x, float y, float z);
|
||||
extern rbCollisionShape *RB_shape_new_sphere(float radius);
|
||||
extern rbCollisionShape *RB_shape_new_capsule(float radius, float height);
|
||||
extern rbCollisionShape *RB_shape_new_cone(float radius, float height);
|
||||
extern rbCollisionShape *RB_shape_new_cylinder(float radius, float height);
|
||||
extern rbCollisionShape *RB_shape_new_box(float x, float y, float z, const float loc[3], const float rot[4], const float center[3]);
|
||||
extern rbCollisionShape *RB_shape_new_sphere(float radius, const float loc[3], const float rot[4], const float center[3]);
|
||||
extern rbCollisionShape *RB_shape_new_capsule(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
|
||||
extern rbCollisionShape *RB_shape_new_cone(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
|
||||
extern rbCollisionShape *RB_shape_new_cylinder(float radius, float height, const float loc[3], const float rot[4], const float center[3]);
|
||||
|
||||
/* Setup (Convex Hull) ------------ */
|
||||
|
||||
@@ -227,14 +239,25 @@ extern rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int
|
||||
/* Setup (Triangle Mesh) ---------- */
|
||||
|
||||
/* 1 */
|
||||
extern rbMeshData *RB_trimesh_data_new(void);
|
||||
extern void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]);
|
||||
extern rbMeshData *RB_trimesh_data_new(int num_tris, int num_verts);
|
||||
extern void RB_trimesh_add_vertices(rbMeshData *mesh, float *vertices, int num_verts, int vert_stride);
|
||||
extern void RB_trimesh_add_triangle_indices(rbMeshData *mesh, int num, int index0, int index1, int index2);
|
||||
extern void RB_trimesh_finish(rbMeshData *mesh);
|
||||
/* 2a - Triangle Meshes */
|
||||
extern rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh);
|
||||
/* 2b - GImpact Meshes */
|
||||
extern rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh);
|
||||
|
||||
|
||||
extern rbHACDMeshData *RB_hacd_mesh_new(int num_tris, int num_verts);
|
||||
extern void RB_hacd_mesh_add_triangle(rbHACDMeshData *mesh, const float v1[3], const float v2[3], const float v3[3]);
|
||||
|
||||
extern rbCollisionShape *RB_shape_new_convex_decomp(rbHACDMeshData *mesh);
|
||||
|
||||
/* Compound Shapes ------------------- */
|
||||
extern void RB_shape_add_compound_child(rbRigidBody *parent, rbCollisionShape *child, float child_pos[3], float child_orn[4]);
|
||||
|
||||
|
||||
/* Cleanup --------------------------- */
|
||||
|
||||
extern void RB_shape_delete(rbCollisionShape *shape);
|
||||
@@ -245,6 +268,8 @@ extern void RB_shape_delete(rbCollisionShape *shape);
|
||||
extern float RB_shape_get_margin(rbCollisionShape *shape);
|
||||
extern void RB_shape_set_margin(rbCollisionShape *shape, float value);
|
||||
|
||||
extern void RB_shape_trimesh_update(rbCollisionShape *shape, float *vertices, int num_verts, int vert_stride, float min[3], float max[3]);
|
||||
|
||||
/* ********************************** */
|
||||
/* Constraints */
|
||||
|
||||
|
@@ -59,6 +59,8 @@ subject to the following restrictions:
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "GPU_draw.h"
|
||||
|
||||
#include "RBI_api.h"
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
@@ -73,6 +75,10 @@ subject to the following restrictions:
|
||||
#include "BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h"
|
||||
#include "BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h"
|
||||
|
||||
#include <BulletCollision/CollisionDispatch/btInternalEdgeUtility.h>
|
||||
|
||||
#include "hacdHACD.h"
|
||||
|
||||
struct rbDynamicsWorld {
|
||||
btDiscreteDynamicsWorld *dynamicsWorld;
|
||||
btDefaultCollisionConfiguration *collisionConfiguration;
|
||||
@@ -80,15 +86,47 @@ struct rbDynamicsWorld {
|
||||
btBroadphaseInterface *pairCache;
|
||||
btConstraintSolver *constraintSolver;
|
||||
btOverlapFilterCallback *filterCallback;
|
||||
double elapsed_time;
|
||||
};
|
||||
|
||||
enum ActivationType {
|
||||
ACTIVATION_COLLISION = 0,
|
||||
ACTIVATION_TRIGGER,
|
||||
ACTIVATION_TIME
|
||||
};
|
||||
|
||||
struct rbRigidBody {
|
||||
btRigidBody *body;
|
||||
rbDynamicsWorld *world;
|
||||
int col_groups;
|
||||
bool is_trigger;
|
||||
bool suspended;
|
||||
float saved_mass;
|
||||
double activation_time;
|
||||
float activation_impulse;
|
||||
int activation_type;
|
||||
};
|
||||
|
||||
struct rbVert {
|
||||
float x, y, z;
|
||||
};
|
||||
struct rbTri {
|
||||
int v0, v1, v2;
|
||||
};
|
||||
|
||||
struct rbMeshData {
|
||||
btTriangleIndexVertexArray *index_array;
|
||||
rbVert *vertices;
|
||||
rbTri *triangles;
|
||||
int num_vertices;
|
||||
int num_triangles;
|
||||
};
|
||||
|
||||
struct rbCollisionShape {
|
||||
btCollisionShape *cshape;
|
||||
btTriangleMesh *mesh;
|
||||
btCollisionShape *compound;
|
||||
rbMeshData *mesh;
|
||||
btTriangleInfoMap *triangle_info_map;
|
||||
};
|
||||
|
||||
struct rbFilterCallback : public btOverlapFilterCallback
|
||||
@@ -99,14 +137,158 @@ struct rbFilterCallback : public btOverlapFilterCallback
|
||||
rbRigidBody *rb1 = (rbRigidBody *)((btRigidBody *)proxy1->m_clientObject)->getUserPointer();
|
||||
|
||||
bool collides;
|
||||
collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
|
||||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
|
||||
|
||||
bool rb0_kinematic = ((btRigidBody *)proxy0->m_clientObject)->isKinematicObject();
|
||||
bool rb1_kinematic = ((btRigidBody *)proxy1->m_clientObject)->isKinematicObject();
|
||||
|
||||
/* allow static-static collision so suspended bodies can be activated by kinematic objects */
|
||||
if ((rb0->suspended && rb1_kinematic) || (rb1->suspended && rb0_kinematic)) {
|
||||
collides = true;
|
||||
}
|
||||
else {
|
||||
collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0;
|
||||
collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask);
|
||||
}
|
||||
collides = collides && (rb0->col_groups & rb1->col_groups);
|
||||
|
||||
return collides;
|
||||
}
|
||||
};
|
||||
|
||||
static inline void activate(rbRigidBody *rb)
|
||||
{
|
||||
btRigidBody *body = rb->body;
|
||||
rb->suspended = false;
|
||||
rb->world->dynamicsWorld->removeRigidBody(body);
|
||||
RB_body_set_mass(rb, rb->saved_mass);
|
||||
rb->world->dynamicsWorld->addRigidBody(body);
|
||||
body->activate();
|
||||
}
|
||||
|
||||
static inline void activate_on_impulse(btPersistentManifold *manifold, rbRigidBody *rb0, rbRigidBody *rb1)
|
||||
{
|
||||
if (rb0->activation_impulse > 0.0f) {
|
||||
float impulse = 0.0f;
|
||||
/* use contact with highest impulse */
|
||||
for (int i = 0; i < manifold->getNumContacts(); i++) {
|
||||
btScalar velocity = (rb1->body->getLinearVelocity() + rb1->body->getAngularVelocity()).dot(-manifold->getContactPoint(i).m_normalWorldOnB);
|
||||
impulse = (impulse < velocity) ? velocity : impulse;
|
||||
}
|
||||
impulse /= rb1->body->getInvMass();
|
||||
if (impulse >= rb0->activation_impulse)
|
||||
activate(rb0);
|
||||
}
|
||||
else {
|
||||
activate(rb0);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void handle_activation(btPersistentManifold *manifold, rbRigidBody *rb0, rbRigidBody *rb1)
|
||||
{
|
||||
if (rb0->suspended) {
|
||||
switch(rb0->activation_type) {
|
||||
case ACTIVATION_COLLISION:
|
||||
activate_on_impulse(manifold, rb0, rb1);
|
||||
break;
|
||||
case ACTIVATION_TRIGGER:
|
||||
if (rb1->is_trigger) {
|
||||
activate_on_impulse(manifold, rb0, rb1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void nearCallback(btBroadphasePair &collisionPair, btCollisionDispatcher &dispatcher, const btDispatcherInfo &dispatchInfo)
|
||||
{
|
||||
btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject;
|
||||
btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject;
|
||||
|
||||
if (dispatcher.needsCollision(colObj0, colObj1)) {
|
||||
btCollisionObjectWrapper obj0Wrap(0, colObj0->getCollisionShape(), colObj0,colObj0->getWorldTransform(), -1, -1);
|
||||
btCollisionObjectWrapper obj1Wrap(0, colObj1->getCollisionShape(), colObj1,colObj1->getWorldTransform(), -1, -1);
|
||||
|
||||
|
||||
//dispatcher will keep algorithms persistent in the collision pair
|
||||
if (!collisionPair.m_algorithm) {
|
||||
collisionPair.m_algorithm = dispatcher.findAlgorithm(&obj0Wrap, &obj1Wrap);
|
||||
}
|
||||
if (collisionPair.m_algorithm) {
|
||||
btManifoldResult contactPointResult(&obj0Wrap, &obj1Wrap);
|
||||
|
||||
if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) {
|
||||
//discrete collision detection query
|
||||
|
||||
collisionPair.m_algorithm->processCollision(&obj0Wrap, &obj1Wrap, dispatchInfo, &contactPointResult);
|
||||
}
|
||||
else {
|
||||
//continuous collision detection query, time of impact (toi)
|
||||
btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0, colObj1, dispatchInfo, &contactPointResult);
|
||||
if (dispatchInfo.m_timeOfImpact > toi)
|
||||
dispatchInfo.m_timeOfImpact = toi;
|
||||
|
||||
}
|
||||
btPersistentManifold *manifold = contactPointResult.getPersistentManifold();
|
||||
if (manifold && manifold->getNumContacts() > 0) {
|
||||
rbRigidBody *rb0 = (rbRigidBody *)((btRigidBody *)collisionPair.m_pProxy0->m_clientObject)->getUserPointer();
|
||||
rbRigidBody *rb1 = (rbRigidBody *)((btRigidBody *)collisionPair.m_pProxy1->m_clientObject)->getUserPointer();
|
||||
|
||||
handle_activation(manifold, rb0, rb1);
|
||||
handle_activation(manifold, rb1, rb0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool contactAddedCallback(btManifoldPoint &cp, const btCollisionObjectWrapper *colObj0Wrap, int partId0, int index0, const btCollisionObjectWrapper *colObj1Wrap, int partId1, int index1)
|
||||
{
|
||||
btAdjustInternalEdgeContacts(cp, colObj1Wrap, colObj0Wrap, partId1, index1);
|
||||
return true;
|
||||
}
|
||||
|
||||
class rbDebugDraw : public btIDebugDraw {
|
||||
private:
|
||||
int debug_mode;
|
||||
public:
|
||||
rbDebugDraw() { }
|
||||
virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
|
||||
{
|
||||
float root[3] = {from.x(), from.y(), from.z()};
|
||||
float tip[3] = {to.x(), to.y(), to.z()};
|
||||
float col[3] = {color.x(), color.y(), color.z()};
|
||||
GPU_debug_add_line(root, tip, col);
|
||||
}
|
||||
virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)
|
||||
{
|
||||
float root[3] = {PointOnB.x(), PointOnB.y(), PointOnB.z()};
|
||||
btVector3 to = PointOnB + normalOnB;
|
||||
float nor_tip[3] = {to.x(), to.y(), to.z()};
|
||||
|
||||
float col[3] = {0.0f, 1.0f, 1.0f};
|
||||
GPU_debug_add_point(root, col);
|
||||
col[0] = 1.0f;
|
||||
col[1] = 0.0f;
|
||||
col[2] = 1.0f;
|
||||
GPU_debug_add_line(root, nor_tip, col);
|
||||
}
|
||||
virtual void reportErrorWarning(const char *warningString)
|
||||
{
|
||||
|
||||
}
|
||||
virtual void draw3dText(const btVector3& location,const char *textString)
|
||||
{
|
||||
|
||||
}
|
||||
virtual void setDebugMode(int debugMode)
|
||||
{
|
||||
debug_mode = debugMode;
|
||||
}
|
||||
virtual int getDebugMode() const
|
||||
{
|
||||
return debug_mode;
|
||||
}
|
||||
};
|
||||
|
||||
static inline void copy_v3_btvec3(float vec[3], const btVector3 &btvec)
|
||||
{
|
||||
vec[0] = (float)btvec[0];
|
||||
@@ -135,6 +317,7 @@ rbDynamicsWorld *RB_dworld_new(const float gravity[3])
|
||||
|
||||
world->dispatcher = new btCollisionDispatcher(world->collisionConfiguration);
|
||||
btGImpactCollisionAlgorithm::registerAlgorithm((btCollisionDispatcher *)world->dispatcher);
|
||||
((btCollisionDispatcher *)world->dispatcher)->setNearCallback(nearCallback);
|
||||
|
||||
world->pairCache = new btDbvtBroadphase();
|
||||
|
||||
@@ -152,6 +335,22 @@ rbDynamicsWorld *RB_dworld_new(const float gravity[3])
|
||||
|
||||
RB_dworld_set_gravity(world, gravity);
|
||||
|
||||
// gContactAddedCallback = contactAddedCallback;
|
||||
|
||||
world->elapsed_time = 0.0;
|
||||
|
||||
// HACK set debug drawer, this is only temporary
|
||||
btIDebugDraw *debugDrawer = new rbDebugDraw();
|
||||
debugDrawer->setDebugMode(btIDebugDraw::DBG_DrawWireframe |
|
||||
btIDebugDraw::DBG_DrawAabb |
|
||||
btIDebugDraw::DBG_DrawContactPoints |
|
||||
btIDebugDraw::DBG_DrawText |
|
||||
btIDebugDraw::DBG_DrawConstraintLimits |
|
||||
btIDebugDraw::DBG_DrawConstraints |
|
||||
btIDebugDraw::DBG_DrawConstraintLimits
|
||||
);
|
||||
world->dynamicsWorld->setDebugDrawer(debugDrawer);
|
||||
|
||||
return world;
|
||||
}
|
||||
|
||||
@@ -200,7 +399,12 @@ void RB_dworld_set_split_impulse(rbDynamicsWorld *world, int split_impulse)
|
||||
|
||||
void RB_dworld_step_simulation(rbDynamicsWorld *world, float timeStep, int maxSubSteps, float timeSubStep)
|
||||
{
|
||||
world->elapsed_time += timeStep;
|
||||
world->dynamicsWorld->stepSimulation(timeStep, maxSubSteps, timeSubStep);
|
||||
|
||||
// draw debug information
|
||||
GPU_debug_reset();
|
||||
world->dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
|
||||
/* Export -------------------------- */
|
||||
@@ -237,6 +441,7 @@ void RB_dworld_add_body(rbDynamicsWorld *world, rbRigidBody *object, int col_gro
|
||||
{
|
||||
btRigidBody *body = object->body;
|
||||
object->col_groups = col_groups;
|
||||
object->world = world;
|
||||
|
||||
world->dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
@@ -312,12 +517,18 @@ rbRigidBody *RB_body_new(rbCollisionShape *shape, const float loc[3], const floa
|
||||
btDefaultMotionState *motionState = new btDefaultMotionState(trans);
|
||||
|
||||
/* make rigidbody */
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->cshape);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(1.0f, motionState, shape->compound);
|
||||
|
||||
object->body = new btRigidBody(rbInfo);
|
||||
|
||||
object->body->setUserPointer(object);
|
||||
|
||||
object->is_trigger = false;
|
||||
object->suspended = false;
|
||||
|
||||
if (shape->cshape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE)
|
||||
object->body->setCollisionFlags(object->body->getCollisionFlags() | btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
@@ -352,7 +563,7 @@ void RB_body_set_collision_shape(rbRigidBody *object, rbCollisionShape *shape)
|
||||
btRigidBody *body = object->body;
|
||||
|
||||
/* set new collision shape */
|
||||
body->setCollisionShape(shape->cshape);
|
||||
body->setCollisionShape(shape->compound);
|
||||
|
||||
/* recalculate inertia, since that depends on the collision shape... */
|
||||
RB_body_set_mass(object, RB_body_get_mass(object));
|
||||
@@ -385,9 +596,10 @@ void RB_body_set_mass(rbRigidBody *object, float value)
|
||||
btCollisionShape *shape = body->getCollisionShape();
|
||||
shape->calculateLocalInertia(value, localInertia);
|
||||
}
|
||||
|
||||
body->setMassProps(value, localInertia);
|
||||
body->updateInertiaTensor();
|
||||
if (!object->suspended) {
|
||||
body->setMassProps(value, localInertia);
|
||||
body->updateInertiaTensor();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -521,6 +733,8 @@ void RB_body_set_angular_factor(rbRigidBody *object, float x, float y, float z)
|
||||
|
||||
void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
|
||||
{
|
||||
if (object->suspended)
|
||||
return;
|
||||
btRigidBody *body = object->body;
|
||||
if (kinematic)
|
||||
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
@@ -528,6 +742,48 @@ void RB_body_set_kinematic_state(rbRigidBody *object, int kinematic)
|
||||
body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_KINEMATIC_OBJECT);
|
||||
}
|
||||
|
||||
void RB_body_suspend(rbRigidBody *object)
|
||||
{
|
||||
object->saved_mass = RB_body_get_mass(object);
|
||||
RB_body_set_mass(object, 0.0f);
|
||||
object->suspended = true;
|
||||
}
|
||||
|
||||
void RB_body_set_trigger(rbRigidBody *object, int trigger)
|
||||
{
|
||||
object->is_trigger = trigger;
|
||||
}
|
||||
|
||||
void RB_body_set_ghost(rbRigidBody *object, int ghost)
|
||||
{
|
||||
btRigidBody *body = object->body;
|
||||
if (ghost)
|
||||
body->setCollisionFlags(body->getCollisionFlags() | btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
else
|
||||
body->setCollisionFlags(body->getCollisionFlags() & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
|
||||
}
|
||||
|
||||
void RB_body_set_activation_type(rbRigidBody *object, int type)
|
||||
{
|
||||
object->activation_type = type;
|
||||
}
|
||||
|
||||
void RB_body_set_activation_time(rbRigidBody *object, double time)
|
||||
{
|
||||
object->activation_time = time;
|
||||
}
|
||||
|
||||
void RB_body_set_activation_impulse(rbRigidBody *object, float impulse)
|
||||
{
|
||||
object->activation_impulse = impulse;
|
||||
}
|
||||
|
||||
void RB_body_try_activation(rbRigidBody *object)
|
||||
{
|
||||
if (object->suspended && object->activation_time <= object->world->elapsed_time)
|
||||
activate(object);
|
||||
}
|
||||
|
||||
/* ............ */
|
||||
|
||||
void RB_body_set_activation_state(rbRigidBody *object, int use_deactivation)
|
||||
@@ -608,11 +864,31 @@ void RB_body_get_position(rbRigidBody *object, float v_out[3])
|
||||
copy_v3_btvec3(v_out, body->getWorldTransform().getOrigin());
|
||||
}
|
||||
|
||||
void RB_body_get_orientation(rbRigidBody *object, float v_out[4])
|
||||
void RB_body_get_pos_orn(rbRigidBody *object, float pos_out[3], float orn_out[4])
|
||||
{
|
||||
btRigidBody *body = object->body;
|
||||
|
||||
copy_quat_btquat(v_out, body->getWorldTransform().getRotation());
|
||||
copy_v3_btvec3(pos_out, body->getWorldTransform().getOrigin());
|
||||
copy_quat_btquat(orn_out, body->getWorldTransform().getRotation());
|
||||
}
|
||||
|
||||
void RB_body_get_compound_pos_orn(rbRigidBody *parent_object, rbCollisionShape *child_shape, float pos_out[3], float orn_out[4])
|
||||
{
|
||||
btRigidBody *body = parent_object->body;
|
||||
btCompoundShape *compound = (btCompoundShape*)body->getCollisionShape();
|
||||
btTransform transform = body->getWorldTransform();
|
||||
btTransform child_transform;
|
||||
|
||||
for (int i = 0; i < compound->getNumChildShapes(); i++) {
|
||||
if (child_shape->compound == compound->getChildShape(i)) {
|
||||
child_transform = compound->getChildTransform(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
transform *= child_transform;
|
||||
|
||||
copy_v3_btvec3(pos_out, transform.getOrigin());
|
||||
copy_quat_btquat(orn_out, transform.getRotation());
|
||||
}
|
||||
|
||||
/* ............ */
|
||||
@@ -630,44 +906,54 @@ void RB_body_apply_central_force(rbRigidBody *object, const float v_in[3])
|
||||
|
||||
/* Setup (Standard Shapes) ----------- */
|
||||
|
||||
rbCollisionShape *RB_shape_new_box(float x, float y, float z)
|
||||
static rbCollisionShape *prepare_primitive_shape(btCollisionShape *cshape, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
shape->cshape = new btBoxShape(btVector3(x, y, z));
|
||||
shape->cshape = cshape;
|
||||
shape->mesh = NULL;
|
||||
shape->triangle_info_map = NULL;
|
||||
|
||||
btTransform world_transform = btTransform();
|
||||
world_transform.setIdentity();
|
||||
world_transform.setOrigin(btVector3(loc[0], loc[1], loc[2]));
|
||||
world_transform.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
|
||||
|
||||
shape->compound = new btCompoundShape();
|
||||
btTransform compound_transform;
|
||||
compound_transform.setIdentity();
|
||||
/* adjust center of mass */
|
||||
compound_transform.setOrigin(btVector3(center[0], center[1], center[2]));
|
||||
compound_transform.setRotation(btQuaternion(rot[1], rot[2], rot[3], rot[0]));
|
||||
compound_transform = world_transform.inverse() * compound_transform;
|
||||
|
||||
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_sphere(float radius)
|
||||
rbCollisionShape *RB_shape_new_box(float x, float y, float z, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
shape->cshape = new btSphereShape(radius);
|
||||
shape->mesh = NULL;
|
||||
return shape;
|
||||
return prepare_primitive_shape(new btBoxShape(btVector3(x, y, z)), loc, rot, center);
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_capsule(float radius, float height)
|
||||
rbCollisionShape *RB_shape_new_sphere(float radius, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
shape->cshape = new btCapsuleShapeZ(radius, height);
|
||||
shape->mesh = NULL;
|
||||
return shape;
|
||||
return prepare_primitive_shape(new btSphereShape(radius), loc, rot, center);
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_cone(float radius, float height)
|
||||
rbCollisionShape *RB_shape_new_capsule(float radius, float height, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
shape->cshape = new btConeShapeZ(radius, height);
|
||||
shape->mesh = NULL;
|
||||
return shape;
|
||||
return prepare_primitive_shape(new btCapsuleShapeZ(radius, height), loc, rot, center);
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_cylinder(float radius, float height)
|
||||
rbCollisionShape *RB_shape_new_cone(float radius, float height, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
shape->cshape = new btCylinderShapeZ(btVector3(radius, radius, height));
|
||||
shape->mesh = NULL;
|
||||
return shape;
|
||||
return prepare_primitive_shape(new btConeShapeZ(radius, height), loc, rot, center);
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_cylinder(float radius, float height, const float loc[3], const float rot[4], const float center[3])
|
||||
{
|
||||
return prepare_primitive_shape(new btCylinderShapeZ(btVector3(radius, radius, height)), loc, rot, center);
|
||||
}
|
||||
|
||||
/* Setup (Convex Hull) ------------ */
|
||||
@@ -687,65 +973,203 @@ rbCollisionShape *RB_shape_new_convex_hull(float *verts, int stride, int count,
|
||||
|
||||
shape->cshape = hull_shape;
|
||||
shape->mesh = NULL;
|
||||
shape->triangle_info_map = NULL;
|
||||
|
||||
shape->compound = new btCompoundShape();
|
||||
btTransform compound_transform;
|
||||
compound_transform.setIdentity();
|
||||
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
/* Setup (Triangle Mesh) ---------- */
|
||||
|
||||
/* Need to call rbTriMeshNewData() followed by rbTriMeshAddTriangle() several times
|
||||
* to set up the mesh buffer BEFORE calling rbShapeNewTriMesh(). Otherwise,
|
||||
* we get nasty crashes...
|
||||
*/
|
||||
/* Need to call RB_trimesh_finish() after creating triangle mesh and adding vertices and triangles */
|
||||
|
||||
rbMeshData *RB_trimesh_data_new()
|
||||
rbMeshData *RB_trimesh_data_new(int num_tris, int num_verts)
|
||||
{
|
||||
// XXX: welding threshold?
|
||||
return (rbMeshData *) new btTriangleMesh(true, false);
|
||||
rbMeshData *mesh = new rbMeshData;
|
||||
mesh->vertices = new rbVert[num_verts];
|
||||
mesh->triangles = new rbTri[num_tris];
|
||||
mesh->num_vertices = num_verts;
|
||||
mesh->num_triangles = num_tris;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void RB_trimesh_add_triangle(rbMeshData *mesh, const float v1[3], const float v2[3], const float v3[3])
|
||||
|
||||
static void RB_trimesh_data_delete(rbMeshData *mesh)
|
||||
{
|
||||
btTriangleMesh *meshData = reinterpret_cast<btTriangleMesh*>(mesh);
|
||||
|
||||
/* cast vertices to usable forms for Bt-API */
|
||||
btVector3 vtx1((btScalar)v1[0], (btScalar)v1[1], (btScalar)v1[2]);
|
||||
btVector3 vtx2((btScalar)v2[0], (btScalar)v2[1], (btScalar)v2[2]);
|
||||
btVector3 vtx3((btScalar)v3[0], (btScalar)v3[1], (btScalar)v3[2]);
|
||||
|
||||
/* add to the mesh
|
||||
* - remove duplicated verts is enabled
|
||||
*/
|
||||
meshData->addTriangle(vtx1, vtx2, vtx3, false);
|
||||
delete mesh->index_array;
|
||||
delete mesh->vertices;
|
||||
delete mesh->triangles;
|
||||
delete mesh;
|
||||
}
|
||||
|
||||
void RB_trimesh_add_vertices(rbMeshData *mesh, float *vertices, int num_verts, int vert_stride)
|
||||
{
|
||||
for (int i = 0; i < num_verts; i++) {
|
||||
float *vert = (float*)(((char*)vertices + i * vert_stride));
|
||||
mesh->vertices[i].x = vert[0];
|
||||
mesh->vertices[i].y = vert[1];
|
||||
mesh->vertices[i].z = vert[2];
|
||||
}
|
||||
}
|
||||
void RB_trimesh_add_triangle_indices(rbMeshData *mesh, int num, int index0, int index1, int index2)
|
||||
{
|
||||
mesh->triangles[num].v0 = index0;
|
||||
mesh->triangles[num].v1 = index1;
|
||||
mesh->triangles[num].v2 = index2;
|
||||
}
|
||||
void RB_trimesh_finish(rbMeshData *mesh)
|
||||
{
|
||||
mesh->index_array = new btTriangleIndexVertexArray(mesh->num_triangles, (int*)mesh->triangles, sizeof(rbTri),
|
||||
mesh->num_vertices, (float*)mesh->vertices, sizeof(rbVert));
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_trimesh(rbMeshData *mesh)
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh);
|
||||
|
||||
/* triangle-mesh we create is a BVH wrapper for triangle mesh data (for faster lookups) */
|
||||
// RB_TODO perhaps we need to allow saving out this for performance when rebuilding?
|
||||
btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(tmesh, true, true);
|
||||
btBvhTriangleMeshShape *unscaledShape = new btBvhTriangleMeshShape(mesh->index_array, true, true);
|
||||
|
||||
shape->triangle_info_map = new btTriangleInfoMap();
|
||||
// btGenerateInternalEdgeInfo(unscaledShape, shape->triangle_info_map);
|
||||
|
||||
shape->cshape = new btScaledBvhTriangleMeshShape(unscaledShape, btVector3(1.0f, 1.0f, 1.0f));
|
||||
shape->mesh = tmesh;
|
||||
shape->mesh = mesh;
|
||||
|
||||
shape->compound = new btCompoundShape();
|
||||
btTransform compound_transform;
|
||||
compound_transform.setIdentity();
|
||||
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
void RB_shape_trimesh_update(rbCollisionShape *shape, float *vertices, int num_verts, int vert_stride, float min[3], float max[3])
|
||||
{
|
||||
if (shape->mesh == NULL || num_verts != shape->mesh->num_vertices)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < num_verts; i++) {
|
||||
float *vert = (float*)(((char*)vertices + i * vert_stride));
|
||||
shape->mesh->vertices[i].x = vert[0];
|
||||
shape->mesh->vertices[i].y = vert[1];
|
||||
shape->mesh->vertices[i].z = vert[2];
|
||||
}
|
||||
|
||||
if (shape->cshape->getShapeType() == SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE) {
|
||||
btScaledBvhTriangleMeshShape *scaled_shape = (btScaledBvhTriangleMeshShape *)shape->cshape;
|
||||
btBvhTriangleMeshShape *mesh_shape = scaled_shape->getChildShape();
|
||||
mesh_shape->refitTree(btVector3(min[0], min[1], min[2]), btVector3(max[0], max[1], max[2]));
|
||||
}
|
||||
else if (shape->cshape->getShapeType() == GIMPACT_SHAPE_PROXYTYPE) {
|
||||
btGImpactMeshShape *mesh_shape = (btGImpactMeshShape*)shape->cshape;
|
||||
mesh_shape->updateBound();
|
||||
}
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_gimpact_mesh(rbMeshData *mesh)
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
/* interpret mesh buffer as btTriangleIndexVertexArray (i.e. an impl of btStridingMeshInterface) */
|
||||
btTriangleMesh *tmesh = reinterpret_cast<btTriangleMesh*>(mesh);
|
||||
|
||||
btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(tmesh);
|
||||
btGImpactMeshShape *gimpactShape = new btGImpactMeshShape(mesh->index_array);
|
||||
gimpactShape->updateBound(); // TODO: add this to the update collision margin call?
|
||||
|
||||
shape->cshape = gimpactShape;
|
||||
shape->mesh = tmesh;
|
||||
shape->mesh = mesh;
|
||||
shape->triangle_info_map = NULL;
|
||||
|
||||
shape->compound = new btCompoundShape();
|
||||
btTransform compound_transform;
|
||||
compound_transform.setIdentity();
|
||||
((btCompoundShape*)shape->compound)->addChildShape(compound_transform, shape->cshape);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
struct rbHACDMeshData {
|
||||
std::vector< HACD::Vec3<HACD::Real> > verts;
|
||||
std::vector< HACD::Vec3<long> > tris;
|
||||
};
|
||||
|
||||
rbHACDMeshData *RB_hacd_mesh_new(int num_tris, int num_verts)
|
||||
{
|
||||
rbHACDMeshData *mesh = new rbHACDMeshData;
|
||||
|
||||
mesh->verts.reserve(num_verts);
|
||||
mesh->tris.reserve(num_tris);
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void RB_hacd_mesh_add_triangle(rbHACDMeshData *mesh, const float v1[3], const float v2[3], const float v3[3])
|
||||
{
|
||||
mesh->tris.push_back(HACD::Vec3<long>(mesh->verts.size(), mesh->verts.size()+1, mesh->verts.size()+2));
|
||||
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v1[0], v1[1], v1[2]));
|
||||
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v2[0], v2[1], v2[2]));
|
||||
mesh->verts.push_back(HACD::Vec3<HACD::Real>(v3[0], v3[1], v3[2]));
|
||||
}
|
||||
|
||||
rbCollisionShape *RB_shape_new_convex_decomp(rbHACDMeshData *mesh)
|
||||
{
|
||||
rbCollisionShape *shape = new rbCollisionShape;
|
||||
btCompoundShape *compound = new btCompoundShape();
|
||||
|
||||
HACD::HACD hacd;
|
||||
hacd.SetPoints(&mesh->verts[0]);
|
||||
hacd.SetNPoints(mesh->verts.size());
|
||||
hacd.SetTriangles(&mesh->tris[0]);
|
||||
hacd.SetNTriangles(mesh->tris.size());
|
||||
|
||||
hacd.Compute();
|
||||
|
||||
int num_clusters = hacd.GetNClusters();
|
||||
|
||||
for (int i = 0; i < num_clusters; i++) {
|
||||
int num_verts = hacd.GetNPointsCH(i);
|
||||
int num_tris = hacd.GetNTrianglesCH(i);
|
||||
HACD::Vec3<HACD::Real> verts[num_verts];
|
||||
HACD::Vec3<long> tris[num_tris];
|
||||
hacd.GetCH(i, verts, tris);
|
||||
|
||||
btVector3 hull_verts[num_verts];
|
||||
for (int i = 0; i < num_verts; i++) {
|
||||
hull_verts[i].setX(verts[i].X());
|
||||
hull_verts[i].setY(verts[i].Y());
|
||||
hull_verts[i].setZ(verts[i].Z());
|
||||
}
|
||||
|
||||
btTransform transform;
|
||||
transform.setIdentity();
|
||||
btConvexHullShape *hull = new btConvexHullShape(&hull_verts[0].getX(), num_verts);
|
||||
compound->addChildShape(transform, hull);
|
||||
}
|
||||
|
||||
shape->mesh = NULL;
|
||||
shape->triangle_info_map = NULL;
|
||||
shape->compound = compound;
|
||||
shape->cshape = compound;
|
||||
|
||||
delete mesh;
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
void RB_shape_add_compound_child(rbRigidBody *parent, rbCollisionShape *child, float child_pos[3], float child_orn[4])
|
||||
{
|
||||
btCompoundShape *compound = (btCompoundShape*)parent->body->getCollisionShape();
|
||||
btTransform parent_transform = parent->body->getCenterOfMassTransform(); // TODO center of mass?
|
||||
btTransform transform;
|
||||
transform.setOrigin(btVector3(child_pos[0], child_pos[1], child_pos[2]));
|
||||
transform.setRotation(btQuaternion(child_orn[1], child_orn[2], child_orn[3], child_orn[0]));
|
||||
transform = parent_transform.inverse() * transform;
|
||||
compound->addChildShape(transform, child->compound);
|
||||
}
|
||||
|
||||
/* Cleanup --------------------------- */
|
||||
|
||||
void RB_shape_delete(rbCollisionShape *shape)
|
||||
@@ -756,8 +1180,12 @@ void RB_shape_delete(rbCollisionShape *shape)
|
||||
delete child_shape;
|
||||
}
|
||||
if (shape->mesh)
|
||||
delete shape->mesh;
|
||||
delete shape->cshape;
|
||||
RB_trimesh_data_delete(shape->mesh);
|
||||
if (shape->triangle_info_map)
|
||||
delete shape->triangle_info_map;
|
||||
if (shape->cshape != shape->compound)
|
||||
delete shape->cshape;
|
||||
delete shape->compound;
|
||||
delete shape;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@
|
||||
# <pep8 compliant>
|
||||
import bpy
|
||||
from bpy.types import Panel
|
||||
from bl_ui.properties_physics_common import effector_weights_ui
|
||||
|
||||
|
||||
class PHYSICS_PT_rigidbody_panel():
|
||||
@@ -44,10 +45,14 @@ class PHYSICS_PT_rigid_body(PHYSICS_PT_rigidbody_panel, Panel):
|
||||
|
||||
if rbo is not None:
|
||||
layout.prop(rbo, "type", text="Type")
|
||||
row = layout.row()
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
if rbo.type == 'ACTIVE':
|
||||
row.prop(rbo, "enabled", text="Dynamic")
|
||||
row.prop(rbo, "kinematic", text="Animated")
|
||||
col.prop(rbo, "enabled", text="Dynamic")
|
||||
col.prop(rbo, "kinematic", text="Animated")
|
||||
col = split.column()
|
||||
col.prop(rbo, "trigger", text="Trigger")
|
||||
col.prop(rbo, "ghost", text="Ghost")
|
||||
|
||||
if rbo.type == 'ACTIVE':
|
||||
layout.prop(rbo, "mass")
|
||||
@@ -69,6 +74,12 @@ class PHYSICS_PT_rigid_body_collisions(PHYSICS_PT_rigidbody_panel, Panel):
|
||||
rbo = ob.rigid_body
|
||||
|
||||
layout.prop(rbo, "collision_shape", text="Shape")
|
||||
|
||||
if rbo.collision_shape in {'MESH', 'CONVEX_HULL', 'APPROX'}:
|
||||
layout.prop(rbo, "mesh_source", text="Source")
|
||||
|
||||
if rbo.collision_shape == 'MESH' and rbo.mesh_source == 'DEFORM':
|
||||
layout.prop(rbo, "use_deform", text="Deforming")
|
||||
|
||||
split = layout.split()
|
||||
|
||||
@@ -107,26 +118,49 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel):
|
||||
ob = context.object
|
||||
rbo = ob.rigid_body
|
||||
|
||||
#col = layout.column(align=1)
|
||||
#col.label(text="Activation:")
|
||||
# XXX: settings such as activate on collison/etc.
|
||||
|
||||
split = layout.split()
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Activation:")
|
||||
col.prop(rbo, "use_start_deactivated")
|
||||
sub = col.column()
|
||||
sub.active = rbo.use_start_deactivated
|
||||
sub.prop(rbo, "activation_type", text="Type")
|
||||
if rbo.activation_type == 'TIME':
|
||||
sub.prop(rbo, "activation_time", text="Time")
|
||||
elif rbo.activation_type in {'COLLISION', 'TRIGGER'}:
|
||||
sub.prop(rbo, "activation_impulse", text="Threshold")
|
||||
|
||||
col = split.column()
|
||||
col.label(text="Deactivation:")
|
||||
col.prop(rbo, "use_deactivation")
|
||||
sub = col.column()
|
||||
sub.active = rbo.use_deactivation
|
||||
sub.prop(rbo, "use_start_deactivated")
|
||||
sub.prop(rbo, "deactivate_linear_velocity", text="Linear Vel")
|
||||
sub.prop(rbo, "deactivate_angular_velocity", text="Angular Vel")
|
||||
# TODO: other params such as time?
|
||||
|
||||
col = split.column()
|
||||
col = layout.column()
|
||||
col.label(text="Damping:")
|
||||
col.prop(rbo, "linear_damping", text="Translation")
|
||||
col.prop(rbo, "angular_damping", text="Rotation")
|
||||
|
||||
class PHYSICS_PT_rigid_body_field_weights(PHYSICS_PT_rigidbody_panel, Panel):
|
||||
bl_label = "Rigid Body Field Weights"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
COMPAT_ENGINES = {'BLENDER_RENDER'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
obj = context.object
|
||||
return (obj and obj.rigid_body and
|
||||
obj.rigid_body.type == 'ACTIVE' and
|
||||
(not context.scene.render.use_game_engine))
|
||||
|
||||
def draw(self, context):
|
||||
ob = context.object
|
||||
rbo = ob.rigid_body
|
||||
|
||||
effector_weights_ui(self, context, rbo.effector_weights, 'RIGID_BODY')
|
||||
|
||||
if __name__ == "__main__": # only for live edit.
|
||||
bpy.utils.register_module(__name__)
|
||||
|
@@ -2741,6 +2741,7 @@ class VIEW3D_PT_view3d_display(Panel):
|
||||
col.prop(view, "show_outline_selected")
|
||||
col.prop(view, "show_all_objects_origin")
|
||||
col.prop(view, "show_relationship_lines")
|
||||
col.prop(view, "show_physics")
|
||||
|
||||
col = layout.column()
|
||||
col.active = display_all
|
||||
|
@@ -67,10 +67,7 @@ struct RigidBodyWorld *BKE_rigidbody_world_copy(struct RigidBodyWorld *rbw);
|
||||
void BKE_rigidbody_world_groups_relink(struct RigidBodyWorld *rbw);
|
||||
|
||||
/* 'validate' (i.e. make new or replace old) Physics-Engine objects */
|
||||
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, short rebuild);
|
||||
void BKE_rigidbody_validate_sim_object(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild);
|
||||
void BKE_rigidbody_validate_sim_shape(struct Object *ob, short rebuild);
|
||||
void BKE_rigidbody_validate_sim_constraint(struct RigidBodyWorld *rbw, struct Object *ob, short rebuild);
|
||||
void BKE_rigidbody_validate_sim_world(struct Scene *scene, struct RigidBodyWorld *rbw, bool rebuild);
|
||||
|
||||
/* -------------- */
|
||||
/* Utilities */
|
||||
|
@@ -1009,8 +1009,12 @@ static int ptcache_rigidbody_write(int index, void *rb_v, void **data, int UNUS
|
||||
|
||||
if (rbo->type == RBO_TYPE_ACTIVE) {
|
||||
#ifdef WITH_BULLET
|
||||
RB_body_get_position(rbo->physics_object, rbo->pos);
|
||||
RB_body_get_orientation(rbo->physics_object, rbo->orn);
|
||||
if (ob->parent && ob->parent->rigidbody_object && ob->parent->flag) {
|
||||
RB_body_get_compound_pos_orn(ob->parent->rigidbody_object->physics_object, rbo->physics_shape, rbo->pos, rbo->orn);
|
||||
}
|
||||
else {
|
||||
RB_body_get_pos_orn(rbo->physics_object, rbo->pos, rbo->orn);
|
||||
}
|
||||
#endif
|
||||
PTCACHE_DATA_FROM(data, BPHYS_DATA_LOCATION, rbo->pos);
|
||||
PTCACHE_DATA_FROM(data, BPHYS_DATA_ROTATION, rbo->orn);
|
||||
|
@@ -144,6 +144,10 @@ void BKE_rigidbody_free_object(Object *ob)
|
||||
rbo->physics_shape = NULL;
|
||||
}
|
||||
|
||||
/* free effector weights */
|
||||
if (rbo->effector_weights)
|
||||
MEM_freeN(rbo->effector_weights);
|
||||
|
||||
/* free data itself */
|
||||
MEM_freeN(rbo);
|
||||
ob->rigidbody_object = NULL;
|
||||
@@ -178,11 +182,15 @@ void BKE_rigidbody_free_constraint(Object *ob)
|
||||
|
||||
RigidBodyOb *BKE_rigidbody_copy_object(Object *ob)
|
||||
{
|
||||
RigidBodyOb *rbo = ob->rigidbody_object;
|
||||
RigidBodyOb *rboN = NULL;
|
||||
|
||||
if (ob->rigidbody_object) {
|
||||
if (rbo) {
|
||||
/* just duplicate the whole struct first (to catch all the settings) */
|
||||
rboN = MEM_dupallocN(ob->rigidbody_object);
|
||||
rboN = MEM_dupallocN(rbo);
|
||||
|
||||
if (rbo->effector_weights)
|
||||
rboN->effector_weights = MEM_dupallocN(rbo->effector_weights);
|
||||
|
||||
/* tag object as needing to be verified */
|
||||
rboN->flag |= RBO_FLAG_NEEDS_VALIDATE;
|
||||
@@ -225,26 +233,47 @@ void BKE_rigidbody_relink_constraint(RigidBodyCon *rbc)
|
||||
/* ************************************** */
|
||||
/* Setup Utilities - Validate Sim Instances */
|
||||
|
||||
/* get the appropriate DerivedMesh based on rigid body mesh source */
|
||||
static DerivedMesh *rigidbody_get_mesh(Object *ob)
|
||||
{
|
||||
if (ob->rigidbody_object->mesh_source == RBO_MESH_DEFORM) {
|
||||
return ob->derivedDeform;
|
||||
}
|
||||
else if (ob->rigidbody_object->mesh_source == RBO_MESH_FINAL) {
|
||||
return ob->derivedFinal;
|
||||
}
|
||||
else {
|
||||
return CDDM_from_mesh(ob->data, ob);
|
||||
}
|
||||
}
|
||||
|
||||
/* create collision shape of mesh - convex hull */
|
||||
static rbCollisionShape *rigidbody_get_shape_convexhull_from_mesh(Object *ob, float margin, bool *can_embed)
|
||||
{
|
||||
rbCollisionShape *shape = NULL;
|
||||
Mesh *me = NULL;
|
||||
DerivedMesh *dm = NULL;
|
||||
MVert *mvert = NULL;
|
||||
int totvert = 0;
|
||||
|
||||
if (ob->type == OB_MESH && ob->data) {
|
||||
me = ob->data;
|
||||
dm = rigidbody_get_mesh(ob);
|
||||
mvert = (dm) ? dm->getVertArray(dm) : NULL;
|
||||
totvert = (dm) ? dm->getNumVerts(dm) : 0;
|
||||
}
|
||||
else {
|
||||
printf("ERROR: cannot make Convex Hull collision shape for non-Mesh object\n");
|
||||
}
|
||||
|
||||
if (me && me->totvert) {
|
||||
shape = RB_shape_new_convex_hull((float *)me->mvert, sizeof(MVert), me->totvert, margin, can_embed);
|
||||
if (totvert) {
|
||||
shape = RB_shape_new_convex_hull((float *)mvert, sizeof(MVert), totvert, margin, can_embed);
|
||||
}
|
||||
else {
|
||||
printf("ERROR: no vertices to define Convex Hull collision shape with\n");
|
||||
}
|
||||
|
||||
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
|
||||
dm->release(dm);
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
@@ -256,14 +285,20 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
|
||||
rbCollisionShape *shape = NULL;
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
DerivedMesh *dm = CDDM_from_mesh(ob->data, ob);
|
||||
|
||||
DerivedMesh *dm = NULL;
|
||||
MVert *mvert;
|
||||
MFace *mface;
|
||||
int totvert;
|
||||
int totface;
|
||||
int tottris = 0;
|
||||
int triangle_index = 0;
|
||||
|
||||
dm = rigidbody_get_mesh(ob);
|
||||
|
||||
/* ensure mesh validity, then grab data */
|
||||
if (dm == NULL)
|
||||
return NULL;
|
||||
|
||||
DM_ensure_tessface(dm);
|
||||
|
||||
mvert = (dm) ? dm->getVertArray(dm) : NULL;
|
||||
@@ -279,31 +314,30 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
|
||||
rbMeshData *mdata;
|
||||
int i;
|
||||
|
||||
/* count triangles */
|
||||
for (i = 0; i < totface; i++) {
|
||||
(mface[i].v4) ? (tottris += 2) : (tottris += 1);
|
||||
}
|
||||
|
||||
/* init mesh data for collision shape */
|
||||
mdata = RB_trimesh_data_new();
|
||||
mdata = RB_trimesh_data_new(tottris, totvert);
|
||||
|
||||
RB_trimesh_add_vertices(mdata, (float*)mvert, totvert, sizeof(MVert));
|
||||
|
||||
/* loop over all faces, adding them as triangles to the collision shape
|
||||
* (so for some faces, more than triangle will get added)
|
||||
*/
|
||||
for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) {
|
||||
/* add first triangle - verts 1,2,3 */
|
||||
{
|
||||
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
|
||||
MVert *vb = (mface->v2 < totvert) ? (mvert + mface->v2) : (mvert);
|
||||
MVert *vc = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
|
||||
|
||||
RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co);
|
||||
}
|
||||
|
||||
RB_trimesh_add_triangle_indices(mdata, triangle_index, mface->v1, mface->v2, mface->v3);
|
||||
triangle_index++;
|
||||
/* add second triangle if needed - verts 1,3,4 */
|
||||
if (mface->v4) {
|
||||
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
|
||||
MVert *vb = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
|
||||
MVert *vc = (mface->v4 < totvert) ? (mvert + mface->v4) : (mvert);
|
||||
|
||||
RB_trimesh_add_triangle(mdata, va->co, vb->co, vc->co);
|
||||
RB_trimesh_add_triangle_indices(mdata, triangle_index, mface->v1, mface->v3, mface->v4);
|
||||
triangle_index++;
|
||||
}
|
||||
}
|
||||
RB_trimesh_finish(mdata);
|
||||
|
||||
/* construct collision shape
|
||||
*
|
||||
@@ -322,10 +356,86 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
|
||||
}
|
||||
}
|
||||
|
||||
/* cleanup temp data */
|
||||
if (dm) {
|
||||
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
|
||||
dm->release(dm);
|
||||
}
|
||||
else {
|
||||
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
|
||||
}
|
||||
|
||||
return shape;
|
||||
}
|
||||
|
||||
/* create collision shape of mesh - convex decomposition
|
||||
* returns NULL if creation fails.
|
||||
*/
|
||||
static rbCollisionShape *rigidbody_get_shape_convex_decomp_from_mesh(Object *ob)
|
||||
{
|
||||
rbCollisionShape *shape = NULL;
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
DerivedMesh *dm = NULL;
|
||||
|
||||
MVert *mvert;
|
||||
MFace *mface;
|
||||
int totvert;
|
||||
int totface;
|
||||
int tottris = 0;
|
||||
|
||||
dm = rigidbody_get_mesh(ob);
|
||||
|
||||
/* ensure mesh validity, then grab data */
|
||||
BLI_assert(dm!= NULL); // RB_TODO need to make sure there's no case where deform derived mesh doesn't exist
|
||||
DM_ensure_tessface(dm);
|
||||
|
||||
mvert = (dm) ? dm->getVertArray(dm) : NULL;
|
||||
totvert = (dm) ? dm->getNumVerts(dm) : 0;
|
||||
mface = (dm) ? dm->getTessFaceArray(dm) : NULL;
|
||||
totface = (dm) ? dm->getNumTessFaces(dm) : 0;
|
||||
|
||||
/* sanity checking - potential case when no data will be present */
|
||||
if ((totvert == 0) || (totface == 0)) {
|
||||
printf("WARNING: no geometry data converted for Mesh Collision Shape (ob = %s)\n", ob->id.name + 2);
|
||||
}
|
||||
else {
|
||||
rbHACDMeshData *mdata;
|
||||
int i;
|
||||
|
||||
/* count triangles */
|
||||
for (i = 0; (i < totface) && (mface); i++) {
|
||||
(mface->v4) ? (tottris += 2) : (tottris += 1);
|
||||
}
|
||||
|
||||
/* init mesh data for collision shape */
|
||||
mdata = RB_hacd_mesh_new(tottris, totvert);
|
||||
|
||||
/* loop over all faces, adding them as triangles to the collision shape
|
||||
* (so for some faces, more than triangle will get added)
|
||||
*/
|
||||
for (i = 0; (i < totface) && (mface) && (mvert); i++, mface++) {
|
||||
/* add first triangle - verts 1,2,3 */
|
||||
{
|
||||
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
|
||||
MVert *vb = (mface->v2 < totvert) ? (mvert + mface->v2) : (mvert);
|
||||
MVert *vc = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
|
||||
|
||||
RB_hacd_mesh_add_triangle(mdata, va->co, vb->co, vc->co);
|
||||
}
|
||||
|
||||
/* add second triangle if needed - verts 1,3,4 */
|
||||
if (mface->v4) {
|
||||
MVert *va = (mface->v1 < totvert) ? (mvert + mface->v1) : (mvert);
|
||||
MVert *vb = (mface->v3 < totvert) ? (mvert + mface->v3) : (mvert);
|
||||
MVert *vc = (mface->v4 < totvert) ? (mvert + mface->v4) : (mvert);
|
||||
|
||||
RB_hacd_mesh_add_triangle(mdata, va->co, vb->co, vc->co);
|
||||
}
|
||||
}
|
||||
shape = RB_shape_new_convex_decomp(mdata);
|
||||
}
|
||||
|
||||
if (dm && ob->rigidbody_object->mesh_source == RBO_MESH_BASE)
|
||||
dm->release(dm);
|
||||
}
|
||||
else {
|
||||
printf("ERROR: cannot make Triangular Mesh collision shape for non-Mesh object\n");
|
||||
@@ -334,15 +444,69 @@ static rbCollisionShape *rigidbody_get_shape_trimesh_from_mesh(Object *ob)
|
||||
return shape;
|
||||
}
|
||||
|
||||
/* check parent child relationships to construct compound shapes */
|
||||
static void rigidbody_prepare_compounds(RigidBodyWorld *rbw)
|
||||
{
|
||||
GroupObject *go;
|
||||
for (go = rbw->group->gobject.first; go; go = go->next) {
|
||||
Object *ob = go->ob;
|
||||
RigidBodyOb *rbo = ob ? ob->rigidbody_object : NULL;
|
||||
if (rbo == NULL)
|
||||
continue;
|
||||
|
||||
if (ob->parent && ob->parent->rigidbody_object) {
|
||||
rbo->flag |= RBO_FLAG_COMPOUND_CHILD;
|
||||
ob->parent->rigidbody_object->flag |= RBO_FLAG_COMPOUND_PARENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* note, object must be a compound shape parent */
|
||||
static void rigidbody_compound_shape_add_children(RigidBodyWorld *rbw, Object *ob)
|
||||
{
|
||||
GroupObject *go;
|
||||
|
||||
RigidBodyOb *rbo = ob->rigidbody_object;
|
||||
if (rbo == NULL)
|
||||
return;
|
||||
|
||||
// RB_TODO check entire parent hirarchy not only one level.
|
||||
for (go = rbw->group->gobject.first; go; go = go->next) {
|
||||
Object *child_ob = go->ob;
|
||||
RigidBodyOb *child_rbo = child_ob ? child_ob->rigidbody_object : NULL;
|
||||
|
||||
if (child_rbo && child_rbo->flag & RBO_FLAG_COMPOUND_CHILD) {
|
||||
if (child_ob->parent == ob) {
|
||||
float pos[3], orn[4];
|
||||
mat4_to_loc_quat(pos, orn, child_ob->obmat);
|
||||
RB_shape_add_compound_child(rbo->physics_object, child_rbo->physics_shape, pos, orn);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rigidbody_update_compounds(RigidBodyWorld *rbw)
|
||||
{
|
||||
GroupObject *go;
|
||||
for (go = rbw->group->gobject.first; go; go = go->next) {
|
||||
Object *ob = go->ob;
|
||||
RigidBodyOb *rbo = ob ? ob->rigidbody_object : NULL;
|
||||
if (rbo && rbo->flag & RBO_FLAG_COMPOUND_PARENT)
|
||||
rigidbody_compound_shape_add_children(rbw, ob);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create new physics sim collision shape for object and store it,
|
||||
* or remove the existing one first and replace...
|
||||
*/
|
||||
void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
|
||||
static void rigidbody_validate_sim_shape(Object *ob, bool rebuild)
|
||||
{
|
||||
RigidBodyOb *rbo = ob->rigidbody_object;
|
||||
rbCollisionShape *new_shape = NULL;
|
||||
BoundBox *bb = NULL;
|
||||
float size[3] = {1.0f, 1.0f, 1.0f};
|
||||
float center[3], min[3], max[3];
|
||||
float loc[3], rot[4];
|
||||
float radius = 1.0f;
|
||||
float height = 1.0f;
|
||||
float capsule_height;
|
||||
@@ -383,25 +547,33 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
|
||||
radius = MAX3(size[0], size[1], size[2]);
|
||||
}
|
||||
|
||||
mat4_to_loc_quat(loc, rot, ob->obmat);
|
||||
|
||||
/* calculate world space center of object */
|
||||
mul_v3_m4v3(min, ob->obmat, bb->vec[0]);
|
||||
mul_v3_m4v3(max, ob->obmat, bb->vec[6]);
|
||||
add_v3_v3v3(center, max, min);
|
||||
mul_v3_fl(center, 0.5f);
|
||||
|
||||
/* create new shape */
|
||||
switch (rbo->shape) {
|
||||
case RB_SHAPE_BOX:
|
||||
new_shape = RB_shape_new_box(size[0], size[1], size[2]);
|
||||
new_shape = RB_shape_new_box(size[0], size[1], size[2], loc, rot, center);
|
||||
break;
|
||||
|
||||
case RB_SHAPE_SPHERE:
|
||||
new_shape = RB_shape_new_sphere(radius);
|
||||
new_shape = RB_shape_new_sphere(radius, loc, rot, center);
|
||||
break;
|
||||
|
||||
case RB_SHAPE_CAPSULE:
|
||||
capsule_height = (height - radius) * 2.0f;
|
||||
new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f);
|
||||
new_shape = RB_shape_new_capsule(radius, (capsule_height > 0.0f) ? capsule_height : 0.0f, loc, rot, center);
|
||||
break;
|
||||
case RB_SHAPE_CYLINDER:
|
||||
new_shape = RB_shape_new_cylinder(radius, height);
|
||||
new_shape = RB_shape_new_cylinder(radius, height, loc, rot, center);
|
||||
break;
|
||||
case RB_SHAPE_CONE:
|
||||
new_shape = RB_shape_new_cone(radius, height * 2.0f);
|
||||
new_shape = RB_shape_new_cone(radius, height * 2.0f, loc, rot, center);
|
||||
break;
|
||||
|
||||
case RB_SHAPE_CONVEXH:
|
||||
@@ -417,6 +589,9 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
|
||||
case RB_SHAPE_TRIMESH:
|
||||
new_shape = rigidbody_get_shape_trimesh_from_mesh(ob);
|
||||
break;
|
||||
case RB_SHAPE_APPROX:
|
||||
new_shape = rigidbody_get_shape_convex_decomp_from_mesh(ob);
|
||||
break;
|
||||
}
|
||||
/* assign new collision shape if creation was successful */
|
||||
if (new_shape) {
|
||||
@@ -425,9 +600,10 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
|
||||
rbo->physics_shape = new_shape;
|
||||
RB_shape_set_margin(rbo->physics_shape, RBO_GET_MARGIN(rbo));
|
||||
}
|
||||
else { /* otherwise fall back to box shape */
|
||||
/* use box shape if we can't fall back to old shape */
|
||||
else if (rbo->physics_shape == NULL) {
|
||||
rbo->shape = RB_SHAPE_BOX;
|
||||
BKE_rigidbody_validate_sim_shape(ob, true);
|
||||
rigidbody_validate_sim_shape(ob, true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -436,7 +612,7 @@ void BKE_rigidbody_validate_sim_shape(Object *ob, short rebuild)
|
||||
/* Create physics sim representation of object given RigidBody settings
|
||||
* < rebuild: even if an instance already exists, replace it
|
||||
*/
|
||||
void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short rebuild)
|
||||
static void rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, bool rebuild)
|
||||
{
|
||||
RigidBodyOb *rbo = (ob) ? ob->rigidbody_object : NULL;
|
||||
float loc[3];
|
||||
@@ -451,11 +627,10 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
|
||||
/* make sure collision shape exists */
|
||||
/* FIXME we shouldn't always have to rebuild collision shapes when rebuilding objects, but it's needed for constraints to update correctly */
|
||||
if (rbo->physics_shape == NULL || rebuild)
|
||||
BKE_rigidbody_validate_sim_shape(ob, true);
|
||||
rigidbody_validate_sim_shape(ob, true);
|
||||
|
||||
if (rbo->physics_object) {
|
||||
if (rebuild == false)
|
||||
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
|
||||
if (rbo->physics_object && rebuild == false) {
|
||||
RB_dworld_remove_body(rbw->physics_world, rbo->physics_object);
|
||||
}
|
||||
if (!rbo->physics_object || rebuild) {
|
||||
/* remove rigid body if it already exists before creating a new one */
|
||||
@@ -474,7 +649,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
|
||||
RB_body_set_sleep_thresh(rbo->physics_object, rbo->lin_sleep_thresh, rbo->ang_sleep_thresh);
|
||||
RB_body_set_activation_state(rbo->physics_object, rbo->flag & RBO_FLAG_USE_DEACTIVATION);
|
||||
|
||||
if (rbo->type == RBO_TYPE_PASSIVE || rbo->flag & RBO_FLAG_START_DEACTIVATED)
|
||||
if (rbo->type == RBO_TYPE_PASSIVE)
|
||||
RB_body_deactivate(rbo->physics_object);
|
||||
|
||||
|
||||
@@ -488,10 +663,17 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
|
||||
(ob->protectflag & OB_LOCK_ROTZ) == 0);
|
||||
|
||||
RB_body_set_mass(rbo->physics_object, RBO_GET_MASS(rbo));
|
||||
if (rbo->flag & RBO_FLAG_START_DEACTIVATED)
|
||||
RB_body_suspend(rbo->physics_object);
|
||||
RB_body_set_kinematic_state(rbo->physics_object, rbo->flag & RBO_FLAG_KINEMATIC || rbo->flag & RBO_FLAG_DISABLED);
|
||||
RB_body_set_trigger(rbo->physics_object, rbo->flag & RBO_FLAG_TRIGGER);
|
||||
RB_body_set_ghost(rbo->physics_object, rbo->flag & RBO_FLAG_GHOST);
|
||||
RB_body_set_activation_type(rbo->physics_object, rbo->activation_type);
|
||||
RB_body_set_activation_time(rbo->physics_object, rbo->activation_time);
|
||||
RB_body_set_activation_impulse(rbo->physics_object, rbo->activation_impulse);
|
||||
}
|
||||
|
||||
if (rbw && rbw->physics_world)
|
||||
if (rbw && rbw->physics_world && (rbo->flag & RBO_FLAG_COMPOUND_CHILD) == 0) // RB_TODO find better solution for compound shapes
|
||||
RB_dworld_add_body(rbw->physics_world, rbo->physics_object, rbo->col_groups);
|
||||
}
|
||||
|
||||
@@ -500,7 +682,7 @@ void BKE_rigidbody_validate_sim_object(RigidBodyWorld *rbw, Object *ob, short re
|
||||
/* Create physics sim representation of constraint given rigid body constraint settings
|
||||
* < rebuild: even if an instance already exists, replace it
|
||||
*/
|
||||
void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, short rebuild)
|
||||
static void rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, bool rebuild)
|
||||
{
|
||||
RigidBodyCon *rbc = (ob) ? ob->rigidbody_constraint : NULL;
|
||||
float loc[3];
|
||||
@@ -672,7 +854,7 @@ void BKE_rigidbody_validate_sim_constraint(RigidBodyWorld *rbw, Object *ob, shor
|
||||
|
||||
/* Create physics sim world given RigidBody world settings */
|
||||
// NOTE: this does NOT update object references that the scene uses, in case those aren't ready yet!
|
||||
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, short rebuild)
|
||||
void BKE_rigidbody_validate_sim_world(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
|
||||
{
|
||||
/* sanity checks */
|
||||
if (rbw == NULL)
|
||||
@@ -772,6 +954,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
|
||||
/* create new settings data, and link it up */
|
||||
rbo = MEM_callocN(sizeof(RigidBodyOb), "RigidBodyOb");
|
||||
|
||||
rbo->effector_weights = BKE_add_effector_weights(NULL);
|
||||
|
||||
/* set default settings */
|
||||
rbo->type = type;
|
||||
|
||||
@@ -790,6 +974,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
|
||||
|
||||
rbo->col_groups = 1;
|
||||
|
||||
rbo->activation_time = 1.0f;
|
||||
|
||||
/* use triangle meshes for passive objects
|
||||
* use convex hulls for active objects since dynamic triangle meshes are very unstable
|
||||
*/
|
||||
@@ -797,6 +983,8 @@ RigidBodyOb *BKE_rigidbody_create_object(Scene *scene, Object *ob, short type)
|
||||
rbo->shape = RB_SHAPE_CONVEXH;
|
||||
else
|
||||
rbo->shape = RB_SHAPE_TRIMESH;
|
||||
|
||||
rbo->mesh_source = RBO_MESH_DEFORM;
|
||||
|
||||
/* set initial transform */
|
||||
mat4_to_loc_quat(rbo->pos, rbo->orn, ob->obmat);
|
||||
@@ -1000,6 +1188,20 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
|
||||
if (rbo->physics_object == NULL)
|
||||
return;
|
||||
|
||||
if (rbo->shape == RB_SHAPE_TRIMESH && rbo->flag & RBO_FLAG_USE_DEFORM) {
|
||||
DerivedMesh *dm = ob->derivedDeform;
|
||||
if (dm) {
|
||||
MVert *mvert = dm->getVertArray(dm);
|
||||
int totvert = dm->getNumVerts(dm);
|
||||
BoundBox *bb = BKE_object_boundbox_get(ob);
|
||||
|
||||
RB_shape_trimesh_update(rbo->physics_shape, (float*)mvert, totvert, sizeof(MVert), bb->vec[0], bb->vec[6]);
|
||||
}
|
||||
}
|
||||
|
||||
if (rbo->type == RBO_TYPE_ACTIVE && rbo->activation_type == RBO_ACTIVATION_TIME)
|
||||
RB_body_try_activation(rbo->physics_object);
|
||||
|
||||
mat4_decompose(loc, rot, scale, ob->obmat);
|
||||
|
||||
/* update scale for all objects */
|
||||
@@ -1022,13 +1224,16 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
|
||||
/* update influence of effectors - but don't do it on an effector */
|
||||
/* only dynamic bodies need effector update */
|
||||
else if (rbo->type == RBO_TYPE_ACTIVE && ((ob->pd == NULL) || (ob->pd->forcefield == PFIELD_NULL))) {
|
||||
EffectorWeights *effector_weights = rbw->effector_weights;
|
||||
EffectedPoint epoint;
|
||||
ListBase *effectors;
|
||||
ListBase *effectors_local;
|
||||
ListBase *effectors_global;
|
||||
|
||||
/* get effectors present in the group specified by effector_weights */
|
||||
effectors = pdInitEffectors(scene, ob, NULL, effector_weights);
|
||||
if (effectors) {
|
||||
effectors_local = pdInitEffectors(scene, ob, NULL, rbo->effector_weights);
|
||||
effectors_global = pdInitEffectors(scene, ob, NULL, rbw->effector_weights);
|
||||
if (effectors_local && effectors_global) {
|
||||
float eff_force_local[3] = {0.0f, 0.0f, 0.0f};
|
||||
float eff_force_global[3] = {0.0f, 0.0f, 0.0f};
|
||||
float eff_force[3] = {0.0f, 0.0f, 0.0f};
|
||||
float eff_loc[3], eff_vel[3];
|
||||
|
||||
@@ -1042,19 +1247,22 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
|
||||
/* calculate net force of effectors, and apply to sim object
|
||||
* - we use 'central force' since apply force requires a "relative position" which we don't have...
|
||||
*/
|
||||
pdDoEffectors(effectors, NULL, effector_weights, &epoint, eff_force, NULL);
|
||||
if (G.f & G_DEBUG)
|
||||
printf("\tapplying force (%f,%f,%f) to '%s'\n", eff_force[0], eff_force[1], eff_force[2], ob->id.name + 2);
|
||||
pdDoEffectors(effectors_local, NULL, rbo->effector_weights, &epoint, eff_force_local, NULL);
|
||||
pdDoEffectors(effectors_global, NULL, rbw->effector_weights, &epoint, eff_force_global, NULL);
|
||||
add_v3_v3v3(eff_force, eff_force_global, eff_force_local);
|
||||
mul_v3_fl(eff_force, 0.5f);
|
||||
/* activate object in case it is deactivated */
|
||||
if (!is_zero_v3(eff_force))
|
||||
if (!is_zero_v3(eff_force)) {
|
||||
/* adjust the force based on fps, use 24 as neutral point since it's blender's default */
|
||||
mul_v3_fl(eff_force, (float)FPS / 24.0f);
|
||||
RB_body_activate(rbo->physics_object);
|
||||
RB_body_apply_central_force(rbo->physics_object, eff_force);
|
||||
RB_body_apply_central_force(rbo->physics_object, eff_force);
|
||||
}
|
||||
}
|
||||
else if (G.f & G_DEBUG)
|
||||
printf("\tno forces to apply to '%s'\n", ob->id.name + 2);
|
||||
|
||||
/* cleanup */
|
||||
pdEndEffectors(&effectors);
|
||||
pdEndEffectors(&effectors_global);
|
||||
pdEndEffectors(&effectors_local);
|
||||
}
|
||||
/* NOTE: passive objects don't need to be updated since they don't move */
|
||||
|
||||
@@ -1066,7 +1274,7 @@ static void rigidbody_update_sim_ob(Scene *scene, RigidBodyWorld *rbw, Object *o
|
||||
/* Updates and validates world, bodies and shapes.
|
||||
* < rebuild: rebuild entire simulation
|
||||
*/
|
||||
static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int rebuild)
|
||||
static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, bool rebuild)
|
||||
{
|
||||
GroupObject *go;
|
||||
|
||||
@@ -1074,8 +1282,11 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
if (rebuild)
|
||||
BKE_rigidbody_validate_sim_world(scene, rbw, true);
|
||||
rigidbody_update_sim_world(scene, rbw);
|
||||
|
||||
|
||||
/* update objects */
|
||||
if (rebuild)
|
||||
rigidbody_prepare_compounds(rbw);
|
||||
|
||||
for (go = rbw->group->gobject.first; go; go = go->next) {
|
||||
Object *ob = go->ob;
|
||||
|
||||
@@ -1091,7 +1302,7 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
* - assume object to be active? That is the default for newly added settings...
|
||||
*/
|
||||
ob->rigidbody_object = BKE_rigidbody_create_object(scene, ob, RBO_TYPE_ACTIVE);
|
||||
BKE_rigidbody_validate_sim_object(rbw, ob, true);
|
||||
rigidbody_validate_sim_object(rbw, ob, true);
|
||||
|
||||
rbo = ob->rigidbody_object;
|
||||
}
|
||||
@@ -1100,15 +1311,15 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
/* refresh object... */
|
||||
if (rebuild) {
|
||||
/* World has been rebuilt so rebuild object */
|
||||
BKE_rigidbody_validate_sim_object(rbw, ob, true);
|
||||
rigidbody_validate_sim_object(rbw, ob, true);
|
||||
}
|
||||
else if (rbo->flag & RBO_FLAG_NEEDS_VALIDATE) {
|
||||
BKE_rigidbody_validate_sim_object(rbw, ob, false);
|
||||
rigidbody_validate_sim_object(rbw, ob, false);
|
||||
}
|
||||
/* refresh shape... */
|
||||
if (rbo->flag & RBO_FLAG_NEEDS_RESHAPE) {
|
||||
/* mesh/shape data changed, so force shape refresh */
|
||||
BKE_rigidbody_validate_sim_shape(ob, true);
|
||||
rigidbody_validate_sim_shape(ob, true);
|
||||
/* now tell RB sim about it */
|
||||
// XXX: we assume that this can only get applied for active/passive shapes that will be included as rigidbodies
|
||||
RB_body_set_collision_shape(rbo->physics_object, rbo->physics_shape);
|
||||
@@ -1120,6 +1331,10 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
rigidbody_update_sim_ob(scene, rbw, ob, rbo);
|
||||
}
|
||||
}
|
||||
|
||||
if (rebuild)
|
||||
rigidbody_update_compounds(rbw);
|
||||
|
||||
/* update constraints */
|
||||
if (rbw->constraints == NULL) /* no constraints, move on */
|
||||
return;
|
||||
@@ -1137,7 +1352,7 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
* constraint settings (perhaps it was added manually), add!
|
||||
*/
|
||||
ob->rigidbody_constraint = BKE_rigidbody_create_constraint(scene, ob, RBC_TYPE_FIXED);
|
||||
BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
|
||||
rigidbody_validate_sim_constraint(rbw, ob, true);
|
||||
|
||||
rbc = ob->rigidbody_constraint;
|
||||
}
|
||||
@@ -1145,10 +1360,10 @@ static void rigidbody_update_simulation(Scene *scene, RigidBodyWorld *rbw, int r
|
||||
/* perform simulation data updates as tagged */
|
||||
if (rebuild) {
|
||||
/* World has been rebuilt so rebuild constraint */
|
||||
BKE_rigidbody_validate_sim_constraint(rbw, ob, true);
|
||||
rigidbody_validate_sim_constraint(rbw, ob, true);
|
||||
}
|
||||
else if (rbc->flag & RBC_FLAG_NEEDS_VALIDATE) {
|
||||
BKE_rigidbody_validate_sim_constraint(rbw, ob, false);
|
||||
rigidbody_validate_sim_constraint(rbw, ob, false);
|
||||
}
|
||||
rbc->flag &= ~RBC_FLAG_NEEDS_VALIDATE;
|
||||
}
|
||||
|
@@ -4954,6 +4954,12 @@ static void direct_link_object(FileData *fd, Object *ob)
|
||||
if (ob->rigidbody_object) {
|
||||
RigidBodyOb *rbo = ob->rigidbody_object;
|
||||
|
||||
rbo->effector_weights = newdataadr(fd, rbo->effector_weights);
|
||||
if (rbo->effector_weights)
|
||||
rbo->effector_weights->group = newlibadr(fd, ob->id.lib, rbo->effector_weights->group);
|
||||
else
|
||||
rbo->effector_weights = BKE_add_effector_weights(NULL);
|
||||
|
||||
/* must nullify the references to physics sim objects, since they no-longer exist
|
||||
* (and will need to be recalculated)
|
||||
*/
|
||||
|
@@ -1525,6 +1525,7 @@ static void write_objects(WriteData *wd, ListBase *idbase)
|
||||
if (ob->rigidbody_object) {
|
||||
// TODO: if any extra data is added to handle duplis, will need separate function then
|
||||
writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object);
|
||||
writestruct(wd, DATA, "EffectorWeights", 1, ob->rigidbody_object->effector_weights);
|
||||
}
|
||||
if (ob->rigidbody_constraint) {
|
||||
writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint);
|
||||
|
@@ -347,6 +347,7 @@ static int rigidbody_objects_shape_change_exec(bContext *C, wmOperator *op)
|
||||
if (change) {
|
||||
/* send updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_POINTCACHE, NULL);
|
||||
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
/* done */
|
||||
return OPERATOR_FINISHED;
|
||||
@@ -535,6 +536,7 @@ static float rigidbody_object_calc_volume(Object *ob)
|
||||
*/
|
||||
case RB_SHAPE_CONVEXH:
|
||||
case RB_SHAPE_TRIMESH:
|
||||
case RB_SHAPE_APPROX:
|
||||
volume = size[0] * size[1] * size[2];
|
||||
break;
|
||||
|
||||
|
@@ -6203,7 +6203,7 @@ static void get_local_bounds(Object *ob, float center[3], float size[3])
|
||||
}
|
||||
#endif
|
||||
|
||||
static void draw_bb_quadric(BoundBox *bb, char type)
|
||||
static void draw_bb_quadric(BoundBox *bb, char type, float *offset)
|
||||
{
|
||||
float size[3], cent[3];
|
||||
GLUquadricObj *qobj = gluNewQuadric();
|
||||
@@ -6219,6 +6219,8 @@ static void draw_bb_quadric(BoundBox *bb, char type)
|
||||
cent[2] = 0.5f * (bb->vec[0][2] + bb->vec[1][2]);
|
||||
|
||||
glPushMatrix();
|
||||
if (offset)
|
||||
glTranslatef(offset[0], offset[1], offset[2]);
|
||||
if (type == OB_BOUND_SPHERE) {
|
||||
float scale = MAX3(size[0], size[1], size[2]);
|
||||
glTranslatef(cent[0], cent[1], cent[2]);
|
||||
@@ -6280,11 +6282,41 @@ static void draw_bounding_volume(Scene *scene, Object *ob, char type)
|
||||
BKE_boundbox_init_from_minmax(bb, min, max);
|
||||
}
|
||||
|
||||
if (bb == NULL) return;
|
||||
|
||||
if (type == OB_BOUND_BOX) draw_box(bb->vec);
|
||||
else draw_bb_quadric(bb, type);
|
||||
if (bb == NULL)
|
||||
return;
|
||||
|
||||
if (ob->gameflag & OB_BOUNDS) { /* need to offset bounds for game engine, so it's drawn around origin */
|
||||
float offset[3], center[3], min[3], max[3];
|
||||
|
||||
mul_v3_m4v3(min, ob->obmat, bb->vec[0]);
|
||||
mul_v3_m4v3(max, ob->obmat, bb->vec[6]);
|
||||
add_v3_v3v3(center, max, min);
|
||||
mul_v3_fl(center, 0.5f);
|
||||
|
||||
sub_v3_v3v3(offset, ob->obmat[3], center);
|
||||
|
||||
if (type == OB_BOUND_BOX) {
|
||||
float vec[8][3];
|
||||
add_v3_v3v3(vec[0], bb->vec[0], offset);
|
||||
add_v3_v3v3(vec[1], bb->vec[1], offset);
|
||||
add_v3_v3v3(vec[2], bb->vec[2], offset);
|
||||
add_v3_v3v3(vec[3], bb->vec[3], offset);
|
||||
add_v3_v3v3(vec[4], bb->vec[4], offset);
|
||||
add_v3_v3v3(vec[5], bb->vec[5], offset);
|
||||
add_v3_v3v3(vec[6], bb->vec[6], offset);
|
||||
add_v3_v3v3(vec[7], bb->vec[7], offset);
|
||||
draw_box(vec);
|
||||
}
|
||||
else {
|
||||
draw_bb_quadric(bb, type, offset);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (type == OB_BOUND_BOX)
|
||||
draw_box(bb->vec);
|
||||
else
|
||||
draw_bb_quadric(bb, type, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void drawtexspace(Object *ob)
|
||||
@@ -6567,6 +6599,36 @@ static void draw_object_matcap_check(Scene *scene, View3D *v3d, Object *ob)
|
||||
|
||||
}
|
||||
|
||||
static void draw_rigidbody_shape(Object *ob)
|
||||
{
|
||||
BoundBox *bb = NULL;
|
||||
|
||||
if (ob->type == OB_MESH) {
|
||||
bb = BKE_mesh_boundbox_get(ob);
|
||||
}
|
||||
|
||||
if (bb == NULL)
|
||||
return;
|
||||
|
||||
switch (ob->rigidbody_object->shape) {
|
||||
case RB_SHAPE_BOX:
|
||||
draw_box(bb->vec);
|
||||
break;
|
||||
case RB_SHAPE_SPHERE:
|
||||
draw_bb_quadric(bb, OB_BOUND_SPHERE, NULL);
|
||||
break;
|
||||
case RB_SHAPE_CONE:
|
||||
draw_bb_quadric(bb, OB_BOUND_CONE, NULL);
|
||||
break;
|
||||
case RB_SHAPE_CYLINDER:
|
||||
draw_bb_quadric(bb, OB_BOUND_CYLINDER, NULL);
|
||||
break;
|
||||
case RB_SHAPE_CAPSULE:
|
||||
draw_bb_quadric(bb, OB_BOUND_CAPSULE, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* main object drawing function, draws in selection
|
||||
* \param dflag (draw flag) can be DRAW_PICKING and/or DRAW_CONSTCOLOR, DRAW_SCENESET
|
||||
@@ -6709,6 +6771,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
|
||||
|
||||
/* draw-extra supported for boundbox drawmode too */
|
||||
if (dt >= OB_BOUNDBOX) {
|
||||
|
||||
dtx = ob->dtx;
|
||||
if (ob->mode & OB_MODE_EDIT) {
|
||||
// the only 2 extra drawtypes alowed in editmode
|
||||
@@ -7114,21 +7177,26 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short
|
||||
}
|
||||
|
||||
if (!render_override) {
|
||||
bConstraint *con;
|
||||
if ((v3d->flag2 & V3D_NO_PHYSICS) == 0) {
|
||||
bConstraint *con;
|
||||
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
|
||||
bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data;
|
||||
if (data->flag & CONSTRAINT_DRAW_PIVOT)
|
||||
draw_rigid_body_pivot(data, dflag, ob_wire_col);
|
||||
for (con = ob->constraints.first; con; con = con->next) {
|
||||
if (con->type == CONSTRAINT_TYPE_RIGIDBODYJOINT) {
|
||||
bRigidBodyJointConstraint *data = (bRigidBodyJointConstraint *)con->data;
|
||||
if (data->flag & CONSTRAINT_DRAW_PIVOT)
|
||||
draw_rigid_body_pivot(data, dflag, ob_wire_col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((ob->gameflag & OB_BOUNDS) && (ob->mode == OB_MODE_OBJECT)) {
|
||||
if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) {
|
||||
setlinestyle(2);
|
||||
draw_bounding_volume(scene, ob, ob->collision_boundtype);
|
||||
setlinestyle(0);
|
||||
if (ob->gameflag & OB_BOUNDS) {
|
||||
if (ob->boundtype != ob->collision_boundtype || (dtx & OB_DRAWBOUNDOX) == 0) {
|
||||
setlinestyle(2);
|
||||
draw_bounding_volume(scene, ob, ob->collision_boundtype);
|
||||
setlinestyle(0);
|
||||
}
|
||||
}
|
||||
if (ob->rigidbody_object) {
|
||||
draw_rigidbody_shape(ob);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3334,6 +3334,9 @@ static void view3d_main_area_draw_objects(const bContext *C, ARegion *ar, const
|
||||
draw_object(scene, ar, v3d, base, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// HACK draw bullet debug world
|
||||
GPU_debug_draw();
|
||||
|
||||
// REEB_draw();
|
||||
|
||||
|
@@ -45,6 +45,17 @@ struct View3D;
|
||||
struct RegionView3D;
|
||||
struct SmokeModifierData;
|
||||
|
||||
// HACK bullet debug draw functions
|
||||
typedef struct GPUDebugVert {
|
||||
float pos[3];
|
||||
float col[3];
|
||||
} GPUDebugVert;
|
||||
|
||||
void GPU_debug_add_line(float p1[3], float p2[3], float col[3]);
|
||||
void GPU_debug_add_point(float pos[3], float col[3]);
|
||||
void GPU_debug_draw(void);
|
||||
void GPU_debug_reset(void);
|
||||
|
||||
/* OpenGL drawing functions related to shading. These are also
|
||||
* shared with the game engine, where there were previously
|
||||
* duplicates of some of these functions. */
|
||||
|
@@ -74,6 +74,11 @@
|
||||
|
||||
extern Material defmaterial; /* from material.c */
|
||||
|
||||
static GPUDebugVert GPU_varr[100000];
|
||||
static int GPU_varr_numverts = 0;
|
||||
static GPUDebugVert GPU_parr[100000];
|
||||
static int GPU_parr_numverts = 0;
|
||||
|
||||
/* These are some obscure rendering functions shared between the
|
||||
* game engine and the blender, in this module to avoid duplicaten
|
||||
* and abstract them away from the rest a bit */
|
||||
@@ -87,6 +92,57 @@ static void gpu_mcol(unsigned int ucol)
|
||||
glColor3ub(cp[3], cp[2], cp[1]);
|
||||
}
|
||||
|
||||
// HACK bullet debug draw functions
|
||||
void GPU_debug_add_line(float p1[3], float p2[3], float col[3])
|
||||
{
|
||||
if (G.debug_value == 616) {
|
||||
copy_v3_v3(GPU_varr[GPU_varr_numverts].pos, p1);
|
||||
copy_v3_v3(GPU_varr[GPU_varr_numverts].col, col);
|
||||
GPU_varr_numverts++;
|
||||
copy_v3_v3(GPU_varr[GPU_varr_numverts].pos, p2);
|
||||
copy_v3_v3(GPU_varr[GPU_varr_numverts].col, col);
|
||||
GPU_varr_numverts++;
|
||||
}
|
||||
}
|
||||
void GPU_debug_add_point(float pos[3], float col[3])
|
||||
{
|
||||
if (G.debug_value == 616) {
|
||||
copy_v3_v3(GPU_parr[GPU_parr_numverts].pos, pos);
|
||||
copy_v3_v3(GPU_parr[GPU_parr_numverts].col, col);
|
||||
GPU_parr_numverts++;
|
||||
}
|
||||
}
|
||||
void GPU_debug_draw(void)
|
||||
{
|
||||
if (G.debug_value == 616) {
|
||||
// glDisable(GL_DEPTH_TEST);
|
||||
|
||||
glEnableClientState(GL_VERTEX_ARRAY);
|
||||
glEnableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(GPUDebugVert), GPU_varr);
|
||||
glColorPointer(3, GL_FLOAT, sizeof(GPUDebugVert), &(GPU_varr->col[0]));
|
||||
glDrawArrays(GL_LINES, 0, GPU_varr_numverts);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glPointSize(5.0f);
|
||||
|
||||
glVertexPointer(3, GL_FLOAT, sizeof(GPUDebugVert), GPU_parr);
|
||||
glColorPointer(3, GL_FLOAT, sizeof(GPUDebugVert), &(GPU_parr->col[0]));
|
||||
glDrawArrays(GL_POINTS, 0, GPU_parr_numverts);
|
||||
|
||||
glDisableClientState(GL_VERTEX_ARRAY);
|
||||
glDisableClientState(GL_COLOR_ARRAY);
|
||||
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
void GPU_debug_reset(void)
|
||||
{
|
||||
GPU_varr_numverts = 0;
|
||||
GPU_parr_numverts = 0;
|
||||
}
|
||||
|
||||
void GPU_render_text(MTFace *tface, int mode,
|
||||
const char *textstr, int textlen, unsigned int *col,
|
||||
float *v1, float *v2, float *v3, float *v4, int glattrib)
|
||||
|
@@ -103,7 +103,8 @@ typedef struct RigidBodyOb {
|
||||
|
||||
int flag; /* (eRigidBodyOb_Flag) */
|
||||
int col_groups; /* Collision groups that determines wich rigid bodies can collide with each other */
|
||||
int pad;
|
||||
short mesh_source; /* (eRigidBody_MeshSource) mesh source for mesh based collision shapes */
|
||||
short activation_type; /* (eRigidBody_ActivationType) specifies how the RigidBody can be activaged */
|
||||
|
||||
/* Physics Parameters */
|
||||
float mass; /* how much object 'weighs' (i.e. absolute 'amount of stuff' it holds) */
|
||||
@@ -121,7 +122,10 @@ typedef struct RigidBodyOb {
|
||||
|
||||
float orn[4]; /* rigid body orientation */
|
||||
float pos[3]; /* rigid body position */
|
||||
float pad1;
|
||||
float activation_time; /* time until body is activated */
|
||||
float activation_impulse; /* impulse threshold that needs to be reached for body to get activated */
|
||||
int pad;
|
||||
struct EffectorWeights *effector_weights;
|
||||
} RigidBodyOb;
|
||||
|
||||
|
||||
@@ -148,7 +152,16 @@ typedef enum eRigidBodyOb_Flag {
|
||||
/* rigidbody is not dynamically simulated */
|
||||
RBO_FLAG_DISABLED = (1 << 5),
|
||||
/* collision margin is not embedded (only used by convex hull shapes for now) */
|
||||
RBO_FLAG_USE_MARGIN = (1 << 6)
|
||||
RBO_FLAG_USE_MARGIN = (1 << 6),
|
||||
/* compound shape flags, should not be set manually */
|
||||
RBO_FLAG_COMPOUND_PARENT = (1 << 7),
|
||||
RBO_FLAG_COMPOUND_CHILD = (1 << 8),
|
||||
/* rigidbdody is used as a collision trigger */
|
||||
RBO_FLAG_TRIGGER = (1 << 9),
|
||||
/* rigidbdody has no collision response */
|
||||
RBO_FLAG_GHOST = (1 << 10),
|
||||
/* collision shape deforms during simulation (only for passive triangle mesh shapes) */
|
||||
RBO_FLAG_USE_DEFORM = (1 << 11)
|
||||
} eRigidBodyOb_Flag;
|
||||
|
||||
/* RigidBody Collision Shape */
|
||||
@@ -168,11 +181,28 @@ typedef enum eRigidBody_Shape {
|
||||
RB_SHAPE_CONVEXH,
|
||||
/* triangulated mesh */
|
||||
RB_SHAPE_TRIMESH,
|
||||
|
||||
/* concave mesh approximated using primitives */
|
||||
//RB_SHAPE_COMPOUND,
|
||||
/* concave mesh approximated using convex hulls */
|
||||
RB_SHAPE_APPROX
|
||||
} eRigidBody_Shape;
|
||||
|
||||
typedef enum eRigidBody_MeshSource {
|
||||
/* base mesh */
|
||||
RBO_MESH_BASE = 0,
|
||||
/* only deformations */
|
||||
RBO_MESH_DEFORM,
|
||||
/* final derived mesh */
|
||||
RBO_MESH_FINAL
|
||||
} eRigidBody_MeshSource;
|
||||
|
||||
typedef enum eRigidBody_ActivationType {
|
||||
/* body gets activated on collision with other bodies */
|
||||
RBO_ACTIVATION_COLLISION = 0,
|
||||
/* body gets activated on collision with a trigger body */
|
||||
RBO_ACTIVATION_TRIGGER,
|
||||
/* body gets activated after a certain ammount of time */
|
||||
RBO_ACTIVATION_TIME
|
||||
} eRigidBody_ActivationType;
|
||||
|
||||
/* ******************************** */
|
||||
/* RigidBody Constraint */
|
||||
|
||||
|
@@ -281,6 +281,7 @@ typedef struct View3D {
|
||||
#define V3D_SHOW_SOLID_MATCAP 8192 /* runtime flag */
|
||||
#define V3D_OCCLUDE_WIRE 16384
|
||||
#define V3D_SHADELESS_TEX 32768
|
||||
#define V3D_NO_PHYSICS 32768 // RB_FIXME need new drawing flag
|
||||
|
||||
|
||||
/* View3D->around */
|
||||
|
@@ -61,6 +61,8 @@ EnumPropertyItem rigidbody_object_shape_items[] = {
|
||||
"fewer vertices)"},
|
||||
{RB_SHAPE_TRIMESH, "MESH", ICON_MESH_MONKEY, "Mesh",
|
||||
"Mesh consisting of triangles only, allowing for more detailed interactions than convex hulls"},
|
||||
{RB_SHAPE_APPROX, "APPROX", ICON_MESH_MONKEY, "Approx",
|
||||
"Approximation of the mesh using convex decomposition"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
/* collision shapes of constraints in rigid body sim */
|
||||
@@ -76,6 +78,19 @@ EnumPropertyItem rigidbody_constraint_type_items[] = {
|
||||
{RBC_TYPE_MOTOR, "MOTOR", ICON_NONE, "Motor", "Drive rigid body around or along an axis"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
/* mesh source for collision shape creation */
|
||||
EnumPropertyItem rigidbody_mesh_source_items[] = {
|
||||
{RBO_MESH_BASE, "BASE", 0, "Base", "Base mesh"},
|
||||
{RBO_MESH_DEFORM, "DEFORM", 0, "Deform", "Deformations (shaps keys, deform modifiers"},
|
||||
{RBO_MESH_FINAL, "FINAL", 0, "Final", "All modifiers"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
EnumPropertyItem rigidbody_activation_type_items[] = {
|
||||
{RBO_ACTIVATION_COLLISION, "COLLISION", 0, "Collision", "Activation on collision with other rigid bodies"},
|
||||
{RBO_ACTIVATION_TRIGGER, "TRIGGER", 0, "Trigger", "Activation on collision with trigger object"},
|
||||
{RBO_ACTIVATION_TIME, "TIME", 0, "Time", "Activation after a specified ammount of time"},
|
||||
{0, NULL, 0, NULL, NULL}};
|
||||
|
||||
|
||||
#ifdef RNA_RUNTIME
|
||||
|
||||
@@ -768,7 +783,21 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Type", "Role of object in Rigid Body Simulations");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
|
||||
prop = RNA_def_property(srna, "mesh_source", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "mesh_source");
|
||||
RNA_def_property_enum_items(prop, rigidbody_mesh_source_items);
|
||||
RNA_def_property_ui_text(prop, "Mesh Source", "Source of the mesh used to create collision shape");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "activation_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, NULL, "activation_type");
|
||||
RNA_def_property_enum_items(prop, rigidbody_activation_type_items);
|
||||
RNA_def_property_ui_text(prop, "Activation Type", "Type of activation used");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
/* booleans */
|
||||
prop = RNA_def_property(srna, "enabled", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", RBO_FLAG_DISABLED);
|
||||
@@ -782,7 +811,7 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
|
||||
RNA_def_property_enum_funcs(prop, NULL, "rna_RigidBodyOb_shape_set", NULL);
|
||||
RNA_def_property_ui_text(prop, "Collision Shape", "Collision Shape of object in Rigid Body Simulations");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "kinematic", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_KINEMATIC);
|
||||
@@ -790,6 +819,23 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Kinematic", "Allow rigid body to be controlled by the animation system");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "trigger", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_TRIGGER);
|
||||
RNA_def_property_ui_text(prop, "Trigger", "Rigid body acts as collision trigger");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "ghost", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_GHOST);
|
||||
RNA_def_property_ui_text(prop, "Ghost", "Rigid body does not respond to collisions");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "use_deform", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_DEFORM);
|
||||
RNA_def_property_ui_text(prop, "Deforming", "Rigid body deforms during simulation");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
/* Physics Parameters */
|
||||
prop = RNA_def_property(srna, "mass", PROP_FLOAT, PROP_UNIT_MASS);
|
||||
RNA_def_property_float_sdna(prop, NULL, "mass");
|
||||
@@ -800,15 +846,29 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
/* Dynamics Parameters - Activation */
|
||||
// TODO: define and figure out how to implement these
|
||||
prop = RNA_def_property(srna, "activation_time", PROP_FLOAT, PROP_UNIT_TIME);
|
||||
RNA_def_property_float_sdna(prop, NULL, "activation_time");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_float_default(prop, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Time", "Time until activation");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
prop = RNA_def_property(srna, "activation_impulse", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, NULL, "activation_impulse");
|
||||
RNA_def_property_range(prop, 0.0f, FLT_MAX);
|
||||
RNA_def_property_float_default(prop, 1.0f);
|
||||
RNA_def_property_ui_text(prop, "Impulse Threshold", "Impulse that need to be reached for body to be activated");
|
||||
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
/* Dynamics Parameters - Deactivation */
|
||||
prop = RNA_def_property(srna, "use_deactivation", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", RBO_FLAG_USE_DEACTIVATION);
|
||||
RNA_def_property_boolean_default(prop, TRUE);
|
||||
RNA_def_property_boolean_funcs(prop, NULL, "rna_RigidBodyOb_activation_state_set");
|
||||
RNA_def_property_ui_text(prop, "Enable Deactivation",
|
||||
"Enable deactivation of resting rigid bodies (increases performance and stability "
|
||||
RNA_def_property_ui_text(prop, "Allow Deactivation",
|
||||
"Allow deactivation of resting rigid bodies (increases performance and stability "
|
||||
"but can cause glitches)");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
|
||||
@@ -900,6 +960,12 @@ static void rna_def_rigidbody_object(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Collision Groups", "Collision Groups Rigid Body belongs to");
|
||||
RNA_def_property_update(prop, NC_OBJECT | ND_POINTCACHE, "rna_RigidBodyOb_reset");
|
||||
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
|
||||
|
||||
/* effector weights */
|
||||
prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE);
|
||||
RNA_def_property_struct_type(prop, "EffectorWeights");
|
||||
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
|
||||
RNA_def_property_ui_text(prop, "Effector Weights", "");
|
||||
}
|
||||
|
||||
static void rna_def_rigidbody_constraint(BlenderRNA *brna)
|
||||
|
@@ -1971,6 +1971,11 @@ static void rna_def_space_view3d(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(prop, "Only Render", "Display only objects which will be rendered");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "show_physics", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, NULL, "flag2", V3D_NO_PHYSICS);
|
||||
RNA_def_property_ui_text(prop, "Physics", "Display physics visualization");
|
||||
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL);
|
||||
|
||||
prop = RNA_def_property(srna, "use_occlude_geometry", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "flag", V3D_ZBUF_SELECT);
|
||||
RNA_def_property_ui_text(prop, "Occlude Geometry", "Limit selection to visible (clipped with depth buffer)");
|
||||
|
@@ -121,6 +121,7 @@ endif()
|
||||
ge_logic_network
|
||||
ge_logic_ngnetwork
|
||||
ge_logic_loopbacknetwork
|
||||
extern_hacd
|
||||
extern_bullet
|
||||
bf_intern_guardedalloc
|
||||
bf_intern_memutil
|
||||
|
@@ -1063,6 +1063,7 @@ endif()
|
||||
|
||||
if(WITH_BULLET)
|
||||
list_insert_after(BLENDER_SORTED_LIBS "bf_blenkernel" "bf_intern_rigidbody")
|
||||
list_insert_after(BLENDER_SORTED_LIBS "bf_intern_rigidbody" "extern_hacd")
|
||||
endif()
|
||||
|
||||
if(WITH_BULLET AND NOT WITH_SYSTEM_BULLET)
|
||||
|
Reference in New Issue
Block a user