#!/usr/bin/perl -w

# This is a helper script for generating pimped up OSM tiles.
# The standard openstreetmap-carto-style as used on openstreetmap.org
# looks extremely dull in Zoomlevels 0-8. They look a lot nicer if
# "landuse" (forests, deserts) is shown. One way to do this is to
# generate two modifications of the osm-carto style, render tiles
# in each style, and then merge them:
# - For the background, essentially empty all .mss files except
#   style.mss and landcover.mss - you need to throw out everything but
#   the landuse. For the landuse, make sure to adapt the rules so that
#   it is shown on zoomlevel 8. Render only zoomlevel 8.
# - For the foreground, change style.mss: background-color within
#   Map { } needs to be "transparent" (without the quotes). #world in
#   shapefiles.mss needs to be removed. Render zoomlevels 0-8.
# For rendering, the polytiles.pl script from
# https://github.com/Zverik/polytiles can be very helpful.
# You might have to remove some non installed fonts from the XML.
# After you are done rendering the source tiles, you can then use this
# script to merge back+foreground. Voila, nicer looking tiles!

# WARNING: Doing this for zoom level 0 in HD requires 90 GB of
# space in $TMPDIR and/or RAM (depending on Graphics::Magick behaviour/config)!
# That's why levels 0+1 are not generated by default (you need to change
# a line below, or generate them manually instead).

# URL generally is:   /zoom/X/Y.png  within the dirs below.

# The source for the foreground that you want to put over the
# background. The foreground needs to exist for all zoomlevels you
# want to generate.
$srcfgpath = '/mnt/tiles/statictiles/osm.org-lowzoom-fg/';
# The source for the background. Only one zoomlevel needs to exist,
# see ZOOMMAX below.
$srcbgpath = '/mnt/tiles/statictiles/osm.org-lowzoom-bg/';
# Where the combined tiles (background+foreground) are written to.
$dstpath='/mnt/tiles/statictiles/osm.org-lowzoom-new/';

# The name is a bit misleading: ZOOMMAX actually sets the zoomlevel
# from which the backgrounds are taken (and then scaled as needed).
# You obviously cannot merge tiles with a zoomlevel greater than
# that.
$ZOOMMAX = 8;

# Tilesize. Usually 256 for normal tiles or 512 for HD.
$TILESIZE = 256;

use Graphics::Magick;

# Par. 0:  Z
# Par. 1:  X
# Par. 2:  Y
sub mergetile($$$) {
  my $ZS = $_[0];
  my $XS = $_[1];
  my $YS = $_[2];
  my $N = 1;
  my $dstfilename = sprintf("%s/%d/%d/%d.png", $dstpath, $ZS, $XS, $YS);
  my $olfilename = sprintf("%s/%d/%d/%d.png", $srcfgpath, $ZS, $XS, $YS);
  if ($ZS > $ZOOMMAX) {
    print("Sorry - can only merge Z <= $ZOOMMAX\n"); exit(1);
  }
  my $z = $ZS;
  while ($ZS < $ZOOMMAX) {
    $N = $N * 2;  # Twice as many tiles (per direction)
    $XS = $XS * 2; # Starting at 2*X
    $YS = $YS * 2; # and 2*Y.
    $ZS++;
  }
  printf("Combining %d tiles (%d x %d pixels)\n", $N * $N, $N * $TILESIZE, $N * $TILESIZE);
  # Now load them all and fill them into one big picture.
  my $dimage = Graphics::Magick->new('size' => sprintf("%dx%d", $N * $TILESIZE, $N * $TILESIZE)); # magick => 'png', 
  $status = $dimage->Read("xc:white"); # This actually creates the image, the above does NOT - very intuitive!
  warn "$status" if "$status";
  my $x; my $y;
  for ($x = 0; $x < $N; $x++) {
    for ($y = 0; $y < $N; $y++) {
      my $fn = sprintf("%s/%d/%d/%d.png", $srcbgpath, $ZOOMMAX, $XS + $x, $YS + $y);
      #print("Loading: $fn\n");
      my $tmpimg = Graphics::Magick->new();
      $status = $tmpimg->Read($fn);
      warn "$status" if "$status";
      $dimage->Composite( 'image' => $tmpimg, 'compose' => 'over',
                          'x' => ($x * $TILESIZE),
                          'y' => ($y * $TILESIZE));
    }
  }
  $dimage->Resize('geometry' => sprintf("%dx%d", $TILESIZE, $TILESIZE), 'filter' => 'Lanczos');
  #print("Loading: $olfilename\n");
  my $olimg = Graphics::Magick->new();
  $status = $olimg->Read($olfilename);
  warn "$status" if "$status";
  $dimage->Composite( 'image' => $olimg, 'compose' => 'over', 'x' => 0, 'y' => 0 );
  print("Writing combined image to: $dstfilename\n");
  $status = $dimage->Write($dstfilename);
  warn "$status" if "$status";
}

# "main()"

#mergetile(1, 1, 0);
#mergetile(2, 2, 1);
#mergetile(3, 4, 2);
#mergetile(4, 8, 5);
#mergetile(5, 16, 10);
#mergetile(6, 33, 21);
#mergetile(7, 67, 43);
#mergetile(8, 135, 87);
my $rz; my $rx; my $ry;
for ($rz = 2; $rz <= 8; $rz++) {
  my $ntilesperdir = 2 ** $rz;  # Allgemein: 2 ^ Zoomlevel
  for ($rx = 0; $rx < $ntilesperdir; $rx++) {
    my $targdir = sprintf("%s/%d/%d", $dstpath, $rz, $rx);
    if (! -e $targdir) {
      print("Trying to create $targdir...");
      # FIXME: mkdir -p   - the zoom level dir might not exist either!
      if (mkdir($targdir)) {
        print(" OK!\n");
      } else {
        print(" FAILED!\n");
      }
    }
    for ($ry = 0; $ry < $ntilesperdir; $ry++) {
      mergetile($rz, $rx, $ry);
    }
  }
}

