display: add dcircle() and dellipse() rendering functions

For PythonExtra#2.
This commit is contained in:
Lephe 2024-01-04 11:52:51 +01:00
parent 2bb5294578
commit 18a7b9ae5b
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 127 additions and 0 deletions

View file

@ -102,6 +102,8 @@ set(SOURCES_COMMON
# MMU driver
src/mmu/mmu.c
# Rendering
src/render/dcircle.c
src/render/dellipse.c
src/render/dhline.c
src/render/dimage.c
src/render/dline.c

View file

@ -212,6 +212,38 @@ void dhline(int y, int color);
@color Line color (same values as dline() are allowed) */
void dvline(int x, int color);
//---
// Other geometric shapes
//---
/* dcircle(): Circle with border
This function renders a circle defined by its middle point (xm, ym) and a
radius r. The border and fill can be set separately. This function uses
Bresenham's algorithm and only renders circles of odd diameter; if you want
an even diameter, use dellipse() with a bounding box.
@xm @ym Coordinates of center
@r Radius (integer, >= 0)
@fill_color Color of the disc inside the circle, C_NONE to disable
@border_color Color of the circle itself, C_NONE to disable */
void dcircle(int xm, int ym, int r, int fill_color, int border_color);
/* dellipse(): Ellipse with border
This function renders a non-rotated ellipse, defined by its bounding box.
The border and fill can be set separately. The border is as 1-pixel thin
border given by Bresenham's algorithm.
To render an ellipse from its center coordinates (x,y) and semi-major/minor
axes a/b, use dellipse(x-a, y-b, x+a, y+b, fill_color, border_color).
@x1 @y1 @x2 @y2 Ellipse's bounding box (both bounds included, like drect())
@fill_color Color of the surface inside the ellipse, C_NONE to disable
@border_color Color of the ellipse itself, C_NONE to disable */
void dellipse(int x1, int y1, int x2, int y2, int fill_color,
int border_color);
//---
// Text rendering (topti)
//---

36
src/render/dcircle.c Normal file
View file

@ -0,0 +1,36 @@
#include <gint/display.h>
/* Based on <http://members.chello.at/~easyfilter/bresenham.html> */
void dcircle(int xm, int ym, int r, int fill_color, int border_color)
{
if(r < 0 || (fill_color == C_NONE && border_color == C_NONE)) return;
/* Circle is completely outside the rendering window */
if(xm-r >= dwindow.right || xm+r < dwindow.left) return;
if(ym-r >= dwindow.bottom || ym+r < dwindow.top) return;
int x = -r, y = 0, err = 2-2*r; /* II. Quadrant */
/* The iteration is slightly changed from the original. We swap x/y in
quadrants II. and IV. so that we get horizontal linesi nstead of a
single arc rotated 4 times. However this means we have to go until
x <= 0 instead of x < 0. */
do {
if(fill_color != C_NONE)
dline(xm-x, ym+y, xm+x, ym+y, fill_color);
dpixel(xm-x, ym+y, border_color); /* I. Quadrant */
dpixel(xm+x, ym+y, border_color); /* II. Quadrant */
if(fill_color != C_NONE)
dline(xm-x, ym-y, xm+x, ym-y, fill_color);
dpixel(xm+x, ym-y, border_color); /* III. Quadrant */
dpixel(xm-x, ym-y, border_color); /* IV. Quadrant */
r = err;
if (r <= y) /* e_xy+e_y < 0 */
err += ++y*2+1;
if (r > x || err > y) /* e_xy+e_x > 0 or no 2nd y-step */
err += ++x*2+1;
}
while (x <= 0);
}

57
src/render/dellipse.c Normal file
View file

@ -0,0 +1,57 @@
#include <gint/display.h>
#include <gint/defs/util.h>
/* Based on <http://members.chello.at/~easyfilter/bresenham.html> */
void dellipse(int x1, int y1, int x2, int y2, int fill_color, int border_color)
{
if(fill_color == C_NONE && border_color == C_NONE) return;
if(x1 > x2) swap(x1, x2);
if(y1 > y2) swap(y1, y2);
/* Ellipse is completely outside the rendering window */
if(x1 >= dwindow.right || x2 < dwindow.left) return;
if(y1 >= dwindow.bottom || y2 < dwindow.top) return;
int a = x2-x1, b = y2-y1, b1 = b&1; /* diameter */
int dx = 4*(1-a)*b*b, dy = 4*(b1+1)*a*a; /* error increment */
int err = dx + dy + b1 * a * a, e2; /* error of 1.step */
y1 += (b + 1) / 2;
y2 = y1-b1; /* starting pixel */
a = 8 * a * a;
b1 = 8 * b * b;
do {
if(fill_color != C_NONE)
dline(x1, y1, x2, y1, fill_color);
dpixel(x2, y1, border_color); /* I. Quadrant */
dpixel(x1, y1, border_color); /* II. Quadrant */
if(fill_color != C_NONE)
dline(x1, y2, x2, y2, fill_color);
dpixel(x1, y2, border_color); /* III. Quadrant */
dpixel(x2, y2, border_color); /* IV. Quadrant */
e2 = 2 * err;
if (e2 <= dy) {
y1++;
y2--;
err += (dy += a);
}
if (e2 >= dx || 2 * err > dy) {
x1++;
x2--;
err += (dx += b1);
}
}
while (x1 <= x2);
while (y1 - y2 <= b) /* to early stop of flat ellipses a=1 */
{
dpixel(x1 - 1, y1, border_color); /* finish tip of ellipse */
dpixel(x2 + 1, y1++, border_color);
dpixel(x1 - 1, y2, border_color);
dpixel(x2 + 1, y2--, border_color);
}
}