1 /*$
2 Copyright (C) 2016-2020 Azel.
3
4 This file is part of AzPainterB.
5
6 AzPainterB 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 AzPainterB 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 * TileImage
22 *
23 * ブラシ描画
24 *****************************************/
25 /*
26 * [!] 描画前に TileImageDrawInfo::pixdraw に描画色を指定しておく。
27 */
28
29 #include <math.h>
30
31 #include "mDef.h"
32
33 #include "TileImage.h"
34 #include "TileImageDrawInfo.h"
35
36 #include "BrushDrawParam.h"
37
38
39 //-----------------
40
41 #define _CURVE_NUM 10
42
43 typedef struct
44 {
45 double x,y,pressure;
46 }DrawPoint;
47
48 typedef union
49 {
50 struct { double r,g,b,a; }; //a = 0.0 - 1.0
51 double ar[4];
52 }PixelRGBA_double;
53
54 //-----------------
55 /* 作業用データ */
56
57 typedef struct
58 {
59 double t,lastx,lasty,lastpress;
60
61 DrawPoint curve_pt[4];
62 double curve_param[_CURVE_NUM][4];
63
64 PixelRGBA_double pixwater, //水彩色
65 pixwater_draw; //水彩、開始時の描画色
66 }DrawBrushWork;
67
68 static DrawBrushWork g_work;
69
70 //-----------------
71
72 #define _BRUSHPARAM (g_tileimage_dinfo.brushparam)
73
74 //-----------------
75
76 static void _drawbrush_point(TileImage *p,double x,double y,double radius,double opacity);
77
78 //-----------------
79
80
81
82 //==================================
83 // sub
84 //==================================
85
86
87 /** 水彩時、指定位置から半径内の色の平均色を double で取得 */
88
_water_get_average_color(TileImage * p,double x,double y,double radius,PixelRGBA_double * pixdst)89 static void _water_get_average_color(TileImage *p,
90 double x,double y,double radius,PixelRGBA_double *pixdst)
91 {
92 int x1,y1,x2,y2,cnt,ix,iy;
93 double rd,r,g,b,a,dx,dy,dd;
94 PixelRGBA pix;
95
96 x1 = floor(x - radius);
97 y1 = floor(y - radius);
98 x2 = floor(x + radius);
99 y2 = floor(y + radius);
100
101 rd = radius * radius;
102
103 r = g = b = a = 0;
104 cnt = 0;
105
106 for(iy = y1; iy <= y2; iy++)
107 {
108 dy = iy - y;
109 dy *= dy;
110
111 for(ix = x1; ix <= x2; ix++)
112 {
113 dx = ix - x;
114
115 if(dx * dx + dy < rd)
116 {
117 TileImage_getPixel_clip(p, ix, iy, &pix);
118
119 dd = pix.a / 255.0;
120
121 r += pix.r * dd;
122 g += pix.g * dd;
123 b += pix.b * dd;
124 a += dd;
125
126 cnt++;
127 }
128 }
129 }
130
131 //平均
132
133 if(a == 0 || cnt == 0)
134 pixdst->r = pixdst->g = pixdst->b = pixdst->a = 0;
135 else
136 {
137 dd = 1.0 / a;
138
139 pixdst->r = r * dd;
140 pixdst->g = g * dd;
141 pixdst->b = b * dd;
142 pixdst->a = a / cnt;
143 }
144 }
145
146 /** 水彩の混色 */
147 /*
148 * やまかわ氏の "gimp-painter-" (MixBrush 改造版) のソースを参考にしています。
149 * http://sourceforge.jp/projects/gimp-painter/releases/?package_id=6799
150 */
151
_water_mix_color(PixelRGBA_double * pixdst,PixelRGBA_double * pix1,double op1,PixelRGBA_double * pix2,double op2,mBool alpha)152 static void _water_mix_color(PixelRGBA_double *pixdst,
153 PixelRGBA_double *pix1,double op1,
154 PixelRGBA_double *pix2,double op2,mBool alpha)
155 {
156 double a1,a2;
157
158 a1 = pix1->a * op1;
159 a2 = pix2->a * (1.0 - a1) * op2;
160
161 if(a1 == 0)
162 {
163 *pixdst = *pix2;
164 pixdst->a = a2;
165 }
166 else if(a2 == 0)
167 {
168 *pixdst = *pix1;
169 pixdst->a = a1;
170 }
171 else
172 {
173 pixdst->a = a1 + a2;
174
175 a1 = a1 / (a1 + a2);
176 a2 = 1.0 - a1;
177
178 pixdst->r = pix1->r * a1 + pix2->r * a2;
179 pixdst->g = pix1->g * a1 + pix2->g * a2;
180 pixdst->b = pix1->b * a1 + pix2->b * a2;
181 }
182
183 if(alpha)
184 {
185 op1 = pow(op1, 1.35);
186 op2 = pow(op2, 1.15);
187 a1 = op1 + op2;
188
189 if(a1 == 0)
190 pixdst->a = 0;
191 else
192 {
193 a2 = op1 / a1;
194 pixdst->a = (pix1->a * a2 + pix2->a * (1.0 - a2)) * (op1 + (1.0 - op1) * op2);
195 }
196 }
197 }
198
199 /** 水彩、描画色の計算 */
200
_water_calc_drawcol(TileImage * p,double x,double y,double radius,double * popacity,PixelRGBA * pixdst)201 static void _water_calc_drawcol(TileImage *p,double x,double y,double radius,
202 double *popacity,PixelRGBA *pixdst)
203 {
204 BrushDrawParam *param = _BRUSHPARAM;
205 PixelRGBA_double pix1,pix2;
206 int i,n;
207 double opa;
208
209 //描画色 + 前回の色 => pix1
210
211 _water_mix_color(&pix1,
212 &g_work.pixwater_draw, param->water[0],
213 &g_work.pixwater, 1, FALSE);
214
215 //pix1 + 描画先の色 => pixwater
216
217 _water_get_average_color(p, x, y, radius, &pix2);
218
219 _water_mix_color(&g_work.pixwater,
220 &pix1, param->water[2],
221 &pix2, param->water[1], TRUE);
222
223 //結果の描画色
224
225 for(i = 0; i < 3; i++)
226 {
227 n = round(g_work.pixwater.ar[i]);
228
229 if(n < 0) n = 0;
230 else if(n > 255) n = 255;
231
232 pixdst->ar[i] = n;
233 }
234
235 //濃度 (*popacity は 0-255)
236 /* pixwater のアルファ値で制限 */
237
238 opa = g_work.pixwater.a * 255;
239
240 if(opa < *popacity)
241 *popacity = opa;
242 }
243
244
245 //==================================
246 //
247 //==================================
248
249
250 /** 曲線補間用パラメータ初期化 */
251
__TileImage_initCurve()252 void __TileImage_initCurve()
253 {
254 int i;
255 double t,tt,t1,t2,t3;
256
257 tt = 1.0 / 6.0;
258
259 for(i = 0, t = 1.0 / _CURVE_NUM; i < _CURVE_NUM; i++, t += 1.0 / _CURVE_NUM)
260 {
261 t1 = 4.0 - (t + 3.0);
262 t2 = t + 2.0;
263 t3 = t + 1.0;
264
265 g_work.curve_param[i][0] = tt * t1 * t1 * t1;
266 g_work.curve_param[i][1] = tt * ( 3 * t2 * t2 * t2 - 24 * t2 * t2 + 60 * t2 - 44);
267 g_work.curve_param[i][2] = tt * (-3 * t3 * t3 * t3 + 12 * t3 * t3 - 12 * t3 + 4);
268 g_work.curve_param[i][3] = tt * t * t * t;
269 }
270 }
271
272 /** ブラシ自由線描画の開始 */
273
TileImage_beginDrawBrush_free(TileImage * p,double x,double y,double pressure)274 void TileImage_beginDrawBrush_free(TileImage *p,double x,double y,double pressure)
275 {
276 g_work.lastx = x;
277 g_work.lasty = y;
278 g_work.lastpress = pressure;
279 g_work.t = 0;
280
281 //曲線補間
282
283 if(_BRUSHPARAM->flags & BRUSHDP_F_CURVE)
284 {
285 g_work.curve_pt[0].x = x;
286 g_work.curve_pt[0].y = y;
287 g_work.curve_pt[0].pressure = pressure;
288
289 g_work.curve_pt[1] = g_work.curve_pt[0];
290 g_work.curve_pt[2] = g_work.curve_pt[0];
291 }
292
293 //水彩
294
295 if(_BRUSHPARAM->flags & BRUSHDP_F_WATER)
296 {
297 PixelRGBA_double *pix = &g_work.pixwater_draw;
298
299 //開始時の描画色
300
301 pix->r = g_tileimage_dinfo.pixdraw.r;
302 pix->g = g_tileimage_dinfo.pixdraw.g;
303 pix->b = g_tileimage_dinfo.pixdraw.b;
304 pix->a = 1;
305
306 //描画先の平均色
307
308 _water_get_average_color(p, x, y, _BRUSHPARAM->radius, &g_work.pixwater);
309 }
310 }
311
312
313 //================================
314 // 線の描画
315 //================================
316
317
318 /** 曲線補間の線描画 */
319
_drawbrush_curveline(TileImage * p)320 static void _drawbrush_curveline(TileImage *p)
321 {
322 int i;
323 double lastx,lasty,x,y,press_st,press_ed;
324 double t1,t2,t3,t4;
325 DrawPoint *pt = g_work.curve_pt;
326
327 lastx = g_work.lastx;
328 lasty = g_work.lasty;
329 press_st = g_work.lastpress;
330
331 //
332
333 for(i = 0; i < _CURVE_NUM; i++)
334 {
335 t1 = g_work.curve_param[i][0];
336 t2 = g_work.curve_param[i][1];
337 t3 = g_work.curve_param[i][2];
338 t4 = g_work.curve_param[i][3];
339
340 //
341
342 x = pt[0].x * t1 + pt[1].x * t2 + pt[2].x * t3 + pt[3].x * t4;
343 y = pt[0].y * t1 + pt[1].y * t2 + pt[2].y * t3 + pt[3].y * t4;
344
345 press_ed = pt[0].pressure * t1 + pt[1].pressure * t2 + pt[2].pressure * t3 + pt[3].pressure * t4;
346
347 g_work.t = TileImage_drawBrushLine(p,
348 lastx, lasty, x, y, press_st, press_ed, g_work.t);
349
350 //
351
352 lastx = x;
353 lasty = y;
354 press_st = press_ed;
355 }
356
357 //
358
359 g_work.lastx = x;
360 g_work.lasty = y;
361 g_work.lastpress = press_ed;
362 }
363
364 /** ブラシで自由線描画 */
365
TileImage_drawBrushFree(TileImage * p,double x,double y,double pressure)366 void TileImage_drawBrushFree(TileImage *p,double x,double y,double pressure)
367 {
368 if(_BRUSHPARAM->flags & BRUSHDP_F_CURVE)
369 {
370 //曲線補間
371
372 g_work.curve_pt[3].x = x;
373 g_work.curve_pt[3].y = y;
374 g_work.curve_pt[3].pressure = pressure;
375
376 _drawbrush_curveline(p);
377
378 for(int i = 0; i < 3; i++)
379 g_work.curve_pt[i] = g_work.curve_pt[i + 1];
380 }
381 else
382 {
383 //線形補間
384
385 g_work.t = TileImage_drawBrushLine(p,
386 g_work.lastx, g_work.lasty, x, y,
387 g_work.lastpress, pressure, g_work.t);
388
389 g_work.lastx = x;
390 g_work.lasty = y;
391 g_work.lastpress = pressure;
392 }
393 }
394
395
396 //=====================================
397 // 線を引く
398 //=====================================
399
400
401 /** ブラシで線を引く (線形補間)
402 *
403 * @return 次の t 値が返る */
404
TileImage_drawBrushLine(TileImage * p,double x1,double y1,double x2,double y2,double press_st,double press_ed,double t_start)405 double TileImage_drawBrushLine(TileImage *p,
406 double x1,double y1,double x2,double y2,
407 double press_st,double press_ed,double t_start)
408 {
409 BrushDrawParam *param = _BRUSHPARAM;
410 double len,t,dx,dy,ttm,dtmp;
411 double press_len,radius_len,opa_len,press,radius,opacity;
412
413 //線の長さ
414
415 dx = x2 - x1;
416 dy = y2 - y1;
417
418 len = sqrt(dx * dx + dy * dy);
419 if(len == 0) return t_start;
420
421 //間隔を長さ 1.0 に対する値に
422
423 ttm = param->interval / len;
424
425 //各値の幅
426
427 radius_len = 1.0 - param->min_size;
428 opa_len = 1.0 - param->min_opacity;
429 press_len = press_ed - press_st;
430
431 //------------------
432
433 t = t_start / len;
434
435 while(t < 1.0)
436 {
437 //筆圧
438
439 press = press_len * t + press_st;
440
441 if(param->flags & BRUSHDP_F_PRESSURE_GAMMA)
442 press = pow(press, param->pressure_gamma);
443
444 //半径、濃度
445
446 radius = (press * radius_len + param->min_size) * param->radius;
447 opacity = (press * opa_len + param->min_opacity) * param->opacity;
448
449 //点描画
450
451 _drawbrush_point(p, x1 + dx * t, y1 + dy * t, radius, opacity);
452
453 //次へ
454
455 dtmp = radius * ttm;
456 if(dtmp < 0.0001) dtmp = 0.0001;
457
458 t += dtmp;
459 }
460
461 //次回の開始 t 値 (px に変換)
462
463 return len * (t - 1.0);
464 }
465
466 /** 入り抜き指定ありの直線 */
467
TileImage_drawBrushLine_headtail(TileImage * p,double x1,double y1,double x2,double y2,uint32_t headtail)468 void TileImage_drawBrushLine_headtail(TileImage *p,
469 double x1,double y1,double x2,double y2,uint32_t headtail)
470 {
471 int head,tail;
472 double t,dx,dy,d,xx,yy,xx2,yy2;
473
474 head = headtail >> 16;
475 tail = headtail & 0xffff;
476
477 if(tail > 1000 - head)
478 tail = 1000 - head;
479
480 //両方 0 なら入り抜きなしの通常線
481
482 if(head == 0 && tail == 0)
483 {
484 TileImage_drawBrushLine(p, x1, y1, x2, y2, 1, 1, 0);
485 return;
486 }
487
488 //----------
489
490 dx = x2 - x1;
491 dy = y2 - y1;
492
493 xx = x1, yy = y1;
494 t = 0;
495
496 //入り
497
498 if(head)
499 {
500 d = head * 0.001;
501 xx = x1 + dx * d;
502 yy = y1 + dy * d;
503
504 t = TileImage_drawBrushLine(p, x1, y1, xx, yy, 0, 1, t);
505 }
506
507 //中間部分 (筆圧が最大の部分)
508
509 if(tail != 1000 - head)
510 {
511 d = (1000 - tail) * 0.001;
512 xx2 = x1 + dx * d;
513 yy2 = y1 + dy * d;
514
515 t = TileImage_drawBrushLine(p, xx, yy, xx2, yy2, 1, 1, t);
516
517 xx = xx2, yy = yy2;
518 }
519
520 //抜き
521
522 if(tail)
523 TileImage_drawBrushLine(p, xx, yy, x2, y2, 1, 0, t);
524 }
525
526 /** 四角形描画 */
527
TileImage_drawBrushBox(TileImage * p,mDoublePoint * pt)528 void TileImage_drawBrushBox(TileImage *p,mDoublePoint *pt)
529 {
530 TileImage_drawBrushLine(p, pt[0].x, pt[0].y, pt[1].x, pt[1].y, 1, 1, 0);
531 TileImage_drawBrushLine(p, pt[1].x, pt[1].y, pt[2].x, pt[2].y, 1, 1, 0);
532 TileImage_drawBrushLine(p, pt[2].x, pt[2].y, pt[3].x, pt[3].y, 1, 1, 0);
533 TileImage_drawBrushLine(p, pt[3].x, pt[3].y, pt[0].x, pt[0].y, 1, 1, 0);
534 }
535
536
537 //=====================================
538 // 点の描画
539 //=====================================
540
541 #define FIXF_BIT 10
542 #define FIXF_VAL (1<<FIXF_BIT)
543
544
545 /** 円形 (硬い) */
546
_drawbrush_point_hard(TileImage * p,double drawx,double drawy,double radius,double opacity,PixelRGBA * pix)547 static void _drawbrush_point_hard(TileImage *p,
548 double drawx,double drawy,double radius,double opacity,PixelRGBA *pix)
549 {
550 int subnum,x1,y1,x2,y2,ix,iy,px,py,antialias;
551 int xtbl[11],ytbl[11],subpos[11],rr,n,fx,fy,fx_left;
552 int64_t fpos;
553 double ddiv;
554 PixelRGBA pixdraw;
555 void (*drawpix)(TileImage *,int,int,PixelRGBA *) = g_tileimage_dinfo.funcDrawPixel;
556
557 //半径の大きさによりサブピクセル数調整
558
559 if(radius < 3) subnum = 11;
560 else if(radius < 15) subnum = 5;
561 else subnum = 3;
562
563 //px 範囲
564
565 x1 = (int)floor(drawx - radius);
566 y1 = (int)floor(drawy - radius);
567 x2 = (int)floor(drawx + radius);
568 y2 = (int)floor(drawy + radius);
569
570 //座標は固定少数点数にする
571
572 fx_left = floor((x1 - drawx) * FIXF_VAL);
573 fy = floor((y1 - drawy) * FIXF_VAL);
574 rr = floor(radius * radius * FIXF_VAL);
575 ddiv = 1.0 / (subnum * subnum);
576
577 pixdraw = *pix;
578 antialias = (_BRUSHPARAM->flags & BRUSHDP_F_ANTIALIAS);
579
580 for(ix = 0; ix < subnum; ix++)
581 subpos[ix] = (ix << FIXF_BIT) / subnum;
582
583 //------------------
584
585 for(py = y1; py <= y2; py++, fy += FIXF_VAL)
586 {
587 //Y テーブル
588
589 for(iy = 0; iy < subnum; iy++)
590 {
591 fpos = fy + subpos[iy];
592 ytbl[iy] = fpos * fpos >> FIXF_BIT;
593 }
594
595 //
596
597 for(px = x1, fx = fx_left; px <= x2; px++, fx += FIXF_VAL)
598 {
599 //X テーブル
600
601 for(ix = 0; ix < subnum; ix++)
602 {
603 fpos = fx + subpos[ix];
604 xtbl[ix] = fpos * fpos >> FIXF_BIT;
605 }
606
607 //オーバーサンプリングで円の内外判定
608
609 n = 0;
610
611 for(iy = 0; iy < subnum; iy++)
612 {
613 for(ix = 0; ix < subnum; ix++)
614 {
615 if(xtbl[ix] + ytbl[iy] < rr) n++;
616 }
617 }
618
619 //1px 点を打つ
620
621 if(n)
622 {
623 n = (int)(opacity * (n * ddiv) + 0.5);
624 if(n)
625 {
626 if(antialias)
627 pixdraw.a = n;
628 else
629 pixdraw.a = (int)(opacity + 0.5);
630
631 (drawpix)(p, px, py, &pixdraw);
632 }
633 }
634 }
635 }
636 }
637
638 /** 円形 (柔らかい1) */
639
_drawbrush_point_soft1(TileImage * p,double drawx,double drawy,double radius,double opacity,PixelRGBA * pix)640 static void _drawbrush_point_soft1(TileImage *p,
641 double drawx,double drawy,double radius,double opacity,PixelRGBA *pix)
642 {
643 int subnum,x1,y1,x2,y2,ix,iy,px,py,c,antialias;
644 double dsubadd,dsumdiv,dtmp,dsum,rrdiv,ytbl[11],xtbl[11];
645 PixelRGBA pixdraw;
646 void (*drawpix)(TileImage *,int,int,PixelRGBA *) = g_tileimage_dinfo.funcDrawPixel;
647
648 //半径の大きさによりサブピクセル数調整
649
650 if(radius < 3) subnum = 11;
651 else if(radius < 15) subnum = 5;
652 else if(radius < 40) subnum = 3;
653 else subnum = 1;
654
655 //px 範囲
656
657 x1 = (int)floor(drawx - radius);
658 y1 = (int)floor(drawy - radius);
659 x2 = (int)floor(drawx + radius);
660 y2 = (int)floor(drawy + radius);
661
662 //
663
664 rrdiv = 1.0 / (radius * radius);
665 dsubadd = 1.0 / subnum;
666 dsumdiv = 1.0 / (subnum * subnum);
667
668 pixdraw = *pix;
669 antialias = (_BRUSHPARAM->flags & BRUSHDP_F_ANTIALIAS);
670
671 //------------------
672
673 for(py = y1; py <= y2; py++)
674 {
675 //Y テーブル
676
677 for(iy = 0, dtmp = py - drawy; iy < subnum; iy++, dtmp += dsubadd)
678 ytbl[iy] = dtmp * dtmp;
679
680 //
681
682 for(px = x1; px <= x2; px++)
683 {
684 //X テーブル
685
686 for(ix = 0, dtmp = px - drawx; ix < subnum; ix++, dtmp += dsubadd)
687 xtbl[ix] = dtmp * dtmp;
688
689 //オーバーサンプリング
690
691 dsum = 0;
692
693 for(iy = 0; iy < subnum; iy++)
694 {
695 for(ix = 0; ix < subnum; ix++)
696 {
697 dtmp = (xtbl[ix] + ytbl[iy]) * rrdiv;
698
699 if(dtmp < 1)
700 {
701 //半径 0.3 以内は最大濃度、それ以上は 0.0-1.0 に置換
702
703 if(dtmp < 0.3)
704 dtmp = 0;
705 else
706 dtmp = (dtmp - 0.3) * (1.0 / 0.7);
707
708 dsum += 1.0 - dtmp;
709 }
710 }
711 }
712
713 //1px 点を打つ
714
715 if(dsum != 0)
716 {
717 c = (int)(opacity * (dsum * dsumdiv) + 0.5);
718 if(c)
719 {
720 if(antialias)
721 pixdraw.a = c;
722 else
723 pixdraw.a = (int)(opacity + 0.5);
724
725 (drawpix)(p, px, py, &pixdraw);
726 }
727 }
728 }
729 }
730 }
731
732 /** 円形 (柔らかい2) */
733
_drawbrush_point_soft2(TileImage * p,double drawx,double drawy,double radius,double opacity,PixelRGBA * pix)734 static void _drawbrush_point_soft2(TileImage *p,
735 double drawx,double drawy,double radius,double opacity,PixelRGBA *pix)
736 {
737 int subnum,x1,y1,x2,y2,ix,iy,px,py,c,antialias;
738 double dsubadd,dsumdiv,dtmp,dsum,rrdiv,ytbl[11],xtbl[11];
739 PixelRGBA pixdraw;
740 void (*drawpix)(TileImage *,int,int,PixelRGBA *) = g_tileimage_dinfo.funcDrawPixel;
741
742 //半径の大きさによりサブピクセル数調整
743
744 if(radius < 3) subnum = 11;
745 else if(radius < 15) subnum = 5;
746 else if(radius < 40) subnum = 3;
747 else subnum = 1;
748
749 //px 範囲
750
751 x1 = (int)floor(drawx - radius);
752 y1 = (int)floor(drawy - radius);
753 x2 = (int)floor(drawx + radius);
754 y2 = (int)floor(drawy + radius);
755
756 //
757
758 rrdiv = 1.0 / (radius * radius);
759 dsubadd = 1.0 / subnum;
760 dsumdiv = 1.0 / (subnum * subnum);
761
762 pixdraw = *pix;
763 antialias = (_BRUSHPARAM->flags & BRUSHDP_F_ANTIALIAS);
764
765 //------------------
766
767 for(py = y1; py <= y2; py++)
768 {
769 //Y テーブル
770
771 for(iy = 0, dtmp = py - drawy; iy < subnum; iy++, dtmp += dsubadd)
772 ytbl[iy] = dtmp * dtmp;
773
774 //
775
776 for(px = x1; px <= x2; px++)
777 {
778 //X テーブル
779
780 for(ix = 0, dtmp = px - drawx; ix < subnum; ix++, dtmp += dsubadd)
781 xtbl[ix] = dtmp * dtmp;
782
783 //オーバーサンプリング
784
785 dsum = 0;
786
787 for(iy = 0; iy < subnum; iy++)
788 {
789 for(ix = 0; ix < subnum; ix++)
790 {
791 //半径をそのまま濃度に
792
793 dtmp = (xtbl[ix] + ytbl[iy]) * rrdiv;
794
795 if(dtmp < 1)
796 dsum += 1.0 - dtmp;
797 }
798 }
799
800 //1px 点を打つ
801
802 if(dsum != 0)
803 {
804 c = (int)(opacity * (dsum * dsumdiv) + 0.5);
805 if(c)
806 {
807 if(antialias)
808 pixdraw.a = c;
809 else
810 pixdraw.a = (int)(opacity + 0.5);
811
812 (drawpix)(p, px, py, &pixdraw);
813 }
814 }
815 }
816 }
817 }
818
819 /** 円形 (柔らかい3) */
820
_drawbrush_point_soft3(TileImage * p,double drawx,double drawy,double radius,double opacity,PixelRGBA * pix)821 static void _drawbrush_point_soft3(TileImage *p,
822 double drawx,double drawy,double radius,double opacity,PixelRGBA *pix)
823 {
824 int subnum,x1,y1,x2,y2,ix,iy,px,py,c,antialias;
825 double dsubadd,dsumdiv,dtmp,dsum,rrdiv,ytbl[11],xtbl[11];
826 PixelRGBA pixdraw;
827 void (*drawpix)(TileImage *,int,int,PixelRGBA *) = g_tileimage_dinfo.funcDrawPixel;
828
829 //半径の大きさによりサブピクセル数調整
830
831 if(radius < 3) subnum = 11;
832 else if(radius < 15) subnum = 5;
833 else if(radius < 40) subnum = 3;
834 else subnum = 1;
835
836 //px 範囲
837
838 x1 = (int)floor(drawx - radius);
839 y1 = (int)floor(drawy - radius);
840 x2 = (int)floor(drawx + radius);
841 y2 = (int)floor(drawy + radius);
842
843 //
844
845 rrdiv = 1.0 / (radius * radius);
846 dsubadd = 1.0 / subnum;
847 dsumdiv = 1.0 / (subnum * subnum);
848
849 pixdraw = *pix;
850 antialias = (_BRUSHPARAM->flags & BRUSHDP_F_ANTIALIAS);
851
852 //------------------
853
854 for(py = y1; py <= y2; py++)
855 {
856 //Y テーブル
857
858 for(iy = 0, dtmp = py - drawy; iy < subnum; iy++, dtmp += dsubadd)
859 ytbl[iy] = dtmp * dtmp;
860
861 //
862
863 for(px = x1; px <= x2; px++)
864 {
865 //X テーブル
866
867 for(ix = 0, dtmp = px - drawx; ix < subnum; ix++, dtmp += dsubadd)
868 xtbl[ix] = dtmp * dtmp;
869
870 //オーバーサンプリング
871
872 dsum = 0;
873
874 for(iy = 0; iy < subnum; iy++)
875 {
876 for(ix = 0; ix < subnum; ix++)
877 {
878 dtmp = (xtbl[ix] + ytbl[iy]) * rrdiv;
879
880 if(dtmp < 1)
881 {
882 dtmp = 1.0 - dtmp;
883
884 dtmp = dtmp - dtmp * 0.25;
885 if(dtmp < 0) dtmp = 0;
886
887 dsum += dtmp;
888 }
889 }
890 }
891
892 //1px 点を打つ
893
894 if(dsum != 0)
895 {
896 c = (int)(opacity * (dsum * dsumdiv) + 0.5);
897 if(c)
898 {
899 if(antialias)
900 pixdraw.a = c;
901 else
902 pixdraw.a = (int)(opacity + 0.5);
903
904 (drawpix)(p, px, py, &pixdraw);
905 }
906 }
907 }
908 }
909 }
910
911 /** ブラシ、点の描画 */
912
_drawbrush_point(TileImage * p,double x,double y,double radius,double opacity)913 void _drawbrush_point(TileImage *p,
914 double x,double y,double radius,double opacity)
915 {
916 PixelRGBA pix;
917 void (*drawpoint[4])(TileImage *p,double,double,double,double,PixelRGBA *) =
918 {
919 _drawbrush_point_hard, _drawbrush_point_soft1,
920 _drawbrush_point_soft2, _drawbrush_point_soft3
921 };
922
923 if(opacity != 0 && radius > 0.05)
924 {
925 pix = g_tileimage_dinfo.pixdraw;
926
927 //水彩、描画色の計算
928
929 if(_BRUSHPARAM->flags & BRUSHDP_F_WATER)
930 {
931 _water_calc_drawcol(p, x, y, radius, &opacity, &pix);
932
933 if(opacity == 0) return;
934 }
935
936 //
937
938 (drawpoint[_BRUSHPARAM->shape])(p, x, y, radius, opacity, &pix);
939 }
940 }
941