// 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 #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 m_coords; std::vector 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 #include //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 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;ipush_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(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(prim.m_coords); for(size_t ipt=0;iptsetError(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& 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& m_norms; }; protected: std::ostream& m_out; GLUtesselator* m_tobj; std::vector* m_coords; std::vector 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