core/vgui/vgui_section_render.cxx
Go to the documentation of this file.
00001 // This is core/vgui/vgui_section_render.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 // \author fsm
00008 
00009 #include "vgui_section_render.h"
00010 
00011 #include <vcl_cmath.h>
00012 #include <vcl_cassert.h>
00013 #include <vcl_climits.h> // for UCHAR_MAX
00014 // not used? #include <vcl_iostream.h>
00015 #include <vgui/internals/vgui_rasterpos.h>
00016 #include <vgui/internals/vgui_accelerate.h>
00017 
00018 static inline float fsm_max(float x, float y) { return x>y ? x : y; }
00019 static inline float fsm_min(float x, float y) { return x<y ? x : y; }
00020 
00021 // Set to 1 for verbose debugging.
00022 #if 0
00023 # include <vcl_cstdio.h>
00024 # define fsm_debug vcl_printf
00025 #else
00026 static inline void fsm_debug(char const *, ...) { }
00027 #endif
00028 static bool clamped_viewport(float x0, float y0, float x1, float y1,
00029                              unsigned& i0, unsigned& j0,
00030                              unsigned& ni, unsigned& nj,
00031                              float& zoomx, float& zoomy)
00032 {
00033   // Get current matrix state, in fortran order.
00034   double Pt[4][4], Mt[4][4];
00035   glGetDoublev(GL_PROJECTION_MATRIX, &Pt[0][0]);
00036   glGetDoublev(GL_MODELVIEW_MATRIX,  &Mt[0][0]);
00037 
00038   // Get total world-to-device transformation. It should be of the form :
00039   // * 0 0 *
00040   // 0 * 0 *
00041   // 0 0 * *
00042   // 0 0 0 *
00043   // with the diagonal entries non-zero. If not of this form, return false.
00044   //
00045   double T[4][4];
00046   for (unsigned i=0; i<4; ++i) {
00047     for (unsigned j=0; j<4; ++j) {
00048       T[i][j] = 0;
00049       for (unsigned k=0; k<4; ++k)
00050         T[i][j] += Pt[k][i] * Mt[j][k]; // Pt[k][i] = P[i][k] etc
00051     }
00052   }
00053   if (!T[0][0]|| T[0][1] || T[0][2] ||
00054       T[1][0] ||!T[1][1] || T[1][2] ||
00055       T[2][0] || T[2][1] ||!T[2][2] ||
00056       T[3][0] || T[3][1] || T[3][2] || !T[3][3])
00057     return false; // cannot do
00058   // From image to device coordinates, the projection is :
00059   // [ T00  0  T03 ]   [ a   u ]
00060   // [  0  T11 T13 ] ~ [   b v ]
00061   // [  0   0  T33 ]   [     1 ]
00062   float a = float(T[0][0]/T[3][3]), b = float(T[1][1]/T[3][3]);
00063   float u = float(T[0][3]/T[3][3]), v = float(T[1][3]/T[3][3]);
00064 
00065   // Get size of viewport. We need this to determine how much to scale pixels by.
00066   GLint vp[4]; // x,y, w,h
00067   glGetIntegerv(GL_VIEWPORT, vp);
00068   //int vp_x = vp[0];
00069   //int vp_y = vp[1];
00070   int vp_w = vp[2];
00071   int vp_h = vp[3];
00072   if (vp_w <= 0 || vp_h <= 0)
00073     return true;
00074 
00075 
00076   // From device to viewport coordinates, the transformation is :
00077   // [ vp_w   0  vp_x ] [ 1/2  0  1/2 ]
00078   // [   0  vp_h vp_y ] [  0  1/2 1/2 ]
00079   // [   0    0    1  ] [  0   0   1  ]
00080   // where vp_x, vp_y, vp_w, vp_h are the start, width and height of the viewport.
00081 
00082   // Compute pixel zoom, as passed to glPixelZoom().
00083  zoomx = a*vp_w/2;
00084  zoomy = b*vp_h/2;
00085 
00086   // Clip the given region [x0, x1] x [y0, y1] to the viewport.  In
00087   // device coordinates, the viewport is [-1, +1] x [-1, +1] so it's
00088   // easiest to start from that. This clipping is especially important
00089   // for non-local displays, where the display clipping happens on the
00090   // display server.
00091   //
00092   if (a>0) {
00093     // [ (-1-u)/a, (+1-u)/a ]
00094     x0 = fsm_max(x0, (-1-u)/a);
00095     x1 = fsm_min(x1, (+1-u)/a);
00096   }
00097   else {
00098     // [ (+1-u)/a, (-1-u)/a ]
00099     x0 = fsm_max(x0, (+1-u)/a);
00100     x1 = fsm_min(x1, (-1-u)/a);
00101   }
00102   if (b>0) {
00103     // [ (-1-v)/b, (+1-v)/b ]
00104     y0 = fsm_max(y0, (-1-v)/b);
00105     y1 = fsm_min(y1, (+1-v)/b);
00106   }
00107   else {
00108     // [ (+1-v)/b, (-1-v)/b ]
00109     y0 = fsm_max(y0, (+1-v)/b);
00110     y1 = fsm_min(y1, (-1-v)/b);
00111   }
00112   if (x0 > x1 || y0 > y1) {
00113     fsm_debug("nothing to render\n");
00114     return true; // that's easy.
00115   }
00116 
00117   // Before dumping the image, we have to set a valid raster
00118   // position. However, to get a smooth panning effect, we want to
00119   // render the (potentially) partial pixels at the borders, which
00120   // means we must get the raster position to an "invalid" position
00121   // outside the viewport. vgui_rasterpos wraps the appropriate
00122   // trickery.
00123 
00124   int i_x0 = int(vcl_floor(x0)), i_y0 = int(vcl_floor(y0));
00125   int i_x1 = int(vcl_ceil (x1)), i_y1 = int(vcl_ceil (y1));
00126   //Set the raster position
00127   vgui_rasterpos2i( i_x0, i_y0 );
00128   //return the view parameters
00129   i0 = static_cast<unsigned>(i_x0);   ni = static_cast<unsigned>(i_x1-i_x0);
00130   j0 = static_cast<unsigned>(i_y0);   nj = static_cast<unsigned>(i_y1-i_y0);
00131   return true;
00132 }
00133 
00134 bool pixel_view(unsigned& i0, unsigned& ni, unsigned& j0, unsigned& nj,
00135                 float& zoomx, float& zoomy)
00136 {
00137   float x0 = i0, x1 = ni, y0 = j0, y1 = nj;
00138   return clamped_viewport(x0, y0, x1, y1, i0, j0, ni, nj, zoomx, zoomy);
00139 }
00140 
00141 static void GL_setup(GLenum format, GLenum type , bool hardware_map,
00142                      GLint& alignment, GLint& row_length, GLint& skip_pixels,
00143                      GLint& skip_rows, GLint& table_size, GLboolean& map_color,
00144                      vbl_array_1d<float>* fLmap,  vbl_array_1d<float>* fRmap,
00145                      vbl_array_1d<float>* fGmap,  vbl_array_1d<float>* fBmap,
00146                      vbl_array_1d<float>* fAmap)
00147 {
00148   glGetIntegerv(GL_UNPACK_ALIGNMENT,   &alignment);
00149   glGetIntegerv(GL_UNPACK_ROW_LENGTH,  &row_length);
00150    glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &skip_pixels);
00151   glGetIntegerv(GL_UNPACK_SKIP_ROWS,   &skip_rows);
00152   glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, &table_size);
00153   glGetBooleanv(GL_MAP_COLOR, &map_color);
00154   //If hardware mapping is requested, set up the maps
00155   //only support color mapping for byte component type
00156   if (hardware_map&&type == GL_UNSIGNED_BYTE&&table_size>=(UCHAR_MAX+1))
00157   {
00158     if (format == GL_LUMINANCE)
00159     {
00160       glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
00161       float* tfLmap = fLmap->begin();
00162       glPixelMapfv(GL_PIXEL_MAP_R_TO_R, UCHAR_MAX, tfLmap);
00163       glPixelMapfv(GL_PIXEL_MAP_G_TO_G, UCHAR_MAX, tfLmap);
00164       glPixelMapfv(GL_PIXEL_MAP_B_TO_B, UCHAR_MAX, tfLmap);
00165     }
00166     else if (format == GL_RGB)
00167     {
00168       glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
00169       float* tfRmap = fRmap->begin();
00170       float* tfGmap = fGmap->begin();
00171       float* tfBmap = fBmap->begin();
00172       glPixelMapfv(GL_PIXEL_MAP_R_TO_R, UCHAR_MAX, tfRmap);
00173       glPixelMapfv(GL_PIXEL_MAP_G_TO_G, UCHAR_MAX, tfGmap);
00174       glPixelMapfv(GL_PIXEL_MAP_B_TO_B, UCHAR_MAX, tfBmap);
00175     }
00176     else if (format == GL_RGBA)
00177     {
00178       glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
00179       float* tfRmap = fRmap->begin();
00180       float* tfGmap = fGmap->begin();
00181       float* tfBmap = fBmap->begin();
00182       float* tfAmap = fAmap->begin();
00183       glPixelMapfv(GL_PIXEL_MAP_R_TO_R, UCHAR_MAX, tfRmap);
00184       glPixelMapfv(GL_PIXEL_MAP_G_TO_G, UCHAR_MAX, tfGmap);
00185       glPixelMapfv(GL_PIXEL_MAP_B_TO_B, UCHAR_MAX, tfBmap);
00186       glPixelMapfv(GL_PIXEL_MAP_A_TO_A, UCHAR_MAX, tfAmap);
00187     }
00188   }
00189   if (hardware_map&&format == GL_LUMINANCE&&type == GL_UNSIGNED_SHORT
00190       && table_size>=USHRT_MAX)
00191   {
00192     glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
00193     float* tfLmap = fLmap->begin();
00194     glPixelMapfv(GL_PIXEL_MAP_R_TO_R, USHRT_MAX, tfLmap);
00195     glPixelMapfv(GL_PIXEL_MAP_G_TO_G, USHRT_MAX, tfLmap);
00196     glPixelMapfv(GL_PIXEL_MAP_B_TO_B, USHRT_MAX, tfLmap);
00197   }
00198 }
00199 
00200 static void GL_restore(GLboolean& map_color, GLint alignment, GLint row_length,
00201                        GLint skip_pixels, GLint skip_rows)
00202 {
00203   // Restore previous values.
00204   glPixelTransferi(GL_MAP_COLOR, map_color);
00205   glPixelStorei(GL_UNPACK_ALIGNMENT,   alignment);
00206   glPixelStorei(GL_UNPACK_ROW_LENGTH,  row_length);
00207   glPixelStorei(GL_UNPACK_SKIP_ROWS  , skip_pixels);
00208   glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_rows);
00209 }
00210 
00211 bool vgui_section_render(void const *pixels,
00212                          unsigned w, unsigned h, // Size of image.
00213                          float x0, float y0,  // Region of image
00214                          float x1, float y1,  // to render.
00215                          GLenum format,
00216                          GLenum type ,
00217                          bool hardware_map,
00218                          vbl_array_1d<float>* fLmap,
00219                          vbl_array_1d<float>* fRmap,
00220                          vbl_array_1d<float>* fGmap,
00221                          vbl_array_1d<float>* fBmap,
00222                          vbl_array_1d<float>* fAmap)
00223 {
00224   assert(h>0);//eliminates warning of unused h
00225   assert(pixels);
00226   assert(x0 <= x1);
00227   assert(y0 <= y1);
00228 
00229   assert(!hardware_map||format != GL_LUMINANCE||fLmap);
00230   assert(!hardware_map||format != GL_RGB||(fRmap&&fGmap&&fBmap));
00231   assert(!hardware_map||format != GL_RGBA||(fRmap&&fGmap&&fBmap&&fAmap));
00232   float zoomx=1.0f, zoomy=1.0f;
00233   unsigned i0=0, j0=0, ni=0, nj=0;
00234   if (!clamped_viewport(x0, y0, x1, y1, i0, j0, ni, nj, zoomx, zoomy))
00235     return false;
00236   int i_x0 = i0, i_y0 = j0, i_x1 = i0+ni, i_y1 = j0+nj;
00237   // Store old transfer characteristics for restoring it in a bit.
00238   GLint alignment, row_length, skip_pixels, skip_rows, table_size;
00239   GLboolean map_color;
00240   GL_setup(format, type, hardware_map, alignment, row_length,
00241            skip_pixels, skip_rows, table_size, map_color, fLmap, fRmap,
00242            fGmap, fBmap, fAmap);
00243   // Set pixel transfer characteristics.
00244   glPixelStorei(GL_UNPACK_ALIGNMENT,   1);         // use byte alignment for now.
00245   glPixelStorei(GL_UNPACK_ROW_LENGTH,  w);         // size of image rows.
00246   glPixelStorei(GL_UNPACK_SKIP_PIXELS, i_x0);      // number of pixels to skip on the left.
00247   glPixelStorei(GL_UNPACK_SKIP_ROWS,   i_y0);      // number of pixels to skip at the bottom.
00248 
00249   glPixelZoom( zoomx, zoomy );
00250   vgui_accelerate::instance()->vgui_glDrawPixels(i_x1 - i_x0, // Size of pixel rectangle
00251                                                  i_y1 - i_y0, // to be written to frame buffer.
00252                                                  format,
00253                                                  type,
00254                                                  pixels);
00255   GL_restore(map_color, alignment, row_length, skip_pixels, skip_rows);
00256   return true; // could do
00257 }
00258 
00259 bool vgui_view_render(void const *pixels,
00260                       unsigned w, unsigned h, // Size of view
00261                       float zoomx, float zoomy,
00262                       GLenum format,
00263                       GLenum type ,
00264                       bool hardware_map,
00265                       vbl_array_1d<float>* fLmap,
00266                       vbl_array_1d<float>* fRmap,
00267                       vbl_array_1d<float>* fGmap,
00268                       vbl_array_1d<float>* fBmap,
00269                       vbl_array_1d<float>* fAmap)
00270 {
00271   assert(pixels);
00272   assert(!hardware_map||format != GL_LUMINANCE||fLmap);
00273   assert(!hardware_map||format != GL_RGB||(fRmap&&fGmap&&fBmap));
00274   assert(!hardware_map||format != GL_RGBA||(fRmap&&fGmap&&fBmap&&fAmap));
00275 
00276   // Store old transfer characteristics for restoring it in a bit.
00277   GLint alignment, row_length, table_size, skip_pixels, skip_rows;
00278   GLboolean map_color;
00279   GL_setup(format, type, hardware_map, alignment, row_length,
00280            skip_pixels, skip_rows, table_size, map_color, fLmap, fRmap,
00281            fGmap, fBmap, fAmap);
00282   // Set pixel transfer characteristics.
00283   glPixelStorei(GL_UNPACK_ALIGNMENT,   1);         // use byte alignment for now.
00284   glPixelStorei(GL_UNPACK_ROW_LENGTH,  w);         // size of image rows.
00285   glPixelZoom( zoomx+0.001f, zoomy+0.001f );       // something weird happens
00286                                                    // for identity zoom
00287   vgui_accelerate::instance()->vgui_glDrawPixels(w, // Size of pixel rectangle
00288                                                  h, // to be written to frame buffer.
00289                                                  format,
00290                                                  type,
00291                                                  pixels);
00292 
00293   GL_restore(map_color, alignment, row_length, skip_pixels, skip_rows);
00294   return true; // could do
00295 }
00296 
00297 //--------------------------------------------------------------------------------