Annotation of nono/lib/bitmap.cpp, revision 1.1.1.7

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.7 ! root      521: // (dx, dy) にビットマップ(RGBX) src の範囲 sr を描画する。
1.1.1.5   root      522: // 描画範囲をはみ出さないこと。
                    523: void
1.1.1.7 ! root      524: BitmapRGBX::DrawBitmap(int dx, int dy, const BitmapRGBX& src, const Rect& sr)
1.1.1.5   root      525: {
                    526:        assert(buf);
                    527: 
1.1.1.7 ! root      528:        for (uint y = 0; y < sr.h; y++) {
1.1.1.5   root      529:                uint32 *d = (uint32 *)GetPtr(dx, dy + y);
1.1.1.7 ! root      530:                const uint32 *s = (const uint32 *)src.GetPtr(sr.x, sr.y + y);
        !           531:                for (uint x = 0; x < sr.w; x++) {
1.1.1.5   root      532:                        *d++ = *s++;
                    533:                }
                    534:        }
                    535: }
                    536: 
                    537: // src 全域が dr のサイズになるよう拡大縮小して描画。
                    538: // 拡大、縮小、等倍すべて可能。
                    539: void
                    540: BitmapRGBX::DrawBitmapStretch(const Rect& dr, const BitmapRGBX& src)
                    541: {
                    542:        uint srcw = src.GetWidth();
                    543:        uint srch = src.GetHeight();
                    544: 
                    545:        if (dr.w < srcw && dr.h < srch) {
                    546:                uint w1 = srcw - dr.w;
                    547:                uint h1 = srch - dr.h;
                    548:                uint wn = dr.w / w1;
                    549:                uint wr = dr.w % w1;
                    550:                uint hn = dr.h / h1;
                    551:                uint hr = dr.h % h1;
                    552:                if (wr == 0 && hr == 0 && wn == hn && wn < 256) {
                    553:                        // (N-1)/N 倍に縮小。
                    554:                        DrawBitmapNtoNm1(dr, src, wn + 1);
                    555:                        return;
                    556:                }
                    557:        }
                    558:        if (dr.w > srcw && dr.h > srch) {
                    559:                uint w1 = dr.w - srcw;
                    560:                uint h1 = dr.h - srch;
                    561:                uint wn = dr.w / w1;
                    562:                uint wr = dr.w % w1;
                    563:                uint hn = dr.h / h1;
                    564:                uint hr = dr.h % h1;
                    565:                if (wr == 0 && hr == 0 && wn == hn && wn < 16) {
                    566:                        // N/(N-1) 倍に拡大。
                    567:                        DrawBitmapNm1toN(dr, src, wn);
                    568:                        return;
                    569:                }
                    570:        }
                    571:        if (__predict_false(dr.w == srcw && dr.h == srch)) {
                    572:                // 等倍。
                    573:                DrawBitmap(dr.x, dr.y, src);
                    574:                return;
                    575:        }
                    576: 
                    577:        // 任意倍率の拡大縮小。
                    578:        DrawBitmapMean(dr, src);
                    579: }
                    580: 
                    581: // src 全域を (N-1)/N 倍に縮小描画。
                    582: // dr.w == src.Width * (N-1)/N
                    583: // dr.h == src.Height * (N-1)/N
                    584: // で呼び出すこと。
                    585: void
                    586: BitmapRGBX::DrawBitmapNtoNm1(const Rect& dr, const BitmapRGBX& src, uint N)
                    587: {
                    588:        // 画像を 3/4 倍に縮小する場合 (N=4、N1=3、N2=2)。
                    589:        //
                    590:        // ※ この説明中では二次元座標の x, y を A(y, x) マクロの順に揃えてあり
                    591:        //    数学で通常使う (x, y) の順ではない点に注意。
                    592:        //
                    593:        // dst の (0, 0) は src の (0, 0), (0, 1), (1, 0), (1, 1) の4点から、
                    594:        // dst の (0, 1) は src の (0, 1), (0, 2), (1, 1), (1, 2) の4点から、
                    595:        // dst の (0, 2) は src の (0, 2), (0, 3), (1, 2), (1, 3) の4点から、
                    596:        // :
                    597:        // 適当な割合で合成することになる。
                    598:        // この時どの dst に対しても src が4点なことがポイント。
                    599:        //
                    600:        // 出力 3x3 ピクセルに対する入力の 4x4 ピクセル内部を各 2x2 に小分けに
                    601:        // した計 8x8 の行列を以下のようにすると、この (空白で区切られた) 各 4x4
                    602:        // ピクセル内の 4値の合計はいずれも 9。
                    603:        //
                    604:        //  0 0  0 0  0 0  0 0
                    605:        //  0 9  3 6  6 3  9 0
                    606:        //
                    607:        //  0 3  1 2  2 1  3 0
                    608:        //  0 6  2 4  4 2  6 0
                    609:        //
                    610:        //  0 6  2 4  4 2  6 0
                    611:        //  0 3  1 2  2 1  3 0
                    612:        //
                    613:        //  0 9  3 6  6 3  9 0
                    614:        //  0 0  0 0  0 0  0 0
                    615:        //
                    616:        // これを外周の 0 を取り除いた 6x6 行列に読み替えると、
                    617:        // この (空白で区切られた) 各 3x3 ピクセル内の4値の合計はいずれも 16 に
                    618:        // なっており、元の 4x4 ピクセルの成分を均等に分配できる。
                    619:        //
                    620:        //  9 3  6 6  3 9
                    621:        //  3 1  2 2  1 3
                    622:        //
                    623:        //  6 2  4 4  2 6
                    624:        //  6 2  4 4  2 6
                    625:        //
                    626:        //  3 1  2 2  1 3
                    627:        //  9 3  6 6  3 9
                    628:        //
                    629:        //
                    630:        // この計 6x6 の行列は 3x3 (N1 x N1) 行列の A[] から、オフセットを
                    631:        // 移動させながら求めることが出来る。
                    632:        //
                    633:        //     | 1  2  3 |
                    634:        // A = | 2  4  6 | / 16
                    635:        //     | 3  6  9 |
                    636:        //
                    637:        // 具体的には dst(0, 0), dst(0, 1), dst(0, 2) の変換行列はそれぞれ
                    638:        // 次のようになる。
                    639:        //
                    640:        //           | 9  3 |                | 6  6 |                | 3  9 |
                    641:        // a_(0,0) = | 3  1 |/16,  a_(0,1) = | 2  2 |/16,  a_(0,2) = | 1  3 |/16
                    642:        //
                    643:        // よって例えば dst(0, 2) の点の明るさは a_(0,2) を用いて
                    644:        //
                    645:        //  dst(0, 2) = src(0, 2) * 3/16 + src(0, 3) * 9/16
                    646:        //            + src(1, 2) * 1/16 + src(1, 3) * 3/16
                    647:        //
                    648:        // で求められる。
                    649: 
                    650:        assertmsg(N >= 2, "N=%u", N);
                    651:        uint N1 = N - 1;
                    652:        uint N2 = N - 2;
                    653:        std::vector<uint> a(N1 * N1);
                    654: #define A(y, x) a[(y) * N1 + (x)]
                    655: 
                    656:        // 小数部 8bit の固定小数点数で面積比変換行列を計算。
                    657:        for (uint y = 0; y < N1; y++) {
                    658:                for (uint x = 0; x < N1; x++) {
                    659:                        A(y, x) = (x + 1) * (y + 1) * 256 / (N * N);
                    660:                }
                    661:        }
                    662: 
                    663:        // N to (N-1) 変換なので、dst 側 N-1 ピクセルごとに
                    664:        // src 側を N ピクセル参照すればよく、境界条件を簡略化できる。
                    665:        const uint32 stride32 = src.GetStride() / sizeof(uint32);
                    666:        for (uint sy = 0, dy = 0; dy < dr.h; sy += N, dy += N1) {
                    667:                for (uint sx = 0, dx = 0; dx < dr.w; sx += N, dx += N1) {
                    668:                        const uint32 *s0 = (const uint32 *)src.GetPtr(sx, sy);
                    669:                        for (uint ty = 0; ty < N1; ty++) {
                    670:                                const uint32 *s1 = s0 + stride32;
                    671:                                uint32 *d = (uint32 *)GetPtr(dx, dy + ty);
                    672:                                for (uint tx = 0; tx < N1; tx++) {
                    673:                                        uint a00 = A(N2 - ty, N2 - tx);
                    674:                                        uint a01 = A(N2 - ty,      tx);
                    675:                                        uint a10 = A(     ty, N2 - tx);
                    676:                                        uint a11 = A(     ty,      tx);
                    677: 
                    678:                                        Color c00(s0[tx + 0]);
                    679:                                        Color c01(s0[tx + 1]);
                    680:                                        Color c10(s1[tx + 0]);
                    681:                                        Color c11(s1[tx + 1]);
                    682: 
                    683:                                        uint r, g, b;
                    684:                                        r = a00 * c00.r
                    685:                                          + a01 * c01.r
                    686:                                          + a10 * c10.r
                    687:                                          + a11 * c11.r;
                    688:                                        r >>= 8;
                    689: 
                    690:                                        g = a00 * c00.g
                    691:                                          + a01 * c01.g
                    692:                                          + a10 * c10.g
                    693:                                          + a11 * c11.g;
                    694:                                        g >>= 8;
                    695: 
                    696:                                        b = a00 * c00.b
                    697:                                          + a01 * c01.b
                    698:                                          + a10 * c10.b
                    699:                                          + a11 * c11.b;
                    700:                                        b >>= 8;
                    701: 
                    702:                                        Color c(r, g, b);
                    703:                                        d[tx] = c.u32;
                    704:                                }
                    705:                                s0 += stride32;
                    706:                        }
                    707:                }
                    708:        }
                    709: #undef A
                    710: }
                    711: 
                    712: // src 全域を N/(N-1) 倍に拡大描画。
                    713: // dr.w == src.Width * N/(N-1)
                    714: // dr.h == src.Height * N/(N-1)
                    715: // で呼び出すこと。
                    716: void
                    717: BitmapRGBX::DrawBitmapNm1toN(const Rect& dr, const BitmapRGBX& src, uint N)
                    718: {
                    719:        assertmsg(N >= 2, "N=%u", N);
                    720:        uint N1 = N - 1;
                    721:        std::vector<uint> a(N * N);
                    722: #define A(y, x) a[(y) * N + (x)]
                    723: 
                    724:        // 小数部 8bit の固定小数点数で面積比変換行列を計算。
                    725:        for (uint y = 0; y < N; y++) {
                    726:                for (uint x = 0; x < N; x++) {
                    727:                        A(y, x) = x * y * 256 / (N1 * N1);
                    728:                }
                    729:        }
                    730: 
                    731:        const uint sstride32 = src.GetStride() / sizeof(uint32);
                    732:        const uint dstride32 = GetStride() / sizeof(uint32);
                    733:        // N to (N+1) 変換なので、
                    734:        for (uint sy = 0, dy = 0; dy < dr.h; sy += N1, dy += N) {
                    735:                for (uint sx = 0, dx = 0; dx < dr.w; sx += N1, dx += N) {
                    736:                        const uint32 *s0i = (const uint32 *)src.GetPtr(sx, sy);
                    737:                        uint32 *d = (uint32 *)GetPtr(dx, dy);
                    738:                        for (uint ty = 0; ty < N; ty++) {
                    739:                                const uint32 *s1 = (const uint32 *)(s0i + ty * sstride32);
                    740:                                const uint32 *s0 = (const uint32 *)(s1 - sstride32);
                    741:                                for (uint tx = 0; tx < N; tx++, s0++, s1++) {
                    742:                                        uint a00 = A(     ty,      tx);
                    743:                                        uint a01 = A(     ty, N1 - tx);
                    744:                                        uint a10 = A(N1 - ty,      tx);
                    745:                                        uint a11 = A(N1 - ty, N1 - tx);
                    746: 
                    747:                                        uint32 v00 = a00 ? s0[-1] : 0;
                    748:                                        uint32 v01 = a01 ? s0[ 0] : 0;
                    749:                                        uint32 v10 = a10 ? s1[-1] : 0;
                    750:                                        uint32 v11 = a11 ? s1[ 0] : 0;
                    751: 
                    752:                                        Color c00(v00);
                    753:                                        Color c01(v01);
                    754:                                        Color c10(v10);
                    755:                                        Color c11(v11);
                    756: 
                    757:                                        uint r, g, b;
                    758: 
                    759:                                        r = a00 * c00.r
                    760:                                          + a01 * c01.r
                    761:                                          + a10 * c10.r
                    762:                                          + a11 * c11.r;
                    763:                                        r >>= 8;
                    764: 
                    765:                                        g = a00 * c00.g
                    766:                                          + a01 * c01.g
                    767:                                          + a10 * c10.g
                    768:                                          + a11 * c11.g;
                    769:                                        g >>= 8;
                    770: 
                    771:                                        b = a00 * c00.b
                    772:                                          + a01 * c01.b
                    773:                                          + a10 * c10.b
                    774:                                          + a11 * c11.b;
                    775:                                        b >>= 8;
                    776: 
                    777:                                        Color c(r, g, b);
                    778:                                        d[tx] = c.u32;
                    779:                                }
                    780:                                d += dstride32;
                    781:                        }
                    782:                }
                    783:        }
                    784: #undef A
                    785: }
                    786: 
                    787: // src 全域が dr のサイズになるよう面積平均法で拡大縮小して描画。
                    788: // (等倍も無駄だけど動作はするはず)
                    789: void
                    790: BitmapRGBX::DrawBitmapMean(const Rect& dr, const BitmapRGBX& src)
                    791: {
                    792:        // dst の 1 pixel が src の 何 pixel に相当するか
                    793:        float tx = (float)src.GetWidth() / dr.w;
                    794:        float ty = (float)src.GetHeight() / dr.h;
                    795: 
                    796:        // src 上を動くウィンドウ
                    797:        RectF sr(0, 0, tx, ty);
                    798: 
                    799:        for (uint y = 0; y < dr.h; y++) {
                    800:                uint32 *d = (uint32 *)GetRowPtr(y);
                    801:                sr.x = 0;
                    802:                for (uint x = 0; x < dr.w; x++) {
                    803:                        Color c = src.Mean(sr);
                    804:                        *d++ = c.u32;
                    805:                        sr.x += tx;
                    806:                }
                    807:                sr.y += ty;
                    808:        }
                    809: }
                    810: 
