ya2 · news · projects · code · about

some cleaning
[pmachines.git] / ya2 / p3d / p3d.py
CommitLineData
8ee66edd
FC
1import sys
2from logging import info
3from os.path import exists, dirname
e65a09cf 4from os import _exit
8ee66edd
FC
5from glob import glob
6from pathlib import Path
7from panda3d.core import loadPrcFileData, Texture, TextPropertiesManager, \
8 TextProperties, PandaSystem, Filename, WindowProperties, GraphicsWindow
9from panda3d.bullet import get_bullet_version
8ee66edd
FC
10from direct.showbase.DirectObject import DirectObject
11from direct.task.Task import Task
e65a09cf 12# from gltf import patch_loader
8ee66edd
FC
13
14
cb700bcc 15# class LibShowBase(ShowBase): pass
8ee66edd
FC
16
17
18class LibP3d(DirectObject):
19
20 task_cont = Task.cont
21
22 def __init__(self):
23 DirectObject.__init__(self)
24 self.__end_cb = self.__notify = None
25 self.__logged_keys = {}
26
27 @staticmethod
28 def runtime(): return not exists('main.py')
29
30 @staticmethod
31 def configure():
32 loadPrcFileData('', 'notify-level-ya2 info')
33 # loadPrcFileData('', 'gl-version 3 2')
34
35 @staticmethod
36 def fixpath(path):
37 home = '/home/flavio'
38 if sys.platform == 'win32' and not exists(exists(home + '/.wine/')):
e65a09cf
FC
39 if path.startswith('/'):
40 path = path[1] + ':\\' + path[3:]
8ee66edd
FC
41 path = path.replace('/', '\\')
42 return path
43
44 @staticmethod
45 def p3dpath(path): return Filename.fromOsSpecific(path)
46
47 @property
e65a09cf
FC
48 def last_frame_dt(self):
49 return globalClock.get_dt()
8ee66edd
FC
50
51 @property
52 def build_version(self):
53 appimg_mnt = glob('/tmp/.mount_Yocto*')
54 if appimg_mnt:
e65a09cf
FC
55 # with open(
56 # appimg_mnt[0] + '/usr/bin/appimage_version.txt') as fver:
8ee66edd
FC
57 with open(self.curr_path + '/assets/bld_version.txt') as fver:
58 return fver.read().strip()
59 try:
60 with open(self.curr_path + '/assets/bld_version.txt') as fver:
61 return fver.read().strip()
62 except FileNotFoundError:
63 info(self.curr_path + '/assets/bld_version.txt')
64 return 'notfound'
65
66 @property
67 def is_appimage(self):
68 par_path = str(Path(__file__).parent.absolute())
69 is_appimage = par_path.startswith('/tmp/.mount_Yocto')
70 return is_appimage and par_path.endswith('/usr/bin')
71
72 @property
73 def curr_path(self):
74 if sys.platform == 'darwin':
75 return dirname(__file__) + '/../Resources/'
76 # return dirname(__file__)
77 par_path = str(Path(__file__).parent.absolute())
78 if self.is_appimage:
79 return str(Path(par_path).absolute())
80 is_snap = par_path.startswith('/snap/')
81 is_snap = is_snap and par_path.endswith('/x1')
82 if is_snap:
83 return str(Path(par_path).absolute())
e65a09cf 84 # return getcwd()
8ee66edd
FC
85 curr_path = dirname(__file__)
86 info('current path: %s' % curr_path)
87 return curr_path
88
89 @staticmethod
e65a09cf
FC
90 def send(msg):
91 return messenger.send(msg)
8ee66edd
FC
92
93 @staticmethod
94 def do_later(time, meth, args=None):
95 args = args or []
96 return taskMgr.doMethodLater(
97 time, lambda meth, args: meth(*args), meth.__name__, [meth, args])
98
99 @staticmethod
100 def add_task(mth, priority=0):
101 return taskMgr.add(mth, mth.__name__, priority)
102
103 @staticmethod
e65a09cf
FC
104 def remove_task(tsk):
105 taskMgr.remove(tsk)
106
107 # def init(self, green=(.2, .8, .2, 1), red=(.8, .2, .2, 1), end_cb=None):
108 # LibShowBase()
109 # base.disableMouse()
110 # #patch_loader(base.loader)
111 # self.__end_cb = end_cb
112 # self.__init_win()
113 # self.__init_fonts(green, red)
114 # self.__set_roots()
115 # self.accept('aspectRatioChanged', self.on_aspect_ratio_changed)
8ee66edd
FC
116
117 @staticmethod
118 def __set_roots():
e65a09cf 119 base = base
8ee66edd
FC
120 base.a2dTopQuarter = base.aspect2d.attachNewNode('a2dTopQuarter')
121 base.a2dTopQuarter.set_pos(base.a2dLeft / 2, 0, base.a2dTop)
122 base.a2dTopThirdQuarter = \
123 base.aspect2d.attachNewNode('a2dTopThirdQuarter')
124 base.a2dTopThirdQuarter.set_pos(base.a2dRight / 2, 0, base.a2dTop)
125 base.a2dCenterQuarter = base.aspect2d.attachNewNode('a2dCenterQuarter')
126 base.a2dCenterQuarter.set_pos(base.a2dLeft / 2, 0, 0)
127 base.a2dCenterThirdQuarter = \
128 base.aspect2d.attachNewNode('a2dCenterThirdQuarter')
129 base.a2dCenterThirdQuarter.set_pos(base.a2dRight / 2, 0, 0)
130 base.a2dBottomQuarter = base.aspect2d.attachNewNode('a2dBottomQuarter')
131 base.a2dBottomQuarter.set_pos(base.a2dLeft / 2, 0, base.a2dBottom)
132 base.a2dBottomThirdQuarter = \
133 base.aspect2d.attachNewNode('a2dBottomThirdQuarter')
134 base.a2dBottomThirdQuarter.set_pos(
135 base.a2dRight / 2, 0, base.a2dBottom)
136
137 @staticmethod
138 def on_aspect_ratio_changed():
e65a09cf 139 base = base
8ee66edd
FC
140 base.a2dTopQuarter.set_pos(base.a2dLeft / 2, 0, base.a2dTop)
141 base.a2dTopThirdQuarter.set_pos(base.a2dRight / 2, 0, base.a2dTop)
142 base.a2dBottomQuarter.set_pos(base.a2dLeft / 2, 0, base.a2dBottom)
143 base.a2dBottomThirdQuarter.set_pos(
144 base.a2dRight / 2, 0, base.a2dBottom)
145
146 @property
e65a09cf
FC
147 def has_window(self):
148 return bool(base.win)
8ee66edd
FC
149
150 @property
151 def resolution(self):
152 if not isinstance(base.win, GraphicsWindow):
153 return 800, 600
154 win_prop = base.win.get_properties()
155 return win_prop.get_x_size(), win_prop.get_y_size()
156
157 @property
158 def resolutions(self):
159 d_i = base.pipe.get_display_information()
160
161 def res(idx):
162 return d_i.get_display_mode_width(idx), \
163 d_i.get_display_mode_height(idx)
164 ret = [res(idx) for idx in range(d_i.get_total_display_modes())]
165 return ret if ret else [self.resolution]
166
167 @staticmethod
168 def toggle_fullscreen():
169 props = WindowProperties()
170 props.set_fullscreen(not base.win.is_fullscreen())
171 base.win.request_properties(props)
172
173 @staticmethod
174 def set_resolution(res, fullscreen=None):
175 props = WindowProperties()
176 props.set_size(res)
e65a09cf
FC
177 if fullscreen:
178 props.set_fullscreen(True)
8ee66edd
FC
179 if isinstance(base.win, GraphicsWindow):
180 base.win.request_properties(props)
181
182 def __init_win(self):
183 if base.win and isinstance(base.win, GraphicsWindow):
184 base.win.set_close_request_event('window-closed')
185 # not headless
186 self.accept('window-closed', self.__on_end)
187
188 @staticmethod
189 def __init_fonts(green=(.2, .8, .2, 1), red=(.8, .2, .2, 1)):
190 tp_mgr = TextPropertiesManager.get_global_ptr()
191 for namecol, col in zip(['green', 'red'], [green, red]):
192 props = TextProperties()
193 props.set_text_color(col)
194 tp_mgr.set_properties(namecol, props)
195 for namesize, col in zip(['small', 'smaller'], [.46, .72]):
196 props = TextProperties()
197 props.set_text_scale(.46)
198 tp_mgr.set_properties(namesize, props)
199 tp_italic = TextProperties()
200 tp_italic.set_slant(.2)
201 tp_mgr.set_properties('italic', tp_italic)
202
203 def __on_end(self):
204 base.closeWindow(base.win)
e65a09cf
FC
205 if self.__end_cb:
206 self.__end_cb()
8ee66edd
FC
207 _exit(0)
208
209 @staticmethod
210 def load_font(filepath, outline=True):
211 font = base.loader.loadFont(filepath)
212 font.set_pixels_per_unit(60)
213 font.set_minfilter(Texture.FTLinearMipmapLinear)
e65a09cf
FC
214 if outline:
215 font.set_outline((0, 0, 0, 1), .8, .2)
8ee66edd
FC
216 return font
217
218 @staticmethod
219 def log(msg): print(msg)
220
221 @property
222 def version(self): return PandaSystem.get_version_string()
223
224 @property
225 def lib_commit(self): return PandaSystem.get_git_commit()
226
227 @property
228 def phys_version(self): return get_bullet_version()
229
230 @property
231 def user_appdata_dir(self): return Filename.get_user_appdata_directory()
232
233 @property
e65a09cf
FC
234 def driver_vendor(self):
235 return base.win.get_gsg().get_driver_vendor()
8ee66edd
FC
236
237 @property
e65a09cf
FC
238 def driver_renderer(self):
239 return base.win.get_gsg().get_driver_renderer()
8ee66edd
FC
240
241 @property
242 def driver_shader_version_major(self):
243 return base.win.get_gsg().get_driver_shader_version_major()
244
245 @property
246 def driver_shader_version_minor(self):
247 return base.win.get_gsg().get_driver_shader_version_minor()
248
249 @property
e65a09cf
FC
250 def driver_version(self):
251 return base.win.get_gsg().get_driver_version()
8ee66edd
FC
252
253 @property
254 def driver_version_major(self):
255 return base.win.get_gsg().get_driver_version_major()
256
257 @property
258 def driver_version_minor(self):
259 return base.win.get_gsg().get_driver_version_minor()
260
261 @property
262 def fullscreen(self):
263 if isinstance(base.win, GraphicsWindow):
264 return base.win.get_properties().get_fullscreen()
265
266 @property
e65a09cf
FC
267 def volume(self):
268 return base.sfxManagerList[0].get_volume()
8ee66edd
FC
269
270 @volume.setter
e65a09cf
FC
271 def volume(self, vol):
272 base.sfxManagerList[0].set_volume(vol)
8ee66edd
FC
273
274 @property
275 def mousepos(self):
276 mwn = base.mouseWatcherNode
e65a09cf
FC
277 if not mwn:
278 return 0, 0
279 if not mwn.hasMouse():
280 return 0, 0
8ee66edd
FC
281 return mwn.get_mouse_x(), mwn.get_mouse_y()
282
283 @property
e65a09cf
FC
284 def aspect_ratio(self):
285 return base.getAspectRatio()
8ee66edd 286
2d1773b1
FC
287 @staticmethod
288 def wdg_pos(wdg):
289 pos = wdg.get_pos(pixel2d)
290 return int(round(pos[0])), int(round(-pos[2]))
291
8ee66edd
FC
292 @staticmethod
293 def set_icon(filename):
294 props = WindowProperties()
295 props.set_icon_filename(filename)
296 if isinstance(base.win, GraphicsWindow):
297 base.win.requestProperties(props)
298
299 @staticmethod
300 def __set_std_cursor(show):
301 props = WindowProperties()
302 props.set_cursor_hidden(not show)
303 if isinstance(base.win, GraphicsWindow):
304 base.win.requestProperties(props)
305
306 @staticmethod
307 def show_std_cursor(): LibP3d.__set_std_cursor(True)
308
309 @staticmethod
310 def hide_std_cursor(): LibP3d.__set_std_cursor(False)
311
312 @staticmethod
313 def find_geoms(model, name): # no need to be cached
314 geoms = model.node.find_all_matches('**/+GeomNode')
e65a09cf
FC
315
316 def is_nm(geom):
317 return geom.get_name().startswith(name)
8ee66edd
FC
318 named_geoms = [geom for geom in geoms if is_nm(geom)]
319 return [ng for ng in named_geoms if name in ng.get_name()]
320
321 @staticmethod
322 def load_sfx(filepath, loop=False):
323 sfx = loader.loadSfx(filepath)
324 sfx.set_loop(loop)
325 return sfx
326
327 def remap_code(self, key):
328 kmap = base.win.get_keyboard_map()
329 for i in range(kmap.get_num_buttons()):
330 if key.lower() == kmap.get_mapped_button_label(i).lower():
331 self.__log_key(
332 'code mapping %s to key %s' %
333 (key, kmap.get_mapped_button(i)), key,
334 kmap.get_mapped_button(i))
335 return kmap.get_mapped_button(i)
336 for i in range(kmap.get_num_buttons()):
337 if key.lower() == kmap.get_mapped_button(i).get_name().lower():
338 self.__log_key(
339 'code mapping %s to key %s' %
340 (key, kmap.get_mapped_button(i)), key,
341 kmap.get_mapped_button(i))
342 return kmap.get_mapped_button(i)
343 self.__log_key('not found a code mapping for %s' %
344 key, key, 'not_found')
345 return key
346
347 def remap_str(self, key):
348 if not base.win: # when launched with --version
349 return key
e65a09cf
FC
350 # if isinstance(base.win, GraphicsBuffer):
351 # return key
8ee66edd
FC
352 kmap = base.win.get_keyboard_map()
353 for i in range(kmap.get_num_buttons()):
354 if str(key).lower() == kmap.get_mapped_button_label(i).lower():
355 self.__log_key(
356 'string mapping %s to key %s' %
357 (key, kmap.get_mapped_button(i).get_name()), key,
358 kmap.get_mapped_button(i).get_name())
359 return kmap.get_mapped_button(i).get_name()
360 for i in range(kmap.get_num_buttons()):
361 if key.lower() == kmap.get_mapped_button(i).get_name().lower():
362 self.__log_key(
363 'string mapping %s to key %s' %
364 (key, kmap.get_mapped_button(i).get_name()), key,
365 kmap.get_mapped_button(i).get_name())
366 return kmap.get_mapped_button(i).get_name()
367 self.__log_key('not found a string mapping for %s' %
368 key, key, kmap.get_mapped_button(i).get_name())
369 return key
370
371 def __log_key(self, msg, key1, key2):
372 if key1 in self.__logged_keys and self.__logged_keys[key1] == key2:
373 return
374 self.__logged_keys[key1] = key2
375 print(msg)
376
377 def destroy(self): pass