Skip to content

Commit

Permalink
convert: Split SLPFrame/SLPFrame classes for faster conversion.
Browse files Browse the repository at this point in the history
  • Loading branch information
heinezen committed Sep 11, 2019
1 parent 420972c commit a3ec958
Show file tree
Hide file tree
Showing 8 changed files with 713 additions and 171 deletions.
2 changes: 1 addition & 1 deletion doc/convert/convert_single_file.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ The invocation could be:

SLPs in DRS archives (for older versions of Age of Empires 1, Age of Empires 2 and SWGB):
```
python3 -m openage convert-file ~/games/aoe2/Data/graphics.drs 326.slp /tmp/rofl.png
python3 -m openage convert-file --drs ~/games/aoe2/Data/graphics.drs 326.slp /tmp/rofl.png
```

Standalone SLPs (Age of Empires 1: DE and Age of Empires 2: HD):
Expand Down
14 changes: 9 additions & 5 deletions doc/media/slp-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ Length | Type | Description | Example
4 bytes | uint32 | Command table offset | 2464, 0x000009A0
4 bytes | uint32 | Outline table offset | 64, 0x00000040
4 bytes | uint32 | Palette offset (unused) | 0, 0x00000000
4 bytes | uint32 | Properties (likely unused) | 16, 0x00000010
4 bytes | uint32 | Properties | 16, 0x00000010
4 bytes | int32 | Width of image | 800, 0x00000320
4 bytes | int32 | Height of image | 600, 0x00000258
4 bytes | int32 | Centre of sprite (X coord) | 0, 0x00000000
Expand All @@ -92,12 +92,14 @@ Python format: `Struct("< I I I I i i i i")`
* `palette_offset` is apparently never used.
* `properties` is only used to indicate which palette for the image to use.
However, these seem to be the same, so can generally be ignored.
* 0x10 - "default game palette"
* 0x00 - "global color palette"
Up to HD, these seem to be the same, so can generally be ignored.
* 0x10 - "default game palette"
* 0x00 - "global color palette"
* In AoE1:DE `properties` stores the palette number in the second last 2 bytes
* 0x0009 - use `09_buildings_asian.pal`
* `hotspot_x` & `hotspot_y` tell the engine where the centre of the unit is.
One image of size `width`*`height` has `height` rows, of course.
One image of size `width * height` has `height` rows, of course.
### SLP Frame row edge
Expand Down Expand Up @@ -306,6 +308,8 @@ Command Name | Byte value | Pixel Count | Description
-------------------------|-------------------|----------------|------------
Lesser draw | `0bXXXXXX00` | `cmd_byte >> 2` | An array of length *Count* filled with 1-byte "shadow" values (see below)
Lesser skip | `0bXXXXXX01` | `cmd_byte >> 2` or next | *Count* transparent pixels should be drawn from the current position.
Greater draw | `0bXXXX0010` | `cmd_byte << 4 + next` | An array of length *Count* filled with 1-byte "shadow" values follows, 1 value per pixel.
Greater skip | `0bXXXX0011` | `cmd_byte << 4 + next` | *Count* transparent pixels should be drawn from the current position.
Fill | `0bXXXX0111` | `cmd_byte >> 4` or next | One palette index byte follows. This color should be drawn `pixel_count` times from the current position.
The "shadow" values have to be converted to an alpha mask by left shifting
Expand Down
22 changes: 11 additions & 11 deletions doc/media/smp-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ For examples of drawing commands, see the [Examples](#examples) section.

### Full command list

An `X` signifies that the bit can have any value. These bts are used for
An `X` signifies that the bit can have any value. These bits are used for
storing the length (pixel count) of the command.

The commands works slightly different for each frame type.
Expand All @@ -204,10 +204,10 @@ The commands works slightly different for each frame type.

Command Name | Byte value | Pixel Count | Description
-----------------|---------------|--------------------------|------------
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 4-byte SMP pixels follows (see [SMP Pixel](#smp-pixel))
Playercolor Draw | `0bXXXXXX10` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 4-byte SMP pixels follows (see [SMP Pixel](#smp-pixel))
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 4-byte SMP pixels follows (see [SMP Pixel](#smp-pixel))
Playercolor Draw | `0bXXXXXX10` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 4-byte SMP pixels follows (see [SMP Pixel](#smp-pixel))
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.

* When converting the main graphics, the alpha values from the palette are
apparently ignored by the game.
Expand All @@ -217,9 +217,9 @@ apparently ignored by the game.

Command Name | Byte value | Pixel Count | Description
-----------------|---------------|--------------------------|------------
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 1-byte alpha values follows.
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | An array of length `pixel_count * 4` bytes filled with 1-byte alpha values follows.
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.

* Shadow frames (frame type `0x04`) sometimes do not explicitely draw the last
pixel in a row. If that happens, the openage converter draws the last *Draw* command
Expand All @@ -230,9 +230,9 @@ again

Command Name | Byte value | Pixel Count | Description
-----------------|---------------|--------------------------|------------
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | *Count* player color pixels should be drawn from the current position.
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.
Skip | `0bXXXXXX00` | `(cmd_byte >> 2) + 1` | *Count* transparent pixels should be drawn from the current position.
Draw | `0bXXXXXX01` | `(cmd_byte >> 2) + 1` | *Count* player color pixels should be drawn from the current position.
End of Row | `0bXXXXXX11` | 0 | End of commands for this row. If more commands follow, they are for the next row.

* SMP files do ot specify a color from a palette. The openage converter always uses the
color from index 0 in the player color palette for these *Draw* commands.
Expand Down
2 changes: 2 additions & 0 deletions openage/convert/hardcoded/texture.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"""

# The maximum allowed texture dimension.
# TODO: Maximum allowed dimension needs to
# be determined by converter.
MAX_TEXTURE_DIMENSION = 32768

# Margin between subtextures in atlas to avoid texture bleeding.
Expand Down
26 changes: 15 additions & 11 deletions openage/convert/singlefile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,12 @@ def init_subparser(cli):
cli.add_argument("--drs", type=argparse.FileType('rb'),
help=("drs archive filename that contains an slp "
"e.g. path ~/games/aoe/graphics.drs"))
cli.add_argument("--mode",
help=("choose between DRS-SLP, SLP or SMP; "
cli.add_argument("--mode", choices=['drs-slp', 'slp', 'smp'],
help=("choose between drs-slp, slp or smp; "
"otherwise, this is determined by the file extension"))
cli.add_argument("filename", help=("filename "
"e.g. path ~/games/aoe/326.slp"))
cli.add_argument("filename", help=("filename or, if inside a drs archive "
"given by --drs, the filename within "
"the drs archive"))
cli.add_argument("output", help="image output path name")


Expand All @@ -48,23 +49,23 @@ def main(args, error):
del error # unused

file_path = Path(args.filename)
file_extension = file_path.suffix[1:].upper()
file_extension = file_path.suffix[1:].lower()

if args.mode == "SLP" or (file_extension == "SLP" and not args.drs):
if args.mode == "slp" or (file_extension == "slp" and not args.drs):
if not args.palette_file:
raise Exception("palette-file needs to be specified")

read_slp_file(args.filename, args.palette_file, args.output,
player_palette=args.player_palette_file)

elif args.mode == "DRS-SLP" or (file_extension == "SLP" and args.drs):
elif args.mode == "drs-slp" or (file_extension == "slp" and args.drs):
if not (args.drs and args.palette_index):
raise Exception("palette-file needs to be specified")

read_slp_in_drs_file(args.drs, args.filename, args.palette_index,
args.output, interfac=args.interfac)

elif args.mode == "SMP" or file_extension == "SMP":
elif args.mode == "smp" or file_extension == "smp":
if not (args.palette_file and args.player_palette_file):
raise Exception("palette-file needs to be specified")

Expand Down Expand Up @@ -142,11 +143,14 @@ def read_slp_in_drs_file(drs, slp_path, palette_index, output_path, interfac=Non

else:
# otherwise use the path of the drs.
interfac_file = Path(drs.name).with_name("interfac.drs").open("rb") # pylint: disable=no-member
interfac_file = Path(drs.name).with_name(
"interfac.drs").open("rb") # pylint: disable=no-member

# open palette
info("opening palette in drs '%s:%s.bina'...", interfac_file.name, palette_index)
palette_file = DRS(interfac_file).root["%s.bina" % palette_index].open("rb")
info("opening palette in drs '%s:%s.bina'...",
interfac_file.name, palette_index)
palette_file = DRS(
interfac_file).root["%s.bina" % palette_index].open("rb")

info("parsing palette data...")
palette = ColorTable(palette_file.read())
Expand Down
Loading

0 comments on commit a3ec958

Please sign in to comment.