Massive commit. Raytracer for tile preparation. Resource generator. Everything moved into RAM for processing.
This commit is contained in:
parent
aae81c58e9
commit
2278fe3b0a
18
defines.py
18
defines.py
@ -132,6 +132,7 @@ mstr_ortho_layers = [
|
||||
("natural", "bare_rock", "natural", "bare_rock"),
|
||||
("highway", "track", 3),
|
||||
("highway", "path", 3),
|
||||
("highway", "footway", 4),
|
||||
("leisure", "park", "leisure", "green"),
|
||||
("leisure", "dog_park", "leisure", "green"),
|
||||
("leisure", "garden", "leisure", "green"),
|
||||
@ -144,7 +145,6 @@ mstr_ortho_layers = [
|
||||
# Z-Order 2
|
||||
("highway", "service", 6),
|
||||
("highway", "residential", 12),
|
||||
("highway", "footway", 4),
|
||||
("highway", "primary", 25),
|
||||
("highway", "secondary", 13),
|
||||
("highway", "tertiary", 20),
|
||||
@ -191,6 +191,7 @@ mstr_ortho_layers = [
|
||||
("building", "kindergarten", "building", "kindergarten"),
|
||||
("building", "public", "building", "public"),
|
||||
("building", "commercial", "building", "commercial"),
|
||||
("building", "warehouse", "building", "warehouse"),
|
||||
("building", "yes", "building", "common"),
|
||||
("water", "lake", "natural", "water"),
|
||||
("water", "pond", "natural", "water"),
|
||||
@ -281,9 +282,10 @@ mstr_mask_blur = [
|
||||
("building", "terrace", 1),
|
||||
("building", "hangar", 1),
|
||||
("building", "school", 1),
|
||||
("building", "kindergarten", 1),
|
||||
("building", "public", 1),
|
||||
("building", "commercial", 1),
|
||||
("building", "kindergarten", 1),
|
||||
("building", "public", 1),
|
||||
("building", "commercial", 1),
|
||||
("building", "warehouse", 1),
|
||||
("building", "yes", 0),
|
||||
("place", "sea", 1),
|
||||
("place", "ocean", 1)
|
||||
@ -396,7 +398,13 @@ mstr_building_base_colors = [
|
||||
"#373942", "#40424a", "#363b4f", "#2c2d32", "#444651",
|
||||
"#454545", "#39393b", "#4b4b4c", "#363638", "#525252"
|
||||
]
|
||||
)
|
||||
),
|
||||
("warehouse", [
|
||||
"#403a33", "#4f4b46", "#413629", "#574c3f", "#3a2e21",
|
||||
"#aaaeb6", "#939cac", "#8a919d", "#a0b9bf", "#8d999b",
|
||||
"#49575a", "#273d43", "#313a3c", "#484f50", "#212d30"
|
||||
]
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
|
@ -108,3 +108,4 @@ def xplane_latlng_folder(numbers):
|
||||
if abs(numbers[1]) >= 100 : fstr = fstr + str(numbers[1])
|
||||
|
||||
return fstr
|
||||
|
||||
|
939
layergen.py
939
layergen.py
File diff suppressed because it is too large
Load Diff
8
log.py
8
log.py
@ -11,9 +11,15 @@
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
import datetime
|
||||
from colorama import init as colorama_init
|
||||
from colorama import Fore
|
||||
from colorama import Style
|
||||
from defines import *
|
||||
|
||||
def mstr_msg(fnc, msg):
|
||||
if mstr_show_log == True:
|
||||
colorama_init()
|
||||
now = datetime.datetime.now()
|
||||
print(now.strftime(" %H:%M:%S" + " | ["+fnc+"] | " + msg))
|
||||
|
||||
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}')
|
||||
#print(f"{Fore.GREEN}" + now.strftime(" %H:%M:%S" + " | ["+fnc+"] | " + msg))
|
@ -252,6 +252,14 @@ class mstr_maskgen:
|
||||
if sp[3] != 0:
|
||||
bld_shadow_pix[x,y] = (0,0,0,120)
|
||||
|
||||
|
||||
# Mark buildings in red
|
||||
for y in range(mstr_photores):
|
||||
for x in range(mstr_photores):
|
||||
mp = mask_pix[x,y]
|
||||
if mp[3] != 0:
|
||||
bld_shadow_pix[x,y] = (255,0,0,255)
|
||||
|
||||
# Store
|
||||
if os.path.isfile(fn) == True:
|
||||
lyr = Image.open(fn)
|
||||
|
32
og.py
32
og.py
@ -35,13 +35,9 @@ prep = False
|
||||
|
||||
if len(sys.argv) == 4:
|
||||
cli = True
|
||||
if sys.argv[3] == "true": prep = True
|
||||
|
||||
#if len(sys.argv) == 4:
|
||||
# pbf = True
|
||||
|
||||
# Only if we find enough arguments, proceed.
|
||||
if cli == True:
|
||||
if cli:
|
||||
lat = int(sys.argv[1])
|
||||
lng = int(sys.argv[2])
|
||||
|
||||
@ -50,29 +46,19 @@ if cli == True:
|
||||
# Create the class and init values
|
||||
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd(), prep)
|
||||
|
||||
if prep == True:
|
||||
# Prepare a tile
|
||||
if sys.argv[3] == "prepare":
|
||||
og._prepareTile()
|
||||
|
||||
if prep == False:
|
||||
if sys.argv[3] != "xpscenery":
|
||||
og._generateOrthos_mt(int(sys.argv[3]))
|
||||
# Generate orthos
|
||||
if sys.argv[3] != "prepare" and sys.argv[3] != "xpscenery":
|
||||
og._generateOrthos_mt(int(sys.argv[3]))
|
||||
|
||||
# Build the terrain mesh and assign ground textures
|
||||
if sys.argv[3] == "xpscenery":
|
||||
og.generate_xp_scenery()
|
||||
# Build the terrain mesh and assign ground textures
|
||||
if sys.argv[3] == "xpscenery":
|
||||
og.generate_xp_scenery()
|
||||
|
||||
|
||||
# Only if we find enough arguments, proceed.
|
||||
if pbf == True:
|
||||
lat = int(sys.argv[1])
|
||||
lng = int(sys.argv[2])
|
||||
pbf = sys.argv[3]
|
||||
|
||||
if pbf == "pbf":
|
||||
# Create the class and init values
|
||||
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd())
|
||||
og._generateData()
|
||||
|
||||
|
||||
if cli == False and pbf == False:
|
||||
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
||||
|
@ -170,9 +170,13 @@ class mstr_orthographic:
|
||||
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
|
||||
maxlatlng = [ mlat, mlng ]
|
||||
|
||||
# For completion layers
|
||||
numbers = list(range(1, 16))
|
||||
res = random.sample(numbers, 5)
|
||||
|
||||
procs = []
|
||||
for p in range(1, amtsmt+1):
|
||||
proc = Process(target=self._buildOrtho, args=[1, p, amtsmt])
|
||||
proc = Process(target=self._buildOrtho, args=[1, p, amtsmt, res])
|
||||
procs.append(proc)
|
||||
proc.start()
|
||||
mstr_msg("orthographic", "Ortho threads started")
|
||||
@ -181,7 +185,7 @@ class mstr_orthographic:
|
||||
# Starts a threading loop to build orthos, with the defined starting point in
|
||||
# the lat-lng grid. You will also need to provide the horizontal stepping so
|
||||
# that the thread keeps running.
|
||||
def _buildOrtho(self, v, h, step):
|
||||
def _buildOrtho(self, v, h, step, cpl):
|
||||
|
||||
# Starting point
|
||||
grid_lat = v
|
||||
@ -256,7 +260,6 @@ class mstr_orthographic:
|
||||
lg = mstr_layergen(layer[0], layer[1], self._lat, grid_lat, self._long, grid_lng, layer[2])
|
||||
lg.set_max_latlng_tile(maxlatlng)
|
||||
lg.set_latlng_folder(self._latlngfld)
|
||||
#lg.open_db()
|
||||
lg.open_tile_info()
|
||||
lyr = lg.genlayer(mask, osmxml)
|
||||
photolayers.append(lyr)
|
||||
@ -274,7 +277,8 @@ class mstr_orthographic:
|
||||
# Snap a photo with our satellite :)
|
||||
mstr_msg("orthographic", "Generating ortho photo")
|
||||
pg = mstr_photogen(self._lat, self._long, grid_lat, grid_lng, maxlatlng[0], maxlatlng[1])
|
||||
pg.genphoto(photolayers, waterlayers)
|
||||
pg.setLayerNames(layers)
|
||||
pg.genphoto(photolayers, waterlayers, cpl)
|
||||
mstr_msg("orthographic", " -- Ortho photo generated -- ")
|
||||
print("")
|
||||
print("")
|
||||
@ -375,12 +379,12 @@ class mstr_orthographic:
|
||||
bb_lat = self._lat
|
||||
bb_lng = self._long
|
||||
|
||||
|
||||
# We will now prepare the graphic tile generation. We do this by only generating
|
||||
# the masks and determine which sources to use in the actual images.
|
||||
# Previously, I downloaded all XML files in one go - but to ease the
|
||||
# stress on OSM servers and my server, we will do acquire the data
|
||||
# only for the current processed part of the tile.
|
||||
"""
|
||||
for lat_grid in range(1, maxlatlng[0]+1):
|
||||
for lng_grid in range(1, maxlatlng[1]+1):
|
||||
# Adjust bounding box
|
||||
@ -403,7 +407,7 @@ class mstr_orthographic:
|
||||
mask = mg._build_mask(osmxml, is_prep=True) # We need an object here
|
||||
|
||||
tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, layer[0], layer[1], mask, False)
|
||||
tp._prepareTile()
|
||||
tp._determineEdges()
|
||||
|
||||
curlyr = curlyr+1
|
||||
|
||||
@ -428,6 +432,24 @@ class mstr_orthographic:
|
||||
if cur_tile_y > top_lat:
|
||||
top_lat = cur_tile_y
|
||||
|
||||
exit(1)
|
||||
"""
|
||||
|
||||
# We now need to "raytrace" the resources for correct placement
|
||||
mstr_msg("orthographic", "Performing resource plamement tracing for tile")
|
||||
for lat_grid in range(1, maxlatlng[0]+1):
|
||||
for lng_grid in range(1, maxlatlng[1]+1):
|
||||
mstr_msg("orthographic", "Placement tracing for " + str(lat_grid) + ":" + str(lng_grid))
|
||||
df = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + str(lat_grid) + "_" + str(lng_grid)
|
||||
fnlines = []
|
||||
with open(df) as textfile:
|
||||
fnlines = textfile.readlines()
|
||||
|
||||
for l in range(0, len(fnlines)):
|
||||
lyr = fnlines[l].split(" ")
|
||||
tp = mstr_tileprep(self._lat, self._long, lat_grid, lng_grid, lyr[0], lyr[1], None, False)
|
||||
tp._setLatLngFold(self._latlngfld)
|
||||
tp._placeTileSources(lat_grid, lng_grid)
|
||||
|
||||
|
||||
# Generates X-Plane 11/12 scenery with
|
||||
|
307
photogen.py
307
photogen.py
@ -1,12 +1,14 @@
|
||||
|
||||
import os
|
||||
from PIL import Image, ImageFilter, ImageEnhance
|
||||
from PIL import Image, ImageFilter, ImageEnhance, ImageFile
|
||||
from defines import *
|
||||
from layergen import *
|
||||
from log import *
|
||||
from functions import *
|
||||
from xp_normalmap import *
|
||||
|
||||
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# ORTHOGRAPHIC
|
||||
# Your personal aerial satellite. Always on. At any altitude.*
|
||||
@ -37,16 +39,29 @@ class mstr_photogen:
|
||||
mstr_msg("photogen", "Photogen initialized")
|
||||
|
||||
|
||||
# Defines the order of layer names that were processed
|
||||
# Called by orthographic prior to starting the photo gen process
|
||||
def setLayerNames(self, names):
|
||||
self._lyrnames = names
|
||||
|
||||
|
||||
# This puts it all together. Bonus: AND saves it.
|
||||
def genphoto(self, layers, waterlayers):
|
||||
def genphoto(self, layers, waterlayers, cpl):
|
||||
# Template for the file name which is always the same
|
||||
#root_filename = mstr_datafolder + "/_cache/" + str(self._lat) + "-" + str(self._ty) + "_" + str(self._lng) + "-" + str(self._tx) + "_"
|
||||
|
||||
# Correct layers
|
||||
#mstr_msg("photogen", "Correcting layer order issues")
|
||||
#layers = self.correctLayerIssues(layers)
|
||||
|
||||
# First, we walk through all layers and blend them on top of each other, in order
|
||||
mstr_msg("photogen", "Merging layers")
|
||||
|
||||
lyr=0
|
||||
for l in layers:
|
||||
self._tile.alpha_composite(l)
|
||||
if self._lyrnames[lyr] != "building":
|
||||
self._tile.alpha_composite(l)
|
||||
lyr=lyr+1
|
||||
|
||||
|
||||
# When we have run through this loop, we will end up with a sandwiched
|
||||
@ -65,65 +80,80 @@ class mstr_photogen:
|
||||
if emptyspace == True:
|
||||
|
||||
mstr_msg("photogen", "Patching empty space")
|
||||
mask = self.buildCompletionMask()
|
||||
|
||||
# Load the mask
|
||||
mask_px = mask.load()
|
||||
|
||||
cmpl = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
cmp_px = cmpl.load()
|
||||
|
||||
edn = self.find_earthnavdata_number()
|
||||
edns = self.latlng_folder(edn)
|
||||
idx = 0
|
||||
for r in mstr_completion_colors:
|
||||
if r[0] == edns:
|
||||
break
|
||||
else:
|
||||
idx = idx+1
|
||||
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
p = mask_px[x,y]
|
||||
if p[3] > 0:
|
||||
cidx = randrange(0, len(mstr_completion_colors[idx][1])-1)
|
||||
clr = mstr_completion_colors[idx][1][cidx]
|
||||
cmp_px[x,y] = (clr[0], clr[1], clr[2], 255)
|
||||
cplstr = ""
|
||||
for c in range(0, len(cpl)):
|
||||
cplstr = cplstr + str(cpl[c])
|
||||
if c < len(cpl)-1:
|
||||
cplstr = cplstr + "_"
|
||||
|
||||
# Some features
|
||||
patches = glob.glob(mstr_datafolder + "textures/tile/completion/*.png")
|
||||
# Should this not exist yet, we need to create it
|
||||
rg = mstr_resourcegen("landuse", "meadow", cpl)
|
||||
rg.setLayerContrast(randrange(1,4))
|
||||
ptcimg = rg.gensource()
|
||||
|
||||
# Pick an amount of features to add
|
||||
patch_amt = randrange(1, 7)
|
||||
ptc_src = [ptcimg[0]]
|
||||
samples = 250 # <- We need this in a moment
|
||||
for i in range(samples):
|
||||
imgid = 0
|
||||
if len(ptc_src) == 1: imgid = 0
|
||||
l = 0 - int(ptc_src[imgid].width / 2)
|
||||
r = cmpl.width - int(ptc_src[imgid].width / 2)
|
||||
t = 0 - int(ptc_src[imgid].height / 2)
|
||||
b = cmpl.height - int(ptc_src[imgid].height / 2)
|
||||
cmpl.alpha_composite(ptc_src[imgid], (randrange(l, r), randrange(t, b)))
|
||||
|
||||
# Add those somewhere
|
||||
for p in range(1, patch_amt+1):
|
||||
# Load some patch
|
||||
ptc = Image.open(mstr_datafolder + "textures/tile/completion/p" + str(randrange(1, len(patches)+1)) + ".png")
|
||||
# Rotate it
|
||||
ptc = ptc.rotate(randrange(0, 360), expand=True)
|
||||
brd_img = ptcimg[1]
|
||||
cmpl.alpha_composite(brd_img)
|
||||
|
||||
# Make sure ortho generation does not crash
|
||||
if ptc.width >= mstr_photores:
|
||||
ptc = ptc.resize((1536, 1536), Image.Resampling.BILINEAR)
|
||||
# Patches to add from other sources. If they don't exist, we also need to make them
|
||||
masks = glob.glob(mstr_datafolder + "textures/tile/completion/*.png")
|
||||
amt = randrange(5, 16)
|
||||
for i in range(1, amt + 1):
|
||||
pick = randrange(0, len(masks))
|
||||
patchmask = Image.open(masks[pick])
|
||||
patchpix = patchmask.load()
|
||||
# Pick from possible tags and values for the patches
|
||||
patchtags = [
|
||||
["landuse", "meadow"],
|
||||
["landuse", "grass"],
|
||||
["natural", "heath"],
|
||||
["natural", "scrub"]
|
||||
]
|
||||
|
||||
# Adjust alpha on this image
|
||||
ptc_p = ptc.load()
|
||||
for y in range(ptc.height):
|
||||
for x in range(ptc.width):
|
||||
c = ptc_p[x,y]
|
||||
if c[3] > 0:
|
||||
na = c[3] - 160
|
||||
if na < 0: na = 0
|
||||
nc = (c[0], c[1], c[2], na)
|
||||
ptc_p[x,y] = nc
|
||||
numbers = list(range(1, 16))
|
||||
src = random.sample(numbers, 5)
|
||||
|
||||
# Find a location INSIDE the image!
|
||||
px = randrange(1, randrange(self._imgsize - ptc.width - 1))
|
||||
py = randrange(1, randrange(self._imgsize - ptc.height - 1))
|
||||
patchpick = randrange(0, len(patchtags))
|
||||
|
||||
# Add it to the completion image
|
||||
cmpl.alpha_composite(ptc, dest=(px,py))
|
||||
rg = mstr_resourcegen(patchtags[patchpick][0], patchtags[patchpick][1], src)
|
||||
rg.setLayerContrast(randrange(1, 4))
|
||||
ptch = rg.gensource()
|
||||
|
||||
rg_img = ptch[0]
|
||||
rg_pix = rg_img.load()
|
||||
|
||||
# The patch to be used in the layer
|
||||
layerpatch = Image.new("RGBA", (patchmask.width, patchmask.height))
|
||||
lp_pix = layerpatch.load()
|
||||
for y in range(0, patchmask.height):
|
||||
for x in range(0, patchmask.width):
|
||||
ptc_msk = patchpix[x, y]
|
||||
if ptc_msk[3] > 0:
|
||||
oc = rg_pix[x, y]
|
||||
nc = (oc[0], oc[1], oc[2], ptc_msk[3])
|
||||
lp_pix[x, y] = nc
|
||||
|
||||
layerpatch = layerpatch.rotate(randrange(0, 360), expand=True)
|
||||
|
||||
lx = randrange(self._imgsize - layerpatch.width)
|
||||
ly = randrange(self._imgsize - layerpatch.height)
|
||||
cmpl.alpha_composite(layerpatch, (lx, ly))
|
||||
|
||||
# Merge the images
|
||||
cmpl.alpha_composite(self._tile)
|
||||
@ -153,10 +183,21 @@ class mstr_photogen:
|
||||
if c[3] == 0:
|
||||
corrpix[x,y] = (0,0,0,0)
|
||||
|
||||
# One more thing...
|
||||
mstr_msg("photogen", "Adding features to layers")
|
||||
self.addTreesToFeatures(layers)
|
||||
|
||||
# Throw missing buildings on top
|
||||
lyr = 0
|
||||
for l in layers:
|
||||
if self._lyrnames[lyr] == "building":
|
||||
self._tile.alpha_composite(l)
|
||||
lyr = lyr + 1
|
||||
|
||||
# We are now in posession of the final image.
|
||||
|
||||
# Contrast
|
||||
self._tile = ImageEnhance.Contrast(self._tile).enhance(1)
|
||||
#self._tile = ImageEnhance.Contrast(self._tile).enhance(0.1)
|
||||
|
||||
# This we can save accordingly.
|
||||
self._tile.save(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
||||
@ -191,6 +232,172 @@ class mstr_photogen:
|
||||
nrmimg.save(nrmfln)
|
||||
|
||||
|
||||
# Generates some random tree.
|
||||
# We will now move away from using pre-made trees...
|
||||
# they didn't look so great
|
||||
def generate_tree(self):
|
||||
sx = randrange(18, 31)
|
||||
sy = randrange(18, 31)
|
||||
|
||||
treepoly = Image.new("RGBA", (sx, sy))
|
||||
draw = ImageDraw.Draw(treepoly)
|
||||
|
||||
draw.ellipse((4, 4, sx - 4, sy - 4), fill="black")
|
||||
|
||||
tree = Image.new("RGBA", (sx, sy))
|
||||
treepx = tree.load()
|
||||
maskpx = treepoly.load()
|
||||
|
||||
# How many tree points do we want?
|
||||
treepts = 75
|
||||
# How many of those have been drawn?
|
||||
ptsdrawn = 0
|
||||
|
||||
bc = [
|
||||
(36, 50, 52),
|
||||
(30, 41, 39),
|
||||
(32, 45, 37),
|
||||
(32, 39, 49),
|
||||
(33, 34, 40),
|
||||
(44, 50, 53),
|
||||
(40, 46, 48),
|
||||
(14, 31, 38),
|
||||
(17, 41, 33),
|
||||
(39, 56, 35),
|
||||
(51, 51, 42),
|
||||
(12, 27, 31),
|
||||
(45, 59, 48),
|
||||
(37, 54, 29),
|
||||
(59, 50, 34),
|
||||
(59, 59, 35),
|
||||
(59, 51, 35),
|
||||
(70, 72, 45),
|
||||
(48, 59, 44),
|
||||
(29, 47, 23),
|
||||
(47, 61, 43),
|
||||
(29, 68, 15),
|
||||
(53, 77, 63),
|
||||
(20, 68, 40)
|
||||
]
|
||||
|
||||
bcp = randrange(0, len(bc))
|
||||
|
||||
treedraw = ImageDraw.Draw(tree)
|
||||
while ptsdrawn < treepts + 1:
|
||||
rx = randrange(0, sx)
|
||||
ry = randrange(0, sy)
|
||||
mp = maskpx[rx, ry]
|
||||
if mp[3] > 0:
|
||||
d = randrange(0, 51)
|
||||
r = bc[bcp][0]
|
||||
g = bc[bcp][1] + d
|
||||
b = bc[bcp][2] + (d // 2)
|
||||
a = randrange(170, 256)
|
||||
c = (r, g, b, a)
|
||||
ex = randrange(2, 5)
|
||||
ey = randrange(2, 5)
|
||||
treedraw.ellipse((rx - (ex // 2), ry - (ey // 2), rx + (ey // 2), ry + (ey // 2)), fill=c)
|
||||
ptsdrawn = ptsdrawn + 1
|
||||
|
||||
for y in range(0, tree.height):
|
||||
for x in range(0, tree.width):
|
||||
tp = treepx[x, y]
|
||||
diff = randrange(0, 31)
|
||||
nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])
|
||||
treepx[x, y] = nc
|
||||
|
||||
tree = tree.filter(ImageFilter.GaussianBlur(radius=0.5))
|
||||
|
||||
for y in range(0, tree.height):
|
||||
for x in range(0, tree.width):
|
||||
tp = treepx[x, y]
|
||||
diff = randrange(0, 51)
|
||||
nc = (tp[0] - diff, tp[1] - diff, tp[2] - diff, tp[3])
|
||||
treepx[x, y] = nc
|
||||
|
||||
return tree
|
||||
|
||||
|
||||
# This used to be in layergen and solves the problem of roads being rendered above trees.
|
||||
# It is the only solution that worked, after some research.
|
||||
def addTreesToFeatures(self, layers):
|
||||
|
||||
# Walk through list of layers to decide where to add the trees
|
||||
curlyr = 0
|
||||
for lyr in self._lyrnames:
|
||||
# Add trees only in some features
|
||||
if (lyr[0] == "landuse" and lyr[1] == "cemetery") or (
|
||||
lyr[0] == "landuse" and lyr[1] == "residential") or (
|
||||
lyr[0] == "leisure" and lyr[1] == "park"):
|
||||
trees = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
amt = 4000
|
||||
lyrmask = layers[curlyr].load() # We can use the layer image as alpha mask
|
||||
for i in range(1, amt + 1):
|
||||
lx = randrange(0, self._imgsize)
|
||||
ly = randrange(0, self._imgsize)
|
||||
lp = lyrmask[lx,ly]
|
||||
if lp[3] > 0:
|
||||
tree = self.generate_tree()
|
||||
trees.alpha_composite(tree, (lx, ly))
|
||||
|
||||
tree_shadow = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
tree_pix = trees.load()
|
||||
shadow_pix = tree_shadow.load()
|
||||
for y in range(self._imgsize):
|
||||
for x in range(self._imgsize):
|
||||
tp = tree_pix[x, y]
|
||||
if tp[3] > 0:
|
||||
rndshd = randrange(5, 210)
|
||||
sc = (0, 0, 0, rndshd)
|
||||
if x + 8 < self._imgsize and y + 5 < self._imgsize:
|
||||
shadow_pix[x + 8, y + 5] = sc
|
||||
tree_shadow = tree_shadow.filter(ImageFilter.GaussianBlur(radius=2))
|
||||
tree_shadow.alpha_composite(trees)
|
||||
self._tile.alpha_composite(tree_shadow)
|
||||
curlyr = curlyr + 1
|
||||
|
||||
# Reset
|
||||
curlyr = 0
|
||||
bldg = []
|
||||
tilepix = self._tile.load()
|
||||
for lyr in self._lyrnames:
|
||||
if lyr[0] == "building":
|
||||
bldg.append(curlyr)
|
||||
curlyr = curlyr + 1
|
||||
|
||||
for b in range(0, len(bldg)):
|
||||
bldg_lyr = layers[bldg[b]].load()
|
||||
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")
|
||||
shdw_pix = shdw.load()
|
||||
for y in range(0, self._imgsize):
|
||||
for x in range(0, self._imgsize):
|
||||
bpix = bldg_lyr[x,y]
|
||||
spix = shdw_pix[x,y]
|
||||
if bpix[3] > 0 and spix[0] == 255:
|
||||
tilepix[x,y] = ( bpix[0], bpix[1], bpix[2], bpix[3] )
|
||||
|
||||
|
||||
|
||||
# Correct some layer issues
|
||||
def correctLayerIssues(self, layers):
|
||||
|
||||
# First the residential/forest dilemma
|
||||
residential = 0
|
||||
forest = 0
|
||||
|
||||
curlyr = 0
|
||||
for lyr in self._lyrnames:
|
||||
if lyr[0] == "landuse" and lyr[1] == "residential":
|
||||
residential=curlyr
|
||||
if lyr[0] == "landuse" and lyr[1] == "forest":
|
||||
forest = curlyr
|
||||
curlyr = curlyr+1
|
||||
|
||||
layers[forest].alpha_composite(layers[residential])
|
||||
|
||||
return layers
|
||||
|
||||
|
||||
|
||||
|
||||
# This checks the final image for empty patches. Should one be
|
||||
|
35
tileinfo.py
35
tileinfo.py
@ -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
|
||||
|
||||
|
240
tileprep.py
240
tileprep.py
@ -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")
|
||||
self._tileinfo.add_adjacency_data(self._tag, self._value, "0", adjstr)
|
||||
|
||||
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")
|
||||
|
||||
# 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
|
@ -1,3 +1,4 @@
|
||||
from random import randrange
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# ORTHOGRAPHIC
|
||||
@ -73,7 +74,7 @@ class mstr_xp_normalmap:
|
||||
# Resize original
|
||||
image = image.resize((int(mstr_photores/4), int(mstr_photores/4)), Image.Resampling.BILINEAR)
|
||||
|
||||
nmp = Image.new("RGBA", (image.width, image.height), (128,128,1,1))
|
||||
nmp = Image.new("RGBA", (image.width, image.height), (128,128,0,0))
|
||||
|
||||
if water: nmp = Image.new("RGBA", (image.width, image.height), (128, 128, 255, 0))
|
||||
|
||||
@ -83,48 +84,62 @@ class mstr_xp_normalmap:
|
||||
# Let's try some shenanigans
|
||||
w = image.width
|
||||
h = image.height
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
p = org[x,y]
|
||||
if p[3] > 0: # Only do something if there is something to do in layer
|
||||
# Neighboring pixels
|
||||
px_t = org[ self.clamp(x, w), self.clamp(y+1, h) ]
|
||||
px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_r = org[ self.clamp(x+1, w), self.clamp(y, h) ]
|
||||
px_br = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_b = org[ self.clamp(x, w), self.clamp(y-1, h) ]
|
||||
px_bl = org[ self.clamp(x-1, w), self.clamp(y-1, h) ]
|
||||
px_l = org[ self.clamp(x-1, w), self.clamp(y, h) ]
|
||||
px_tl = org[ self.clamp(x-1, w), self.clamp(y+1, h) ]
|
||||
if not water:
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
p = org[x,y]
|
||||
if p[3] > 0: # Only do something if there is something to do in layer
|
||||
# Neighboring pixels
|
||||
px_t = org[ self.clamp(x, w), self.clamp(y+1, h) ]
|
||||
px_tr = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_r = org[ self.clamp(x+1, w), self.clamp(y, h) ]
|
||||
px_br = org[ self.clamp(x+1, w), self.clamp(y+1, h) ]
|
||||
px_b = org[ self.clamp(x, w), self.clamp(y-1, h) ]
|
||||
px_bl = org[ self.clamp(x-1, w), self.clamp(y-1, h) ]
|
||||
px_l = org[ self.clamp(x-1, w), self.clamp(y, h) ]
|
||||
px_tl = org[ self.clamp(x-1, w), self.clamp(y+1, h) ]
|
||||
|
||||
# Intensities of pixels
|
||||
it_t = self.intensity(px_t)
|
||||
it_tr = self.intensity(px_tr)
|
||||
it_r = self.intensity(px_r)
|
||||
it_br = self.intensity(px_br)
|
||||
it_b = self.intensity(px_b)
|
||||
it_bl = self.intensity(px_bl)
|
||||
it_l = self.intensity(px_l)
|
||||
it_tl = self.intensity(px_tl)
|
||||
# Intensities of pixels
|
||||
it_t = self.intensity(px_t)
|
||||
it_tr = self.intensity(px_tr)
|
||||
it_r = self.intensity(px_r)
|
||||
it_br = self.intensity(px_br)
|
||||
it_b = self.intensity(px_b)
|
||||
it_bl = self.intensity(px_bl)
|
||||
it_l = self.intensity(px_l)
|
||||
it_tl = self.intensity(px_tl)
|
||||
|
||||
# Sobel filter
|
||||
dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)
|
||||
dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)
|
||||
dz = 10 # This is usually a good value for strength
|
||||
v = (dx, dy, dz)
|
||||
nrm = self.normalize_vector(v)
|
||||
# Sobel filter
|
||||
dx = (it_tr + 2.0 * it_r + it_br) - (it_tl + 2.0 * it_l + it_bl)
|
||||
dy = (it_bl + 2.0 * it_b + it_br) - (it_tl + 2.0 * it_t + it_tr)
|
||||
dz = 10 # This is usually a good value for strength
|
||||
v = (dx, dy, dz)
|
||||
nrm = self.normalize_vector(v)
|
||||
|
||||
if nrm[1] > 0:
|
||||
nrm[1] = 0 - (abs(nrm[1]))
|
||||
else:
|
||||
nrm[1] = abs(nrm[1])
|
||||
if nrm[1] > 0:
|
||||
nrm[1] = 0 - (abs(nrm[1]))
|
||||
else:
|
||||
nrm[1] = abs(nrm[1])
|
||||
|
||||
# Set pixel
|
||||
if water:
|
||||
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])))
|
||||
if not water:
|
||||
# Set pixel
|
||||
nmp_pix[x,y] = (int(self.map_component(nrm[0])), int(self.map_component(nrm[1])), 255 - int(self.map_component(nrm[2])), 1)
|
||||
|
||||
# Previous code produced bad and eerie looking lines at the border of the image. Let's have a go with this.
|
||||
if water:
|
||||
for y in range(h):
|
||||
for x in range(w):
|
||||
p = org[x,y]
|
||||
if p[3] > 0:
|
||||
wr = randrange(116, 141)
|
||||
wg = randrange(111, 139)
|
||||
wb = 255
|
||||
if x == 0 or x == w-1: wb = 0
|
||||
if y == 0 or y == h-1: wb = 0
|
||||
wa = p[3]
|
||||
c = (wr, wg, wb, wa)
|
||||
nmp_pix[x,y] = c
|
||||
|
||||
|
||||
mstr_msg("xp_normalmap", "[X-Plane] Normal map generated")
|
||||
return nmp
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user