• Stars
    star
    124
  • Rank 288,207 (Top 6 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 6 years ago
  • Updated almost 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Convenience package for dealing with graphics in my pixel drawing experiments.

gfx

Build status Go Report Card GoDoc License MIT

Convenience package for dealing with graphics in my pixel drawing experiments.

⚠️ NO STABILITY GUARANTEES ⚠️

Triangles

Triangles can be drawn to an image using a *gfx.DrawTarget.

gfx-triangles

package main

import "github.com/peterhellberg/gfx"

var p = gfx.PaletteFamicube

func main() {
	n := 50
	m := gfx.NewPaletted(900, 270, p, p.Color(n+7))
	t := gfx.NewDrawTarget(m)

	t.MakeTriangles(&gfx.TrianglesData{
		vx(114, 16, n+1), vx(56, 142, n+2), vx(352, 142, n+3),
		vx(350, 142, n+4), vx(500, 50, n+5), vx(640, 236, n+6),
		vx(640, 70, n+8), vx(820, 160, n+9), vx(670, 236, n+10),
	}).Draw()

	gfx.SavePNG("gfx-example-triangles.png", m)
}

func vx(x, y float64, n int) gfx.Vertex {
	return gfx.Vertex{Position: gfx.V(x, y), Color: p.Color(n)}
}

Polygons

A gfx.Polygon is represented by a list of vectors. There is also gfx.Polyline which is a slice of polygons forming a line.

gfx-example-polygon

package main

import "github.com/peterhellberg/gfx"

var edg32 = gfx.PaletteEDG32

func main() {
	m := gfx.NewNRGBA(gfx.IR(0, 0, 1024, 256))
	p := gfx.Polygon{
		{80, 40},
		{440, 60},
		{700, 200},
		{250, 230},
		{310, 140},
	}

	p.EachPixel(m, func(x, y int) {
		pv := gfx.IV(x, y)
		l := pv.To(p.Rect().Center()).Len()

		gfx.Mix(m, x, y, edg32.Color(int(l/18)%32))
	})

	for n, v := range p {
		c := edg32.Color(n * 4)

		gfx.DrawCircle(m, v, 15, 8, gfx.ColorWithAlpha(c, 96))
		gfx.DrawCircle(m, v, 16, 1, c)
	}

	gfx.SavePNG("gfx-example-polygon.png", m)
}

Blocks

You can draw (isometric) blocks using the gfx.Blocks and gfx.Block types.

gfx-example-blocks

package main

import "github.com/peterhellberg/gfx"

func main() {
	var (
		dst    = gfx.NewPaletted(898, 330, gfx.PaletteGo, gfx.PaletteGo[14])
		rect   = gfx.BoundsToRect(dst.Bounds())
		origin = rect.Center().ScaledXY(gfx.V(1.5, -2.5)).Vec3(0.55)
		blocks gfx.Blocks
	)

	for i, bc := range gfx.BlockColorsGo {
		var (
			f    = float64(i) + 0.5
			v    = f * 11
			pos  = gfx.V3(290+(v*3), 8.5*v, 9*(f+2))
			size = gfx.V3(90, 90, 90)
		)

		blocks.AddNewBlock(pos, size, bc)
	}

	blocks.Draw(dst, origin)

	gfx.SavePNG("gfx-example-blocks.png", dst)
}

Signed Distance Functions

The gfx.SignedDistance type allows you to use basic signed distance functions (and operations) to produce some interesting graphics.

gfx-example-sdf

package main

import "github.com/peterhellberg/gfx"

func main() {
	c := gfx.PaletteEDG36.Color
	m := gfx.NewImage(1024, 256, c(5))

	gfx.EachPixel(m.Bounds(), func(x, y int) {
		sd := gfx.SignedDistance{gfx.IV(x, y)}

		if d := sd.OpRepeat(gfx.V(128, 128), func(sd gfx.SignedDistance) float64 {
			return sd.OpSubtraction(sd.Circle(50), sd.Line(gfx.V(0, 0), gfx.V(64, 64)))
		}); d < 40 {
			m.Set(x, y, c(int(gfx.MathAbs(d/5))))
		}
	})

	gfx.SavePNG("gfx-example-sdf.png", m)
}

Domain Coloring

You can use the CmplxPhaseAt method on a gfx.Palette to do domain coloring.

gfx-example-domain-coloring

package main

import "github.com/peterhellberg/gfx"

const (
	w, h        = 1800, 540
	fovY        = 1.9
	aspectRatio = float64(w) / float64(h)
	centerReal  = 0
	centerImag  = 0
	ahc         = aspectRatio*fovY/2.0 + centerReal
	hfc         = fovY/2.0 + centerImag
)

func pixelCoordinates(px, py int) gfx.Vec {
	return gfx.V(
		((float64(px)/(w-1))*2-1)*ahc,
		((float64(h-py-1)/(h-1))*2-1)*hfc,
	)
}

func main() {
	var (
		p  = gfx.PaletteEN4
		p0 = pixelCoordinates(0, 0)
		p1 = pixelCoordinates(w-1, h-1)
		y  = p0.Y
		d  = gfx.V((p1.X-p0.X)/(w-1), (p1.Y-p0.Y)/(h-1))
		m  = gfx.NewImage(w, h)
	)

	for py := 0; py < h; py++ {
		x := p0.X

		for px := 0; px < w; px++ {
			cc := p.CmplxPhaseAt(gfx.CmplxCos(gfx.CmplxSin(0.42 / complex(y*x, x*x))))

			m.Set(px, py, cc)

			x += d.X
		}

		y += d.Y
	}

	gfx.SavePNG("gfx-example-domain-coloring.png", m)
}

Animation

There is rudimentary support for making animations using gfx.Animation, the animations can then be encoded into GIF.

gfx-example-animation

package main

import "github.com/peterhellberg/gfx"

func main() {
	a := &gfx.Animation{}
	p := gfx.PaletteEDG36

	var fireflower = []uint8{
		0, 1, 1, 1, 1, 1, 1, 0,
		1, 1, 2, 2, 2, 2, 1, 1,
		1, 2, 3, 3, 3, 3, 2, 1,
		1, 1, 2, 2, 2, 2, 1, 1,
		0, 1, 1, 1, 1, 1, 1, 0,
		0, 0, 0, 4, 4, 0, 0, 0,
		0, 0, 0, 4, 4, 0, 0, 0,
		4, 4, 0, 4, 4, 0, 4, 4,
		0, 4, 0, 4, 4, 0, 4, 0,
		0, 4, 4, 4, 4, 4, 4, 0,
		0, 0, 4, 4, 4, 4, 0, 0,
	}

	for i := 0; i < len(p)-4; i++ {
		t := gfx.NewTile(p[i:i+4], 8, fireflower)

		a.AddPalettedImage(gfx.NewScaledPalettedImage(t, 20))
	}

	a.SaveGIF("gfx-example-animation.gif")
}

Line drawing

DrawInt functions

Drawing functions based on TinyDraw, which in turn is based on the Adafruit GFX library.

gfx-example-draw-int

package main

import "github.com/peterhellberg/gfx"

func main() {
	m := gfx.NewImage(160, 128, gfx.ColorTransparent)

	p := gfx.PaletteNight16

	gfx.DrawIntLine(m, 10, 10, 94, 10, p.Color(0))
	gfx.DrawIntLine(m, 94, 16, 10, 16, p.Color(1))
	gfx.DrawIntLine(m, 10, 20, 10, 118, p.Color(2))
	gfx.DrawIntLine(m, 16, 118, 16, 20, p.Color(4))

	gfx.DrawIntLine(m, 40, 40, 80, 80, p.Color(5))
	gfx.DrawIntLine(m, 40, 40, 80, 70, p.Color(6))
	gfx.DrawIntLine(m, 40, 40, 80, 60, p.Color(7))
	gfx.DrawIntLine(m, 40, 40, 80, 50, p.Color(8))
	gfx.DrawIntLine(m, 40, 40, 80, 40, p.Color(9))

	gfx.DrawIntLine(m, 100, 100, 40, 100, p.Color(10))
	gfx.DrawIntLine(m, 100, 100, 40, 90, p.Color(11))
	gfx.DrawIntLine(m, 100, 100, 40, 80, p.Color(12))
	gfx.DrawIntLine(m, 100, 100, 40, 70, p.Color(13))
	gfx.DrawIntLine(m, 100, 100, 40, 60, p.Color(14))
	gfx.DrawIntLine(m, 100, 100, 40, 50, p.Color(15))

	gfx.DrawIntRectangle(m, 30, 106, 120, 20, p.Color(14))
	gfx.DrawIntFilledRectangle(m, 34, 110, 112, 12, p.Color(8))

	gfx.DrawIntCircle(m, 120, 30, 20, p.Color(5))
	gfx.DrawIntFilledCircle(m, 120, 30, 16, p.Color(4))

	gfx.DrawIntTriangle(m, 120, 102, 100, 80, 152, 46, p.Color(9))
	gfx.DrawIntFilledTriangle(m, 119, 98, 105, 80, 144, 54, p.Color(6))

	s := gfx.NewScaledImage(m, 6)

	gfx.SavePNG("gfx-example-draw-int.png", s)
}

Bresenham's line algorithm

gfx.DrawLineBresenham draws a line using Bresenham's line algorithm.

gfx-example-bresenham-line

package main

import "github.com/peterhellberg/gfx"

var (
	red   = gfx.BlockColorRed.Medium
	green = gfx.BlockColorGreen.Medium
	blue  = gfx.BlockColorBlue.Medium
)

func main() {
	m := gfx.NewImage(32, 16, gfx.ColorTransparent)

	gfx.DrawLineBresenham(m, gfx.V(2, 2), gfx.V(2, 14), red)
	gfx.DrawLineBresenham(m, gfx.V(6, 2), gfx.V(32, 2), green)
	gfx.DrawLineBresenham(m, gfx.V(6, 6), gfx.V(30, 14), blue)

	s := gfx.NewScaledImage(m, 16)

	gfx.SavePNG("gfx-example-bresenham-line.png", s)
}

Geometry and Transformation

The (2D) geometry and transformation types are based on those found in https://github.com/faiface/pixel (but indended for use without Pixel)

2D types

Vec

gfx.Vec is a 2D vector type with X and Y components.

Rect

gfx.Rect is a 2D rectangle aligned with the axes of the coordinate system. It is defined by two gfx.Vec, Min and Max.

Matrix

gfx.Matrix is a 2x3 affine matrix that can be used for all kinds of spatial transforms, such as movement, scaling and rotations.

gfx-readme-examples-matrix

package main

import "github.com/peterhellberg/gfx"

var en4 = gfx.PaletteEN4

func main() {
	a := &gfx.Animation{Delay: 10}

	c := gfx.V(128, 128)

	p := gfx.Polygon{
		{50, 50},
		{50, 206},
		{128, 96},
		{206, 206},
		{206, 50},
	}

	for d := 0.0; d < 360; d += 2 {
		m := gfx.NewPaletted(256, 256, en4, en4.Color(3))

		matrix := gfx.IM.RotatedDegrees(c, d)

		gfx.DrawPolygon(m, p.Project(matrix), 0, en4.Color(2))
		gfx.DrawPolygon(m, p.Project(matrix.Scaled(c, 0.5)), 0, en4.Color(1))

		gfx.DrawCircleFilled(m, c, 5, en4.Color(0))

		a.AddPalettedImage(m)
	}

	a.SaveGIF("/tmp/gfx-readme-examples-matrix.gif")
}

3D types

Vec3

gfx.Vec3 is a 3D vector type with X, Y and Z components.

Box

gfx.Box is a 3D box. It is defined by two gfx.Vec3, Min and Max

Errors

The gfx.Error type is a string that implements the error interface.

If you are using Ebiten then you can return the provided gfx.ErrDone error to exit its run loop.

HTTP

You can use gfx.GetPNG to download and decode a PNG given an URL.

Log

I find that it is fairly common for me to do some logging driven development when experimenting with graphical effects, so I've included gfx.Log, gfx.Dump, gfx.Printf and gfx.Sprintf in this package.

Math

I have included a few functions that call functions in the math package.

There is also gfx.Sign, gfx.Clamp and gfx.Lerp functions for float64.

Cmplx

I have included a few functions that call functions in the cmplx package.

Reading files

It is fairly common to read files in my experiments, so I've included gfx.ReadFile and gfx.ReadJSON in this package.

Resizing images

You can use gfx.ResizeImage to resize an image. (nearest neighbor, mainly useful for pixelated graphics)

Noise

Different types of noise is often used in procedural generation.

SimplexNoise

SimplexNoise is a speed-improved simplex noise algorithm for 2D, 3D and 4D.

gfx-example-simplex

package main

import "github.com/peterhellberg/gfx"

func main() {
	sn := gfx.NewSimplexNoise(17)

	dst := gfx.NewImage(1024, 256)

	gfx.EachImageVec(dst, gfx.ZV, func(u gfx.Vec) {
		n := sn.Noise2D(u.X/900, u.Y/900)
		c := gfx.PaletteSplendor128.At(n / 2)

		gfx.SetVec(dst, u, c)
	})

	gfx.SavePNG("gfx-example-simplex.png", dst)
}

Colors

You can construct new colors using gfx.ColorRGBA, gfx.ColorNRGBA, gfx.ColorGray, gfx.ColorGray16 and gfx.ColorWithAlpha.

There is also a gfx.LerpColors function that performs linear interpolation between two colors.

Default colors

There are a few default colors in this package, convenient when you just want to experiment, for more ambitious projects I suggest creating a gfx.Palette (or even use one of the included palettes).

Variable Color
gfx.ColorBlack gfx.ColorBlack
gfx.ColorWhite gfx.ColorWhite
gfx.ColorTransparent gfx.ColorTransparent
gfx.ColorOpaque gfx.ColorOpaque
gfx.ColorRed gfx.ColorRed
gfx.ColorGreen gfx.ColorGreen
gfx.ColorBlue gfx.ColorBlue
gfx.ColorCyan gfx.ColorCyan
gfx.ColorMagenta gfx.ColorMagenta
gfx.ColorYellow gfx.ColorYellow

Block colors

Each gfx.BlockColor consists of a Dark, Medium and Light shade of the same color.

Variable Block Color
gfx.BlockColorYellow gfx.BlockColorYellow
gfx.BlockColorOrange gfx.BlockColorOrange
gfx.BlockColorBrown gfx.BlockColorBrown
gfx.BlockColorGreen gfx.BlockColorGreen
gfx.BlockColorBlue gfx.BlockColorBlue
gfx.BlockColorPurple gfx.BlockColorPurple
gfx.BlockColorRed gfx.BlockColorRed
gfx.BlockColorWhite gfx.BlockColorWhite
gfx.BlockColorBlack gfx.BlockColorBlack
gfx.BlockColorGoGopherBlue gfx.BlockColorGoGopherBlue
gfx.BlockColorGoLightBlue gfx.BlockColorGoLightBlue
gfx.BlockColorGoAqua gfx.BlockColorGoAqua
gfx.BlockColorGoFuchsia gfx.BlockColorGoFuchsia
gfx.BlockColorGoBlack gfx.BlockColorGoBlack
gfx.BlockColorGoYellow gfx.BlockColorGoYellow

Palettes

There are a number of palettes in the gfx package, most of them are found in the Lospec Palette List.

Variable Colors Lospec Palette
gfx.Palette1Bit 2 Palette1Bit
gfx.Palette2BitGrayScale 4 Palette2BitGrayScale
gfx.PaletteEN4 4 PaletteEN4
gfx.PaletteARQ4 4 PaletteARQ4
gfx.PaletteInk 5 PaletteInk
gfx.Palette3Bit 8 Palette3Bit
gfx.PaletteEDG8 8 PaletteEDG8
gfx.PaletteAmmo8 8 PaletteAmmo8
gfx.PaletteNYX8 8 PaletteNYX8
gfx.Palette15PDX 15 Palette15PDX
gfx.PaletteCGA 16 PaletteCGA
gfx.PalettePICO8 16 PalettePICO8
gfx.PaletteNight16 16 PaletteNight16
gfx.PaletteAAP16 16 PaletteAAP16
gfx.PaletteArne16 16 PaletteArne16
gfx.PaletteEDG16 16 PaletteEDG16
gfx.Palette20PDX 20 Palette20PDX
gfx.PaletteTango 27 PaletteTango
gfx.PaletteEDG32 32 PaletteEDG32
gfx.PaletteEDG36 36 PaletteEDG36
gfx.PaletteEDG64 64 PaletteEDG64
gfx.PaletteAAP64 64 PaletteAAP64
gfx.PaletteFamicube 64 PaletteFamicube
gfx.PaletteSplendor128 128 PaletteSplendor128

The palette images were generated like this:

package main

import "github.com/peterhellberg/gfx"

func main() {
	for size, paletteLookup := range gfx.PalettesByNumberOfColors {
		for name, palette := range paletteLookup {
			dst := gfx.NewImage(size, 1)

			for x, c := range palette {
				dst.Set(x, 0, c)
			}

			filename := gfx.Sprintf("gfx-Palette%s.png", name)

			gfx.SavePNG(filename, gfx.NewResizedImage(dst, 1120, 96))
		}
	}
}

License (MIT)

Copyright (c) 2019-2021 Peter Hellberg

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

More Repositories

1

hashids.rb

A small Ruby gem to generate YouTube-like hashes from one or many numbers. Use hashids when you do not want to expose your database ids to the user.
Ruby
965
star
2

wiki

A tiny wiki using BoltDB and Blackfriday
Go
203
star
3

xip.name

Simple wildcard DNS inspired by xip.io
Go
156
star
4

karta

Experiments with map generation using Voronoi diagrams
Go
95
star
5

pixel-experiments

Various experiments using the pixel library
Go
87
star
6

pinch

Retrieve a file from inside a zip file, over the network!
Ruby
62
star
7

giphy

Go library for the Giphy API
Go
60
star
8

hiro

Generates HTML from API Blueprints using the Snow Crash command line tool Drafter and Iglo.
Go
53
star
9

tpb-search

Locally index and search database dumps from https://openbay.isohunt.to using the bleve text indexing library
Go
49
star
10

link

Parses Link headers used for pagination, as defined in RFC 5988
Go
40
star
11

go-streaming-loadbalancer

A small loadbalancer API written in Go (Using Pat, Redigo and Go-GeoIP)
Go
34
star
12

neocities

A Neocities client written in Go
Go
33
star
13

duration

Parse a RFC 3339 duration string into time.Duration
Go
29
star
14

swapi

A SWAPI client written in Go
Go
28
star
15

photography

Files used in my photography post processing workflow. Lightroom presets, etc.
25
star
16

dircolors-jellybeans

Dircolors suitable for use with jellybeans.vim
Shell
24
star
17

acr122u

A Go package for the ACR122U USB NFC Reader
Go
24
star
18

tinypng

A TinyPNG client written in Go
Go
22
star
19

sseclient

Server-sent events (SSE) client in Go
Go
19
star
20

hn

Go library for the Hacker News API
Go
19
star
21

flip

Go library used to flip text
Go
18
star
22

fixer

Go client for the Foreign exchange rates and currency conversion API 💰
Go
18
star
23

gopher

A simple server for the Gopher protocol written in Go.
Go
17
star
24

ssh-chat-bot

A small chatbot for ssh-chat
Go
17
star
25

lossypng

Library version of the lossypng command line tool by @foobaz
Go
16
star
26

env

Load environment variables into Go types, with fallback values.
Go
14
star
27

life

Conway's Game of Life written in Go using termbox-go
Go
12
star
28

dotfiles

My config files (aka dotfiles)
Vim Script
11
star
29

gui

Minimal GUI in Go initially based on https://github.com/faiface/gui
Go
11
star
30

emojilib

The Emoji keyword library by @muan ported to Go
Go
11
star
31

release

A small package used to parse scene release names
Go
9
star
32

nobel

Ruby client for the Nobel Prize API
Ruby
9
star
33

brandy

Brandy Basic V Interpreter patched to compile under OS X
C
9
star
34

w4-2048

2048 using the fantasy console WASM-4 and TinyGo
Go
8
star
35

wavefront

A go getable version of wavefront (OBJ/MTL) parser used by the go-qml examples.
Go
8
star
36

nesdev

I’m just playing around, not meant to be useful for anyone but me :)
Assembly
8
star
37

