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')
42 [itm
.destroy() for itm
in self
.items
]
43 self
.items
= [Box(self
._world
, self
._mouse
_plane
_node
, 3, self
.cb_inst
)]
49 self
._unset
_mouse
_plane
()
50 [itm
.destroy() for itm
in self
.items
]
52 self
._side
_panel
.destroy()
53 self
._cursor
.destroy()
54 taskMgr
.remove(self
._scene
_tsk
)
56 def _set_camera(self
):
57 base
.camera
.set_pos(0, -20, 0)
58 base
.camera
.look_at(0, 0, 0)
60 def __load_img_btn(self
, path
, col
):
61 img
= OnscreenImage('assets/buttons/%s.png' % path
)
62 img
.set_transparency(True)
68 def load_images_btn(path
, col
):
71 (.6, .6, .6, 1), # ready
73 (.8, .8, .8, 1), # rollover
79 (.4, .1, .1, .4)]}[col
]
80 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
81 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
83 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
84 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
85 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
86 ('next', self
.on_next
, DISABLED
, abr
, 'gray'),
87 ('previous', self
.on_prev
, DISABLED
, abr
, 'gray'),
88 ('rewind', self
.reset
, NORMAL
, abr
, 'gray')]
91 for binfo
in btn_info
:
92 imgs
= load_images_btn(binfo
[0], binfo
[4])
93 if binfo
[3] == base
.a2dBottomLeft
:
99 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
101 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
102 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
103 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
104 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
105 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
106 btn
.set_transparency(True)
108 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
109 self
.__prev
_btn
, self
.__rewind
_btn
= btns
111 def _unset_gui(self
):
113 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
114 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
115 [btn
.destroy() for btn
in btns
]
117 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
118 light
= Spotlight(name
)
120 light
.setLens(PerspectiveLens())
121 light_np
= render
.attach_new_node(light
)
122 light_np
.set_pos(pos
)
123 light_np
.look_at(look_at
)
124 light
.set_color(color
)
125 render
.set_light(light_np
)
128 def _set_lights(self
):
129 alight
= AmbientLight('alight') # for ao
130 alight
.set_color((.15, .15, .15, 1))
131 self
._alnp
= render
.attach_new_node(alight
)
132 render
.set_light(self
._alnp
)
133 self
._key
_light
= self
._set
_spotlight
(
134 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
135 self
._shadow
_light
= self
._set
_spotlight
(
136 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
137 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
138 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
139 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
140 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
142 def _unset_lights(self
):
143 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
144 render
.clear_light(light
)
147 def _set_input(self
):
148 self
.accept('mouse1', self
.on_click_l
)
149 self
.accept('mouse1-up', self
.on_release
)
150 self
.accept('mouse3', self
.on_click_r
)
151 self
.accept('mouse3-up', self
.on_release
)
153 def _unset_input(self
):
154 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
157 def _set_mouse_plane(self
):
158 shape
= BulletPlaneShape((0, -1, 0), 0)
159 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
160 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
161 self
._mouse
_plane
_node
.addShape(shape
)
162 #np = render.attachNewNode(self._mouse_plane_node)
163 #self._world.attachRigidBody(self._mouse_plane_node)
164 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
166 def _unset_mouse_plane(self
):
167 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
170 if not base
.mouseWatcherNode
.has_mouse(): return []
171 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
172 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
174 def _on_click(self
, method
):
177 for hit
in self
._get
_hits
():
178 if hit
.get_node() == self
._mouse
_plane
_node
:
179 pos
= hit
.get_hit_pos()
180 for hit
in self
._get
_hits
():
181 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
182 if not self
._item
_active
:
183 self
._item
_active
= item
184 getattr(item
, method
)(pos
)
185 img
= 'move' if method
== 'on_click_l' else 'rotate'
186 self
._cursor
.set_image('assets/buttons/%s.png' % img
)
188 def on_click_l(self
):
189 self
._on
_click
('on_click_l')
191 def on_click_r(self
):
192 self
._on
_click
('on_click_r')
194 def on_release(self
):
195 self
._item
_active
= None
196 [item
.on_release() for item
in self
.items
]
197 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
199 def on_aspect_ratio_changed(self
):
200 [item
.on_aspect_ratio_changed() for item
in self
.items
]
201 self
._side
_panel
.update(self
.items
)
203 def on_frame(self
, task
):
204 hits
= self
._get
_hits
()
206 for hit
in self
._get
_hits
():
207 if hit
.get_node() == self
._mouse
_plane
_node
:
208 pos
= hit
.get_hit_pos()
209 hit_nodes
= [hit
.get_node() for hit
in hits
]
210 if self
._item
_active
:
211 items_hit
= [self
._item
_active
]
213 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
214 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
215 [itm
.on_mouse_on() for itm
in items_hit
]
216 [itm
.on_mouse_off() for itm
in items_no_hit
]
217 if pos
and self
._item
_active
:
218 self
._item
_active
.on_mouse_move(pos
)
221 def cb_inst(self
, item
):
225 [itm
.play() for itm
in self
.items
]
236 def _set_instructions(self
):
239 mgr
= TextPropertiesManager
.get_global_ptr()
240 for name
in ['mouse_l', 'mouse_r']:
241 graphic
= OnscreenImage('assets/buttons/%s.png' % name
)
242 graphic
.set_scale(.5)
243 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
244 graphic
.get_texture().set_anisotropic_degree(2)
245 mgr
.set_graphic(name
, graphic
)
247 graphic
.set_transparency(True)
248 graphic
.detach_node()
249 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
250 frameSize
=(-.6, .6, -.3, .3))
251 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
253 font
.set_pixels_per_unit(60)
254 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
255 font
.set_outline((0, 0, 0, 1), .8, .2)
256 txt
= _('keep \5mouse_l\5 pressed to drag an item\n\n'
257 'keep \5mouse_r\5 pressed to rotate an item')
258 self
._txt
= OnscreenText(
259 txt
, parent
=frm
, font
=font
, scale
=0.06, fg
=(.9, .9, .9, 1),
260 align
=TextNode
.A_left
)
261 u_l
= self
._txt
.textNode
.get_upper_left_3d()
262 l_r
= self
._txt
.textNode
.get_lower_right_3d()
263 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
266 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
267 z
+= (btn_scale
+ 2 * mar
) / 2
268 self
._txt
['pos'] = -w
/ 2, z
269 u_l
= self
._txt
.textNode
.get_upper_left_3d()
270 l_r
= self
._txt
.textNode
.get_lower_right_3d()
271 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
272 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
273 frm
['frameSize'] = fsz
275 (.6, .6, .6, 1), # ready
276 (1, 1, 1, 1), # press
277 (.8, .8, .8, 1), # rollover
279 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
281 image
=imgs
, scale
=btn_scale
,
282 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
283 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
284 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
285 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
286 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
287 btn
.set_transparency(True)
289 def __store_state(self
):
291 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
292 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
293 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
295 btn
['state'] = DISABLED
296 [itm
.store_state() for itm
in self
.items
]
298 def __restore_state(self
):
300 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
301 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
302 for btn
, state
in zip(btns
, self
.__btn
_state
):
304 [itm
.restore_state() for itm
in self
.items
]
307 def __on_close_instructions(self
, frm
):
309 self
.__restore
_state
()