File Coverage

blib/lib/SWF/Builder/Character.pm
Criterion Covered Total %
statement 109 220 49.5
branch 20 60 33.3
condition 4 16 25.0
subroutine 23 39 58.9
pod 0 3 0.0
total 156 338 46.1


line stmt bran cond sub pod time code
1             package SWF::Builder::Character;
2              
3 1     1   7 use strict;
  1         2  
  1         41  
4              
5 1     1   6 use Carp;
  1         2  
  1         85  
6 1     1   5 use SWF::Element;
  1         2  
  1         22  
7 1     1   5 use SWF::Builder::ExElement;
  1         2  
  1         53  
8 1     1   5 use SWF::Builder;
  1         2  
  1         606  
9              
10             our $VERSION = '0.03';
11              
12             sub _init_character {
13 4     4   11 my $self = shift;
14              
15 4         39 $self->{ID} = SWF::Element::ID->new;
16 4         122 $self->{_depends} = {};
17 4         11 $self->{_parent} = undef;
18 4         52 $self->{_root} = undef;
19 4         13 $self->{_export_name} = undef;
20             }
21              
22             sub name {
23 0     0 0 0 my ($self, $name) = @_;
24              
25 0 0       0 if (defined $name) {
26 0         0 my $rname = $name;
27 0 0       0 croak "Can't rename the character which has been already exported as '".$self->{_export_name}."'" if defined $self->{_export_name};
28 0         0 utf2bin($name);
29 0         0 $self->{_root}->_depends($self, 1);
30 0         0 $self->{_export_name} = $name;
31 0         0 return $rname;
32             } else {
33 0 0       0 unless (defined $self->{_export_name}) {
34 0 0       0 if ($self->{_root}{_auto_namer}) {
35 0         0 $name = join('', $self =~ /Character::([^:]+)::.+\(0x(.+)\)$/);
36 0         0 $self->{_root}{_names}{$name} = $self;
37 0         0 $self->{_root}->_depends($self, 1);
38 0         0 $self->{_export_name} = $name;
39             } else {
40 0         0 croak "Can't get the name of the character";
41             }
42             } else {
43 0         0 my $rname = $self->{_export_name};
44 0         0 bin2utf($rname);
45 0         0 return $rname;
46             }
47             }
48             }
49              
50             *export_asset = \&name;
51              
52             sub pack {
53 4     4 0 61 my ($self, $stream) = @_;
54              
55 4 50       17 return if $self->{ID}->defined;
56 4         26 for my $dep (values %{$self->{_depends}}) {
  4         16  
57 3 50       13 $dep->pack($stream) unless $dep->{ID}->defined;
58             }
59              
60 4 50       17 if ($self->{_root}) {
61 4         55 $self->{ID}->configure($self->get_ID);
62             } else {
63 0 0       0 croak "Character ID need to be initialized to pack" unless $self->{ID}->defined;
64             }
65              
66 4         95 $self->_pack($stream);
67              
68 4 50       29420 if (defined $self->{_export_name}) {
69 0         0 SWF::Element::Tag::ExportAssets->new
70             ( Assets => [[ ID => $self->{ID}, Name => $self->{_export_name}]]
71             )->pack($stream);
72             }
73             }
74              
75             sub get_ID {
76 4     4 0 23 shift->{_root}{_ID_seed}++;
77             }
78              
79             sub _depends {
80 3     3   6 my ($self, $char) = @_;
81              
82 3         17 $self->{_depends}{$char} = $char;
83             }
84              
85             sub _destroy {
86 4     4   8 %{+shift} = ();
  4         492  
87             }
88              
89             ####
90              
91             package SWF::Builder::Character::Displayable;
92              
93             @SWF::Builder::Character::Displayable::ISA = qw/SWF::Builder::Character/;
94              
95 1     1   5 use Carp;
  1         2  
  1         598  
