From cd5ca3f04f826a6678d9cfcd18e8b7b9a90881ae Mon Sep 17 00:00:00 2001 From: Sander Schobers Date: Sun, 10 May 2020 17:40:56 +0200 Subject: [PATCH] Added tool to color image. Separated some image related methods. Added feedback for simulation speed (colored buttons). --- cmd/imadapt/color.go | 34 ++++++++++ cmd/imadapt/crop.go | 7 +- cmd/imadapt/gray.go | 6 +- cmd/imadapt/imadapt.go | 13 ++++ cmd/imadapt/setalpha.go | 6 +- .../res/images/fastForward_disabled.png | Bin 0 -> 373 bytes cmd/tins2020/res/images/forward_disabled.png | Bin 0 -> 346 bytes cmd/tins2020/res/images/pause_disabled.png | Bin 0 -> 246 bytes cmd/tins2020/res/textures.txt | 3 + color.go | 58 +--------------- game.go | 1 + gamecontrols.go | 27 ++++++-- img/color.go | 62 ++++++++++++++++++ {cmd/imadapt => img}/io.go | 6 +- 14 files changed, 150 insertions(+), 73 deletions(-) create mode 100644 cmd/imadapt/color.go create mode 100644 cmd/tins2020/res/images/fastForward_disabled.png create mode 100644 cmd/tins2020/res/images/forward_disabled.png create mode 100644 cmd/tins2020/res/images/pause_disabled.png create mode 100644 img/color.go rename {cmd/imadapt => img}/io.go (73%) diff --git a/cmd/imadapt/color.go b/cmd/imadapt/color.go new file mode 100644 index 0000000..8eb2a7e --- /dev/null +++ b/cmd/imadapt/color.go @@ -0,0 +1,34 @@ +package main + +import ( + "image" + "image/color" + + "opslag.de/schobers/tins2020/img" +) + +func colorImage(path string, col color.Color) error { + src, err := img.DecodeImage(path) + if err != nil { + return err + } + + colNRGBA := color.NRGBAModel.Convert(col).(color.NRGBA) + bounds := src.Bounds() + dst := image.NewRGBA(bounds) + for y := bounds.Min.Y; y < bounds.Max.Y; y++ { + for x := bounds.Min.X; x < bounds.Max.X; x++ { + c := src.At(x, y) + srcCol := color.NRGBAModel.Convert(c).(color.NRGBA) + if srcCol.A > 0 { + dstCol := colNRGBA + dstCol.A = srcCol.A + dst.Set(x, y, dstCol) + } else { + dst.Set(x, y, c) + } + } + } + return img.EncodePNG(path, dst) + return nil +} diff --git a/cmd/imadapt/crop.go b/cmd/imadapt/crop.go index 56f6d64..1651f7c 100644 --- a/cmd/imadapt/crop.go +++ b/cmd/imadapt/crop.go @@ -5,10 +5,11 @@ import ( "image/draw" "github.com/nfnt/resize" + "opslag.de/schobers/tins2020/img" ) func crop(path string, crop rect, size *point) error { - src, err := decodeImage(path) + src, err := img.DecodeImage(path) if err != nil { return err } @@ -17,9 +18,9 @@ func crop(path string, crop rect, size *point) error { dst := image.NewRGBA(dstRect) draw.Draw(dst, dstRect, src, srcRect.Min, draw.Src) if size == nil { - return encodePNG(path, dst) + return img.EncodePNG(path, dst) } resized := resize.Resize(uint(size.x), uint(size.y), dst, resize.Bilinear) - return encodePNG(path, resized) + return img.EncodePNG(path, resized) } diff --git a/cmd/imadapt/gray.go b/cmd/imadapt/gray.go index d58700e..c91d686 100644 --- a/cmd/imadapt/gray.go +++ b/cmd/imadapt/gray.go @@ -3,10 +3,12 @@ package main import ( "image" "image/color" + + "opslag.de/schobers/tins2020/img" ) func convertToGray(path string) error { - src, err := decodeImage(path) + src, err := img.DecodeImage(path) if err != nil { return err } @@ -25,5 +27,5 @@ func convertToGray(path string) error { } } } - return encodePNG(path, dst) + return img.EncodePNG(path, dst) } diff --git a/cmd/imadapt/imadapt.go b/cmd/imadapt/imadapt.go index b8c89ae..6e0b2ce 100644 --- a/cmd/imadapt/imadapt.go +++ b/cmd/imadapt/imadapt.go @@ -5,6 +5,8 @@ import ( "flag" "fmt" "log" + + "opslag.de/schobers/tins2020/img" ) func run() error { @@ -73,6 +75,17 @@ func run() error { return fmt.Errorf("couldn't crop '%s'; error: %v", path, err) } } + case "color": + flags := flag.NewFlagSet("color", flag.ContinueOnError) + var col string + flags.StringVar(&col, "color", "#ff0000", "target color") + flags.Parse(args[1:]) + for _, path := range flags.Args() { + err := colorImage(path, img.MustHexColor(col)) + if err != nil { + return fmt.Errorf("couldn't convert to grayscale of '%s'; error: %v", path, err) + } + } } return nil } diff --git a/cmd/imadapt/setalpha.go b/cmd/imadapt/setalpha.go index a0c5e93..cbc302b 100644 --- a/cmd/imadapt/setalpha.go +++ b/cmd/imadapt/setalpha.go @@ -3,10 +3,12 @@ package main import ( "image" "image/color" + + "opslag.de/schobers/tins2020/img" ) func setAlpha(path string, alpha int) error { - src, err := decodeImage(path) + src, err := img.DecodeImage(path) if err != nil { return err } @@ -21,5 +23,5 @@ func setAlpha(path string, alpha int) error { dst.Set(x, y, c) } } - return encodePNG(path, dst) + return img.EncodePNG(path, dst) } diff --git a/cmd/tins2020/res/images/fastForward_disabled.png b/cmd/tins2020/res/images/fastForward_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..a343fc96e8fb230b422bae3e2d4d7689ab6bb793 GIT binary patch literal 373 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2o;fFxq&!IEGZrd2@Yl;9&;=)(7Q0 ztP`D>6jMqVR3-#<1$DRx_gDu=>m3yRVYBJ@#HUw1zJGI{RV{hq-roEtm)GWPm=xl% z1&-FR6=}!TysVR-c)8rE?(P43%m3`#`Ty7KTP>mPT@~&^7v{{Cx1SUI`_A7zzPX21 zDZBp5OuZ9ZlXy-kqO|4AE#)t4(|^25So~`|(kl)!EWrDItS>k$GFyrs|{@ z%3b1asnq3j|j(zV=xH{3GyGkBNG(Bjkl=`#(Z&25zfA%$XJh2-Z z0={*$G%&j4oLjS))6m&LFsZ9S=!gs>YX>(|N{2L)ONTa-N{2NQiw6e_mtvxTMnj8J z0?(vI-Nlxx`=)HPzVxI;cA@3!bH6rk`95*=$_W_|WXZz7@c+L<)0yMnx5+&N1}B53 LtDnm{r-UW|On0D5 literal 0 HcmV?d00001 diff --git a/cmd/tins2020/res/images/forward_disabled.png b/cmd/tins2020/res/images/forward_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..29aed4eba7b92992c6ac07eb638fd51412c7f0a4 GIT binary patch literal 346 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2o;fFe-YwIEGZrd2?;!S|&ptwg>k9 z`3tVwNog!hW?s-ZEpT1ys|coz2iG3t@Np1OP*KV7+g2Z~{y)~wYl{EQBmWLMOq!74 z>9IvcB}zz0cmJf5oAd15bZ<9V?eAZ|RL}qa?B-kVs$5ExSTo`}jwfy1ayf5%z|F|> zC+gOA?eAxuYoJzsggLqF=1qyq;oY5v^>vXFUb2Y^8LStjoY%gYCQ;R$)LQs*tBygQ z?_#rKTYq0YvSa(lD2Z~8DF%uP6-jD~epW>bF178urhSr0P$7wh$st6bplyZX1CBt~ z1DuQc8kmo;Fd7}ZaB`hL-OIET@-@cJM pDd6L~x~p&xu`%ytWnlRKfBEDbv63Biz#wB_@O1TaS?83{1ORJPh?f8W literal 0 HcmV?d00001 diff --git a/cmd/tins2020/res/images/pause_disabled.png b/cmd/tins2020/res/images/pause_disabled.png new file mode 100644 index 0000000000000000000000000000000000000000..c201569e69e26731be5815b188cbcddb2e00b159 GIT binary patch literal 246 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETy`C@!S6QXXIzQ9K%R`vs^mg&e)k8OTDlZ8b_kJXN}HpPk*aw)TFj-F&f`5EZl1oc1v? bF#P`?m}Vdt%JXFf&?5| 0 { - a = values[3] - } - return sdl.Color{R: uint8(values[0]), G: uint8(values[1]), B: uint8(values[2]), A: uint8(a)}, nil -} - -func MustHexColor(s string) sdl.Color { - color, err := HexColor(s) - if err != nil { - panic(err) - } - return color -} - -func HexToInt(s string) (int, error) { - var i int - for _, c := range s { - i *= 16 - if c >= '0' && c <= '9' { - i += int(c - '0') - } else if c >= 'A' && c <= 'F' { - i += int(c - 'A' + 10) - } else if c >= 'a' && c <= 'f' { - i += int(c - 'a' + 10) - } else { - return 0, errors.New("hex digit not supported") - } - } - return i, nil -} - -func HexToInts(s ...string) ([]int, error) { - ints := make([]int, len(s)) - for i, s := range s { - value, err := HexToInt(s) - if err != nil { - return nil, err - } - ints[i] = value - } - return ints, nil -} +func MustHexColor(s string) sdl.Color { return sdl.Color(img.MustHexColor(s)) } diff --git a/game.go b/game.go index 1bd918d..dbb6f99 100644 --- a/game.go +++ b/game.go @@ -58,6 +58,7 @@ func NewGame() *Game { } terrain.AddFlower(Pt(0, 0), NewPoppyTraits()) return &Game{ + Speed: GameSpeedNormal, Balance: 100, Terrain: terrain, diff --git a/gamecontrols.go b/gamecontrols.go index f240005..83fa6f9 100644 --- a/gamecontrols.go +++ b/gamecontrols.go @@ -19,6 +19,12 @@ func NewGameControls(game *Game) *GameControls { } func (c *GameControls) updateSpeedControls() { + disable := func(b *IconButton, speed GameSpeed) { + b.IsDisabled = speed == c.game.Speed + } + disable(c.pause, GameSpeedPaused) + disable(c.run, GameSpeedNormal) + disable(c.runFast, GameSpeedFast) } func (c *GameControls) Arrange(ctx *Context, bounds Rectangle) { @@ -40,18 +46,25 @@ func (c *GameControls) Init(ctx *Context) error { } c.top.Orientation = OrientationHorizontal - c.pause = NewIconButton("control-pause", EmptyEvent(func() { + c.pause = NewIconButtonConfig("control-pause", EmptyEvent(func() { c.game.Pause() c.updateSpeedControls() - })) - c.run = NewIconButton("control-run", EmptyEvent(func() { + }), func(b *IconButton) { + b.IconDisabled = "control-pause-disabled" + }) + c.run = NewIconButtonConfig("control-run", EmptyEvent(func() { c.game.Run() c.updateSpeedControls() - })) - c.runFast = NewIconButton("control-run-fast", EmptyEvent(func() { + }), func(b *IconButton) { + b.IconDisabled = "control-run-disabled" + }) + c.runFast = NewIconButtonConfig("control-run-fast", EmptyEvent(func() { c.game.RunFast() c.updateSpeedControls() - })) + }), func(b *IconButton) { + b.IconDisabled = "control-run-fast-disabled" + }) + c.updateSpeedControls() c.top.Buttons = []Control{c.pause, c.run, c.runFast} c.menu.Background = MustHexColor("#356dad") @@ -71,7 +84,7 @@ func (c *GameControls) Render(ctx *Context) { topBar := MustHexColor("#0000007f") ctx.Renderer.SetDrawColor(topBar.R, topBar.G, topBar.B, topBar.A) ctx.Renderer.FillRect(Rect(c.menu.Bounds.Right(), 0, c.flowers.Bounds.X, 64).SDLPtr()) - ctx.Fonts.Font("balance").RenderCopyAlign(ctx.Renderer, FmtMoney(c.game.Balance), Pt(c.top.Bounds.X-8, 58), MustHexColor("#79A6D9"), TextAlignmentRight) + ctx.Fonts.Font("balance").RenderCopyAlign(ctx.Renderer, FmtMoney(c.game.Balance), Pt(c.top.Bounds.X-8, 58), MustHexColor("#4AC69A"), TextAlignmentRight) c.Container.Render(ctx) } diff --git a/img/color.go b/img/color.go new file mode 100644 index 0000000..9013da9 --- /dev/null +++ b/img/color.go @@ -0,0 +1,62 @@ +package img + +import ( + "errors" + "image/color" + "regexp" +) + +var hexColorRE = regexp.MustCompile(`^#?([0-9A-Fa-f]{2})-?([0-9A-Fa-f]{2})-?([0-9A-Fa-f]{2})-?([0-9A-Fa-f]{2})?$`) + +func HexColor(s string) (color.RGBA, error) { + match := hexColorRE.FindStringSubmatch(s) + if match == nil { + return color.RGBA{}, errors.New("invalid color format") + } + values, err := HexToInts(match[1:]...) + if err != nil { + return color.RGBA{}, err + } + a := 255 + if len(match[4]) > 0 { + a = values[3] + } + return color.RGBA{R: uint8(values[0]), G: uint8(values[1]), B: uint8(values[2]), A: uint8(a)}, nil +} + +func MustHexColor(s string) color.RGBA { + color, err := HexColor(s) + if err != nil { + panic(err) + } + return color +} + +func HexToInt(s string) (int, error) { + var i int + for _, c := range s { + i *= 16 + if c >= '0' && c <= '9' { + i += int(c - '0') + } else if c >= 'A' && c <= 'F' { + i += int(c - 'A' + 10) + } else if c >= 'a' && c <= 'f' { + i += int(c - 'a' + 10) + } else { + return 0, errors.New("hex digit not supported") + } + } + return i, nil +} + +func HexToInts(s ...string) ([]int, error) { + ints := make([]int, len(s)) + for i, s := range s { + value, err := HexToInt(s) + if err != nil { + return nil, err + } + ints[i] = value + } + return ints, nil +} diff --git a/cmd/imadapt/io.go b/img/io.go similarity index 73% rename from cmd/imadapt/io.go rename to img/io.go index 54ec97a..b2ba033 100644 --- a/cmd/imadapt/io.go +++ b/img/io.go @@ -1,4 +1,4 @@ -package main +package img import ( "image" @@ -6,7 +6,7 @@ import ( "os" ) -func encodePNG(path string, im image.Image) error { +func EncodePNG(path string, im image.Image) error { dst, err := os.Create(path) if err != nil { return err @@ -15,7 +15,7 @@ func encodePNG(path string, im image.Image) error { return png.Encode(dst, im) } -func decodeImage(path string) (image.Image, error) { +func DecodeImage(path string) (image.Image, error) { f, err := os.Open(path) if err != nil { return nil, err