グラデーションな図形

 投稿者:山中和義  投稿日:2009年 5月14日(木)11時03分26秒
  グラデーション図形を描くルーチンをつくってみました。 実は以前つくったものの抜粋ですが、、、

●サンプル1
DIM x(0 TO 20),y(0 TO 20),r(0 TO 20),g(0 TO 20),b(0 TO 20) !頂点の位置と色

SET WINDOW -10,10,-10,10 !表示領域

DATA 1,0,0 !色RGB
DATA 1,1,0
DATA 0,1,0
DATA 0,1,1
DATA 0,0,1
DATA 1,0,1
DATA 1,0,0

CALL PLOT.Init !※


LET x(0)=0 !始点(0,0)、終点(3,0)
LET x(1)=3
LET y(0)=0
LET y(1)=0
PICTURE L1 !横線
   CALL PLOT.LINES(x,y,r,g,b) !※
END PICTURE

READ r(0),g(0),b(0) !始点の色

FOR i=1 TO 6
   READ r(1),g(1),b(1) !終点の色

   DRAW BAR WITH SHIFT(i*3-12,0)

   LET r(0)=r(1) !次へ
   LET g(0)=g(1)
   LET b(0)=b(1)
NEXT i

PICTURE BAR !棒状
   FOR j=8 TO -8 STEP -0.05
      DRAW L1 WITH SHIFT(0,j)
   NEXT j
END PICTURE

END




●サンプル2
DIM x(0 TO 20),y(0 TO 20),r(0 TO 20),g(0 TO 20),b(0 TO 20) !頂点の位置と色

SET WINDOW -10,10,-10,10 !表示領域

DATA 1,0,0 !色RGB
DATA 1,1,0
DATA 0,1,0
DATA 0,1,1
DATA 0,0,1
DATA 1,0,1
DATA 1,0,0

CALL PLOT.Init !※

LET  x(0)=0 !1点目の位置(中央)
LET  y(0)=0

LET  r(0)=0.2 !頂点の色
LET  g(0)=0.2
LET  b(0)=0.2

LET  x(1)=9*COS(0) !2点目
LET  y(1)=9*SIN(0)
READ r(1),g(1),b(1)

FOR i=1 TO 6 !六角形 ※三角形が6つ
   LET  x(2)=9*COS(i*PI/3) !3点目
   LET  y(2)=9*SIN(i*PI/3)
   READ r(2),g(2),b(2)

   CALL PLOT.AREALIMIT(3, x,y, r,g,b) !※

   LET  x(1)=x(2) !次へ
   LET  y(1)=y(2)

   LET  r(1)=r(2)
   LET  g(1)=g(2)
   LET  b(1)=b(2)
NEXT i

END


つづく
 

Re: グラデーションな図形

 投稿者:山中和義  投稿日:2009年 5月14日(木)11時04分36秒
  > No.376[元記事へ]

つづき

以下のプログラムを、それぞれのサンプルのEND文以降につなげてください。

MODULE PLOT !各頂点の色をもとに線分と凸多角形にグラデーションをかける

SET POINT STYLE 1 !マークの形状

SHARE NUMERIC Xmin(0 TO 1024),Xmax(0 TO 1024) !y座標(y行)におけるx座標の最小値、最大値 ※要調整
SHARE NUMERIC Rmin(0 TO 1024),Rmax(0 TO 1024)
SHARE NUMERIC Gmin(0 TO 1024),Gmax(0 TO 1024)
SHARE NUMERIC Bmin(0 TO 1024),Bmax(0 TO 1024)

SHARE NUMERIC ww,hh !スクリーンの位置、大きさ

EXTERNAL SUB Init !レンダリングターゲットを初期化する
   SET COLOR mode "NATIVE" !RGB指定
   SET TEXT font "",12 !文字サイズ
   ASK WINDOW x1,x2,y1,y2 !座標系の端の座標を取得する
   ASK PIXEL SIZE (x1,y1; x2,y2) ww,hh !画面の大きさ(ピクセル単位)を調べる
END SUB

