533 lines
16 KiB
Plaintext
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
|
|
|