#!/usr/bin/perl use strict; use warnings; use Image::Magick; # SPR32 file format: # # dsprite_s = # int ident = "IDSP" # int version = 32 # int type = {projection type enum} # float boundingradius # int width = width of largest frame # int height = height of largest frame # int numframes # float beamlength # int synctype = {ST_SYNC=0, ST_RAND=1} # # Shared Setup: # for 1..numframes: # int type = {SPR_SINGLE=0, SPR_GROUP=1} # if type == SPR_GROUP: # int numframes_thisgroup # for 1..numframes_thisgroup: # float interval # for 1..numframes_thisgroup: # dspriteframe_s = # int origin_x # int origin_y # int width # int height # width*height*4 bytes of image data, RGBA my $magick = Image::Magick->new(); sub checkmagick($) { my ($e) = @_; die $e if $e; return $e; } sub writesprite($$) { my ($spritestruct, $filename) = @_; open my $fh, '>', $filename; binmode $fh; syswrite $fh, "IDSP"; syswrite $fh, pack 'V', 32; syswrite $fh, pack 'V', $spritestruct->{type}; my $radius_x = abs(abs($spritestruct->{x0}) > abs($spritestruct->{x1}) ? $spritestruct->{x0} : $spritestruct->{x1}); my $radius_y = abs(abs($spritestruct->{y0}) > abs($spritestruct->{y1}) ? $spritestruct->{y0} : $spritestruct->{y1}); syswrite $fh, pack 'f', sqrt($radius_x * $radius_x + $radius_y * $radius_y); syswrite $fh, pack 'V', $spritestruct->{x1} - $spritestruct->{x0}; syswrite $fh, pack 'V', $spritestruct->{y1} - $spritestruct->{y0}; syswrite $fh, pack 'V', scalar @{$spritestruct->{groups}}; syswrite $fh, pack 'f', $spritestruct->{beamlength}; syswrite $fh, pack 'V', $spritestruct->{synctype}; for my $g(@{$spritestruct->{groups}}) { my $f = $g->{frames}; if(@$f == 1) { # no group syswrite $fh, pack 'V', 0; } else { # group syswrite $fh, pack 'V', 1; syswrite $fh, pack 'V', scalar @$f; syswrite $fh, pack 'f', $_->{interval} for @$f; } for(@$f) { syswrite $fh, pack 'V', $_->{orgx} - $_->{width}; syswrite $fh, pack 'V', $_->{orgy}; syswrite $fh, pack 'V', $_->{width}; syswrite $fh, pack 'V', $_->{height}; syswrite $fh, $_->{data}; } } } sub spritestruct($$$) { my ($type, $beamlength, $synctype) = @_; return { type => $type, beamlength => $beamlength, synctype => $synctype, x0 => 0, y0 => 0, x1 => 0, y1 => 0, groups => [ # { # frames => [ # { # width => ..., # height => ..., # orgx => ..., # orgy => ..., # data => ..., # interval => ..., # }, # ] # }, ], }; } sub spriteframe($$$$$) { my ($spritestruct, $imagefile, $orgx, $orgy, $interval) = @_; checkmagick $magick->Read($imagefile); my ($width, $height) = $magick->Get('columns', 'rows'); my $data = $magick->ImageToBlob(depth => 8, magick => 'RGBA'); @$magick = (); die "Size mismatch for $imagefile: @{[length $data]} is not @{[4 * $width * $height]}" if length $data != 4 * $width * $height; my $g = ($spritestruct->{groups}->[-1]); push @{$g->{frames}}, my $s = {}; $s->{width} = $width; $s->{orgx} = $orgx; $s->{orgy} = $orgy; $s->{width} = $width; $s->{height} = $height; $s->{data} = $data; $s->{interval} = $interval; my $x0 = 0 - $orgx; my $y0 = 0 - $orgy; my $x1 = $width - $orgx; my $y1 = $height - $orgy; $spritestruct->{x0} = $x0 if $width > $spritestruct->{x0}; $spritestruct->{y0} = $y0 if $width > $spritestruct->{y0}; $spritestruct->{x1} = $x1 if $width > $spritestruct->{x1}; $spritestruct->{y1} = $y1 if $width > $spritestruct->{y1}; } sub spritegroup($) { my ($spritestruct) = @_; push @{$spritestruct->{groups}}, my $g = {}; } sub usage() { die <