1 from panda3d
.core
import AmbientLight
, DirectionalLight
, Point3
, Texture
, \
2 TextPropertiesManager
, TextNode
, Spotlight
, PerspectiveLens
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
.__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 taskMgr
.remove(self
._scene
_tsk
)
51 def _set_camera(self
):
52 base
.camera
.set_pos(0, -20, 0)
53 base
.camera
.look_at(0, 0, 0)
55 def __load_img_btn(self
, path
, col
):
56 img
= OnscreenImage('assets/buttons/%s.png' % path
)
57 img
.set_transparency(True)
63 def load_images_btn(path
, col
):
66 (.6, .6, .6, 1), # ready
68 (.8, .8, .8, 1), # rollover
74 (.4, .1, .1, .4)]}[col
]
75 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
76 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
78 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
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')]
86 for binfo
in btn_info
:
87 imgs
= load_images_btn(binfo
[0], binfo
[4])
88 if binfo
[3] == base
.a2dBottomLeft
:
94 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
96 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
97 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
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'))
101 btn
.set_transparency(True)
103 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
104 self
.__prev
_btn
, self
.__rewind
_btn
= btns
106 def _unset_gui(self
):
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
]
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
)
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
)
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))
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)
142 def _unset_lights(self
):
143 for light
in [self
._key
_light
, self
._fill
_light
, self
._rim
_light
,
144 self
.__shadow
_light
]:
145 render
.clear_light(light
)
148 def _set_input(self
):
149 self
.accept('mouse1', self
.on_click_l
)
150 self
.accept('mouse1-up', self
.on_release
)
151 self
.accept('mouse3', self
.on_click_r
)
152 self
.accept('mouse3-up', self
.on_release
)
154 def _unset_input(self
):
155 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
158 def _set_mouse_plane(self
):
159 shape
= BulletPlaneShape((0, -1, 0), 0)
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)
165 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
167 def _unset_mouse_plane(self
):
168 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
171 if not base
.mouseWatcherNode
.has_mouse(): return []
172 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
173 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
175 def _on_click(self
, method
):
178 for hit
in self
._get
_hits
():
179 if hit
.get_node() == self
._mouse
_plane
_node
:
180 pos
= hit
.get_hit_pos()
181 for hit
in self
._get
_hits
():
182 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
183 getattr(item
, method
)(pos
)
184 img
= 'move' if method
== 'on_click_l' else 'rotate'
185 self
._cursor
.set_image('assets/buttons/%s.png' % img
)
187 def on_click_l(self
):
188 self
._on
_click
('on_click_l')
190 def on_click_r(self
):
191 self
._on
_click
('on_click_r')
193 def on_release(self
):
194 [item
.on_release() for item
in self
.items
]
195 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
197 def on_aspect_ratio_changed(self
):
198 [item
.on_aspect_ratio_changed() for item
in self
.items
]
199 self
._side
_panel
.update(self
.items
)
201 def on_frame(self
, task
):
202 hits
= self
._get
_hits
()
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
]
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
]
213 [itm
.on_mouse_move(pos
) for itm
in self
.items
]
216 def cb_inst(self
, item
):
220 [itm
.play() for itm
in self
.items
]
234 def on_information(self
):
235 print('on_information')
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
)
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
()