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  * TileImage
22  **********************************/
23 
24 #include <string.h>
25 
26 #include "mDef.h"
27 #include "mRectBox.h"
28 #include "mPixbuf.h"
29 
30 #include "defTileImage.h"
31 
32 #include "TileImage.h"
33 #include "TileImage_pv.h"
34 #include "TileImage_coltype.h"
35 #include "TileImageDrawInfo.h"
36 
37 #include "ImageBufRGB16.h"
38 #include "blendcol.h"
39 
40 
41 //--------------------------
42 /* グローバル変数 */
43 
44 TileImageDrawInfo g_tileimage_dinfo;	//描画用情報
45 TileImageWorkData g_tileimage_work;		//作業用データ
46 TileImageColtypeFuncs g_tileimage_funcs[4];	//各カラータイプ毎の関数
47 
48 //--------------------------
49 
50 void __TileImage_initCurve();
51 
52 //--------------------------
53 
54 
55 
56 //==========================
57 // TileImageDrawInfo
58 //==========================
59 
60 
61 /** TileImageDrawInfo の rcdraw の範囲をクリア */
62 
TileImageDrawInfo_clearDrawRect()63 void TileImageDrawInfo_clearDrawRect()
64 {
65 	g_tileimage_dinfo.rcdraw.x1 = g_tileimage_dinfo.rcdraw.y1 = 1;
66 	g_tileimage_dinfo.rcdraw.x2 = g_tileimage_dinfo.rcdraw.y2 = 0;
67 }
68 
69 
70 //==========================
71 // 全体の初期化/解放
72 //==========================
73 
74 
75 /** 初期化 */
76 
TileImage_init()77 mBool TileImage_init()
78 {
79 	TileImageWorkData *work = &g_tileimage_work;
80 	int size;
81 
82 	work->dot_size = 0;
83 
84 	//作業用バッファ確保
85 
86 	size = TILEIMAGE_DOTSTYLE_RADIUS_MAX * 2 + 1;
87 	size *= size;
88 
89 	work->dotstyle = (uint8_t *)mMalloc((size + 7) / 8, FALSE);
90 	if(!work->dotstyle) return FALSE;
91 
92 	work->fingerbuf = (RGBAFix15 *)mMalloc(size * 8, FALSE);
93 	if(!work->fingerbuf) return FALSE;
94 
95 	//曲線補間用パラメータ
96 
97 	__TileImage_initCurve();
98 
99 	//カラータイプ毎の関数テーブル
100 
101 	__TileImage_RGBA_setFuncTable(g_tileimage_funcs + TILEIMAGE_COLTYPE_RGBA);
102 	__TileImage_Gray_setFuncTable(g_tileimage_funcs + TILEIMAGE_COLTYPE_GRAY);
103 	__TileImage_A16_setFuncTable(g_tileimage_funcs + TILEIMAGE_COLTYPE_ALPHA16);
104 	__TileImage_A1_setFuncTable(g_tileimage_funcs + TILEIMAGE_COLTYPE_ALPHA1);
105 
106 	return TRUE;
107 }
108 
109 /** 終了時 */
110 
TileImage_finish()111 void TileImage_finish()
112 {
113 	mFree(g_tileimage_work.dotstyle);
114 	mFree(g_tileimage_work.fingerbuf);
115 }
116 
117 
118 //==========================
119 // 解放
120 //==========================
121 
122 
123 /** すべて解放 */
124 
TileImage_free(TileImage * p)125 void TileImage_free(TileImage *p)
126 {
127 	uint8_t **pp;
128 	uint32_t i;
129 
130 	if(p)
131 	{
132 		if(p->ppbuf)
133 		{
134 			pp = p->ppbuf;
135 
136 			for(i = p->tilew * p->tileh; i; i--, pp++)
137 			{
138 				if(*pp && *pp != TILEIMAGE_TILE_EMPTY)
139 					mFree(*pp);
140 			}
141 
142 			mFree(p->ppbuf);
143 		}
144 
145 		mFree(p);
146 	}
147 }
148 
149 /** 一つのタイルを解放 */
150 
TileImage_freeTile(uint8_t ** pptile)151 void TileImage_freeTile(uint8_t **pptile)
152 {
153 	if(*pptile)
154 	{
155 		if(*pptile != TILEIMAGE_TILE_EMPTY)
156 			mFree(*pptile);
157 
158 		*pptile = NULL;
159 	}
160 }
161 
162 /** 指定タイル位置のタイルを解放 (UNDO用) */
163 
TileImage_freeTile_atPos(TileImage * p,int tx,int ty)164 void TileImage_freeTile_atPos(TileImage *p,int tx,int ty)
165 {
166 	uint8_t **pp = TILEIMAGE_GETTILE_BUFPT(p, tx, ty);
167 
168 	if(*pp)
169 		TileImage_freeTile(pp);
170 }
171 
172 /** 指定px位置のタイルを解放 (UNDO用) */
173 
TileImage_freeTile_atPixel(TileImage * p,int x,int y)174 void TileImage_freeTile_atPixel(TileImage *p,int x,int y)
175 {
176 	int tx,ty;
177 
178 	if(TileImage_pixel_to_tile(p, x, y, &tx, &ty))
179 		TileImage_freeTile_atPos(p, tx, ty);
180 }
181 
182 /** 全タイルとタイルバッファを解放 (TileImage 自体は残す) */
183 
TileImage_freeTileBuf(TileImage * p)184 void TileImage_freeTileBuf(TileImage *p)
185 {
186 	if(p)
187 	{
188 		TileImage_freeAllTiles(p);
189 
190 		mFree(p->ppbuf);
191 		p->ppbuf = NULL;
192 	}
193 }
194 
195 /** タイルをすべて解放 (タイル配列は残す) */
196 
TileImage_freeAllTiles(TileImage * p)197 void TileImage_freeAllTiles(TileImage *p)
198 {
199 	uint8_t **pp;
200 	int i;
201 
202 	if(p && p->ppbuf)
203 	{
204 		pp = p->ppbuf;
205 
206 		for(i = p->tilew * p->tileh; i; i--, pp++)
207 			TileImage_freeTile(pp);
208 	}
209 }
210 
211 /** 空のタイルをすべて解放
212  *
213  * @return すべて空なら TRUE */
214 
TileImage_freeEmptyTiles(TileImage * p)215 mBool TileImage_freeEmptyTiles(TileImage *p)
216 {
217 	uint8_t **ppbuf;
218 	uint32_t i;
219 	TileImageColFunc_isTransparentTile func;
220 	mBool empty = TRUE;
221 
222 	if(p && p->ppbuf)
223 	{
224 		ppbuf = p->ppbuf;
225 		func = g_tileimage_funcs[p->coltype].isTransparentTile;
226 
227 		for(i = p->tilew * p->tileh; i; i--, ppbuf++)
228 		{
229 			if(*ppbuf)
230 			{
231 				if((func)(*ppbuf))
232 					TileImage_freeTile(ppbuf);
233 				else
234 					empty = FALSE;
235 			}
236 		}
237 	}
238 
239 	return empty;
240 }
241 
242 /** 空のタイルをすべて解放 (アンドゥ側でタイルが確保されている部分のみ)
243  *
244  * アンドゥ用イメージでタイルが確保されている部分は、イメージが変更された部分。
245  * それらの中で、消しゴム等ですべて透明になったタイルは解放して、メモリ負担を軽減させる。 */
246 
TileImage_freeEmptyTiles_byUndo(TileImage * p,TileImage * imgundo)247 void TileImage_freeEmptyTiles_byUndo(TileImage *p,TileImage *imgundo)
248 {
249 	uint8_t **ppbuf,**ppundo;
250 	uint32_t i;
251 	TileImageColFunc_isTransparentTile func = g_tileimage_funcs[p->coltype].isTransparentTile;
252 
253 	if(imgundo)
254 	{
255 		ppbuf = p->ppbuf;
256 		ppundo = imgundo->ppbuf;
257 
258 		for(i = p->tilew * p->tileh; i; i--, ppbuf++, ppundo++)
259 		{
260 			if(*ppundo && *ppbuf && (func)(*ppbuf))
261 				TileImage_freeTile(ppbuf);
262 		}
263 	}
264 }
265 
266 
267 
268 //==========================
269 // 作成/複製
270 //==========================
271 
272 
273 /** 作成 (px サイズ指定) */
274 
TileImage_new(int type,int w,int h)275 TileImage *TileImage_new(int type,int w,int h)
276 {
277 	return __TileImage_create(type, (w + 63) / 64, (h + 63) / 64);
278 }
279 
280 /** 作成 (TileImageInfo から) */
281 
TileImage_newFromInfo(int type,TileImageInfo * info)282 TileImage *TileImage_newFromInfo(int type,TileImageInfo *info)
283 {
284 	TileImage *p;
285 
286 	if(info->tilew <= 0 || info->tileh <= 0)
287 		return TileImage_new(type, 1, 1);
288 	else
289 	{
290 		p = __TileImage_create(type, info->tilew, info->tileh);
291 		if(p)
292 		{
293 			p->offx = info->offx;
294 			p->offy = info->offy;
295 		}
296 
297 		return p;
298 	}
299 }
300 
301 /** 作成 (ピクセル範囲から) */
302 
TileImage_newFromRect(int type,mRect * rc)303 TileImage *TileImage_newFromRect(int type,mRect *rc)
304 {
305 	TileImageInfo info;
306 
307 	info.offx = rc->x1;
308 	info.offy = rc->y1;
309 	info.tilew = (rc->x2 - rc->x1 + 1 + 63) >> 6;
310 	info.tileh = (rc->y2 - rc->y1 + 1 + 63) >> 6;
311 
312 	return TileImage_newFromInfo(type, &info);
313 }
314 
315 /** 作成 (ピクセル範囲から。ファイル読み込み用)
316  *
317  * @param rc  x2,y2 は +1。x1 >= x2 or y1 >= y2 で空状態。 */
318 
TileImage_newFromRect_forFile(int type,mRect * rc)319 TileImage *TileImage_newFromRect_forFile(int type,mRect *rc)
320 {
321 	TileImageInfo info;
322 
323 	if(rc->x1 >= rc->x2 && rc->y1 >= rc->y2)
324 	{
325 		//空
326 
327 		info.offx = info.offy = 0;
328 		info.tilew = info.tileh = 1;
329 	}
330 	else
331 	{
332 		info.tilew = (rc->x2 - rc->x1) >> 6;
333 		info.tileh = (rc->y2 - rc->y1) >> 6;
334 
335 		if(info.tilew <= 0) info.tilew = 1;
336 		if(info.tileh <= 0) info.tileh = 1;
337 
338 		info.offx = rc->x1;
339 		info.offy = rc->y1;
340 	}
341 
342 	return TileImage_newFromInfo(type, &info);
343 }
344 
345 /** 複製を新規作成 (タイルイメージも含む) */
346 
TileImage_newClone(TileImage * src)347 TileImage *TileImage_newClone(TileImage *src)
348 {
349 	TileImage *p;
350 	uint32_t i;
351 	uint8_t **ppsrc,**ppdst;
352 
353 	//作成
354 
355 	p = __TileImage_create(src->coltype, src->tilew, src->tileh);
356 	if(!p) return NULL;
357 
358 	p->offx = src->offx;
359 	p->offy = src->offy;
360 	p->rgb  = src->rgb;
361 
362 	//タイルコピー
363 
364 	ppsrc = src->ppbuf;
365 	ppdst = p->ppbuf;
366 
367 	for(i = p->tilew * p->tileh; i; i--, ppsrc++, ppdst++)
368 	{
369 		if(*ppsrc)
370 		{
371 			*ppdst = TileImage_allocTile(p, FALSE);
372 			if(!(*ppdst))
373 			{
374 				TileImage_free(p);
375 				return NULL;
376 			}
377 
378 			memcpy(*ppdst, *ppsrc, p->tilesize);
379 		}
380 	}
381 
382 	return p;
383 }
384 
385 
386 //==========================
387 //
388 //==========================
389 
390 
391 /** src と同じ構成になるように作成、または配列リサイズ
392  *
393  * 描画時の元イメージ保存用、またはストローク用イメージなどの作成に使う。
394  * p が NULL なら新規作成。構成が同じならそのまま p が返る。
395  * エラーなら解放されて NULL が返る。
396  *
397  * @param type カラータイプ。負の値で src と同じ */
398 
TileImage_createSame(TileImage * p,TileImage * src,int type)399 TileImage *TileImage_createSame(TileImage *p,TileImage *src,int type)
400 {
401 	if(type < 0) type = src->coltype;
402 
403 	if(!p)
404 	{
405 		//------ 新規作成
406 
407 		TileImageInfo info;
408 
409 		TileImage_getInfo(src, &info);
410 
411 		return TileImage_newFromInfo(type, &info);
412 	}
413 	else
414 	{
415 		//------ 作成済み。構成が同じならそのまま返す
416 
417 		//移動ツールで移動した場合があるので、常にコピー
418 
419 		p->offx = src->offx;
420 		p->offy = src->offy;
421 
422 		//構成が異なる
423 
424 		if(p->coltype != type || p->tilew != src->tilew || p->tileh != src->tileh)
425 		{
426 			//タイプ
427 
428 			p->coltype = type;
429 
430 			__TileImage_setTileSize(p);
431 
432 			//配列再作成
433 
434 			TileImage_freeTileBuf(p);
435 
436 			p->tilew = src->tilew;
437 			p->tileh = src->tileh;
438 
439 			if(!__TileImage_allocTileBuf(p))
440 			{
441 				TileImage_free(p);
442 				p = NULL;
443 			}
444 		}
445 
446 		return p;
447 	}
448 }
449 
450 /** イメージをクリアする
451  *
452  * タイルを削除して、タイル配列を 1x1 にする。 */
453 
TileImage_clear(TileImage * p)454 void TileImage_clear(TileImage *p)
455 {
456 	TileImage_freeTileBuf(p);
457 
458 	p->offx = p->offy = 0;
459 	p->tilew = p->tileh = 1;
460 
461 	__TileImage_allocTileBuf(p);
462 }
463 
464 
465 //===============================
466 // タイル配列
467 //===============================
468 
469 
470 /** タイル配列をイメージサイズから再作成 */
471 
TileImage_reallocTileBuf_fromImageSize(TileImage * p,int w,int h)472 mBool TileImage_reallocTileBuf_fromImageSize(TileImage *p,int w,int h)
473 {
474 	TileImage_freeTileBuf(p);
475 
476 	p->offx = p->offy = 0;
477 	p->tilew = (w + 63) >> 6;
478 	p->tileh = (h + 63) >> 6;
479 
480 	return __TileImage_allocTileBuf(p);
481 }
482 
483 /** タイル配列リサイズ (現在の画像サイズ全体を含むように) */
484 
TileImage_resizeTileBuf_includeImage(TileImage * p)485 mBool TileImage_resizeTileBuf_includeImage(TileImage *p)
486 {
487 	mRect rc;
488 
489 	//描画可能な範囲
490 
491 	TileImage_getCanDrawRect_pixel(p, &rc);
492 
493 	//px -> タイル位置
494 
495 	TileImage_pixel_to_tile_rect(p, &rc);
496 
497 	//リサイズ
498 
499 	return __TileImage_resizeTileBuf(p, rc.x1, rc.y1,
500 			rc.x2 - rc.x1 + 1, rc.y2 - rc.y1 + 1);
501 }
502 
503 /** 2つのイメージを結合した範囲でタイル配列リサイズ */
504 
TileImage_resizeTileBuf_combine(TileImage * p,TileImage * src)505 mBool TileImage_resizeTileBuf_combine(TileImage *p,TileImage *src)
506 {
507 	mRect rc,rc2;
508 	int tx1,ty1,tx2,ty2;
509 
510 	//px 範囲を結合
511 
512 	TileImage_getAllTilesPixelRect(p, &rc);
513 	TileImage_getAllTilesPixelRect(src, &rc2);
514 
515 	mRectUnion(&rc, &rc2);
516 
517 	//px 範囲 -> p におけるタイル位置
518 
519 	TileImage_pixel_to_tile_nojudge(p, rc.x1, rc.y1, &tx1, &ty1);
520 	TileImage_pixel_to_tile_nojudge(p, rc.x2, rc.y2, &tx2, &ty2);
521 
522 	return __TileImage_resizeTileBuf(p, tx1, ty1, tx2 - tx1 + 1, ty2 - ty1 + 1);
523 }
524 
525 /** タイル配列リサイズ (UNDO用) */
526 
TileImage_resizeTileBuf_forUndo(TileImage * p,TileImageInfo * info)527 mBool TileImage_resizeTileBuf_forUndo(TileImage *p,TileImageInfo *info)
528 {
529 	uint8_t **ppnew,**ppd;
530 	int ttx,tty,ix,iy,tx,ty,sw,sh;
531 
532 	//配列は変更なし
533 
534 	if(info->tilew == p->tilew && info->tileh == p->tileh)
535 		return TRUE;
536 
537 	//新規確保
538 
539 	ppnew = __TileImage_allocTileBuf_new(info->tilew, info->tileh, TRUE);
540 	if(!ppnew) return FALSE;
541 
542 	//データコピー
543 
544 	ppd = ppnew;
545 	ttx = (info->offx - p->offx) >> 6;
546 	tty = (info->offy - p->offy) >> 6;
547 	sw = p->tilew;
548 	sh = p->tileh;
549 
550 	for(iy = info->tileh, ty = tty; iy > 0; iy--, ty++)
551 	{
552 		for(ix = info->tilew, tx = ttx; ix > 0; ix--, tx++, ppd++)
553 		{
554 			if(tx >= 0 && tx < sw && ty >= 0 && ty < sh)
555 				*ppd = *(p->ppbuf + ty * sw + tx);
556 		}
557 	}
558 
559 	//入れ替え
560 
561 	mFree(p->ppbuf);
562 
563 	p->ppbuf = ppnew;
564 	p->tilew = info->tilew;
565 	p->tileh = info->tileh;
566 	p->offx  = info->offx;
567 	p->offy  = info->offy;
568 
569 	return TRUE;
570 }
571 
572 
573 //==========================
574 // タイル
575 //==========================
576 
577 
578 /** 一つのタイルを確保 */
579 
TileImage_allocTile(TileImage * p,mBool clear)580 uint8_t *TileImage_allocTile(TileImage *p,mBool clear)
581 {
582 	return (uint8_t *)mMalloc(p->tilesize, clear);
583 }
584 
585 /** ポインタの位置にタイルがなければ確保
586  *
587  * @return FALSE で、タイルの新規確保に失敗 */
588 
TileImage_allocTile_atptr(TileImage * p,uint8_t ** ppbuf,mBool clear)589 mBool TileImage_allocTile_atptr(TileImage *p,uint8_t **ppbuf,mBool clear)
590 {
591 	if(!(*ppbuf))
592 	{
593 		*ppbuf = TileImage_allocTile(p, clear);
594 		if(!(*ppbuf)) return FALSE;
595 	}
596 
597 	return TRUE;
598 }
599 
600 /** 指定タイル位置のタイルを取得 (タイルが確保されていなければ確保する)
601  *
602  * @return タイルポインタ。位置が範囲外や、確保失敗の場合は NULL */
603 
TileImage_getTileAlloc_atpos(TileImage * p,int tx,int ty,mBool clear)604 uint8_t *TileImage_getTileAlloc_atpos(TileImage *p,int tx,int ty,mBool clear)
605 {
606 	uint8_t **pp;
607 
608 	if(tx < 0 || ty < 0 || tx >= p->tilew || ty >= p->tileh)
609 		return NULL;
610 	else
611 	{
612 		pp = TILEIMAGE_GETTILE_BUFPT(p, tx, ty);
613 
614 		if(!(*pp))
615 			*pp = TileImage_allocTile(p, clear);
616 
617 		return *pp;
618 	}
619 }
620 
621 
622 //==========================
623 // セット/変更
624 //==========================
625 
626 
627 /** オフセット位置をセット */
628 
TileImage_setOffset(TileImage * p,int offx,int offy)629 void TileImage_setOffset(TileImage *p,int offx,int offy)
630 {
631 	p->offx = offx;
632 	p->offy = offy;
633 }
634 
635 /** オフセット位置を相対移動 */
636 
TileImage_moveOffset_rel(TileImage * p,int x,int y)637 void TileImage_moveOffset_rel(TileImage *p,int x,int y)
638 {
639 	p->offx += x;
640 	p->offy += y;
641 }
642 
643 /** A16/1 時の線の色セット */
644 
TileImage_setImageColor(TileImage * p,uint32_t col)645 void TileImage_setImageColor(TileImage *p,uint32_t col)
646 {
647 	RGBtoRGBFix15(&p->rgb, col);
648 }
649 
650 
651 //==========================
652 // 計算など
653 //==========================
654 
655 
656 /** px 位置からタイル位置を取得
657  *
658  * @return FALSE で範囲外 */
659 
TileImage_pixel_to_tile(TileImage * p,int x,int y,int * tilex,int * tiley)660 mBool TileImage_pixel_to_tile(TileImage *p,int x,int y,int *tilex,int *tiley)
661 {
662 	x = (x - p->offx) >> 6;
663 	y = (y - p->offy) >> 6;
664 
665 	*tilex = x;
666 	*tiley = y;
667 
668 	return (x >= 0 && x < p->tilew && y >= 0 && y < p->tileh);
669 }
670 
671 /** px 位置からタイル位置を取得 (範囲外判定を行わない) */
672 
TileImage_pixel_to_tile_nojudge(TileImage * p,int x,int y,int * tilex,int * tiley)673 void TileImage_pixel_to_tile_nojudge(TileImage *p,int x,int y,int *tilex,int *tiley)
674 {
675 	*tilex = (x - p->offx) >> 6;
676 	*tiley = (y - p->offy) >> 6;
677 }
678 
679 /** px -> タイル位置 (mRect) */
680 
TileImage_pixel_to_tile_rect(TileImage * p,mRect * rc)681 void TileImage_pixel_to_tile_rect(TileImage *p,mRect *rc)
682 {
683 	TileImage_pixel_to_tile_nojudge(p, rc->x1, rc->y1, &rc->x1, &rc->y1);
684 	TileImage_pixel_to_tile_nojudge(p, rc->x2, rc->y2, &rc->x2, &rc->y2);
685 }
686 
687 /** タイル位置から左上の px 位置取得 */
688 
TileImage_tile_to_pixel(TileImage * p,int tx,int ty,int * px,int * py)689 void TileImage_tile_to_pixel(TileImage *p,int tx,int ty,int *px,int *py)
690 {
691 	*px = (tx << 6) + p->offx;
692 	*py = (ty << 6) + p->offy;
693 }
694 
695 /** すべてのタイルの範囲を px で取得 */
696 
TileImage_getAllTilesPixelRect(TileImage * p,mRect * rc)697 void TileImage_getAllTilesPixelRect(TileImage *p,mRect *rc)
698 {
699 	int x1,y1,x2,y2;
700 
701 	TileImage_tile_to_pixel(p, 0, 0, &x1, &y1);
702 	TileImage_tile_to_pixel(p, p->tilew - 1, p->tileh - 1, &x2, &y2);
703 
704 	rc->x1 = x1, rc->y1 = y1;
705 	rc->x2 = x2 + 63, rc->y2 = y2 + 63;
706 }
707 
708 
709 //======================
710 // 情報取得
711 //======================
712 
713 
714 /** オフセット位置を取得 */
715 
TileImage_getOffset(TileImage * p,mPoint * pt)716 void TileImage_getOffset(TileImage *p,mPoint *pt)
717 {
718 	pt->x = p->offx;
719 	pt->y = p->offy;
720 }
721 
722 /** イメージ情報取得 */
723 
TileImage_getInfo(TileImage * p,TileImageInfo * info)724 void TileImage_getInfo(TileImage *p,TileImageInfo *info)
725 {
726 	info->tilew = p->tilew;
727 	info->tileh = p->tileh;
728 	info->offx  = p->offx;
729 	info->offy  = p->offy;
730 }
731 
732 /** 現在描画可能な範囲を px で取得
733  *
734  * タイル全体とキャンバス範囲を含む。 */
735 
TileImage_getCanDrawRect_pixel(TileImage * p,mRect * rc)736 void TileImage_getCanDrawRect_pixel(TileImage *p,mRect *rc)
737 {
738 	mRect rc1,rc2;
739 
740 	TileImage_getAllTilesPixelRect(p, &rc1);
741 
742 	rc2.x1 = rc2.y1 = 0;
743 	rc2.x2 = g_tileimage_dinfo.imgw - 1;
744 	rc2.y2 = g_tileimage_dinfo.imgh - 1;
745 
746 	//範囲を合成
747 
748 	mRectUnion(&rc1, &rc2);
749 
750 	*rc = rc1;
751 }
752 
753 /** 指定範囲 (px) 全体を含むタイル範囲を取得
754  *
755  * @param rc  タイル範囲が入る
756  * @param box イメージの範囲 (px)
757  * @return FALSE で全体がタイル範囲外 */
758 
TileImage_getTileRect_fromPixelBox(TileImage * p,mRect * rc,mBox * box)759 mBool TileImage_getTileRect_fromPixelBox(TileImage *p,mRect *rc,mBox *box)
760 {
761 	int tx1,ty1,tx2,ty2,f;
762 
763 	//box 四隅のタイル位置
764 
765 	TileImage_pixel_to_tile_nojudge(p, box->x, box->y, &tx1, &ty1);
766 	TileImage_pixel_to_tile_nojudge(p, box->x + box->w - 1, box->y + box->h - 1, &tx2, &ty2);
767 
768 	//各位置が範囲外かどうかのフラグ
769 
770 	f = (tx1 < 0) | ((tx2 < 0) << 1)
771 		| ((tx1 >= p->tilew) << 2) | ((tx2 >= p->tilew) << 3)
772 		| ((ty1 < 0) << 4) | ((ty2 < 0) << 5)
773 		| ((ty1 >= p->tileh) << 6) | ((ty2 >= p->tileh) << 7);
774 
775 	//全体が範囲外か
776 
777 	if((f & 0x03) == 0x03 || (f & 0x30) == 0x30
778 		|| (f & 0x0c) == 0x0c || (f & 0xc0) == 0xc0)
779 		return FALSE;
780 
781 	//調整
782 
783 	if(f & 1) tx1 = 0;
784 	if(f & 8) tx2 = p->tilew - 1;
785 	if(f & 0x10) ty1 = 0;
786 	if(f & 0x80) ty2 = p->tileh - 1;
787 
788 	//セット
789 
790 	rc->x1 = tx1, rc->y1 = ty1;
791 	rc->x2 = tx2, rc->y2 = ty2;
792 
793 	return TRUE;
794 }
795 
796 /** box の範囲 (px) を含むタイルを処理する際の情報を取得
797  *
798  * @return タイルの開始位置のポインタ (NULL で範囲外) */
799 
TileImage_getTileRectInfo(TileImage * p,TileImageTileRectInfo * info,mBox * box)800 uint8_t **TileImage_getTileRectInfo(TileImage *p,TileImageTileRectInfo *info,mBox *box)
801 {
802 	//タイル範囲
803 
804 	if(!TileImage_getTileRect_fromPixelBox(p, &info->rctile, box))
805 		return NULL;
806 
807 	//左上タイルの px 位置
808 
809 	TileImage_tile_to_pixel(p,
810 		info->rctile.x1, info->rctile.y1, &info->pxtop.x, &info->pxtop.y);
811 
812 	//box を mRect へ (クリッピング用)
813 
814 	info->rcclip.x1 = box->x;
815 	info->rcclip.y1 = box->y;
816 	info->rcclip.x2 = box->x + box->w;
817 	info->rcclip.y2 = box->y + box->h;
818 
819 	info->pitch = p->tilew - (info->rctile.x2 - info->rctile.x1 + 1);
820 
821 	//タイル位置
822 
823 	return TILEIMAGE_GETTILE_BUFPT(p, info->rctile.x1, info->rctile.y1);
824 }
825 
826 /** イメージが存在する部分の px 範囲取得
827  *
828  * 透明な部分は除く。キャンバスの範囲外部分も含む。
829  *
830  * @param tilenum  確保されているタイル数が入る。NULL でなし
831  * @return FALSE で範囲なし */
832 
TileImage_getHaveImageRect_pixel(TileImage * p,mRect * rcdst,int * tilenum)833 mBool TileImage_getHaveImageRect_pixel(TileImage *p,mRect *rcdst,int *tilenum)
834 {
835 	uint8_t **pp;
836 	mRect rc;
837 	int x,y,num = 0;
838 
839 	mRectEmpty(&rc);
840 
841 	//確保されているタイルの最小/最大位置
842 
843 	if(p)
844 	{
845 		pp = p->ppbuf;
846 
847 		for(y = 0; y < p->tileh; y++)
848 		{
849 			for(x = 0; x < p->tilew; x++, pp++)
850 			{
851 				if(*pp)
852 				{
853 					mRectIncPoint(&rc, x, y);
854 					num++;
855 				}
856 			}
857 		}
858 	}
859 
860 	if(tilenum) *tilenum = num;
861 
862 	//タイル位置 -> px
863 
864 	if(mRectIsEmpty(&rc))
865 	{
866 		*rcdst = rc;
867 		return FALSE;
868 	}
869 	else
870 	{
871 		TileImage_tile_to_pixel(p, 0, 0, &x, &y);
872 
873 		rcdst->x1 = x + (rc.x1 << 6);
874 		rcdst->y1 = y + (rc.y1 << 6);
875 		rcdst->x2 = x + (rc.x2 << 6) + 63;
876 		rcdst->y2 = y + (rc.y2 << 6) + 63;
877 
878 		return TRUE;
879 	}
880 }
881 
882 /** 確保されているタイルの数を取得
883  *
884  * APD v3 書き込み時 */
885 
TileImage_getHaveTileNum(TileImage * p)886 int TileImage_getHaveTileNum(TileImage *p)
887 {
888 	uint8_t **pp;
889 	int i,num = 0;
890 
891 	pp = p->ppbuf;
892 
893 	for(i = p->tilew * p->tileh; i; i--, pp++)
894 	{
895 		if(*pp) num++;
896 	}
897 
898 	return num;
899 }
900 
901 /** rc を描画可能な範囲内にクリッピング
902  *
903  * @return FALSE で全体が範囲外 */
904 
TileImage_clipCanDrawRect(TileImage * p,mRect * rc)905 mBool TileImage_clipCanDrawRect(TileImage *p,mRect *rc)
906 {
907 	mRect rc1;
908 
909 	TileImage_getCanDrawRect_pixel(p, &rc1);
910 
911 	//範囲外
912 
913 	if(rc->x1 > rc1.x2 || rc->y1 > rc1.y2
914 		|| rc->x2 < rc1.x1 || rc->y2 < rc1.y1)
915 		return FALSE;
916 
917 	//調整
918 
919 	if(rc->x1 < rc1.x1) rc->x1 = rc1.x1;
920 	if(rc->y1 < rc1.y1) rc->y1 = rc1.y1;
921 	if(rc->x2 > rc1.x2) rc->x2 = rc1.x2;
922 	if(rc->y2 > rc1.y2) rc->y2 = rc1.y2;
923 
924 	return TRUE;
925 }
926 
927 
928 //=============================
929 // いろいろ
930 //=============================
931 
932 
933 /** ImageBufRGB16 に合成 */
934 
TileImage_blendToImageRGB16(TileImage * p,ImageBufRGB16 * dst,mBox * boxdst,int opacity,int blendmode,ImageBuf8 * imgtex)935 void TileImage_blendToImageRGB16(TileImage *p,ImageBufRGB16 *dst,
936 	mBox *boxdst,int opacity,int blendmode,ImageBuf8 *imgtex)
937 {
938 	TileImageTileRectInfo info;
939 	TileImageBlendInfo binfo;
940 	uint8_t **pp;
941 	int ix,iy,px,py,tw;
942 	TileImageColFunc_blendTile func = g_tileimage_funcs[p->coltype].blendTile;
943 
944 	if(opacity == 0) return;
945 
946 	if(!(pp = TileImage_getTileRectInfo(p, &info, boxdst)))
947 		return;
948 
949 	binfo.opacity = opacity;
950 	binfo.funcBlend = g_blendcolfuncs[blendmode];
951 	binfo.imgtex = imgtex;
952 
953 	//タイル毎に合成
954 
955 	tw = info.rctile.x2 - info.rctile.x1 + 1;
956 	iy = info.rctile.y2 - info.rctile.y1 + 1;
957 
958 	for(py = info.pxtop.y; iy; iy--, py += 64, pp += info.pitch)
959 	{
960 		for(ix = tw, px = info.pxtop.x; ix; ix--, px += 64, pp++)
961 		{
962 			if(!(*pp)) continue;
963 
964 			__TileImage_setBlendInfo(&binfo, px, py, &info.rcclip);
965 
966 			binfo.tile = *pp;
967 			binfo.dst = dst->buf + binfo.dy * dst->width + binfo.dx;
968 			binfo.pitch_dst = dst->width - binfo.w;
969 
970 			(func)(p, &binfo);
971 		}
972 	}
973 }
974 
975 /** A1 タイプイメージを mPixbuf に XOR 合成 */
976 
TileImage_blendXorToPixbuf(TileImage * p,mPixbuf * pixbuf,mBox * boxdst)977 void TileImage_blendXorToPixbuf(TileImage *p,mPixbuf *pixbuf,mBox *boxdst)
978 {
979 	TileImageTileRectInfo info;
980 	TileImageBlendInfo binfo;
981 	uint8_t **pptile;
982 	int ix,iy,px,py,tw;
983 	mBox box;
984 
985 	if(!mPixbufGetClipBox_box(pixbuf, &box, boxdst)) return;
986 
987 	//描画先に相当するタイル範囲
988 
989 	if(!(pptile = TileImage_getTileRectInfo(p, &info, &box)))
990 		return;
991 
992 	//タイル毎に合成
993 
994 	tw = info.rctile.x2 - info.rctile.x1 + 1;
995 	iy = info.rctile.y2 - info.rctile.y1 + 1;
996 
997 	for(py = info.pxtop.y; iy; iy--, py += 64, pptile += info.pitch)
998 	{
999 		for(ix = tw, px = info.pxtop.x; ix; ix--, px += 64, pptile++)
1000 		{
1001 			if(*pptile)
1002 			{
1003 				__TileImage_setBlendInfo(&binfo, px, py, &info.rcclip);
1004 
1005 				binfo.tile = *pptile;
1006 
1007 				__TileImage_A1_blendXorToPixbuf(p, pixbuf, &binfo);
1008 			}
1009 		}
1010 	}
1011 }
1012 
1013 /** プレビューを mPixbuf に描画
1014  *
1015  * レイヤ一覧用。チェック柄を背景に。 */
1016 
TileImage_drawPreview(TileImage * p,mPixbuf * pixbuf,int x,int y,int boxw,int boxh,int sw,int sh)1017 void TileImage_drawPreview(TileImage *p,mPixbuf *pixbuf,
1018 	int x,int y,int boxw,int boxh,int sw,int sh)
1019 {
1020 	double dscale,d;
1021 	mBox box;
1022 	uint8_t *pd,ckcol8[2] = {224,192};
1023 	int ix,iy,pitchd,bpp,finc,finc2,fy,fx,fxleft,n,jx,jy,ff;
1024 	int ytbl[3],xtbl[3],ckx,cky,rr,gg,bb,aa,ckcol15[2] = {28783,24671};
1025 	uint32_t colex;
1026 	RGBAFix15 pix;
1027 
1028 	if(!mPixbufGetClipBox_d(pixbuf, &box, x, y, boxw, boxh))
1029 		return;
1030 
1031 	colex = mRGBtoPix(0xb0b0b0);
1032 
1033 	//倍率 (倍率の低い方、拡大はしない)
1034 
1035 	dscale = (double)boxw / sw;
1036 	d = (double)boxh / sh;
1037 
1038 	if(d < dscale) dscale = d;
1039 	if(d > 1.0) d = 1.0;
1040 
1041 	//
1042 
1043 	pd = mPixbufGetBufPtFast(pixbuf, box.x, box.y);
1044 	bpp = pixbuf->bpp;
1045 	pitchd = pixbuf->pitch_dir - box.w * bpp;
1046 
1047 	x = box.x - x;
1048 	y = box.y - y;
1049 
1050 	finc = (int)((1<<16) / dscale + 0.5);
1051 	finc2 = finc / 3;
1052 
1053 	fxleft = (int)(((x - boxw * 0.5) / dscale + sw * 0.5) * (1<<16));
1054 	fy = (int)(((y - boxh * 0.5) / dscale + sh * 0.5) * (1<<16));
1055 
1056 	cky = y & 7;
1057 
1058 	//
1059 
1060 	for(iy = box.h; iy; iy--, fy += finc, cky = (cky + 1) & 7)
1061 	{
1062 		n = fy >> 16;
1063 
1064 		if(n < 0 || n >= sh)
1065 		{
1066 			mPixbufRawLineH(pixbuf, pd, box.w, colex);
1067 			pd += pixbuf->pitch_dir;
1068 			continue;
1069 		}
1070 
1071 		//Yテーブル
1072 
1073 		for(jy = 0, ff = fy; jy < 3; jy++, ff += finc2)
1074 		{
1075 			n = ff >> 16;
1076 			if(n >= sh) n = sh - 1;
1077 
1078 			ytbl[jy] = n;
1079 		}
1080 
1081 		//----- X
1082 
1083 		ckx = x & 7;
1084 
1085 		for(ix = box.w, fx = fxleft; ix; ix--, fx += finc, pd += bpp, ckx = (ckx + 1) & 7)
1086 		{
1087 			n = fx >> 16;
1088 
1089 			if(n < 0 || n >= sw)
1090 			{
1091 				(pixbuf->setbuf)(pd, colex);
1092 				continue;
1093 			}
1094 
1095 			//Xテーブル
1096 
1097 			for(jx = 0, ff = fx; jx < 3; jx++, ff += finc2)
1098 			{
1099 				n = ff >> 16;
1100 				if(n >= sw) n = sw - 1;
1101 
1102 				xtbl[jx] = n;
1103 			}
1104 
1105 			//オーバーサンプリング
1106 
1107 			rr = gg = bb = aa = 0;
1108 
1109 			for(jy = 0; jy < 3; jy++)
1110 			{
1111 				for(jx = 0; jx < 3; jx++)
1112 				{
1113 					TileImage_getPixel(p, xtbl[jx], ytbl[jy], &pix);
1114 
1115 					if(pix.a)
1116 					{
1117 						rr += pix.r * pix.a >> 15;
1118 						gg += pix.g * pix.a >> 15;
1119 						bb += pix.b * pix.a >> 15;
1120 						aa += pix.a;
1121 					}
1122 				}
1123 			}
1124 
1125 			//チェック柄と合成
1126 
1127 			n = (ckx >> 2) ^ (cky >> 2);
1128 
1129 			if(aa == 0)
1130 				rr = gg = bb = ckcol8[n];
1131 			else
1132 			{
1133 				rr = ((int64_t)rr << 15) / aa;
1134 				gg = ((int64_t)gg << 15) / aa;
1135 				bb = ((int64_t)bb << 15) / aa;
1136 				aa /= 9;
1137 
1138 				n = ckcol15[n];
1139 
1140 				rr = (((rr - n) * aa >> 15) + n) * 255 >> 15;
1141 				gg = (((gg - n) * aa >> 15) + n) * 255 >> 15;
1142 				bb = (((bb - n) * aa >> 15) + n) * 255 >> 15;
1143 			}
1144 
1145 			(pixbuf->setbuf)(pd, mRGBtoPix2(rr,gg,bb));
1146 		}
1147 
1148 		pd += pitchd;
1149 	}
1150 }
1151 
1152 /** フィルタプレビュー描画 (イメージとチェック柄背景を合成)
1153  *
1154  * @param box イメージ座標 */
1155 
TileImage_drawFilterPreview(TileImage * p,mPixbuf * pixbuf,mBox * box)1156 void TileImage_drawFilterPreview(TileImage *p,mPixbuf *pixbuf,mBox *box)
1157 {
1158 	uint8_t *pd;
1159 	int ix,iy,pitch,w,h,fy,bkgnd,r,g,b,plaidcol[2] = {28784,24672};
1160 	RGBAFix15 pix;
1161 
1162 	w = box->w, h = box->h;
1163 
1164 	pd = mPixbufGetBufPtFast(pixbuf, 1, 1);
1165 	pitch = pixbuf->pitch_dir - pixbuf->bpp * w;
1166 
1167 	for(iy = 0; iy < h; iy++, pd += pitch)
1168 	{
1169 		fy = (iy >> 3) & 1;
1170 
1171 		for(ix = 0; ix < w; ix++, pd += pixbuf->bpp)
1172 		{
1173 			TileImage_getPixel(p, box->x + ix, box->y + iy, &pix);
1174 
1175 			bkgnd = plaidcol[fy ^ ((ix >> 3) & 1)];
1176 
1177 			if(pix.a == 0)
1178 				pix.r = pix.g = pix.b = bkgnd;
1179 			else if(pix.a != 255)
1180 			{
1181 				pix.r = ((pix.r - bkgnd) * pix.a >> 15) + bkgnd;
1182 				pix.g = ((pix.g - bkgnd) * pix.a >> 15) + bkgnd;
1183 				pix.b = ((pix.b - bkgnd) * pix.a >> 15) + bkgnd;
1184 			}
1185 
1186 			r = RGBCONV_FIX15_TO_8(pix.r);
1187 			g = RGBCONV_FIX15_TO_8(pix.g);
1188 			b = RGBCONV_FIX15_TO_8(pix.b);
1189 
1190 			(pixbuf->setbuf)(pd, mRGBtoPix2(r, g, b));
1191 		}
1192 	}
1193 }
1194 
1195 /** ヒストグラム取得
1196  *
1197  * (0-256 = 257個) x 4byte。
1198  * RGBA または GRAY のみ。 */
1199 
TileImage_getHistogram(TileImage * p)1200 uint32_t *TileImage_getHistogram(TileImage *p)
1201 {
1202 	uint32_t *buf;
1203 	uint8_t **pptile;
1204 	uint32_t i,j;
1205 	mBool type_rgba;
1206 	RGBAFix15 *ps;
1207 	uint16_t *ps16;
1208 
1209 	buf = (uint32_t *)mMalloc(257 * 4, TRUE);
1210 	if(!buf) return NULL;
1211 
1212 	type_rgba = (p->coltype == TILEIMAGE_COLTYPE_RGBA);
1213 
1214 	//タイルごと
1215 
1216 	pptile = p->ppbuf;
1217 
1218 	for(i = p->tilew * p->tileh; i; i--, pptile++)
1219 	{
1220 		if(!(*pptile)) continue;
1221 
1222 		if(type_rgba)
1223 		{
1224 			//RGBA
1225 
1226 			ps = (RGBAFix15 *)(*pptile);
1227 
1228 			for(j = 64 * 64; j; j--, ps++)
1229 			{
1230 				if(ps->a)
1231 					buf[(ps->r * 77 + ps->g * 150 + ps->b * 29) >> (8 + 15 - 8)]++;
1232 			}
1233 		}
1234 		else
1235 		{
1236 			//GRAY
1237 
1238 			ps16 = (uint16_t *)(*pptile);
1239 
1240 			for(j = 64 * 64; j; j--, ps16 += 2)
1241 			{
1242 				if(ps16[1])
1243 					buf[ps16[0] >> (15 - 8)]++;
1244 			}
1245 		}
1246 	}
1247 
1248 	return buf;
1249 }
1250