]> marstr Code Repo - marstr/orthographic.git/commitdiff
Massive commit. Raytracer for tile preparation. Resource generator. Everything moved...
authorMarcus Str. <marcus@marstr.online>
Tue, 17 Dec 2024 16:18:05 +0000 (17:18 +0100)
committerMarcus Str. <marcus@marstr.online>
Tue, 17 Dec 2024 16:18:05 +0000 (17:18 +0100)
defines.py
functions.py
layergen.py
log.py
maskgen.py
og.py
orthographic.py
photogen.py
tileinfo.py
tileprep.py
xp_normalmap.py

index b437c17a39fa43bdb9496cb33ef0ea61dcf659a0..638d86b40dd4eedc23a8f835ba1d5d967a080791 100644 (file)
@@ -132,6 +132,7 @@ mstr_ortho_layers = [
     ("natural", "bare_rock", "natural", "bare_rock"),\r
     ("highway", "track", 3),\r
     ("highway", "path", 3),\r
+    ("highway", "footway", 4),\r
     ("leisure", "park", "leisure", "green"),\r
     ("leisure", "dog_park", "leisure", "green"),\r
     ("leisure", "garden", "leisure", "green"),\r
@@ -144,7 +145,6 @@ mstr_ortho_layers = [
     # Z-Order 2\r
     ("highway", "service", 6),\r
     ("highway", "residential", 12),\r
-    ("highway", "footway", 4),\r
     ("highway", "primary", 25),\r
     ("highway", "secondary", 13),\r
     ("highway", "tertiary", 20),\r
@@ -191,6 +191,7 @@ mstr_ortho_layers = [
     ("building", "kindergarten", "building", "kindergarten"),\r
     ("building", "public", "building", "public"),\r
     ("building", "commercial", "building", "commercial"),\r
+    ("building", "warehouse", "building", "warehouse"),\r
     ("building", "yes", "building", "common"),\r
     ("water", "lake", "natural", "water"),\r
     ("water", "pond", "natural", "water"),\r
@@ -281,9 +282,10 @@ mstr_mask_blur = [
     ("building", "terrace", 1),\r
     ("building", "hangar", 1),\r
     ("building", "school", 1),\r
-       ("building", "kindergarten", 1),\r
-       ("building", "public", 1),\r
-       ("building", "commercial", 1),\r
+    ("building", "kindergarten", 1),\r
+    ("building", "public", 1),\r
+    ("building", "commercial", 1),\r
+    ("building", "warehouse", 1),\r
     ("building", "yes", 0),\r
     ("place", "sea", 1),\r
     ("place", "ocean", 1)\r
@@ -396,7 +398,13 @@ mstr_building_base_colors = [
         "#373942", "#40424a", "#363b4f", "#2c2d32", "#444651",\r
         "#454545", "#39393b", "#4b4b4c", "#363638", "#525252"\r
         ]\r
-    )\r
+    ),\r
+    ("warehouse", [\r
+        "#403a33", "#4f4b46", "#413629", "#574c3f", "#3a2e21",\r
+        "#aaaeb6", "#939cac", "#8a919d", "#a0b9bf", "#8d999b",\r
+        "#49575a", "#273d43", "#313a3c", "#484f50", "#212d30"\r
+        ]\r
+    ),\r
 ]\r
 \r
 \r
index c1d89b4dbb1d8b211f99edc984c24ff5b9bee178..0e1cc4473f6acefd788e79de420e0352de47616f 100644 (file)
@@ -107,4 +107,5 @@ def xplane_latlng_folder(numbers):
     if abs(numbers[1]) >= 10 and numbers[0] <= 99: fstr = fstr + "0" + str(numbers[1])\r
     if abs(numbers[1]) >= 100 : fstr = fstr + str(numbers[1])\r
 \r
-    return fstr
\ No newline at end of file
+    return fstr\r
+\r
index adf6451673050435af282c7a9b77f746bccd3cf2..ff3dd651b6ae75bde300db5a2ffbe939239374b4 100644 (file)
 \r
 import glob\r
 import os\r
+import time\r
 from random import randrange\r
 import random\r
-from PIL import Image, ImageFilter, ImageDraw\r
+\r
+import PIL.ImageOps\r
+from PIL import Image, ImageFilter, ImageDraw, ImageOps, ImageFile\r
 from defines import *\r
 from log import *\r
 from tileinfo import *\r
 from osmxml import *\r
 from functions import *\r
+from resourcegen import *\r
+\r
+ImageFile.LOAD_TRUNCATED_IMAGES = True\r
 \r
 class mstr_layergen:\r
 \r
@@ -116,7 +122,7 @@ class mstr_layergen:
     # Find the source to use pre-determined in phase one\r
     def findLayerSource(self):\r
         # The source number\r
-        src = -1\r
+        src = []\r
 \r
         # The already existing source data\r
         srcfile = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(self._lat_number) + "_" + str(self._lng_number)\r
@@ -125,26 +131,125 @@ class mstr_layergen:
         with open(srcfile) as file:\r
             for line in file:\r
                 linedata = line.split(" ")\r
-                if linedata[2] == self._tag and linedata[3] == self._value:\r
-                    src = int(linedata[4])\r
+                if linedata[0] == self._tag and linedata[1] == self._value:\r
+                    src = linedata[2].split(",")\r
                     break\r
         \r
-        # Should we encounter a -1 at this point, we can choose something\r
+        # Should we encounter a 0 length at this point, we can choose something\r
         # It means it touches no border as it was not found in the file\r
-        if src == -1:\r
-            root_folder = mstr_datafolder + "textures/"\r
-            for s in mstr_ortho_layers:\r
-                if s[0] == self._tag and s[1] == self._value:\r
-                    fld_main = len(s)-2\r
-                    fld_sub  = len(s)-1\r
-                    root_folder = root_folder + s[fld_main] + "/" + s[fld_sub]\r
-            \r
-            brd = glob.glob(root_folder + "/brd/b*.png")\r
-            src = randrange(1, len(brd)+1)\r
+        if len(src) == 0:\r
+            while len(src) < 6:\r
+                pick = randrange(1, 16)\r
+                if pick not in src: src.append(pick)\r
 \r
         return src\r
 \r
 \r
+    # Find layer contrast to apply, if any\r
+    def findLayerContrast(self):\r
+\r
+        contrast = 0\r
+\r
+        # The already existing source data\r
+        srcfile = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(self._lat_number) + "_" + str(\r
+            self._lng_number)\r
+\r
+        # Let's open the file and find our entry\r
+        with open(srcfile) as file:\r
+            for line in file:\r
+                linedata = line.split(" ")\r
+                if linedata[0] == self._tag and linedata[1] == self._value:\r
+                    src = linedata[2].split(",")\r
+                    contrast = src[4]\r
+\r
+        return contrast\r
+\r
+\r
+    # Generates some random tree.\r
+    # We will now move away from using pre-made trees...\r
+    # they didn't look so great\r
+    def generate_tree(self):\r
+        sx = randrange(18, 31)\r
+        sy = randrange(18, 31)\r
+\r
+        treepoly = Image.new("RGBA", (sx, sy))\r
+        draw = ImageDraw.Draw(treepoly)\r
+\r
+        draw.ellipse((4, 4, sx - 4, sy - 4), fill="black")\r
+\r
+        tree = Image.new("RGBA", (sx, sy))\r
+        treepx = tree.load()\r
+        maskpx = treepoly.load()\r
+\r
+        # How many tree points do we want?\r
+        treepts = 75\r
+        # How many of those have been drawn?\r
+        ptsdrawn = 0\r
+\r
+        bc = [\r
+            (36, 50, 52),\r
+            (30, 41, 39),\r
+            (32, 45, 37),\r
+            (32, 39, 49),\r
+            (33, 34, 40),\r
+            (44, 50, 53),\r
+            (40, 46, 48),\r
+            (14, 31, 38),\r
+            (17, 41, 33),\r
+            (39, 56, 35),\r
+            (51, 51, 42),\r
+            (12, 27, 31),\r
+            (45, 59, 48),\r
+            (37, 54, 29),\r
+            (59, 50, 34),\r
+            (59, 59, 35),\r
+            (59, 51, 35),\r
+            (70, 72, 45),\r
+            (48, 59, 44),\r
+            (29, 47, 23),\r
+            (47, 61, 43),\r
+            (29, 68, 15),\r
+            (53, 77, 63),\r
+            (20, 68, 40)\r
+        ]\r
+\r
+        bcp = randrange(0, len(bc))\r
+\r
+        treedraw = ImageDraw.Draw(tree)\r
+        while ptsdrawn < treepts + 1:\r
+            rx = randrange(0, sx)\r
+            ry = randrange(0, sy)\r
+            mp = maskpx[rx, ry]\r
+            if mp[3] > 0:\r
+                d = randrange(0, 51)\r
+                r = bc[bcp][0]\r
+                g = bc[bcp][1] + d\r
+                b = bc[bcp][2] + (d // 2)\r
+                a = randrange(170, 256)\r
+                c = (r, g, b, a)\r
+                ex = randrange(2, 5)\r
+                ey = randrange(2, 5)\r
+                treedraw.ellipse((rx - (ex // 2), ry - (ey // 2), rx + (ey // 2), ry + (ey // 2)), fill=c)\r
+                ptsdrawn = ptsdrawn + 1\r
+\r
+        for y in range(0, tree.height):\r
+            for x in range(0, tree.width):\r
+                tp = treepx[x, y]\r
+                diff = randrange(0, 31)\r
+                nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])\r
+                treepx[x, y] = nc\r
+\r
+        tree = tree.filter(ImageFilter.GaussianBlur(radius=0.5))\r
+\r
+        for y in range(0, tree.height):\r
+            for x in range(0, tree.width):\r
+                tp = treepx[x, y]\r
+                diff = randrange(0, 51)\r
+                nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])\r
+                treepx[x, y] = nc\r
+\r
+        return tree\r
+\r
 \r
     # This generates the layer from the defined mask\r
     def genlayer(self, mask, xml):\r
@@ -163,12 +268,6 @@ class mstr_layergen:
         # If we find an airport, make a note ...\r
         if icao != None:\r
             if len(icao) >= 1 and self._is_completion == False:\r
-                #for i in icao:\r
-                    # ... but only, if this airport is not already noted\r
-                    #iccheck = self._tiledb.perform_query("SELECT * FROM airports WHERE icao='" + i +"';")\r
-                    #if len(iccheck) == 0:\r
-                        #self._tiledb.insert_icao(i, self._lat_number, self._lng_number, self._latitude, self._longitude)\r
-                    #    mstr_msg("layergen", "Airport/s noted in data file")\r
                 rw_surface = xml.find_runway_surface()\r
 \r
         # The image for the layer itself\r
@@ -179,7 +278,7 @@ class mstr_layergen:
         # We need to differentiate that.\r
 \r
         if (self._isline == False and self._tag != "building") or (self._is_completion == True):\r
-            # Determine where we get the our source material from\r
+            # Determine where we get the source material from\r
             root_folder = mstr_datafolder + "textures/"\r
             for s in mstr_ortho_layers:\r
                 if s[0] == self._tag and s[1] == self._value:\r
@@ -189,14 +288,33 @@ class mstr_layergen:
 \r
             # Determine which sources to use.\r
             src = self.findLayerSource()\r
-            \r
-            ptc = glob.glob(root_folder + "/ptc/b" + str(src) + "_p*.png")\r
-            \r
-            # Load in the sources to work with\r
-            brd_src = Image.open(root_folder + "/brd/b" + str(src) + ".png")\r
+\r
+            # Patch and border sources. There can only be one for each.\r
+            brd_src = None\r
             ptc_src = []\r
-            for p in ptc:\r
-                ptc_src.append(Image.open(p))\r
+            \r
+            # Find out if the generated image already exists.\r
+            # If not, both border and patch need to be generated first.\r
+            gensrc_ptc = mstr_datafolder + "_cache/_pool/ptc_" + self._tag + "_" + self._value + "_"\r
+            for s in range(len(src)):\r
+                gensrc_ptc = gensrc_ptc + str(src[s])\r
+                if s < len(src) - 1:\r
+                    gensrc_ptc = gensrc_ptc + "_"\r
+            gensrc_ptc = gensrc_ptc + ".png"\r
+\r
+            # Find this layer's predetermined contrast\r
+            lyr_contrast = self.findLayerContrast()\r
+\r
+            # Should this not exist yet, we need to create it\r
+            #if os.path.isfile(gensrc_ptc) == False:\r
+            rg = mstr_resourcegen(self._tag, self._value, src)\r
+            rg.setLayerContrast(int(lyr_contrast))\r
+            lyr_res = rg.gensource()\r
+\r
+            # Open the images\r
+            ptc_src.append(lyr_res[0]) # Used to be an array, so let's keep it\r
+            brd_src = lyr_res[1]\r
+\r
             mstr_msg("layergen", "Layer sources selected")\r
             \r
             # Generate an edge mask from the original\r
@@ -260,83 +378,53 @@ class mstr_layergen:
             layer.alpha_composite( brd_src )\r
 \r
             # Here we need to do some magic to make some features look more natural\r
-            if (self._tag == "landuse" and self._value == "meadow") or (self._tag == "natural" and self._value == "grassland") or (self._tag == "natural" and self._value == "heath") or (self._tag == "landuse" and self._value == "cemetery") or (self._tag == "landuse" and self._value == "residential"):\r
-                if self._is_completion == False:\r
-                    amt = randrange(2, 9)\r
-                    for i in range(1, amt+1):\r
-                        ptc = randrange(1, 14)\r
-                        img = Image.open(mstr_datafolder + "textures/tile/completion/p" + str(ptc)+".png")\r
-                        img = img.rotate(randrange(0, 360), expand=True)\r
-                        a = img.getchannel("A")\r
-                        bbox = a.getbbox()\r
-                        img = img.crop(bbox)\r
-                        lx = randrange( self._imgsize - img.width ) \r
-                        ly = randrange( self._imgsize - img.height )\r
-                        layer.alpha_composite( img, (lx, ly) )\r
-                if self._is_completion == True:\r
-                    mp = mask.load()\r
-                    edn = self.xplane_latlng_folder(self.find_earthnavdata_number())\r
-                    idx = 0\r
-                    for r in mstr_completion_colors:\r
-                        if r[0] == edn:\r
-                            break\r
-                        else:\r
-                            idx = idx+1\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            if mp[x,y][3] > 0:\r
-                                # Pick a color\r
-                                a = mp[x,y]\r
-                                cidx = randrange(len(mstr_completion_colors[idx][1]))\r
-                                clr = mstr_completion_colors[idx][1][cidx]\r
-                                layer_pix[x,y] = (clr[0], clr[1], clr[2], a[3])\r
-                    amt = randrange(1,51)\r
-                    for i in range(1, amt+1):\r
-                        ptc = randrange(1, 14)\r
-                        img = Image.open(mstr_datafolder + "textures/tile/completion/p" + str(ptc)+".png")\r
-                        img = img.rotate(randrange(0, 360), expand=True)\r
-                        a = img.getchannel("A")\r
-                        bbox = a.getbbox()\r
-                        img = img.crop(bbox)\r
-                        imgp = img.load()\r
-                        for y in range(img.height):\r
-                            for x in range(img.width):\r
-                                c = imgp[x,y]\r
-                                nc = (c[0], c[1], c[2], int(imgp[x,y][3]*0.4))\r
-                                imgp[x,y] = nc\r
-                        lx = randrange( self._imgsize - img.width ) \r
-                        ly = randrange( self._imgsize - img.height )\r
-                        layer.alpha_composite( img, (lx, ly))\r
-                    layer = layer.filter(ImageFilter.GaussianBlur(radius=1))\r
-                    \r
-\r
-            # Add trees only in some features\r
-            if (self._tag == "landuse" and self._value == "cemetery") or (self._tag == "landuse" and self._value == "residential") or (self._tag == "leisure" and self._value == "park"):\r
-                trees = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                amt = 3500\r
-                for i in range(1, amt+1):\r
-                    p = randrange(1, 16)\r
-                    tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")\r
-                    lx = randrange( self._imgsize - tree.width ) \r
-                    ly = randrange( self._imgsize - tree.height )\r
-                    trees.alpha_composite(tree, (lx, ly))\r
-                    \r
-                tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                tree_pix = trees.load()\r
-                shadow_pix = tree_shadow.load()\r
-                for y in range(self._imgsize):\r
-                    for x in range(self._imgsize):\r
-                        tp = tree_pix[x,y]\r
-                        if tp[3] > 0:\r
-                            rndshd = randrange(5, 210)\r
-                            sc = (0,0,0,rndshd)\r
-                            if x+8 < self._imgsize and y+5 < self._imgsize:\r
-                                shadow_pix[x+8,y+5] = sc\r
-                tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))\r
-                tree_shadow.alpha_composite(trees)\r
-                layer.alpha_composite(tree_shadow)\r
-\r
-            mstr_msg("layergen", "Layer image completed")\r
+            if (self._tag == "landuse" and self._value == "meadow") or (\r
+                    self._tag == "natural" and self._value == "grassland") or (\r
+                    self._tag == "natural" and self._value == "heath") or (\r
+                    self._tag == "landuse" and self._value == "cemetery") or (\r
+                    self._tag == "landuse" and self._value == "residential"):\r
+                amt = randrange(2, 9)\r
+                masks = glob.glob(mstr_datafolder + "textures/tile/completion/*.png")\r
+                for i in range(1, amt + 1):\r
+                    pick = randrange(0, len(masks))\r
+                    patchmask = Image.open(masks[pick])\r
+                    patchpix = patchmask.load()\r
+                    # Pick from possible tags and values for the patches\r
+                    patchtags = [\r
+                        ["landuse", "meadow"],\r
+                        ["landuse", "grass"],\r
+                        ["natural", "heath"],\r
+                        ["natural", "scrub"]\r
+                    ]\r
+\r
+                    numbers = list(range(1, 16))\r
+                    src = random.sample(numbers, 5)\r
+\r
+                    patchpick = randrange(0, len(patchtags))\r
+                    ctr = randrange(1, 4)\r
+                    rg = mstr_resourcegen(patchtags[patchpick][0], patchtags[patchpick][1], src)\r
+                    rg.setLayerContrast(ctr)\r
+                    ptch = rg.gensource()\r
+\r
+                    rg_img = ptch[0]\r
+                    rg_pix = rg_img.load()\r
+\r
+                    # The patch to be used in the layer\r
+                    layerpatch = Image.new("RGBA", (patchmask.width, patchmask.height))\r
+                    lp_pix = layerpatch.load()\r
+                    for y in range(0, patchmask.height):\r
+                        for x in range(0, patchmask.width):\r
+                            ptc_msk = patchpix[x,y]\r
+                            if ptc_msk[3] > 0:\r
+                                oc = rg_pix[x,y]\r
+                                nc = ( oc[0], oc[1], oc[2], ptc_msk[3] )\r
+                                lp_pix[x,y] = nc\r
+\r
+                    layerpatch = layerpatch.rotate(randrange(0, 360), expand=True)\r
+\r
+                    lx = randrange(self._imgsize - layerpatch.width)\r
+                    ly = randrange(self._imgsize - layerpatch.height)\r
+                    layer.alpha_composite(layerpatch, (lx, ly))\r
 \r
 \r
             # And now for the Big Mac.\r
