ya2 · news · projects · code · about

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