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

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"
                     12: #include <cmath>
                     13: 
                     14: //
                     15: // ビットマップ (基本クラス)
                     16: //
                     17: 
                     18: // コンストラクタ
                     19: BitmapBase::BitmapBase()
                     20: {
                     21: }
                     22: 
                     23: // コンストラクタ
                     24: BitmapBase::BitmapBase(int width_, int height_, int depth_)
                     25: {
                     26:        Create(width_, height_, depth_);
                     27: }
                     28: 
                     29: // デストラクタ
                     30: BitmapBase::~BitmapBase()
                     31: {
                     32: }
                     33: 
1.1.1.3 ! root       34: // 作成。width_ * height_ が面積を持っていれば true を返す。
        !            35: bool
1.1       root       36: BitmapBase::Create(int width_, int height_, int depth_)
                     37: {
                     38:        assert(depth_ == 1 || depth_ == 8 || depth_ == 24);
                     39: 
                     40:        width = width_;
                     41:        height = height_;
                     42: 
                     43:        if (depth_ == 1) {
                     44:                stride = (width + 7) / 8;
                     45:        } else {
                     46:                stride = width * depth_ / 8;
                     47:        }
1.1.1.3 ! root       48: 
        !            49:        return (width > 0 && height > 0);
1.1       root       50: }
                     51: 
                     52: 
                     53: //
                     54: // 1bpp ビットマップ
                     55: //
                     56: 
                     57: // コンストラクタ
                     58: BitmapI1::BitmapI1()
                     59: {
                     60: }
                     61: 
                     62: // コンストラクタ
                     63: BitmapI1::BitmapI1(int width_, int height_)
                     64: {
                     65:        Create(width_, height_);
                     66: }
                     67: 
                     68: // コンストラクタ
                     69: BitmapI1::BitmapI1(const void *buf_, int width_, int height_)
                     70:        : inherited(width_, height_, 1)
                     71: {
                     72:        buf = static_cast<uint8 *>(const_cast<void *>(buf_));
                     73: }
                     74: 
                     75: // デストラクタ
                     76: BitmapI1::~BitmapI1()
                     77: {
                     78: }
                     79: 
                     80: // 作成
                     81: void
                     82: BitmapI1::Create(int width_, int height_)
                     83: {
1.1.1.3 ! root       84:        if (inherited::Create(width_, height_, 1)) {
        !            85:                owned_buf.reset(new uint8[stride * height]);
        !            86:                buf = owned_buf.get();
        !            87:        } else {
        !            88:                owned_buf.reset();
        !            89:                buf = NULL;
        !            90:        }
1.1       root       91: }
                     92: 
                     93: // カラーコード cc で全体を塗りつぶす。
                     94: // 未使用ビットも変更される。
                     95: void
                     96: BitmapI1::Fill(int cc)
                     97: {
                     98:        assert(buf);
                     99: 
                    100:        memset(buf, (cc ? 0xff : 0), stride * height);
                    101: }
                    102: 
                    103: 
                    104: //
                    105: // 8bpp ビットマップ
                    106: //
                    107: 
                    108: // コンストラクタ
                    109: BitmapI8::BitmapI8()
                    110: {
                    111: }
                    112: 
                    113: // コンストラクタ
                    114: BitmapI8::BitmapI8(int width_, int height_)
                    115: {
                    116:        Create(width_, height_);
                    117: }
                    118: 
                    119: // コンストラクタ
                    120: BitmapI8::BitmapI8(const void *buf_, int width_, int height_)
                    121: {
1.1.1.2   root      122:        Create(buf_, width_, height_);
1.1       root      123: }
                    124: 
                    125: // デストラクタ
                    126: BitmapI8::~BitmapI8()
                    127: {
                    128: }
                    129: 
                    130: // 作成
                    131: void
                    132: BitmapI8::Create(int width_, int height_)
                    133: {
1.1.1.3 ! root      134:        if (inherited::Create(width_, height_, 8)) {
        !           135:                owned_buf.reset(new uint8[stride * height]);
        !           136:                buf = owned_buf.get();
        !           137:        } else {
        !           138:                owned_buf.reset();
        !           139:                buf = NULL;
        !           140:        }
1.1       root      141: }
                    142: 
1.1.1.2   root      143: // 元データを指定して作成
                    144: void
                    145: BitmapI8::Create(const void *buf_, int width_, int height_)
                    146: {
1.1.1.3 ! root      147:        if (inherited::Create(width_, height_, 8)) {
        !           148:                buf = static_cast<uint8 *>(const_cast<void *>(buf_));
        !           149:        } else {
        !           150:                buf = NULL;
        !           151:        }
1.1.1.2   root      152: }
                    153: 
