Example #1
0
func (t *textureImpl) draw(xp render.Picture, src2dst *f64.Aff3, sr image.Rectangle, op draw.Op, w, h int, opts *screen.DrawOptions) {
	// TODO: honor sr.Max

	t.renderMu.Lock()
	defer t.renderMu.Unlock()

	// For simple copies and scales, the inverse matrix is trivial to compute,
	// and we do not need the "Src becomes OutReverse plus Over" dance (see
	// below). Thus, draw can be one render.SetPictureTransform call and then
	// one render.Composite call, regardless of whether or not op is Src.
	if src2dst[1] == 0 && src2dst[3] == 0 {
		dstXMin := float64(sr.Min.X)*src2dst[0] + src2dst[2]
		dstXMax := float64(sr.Max.X)*src2dst[0] + src2dst[2]
		if dstXMin > dstXMax {
			// TODO: check if this (and below) works when src2dst[0] < 0.
			dstXMin, dstXMax = dstXMax, dstXMin
		}
		dXMin := int(math.Floor(dstXMin))
		dXMax := int(math.Ceil(dstXMax))

		dstYMin := float64(sr.Min.Y)*src2dst[4] + src2dst[5]
		dstYMax := float64(sr.Max.Y)*src2dst[4] + src2dst[5]
		if dstYMin > dstYMax {
			// TODO: check if this (and below) works when src2dst[4] < 0.
			dstYMin, dstYMax = dstYMax, dstYMin
		}
		dYMin := int(math.Floor(dstYMin))
		dYMax := int(math.Ceil(dstYMax))

		render.SetPictureTransform(t.s.xc, t.xp, render.Transform{
			f64ToFixed(1 / src2dst[0]), 0, 0,
			0, f64ToFixed(1 / src2dst[4]), 0,
			0, 0, 1 << 16,
		})
		render.Composite(t.s.xc, renderOp(op), t.xp, 0, xp,
			int16(sr.Min.X), int16(sr.Min.Y), // SrcX, SrcY,
			0, 0, // MaskX, MaskY,
			int16(dXMin), int16(dYMin), // DstX, DstY,
			uint16(dXMax-dXMin), uint16(dYMax-dYMin), // Width, Height,
		)
		return
	}

	// The X11/Render transform matrix maps from destination pixels to source
	// pixels, so we invert src2dst.
	dst2src := inv(src2dst)
	render.SetPictureTransform(t.s.xc, t.xp, render.Transform{
		f64ToFixed(dst2src[0]), f64ToFixed(dst2src[1]), f64ToFixed(dst2src[2]),
		f64ToFixed(dst2src[3]), f64ToFixed(dst2src[4]), f64ToFixed(dst2src[5]),
		0, 0, 1 << 16,
	})

	if op == draw.Src {
		// render.Composite visits every dst-space pixel in the rectangle
		// defined by its args DstX, DstY, Width, Height. That axis-aligned
		// bounding box (AABB) must contain the transformation of the sr
		// rectangle in src-space to a quad in dst-space, but it need not be
		// the smallest possible AABB.
		//
		// In any case, for arbitrary src2dst affine transformations, which
		// include rotations, this means that a naive render.Composite call
		// will affect those pixels inside the AABB but outside the quad. For
		// the draw.Src operator, this means that pixels in that AABB can be
		// incorrectly set to zero.
		//
		// Instead, we implement the draw.Src operator as two render.Composite
		// calls. The first one (using the PictOpOutReverse operator) clears
		// the dst-space quad but leaves pixels outside that quad (but inside
		// the AABB) untouched. The second one (using the PictOpOver operator)
		// fills in the quad and again does not touch the pixels outside.
		//
		// What X11/Render calls PictOpOutReverse is also known as dst-out. See
		// http://www.w3.org/TR/SVGCompositing/examples/compop-porterduff-examples.png
		// for a visualization.
		//
		// The arguments to this render.Composite call are identical to the
		// second one call below, other than the compositing operator.
		//
		// TODO: the source picture for this call needs to be fully opaque even
		// if t.xp isn't.
		render.Composite(t.s.xc, render.PictOpOutReverse, t.xp, 0, xp,
			int16(sr.Min.X), int16(sr.Min.Y), 0, 0, 0, 0, uint16(w), uint16(h),
		)
	}

	// TODO: tighten the (0, 0)-(w, h) dst rectangle. As it is, we're
	// compositing an unnecessarily large number of pixels.

	render.Composite(t.s.xc, render.PictOpOver, t.xp, 0, xp,
		int16(sr.Min.X), int16(sr.Min.Y), // SrcX, SrcY,
		0, 0, // MaskX, MaskY,
		0, 0, // DstX, DstY,
		uint16(w), uint16(h), // Width, Height,
	)
}
Example #2
0
func (t *textureImpl) draw(xp render.Picture, src2dst *f64.Aff3, sr image.Rectangle, op draw.Op, w, h int, opts *screen.DrawOptions) {
	// TODO: honor sr.Max

	// TODO: use a mutex a la https://go-review.googlesource.com/14861, so that
	// the render.Xxx calls in this method are effectively one atomic
	// operation, in case multiple concurrent Draw(etc, t, etc) calls occur.

	// TODO: recognize simple copies or scales, which do not need the "Src
	// becomes OutReverse plus Over" dance and can be one simple
	// render.Composite(etc, renderOp(op), etc) call, regardless of whether or
	// not op is Src.

	// The XTransform matrix maps from destination pixels to source
	// pixels, so we invert src2dst.
	dst2src := inv(src2dst)
	render.SetPictureTransform(t.s.xc, t.xp, render.Transform{
		f64ToFixed(dst2src[0]), f64ToFixed(dst2src[1]), f64ToFixed(dst2src[2]),
		f64ToFixed(dst2src[3]), f64ToFixed(dst2src[4]), f64ToFixed(dst2src[5]),
		f64ToFixed(0), f64ToFixed(0), f64ToFixed(1),
	})

	if op == draw.Src {
		// render.Composite visits every dst-space pixel in the rectangle
		// defined by its args DstX, DstY, Width, Height. That axis-aligned
		// bounding box (AABB) must contain the transformation of the sr
		// rectangle in src-space to a quad in dst-space, but it need not be
		// the smallest possible AABB.
		//
		// In any case, for arbitrary src2dst affine transformations, which
		// include rotations, this means that a naive render.Composite call
		// will affect those pixels inside the AABB but outside the quad. For
		// the draw.Src operator, this means that pixels in that AABB can be
		// incorrectly set to zero.
		//
		// Instead, we implement the draw.Src operator as two render.Composite
		// calls. The first one (using the PictOpOutReverse operator) clears
		// the dst-space quad but leaves pixels outside that quad (but inside
		// the AABB) untouched. The second one (using the PictOpOver operator)
		// fills in the quad and again does not touch the pixels outside.
		//
		// What X11/Render calls PictOpOutReverse is also known as dst-out. See
		// http://www.w3.org/TR/SVGCompositing/examples/compop-porterduff-examples.png
		// for a visualization.
		//
		// The arguments to this render.Composite call are identical to the
		// second one call below, other than the compositing operator.
		//
		// TODO: the source picture for this call needs to be fully opaque even
		// if t.xp isn't.
		render.Composite(t.s.xc, render.PictOpOutReverse, t.xp, 0, xp,
			int16(sr.Min.X), int16(sr.Min.Y), 0, 0, 0, 0, uint16(w), uint16(h),
		)
	}

	// TODO: tighten the (0, 0)-(w, h) dst rectangle. As it is, we're
	// compositing an unnecessarily large number of pixels.

	render.Composite(t.s.xc, render.PictOpOver, t.xp, 0, xp,
		int16(sr.Min.X), int16(sr.Min.Y), // SrcX, SrcY,
		0, 0, // MaskX, MaskY,
		0, 0, // DstX, DstY,
		uint16(w), uint16(h), // Width, Height,
	)
}