@@ -352,74 +440,24 @@ class mstr_layergen:
                         a=mask_pix[x,y]\r
                         layer_comp_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])\r
 \r
-            # For some things, we will need to add a border and then add this to the layer.\r
-            layer_border = None\r
-            if self._tag == "landuse":\r
-                if self._value == "forest" or self._value == "farmland":\r
-                    osm_edge = osm_edge.filter(ImageFilter.ModeFilter(size=15))\r
-                    osm_edge = osm_edge.filter(ImageFilter.BoxBlur(radius=2))\r
-                    layer_border = self.genborder(osm_edge, "landuse", "meadow")\r
-                    layer_comp.alpha_composite(layer_border)\r
-\r
-\r
-            # Here we want to make sure that the generated image fits well with others, so\r
-            # let's do that.\r
-            mstr_msg("layergen", "Generating adjacent fades")\r
-            adjfade = self.generate_adjacent_fades(mask)\r
-\r
-            layer_comp.alpha_composite(adjfade)\r
-            mstr_msg("layergen", "Adjacent fading completed")\r
-\r
 \r
             # Add a white-ish border around pitches\r
             if self._tag == "leisure" and self._value == "pitch":\r
-                epx = osm_edge.load()\r
-                for y in range(self._imgsize):\r
-                    for x in range(self._imgsize):\r
-                        ep = epx[x,y]\r
-                        if ep[3] > 0:\r
-                            d = randrange(10,101)\r
-                            nw = (200-d,200-d,200-d,255)\r
-                            layer_comp_pix[x,y] = nw\r
-\r
-            # I need to put this special sub-call here to solve an otherwise unsolvable\r
-            # conflict with layer order\r
-            if self._tag == "landuse" and self._value == "forest":\r
-                # The residential layer MUST exist before we reach the forest part.\r
-                fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_landuse-residential_layer.png"\r
-                if os.path.isfile(fn):\r
-                    rsd = Image.open(fn)\r
-                    rsd_pix = rsd.load()\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            rpix = rsd_pix[x,y]\r
-                            lpix = layer_comp_pix[x,y]\r
-                            if rpix[3] > 0 and lpix[3] > 0:\r
-                                layer_comp_pix[x,y] = (lpix[0], lpix[1], lpix[2], 255-rpix[3])\r
+                pitch_edge = osm_edge\r
+                pitch_edge = pitch_edge.filter(ImageFilter.GaussianBlur(radius=0.5))\r
+                pitch_mask = pitch_edge.load()\r
 \r
-            # Store layer\r
-            #if self._is_completion == False:\r
-            #    layer_comp.save( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )\r
-            #if self._is_completion == True:\r
-            #   layer_comp.save( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_tile-completion_layer.png" )\r
-            #layer_final.save( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )\r
-            mstr_msg("layergen", "Layer image finalized and saved.")\r
+                # ImageOps.invert does not like RGBA images for inversion. So I need to do it.\r
+                for y in range(0, self._imgsize):\r
+                    for x in range(0, self._imgsize):\r
+                        pm = pitch_mask[x,y]\r
+                        if pm[3] > 0:\r
+                            d = randrange(0, 21)\r
+                            layer_comp_pix[x,y] = ( 110-pm[0]-d, 110-pm[1]-d, 110-pm[2]-d, pm[3]-(d*2) )\r
 \r
 \r
-            # Depending on if scenery for XP should be made, AND if normal maps should be made, we would\r
-            # need to make them at this exact point\r
-            """\r
-            if mstr_xp_genscenery == True:\r
-                if mstr_xp_scn_normalmaps == True and self._is_completion == False:\r
-                    nm = False\r
-                    for n in mstr_xp_normal_maps:\r
-                        if n[0] == self._tag and (n[1] == self._value or n[1] == "*"):\r
-                            nm = True\r
-                            break\r
-                    if nm == True:\r
-                        nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)\r
-                        nrm.build_normalmap(layer_comp)\r
-            """\r
+            # Layer complete\r
+            mstr_msg("layergen", "Layer image completed.")\r
 \r
 \r
             # Let's try our hand at pseudo shadows\r
@@ -456,35 +494,6 @@ class mstr_layergen:
                             layer_comp = shadow\r
                             mstr_msg("layergen", "Shadow layer completed")\r
 \r