ruuvitag

This is a Go package for decoding RuuviTag sensor data
Go
7
star
38

gophereyes

A follow the mouse demo
Go
7
star
39

plasma

Experiments with plasma generation in Go
Go
6
star
40

adventure

A small text based adventure game using the ishell package.
Go
6
star
41

check-ssh-chat

Check if a ssh-chat server is up and responding
Go
5
star
42

jsonstore

A Go client for the www.jsonstore.io API   💾 🚀
Go
5
star
43

population

Go library for the World Population API
Go
4
star
44

natsdraw

draw.Image over NATS
Go
4
star
45

go-pinch

Pinch using Go
Go
4
star
46

maze

Generate a maze using Prim's Algorithm
Go
4
star
47

loc

SSE stream of visitor locations plotted on a map using D3.js
Go
4
star
48

hi

Find images for a given hashtag
Go
3
star
49

beats

Go library for all your Swatch Internet Time needs
Go
3
star
50

publicdns

A client for Google Public DNS written in Go
Go
3
star
51

hackerrank

Solutions to HackerRank challenges.
Go
2
star
52

vedis-from-c-and-go

Experimenting with Vedis from C and Go
C
2
star
53

lights

A command line tool for circadian lighting at my desk
Go
2
star
54

humans

Parsing your humans.txt into JSON
Ruby
2
star
55

