core/vgui/vgui_section_buffer.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_section_buffer.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 // \brief  See vgui_section_buffer.h for a description of this file.
00009 //
00010 // \verbatim
00011 //  Modifications
00012 //   16-AUG-2000 Marko Bacic, Oxford RRG -- Added support for multiple textures
00013 //               Many cheap graphics cards do not support texture maps
00014 //               bigger than 256x256. To support images greater than 256x256
00015 //               it was necessary to add support for multiple textures.
00016 //               Hence an image is rendered by tiling together several textures
00017 //               containing different parts of it.
00018 //   16-AUG-2000 fsm -- Imposed my rigid ways on Marko's changes.
00019 //               Fixes for SolarisGL.
00020 //   05-AUG-2003 Amitha Perera --
00021 //               Added support for rendering vil_image_views, and cleaned up
00022 //               the macros for selecting the pixel types and doing the data
00023 //               conversion.
00024 // \endverbatim
00025 
00026 #include "vgui_section_buffer.h"
00027 
00028 #include <vcl_cassert.h>
00029 #include <vcl_iostream.h>
00030 #include <vbl/vbl_array_1d.h>
00031 #include <vil1/vil1_image.h>
00032 #include <vil1/vil1_pixel.h>
00033 
00034 #include <vil/vil_image_view.h>
00035 #include <vil/vil_image_resource.h>
00036 #include <vil/vil_pixel_format.h>
00037 #include "vgui_macro.h"
00038 #include "vgui_pixel.h"
00039 #include "vgui_section_render.h"
00040 #include "vgui_range_map_params.h"
00041 #include "vgui_range_map.h"
00042 #include "internals/vgui_gl_selection_macros.h"
00043 #include "internals/vgui_accelerate.h"
00044 
00045 static bool debug = false;
00046 
00047 namespace
00048 {
00049   // These two helper functions are used in the apply() methods. See
00050   // the comments in apply(vil_image_view_base).
00051 
00052   // This is a helper routine for vgui_section_buffer::apply()
00053   //
00054   // Converts the section of \a in marked by (x,y)-(x+w-1,y+h-1) into
00055   // the output GL buffer \a out.
00056   //
00057   // Also handles multi-plane images with scalar-valued pixels.
00058   //
00059   template <class InT, class OutT>
00060   bool
00061   convert_buffer( vil_image_view<InT> const& in,
00062                   vgui_range_map_params_sptr const& rmp,
00063                   OutT* out, vcl_ptrdiff_t hstep )
00064   {
00065     bool params_but_not_mappable = false;
00066     if (rmp&&rmp->n_components_==in.nplanes())
00067     {
00068       vgui_range_map<InT> rm(*rmp);
00069       if (rm.table_mapable())
00070       {
00071         // offset for signed types
00072         int O = rm.offset();
00073         switch ( in.nplanes() )
00074         {
00075           case 1:
00076           {
00077             vbl_array_1d<vxl_byte> Lmap = rm.Lmap();
00078             for ( unsigned j=0; j < in.nj(); ++j )
00079               for ( unsigned i=0; i < in.ni(); ++i )
00080                 vgui_pixel_convert( Lmap[(unsigned)(in(i,j)+O)],
00081                                     *(out+i+j*hstep) );
00082             return true;
00083           }
00084           case 3:
00085           {
00086             vbl_array_1d<vxl_byte> Rmap = rm.Rmap();
00087             vbl_array_1d<vxl_byte> Gmap = rm.Gmap();
00088             vbl_array_1d<vxl_byte> Bmap = rm.Bmap();
00089             for ( unsigned j=0; j < in.nj(); ++j )
00090               for ( unsigned i=0; i < in.ni(); ++i )
00091                 vgui_pixel_convert( Rmap[(unsigned)(in(i,j,0)+O)],
00092                                     Gmap[(unsigned)(in(i,j,1)+O)],
00093                                     Bmap[(unsigned)(in(i,j,2)+O)],
00094                                     *(out+i+j*hstep) );
00095             return true;
00096           }
00097           case 4:
00098           {
00099             vbl_array_1d<vxl_byte> Rmap = rm.Rmap();
00100             vbl_array_1d<vxl_byte> Gmap = rm.Gmap();
00101             vbl_array_1d<vxl_byte> Bmap = rm.Bmap();
00102             vbl_array_1d<vxl_byte> Xmap = rm.Xmap();
00103             if (rm.band_map_==vgui_range_map_params::RGBA_m)
00104             {
00105               for ( unsigned j=0; j < in.nj(); ++j ) // go here
00106                 for ( unsigned i=0; i < in.ni(); ++i )
00107                   vgui_pixel_convert( Rmap[(unsigned)(in(i,j,0)+O)],
00108                                       Gmap[(unsigned)(in(i,j,1)+O)],
00109                                       Bmap[(unsigned)(in(i,j,2)+O)],
00110                                       Xmap[(unsigned)(in(i,j,3)+O)],
00111                                       *(out+i+j*hstep) );
00112               return true;
00113             }
00114             else
00115               switch (rm.band_map_)
00116               {
00117                 case vgui_range_map_params::RGB_m :
00118                   for ( unsigned j=0; j < in.nj(); ++j )
00119                     for ( unsigned i=0; i < in.ni(); ++i )
00120                       vgui_pixel_convert( Rmap[(unsigned)(in(i,j,0))+O],
00121                                           Gmap[(unsigned)(in(i,j,1))+O],
00122                                           Bmap[(unsigned)(in(i,j,2))+O],
00123                                           Xmap[(unsigned)(rmp->max_X_)],
00124                                           *(out+i+j*hstep) );
00125                   return true;
00126                 case vgui_range_map_params::XRG_m :
00127                   for ( unsigned j=0; j < in.nj(); ++j )
00128                     for ( unsigned i=0; i < in.ni(); ++i )
00129                       vgui_pixel_convert( Rmap[(unsigned)(in(i,j,3))+O],
00130                                           Gmap[(unsigned)(in(i,j,0))+O],
00131                                           Bmap[(unsigned)(in(i,j,1))+O],
00132                                           Xmap[(unsigned)(rmp->max_X_)],
00133                                           *(out+i+j*hstep) );
00134                   return true;
00135                 case vgui_range_map_params::RXB_m :
00136                   for ( unsigned j=0; j < in.nj(); ++j )
00137                     for ( unsigned i=0; i < in.ni(); ++i )
00138                       vgui_pixel_convert( Rmap[(unsigned)(in(i,j,1))+O],
00139                                           Gmap[(unsigned)(in(i,j,3))+O],
00140                                           Bmap[(unsigned)(in(i,j,2))+O],
00141                                           Xmap[(unsigned)(rmp->max_X_)],
00142                                           *(out+i+j*hstep) );
00143                   return true;
00144                 case vgui_range_map_params::RGX_m :
00145                   for ( unsigned j=0; j < in.nj(); ++j )
00146                     for ( unsigned i=0; i < in.ni(); ++i )
00147                       vgui_pixel_convert( Rmap[(unsigned)(in(i,j,0))+O],
00148                                           Gmap[(unsigned)(in(i,j,1))+O],
00149                                           Bmap[(unsigned)(in(i,j,3))+O],
00150                                           Xmap[(unsigned)(rmp->max_X_)],
00151                                           *(out+i+j*hstep) );
00152                   return true;
00153                 default:
00154                   assert(!"invalid band_map");
00155                   return false;
00156               }
00157           }
00158           default:
00159             assert(!"invalid nplanes");
00160             return false;
00161         }
00162       }
00163       if (rm.mapable()) // have to compute the mapping on the fly,e.g. for float
00164       {
00165         switch ( in.nplanes() )
00166         {
00167          case 1:
00168           for ( unsigned j=0; j < in.nj(); ++j )
00169             for ( unsigned i=0; i < in.ni(); ++i )
00170               vgui_pixel_convert( rm.map_L_pixel(in(i,j)),
00171                                   *(out+i+j*hstep) );
00172           return true;
00173          case 3:
00174           for ( unsigned j=0; j < in.nj(); ++j )
00175             for ( unsigned i=0; i < in.ni(); ++i )
00176               vgui_pixel_convert( rm.map_R_pixel(in(i,j,0)),
00177                                   rm.map_G_pixel(in(i,j,1)),
00178                                   rm.map_B_pixel(in(i,j,2)),
00179                                   *(out+i+j*hstep) );
00180           return true;
00181          case 4:
00182           if (rm.band_map_==vgui_range_map_params::RGBA_m)
00183           {
00184             for ( unsigned j=0; j < in.nj(); ++j )
00185               for ( unsigned i=0; i < in.ni(); ++i )
00186                 vgui_pixel_convert( rm.map_R_pixel(in(i,j,0)),
00187                                     rm.map_G_pixel(in(i,j,1)),
00188                                     rm.map_B_pixel(in(i,j,2)),
00189                                     rm.map_X_pixel(in(i,j,3)),
00190                                     *(out+i+j*hstep) );
00191             return true;
00192           }
00193           else
00194           {
00195             switch (rm.band_map_)
00196             {
00197              case vgui_range_map_params::RGB_m :
00198               for ( unsigned j=0; j < in.nj(); ++j )
00199                 for ( unsigned i=0; i < in.ni(); ++i )
00200                   vgui_pixel_convert( rm.map_R_pixel(in(i,j,0)),
00201                                       rm.map_G_pixel(in(i,j,1)),
00202                                       rm.map_B_pixel(in(i,j,2)),
00203                                       rm.map_X_pixel(0),
00204                                       *(out+i+j*hstep) );
00205               break;
00206              case vgui_range_map_params::XRG_m :
00207               for ( unsigned j=0; j < in.nj(); ++j )
00208                 for ( unsigned i=0; i < in.ni(); ++i )
00209                   vgui_pixel_convert( rm.map_R_pixel(in(i,j,3)),
00210                                       rm.map_G_pixel(in(i,j,1)),
00211                                       rm.map_B_pixel(in(i,j,2)),
00212                                       rm.map_X_pixel(0),
00213                                       *(out+i+j*hstep) );
00214               break;
00215              case vgui_range_map_params::RXB_m :
00216               for ( unsigned j=0; j < in.nj(); ++j )
00217                 for ( unsigned i=0; i < in.ni(); ++i )
00218                   vgui_pixel_convert( rm.map_R_pixel(in(i,j,1)),
00219                                       rm.map_G_pixel(in(i,j,3)),
00220                                       rm.map_B_pixel(in(i,j,2)),
00221                                       rm.map_X_pixel(0),
00222                                       *(out+i+j*hstep) );
00223               break;
00224              case vgui_range_map_params::RGX_m :
00225               for ( unsigned j=0; j < in.nj(); ++j )
00226                 for ( unsigned i=0; i < in.ni(); ++i )
00227                   vgui_pixel_convert( rm.map_R_pixel(in(i,j,0)),
00228                                       rm.map_G_pixel(in(i,j,1)),
00229                                       rm.map_B_pixel(in(i,j,3)),
00230                                       rm.map_X_pixel(0),
00231                                       *(out+i+j*hstep) );
00232               break;
00233              default:
00234               assert(!"invalid band_map");
00235               return false;
00236             }
00237           }
00238          default:
00239           assert(!"invalid nplanes");
00240           return false;
00241         }// end switch
00242       }
00243       params_but_not_mappable = true;
00244     }
00245 
00246     // otherwise, just clamp the values as originally done
00247     if (params_but_not_mappable || !rmp || rmp->n_components_!=in.nplanes())
00248     {
00249       switch ( in.nplanes() )
00250       {
00251         case 1:
00252           for ( unsigned j=0; j < in.nj(); ++j )
00253             for ( unsigned i=0; i < in.ni(); ++i )
00254               vgui_pixel_convert( in(i,j), *(out+i+j*hstep) );
00255           return true;
00256         case 3:
00257           for ( unsigned j=0; j < in.nj(); ++j )
00258             for ( unsigned i=0; i < in.ni(); ++i )
00259               vgui_pixel_convert( in(i,j,0), in(i,j,1), in(i,j,2),
00260                                   *(out+i+j*hstep) );
00261           return true;
00262         case 4:
00263           for ( unsigned j=0; j < in.nj(); ++j )
00264             for ( unsigned i=0; i < in.ni(); ++i )
00265               vgui_pixel_convert( in(i,j,0), in(i,j,1), in(i,j,2),
00266                                   in(i,j,3), *(out+i+j*hstep) );
00267           return true;
00268         default:
00269           assert(!"invalid nplanes");
00270           return false;
00271       } // end case
00272     }
00273     else
00274       return false;
00275   }
00276 
00277   // Given the input image type, determine the output image type (GL
00278   // pixel type) and call convert_buffer() to do the actual conversion
00279   //
00280   // Used in the vgui_section_buffer::apply().
00281   //
00282   template <class InT>
00283   bool
00284   convert_image( vil_image_view<InT> const& in,
00285                  vgui_range_map_params_sptr const& rmp,
00286                  void* out, vcl_ptrdiff_t hstep,
00287                  GLenum format, GLenum type )
00288   {
00289     bool result = false;
00290 
00291 #define Code(BufferType) result=convert_buffer(in,rmp,(BufferType*)out,hstep);
00292     ConditionListBegin;
00293     ConditionListBody( format, type );
00294     ConditionListFail {
00295       // shouldn't fail here. If we don't know this format and type, the
00296       // constructor would've failed.
00297       assert( false );
00298     }
00299 #undef Code
00300 
00301     return result;
00302   }
00303 } // end anonymous namespace
00304 
00305 
00306 // =============================================================================
00307 //                                                          VGUI SECTION BUFFER
00308 // =============================================================================
00309 
00310 
00311 // ---------------------------------------------------------------------------
00312 //                                                                 constructor
00313 
00314 vgui_section_buffer::
00315 vgui_section_buffer( unsigned in_x, unsigned in_y,
00316                      unsigned in_w, unsigned in_h,
00317                      GLenum in_format,
00318                      GLenum in_type )
00319   : format_( in_format ),
00320     type_( in_type ),
00321     x_( in_x ),
00322     y_( in_y ),
00323     w_( in_w ),
00324     h_( in_h ),
00325     zoomx_(1.0f),
00326     zoomy_(1.0f),
00327     allocw_( w_ ),
00328     alloch_( h_ ),
00329     buffer_( 0 ),
00330     buffer_ok_( false )
00331 {
00332   assert( w_ > 0 && h_ > 0 );
00333 
00334   // It doesn't seem to make any sense to specify only one of the 'format' and
00335   // 'type' parameters. Until we decide if it makes sense, it's not allowed.
00336   if      ( format_ == GL_NONE && type_ == GL_NONE )
00337     vgui_accelerate::instance()->vgui_choose_cache_format( &format_, &type_ );
00338   else if ( format_ == GL_NONE || type_ == GL_NONE )
00339     assert(false);
00340 
00341   // make sure allocw_ and alloch_ have been initialized.
00342   assert( allocw_*alloch_ >= w_*h_ );
00343 
00344   // To add a new format, you need to:
00345   // - create a new pixel type in vgui_pixel.h. Make sure the size of
00346   //   that pixel type is the same as that of the corresponding GL type.
00347   // - add the format type to
00348   //   internals/vgui_gl_selection_macros.h. Make sure to only
00349   //   conditionally include your type unless you are certain that all
00350   //   OpenGL implementations will support that type.
00351 
00352   // This will generate code for every GL pixel type we know about.
00353 #define Code(BufferType) buffer_=new BufferType[allocw_*alloch_];
00354   ConditionListBegin;
00355   ConditionListBody( format_, type_ );
00356   ConditionListFail {
00357     vcl_cerr << __FILE__ << ": " << __LINE__ << ": unknown GL format ("
00358              << format_ << ") and type (" << type_ << ").\n"
00359              << "You can probably easily add support here.\n";
00360     assert( false );
00361   }
00362 #undef Code
00363 }
00364 
00365 
00366 // ---------------------------------------------------------------------------
00367 //                                                                  destructor
00368 
00369 vgui_section_buffer::
00370 ~vgui_section_buffer()
00371 {
00372   // We need to cast back to the correct type before we delete to make
00373   // sure the correct things happen. Since the data types are POD, it
00374   // doesn't really matter, because no destructors need to be
00375   // called. However, it's always good to do it correctly.
00376   //
00377 #define Code(BufferType) delete[] static_cast<BufferType*>(buffer_);
00378   ConditionListBegin;
00379   ConditionListBody( format_, type_ );
00380   ConditionListFail {
00381     assert( false );
00382   }
00383 #undef Code
00384 }
00385 
00386 
00387 // ---------------------------------------------------------------------------
00388 //                                                  apply (vil image resource)
00389 
00390 void
00391 vgui_section_buffer::
00392 apply( vil_image_resource_sptr const& image_in,
00393        vgui_range_map_params_sptr const& rmp)
00394 {
00395   // In order to display the image, we need to convert the pixels from
00396   // the input image format to the OpenGL buffer format (given by
00397   // format_ and type_). So, there are two "run-time types" that we
00398   // need to handle: the input image pixel type, and the OpenGL buffer
00399   // pixel type. This function determines the first, and based on
00400   // that, calls the appropriate convert_image template instance. That
00401   // function will figure out the current OpenGL pixel type and call
00402   // convert_buffer to actually convert the pixels.
00403 
00404 #define DoCase( T )                                                           \
00405     case T:                                                                   \
00406     {                                                                         \
00407       typedef vil_pixel_format_type_of<T>::type Type;                         \
00408       vil_image_view<Type> img = image_in->get_view( x_, w_, y_, h_ );        \
00409       assert( img );                                                          \
00410       conversion_okay = convert_image(img,rmp,buffer_,allocw_,format_,type_); \
00411       break;                                                                  \
00412     }
00413 
00414   bool conversion_okay = false;
00415   vil_pixel_format component_format =
00416     vil_pixel_format_component_format( image_in->pixel_format() );
00417 
00418   switch ( component_format )
00419   {
00420     DoCase( VIL_PIXEL_FORMAT_UINT_32 )
00421     DoCase( VIL_PIXEL_FORMAT_INT_32 )
00422     DoCase( VIL_PIXEL_FORMAT_UINT_16 )
00423     DoCase( VIL_PIXEL_FORMAT_INT_16 )
00424     DoCase( VIL_PIXEL_FORMAT_BYTE )
00425     DoCase( VIL_PIXEL_FORMAT_SBYTE )
00426     DoCase( VIL_PIXEL_FORMAT_FLOAT )
00427     DoCase( VIL_PIXEL_FORMAT_DOUBLE )
00428     DoCase( VIL_PIXEL_FORMAT_BOOL )
00429     default:
00430       vcl_cerr << __FILE__ << ": " << __LINE__
00431                << ": can't handle image pixel format "
00432                << component_format << '\n';
00433   }
00434 
00435 #undef DoCase
00436 
00437   if ( !conversion_okay ) {
00438     vcl_cerr << __FILE__ << ": " << __LINE__ << ": conversion failed\n";
00439   }
00440 
00441   buffer_ok_ = conversion_okay;
00442 }
00443 
00444 
00445 // ---------------------------------------------------------------------------
00446 //                                                          apply (vil1 image)
00447 
00448 void
00449 vgui_section_buffer::
00450 apply( vil1_image const& image,
00451        vgui_range_map_params_sptr const& rmp)
00452 {
00453   // See comment in the other apply().
00454 
00455   assert( image.planes() == 1 ); // TODO: 3-plane RGB or 4-plane RGBA
00456   vil1_pixel_format_t pixel_format = vil1_pixel_format( image );
00457 
00458   bool conversion_ok = false;
00459   bool section_ok = false;
00460 
00461 #define DoCase( PixelFormat, DataType, NComp )                                \
00462     case PixelFormat:                                                         \
00463     {                                                                         \
00464       DataType* temp_buffer = new DataType[ w_ * h_ * NComp ];                \
00465       section_ok = image.get_section( temp_buffer, x_, y_, w_, h_ );          \
00466       if ( section_ok ) {                                                     \
00467         vil_image_view<DataType> view( temp_buffer, w_, h_, NComp,            \
00468                                        NComp, NComp*w_, 1 );                  \
00469         conversion_ok = convert_image(view,rmp,buffer_,allocw_,format_,type_);\
00470       }                                                                       \
00471       delete[] temp_buffer;                                                   \
00472       break;                                                                  \
00473     }
00474 
00475   switch ( pixel_format )
00476   {
00477     DoCase( VIL1_BYTE,       vxl_byte,    1 )
00478     DoCase( VIL1_UINT16,     vxl_uint_16, 1 )
00479     DoCase( VIL1_UINT32,     vxl_uint_32, 1 )
00480     DoCase( VIL1_FLOAT,      float,       1 )
00481     DoCase( VIL1_DOUBLE,     double,      1 )
00482     DoCase( VIL1_RGB_BYTE,   vxl_byte,    3 )
00483     DoCase( VIL1_RGB_UINT16, vxl_uint_16, 3 )
00484     DoCase( VIL1_RGB_FLOAT,  float,       3 )
00485     DoCase( VIL1_RGB_DOUBLE, double,      3 )
00486     DoCase( VIL1_RGBA_BYTE,  vxl_byte,    4 )
00487     default:
00488       vcl_cerr << __FILE__ << ": " << __LINE__
00489                << ": can't handle image pixel format "
00490                << vil1_print( pixel_format ) << '\n';
00491   }
00492 
00493 #undef DoCase
00494 
00495   if ( !conversion_ok ) {
00496     vcl_cerr << __FILE__ << ": " << __LINE__ << ": conversion failed\n";
00497   }
00498 
00499   if (debug || !section_ok)
00500     vcl_cerr << (section_ok ? "section ok" : "section bad") << vcl_endl;
00501 
00502   buffer_ok_ = section_ok && conversion_ok;
00503 }
00504 
00505 // ---------------------------------------------------------------------------
00506 //                                                           draw as rectangle
00507 
00508 bool
00509 vgui_section_buffer::
00510 draw_as_rectangle( float x0, float y0,  float x1, float y1 ) const
00511 {
00512   glColor3i( 0, 1, 0 ); // is green good for everyone?
00513   glLineWidth( 1 );
00514   glBegin( GL_LINE_LOOP );
00515   glVertex2f( x0, y0 );
00516   glVertex2f( x1, y0 );
00517   glVertex2f( x1, y1 );
00518   glVertex2f( x0, y1 );
00519   glEnd();
00520   return true;
00521 }
00522 
00523 
00524 bool
00525 vgui_section_buffer::
00526 draw_as_rectangle() const
00527 {
00528   return draw_as_rectangle( (float)x_, (float)y_, float(x_+w_), float(y_+h_) );
00529 }
00530 
00531 
00532 // ---------------------------------------------------------------------------
00533 //                                                               draw as image
00534 
00535 bool
00536 vgui_section_buffer::
00537 draw_as_image( float x0, float y0,  float x1, float y1 ) const
00538 {
00539   if ( !buffer_ok_ ) {
00540     vgui_macro_warning << "bad buffer in draw_as_image()\n";
00541     return draw_as_rectangle( x0, y0, x1, y1 );
00542   }
00543 
00544   return vgui_section_render( buffer_,
00545                               allocw_, alloch_,
00546                               x0,y0, x1, y1,
00547                               format_, type_ ,0/*, true*/ );
00548 }
00549 
00550 bool
00551 vgui_section_buffer::
00552 draw_as_image() const
00553 {
00554   return draw_as_image( (float)x_, (float)y_, float(x_+w_), float(y_+h_) );
00555 }
00556 
00557 bool
00558 vgui_section_buffer::draw_viewport_as_image() const
00559 {
00560   // render visible viewport buffer
00561   return vgui_view_render( buffer_,
00562                            w_, h_,
00563                            zoomx_, zoomy_,
00564                            format_, type_ ,false); // no hardware map
00565 }