package main import ( "flag" "log" "math" "os" "path/filepath" "github.com/faiface/pixel" "github.com/faiface/pixel/pixelgl" "golang.org/x/image/colornames" "ur.gs/chaos-gate/internal/conv" "ur.gs/chaos-gate/internal/data" "ur.gs/chaos-gate/internal/sets" "ur.gs/chaos-gate/internal/ui" ) var ( gamePath = flag.String("game-path", "./orig", "Path to a WH40K: Chaos Gate installation") setFile = flag.String("set", "", "Path to a .set file, e.g. ./orig/Sets/map01.set") ) type env struct { set *sets.MapSet objects map[string]*conv.Object } type state struct { env *env step int objIdx int spriteIdx int zoom float64 cam pixel.Matrix camPos pixel.Vec } func main() { flag.Parse() if *gamePath == "" || *setFile == "" { flag.Usage() os.Exit(1) } mapSet, err := sets.LoadSet(*setFile) if err != nil { log.Fatalf("Couldn't load set file %s: %v", *setFile, err) } objects := make(map[string]*conv.Object) for _, name := range mapSet.Palette { objFile := filepath.Join(*gamePath, "Obj", name+".obj") obj, err := data.LoadObject(objFile) if err != nil { log.Fatalf("Failed to load %s: %v", name, err) } objects[name] = conv.ConvertObject(obj, name) } env := &env{objects: objects, set: mapSet} // The main thread now belongs to pixelgl pixelgl.Run(env.run) } func (e *env) run() { win, err := ui.NewWindow("View Set: " + *setFile) if err != nil { log.Fatal("Couldn't create window: %v", err) } pWin := win.PixelWindow state := &state{ env: e, camPos: pixel.V(0, float64(-pWin.Bounds().Size().Y)), zoom: 8.0, } // For now, just try to display the various objects // left + right to change object, up + down to change frame win.Run(func() { oldState := *state state = state.runStep(pWin) if oldState != *state || oldState.step == 0 { log.Printf( "new state: numObj=%d object=%d (%s) numFrames=%d sprite=%d zoom=%.2f", state.env.set.Count(), state.objIdx, state.env.set.Palette[state.objIdx], // FIXME: palette is a confusing name len(state.curObject().Sprites), state.spriteIdx, state.zoom, ) state.step += 1 state.present(pWin) } }) } func (s *state) runStep(pWin *pixelgl.Window) *state { newState := *s newState.handleKeys(pWin) return &newState } func (s *state) present(pWin *pixelgl.Window) { obj := s.curObject() sprite := obj.Sprites[s.spriteIdx] center := pWin.Bounds().Center() cam := pixel.IM cam = cam.ScaledXY(center, pixel.Vec{1.0, -1.0}) // invert the Y axis cam = cam.Scaled(center, s.zoom) // apply current zoom factor //cam = cam.Moved(center.Sub(s.camPos)) // Make it central //cam = cam.Rotated(center, -0.785) // Apply isometric angle s.cam = cam pWin.SetMatrix(s.cam) pWin.Clear(colornames.Black) pixel.NewSprite(sprite.Pic, sprite.Pic.Bounds()).Draw(pWin, pixel.IM.Moved(center)) } func (s *state) handleKeys(pWin *pixelgl.Window) { if pWin.JustPressed(pixelgl.KeyLeft) { if s.objIdx > 0 { s.objIdx -= 1 s.spriteIdx = 0 } } if pWin.JustPressed(pixelgl.KeyRight) { if s.objIdx < s.env.set.Count()-1 { s.objIdx += 1 s.spriteIdx = 0 } } if pWin.JustPressed(pixelgl.KeyDown) { if s.spriteIdx > 0 { s.spriteIdx -= 1 } } if pWin.JustPressed(pixelgl.KeyUp) { if s.spriteIdx < len(s.curObject().Sprites)-1 { s.spriteIdx += 1 } } // Zoom in and out with the mouse wheel s.zoom *= math.Pow(1.2, pWin.MouseScroll().Y) } func (s *state) curObject() *conv.Object { name := s.env.set.Palette[s.objIdx] log.Printf("name: %v, objects: %#v", name, s.env.objects) return s.env.objects[name] }