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

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:        : inherited(width_, height_, 8)
                    117: {
                    118:        buf = static_cast<uint8 *>(const_cast<void *>(buf_));
                    119: }
                    120: 
                    121: // デストラクタ
                    122: BitmapI8::~BitmapI8()
                    123: {
                    124: }
                    125: 
                    126: // 作成
                    127: void
                    128: BitmapI8::Create(int width_, int height_)
                    129: {
                    130:        inherited::Create(width_, height_, 8);
                    131: 
                    132:        owned_buf.reset(new uint8[stride * height]);
                    133:        buf = owned_buf.get();
                    134: }
                    135: 
                    136: // カラーコード cc で全体を塗りつぶす。
                    137: // 未使用ビットも変更される。
                    138: void
                    139: BitmapI8::Fill(int cc)
                    140: {
                    141:        assert(buf);
                    142: 
                    143:        memset(buf, cc, stride * height);
                    144: }
                    145: 
                    146: 
                    147: //
                    148: // 24bpp ビットマップ
                    149: //
                    150: 
                    151: // コンストラクタ
                    152: BitmapRGB::BitmapRGB()
                    153: {
                    154: }
                    155: 
                    156: // コンストラクタ
                    157: BitmapRGB::BitmapRGB(int width_, int height_)
                    158: {
                    159:        Create(width_, height_);
                    160: }
                    161: 
                    162: // コンストラクタ
                    163: BitmapRGB::BitmapRGB(const void *buf_, int width_, int height_)
                    164:        : inherited(width_, height_, 24)
                    165: {
                    166:        buf = static_cast<uint8 *>(const_cast<void *>(buf_));
                    167: }
                    168: 
                    169: // デストラクタ
                    170: BitmapRGB::~BitmapRGB()
                    171: {
                    172: }
                    173: 
                    174: // 作成
                    175: void
                    176: BitmapRGB::Create(int width_, int height_)
                    177: {
                    178:        inherited::Create(width_, height_, 24);
                    179: 
                    180:        owned_buf.reset(new uint8[stride * height]);
                    181:        buf = owned_buf.get();
                    182: }
                    183: 
                    184: // 色 c で全体を塗りつぶす。
                    185: void
                    186: BitmapRGB::Fill(Color c)
                    187: {
                    188:        FillRect(c, 0, 0, width, height);
                    189: }
                    190: 
                    191: // (dx, dy) にビットマップ src を描画する。
                    192: // 描画範囲をはみ出さないこと。
                    193: void
                    194: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapI1& src, const Color *palette)
                    195: {
                    196:        assert(buf);
                    197: 
                    198:        const uint8 *srcbuf = src.GetBuf();
                    199: 
                    200:        uint8 data = 0;
                    201:        for (int y = 0; y < src.GetHeight(); y++) {
                    202:                uint8 *d = GetPtr(dx, dy + y);
                    203:                for (int x = 0; x < src.GetWidth(); x++) {
                    204:                        if (__predict_false(x % 8 == 0)) {
                    205:                                data = *srcbuf++;
                    206:                        }
                    207:                        int cc;
                    208:                        if ((int8)data < 0) {
                    209:                                cc = 1;
                    210:                        } else {
                    211:                                cc = 0;
                    212:                        }
                    213:                        data <<= 1;
                    214: 
                    215:                        Color c = palette[cc];
                    216:                        *d++ = c.r;
                    217:                        *d++ = c.g;
                    218:                        *d++ = c.b;
                    219:                }
                    220:        }
                    221: }
                    222: 
                    223: // (dx, dy) にビットマップ src の範囲 sr を描画する。
                    224: // 描画範囲をはみ出さないこと。
                    225: void
                    226: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapI8& src, const Color *palette,
                    227:        const Rect& sr)
                    228: {
                    229:        for (int y = 0; y < sr.h; y++) {
                    230:                uint8 *d = GetPtr(dx, dy + y);
                    231:                const uint8 *s = src.GetPtr(sr.x, sr.y + y);
                    232:                for (int x = 0; x < sr.w; x++) {
                    233:                        int cc = *s++;
                    234:                        Color c = palette[cc];
                    235:                        *d++ = c.r;
                    236:                        *d++ = c.g;
                    237:                        *d++ = c.b;
                    238:                }
                    239:        }
                    240: }
                    241: 
                    242: // (dx, dy) にビットマップ src を描画する。
                    243: // 描画範囲をはみ出さないこと。
                    244: void
                    245: BitmapRGB::DrawBitmap(int dx, int dy, const BitmapRGB& src)
                    246: {
                    247:        assert(buf);
                    248: 
                    249:        const uint8 *s = src.GetBuf();
                    250: 
                    251:        for (int y = 0; y < src.GetHeight(); y++) {
                    252:                uint8 *d = GetPtr(dx, dy + y);
                    253:                for (int x = 0; x < src.GetWidth(); x++) {
                    254:                        *d++ = *s++;
                    255:                        *d++ = *s++;
                    256:                        *d++ = *s++;
                    257:                }
                    258:        }
                    259: }
                    260: 
                    261: // (dx, dy) にビットマップ src を scale 倍にして描画する。
                    262: // 描画範囲をはみ出さないこと。
                    263: void
                    264: BitmapRGB::DrawScaleUp(int dx, int dy, int scale, const BitmapI1& src,
                    265:        const Color *palette)
                    266: {
                    267:        assert(buf);
                    268: 
                    269:        const uint8 *srcbuf = src.GetBuf();
                    270:        uint8 data = 0;
                    271:        int dx0 = dx;
                    272: 
                    273:        for (int y = 0; y < src.GetHeight(); y++) {
                    274:                dx = dx0;
                    275:                for (int x = 0; x < src.GetWidth(); x++) {
                    276:                        if (__predict_false(x % 8 == 0)) {
                    277:                                data = *srcbuf++;
                    278:                        }
                    279:                        int cc;
                    280:                        if ((int8)data < 0) {
                    281:                                cc = 1;
                    282:                        } else {
                    283:                                cc = 0;
                    284:                        }
                    285:                        data <<= 1;
                    286: 
                    287:                        FillRect(palette[cc], dx, dy, scale, scale);
                    288:                        dx += scale;
                    289:                }
                    290:                dy += scale;
                    291:        }
                    292: }
                    293: 
                    294: // sr 範囲の色の平均を返す
                    295: Color
                    296: BitmapRGB::Mean(const RectD& sr) const
                    297: {
                    298:        int x1 = std::floor(sr.x);
                    299:        int y1 = std::floor(sr.y);
                    300:        int x2 = std::ceil(sr.x + sr.w);
                    301:        int y2 = std::ceil(sr.y + sr.h);
                    302:        if (__predict_false(x2 >= GetWidth())) {
                    303:                x2 = GetWidth();
                    304:        }
                    305:        if (__predict_false(y2 >= GetHeight())) {
                    306:                y2 = GetHeight();
                    307:        }
                    308: 
                    309:        ColorD sum;
                    310:        // サブピクセルの辺の長さ
                    311:        double rx, ry;
                    312:        double s = 0;
                    313:        for (int y = y1; y < y2; y++) {
                    314:                if (y == y1) {
                    315:                        ry = 1 - (sr.y - y1);
                    316:                } else if (y == y2 - 1) {
                    317:                        ry = 1 - (y2 - (sr.y + sr.h));
                    318:                } else {
                    319:                        ry = 1;
                    320:                }
                    321: 
                    322:                const uint8 *p = GetPtr(x1, y);
                    323:                for (int x = x1; x < x2; x++) {
                    324:                        if (x == x1) {
                    325:                                rx = 1 - (sr.x - x1);
                    326:                        } else if (y == x2 - 1) {
                    327:                                rx = 1 - (x2 - (sr.x + sr.w));
                    328:                        } else {
                    329:                                rx = 1;
                    330:                        }
                    331: 
                    332:                        Color c;
                    333:                        c.r = *p++;
                    334:                        c.g = *p++;
                    335:                        c.b = *p++;
                    336: 
                    337:                        // 面積比をかけて合成
                    338:                        sum.r += c.r * rx * ry;
                    339:                        sum.g += c.g * rx * ry;
                    340:                        sum.b += c.b * rx * ry;
                    341:                        s += rx * ry;
                    342:                }
                    343:        }
                    344: 
                    345:        // 平均にする
                    346:        sum.r /= s;
                    347:        sum.g /= s;
                    348:        sum.b /= s;
                    349: 
                    350:        return Color(sum.r, sum.g, sum.b);
                    351: }
                    352: 
                    353: // 伸縮して描画
                    354: void
                    355: BitmapRGB::StretchDraw(Rect dr, const BitmapRGB& src)
                    356: {
                    357:        if (__predict_false(dr.w == src.GetWidth() && dr.h == src.GetHeight())) {
                    358:                DrawBitmap(dr.x, dr.y, src);
                    359:                return;
                    360:        }
                    361: 
                    362:        // dst の 1 pixel が src の 何 pixel に相当するか
                    363:        double tx = (double)src.GetWidth() / dr.w;
                    364:        double ty = (double)src.GetHeight() / dr.h;
                    365: 
                    366:        // src 上を動くウィンドウ
                    367:        RectD sr(0, 0, tx, ty);
                    368: 
                    369:        for (int y = 0; y < dr.h; y++) {
                    370:                uint8 *d = GetRowPtr(y);
                    371:                sr.x = 0;
                    372:                for (int x = 0; x < dr.w; x++) {
                    373:                        Color c = src.Mean(sr);
                    374: 
                    375:                        *d++ = c.r;
                    376:                        *d++ = c.g;
                    377:                        *d++ = c.b;
                    378:                        sr.x += tx;
                    379:                }
                    380:                sr.y += ty;
                    381:        }
                    382: }
                    383: 
                    384: // 直線 (x1, y1) - (x2, y2) を描画する。終点は開区間。
                    385: // 描画範囲をはみ出さないこと。
                    386: void
                    387: BitmapRGB::DrawLine(Color c, int x1, int y1, int x2, int y2)
                    388: {
                    389:        if (y1 == y2) {
                    390:                DrawLineH(c, x1, y1, x2);
                    391:        } else if (x1 == x2) {
                    392:                DrawLineV(c, x1, y1, y2);
                    393:        } else {
                    394:                assert(false);
                    395:        }
                    396: }
                    397: 
                    398: // 水平の直線 (x1, y1) - (x2, y1) を描画する。終点は開区間。
                    399: // 描画範囲をはみ出さないこと。
                    400: void
                    401: BitmapRGB::DrawLineH(Color c, int x1, int y1, int x2)
                    402: {
                    403:        assert(buf);
                    404: 
                    405:        if (__predict_false(x1 > x2)) {
                    406:                std::swap(x1, x2);
                    407:                x1++;
                    408:                x2++;
                    409:        }
                    410: 
                    411:        uint8 *d = GetPtr(x1, y1);
                    412: 
                    413:        // 12バイト境界に整列するまで
                    414:        for (; (uintptr_t)d % 4 != 0 && x1 < x2 ; x1++) {
                    415:                *d++ = c.r;
                    416:                *d++ = c.g;
                    417:                *d++ = c.b;
                    418:        }
                    419: 
                    420:        // 12バイト境界から 12バイト以上残ってる間
                    421:        int cnt = (x2 - x1) / 4;
                    422:        if (__predict_true(cnt > 0)) {
                    423:                uint32 pat[3];
                    424:                for (uint8 *p = (uint8 *)pat, *pend = p + sizeof(pat); p < pend; ) {
                    425:                        *p++ = c.r;
                    426:                        *p++ = c.g;
                    427:                        *p++ = c.b;
                    428:                }
                    429:                for (int i = 0; i < cnt; i++) {
                    430:                        memcpy(d, pat, sizeof(pat));
                    431:                        d += sizeof(pat);
                    432:                }
                    433:                x1 += cnt * sizeof(pat) / 3;
                    434:        }
                    435: 
                    436:        // 残り
                    437:        for (; x1 < x2; x1++) {
                    438:                *d++ = c.r;
                    439:                *d++ = c.g;
                    440:                *d++ = c.b;
                    441:        }
                    442: }
                    443: 
                    444: // 垂直の直線 (x1, y1) - (x1, y2) を描画する。終点は開区間。
                    445: // 描画範囲をはみ出さないこと。
                    446: void
                    447: BitmapRGB::DrawLineV(Color c, int x1, int y1, int y2)
                    448: {
                    449:        assert(buf);
                    450: 
                    451:        if (__predict_false(y1 > y2)) {
                    452:                std::swap(y1, y2);
                    453:                y1++;
                    454:                y2++;
                    455:        }
                    456: 
                    457:        for (; y1 < y2; y1++) {
                    458:                uint8 *d = GetPtr(x1, y1);
                    459:                *d++ = c.r;
                    460:                *d++ = c.g;
                    461:                *d++ = c.b;
                    462:        }
                    463: }
                    464: 
                    465: // 矩形 (dx, dy) - (dw * dh) を色 c で塗りつぶす。
                    466: // 描画範囲をはみ出さないこと。
                    467: void
                    468: BitmapRGB::FillRect(Color c, int dx, int dy, int dw, int dh)
                    469: {
                    470:        FillRect(c, Rect(dx, dy, dw, dh));
                    471: }
                    472: 
                    473: // 矩形 rect を色 c で塗りつぶす。
                    474: // 描画範囲をはみ出さないこと。
                    475: void
                    476: BitmapRGB::FillRect(Color c, const Rect& rect)
                    477: {
                    478:        assert(buf);
                    479: 
                    480:        const int l = rect.x;
                    481:        const int t = rect.y;
                    482: 
                    483:        DrawLineH(c, l, t, l + rect.w);
                    484: 
                    485:        uint8 *s = GetPtr(l, t);
                    486:        uint8 *d = s + stride;
                    487:        const int len = rect.w * 3;
                    488: 
                    489:        for (int y = t + 1; y < t + rect.h; y++) {
                    490:                memcpy(d, s, len);
                    491:                d += stride;
                    492:        }
                    493: }
                    494: 
                    495: // 矩形 (dx, dy) - (dw * dh) を色 c で描画する。
                    496: // 描画範囲をはみ出さないこと。
                    497: void
                    498: BitmapRGB::DrawRect(Color c, int dx, int dy, int dw, int dh)
                    499: {
                    500:        DrawRect(c, Rect(dx, dy, dw, dh));
                    501: }
                    502: 
                    503: // 矩形 rect の辺を色 c で描画する。
                    504: // 描画範囲をはみ出さないこと。
                    505: void
                    506: BitmapRGB::DrawRect(Color c, const Rect& rect)
                    507: {
                    508:        assert(buf);
                    509: 
                    510:        int l = rect.x;
                    511:        int t = rect.y;
                    512:        int r = rect.GetRight();
                    513:        int b = rect.GetBottom();
                    514: 
                    515:        DrawLineH(c, l, t, r);  // 上辺→
                    516:        DrawLineV(c, r, t, b);  // 右辺↓
                    517:        DrawLineH(c, r, b, l);  // 下辺←
                    518:        DrawLineV(c, l, b, t);  // 左辺↑
                    519: }

unix.superglobalmegacorp.com

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