If you're using these instructions now I have found something confusing. If I use the latest version of GE I get an error loading the PNG. If I use an older version (8.1.0) then I have no issues and it all works perfectly.
Something to be aware of
[FS19 Tutorial] increase the DensityHeighttypes/dumpable piles
-
- Posts: 11
- Joined: Thu Jul 29, 2021 3:29 pm
Re: [FS19 Tutorial] increase the DensityHeighttypes/dumpable piles
(similar post for multi-terrain angle here: viewtopic.php?f=895&t=140397&p=1415800#p1415800)
I wanted to convert Alien Jim's Spectacle Island for increased height types, but felt like it was a shame to lose the mess that he so thoughtfully scattered for us at the farm (or worse, have it be messed up textures without collisions...). I started digging into the bit-level meanings in the terrainHeightDetail_density map, and wrote a little script to preserve heaps on the ground when you increase the height types
Crudely, a pixel in the density map of a 31-type map has values
where the 5 bits labeled "A" encode which filltype is on the ground at a given pixel. The rest of the bits aren't really important to understand this process, but at least specify the pile height.
If we add one channel in groundHeightShader.xml and the map i3d file to move to 63 height types, and then load an fewer-channel png in giants editor, the data is read through our new bitmask
but since the data wasn't written in that format, the leftmost bit of our old "B" data is interpreted as part of "A", and "B" is interpreted with its original leading bit missing and the rest shifted. This causes materials to differ from pixel to pixel within what was once a uniform heap, piles change height or disappear, and collisions are lost due to nonsense data.
To preserve the original heap types, you can insert a processing step between using the GRLE converter and loading in giants editor. When adding a single height type channel, we convert the data format to
just appending an appropriate number of zeros to the original "A" data, and shifting B to the right (dropping some thankfully-unused bits off the end).
I wrote a quick python script to do this, and thought I'd share it in case anyone else might find it useful. I wrote it to be used from the command line in linux, but the update_pixel function should be easily adaptable to other workflows.
My testing went as far as loading Spectacle Island with
To be clear, you would use the grle converter as before, run this script on its output, and then copy this script's result into the mapDE or mapUS folder (all other steps still required). For maps with no starting heaps, there's no benefit to this extra processing step. But, hopefully others will find it useful for maps that do, or for trying to preserve their savegame.
I wanted to convert Alien Jim's Spectacle Island for increased height types, but felt like it was a shame to lose the mess that he so thoughtfully scattered for us at the farm (or worse, have it be messed up textures without collisions...). I started digging into the bit-level meanings in the terrainHeightDetail_density map, and wrote a little script to preserve heaps on the ground when you increase the height types
Crudely, a pixel in the density map of a 31-type map has values
Code: Select all
AAAAABBB|BBBBBBBB|BBBBBBBB
red |green |blue
If we add one channel in groundHeightShader.xml and the map i3d file to move to 63 height types, and then load an fewer-channel png in giants editor, the data is read through our new bitmask
Code: Select all
AAAAAABB|BBBBBBBB|BBBBBBBB
To preserve the original heap types, you can insert a processing step between using the GRLE converter and loading in giants editor. When adding a single height type channel, we convert the data format to
Code: Select all
AAAAA0BB|BBBBBBBB|BBBBBBBB
I wrote a quick python script to do this, and thought I'd share it in case anyone else might find it useful. I wrote it to be used from the command line in linux, but the update_pixel function should be easily adaptable to other workflows.
Code: Select all
#!/usr/bin/python3
import sys,argparse
from os.path import exists
from PIL import Image
def update_pixel(p,inchan,outchan):
if all(_p==0 for _p in p):
return p
pixel = p[0] + (256 * p[1]) + (65536 * p[2])
intypemask = 2**inchan - 1
outpixel = (
(pixel & intypemask) | #mask/preserve inchan-bits corresponding to the heap type
( (pixel & ~intypemask) << (outchan-inchan) ) ) #shift the rest to the left by the number of added height channels
return (outpixel % 256, outpixel // 256, outpixel // 65536)
def main(argv):
parser = argparse.ArgumentParser(description='Converts terrainDetailHeight density map between #types without heap type loss')
parser.add_argument('-i', '--inchannels', action='store', type=int, default=5, dest='inchannels', help='# height channels in input png. default=5-->31 heighttypes')
parser.add_argument('-o', '--outchannels', action='store', type=int, dest='outchannels', required=True, help='# height channels in output png. end heighttypes=2^n-1')
parser.add_argument('-I', '--inpng', action='store', dest='infile', required=True, help='input png (output from GRLE converter)')
parser.add_argument('-O', '--outpng', action='store', dest='outfile', required=True, help='file to write')
args = parser.parse_args()
print(args)
print("in channels:", args.inchannels)
print("out channels:", args.outchannels)
print("in file:", args.infile)
print("out file:", args.outfile)
addchannels = args.outchannels - args.inchannels
if not exists(args.infile):
print("in file missing")
sys.exit(1)
elif exists(args.outfile):
print("out file exists. won't overwrite")
sys.exit(1)
elif args.inchannels < 5:
print("inchannels invalid")
sys.exit(1)
elif addchannels == 0:
print("nothing to do")
sys.exit(0)
elif addchannels < 0:
print("inchannels > outchannels. why?")
sys.exit(1)
img = Image.open(args.infile)
pixels = list(img.getdata())
new_pixels = [update_pixel(p,args.inchannels,args.outchannels) for p in pixels]
img.putdata(new_pixels)
img.save(args.outfile)
if __name__ == "__main__":
main(sys.argv[1:])
- Seasons
- Straw Harvest
- MaizePlus
- MaizePlus Forage Extension
To be clear, you would use the grle converter as before, run this script on its output, and then copy this script's result into the mapDE or mapUS folder (all other steps still required). For maps with no starting heaps, there's no benefit to this extra processing step. But, hopefully others will find it useful for maps that do, or for trying to preserve their savegame.