ilteris kaplan blog

Archive of blog posts since 2005

April 5, 2008

Wiki

Pixel Drawing

#wiki

Pixel Drawing

Step by Step

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 8X4 = 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.
}

Source Code


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;
	
}

Continue Reading

Back to Archive