|
|
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.