Initial revision
diff --git a/Demo/sgi/gl/kunst.py b/Demo/sgi/gl/kunst.py
new file mode 100755
index 0000000..8fb982e
--- /dev/null
+++ b/Demo/sgi/gl/kunst.py
@@ -0,0 +1,446 @@
+#!/ufs/guido/bin/sgi/python
+# Simulate the artwork in the hall.
+# Jack Jansen, Feb 91.
+#
+# Please please please don't try to read this code.
+# It is the first GL program I ever wrote, and used to do
+# very different things before it's current function:-)
+from gl import *
+from GL import *
+from math import *
+from DEVICE import *
+import sys
+import __main__
+main_dict = __main__.__dict__
+
+SPOTDIRECTION = 103
+SPOTLIGHT = 104
+
+#
+# Make a cylinder paralel with the Z axis with center (X,Y,0)
+# and radius 1
+def mkcyl(nslice, nparts, docircle):
+	cyl = []
+	step = 2.0 / float(nslice)
+	z = -1.0
+	for i in range(nslice):
+	    cyl.append(mkslice(z, z+step, nparts, docircle))
+	    z = z + step
+	return drawcylinder(cyl)
+#
+# Make one part of a cylinder
+#
+def mkslice(z1, z2, nparts, docircle):
+	if docircle:
+	    w1 = z1
+	    w2 = z2
+	    w1 = sqrt(1.0-w1*w1)
+	    w2 = sqrt(1.0-w2*w2)
+	    normalz = 1.0
+	else:
+	    w1 = 1.0
+	    w2 = 1.0
+	    normalz = 0.0
+	slice = []
+	step = (2.0*pi)/float(nparts)
+	angle = 0.0
+	for i in range(nparts+1):
+	    vx = cos(angle)
+	    vy = sin(angle)
+	    slice.append( ((vx*w1,vy*w1,z1), (vx*w1, vy*w1, z1*normalz)) )
+	    slice.append( ((vx*w2,vy*w2,z2), (vx*w2, vy*w2, z2*normalz)) )
+	    angle = angle + step
+	return slice
+#
+# Drawcylinder : draw the cylinder
+#
+class struct(): pass
+curobj = struct()
+curobj.curobj = 1
+def drawcylinder(cyl):
+	obj = curobj.curobj
+	curobj.curobj = curobj.curobj+1
+	makeobj(obj)
+	for slice in cyl:
+	    bgntmesh()
+	    vnarray(slice)
+	    endtmesh()
+	closeobj()
+	return obj
+#
+def drawnormals(cyl):
+	for slice in cyl:
+	    for triang in slice:
+		bgnline()
+		v3f(triang[0])
+		v3f(triang[0][0] + triang[1][0], triang[0][1] + triang[1][1], triang[0][2] + triang[1][2])
+		endline()
+def drawfloors():
+	obj = curobj.curobj
+	curobj.curobj = curobj.curobj+1
+	makeobj(obj)
+	bgnpolygon()
+	v3i(4,6,-6)
+	v3i(-6,6,-6)
+	v3i(-6,-6,-6)
+	v3i(4,-6,-6)
+	endpolygon()
+	for floor in range(3):
+	    pos = -1 + 5*floor
+	    bgnpolygon()
+	    v3i(4,4,pos)
+	    v3i(-6,4,pos)
+	    v3i(-6,6,pos)
+	    v3i(4,6,pos)
+	    endpolygon()
+	    bgnpolygon()
+	    v3i(-4,4,pos)
+	    v3i(-4,-4,pos)
+	    v3i(-6,-4,pos)
+	    v3i(-6,4,pos)
+	    endpolygon()
+	    bgnpolygon()
+	    v3i(-6,-4,pos)
+	    v3i(-6,-6,pos)
+	    v3i(4,-6,pos)
+	    v3i(4,-4,pos)
+	    endpolygon()
+	closeobj()
+	return obj
+def drawdoors():
+	obj = curobj.curobj
+	curobj.curobj = curobj.curobj+1
+	makeobj(obj)
+	for floor in range(3):
+	    pos = -1+5*floor
+	    bgnpolygon()
+	    v3i(-2,6,pos)
+	    v3i(-2,6,pos+3)
+	    v3i(0,6,pos+3)
+	    v3i(0,6,pos)
+	    endpolygon()
+	closeobj()
+	return obj
+def drawrailing():
+	obj = curobj.curobj
+	curobj.curobj = curobj.curobj+1
+	makeobj(obj)
+	for floor in range(3):
+	    pos = -1 + 5*floor
+	    bgnpolygon()
+	    v3i(4,4,pos)
+	    v3i(4,4,pos-1)
+	    v3i(-4,4,pos-1)
+	    v3i(-4,4,pos)
+	    endpolygon()
+	    bgnpolygon()
+	    v3i(-4,4,pos)
+	    v3i(-4,4,pos-1)
+	    v3i(-4,-4,pos-1)
+	    v3i(-4,-4,pos)
+	    endpolygon()
+	    bgnpolygon()
+	    v3i(-4,-4,pos)
+	    v3i(-4,-4,pos-1)
+	    v3i(4,-4,pos-1)
+	    v3i(4,-4,pos)
+	    endpolygon()
+	closeobj()
+	return obj
+def drawwalls():
+	obj = curobj.curobj
+	curobj.curobj = curobj.curobj+1
+	makeobj(obj)
+	bgnpolygon()
+	v3i(4,6,-6)
+	v3i(4,6,18)
+	v3i(-6,6,18)
+	v3i(-6,6,-6)
+	endpolygon()
+	bgnpolygon()
+	v3i(-6,6,-6)
+	v3i(-6,6,18)
+	v3i(-6,-6,18)
+	v3i(-6,-6,-6)
+	endpolygon()
+	bgnpolygon()
+	v3i(-6,-6,-6)
+	v3i(-6,-6,18)
+	v3i(4,-6,18)
+	v3i(4,-6,-6)
+	endpolygon()
+	bgnpolygon()
+	v3i(4,-6,-6)
+	v3i(4,-6,18)
+	v3i(4,4,18)
+	v3i(4,4,-6)
+	endpolygon()
+	closeobj()
+	return obj
+def axis():
+	bgnline()
+	cpack(0xff0000)
+	v3i(-1,0,0)
+	v3i(1,0,0)
+	v3f(1.0, 0.1, 0.1)
+	endline()
+	bgnline()
+	cpack(0xff00)
+	v3i(0,-1,0)
+	v3i(0,1,0)
+	v3f(0.1, 1.0, 0.1)
+	endline()
+	bgnline()
+	cpack(0xff)
+	v3i(0,0,-1)
+	v3i(0,0,1)
+	v3f(0.1,0.1,1.0)
+	endline()
+#
+silver = [ DIFFUSE, 0.3, 0.3, 0.3, SPECULAR, 0.9, 0.9, 0.95, \
+	SHININESS, 40.0, LMNULL]
+floormat = [ AMBIENT, 0.5, 0.25, 0.15, DIFFUSE, 0.5, 0.25, 0.15, SPECULAR, 0.6, 0.3, 0.2, SHININESS, 20.0, LMNULL]
+wallmat = [ DIFFUSE, 0.4, 0.2, 0.1, AMBIENT, 0.4, 0.20, 0.10, SPECULAR, 0.0, 0.0, 0.0, SHININESS, 20.0, LMNULL]
+offwhite = [ DIFFUSE, 0.8, 0.8, 0.6, AMBIENT, 0.8, 0.8, 0.6, SPECULAR, 0.9, 0.9, 0.9, SHININESS, 30.0, LMNULL]
+doormat = [ DIFFUSE, 0.1, 0.2, 0.5, AMBIENT, 0.2, 0.4, 1.0, SPECULAR, 0.2, 0.4, 1.0, SHININESS, 60.0, LMNULL]
+
+toplight = [ LCOLOR, 1.0, 1.0, 0.5, \
+	POSITION, 0.0, 0.0, 11.0, 1.0, LMNULL]
+floor1light = [ LCOLOR, 1.0, 1.0, 1.0, POSITION, 3.9, -3.9, 0.0, 1.0, \
+	SPOTDIRECTION, 1.0, 1.0, 0.0, SPOTLIGHT, 10.0, 90.0, LMNULL]
+
+lmodel = [ AMBIENT, 0.92, 0.8, 0.5, LOCALVIEWER, 1.0, LMNULL]
+#
+def lighting():
+	INDIGO=1	# XXXX Seems indigo only has one light.
+	lmdef(DEFMATERIAL, 2, silver)
+	lmdef(DEFMATERIAL, 3, floormat)
+	lmdef(DEFMATERIAL, 4, wallmat)
+	lmdef(DEFMATERIAL, 5, offwhite)
+	lmdef(DEFMATERIAL, 6, doormat)
+	lmdef(DEFLIGHT, 1, toplight)
+	if not INDIGO:
+	    lmdef(DEFLIGHT, 2, floor1light)
+	lmdef(DEFLMODEL, 1, lmodel)
+	lmbind(LIGHT0, 1)
+	if not INDIGO:
+	    lmbind(LIGHT1, 2)
+	lmbind(LMODEL, 1)
+IdMat=[1.0,0.0,0.0,0.0, 0.0,1.0,0.0,0.0, 0.0,0.0,1.0,0.0, 0.0,0.0,0.0,1.0]
+#
+wrongrange='Wrong Range'
+def defun(axis):
+	done = 0
+	res = 0.0	# Hack around exec(...)
+	while not done:
+	    print 'F'+axis+'(t) = ',
+	    s = sys.stdin.readline(100)
+	    print
+	    try:
+		s = 'def f'+axis+'(t): return '+s
+		exec(s, main_dict)
+		exec('res = f'+axis+'(0.0)\n')
+		if res < -10.0 or res > 10.0:
+			raise wrongrange
+		exec('res = f'+axis+'(100.0)\n')
+		if res < -10.0 or res > 10.0:
+			raise wrongrange
+		done = 1
+	    except RuntimeError:
+		print 'Sorry, there is a syntax error in your expression'
+	    except TypeError:
+		print 'Please remember to use floating point numbers'
+	    except wrongrange:
+		print 'Sorry, function values out of range (non-periodic function?)'
+def getfunctions():
+	print 'Welcome to the CWI art simulator. You can now enter X, Y and Z'
+	print 'coordinates as a function of t.'
+	print 'Alternatively, you can specify the name of a python module'
+	print 'defining functions fx(t), fy(t) and fz(t) on the command line'
+	print 'Normal trig functions are available. Please use floating point'
+	print 'values only (so 0.0 for 0). Comments to jack@cwi.nl'
+	defun('x')
+	defun('y')
+	defun('z')
+	print 'Ok, here you go. Use mouse+right button to move up/down,'
+	print 'mouse+middle to speed up/slow down time. type ESC to quit simulation'
+def main():
+	if len(sys.argv) > 1:
+	    exec('from '+sys.argv[1]+' import *\n')
+	else:
+	    getfunctions()
+	foreground()
+	prefposition(100,600,100,600)
+	void = winopen('cyl')
+	qdevice(ESCKEY)
+	qdevice(MOUSE1)
+	qdevice(MOUSE2)
+	qdevice(PKEY)
+	RGBmode()
+	doublebuffer()
+	gconfig()
+	zbuffer(1)
+	mmode(MVIEWING)
+	perspective(600, 1.0, 0.01, 20.0)
+	loadmatrix(IdMat)
+	vx = 0.0
+	vy = -3.9
+	vz = 0.0
+	lookat(0.0, -3.9, 0.0, 0.0, 0.0, 0.0, 0)
+	lighting()
+	t = -1.0
+	step = 0.2
+	bol = mkcyl(12,24, 1)
+	cable = mkcyl(1, 6, 0)
+	floors = drawfloors()
+	walls = drawwalls()
+	pillar = mkcyl(1,4,0)
+	railing = drawrailing()
+	doors = drawdoors()
+	shademodel(GOURAUD)
+	mousing = -1
+	pausing = 0
+	while 1:
+	    #
+	    # Check for some user input
+	    #
+	    if qtest():
+		dev, value = qread()
+		if dev == PKEY and value == 1:
+			pausing = 1
+		if dev == ESCKEY:
+		    break
+		elif (dev==MOUSE1 or dev==MOUSE2) and value == 1:
+		    if mousing > 0:
+			vx = 0.0
+			vy = -3.9
+			vz = 0.0
+		    mousing = dev
+		    oldx = getvaluator(MOUSEX)
+		    oldy = getvaluator(MOUSEY)
+		elif (dev==MOUSE1 or dev==MOUSE2):
+		    mousing = -1
+	    if mousing >= 0:
+		newx = getvaluator(MOUSEX)
+		newy = getvaluator(MOUSEY)
+		if newy <> oldy and mousing==MOUSE1:
+		    vz = vz + float(newy - oldy)/100.0
+		    if vz < -5.99:
+			vz = -5.99
+		    dist = sqrt(vx*vx + vy*vy + vz*vz)
+		    perspective(600, 1.0, 0.01, dist+16.0)
+		    loadmatrix(IdMat)
+		    if vz < 0.0:
+			lookat(vx, vy, vz, 0.0, 0.0, 0.0, 1800)
+		    else:
+			lookat(vx, vy, vz, 0.0, 0.0, 0.0, 0)
+		if newy <> oldy and mousing==MOUSE2:
+		    step = step * exp(float(newy-oldy)/400.0)
+	    if getbutton(CTRLKEY) == 0:
+		t = t + step
+	    else:
+		t = t - step
+	    if getbutton(LEFTSHIFTKEY) == 0:
+		shademodel(GOURAUD)
+	    else:
+		shademodel(FLAT)
+	    #
+	    # Draw background and axis
+	    czclear(0x802020,getgdesc(GD_ZMAX))
+	    #axis()
+	    #
+	    # draw the floors
+	    #
+	    lmbind(MATERIAL, 3)
+	    callobj(floors)
+	    lmbind(MATERIAL, 4)
+	    callobj(walls)
+	    lmbind(MATERIAL, 5)
+	    pushmatrix()
+	    translate(-4.5,4.5,3.0)
+	    scale(0.2,0.2,9.0)
+	    rotate(450,'z')
+	    callobj(pillar)
+	    popmatrix()
+	    callobj(railing)
+	    lmbind(MATERIAL, 6)
+	    pushmatrix()
+	    translate(0.0, -0.01, 0.0)
+	    callobj(doors)
+	    popmatrix()
+	    #
+	    # Draw object
+	    #
+	    bolx = fx(t)
+	    boly = fy(t)
+	    bolz = fz(t)
+	    err = ''
+	    if bolx < -4.0 or bolx > 4.0:
+		err = 'X('+`bolx`+') out of range [-4,4]'
+	    if boly < -4.0 or boly > 4.0:
+		err = 'Y('+`boly`+') out of range [-4,4]'
+	    if bolz < -4.0 or bolz > 8.0:
+		err = 'Z('+`bolz`+') out of range [-4,8]'
+	    if not err:
+		pushmatrix()
+		translate(bolx, boly, bolz)
+		scale(0.3, 0.3, 0.3)
+		lmbind(MATERIAL, 2)
+		blendfunction(BF_ONE, BF_ONE)
+		callobj(bol)
+		blendfunction(BF_ONE, BF_ZERO)
+		popmatrix()
+		#
+		# Draw the cables
+		#
+		bolz = bolz + 0.3
+		pushmatrix()
+		#linesmooth(SML_ON)
+		bgnline()
+		v3i(-4,-4,9)
+		v3f(bolx, boly, bolz)
+		endline()
+		bgnline()
+		v3i(-4,4,9)
+		v3f(bolx, boly, bolz)
+		endline()
+		bgnline()
+		v3i(4,-4,9)
+		v3f(bolx, boly, bolz)
+		endline()
+		bgnline()
+		v3i(4,4,9)
+		v3f(bolx, boly, bolz)
+		endline()
+		popmatrix()
+	    if mousing == MOUSE2 or err:
+		cpack(0xff0000)
+		cmov(0.0, 0.0, 0.4)
+		charstr('t='+`t`)
+	    if mousing == MOUSE2:
+		cpack(0xff0000)
+		cmov(0.0, 0.0, 0.2)
+		charstr('delta-t='+`step`)
+	    if err:
+		cpack(0xff00)
+		cmov(0.0, 0.0, 0.2)
+		charstr(err)
+		pausing = 1
+	    if pausing:
+		cpack(0xff00)
+		cmov(0.0, 0.0, 0.0)
+		charstr('Pausing, type P to continue')
+	    swapbuffers()
+	    if pausing:
+		while 1:
+		    dv=qread()
+		    if dv==(PKEY,1):
+			break
+		    if dv==(ESCKEY,1):
+			sys.exit(0)
+		pausing = 0
+#
+try:
+    main()
+except KeyboardInterrupt:
+    sys.exit(1)