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
13 from panda3d
.bullet
import BulletWorld
, BulletDebugNode
14 from direct
.showbase
.ShowBase
import ShowBase
15 from direct
.fsm
.FSM
import FSM
16 from game
.music
import MusicMgr
17 from game
.items
.background
import Background
18 from game
.menu
import Menu
19 from game
.scene
import Scene
20 from game
.scenes
.scene_basketball
import SceneBasketBall
21 from game
.scenes
.scene_box
import SceneBox
22 from game
.scenes
.scene_domino_box_basketball
import SceneDominoBoxBasketball
23 from game
.scenes
.scene_domino_box
import SceneDominoBox
24 from game
.scenes
.scene_domino
import SceneDomino
25 from game
.scenes
.scene_teeter_domino_box_basketball
import SceneTeeterDominoBoxBasketball
26 from game
.scenes
.scene_teeter_tooter
import SceneTeeterTooter
27 from lib
.dictfile
import DctFile
28 from lib
.lib
.p3d
.p3d
import LibP3d
29 from lib
.engine
.lang
import LangMgr
30 from lib
.engine
.functional
import FunctionalTest
35 def __init__(self
, pmachines
):
36 super().__init
__('Main FSM')
37 self
._pmachines
= pmachines
40 self
._pmachines
.on_menu_enter()
43 self
._pmachines
.on_menu_exit()
45 def enterScene(self
, cls
):
46 self
._pmachines
.on_scene_enter(cls
)
49 self
._pmachines
.on_scene_exit()
59 SceneDominoBoxBasketball
,
61 SceneTeeterDominoBoxBasketball
]
64 info('platform: %s' % platform
)
65 info('exists main.py: %s' % exists('main.py'))
66 args
= self
._parse
_args
()
68 self
.base
= ShowBase()
69 self
._prepare
_window
(args
)
70 self
.updating
= args
.update
71 self
.version
= args
.version
74 if args
.functional_test
and int(args
.functional_test
) == 1:
75 self
._options
['settings']['volume'] = 0
76 self
._music
= MusicMgr(self
._options
['settings']['volume'])
77 self
.lang_mgr
= LangMgr(self
._options
['settings']['language'],
80 self
._fsm
= MainFsm(self
)
82 cls
= [cls
for cls
in self
.scenes
if cls
.__name
__ == args
.screenshot
][0]
83 scene
= cls(BulletWorld(), None, True, False, lambda: None, self
.scenes
)
87 elif self
._options
['development']['auto_start']:
88 mod_name
= 'game.scenes.scene_' + self
._options
['development']['auto_start']
89 for member
in import_module(mod_name
).__dict
__.values():
90 if isclass(member
) and issubclass(member
, Scene
) and \
93 self
._fsm
.demand('Scene', cls
)
95 self
._fsm
.demand('Menu')
96 if args
.functional_test
or args
.functional_ref
:
97 FunctionalTest(args
.functional_test
, args
.functional_ref
)
99 def on_menu_enter(self
):
100 self
._menu
_bg
= Background()
102 self
._fsm
, self
.lang_mgr
, self
._options
, self
._music
,
103 self
._pipeline
, self
.scenes
)
106 self
._fsm
.demand('Menu')
108 def on_menu_exit(self
):
109 self
._menu
_bg
.destroy()
112 def on_scene_enter(self
, cls
):
115 self
.world
, self
.on_home
,
116 self
._options
['development']['auto_close_instructions'],
117 self
._options
['development']['debug_items'],
121 def on_scene_exit(self
):
122 self
._unset
_physics
()
123 self
._scene
.destroy()
125 def reload(self
, cls
):
126 self
._fsm
.demand('Scene', cls
)
128 def _configure(self
, args
):
129 load_prc_file_data('', 'window-title pmachines')
130 load_prc_file_data('', 'framebuffer-srgb true')
131 load_prc_file_data('', 'sync-video true')
132 # load_prc_file_data('', 'threading-model Cull/Draw')
133 # it freezes when you go to the next scene
135 load_prc_file_data('', 'window-type offscreen')
136 load_prc_file_data('', 'audio-library-name null')
138 def _parse_args(self
):
139 parser
= argparse
.ArgumentParser()
140 parser
.add_argument('--update', action
='store_true')
141 parser
.add_argument('--version', action
='store_true')
142 parser
.add_argument('--optfile')
143 parser
.add_argument('--screenshot')
144 parser
.add_argument('--functional-test')
145 parser
.add_argument('--functional-ref', action
='store_true')
146 cmd_line
= [arg
for arg
in iter(argv
[1:]) if not arg
.startswith('-psn_')]
147 args
= parser
.parse_args(cmd_line
)
150 def _prepare_window(self
, args
):
152 if (platform
.startswith('win') or platform
.startswith('linux')) and (
153 not exists('main.py') or __file__
.startswith('/app/bin/')):
154 # it is the deployed version for windows
155 data_path
= str(Filename
.get_user_appdata_directory()) + '/pmachines'
156 home
= '/home/flavio' # we must force this for wine
157 if data_path
.startswith('/c/users/') and exists(home
+ '/.wine/'):
158 data_path
= home
+ '/.wine/drive_' + data_path
[1:]
159 info('creating dirs: %s' % data_path
)
160 makedirs(data_path
, exist_ok
=True)
161 optfile
= args
.optfile
if args
.optfile
else 'options.ini'
162 info('data path: %s' % data_path
)
163 info('option file: %s' % optfile
)
164 info('fixed path: %s' % LibP3d
.fixpath(data_path
+ '/' + optfile
))
178 'auto_close_instructions': 0,
182 opt_path
= LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
183 opt_exists
= exists(opt_path
)
184 self
._options
= DctFile(
185 LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
,
188 self
._options
.store()
189 res
= self
._options
['settings']['resolution']
191 res
= LVector2i(*[int(_res
) for _res
in res
.split('x')])
193 d_i
= base
.pipe
.get_display_information()
195 return d_i
.get_display_mode_width(idx
), \
196 d_i
.get_display_mode_height(idx
)
198 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
199 res
= sorted(resolutions
)[-1]
200 fullscreen
= self
._options
['settings']['fullscreen']
201 if args
.functional_test
or args
.functional_ref
:
204 props
= WindowProperties()
206 props
.set_fullscreen(fullscreen
)
207 props
.set_icon_filename('assets/images/icon/pmachines.ico')
208 if not args
.screenshot
:
209 base
.win
.request_properties(props
)
210 #gltf.patch_loader(base.loader)
211 if self
._options
['development']['simplepbr']:
212 self
._pipeline
= simplepbr
.init(
213 use_normal_maps
=True,
214 use_emission_maps
=False,
215 use_occlusion_maps
=True,
216 msaa_samples
=4 if self
._options
['settings']['antialiasing'] else 1,
217 enable_shadows
=int(self
._options
['settings']['shadows']))
218 debug(f
'msaa: {self._pipeline.msaa_samples}')
219 debug(f
'shadows: {self._pipeline.enable_shadows}')
220 render
.setAntialias(AntialiasAttrib
.MAuto
)
221 self
.base
.set_background_color(0, 0, 0, 1)
222 self
.base
.disable_mouse()
223 if self
._options
['development']['show_buffers']:
224 base
.bufferViewer
.toggleEnable()
225 if self
._options
['development']['fps']:
226 base
.set_frame_rate_meter(True)
227 #self.base.accept('window-event', self._on_win_evt)
228 self
.base
.accept('aspectRatioChanged', self
._on
_aspect
_ratio
_changed
)
230 def _set_physics(self
):
231 if self
._options
['development']['physics_debug']:
232 debug_node
= BulletDebugNode('Debug')
233 debug_node
.show_wireframe(True)
234 debug_node
.show_constraints(True)
235 debug_node
.show_bounding_boxes(True)
236 debug_node
.show_normals(True)
237 self
._debug
_np
= render
.attach_new_node(debug_node
)
238 self
._debug
_np
.show()
239 self
.world
= BulletWorld()
240 self
.world
.set_gravity((0, 0, -9.81))
241 if self
._options
['development']['physics_debug']:
242 self
.world
.set_debug_node(self
._debug
_np
.node())
244 dt
= globalClock
.get_dt()
245 self
.world
.do_physics(dt
, 10, 1/180)
247 self
._phys
_tsk
= taskMgr
.add(update
, 'update')
249 def _unset_physics(self
):
250 if self
._options
['development']['physics_debug']:
251 self
._debug
_np
.remove_node()
253 taskMgr
.remove(self
._phys
_tsk
)
255 def _on_aspect_ratio_changed(self
):
256 if self
._fsm
.state
== 'Scene':
257 self
._scene
.on_aspect_ratio_changed()