In this code, we are introduced couple of new concepts for drawing pixels on the screen. First of all in the header of the application we added another line:
unsigned short gSquares[640*2][480*2];
This is a 2d array that is going to hold our distance values between two points (one of them is going to be mouse loc and the other is pixel on the window.) Second our drawtobuffer function is introduced with new variables and functions eventually. We have x,y values which is going to be values of mouse h and v. mousepoint pointer as we did have in first week example, we are introduced to new vars from now on: The rowBytes field of the bitmap contains the width of a row of the image in bytes.
void DrawToBuffer(void) { // this is where we actually set our pixels long x , y; Point mousepoint; unsigned short rowBytes,distance; Ptr PixMapBase; PixMapHandle ourPixmap; unsigned char R,G,B; GetMouse(&mousepoint); ourPixmap=GetGWorldPixMap(ourBuffer); // getting the pixel map of our buffer GWorld so that we can access the pixels rowBytes = ((**(ourPixmap)).rowBytes) & 0x7fff; // getting the number of bytes in each row of the pixel map. This is then used to // calculate the location in memory of specific pixels PixMapBase = GetPixBaseAddr(ourPixmap ); // getting the base address in memory of the begining of the pixel data if (mousepoint.h<50) mousepoint.h=50; // Checking that we are at least 50 pixels into the window, this will insure if (mousepoint.v<50) mousepoint.v=50; // that we are not trying to access pixels in memory that are outside of our if (mousepoint.h> 640-50) mousepoint.h=640-50; // pixelmap , which would cause it to crash. if (mousepoint.v>480-50) mousepoint.v=480-50; for(x=mousepoint.h-50;x<mousepoint.h+50;x++){ for(y=mousepoint.v-50;y<mousepoint.v+50;y++){ distance = gSquares[640+(x-mousepoint.h)][480+(y-mousepoint.v)]; // getting the distance from the mouse to the pixels using our squares[][] array if (distance < 50) { R = distance+mousepoint.h; // giving R,G and B some values that change with the distance from the mouse G = distance+mousepoint.v; B = mousepoint.h; ourSetPixel(x,y,R,G,B,rowBytes,PixMapBase); // calling our method that set individual pixels and expects : X coordinate of the pixel, // y coordinate of the pixel, R value, G value, B value, the number of bytes // in each row of the pixel map, the base address in memory of the begining of the pixel data } } } }
After we get x coordinate of pixel, y coordinate of pixel, R,G,B value the number of bytes in each row of the pixel map, and the base address in memory of the beginning of the pixel data we pass those as arguments to ourSetPixel function. Here is the definition of the function:
void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase){ Ptr AdressOfRed; AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1; *(AdressOfRed)=R; *(AdressOfRed+1)=G; *(AdressOfRed+2)=B; }
AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1;
This line gives us the actual memory place of Red in the pixel. The formula to get the location of an actual pixel in a 2d array is this: width * y+x. Since we have ARGB in each pixel 8×4 = 32bit, we need to extract the second element which is going to be the red. That’s why we multiply it by 4 and add 1 to it.
The rest of the code is more or less the same. In the initialization function we run two for loops to get the distance between two pixels for every other pixel on the window. We are going to use this as our “display table” for later:
for(x=-640;x<640;x++){// repeating for all posible conditions -640 to 640 and -480 to 480 for(y=-480;y<480;y++){ gSquares[x+640][y+480] = sqrt(x*x+y*y); // calculating all distances and palcing in a global 2D array , this way we only }// calculate the square root once instead of every frame. }
void Initialize(void); // function prototypes void DrawLine( void ); void doEventLoop( void ); void DrawToBuffer(void); void CopyToWindow (void); int ourRandom( int min, int max ); void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase); //globals WindowPtr ourWindow; Rect windRect; GWorldPtr ourBuffer; int count=0; unsigned short gSquares[640*2][480*2]; void DrawToBuffer(void) // this is where the interesting stuff happens, this is where we actually set our pixels { long x , y; Point mousepoint; unsigned short rowBytes,distance; Ptr PixMapBase; PixMapHandle ourPixmap; unsigned char R,G,B; GetMouse(&mousepoint); ourPixmap=GetGWorldPixMap(ourBuffer); // getting the pixel map of our buffer GWorld so that we can access the pixels rowBytes = ((**(ourPixmap)).rowBytes) & 0x7fff; // getting the number of bytes in each row of the pixel map. This is then used to // calculate the location in memory of specific pixels PixMapBase = GetPixBaseAddr(ourPixmap ); // getting the base address in memory of the begining of the pixel data if (mousepoint.h<50) mousepoint.h=50; // Checking that we are at least 50 pixels into the window, this will insure if (mousepoint.v<50) mousepoint.v=50; // that we are not trying to access pixels in memory that are outside of our if (mousepoint.h> 640-50) mousepoint.h=640-50; // pixelmap , which would cause it to crash. if (mousepoint.v>480-50) mousepoint.v=480-50; for(x=mousepoint.h-50;x<mousepoint.h+50;x++){ for(y=mousepoint.v-50;y<mousepoint.v+50;y++){ distance = gSquares[640+(x-mousepoint.h)][480+(y-mousepoint.v)]; // getting the distance from the mouse to the pixels using our squares[][] array if (distance < 50){ R = distance+mousepoint.h; // giving R,G and B some values that change with the distance from the mouse G = distance+mousepoint.v; B = mousepoint.h; ourSetPixel(x,y,R,G,B,rowBytes,PixMapBase); // calling our method that set individual pixels and expects : X coordinate of the pixel, // y coordinate of the pixel, R value, G value, B value, the number of bytes in each row of the pixel map, the base } // address in memory of the begining of the pixel data } } } void ourSetPixel(unsigned short horizontal,unsigned short vertical,unsigned char R,unsigned char G,unsigned char B,unsigned short rowbytes,Ptr pixbase){ Ptr AdressOfRed; AdressOfRed = rowbytes * vertical +pixbase+horizontal*4+1; *(AdressOfRed)=R; *(AdressOfRed+1)=G; *(AdressOfRed+2)=B; } void CopyToWindow (void){ // copy all our buffer to the window, completely replaceing // everything that was there Rect sourceRect,destRect; SetPortWindowPort(ourWindow); GetPortBounds( GetWindowPort(ourWindow), &destRect ); GetPortBounds( ourBuffer, &sourceRect ); CopyBits( GetPortBitMapForCopyBits( ourBuffer ), GetPortBitMapForCopyBits(GetWindowPort(ourWindow)), &sourceRect, &destRect, srcCopy, NULL ); } void main( void ) { Initialize(); doEventLoop(); } void Initialize(void){ OSErr error; short x, y; SetRect(&windRect,100,100,740,580); InitCursor(); ourWindow = NewCWindow( 0L, &windRect, "\pDrawing Pixels", true, noGrowDocProc,(WindowPtr)-1L, true, 0L ); if ( ourWindow == nil ) ExitToShell(); ShowWindow( ourWindow ); SetPortWindowPort( ourWindow ); SetRect(&windRect,0,0,640,480); error =NewGWorld(&ourBuffer, 32, &windRect, nil, nil,0 ); // creating our offscreen buffer if (error != noErr ) ExitToShell(); for(x=-640;x<640;x++){ // repeating for all posible conditions -640 to 640 and -480 to 480 for(y=-480;y<480;y++){ gSquares[x+640][y+480] = sqrt(x*x+y*y); // calculating all distances and palcing in a global 2D array , this way we only } // calculate the square root once instead of every frame. } } /*************** The Event Loop ***************/ void doEventLoop() { EventRecord anEvent; WindowPtr evtWind; short clickArea; Rect screenRect; Point thePoint; for (;;) { if (WaitNextEvent( everyEvent, &anEvent, 0, nil )) { if (anEvent.what == mouseDown) { clickArea = FindWindow( anEvent.where, &evtWind ); if (clickArea == inDrag) { GetRegionBounds( GetGrayRgn(), &screenRect ); DragWindow( evtWind, anEvent.where, &screenRect ); } else if (clickArea == inContent) { if (evtWind != FrontWindow()) SelectWindow( evtWind ); else { thePoint = anEvent.where; GlobalToLocal( &thePoint ); //Handle click in window content here } } else if (clickArea == inGoAway) if (TrackGoAway( evtWind, anEvent.where )) return; } } DrawToBuffer(); // after checking for various events we call our drawing finctions CopyToWindow(); } } int ourRandom( int min, int max ){ // method that returns a random number between min and max return( (Random()+32768) /((32768*2)/ (max-min)))+ min; }