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 pmachines
.music
import MusicMgr
17 from pmachines
.items
.background
import Background
18 from pmachines
.menu
import Menu
19 from pmachines
.scene
import Scene
20 from lib
.dictfile
import DctFile
21 from lib
.lib
.p3d
.p3d
import LibP3d
22 from lib
.engine
.lang
import LangMgr
27 def __init__(self
, pmachines
):
28 super().__init
__('Main FSM')
29 self
._pmachines
= pmachines
32 self
._pmachines
.on_menu_enter()
35 self
._pmachines
.on_menu_exit()
37 def enterScene(self
, cls
):
38 self
._pmachines
.on_scene_enter(cls
)
41 self
._pmachines
.on_scene_exit()
47 info('platform: %s' % platform
)
48 info('exists main.py: %s' % exists('main.py'))
49 args
= self
._parse
_args
()
51 self
.base
= ShowBase()
52 self
._prepare
_window
(args
)
53 self
.updating
= args
.update
54 self
.version
= args
.version
57 self
._music
= MusicMgr(self
._options
['settings']['volume'])
58 self
.lang_mgr
= LangMgr(self
._options
['settings']['language'],
61 self
._fsm
= MainFsm(self
)
64 for _file
in glob('pmachines/scenes/*.py'):
65 _fn
= _file
.replace('.py', '').replace('/', '.')
66 for member
in import_module(_fn
).__dict
__.values():
67 if isclass(member
) and issubclass(member
, Scene
) and \
69 scene_classes
+= [member
]
70 cls
= [cls
for cls
in scene_classes
if cls
.__name
__ == args
.screenshot
][0]
71 scene
= cls(BulletWorld(), None, True, False, lambda: None)
75 elif self
._options
['development']['auto_start']:
76 mod_name
= 'pmachines.scenes.scene_' + self
._options
['development']['auto_start']
77 for member
in import_module(mod_name
).__dict
__.values():
78 if isclass(member
) and issubclass(member
, Scene
) and \
81 self
._fsm
.demand('Scene', cls
)
83 self
._fsm
.demand('Menu')
85 def on_menu_enter(self
):
86 self
._menu
_bg
= Background()
88 self
._fsm
, self
.lang_mgr
, self
._options
, self
._music
,
92 self
._fsm
.demand('Menu')
94 def on_menu_exit(self
):
95 self
._menu
_bg
.destroy()
98 def on_scene_enter(self
, cls
):
101 self
.world
, self
.on_home
,
102 self
._options
['development']['auto_close_instructions'],
103 self
._options
['development']['debug_items'],
106 def on_scene_exit(self
):
107 self
._unset
_physics
()
108 self
._scene
.destroy()
110 def reload(self
, cls
):
111 self
._fsm
.demand('Scene', cls
)
113 def _configure(self
, args
):
114 load_prc_file_data('', 'window-title pmachines')
115 load_prc_file_data('', 'framebuffer-srgb true')
116 load_prc_file_data('', 'sync-video true')
117 # load_prc_file_data('', 'threading-model Cull/Draw')
118 # it freezes when you go to the next scene
120 load_prc_file_data('', 'window-type offscreen')
121 load_prc_file_data('', 'audio-library-name null')
123 def _parse_args(self
):
124 parser
= argparse
.ArgumentParser()
125 parser
.add_argument('--update', action
='store_true')
126 parser
.add_argument('--version', action
='store_true')
127 parser
.add_argument('--optfile')
128 parser
.add_argument('--screenshot')
129 cmd_line
= [arg
for arg
in iter(argv
[1:]) if not arg
.startswith('-psn_')]
130 args
= parser
.parse_args(cmd_line
)
133 def _prepare_window(self
, args
):
135 if (platform
.startswith('win') or platform
.startswith('linux')) and (
136 not exists('main.py') or __file__
.startswith('/app/bin/')):
137 # it is the deployed version for windows
138 data_path
= str(Filename
.get_user_appdata_directory()) + '/pmachines'
139 home
= '/home/flavio' # we must force this for wine
140 if data_path
.startswith('/c/users/') and exists(home
+ '/.wine/'):
141 data_path
= home
+ '/.wine/drive_' + data_path
[1:]
142 info('creating dirs: %s' % data_path
)
143 makedirs(data_path
, exist_ok
=True)
144 optfile
= args
.optfile
if args
.optfile
else 'options.ini'
145 info('data path: %s' % data_path
)
146 info('option file: %s' % optfile
)
147 info('fixed path: %s' % LibP3d
.fixpath(data_path
+ '/' + optfile
))
161 'auto_close_instructions': 0,
165 opt_path
= LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
166 opt_exists
= exists(opt_path
)
167 self
._options
= DctFile(
168 LibP3d
.fixpath(data_path
+ '/' + optfile
) if data_path
else optfile
,
171 self
._options
.store()
172 res
= self
._options
['settings']['resolution']
174 res
= LVector2i(*[int(_res
) for _res
in res
.split('x')])
176 d_i
= base
.pipe
.get_display_information()
178 return d_i
.get_display_mode_width(idx
), \
179 d_i
.get_display_mode_height(idx
)
181 _res(idx
) for idx
in range(d_i
.get_total_display_modes())]
182 res
= sorted(resolutions
)[-1]
183 props
= WindowProperties()
185 props
.set_fullscreen(self
._options
['settings']['fullscreen'])
186 props
.set_icon_filename('assets/icon/pmachines.ico')
187 if not args
.screenshot
:
188 base
.win
.request_properties(props
)
189 gltf
.patch_loader(base
.loader
)
190 if self
._options
['development']['simplepbr']:
191 self
._pipeline
= simplepbr
.init(
192 use_normal_maps
=True,
193 use_emission_maps
=False,
194 use_occlusion_maps
=True,
195 msaa_samples
=4 if self
._options
['settings']['antialiasing'] else 1,
196 enable_shadows
=int(self
._options
['settings']['shadows']))
197 debug(f
'msaa: {self._pipeline.msaa_samples}')
198 debug(f
'shadows: {self._pipeline.enable_shadows}')
199 render
.setAntialias(AntialiasAttrib
.MAuto
)
200 self
.base
.set_background_color(0, 0, 0, 1)
201 self
.base
.disable_mouse()
202 if self
._options
['development']['show_buffers']:
203 base
.bufferViewer
.toggleEnable()
204 if self
._options
['development']['fps']:
205 base
.set_frame_rate_meter(True)
206 #self.base.accept('window-event', self._on_win_evt)
207 self
.base
.accept('aspectRatioChanged', self
._on
_aspect
_ratio
_changed
)
209 def _set_physics(self
):
210 if self
._options
['development']['physics_debug']:
211 debug_node
= BulletDebugNode('Debug')
212 debug_node
.show_wireframe(True)
213 debug_node
.show_constraints(True)
214 debug_node
.show_bounding_boxes(True)
215 debug_node
.show_normals(True)
216 self
._debug
_np
= render
.attach_new_node(debug_node
)
217 self
._debug
_np
.show()
218 self
.world
= BulletWorld()
219 self
.world
.set_gravity((0, 0, -9.81))
220 if self
._options
['development']['physics_debug']:
221 self
.world
.set_debug_node(self
._debug
_np
.node())
223 dt
= globalClock
.get_dt()
224 self
.world
.do_physics(dt
, 10, 1/180)
226 self
._phys
_tsk
= taskMgr
.add(update
, 'update')
228 def _unset_physics(self
):
229 if self
._options
['development']['physics_debug']:
230 self
._debug
_np
.remove_node()
232 taskMgr
.remove(self
._phys
_tsk
)
234 def _on_aspect_ratio_changed(self
):
235 if self
._fsm
.state
== 'Scene':
236 self
._scene
.on_aspect_ratio_changed()