package generator import ( "fmt" "image" "image/draw" "image/png" "io" "github.com/nfnt/resize" "github.com/pkg/errors" "github.com/tribalwarshelp/shared/models" ) const ( defaultBackgroundColor = "#000" defaultGridLineColor = "#fff" defaultContinentNumberColor = "#fff" defaultMapSize = 1000 ) type Marker struct { Villages []*models.Village `json:"villages" gqlgen:"villages" xml:"villages"` Color string `json:"color" gqlgen:"color" xml:"color"` } type Config struct { Markers []*Marker Destination io.Writer MapSize int ContinentGrid bool ContinentNumbers bool BackgroundColor string GridLineColor string ContinentNumberColor string Scale float32 CenterX int CenterY int } func (cfg *Config) init() { if cfg.BackgroundColor == "" { cfg.BackgroundColor = defaultBackgroundColor } if cfg.GridLineColor == "" { cfg.GridLineColor = defaultGridLineColor } if cfg.ContinentNumberColor == "" { cfg.ContinentNumberColor = defaultContinentNumberColor } if cfg.MapSize <= 0 { cfg.MapSize = defaultMapSize } if cfg.Scale <= 0 { cfg.Scale = 1 } if cfg.CenterX <= 0 { cfg.CenterX = cfg.MapSize / 2 } if cfg.CenterY <= 0 { cfg.CenterY = cfg.MapSize / 2 } cfg.CenterX = int(float32(cfg.CenterX) * cfg.Scale) cfg.CenterY = int(float32(cfg.CenterY) * cfg.Scale) } func Generate(cfg Config) error { cfg.init() upLeft := image.Point{0, 0} lowRight := image.Point{cfg.MapSize, cfg.MapSize} img := image.NewRGBA(image.Rectangle{upLeft, lowRight}) mapSizeDividedBy10 := cfg.MapSize / 10 imgHalfWidth := cfg.MapSize / 2 imgHalfHeight := imgHalfWidth backgroundColor, err := parseHexColorFast(cfg.BackgroundColor) if err != nil { return errors.Wrap(err, "map-generator") } // Background. for y := 0; y < cfg.MapSize; y++ { for x := 0; x < cfg.MapSize; x++ { img.Set(x, y, backgroundColor) } } // Markers for _, marker := range cfg.Markers { parsedColor, err := parseHexColorFast(marker.Color) if err != nil { return err } for _, village := range marker.Villages { img.Set(village.X, village.Y, parsedColor) } } //Continents if cfg.ContinentGrid { gridLineColor, err := parseHexColorFast(cfg.GridLineColor) if err != nil { return errors.Wrap(err, "map-generator") } for y := mapSizeDividedBy10; y < cfg.MapSize; y += mapSizeDividedBy10 { for x := 0; x < cfg.MapSize; x++ { img.Set(x, y, gridLineColor) } } for x := mapSizeDividedBy10; x < cfg.MapSize; x += mapSizeDividedBy10 { for y := 0; y < cfg.MapSize; y++ { img.Set(x, y, gridLineColor) } } } if cfg.ContinentNumbers { continent := 0 continentNumberColor, err := parseHexColorFast(cfg.ContinentNumberColor) if err != nil { return errors.Wrap(err, "map-generator") } for y := mapSizeDividedBy10; y <= cfg.MapSize; y += mapSizeDividedBy10 { for x := mapSizeDividedBy10; x <= cfg.MapSize; x += mapSizeDividedBy10 { continentStr := fmt.Sprintf("%d", continent) if continent < 10 { continentStr = fmt.Sprintf("0%d", continent) } drawText(img, x-16, y-3, continentNumberColor, continentStr) continent++ } } } var resizedImg image.Image = img if cfg.Scale != 1 { width := uint(float32(cfg.MapSize) * cfg.Scale) resizedImg = resize.Resize(width, width, img, resize.Lanczos3) } b := resizedImg.Bounds() centered := image.NewRGBA(image.Rectangle{upLeft, lowRight}) draw.Draw(centered, b, resizedImg, image.Point{ X: cfg.CenterX - imgHalfWidth, Y: cfg.CenterY - imgHalfHeight, }, draw.Src) if err := png.Encode(cfg.Destination, centered); err != nil { return errors.Wrap(err, "map-generator") } return nil }