Annotation of nono/lib/bitmap.cpp, revision 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.