package main import ( "flag" "image" "log" "math" "os" "path/filepath" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/inpututil" "ur.gs/ordoor/internal/conv" "ur.gs/ordoor/internal/data" "ur.gs/ordoor/internal/ui" ) var ( gamePath = flag.String("game-path", "./orig", "Path to a WH40K: Chaos Gate installation") objFile = flag.String("obj", "", "Path to a .obj file, e.g. ./orig/Obj/TZEENTCH.OBJ") ) type env struct { obj *conv.Object state *state } type state struct { step int spriteIdx int maxSprite int zoom float64 origin image.Point } func main() { flag.Parse() if *gamePath == "" || *objFile == "" { flag.Usage() os.Exit(1) } rawObj, err := data.LoadObject(*objFile) if err != nil { log.Fatalf("Failed to load %s: %v", *objFile, err) } obj, err := conv.ConvertObject(rawObj, filepath.Base(*objFile)) if err != nil { log.Fatalf("Failed to convert %s: %v", *objFile, err) } state := &state{ zoom: 6.0, origin: image.Point{0, 0}, maxSprite: len(obj.Sprites) - 1, } env := &env{obj: obj, state: state} win, err := ui.NewWindow("View Object: " + *objFile) if err != nil { log.Fatal(err) } // The main thread now belongs to ebiten if err := win.Run(env.Update, env.Draw); err != nil { log.Fatal(err) } } func (e *env) Update() error { oldState := e.state state := oldState.runStep() if oldState.step == 0 || *oldState != *state { log.Printf( "new state: numSprites=%d sprite=%d zoom=%.2f, origin=%+v", len(e.obj.Sprites), state.spriteIdx, state.zoom, state.origin, ) } state.step += 1 e.state = state return nil } func (s *state) runStep() *state { newState := *s newState.handleKeys() return &newState } func (e *env) Draw(screen *ebiten.Image) error { sprite := e.obj.Sprites[e.state.spriteIdx] cam := ebiten.GeoM{} cam.Translate(float64(e.state.origin.X), float64(e.state.origin.Y)) // Move to origin cam.Scale(e.state.zoom, e.state.zoom) // apply current zoom factor return screen.DrawImage(sprite.Image, &ebiten.DrawImageOptions{GeoM: cam}) } func (s *state) handleKeys() { if inpututil.IsKeyJustReleased(ebiten.KeyMinus) { if s.spriteIdx > 0 { s.spriteIdx -= 1 } } if inpututil.IsKeyJustReleased(ebiten.KeyEqual) { if s.spriteIdx < s.maxSprite { s.spriteIdx += 1 } } if ebiten.IsKeyPressed(ebiten.KeyLeft) { s.origin.X += 4 } if ebiten.IsKeyPressed(ebiten.KeyRight) { s.origin.X -= 4 } if ebiten.IsKeyPressed(ebiten.KeyUp) { s.origin.Y += 4 } if ebiten.IsKeyPressed(ebiten.KeyDown) { s.origin.Y -= 4 } // Zoom in and out with the mouse wheel _, wheelY := ebiten.Wheel() s.zoom *= math.Pow(1.2, wheelY) }