Kuin Advent Calendar 2016 - 17日目

この記事は【Kuin Advent Calendar 2016】の17日目の記事です。

←前の日の記事   →次の日の記事

【記事中で紹介しているコードについて】
コンパイルが通らない場合など、不具合があれば、@tatt61880まで連絡いただけると助かります。よろしくお願いいたします。


ドラゴン曲線を表示するKuinのコードです。
※出力画像はdepthを10にしたときのものです。処理が少し重いです。リリースコンパイル推奨。
[Image:dragon_curve.kn.png]
dragon_curve.kn
func main()
	var depth: int :: 8
	var size: int :: (1b64).shl(depth) $ int
	do @drawDragon(size, depth * 2)
end func

const ww: int :: 512
var wh: int
var h: int

func drawDragon(leng: int, depth: int)
	var d: int :: leng / 3 + 1
	do @h :: leng + 3
	do @w :: leng + d * 3 / 2 + 2
	do @wh :: @ww * @h / @w
	do @buf :: #[@h * @w]@Rgb
	for i(0, ^@buf - 1)
		do @buf[i] :: #@Rgb
	end for

	do @x :: d
	do @y :: d
	do @dx :: leng
	do @dy :: 0
	do @scale :: 1
	do @clen :: 0

	for(1, depth)
		do @dy :: @dx + @dy
		do @dx :: 2 * @dx - @dy
		do @scale :* 2
		do @x :* 2
		do @y :* 2
	end for
	do @iter_string("FX", depth)

	var maxv: float :: 0.0
	for i(0, ^@buf - 1)
		var b: @Rgb :: @buf[i]
		for j(0, ^[b.r, b.g, b.b] - 1)
			var c: float :: [b.r, b.g, b.b][j]
			if(c > maxv)
				do maxv :: c
			end if
		end for
	end for
	var rate: float :: 255.0 / maxv
	for i(0, ^@buf - 1)
		do @buf[i].r :* rate
		do @buf[i].g :* rate
		do @buf[i].b :* rate
	end for

	if(true)
		{ 画面に出力する場合はこちら。 }
		var wndMain: wnd@Wnd :: wnd@makeWnd(null, %aspect, @ww, @wh, "Dragon curve")
		var drawMain: wnd@Draw :: wnd@makeDraw(wndMain, 0, 0, @ww, @wh, %scale, %scale, false)
		do drawMain.onPaint :: onPaint
		func onPaint(wnd: wnd@WndBase, width: int, height: int)
			var pixSize: float :: @ww $ float / @w $ float
			for i(0, @h * @w - 1)
				do draw@rect(pixSize * (i % @w) $ float, pixSize * (i / @w) $ float, pixSize, pixSize,
				| @buf[i].r $bit8 $int * 0x10000
				| +@buf[i].g $bit8 $int * 0x100
				| +@buf[i].b $bit8 $int
				| +0xFF000000)
			end for
			do draw@render(0)
		end func

		while(wnd@act())
		end while
	else
		{ ファイルに出力する場合はこちら。PNM形式(P6)で保存します。 }
		var fs: file@Writer :: file@makeWriter("dragon_curve.pnm", false)
		do fs.writeStr("P6\n\{@w} \{@h}\n255\n")
		var fpix: []bit8 :: #[@h * @w * 3]bit8
		for i(0, @h * @w - 1)
			do fpix[3 * i    ] :: @buf[i].r $ bit8
			do fpix[3 * i + 1] :: @buf[i].g $ bit8
			do fpix[3 * i + 2] :: @buf[i].b $ bit8
		end for
		do fs.write(fpix)
	end if
end func

var x: int
var y: int
var w: int
var dx: int
var dy: int
var scale: int
var clen: int

class Rgb()
	+var r: float
	+var g: float
	+var b: float
end class

var buf: []@Rgb
 
func h_rgb(x: int, y: int)
	var VAL: float :: 1.0 - (lib@cos(lib@pi * 64.0 * @clen $ float / @scale $ float) - 1.0) / 4.0
	const SAT: float :: 1.0
	var h: float :: 6.0 * @clen $ float / @scale $ float
	var c: float :: VAL * SAT
	var X: float :: -c * (h % 2.0).abs()
 
	var p: @Rgb :: @buf[y * @w + x]
	switch(h $ int % 6)
	case 0
		do p.r :+ c
		do p.g :+ X
	case 1
		do p.r :+ X
		do p.g :+ c
	case 2
		do p.g :+ c
		do p.b :+ X
	case 3
		do p.g :+ X
		do p.b :+ c
	case 4
		do p.b :+ c
		do p.r :+ X
	case 5
		do p.b :+ X
		do p.r :+ c
	default
	end switch
end func
 
func iter_string(str: []char, d: int)
	for i(0, ^str - 1)
		var c: char :: str[i]
		switch(c)
		case 'X'
			if(d <> 0)
				do @iter_string("X+YF+", d - 1)
			end if
		case 'Y'
			if(d <> 0)
				do @iter_string("-FX-Y", d - 1)
			end if
		case '+'
			do @dx :$ @dy
			do @dy :: -@dy
		case '-'
			do @dx :$ @dy
			do @dx :: -@dx
		case 'F'
			do @clen :+ 1
			do @h_rgb(@x / @scale, @y / @scale)
			do @x :+ @dx
			do @y :+ @dy
		default
			assert false
		end switch
	end for
end func


←前の日の記事   →次の日の記事