Source code: com/anotherbigidea/flash/movie/Shape.java
1 /****************************************************************
2 * Copyright (c) 2001, David N. Main, All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the
6 * following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 *
17 * 3. The name of the author may not be used to endorse or
18 * promote products derived from this software without specific
19 * prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
32 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 ****************************************************************/
34 package com.anotherbigidea.flash.movie;
35
36 import java.io.*;
37 import java.util.*;
38 import com.anotherbigidea.flash.interfaces.*;
39 import com.anotherbigidea.flash.writers.*;
40 import com.anotherbigidea.flash.readers.*;
41 import com.anotherbigidea.flash.structs.*;
42 import com.anotherbigidea.flash.SWFConstants;
43
44 /**
45 * A Shape Symbol
46 */
47 public class Shape extends Symbol
48 {
49 public abstract static class Element {}
50
51 public abstract static class Style extends Shape.Element
52 {
53 }
54
55 public abstract static class FillStyle extends Shape.Style
56 {
57 }
58
59 public static class ColorFill extends Shape.FillStyle
60 {
61 protected Color color;
62
63 /**
64 * @return may be Color or AlphaColor
65 */
66 public Color getColor() { return color; }
67 public void setColor( Color color ) { this.color = color; }
68
69 public ColorFill( Color color )
70 {
71 this.color = color;
72 }
73 }
74
75 public static class ImageFill extends Shape.FillStyle
76 {
77 protected Symbol image;
78 protected Transform matrix;
79 protected boolean clipped;
80
81 public Symbol getImage() { return image; }
82 public Transform getTransform() { return matrix; }
83 public boolean isClipped() { return clipped; }
84
85 public void setImage( Symbol image ) { this.image = image; }
86 public void setTransform( Transform matrix ) { this.matrix = matrix; }
87 public void setClipped( boolean isClipped ) { clipped = isClipped; }
88
89 public ImageFill( Symbol image, Transform matrix, boolean isClipped )
90 {
91 this.image = image;
92 this.matrix = matrix;
93 this.clipped = isClipped;
94 }
95 }
96
97 public static class GradientFill extends Shape.FillStyle
98 {
99 protected Color[] colors;
100 protected int[] ratios;
101 protected Transform matrix;
102 protected boolean radial;
103
104 public Color[] getColors() { return colors; }
105 public Transform getTransform() { return matrix; }
106 public int[] getRatios() { return ratios; }
107 public boolean isRadial() { return radial; }
108
109 public void setColors( Color[] colors ) { this.colors = colors; }
110 public void setRatios( int[] ratios ) { this.ratios = ratios; }
111 public void setTransform( Transform matrix ) { this.matrix = matrix; }
112 public void setRadial( boolean isRadial ) { this.radial = isRadial; }
113
114 public GradientFill( Color[] colors, int[] ratios,
115 Transform matrix, boolean isRadial )
116 {
117 this.colors = colors;
118 this.matrix = matrix;
119 this.radial = isRadial;
120 this.ratios = ratios;
121 }
122 }
123
124 public static class LineStyle extends Shape.Style
125 {
126 protected double width;
127 protected Color color;
128
129 public double getWidth() { return width; }
130 public Color getColor() { return color; }
131
132 public void setWidth( double width ) { this.width = width; }
133 public void setColor( Color color ) { this.color = color; }
134
135 public LineStyle( double width, Color color )
136 {
137 this.width = width;
138 this.color = color;
139 }
140 }
141
142 public abstract static class SetStyle extends Shape.Element
143 {
144 protected int index;
145
146 public int getStyleIndex() { return index; }
147 public void setStyleIndex( int index ) { this.index = index; }
148
149 protected SetStyle( int index )
150 {
151 this.index = index;
152 }
153 }
154
155 public abstract static class SetFillStyle extends Shape.SetStyle
156 {
157 protected SetFillStyle( int index )
158 {
159 super( index );
160 }
161 }
162
163 public static class SetLeftFillStyle extends Shape.SetFillStyle
164 {
165 public SetLeftFillStyle( int index )
166 {
167 super( index );
168 }
169 }
170
171 public static class SetRightFillStyle extends Shape.SetFillStyle
172 {
173 public SetRightFillStyle( int index )
174 {
175 super( index );
176 }
177 }
178
179 public static class SetLineStyle extends Shape.SetStyle
180 {
181 public SetLineStyle( int index )
182 {
183 super( index );
184 }
185 }
186
187 public abstract static class Vector extends Shape.Element
188 {
189 protected double x, y;
190
191 public double getX() { return x; }
192 public double getY() { return y; }
193
194 public void setX( double x ) { this.x = x; }
195 public void setY( double y ) { this.y = y; }
196
197 protected Vector( double x, double y )
198 {
199 this.x = x;
200 this.y = y;
201 }
202 }
203
204 public static class Move extends Shape.Vector
205 {
206 public Move( double x, double y )
207 {
208 super( x, y );
209 }
210 }
211
212 public static class Line extends Shape.Vector
213 {
214 public Line( double x, double y )
215 {
216 super( x, y );
217 }
218 }
219
220 public static class Curve extends Shape.Vector
221 {
222 protected double cx, cy;
223
224 public double getControlX() { return cx; }
225 public double getControlY() { return cy; }
226
227 public void setControlX( double cx ) { this.cx = cx; }
228 public void setControlY( double cy ) { this.cy = cy; }
229
230 public Curve( double x, double y, double controlX, double controlY )
231 {
232 super( x, y );
233 this.cx = controlX;
234 this.cy = controlY;
235 }
236 }
237
238 protected ArrayList elements = new ArrayList();
239 protected double minX, maxX, minY, maxY; //bounding rectangle
240 protected boolean hasAlpha = false;
241 protected double maxLineWidth;
242 protected double currx, curry;
243
244 public Shape() {}
245
246 /**
247 * Get the bounding rectangle as a double[4] - (min-X,min-Y,max-X,max-Y)
248 */
249 public double[] getBoundingRectangle()
250 {
251 return new double[] { minX, minY, maxX, maxY };
252 }
253
254 /**
255 * Set the bounding rectangle. This will be automatically calculated
256 * as the geometry vectors are defined and this rectangle will be enlarged
257 * if it does not contain all the vectors.
258 */
259 public void setBoundingRectangle( double minx, double minY,
260 double maxX, double maxY )
261 {
262 this.minX = minX;
263 this.minY = minY;
264 this.maxX = maxX;
265 this.maxY = maxY;
266 }
267
268 /**
269 * Access the list of shape elements
270 * Each object is a subclass of Shape.Element
271 */
272 public ArrayList getShapeElements()
273 {
274 return elements;
275 }
276
277 /**
278 * Define a line style
279 * @param color if null then black is assumed
280 */
281 public void defineLineStyle( double width, Color color )
282 {
283 if( color == null ) color = new Color(0,0,0);
284
285 LineStyle style = new LineStyle( width, color );
286
287 if( maxLineWidth < width ) maxLineWidth = width;
288
289 if( color instanceof AlphaColor ) hasAlpha = true;
290
291 elements.add( style );
292 }
293
294 /**
295 * Define a color fill
296 * @param color if null then white is assumed
297 */
298 public void defineFillStyle( Color color )
299 {
300 if( color == null ) color = new Color(255,255,255);
301 ColorFill fill = new ColorFill( color );
302
303 if( color instanceof AlphaColor ) hasAlpha = true;
304
305 elements.add( fill );
306 }
307
308 /**
309 * Define an image fill
310 */
311 public void defineFillStyle( Symbol image, Transform matrix, boolean clipped )
312 {
313 ImageFill fill = new ImageFill(image,matrix,clipped);
314
315 elements.add( fill );
316 }
317
318 /**
319 * Define a gradient fill
320 */
321 public void defineFillStyle( Color[] colors, int[] ratios,
322 Transform matrix, boolean radial )
323 {
324 GradientFill fill = new GradientFill( colors, ratios, matrix, radial );
325
326 elements.add( fill );
327
328 for( int i = 0; i < colors.length; i++ )
329 {
330 if( colors[i] == null ) continue;
331 if( colors[i] instanceof AlphaColor ) hasAlpha = true;
332 }
333 }
334
335 /**
336 * Set the left fill style
337 */
338 public void setLeftFillStyle( int index )
339 {
340 SetLeftFillStyle fill = new SetLeftFillStyle( index );
341
342 elements.add( fill );
343 }
344
345 /**
346 * Set the right fill style
347 */
348 public void setRightFillStyle( int index )
349 {
350 SetRightFillStyle fill = new SetRightFillStyle( index );
351
352 elements.add( fill );
353 }
354
355 /**
356 * Set the line style
357 */
358 public void setLineStyle( int index )
359 {
360 SetLineStyle style = new SetLineStyle( index );
361
362 elements.add( style );
363 }
364
365 /**
366 * Move the pen without drawing any line
367 */
368 public void move( double x, double y )
369 {
370 Move move = new Move( x, y );
371
372 if( x < minX ) minX = x;
373 if( y < minY ) minY = y;
374 if( x > maxX ) maxX = x;
375 if( y > maxY ) maxY = y;
376
377 elements.add( move );
378 }
379
380 /**
381 * Draw a line in the current line style (if any)
382 */
383 public void line( double x, double y )
384 {
385 Line line = new Line( x, y );
386
387 if( x < minX ) minX = x;
388 if( y < minY ) minY = y;
389 if( x > maxX ) maxX = x;
390 if( y > maxY ) maxY = y;
391
392 elements.add( line );
393 }
394
395 /**
396 * Draw a curve in the current line style (if any)
397 */
398 public void curve( double x, double y, double controlX, double controlY )
399 {
400 Curve curve = new Curve( x, y, controlX, controlY );
401
402 if( x < minX ) minX = x;
403 if( y < minY ) minY = y;
404 if( x > maxX ) maxX = x;
405 if( y > maxY ) maxY = y;
406
407 if( controlX < minX ) minX = controlX;
408 if( controlY < minY ) minY = controlY;
409 if( controlX > maxX ) maxX = controlX;
410 if( controlY > maxY ) maxY = controlY;
411
412 elements.add( curve );
413 }
414
415 protected int defineSymbol( Movie movie,
416 SWFTagTypes timelineWriter,
417 SWFTagTypes definitionWriter )
418 throws IOException
419 {
420 currx = 0.0;
421 curry = 0.0;
422
423 predefineImageFills( movie, timelineWriter, definitionWriter );
424
425 int id = getNextId(movie);
426
427 Rect outline = getRect();
428
429 SWFShape shape = hasAlpha ?
430 definitionWriter.tagDefineShape3( id, outline ) :
431 definitionWriter.tagDefineShape2( id, outline );
432
433 writeShape( shape );
434
435 return id;
436 }
437
438 protected Rect getRect()
439 {
440 double adjust = maxLineWidth/2.0;
441
442 Rect outline = new Rect( (int)(minX*SWFConstants.TWIPS - adjust*SWFConstants.TWIPS),
443 (int)(minY*SWFConstants.TWIPS - adjust*SWFConstants.TWIPS),
444 (int)(maxX*SWFConstants.TWIPS + adjust*SWFConstants.TWIPS),
445 (int)(maxY*SWFConstants.TWIPS + adjust*SWFConstants.TWIPS));
446
447 return outline;
448 }
449
450 protected void predefineImageFills( Movie movie,
451 SWFTagTypes timelineWriter,
452 SWFTagTypes definitionWriter )
453 throws IOException
454 {
455 //--Make sure any image fills are defined prior to the shape
456 for( Iterator it = elements.iterator(); it.hasNext(); )
457 {
458 Object el = it.next();
459
460 if( el instanceof Shape.ImageFill )
461 {
462 Symbol image = ((Shape.ImageFill)el).getImage();
463
464 if( image != null ) image.define( movie,
465 timelineWriter,
466 definitionWriter );
467 }
468 }
469 }
470
471 protected void writeShape( SWFShape shape ) throws IOException
472 {
473 for( Iterator it = elements.iterator(); it.hasNext(); )
474 {
475 Object el = it.next();
476
477 if( el instanceof Shape.ColorFill )
478 {
479 Shape.ColorFill fill = (Shape.ColorFill)el;
480 shape.defineFillStyle( fill.getColor() );
481 }
482 else if( el instanceof Shape.ImageFill )
483 {
484 Shape.ImageFill fill = (Shape.ImageFill)el;
485
486 Symbol image = fill.getImage();
487 int imgId = (image != null) ? image.getId() : 65535;
488
489 shape.defineFillStyle( imgId, fill.getTransform(), fill.isClipped() );
490 }
491 else if( el instanceof Shape.GradientFill )
492 {
493 Shape.GradientFill fill = (Shape.GradientFill)el;
494
495 shape.defineFillStyle( fill.getTransform(),
496 fill.getRatios(),
497 fill.getColors(),
498 fill.isRadial() );
499 }
500 else if( el instanceof Shape.LineStyle )
501 {
502 Shape.LineStyle style = (Shape.LineStyle)el;
503
504 shape.defineLineStyle( (int)(style.getWidth() * SWFConstants.TWIPS),
505 style.getColor() );
506 }
507 else if( el instanceof Shape.SetLeftFillStyle )
508 {
509 Shape.SetLeftFillStyle style = (Shape.SetLeftFillStyle)el;
510 shape.setFillStyle0( style.getStyleIndex() );
511 }
512 else if( el instanceof Shape.SetRightFillStyle )
513 {
514 Shape.SetRightFillStyle style = (Shape.SetRightFillStyle)el;
515 shape.setFillStyle1( style.getStyleIndex() );
516 }
517 else if( el instanceof Shape.SetLineStyle )
518 {
519 Shape.SetLineStyle style = (Shape.SetLineStyle)el;
520 shape.setLineStyle( style.getStyleIndex() );
521 }
522 else writeVector( shape, el );
523 }
524
525 shape.done();
526 }
527
528 protected void writeVector( SWFVectors vecs, Object el ) throws IOException
529 {
530 if( el instanceof Shape.Move )
531 {
532 Shape.Move move = (Shape.Move)el;
533
534 currx = move.getX()*SWFConstants.TWIPS;
535 curry = move.getY()*SWFConstants.TWIPS;
536
537 int x = (int)currx;
538 int y = (int)curry;
539
540 vecs.move( x, y );
541
542 //System.out.println( "M: " + x + " " + y );
543 }
544 else if( el instanceof Shape.Line )
545 {
546 Shape.Line line = (Shape.Line)el;
547
548 double xx = line.getX()*SWFConstants.TWIPS;
549 double yy = line.getY()*SWFConstants.TWIPS;
550
551 int dx = (int)(xx - currx);
552 int dy = (int)(yy - curry);
553
554 vecs.line( dx, dy );
555
556 //System.out.println( "currx=" + currx + " curry=" + curry + " xx=" + xx + " yy=" + yy + " (xx - currx)=" + (xx - currx) + " (yy - curry)=" + (yy - curry) );
557 //System.out.println( "L: " + dx + " " + dy );
558
559 currx = xx;
560 curry = yy;
561 }
562 else if( el instanceof Shape.Curve )
563 {
564 Shape.Curve curve = (Shape.Curve)el;
565
566 double xx = curve.getX() *SWFConstants.TWIPS;
567 double yy = curve.getY() *SWFConstants.TWIPS;
568 double cxx = curve.getControlX()*SWFConstants.TWIPS;
569 double cyy = curve.getControlY()*SWFConstants.TWIPS;
570
571 int dx = (int)(xx - cxx);
572 int dy = (int)(yy - cyy);
573 int cx = (int)(cxx - currx);
574 int cy = (int)(cyy - curry);
575
576 vecs.curve( cx, cy, dx, dy );
577
578 currx = xx;
579 curry = yy;
580
581 //System.out.println( "C: " + cx + " " + cy + " " + dx + " " + dy );
582 }
583 }
584
585 protected void writeGlyph( SWFVectors vecs ) throws IOException
586 {
587 currx = 0.0;
588 curry = 0.0;
589
590 for( Iterator it = elements.iterator(); it.hasNext(); )
591 {
592 writeVector( vecs, it.next() );
593 }
594
595 vecs.done();
596 }
597 }