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