def api_ctx_ownership(): ctx = ngl.Context() ctx2 = ngl.Context() ret = ctx.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 ret = ctx2.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 scene = _get_scene() assert ctx.set_scene(scene) == 0 assert ctx.draw(0) == 0 assert ctx2.set_scene(scene) != 0 assert ctx2.draw(0) == 0 del ctx del ctx2
def api_resize_fail(): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 ret = ctx.resize(32, 32) assert ret != 0 del ctx
def api_ctx_ownership(): viewer = ngl.Context() viewer2 = ngl.Context() assert viewer.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 assert viewer2.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 scene = _get_scene() assert viewer.set_scene(scene) == 0 assert viewer.draw(0) == 0 assert viewer2.set_scene(scene) != 0 assert viewer2.draw(0) == 0 del viewer del viewer2
def api_text_live_change(width=320, height=240): import zlib ctx = ngl.Context() capture_buffer = bytearray(width * height * 4) ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer) assert ret == 0 # An empty string forces the text node to deal with a pipeline with nul # attributes, this is what we exercise here, along with a varying up and # down number of characters text_strings = ["foo", "", "foobar", "world", "hello\nworld", "\n\n", "last"] # Exercise the diamond-form/prepare mechanism text_node = ngl.Text() assert ctx.set_scene(autogrid_simple([text_node] * 4)) == 0 ctx.draw(0) last_crc = zlib.crc32(capture_buffer) for i, s in enumerate(text_strings, 1): text_node.set_text(s) ctx.draw(i) crc = zlib.crc32(capture_buffer) assert crc != last_crc last_crc = crc
def api_media_sharing_failure(): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 m = ngl.Media("/dev/null") scene = ngl.Group(children=(ngl.Texture2D(data_src=m), ngl.Texture2D(data_src=m))) assert _ret_to_fourcc(ctx.set_scene(scene)) == "Eusg" # Usage error
def createFramebufferObject(self, size): fmt = QOpenGLFramebufferObjectFormat() fmt.setAttachment(QOpenGLFramebufferObject.CombinedDepthStencil) self._fbo = QOpenGLFramebufferObject(size, fmt) # Clear any previous OpenGL error. This workarounds an issue on macOS # where the current context contains errors (due to Qt OpenGL # implementation). These errors need to be cleared before calling the # node.gl API otherwise node.gl will in turn error out. gl_funcs = QOpenGLFunctions(QOpenGLContext.currentContext()) gl_funcs.glGetError() if not self._context: self._context = ngl.Context() config_gl = ngl.ConfigGL(external=True, external_framebuffer=self._fbo.handle()) self._context.configure( backend=ngl.BACKEND_OPENGL, width=self._fbo.width(), height=self._fbo.height(), backend_config=config_gl, ) else: self._context.gl_wrap_framebuffer(self._fbo.handle()) return self._fbo
def api_media_sharing_failure(): import struct ctx = ngl.Context() assert ctx.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 m = ngl.Media('/dev/null') scene = ngl.Group(children=(m, m)) assert _ret_to_fourcc(ctx.set_scene(scene)) == 'Eusg' # Usage error
def _init_ctx(self, rendering_backend): if self._ctx: return self._ctx = ngl.Context() self._ctx.configure(backend=misc.get_backend(rendering_backend), offscreen=1, width=16, height=16)
def api_hud(width=234, height=123): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend, hud=1) assert ret == 0 scene = _get_scene() assert ctx.set_scene(scene) == 0 for i in range(60 * 3): assert ctx.draw(i / 60.0) == 0 del ctx
def api_reconfigure_fail(): ctx = ngl.Context() assert ctx.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 scene = _get_scene() assert ctx.set_scene(scene) == 0 assert ctx.draw(0) == 0 assert ctx.configure(offscreen=0, backend=_backend) != 0 assert ctx.draw(1) != 0 del ctx
def api_shader_init_fail(width=320, height=240): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend) assert ret == 0 render = ngl.Render(ngl.Quad(), ngl.Program(vertex="<bug>", fragment="<bug>")) assert ctx.set_scene(render) != 0 assert ctx.set_scene(render) != 0 # another try to make sure the state stays consistent assert ctx.draw(0) == 0
def api_capture_buffer_lifetime(width=1024, height=1024): capture_buffer = bytearray(width * height * 4) ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer) assert ret == 0 del capture_buffer scene = _get_scene() assert ctx.set_scene(scene) == 0 assert ctx.draw(0) == 0 del ctx
def api_reconfigure(): viewer = ngl.Context() assert viewer.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 scene = _get_scene() assert viewer.set_scene(scene) == 0 assert viewer.draw(0) == 0 assert viewer.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 assert viewer.draw(1) == 0 del viewer
def api_ctx_ownership_subgraph(): for shared in (True, False): ctx = ngl.Context() ctx2 = ngl.Context() ret = ctx.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 ret = ctx2.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 quad = ngl.Quad() render1 = _get_scene(quad) if not shared: quad = ngl.Quad() render2 = _get_scene(quad) scene = ngl.Group([render1, render2]) assert ctx.set_scene(render2) == 0 assert ctx.draw(0) == 0 assert ctx2.set_scene(scene) != 0 assert ctx2.draw(0) == 0 del ctx del ctx2
def api_hud(width=234, height=123): viewer = ngl.Context() assert viewer.configure(offscreen=1, width=width, height=height, backend=_backend) == 0 render = _get_scene() scene = ngl.HUD(render) assert viewer.set_scene(scene) == 0 for i in range(60 * 3): assert viewer.draw(i / 60.) == 0 del viewer
def api_reset_scene(width=320, height=240): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend) assert ret == 0 render = _get_scene() assert ctx.set_scene(render) == 0 ctx.draw(0) assert ctx.set_scene(None) == 0 ctx.draw(1) assert ctx.set_scene(render) == 0 ctx.draw(2) assert ctx.set_scene(None) == 0 ctx.draw(3)
def api_ctx_ownership_subgraph(): for shared in (True, False): viewer = ngl.Context() viewer2 = ngl.Context() assert viewer.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 assert viewer2.configure(offscreen=1, width=16, height=16, backend=_backend) == 0 quad = ngl.Quad() render1 = _get_scene(quad) if not shared: quad = ngl.Quad() render2 = _get_scene(quad) scene = ngl.Group([render1, render2]) assert viewer.set_scene(render2) == 0 assert viewer.draw(0) == 0 assert viewer2.set_scene(scene) != 0 assert viewer2.draw(0) == 0 # XXX: drawing with no scene is allowed? del viewer del viewer2
def api_reconfigure_clearcolor(width=16, height=16): import zlib viewer = ngl.Context() capture_buffer = bytearray(width * height * 4) viewer = ngl.Context() assert viewer.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer) == 0 scene = _get_scene() assert viewer.set_scene(scene) == 0 assert viewer.draw(0) == 0 assert zlib.crc32(capture_buffer) == 0xb4bd32fa assert viewer.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer, clear_color=(0.3, 0.3, 0.3, 1.0)) == 0 assert viewer.draw(0) == 0 assert zlib.crc32(capture_buffer) == 0xfeb0bb01 del capture_buffer del viewer
def render_frames(self): # We make sure the lists of medias is explicitely empty. If we don't a # jobbed make on the tests will attempt concurrent generations of a # default ngl-media.mp4. idict = dict(medias=[]) backend = os.environ.get('BACKEND') if backend: idict['backend'] = backend ret = self._scene_func(idict=idict, **self._scene_kwargs) width, height = self._width, self._height duration = ret['duration'] scene = ret['scene'] capture_buffer = bytearray(width * height * 4) viewer = ngl.Context() assert viewer.configure( offscreen=1, width=width, height=height, backend=get_backend(backend) if backend else ngl.BACKEND_AUTO, samples=self._samples, clear_color=self._clear_color, capture_buffer=capture_buffer) == 0 timescale = duration / float(self._nb_keyframes) if self._scene_wrap: scene = self._scene_wrap(scene) if self._exercise_dot: assert scene.dot() if self._exercise_serialization: scene_str = scene.serialize() viewer.set_scene_from_string(scene_str) else: viewer.set_scene(scene) for t_id in range(self._nb_keyframes): if self._keyframes_callback: self._keyframes_callback(t_id) viewer.draw(t_id * timescale) yield (width, height, capture_buffer) if not self._exercise_serialization and self._exercise_dot: scene.dot()
def api_capture_buffer(width=16, height=16): import zlib ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend) assert ret == 0 scene = _get_scene() assert ctx.set_scene(scene) == 0 for i in range(2): capture_buffer = bytearray(width * height * 4) assert ctx.set_capture_buffer(capture_buffer) == 0 assert ctx.draw(0) == 0 assert ctx.set_capture_buffer(None) == 0 assert ctx.draw(0) == 0 assert zlib.crc32(capture_buffer) == 0xB4BD32FA del ctx
def render_frames(self): idict = {} backend = os.environ.get("BACKEND") if backend: idict["backend"] = backend ret = self._scene_func(idict=idict, **self._scene_kwargs) width, height = self._width, self._height duration = ret["duration"] scene = ret["scene"] capture_buffer = bytearray(width * height * 4) ctx = ngl.Context() ret = ctx.configure( offscreen=1, width=width, height=height, backend=get_backend(backend) if backend else ngl.BACKEND_AUTO, samples=self._samples, clear_color=self._clear_color, capture_buffer=capture_buffer, hud=self._hud, hud_export_filename=self._hud_export_filename, ) assert ret == 0 timescale = duration / float(self._nb_keyframes) if self._exercise_dot: assert scene.dot() if self._exercise_serialization: scene_str = scene.serialize() assert ctx.set_scene_from_string(scene_str) == 0 else: assert ctx.set_scene(scene) == 0 for t_id in range(self._nb_keyframes): if self._keyframes_callback: self._keyframes_callback(t_id) ctx.draw(t_id * timescale) yield (width, height, capture_buffer) if not self._exercise_serialization and self._exercise_dot: scene.dot()
def api_denied_node_live_change(width=320, height=240): ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=width, height=height, backend=_backend) assert ret == 0 scene = ngl.Translate(ngl.Group()) # Check that we can live change but not into a node assert ctx.set_scene(scene) == 0 assert scene.set_vector(1, 2, 3) == 0 assert scene.set_vector(ngl.UniformVec3(value=(3, 2, 1))) != 0 # Check that we can do the change after a reset of the context assert ctx.set_scene(None) == 0 assert scene.set_vector(ngl.UniformVec3(value=(4, 5, 6))) == 0 # Check that we can not live unplug a node from a live changeable parameter assert ctx.set_scene(scene) == 0 assert scene.set_vector(ngl.UniformVec3(value=(7, 8, 9))) != 0
def __init__(self, window, width, height, config): super().__init__() self._mutex = QtCore.QMutex() self._cond = QtCore.QWaitCondition() self._window = window self._width = width self._height = height self._scene = None self._framerate = config.get('framerate') self._duration = 0.0 self._clear_color = config.get('clear_color') self._aspect_ratio = config.get('aspect_ratio') self._samples = config.get('samples') self._backend = config.get('backend') self._events = [] self._wait_first_frame = True self._clock = Clock(self._framerate, self._duration) self._viewer = ngl.Context() self._configure_viewer()
def api_reconfigure_clearcolor(width=16, height=16): import zlib capture_buffer = bytearray(width * height * 4) ctx = ngl.Context() assert ctx.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer) == 0 scene = _get_scene() assert ctx.set_scene(scene) == 0 assert ctx.draw(0) == 0 assert zlib.crc32(capture_buffer) == 0xb4bd32fa assert ctx.configure(offscreen=1, width=width, height=height, backend=_backend, capture_buffer=capture_buffer, clear_color=(0.4, 0.4, 0.4, 1.0)) == 0 assert ctx.draw(0) == 0 assert zlib.crc32(capture_buffer) == 0x05c44869 del capture_buffer del ctx
def api_livectls(): # Build a scene and extract its live controls rng = random.Random(0) scene = ngl.Group( children=( ngl.UniformBool(live_id="b"), ngl.UniformFloat(live_id="f"), ngl.UniformIVec3(live_id="iv3"), ngl.UserSwitch( ngl.Group( children=( ngl.UniformMat4(live_id="m4"), ngl.UniformColor(live_id="clr"), ngl.UniformQuat(as_mat4=True, live_id="rot"), ) ), live_id="switch", ), ngl.Text(live_id="txt"), ) ) livectls = ngl.get_livectls(scene) assert len(livectls) == 8 # Attach scene and run a dummy draw to make sure it's valid ctx = ngl.Context() ret = ctx.configure(offscreen=1, width=16, height=16, backend=_backend) assert ret == 0 assert ctx.set_scene(scene) == 0 assert ctx.draw(0) == 0 # Apply live changes on nodes previously tracked by get_livectls() values = dict( b=True, f=rng.uniform(-1, 1), iv3=[rng.randint(-100, 100) for i in range(3)], switch=False, m4=[rng.uniform(-1, 1) for i in range(16)], clr=(0.9, 0.3, 0.8), rot=(0.1, -0.2, 0.5, -0.3), txt="test string", ) for live_id, value in values.items(): node = livectls[live_id]["node"] node_type = livectls[live_id]["node_type"] assert node_type == node.__class__.__name__ if node_type == "UserSwitch": node.set_enabled(value) elif node_type == "Text": node.set_text(value) elif hasattr(value, "__iter__"): node.set_value(*value) else: node.set_value(value) # Detach scene from context and grab all live controls again assert ctx.set_scene(None) == 0 livectls = ngl.get_livectls(scene) # Inspect nodes to check if they were properly altered by the live changes for live_id, expected_value in values.items(): value = livectls[live_id]["val"] node_type = livectls[live_id]["node_type"] if node_type == "Text": assert value == expected_value, (value, expected_value) elif hasattr(value, "__iter__"): assert all(math.isclose(v, e, rel_tol=1e-6) for v, e in zip(value, expected_value)) else: assert math.isclose(value, expected_value, rel_tol=1e-6)
def api_backend(): ctx = ngl.Context() assert ctx.configure(backend=0x1234) < 0 del ctx
def _export(self, filename, width, height, extra_enc_args=None): fd_r, fd_w = os.pipe() cfg = self._get_scene_func() if not cfg: self.failed.emit("You didn't select any scene to export.") return False fps = cfg["framerate"] duration = cfg["duration"] samples = cfg["samples"] cmd = [ # fmt: off "ffmpeg", "-r", "%d/%d" % fps, "-nostats", "-nostdin", "-f", "rawvideo", "-video_size", "%dx%d" % (width, height), "-pixel_format", "rgba", "-i", "pipe:%d" % fd_r # fmt: on ] if extra_enc_args: cmd += extra_enc_args cmd += ["-y", filename] reader = subprocess.Popen(cmd, pass_fds=(fd_r,)) os.close(fd_r) capture_buffer = bytearray(width * height * 4) # node.gl context ctx = ngl.Context() ctx.configure( platform=ngl.PLATFORM_AUTO, backend=get_backend(cfg["backend"]), offscreen=1, width=width, height=height, viewport=get_viewport(width, height, cfg["aspect_ratio"]), samples=samples, clear_color=cfg["clear_color"], capture_buffer=capture_buffer, ) ctx.set_scene_from_string(cfg["scene"]) if self._time is not None: ctx.draw(self._time) os.write(fd_w, capture_buffer) self.progressed.emit(100) else: # Draw every frame nb_frame = int(duration * fps[0] / fps[1]) for i in range(nb_frame): if self._cancelled: break time = i * fps[1] / float(fps[0]) ctx.draw(time) os.write(fd_w, capture_buffer) self.progressed.emit(i * 100 / nb_frame) self.progressed.emit(100) os.close(fd_w) reader.wait() return True
def api_backend(): ctx = ngl.Context() ret = ctx.configure(backend=0x1234) assert ret < 0 del ctx
def _export(self, filename, width, height, extra_enc_args=None): fd_r, fd_w = os.pipe() cfg = self._get_scene_func() if not cfg: self.failed.emit() return False fps = cfg['framerate'] duration = cfg['duration'] samples = cfg['samples'] cmd = [ 'ffmpeg', '-r', '%d/%d' % fps, '-nostats', '-nostdin', '-f', 'rawvideo', '-video_size', '%dx%d' % (width, height), '-pixel_format', 'rgba', '-i', 'pipe:%d' % fd_r ] if extra_enc_args: cmd += extra_enc_args cmd += ['-y', filename] reader = subprocess.Popen(cmd, pass_fds=(fd_r, )) os.close(fd_r) capture_buffer = bytearray(width * height * 4) # node.gl context ctx = ngl.Context() ctx.configure( platform=ngl.PLATFORM_AUTO, backend=get_backend(cfg['backend']), offscreen=1, width=width, height=height, viewport=get_viewport(width, height, cfg['aspect_ratio']), samples=samples, clear_color=cfg['clear_color'], capture_buffer=capture_buffer, ) ctx.set_scene_from_string(cfg['scene']) if self._time is not None: ctx.draw(self._time) os.write(fd_w, capture_buffer) self.progressed.emit(100) else: # Draw every frame nb_frame = int(duration * fps[0] / fps[1]) for i in range(nb_frame): if self._cancelled: break time = i * fps[1] / float(fps[0]) ctx.draw(time) os.write(fd_w, capture_buffer) self.progressed.emit(i * 100 / nb_frame) self.progressed.emit(100) os.close(fd_w) reader.wait() return True
def api_backend(): viewer = ngl.Context() assert viewer.configure(backend=0x1234) < 0 del viewer