April 5, 2008
WikiPixel Drawing
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