Commit | Line | Data |
---|---|---|
8ee66edd FC |
1 | import sys |
2 | from logging import info | |
3 | from os.path import exists, dirname | |
e65a09cf | 4 | from os import _exit |
8ee66edd FC |
5 | from glob import glob |
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 | |
8ee66edd FC |
10 | from direct.showbase.DirectObject import DirectObject |
11 | from 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 | ||
18 | class 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(): | |
c991401b | 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(): | |
c991401b | 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 |