96              
97             sub _search_sibling {
98 1     1   3 my ($parent, $ref) = @_;
99 1         9 my $p;
100              
101 1         5 while(exists $ref->{_parent}) {
102 1         3 $p = $ref->{_parent};
103 1 50       9 return $ref if $p eq $parent;
104 0         0 $ref = $p;
105             }
106 0         0 return undef;
107             }
108              
109             sub place {
110 3     3   25 my ($self, %param) = @_;
111              
112 3 50 33     41 my $parent = $param{MovieClip} || $param{MC} || $param{clip_with} || $self->{_parent} or croak "Can't get the movieclip to place";
113 3 50       30 if ($parent eq '_root') {
    50          
114 0         0 $parent = $self->{_root};
115             } elsif (ref($parent) eq 'SWF::Builder') {
116 0         0 $parent = $parent->{_root};
117             }
118 3 50       28 croak "The item can be placed only on the movie which defines it" if $parent->{_root} != $self->{_root};
119              
120 3   50     13 my $frame = $param{Frame} || 1;
121              
122 3         27 $parent->_depends($self, $frame);
123              
124 3         44 my $disp_i =
125             bless {
126             _parent => $parent,
127             _root => $self->{_root},
128             _first_frame => $frame,
129             _last_frame_offset
130             => 2**64,
131             _current_frame => $frame,
132             _obj => $self,
133             _tags => [],
134             }, 'SWF::Builder::DisplayInstance';
135              
136 3         6 push @{$self->{_root}{_to_destroy}}, $disp_i;
  3         10  
137              
138 3         4 my $depth;
139              
140 3 100       11 if (exists $param{below}) {
    50          
141 1 50       6 my $refitem = _search_sibling($parent, $param{below}) or croak "Can't place the item below what on the different movieclip";
142 1         11 $depth = SWF::Builder::Depth->new($disp_i, $refitem->{_depth}{_lower});
143             } elsif (exists $param{above}) {
144 0 0       0 my $refitem = _search_sibling($parent, $param{above}) or croak "Can't place the item above what on the different movieclip";
145 0         0 $depth = SWF::Builder::Depth->new($disp_i, $refitem->{_depth});
146             } else {
147 2         17 $depth = SWF::Builder::Depth->new($disp_i, $parent->{_depth_list}{_lower});
148             }
149              
150 3         15 $disp_i->{_depth} = $depth;
151 3         12 $disp_i->frame($frame);
152 3         4 $disp_i->{_current_frame} = $frame;
153 3         22 $disp_i;
154             }
155              
156             ####
157              
158             package SWF::Builder::Character::UsableAsMask;
159              
160             @SWF::Builder::Character::UsableAsMask::ISA = qw/SWF::Builder::Character::Displayable/;
161              
162             sub place_as_mask {
163 0     0   0 my $self = shift;
164              
165 0         0 my $disp_i = $self->place(@_);
166 0         0 bless $disp_i, 'SWF::Builder::MaskInstance';
167 0         0 bless $disp_i->{_depth}, 'SWF::Builder::MaskDepth';
168 0         0 $disp_i->{_clipdepth} = SWF::Element::Depth->new(0);
169 0         0 $disp_i->{_frame_list} = $disp_i->{_parent}{_frame_list};
170 0         0 $disp_i->{_depth_list} = SWF::Builder::Depth->new($disp_i);
171 0         0 $disp_i->{_depends} = {};
172 0         0 $disp_i->frame($disp_i->{_first_frame});
173 0         0 $disp_i->{_current_frame} = $disp_i->{_first_frame};
174 0         0 $disp_i;
175             }
176              
177              
178             ####
179              
180             package SWF::Builder::Character::Imported;
181              
182             @SWF::Builder::Character::Imported::ISA = qw/SWF::Builder::Character/;
183              
184 1     1   5 use Carp;
  1         2  
  1         193  
185              
186             sub new {
187 0     0   0 my ($class, $url, $name, $type) = @_;
188              
189 0   0     0 $type ||= 'MovieClip';
190 0         0 $class = "SWF::Builder::Character::${type}::Imported";
191              
192 0         0 my $self = bless {
193             _url => $url,
194             _name => $name,
195             }, $class;
196              
197 0         0 eval "require SWF::Builder::Character::$type";
198 0 0       0 croak "Can't import character type '$type'" unless UNIVERSAL::can($class, '_init_character');
199 0         0 $self->_init_character;
200 0         0 $self;
201             }
202              
203             sub _pack {
204 0     0   0 my ($self, $stream) = @_;
205              
206 0         0 SWF::Element::Tag::ImportAssets->new
207             ( URL => $self->{_url},
208             Assets => [[ID => $self->{ID}, Name => $self->{_name}]]
209             )->pack($stream);
210              
211             }
212              
213             ####
214              
215             package SWF::Builder::DisplayInstance;
216              
217 1     1   4 use Carp;
  1         1  
  1         39  
