Back to home page

EIC code displayed by LXR

 
 

    


Warning, /include/Geant4/toolx/sg/GL_manager is written in an unsupported language. File is not indexed.

0001 // Copyright (C) 2010, Guy Barrand. All rights reserved.
0002 // See the file tools.license for terms.
0003 
0004 #ifndef toolx_sg_GL_manager
0005 #define toolx_sg_GL_manager
0006 
0007 #include "gl"
0008 #include "../glbuf"
0009 
0010 #include <tools/sg/render_manager>
0011 #include <tools/mapmanip>
0012 #include <tools/carray>
0013 
0014 #include <cmath> //::sqrt
0015 
0016 #ifdef TOOLS_MEM
0017 #include <tools/mem>
0018 #endif
0019 
0020 namespace toolx {
0021 namespace sg {
0022 
0023 class GL_manager : public virtual tools::sg::render_manager {
0024   typedef tools::sg::render_manager parent;
0025 public:
0026   TOOLS_SCLASS(toolx::sg::GL_manager)
0027   virtual void* cast(const std::string& a_class) const {
0028     if(void* p = tools::cmp_cast<GL_manager>(this,a_class)) {return p;}
0029     else return 0;
0030   }
0031 public:
0032   virtual bool begin_render(int a_x,int a_y,unsigned int a_ww,unsigned int a_wh,
0033                             float a_r,float a_g,float a_b,float a_a,bool a_clear = true) {
0034     gl_clear_errors();
0035 
0036 #if TARGET_OS_IPHONE
0037 #elif defined(ANDROID)
0038 #elif _WIN32
0039 #elif __APPLE__ // Cocoa
0040     // to avoid a 0x506 error message :
0041 #ifdef TOOLX_HAS_GL_VBO
0042 #if GL_ARB_framebuffer_object
0043     if(::glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE) {
0044       //m_out << "toolx::sg::GL_manager::begin_render :"
0045       //      << " frame buffer not complete."
0046       //      << std::endl;
0047       return false;
0048     }
0049 #endif //GL_ARB_framebuffer_object
0050 #endif //TOOLX_HAS_GL_VBO
0051 #else
0052 #endif
0053 
0054     // WARNING : the values set here must match the default values in sg::state.
0055 
0056     // Antialiasing :
0057 #if TARGET_OS_IPHONE
0058 #elif defined(ANDROID)
0059     ::glEnable(GL_MULTISAMPLE);
0060 #elif _WIN32
0061 #elif __APPLE__
0062     ::glEnable(GL_MULTISAMPLE); //Cocoa
0063 #else
0064 #endif
0065 
0066     /* NOTE : not GL-ES :
0067     //   ::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
0068     // The upper is cruely lacking with povama solid+light.
0069     //   ::glEnable(GL_LINE_STIPPLE);
0070 
0071     ::glDisable(GL_POLYGON_SMOOTH);
0072     ::glAccum(GL_LOAD,1.0f);
0073     ::glAccum(GL_RETURN,1.0f);
0074     ::glReadBuffer(GL_FRONT);
0075 
0076     NOTE : GL_POLYGON_SMOOTH is here on Cocoa/AGL, Windows/WGL but it
0077            does nothing.
0078     */
0079 
0080 #if TARGET_OS_IPHONE
0081 // GL-ES
0082 #elif defined(ANDROID)
0083 // GL-ES
0084 #else
0085     ::glDisable(GL_POLYGON_STIPPLE); //CoinGL : reading a .wrl having Material::transparency may enable GL_POLYGON_STIPPLE.
0086 #endif
0087 
0088 /*
0089     ::printf("debug : is enabled %d\n",::glIsEnabled(GL_COLOR_MATERIAL));
0090    {GLfloat v[4];
0091     ::glGetMaterialfv(GL_FRONT,GL_AMBIENT,v);
0092     ::printf("debug : ambient : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
0093    {GLfloat v[4];
0094     ::glGetMaterialfv(GL_FRONT,GL_DIFFUSE,v);
0095     ::printf("debug : diffuse : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
0096    {GLfloat v[4];
0097     ::glGetMaterialfv(GL_FRONT,GL_SPECULAR,v);
0098     ::printf("debug : specular : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
0099    {GLfloat v[4];
0100     ::glGetMaterialfv(GL_FRONT,GL_EMISSION,v);
0101     ::printf("debug : emission : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
0102    {GLfloat shine;
0103     ::glGetMaterialfv(GL_FRONT,GL_SHININESS,&shine);
0104     ::printf("debug : shine : %g\n",shine);}
0105 debug : is enabled 0
0106 debug : ambient : 0.2 0.2 0.2 1
0107 debug : diffuse : 0.8 0.8 0.8 1
0108 debug : specular : 0 0 0 1
0109 debug : emission : 0 0 0 1
0110 debug : shine : 0
0111 */
0112 
0113     ::glEnable(GL_NORMALIZE);
0114     ::glShadeModel(GL_FLAT);
0115     //::glShadeModel(GL_SMOOTH);
0116     // GL-ES : ::glMaterialfv does not work. We then use :
0117     //         ::glEnable(GL_COLOR_MATERIAL) and ::glColor.
0118     //::glColorMaterial(GL_FRONT, GL_DIFFUSE);  //?
0119     ::glEnable(GL_COLOR_MATERIAL);
0120 
0121 /*
0122 debug : is enabled 1
0123 debug : ambient : 1 1 1 1
0124 debug : diffuse : 1 1 1 1
0125 debug : specular : 0 0 0 1
0126 debug : emission : 0 0 0 1
0127 debug : shine : 0
0128 */
0129 
0130     // to handle transparency (same as SoGLRenderAction::SCREEN_DOOR ?) :
0131     //::glEnable(GL_BLEND);
0132     // NOTE : with Cocoa+AppleGL on macOS-10.14 (Mojave), it appears that points are blended ! (Even if alpha color is 1).
0133     //        Seen with some simulated catalog of galaxies done for LSST/DC2.
0134     //        To master this, we disable GL_BLEND by default. Then people wanting some transparency have to
0135     //        use the tools::sg::blend node in their scene graph.
0136     ::glDisable(GL_BLEND); //must be in sync with tools::sg::state.m_GL_BLEND and sg::blend node default.
0137     ::glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
0138 
0139     //WARNING : the below glEnable/glDisable corresponds
0140     //          to defaults in tools::sg::state.
0141     ::glEnable(GL_DEPTH_TEST);
0142     ::glDisable(GL_LIGHTING);
0143     ::glFrontFace(GL_CCW);
0144     ::glEnable(GL_CULL_FACE);
0145     ::glDisable(GL_POLYGON_OFFSET_FILL);
0146     ::glDisable(GL_TEXTURE_2D);
0147 
0148     ::glDisable(GL_POINT_SMOOTH);
0149     ::glPointSize(1);
0150     ::glDisable(GL_LINE_SMOOTH); //NOTE : it does not work on all platforms !
0151     ::glLineWidth(1);
0152 
0153     ::glViewport(a_x,a_y,a_ww,a_wh);
0154 
0155    // NOTE : iOS : glScissor logic does not work properly with Apple multisampling.
0156    //        But it appears that it is not needed for VR split views.
0157    //        Here a combination glViewport+[correct camera lrbt] does the clipping job (???).
0158    //        (But the clear color should be the same for both views).
0159    //::glEnable(GL_SCISSOR_TEST);
0160    //::glScissor(a_x,a_y,a_ww,a_wh);
0161 
0162     //NOTE : a=0 coworks with the below logic to handle transparent background.
0163     if(a_clear) {
0164       ::glClearColor(a_r,a_g,a_b,0);
0165       ::glClear(GL_COLOR_BUFFER_BIT);
0166       ::glClear(GL_DEPTH_BUFFER_BIT);
0167     }
0168 
0169     //WARNING : Android, iPhone : only one glPushMatrix ok !
0170     ::glMatrixMode(GL_PROJECTION);
0171     ::glLoadIdentity();
0172 
0173     //WARNING : we take the convention that the current mode is MODELVIEW
0174     ::glMatrixMode(GL_MODELVIEW);
0175     ::glLoadIdentity();
0176 
0177     //m_clear_color.set_a(0.2);
0178 
0179     // to handle a transparent background :
0180     //NOTE : not tested on Android and iOS.
0181     // dst color :
0182     //    cr * alpha + cr * (1-alpha) = cr
0183     //    cg * alpha + cg * (1-alpha) = cg
0184     //    cb * alpha + cb * (1-alpha) = cb
0185     //    alpha*alpha + 0 * (1-alpha) = ca => alpha = sqrt(ca)
0186 
0187    {::glColor4f(a_r,a_g,a_b,::sqrt(a_a));
0188     float xyzs[12];
0189     xyzs[0] = -1;xyzs[ 1] = -1;xyzs[ 2] = 0;
0190     xyzs[3] =  1;xyzs[ 4] = -1;xyzs[ 5] = 0;
0191     xyzs[6] =  1;xyzs[ 7] =  1;xyzs[ 8] = 0;
0192     xyzs[9] = -1;xyzs[10] =  1;xyzs[11] = 0;
0193     ::glDisable(GL_DEPTH_TEST);
0194     ::glEnableClientState(GL_VERTEX_ARRAY);
0195     ::glVertexPointer(3,GL_FLOAT,0,xyzs);
0196     ::glDrawArrays(GL_TRIANGLE_FAN,0,4);
0197     ::glDisableClientState(GL_VERTEX_ARRAY);
0198     ::glEnable(GL_DEPTH_TEST);}
0199 
0200     return true;
0201   }
0202 
0203   virtual void end_render() {
0204     ::glFinish();
0205     gl_dump_if_errors(m_out,"toolx::sg::GL_manager::end_render :");
0206   }
0207 
0208   ////////////////////////////////////////////////
0209   /// texture : //////////////////////////////////
0210   ////////////////////////////////////////////////
0211   virtual unsigned int create_texture(const tools::img_byte& a_img,bool a_NEAREST) {
0212 
0213     unsigned int gl_id;
0214     ::glGenTextures(1,&gl_id);
0215     if(!gl_id) return 0;
0216 
0217 #ifdef TOOLS_MEM
0218     tools::mem::increment(tools::s_tex().c_str());
0219 #endif
0220     unsigned int gsto_size = a_img.size();
0221     ::glBindTexture(GL_TEXTURE_2D,gl_id);
0222     bool status = true;
0223    {int sz;
0224     ::glGetIntegerv(GL_MAX_TEXTURE_SIZE,&sz);
0225   // MacBookPro : it returns 8192.
0226   // Android : it returns 2048.
0227   // iPad1 : it returns 2048.
0228   // iPod : it returns ?
0229   //::printf("debug : GL_MAX_TEXTURE_SIZE : %d\n",sz);
0230     tools::img_byte res;
0231     if(!sz) {
0232       m_out << "toolx::sg::gl::tex_img : warning : GL_MAX_TEXTURE_SIZE is zero." << std::endl;
0233       status = gl_tex_img(m_out,a_img);
0234     } else {
0235     if(a_img.check_gl_limit(sz,res)) {
0236       if(res.is_empty()) { //a_img does not exceed.
0237         status = gl_tex_img(m_out,a_img);
0238       } else {
0239         m_out << "toolx::sg::gl::tex_img : warning : img size > GL_MAX_TEXTURE_SIZE (" << sz << ")." << std::endl;
0240         status = gl_tex_img(m_out,res);
0241         gsto_size = res.size();
0242       }
0243     } else {
0244       m_out << "toolx::sg::gl::tex_img :"
0245             << " warning : img size > GL_MAX_TEXTURE_SIZE (" << sz << ") but can't reduce."
0246             << std::endl;
0247       status = false;
0248     }}}
0249 
0250     if(a_NEAREST) {
0251       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //good to see astro images pixels.
0252       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //idem.
0253     } else {
0254       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
0255       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
0256     }
0257     ::glBindTexture(GL_TEXTURE_2D,0);
0258 
0259     if(!status) {
0260       gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_texture (1) :");
0261       ::glDeleteTextures(1,&gl_id);
0262 #ifdef TOOLS_MEM
0263       tools::mem::decrement(tools::s_tex().c_str());
0264 #endif
0265       gl_id = 0;
0266       gl_clear_errors();
0267       return 0;
0268     }
0269 
0270     if(gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_texture (2) :")) {
0271       ::glDeleteTextures(1,&gl_id);
0272 #ifdef TOOLS_MEM
0273       tools::mem::decrement(tools::s_tex().c_str());
0274 #endif
0275       gl_id = 0;
0276       gl_clear_errors();
0277       return 0;
0278     }
0279 
0280     unsigned int _id = m_gen_id;m_gen_id++;
0281     m_gstos[_id] = new gsto_t(gsto_t::kind_texture,gl_id,gsto_size,0);
0282     return _id;
0283   }
0284 
0285   ////////////////////////////////////////////////
0286   /// VBO ////////////////////////////////////////
0287   ////////////////////////////////////////////////
0288   virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
0289     if(!a_floatn) return 0;
0290     switch(m_gsto_mode) {
0291     case tools::sg::gsto_gl_vbo:{
0292 #ifdef TOOLX_HAS_GL_VBO
0293       unsigned int gl_id = 0;
0294       ::glGenBuffers(1,&gl_id);
0295       if(!gl_id) {
0296         if(!m_warned) {
0297           m_warned = true;
0298           m_out << "toolx::sg::GL_manager::create_gsto_from_data : glGenBuffers failed ()." << std::endl;
0299         }
0300         return 0;
0301       }
0302 #ifdef TOOLS_MEM
0303       tools::mem::increment(tools::s_gsto().c_str());
0304 #endif
0305 
0306       ::glBindBuffer(GL_ARRAY_BUFFER,gl_id);
0307       ::glBufferData(GL_ARRAY_BUFFER,
0308                      a_floatn*sizeof(float),a_data,
0309                      GL_STATIC_DRAW);
0310       ::glBindBuffer(GL_ARRAY_BUFFER,0);
0311 
0312       if(gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_gsto_from_data :")) {
0313         ::glDeleteBuffers(1,&gl_id);
0314 #ifdef TOOLS_MEM
0315         tools::mem::decrement(tools::s_gsto().c_str());
0316 #endif
0317         gl_id = 0;
0318         gl_clear_errors();
0319         return 0;
0320       }
0321 
0322       unsigned int _id = m_gen_id;m_gen_id++;
0323       m_gstos[_id] = new gsto_t(gsto_t::kind_buffer,gl_id,a_floatn*sizeof(float),0);
0324       return _id;
0325 #else //!TOOLX_HAS_GL_VBO
0326       m_out << "toolx::sg::GL_manager::create_gsto_from_data :"
0327             << " gsto mode is gl_vbo but class not compiled with TOOLX_HAS_GL_VBO."
0328             << std::endl;
0329       return 0;
0330 #endif //TOOLX_HAS_GL_VBO
0331       }break;
0332     case tools::sg::gsto_gl_list:{
0333       unsigned int gl_id = 0;
0334       unsigned int _id = m_gen_id;m_gen_id++;
0335       m_gstos[_id] = new gsto_t(gsto_t::kind_list,gl_id,a_floatn*sizeof(float),a_data);
0336       return _id;
0337       }break;
0338     case tools::sg::gsto_memory:{
0339       unsigned int gl_id = 0;
0340       unsigned int _id = m_gen_id;m_gen_id++;
0341       m_gstos[_id] = new gsto_t(gsto_t::kind_memory,gl_id,a_floatn*sizeof(float),a_data);
0342       return _id;
0343       }break;
0344     }
0345     return 0;
0346   }
0347 
0348   virtual bool is_gsto_id_valid(unsigned int a_id) const {
0349     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
0350     if(it==m_gstos.end()) return false;
0351     return (*it).second->is_valid();
0352   }
0353 
0354   virtual void delete_gsto(unsigned int a_id){
0355     tools::delete_key<unsigned int,gsto_t>(m_gstos,a_id);
0356   }
0357 
0358   ////////////////////////////////////////////////////////
0359   ////////////////////////////////////////////////////////
0360   ////////////////////////////////////////////////////////
0361 
0362   float* gsto_data(unsigned int a_id) const {
0363     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
0364     if(it==m_gstos.end()) return 0;
0365     return (*it).second->m_data;
0366   }
0367 
0368   unsigned int gsto_gl_list_id(unsigned int a_id,bool& a_created) const {
0369     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
0370     if(it==m_gstos.end()) {a_created = false;return 0;}
0371     if((*it).second->m_kind!=gsto_t::kind_list) {a_created = false;return 0;}
0372     if((*it).second->m_gl_id) {
0373       a_created = false;
0374       return (*it).second->m_gl_id;
0375     } else {
0376 #ifdef TOOLX_HAS_GL_LIST
0377       unsigned int _id = ::glGenLists(1);
0378       if(!_id) {a_created = false;return 0;}
0379 #ifdef TOOLS_MEM
0380       tools::mem::increment(tools::s_gsto().c_str());
0381 #endif
0382       a_created = true;
0383       (*it).second->m_gl_id = _id;
0384       return _id;
0385 #else
0386       a_created = false;
0387       return 0;
0388 #endif
0389     }
0390   }
0391 
0392   ////////////////////////////////////////////////////////
0393   ////////////////////////////////////////////////////////
0394   ////////////////////////////////////////////////////////
0395   virtual tools::sg::gsto_mode get_gsto_mode() const {return m_gsto_mode;}
0396 
0397   virtual void set_gsto_mode(tools::sg::gsto_mode a_v) {
0398     if(a_v==m_gsto_mode) return;
0399     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
0400     switch(a_v) {
0401     case tools::sg::gsto_gl_vbo:{
0402 #ifdef TOOLX_HAS_GL_VBO
0403       m_gsto_mode = a_v;
0404 #else
0405       m_gsto_mode = tools::sg::gsto_memory;
0406 #endif
0407       }break;
0408     case tools::sg::gsto_gl_list:{
0409 #ifdef TOOLX_HAS_GL_LIST
0410       m_gsto_mode = a_v;
0411 #else
0412       m_gsto_mode = tools::sg::gsto_memory;
0413 #endif
0414       }break;
0415     case tools::sg::gsto_memory:{
0416       m_gsto_mode = tools::sg::gsto_memory;
0417       }break;
0418     }
0419   }
0420 
0421   virtual void available_gsto_modes(std::vector<std::string>& a_vs) {
0422     a_vs.clear();
0423 #ifdef TOOLX_HAS_GL_VBO
0424     a_vs.push_back(tools::sg::s_gsto_gl_vbo());
0425 #endif
0426 #ifdef TOOLX_HAS_GL_LIST
0427     a_vs.push_back(tools::sg::s_gsto_gl_list());
0428 #endif
0429     a_vs.push_back(tools::sg::s_gsto_memory());
0430   }
0431 
0432   virtual void available_not_memory_gsto_mode(std::string& a_v) const {
0433     a_v.clear();
0434 #ifdef TOOLX_HAS_GL_VBO
0435     a_v = tools::sg::s_gsto_gl_vbo();
0436 #endif
0437 #ifdef TOOLX_HAS_GL_LIST
0438     if(a_v.empty()) a_v = tools::sg::s_gsto_gl_list();
0439 #endif
0440   }
0441 
0442   virtual size_t used_texture_memory() const {
0443     size_t sz = 0;
0444     std::map<unsigned int,gsto_t*>::const_iterator it;
0445     for(it=m_gstos.begin();it!=m_gstos.end();++it) {
0446       if((*it).second->m_kind==gsto_t::kind_texture) sz += (*it).second->m_size;
0447     }
0448     return sz;
0449   }
0450 
0451   virtual size_t gstos_size() const {
0452     size_t sz = 0;
0453     std::map<unsigned int,gsto_t*>::const_iterator it;
0454     for(it=m_gstos.begin();it!=m_gstos.end();++it) sz += (*it).second->m_size;
0455     return sz;
0456   }
0457 
0458 public:
0459   GL_manager(std::ostream& a_out)
0460   :m_out(a_out)
0461   ,m_gen_id(1)
0462 #ifdef TOOLX_HAS_GL_VBO
0463   ,m_gsto_mode(tools::sg::gsto_gl_vbo) //priority to GL VBOs.
0464 #elif TOOLX_HAS_GL_LIST
0465   ,m_gsto_mode(tools::sg::gsto_gl_list)
0466 #else
0467   ,m_gsto_mode(tools::sg::gsto_memory)
0468 #endif
0469   ,m_warned(false)
0470   {}
0471   virtual ~GL_manager(){
0472     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
0473   }
0474 public:
0475   GL_manager(const GL_manager& a_from)
0476   :parent(a_from)
0477   ,m_out(a_from.m_out)
0478   ,m_gen_id(a_from.m_gen_id)
0479   ,m_gsto_mode(a_from.m_gsto_mode)
0480   ,m_warned(false)
0481   {}
0482   GL_manager& operator=(const GL_manager& a_from){
0483     if(&a_from==this) return *this;
0484     m_gen_id = a_from.m_gen_id;
0485     m_gsto_mode = a_from.m_gsto_mode;
0486     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
0487     m_warned = false;
0488     return *this;
0489   }
0490 
0491 public:
0492   void bind_gsto(unsigned int a_id) {
0493     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
0494     if(it==m_gstos.end()) return;
0495     (*it).second->bind();
0496   }
0497 
0498   void delete_gstos() {
0499     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
0500   }
0501 
0502 public:
0503 
0504   static unsigned char* get_rgbas(unsigned int a_w,unsigned int a_h) {
0505     //WARNING : it does OpenGL. Under Android it should be executed
0506     //          in the OpenGL thread.
0507     //NOTE : Android, iOS : RGB produces a black image.
0508     unsigned char* rgbas = new unsigned char[4 * a_w * a_h];
0509     if(!rgbas) return 0;
0510     ::glPixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
0511     ::glReadPixels(0,0,a_w,a_h,GL_RGBA,GL_UNSIGNED_BYTE,rgbas);
0512  /*{size_t number = 4 * a_w * a_h;
0513     size_t count_not_255 = 0;
0514     for(size_t item=3;item<number;item+=4) {
0515       unsigned char a = rgbas[item];
0516       if(a!=255) {
0517         ::printf("%lu : %d\n",item,a);
0518         count_not_255++;
0519         rgbas[item] = 255;
0520       }
0521     }
0522     ::printf("not_255 : %lu\n",count_not_255);}*/
0523     return rgbas;
0524   }
0525 
0526 #if defined(TARGET_OS_IPHONE) || defined(ANDROID)
0527   static unsigned char* get_rgbs(unsigned int a_w,unsigned int a_h) {
0528     unsigned char* rgbas = get_rgbas(a_w,a_h);
0529     if(!rgbas) return 0;
0530     unsigned char* rgbs = tools::_4s_to_3s<unsigned char,unsigned int>(rgbas,a_w,a_h);
0531     delete [] rgbas;
0532     return rgbs;
0533   }
0534 #else
0535   static unsigned char* get_rgbs(unsigned int a_w,unsigned int a_h) {
0536     //WARNING : it does OpenGL. Under Android it should be executed
0537     //          in the OpenGL thread.
0538     //NOTE : Android, iOS : RGB produces a black image.
0539     unsigned char* rgbs = new unsigned char[3 * a_w * a_h];
0540     if(!rgbs) return 0;
0541     ::glPixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
0542     ::glReadPixels(0,0,a_w,a_h,GL_RGB,GL_UNSIGNED_BYTE,rgbs);
0543     return rgbs;
0544   }
0545 #endif
0546 
0547 protected:
0548   std::ostream& m_out;
0549 
0550   class gsto_t {
0551     TOOLS_SCLASS(GL_manager::gsto_t)
0552   public:
0553     enum kind {
0554       kind_texture,
0555       kind_buffer,
0556       kind_list,
0557       kind_memory
0558     };
0559   public:
0560     gsto_t(kind a_kind,int a_gl_id,size_t a_size,const float* a_data)
0561     :m_gl_id(a_gl_id)
0562     ,m_kind(a_kind)
0563     ,m_size(a_size)
0564     ,m_data(0)
0565     {
0566 #ifdef TOOLS_MEM
0567       tools::mem::increment(s_class().c_str());
0568 #endif
0569       if(a_data) {
0570         size_t num = m_size/sizeof(float);
0571         m_data = new float[num];
0572 #ifdef TOOLS_MEM
0573         tools::mem::increment(tools::s_new().c_str());
0574 #endif
0575         ::memcpy(m_data,a_data,m_size);
0576       }
0577     }
0578     virtual ~gsto_t() {
0579       if(m_kind==kind_texture) {
0580         ::glDeleteTextures(1,&m_gl_id);
0581 #ifdef TOOLS_MEM
0582         tools::mem::decrement(tools::s_tex().c_str());
0583 #endif
0584       } else if(m_kind==kind_buffer) {
0585 #ifdef TOOLX_HAS_GL_VBO
0586         ::glDeleteBuffers(1,&m_gl_id);
0587 #ifdef TOOLS_MEM
0588         tools::mem::decrement(tools::s_gsto().c_str());
0589 #endif
0590 #endif
0591       } else if(m_kind==kind_list) {
0592         if(m_gl_id) {
0593 #ifdef TOOLX_HAS_GL_LIST
0594           ::glDeleteLists(m_gl_id,1);
0595 #ifdef TOOLS_MEM
0596           tools::mem::decrement(tools::s_gsto().c_str());
0597 #endif
0598 #endif
0599         }
0600       }
0601 
0602       if(m_data) {
0603         delete [] m_data;
0604 #ifdef TOOLS_MEM
0605         tools::mem::decrement(tools::s_new().c_str());
0606 #endif
0607       }
0608 #ifdef TOOLS_MEM
0609       tools::mem::decrement(s_class().c_str());
0610 #endif
0611     }
0612   private:
0613     gsto_t(const gsto_t& a_from)
0614     :m_gl_id(a_from.m_gl_id)
0615     ,m_kind(a_from.m_kind)
0616     ,m_size(a_from.m_size)
0617     ,m_data(0)
0618     {
0619 #ifdef TOOLS_MEM
0620       tools::mem::increment(s_class().c_str());
0621 #endif
0622       if(a_from.m_data) {
0623         size_t num = m_size/sizeof(float);
0624         m_data = new float[num];
0625 #ifdef TOOLS_MEM
0626         tools::mem::increment(tools::s_new().c_str());
0627 #endif
0628         ::memcpy(m_data,a_from.m_data,m_size);
0629       }
0630     }
0631     gsto_t& operator=(const gsto_t& a_from){
0632       if(&a_from==this) return *this;
0633       m_gl_id = a_from.m_gl_id;
0634       m_kind = a_from.m_kind;
0635       m_size = a_from.m_size;
0636       if(m_data) {
0637         delete [] m_data;
0638 #ifdef TOOLS_MEM
0639         tools::mem::decrement(tools::s_new().c_str());
0640 #endif
0641         m_data = 0;
0642       }
0643       if(a_from.m_data) {
0644         size_t num = m_size/sizeof(float);
0645         m_data = new float[num];
0646 #ifdef TOOLS_MEM
0647         tools::mem::increment(tools::s_new().c_str());
0648 #endif
0649         ::memcpy(m_data,a_from.m_data,m_size);
0650       }
0651       return *this;
0652     }
0653   public:
0654     bool is_valid() const {
0655       if(m_kind==kind_texture) {
0656         return (::glIsTexture(m_gl_id)==GL_TRUE?true:false);
0657       } else if(m_kind==kind_buffer) {
0658 #ifdef TOOLX_HAS_GL_VBO
0659         return (::glIsBuffer(m_gl_id)==GL_TRUE?true:false);
0660 #endif
0661       } else if(m_kind==kind_list) {
0662 #ifdef TOOLX_HAS_GL_LIST
0663         return (::glIsList(m_gl_id)==GL_TRUE?true:false);
0664 #endif
0665       } else if(m_kind==kind_memory) {
0666         return true;
0667       }
0668       return false;
0669     }
0670     void bind() const {
0671       if(m_kind==kind_texture) {
0672         ::glBindTexture(GL_TEXTURE_2D,m_gl_id);
0673       } else if(m_kind==kind_buffer) {
0674 #ifdef TOOLX_HAS_GL_VBO
0675         ::glBindBuffer(GL_ARRAY_BUFFER,m_gl_id);
0676 #endif
0677       }
0678     }
0679   public:
0680     unsigned int m_gl_id;
0681     kind m_kind;
0682     size_t m_size;
0683     float* m_data;
0684   };
0685 
0686   std::map<unsigned int,gsto_t*> m_gstos;
0687 
0688   unsigned int m_gen_id;
0689   tools::sg::gsto_mode m_gsto_mode;
0690   bool m_warned;
0691 };
0692 
0693 }}
0694 
0695 #endif