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

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

unix.superglobalmegacorp.com

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