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