From be4229b8fe11ab4206b72d5b5d55b634200581f8 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Sat, 21 Mar 2020 13:37:20 +0000 Subject: [PATCH] Remove internal/conv This sets font rendering back a little bit, but not much. --- cmd/view-menu/main.go | 91 +++++++++++------------------- cmd/view-obj/main.go | 33 +++++------ cmd/view-set/main.go | 94 +++++++++++++++---------------- internal/assetstore/assetstore.go | 4 ++ internal/assetstore/object.go | 50 ++++++++++++---- internal/assetstore/set.go | 11 ++-- internal/conv/font.go | 23 -------- internal/conv/object.go | 59 ------------------- 8 files changed, 145 insertions(+), 220 deletions(-) delete mode 100644 internal/conv/font.go delete mode 100644 internal/conv/object.go diff --git a/cmd/view-menu/main.go b/cmd/view-menu/main.go index 6d6d0eb..63d5050 100644 --- a/cmd/view-menu/main.go +++ b/cmd/view-menu/main.go @@ -2,7 +2,6 @@ package main import ( "flag" - "fmt" "image" "log" "os" @@ -10,24 +9,23 @@ import ( "github.com/hajimehoshi/ebiten" - "code.ur.gs/lupine/ordoor/internal/conv" + "code.ur.gs/lupine/ordoor/internal/assetstore" "code.ur.gs/lupine/ordoor/internal/data" - "code.ur.gs/lupine/ordoor/internal/fonts" "code.ur.gs/lupine/ordoor/internal/menus" "code.ur.gs/lupine/ordoor/internal/ui" ) var ( gamePath = flag.String("game-path", "./orig", "Path to a WH40K: Chaos Gate installation") - menuFile = flag.String("menu", "", "Path to a .mnu file, e.g. ./orig/Menu/MainGame.mnu") + menuFile = flag.String("menu", "", "Name of a menu, e.g. Main") ) type env struct { menu *menus.Menu - objects []*conv.Object + objects []*assetstore.Object - fonts []*conv.Font - fontObjs []*conv.Object + // fonts []*assetstore.Font + // fontObjs []*assetstore.Object step int state state @@ -39,41 +37,6 @@ type state struct { winBounds image.Rectangle } -func loadObjects(names ...string) ([]*conv.Object, error) { - objs := make([]*conv.Object, 0, len(names)) - - for _, name := range names { - objFile := filepath.Join(filepath.Dir(*menuFile), name) - rawObj, err := data.LoadObject(objFile) - if err != nil { - log.Fatalf("Failed to load %s: %v", name, err) - } - - obj, err := conv.ConvertObject(rawObj, name) - if err != nil { - return nil, err - } - - objs = append(objs, obj) - } - - return objs, nil -} - -func loadFonts(names ...string) ([]*conv.Font, error) { - var out []*conv.Font - for _, name := range names { - fnt, err := fonts.LoadFont(filepath.Join(*gamePath, "Fonts", name+".fnt")) - if err != nil { - return nil, fmt.Errorf("%v: %v", name, err) - } - - out = append(out, conv.ConvertFont(fnt)) - } - - return out, nil -} - func main() { flag.Parse() @@ -82,6 +45,11 @@ func main() { os.Exit(1) } + assets, err := assetstore.New(*gamePath) + if err != nil { + log.Fatal(err) + } + menu, err := menus.LoadMenu(*menuFile) if err != nil { log.Fatalf("Couldn't load menu file %s: %v", *menuFile, err) @@ -93,21 +61,26 @@ func main() { menu.Internationalize(i18n) } - loadedFonts, err := loadFonts(menu.FontNames...) - if err != nil { - log.Fatalf("Failed to load font: %v", err) - } + // loadedFonts, err := loadFonts(menu.FontNames...) + // if err != nil { + // log.Fatalf("Failed to load font: %v", err) + // } - menuObjs, err := loadObjects(menu.ObjectFiles...) - if err != nil { - log.Fatalf("Failed to load objects: %v", err) + var menuObjs []*assetstore.Object + for _, filename := range menu.ObjectFiles { + obj, err := assets.ObjectByPath(filepath.Join(*gamePath, "Menu", filename)) + if err != nil { + log.Fatalf("Failed to load %v: %v", filename, err) + } + + menuObjs = append(menuObjs, obj) } state := state{} env := &env{ - menu: menu, - objects: menuObjs, - fonts: loadedFonts, + menu: menu, + objects: menuObjs, + // fonts: loadedFonts, state: state, lastState: state, } @@ -156,8 +129,6 @@ func (e *env) Draw(screen *ebiten.Image) error { } func (e *env) drawRecord(record *menus.Record, screen *ebiten.Image, offset ebiten.GeoM) error { - origOffset := offset - // Draw this record if it's valid to do so. FIXME: lots to learn if len(record.SpriteId) >= 0 { spriteId := record.SpriteId[0] @@ -187,8 +158,10 @@ func (e *env) drawRecord(record *menus.Record, screen *ebiten.Image, offset ebit // FIXME: Need to handle multiple objects obj := e.objects[0] - sprite := obj.Sprites[spriteId] - + sprite, err := obj.Sprite(spriteId) + if err != nil { + return err + } x = x + float64(sprite.XOffset) y = y + float64(sprite.YOffset) @@ -205,9 +178,9 @@ func (e *env) drawRecord(record *menus.Record, screen *ebiten.Image, offset ebit // FIXME: we probably shouldn't draw everything? // FIXME: handle multiple fonts - if len(e.fonts) > 0 && record.Desc != "" { - e.fonts[0].Output(screen, origOffset, record.Desc) - } + // if len(e.fonts) > 0 && record.Desc != "" { + // e.fonts[0].Output(screen, origOffset, record.Desc) + // } } out: // Draw all children of this record diff --git a/cmd/view-obj/main.go b/cmd/view-obj/main.go index 0ba6fd0..d086694 100644 --- a/cmd/view-obj/main.go +++ b/cmd/view-obj/main.go @@ -6,22 +6,20 @@ import ( "log" "math" "os" - "path/filepath" "github.com/hajimehoshi/ebiten" - "code.ur.gs/lupine/ordoor/internal/conv" - "code.ur.gs/lupine/ordoor/internal/data" + "code.ur.gs/lupine/ordoor/internal/assetstore" "code.ur.gs/lupine/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") + objName = flag.String("obj", "", "Name of an .obj file, e.g. TZEENTCH") ) type env struct { - obj *conv.Object + obj *assetstore.Object step int state state @@ -38,19 +36,19 @@ type state struct { func main() { flag.Parse() - if *gamePath == "" || *objFile == "" { + if *gamePath == "" || *objName == "" { flag.Usage() os.Exit(1) } - rawObj, err := data.LoadObject(*objFile) + assets, err := assetstore.New(*gamePath) if err != nil { - log.Fatalf("Failed to load %s: %v", *objFile, err) + log.Fatal("Failed to set up asset store: %v", err) } - obj, err := conv.ConvertObject(rawObj, filepath.Base(*objFile)) + obj, err := assets.Object(*objName) if err != nil { - log.Fatalf("Failed to convert %s: %v", *objFile, err) + log.Fatalf("Failed to load %s: %v", *objName, err) } state := state{ @@ -64,7 +62,7 @@ func main() { lastState: state, } - win, err := ui.NewWindow("View Object: " + *objFile) + win, err := ui.NewWindow("View Object: " + *objName) if err != nil { log.Fatal(err) } @@ -86,9 +84,9 @@ func main() { func (e *env) Update() error { if e.step == 0 || e.lastState != e.state { log.Printf( - "new state: numSprites=%d sprite=%d zoom=%.2f, origin=%+v", - len(e.obj.Sprites), + "new state: sprite=%d/%d zoom=%.2f, origin=%+v", e.state.spriteIdx, + e.obj.NumSprites, e.state.zoom, e.state.origin, ) @@ -102,7 +100,10 @@ func (e *env) Update() error { } func (e *env) Draw(screen *ebiten.Image) error { - sprite := e.obj.Sprites[e.state.spriteIdx] + sprite, err := e.obj.Sprite(e.state.spriteIdx) + if err != nil { + return err + } cam := ebiten.GeoM{} cam.Translate(float64(e.state.origin.X), float64(e.state.origin.Y)) // Move to origin @@ -119,8 +120,8 @@ func (e *env) changeSprite(by int) func() { e.state.spriteIdx = 0 } - if e.state.spriteIdx > len(e.obj.Sprites)-1 { - e.state.spriteIdx = len(e.obj.Sprites) - 1 + if e.state.spriteIdx > e.obj.NumSprites-1 { + e.state.spriteIdx = e.obj.NumSprites - 1 } } } diff --git a/cmd/view-set/main.go b/cmd/view-set/main.go index 8a575da..668f93b 100644 --- a/cmd/view-set/main.go +++ b/cmd/view-set/main.go @@ -6,25 +6,20 @@ import ( "log" "math" "os" - "path/filepath" "github.com/hajimehoshi/ebiten" - "code.ur.gs/lupine/ordoor/internal/conv" - "code.ur.gs/lupine/ordoor/internal/data" - "code.ur.gs/lupine/ordoor/internal/sets" + "code.ur.gs/lupine/ordoor/internal/assetstore" "code.ur.gs/lupine/ordoor/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") + setName = flag.String("set", "", "Name of a set, e.g., map01") ) type env struct { - set *sets.MapSet - objects map[string]*conv.Object - + set *assetstore.Set step int state state lastState state @@ -41,47 +36,29 @@ type state struct { func main() { flag.Parse() - if *gamePath == "" || *setFile == "" { + if *gamePath == "" || *setName == "" { flag.Usage() os.Exit(1) } - mapSet, err := sets.LoadSet(*setFile) + assets, err := assetstore.New(*gamePath) if err != nil { - log.Fatalf("Couldn't load set file %s: %v", *setFile, err) + log.Fatal(err) } - rawObjs := make([]*data.Object, 0, len(mapSet.Palette)) - 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) - } - obj.Name = name - - rawObjs = append(rawObjs, obj) + set, err := assets.Set(*setName) + if err != nil { + log.Fatalf("Couldn't load set %s: %v", *setName, err) } - objs := make([]*conv.Object, 0, len(rawObjs)) - for _, rawObj := range rawObjs { - obj, err := conv.ConvertObject(rawObj, rawObj.Name) - if err != nil { - log.Fatal(err) - } - - objs = append(objs, obj) - } - - win, err := ui.NewWindow("View Set: " + *setFile) + win, err := ui.NewWindow("View Set: " + *setName) if err != nil { log.Fatal("Couldn't create window: %v", err) } state := state{zoom: 8.0} env := &env{ - set: mapSet, - objects: conv.MapByName(objs), + set: set, state: state, lastState: state, } @@ -101,13 +78,18 @@ func main() { } func (e *env) Update() error { + curObj, err := e.curObject() + if err != nil { + return err + } + if e.step == 0 || e.lastState != e.state { log.Printf( - "new state: numObj=%d object=%d (%s) numFrames=%d sprite=%d zoom=%.2f", - e.set.Count(), + "new state: object=%d/%d (%s) numFrames=%d sprite=%d zoom=%.2f", e.state.objIdx, - e.set.Palette[e.state.objIdx], // FIXME: palette is a confusing name - len(e.curObject().Sprites), + e.set.NumObjects, + curObj.Name, + curObj.NumSprites, e.state.spriteIdx, e.state.zoom, ) @@ -120,8 +102,10 @@ func (e *env) Update() error { } func (e *env) Draw(screen *ebiten.Image) error { - obj := e.curObject() - sprite := obj.Sprites[e.state.spriteIdx] + sprite, err := e.curSprite() + if err != nil { + return err + } cam := ebiten.GeoM{} cam.Scale(e.state.zoom, e.state.zoom) // apply current zoom factor @@ -140,8 +124,8 @@ func (e *env) changeObjIdx(by int) func() { e.state.objIdx = 0 } - if e.state.objIdx > e.set.Count()-1 { - e.state.objIdx = e.set.Count() - 1 + if e.state.objIdx > e.set.NumObjects-1 { + e.state.objIdx = e.set.NumObjects - 1 } // reset sprite index when object changes @@ -153,15 +137,19 @@ func (e *env) changeObjIdx(by int) func() { func (e *env) changeSpriteIdx(by int) func() { return func() { - e.state.spriteIdx += by + obj, err := e.curObject() + if err != nil { + log.Printf("Encountered %v trying to change sprite index", err) + return + } + e.state.spriteIdx += by if e.state.spriteIdx < 0 { e.state.spriteIdx = 0 } - count := len(e.curObject().Sprites) - if e.state.spriteIdx > count-1 { - e.state.spriteIdx = count - 1 + if e.state.spriteIdx > obj.NumSprites-1 { + e.state.spriteIdx = obj.NumSprites - 1 } } } @@ -171,7 +159,15 @@ func (e *env) changeZoom(_, y float64) { e.state.zoom *= math.Pow(1.2, y) } -func (e *env) curObject() *conv.Object { - name := e.set.Palette[e.state.objIdx] - return e.objects[name] +func (e *env) curObject() (*assetstore.Object, error) { + return e.set.Object(e.state.objIdx) +} + +func (e *env) curSprite() (*assetstore.Sprite, error) { + obj, err := e.curObject() + if err != nil { + return nil, err + } + + return obj.Sprite(e.state.spriteIdx) } diff --git a/internal/assetstore/assetstore.go b/internal/assetstore/assetstore.go index 2d96f31..44ef545 100644 --- a/internal/assetstore/assetstore.go +++ b/internal/assetstore/assetstore.go @@ -3,6 +3,7 @@ package assetstore import ( "fmt" "io/ioutil" + "log" "os" "path/filepath" "strings" @@ -91,7 +92,10 @@ func (a *AssetStore) lookup(name, ext string, dirs ...string) (string, error) { for _, dir := range dirs { dir = canonical(dir) + log.Printf("Looking in canonical dir %s", dir) if base, ok := a.entries[dir]; ok { + log.Printf(" base: %#+v", base) + log.Printf(" filename: %v", filename) if file, ok := base[filename]; ok { actualDir := a.entries[RootDir][dir] return filepath.Join(a.RootDir, actualDir, file), nil diff --git a/internal/assetstore/object.go b/internal/assetstore/object.go index d0a82c7..cb67498 100644 --- a/internal/assetstore/object.go +++ b/internal/assetstore/object.go @@ -3,6 +3,8 @@ package assetstore import ( "fmt" "log" + "path/filepath" + "strings" "github.com/hajimehoshi/ebiten" @@ -13,7 +15,9 @@ type Object struct { assets *AssetStore sprites []*Sprite - raw *data.Object + raw *data.Object + NumSprites int + Name string } type Sprite struct { @@ -41,23 +45,49 @@ func (a *AssetStore) Object(name string) (*Object, error) { return nil, err } - raw, err := data.LoadObjectLazily(filename) + obj, err := a.ObjectByPath(filename) if err != nil { return nil, err } - raw.Name = name - - obj := &Object{ - assets: a, - sprites: make([]*Sprite, int(raw.NumSprites)), - raw: raw, - } a.objs[name] = obj + return obj, nil } -// Filled lazily +// FIXME: Objects loaded by path are not cached +func (a *AssetStore) ObjectByPath(path string) (*Object, error) { + name := filepath.Base(path) + name = strings.Replace(name, filepath.Ext(name), "", -1) + name = canonical(name) + + raw, err := data.LoadObjectLazily(path) + if err != nil { + return nil, err + } + + obj := &Object{ + assets: a, + sprites: make([]*Sprite, int(raw.NumSprites)), + raw: raw, + NumSprites: int(raw.NumSprites), + Name: canonical(name), + } + + return obj, nil +} + +// Loads all sprites in the object eagerly +func (o *Object) LoadSprites() error { + for i := 0; i < o.NumSprites; i++ { + if _, err := o.Sprite(i); err != nil { + return err + } + } + + return nil +} + func (o *Object) Sprite(idx int) (*Sprite, error) { if sprite := o.sprites[idx]; sprite != nil { return sprite, nil diff --git a/internal/assetstore/set.go b/internal/assetstore/set.go index d8df7fc..d699df8 100644 --- a/internal/assetstore/set.go +++ b/internal/assetstore/set.go @@ -14,11 +14,12 @@ var ( type Set struct { assets *AssetStore - raw *sets.MapSet + raw *sets.MapSet + NumObjects int } func (s *Set) Object(idx int) (*Object, error) { - if idx < 0 || idx >= len(s.raw.Palette) { + if idx < 0 || idx >= s.NumObjects { return nil, ErrOutOfBounds } @@ -27,6 +28,7 @@ func (s *Set) Object(idx int) (*Object, error) { func (a *AssetStore) Set(name string) (*Set, error) { name = canonical(name) + if set, ok := a.sets[name]; ok { return set, nil } @@ -43,8 +45,9 @@ func (a *AssetStore) Set(name string) (*Set, error) { } set := &Set{ - assets: a, - raw: raw, + assets: a, + raw: raw, + NumObjects: len(raw.Palette), } a.sets[name] = set diff --git a/internal/conv/font.go b/internal/conv/font.go deleted file mode 100644 index 9ae1e88..0000000 --- a/internal/conv/font.go +++ /dev/null @@ -1,23 +0,0 @@ -package conv - -import ( - "fmt" - - "code.ur.gs/lupine/ordoor/internal/fonts" -) - -type Font struct { - Name string -} - -func (f *Font) Output(to interface{}, m interface{}, format string, args ...interface{}) { - - // FIXME: actually output some text onto screen - - fmt.Printf(format+"\n", args...) -} - -func ConvertFont(font *fonts.Font) *Font { - // FIXME: actually use the pixel data in font - return &Font{Name: font.Name} -} diff --git a/internal/conv/object.go b/internal/conv/object.go deleted file mode 100644 index 7e04330..0000000 --- a/internal/conv/object.go +++ /dev/null @@ -1,59 +0,0 @@ -package conv - -import ( - "github.com/hajimehoshi/ebiten" - - "code.ur.gs/lupine/ordoor/internal/data" -) - -// Important conversions: -// -// * Width & height now stored using int -// * Colour data is now 32-bit rather than using a palette -type Sprite struct { - XOffset int - YOffset int - Width int - Height int - - Image *ebiten.Image -} - -type Object struct { - Name string - Sprites []*Sprite -} - -func MapByName(objects []*Object) map[string]*Object { - out := make(map[string]*Object, len(objects)) - - for _, obj := range objects { - out[obj.Name] = obj - } - - return out -} - -func ConvertObject(rawObj *data.Object, name string) (*Object, error) { - out := &Object{ - Name: name, - Sprites: make([]*Sprite, len(rawObj.Sprites)), - } - - for i, rawSpr := range rawObj.Sprites { - ebitenImage, err := ebiten.NewImageFromImage(rawSpr.ToImage(), ebiten.FilterDefault) - if err != nil { - return nil, err - } - - out.Sprites[i] = &Sprite{ - XOffset: int(rawSpr.XOffset), - YOffset: int(rawSpr.YOffset), - Width: int(rawSpr.Width), - Height: int(rawSpr.Height), - Image: ebitenImage, - } - } - - return out, nil -}