ACADEMIC RESEARCH AND PUBLICATIONS
during Graduate and Undergraduate Studies
Doctoral Candidate in Computer Science
Visual Computing Division, Digital Production Arts
Clemson University | School of Computing
PIXEL MANIPULATION:
A COMPUTER GRAPHICS PROJECT
/* "Draw" a pixel by changing its color. Used for RGB format, and default values make cyan.
* x = ((mem - base)/bpp) % width
* y = ((mem - base)/bpp) / width
* mem = y*bpp*width + x*bpp + base
*/
void drawPixel(GLubyte * buffer, int bpp, int w, int h, int x, int y, int r=0, int g=255, int b=255)
{
GLubyte *memLoc = (y*bpp*w + x*bpp + buffer);
*(memLoc) = r;
*(memLoc+1) = g;
*(memLoc+2) = b;
}
//--------------------------------------
/* Draw a line from one pixel to another using Bresenham's Algorithm. */
void drawLine(GLubyte * buffer, int w, int h, int bpp, int x1, int y1, int x2, int y2)
{
int dx = x2-x1;
int dy = y2-y1;
int j = y1;
int i = x1;
int xchange, ychange;
int er=0;
if (dx < 0)
{ xchange = -1; dx = -dx; }
else
{ xchange = 1; }
if (dy < 0)
{ ychange = -1; dy = -dy; }
else
{ ychange = 1; }
if (std::abs(dx) >= std::abs(dy)) // If dy <= dx, increment mainly along x. Else, along y.
{
while (i != x2)
{
drawPixel(buffer, bpp, w, h, i, j);
er += dy;
if ((er << 1) >= dx)
{
j += ychange;
er -= dx;
}
i += xchange; // Always increment x if major axis is x
}
}
else
{
while (j != y2)
{
drawPixel(buffer, bpp, w, h, i, j);
er += dx;
if ((er << 1) >= dy)
{
i += xchange;
er -= dy;
}
j += ychange;
}
}
}
//--------------------------------------
/* Draw a circle using the Midpoint Circle Algorithm. */
void drawCircle(GLubyte * buffer, int w, int h, int bpp, int r)
{
//float dec;
int dec = 0;
int xc = w/2;
int yc = h/2;
int i = xc+r; // Starting point in first octant at (r, 0)
int j = yc+0;
int dx, dy;
// Draw 8 points at once: (x,y), (-x,y), (x,-y), (-x,-y), (y,x), (-y,x), (y,-x), (-y,-x)
while (j <= i)
{
dx = std::abs(i-xc);
dy = std::abs(j-yc);
drawPixel(buffer, bpp, w, h, xc+dx, yc-dy); // Octant 0
drawPixel(buffer, bpp, w, h, yc+dy, xc-dx); // Octant 1
drawPixel(buffer, bpp, w, h, yc-dy, xc-dx); // Octant 2
drawPixel(buffer, bpp, w, h, xc-dx, yc-dy); // Octant 3
drawPixel(buffer, bpp, w, h, xc-dx, yc+dy); // Octant 4
drawPixel(buffer, bpp, w, h, yc-dy, xc+dx); // Octant 5
drawPixel(buffer, bpp, w, h, yc+dy, xc+dx); // Octant 6
drawPixel(buffer, bpp, w, h, xc+dx, yc+dy); // Octant 7
dec = circleDec(i, j, r, xc, yc);
j++;
if (dec <= 0) // Current point is within the circle, so don't need to move i any further left
{ dec += (j*2) +1; }
else
{
i--;
dec += ((j-i)*2)+1;
}
}
}
//--------------------------------------
/* Call drawCircle multiple times with increasing radius. */
GLubyte * drawConcentricCircles(struct image imgStruct)
{
int w = imgStruct.width;
int h = imgStruct.height;
int bpp = imgStruct.bpp;
GLubyte *buffer = (unsigned char *) malloc(w * h * bpp);
for (int r=50; r<w/2; r+=50)
{ drawCircle(buffer, w, h, bpp, r); }
// Write to file.
GLubyte * magicB = imgStruct.mbBuffer;
GLubyte * wBuffer = imgStruct.wBuffer;
GLubyte * hBuffer = imgStruct.hBuffer;
FILE *ptrFile;
ptrFile = fopen("conCircles.sif", "wb");
fwrite(magicB, 1, 2, ptrFile); // Size of 1 byte, repeated twice
fwrite(wBuffer, 1, 2, ptrFile);
fwrite(hBuffer, 1, 2, ptrFile);
fwrite(buffer, bpp, w*h, ptrFile);
fclose(ptrFile);
return buffer;
}
//--------------------------------------
/* Parametric formula of a point on a cubic Bezier curve. */
float curvePoint(int p0, int p1, int p2, int p3, float t)
{
float q = 1-t;
float pt1 = q*q*q*p0;
float pt2 = 3*q*q*t*p1;
float pt3 = 3*q*t*t*p2;
float pt4 = t*t*t*p3;
float ans = pt1 + pt2 + pt3 + pt4;
return ans;
}
//--------------------------------------
/* Using only 4 random points right now, for a cubic curve. */
GLubyte * drawCurve(struct image imgStruct)
{
int w = imgStruct.width;
int h = imgStruct.height;
int bpp = imgStruct.bpp;
GLubyte *buffer = (unsigned char*) malloc(w*h*bpp);
int x0 = 106;
int y0 = 206;
int x1 = 356;
int y1 = 150;
int x2 = 36;
int y2 = 400;
int x3 = 476;
int y3 = 306;
float i, j;
int iPrev = curvePoint(x0, x1, x2, x3, 0);
int jPrev = curvePoint(y0, y1, y2, y3, 0);
for(float p=0; p<=1; p+=0.005) // Iterates 200 times. The smaller the increment, the more accurate the curve (up to a point).
{
i = curvePoint(x0, x1, x2, x3, p);
j = curvePoint(y0, y1, y2, y3, p);
drawLine(buffer, w, h, bpp, iPrev, jPrev, i, j); // Ensure connectedness with drawing lines instead of individual points.
iPrev = i;
jPrev = j;
}
// Write to file.
GLubyte * magicB = imgStruct.mbBuffer;
GLubyte * wBuffer = imgStruct.wBuffer;
GLubyte * hBuffer = imgStruct.hBuffer;
FILE *ptrFile;
ptrFile = fopen("curve.sif", "wb");
fwrite(magicB, 1, 2, ptrFile); // Size of 1 byte, repeated twice
fwrite(wBuffer, 1, 2, ptrFile);
fwrite(hBuffer, 1, 2, ptrFile);
fwrite(buffer, bpp, w*h, ptrFile);
fclose(ptrFile);
return buffer;
}
PROJECT PAGE
Language: C (using OpenGL)
Date: Spring 2016
Class: Computer Graphics
In this first CG project, I had to read an image file pixel by pixel into a buffer for OpenGL, becoming familiar with how to access memory for pixel information. I then manipulated the data in the buffer and saved the new buffers to a file of an image format. I implemented Bresenham's Line Algorithm and the Midpoint Circle Algorithm (both provided in the code snippet) to draw lines and circles one at a time. I called these algorithms by other functions to make the designs in the screenshots. Lastly I drew Bézier curves out of the pixels using a parametric formula (also in the code snippet).