2015-07-26 16:44:51 +02:00
|
|
|
// Copyright 2014, 2015 by Sascha L. Teichmann
|
2014-09-09 15:22:29 +02:00
|
|
|
// Use of this source code is governed by the MIT license
|
|
|
|
// that can be found in the LICENSE file.
|
|
|
|
|
2014-09-14 00:02:04 +02:00
|
|
|
package common
|
2014-09-09 15:01:14 +02:00
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"image/color"
|
|
|
|
"os"
|
2014-10-19 11:43:53 +02:00
|
|
|
"sort"
|
2016-04-23 16:45:33 +02:00
|
|
|
"strconv"
|
2014-09-09 15:01:14 +02:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
2015-07-26 11:55:38 +02:00
|
|
|
// Dim transparent 2% every node.
|
|
|
|
const DefaultTransparentDim = 2.0 / 100.0
|
|
|
|
|
2014-09-09 23:33:53 +02:00
|
|
|
type Colors struct {
|
2014-10-25 11:20:51 +02:00
|
|
|
Colors []color.RGBA
|
|
|
|
NameIndex map[string]int32
|
|
|
|
NumTransparent int32
|
2015-07-26 11:55:38 +02:00
|
|
|
TransparentDim float32
|
2014-10-19 11:43:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type namedColor struct {
|
|
|
|
name string
|
|
|
|
color color.RGBA
|
|
|
|
}
|
|
|
|
|
|
|
|
type sortByAlpha []namedColor
|
|
|
|
|
|
|
|
func (colors sortByAlpha) Less(i, j int) bool {
|
|
|
|
return colors[i].color.A < colors[j].color.A
|
|
|
|
}
|
|
|
|
|
|
|
|
func (colors sortByAlpha) Len() int {
|
|
|
|
return len(colors)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (colors sortByAlpha) Swap(i, j int) {
|
|
|
|
colors[i], colors[j] = colors[j], colors[i]
|
2014-09-09 23:33:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func ParseColors(filename string) (colors *Colors, err error) {
|
2014-09-09 15:01:14 +02:00
|
|
|
|
|
|
|
var file *os.File
|
|
|
|
if file, err = os.Open(filename); err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
|
2014-10-19 11:43:53 +02:00
|
|
|
cols := make([]namedColor, 0, 2200)
|
2014-09-09 15:01:14 +02:00
|
|
|
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
|
|
for scanner.Scan() {
|
|
|
|
line := scanner.Text()
|
|
|
|
if strings.HasPrefix(line, "#") {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
c := color.RGBA{A: 0xff}
|
|
|
|
var name string
|
2014-09-09 17:48:39 +02:00
|
|
|
if n, _ := fmt.Sscanf(
|
|
|
|
line, "%s %d %d %d %d", &name, &c.R, &c.G, &c.B, &c.A); n > 0 {
|
2014-10-19 11:43:53 +02:00
|
|
|
cols = append(cols, namedColor{name: name, color: c})
|
2014-09-09 17:48:39 +02:00
|
|
|
}
|
2014-09-09 15:01:14 +02:00
|
|
|
}
|
|
|
|
err = scanner.Err()
|
2014-10-19 11:43:53 +02:00
|
|
|
|
|
|
|
// Sort transparent colors to front. Makes it easier to figure out
|
|
|
|
// if an index corresponds to a transparent color (i < Transparent).
|
|
|
|
sort.Sort(sortByAlpha(cols))
|
|
|
|
|
|
|
|
cs := make([]color.RGBA, len(cols))
|
|
|
|
nameIndex := make(map[string]int32, len(cols))
|
|
|
|
|
2014-10-25 11:20:51 +02:00
|
|
|
numTransparent := int32(0)
|
2014-10-19 11:43:53 +02:00
|
|
|
for i, nc := range cols {
|
|
|
|
if nc.color.A < 0xff {
|
2014-10-25 11:20:51 +02:00
|
|
|
numTransparent++
|
2014-10-19 11:43:53 +02:00
|
|
|
}
|
|
|
|
cs[i] = nc.color
|
|
|
|
nameIndex[nc.name] = int32(i)
|
|
|
|
}
|
2014-10-25 11:20:51 +02:00
|
|
|
colors = &Colors{
|
|
|
|
Colors: cs,
|
|
|
|
NameIndex: nameIndex,
|
2015-07-26 11:55:38 +02:00
|
|
|
NumTransparent: numTransparent,
|
|
|
|
TransparentDim: DefaultTransparentDim}
|
2014-09-09 15:01:14 +02:00
|
|
|
return
|
|
|
|
}
|
2014-10-26 11:01:36 +01:00
|
|
|
|
|
|
|
func (colors *Colors) IsTransparent(index int32) bool {
|
|
|
|
return index < colors.NumTransparent
|
|
|
|
}
|
|
|
|
|
|
|
|
func BlendColor(c1, c2 color.RGBA, a float32) color.RGBA {
|
|
|
|
b := float32(1) - a
|
|
|
|
return color.RGBA{
|
|
|
|
R: uint8(float32(c1.R)*a + float32(c2.R)*b),
|
|
|
|
G: uint8(float32(c1.G)*a + float32(c2.G)*b),
|
|
|
|
B: uint8(float32(c1.B)*a + float32(c2.B)*b),
|
|
|
|
A: 0xff}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (colors *Colors) BlendColors(span *Span, col color.RGBA, pos int32) color.RGBA {
|
|
|
|
curr := span
|
|
|
|
// Ignore colors below pos.
|
|
|
|
for ; curr != nil && pos >= curr.To; curr = curr.Next {
|
|
|
|
}
|
|
|
|
if curr == nil {
|
|
|
|
return col
|
|
|
|
}
|
2015-07-26 11:55:38 +02:00
|
|
|
dim := colors.TransparentDim
|
2014-10-26 11:01:36 +01:00
|
|
|
for ; curr != nil; curr = curr.Next {
|
2015-07-20 14:56:41 +02:00
|
|
|
c := colors.Colors[curr.Value]
|
2015-07-26 11:55:38 +02:00
|
|
|
// At least alpha channel attenuation + dim% extra for each depth meter.
|
|
|
|
base := float32(c.A) / 255.0
|
|
|
|
factor := min32f(1.0, base+float32(curr.To-curr.From)*dim)
|
2015-07-20 14:56:41 +02:00
|
|
|
col = BlendColor(c, col, factor)
|
2014-10-26 11:01:36 +01:00
|
|
|
}
|
|
|
|
return col
|
|
|
|
}
|
2016-04-23 16:45:33 +02:00
|
|
|
|
|
|
|
func ParseColor(col string) (color.RGBA, error) {
|
|
|
|
col = strings.TrimLeft(col, "#")
|
|
|
|
rgb, err := strconv.ParseUint(col, 16, 32)
|
|
|
|
if err != nil {
|
|
|
|
return color.RGBA{}, err
|
|
|
|
}
|
|
|
|
return color.RGBA{
|
|
|
|
R: uint8(rgb >> 16),
|
|
|
|
G: uint8(rgb >> 8),
|
|
|
|
B: uint8(rgb),
|
|
|
|
A: 0xff}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ColorToHex(col color.RGBA) string {
|
|
|
|
return fmt.Sprintf("#%02x%02x%02x", col.R, col.G, col.B)
|
|
|
|
}
|