annotate lightsim/openglsim.py @ 2148:2973ec5df7e4

add dep
author drewp@bigasterisk.com
date Wed, 17 May 2023 19:09:01 -0700
parents 61164aaadbaa
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
1 #!/usr/bin/python2.4
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
2 # see http://www.sgi.com/software/opengl/advanced97/notes/node57.html for accum notes
45b12307c695 Initial revision
drewp
parents:
diff changeset
3
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
4 from __future__ import division
341
f866d4dec57b openglsim now mixes images
drewp@bigasterisk.com
parents: 0
diff changeset
5 import sys, time
659
61164aaadbaa change lightsim to numpy
drewp@bigasterisk.com
parents: 466
diff changeset
6 import numpy as num
345
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
7 import Tkinter as tk
341
f866d4dec57b openglsim now mixes images
drewp@bigasterisk.com
parents: 0
diff changeset
8 import Image
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
9 from louie import dispatcher
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
10
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
11 from PyQt4.QtCore import QSize
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
12 from PyQt4.QtOpenGL import QGLWidget
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
13 from OpenGL.GL import *
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
14
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
15 def xxxdrawWithAlpha(imgString, w, h, alpha):
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
16 # this one should be faster because GL does the alpha adjust, but
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
17 # i don't think it works yet
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
18
345
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
19 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
20
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
21 glClear(GL_COLOR_BUFFER_BIT)
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
22 #glBlendColor(1, 1, 1, mag) # needs ARB_imaging
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
23 glDrawPixels(w, h, GL_RGBA, GL_UNSIGNED_BYTE, imgString)
839545f174d3 add drawPixels version
Drew Perttula <drewp@bigasterisk.com>
parents: 341
diff changeset
24
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
25 class Surface(QGLWidget):
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
26 """widget that adds multiple image files together with adjustable scales"""
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
27 def __init__(self, parent, filenames, imgRescaleTo=None):
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
28 """
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
29 imgRescaleTo can be a length of pixels to reduce all the input
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
30 images into. Try 64 for a low res drawing.
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
31 """
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
32 QGLWidget.__init__(self, parent)
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
33
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
34 self.levels = {} # filename : brightness
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
35
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
36 self.image = {} # filename : imgstr
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
37 for filename in filenames:
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
38 print "open", filename
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
39 im = Image.open(filename)
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
40 self.origImageSize = im.size[0], im.size[1]
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
41 if imgRescaleTo:
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
42 im.thumbnail((imgRescaleTo, imgRescaleTo))
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
43 im = im.transpose(Image.FLIP_TOP_BOTTOM)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
44 self.imageWidth = im.size[0]
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
45 self.imageHeight = im.size[1]
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
46 self.image[filename] = im.convert("RGBA").tostring()
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
47
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
48 def initializeGL(self):
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
49 glDisable(GL_CULL_FACE)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
50 glShadeModel(GL_FLAT)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
51 print 'GL_ARB_imaging', 'GL_ARB_imaging' in glGetString(GL_EXTENSIONS)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
52 import OpenGL
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
53 print OpenGL.__version__
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
54
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
55 def sizeHint(self):
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
56 return QSize(*self.origImageSize)
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
57
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
58 def paintGL(self):
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
59 """you set self.levels to dict and call tkRedraw"""
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
60 assert 'GL_ARB_imaging' in glGetString(GL_EXTENSIONS).split()
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
61 start = time.time()
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
62
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
63 glClearColor(0.0, 0.0, 0.0, 0)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
64 glClear( GL_COLOR_BUFFER_BIT |GL_ACCUM_BUFFER_BIT)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
65 glEnable(GL_BLEND)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
66 glBlendFunc(GL_SRC_ALPHA, GL_ONE) # add
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
67
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
68 # l=glGenLists(1)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
69 # glNewList(l,GL_COMPILE)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
70 # glEndList()
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
71
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
72 # drawing to glAccum might be good
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
73 layerTimes = []
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
74 layers = 0
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
75 for filename, mag in self.levels.items():
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
76 t = time.time()
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
77 layers += self.drawWithAlpha(self.image[filename],
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
78 self.imageWidth, self.imageHeight, mag)
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
79 layerTimes.append(time.time() - t)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
80
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
81 dispatcher.send("status", key="visibleLayers", value=str(layers))
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
82
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
83 dispatcher.send("status", key="redraw",
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
84 value="%.1fms" % ((time.time() - start) * 1000))
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
85
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
86
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
87 def drawWithAlpha(self, imgString, w, h, alpha):
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
88 """without opengl extensions. Returns number of layers drawn"""
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
89 if alpha == 0:
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
90 return 0
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
91 t = time.time()
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
92 ar = num.reshape(num.fromstring(imgString, dtype='uint8'),
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
93 (w * h, 4))
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
94 #print " tonum", time.time() - t
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
95 if alpha != 1:
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
96 ar[:,3] *= alpha
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
97
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
98 #print " scl", time.time() - t
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
99
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
100 # this might be a good way to scale the color channels too,
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
101 # but the blend might take two steps. Anyway,
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
102 # GL_CONSTANT_COLOR seems not to work, so i'm not exploring
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
103 # this right now.
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
104 #glBlendFunc(GL_CONSTANT_COLOR, GL_ONE)
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
105 #glBlendColor(.8, .5, .5, .5)
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
106
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
107 glPixelZoom(self.width() / w, self.height() / h)
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
108 glDrawPixels(w, h,
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
109 GL_RGBA, GL_UNSIGNED_BYTE, ar.tostring())
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
110 #print " draw", time.time() - t
466
f69ba5ac17c5 qt version of lightsim now works
drewp@bigasterisk.com
parents: 463
diff changeset
111 return 1
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
112
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
113 def newLevels(self, event=None, levels=None):
353
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
114 if levels != self.levels:
941cfe1e1691 lightsim now reads levels from dmxserver
drewp@bigasterisk.com
parents: 346
diff changeset
115 self.levels = levels
463
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
116 self.updateGL()
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
117
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
118
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
119 ## def mousePressEvent(self, event):
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
120 ## self.lastPos = QtCore.QPoint(event.pos())
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
121
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
122 ## def mouseMoveEvent(self, event):
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
123 ## dx = event.x() - self.lastPos.x()
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
124 ## dy = event.y() - self.lastPos.y()
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
125 ## rot = (.25*dy, .25*dx, 0)
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
126 ## if event.buttons() & QtCore.Qt.LeftButton:
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
127 ## self.emit(QtCore.SIGNAL("rotationChanged"), rot)
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
128 ## elif event.buttons() & QtCore.Qt.MidButton:
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
129 ## self.emit(QtCore.SIGNAL("camDistChanged"), .01*dy)
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
130
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
131 ## self.lastPos = QtCore.QPoint(event.pos())
60b49f6c2027 start porting lightsim to qt
drewp@bigasterisk.com
parents: 353
diff changeset
132
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
133 def main():
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
134 root = tk.Frame()
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
135 root.pack(expand=True, fill='both')
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
136 QuitButton = tk.Button(root, {'text':'Quit'})
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
137 QuitButton.bind('<ButtonRelease-1>', sys.exit)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
138 QuitButton.pack()
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
139
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
140 filenames=['skyline/bg.png',
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
141 'skyline/cyc-lo-red.png',
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
142 'skyline/cyc-lo-grn.png',
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
143 ]
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
144
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
145 scales = {} # filename : scale
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
146 for f in filenames:
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
147 scales[f] = tk.Scale(
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
148 root, label=f, from_=0, to=1, res=.05, orient='horiz',
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
149 command=lambda *args: ogl.newLevels(
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
150 levels=dict([(f, s.get()) for f,s in scales.items()])))
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
151 scales[f].pack()
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
152 ogl = Surface(root, filenames)
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
153 ogl.pack(side='top', expand=True, fill='both')
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
154
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
155 ogl.mainloop()
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
156
45b12307c695 Initial revision
drewp
parents:
diff changeset
157 if __name__ == '__main__':
346
a08882a05d29 openglsim refactor. now dims a few lights
drewp@bigasterisk.com
parents: 345
diff changeset
158 main()
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
159
45b12307c695 Initial revision
drewp
parents:
diff changeset
160 demo = Surface