Files
geant4/source/externals/g4tools/include/tools/sg/tessellate
T
2021-06-25 16:12:29 +02:00

533 lines
16 KiB
Plaintext

// Copyright (C) 2010, Guy Barrand. All rights reserved.
// See the file tools.license for terms.
#ifndef tools_sg_tessellate
#define tools_sg_tessellate
//#include "../tessellate"
#include <vector>
#include "../glprims"
#ifdef TOOLS_MEM
#include "../mem"
#include "../S_STRING"
#endif
namespace tools {
namespace sg {
class tess_prim {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::sg::tess_prim)
#endif
public:
tess_prim()
:m_mode(gl::triangles())
,m_size(0)
,m_pos_coords(0)
,m_pos_norms(0)
{
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~tess_prim(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
tess_prim(const tess_prim& a_from)
:m_mode(a_from.m_mode)
,m_coords(a_from.m_coords)
,m_norms(a_from.m_norms)
,m_size(a_from.m_size)
,m_pos_coords(a_from.m_pos_coords)
,m_pos_norms(a_from.m_pos_norms)
{
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
tess_prim& operator=(const tess_prim& a_from){
if(&a_from==this) return *this;
m_mode = a_from.m_mode;
m_coords = a_from.m_coords;
m_norms = a_from.m_norms;
m_size = a_from.m_size;
m_pos_coords = a_from.m_pos_coords;
m_pos_norms = a_from.m_pos_norms;
return *this;
}
public:
gl::mode_t m_mode;
std::vector<float> m_coords;
std::vector<float> m_norms;
//for gsto :
size_t m_size;
typedef size_t bufpos;
bufpos m_pos_coords;
bufpos m_pos_norms;
};
}}
#include "../vdata"
#include "../forit"
#include "primitive_visitor"
#include <ostream>
#include <cmath> //sqrt
#ifdef TOOLS_MEM
#include "../S_STRING"
#include "../mem"
#endif
#include "../glutess/glutess"
namespace tools {
namespace sg {
class tessellate {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::sg::tessellate);
#endif
public:
tessellate(std::ostream& a_out):m_out(a_out),m_tobj(0) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
m_tobj = gluNewTess();
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_BEGIN_DATA, (Func)begin_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_END_DATA, (Func)end_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_VERTEX_DATA, (Func)vertex_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_COMBINE_DATA,(Func)combine_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_ERROR_DATA, (Func)error_cbk);
//set winding rule to positive => no holes
::gluTessProperty(m_tobj,(GLUenum)GLU_TESS_WINDING_RULE,GLU_TESS_WINDING_POSITIVE);
//m_out << "tools::sg::tessellate::tessellate :"
// << " GL_TRIANGLE_STRIP " << GL_TRIANGLE_STRIP
// << " GL_TRIANGLE_FAN " << GL_TRIANGLE_FAN
// << " GL_TRIANGLES " << GL_TRIANGLES
// << std::endl;
}
virtual ~tessellate(){
::gluDeleteTess(m_tobj);
_clear();
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
tessellate(const tessellate& a_from):m_out(a_from.m_out),m_tobj(0) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
m_tobj = gluNewTess();
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_BEGIN_DATA, (Func)begin_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_END_DATA, (Func)end_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_VERTEX_DATA, (Func)vertex_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_COMBINE_DATA,(Func)combine_cbk);
::gluTessCallback(m_tobj,(GLUenum)GLU_TESS_ERROR_DATA, (Func)error_cbk);
//set winding rule to positive => no holes
::gluTessProperty(m_tobj,(GLUenum)GLU_TESS_WINDING_RULE,GLU_TESS_WINDING_POSITIVE);
}
tessellate& operator=(const tessellate& a_from){
if(&a_from==this) return *this;
_clear();
return *this;
}
public:
typedef std::vector<tess_prim*> prims_t;
void do_it(size_t a_npt,const double* a_contour,prims_t& a_prims){
::gluTessBeginPolygon(m_tobj,this);
::gluTessBeginContour(m_tobj);
double* pos = (double*)a_contour;
for(size_t i=0;i<a_npt;i++,pos+=3) {
::gluTessVertex(m_tobj,pos,pos);
}
::gluTessEndContour(m_tobj);
a_prims.clear();
m_prims = &a_prims;
m_combine_trids_num = 0;
::gluTessEndPolygon(m_tobj); //trigger callbacks and fill a_prims.
}
void clear(){_clear();}
protected:
typedef _GLUfuncptr Func;
static void GLUAPIENTRY begin_cbk(GLUenum a_which,void* a_this) {
tessellate& self = *((tessellate*)a_this);
self.m_prims->push_back(new tess_prim());
tess_prim& prim = *(self.m_prims->back());
prim.m_mode = a_which;
prim.m_coords.reserve(12); //4 points.
prim.m_norms.reserve(12);
self.m_coords = &prim.m_coords;
//::printf("tools::sg::tessellate::begin_cbk : %d : STRIP %d FAN %d TRIS %d\n",
// a_which,GL_TRIANGLE_STRIP,GL_TRIANGLE_FAN,GL_TRIANGLES);
}
static void GLUAPIENTRY vertex_cbk(void* a_vertex,void* a_this) {
tessellate& self = *((tessellate*)a_this);
double* vertex = (double*)a_vertex;
self.m_coords->push_back(float(vertex[0]));
self.m_coords->push_back(float(vertex[1]));
self.m_coords->push_back(float(vertex[2]));
}
typedef float _vec3f[3];
static void GLUAPIENTRY end_cbk(void* a_this){
tessellate& self = *((tessellate*)a_this);
tess_prim& prim = *(self.m_prims->back());
//self.m_out << "tools::sg::tessellate::end_cbk : "
// << prim.m_coords.size()/3 << std::endl;
add_prm aprm(self.m_out,prim.m_norms);
float* data = vec_data<float>(prim.m_coords);
bool ok = true;
if(prim.m_mode==gl::triangles()) {
if(!aprm.add_triangles(prim.m_coords.size(),data,false)) {
self.m_out << "tools::sg::tessellate::end_cbk : "
<< " add_triangles failed."
<< std::endl;
ok = false;
}
} else if(prim.m_mode==gl::triangle_strip()) {
if(!aprm.add_triangle_strip(prim.m_coords.size(),data,false)){
self.m_out << "tools::sg::tessellate::end_cbk : "
<< " add_triangle_strip failed."
<< std::endl;
ok = false;
}
} else if(prim.m_mode==gl::triangle_fan()) {
if(!aprm.add_triangle_fan(prim.m_coords.size(),data,false)) {
self.m_out << "tools::sg::tessellate::end_cbk : "
<< " add_triangle_fan failed."
<< std::endl;
ok = false;
}
} else {
self.m_out << "tools::sg::tessellate::end_cbk : "
<< " mode " << prim.m_mode << " not yet treated."
<< std::endl;
ok = false;
}
if(!ok) {
size_t num = prim.m_coords.size();
self.m_out << "tools::sg::tessellate::end_cbk :"
<< " primitive anomaly."
<< " num points " << num
<< " mode " << prim.m_mode
<< " (TRIANGLES=4, STRIP=5, FAN=6)."
<< std::endl;
float* pos = vec_data<float>(prim.m_coords);
for(size_t ipt=0;ipt<num;ipt++) {
self.m_out << " " << ipt << " :"
<< " " << *(pos+0)
<< " " << *(pos+1)
<< " " << *(pos+2)
<< std::endl;
pos += 3;
}
prim.m_coords.clear();
prim.m_norms.clear();
}
}
static void GLUAPIENTRY combine_cbk(double a_coords[3],
void* /*a_vertex_data*/[4],
float /*a_weight*/[4],
void** a_data_out,
void* a_this) {
tessellate& self = *((tessellate*)a_this);
double* v = self.add_combine_vec3d(a_coords[0],a_coords[1],a_coords[2]);
//if(!v) ???
*a_data_out = v;
}
static void GLUAPIENTRY error_cbk(GLUenum,void*) {
//const GLubyte* estring = gluErrorString(aErrorCode);
//::fprintf(stderr, "Tessellation Error: %s\n", estring);
//SbTessContour* This = (SbTessContour*)aThis;
//This->setError(true);
}
double* add_combine_vec3d(double a_x,double a_y,double a_z) {
double* v = 0;
if(m_combine_trids_num>=m_combine_trids.size()) {
v = new double[3];
m_combine_trids.push_back(v);
} else {
v = m_combine_trids[m_combine_trids_num];
}
m_combine_trids_num++;
v[0] = a_x;
v[1] = a_y;
v[2] = a_z;
return v;
}
void _clear() {
tools_vforit(double*,m_combine_trids,it) delete [] *it;
m_combine_trids.clear();
m_combine_trids_num = 0;
}
protected:
class add_prm : public primitive_visitor {
protected:
virtual bool project(float&,float&,float&,float&) {return true;}
virtual bool add_point(float,float,float,float) {return false;}
virtual bool add_point(float,float,float,float,
float,float,float,float) {return false;}
virtual bool add_line(float,float,float,float,
float,float,float,float) {return false;}
virtual bool add_line(float,float,float,float,float,float,float,float,
float,float,float,float,float,float,float,float) {
return false;
}
virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float,
float a_p2x,float a_p2y,float a_p2z,float,
float a_p3x,float a_p3y,float a_p3z,float){
float vx = a_p2x-a_p1x;
float vy = a_p2y-a_p1y;
float vz = a_p2z-a_p1z;
float wx = a_p3x-a_p2x;
float wy = a_p3y-a_p2y;
float wz = a_p3z-a_p2z;
// vx wx
// vy ^ wy
// vz wz
float cx = vy*wz-vz*wy;
float cy = vz*wx-vx*wz;
float cz = vx*wy-vy*wx;
float len = (float)::sqrt(cx*cx + cy*cy + cz*cz);
if(!len) {
//m_out << "tools::sg::tessellate::add_prm : null normal."
// << std::endl;
} else {
cx /= len;
cy /= len;
cz /= len;
}
if(m_mode==gl::triangles()) {
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
} else if( (m_mode==gl::triangle_strip()) ||
(m_mode==gl::triangle_fan()) ){
if(m_norms.empty()) { //startup : three vertices.
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
} else { //one vertex :
m_norms.push_back(cx);
m_norms.push_back(cy);
m_norms.push_back(cz);
}
}
return true;
}
virtual bool add_triangle(float a_p1x,float a_p1y,float a_p1z,float a_p1w,
float,float,float,float,
float a_p2x,float a_p2y,float a_p2z,float a_p2w,
float,float,float,float,
float a_p3x,float a_p3y,float a_p3z,float a_p3w,
float,float,float,float){
return add_prm::add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
a_p2x,a_p2y,a_p2z,a_p2w,
a_p3x,a_p3y,a_p3z,a_p3w);
}
virtual bool project_normal(float& a_x,float& a_y,float& a_z) {
(void)a_x;(void)a_y;(void)a_z;
return true;
}
virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
float a_nx,float a_ny,float a_nz) {
(void)a_x;(void)a_y;(void)a_z;(void)a_w;
(void)a_nx;(void)a_ny;(void)a_nz;
return false;
}
virtual bool add_point_normal(float a_x,float a_y,float a_z,float a_w,
float a_nx,float a_ny,float a_nz,
float a_r,float a_g,float a_b,float a_a) {
(void)a_x;(void)a_y;(void)a_z;(void)a_w;
(void)a_nx;(void)a_ny;(void)a_nz;
(void)a_r;(void)a_g;(void)a_b;(void)a_a;
return false;
}
virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw,
float a_bnx,float a_bny,float a_bnz,
float a_ex,float a_ey,float a_ez,float a_ew,
float a_enx,float a_eny,float a_enz) {
(void)a_bx;(void)a_by;(void)a_bz;(void)a_bw;
(void)a_bnx;(void)a_bny;(void)a_bnz;
(void)a_ex;(void)a_ey;(void)a_ez;(void)a_ew;
(void)a_enx;(void)a_eny;(void)a_enz;
return false;
}
virtual bool add_line_normal(float a_bx,float a_by,float a_bz,float a_bw,
float a_bnx,float a_bny,float a_bnz,
float a_br,float a_bg,float a_bb,float a_ba,
float a_ex,float a_ey,float a_ez,float a_ew,
float a_enx,float a_eny,float a_enz,
float a_er,float a_eg,float a_eb,float a_ea){
(void)a_bx;(void)a_by;(void)a_bz;(void)a_bw;
(void)a_bnx;(void)a_bny;(void)a_bnz;
(void)a_br;(void)a_bg;(void)a_bb;(void)a_ba;
(void)a_ex;(void)a_ey;(void)a_ez;(void)a_ew;
(void)a_enx;(void)a_eny;(void)a_enz;
(void)a_er;(void)a_eg;(void)a_eb;(void)a_ea;
return false;
}
virtual bool add_triangle_normal(
float a_p1x,float a_p1y,float a_p1z,float a_p1w,
float a_n1x,float a_n1y,float a_n1z,
float a_p2x,float a_p2y,float a_p2z,float a_p2w,
float a_n2x,float a_n2y,float a_n2z,
float a_p3x,float a_p3y,float a_p3z,float a_p3w,
float a_n3x,float a_n3y,float a_n3z) {
add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
a_p2x,a_p2y,a_p2z,a_p2w,
a_p3x,a_p3y,a_p3z,a_p3w);
//m_this.m_triangles.add_normal(a_n1x,a_n1y,a_n1z);
//m_this.m_triangles.add_normal(a_n2x,a_n2y,a_n2z);
//m_this.m_triangles.add_normal(a_n3x,a_n3y,a_n3z);
(void)a_n1x;(void)a_n1y;(void)a_n1z;
(void)a_n2x;(void)a_n2y;(void)a_n2z;
(void)a_n3x;(void)a_n3y;(void)a_n3z;
return true;
}
virtual bool add_triangle_normal(
float a_p1x,float a_p1y,float a_p1z,float a_p1w,
float a_n1x,float a_n1y,float a_n1z,
float a_r1,float a_g1,float a_b1,float a_a1,
float a_p2x,float a_p2y,float a_p2z,float a_p2w,
float a_n2x,float a_n2y,float a_n2z,
float a_r2,float a_g2,float a_b2,float a_a2,
float a_p3x,float a_p3y,float a_p3z,float a_p3w,
float a_n3x,float a_n3y,float a_n3z,
float a_r3,float a_g3,float a_b3,float a_a3){
add_triangle(a_p1x,a_p1y,a_p1z,a_p1w,
a_r1,a_g1,a_b1,a_a1,
a_p2x,a_p2y,a_p2z,a_p2w,
a_r2,a_g2,a_b2,a_a2,
a_p3x,a_p3y,a_p3z,a_p3w,
a_r3,a_g3,a_b3,a_a3);
//m_this.m_triangles.add_normal(a_n1x,a_n1y,a_n1z);
//m_this.m_triangles.add_normal(a_n2x,a_n2y,a_n2z);
//m_this.m_triangles.add_normal(a_n3x,a_n3y,a_n3z);
(void)a_n1x;(void)a_n1y;(void)a_n1z;
(void)a_n2x;(void)a_n2y;(void)a_n2z;
(void)a_n3x;(void)a_n3y;(void)a_n3z;
return true;
}
public:
add_prm(std::ostream& a_out,std::vector<float>& a_norms)
:m_out(a_out)
,m_norms(a_norms)
{}
virtual ~add_prm(){}
public:
add_prm(const add_prm& a_from):primitive_visitor(a_from),m_out(a_from.m_out),m_norms(a_from.m_norms) {}
add_prm& operator=(const add_prm& a_from){
primitive_visitor::operator=(a_from);
return *this;
}
protected:
std::ostream& m_out;
public:
std::vector<float>& m_norms;
};
protected:
std::ostream& m_out;
GLUtesselator* m_tobj;
std::vector<float>* m_coords;
std::vector<double*> m_combine_trids;
size_t m_combine_trids_num;
prims_t* m_prims;
};
/*
class tessellate_factory {
#ifdef TOOLS_MEM
TOOLS_SCLASS(tools::sg::tessellate_factory);
#endif
public:
tessellate_factory(){
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
virtual ~tessellate_factory(){
#ifdef TOOLS_MEM
mem::decrement(s_class().c_str());
#endif
}
public:
tessellate_factory(const tessellate_factory& a_from) {
#ifdef TOOLS_MEM
mem::increment(s_class().c_str());
#endif
}
tessellate_factory& operator=(const tessellate_factory&){
return *this;
}
public:
virtual tessellate* create(std::ostream& a_out) {
return new tessellate(a_out);
}
};
*/
}}
#endif