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