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
)]
32 self
._item
_active
= None
35 self
.__restore
_state
()
37 self
._set
_instructions
()
38 self
._bg
= Background()
39 self
._side
_panel
= SidePanel(world
, self
._mouse
_plane
_node
, (-5, 4), (-3, 1), 1, self
.items
)
40 self
._scene
_tsk
= taskMgr
.add(self
.on_frame
, 'on_frame')
46 self
._unset
_mouse
_plane
()
47 [itm
.destroy() for itm
in self
.items
]
49 self
._side
_panel
.destroy()
50 self
._cursor
.destroy()
51 taskMgr
.remove(self
._scene
_tsk
)
53 def _set_camera(self
):
54 base
.camera
.set_pos(0, -20, 0)
55 base
.camera
.look_at(0, 0, 0)
57 def __load_img_btn(self
, path
, col
):
58 img
= OnscreenImage('assets/buttons/%s.png' % path
)
59 img
.set_transparency(True)
65 def load_images_btn(path
, col
):
68 (.6, .6, .6, 1), # ready
70 (.8, .8, .8, 1), # rollover
76 (.4, .1, .1, .4)]}[col
]
77 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
78 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
80 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
81 ('information', self
.on_information
, DISABLED
, abl
, 'gray'),
82 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
83 ('next', self
.on_next
, DISABLED
, abr
, 'gray'),
84 ('previous', self
.on_prev
, DISABLED
, abr
, 'gray'),
85 ('rewind', self
.on_rewind
, DISABLED
, abr
, 'gray')]
88 for binfo
in btn_info
:
89 imgs
= load_images_btn(binfo
[0], binfo
[4])
90 if binfo
[3] == base
.a2dBottomLeft
:
96 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
98 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
99 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
100 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
101 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
102 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
103 btn
.set_transparency(True)
105 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
106 self
.__prev
_btn
, self
.__rewind
_btn
= btns
108 def _unset_gui(self
):
110 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
111 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
112 [btn
.destroy() for btn
in btns
]
114 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
115 light
= Spotlight(name
)
117 light
.setLens(PerspectiveLens())
118 light_np
= render
.attach_new_node(light
)
119 light_np
.set_pos(pos
)
120 light_np
.look_at(look_at
)
121 light
.set_color(color
)
122 render
.set_light(light_np
)
125 def _set_lights(self
):
126 alight
= AmbientLight('alight') # for ao
127 alight
.set_color((.15, .15, .15, 1))
128 self
._alnp
= render
.attach_new_node(alight
)
129 render
.set_light(self
._alnp
)
130 self
._key
_light
= self
._set
_spotlight
(
131 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
132 self
._shadow
_light
= self
._set
_spotlight
(
133 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
134 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
135 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
136 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
137 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
139 def _unset_lights(self
):
140 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
141 render
.clear_light(light
)
144 def _set_input(self
):
145 self
.accept('mouse1', self
.on_click_l
)
146 self
.accept('mouse1-up', self
.on_release
)
147 self
.accept('mouse3', self
.on_click_r
)
148 self
.accept('mouse3-up', self
.on_release
)
150 def _unset_input(self
):
151 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
154 def _set_mouse_plane(self
):
155 shape
= BulletPlaneShape((0, -1, 0), 0)
156 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
157 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
158 self
._mouse
_plane
_node
.addShape(shape
)
159 #np = render.attachNewNode(self._mouse_plane_node)
160 #self._world.attachRigidBody(self._mouse_plane_node)
161 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
163 def _unset_mouse_plane(self
):
164 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
167 if not base
.mouseWatcherNode
.has_mouse(): return []
168 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
169 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
171 def _on_click(self
, method
):
174 for hit
in self
._get
_hits
():
175 if hit
.get_node() == self
._mouse
_plane
_node
:
176 pos
= hit
.get_hit_pos()
177 for hit
in self
._get
_hits
():
178 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
179 if not self
._item
_active
:
180 self
._item
_active
= item
181 getattr(item
, method
)(pos
)
182 img
= 'move' if method
== 'on_click_l' else 'rotate'
183 self
._cursor
.set_image('assets/buttons/%s.png' % img
)
185 def on_click_l(self
):
186 self
._on
_click
('on_click_l')
188 def on_click_r(self
):
189 self
._on
_click
('on_click_r')
191 def on_release(self
):
192 self
._item
_active
= None
193 [item
.on_release() for item
in self
.items
]
194 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
196 def on_aspect_ratio_changed(self
):
197 [item
.on_aspect_ratio_changed() for item
in self
.items
]
198 self
._side
_panel
.update(self
.items
)
200 def on_frame(self
, task
):
201 hits
= self
._get
_hits
()
203 for hit
in self
._get
_hits
():
204 if hit
.get_node() == self
._mouse
_plane
_node
:
205 pos
= hit
.get_hit_pos()
206 hit_nodes
= [hit
.get_node() for hit
in hits
]
207 if self
._item
_active
:
208 items_hit
= [self
._item
_active
]
210 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
211 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
212 [itm
.on_mouse_on() for itm
in items_hit
]
213 [itm
.on_mouse_off() for itm
in items_no_hit
]
214 if pos
and self
._item
_active
:
215 self
._item
_active
.on_mouse_move(pos
)
218 def cb_inst(self
, item
):
222 [itm
.play() for itm
in self
.items
]
236 def on_information(self
):
237 print('on_information')
239 def _set_instructions(self
):
240 mgr
= TextPropertiesManager
.get_global_ptr()
241 for name
in ['mouse_l', 'mouse_r']:
242 graphic
= OnscreenImage('assets/buttons/%s.png' % name
)
243 graphic
.set_scale(.5)
244 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
245 graphic
.get_texture().set_anisotropic_degree(2)
246 mgr
.set_graphic(name
, graphic
)
248 graphic
.set_transparency(True)
249 graphic
.detach_node()
250 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
251 frameSize
=(-.6, .6, -.3, .3))
252 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
254 font
.set_pixels_per_unit(60)
255 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
256 font
.set_outline((0, 0, 0, 1), .8, .2)
257 txt
= _('keep \5mouse_l\5 pressed to drag an item\n\n'
258 'keep \5mouse_r\5 pressed to rotate an item')
259 self
._txt
= OnscreenText(
260 txt
, parent
=frm
, font
=font
, scale
=0.06, fg
=(.9, .9, .9, 1),
261 align
=TextNode
.A_left
)
262 u_l
= self
._txt
.textNode
.get_upper_left_3d()
263 l_r
= self
._txt
.textNode
.get_lower_right_3d()
264 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
267 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
268 z
+= (btn_scale
+ 2 * mar
) / 2
269 self
._txt
['pos'] = -w
/ 2, z
270 u_l
= self
._txt
.textNode
.get_upper_left_3d()
271 l_r
= self
._txt
.textNode
.get_lower_right_3d()
272 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
273 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
274 frm
['frameSize'] = fsz
276 (.6, .6, .6, 1), # ready
277 (1, 1, 1, 1), # press
278 (.8, .8, .8, 1), # rollover
280 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
282 image
=imgs
, scale
=btn_scale
,
283 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
284 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
285 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
286 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
287 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
288 btn
.set_transparency(True)
290 def __store_state(self
):
292 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
293 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
294 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
296 btn
['state'] = DISABLED
297 [itm
.store_state() for itm
in self
.items
]
299 def __restore_state(self
):
301 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
302 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
303 for btn
, state
in zip(btns
, self
.__btn
_state
):
305 [itm
.restore_state() for itm
in self
.items
]
308 def __on_close_instructions(self
, frm
):
310 self
.__restore
_state
()