1#!/usr/bin/env python
2# coding: utf-8
3
4###
5# Copyright (c) 2005 Øystein Handegard <handegar@sim.no>
6#
7# Permission to use, copy, modify, and distribute this software for any
8# purpose with or without fee is hereby granted, provided that the above
9# copyright notice and this permission notice appear in all copies.
10#
11# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18#
19
20from __future__ import print_function
21import math
22from pivy.coin import *
23from pivy.sogui import *
24
25##############################################################
26
27def generateColoredLights(distance):
28    scenegraph = SoSeparator()
29    rotor = SoRotor()
30    rotor.rotation = (1, 1, 1, 0)
31    rotor.speed = 0.2
32
33    redlight = SoPointLight()
34    redlight.color = (1, 0, 0)
35    redlight.location = (0, distance, 0)
36
37    goldlight = SoPointLight()
38    goldlight.color = (1, 185.0/256, 75.0/256)
39    goldlight.location = (distance, 0, 0)
40
41    trans = SoTranslation()
42    trans.translation = (distance, 0, distance)
43
44    scenegraph.addChild(rotor)
45    scenegraph.addChild(redlight)
46    scenegraph.addChild(rotor)
47    scenegraph.addChild(goldlight)
48    return scenegraph
49
50def generateTile(height, width, thickness):
51    h = height*(1-(8*thickness))
52    w = width*(1-(8*thickness))
53    s = (8*thickness)+1.0
54    t = -thickness
55
56    points = ((0, -w/2.0, -h/2.0), (0, w/2.0, -h/2.0), (0, w/2.0, h/2.0), (0, -w/2.0, h/2.0),
57              (t, -(s*w)/2.0, -(s*h)/2.0), (t, (s*w)/2.0, (-s*h)/2.0), (t, (s*w)/2.0, (s*h)/2.0), (t, (-s*w)/2.0, (s*h)/2.0))
58    indices = (0, 1, 2, 3, -1,  4, 5, 1, 0, -1,  5, 6, 2, 1, -1,  3, 2, 6, 7, -1,  0, 3, 7, 4, -1 )
59
60    coordset = SoCoordinate3()
61    coordset.point.setValues(0, len(points), points)
62
63    faceset = SoIndexedFaceSet()
64    faceset.coordIndex.setValues(0, len(indices), indices)
65
66    sep = SoSeparator()
67    sep.addChild(coordset)
68    sep.addChild(faceset)
69
70    return sep
71
72
73def generateMirrorBall(radius, tileheight, tilewidth):
74    root = SoSeparator()
75
76    tilethickness = ((tilewidth + tileheight)/2.0)/50.0 # looks nice
77    tile = generateTile(tileheight, tilewidth, tilethickness)
78
79    radiustrans = SoTranslation()
80    radiustrans.translation = SbVec3f(radius,0,0)
81
82    mirrormat = SoMaterial()
83    mirrormat.specularColor = (1, 1, 1)
84    mirrormat.diffuseColor = (0.2, 0.2, 0.2)
85    mirrormat.shinyness = 0.5
86    root.addChild(mirrormat)
87
88    rot1 = SbRotation()
89    rot2 = SbRotation()
90
91    x = M_PI
92    anglesteplong = M_PI / (2.0 * math.asin(tileheight / (2.0 * radius)))
93    anglesteplat = M_PI / (2.0 * math.asin(tilewidth / (2.0 * radius)))
94
95    while x > 0:
96        y = M_PI*2
97        while y > 0:
98            sep = SoSeparator()
99            rot1.setValue(SbVec3f(0,0,1), x)
100            rot2.setValue(SbVec3f(1, 0, 0), y)
101            y = y - (M_PI*2 / ((anglesteplong*2)*math.sin(x)))
102            rot = SoRotation()
103            rot.rotation = (rot1*rot2)
104            sep.addChild(rot)
105            sep.addChild(radiustrans)
106            sep.addChild(tile)
107            root.addChild(sep)
108        x = x - (M_PI / anglesteplat)
109
110    return root
111
112##############################################################
113
114def main():
115    myWindow = SoGui.init(sys.argv[0])
116    if myWindow == None: sys.exit(1)
117
118    # Radius and tile size of the mirror-ball
119    radius = 8
120    tilesizex = 1
121    tilesizey = 0.8
122
123    # Create rotating lights around the ball
124    lights = generateColoredLights(radius * 50.0)
125    lights.addChild(SoResetTransform())
126
127    # Generate mirror ball.
128    print("Generating a mirror ball with radius %d and tile size %.1fx%.1f..." % (radius, tilesizex, tilesizey))
129    lights.addChild(generateMirrorBall(radius, tilesizex, tilesizey))
130    print("...finished.")
131
132    # setup viewer
133    myViewer = SoGuiExaminerViewer(myWindow)
134    myViewer.setSceneGraph(lights)
135    myViewer.setTitle("Examiner Viewer")
136    myViewer.viewAll()
137    myViewer.show()
138
139    SoGui.show(myWindow)
140    SoGui.mainLoop()
141
142    return 0
143
144if __name__ == "__main__":
145    sys.exit(main())
146