-\r
-            # Create a water mask we need to remove from the DDS later\r
-            """\r
-            if (self._tag == "natural" and self._value == "water") or (self._tag == "water" and self._value == "lake") or (self._tag == "water" and self._value == "pond") or (self._tag == "water" and self._value == "river") or (self._tag == "leisure" and self._value == "swimming_pool"):\r
-                mstr_msg("layergen", "Generating inland water mask")\r
-                water_file = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._lat_number) + "_" + str(self._lng_number) + "_water.png"\r
-                inl_mask = None\r
-                if os.path.isfile(water_file):\r
-                    inl_mask = Image.open(water_file)\r
-                else:\r
-                    inl_mask = Image.new("L", (self._imgsize, self._imgsize), (255))\r
-                lyr_pix = layer_comp.load()\r
-                inl_pix = inl_mask.load()\r
-                for y in range(self._imgsize):\r
-                    for x in range(self._imgsize):\r
-                        l = lyr_pix[x,y]\r
-                        if l[3] > 50:\r
-                            clr = 255-l[3]\r
-                            c = (clr)\r
-                            inl_pix[x,y] = c\r
-                inl_mask.save(water_file)\r
-                        #if l[3] > 65:\r
-                        #    b = 255 - l[3]\r
-                        #    inl_pix[x,y] = (255,0,255,255)\r
-                #inl_mask.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_mask.png")\r
-                #layer_comp = inl_mask\r
-                mstr_msg("layergen", "Inland water mask generated and saved")\r
-            """\r
-\r
             # Return the completed image\r
             return layer_comp\r
         \r
@@ -495,7 +504,7 @@ class mstr_layergen:
 \r
         # If we encounter one of these road-specific tags, we need to proceed differently.\r
 \r
-        if self._isline == True or self._tag == "building":\r
+        if self._isline == True or self._tag != "building":\r
 \r
             # We will need the mask in question\r
             #mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )\r
@@ -546,15 +555,24 @@ class mstr_layergen:
                             d = randrange(41, 61)\r
                             layer_comp_pix[x, y] = ( d,d,d,a[3] )\r
                         if self._tag == "highway" and self._value != "motorway":\r
-                            dr = randrange(110,121)\r
-                            dg = randrange(110,121)\r
-                            db = randrange(115,130)\r
-                            layer_comp_pix[x, y] = ( dr,dg,db,a[3] )\r
+                            d = randrange(0, 36)\r
+                            dr = 90+d\r
+                            dg = 90+d\r
+                            db = 95+d\r
+                            da = a[3]\r
+                            layer_comp_pix[x, y] = ( dr,dg,db,da )\r
                         if self._tag == "highway" and self._value == "motorway":\r
-                            dr = randrange(77,89)\r
-                            dg = randrange(88,96)\r
-                            db = randrange(90,101)\r
+                            d = randrange(0, 36)\r
+                            dr = 57+d\r
+                            dg = 68+d\r
+                            db = 70+d\r
                             layer_comp_pix[x, y] = ( dr,dg,db,a[3] )\r
+                        if self._tag == "highway" and (self._value == "footway" or self._value == "track" or self._value == "path"):\r
+                            dr = randrange(158, 183)\r
+                            dg = randrange(143, 178)\r
+                            db = randrange(90, 161)\r
+                            da = a[3]-20\r
+                            layer_comp_pix[x, y] = (dr, dg, db, da)\r
                         if self._tag == "waterway" and (self._value == "stream" or self._value == "river"):\r
                             d = randrange(1, 15)\r
                             # Rock, grass, water\r
@@ -566,29 +584,6 @@ class mstr_layergen:
                             if t < 0: t = 0\r
                             if e[3] > 0:\r
                                 layer_comp_pix[x, y] = ( mats[pick-1][0], mats[pick-1][1], mats[pick-1][2], 35 )\r
-                        \r
-                        # A bit special here\r
-                        if self._tag == "building":\r
-                            # Find a color range for the pixel\r
-                            d = randrange(1,21)\r
-                            nr = a[0]+40 - d\r
-                            ng = a[1]+40 - d\r
-                            nb = a[2]+40 - d\r
-                            if nr < 0: nr = 0\r
-                            if ng < 0: ng = 0\r
-                            if nb < 0: nb = 0\r
-                            if nr > 255: nr = 255\r
-                            if ng > 255: ng = 255\r
-                            if nb > 255: nb = 255\r
-                            nc = (nr, ng, nb, 255)\r
-                            layer_comp_pix[x,y] = (nr,ng,nb,255)\r
-                            \r
-                        if self._value == "track" or self._value == "path":\r
-                            d = randrange(1,20)\r
-                            r = 164 - d\r
-                            g = 159 - d\r
-                            b = 138  - d\r
-                            layer_comp_pix[x, y] = ( r,g,b,a[3] )\r
 \r
             # A bit different for tree rows\r
             if self._tag == "natural" and self._value == "tree_row":\r
@@ -599,8 +594,7 @@ class mstr_layergen:
                     a = mask_pix[lx,ly]\r
                     if a[3] > 0:\r
                         if lx < self._imgsize and ly < self._imgsize:\r
-                            p = randrange(1,16)\r
-                            tree = Image.open(mstr_datafolder + "textures/building/area/p" + str(p) + ".png")\r
+                            tree = self.generate_tree()\r
                             trees.alpha_composite(tree, (lx, ly))\r
                 if mstr_shadow_enabled == True:\r
                     tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
@@ -618,221 +612,8 @@ class mstr_layergen:
                     tree_shadow.alpha_composite(trees)\r
                     layer_comp.alpha_composite(tree_shadow)\r
 \r
-            # We will do some super magic here to let houses look more realistic\r
-            if self._tag == "building":\r
-                \r
-                details = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                trees = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                roof_details = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-\r
-                if mstr_shadow_enabled == True:\r
-                    fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_building-" + self._value + "_layer_shadow.png"\r
-                    if os.path.isfile(fn):\r
-                        shadow = Image.open(fn)\r
-\r
-                vls = [ "detached", "hotel", "farm", "semidetached_house", "apartments", "civic", "house", "school", "kindergarten", "yes" ]\r
-                if self._value in vls:\r
-                    # Generate a new image\r
-                    details_pix = details.load()\r
-                    layer_pix = layer_comp.load()\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            p = layer_pix[x,y]\r
-                            if p[3] > 0:\r
-                                shf_x = x+randrange(1, 16)\r
-                                shf_y = y+randrange(1, 16)\r
-                                shf_x2 = x-randrange(1, 16)\r
-                                shf_y2 = y-randrange(1, 16)\r
-                                if shf_x < self._imgsize and shf_y < self._imgsize and shf_x2 < self._imgsize and shf_y2 < self._imgsize:\r
-                                    st = random.uniform(0.65, 0.85)\r
-                                    ca = 255 * st\r
-                                    aa = int(ca)\r
-                                    d = randrange(1,26)\r
-                                    d2 = randrange(1,26)\r
-                                    details_pix[shf_x, shf_y] = (187-d, 179-d, 176-d, aa)\r
-                                    details_pix[shf_x2, shf_y2] = (187-d2, 179-d2, 176-d2, aa)\r
-\r
-                    # Image for roof details\r
-                    roof_det_pix = roof_details.load()\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            mp = mask_pix[x,y]\r
-                            if mp[3] == 255:\r
-                                # Determine if we render some pixel\r
-                                rnd = randrange(1, 3)\r
-                                if rnd == 2:\r
-                                    # Find a range for the base color of the pixel\r
-                                    d = randrange(21)\r
-                                    # Find a random alpha value\r
-                                    a = randrange(1, 151)\r
-                                    nc = (mstr_building_detail_colors[0][0]-d, mstr_building_detail_colors[0][1]-d, mstr_building_detail_colors[0][2]-d, a)\r
-                                    roof_det_pix[x,y] = nc\r
-\r
-\r
-                    # Let's see how it works with this method\r
-                    #details.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer_details.png")\r
-                    #layer_comp.alpha_composite(details)\r
-\r
-                    # Add some random trees\r
-                    div = int(self._imgsize/200)\r
-                    for y in range(0, self._imgsize, div):\r
-                        for x in range(0, self._imgsize, div):\r
-                            if x > 0 and x < self._imgsize and y > 0 and y < self._imgsize:\r
-                                p = mask_pix[x, y]\r
-                                if p[3] != 0:\r
-                                    # We found something...\r
-                                    # Determine if we put something somewhere\r
-                                    placement = randrange(0, 5)\r
-                                    if placement == 1:\r
-                                        # Do some random shift away from this location\r
-                                        shf_x = randrange(x-11, x+11)\r
-                                        shf_y = randrange(y-11, y+11)\r
-                                        if shf_x < self._imgsize and shf_y < self._imgsize:\r
-                                            # Pick a number of trees to place\r
-                                            numtrees = randrange(1, 16)\r
-                                            for i in range(1, numtrees+1):\r
-                                                # Pick some file\r
-                                                pick = str(randrange(1, 16))\r
-                                                tree = Image.open(mstr_datafolder + "textures/building/area/p" + pick + ".png")\r
-                                                # Do a correction for the location if needed\r
-                                                if shf_x < 1: shf_x = 1\r
-                                                if shf_y < 1: shf_y = 1\r
-                                                if shf_x > self._imgsize - tree.width: shf_x = self._imgsize - tree.width - 1\r
-                                                if shf_y > self._imgsize - tree.height: shf_y = self._imgsize - tree.height - 1\r
-                                                trees.alpha_composite(tree, (shf_x, shf_y))\r
-                    \r
-                    \r
-                    if mstr_shadow_enabled == True:\r
-                        tree_pix = trees.load()\r
-                        shadow_pix = tree_shadow.load()\r
-                        for y in range(self._imgsize):\r
-                            for x in range(self._imgsize):\r
-                                tp = tree_pix[x,y]\r
-                                if tp[3] > 0:\r
-                                    rndshd = randrange(5, 210)\r
-                                    sc = (0,0,0,rndshd)\r
-                                    if x+8 < self._imgsize and y+5 < self._imgsize:\r
-                                        shadow_pix[x+8,y+5] = sc\r
-                        tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))\r
-                        tree_shadow.alpha_composite(trees)\r
-\r
-                # Let's try this one on for size\r
-                bld_comp = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                details = details.filter(ImageFilter.GaussianBlur(radius=1))\r
-                bld_comp.alpha_composite(details)\r
-                bld_comp.alpha_composite(tree_shadow)\r
-                bld_comp.alpha_composite(trees)\r
-                shd_p  = shadow.load()\r
-                for y in range(self._imgsize):\r
-                    for x in range(self._imgsize):\r
-                        c = shd_p[x,y]\r
-                        if c[3] > 0:\r
-                            s = (0,0,0,120-(randrange(0,21)))\r
-                            shd_p[x,y] = s\r
-                shadow = shadow.filter(ImageFilter.GaussianBlur(radius=1))\r
-                bld_comp.alpha_composite(shadow)\r
-                layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=1.1))\r
-                bld_comp.alpha_composite(layer_comp)\r
-                layer_comp = bld_comp\r
-                layer_comp.alpha_composite(roof_details)\r
-\r
             mstr_msg("layergen", "Layer image generated")\r
 \r
