Commit | Line | Data |
---|---|---|
2aaa10d3 | 1 | from panda3d.core import AmbientLight, DirectionalLight, Point3, Texture, \ |
5fdf77d0 | 2 | TextPropertiesManager, TextNode, Spotlight, PerspectiveLens |
36099535 FC |
3 | from panda3d.bullet import BulletPlaneShape, BulletGhostNode |
4 | from direct.gui.OnscreenImage import OnscreenImage | |
2aaa10d3 FC |
5 | from direct.gui.OnscreenText import OnscreenText |
6 | from direct.gui.DirectGui import DirectButton, DirectFrame | |
36099535 | 7 | from direct.gui.DirectGuiGlobals import FLAT, DISABLED, NORMAL |
1be87278 FC |
8 | from direct.showbase.DirectObject import DirectObject |
9 | from pmachines.items.background import Background | |
10 | from pmachines.items.box import Box | |
a5dc83f4 | 11 | from pmachines.sidepanel import SidePanel |
79f81d48 | 12 | from lib.engine.gui.cursor import MouseCursor |
13263131 | 13 | from lib.lib.p3d.gfx import P3dGfxMgr |
1be87278 FC |
14 | |
15 | ||
16 | class Scene(DirectObject): | |
17 | ||
e669403e | 18 | def __init__(self, world, exit_cb, auto_close_instr): |
1be87278 FC |
19 | super().__init__() |
20 | self._world = world | |
5964572b | 21 | self._exit_cb = exit_cb |
1be87278 | 22 | self._set_camera() |
79f81d48 FC |
23 | self._cursor = MouseCursor( |
24 | 'assets/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1), | |
25 | (.01, .01)) | |
36099535 | 26 | self._set_gui() |
1be87278 FC |
27 | self._set_lights() |
28 | self._set_input() | |
c8d8653f | 29 | self._set_mouse_plane() |
a0acba9a FC |
30 | self.items = [Box(world, self._mouse_plane_node, 3, self.cb_inst)] |
31 | self._paused = True | |
32 | self.__store_state() | |
e669403e FC |
33 | if auto_close_instr: |
34 | self.__restore_state() | |
35 | else: | |
36 | self._set_instructions() | |
5964572b FC |
37 | self._bg = Background() |
38 | self._side_panel = SidePanel(world, self._mouse_plane_node, (-5, 4), (-3, 1), 1, self.items) | |
39 | self._scene_tsk = taskMgr.add(self.on_frame, 'on_frame') | |
40 | ||
41 | def destroy(self): | |
42 | self._unset_gui() | |
43 | self._unset_lights() | |
44 | self._unset_input() | |
45 | self._unset_mouse_plane() | |
46 | [itm.destroy() for itm in self.items] | |
47 | self._bg.destroy() | |
48 | self._side_panel.destroy() | |
49 | taskMgr.remove(self._scene_tsk) | |
1be87278 FC |
50 | |
51 | def _set_camera(self): | |
52 | base.camera.set_pos(0, -20, 0) | |
53 | base.camera.look_at(0, 0, 0) | |
54 | ||
a0acba9a FC |
55 | def __load_img_btn(self, path, col): |
56 | img = OnscreenImage('assets/buttons/%s.png' % path) | |
57 | img.set_transparency(True) | |
58 | img.set_color(col) | |
59 | img.detach_node() | |
60 | return img | |
61 | ||
36099535 | 62 | def _set_gui(self): |
01b221a6 FC |
63 | def load_images_btn(path, col): |
64 | colors = { | |
65 | 'gray': [ | |
66 | (.6, .6, .6, 1), # ready | |
67 | (1, 1, 1, 1), # press | |
68 | (.8, .8, .8, 1), # rollover | |
69 | (.4, .4, .4, .4)], | |
70 | 'green': [ | |
71 | (.1, .68, .1, 1), | |
72 | (.1, 1, .1, 1), | |
73 | (.1, .84, .1, 1), | |
74 | (.4, .1, .1, .4)]}[col] | |
a0acba9a | 75 | return [self.__load_img_btn(path, col) for col in colors] |
36099535 FC |
76 | abl, abr = base.a2dBottomLeft, base.a2dBottomRight |
77 | btn_info = [ | |
5964572b | 78 | ('home', self.on_home, NORMAL, abl, 'gray'), |
01b221a6 FC |
79 | ('information', self.on_information, DISABLED, abl, 'gray'), |
80 | ('right', self.on_play, NORMAL, abr, 'green'), | |
81 | ('next', self.on_next, DISABLED, abr, 'gray'), | |
82 | ('previous', self.on_prev, DISABLED, abr, 'gray'), | |
83 | ('rewind', self.on_rewind, DISABLED, abr, 'gray')] | |
36099535 | 84 | num_l = num_r = 0 |
a0acba9a | 85 | btns = [] |
36099535 | 86 | for binfo in btn_info: |
01b221a6 | 87 | imgs = load_images_btn(binfo[0], binfo[4]) |
36099535 FC |
88 | if binfo[3] == base.a2dBottomLeft: |
89 | sign, num = 1, num_l | |
90 | num_l += 1 | |
91 | else: | |
92 | sign, num = -1, num_r | |
93 | num_r += 1 | |
94 | fcols = (.4, .4, .4, .14), (.3, .3, .3, .05) | |
95 | btn = DirectButton( | |
96 | image=imgs, scale=.05, pos=(sign * (.06 + .11 * num), 1, .06), | |
97 | parent=binfo[3], command=binfo[1], state=binfo[2], relief=FLAT, | |
54a1397e FC |
98 | frameColor=fcols[0] if binfo[2] == NORMAL else fcols[1], |
99 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
100 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
36099535 | 101 | btn.set_transparency(True) |
a0acba9a FC |
102 | btns += [btn] |
103 | self.__home_btn, self.__info_btn, self.__right_btn, self.__next_btn, \ | |
104 | self.__prev_btn, self.__rewind_btn = btns | |
36099535 | 105 | |
5964572b FC |
106 | def _unset_gui(self): |
107 | btns = [ | |
108 | self.__home_btn, self.__info_btn, self.__right_btn, | |
109 | self.__next_btn, self.__prev_btn, self.__rewind_btn] | |
110 | [btn.destroy() for btn in btns] | |
111 | ||
1be87278 FC |
112 | def _set_directional_light(self, name, hpr, color): |
113 | light = DirectionalLight(name) | |
114 | light_np = render.attach_new_node(light) | |
115 | light_np.set_hpr(*hpr) | |
116 | light.set_color(color) | |
117 | render.set_light(light_np) | |
5964572b | 118 | return light_np |
1be87278 FC |
119 | |
120 | def _set_lights(self): | |
121 | alight = AmbientLight('alight') # for ao | |
122 | alight.set_color((.4, .4, .4, 1)) | |
123 | alnp = render.attach_new_node(alight) | |
124 | render.set_light(alnp) | |
5964572b FC |
125 | self._key_light = self._set_directional_light( |
126 | 'key light', (315, -60, 0), (3.6, 3.6, 3.6, 1)) | |
127 | self._fill_light = self._set_directional_light( | |
128 | 'fill light', (195, -30, 0), (.4, .4, .4, 1)) | |
129 | self._rim_light = self._set_directional_light( | |
130 | 'rim light', (75, -30, 0), (.3, .3, .3, 1)) | |
5fdf77d0 FC |
131 | slight = Spotlight('slight') |
132 | slight.set_color((.1, .1, .1, 1)) | |
133 | slight.setLens(PerspectiveLens()) | |
134 | self.__shadow_light = render.attachNewNode(slight) | |
135 | self.__shadow_light.set_pos(-5, -80, 5) | |
136 | self.__shadow_light.look_at((0, 0, 0)) | |
137 | render.set_light(self.__shadow_light) | |
138 | self.__shadow_light.node().set_shadow_caster(True, 2048, 2048) | |
139 | self.__shadow_light.node().get_lens().set_film_size(2048, 2048) | |
140 | self.__shadow_light.node().get_lens().set_near_far(1, 256) | |
5964572b FC |
141 | |
142 | def _unset_lights(self): | |
5fdf77d0 FC |
143 | for light in [self._key_light, self._fill_light, self._rim_light, |
144 | self.__shadow_light]: | |
5964572b FC |
145 | render.clear_light(light) |
146 | light.remove_node() | |
1be87278 FC |
147 | |
148 | def _set_input(self): | |
49c79300 | 149 | self.accept('mouse1', self.on_click_l) |
c8d8653f | 150 | self.accept('mouse1-up', self.on_release) |
49c79300 FC |
151 | self.accept('mouse3', self.on_click_r) |
152 | self.accept('mouse3-up', self.on_release) | |
c8d8653f | 153 | |
5964572b FC |
154 | def _unset_input(self): |
155 | for evt in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']: | |
156 | self.ignore(evt) | |
157 | ||
c8d8653f | 158 | def _set_mouse_plane(self): |
651713a9 | 159 | shape = BulletPlaneShape((0, -1, 0), 0) |
c8d8653f FC |
160 | #self._mouse_plane_node = BulletRigidBodyNode('mouse plane') |
161 | self._mouse_plane_node = BulletGhostNode('mouse plane') | |
162 | self._mouse_plane_node.addShape(shape) | |
163 | #np = render.attachNewNode(self._mouse_plane_node) | |
164 | #self._world.attachRigidBody(self._mouse_plane_node) | |
06af3aa9 | 165 | self._world.attach_ghost(self._mouse_plane_node) |
1be87278 | 166 | |
5964572b FC |
167 | def _unset_mouse_plane(self): |
168 | self._world.remove_ghost(self._mouse_plane_node) | |
169 | ||
37ba71d8 FC |
170 | def _get_hits(self): |
171 | if not base.mouseWatcherNode.has_mouse(): return [] | |
13263131 | 172 | p_from, p_to = P3dGfxMgr.world_from_to(base.mouseWatcherNode.get_mouse()) |
37ba71d8 FC |
173 | return self._world.ray_test_all(p_from, p_to).get_hits() |
174 | ||
49c79300 | 175 | def _on_click(self, method): |
a0acba9a FC |
176 | if self._paused: |
177 | return | |
c8d8653f FC |
178 | for hit in self._get_hits(): |
179 | if hit.get_node() == self._mouse_plane_node: | |
180 | pos = hit.get_hit_pos() | |
37ba71d8 | 181 | for hit in self._get_hits(): |
1be87278 | 182 | for item in [i for i in self.items if hit.get_node() == i.node]: |
49c79300 | 183 | getattr(item, method)(pos) |
79f81d48 FC |
184 | img = 'move' if method == 'on_click_l' else 'rotate' |
185 | self._cursor.set_image('assets/buttons/%s.png' % img) | |
49c79300 FC |
186 | |
187 | def on_click_l(self): | |
188 | self._on_click('on_click_l') | |
189 | ||
190 | def on_click_r(self): | |
191 | self._on_click('on_click_r') | |
c8d8653f FC |
192 | |
193 | def on_release(self): | |
49c79300 | 194 | [item.on_release() for item in self.items] |
79f81d48 | 195 | self._cursor.set_image('assets/buttons/arrowUpLeft.png') |
37ba71d8 | 196 | |
651713a9 FC |
197 | def on_aspect_ratio_changed(self): |
198 | [item.on_aspect_ratio_changed() for item in self.items] | |
a5dc83f4 | 199 | self._side_panel.update(self.items) |
651713a9 | 200 | |
37ba71d8 | 201 | def on_frame(self, task): |
c8d8653f FC |
202 | hits = self._get_hits() |
203 | pos = None | |
204 | for hit in self._get_hits(): | |
205 | if hit.get_node() == self._mouse_plane_node: | |
206 | pos = hit.get_hit_pos() | |
207 | hit_nodes = [hit.get_node() for hit in hits] | |
37ba71d8 FC |
208 | items_hit = [itm for itm in self.items if itm.node in hit_nodes] |
209 | items_no_hit = [itm for itm in self.items if itm not in items_hit] | |
210 | [itm.on_mouse_on() for itm in items_hit] | |
211 | [itm.on_mouse_off() for itm in items_no_hit] | |
c8d8653f FC |
212 | if pos: |
213 | [itm.on_mouse_move(pos) for itm in self.items] | |
37ba71d8 | 214 | return task.cont |
c8d8653f | 215 | |
7850ccc4 FC |
216 | def cb_inst(self, item): |
217 | self.items += [item] | |
218 | ||
c8d8653f FC |
219 | def on_play(self): |
220 | [itm.play() for itm in self.items] | |
36099535 FC |
221 | |
222 | def on_next(self): | |
223 | print('on_next') | |
224 | ||
225 | def on_prev(self): | |
226 | print('on_prev') | |
227 | ||
228 | def on_rewind(self): | |
229 | print('on_rewind') | |
230 | ||
231 | def on_home(self): | |
5964572b | 232 | self._exit_cb() |
36099535 FC |
233 | |
234 | def on_information(self): | |
235 | print('on_information') | |
2aaa10d3 FC |
236 | |
237 | def _set_instructions(self): | |
238 | mgr = TextPropertiesManager.get_global_ptr() | |
239 | for name in ['mouse_l', 'mouse_r']: | |
240 | graphic = OnscreenImage('assets/buttons/%s.png' % name) | |
241 | graphic.set_scale(.5) | |
242 | graphic.get_texture().set_minfilter(Texture.FTLinearMipmapLinear) | |
243 | graphic.get_texture().set_anisotropic_degree(2) | |
244 | mgr.set_graphic(name, graphic) | |
245 | graphic.set_z(-.2) | |
246 | graphic.set_transparency(True) | |
247 | graphic.detach_node() | |
248 | frm = DirectFrame(frameColor=(.4, .4, .4, .06), | |
249 | frameSize=(-.6, .6, -.3, .3)) | |
250 | font = base.loader.load_font('assets/fonts/Hanken-Book.ttf') | |
251 | font.clear() | |
252 | font.set_pixels_per_unit(60) | |
253 | font.set_minfilter(Texture.FTLinearMipmapLinear) | |
254 | font.set_outline((0, 0, 0, 1), .8, .2) | |
255 | txt = _('keep \5mouse_l\5 pressed to drag an item\n\n' | |
256 | 'keep \5mouse_r\5 pressed to rotate an item') | |
257 | self._txt = OnscreenText( | |
258 | txt, parent=frm, font=font, scale=0.06, fg=(.9, .9, .9, 1), | |
259 | align=TextNode.A_left) | |
260 | u_l = self._txt.textNode.get_upper_left_3d() | |
261 | l_r = self._txt.textNode.get_lower_right_3d() | |
262 | w, h = l_r[0] - u_l[0], u_l[2] - l_r[2] | |
a0acba9a FC |
263 | btn_scale = .05 |
264 | mar = .06 # margin | |
2aaa10d3 | 265 | z = h / 2 - font.get_line_height() * self._txt['scale'][1] |
a0acba9a | 266 | z += (btn_scale + 2 * mar) / 2 |
2aaa10d3 FC |
267 | self._txt['pos'] = -w / 2, z |
268 | u_l = self._txt.textNode.get_upper_left_3d() | |
269 | l_r = self._txt.textNode.get_lower_right_3d() | |
a0acba9a FC |
270 | c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale |
271 | fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar | |
2aaa10d3 | 272 | frm['frameSize'] = fsz |
a0acba9a FC |
273 | colors = [ |
274 | (.6, .6, .6, 1), # ready | |
275 | (1, 1, 1, 1), # press | |
276 | (.8, .8, .8, 1), # rollover | |
277 | (.4, .4, .4, .4)] | |
278 | imgs = [self.__load_img_btn('exitRight', col) for col in colors] | |
279 | btn = DirectButton( | |
280 | image=imgs, scale=btn_scale, | |
281 | pos=(l_r[0] - btn_scale, 1, l_r[2] - mar - btn_scale), | |
282 | parent=frm, command=self.__on_close_instructions, extraArgs=[frm], | |
283 | relief=FLAT, frameColor=(.6, .6, .6, .08), | |
284 | rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'), | |
285 | clickSound=loader.load_sfx('assets/audio/sfx/click.ogg')) | |
286 | btn.set_transparency(True) | |
287 | ||
288 | def __store_state(self): | |
289 | btns = [ | |
290 | self.__home_btn, self.__info_btn, self.__right_btn, | |
291 | self.__next_btn, self.__prev_btn, self.__rewind_btn] | |
292 | self.__btn_state = [btn['state'] for btn in btns] | |
293 | for btn in btns: | |
294 | btn['state'] = DISABLED | |
295 | [itm.store_state() for itm in self.items] | |
296 | ||
297 | def __restore_state(self): | |
298 | btns = [ | |
299 | self.__home_btn, self.__info_btn, self.__right_btn, | |
300 | self.__next_btn, self.__prev_btn, self.__rewind_btn] | |
301 | for btn, state in zip(btns, self.__btn_state): | |
302 | btn['state'] = state | |
303 | [itm.restore_state() for itm in self.items] | |
304 | self._paused = False | |
305 | ||
306 | def __on_close_instructions(self, frm): | |
307 | frm.remove_node() | |
308 | self.__restore_state() |