sanangeles.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. # San Angeles Observation
  2. # Original C version Copyright 2004-2005 Jetro Lauha
  3. # Web: http://iki.fi/jetro/
  4. #
  5. # BSD-license.
  6. #
  7. # Javascript version by Ken Waters
  8. # Skulpt (Python) version by Scott Graham
  9. import webgl
  10. ShapeParams = [
  11. # m a b n1 n2 n3 m a b n1 n2 n3 res1 res2 scale (org.res1,res2)
  12. [10, 1, 2, 90, 1, -45, 8, 1, 1, -1, 1, -0.4 , 20, 30, 2], # 40, 60
  13. [10, 1, 2, 90, 1, -45, 4, 1, 1, 10, 1, -0.4 , 20, 20, 4], # 40, 40
  14. [10, 1, 2, 60, 1, -10, 4, 1, 1, -1, -2, -0.4 , 41, 41, 1], # 82, 82
  15. [ 6, 1, 1, 60, 1, -70, 8, 1, 1, 0.4 , 3, 0.25 , 20, 20, 1], # 40, 40
  16. [ 4, 1, 1, 30, 1, 20, 12, 1, 1, 0.4 , 3, 0.25 , 10, 30, 1], # 20, 60
  17. [ 8, 1, 1, 30, 1, -4, 8, 2, 1, -1, 5, 0.5 , 25, 26, 1], # 60, 60
  18. [13, 1, 1, 30, 1, -4, 13, 1, 1, 1, 5, 1, 30, 30, 6], # 60, 60
  19. [10, 1, 1.1 , -0.5 , 0.1 , 70, 60, 1, 1, -90, 0, -0.25 , 20, 60, 8], # 60, 180
  20. [ 7, 1, 1, 20, -0.3 , -3.5 , 6, 1, 1, -1, 4.5 , 0.5 , 10, 20, 4], # 60, 80
  21. [ 4, 1, 1, 10, 10, 10, 4, 1, 1, 10, 10, 10, 10, 20, 1], # 20, 40
  22. [ 4, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 10, 10, 2], # 10, 10
  23. [ 1, 1, 1, 38, -0.25 , 19, 4, 1, 1, 10, 10, 10, 10, 15, 2], # 20, 40
  24. [ 2, 1, 1, 0.7 , 0.3 , 0.2 , 3, 1, 1, 100, 100, 100, 10, 25, 2], # 20, 50
  25. [ 6, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 30, 30, 2], # 60, 60
  26. [ 3, 1, 1, 1, 1, 1, 6, 1, 1, 2, 1, 1, 10, 20, 2], # 20, 40
  27. [ 6, 1, 1, 6, 5.5 , 100, 6, 1, 1, 25, 10, 10, 30, 20, 2], # 60, 40
  28. [ 3, 1, 1, 0.5 , 1.7 , 1.7 , 2, 1, 1, 10, 10, 10, 20, 20, 2], # 40, 40
  29. [ 5, 1, 1, 0.1 , 1.7 , 1.7 , 1, 1, 1, 0.3 , 0.5 , 0.5 , 20, 20, 4], # 40, 40
  30. [ 2, 1, 1, 6, 5.5 , 100, 6, 1, 1, 4, 10, 10, 10, 22, 1], # 40, 40
  31. [ 6, 1, 1, -1, 70, 0.1 , 9, 1, 0.5 , -98, 0.05 , -45, 20, 30, 4], # 60, 91
  32. [ 6, 1, 1, -1, 90, -0.1 , 7, 1, 1, 90, 1.3 , 34, 13, 16, 1] # 32, 60
  33. ]
  34. class CamTrack:
  35. def __init__(self, src, dest, dist, len):
  36. self.src = src
  37. self.dest = dest
  38. self.dist = dist
  39. self.len = len
  40. CamTracks = [
  41. CamTrack([4500, 2700, 100, 70, -30], [50, 50, -90, -100, 0], 20, 1),
  42. CamTrack([ -1448, 4294, 25, 363, 0 ], [ -136, 202, 125, -98, 100], 0, 1),
  43. CamTrack([ 1437, 4930, 200, -275, -20 ], [ 1684, 0, 0, 9, 0], 0, 1),
  44. CamTrack([ 1800, 3609, 200, 0, 675 ], [ 0, 0, 0, 300, 0], 0, 1),
  45. CamTrack([ 923, 996, 50, 2336, -80 ], [ 0, -20, -50, 0, 170], 0, 1),
  46. CamTrack([ -1663, -43, 600, 2170, 0 ], [ 20, 0, -600, 0, 100], 0, 1),
  47. CamTrack([ 1049, -1420, 175, 2111, -17 ], [ 0, 0, 0, -334, 0], 0, 2),
  48. CamTrack([ 0, 0, 50, 300, 25 ], [ 0, 0, 0, 300, 0], 70, 2),
  49. CamTrack([ -473, -953, 3500, -353, -350 ], [ 0, 0, -2800, 0, 0], 0, 2),
  50. CamTrack([ 191, 1938, 35, 1139, -17 ], [ 1205, -2909, 0, 0, 0], 0, 2),
  51. CamTrack([ -1449, -2700, 150, 0, 0 ], [ 0, 2000, 0, 0, 0], 0, 2),
  52. CamTrack([ 5273, 4992, 650, 373, -50 ], [ -4598, -3072, 0, 0, 0], 0, 2),
  53. CamTrack([ 3223, -3282, 1075, -393, -25 ], [ 1649, -1649, 0, 0, 0], 0, 2),
  54. ]
  55. CAMTRACK_LEN = 5442
  56. FlatVertexSource = """
  57. attribute vec3 pos;
  58. attribute vec4 colorIn;
  59. uniform mat4 mvp;
  60. varying vec4 color;
  61. void main() {
  62. color = colorIn;
  63. gl_Position = mvp * vec4(pos.xyz, 1.);
  64. }
  65. """
  66. FlatFragmentSource = """
  67. #ifdef GL_ES
  68. precision highp float;
  69. #endif
  70. varying vec4 color;
  71. void main() {
  72. gl_FragColor = vec4(color.rgb, 1.0);
  73. }
  74. """
  75. LitVertexSource = """
  76. attribute vec3 pos;
  77. attribute vec3 normal;
  78. attribute vec4 colorIn;
  79. varying vec4 color;
  80. uniform mat4 mvp;
  81. uniform mat3 normalMatrix;
  82. uniform vec4 ambient;
  83. uniform float shininess;
  84. uniform vec3 light_0_direction;
  85. uniform vec4 light_0_diffuse;
  86. uniform vec4 light_0_specular;
  87. uniform vec3 light_1_direction;
  88. uniform vec4 light_1_diffuse;
  89. uniform vec3 light_2_direction;
  90. uniform vec4 light_2_diffuse;
  91. vec3 worldNormal;
  92. vec4 SpecularLight(vec3 direction,
  93. vec4 diffuseColor,
  94. vec4 specularColor) {
  95. vec3 lightDir = normalize(direction);
  96. float diffuse = max(0., dot(worldNormal, lightDir));
  97. float specular = 0.;
  98. if (diffuse > 0.) {
  99. vec3 halfv = normalize(lightDir + vec3(0., 0., 1.));
  100. specular = pow(max(0., dot(halfv, worldNormal)), shininess);
  101. }
  102. return diffuse * diffuseColor * colorIn + specular * specularColor;
  103. }
  104. vec4 DiffuseLight(vec3 direction, vec4 diffuseColor) {
  105. vec3 lightDir = normalize(direction);
  106. float diffuse = max(0., dot(worldNormal, lightDir));
  107. return diffuse * diffuseColor * colorIn;
  108. }
  109. void main() {
  110. worldNormal = normalize(normalMatrix * normal);
  111. gl_Position = mvp * vec4(pos, 1.);
  112. color = ambient * colorIn;
  113. color += SpecularLight(light_0_direction, light_0_diffuse,
  114. light_0_specular);
  115. color += DiffuseLight(light_1_direction, light_1_diffuse);
  116. color += DiffuseLight(light_2_direction, light_2_diffuse);
  117. }
  118. """
  119. FadeVertexSource = """
  120. #ifdef GL_ES
  121. precision highp float;
  122. #endif
  123. attribute vec2 pos;
  124. varying vec4 color;
  125. uniform float minFade;
  126. void main() {
  127. color = vec4(minFade, minFade, minFade, 1.);
  128. gl_Position = vec4(pos, 0., 1.);
  129. }
  130. """
  131. class Random:
  132. def __init__(self, seed):
  133. self.randomSeed = seed
  134. def seed(self, seed):
  135. self.randomSeed = seed
  136. def uInt(self):
  137. self.randomSeed = (self.randomSeed * 0x343fd + 0x269ec3) & 0xffffffff
  138. return (self.randomSeed >> 16) & 0xfff
  139. class GlObject:
  140. def __init__(self, gl, shader, vertices, colors, normals=None):
  141. self.shader = shader
  142. self.count = len(vertices) / 3
  143. self.vbo = gl.createBuffer()
  144. vertexArray = gl.Float32Array(vertices)
  145. colorArray = gl.Uint8Array(colors)
  146. self.vertexOffset = 0
  147. self.colorOffset = vertexArray.byteLength
  148. self.normalOffset = self.colorOffset + colorArray.byteLength
  149. sizeInBytes = self.normalOffset
  150. normalArray = None
  151. self.hasNormals = normals != None
  152. if normals:
  153. normalArray = gl.Float32Array(normals)
  154. sizeInBytes += normalArray.byteLength
  155. gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)
  156. gl.bufferData(gl.ARRAY_BUFFER, sizeInBytes, gl.STATIC_DRAW)
  157. gl.bufferSubData(gl.ARRAY_BUFFER, self.vertexOffset, vertexArray)
  158. gl.bufferSubData(gl.ARRAY_BUFFER, self.colorOffset, colorArray)
  159. if normals:
  160. gl.bufferSubData(gl.ARRAY_BUFFER, self.normalOffset, normalArray)
  161. def draw(self):
  162. self.shader.use()
  163. gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)
  164. gl.vertexAttribPointer(self.shader.posLoc, 3, gl.FLOAT, False, 0, self.vertexOffset)
  165. gl.enableVertexAttribArray(self.shader.posLoc)
  166. gl.vertexAttribPointer(self.shader.colorInLoc, 4, gl.UNSIGNED_BYTE, True, 0, self.colorOffset)
  167. gl.enableVertexAttribArray(self.shader.colorInLoc)
  168. if self.hasNormals:
  169. gl.vertexAttribPointer(self.shader.normalLoc, 3, gl.FLOAT, False, 0, self.normalOffset)
  170. gl.enableVertexAttribArray(self.shader.normalLoc)
  171. gl.drawArrays(gl.TRIANGLES, 0, self.count)
  172. if self.hasNormals:
  173. gl.disableVertexAttribArray(self.shader.normalLoc)
  174. gl.disableVertexAttribArray(self.shader.colorInLoc)
  175. gl.disableVertexAttribArray(self.shader.posLoc)
  176. def createGroundPlane(gl, shader, random):
  177. scale = 4
  178. xBegin, xEnd = -15, 15
  179. yBegin, yEnd = -15, 15
  180. triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2
  181. colors = []
  182. vertices = []
  183. for y in range(yBegin, yEnd):
  184. for x in range(xBegin, xEnd):
  185. color = (random.uInt() & 0x4f) + 81
  186. for i in range(6):
  187. colors.extend([color, color, color, 0])
  188. for i in range(6):
  189. xm = x + ((0x1c >> a) & 1)
  190. ym = y + ((0x31 >> a) & 1)
  191. m = math.cos(xm * 2) * math.sin(ym * 4) * 0.75
  192. vertices.extend([xm * scale + m, ym * scale + m, 0])
  193. return GlObject(shader, vertices, colors)
  194. ground = None
  195. fadeVBO = None
  196. shapes = None
  197. modelview = None
  198. projection = None
  199. mvp = None
  200. normalMatrix = None
  201. currentCamTrackStartTick = 0
  202. nextCamTrackStartTick = 0
  203. sTick = 0
  204. currentCamTrack = 0
  205. def main():
  206. global gl, random, modelview, projection, mvp, normalMatrix
  207. modelview = webgl.Mat44()
  208. projection = webgl.Mat44()
  209. mvp = webgl.Mat44()
  210. normalMatrix = webgl.Mat33()
  211. gl = webgl.GL("canv")
  212. gl.enable(gl.DEPTH_TEST)
  213. gl.disable(gl.CULL_FACE)
  214. random = Random(15)
  215. flatShader = webgl.Shader(gl, FlatVertexSource, FlatFragmentSource)
  216. litShader = webgl.Shader(gl, LitVertexSource, FlatFragmentSource)
  217. fadeShader = webgl.Shader(gl, FadeVertexSource, FlatFragmentSource)
  218. # bind non-changing lighting parameters
  219. litShader.use()
  220. gl.uniform4f(litShader.ambientLoc, .2, .2, .2, 1.)
  221. gl.uniform4f(litShader.light_0_diffuseLoc, 1., .4, 0, 1.)
  222. gl.uniform4f(litShader.light_1_diffuseLoc, .07, .14, .35, 1.)
  223. gl.uniform4f(litShader.light_2_diffuseLoc, .07, .17, .14, 1.)
  224. gl.uniform4f(litShader.light_0_specularLoc, 1., 1., 1., 1.)
  225. gl.uniform1f(litShader.shininessLoc, 60.)
  226. shapes = [createSuperShape(litShader, x) for x in ShapeParams]
  227. ground = createGroundPlane(flatShader)
  228. def clamp(x, mn=0, mx=255):
  229. return max(min(x, mx), mn)
  230. def superShapeMap(r1, r2, t, p):
  231. return gl.Vec3(math.cos(t) * math.cos(p) / r1 / r2,
  232. math.sin(t) * math.cos(p) / r1 / r2,
  233. math.sin(p) / r2)
  234. def ssFunc(t, p):
  235. return pow(pow(abs(cos(p[0] * t / 4)) / p[1], p[4]) +
  236. pow(abs(sin(p[0] * t / 4)) / p[2], p[5]),
  237. 1.0 / p[3])
  238. def createSuperShape(shader, params):
  239. resol1 = params[-3]
  240. resol2 = params[-2]
  241. # latitude 0 to pi/2 for no mirrored bottom
  242. # (latitudeBegin==0 for -pi/2 to pi/2 originally)
  243. latitudeBegin = resol2 / 4
  244. latitudeEnd = resol2 / 2
  245. longitudeCount = resol1
  246. vertices = []
  247. colors = []
  248. normals = []
  249. baseColor = [(random.uInt() % 155 + 100) / 255.0 for x in range(3)]
  250. currentVertex = 0
  251. for longitude in range(longitudeCount):
  252. for latitude in range(latitudeBegin, latitudeEnd):
  253. t1 = -math.pi + longitude * 2 * math.pi / resol1
  254. t2 = -math.pi + (longitute + 1) * 2 * math.pi / resol1
  255. p1 = -math.pi / 2 + latitude * 2 * math.pi / resol2
  256. p2 = -math.pi / 2 + (latitude + 1) * 2 * math.pi / resol2
  257. r0 = ssFunc(t1, params)
  258. r1 = ssFunc(p1, params[6:])
  259. r2 = ssFunc(t2)
  260. r3 = ssFunc(p2, params[6:])
  261. if r0 and r1 and r2 and r3:
  262. pa = superShapeMap(r0, r1, t1, p1)
  263. pb = superShapeMap(r2, r1, t2, p1)
  264. pc = superShapeMap(r2, r3, r2, p2)
  265. pd = superShapeMap(r0, r3, t1, p2)
  266. # kludge to set lower edge of the object to fixed level
  267. if latitude == latitudeBegin + 1:
  268. pa.z = pb.z = 0
  269. v1 = pb - pa
  270. v2 = pd - pa
  271. n = gl.cross(v1, v2)
  272. # Pre-normalization of the normals is disabled here because
  273. # they will be normalized anyway later due to automatic
  274. # normalization (NORMALIZE). It is enabled because the
  275. # objects are scaled with scale.
  276. #
  277. # Note we have to normalize by hand in the shader
  278. ca = pa.z + 0.5
  279. for i in range(6):
  280. normals.extend([n.x, n.y, n.z])
  281. for i in range(6):
  282. colors.append(clamp(ca * baseColor[0] * 255))
  283. colors.append(clamp(ca * baseColor[1] * 255))
  284. colors.append(clamp(ca * baseColor[2] * 255))
  285. colors.append(0)
  286. vertices.extend([pa.x, pa.y, pa.z])
  287. vertices.extend([pb.x, pb.y, pb.z])
  288. vertices.extend([pd.x, pd.y, pd.z])
  289. vertices.extend([pb.x, pb.y, pb.z])
  290. vertices.extend([pc.x, pc.y, pc.z])
  291. vertices.extend([pd.x, pd.y, pd.z])
  292. return GlObject(gl, shader, vertices, colors, normals)
  293. def configureLightAndMaterial():
  294. l0 = modelview.transform3(Vec3(-4., 1., 1.))
  295. l1 = modelview.transform3(Vec3(1., -2., -1.))
  296. l2 = modelview.transform3(Vec3(-1., 0., -4.))
  297. litShader.use()
  298. gl.uniform3f(litShader.light_0_directionLoc, l0.x, l0.y, l0.z)
  299. gl.uniform3f(litShader.light_1_directionLoc, l1.x, l1.y, l1.z)
  300. gl.uniform3f(litShader.light_2_directionLoc, l2.x, l2.y, l2.z)
  301. def drawModels(zScale):
  302. translationScale = 9
  303. modelview.scale(1, 1, zScale)
  304. random.seed(9)
  305. for y in range(-5, 5):
  306. for x in range(-5, 5):
  307. curShape = random.uInt() % len(ShapeParams)
  308. buildingScale = ShapeParams[curShape][-1]
  309. modelview.push()
  310. modelview.translate(x * translationScale, y * translationScale, 0)
  311. rv = random.uInt() % 360
  312. modelview.rotate(-rv, 0, 0, 1)
  313. modelview.scale(buildingScale, buildingScale, buildingScale)
  314. shapes[curShape].draw()
  315. modelview.pop()
  316. ship = shapes[-1]
  317. for x in range(-2, 2):
  318. shipScale100 = translationScale * 500
  319. offs100 = x * shipScale100 + (sTick % shipScale100)
  320. offs = 0.01 * offs100
  321. modelview.push()
  322. modelview.translate(offs, -4.0, 2.0)
  323. ship.draw()
  324. modelview.pop()
  325. modelview.push()
  326. modelview.translate(-4., offs, 4.)
  327. modelview.rotate(-90., 0., 0., 1.)
  328. ship.draw()
  329. modelview.pop()
  330. def camTrack():
  331. nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN
  332. while nextCamTrackStartTick <= sTick:
  333. ++currentCamTrack
  334. if currentCamTrack >= len(CamTracks):
  335. currentCamTrack = 0
  336. currentCamTrackStartTick = nextCamTrackStartTick
  337. nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN
  338. cam = CamTracks[currentCamTrack]
  339. currentCamTick = sTick - currentCamTrackStartTick
  340. trackPos = currentCamTick / (CAMTRACK_LEN * cam.len)
  341. lerp = [0.01 * cam.src[a] + cam.dest[a] * trackPos for a in range(5)]
  342. if cam.dist:
  343. dist = cam.dist * 0.1
  344. cX = lerp[0]
  345. cY = lerp[1]
  346. cZ = lerp[2]
  347. eX = cX - math.cos(lerp[3]) * dist
  348. eY = cY - math.sin(lerp[3]) * dist
  349. eZ = cZ - lerp[4]
  350. else:
  351. eX = lerp[0]
  352. eY = lerp[1]
  353. eZ = lerp[2]
  354. cX = eX + math.cos(lerp[3])
  355. cY = eY + math.sin(lerp[3])
  356. cZ = eZ + lerp[4]
  357. modelview.lookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1)
  358. def drawGroundPlane():
  359. gl.disable(gl.CULL_FACE)
  360. gl.disable(gl.DEPTH_TEST)
  361. gl.enable(gl.BLEND)
  362. gl.blendFunc(gl.ZERO, gl.SRC_COLOR)
  363. ground.draw()
  364. gl.disable(gl.BLEND)
  365. gl.enable(gl.DEPTH_TEST)
  366. def drawFadeQuad():
  367. global fadeVBO
  368. if not fadeVBO:
  369. vertices = gl.Float32Array([
  370. -1, -1,
  371. 1, -1,
  372. -1, 1,
  373. 1, -1,
  374. 1, 1,
  375. -1, 1])
  376. fadeVBO = gl.createBuffer()
  377. gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)
  378. gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)
  379. beginFade = sTick - currentCamTrackStartTick
  380. endFade = nextCamTrackStartTick - sTick
  381. minFade = min(beginFade, endFade)
  382. if minFade < 1024:
  383. gl.disable(gl.DEPTH_TEST)
  384. gl.enable(gl.BLEND)
  385. gl.blendFunc(gl.ZERO, gl.SRC_COLOR)
  386. fadeShader.use()
  387. gl.uniform1f(fadeShader.minFadeLoc, minFade / 1024.0)
  388. gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)
  389. gl.vertexAttribPointer(fadeShader.posLoc, 2, gl.FLOAT, false, 0, 0)
  390. gl.enableVertexAttribArray(fadeShader.posLoc)
  391. gl.drawArrays(gl.TRIANGLES, 0, 6)
  392. gl.disableVertexAttribArray(fadeShader.posLoc)
  393. gl.disable(gl.BLEND)
  394. gl.enable(gl.DEPTH_TEST)
  395. def draw(gl, width, height):
  396. sTick = (sTick + tick) / 2
  397. gl.clearColor(0.1, 0.2, 0.3, 1.0)
  398. gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT)
  399. projection.loadIdentity()
  400. projection.perspective(45, width / height, 0.5, 100)
  401. modelview.loadIdentity()
  402. camTrack()
  403. configureLightAndMaterial()
  404. modelview.push()
  405. drawModels(-1)
  406. modelview.pop()
  407. drawGroundPlane()
  408. drawModels(1)
  409. drawFadeQuad()
  410. main()