-            # Building shadow\r
-            if mstr_shadow_enabled == True:\r
-                    \r
-                # Some funnies with shadows\r
-                if self._tag == "building" and (self._value == "detached" or self._value == "semidetached_house" or self._value == "apartments" or self._value == "civic" or self._value == "house" or self._value == "terrace"):\r
-                    mask_pix = mask.load()\r
-                    roofshadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                    roofpix = roofshadow.load()\r
-                    # Generate a pseudo shifted roof shadow\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            mp = mask_pix[x,y]\r
-                            if mp[3] == 255:\r
-                                nx = x+8\r
-                                ny = y+4\r
-                                if nx < self._imgsize and ny < self._imgsize:\r
-                                    roofpix[nx,ny] = (0,0,0,255)\r
-\r
-                    # Now apply the shift where necessary\r
-                    roofpix = roofshadow.load()\r
-                    mask_pix = mask.load()\r
-                    layer_comp_pix = layer_comp.load()\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            rp = roofpix[x,y]\r
-                            mp = mask_pix[x,y]\r
-                            if rp[3] == 255 and mp[3] == 255:\r
-                                c = layer_comp_pix[x,y]\r
-                                dim = randrange(30,61)\r
-                                nr = c[0] - dim\r
-                                ng = c[1] - dim\r
-                                nb = c[2] - dim\r
-                                if nr < 0: nr = 0\r
-                                if ng < 0: ng = 0\r
-                                if nb < 0: nb = 0\r
-                                layer_comp_pix[x,y] = (nr, ng, nb, c[3])\r
-                    #layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=1))\r
-\r
-\r
-            # Let's add some details to the roofs\r
-            if self._tag == "building":\r
-                vls = [ "detached", "hotel", "farm", "semidetached_house", "apartments", "civic", "house", "school", "kindergarten", "yes" ]\r
-                if self._value in vls:\r
-                    roof_additional_detail = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-                    rad_pix = roof_additional_detail.load()\r
-                    for r in range(30001):\r
-                        lx = randrange(self._imgsize)\r
-                        ly = randrange(self._imgsize)\r
-                        mp = mask_pix[lx,ly]\r
-                        if mp[3] == 255:\r
-                            # Brighter or darker pixel\r
-                            bod = randrange(1,3)\r
-                            c = 0\r
-                            if bod == 2:\r
-                                c = 40\r
-                            else:\r
-                                c = 200\r
-                            dt = (c, c, c, 130)\r
-                            rad_pix[lx,ly] = dt\r
-                            if lx+1 < self._imgsize:\r
-                                rad_pix[lx+1, ly] = dt\r
-                            if lx+1 < self._imgsize and ly+1 < self._imgsize:\r
-                                rad_pix[lx+1, ly+1] = dt\r
-                            if ly+1 < self._imgsize:\r
-                                rad_pix[lx, ly+1] = dt\r
-                    layer_comp.alpha_composite(roof_additional_detail)\r
-            \r
-            # Let's put some other details on commercial buildings\r
-            if self._tag == "building":\r
-                vls = [ "office", "retail", "industrial" ]\r
-                if self._value in vls:\r
-\r
-                    # Find a suitable location to render something\r
-                    for r in range(15001):\r
-                        lx = randrange(self._imgsize)\r
-                        ly = randrange(self._imgsize)\r
-                        mp = mask_pix[lx,ly]\r
-\r
-                        # Think of some random shape\r
-                        if mp[3] == 255:\r
-                            rw = randrange(3,8)\r
-                            rh = randrange(3,8)\r
-                            sh = Image.new("RGBA", (rw, rh), (30,30,30,130))\r
-                            shp = sh.load()\r
-                            for sy in range(rh):\r
-                                for sx in range(rw):\r
-                                    if sx > 0 and sx < rw and sy > 0 and sy < rh: shp[sx, sy] = (180,180,180,160)\r
-                            rt = randrange(1, 3)\r
-                            if rt == 2:\r
-                                sh = sh.rotate(45, expand=True)\r
-\r
-                            layer_comp.alpha_composite(sh, (lx, ly))\r
-\r
             \r
             # Highways and runways of any kind get some special treatment\r
             if (self._tag == "highway" and self._value == "motorway") or (self._tag == "highway" and self._value == "primary") or (self._tag == "highway" and self._value == "secondary") or (self._tag == "highway" and self._value == "tertiary") or (self._tag == "aeroway" and self._value == "runway"):\r
@@ -889,174 +670,164 @@ class mstr_layergen:
             mstr_msg("layergen", "Layer image finalized and saved.")\r
 \r
 \r
-            # Depending on if scenery for XP should be made, AND if normal maps should be made, we would\r
-            # need to make them at this exact point\r
-            """\r
-            if mstr_xp_genscenery == True:\r
-                if mstr_xp_scn_normalmaps == True and self._is_completion == False:\r
-                    nm = False\r
-                    for n in mstr_xp_normal_maps:\r
-                        if n[0] == self._tag and (n[1] == self._value or n[1] == "*"):\r
-                            nm = True\r
-                            break\r
-                    if nm == True:\r
-                        nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld)\r
-                        nrm.build_normalmap(layer_comp)\r
-            """\r
-\r
-\r
             # Return image\r
             return layer_comp\r
 \r
+        # ------------------------------------------------------------------------------------------\r
+        # ------------------------------------------------------------------------------------------\r
+        # ------------------------------------------------------------------------------------------\r
 \r
-    # Should we find more than one source, the first one found will take precedence.\r
-    # For the others, we will need to generate fading images, so that the final layer \r
-    # image works with other tiles\r
-    def generate_adjacent_fades(self, mask):\r
-        adj_sources = self.find_all_adjacent_sources()\r
-        precedence = -1\r
+        # As we now have a specific pool for buildings, we will need to enter a third branch\r
+        # to handle all kinds of buildings in the orthos.\r
+        if self._tag == "building":\r
+            # Access to pixels from OSM mask\r
+            mask_pix = mask.load()\r
 \r
-        # Be prepared for every border\r
-        brd_t = Image.open(mstr_datafolder + "textures/multi_source/brd_t.png")\r
-        brd_r = Image.open(mstr_datafolder + "textures/multi_source/brd_r.png")\r
-        brd_b = Image.open(mstr_datafolder + "textures/multi_source/brd_b.png")\r
-        brd_l = Image.open(mstr_datafolder + "textures/multi_source/brd_l.png")\r
+            # Separate images for additional details\r
+            tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            trees = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            bld_src = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            bld_main = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            osm_edge = mask.filter(ImageFilter.FIND_EDGES)\r
 \r
-        brd_t_pix = brd_t.load()\r
-        brd_r_pix = brd_r.load()\r
-        brd_b_pix = brd_b.load()\r
-        brd_l_pix = brd_l.load()\r
+            # Determine which sources to use.\r
+            src = self.findLayerSource()\r
 \r
-        for s in range(0, 4):\r
-            if adj_sources[s] != -1:\r
-                precedence = adj_sources[s]\r
-                break\r
+            # Patch and border sources. There can only be one for each.\r
+            brd_src = None\r
+            ptc_src = []\r
 \r
-        # Generate required images\r
-        # Basically a shortened version of the main layergen call\r
-        adj_image = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-        for s in range(0, 4):\r
-            if adj_sources[s] != precedence and adj_sources[s] != -1:\r
-                src = adj_sources[s]\r
+            # Find this layer's predetermined contrast\r
+            lyr_contrast = self.findLayerContrast()\r
 \r
-                adj_pix = adj_image.load()\r
+            rg = mstr_resourcegen(self._tag, self._value, src)\r
+            rg.setLayerContrast(int(lyr_contrast))\r
+            bldg_src = rg.gensource()\r
 \r
-                # Root folder\r
-                root_folder = mstr_datafolder + "textures/" + self._tag + "/" + self._value\r
+            # Open the images\r
+            ptc_src.append(bldg_src[0])  # Used to be an array, so let's keep it\r
+            brd_src = bldg_src[1]\r
 \r
-                # Load in the sources to work with\r
-                ptc = glob.glob(root_folder + "/ptc/b" + str(src) + "_p*.png")\r
-                brd_src = Image.open(root_folder + "/brd/b" + str(src) + ".png")\r
-                ptc_src = []\r
-                for p in ptc:\r
-                    ptc_src.append(Image.open(p))\r
+            # Begin producing a largely random image\r
+            samples = 250  # <- We need this in a moment\r
+            for i in range(samples):\r
+                imgid = 0\r
+                if len(ptc_src) == 1: imgid = 0\r
+                if len(ptc_src) >= 2:\r
+                    imgid = randrange(1, len(ptc_src) + 1) - 1\r
+                l = 0 - int(ptc_src[imgid].width / 2)\r
+                r = layer.width - int(ptc_src[imgid].width / 2)\r
+                t = 0 - int(ptc_src[imgid].height / 2)\r
+                b = layer.height - int(ptc_src[imgid].height / 2)\r
+                bld_src.alpha_composite(ptc_src[imgid], (randrange(l, r), randrange(t, b)))\r
+            mstr_msg("layergen", "Layer image generated")\r
 \r
-                #mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + ".png" )\r
-                #lyr_mask = Image.open( mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_layer.png" )\r
+            bld_src_pix = bld_src.load()\r
+            bld_main_pix = bld_main.load()\r
+            for y in range(0, self._imgsize):\r
+                for x in range(0, self._imgsize):\r
+                    mp = mask_pix[x,y]\r
+                    bp = bld_src_pix[x,y]\r
+                    if mp[3] > 0:\r
+                        nc = ( bp[0], bp[1], bp[2], mp[3] )\r
+                        bld_main_pix[x,y] = nc\r
+\r
+            bld_main = bld_main.filter(ImageFilter.GaussianBlur(radius=0.5))\r
+            osm_edge = osm_edge.filter(ImageFilter.GaussianBlur(radius=1.5))\r
+            bld_edge = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            bld_edge_pix = bld_edge.load()\r
+            edge_pix = osm_edge.load()\r
+            for y in range(osm_edge.height):\r
+                for x in range(osm_edge.width):\r
+                    ep = edge_pix[x,y]\r
+                    bp = bld_src_pix[x,y]\r
+                    if ep[3] == 255 and bp[3] == 255:\r
+                        nc = (0,0,0,60)\r
+                        bld_edge_pix[x,y] = nc\r
+            bld_main.alpha_composite(bld_edge)\r
 \r
-                for i in mstr_mask_blur:\r
-                    if i[0] == self._tag and i[1] == self._value:\r
-                        if self._tag != "place" and (self._value != "sea" or self._value != "ocean"): \r
-                            mask = mask.filter(ImageFilter.BoxBlur(radius=i[2]))\r
-                            break\r
-                mask_pix = mask.load()\r
-            \r
-                # Begin producing a largely random image\r
-                samples = 250   # <- We need this in a moment\r
-                for i in range(samples):\r
-                    imgid = 0\r
-                    if len(ptc_src) == 1: imgid = 0\r
-                    if len(ptc_src) >= 2:\r
-                        imgid = randrange(1, len(ptc_src)+1) - 1\r
-                    l = 0 - int(ptc_src[imgid].width / 2)\r
-                    r = adj_image.width - int(ptc_src[imgid].width / 2)\r
-                    t = 0 - int(ptc_src[imgid].height / 2)\r
-                    b = adj_image.height - int(ptc_src[imgid].height / 2)\r
-                    adj_image.alpha_composite( ptc_src[imgid], ( randrange(l, r), randrange(t, b) ) )\r
-\r
-                adj_image.alpha_composite( brd_src )\r
-\r
-                #lyr_pix = lyr_mask.load()\r
-                for y in range(self._imgsize):\r
-                    for x in range(self._imgsize):\r
-                        if mask_pix[x, y][3] > 0:\r
-                            rgb=adj_pix[x,y]\r
-                            a=mask_pix[x,y]\r
-                            adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3])\r
 \r
-                # Up until here we mimiced the exact same behavior as layergen. However, now\r
-                # we need to adjust the alpha to make this layer fade.\r
-                # Then, we save the image\r
-                if s == 0:\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            fade_a = brd_t_pix[0, y]\r
-                            if mask_pix[x, y][3] > 0:\r
-                                c = adj_pix[x,y]\r
-                                adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3])\r
-                            else:\r
-                                adj_pix[x,y] = (0,0,0,0)\r
-                    #adj_image.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_fade_top.png")\r
-                \r
-                if s == 1:\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            fade_a = brd_r_pix[x, 0]\r
-                            if mask_pix[x, y][3] > 0:\r
-                                c = adj_pix[x,y]\r
-                                adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3])\r
-                            else:\r
-                                adj_pix[x,y] = (0,0,0,0)\r
-                    #adj_image.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_fade_right.png")\r
-                \r
-                if s == 2:\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            fade_a = brd_b_pix[0, y]\r
-                            if mask_pix[x, y][3] > 0:\r
-                                c = adj_pix[x,y]\r
-                                adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3])\r
+            if mstr_shadow_enabled == True:\r
+                fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(\r
+                    self._longitude) + "-" + str(self._lng_number) + "_building-" + self._value + "_layer_shadow.png"\r
+                if os.path.isfile(fn):\r
+                    shadow = Image.open(fn)\r
+\r
+            # Add some random trees\r
+            for t in range(0, 5000):\r
+                loc_x = randrange(0, self._imgsize)\r
+                loc_y = randrange(0, self._imgsize)\r
+                shf_val = 21\r
+                shf_x = randrange(loc_x - shf_val, loc_x + shf_val)\r
+                shf_y = randrange(loc_y - shf_val, loc_y + shf_val)\r
+                mp = mask_pix[loc_x, loc_y]\r
+                if mp[3] == 255:\r
+                    shf_att = 0\r
+                    shf_ok = False\r
+                    shf_x = randrange(loc_x - shf_val, loc_x + shf_val)\r
+                    shf_y = randrange(loc_y - shf_val, loc_y + shf_val)\r
+                    while shf_att < 51:\r
+                        if shf_x > 0 and shf_x < self._imgsize and shf_y > 0 and shf_y < self._imgsize:\r
+                            sp = mask_pix[shf_x, shf_y]\r
+                            if sp[3] == 0:\r
+                                shf_ok = True\r
+                                break\r
                             else:\r
