diff --git a/go.mod b/go.mod index ef8d8a0..c602e83 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,7 @@ require ( github.com/jfreymuth/oggvorbis v1.0.1 // indirect github.com/kr/text v0.2.0 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + github.com/samuel/go-pcx v0.0.0-20180426214139-d9c017170db4 github.com/stretchr/testify v1.5.1 golang.org/x/exp v0.0.0-20200331195152-e8c3332aa8e5 // indirect golang.org/x/image v0.0.0-20200119044424-58c23975cae1 diff --git a/go.sum b/go.sum index 957dc7e..92f91d7 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,8 @@ github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLA github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/samuel/go-pcx v0.0.0-20180426214139-d9c017170db4 h1:Y/KOCu+ZLB730PudefxfsKVjtI0m0RhvFk9a0l4O1+c= +github.com/samuel/go-pcx v0.0.0-20180426214139-d9c017170db4/go.mod h1:qxuIawynlRhuaHowuXvd1xjyFWx87Ro4gkZlKRXtHnQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= diff --git a/internal/assetstore/assetstore.go b/internal/assetstore/assetstore.go index 6cda5ee..381911b 100644 --- a/internal/assetstore/assetstore.go +++ b/internal/assetstore/assetstore.go @@ -8,6 +8,8 @@ import ( "path/filepath" "strings" + "github.com/hajimehoshi/ebiten" + "code.ur.gs/lupine/ordoor/internal/config" "code.ur.gs/lupine/ordoor/internal/data" "code.ur.gs/lupine/ordoor/internal/idx" @@ -44,6 +46,7 @@ type AssetStore struct { fonts map[string]*Font generic *data.Generic idx *idx.Idx + images map[string]*ebiten.Image maps map[string]*Map menus map[string]*Menu objs map[string]*Object @@ -109,6 +112,7 @@ func (a *AssetStore) Refresh() error { a.entries = newEntryMap a.fonts = make(map[string]*Font) a.idx = nil + a.images = make(map[string]*ebiten.Image) a.maps = make(map[string]*Map) a.menus = make(map[string]*Menu) a.objs = make(map[string]*Object) diff --git a/internal/assetstore/image.go b/internal/assetstore/image.go new file mode 100644 index 0000000..02178db --- /dev/null +++ b/internal/assetstore/image.go @@ -0,0 +1,42 @@ +package assetstore + +import ( + "image" + "os" + + "github.com/hajimehoshi/ebiten" + _ "github.com/samuel/go-pcx/pcx" // PCX support +) + +func (a *AssetStore) Image(name string) (*ebiten.Image, error) { + name = canonical(name) + if img, ok := a.images[name]; ok { + return img, nil + } + + // baps, ordoor, geas store .pcx files in Pic + // TODO: SL stores .bmp files in Res + filename, err := a.lookup(name, "pcx", "Pic") + if err != nil { + return nil, err + } + + f, err := os.Open(filename) + if err != nil { + return nil, err + } + defer f.Close() + + rawImg, _, err := image.Decode(f) + if err != nil { + return nil, err + } + + img, err := ebiten.NewImageFromImage(rawImg, ebiten.FilterDefault) + if err != nil { + return nil, err + } + + a.images[name] = img + return img, nil +} diff --git a/internal/ordoor/display.go b/internal/ordoor/display.go new file mode 100644 index 0000000..1d38186 --- /dev/null +++ b/internal/ordoor/display.go @@ -0,0 +1,20 @@ +package ordoor + +import ( + "time" +) + +func (o *Ordoor) DisplayImageFor(d time.Duration, name string) error { + img, err := o.assets.Image(name) + if err != nil { + return err + } + + o.pic = img + go func() { + <-time.After(d) + o.pic = nil // FIXME: this is a race condition and a half + }() + + return nil +} diff --git a/internal/ordoor/ordoor.go b/internal/ordoor/ordoor.go index 386fddc..fd0aa01 100644 --- a/internal/ordoor/ordoor.go +++ b/internal/ordoor/ordoor.go @@ -7,6 +7,7 @@ package ordoor import ( "fmt" "log" + "time" "github.com/hajimehoshi/ebiten" "github.com/hajimehoshi/ebiten/audio" @@ -29,6 +30,10 @@ type Ordoor struct { // Relevant to interface state flow *flow.Flow + // FIXME: should be put inside flow + // If this is set, we display it instead of flow + pic *ebiten.Image + // Relevant to campaign state ship *ship.Ship } @@ -81,10 +86,6 @@ func Run(configFile string, overrideX, overrideY int) error { ordoor.win = win - if err := ordoor.setupFlow(); err != nil { - return fmt.Errorf("failed to setup UI flow: %v", err) - } - if err := ordoor.Run(); err != nil { return fmt.Errorf("Run finished with error: %v", err) } @@ -93,12 +94,16 @@ func Run(configFile string, overrideX, overrideY int) error { } func (o *Ordoor) Run() error { - // FIXME: we're missing a screen about SSI here + // FIXME: these should be displayed *after*, not *before*, the copyright if o.config.Options.PlayMovies { o.PlaySkippableVideo("LOGOS") o.PlaySkippableVideo("movie1") } + if err := o.DisplayImageFor(time.Second, "copyright"); err != nil { + log.Printf("Failed to display copyright image: %v", err) + } + err := o.win.Run() if err == flow.ErrExit { log.Printf("Exit requested") @@ -151,6 +156,16 @@ func (o *Ordoor) setupFlow() error { } func (o *Ordoor) Update(screenX, screenY int) error { + if pic := o.pic; pic != nil { + return nil // Ignore flow until we don't have a pic any more + } + + if o.flow == nil { + if err := o.setupFlow(); err != nil { + return fmt.Errorf("failed to setup UI flow: %v", err) + } + } + // Ensure music is doing the right thing if o.music != nil && o.music.IsPlaying() != o.config.Options.PlayMusic { if o.config.Options.PlayMusic { @@ -165,9 +180,24 @@ func (o *Ordoor) Update(screenX, screenY int) error { } func (o *Ordoor) Draw(screen *ebiten.Image) error { + if pic := o.pic; pic != nil { + // Scale the picture to the screen and draw it + scaleX := float64(screen.Bounds().Dx()) / float64(pic.Bounds().Dx()) + scaleY := float64(screen.Bounds().Dy()) / float64(pic.Bounds().Dy()) + + do := &ebiten.DrawImageOptions{} + do.GeoM.Scale(scaleX, scaleY) + + return screen.DrawImage(pic, do) + } + return o.flow.Draw(screen) } func (o *Ordoor) Cursor() (*ebiten.Image, *ebiten.DrawImageOptions, error) { - return o.flow.Cursor() + if o.flow != nil { + return o.flow.Cursor() + } + + return nil, nil, nil }