Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

ref_image.C

Go to the documentation of this file.
00001 #include "color_id_texture.H"
00002 #include "ref_image.H"
00003 
00004 using namespace mlib;
00005 
00006 HASH       RefImage::_hash(16);
00007 HASH      RefImage2::_hash(16);
00008 HASH     IDRefImage::_hash(16);
00009 HASH TexMemRefImage::_hash(16);
00010 
00011 uint IDRefImage::_red_bits   = 0;
00012 uint IDRefImage::_green_bits = 0;
00013 uint IDRefImage::_blue_bits  = 0;
00014 uint IDRefImage::_alpha_bits = 0;
00015 
00016 bool IDRefImage::_nonstandard_bits = false;
00017 
00018 IDRefImage* IDRefImage::_instance = 0;
00019 
00020 /**********************************************************************
00021  * RefImage:
00022  **********************************************************************/
00023 RefImage* 
00024 RefImage::lookup(CVIEWptr& v)
00025 {
00026    if (!v) {
00027       err_msg( "RefImage::lookup: error -- view is nil");
00028       return 0;
00029    }
00030    if (!v->impl()) {
00031       err_msg( "RefImage::lookup: error -- view->impl() is nil");
00032       return 0;
00033    }
00034 
00035    // hash on the view implementation rather than the view itself
00036    long key = (long)v->impl();
00037    RefImage* ret = (RefImage*) _hash.find(key);
00038    if (!ret && (ret = new RefImage(v)))
00039       _hash.add(key, (void *)ret);
00040    return ret;
00041 }
00042 
00043 void 
00044 RefImage::draw_FB() const 
00045 {
00046    // before calling glRasterPos2i(),
00047    // first set up orthographic viewing
00048    // matrix for points in pixel coords:
00049    glMatrixMode(GL_MODELVIEW);
00050    glPushMatrix();
00051    glLoadIdentity();
00052    glMatrixMode(GL_PROJECTION);
00053    glPushMatrix();
00054    glLoadMatrixd(VIEW::peek()->pix_proj().transpose().matrix());
00055 
00056    glRasterPos2i(0,0);
00057 
00058    glPushAttrib(GL_ENABLE_BIT);
00059    glDisable(GL_BLEND);
00060 
00061    glDrawPixels(_width,_height,_format,_type,_values);
00062 
00063    glPopAttrib();
00064 
00065    glPopMatrix();
00066    glMatrixMode(GL_MODELVIEW);
00067    glPopMatrix();
00068 }
00069 
00070 int
00071 RefImage::read_file(char* file)
00072 {
00073    // load up the ref image with an image from a file
00074 
00075    // the Image class already has file I/O capabilities, so we just
00076    // use on of those and copy the data into the RefImage format:
00077    Image img;
00078 
00079    // try to read the file as an image (ppm or png):
00080    if (!img.load_file(file)) {
00081       err_msg( "RefImage::read_file: can't read file %s", file);
00082       return 0;
00083    }
00084 
00085    // resize this
00086    resize(img.width(), img.height());
00087 
00088    // get ready for the switch statement below where we read the data
00089    // according to the internal format of the Image, based on the bits
00090    // per pixel (bpp):
00091    uchar* data = img.data();
00092    uint i=0;
00093    switch(img.bpp()) {
00094     case 4:
00095       // R,G,B,A unsigned char's
00096       for (i=0; i<max(); i++) {
00097          val(i) = build_rgba(data[0], data[1], data[2], data[3]);
00098          data += 4;
00099       }
00100       break;
00101     case 3:
00102       // R,G,B unsigned char's
00103       for (i=0; i<max(); i++) {
00104          val(i) = build_rgba(data[0], data[1], data[2]);
00105          data += 3;
00106       }
00107       break;
00108     case 2:
00109       // luminance/alpha unsigned char's
00110       for (i=0; i<max(); i++) {
00111          val(i) = build_rgba(data[0], data[0], data[0], data[1]);
00112          data += 2;
00113       }
00114       break;
00115     case 1:
00116       // luminance unsigned char's
00117       for (i=0; i<max(); i++) {
00118          val(i) = build_rgba(data[0], data[0], data[0]);
00119          data += 1;
00120       }
00121       break;
00122     default:
00123       // it's not in there
00124       err_msg( "RefImage::read_file: unknown bits per pixel (%d) in image", img.bpp());
00125       return 0;
00126    }
00127 
00128    // no more errors are possible!
00129    return 1;
00130 }
00131 
00132 void 
00133 RefImage::fill(uint fill_color)
00134 {
00135    for (uint i=0; i<_max; i++) {
00136       val(i) = fill_color;
00137    }
00138 }
00139 
00140 int
00141 RefImage::write_file(char* file)
00142 {
00143    if (_format != GL_RGBA && _format != GL_RGB) {
00144       err_msg( "RefImage::write_file: unsupported format (%x)", _format);
00145       return 0;
00146    }
00147 
00148    return Image::write_png(
00149       _width,
00150       _height,
00151       (_format==GL_RGBA) ? 4 : 3,
00152       (GLubyte*)_values,
00153       str_ptr(file)
00154       );
00155 }
00156 
00157 int
00158 RefImage::copy_rgb(Image& img) const
00159 {
00160    // return an Image with same dimensions
00161    // as this, but formatted for RGB:
00162 
00163    // resize image
00164    if (!img.resize(_width,_height,3)) {
00165       err_msg( "RefImage::copy_rgb_image: can't resize image");
00166       return 0;
00167    }
00168 
00169    // copy data
00170    uchar* d = img.data();
00171    for (uint i=0; i<_max; i++) {
00172       uint v = val(i);
00173       *d++ = rgba_to_r(v);
00174       *d++ = rgba_to_g(v);
00175       *d++ = rgba_to_b(v);
00176    }
00177 
00178    return 1;
00179 }
00180 
00181 inline void
00182 set_default_gl_state()
00183 {
00184    glLineWidth(1.0);
00185    glDepthMask(GL_TRUE);
00186    glDepthFunc(GL_LESS);
00187    glEnable(GL_DEPTH_TEST);
00188    glDisable(GL_NORMALIZE);
00189    glDisable(GL_BLEND);
00190    glEnable(GL_CULL_FACE);
00191 }
00192 
00193 void
00194 RefImage::update()
00195 {
00196    glDrawBuffer(GL_BACK);
00197    glReadBuffer(GL_BACK);
00198 
00199    VIEWptr view = VIEW::peek();
00200 
00201    // set up lights
00202    view->setup_lights();
00203 
00204    glPushAttrib(GL_ENABLE_BIT);
00205 
00206    // set default state
00207    set_default_gl_state();
00208 
00209    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
00210    glEnable(GL_COLOR_MATERIAL);
00211    glShadeModel(GL_SMOOTH);
00212   
00213    glViewport(0,0,_width,_height);
00214 
00215    glClearColor(1,1,1,1);
00216    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00217 
00218    draw_objects(view->drawn());
00219 
00220    glReadPixels(0,0,_width,_height,_format,_type,_values);
00221 
00222    glPopAttrib();
00223 
00224    int w, h;
00225    VIEW_SIZE(w,h);
00226    glViewport(0,0,w,h);
00227 }
00228 
00229 void
00230 RefImage::draw_objects(CGELlist& drawn) const
00231 {
00232    VIEWptr view = VIEW::peek();
00233 
00234    // setup projection matrix
00235    glMatrixMode(GL_PROJECTION);
00236    glLoadMatrixd(view->cam()->projection_xform().transpose().matrix());
00237 
00238    // get the camera position matrix
00239    Wtransf mat = view->cam()->xform().transpose();
00240 
00241    glMatrixMode(GL_MODELVIEW);
00242    for (int i=0; i < drawn.num(); i++) {
00243       glLoadMatrixd(mat.matrix());
00244       drawn[i]->draw_ref_img(_ref_img_type);
00245    }
00246 }
00247 
00248 bool
00249 RefImage::find_val_in_box(uint v, Cpoint2i& center, uint rad) const
00250 {
00251    // Return true if the given value v is found in an (n x n) square
00252    // region around the given center location, where n = 2*rad + 1.
00253    // E.g., if rad == 1 the search is within a 3 x 3 region.
00254 
00255    // Get bounds of search region, careful at image boundary:
00256    uint min_x = (uint) ::max(center[0] - rad, uint(0));
00257    uint max_x = (uint) ::min(center[0] + rad, uint(_width-1));
00258    uint min_y = (uint) ::max(center[1] - rad, uint(0));
00259    uint max_y = (uint) ::min(center[1] + rad, uint(_height-1));
00260 
00261    for (uint y=min_y; y<=max_y; y++) {
00262       uint d = y * _width;
00263       for (uint x=min_x; x<=max_x; x++)
00264          if (val(d + x) == v)
00265             return true;
00266    }
00267    return false;
00268 }
00269 
00270 bool
00271 RefImage::find_val_in_box(uint v, uint mask , Cpoint2i& center, uint rad, int nbr) const
00272 {
00273    // Return true if the given value v is found in an (n x n) square
00274    // region around the given center location, where n = 2*rad + 1.
00275    // E.g., if rad == 1 the search is within a 3 x 3 region.
00276 
00277    // XXX in this call we're looking only at a certain section 
00278    // of the bits, cause we're encoding more than just ID into
00279    // the color here    - philipd
00280 
00281    // Get bounds of search region, careful at image boundary:
00282    uint min_x = (uint) ::max(center[0] - rad, uint(0));
00283    uint max_x = (uint) ::min(center[0] + rad, uint(_width-1));
00284    uint min_y = (uint) ::max(center[1] - rad, uint(0));
00285    uint max_y = (uint) ::min(center[1] + rad, uint(_height-1));
00286 
00287    for (uint y=min_y; y<=max_y; y++) {
00288       uint d = y * _width;
00289       for (uint x=min_x; x<=max_x; x++)
00290          if ( (val(d + x) & mask) == (v & mask)) { 
00291             //we've found the right id ( upper bits match )
00292             //but should we do something more, like check
00293             //that parameter is in range?
00294             int found_l   = (int)(val(d+x)& 0x000000ff);
00295             int target_l  = (int)(v       & 0x000000ff);
00296             if ( abs( found_l - target_l ) <= nbr ) {  
00297                return true;
00298             }
00299          }
00300    }
00301    return false;
00302 }
00303 
00304 /**********************************************************************
00305  * RefImage2:
00306  **********************************************************************/
00307 RefImage2* 
00308 RefImage2::lookup(CVIEWptr& v)
00309 {
00310    if (!v) {
00311       err_msg( "RefImage2::lookup: error -- view is nil");
00312       return 0;
00313    }
00314    if (!v->impl()) {
00315       err_msg( "RefImage2::lookup: error -- view->impl() is nil");
00316       return 0;
00317    }
00318 
00319    // hash on the view implementation rather than the view itself
00320    long key = (long)v->impl();
00321    RefImage2* ret = (RefImage2*) _hash.find(key);
00322    if (!ret && (ret = new RefImage2(v)))
00323       _hash.add(key, (void *)ret);
00324    return ret;
00325 }
00326 
00327 /**********************************************************************
00328  * IDRefImage:
00329  **********************************************************************/
00330 IDRefImage* 
00331 IDRefImage::lookup(CVIEWptr& v)
00332 {
00333    if (!v) {
00334       err_msg( "IDRefImage::lookup: error -- view is nil");
00335       return 0;
00336    }
00337    if (!v->impl()) {
00338       err_msg( "IDRefImage::lookup: error -- view->impl() is nil");
00339       return 0;
00340    }
00341 
00342    // hash on the view implementation rather than the view itself
00343    long key = (long)v->impl();
00344    IDRefImage* ret = (IDRefImage*) _hash.find(key);
00345    if (!ret && (ret = new IDRefImage(v)))
00346       _hash.add(key, (void *)ret);
00347    return ret;
00348 }
00349 
00350 IDRefImage::IDRefImage(CVIEWptr& v) :
00351    RefImage(v, RCOLOR_ID) 
00352 {
00353    _ref_img_type = RefImageClient::REF_IMG_ID;
00354    setup_bits(v);
00355 }
00356 
00357 void
00358 IDRefImage::setup_bits(CVIEWptr& view)
00359 {
00360    if (!view)
00361       return;
00362 
00363    // Only do it the first time
00364    if (_red_bits || _green_bits || _blue_bits) {
00365       // Already done, quit early. But check if it's the same answer.
00366       if (view->win()->red_bits()   != _red_bits   ||
00367           view->win()->green_bits() != _green_bits ||
00368           view->win()->blue_bits()  != _blue_bits  ||
00369           view->win()->alpha_bits() != _alpha_bits)
00370          err_msg( "IDRefImage::setup_bits: Error: mismatch of bits");
00371       return;
00372    }
00373    _red_bits    = view->win()->red_bits();
00374    _green_bits  = view->win()->green_bits();
00375    _blue_bits   = view->win()->blue_bits();
00376    _alpha_bits  = view->win()->alpha_bits();
00377 
00378    // XXX - alpha is not considered at this time
00379    _nonstandard_bits = (
00380       (_red_bits   != 8) ||
00381       (_green_bits != 8) ||
00382       (_blue_bits  != 8)
00383       );
00384 
00385    uint r,g,b,a,s,d; 
00386 
00387    r = view->win()->accum_red_bits();
00388    g = view->win()->accum_green_bits();
00389    b = view->win()->accum_blue_bits();
00390    a = view->win()->accum_alpha_bits();
00391    s = view->win()->stencil_bits();
00392    d = view->win()->depth_bits();
00393 
00394    err_msg( "");
00395 
00396    err_msg( "GL Vendor:       %s", glGetString(GL_VENDOR));
00397    err_msg( "GL Renderer:     %s", glGetString(GL_RENDERER));
00398    err_msg( "GL Version:      %s", glGetString(GL_VERSION));
00399 
00400    err_msg( "GL Color RGBA:   %u,%u,%u,%u",
00401             _red_bits, _green_bits, _blue_bits, _alpha_bits);
00402    err_msg( "GL Accum RGBA:   %u,%u,%u,%u", r,g,b,a);
00403    err_msg( "GL Stencil Bits: %u", s);
00404    err_msg( "GL Depth Bits:   %u", d);
00405 
00406    GLint num_units=0;
00407    glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num_units);
00408    err_msg( "Texture units:   %d", num_units);
00409 
00410    err_msg( "");   
00411    
00412 }
00413 
00414 void
00415 IDRefImage::draw_objects(CGELlist& drawn) const
00416 {
00417    int i;
00418 
00419    VIEWptr view = VIEW::peek();
00420 
00421    // setup projection matrix
00422    glMatrixMode(GL_PROJECTION);
00423    glLoadMatrixd(view->cam()->projection_xform().transpose().matrix());
00424 
00425    // get the camera position matrix
00426    Wtransf mat = view->cam()->xform().transpose();
00427 
00428    // XXX - Lets hope people don't change the matrix mode, eh?
00429    glMatrixMode(GL_MODELVIEW);
00430 
00431    // Q: why keep loading the matrix inside the loops?
00432    //    as a defensive gesture? but each loop goes thru
00433    //    all the objects, though in many cases every object
00434    //    does a no-op. that makes for a lot of ogl calls
00435    //    where otherwise it could be a bunch of no-ops.
00436 
00437    //Triangles for see thru objects
00438    for (i=0; i < drawn.num(); i++) {     
00439       glLoadMatrixd(mat.matrix());
00440       drawn[i]->draw_ref_img(RefImageClient::REF_IMG_ID_PRE1);
00441    }
00442 
00443    //Clear Z buffer
00444    glClear(GL_DEPTH_BUFFER_BIT);
00445 
00446    //Hidden lines with z testing
00447    for (i=0; i < drawn.num(); i++) {
00448       glLoadMatrixd(mat.matrix());
00449       drawn[i]->draw_ref_img(RefImageClient::REF_IMG_ID_PRE2);
00450    }
00451 
00452    //Clear Z buffer - and only write z's!
00453    glClear(GL_DEPTH_BUFFER_BIT);
00454    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
00455 
00456    //Triangles for see thru objects (just write the z's)
00457    for (i=0; i < drawn.num(); i++) {
00458       glLoadMatrixd(mat.matrix());
00459       drawn[i]->draw_ref_img(RefImageClient::REF_IMG_ID_PRE3);
00460    }
00461 
00462    //Restore writing to color buffer
00463    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
00464 
00465    //Visible lines with z testing
00466    for (i=0; i < drawn.num(); i++) {
00467       glLoadMatrixd(mat.matrix());
00468       drawn[i]->draw_ref_img(RefImageClient::REF_IMG_ID_PRE4);
00469    }
00470 
00471    //Non-see thru objects to their business...
00472    for (i=0; i < drawn.num(); i++) {
00473       glLoadMatrixd(mat.matrix());
00474       drawn[i]->draw_ref_img(RefImageClient::REF_IMG_ID);
00475    }
00476 }
00477 
00478 bool
00479 IDRefImage::search(
00480    CNDCpt&         c,              // center of search region
00481    double          screen_pix_rad, // search radius in screen pixels
00482    CSimplexFilter& filt,           // tells what kind of simplex to look for
00483    Point2i&        hit             // closest ref image pixel matching search
00484    )
00485 {
00486    // Search around the given location within the given
00487    // radius (specified in units of screen pixels, not
00488    // pixels of this image), to find the closest Bsimplex
00489    // matching the criteria given by the filter function.
00490 
00491    // for safety disallow negative values for the radius.
00492    screen_pix_rad = ::max(0.0, screen_pix_rad);
00493 
00494    // convert radius in screen pixels to ndc units:
00495    double ndc_rad = VIEW::pix_to_ndc_scale() * screen_pix_rad;
00496 
00497    // now to pixel units in this image:
00498    double R = _half_min_dim * ndc_rad;
00499    // get the box containing the search region but not going
00500    // outside the boundaries of this image:
00501    Point2i center = ndc_to_pix(c);
00502    int      min_x = ::max(center[0] - int(ceil(R)), 0);
00503    int      max_x = ::min(center[0] + int(ceil(R)), int(_width-1));
00504    int      min_y = ::max(center[1] - int(ceil(R)), 0);
00505    int      max_y = ::min(center[1] + int(ceil(R)), int(_height-1));
00506 
00507    bool           ret = 0;
00508    double    min_dist = 0, d;
00509    for (int y = min_y; y <= max_y; y++) {
00510       for (int x = min_x; x <= max_x; x++) {
00511          Point2i cur(x,y);
00512          if ((d = cur.dist(center)) < R && // if we're in the radius and
00513              filt.accept(simplex(cur))  && // the simplex is acceptable
00514              (!ret || d < min_dist)) {     // and no winner or new winner
00515             ret      = true;
00516             hit      = cur;
00517             min_dist = d;
00518          }
00519       }
00520    }
00521    return ret;
00522 }
00523 
00524 Bsimplex* 
00525 IDRefImage::find_near_simplex(
00526    CNDCpt&         c,              // location - center of search region
00527    double          screen_pix_rad, // search radius in screen pixels
00528    CSimplexFilter& filt            // tells what kind of simplex to look for
00529    )
00530 {
00531    Point2i hit;
00532 
00533    if (search(c, screen_pix_rad, filt, hit))
00534       return simplex(hit);
00535    return 0;
00536 }
00537 
00538 Bedge* 
00539 IDRefImage::find_neighbor(CNDCpt& p, Bedge* current, int radius) const 
00540 {
00541    // check neighbors, spiralling out from middle
00542    Point2i center = ndc_to_pix(p);
00543    Bedge* temp = 0;
00544    Point2i check;
00545    for (int rad = 0; rad <= radius; rad++) {
00546       for (int i = -rad; i <= rad; i++) {
00547          for (int j = -rad; j <= rad; j++) {
00548             if ((abs(i)==rad) || (abs(j)==rad)) {
00549                check = Point2i(center[0]+i, center[1]+j);
00550                if (pix_in_range(check)  &&
00551                    (temp = edge(check)) &&
00552                    (temp != current)
00553                    && (temp->patch() == current->patch()) && (temp->is_sil()))
00554                   return temp;
00555             }
00556          }
00557       }
00558    }
00559    
00560    return 0; // no neighbor found
00561 }
00562 
00563 
00564 //  ARRAY<Bedge*>
00565 //  IDRefImage::find_all_neighbors(CNDCpt& p, Patch* patch, int radius) const 
00566 //  {
00567 //     static ARRAY<Bedge*> neighbors(radius*radius);
00568 //     neighbors.clear();
00569 //     // find neighbors, spiralling out from middle
00570 //     Point2i center = ndc_to_pix(p);
00571 //     Bedge* temp = 0;
00572 //     Point2i check;
00573 //     for (int rad = 0; rad <= radius; rad++) {
00574 //        for (int i = -rad; i <= rad; i++) {
00575 //           for (int j = -rad; j <= rad; j++) {
00576 //              if ((abs(i) <= rad) || (abs(j) <= rad)) {
00577 //                 check = center + Vec2i(i,j);
00578 //                 if (!pix_in_range(check))
00579 //                    continue;
00580 //                 temp = edge(check);
00581 //                 if (!temp)
00582 //                    continue;
00583 //                 if ((temp->patch() == patch) && (temp->is_sil()))
00584 //                    neighbors.add_uniquely(temp);
00585 //              }
00586 //           }
00587 //        }
00588 //     }
00589    
00590 //     return neighbors; 
00591 //  }
00592 
00593 
00594 
00595 // XXX -- Is this change correct?  Original function is above.
00596 //        Removed seemingly unnecessary outermost for-loop.
00597 ARRAY<Bedge*>
00598 IDRefImage::find_all_neighbors(CNDCpt& p, Patch* patch, int radius) const 
00599 {
00600    Point2i center = ndc_to_pix(p);
00601 
00602    return find_all_neighbors(center, patch, radius);
00603 }
00604 
00605 ARRAY<Bedge*>
00606 IDRefImage::find_all_neighbors(Cpoint2i& center, Patch* patch, int radius) const 
00607 {
00608    static ARRAY<Bedge*> neighbors(radius*radius);
00609    neighbors.clear();
00610    // find neighbors, spiralling out from middle
00611    Bedge* temp = 0;
00612    Point2i check;
00613    for (int i = -radius; i <= radius; i++) {
00614       for (int j = -radius; j <= radius; j++) {
00615          check = center + Vec2i(i,j);
00616          if (!pix_in_range(check))
00617             continue;
00618          temp = edge(check);
00619          if (!temp)
00620             continue;
00621          if ((temp->patch() == patch) && (temp->is_sil()))
00622             neighbors.add_uniquely(temp);
00623       }
00624    }
00625    
00626    return neighbors; 
00627 }
00628 
00629 bool 
00630 IDRefImage::is_simplex_near(CNDCpt& p, const Bsimplex* simp, int radius) const
00631 {
00632    // check neighbors, spiralling (?) out from middle
00633    Point2i center = ndc_to_pix(p);
00634    Bsimplex* temp = 0;
00635    Point2i check;
00636    for (int rad = 0; rad <= radius; rad++) {
00637       for (int i = -rad; i <= rad; i++) {
00638          for (int j = -rad; j <= rad; j++) {
00639             if ((abs(i)==rad) || (abs(j)==rad)) {
00640                check = Point2i(center[0]+i, center[1]+j);
00641                if (pix_in_range(check) &&
00642                    (temp = simplex(check)) &&
00643                    (temp == simp))
00644                   return true;
00645             }
00646          }
00647       }
00648    }
00649    
00650    return false;
00651 }
00652 
00653 bool
00654 IDRefImage::is_patch_sil_edge_near(
00655    CNDCpt& ndc,
00656    const Patch* patch,
00657    int radius
00658    ) const
00659 {
00660    // check neighbors, spiralling (?) out from middle
00661    Point2i center = ndc_to_pix(ndc);
00662    Point2i check; 
00663    for (int rad = 0; rad <= radius; rad++) {
00664       for (int i = -rad; i <= rad; i++) {
00665          for (int j = -rad; j <= rad; j++) {
00666             if ((abs(i)==rad) || (abs(j)==rad)) {
00667                check = Point2i(center[0]+i, center[1]+j);
00668                if (is_patch_sil_edge(check, patch)) return true;
00669             }
00670          }
00671       }
00672    }
00673    return false;
00674 }
00675 
00676 Bface* 
00677 VisRefImage::get_face(CNDCpt& cur, double screen_rad) 
00678 {
00679    // Return the nearest Bface within the given screen region,
00680    // with a preference for front-facing Bfaces:
00681    
00682    Bface* ret = (Bface*)get_simplex(cur, screen_rad, FrontFacingBfaceFilter());
00683    return ret ? ret : (Bface*)get_simplex(cur, screen_rad, BfaceFilter());
00684 }
00685 
00686 Bface_list
00687 VisRefImage::get_faces(const PIXEL_list& pix, double screen_rad)
00688 {
00689    // Call get_face() on each screen point in sequence:
00690 
00691    Bface_list ret;
00692    for (int i=0; i<pix.num(); i++) {
00693       Bface* f = get_face(pix[i], screen_rad);
00694       if (f)
00695          ret.add_uniquely(f);
00696    }
00697    return ret;
00698 }
00699 
00700 
00701 Bface*          // Bface* at given subdivision level for a given screen point
00702 VisRefImage::get_face_bc (
00703    Wvec& bc,    // returned: barycentric coords of near point on face
00704    CNDCpt& ndc, // given screen point
00705    double rad   // search radius 
00706    ) 
00707 {
00708    // 1. Search the VisRefImage to find the nearest Bface
00709    //    within a radius of the given screen location.
00710    //    Get the face at currently drawn subdivision level.
00711    Bface* f = get_face(ndc, rad);
00712 
00713    // 2. Convert the screen location to a barycentric
00714    //    coordinate on the Bface.
00715    if (f)
00716       f->near_pt(ndc, bc);
00717 
00718    return f;
00719 }
00720 
00721 Bface*          // Bface* at given subdivision level for a given screen point
00722 VisRefImage::get_sub_face(
00723    int level,   // given subdivision level
00724    Wvec& bc,    // returned: barycentric coords of near point on face
00725    CNDCpt& ndc, // given screen point
00726    double rad   // search radius 
00727    ) 
00728 {
00729    Bface* f = get_face_bc(bc, ndc, rad);
00730 
00731    if (level == 0)
00732       return f;
00733    else if (f && LMESH::isa(f->mesh()))
00734       return ((Lface*)f)->bc_to_level(level, bc);
00735    else
00736       return 0;
00737 }
00738 
00739 Bface*          // Bface* at current mesh edit level for a given screen point
00740 VisRefImage::get_edit_face(
00741    Wvec& bc,    // returned: barycentric coords of near point on face
00742    CNDCpt& ndc, // given screen point
00743    double rad   // search radius 
00744    ) 
00745 {
00746    Bface* f = get_face_bc(bc, ndc, rad);
00747 
00748    if (f && LMESH::isa(f->mesh()))
00749       return ((Lface*)f)->bc_to_edit_level(bc);
00750    else
00751       return 0;
00752 }
00753 
00754 void
00755 IDRefImage::update()
00756 {
00757    glDrawBuffer(GL_BACK);
00758    glReadBuffer(GL_BACK);
00759 
00760    // disable lights
00761    glDisable(GL_LIGHTING);
00762    glDisable(GL_LIGHT0);
00763    glDisable(GL_LIGHT1);
00764 
00765    // set default state
00766    set_default_gl_state();
00767 
00768    glDisable(GL_COLOR_MATERIAL);
00769    glShadeModel(GL_FLAT);
00770 
00771    glViewport(0,0,_width,_height);
00772 
00773    glClearColor(0,0,0,0);
00774    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00775 
00776    draw_objects(VIEW::peek()->drawn());
00777 
00778    glReadPixels(0,0,_width,_height,_format,_type,_values);
00779 
00780    int w, h;
00781    VIEW_SIZE(w,h);
00782    glViewport(0,0,w,h);
00783 }
00784 
00785 /**********************************************************************
00786  * VisRefImage:
00787  **********************************************************************/
00788 
00789 // factory class for producing VisRefImages
00790 class VisRefImageFactory : public BaseVisRefImageFactory {
00791  public:
00792    virtual BaseVisRefImage* produce(CVIEWptr& v) { return new VisRefImage(v); }
00793 };
00794 
00795 VisRefImage::VisRefImage(CVIEWptr& v) :
00796    IDRefImage(v) 
00797 {
00798    reset();
00799    observe();
00800 }
00801 
00802 void
00803 VisRefImage::init()
00804 {
00805    if (!BaseVisRefImage::_factory)
00806       BaseVisRefImage::_factory = new VisRefImageFactory;
00807 }
00808 
00809 bool
00810 VisRefImage::need_update() 
00811 {
00812    // this custom scaling could be moved into RefImage.
00813    //  (It resizes the ref image to match the aspect
00814    //   ratio of the view and to keep the minimum side
00815    //   no longer than 256 pixels).
00816    int w, h;
00817    _view->get_size(w,h);
00818    double scale = 1.0;
00819    int ref_w = 256, ref_h = 256;
00820    int min_side = min(w,h);
00821    if (min_side <= 256) {
00822       ref_w = w;
00823       ref_h = h;
00824    } else {
00825       scale = min_side / 256.0;
00826       if (w > h)
00827          ref_w = (int)round(w/scale);
00828       else
00829          ref_h = (int)round(h/scale);
00830    }
00831 
00832    return (resize(ref_w,ref_h) || _dirty);
00833 }
00834 
00835 void 
00836 VisRefImage::debug(CNDCpt& p) const
00837 {
00838    cerr << "VisRefImage::debug: ndc: " << p;
00839    uint id = ndc_to_uint(p);
00840    cerr << ", uint: " << id;
00841    GLuint v = val(id);
00842    cerr << ", val: " << v;
00843    uint key = rgba_to_key(v);
00844    cerr << ", key: " << key;
00845    Bsimplex* s = Bsimplex::lookup(key);
00846    cerr << ", simplex: " << s;
00847    cerr << endl;
00848 }
00849 
00850 void
00851 VisRefImage::draw_objects(CGELlist& drawn) const
00852 {
00853    VIEWptr view = VIEW::peek();
00854 
00855    // setup projection matrix
00856    glMatrixMode(GL_PROJECTION);
00857    glLoadMatrixd(view->cam()->projection_xform().transpose().matrix());
00858 
00859    // get the camera position matrix
00860    Wtransf mat = view->cam()->xform().transpose();
00861 
00862    glMatrixMode(GL_MODELVIEW);
00863    for (int i=0; i < drawn.num(); i++) {
00864       glLoadMatrixd(mat.matrix());
00865       drawn[i]->draw_vis_ref();
00866    }
00867 }
00868 
00869 void 
00870 VisRefImage::observe() 
00871 {
00872    if (_view) {
00873       // BMESHobs:
00874       subscribe_all_mesh_notifications();
00875 
00876       // CAMobs:
00877       _view->cam()->data()->add_cb(this);
00878 
00879       // DISPobs:
00880       disp_obs();
00881 
00882       // EXISTobs:
00883       exist_obs();
00884 
00885       // XFORMobs:
00886       xform_obs();
00887 
00888       // FRAMEobs:
00889       WORLD::get_world()->schedule(this);
00890    }
00891 }
00892 
00893 void 
00894 VisRefImage::unobserve() 
00895 {
00896    if (_view) {
00897       // BMESHobs:
00898       unsubscribe_all_mesh_notifications();
00899 
00900       // CAMobs:
00901       _view->cam()->data()->rem_cb(this);
00902 
00903       // DISPobs:
00904       unobs_display();
00905 
00906       // EXISTobs:
00907       unobs_exist();
00908 
00909       // XFORMobs:
00910       unobs_xform();
00911 
00912       // FRAMEobs:
00913       WORLD::get_world()->unschedule(this);
00914    }
00915 }
00916 
00917 int
00918 VisRefImage::tick()
00919 {
00920    if (_countup++ > 4 && _dirty)
00921       update();
00922    return 1;
00923 }
00924 
00925 uint
00926 IDRefImage::key_to_rgba2(uint key) 
00927 {
00928    // Convert a Bsimplex "key" value to an RGBA value. Assumes the
00929    // frame buffer does not store alpha. Thus the key should not store
00930    // any info in the highest-order byte. On non-intel platforms, we
00931    // shift the key value left by 8 bits, resulting in an RGBA value
00932    // with no info in the lowest order byte. This value can be written
00933    // to the frame buffer and later read back (as long as 8 bits is
00934    // allocated per color component as is usual). After shifting the
00935    // result 8 bits to the right, we end up with the original key
00936    // value. This is done in rgba_to_key(), below.
00937 
00938    // XXX -
00939    //   Handles other than 8 bits per component
00940    //   only on Intel platforms (pending fixes).
00941 
00942 #if defined(WIN32) || defined(i386)
00943 
00944    // Intel platform: colors strored as ABGR, no shift needed
00945    if (_nonstandard_bits) {
00946       // bits per component is other than 8.
00947       //
00948       // divide up the info in 'key' into 3 groups with the same
00949       // number of bits as allotted to red, green, and blue color
00950       // components. arrange the 3 groups into 3 bytes of a 4-byte
00951       // unsigned int, which can be fed to OpenGL using
00952       // glColor4ubv().
00953 
00954       // E.g., if bits for red, green and blue components are 5, 6, 5,
00955       // respectively, then we want to rearrange the bits in 'key' as
00956       // follows:
00957       //
00958       // ******** ******** bbbbbggg gggrrrrr          key
00959       //
00960       //                  |
00961       //                  |
00962       //                  V
00963       //
00964       // ******** bbbbb*** gggggg** rrrrr***         rgba
00965       //    A        B        G        R
00966 
00967       // masks to select the 3 chunks of data within 'key':
00968       static uint mask_r = ((1<<_red_bits)   - 1);
00969       static uint mask_g = ((1<<_green_bits) - 1) << (_red_bits);
00970       static uint mask_b = ((1<<_blue_bits)  - 1) << (_red_bits + _green_bits);
00971 
00972       // shifts needed to place the blue and green chunks at the
00973       // proper position in the unsigned int:
00974       static int shift_r =  8 - _red_bits;
00975       static int shift_g = 16 - _red_bits - _green_bits;
00976       static int shift_b = 24 - _red_bits - _green_bits - _blue_bits;
00977 
00978       return (((key & mask_r) << shift_r) |
00979               ((key & mask_g) << shift_g) |
00980               ((key & mask_b) << shift_b));
00981    }
00982 
00983    // (Intel)
00984    // No fancy bit-fussing needed
00985    return key;
00986 
00987 #else
00988    // non-Intel platform:
00989    // Colors stored as RGBA, shift data past A on the assumption
00990    // that the framebuffer doesn't actually store alpha:
00991 
00992    // XXX - should handle bits per component other than 8
00993 
00994    return ((key << 8) | 0xff);
00995 
00996 #endif
00997 }
00998 
00999 uint 
01000 IDRefImage::rgba_to_key2(uint rgba) 
01001 {
01002    // companion method for key_to_rgba() -- see comment above
01003 
01004 #if defined(WIN32) || defined(i386)
01005    if (_nonstandard_bits) {
01006       // fewer than 8 bits per component.
01007       //
01008       // select out valid bits and repack them into the 'key'
01009       // format. (i.e. the valid bits put back together to form an
01010       // integer value).
01011 
01012       // ******** bbbbb*** gggggg** rrrrr***         rgba
01013       //    A        B        G        R
01014       //
01015       //                  |
01016       //                  |
01017       //                  V
01018       //
01019       // ******** ******** bbbbbggg gggrrrrr          key
01020 
01021 
01022       // masks for selecting the valid bits where they lay within the
01023       // rgba unsigned int:
01024       static uint mask_r = ((1<<_red_bits)  -1) << ( 8 - _red_bits);
01025       static uint mask_g = ((1<<_green_bits)-1) << (16 - _green_bits);
01026       static uint mask_b = ((1<<_blue_bits) -1) << (24 - _blue_bits);
01027 
01028       // shifts needed to get the bits into position in the 'key'
01029       // unsigned int:
01030       static int shift_r =  8 - _red_bits;
01031       static int shift_g = 16 - _red_bits - _green_bits;
01032       static int shift_b = 24 - _red_bits - _green_bits - _blue_bits;
01033        
01034       return (((rgba & mask_r) >> shift_r) |
01035               ((rgba & mask_g) >> shift_g) |
01036               ((rgba & mask_b) >> shift_b));
01037                 
01038    }
01039 
01040    // Intel:
01041    //   Colors stored as ABGR, no shift needed.
01042    //   But If alpha is not stored in framebuffer, 
01043    //   have to  mask away those garbage bits:
01044    if (_alpha_bits == 8)
01045       return rgba;
01046    else
01047       return (rgba & 0xffffff);
01048 
01049 #else
01050 
01051    // Non-Intel:
01052 
01053    // XXX - should handle nonstandard bits here
01054    // colors stored as RGBA. undo the shift in key_to_rgba() above:
01055    return (rgba >> 8);
01056 #endif
01057 }
01058 
01059 /**********************************************************************
01060  * TexMemRefImage: 
01061  **********************************************************************/
01062 static bool debug_tmri = Config::get_var_bool("DEBUG_TEX_MEM_REF_IMAGE",false);
01063 
01064 TexMemRefImage::TexMemRefImage(
01065    CVIEWptr& v,
01066    RefImageClient::ref_img_t img_type) :
01067    _view(v),
01068    _ref_img_type(img_type),
01069    _texture(0)
01070 {
01071    _texture = new TEXTUREgl();
01072    assert(_texture);
01073 
01074    // let's try not doing power-of-2 expanding:
01075    _texture->set_expand_image(false);
01076 
01077    _texture->set_tex_unit(TexUnit::REF_IMG + GL_TEXTURE0);
01078    _texture->set_mipmap(false);
01079    _texture->set_tex_fn(GL_REPLACE);
01080 }
01081 
01082 bool
01083 TexMemRefImage::resize(const Point2i& dims)
01084 {
01085    // resize to new dimensions:
01086    assert(_texture);
01087 
01088    // See if the image needs to be resized. This is needed if the
01089    // view's width or height are larger than the image's width or height:
01090    const Image& img = _texture->image();
01091    if (debug_tmri && (static_cast<int>(img.width())  != dims[0] ||
01092                       static_cast<int>(img.height()) != dims[1])) {
01093       cerr << "TexMemRefImage::resize: changing size from"
01094            << img.width() << "x" << img.height() << " to "
01095            << dims[0] << "x" << dims[1] << endl;
01096    }
01097    return _texture->image().resize(dims[0],dims[1]);
01098 }
01099 
01100 TexMemRefImage* 
01101 TexMemRefImage::lookup(CVIEWptr& v)
01102 {
01103    if (!v) {
01104       err_msg( "TexMemRefImage::lookup: error -- view is nil");
01105       return 0;
01106    }
01107    if (!v->impl()) {
01108       err_msg( "TexMemRefImage::lookup: error -- view->impl() is nil");
01109       return 0;
01110    }
01111 
01112    // hash on the view implementation rather than the view itself
01113    long key = (long)v->impl();
01114    TexMemRefImage* ret = (TexMemRefImage*) _hash.find(key);
01115    if (!ret && (ret = new TexMemRefImage(v)))
01116       _hash.add(key, (void *)ret);
01117    return ret;
01118 }
01119 
01120 void
01121 TexMemRefImage::update()
01122 {
01123    glDrawBuffer(GL_BACK);
01124    glReadBuffer(GL_BACK);
01125 
01126    VIEWptr view = VIEW::peek();
01127 
01128    glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT);
01129 
01130    // set up lights
01131    view->setup_lights();
01132 
01133    // set default state
01134    set_default_gl_state();
01135 
01136    glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
01137    glEnable(GL_COLOR_MATERIAL);
01138    glShadeModel(GL_SMOOTH);
01139   
01140    glClearColor(1,1,1,1);
01141    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
01142 
01143    draw_objects(view->drawn());
01144 
01145    read_FB();
01146 
01147    glPopAttrib();
01148 }
01149 
01150 inline bool
01151 is_proper_3d_object(CGELptr& gel)
01152 {
01153    return gel && gel->bbox().valid();
01154 }
01155 
01156 void
01157 TexMemRefImage::draw_objects(CGELlist& drawn) const
01158 {
01159    assert(_view);
01160 
01161    //sort into two groups 
01162    GELlist _blended;
01163    _blended.clear();
01164    GELlist _opaque;
01165    _opaque.clear();
01166    
01167    for (int i=0; i < drawn.num(); i++ ) {
01168       if (!drawn[i]->is_3D()) {
01169          ; // skip it
01170       } else if (drawn[i]->can_do_halo() && GEOM::do_halo_ref()) {
01171          _blended += drawn[i];
01172       } else {
01173          _opaque  += drawn[i];
01174       }
01175    }
01176    
01177    _blended.sort(GL_VIEW::depth_compare);
01178 
01179    // setup projection matrix
01180    glMatrixMode(GL_PROJECTION);
01181    glPushMatrix();
01182    glLoadMatrixd(_view->cam()->projection_xform().transpose().matrix());
01183 
01184    glMatrixMode(GL_MODELVIEW);
01185    glPushMatrix();
01186   
01187    // draw the two groups
01188 
01189    // get the viewing matrix
01190    Wtransf mat = _view->cam()->xform().transpose();
01191 
01192    for (int i=0; i < _opaque.num(); i++) {
01193       glLoadMatrixd(mat.matrix());
01194       _opaque[i]->draw_ref_img(_ref_img_type);
01195    }
01196 
01197    glEnable(GL_BLEND);                                // GL_ENABLE_BIT
01198    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_COLOR_BUFFER_BIT
01199    for (int i=0; i < _blended.num(); i++) {
01200       glLoadMatrixd(mat.matrix());
01201       _blended[i]->draw_ref_img(_ref_img_type);
01202    }
01203 
01204    // restore projection matrix
01205    glMatrixMode(GL_PROJECTION);
01206    glPopMatrix();
01207 
01208    // restore modelview matrix
01209    glMatrixMode(GL_MODELVIEW);
01210    glPopMatrix();
01211 }
01212 
01213 void
01214 TexMemRefImage::read_FB()
01215 {
01216    // ensure dimensions match current window size:
01217    resize(_view->cur_size());
01218 
01219    glPushAttrib(GL_ENABLE_BIT);
01220 
01221    // Specify texture
01222    _texture->apply_texture();   // GL_ENABLE_BIT
01223 
01224    glReadBuffer(GL_BACK);
01225 
01226    const Image& img = _texture->image();
01227 
01228    // Copies the frame buffer into a texture in gpu texture memory.
01229    glCopyTexImage2D(
01230       GL_TEXTURE_2D,  // The target to which the image data will be changed.
01231       0,              // Level of detail, 0 is base detail
01232       GL_RGBA,        // internal format
01233       0,              // x-coord of lower left corner of the window
01234       0,              // y-coord of lower left corner of the window
01235       img.width(),    // width - must be a power of 2
01236       img.height(),   // height - must be a power of 2
01237       0);             // border size, must be 0 or 1
01238 
01239    glPopAttrib();
01240 }
01241 
01242 void
01243 TexMemRefImage::draw_FB()
01244 {
01245    // load identity for model matrix
01246    glMatrixMode(GL_MODELVIEW);
01247    glPushMatrix();
01248    glLoadIdentity();
01249 
01250    // set up to draw in XY coords:
01251    glMatrixMode(GL_PROJECTION);
01252    glPushMatrix();
01253    glLoadMatrixd(VIEW::peek()->xypt_proj().transpose().matrix());
01254 
01255    // set opengl state:
01256    glPushAttrib(GL_ENABLE_BIT);
01257    glDisable(GL_LIGHTING);
01258    glDisable(GL_DEPTH_TEST); // prevents depth testing AND writing
01259    glDisable(GL_BLEND); //so it doesn't bleed stuff from the front buffer through the low alpha areas
01260 
01261    // Draw a quad with our texture on it
01262    _texture->apply_texture(); // GL_ENABLE_BIT
01263 
01264    GLfloat t = 1;
01265    glColor4f(1, 1, 1, 1);
01266    glBegin(GL_QUADS);
01267    // draw vertices in CCW order starting at bottom left:
01268    GLenum unit = _texture->get_tex_unit();
01269    glMultiTexCoord2f(unit, 0, 0); glVertex2f(-t, -t);
01270    glMultiTexCoord2f(unit, 1, 0); glVertex2f( t, -t);
01271    glMultiTexCoord2f(unit, 1, 1); glVertex2f( t,  t);
01272    glMultiTexCoord2f(unit, 0, 1); glVertex2f(-t,  t);
01273    glEnd();
01274 
01275    // restore state:
01276    glPopAttrib();
01277 
01278    // restore projection matrix
01279    glMatrixMode(GL_PROJECTION);
01280    glPopMatrix();
01281 
01282    // restore modelview matrix
01283    glMatrixMode(GL_MODELVIEW);
01284    glPopMatrix();
01285 }
01286 
01287 // end of file ref_image.C

Generated on Mon Sep 18 11:39:33 2006 for jot by  doxygen 1.4.4