-                                adj_pix[x,y] = (0,0,0,0)\r
-                    #adj_image.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_fade_bottom.png")\r
+                                shf_att = shf_att + 1\r
+                        else:\r
+                            shf_val = shf_val + 10\r
 \r
-                if s == 3:\r
-                    for y in range(self._imgsize):\r
-                        for x in range(self._imgsize):\r
-                            fade_a = brd_l_pix[x, 0]\r
-                            if mask_pix[x, y][3] > 0:\r
-                                c = adj_pix[x,y]\r
-                                adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3])\r
-                            else:\r
-                                adj_pix[x,y] = (0,0,0,0)\r
-                    #adj_image.save(mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + "_fade_left.png")\r
+                        shf_att = shf_att + 1\r
+\r
+                    if shf_ok == True:\r
+                        tree = self.generate_tree()\r
+                        trees.alpha_composite(tree, (shf_x, shf_y))\r
 \r
-        # Return the image\r
-        return adj_image\r
+            # Perform correction for tree rendering\r
+            tree_pix = trees.load()\r
+            for y in range (0, self._imgsize):\r
+                for x in range(0, self._imgsize):\r
+                    mp = mask_pix[x,y]\r
+                    tp = tree_pix[x,y]\r
+                    if mp[3] == 255 and tp[3] == 255:\r
+                        tree_pix[x,y] = (0,0,0,0)\r
 \r
 \r
 \r
-    def find_all_adjacent_sources(self):\r
-        # Sources for this tag and value - top, right, bottom, left\r
-        sources = [-1,-1,-1,-1] \r
+            if mstr_shadow_enabled == True:\r
+                tree_pix = trees.load()\r
+                shadow_pix = tree_shadow.load()\r
+                for y in range(self._imgsize):\r
+                    for x in range(self._imgsize):\r
+                        tp = tree_pix[x, y]\r
+                        if tp[3] > 0:\r
+                            rndshd = randrange(5, 210)\r
+                            sc = (0, 0, 0, rndshd)\r
+                            if x + 8 < self._imgsize and y + 5 < self._imgsize:\r
+                                shadow_pix[x + 8, y + 5] = sc\r
+                tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))\r
+                tree_shadow.alpha_composite(trees)\r
+\r
+            # Let's try this one on for size\r
+            bld_comp = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+            bld_comp.alpha_composite(tree_shadow)\r
+            bld_comp.alpha_composite(trees)\r
+            shd_p = shadow.load()\r
+            for y in range(self._imgsize):\r
+                for x in range(self._imgsize):\r
+                    c = shd_p[x, y]\r
+                    if c[3] > 0:\r
+                        s = (0, 0, 0, 120 - (randrange(0, 21)))\r
+                        shd_p[x, y] = s\r
+            shadow = shadow.filter(ImageFilter.GaussianBlur(radius=1))\r
+            bld_comp.alpha_composite(shadow)\r
+            #bld_comp = bld_comp.filter(ImageFilter.GaussianBlur(radius=1.1))\r
+            bld_comp.alpha_composite(bld_main)\r
 \r
-        # Perform query for each neighboring tile\r
-        src_top = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number+1, self._lng_number, self._tag, self._value)\r
-        src_rgt = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number, self._lng_number+1, self._tag, self._value)\r
-        src_btm = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number-1, self._lng_number, self._tag, self._value)\r
-        src_lft = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number, self._lng_number-1, self._tag, self._value)\r
+            return bld_comp\r
 \r
-        if len(src_top) == 2:\r
-            if "b" in src_top[1]: sources[0] = src_top[0]\r
-        if len(src_rgt) == 2:\r
-            if "l" in src_rgt[1]: sources[1] = src_rgt[0]\r
-        if len(src_btm) == 2:\r
-            if "t" in src_btm[1]: sources[2] = src_btm[0]\r
-        if len(src_lft) == 2:\r
-            if "r" in src_lft[1]: sources[3] = src_lft[0]\r
 \r
-        # Report our findings\r
-        return sources\r
 \r
     # Find the next "by-ten" numbers for the current latitude and longitude\r
     def find_earthnavdata_number(self):\r
diff --git a/log.py b/log.py
index 2a26dd58b088a6f1e78f72be9bb49dfc4ec5de4b..34eb6d2d83420767f2038a6de4d0b1cf61f64f19 100644 (file)
--- a/log.py
+++ b/log.py
 # -------------------------------------------------------------------\r
 \r
 import datetime\r
+from colorama import init as colorama_init\r
+from colorama import Fore\r
+from colorama import Style\r
 from defines import *\r
 \r
 def mstr_msg(fnc, msg):\r
     if mstr_show_log == True:\r
+        colorama_init()\r
         now = datetime.datetime.now()\r
-        print(now.strftime(" %H:%M:%S" + " | ["+fnc+"] | " + msg))
\ No newline at end of file
+\r
+        print(f' {Fore.GREEN}'+now.strftime("%H:%M:%S")+f'{Style.RESET_ALL} | {Fore.YELLOW}[' + fnc + f']{Style.RESET_ALL} | {Fore.CYAN}'+ msg + f'{Style.RESET_ALL}')\r
+        #print(f"{Fore.GREEN}" + now.strftime(" %H:%M:%S" + " | ["+fnc+"] | " + msg))
\ No newline at end of file
index 519e8110898acf2f0c0be259b36681715a6e3345..b8080c2a04efbf040ead4b6fb433f342e1af95ee 100644 (file)
@@ -252,6 +252,14 @@ class mstr_maskgen:
                         if sp[3] != 0:\r
                             bld_shadow_pix[x,y] = (0,0,0,120)\r
 \r
+\r
+                # Mark buildings in red\r
+                for y in range(mstr_photores):\r
+                    for x in range(mstr_photores):\r
+                        mp = mask_pix[x,y]\r
+                        if mp[3] != 0:\r
+                            bld_shadow_pix[x,y] = (255,0,0,255)\r
+\r
                 # Store\r
                 if os.path.isfile(fn) == True:\r
                     lyr = Image.open(fn)\r
diff --git a/og.py b/og.py
index 8b0f4e4606af97e1a68c8186bf170e7b684ce103..9c646ff333c3c71e0113ef0dcbdcad5340f1a961 100644 (file)
--- a/og.py
+++ b/og.py
@@ -35,13 +35,9 @@ prep = False
 \r
 if len(sys.argv) == 4:\r
     cli = True\r
-    if sys.argv[3] == "true": prep = True\r
-\r
-#if len(sys.argv) == 4:\r
-#    pbf = True\r
 \r
 # Only if we find enough arguments, proceed.\r
-if cli == True:\r
+if cli:\r
     lat = int(sys.argv[1])\r
     lng = int(sys.argv[2])\r
 \r
@@ -50,28 +46,18 @@ if cli == True:
     # Create the class and init values\r
     og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd(), prep)\r
 \r
-    if prep == True:\r
+    # Prepare a tile\r
+    if sys.argv[3] == "prepare":\r
         og._prepareTile()\r
 \r
-    if prep == False:\r
-        if sys.argv[3] != "xpscenery":\r
-            og._generateOrthos_mt(int(sys.argv[3]))\r
-        \r
-        # Build the terrain mesh and assign ground textures\r
-        if sys.argv[3] == "xpscenery":\r
-            og.generate_xp_scenery()\r
-\r
+    # Generate orthos\r
+    if sys.argv[3] != "prepare" and sys.argv[3] != "xpscenery":\r
+        og._generateOrthos_mt(int(sys.argv[3]))\r
 \r
-# Only if we find enough arguments, proceed.\r
-if pbf == True:\r
-    lat = int(sys.argv[1])\r
-    lng = int(sys.argv[2])\r
-    pbf = sys.argv[3]\r
+    # Build the terrain mesh and assign ground textures\r
+    if sys.argv[3] == "xpscenery":\r
+        og.generate_xp_scenery()\r
 \r
-    if pbf == "pbf":\r
-        # Create the class and init values\r
-        og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())\r
-        og._generateData()\r
 \r
 \r
 if cli == False and pbf == False:\r
index c16e705c4f3975001e3a54efd6796dce7c287658..459bb68f53899864dcedc667147f267c49fd35cb 100644 (file)
@@ -170,9 +170,13 @@ class mstr_orthographic:
         mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))\r
         maxlatlng = [ mlat, mlng ]\r
 \r
+        # For completion layers\r
+        numbers = list(range(1, 16))\r
+        res = random.sample(numbers, 5)\r
+\r
         procs = []\r
         for p in range(1, amtsmt+1):\r
-            proc = Process(target=self._buildOrtho, args=[1, p, amtsmt])\r
+            proc = Process(target=self._buildOrtho, args=[1, p, amtsmt, res])\r
             procs.append(proc)\r
             proc.start()\r
         mstr_msg("orthographic", "Ortho threads started")\r
@@ -181,7 +185,7 @@ class mstr_orthographic:
     # Starts a threading loop to build orthos, with the defined starting point in\r
     # the lat-lng grid. You will also need to provide the horizontal stepping so\r
     # that the thread keeps running.\r
-    def _buildOrtho(self, v, h, step):\r
+    def _buildOrtho(self, v, h, step, cpl):\r
 \r
         # Starting point\r
         grid_lat = v\r
@@ -256,7 +260,6 @@ class mstr_orthographic:
                     lg = mstr_layergen(layer[0], layer[1], self._lat, grid_lat, self._long, grid_lng, layer[2])\r
                     lg.set_max_latlng_tile(maxlatlng)\r
                     lg.set_latlng_folder(self._latlngfld)\r
-                    #lg.open_db()\r
                     lg.open_tile_info()\r
                     lyr = lg.genlayer(mask, osmxml)\r
                     photolayers.append(lyr)\r
@@ -274,7 +277,8 @@ class mstr_orthographic:
                 # Snap a photo with our satellite :)\r
                 mstr_msg("orthographic", "Generating ortho photo")\r
                 pg = mstr_photogen(self._lat, self._long, grid_lat, grid_lng,  maxlatlng[0], maxlatlng[1])\r
-                pg.genphoto(photolayers, waterlayers)\r
+                pg.setLayerNames(layers)\r
+                pg.genphoto(photolayers, waterlayers, cpl)\r
                 mstr_msg("orthographic", " -- Ortho photo generated -- ")\r
                 print("")\r
                 print("")\r
@@ -375,12 +379,12 @@ class mstr_orthographic:
         bb_lat = self._lat\r
         bb_lng = self._long\r
 \r
-\r
         # We will now prepare the graphic tile generation. We do this by only generating\r
         # the masks and determine which sources to use in the actual images.\r
         # Previously, I downloaded all XML files in one go - but to ease the\r
         # stress on OSM servers and my server, we will do acquire the data\r
         # only for the current processed part of the tile.\r
