Beispiel #1
0
//planets is an exploration of scale
func planets(width, height int, message string) {

	w := openvg.VGfloat(width)
	h := openvg.VGfloat(height)
	y := h / 2

	margin := openvg.VGfloat(100.0)
	minsize := openvg.VGfloat(7.0)
	labeloc := openvg.VGfloat(100.0)
	bgcolor := "black"
	labelcolor := "white"
	maxsize := (h / 2) * 0.05

	origin := sun.distance
	mostDistant := neptune.distance
	firstSize := mercury.radius
	lastSize := neptune.radius

	openvg.Start(width, height)
	openvg.BackgroundColor(bgcolor)

	for _, p := range solarSystem {
		x := vmap(p.distance, origin, mostDistant, margin, w-margin)
		r := vmap(p.radius, firstSize, lastSize, minsize, maxsize)

		if p.name == "Sun" {
			openvg.FillRGB(p.color.Red, p.color.Green, p.color.Blue, 1)
			openvg.Circle(margin-(r/2), y, r)
		} else {
			light(x, y, r, p.color)
			openvg.Circle(x, y, r)
			if p.name == "Saturn" {
				ringwidth := r * 2.35 // Saturn's rings are over 2x the planet radius
				openvg.StrokeWidth(3)
				openvg.StrokeRGB(p.color.Red, p.color.Green, p.color.Blue, 1)
				openvg.Line((x - ringwidth/2), y, (x + ringwidth/2), y)
				openvg.StrokeWidth(0)
			}
		}
		if p.name == "Earth" && len(message) > 1 {
			openvg.StrokeColor(labelcolor)
			openvg.StrokeWidth(1)
			openvg.Line(x, y+(r/2), x, y+labeloc)
			openvg.StrokeWidth(0)
			openvg.FillColor(labelcolor)
			openvg.TextMid(x, y+labeloc+10, message, "sans", 12)
		}
	}
	openvg.End()
}
Beispiel #2
0
func combohand(cx, cy, px, py, r, stroke openvg.VGfloat, t float64, value int, color string) {
	thinr := float64(r * 0.25)
	t = minadjust(t, value) * deg2rad
	tx := cx + openvg.VGfloat(thinr*math.Cos(t))
	ty := cy + openvg.VGfloat(thinr*math.Sin(t))
	openvg.FillColor(color)
	openvg.Ellipse(px, py, stroke*2, stroke*2)
	openvg.Ellipse(tx, ty, stroke*2, stroke*2)
	openvg.StrokeWidth(stroke)
	openvg.StrokeColor(color)
	openvg.Line(cx, cy, tx, ty)
	openvg.StrokeWidth(stroke * 2)
	openvg.Line(tx, ty, px, py)
	openvg.StrokeWidth(0)
}
Beispiel #3
0
// rshapes draws shapes with random colors, openvg.Strokes, and sizes.
func rshapes(width, height, n int) {

	var sx, sy, cx, cy, px, py, ex, ey, pox, poy openvg.VGfloat

	np := 10
	polyx := make([]openvg.VGfloat, np)
	polyy := make([]openvg.VGfloat, np)
	openvg.Start(width, height)
	for i := 0; i < n; i++ {
		openvg.FillRGB(randcolor(), randcolor(), randcolor(), openvg.VGfloat(rand.Float32()))
		openvg.Ellipse(randf(width), randf(height), randf(200), randf(100))
		openvg.Circle(randf(width), randf(height), randf(100))
		openvg.Rect(randf(width), randf(height), randf(200), randf(100))
		openvg.Arc(randf(width), randf(height), randf(200), randf(200), randf(360), randf(360))

		sx = randf(width)
		sy = randf(height)
		openvg.StrokeRGB(randcolor(), randcolor(), randcolor(), 1)
		openvg.StrokeWidth(randf(5))
		openvg.Line(sx, sy, sx+randf(200), sy+randf(100))
		openvg.StrokeWidth(0)

		sx = randf(width)
		sy = randf(height)
		ex = sx + randf(200)
		ey = sy
		cx = sx + ((ex - sx) / 2.0)
		cy = sy + randf(100)
		openvg.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)
		openvg.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)
		}
		openvg.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)
		}
		openvg.Polyline(polyx, polyy) // , np)
	}
	openvg.FillRGB(128, 0, 0, 1)
	openvg.Text(20, 20, "OpenVG on the Raspberry Pi", "sans", 32)
	openvg.End()
}
Beispiel #4
0
// showgrid xrays a slide
func showgrid(d deck.Deck, n int, p float64) {
	w := openvg.VGfloat(d.Canvas.Width)
	h := openvg.VGfloat(d.Canvas.Height)
	percent := openvg.VGfloat(p)
	fs := (w / 100) // labels are 1% of the width
	xpct := (percent / 100.0) * w
	ypct := (percent / 100.0) * h

	openvg.StrokeColor("lightgray", 0.5)
	openvg.StrokeWidth(3)

	// horizontal gridlines
	xl := percent
	for x := xpct; x <= w; x += xpct {
		openvg.Line(x, 0, x, h)
		openvg.Text(x, percent, fmt.Sprintf("%.0f%%", xl), "sans", int(fs))
		xl += percent
	}

	// vertical gridlines
	yl := percent
	for y := ypct; y <= h; y += ypct {
		openvg.Line(0, y, w, y)
		openvg.Text(percent, y, fmt.Sprintf("%.0f%%", yl), "sans", int(fs))
		yl += percent
	}

	// show boundary and location of images
	if n < 0 || n > len(d.Slide) {
		return
	}
	for _, im := range d.Slide[n].Image {
		x := pct(im.Xp, w)
		y := pct(im.Yp, h)
		iw := openvg.VGfloat(im.Width)
		ih := openvg.VGfloat(im.Height)
		if im.Scale > 0 {
			iw *= openvg.VGfloat(im.Scale / 100)
			ih *= openvg.VGfloat(im.Scale / 100)
		}
		openvg.FillRGB(127, 0, 0, 0.3)
		openvg.Circle(x, y, fs)
		openvg.FillRGB(255, 0, 0, 0.1)
		openvg.Rect(x-iw/2, y-ih/2, iw, ih)
	}
	openvg.End()
}
Beispiel #5
0
func roundhand(cx, cy, px, py, stroke openvg.VGfloat, color string) {
	openvg.StrokeWidth(stroke)
	openvg.StrokeColor(color)
	openvg.Line(cx, cy, px, py)
	openvg.StrokeWidth(0)
	openvg.FillColor(color)
	openvg.Ellipse(px, py, stroke, stroke)
}
Beispiel #6
0
func secondhand(cx, cy, sx, sy, textsize openvg.VGfloat) {
	openvg.FillColor(secolor, 0.4)
	openvg.Ellipse(sx, sy, textsize, textsize)
	if secline {
		openvg.StrokeWidth(textsize / 6)
		openvg.StrokeColor(secolor)
		openvg.Line(cx, cy, sx, sy)
		openvg.StrokeWidth(0)
	}
}
Beispiel #7
0
func face(x, y, r openvg.VGfloat, ts int) {
	var fx, fy, va openvg.VGfloat
	va = openvg.VGfloat(ts) / 2.0
	secsize := openvg.VGfloat(ts) / 3
	radius := float64(r)
	ir := radius * 1.2
	// hour display
	openvg.FillColor(digitcolor)
	openvg.StrokeColor(digitcolor)
	openvg.StrokeWidth(5)
	for h := 12; h > 0; h-- {
		t := hourangles[h%12] * deg2rad
		fx = x + openvg.VGfloat(radius*math.Cos(t))
		fy = y + openvg.VGfloat(radius*math.Sin(t))
		ix := x + openvg.VGfloat(ir*math.Cos(t))
		iy := y + openvg.VGfloat(ir*math.Sin(t))
		if showdigits {
			openvg.TextMid(fx, fy-va, hourdigits[h%12], "sans", ts)
		} else {
			openvg.Line(fx, fy, ix, iy)
		}
	}
	// second display
	openvg.FillColor(dotcolor)
	openvg.StrokeColor(dotcolor)
	openvg.StrokeWidth(2)
	re := radius * edge
	for a := 0.0; a < 360; a += 6.0 {
		t := a * deg2rad
		sx := x + openvg.VGfloat(re*math.Cos(t))
		sy := y + openvg.VGfloat(re*math.Sin(t))
		if showdots {
			openvg.Ellipse(sx, sy, secsize, secsize)
		} else {
			ix := x + openvg.VGfloat(ir*math.Cos(t))
			iy := y + openvg.VGfloat(ir*math.Sin(t))
			openvg.Line(sx, sy, ix, iy)
		}
	}
	openvg.StrokeWidth(0)

}
Beispiel #8
0
func main() {

	width, height := openvg.Init()

	w := openvg.VGfloat(width)
	h := openvg.VGfloat(height)
	y := h / 2
	var (
		margin  openvg.VGfloat = 100.0
		minsize openvg.VGfloat = 7.0
		labeloc openvg.VGfloat = 100.0
	)
	bgcolor := "black"
	labelcolor := "white"
	maxsize := (h / 2) * 0.05

	origin := sun.distance
	mostDistant := neptune.distance
	firstSize := mercury.radius
	lastSize := neptune.radius

	openvg.Start(width, height)
	openvg.BackgroundColor(bgcolor)

	for _, p := range solarSystem {
		x := vmap(p.distance, origin, mostDistant, margin, w-margin)
		r := vmap(p.radius, firstSize, lastSize, minsize, maxsize)

		if p.name == "Sun" {
			openvg.FillRGB(p.color.Red, p.color.Green, p.color.Blue, 1)
			openvg.Circle(margin-(r/2), y, r)
		} else {
			light(x, y, r, p.color)
			openvg.Circle(x, y, r)
		}
		if p.name == "Earth" && len(os.Args) > 1 {
			openvg.StrokeColor(labelcolor)
			openvg.StrokeWidth(1)
			openvg.Line(x, y+(r/2), x, y+labeloc)
			openvg.StrokeWidth(0)
			openvg.FillColor(labelcolor)
			openvg.TextMid(x, y+labeloc+10, os.Args[1], "sans", 12)
		}
	}
	openvg.End()
	bufio.NewReader(os.Stdin).ReadByte()
	openvg.Finish()
}
Beispiel #9
0
// fontrange shows a range of fonts
func fontrange(w, h int) {
	var x, lx, length openvg.VGfloat
	y := openvg.VGfloat(h) / 2.0
	w2 := openvg.VGfloat(w) / 2.0
	spacing := openvg.VGfloat(50.0)
	s2 := spacing / 2.0
	sizes := []int{6, 7, 8, 9, 10, 11, 12, 14, 16, 18, 21, 24, 36, 48, 60, 72, 96}

	openvg.Start(w, h)
	openvg.Background(255, 255, 255)

	// compute the length so we can center
	length = 0.0
	for _, s := range sizes {
		length += openvg.VGfloat(s) + spacing
	}
	length -= spacing
	lx = w2 - (length / 2) // center point

	// for each size, display a character and label
	x = lx
	for _, s := range sizes {
		openvg.FillRGB(128, 0, 0, 1)
		openvg.TextMid(x, y, "a", "serif", s)
		openvg.FillRGB(128, 128, 128, 1)
		openvg.TextMid(x, y-spacing, fmt.Sprintf("%d", s), "sans", 16)
		x += openvg.VGfloat(s) + spacing
	}
	// draw a openvg.Line below the characters, a curve above
	x -= spacing
	openvg.StrokeRGB(150, 150, 150, 0.5)
	openvg.StrokeWidth(2)
	openvg.Line(lx, y-s2, x, y-s2)
	openvg.FillRGB(255, 255, 255, 1)
	openvg.Qbezier(lx, y+s2, x, y+s2, x, y+(spacing*3))
	openvg.End()
}
Beispiel #10
0
// plot places a plot at the specified location with the specified dimemsions
// using the specified settings, using the specified data
func plot(x, y, w, h openvg.VGfloat, settings plotset, d []rawdata) {
	nd := len(d)
	if nd < 2 {
		fmt.Fprintf(os.Stderr, "%d is not enough points to plot\n", len(d))
		return
	}
	// Compute the minima and maxima of the data
	maxx, minx := d[0].x, d[0].x
	maxy, miny := d[0].y, d[0].y
	for _, v := range d {

		if v.x > maxx {
			maxx = v.x
		}
		if v.y > maxy {
			maxy = v.y
		}
		if v.x < minx {
			minx = v.x
		}
		if v.y < miny {
			miny = v.y
		}
	}
	// Prepare for a area or line chart by allocating
	// polygon coordinates; for the horizon plot, you need two extra coordinates
	// for the extrema.
	needpoly := settings.opt["area"] || settings.opt["connect"]
	var xpoly, ypoly []openvg.VGfloat
	if needpoly {
		xpoly = make([]openvg.VGfloat, nd+2)
		ypoly = make([]openvg.VGfloat, nd+2)
		// preload the extrema of the polygon,
		// the bottom left and bottom right of the plot's rectangle
		xpoly[0] = x
		ypoly[0] = y
		xpoly[nd+1] = x + w
		ypoly[nd+1] = y
	}
	// Draw the plot's bounding rectangle
	if settings.opt["showbg"] && !settings.opt["sameplot"] {
		openvg.FillColor(settings.attr["bgcolor"])
		openvg.Rect(x, y, w, h)
	}
	// Loop through the data, drawing items as specified
	spacer := openvg.VGfloat(10.0)
	for i, v := range d {
		xp := fmap(v.x, minx, maxx, x, x+w)
		yp := fmap(v.y, miny, maxy, y, y+h)
		if needpoly {
			xpoly[i+1] = xp
			ypoly[i+1] = yp
		}
		if settings.opt["showbar"] {
			openvg.StrokeColor(settings.attr["barcolor"])
			openvg.StrokeWidth(settings.size["barsize"])
			openvg.Line(xp, yp, xp, y)
		}
		if settings.opt["showdot"] {
			openvg.FillColor(settings.attr["dotcolor"])
			openvg.StrokeWidth(0)
			openvg.Circle(xp, yp, settings.size["dotsize"])
		}
		if settings.opt["showx"] {
			if i%int(settings.size["xinterval"]) == 0 {
				openvg.FillColor("black")
				openvg.TextMid(xp, y-(spacer*2), fmt.Sprintf("%d", int(v.x)), settings.attr["font"], int(settings.size["fontsize"]))
				openvg.StrokeColor("silver")
				openvg.StrokeWidth(1)
				openvg.Line(xp, y, xp, y-spacer)
			}
			openvg.StrokeWidth(0)
		}
	}
	// Done constructing the points for the area or line plots, display them in one shot
	if settings.opt["area"] {
		openvg.FillColor(settings.attr["areacolor"])
		openvg.Polygon(xpoly, ypoly)
	}

	if settings.opt["connect"] {
		openvg.StrokeColor(settings.attr["linecolor"])
		openvg.StrokeWidth(settings.size["linesize"])
		openvg.Polyline(xpoly[1:nd+1], ypoly[1:nd+1])
	}
	// Put on the y axis labels, if specified
	if settings.opt["showy"] {
		bot := openvg.VGfloat(math.Floor(float64(miny)))
		top := openvg.VGfloat(math.Ceil(float64(maxy)))
		yrange := top - bot
		interval := yrange / openvg.VGfloat(settings.size["yinterval"])
		for yax := bot; yax <= top; yax += interval {
			yaxp := fmap(yax, bot, top, openvg.VGfloat(y), openvg.VGfloat(y+h))
			openvg.FillColor("black")
			openvg.TextEnd(x-spacer, yaxp, fmt.Sprintf("%.1f", yax), settings.attr["font"], int(settings.size["fontsize"]))
			openvg.StrokeColor("silver")
			openvg.StrokeWidth(1)
			openvg.Line(x-spacer, yaxp, x, yaxp)
		}
		openvg.StrokeWidth(0)
	}
	// Finally, tack on the label, if specified
	if len(settings.attr["label"]) > 0 {
		openvg.FillColor(settings.attr["labelcolor"], 0.3)
		openvg.TextMid(x+(w/2), y+(h/2), settings.attr["label"], settings.attr["font"], int(w/8)) // int(settings.size["fontsize"]))
	}
	openvg.StrokeWidth(0)
}
Beispiel #11
0
// refcard shows a reference card of shapes
func refcard(width, height int) {
	shapenames := []string{
		"Circle",
		"Ellipse",
		"Rectangle",
		"Rounded Rectangle",
		"Line",
		"Polyline",
		"Polygon",
		"Arc",
		"Quadratic Bezier",
		"Cubic Bezier",
		"Image",
	}
	top := openvg.VGfloat(height) * .95
	sx := openvg.VGfloat(width) * 0.10
	sy := top
	sw := openvg.VGfloat(width) * .05
	sh := openvg.VGfloat(height) * .045
	dotsize := openvg.VGfloat(7.0)
	spacing := openvg.VGfloat(2.0)
	fontsize := int(openvg.VGfloat(height) * .033)
	shapecolor := Color{202, 225, 255, 1.0}

	openvg.Start(width, height)
	openvg.FillRGB(128, 0, 0, 1)
	openvg.TextEnd(openvg.VGfloat(width-20), openvg.VGfloat(height/2),
		"OpenVG on the Raspberry Pi", "sans", fontsize+(fontsize/2))
	openvg.FillRGB(0, 0, 0, 1)
	for _, s := range shapenames {
		openvg.Text(sx+sw+sw/2, sy, s, "sans", fontsize)
		sy -= sh * spacing
	}
	sy = top
	cx := sx + (sw / 2)
	ex := sx + sw
	openvg.FillRGB(shapecolor.red, shapecolor.green, shapecolor.blue, shapecolor.alpha)
	openvg.Circle(cx, sy, sw)
	coordpoint(cx, sy, dotsize, shapecolor)
	sy -= sh * spacing
	openvg.Ellipse(cx, sy, sw, sh)
	coordpoint(cx, sy, dotsize, shapecolor)
	sy -= sh * spacing
	openvg.Rect(sx, sy, sw, sh)
	coordpoint(sx, sy, dotsize, shapecolor)
	sy -= sh * spacing
	openvg.Roundrect(sx, sy, sw, sh, 20, 20)
	coordpoint(sx, sy, dotsize, shapecolor)
	sy -= sh * spacing

	openvg.StrokeWidth(1)
	openvg.StrokeRGB(204, 204, 204, 1)
	openvg.Line(sx, sy, ex, sy)
	coordpoint(sx, sy, dotsize, shapecolor)
	coordpoint(ex, sy, dotsize, shapecolor)
	sy -= sh

	px := []openvg.VGfloat{sx, sx + (sw / 4), sx + (sw / 2), sx + ((sw * 3) / 4), sx + sw}
	py := []openvg.VGfloat{sy, sy - sh, sy, sy - sh, sy}

	openvg.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
	openvg.Polygon(px, py) // , 5)
	sy -= (sh * spacing) + sh

	openvg.Arc(sx+(sw/2), sy, sw, sh, 0, 180)
	coordpoint(sx+(sw/2), sy, dotsize, shapecolor)
	sy -= sh * spacing

	var cy, ey openvg.VGfloat
	cy = sy + (sh / 2)
	ey = sy
	openvg.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
	openvg.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)
	openvg.Image(sx, sy, 110, 110, "starx.jpg")

	openvg.End()
}
Beispiel #12
0
// showlide displays slides
func showslide(d deck.Deck, imap map[string]image.Image, n int) {

	var video videoType

	if n < 0 || n > len(d.Slide)-1 {
		return
	}
	slide := d.Slide[n]
	if slide.Bg == "" {
		slide.Bg = "white"
	}
	if slide.Fg == "" {
		slide.Fg = "black"
	}
	openvg.Start(d.Canvas.Width, d.Canvas.Height)
	cw := openvg.VGfloat(d.Canvas.Width)
	ch := openvg.VGfloat(d.Canvas.Height)
	if slide.Gradcolor1 != "" && slide.Gradcolor2 != "" {
		oc := []openvg.Offcolor{
			{0, openvg.Colorlookup(slide.Gradcolor1), 1},
			{1, openvg.Colorlookup(slide.Gradcolor2), 1},
		}
		openvg.FillLinearGradient(0, ch, 0, 0, oc)
	} else {
		openvg.FillColor(slide.Bg)
	}
	openvg.Rect(0, 0, cw, ch)
	var x, y, fs openvg.VGfloat

	// every image in the slide
	for _, im := range slide.Image {
		x = pct(im.Xp, cw)
		y = pct(im.Yp, ch)
		imw := openvg.VGfloat(im.Width)
		imh := openvg.VGfloat(im.Height)
		if im.Scale > 0 {
			imw *= openvg.VGfloat(im.Scale / 100)
			imh *= openvg.VGfloat(im.Scale / 100)
		}
		midx := openvg.VGfloat(imw / 2)
		midy := openvg.VGfloat(imh / 2)

		if im.Type == "video" {
			// Only one video per slide supported
			video.name = im.Name
			video.x = x - midx
			video.y = y - midy
			video.w = imw
			video.h = imh
			video.altimg = im.Link
		} else {
			img, ok := imap[im.Name]
			if ok {
				openvg.Img(x-midx, y-midy, img)
			}
			if len(im.Caption) > 0 {
				capfs := pctwidth(im.Sp, cw, cw/100)
				if im.Font == "" {
					im.Font = "sans"
				}
				if im.Color == "" {
					openvg.FillColor(slide.Fg)
				} else {
					openvg.FillColor(im.Color)
				}
				if im.Align == "" {
					im.Align = "center"
				}
				switch im.Align {
				case "left", "start":
					x -= midx
				case "right", "end":
					x += midx
				}
				showtext(x, y-((midy)+(capfs*2.0)), im.Caption, im.Align, im.Font, capfs)
			}
		}
	}

	// every graphic on the slide
	const defaultColor = "rgb(127,127,127)"
	const defaultSw = 1.5
	var strokeopacity float64
	// line
	for _, line := range slide.Line {
		if line.Color == "" {
			line.Color = slide.Fg // defaultColor
		}
		if line.Opacity == 0 {
			strokeopacity = 1
		} else {
			strokeopacity = line.Opacity / 100.0
		}
		x1, y1, sw := dimen(d, line.Xp1, line.Yp1, line.Sp)
		x2, y2, _ := dimen(d, line.Xp2, line.Yp2, 0)
		openvg.StrokeColor(line.Color, openvg.VGfloat(strokeopacity))
		if sw == 0 {
			sw = defaultSw
		}
		openvg.StrokeWidth(openvg.VGfloat(sw))
		openvg.StrokeColor(line.Color)
		openvg.Line(x1, y1, x2, y2)
		openvg.StrokeWidth(0)
	}
	// ellipse
	for _, ellipse := range slide.Ellipse {
		x, y, _ = dimen(d, ellipse.Xp, ellipse.Yp, 0)
		var w, h openvg.VGfloat
		w = pct(ellipse.Wp, cw)
		if ellipse.Hr == 0 { // if relative height not specified, base height on overall height
			h = pct(ellipse.Hp, ch)
		} else {
			h = pct(ellipse.Hr, w)
		}
		if ellipse.Color == "" {
			ellipse.Color = defaultColor
		}
		if ellipse.Opacity == 0 {
			ellipse.Opacity = 1
		} else {
			ellipse.Opacity /= 100
		}
		openvg.FillColor(ellipse.Color, openvg.VGfloat(ellipse.Opacity))
		openvg.Ellipse(x, y, w, h)
	}
	// rect
	for _, rect := range slide.Rect {
		x, y, _ = dimen(d, rect.Xp, rect.Yp, 0)
		var w, h openvg.VGfloat
		w = pct(rect.Wp, cw)
		if rect.Hr == 0 { // if relative height not specified, base height on overall height
			h = pct(rect.Hp, ch)
		} else {
			h = pct(rect.Hr, w)
		}
		if rect.Color == "" {
			rect.Color = defaultColor
		}
		if rect.Opacity == 0 {
			rect.Opacity = 1
		} else {
			rect.Opacity /= 100
		}
		openvg.FillColor(rect.Color, openvg.VGfloat(rect.Opacity))
		openvg.Rect(x-(w/2), y-(h/2), w, h)
	}
	// curve
	for _, curve := range slide.Curve {
		if curve.Color == "" {
			curve.Color = defaultColor
		}
		if curve.Opacity == 0 {
			strokeopacity = 1
		} else {
			strokeopacity = curve.Opacity / 100.0
		}
		x1, y1, sw := dimen(d, curve.Xp1, curve.Yp1, curve.Sp)
		x2, y2, _ := dimen(d, curve.Xp2, curve.Yp2, 0)
		x3, y3, _ := dimen(d, curve.Xp3, curve.Yp3, 0)
		openvg.StrokeColor(curve.Color, openvg.VGfloat(strokeopacity))
		openvg.FillColor(slide.Bg, openvg.VGfloat(curve.Opacity))
		if sw == 0 {
			sw = defaultSw
		}
		openvg.StrokeWidth(sw)
		openvg.Qbezier(x1, y1, x2, y2, x3, y3)
		openvg.StrokeWidth(0)
	}

	// arc
	for _, arc := range slide.Arc {
		if arc.Color == "" {
			arc.Color = defaultColor
		}
		if arc.Opacity == 0 {
			strokeopacity = 1
		} else {
			strokeopacity = arc.Opacity / 100.0
		}
		ax, ay, sw := dimen(d, arc.Xp, arc.Yp, arc.Sp)
		w := pct(arc.Wp, cw)
		h := pct(arc.Hp, cw)
		openvg.StrokeColor(arc.Color, openvg.VGfloat(strokeopacity))
		openvg.FillColor(slide.Bg, openvg.VGfloat(arc.Opacity))
		if sw == 0 {
			sw = defaultSw
		}
		openvg.StrokeWidth(sw)
		openvg.Arc(ax, ay, w, h, openvg.VGfloat(arc.A1), openvg.VGfloat(arc.A2))
		openvg.StrokeWidth(0)
	}

	// polygon
	for _, poly := range slide.Polygon {
		if poly.Color == "" {
			poly.Color = defaultColor
		}
		if poly.Opacity == 0 {
			poly.Opacity = 1
		} else {
			poly.Opacity /= 100
		}
		xs := strings.Split(poly.XC, " ")
		ys := strings.Split(poly.YC, " ")
		if len(xs) != len(ys) {
			continue
		}
		if len(xs) < 3 || len(ys) < 3 {
			continue
		}
		px := make([]openvg.VGfloat, len(xs))
		py := make([]openvg.VGfloat, len(ys))
		for i := 0; i < len(xs); i++ {
			x, err := strconv.ParseFloat(xs[i], 32)
			if err != nil {
				px[i] = 0
			} else {
				px[i] = pct(x, cw)
			}
			y, err := strconv.ParseFloat(ys[i], 32)
			if err != nil {
				py[i] = 0
			} else {
				py[i] = pct(y, ch)
			}
		}
		openvg.FillColor(poly.Color, openvg.VGfloat(poly.Opacity))
		openvg.Polygon(px, py)
	}

	openvg.FillColor(slide.Fg)

	// every list in the slide
	var offset, textopacity openvg.VGfloat
	const blinespacing = 2.4
	for _, l := range slide.List {
		if l.Font == "" {
			l.Font = "sans"
		}
		x, y, fs = dimen(d, l.Xp, l.Yp, l.Sp)
		if l.Type == "bullet" {
			offset = 1.2 * fs
		} else {
			offset = 0
		}
		if l.Lp == 0 {
			l.Lp = blinespacing
		}
		if l.Opacity == 0 {
			textopacity = 1
		} else {
			textopacity = openvg.VGfloat(l.Opacity / 100)
		}
		// every list item
		var li, lifont string
		for ln, tl := range l.Li {
			if len(l.Color) > 0 {
				openvg.FillColor(l.Color, textopacity)
			} else {
				openvg.FillColor(slide.Fg)
			}
			if l.Type == "bullet" {
				boffset := fs / 2
				openvg.Ellipse(x, y+boffset, boffset, boffset)
				//openvg.Rect(x, y+boffset/2, boffset, boffset)
			}
			if l.Type == "number" {
				li = fmt.Sprintf("%d. ", ln+1) + tl.ListText
			} else {
				li = tl.ListText
			}
			if len(tl.Color) > 0 {
				openvg.FillColor(tl.Color, textopacity)
			}
			if len(tl.Font) > 0 {
				lifont = tl.Font
			} else {
				lifont = l.Font
			}
			showtext(x+offset, y, li, l.Align, lifont, fs)
			y -= fs * openvg.VGfloat(l.Lp)
		}
	}
	openvg.FillColor(slide.Fg)

	// every text in the slide
	const linespacing = 1.8

	var tdata string
	for _, t := range slide.Text {
		if t.File != "" {
			tdata = includefile(t.File)
		} else {
			tdata = t.Tdata
		}
		if t.Font == "" {
			t.Font = "sans"
		}
		if t.Opacity == 0 {
			textopacity = 1
		} else {
			textopacity = openvg.VGfloat(t.Opacity / 100)
		}
		if t.Lp == 0 {
			t.Lp = linespacing
		}
		x, y, fs = dimen(d, t.Xp, t.Yp, t.Sp)
		td := strings.Split(tdata, "\n")
		if t.Type == "code" {
			ls := fs * openvg.VGfloat(t.Lp)
			t.Font = "mono"
			tdepth := (ls * openvg.VGfloat(len(td))) + fs
			openvg.FillColor("rgb(240,240,240)")
			openvg.Rect(x-20, y-tdepth+(ls), pctwidth(t.Wp, cw, cw-x-20), tdepth)
		}
		if t.Color == "" {
			openvg.FillColor(slide.Fg, textopacity)
		} else {
			openvg.FillColor(t.Color, textopacity)
		}
		if t.Type == "block" {
			textwrap(x, y, pctwidth(t.Wp, cw, cw/2), tdata, t.Font, fs, fs*openvg.VGfloat(t.Lp), 0.3)
		} else {
			// every text line
			ls := fs * openvg.VGfloat(t.Lp)
			for _, txt := range td {
				showtext(x, y, txt, t.Align, t.Font, fs)
				y -= ls
			}
		}
	}
	openvg.FillColor(slide.Fg)
	openvg.End()
	if video.altimg != "" {
		img, ok := imap[video.altimg]
		if ok {
			openvg.Img(video.x, video.y, img)
		}
	}
	if video.name != "" {
		openvg.Video(video.x, video.y, video.w, video.h, video.name)
	}
}