5 from importlib
import import_module
6 from inspect
import isclass
7 from sys
import platform
, argv
, exit
8 from logging
import info
, debug
9 from os
.path
import exists
10 from os
import makedirs
11 from panda3d
.core
import Filename
, load_prc_file_data
, AntialiasAttrib
, \
12 Texture
, WindowProperties
, LVector2i
, TextNode
13 from panda3d
.bullet
import BulletWorld
, BulletDebugNode
14 from direct
.showbase
.ShowBase
import ShowBase
15 from direct
.gui
.OnscreenText
import OnscreenText
16 from direct
.fsm
.FSM
import FSM
17 from game
.music
import MusicMgr
18 from game
.items
.background
import Background
19 from game
.menu
import Menu
20 from game
.scene
import Scene
21 from game
.scenes
.scene_basketball
import SceneBasketBall
22 from game
.scenes
.scene_box
import SceneBox
23 from game
.scenes
.scene_domino_box_basketball
import SceneDominoBoxBasketball
24 from game
.scenes
.scene_domino_box
import SceneDominoBox
25 from game
.scenes
.scene_domino
import SceneDomino
26 from game
.scenes
.scene_teeter_domino_box_basketball
import SceneTeeterDominoBoxBasketball
27 from game
.scenes
.scene_teeter_tooter
import SceneTeeterTooter
28 from lib
.dictfile
import DctFile
29 from lib
.lib
.p3d
.p3d
import LibP3d
30 from lib
.engine
.lang
import LangMgr
31 from lib
.engine
.functional
import FunctionalTest
36 def __init__(self
, pmachines
):
37 super().__init
__('Main FSM')
38 self
._pmachines
= pmachines
41 self
._pmachines
.on_menu_enter()
44 self
._pmachines
.on_menu_exit()
46 def enterScene(self
, cls
):
47 self
._pmachines
.on_scene_enter(cls
)
50 self
._pmachines
.on_scene_exit()
60 SceneDominoBoxBasketball
,
62 SceneTeeterDominoBoxBasketball
]
65 info('platform: %s' % platform
)
66 info('exists main.py: %s' % exists('main.py'))
67 args
= self
._parse
_args
()
69 self
.base
= ShowBase()
70 self
._prepare
_window
(args
)
71 self
.updating
= args
.update
72 self
.version
= args
.version
75 if args
.functional_test
and int(args
.functional_test
) == 1:
76 self
._options
['settings']['volume'] = 0
77 self
._music
= MusicMgr(self
._options
['settings']['volume'])
78 self
.lang_mgr
= LangMgr(self
._options
['settings']['language'],
81 self
._fsm
= MainFsm(self
)
83 cls
= [cls
for cls
in self
.scenes
if cls
.__name
__ == args
.screenshot
][0]
84 scene
= cls(BulletWorld(), None, True, False, lambda: None, self
.scenes
)
88 elif self
._options
['development']['auto_start']:
89 mod_name
= 'game.scenes.scene_' + self
._options
['development']['auto_start']
90 for member
in import_module(mod_name
).__dict
__.values():
91 if isclass(member
) and issubclass(member
, Scene
) and \
94 self
._fsm
.demand('Scene', cls
)
96 self
._fsm
.demand('Menu')
97 if args
.functional_test
or args
.functional_ref
:
98 FunctionalTest(args
.functional_test
, args
.functional_ref
)
100 def on_menu_enter(self
):
101 self
._menu
_bg
= Background()
103 self
._fsm
, self
.lang_mgr
, self
._options
, self
._music
,
104 self
._pipeline
, self
.scenes
)
107 self
._fsm
.demand('Menu')
109 def on_menu_exit(self
):
110 self
._menu
_bg
.destroy()
113 def on_scene_enter(self
, cls
):
116 self
.world
, self
.on_home
,
117 self
._options
['development']['auto_close_instructions'],
118 self
._options
['development']['debug_items'],
122 def on_scene_exit(self
):
123 self
._unset
_physics
()
124 self
._scene
.destroy()
126 def reload(self
, cls
):
127 self
._fsm
.demand('Scene', cls
)
129 def _configure(self
, args
):
130 load_prc_file_data('', 'window-title pmachines')
131 load_prc_file_data('', 'framebuffer-srgb true')
132 load_prc_file_data('', 'sync-video true')
133 if args
.functional_test
or args
.functional_ref
:
134 load_prc_file_data('', 'win-size 1280 720')
135 # otherwise it is not centered in exwm
136 # load_prc_file_data('', 'threading-model Cull/Draw')
137 # it freezes when you go to the next scene
139 load_prc_file_data('', 'window-type offscreen')
140 load_prc_file_data('', 'audio-library-name null')
142 def _parse_args(self
):
143 parser
= argparse
.ArgumentParser()
144 parser
.add_argument('--update', action
='store_true')
145 parser
.add_argument('--version', action
='store_true')
146 parser
.add_argument('--optfile')
147 parser
.add_argument('--screenshot')
148 parser
.add_argument('--functional-test')
149 parser
.add_argument('--functional-ref', action
='store_true')
150 cmd_line
= [arg
for arg
in iter(argv
[1:]) if not arg
.startswith('-psn_')]
151 args
= parser
.parse_args(cmd_line
)
154 def _prepare_window(self
, args
):
156 if (platform
.startswith('win') or platform
.startswith('linux')) and (
157 not exists('main.py') or __file__
.startswith('/app/bin/')):
158 # it is the deployed version for windows
159 data_path
= str(Filename
.get_user_appdata_directory()) + '/pmachines'
160 home
= '/home/flavio' # we must force this for wine
161 if data_path
.startswith('/c/users/') and exists(home
+ '/.wine/'):
162 data_path
= home
+ '/.wine/drive_' + data_path
[1:]
163 info('creating dirs: %s' % data_path
)
164 makedirs(data_path
, exist_ok
=True)
165 optfile
= args
.optfile
if args
.optfile
else 'options.ini'
166 info('data path: %s' % data_path
)
167 info('option file: %s' % optfile
)
168 info('fixed path: %s' % LibP3d
.fixpath(data_path
+ '/' + optfile
))
182 'auto_close_instructions': 0,
187 opt_path
= LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
188 opt_exists
= exists(opt_path
)
189 self
._options
= DctFile(
190 LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
,
193 self
._options
.store()
194 res
= self
._options
['settings']['resolution']
196 res
= LVector2i(*[int(_res
) for _res
in res
.split('x')])
198 d_i
= base
.pipe
.get_display_information()
200 return d_i
.get_display_mode_width(idx
), \
201 d_i
.get_display_mode_height(idx
)
203 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
204 res
= sorted(resolutions
)[-1]
205 fullscreen
= self
._options
['settings']['fullscreen']
206 props
= WindowProperties()
207 if args
.functional_test
or args
.functional_ref
:
211 props
.set_fullscreen(fullscreen
)
212 props
.set_icon_filename('assets/images/icon/pmachines.ico')
213 if not args
.screenshot
:
214 base
.win
.request_properties(props
)
215 #gltf.patch_loader(base.loader)
216 if self
._options
['development']['simplepbr']:
217 self
._pipeline
= simplepbr
.init(
218 use_normal_maps
=True,
219 use_emission_maps
=False,
220 use_occlusion_maps
=True,
221 msaa_samples
=4 if self
._options
['settings']['antialiasing'] else 1,
222 enable_shadows
=int(self
._options
['settings']['shadows']))
223 debug(f
'msaa: {self._pipeline.msaa_samples}')
224 debug(f
'shadows: {self._pipeline.enable_shadows}')
225 render
.setAntialias(AntialiasAttrib
.MAuto
)
226 self
.base
.set_background_color(0, 0, 0, 1)
227 self
.base
.disable_mouse()
228 if self
._options
['development']['show_buffers']:
229 base
.bufferViewer
.toggleEnable()
230 if self
._options
['development']['fps']:
231 base
.set_frame_rate_meter(True)
232 #self.base.accept('window-event', self._on_win_evt)
233 self
.base
.accept('aspectRatioChanged', self
._on
_aspect
_ratio
_changed
)
234 if self
._options
['development']['mouse_coords']:
235 coords_txt
= OnscreenText(
236 '', parent
=base
.a2dTopRight
, scale
=0.04,
237 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
238 def update_coords(task
):
239 txt
= '%s %s' % (int(base
.win
.get_pointer(0).x
),
240 int(base
.win
.get_pointer(0).y
))
241 coords_txt
['text'] = txt
243 taskMgr
.add(update_coords
, 'update_coords')
246 def _set_physics(self
):
247 if self
._options
['development']['physics_debug']:
248 debug_node
= BulletDebugNode('Debug')
249 debug_node
.show_wireframe(True)
250 debug_node
.show_constraints(True)
251 debug_node
.show_bounding_boxes(True)
252 debug_node
.show_normals(True)
253 self
._debug
_np
= render
.attach_new_node(debug_node
)
254 self
._debug
_np
.show()
255 self
.world
= BulletWorld()
256 self
.world
.set_gravity((0, 0, -9.81))
257 if self
._options
['development']['physics_debug']:
258 self
.world
.set_debug_node(self
._debug
_np
.node())
260 dt
= globalClock
.get_dt()
261 self
.world
.do_physics(dt
, 10, 1/180)
263 self
._phys
_tsk
= taskMgr
.add(update
, 'update')
265 def _unset_physics(self
):
266 if self
._options
['development']['physics_debug']:
267 self
._debug
_np
.remove_node()
269 taskMgr
.remove(self
._phys
_tsk
)
271 def _on_aspect_ratio_changed(self
):
272 if self
._fsm
.state
== 'Scene':
273 self
._scene
.on_aspect_ratio_changed()