+        """\r
         for lat_grid in range(1, maxlatlng[0]+1):\r
             for lng_grid in range(1, maxlatlng[1]+1):\r
                 # Adjust bounding box\r
@@ -403,7 +407,7 @@ class mstr_orthographic:
                         mask = mg._build_mask(osmxml, is_prep=True) # We need an object here\r
 \r
                         tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False)\r
-                        tp._prepareTile()\r
+                        tp._determineEdges()\r
 \r
                     curlyr = curlyr+1\r
 \r
@@ -428,6 +432,24 @@ class mstr_orthographic:
             if cur_tile_y > top_lat:\r
                 top_lat = cur_tile_y\r
 \r
+        exit(1)\r
+        """\r
+\r
+        # We now need to "raytrace" the resources for correct placement\r
+        mstr_msg("orthographic", "Performing resource plamement tracing for tile")\r
+        for lat_grid in range(1, maxlatlng[0]+1):\r
+            for lng_grid in range(1, maxlatlng[1]+1):\r
+                mstr_msg("orthographic", "Placement tracing for " + str(lat_grid) + ":" + str(lng_grid))\r
+                df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(lat_grid) + "_" + str(lng_grid)\r
+                fnlines = []\r
+                with open(df) as textfile:\r
+                    fnlines = textfile.readlines()\r
+\r
+                for l in range(0, len(fnlines)):\r
+                    lyr = fnlines[l].split(" ")\r
+                    tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, lyr[0], lyr[1], None, False)\r
+                    tp._setLatLngFold(self._latlngfld)\r
+                    tp._placeTileSources(lat_grid, lng_grid)\r
 \r
 \r
     # Generates X-Plane 11/12 scenery with\r
index 56a4fba052a3777874e1d9bce1f642ce772264e0..2a8cb5e4e9c03d97528849da1953cea8c13589f9 100644 (file)
@@ -1,12 +1,14 @@
 \r
 import os\r
-from PIL import Image, ImageFilter, ImageEnhance\r
+from PIL import Image, ImageFilter, ImageEnhance, ImageFile\r
 from defines import *\r
 from layergen import *\r
 from log import *\r
 from functions import *\r
 from xp_normalmap import *\r
 \r
+ImageFile.LOAD_TRUNCATED_IMAGES = True\r
+\r
 # -------------------------------------------------------------------\r
 # ORTHOGRAPHIC\r
 # Your personal aerial satellite. Always on. At any altitude.*\r
@@ -36,17 +38,30 @@ class mstr_photogen:
         self._latlngfld = self.latlng_folder([lat,lng])\r
         mstr_msg("photogen", "Photogen initialized")\r
 \r
+\r
+    # Defines the order of layer names that were processed\r
+    # Called by orthographic prior to starting the photo gen process\r
+    def setLayerNames(self, names):\r
+        self._lyrnames = names\r
+\r
     \r
     # This puts it all together. Bonus: AND saves it.\r
-    def genphoto(self, layers, waterlayers):\r
+    def genphoto(self, layers, waterlayers, cpl):\r
         # Template for the file name which is always the same\r
         #root_filename = mstr_datafolder + "/_cache/" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_"\r
 \r
+        # Correct layers\r
+        #mstr_msg("photogen", "Correcting layer order issues")\r
+        #layers = self.correctLayerIssues(layers)\r
+\r
         # First, we walk through all layers and blend them on top of each other, in order\r
         mstr_msg("photogen", "Merging layers")\r
 \r
+        lyr=0\r
         for l in layers:\r
-            self._tile.alpha_composite(l)\r
+            if self._lyrnames[lyr] != "building":\r
+                self._tile.alpha_composite(l)\r
+            lyr=lyr+1\r
 \r
 \r
         # When we have run through this loop, we will end up with a sandwiched\r
@@ -65,65 +80,80 @@ class mstr_photogen:
         if emptyspace == True:\r
 \r
             mstr_msg("photogen", "Patching empty space")\r
-            mask = self.buildCompletionMask()\r
-\r
-            # Load the mask\r
-            mask_px = mask.load()\r
 \r
             cmpl = Image.new("RGBA", (self._imgsize, self._imgsize))\r
-            cmp_px = cmpl.load()\r
 \r
             edn = self.find_earthnavdata_number()\r
             edns = self.latlng_folder(edn)\r
-            idx = 0\r
-            for r in mstr_completion_colors:\r
-                if r[0] == edns:\r
-                    break\r
-                else:\r
-                    idx = idx+1\r
-            \r
-            for y in range(self._imgsize):\r
-                for x in range(self._imgsize):\r
-                    p = mask_px[x,y]\r
-                    if p[3] > 0:\r
-                        cidx = randrange(0, len(mstr_completion_colors[idx][1])-1)\r
-                        clr = mstr_completion_colors[idx][1][cidx]\r
-                        cmp_px[x,y] = (clr[0], clr[1], clr[2], 255)\r
-\r
-            # Some features\r
-            patches = glob.glob(mstr_datafolder + "textures/tile/completion/*.png")\r
-\r
-            # Pick an amount of features to add\r
-            patch_amt = randrange(1, 7)\r
-\r
-            # Add those somewhere\r
-            for p in range(1, patch_amt+1):\r
-                # Load some patch\r
-                ptc = Image.open(mstr_datafolder + "textures/tile/completion/p" + str(randrange(1, len(patches)+1)) + ".png")\r
-                # Rotate it\r
-                ptc = ptc.rotate(randrange(0, 360), expand=True)\r
-\r
-                # Make sure ortho generation does not crash\r
-                if ptc.width >= mstr_photores:\r
-                    ptc = ptc.resize((1536, 1536), Image.Resampling.BILINEAR)\r
-\r
-                # Adjust alpha on this image\r
-                ptc_p = ptc.load()\r
-                for y in range(ptc.height):\r
-                    for x in range(ptc.width):\r
-                        c = ptc_p[x,y]\r
-                        if c[3] > 0:\r
-                            na = c[3] - 160\r
-                            if na < 0: na = 0\r
-                            nc = (c[0], c[1], c[2], na)\r
-                            ptc_p[x,y] = nc\r
-\r
-                # Find a location INSIDE the image!\r
-                px = randrange(1, randrange(self._imgsize - ptc.width - 1))\r
-                py = randrange(1, randrange(self._imgsize - ptc.height - 1))\r
-\r
-                # Add it to the completion image\r
-                cmpl.alpha_composite(ptc, dest=(px,py))\r
+\r
+            cplstr = ""\r
+            for c in range(0, len(cpl)):\r
+                cplstr = cplstr + str(cpl[c])\r
+                if c < len(cpl)-1:\r
+                    cplstr = cplstr + "_"\r
+\r
+            # Should this not exist yet, we need to create it\r
+            rg = mstr_resourcegen("landuse", "meadow", cpl)\r
+            rg.setLayerContrast(randrange(1,4))\r
+            ptcimg = rg.gensource()\r
+\r
+            ptc_src = [ptcimg[0]]\r
+            samples = 250  # <- We need this in a moment\r
+            for i in range(samples):\r
+                imgid = 0\r
+                if len(ptc_src) == 1: imgid = 0\r
+                l = 0 - int(ptc_src[imgid].width / 2)\r
+                r = cmpl.width - int(ptc_src[imgid].width / 2)\r
+                t = 0 - int(ptc_src[imgid].height / 2)\r
+                b = cmpl.height - int(ptc_src[imgid].height / 2)\r
+                cmpl.alpha_composite(ptc_src[imgid], (randrange(l, r), randrange(t, b)))\r
+\r
+            brd_img = ptcimg[1]\r
+            cmpl.alpha_composite(brd_img)\r
+\r
+            # Patches to add from other sources. If they don't exist, we also need to make them\r
+            masks = glob.glob(mstr_datafolder + "textures/tile/completion/*.png")\r
+            amt = randrange(5, 16)\r
+            for i in range(1, amt + 1):\r
+                pick = randrange(0, len(masks))\r
+                patchmask = Image.open(masks[pick])\r
+                patchpix = patchmask.load()\r
+                # Pick from possible tags and values for the patches\r
+                patchtags = [\r
+                    ["landuse", "meadow"],\r
+                    ["landuse", "grass"],\r
+                    ["natural", "heath"],\r
+                    ["natural", "scrub"]\r
+                ]\r
+\r
+                numbers = list(range(1, 16))\r
+                src = random.sample(numbers, 5)\r
+\r
+                patchpick = randrange(0, len(patchtags))\r
+\r
+                rg = mstr_resourcegen(patchtags[patchpick][0], patchtags[patchpick][1], src)\r
+                rg.setLayerContrast(randrange(1, 4))\r
+                ptch = rg.gensource()\r
+\r
+                rg_img = ptch[0]\r
+                rg_pix = rg_img.load()\r
+\r
+                # The patch to be used in the layer\r
+                layerpatch = Image.new("RGBA", (patchmask.width, patchmask.height))\r
+                lp_pix = layerpatch.load()\r
+                for y in range(0, patchmask.height):\r
+                    for x in range(0, patchmask.width):\r
+                        ptc_msk = patchpix[x, y]\r
+                        if ptc_msk[3] > 0:\r
+                            oc = rg_pix[x, y]\r
+                            nc = (oc[0], oc[1], oc[2], ptc_msk[3])\r
+                            lp_pix[x, y] = nc\r
+\r
+                layerpatch = layerpatch.rotate(randrange(0, 360), expand=True)\r
+\r
+                lx = randrange(self._imgsize - layerpatch.width)\r
+                ly = randrange(self._imgsize - layerpatch.height)\r
+                cmpl.alpha_composite(layerpatch, (lx, ly))\r
 \r
             # Merge the images\r
             cmpl.alpha_composite(self._tile)\r
@@ -152,11 +182,22 @@ class mstr_photogen:
                     corrpix[x,y] = nc\r
                 if c[3] == 0:\r
                     corrpix[x,y] = (0,0,0,0)\r
+\r
+        # One more thing...\r
+        mstr_msg("photogen", "Adding features to layers")\r
+        self.addTreesToFeatures(layers)\r
+\r
+        # Throw missing buildings on top\r
+        lyr = 0\r
+        for l in layers:\r
+            if self._lyrnames[lyr] == "building":\r
+                self._tile.alpha_composite(l)\r
+            lyr = lyr + 1\r
         \r
         # We are now in posession of the final image.\r
         \r
         # Contrast\r
