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