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