Shapeの基礎の基礎
@SWF研究会#2
Kensaku Araga
September 25, 2012
Kensaku Araga
September 25, 2012
簡単な1フレームのSWFをベクターデータとして再現できるようになる
ポイントの移動
直線を引く
二次ベジェ曲線
|
// drawRectを使う
public function draw(): void
{
var shape: Shape = new Shape();
shape.graphics.lineStyle(4, 0x0000ff);
shape.graphics.beginFill(0xff0000, 1.0);
shape.graphics.drawRect(50, 70, 140, 140);
addChild(shape);
}
|
|
// SWFで使える機能のみを使う
public function lineTo(): Shape
{
var shape: Shape = new Shape();
shape.graphics.lineStyle(4, 0x0000ff);
shape.graphics.beginFill(0xff0000, 1.0);
shape.graphics.moveTo(50, 70);
shape.graphics.lineTo(50, 210);
shape.graphics.lineTo(190, 210);
shape.graphics.lineTo(190, 70);
shape.graphics.lineTo(50, 70);
addChild(shape);
}
|
|
// drawCircleを使う
public function draw(): void
{
var shape: Shape = new Shape();
shape.graphics.lineStyle(4, 0x0000ff);
shape.graphics.beginFill(0xff0000, 1.0);
shape.graphics.drawCircle(100, 100, 90);
addChild(shape);
}
|
// SWFで使えるものだけを使う
public function draw(): void
{
var shape: Shape = new Shape();
shape.graphics.lineStyle(4, 0x0000ff);
shape.graphics.beginFill(0xff0000, 1.0);
shape.graphics.moveTo(163.60, 163.60);
shape.graphics.curveTo(137.30, 190.00, 100.00, 190.00);
shape.graphics.curveTo(62.65, 190.00, 36.30, 163.60);
shape.graphics.curveTo(10.00, 137.30, 10.00, 100.00);
shape.graphics.curveTo(10.00, 62.65, 36.30, 36.30);
shape.graphics.curveTo(62.65, 10.00, 100.00, 10.00);
shape.graphics.curveTo(137.30, 10.00, 163.60, 36.30);
shape.graphics.curveTo(190.00, 62.65, 190.00, 100.00);
shape.graphics.curveTo(190.00, 137.30, 163.60, 163.60);
addChild(shape);
}
|
⇒
moveTo、lineTo、curveTo、塗り、線
があれば、どんな言語にも
必ずコンバートできる
|
|
swfdumpで中身を見てみよう
$ swfdump --shapes sample/sample.swf
[002] 146 DEFINESHAPE defines id 0001
| fillstyles(02) linestyles(00)
| 1 ) SOLID 000066ff
| 2 ) SOLID ff0000ff
|
| fill: 00/02 line:00 - moveTo 189.85 69.05
| fill: 00/02 line:00 - splineTo (199.95 79.15) 199.95 93.45
| fill: 00/02 line:00 - splineTo (199.95 107.75) 189.85 117.85
| fill: 00/02 line:00 - splineTo (180.55 127.15) 167.75 127.90
| fill: 00/02 line:00 - lineTo 209.70 200.65
| fill: 00/02 line:00 - lineTo 121.25 200.65
| fill: 00/02 line:00 - lineTo 163.30 127.90
| fill: 00/02 line:00 - splineTo (150.40 127.20) 141.05 117.85
| fill: 00/02 line:00 - splineTo (130.95 107.75) 130.95 93.45
| fill: 00/02 line:00 - splineTo (130.95 79.15) 141.05 69.05
| fill: 00/02 line:00 - splineTo (151.15 58.95) 165.45 58.95
| fill: 00/02 line:00 - splineTo (179.75 58.95) 189.85 69.05
| fill: 00/01 line:00 - moveTo 106.00 93.45
| fill: 00/01 line:00 - splineTo (106.00 107.75) 95.90 117.85
| fill: 00/01 line:00 - splineTo (90.50 123.25) 83.95 125.75
| fill: 00/01 line:00 - lineTo 116.20 125.75
| fill: 00/01 line:00 - lineTo 72.00 202.35
| fill: 00/01 line:00 - lineTo 27.75 125.75
| fill: 00/01 line:00 - lineTo 59.10 125.75
| fill: 00/01 line:00 - splineTo (52.50 123.25) 47.10 117.85
| fill: 00/01 line:00 - splineTo (37.00 107.75) 37.00 93.45
| fill: 00/01 line:00 - splineTo (37.00 79.15) 47.10 69.05
| fill: 00/01 line:00 - splineTo (57.20 58.95) 71.50 58.95
| fill: 00/01 line:00 - splineTo (85.80 58.95) 95.90 69.05
| fill: 00/01 line:00 - splineTo (106.00 79.15) 106.00 93.45
|
ActionScript3.0で書いてみよう
public function shape(): Shape
{
var shape: Shape = new Shape();
shape.graphics.beginFill(0xff0000, 1); // 2
shape.graphics.moveTo(189.85, 69.05); // fill 00/02, line 00
shape.graphics.curveTo(199.95, 79.15, 199.95, 93.45); // fill 00/02, line 00
shape.graphics.curveTo(199.95, 107.75, 189.85, 117.85); // fill 00/02, line 00
shape.graphics.curveTo(180.55, 127.15, 167.75, 127.90); // fill 00/02, line 00
shape.graphics.lineTo(209.70, 200.65); // fill 00/02, line 00
shape.graphics.lineTo(121.25, 200.65); // fill 00/02, line 00
shape.graphics.lineTo(163.30, 127.90); // fill 00/02, line 00
shape.graphics.curveTo(150.40, 127.20, 141.05, 117.85); // fill 00/02, line 00
shape.graphics.curveTo(130.95, 107.75, 130.95, 93.45); // fill 00/02, line 00
shape.graphics.curveTo(130.95, 79.15, 141.05, 69.05); // fill 00/02, line 00
shape.graphics.curveTo(151.15, 58.95, 165.45, 58.95); // fill 00/02, line 00
shape.graphics.curveTo(179.75, 58.95, 189.85, 69.05); // fill 00/02, line 00
shape.graphics.beginFill(0x000066, 1); // 1
shape.graphics.moveTo(106.00, 93.45); // fill 00/01, line 00
shape.graphics.curveTo(106.00, 107.75, 95.90, 117.85); // fill 00/01, line 00
shape.graphics.curveTo(90.50, 123.25, 83.95, 125.75); // fill 00/01, line 00
shape.graphics.lineTo(116.20, 125.75); // fill 00/01, line 00
shape.graphics.lineTo(72.00, 202.35); // fill 00/01, line 00
shape.graphics.lineTo(27.75, 125.75); // fill 00/01, line 00
shape.graphics.lineTo(59.10, 125.75); // fill 00/01, line 00
shape.graphics.curveTo(52.50, 123.25, 47.10, 117.85); // fill 00/01, line 00
shape.graphics.curveTo(37.00, 107.75, 37.00, 93.45); // fill 00/01, line 00
shape.graphics.curveTo(37.00, 79.15, 47.10, 69.05); // fill 00/01, line 00
shape.graphics.curveTo(57.20, 58.95, 71.50, 58.95); // fill 00/01, line 00
shape.graphics.curveTo(85.80, 58.95, 95.90, 69.05); // fill 00/01, line 00
shape.graphics.curveTo(106.00, 79.15, 106.00, 93.45); // fill 00/01, line 00
return shape;
}
JavaScriptでも書いてみよう
onload = function() {
var canvas = document.getElementById('shape');
var ctx = canvas.getContext('2d');
ctx.beginPath();
ctx.fillStyle = '#ff0000'; // 2
ctx.moveTo(189.85, 69.05); // fill 00/02, line 00
ctx.quadraticCurveTo(199.95, 79.15, 199.95, 93.45); // fill 00/02, line 00
ctx.quadraticCurveTo(199.95, 107.75, 189.85, 117.85); // fill 00/02, line 00
ctx.quadraticCurveTo(180.55, 127.15, 167.75, 127.90); // fill 00/02, line 00
ctx.lineTo(209.70, 200.65); // fill 00/02, line 00
ctx.lineTo(121.25, 200.65); // fill 00/02, line 00
ctx.lineTo(163.30, 127.90); // fill 00/02, line 00
ctx.quadraticCurveTo(150.40, 127.20, 141.05, 117.85); // fill 00/02, line 00
ctx.quadraticCurveTo(130.95, 107.75, 130.95, 93.45); // fill 00/02, line 00
ctx.quadraticCurveTo(130.95, 79.15, 141.05, 69.05); // fill 00/02, line 00
ctx.quadraticCurveTo(151.15, 58.95, 165.45, 58.95); // fill 00/02, line 00
ctx.quadraticCurveTo(179.75, 58.95, 189.85, 69.05); // fill 00/02, line 00
ctx.fill();
ctx.beginPath();
ctx.fillStyle = '#000066'; // 1
ctx.moveTo(106.00, 93.45); // fill 00/01, line 00
ctx.quadraticCurveTo(106.00, 107.75, 95.90, 117.85); // fill 00/01, line 00
ctx.quadraticCurveTo(90.50, 123.25, 83.95, 125.75); // fill 00/01, line 00
ctx.lineTo(116.20, 125.75); // fill 00/01, line 00
ctx.lineTo(72.00, 202.35); // fill 00/01, line 00
ctx.lineTo(27.75, 125.75); // fill 00/01, line 00
ctx.lineTo(59.10, 125.75); // fill 00/01, line 00
ctx.quadraticCurveTo(52.50, 123.25, 47.10, 117.85); // fill 00/01, line 00
ctx.quadraticCurveTo(37.00, 107.75, 37.00, 93.45); // fill 00/01, line 00
ctx.quadraticCurveTo(37.00, 79.15, 47.10, 69.05); // fill 00/01, line 00
ctx.quadraticCurveTo(57.20, 58.95, 71.50, 58.95); // fill 00/01, line 00
ctx.quadraticCurveTo(85.80, 58.95, 95.90, 69.05); // fill 00/01, line 00
ctx.quadraticCurveTo(106.00, 79.15, 106.00, 93.45); // fill 00/01, line 00
ctx.fill();
};
| DefineShape |
初期
≧ SWF1 |
|---|---|
| DefineShape2 |
Styleを増量
≧ SWF2 |
| DefineShape3 |
アルファをサポート
≧ SWF3 |
| DefineShape4 |
線の種類が増加
≧ SWF8 |
| Header | Tag type = 2, 22, 32, 83 | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
| ShapeId | characterId (Define*の中でユニーク) | ||||||||||
| ShapeBounds | 矩形の境界 中心点とか (0,0) の位置とかが決まる | ||||||||||
| Shapes |
ベクターデータに関する諸々の情報
|
| FillStyleType |
0x00 = 塗りつぶし 0x10-0x13 = グラデーション 0x40-0x43 = 画像 |
|---|---|
| Color | RGB(Shape1,2) RGBA(Shape3) |
| GradientMatrix | グラデーションの配置(回転や始点など) |
| Gradient | グラデーションの情報 |
| BitmapId | 画像のcharacterId |
| BitmapMatrix | 画像のMatrix |
| Width | 線の太さ |
|---|---|
| Color | RGB(Shape1,2) RGBA(Shape3) |
SWF8以降のlineStyle2で項目が増えますが省略します
以下の4種類で構成
| EndShapeRecord | レコードの終了 |
|---|---|
| StyleChangeRecord |
|
| StraightEdgeRecord | lineTo |
| CurvedEdgeRecord | curveTo |
DefineShape[2]:
ShapeID: 1
ShapeBounds: { Xmin: 960, Xmax: 3840, Ymin: 1360, Ymax: 4240 }
Shapes:
FillStyles:
[1] FILLSTYLE1: { Color: #ff0000 }
LineStyles:
[1] LINESTYLE1: { With: 80, Color: #0000ff }
ShapeRecords:
StyleChangeRecord: MoveTo( 3800, 4200 ), FillStyle1: 1, LineStyle: 1
StraightEdgeRecord: LineTo( -2800, 0 )
StraightEdgeRecord: LineTo( 0, -2800 )
StraightEdgeRecord: LineTo( 2800, 0 )
StraightEdgeRecord: LineTo( 0, 2800 )
EndShapeRecord:
パスの座標は相対値
絶対値に変更するには
(toX', toY') = (x + toX, y + toY)
curveToではどうなるか
(controleX', controleY') = (x + controleX, y + controleY) (toX', toY') = (x + controleX + toX, y + controleY + toY)
|
|
[002] 65 DEFINESHAPE defines id 0001
| fillstyles(03) linestyles(00)
| 1 ) SOLID ff0000ff
| 2 ) SOLID ffff00ff
| 3 ) SOLID 0000ccff
|
| fill: 02/03 line:00 - moveTo 161.00 101.00
| fill: 02/03 line:00 - lineTo 161.00 156.00
| fill: 02/03 line:00 - lineTo 103.00 156.00
| fill: 02/00 line:00 - lineTo 103.00 210.00
| fill: 02/00 line:00 - lineTo 212.00 210.00
| fill: 02/00 line:00 - lineTo 212.00 101.00
| fill: 02/00 line:00 - lineTo 161.00 101.00
| fill: 01/00 line:00 - lineTo 161.00 44.00
| fill: 01/00 line:00 - lineTo 49.00 44.00
| fill: 01/00 line:00 - lineTo 49.00 156.00
| fill: 01/00 line:00 - lineTo 103.00 156.00
| fill: 01/03 line:00 - lineTo 103.00 101.00
| fill: 01/03 line:00 - lineTo 161.00 101.00
public function draw(): void
{
var shape: Shape = new Shape();
shape.graphics.beginFill(0xffff00, 1.0);
shape.graphics.moveTo( 161.00, 101.00 ); // 2, 3
shape.graphics.lineTo( 161.00, 156.00 ); // 2, 3
shape.graphics.lineTo( 103.00, 156.00 ); // 2, 3
shape.graphics.lineTo( 103.00, 210.00 ); // 2, 0
shape.graphics.lineTo( 212.00, 210.00 ); // 2, 0
shape.graphics.lineTo( 212.00, 101.00 ); // 2, 0
shape.graphics.lineTo( 161.00, 101.00 ); // 2, 0
shape.graphics.beginFill(0xff0000, 1.0);
shape.graphics.lineTo( 161.00, 44.00 ); // 1, 0
shape.graphics.lineTo( 49.00 , 44.00 ); // 1, 0
shape.graphics.lineTo( 49.00 , 156.00 ); // 1, 0
shape.graphics.lineTo( 103.00, 156.00 ); // 1, 0
shape.graphics.lineTo( 103.00, 101.00 ); // 1, 3
shape.graphics.lineTo( 161.00, 101.00 ); // 1, 3
addChild( shape );
}
fill: 02/03 line:00 - moveTo 161.00 101.00 fill: 01/03 line:00 - lineTo 103.00 101.00
DefineShape[2]:
ShapeID: 1
ShapeBounds: { Xmin: 980, Xmax: 4240, Ymin: 880, Ymax: 4200 }
Shapes:
FillStyles:
[1] FILLSTYLE1: { Color: #ff0000 }
[2] FILLSTYLE1: { Color: #ffff00 }
[3] FILLSTYLE1: { Color: #0000cc }
LineStyles:
ShapeRecords:
StyleChangeRecord: MoveTo( 3220, 2020 ), FillStyle0: 2, FillStyle1: 3
StraightEdgeRecord: LineTo( 0, 1100 )
StraightEdgeRecord: LineTo( -1160, 0 )
StyleChangeRecord: FillStyle1: 0
StraightEdgeRecord: LineTo( 0, 1080 )
StraightEdgeRecord: LineTo( 2180, 0 )
StraightEdgeRecord: LineTo( 0, -2180 )
StraightEdgeRecord: LineTo( -1020, 0 )
StyleChangeRecord: FillStyle0: 1
StraightEdgeRecord: LineTo( 0, -1140 )
StraightEdgeRecord: LineTo( -2240, 0 )
StraightEdgeRecord: LineTo( 0, 2240 )
StraightEdgeRecord: LineTo( 1080, 0 )
StyleChangeRecord: FillStyle1: 3
StraightEdgeRecord: LineTo( 0, -1100 )
StraightEdgeRecord: LineTo( 1160, 0 )
EndShapeRecord:
fillStyle0とfillStyle1と2種類あり両方にStyleが設定されている
なんじゃこりゃあ?
| fillStyle0 | 進行方向右側の塗り |
|---|---|
| fillStyle1 | 進行方向左側の塗り |
|
|
public function draw(): void
{
var shape: Shape = new Shape();
// 略
// fillStyle0 の分を追加
shape.graphics.beginFill(0x0000cc, 1.0);
shape.graphics.moveTo( 161.00, 101.00 ); // 2, 3
shape.graphics.lineTo( 161.00, 156.00 ); // 2, 3
shape.graphics.lineTo( 103.00, 156.00 ); // 2, 3
shape.graphics.lineTo( 103.00, 101.00 ); // 1, 3
shape.graphics.lineTo( 161.00, 101.00 ); // 1, 3
addChild( shape );
}
しかし
| Depth |
配置位置 DisplayObjectContainer::addChildAt() のindexに当たる またタイムラインの位置(小さいほど奥) |
|---|---|
| CharacterId | Define*を指し示すID |
| Matrix | 配置、拡大・縮小、回転 |
| ColorTransform | 色の変形 |
| Name | インスタンス名(PlaceObject2) |
| Ratio | Morphingの比率(PlaceObject2) |
| Cripp* | Crippingに関する情報(PlaceObject2) |
| CharacterId | Define*.characterIdを取り出す |
|---|---|
| Depth | DisplayObjectContainer.addChildAt |
| Matrix | DisplayObject.transform.matrix |
| ColorTransform | DisplayObject.transform.colorTransform |
|
|
|
DEFINESPRITE defines id 0002
PLACEOBJECT2 places id 0001 at depth 0002
| Matrix
| 1.000 0.000 -57.75
| 0.000 1.000 15.30
SHOWFRAME 1 (00:00:00,000)
END
PLACEOBJECT2 places id 0002 at depth 0001 name "ar"
| Matrix
| 1.000 0.000 157.20
| 0.000 1.000 141.35
var shape_0001:Shape = create_shape_0002(); shape_0001.transform.matrix = new Matrix(1, 0, 0, 1, -57.75, 15.30); var sprite_0002:Sprite = new Sprite(); sprite_0002.addChildAt(shape_0001, 2); sprite_0002.transform.matrix = new Matrix(1, 0, 0, 1, 157.20, 141.35); addChildAt(sprite_0002, 1);
| FillStyleType | グラデーションタイプ |
|---|---|
| 0x10 |
Liner
|
| 0x12 |
Radial
|
| 0 = Pad |
|
|---|---|
| 1 = Reflect |
|
| 2 = Repeat |
|
| 0 = Normal RGB |
|
|---|---|
| 1 = Linear RGB |
|
GradientRecord(control point)の配列
| GradientRecord[0] |
| ||||
| GradientRecord[2] | { Ratio = 255, Color = #000 } |
| FillStyleType | 0x10 = Liner | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| SpreadMode | 0 = Pad | ||||||||||||||||
| InterpolationMode | 0 = Normal RGB | ||||||||||||||||
| GradientRecords |
|
// 虹の場合
public function draw(): void {
var shape: Shape = new Shape();
shape.graphics.lineStyle(1, 0x000000);
var matrix: Matrix = new Matrix();
matrix.createGradientBox(200, 200);
shape.graphics.beginGradientFill(
'linear', // type
[0xff0000, 0xffff00, 0x00ff00, 0x00ffff, 0x0000ff, 0xff00ff, 0xff0000], // colors
[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 ], // alphas
[0, 42, 93, 127, 170, 212, 255 ], // ratios
matrix, // GradientMatrix
'pad', // spreadMethod
'rgb' // interpolationMethod
);
shape.graphics.drawRect( 0, 0, 200, 200 );
shape.x = 20;
shape.y = 20;
addChild(shape);
}
// 虹の場合
onload = function() {
var canvas = document.getElementById('shape');
var ctx = canvas.getContext('2d');
ctx.beginPath();
var grad = ctx.createLinearGradient(20,0, 220,0);
grad.addColorStop(0 / 255, '#ff0000');
grad.addColorStop(42 / 255, '#ffff00');
grad.addColorStop(93 / 255, '#00ff00');
grad.addColorStop(127 / 255, '#00ffff');
grad.addColorStop(170 / 255, '#0000ff');
grad.addColorStop(212 / 255, '#ff00ff');
grad.addColorStop(255 / 255, '#ff0000');
ctx.strokeStyle = '#000000';
ctx.lineWidth = 1;
ctx.fillStyle = grad;
ctx.rect(20,20,200,200);
ctx.fill();
ctx.stroke();
};
説明しきれなくてごめんなさい
| defs | オブジェクト定義 | ||||||
|---|---|---|---|---|---|---|---|
| g |
グループ化<g id="内部参照可能な名前" transform="matrix(Matrix)" > | ||||||
| path |
<path d="パスの情報" fill="塗り"
stroke="線の色" stroke-width="線の太さ" viewBox="矩形" >
| ||||||
| use |
<use xlink:href="#内部参照" transform="matrix(Matrix)" > | ||||||
|
linearGradient radialGradient |
<linearGradient id="g_1_0" spreadMethod="pad"> <stop stop-color="#ffffff" offset="0%"/> <stop stop-color="#000000" offset="100%"/> </linearGradient> |