1.1       root      811: // sr 範囲の色の平均を返す
                    812: Color
1.1.1.5   root      813: BitmapRGBX::Mean(const RectF& sr) const
1.1       root      814: {
1.1.1.5   root      815:        uint x1 = std::floor(sr.x);
                    816:        uint y1 = std::floor(sr.y);
                    817:        uint x2 = std::ceil(sr.x + sr.w);
                    818:        uint y2 = std::ceil(sr.y + sr.h);
                    819:        if (__predict_false(x2 > GetWidth())) {
1.1       root      820:                x2 = GetWidth();
                    821:        }
1.1.1.5   root      822:        if (__predict_false(y2 > GetHeight())) {
1.1       root      823:                y2 = GetHeight();
                    824:        }
                    825: 
1.1.1.5   root      826:        float sum_r = 0;
                    827:        float sum_g = 0;
                    828:        float sum_b = 0;
                    829: 
1.1       root      830:        // サブピクセルの辺の長さ
1.1.1.5   root      831:        float rx, ry;
                    832:        float area = 0;
                    833:        for (uint y = y1; y < y2; y++) {
1.1       root      834:                if (y == y1) {
                    835:                        ry = 1 - (sr.y - y1);
                    836:                } else if (y == y2 - 1) {
                    837:                        ry = 1 - (y2 - (sr.y + sr.h));
                    838:                } else {
                    839:                        ry = 1;
                    840:                }
                    841: 
1.1.1.5   root      842:                const uint32 *p = (const uint32 *)GetPtr(x1, y);
                    843:                for (uint x = x1; x < x2; x++) {
                    844:                        Color c(*p++);
                    845: 
1.1       root      846:                        if (x == x1) {
                    847:                                rx = 1 - (sr.x - x1);
1.1.1.5   root      848:                        } else if (x == x2 - 1) {
1.1       root      849:                                rx = 1 - (x2 - (sr.x + sr.w));
                    850:                        } else {
                    851:                                rx = 1;
                    852:                        }
                    853: 
                    854:                        // 面積比をかけて合成
1.1.1.5   root      855:                        sum_r += c.r * rx * ry;
                    856:                        sum_g += c.g * rx * ry;
                    857:                        sum_b += c.b * rx * ry;
                    858:                        area += rx * ry;
1.1       root      859:                }
                    860:        }
                    861: 
                    862:        // 平均にする
1.1.1.5   root      863:        sum_r /= area;
                    864:        sum_g /= area;
                    865:        sum_b /= area;
1.1       root      866: 
1.1.1.5   root      867:        return Color(sum_r, sum_g, sum_b);
1.1       root      868: }
                    869: 
