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

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: }

unix.superglobalmegacorp.com

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