Skip to content

Commit

Permalink
Add function to draw a circle
Browse files Browse the repository at this point in the history
  • Loading branch information
RossAdrian committed Aug 3, 2024
1 parent 16cda7b commit ce64cf3
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 2 deletions.
33 changes: 33 additions & 0 deletions native/module_pyfb.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,38 @@ static PyObject* pyfunc_pyfb_sdrawLine(PyObject* self, PyObject* args) {
return PyLong_FromLong(exitcode);
}

/**
* Python wrapper for the pyfb_drawCircle function.
*
* @param self The function
* @param args The arguments, expecting long of the fbnum, long of the xm, long of the ym, long of the radius, long of the color
*
* @return Just 0
*/
static PyObject* pyfunc_pyfb_sdrawCircle(PyObject* self, PyObject* args) {
unsigned char fbnum_c;
unsigned long int xm;
unsigned long int ym;
unsigned long int radius;
uint32_t color_val;

if(!PyArg_ParseTuple(args, "bkkkI", &fbnum_c, &xm, &ym, &radius, &color_val)) {
PyErr_SetString(PyExc_TypeError, "Expecting arguments of type (byte, long, long, long, long)");
return NULL;
}

// Now parse the color
struct pyfb_color color;
pyfb_initcolor_u32(&color, color_val);

// and invoke the target function
pyfb_sdrawCircle((uint8_t)fbnum_c, xm, ym, radius, &color);

// and return just 0
int exitcode = 0;
return PyLong_FromLong(exitcode);
}

// The module def

/**
Expand All @@ -235,6 +267,7 @@ static PyMethodDef pyfb_methods[] = {
{"pyfb_drawLine", pyfunc_pyfb_sdrawLine, METH_VARARGS, "Draw a line on the framebuffer"},
{"pyfb_drawHorizontalLine", pyfunc_pyfb_sdrawHorizontalLine, METH_VARARGS, "Draw a horizontal line on the framebuffer"},
{"pyfb_drawVerticalLine", pyfunc_pyfb_sdrawVerticalLine, METH_VARARGS, "Draw a vertical line on the framebuffer"},
{"pyfb_drawCircle", pyfunc_pyfb_sdrawCircle, METH_VARARGS, "Draw a circle on the framebuffer"},
{"pyfb_flushBuffer", pyfunc_pyfb_flushBuffer, METH_VARARGS, "Flush the offscreen buffer to the framebuffer"},
{"pyfb_getResolution", pyfunc_pyfb_getResolution, METH_VARARGS, "Returns a tupel of the framebuffer resolution"},
{NULL, NULL, 0, NULL}};
Expand Down
102 changes: 100 additions & 2 deletions native/paint.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,35 @@
*/
#define ULI_TO_LI(x) ((long int)(x))

/**
* Sets a pixel, but only if it is on screen, else ignored.
*
* @param xres The x resolution
* @param yres The y resolution
* @param x The x coordinate
* @param y The y coordinate
* @param fbnum The framebuffer number
* @param color The color value
*/
#define SET_PIXEL_OR_IGNORE(fbnum, x, y, xres, yres, color) \
if(x < xres && y < yres) { \
pyfb_setPixel(fbnum, x, y, color); \
}

/**
* Long int abs function.
*
* @param x The number to remove a minus
*
* @return The input number without possible minus
*/
static inline long int li_abs(long int x) {
if(x < 0) {
return (unsigned long int)(x * -1);
return (long int)(x * -1);
}

// else
return (unsigned long int)x;
return (long int)x;
}

