Pixa (was raster / shader project - insane?)

Discussions about the technical aspects of graphics development, including NewGRF tools and utilities.

Moderator: Graphics Moderators

User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Pixa (was raster / shader project - insane?)

Post 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
Last edited by andythenorth on 02 Mar 2012 08:25, edited 1 time in total.
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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 6191 times
a_test_trailer.png
a_test_trailer.png (2.63 KiB) Viewed 6191 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
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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')
Attachments
DOS palette example - this palette is generated directly from the palette used by a specific sprite.
DOS palette example - this palette is generated directly from the palette used by a specific sprite.
palette_key.png (9.83 KiB) Viewed 6156 times
User avatar
PikkaBird
Graphics Moderator
Graphics Moderator
Posts: 5601
Joined: 13 Sep 2004 13:21
Location: The Moon

Re: Raster / shader project - insane?

Post by PikkaBird »

Your ideas are intriguing to me and I wish to subscribe to your newsletter.
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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 6147 times
Zoomed (for luck):
result_zoom.png
result_zoom.png (13.93 KiB) Viewed 6147 times
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Raster / shader project - insane?

Post 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
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Raster / shader project - insane?

Post 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.
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Raster / shader project - insane?

Post by FooBar »

very cool :)

if you keep the purple for the cargo, you can then use that as base for recolouring.
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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 :)
User avatar
Lord Aro
Tycoon
Tycoon
Posts: 2369
Joined: 25 Jun 2009 16:42
Location: Location, Location
Contact:

Re: Raster / shader project - insane?

Post by Lord Aro »

Didn't Zephyris do something like that at some point?
AroAI - A really feeble attempt at an AI

It is practically impossible to teach good programming to students that have had a prior exposure to BASIC: as potential programmers they are mentally mutilated beyond hope of regeneration. --Edsger Dijkstra
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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
Attachments
7_8_tipping_trailer_fifth_wheel_cc_1_COAL.png
7_8_tipping_trailer_fifth_wheel_cc_1_COAL.png (2.48 KiB) Viewed 5926 times
7_8_tipping_trailer_fifth_wheel_cc_2_COAL.png
7_8_tipping_trailer_fifth_wheel_cc_2_COAL.png (2.49 KiB) Viewed 5926 times
7_8_tipping_trailer_fifth_wheel_cc_1_GRAI.png
7_8_tipping_trailer_fifth_wheel_cc_1_GRAI.png (2.49 KiB) Viewed 5926 times
User avatar
andythenorth
Tycoon
Tycoon
Posts: 5656
Joined: 31 Mar 2007 14:23
Location: Lost in Music

Re: Raster / shader project - insane?

Post 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 5855 times
tank_trailers_2.png
tank_trailers_2.png (64.95 KiB) Viewed 5855 times
User avatar
FooBar
Tycoon
Tycoon
Posts: 6553
Joined: 21 May 2007 11:47
Location: The Netherlands
Contact:

Re: Raster / shader project - insane?

Post by FooBar »

I'm quite surprised you can draw a tanker out of a single line of pixels!
Post Reply

Return to “NewGRF Technical Discussions”

Who is online

Users browsing this forum: No registered users and 4 guests