500 lines
13 KiB
Plaintext
500 lines
13 KiB
Plaintext
// Copyright (C) 2010, Guy Barrand. All rights reserved.
|
|
// See the file tools.license for terms.
|
|
|
|
#ifndef tools_sg_polyhedron
|
|
#define tools_sg_polyhedron
|
|
|
|
#include "node"
|
|
#include "sf"
|
|
#include "render_action"
|
|
#include "pick_action"
|
|
#include "bbox_action"
|
|
#include "state"
|
|
#include "render_manager"
|
|
#include "gstos"
|
|
#include "../hep/sf_polyhedron"
|
|
#include "../vmanip"
|
|
|
|
#include "tessellate"
|
|
|
|
namespace tools {
|
|
namespace sg {
|
|
|
|
class polyhedron : public node, public gstos {
|
|
TOOLS_NODE(polyhedron,tools::sg::polyhedron,node)
|
|
public:
|
|
hep::sf_polyhedron ph;
|
|
sf<bool> solid;
|
|
sf<bool> reduced_wire_frame;
|
|
sf<bool> enforce_edges;
|
|
public:
|
|
virtual const desc_fields& node_desc_fields() const {
|
|
TOOLS_FIELD_DESC_NODE_CLASS(tools::sg::polyhedron)
|
|
static const desc_fields s_v(parent::node_desc_fields(),4, //WARNING : take care of count.
|
|
TOOLS_ARG_FIELD_DESC(ph),
|
|
TOOLS_ARG_FIELD_DESC(solid),
|
|
TOOLS_ARG_FIELD_DESC(reduced_wire_frame),
|
|
TOOLS_ARG_FIELD_DESC(enforce_edges)
|
|
);
|
|
return s_v;
|
|
}
|
|
private:
|
|
void add_fields(){
|
|
add_field(&ph);
|
|
add_field(&solid);
|
|
add_field(&reduced_wire_frame);
|
|
add_field(&enforce_edges);
|
|
}
|
|
public: //node
|
|
|
|
typedef tessellate::prims_t prims_t;
|
|
|
|
protected: //gstos
|
|
virtual unsigned int create_gsto(std::ostream& a_out,render_manager& a_mgr) {
|
|
m_size = 0;
|
|
if(solid.value()) {
|
|
|
|
size_t sz = 0;
|
|
|
|
if(m_draw_edges) sz += m_xyzs.size();
|
|
|
|
{tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
const tess_prim& item = *(*it);
|
|
const std::vector<float>& coords = item.m_coords;
|
|
const std::vector<float>& norms = item.m_norms;
|
|
if(coords.empty()) continue;
|
|
if(norms.size()!=coords.size()) {
|
|
a_out << "tools::sg::polyhedron::create_gsto :"
|
|
<< " bad number of normals."
|
|
<< std::endl;
|
|
continue;
|
|
}
|
|
sz += coords.size()+norms.size();
|
|
}
|
|
}}
|
|
|
|
if(sz) {
|
|
|
|
float* buffer = new float[sz];
|
|
char* pos = (char*)buffer;
|
|
size_t psz = 0;
|
|
|
|
if(m_draw_edges) {
|
|
if(m_xyzs.size()) {
|
|
size_t _sz = m_xyzs.size()*sizeof(float);
|
|
::memcpy(pos,vec_data<float>(m_xyzs),_sz);
|
|
pos += _sz;
|
|
psz += _sz;
|
|
m_size = m_xyzs.size();
|
|
//m_xyzs.clear(); //we need them for pick,write,...
|
|
}
|
|
}
|
|
|
|
{tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
tess_prim& item = *(*it);
|
|
const std::vector<float>& coords = item.m_coords;
|
|
const std::vector<float>& norms = item.m_norms;
|
|
if(coords.empty()) continue;
|
|
if(norms.size()!=coords.size()) continue;
|
|
|
|
item.m_size = coords.size();
|
|
|
|
{item.m_pos_coords = psz;
|
|
size_t _sz = coords.size()*sizeof(float);
|
|
::memcpy(pos,vec_data<float>(coords),_sz);
|
|
pos += _sz;
|
|
psz += _sz;}
|
|
|
|
{item.m_pos_norms = psz;
|
|
size_t _sz = norms.size()*sizeof(float);
|
|
::memcpy(pos,vec_data<float>(norms),_sz);
|
|
pos += _sz;
|
|
psz += _sz;}
|
|
|
|
// we don't need coords, norms for rendering
|
|
// but needed for pick,write...
|
|
//coords.clear();
|
|
//norms.clear();
|
|
|
|
//we still need m_prims.
|
|
|
|
}
|
|
}}
|
|
|
|
unsigned int id = a_mgr.create_gsto_from_data(sz,buffer);
|
|
delete [] buffer;
|
|
return id;
|
|
}
|
|
|
|
} else {
|
|
m_size = m_xyzs.size();
|
|
return a_mgr.create_gsto_from_data(m_xyzs);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public:
|
|
virtual void render(render_action& a_action) {
|
|
const state& state = a_action.state();
|
|
|
|
bool draw_edges = false;
|
|
if(solid.value()) {
|
|
draw_edges = state.m_GL_LIGHTING?false:true;
|
|
if(enforce_edges.value()) draw_edges = true;
|
|
}
|
|
|
|
if( touched() ||
|
|
(draw_edges && m_xyzs.empty()) ||
|
|
(solid.value() && m_primss.empty()) ){
|
|
update_what what = lines;
|
|
if(solid.value()) what = draw_edges?faces_and_lines:faces;
|
|
update_sg(a_action.out(),what);
|
|
reset_touched();
|
|
}
|
|
|
|
unsigned int _id = 0;
|
|
if(state.m_use_gsto) {
|
|
m_draw_edges = draw_edges;
|
|
_id = get_gsto_id(a_action.out(),a_action.render_manager());
|
|
} else {
|
|
clean_gstos(&a_action.render_manager());
|
|
}
|
|
|
|
//a_action.out() << "debug : tools::sg::polyhedron::render_action :"
|
|
// << " m_xyzs.size() " << m_xyzs.size()
|
|
// << " m_primss.size() " << m_primss.size()
|
|
// << std::endl;
|
|
|
|
if(solid.value()) {
|
|
|
|
if(_id) {
|
|
|
|
a_action.begin_gsto(_id);
|
|
if(draw_edges && m_size) {
|
|
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
|
|
a_action.set_lighting(false);
|
|
a_action.color4f(0,0,0,1);
|
|
|
|
a_action.draw_gsto_v(gl::lines(),m_size/3,0);
|
|
|
|
//pushes back the filled polygons to avoid z-fighting with lines
|
|
a_action.set_polygon_offset(true);
|
|
|
|
a_action.color4f(state.m_color);
|
|
a_action.set_lighting(state.m_GL_LIGHTING);
|
|
}
|
|
|
|
{tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
const tess_prim& item = *(*it);
|
|
a_action.draw_gsto_vn(item.m_mode,item.m_size/3,item.m_pos_coords,item.m_pos_norms);
|
|
}
|
|
}}
|
|
|
|
a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
|
|
a_action.end_gsto();
|
|
} else {
|
|
|
|
if(draw_edges){
|
|
if(m_xyzs.size()) {
|
|
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
|
|
a_action.set_lighting(false);
|
|
a_action.color4f(0,0,0,1);
|
|
|
|
a_action.draw_vertex_array(gl::lines(),m_xyzs);
|
|
|
|
//pushes back the filled polygons to avoid z-fighting with lines
|
|
a_action.set_polygon_offset(true);
|
|
|
|
a_action.color4f(state.m_color);
|
|
a_action.set_lighting(state.m_GL_LIGHTING);
|
|
}
|
|
}
|
|
|
|
{tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
const tess_prim& item = *(*it);
|
|
const std::vector<float>& coords = item.m_coords;
|
|
if(coords.empty()) continue;
|
|
const std::vector<float>& norms = item.m_norms;
|
|
if(norms.size()!=coords.size()) {
|
|
a_action.out() << "tools::sg::polyhedron::render :"
|
|
<< " bad number of normals."
|
|
<< std::endl;
|
|
continue;
|
|
}
|
|
a_action.draw_vertex_normal_array(item.m_mode,coords,norms);
|
|
}
|
|
}}
|
|
a_action.set_polygon_offset(state.m_GL_POLYGON_OFFSET_FILL);
|
|
}
|
|
|
|
} else { //not solid
|
|
//Same logic as Inventor SoLightModel.model = BASE_COLOR.
|
|
a_action.set_lighting(false); // do we want that ?
|
|
|
|
if(_id) {
|
|
a_action.begin_gsto(_id);
|
|
a_action.draw_gsto_v(gl::lines(),m_size/3,0);
|
|
a_action.end_gsto();
|
|
} else {
|
|
a_action.draw_vertex_array(gl::lines(),m_xyzs);
|
|
}
|
|
|
|
a_action.set_lighting(state.m_GL_LIGHTING);
|
|
}
|
|
}
|
|
|
|
virtual void bbox(bbox_action& a_action) {
|
|
if(touched()) {
|
|
update_sg(a_action.out(),lines);
|
|
reset_touched();
|
|
}
|
|
if(solid.value()) {
|
|
tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
const tess_prim& item = *(*it);
|
|
const std::vector<float>& coords = item.m_coords;
|
|
a_action.add_points(coords);
|
|
}
|
|
}
|
|
} else {
|
|
a_action.add_points(m_xyzs);
|
|
}
|
|
}
|
|
|
|
virtual void pick(pick_action& a_action) {
|
|
if(touched()) {
|
|
update_what what = solid.value()?faces:lines;
|
|
update_sg(a_action.out(),what);
|
|
reset_touched();
|
|
}
|
|
if(solid.value()) {
|
|
tools_vforcit(prims_t,m_primss,itt) {
|
|
const prims_t& prims = *itt;
|
|
tools_vforcit(tess_prim*,prims,it) {
|
|
const tess_prim& item = *(*it);
|
|
const std::vector<float>& coords = item.m_coords;
|
|
if(a_action.add__primitive(*this,item.m_mode,coords,true)) return;
|
|
}
|
|
}
|
|
} else {
|
|
a_action.add__lines(*this,m_xyzs,true);
|
|
}
|
|
}
|
|
public:
|
|
polyhedron()
|
|
:parent()
|
|
,ph(hep::polyhedron())
|
|
,solid(true)
|
|
,reduced_wire_frame(true)
|
|
,enforce_edges(false)
|
|
|
|
,m_tess(0)
|
|
{
|
|
add_fields();
|
|
}
|
|
virtual ~polyhedron(){
|
|
_clear();
|
|
delete m_tess;
|
|
}
|
|
public:
|
|
polyhedron(const polyhedron& a_from)
|
|
:parent(a_from)
|
|
,gstos(a_from)
|
|
,ph(a_from.ph)
|
|
,solid(a_from.solid)
|
|
,reduced_wire_frame(a_from.reduced_wire_frame)
|
|
,enforce_edges(a_from.enforce_edges)
|
|
|
|
,m_xyzs(a_from.m_xyzs)
|
|
,m_tess(0)
|
|
{
|
|
add_fields();
|
|
}
|
|
polyhedron& operator=(const polyhedron& a_from){
|
|
parent::operator=(a_from);
|
|
gstos::operator=(a_from);
|
|
ph = a_from.ph;
|
|
solid = a_from.solid;
|
|
reduced_wire_frame = a_from.reduced_wire_frame;
|
|
enforce_edges = a_from.enforce_edges;
|
|
|
|
m_xyzs = a_from.m_xyzs;
|
|
|
|
return *this;
|
|
}
|
|
|
|
public:
|
|
enum update_what {
|
|
faces = 0,
|
|
lines = 1,
|
|
faces_and_lines
|
|
};
|
|
|
|
void update_sg(std::ostream& a_out,const update_what& a_what) {
|
|
//a_out << "debug : tools::sg::polyhedron::update_sg" << std::endl;
|
|
|
|
clean_gstos(); //must reset for all render_manager.
|
|
|
|
_clear();
|
|
|
|
const hep::polyhedron& sbPolyhedron = ph.value();
|
|
if(sbPolyhedron.GetNoFacets()<=0) {
|
|
//a_out << "tools::sg::polyhedron::update_sg : abnormal polyhedron." << std::endl;
|
|
return; // Abnormal polyhedron.
|
|
}
|
|
|
|
if((a_what==faces)||(a_what==faces_and_lines)) {
|
|
|
|
std::vector<double> doubles;
|
|
|
|
vec3d unitNormal;
|
|
vec3d* pV = sbPolyhedron.GetPV();
|
|
|
|
// Assume all facets are convex quadrilaterals :
|
|
bool notLastFace;
|
|
do {
|
|
notLastFace = sbPolyhedron.GetNextUnitNormal(unitNormal);
|
|
|
|
doubles.clear(); //begin POLYGON
|
|
|
|
bool notLastEdge;
|
|
int edgeFlag = 1;
|
|
do {
|
|
// optimize to avoid copying vec3f.
|
|
//notLastEdge = sbPolyhedron.GetNextVertex(vertex,edgeFlag);
|
|
int index;
|
|
notLastEdge = sbPolyhedron.GetNextVertexIndex(index,edgeFlag);
|
|
vec3d* vertex = pV+index; //WARNING : must not be modified !
|
|
|
|
doubles.push_back((*vertex)[0]);
|
|
doubles.push_back((*vertex)[1]);
|
|
doubles.push_back((*vertex)[2]);
|
|
|
|
} while (notLastEdge);
|
|
|
|
if(!m_tess) m_tess = new tessellate(a_out);
|
|
|
|
m_primss.push_back(prims_t());
|
|
prims_t& prims = m_primss.back();
|
|
|
|
m_tess->do_it(doubles.size()/3,vec_data(doubles),prims);
|
|
|
|
m_tess->clear();
|
|
|
|
} while (notLastFace);
|
|
}
|
|
|
|
if((a_what==lines)||(a_what==faces_and_lines)) {
|
|
float pvbx = 0;
|
|
float pvby = 0;
|
|
float pvbz = 0;
|
|
|
|
float pvex,pvey,pvez;
|
|
|
|
vec3d unitNormal;
|
|
vec3d* pV = sbPolyhedron.GetPV();
|
|
|
|
bool notLastFace;
|
|
do {
|
|
notLastFace = sbPolyhedron.GetNextUnitNormal(unitNormal);
|
|
|
|
// Treat edges :
|
|
int edgeFlag = 1;
|
|
int prevEdgeFlag = edgeFlag;
|
|
bool notLastEdge;
|
|
bool firstEdge = true;
|
|
do {
|
|
int index;
|
|
notLastEdge = sbPolyhedron.GetNextVertexIndex(index,edgeFlag);
|
|
vec3d* vertex = pV+index; //WARNING : must not be modified !
|
|
|
|
if(!reduced_wire_frame) edgeFlag = 1;
|
|
if(firstEdge) {
|
|
if(edgeFlag) {
|
|
pvbx = (float)(*vertex)[0];
|
|
pvby = (float)(*vertex)[1];
|
|
pvbz = (float)(*vertex)[2];
|
|
} else {
|
|
}
|
|
firstEdge = false;
|
|
prevEdgeFlag = edgeFlag;
|
|
} else {
|
|
if(edgeFlag!=prevEdgeFlag) {
|
|
if(edgeFlag) { // Pass to a visible edge :
|
|
pvbx = (float)(*vertex)[0];
|
|
pvby = (float)(*vertex)[1];
|
|
pvbz = (float)(*vertex)[2];
|
|
} else { // Pass to an invisible edge :
|
|
pvex = (float)(*vertex)[0];
|
|
pvey = (float)(*vertex)[1];
|
|
pvez = (float)(*vertex)[2];
|
|
|
|
m_xyzs.push_back(pvbx);
|
|
m_xyzs.push_back(pvby);
|
|
m_xyzs.push_back(pvbz);
|
|
|
|
m_xyzs.push_back(pvex);
|
|
m_xyzs.push_back(pvey);
|
|
m_xyzs.push_back(pvez);
|
|
}
|
|
prevEdgeFlag = edgeFlag;
|
|
} else {
|
|
if(edgeFlag) {
|
|
pvex = (float)(*vertex)[0];
|
|
pvey = (float)(*vertex)[1];
|
|
pvez = (float)(*vertex)[2];
|
|
|
|
m_xyzs.push_back(pvbx);
|
|
m_xyzs.push_back(pvby);
|
|
m_xyzs.push_back(pvbz);
|
|
|
|
m_xyzs.push_back(pvex);
|
|
m_xyzs.push_back(pvey);
|
|
m_xyzs.push_back(pvez);
|
|
|
|
pvbx = pvex;
|
|
pvby = pvey;
|
|
pvbz = pvez;
|
|
} else {
|
|
}
|
|
}
|
|
}
|
|
} while (notLastEdge);
|
|
} while (notLastFace);
|
|
|
|
}
|
|
}
|
|
|
|
const std::vector<float>& xyzs() const {return m_xyzs;}
|
|
|
|
protected:
|
|
void _clear(){
|
|
tools_vforit(prims_t,m_primss,it) raw_clear(*it);
|
|
m_primss.clear();
|
|
m_xyzs.clear();
|
|
}
|
|
|
|
protected:
|
|
std::vector<float> m_xyzs;
|
|
|
|
//gluTess
|
|
tessellate* m_tess;
|
|
std::vector<prims_t> m_primss;
|
|
|
|
size_t m_size;
|
|
bool m_draw_edges;
|
|
};
|
|
|
|
}}
|
|
|
|
#endif
|