1.1.1.7 ! root      870: // (x, y) に点を描画する。
        !           871: // 描画範囲をはみ出さないこと。
        !           872: void
        !           873: BitmapRGBX::DrawPoint(Color c, int x, int y)
        !           874: {
        !           875:        uint32 *d = (uint32 *)GetPtr(x, y);
        !           876:        *d = c.u32;
        !           877: }
        !           878: 
1.1       root      879: // 直線 (x1, y1) - (x2, y2) を描画する。終点は開区間。
                    880: // 描画範囲をはみ出さないこと。
                    881: void
1.1.1.5   root      882: BitmapRGBX::DrawLine(Color c, int x1, int y1, int x2, int y2)
1.1       root      883: {
                    884:        if (y1 == y2) {
                    885:                DrawLineH(c, x1, y1, x2);
                    886:        } else if (x1 == x2) {
                    887:                DrawLineV(c, x1, y1, y2);
                    888:        } else {
                    889:                assert(false);
                    890:        }
                    891: }
                    892: 
                    893: // 水平の直線 (x1, y1) - (x2, y1) を描画する。終点は開区間。
                    894: // 描画範囲をはみ出さないこと。
                    895: void
1.1.1.5   root      896: BitmapRGBX::DrawLineH(Color c, int x1, int y1, int x2)
1.1       root      897: {
                    898:        assert(buf);
                    899: 
                    900:        if (__predict_false(x1 > x2)) {
                    901:                std::swap(x1, x2);
                    902:                x1++;
                    903:                x2++;
                    904:        }
                    905: 
1.1.1.5   root      906:        uint32 *d = (uint32 *)GetPtr(x1, y1);
                    907:        for (int x = x1; x < x2; x++) {
                    908:                *d++ = c.u32;
1.1       root      909:        }
                    910: }
                    911: 
                    912: // 垂直の直線 (x1, y1) - (x1, y2) を描画する。終点は開区間。
                    913: // 描画範囲をはみ出さないこと。
                    914: void
