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