ya2 · news · projects · code · about

removed uml diagrams
[pmachines.git] / ya2 / lib / p3d / p3d.py
CommitLineData
8ee66edd
FC
1import sys
2from logging import info
3from os.path import exists, dirname
4from os import getcwd, _exit
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
10from direct.showbase.ShowBase import ShowBase
11from direct.showbase.DirectObject import DirectObject
12from direct.task.Task import Task
13#from gltf import patch_loader
14
15
cb700bcc 16# class LibShowBase(ShowBase): pass
8ee66edd
FC
17
18
19class LibP3d(DirectObject):
20
21 task_cont = Task.cont
22
23 def __init__(self):
24 DirectObject.__init__(self)
25 self.__end_cb = self.__notify = None
26 self.__logged_keys = {}
27
28 @staticmethod
29 def runtime(): return not exists('main.py')
30
31 @staticmethod
32 def configure():
33 loadPrcFileData('', 'notify-level-ya2 info')
34 # loadPrcFileData('', 'gl-version 3 2')
35
36 @staticmethod
37 def fixpath(path):
38 home = '/home/flavio'
39 if sys.platform == 'win32' and not exists(exists(home + '/.wine/')):
40 if path.startswith('/'): path = path[1] + ':\\' + path[3:]
41 path = path.replace('/', '\\')
42 return path
43
44 @staticmethod
45 def p3dpath(path): return Filename.fromOsSpecific(path)
46
47 @property
48 def last_frame_dt(self): return globalClock.get_dt()
49
50 @property
51 def build_version(self):
52 appimg_mnt = glob('/tmp/.mount_Yocto*')
53 if appimg_mnt:
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()
57 try:
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')
62 return 'notfound'
63
64 @property
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')
69
70 @property
71 def curr_path(self):
72 if sys.platform == 'darwin':
73 return dirname(__file__) + '/../Resources/'
74 # return dirname(__file__)
75 par_path = str(Path(__file__).parent.absolute())
76 if self.is_appimage:
77 return str(Path(par_path).absolute())
78 is_snap = par_path.startswith('/snap/')
79 is_snap = is_snap and par_path.endswith('/x1')
80 if is_snap:
81 return str(Path(par_path).absolute())
82 #return getcwd()
83 curr_path = dirname(__file__)
84 info('current path: %s' % curr_path)
85 return curr_path
86
87 @staticmethod
88 def send(msg): return messenger.send(msg)
89
90 @staticmethod
91 def do_later(time, meth, args=None):
92 args = args or []
93 return taskMgr.doMethodLater(
94 time, lambda meth, args: meth(*args), meth.__name__, [meth, args])
95
96 @staticmethod
97 def add_task(mth, priority=0):
98 return taskMgr.add(mth, mth.__name__, priority)
99
100 @staticmethod
101 def remove_task(tsk): taskMgr.remove(tsk)
102
103 def init(self, green=(.2, .8, .2, 1), red=(.8, .2, .2, 1), end_cb=None):
104 LibShowBase()
105 base.disableMouse()
106 #patch_loader(base.loader)
107 self.__end_cb = end_cb
108 self.__init_win()
109 self.__init_fonts(green, red)
110 self.__set_roots()
111 self.accept('aspectRatioChanged', self.on_aspect_ratio_changed)
112
113 @staticmethod
114 def __set_roots():
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)
131
132 @staticmethod
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)
139
140 @property
141 def has_window(self): return bool(base.win)
142
143 @property
144 def resolution(self):
145 if not isinstance(base.win, GraphicsWindow):
146 return 800, 600
147 win_prop = base.win.get_properties()
148 return win_prop.get_x_size(), win_prop.get_y_size()
149
150 @property
151 def resolutions(self):
152 d_i = base.pipe.get_display_information()
153
154 def res(idx):
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]
159
160 @staticmethod
161 def toggle_fullscreen():
162 props = WindowProperties()
163 props.set_fullscreen(not base.win.is_fullscreen())
164 base.win.request_properties(props)
165
166 @staticmethod
167 def set_resolution(res, fullscreen=None):
168 props = WindowProperties()
169 props.set_size(res)
170 if fullscreen: props.set_fullscreen(True)
171 if isinstance(base.win, GraphicsWindow):
172 base.win.request_properties(props)
173
174 def __init_win(self):
175 if base.win and isinstance(base.win, GraphicsWindow):
176 base.win.set_close_request_event('window-closed')
177 # not headless
178 self.accept('window-closed', self.__on_end)
179
180 @staticmethod
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)
194
195 def __on_end(self):
196 base.closeWindow(base.win)
197 if self.__end_cb: self.__end_cb()
198 _exit(0)
199
200 @staticmethod
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)
206 return font
207
208 @staticmethod
209 def log(msg): print(msg)
210
211 @property
212 def version(self): return PandaSystem.get_version_string()
213
214 @property
215 def lib_commit(self): return PandaSystem.get_git_commit()
216
217 @property
218 def phys_version(self): return get_bullet_version()
219
220 @property
221 def user_appdata_dir(self): return Filename.get_user_appdata_directory()
222
223 @property
224 def driver_vendor(self): return base.win.get_gsg().get_driver_vendor()
225
226 @property
227 def driver_renderer(self): return base.win.get_gsg().get_driver_renderer()
228
229 @property
230 def driver_shader_version_major(self):
231 return base.win.get_gsg().get_driver_shader_version_major()
232
233 @property
234 def driver_shader_version_minor(self):
235 return base.win.get_gsg().get_driver_shader_version_minor()
236
237 @property
238 def driver_version(self): return base.win.get_gsg().get_driver_version()
239
240 @property
241 def driver_version_major(self):
242 return base.win.get_gsg().get_driver_version_major()
243
244 @property
245 def driver_version_minor(self):
246 return base.win.get_gsg().get_driver_version_minor()
247
248 @property
249 def fullscreen(self):
250 if isinstance(base.win, GraphicsWindow):
251 return base.win.get_properties().get_fullscreen()
252
253 @property
254 def volume(self): return base.sfxManagerList[0].get_volume()
255
256 @volume.setter
257 def volume(self, vol): base.sfxManagerList[0].set_volume(vol)
258
259 @property
260 def mousepos(self):
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()
265
266 @property
267 def aspect_ratio(self): return base.getAspectRatio()
268
269 @staticmethod
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)
275
276 @staticmethod
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)
282
283 @staticmethod
284 def show_std_cursor(): LibP3d.__set_std_cursor(True)
285
286 @staticmethod
287 def hide_std_cursor(): LibP3d.__set_std_cursor(False)
288
289 @staticmethod
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()]
295
296 @staticmethod
297 def load_sfx(filepath, loop=False):
298 sfx = loader.loadSfx(filepath)
299 sfx.set_loop(loop)
300 return sfx
301
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():
306 self.__log_key(
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():
313 self.__log_key(
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')
320 return key
321
322 def remap_str(self, key):
323 if not base.win: # when launched with --version
324 return key
325 #if isinstance(base.win, GraphicsBuffer):
326 # return key
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():
330 self.__log_key(
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():
337 self.__log_key(
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())
344 return key
345
346 def __log_key(self, msg, key1, key2):
347 if key1 in self.__logged_keys and self.__logged_keys[key1] == key2:
348 return
349 self.__logged_keys[key1] = key2
350 print(msg)
351
352 def destroy(self): pass