diff options
| author | Přemysl Janouch <p@janouch.name> | 2018-09-06 18:12:47 +0200 | 
|---|---|---|
| committer | Přemysl Janouch <p@janouch.name> | 2018-09-06 18:17:30 +0200 | 
| commit | 632b3ae494d45755525644fe5d04475c95aae364 (patch) | |
| tree | 5800fd7d07ff9e3c2051fddb8c78736341800383 | |
| parent | e8381d86ce4fb13b83e85b4554143efa8c8620ba (diff) | |
| download | haven-632b3ae494d45755525644fe5d04475c95aae364.tar.gz haven-632b3ae494d45755525644fe5d04475c95aae364.tar.xz haven-632b3ae494d45755525644fe5d04475c95aae364.zip | |
xgb-draw: double buffer, change color, cleanup
| -rw-r--r-- | prototypes/xgb-draw.go | 105 | 
1 files changed, 60 insertions, 45 deletions
| diff --git a/prototypes/xgb-draw.go b/prototypes/xgb-draw.go index 7a1bdfc..b893f6f 100644 --- a/prototypes/xgb-draw.go +++ b/prototypes/xgb-draw.go @@ -1,9 +1,6 @@  // Network-friendly drawing application based on XRender.  // -// TODO -//  - use double buffering to remove flicker -//    (more pronounced over X11 forwarding) -//  - maybe keep the pixmap as large as the window +// TODO: Maybe keep the pixmap as large as the window.  package main  import ( @@ -26,6 +23,23 @@ func findPictureFormat(formats []render.Pictforminfo,  	return 0  } +func createNewPicture(X *xgb.Conn, depth byte, drawable xproto.Drawable, +	width uint16, height uint16, format render.Pictformat) render.Picture { +	pixmapid, err := xproto.NewPixmapId(X) +	if err != nil { +		log.Fatalln(err) +	} +	_ = xproto.CreatePixmap(X, depth, pixmapid, drawable, width, height) + +	pictid, err := render.NewPictureId(X) +	if err != nil { +		log.Fatalln(err) +	} +	_ = render.CreatePicture(X, pictid, xproto.Drawable(pixmapid), format, +		0, []uint32{}) +	return pictid +} +  func main() {  	X, err := xgb.NewConn()  	if err != nil { @@ -125,53 +139,44 @@ func main() {  		log.Fatalln(err)  	}  	_ = render.CreateSolidFill(X, colorid, render.Color{ -		Red:   0xeeee, +		Red:   0x4444,  		Green: 0x8888, -		Blue:  0x4444, +		Blue:  0xffff,  		Alpha: 0xffff,  	}) -	// Pixmaps. +	// Various pixmaps.  	const (  		pixWidth  = 1000  		pixHeight = 1000  	) -	pixid, err := xproto.NewPixmapId(X) -	if err != nil { -		log.Fatalln(err) -	} -	_ = xproto.CreatePixmap(X, 24, pixid, xproto.Drawable(screen.Root), -		pixWidth, pixHeight) - -	pixpictid, err := render.NewPictureId(X) -	if err != nil { -		log.Fatalln(err) -	} -	render.CreatePicture(X, pixpictid, xproto.Drawable(pixid), -		pformatRGB, 0, []uint32{}) - -	pixmaskid, err := xproto.NewPixmapId(X) -	if err != nil { -		log.Fatalln(err) -	} -	_ = xproto.CreatePixmap(X, 8, pixmaskid, xproto.Drawable(screen.Root), -		pixWidth, pixHeight) +	canvasid := createNewPicture(X, 24, +		xproto.Drawable(screen.Root), pixWidth, pixHeight, pformatRGB) +	bufferid := createNewPicture(X, 24, +		xproto.Drawable(screen.Root), pixWidth, pixHeight, pformatRGB) +	maskid := createNewPicture(X, 8, +		xproto.Drawable(screen.Root), pixWidth, pixHeight, pformatAlpha) -	pixmaskpictid, err := render.NewPictureId(X) -	if err != nil { -		log.Fatalln(err) -	} -	render.CreatePicture(X, pixmaskpictid, xproto.Drawable(pixmaskid), -		pformatAlpha, 0, []uint32{}) +	// Smoothing by way of blur, apparently a misguided idea. +	/* +		_ = render.SetPictureFilter(X, maskid, +			uint16(len("convolution")), "convolution", +			[]render.Fixed{F64ToFixed(3), F64ToFixed(3), +				F64ToFixed(0), F64ToFixed(0.15), F64ToFixed(0), +				F64ToFixed(0.15), F64ToFixed(0.40), F64ToFixed(0.15), +				F64ToFixed(0), F64ToFixed(0.15), F64ToFixed(0)}) +	*/  	// Pixmaps come uninitialized. -	render.FillRectangles(X, -		render.PictOpSrc, pixpictid, render.Color{ +	_ = render.FillRectangles(X, +		render.PictOpSrc, canvasid, render.Color{  			Red: 0xffff, Green: 0xffff, Blue: 0xffff, Alpha: 0xffff,  		}, []xproto.Rectangle{{Width: pixWidth, Height: pixHeight}}) -	// This is the only method we can use to render proper brush strokes. +	// This is the only method we can use to render brush strokes without +	// alpha accumulation due to stamping. Though this also seems to be +	// misguided. Keeping it here for educational purposes.  	//  	// ConjointOver is defined as: A = Aa * 1 + Ab * max(1-Aa/Ab,0)  	// which basically resolves to: A = max(Aa, Ab) @@ -184,20 +189,28 @@ func main() {  	//  - https://keithp.com/~keithp/talks/cairo2003.pdf  	drawPointAt := func(x, y int16) {  		_ = render.Composite(X, render.PictOpConjointOver, -			brushid, render.PictureNone, pixmaskpictid, +			brushid, render.PictureNone, maskid,  			0, 0, 0, 0, x-brushRadius, y-brushRadius,  			brushRadius*2, brushRadius*2) -		_ = render.SetPictureClipRectangles(X, pid, +		_ = render.SetPictureClipRectangles(X, bufferid,  			x-brushRadius, y-brushRadius, []xproto.Rectangle{  				{Width: brushRadius * 2, Height: brushRadius * 2}}) -  		_ = render.Composite(X, render.PictOpSrc, -			pixpictid, render.PictureNone, pid, +			canvasid, render.PictureNone, bufferid,  			0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */  			pixWidth, pixHeight)  		_ = render.Composite(X, render.PictOpOver, -			colorid, pixmaskpictid, pid, +			colorid, maskid, bufferid, +			0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */ +			pixWidth, pixHeight) + +		// Composited, now blit to window without flicker. +		_ = render.SetPictureClipRectangles(X, pid, +			x-brushRadius, y-brushRadius, []xproto.Rectangle{ +				{Width: brushRadius * 2, Height: brushRadius * 2}}) +		_ = render.Composite(X, render.PictOpSrc, +			bufferid, render.PictureNone, pid,  			0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */  			pixWidth, pixHeight)  	} @@ -271,14 +284,16 @@ func main() {  			_ = render.SetPictureClipRectangles(X, pid, int16(e.X), int16(e.Y),  				[]xproto.Rectangle{{Width: e.Width, Height: e.Height}}) +			// Not bothering to deflicker here using the buffer pixmap, +			// with compositing this event is rare enough.  			_ = render.Composite(X, render.PictOpSrc, -				pixpictid, render.PictureNone, pid, +				canvasid, render.PictureNone, pid,  				0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */  				pixWidth, pixHeight)  			if drawing {  				_ = render.Composite(X, render.PictOpOver, -					colorid, pixmaskpictid, pid, +					colorid, maskid, pid,  					0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */  					pixWidth, pixHeight)  			} @@ -286,7 +301,7 @@ func main() {  		case xproto.ButtonPressEvent:  			if e.Detail == xproto.ButtonIndex1 {  				render.FillRectangles(X, -					render.PictOpSrc, pixmaskpictid, render.Color{}, +					render.PictOpSrc, maskid, render.Color{},  					[]xproto.Rectangle{{Width: pixWidth, Height: pixHeight}})  				drawing = true @@ -303,7 +318,7 @@ func main() {  		case xproto.ButtonReleaseEvent:  			if e.Detail == xproto.ButtonIndex1 {  				_ = render.Composite(X, render.PictOpOver, -					colorid, pixmaskpictid, pixpictid, +					colorid, maskid, canvasid,  					0, 0, 0, 0, 0 /* dst-x */, 0, /* dst-y */  					pixWidth, pixHeight) | 
