Good day !
I’m currently trying to port the EggOctree tool (Egg Octree) to C++. I think I was able to put everything together correctly for the most part, however I get a segmentation fault when using the triangulate_polygons. I haven’t been able to make sense of it.
I have some code to reproduce the issue:
#include <panda3d/eggData.h>
#include <panda3d/eggGroupNode.h>
#include <panda3d/eggGroup.h>
#include <panda3d/eggPolygon.h>
#include <boost/concept_check.hpp>
#define MAX_3(a, b, c) (a > b && a > c ? a : (b > a && b > c ? b : c))
#define until(condition) while (!(condition))
#define unless(condition) if (!(condition))
struct Egg2EggOctree
{
struct Cell
{
LPoint3f min, max;
PT(EggGroupNode) group;
};
typedef std::vector<std::vector<std::vector<Cell> > > Cells;
public:
static void Build(const std::string& source_path, const std::string& dest, LPoint3f cell_size, bool collide = false)
{
Egg2EggOctree(source_path, dest, cell_size, collide);
}
private:
Egg2EggOctree(const std::string& source_path, const std::string& dest, LPoint3f cell_size, bool collide)
{
std::cout << "[EggOctree] Processing '" << source_path << "'. Output: '" << dest << '\'' << std::endl;
PT(EggData) egg = new EggData();
PT(EggData) egg_target = new EggData();
PT(EggGroupNode) source;
PT(EggVertexPool) vertex_pool;
LPoint3f minBB, maxBB;
int n_vertexes;
std::cout << ":: Loading egg file" << std::endl;
egg->read(source_path);
std::cout << "> Done" << std::endl;
egg->get_first_child();
source = reinterpret_cast<EggGroupNode*>(egg->get_next_child()); // the source node must contain a VertexPool and a list of Polygons
if (source->get_class_type() != egg->get_next_child()->get_type())
{
std::cout << "Oh shit ! It's not an EggGroupNode" << std::endl;
return ;
}
egg_target->set_coordinate_system(egg->get_coordinate_system());
std::cout << ":: Triangulating polygons" << std::endl;
// The following line crashes:
source->triangulate_polygons(EggGroupNode::T_polygon | EggGroupNode::T_convex);
std::cout << "> Done" << std::endl;
vertex_pool = reinterpret_cast<EggVertexPool*>(source->get_first_child());
n_vertexes = vertex_pool->get_highest_index();
for (int i = 0 ; i < n_vertexes ; ++i)
{
PT(EggVertex) vertex = vertex_pool->get_vertex(i);
LVertexd vertex_pos = vertex->get_pos3();
// Set the X, Y or Z components
#define SET_XYZ(coord) \
if (vertex_pos.get_##coord() < minBB.get_##coord()) \
{ minBB.set_##coord(vertex_pos.get_##coord()); }
SET_XYZ(x)
SET_XYZ(y)
SET_XYZ(z)
#undef SET_XYZ
}
{
LPoint3f bbox_size = maxBB - minBB;
ncx = ceil(bbox_size.get_x());
ncy = ceil(bbox_size.get_y());
ncz = ceil(bbox_size.get_z());
depth = MAX_3(ncx, ncy, ncz);
cells.resize(ncx);
for (int x = 0 ; x < ncx ; ++x)
{
cells[x].resize(ncy);
for (int y = 0 ; y < ncy ; ++y)
{
cells[x][y].resize(ncz);
for (int z = 0 ; z < ncz ; ++z)
{
Cell cell;
std::stringstream group_name;
cell.min = LPoint3f(minBB.get_x() + x * cell_size.get_x(),
minBB.get_y() + y * cell_size.get_y(),
minBB.get_z() + z * cell_size.get_z());
cell.max = LPoint3f(minBB.get_x() + (x + 1) * cell_size.get_x(),
minBB.get_y() + (y + 1) * cell_size.get_y(),
minBB.get_z() + (z + 1) * cell_size.get_z());
group_name << "leaf_" << x << '_' << y << '_' << z;
cell.group = new EggGroupNode(group_name.str());
cells[x][y][z] = cell;
}
}
}
if (collide)
{
for (int x = 0 ; x < ncx ; ++x)
{
for (int y = 0 ; y < ncy ; ++y)
{
for (int z = 0 ; z < ncz ; ++z)
{
// TODO Find out what should be happening here.
// cells[x][y][z].group->add_object_type("barrier");
}
}
}
// Iterate on the <Polygon>s (should be triangles)
PT(EggNode) node = source->get_next_child();
until (node.is_null())
{
if (node->is_of_type(EggPolygon::get_class_type()))
{
PT(EggPolygon) poly = reinterpret_cast<EggPolygon*>(node.p());
//
// Get the triangle center
//
LVertexd poly_center(0, 0, 0);
for (unsigned short i = 0 ; i < 3 ; ++i)
{
LVertexd pos3 = poly->get_vertex(i)->get_pos3();
poly_center += pos3;
}
poly_center /= 3.f;
//
// Add the triangle to the corresponding cell group
//
#define INIT_CXYZ(coord) floor(poly_center.get_##coord() - minBB.get_##coord()) / cell_size.get_##coord()
int cx = INIT_CXYZ(x);
int cy = INIT_CXYZ(y);
int cz = INIT_CXYZ(z);
#undef INIT_CXYZ
cells[cx][cy][cz].group->add_child(poly);
}
node = source->get_next_child();
}
egg_target->add_child(vertex_pool);
n_leaves = Recur(egg_target.p(), 0, 0, 0, 0);
std::cout << n_leaves << " leaves added" << std::endl;
}
}
std::cout << ":: Generating output file" << std::endl;
egg_target->write_egg(dest);
std::cout << "> Done" << std::endl;
}
template<typename T>
int Recur(T* node, int depth, int x, int y, int z)
{
if (depth < this->depth)
{
PT(EggGroup) nnode = new EggGroup("");
int delt = pow(2, this->depth - depth - 1);
int n_childs = 0;
n_childs += Recur(nnode.p(), depth + 1, x, y, z);
n_childs += Recur(nnode.p(), depth + 1, x + delt, y, z);
n_childs += Recur(nnode.p(), depth + 1, x, y + delt, z);
n_childs += Recur(nnode.p(), depth + 1, x + delt, y + delt, z);
n_childs += Recur(nnode.p(), depth + 1, x, y, z + delt);
n_childs += Recur(nnode.p(), depth + 1, x + delt, y, z + delt);
n_childs += Recur(nnode.p(), depth + 1, x, y + delt, z + delt);
n_childs += Recur(nnode.p(), depth + 1, x + delt, y + delt, z + delt);
if (n_childs > 0)
node->add_child(nnode);
return (n_childs);
}
{
// We are in a leaf
if (x < ncx && y < ncy && z < ncz)
{
node->add_child(cells[x][y][z].group);
return (1);
}
else
return (0);
}
}
Cells cells;
int n_leaves;
int depth;
int ncx, ncy, ncz;
};
int main(int argc, char** argv)
{
if (argc == 4 && std::string(argv[1]) == "--egg-octree")
{
Egg2EggOctree::Build(argv[2], argv[3], LPoint3f(5, 5, 5), true);
return (0);
}
return (1);
}
I figured maybe the type check was wrong, but as far as I know it’s supposed to be an EggGroupNode and I checked for that type (unless I did that check wrong).
What else could possibly be responsible ?
On another matter, I also haven’t been able to find what the addObjectType line was doing in the Python script, so I didn’t find any way to do it in C++. If anyone has a clue what it does it might prove useful !
Thanks !