Tekkotsu Homepage
Demos
Overview
Downloads
Dev. Resources
Reference
Credits

Graphics.cc

Go to the documentation of this file.
00001 #include "Graphics.h"
00002 #include "FilterBankGenerator.h"
00003 
00004 using namespace std;
00005 
00006 //! empty definition of macro for checking for any exceeding of image's memory boundaries
00007 //#define CHKBOUNDS(p) {}
00008 
00009 // ! check memory boundaries of image, first that we are after the start of the image, second that we are before the end of the image, and third that we are within a valid row (in case of interleaved rows), fourth that we are within a valid column (interleaved pixels)
00010 #define CHKBOUNDS(p,ERR_F) { \
00011   unsigned int rowoffset=(p-img)-(p-img)/yInc*yInc; \
00012   if(p<img || p>=img+h*yInc || rowoffset>=w*xInc || rowoffset/xInc*xInc!=rowoffset) { \
00013     cout << "Graphics Bad draw! line:" << __LINE__ << " frame=" << (gen!=NULL?gen->getFrameNumber():0) << ' '  /*<< (void*)p << '-' << (void*)img << '='*/ << (int)(p-img) << " w=" << w << " xInc=" << xInc << " h=" << h << " yInc=" << yInc << endl; \
00014     ERR_F; \
00015   } \
00016 }
00017 
00018 
00019 Graphics::Graphics(FilterBankGenerator& fbg, unsigned int layer, unsigned int channel)
00020   : gen(&fbg), genLayer(layer), genChan(channel), img(NULL), w(0), h(0), xInc(0), yInc(0), c(0)
00021 {
00022   updateFBG();
00023 }
00024 
00025 Graphics::Graphics(unsigned char * base, unsigned int width, unsigned int height, unsigned int interval, unsigned int stride)
00026   : gen(NULL), genLayer(), genChan(), img(base), w(width), h(height), xInc(interval), yInc(stride), c(0)
00027 {}
00028 
00029 void Graphics::updateFBG() {
00030   if(gen==NULL)
00031     return;
00032   img=gen->getImage(genLayer,genChan);
00033   w=gen->getWidth(genLayer);
00034   h=gen->getHeight(genLayer);
00035   xInc=gen->getIncrement(genLayer);
00036   yInc=gen->getStride(genLayer);
00037 }
00038 
00039 void Graphics::drawRect(int x, int y, int width, int height) {
00040   if(img==NULL)
00041     return;
00042   if(width<0) {
00043     x+=width;
00044     width=-width;
00045   }
00046   if(height<0) {
00047     y+=height;
00048     height=-height;
00049   }
00050   if(x>=(int)w || y>=(int)h || x+width<0 || y+height<0) //completely out of bounds
00051     return;
00052   if(x<0 && y<0 && x+width>=(int)w && y+height>=(int)h) //out of bounds (circumscribed)
00053     return;
00054   unsigned int left=x>0?x:0;
00055   unsigned int top=y>0?y:0;
00056   unsigned int right=( (x+width>=(int)w) ? w : x+width); //not inclusive
00057   unsigned int bot=( (y+height>=(int)h) ? h : y+height); //not inclusive
00058   //left vertical
00059   if(x>=0) {
00060     unsigned char * p=img+top*yInc+left*xInc;
00061     unsigned char * end=img+bot*yInc+left*xInc;
00062     while(p!=end) {
00063       CHKBOUNDS(p,return);
00064       *p=c;
00065       p+=yInc;
00066     }
00067   }   
00068   //top horizontal
00069   if(y>=0) {
00070     unsigned char * p=img+top*yInc+left*xInc;
00071     unsigned char * end=img+top*yInc+right*xInc;
00072     while(p!=end) {
00073       CHKBOUNDS(p,return);
00074       *p=c;
00075       p+=xInc;
00076     }
00077   }
00078   //right vertical
00079   if(right<w && left!=right) {
00080     unsigned char * p=img+top*yInc+right*xInc;
00081     unsigned char * end=img+bot*yInc+right*xInc;
00082     while(p!=end) {
00083       CHKBOUNDS(p,return);
00084       *p=c;
00085       p+=yInc;
00086     }
00087   }   
00088   //bottom horizontal
00089   if(bot<h && top!=bot) {
00090     unsigned char * p=img+bot*yInc+left*xInc;
00091     unsigned char * end=img+bot*yInc+right*xInc;
00092     while(p!=end) {
00093       CHKBOUNDS(p,return);
00094       *p=c;
00095       p+=xInc;
00096     }
00097   }
00098   //bottom right corner
00099   if(right<w && bot<h) {
00100     unsigned char * p=img+bot*yInc+right*xInc;
00101     CHKBOUNDS(p,return);
00102     *p=c;
00103     return;
00104   }
00105 }
00106 void Graphics::drawRect(float x, float y, float width, float height) {
00107   unsigned int left,top,right,bot;
00108   getPixelCoordinates(left,top,x,y);
00109   getPixelCoordinates(right,bot,x+width,y+height);
00110   drawRect((int)left,(int)top,(int)(right-left),(int)(bot-top));
00111 }
00112 
00113 /*! @todo I think this could be a little faster by writing two cases -- one that
00114  *  handles mostly-vertical lines, and one that handles mostly-horizontal ones.
00115  *  Then the primary loop could be over integer coordinates along that axis, and
00116  *  only the position along the other axis would have to be calculated as
00117  *  floating point */
00118 void Graphics::drawLine(int ix1, int iy1, int ix2, int iy2) {
00119   // the "right" way, allows full range of unsigned int for width
00120   //if(ix1<0 && ix2<0 || iy1<0 && iy2<0 || ix1>0 && ix2>0 && (unsigned int)ix1>=w && (unsigned int)ix2>=w || iy1>0 && iy2>0 && (unsigned int)iy1>=h && (unsigned int)iy2>=h)
00121   //  return; //completely outside visible region
00122 
00123   // the "realistic way" saves some CPU
00124   if(ix1<0 && ix2<0 || iy1<0 && iy2<0 || ix1>=(int)w && ix2>=(int)w || iy1>=(int)h && iy2>=(int)h)
00125     return; //completely outside visible region
00126 
00127   float x1=ix1, y1=iy1, x2=ix2, y2=iy2;
00128   float width=x2-x1;
00129   float height=y2-y1;
00130   bool clipped=false;
00131   if(width!=0) {
00132     float slope=height/width;
00133     if(x1<x2) {
00134       if(x1<0) {
00135         y1-=x1*slope;
00136         x1=0;
00137         clipped=true;
00138       }
00139       if(x2>=w) {
00140         y2-=(x2-(w-1))*slope;
00141         x2=w-1;
00142         clipped=true;
00143       }
00144     } else {
00145       if(x2<0) {
00146         y2-=x2*slope;
00147         x2=0;
00148         clipped=true;
00149       }
00150       if(x1>=w) {
00151         y1-=(x1-(w-1))*slope;
00152         x1=w-1;
00153         clipped=true;
00154       }
00155     }
00156   }
00157   if(clipped) {
00158     if(x1<0 && x2<0 || y1<0 && y2<0 || x1>=w && x2>=w || y1>=h && y2>=h)
00159       return; //completely outside visible region
00160     clipped=false;
00161   }
00162   if(height!=0) {
00163     float invslope=width/height;
00164     if(y1<y2) {
00165       if(y1<0) {
00166         x1-=y1*invslope;
00167         y1=0;
00168         clipped=true;
00169       }
00170       if(y2>=h) {
00171         x2-=(y2-(h-1))*invslope;
00172         y2=h-1;
00173         clipped=true;
00174       }
00175     } else {
00176       if(y2<0) {
00177         x2-=y2*invslope;
00178         y2=0;
00179         clipped=true;
00180       }
00181       if(y1>=h) {
00182         x1-=(y1-(h-1))*invslope;
00183         y1=h-1;
00184         clipped=true;
00185       }
00186     }
00187   }
00188   if(clipped) {
00189     if(x1<0 && x2<0 || y1<0 && y2<0 || x1>=w && x2>=w || y1>=h && y2>=h)
00190       return; //completely outside visible region
00191     clipped=false;
00192   }
00193   width=x2-x1;
00194   height=y2-y1;
00195   int aw=abs((int)width);
00196   int ah=abs((int)height);
00197   int d=aw>ah?aw:ah;
00198   float dx=width/d;
00199   float dy=height/d;
00200   for(float x=x1,y=y1;d>0;d--,x+=dx,y+=dy) {
00201     unsigned char * p=(img+((int)y)*yInc+((int)x)*xInc);
00202     CHKBOUNDS(p,continue);
00203     *p=c;
00204   }
00205   unsigned char * p=(img+((int)y2)*yInc+((int)x2)*xInc);
00206   CHKBOUNDS(p,return);
00207   *p=c;
00208 }
00209 void Graphics::drawLine(float x1, float y1, float x2, float y2) {
00210   unsigned int px1,py1,px2,py2;
00211   getPixelCoordinates(px1,py1,x1,y1);
00212   getPixelCoordinates(px2,py2,x2,y2);
00213   drawLine((int)px1,(int)py1,(int)px2,(int)py2);
00214 }
00215 
00216 void Graphics::getPixelCoordinates(unsigned int& px, unsigned int& py, float x, float y) const {
00217   if(gen!=NULL) {
00218     gen->getPixelCoordinates(px,py,x,y,genLayer);
00219   } else {
00220     //note width sets the scale for both, so coordinate system is square... is good? I'm up for debate.
00221     px=(unsigned int)((w-1)*(x+1)/2+.5f); //+.5 to round to nearest
00222     float aspect=h/(float)w;
00223     py=(unsigned int)((h-1)*(y+aspect)/(aspect*2)+.5f); //+.5 to round to nearest
00224   }
00225 }
00226   
00227 void Graphics::getRealCoordinates(float& x, float& y, unsigned int px, unsigned int py) const {
00228   if(gen!=NULL) {
00229     gen->getRealCoordinates(x,y,px,py,genLayer);
00230   } else {
00231     //note width sets the scale for both, so coordinate system is square... is good? I'm up for debate.
00232     x=px/(float)(w-1)*2-1;
00233     float aspect=h/(float)w;
00234     y=py/(float)(h-1)*aspect*2-aspect;
00235   }
00236 }
00237 
00238 /*! @file
00239  * @brief 
00240  * @author ejt (Creator)
00241  *
00242  * $Author: ejt $
00243  * $Name: tekkotsu-4_0 $
00244  * $Revision: 1.5 $
00245  * $State: Exp $
00246  * $Date: 2006/07/03 01:54:58 $
00247  */

Tekkotsu v4.0
Generated Thu Nov 22 00:54:53 2007 by Doxygen 1.5.4