From 942b0021d50d8bc7ba342f2a965b1f0dae98738e Mon Sep 17 00:00:00 2001 From: Jisu Sim Date: Mon, 7 May 2018 13:31:56 +0900 Subject: [PATCH] File refresh, configuration, camera zoom short key. --- README.md | 7 +- cmd/BitmapLogicSimulator/config.go | 50 +++++++++++ cmd/BitmapLogicSimulator/main.go | 128 ++++++++++++++++++++++------- simulator.go | 16 ++-- 4 files changed, 162 insertions(+), 39 deletions(-) create mode 100644 cmd/BitmapLogicSimulator/config.go diff --git a/README.md b/README.md index 6cee5b1..db3a24e 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,7 @@ OR gate can be constructed using two wires merged. ### Simulation ## TODO List -- [x] simulation -- [ ] file refresh per some certain time -- [ ] load and save configuration +- [x] Simulation +- [x] File refresh per some certain time +- [x] Load and save configuration +- [ ] Optimization(performance, memory) diff --git a/cmd/BitmapLogicSimulator/config.go b/cmd/BitmapLogicSimulator/config.go new file mode 100644 index 0000000..7984275 --- /dev/null +++ b/cmd/BitmapLogicSimulator/config.go @@ -0,0 +1,50 @@ +package main + +import ( + "encoding/json" + "os" +) + +type Config struct { + FileName string + SimulationsPerFrame int +} + +func loadConfig(configFileName string) (*Config, error) { + configFile, err := os.Open(configFileName) + defer configFile.Close() + if err != nil { + return &Config{"", 5}, nil + } + + decoder := json.NewDecoder(configFile) + + c := new(Config) + + err = decoder.Decode(&c) + if err != nil { + return nil, err + } + + return c, nil +} + +func saveConfig(configFileName string, c *Config) error { + configFile, err := os.Create(configFileName) + defer configFile.Close() + if err != nil { + return err + } + + bytes, err := json.MarshalIndent(c, "", "\t") + if err != nil { + return nil + } + + _, err = configFile.Write(bytes) + if err != nil { + return err + } + + return nil +} diff --git a/cmd/BitmapLogicSimulator/main.go b/cmd/BitmapLogicSimulator/main.go index 200a7e6..81ec634 100644 --- a/cmd/BitmapLogicSimulator/main.go +++ b/cmd/BitmapLogicSimulator/main.go @@ -7,9 +7,11 @@ import ( _ "image/png" "log" "os" + "path" "runtime" "strings" + "github.com/fsnotify/fsnotify" "github.com/go-gl/gl/v4.1-core/gl" "github.com/go-gl/glfw/v3.2/glfw" "github.com/go-gl/mathgl/mgl32" @@ -60,11 +62,14 @@ const ( WINDOW_TITLE = "go-BitmapLogicSimulator by rlj1202" ) +var watcher *fsnotify.Watcher + var simulator *gobls.Simulator -var simulatePerFrame int = 10 var programId uint32 +var texId uint32 + var overlayPBO uint32 var overlayTex uint32 @@ -81,12 +86,30 @@ var mouseXIdx int var mouseYIdx int func main() { - imgFileName := "_circuit.png" + c, err := loadConfig("config.json") + defer saveConfig("config.json", c) + if err != nil { + panic(err) + } + + log.Printf("config : %v\n", *c) + + imgFile, err := os.Open(c.FileName) + if err != nil { + panic(err) + } + + watcher, err := fsnotify.NewWatcher() + defer watcher.Close() + if err != nil { + panic(err) + } + watcher.Add(path.Dir(c.FileName)) runtime.LockOSThread() // init glfw - err := glfw.Init() + err = glfw.Init() if err != nil { panic(err) } @@ -107,6 +130,7 @@ func main() { window.SetScrollCallback(scrollCallback) window.SetMouseButtonCallback(mouseButtonCallback) window.SetCursorPosCallback(cursorPosCallback) + window.SetKeyCallback(keyCallback) window.MakeContextCurrent() glfw.SwapInterval(1) @@ -181,22 +205,6 @@ func main() { gl.VertexAttribPointer(1, 2, gl.FLOAT, false, 0, nil) gl.EnableVertexAttribArray(1) - log.Println("load image") - - // load image - imgFile, err := os.Open(imgFileName) - if err != nil { - panic(err) - } - img, _, err := image.Decode(imgFile) - if err != nil { - panic(err) - } - texId, err := loadTexture(img) - if err != nil { - panic(err) - } - log.Println("create simulation") // create simulation, overlay PBO, overlay texture @@ -205,17 +213,36 @@ func main() { log.Println("process image") // load image - loadImage(img) + loadImage(imgFile) + imgFile.Close() + // start simulation width, height := window.GetSize() updateProjectionMat(programId, float32(width), float32(height)/float32(width)) - - gl.ClearColor(1, 0, 0, 1) + gl.ClearColor(0.1, 0.1, 0.1, 1) for !window.ShouldClose() { glfw.PollEvents() gl.Clear(gl.COLOR_BUFFER_BIT) + select { + case event := <-watcher.Events: + if event.Name == c.FileName { + if event.Op&fsnotify.Create == fsnotify.Create || event.Op&fsnotify.Write == fsnotify.Write { + log.Println("file refreshed.") + + imgFile, err := os.Open(event.Name) + if err == nil { + loadImage(imgFile) + imgFile.Close() + } + } + } + case err = <-watcher.Errors: + log.Printf("file watcher err : %v\n", err) + default: + } + updateOverlayTex() gl.ActiveTexture(gl.TEXTURE0) @@ -224,7 +251,7 @@ func main() { gl.BindTexture(gl.TEXTURE_2D, overlayTex) gl.DrawArrays(gl.TRIANGLE_STRIP, 0, 6) - for i := 0; i < simulatePerFrame; i++ { + for i := 0; i < c.SimulationsPerFrame; i++ { simulator.Simulate() } @@ -232,16 +259,35 @@ func main() { } } -func loadImage(img image.Image) { +func loadImage(imgFile *os.File) { + img, _, err := image.Decode(imgFile) + if err != nil { + panic(err) + } + + if texId == 0 { + gl.GenTextures(1, &texId) + + log.Println("gen texture name.") + } + err = loadTexture(img) + if err != nil { + panic(err) + } + simulator.LoadImage(img) width, height := simulator.Size() if overlayPBO == 0 { gl.GenBuffers(1, &overlayPBO) + + log.Println("gen overlay PBO name.") } if overlayTex == 0 { gl.GenTextures(1, &overlayTex) + + log.Println("gen overlay texture name.") } gl.BindBuffer(gl.PIXEL_UNPACK_BUFFER, overlayPBO) @@ -320,15 +366,13 @@ func updateProjectionMat(shaderProgram uint32, width, ratio float32) { gl.ProgramUniformMatrix4fv(shaderProgram, projectionLoc, 1, false, &(projectionMat[0])) } -func loadTexture(img image.Image) (uint32, error) { - texId := uint32(0) - gl.GenTextures(1, &texId) +func loadTexture(img image.Image) error { gl.BindTexture(gl.TEXTURE_2D, texId) rgba := image.NewRGBA(img.Bounds()) if rgba.Stride != rgba.Rect.Size().X*4 { - return 0, errors.New("Unsupported stride.") + return errors.New("Unsupported stride.") } draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src) @@ -339,7 +383,7 @@ func loadTexture(img image.Image) (uint32, error) { gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST) gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR) - return texId, nil + return nil } func loadShader(rawSource string, shaderType uint32) (uint32, error) { @@ -451,3 +495,29 @@ func cursorPosCallback(w *glfw.Window, xpos, ypos float64) { updateCameraLocMat() } } + +func keyCallback(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) { + if glfw.KeyKP0 <= key && key <= glfw.KeyKP9 && action == glfw.Press { + width, height := simulator.Size() + + switch key { + case glfw.KeyKP0: + cameraZoom = 1.0 + cameraX = 0.0 + cameraY = 0.0 + case glfw.KeyKP1: + cameraZoom = 1.0 + case glfw.KeyKP2: + cameraZoom = 2.0 + case glfw.KeyKP3: + cameraZoom = 3.0 + case glfw.KeyKP4: + cameraZoom = 4.0 + case glfw.KeyKP5: + cameraZoom = 5.0 + } + + updateScaleMat(float32(width), float32(height), cameraZoom) + updateCameraLocMat() + } +} diff --git a/simulator.go b/simulator.go index 0536984..8e234f3 100644 --- a/simulator.go +++ b/simulator.go @@ -182,16 +182,18 @@ func (simulator *Simulator) LoadImage(img image.Image) { states[i] = false } - // load previous states - if simulator.prevImage != nil { - for y := 0; y < height; y++ { - for x := 0; x < width; x++ { - if wireMap[y][x] != 0 && isConductive(simulator.prevImage.At(x, y)) { - states[wireRemap[wireMap[y][x]]] = true + // copy previous states + /* + if simulator.prevImage != nil { + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + if wireMap[y][x] != 0 && isConductive(simulator.prevImage.At(x, y)) { + states[wireRemap[wireMap[y][x]]] = true + } } } } - } + */ simulator.width = width simulator.height = height