From d5c3c5ecadfbd3db7b4a37b900d73f8d3e0cfcb2 Mon Sep 17 00:00:00 2001 From: Marcus Str Date: Sat, 28 Sep 2024 21:06:40 +0200 Subject: [PATCH] Implemented new function in layergen to combat the issue of different sources for material, when these neighbor on different edges. A fade in each direction for the non-precedence material is now implemented, hopefully solving this issue. To be tested by MarStr. --- functions.py | 4 +- layergen.py | 167 ++++++++++++++++++++++++++++++++ textures/multi_source/brd_b.png | Bin 0 -> 1001 bytes textures/multi_source/brd_l.png | Bin 0 -> 963 bytes textures/multi_source/brd_r.png | Bin 0 -> 969 bytes textures/multi_source/brd_t.png | Bin 0 -> 1005 bytes 6 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 textures/multi_source/brd_b.png create mode 100644 textures/multi_source/brd_l.png create mode 100644 textures/multi_source/brd_r.png create mode 100644 textures/multi_source/brd_t.png diff --git a/functions.py b/functions.py index 9f02251..664a875 100644 --- a/functions.py +++ b/functions.py @@ -83,4 +83,6 @@ def findAirportTiles(av, ah): # Testing def in_circle(center_x, center_y, radius, x, y): square_dist = (center_x - x) ** 2 + (center_y - y) ** 2 - return square_dist <= radius ** 2 \ No newline at end of file + return square_dist <= radius ** 2 + + diff --git a/layergen.py b/layergen.py index b47d29d..1015283 100644 --- a/layergen.py +++ b/layergen.py @@ -441,6 +441,29 @@ class mstr_layergen: layer_border = self.genborder(osm_edge, "landuse", "meadow") layer_comp.alpha_composite(layer_border) + + # Here we want to make sure that the generated image fits well with others, so + # let's do that. + mstr_msg("layergen", "Generating adjacent fades") + self.generate_adjacent_fades() + + # Determine if there are any fades, and if so, fade those in first before we save the layer + fade_fn = mstr_datafolder + "_cache/" + str(self._latitude) + "-" + str(self._lat_number) + "_" + str(self._longitude) + "-" + str(self._lng_number) + "_" + self._tag + "-" + self._value + if os.path.isfile(fade_fn + "_fade_top.png") == True: + fade = Image.open(fade_fn + "_fade_top.png") + layer_comp.alpha_composite(fade) + if os.path.isfile(fade_fn + "_fade_right.png") == True: + fade = Image.open(fade_fn + "_fade_right.png") + layer_comp.alpha_composite(fade) + if os.path.isfile(fade_fn + "_fade_bottom.png") == True: + fade = Image.open(fade_fn + "_fade_bottom.png") + layer_comp.alpha_composite(fade) + if os.path.isfile(fade_fn + "_fade_left.png") == True: + fade = Image.open(fade_fn + "_fade_left.png") + layer_comp.alpha_composite(fade) + mstr_msg("layergen", "Adjacent fading completed") + + # Store layer if self._is_completion == False: 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" ) @@ -805,6 +828,7 @@ class mstr_layergen: if self._tag == "waterway" and (self._value == "river" or self._value == "stream"): layer_comp = layer_comp.filter(ImageFilter.GaussianBlur(radius=4)) + # Store layer 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.") @@ -823,3 +847,146 @@ class mstr_layergen: nrm = mstr_xp_normalmap(self._latitude, self._longitude, self._tag, self._value, self._lat_number, self._lng_number, self._latlngfld) nrm.build_normalmap() + + # Should we find more than one source, the first one found will take precedence. + # For the others, we will need to generate fading images, so that the final layer + # image works with other tiles + def generate_adjacent_fades(self): + adj_sources = self.find_all_adjacent_sources() + precedence = -1 + + # Be prepared for every border + brd_t = Image.open(mstr_datafolder + "textures/multi_source/brd_t.png") + brd_r = Image.open(mstr_datafolder + "textures/multi_source/brd_r.png") + brd_b = Image.open(mstr_datafolder + "textures/multi_source/brd_b.png") + brd_l = Image.open(mstr_datafolder + "textures/multi_source/brd_l.png") + + brd_t_pix = brd_t.load() + brd_r_pix = brd_r.load() + brd_b_pix = brd_b.load() + brd_l_pix = brd_l.load() + + for s in range(0, 4): + if adj_sources[s] != -1: + precedence = adj_sources[s] + break + + # Generate required images + # Basically a shortened version of the main layergen call + for s in range(0, 4): + if adj_sources[s] != precedence and adj_sources[s] != -1: + src = adj_sources[s] + + adj_image = Image.new("RGBA", (self._imgsize, self._imgsize)) + adj_pix = adj_image.load() + + # Root folder + root_folder = mstr_datafolder + "textures/" + self._tag + "/" + self._value + + # Load in the sources to work with + ptc = glob.glob(root_folder + "/ptc/b" + str(src) + "_p*.png") + brd_src = Image.open(root_folder + "/brd/b" + str(src) + ".png") + ptc_src = [] + for p in ptc: + ptc_src.append(Image.open(p)) + + osm_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" ) + + for i in mstr_mask_blur: + if i[0] == self._tag and i[1] == self._value: + if self._tag != "place" and (self._value != "sea" or self._value != "ocean"): + osm_mask = osm_mask.filter(ImageFilter.BoxBlur(radius=i[2])) + break + mask_pix = osm_mask.load() + + # Begin producing a largely random image + samples = 250 # <- We need this in a moment + for i in range(samples): + imgid = 0 + if len(ptc_src) == 1: imgid = 0 + if len(ptc_src) >= 2: + imgid = randrange(1, len(ptc_src)+1) - 1 + l = 0 - int(ptc_src[imgid].width / 2) + r = adj_image.width - int(ptc_src[imgid].width / 2) + t = 0 - int(ptc_src[imgid].height / 2) + b = adj_image.height - int(ptc_src[imgid].height / 2) + adj_image.alpha_composite( ptc_src[imgid], ( randrange(l, r), randrange(t, b) ) ) + + adj_image.alpha_composite( brd_src ) + + for y in range(self._imgsize): + for x in range(self._imgsize): + if mask_pix[x, y][3] > 0: + rgb=adj_pix[x,y] + a=mask_pix[x,y] + adj_pix[x, y] = ( rgb[0], rgb[1], rgb[2], a[3]) + + # Up until here we mimiced the exact same behavior as layergen. However, now + # we need to adjust the alpha to make this layer fade. + # Then, we save the image + if s == 0: + for y in range(self._imgsize): + for x in range(self._imgsize): + fade_a = brd_t_pix[0, y] + if mask_pix[x, y][3] > 0: + c = adj_pix[x,y] + adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3]) + else: + adj_pix[x,y] = (0,0,0,0) + 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") + + if s == 1: + for y in range(self._imgsize): + for x in range(self._imgsize): + fade_a = brd_r_pix[x, 0] + if mask_pix[x, y][3] > 0: + c = adj_pix[x,y] + adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3]) + else: + adj_pix[x,y] = (0,0,0,0) + 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") + + if s == 2: + for y in range(self._imgsize): + for x in range(self._imgsize): + fade_a = brd_b_pix[0, y] + if mask_pix[x, y][3] > 0: + c = adj_pix[x,y] + adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3]) + else: + adj_pix[x,y] = (0,0,0,0) + 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") + + if s == 3: + for y in range(self._imgsize): + for x in range(self._imgsize): + fade_a = brd_l_pix[x, 0] + if mask_pix[x, y][3] > 0: + c = adj_pix[x,y] + adj_pix[x,y] = (c[0], c[1], c[2], fade_a[3]) + else: + adj_pix[x,y] = (0,0,0,0) + 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") + + + def find_all_adjacent_sources(self): + # Sources for this tag and value - top, right, bottom, left + sources = [-1,-1,-1,-1] + + # Perform query for each neighboring tile + src_top = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number+1, self._lng_number, self._tag, self._value) + src_rgt = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number, self._lng_number+1, self._tag, self._value) + src_btm = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number-1, self._lng_number, self._tag, self._value) + src_lft = self._tileinfo.get_adjacency_for_tag_and_value(self._lat_number, self._lng_number-1, self._tag, self._value) + + if len(src_top) == 2: + if "b" in src_top[1]: sources[0] = src_top[0] + if len(src_rgt) == 2: + if "l" in src_rgt[1]: sources[1] = src_rgt[0] + if len(src_btm) == 2: + if "t" in src_btm[1]: sources[2] = src_btm[0] + if len(src_lft) == 2: + if "r" in src_lft[1]: sources[3] = src_lft[0] + + # Report our findings + return sources diff --git a/textures/multi_source/brd_b.png b/textures/multi_source/brd_b.png new file mode 100644 index 0000000000000000000000000000000000000000..c28c1e17231868eaf1f6690ca5cb8982d424dbc5 GIT binary patch literal 1001 zcmVEX>4Tx04R}tkv&MmKpe$iQ>7{uK|6?a$WWc^;0NMZt5Adrp;l;vxAeOiZLMN=c5CXT3@PWeK{ zW0mt3XRTai&3p0}26Ot#GS_K_k-#FBAVGwJDoQBBMwC{a6bmWZk9Y8oxPFOT3b{&P z#tGnm2Cnp$zfuQgKS{5( zw8#-Kunk;Xw=`uBxZDATpA6ZQUCB>V$mfCgGy0}1Fmwy_t$DpQ_i_3Fq^Yaq4RCM> zj1?$*y~DeE+I#!=OtZfq`=N5(W|IJt00006VoOIv07U>r03*F-QXc>S010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=m{JWG!9}c5cdE802y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00F^CL_t(&-tAbycEcbHll=extR31lB{7Z-*=5hVl_X%W zkmUl6Mx)VaG#ZUYqtR$I8jVKdKZ7C0pS#*DXGy*cM zWZ^`|#Y=)u7&Q53%5YnWybY83G1qyOAV~5(!eM8M*#uzP*S~{sU$JcK+I0(W+SV`o zlz$qpLBKx}Fv(qL%9qr^4q4!uSeAr#7T+s*2~psz@Rfp`@=xW$TrWUjknW9&z940g z>Le`XT+XQ-id4zlyb3My>JKjaof2BOg?KE!h@Q%qTu{O(ploL>U;Kkg7Z-X<*8O@e zu~v!U7va1~s0s=Rg9OLjj8jcDVqO9l-EiOzuL6oS7tXQ?+~Gm^az=c$))sK1CF64% zR=-=%?Dtf$6T&FJ#N4%!8(rY5)#7tq@AuQe!|5t`uAO0~>%Dc-bz<(c6cY|z+CGJX zlC7K`&8iNn=3X;@xU3}a%K>c6w_Xe**Z1ZwLZi-m7VClkkyeD~h&kpJl7-$~4FL25 X8fKC8$`L6K00000NkvXXu0mjfkaNQh literal 0 HcmV?d00001 diff --git a/textures/multi_source/brd_l.png b/textures/multi_source/brd_l.png new file mode 100644 index 0000000000000000000000000000000000000000..7d0768d553022e168edca23b6127d94c5c2497e1 GIT binary patch literal 963 zcmV;!13dhRP)EX>4Tx04R}tkv&MmKpe$iQ>7{uK|6?a$WWc^;0NMZt5Adrp;l;vxAeOiZLMN=c5CXT3@PWeK{ zW0mt3XRTai&3p0}26Ot#GS_K_k-#FBAVGwJDoQBBMwC{a6bmWZk9Y8oxPFOT3b{&P z#tGnm2Cnp$zfuQgKS{5( zw8#-Kunk;Xw=`uBxZDATpA6ZQUCB>V$mfCgGy0}1Fmwy_t$DpQ_i_3Fq^Yaq4RCM> zj1?$*y~DeE+I#!=OtZfq`=N5(W|IJt00006VoOIv07U>r03*F-QXc>S010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=m{JWGYTpILMZ?M02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00EmxL_t(&-tAYxvV<@QBme);@(x-pN+IZ;-jJD{-P+nh zfY61A=SS(G0={(hMQ3fmNzWyN&B_wi*bKhY1C7L zF{u}K4~gytjBZ9bs@D~u)a#{~^AhyA>iOk%8&gc)49@JEX>4Tx04R}tkv&MmKpe$iQ>7{uK|6?a$WWc^;0NMZt5Adrp;l;vxAeOiZLMN=c5CXT3@PWeK{ zW0mt3XRTai&3p0}26Ot#GS_K_k-#FBAVGwJDoQBBMwC{a6bmWZk9Y8oxPFOT3b{&P z#tGnm2Cnp$zfuQgKS{5( zw8#-Kunk;Xw=`uBxZDATpA6ZQUCB>V$mfCgGy0}1Fmwy_t$DpQ_i_3Fq^Yaq4RCM> zj1?$*y~DeE+I#!=OtZfq`=N5(W|IJt00006VoOIv07U>r03*F-QXc>S010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=m{JWGy@!+Y)SwC02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00E&%L_t(&-tAXOf`c#&v*!PQ_8cHIix-*BZLCWh2*&Xu z8AzkiXfzs)Mx)VaG#ZWn0NlU2t#Mz2v3LJ(tbvb7bFbz$j`i+ez8BBQB3s$}vRE+j z+3m@fXH9Ygy$=q@o+fLVuED8~ET5l!5Qr}JF8kMY?>P<54~VGpal>Mfufb8wBcKT4 zC&_&*F+KfZ^Bd(Xx&OR$&#~#p>SCq;N6r@u)&5?6yK05)5i9>X)tZ_AyQmQOLUH1B zY7{tv;S}Tj5V-;^aSbe-%=lpCpVb7GGaVm}I<@x!DynP^F!|8!+@nv4_?o;~$?x|) z;`6|d;J415hv)ujsC1%oSUJBo>k`l z=lZ1Qy7v5`g^1?W literal 0 HcmV?d00001 diff --git a/textures/multi_source/brd_t.png b/textures/multi_source/brd_t.png new file mode 100644 index 0000000000000000000000000000000000000000..7436210fff4dc0f3b2ac0606cdc531eb6712f0c9 GIT binary patch literal 1005 zcmVEX>4Tx04R}tkv&MmKpe$iQ>7{uK|6?a$WWc^;0NMZt5Adrp;l;vxAeOiZLMN=c5CXT3@PWeK{ zW0mt3XRTai&3p0}26Ot#GS_K_k-#FBAVGwJDoQBBMwC{a6bmWZk9Y8oxPFOT3b{&P z#tGnm2Cnp$zfuQgKS{5( zw8#-Kunk;Xw=`uBxZDATpA6ZQUCB>V$mfCgGy0}1Fmwy_t$DpQ_i_3Fq^Yaq4RCM> zj1?$*y~DeE+I#!=OtZfq`=N5(W|IJt00006VoOIv07U>r03*F-QXc>S010qNS#tmY zE+YT{E+YYWr9XB6000McNliru=m{JWGc@aAUxEMt02y>eSad^gZEa<4bO1wgWnpw> zWFU8GbZ8()Nlj2!fese{00G5GL_t(&-tAY*wuB%IOZfk9ws$cq3|MHXv$>~Pc<_Pt zk){;@q+AEwhwc;)cUhFZ-6QuYr2wM7Z+=atwy4+Yipmb60HXPE*-QdO5Lt{oo1^9#U>0%{Pgxq1&RX4aE`;0GxMBHWvxB*4kYbTe#I1k__> z-?5i@Ykw{xf*0$$U!HHq@40%$8E)p_$zldOQ?E2XD|VuQ^7M_Jq&WDe4vTP$hyOVn zJKGspjC`?n;`TWLEaGZF6aIBJ+h?