1 from panda3d
.core
import AmbientLight
, DirectionalLight
, Point3
, Texture
, \
2 TextPropertiesManager
, TextNode
, Spotlight
, PerspectiveLens
, BitMask32
3 from panda3d
.bullet
import BulletPlaneShape
, BulletGhostNode
4 from direct
.gui
.OnscreenImage
import OnscreenImage
5 from direct
.gui
.OnscreenText
import OnscreenText
6 from direct
.gui
.DirectGui
import DirectButton
, DirectFrame
7 from direct
.gui
.DirectGuiGlobals
import FLAT
, DISABLED
, NORMAL
8 from direct
.showbase
.DirectObject
import DirectObject
9 from pmachines
.items
.background
import Background
10 from pmachines
.items
.box
import Box
11 from pmachines
.sidepanel
import SidePanel
12 from lib
.engine
.gui
.cursor
import MouseCursor
13 from lib
.lib
.p3d
.gfx
import P3dGfxMgr
16 class Scene(DirectObject
):
18 def __init__(self
, world
, exit_cb
, auto_close_instr
):
21 self
._exit
_cb
= exit_cb
23 self
._cursor
= MouseCursor(
24 'assets/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1),
29 self
._set
_mouse
_plane
()
30 self
.items
= [Box(world
, self
._mouse
_plane
_node
, 3, self
.cb_inst
)]
34 self
._item
_active
= None
37 self
.__restore
_state
()
39 self
._set
_instructions
()
40 self
._bg
= Background()
41 self
._side
_panel
= SidePanel(world
, self
._mouse
_plane
_node
, (-5, 4), (-3, 1), 1, self
.items
)
42 self
._scene
_tsk
= taskMgr
.add(self
.on_frame
, 'on_frame')
47 [itm
.destroy() for itm
in self
.items
]
48 self
.items
= [Box(self
._world
, self
._mouse
_plane
_node
, 3, self
.cb_inst
)]
54 self
._unset
_mouse
_plane
()
55 [itm
.destroy() for itm
in self
.items
]
57 self
._side
_panel
.destroy()
58 self
._cursor
.destroy()
59 taskMgr
.remove(self
._scene
_tsk
)
61 def _set_camera(self
):
62 base
.camera
.set_pos(0, -20, 0)
63 base
.camera
.look_at(0, 0, 0)
65 def __load_img_btn(self
, path
, col
):
66 img
= OnscreenImage('assets/buttons/%s.png' % path
)
67 img
.set_transparency(True)
73 def load_images_btn(path
, col
):
76 (.6, .6, .6, 1), # ready
78 (.8, .8, .8, 1), # rollover
84 (.4, .1, .1, .4)]}[col
]
85 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
86 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
88 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
89 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
90 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
91 ('next', self
.on_next
, DISABLED
, abr
, 'gray'),
92 ('previous', self
.on_prev
, DISABLED
, abr
, 'gray'),
93 ('rewind', self
.reset
, NORMAL
, abr
, 'gray')]
96 for binfo
in btn_info
:
97 imgs
= load_images_btn(binfo
[0], binfo
[4])
98 if binfo
[3] == base
.a2dBottomLeft
:
102 sign
, num
= -1, num_r
104 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
106 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
107 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
108 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
109 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
110 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
111 btn
.set_transparency(True)
113 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
114 self
.__prev
_btn
, self
.__rewind
_btn
= btns
116 def _unset_gui(self
):
118 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
119 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
120 [btn
.destroy() for btn
in btns
]
122 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
123 light
= Spotlight(name
)
125 light
.setLens(PerspectiveLens())
126 light_np
= render
.attach_new_node(light
)
127 light_np
.set_pos(pos
)
128 light_np
.look_at(look_at
)
129 light
.set_color(color
)
130 render
.set_light(light_np
)
133 def _set_lights(self
):
134 alight
= AmbientLight('alight') # for ao
135 alight
.set_color((.15, .15, .15, 1))
136 self
._alnp
= render
.attach_new_node(alight
)
137 render
.set_light(self
._alnp
)
138 self
._key
_light
= self
._set
_spotlight
(
139 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
140 self
._shadow
_light
= self
._set
_spotlight
(
141 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
142 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
143 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
144 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
145 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
147 def _unset_lights(self
):
148 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
149 render
.clear_light(light
)
152 def _set_input(self
):
153 self
.accept('mouse1', self
.on_click_l
)
154 self
.accept('mouse1-up', self
.on_release
)
155 self
.accept('mouse3', self
.on_click_r
)
156 self
.accept('mouse3-up', self
.on_release
)
158 def _unset_input(self
):
159 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
162 def _set_mouse_plane(self
):
163 shape
= BulletPlaneShape((0, -1, 0), 0)
164 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
165 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
166 self
._mouse
_plane
_node
.addShape(shape
)
167 #np = render.attachNewNode(self._mouse_plane_node)
168 #self._world.attachRigidBody(self._mouse_plane_node)
169 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
171 def _unset_mouse_plane(self
):
172 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
175 if not base
.mouseWatcherNode
.has_mouse(): return []
176 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
177 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
179 def _on_click(self
, method
):
182 for hit
in self
._get
_hits
():
183 if hit
.get_node() == self
._mouse
_plane
_node
:
184 pos
= hit
.get_hit_pos()
185 for hit
in self
._get
_hits
():
186 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
187 if not self
._item
_active
:
188 self
._item
_active
= item
189 getattr(item
, method
)(pos
)
190 img
= 'move' if method
== 'on_click_l' else 'rotate'
191 self
._cursor
.set_image('assets/buttons/%s.png' % img
)
193 def on_click_l(self
):
194 self
._on
_click
('on_click_l')
196 def on_click_r(self
):
197 self
._on
_click
('on_click_r')
199 def on_release(self
):
200 if self
._item
_active
and not self
._item
_active
._first
_command
:
201 self
._commands
= self
._commands
[:self
._command
_idx
]
202 self
._commands
+= [self
._item
_active
]
203 self
._command
_idx
+= 1
204 self
.__prev
_btn
['state'] = NORMAL
205 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
206 self
.__prev
_btn
['frameColor'] = fcols
[0]
207 if self
._item
_active
._command
_idx
== len(self
._item
_active
._commands
) - 1:
208 self
.__next
_btn
['state'] = DISABLED
209 self
.__next
_btn
['frameColor'] = fcols
[1]
210 self
._item
_active
= None
211 [item
.on_release() for item
in self
.items
]
212 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
214 def on_aspect_ratio_changed(self
):
215 [item
.on_aspect_ratio_changed() for item
in self
.items
]
216 self
._side
_panel
.update(self
.items
)
218 def on_frame(self
, task
):
219 hits
= self
._get
_hits
()
221 for hit
in self
._get
_hits
():
222 if hit
.get_node() == self
._mouse
_plane
_node
:
223 pos
= hit
.get_hit_pos()
224 hit_nodes
= [hit
.get_node() for hit
in hits
]
225 if self
._item
_active
:
226 items_hit
= [self
._item
_active
]
228 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
229 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
230 [itm
.on_mouse_on() for itm
in items_hit
]
231 [itm
.on_mouse_off() for itm
in items_no_hit
]
232 if pos
and self
._item
_active
:
233 self
._item
_active
.on_mouse_move(pos
)
236 def cb_inst(self
, item
):
240 [itm
.play() for itm
in self
.items
]
243 self
._commands
[self
._command
_idx
].redo()
244 self
._command
_idx
+= 1
245 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
246 self
.__prev
_btn
['state'] = NORMAL
247 self
.__prev
_btn
['frameColor'] = fcols
[0]
248 more_commands
= self
._command
_idx
< len(self
._commands
)
249 self
.__next
_btn
['state'] = NORMAL
if more_commands
else DISABLED
250 self
.__next
_btn
['frameColor'] = fcols
[0] if more_commands
else fcols
[1]
253 self
._command
_idx
-= 1
254 self
._commands
[self
._command
_idx
].undo()
255 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
256 self
.__next
_btn
['state'] = NORMAL
257 self
.__next
_btn
['frameColor'] = fcols
[0]
258 self
.__prev
_btn
['state'] = NORMAL
if self
._command
_idx
else DISABLED
259 self
.__prev
_btn
['frameColor'] = fcols
[0] if self
._command
_idx
else fcols
[1]
264 def _set_instructions(self
):
267 mgr
= TextPropertiesManager
.get_global_ptr()
268 for name
in ['mouse_l', 'mouse_r']:
269 graphic
= OnscreenImage('assets/buttons/%s.png' % name
)
270 graphic
.set_scale(.5)
271 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
272 graphic
.get_texture().set_anisotropic_degree(2)
273 mgr
.set_graphic(name
, graphic
)
275 graphic
.set_transparency(True)
276 graphic
.detach_node()
277 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
278 frameSize
=(-.6, .6, -.3, .3))
279 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
281 font
.set_pixels_per_unit(60)
282 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
283 font
.set_outline((0, 0, 0, 1), .8, .2)
284 txt
= _('keep \5mouse_l\5 pressed to drag an item\n\n'
285 'keep \5mouse_r\5 pressed to rotate an item')
286 self
._txt
= OnscreenText(
287 txt
, parent
=frm
, font
=font
, scale
=0.06, fg
=(.9, .9, .9, 1),
288 align
=TextNode
.A_left
)
289 u_l
= self
._txt
.textNode
.get_upper_left_3d()
290 l_r
= self
._txt
.textNode
.get_lower_right_3d()
291 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
294 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
295 z
+= (btn_scale
+ 2 * mar
) / 2
296 self
._txt
['pos'] = -w
/ 2, z
297 u_l
= self
._txt
.textNode
.get_upper_left_3d()
298 l_r
= self
._txt
.textNode
.get_lower_right_3d()
299 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
300 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
301 frm
['frameSize'] = fsz
303 (.6, .6, .6, 1), # ready
304 (1, 1, 1, 1), # press
305 (.8, .8, .8, 1), # rollover
307 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
309 image
=imgs
, scale
=btn_scale
,
310 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
311 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
312 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
313 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
314 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
315 btn
.set_transparency(True)
317 def __store_state(self
):
319 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
320 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
321 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
323 btn
['state'] = DISABLED
324 [itm
.store_state() for itm
in self
.items
]
326 def __restore_state(self
):
328 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
329 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
330 for btn
, state
in zip(btns
, self
.__btn
_state
):
332 [itm
.restore_state() for itm
in self
.items
]
335 def __on_close_instructions(self
, frm
):
337 self
.__restore
_state
()