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
.__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)
141 self
.__shadow
_light
.node().set_camera_mask(BitMask32(0x01))
143 def _unset_lights(self
):
144 for light
in [self
._key
_light
, self
._fill
_light
, self
._rim
_light
,
145 self
.__shadow
_light
]:
146 render
.clear_light(light
)
149 def _set_input(self
):
150 self
.accept('mouse1', self
.on_click_l
)
151 self
.accept('mouse1-up', self
.on_release
)
152 self
.accept('mouse3', self
.on_click_r
)
153 self
.accept('mouse3-up', self
.on_release
)
155 def _unset_input(self
):
156 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
159 def _set_mouse_plane(self
):
160 shape
= BulletPlaneShape((0, -1, 0), 0)
161 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
162 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
163 self
._mouse
_plane
_node
.addShape(shape
)
164 #np = render.attachNewNode(self._mouse_plane_node)
165 #self._world.attachRigidBody(self._mouse_plane_node)
166 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
168 def _unset_mouse_plane(self
):
169 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
172 if not base
.mouseWatcherNode
.has_mouse(): return []
173 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
174 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
176 def _on_click(self
, method
):
179 for hit
in self
._get
_hits
():
180 if hit
.get_node() == self
._mouse
_plane
_node
:
181 pos
= hit
.get_hit_pos()
182 for hit
in self
._get
_hits
():
183 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
]:
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 [item
.on_release() for item
in self
.items
]
196 self
._cursor
.set_image('assets/buttons/arrowUpLeft.png')
198 def on_aspect_ratio_changed(self
):
199 [item
.on_aspect_ratio_changed() for item
in self
.items
]
200 self
._side
_panel
.update(self
.items
)
202 def on_frame(self
, task
):
203 hits
= self
._get
_hits
()
205 for hit
in self
._get
_hits
():
206 if hit
.get_node() == self
._mouse
_plane
_node
:
207 pos
= hit
.get_hit_pos()
208 hit_nodes
= [hit
.get_node() for hit
in hits
]
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
]
214 [itm
.on_mouse_move(pos
) for itm
in self
.items
]
217 def cb_inst(self
, item
):
221 [itm
.play() for itm
in self
.items
]
235 def on_information(self
):
236 print('on_information')
238 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
()