microview

Go library used to remote control a MicroView
Go
2
star
56

go-tdtool-api

A simple API in front of the TellStick tdtool written in Go (List and turn devices on/off)
Go
2
star
57

mandelbrot

The Mandelbrot Set in Go
Go
2
star
58

monastic

Implementation of The Ciphers of the Monks in Go
Go
2
star
59

kinetosis

Read XYZ orientation data from the Sudden Motion Sensor present in most recent Apple laptops. (This is a lie since the Air doesn’t even have one… so I don’t have a way to keep the code updated :)
Ruby
2
star
60

mat

A small API client for the Mat API
Ruby
1
star
61

scb

A small API client for the SCB API.
Ruby
1
star
62

peterhellberg.github.com

My Open Source projects on GitHub
1
star
63

nostr-json

Generate a nostr.json used for verification of a Nostr user
Go
1
star
64

fuzz

Randomized testing for my Go packages using go-fuzz
Go
1
star
65

stub-web-server

Stub web server used for testing
Go
1
star
66

sr

Go library for Sveriges Radio API
Go
1
star
67

brickcolor

A (generated) Go package with all of the Roblox BrickColor Codes
Go
1
star
68

land_of_lisp

A series of Lisp exercises as I work through the Land of Lisp book
Common Lisp
1
star
69

riksteatern

Ruby client for the Riksteatern API
Ruby
1
star
70

langtons-ant

Langton's ant written in Go using termbox-go
Go
1
star
71

typ

A small Zig ⚡ module, as a convenience for me when writing WebAssembly plugins for Typst
Zig
1
star
72

filmtipset

API client for the Filmtipset API (requires access key)
Ruby
1
star
73

code_year

EXPERIMENT: A VERY naïve parser for the #code2011 tweets
Ruby
1
star
74

gradient

Create vertical and horizontal gradients in Go
Go
1
star
75

warmup

HTTP cache warming
Go
1
star