1.1       root      154: // カラーコード cc で全体を塗りつぶす。
                    155: // 未使用ビットも変更される。
                    156: void
                    157: BitmapI8::Fill(int cc)
                    158: {
                    159:        assert(buf);
                    160: 
                    161:        memset(buf, cc, stride * height);
                    162: }
                    163: 
                    164: 
                    165: //
                    166: // 24bpp ビットマップ
                    167: //
                    168: 
                    169: // コンストラクタ
                    170: BitmapRGB::BitmapRGB()
                    171: {
                    172: }
                    173: 
                    174: // コンストラクタ
                    175: BitmapRGB::BitmapRGB(int width_, int height_)
                    176: {
                    177:        Create(width_, height_);
                    178: }
                    179: 
                    180: // コンストラクタ
                    181: BitmapRGB::BitmapRGB(const void *buf_, int width_, int height_)
                    182:        : inherited(width_, height_, 24)
                    183: {
                    184:        buf = static_cast<uint8 *>(const_cast<void *>(buf_));
                    185: }
                    186: 
                    187: // デストラクタ
                    188: BitmapRGB::~BitmapRGB()
                    189: {
                    190: }
                    191: 
                    192: // 作成
                    193: void
                    194: BitmapRGB::Create(int width_, int height_)
                    195: {
1.1.1.3 ! root      196:        if (inherited::Create(width_, height_, 24)) {
        !           197:                owned_buf.reset(new uint8[stride * height]);
        !           198:                buf = owned_buf.get();
        !           199:        } else {
        !           200:                owned_buf.reset();
        !           201:                buf = NULL;
        !           202:        }
1.1       root      203: }
                    204: 
                    205: // 色 c で全体を塗りつぶす。
                    206: void
                    207: BitmapRGB::Fill(Color c)
                    208: {
                    209:        FillRect(c, 0, 0, width, height);
                    210: }
                    211: 
                    212: // (dx, dy) にビットマップ src を描画する。
                    213: // 描画範囲をはみ出さないこと。
                    214: void
                    215: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapI1& src, const Color *palette)
                    216: {
                    217:        assert(buf);
                    218: 
                    219:        const uint8 *srcbuf = src.GetBuf();
                    220: 
                    221:        uint8 data = 0;
                    222:        for (int y = 0; y < src.GetHeight(); y++) {
                    223:                uint8 *d = GetPtr(dx, dy + y);
                    224:                for (int x = 0; x < src.GetWidth(); x++) {
                    225:                        if (__predict_false(x % 8 == 0)) {
                    226:                                data = *srcbuf++;
                    227:                        }
                    228:                        int cc;
                    229:                        if ((int8)data < 0) {
                    230:                                cc = 1;
                    231:                        } else {
                    232:                                cc = 0;
                    233:                        }
                    234:                        data <<= 1;
                    235: 
                    236:                        Color c = palette[cc];
                    237:                        *d++ = c.r;
                    238:                        *d++ = c.g;
                    239:                        *d++ = c.b;
                    240:                }
                    241:        }
                    242: }
                    243: 
1.1.1.2   root      244: // (dx, dy) にビットマップ src の全域を描画する。
                    245: // 描画範囲をはみ出さないこと。
                    246: void
                    247: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapI8& src, const Color *palette)
                    248: {
                    249:        Rect sr(0, 0, src.GetWidth(), src.GetHeight());
                    250:        DrawBitmap(dx, dy, src, palette, sr);
                    251: }
                    252: 
