Geant4 Cross Reference

Cross-Referencing   Geant4
Geant4/externals/g4tools/include/toolx/sg/GL_manager

Version: [ ReleaseNotes ] [ 1.0 ] [ 1.1 ] [ 2.0 ] [ 3.0 ] [ 3.1 ] [ 3.2 ] [ 4.0 ] [ 4.0.p1 ] [ 4.0.p2 ] [ 4.1 ] [ 4.1.p1 ] [ 5.0 ] [ 5.0.p1 ] [ 5.1 ] [ 5.1.p1 ] [ 5.2 ] [ 5.2.p1 ] [ 5.2.p2 ] [ 6.0 ] [ 6.0.p1 ] [ 6.1 ] [ 6.2 ] [ 6.2.p1 ] [ 6.2.p2 ] [ 7.0 ] [ 7.0.p1 ] [ 7.1 ] [ 7.1.p1 ] [ 8.0 ] [ 8.0.p1 ] [ 8.1 ] [ 8.1.p1 ] [ 8.1.p2 ] [ 8.2 ] [ 8.2.p1 ] [ 8.3 ] [ 8.3.p1 ] [ 8.3.p2 ] [ 9.0 ] [ 9.0.p1 ] [ 9.0.p2 ] [ 9.1 ] [ 9.1.p1 ] [ 9.1.p2 ] [ 9.1.p3 ] [ 9.2 ] [ 9.2.p1 ] [ 9.2.p2 ] [ 9.2.p3 ] [ 9.2.p4 ] [ 9.3 ] [ 9.3.p1 ] [ 9.3.p2 ] [ 9.4 ] [ 9.4.p1 ] [ 9.4.p2 ] [ 9.4.p3 ] [ 9.4.p4 ] [ 9.5 ] [ 9.5.p1 ] [ 9.5.p2 ] [ 9.6 ] [ 9.6.p1 ] [ 9.6.p2 ] [ 9.6.p3 ] [ 9.6.p4 ] [ 10.0 ] [ 10.0.p1 ] [ 10.0.p2 ] [ 10.0.p3 ] [ 10.0.p4 ] [ 10.1 ] [ 10.1.p1 ] [ 10.1.p2 ] [ 10.1.p3 ] [ 10.2 ] [ 10.2.p1 ] [ 10.2.p2 ] [ 10.2.p3 ] [ 10.3 ] [ 10.3.p1 ] [ 10.3.p2 ] [ 10.3.p3 ] [ 10.4 ] [ 10.4.p1 ] [ 10.4.p2 ] [ 10.4.p3 ] [ 10.5 ] [ 10.5.p1 ] [ 10.6 ] [ 10.6.p1 ] [ 10.6.p2 ] [ 10.6.p3 ] [ 10.7 ] [ 10.7.p1 ] [ 10.7.p2 ] [ 10.7.p3 ] [ 10.7.p4 ] [ 11.0 ] [ 11.0.p1 ] [ 11.0.p2 ] [ 11.0.p3, ] [ 11.0.p4 ] [ 11.1 ] [ 11.1.1 ] [ 11.1.2 ] [ 11.1.3 ] [ 11.2 ] [ 11.2.1 ] [ 11.2.2 ] [ 11.3.0 ]

  1 // Copyright (C) 2010, Guy Barrand. All rights reserved.
  2 // See the file tools.license for terms.
  3 
  4 #ifndef toolx_sg_GL_manager
  5 #define toolx_sg_GL_manager
  6 
  7 #include "gl"
  8 #include "../glbuf"
  9 
 10 #include <tools/sg/render_manager>
 11 #include <tools/mapmanip>
 12 #include <tools/carray>
 13 
 14 #include <cmath> //::sqrt
 15 
 16 #ifdef TOOLS_MEM
 17 #include <tools/mem>
 18 #endif
 19 
 20 namespace toolx {
 21 namespace sg {
 22 
 23 class GL_manager : public virtual tools::sg::render_manager {
 24   typedef tools::sg::render_manager parent;
 25 public:
 26   TOOLS_SCLASS(toolx::sg::GL_manager)
 27   virtual void* cast(const std::string& a_class) const {
 28     if(void* p = tools::cmp_cast<GL_manager>(this,a_class)) {return p;}
 29     else return 0;
 30   }
 31 public:
 32   virtual bool begin_render(int a_x,int a_y,unsigned int a_ww,unsigned int a_wh,
 33                             float a_r,float a_g,float a_b,float a_a,bool a_clear = true) {
 34     gl_clear_errors();
 35 
 36 #if TARGET_OS_IPHONE
 37 #elif defined(ANDROID)
 38 #elif _WIN32
 39 #elif __APPLE__ // Cocoa
 40     // to avoid a 0x506 error message :
 41 #ifdef TOOLX_HAS_GL_VBO
 42 #if GL_ARB_framebuffer_object
 43     if(::glCheckFramebufferStatus(GL_FRAMEBUFFER)!=GL_FRAMEBUFFER_COMPLETE) {
 44       //m_out << "toolx::sg::GL_manager::begin_render :"
 45       //      << " frame buffer not complete."
 46       //      << std::endl;
 47       return false;
 48     }
 49 #endif //GL_ARB_framebuffer_object
 50 #endif //TOOLX_HAS_GL_VBO
 51 #else
 52 #endif
 53 
 54     // WARNING : the values set here must match the default values in sg::state.
 55 
 56     // Antialiasing :
 57 #if TARGET_OS_IPHONE
 58 #elif defined(ANDROID)
 59     ::glEnable(GL_MULTISAMPLE);
 60 #elif _WIN32
 61 #elif __APPLE__
 62     ::glEnable(GL_MULTISAMPLE); //Cocoa
 63 #else
 64 #endif
 65 
 66     /* NOTE : not GL-ES :
 67     //   ::glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
 68     // The upper is cruely lacking with povama solid+light.
 69     //   ::glEnable(GL_LINE_STIPPLE);
 70 
 71     ::glDisable(GL_POLYGON_SMOOTH);
 72     ::glAccum(GL_LOAD,1.0f);
 73     ::glAccum(GL_RETURN,1.0f);
 74     ::glReadBuffer(GL_FRONT);
 75 
 76     NOTE : GL_POLYGON_SMOOTH is here on Cocoa/AGL, Windows/WGL but it
 77            does nothing.
 78     */
 79 
 80 #if TARGET_OS_IPHONE
 81 // GL-ES
 82 #elif defined(ANDROID)
 83 // GL-ES
 84 #else
 85     ::glDisable(GL_POLYGON_STIPPLE); //CoinGL : reading a .wrl having Material::transparency may enable GL_POLYGON_STIPPLE.
 86 #endif
 87 
 88 /*
 89     ::printf("debug : is enabled %d\n",::glIsEnabled(GL_COLOR_MATERIAL));
 90    {GLfloat v[4];
 91     ::glGetMaterialfv(GL_FRONT,GL_AMBIENT,v);
 92     ::printf("debug : ambient : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
 93    {GLfloat v[4];
 94     ::glGetMaterialfv(GL_FRONT,GL_DIFFUSE,v);
 95     ::printf("debug : diffuse : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
 96    {GLfloat v[4];
 97     ::glGetMaterialfv(GL_FRONT,GL_SPECULAR,v);
 98     ::printf("debug : specular : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
 99    {GLfloat v[4];
100     ::glGetMaterialfv(GL_FRONT,GL_EMISSION,v);
101     ::printf("debug : emission : %g %g %g %g\n",v[0],v[1],v[2],v[3]);}
102    {GLfloat shine;
103     ::glGetMaterialfv(GL_FRONT,GL_SHININESS,&shine);
104     ::printf("debug : shine : %g\n",shine);}
105 debug : is enabled 0
106 debug : ambient : 0.2 0.2 0.2 1
107 debug : diffuse : 0.8 0.8 0.8 1
108 debug : specular : 0 0 0 1
109 debug : emission : 0 0 0 1
110 debug : shine : 0
111 */
112 
113     ::glEnable(GL_NORMALIZE);
114     ::glShadeModel(GL_FLAT);
115     //::glShadeModel(GL_SMOOTH);
116     // GL-ES : ::glMaterialfv does not work. We then use :
117     //         ::glEnable(GL_COLOR_MATERIAL) and ::glColor.
118     //::glColorMaterial(GL_FRONT, GL_DIFFUSE);  //?
119     ::glEnable(GL_COLOR_MATERIAL);
120 
121 /*
122 debug : is enabled 1
123 debug : ambient : 1 1 1 1
124 debug : diffuse : 1 1 1 1
125 debug : specular : 0 0 0 1
126 debug : emission : 0 0 0 1
127 debug : shine : 0
128 */
129 
130     // to handle transparency (same as SoGLRenderAction::SCREEN_DOOR ?) :
131     //::glEnable(GL_BLEND);
132     // NOTE : with Cocoa+AppleGL on macOS-10.14 (Mojave), it appears that points are blended ! (Even if alpha color is 1).
133     //        Seen with some simulated catalog of galaxies done for LSST/DC2.
134     //        To master this, we disable GL_BLEND by default. Then people wanting some transparency have to
135     //        use the tools::sg::blend node in their scene graph.
136     ::glDisable(GL_BLEND); //must be in sync with tools::sg::state.m_GL_BLEND and sg::blend node default.
137     ::glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
138 
139     //WARNING : the below glEnable/glDisable corresponds
140     //          to defaults in tools::sg::state.
141     ::glEnable(GL_DEPTH_TEST);
142     ::glDisable(GL_LIGHTING);
143     ::glFrontFace(GL_CCW);
144     ::glEnable(GL_CULL_FACE);
145     ::glDisable(GL_POLYGON_OFFSET_FILL);
146     ::glDisable(GL_TEXTURE_2D);
147 
148     ::glDisable(GL_POINT_SMOOTH);
149     ::glPointSize(1);
150     ::glDisable(GL_LINE_SMOOTH); //NOTE : it does not work on all platforms !
151     ::glLineWidth(1);
152 
153     ::glViewport(a_x,a_y,a_ww,a_wh);
154 
155    // NOTE : iOS : glScissor logic does not work properly with Apple multisampling.
156    //        But it appears that it is not needed for VR split views.
157    //        Here a combination glViewport+[correct camera lrbt] does the clipping job (???).
158    //        (But the clear color should be the same for both views).
159    //::glEnable(GL_SCISSOR_TEST);
160    //::glScissor(a_x,a_y,a_ww,a_wh);
161 
162     //NOTE : a=0 coworks with the below logic to handle transparent background.
163     if(a_clear) {
164       ::glClearColor(a_r,a_g,a_b,0);
165       ::glClear(GL_COLOR_BUFFER_BIT);
166       ::glClear(GL_DEPTH_BUFFER_BIT);
167     }
168 
169     //WARNING : Android, iPhone : only one glPushMatrix ok !
170     ::glMatrixMode(GL_PROJECTION);
171     ::glLoadIdentity();
172 
173     //WARNING : we take the convention that the current mode is MODELVIEW
174     ::glMatrixMode(GL_MODELVIEW);
175     ::glLoadIdentity();
176 
177     //m_clear_color.set_a(0.2);
178 
179     // to handle a transparent background :
180     //NOTE : not tested on Android and iOS.
181     // dst color :
182     //    cr * alpha + cr * (1-alpha) = cr
183     //    cg * alpha + cg * (1-alpha) = cg
184     //    cb * alpha + cb * (1-alpha) = cb
185     //    alpha*alpha + 0 * (1-alpha) = ca => alpha = sqrt(ca)
186 
187    {::glColor4f(a_r,a_g,a_b,::sqrt(a_a));
188     float xyzs[12];
189     xyzs[0] = -1;xyzs[ 1] = -1;xyzs[ 2] = 0;
190     xyzs[3] =  1;xyzs[ 4] = -1;xyzs[ 5] = 0;
191     xyzs[6] =  1;xyzs[ 7] =  1;xyzs[ 8] = 0;
192     xyzs[9] = -1;xyzs[10] =  1;xyzs[11] = 0;
193     ::glDisable(GL_DEPTH_TEST);
194     ::glEnableClientState(GL_VERTEX_ARRAY);
195     ::glVertexPointer(3,GL_FLOAT,0,xyzs);
196     ::glDrawArrays(GL_TRIANGLE_FAN,0,4);
197     ::glDisableClientState(GL_VERTEX_ARRAY);
198     ::glEnable(GL_DEPTH_TEST);}
199 
200     return true;
201   }
202 
203   virtual void end_render() {
204     ::glFinish();
205     gl_dump_if_errors(m_out,"toolx::sg::GL_manager::end_render :");
206   }
207 
208   ////////////////////////////////////////////////
209   /// texture : //////////////////////////////////
210   ////////////////////////////////////////////////
211   virtual unsigned int create_texture(const tools::img_byte& a_img,bool a_NEAREST) {
212 
213     unsigned int gl_id;
214     ::glGenTextures(1,&gl_id);
215     if(!gl_id) return 0;
216 
217 #ifdef TOOLS_MEM
218     tools::mem::increment(tools::s_tex().c_str());
219 #endif
220     unsigned int gsto_size = a_img.size();
221     ::glBindTexture(GL_TEXTURE_2D,gl_id);
222     bool status = true;
223    {int sz;
224     ::glGetIntegerv(GL_MAX_TEXTURE_SIZE,&sz);
225   // MacBookPro : it returns 8192.
226   // Android : it returns 2048.
227   // iPad1 : it returns 2048.
228   // iPod : it returns ?
229   //::printf("debug : GL_MAX_TEXTURE_SIZE : %d\n",sz);
230     tools::img_byte res;
231     if(!sz) {
232       m_out << "toolx::sg::gl::tex_img : warning : GL_MAX_TEXTURE_SIZE is zero." << std::endl;
233       status = gl_tex_img(m_out,a_img);
234     } else {
235     if(a_img.check_gl_limit(sz,res)) {
236       if(res.is_empty()) { //a_img does not exceed.
237         status = gl_tex_img(m_out,a_img);
238       } else {
239         m_out << "toolx::sg::gl::tex_img : warning : img size > GL_MAX_TEXTURE_SIZE (" << sz << ")." << std::endl;
240         status = gl_tex_img(m_out,res);
241         gsto_size = res.size();
242       }
243     } else {
244       m_out << "toolx::sg::gl::tex_img :"
245             << " warning : img size > GL_MAX_TEXTURE_SIZE (" << sz << ") but can't reduce."
246             << std::endl;
247       status = false;
248     }}}
249 
250     if(a_NEAREST) {
251       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST); //good to see astro images pixels.
252       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); //idem.
253     } else {
254       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
255       ::glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
256     }
257     ::glBindTexture(GL_TEXTURE_2D,0);
258 
259     if(!status) {
260       gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_texture (1) :");
261       ::glDeleteTextures(1,&gl_id);
262 #ifdef TOOLS_MEM
263       tools::mem::decrement(tools::s_tex().c_str());
264 #endif
265       gl_id = 0;
266       gl_clear_errors();
267       return 0;
268     }
269 
270     if(gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_texture (2) :")) {
271       ::glDeleteTextures(1,&gl_id);
272 #ifdef TOOLS_MEM
273       tools::mem::decrement(tools::s_tex().c_str());
274 #endif
275       gl_id = 0;
276       gl_clear_errors();
277       return 0;
278     }
279 
280     unsigned int _id = m_gen_id;m_gen_id++;
281     m_gstos[_id] = new gsto_t(gsto_t::kind_texture,gl_id,gsto_size,0);
282     return _id;
283   }
284 
285   ////////////////////////////////////////////////
286   /// VBO ////////////////////////////////////////
287   ////////////////////////////////////////////////
288   virtual unsigned int create_gsto_from_data(size_t a_floatn,const float* a_data) {
289     if(!a_floatn) return 0;
290     switch(m_gsto_mode) {
291     case tools::sg::gsto_gl_vbo:{
292 #ifdef TOOLX_HAS_GL_VBO
293       unsigned int gl_id = 0;
294       ::glGenBuffers(1,&gl_id);
295       if(!gl_id) {
296         if(!m_warned) {
297           m_warned = true;
298           m_out << "toolx::sg::GL_manager::create_gsto_from_data : glGenBuffers failed ()." << std::endl;
299         }
300         return 0;
301       }
302 #ifdef TOOLS_MEM
303       tools::mem::increment(tools::s_gsto().c_str());
304 #endif
305 
306       ::glBindBuffer(GL_ARRAY_BUFFER,gl_id);
307       ::glBufferData(GL_ARRAY_BUFFER,
308                      a_floatn*sizeof(float),a_data,
309                      GL_STATIC_DRAW);
310       ::glBindBuffer(GL_ARRAY_BUFFER,0);
311 
312       if(gl_dump_if_errors(m_out,"toolx::sg::GL_manager::create_gsto_from_data :")) {
313         ::glDeleteBuffers(1,&gl_id);
314 #ifdef TOOLS_MEM
315         tools::mem::decrement(tools::s_gsto().c_str());
316 #endif
317         gl_id = 0;
318         gl_clear_errors();
319         return 0;
320       }
321 
322       unsigned int _id = m_gen_id;m_gen_id++;
323       m_gstos[_id] = new gsto_t(gsto_t::kind_buffer,gl_id,a_floatn*sizeof(float),0);
324       return _id;
325 #else //!TOOLX_HAS_GL_VBO
326       m_out << "toolx::sg::GL_manager::create_gsto_from_data :"
327             << " gsto mode is gl_vbo but class not compiled with TOOLX_HAS_GL_VBO."
328             << std::endl;
329       return 0;
330 #endif //TOOLX_HAS_GL_VBO
331       }break;
332     case tools::sg::gsto_gl_list:{
333       unsigned int gl_id = 0;
334       unsigned int _id = m_gen_id;m_gen_id++;
335       m_gstos[_id] = new gsto_t(gsto_t::kind_list,gl_id,a_floatn*sizeof(float),a_data);
336       return _id;
337       }break;
338     case tools::sg::gsto_memory:{
339       unsigned int gl_id = 0;
340       unsigned int _id = m_gen_id;m_gen_id++;
341       m_gstos[_id] = new gsto_t(gsto_t::kind_memory,gl_id,a_floatn*sizeof(float),a_data);
342       return _id;
343       }break;
344     }
345     return 0;
346   }
347 
348   virtual bool is_gsto_id_valid(unsigned int a_id) const {
349     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
350     if(it==m_gstos.end()) return false;
351     return (*it).second->is_valid();
352   }
353 
354   virtual void delete_gsto(unsigned int a_id){
355     tools::delete_key<unsigned int,gsto_t>(m_gstos,a_id);
356   }
357 
358   ////////////////////////////////////////////////////////
359   ////////////////////////////////////////////////////////
360   ////////////////////////////////////////////////////////
361 
362   float* gsto_data(unsigned int a_id) const {
363     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
364     if(it==m_gstos.end()) return 0;
365     return (*it).second->m_data;
366   }
367 
368   unsigned int gsto_gl_list_id(unsigned int a_id,bool& a_created) const {
369     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
370     if(it==m_gstos.end()) {a_created = false;return 0;}
371     if((*it).second->m_kind!=gsto_t::kind_list) {a_created = false;return 0;}
372     if((*it).second->m_gl_id) {
373       a_created = false;
374       return (*it).second->m_gl_id;
375     } else {
376 #ifdef TOOLX_HAS_GL_LIST
377       unsigned int _id = ::glGenLists(1);
378       if(!_id) {a_created = false;return 0;}
379 #ifdef TOOLS_MEM
380       tools::mem::increment(tools::s_gsto().c_str());
381 #endif
382       a_created = true;
383       (*it).second->m_gl_id = _id;
384       return _id;
385 #else
386       a_created = false;
387       return 0;
388 #endif
389     }
390   }
391 
392   ////////////////////////////////////////////////////////
393   ////////////////////////////////////////////////////////
394   ////////////////////////////////////////////////////////
395   virtual tools::sg::gsto_mode get_gsto_mode() const {return m_gsto_mode;}
396 
397   virtual void set_gsto_mode(tools::sg::gsto_mode a_v) {
398     if(a_v==m_gsto_mode) return;
399     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
400     switch(a_v) {
401     case tools::sg::gsto_gl_vbo:{
402 #ifdef TOOLX_HAS_GL_VBO
403       m_gsto_mode = a_v;
404 #else
405       m_gsto_mode = tools::sg::gsto_memory;
406 #endif
407       }break;
408     case tools::sg::gsto_gl_list:{
409 #ifdef TOOLX_HAS_GL_LIST
410       m_gsto_mode = a_v;
411 #else
412       m_gsto_mode = tools::sg::gsto_memory;
413 #endif
414       }break;
415     case tools::sg::gsto_memory:{
416       m_gsto_mode = tools::sg::gsto_memory;
417       }break;
418     }
419   }
420 
421   virtual void available_gsto_modes(std::vector<std::string>& a_vs) {
422     a_vs.clear();
423 #ifdef TOOLX_HAS_GL_VBO
424     a_vs.push_back(tools::sg::s_gsto_gl_vbo());
425 #endif
426 #ifdef TOOLX_HAS_GL_LIST
427     a_vs.push_back(tools::sg::s_gsto_gl_list());
428 #endif
429     a_vs.push_back(tools::sg::s_gsto_memory());
430   }
431 
432   virtual void available_not_memory_gsto_mode(std::string& a_v) const {
433     a_v.clear();
434 #ifdef TOOLX_HAS_GL_VBO
435     a_v = tools::sg::s_gsto_gl_vbo();
436 #endif
437 #ifdef TOOLX_HAS_GL_LIST
438     if(a_v.empty()) a_v = tools::sg::s_gsto_gl_list();
439 #endif
440   }
441 
442   virtual size_t used_texture_memory() const {
443     size_t sz = 0;
444     std::map<unsigned int,gsto_t*>::const_iterator it;
445     for(it=m_gstos.begin();it!=m_gstos.end();++it) {
446       if((*it).second->m_kind==gsto_t::kind_texture) sz += (*it).second->m_size;
447     }
448     return sz;
449   }
450 
451   virtual size_t gstos_size() const {
452     size_t sz = 0;
453     std::map<unsigned int,gsto_t*>::const_iterator it;
454     for(it=m_gstos.begin();it!=m_gstos.end();++it) sz += (*it).second->m_size;
455     return sz;
456   }
457 
458 public:
459   GL_manager(std::ostream& a_out)
460   :m_out(a_out)
461   ,m_gen_id(1)
462 #ifdef TOOLX_HAS_GL_VBO
463   ,m_gsto_mode(tools::sg::gsto_gl_vbo) //priority to GL VBOs.
464 #elif TOOLX_HAS_GL_LIST
465   ,m_gsto_mode(tools::sg::gsto_gl_list)
466 #else
467   ,m_gsto_mode(tools::sg::gsto_memory)
468 #endif
469   ,m_warned(false)
470   {}
471   virtual ~GL_manager(){
472     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
473   }
474 public:
475   GL_manager(const GL_manager& a_from)
476   :parent(a_from)
477   ,m_out(a_from.m_out)
478   ,m_gen_id(a_from.m_gen_id)
479   ,m_gsto_mode(a_from.m_gsto_mode)
480   ,m_warned(false)
481   {}
482   GL_manager& operator=(const GL_manager& a_from){
483     if(&a_from==this) return *this;
484     m_gen_id = a_from.m_gen_id;
485     m_gsto_mode = a_from.m_gsto_mode;
486     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
487     m_warned = false;
488     return *this;
489   }
490 
491 public:
492   void bind_gsto(unsigned int a_id) {
493     std::map<unsigned int,gsto_t*>::const_iterator it = m_gstos.find(a_id);
494     if(it==m_gstos.end()) return;
495     (*it).second->bind();
496   }
497 
498   void delete_gstos() {
499     tools::safe_clear<unsigned int,gsto_t>(m_gstos);
500   }
501 
502 public:
503 
504   static unsigned char* get_rgbas(unsigned int a_w,unsigned int a_h) {
505     //WARNING : it does OpenGL. Under Android it should be executed
506     //          in the OpenGL thread.
507     //NOTE : Android, iOS : RGB produces a black image.
508     unsigned char* rgbas = new unsigned char[4 * a_w * a_h];
509     if(!rgbas) return 0;
510     ::glPixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
511     ::glReadPixels(0,0,a_w,a_h,GL_RGBA,GL_UNSIGNED_BYTE,rgbas);
512  /*{size_t number = 4 * a_w * a_h;
513     size_t count_not_255 = 0;
514     for(size_t item=3;item<number;item+=4) {
515       unsigned char a = rgbas[item];
516       if(a!=255) {
517         ::printf("%lu : %d\n",item,a);
518         count_not_255++;
519   rgbas[item] = 255;
520       }
521     }
522     ::printf("not_255 : %lu\n",count_not_255);}*/
523     return rgbas;
524   }
525 
526 #if defined(TARGET_OS_IPHONE) || defined(ANDROID)
527   static unsigned char* get_rgbs(unsigned int a_w,unsigned int a_h) {
528     unsigned char* rgbas = get_rgbas(a_w,a_h);
529     if(!rgbas) return 0;
530     unsigned char* rgbs = tools::_4s_to_3s<unsigned char,unsigned int>(rgbas,a_w,a_h);
531     delete [] rgbas;
532     return rgbs;
533   }
534 #else
535   static unsigned char* get_rgbs(unsigned int a_w,unsigned int a_h) {
536     //WARNING : it does OpenGL. Under Android it should be executed
537     //          in the OpenGL thread.
538     //NOTE : Android, iOS : RGB produces a black image.
539     unsigned char* rgbs = new unsigned char[3 * a_w * a_h];
540     if(!rgbs) return 0;
541     ::glPixelStorei(GL_PACK_ALIGNMENT,1); //needed with Cocoa.
542     ::glReadPixels(0,0,a_w,a_h,GL_RGB,GL_UNSIGNED_BYTE,rgbs);
543     return rgbs;
544   }
545 #endif
546 
547 protected:
548   std::ostream& m_out;
549 
550   class gsto_t {
551     TOOLS_SCLASS(GL_manager::gsto_t)
552   public:
553     enum kind {
554       kind_texture,
555       kind_buffer,
556       kind_list,
557       kind_memory
558     };
559   public:
560     gsto_t(kind a_kind,int a_gl_id,size_t a_size,const float* a_data)
561     :m_gl_id(a_gl_id)
562     ,m_kind(a_kind)
563     ,m_size(a_size)
564     ,m_data(0)
565     {
566 #ifdef TOOLS_MEM
567       tools::mem::increment(s_class().c_str());
568 #endif
569       if(a_data) {
570         size_t num = m_size/sizeof(float);
571         m_data = new float[num];
572 #ifdef TOOLS_MEM
573         tools::mem::increment(tools::s_new().c_str());
574 #endif
575         ::memcpy(m_data,a_data,m_size);
576       }
577     }
578     virtual ~gsto_t() {
579       if(m_kind==kind_texture) {
580         ::glDeleteTextures(1,&m_gl_id);
581 #ifdef TOOLS_MEM
582         tools::mem::decrement(tools::s_tex().c_str());
583 #endif
584       } else if(m_kind==kind_buffer) {
585 #ifdef TOOLX_HAS_GL_VBO
586         ::glDeleteBuffers(1,&m_gl_id);
587 #ifdef TOOLS_MEM
588         tools::mem::decrement(tools::s_gsto().c_str());
589 #endif
590 #endif
591       } else if(m_kind==kind_list) {
592         if(m_gl_id) {
593 #ifdef TOOLX_HAS_GL_LIST
594           ::glDeleteLists(m_gl_id,1);
595 #ifdef TOOLS_MEM
596           tools::mem::decrement(tools::s_gsto().c_str());
597 #endif
598 #endif
599         }
600       }
601 
602       if(m_data) {
603         delete [] m_data;
604 #ifdef TOOLS_MEM
605         tools::mem::decrement(tools::s_new().c_str());
606 #endif
607       }
608 #ifdef TOOLS_MEM
609       tools::mem::decrement(s_class().c_str());
610 #endif
611     }
612   private:
613     gsto_t(const gsto_t& a_from)
614     :m_gl_id(a_from.m_gl_id)
615     ,m_kind(a_from.m_kind)
616     ,m_size(a_from.m_size)
617     ,m_data(0)
618     {
619 #ifdef TOOLS_MEM
620       tools::mem::increment(s_class().c_str());
621 #endif
622       if(a_from.m_data) {
623         size_t num = m_size/sizeof(float);
624         m_data = new float[num];
625 #ifdef TOOLS_MEM
626         tools::mem::increment(tools::s_new().c_str());
627 #endif
628         ::memcpy(m_data,a_from.m_data,m_size);
629       }
630     }
631     gsto_t& operator=(const gsto_t& a_from){
632       if(&a_from==this) return *this;
633       m_gl_id = a_from.m_gl_id;
634       m_kind = a_from.m_kind;
635       m_size = a_from.m_size;
636       if(m_data) {
637         delete [] m_data;
638 #ifdef TOOLS_MEM
639         tools::mem::decrement(tools::s_new().c_str());
640 #endif
641         m_data = 0;
642       }
643       if(a_from.m_data) {
644         size_t num = m_size/sizeof(float);
645         m_data = new float[num];
646 #ifdef TOOLS_MEM
647         tools::mem::increment(tools::s_new().c_str());
648 #endif
649         ::memcpy(m_data,a_from.m_data,m_size);
650       }
651       return *this;
652     }
653   public:
654     bool is_valid() const {
655       if(m_kind==kind_texture) {
656         return (::glIsTexture(m_gl_id)==GL_TRUE?true:false);
657       } else if(m_kind==kind_buffer) {
658 #ifdef TOOLX_HAS_GL_VBO
659         return (::glIsBuffer(m_gl_id)==GL_TRUE?true:false);
660 #endif
661       } else if(m_kind==kind_list) {
662 #ifdef TOOLX_HAS_GL_LIST
663         return (::glIsList(m_gl_id)==GL_TRUE?true:false);
664 #endif
665       } else if(m_kind==kind_memory) {
666         return true;
667       }
668       return false;
669     }
670     void bind() const {
671       if(m_kind==kind_texture) {
672         ::glBindTexture(GL_TEXTURE_2D,m_gl_id);
673       } else if(m_kind==kind_buffer) {
674 #ifdef TOOLX_HAS_GL_VBO
675         ::glBindBuffer(GL_ARRAY_BUFFER,m_gl_id);
676 #endif
677       }
678     }
679   public:
680     unsigned int m_gl_id;
681     kind m_kind;
682     size_t m_size;
683     float* m_data;
684   };
685 
686   std::map<unsigned int,gsto_t*> m_gstos;
687 
688   unsigned int m_gen_id;
689   tools::sg::gsto_mode m_gsto_mode;
690   bool m_warned;
691 };
692 
693 }}
694 
695 #endif