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