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  * ブラシリストデータ
22  *****************************************/
23 /*
24  * [BrushList::cur]
25  *
26  *  現在の描画用ブラシパラメータのデータ。
27  *  ブラシ描画時はこのパラメータを使う。
28  *  ブラシの選択が変更されたらここにデータがコピーされる。
29  *  ウィジェット上で値が変更されたら、常にこの値も更新する。
30  *
31  * [BrushList::dp_cur, dp_reg]
32  *
33  *  描画時に使われるパラメータ値。
34  *  ブラシ選択変更時や項目値の変更時は、常にこの値も更新する。
35  */
36 
37 #include <stdio.h>
38 
39 #include "mDef.h"
40 #include "mList.h"
41 #include "mUtilStdio.h"
42 #include "mUtilStr.h"
43 #include "mStr.h"
44 #include "mGui.h"
45 
46 #include "BrushList.h"
47 #include "BrushItem.h"
48 #include "BrushDrawParam.h"
49 #include "BrushSizeList.h"
50 
51 #include "MaterialImgList.h"
52 #include "defPixelMode.h"
53 #include "defMacros.h"
54 
55 
56 //-------------------
57 
58 typedef struct
59 {
60 	mList list;		//グループリスト
61 
62 	BrushItem cur,		//編集用の現在データ
63 		*selitem,		//選択ブラシ
64 		*regitem,		//登録ブラシ
65 		*toggleitem;	//ブラシ切り替え用
66 
67 	BrushDrawParam dp_cur,
68 		dp_reg,
69 		dp_filter;		//フィルタの漫画描画用
70 
71 	int reg_radius;		//キャンバスキーの「登録ブラシのサイズを変更」時の一時的な現在半径値
72 						//0 でなし
73 }BrushList;
74 
75 static BrushList *g_dat = NULL;
76 
77 //-------------------
78 
79 #define GROUP_MAXNUM		100
80 #define BRUSHITEM_MAXNUM 	500
81 
82 //-------------------
83 
84 
85 
86 //*********************************************
87 // BrushGroupItem : グループアイテム
88 //*********************************************
89 
90 
91 /** 破棄ハンドラ */
92 
_groupitem_destroy(mListItem * li)93 static void _groupitem_destroy(mListItem *li)
94 {
95 	BrushGroupItem *p = BRUSHGROUPITEM(li);
96 
97 	//ブラシデータリスト
98 	mListDeleteAll(&p->list);
99 
100 	//名前
101 	mFree(p->name);
102 }
103 
104 /** 先頭ブラシアイテム取得 */
105 
BrushGroup_getTopItem(BrushGroupItem * p)106 BrushItem *BrushGroup_getTopItem(BrushGroupItem *p)
107 {
108 	return (BrushItem *)(p->list.top);
109 }
110 
111 /** グループ内のインデックス番号からアイテム取得 */
112 
BrushGroup_getItemAtIndex(BrushGroupItem * p,int index)113 BrushItem *BrushGroup_getItemAtIndex(BrushGroupItem *p,int index)
114 {
115 	return (BrushItem *)mListGetItemByIndex(&p->list, index);
116 }
117 
118 /** 表示時の縦アイテム数取得 */
119 
BrushGroup_getViewVertNum(BrushGroupItem * p)120 int BrushGroup_getViewVertNum(BrushGroupItem *p)
121 {
122 	return (p->list.num + p->colnum - 1) / p->colnum;
123 }
124 
125 
126 
127 //*******************************************
128 // BrushList : ブラシリスト
129 //*******************************************
130 
131 
132 //==========================
133 // sub
134 //==========================
135 
136 
137 /** 選択アイテムが連動保存タイプか */
138 
_is_sel_linksave()139 static mBool _is_sel_linksave()
140 {
141 	return (g_dat->selitem && (g_dat->selitem->flags & BRUSHITEM_F_AUTO_SAVE));
142 }
143 
144 /** BrushDrawParam:登録ブラシ用の画像を解放 */
145 
_release_drawparam_reg_image()146 static void _release_drawparam_reg_image()
147 {
148 	MaterialImgList_releaseImage(MATERIALIMGLIST_TYPE_BRUSH, g_dat->dp_reg.img_shape);
149 	MaterialImgList_releaseImage(MATERIALIMGLIST_TYPE_TEXTURE, g_dat->dp_reg.img_texture);
150 
151 	g_dat->dp_reg.img_shape = NULL;
152 	g_dat->dp_reg.img_texture = NULL;
153 }
154 
155 /** 選択アイテム変更時の更新 */
156 
_update_selitem(mBool set_regsize)157 static void _update_selitem(mBool set_regsize)
158 {
159 	//編集用にデータコピー
160 
161 	BrushItem_copy(&g_dat->cur, g_dat->selitem);
162 
163 	/* 登録ブラシに変更された時、
164 	 * キャンバスキーでのブラシサイズ変更を編集用データに適用させる。
165 	 * [!] 保存せずに選択を変更すると元に戻る。 */
166 
167 	if(g_dat->selitem == g_dat->regitem && g_dat->reg_radius)
168 	{
169 		if(set_regsize)
170 			g_dat->cur.radius = g_dat->reg_radius;
171 
172 		g_dat->reg_radius = 0;
173 	}
174 
175 	//描画用パラメータセット
176 
177 	BrushList_setBrushDrawParam(FALSE);
178 }
179 
180 /** 描画用の形状の硬さ取得 */
181 
_get_drawparam_shape_hard(int val)182 static double _get_drawparam_shape_hard(int val)
183 {
184 	if(val <= 50)
185 		return (-0.4 - 0.7) * (val * 0.02) + 0.7;
186 	else
187 		return (-5 + 0.4) * ((val - 50) * 0.02) - 0.4;
188 }
189 
190 /** 描画用の形状荒さ取得 */
191 
_get_drawparam_rough(int val)192 static int _get_drawparam_rough(int val)
193 {
194 	if(val == 0)
195 		return 0;
196 	else if(val <= 50)
197 		return val * 2;
198 	else if(val <= 80)
199 		return 100 + (val - 50) * 10;
200 	else if(val <= 90)
201 		return 300 + (val - 80) * 400;
202 	else
203 		return 5000 + (val - 90) * 1000;
204 }
205 
206 /** 描画用の筆圧補正値セット */
207 
_set_drawparam_pressure(BrushDrawParam * p,int type,uint32_t val)208 static void _set_drawparam_pressure(BrushDrawParam *p,int type,uint32_t val)
209 {
210 	int i,pt[4];
211 	double d[4];
212 
213 	switch(type)
214 	{
215 		//曲線
216 		case 0:
217 			if(val == 100)
218 				p->flags &= ~BRUSHDP_F_PRESSURE;
219 			else
220 			{
221 				p->flags |= BRUSHDP_F_PRESSURE;
222 				p->pressure_val[0] = val * 0.01;
223 			}
224 			break;
225 
226 		//線形1点
227 		case 1:
228 			for(i = 0; i < 2; i++, val >>= 8)
229 			{
230 				pt[i] = (uint8_t)val;
231 				d[i] = pt[i] * 0.01;
232 			}
233 
234 			if((pt[0] == 0 && pt[1] == 0) || (pt[0] == 100 && pt[1] == 100))
235 				p->flags &= ~BRUSHDP_F_PRESSURE;
236 			else
237 			{
238 				p->flags |= BRUSHDP_F_PRESSURE;
239 
240 				p->pressure_val[0] = d[0];
241 				p->pressure_val[1] = d[1];
242 				p->pressure_val[2] = 1 - d[0];
243 				p->pressure_val[3] = 1 - d[1];
244 			}
245 			break;
246 
247 		//線形2点
248 		default:
249 			for(i = 0; i < 4; i++, val >>= 8)
250 			{
251 				pt[i] = (uint8_t)val;
252 				d[i] = pt[i] * 0.01;
253 
254 				p->pressure_val[i] = d[i];
255 			}
256 
257 			p->pressure_val[4] = d[2] - d[0];	//in2 - in1
258 			p->pressure_val[5] = d[3] - d[1];	//out2 - out1
259 			p->pressure_val[6] = 1 - d[2];		//1 - in2
260 			p->pressure_val[7] = 1 - d[3];		//1 - out2
261 
262 			p->flags |= BRUSHDP_F_PRESSURE;
263 			break;
264 	}
265 }
266 
267 
268 //==========================
269 //
270 //==========================
271 
272 
273 /** 解放 */
274 
BrushList_free()275 void BrushList_free()
276 {
277 	//編集用ブラシデータ
278 	BrushItem_destroy_handle(M_LISTITEM(&g_dat->cur));
279 
280 	mListDeleteAll(&g_dat->list);
281 
282 	mFree(g_dat);
283 }
284 
285 /** 確保 */
286 
BrushList_new()287 mBool BrushList_new()
288 {
289 	//確保
290 
291 	g_dat = (BrushList *)mMalloc(sizeof(BrushList), TRUE);
292 	if(!g_dat) return FALSE;
293 
294 	//デフォルト値セット
295 
296 	BrushItem_setDefault(&g_dat->cur);
297 
298 	BrushList_setBrushDrawParam(FALSE);
299 
300 	return TRUE;
301 }
302 
303 
304 //========================
305 // 取得
306 //========================
307 
308 
309 /** グループ数取得 */
310 
BrushList_getGroupNum()311 int BrushList_getGroupNum()
312 {
313 	return g_dat->list.num;
314 }
315 
316 /** 先頭グループ取得 */
317 
BrushList_getTopGroup()318 BrushGroupItem *BrushList_getTopGroup()
319 {
320 	return BRUSHGROUPITEM(g_dat->list.top);
321 }
322 
323 /** 編集用ブラシ取得 */
324 
BrushList_getEditItem()325 BrushItem *BrushList_getEditItem()
326 {
327 	return &g_dat->cur;
328 }
329 
330 /** 選択ブラシ取得 */
331 
BrushList_getSelItem()332 BrushItem *BrushList_getSelItem()
333 {
334 	return g_dat->selitem;
335 }
336 
337 /** 登録ブラシ取得 */
338 
BrushList_getRegisteredItem()339 BrushItem *BrushList_getRegisteredItem()
340 {
341 	return g_dat->regitem;
342 }
343 
344 /** 描画開始時、使用するブラシアイテムと描画パラメータ取得
345  *
346  * @param ppparam NULL で取得しない */
347 
BrushList_getDrawInfo(BrushItem ** ppitem,BrushDrawParam ** ppparam,mBool registered)348 void BrushList_getDrawInfo(
349 	BrushItem **ppitem,BrushDrawParam **ppparam,mBool registered)
350 {
351 	BrushList *p = g_dat;
352 
353 	if(registered && p->regitem && p->selitem != p->regitem)
354 	{
355 		//登録ブラシ (現在の選択 = 登録ブラシの場合は除く)
356 
357 		*ppitem = p->regitem;
358 		if(ppparam) *ppparam = &p->dp_reg;
359 	}
360 	else
361 	{
362 		//編集用データ
363 
364 		*ppitem = &p->cur;
365 		if(ppparam) *ppparam = &p->dp_cur;
366 	}
367 }
368 
369 /** フィルタ描画用のパラメータ取得 (漫画用、線描画)
370  *
371  * 通常円形(硬さ最大)、濃度最大、間隔 0.4 */
372 
BrushList_getBrushDrawParam_forFilter()373 BrushDrawParam *BrushList_getBrushDrawParam_forFilter()
374 {
375 	BrushDrawParam *p = &g_dat->dp_filter;
376 
377 	mMemzero(p, sizeof(BrushDrawParam));
378 
379 	p->opacity = 1;
380 	p->interval = 0.4;
381 	p->flags = BRUSHDP_F_SHAPE_HARD_MAX;
382 
383 	return p;
384 }
385 
386 /** キャンバスキーのブラシサイズ変更時の情報取得
387  *
388  * @return 現在の半径値 */
389 
BrushList_getChangeBrushSizeInfo(BrushItem ** ppitem,mBool registered)390 int BrushList_getChangeBrushSizeInfo(BrushItem **ppitem,mBool registered)
391 {
392 	BrushItem *item;
393 
394 	BrushList_getDrawInfo(&item, NULL, registered);
395 
396 	*ppitem = item;
397 
398 	if(item == &g_dat->cur)
399 		//編集データ
400 		return item->radius;
401 	else
402 	{
403 		//登録ブラシ (カレントでない場合)
404 		/* 前回のブラシサイズ変更時の値があればそれを使う */
405 
406 		if(g_dat->reg_radius)
407 			return g_dat->reg_radius;
408 		else
409 			return item->radius;
410 	}
411 }
412 
413 
414 //======================
415 // セット
416 //======================
417 
418 
419 /** 選択アイテムセット
420  *
421  * @param item  NULL で選択なしに
422  * @return 選択が変更されたか */
423 
BrushList_setSelItem(BrushItem * item)424 mBool BrushList_setSelItem(BrushItem *item)
425 {
426 	BrushList *p = g_dat;
427 
428 	if(item == p->selitem)
429 		return FALSE;
430 	else
431 	{
432 		/* 現在の選択が登録ブラシで、別のブラシに変わる場合、
433 		 * 登録ブラシの描画用パラメータを確定 */
434 
435 		if(p->regitem && p->selitem == p->regitem)
436 			BrushList_setBrushDrawParam(TRUE);
437 
438 		//選択変更
439 
440 		p->toggleitem = p->selitem;
441 
442 		p->selitem = item;
443 
444 		if(item) _update_selitem(TRUE);
445 
446 		return TRUE;
447 	}
448 }
449 
450 /** 登録ブラシセット
451  *
452  * @param item  NULL で解除 */
453 
BrushList_setRegisteredItem(BrushItem * item)454 void BrushList_setRegisteredItem(BrushItem *item)
455 {
456 	BrushList *p = g_dat;
457 
458 	if(item != p->regitem)
459 	{
460 		/* 現在の BrushDrawParam の登録ブラシ用データを解放。
461 		 *
462 		 * [!] item != NULL なら BrushList_setBrushDrawParam() 時に
463 		 *     行われるので必要ないが、item == NULL の場合は必要なので実行しておく */
464 
465 		_release_drawparam_reg_image();
466 
467 		p->regitem = item;
468 		p->reg_radius = 0;
469 
470 		if(item) BrushList_setBrushDrawParam(TRUE);
471 	}
472 }
473 
474 /** 直前のブラシと切り替え */
475 
BrushList_toggleLastItem()476 mBool BrushList_toggleLastItem()
477 {
478 	BrushList *p = g_dat;
479 
480 	if(p->toggleitem)
481 		return BrushList_setSelItem(p->toggleitem);
482 	else
483 		return FALSE;
484 }
485 
486 /** 選択ブラシを前後に移動 */
487 
BrushList_moveSelect(mBool next)488 mBool BrushList_moveSelect(mBool next)
489 {
490 	BrushItem *pi = g_dat->selitem;
491 
492 	if(pi)
493 	{
494 		if(next)
495 			pi = BRUSHITEM(pi->i.next);
496 		else
497 			pi = BRUSHITEM(pi->i.prev);
498 
499 		if(pi)
500 			return BrushList_setSelItem(pi);
501 	}
502 
503 	return FALSE;
504 }
505 
506 /** ブラシデータから描画用パラメータセット
507  *
508  * @param registered 登録ブラシ用にセット。FALSE でカレントデータ */
509 
BrushList_setBrushDrawParam(mBool registered)510 void BrushList_setBrushDrawParam(mBool registered)
511 {
512 	BrushItem *pi;
513 	BrushDrawParam *pd;
514 
515 	if(registered)
516 	{
517 		pd = &g_dat->dp_reg;
518 		pi = g_dat->regitem;
519 
520 		//登録ブラシの画像解放
521 
522 		_release_drawparam_reg_image();
523 	}
524 	else
525 		pd = &g_dat->dp_cur, pi = &g_dat->cur;
526 
527 	//--------
528 
529 	pd->radius = pi->radius * 0.1;
530 	pd->opacity = pi->opacity * 0.01;
531 	pd->min_size = pi->min_size * 0.001;
532 	pd->min_opacity = pi->min_opacity * 0.001;
533 	pd->interval_src = pi->interval * 0.01;
534 
535 	//
536 
537 	pd->flags = 0;
538 
539 	if(!(pi->flags & BRUSHITEM_F_ANTIALIAS)) pd->flags |= BRUSHDP_F_NO_ANTIALIAS;
540 	if(pi->flags & BRUSHITEM_F_CURVE) pd->flags |= BRUSHDP_F_CURVE;
541 
542 	//矩形上書き
543 
544 	if(pi->pixelmode == PIXELMODE_OVERWRITE_SQUARE)
545 		pd->flags |= BRUSHDP_F_OVERWRITE_TP;
546 
547 	//ランダム
548 
549 	if(pi->rand_size_min != 1000)
550 	{
551 		pd->flags |= BRUSHDP_F_RANDOM_SIZE;
552 		pd->random_size_min = pi->rand_size_min * 0.001;
553 	}
554 
555 	if(pi->rand_pos_range)
556 	{
557 		pd->flags |= BRUSHDP_F_RANDOM_POS;
558 		pd->random_pos_len = pi->rand_pos_range * 0.02;
559 	}
560 
561 	//水彩
562 
563 	if(pi->type == BRUSHITEM_TYPE_WATER)
564 		pd->flags |= BRUSHDP_F_WATER;
565 
566 	pd->water_param[0] = pi->water_param[0] * 0.001;
567 	pd->water_param[1] = pi->water_param[1] * 0.001;
568 	pd->water_param[2] = pi->water_param[2] * 0.001;
569 
570 	//ブラシ形状
571 
572 	pd->shape_hard = _get_drawparam_shape_hard(pi->hardness);
573 	pd->rough = _get_drawparam_rough(pi->roughness);
574 
575 	if(pi->hardness == 100)
576 		pd->flags |= BRUSHDP_F_SHAPE_HARD_MAX;
577 
578 	pd->angle = (pi->rotate_angle << 9) / 360;  //0-511
579 	pd->angle_random = (pi->rotate_rand_w << 8) / 180;
580 
581 	if(pi->flags & BRUSHITEM_F_ROTATE_TRAVELLING_DIR)
582 		pd->flags |= BRUSHDP_F_TRAVELLING_DIR;
583 
584 	//筆圧
585 
586 	pd->pressure_type = pi->pressure_type;
587 
588 	_set_drawparam_pressure(pd, pi->pressure_type, pi->pressure_val);
589 
590 	//画像
591 	//[!] 登録ブラシの場合は常に画像を保持する
592 
593 	pd->img_shape = MaterialImgList_getImage(MATERIALIMGLIST_TYPE_BRUSH_SHAPE,
594 		pi->shape_path, registered);
595 
596 	pd->img_texture = MaterialImgList_getImage(MATERIALIMGLIST_TYPE_BRUSH_TEXTURE,
597 		pi->texture_path, registered);
598 }
599 
600 
601 //======================
602 // コマンド
603 //======================
604 
605 
606 /** 新規ブラシ作成 */
607 
BrushList_newBrush(BrushGroupItem * group)608 BrushItem *BrushList_newBrush(BrushGroupItem *group)
609 {
610 	BrushItem *pi;
611 
612 	if(group->list.num >= BRUSHITEM_MAXNUM) return NULL;
613 
614 	pi = (BrushItem *)mListAppendNew(&group->list, sizeof(BrushItem), BrushItem_destroy_handle);
615 	if(pi)
616 	{
617 		pi->group = group;
618 
619 		BrushItem_setDefault(pi);
620 	}
621 
622 	return pi;
623 }
624 
625 /** 新規グループ */
626 
BrushList_newGroup(const char * name,int colnum)627 BrushGroupItem *BrushList_newGroup(const char *name,int colnum)
628 {
629 	BrushGroupItem *pg;
630 
631 	if(g_dat->list.num >= GROUP_MAXNUM) return NULL;
632 
633 	pg = (BrushGroupItem *)mListAppendNew((mList *)g_dat, sizeof(BrushGroupItem), _groupitem_destroy);
634 	if(pg)
635 	{
636 		pg->name = mStrdup(name);
637 		pg->colnum = colnum;
638 		pg->expand = 1;
639 	}
640 
641 	return pg;
642 }
643 
644 /** グループを上下に移動 */
645 
BrushList_moveGroup_updown(BrushGroupItem * group,mBool up)646 void BrushList_moveGroup_updown(BrushGroupItem *group,mBool up)
647 {
648 	mListMoveUpDown((mList *)g_dat, M_LISTITEM(group), up);
649 }
650 
651 /** グループを削除 */
652 
BrushList_deleteGroup(BrushGroupItem * group)653 void BrushList_deleteGroup(BrushGroupItem *group)
654 {
655 	BrushList *p = g_dat;
656 
657 	//このグループ内に選択ブラシがある場合、選択ブラシをなしに
658 
659 	if(p->selitem && p->selitem->group == group)
660 		BrushList_setSelItem(NULL);
661 
662 	//このグループ内に登録ブラシがある場合、登録ブラシを解除
663 
664 	if(p->regitem && p->regitem->group == group)
665 		BrushList_setRegisteredItem(NULL);
666 
667 	//このグループ内に切り替えブラシがある場合
668 
669 	if(p->toggleitem && p->toggleitem->group == group)
670 		p->toggleitem = NULL;
671 
672 	//削除
673 
674 	mListDelete((mList *)p, M_LISTITEM(group));
675 }
676 
677 /** ブラシアイテム削除
678  *
679  * 選択アイテムだった場合、削除後は、グループ内の前後のアイテムが選択される。
680  *
681  * @return TRUE で選択アイテムが変更された */
682 
BrushList_deleteItem(BrushItem * item)683 mBool BrushList_deleteItem(BrushItem *item)
684 {
685 	BrushList *p = g_dat;
686 	BrushItem *sel = NULL;
687 
688 	//削除後の選択アイテム
689 
690 	if(item == p->selitem)
691 	{
692 		sel = BRUSHITEM(item->i.next);
693 		if(!sel) sel = BRUSHITEM(item->i.prev);
694 	}
695 
696 	//登録ブラシの場合、解除
697 
698 	if(item == p->regitem)
699 		BrushList_setRegisteredItem(NULL);
700 
701 	//切り替え用ブラシの場合
702 
703 	if(item == p->toggleitem)
704 		p->toggleitem = NULL;
705 
706 	//削除
707 
708 	mListDelete(&item->group->list, M_LISTITEM(item));
709 
710 	//選択変更
711 
712 	if(item == p->selitem)
713 	{
714 		BrushList_setSelItem(sel);
715 		return TRUE;
716 	}
717 	else
718 		return FALSE;
719 }
720 
721 /** ブラシ位置移動 (D&D)
722  *
723  * @param dst_group NULL で dst の前に挿入。NULL 以外でグループの終端へ。 */
724 
BrushList_moveItem(BrushItem * src,BrushGroupItem * dst_group,BrushItem * dst)725 void BrushList_moveItem(BrushItem *src,BrushGroupItem *dst_group,BrushItem *dst)
726 {
727 	if(src == dst) return;
728 
729 	//src のグループから src を外す
730 
731 	mListRemove(&src->group->list, M_LISTITEM(src));
732 
733 	//dst のグループにリンクし直す
734 
735 	if(dst_group)
736 	{
737 		mListAppend(&dst_group->list, M_LISTITEM(src));
738 
739 		src->group = dst_group;
740 	}
741 	else
742 	{
743 		mListInsert(&dst->group->list, M_LISTITEM(dst), M_LISTITEM(src));
744 
745 		src->group = dst->group;
746 	}
747 }
748 
749 /** ブラシ位置を上下移動 */
750 
BrushList_moveItem_updown(BrushItem * item,mBool up)751 void BrushList_moveItem_updown(BrushItem *item,mBool up)
752 {
753 	mListMoveUpDown(&item->group->list, M_LISTITEM(item), up);
754 }
755 
756 /** テキストフォーマットから貼り付け */
757 
BrushList_pasteItem_text(BrushGroupItem * group,BrushItem * item,char * text)758 mBool BrushList_pasteItem_text(BrushGroupItem *group,BrushItem *item,char *text)
759 {
760 	BrushList *p = g_dat;
761 
762 	//グループに新規作成
763 
764 	if(group)
765 	{
766 		item = BrushList_newBrush(group);
767 		if(!item) return FALSE;
768 	}
769 
770 	//セット
771 
772 	BrushItem_setFromText(item, text);
773 
774 	//
775 
776 	if(group)
777 		//新規時、選択する
778 		BrushList_setSelItem(item);
779 	else
780 	{
781 		//上書き時
782 
783 		if(item == p->selitem)
784 			//選択アイテムならデータ更新
785 			_update_selitem(FALSE);
786 		else if(item == p->regitem)
787 			//登録ブラシ (非選択) なら描画用パラメータ更新
788 			BrushList_setBrushDrawParam(TRUE);
789 	}
790 
791 	return TRUE;
792 }
793 
794 /** 新規貼り付け */
795 
BrushList_pasteItem_new(BrushGroupItem * group,BrushItem * src)796 BrushItem *BrushList_pasteItem_new(BrushGroupItem *group,BrushItem *src)
797 {
798 	BrushItem *item;
799 
800 	//新規
801 
802 	item = BrushList_newBrush(group);
803 	if(!item) return NULL;
804 
805 	//コピー
806 
807 	BrushItem_copy(item, src);
808 
809 	return item;
810 }
811 
812 
813 //============================
814 // ブラシ項目値変更
815 //============================
816 /*
817  * - 連携保存時 (手動保存 OFF 時) は、選択アイテムの値も変更。
818  * - dp_cur の描画用パラメータも更新する。
819  */
820 
821 
822 /** dp_cur.flags のフラグ ON/OFF
823  *
824  * @return on を返す */
825 
_dpcur_flag_onoff(uint32_t f,mBool on)826 static mBool _dpcur_flag_onoff(uint32_t f,mBool on)
827 {
828 	if(on)
829 		g_dat->dp_cur.flags |= f;
830 	else
831 		g_dat->dp_cur.flags &= ~f;
832 
833 	return on;
834 }
835 
836 /** 半径値変更 */
837 
_change_radius(int val)838 static void _change_radius(int val)
839 {
840 	g_dat->cur.radius = val;
841 	if(_is_sel_linksave()) g_dat->selitem->radius = val;
842 
843 	g_dat->dp_cur.radius = val * 0.1;
844 }
845 
846 
847 //-----------
848 
849 /** 手動保存 実行 */
850 
BrushList_saveitem_manual()851 void BrushList_saveitem_manual()
852 {
853 	if(g_dat->selitem)
854 	{
855 		BrushItem_copy(g_dat->selitem, &g_dat->cur);
856 
857 		//キャンバスキーでの登録ブラシサイズ変更の値をリセット
858 
859 		if(g_dat->selitem == g_dat->regitem)
860 			g_dat->reg_radius = 0;
861 	}
862 }
863 
864 /** 指定ブラシのブラシ名変更
865  *
866  * @return item が選択ブラシか */
867 
BrushList_setBrushName(BrushItem * item,const char * name)868 mBool BrushList_setBrushName(BrushItem *item,const char *name)
869 {
870 	mStrdup_ptr(&item->name, name);
871 
872 	//選択アイテムなら、カレントデータも変更
873 	/* [!] 手動保存で保存する際には名前もコピーされるので、
874 	 *     ここで変更しておかないと、手動保存の実行時に以前の名前がコピーされてしまう */
875 
876 	if(item != g_dat->selitem)
877 		return FALSE;
878 	else
879 	{
880 		mStrdup_ptr(&g_dat->cur.name, name);
881 		return TRUE;
882 	}
883 }
884 
885 /** ブラシリスト編集後 */
886 
BrushList_afterBrushListEdit()887 void BrushList_afterBrushListEdit()
888 {
889 	//選択アイテムの名前が変更された場合、編集用データの名前も変更する
890 
891 	if(g_dat->selitem)
892 		mStrdup_ptr(&g_dat->cur.name, g_dat->selitem->name);
893 }
894 
895 /** タイプ */
896 
BrushList_updateval_type(int val)897 void BrushList_updateval_type(int val)
898 {
899 	BrushItem *cur = &g_dat->cur;
900 	int n;
901 
902 	cur->type = val;
903 	if(_is_sel_linksave()) g_dat->selitem->type = val;
904 
905 	//塗りタイプ調整
906 
907 	if(cur->pixelmode >= BrushItem_getPixelModeNum(cur))
908 	{
909 		cur->pixelmode = 0;
910 		if(_is_sel_linksave()) g_dat->selitem->pixelmode = 0;
911 	}
912 
913 	//半径値調整 (指先 <-> 他の変更時)
914 
915 	n = BrushItem_adjustRadius(cur, cur->radius);
916 
917 	if(n != cur->radius)
918 		_change_radius(n);
919 
920 	//水彩フラグ
921 
922 	_dpcur_flag_onoff(BRUSHDP_F_WATER, (val == BRUSHITEM_TYPE_WATER));
923 }
924 
925 /** 半径
926  *
927  * @return 調整された値 */
928 
BrushList_updateval_radius(int val)929 int BrushList_updateval_radius(int val)
930 {
931 	val = BrushItem_adjustRadius(&g_dat->cur, val);
932 
933 	_change_radius(val);
934 
935 	return val;
936 }
937 
938 /** 登録ブラシの半径 (キャンバスキーでのサイズ変更時)
939  *
940  * 登録ブラシが選択ブラシでない状態の時。
941  * val : 指先の場合はそのままの値。 */
942 
BrushList_updateval_radius_reg(int val)943 void BrushList_updateval_radius_reg(int val)
944 {
945 	if(g_dat->regitem->flags & BRUSHITEM_F_AUTO_SAVE)
946 	{
947 		g_dat->regitem->radius = val;
948 		g_dat->reg_radius = 0;
949 	}
950 	else
951 		g_dat->reg_radius = val;
952 
953 	g_dat->dp_reg.radius = val * 0.1;
954 }
955 
956 /** 濃度 */
957 
BrushList_updateval_opacity(int val)958 void BrushList_updateval_opacity(int val)
959 {
960 	g_dat->cur.opacity = val;
961 	if(_is_sel_linksave()) g_dat->selitem->opacity = val;
962 
963 	g_dat->dp_cur.opacity = val * 0.01;
964 }
965 
966 /** 塗りタイプ */
967 
BrushList_updateval_pixelmode(int val)968 void BrushList_updateval_pixelmode(int val)
969 {
970 	g_dat->cur.pixelmode = val;
971 	if(_is_sel_linksave()) g_dat->selitem->pixelmode = val;
972 
973 	//ブラシ形状の透明部分も描画するか
974 
975 	_dpcur_flag_onoff(BRUSHDP_F_OVERWRITE_TP, (val == PIXELMODE_OVERWRITE_SQUARE));
976 }
977 
978 /** 手ブレ補正タイプ */
979 
BrushList_updateval_hosei_type(int val)980 void BrushList_updateval_hosei_type(int val)
981 {
982 	g_dat->cur.hosei_type = val;
983 	if(_is_sel_linksave()) g_dat->selitem->hosei_type = val;
984 }
985 
986 /** 手ブレ補正強さ */
987 
BrushList_updateval_hosei_str(int val)988 void BrushList_updateval_hosei_str(int val)
989 {
990 	g_dat->cur.hosei_strong = val;
991 	if(_is_sel_linksave()) g_dat->selitem->hosei_strong = val;
992 }
993 
994 /** サイズ最小 */
995 
BrushList_updateval_min_size(int val)996 void BrushList_updateval_min_size(int val)
997 {
998 	g_dat->cur.min_size = val;
999 	if(_is_sel_linksave()) g_dat->selitem->min_size = val;
1000 
1001 	g_dat->dp_cur.min_size = val * 0.001;
1002 }
1003 
1004 /** 濃度最小 */
1005 
BrushList_updateval_min_opacity(int val)1006 void BrushList_updateval_min_opacity(int val)
1007 {
1008 	g_dat->cur.min_opacity = val;
1009 	if(_is_sel_linksave()) g_dat->selitem->min_opacity = val;
1010 
1011 	g_dat->dp_cur.min_opacity = val * 0.001;
1012 }
1013 
1014 /** 間隔 */
1015 
BrushList_updateval_interval(int val)1016 void BrushList_updateval_interval(int val)
1017 {
1018 	g_dat->cur.interval = val;
1019 	if(_is_sel_linksave()) g_dat->selitem->interval = val;
1020 
1021 	g_dat->dp_cur.interval_src = val * 0.01;
1022 }
1023 
1024 /** ランダムサイズ */
1025 
BrushList_updateval_random_size(int val)1026 void BrushList_updateval_random_size(int val)
1027 {
1028 	g_dat->cur.rand_size_min = val;
1029 	if(_is_sel_linksave()) g_dat->selitem->rand_size_min = val;
1030 
1031 	//
1032 
1033 	if(_dpcur_flag_onoff(BRUSHDP_F_RANDOM_SIZE, (val != 1000)))
1034 		g_dat->dp_cur.random_size_min = val * 0.001;
1035 }
1036 
1037 /** ランダム位置 */
1038 
BrushList_updateval_random_pos(int val)1039 void BrushList_updateval_random_pos(int val)
1040 {
1041 	g_dat->cur.rand_pos_range = val;
1042 	if(_is_sel_linksave()) g_dat->selitem->rand_pos_range = val;
1043 
1044 	//
1045 
1046 	if(_dpcur_flag_onoff(BRUSHDP_F_RANDOM_POS, (val != 0)))
1047 		g_dat->dp_cur.random_pos_len = val * 0.02;
1048 }
1049 
1050 /** 水彩パラメータ */
1051 
BrushList_updateval_waterparam(int no,int val)1052 void BrushList_updateval_waterparam(int no,int val)
1053 {
1054 	g_dat->cur.water_param[no] = val;
1055 	if(_is_sel_linksave()) g_dat->selitem->water_param[no] = val;
1056 
1057 	g_dat->dp_cur.water_param[no] = val * 0.001;
1058 }
1059 
1060 /** 形状画像 */
1061 
BrushList_updateval_shape_path(const char * path)1062 void BrushList_updateval_shape_path(const char *path)
1063 {
1064 	mStrdup_ptr(&g_dat->cur.shape_path, path);
1065 
1066 	if(_is_sel_linksave())
1067 		mStrdup_ptr(&g_dat->selitem->shape_path, path);
1068 
1069 	g_dat->dp_cur.img_shape = MaterialImgList_getImage(MATERIALIMGLIST_TYPE_BRUSH_SHAPE, path, FALSE);
1070 }
1071 
1072 /** 形状、硬さ */
1073 
BrushList_updateval_shape_hard(int val)1074 void BrushList_updateval_shape_hard(int val)
1075 {
1076 	g_dat->cur.hardness = val;
1077 	if(_is_sel_linksave()) g_dat->selitem->hardness = val;
1078 
1079 	//
1080 
1081 	g_dat->dp_cur.shape_hard = _get_drawparam_shape_hard(val);
1082 
1083 	_dpcur_flag_onoff(BRUSHDP_F_SHAPE_HARD_MAX, (val == 100));
1084 }
1085 
1086 /** 形状、荒さ */
1087 
BrushList_updateval_shape_rough(int val)1088 void BrushList_updateval_shape_rough(int val)
1089 {
1090 	g_dat->cur.roughness = val;
1091 	if(_is_sel_linksave()) g_dat->selitem->roughness = val;
1092 
1093 	g_dat->dp_cur.rough = _get_drawparam_rough(val);
1094 }
1095 
1096 /** 進行方向 */
1097 
BrushList_updateval_travelling_dir()1098 void BrushList_updateval_travelling_dir()
1099 {
1100 	g_dat->cur.flags ^= BRUSHITEM_F_ROTATE_TRAVELLING_DIR;
1101 
1102 	if(_is_sel_linksave())
1103 		g_dat->selitem->flags ^= BRUSHITEM_F_ROTATE_TRAVELLING_DIR;
1104 
1105 	g_dat->dp_cur.flags ^= BRUSHDP_F_TRAVELLING_DIR;
1106 }
1107 
1108 /** 角度 */
1109 
BrushList_updateval_angle(int val)1110 void BrushList_updateval_angle(int val)
1111 {
1112 	g_dat->cur.rotate_angle = val;
1113 	if(_is_sel_linksave()) g_dat->selitem->rotate_angle = val;
1114 
1115 	g_dat->dp_cur.angle = val * 512 / 360;
1116 }
1117 
1118 /** 角度ランダム */
1119 
BrushList_updateval_angle_radom(int val)1120 void BrushList_updateval_angle_radom(int val)
1121 {
1122 	g_dat->cur.rotate_rand_w = val;
1123 	if(_is_sel_linksave()) g_dat->selitem->rotate_rand_w = val;
1124 
1125 	g_dat->dp_cur.angle_random = val * 256 / 180;
1126 }
1127 
1128 /** 筆圧補正タイプ */
1129 
BrushList_updateval_pressure_type(int type)1130 void BrushList_updateval_pressure_type(int type)
1131 {
1132 	uint32_t def,defval[3] = {
1133 		100, 50|(50<<8), 30|(30<<8)|(60<<16)|(60<<24)
1134 	};
1135 
1136 	//タイプ
1137 
1138 	g_dat->cur.pressure_type = type;
1139 	if(_is_sel_linksave()) g_dat->selitem->pressure_type = type;
1140 
1141 	g_dat->dp_cur.pressure_type = type;
1142 
1143 	//値 (各タイプのデフォルト値に初期化)
1144 
1145 	def = defval[type];
1146 
1147 	g_dat->cur.pressure_val = def;
1148 	if(_is_sel_linksave()) g_dat->selitem->pressure_val = def;
1149 
1150 	_set_drawparam_pressure(&g_dat->dp_cur, type, def);
1151 }
1152 
1153 /** 筆圧補正、値 */
1154 
BrushList_updateval_pressure_value(uint32_t val)1155 void BrushList_updateval_pressure_value(uint32_t val)
1156 {
1157 	g_dat->cur.pressure_val = val;
1158 	if(_is_sel_linksave()) g_dat->selitem->pressure_val = val;
1159 
1160 	_set_drawparam_pressure(&g_dat->dp_cur, g_dat->cur.pressure_type, val);
1161 }
1162 
1163 /** テクスチャ画像 */
1164 
BrushList_updateval_texture_path(const char * path)1165 void BrushList_updateval_texture_path(const char *path)
1166 {
1167 	mStrdup_ptr(&g_dat->cur.texture_path, path);
1168 
1169 	if(_is_sel_linksave())
1170 		mStrdup_ptr(&g_dat->selitem->texture_path, path);
1171 
1172 	g_dat->dp_cur.img_texture = MaterialImgList_getImage(MATERIALIMGLIST_TYPE_BRUSH_TEXTURE, path, FALSE);
1173 }
1174 
1175 /** アンチエイリアス */
1176 
BrushList_updateval_antialias(BrushList * p)1177 void BrushList_updateval_antialias(BrushList *p)
1178 {
1179 	g_dat->cur.flags ^= BRUSHITEM_F_ANTIALIAS;
1180 	if(_is_sel_linksave()) g_dat->selitem->flags ^= BRUSHITEM_F_ANTIALIAS;
1181 
1182 	g_dat->dp_cur.flags ^= BRUSHDP_F_NO_ANTIALIAS;
1183 }
1184 
1185 /** 曲線補間 */
1186 
BrushList_updateval_curve(BrushList * p)1187 void BrushList_updateval_curve(BrushList *p)
1188 {
1189 	g_dat->cur.flags ^= BRUSHITEM_F_CURVE;
1190 	if(_is_sel_linksave()) g_dat->selitem->flags ^= BRUSHITEM_F_CURVE;
1191 
1192 	g_dat->dp_cur.flags ^= BRUSHDP_F_CURVE;
1193 }
1194 
1195 /** 詳細設定のダイアログ後
1196  *
1197  * 値は常に連動保存させる。 */
1198 
BrushList_updateval_detail()1199 void BrushList_updateval_detail()
1200 {
1201 	BrushItem *sel,*cur;
1202 
1203 	cur = &g_dat->cur;
1204 
1205 	//連動保存
1206 
1207 	sel = g_dat->selitem;
1208 
1209 	if(sel)
1210 	{
1211 		//自動保存
1212 
1213 		if(cur->flags & BRUSHITEM_F_AUTO_SAVE)
1214 			sel->flags |= BRUSHITEM_F_AUTO_SAVE;
1215 		else
1216 			sel->flags &= ~BRUSHITEM_F_AUTO_SAVE;
1217 
1218 		//半径 (指先以外)
1219 
1220 		if(cur->type != BRUSHITEM_TYPE_FINGER)
1221 		{
1222 			sel->radius = cur->radius;
1223 			sel->radius_min = cur->radius_min;
1224 			sel->radius_max = cur->radius_max;
1225 		}
1226 	}
1227 
1228 	//描画用 (半径が調整された場合があるため)
1229 
1230 	g_dat->dp_cur.radius = cur->radius * 0.1;
1231 }
1232 
1233 
1234 /*********** ファイル処理 ***************************/
1235 
1236 
1237 //===============================
1238 // sub
1239 //===============================
1240 
1241 
1242 /** 設定ファイル開く */
1243 
_open_configfile(const char * fname,mBool write)1244 static FILE *_open_configfile(const char *fname,mBool write)
1245 {
1246 	mStr str = MSTR_INIT;
1247 	FILE *fp;
1248 
1249 	mAppGetConfigPath(&str, fname);
1250 
1251 	fp = mFILEopenUTF8(str.buf, (write)? "wb": "rb");
1252 
1253 	mStrFree(&str);
1254 
1255 	return fp;
1256 }
1257 
1258 
1259 //===============================
1260 // ファイル読み込み
1261 //===============================
1262 
1263 
1264 /** 文字列読み込み */
1265 
_read_string(FILE * fp,char ** ppstr)1266 static mBool _read_string(FILE *fp,char **ppstr)
1267 {
1268 	char *name;
1269 
1270 	if(mFILEreadStr_len16BE(fp, &name) == -1)
1271 		return FALSE;
1272 	else
1273 	{
1274 		mStrdup_ptr(ppstr, name);
1275 		mFree(name);
1276 
1277 		return TRUE;
1278 	}
1279 }
1280 
1281 /** ブラシアイテム読み込み
1282  *
1283  * @return -1 でエラー、それ以外でフラグ */
1284 
_read_brushitem(FILE * fp,BrushItem * pi)1285 static int _read_brushitem(FILE *fp,BrushItem *pi)
1286 {
1287 	uint8_t flags;
1288 	uint16_t exsize;
1289 
1290 	if(!mFILEreadByte(fp, &flags)
1291 		|| !mFILEread16BE(fp, &exsize)
1292 
1293 		|| !mFILEread32BE(fp, &pi->pressure_val)
1294 		|| mFILEreadArray16BE(fp, &pi->radius, BRUSHITEM_16BITVAL_NUM) != BRUSHITEM_16BITVAL_NUM
1295 		|| fread(&pi->type, 1, BRUSHITEM_8BITVAL_NUM, fp) != BRUSHITEM_8BITVAL_NUM
1296 
1297 		|| !_read_string(fp, &pi->name)
1298 		|| !_read_string(fp, &pi->shape_path)
1299 		|| !_read_string(fp, &pi->texture_path))
1300 		return -1;
1301 
1302 	//拡張データ
1303 
1304 	fseek(fp, exsize, SEEK_CUR);
1305 
1306 	return flags;
1307 }
1308 
1309 /** ブラシデータ読み込み */
1310 
_read_brushdata(BrushList * p,FILE * fp)1311 static void _read_brushdata(BrushList *p,FILE *fp)
1312 {
1313 	uint8_t type,flags,colnum;
1314 	uint16_t size;
1315 	long pos;
1316 	int ret;
1317 	char *name;
1318 	BrushGroupItem *group = NULL;
1319 	BrushItem *pi,*pi_sel = NULL,*pi_reg = NULL;
1320 
1321 	while(mFILEreadByte(fp, &type) && type != 255)
1322 	{
1323 		//サイズ
1324 
1325 		if(!mFILEread16BE(fp, &size)) break;
1326 
1327 		pos = ftell(fp);
1328 
1329 		//
1330 
1331 		if(type == 0)
1332 		{
1333 			//---- ブラシ
1334 
1335 			if(!group) break;
1336 
1337 			//作成
1338 
1339 			pi = BrushList_newBrush(group);
1340 			if(!pi) break;
1341 
1342 			//読み込み
1343 
1344 			ret = _read_brushitem(fp, pi);
1345 			if(ret == -1) break;
1346 
1347 			//フラグ
1348 
1349 			if(ret & 1) pi_sel = pi;
1350 			if(ret & 2) pi_reg = pi;
1351 		}
1352 		else if(type == 1)
1353 		{
1354 			//---- グループ
1355 
1356 			if(!mFILEreadByte(fp, &flags)
1357 				|| !mFILEreadByte(fp, &colnum)
1358 				|| mFILEreadStr_len16BE(fp, &name) == -1)
1359 				break;
1360 
1361 			group = BrushList_newGroup(name, colnum);
1362 
1363 			mFree(name);
1364 
1365 			if(!group) break;
1366 
1367 			group->expand = flags & 1;
1368 		}
1369 
1370 		//次へ
1371 
1372 		fseek(fp, pos + size, SEEK_SET);
1373 	}
1374 
1375 	//選択、登録アイテム
1376 
1377 	BrushList_setSelItem(pi_sel);
1378 	BrushList_setRegisteredItem(pi_reg);
1379 }
1380 
1381 /** ブラシの設定ファイル読み込み */
1382 
_load_configfile()1383 static void _load_configfile()
1384 {
1385 	FILE *fp;
1386 	uint8_t ver,subver;
1387 	uint16_t wd;
1388 
1389 	//開く
1390 
1391 	fp = _open_configfile(CONFIG_FILENAME_BRUSH, FALSE);
1392 	if(!fp) return;
1393 
1394 	//ヘッダ
1395 
1396 	if(!mFILEreadCompareStr(fp, "AZPLBRD")) goto ERR;
1397 
1398 	//バージョン
1399 
1400 	if(!mFILEreadByte(fp, &ver)
1401 		|| ver != 1
1402 		|| !mFILEreadByte(fp, &subver))
1403 		goto ERR;
1404 
1405 	//サイズリスト
1406 
1407 	if(!mFILEread16BE(fp, &wd)) goto ERR;
1408 
1409 	if(wd)
1410 	{
1411 		if(!BrushSizeList_alloc(wd)
1412 			|| mFILEreadArray16BE(fp, BrushSizeList_getBuf(), wd) != wd)
1413 			goto ERR;
1414 
1415 		BrushSizeList_setNum(wd);
1416 	}
1417 
1418 	//ブラシデータ
1419 
1420 	_read_brushdata(g_dat, fp);
1421 
1422 ERR:
1423 	fclose(fp);
1424 }
1425 
1426 /** ブラシの設定ファイルを読み込み (初期化時) */
1427 
BrushList_loadconfigfile()1428 void BrushList_loadconfigfile()
1429 {
1430 	_load_configfile();
1431 
1432 	//グループが一つもない場合は、新規作成
1433 
1434 	if(g_dat->list.num == 0)
1435 		BrushList_newGroup("group", 2);
1436 }
1437 
1438 
1439 //===============================
1440 // ファイル保存
1441 //===============================
1442 
1443 
1444 /** ブラシデータ書き込み */
1445 
_write_brushitem(BrushList * p,FILE * fp,BrushItem * pi)1446 static void _write_brushitem(BrushList *p,FILE *fp,BrushItem *pi)
1447 {
1448 	int n,size;
1449 	fpos_t pos;
1450 
1451 	//type (0=brush)
1452 	mFILEwriteByte(fp, 0);
1453 
1454 	//size
1455 	fgetpos(fp, &pos);
1456 	mFILEwrite16BE(fp, 0);
1457 
1458 	//----------
1459 
1460 	size = 1 + 2 + 4 + 2 * BRUSHITEM_16BITVAL_NUM + BRUSHITEM_8BITVAL_NUM;
1461 
1462 	//flags (0bit:select 1bit:登録ブラシ)
1463 
1464 	n = (pi == p->selitem);
1465 	if(pi == p->regitem) n |= 2;
1466 
1467 	mFILEwriteByte(fp, n);
1468 
1469 	//拡張データサイズ
1470 
1471 	mFILEwrite16BE(fp, 0);
1472 
1473 	//基本データ
1474 
1475 	mFILEwrite32BE(fp, pi->pressure_val);
1476 
1477 	mFILEwriteArray16BE(fp, &pi->radius, BRUSHITEM_16BITVAL_NUM);
1478 	fwrite(&pi->type, 1, BRUSHITEM_8BITVAL_NUM, fp);
1479 
1480 	size += mFILEwriteStr_len16BE(fp, pi->name, -1);
1481 	size += mFILEwriteStr_len16BE(fp, pi->shape_path, -1);
1482 	size += mFILEwriteStr_len16BE(fp, pi->texture_path, -1);
1483 
1484 	//サイズ
1485 
1486 	fsetpos(fp, &pos);
1487 	mFILEwrite16BE(fp, size);
1488 	fseek(fp, 0, SEEK_END);
1489 }
1490 
1491 /** 設定ファイルに保存 */
1492 
BrushList_saveconfigfile()1493 void BrushList_saveconfigfile()
1494 {
1495 	FILE *fp;
1496 	BrushGroupItem *gi;
1497 	BrushItem *pi;
1498 	int n;
1499 
1500 	//開く
1501 
1502 	fp = _open_configfile(CONFIG_FILENAME_BRUSH, TRUE);
1503 	if(!fp) return;
1504 
1505 	//ヘッダ
1506 
1507 	fputs("AZPLBRD", fp);
1508 	mFILEwriteByte(fp, 1);	//ver = 1
1509 	mFILEwriteByte(fp, 0);	//sub version
1510 
1511 	//サイズリスト
1512 
1513 	n = BrushSizeList_getNum();
1514 
1515 	mFILEwrite16BE(fp, n);
1516 	mFILEwriteArray16BE(fp, BrushSizeList_getBuf(), n);
1517 
1518 	//ブラシデータ
1519 
1520 	for(gi = BRUSHGROUPITEM(g_dat->list.top); gi; gi = BRUSHGROUPITEM(gi->i.next))
1521 	{
1522 		//----- グループデータ
1523 
1524 		n = mStrlen(gi->name);
1525 		if(n > 0xffff) n = 0xffff;
1526 
1527 		//type (1=group)
1528 		mFILEwriteByte(fp, 1);
1529 		//size
1530 		mFILEwrite16BE(fp, 1 + 1 + 2 + n);
1531 
1532 		//flags (0bit:expand)
1533 		mFILEwriteByte(fp, gi->expand);
1534 		//横に並べる数
1535 		mFILEwriteByte(fp, gi->colnum);
1536 		//名前
1537 		mFILEwriteStr_len16BE(fp, gi->name, n);
1538 
1539 		//------ ブラシアイテム
1540 
1541 		for(pi = BRUSHITEM(gi->list.top); pi; pi = BRUSHITEM(pi->i.next))
1542 			_write_brushitem(g_dat, fp, pi);
1543 	}
1544 
1545 	//ブラシ終了
1546 	mFILEwriteByte(fp, 255);
1547 
1548 	fclose(fp);
1549 }
1550 
1551 
1552 //===============================
1553 // ver.1 => ver.2 ファイル変換
1554 //===============================
1555 
1556 
1557 /** ブラシデータ変換 */
1558 
_convert_brush(FILE * fpin,FILE * fpout,uint8_t flags)1559 static mBool _convert_brush(FILE *fpin,FILE *fpout,uint8_t flags)
1560 {
1561 	char *name,*brush_path = NULL,*tex_path = NULL;
1562 	uint8_t bt,bt2,btbuf[6];
1563 	uint16_t wbuf[15];
1564 	int len[3];
1565 	mBool ret = FALSE;
1566 
1567 	//------ 読み込み
1568 
1569 	//名前
1570 
1571 	len[0] = mFILEreadStr_variableLen(fpin, &name);
1572 	if(len[0] < 0) return FALSE;
1573 
1574 	//ブラシ画像パス
1575 
1576 	len[1] = mFILEreadStr_variableLen(fpin, &brush_path);
1577 	if(len[1] < 0) goto ERR;
1578 
1579 	//テクスチャ画像パス
1580 
1581 	len[2] = mFILEreadStr_variableLen(fpin, &tex_path);
1582 	if(len[2] < 0) goto ERR;
1583 
1584 	//2byte、1byte データ
1585 
1586 	if(fread(wbuf, 1, 15 * 2, fpin) != 15 * 2
1587 		|| fread(btbuf, 1, 6, fpin) != 6)
1588 		goto ERR;
1589 
1590 	//======= 書き込み
1591 
1592 	//type (0=brush)
1593 
1594 	mFILEwriteByte(fpout, 0);
1595 
1596 	//データサイズ
1597 
1598 	mFILEwrite16BE(fpout,
1599 		1 + 2 + 4 + 2 * BRUSHITEM_16BITVAL_NUM + BRUSHITEM_8BITVAL_NUM
1600 		+ 2 * 3 + len[0] + len[1] + len[2]);
1601 
1602 	//flags (0bit:select 1bit:登録ブラシ)
1603 
1604 	mFILEwriteByte(fpout, ((flags & 0x40) != 0) | ((flags & 0x80) >> 6));
1605 
1606 	//拡張データサイズ
1607 
1608 	mFILEwrite16BE(fpout, 0);
1609 
1610 	//筆圧値 (32bit)
1611 
1612 	mFILEwriteZero(fpout, 2);
1613 	fwrite(wbuf + 13, 1, 2, fpout);
1614 
1615 	//---- 16bit値 (BE)
1616 	/* 0:半径 1:半径最大 2:最小サイズ 3:最小濃度 4:間隔
1617 	 * 5:ランダムサイズ 6:ランダム位置 7,8,9:水彩1..3
1618 	 * 10:回転角度 11:回転ランダム 12:荒さ 13:筆圧サイズ 14:筆圧濃度 */
1619 
1620 	//半径
1621 
1622 	fwrite(wbuf, 1, 2, fpout);
1623 
1624 	//半径最小/最大
1625 
1626 	mFILEwrite16BE(fpout, BRUSHITEM_RADIUS_MIN);
1627 
1628 	fwrite(wbuf + 1, 1, 2, fpout);
1629 
1630 	//最小サイズ/最小濃度/間隔/ランダムサイズ/ランダム位置
1631 
1632 	fwrite(wbuf + 2, 1, 2 * 5, fpout);
1633 
1634 	//回転角度
1635 
1636 	fwrite(wbuf + 10, 1, 2, fpout);
1637 
1638 	//水彩
1639 
1640 	fwrite(wbuf + 7, 1, 2 * 3, fpout);
1641 
1642 	//----- 8bit値
1643 	/* 0:濃度
1644 	 * 1:塗りタイプ (0:重ね 1:A比較 2:上書き 3:消しゴム 4:覆い焼き 5:焼き込み 6:加算 7:ぼかし)
1645 	 * 2:補正タイプ(なし/強/中/弱) 3:補正強さ 4:硬さ
1646 	 * 5:フラグ (0:手動保存 1:水彩 2:進行方向 3:アンチエイリアス 4:曲線補間) */
1647 
1648 	//ブラシタイプ/塗りタイプ
1649 
1650 	bt2 = 0;
1651 
1652 	if(btbuf[5] & (1<<1))
1653 		bt = BRUSHITEM_TYPE_WATER;
1654 	else if(btbuf[1] == 7)
1655 		bt = BRUSHITEM_TYPE_BLUR;
1656 	else if(btbuf[1] == 3)
1657 		bt = BRUSHITEM_TYPE_ERASE;
1658 	else
1659 	{
1660 		bt = 0;
1661 
1662 		switch(btbuf[1])
1663 		{
1664 			case 0: bt2 = PIXELMODE_BLEND_PIXEL; break;
1665 			case 1: bt2 = PIXELMODE_COMPARE_A; break;
1666 			case 2: bt2 = PIXELMODE_OVERWRITE_STYLE; break;
1667 			case 4: bt2 = PIXELMODE_DODGE; break;
1668 			case 5: bt2 = PIXELMODE_BURN; break;
1669 			case 6: bt2 = PIXELMODE_ADD; break;
1670 		}
1671 	}
1672 
1673 	//ブラシタイプ
1674 
1675 	fwrite(&bt, 1, 1, fpout);
1676 
1677 	//濃度
1678 
1679 	fwrite(btbuf, 1, 1, fpout);
1680 
1681 	//塗りタイプ
1682 
1683 	fwrite(&bt2, 1, 1, fpout);
1684 
1685 	//補正タイプ
1686 
1687 	bt = btbuf[2];
1688 	if(bt == 1) bt = 3;
1689 	else if(bt == 3) bt = 1;
1690 
1691 	fwrite(&bt, 1, 1, fpout);
1692 
1693 	//補正強さ
1694 
1695 	mFILEwriteByte(fpout, btbuf[3] + 1);
1696 
1697 	//硬さ
1698 
1699 	fwrite(btbuf + 4, 1, 1, fpout);
1700 
1701 	//荒さ (2byte -> 1byte)
1702 
1703 	fwrite((uint8_t *)wbuf + 12 * 2 + 1, 1, 1, fpout);
1704 
1705 	//回転ランダム (2byte -> 1byte)
1706 
1707 	fwrite((uint8_t *)wbuf + 11 * 2 + 1, 1, 1, fpout);
1708 
1709 	//筆圧補正タイプ
1710 
1711 	mFILEwriteByte(fpout, 0);
1712 
1713 	//フラグ
1714 
1715 	bt = 0;
1716 	bt2 = btbuf[5];
1717 
1718 	if(!(bt2 & 1)) bt |= BRUSHITEM_F_AUTO_SAVE;
1719 	if(bt2 & 4) bt |= BRUSHITEM_F_ROTATE_TRAVELLING_DIR;
1720 	if(bt2 & 8) bt |= BRUSHITEM_F_ANTIALIAS;
1721 	if(bt2 & 16) bt |= BRUSHITEM_F_CURVE;
1722 
1723 	fwrite(&bt, 1, 1, fpout);
1724 
1725 	//----- 文字列
1726 
1727 	mFILEwriteStr_len16BE(fpout, name, len[0]);
1728 	mFILEwriteStr_len16BE(fpout, brush_path, len[1]);
1729 	mFILEwriteStr_len16BE(fpout, tex_path, len[2]);
1730 
1731 	//----- 終了
1732 
1733 	ret = TRUE;
1734 
1735 ERR:
1736 	mFree(name);
1737 	mFree(brush_path);
1738 	mFree(tex_path);
1739 
1740 	return ret;
1741 }
1742 
1743 /** ver.1 の設定ファイルから変換 */
1744 
BrushList_convert_from_ver1()1745 void BrushList_convert_from_ver1()
1746 {
1747 	FILE *fpin,*fpout;
1748 	uint8_t bt,*buf;
1749 	uint16_t wd;
1750 	int size,type;
1751 
1752 	//読み込み
1753 
1754 	fpin = _open_configfile("brush.dat", FALSE);
1755 	if(!fpin) return;
1756 
1757 	if(!mFILEreadCompareStr(fpin, "AZPLBRD")
1758 		|| !mFILEreadByte(fpin, &bt)
1759 		|| bt != 0
1760 		|| !mFILEreadByte(fpin, &bt)
1761 		|| bt != 0)
1762 	{
1763 		fclose(fpin);
1764 		return;
1765 	}
1766 
1767 	//書き込み
1768 
1769 	fpout = _open_configfile(CONFIG_FILENAME_BRUSH, TRUE);
1770 	if(!fpout) return;
1771 
1772 	fputs("AZPLBRD", fpout);
1773 	mFILEwriteByte(fpout, 1);
1774 	mFILEwriteByte(fpout, 0);
1775 
1776 	//サイズリスト
1777 
1778 	if(!mFILEread16BE(fpin, &wd)) goto END;
1779 
1780 	if(wd)
1781 	{
1782 		size = wd << 1;
1783 
1784 		buf = (uint8_t *)mMalloc(size, FALSE);
1785 		if(!buf) goto END;
1786 
1787 		if(fread(buf, 1, size, fpin) != size)
1788 		{
1789 			mFree(buf);
1790 			goto END;
1791 		}
1792 
1793 		mFILEwrite16BE(fpout, wd);
1794 		fwrite(buf, 1, size, fpout);
1795 
1796 		mFree(buf);
1797 	}
1798 
1799 	//ブラシデータ
1800 
1801 	while(mFILEreadByte(fpin, &bt))
1802 	{
1803 		type = bt & 0x3f;
1804 		if(type >= 2) break;
1805 
1806 		if(type == 1)
1807 		{
1808 			//---- グループ
1809 
1810 			//type (1=group)
1811 			mFILEwriteByte(fpout, 1);
1812 			//size
1813 			mFILEwrite16BE(fpout, 1 + 1 + 2 + 5);
1814 
1815 			//flags (0bit:expand)
1816 			mFILEwriteByte(fpout, ((bt & 0x40) != 0));
1817 			//横に並べる数
1818 			mFILEwriteByte(fpout, 2);
1819 			//名前
1820 			mFILEwrite16BE(fpout, 5);
1821 			fputs("group", fpout);
1822 		}
1823 		else
1824 		{
1825 			//ブラシ
1826 
1827 			if(!_convert_brush(fpin, fpout, bt))
1828 				break;
1829 		}
1830 	}
1831 
1832 	mFILEwriteByte(fpout, 255);
1833 
1834 	//
1835 
1836 END:
1837 	fclose(fpin);
1838 	fclose(fpout);
1839 }
1840