rework color parsing & dynamic palettes
This commit is contained in:
		
							parent
							
								
									8f18af72f7
								
							
						
					
					
						commit
						82f09db519
					
				|  | @ -8,27 +8,31 @@ import ( | |||
| 	"golang.org/x/image/draw" | ||||
| ) | ||||
| 
 | ||||
| // pattern provides infinite algorithmically generated patterns and implements
 | ||||
| // Pattern provides infinite algorithmically generated Patterns and implements
 | ||||
| // the image.Image interface.
 | ||||
| type pattern struct{} | ||||
| type Pattern struct { | ||||
| 	Size image.Point | ||||
| } | ||||
| 
 | ||||
| // Image interface
 | ||||
| func (c *pattern) ColorModel() color.Model { return color.NRGBAModel } | ||||
| func (c *pattern) At(x, y int) color.Color { return color.Transparent } | ||||
| func (c *pattern) Bounds() image.Rectangle { | ||||
| func (c *Pattern) ColorModel() color.Model { return color.NRGBAModel } | ||||
| func (c *Pattern) At(x, y int) color.Color { return color.Transparent } | ||||
| func (c *Pattern) Bounds() image.Rectangle { | ||||
| 	return image.Rectangle{image.Point{-1e9, -1e9}, image.Point{1e9, 1e9}} | ||||
| } | ||||
| 
 | ||||
| func (p *pattern) ToFixedImage(bounds image.Rectangle) *image.NRGBA { | ||||
| func (p *Pattern) ToFixedImage(bounds image.Rectangle) *image.NRGBA { | ||||
| 	img := image.NewNRGBA(bounds) | ||||
| 	// TODO: allow setting a mask?
 | ||||
| 	// override size for pattern?
 | ||||
| 	p.Size = bounds.Size() // override size for this Pattern
 | ||||
| 	draw.Draw(img, bounds, p, image.Point{}, draw.Src) | ||||
| 	return img | ||||
| } | ||||
| 
 | ||||
| type StripePattern struct { | ||||
| 	pattern | ||||
| 	Pattern | ||||
| 	Palette color.Palette | ||||
| 	Size    int | ||||
| } | ||||
| 
 | ||||
| func (c *StripePattern) At(x, y int) color.Color { | ||||
|  | @ -37,7 +41,7 @@ func (c *StripePattern) At(x, y int) color.Color { | |||
| 		return color.Transparent | ||||
| 	} | ||||
| 
 | ||||
| 	pxPerStripe := c.Size / n | ||||
| 	pxPerStripe := c.Size.Y / n | ||||
| 	if pxPerStripe <= 0 { | ||||
| 		pxPerStripe = 1 | ||||
| 	} | ||||
|  | @ -46,8 +50,8 @@ func (c *StripePattern) At(x, y int) color.Color { | |||
| } | ||||
| 
 | ||||
| func NewPrideImage(p color.Palette, bounds image.Rectangle) image.Image { | ||||
| 	pattern := StripePattern{Palette: p, Size: bounds.Dy()} | ||||
| 	return pattern.ToFixedImage(bounds) | ||||
| 	Pattern := StripePattern{Palette: p} | ||||
| 	return Pattern.ToFixedImage(bounds) | ||||
| } | ||||
| 
 | ||||
| var PrideFlags = map[string]color.Palette{ | ||||
|  | @ -74,27 +78,67 @@ var PrideFlags = map[string]color.Palette{ | |||
| 	}, | ||||
| } | ||||
| 
 | ||||
| type SineColorPattern struct { | ||||
| 	pattern | ||||
| 	Luma  uint8 | ||||
| 	Freq  float64 | ||||
| 	Phase float64 | ||||
| type DynamicPattern struct { | ||||
| 	Pattern | ||||
| 
 | ||||
| 	Color func(x, y int, p *DynamicPattern) (float64, float64, float64) // should return rgb in [0,1] range
 | ||||
| 
 | ||||
| 	Luma  float64 // color parameter
 | ||||
| 	Freq  float64 // frequency parameter
 | ||||
| 	Phase float64 // phase parameter
 | ||||
| 
 | ||||
| 	Brightness float64 // additive base brightness
 | ||||
| 	ColFactor  float64 // Pattern intensity
 | ||||
| } | ||||
| 
 | ||||
| func (c *SineColorPattern) At(x, y int) color.Color { | ||||
| 	TAU := 6.28318 | ||||
| 	offset := 0.5 | ||||
| 	scale := 0.5 | ||||
| 	v := math.Atan2(float64(x), float64(y)) | ||||
| 
 | ||||
| func (c *DynamicPattern) At(x, y int) color.Color { | ||||
| 	col := color.NRGBA{} | ||||
| 	col.R = uint8((offset+scale*math.Sin(v/c.Freq*TAU))*128 + 128) | ||||
| 	col.G = uint8((offset+scale*math.Sin(v/c.Freq*TAU+TAU/3))*128 + 128) | ||||
| 	col.B = uint8((offset+scale*math.Sin(v/c.Freq*TAU+TAU/1.5))*128 + 128) | ||||
| 
 | ||||
| 	if c.ColFactor == 0.0 && c.Brightness == 0.0 { | ||||
| 		c.ColFactor = 1.0 | ||||
| 	} | ||||
| 	if c.Color != nil { | ||||
| 		r, g, b := c.Color(x, y, c) | ||||
| 		col.R = uint8(r * c.ColFactor * 255) | ||||
| 		col.G = uint8(g * c.ColFactor * 255) | ||||
| 		col.B = uint8(b * c.ColFactor * 255) | ||||
| 	} | ||||
| 	if c.Freq == 0.0 { | ||||
| 		c.Freq = 1.0 | ||||
| 	} | ||||
| 
 | ||||
| 	col.R = col.R + uint8(255*c.Brightness) | ||||
| 	col.G = col.G + uint8(255*c.Brightness) | ||||
| 	col.B = col.B + uint8(255*c.Brightness) | ||||
| 	col.A = 0xff | ||||
| 
 | ||||
| 	// col.R = c.Luma
 | ||||
| 	// col.G = uint8(math.Sin(float64(x)/c.Freq+c.Phase) * 128 + 128)
 | ||||
| 	// col.B = uint8(math.Cos(float64(y)/c.Freq+c.Phase) * 128 + 128)
 | ||||
| 	return col | ||||
| } | ||||
| 
 | ||||
| var DynPatterns = map[string]image.Image{ | ||||
| 	"rbow": &DynamicPattern{ | ||||
| 		Color: func(x, y int, p *DynamicPattern) (float64, float64, float64) { | ||||
| 			xx := float64(x) / 26.0 // TODO: dynamic sizing
 | ||||
| 			yy := float64(y) / 13.0 | ||||
| 			r := 0.5 + 0.5*math.Cos(xx+p.Phase) | ||||
| 			g := 0.5 + 0.5*math.Sin(yy+p.Phase) | ||||
| 			b := 0.5 + 0.5*math.Sin(xx+p.Phase)*math.Cos(yy+p.Phase) | ||||
| 			return r, g, b | ||||
| 		}, | ||||
| 	}, | ||||
| 
 | ||||
| 	"pastel": &DynamicPattern{ | ||||
| 		Brightness: 0.5, // TODO: expose these params?
 | ||||
| 		ColFactor:  0.5, | ||||
| 		Freq:       5.0, | ||||
| 
 | ||||
| 		Color: func(x, y int, p *DynamicPattern) (float64, float64, float64) { | ||||
| 			offset := 0.0 | ||||
| 			v := math.Atan2(float64(x)-offset, float64(y)-offset) + p.Phase | ||||
| 			r := 0.5 + 0.5*math.Sin(v*p.Freq) | ||||
| 			g := 0.5 + 0.5*math.Cos(v*p.Freq) | ||||
| 			b := 0.5 + 0.5*math.Sin(v*p.Freq+6.28318/p.Luma) | ||||
| 			return r, g, b | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
|  |  | |||
							
								
								
									
										23
									
								
								rpc/repl.go
								
								
								
								
							
							
						
						
									
										23
									
								
								rpc/repl.go
								
								
								
								
							|  | @ -128,16 +128,27 @@ func RunREPL(f Fluter) { | |||
| // alternatively treat it as palette name. If both fail,
 | ||||
| // give image.Transparent
 | ||||
| func parseColorOrPalette(input string) image.Image { | ||||
| 	if col, err := hex.DecodeString(input); err == nil { | ||||
| 	if input == "w" { | ||||
| 		return image.NewUniform(color.White) | ||||
| 	} else if input == "b" { | ||||
| 		return image.NewUniform(color.Black) | ||||
| 	} else if input == "t" { | ||||
| 		return image.Transparent | ||||
| 	} else if col, err := hex.DecodeString(input); err == nil && len(col) >= 3 { | ||||
| 		var alpha byte = 0xff | ||||
| 		if len(col) == 4 { | ||||
| 			alpha = col[3] | ||||
| 		} | ||||
| 		return image.NewUniform(color.NRGBA{col[0], col[1], col[2], alpha}) | ||||
| 	} else if pal := render.PrideFlags[input]; len(pal) != 0 { | ||||
| 		return &render.StripePattern{Palette: pal, Size: 13} | ||||
| 	} else { | ||||
| 		return &render.SineColorPattern{Luma: 0xf0, Freq: 1} | ||||
| 		return image.Transparent | ||||
| 	} | ||||
| 
 | ||||
| 	if pal := render.PrideFlags[input]; len(pal) != 0 { | ||||
| 		return &render.StripePattern{Palette: pal} | ||||
| 	} | ||||
| 
 | ||||
| 	if p, ok := render.DynPatterns[input]; ok { | ||||
| 		return p | ||||
| 	} | ||||
| 
 | ||||
| 	return image.Transparent | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue