Perlin-noise based renderer fully functional. perlin.py adjusted to produce fully dynamic Perlin noises, per resource. Scenery generated to produce proper ZL16 tiles. Correction for incorrectly rendered water bodies in photogen.py . Removed waterway:stream from rendering as it is no actual geographical feature.
This commit is contained in:
parent
9eddb97425
commit
88905ac509
@ -71,7 +71,7 @@ mstr_xp_genscenery = True
|
||||
|
||||
# Generate normal maps for X-Plane scenery?
|
||||
# Strong recommendation: yes
|
||||
mstr_xp_scn_normalmaps = True
|
||||
mstr_xp_scn_normalmaps = False
|
||||
|
||||
# Paths to required X-Plane scenery tools
|
||||
#mstr_xp_meshtool = "/home/marcus/Developer/Projects/orthographic/bin/MeshTool"
|
||||
@ -195,11 +195,11 @@ mstr_ortho_layers = [
|
||||
("building", "commercial", "building", "commercial"),
|
||||
("building", "warehouse", "building", "warehouse"),
|
||||
("building", "yes", "building", "common"),
|
||||
#("waterway", "river", 3),
|
||||
("water", "lake", "natural", "water"),
|
||||
("water", "pond", "natural", "water"),
|
||||
("water", "river", "natural", "water"),
|
||||
("natural", "water", "natural", "water"),
|
||||
("waterway", "river", 3),
|
||||
("place", "sea", "natural", "sea"),
|
||||
("place", "ocean", "natural", "sea")
|
||||
]
|
||||
@ -244,11 +244,12 @@ mstr_mask_blur = [
|
||||
("natural", "water", 1),
|
||||
("natural", "bay", 7),
|
||||
("natural", "beach", 7),
|
||||
("natural", "sand", 3),
|
||||
("water", "lake", 3),
|
||||
("water", "pond", 3),
|
||||
("water", "river", 3),
|
||||
("leisure", "swimming_pool", 3),
|
||||
("waterway", "river", 3),
|
||||
#("waterway", "river", 3),
|
||||
("waterway", "stream", 2),
|
||||
("amenity", "parking", 1),
|
||||
("amenity", "school", 1),
|
||||
|
@ -361,8 +361,8 @@ class mstr_layergen:
|
||||
for x in range(0, layer.width):
|
||||
xp = prln_x + int(x/prln_pix_step)
|
||||
yp = prln_y + int(y/prln_pix_step)
|
||||
if xp == perlin_map.width: xp = perlin_map.width - 1
|
||||
if yp == perlin_map.height: yp = perlin_map.height - 1
|
||||
if xp >= perlin_map.width: xp = perlin_map.width - 1
|
||||
if yp >= perlin_map.height: yp = perlin_map.height - 1
|
||||
pc = perlin_pix[xp,yp]
|
||||
df = randrange(0, 6)
|
||||
lc = (pc[0]+df, pc[1]+df, pc[2]+df, 255)
|
||||
@ -666,7 +666,6 @@ class mstr_layergen:
|
||||
#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" )
|
||||
mstr_msg("layergen", "Layer image finalized and saved.")
|
||||
|
||||
|
||||
# Return image
|
||||
return layer_comp
|
||||
|
||||
@ -801,8 +800,6 @@ class mstr_layergen:
|
||||
if mp[3] == 255 and tp[3] == 255:
|
||||
tree_pix[x,y] = (0,0,0,0)
|
||||
|
||||
|
||||
|
||||
if mstr_shadow_enabled == True:
|
||||
tree_pix = trees.load()
|
||||
shadow_pix = tree_shadow.load()
|
||||
@ -842,7 +839,6 @@ class mstr_layergen:
|
||||
return bld_comp
|
||||
|
||||
|
||||
|
||||
# Find the next "by-ten" numbers for the current latitude and longitude
|
||||
def find_earthnavdata_number(self):
|
||||
earthnavdata = []
|
||||
|
46
og.py
46
og.py
@ -19,25 +19,26 @@ from defines import *
|
||||
|
||||
|
||||
# Print a welcome message
|
||||
print(r' ')
|
||||
print(r' ____ __ __ __ _ ')
|
||||
print(r' / __ \_____/ /_/ /_ ____ ____ __________ _____ / /_ (_)____')
|
||||
print(r' / / / / ___/ __/ __ \/ __ \/ __ `/ ___/ __ `/ __ \/ __ \/ / ___/')
|
||||
print(r'/ /_/ / / / /_/ / / / /_/ / /_/ / / / /_/ / /_/ / / / / / /__ ')
|
||||
print(r'\____/_/ \__/_/ /_/\____/\__, /_/ \__,_/ .___/_/ /_/_/\___/ ')
|
||||
print(r' /____/ /_/ ')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' A ground texture generator, using photo realistic resources,')
|
||||
print(r' for flight simulators.')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' Developed by and (c) Marcus Str.')
|
||||
print(r' Website: https://marstr.online/orthographic')
|
||||
print(r' Code repo: https://marstr.online/code/gitweb.cgi?p=orthographic')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' If you paid for this software, you have been scammed. The source')
|
||||
print(r' code and always available free of charge.')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' ')
|
||||
def _welcome():
|
||||
print(r' ')
|
||||
print(r' ____ __ __ __ _ ')
|
||||
print(r' / __ \_____/ /_/ /_ ____ ____ __________ _____ / /_ (_)____')
|
||||
print(r' / / / / ___/ __/ __ \/ __ \/ __ `/ ___/ __ `/ __ \/ __ \/ / ___/')
|
||||
print(r'/ /_/ / / / /_/ / / / /_/ / /_/ / / / /_/ / /_/ / / / / / /__ ')
|
||||
print(r'\____/_/ \__/_/ /_/\____/\__, /_/ \__,_/ .___/_/ /_/_/\___/ ')
|
||||
print(r' /____/ /_/ ')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' A ground texture generator, using photo realistic resources,')
|
||||
print(r' for flight simulators.')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' Developed by and (c) Marcus Str.')
|
||||
print(r' Website: https://marstr.online/orthographic')
|
||||
print(r' Code repo: http://marstr.online:3000/marstr/orthographic')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' If you paid for this software, you have been scammed. The source')
|
||||
print(r' code and always available free of charge.')
|
||||
print(r' ----------------------------------------------------------------')
|
||||
print(r' ')
|
||||
|
||||
|
||||
# Evaluate CLI arguments and process tile.
|
||||
@ -61,20 +62,17 @@ if __name__ == '__main__':
|
||||
# Create the class and init values
|
||||
og = mstr_orthographic(lat, lng, mstr_datafolder, os.getcwd(), prep)
|
||||
|
||||
# Prepare a tile
|
||||
if sys.argv[3] == "prepare":
|
||||
og._prepareTile()
|
||||
|
||||
# Generate orthos
|
||||
if sys.argv[3] != "prepare" and sys.argv[3] != "xpscenery":
|
||||
_welcome()
|
||||
og._generateOrthos_mt(int(sys.argv[3]))
|
||||
|
||||
# Build the terrain mesh and assign ground textures
|
||||
if sys.argv[3] == "xpscenery":
|
||||
_welcome()
|
||||
og.generate_xp_scenery()
|
||||
|
||||
|
||||
|
||||
if cli == False and pbf == False:
|
||||
mstr_msg("_main", "Please provide Latitude and Longitude. Exiting.")
|
||||
print ("")
|
||||
|
@ -241,15 +241,16 @@ class mstr_orthographic:
|
||||
# Step 2
|
||||
# Create folders and generate all perlin noise maps
|
||||
self._createFolders()
|
||||
"""
|
||||
#"""
|
||||
for l in mstr_ortho_layers:
|
||||
if l[0] != "highway" and l[0] != "building":
|
||||
mstr_important_msg("orthographic", "Generating Perlin map for " + l[0] + ":" + l[1])
|
||||
prln = mstr_perlin(l[0], l[1], mlat, mlng, 16)
|
||||
pmap = prln._generatePerlinMap()
|
||||
fn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/perlin/" + l[0] + "_" + l[1] + ".png"
|
||||
pmap.save(fn)
|
||||
"""
|
||||
if os.path.isfile(fn) == False:
|
||||
mstr_important_msg("orthographic", "Generating Perlin map for " + l[0] + ":" + l[1])
|
||||
prln = mstr_perlin(l[0], l[1], mlat, mlng, 16)
|
||||
pmap = prln._generatePerlinMap()
|
||||
pmap.save(fn)
|
||||
#"""
|
||||
|
||||
# For completion layers
|
||||
numbers = list(range(1, 16))
|
||||
@ -285,9 +286,15 @@ class mstr_orthographic:
|
||||
mlng = 1
|
||||
while bb_lat < self._lat + 1:
|
||||
bb_lat = bb_lat + self._vstep
|
||||
if bb_lat >= self._lat + 1:
|
||||
bb_lat = bb_lat - self._zoomlevel
|
||||
break
|
||||
mlat = mlat+1
|
||||
while bb_lng < self._long + 1:
|
||||
bb_lng = bb_lng + self._zoomlevel
|
||||
if bb_lng >= self._long + 1:
|
||||
bb_lng = bb_lng - self._zoomlevel
|
||||
break
|
||||
mlng = mlng+1
|
||||
mstr_msg("orthographic", "Max lat tile: " + str(mlat) + " - max lng tile: " + str(mlng))
|
||||
maxlatlng = [ mlat, mlng ]
|
||||
@ -631,7 +638,7 @@ class mstr_orthographic:
|
||||
# - the finished orthos
|
||||
# - a current LIDAR scan of the terrain
|
||||
def generate_xp_scenery(self):
|
||||
mstr_msg("orthographic", "[X-Plane] Generation of scenery started")
|
||||
mstr_important_msg("orthographic", "[X-Plane] Generation of scenery started")
|
||||
|
||||
# This call appears quite often... surely this can be done better
|
||||
mlat = 1
|
||||
@ -654,8 +661,8 @@ class mstr_orthographic:
|
||||
mstr_msg("orthographic", "[X-Plane] Scenery object instantiated")
|
||||
|
||||
# Download LIDAR scan from our endpoint
|
||||
xpscn.acquire_elevation_data()
|
||||
mstr_msg("orthographic", "[X-Plane] Elevation data acquired")
|
||||
#xpscn.acquire_elevation_data()
|
||||
#mstr_msg("orthographic", "[X-Plane] Elevation data acquired")
|
||||
|
||||
# Generate the .ter files
|
||||
xpscn.build_ter_files()
|
||||
|
151
perlin.py
151
perlin.py
@ -15,6 +15,8 @@ from PIL import Image # Depends on the Pillow lib
|
||||
from random import randrange
|
||||
import random
|
||||
import numpy as np
|
||||
import glob
|
||||
from defines import *
|
||||
from perlin_numpy import (
|
||||
generate_perlin_noise_2d, generate_fractal_noise_2d
|
||||
)
|
||||
@ -32,113 +34,70 @@ class mstr_perlin:
|
||||
if zl == 16: self._mapscale = 80
|
||||
if zl == 18: self._mapscale = 20
|
||||
|
||||
# Define some base colors
|
||||
# tag, value, base color, perlin noise color palette
|
||||
self._bc = [
|
||||
# Amenity
|
||||
["amenity", "parking", (31,32,34,255), [ (31,32,34), (74,74,73), (56,55,55), (34,40,44) ]],
|
||||
["amenity", "school", (26,26,26,255), [ (26,26,26), (78,78,78), (28,29,25), (86,74,64) ]],
|
||||
# Barrier
|
||||
["barrier", "hedge", (27,37,25,255), [ (27,37,25), (8,14,13), (15,20,23), (40,40,38) ]],
|
||||
# Boundary
|
||||
["boundary", "administrative", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
||||
# Landuse
|
||||
["landuse", "cemetery", (22,22,20,255), [ (22,22,20), (44,43,40), (31,33,29), (39,37,34) ]],
|
||||
["landuse", "construction", (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
|
||||
["landuse", "farmland", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["landuse", "farmyard", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["landuse", "forest", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
||||
["landuse", "grass", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
||||
["landuse", "greenfield", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
||||
["landuse", "meadow", (28,29,27,255), [ (28,29,27), (36,42,40), (45,44,41), (21,22,20) ]],
|
||||
["landuse", "military", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
||||
["landuse", "orchard", (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
|
||||
["landuse", "recreation_ground", (27,38,27,255), [ (27,38,27), (19,22,16), (40,42,33), (40,50,45) ]],
|
||||
["landuse", "residential", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
||||
["landuse", "residential-boundary", (50,49,46,255), [ (50,49,46), (32,38,34), (9,14,18), (82,80,76) ]],
|
||||
["landuse", "vineyard", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
# Leisure
|
||||
["leisure", "dog_park", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["leisure", "garden", (39,39,32,255), [ (39,39,32), (38,47,43), (35,41,31), (21,25,18) ]],
|
||||
["leisure", "golf_course", (29,39,28,255), [ (29,39,28), (86,81,76), (60,55,45), (13,18,14) ]],
|
||||
["leisure", "green", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["leisure", "nature_reserve", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
||||
["leisure", "park", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
||||
["leisure", "pitch", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["leisure", "playground", (65,51,32,255), [ (65,51,32), (77,73,67), (45,49,43), (74,63,48) ]],
|
||||
["leisure", "sports_centre", (66,60,49,255), [ (66,60,49), (23,32,27), (14,18,20), (45,43,39) ]],
|
||||
["leisure", "swimming_pool", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
||||
# Natural
|
||||
["natural", "bare_rock", (47,54,56,255), [ (47,54,56), (79,75,71), (84,51,43), (26,33,45) ]],
|
||||
["natural", "beach", (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
|
||||
["natural", "desert", (79,64,42,255), [ (79,64,42), (79,47,24), (37,41,27), (51,39,23) ]],
|
||||
["natural", "grassland", (23,24,22,255), [ (23,24,22), (40,27,35), (32,34,30), (54,53,51) ]],
|
||||
["natural", "heath", (26,28,23,255), [ (26,28,23), (45,44,42), (30,34,29), (45,45,42) ]],
|
||||
["natural", "sand", (79,76,69,255), [ (79,76,69), (82,83,80), (71,61,48), (69,68,66) ]],
|
||||
["natural", "scree", (38,36,33,255), [ (38,36,33), (81,80,76), (43,42,31), (37,34,27) ]],
|
||||
["natural", "scrub", (41,39,35,255), [ (41,39,35), (44,38,34), (30,32,39), (20,27,22) ]],
|
||||
["natural", "water", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
||||
["natural", "wetland", (32,34,33,255), [ (32,34,33), (5, 8, 8), (35,36,35), (17,19,17) ]],
|
||||
["natural", "wood", (0,30,10,255), [ (0,30,10), (18,23,16), (15,23,24), (24,29,27) ]],
|
||||
# Water
|
||||
["water", "lake", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
||||
["water", "pond", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]],
|
||||
["water", "river", (9,13,18,255), [ (9,13,18), (9,15,21), (11,12,12), (22,28,31) ]]
|
||||
]
|
||||
|
||||
def _generateColorIndex(self):
|
||||
idx = []
|
||||
|
||||
colorsrc = glob.glob(mstr_datafolder + "textures/" + self._tag + "/" + self._value + "/*.png")
|
||||
if len(colorsrc) >= 4:
|
||||
picknum = list(range(0, len(colorsrc)))
|
||||
picksel = random.sample(picknum, 4)
|
||||
|
||||
for p in range(0, 4):
|
||||
ptc = Image.open(colorsrc[picksel[p]])
|
||||
ptc = ptc.resize((1,1), resample=Image.Resampling.BILINEAR)
|
||||
clr = ptc.getpixel((0,0))
|
||||
res = (clr[0], clr[1], clr[2])
|
||||
idx.append(res)
|
||||
|
||||
# Find base color depending on tag/value
|
||||
def _findBaseColor(self):
|
||||
idx = -1
|
||||
for b in range(len(self._bc)):
|
||||
if self._bc[b][0] == self._tag and self._bc[b][1] == self._value:
|
||||
idx = b
|
||||
break
|
||||
return idx
|
||||
|
||||
|
||||
# Generates a Perlin map depending on what we need
|
||||
def _generatePerlinMap(self):
|
||||
idx = self._findBaseColor()
|
||||
|
||||
#idx = self._findBaseColor()
|
||||
clr = self._generateColorIndex()
|
||||
bw = self._mlng * self._mapscale
|
||||
bh = self._mlat * self._mapscale
|
||||
wh = 2048
|
||||
base = Image.new("RGBA", (bw,bh), self._bc[idx][2])
|
||||
base = Image.new("RGBA", (bw,bh))
|
||||
|
||||
for c in range(len(self._bc[idx][3])):
|
||||
np.random.seed(randrange(10000000, 100000000))
|
||||
noise1 = generate_fractal_noise_2d((wh,wh), (16,16), 5)
|
||||
np.random.seed(randrange(10000000, 100000000))
|
||||
noise2 = generate_fractal_noise_2d((wh,wh), (8,8), 4)
|
||||
|
||||
im1 = Image.new("RGBA", (wh,wh))
|
||||
im2 = Image.new("RGBA", (wh,wh))
|
||||
if len(clr) == 4:
|
||||
wh = 2048
|
||||
base = Image.new("RGBA", (bw,bh), clr[0])
|
||||
|
||||
for y in range(0, wh):
|
||||
for x in range(0, wh):
|
||||
n = (noise1[y][x] + 1) / 2
|
||||
v = (
|
||||
self._bc[idx][3][c][0],
|
||||
self._bc[idx][3][c][1],
|
||||
self._bc[idx][3][c][2],
|
||||
int(n*255)
|
||||
)
|
||||
im1.putpixel((x,y), v)
|
||||
|
||||
for y in range(0, wh):
|
||||
for x in range(0, wh):
|
||||
n = (noise2[y][x] + 1) / 2
|
||||
v = (
|
||||
self._bc[idx][3][c][0],
|
||||
self._bc[idx][3][c][1],
|
||||
self._bc[idx][3][c][2],
|
||||
int(n*255)
|
||||
)
|
||||
im2.putpixel((x,y), v)
|
||||
|
||||
im = Image.blend(im1,im2, alpha=0.5)
|
||||
base.alpha_composite(im)
|
||||
for c in range(len(clr)):
|
||||
np.random.seed(randrange(10000000, 100000000))
|
||||
noise1 = generate_fractal_noise_2d((wh,wh), (64,64), 5)
|
||||
np.random.seed(randrange(10000000, 100000000))
|
||||
noise2 = generate_fractal_noise_2d((wh,wh), (32,32), 4)
|
||||
|
||||
im1 = Image.new("RGBA", (wh,wh))
|
||||
im2 = Image.new("RGBA", (wh,wh))
|
||||
|
||||
for y in range(0, wh):
|
||||
for x in range(0, wh):
|
||||
n = (noise1[y][x] + 1) / 2
|
||||
v = (
|
||||
clr[c][0],
|
||||
clr[c][1],
|
||||
clr[c][2],
|
||||
int(n*255)
|
||||
)
|
||||
im1.putpixel((x,y), v)
|
||||
|
||||
for y in range(0, wh):
|
||||
for x in range(0, wh):
|
||||
n = (noise2[y][x] + 1) / 2
|
||||
v = (
|
||||
clr[c][0],
|
||||
clr[c][1],
|
||||
clr[c][2],
|
||||
int(n*255)
|
||||
)
|
||||
im2.putpixel((x,y), v)
|
||||
|
||||
im = Image.blend(im1,im2, alpha=0.675)
|
||||
base.alpha_composite(im)
|
||||
|
||||
# Provide the perlin map
|
||||
return base
|
85
photogen.py
85
photogen.py
@ -210,8 +210,6 @@ class mstr_photogen:
|
||||
#self._tile = ImageEnhance.Contrast(self._tile).enhance(0.1)
|
||||
|
||||
# This we can save accordingly.
|
||||
self._tile.show()
|
||||
exit()
|
||||
self._tile.save(mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(self._ty) + "_" + str(self._tx) + ".png")
|
||||
|
||||
# Now we convert this into a DDS
|
||||
@ -489,13 +487,13 @@ class mstr_photogen:
|
||||
# First the residential/forest dilemma
|
||||
residential = -1
|
||||
forest = -1
|
||||
reserve = -1
|
||||
|
||||
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
|
||||
if lyr[0] == "landuse" and lyr[1] == "residential": residential=curlyr
|
||||
if lyr[0] == "landuse" and lyr[1] == "forest": forest = curlyr
|
||||
if lyr[0] == "leisure" and lyr[1] == "nature_reserve": reserve = curlyr
|
||||
curlyr = curlyr+1
|
||||
|
||||
# Make sure we hit the correct layers with correct content!
|
||||
@ -515,11 +513,82 @@ class mstr_photogen:
|
||||
|
||||
layers[forest].alpha_composite(rsd_adj)
|
||||
|
||||
|
||||
if residential != -1 and reserve != -1:
|
||||
rsd_pix = layers[residential].load()
|
||||
frs_pix = layers[reserve].load()
|
||||
rsd_adj = Image.new("RGBA", (self._imgsize, self._imgsize))
|
||||
adj_pix = rsd_adj.load()
|
||||
|
||||
for y in range(0, self._tile.height):
|
||||
for x in range(0, self._tile.width):
|
||||
fp = frs_pix[x,y]
|
||||
rp = rsd_pix[x,y]
|
||||
if rp[3] > 0 and fp[3] > 0:
|
||||
adj_pix[x,y] = (rp[0], rp[1], rp[2], rp[3])
|
||||
|
||||
layers[reserve].alpha_composite(rsd_adj)
|
||||
|
||||
# At ZL16 there seems to be an issue with water bodies, especially rivers (natural:water).
|
||||
# Let's see if we can correct that
|
||||
|
||||
# natural:water
|
||||
ntrl_water = False
|
||||
ntrl_idx = 0
|
||||
for lyr in self._lyrnames:
|
||||
if lyr[0] == "natural" and lyr[1] == "water":
|
||||
ntrl_water = True
|
||||
break
|
||||
ntrl_idx = ntrl_idx + 1
|
||||
|
||||
if ntrl_water == True:
|
||||
|
||||
# We'll go through all layers and "shavve off" excess.
|
||||
# This way we can hopefully correct incorrect line and polygon renders.
|
||||
for l in range(0, len(layers)):
|
||||
if l < ntrl_idx: # <- We don't want to load the target layer itself
|
||||
lyrpix = layers[l].load()
|
||||
wtr_pix = layers[ntrl_idx].load()
|
||||
for y in range(0, self._tile.height):
|
||||
for x in range(0, self._tile.width):
|
||||
lp = lyrpix[x,y]
|
||||
wp = wtr_pix[x,y]
|
||||
if lp[3] > 0:
|
||||
a = 255 - lp[3]
|
||||
if a < wp[3]:
|
||||
c = (wp[0], wp[1], wp[2], a)
|
||||
wtr_pix[x,y] = c
|
||||
|
||||
# water:river
|
||||
river_water = False
|
||||
river_idx = 0
|
||||
for lyr in self._lyrnames:
|
||||
if lyr[0] == "water" and lyr[1] == "river":
|
||||
river_water = True
|
||||
break
|
||||
river_idx = river_idx + 1
|
||||
|
||||
if river_water == True:
|
||||
|
||||
# We'll go through all layers and "shavve off" excess.
|
||||
# This way we can hopefully correct incorrect line and polygon renders.
|
||||
for l in range(0, len(layers)):
|
||||
if l < river_idx and l != ntrl_idx: # <- We don't want to load the target layer itself
|
||||
lyrpix = layers[l].load()
|
||||
wtr_pix = layers[river_idx].load()
|
||||
for y in range(0, self._tile.height):
|
||||
for x in range(0, self._tile.width):
|
||||
lp = lyrpix[x,y]
|
||||
wp = wtr_pix[x,y]
|
||||
if lp[3] > 0:
|
||||
a = 255 - lp[3]
|
||||
if a < wp[3]:
|
||||
c = (wp[0], wp[1], wp[2], a)
|
||||
wtr_pix[x,y] = c
|
||||
|
||||
return layers
|
||||
|
||||
|
||||
|
||||
|
||||
# This checks the final image for empty patches. Should one be
|
||||
# found, we will generate something to fill the gap. If this is
|
||||
# the case, we will also note this in the database for the tile,
|
||||
|
@ -92,8 +92,13 @@ class mstr_xp_scenery:
|
||||
end = self.find_earthnavdata_number()
|
||||
llf = self.xplane_latlng_folder(end)
|
||||
meshtxt = mstr_datafolder + "_cache/mesh_"+self._latlngfld+".txt"
|
||||
cmd = mstr_xp_dsftool + " --text2dsf " + meshtxt + " '" + mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf'"
|
||||
meshtxt = meshtxt.replace("/", "\\")
|
||||
cmdpath = mstr_datafolder + "_cache/" + self._latlngfld + ".dsf"
|
||||
#cmdpath = mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf"
|
||||
cmdpath = cmdpath.replace("/", "\\")
|
||||
cmd = mstr_xp_dsftool + " --text2dsf " + meshtxt + " " + cmdpath
|
||||
os.system(cmd)
|
||||
os.replace(cmdpath, mstr_datafolder + "z_orthographic/Earth nav data/" + llf + "/" + self._latlngfld + ".dsf")
|
||||
|
||||
|
||||
# Find exact with of longitude
|
||||
@ -165,14 +170,14 @@ class mstr_xp_scenery:
|
||||
cur_lat = self._lat
|
||||
cur_lng = self._lng
|
||||
xp_folder = self.xplane_latlng_folder([self._lat, self._lng])
|
||||
for lat in range(1, self._mlat+1):
|
||||
for lng in range(1, self._mlng+1):
|
||||
for lat in range(1, self._mlat):
|
||||
for lng in range(1, self._mlng):
|
||||
|
||||
wdt = self.find_width_of_longitude(cur_lat)
|
||||
dmt = wdt * mstr_zl_18
|
||||
dmt = wdt * mstr_zl_16
|
||||
|
||||
cnt_x = cur_lat + (self._vstep/2)
|
||||
cnt_y = cur_lng + (mstr_zl_18/2)
|
||||
cnt_y = cur_lng + (mstr_zl_16/2)
|
||||
|
||||
terstr = ""
|
||||
terstr = terstr + "A\r\n"
|
||||
@ -181,15 +186,15 @@ class mstr_xp_scenery:
|
||||
terstr = terstr + "\r\n"
|
||||
terstr = terstr + "LOAD_CENTER " + str(cnt_x) + " " + str(cnt_y) + " " + str(dmt) + " 2048\r\n"
|
||||
terstr = terstr + "BASE_TEX_NOWRAP ../../orthos/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".dds\r\n"
|
||||
if mstr_xp_scn_normalmaps:
|
||||
terstr = terstr + "NORMAL_TEX 1.0 ../../normals/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".png\r\n"
|
||||
#if mstr_xp_scn_normalmaps:
|
||||
# terstr = terstr + "NORMAL_TEX 1.0 ../../normals/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".png\r\n"
|
||||
|
||||
terfln = mstr_datafolder + "z_orthographic/terrain/" + self._latlngfld + "/" + str(lat)+"_"+str(lng)+".ter"
|
||||
|
||||
with open(terfln, 'w') as textfile:
|
||||
textfile.write(terstr)
|
||||
|
||||
cur_lng = round(cur_lng + mstr_zl_18, 6)
|
||||
cur_lng = round(cur_lng + mstr_zl_16, 6)
|
||||
|
||||
cur_lng = self._lng
|
||||
cur_lat = round(cur_lat + self._vstep, 6)
|
||||
@ -200,7 +205,7 @@ class mstr_xp_scenery:
|
||||
# This generates the entire terrain mesh
|
||||
def generate_terrain_mesh(self):
|
||||
# Get the DEM model file name, and acquire important info about the data
|
||||
meshfn = mstr_datafolder + "_cache/" + self.build_dem_filename()
|
||||
meshfn = mstr_datafolder + "z_orthographic/data/" + self._latlngfld + "/" + self.build_dem_filename()
|
||||
siz = os.path.getsize(meshfn)
|
||||
dim = int(math.sqrt(siz/2))
|
||||
assert dim*dim*2 == siz, 'Invalid file size'
|
||||
@ -245,8 +250,8 @@ class mstr_xp_scenery:
|
||||
dsf_str = ""
|
||||
|
||||
# Orthos
|
||||
for lat in range(1, self._mlat+1):
|
||||
for lng in range(1, self._mlng+1):
|
||||
for lat in range(1, self._mlat):
|
||||
for lng in range(1, self._mlng):
|
||||
# Write the line only if an ortho exists of course.
|
||||
ddsf = mstr_datafolder + "z_orthographic/orthos/" + self._latlngfld + "/" + str(lat) + "_" + str(lng) + ".dds"
|
||||
if os.path.isfile(ddsf):
|
||||
@ -261,8 +266,8 @@ class mstr_xp_scenery:
|
||||
# Current patch
|
||||
curpatch = 0
|
||||
|
||||
for lat in range(1, self._mlat+1):
|
||||
for lng in range(1, self._mlng+1):
|
||||
for lat in range(1, self._mlat):
|
||||
for lng in range(1, self._mlng):
|
||||
|
||||
# Create the patch only if the matching ortho exists.
|
||||
# This way we make sure that we hit the same order as the .ter files.
|
||||
@ -273,7 +278,7 @@ class mstr_xp_scenery:
|
||||
|
||||
# Base coords for this ortho
|
||||
base_lat = self._lat + ((lat-1) * self._vstep)
|
||||
base_lng = self._lng + ((lng-1) * mstr_zl_18)
|
||||
base_lng = self._lng + ((lng-1) * mstr_zl_16)
|
||||
|
||||
# Begin a new patch
|
||||
mstr_msg("xp_scenery", "[X-Plane] Processing ortho patch " + str(curpatch))
|
||||
@ -281,9 +286,10 @@ class mstr_xp_scenery:
|
||||
textfile.write("BEGIN_PATCH " + str(curpatch) + " 0.000000 -1.000000 1 7\r\n")
|
||||
|
||||
# Step for each ortho vertex
|
||||
odiv = 4
|
||||
#odiv = 4
|
||||
odiv = 16
|
||||
latstep = self._vstep/odiv
|
||||
lngstep = mstr_zl_18 /odiv
|
||||
lngstep = mstr_zl_16 /odiv
|
||||
uv_step = 1 / odiv
|
||||
|
||||
# Generate the ortho tile
|
||||
@ -300,10 +306,14 @@ class mstr_xp_scenery:
|
||||
lng_l = base_lng
|
||||
if y == 0:
|
||||
lat_b = base_lat
|
||||
if y == 3:
|
||||
if y == 15:
|
||||
#if y == 3:
|
||||
lat_t = base_lat + self._vstep
|
||||
if x == 3:
|
||||
lng_r = base_lng + mstr_zl_18
|
||||
if x == 15:
|
||||
lng_r = base_lng + mstr_zl_16
|
||||
#if x == 3:
|
||||
#lng_r = base_lng + mstr_zl_18
|
||||
|
||||
|
||||
# Corrections, just in case
|
||||
if lat_b > self._lat + 1: lat_b = self._lat+1
|
||||
|
Loading…
x
Reference in New Issue
Block a user