XORPAINT.C
[目次 | 関数]
1|/**************************************************************************
2|* 1. <<< 塗りつぶし (XorPaint) >>>
3|*
4|*・even-odd method による高速塗りつぶしの処理をします。
5|* ただし、ここでは XOR アルゴリズムと呼ぶことにします。
6|*
7|*
8|*【解説】XOR paint アルゴリズム
9|*
10|*
11|*
12|* 図のように上のビットと下のビットを XOR 演算することで、even-odd 法のような
13|* 塗りつぶしが高速に出来る。
14|* この場合、塗りつぶす領域は右図のように上下の境界線のみに指定しないと、
15|* 左右がギザギザになってしまう。画面全体を囲んだ場合、左端と下端は塗られない。
16|* 左端は、後で示す x 値の小さい端点を描かないこと、下端は、右の最終ラインが
17|* キャンセルされてしまうことより。
18|*
19|* 境界線の交点は、描かないようにする。描いてしまうと、滝が落ちるように塗ら
20|* れてしまう。 XOR 描画するとよい。
21|*
22|*
23|* 鋭角による点の重なりも、交点と同様に描かないようにする。
24|*
25|*
26|* 頂点は、y 軸と平行な線と交差する場合に描く。
27|* そのために、線分を書く場合に工夫が要る。 x 座標が小さい方の点は描かず、
28|* x 座標が大きい方の点を描く。
29|*
30|*
31|* クリッピングを考慮するなら、次の点に注意する。
32|* ・上下端に境界線を描く
33|* ・クリップ領域の底辺は XOR PAINT で消えてしまうので、
34|* 領域は 1ピクセル分増やす
35|*
36|*
37|* 2. <<< バグ情報 >>>
38|*・画面の最も下のラインが塗りつぶされません。
39|* (クリッピング領域の最も下のラインは塗りつぶされます。)
40|***************************************************************************/
41|
42|#include <all.h>
43|
44|#ifndef USES_DRAW
45|#error
46|#endif
47|#include "draw.h"
48|
49|/*******************************************************************
50|* 3. <<< 初期化する [XorPaint_init()] >>>
51|*【補足】
52|*・buf_sizeof は、width * height * 5/2 です。
53|*・paintPattern の指定は、Mask_A_initBy1bpp_x2 関数などを用います。
54|*・この関数が呼ばれた後に、XorPaint_clear 関数を呼び出します。
55|********************************************************************/
56|void XorPaint_init( XorPaint* m, char* buf, size_t buf_sizeof,
57| int width, int height, Mask_A* paintPattern )
58|{
59| #ifdef _CHECKER
60| if ( buf_sizeof != (size_t)width * height * 5 / 2 ) error();
61| #endif
62|
63| Screen_init( &m->paintPlaneX, buf + width*height*2, width, height );
64| DScreen_init( &m->boundPlaneX, buf + width*height, width, height );
65| DScreen_init( &m->linePlaneX, buf, width, height );
66|
67| Draw_init( &m->paintPlane, Screen_inf_DrawScr( &m->paintPlaneX ) );
68| Draw_init( &m->boundPlane, DScreen_inf_DrawScr( &m->boundPlaneX ) );
69| Draw_init( &m->linePlane, DScreen_inf_DrawScr( &m->linePlaneX ) );
70|
71| m->bLine = true;
72| m->paintPattern = paintPattern;
73| m->bNoBound = true;
74|}
75|
76|
77|/********************************************************************
78|* 4. <<< 境界線を全く描かないものとして初期化する [XorPaint_init2()] >>>
79|*【補足】
80|*・buf_sizeof は、width * height * 3/2 です。(メモリ消費量が少ない)
81|*・paintPattern の指定は、Mask_A_initBy1bpp_x2 関数などを用います。
82|*・この関数が呼ばれた後に、XorPaint_clear 関数を呼び出します。
83|********************************************************************/
84|void XorPaint_init2( XorPaint* m, char* buf, size_t buf_sizeof,
85| int width, int height, Mask_A* paintPattern )
86|{
87| #ifdef _CHECKER
88| if ( buf_sizeof != (size_t)width * height * 3 / 2 ) error();
89| #endif
90|
91| Screen_init( &m->paintPlaneX, buf + width*height, width, height );
92| DScreen_init( &m->boundPlaneX, buf, width, height );
93|
94| Draw_init( &m->paintPlane, Screen_inf_DrawScr( &m->paintPlaneX ) );
95| Draw_init( &m->boundPlane, DScreen_inf_DrawScr( &m->boundPlaneX ) );
96|
97| m->bLine = false;
98| m->paintPattern = paintPattern;
99| m->bNoBound = true;
100|}
101|
102|
103|/********************************************************************
104|* 5. <<< すべてのプレーンを初期化する [XorPaint_clear()] >>>
105|*【補足】
106|*・必要な部分だけ初期化して、m->bNoBound を true に戻します。
107|********************************************************************/
108|void XorPaint_clear( XorPaint* m )
109|{
110| /* プレーン全体を初期化する */
111| if ( m->bNoBound ) {
112| Screen_clear( &m->paintPlaneX, 0 );
113| DScreen_trueClear( &m->boundPlaneX );
114| if ( m->bLine )
115| DScreen_trueClear( &m->linePlaneX );
116| }
117| /* 領域の座標範囲だけ初期化する */
118| else {
119| int w = Screen_getWidth( &m->paintPlaneX );
120| int h = Screen_getHeight( &m->paintPlaneX );
121|
122| if ( m->minX < 0 ) m->minX = 0;
123| if ( m->maxX >= w ) m->maxX = w-1;
124| if ( m->minY < 0 ) m->minY = 0;
125| if ( m->maxY >= h ) m->maxY = h-1;
126|
127| if ( m->minX < m->maxX && m->minY < m->maxY ) {
128| Screen_rectFill2(
129| Screen_by_DrawScr( m->paintPlane.drawScr ),
130| m->minX, m->minY, m->maxX, m->maxY, 0 );
131| DScreen_rectFillClear2(
132| DScreen_by_DrawScr( m->boundPlane.drawScr ),
133| m->minX, m->minY, m->maxX, m->maxY );
134| if ( m->bLine ) {
135| DScreen_rectFillClear2(
136| DScreen_by_DrawScr( m->linePlane.drawScr ),
137| m->minX, m->minY, m->maxX, m->maxY );
138| }
139| }
140| m->bNoBound = true;
141| }
142|}
143|
144|
145|/********************************************************************
146|* 6. <<< 領域を塗りつぶして、その結果を target に描く [XorPaint_flushTo()] >>>
147|*【引数】
148|* ・int x,y; target のオフセット
149|*【補足】
150|*・プレーンを x,y だけずらした座標に描きます。
151|*・XorPaint_drawLine などの関数で閉領域にしてから呼び出すこと。
152|*・連続してこの関数を呼び出すことは出来ません。
153|* 一度 XorPaint_clear 関数でクリアしたら出来ます。
154|*【内部補足】
155|*・1. Screen_xorPaint は、境界があいまいに塗りつぶされるため、
156|* boundPlane と合成することで境界を正確にします。
157|********************************************************************/
158|void XorPaint_flushTo( XorPaint* m, DrawScr target, int x, int y )
159|{
160| Screen* paintPlane = Screen_by_DrawScr( m->paintPlane.drawScr );
161|
162|
163|#if 1
164| /* paintPlane を塗りつぶして、boundPlane と合成する(内部補足1) */
165| Screen_xorPaint( paintPlane );
166| /*Screen_flushFromDScreen( paintPlane, &m->boundPlaneX );*/
167| Screen_flushFromDScreen2( paintPlane, &m->boundPlaneX,NULL,0,0 );
168|
169| /* paintPlane に模様をかけて、target に描く */
170|#if 1
171| DrawScr_flushFromScreen2( target, paintPlane, m->paintPattern, x,y );
172|#endif
173|#if 0
174| DScreen_setClip( &m->boundPlaneX, m->minX, m->minY,
175| m->maxX - m->minX + 1, m->maxY - m->minY + 1 );
176| Screen_flushFromPartDScreen( Screen_by_DrawScr( target ), &m->boundPlaneX,
177| m->paintPattern, x, y );
178| DScreen_clearClip( &m->boundPlaneX );
179|#endif
180|
181| /* 境界線を target に描く */
182| if ( m->bLine ) {
183| DrawScr_flushFromDScreen2( target,
184| DScreen_by_DrawScr( m->linePlane.drawScr ),
185| NULL, x, y );
186| }
187|#endif
188|#if 0
189| Screen* targetS = Screen_by_DrawScr( target );
190|
191| /* 塗る領域を模様で描く */
192| Screen_xorPartPaintFlushToScreen( paintPlane, targetS,
193| &XorPaint_paintMask, dx + m->minX, dy + m->minY, 0,
194| m->minX, m->minY, m->maxX, m->maxY );
195|
196| /* 塗る領域の境界を模様で描く */
197| Screen_flushFromPartDScreen( targetS,
198| DScreen_by_DrawScr( m->boundPlane.drawScr ),
199| &XorPaint_paintMask, m->minX, m->minY, m->maxX, m->maxY,
200| dx + m->minX, dy + m->minY );
201|
202| /* 境界線を描く */
203| if ( m->bLine ) {
204| Screen_flushFromPartDScreen( targetS,
205| DScreen_by_DrawScr( m->linePlane.drawScr ),
206| &XorPaint_colorMask, m->minX, m->minY, m->maxX, m->maxY,
207| dx + m->minX, dy + m->minY );
208| }
209|#endif
210|}
211|
212|
213|/********************************************************************
214|* 7. <<< 領域の境界を設定する [XorPaint_setBound()] >>>
215|********************************************************************/
216|void XorPaint_setBound( XorPaint* m, int x1, int y1, int x2, int y2 )
217|{
218| /* 領域の境界を仮描画する */
219| Draw_line( &m->boundPlane, x1, y1, x2, y2, 0xF );
220| Draw_lineForXorPaint( &m->paintPlane, x1, y1, x2, y2, 0xF );
221|
222| /* 領域の座標範囲を合わせる */
223| XorPaint_setRange( m, x1, y1 );
224| XorPaint_setRange( m, x2, y2 );
225|}
226|
227|
228|/********************************************************************
229|* 8. <<< 境界線を設定して描画する [XorPaint_drawLine()] >>>
230|********************************************************************/
231|void XorPaint_drawLine( XorPaint* m, int x1, int y1, int x2, int y2,
232| int color )
233|{
234| #ifdef _CHECKER
235| if ( ! m->bLine ) error();
236| #endif
237|
238| XorPaint_setBound( m, x1, y1, x2, y2 );
239| Draw_line( &m->linePlane, x1, y1, x2, y2, color );
240|}
241|
242|
243|#ifdef USES_SSTACK
244|
245|/********************************************************************
246|* 9. <<< 領域の境界をベジェ曲線で設定する [XorPaint_setBezierBound()] >>>
247|********************************************************************/
248|void XorPaint_setBezierBound( XorPaint* m, int x1, int y1, int x2, int y2,
249| int x3, int y3, int x4, int y4 )
250|{
251| /* 領域の境界を仮描画する */
252| Draw_bezier( &m->boundPlane, x1, y1, x2, y2, x3, y3, x4, y4, 0xF );
253| Draw_bezierForXorPaint( &m->paintPlane,
254| x1, y1, x2, y2, x3, y3, x4, y4, 0xF );
255|
256| /* 領域の座標範囲を合わせる */
257| XorPaint_setRange( m, x1, y1 );
258| XorPaint_setRange( m, x2, y2 );
259| XorPaint_setRange( m, x3, y3 );
260| XorPaint_setRange( m, x4, y4 );
261|}
262|
263|#endif /* USES_SSTACK */
264|
265|
266|#ifdef USES_SSTACK
267|
268|/********************************************************************
269|* 10. <<< ベジェ曲線の境界線を設定して描画する [XorPaint_drawBezierLine()] >>>
270|********************************************************************/
271|void XorPaint_drawBezierLine( XorPaint* m, int x1, int y1, int x2, int y2,
272| int x3, int y3, int x4, int y4, int color )
273|{
274| #ifdef _CHECKER
275| if ( ! m->bLine ) error();
276| #endif
277|
278| XorPaint_setBezierBound( m, x1, y1, x2, y2, x3, y3, x4, y4 );
279| Draw_bezier( &m->linePlane, x1, y1, x2, y2, x3, y3, x4, y4, color );
280|}
281|
282|#endif /* USES_SSTACK */
283|
284|
285|
286|/********************************************************************
287|* 11. <<< 領域の座標範囲を合わせる [XorPaint_setRange()] >>>
288|*【補足】
289|*・頂点座標 x,y を指定して、もし、領域の座標範囲(m->minX など)から
290|* はみ出るなら、修正します。
291|********************************************************************/
292|void XorPaint_setRange( XorPaint* m, int x, int y )
293|{
294| #ifdef _CHECKER
295| if ( sizeof(UINT32) / Screen_getPixelPerByte(
296| Screen_by_DrawScr( m->paintPlane.drawScr ) ) != 2 ) error();
297| #endif
298|
299| if ( m->bNoBound ) {
300| m->minX = ( x & 0xFFF8 );
301| m->maxX = ( x & 0xFFF8 ) + 0x7;
302| m->minY = y;
303| m->maxY = y;
304| m->bNoBound = 0;
305| }
306| else {
307| if ( x < m->minX ) m->minX = ( x & 0xFFF8 );
308| if ( x > m->maxX ) m->maxX = ( x & 0xFFF8 ) + 0x7;
309| if ( y < m->minY ) m->minY = y;
310| if ( y > m->maxY ) m->maxY = y;
311| }
312|}
313|
314|