void __APISTATUS_internal pyfb_drawLine(uint8_t fbnum,
Expand Down Expand Up @@ -121,6 +143,82 @@ void __APISTATUS_internal pyfb_sdrawLine(uint8_t fbnum,
// all is valid, so draw the line
pyfb_drawLine(fbnum, x1, y1, x2, y2, color);

// ready, so return
pyfb_fbunlock(fbnum);
}

void __APISTATUS_internal pyfb_drawCircle(uint8_t fbnum,
unsigned long int xm,
unsigned long int ym,
unsigned long int radius,
struct pyfb_color* color) {
long int x0 = ULI_TO_LI(xm);
long int y0 = ULI_TO_LI(ym);
long int rad = ULI_TO_LI(radius);

long int f = 1 - rad;
long int ddF_x = 0;
long int ddF_y = -2 * radius;
long int x = 0;
long int y = radius;

struct pyfb_videomode_info vinfo;
pyfb_vinfo(fbnum, &vinfo);

const unsigned long int xres = vinfo.vinfo.xres;
const unsigned long int yres = vinfo.vinfo.yres;

SET_PIXEL_OR_IGNORE(fbnum, x0, y0 + rad, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0, y0 - rad, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 + rad, y0, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 - rad, y0, xres, yres, color);

while(x < y) {
if(f >= 0) {
y -= 1;
ddF_y += 2;
f += ddF_y;
}

x += 1;
ddF_x += 2;
f += ddF_x + 1;

SET_PIXEL_OR_IGNORE(fbnum, x0 + x, y0 + y, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 - x, y0 + y, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 + x, y0 - y, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 - x, y0 - y, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 + y, y0 + x, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 - y, y0 + x, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 + y, y0 - x, xres, yres, color);
SET_PIXEL_OR_IGNORE(fbnum, x0 - y, y0 - x, xres, yres, color);
}
}

void pyfb_sdrawCircle(uint8_t fbnum,
unsigned long int xm,
unsigned long int ym,
unsigned long int radius,
struct pyfb_color* color) {
// first check if fbnum is valid
if(fbnum >= MAX_FRAMEBUFFERS) {
PyErr_SetString(PyExc_ValueError, "The framebuffer number is not valid");
return;
}

// Ok, then lock
pyfb_fblock(fbnum);

// next test if the device is really in use
if(!pyfb_fbused(fbnum)) {
// this framebuffer is not in use, so ignore
PyErr_SetString(PyExc_IOError, "The framebuffer is not opened");
pyfb_fbunlock(fbnum);
return;
}

pyfb_drawCircle(fbnum, xm, ym, radius, color);

// ready, so return
pyfb_fbunlock(fbnum);
}
30 changes: 30 additions & 0 deletions native/pyframebuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,36 @@ extern void __APISTATUS_internal pyfb_sdrawLine(uint8_t fbnum,
unsigned long int y2,
const struct pyfb_color* color);

/**
* Safe version to draw a circle on the screen.
*
* @param fbnum The framebuffer number
* @param xm The x coordinate of the middle point
* @param ym The y coordinate of the middle point
* @param radius The circle radius
* @param color The color value
*/
extern void pyfb_sdrawCircle(uint8_t fbnum,
unsigned long int xm,
unsigned long int ym,
unsigned long int radius,
struct pyfb_color* color);

/**
* Unsafe version to draw a circle on the screen.
*
* @param fbnum The framebuffer number
* @param xm The x coordinate of the middle point
* @param ym The y coordinate of the middle point
* @param radius The circle radius
* @param color The color value
*/
extern void __APISTATUS_internal pyfb_drawCircle(uint8_t fbnum,
unsigned long int xm,
unsigned long int ym,
unsigned long int radius,
struct pyfb_color* color);

/**
* Paints the content of the offscreen buffer to the framebuffer. This function must be callen
* because this is the only operation that is required to paint the content of the offscreen
Expand Down
12 changes: 12 additions & 0 deletions pyframebuffer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,18 @@ def drawVerticalLine(self, x, y, len, color):
color = getColorValue(color)
fb.pyfb_drawVerticalLine(self.fbnum, x, y, len, color)

def drawCircle(self, xm, ym, radius, color):
"""
Draws a circle on the offscreen buffer.
@param xm The x coordinate of the middle
@param ym The y coordinate of the middle
@param radius The radius of the circle
@param color The color value of Color object
"""
color = getColorValue(color)
fb.pyfb_drawCircle(self.fbnum, xm, ym, radius, color)


def openfb(num):
"""
Expand Down

0 comments on commit ce64cf3

Please sign in to comment.