#!/usr/bin/env ascript

classref(`image).rgbread(stream:stream) = {
	ImageHeader = struct(imagic:number, type:number, dim:number,
						width:number, height:number, nElems:number)
	buff = stream.read()
	hdr = ImageHeader * buff.unpack(">HHHHHH")
	self.allocbuff(hdr.width, hdr.height)
	p = buff.pointer(512)
	n = hdr.height * hdr.nElems
	rowStart = p.unpack(e">${n}I")
	//rowSize = p.unpack(e">${n}i")
	getrow(y:number, iElem:number) = {
		p = buff.pointer(rowStart[y + iElem * hdr.height])
		repeat ():iter {
			[pixel] = p.unpack("B")
			count = pixel & 0x7f
			if (count == 0) {
				break
			} elsif ((pixel & 0x80) == 0) {
				[pixel] = p.unpack("B")
				repeat (count):iter { pixel }
			} else {
				p.unpack(e"${count}B").each()
			}
		}
	}
	if (self.format == `rgb) {
		repeat (hdr.height) {|y|
			self.putpixel(0.., y, color(getrow(y, 0), getrow(y, 1), getrow(y, 2)))
		}
	} elsif (self.format == `rgba) {
		repeat (hdr.height) {|y|
			self.putpixel(0.., y, color(getrow(y, 0), getrow(y, 1), getrow(y, 2), 0))
		}
	} else {
		raise(ValueError, "unknown image format")
	}
	self
}
classref(`image).rgbread.help("""Reads an image in RGB format""")

