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|