2022-08-10 18:41:57 +00:00
|
|
|
// Copyright (c) 2022 David Vogel
|
|
|
|
//
|
|
|
|
// This software is released under the MIT License.
|
|
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"image"
|
|
|
|
"image/color"
|
|
|
|
"math"
|
|
|
|
"os"
|
|
|
|
|
|
|
|
"github.com/tdewolff/canvas"
|
2022-08-11 09:10:07 +00:00
|
|
|
"github.com/tdewolff/canvas/renderers/rasterizer"
|
2022-08-10 18:41:57 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var playerPathDisplayStyle = canvas.Style{
|
|
|
|
FillColor: canvas.Transparent,
|
|
|
|
//StrokeColor: color.RGBA{0, 0, 0, 127},
|
|
|
|
StrokeWidth: 3.0,
|
|
|
|
StrokeCapper: canvas.RoundCap,
|
|
|
|
StrokeJoiner: canvas.MiterJoin,
|
|
|
|
DashOffset: 0.0,
|
|
|
|
Dashes: []float64{},
|
|
|
|
FillRule: canvas.NonZero,
|
|
|
|
}
|
|
|
|
|
|
|
|
type PlayerPathElement struct {
|
|
|
|
From [2]float64 `json:"from"`
|
|
|
|
To [2]float64 `json:"to"`
|
|
|
|
HP float64 `json:"hp"`
|
|
|
|
MaxHP float64 `json:"maxHP"`
|
|
|
|
Polymorphed bool `json:"polymorphed"`
|
|
|
|
}
|
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
type PlayerPath []PlayerPathElement
|
2022-08-10 18:41:57 +00:00
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
func LoadPlayerPath(path string) (PlayerPath, error) {
|
2022-08-10 18:41:57 +00:00
|
|
|
file, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
var result PlayerPath
|
2022-08-10 18:41:57 +00:00
|
|
|
|
|
|
|
jsonDec := json.NewDecoder(file)
|
|
|
|
if err := jsonDec.Decode(&result); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
return result, nil
|
2022-08-10 18:41:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
func (p PlayerPath) Draw(destImage *image.RGBA) {
|
|
|
|
destRect := destImage.Bounds()
|
|
|
|
|
|
|
|
// Same as destImage, but top left is translated to (0, 0).
|
|
|
|
originImage := destImage.SubImage(destRect).(*image.RGBA)
|
|
|
|
originImage.Rect = originImage.Rect.Sub(destRect.Min)
|
|
|
|
|
|
|
|
c := canvas.New(float64(destRect.Dx()), float64(destRect.Dy()))
|
|
|
|
ctx := canvas.NewContext(c)
|
|
|
|
ctx.SetCoordSystem(canvas.CartesianIV)
|
|
|
|
ctx.SetCoordRect(canvas.Rect{X: -float64(destRect.Min.X), Y: -float64(destRect.Min.Y), W: float64(destRect.Dx()), H: float64(destRect.Dy())}, float64(destRect.Dx()), float64(destRect.Dy()))
|
|
|
|
|
2022-08-10 18:41:57 +00:00
|
|
|
// Set drawing style.
|
2022-08-11 09:10:07 +00:00
|
|
|
ctx.Style = playerPathDisplayStyle
|
2022-08-10 18:41:57 +00:00
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
for _, pathElement := range p {
|
2022-08-10 18:41:57 +00:00
|
|
|
from, to := pathElement.From, pathElement.To
|
|
|
|
|
|
|
|
// Only draw if the path may cross the image rectangle.
|
|
|
|
pathRect := image.Rectangle{image.Point{int(from[0]), int(from[1])}, image.Point{int(to[0]), int(to[1])}}.Canon().Inset(int(-playerPathDisplayStyle.StrokeWidth) - 1)
|
2022-08-11 09:10:07 +00:00
|
|
|
if pathRect.Overlaps(destRect) {
|
2022-08-10 18:41:57 +00:00
|
|
|
path := &canvas.Path{}
|
|
|
|
path.MoveTo(from[0], from[1])
|
|
|
|
path.LineTo(to[0], to[1])
|
|
|
|
|
|
|
|
if pathElement.Polymorphed {
|
|
|
|
// Set stroke color to typically polymorph color.
|
2022-08-11 09:10:07 +00:00
|
|
|
ctx.Style.StrokeColor = color.RGBA{127, 50, 83, 127}
|
2022-08-10 18:41:57 +00:00
|
|
|
} else {
|
|
|
|
// Set stroke color depending on HP level.
|
|
|
|
hpFactor := math.Max(math.Min(pathElement.HP/pathElement.MaxHP, 1), 0)
|
|
|
|
hpFactorInv := 1 - hpFactor
|
|
|
|
r, g, b, a := uint8((0*hpFactor+1*hpFactorInv)*127), uint8((1*hpFactor+0*hpFactorInv)*127), uint8(0), uint8(127)
|
2022-08-11 09:10:07 +00:00
|
|
|
ctx.Style.StrokeColor = color.RGBA{r, g, b, a}
|
2022-08-10 18:41:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-11 09:10:07 +00:00
|
|
|
ctx.DrawPath(0, 0, path)
|
2022-08-10 18:41:57 +00:00
|
|
|
}
|
|
|
|
}
|
2022-08-11 09:10:07 +00:00
|
|
|
|
|
|
|
// Theoretically we would need to linearize imgRGBA first, but DefaultColorSpace assumes that the color space is linear already.
|
|
|
|
r := rasterizer.FromImage(originImage, canvas.DPMM(1.0), canvas.DefaultColorSpace)
|
|
|
|
c.Render(r)
|
|
|
|
r.Close() // This just transforms the image's luminance curve back from linear into non linear.
|
2022-08-10 18:41:57 +00:00
|
|
|
}
|