-        self._tile = ImageEnhance.Contrast(self._tile).enhance(1)\r
+        #self._tile = ImageEnhance.Contrast(self._tile).enhance(0.1)\r
 \r
         # This we can save accordingly.\r
         self._tile.save(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")\r
@@ -191,6 +232,172 @@ class mstr_photogen:
             nrmimg.save(nrmfln)\r
 \r
 \r
+    # Generates some random tree.\r
+    # We will now move away from using pre-made trees...\r
+    # they didn't look so great\r
+    def generate_tree(self):\r
+        sx = randrange(18, 31)\r
+        sy = randrange(18, 31)\r
+\r
+        treepoly = Image.new("RGBA", (sx, sy))\r
+        draw = ImageDraw.Draw(treepoly)\r
+\r
+        draw.ellipse((4, 4, sx - 4, sy - 4), fill="black")\r
+\r
+        tree = Image.new("RGBA", (sx, sy))\r
+        treepx = tree.load()\r
+        maskpx = treepoly.load()\r
+\r
+        # How many tree points do we want?\r
+        treepts = 75\r
+        # How many of those have been drawn?\r
+        ptsdrawn = 0\r
+\r
+        bc = [\r
+            (36, 50, 52),\r
+            (30, 41, 39),\r
+            (32, 45, 37),\r
+            (32, 39, 49),\r
+            (33, 34, 40),\r
+            (44, 50, 53),\r
+            (40, 46, 48),\r
+            (14, 31, 38),\r
+            (17, 41, 33),\r
+            (39, 56, 35),\r
+            (51, 51, 42),\r
+            (12, 27, 31),\r
+            (45, 59, 48),\r
+            (37, 54, 29),\r
+            (59, 50, 34),\r
+            (59, 59, 35),\r
+            (59, 51, 35),\r
+            (70, 72, 45),\r
+            (48, 59, 44),\r
+            (29, 47, 23),\r
+            (47, 61, 43),\r
+            (29, 68, 15),\r
+            (53, 77, 63),\r
+            (20, 68, 40)\r
+        ]\r
+\r
+        bcp = randrange(0, len(bc))\r
+\r
+        treedraw = ImageDraw.Draw(tree)\r
+        while ptsdrawn < treepts + 1:\r
+            rx = randrange(0, sx)\r
+            ry = randrange(0, sy)\r
+            mp = maskpx[rx, ry]\r
+            if mp[3] > 0:\r
+                d = randrange(0, 51)\r
+                r = bc[bcp][0]\r
+                g = bc[bcp][1] + d\r
+                b = bc[bcp][2] + (d // 2)\r
+                a = randrange(170, 256)\r
+                c = (r, g, b, a)\r
+                ex = randrange(2, 5)\r
+                ey = randrange(2, 5)\r
+                treedraw.ellipse((rx - (ex // 2), ry - (ey // 2), rx + (ey // 2), ry + (ey // 2)), fill=c)\r
+                ptsdrawn = ptsdrawn + 1\r
+\r
+        for y in range(0, tree.height):\r
+            for x in range(0, tree.width):\r
+                tp = treepx[x, y]\r
+                diff = randrange(0, 31)\r
+                nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])\r
+                treepx[x, y] = nc\r
+\r
+        tree = tree.filter(ImageFilter.GaussianBlur(radius=0.5))\r
+\r
+        for y in range(0, tree.height):\r
+            for x in range(0, tree.width):\r
+                tp = treepx[x, y]\r
+                diff = randrange(0, 51)\r
+                nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])\r
+                treepx[x, y] = nc\r
+\r
+        return tree\r
+\r
+\r
+    # This used to be in layergen and solves the problem of roads being rendered above trees.\r
+    # It is the only solution that worked, after some research.\r
+    def addTreesToFeatures(self, layers):\r
+\r
+        # Walk through list of layers to decide where to add the trees\r
+        curlyr = 0\r
+        for lyr in self._lyrnames:\r
+            # Add trees only in some features\r
+            if (lyr[0] == "landuse" and lyr[1] == "cemetery") or (\r
+                    lyr[0] == "landuse" and lyr[1] == "residential") or (\r
+                    lyr[0] == "leisure" and lyr[1] == "park"):\r
+                trees = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+                amt = 4000\r
+                lyrmask = layers[curlyr].load() # We can use the layer image as alpha mask\r
+                for i in range(1, amt + 1):\r
+                    lx = randrange(0, self._imgsize)\r
+                    ly = randrange(0, self._imgsize)\r
+                    lp = lyrmask[lx,ly]\r
+                    if lp[3] > 0:\r
+                        tree = self.generate_tree()\r
+                        trees.alpha_composite(tree, (lx, ly))\r
+\r
+                tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))\r
+                tree_pix = trees.load()\r
+                shadow_pix = tree_shadow.load()\r
+                for y in range(self._imgsize):\r
+                    for x in range(self._imgsize):\r
+                        tp = tree_pix[x, y]\r
+                        if tp[3] > 0:\r
+                            rndshd = randrange(5, 210)\r
+                            sc = (0, 0, 0, rndshd)\r
+                            if x + 8 < self._imgsize and y + 5 < self._imgsize:\r
+                                shadow_pix[x + 8, y + 5] = sc\r
+                tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))\r
+                tree_shadow.alpha_composite(trees)\r
+                self._tile.alpha_composite(tree_shadow)\r
+            curlyr = curlyr + 1\r
+\r
+        # Reset\r
+        curlyr = 0\r
+        bldg = []\r
+        tilepix = self._tile.load()\r
+        for lyr in self._lyrnames:\r
+            if lyr[0] == "building":\r
+                bldg.append(curlyr)\r
+            curlyr = curlyr + 1\r
+\r
+        for b in range(0, len(bldg)):\r
+            bldg_lyr = layers[bldg[b]].load()\r
+            shdw = Image.open(mstr_datafolder + "_cache/" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_" + self._lyrnames[bldg[b]][0] + "-" + self._lyrnames[bldg[b]][1] + "_layer_shadow.png")\r
+            shdw_pix = shdw.load()\r
+            for y in range(0, self._imgsize):\r
+                for x in range(0, self._imgsize):\r
+                    bpix = bldg_lyr[x,y]\r
+                    spix = shdw_pix[x,y]\r
+                    if bpix[3] > 0 and spix[0] == 255:\r
+                        tilepix[x,y] = ( bpix[0], bpix[1], bpix[2], bpix[3] )\r
+\r
+\r
+\r
+    # Correct some layer issues\r
+    def correctLayerIssues(self, layers):\r
+\r
+        # First the residential/forest dilemma\r
+        residential = 0\r
+        forest = 0\r
+\r
+        curlyr = 0\r
+        for lyr in self._lyrnames:\r
+            if lyr[0] == "landuse" and lyr[1] == "residential":\r
+                residential=curlyr\r
+            if lyr[0] == "landuse" and lyr[1] == "forest":\r
+                forest = curlyr\r
+            curlyr = curlyr+1\r
+\r
+        layers[forest].alpha_composite(layers[residential])\r
+\r
+        return layers\r
+\r
+\r
 \r
 \r
     # This checks the final image for empty patches. Should one be\r
index 18a13e8cb2c130f0aee83f4fe8370e91c30fd1ed..de242e7510f006b2206b99bc56ae408214e39038 100644 (file)
@@ -29,7 +29,6 @@ class mstr_tileinfo:
         #self._adjfile = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/adjinfo"
         self._cplfile = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/cplinfo"
         self.createDataFile()
-        self.createCompletionFile()
 
 
     def createDataFile(self):
@@ -37,15 +36,8 @@ class mstr_tileinfo:
             open(self._adjfile, 'a').close()
 
 
-    def createCompletionFile(self):
-        if os.path.isfile(self._cplfile) == False:
-            open(self._cplfile, 'a').close()
-
-
-    def add_adjacency_data(self, tv, th, tag, value, source, adj):
+    def add_adjacency_data(self, tag, value, source, adj):
         line = ""
-        line = line + str(tv) + " "
-        line = line + str(th) + " "
         line = line + tag + " "
         line = line + value + " "
         line = line + str(source) + " "
@@ -55,19 +47,6 @@ class mstr_tileinfo:
             textfile.write(line)
 
 
-    def add_completion_data(self, tv, th, tag, value, source, adj):
-        line = ""
-        line = line + str(tv) + " "
-        line = line + str(th) + " "
-        line = line + tag + " "
-        line = line + value + " "
-        line = line + str(source) + " "
-        line = line + str(adj) + "\n"
-
-        with open(self._cplfile, 'a') as textfile:
-            textfile.write(line)
-
-
     def get_adjacency_for_tag_and_value(self, tv, th, tag, value):
         adj = []
         fnlines = []
@@ -78,12 +57,11 @@ class mstr_tileinfo:
 
             for ln in fnlines:
                 l = ln.split(" ")
-                if int(l[0]) == tv and int(l[1]) == th:
-                    if l[2] == tag and l[3] == value:
-                        l[5] = l[5].replace("\n", "")
-                        adj.append(int(l[4]))
-                        adj.append(l[5])
-                        break
+                if l[0] == tag and l[1] == value:
+                    l[3] = l[3].replace("\n", "")
+                    adj.append(l[2])
+                    adj.append(l[3])
+                    break
 
         return adj
 
@@ -243,3 +221,4 @@ class mstr_tileinfo:
         if abs(numbers[1]) >= 100 : fstr = fstr + str(numbers[1])
 
         return fstr
+
index f5197a2f9aca605f4877a850cada3bcfc8a76872..473582711a88180a8ca3f0e545017f4e9bd0c09d 100644 (file)
@@ -14,6 +14,7 @@
 # -------------------------------------------------------------------
 
 import glob
+from os import MFD_ALLOW_SEALING
 from random import randrange
 from PIL import Image
 from osmxml import *
@@ -34,7 +35,7 @@ class mstr_tileprep:
         self._tag       = tag
         self._value     = value
         self._edges     = ""   # To be filled by _edgeDetect call
-        self._source    = -1
+        self._source    = ""
         self._mask      = mask
         latlngfld = xplane_latlng_folder([lat, lng])
         self._tileinfo  = mstr_tileinfo(lat, lng, v, h, latlngfld)
@@ -53,8 +54,8 @@ class mstr_tileprep:
         return srcfld
 
 
-    # Prepare the tile accordingly
-    def _prepareTile(self):
+    # Use the mask to determine the edges
+    def _determineEdges(self):
         # Load the mask pixels
         mp = self._mask.load()
         imgsize = self._mask.width
@@ -69,29 +70,29 @@ class mstr_tileprep:
         al=False
 
         # Top scan
-        for i in range(0, imgsize-1):
+        for i in range(0, imgsize):
             p = mp[i,0]
             if p[3] > 0:
                 at=True
                 break
        
         # Right scan
-        for i in range(0, imgsize-1):
+        for i in range(0, imgsize):
             p = mp[imgsize-1,i]
             if p[3] > 0:
                 ar=True
                 break
         
         # Bottom scan
-        for i in range(0, imgsize-1):
+        for i in range(0, imgsize):
             p = mp[i,imgsize-1]
             if p[3] > 0:
                 ab=True
                 break
         
         # Left scan
-        for i in range(0, imgsize-1):
-            p = mp[1,i]
+        for i in range(0, imgsize):
+            p = mp[0,i]
             if p[3] > 0:
                 al=True
                 break
@@ -103,48 +104,187 @@ class mstr_tileprep:
         if ab==True: adjstr = adjstr + "b"
         if al==True: adjstr = adjstr + "l"
 
-        # Now find out of there is a source from any adjacent tile
-        adjtiles = findAdjacentTilesTo(self._tile_v, self._tile_h)
-        sat = []
-        sar = []
-        sab = []
-        sal = []
-        if self._is_completion == False:
-            if at == True: sat = self._tileinfo.get_adjacency_for_tag_and_value(adjtiles[0][0], adjtiles[0][1], self._tag, self._value) # Top
-            if ar == True: sar = self._tileinfo.get_adjacency_for_tag_and_value(adjtiles[1][0], adjtiles[1][1], self._tag, self._value) # Right
-            if ab == True: sab = self._tileinfo.get_adjacency_for_tag_and_value(adjtiles[2][0], adjtiles[2][1], self._tag, self._value) # Bottom
-            if al == True: sal = self._tileinfo.get_adjacency_for_tag_and_value(adjtiles[3][0], adjtiles[3][1], self._tag, self._value) # Left
-        if self._is_completion == True:
-            if at == True: sat = self._tileinfo.get_adjacency_for_completion(adjtiles[0][0], adjtiles[0][1]) # Top
-            if ar == True: sar = self._tileinfo.get_adjacency_for_completion(adjtiles[1][0], adjtiles[1][1]) # Right
-            if ab == True: sab = self._tileinfo.get_adjacency_for_completion(adjtiles[2][0], adjtiles[2][1]) # Bottom
-            if al == True: sal = self._tileinfo.get_adjacency_for_completion(adjtiles[3][0], adjtiles[3][1]) # Left
-
-        if self._source == -1 and len(sat) == 2: self._source = sat[0]
-        if self._source == -1 and len(sar) == 2: self._source = sar[0]
-        if self._source == -1 and len(sab) == 2: self._source = sab[0]
-        if self._source == -1 and len(sal) == 2: self._source = sal[0]
-
-        # If there was nothing in the info still, we need to select some source
-        if self._source == -1:
-            srcfld = self._findCorrectTextureFolder()
-            tx = mstr_datafolder + "textures/" + srcfld[0] + "/" + srcfld[1] + "/brd/b*.png"
-            lst = glob.glob(tx)
-            if len(lst) == 1: self._source = 1
-            if len(lst) >= 2: self._source = randrange(1, len(lst)+1)
-
-
-        # Store into DB - but only if there is something to store
+        # We will now write this down first, without a source being selected
         if adjstr != "":
-            if self._is_completion == False:
-                r = self._tileinfo.get_adjacency_for_tag_and_value(self._tile_v, self._tile_h, self._tag, self._value)
-                if len(r) == 0:
-                    self._tileinfo.add_adjacency_data(self._tile_v, self._tile_h, self._tag, self._value, self._source, adjstr)
-                    mstr_msg("tileprep", "Adjacency info stored in database")
-
-            if self._is_completion == True:
-                r = self._tileinfo.get_adjacency_for_completion(self._tile_v, self._tile_h)
-                if len(r) == 0:
-                    self._tileinfo.add_completion_data(self._tile_v, self._tile_h, self._tag, self._value, self._source, adjstr)
-                    mstr_msg("tileprep", "Adjacency info for completion stored in database")
+            self._tileinfo.add_adjacency_data(self._tag, self._value, "0", adjstr)
 
+
+    # Set the latlng folder
+    def _setLatLngFold(self, latlngfld):
+        self._latlngfld = latlngfld
+    
+    
+    # Find out if there is already something in place for this tag of this tile
+    def _getResourceInfo(self, tv, th):
+        # This either remains 0 or a string different to "0" in the end
+        src = "0"
+        df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tv) + "_" + str(th)
+        fnlines = []
+        if os.path.isfile(df) == True: # It is possible that the requested file does not yet exist
+            with open(df) as textfile:
+                fnlines = textfile.readlines()
+            
+            for ln in fnlines:
+                l = ln.split(" ")
+                if l[0] == self._tag and l[1] == self._value:
+                    l[3] = l[3].replace("\n", "")
+                    src = l[2]
+
+        return src
+
+
+    # Find the edge touch info
+    def _getResourceTouch(self, tv, th):
+        touch = ""
+        df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tv) + "_" + str(th)
+        fnlines = []
+        if os.path.isfile(df) == True:  # It is possible that the requested file does not yet exist
+            with open(df) as textfile:
+                fnlines = textfile.readlines()
+
+            for ln in fnlines:
+                l = ln.split(" ")
+                if l[0] == self._tag and l[1] == self._value:
+                    l[3] = l[3].replace("\n", "")
+                    touch = l[3]
+
+        return touch
+
+
+    # Select a combination of resources
+    def _selectResources(self):
+        numbers = list(range(1, 16))
+        res = random.sample(numbers, 5)
+
+        # Construct a string of the array
+        resstr = ""
+        for r in range(len(res)):
+            resstr = resstr + str(res[r])
+            if r < len(res)-1:
+                resstr = resstr + ","
+
+        return resstr
+
+
+    # Store the required resource information into the appropriate tile
+    def _storeResourceInfo(self, tile_v, tile_h, res):
+        df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(tile_v) + "_" + str(tile_h)
+        fnlines = []
+        contrast = 0
+        if os.path.isfile(df) == True: # It is possible that the requested file does not yet exist
+            with open(df) as textfile:
+                fnlines = textfile.readlines()
+            curline = 0
+            for ln in fnlines:
+                l = ln.split(" ")
+                if l[0] == self._tag and l[1] == self._value:
+                    l[2] = res
+                contrast = int(l[4])
+
+                # Find contrast values for some tags
+                if (
+                        (l[0] == "landuse" and l[1] == "forest") or
+                        (l[0] == "landuse" and l[1] == "meadow") or
+                        (l[0] == "landuse" and l[1] == "grass") or
+                        (l[0] == "leisure" and l[1] == "nature_reserve") or
+                        (l[0] == "natural" and l[1] == "grassland") or
+                        (l[0] == "landuse" and l[1] == "greenfield") or
+                        (l[0] == "natural" and l[1] == "heath") or
+                        (l[0] == "natural" and l[1] == "wetland") or
+                        (l[0] == "leisure" and l[1] == "park") or
+                        (l[0] == "building")
+                ):
+                    if int(l[4]) == 0: contrast = randrange(1, 4)
+
+                l[3] = l[3].replace("\n", "")
+                fnlines[curline] = l[0] + " " + l[1] + " " + l[2] + " " + l[3] + " " + str(contrast) + "\n"
+
+                curline = curline+1
+
+            lines = ""
+            for l in range(len(fnlines)):
+                lines = lines + fnlines[l]
+
+            with open(df, 'w') as textfile:
+                textfile.write(lines)
+
+
+    # Walk through the now existing data files and make sure we always pick the correct
+    # sources for every tile, thus evading previous edge detection errors
+    def _placeTileSources(self, mlat, mlng):
+
+        # The first tile gets to choose something for itself
+        if self._tile_v == 1 and self._tile_h == 1:
+            resstr = self._selectResources()
+            self._storeResourceInfo(1, 1, resstr)
+
+        # Start "raytracing"
+
+        # Initial reset
+        tv = self._tile_v
+        th = self._tile_h
+        # Start marching north
+        while tv < mlat+1:
+            restch = self._getResourceTouch(tv, th)
+            if "t" in restch:
+                resstr = self._getResourceInfo(tv, th)
+                if resstr == "0":
+                    resstr = self._selectResources()
+                    self._storeResourceInfo(tv, th, resstr)
+                resd = self._getResourceInfo(tv+1, th)
+                if resd=="0":
+                    self._storeResourceInfo(tv + 1, th, resstr)
+            else:
+                break
+            tv = tv + 1
+
+        # Start marching east
+        tv = self._tile_v
+        th = self._tile_h
+        while th < mlng + 1:
+            restch = self._getResourceTouch(tv, th)
+            if "r" in restch:
+                resstr = self._getResourceInfo(tv, th)
+                if resstr == "0":
+                    resstr = self._selectResources()
+                    self._storeResourceInfo(tv, th, resstr)
+                resd = self._getResourceInfo(tv, th+1)
+                if resd == "0":
+                    self._storeResourceInfo(tv, th + 1, resstr)
+            else:
+                break
+            th = th + 1
+
+        # Start marching south
+        tv = self._tile_v
+        th = self._tile_h
+        while tv > 0:
+            restch = self._getResourceTouch(tv, th)
+            if "b" in restch:
+                resstr = self._getResourceInfo(tv, th)
+                if resstr == "0":
+                    resstr = self._selectResources()
+                    self._storeResourceInfo(tv, th, resstr)
+                resd = self._getResourceInfo(tv - 1, th)
+                if resd == "0":
+                    self._storeResourceInfo(tv - 1, th, resstr)
+            else:
+                break
+            tv = tv - 1
+
+        # Start marching west
+        tv = self._tile_v
+        th = self._tile_h
+        while th > 0:
+            restch = self._getResourceTouch(tv, th)
+            if "l" in restch:
+                resstr = self._getResourceInfo(tv, th)
+                if resstr == "0":
+                    resstr = self._selectResources()
+                    self._storeResourceInfo(tv, th, resstr)
+                resd = self._getResourceInfo(tv, th-1)
+                if resd == "0":
+                    self._storeResourceInfo(tv, th - 1, resstr)
+            else:
+                break
+            th = th - 1
\ No newline at end of file
index 6a326603c19b6a92a9aea47c82b193c2b8868748..9f39266209b9183c164dbed3cbcef7925df91bda 100644 (file)
@@ -1,3 +1,4 @@
+from random import randrange\r
 \r
 # -------------------------------------------------------------------\r
 # ORTHOGRAPHIC\r