1.1.1.5   root      915: BitmapRGBX::DrawLineV(Color c, int x1, int y1, int y2)
1.1       root      916: {
                    917:        assert(buf);
                    918: 
                    919:        if (__predict_false(y1 > y2)) {
                    920:                std::swap(y1, y2);
                    921:                y1++;
                    922:                y2++;
                    923:        }
                    924: 
1.1.1.5   root      925:        for (int y = y1; y < y2; y++) {
                    926:                uint32 *d = (uint32 *)GetPtr(x1, y);
                    927:                *d = c.u32;
1.1       root      928:        }
                    929: }
                    930: 
                    931: // 矩形 rect を色 c で塗りつぶす。
                    932: // 描画範囲をはみ出さないこと。
                    933: void
1.1.1.5   root      934: BitmapRGBX::FillRect(Color c, const Rect& rect)
1.1       root      935: {
                    936:        assert(buf);
                    937: 
1.1.1.5   root      938:        DrawLineH(c, rect.x, rect.y, rect.x + rect.w);
                    939:        CopyFromTop(rect);
                    940: }
1.1       root      941: 
1.1.1.5   root      942: // rect の一番上のラスターを rect の残りのラスターにコピーする。
                    943: void
                    944: BitmapRGBX::CopyFromTop(const Rect& rect)
                    945: {
                    946:        uint8 *s = GetPtr(rect.x, rect.y);
1.1       root      947:        uint8 *d = s + stride;
1.1.1.5   root      948:        const uint len = rect.w * 4;
1.1       root      949: 
1.1.1.5   root      950:        for (uint y = rect.y + 1; y < rect.y + rect.h; y++) {
1.1       root      951:                memcpy(d, s, len);
                    952:                d += stride;
                    953:        }
                    954: }
                    955: 
                    956: // 矩形 rect の辺を色 c で描画する。
                    957: // 描画範囲をはみ出さないこと。
                    958: void
