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
.log
import LogMgr
32 from lib
.engine
.functional
import FunctionalTest
37 def __init__(self
, pmachines
):
38 super().__init
__('Main FSM')
39 self
._pmachines
= pmachines
42 self
._pmachines
.on_menu_enter()
45 self
._pmachines
.on_menu_exit()
47 def enterScene(self
, cls
):
48 self
._pmachines
.on_scene_enter(cls
)
51 self
._pmachines
.on_scene_exit()
61 SceneDominoBoxBasketball
,
63 SceneTeeterDominoBoxBasketball
]
66 info('platform: %s' % platform
)
67 info('exists main.py: %s' % exists('main.py'))
68 self
._args
= args
= self
._parse
_args
()
70 self
.base
= ShowBase()
72 self
.updating
= args
.update
73 self
.version
= args
.version
74 self
.log_mgr
= LogMgr
.init_cls()(self
)
75 self
._prepare
_window
(args
)
78 if args
.functional_test
:
79 self
._options
['settings']['volume'] = 0
80 self
._music
= MusicMgr(self
._options
['settings']['volume'])
81 self
.lang_mgr
= LangMgr(self
._options
['settings']['language'],
84 self
._fsm
= MainFsm(self
)
86 cls
= [cls
for cls
in self
.scenes
if cls
.__name
__ == args
.screenshot
][0]
87 scene
= cls(BulletWorld(), None, True, False, lambda: None, self
.scenes
)
91 elif self
._options
['development']['auto_start']:
92 mod_name
= 'game.scenes.scene_' + self
._options
['development']['auto_start']
93 for member
in import_module(mod_name
).__dict
__.values():
94 if isclass(member
) and issubclass(member
, Scene
) and \
97 self
._fsm
.demand('Scene', cls
)
99 self
._fsm
.demand('Menu')
100 if args
.functional_test
or args
.functional_ref
:
101 FunctionalTest(args
.functional_ref
)
103 def on_menu_enter(self
):
104 self
._menu
_bg
= Background()
106 self
._fsm
, self
.lang_mgr
, self
._options
, self
._music
,
107 self
._pipeline
, self
.scenes
, self
._args
.functional_test
or self
._args
.functional_ref
)
110 self
._fsm
.demand('Menu')
112 def on_menu_exit(self
):
113 self
._menu
_bg
.destroy()
116 def on_scene_enter(self
, cls
):
119 self
.world
, self
.on_home
,
120 self
._options
['development']['auto_close_instructions'],
121 self
._options
['development']['debug_items'],
125 def on_scene_exit(self
):
126 self
._unset
_physics
()
127 self
._scene
.destroy()
129 def reload(self
, cls
):
130 self
._fsm
.demand('Scene', cls
)
132 def _configure(self
, args
):
133 load_prc_file_data('', 'window-title pmachines')
134 load_prc_file_data('', 'framebuffer-srgb true')
135 load_prc_file_data('', 'sync-video true')
136 if args
.functional_test
or args
.functional_ref
:
137 load_prc_file_data('', 'win-size 1360 768')
138 # otherwise it is not centered in exwm
139 # load_prc_file_data('', 'threading-model Cull/Draw')
140 # it freezes when you go to the next scene
142 load_prc_file_data('', 'window-type offscreen')
143 load_prc_file_data('', 'audio-library-name null')
145 def _parse_args(self
):
146 parser
= argparse
.ArgumentParser()
147 parser
.add_argument('--update', action
='store_true')
148 parser
.add_argument('--version', action
='store_true')
149 parser
.add_argument('--optfile')
150 parser
.add_argument('--screenshot')
151 parser
.add_argument('--functional-test', action
='store_true')
152 parser
.add_argument('--functional-ref', action
='store_true')
153 cmd_line
= [arg
for arg
in iter(argv
[1:]) if not arg
.startswith('-psn_')]
154 args
= parser
.parse_args(cmd_line
)
157 def _prepare_window(self
, args
):
159 if (platform
.startswith('win') or platform
.startswith('linux')) and (
160 not exists('main.py') or __file__
.startswith('/app/bin/')):
161 # it is the deployed version for windows
162 data_path
= str(Filename
.get_user_appdata_directory()) + '/pmachines'
163 home
= '/home/flavio' # we must force this for wine
164 if data_path
.startswith('/c/users/') and exists(home
+ '/.wine/'):
165 data_path
= home
+ '/.wine/drive_' + data_path
[1:]
166 info('creating dirs: %s' % data_path
)
167 makedirs(data_path
, exist_ok
=True)
168 optfile
= args
.optfile
if args
.optfile
else 'options.ini'
169 info('data path: %s' % data_path
)
170 info('option file: %s' % optfile
)
171 info('fixed path: %s' % LibP3d
.fixpath(data_path
+ '/' + optfile
))
185 'auto_close_instructions': 0,
190 opt_path
= LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
191 opt_exists
= exists(opt_path
)
192 self
._options
= DctFile(
193 LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
,
196 self
._options
.store()
197 res
= self
._options
['settings']['resolution']
199 res
= LVector2i(*[int(_res
) for _res
in res
.split('x')])
201 d_i
= base
.pipe
.get_display_information()
203 return d_i
.get_display_mode_width(idx
), \
204 d_i
.get_display_mode_height(idx
)
206 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
207 res
= sorted(resolutions
)[-1]
208 fullscreen
= self
._options
['settings']['fullscreen']
209 props
= WindowProperties()
210 if args
.functional_test
or args
.functional_ref
:
214 props
.set_fullscreen(fullscreen
)
215 props
.set_icon_filename('assets/images/icon/pmachines.ico')
216 if not args
.screenshot
and not self
.version
:
217 base
.win
.request_properties(props
)
218 #gltf.patch_loader(base.loader)
219 if self
._options
['development']['simplepbr'] and not self
.version
:
220 self
._pipeline
= simplepbr
.init(
221 use_normal_maps
=True,
222 use_emission_maps
=False,
223 use_occlusion_maps
=True,
224 msaa_samples
=4 if self
._options
['settings']['antialiasing'] else 1,
225 enable_shadows
=int(self
._options
['settings']['shadows']))
226 debug(f
'msaa: {self._pipeline.msaa_samples}')
227 debug(f
'shadows: {self._pipeline.enable_shadows}')
228 render
.setAntialias(AntialiasAttrib
.MAuto
)
229 self
.base
.set_background_color(0, 0, 0, 1)
230 self
.base
.disable_mouse()
231 if self
._options
['development']['show_buffers']:
232 base
.bufferViewer
.toggleEnable()
233 if self
._options
['development']['fps']:
234 base
.set_frame_rate_meter(True)
235 #self.base.accept('window-event', self._on_win_evt)
236 self
.base
.accept('aspectRatioChanged', self
._on
_aspect
_ratio
_changed
)
237 if self
._options
['development']['mouse_coords']:
238 coords_txt
= OnscreenText(
239 '', parent
=base
.a2dTopRight
, scale
=0.04,
240 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
241 def update_coords(task
):
242 txt
= '%s %s' % (int(base
.win
.get_pointer(0).x
),
243 int(base
.win
.get_pointer(0).y
))
244 coords_txt
['text'] = txt
246 taskMgr
.add(update_coords
, 'update_coords')
248 def _set_physics(self
):
249 if self
._options
['development']['physics_debug']:
250 debug_node
= BulletDebugNode('Debug')
251 debug_node
.show_wireframe(True)
252 debug_node
.show_constraints(True)
253 debug_node
.show_bounding_boxes(True)
254 debug_node
.show_normals(True)
255 self
._debug
_np
= render
.attach_new_node(debug_node
)
256 self
._debug
_np
.show()
257 self
.world
= BulletWorld()
258 self
.world
.set_gravity((0, 0, -9.81))
259 if self
._options
['development']['physics_debug']:
260 self
.world
.set_debug_node(self
._debug
_np
.node())
262 dt
= globalClock
.get_dt()
263 self
.world
.do_physics(dt
, 10, 1/180)
265 self
._phys
_tsk
= taskMgr
.add(update
, 'update')
267 def _unset_physics(self
):
268 if self
._options
['development']['physics_debug']:
269 self
._debug
_np
.remove_node()
271 taskMgr
.remove(self
._phys
_tsk
)
273 def _on_aspect_ratio_changed(self
):
274 if self
._fsm
.state
== 'Scene':
275 self
._scene
.on_aspect_ratio_changed()