root/as3/gunyarapaint/trunk/gunyarapaint/src/org/libspark/gunyarapaint/entities/GPLogger.as

リビジョン 1307, 20.6 kB (コミッタ: tasuku, コミット時期: 5 年 前)

added layer blendMode log

Line 
1 // 今考えると、このクラス全体的に設計がおかしい。
2 // 定数持っているなら、それを外部から指定してもらうべきだし、
3 // 読み込みのswitchは同じような処理を2回やって無駄だ。
4
5 package org.libspark.gunyarapaint.entities
6 {
7   import flash.display.BitmapData;
8   import flash.errors.EOFError;
9   import flash.utils.ByteArray;
10  
11   import org.libspark.gunyarapaint.controls.GPCanvas;
12  
13   import mx.controls.Alert;
14   import mx.utils.Base64Decoder;
15   import mx.utils.Base64Encoder;
16  
17   public class GPLogger
18   {
19     // Arrayだせーな。Objectにしたほうがよかったかな。まあいいや。
20     private var preX:uint, preY:uint;
21     private var preAction:String = '';
22    
23     private var log:ByteArray;
24    
25     private var logCount:uint;
26
27     private var width:uint, height:uint;
28     private var undoBufferSize:uint;
29     private var isCompress:Boolean = false;
30
31     // 互換性。つか、過去のバグやマズった設計で作られたログについてちゃんと再生できるようにする。
32     private var compatibility_0_0_1:Boolean = false;
33
34     public function GPLogger(log:ByteArray):void {
35       if (log) {
36         this.log = log;       
37       } else {
38         this.log = new ByteArray();
39       }
40       this.log.endian = flash.utils.Endian.BIG_ENDIAN;
41     }
42    
43     public function writeHeader(width:uint, height:uint, undoBufferSize:uint):void {
44       this.width = width;
45       this.height = height;
46       this.undoBufferSize = undoBufferSize;
47      
48       log.writeUTFBytes('GUNYARA_PAINT:0.0.2:');
49       writeShort(width);
50       writeShort(height);
51       writeShort(undoBufferSize);
52     }
53    
54     public function readHeader():void {
55       var buf:String = log.readUTFBytes(14);
56       if (buf != 'GUNYARA_PAINT:') {
57         Alert('不正なお絵カキコのログです。');
58         log = null;
59         return;
60       }
61       buf = log.readUTFBytes(6);
62       switch (buf) {
63       case '0.0.1:':
64         compatibility_0_0_1 = true;
65         break;
66       case '0.0.2:':
67         break;
68       default:
69         Alert('このバージョンのログには対応しておりません。ブラウザをリロードしてみてください。');
70         log = null;
71         return;
72       }
73       width = readShort();
74       height = readShort();
75       undoBufferSize = readShort();
76     }
77    
78     public function createViewerCanvas(baseImg:BitmapData):GPCanvas {
79       resetPosition();
80       var pen:GPPen = new GPPen();
81       var canvas:GPCanvas = new GPCanvas(width, height, undoBufferSize, this, baseImg, pen);
82       return canvas;
83     }
84
85     // ACTIONは6bit長 0x3fまで
86     public static const ACTION_NONE:uint = 0;
87     public static const ACTION_MOVETO:uint = 1;
88     public static const ACTION_LINETO:uint = 2;
89     public static const ACTION_LINESTYLE:uint = 3;
90     public static const ACTION_DRAW_SHAPE_ON_BITMAP:uint = 4;
91     public static const ACTION_UNDO:uint = 5;
92     public static const ACTION_REDO:uint = 6;
93     public static const ACTION_BEGIN_FILL:uint = 7;
94     public static const ACTION_END_FILL:uint = 8;
95     public static const ACTION_DRAW_RECT:uint = 9;
96     public static const ACTION_DRAW_CIRCLE:uint = 10;
97     public static const ACTION_DRAW_ELLIPSE:uint = 11;
98     public static const ACTION_DRAW_ROUND_RECT:uint = 12;
99     public static const ACTION_FLOOD_FILL:uint = 13;
100     public static const ACTION_LAYER_NEW:uint = 14;
101     public static const ACTION_LAYER_COPY:uint = 15;
102     public static const ACTION_LAYER_SWAP:uint = 16;
103     public static const ACTION_LAYER_MERGE_WITH_BELOW:uint = 17;
104     public static const ACTION_LAYER_REMOVE:uint = 18;
105     public static const ACTION_LAYER_CHANGE_TARGET:uint = 19;
106     public static const ACTION_LAYER_CHANGE_VISIBLE:uint = 20;
107     public static const ACTION_LAYER_CHANGE_BLEND_MODE:uint = 21;
108
109     // LINESTYLE
110     public static const LINESTYLE_THICKNESS:uint = 1;
111     public static const LINESTYLE_COLOR:uint = 2;
112     public static const LINESTYLE_ALPHA:uint = 3;
113     public static const LINESTYLE_BLEND_MODE:uint = 4;
114     public static const LINESTYLE_SCALE_MODE:uint = 5;
115     public static const LINESTYLE_CAPS:uint = 6;
116     public static const LINESTYLE_JOINTS:uint = 7;
117     public static const LINESTYLE_MITER_LIMIT:uint = 8;
118     public static const LINESTYLE_PIXEL_HINTING:uint = 9; // NB: not used! first version, this is true
119
120     public function write(info:Array):void {
121       var x:uint, y:uint, dx:int, dy:int;
122       switch(info[0]) { // 0x00 - 0x3f
123       case 'moveTo':
124         x = info[1];
125         y = info[2];
126         dx = x - preX;
127         dy = y - preY;
128         if (dx >= -64 && dx <= 63 && dy >= -64 && dy <= 63) {
129           // dxもdyも7bitに収まる場合
130           writeShort(0x4000 | (dx << 7) & 0x3f80 | dy & 0x7f);
131         } else {
132           writeByte(ACTION_MOVETO);
133           writeShort(dx);
134           writeShort(dy);
135         }
136         preX = x;
137         preY = y;
138         break;
139       case 'lineTo':
140         x = info[1];
141         y = info[2];
142         dx = x - preX;
143         dy = y - preY;
144         if (dx >= -4 && dx <= 3 && dy >= -4 && dy <= 3) {
145           // dxもdyも3bitに収まる場合
146           writeByte(0x80 | (dx << 3) & 0x38 | dy & 0x7);
147         } else if (dx >= -64 && dx <= 63 && dy >= -64 && dy <= 63) {
148           // dxもdyも7bitに収まる場合
149           writeShort(0xc000 | (dx << 7) & 0x3f80 | dy & 0x7f);
150         } else {
151           // それ以外の場合 dx,dyを16bit長で保存
152           writeByte(ACTION_LINETO);
153           writeShort(dx);
154           writeShort(dy);
155         }     
156         preX = x;
157         preY = y;
158         break;
159       case 'lineStyle':
160         var style:uint = info[1];
161         writeByte(ACTION_LINESTYLE);
162         writeByte(style);
163         switch (style) {
164         case GPLogger.LINESTYLE_THICKNESS:
165           writeByte(info[2]); // 255
166           break;
167         case GPLogger.LINESTYLE_COLOR:
168           writeUInt(info[2]);
169           break;
170         case GPLogger.LINESTYLE_ALPHA:
171         case GPLogger.LINESTYLE_MITER_LIMIT:
172           writeDouble(info[2]);
173           break;
174         case GPLogger.LINESTYLE_BLEND_MODE:
175         case GPLogger.LINESTYLE_SCALE_MODE:
176         case GPLogger.LINESTYLE_CAPS:
177         case GPLogger.LINESTYLE_JOINTS:
178           writeUTF(info[2]);
179           break;
180         case GPLogger.LINESTYLE_PIXEL_HINTING:
181           writeBoolean(info[2]);
182           break;
183         default:
184           Alert.show('対応していないラインスタイルがログされました!');
185           break;
186         }
187         break;
188       case 'drawShapeOnBitmap':
189         writeByte(ACTION_DRAW_SHAPE_ON_BITMAP);
190         break;     
191       case 'undo':
192         writeByte(ACTION_UNDO);
193         break;
194       case 'redo':
195         writeByte(ACTION_REDO);
196         break;
197       case 'beginFill':
198         writeByte(ACTION_BEGIN_FILL);
199         writeUInt(info[1]); // color
200         writeDouble(info[2]); // alpha
201         break;
202       case 'endFill':
203         writeByte(ACTION_END_FILL);
204         break;
205       case 'drawCircle':
206         // 直前のmoveToの座標を中心。よって、半径のみ保存
207         writeByte(ACTION_DRAW_CIRCLE);
208         writeDouble(info[1]);
209         break;
210       case 'floodFill':
211         writeByte(ACTION_FLOOD_FILL);
212         break;
213       case 'layerNew':
214         writeByte(ACTION_LAYER_NEW);
215         break;
216       case 'layerCopy':
217         writeByte(ACTION_LAYER_COPY);
218         break;
219       case 'layerSwap':
220         writeByte(ACTION_LAYER_SWAP);
221         writeByte(info[1]);
222         writeByte(info[2]);
223         break;
224       case 'layerMergeWithBelow':
225         writeByte(ACTION_LAYER_MERGE_WITH_BELOW);
226         break;
227       case 'layerRemove':
228         writeByte(ACTION_LAYER_REMOVE);
229         break;
230       case 'layerChangeTarget':
231         writeByte(ACTION_LAYER_CHANGE_TARGET);
232         writeByte(info[1]);
233         break;
234       case 'layerChangeVisible':
235         writeByte(ACTION_LAYER_CHANGE_VISIBLE);
236         writeByte(info[1]);
237         writeBoolean(info[2]);
238         break;
239       case 'layerChangeBlendMode':
240         writeByte(ACTION_LAYER_CHANGE_BLEND_MODE);
241         writeUTF(info[1]);
242         break;
243       default:
244         Alert.show('対応していないアクションがログされました!');
245         return;
246       }
247       logCount++;
248     }
249     public function getLogCount():uint {
250       return logCount;
251     }
252     // put byte data
253     private function writeByte(byte:int):void {
254       log.writeByte(byte);
255     }
256     private function writeShort(value:int):void {
257       log.writeShort(value);
258     }
259     private function writeUInt(value:uint):void {
260       log.writeUnsignedInt(value);
261     }
262     private function writeDouble(value:Number):void {
263       log.writeDouble(value);
264     }
265     private function writeUTF(value:String):void {
266       log.writeUTF(value);
267     }
268     private function writeBoolean(value:Boolean):void {
269       log.writeByte(value ? 1 : 0);
270     }
271     private function readByte():uint {
272       return log.readUnsignedByte();
273     }
274     private function readShort():int {
275       return log.readShort();
276     }
277     private function readUShort():uint {
278       return uint(log.readShort() & 0xffff);
279     }
280     private function readUInt():uint {
281       return log.readUnsignedInt();
282     }
283     private function readDouble():Number {
284       return log.readDouble();
285     }
286     private function readUTF():String {
287       return log.readUTF();
288     }
289     private function readBoolean():Boolean {
290       return (log.readByte() == 1);
291     }
292
293     // ログ関係のローカル変数
294     private var _playCanvas:GPCanvas;
295     private var playLogIntervalId:uint;
296     private var _playSpeed:uint;
297
298     public function set playSpeed(speed:uint):void {
299       _playSpeed = speed;
300     }
301
302     public function play(canvas:GPCanvas, speed:uint):void {
303       _playCanvas = canvas;
304       _playSpeed = speed;
305       playLogIntervalId = flash.utils.setInterval(playNext, 50);
306     }
307
308     private function playNext():void {
309       var preAction:uint = GPLogger.ACTION_NONE; // for avoid version 0.0.1 bug...◆
310       for (var i:uint = 0; i < _playSpeed; i++) {
311         var a:Array;
312         var isBreak:Boolean = false;
313         if ((a = read())) {
314           var action:uint = a[0];
315          
316           // avoid version 0.0.1 bug
317           if (compatibility_0_0_1 &&
318               preAction == GPLogger.ACTION_MOVETO && action != GPLogger.ACTION_LINETO) {
319             _playCanvas.drawOldBugPointRect();
320           }
321          
322           switch (action) {
323           case GPLogger.ACTION_MOVETO:
324             trace('MOVE_TO x:' + a[1] + ' y:' + a[2]);
325             if (compatibility_0_0_1) {
326               _playCanvas.oldMoveTo(a[1], a[2]);             
327             } else {
328               _playCanvas.moveTo(a[1], a[2]);
329             }
330             break;
331           case GPLogger.ACTION_LINETO:
332             trace('LINE_TO x:' + a[1] + ' y:' + a[2]);
333             if (compatibility_0_0_1) {
334               _playCanvas.oldLineTo(a[1], a[2]);
335             } else {
336               _playCanvas.lineTo(a[1], a[2]);
337             }
338             break;
339           case GPLogger.ACTION_LINESTYLE:
340             switch (a[1]) {
341             case GPLogger.LINESTYLE_THICKNESS:
342               trace('LINE_STYLE thickness:' + a[2]);
343               _playCanvas.pen.thickness = a[2];
344               break;
345             case GPLogger.LINESTYLE_COLOR:
346               trace('LINE_STYLE color:' + a[2]);
347               _playCanvas.pen.color = a[2];
348               break;
349             case GPLogger.LINESTYLE_ALPHA:
350               trace('LINE_STYLE alpha:' + a[2]);
351               _playCanvas.pen.alpha = a[2];
352               break;
353             case GPLogger.LINESTYLE_BLEND_MODE:
354               trace('LINE_STYLE blend_mode:' + a[2]);
355               _playCanvas.pen.blendMode = a[2];
356               break;
357             case GPLogger.LINESTYLE_SCALE_MODE:
358               trace('LINE_STYLE blend_mode:' + a[2]);
359               _playCanvas.pen.scaleMode = a[2];
360               break;
361             case GPLogger.LINESTYLE_CAPS:
362               trace('LINE_STYLE caps_mode:' + a[2]);
363               _playCanvas.pen.capsStyle = a[2];
364               break;
365             case GPLogger.LINESTYLE_JOINTS:
366               trace('LINE_STYLE joint_style:' + a[2]);
367               _playCanvas.pen.jointStyle = a[2];
368               break;
369             case GPLogger.LINESTYLE_MITER_LIMIT:
370               trace('LINE_STYLE miter_limit:' + a[2]);
371               _playCanvas.pen.miterLimit = a[2];
372               break;
373             case GPLogger.LINESTYLE_PIXEL_HINTING:
374               trace('LINE_STYLE pixel_hinting:' + a[2]);
375               _playCanvas.pen.pixelHinting = a[2];
376               break;
377             default:
378               Alert.show('未対応のラインスタイルです。');
379               break;
380             }
381             _playCanvas.setAndLogLineStyle();
382             break;
383           case GPLogger.ACTION_DRAW_SHAPE_ON_BITMAP:
384             trace('DRAW_SHAPE_ON_BITMAP');
385             _playCanvas.drawShapeOnBitmap();
386             // 高速化のためコメントアウト
387             // isBreak = true;
388             break;
389           case GPLogger.ACTION_UNDO:
390             trace('UNDO');
391             _playCanvas.undo();
392             isBreak = true;
393             break;
394           case GPLogger.ACTION_REDO:
395             trace('REDO');
396             _playCanvas.redo();
397             isBreak = true;
398             break;
399           case GPLogger.ACTION_BEGIN_FILL:
400             trace('BEGIN_FILL color:'+ a[1] + ' alpha:' + a[2]);
401             _playCanvas.beginFill(a[1], a[2]);
402             break;
403           case GPLogger.ACTION_END_FILL:
404             trace('END_FILL');
405             _playCanvas.endFill();
406             break;
407           case GPLogger.ACTION_DRAW_CIRCLE:
408             trace('DRAW_CIRCLE radius:' + a[1]);
409             _playCanvas.drawCircle(a[1]);
410             break;
411           case GPLogger.ACTION_FLOOD_FILL:
412             trace('FLOOD_FILL');
413             _playCanvas.floodFill();
414             break;
415           case ACTION_LAYER_NEW:
416             trace('LAYER_NEW');
417             _playCanvas.layerNew();
418             break;
419           case ACTION_LAYER_COPY:
420             trace('LAYER_COPY');
421             _playCanvas.layerCopy();
422             break;
423           case ACTION_LAYER_SWAP:
424             trace('LAYER_SWAP from:' + a[1] + ' to:' + a[2]);
425             _playCanvas.layerSwap(a[1], a[2]);
426             break;
427           case ACTION_LAYER_MERGE_WITH_BELOW:
428             trace('LAYER_MERGE_WITH_BELOW');
429             _playCanvas.layerMergeWithBelow();
430             break;
431           case ACTION_LAYER_REMOVE:
432             trace('LAYER_REMOVE');
433             _playCanvas.layerRemove();
434             break;
435           case ACTION_LAYER_CHANGE_TARGET:
436             trace('LAYER_CHANGE_TARGET target:' + a[1]);
437             _playCanvas.layerChangeTarget(a[1]);
438             break;
439           case ACTION_LAYER_CHANGE_VISIBLE:
440             trace('LAYER_CHANGE_VISIBLE target:' + a[1] + ' value:' + a[2]);
441             _playCanvas.layerChangeVisible(a[1], a[2]);
442             break;
443           case ACTION_LAYER_CHANGE_BLEND_MODE:
444             trace('LAYER_CHANGE_BLEND_MODE blendMode:' + a[1]);
445             _playCanvas.layerChangeBlendMode(a[1]);
446             break;         
447           default:
448             Alert.show('未対応のアクションです。');
449             break;
450           }
451           // LINETOだけSPEED分描画
452           if (isBreak) {
453             break;
454           }
455           preAction = action;
456         } else {
457           flash.utils.clearInterval(playLogIntervalId);
458           _playCanvas.completePlayLog();
459           break;
460         }
461       }
462     }
463    
464     public function read():Array {
465       var byte:uint;
466       var dx:int, dy:int;
467       var short:uint;
468       var obj:Object;
469       var obj2:Object;
470       var obj3:Object;
471      
472       try {
473         byte = readByte();
474         switch (byte) {
475         case ACTION_MOVETO:
476           dx = readShort();
477           dy = readShort();
478           preX += dx;
479           preY += dy;
480           return [ACTION_MOVETO, preX, preY];
481         case ACTION_LINETO:
482           dx = readShort();
483           dy = readShort();
484           preX += dx;
485           preY += dy;
486           return [ACTION_LINETO, preX, preY];
487         case ACTION_LINESTYLE:
488           dx = readByte(); // style type
489           switch (dx) {
490           case GPLogger.LINESTYLE_THICKNESS:
491             obj = readByte();
492             break;
493           case GPLogger.LINESTYLE_COLOR:
494             obj = readUInt();
495             break;
496           case GPLogger.LINESTYLE_ALPHA:
497           case GPLogger.LINESTYLE_MITER_LIMIT:
498             obj = readDouble();
499             break;
500           case GPLogger.LINESTYLE_BLEND_MODE:
501           case GPLogger.LINESTYLE_SCALE_MODE:
502           case GPLogger.LINESTYLE_CAPS:
503           case GPLogger.LINESTYLE_JOINTS:
504             obj = readUTF();
505             break;
506           case GPLogger.LINESTYLE_PIXEL_HINTING:
507             obj = readBoolean();
508             break;
509           default:
510             Alert.show('未対応のラインスタイルです。');
511             break;
512           }
513           return [ACTION_LINESTYLE, dx, obj];
514         case ACTION_DRAW_SHAPE_ON_BITMAP:
515           return [ACTION_DRAW_SHAPE_ON_BITMAP];
516         case ACTION_UNDO:
517           return [ACTION_UNDO];
518         case ACTION_REDO:
519           return [ACTION_REDO];
520         case ACTION_BEGIN_FILL:
521           obj = readUInt();
522           obj2 = readDouble();
523           return [ACTION_BEGIN_FILL, obj, obj2];
524         case ACTION_END_FILL:
525           return [ACTION_END_FILL];
526         case ACTION_DRAW_CIRCLE:
527           obj = readDouble();
528           return [ACTION_DRAW_CIRCLE, obj];
529         case ACTION_FLOOD_FILL:
530           return [ACTION_FLOOD_FILL];
531         case ACTION_LAYER_NEW:
532           return [ACTION_LAYER_NEW];
533         case ACTION_LAYER_COPY:
534           return [ACTION_LAYER_COPY];
535         case ACTION_LAYER_SWAP:
536           obj = readByte();
537           obj2 = readByte();
538           return [ACTION_LAYER_SWAP, obj, obj2];
539         case ACTION_LAYER_MERGE_WITH_BELOW:
540           return [ACTION_LAYER_MERGE_WITH_BELOW];
541         case ACTION_LAYER_REMOVE:
542           return [ACTION_LAYER_REMOVE];
543         case ACTION_LAYER_CHANGE_TARGET:
544           obj = readByte();
545           return [ACTION_LAYER_CHANGE_TARGET, obj];
546         case ACTION_LAYER_CHANGE_VISIBLE:
547           obj = readByte();
548           obj2 = readBoolean();
549           return [ACTION_LAYER_CHANGE_VISIBLE, obj, obj2];
550         case ACTION_LAYER_CHANGE_BLEND_MODE:
551           obj = readUTF();
552           return [ACTION_LAYER_CHANGE_BLEND_MODE, obj];
553         default:
554           if (byte & 0x80) {
555             if (byte & 0x40) {
556               // 7bit lineTo
557               log.position -= 1;
558               short = readShort();
559               dx = (short << 18) >> 25;
560               dy = (short << 25) >> 25;
561             } else {
562               // 3bit lineTo
563               dx = (byte << 26) >> 29;
564               dy = (byte << 29) >> 29;
565             }
566             preX += dx;
567             preY += dy;
568             return [ACTION_LINETO, preX, preY];
569           } else if (byte & 0x40) {
570             // 7bit moveTo
571             log.position -= 1;
572             short = readShort();
573             dx = (short << 18) >> 25;
574             dy = (short << 25) >> 25;
575             preX += dx;
576             preY += dy;
577             return [ACTION_MOVETO, preX, preY];
578           } else {
579             Alert.show('未対応のアクションです。');
580             // error
581           }
582         }
583       } catch (e:EOFError) {
584       }
585       return null;
586     }
587     public function resetPosition():void {
588       if (isCompress) {
589         log.uncompress();
590         isCompress = false;
591       }
592       log.position = 0;
593       readHeader();
594       preX = 0;
595       preY = 0;
596       logCount = 0;
597     }
598     public function compress():void {
599       if (!isCompress) {
600         log.compress();
601         isCompress = true;       
602       }
603     }
604     public function get password():String {
605       var pos:uint = log.position;
606       var e:Base64Encoder = new Base64Encoder();
607       log.compress();
608       e.encodeBytes(log);
609       log.uncompress();
610       log.position = pos;
611       return e.flush();
612     }
613     public static function deserialize(s:String):GPLogger {
614       var e:Base64Decoder = new Base64Decoder();
615       e.decode(s);
616       var b:ByteArray = e.toByteArray();
617       b.uncompress();
618       return new GPLogger(b);
619     }
620    
621     public function getCompressedLog():ByteArray {
622       compress();
623       return log;
624     }
625   }
626 }
Note: リポジトリブラウザについてのヘルプは TracBrowser を参照してください。