From c33b7ee0a2a3614d656697f641bad4f4748fc056 Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sat, 14 Jan 2023 22:15:27 +0100 Subject: [PATCH] Implement draw.Image --- examples/example.go | 4 +-- examples/testdata/Testbild.png | Bin 0 -> 34935 bytes examples/testimage.go | 56 +++++++++++++++++++++++++++++++++ fenster.go | 41 +++++++++++++++++++++--- 4 files changed, 95 insertions(+), 6 deletions(-) create mode 100644 examples/testdata/Testbild.png create mode 100644 examples/testimage.go diff --git a/examples/example.go b/examples/example.go index f41d000..21a1cab 100644 --- a/examples/example.go +++ b/examples/example.go @@ -20,11 +20,11 @@ func main() { // Fill screen with random noise for i := 0; i < 240; i++ { for j := 0; j < 320; j++ { - f.SetPixel(j, i, rand.Uint32()) + f.Set(j, i, fenster.RGB(rand.Uint32())) } } // Wait for FPS rate - sleep := 16*time.Millisecond - time.Now().Sub(lastFrame) + sleep := 16*time.Millisecond - time.Since(lastFrame) if sleep > 0 { time.Sleep(sleep) } diff --git a/examples/testdata/Testbild.png b/examples/testdata/Testbild.png new file mode 100644 index 0000000000000000000000000000000000000000..4f97d0b0d83bbc98a69cf3c94015ce30de66718d GIT binary patch literal 34935 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 M07*qoM6N<$f;wgFMF0Q* literal 0 HcmV?d00001 diff --git a/examples/testimage.go b/examples/testimage.go new file mode 100644 index 0000000..220a703 --- /dev/null +++ b/examples/testimage.go @@ -0,0 +1,56 @@ +package main + +import ( + "image" + "image/color/palette" + "image/draw" + "image/png" + "log" + "os" + "time" + + "github.com/zserge/fenster" +) + +func openImage(fname string) (image.Image, error) { + fd, err := os.Open(fname) + if err != nil { + return nil, err + } + defer fd.Close() + return png.Decode(fd) +} + +func main() { + f := fenster.New() + f.Open(320, 240, "Hello") + defer f.Close() + lastFrame := time.Now() + + img, err := openImage("testdata/Testbild.png") + if err != nil { + log.Fatal(err) + } + + // convert to paletted image + pimg := image.NewPaletted(img.Bounds(), palette.Plan9) + draw.Draw(pimg, pimg.Bounds(), img, image.Point{}, draw.Src) + + for f.Loop() { + // If escape is pressed - exit + if f.Key(27) { + break + } + + // rotate palette + pimg.Palette = append(pimg.Palette[1:], pimg.Palette[0]) + draw.Draw(f, f.Bounds(), pimg, image.Point{}, draw.Src) + + // Wait for FPS rate + sleep := 16*time.Millisecond - time.Since(lastFrame) + if sleep > 0 { + time.Sleep(sleep) + } + lastFrame = time.Now() + } +} diff --git a/fenster.go b/fenster.go index d9adb4d..75f52b0 100644 --- a/fenster.go +++ b/fenster.go @@ -9,6 +9,9 @@ package fenster import "C" import ( "fmt" + "image" + "image/color" + "image/draw" "runtime" "unsafe" ) @@ -22,10 +25,33 @@ type Fenster interface { Open(w, h int, title string) error Loop() bool Close() - Pixel(x int, y int) uint32 - SetPixel(x int, y int, rgb uint32) Key(byte) bool Mod() Mods + draw.Image +} + +// RGB Color 00RRGGBB +type RGB uint32 + +func (c RGB) RGBA() (r uint32, g uint32, b uint32, a uint32) { + r = uint32(c>>16) & 0xff + r |= r << 8 + g = uint32(c>>8) & 0xff + g |= g << 8 + b = uint32(c) & 0xff + b |= b << 8 + a = 0xffff + return r, g, b, a +} + +var RGBModel = color.ModelFunc(rgbModel) + +func rgbModel(c color.Color) color.Color { + if _, ok := c.(RGB); ok { + return c + } + r, g, b, _ := c.RGBA() + return RGB((r>>8)<<16 | (g>>8)<<8 | (b >> 8)) } type Mods int @@ -35,6 +61,11 @@ type fenster struct { buf []uint32 } +func (f *fenster) ColorModel() color.Model { return RGBModel } +func (f *fenster) Bounds() image.Rectangle { + return image.Rect(0, 0, int(f.f.width), int(f.f.height)) +} + func New() Fenster { return &fenster{} } func (f *fenster) Open(w, h int, title string) error { f.f.title = C.CString(title) @@ -54,5 +85,7 @@ func (f *fenster) Close() { C.fenster_close(&f.f) } func (f *fenster) Key(code byte) bool { return f.f.keys[code] != 0 } func (f *fenster) Mod() Mods { return Mods(f.f.mod) } -func (f *fenster) Pixel(x, y int) uint32 { return f.buf[y*int(f.f.width)+x] } -func (f *fenster) SetPixel(x, y int, color uint32) { f.buf[y*int(f.f.width)+x] = color } +func (f *fenster) At(x, y int) color.Color { return RGB(f.buf[y*int(f.f.width)+x]) } +func (f *fenster) Set(x, y int, c color.Color) { + f.buf[y*int(f.f.width)+x] = uint32(f.ColorModel().Convert(c).(RGB)) +}