ACADEMIC RESEARCH AND PUBLICATIONS
during Graduate and Undergraduate Studies
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).