2 from logging
import info
3 from os
.path
import exists
, dirname
4 from os
import getcwd
, _exit
6 from pathlib
import Path
7 from panda3d
.core
import loadPrcFileData
, Texture
, TextPropertiesManager
, \
8 TextProperties
, PandaSystem
, Filename
, WindowProperties
, GraphicsWindow
9 from panda3d
.bullet
import get_bullet_version
10 from direct
.showbase
.ShowBase
import ShowBase
11 from direct
.showbase
.DirectObject
import DirectObject
12 from direct
.task
.Task
import Task
13 #from gltf import patch_loader
16 class LibShowBase(ShowBase
): pass
19 class LibP3d(DirectObject
):
24 DirectObject
.__init
__(self
)
25 self
.__end
_cb
= self
.__notify
= None
26 self
.__logged
_keys
= {}
29 def runtime(): return not exists('main.py')
33 loadPrcFileData('', 'notify-level-ya2 info')
34 # loadPrcFileData('', 'gl-version 3 2')
39 if sys
.platform
== 'win32' and not exists(exists(home
+ '/.wine/')):
40 if path
.startswith('/'): path
= path
[1] + ':\\' + path
[3:]
41 path
= path
.replace('/', '\\')
45 def p3dpath(path
): return Filename
.fromOsSpecific(path
)
48 def last_frame_dt(self
): return globalClock
.get_dt()
51 def build_version(self
):
52 appimg_mnt
= glob('/tmp/.mount_Yocto*')
54 #with open(appimg_mnt[0] + '/usr/bin/appimage_version.txt') as fver:
55 with
open(self
.curr_path
+ '/assets/bld_version.txt') as fver
:
56 return fver
.read().strip()
58 with
open(self
.curr_path
+ '/assets/bld_version.txt') as fver
:
59 return fver
.read().strip()
60 except FileNotFoundError
:
61 info(self
.curr_path
+ '/assets/bld_version.txt')
65 def is_appimage(self
):
66 par_path
= str(Path(__file__
).parent
.absolute())
67 is_appimage
= par_path
.startswith('/tmp/.mount_Yocto')
68 return is_appimage
and par_path
.endswith('/usr/bin')
72 if sys
.platform
== 'darwin':
73 return dirname(__file__
) + '/../Resources/'
74 # return dirname(__file__)
75 par_path
= str(Path(__file__
).parent
.absolute())
77 return str(Path(par_path
).absolute())
78 is_snap
= par_path
.startswith('/snap/')
79 is_snap
= is_snap
and par_path
.endswith('/x1')
81 return str(Path(par_path
).absolute())
83 curr_path
= dirname(__file__
)
84 info('current path: %s' % curr_path
)
88 def send(msg
): return messenger
.send(msg
)
91 def do_later(time
, meth
, args
=None):
93 return taskMgr
.doMethodLater(
94 time
, lambda meth
, args
: meth(*args
), meth
.__name
__, [meth
, args
])
97 def add_task(mth
, priority
=0):
98 return taskMgr
.add(mth
, mth
.__name
__, priority
)
101 def remove_task(tsk
): taskMgr
.remove(tsk
)
103 def init(self
, green
=(.2, .8, .2, 1), red
=(.8, .2, .2, 1), end_cb
=None):
106 #patch_loader(base.loader)
107 self
.__end
_cb
= end_cb
109 self
.__init
_fonts
(green
, red
)
111 self
.accept('aspectRatioChanged', self
.on_aspect_ratio_changed
)
115 base
.a2dTopQuarter
= base
.aspect2d
.attachNewNode('a2dTopQuarter')
116 base
.a2dTopQuarter
.set_pos(base
.a2dLeft
/ 2, 0, base
.a2dTop
)
117 base
.a2dTopThirdQuarter
= \
118 base
.aspect2d
.attachNewNode('a2dTopThirdQuarter')
119 base
.a2dTopThirdQuarter
.set_pos(base
.a2dRight
/ 2, 0, base
.a2dTop
)
120 base
.a2dCenterQuarter
= base
.aspect2d
.attachNewNode('a2dCenterQuarter')
121 base
.a2dCenterQuarter
.set_pos(base
.a2dLeft
/ 2, 0, 0)
122 base
.a2dCenterThirdQuarter
= \
123 base
.aspect2d
.attachNewNode('a2dCenterThirdQuarter')
124 base
.a2dCenterThirdQuarter
.set_pos(base
.a2dRight
/ 2, 0, 0)
125 base
.a2dBottomQuarter
= base
.aspect2d
.attachNewNode('a2dBottomQuarter')
126 base
.a2dBottomQuarter
.set_pos(base
.a2dLeft
/ 2, 0, base
.a2dBottom
)
127 base
.a2dBottomThirdQuarter
= \
128 base
.aspect2d
.attachNewNode('a2dBottomThirdQuarter')
129 base
.a2dBottomThirdQuarter
.set_pos(
130 base
.a2dRight
/ 2, 0, base
.a2dBottom
)
133 def on_aspect_ratio_changed():
134 base
.a2dTopQuarter
.set_pos(base
.a2dLeft
/ 2, 0, base
.a2dTop
)
135 base
.a2dTopThirdQuarter
.set_pos(base
.a2dRight
/ 2, 0, base
.a2dTop
)
136 base
.a2dBottomQuarter
.set_pos(base
.a2dLeft
/ 2, 0, base
.a2dBottom
)
137 base
.a2dBottomThirdQuarter
.set_pos(
138 base
.a2dRight
/ 2, 0, base
.a2dBottom
)
141 def has_window(self
): return bool(base
.win
)
144 def resolution(self
):
145 if not isinstance(base
.win
, GraphicsWindow
):
147 win_prop
= base
.win
.get_properties()
148 return win_prop
.get_x_size(), win_prop
.get_y_size()
151 def resolutions(self
):
152 d_i
= base
.pipe
.get_display_information()
155 return d_i
.get_display_mode_width(idx
), \
156 d_i
.get_display_mode_height(idx
)
157 ret
= [res(idx
) for idx
in range(d_i
.get_total_display_modes())]
158 return ret
if ret
else [self
.resolution
]
161 def toggle_fullscreen():
162 props
= WindowProperties()
163 props
.set_fullscreen(not base
.win
.is_fullscreen())
164 base
.win
.request_properties(props
)
167 def set_resolution(res
, fullscreen
=None):
168 props
= WindowProperties()
170 if fullscreen
: props
.set_fullscreen(True)
171 if isinstance(base
.win
, GraphicsWindow
):
172 base
.win
.request_properties(props
)
174 def __init_win(self
):
175 if base
.win
and isinstance(base
.win
, GraphicsWindow
):
176 base
.win
.set_close_request_event('window-closed')
178 self
.accept('window-closed', self
.__on
_end
)
181 def __init_fonts(green
=(.2, .8, .2, 1), red
=(.8, .2, .2, 1)):
182 tp_mgr
= TextPropertiesManager
.get_global_ptr()
183 for namecol
, col
in zip(['green', 'red'], [green
, red
]):
184 props
= TextProperties()
185 props
.set_text_color(col
)
186 tp_mgr
.set_properties(namecol
, props
)
187 for namesize
, col
in zip(['small', 'smaller'], [.46, .72]):
188 props
= TextProperties()
189 props
.set_text_scale(.46)
190 tp_mgr
.set_properties(namesize
, props
)
191 tp_italic
= TextProperties()
192 tp_italic
.set_slant(.2)
193 tp_mgr
.set_properties('italic', tp_italic
)
196 base
.closeWindow(base
.win
)
197 if self
.__end
_cb
: self
.__end
_cb
()
201 def load_font(filepath
, outline
=True):
202 font
= base
.loader
.loadFont(filepath
)
203 font
.set_pixels_per_unit(60)
204 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
205 if outline
: font
.set_outline((0, 0, 0, 1), .8, .2)
209 def log(msg
): print(msg
)
212 def version(self
): return PandaSystem
.get_version_string()
215 def lib_commit(self
): return PandaSystem
.get_git_commit()
218 def phys_version(self
): return get_bullet_version()
221 def user_appdata_dir(self
): return Filename
.get_user_appdata_directory()
224 def driver_vendor(self
): return base
.win
.get_gsg().get_driver_vendor()
227 def driver_renderer(self
): return base
.win
.get_gsg().get_driver_renderer()
230 def driver_shader_version_major(self
):
231 return base
.win
.get_gsg().get_driver_shader_version_major()
234 def driver_shader_version_minor(self
):
235 return base
.win
.get_gsg().get_driver_shader_version_minor()
238 def driver_version(self
): return base
.win
.get_gsg().get_driver_version()
241 def driver_version_major(self
):
242 return base
.win
.get_gsg().get_driver_version_major()
245 def driver_version_minor(self
):
246 return base
.win
.get_gsg().get_driver_version_minor()
249 def fullscreen(self
):
250 if isinstance(base
.win
, GraphicsWindow
):
251 return base
.win
.get_properties().get_fullscreen()
254 def volume(self
): return base
.sfxManagerList
[0].get_volume()
257 def volume(self
, vol
): base
.sfxManagerList
[0].set_volume(vol
)
261 mwn
= base
.mouseWatcherNode
262 if not mwn
: return 0, 0
263 if not mwn
.hasMouse(): return 0, 0
264 return mwn
.get_mouse_x(), mwn
.get_mouse_y()
267 def aspect_ratio(self
): return base
.getAspectRatio()
270 def set_icon(filename
):
271 props
= WindowProperties()
272 props
.set_icon_filename(filename
)
273 if isinstance(base
.win
, GraphicsWindow
):
274 base
.win
.requestProperties(props
)
277 def __set_std_cursor(show
):
278 props
= WindowProperties()
279 props
.set_cursor_hidden(not show
)
280 if isinstance(base
.win
, GraphicsWindow
):
281 base
.win
.requestProperties(props
)
284 def show_std_cursor(): LibP3d
.__set
_std
_cursor
(True)
287 def hide_std_cursor(): LibP3d
.__set
_std
_cursor
(False)
290 def find_geoms(model
, name
): # no need to be cached
291 geoms
= model
.node
.find_all_matches('**/+GeomNode')
292 is_nm
= lambda geom
: geom
.get_name().startswith(name
)
293 named_geoms
= [geom
for geom
in geoms
if is_nm(geom
)]
294 return [ng
for ng
in named_geoms
if name
in ng
.get_name()]
297 def load_sfx(filepath
, loop
=False):
298 sfx
= loader
.loadSfx(filepath
)
302 def remap_code(self
, key
):
303 kmap
= base
.win
.get_keyboard_map()
304 for i
in range(kmap
.get_num_buttons()):
305 if key
.lower() == kmap
.get_mapped_button_label(i
).lower():
307 'code mapping %s to key %s' %
308 (key
, kmap
.get_mapped_button(i
)), key
,
309 kmap
.get_mapped_button(i
))
310 return kmap
.get_mapped_button(i
)
311 for i
in range(kmap
.get_num_buttons()):
312 if key
.lower() == kmap
.get_mapped_button(i
).get_name().lower():
314 'code mapping %s to key %s' %
315 (key
, kmap
.get_mapped_button(i
)), key
,
316 kmap
.get_mapped_button(i
))
317 return kmap
.get_mapped_button(i
)
318 self
.__log
_key
('not found a code mapping for %s' %
319 key
, key
, 'not_found')
322 def remap_str(self
, key
):
323 if not base
.win
: # when launched with --version
325 #if isinstance(base.win, GraphicsBuffer):
327 kmap
= base
.win
.get_keyboard_map()
328 for i
in range(kmap
.get_num_buttons()):
329 if str(key
).lower() == kmap
.get_mapped_button_label(i
).lower():
331 'string mapping %s to key %s' %
332 (key
, kmap
.get_mapped_button(i
).get_name()), key
,
333 kmap
.get_mapped_button(i
).get_name())
334 return kmap
.get_mapped_button(i
).get_name()
335 for i
in range(kmap
.get_num_buttons()):
336 if key
.lower() == kmap
.get_mapped_button(i
).get_name().lower():
338 'string mapping %s to key %s' %
339 (key
, kmap
.get_mapped_button(i
).get_name()), key
,
340 kmap
.get_mapped_button(i
).get_name())
341 return kmap
.get_mapped_button(i
).get_name()
342 self
.__log
_key
('not found a string mapping for %s' %
343 key
, key
, kmap
.get_mapped_button(i
).get_name())
346 def __log_key(self
, msg
, key1
, key2
):
347 if key1
in self
.__logged
_keys
and self
.__logged
_keys
[key1
] == key2
:
349 self
.__logged
_keys
[key1
] = key2
352 def destroy(self
): pass