Skip to content

Commit

Permalink
add: add tiles historic to handle multiple screen sharing same tiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Jerome Le Saux committed May 14, 2024
1 parent 1f59824 commit 8142d2f
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 47 deletions.
2 changes: 1 addition & 1 deletion cmd/martine/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -706,7 +706,7 @@ func main() {
16x16 : 20x24
*/

if err := gfx.Tilemap(screenMode, filename, *picturePath, size, in, cfg); err != nil {
if err := gfx.Tilemap(screenMode, filename, *picturePath, size, in, cfg, nil); err != nil {
log.GetLogger().Error("Error whie do tilemap action with error :%v\n", err)
os.Exit(-1)
}
Expand Down
96 changes: 96 additions & 0 deletions export/sprite/tiles_collection.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package sprite

import (
"encoding/json"
"image"
"os"
"path/filepath"

"github.com/jeromelesaux/martine/constants"
)

const (
tileHistoricalFilename = "tiles_historical.th"
)

type TilesHistorical struct {
Width int `json:"width"`
Height int `json:"height"`
Tiles []TileHistorical `json:"sprites"`
}

type TileHistorical struct {
Label string `json:"label"`
Index int `json:"index"`
Tile *image.NRGBA `json:"sprite"`
}

func NewSpritesHistorical(width, height int) *TilesHistorical {
return &TilesHistorical{
Width: width,
Height: height,
Tiles: make([]TileHistorical, 0),
}
}

func (s *TilesHistorical) Add(spr TileHistorical) {
s.Tiles = append(s.Tiles, spr)
}

func (s TilesHistorical) LastIndex() int {
var index int
for _, spr := range s.Tiles {
if spr.Index > index {
index = spr.Index
}
}
return index
}

func (s *TilesHistorical) Append(n *TilesHistorical) {
s.Tiles = append(s.Tiles, n.Tiles...)
}

func (s *TilesHistorical) Save(folderpath string) error {
f, err := os.Open(filepath.Join(folderpath, tileHistoricalFilename))
if err != nil {
return err
}
defer f.Close()
return json.NewEncoder(f).Encode(s)
}

func (s TilesHistorical) Tile(i *image.NRGBA) (TileHistorical, bool) {
for _, spr := range s.Tiles {
if ImageAreEquals(spr.Tile, i) {
return spr, true
}
}
return TileHistorical{}, false
}

func (s TilesHistorical) IndexOf(i *image.NRGBA) int {
for _, spr := range s.Tiles {
if ImageAreEquals(spr.Tile, i) {
return spr.Index
}
}
return -1
}

func ImageAreEquals(i0, i1 *image.NRGBA) bool {
if i1 == nil || i0 == nil {
return false
}
if i0.Bounds().Max.X != i1.Bounds().Max.X || i0.Bounds().Max.Y != i1.Bounds().Max.Y {
return false
}
for y := 0; y < i0.Bounds().Max.Y; y++ {
for x := 0; x < i0.Bounds().Max.X; x++ {
if !constants.ColorsAreEquals(i0.At(x, y), i1.At(x, y)) {
return false
}
}
}
return true
}
2 changes: 1 addition & 1 deletion gfx/animate/animate_motif.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ func DeltaMotif(gitFilepath string, cfg *config.MartineConfig, threshold int, in
}

// recuperation des motifs
a := transformation.AnalyzeTilesBoard(screens[0], constants.Size{Width: 4, Height: 4})
a := transformation.AnalyzeTilesBoard(screens[0], constants.Size{Width: 4, Height: 4}, nil)
refBoard := a.ReduceTilesNumber(float64(threshold))
btc := make([][]transformation.BoardTile, 0)
btc = append(btc, refBoard)
Expand Down
2 changes: 0 additions & 2 deletions gfx/sprite/board.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,3 @@ func SplitBoardToSprite(
}*/
return results, rawSprites, nil
}


22 changes: 12 additions & 10 deletions gfx/tilemap.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
impPalette "github.com/jeromelesaux/martine/export/impdraw/palette"
"github.com/jeromelesaux/martine/export/impdraw/tile"
"github.com/jeromelesaux/martine/export/png"
"github.com/jeromelesaux/martine/export/sprite"
"github.com/jeromelesaux/martine/gfx/errors"
"github.com/jeromelesaux/martine/gfx/transformation"
)
Expand Down Expand Up @@ -68,7 +69,7 @@ func AnalyzeTilemap(mode uint8, isCpcPlus bool, filename, picturePath string, in
if !impTileFlag {
for size.Width <= 32 || size.Height <= 32 {
log.GetLogger().Info("Analyse the image for size [width:%d,height:%d]", size.Width, size.Height)
board := transformation.AnalyzeTilesBoard(m, size)
board := transformation.AnalyzeTilesBoard(m, size, nil)
tilesSize := sizeOctet(board.TileSize, mode) * len(board.BoardTiles)
log.GetLogger().Info(" found [%d] tiles full length [#%X]\n", len(board.BoardTiles), tilesSize)
boards = append(boards, board)
Expand All @@ -78,7 +79,7 @@ func AnalyzeTilemap(mode uint8, isCpcPlus bool, filename, picturePath string, in
} else {
for _, s := range impTilesSizes {
log.GetLogger().Info("Analyse the image for size [width:%d,height:%d]", s.Width, s.Height)
board := transformation.AnalyzeTilesBoard(m, s)
board := transformation.AnalyzeTilesBoard(m, s, nil)
tilesSize := sizeOctet(board.TileSize, mode) * len(board.BoardTiles)
log.GetLogger().Info(" found [%d] tiles full length [#%X]\n", len(board.BoardTiles), tilesSize)
boards = append(boards, board)
Expand Down Expand Up @@ -263,10 +264,10 @@ func ExportTilemapClassical(m image.Image, filename string, board *transformatio
log.GetLogger().Error("Cannot export to Imp-TileMap the image %s error %v", cfg.OutputPath, err)
return err
}
return nil
return board.SaveHistoric(cfg.OutputPath)
}

func TilemapClassical(mode uint8, isCpcPlus bool, filename, picturePath string, in image.Image, size constants.Size, cfg *config.MartineConfig) (*transformation.AnalyzeBoard, [][]image.Image, color.Palette) {
func TilemapClassical(mode uint8, isCpcPlus bool, filename, picturePath string, in image.Image, size constants.Size, cfg *config.MartineConfig, tilesHistoric *sprite.TilesHistorical) (*transformation.AnalyzeBoard, [][]image.Image, color.Palette) {
mapSize := constants.Size{Width: in.Bounds().Max.X, Height: in.Bounds().Bounds().Max.Y, ColorsAvailable: 16}
m := ci.Resize(in, mapSize, cfg.ResizingAlgo)
var palette color.Palette
Expand All @@ -278,7 +279,7 @@ func TilemapClassical(mode uint8, isCpcPlus bool, filename, picturePath string,
palette = ci.ToCPCPalette(palette, refPalette)
palette = constants.SortColorsByDistance(palette)
_, m = ci.DowngradingWithPalette(m, palette)
tilemap := transformation.AnalyzeTilesBoard(m, size)
tilemap := transformation.AnalyzeTilesBoard(m, size, tilesHistoric)
var tilesImagesTilemap [][]image.Image
for y := 0; y < m.Bounds().Max.Y; y += tilemap.TileSize.Height {
tilesmap := make([]image.Image, 0)
Expand Down Expand Up @@ -309,7 +310,7 @@ func sizeOctet(size constants.Size, mode uint8) int {
}

// nolint: funlen, gocognit
func Tilemap(mode uint8, filename, picturePath string, size constants.Size, in image.Image, cfg *config.MartineConfig) error {
func Tilemap(mode uint8, filename, picturePath string, size constants.Size, in image.Image, cfg *config.MartineConfig, tilesHistoric *sprite.TilesHistorical) error {
/*
8x8 : 40x25
16x8 : 20x25
Expand Down Expand Up @@ -376,7 +377,7 @@ func Tilemap(mode uint8, filename, picturePath string, size constants.Size, in i
if err != nil {
return err
}
analyze := transformation.AnalyzeTilesBoard(m, cfg.Size)
analyze := transformation.AnalyzeTilesBoard(m, cfg.Size, tilesHistoric)
tilesSize := sizeOctet(analyze.TileSize, mode) * len(analyze.BoardTiles)
log.GetLogger().Info("board with number of tiles [%d] and size [width:%d, height:%d] size:#%X\n", len(analyze.BoardTiles), analyze.TileSize.Width, analyze.TileSize.Height, tilesSize)
if err := analyze.SaveSchema(filepath.Join(cfg.OutputPath, "tilesmap_schema.png")); err != nil {
Expand Down Expand Up @@ -498,7 +499,7 @@ func fillImage(m image.Image, scenes []*image.NRGBA, nbTilePixelHigh, nbTilePixe
}

// nolint: funlen
func TilemapRaw(mode uint8, isCpcPlus bool, size constants.Size, in image.Image, cfg *config.MartineConfig) (*transformation.AnalyzeBoard, [][]image.Image, color.Palette, error) {
func TilemapRaw(mode uint8, isCpcPlus bool, size constants.Size, in image.Image, cfg *config.MartineConfig, tilesHistoric *sprite.TilesHistorical) (*transformation.AnalyzeBoard, [][]image.Image, color.Palette, error) {
/*
8x8 : 40x25
16x8 : 20x25
Expand Down Expand Up @@ -546,7 +547,7 @@ func TilemapRaw(mode uint8, isCpcPlus bool, size constants.Size, in image.Image,
palette = constants.SortColorsByDistance(palette)
_, m = ci.DowngradingWithPalette(m, palette)

analyze := transformation.AnalyzeTilesBoard(m, cfg.Size)
analyze := transformation.AnalyzeTilesBoard(m, cfg.Size, tilesHistoric)

// now display all maps images
for y := 0; y < len(analyze.TileMap); y++ {
Expand Down Expand Up @@ -635,7 +636,8 @@ func ExportTilemap(analyze *transformation.AnalyzeBoard, filename string, palett
index++
}
}
return
// save historic
return analyze.SaveHistoric(cfg.OutputPath)
}

// nolint: funlen, gocognit
Expand Down
2 changes: 1 addition & 1 deletion gfx/transformation/motif_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestMotifs(t *testing.T) {
if err != nil {
t.Fatal(err)
}
a := transformation.AnalyzeTilesBoard(out, constants.Size{Width: 4, Height: 4})
a := transformation.AnalyzeTilesBoard(out, constants.Size{Width: 4, Height: 4}, nil)
threshold := 27
board := a.ReduceTilesNumber(float64(threshold))
fmt.Printf("number sprites inital [%d] [%d] with threshold :%d\n", len(a.BoardTiles), len(board), threshold)
Expand Down
95 changes: 66 additions & 29 deletions gfx/transformation/tile_analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
"github.com/jeromelesaux/martine/export/amsdos"
"github.com/jeromelesaux/martine/export/ascii"
"github.com/jeromelesaux/martine/export/png"
exspr "github.com/jeromelesaux/martine/export/sprite"
"github.com/jeromelesaux/martine/gfx/errors"
"github.com/jeromelesaux/martine/log"
"github.com/pbnjay/pixfont"
Expand Down Expand Up @@ -48,15 +49,32 @@ func (b *BoardTile) AddTile(tp []TilePosition) {
b.TilePositions = append(b.TilePositions, tp...)
}

func (a *AnalyzeBoard) Analyse(sprite *Tile, x, y int) int {
func (a *AnalyzeBoard) Analyse(tile *Tile, x, y int) int {
var index int
if a.historicalTiles != nil {
index = a.historicalTiles.LastIndex()
}
for i, v := range a.BoardTiles {
if TilesAreEquals(v.Tile, sprite) {
a.SetAddTile(x, y, i)
return i
if a.historicalTiles != nil {
spt, found := a.historicalTiles.Tile(tile.Image())
if found {
a.SetAddTile(x, y, spt.Index)
}
} else {
if TilesAreEquals(v.Tile, tile) {
a.SetAddTile(x, y, i+index)
return i
} else {
a.newHistoricalTiles.Add(exspr.TileHistorical{
Label: fmt.Sprintf("tile_%02d", index+i),
Index: index + i,
Tile: v.Tile.Image(),
})
}
}
}

a.NewTile(sprite, x, y)
a.NewTile(tile, x, y)
return len(a.BoardTiles) - 1

}
Expand Down Expand Up @@ -85,11 +103,43 @@ func (a *AnalyzeBoard) NewTile(sprite *Tile, x, y int) {
}

type AnalyzeBoard struct {
Tiles [][]image.Image
BoardTiles []BoardTile
TileSize constants.Size
ImageSize constants.Size
TileMap [][]int
Tiles [][]image.Image
BoardTiles []BoardTile
TileSize constants.Size
ImageSize constants.Size
TileMap [][]int
historicalTiles *exspr.TilesHistorical
newHistoricalTiles *exspr.TilesHistorical
}

func NewAnalyzeBoard(
tilesize constants.Size,
imgSize image.Rectangle,
horizontalTileNumber int,
verticalTileNumber int,
historic *exspr.TilesHistorical,
) *AnalyzeBoard {
a := &AnalyzeBoard{
TileSize: tilesize,
ImageSize: constants.Size{Width: imgSize.Max.X, Height: imgSize.Max.Y},
BoardTiles: make([]BoardTile, 0),
TileMap: make([][]int, horizontalTileNumber),
historicalTiles: historic,
newHistoricalTiles: exspr.NewSpritesHistorical(tilesize.Width, tilesize.Height),
}
for i := 0; i < horizontalTileNumber; i++ {
a.TileMap[i] = make([]int, verticalTileNumber)
}
return a
}

func (a *AnalyzeBoard) SaveHistoric(folderpath string) error {
if a.historicalTiles == nil {
a.historicalTiles = a.newHistoricalTiles
} else {
a.historicalTiles.Append(a.newHistoricalTiles)
}
return a.historicalTiles.Save(folderpath)
}

func (a *AnalyzeBoard) TileIndex(tile *Tile, tiles []BoardTile) int {
Expand Down Expand Up @@ -242,15 +292,7 @@ func getCloserTile(sprt Tile, t []Tile) Tile {
func AnalyzeTilesBoardWithTiles(im image.Image, size constants.Size, tiles []Tile) *AnalyzeBoard {
nbTileW := im.Bounds().Max.X / size.Width
nbTileH := (im.Bounds().Max.Y / size.Height) - 1
board := &AnalyzeBoard{
TileSize: size,
ImageSize: constants.Size{Width: im.Bounds().Max.X, Height: im.Bounds().Max.Y},
BoardTiles: make([]BoardTile, 0),
TileMap: make([][]int, nbTileH),
}
for i := 0; i < nbTileH; i++ {
board.TileMap[i] = make([]int, nbTileW)
}
board := NewAnalyzeBoard(size, im.Bounds(), nbTileH, nbTileW, nil)

indexX := 1
for x := size.Width; x < im.Bounds().Max.X; x += size.Width {
Expand All @@ -268,25 +310,19 @@ func AnalyzeTilesBoardWithTiles(im image.Image, size constants.Size, tiles []Til
}
indexX++
}

return board
}

func AnalyzeTilesBoard(im image.Image, size constants.Size) *AnalyzeBoard {
func AnalyzeTilesBoard(im image.Image, size constants.Size, tilesHistoric *exspr.TilesHistorical) *AnalyzeBoard {
var heightCorrection int
if (im.Bounds().Max.Y % size.Height) != 0 {
heightCorrection = 1
}
nbTileW := (im.Bounds().Max.X / size.Width) + 1
nbTileH := (im.Bounds().Max.Y / size.Height) - (heightCorrection) + 1
board := &AnalyzeBoard{
TileSize: size,
ImageSize: constants.Size{Width: im.Bounds().Max.X, Height: im.Bounds().Max.Y},
BoardTiles: make([]BoardTile, 0),
TileMap: make([][]int, nbTileH),
}
for i := 0; i < nbTileH; i++ {
board.TileMap[i] = make([]int, nbTileW)
}
board := NewAnalyzeBoard(size, im.Bounds(), nbTileH, nbTileW, tilesHistoric)

sprt0, _ := ExtractTile(im, size, 0, 0)
/* if err != nil {
log.GetLogger().Error( "Error while extracting tile size(%d,%d) at position (%d,%d) error :%v\n", size.Width, size.Height, 0, 0, err)
Expand All @@ -309,6 +345,7 @@ func AnalyzeTilesBoard(im image.Image, size constants.Size) *AnalyzeBoard {
}
indexX++
}

return board
}

Expand Down
2 changes: 1 addition & 1 deletion gfx/transformation/tile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ func TestBoardSprite(t *testing.T) {
if err != nil {
t.Fatalf("Cannot decode png file error :%v\n", err)
}
a := transformation.AnalyzeTilesBoard(im, constants.Size{Width: 16, Height: 16})
a := transformation.AnalyzeTilesBoard(im, constants.Size{Width: 16, Height: 16}, nil)
//t.Log(a.String())
//fmt.Println(a.String())
err = a.SaveSchema("../../test/alexkidd_board.png")
Expand Down
2 changes: 2 additions & 0 deletions ui/martine-ui/menu/tilemap_menu.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (

"fyne.io/fyne/v2"
w "github.com/jeromelesaux/fyne-io/widget"
"github.com/jeromelesaux/martine/export/sprite"
"github.com/jeromelesaux/martine/gfx/transformation"
"github.com/jeromelesaux/martine/log"
)
Expand All @@ -26,6 +27,7 @@ type TilemapMenu struct {
ExportFolderPath string
ExportImpdraw bool
ExportFlat bool
Historic *sprite.TilesHistorical
}

func (tm *TilemapMenu) ResetExport() {
Expand Down
Loading

0 comments on commit 8142d2f

Please sign in to comment.