EXTERNAL SUB SetPixel(x,y,c) !座標(x,y,z)に色(r,g,b)で点を描く ※PLOT POINTS: x,y と同じ
   SET POINT COLOR c
   PLOT POINTS: WORLDX(x), WORLDX(y) !問題座標に戻して描く
   !!!PLOT POINTS: x * (x2 - x1) / ww + x1, y * (y2 - y1) / hh + y1 !問題座標に戻して描く
END SUB


PUBLIC SUB POINTS !※PLOT POINTS: x,y と同じ
EXTERNAL SUB POINTS(xx,yy,rr,gg,bb) !線分を描画する
   LET  x1 = PIXELX(xx)
   LET  y1 = PIXELY(yy)

   IF (y1 >= 0) AND (y1 < hh) THEN !画面内なら
      IF (x1 >= 0) AND (x1 < ww) THEN
         CALL SetPixel(INT(x1),INT(y1), colorindex(rr,gg,bb))
      END IF
   END IF
END SUB

PUBLIC SUB LINES !※PLOT LINES: x0,y0; x1,y1 または MAT PLOT LINES,LIMIT 2: x,y と同じ
EXTERNAL SUB LINES(xx(),yy(),rr(),gg(),bb()) !線分を描画する
   LET  x1 = PIXELX(xx(0))
   LET  y1 = PIXELY(yy(0))

   LET  x2 = PIXELX(xx(1))
   LET  y2 = PIXELY(yy(1))

   LET  r1 = rr(0) !初期値を設定する
   LET  g1 = gg(0)
   LET  b1 = bb(0)

   SET DRAW mode hidden !ちらつき防止(開始)

   IF (x1 = x2) AND (y1 = y2) THEN !始点と終点が同じなら
      IF (y1 >= 0) AND (y1 < hh) THEN !画面内なら
         IF (x1 >= 0) AND (x1 < ww) THEN
            CALL SetPixel(INT(x1),INT(y1), colorindex(r1,g1,b1))
         END IF
      END IF
   ELSE
      LET  dx = x2 - x1 !相対的長さ
      LET  dy = y2 - y1

      IF ABS(dy) < ABS(dx) THEN !xの方が増分が多い
      !□□□■
      !□■■□  y=l*x+mの式として考える
      !■□□□
         LET  l = dy / dx !傾きを求める
         LET  dr = (rr(1) - rr(0)) / dx
         LET  dg = (gg(1) - gg(0)) / dx
         LET  db = (bb(1) - bb(0)) / dx
         FOR i=0 TO dx STEP SGN(dx)
            LET  x = x1 + i
            LET  y = l * i + y1
            LET  r = dr * i + r1
            LET  g = dg * i + g1
            LET  b = db * i + b1
            IF (y >= 0) AND (y < hh) THEN !画面内なら
               IF (x >= 0) AND (x < ww) THEN
                  CALL SetPixel(INT(x),INT(y), colorindex(r,g,b))
               END IF
            END IF
         NEXT i
      ELSE !yの方が増分が多い
      !□□■
      !□■□  x=l*y+mの式として考える
      !□■□
      !■□□
         LET  l = dx / dy !傾きを求める
         LET  dr = (rr(1) - rr(0)) / dy
         LET  dg = (gg(1) - gg(0)) / dy
         LET  db = (bb(1) - bb(0)) / dy
         FOR i=0 TO dy STEP SGN(dy)
            LET  x = l * i + x1
            LET  y = y1 + i
            LET  r = dr * i + r1
            LET  g = dg * i + g1
            LET  b = db * i + b1
            IF (y >= 0) AND (y < hh) THEN !画面内なら
               IF (x >= 0) AND (x < ww) THEN
                  CALL SetPixel(INT(x),INT(y), colorindex(r,g,b))
               END IF
            END IF
         NEXT i
      END IF
   END IF

   SET DRAW mode explicit !ちらつき防止(終了)
END SUB

