| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500 | # San Angeles Observation# Original C version Copyright 2004-2005 Jetro Lauha# Web: http://iki.fi/jetro/# # BSD-license.## Javascript version by Ken Waters# Skulpt (Python) version by Scott Grahamimport webglShapeParams = [    # m  a     b     n1      n2     n3     m     a     b     n1     n2      n3   res1 res2 scale  (org.res1,res2)    [10, 1,    2,    90,      1,   -45,    8,    1,    1,    -1,     1,  -0.4 ,   20,  30, 2], # 40, 60    [10, 1,    2,    90,      1,   -45,    4,    1,    1,    10,     1,  -0.4 ,   20,  20, 4], # 40, 40    [10, 1,    2,    60,      1,   -10,    4,    1,    1,    -1,    -2,  -0.4 ,   41,  41, 1], # 82, 82    [ 6, 1,    1,    60,      1,   -70,    8,    1,    1,  0.4 ,     3,  0.25 ,   20,  20, 1], # 40, 40    [ 4, 1,    1,    30,      1,    20,   12,    1,    1,  0.4 ,     3,  0.25 ,   10,  30, 1], # 20, 60    [ 8, 1,    1,    30,      1,    -4,    8,    2,    1,    -1,     5,   0.5 ,   25,  26, 1], # 60, 60    [13, 1,    1,    30,      1,    -4,   13,    1,    1,     1,     5,      1,   30,  30, 6], # 60, 60    [10, 1, 1.1 , -0.5 ,   0.1 ,    70,   60,    1,    1,   -90,     0, -0.25 ,   20,  60, 8], # 60, 180    [ 7, 1,    1,    20,  -0.3 , -3.5 ,    6,    1,    1,    -1,  4.5 ,   0.5 ,   10,  20, 4], # 60, 80    [ 4, 1,    1,    10,     10,    10,    4,    1,    1,    10,    10,     10,   10,  20, 1], # 20, 40    [ 4, 1,    1,     1,      1,     1,    4,    1,    1,     1,     1,      1,   10,  10, 2], # 10, 10    [ 1, 1,    1,    38, -0.25 ,    19,    4,    1,    1,    10,    10,     10,   10,  15, 2], # 20, 40    [ 2, 1,    1,  0.7 ,   0.3 ,  0.2 ,    3,    1,    1,   100,   100,    100,   10,  25, 2], # 20, 50    [ 6, 1,    1,     1,      1,     1,    3,    1,    1,     1,     1,      1,   30,  30, 2], # 60, 60    [ 3, 1,    1,     1,      1,     1,    6,    1,    1,     2,     1,      1,   10,  20, 2], # 20, 40    [ 6, 1,    1,     6,   5.5 ,   100,    6,    1,    1,    25,    10,     10,   30,  20, 2], # 60, 40    [ 3, 1,    1,  0.5 ,   1.7 ,  1.7 ,    2,    1,    1,    10,    10,     10,   20,  20, 2], # 40, 40    [ 5, 1,    1,  0.1 ,   1.7 ,  1.7 ,    1,    1,    1,  0.3 ,  0.5 ,   0.5 ,   20,  20, 4], # 40, 40    [ 2, 1,    1,     6,   5.5 ,   100,    6,    1,    1,     4,    10,     10,   10,  22, 1], # 40, 40    [ 6, 1,    1,    -1,     70,  0.1 ,    9,    1, 0.5 ,   -98, 0.05 ,    -45,   20,  30, 4], # 60, 91    [ 6, 1,    1,    -1,     90, -0.1 ,    7,    1,    1,    90,  1.3 ,     34,   13,  16, 1]  # 32, 60]class CamTrack:    def __init__(self, src, dest, dist, len):        self.src = src        self.dest = dest        self.dist = dist        self.len = lenCamTracks = [    CamTrack([4500, 2700, 100, 70, -30], [50, 50, -90, -100, 0], 20, 1),    CamTrack([ -1448, 4294, 25, 363, 0 ], [ -136, 202, 125, -98, 100], 0, 1),    CamTrack([ 1437, 4930, 200, -275, -20 ], [ 1684, 0, 0, 9, 0], 0, 1),    CamTrack([ 1800, 3609, 200, 0, 675 ], [ 0, 0, 0, 300, 0], 0, 1),    CamTrack([ 923, 996, 50, 2336, -80 ], [ 0, -20, -50, 0, 170], 0, 1),    CamTrack([ -1663, -43, 600, 2170, 0 ], [ 20, 0, -600, 0, 100], 0, 1),    CamTrack([ 1049, -1420, 175, 2111, -17 ], [ 0, 0, 0, -334, 0], 0, 2),    CamTrack([ 0, 0, 50, 300, 25 ], [ 0, 0, 0, 300, 0], 70, 2),    CamTrack([ -473, -953, 3500, -353, -350 ], [ 0, 0, -2800, 0, 0], 0, 2),    CamTrack([ 191, 1938, 35, 1139, -17 ], [ 1205, -2909, 0, 0, 0], 0, 2),    CamTrack([ -1449, -2700, 150, 0, 0 ], [ 0, 2000, 0, 0, 0], 0, 2),    CamTrack([ 5273, 4992, 650, 373, -50 ], [ -4598, -3072, 0, 0, 0], 0, 2),    CamTrack([ 3223, -3282, 1075, -393, -25 ], [ 1649, -1649, 0, 0, 0], 0, 2),]CAMTRACK_LEN = 5442FlatVertexSource = """attribute vec3 pos;attribute vec4 colorIn;uniform mat4 mvp;varying vec4 color;void main() {    color = colorIn;    gl_Position = mvp * vec4(pos.xyz, 1.);}"""FlatFragmentSource = """#ifdef GL_ESprecision highp float;#endifvarying vec4 color;void main() {    gl_FragColor = vec4(color.rgb, 1.0);}"""LitVertexSource = """attribute vec3 pos;attribute vec3 normal;attribute vec4 colorIn;varying vec4 color;uniform mat4 mvp;uniform mat3 normalMatrix;uniform vec4 ambient;uniform float shininess;uniform vec3 light_0_direction;uniform vec4 light_0_diffuse;uniform vec4 light_0_specular;uniform vec3 light_1_direction;uniform vec4 light_1_diffuse;uniform vec3 light_2_direction;uniform vec4 light_2_diffuse;vec3 worldNormal;vec4 SpecularLight(vec3 direction,                   vec4 diffuseColor,                   vec4 specularColor) {    vec3 lightDir = normalize(direction);    float diffuse = max(0., dot(worldNormal, lightDir));    float specular = 0.;    if (diffuse > 0.) {        vec3 halfv = normalize(lightDir + vec3(0., 0., 1.));        specular = pow(max(0., dot(halfv, worldNormal)), shininess);    }    return diffuse * diffuseColor * colorIn + specular * specularColor;}vec4 DiffuseLight(vec3 direction, vec4 diffuseColor) {    vec3 lightDir = normalize(direction);    float diffuse = max(0., dot(worldNormal, lightDir));    return diffuse * diffuseColor * colorIn;}void main() {    worldNormal = normalize(normalMatrix * normal);    gl_Position = mvp * vec4(pos, 1.);    color = ambient * colorIn;    color += SpecularLight(light_0_direction, light_0_diffuse,                           light_0_specular);    color += DiffuseLight(light_1_direction, light_1_diffuse);    color += DiffuseLight(light_2_direction, light_2_diffuse);}"""FadeVertexSource = """#ifdef GL_ESprecision highp float;#endifattribute vec2 pos;varying vec4 color;uniform float minFade;void main() {    color = vec4(minFade, minFade, minFade, 1.);    gl_Position = vec4(pos, 0., 1.);}"""class Random:    def __init__(self, seed):        self.randomSeed = seed    def seed(self, seed):        self.randomSeed = seed    def uInt(self):        self.randomSeed = (self.randomSeed * 0x343fd + 0x269ec3) & 0xffffffff        return (self.randomSeed >> 16) & 0xfffclass GlObject:    def __init__(self, gl, shader, vertices, colors, normals=None):        self.shader = shader        self.count = len(vertices) / 3        self.vbo = gl.createBuffer()        vertexArray = gl.Float32Array(vertices)        colorArray = gl.Uint8Array(colors)        self.vertexOffset = 0        self.colorOffset = vertexArray.byteLength        self.normalOffset = self.colorOffset + colorArray.byteLength        sizeInBytes = self.normalOffset        normalArray = None        self.hasNormals = normals != None        if normals:            normalArray = gl.Float32Array(normals)            sizeInBytes += normalArray.byteLength        gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)        gl.bufferData(gl.ARRAY_BUFFER, sizeInBytes, gl.STATIC_DRAW)        gl.bufferSubData(gl.ARRAY_BUFFER, self.vertexOffset, vertexArray)        gl.bufferSubData(gl.ARRAY_BUFFER, self.colorOffset, colorArray)        if normals:            gl.bufferSubData(gl.ARRAY_BUFFER, self.normalOffset, normalArray)    def draw(self):        self.shader.use()        gl.bindBuffer(gl.ARRAY_BUFFER, self.vbo)        gl.vertexAttribPointer(self.shader.posLoc, 3, gl.FLOAT, False, 0, self.vertexOffset)        gl.enableVertexAttribArray(self.shader.posLoc)        gl.vertexAttribPointer(self.shader.colorInLoc, 4, gl.UNSIGNED_BYTE, True, 0, self.colorOffset)        gl.enableVertexAttribArray(self.shader.colorInLoc)        if self.hasNormals:            gl.vertexAttribPointer(self.shader.normalLoc, 3, gl.FLOAT, False, 0, self.normalOffset)            gl.enableVertexAttribArray(self.shader.normalLoc)        gl.drawArrays(gl.TRIANGLES, 0, self.count)        if self.hasNormals:            gl.disableVertexAttribArray(self.shader.normalLoc)        gl.disableVertexAttribArray(self.shader.colorInLoc)        gl.disableVertexAttribArray(self.shader.posLoc)def createGroundPlane(gl, shader, random):    scale = 4    xBegin, xEnd = -15, 15    yBegin, yEnd = -15, 15    triangleCount = (yEnd - yBegin) * (xEnd - xBegin) * 2    colors = []    vertices = []    for y in range(yBegin, yEnd):        for x in range(xBegin, xEnd):            color = (random.uInt() & 0x4f) + 81            for i in range(6):                colors.extend([color, color, color, 0])            for i in range(6):                xm = x + ((0x1c >> a) & 1)                ym = y + ((0x31 >> a) & 1)                m = math.cos(xm * 2) * math.sin(ym * 4) * 0.75                vertices.extend([xm * scale + m, ym * scale + m, 0])    return GlObject(shader, vertices, colors)ground = NonefadeVBO = Noneshapes = Nonemodelview = Noneprojection = Nonemvp = NonenormalMatrix = NonecurrentCamTrackStartTick = 0nextCamTrackStartTick = 0sTick = 0currentCamTrack = 0def main():    global gl, random, modelview, projection, mvp, normalMatrix    modelview = webgl.Mat44()    projection = webgl.Mat44()    mvp = webgl.Mat44()    normalMatrix = webgl.Mat33()    gl = webgl.GL("canv")    gl.enable(gl.DEPTH_TEST)    gl.disable(gl.CULL_FACE)    random = Random(15)    flatShader = webgl.Shader(gl, FlatVertexSource, FlatFragmentSource)    litShader = webgl.Shader(gl, LitVertexSource, FlatFragmentSource)    fadeShader = webgl.Shader(gl, FadeVertexSource, FlatFragmentSource)    # bind non-changing lighting parameters    litShader.use()    gl.uniform4f(litShader.ambientLoc, .2, .2, .2, 1.)    gl.uniform4f(litShader.light_0_diffuseLoc, 1., .4, 0, 1.)    gl.uniform4f(litShader.light_1_diffuseLoc, .07, .14, .35, 1.)    gl.uniform4f(litShader.light_2_diffuseLoc, .07, .17, .14, 1.)    gl.uniform4f(litShader.light_0_specularLoc, 1., 1., 1., 1.)    gl.uniform1f(litShader.shininessLoc, 60.)    shapes = [createSuperShape(litShader, x) for x in ShapeParams]    ground = createGroundPlane(flatShader)def clamp(x, mn=0, mx=255):    return max(min(x, mx), mn)def superShapeMap(r1, r2, t, p):    return gl.Vec3(math.cos(t) * math.cos(p) / r1 / r2,                   math.sin(t) * math.cos(p) / r1 / r2,                   math.sin(p) / r2)def ssFunc(t, p):    return pow(pow(abs(cos(p[0] * t / 4)) / p[1], p[4]) +               pow(abs(sin(p[0] * t / 4)) / p[2], p[5]),               1.0 / p[3])def createSuperShape(shader, params):    resol1 = params[-3]    resol2 = params[-2]    # latitude 0 to pi/2 for no mirrored bottom    # (latitudeBegin==0 for -pi/2 to pi/2 originally)    latitudeBegin = resol2 / 4    latitudeEnd = resol2 / 2    longitudeCount = resol1    vertices = []    colors = []    normals = []    baseColor = [(random.uInt() % 155 + 100) / 255.0 for x in range(3)]    currentVertex = 0    for longitude in range(longitudeCount):        for latitude in range(latitudeBegin, latitudeEnd):            t1 = -math.pi + longitude * 2 * math.pi / resol1            t2 = -math.pi + (longitute + 1) * 2 * math.pi / resol1            p1 = -math.pi / 2 + latitude * 2 * math.pi / resol2            p2 = -math.pi / 2 + (latitude + 1) * 2 * math.pi / resol2            r0 = ssFunc(t1, params)            r1 = ssFunc(p1, params[6:])            r2 = ssFunc(t2)            r3 = ssFunc(p2, params[6:])            if r0 and r1 and r2 and r3:                pa = superShapeMap(r0, r1, t1, p1)                pb = superShapeMap(r2, r1, t2, p1)                pc = superShapeMap(r2, r3, r2, p2)                pd = superShapeMap(r0, r3, t1, p2)                                # kludge to set lower edge of the object to fixed level                if latitude == latitudeBegin + 1:                    pa.z = pb.z = 0                v1 = pb - pa                v2 = pd - pa                n = gl.cross(v1, v2)                                # Pre-normalization of the normals is disabled here because                # they will be normalized anyway later due to automatic                # normalization (NORMALIZE). It is enabled because the                # objects are scaled with scale.                #                # Note we have to normalize by hand in the shader                ca = pa.z + 0.5                for i in range(6):                    normals.extend([n.x, n.y, n.z])                for i in range(6):                    colors.append(clamp(ca * baseColor[0] * 255))                    colors.append(clamp(ca * baseColor[1] * 255))                    colors.append(clamp(ca * baseColor[2] * 255))                    colors.append(0)                vertices.extend([pa.x, pa.y, pa.z])                vertices.extend([pb.x, pb.y, pb.z])                vertices.extend([pd.x, pd.y, pd.z])                vertices.extend([pb.x, pb.y, pb.z])                vertices.extend([pc.x, pc.y, pc.z])                vertices.extend([pd.x, pd.y, pd.z])    return GlObject(gl, shader, vertices, colors, normals)def configureLightAndMaterial():    l0 = modelview.transform3(Vec3(-4., 1., 1.))    l1 = modelview.transform3(Vec3(1., -2., -1.))    l2 = modelview.transform3(Vec3(-1., 0., -4.))    litShader.use()    gl.uniform3f(litShader.light_0_directionLoc, l0.x, l0.y, l0.z)    gl.uniform3f(litShader.light_1_directionLoc, l1.x, l1.y, l1.z)    gl.uniform3f(litShader.light_2_directionLoc, l2.x, l2.y, l2.z)def drawModels(zScale):    translationScale = 9    modelview.scale(1, 1, zScale)    random.seed(9)    for y in range(-5, 5):        for x in range(-5, 5):            curShape = random.uInt() % len(ShapeParams)            buildingScale = ShapeParams[curShape][-1]            modelview.push()            modelview.translate(x * translationScale, y * translationScale, 0)            rv = random.uInt() % 360            modelview.rotate(-rv, 0, 0, 1)            modelview.scale(buildingScale, buildingScale, buildingScale)            shapes[curShape].draw()            modelview.pop()    ship = shapes[-1]    for x in range(-2, 2):        shipScale100 = translationScale * 500        offs100 = x * shipScale100 + (sTick % shipScale100)        offs = 0.01 * offs100        modelview.push()        modelview.translate(offs, -4.0, 2.0)        ship.draw()        modelview.pop()        modelview.push()        modelview.translate(-4., offs, 4.)        modelview.rotate(-90., 0., 0., 1.)        ship.draw()        modelview.pop()def camTrack():    nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN    while nextCamTrackStartTick <= sTick:        ++currentCamTrack        if currentCamTrack >= len(CamTracks):            currentCamTrack = 0        currentCamTrackStartTick = nextCamTrackStartTick        nextCamTrackStartTick = currentCamTrackStartTick + CamTracks[currentCamTrack].len * CAMTRACK_LEN    cam = CamTracks[currentCamTrack]    currentCamTick = sTick - currentCamTrackStartTick    trackPos = currentCamTick / (CAMTRACK_LEN * cam.len)    lerp = [0.01 * cam.src[a] + cam.dest[a] * trackPos for a in range(5)]    if cam.dist:        dist = cam.dist * 0.1        cX = lerp[0]        cY = lerp[1]        cZ = lerp[2]        eX = cX - math.cos(lerp[3]) * dist        eY = cY - math.sin(lerp[3]) * dist        eZ = cZ - lerp[4]    else:        eX = lerp[0]        eY = lerp[1]        eZ = lerp[2]        cX = eX + math.cos(lerp[3])        cY = eY + math.sin(lerp[3])        cZ = eZ + lerp[4]    modelview.lookAt(eX, eY, eZ, cX, cY, cZ, 0, 0, 1)def drawGroundPlane():    gl.disable(gl.CULL_FACE)    gl.disable(gl.DEPTH_TEST)    gl.enable(gl.BLEND)    gl.blendFunc(gl.ZERO, gl.SRC_COLOR)    ground.draw()    gl.disable(gl.BLEND)    gl.enable(gl.DEPTH_TEST)def drawFadeQuad():    global fadeVBO    if not fadeVBO:        vertices = gl.Float32Array([            -1, -1,            1, -1,            -1, 1,            1, -1,            1, 1,            -1, 1])        fadeVBO = gl.createBuffer()        gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)    beginFade = sTick - currentCamTrackStartTick    endFade = nextCamTrackStartTick - sTick    minFade = min(beginFade, endFade)    if minFade < 1024:        gl.disable(gl.DEPTH_TEST)        gl.enable(gl.BLEND)        gl.blendFunc(gl.ZERO, gl.SRC_COLOR)        fadeShader.use()        gl.uniform1f(fadeShader.minFadeLoc, minFade / 1024.0)        gl.bindBuffer(gl.ARRAY_BUFFER, fadeVBO)        gl.vertexAttribPointer(fadeShader.posLoc, 2, gl.FLOAT, false, 0, 0)        gl.enableVertexAttribArray(fadeShader.posLoc)        gl.drawArrays(gl.TRIANGLES, 0, 6)        gl.disableVertexAttribArray(fadeShader.posLoc)        gl.disable(gl.BLEND)        gl.enable(gl.DEPTH_TEST)def draw(gl, width, height):    sTick = (sTick + tick) / 2    gl.clearColor(0.1, 0.2, 0.3, 1.0)    gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT)    projection.loadIdentity()    projection.perspective(45, width / height, 0.5, 100)    modelview.loadIdentity()    camTrack()    configureLightAndMaterial()    modelview.push()    drawModels(-1)    modelview.pop()    drawGroundPlane()    drawModels(1)    drawFadeQuad()main()
 |