home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C++ / Snippets / New Venus / src / view_2d.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-05  |  5.1 KB  |  143 lines  |  [TEXT/CWIE]

  1. /*
  2.  ***********************************************************************
  3.  *
  4.  *            Displaying a full-index-color image as a custom dialog item
  5.  *
  6.  ***********************************************************************
  7.  */
  8.  
  9. #include "image.h"
  10. #include "ImageViews.h"
  11. #include <Palettes.h>
  12.  
  13.                                 // Kind of a formal constructor, merely an initialization
  14. ImageView::ImageView(const IMAGE& _image)
  15.     : OffScreenBuffer(_image,elevation_color_CLUT_id), image(_image),
  16.       viewer_pos(110,128, 1<<14,0)
  17. {
  18.                         // Move pixels from IMAGE to a off-screen pixmap
  19.                         // Note that the rows of pixmap may be padded, by
  20.                         // as much as off_to_next_row bytes. So we need
  21.                         // to skip over the padding as we move pixels row
  22.                         // by row
  23.   class ImageToPixMap : public PixelPrimAction
  24.   {
  25.     PixMapHandle pixmap;
  26.     unsigned char * pixp;
  27.     const card height, width, off_to_next_row;
  28.     card  curr_row, curr_col;
  29.     void operation(GRAY& pixel)        // put a pixel to pixmap[row,col]
  30.     {
  31.       *pixp++ = pixel;
  32.       if( ++curr_col >= width )
  33.         curr_col = 0, curr_row++, pixp += off_to_next_row;
  34.     }
  35.     public:
  36.     ImageToPixMap(OffScreenBuffer& buffer)
  37.         : pixmap(buffer.get_pixmap()),
  38.           height(buffer.height()),
  39.           width(buffer.width()),
  40.           off_to_next_row(buffer.bytes_per_row()-buffer.width()),
  41.           curr_row(0), curr_col(0)
  42.         {
  43.           assert( LockPixels(pixmap) );
  44.           pixp = (unsigned char *)GetPixBaseAddr(pixmap);
  45.         }
  46.         ~ImageToPixMap(void)
  47.         { 
  48.           assert( curr_row == height && curr_col == 0 );
  49.           UnlockPixels(pixmap); pixmap = 0;
  50.         }
  51.   };
  52.   ((IMAGE&)image).apply(ImageToPixMap(*this));
  53. }
  54.  
  55.                                 // This is a real constructor, but called late
  56. void ImageView::bind(const ModelessDialog& the_dialog, const int item_no)
  57. {
  58.   UserItem::bind(the_dialog,item_no);
  59.   PmForeColor(255);
  60. }
  61.  
  62.                                 // Draw a plane mark on the map indicating the view point
  63.                                 // and the gaze direction
  64.                                 // We assume the the grafport is set up properly
  65.                                 // and that |g| = 1<<14
  66. void ImageView::draw_mark(void)
  67. {
  68.   PenSize(1,1);
  69.   MoveTo(viewer_pos.xe - (viewer_pos.gx>>13) + rect.left, // draw a vector in the direction
  70.            viewer_pos.ye - (viewer_pos.gy>>13) + rect.top); // of a gaze
  71.   Line(viewer_pos.gx>>11,viewer_pos.gy>>11);
  72.   MoveTo(viewer_pos.xe - (viewer_pos.gy>>13) + rect.left, // draw a crossbar in the perpendicular
  73.            viewer_pos.ye + (viewer_pos.gx>>13) + rect.top); // direction, that is, (gy,-gx)
  74.   Line(viewer_pos.gy>>12,-(viewer_pos.gx>>12));
  75.  
  76.                                 // Erase the mark of the plane off the map
  77.                                 // by redrawing a corresponding rectange of the map
  78. void ImageView::undraw_mark(void)
  79. {
  80.   Rect map_rect = {viewer_pos.ye-4,viewer_pos.xe-4,viewer_pos.ye+4,viewer_pos.xe+4};
  81.   Rect where_rect = map_rect;
  82.   where_rect.left += rect.left; where_rect.right += rect.left;
  83.   where_rect.top += rect.top;   where_rect.bottom += rect.top;
  84.   OffScreenBuffer::draw(where_rect,map_rect);
  85. }
  86.  
  87.                                 // Initialize the observer's position and prepare for
  88.                                 // circling aroung (by setting up the radius and
  89.                                 // computing the center)
  90.                                 // Note, vector g is perpendicular to the radius,
  91.                                 // so radius vector is r=(gy,-gx). Then the center
  92.                                 // C = E - r = (xe-radius*gy/|g|,ye+radius*gx/|g|)
  93. ViewerPosition::ViewerPosition(const int _xe, const int _ye, const int _gx, const int _gy)
  94.       : xe(_xe), ye(_ye), gx(_gx), gy(_gy), g_per_rad((float)g_unit/flying_radius)
  95. {
  96.   assert( gx*gx + gy*gy == g_unit*g_unit );            // Just to test our assumptions
  97.   xc = xe - ((flying_radius * gy)>>14);
  98.   yc = ye + ((flying_radius * gx)>>14);
  99.   rx = xe - xc; ry = ye - yc;
  100. }
  101.  
  102.  
  103.                             // Perform one step of circling around, that is, rotate a vector
  104.                             // (xe-xc, ye-yc) to become
  105.                             // (1  -s    )  (xe-xc)
  106.                             // (s  1-s^2 )  (ye-yc)
  107.                             // where 's' is a rotation constant (sine of the rotation angle
  108.                             // to be precise). It can be any number within [-1,1], though
  109.                             // it's better be small. Note that the determinant of the matrix
  110.                             // is exactly 1, no matter what s is. That is, even repeated application
  111.                             // of the matrix would not cause size distortions.
  112.                             // The formulas could be written in a better way: 
  113.                             // if r' = rotate(r=E-C) then
  114.                             // r'x = rx - s*ry
  115.                             // r'y = s*r'x + ry
  116.                             // The gaze vector has to be corrected, too
  117.                             // g' = |g|*(-r'y,r'x)/r
  118.                             // to keep it orthogonal to r'=CE' (note, |r'|=|r|=r)
  119.                             // Yes, we have to use floting point here. But it's not that big
  120.                             // deal on PowerPC. Animation is way too fast anyway.
  121. void ViewerPosition::do_one_turn(void)
  122. {
  123.   const float s = 0.04;
  124.   rx -= s*ry;                    // Do rotation
  125.   ry += s*rx;                    // note, it's new rx we're using here, see formulas above
  126.   gx = (int)(-ry*g_per_rad);
  127.   gy = (int)(rx*g_per_rad);
  128.   xe = xc + (int)rx; ye = yc + (int)ry;
  129.  // _error("correction factor %d, rpx %d, rpy %d, new %d, %d",corr_factor,rpx,rpy,new_xe,new_ye);
  130.  
  131.   if( gx < 2 && gx > -2 )            // Do recovery to compensate for the lost precision
  132.   {
  133.     gx = 0;
  134.     if( gy > 0 )
  135.       gy = g_unit, xe = xc + flying_radius, rx = flying_radius;
  136.     else
  137.       gy = -g_unit, xe = xc - flying_radius, rx = -flying_radius;
  138.     ye = yc, ry = 0; 
  139.   }
  140. }
  141.  
  142.