@@ -73,7 +74,7 @@ class mstr_xp_normalmap:
         # Resize original\r
         image = image.resize((int(mstr_photores/4), int(mstr_photores/4)), Image.Resampling.BILINEAR)\r
 \r
-        nmp = Image.new("RGBA", (image.width, image.height), (128,128,1,1))\r
+        nmp = Image.new("RGBA", (image.width, image.height), (128,128,0,0))\r
 \r
         if water: nmp = Image.new("RGBA", (image.width, image.height), (128, 128, 255, 0))\r
 \r
@@ -83,48 +84,62 @@ class mstr_xp_normalmap:
         # Let's try some shenanigans\r
         w = image.width\r
         h = image.height\r
-        for y in range(h):\r
-            for x in range(w):\r
-                p = org[x,y]\r
-                if p[3] > 0: # Only do something if there is something to do in layer\r
-                    # Neighboring pixels\r
-                    px_t  = org[ self.clamp(x, w),   self.clamp(y+1, h) ]\r
-                    px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]\r
-                    px_r  = org[ self.clamp(x+1, w), self.clamp(y, h)   ]\r
-                    px_br = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]\r
-                    px_b  = org[ self.clamp(x, w),   self.clamp(y-1, h) ]\r
-                    px_bl = org[ self.clamp(x-1, w), self.clamp(y-1, h) ]\r
-                    px_l  = org[ self.clamp(x-1, w), self.clamp(y, h)   ]\r
-                    px_tl = org[ self.clamp(x-1, w), self.clamp(y+1, h) ]\r
-\r
-                    # Intensities of pixels\r
-                    it_t  = self.intensity(px_t)\r
-                    it_tr = self.intensity(px_tr)\r
-                    it_r  = self.intensity(px_r)\r
-                    it_br = self.intensity(px_br)\r
-                    it_b  = self.intensity(px_b)\r
-                    it_bl = self.intensity(px_bl)\r
-                    it_l  = self.intensity(px_l)\r
-                    it_tl = self.intensity(px_tl)\r
-\r
-                    # Sobel filter\r
-                    dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)\r
-                    dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)\r
-                    dz = 10 # This is usually a good value for strength\r
-                    v = (dx, dy, dz)\r
-                    nrm = self.normalize_vector(v)\r
-                    \r
-                    if nrm[1] > 0:\r
-                        nrm[1] = 0 - (abs(nrm[1]))\r
-                    else:\r
-                        nrm[1] = abs(nrm[1])\r
-\r
-                    # Set pixel\r
-                    if water:\r
-                        nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), int(self.map_component(nrm[2])), int(self.map_component(nrm[2])))\r
-                    if not water:\r
+        if not water:\r
+            for y in range(h):\r
+                for x in range(w):\r
+                    p = org[x,y]\r
+                    if p[3] > 0: # Only do something if there is something to do in layer\r
+                        # Neighboring pixels\r
+                        px_t  = org[ self.clamp(x, w),   self.clamp(y+1, h) ]\r
+                        px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]\r
+                        px_r  = org[ self.clamp(x+1, w), self.clamp(y, h)   ]\r
+                        px_br = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]\r
+                        px_b  = org[ self.clamp(x, w),   self.clamp(y-1, h) ]\r
+                        px_bl = org[ self.clamp(x-1, w), self.clamp(y-1, h) ]\r
+                        px_l  = org[ self.clamp(x-1, w), self.clamp(y, h)   ]\r
+                        px_tl = org[ self.clamp(x-1, w), self.clamp(y+1, h) ]\r
+\r
+                        # Intensities of pixels\r
+                        it_t  = self.intensity(px_t)\r
+                        it_tr = self.intensity(px_tr)\r
+                        it_r  = self.intensity(px_r)\r
+                        it_br = self.intensity(px_br)\r
+                        it_b  = self.intensity(px_b)\r
+                        it_bl = self.intensity(px_bl)\r
+                        it_l  = self.intensity(px_l)\r
+                        it_tl = self.intensity(px_tl)\r
+\r
+                        # Sobel filter\r
+                        dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)\r
+                        dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)\r
+                        dz = 10 # This is usually a good value for strength\r
+                        v = (dx, dy, dz)\r
+                        nrm = self.normalize_vector(v)\r
+\r
+                        if nrm[1] > 0:\r
+                            nrm[1] = 0 - (abs(nrm[1]))\r
+                        else:\r
+                            nrm[1] = abs(nrm[1])\r
+\r
+                        # Set pixel\r
                         nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), 255 - int(self.map_component(nrm[2])), 1)\r
 \r
+        # Previous code produced bad and eerie looking lines at the border of the image. Let's have a go with this.\r
+        if water:\r
+            for y in range(h):\r
+                for x in range(w):\r
+                    p = org[x,y]\r
+                    if p[3] > 0:\r
+                        wr = randrange(116, 141)\r
+                        wg = randrange(111, 139)\r
+                        wb = 255\r
+                        if x == 0 or x == w-1: wb = 0\r
+                        if y == 0 or y == h-1: wb = 0\r
+                        wa = p[3]\r
+                        c = (wr, wg, wb, wa)\r
+                        nmp_pix[x,y] = c\r
+\r
+\r
         mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")\r
         return nmp\r
     \r