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