ya2 · news · projects · code · about

first commit
[pmachines.git] / lib / lib / p3d / gfx.py
CommitLineData
8ee66edd
FC
1import datetime
2from logging import debug, info
3from os import getcwd
4from os.path import exists, dirname
5from panda3d.core import get_model_path, AntialiasAttrib, PandaNode, \
6 LightRampAttrib, Camera, OrthographicLens, NodePath, OmniBoundingVolume, \
7 AmbientLight as P3DAmbientLight, Spotlight as P3DSpotlight, Point2, \
8 Point3, Texture
9from direct.filter.CommonFilters import CommonFilters
10from direct.actor.Actor import Actor
11from lib.lib.p3d.p3d import LibP3d
12
13
14class RenderToTexture:
15
16 def __init__(self, size=(256, 256)):
17 self.__set_buffer(size)
18 self.__set_display_region()
19 self.__set_camera()
20 self.__set_root()
21 self.display_region.set_camera(self.camera)
22
23 def __set_buffer(self, size):
24 self.buffer = base.win.make_texture_buffer('result buffer', size[0],
25 size[1])
26 self.buffer.set_sort(-100)
27
28 def __set_display_region(self):
29 self.display_region = self.buffer.make_display_region()
30 self.display_region.set_sort(20)
31
32 def __set_camera(self):
33 self.camera = NodePath(Camera('camera 2d'))
34 lens = OrthographicLens()
35 lens.set_film_size(1, 1)
36 lens.set_near_far(-1000, 1000)
37 self.camera.node().set_lens(lens)
38
39 def __set_root(self):
40 self.root = NodePath('root')
41 self.root.set_depth_test(False)
42 self.root.set_depth_write(False)
43 self.camera.reparent_to(self.root)
44
45 @property
46 def texture(self): return self.buffer.get_texture()
47
48 def destroy(self):
49 base.graphicsEngine.remove_window(self.buffer)
50 if base.win: # if you close the window during a race
51 base.win.remove_display_region(self.display_region)
52 list(map(lambda node: node.remove_node(), [self.camera, self.root]))
53
54
55class P3dGfxMgr:
56
57 def __init__(self, model_path, antialiasing, shaders, srgb):
58 self.root = P3dNode(render)
59 self.__srgb = srgb
60 self.callbacks = {}
61 self.filters = None
62 get_model_path().append_directory(model_path)
63 if LibP3d.runtime():
64 root_dir = LibP3d.p3dpath(dirname(__file__))
65 paths = [root_dir + '/' + model_path, root_dir]
66 list(map(get_model_path().append_directory, paths))
67 render.set_shader_auto()
68 # render.set_two_sided(True) # it breaks shadows
69 if antialiasing: render.set_antialias(AntialiasAttrib.MAuto)
70 if shaders and base.win:
71 self.filters = CommonFilters(base.win, base.cam)
72
73 def load_model(self, filename, callback=None, anim=None):
74 ext = '.bam' if exists(filename + '.bam') else ''
75 if anim:
76 anim_dct = {'anim': filename + '-Anim' + ext}
77 node = P3dNode(self.set_srgb(Actor(filename + ext, anim_dct)))
78 elif callback:
79 callb = lambda model: callback(P3dNode(self.set_srgb(model)))
80 node = loader.loadModel(filename + ext, callback=callb)
81 else:
82 node = P3dNode(self.set_srgb(
83 loader.loadModel(LibP3d.p3dpath(filename + ext))))
84 return node
85
86 def set_srgb(self, model):
87 if self.__srgb:
88 for texture in model.find_all_textures():
89 if texture.get_format() in [Texture.F_rgba, Texture.F_rgbm]:
90 texture.set_format(Texture.F_srgb_alpha)
91 elif texture.get_format() in [Texture.F_rgb]:
92 texture.set_format(Texture.F_srgb)
93 return model
94
95 @staticmethod
96 def toggle_aa():
97 aa_not_none = render.get_antialias() != AntialiasAttrib.MNone
98 if render.has_antialias() and aa_not_none:
99 render.clear_antialias()
100 else: render.set_antialias(AntialiasAttrib.MAuto, 1)
101
102 def set_toon(self):
103 tmp_node = NodePath(PandaNode('temp node'))
104 tmp_node.set_attrib(LightRampAttrib.make_single_threshold(.5, .4))
105 tmp_node.set_shader_auto()
106 base.cam.node().set_initial_state(tmp_node.get_state())
107 self.filters.set_cartoon_ink(separation=1)
108
109 def set_bloom(self):
110 if not base.win: return
111 self.filters.setBloom(
112 blend=(.3, .4, .3, 0), mintrigger=.6, maxtrigger=1.0, desat=.6,
113 intensity=1.0, size='medium')
114 # default: (.3, .4, .3, 0), .6, 1, .6, 1, 'medium'
115
116 @staticmethod
117 def pos2d(node):
118 p3d = base.cam.get_relative_point(node.node, Point3(0, 0, 0))
119 p2d = Point2()
120 return p2d if base.camLens.project(p3d, p2d) else None
121
122 @property
123 def shader_support(self):
124 return base.win.get_gsg().get_supports_basic_shaders()
125
126 def screenshot(self, path=None):
127 time = datetime.datetime.now().strftime('%y%m%d%H%M%S')
128 #res = base.win.save_screenshot(Filename(path or ("yocto%s.png" % time)))
129 #debug('screenshot %s (%s)' % (path or ("yocto%s.png" % time), res))
130 res = base.screenshot(path or ("yocto%s.png" % time), False)
131 info('screenshot %s (%s; %s)' % (path or ("yocto%s.png" % time), res, getcwd()))
132
133 @staticmethod
134 def enable_shader(): render.set_shader_auto()
135
136 @staticmethod
137 def disable_shader(): render.set_shader_off()
138
139 @staticmethod
140 def print_stats(two_d=True, three_d=True, analyze=True, ls=True):
141 '''Print graphics stats. They use standard output (from p3d).'''
142 info = []
143 if two_d and analyze:
144 info +=[('render2d.analyze', base.render2d.analyze)]
145 if three_d and analyze:
146 info +=[('render.analyze', base.render.analyze)]
147 if two_d and ls:
148 info +=[('render2d.ls', base.render2d.ls)]
149 if three_d and ls:
150 info +=[('render.ls', base.render.ls)]
151 for elm in info:
152 print('\n\n#####\n%s()' % elm[0])
153 elm[1]()
154
155
156class P3dNode:
157
158 def __init__(self, nodepath):
159 self.nodepath = nodepath
160 self.node.set_python_tag('libnode', self)
161
162 def set_collide_mask(self, mask): return self.node.set_collide_mask(mask)
163 def set_x(self, val): return self.node.set_x(val)
164 def set_y(self, val): return self.node.set_y(val)
165 def set_z(self, val): return self.node.set_z(val)
166 def set_hpr(self, val): return self.node.set_hpr(val)
167 def set_h(self, val): return self.node.set_h(val)
168 def set_p(self, val): return self.node.set_p(val)
169 def set_r(self, val): return self.node.set_r(val)
170 def set_scale(self, val): return self.node.set_scale(val)
171 def set_transparency(self, val): return self.node.set_transparency(val)
172 def set_alpha_scale(self, val): return self.node.set_alpha_scale(val)
173 def set_texture(self, texturestage, texture):
174 return self.node.set_texture(texturestage, texture)
175 def has_tag(self, name): return self.node.has_tag(name)
176 def get_tag(self, name): return self.node.get_tag(name)
177 def get_python_tag(self, name): return self.node.get_python_tag(name)
178 def remove_node(self): return self.node.remove_node()
179 def flatten_strong(self): return self.node.flatten_strong()
180 def clear_model_nodes(self): return self.node.clear_model_nodes()
181 def show(self): return self.node.show()
182 def set_depth_offset(self, val): return self.node.set_depth_offset(val)
183 def loop(self, val): return self.node.loop(val)
184 def cleanup(self): return self.node.cleanup()
185 def write_bam_file(self, fname): return self.node.write_bam_file(fname)
186
187 def attach_node(self, name):
188 return P3dNode(self.node.attach_new_node(name))
189
190 def add_shape(self, shape):
191 return self.node.node().add_shape(shape._mesh_shape)
192 #TODO: don't access a protected member
193
194 @property
195 def name(self): return self.node.get_name()
196
197 @property
198 def node(self): return self.nodepath
199
200 @property
201 def p3dnode(self): return self.node.node()
202
203 def set_pos(self, pos): return self.node.set_pos(pos._vec)
204 #TODO: don't access a protected member
205
206 def get_pos(self, other=None):
207 return self.node.get_pos(* [] if other is None else [other.node])
208
209 @property
210 def x(self): return self.node.get_x()
211
212 @property
213 def y(self): return self.node.get_y()
214
215 @property
216 def z(self): return self.node.get_z()
217
218 @property
219 def hpr(self): return self.node.get_hpr()
220
221 @property
222 def h(self): return self.node.get_h()
223
224 @property
225 def p(self): return self.node.get_p()
226
227 @property
228 def r(self): return self.node.get_r()
229
230 @property
231 def scale(self): return self.node.get_scale()
232
233 @property
234 def is_empty(self): return self.node.is_empty()
235
236 def get_relative_vector(self, node, vec):
237 return self.node.get_relative_vector(node.node, vec)
238
239 def set_material(self, mat): return self.node.set_material(mat, 1)
240
241 def set_python_tag(self, name, val):
242 return self.node.set_python_tag(name, val)
243
244 def get_distance(self, other_node):
245 return self.node.get_distance(other_node.node)
246
247 def reparent_to(self, parent): return self.node.reparent_to(parent.node)
248
249 def wrt_reparent_to(self, parent):
250 return self.node.wrt_reparent_to(parent.node)
251
252 @staticmethod
253 def __get_pandanode(nodepath):
254 if nodepath.has_python_tag('libnode'):
255 return nodepath.get_python_tag('libnode')
256 return P3dNode(nodepath)
257
258 def find_all_matches(self, name):
259 nodes = self.node.find_all_matches(name)
260 return [self.__get_pandanode(node) for node in nodes]
261
262 def find(self, name):
263 model = self.node.find(name)
264 if model: return self.__get_pandanode(model)
265
266 def optimize(self):
267 self.node.prepare_scene(base.win.get_gsg()) # crash with texture.set_format
268 self.node.premunge_scene(base.win.get_gsg())
269
270 def hide(self, mask=None):
271 return self.node.hide(*[] if mask is None else [mask])
272
273 @property
274 def tight_bounds(self): return self.node.get_tight_bounds()
275
276 @property
277 def parent(self): return self.node.get_parent()
278
279 @property
280 def children(self): return self.node.get_children()
281
282 def destroy(self): return self.node.remove_node()
283
284
285class P3dAnimNode:
286
287 def __init__(self, filepath, anim_dct):
288 self.node = Actor(filepath, anim_dct)
289
290 def loop(self, val): return self.node.loop(val)
291
292 def reparent_to(self, node): self.node.reparent_to(node)
293
294 @property
295 def name(self): return self.node.get_name()
296
297 def optimize(self):
298 self.node.prepare_scene(base.win.get_gsg())
299 self.node.premunge_scene(base.win.get_gsg())
300
301 def set_omni(self):
302 self.node.node().set_bounds(OmniBoundingVolume())
303 self.node.node().set_final(True)
304
305 def destroy(self): self.node.cleanup()
306
307
308class P3dAmbientLight:
309
310 def __init__(self, color):
311 ambient_lgt = P3DAmbientLight('ambient light')
312 ambient_lgt.set_color(color)
313 self.ambient_np = render.attach_new_node(ambient_lgt)
314 render.set_light(self.ambient_np)
315
316 def destroy(self):
317 render.clear_light(self.ambient_np)
318 self.ambient_np.remove_node()
319
320
321class P3dSpotlight:
322
323 def __init__(self, mask=None):
324 self.spot_lgt = render.attach_new_node(P3DSpotlight('spot'))
325 snode = self.spot_lgt.node()
326 snode.set_scene(render)
327 snode.set_shadow_caster(True, 1024, 1024)
328 snode.get_lens().set_fov(40)
329 snode.get_lens().set_near_far(20, 200)
330 if mask: snode.set_camera_mask(mask)
331 render.set_light(self.spot_lgt)
332
333 def set_pos(self, pos): return self.spot_lgt.set_pos(*pos)
334
335 def look_at(self, pos): return self.spot_lgt.look_at(*pos)
336
337 def set_color(self, color): return self.spot_lgt.set_color(*color)
338
339 def destroy(self):
340 render.clear_light(self.spot_lgt)
341 self.spot_lgt.remove_node()