[First commit]
This commit is contained in:
commit
885373889b
|
@ -0,0 +1 @@
|
||||||
|
img/*
|
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
const (
|
||||||
|
screenWidth int = 500
|
||||||
|
screenHeight int = 500
|
||||||
|
windowWidth int = 1000
|
||||||
|
windowHeight int = 1000
|
||||||
|
layerCount int = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
function Function = &X1{}
|
||||||
|
)
|
|
@ -0,0 +1,19 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type X1 struct{}
|
||||||
|
|
||||||
|
func (x *X1) Func(f float64) uint16 {
|
||||||
|
v := (65535 / 2) * (float64(screenHeight+screenWidth) / 2) / f
|
||||||
|
return ToUint16(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
type X2 struct{}
|
||||||
|
|
||||||
|
func (x *X2) Func(f float64) uint16 {
|
||||||
|
v := (math.Sin((float64(screenWidth)*float64(screenHeight))/f) + 1) / 2 * 65535
|
||||||
|
return ToUint16(v)
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
module git.ctdo.de/xoy/xvisuals
|
||||||
|
|
||||||
|
go 1.23.2
|
||||||
|
|
||||||
|
require github.com/hajimehoshi/ebiten/v2 v2.8.1
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 // indirect
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 // indirect
|
||||||
|
github.com/ebitengine/purego v0.8.0 // indirect
|
||||||
|
github.com/jezek/xgb v1.1.1 // indirect
|
||||||
|
golang.org/x/sync v0.8.0 // indirect
|
||||||
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
)
|
|
@ -0,0 +1,16 @@
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325 h1:Gk1XUEttOk0/hb6Tq3WkmutWa0ZLhNn/6fc6XZpM7tM=
|
||||||
|
github.com/ebitengine/gomobile v0.0.0-20240911145611-4856209ac325/go.mod h1:ulhSQcbPioQrallSuIzF8l1NKQoD7xmMZc5NxzibUMY=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0 h1:5J4U0kXF+pv/DhiXt5/lTz0eO5ogJ1iXb8Yj1yReDqE=
|
||||||
|
github.com/ebitengine/hideconsole v1.0.0/go.mod h1:hTTBTvVYWKBuxPr7peweneWdkUwEuHuB3C1R/ielR1A=
|
||||||
|
github.com/ebitengine/purego v0.8.0 h1:JbqvnEzRvPpxhCJzJJ2y0RbiZ8nyjccVUrSM3q+GvvE=
|
||||||
|
github.com/ebitengine/purego v0.8.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.1 h1:6n6ZXnbeSCZccdqrH7s9Ut+dll9TEostUqbc72Tis/g=
|
||||||
|
github.com/hajimehoshi/ebiten/v2 v2.8.1/go.mod h1:SXx/whkvpfsavGo6lvZykprerakl+8Uo1X8d2U5aAnA=
|
||||||
|
github.com/jezek/xgb v1.1.1 h1:bE/r8ZZtSv7l9gk6nU0mYx51aXrvnyb44892TwSaqS4=
|
||||||
|
github.com/jezek/xgb v1.1.1/go.mod h1:nrhwO0FX/enq75I7Y7G8iN1ubpSGZEiA3v9e9GyRFlk=
|
||||||
|
golang.org/x/image v0.20.0 h1:7cVCUjQwfL18gyBJOmYvptfSHS8Fb3YUDtfLIZ7Nbpw=
|
||||||
|
golang.org/x/image v0.20.0/go.mod h1:0a88To4CYVBAHp5FXJm8o7QbUl37Vd85ply1vyD8auM=
|
||||||
|
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||||
|
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
|
@ -0,0 +1,133 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"image/png"
|
||||||
|
"log"
|
||||||
|
"math"
|
||||||
|
"math/rand"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/hajimehoshi/ebiten/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Game struct {
|
||||||
|
points []*Position
|
||||||
|
preScreens []*ColorArray
|
||||||
|
screen *ebiten.Image
|
||||||
|
pressCountEnter int
|
||||||
|
pressCountSpace int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) NewImage() {
|
||||||
|
image := NewColorArray()
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
x, y := rand.Intn(screenHeight), rand.Intn(screenWidth)
|
||||||
|
g.points[i] = &Position{x, y}
|
||||||
|
}
|
||||||
|
for x := 0; x < screenWidth; x++ {
|
||||||
|
for y := 0; y < screenHeight; y++ {
|
||||||
|
c := make([]uint16, 3)
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
p := g.points[i]
|
||||||
|
if p.X != x || p.Y != y {
|
||||||
|
v := math.Abs(p.Dist(&Position{x, y}))
|
||||||
|
c[i] = function.Func(v)
|
||||||
|
} else {
|
||||||
|
c[0] = 65535
|
||||||
|
c[1] = 65535
|
||||||
|
c[2] = 65535
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
image.Set(x, y, color.RGBA64{c[0], c[1], c[2], 255})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g.preScreens = append(g.preScreens, image)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (gm *Game) Init() {
|
||||||
|
for i := 0; i < layerCount; i++ {
|
||||||
|
gm.NewImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
for x := 0; x < screenWidth; x++ {
|
||||||
|
for y := 0; y < screenHeight; y++ {
|
||||||
|
var r, g, b int64 = 0, 0, 0
|
||||||
|
for i := 0; i < layerCount; i++ {
|
||||||
|
R, G, B, _ := gm.preScreens[i].At(x, y).RGBA()
|
||||||
|
r += int64(R)
|
||||||
|
g += int64(G)
|
||||||
|
b += int64(B)
|
||||||
|
}
|
||||||
|
r /= int64(layerCount)
|
||||||
|
g /= int64(layerCount)
|
||||||
|
b /= int64(layerCount)
|
||||||
|
gm.screen.Set(x, y, color.RGBA64{uint16(r), uint16(g), uint16(b), 65535})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) ReInit() {
|
||||||
|
g.points = make([]*Position, 3)
|
||||||
|
g.preScreens = make([]*ColorArray, 0)
|
||||||
|
g.screen = ebiten.NewImage(screenWidth, screenHeight)
|
||||||
|
g.Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewGame() *Game {
|
||||||
|
gm := &Game{
|
||||||
|
make([]*Position, 3),
|
||||||
|
make([]*ColorArray, 0),
|
||||||
|
ebiten.NewImage(screenWidth, screenHeight),
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
}
|
||||||
|
gm.Init()
|
||||||
|
return gm
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Update() error {
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeyEnter) && g.pressCountEnter == 0 {
|
||||||
|
file, err := os.Create(strconv.FormatInt(time.Now().Unix(), 10) + ".png")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer file.Close()
|
||||||
|
err = png.Encode(file, g.screen)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
g.pressCountEnter++
|
||||||
|
} else if !ebiten.IsKeyPressed(ebiten.KeyEnter) && g.pressCountEnter > 0 {
|
||||||
|
g.pressCountEnter = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if ebiten.IsKeyPressed(ebiten.KeySpace) && g.pressCountSpace == 0 {
|
||||||
|
g.ReInit()
|
||||||
|
g.pressCountSpace++
|
||||||
|
} else if !ebiten.IsKeyPressed(ebiten.KeySpace) && g.pressCountSpace > 0 {
|
||||||
|
g.pressCountSpace = 0
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Draw(screen *ebiten.Image) {
|
||||||
|
screen.DrawImage(g.screen, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
|
||||||
|
return screenWidth, screenHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
g := NewGame()
|
||||||
|
ebiten.SetWindowSize(windowWidth, windowHeight)
|
||||||
|
ebiten.SetWindowTitle("XVisuals")
|
||||||
|
if err := ebiten.RunGame(g); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
# XVisuals
|
||||||
|
|
||||||
|
Visualization of mathematical formulas.
|
||||||
|
|
||||||
|
## Controls
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
| ----- | ------------------ |
|
||||||
|
| Space | Generate new image |
|
||||||
|
| Enter | Save current image |
|
|
@ -0,0 +1,55 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"image/color"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Function interface {
|
||||||
|
Func(float64) uint16
|
||||||
|
}
|
||||||
|
|
||||||
|
type ColorArray struct {
|
||||||
|
img []color.Color
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewColorArray() *ColorArray {
|
||||||
|
ca := &ColorArray{make([]color.Color, screenWidth*screenHeight)}
|
||||||
|
ca.Clear(color.Black)
|
||||||
|
return ca
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca *ColorArray) Clear(c color.Color) {
|
||||||
|
for i := 0; i < len(ca.img); i++ {
|
||||||
|
ca.img[i] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca *ColorArray) At(x, y int) color.Color {
|
||||||
|
position := x + (y * screenHeight)
|
||||||
|
if position > len(ca.img) || position < 0 {
|
||||||
|
return color.Black
|
||||||
|
} else {
|
||||||
|
return ca.img[position]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ca *ColorArray) Set(x, y int, c color.Color) {
|
||||||
|
position := x + (y * screenHeight)
|
||||||
|
if position < len(ca.img) && position >= 0 {
|
||||||
|
ca.img[position] = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position struct {
|
||||||
|
X int
|
||||||
|
Y int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Position) Length() float64 {
|
||||||
|
return math.Sqrt(float64(p.X)*float64(p.X) + float64(p.Y)*float64(p.Y))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *Position) Dist(P *Position) float64 {
|
||||||
|
return (&Position{p.X - P.X, p.Y - P.Y}).Length()
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToUint16(f float64) uint16 {
|
||||||
|
if f > 65535 {
|
||||||
|
return uint16(math.Mod(f, 65535))
|
||||||
|
} else {
|
||||||
|
return uint16(f)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue