ya2 · news · projects · code · about

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