1.1       root      253: // (dx, dy) にビットマップ src の範囲 sr を描画する。
                    254: // 描画範囲をはみ出さないこと。
                    255: void
                    256: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapI8& src, const Color *palette,
                    257:        const Rect& sr)
                    258: {
                    259:        for (int y = 0; y < sr.h; y++) {
                    260:                uint8 *d = GetPtr(dx, dy + y);
                    261:                const uint8 *s = src.GetPtr(sr.x, sr.y + y);
                    262:                for (int x = 0; x < sr.w; x++) {
                    263:                        int cc = *s++;
                    264:                        Color c = palette[cc];
                    265:                        *d++ = c.r;
                    266:                        *d++ = c.g;
                    267:                        *d++ = c.b;
                    268:                }
                    269:        }
                    270: }
                    271: 
                    272: // (dx, dy) にビットマップ src を描画する。
                    273: // 描画範囲をはみ出さないこと。
                    274: void
                    275: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapRGB& src)
                    276: {
                    277:        assert(buf);
                    278: 
                    279:        const uint8 *s = src.GetBuf();
                    280: 
                    281:        for (int y = 0; y < src.GetHeight(); y++) {
                    282:                uint8 *d = GetPtr(dx, dy + y);
                    283:                for (int x = 0; x < src.GetWidth(); x++) {
                    284:                        *d++ = *s++;
                    285:                        *d++ = *s++;
                    286:                        *d++ = *s++;
                    287:                }
                    288:        }
                    289: }
                    290: 
                    291: // (dx, dy) にビットマップ src を scale 倍にして描画する。
                    292: // 描画範囲をはみ出さないこと。
                    293: void
                    294: BitmapRGB::DrawScaleUp(int dx, int dy, int scale, const BitmapI1& src,
                    295:        const Color *palette)
                    296: {
                    297:        assert(buf);
                    298: 
                    299:        const uint8 *srcbuf = src.GetBuf();
                    300:        uint8 data = 0;
                    301:        int dx0 = dx;
                    302: 
                    303:        for (int y = 0; y < src.GetHeight(); y++) {
                    304:                dx = dx0;
                    305:                for (int x = 0; x < src.GetWidth(); x++) {
                    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: 
                    317:                        FillRect(palette[cc], dx, dy, scale, scale);
                    318:                        dx += scale;
                    319:                }
                    320:                dy += scale;
                    321:        }
                    322: }
                    323: 
1.1.1.2   root      324: // 分数で表現可能な拡大縮小描画。
                    325: // dr にビットマップ src の (sxN / sxD, syN / syD) からを
                    326: // dst の 1 ピクセルに対して (sxS / sxD, syS / syD) ずつ動かした位置を
                    327: // 読み出し位置として描画する。
                    328: // 描画範囲をはみ出さないこと。
                    329: void
                    330: BitmapRGB::DrawScale(const Rect& dr, const BitmapI8& src, const Color *palette,
                    331:        int sxN, int sxD, int sxS, int syN, int syD, int syS)
                    332: {
                    333:        assert(buf);
                    334:        assert(sxD >= 1);
                    335:        assert(syD >= 1);
                    336:        assert(sxS != 0);
                    337:        assert(syS != 0);
                    338: 
                    339:        int sxI = sxN / sxD;
                    340:        int syI = syN / syD;
                    341: 
                    342:        sxN %= sxD;
                    343:        syN %= syD;
                    344: 
                    345:        int sxI0 = sxI;
                    346:        int sxN0 = sxN;
                    347: 
                    348:        int sx;
                    349:        int sy = syI - 1;
                    350: 
                    351:        for (int y = 0; y < dr.h; y++) {
                    352:                uint8 *d = GetPtr(dr.x, dr.y + y);
                    353: 
                    354:                if (sy != syI) {
                    355:                        sy = syI;
                    356: 
                    357:                        sx = sxI0 - 1;
                    358:                        sxI = sxI0;
                    359:                        sxN = sxN0;
                    360: 
                    361:                        uint8 cc = 0;
                    362:                        for (int x = 0; x < dr.w; x++) {
                    363:                                if (sx != sxI) {
                    364:                                        sx = sxI;
                    365:                                        const uint8 *s = src.GetPtr(sx, sy);
                    366:                                        cc = *s;
                    367:                                }
                    368:                                const Color& c = palette[cc];
                    369:                                *d++ = c.r;
                    370:                                *d++ = c.g;
                    371:                                *d++ = c.b;
                    372: 
                    373:                                sxN += sxS;
                    374:                                if (sxN >= sxD) {
                    375:                                        sxI += sxN / sxD;
                    376:                                        sxN %= sxD;
                    377:                                }
                    378:                        }
                    379:                } else {
                    380:                        // 前のラスタの中からコピーすればよい
                    381:                        memcpy(d, d - stride, dr.w * 3);
                    382:                }
                    383: 
                    384:                syN += syS;
                    385:                if (syN >= syD) {
                    386:                        syI += syN / syD;
                    387:                        syN %= syD;
                    388:                }
                    389:        }
                    390: }
                    391: 