mainloop(width:number, height:number, delay:number, drawTrigger:symbol) {`block} = {
	import(sdl)
	import(opengl) {*}
	keycodeToSymbol = %{
		sdl.K_ESCAPE	=> `escape
		sdl.K_TAB		=> `tab
		sdl.K_SPACE		=> `space
		sdl.K_RETURN	=> `return
		sdl.K_BACKSPACE	=> `backspace
		sdl.K_LEFT		=> `left
		sdl.K_RIGHT		=> `right
		sdl.K_UP		=> `up
		sdl.K_DOWN		=> `down
		sdl.K_PRINT		=> `print
		sdl.K_a			=> `a
		sdl.K_b			=> `b
		sdl.K_c			=> `c
		sdl.K_d			=> `d
		sdl.K_e			=> `e
		sdl.K_f			=> `f
		sdl.K_g			=> `g
		sdl.K_h			=> `h
		sdl.K_i			=> `i
		sdl.K_j			=> `j
		sdl.K_k			=> `k
		sdl.K_l			=> `l
		sdl.K_m			=> `m
		sdl.K_n			=> `n
		sdl.K_o			=> `o
		sdl.K_p			=> `p
		sdl.K_q			=> `q
		sdl.K_r			=> `r
		sdl.K_s			=> `s
		sdl.K_t			=> `t
		sdl.K_u			=> `u
		sdl.K_v			=> `v
		sdl.K_w			=> `w
		sdl.K_x			=> `x
		sdl.K_y			=> `y
		sdl.K_z			=> `z
		sdl.K_0			=> `num0
		sdl.K_1			=> `num1
		sdl.K_2			=> `num2
		sdl.K_3			=> `num3
		sdl.K_4			=> `num4
		sdl.K_5			=> `num5
		sdl.K_6			=> `num6
		sdl.K_7			=> `num7
		sdl.K_8			=> `num8
		sdl.K_9			=> `num9
	}
	d = dict {|block|}
	[onInit, onResize, onDraw] = d.get([`onInit, `onResize, `onDraw]):list
	[onKeyDown, onKeyUp, onKeyPoll] = d.get([`onKeyDown, `onKeyUp, `onKeyPoll]):list
	[onMouseMotion, onMouseButtonDown, onMouseButtonUp] = \
			d.get([`onMouseMotion, `onMouseButtonDown, `onMouseButtonUp]):list
	items = zip(keycodeToSymbol.values(), keycodeToSymbol.keys())
	symbolToKeycode = dict(items)
	sdl.Init(sdl.INIT_VIDEO)
	bpp = sdl.GetVideoInfo().vfmt.BitsPerPixel
	screen = sdl.SetVideoMode(width, height, bpp, sdl.OPENGL)
	sdl.GL_SetAttribute * [
		[sdl.GL_RED_SIZE, 5], [sdl.GL_GREEN_SIZE, 5], [sdl.GL_BLUE_SIZE, 5],
		[sdl.GL_DEPTH_SIZE, 32], [sdl.GL_DOUBLEBUFFER, 0]
	]
	onInit && onInit()
	onResize && onResize(screen.w, screen.h)
	repeat {
		event = sdl.PollEvent()
		if (event == nil) {
			// nothing to do
		} elsif (event.type == sdl.VIDEOEXPOSE) {
			onDraw && onDraw()
			sdl.GL_SwapBuffers()
		} elsif (event.type == sdl.VIDEORESIZE) {
			onResize && onResize(event.width, event.height)
			onDraw && onDraw()
			sdl.GL_SwapBuffers()
		} elsif (event.type == sdl.QUIT) {
			break
		} elsif (event.type == sdl.KEYDOWN) {
			if (event.sym == sdl.K_ESCAPE) {
				break
			} elsif (event.sym == sdl.K_PRINT) {
				img = glReadPixels(0, 0, screen.w, screen.h, `rgb)
				img.writebmp(open("snapshot.bmp", "w"))
				println("snapshot.bmp was generated")
			} else {
				symbol = keycodeToSymbol.get(event.sym)
				if (symbol && onKeyDown) {
					func = onKeyDown.get(symbol)
					if (func) { func() }
				}
			}
			if (drawTrigger == `keydown) {
				onDraw && onDraw()
				sdl.GL_SwapBuffers()
			}
		} elsif (event.type == sdl.KEYUP) {
			symbol = keycodeToSymbol.get(event.sym)
			if (symbol && onKeyUp) {
				func = onKeyUp.get(symbol)
				if (func) { func() }
			}
		} elsif (event.type == sdl.MOUSEMOTION) {
			onMouseMotion && onMouseMotion(event.x, event.y)
		} elsif (event.type == sdl.MOUSEBUTTONDOWN) {
			onMouseButtonDown && onMouseButtonDown(event.x, event.y)
		} elsif (event.type == sdl.MOUSEBUTTONUP) {
			onMouseButtonUp && onMouseButtonUp(event.x, event.y)
		}
		if (onKeyPoll) {
			for (func in onKeyPoll.values().filter(
						sdl.CheckKeyState(symbolToKeycode[onKeyPoll.keys()]))) {
				func()
			}
		}
		if (drawTrigger == `idle) {
			onDraw && onDraw()
			sdl.GL_SwapBuffers()
		}
		sdl.Delay(delay)
	}
	sdl.Quit()
}

if (__name__ == "__main__") {
	import(opengl) {*}
	mainloop(300, 300, 0, `none) {
		`onInit => lambda {
		}
		`onResize => lambda(width:number, height:number) {
		}
		`onDraw => lambda {
			glClearColor(0, 0, 1, 1)
			glClear(GL_COLOR_BUFFER_BIT)
			glFlush()
		}
		`onKeyDown => %{
			`space => lambda {
				println("KeyDown(space)")
			}
		}
		`onKeyPoll => %{
		}
		`onMouseMotion => lambda(x:number, y:number) {
			printf("MouseMotion(%d, %d)\n", x, y)
		}
		`onMouseButtonDown => lambda(x:number, y:number) {
			printf("MouseButtonDown(%d, %d)\n", x, y)
		}
		`onMouseButtonUp => lambda(x:number, y:number) {
			printf("MouseButtonUp(%d, %d)\n", x, y)
		}
	}
}
