User:Dyne

From OpenSimulator

Jump to: navigation, search

I am posting this here for the time being; it will probably eventually be put somewhere else in the User Docs section.


Below is a python script that takes one or more images (usually greyscale terrain maps, large enough for multiple sims) and splits them into sim-sized tiles. The tiles will be inverted along the Y axis to match OpenSim's axes (you could do this from L3DT, but I find it nicer to have a correctly-oriented full map handy).

This basically does the same thing as script terrain load-tile, but since I wanted to use Bailiwick to fiddle with the channels of the sim, and it doesn't take multi-sim input files, I needed to do it a different way. Hopefully this will be useful.

Copy the script into your text editor and name the thing terrain-split.py (or whatever). Note that it requires that the Python Imaging Library be installed, or it won't work.

Usage

Assuming that your input is a 512x512 pixel image at the following path (relative to the where you invoke the script):

mysims/multisim.png

Then you'd run it like:

python terrain-split.py mysims/multisim.png

This will do one of two things, depending on the value of the __interactive__ variable (I haven't made that into a nice commandline switch yet). If it is 0, then the script will spit out these files (along with some text output):

  • mysims/multisim.0.1.png (the northwest piece)
  • mysims/multisim.1.1.png (the northeast piece)
  • mysims/multisim.0.0.png (the southwest piece)
  • mysims/multisim.1.0.png (the southeast piece)

The numbers there are intended to aid you in picking grid positions for those sims. You choose a grid position for the lower left/southwest sim ... say (1575, 634). Then, for each sim, just add those two numbers to the base grid X and Y respectively:

  • NW: 1575, 635
  • NE: 1576, 635
  • SW: 1575, 634
  • SE: 1576, 634

If the __interactive__ variable is set to 1, the script will be slightly nicer and ask you for the base grid coordinate (always for the sim in the lower left corner) and then the name of each sim as it processes it. If I used the same input file and base coordinates as above, and named the above sims "alice", "bob", "charles", and "dan", then it'd spit out these files:

  • mysims/alice.1575.635.png
  • mysims/bob.1576.635.png
  • mysims/charles.1575.634.png
  • mysims/dan.1576.634.png

The tilesize is defined in the script (256 pixels by default, to match the required size for a sim texture at present). The script will take images of arbitrary size (so you could use a 768x1024 input, which will produce 12 sims, in 3 rows and 4 columns), but any pixels along the right or bottom edges that aren't large enough to be a full tile will get ignored. You can also specify multiple input files, and it'll loop through them one by one.

I left the noninteractive mode in, just in case someone wanted to use this in a more automatic fashion.

This has not been fully tested, so there may well be stupid bugs.


Script

#!/usr/bin/python
'''This simple script takes the filename of an image that is a multiple of the tilesize (256 by default), and splits it into tiles of that size.

USAGE: python terrain-split.py infile1 [infile2 ... infileN]

Note that any extra pixels in the original image beyond an even multiple of the tilesize are ignored.
'''

__interactive__ = 1

import Image, ImageOps
import os.path, sys

tilesize=256

for infile in sys.argv[1:]:
	try:
		myimage = Image.open(infile)
		path, filename = os.path.split(infile)
		basename, extension = os.path.splitext(filename)
		(width,height) = myimage.size
		tileswide = width // tilesize
		tileshigh = height // tilesize
		twremain = width % tilesize  # leftover pixels
		thremain = height % tilesize  # leftover pixels

		print
		print "---------------------------------------------------------"
		print "Input file: " + infile
		print "Image dimensions: %s x %s pixels" % (width,height)
		print "Output: %s x %s tiles (%s files) of %s pixels square" % (tileswide, tileshigh, tileswide*tileshigh, tilesize)
		print "Pixels truncated: %s across, %s down" % (twremain, thremain)
		if __interactive__:
                        print
                        print "Note: Values in [brackets] are defaults."
                        print
                        xin = raw_input("What is the desired grid X coordinate of the lower-left sim [1000]? ")
                        if xin == "":
                                basegridX = 1000
                        else:
                                basegridX = int(xin)
                        yin = raw_input("What is the desired grid Y coordinate of the lower-left sim [1000]? ")
                        if yin == "":
                                basegridY = 1000
                        else:
                                basegridY = int(yin)
		for y in range(tileshigh):
                        print
			print "Tiling Row #%s" % str(y+1)
			for x in range(tileswide):
				# Compute the upper left corner
				xnew = x * tilesize
				ynew = y * tilesize
				yrelative = tileshigh-y-1

				# Decide how to name the file
				if __interactive__:  # the filename will be based on individual names and will include the actual grid coordinates
                                        nameprompt = "What is the name of the sim at row %s, column %s [%s]? " % (y+1, x+1, basename)
                                        simname = raw_input(nameprompt)
                                        if simname == "":
                                                simname = basename
        				newfile = simname + "." + str(x + basegridX) + "." + str(basegridY+yrelative) + extension
                                else:  # the filename of our output tile is based on the input file and includes relative positions
        				newfile = basename + "." + str(x) + "." + str(yrelative) + extension
        			outfile = os.path.join(path, newfile)
				
				# Create the tile
				# Flip the tile along the way (transpose) to account for inverted Y axis.
				borders = (xnew, ynew, xnew+tilesize, ynew+tilesize)
				tile = Image.new("RGB", (tilesize, tilesize))
				region = myimage.crop(borders).transpose(Image.FLIP_TOP_BOTTOM)
				tile.paste(region, (0,0) )

				# Attempt to save it				
				try:
					tile.save(outfile)
					print "Writing: File %s with coords %s - %s" % (outfile, (xnew,ynew), (xnew+tilesize-1, ynew+tilesize-1) )
				except IOError:
					print "Cannot open output file ", outfile
	except IOError:
		print "Cannot open file ", infile
	print "---------------------------------------------------------"
Personal tools
General
About This Wiki