218 1     1   5 use SWF::Builder::ExElement;
  1         2  
  1         620  
219              
220             sub frame {
221 6     6   10 my ($self, $frame) = @_;
222 6         17 my $frametag;
223              
224 6         12 my $frame_offset = $frame - $self->{_first_frame};
225              
226 6 100       19 unless (defined($self->{_tags}[$frame_offset])) {
227 3 50 33     46 croak "The frame $frame is out of range" if $frame_offset < 0 or $frame_offset >= $self->{_last_frame_offset};
228 3         37 $frametag = bless {
229             _parent => $self,
230             _frame_offset => $frame_offset,
231             _tag =>
232             SWF::Element::Tag::PlaceObject2->new
233             ( Depth => $self->{_depth}{_depth} ),
234             }, 'SWF::Builder::DisplayInstance::Frame';
235 3         201 $self->{_tags}[$frame_offset] = $frametag;
236 3         5 push @{$self->{_parent}{_frame_list}[$frame-1]}, $frametag;
  3         12  
237 3 50       11 if ($frame_offset == 0) {
238 3         18 $frametag->{_tag}->CharacterID($self->{_obj}{ID});
239             } else {
240 0         0 $frametag->{_tag}->PlaceFlagMove(1);
241             }
242             } else {
243 3         5 $frametag = $self->{_tags}[$frame_offset];
244             }
245 6         35 $self->{_current_frame} = $frame+1;
246 6         18 $frametag;
247             }
248              
249             sub name {
250 0     0   0 my ($self, $name) = @_;
251 0         0 my $tag = $self->{_tags}[0]{_tag};
252 0 0       0 if (defined $name) {
253 0         0 my $rname = $name;
254 0 0       0 croak "Can't rename the display instance, which is already named as '".$self->Name."'" if $tag->Name->defined;
255 0         0 utf2bin($name);
256 0         0 $tag->Name($name);
257 0         0 return $rname;
258             } else {
259 0 0       0 unless ($tag->Name->defined) {
260 0 0       0 if ($self->{_root}{_auto_namer}) {
261 0         0 ($name) = ($self =~ /\(0x(.+)\)$/);
262 0         0 $name = "DI$name";
263 0         0 $self->{_root}{_names}{$name} = $self;
264 0         0 $tag->Name($name);
265             } else {
266 0         0 croak "Can't get the name of the display instance";
267             }
268             } else {
269 0         0 my $rname = $tag->Name;
270 0         0 bin2utf($rname);
271 0         0 return $rname;
272             }
273             }
274             }
275              
276             sub AUTOLOAD {
277 3     3   125 my $self = shift;
278 3         6 my ($name, $class);
279 3         6 my $sub = $SWF::Builder::DisplayInstance::AUTOLOAD;
280              
281 3 50       19 return if $sub =~/::DESTROY$/;
282 3         16 $sub =~ s/.+:://;
283 3 50       36 croak "Can't locate object method \"$sub\" via package \"".ref($self).'" (perhaps you forgot to load "'.ref($self).'"?)' unless SWF::Builder::DisplayInstance::Frame->can($sub);
284 3         17 $self->frame($self->{_current_frame})->$sub(@_);
285             }
286              
287             sub _destroy {
288 3     3   5 %{+shift} = ();
  3         60  
289             }
290             ####
291              
292             package SWF::Builder::DisplayInstance::Frame;
293              
294 1     1   6 use Carp;
  1         2  
  1         777  
