OmniGCardConverter.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) Massimo Cora' 2006 <maxcvs@gmail.com>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifdef WIN32
00020 #include <windows.h>
00021 #endif
00022 
00023 // opencv
00024 #include <cv.h>
00025 #include <cxtypes.h>
00026 #include <highgui.h>
00027 #include <cvaux.h>
00028 
00029 
00030 #include "OmniGCardConverter.hh"
00031 
00032 
00033 void OmniGCardConverter::angle_type_conversion( const OmniAngle<double> &angle_in, 
00034                                                         OmniAngle<int> &angle_out )
00035 {
00036         int theta, steps;
00037         double rad_angle_start, rad_angle_end;
00038 
00039         rad_angle_start = angle_in.angle_start;
00040         rad_angle_end = angle_in.angle_end;
00041     
00042         // check whether the class was initialized correctly
00043         if ( !is_initialized () )
00044                 return;
00045 
00046         // we need a positive interval.
00047         // So check for a negative angle
00048         if ( rad_angle_start < 0 )
00049                 rad_angle_start = 2 * CV_PI + rad_angle_start;
00050         
00051         if ( rad_angle_end < 0 )
00052                 rad_angle_end = 2 * CV_PI + rad_angle_end;
00053 
00054         // case in which we want to take an angle for example from 3/2pi to pi/2.
00055         if ( rad_angle_end < rad_angle_start ) {
00056                 theta = (int)ceil( rad_angle_start * (_max_radius - _min_radius) );
00057 
00058                 // rad_angle_start + (2 pi angle - rad_angle_end)
00059                 steps = (int)ceil( rad_angle_end *(_max_radius - _min_radius) ) +
00060                         (_pano_width - theta);
00061         }
00062         else if ( rad_angle_end > rad_angle_start ) {
00063                 theta = (int)ceil( rad_angle_start * (_max_radius - _min_radius) );
00064                 steps = (int)ceil( rad_angle_end * (_max_radius - _min_radius) ) - theta;
00065         }
00066         else {                  // normal case
00067                 steps = _pano_width;
00068                 theta = 0;
00069         }
00070 
00071         // now fill in the struct
00072         angle_out.range = steps;
00073         angle_out.angle_start = theta;
00074         angle_out.angle_end = (theta + steps) % _pano_width;
00075 }
00076 
00077 
00078 IplImage* OmniGCardConverter::omni2pano( IplImage *omni_frame, const OmniAngle<int> &IN_interval )
00079 {
00080         assert( omni_frame->width == _video_width );
00081         assert( omni_frame->height == _video_height );
00082 
00083         // update the texture 
00084         glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, omni_frame->width, omni_frame->height,
00085                         GL_BGR_EXT, GL_UNSIGNED_BYTE, omni_frame->imageData);
00086 
00087 
00088         float slide_par = (float)IN_interval.angle_start / (float)_pano_width;
00089 
00090         // go with painting procedure
00091         gl_paint ( slide_par );
00092 
00093         //
00094         // adjust the width size to the next 32 divisor: this is for image alignment correctness
00095         // and mainly if you want to stream that image with ffmpeg, that has problems and incompatibility
00096         // against OpenCv and IplImages.
00097         //
00098         int adjusted_range = IN_interval.range;
00099         int tmp_val = IN_interval.range % 32;
00100 
00101         if ( tmp_val != 0 )
00102                 adjusted_range -= tmp_val;
00103 
00104         // FIXME: probably with some cyclic buffer we can avoid to alloc everytime a new frame
00105         IplImage *res_image;
00106         res_image = cvCreateImage( cvSize( adjusted_range, _pano_height ), IPL_DEPTH_8U, 3 );
00107 
00108         glReadPixels ( 0, 0, adjusted_range,
00109                         res_image->height, GL_BGR_EXT, GL_UNSIGNED_BYTE, res_image->imageData );
00110 
00111         // FIXME: remove this for perfomance...
00112         if ( _flipped_mode )
00113                 cvFlip( res_image, res_image, 0);
00114         return res_image;
00115 }
00116 
00117 
00118 OmniGCardConverter::OmniGCardConverter( double min_radius,
00119                                                                                 double max_radius,
00120                                                                                 double omni_center_x,
00121                                                                                 double omni_center_y,
00122                                                                                 unsigned int video_width,
00123                                                                                 unsigned int video_height,
00124                                                                                 char *program_name /*= "benchmark_hardware"*/,
00125                                                                                 char *vertex_program_file_name /*= "vertex_shader.cg"*/,
00126                                                                                 char *vertex_program_name /*= "vertex_shader_main"*/,
00127                                                                                 char *fragment_program_file_name /*= "pixel_shader.cg"*/,
00128                                                                                 char *fragment_program_name /*= "pixel_shader_main"*/,
00129                                                                             bool flipped_mode /* = false */ ) :
00130                                                                 _min_radius( min_radius ),
00131                                                                 _max_radius( max_radius ),
00132                                                                 _omni_center_x( omni_center_x ),
00133                                                                 _omni_center_y( omni_center_y ),
00134                                                                 _video_width( video_width ),
00135                                 _video_height( video_height ),
00136                                                                 _flipped_mode( flipped_mode )
00137 {
00138         GLuint texture;
00139 
00140         _initialized = false;
00141 
00142         // be sure to have max_radius and min_radius even
00143         if ( (int)_max_radius % 2 != 0 )
00144                 _max_radius++;
00145         if ( (int)_min_radius % 2 != 0 )
00146                 _min_radius++;
00147         
00148         // calculate the final pano width and height
00149         _pano_width = (int)ceil( (_max_radius - _min_radius ) * 2 * CV_PI );
00150         _pano_height = (int)ceil( _max_radius - _min_radius );
00151 
00152 #ifdef WIN32
00153         wgl_init( &_g_window, &_g_application, &_g_keys, _pano_width, _pano_height );
00154 #else   // LINUX
00155         _dpy = XOpenDisplay(NULL);
00156         if ( !_dpy ) {
00157                 DEBUG_PRINT ("Error: XOpenDisplay failed\n");
00158         return;
00159         }
00160 
00161         if ( _pano_width == 0 || _pano_height == 0 ) {
00162                 DEBUG_PRINT("WARNING: _pano_width == 0 || _pano_height == 0\n");
00163         }
00164         
00165         _win = glx_init( _dpy, _pano_width, _pano_height );
00166         if ( _win == 0 ) {
00167                 DEBUG_PRINT ("Error making window\n");
00168                 return;
00169         }
00170 #endif
00171 
00172         _hw_video_height = _hw_video_width = get_texturized_video_size( _video_width, _video_height );
00173 
00174         // strdup some strings
00175         _program_name = strdup( program_name );
00176 
00177         _vertex_program_file_name = strdup( vertex_program_file_name );
00178         _vertex_program_name = strdup ( vertex_program_name );
00179 
00180         _fragment_program_file_name = strdup( fragment_program_file_name );
00181         _fragment_program_name = strdup( fragment_program_name );       
00182         
00183     glGenTextures(1, &texture);
00184         glBindTexture (GL_TEXTURE_2D, texture);
00185 
00186         // Start Of User Initialization
00187         glClearColor (0.0f, 0.0f, 0.0f, 0.0f);
00188 
00189 #ifdef WIN32
00190         setVSync(0);
00191 #endif
00192 
00193         // Enable Texture Mapping
00194         glEnable( GL_TEXTURE_2D );
00195 
00196         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
00197         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
00198 
00199         _cg_context = cgCreateContext();
00200         if ( _cg_context == NULL || check_for_cg_error( "creating context", _program_name, _cg_context) < 0 )
00201                 return;
00202 
00203         //
00204         // vertex shader part
00205         //
00206 
00207         _cg_vertex_profile = cgGLGetLatestProfile( CG_GL_VERTEX );
00208         cgGLSetOptimalOptions( _cg_vertex_profile );
00209         if ( check_for_cg_error("selecting vertex profile", _program_name, _cg_context) < 0 )
00210                 return;
00211 
00212         _cg_vertex_program =
00213                 cgCreateProgramFromFile(
00214                         _cg_context,              /* Cg runtime context */
00215                         CG_SOURCE,                /* Program in human-readable form */
00216                         _vertex_program_file_name,  /* Name of file containing program */
00217                         _cg_vertex_profile,        /* Profile: OpenGL ARB vertex program */
00218                         _vertex_program_name,      /* Entry function name */
00219                         NULL );                    /* No extra compiler options */
00220 
00221         if ( check_for_cg_error("creating vertex program from file", _program_name, _cg_context) < 0)
00222                 return;
00223 
00224         cgGLLoadProgram( _cg_vertex_program );
00225         if ( check_for_cg_error("loading vertex program", _program_name, _cg_context) < 0 )
00226                 return;
00227 
00228 
00229         // setup the min radius to skip from conversion. Namely min_radius_on_max_radius
00230         // e.g. 40 / 220 = 0.18, where 40 and 220 are respectively the min and max madius
00231         _cg_vertex_param_min_radius_on_max_radius = cgGetNamedParameter( _cg_vertex_program, "min_radius_on_max_radius" );
00232         cgGLSetParameter1f( _cg_vertex_param_min_radius_on_max_radius, (float)(_min_radius / _max_radius) );
00233 
00234         //
00235         // fragment/pixel shader part
00236         //
00237 
00238         _cg_fragment_profile = cgGLGetLatestProfile( CG_GL_FRAGMENT );
00239         cgGLSetOptimalOptions( _cg_fragment_profile );
00240         if ( check_for_cg_error("selecting fragment profile", _program_name, _cg_context) < 0 )
00241                 return;
00242 
00243         _cg_fragment_program =
00244                 cgCreateProgramFromFile(
00245                         _cg_context,                                    /* Cg runtime context */
00246                         CG_SOURCE,                                              /* Program in human-readable form */
00247                         _fragment_program_file_name,    /* Name of file containing program */
00248                         _cg_fragment_profile,                   /* Profile: OpenGL ARB vertex program */
00249                         _fragment_program_name,                 /* Entry function name */
00250                         NULL);                                                  /* No extra compiler options */
00251 
00252         if ( check_for_cg_error("creating fragment program from file", _program_name, _cg_context) < 0 )
00253                 return;
00254         
00255         cgGLLoadProgram( _cg_fragment_program );
00256         if ( check_for_cg_error("loading fragment program", _program_name, _cg_context) < 0 )
00257                 return;
00258 
00259         _cg_fragment_param_omni_tex = cgGetNamedParameter( _cg_fragment_program, "omni_tex" );
00260         _cg_fragment_param_center_x = cgGetNamedParameter( _cg_fragment_program, "center_x" );
00261         _cg_fragment_param_center_y = cgGetNamedParameter( _cg_fragment_program, "center_y" );
00262         _cg_fragment_param_width_on_height = cgGetNamedParameter( _cg_fragment_program, "width_on_height" );
00263         _cg_fragment_param_slide = cgGetNamedParameter( _cg_fragment_program, "slide" );
00264 
00265         unsigned char *empty_texture = new unsigned char[_hw_video_height * _hw_video_width * 3];
00266 
00267         // Create The Texture
00268         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _hw_video_width, _hw_video_height, 
00269                 0, GL_RGB, GL_UNSIGNED_BYTE, empty_texture );
00270         delete empty_texture;
00271 
00272         cgGLSetTextureParameter( _cg_fragment_param_omni_tex, texture );
00273         cgGLSetParameter1f( _cg_fragment_param_center_x, (float)_omni_center_x / (float)_hw_video_width );
00274         cgGLSetParameter1f( _cg_fragment_param_center_y, (float)_omni_center_y / (float)_hw_video_height );
00275         cgGLSetParameter1f( _cg_fragment_param_width_on_height, (float)_video_width / (float)_video_height );
00276         cgGLSetParameter1f( _cg_fragment_param_slide, 0.0f );
00277 
00278         _initialized = true;
00279 }
00280 
00281 OmniGCardConverter::~OmniGCardConverter() 
00282 {
00283         if ( _program_name )
00284                 free( _program_name );
00285         if ( _vertex_program_file_name )
00286                 free( _vertex_program_file_name );
00287         if ( _vertex_program_name )
00288                 free( _vertex_program_name );
00289         if ( _fragment_program_file_name )
00290                 free( _fragment_program_file_name );
00291         if ( _fragment_program_name )
00292                 free( _fragment_program_name ); 
00293                 
00294 #ifdef WIN32
00295         wgl_deinit (&_g_window, &_g_application, &_g_keys);
00296 #else
00297         glx_deinit( _dpy );
00298 #endif
00299                 
00300 }
00301 
00302 #ifdef WIN32
00303 void OmniGCardConverter::setVSync( int interval /* = 1 */) 
00304 {
00305         const char *extensions = (const char*)glGetString( GL_EXTENSIONS );
00306 
00307         if( strstr( extensions, "WGL_EXT_swap_control" ) == 0 )
00308                 return; // Error: WGL_EXT_swap_control extension not supported on your computer.\n");
00309         else {
00310                 _wglSwapIntervalEXT = (PFNWGLSWAPINTERVALFARPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
00311 
00312                 if( _wglSwapIntervalEXT )
00313                         _wglSwapIntervalEXT( interval );
00314         }
00315 }
00316 #endif
00317 
00318 int OmniGCardConverter::check_for_cg_error( const char *situation, char *prg_name, CGcontext cg_ctx )
00319 {
00320         CGerror error;
00321         const char *string = cgGetLastErrorString(&error);
00322 
00323         if (error != CG_NO_ERROR) {
00324                 DEBUG_PRINT("%s: %s: %s\n",
00325                         prg_name, situation, string);
00326 
00327                 if (error == CG_COMPILER_ERROR) {
00328                         DEBUG_PRINT("%s\n", cgGetLastListing( cg_ctx ));
00329                 }
00330                 return -1;
00331         }
00332 
00333         return 0;
00334 }
00335 
00336 int OmniGCardConverter::get_texturized_video_size( int video_width, int video_height ) 
00337 {
00338         int mask=0;
00339         int value;
00340 
00341         value = (video_width >= video_height ? video_width : video_height);
00342         
00343     while( (mask & value) != value ) {
00344                 mask = ( mask << 1 ) +1;
00345         }
00346 
00347         return mask +1;
00348 }
00349 
00350 double OmniGCardConverter::get_min_radius () 
00351 {
00352         return _min_radius;
00353 }
00354 
00355 double OmniGCardConverter::get_max_radius ()
00356 {
00357         return _max_radius;
00358 }
00359 
00360 double OmniGCardConverter::get_omni_center_y ()
00361 {
00362         return _omni_center_y;
00363 }
00364 
00365 double OmniGCardConverter::get_omni_center_x () 
00366 {
00367         return _omni_center_x;
00368 }
00369 
00370 bool OmniGCardConverter::is_initialized () 
00371 {
00372         return _initialized;
00373 }
00374 
00375 void OmniGCardConverter::gl_paint ( float slide /*= 0.0f*/ )
00376 {
00377         glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);            // Clear Screen And Depth Buffer
00378 
00379         cgGLBindProgram( _cg_vertex_program );
00380         cgGLEnableProfile( _cg_vertex_profile );
00381         
00382         cgGLBindProgram( _cg_fragment_program );
00383         cgGLEnableProfile( _cg_fragment_profile );
00384 
00385         cgGLSetParameter1f( _cg_fragment_param_slide, slide);
00386 
00387         cgGLEnableTextureParameter( _cg_fragment_param_omni_tex );
00388         cgGLEnableClientState ( _cg_fragment_param_center_x );
00389         cgGLEnableClientState ( _cg_fragment_param_center_y );
00390         cgGLEnableClientState ( _cg_fragment_param_slide );
00391 
00392         // Begin Drawing The Background (One Quad)
00393         glBegin(GL_QUADS);                                                                              
00394 
00395         glTexCoord2f(0, 0);
00396         glVertex2f(-1, -1);
00397 
00398         glTexCoord2f(1, 0);
00399         glVertex2f(1, -1);
00400 
00401         glTexCoord2f(1, 1);
00402         glVertex2f(1, 1);
00403         
00404         glTexCoord2f(0, 1);
00405         glVertex2f(-1, 1);
00406 
00407         // Done Drawing 
00408         glEnd();                                                                                                
00409 
00410     // disable hardware acceleration
00411         cgGLDisableProfile( _cg_vertex_profile );
00412         cgGLDisableProfile( _cg_fragment_profile );
00413         cgGLDisableTextureParameter( _cg_fragment_param_omni_tex );
00414 
00415         // flush rendering pipeline
00416         glFlush();
00417 }
00418 
00419 /* unsed yet */
00420 IplImage* OmniGCardConverter::omni2pano( IplImage *omni_frame, const OmniAngle<double> &IN_interval )
00421 {
00422         DEBUG_PRINT ("unused function omni2pano with double angle\n");
00423         return NULL;
00424 }
00425 
00426 
00427 void OmniGCardConverter::pano2omni_xy( CvPoint *pano_point, double theta_start, 
00428                                                                           CvPoint *omni_point )
00429 {
00430         omni_point->x = (int)((pano_point->y  + _min_radius ) * 
00431                 cos((theta_start + pano_point->x) / _max_radius ));  
00432 
00433         omni_point->y = (int)((pano_point->y + _min_radius ) * 
00434                 sin((theta_start + pano_point->x) / _max_radius ));  
00435 
00436         omni_point->x += (int)_omni_center_x;
00437         omni_point->y += (int)_omni_center_y;
00438 }
00439 
00440 
00441 
00442 bool OmniGCardConverter::check_for_3d_gcard_availability ()
00443 {
00444 
00445 
00446 #ifdef WIN32    
00447         Application     g_application;
00448         GL_Window       g_window;
00449         Keys            g_keys;
00450 
00451         wgl_init( &g_window, &g_application, &g_keys, 0, 0 );
00452 #else
00453     Display *dpy_tmp;
00454     Window win_tmp;
00455 
00456         dpy_tmp = XOpenDisplay (NULL);
00457         if ( !dpy_tmp ) {
00458                 DEBUG_PRINT ("Error: XOpenDisplay failed\n");
00459         return false;
00460         }
00461 
00462         win_tmp = glx_init( dpy_tmp, 1, 1 );
00463 
00464         if ( win_tmp == 0 ) {
00465                 DEBUG_PRINT ("Error making window\n");
00466                 return false;
00467         }
00468 
00469 #endif
00470 
00471         // ok, instead of doing the cg* tests below, we can also check the GL_EXTENSIONS 
00472         // stuff in a way like this.
00473 /*
00474         // Make sure the card supports fragment programs at all, by searching for the extension string
00475         const char *extensions = reinterpret_cast<const char *>( glGetString( GL_EXTENSIONS ) );
00476         const bool cardSupportsARB = ( strstr( extensions, "GL_ARB_fragment_program" ) != NULL );
00477 */
00478 
00479 
00480         CGcontext   cg_context_tmp;
00481         CGprofile   cg_vertex_profile_tmp, cg_fragment_profile_tmp;
00482 
00483         cg_context_tmp = cgCreateContext();
00484         if ( cg_context_tmp == NULL || check_for_cg_error("creating context", NULL, cg_context_tmp) < 0 ) {
00485 #ifdef WIN32
00486                 wgl_deinit( &g_window, &g_application, &g_keys);
00487 #else
00488                 glx_deinit( dpy_tmp );
00489 #endif
00490                 return false;
00491         }
00492 
00493         // vertex shader check
00494 
00495         cg_vertex_profile_tmp = cgGLGetLatestProfile( CG_GL_VERTEX );
00496         cgGLSetOptimalOptions( cg_vertex_profile_tmp );
00497         if ( check_for_cg_error("selecting vertex profile", NULL, cg_context_tmp) < 0 ) {
00498 #ifdef WIN32    
00499                 wgl_deinit( &g_window, &g_application, &g_keys);
00500 #else
00501                 glx_deinit( dpy_tmp );
00502 #endif
00503                 return false;
00504         }
00505 
00506         // fragment/pixel shader check
00507         cg_fragment_profile_tmp = cgGLGetLatestProfile( CG_GL_FRAGMENT );
00508         cgGLSetOptimalOptions( cg_fragment_profile_tmp );
00509         if ( check_for_cg_error("selecting fragment profile", NULL, cg_context_tmp) < 0 ) {
00510 #ifdef WIN32
00511                 wgl_deinit( &g_window, &g_application, &g_keys);
00512 #else
00513         glx_deinit( dpy_tmp );
00514 #endif
00515 
00516                 return false;
00517         }
00518 
00519 #ifdef WIN32
00520         wgl_deinit( &g_window, &g_application, &g_keys);
00521 #else
00522         glx_deinit( dpy_tmp );
00523 #endif
00524 
00525         return true;
00526 }

Generated on Tue Dec 26 10:32:38 2006 for Omnimeeting by  doxygen 1.4.7