1.1       root      392: // sr 範囲の色の平均を返す
                    393: Color
                    394: BitmapRGB::Mean(const RectD& sr) const
                    395: {
                    396:        int x1 = std::floor(sr.x);
                    397:        int y1 = std::floor(sr.y);
                    398:        int x2 = std::ceil(sr.x + sr.w);
                    399:        int y2 = std::ceil(sr.y + sr.h);
                    400:        if (__predict_false(x2 >= GetWidth())) {
                    401:                x2 = GetWidth();
                    402:        }
                    403:        if (__predict_false(y2 >= GetHeight())) {
                    404:                y2 = GetHeight();
                    405:        }
                    406: 
                    407:        ColorD sum;
                    408:        // サブピクセルの辺の長さ
                    409:        double rx, ry;
                    410:        double s = 0;
                    411:        for (int y = y1; y < y2; y++) {
                    412:                if (y == y1) {
                    413:                        ry = 1 - (sr.y - y1);
                    414:                } else if (y == y2 - 1) {
                    415:                        ry = 1 - (y2 - (sr.y + sr.h));
                    416:                } else {
                    417:                        ry = 1;
                    418:                }
                    419: 
                    420:                const uint8 *p = GetPtr(x1, y);
                    421:                for (int x = x1; x < x2; x++) {
                    422:                        if (x == x1) {
                    423:                                rx = 1 - (sr.x - x1);
                    424:                        } else if (y == x2 - 1) {
                    425:                                rx = 1 - (x2 - (sr.x + sr.w));
                    426:                        } else {
                    427:                                rx = 1;
                    428:                        }
                    429: 
                    430:                        Color c;
                    431:                        c.r = *p++;
                    432:                        c.g = *p++;
                    433:                        c.b = *p++;
                    434: 
                    435:                        // 面積比をかけて合成
                    436:                        sum.r += c.r * rx * ry;
                    437:                        sum.g += c.g * rx * ry;
                    438:                        sum.b += c.b * rx * ry;
                    439:                        s += rx * ry;
                    440:                }
                    441:        }
                    442: 
                    443:        // 平均にする
                    444:        sum.r /= s;
                    445:        sum.g /= s;
                    446:        sum.b /= s;
                    447: 
                    448:        return Color(sum.r, sum.g, sum.b);
                    449: }
                    450: 
                    451: // 伸縮して描画
                    452: void
                    453: BitmapRGB::StretchDraw(Rect dr, const BitmapRGB& src)
                    454: {
                    455:        if (__predict_false(dr.w == src.GetWidth() && dr.h == src.GetHeight())) {
                    456:                DrawBitmap(dr.x, dr.y, src);
                    457:                return;
                    458:        }
                    459: 
                    460:        // dst の 1 pixel が src の 何 pixel に相当するか
                    461:        double tx = (double)src.GetWidth() / dr.w;
                    462:        double ty = (double)src.GetHeight() / dr.h;
                    463: 
                    464:        // src 上を動くウィンドウ
                    465:        RectD sr(0, 0, tx, ty);
                    466: 
                    467:        for (int y = 0; y < dr.h; y++) {
                    468:                uint8 *d = GetRowPtr(y);
                    469:                sr.x = 0;
                    470:                for (int x = 0; x < dr.w; x++) {
                    471:                        Color c = src.Mean(sr);
                    472: 
                    473:                        *d++ = c.r;
                    474:                        *d++ = c.g;
                    475:                        *d++ = c.b;
                    476:                        sr.x += tx;
                    477:                }
                    478:                sr.y += ty;
                    479:        }
                    480: }
                    481: 
                    482: // 直線 (x1, y1) - (x2, y2) を描画する。終点は開区間。
                    483: // 描画範囲をはみ出さないこと。
                    484: void
                    485: BitmapRGB::DrawLine(Color c, int x1, int y1, int x2, int y2)
                    486: {
                    487:        if (y1 == y2) {
                    488:                DrawLineH(c, x1, y1, x2);
                    489:        } else if (x1 == x2) {
                    490:                DrawLineV(c, x1, y1, y2);
                    491:        } else {
                    492:                assert(false);
                    493:        }
                    494: }
                    495: 
                    496: // 水平の直線 (x1, y1) - (x2, y1) を描画する。終点は開区間。
                    497: // 描画範囲をはみ出さないこと。
                    498: void
                    499: BitmapRGB::DrawLineH(Color c, int x1, int y1, int x2)
                    500: {
                    501:        assert(buf);
                    502: 
                    503:        if (__predict_false(x1 > x2)) {
                    504:                std::swap(x1, x2);
                    505:                x1++;
                    506:                x2++;
                    507:        }
                    508: 
                    509:        uint8 *d = GetPtr(x1, y1);
                    510: 
                    511:        // 12バイト境界に整列するまで
                    512:        for (; (uintptr_t)d % 4 != 0 && x1 < x2 ; x1++) {
                    513:                *d++ = c.r;
                    514:                *d++ = c.g;
                    515:                *d++ = c.b;
                    516:        }
                    517: 
                    518:        // 12バイト境界から 12バイト以上残ってる間
                    519:        int cnt = (x2 - x1) / 4;
                    520:        if (__predict_true(cnt > 0)) {
                    521:                uint32 pat[3];
                    522:                for (uint8 *p = (uint8 *)pat, *pend = p + sizeof(pat); p < pend; ) {
                    523:                        *p++ = c.r;
                    524:                        *p++ = c.g;
                    525:                        *p++ = c.b;
                    526:                }
                    527:                for (int i = 0; i < cnt; i++) {
                    528:                        memcpy(d, pat, sizeof(pat));
                    529:                        d += sizeof(pat);
                    530:                }
                    531:                x1 += cnt * sizeof(pat) / 3;
                    532:        }
                    533: 
                    534:        // 残り
                    535:        for (; x1 < x2; x1++) {
                    536:                *d++ = c.r;
                    537:                *d++ = c.g;
                    538:                *d++ = c.b;
                    539:        }
                    540: }
                    541: 
                    542: // 垂直の直線 (x1, y1) - (x1, y2) を描画する。終点は開区間。
                    543: // 描画範囲をはみ出さないこと。
                    544: void
                    545: BitmapRGB::DrawLineV(Color c, int x1, int y1, int y2)
                    546: {
                    547:        assert(buf);
                    548: 
                    549:        if (__predict_false(y1 > y2)) {
                    550:                std::swap(y1, y2);
                    551:                y1++;
                    552:                y2++;
                    553:        }
                    554: 
                    555:        for (; y1 < y2; y1++) {
                    556:                uint8 *d = GetPtr(x1, y1);
                    557:                *d++ = c.r;
                    558:                *d++ = c.g;
                    559:                *d++ = c.b;
                    560:        }
                    561: }
                    562: 
                    563: // 矩形 (dx, dy) - (dw * dh) を色 c で塗りつぶす。
                    564: // 描画範囲をはみ出さないこと。
                    565: void
                    566: BitmapRGB::FillRect(Color c, int dx, int dy, int dw, int dh)
                    567: {
                    568:        FillRect(c, Rect(dx, dy, dw, dh));
                    569: }
                    570: 
                    571: // 矩形 rect を色 c で塗りつぶす。
                    572: // 描画範囲をはみ出さないこと。
                    573: void
                    574: BitmapRGB::FillRect(Color c, const Rect& rect)
                    575: {
                    576:        assert(buf);
                    577: 
                    578:        const int l = rect.x;
                    579:        const int t = rect.y;
                    580: 
                    581:        DrawLineH(c, l, t, l + rect.w);
                    582: 
                    583:        uint8 *s = GetPtr(l, t);
                    584:        uint8 *d = s + stride;
                    585:        const int len = rect.w * 3;
                    586: 
                    587:        for (int y = t + 1; y < t + rect.h; y++) {
                    588:                memcpy(d, s, len);
                    589:                d += stride;
                    590:        }
                    591: }
                    592: 
                    593: // 矩形 (dx, dy) - (dw * dh) を色 c で描画する。
                    594: // 描画範囲をはみ出さないこと。
                    595: void
                    596: BitmapRGB::DrawRect(Color c, int dx, int dy, int dw, int dh)
                    597: {
                    598:        DrawRect(c, Rect(dx, dy, dw, dh));
                    599: }
                    600: 
                    601: // 矩形 rect の辺を色 c で描画する。
                    602: // 描画範囲をはみ出さないこと。
                    603: void
                    604: BitmapRGB::DrawRect(Color c, const Rect& rect)
                    605: {
                    606:        assert(buf);
                    607: 
                    608:        int l = rect.x;
                    609:        int t = rect.y;
                    610:        int r = rect.GetRight();
                    611:        int b = rect.GetBottom();
                    612: 
                    613:        DrawLineH(c, l, t, r);  // 上辺→
                    614:        DrawLineV(c, r, t, b);  // 右辺↓
                    615:        DrawLineH(c, r, b, l);  // 下辺←
                    616:        DrawLineV(c, l, b, t);  // 左辺↑
                    617: }

unix.superglobalmegacorp.com

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