|
|
1.1 root 1: //
2: // nono
3: // Copyright (C) 2021 nono project
4: // Licensed under nono-license.txt
5: //
6:
7: //
8: // ビットマップ
9: //
10:
11: #include "bitmap.h"
1.1.1.5 root 12: #include "mainapp.h"
1.1 root 13: #include <cmath>
14:
15: //
16: // ビットマップ (基本クラス)
17: //
18:
19: // コンストラクタ
1.1.1.5 root 20: BitmapBase::BitmapBase(uint depth_, uint width_, uint height_, const void *buf_)
1.1.1.4 root 21: : depth(depth_)
1.1 root 22: {
1.1.1.4 root 23: assert(depth == 1 || (depth % 8) == 0);
24: Create(width_, height_, buf_);
1.1 root 25: }
26:
27: // デストラクタ
28: BitmapBase::~BitmapBase()
29: {
30: }
31:
1.1.1.4 root 32: // サイズを指定してビットマップを作成する。
33: // width_, height_ は 0 が指定される場合もある(初期状態)。
34: // buf_ が NULL ならこっちでメモリを確保。
35: void
1.1.1.5 root 36: BitmapBase::Create(uint width_, uint height_, const void *buf_)
1.1 root 37: {
1.1.1.4 root 38: width = width_;
1.1 root 39: height = height_;
40:
1.1.1.4 root 41: if (depth == 1) {
1.1 root 42: stride = (width + 7) / 8;
43: } else {
1.1.1.4 root 44: stride = width * depth / 8;
45: }
46:
1.1.1.5 root 47: owned_buf.Reset();
1.1.1.4 root 48: if (buf_) {
49: buf = static_cast<uint8 *>(const_cast<void *>(buf_));
50: } else {
51: if (width > 0 && height > 0) {
1.1.1.5 root 52: owned_buf.Reset(stride * height);
1.1.1.4 root 53: }
54: buf = owned_buf.get();
1.1 root 55: }
1.1.1.4 root 56: }
57:
1.1.1.6 ! root 58: // コピーコンストラクタ
! 59: BitmapBase::BitmapBase(const BitmapBase& src)
! 60: {
! 61: width = src.width;
! 62: height = src.height;
! 63: stride = src.stride;
! 64: depth = src.depth;
! 65:
! 66: owned_buf = src.owned_buf;
! 67: // src.buf は src.owned_buf かクラス外のどこか (か NULL) を指している。
! 68: if (src.buf == src.owned_buf.get()) {
! 69: buf = owned_buf.get();
! 70: } else {
! 71: buf = src.buf;
! 72: }
! 73: }
! 74:
! 75: // コピー代入演算子
! 76: BitmapBase&
! 77: BitmapBase::operator=(const BitmapBase& src)
! 78: {
! 79: owned_buf.Reset();
! 80:
! 81: width = src.width;
! 82: height = src.height;
! 83: stride = src.stride;
! 84: depth = src.depth;
! 85:
! 86: owned_buf = src.owned_buf;
! 87: // src.buf は src.owned_buf かクラス外のどこか (か NULL) を指している。
! 88: if (src.buf == src.owned_buf.get()) {
! 89: buf = owned_buf.get();
! 90: } else {
! 91: buf = src.buf;
! 92: }
! 93:
! 94: return *this;
! 95: }
! 96:
1.1.1.4 root 97: // 全域をコピーしてくる。
98: void
99: BitmapBase::CopyFrom(const BitmapBase *src)
100: {
101: assert(src);
102: assert(stride == src->stride);
103: assert(height == src->height);
1.1.1.3 root 104:
1.1.1.4 root 105: memcpy(buf, src->buf, stride * height);
1.1 root 106: }
107:
108:
109: //
110: // 1bpp ビットマップ
111: //
112:
113: // コンストラクタ
114: BitmapI1::BitmapI1()
1.1.1.4 root 115: : BitmapI1(0, 0) // 移譲
1.1 root 116: {
117: }
118:
119: // コンストラクタ
1.1.1.5 root 120: BitmapI1::BitmapI1(uint width_, uint height_)
1.1.1.4 root 121: : BitmapI1(NULL, width_, height_) // 移譲
1.1 root 122: {
123: }
124:
125: // コンストラクタ
1.1.1.5 root 126: BitmapI1::BitmapI1(const void *buf_, uint width_, uint height_)
1.1.1.4 root 127: : inherited(1, width_, height_, buf_)
1.1 root 128: {
129: }
130:
131: // デストラクタ
132: BitmapI1::~BitmapI1()
133: {
134: }
135:
1.1.1.4 root 136: // (x, y) のアドレスを返す関数だが、I1 ではサポートしていない。
137: uint8 *
138: BitmapI1::GetPtr(int x, int y) const
1.1 root 139: {
1.1.1.4 root 140: assertmsg(false, "GetPtr() not work for BitmapI1");
141: return NULL;
1.1 root 142: }
143:
1.1.1.6 ! root 144: // 1ラスタを読み込む/書き出すマクロ。副作用もりもり。
! 145: #define Load(bits, src) do { \
! 146: bits = 0; \
! 147: for (int x = 0; x < stride; x++) { \
! 148: bits <<= 8; \
! 149: bits |= *src++; \
! 150: } \
! 151: } while (0)
! 152: #define Store(bits, dst) do { \
! 153: for (int x = stride - 1; x >= 0; x--) { \
! 154: *dst++ = (bits >> (x * 8)) & 0xff; \
! 155: } \
! 156: } while (0)
! 157:
! 158: // このビットマップ(フォント)をボールドにした新しいビットマップを返す。
! 159: BitmapI1
! 160: BitmapI1::ConvertToBold() const
! 161: {
! 162: assert(stride <= 8);
! 163:
! 164: BitmapI1 dst(width, height);
! 165: const uint8 *s = buf;
! 166: uint8 *d = dst.buf;
! 167: for (int y = 0; y < height; y++) {
! 168: uint64 bits;
! 169: Load(bits, s);
! 170: bits |= bits >> 1;
! 171: Store(bits, d);
! 172: }
! 173: return dst;
! 174: }
! 175:
! 176: // このビットマップ(フォント)をイタリックにした新しいビットマップを返す。
! 177: BitmapI1
! 178: BitmapI1::ConvertToItalic() const
! 179: {
! 180: assert(stride <= 7);
! 181:
! 182: BitmapI1 dst(width, height);
! 183: int half = height / 2;
! 184: const uint8 *s = buf;
! 185: uint8 *d = dst.buf;
! 186: int y;
! 187:
! 188: // 上段は、右端が sticky な右シフト。
! 189: for (y = 0; y <= half; y++) {
! 190: uint64 bits;
! 191: Load(bits, s);
! 192: bits = (bits >> 1) | (bits & 1);
! 193: Store(bits, d);
! 194: }
! 195:
! 196: // 下段は、シフトしないのでコピー。
! 197: memcpy(d, s, stride * (height - y));
! 198:
! 199: return dst;
! 200: }
! 201:
! 202: #undef Load
! 203: #undef Store
! 204:
1.1 root 205:
206: //
207: // 8bpp ビットマップ
208: //
209:
210: // コンストラクタ
211: BitmapI8::BitmapI8()
1.1.1.4 root 212: : BitmapI8(0, 0) // 移譲
1.1 root 213: {
214: }
215:
216: // コンストラクタ
1.1.1.5 root 217: BitmapI8::BitmapI8(uint width_, uint height_)
1.1.1.4 root 218: : BitmapI8(NULL, width_, height_) // 移譲
1.1 root 219: {
220: }
221:
222: // コンストラクタ
1.1.1.5 root 223: BitmapI8::BitmapI8(const void *buf_, uint width_, uint height_)
1.1.1.4 root 224: : inherited(8, width_, height_, buf_)
1.1 root 225: {
226: }
227:
228: // デストラクタ
229: BitmapI8::~BitmapI8()
230: {
231: }
232:
233:
234: //
235: // 24bpp ビットマップ
236: //
237:
238: // コンストラクタ
239: BitmapRGB::BitmapRGB()
1.1.1.4 root 240: : BitmapRGB(0, 0) // 移譲
1.1 root 241: {
242: }
243:
244: // コンストラクタ
1.1.1.5 root 245: BitmapRGB::BitmapRGB(uint width_, uint height_)
1.1.1.4 root 246: : BitmapRGB(NULL, width_, height_) // 移譲
1.1 root 247: {
248: }
249:
250: // コンストラクタ
1.1.1.5 root 251: BitmapRGB::BitmapRGB(const void *buf_, uint width_, uint height_)
1.1.1.4 root 252: : inherited(24, width_, height_, buf_)
1.1 root 253: {
254: }
255:
256: // デストラクタ
257: BitmapRGB::~BitmapRGB()
258: {
259: }
260:
1.1.1.5 root 261:
262: //
263: // 32bpp (RGBX) ビットマップ
264: //
265:
266: // コンストラクタ
267: BitmapRGBX::BitmapRGBX()
268: : BitmapRGBX(0, 0) // 移譲
269: {
270: }
271:
272: // コンストラクタ
273: BitmapRGBX::BitmapRGBX(uint width_, uint height_)
274: : BitmapRGBX(NULL, width_, height_) // 移譲
275: {
276: }
277:
278: // コンストラクタ
279: BitmapRGBX::BitmapRGBX(const void *buf_, uint width_, uint height_)
280: : inherited(32, width_, height_, buf_)
281: {
282: #if defined(HAVE_AVX2)
283: enable_avx2 = gMainApp.enable_avx2;
284: #endif
285: }
286:
287: // デストラクタ
288: BitmapRGBX::~BitmapRGBX()
289: {
290: }
291:
292: // (dx, dy) にビットマップ(I1) src を描画する。
1.1 root 293: // 描画範囲をはみ出さないこと。
294: void
1.1.1.5 root 295: BitmapRGBX::DrawBitmapI1(int dx, int dy, const BitmapI1& src,
296: const Color *palette)
1.1 root 297: {
298: assert(buf);
299:
300: const uint8 *srcbuf = src.GetBuf();
301:
302: uint8 data = 0;
1.1.1.5 root 303: for (uint y = 0; y < src.GetHeight(); y++) {
304: uint32 *d = (uint32 *)GetPtr(dx, dy + y);
305: for (uint x = 0; x < src.GetWidth(); x++) {
1.1 root 306: if (__predict_false(x % 8 == 0)) {
307: data = *srcbuf++;
308: }
309: int cc;
310: if ((int8)data < 0) {
311: cc = 1;
312: } else {
313: cc = 0;
314: }
315: data <<= 1;
316:
1.1.1.5 root 317: *d++ = palette[cc].u32;
1.1 root 318: }
319: }
320: }
321:
322: // (dx, dy) にビットマップ src を scale 倍にして描画する。
323: // 描画範囲をはみ出さないこと。
324: void
1.1.1.5 root 325: BitmapRGBX::DrawBitmapI1Scale(int dx, int dy, const BitmapI1& src,
326: const Color *palette, int scale)
1.1 root 327: {
328: assert(buf);
329:
330: const uint8 *srcbuf = src.GetBuf();
331: uint8 data = 0;
1.1.1.5 root 332: uint dx0 = dx;
1.1 root 333:
1.1.1.5 root 334: for (uint y = 0; y < src.GetHeight(); y++) {
1.1 root 335: dx = dx0;
1.1.1.5 root 336: for (uint x = 0; x < src.GetWidth(); x++) {
1.1 root 337: if (__predict_false(x % 8 == 0)) {
338: data = *srcbuf++;
339: }
340: int cc;
341: if ((int8)data < 0) {
342: cc = 1;
343: } else {
344: cc = 0;
345: }
346: data <<= 1;
347:
348: FillRect(palette[cc], dx, dy, scale, scale);
349: dx += scale;
350: }
351: dy += scale;
352: }
353: }
354:
1.1.1.5 root 355: // BitmapI8 内の s8 から BitmapRGBX 内の d32 に width ピクセルをコピー (C++ 版)
356: // width は双方の画像をはみ出さないこと。
357: void
358: BitmapRGBX::CopyLineI8_gen(uint32 *d32, const uint8 *s8, uint width,
359: const Color *palette)
360: {
361: uint x = 0;
362:
363: if (__predict_true((((uintptr_t)s8) & 3) == 0)) {
364: // 4ピクセルずつ処理する
365: uint w1 = width & ~3;
366: for (; x < w1; x += 4) {
367: uint32 cc4 = *(const uint32 *)s8;
368: s8 += 4;
369:
370: // 4ピクセルをそれぞれ Color に変換
371: #if BYTE_ORDER == LITTLE_ENDIAN
372: // cc4 = $I3I2I1I0
373: Color c0 = palette[ cc4 & 0xff];
374: Color c1 = palette[(cc4 >> 8) & 0xff];
375: Color c2 = palette[(cc4 >> 16) & 0xff];
376: Color c3 = palette[ cc4 >> 24 ];
377: #else
378: // cc4 = $I0I1I2I3
379: Color c0 = palette[ cc4 >> 24 ];
380: Color c1 = palette[(cc4 >> 16) & 0xff];
381: Color c2 = palette[(cc4 >> 8) & 0xff];
382: Color c3 = palette[ cc4 & 0xff];
383: #endif
384:
385: *d32++ = c0.u32;
386: *d32++ = c1.u32;
387: *d32++ = c2.u32;
388: *d32++ = c3.u32;
389: }
390: }
391:
392: for (; x < width; x++) {
393: uint cc = *s8++;
394: Color c = palette[cc];
395: *d32++ = c.u32;
396: }
397: }
398:
399: // (dx, dy) にビットマップ(I8) src の範囲 sr を描画する。
400: // 描画範囲をはみ出さないこと。
401: void
402: BitmapRGBX::DrawBitmapI8(int dx, int dy, const BitmapI8& src,
403: const Color *palette, const Rect& sr)
404: {
405: #if defined(HAVE_AVX2)
406: if (__predict_true(enable_avx2)) {
407: for (uint y = 0; y < sr.h; y++) {
408: uint32 *d = (uint32 *)GetPtr(dx, dy + y);
409: const uint8 *s = src.GetPtr(sr.x, sr.y + y);
410: CopyLineI8_avx2(d, s, sr.w, palette);
411: }
412: } else
413: #endif
414: {
415: for (uint y = 0; y < sr.h; y++) {
416: uint32 *d = (uint32 *)GetPtr(dx, dy + y);
417: const uint8 *s = src.GetPtr(sr.x, sr.y + y);
418: CopyLineI8_gen(d, s, sr.w, palette);
419: }
420: }
421: }
422:
423: // ビットマップ(I8) src の全域を指定のラスターのみ描画する。
424: void
425: BitmapRGBX::DrawBitmapI8Raster(const BitmapI8& src, const Color *palette,
426: const uint8 *update_raster)
427: {
428: uint width = src.GetWidth();
429: uint height = src.GetHeight();
430:
431: #if defined(HAVE_AVX2)
432: if (__predict_true(enable_avx2)) {
433: for (uint y = 0; y < height; y++) {
434: if (update_raster[y] == 0) {
435: continue;
436: }
437: uint32 *d = (uint32 *)GetRowPtr(y);
438: const uint8 *s = src.GetRowPtr(y);
439: CopyLineI8_avx2(d, s, width, palette);
440: }
441: } else
442: #endif
443: {
444: for (uint y = 0; y < height; y++) {
445: if (update_raster[y] == 0) {
446: continue;
447: }
448: uint32 *d = (uint32 *)GetRowPtr(y);
449: const uint8 *s = src.GetRowPtr(y);
450: CopyLineI8_gen(d, s, width, palette);
451: }
452: }
453: }
454:
1.1.1.2 root 455: // 分数で表現可能な拡大縮小描画。
456: // dr にビットマップ src の (sxN / sxD, syN / syD) からを
457: // dst の 1 ピクセルに対して (sxS / sxD, syS / syD) ずつ動かした位置を
458: // 読み出し位置として描画する。
459: // 描画範囲をはみ出さないこと。
460: void
1.1.1.5 root 461: BitmapRGBX::DrawBitmapI8Scale(const Rect& dr, const BitmapI8& src,
462: const Color *palette,
1.1.1.2 root 463: int sxN, int sxD, int sxS, int syN, int syD, int syS)
464: {
465: assert(buf);
466: assert(sxD >= 1);
467: assert(syD >= 1);
468: assert(sxS != 0);
469: assert(syS != 0);
470:
471: int sxI = sxN / sxD;
472: int syI = syN / syD;
473:
474: sxN %= sxD;
475: syN %= syD;
476:
477: int sxI0 = sxI;
478: int sxN0 = sxN;
479:
480: int sx;
481: int sy = syI - 1;
482:
1.1.1.5 root 483: for (uint y = 0; y < dr.h; y++) {
484: uint32 *d = (uint32 *)GetPtr(dr.x, dr.y + y);
1.1.1.2 root 485:
486: if (sy != syI) {
487: sy = syI;
488:
489: sx = sxI0 - 1;
490: sxI = sxI0;
491: sxN = sxN0;
492:
493: uint8 cc = 0;
1.1.1.5 root 494: for (uint x = 0; x < dr.w; x++) {
1.1.1.2 root 495: if (sx != sxI) {
496: sx = sxI;
497: const uint8 *s = src.GetPtr(sx, sy);
498: cc = *s;
499: }
1.1.1.5 root 500: *d++ = palette[cc].u32;
1.1.1.2 root 501:
502: sxN += sxS;
503: if (sxN >= sxD) {
504: sxI += sxN / sxD;
505: sxN %= sxD;
506: }
507: }
508: } else {
509: // 前のラスタの中からコピーすればよい
1.1.1.5 root 510: memcpy(d, (uint8 *)d - stride, dr.w * 4);
1.1.1.2 root 511: }
512:
513: syN += syS;
514: if (syN >= syD) {
515: syI += syN / syD;
516: syN %= syD;
517: }
518: }
519: }
520:
1.1.1.5 root 521: // (dx, dy) にビットマップ(RGBX) src を描画する。
522: // 描画範囲をはみ出さないこと。
523: void
524: BitmapRGBX::DrawBitmap(int dx, int dy, const BitmapRGBX& src)
525: {
526: assert(buf);
527:
528: const uint32 *s = (const uint32 *)src.GetBuf();
529:
530: for (uint y = 0; y < src.GetHeight(); y++) {
531: uint32 *d = (uint32 *)GetPtr(dx, dy + y);
532: for (uint x = 0; x < src.GetWidth(); x++) {
533: *d++ = *s++;
534: }
535: }
536: }
537:
538: // src 全域が dr のサイズになるよう拡大縮小して描画。
539: // 拡大、縮小、等倍すべて可能。
540: void
541: BitmapRGBX::DrawBitmapStretch(const Rect& dr, const BitmapRGBX& src)
542: {
543: uint srcw = src.GetWidth();
544: uint srch = src.GetHeight();
545:
546: if (dr.w < srcw && dr.h < srch) {
547: uint w1 = srcw - dr.w;
548: uint h1 = srch - dr.h;
549: uint wn = dr.w / w1;
550: uint wr = dr.w % w1;
551: uint hn = dr.h / h1;
552: uint hr = dr.h % h1;
553: if (wr == 0 && hr == 0 && wn == hn && wn < 256) {
554: // (N-1)/N 倍に縮小。
555: DrawBitmapNtoNm1(dr, src, wn + 1);
556: return;
557: }
558: }
559: if (dr.w > srcw && dr.h > srch) {
560: uint w1 = dr.w - srcw;
561: uint h1 = dr.h - srch;
562: uint wn = dr.w / w1;
563: uint wr = dr.w % w1;
564: uint hn = dr.h / h1;
565: uint hr = dr.h % h1;
566: if (wr == 0 && hr == 0 && wn == hn && wn < 16) {
567: // N/(N-1) 倍に拡大。
568: DrawBitmapNm1toN(dr, src, wn);
569: return;
570: }
571: }
572: if (__predict_false(dr.w == srcw && dr.h == srch)) {
573: // 等倍。
574: DrawBitmap(dr.x, dr.y, src);
575: return;
576: }
577:
578: // 任意倍率の拡大縮小。
579: DrawBitmapMean(dr, src);
580: }
581:
582: // src 全域を (N-1)/N 倍に縮小描画。
583: // dr.w == src.Width * (N-1)/N
584: // dr.h == src.Height * (N-1)/N
585: // で呼び出すこと。
586: void
587: BitmapRGBX::DrawBitmapNtoNm1(const Rect& dr, const BitmapRGBX& src, uint N)
588: {
589: // 画像を 3/4 倍に縮小する場合 (N=4、N1=3、N2=2)。
590: //
591: // ※ この説明中では二次元座標の x, y を A(y, x) マクロの順に揃えてあり
592: // 数学で通常使う (x, y) の順ではない点に注意。
593: //
594: // dst の (0, 0) は src の (0, 0), (0, 1), (1, 0), (1, 1) の4点から、
595: // dst の (0, 1) は src の (0, 1), (0, 2), (1, 1), (1, 2) の4点から、
596: // dst の (0, 2) は src の (0, 2), (0, 3), (1, 2), (1, 3) の4点から、
597: // :
598: // 適当な割合で合成することになる。
599: // この時どの dst に対しても src が4点なことがポイント。
600: //
601: // 出力 3x3 ピクセルに対する入力の 4x4 ピクセル内部を各 2x2 に小分けに
602: // した計 8x8 の行列を以下のようにすると、この (空白で区切られた) 各 4x4
603: // ピクセル内の 4値の合計はいずれも 9。
604: //
605: // 0 0 0 0 0 0 0 0
606: // 0 9 3 6 6 3 9 0
607: //
608: // 0 3 1 2 2 1 3 0
609: // 0 6 2 4 4 2 6 0
610: //
611: // 0 6 2 4 4 2 6 0
612: // 0 3 1 2 2 1 3 0
613: //
614: // 0 9 3 6 6 3 9 0
615: // 0 0 0 0 0 0 0 0
616: //
617: // これを外周の 0 を取り除いた 6x6 行列に読み替えると、
618: // この (空白で区切られた) 各 3x3 ピクセル内の4値の合計はいずれも 16 に
619: // なっており、元の 4x4 ピクセルの成分を均等に分配できる。
620: //
621: // 9 3 6 6 3 9
622: // 3 1 2 2 1 3
623: //
624: // 6 2 4 4 2 6
625: // 6 2 4 4 2 6
626: //
627: // 3 1 2 2 1 3
628: // 9 3 6 6 3 9
629: //
630: //
631: // この計 6x6 の行列は 3x3 (N1 x N1) 行列の A[] から、オフセットを
632: // 移動させながら求めることが出来る。
633: //
634: // | 1 2 3 |
635: // A = | 2 4 6 | / 16
636: // | 3 6 9 |
637: //
638: // 具体的には dst(0, 0), dst(0, 1), dst(0, 2) の変換行列はそれぞれ
639: // 次のようになる。
640: //
641: // | 9 3 | | 6 6 | | 3 9 |
642: // a_(0,0) = | 3 1 |/16, a_(0,1) = | 2 2 |/16, a_(0,2) = | 1 3 |/16
643: //
644: // よって例えば dst(0, 2) の点の明るさは a_(0,2) を用いて
645: //
646: // dst(0, 2) = src(0, 2) * 3/16 + src(0, 3) * 9/16
647: // + src(1, 2) * 1/16 + src(1, 3) * 3/16
648: //
649: // で求められる。
650:
651: assertmsg(N >= 2, "N=%u", N);
652: uint N1 = N - 1;
653: uint N2 = N - 2;
654: std::vector<uint> a(N1 * N1);
655: #define A(y, x) a[(y) * N1 + (x)]
656:
657: // 小数部 8bit の固定小数点数で面積比変換行列を計算。
658: for (uint y = 0; y < N1; y++) {
659: for (uint x = 0; x < N1; x++) {
660: A(y, x) = (x + 1) * (y + 1) * 256 / (N * N);
661: }
662: }
663:
664: // N to (N-1) 変換なので、dst 側 N-1 ピクセルごとに
665: // src 側を N ピクセル参照すればよく、境界条件を簡略化できる。
666: const uint32 stride32 = src.GetStride() / sizeof(uint32);
667: for (uint sy = 0, dy = 0; dy < dr.h; sy += N, dy += N1) {
668: for (uint sx = 0, dx = 0; dx < dr.w; sx += N, dx += N1) {
669: const uint32 *s0 = (const uint32 *)src.GetPtr(sx, sy);
670: for (uint ty = 0; ty < N1; ty++) {
671: const uint32 *s1 = s0 + stride32;
672: uint32 *d = (uint32 *)GetPtr(dx, dy + ty);
673: for (uint tx = 0; tx < N1; tx++) {
674: uint a00 = A(N2 - ty, N2 - tx);
675: uint a01 = A(N2 - ty, tx);
676: uint a10 = A( ty, N2 - tx);
677: uint a11 = A( ty, tx);
678:
679: Color c00(s0[tx + 0]);
680: Color c01(s0[tx + 1]);
681: Color c10(s1[tx + 0]);
682: Color c11(s1[tx + 1]);
683:
684: uint r, g, b;
685: r = a00 * c00.r
686: + a01 * c01.r
687: + a10 * c10.r
688: + a11 * c11.r;
689: r >>= 8;
690:
691: g = a00 * c00.g
692: + a01 * c01.g
693: + a10 * c10.g
694: + a11 * c11.g;
695: g >>= 8;
696:
697: b = a00 * c00.b
698: + a01 * c01.b
699: + a10 * c10.b
700: + a11 * c11.b;
701: b >>= 8;
702:
703: Color c(r, g, b);
704: d[tx] = c.u32;
705: }
706: s0 += stride32;
707: }
708: }
709: }
710: #undef A
711: }
712:
713: // src 全域を N/(N-1) 倍に拡大描画。
714: // dr.w == src.Width * N/(N-1)
715: // dr.h == src.Height * N/(N-1)
716: // で呼び出すこと。
717: void
718: BitmapRGBX::DrawBitmapNm1toN(const Rect& dr, const BitmapRGBX& src, uint N)
719: {
720: assertmsg(N >= 2, "N=%u", N);
721: uint N1 = N - 1;
722: std::vector<uint> a(N * N);
723: #define A(y, x) a[(y) * N + (x)]
724:
725: // 小数部 8bit の固定小数点数で面積比変換行列を計算。
726: for (uint y = 0; y < N; y++) {
727: for (uint x = 0; x < N; x++) {
728: A(y, x) = x * y * 256 / (N1 * N1);
729: }
730: }
731:
732: const uint sstride32 = src.GetStride() / sizeof(uint32);
733: const uint dstride32 = GetStride() / sizeof(uint32);
734: // N to (N+1) 変換なので、
735: for (uint sy = 0, dy = 0; dy < dr.h; sy += N1, dy += N) {
736: for (uint sx = 0, dx = 0; dx < dr.w; sx += N1, dx += N) {
737: const uint32 *s0i = (const uint32 *)src.GetPtr(sx, sy);
738: uint32 *d = (uint32 *)GetPtr(dx, dy);
739: for (uint ty = 0; ty < N; ty++) {
740: const uint32 *s1 = (const uint32 *)(s0i + ty * sstride32);
741: const uint32 *s0 = (const uint32 *)(s1 - sstride32);
742: for (uint tx = 0; tx < N; tx++, s0++, s1++) {
743: uint a00 = A( ty, tx);
744: uint a01 = A( ty, N1 - tx);
745: uint a10 = A(N1 - ty, tx);
746: uint a11 = A(N1 - ty, N1 - tx);
747:
748: uint32 v00 = a00 ? s0[-1] : 0;
749: uint32 v01 = a01 ? s0[ 0] : 0;
750: uint32 v10 = a10 ? s1[-1] : 0;
751: uint32 v11 = a11 ? s1[ 0] : 0;
752:
753: Color c00(v00);
754: Color c01(v01);
755: Color c10(v10);
756: Color c11(v11);
757:
758: uint r, g, b;
759:
760: r = a00 * c00.r
761: + a01 * c01.r
762: + a10 * c10.r
763: + a11 * c11.r;
764: r >>= 8;
765:
766: g = a00 * c00.g
767: + a01 * c01.g
768: + a10 * c10.g
769: + a11 * c11.g;
770: g >>= 8;
771:
772: b = a00 * c00.b
773: + a01 * c01.b
774: + a10 * c10.b
775: + a11 * c11.b;
776: b >>= 8;
777:
778: Color c(r, g, b);
779: d[tx] = c.u32;
780: }
781: d += dstride32;
782: }
783: }
784: }
785: #undef A
786: }
787:
788: // src 全域が dr のサイズになるよう面積平均法で拡大縮小して描画。
789: // (等倍も無駄だけど動作はするはず)
790: void
791: BitmapRGBX::DrawBitmapMean(const Rect& dr, const BitmapRGBX& src)
792: {
793: // dst の 1 pixel が src の 何 pixel に相当するか
794: float tx = (float)src.GetWidth() / dr.w;
795: float ty = (float)src.GetHeight() / dr.h;
796:
797: // src 上を動くウィンドウ
798: RectF sr(0, 0, tx, ty);
799:
800: for (uint y = 0; y < dr.h; y++) {
801: uint32 *d = (uint32 *)GetRowPtr(y);
802: sr.x = 0;
803: for (uint x = 0; x < dr.w; x++) {
804: Color c = src.Mean(sr);
805: *d++ = c.u32;
806: sr.x += tx;
807: }
808: sr.y += ty;
809: }
810: }
811:
1.1 root 812: // sr 範囲の色の平均を返す
813: Color
1.1.1.5 root 814: BitmapRGBX::Mean(const RectF& sr) const
1.1 root 815: {
1.1.1.5 root 816: uint x1 = std::floor(sr.x);
817: uint y1 = std::floor(sr.y);
818: uint x2 = std::ceil(sr.x + sr.w);
819: uint y2 = std::ceil(sr.y + sr.h);
820: if (__predict_false(x2 > GetWidth())) {
1.1 root 821: x2 = GetWidth();
822: }
1.1.1.5 root 823: if (__predict_false(y2 > GetHeight())) {
1.1 root 824: y2 = GetHeight();
825: }
826:
1.1.1.5 root 827: float sum_r = 0;
828: float sum_g = 0;
829: float sum_b = 0;
830:
1.1 root 831: // サブピクセルの辺の長さ
1.1.1.5 root 832: float rx, ry;
833: float area = 0;
834: for (uint y = y1; y < y2; y++) {
1.1 root 835: if (y == y1) {
836: ry = 1 - (sr.y - y1);
837: } else if (y == y2 - 1) {
838: ry = 1 - (y2 - (sr.y + sr.h));
839: } else {
840: ry = 1;
841: }
842:
1.1.1.5 root 843: const uint32 *p = (const uint32 *)GetPtr(x1, y);
844: for (uint x = x1; x < x2; x++) {
845: Color c(*p++);
846:
1.1 root 847: if (x == x1) {
848: rx = 1 - (sr.x - x1);
1.1.1.5 root 849: } else if (x == x2 - 1) {
1.1 root 850: rx = 1 - (x2 - (sr.x + sr.w));
851: } else {
852: rx = 1;
853: }
854:
855: // 面積比をかけて合成
1.1.1.5 root 856: sum_r += c.r * rx * ry;
857: sum_g += c.g * rx * ry;
858: sum_b += c.b * rx * ry;
859: area += rx * ry;
1.1 root 860: }
861: }
862:
863: // 平均にする
1.1.1.5 root 864: sum_r /= area;
865: sum_g /= area;
866: sum_b /= area;
1.1 root 867:
1.1.1.5 root 868: return Color(sum_r, sum_g, sum_b);
1.1 root 869: }
870:
871: // 直線 (x1, y1) - (x2, y2) を描画する。終点は開区間。
872: // 描画範囲をはみ出さないこと。
873: void
1.1.1.5 root 874: BitmapRGBX::DrawLine(Color c, int x1, int y1, int x2, int y2)
1.1 root 875: {
876: if (y1 == y2) {
877: DrawLineH(c, x1, y1, x2);
878: } else if (x1 == x2) {
879: DrawLineV(c, x1, y1, y2);
880: } else {
881: assert(false);
882: }
883: }
884:
885: // 水平の直線 (x1, y1) - (x2, y1) を描画する。終点は開区間。
886: // 描画範囲をはみ出さないこと。
887: void
1.1.1.5 root 888: BitmapRGBX::DrawLineH(Color c, int x1, int y1, int x2)
1.1 root 889: {
890: assert(buf);
891:
892: if (__predict_false(x1 > x2)) {
893: std::swap(x1, x2);
894: x1++;
895: x2++;
896: }
897:
1.1.1.5 root 898: uint32 *d = (uint32 *)GetPtr(x1, y1);
899: for (int x = x1; x < x2; x++) {
900: *d++ = c.u32;
1.1 root 901: }
902: }
903:
904: // 垂直の直線 (x1, y1) - (x1, y2) を描画する。終点は開区間。
905: // 描画範囲をはみ出さないこと。
906: void
1.1.1.5 root 907: BitmapRGBX::DrawLineV(Color c, int x1, int y1, int y2)
1.1 root 908: {
909: assert(buf);
910:
911: if (__predict_false(y1 > y2)) {
912: std::swap(y1, y2);
913: y1++;
914: y2++;
915: }
916:
1.1.1.5 root 917: for (int y = y1; y < y2; y++) {
918: uint32 *d = (uint32 *)GetPtr(x1, y);
919: *d = c.u32;
1.1 root 920: }
921: }
922:
923: // 矩形 rect を色 c で塗りつぶす。
924: // 描画範囲をはみ出さないこと。
925: void
1.1.1.5 root 926: BitmapRGBX::FillRect(Color c, const Rect& rect)
1.1 root 927: {
928: assert(buf);
929:
1.1.1.5 root 930: DrawLineH(c, rect.x, rect.y, rect.x + rect.w);
931: CopyFromTop(rect);
932: }
1.1 root 933:
1.1.1.5 root 934: // rect の一番上のラスターを rect の残りのラスターにコピーする。
935: void
936: BitmapRGBX::CopyFromTop(const Rect& rect)
937: {
938: uint8 *s = GetPtr(rect.x, rect.y);
1.1 root 939: uint8 *d = s + stride;
1.1.1.5 root 940: const uint len = rect.w * 4;
1.1 root 941:
1.1.1.5 root 942: for (uint y = rect.y + 1; y < rect.y + rect.h; y++) {
1.1 root 943: memcpy(d, s, len);
944: d += stride;
945: }
946: }
947:
948: // 矩形 rect の辺を色 c で描画する。
949: // 描画範囲をはみ出さないこと。
950: void
1.1.1.5 root 951: BitmapRGBX::DrawRect(Color c, const Rect& rect)
1.1 root 952: {
953: assert(buf);
954:
955: int l = rect.x;
956: int t = rect.y;
957: int r = rect.GetRight();
958: int b = rect.GetBottom();
959:
960: DrawLineH(c, l, t, r); // 上辺→
961: DrawLineV(c, r, t, b); // 右辺↓
962: DrawLineH(c, r, b, l); // 下辺←
963: DrawLineV(c, l, b, t); // 左辺↑
964: }
1.1.1.4 root 965:
1.1.1.5 root 966: // 全域を RGB に変換。
967: void
968: BitmapRGBX::ConvertToRGB(BitmapRGB& dst) const
1.1.1.4 root 969: {
1.1.1.5 root 970: assertmsg(dst.GetWidth() == GetWidth(),
971: "dst.width=%u, src.width=%u", dst.GetWidth(), GetWidth());
972: assertmsg(dst.GetHeight() == GetHeight(),
973: "dst.height=%u, src.height=%u", dst.GetWidth(), GetWidth());
974:
975: #if defined(HAVE_AVX2)
976: if (__predict_true(enable_avx2)) {
977: ConvertToRGB_avx2(dst);
978: } else
979: #endif
980: {
981: ConvertToRGB_gen(dst);
982: }
983: }
984:
985: // RGBX から RGB への変換。(C++ 版)
986: void
987: BitmapRGBX::ConvertToRGB_gen(BitmapRGB& dst) const
988: {
989: const BitmapRGBX& src = *this;
990:
991: // この変換は一次元配列とみなしても行える。
992: // モニタ等のパネルでも呼ばれるので何ピクセルで割り切れるかの前提は不可。
993: uint total = GetWidth() * GetHeight();
994: uint packed = total & ~3;
995:
996: const uint32 *s32 = (const uint32 *)src.GetRowPtr(0);
997: const uint32 *s32total = s32 + total;
998: const uint32 *s32packed = s32 + packed;
999:
1000: uint32 *d32 = (uint32 *)dst.GetRowPtr(0);
1001: for (; s32 < s32packed; ) {
1002: // 4ピクセルずつ処理する
1003: uint32 c0 = *s32++;
1004: uint32 c1 = *s32++;
1005: uint32 c2 = *s32++;
1006: uint32 c3 = *s32++;
1007:
1008: #if BYTE_ORDER == LITTLE_ENDIAN
1009: // c0 = $X0B0G0R0
1010: // c1 = $X1B1G1R1
1011: // c2 = $X2B2G2R2
1012: // c3 = $X3B3G3R3
1013: //
1014: // d[0] = $00B0G0R0 | $R1000000 = $R1B0G0R0
1015: // d[1] = $0000B1G1 | $G2R20000 = $G2R2B1G1
1016: // d[2] = $000000B2 | $B3G3R300 = $B3G3R3B2
1017:
1018: *d32++ = (c0 ) | (c1 << 24);
1019: *d32++ = (c1 >> 8) | (c2 << 16);
1020: *d32++ = (c2 >> 16) | (c3 << 8);
1021: #else
1022: // c0 = $R0G0B0X0
1023: // c1 = $R1G1B1X1
1024: // c2 = $R2G2B2X2
1025: // c3 = $R3G3B3X3
1026: //
1027: // d[0] = $R0G0B000 | $000000R1 = $R0G0B0R1
1028: // d[1] = $G1B10000 | $0000R2G2 = $G1B1R2G2
1029: // d[2] = $B2000000 | $00R3G3B3 = $B2R3G3B3
1030:
1031: *d32++ = (c0 ) | (c1 >> 24);
1032: *d32++ = (c1 << 8) | (c2 >> 16);
1033: *d32++ = (c2 << 16) | (c3 >> 8);
1034: #endif
1035: }
1036:
1037: uint8 *d8 = (uint8 *)d32;
1038: for (; s32 < s32total; ) {
1039: // 残りを1ピクセルずつ処理する
1040: Color col(*s32++);
1041: *d8++ = col.r;
1042: *d8++ = col.g;
1043: *d8++ = col.b;
1044: }
1.1.1.4 root 1045: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.