--- nono/lib/bitmap.cpp 2026/04/29 17:05:26 1.1.1.5 +++ nono/lib/bitmap.cpp 2026/04/29 17:05:47 1.1.1.7 @@ -55,6 +55,45 @@ BitmapBase::Create(uint width_, uint hei } } +// コピーコンストラクタ +BitmapBase::BitmapBase(const BitmapBase& src) +{ + width = src.width; + height = src.height; + stride = src.stride; + depth = src.depth; + + owned_buf = src.owned_buf; + // src.buf は src.owned_buf かクラス外のどこか (か NULL) を指している。 + if (src.buf == src.owned_buf.get()) { + buf = owned_buf.get(); + } else { + buf = src.buf; + } +} + +// コピー代入演算子 +BitmapBase& +BitmapBase::operator=(const BitmapBase& src) +{ + owned_buf.Reset(); + + width = src.width; + height = src.height; + stride = src.stride; + depth = src.depth; + + owned_buf = src.owned_buf; + // src.buf は src.owned_buf かクラス外のどこか (か NULL) を指している。 + if (src.buf == src.owned_buf.get()) { + buf = owned_buf.get(); + } else { + buf = src.buf; + } + + return *this; +} + // 全域をコピーしてくる。 void BitmapBase::CopyFrom(const BitmapBase *src) @@ -102,6 +141,67 @@ BitmapI1::GetPtr(int x, int y) const return NULL; } +// 1ラスタを読み込む/書き出すマクロ。副作用もりもり。 +#define Load(bits, src) do { \ + bits = 0; \ + for (int x = 0; x < stride; x++) { \ + bits <<= 8; \ + bits |= *src++; \ + } \ +} while (0) +#define Store(bits, dst) do { \ + for (int x = stride - 1; x >= 0; x--) { \ + *dst++ = (bits >> (x * 8)) & 0xff; \ + } \ +} while (0) + +// このビットマップ(フォント)をボールドにした新しいビットマップを返す。 +BitmapI1 +BitmapI1::ConvertToBold() const +{ + assert(stride <= 8); + + BitmapI1 dst(width, height); + const uint8 *s = buf; + uint8 *d = dst.buf; + for (int y = 0; y < height; y++) { + uint64 bits; + Load(bits, s); + bits |= bits >> 1; + Store(bits, d); + } + return dst; +} + +// このビットマップ(フォント)をイタリックにした新しいビットマップを返す。 +BitmapI1 +BitmapI1::ConvertToItalic() const +{ + assert(stride <= 7); + + BitmapI1 dst(width, height); + int half = height / 2; + const uint8 *s = buf; + uint8 *d = dst.buf; + int y; + + // 上段は、右端が sticky な右シフト。 + for (y = 0; y <= half; y++) { + uint64 bits; + Load(bits, s); + bits = (bits >> 1) | (bits & 1); + Store(bits, d); + } + + // 下段は、シフトしないのでコピー。 + memcpy(d, s, stride * (height - y)); + + return dst; +} + +#undef Load +#undef Store + // // 8bpp ビットマップ @@ -418,18 +518,17 @@ BitmapRGBX::DrawBitmapI8Scale(const Rect } } -// (dx, dy) にビットマップ(RGBX) src を描画する。 +// (dx, dy) にビットマップ(RGBX) src の範囲 sr を描画する。 // 描画範囲をはみ出さないこと。 void -BitmapRGBX::DrawBitmap(int dx, int dy, const BitmapRGBX& src) +BitmapRGBX::DrawBitmap(int dx, int dy, const BitmapRGBX& src, const Rect& sr) { assert(buf); - const uint32 *s = (const uint32 *)src.GetBuf(); - - for (uint y = 0; y < src.GetHeight(); y++) { + for (uint y = 0; y < sr.h; y++) { uint32 *d = (uint32 *)GetPtr(dx, dy + y); - for (uint x = 0; x < src.GetWidth(); x++) { + const uint32 *s = (const uint32 *)src.GetPtr(sr.x, sr.y + y); + for (uint x = 0; x < sr.w; x++) { *d++ = *s++; } } @@ -768,6 +867,15 @@ BitmapRGBX::Mean(const RectF& sr) const return Color(sum_r, sum_g, sum_b); } +// (x, y) に点を描画する。 +// 描画範囲をはみ出さないこと。 +void +BitmapRGBX::DrawPoint(Color c, int x, int y) +{ + uint32 *d = (uint32 *)GetPtr(x, y); + *d = c.u32; +} + // 直線 (x1, y1) - (x2, y2) を描画する。終点は開区間。 // 描画範囲をはみ出さないこと。 void @@ -863,6 +971,49 @@ BitmapRGBX::DrawRect(Color c, const Rect DrawLineV(c, l, b, t); // 左辺↑ } +// 矩形 rect に内接する正円あるいは楕円を描画して中を塗りつぶす。 +// 描画範囲をはみ出さないこと。 +void +BitmapRGBX::DrawFillCircle(Color border, Color fill, const Rect& rect) +{ + int D = rect.h; // 高さを基準にした直径 + float r = D / 2; + float r2 = r * (r + 0.5); // 半径の二乗 + float prev_d = -1; + + // Y 方向を 1 px ずつステップしながら上下両側を対称に描画する。 + // 奇数個のときは真ん中を 2 回書くため、D&1 で補正。 + for (int i = 0, end = r + (D & 1); i < end; i++) { + // x^2 + y^2 = r^2 を解いて、楕円の係数を掛ける。 + float d = std::sqrt(r2 - r * r) * rect.w / rect.h; + r--; + + for (int j = 0; j < 2; j++) { + int y; + if (j == 0) { + y = rect.y + i; + } else { + y = rect.GetBottom() - i; + } + + int x1 = rect.x + rect.w / 2 - d; + int x2 = rect.x + rect.w / 2 + d; + + DrawLineH(fill, x1, y, x2); + + DrawPoint(border, x1, y); + DrawPoint(border, x2, y); + + int prev_x1 = rect.x + rect.w / 2 - prev_d; + int prev_x2 = rect.x + rect.w / 2 + prev_d; + DrawLineH(border, x1, y, prev_x1); + DrawLineH(border, x2, y, prev_x2); + } + + prev_d = d; + } +} + // 全域を RGB に変換。 void BitmapRGBX::ConvertToRGB(BitmapRGB& dst) const