]> icculus.org git repositories - divverent/nexuiz.git/blob - data/models/sprites/makespr32
use r_labelsprites DP feature for sprites; add script that generates the sprites
[divverent/nexuiz.git] / data / models / sprites / makespr32
1 #!/usr/bin/perl
2
3 use strict;
4 use warnings;
5 use Image::Magick;
6
7 # SPR32 file format:
8 #
9 #       dsprite_s =
10 #               int ident = "IDSP"
11 #               int version = 32
12 #               int type = {projection type enum}
13 #               float boundingradius
14 #               int width = width of largest frame
15 #               int height = height of largest frame
16 #               int numframes
17 #               float beamlength
18 #               int synctype = {ST_SYNC=0, ST_RAND=1}
19 #
20 #       Shared Setup:
21 #               for 1..numframes:
22 #                       int type = {SPR_SINGLE=0, SPR_GROUP=1}
23 #                       if type == SPR_GROUP:
24 #                               int numframes_thisgroup
25 #                               for 1..numframes_thisgroup:
26 #                                       float interval
27 #                       for 1..numframes_thisgroup:
28 #                               dspriteframe_s =
29 #                                       int origin_x
30 #                                       int origin_y
31 #                                       int width
32 #                                       int height
33 #                               width*height*4 bytes of image data, RGBA
34
35 my $magick = Image::Magick->new();
36
37 sub checkmagick($)
38 {
39         my ($e) = @_;
40         die $e if $e;
41         return $e;
42 }
43
44 sub writesprite($$)
45 {
46         my ($spritestruct, $filename) = @_;
47         open my $fh, '>', $filename;
48         binmode $fh;
49         syswrite $fh, "IDSP";
50         syswrite $fh, pack 'V', 32;
51         syswrite $fh, pack 'V', $spritestruct->{type};
52
53         my $radius_x = abs(abs($spritestruct->{x0}) > abs($spritestruct->{x1}) ? $spritestruct->{x0} : $spritestruct->{x1});
54         my $radius_y = abs(abs($spritestruct->{y0}) > abs($spritestruct->{y1}) ? $spritestruct->{y0} : $spritestruct->{y1});
55
56         syswrite $fh, pack 'f', sqrt($radius_x * $radius_x + $radius_y * $radius_y);
57         syswrite $fh, pack 'V', $spritestruct->{x1} - $spritestruct->{x0};
58         syswrite $fh, pack 'V', $spritestruct->{y1} - $spritestruct->{y0};
59         syswrite $fh, pack 'V', scalar @{$spritestruct->{groups}};
60         syswrite $fh, pack 'f', $spritestruct->{beamlength};
61         syswrite $fh, pack 'V', $spritestruct->{synctype};
62
63         for my $g(@{$spritestruct->{groups}})
64         {
65                 my $f = $g->{frames};
66                 if(@$f == 1)
67                 {
68                         # no group
69                         syswrite $fh, pack 'V', 0;
70                 }
71                 else
72                 {
73                         # group
74                         syswrite $fh, pack 'V', 1;
75                         syswrite $fh, pack 'V', scalar @$f;
76                         syswrite $fh, pack 'f', $_->{interval} for @$f;
77                 }
78                 for(@$f)
79                 {
80                         syswrite $fh, pack 'V', -$_->{orgx};
81                         syswrite $fh, pack 'V', $_->{orgy};
82                         syswrite $fh, pack 'V', $_->{width};
83                         syswrite $fh, pack 'V', $_->{height};
84                         syswrite $fh, $_->{data};
85                 }
86         }
87 }
88
89 sub spritestruct($$$)
90 {
91         my ($type, $beamlength, $synctype) = @_;
92         return {
93                 type => $type,
94                 beamlength => $beamlength,
95                 synctype => $synctype,
96                 x0 => 0,
97                 y0 => 0,
98                 x1 => 0,
99                 y1 => 0,
100                 groups => [
101                         #       {
102                         #               frames => [
103                         #                       {
104                         #                               width => ...,
105                         #                               height => ...,
106                         #                               orgx => ...,
107                         #                               orgy => ...,
108                         #                               data => ...,
109                         #                               interval => ...,
110                         #                       },
111                         #               ]
112                         #       },
113                 ],
114         };
115 }
116
117 sub spriteframe($$$$$)
118 {
119         my ($spritestruct, $imagefile, $orgx, $orgy, $interval) = @_;
120         checkmagick $magick->Read($imagefile);
121         my ($width, $height) = $magick->Get('columns', 'rows');
122         my $data = $magick->ImageToBlob(depth => 8, magick => 'RGBA');
123         die "Size mismatch"
124                 if length $data != 4 * $width * $height;
125         my $g = ($spritestruct->{groups}->[-1]);
126         push @{$g->{frames}}, my $s = {};
127         $s->{width} = $width;
128         $s->{orgx} = $orgx;
129         $s->{orgy} = $orgy;
130         $s->{width} = $width;
131         $s->{height} = $height;
132         $s->{data} = $data;
133         $s->{interval} = $interval;
134
135         my $x0 = 0 - $orgx;
136         my $y0 = 0 - $orgy;
137         my $x1 = $width - $orgx;
138         my $y1 = $height - $orgy;
139
140         $spritestruct->{x0} = $x0 if $width > $spritestruct->{x0};
141         $spritestruct->{y0} = $y0 if $width > $spritestruct->{y0};
142         $spritestruct->{x1} = $x1 if $width > $spritestruct->{x1};
143         $spritestruct->{y1} = $y1 if $width > $spritestruct->{y1};
144 }
145
146 sub spritegroup($)
147 {
148         my ($spritestruct) = @_;
149         push @{$spritestruct->{groups}}, my $g = {};
150 }
151
152 sub usage()
153 {
154         die <<EOF;
155 Usage: $0
156         -o outfile.spr
157         [-proj projectiontype]
158         [-beam beamlength]
159         [-rand]
160         [-group]
161                 -sprite filename.tga orgx orgy interval
162                 [-sprite filename.tga orgx orgy interval [...]]
163         [-group
164                 -sprite filename.tga orgx orgy interval
165                 [-sprite filename.tga orgx orgy interval [...]] [...]]
166 EOF
167 }
168
169 my $proj = 2; # SPR_VP_PARALLEL
170 my $beam = 0;
171 my $synctype = 0;
172 my $outfile = undef;
173
174 for(;;)
175 {
176         usage()
177                 unless @ARGV;
178         my $s = shift @ARGV;
179         if($s eq '-proj')
180         {
181                 $proj = shift @ARGV;
182         }
183         elsif($s eq '-beam')
184         {
185                 $beam = shift @ARGV;
186         }
187         elsif($s eq '-rand')
188         {
189                 $synctype = 1;
190         }
191         elsif($s eq '-o')
192         {
193                 $outfile = shift @ARGV;
194         }
195         elsif($s eq '-group')
196         {
197                 last;
198         }
199         elsif($s eq '-sprite')
200         {
201                 unshift @ARGV, $s;
202                 last;
203         }
204         else
205         {
206                 unshift @ARGV, $s;
207                 unshift @ARGV, '-sprite';
208                 last;
209         }
210 }
211
212 usage() unless defined $outfile;
213
214 my $spritestruct = spritestruct($proj, $beam, $synctype);
215 print "created sprite with projection $proj, beam length $beam, sync type $synctype\n";
216
217 spritegroup($spritestruct);
218 print "  created sprite group\n";
219
220 for(;;)
221 {
222         last
223                 unless @ARGV;
224         my $s = shift @ARGV;
225         if($s eq '-sprite')
226         {
227                 my ($filename, $orgx, $orgy, $interval) = splice @ARGV, 0, 4;
228                 usage() if not defined $interval;
229                 spriteframe($spritestruct, $filename, $orgx, $orgy, $interval);
230                 print "    created sprite frame $filename, origin at $orgx|$orgy, interval $interval\n";
231         }
232         elsif($s eq '-group')
233         {
234                 spritegroup($spritestruct);
235                 print "  created sprite group\n";
236         }
237         else
238         {
239                 my ($orgx, $orgy, $interval) = splice @ARGV, 0, 3;
240                 usage() if not defined $interval;
241                 spriteframe($spritestruct, $s, $orgx, $orgy, $interval);
242                 print "    created sprite frame $s, origin at $orgx|$orgy, interval $interval\n";
243         }
244 }
245
246 writesprite($spritestruct, $outfile);
247 print "written to $outfile\n";