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