LIBEUNOMIA
読み取り中…
検索中…
一致する文字列を見つけられません
ibuf_draw.h
[詳解]
1/*
2 * Copyright 2002-2021 oZ/acy (名賀月晃嗣)
3 * Redistribution and use in source and binary forms,
4 * with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27/*
28 * @file ibuf_draw.h
29 * @author oZ/acy
30 * @brief 畫像バッファクラステンプレートの描畫系のメンバ函數の實裝
31 *
32 * @date 2016.2.26 ellipse()内の不使用變數の宣言を削除
33 * @date 2021.4.22 LIBPOLYMNIAからLIBEUNOMIAに移植
34 * @date 2021.6.10 paintFill()内の不使用變數の宣言を削除
35 *
36 */
37/* This file is included by "imagebuffer.h". */
38#include <stack>
39#include <cstdlib>
40#include <algorithm>
41
42
43// バッファ全體を塗り潰す
44template<class C_>
46{
47 std::uint8_t* lp = buffer();
48 for (int j = 0; j < height(); ++j, lp += pitch())
49 std::fill_n(reinterpret_cast<C_*>(lp), width(), color);
50}
51
52
53/*==========================================================
54 * 直線を引く
55 * (Bresenham's Algorithm 參考: C MAGAZINE Dec. 2000)
56 */
57template<class C_>
58inline
59void
60eunomia::ImageBuffer<C_>::line(int x1, int y1, int x2, int y2, const C_& color)
61{
62 if ((x1 < 0 && x2 < 0) || (x1 >= w_ && x2 >= w_)
63 || (y1 < 0 && y2 < 0) || (y1 >= h_ && y2 >= h_))
64 return;
65
66 int dx, dy, sx, sy; // 差分と正負
67
68 dx = x2 - x1;
69 dy = y2 - y1;
70
71 if (dx < 0) {
72 sx = -1;
73 dx = -dx;
74 }
75 else if (dx == 0)
76 sx = 0;
77 else
78 sx = 1;
79
80 if (dy < 0) {
81 sy = -1;
82 dy = -dy;
83 }
84 else if (dy == 0)
85 sy = 0;
86 else
87 sy = 1;
88
89 // 描畫に伴ひ動かしてゆく變數
90 int xx1 = x1;
91 int xx2 = x2;
92 int yy1 = y1;
93 int yy2 = y2;
94
95 if (dy == 0) {
96 if (y1 >= 0 && y1 < h_) { // 要らない筈だがまあ……
97 int left = std::max(0, std::min(x1, x2));
98 int right = std::min(w_ - 1, std::max(x1, x2));
99 std::fill_n(lineBuffer(y1) + left, right - left + 1, color);
100 }
101 }
102 else if (dx == 0) {
103 if (x1 >= 0 && x1 < w_) { // 要らない筈だがまあ……
104 int top = std::max(0, std::min(y1, y2));
105 int bottom = std::min(h_ - 1, std::max(y1, y2));
106 std::uint8_t* bp = buf_ + top * pitch_ + x1 * sizeof(C_);
107 for (int j = top; j <= bottom; ++j, bp += pitch_)
108 *reinterpret_cast<C_*>(bp) = color;
109 }
110 }
111 else if (dx >= dy) {
112 int e = -dx;
113 int lx = (dx + 1) / 2;
114
115 std::uint8_t* bp = buf_ + y1 * pitch_ + x1 * sizeof(C_);
116 std::uint8_t* bq = buf_ + y2 * pitch_ + x2 * sizeof(C_);
117 int spx = sx * sizeof(C_);
118
119 for (int i = 0; i < lx; i++) {
120 if (xx1 >= 0 && xx1 < w_ && yy1 >= 0 && yy1 < h_)
121 *reinterpret_cast<C_*>(bp) = color;
122 if (xx2 >= 0 && xx2 < w_ && yy2 >= 0 && yy2 < h_)
123 *reinterpret_cast<C_*>(bq) = color;
124
125 bp += spx;
126 bq -= spx;
127
128 xx1 += sx;
129 xx2 -= sx;
130 e += 2 * dy;
131 if (e >= 0) {
132 if (sy > 0) {
133 bp += pitch_;
134 bq -= pitch_;
135 yy1++;
136 yy2--;
137 }
138 else if (sy < 0) {
139 bp -= pitch_;
140 bq += pitch_;
141 yy1--;
142 yy2++;
143 }
144
145 e -= 2 * dx;
146 }
147 }
148
149 if (!(dx % 2) && xx1 >= 0 && xx1 < w_ && yy1 >= 0 && yy1 < h_)
150 *reinterpret_cast<C_*>(bp) = color;
151 }
152 else {
153 int e = -dy;
154 int ly = (dy + 1) / 2;
155 std::uint8_t* bp = buf_ + y1 * pitch_ + x1 * sizeof(C_);
156 std::uint8_t* bq = buf_ + y2 * pitch_ + x2 * sizeof(C_);
157 int spx = sx * sizeof(C_);
158
159 for (int i = 0; i < ly; i++) {
160 if (xx1 >= 0 && xx1 < w_ && yy1 >= 0 && yy1 < h_)
161 *reinterpret_cast<C_*>(bp) = color;
162 if (xx2 >= 0 && xx2 < w_ && yy2 >= 0 && yy2 < h_)
163 *reinterpret_cast<C_*>(bq) = color;
164
165 if(sy > 0) {
166 bp += pitch_;
167 bq -= pitch_;
168 yy1++;
169 yy2--;
170 }
171 else if (sy < 0) {
172 bp -= pitch_;
173 bq += pitch_;
174 yy1--;
175 yy2++;
176 }
177
178 e += 2 * dx;
179 if (e >= 0) {
180 bp += spx;
181 bq -= spx;
182 xx1 += sx;
183 xx2 -= sx;
184 e -= 2 * dy;
185 }
186 }
187
188 if (!(dy % 2) && xx1 >= 0 && xx1 < w_ && yy1 >= 0 && yy1 < h_)
189 *reinterpret_cast<C_*>(bp) = color;
190 }
191}
193
194/*================================================
195 * 長方形を描く
196 */
197template<class C_>
198inline
199void
201 int left, int top, int right, int bottom, const C_& color, bool fill)
202{
203 // 座標の簡單化
204 if (left > right)
205 std::swap(left, right);
206 if (top > bottom)
207 std::swap(top, bottom);
208
209 // 範圍外なら何もしない
210 if (left >= w_ || right < 0 || top >= h_ || bottom < 0)
211 return;
212
213 // 範圍内に切りつめた値
214 int xx1 = std::max(left, 0);
215 int xx2 = std::min(right, w_ - 1);
216 int yy1 = std::max(top, 0);
217 int yy2 = std::min(bottom, h_ - 1);
218
219 if (fill) { // 塗り潰し
220 std::uint8_t* lp = buf_ + pitch_ * yy1;
221 for (int j = yy1; j <= yy2; ++j, lp += pitch_)
222 std::fill_n(
223 reinterpret_cast<C_*>(lp) + xx1, xx2 - xx1 + 1, color);
224 }
225 else {
226 // 上邊
227 if (top >= 0)
228 std::fill_n(lineBuffer(top) + xx1, xx2 - xx1 + 1, color);
229 // 下邊
230 if (bottom < h_)
231 std::fill_n(lineBuffer(bottom) + xx1, xx2 - xx1 + 1, color);
232
233 std::uint8_t* lr = buf_ + yy1 * pitch_;
234 for (int j = yy1; j <= yy2; ++j, lr += pitch_) {
235 // 左邊
236 if (left >= 0)
237 reinterpret_cast<C_*>(lr)[left] = color;
238 // 右邊
239 if (right < w_)
240 reinterpret_cast<C_*>(lr)[right] = color;
241 }
242 }
243}
244
245
246/*============================================
247 * 楕円の描畫
248 * (Michener's Algorithm 參考: C MAGAZINE Jan. 2001)
249 *
250 * 1 ' 2
251 * 3 4
252 * 5 6 <-- コメント中で用いた番號
253 * 7 8
254 */
255template<class C_>
256inline
257void
259 int x, int y, int a, int b, const C_& color, bool fill)
260{
261 if (a == 0 || b == 0)
262 return;
263
264 // 念の爲
265 a = std::abs(a);
266 b = std::abs(b);
267
268 int p = 0; // 半徑の短い方向の差分
269 int q; // 半徑の長い方向の差分
270 int e; // 判定用
271 if (a < b) {
272 e = 2 - 3 * b;
273 q = b;
274 }
275 else {
276 e = 2 - 3 * a;
277 q = a;
278 }
279
280 while (p <= q) {
281 // 實際に用ゐる中心座標との差分
282 int dx1, dy1, dx2, dy2;
283 // 半徑の短い方向の差分を「潰」す
284 if (a < b) {
285 // 1, 2, 7, 8
286 dx1 = p * a / b;
287 dy1 = q;
288
289 // 3, 4, 5, 6
290 dx2 = q * a / b;
291 dy2 = p;
292 }
293 else {
294 dx1 = p;
295 dy1 = q * b / a;
296
297 dx2 = q;
298 dy2 = p * b / a;
299 }
300
301 // 弧1, 2, 7, 8の處理
302 if (x - dx1 < w_ && x + dx1 >= 0 && y - dy1 < h_ && y + dy1 >= 0) {
303 // ↑まづは完全に畫像領域外でないことを確かめる
304
305 if (fill) {
306 int left = std::max(x - dx1, 0);
307 int right = std::min(x + dx1, w_ - 1);
308
309 if (y - dy1 >= 0) // 1<=>2
310 std::fill_n(lineBuffer(y - dy1) + left, right - left + 1, color);
311 if (y + dy1 < h_) // 7<=>8
312 std::fill_n(lineBuffer(y + dy1) + left, right - left + 1, color);
313 }
314 else {
315 if (y - dy1 >= 0) {
316 if (x - dx1 >= 0)
317 pixel(x - dx1, y - dy1) = color; // 1
318 if (x + dx1 < w_)
319 pixel(x + dx1, y - dy1) = color; // 2
320 }
321 if (y + dy1 < h_) {
322 if (x - dx1 >= 0)
323 pixel(x - dx1, y + dy1) = color; // 7
324 if (x + dx1 < w_)
325 pixel(x + dx1, y + dy1) = color; // 8
326 }
327 }
328 }
329
330 // 弧 3, 4, 5, 6の處理
331 if (x - dx2 < w_ && x + dx2 >= 0 && y - dy2 < h_ && y + dy2 >= 0) {
332 // ↑まづは完全に畫像領域外でないことを確かめる
333
334 if (fill) {
335 int left = std::max(x - dx2, 0);
336 int right = std::min(x + dx2, w_ - 1);
337
338 if (y - dy2 >= 0) // 3<=>4
339 std::fill_n(lineBuffer(y - dy2) + left, right - left + 1, color);
340 if (y + dy2 < h_) // 5<=>6
341 std::fill_n(lineBuffer(y + dy2) + left, right - left + 1, color);
342 }
343 else {
344 if (y - dy2 >= 0) {
345 if (x - dx2 >= 0)
346 pixel(x - dx2, y - dy2) = color; // 3
347 if (x + dx2 < w_)
348 pixel(x + dx2, y - dy2) = color; // 4
349 }
350 if (y + dy2 < h_) {
351 if (x - dx2 >= 0)
352 pixel(x - dx2, y + dy2) = color; // 5
353 if (x + dx1 < w_)
354 pixel(x + dx2, y + dy2) = color; // 6
355 }
356 }
357 }
358
359 // 次に進む
360 if (e < 0)
361 e += p * 4 + 6;
362 else {
363 e += (p - q) * 4 + 10;
364 q--;
365 }
366 p++;
367 }// while
368}
369
370
371/*================================================
372 * 所謂塗り潰し
373 */
374template<class C_>
375inline void eunomia::ImageBuffer<C_>::paintFill(int x, int y, const C_& color)
376{
377 if (x < 0 || y < 0 || x >= w_ || y >= h_)
378 return;
379
380 C_ fromcolor = pixel(x, y);
381 if (color == fromcolor)
382 return;
383
384 std::stack<Point> pstack;
385 pstack.push(Point(x, y));
386
387 while (!pstack.empty()) {
388 Point p = pstack.top();
389 pstack.pop();
390
391 int xx = p.x;
392 int yy = p.y;
393
394 // 上への進行を打診
395 bool ful, fur; // 左上、右上方向の連續性の有無の確認用
396 if (yy > 0 && pixel(xx, yy - 1) == fromcolor) {
397 pstack.push(Point(xx, yy - 1));
398 ful = true;
399 fur = true;
400 } else {
401 ful = false;
402 fur = false;
403 }
404
405 // 下への進行を打診
406 bool fdl, fdr; // 左下、右下方向の連續性の有無の確認用
407 if (yy < h_ - 1 && pixel(xx, yy + 1) == fromcolor) {
408 pstack.push(Point(xx, yy + 1));
409 fdl = true;
410 fdr = true;
411 }
412 else {
413 fdl = false;
414 fdr = false;
415 }
416
417 // 現在の地點を塗る
418 pixel(xx, yy) = color;
419
420 C_* lb = lineBuffer(yy);
421 C_* lbu = lineBuffer(yy - 1);
422 C_* lbd = lineBuffer(yy + 1);
423
424 // 左に進む
425 for (int l = xx - 1; l >= 0 && lb[l] == fromcolor; --l) {
426 // 左上側の處理
427 if (yy > 0) {
428 if (ful && lbu[l] != fromcolor)
429 ful = false;
430 else if (!ful && lbu[l] == fromcolor) {
431 ful = true;
432 pstack.push(Point(l, yy - 1));
433 }
434 }
435
436 if (yy + 1 < h_) {
437 if (fdl && lbd[l] != fromcolor)
438 fdl = false;
439 else if (!fdl && lbd[l] == fromcolor) {
440 fdl = true;
441 pstack.push(Point(l, yy + 1));
442 }
443 }
444
445 lb[l] = color;
446 }
447
448 // 右に進む
449 for (int r = xx + 1; r < w_ && lb[r] == fromcolor; ++r) {
450 // 右上の處理
451 if (yy > 0) {
452 if (fur && lbu[r] != fromcolor)
453 fur = false;
454 else if (!fur && lbu[r] == fromcolor) {
455 fur = true;
456 pstack.push(Point(r, yy - 1));
457 }
458 }
459
460 if (yy + 1 < h_) {
461 if (fdr && lbd[r] != fromcolor)
462 fdr = false;
463 else if (!fdr && lbd[r] == fromcolor) {
464 fdr = true;
465 pstack.push(Point(r, yy + 1));
466 }
467 }
468
469 lb[r] = color;
470 }
471 }
472}
473
474
475
476
477//eof
畫像バッファ基底クラステンプレート
Definition imagebuffer.h:84
void paintFill(int x, int y, const C_ &color)
塗り潰し
Definition ibuf_draw.h:375
void clear(const C_ &color)
バッファ全體の塗り潰し
Definition ibuf_draw.h:45
int width() const noexcept
Definition imagebuffer.h:114
ImageBuffer(int w, int h, int p) noexcept
構築子
Definition imagebuffer.h:101
int pitch() const noexcept
ピッチ
Definition imagebuffer.h:118
void line(int x1, int y1, int x2, int y2, const C_ &color)
線分の描畫
Definition ibuf_draw.h:60
uint8_t * buffer() noexcept
バッファの先頭アドレスの取得
Definition imagebuffer.h:121
void ellipse(int x, int y, int a, int b, const C_ &color, bool fill=false)
楕圓の描畫
Definition ibuf_draw.h:258
int height() const noexcept
高さ
Definition imagebuffer.h:116
void box(int left, int top, int right, int bottom, const C_ &color, bool fill=false)
長方形の描畫
Definition ibuf_draw.h:200
Definition imagebuffer.h:58