|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.