Page 1 of 2

Pixa (was raster / shader project - insane?)

Posted: 15 Feb 2012 13:50
by andythenorth
I am considering using PIL (python image library) to procedurally generate trailers for trucks. Trailers are highly regular in shape, and drawing them to all lengths etc needed for BANDIT will be dull.

I have no experience in this, if I try to invent raster / shader from ground up, it's probably going to be bad.

Anyone interested in helping with this as an experiment?

I have two routes under consideration:

1. comping predefined blocks of pixels, e.g. trailer rear end, n * trailer middle part, trailer front end. This would build up trailers as though building with lego. This route requires component parts shaded for all 8 angles.

2. shading each face (truck trailers are quite regular), e.g floor, rear side, rear end, front side, front end. Pixels would be simply over-written where necessary. This route might be able to use transforms on the - view to generate other views procedurally.

My experience drawing graphics with code is limited to logo-style 'move cursor(delta_x, delta_y), draw(colour)'. Dunno if that's enough :P

Re: Raster / shader project - insane?

Posted: 15 Feb 2012 22:57
by andythenorth
Not insane. Works. More another time.

Re: Raster / shader project - insane?

Posted: 16 Feb 2012 22:18
by andythenorth
Trailer gets a floorplan drawn in false colour.

Pixel generator then sequences pixels to create trailer body.
Pixel sequence is determined by colours in floor plan + body type required.

Won't work at all for complex vehicles.
Will work well for vehicles with regular shapes (fairly certain this includes oval and cylindrical tankers as well as box shapes).
test_input.png
test_input.png (2.83 KiB) Viewed 6318 times
a_test_trailer.png
a_test_trailer.png (2.63 KiB) Viewed 6318 times
Code is pretty simple (this is non-optimised, non-configurable proof of concept):

Code: Select all

import Image
import ImageDraw
spritesheet = Image.open('test_input.png')
spritesheetpx = spritesheet.load()
draw = ImageDraw.Draw(spritesheet)
colours = {}
for x in range(spritesheet.size[0]):
  for y in range(spritesheet.size[1]):
    colour = spritesheetpx[x,y]
    if colour != 255 and colour != 0 and colour != 15:
      colours[colour] = ''
    if spritesheetpx[x,y] == 240:
      if x%2 == 0:
        body_colour = 10
        cc_colour = 200
      else:
        body_colour = 11
        cc_colour = 201
      draw.point([(x,y)],fill=body_colour)
      draw.point([(x,y-1)],fill=cc_colour)
      draw.point([(x,y-2)],fill=body_colour)
      draw.point([(x,y-3)],fill=body_colour)
      draw.point([(x,y-4)],fill=14)
    if spritesheetpx[x,y] == 238:
      if x%2 == 0:
        body_colour = 11
        cc_colour = 201
      else:
        body_colour = 12
        cc_colour = 202
      draw.point([(x,y)],fill=body_colour)
      draw.point([(x,y-1)],fill=cc_colour)
      draw.point([(x,y-2)],fill=body_colour)
      draw.point([(x,y-3)],fill=body_colour)
      draw.point([(x,y-4)],fill=14)
    if spritesheetpx[x,y] == 209:
      draw.point([(x,y)],fill=16)
      draw.point([(x,y-1)],fill=17)
      draw.point([(x,y-2)],fill=18)
      draw.point([(x,y-3)],fill=19)
      draw.point([(x,y-4)],fill=14)
spritesheet.save('a_test_trailer.png')
print colours

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 06:30
by andythenorth
Improved generator code; also a utility which will print out indexes for the palette used in a spritesheet.

Code: Select all

import Image
import ImageDraw
spritesheet = Image.open('test_input.png')
spritesheetpx = spritesheet.load()
draw = ImageDraw.Draw(spritesheet)

# global constants
body_colour = 10
cc_colour = 202

#each sequence is a tuple containing lists in format: [(x-offset,y-offset), colour]
pixel_sequences = dict (
    body_outer = ([(0, 0), body_colour], [(0, 1), cc_colour], [(0, 2), body_colour], [(0, 3), body_colour], [(0, 4), 14]),
    body_end   = ([(0, 0), body_colour], [(0, 1), cc_colour], [(0, 2), body_colour], [(0, 3), body_colour], [(0, 4), 14]),
    body_inner = ([(0, 0), 16], [(0, 1), 17], [(0, 2), 18], [(0, 3), 19], [(0, 4), 14]),
)

key_colour_mapping = {
    209 : dict(seq = 'body_inner', colour_shift= 0),
    238 : dict(seq = 'body_outer', colour_shift = 0),
    240 : dict(seq = 'body_end', colour_shift = -1),
}

def get_pixel_sequence(x, y, key_colour):
    key_map = key_colour_mapping[key_colour]
    raw_sequence = pixel_sequences[key_map['seq']]
    pixel_sequence = []
    for i in raw_sequence:
        pixel_sequence.append({
            'x' : x + i[0][0],
            'y' : y - i[0][1],
            'colour' : i[1] + key_map['colour_shift'],            
        })
    return pixel_sequence

colours = {} #used for debug
for x in range(spritesheet.size[0]):
  for y in range(spritesheet.size[1]):
    colour = spritesheetpx[x,y]
    if colour != 255 and colour != 0 and colour != 15:
      colours[colour] = ''
    if spritesheetpx[x,y] in key_colour_mapping.keys():
        seq = get_pixel_sequence(x, y, spritesheetpx[x,y])
        for i in seq:
            draw.point([(i['x'],i['y'])], fill=i['colour'])
            
spritesheet.save('a_test_trailer.png')

