1 /*$
2 Copyright (C) 2013-2020 Azel.
3
4 This file is part of AzPainter.
5
6 AzPainter is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainter is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * UndoItem
22 *
23 * サブ関数、レイヤの読み書き実処理
24 *****************************************/
25
26 #include <stdio.h> //FILE*
27 #include <string.h> //strlen
28
29 #include "mDef.h"
30 #include "mRectBox.h"
31 #include "mUndo.h"
32 #include "mZlib.h"
33 #include "mUtil.h"
34
35 #include "defDraw.h"
36
37 #include "LayerList.h"
38 #include "LayerItem.h"
39 #include "defTileImage.h"
40 #include "TileImage.h"
41
42 #include "Undo.h"
43 #include "UndoMaster.h"
44 #include "UndoItem.h"
45
46
47 //-----------------------
48
49 /** レイヤ情報 (文字列は除く) */
50
51 typedef struct
52 {
53 uint8_t coltype, //255 でフォルダ
54 opacity,
55 alphamask,
56 blendmode;
57 uint32_t col,
58 flags;
59 }UndoLayerInfo;
60
61 /** レイヤ情報 (文字列含む) */
62
63 typedef struct
64 {
65 UndoLayerInfo i;
66 char *name,
67 *texture_path;
68 }UndoLayerInfo_str;
69
70
71 #define UNDOLAYERINFO_COLTYPE_FOLDER 255
72
73 //-----------------------
74
75 #define _UNDO g_app_undo
76
77 //-----------------------
78
79
80
81 //==================================
82 // レイヤ番号取得/セット
83 //==================================
84
85
86 /** レイヤ番号からレイヤ取得 */
87
UndoItem_getLayerFromNo(int no)88 LayerItem *UndoItem_getLayerFromNo(int no)
89 {
90 return LayerList_getItem_byPos_topdown(APP_DRAW->layerlist, no);
91 }
92
93 /** 親と相対位置のレイヤ番号からレイヤ取得 */
94
UndoItem_getLayerFromNo_forParent(int parent,int pos)95 LayerItem *UndoItem_getLayerFromNo_forParent(int parent,int pos)
96 {
97 LayerItem *item[2];
98
99 LayerList_getItems_fromPos(APP_DRAW->layerlist, item, parent, pos);
100
101 return item[1];
102 }
103
104 /** val にカレントレイヤの番号をセット */
105
UndoItem_setval_curlayer(UndoItem * p,int valno)106 void UndoItem_setval_curlayer(UndoItem *p,int valno)
107 {
108 p->val[valno] = LayerList_getItemPos(APP_DRAW->layerlist, APP_DRAW->curlayer);
109 }
110
111 /** val に指定レイヤの番号 (上から順) をセット */
112
UndoItem_setval_layerno(UndoItem * p,int valno,LayerItem * item)113 void UndoItem_setval_layerno(UndoItem *p,int valno,LayerItem *item)
114 {
115 p->val[valno] = LayerList_getItemPos(APP_DRAW->layerlist, item);
116 }
117
118 /** val に指定レイヤの親番号とレイヤ番号をセット */
119
UndoItem_setval_layerno_forParent(UndoItem * p,int valno,LayerItem * item)120 void UndoItem_setval_layerno_forParent(UndoItem *p,int valno,LayerItem *item)
121 {
122 LayerList_getItemPos_forParent(APP_DRAW->layerlist, item,
123 p->val + valno, p->val + valno + 1);
124 }
125
126
127 //==============================
128 // レイヤ読み書き sub
129 //==============================
130
131
132 /** 文字列書込み */
133
_write_string(UndoItem * p,const char * text)134 static mBool _write_string(UndoItem *p,const char *text)
135 {
136 uint16_t len;
137
138 len = (text)? strlen(text): 0;
139
140 return (UndoItem_write(p, &len, 2)
141 && UndoItem_write(p, text, len));
142 }
143
144 /** 文字列読み込み */
145
_read_string(UndoItem * p,char ** dst)146 static mBool _read_string(UndoItem *p,char **dst)
147 {
148 char *pc;
149 uint16_t len;
150
151 *dst = NULL;
152
153 //長さ
154
155 if(!UndoItem_read(p, &len, 2)) return FALSE;
156
157 //空文字列
158
159 if(len == 0) return TRUE;
160
161 //文字列
162
163 pc = (char *)mMalloc(len + 1, FALSE);
164 if(!pc) return FALSE;
165
166 if(!UndoItem_read(p, pc, len)) return FALSE;
167
168 pc[len] = 0;
169
170 *dst = pc;
171
172 return TRUE;
173 }
174
175 /** レイヤ情報解放 */
176
_free_layerinfo(UndoLayerInfo_str * p)177 static void _free_layerinfo(UndoLayerInfo_str *p)
178 {
179 mFree(p->name);
180 mFree(p->texture_path);
181 }
182
183 /** レイヤ情報読み込み */
184
_read_layerinfo(UndoItem * p,UndoLayerInfo_str * info)185 static mBool _read_layerinfo(UndoItem *p,UndoLayerInfo_str *info)
186 {
187 if(_read_string(p, &info->name)
188 && _read_string(p, &info->texture_path)
189 && UndoItem_read(p, &info->i, sizeof(UndoLayerInfo)))
190 return TRUE;
191 else
192 {
193 _free_layerinfo(info);
194 return FALSE;
195 }
196 }
197
198 /** レイヤ情報をセット */
199
_set_layerinfo(LayerItem * item,UndoLayerInfo_str * info)200 static void _set_layerinfo(LayerItem *item,UndoLayerInfo_str *info)
201 {
202 item->coltype = (info->i.coltype == UNDOLAYERINFO_COLTYPE_FOLDER)? 0: info->i.coltype;
203 item->blendmode = info->i.blendmode;
204 item->opacity = info->i.opacity;
205 item->alphamask = info->i.alphamask;
206 item->col = info->i.col;
207 item->flags = info->i.flags;
208
209 mStrdup_ptr(&item->name, info->name);
210
211 //テクスチャ
212
213 LayerItem_setTexture(item, info->texture_path);
214 }
215
216 /** レイヤ情報読み込み&レイヤ作成 */
217
_create_restore_layer(UndoItem * p,int parent_pos,int rel_pos,int * is_folder)218 static LayerItem *_create_restore_layer(UndoItem *p,int parent_pos,int rel_pos,int *is_folder)
219 {
220 UndoLayerInfo_str info;
221 LayerItem *item;
222
223 //レイヤ情報読み込み
224
225 if(!_read_layerinfo(p, &info))
226 return NULL;
227
228 //レイヤ作成
229
230 item = LayerList_addLayer_pos(APP_DRAW->layerlist, parent_pos, rel_pos);
231
232 //情報をセット
233
234 if(item) _set_layerinfo(item, &info);
235
236 _free_layerinfo(&info);
237
238 //フォルダか
239
240 *is_folder = (info.i.coltype == UNDOLAYERINFO_COLTYPE_FOLDER);
241
242 return item;
243 }
244
245
246 //==============================
247 // レイヤ情報のみ
248 //==============================
249
250
251 /** 単体レイヤ情報書き込み
252 *
253 * 新規レイヤ (空) のリドゥデータセット時 */
254
UndoItem_setdat_layerInfo(UndoItem * p)255 mBool UndoItem_setdat_layerInfo(UndoItem *p)
256 {
257 LayerItem *li;
258 int size;
259 mBool ret;
260
261 //レイヤ
262
263 li = UndoItem_getLayerFromNo_forParent(p->val[0], p->val[1]);
264 if(!li) return FALSE;
265
266 //書き込み
267
268 size = 2 + mStrlen(li->name) + 2 + mStrlen(li->texture_path) + sizeof(UndoLayerInfo);
269
270 if(!UndoItem_alloc(p, size)
271 || !UndoItem_openWrite(p))
272 return FALSE;
273
274 ret = UndoItem_writeLayerInfo(p, li);
275
276 UndoItem_closeWrite(p);
277
278 return ret;
279 }
280
281 /** 新規レイヤ (空) の復元 */
282
UndoItem_restore_newLayerEmpty(UndoItem * p)283 mBool UndoItem_restore_newLayerEmpty(UndoItem *p)
284 {
285 LayerItem *item;
286 TileImage *img;
287 int is_folder;
288
289 if(!UndoItem_openRead(p)) return FALSE;
290
291 //レイヤ情報読み込み&作成
292
293 item = _create_restore_layer(p, p->val[0], p->val[1], &is_folder);
294 if(!item) goto ERR;
295
296 //イメージ作成
297
298 if(!is_folder)
299 {
300 img = TileImage_new(item->coltype, 1, 1);
301 if(!img) goto ERR;
302
303 LayerItem_replaceImage(item, img);
304
305 TileImage_setImageColor(img, item->col);
306 }
307
308 return TRUE;
309
310 ERR:
311 UndoItem_closeRead(p);
312 return FALSE;
313 }
314
315
316 //==============================
317 // レイヤ読み書き 開始/終了
318 //==============================
319 /*
320 * - レイヤ書き込み先は常にファイル。
321 * - 読み書きを開始した場合、処理失敗時にも必ず終了させること。
322 */
323
324
325 /** レイヤ書き込み開始 */
326
UndoItem_beginWriteLayer(UndoItem * p)327 mBool UndoItem_beginWriteLayer(UndoItem *p)
328 {
329 //zlib
330
331 _UNDO->zenc = mZlibEncodeNew_simple(16 * 1024, 4);
332 if(!_UNDO->zenc) return FALSE;
333
334 //書き込み開く
335
336 if(!UndoItem_alloc(p, UNDO_ALLOC_FILE)
337 || !UndoItem_openWrite(p))
338 {
339 mZlibEncodeFree(_UNDO->zenc);
340 return FALSE;
341 }
342
343 mZlibEncodeSetIO_stdio(_UNDO->zenc, _UNDO->writefp);
344
345 return TRUE;
346 }
347
348 /** レイヤ書き込み終了 */
349
UndoItem_endWriteLayer(UndoItem * p)350 void UndoItem_endWriteLayer(UndoItem *p)
351 {
352 UndoItem_closeWrite(p);
353
354 mZlibEncodeFree(_UNDO->zenc);
355 }
356
357 /** レイヤ読み込み開始 */
358
UndoItem_beginReadLayer(UndoItem * p)359 mBool UndoItem_beginReadLayer(UndoItem *p)
360 {
361 //zlib
362
363 _UNDO->zdec = mZlibDecodeNew(16 * 1024, 15);
364 if(!_UNDO->zdec) return FALSE;
365
366 //開く
367
368 if(!UndoItem_openRead(p))
369 {
370 mZlibDecodeFree(_UNDO->zdec);
371 return FALSE;
372 }
373
374 mZlibDecodeSetIO_stdio(_UNDO->zdec, _UNDO->readfp);
375
376 return TRUE;
377 }
378
379 /** レイヤ読み込み終了 */
380
UndoItem_endReadLayer(UndoItem * p)381 void UndoItem_endReadLayer(UndoItem *p)
382 {
383 UndoItem_closeRead(p);
384
385 mZlibDecodeFree(_UNDO->zdec);
386 }
387
388
389 //==================================
390 // レイヤ書き込み
391 //==================================
392
393
394 /** レイヤ情報とイメージ書き込み */
395
UndoItem_writeLayerInfoAndImage(UndoItem * p,LayerItem * item)396 mBool UndoItem_writeLayerInfoAndImage(UndoItem *p,LayerItem *item)
397 {
398 return (UndoItem_writeLayerInfo(p, item)
399 && UndoItem_writeTileImage(p, item->img));
400 }
401
402 /** レイヤ情報書き込み */
403
UndoItem_writeLayerInfo(UndoItem * p,LayerItem * li)404 mBool UndoItem_writeLayerInfo(UndoItem *p,LayerItem *li)
405 {
406 UndoLayerInfo info;
407
408 //レイヤ名、テクスチャパス
409
410 if(!_write_string(p, li->name)
411 || !_write_string(p, li->texture_path))
412 return FALSE;
413
414 //情報
415
416 info.coltype = (li->img)? li->coltype: UNDOLAYERINFO_COLTYPE_FOLDER;
417 info.opacity = li->opacity;
418 info.blendmode = li->blendmode;
419 info.alphamask = li->alphamask;
420 info.col = li->col;
421 info.flags = li->flags;
422
423 return UndoItem_write(p, &info, sizeof(UndoLayerInfo));
424 }
425
426 /** タイルイメージ書き込み */
427
428 /* [TileImageInfo]
429 * [圧縮サイズ]
430 * [タイルイメージ]
431 * 2byte: タイルX位置 (X,Y が 0xffff で終了)
432 * 2byte: タイルY位置
433 * タイルデータ
434 */
435
UndoItem_writeTileImage(UndoItem * p,TileImage * img)436 mBool UndoItem_writeTileImage(UndoItem *p,TileImage *img)
437 {
438 TileImageInfo info;
439 mZlibEncode *enc = _UNDO->zenc;
440 uint8_t **pptile;
441 int ix,iy,tw,th;
442 uint16_t tpos[2];
443
444 //NULL = フォルダなので、成功とする
445
446 if(!img) return TRUE;
447
448 //タイルイメージ情報
449
450 TileImage_getInfo(img, &info);
451
452 if(!UndoItem_write(p, &info, sizeof(TileImageInfo)))
453 return FALSE;
454
455 //圧縮サイズ (仮)
456
457 if(!UndoItem_writeEncSize_temp())
458 return FALSE;
459
460 //各タイル
461
462 mZlibEncodeReset(enc);
463
464 pptile = img->ppbuf;
465 tw = img->tilew;
466 th = img->tileh;
467
468 for(iy = 0; iy < th; iy++)
469 {
470 for(ix = 0; ix < tw; ix++, pptile++)
471 {
472 if(*pptile)
473 {
474 //タイル位置、タイルデータ
475
476 tpos[0] = ix;
477 tpos[1] = iy;
478
479 if(!mZlibEncodeSend(enc, tpos, 4)
480 || !mZlibEncodeSend(enc, *pptile, img->tilesize))
481 return FALSE;
482 }
483 }
484 }
485
486 //終了
487
488 tpos[0] = 0xffff;
489 tpos[1] = 0xffff;
490
491 if(!mZlibEncodeSend(enc, tpos, 4)
492 || !mZlibEncodeFlushEnd(enc))
493 return FALSE;
494
495 //圧縮サイズ
496
497 UndoItem_writeEncSize_real(mZlibEncodeGetWriteSize(enc));
498
499 return TRUE;
500 }
501
502
503 //==================================
504 // レイヤ復元
505 //==================================
506
507
508 /** レイヤを一つ復元
509 *
510 * @param rcupdate 更新範囲が追加される */
511
UndoItem_readLayer(UndoItem * p,int parent_pos,int rel_pos,mRect * rcupdate)512 mBool UndoItem_readLayer(UndoItem *p,int parent_pos,int rel_pos,mRect *rcupdate)
513 {
514 LayerItem *item;
515 mRect rc;
516 int is_folder;
517
518 //レイヤ情報読み込み&作成
519
520 item = _create_restore_layer(p, parent_pos, rel_pos, &is_folder);
521 if(!item) return FALSE;
522
523 //イメージ作成 & 読み込み
524
525 if(!is_folder)
526 {
527 if(!UndoItem_readLayerImage(p, item)) return FALSE;
528
529 //更新範囲
530 /* [!] 複数レイヤの復元時は、
531 * レイヤが非表示状態でも範囲として必要な場合があるので (結合時など)
532 * LayerItem_getVisibleImageRect() で取得しないこと。 */
533
534 if(TileImage_getHaveImageRect_pixel(item->img, &rc, NULL))
535 mRectUnion(rcupdate, &rc);
536 }
537
538 return TRUE;
539 }
540
541 /** 既存のレイヤに情報とイメージを上書き復元
542 *
543 * @param rcupdate イメージのタイルがある範囲を追加 */
544
UndoItem_readLayerOverwrite(UndoItem * p,LayerItem * item,mRect * rcupdate)545 mBool UndoItem_readLayerOverwrite(UndoItem *p,LayerItem *item,mRect *rcupdate)
546 {
547 UndoLayerInfo_str info;
548 mRect rc;
549
550 //レイヤ情報 読み込み&セット
551
552 if(!_read_layerinfo(p, &info)) return FALSE;
553
554 _set_layerinfo(item, &info);
555
556 _free_layerinfo(&info);
557
558 //イメージ
559
560 if(!UndoItem_readLayerImage(p, item))
561 return FALSE;
562
563 //範囲追加
564
565 if(TileImage_getHaveImageRect_pixel(item->img, &rc, NULL))
566 mRectUnion(rcupdate, &rc);
567
568 return TRUE;
569 }
570
571 /** レイヤイメージの復元
572 *
573 * - item の各情報は設定済みであること。
574 * - 既存のイメージを置き換える場合もあり。 */
575
UndoItem_readLayerImage(UndoItem * p,LayerItem * item)576 mBool UndoItem_readLayerImage(UndoItem *p,LayerItem *item)
577 {
578 TileImageInfo info;
579 TileImage *img;
580 mZlibDecode *dec = _UNDO->zdec;
581 uint8_t *tile;
582 uint16_t tpos[2];
583 uint32_t encsize;
584
585 if(!item) return FALSE;
586
587 //イメージ情報
588
589 if(!UndoItem_read(p, &info, sizeof(TileImageInfo)))
590 return FALSE;
591
592 //既存イメージは削除
593
594 TileImage_free(item->img);
595 item->img = NULL;
596
597 //イメージ作成
598
599 img = TileImage_newFromInfo(item->coltype, &info);
600 if(!img) return FALSE;
601
602 item->img = img;
603
604 TileImage_setImageColor(img, item->col);
605
606 //------ タイル読み込み
607
608 //圧縮サイズ
609
610 if(!UndoItem_read(p, &encsize, 4)) return FALSE;
611
612 mZlibDecodeReset(dec);
613 mZlibDecodeSetInSize(dec, encsize);
614
615 //
616
617 while(1)
618 {
619 //タイル位置
620
621 if(mZlibDecodeRead(dec, tpos, 4)) return FALSE;
622
623 if(tpos[0] == 0xffff && tpos[1] == 0xffff) break;
624
625 //タイル作成
626
627 tile = TileImage_getTileAlloc_atpos(img, tpos[0], tpos[1], FALSE);
628 if(!tile) return FALSE;
629
630 //タイルデータ
631
632 if(mZlibDecodeRead(dec, tile, img->tilesize))
633 return FALSE;
634 }
635
636 if(mZlibDecodeReadEnd(dec)) return FALSE;
637
638 return TRUE;
639 }
640
641