1.1.1.5   root      959: BitmapRGBX::DrawRect(Color c, const Rect& rect)
1.1       root      960: {
                    961:        assert(buf);
                    962: 
                    963:        int l = rect.x;
                    964:        int t = rect.y;
                    965:        int r = rect.GetRight();
                    966:        int b = rect.GetBottom();
                    967: 
                    968:        DrawLineH(c, l, t, r);  // 上辺→
                    969:        DrawLineV(c, r, t, b);  // 右辺↓
                    970:        DrawLineH(c, r, b, l);  // 下辺←
                    971:        DrawLineV(c, l, b, t);  // 左辺↑
                    972: }
1.1.1.4   root      973: 
1.1.1.7 ! root      974: // 矩形 rect に内接する正円あるいは楕円を描画して中を塗りつぶす。
        !           975: // 描画範囲をはみ出さないこと。
        !           976: void
        !           977: BitmapRGBX::DrawFillCircle(Color border, Color fill, const Rect& rect)
        !           978: {
        !           979:        int D = rect.h;                         // 高さを基準にした直径
        !           980:        float r = D / 2;
        !           981:        float r2 = r * (r + 0.5);       // 半径の二乗
        !           982:        float prev_d = -1;
        !           983: 
        !           984:        // Y 方向を 1 px ずつステップしながら上下両側を対称に描画する。
        !           985:        // 奇数個のときは真ん中を 2 回書くため、D&1 で補正。
        !           986:        for (int i = 0, end = r + (D & 1); i < end; i++) {
        !           987:                // x^2 + y^2 = r^2 を解いて、楕円の係数を掛ける。
        !           988:                float d = std::sqrt(r2 - r * r) * rect.w / rect.h;
        !           989:                r--;
        !           990: 
        !           991:                for (int j = 0; j < 2; j++) {
        !           992:                        int y;
        !           993:                        if (j == 0) {
        !           994:                                y = rect.y + i;
        !           995:                        } else {
        !           996:                                y = rect.GetBottom() - i;
        !           997:                        }
        !           998: 
        !           999:                        int x1 = rect.x + rect.w / 2 - d;
        !          1000:                        int x2 = rect.x + rect.w / 2 + d;
        !          1001: 
        !          1002:                        DrawLineH(fill, x1, y, x2);
        !          1003: 
        !          1004:                        DrawPoint(border, x1, y);
        !          1005:                        DrawPoint(border, x2, y);
        !          1006: 
        !          1007:                        int prev_x1 = rect.x + rect.w / 2 - prev_d;
        !          1008:                        int prev_x2 = rect.x + rect.w / 2 + prev_d;
        !          1009:                        DrawLineH(border, x1, y, prev_x1);
        !          1010:                        DrawLineH(border, x2, y, prev_x2);
        !          1011:                }
        !          1012: 
        !          1013:                prev_d = d;
        !          1014:        }
        !          1015: }
        !          1016: 
