ya2 · news · projects · code · about

5d046e9b925b15b50b30d140e1562d75f43590cb
[pmachines.git] / pmachines / scene.py
1 from panda3d.core import AmbientLight, DirectionalLight, Point3
2 from panda3d.bullet import BulletPlaneShape, BulletGhostNode
3 from direct.gui.OnscreenImage import OnscreenImage
4 from direct.gui.DirectGui import DirectButton
5 from direct.gui.DirectGuiGlobals import FLAT, DISABLED, NORMAL
6 from direct.showbase.DirectObject import DirectObject
7 from pmachines.items.background import Background
8 from pmachines.items.box import Box
9 from lib.engine.gui.cursor import MouseCursor
10
11
12 class Scene(DirectObject):
13
14 def __init__(self, world):
15 super().__init__()
16 self._world = world
17 self._set_camera()
18 self._cursor = MouseCursor(
19 'assets/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1),
20 (.01, .01))
21 self._set_gui()
22 self._set_lights()
23 self._set_input()
24 self._set_mouse_plane()
25 Background()
26 self.items = [Box(world, self._mouse_plane_node, 3, self.cb_inst)]
27 taskMgr.add(self.on_frame, 'on_frame')
28
29 def _set_camera(self):
30 base.camera.set_pos(0, -20, 0)
31 base.camera.look_at(0, 0, 0)
32
33 def _set_gui(self):
34 def load_img_btn(path, col):
35 img = OnscreenImage('assets/buttons/%s.png' % path)
36 img.set_transparency(True)
37 img.set_color(col)
38 img.detach_node()
39 return img
40 def load_images_btn(path, col):
41 colors = {
42 'gray': [
43 (.6, .6, .6, 1), # ready
44 (1, 1, 1, 1), # press
45 (.8, .8, .8, 1), # rollover
46 (.4, .4, .4, .4)],
47 'green': [
48 (.1, .68, .1, 1),
49 (.1, 1, .1, 1),
50 (.1, .84, .1, 1),
51 (.4, .1, .1, .4)]}[col]
52 return [load_img_btn(path, col) for col in colors]
53 abl, abr = base.a2dBottomLeft, base.a2dBottomRight
54 btn_info = [
55 ('home', self.on_home, DISABLED, abl, 'gray'),
56 ('information', self.on_information, DISABLED, abl, 'gray'),
57 ('right', self.on_play, NORMAL, abr, 'green'),
58 ('next', self.on_next, DISABLED, abr, 'gray'),
59 ('previous', self.on_prev, DISABLED, abr, 'gray'),
60 ('rewind', self.on_rewind, DISABLED, abr, 'gray')]
61 num_l = num_r = 0
62 for binfo in btn_info:
63 imgs = load_images_btn(binfo[0], binfo[4])
64 if binfo[3] == base.a2dBottomLeft:
65 sign, num = 1, num_l
66 num_l += 1
67 else:
68 sign, num = -1, num_r
69 num_r += 1
70 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
71 btn = DirectButton(
72 image=imgs, scale=.05, pos=(sign * (.06 + .11 * num), 1, .06),
73 parent=binfo[3], command=binfo[1], state=binfo[2], relief=FLAT,
74 frameColor=fcols[0] if binfo[2] == NORMAL else fcols[1],
75 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
76 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
77 btn.set_transparency(True)
78
79 def _set_directional_light(self, name, hpr, color):
80 light = DirectionalLight(name)
81 light_np = render.attach_new_node(light)
82 light_np.set_hpr(*hpr)
83 light.set_color(color)
84 render.set_light(light_np)
85
86 def _set_lights(self):
87 alight = AmbientLight('alight') # for ao
88 alight.set_color((.4, .4, .4, 1))
89 alnp = render.attach_new_node(alight)
90 render.set_light(alnp)
91 self._set_directional_light('key light', (315, -60, 0),
92 (3.6, 3.6, 3.6, 1))
93 self._set_directional_light('fill light', (195, -30, 0),
94 (.4, .4, .4, 1))
95 self._set_directional_light('rim light', (75, -30, 0), (.3, .3, .3, 1))
96
97 def _set_input(self):
98 self.accept('mouse1', self.on_click_l)
99 self.accept('mouse1-up', self.on_release)
100 self.accept('mouse3', self.on_click_r)
101 self.accept('mouse3-up', self.on_release)
102
103 def _set_mouse_plane(self):
104 shape = BulletPlaneShape((0, -1, 0), 1)
105 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
106 self._mouse_plane_node = BulletGhostNode('mouse plane')
107 self._mouse_plane_node.addShape(shape)
108 #np = render.attachNewNode(self._mouse_plane_node)
109 #self._world.attachRigidBody(self._mouse_plane_node)
110 self._world.attachGhost(self._mouse_plane_node)
111
112 def _get_hits(self):
113 if not base.mouseWatcherNode.has_mouse(): return []
114 p_from, p_to = Point3(), Point3() # in camera coordinates
115 base.camLens.extrude(base.mouseWatcherNode.get_mouse(), p_from, p_to)
116 p_from = render.get_relative_point(base.cam, p_from) # global coords
117 p_to = render.get_relative_point(base.cam, p_to) # global coords
118 return self._world.ray_test_all(p_from, p_to).get_hits()
119
120 def _on_click(self, method):
121 for hit in self._get_hits():
122 if hit.get_node() == self._mouse_plane_node:
123 pos = hit.get_hit_pos()
124 for hit in self._get_hits():
125 for item in [i for i in self.items if hit.get_node() == i.node]:
126 getattr(item, method)(pos)
127 img = 'move' if method == 'on_click_l' else 'rotate'
128 self._cursor.set_image('assets/buttons/%s.png' % img)
129
130 def on_click_l(self):
131 self._on_click('on_click_l')
132
133 def on_click_r(self):
134 self._on_click('on_click_r')
135
136 def on_release(self):
137 [item.on_release() for item in self.items]
138 self._cursor.set_image('assets/buttons/arrowUpLeft.png')
139
140 def on_frame(self, task):
141 hits = self._get_hits()
142 pos = None
143 for hit in self._get_hits():
144 if hit.get_node() == self._mouse_plane_node:
145 pos = hit.get_hit_pos()
146 hit_nodes = [hit.get_node() for hit in hits]
147 items_hit = [itm for itm in self.items if itm.node in hit_nodes]
148 items_no_hit = [itm for itm in self.items if itm not in items_hit]
149 [itm.on_mouse_on() for itm in items_hit]
150 [itm.on_mouse_off() for itm in items_no_hit]
151 if pos:
152 [itm.on_mouse_move(pos) for itm in self.items]
153 return task.cont
154
155 def cb_inst(self, item):
156 self.items += [item]
157
158 def on_play(self):
159 [itm.play() for itm in self.items]
160
161 def on_next(self):
162 print('on_next')
163
164 def on_prev(self):
165 print('on_prev')
166
167 def on_rewind(self):
168 print('on_rewind')
169
170 def on_home(self):
171 print('on_home')
172
173 def on_information(self):
174 print('on_information')