295              
296             sub scale {
297 0     0   0 my $self = shift;
298              
299 0         0 $self->matrix->scale(@_);
300 0         0 $self;
301             }
302              
303             sub moveto {
304 3     3   14 my $self = shift;
305 3         9 $self->matrix->moveto($_[0]*20, $_[1]*20);
306 3         55 $self;
307             }
308              
309             sub r_moveto {
310 0     0   0 my ($self, $to_rx, $to_ry) = @_;
311              
312 0         0 my $m = $self->matrix;
313 0         0 $m->moveto($m->TranslateX + $to_rx*20, $m->TranslateY + $to_ry*20);
314 0         0 $self;
315             }
316              
317             sub rotate {
318 0     0   0 my ($self, $r) = @_;
319              
320 0         0 $self->matrix->rotate($r);
321 0         0 $self;
322             }
323              
324             sub reset {
325 0     0   0 my $self = shift;
326 0         0 my $m = $self->matrix;
327 0         0 $m->ScaleX(1);
328 0         0 $m->ScaleY(1);
329 0         0 $m->RotateSkew0(0);
330 0         0 $m->RotateSkew1(0);
331 0         0 $self;
332             }
333              
334             sub remove {
335 0     0   0 my $self = shift;
336 0         0 my $parent = $self->{_parent};
337              
338 0 0       0 croak "This DisplayInstance has already set to remove " if ($parent->{_last_frame_offset} < 2**64);
339              
340 0         0 $self->{_tag} = SWF::Element::Tag::RemoveObject2->new( Depth => $parent->{_depth}{_depth} );
341 0         0 $parent->{_last_frame_offset} = $self->{_frame_offset};
342 0         0 $self;
343             }
344              
345             sub frame_action {
346 0     0   0 my $self = shift;
347              
348 0         0 $self->{_parent}{_parent}->frame_action($self->{_parent}{_first_frame}+$self->{_frame_offset});
349             }
350              
351             sub frame_label {
352 0     0   0 my $self = shift;
353              
354 0         0 $self->{_parent}{_parent}->frame_label($self->{_parent}{_first_frame}+$self->{_frame_offset}, @_);
355             }
356              
357             sub ratio {
358 0     0   0 my ($self, $ratio) = @_;
359 0         0 $self->{_tag}->Ratio($ratio);
360 0         0 $self;
361             }
362              
363             sub matrix {
364 3     3   5 my $self = shift;
365 3         7 my $tag = $self->{_tag};
366              
367 3 50       12 unless ($tag->Matrix->defined) {
368 3         186 my $ptags = $self->{_parent}{_tags};
369 3         6 my $frame_offset = $self->{_frame_offset};
370 3   0     9 $frame_offset-- until ($frame_offset == 0 or defined $ptags->[$frame_offset] and $ptags->[$frame_offset]{_tag}->Matrix->defined);
      33        
371 3         11 $tag->Matrix($ptags->[$frame_offset]{_tag}->Matrix->clone);
372             }
373 3         436 $tag->Matrix;
374             }
375              
376             sub pack {
377 3     3   6 my ($self, $stream) = @_;
378              
379 3         22 $self->{_tag}->pack($stream);
380             }
381              
382             ####
383              
384             package SWF::Builder::MaskInstance;
385              
386             @SWF::Builder::MaskInstance::ISA = qw/ SWF::Builder::DisplayInstance /;
387              
388             sub _depends {
389 0     0     my $self = shift;
390              
391 0           $self->{_parent}->_depends(@_);
392             }
393              
394             sub frame {
395 0     0     my $self = shift;
396              
397 0           my $frametag = $self->SUPER::frame(@_);
398 0           $frametag->{_tag}->ClipDepth($self->{_clipdepth});
399 0           $frametag;
400             }
401              
402             #####
403              
404             package SWF::Builder::MaskDepth;
405              
406             @SWF::Builder::MaskDepth::ISA = qw/ SWF::Builder::Depth /;
407              
408             sub set_depth {
409 0     0     my ($self, $n) = @_;
410              
411 0           $self->{_depth}->configure($n++);
412 0           my $depth_list = $self->{_parent}{_depth_list};
413 0           my $depth = $depth_list->{_upper};
414 0           while ($depth != $depth_list) {
415 0           $n = $depth->set_depth($n);
416 0           $depth = $depth->{_upper};
417             }
418 0           $self->{_parent}{_clipdepth}->configure($n-1);
419 0           $n;
420             }
421              
422              
423             1;