PUBLIC SUB AREALIMIT !!※MAT PLOT AREA,LIMIT n: x,y と同じ
EXTERNAL SUB AREALIMIT(NumOfVtx, xx(),yy(),rr(),gg(),bb()) !凸多角形(頂点番号による面の定義)を描画する
   IF NumOfVtx < 3 THEN EXIT SUB

   DIM sx(0 TO NumOfVtx-1),sy(0 TO NumOfVtx-1)
   FOR i=0 TO NumOfVtx-1 !問題座標からピクセル座標に変換する
      LET  sx(i) = PIXELX(xx(i))
      LET  sy(i) = PIXELY(yy(i))
      !!!LET  sx(i) = (xx(i) - x1) * ww / (x2 - x1)
      !!!LET  sy(i) = (yy(i) - y1) * hh / (y2 - y1)
   NEXT i

   LET  top = +2147483647 !バッファの使用範囲を設定する
   LET  btm = -2147483648
   FOR i=0 TO NumOfVtx-1
      IF top > sy(i) THEN LET  top = sy(i)
      IF btm < sy(i) THEN LET  btm = sy(i)
   NEXT i
   LET  top = INT(top)
   LET  btm = INT(btm)
   IF top < 0 THEN LET  top = 0
   IF btm > hh THEN LET  btm = hh

   FOR i=top TO btm-1 !最大最小バッファを初期化する
      LET  Xmin(i) = +2147483647
      LET  Xmax(i) = -2147483648
   NEXT i

   FOR i=0 TO NumOfVtx-2 !稜線の数だけ
      CALL ScanEdge(i,i+1, sx,sy,rr,gg,bb) !稜線が描く各点を求める
   NEXT i
   CALL ScanEdge(NumOfVtx-1,0, sx,sy,rr,gg,bb)

   SET DRAW mode hidden !ちらつき防止(開始)

   FOR y=top TO btm-1 !各ライン(y座標)ごとに走査する - ラスタライズ

      LET  l = (Xmax(y) - Xmin(y)) + 1 !増分値を計算する
      LET  dr = (Rmax(y) - Rmin(y)) / l
      LET  dg = (Gmax(y) - Gmin(y)) / l
      LET  db = (Bmax(y) - Bmin(y)) / l

      LET  r = Rmin(y) !初期値を設定する
      LET  g = Gmin(y)
      LET  b = Bmin(y)

      FOR x=Xmin(y) TO Xmax(y) !ライン上での直線を描く ※PLOT LINES: Xmin(y),y; Xmax(y),y
         IF (x >= 0) AND (x < ww) THEN !画面内なら
            CALL SetPixel(x,y,colorindex(r,g,b)) !問題座標に戻して描く
         END IF
         LET  r = r + dr !次へ
         LET  g = g + dg
         LET  b = b + db
      NEXT x

   NEXT y

   SET DRAW mode explicit !ちらつき防止(終了)
END SUB

EXTERNAL SUB ScanEdge(v1,v2, xx(),yy(),rr(),gg(),bb()) !頂点v1と頂点v2を結ぶ稜線(辺)が描く各点を求める
   LET  l = ABS(INT(yy(v2) - yy(v1))) + 1 !幅を計算する

   LET  dx = (xx(v2) - xx(v1)) / l !増分値を計算する
   LET  dy = (yy(v2) - yy(v1)) / l
   LET  dr = (rr(v2) - rr(v1)) / l
   LET  dg = (gg(v2) - gg(v1)) / l
   LET  db = (bb(v2) - bb(v1)) / l

   LET  x = xx(v1) !初期値を設定する
   LET  y = yy(v1)
   LET  r = rr(v1)
   LET  g = gg(v1)
   LET  b = bb(v1)

   FOR i=0 TO l-1 !各ライン(y座標)ごとに
      LET  px = INT(x)
      LET  py = INT(y)

      IF (py >= 0) AND (py < hh) THEN !画面内なら
         IF Xmin(py) > px THEN !左端位置を記録する
            LET  Xmin(py) = px
            LET  Rmin(py) = r
            LET  Gmin(py) = g
            LET  Bmin(py) = b
         END IF

         IF Xmax(py) < px THEN !右端位置を記録する
            LET  Xmax(py) = px
            LET  Rmax(py) = r
            LET  Gmax(py) = g
            LET  Bmax(py) = b
         END IF
      END IF
      LET  x = x + dx !次へ
      LET  y = y + dy
      LET  r = r + dr
      LET  g = g + dg
      LET  b = b + db
   NEXT i

END SUB

END MODULE
 

戻る