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

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

unix.superglobalmegacorp.com

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