Skip to content
Permalink
Branch: master
Go to file
 
 
Cannot retrieve contributors at this time
700 lines (620 sloc) 17 KB
//
// shapedemo: testbed for OpenVG APIs
// Anthony Starks (ajstarks@gmail.com)
//
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
// randcolor returns a random number 0..255
unsigned int randcolor() {
return (unsigned int)(drand48() * 255.0);
}
// randf returns a floating point number bounded by n
VGfloat randf(int n) {
return drand48() * n;
}
// coordpoint marks a coordinate, preserving a previous color
void coordpoint(VGfloat x, VGfloat y, VGfloat size, VGfloat pcolor[4]) {
Fill(128, 0, 0, 0.3);
Circle(x, y, size);
setfill(pcolor);
}
// grid draws a grid
void grid(VGfloat x, VGfloat y, int n, int w, int h) {
VGfloat ix, iy;
Stroke(128, 128, 128, 0.5);
StrokeWidth(2);
for (ix = x; ix <= x + w; ix += n) {
Line(ix, y, ix, y + h);
}
for (iy = y; iy <= y + h; iy += n) {
Line(x, iy, x + w, iy);
}
}
// gradient demos linear and radial gradients
void gradient(int width, int height) {
VGfloat x1, y1, x2, y2, cx, cy, fx, fy, r;
VGfloat w = (VGfloat)width;
VGfloat h = (VGfloat)height;
VGfloat dotcolor[4] = {0, 0, 0, 0.3};
VGfloat stops[] = {
0.0, 1.0, 1.0, 1.0, 1.0,
0.5, 0.5, 0.5, 0.5, 1.0,
1.0, 0.0, 0.0, 0.0, 1.0
};
x1 = w/8;
x2 = (w*3)/8;
y1 = h/3;
y2 = (h*2)/3;
cx = (w*3)/4;
cy = (h/2);
r = (x2-x1);
fx = cx + (r/4);
fy = cy + (r/4);
Start(w, h);
Background(128, 128, 128);
FillLinearGradient(x1, y1, x2, y2, stops, 3);
Rect(x1, y1, x2-x1, y2-y1);
FillRadialGradient(cx, cy, fx, fy, r, stops, 3);
Circle(cx, cy, r);
RGBA(.5, 0, 0, 0.3, dotcolor);
setfill(dotcolor);
Circle(x1, y1, 10);
Circle(x2, y2, 10);
Circle(cx, cy, 10);
Circle(cx+r/2, cy, 10);
Circle(fx, fy, 10);
RGB(0,0,0,dotcolor);
setfill(dotcolor);
TextMid(x1, y1-20, "(x1, y1)", SansTypeface, 18);
TextMid(x2, y2+10, "(x2, y2)", SansTypeface, 18);
TextMid(cx, cy, "(cx, cy)", SansTypeface, 18);
TextMid(fx, fy, "(fx, fy)", SansTypeface, 18);
TextEnd(cx+(r/2)+20, cy, "r", SansTypeface, 18);
TextMid(x1+((x2-x1)/2), h/6, "Linear Gradient", SansTypeface, 36);
TextMid(cx, h/6, "Radial Gradient", SansTypeface, 36);
End();
}
// makepi draws the Raspberry Pi
void makepi(VGfloat x, VGfloat y, int w, int h) {
// dimensions
VGfloat socw = h / 5,
compw = h / 5,
cjw = h / 10,
cjh = h / 8,
audw = h / 5,
aujw = h / 10,
aujh = cjh / 2,
hdw = w / 6,
hdh = w / 10,
gpw = w / 3,
gph = h / 8,
pw = h / 10,
usw = w / 5,
ush = h / 5,
etw = w / 5,
eth = h / 5,
sdw = w / 6, sdh = w / 4, offset = (w / 2) / 10, w34 = (w * 3) / 4, w2 = w / 2, h2 = h / 2, h40 = (h * 2) / 5;
Fill(0, 128, 0, 1);
Rect(x, y, w, h); // board
Fill(255, 255, 0, 1);
Rect(x + w2, (y + h) - compw, compw, compw); // composite
Fill(192, 192, 192, 1);
Rect(x + w2 + (cjw / 2), y + h, cjw, cjh); // composite jack
Fill(0, 0, 0, 1);
Rect(x + w34, y + h - audw, audw, audw); // audio
Rect(x + w34 + (aujw / 2), y + h, aujw, aujh); // audio jack
Fill(192, 192, 192, 1);
Rect(x + w2, y, hdw, hdh); // HDMI
Rect((x + w) - etw, y, etw, eth); // Ethernet
Rect((x + w + offset) - usw, y + h40, usw, ush); // USB
Rect(x, y, pw, pw); // Power
Fill(0, 0, 0, 1);
Rect(x + (w * 2) / 5, y + h40, socw, socw); // SoC
Rect(x, (y + h) - gph, gpw, gph); // GPIO
Fill(0, 0, 255, 1);
Rect(x - sdw, (y + h2) - (sdh / 2), sdw, sdh); // SD card
}
// raspi draws the raspberry pi, scaled to the screen dimensions
void raspi(int w, int h, char *s) {
VGfloat midx = w / 2, midy = h / 2;
int rw = midx, rh = (rw * 2) / 3, fontsize = w * 0.03;
Start(w, h);
Background(255, 255, 255);
makepi(midx - (rw / 2), midy - (rh / 2), rw, rh);
Fill(128, 0, 0, 1);
TextMid(midx, midy - (rh / 2) - (fontsize * 2), s, SansTypeface, fontsize);
End();
}
typedef struct {
Fontinfo font;
VGfloat tw;
int fontsize;
} FW;
void textbbox(char *s, Fontinfo f, int pointsize) {
}
// adjust the font to fit within a width
void fitwidth(int width, int adj, char *s, FW * f) {
f->tw = TextWidth(s, f->font, f->fontsize);
while (f->tw > width) {
f->fontsize -= adj;
f->tw = TextWidth(s, f->font, f->fontsize);
}
}
// testpattern shows a test pattern
void testpattern(int w, int h, char *s) {
VGfloat midx, midy1, midy2, midy3;
int fontsize = 256, h2 = h / 2;
FW tw1 = { MonoTypeface, 0, fontsize };
FW tw2 = { SansTypeface, 0, fontsize };
FW tw3 = { SerifTypeface, 0, fontsize };
Start(w, h);
// colored squares in the corners
Fill(255, 0, 0, 1);
Rect(0, 0, 100, 100);
Fill(0, 255, 0, 1);
Rect(0, h - 100, 100, 100);
Fill(0, 0, 255, 1);
Rect(w - 100, 0, 100, 100);
Fill(128, 128, 128, 1);
Rect(w - 100, h - 100, 100, 100);
// for each font, (Sans, Serif, Mono), adjust the string to the w
fitwidth(w, 20, s, &tw1);
fitwidth(w, 20, s, &tw2);
fitwidth(w, 20, s, &tw3);
midx = w / 2;
// Adjust the baselines to be medial
midy1 = h2 + 20 + (tw1.fontsize) / 2;
midy2 = h2 - (tw2.fontsize) / 2;
midy3 = h2 - 20 - tw2.fontsize - (tw3.fontsize) / 2;
Fill(128, 128, 128, 1);
TextMid(midx, midy1, s, tw1.font, tw1.fontsize);
Fill(128, 0, 0, 1);
TextMid(midx, midy2, s, tw2.font, tw2.fontsize);
Fill(0, 0, 128, 1);
TextMid(midx, midy3, s, tw3.font, tw3.fontsize);
End();
}
// textlines writes lines of text
void textlines(VGfloat x, VGfloat y, char *s[], Fontinfo f, int fontsize, VGfloat leading) {
int i;
for (i = 0;; i++) {
if (s[i] == NULL) {
break;
}
TextMid(x, y, s[i], f, fontsize);
y -= leading;
}
}
// tb draws a block of text
void tb(int w, int h) {
char *para[] = {
"For lo,",
"the winter is past,",
"the rain is over and gone",
"the flowers appear on the earth;",
"the time for the singing of birds is come,",
"and the voice of the turtle is heard in our land",
NULL
};
VGfloat tmargin = w * 0.5, lmargin = w * 0.10, top = h * .9, mid = h * .6, bot = h * .3;
int fontsize = 24, leading = 40, lfontsize = fontsize * 2, midb = ((leading * 2) + (leading / 2)) - (lfontsize / 2);
Start(w, h);
Fill(49, 79, 79, 1);
textlines(tmargin, top, para, SerifTypeface, fontsize, leading);
textlines(tmargin, mid, para, SansTypeface, fontsize, leading);
textlines(tmargin, bot, para, MonoTypeface, fontsize, leading);
Text(lmargin, top - midb, "Serif", SansTypeface, lfontsize);
Text(lmargin, mid - midb, "Sans", SansTypeface, lfontsize);
Text(lmargin, bot - midb, "Mono", SansTypeface, lfontsize);
End();
}
void imagetest(int w, int h) {
int imgw = 422, imgh = 238;
VGfloat cx = (w / 2) - (imgw / 2), cy = (h / 2) - (imgh / 2);
VGfloat ulx = 0, uly = h - imgh;
VGfloat urx = w - imgw, ury = uly;
VGfloat llx = 0, lly = 0;
VGfloat lrx = urx, lry = lly;
Start(w, h);
Background(0, 0, 0);
Image(cx, cy, imgw, imgh, "desert1.jpg");
Image(ulx, uly, imgw, imgh, "desert2.jpg");
Image(urx, ury, imgw, imgh, "desert3.jpg");
Image(llx, lly, imgw, imgh, "desert4.jpg");
Image(lrx, lry, imgw, imgh, "desert5.jpg");
End();
}
void imagetable(int w, int h) {
int imgw = 422, imgh = 238;
char *itable[] = {
"desert0.jpg",
"desert1.jpg",
"desert2.jpg",
"desert3.jpg",
"desert4.jpg",
"desert5.jpg",
"desert6.jpg",
"desert7.jpg",
NULL
};
VGfloat left = 50.0;
VGfloat bot = h - imgh - 50.0;
VGfloat gutter = 50.0;
VGfloat x = left;
VGfloat y = bot;
int i;
Start(w, h);
Background(0, 0, 0);
for (i = 0; itable[i] != NULL; i++) {
Image(x, y, imgw, imgh, itable[i]);
Fill(255, 255, 255, 0.3);
Rect(x, y, imgw, 32);
Fill(0, 0, 0, 1);
TextMid(x + (imgw / 2), y + 10, itable[i], SansTypeface, 16);
x += imgw + gutter;
if (x > w) {
x = left;
y -= imgh + gutter;
}
}
y = h * 0.1;
Fill(128, 128, 128, 1);
TextMid(w / 2, 100, "Joshua Tree National Park", SansTypeface, 48);
End();
}
// fontrange shows a range of fonts
void fontrange(int w, int h) {
int *s, sizes[] = { 6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 21, 24, 36, 48, 60, 72, 96, 0 };
VGfloat x, y = h / 2, spacing = 50, s2 = spacing / 2, len, lx;
char num[4];
Start(w, h);
Background(255, 255, 255);
// compute the length so we can center
for (len = 0, s = sizes; *s; s++) {
len += *s + spacing;
}
len -= spacing;
lx = (w / 2) - (len / 2); // center point
// for each size, display a character and label
for (x = lx, s = sizes; *s; s++) {
Fill(128, 0, 0, 1);
TextMid(x, y, "a", SerifTypeface, *s);
Fill(128, 128, 128, 1);
snprintf(num, 3, "%d", *s);
TextMid(x, y - spacing, num, SansTypeface, 16);
x += *s + spacing;
}
// draw a line below the characters, a curve above
x -= spacing;
Stroke(150, 150, 150, 0.5);
StrokeWidth(2);
Line(lx, y - s2, x, y - s2);
Fill(255, 255, 255, 1);
Qbezier(lx, y + s2, x, y + s2, x, y + (spacing * 3));
End();
}
// refcard shows a reference card of shapes
void refcard(int width, int height) {
char *shapenames[] = {
"Circle",
"Ellipse",
"Rectangle",
"Rounded Rectangle",
"Line",
"Polyline",
"Polygon",
"Arc",
"Quadratic Bezier",
"Cubic Bezier",
"Image"
};
VGfloat shapecolor[4];
RGB(202, 225, 255, shapecolor);
VGfloat top = height * .95, sx = 500, sy = top, sw = width * .05, sh = height * .045, dotsize = 7, spacing = 2.0;
int i, ns = sizeof(shapenames) / sizeof(char *), fontsize = height * .033;
Start(width, height);
sx = width * 0.10;
Fill(128, 0, 0, 1);
TextEnd(width - 20, height / 2, "OpenVG on the Raspberry Pi", SansTypeface, fontsize + (fontsize / 2));
Fill(0, 0, 0, 1);
for (i = 0; i < ns; i++) {
Text(sx + sw + sw / 2, sy, shapenames[i], SansTypeface, fontsize);
sy -= sh * spacing;
}
sy = top;
VGfloat cx = sx + (sw / 2), ex = sx + sw;
setfill(shapecolor);
Circle(cx, sy, sw);
coordpoint(cx, sy, dotsize, shapecolor);
sy -= sh * spacing;
Ellipse(cx, sy, sw, sh);
coordpoint(cx, sy, dotsize, shapecolor);
sy -= sh * spacing;
Rect(sx, sy, sw, sh);
coordpoint(sx, sy, dotsize, shapecolor);
sy -= sh * spacing;
Roundrect(sx, sy, sw, sh, 20, 20);
coordpoint(sx, sy, dotsize, shapecolor);
sy -= sh * spacing;
StrokeWidth(1);
Stroke(204, 204, 204, 1);
Line(sx, sy, ex, sy);
coordpoint(sx, sy, dotsize, shapecolor);
coordpoint(ex, sy, dotsize, shapecolor);
sy -= sh;
VGfloat px[5] = { sx, sx + (sw / 4), sx + (sw / 2), sx + ((sw * 3) / 4), sx + sw };
VGfloat py[5] = { sy, sy - sh, sy, sy - sh, sy };
Polyline(px, py, 5);
coordpoint(px[0], py[0], dotsize, shapecolor);
coordpoint(px[1], py[1], dotsize, shapecolor);
coordpoint(px[2], py[2], dotsize, shapecolor);
coordpoint(px[3], py[3], dotsize, shapecolor);
coordpoint(px[4], py[4], dotsize, shapecolor);
sy -= sh * spacing;
py[0] = sy;
py[1] = sy - sh;
py[2] = sy - (sh / 2);
py[3] = py[1] - (sh / 4);
py[4] = sy;
Polygon(px, py, 5);
sy -= (sh * spacing) + sh;
Arc(sx + (sw / 2), sy, sw, sh, 0, 180);
coordpoint(sx + (sw / 2), sy, dotsize, shapecolor);
sy -= sh * spacing;
VGfloat cy = sy + (sh / 2), ey = sy;
Qbezier(sx, sy, cx, cy, ex, ey);
coordpoint(sx, sy, dotsize, shapecolor);
coordpoint(cx, cy, dotsize, shapecolor);
coordpoint(ex, ey, dotsize, shapecolor);
sy -= sh * spacing;
ey = sy;
cy = sy + sh;
Cbezier(sx, sy, cx, cy, cx, sy, ex, ey);
coordpoint(sx, sy, dotsize, shapecolor);
coordpoint(cx, cy, dotsize, shapecolor);
coordpoint(cx, sy, dotsize, shapecolor);
coordpoint(ex, ey, dotsize, shapecolor);
sy -= (sh * spacing * 1.5);
Image(sx, sy, 100, 100, "starx.jpg");
End();
}
// rotext draws text, rotated around the center of the screen, progressively faded
void rotext(int w, int h, int n, char *s) {
VGfloat fade = (100.0 / (VGfloat) n) / 100.0;
VGfloat deg = 360.0 / n;
VGfloat x = w / 2, y = h / 2;
VGfloat alpha = 1.0; // start solid
int i, size = w / 8;
Start(w, h);
Background(0, 0, 0);
Translate(x, y);
for (i = 0; i < n; i++) {
Fill(255, 255, 255, alpha);
Text(0, 0, s, SerifTypeface, size);
alpha -= fade; // fade
size += n; // enlarge
Rotate(deg);
}
End();
}
// rseed seeds the random number generator from the random device
void rseed(void) {
unsigned char d[sizeof(long int)];
long int s;
int fd;
// read bytes from the random device,
// pack them into a long int.
fd = open("/dev/urandom", O_RDONLY);
if (fd < 0) {
srand48(1);
return;
}
read(fd, (void *)d, (size_t) sizeof(long int));
s = d[3] | (d[2] << 8) | (d[1] << 16) | (d[0] << 24);
srand48(s);
close(fd);
}
// rshapes draws shapes with random colors, strokes, and sizes.
void rshapes(int width, int height, int n) {
int i, j, np = 10;
VGfloat sx, sy, cx, cy, px, py, ex, ey, pox, poy;
VGfloat polyx[np], polyy[np];
rseed();
Start(width, height);
for (i = 0; i < n; i++) {
Fill(randcolor(), randcolor(), randcolor(), drand48());
Ellipse(randf(width), randf(height), randf(200), randf(100));
Circle(randf(width), randf(height), randf(100));
Rect(randf(width), randf(height), randf(200), randf(100));
Arc(randf(width), randf(height), randf(200), randf(200), randf(360), randf(360));
sx = randf(width);
sy = randf(height);
Stroke(randcolor(), randcolor(), randcolor(), 1);
StrokeWidth(randf(5));
Line(sx, sy, sx + randf(200), sy + randf(100));
StrokeWidth(0);
sx = randf(width);
sy = randf(height);
ex = sx + randf(200);
ey = sy;
cx = sx + ((ex - sx) / 2.0);
cy = sy + randf(100);
Qbezier(sx, sy, cx, cy, ex, ey);
sx = randf(width);
sy = randf(height);
ex = sx + randf(200);
ey = sy;
cx = sx + ((ex - sx) / 2.0);
cy = sy + randf(100);
px = cx;
py = sy - randf(100);
Cbezier(sx, sy, cx, cy, px, py, ex, ey);
pox = randf(width);
poy = randf(height);
for (j = 0; j < np; j++) {
polyx[j] = pox + randf(200);
polyy[j] = poy + randf(100);
}
Polygon(polyx, polyy, np);
pox = randf(width);
poy = randf(height);
for (j = 0; j < np; j++) {
polyx[j] = pox + randf(200);
polyy[j] = poy + randf(100);
}
Polyline(polyx, polyy, np);
}
Fill(128, 0, 0, 1);
Text(20, 20, "OpenVG on the Raspberry Pi", SansTypeface, 32);
End();
}
// sunearth shows the relative sizes of the sun and the earth
void sunearth(int w, int h) {
VGfloat sun, earth, x, y;
int i;
rseed();
Start(w, h);
Background(0, 0, 0);
Fill(255, 255, 255, 1);
for (i = 0; i < w / 4; i++) {
x = randf(w);
y = randf(h);
Circle(x, y, 2);
}
earth = (VGfloat) w *0.010;
sun = earth * 109;
Fill(0, 0, 255, 1);
Circle(w / 3, h - (h / 10), earth);
Fill(255, 255, 224, 1);
Circle(w, 0, sun);
End();
}
// advert is an ad for the package
void advert(int w, int h) {
VGfloat y = h/4;
int fontsize = (w * 4) / 100;
char *s = "github.com/ajstarks/openvg";
char *a = "ajstarks@gmail.com";
int imw = 110, imh = 110, rw = w/4, rh = (rw*2/3);
VGfloat tw = TextWidth(s, SansTypeface, fontsize);
Start(w, h);
makepi((w/2) - (rw/2), h/2, rw, rh);
Fill(128, 0, 0, 1);
Text(w / 2 - (tw / 2), y - (fontsize / 4), s, SansTypeface, fontsize);
y -= 100;
tw = TextWidth(a, SansTypeface, fontsize / 3);
Fill(128, 128, 128, 1);
Text(w / 2 - (tw / 2), y, a, SansTypeface, fontsize / 3);
Image((w / 2) - (imw / 2), 20, imw, imh, "starx.jpg");
End();
}
// demo shows a timed demonstration
void demo(int w, int h, int sec) {
refcard(w, h);
sleep(sec);
rshapes(w, h, 50);
sleep(sec);
testpattern(w, h, "OpenVG on RasPi");
sleep(sec);
imagetable(w, h);
sleep(sec);
rotext(w, h, 30, "Raspi");
sleep(sec);
tb(w, h);
sleep(sec);
fontrange(w, h);
sleep(sec);
sunearth(w, h);
sleep(sec);
raspi(w, h, "The Raspberry Pi");
sleep(sec);
gradient(w,h);
sleep(sec);
advert(w, h);
}
// wait for a specific character
void waituntil(int endchar) {
int key;
for (;;) {
key = getchar();
if (key == endchar || key == '\n') {
break;
}
}
}
// main initializes the system and shows the picture.
// Exit and clean up when you hit [RETURN].
int main(int argc, char **argv) {
int w, h, n;
char *usage =
"%s [command]\n\tdemo sec\n\tastro\n\ttest ...\n\trand n\n\trotate n ...\n\timage\n\ttext\n\tfontsize\n\traspi\n\tadvert\n\tgradient\n";
char *progname = argv[0];
saveterm();
init(&w, &h);
rawterm();
switch (argc) {
case 2:
if (strncmp(argv[1], "image", 5) == 0) {
imagetable(w, h);
} else if (strncmp(argv[1], "text", 4) == 0) {
tb(w, h);
} else if (strncmp(argv[1], "astro", 5) == 0) {
sunearth(w, h);
} else if (strncmp(argv[1], "fontsize", 8) == 0) {
fontrange(w, h);
} else if (strncmp(argv[1], "advert", 6) == 0) {
advert(w,h);
} else if (strncmp(argv[1], "raspi", 5) == 0) {
raspi(w, h, "The Raspberry Pi");
} else if (strncmp(argv[1], "gradient", 8) == 0) {
gradient(w,h);
} else {
restoreterm();
fprintf(stderr, usage, progname);
return 1;
}
break;
case 3:
n = atoi(argv[2]);
if (strncmp(argv[1], "demo", 4) == 0) {
if (n < 1 || n > 30) {
n = 5;
}
demo(w, h, n);
} else if (strncmp(argv[1], "rand", 4) == 0) {
if (n < 1 || n > 1000) {
n = 100;
}
rshapes(w, h, n);
} else if (strncmp(argv[1], "test", 4) == 0) {
testpattern(w, h, argv[2]);
} else {
restoreterm();
fprintf(stderr, usage, progname);
return 1;
}
break;
case 4:
if (strncmp(argv[1], "rotate", 6) == 0) {
rotext(w, h, atoi(argv[2]), argv[3]);
} else {
restoreterm();
fprintf(stderr, usage, progname);
return 1;
}
break;
default:
refcard(w, h);
}
waituntil(0x1b);
restoreterm();
finish();
return 0;
}
You can’t perform that action at this time.