top of page

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).

Click on images to expand.

bottom of page