core/vgui/vgui_utils.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_utils.cxx
00002 #include "vgui_utils.h"
00003 //:
00004 // \file
00005 // \author fsm
00006 // \date   Oct 99
00007 // \brief  See vgui_utils.h for a description of this file.
00008 
00009 #include <vcl_cstdlib.h>
00010 #include <vcl_cassert.h>
00011 #include <vcl_iostream.h>
00012 
00013 #include <vil1/vil1_rgba.h>
00014 #include <vil1/vil1_save.h>
00015 
00016 #include <vgui/vgui_gl.h>
00017 #include <vgui/vgui_glu.h>
00018 
00019 #include <vil/vil_rgba.h>
00020 
00021 //------------------------------------------------------------------------------
00022 // copy the buffer into a memory image
00023 vil1_memory_image_of<vil1_rgb<GLubyte> > vgui_utils::get_image()
00024 {
00025   // We should grab the pixels off the front buffer, since that is what is visible.
00026   GLint cur_read_buffer;
00027   glGetIntegerv( GL_READ_BUFFER, &cur_read_buffer );
00028   glReadBuffer( GL_FRONT );
00029 
00030   // get viewport size
00031   GLint vp[4]; // x,y,w,h
00032   glGetIntegerv(GL_VIEWPORT, vp);
00033   unsigned x = vp[0];
00034   unsigned y = vp[1];
00035   unsigned w = vp[2];
00036   unsigned h = vp[3];
00037 
00038   // It's easier to get the buffer in vil1_rgba format and then convert to
00039   // RGB, because that avoids alignment problems with glReadPixels.
00040   vil1_rgba<GLubyte> *pixels = new vil1_rgba<GLubyte>[ w * h ];
00041 
00042   //
00043   glPixelZoom(1,1);
00044   glPixelTransferi(GL_MAP_COLOR,0);
00045   glPixelTransferi(GL_RED_SCALE,1);   glPixelTransferi(GL_RED_BIAS,0);
00046   glPixelTransferi(GL_GREEN_SCALE,1); glPixelTransferi(GL_GREEN_BIAS,0);
00047   glPixelTransferi(GL_BLUE_SCALE,1);  glPixelTransferi(GL_BLUE_BIAS,0);
00048 
00049   //
00050   glPixelStorei(GL_PACK_ALIGNMENT,1);   // byte alignment.
00051   glPixelStorei(GL_PACK_ROW_LENGTH,0);  // use default value (the arg to pixel routine).
00052   glPixelStorei(GL_PACK_SKIP_PIXELS,0); //
00053   glPixelStorei(GL_PACK_SKIP_ROWS,0);   //
00054 
00055   //
00056   glReadPixels(x, y,             //
00057                w, h,             //
00058                GL_RGBA,          // format
00059                GL_UNSIGNED_BYTE, // type
00060                pixels);
00061 
00062   glReadBuffer( cur_read_buffer );
00063 
00064   // glReadPixels() reads the pixels from the bottom of the viewport up.
00065   // Copy them into a vil1_memory_image_of in the other order :
00066   vil1_memory_image_of<vil1_rgb<GLubyte> > colour_buffer(w, h);
00067   for (unsigned yy=0; yy<h; ++yy)
00068     for (unsigned xx=0; xx<w; ++xx) {
00069       colour_buffer(xx, h-1-yy).r = pixels[xx + w*yy].r;
00070       colour_buffer(xx, h-1-yy).g = pixels[xx + w*yy].g;
00071       colour_buffer(xx, h-1-yy).b = pixels[xx + w*yy].b;
00072     }
00073 
00074   //
00075   delete [] pixels;
00076   return colour_buffer;
00077 }
00078 
00079 // return a memory image corresponding to the GL buffer
00080 vil1_memory_image_of<vil1_rgb<unsigned char> >
00081 vgui_utils::colour_buffer_to_image()
00082 {
00083   vil1_memory_image_of<vil1_rgb<GLubyte> > colour_buffer =
00084     vgui_utils::get_image();
00085   vil1_memory_image_of<vil1_rgb<unsigned char> > temp(colour_buffer);
00086   return temp;
00087 }
00088 
00089 // write the GL buffer to a file
00090 void vgui_utils::dump_colour_buffer(char const *file)
00091 {
00092   vil1_memory_image_of<vil1_rgb<GLubyte> > colour_buffer =
00093     vgui_utils::get_image();
00094   vil1_save(colour_buffer, file);
00095 }
00096 
00097 //------------------------------------------------------------------------------
00098 // copy the buffer into a vil image view
00099 vil_image_view<GLubyte>
00100 vgui_utils::get_view()
00101 {
00102   // get viewport size
00103   GLint vp[4]; // x,y,w,h
00104   glGetIntegerv(GL_VIEWPORT, vp);
00105   unsigned x = vp[0];
00106   unsigned y = vp[1];
00107   unsigned w = vp[2];
00108   unsigned h = vp[3];
00109 
00110   // It's easier to get the buffer in vil_rgba format and then convert to
00111   // RGB, because that avoids alignment problems with glReadPixels.
00112   vil_rgba<GLubyte> *pixels = new vil_rgba<GLubyte>[ w * h ];
00113 
00114   //
00115   glPixelZoom(1,1);
00116   glPixelTransferi(GL_MAP_COLOR,0);
00117   glPixelTransferi(GL_RED_SCALE,1);   glPixelTransferi(GL_RED_BIAS,0);
00118   glPixelTransferi(GL_GREEN_SCALE,1); glPixelTransferi(GL_GREEN_BIAS,0);
00119   glPixelTransferi(GL_BLUE_SCALE,1);  glPixelTransferi(GL_BLUE_BIAS,0);
00120 
00121   //
00122   glPixelStorei(GL_PACK_ALIGNMENT,1);   // byte alignment.
00123   glPixelStorei(GL_PACK_ROW_LENGTH,0);  // use default value (the arg to pixel routine).
00124   glPixelStorei(GL_PACK_SKIP_PIXELS,0); //
00125   glPixelStorei(GL_PACK_SKIP_ROWS,0);   //
00126 
00127   //
00128   glReadPixels(x, y,             //
00129                w, h,             //
00130                GL_RGBA,          // format
00131                GL_UNSIGNED_BYTE, // type
00132                pixels);
00133 
00134   // glReadPixels() reads the pixels from the bottom of the viewport up.
00135   // Copy them into a vil_image_view in the other order :
00136   vil_image_view<GLubyte> view(w, h, 1, 3);
00137   for (unsigned yy=0; yy<h; ++yy)
00138     for (unsigned xx=0; xx<w; ++xx) {
00139       view(xx, h-1-yy, 0) = pixels[xx + w*yy].r;
00140       view(xx, h-1-yy, 1) = pixels[xx + w*yy].g;
00141       view(xx, h-1-yy, 2) = pixels[xx + w*yy].b;
00142     }
00143 
00144   //
00145   delete [] pixels;
00146   return view;
00147 }
00148 
00149 
00150 //: Get an image view corresponding to the OpenGL area
00151 vil_image_view<vxl_byte>
00152 vgui_utils::colour_buffer_to_view()
00153 {
00154   vil_image_view<GLubyte> buffer = vgui_utils::get_view();
00155   vil_image_view<vxl_byte> temp(buffer);
00156   return temp;
00157 }
00158 
00159 
00160 //------------------------------------------------------------------------------
00161 
00162 // Copies the contents of the current read colour buffer into the current draw
00163 // colour buffer.
00164 void vgui_utils::do_copy()
00165 {
00166   //void glCopyPixels( GLint x, GLint y, GLsizei width, GLsizei height, GLenum type )
00167 
00168   GLint vp[4]; // x,y,w,h
00169   glGetIntegerv(GL_VIEWPORT, vp);
00170 
00171   // save matrices and set new :
00172   glMatrixMode(GL_MODELVIEW);
00173   glPushMatrix();
00174   glLoadIdentity();
00175 
00176   glMatrixMode(GL_PROJECTION);
00177   glPushMatrix();
00178   glLoadIdentity();
00179   glOrtho(0,vp[2], 0,vp[3], -1,+1); // near, far
00180 
00181   // set raster position to the bottom left-hand corner.
00182   glRasterPos2i(0, 0);
00183 
00184   // restore old matrices.
00185   glMatrixMode(GL_MODELVIEW);
00186   glPopMatrix();
00187 
00188   glMatrixMode(GL_PROJECTION);
00189   glPopMatrix();
00190 
00191   // copy pixels :
00192   glPixelZoom(1,1);
00193   glPixelTransferi(GL_MAP_COLOR,0);
00194   glPixelTransferi(GL_RED_SCALE,1);   glPixelTransferi(GL_RED_BIAS,0);
00195   glPixelTransferi(GL_GREEN_SCALE,1); glPixelTransferi(GL_GREEN_BIAS,0);
00196   glPixelTransferi(GL_BLUE_SCALE,1);  glPixelTransferi(GL_BLUE_BIAS,0);
00197   glPixelTransferi(GL_ALPHA_SCALE,1); glPixelTransferi(GL_ALPHA_BIAS,0);
00198   glDisable(GL_DITHER);
00199   glCopyPixels(0,0,         // window coordinates of lower left corner
00200                vp[2],vp[3], // width and height of region to be copied.
00201                GL_COLOR);   // copy colour values.
00202 }
00203 
00204 void vgui_utils::copy_front_to_back()
00205 {
00206   GLint old_read,old_draw;
00207   glGetIntegerv(GL_READ_BUFFER,&old_read);
00208   glGetIntegerv(GL_DRAW_BUFFER,&old_draw);
00209 
00210   glReadBuffer(GL_FRONT);
00211   glDrawBuffer(GL_BACK);
00212   vgui_utils::do_copy();
00213 
00214   glReadBuffer(GLenum(old_read));
00215   glDrawBuffer(GLenum(old_draw));
00216 }
00217 
00218 void vgui_utils::copy_back_to_front()
00219 {
00220   GLint old_read,old_draw;
00221   glGetIntegerv(GL_READ_BUFFER,&old_read);
00222   glGetIntegerv(GL_DRAW_BUFFER,&old_draw);
00223 
00224   glReadBuffer(GL_BACK);
00225   glDrawBuffer(GL_FRONT);
00226   vgui_utils::do_copy();
00227 
00228   glReadBuffer(GLenum(old_read));
00229   glDrawBuffer(GLenum(old_draw));
00230 }
00231 
00232 //------------------------------------------------------------------------------
00233 
00234 static GLint gl_old_buffer = -1;
00235 
00236 void vgui_utils::begin_sw_overlay()
00237 {
00238   glGetIntegerv(GL_DRAW_BUFFER, &gl_old_buffer);
00239   if (gl_old_buffer != GL_NONE)
00240     glDrawBuffer(GL_FRONT);
00241 }
00242 
00243 void vgui_utils::end_sw_overlay()
00244 {
00245   if (gl_old_buffer == -1) {
00246     vcl_cerr << "WARNING :  end_sw_overlay called before begin_sw_overlay\n";
00247     return;
00248   }
00249 
00250   glFlush();
00251   // revert to rendering into the back buffer :
00252   glDrawBuffer((GLenum)gl_old_buffer);
00253 
00254   gl_old_buffer = -1;
00255 }
00256 
00257 
00258 static bool in_pick_mode = false;
00259 
00260 GLuint* vgui_utils::enter_pick_mode(float x,float y,float w,float h)
00261 {
00262   assert(!in_pick_mode); in_pick_mode = true;
00263 
00264   if (h==0) h=w;
00265 
00266   static unsigned const HIT_BUFFER_SIZE=4096;
00267   static GLuint buffer[HIT_BUFFER_SIZE];
00268 
00269   // define hit buffer
00270   glSelectBuffer(HIT_BUFFER_SIZE,buffer);
00271 
00272   // get viewport
00273   GLint viewport[4];
00274   glGetIntegerv(GL_VIEWPORT, viewport);
00275 
00276   // enter selection mode
00277   glRenderMode(GL_SELECT);
00278 
00279   //
00280   glInitNames();
00281 
00282   // save old projection matrix and define viewing volume for selection :
00283   glMatrixMode(GL_PROJECTION);
00284   glPushMatrix();
00285 
00286   float P[16]; // get current projection matrix
00287   glGetFloatv(GL_PROJECTION_MATRIX,P);
00288 
00289   glLoadIdentity(); // make a pick matrix
00290   gluPickMatrix(x,y,w,h,viewport); // thank heavens for viewport coordinates.
00291 
00292   glMultMatrixf(P); // right multiply the old matrix onto it
00293 
00294   return buffer;
00295 }
00296 
00297 // return number of hits.
00298 unsigned vgui_utils::leave_pick_mode()
00299 {
00300   assert(in_pick_mode); in_pick_mode = false;
00301 
00302   // restore viewing volume and render mode
00303   glMatrixMode(GL_PROJECTION);
00304   glPopMatrix();
00305   return glRenderMode(GL_RENDER);
00306 }
00307 
00308 void vgui_utils::process_hits(int num_hits, GLuint* ptr, vcl_vector<vcl_vector<unsigned> >& hits)
00309 {
00310 #ifdef DEBUG
00311     vcl_cerr << "hits = " << num_hits << vcl_endl;
00312 #endif
00313   // for each hit
00314    for (int i = 0; i < num_hits; i++) {
00315      GLuint num_names = *ptr;
00316 #ifdef DEBUG
00317        vcl_cerr << "number of names for hit["<< i <<"] = " << num_names << vcl_endl;
00318 #endif
00319      ptr++;
00320 #ifdef DEBUG
00321        vcl_cerr << " z1 is " << *ptr;
00322 #endif
00323      ptr++;
00324 #ifdef DEBUG
00325        vcl_cerr << "; z2 is " << *ptr << vcl_endl;
00326 #endif
00327      ptr++;
00328 
00329      vcl_vector<unsigned> names;
00330 #ifdef DEBUG
00331        vcl_cerr << " the name is ";
00332 #endif
00333      // for each name
00334      for (unsigned int j = 0; j < num_names; j++) {
00335        names.push_back(*ptr);
00336 #ifdef DEBUG
00337          vcl_cerr << *ptr << ' ';
00338 #endif
00339        ptr++;
00340      }
00341 #ifdef DEBUG
00342        vcl_cerr << vcl_endl << "names.size() " << names.size() << vcl_endl;
00343 #endif
00344      hits.push_back(names);
00345 
00346 #ifdef DEBUG
00347        vcl_cerr << vcl_endl;
00348 #endif
00349    }
00350 #ifdef DEBUG
00351      vcl_cerr << "hits.size() " << hits.size() << vcl_endl;
00352 #endif
00353 }
00354 
00355 
00356 int
00357 vgui_utils::bits_per_pixel(GLenum format, GLenum type)
00358 {
00359 #define M(f, t, size) if (format == f && type == t) return size;
00360   M(GL_RGB,      GL_UNSIGNED_BYTE,          24);
00361   M(GL_BGR,      GL_UNSIGNED_BYTE,          24);
00362   M(GL_RGBA,     GL_UNSIGNED_BYTE,          32);
00363 #if defined(GL_UNSIGNED_SHORT_5_6_5)
00364   M(GL_RGB,      GL_UNSIGNED_SHORT_5_6_5,   16);
00365 #endif
00366 #if defined(GL_UNSIGNED_SHORT_5_5_5_1)
00367   M(GL_RGB,      GL_UNSIGNED_SHORT_5_5_5_1, 16);
00368 #endif
00369 #if defined(GL_BGRA)
00370   M(GL_BGRA,     GL_UNSIGNED_BYTE,          32);
00371 #endif
00372 #if defined(GL_EXT_abgr) || defined(GL_ABGR_EXT)
00373   M(GL_ABGR_EXT, GL_UNSIGNED_BYTE,          32);
00374 #endif
00375 #undef M
00376 
00377   vcl_cerr << "vgui_utils::bits_per_pixel: UNKNOWN COMBO, format = " << format << ", type = " << type << vcl_endl;
00378   vcl_abort();
00379   return 0;
00380 }