1.1.1.5   root     1017: // 全域を RGB に変換。
                   1018: void
                   1019: BitmapRGBX::ConvertToRGB(BitmapRGB& dst) const
1.1.1.4   root     1020: {
1.1.1.5   root     1021:        assertmsg(dst.GetWidth() == GetWidth(),
                   1022:                "dst.width=%u, src.width=%u", dst.GetWidth(), GetWidth());
                   1023:        assertmsg(dst.GetHeight() == GetHeight(),
                   1024:                "dst.height=%u, src.height=%u", dst.GetWidth(), GetWidth());
                   1025: 
                   1026: #if defined(HAVE_AVX2)
                   1027:        if (__predict_true(enable_avx2)) {
                   1028:                ConvertToRGB_avx2(dst);
                   1029:        } else
                   1030: #endif
                   1031:        {
                   1032:                ConvertToRGB_gen(dst);
                   1033:        }
                   1034: }
                   1035: 
                   1036: // RGBX から RGB への変換。(C++ 版)
                   1037: void
                   1038: BitmapRGBX::ConvertToRGB_gen(BitmapRGB& dst) const
                   1039: {
                   1040:        const BitmapRGBX& src = *this;
                   1041: 
                   1042:        // この変換は一次元配列とみなしても行える。
                   1043:        // モニタ等のパネルでも呼ばれるので何ピクセルで割り切れるかの前提は不可。
                   1044:        uint total  = GetWidth() * GetHeight();
                   1045:        uint packed = total & ~3;
                   1046: 
                   1047:        const uint32 *s32 = (const uint32 *)src.GetRowPtr(0);
                   1048:        const uint32 *s32total  = s32 + total;
                   1049:        const uint32 *s32packed = s32 + packed;
                   1050: 
                   1051:        uint32 *d32 = (uint32 *)dst.GetRowPtr(0);
                   1052:        for (; s32 < s32packed; ) {
                   1053:                // 4ピクセルずつ処理する
                   1054:                uint32 c0 = *s32++;
                   1055:                uint32 c1 = *s32++;
                   1056:                uint32 c2 = *s32++;
                   1057:                uint32 c3 = *s32++;
                   1058: 
                   1059: #if BYTE_ORDER == LITTLE_ENDIAN
                   1060:                // c0   = $X0B0G0R0
                   1061:                // c1   = $X1B1G1R1
                   1062:                // c2   = $X2B2G2R2
                   1063:                // c3   = $X3B3G3R3
                   1064:                //
                   1065:                // d[0] = $00B0G0R0 | $R1000000 = $R1B0G0R0
                   1066:                // d[1] = $0000B1G1 | $G2R20000 = $G2R2B1G1
                   1067:                // d[2] = $000000B2 | $B3G3R300 = $B3G3R3B2
                   1068: 
                   1069:                *d32++ = (c0      ) | (c1 << 24);
                   1070:                *d32++ = (c1 >>  8) | (c2 << 16);
                   1071:                *d32++ = (c2 >> 16) | (c3 <<  8);
                   1072: #else
                   1073:                // c0   = $R0G0B0X0
                   1074:                // c1   = $R1G1B1X1
                   1075:                // c2   = $R2G2B2X2
                   1076:                // c3   = $R3G3B3X3
                   1077:                //
                   1078:                // d[0] = $R0G0B000 | $000000R1 = $R0G0B0R1
                   1079:                // d[1] = $G1B10000 | $0000R2G2 = $G1B1R2G2
                   1080:                // d[2] = $B2000000 | $00R3G3B3 = $B2R3G3B3
                   1081: 
                   1082:                *d32++ = (c0      ) | (c1 >> 24);
                   1083:                *d32++ = (c1 <<  8) | (c2 >> 16);
                   1084:                *d32++ = (c2 << 16) | (c3 >>  8);
                   1085: #endif
                   1086:        }
                   1087: 
                   1088:        uint8 *d8 = (uint8 *)d32;
                   1089:        for (; s32 < s32total; ) {
                   1090:                // 残りを1ピクセルずつ処理する
                   1091:                Color col(*s32++);
                   1092:                *d8++ = col.r;
                   1093:                *d8++ = col.g;
                   1094:                *d8++ = col.b;
                   1095:        }
1.1.1.4   root     1096: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.