print colours # debug: what colours did we find in this spritesheet? 

Palette Utility

Code: Select all

import Image
import ImageDraw
import ImagePalette
spritesheet = Image.open('test_input.png')

block_size = 30
palette_key = Image.new('P',(16*block_size,16*block_size))
draw = ImageDraw.Draw(palette_key)

print spritesheet.mode

palette_key.putpalette(spritesheet.palette)
x = 0
y = 0
for i in range (256):
  draw.rectangle([(x,y),(x+block_size,y+block_size)],fill=i)
  bg_size = draw.textsize(str(i))
  text_pos = (x+(block_size/4),y+(block_size/3))
  draw.rectangle([(text_pos[0]-1,text_pos[1]+1),(text_pos[0]+bg_size[0],text_pos[1]+bg_size[1]-2)],fill=255)
  draw.text((x+(block_size/4),y+(block_size/3)),str(i),fill=1)
  x = x+block_size
  if x == 16*block_size:
    x = 0
    y = y + block_size

palette_key.save('palette_key.png')

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 06:59
by PikkaBird
Your ideas are intriguing to me and I wish to subscribe to your newsletter.

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 07:19
by andythenorth
I thought I'd better prove all angles work before going onto tanker bodies etc.

Here's a comp of the input (top row) and result (second row).

The magic colours in the trailer floor plan map to sequences of pixels. Each sequence contains colours and x / y offsets from starting pixel. Straight shapes offset in y direction only. I can do regular curved shapes by offsetting in x direction as well.

I'll also do loading/load sprites (for coal etc) by drawing the pattern on the floor pattern, then varying the length of the sequence.
For things like steel loads, I'm going to comp them on from pre-drawn images, using more magic pixels to set location.
result.png
result.png (5.29 KiB) Viewed 6274 times
Zoomed (for luck):
result_zoom.png
result_zoom.png (13.93 KiB) Viewed 6274 times

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 07:58
by FooBar
Interesting concept.
The only drawing-by-code I once did is a graph, via PHP using GD. But that appears to be more or less the same as how PIL works, so I can more or less follow what you're doing (apart from tuples and dicts, I'm only familiar with arrays, these appear overly complicated).

Now do one with cargo :D

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 08:53
by andythenorth
FooBar wrote:I can more or less follow what you're doing (apart from tuples and dicts, I'm only familiar with arrays
A little python-php translation then for you :D
List ~= array with ints as keys (0-based)
Tuple ~= array with ints as keys (0-based), but immutable (can't append, slice etc)
Dict ~= array
Now do one with cargo :D
Later I will.

I've no idea what this technique I'm using is called. I'm sure it exists in computer graphics lore.
It reminds of extruding a spline in CGI, but it differs quite a bit.
Also reminds me slightly of of building Doom levels in the wad editor, about 16 years ago :o

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 09:02
by FooBar
andythenorth wrote:A little python-php translation then for you :D
List ~= array with ints as keys (0-based)
Tuple ~= array with ints as keys (0-based), but immutable (can't append, slice etc)
Dict ~= array
Ah, thanks. I guess the fact that dict !== array makes that the other two actually have a use :)

As for what it's called? I guess it's some form of computer generated imagery.

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 20:38
by andythenorth
FooBar wrote:Now do one with cargo :D
;)

Re: Raster / shader project - insane?

Posted: 17 Feb 2012 23:23
by FooBar
very cool :)

if you keep the purple for the cargo, you can then use that as base for recolouring.

Re: Raster / shader project - insane?

Posted: 18 Feb 2012 06:37
by andythenorth
FooBar wrote:if you keep the purple for the cargo, you can then use that as base for recolouring.
I'll just generate pngs at compile time with the cargo colours needed ;)

Resulting grf will be a little larger than if recolour sprites were used, openttd (may) be fractionally faster due to not recolouring. Swings / roundabouts :)

Re: Raster / shader project - insane?

Posted: 18 Feb 2012 13:27
by andythenorth
Procedural buildings (quick test)

Re: Raster / shader project - insane?

Posted: 18 Feb 2012 13:31
by Lord Aro
Didn't Zephyris do something like that at some point?

Re: Raster / shader project - insane?

Posted: 18 Feb 2012 13:43
by andythenorth
Lord Aro wrote:Didn't Zephyris do something like that at some point?
Yes, same idea, different approach to implementation.

Re: Raster / shader project - insane?

Posted: 18 Feb 2012 13:56
by andythenorth
:)

Re: Raster / shader project - insane?

Posted: 19 Feb 2012 08:50
by andythenorth
Generation of load colours and load states is done.
A range of body colours can be generated.
The trailer length, number of wheels etc are controlled by the input png file that defines the floorplan.

Below are a few examples of output - the generator creates more than this, but it's not necessary to prove that by posting them all here :)

This can (obviously) be extended to other styles of body, e.g. flatbed, open etc

Re: Raster / shader project - insane?

Posted: 20 Feb 2012 21:47
by andythenorth
Tank trailer input file + result.
The extra set of wheels in the input file is used to generate separate pngs for A trailers and B trailers - the brown pixels are painted as tyres, or masked out with blue.
tanker_input.png
tanker_input.png (7.85 KiB) Viewed 5982 times
tank_trailers_2.png
tank_trailers_2.png (64.95 KiB) Viewed 5982 times

Re: Raster / shader project - insane?

Posted: 21 Feb 2012 07:19
by andythenorth
Tanker B-Train :)

Re: Raster / shader project - insane?

Posted: 21 Feb 2012 08:14
by FooBar
I'm quite surprised you can draw a tanker out of a single line of pixels!