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
34 self
.__restore
_state
()
36 self
._set
_instructions
()
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')
45 self
._unset
_mouse
_plane
()
46 [itm
.destroy() for itm
in self
.items
]
48 self
._side
_panel
.destroy()
49 self
._cursor
.destroy()
50 taskMgr
.remove(self
._scene
_tsk
)
52 def _set_camera(self
):
53 base
.camera
.set_pos(0, -20, 0)
54 base
.camera
.look_at(0, 0, 0)
56 def __load_img_btn(self
, path
, col
):
57 img
= OnscreenImage('assets/buttons/%s.png' % path
)
58 img
.set_transparency(True)
64 def load_images_btn(path
, col
):
67 (.6, .6, .6, 1), # ready
69 (.8, .8, .8, 1), # rollover
75 (.4, .1, .1, .4)]}[col
]
76 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
77 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
79 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
80 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
81 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
82 ('next', self
.on_next
, DISABLED
, abr
, 'gray'),
83 ('previous', self
.on_prev
, DISABLED
, abr
, 'gray'),
84 ('rewind', self
.on_rewind
, DISABLED
, abr
, 'gray')]
87 for binfo
in btn_info
:
88 imgs
= load_images_btn(binfo
[0], binfo
[4])
89 if binfo
[3] == base
.a2dBottomLeft
:
95 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
97 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
98 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
99 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
100 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
101 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
102 btn
.set_transparency(True)
104 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
105 self
.__prev
_btn
, self
.__rewind
_btn
= btns
107 def _unset_gui(self
):
109 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
110 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
111 [btn
.destroy() for btn
in btns
]
113 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
114 light
= Spotlight(name
)
116 light
.setLens(PerspectiveLens())
117 light_np
= render
.attach_new_node(light
)
118 light_np
.set_pos(pos
)
119 light_np
.look_at(look_at
)
120 light
.set_color(color
)
121 render
.set_light(light_np
)
124 def _set_lights(self
):
125 alight
= AmbientLight('alight') # for ao
126 alight
.set_color((.15, .15, .15, 1))
127 self
._alnp
= render
.attach_new_node(alight
)
128 render
.set_light(self
._alnp
)
129 self
._key
_light
= self
._set
_spotlight
(
130 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
131 self
._shadow
_light
= self
._set
_spotlight
(
132 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
133 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
134 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
135 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
136 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
138 def _unset_lights(self
):
139 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
140 render
.clear_light(light
)
143 def _set_input(self
):
144 self
.accept('mouse1', self
.on_click_l
)
145 self
.accept('mouse1-up', self
.on_release
)
146 self
.accept('mouse3', self
.on_click_r
)
147 self
.accept('mouse3-up', self
.on_release
)
149 def _unset_input(self
):
150 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
153 def _set_mouse_plane(self
):
154 shape
= BulletPlaneShape((0, -1, 0), 0)
155 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
156 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
157 self
._mouse
_plane
_node
.addShape(shape
)
158 #np = render.attachNewNode(self._mouse_plane_node)
159 #self._world.attachRigidBody(self._mouse_plane_node)
160 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
162 def _unset_mouse_plane(self
):
163 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
166 if not base
.mouseWatcherNode
.has_mouse(): return []
167 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
168 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
170 def _on_click(self
, method
):
173 for hit
in self
._get
_hits
():
174 if hit
.get_node() == self
._mouse
_plane
_node
:
175 pos
= hit
.get_hit_pos()
176 for hit
in self
._get
_hits
():
177 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
178 if not self
._item
_active
:
179 self
._item
_active
= item
180 getattr(item
, method
)(pos
)
181 img
= 'move' if method
== 'on_click_l' else 'rotate'
182 self
._cursor
.set_image('assets/buttons/%s.png' % img
)
184 def on_click_l(self
):
185 self
._on
_click
('on_click_l')
187 def on_click_r(self
):
188 self
._on
_click
('on_click_r')
190 def on_release(self
):
191 self
._item
_active
= None
192 [item
.on_release() for item
in self
.items
]
193 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
195 def on_aspect_ratio_changed(self
):
196 [item
.on_aspect_ratio_changed() for item
in self
.items
]
197 self
._side
_panel
.update(self
.items
)
199 def on_frame(self
, task
):
200 hits
= self
._get
_hits
()
202 for hit
in self
._get
_hits
():
203 if hit
.get_node() == self
._mouse
_plane
_node
:
204 pos
= hit
.get_hit_pos()
205 hit_nodes
= [hit
.get_node() for hit
in hits
]
206 if self
._item
_active
:
207 items_hit
= [self
._item
_active
]
209 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
210 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
211 [itm
.on_mouse_on() for itm
in items_hit
]
212 [itm
.on_mouse_off() for itm
in items_no_hit
]
213 if pos
and self
._item
_active
:
214 self
._item
_active
.on_mouse_move(pos
)
217 def cb_inst(self
, item
):
221 [itm
.play() for itm
in self
.items
]
235 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
)
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')
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]
265 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
266 z
+= (btn_scale
+ 2 * mar
) / 2
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()
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
272 frm
['frameSize'] = fsz
274 (.6, .6, .6, 1), # ready
275 (1, 1, 1, 1), # press
276 (.8, .8, .8, 1), # rollover
278 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
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)
288 def __store_state(self
):
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
]
294 btn
['state'] = DISABLED
295 [itm
.store_state() for itm
in self
.items
]
297 def __restore_state(self
):
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
):
303 [itm
.restore_state() for itm
in self
.items
]
306 def __on_close_instructions(self
, frm
):
308 self
.__restore
_state
()