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

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

unix.superglobalmegacorp.com

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