Example #1
0
    def render(self):
        '''Render the scene and return image as buffer.
        
        Returns
        -------
        image: HxWxD array
            where D is 4 when `mode=='RGBA'` else 3.
        '''
        with self.offscreen.bind():
            self.offscreen.draw_view3d(
                bpy.context.scene,
                bpy.context.view_layer,
                self.space,  #bpy.context.space_data
                self.region,  #bpy.context.region
                self.camera.view_matrix,
                self.camera.proj_matrix)

            bgl.glActiveTexture(bgl.GL_TEXTURE0)
            bgl.glBindTexture(bgl.GL_TEXTURE_2D, self.offscreen.color_texture)

            # np.asarray seems slow, because bgl.buffer does not support the python buffer protocol
            # bgl.glGetTexImage(bgl.GL_TEXTURE_2D, 0, bgl.GL_RGB, bgl.GL_UNSIGNED_BYTE, self.buffer)
            # https://docs.blender.org/api/blender2.8/gpu.html
            # That's why we use PyOpenGL at this point instead.
            glGetTexImage(bgl.GL_TEXTURE_2D, 0, self.mode,
                          bgl.GL_UNSIGNED_BYTE, self.buffer)

        buffer = self.buffer
        if self.origin == 'upper-left':
            buffer = np.flipud(buffer)
        if self.gamma_coeff:
            buffer = self._color_correct(buffer, self.gamma_coeff)
        return buffer
Example #2
0
 def save_FBO(self):
     bw, bh = self.size
     glEnable(GL_TEXTURE_RECTANGLE_ARB)
     glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
     glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
     glReadBuffer(GL_COLOR_ATTACHMENT0)
     glViewport(0, 0, bw, bh)
     size = bw*bh*4
     data = numpy.empty(size)
     img_data = glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data)
     img = Image.frombuffer("RGBA", (bw, bh), img_data, "raw", "BGRA", bw*4)
     img = ImageOps.flip(img)
     kwargs = {}
     if SAVE_BUFFERS=="jpeg":
         kwargs = {
                   "quality"     : 0,
                   "optimize"    : False,
                   }
     t = time.time()
     tstr = time.strftime("%H-%M-%S", time.localtime(t))
     filename = "./W%i-FBO-%s.%03i.%s" % (self.wid, tstr, (t*1000)%1000, SAVE_BUFFERS)
     log("do_present_fbo: saving %4ix%-4i pixels, %7i bytes to %s", bw, bh, size, filename)
     img.save(filename, SAVE_BUFFERS, **kwargs)
     glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)
     glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0)
     glDisable(GL_TEXTURE_RECTANGLE_ARB)
Example #3
0
    def __record(self):
        diag = QDialog()
        fId = gSettings.value('RecordFPS', 2)
        rId = gSettings.value('RecordResolution', 3)
        layout = QGridLayout()
        diag.setLayout(layout)
        layout.addWidget(QLabel('FPS: '), 0, 0)
        fps = QComboBox()
        fps.addItems(['12', '24', '30', '48', '60', '120'])
        fps.setCurrentIndex(fId)
        layout.addWidget(fps, 0, 1)
        layout.addWidget(QLabel('Vertical resolution: '), 1, 0)
        resolution = QComboBox()
        resolution.addItems(['144', '288', '360', '720', '1080', '2160'])
        resolution.setCurrentIndex(rId)
        layout.addWidget(resolution, 1, 1)
        ok = QPushButton('Ok')
        ok.clicked.connect(diag.accept)
        cancel = QPushButton('Cancel')
        cancel.clicked.connect(diag.reject)
        layout.addWidget(ok, 2, 0)
        layout.addWidget(cancel, 2, 1)
        diag.exec_()
        if diag.result() != QDialog.Accepted:
            return
        gSettings.setValue('RecordFPS', fps.currentIndex())
        gSettings.setValue('RecordResolution', resolution.currentIndex())

        FPS = int(fps.currentText())
        HEIGHT = int(resolution.currentText())
        WIDTH = (HEIGHT * 16) / 9
        FMT = 'jpg'

        data = (ctypes.c_ubyte * (WIDTH * HEIGHT * 3))()  # alloc buffer once
        flooredStart = self._timer.secondsToBeats(int(self._timer.beatsToSeconds(self._timer.start) * FPS) / float(FPS))
        duration = self._timer.beatsToSeconds(self._timer.end - flooredStart)
        if not fileutil.exists('capture'):
            os.makedirs('capture')
        progress = QProgressDialog(self)
        progress.setMaximum(int(duration * FPS))
        prevFrame = 0
        for frame in xrange(int(duration * FPS)):
            deltaTime = (frame - prevFrame) / float(FPS)
            prevFrame = frame
            progress.setValue(frame)
            QApplication.processEvents()
            if progress.wasCanceled():
                break
            beats = flooredStart + self._timer.secondsToBeats(frame / float(FPS))

            shot = self.__shotsManager.shotAtTime(beats)
            if shot is None:
                continue
            sceneFile = os.path.join(ScenesPath(), shot.sceneName + SCENE_EXT)
            scene = Scene.getScene(sceneFile)
            scene.setSize(WIDTH, HEIGHT)

            uniforms = self.__shotsManager.evaluate(beats)
            textureUniforms = self.__shotsManager.additionalTextures(beats)
            self.__sceneView._cameraInput.setData(*(uniforms['uOrigin'] + uniforms['uAngles']))  # feed animation into camera so animationprocessor can read it again
            cameraData = self.__sceneView._cameraInput.data()

            modifier = os.path.join(ProjectDir(), 'animationprocessor.py')
            if fileutil.exists(modifier):
                execfile(modifier, globals(), locals())

            for name in self.__sceneView._textures:
                uniforms[name] = self.__sceneView._textures[name]._id

            scene.drawToScreen(self._timer.beatsToSeconds(beats), beats, uniforms, (0, 0, WIDTH, HEIGHT), textureUniforms)
            scene.colorBuffers[-1][0].use()

            from OpenGL.GL import glGetTexImage, GL_TEXTURE_2D, GL_RGB, GL_UNSIGNED_BYTE
            glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data)

            QImage(data, WIDTH, HEIGHT, QImage.Format_RGB888).mirrored(False, True).save('capture/dump_%s_%05d.%s' % (FPS, int(self._timer.beatsToSeconds(self._timer.start) * FPS) + frame, FMT))
        progress.close()

        if not fileutil.exists('convertcapture'):
            os.makedirs('convertcapture')
        with fileutil.edit('convertcapture/convert.bat') as fh:
            start = ''
            start2 = ''
            if int(self._timer.start * FPS) > 0:
                start = '-start_number {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS))
                start2 = '-vframes {} '.format(int(self._timer.beatsToSeconds(self._timer.end - self._timer.start) * FPS))
            fh.write('cd "../capture"\n"../convertcapture/ffmpeg.exe" -framerate {} {}-i dump_{}_%%05d.{} {}-c:v libx264 -r {} -pix_fmt yuv420p "../convertcapture/output.mp4"'.format(FPS, start, FPS, FMT, start2, FPS))

        with fileutil.edit('convertcapture/convertGif.bat') as fh:
            start = ''
            start2 = ''
            if int(self._timer.start * FPS) > 0:
                start = '-start_number {} '.format(int(self._timer.beatsToSeconds(self._timer.start) * FPS))
                start2 = '-vframes {} '.format(int(self._timer.beatsToSeconds(self._timer.end - self._timer.start) * FPS))
            fh.write('cd "../capture"\n"../convertcapture/ffmpeg.exe" -framerate {} {}-i dump_{}_%%05d.{} {}-r {} "../convertcapture/output.gif"'.format(FPS, start, FPS, FMT, start2, FPS))

        sound = self.timeSlider.soundtrackPath()
        if not sound:
            return
        with fileutil.edit('convertcapture/merge.bat') as fh:
            startSeconds = self._timer.beatsToSeconds(self._timer.start)
            fh.write('ffmpeg -i output.mp4 -itsoffset {} -i "{}" -vcodec copy -shortest merged.mp4'.format(-startSeconds, sound))
    def do_present_fbo(self):
        bw, bh = self.size
        ww, wh = self.render_size

        self.gl_marker("Presenting FBO on screen")
        # Change state to target screen instead of our FBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0)
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

        left, top, right, bottom = self.offsets

        #viewport for clearing the whole window:
        glViewport(0, 0, left+ww+right, top+wh+bottom)
        if self._alpha_enabled:
            # transparent background:
            glClearColor(0.0, 0.0, 0.0, 0.0)
        else:
            # black, no alpha:
            glClearColor(0.0, 0.0, 0.0, 1.0)
        if left or top or right or bottom:
            try:
                glClear(GL_COLOR_BUFFER_BIT)
            except:
                log("ignoring glClear(GL_COLOR_BUFFER_BIT) error, buggy driver?", exc_info=True)

        #viewport for painting to window:
        glViewport(left, top, ww, wh)

        # Draw FBO texture on screen
        self.set_rgb_paint_state()

        rect_count = len(self.pending_fbo_paint)
        if self.glconfig.is_double_buffered() or bw!=ww or bh!=wh:
            #refresh the whole window:
            rectangles = ((0, 0, bw, bh), )
        else:
            #paint just the rectangles we have accumulated:
            rectangles = self.pending_fbo_paint
        self.pending_fbo_paint = []
        log("do_present_fbo: painting %s", rectangles)

        glEnable(GL_TEXTURE_RECTANGLE_ARB)
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
        if self._alpha_enabled:
            # support alpha channel if present:
            glEnablei(GL_BLEND, self.textures[TEX_FBO])
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

        if SAVE_BUFFERS:
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
            glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glReadBuffer(GL_COLOR_ATTACHMENT0)
            glViewport(0, 0, bw, bh)
            from OpenGL.GL import glGetTexImage
            size = bw*bh*4
            import numpy
            data = numpy.empty(size)
            img_data = glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data)
            from PIL import Image, ImageOps
            img = Image.frombuffer("RGBA", (bw, bh), img_data, "raw", "BGRA", bw*4)
            img = ImageOps.flip(img)
            kwargs = {}
            if SAVE_BUFFERS=="jpeg":
                kwargs = {
                          "quality"     : 0,
                          "optimize"    : False,
                          }
            t = time.time()
            tstr = time.strftime("%H-%M-%S", time.localtime(t))
            filename = "./W%i-FBO-%s.%03i.%s" % (self.wid, tstr, (t*1000)%1000, SAVE_BUFFERS)
            log("do_present_fbo: saving %4ix%-4i pixels, %7i bytes to %s", bw, bh, size, filename)
            img.save(filename, SAVE_BUFFERS, **kwargs)
            glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)

        if ww!=bw or wh!=bh:
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

        glBegin(GL_QUADS)
        for x,y,w,h in rectangles:
            #note how we invert coordinates..
            tx1, ty1, tx2, ty2 = x, bh-y,  x+w, bh-y-h
            vx1, vy1, vx2, vy2 = x, y,     x+w, y+h
            glTexCoord2i(tx1, ty1)
            glVertex2i(vx1, vy1)        #top-left of window viewport
            glTexCoord2i(tx1, ty2)
            glVertex2i(vx1, vy2)        #bottom-left of window viewport
            glTexCoord2i(tx2, ty2)
            glVertex2i(vx2, vy2)        #bottom-right of window viewport
            glTexCoord2i(tx2, ty1)
            glVertex2i(vx2, vy1)        #top-right of window viewport
        glEnd()
        glDisable(GL_TEXTURE_RECTANGLE_ARB)

        if self.paint_spinner:
            #add spinner:
            dim = min(bw/3.0, bh/3.0)
            t = time.time()
            count = int(t*4.0)
            bx = bw//2
            by = bh//2
            for i in range(8):      #8 lines
                glBegin(GL_POLYGON)
                c = cv.trs[count%8][i]
                glColor4f(c, c, c, 1)
                mi1 = math.pi*i/4-math.pi/16
                mi2 = math.pi*i/4+math.pi/16
                glVertex2i(int(bx+math.sin(mi1)*10), int(by+math.cos(mi1)*10))
                glVertex2i(int(bx+math.sin(mi1)*dim), int(by+math.cos(mi1)*dim))
                glVertex2i(int(bx+math.sin(mi2)*dim), int(by+math.cos(mi2)*dim))
                glVertex2i(int(bx+math.sin(mi2)*10), int(by+math.cos(mi2)*10))
                glEnd()

        #if desired, paint window border
        if self.border and self.border.shown:
            #double size since half the line will be off-screen
            glLineWidth(self.border.size*2)
            glBegin(GL_LINE_LOOP)
            glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha)
            for px,py in ((0, 0), (bw, 0), (bw, bh), (0, bh)):
                glVertex2i(px, py)
            glEnd()

        if self.pointer_overlay:
            x, y, _, _, size, start_time = self.pointer_overlay
            elapsed = time.time()-start_time
            if elapsed<6:
                alpha = max(0, (5.0-elapsed)/5.0)
                glLineWidth(1)
                glBegin(GL_LINES)
                glColor4f(0, 0, 0, alpha)
                glVertex2i(x-size, y)
                glVertex2i(x+size, y)
                glVertex2i(x, y-size)
                glVertex2i(x, y+size)
                glEnd()
            else:
                self.pointer_overlay = None

        # Show the backbuffer on screen
        self.gl_show(rect_count)
        self.gl_frame_terminator()

        #restore pbo viewport
        glViewport(0, 0, bw, bh)
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

        self.unset_rgb_paint_state()
        log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo)
        glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)
        log("%s.do_present_fbo() done", self)
Example #5
0
    def setupTransforms(self, transforms):
        # note: this is only called from test_drawing.py (as of before 090302)
        """
        Fill a block of transforms.

        Depending on the setting of TEXTURE_XFORMS and UNIFORM_XFORMS, the
        transforms are either in texture memory, or in a uniform array of mat4s
        ("constant memory"), or unsupported (error if we need any here).

        @param transforms: A list of transform matrices, where each transform is
            a flattened list (or Numpy array) of 16 numbers.
        """
        self.n_transforms = nTransforms = len(transforms)

        if not self.supports_transforms():
            assert not nTransforms, "%r doesn't support transforms" % self
            return
        
        self.setActive(True)                # Must activate before setting uniforms.
        
        assert self._has_uniform("n_transforms") # redundant with following
        glUniform1iARB(self._uniform("n_transforms"), self.n_transforms)

        # The shader bypasses transform logic if n_transforms is 0.
        # (Then location coordinates are in global modeling coordinates.)
        if nTransforms > 0:
            if UNIFORM_XFORMS:
                # Load into constant memory.  The GL_EXT_bindable_uniform
                # extension supports sharing this array of mat4s through a VBO.
                # XXX Need to bank-switch this data if more than N_CONST_XFORMS.
                C_transforms = numpy.array(transforms, dtype = numpy.float32)
                glUniformMatrix4fvARB(self._uniform("transforms"),
                                      # Don't over-run the array size.
                                      min(len(transforms), N_CONST_XFORMS),
                                      GL_TRUE, # Transpose.
                                      C_transforms)
            elif TEXTURE_XFORMS:
                # Generate a texture ID and bind the texture unit to it.
                self.transform_memory = glGenTextures(1)
                glBindTexture(GL_TEXTURE_2D, self.transform_memory)
                ## These seem to have no effect with a vertex shader.
                ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                # XXX Needed? glEnable(GL_TEXTURE_2D)

                # Load the transform data into the texture.
                #
                # Problem: SIGSEGV kills Python in gleTextureImagePut under
                # glTexImage2D with more than 250 transforms (16,000 bytes.)
                # Maybe there's a 16-bit signed size calculation underthere, that's
                # overflowing the sign bit... Work around by sending transforms to
                # the texture unit in batches with glTexSubImage2D.)
                glTexImage2D(GL_TEXTURE_2D, 0, # Level zero - base image, no mipmap.
                             GL_RGBA32F_ARB,   # Internal format is floating point.
                             # Column major storage: width = N, height = 4 * RGBA.
                             nTransforms, 4 * 4, 0, # No border.
                             # Data format and type, null pointer to allocate space.
                             GL_RGBA, GL_FLOAT, None)
                # XXX Split this off into a setTransforms method.
                batchSize = 250
                nBatches = (nTransforms + batchSize-1) / batchSize
                for i in range(nBatches):
                    xStart = batchSize * i
                    xEnd = min(nTransforms, xStart + batchSize)
                    xSize = xEnd - xStart
                    glTexSubImage2D(GL_TEXTURE_2D, 0,
                                    # Subimage x and y offsets and sizes.
                                    xStart, 0, xSize, 4 * 4,
                                    # List of matrices is flattened into a sequence.
                                    GL_RGBA, GL_FLOAT, transforms[xStart:xEnd])
                    continue
                # Read back to check proper loading.
                if CHECK_TEXTURE_XFORM_LOADING:
                    mats = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT)
                    nMats = len(mats)
                    print "setupTransforms\n[[",
                    for i in range(nMats):
                        nElts = len(mats[i])
                        perLine = 8
                        nLines = (nElts + perLine-1) / perLine
                        for line in range(nLines):
                            jStart = perLine * line
                            jEnd = min(nElts, jStart + perLine)
                            for j in range(jStart, jEnd):
                                print "%.2f" % mats[i][j],
                                continue
                            if line < nLines-1:
                                print "\n  ",
                                pass
                        if i < nMats-1:
                            print "]\n [",
                            pass
                        continue
                    print "]]"
                pass
            else:
                # should never happen if SUPPORTS_XFORMS is defined correctly
                assert 0, "can't setupTransforms unless UNIFORM_XFORMS or TEXTURE_XFORMS is set"
            pass
        self.setActive(False)                # Deactivate again.
        return
Example #6
0
    def __record(self):
        diag = QDialog()
        fId = gSettings.value('RecordFPS', 2)
        rId = gSettings.value('RecordResolution', 3)
        layout = QGridLayout()
        diag.setLayout(layout)
        layout.addWidget(QLabel('FPS: '), 0, 0)
        fps = QComboBox()
        fps.addItems(['12', '24', '30', '48', '60', '120'])
        fps.setCurrentIndex(fId)
        layout.addWidget(fps, 0, 1)
        layout.addWidget(QLabel('Vertical resolution: '), 1, 0)
        resolution = QComboBox()
        resolution.addItems(['144', '288', '360', '720', '1080', '2160'])
        resolution.setCurrentIndex(rId)
        layout.addWidget(resolution, 1, 1)
        ok = QPushButton('Ok')
        ok.clicked.connect(diag.accept)
        cancel = QPushButton('Cancel')
        cancel.clicked.connect(diag.reject)
        layout.addWidget(ok, 2, 0)
        layout.addWidget(cancel, 2, 1)
        diag.exec_()
        if diag.result() != QDialog.Accepted:
            return
        gSettings.setValue('RecordFPS', fps.currentIndex())
        gSettings.setValue('RecordResolution', resolution.currentIndex())

        FPS = int(fps.currentText())
        HEIGHT = int(resolution.currentText())
        WIDTH = (HEIGHT * 16) / 9
        FMT = 'jpg'

        data = (ctypes.c_ubyte * (WIDTH * HEIGHT * 3))()  # alloc buffer once
        flooredStart = self._timer.secondsToBeats(
            int(self._timer.beatsToSeconds(self._timer.start) * FPS) /
            float(FPS))
        duration = self._timer.beatsToSeconds(self._timer.end - flooredStart)

        captureDir = currentProjectDirectory().join('capture')
        captureDir.ensureExists(isFolder=True)

        progress = QProgressDialog(self)
        progress.setMaximum(int(duration * FPS))
        prevFrame = 0
        for frame in range(int(duration * FPS)):
            deltaTime = (frame - prevFrame) / float(FPS)
            prevFrame = frame
            progress.setValue(frame)
            QApplication.processEvents()
            if progress.wasCanceled():
                break
            beats = flooredStart + self._timer.secondsToBeats(
                frame / float(FPS))

            shot = self.__shotsManager.shotAtTime(beats)
            if shot is None:
                continue
            sceneFile = currentScenesDirectory().join(
                shot.sceneName).ensureExt(SCENE_EXT)
            scene = Scene.getScene(sceneFile)
            scene.setSize(WIDTH, HEIGHT)

            uniforms = self.__shotsManager.evaluate(beats)
            textureUniforms = self.__shotsManager.additionalTextures(beats)
            self.__sceneView._cameraInput.setData(
                *(uniforms['uOrigin'] + uniforms['uAngles'])
            )  # feed animation into camera so animationprocessor can read it again
            cameraData = self.__sceneView._cameraInput.data()

            modifier = currentProjectDirectory().join('animationprocessor.py')
            if modifier.exists():
                execfile(str(modifier), globals(), locals())

            for name in self.__sceneView._textures:
                uniforms[name] = self.__sceneView._textures[name]._id

            scene.drawToScreen(self._timer.beatsToSeconds(beats), beats,
                               uniforms, (0, 0, WIDTH, HEIGHT),
                               textureUniforms)
            scene.colorBuffers[-1][0].use()

            from OpenGL.GL import glGetTexImage, GL_TEXTURE_2D, GL_RGB, GL_UNSIGNED_BYTE
            glGetTexImage(GL_TEXTURE_2D, 0, GL_RGB, GL_UNSIGNED_BYTE, data)

            captureDir = currentProjectDirectory().join('capture')
            QImage(data, WIDTH, HEIGHT, QImage.Format_RGB888).mirrored(
                False, True
            ).save(
                captureDir.join(
                    'dump_%s_%05d.%s' %
                    (FPS,
                     int(self._timer.beatsToSeconds(self._timer.start) * FPS) +
                     frame, FMT)))
        progress.close()

        convertCaptureDir = currentProjectDirectory().join('convertcapture')
        convertCaptureDir.ensureExists(isFolder=True)

        with convertCaptureDir.join('convert.bat').edit() as fh:
            start = ''
            start2 = ''
            if int(self._timer.start * FPS) > 0:
                start = '-start_number {} '.format(
                    int(self._timer.beatsToSeconds(self._timer.start) * FPS))
                start2 = '-vframes {} '.format(
                    int(
                        self._timer.beatsToSeconds(self._timer.end -
                                                   self._timer.start) * FPS))

            fh.write(
                'cd "../capture"\n"{}" -framerate {} {}-i dump_{}_%%05d.{} {}-c:v libx264 -r {} -pix_fmt yuv420p "../convertcapture/output.mp4"'
                .format(FFMPEG_PATH, FPS, start, FPS, FMT, start2, FPS))
        with convertCaptureDir.join('convertGif.bat').edit() as fh:
            start = ''
            start2 = ''
            iln = ''
            if int(self._timer.start * FPS) > 0:
                start = '-start_number {} '.format(
                    int(self._timer.beatsToSeconds(self._timer.start) * FPS))
                start2 = '-vframes {} '.format(
                    int(
                        self._timer.beatsToSeconds(self._timer.end -
                                                   self._timer.start) * FPS))
                iln = '-t {:03f} '.format(
                    self._timer.beatsToSeconds(self._timer.end -
                                               self._timer.start))
            fh.write(
                'REM File format is actually %5d but in a .bat file we need to escape % or something, so you can\'t copy paste this into a cmd prompt without fixing up the %%05d to be %5d.\n'
            )
            fh.write(
                'cd "../capture"\n"{}" -framerate {} {}{}-i dump_{}_%%05d.{} -vf "fps={},scale={}:-1:flags=lanczos,palettegen" palette.png\n'
                .format(FFMPEG_PATH, FPS, start, iln, FPS, FMT, FPS, HEIGHT))
            fh.write(
                '"{}" -framerate {} {}-i dump_{}_%%05d.{} -i "palette.png" -filter_complex "fps=12,scale=360:-1:flags=lanczos[x];[x][1:v]paletteuse" {}-r {} "../convertcapture/output.gif"'
                .format(FFMPEG_PATH, FPS, start, FPS, FMT, start2, FPS))

        sound = self.timeSlider.soundtrackPath()
        if not sound:
            return

        with convertCaptureDir.join('merge.bat').edit() as fh:
            startSeconds = self._timer.beatsToSeconds(self._timer.start)
            fh.write(
                '{} -i output.mp4 -itsoffset {} -i "{}" -vcodec copy -shortest merged.mp4'
                .format(FFMPEG_PATH, -startSeconds, sound))
Example #7
0
    def setupTransforms(self, transforms):
        # note: this is only called from test_drawing.py (as of before 090302)
        """
        Fill a block of transforms.

        Depending on the setting of TEXTURE_XFORMS and UNIFORM_XFORMS, the
        transforms are either in texture memory, or in a uniform array of mat4s
        ("constant memory"), or unsupported (error if we need any here).

        @param transforms: A list of transform matrices, where each transform is
            a flattened list (or Numpy array) of 16 numbers.
        """
        self.n_transforms = nTransforms = len(transforms)

        if not self.supports_transforms():
            assert not nTransforms, "%r doesn't support transforms" % self
            return

        self.setActive(True)                # Must activate before setting uniforms.

        assert self._has_uniform("n_transforms") # redundant with following
        glUniform1iARB(self._uniform("n_transforms"), self.n_transforms)

        # The shader bypasses transform logic if n_transforms is 0.
        # (Then location coordinates are in global modeling coordinates.)
        if nTransforms > 0:
            if UNIFORM_XFORMS:
                # Load into constant memory.  The GL_EXT_bindable_uniform
                # extension supports sharing this array of mat4s through a VBO.
                # XXX Need to bank-switch this data if more than N_CONST_XFORMS.
                C_transforms = numpy.array(transforms, dtype = numpy.float32)
                glUniformMatrix4fvARB(self._uniform("transforms"),
                                      # Don't over-run the array size.
                                      min(len(transforms), N_CONST_XFORMS),
                                      GL_TRUE, # Transpose.
                                      C_transforms)
            elif TEXTURE_XFORMS:
                # Generate a texture ID and bind the texture unit to it.
                self.transform_memory = glGenTextures(1)
                glBindTexture(GL_TEXTURE_2D, self.transform_memory)
                ## These seem to have no effect with a vertex shader.
                ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
                ## glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
                # XXX Needed? glEnable(GL_TEXTURE_2D)

                # Load the transform data into the texture.
                #
                # Problem: SIGSEGV kills Python in gleTextureImagePut under
                # glTexImage2D with more than 250 transforms (16,000 bytes.)
                # Maybe there's a 16-bit signed size calculation underthere, that's
                # overflowing the sign bit... Work around by sending transforms to
                # the texture unit in batches with glTexSubImage2D.)
                glTexImage2D(GL_TEXTURE_2D, 0, # Level zero - base image, no mipmap.
                             GL_RGBA32F_ARB,   # Internal format is floating point.
                             # Column major storage: width = N, height = 4 * RGBA.
                             nTransforms, 4 * 4, 0, # No border.
                             # Data format and type, null pointer to allocate space.
                             GL_RGBA, GL_FLOAT, None)
                # XXX Split this off into a setTransforms method.
                batchSize = 250
                nBatches = (nTransforms + batchSize-1) / batchSize
                for i in range(nBatches):
                    xStart = batchSize * i
                    xEnd = min(nTransforms, xStart + batchSize)
                    xSize = xEnd - xStart
                    glTexSubImage2D(GL_TEXTURE_2D, 0,
                                    # Subimage x and y offsets and sizes.
                                    xStart, 0, xSize, 4 * 4,
                                    # List of matrices is flattened into a sequence.
                                    GL_RGBA, GL_FLOAT, transforms[xStart:xEnd])
                    continue
                # Read back to check proper loading.
                if CHECK_TEXTURE_XFORM_LOADING:
                    mats = glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT)
                    nMats = len(mats)
                    print "setupTransforms\n[[",
                    for i in range(nMats):
                        nElts = len(mats[i])
                        perLine = 8
                        nLines = (nElts + perLine-1) / perLine
                        for line in range(nLines):
                            jStart = perLine * line
                            jEnd = min(nElts, jStart + perLine)
                            for j in range(jStart, jEnd):
                                print "%.2f" % mats[i][j],
                                continue
                            if line < nLines-1:
                                print "\n  ",
                                pass
                        if i < nMats-1:
                            print "]\n [",
                            pass
                        continue
                    print "]]"
                pass
            else:
                # should never happen if SUPPORTS_XFORMS is defined correctly
                assert 0, "can't setupTransforms unless UNIFORM_XFORMS or TEXTURE_XFORMS is set"
            pass
        self.setActive(False)                # Deactivate again.
        return
    def do_present_fbo(self):
        bw, bh = self.size
        ww, wh = self.render_size

        self.gl_marker("Presenting FBO on screen")
        # Change state to target screen instead of our FBO
        glBindFramebuffer(GL_FRAMEBUFFER, 0)
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0)

        if self._alpha_enabled:
            # transparent background:
            glClearColor(0.0, 0.0, 0.0, 0.0)
        else:
            # plain white no alpha:
            glClearColor(1.0, 1.0, 1.0, 1.0)

        # Draw FBO texture on screen
        self.set_rgb_paint_state()

        rect_count = len(self.pending_fbo_paint)
        if self.glconfig.is_double_buffered() or bw!=ww or bh!=wh:
            #refresh the whole window:
            rectangles = ((0, 0, bw, bh), )
        else:
            #paint just the rectangles we have accumulated:
            rectangles = self.pending_fbo_paint
        self.pending_fbo_paint = []
        log("do_present_fbo: painting %s", rectangles)

        glEnable(GL_TEXTURE_RECTANGLE_ARB)
        glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
        if self._alpha_enabled:
            # support alpha channel if present:
            glEnablei(GL_BLEND, self.textures[TEX_FBO])
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)

        if SAVE_BUFFERS:
            glBindFramebuffer(GL_READ_FRAMEBUFFER, self.offscreen_fbo)
            glBindTexture(GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO])
            glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_RECTANGLE_ARB, self.textures[TEX_FBO], 0)
            glReadBuffer(GL_COLOR_ATTACHMENT0)
            glViewport(0, 0, bw, bh)
            from OpenGL.GL import glGetTexImage
            size = bw*bh*4
            import numpy
            data = numpy.empty(size)
            img_data = glGetTexImage(GL_TEXTURE_RECTANGLE_ARB, 0, GL_BGRA, GL_UNSIGNED_BYTE, data)
            from PIL import Image, ImageOps
            img = Image.frombuffer("RGBA", (bw, bh), img_data, "raw", "BGRA", bw*4)
            img = ImageOps.flip(img)
            kwargs = {}
            if SAVE_BUFFERS=="jpeg":
                kwargs = {
                          "quality"     : 0,
                          "optimize"    : False,
                          }
            t = time.time()
            tstr = time.strftime("%H-%M-%S", time.localtime(t))
            filename = "./W%i-FBO-%s.%03i.%s" % (self.wid, tstr, (t*1000)%1000, SAVE_BUFFERS)
            log("do_present_fbo: saving %4ix%-4i pixels, %7i bytes to %s", bw, bh, size, filename)
            img.save(filename, SAVE_BUFFERS, **kwargs)
            glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)

        #viewport for painting to window:
        glViewport(0, 0, ww, wh)
        if ww!=bw or wh!=bh:
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
            glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

        glBegin(GL_QUADS)
        for x,y,w,h in rectangles:
            #note how we invert coordinates..
            tx1, ty1, tx2, ty2 = x, bh-y,  x+w, bh-y-h
            vx1, vy1, vx2, vy2 = x, y,     x+w, y+h
            glTexCoord2i(tx1, ty1)
            glVertex2i(vx1, vy1)        #top-left of window viewport
            glTexCoord2i(tx1, ty2)
            glVertex2i(vx1, vy2)        #bottom-left of window viewport
            glTexCoord2i(tx2, ty2)
            glVertex2i(vx2, vy2)        #bottom-right of window viewport
            glTexCoord2i(tx2, ty1)
            glVertex2i(vx2, vy1)        #top-right of window viewport
        glEnd()
        glDisable(GL_TEXTURE_RECTANGLE_ARB)

        if self.paint_spinner:
            #add spinner:
            dim = min(bw/3.0, bh/3.0)
            t = time.time()
            count = int(t*4.0)
            bx = bw//2
            by = bh//2
            for i in range(8):      #8 lines
                glBegin(GL_POLYGON)
                c = cv.trs[count%8][i]
                glColor4f(c, c, c, 1)
                mi1 = math.pi*i/4-math.pi/16
                mi2 = math.pi*i/4+math.pi/16
                glVertex2i(int(bx+math.sin(mi1)*10), int(by+math.cos(mi1)*10))
                glVertex2i(int(bx+math.sin(mi1)*dim), int(by+math.cos(mi1)*dim))
                glVertex2i(int(bx+math.sin(mi2)*dim), int(by+math.cos(mi2)*dim))
                glVertex2i(int(bx+math.sin(mi2)*10), int(by+math.cos(mi2)*10))
                glEnd()

        #if desired, paint window border
        if self.border and self.border.shown:
            #double size since half the line will be off-screen
            glLineWidth(self.border.size*2)
            glBegin(GL_LINE_LOOP)
            glColor4f(self.border.red, self.border.green, self.border.blue, self.border.alpha)
            for px,py in ((0, 0), (bw, 0), (bw, bh), (0, bh)):
                glVertex2i(px, py)
            glEnd()

        if self.pointer_overlay:
            x, y, _, _, size, start_time = self.pointer_overlay
            elapsed = time.time()-start_time
            if elapsed<6:
                alpha = max(0, (5.0-elapsed)/5.0)
                glLineWidth(1)
                glBegin(GL_LINES)
                glColor4f(0, 0, 0, alpha)
                glVertex2i(x-size, y)
                glVertex2i(x+size, y)
                glVertex2i(x, y-size)
                glVertex2i(x, y+size)
                glEnd()
            else:
                self.pointer_overlay = None

        # Show the backbuffer on screen
        self.gl_show(rect_count)
        self.gl_frame_terminator()

        #restore pbo viewport
        glViewport(0, 0, bw, bh)
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST)

        self.unset_rgb_paint_state()
        log("%s(%s, %s)", glBindFramebuffer, GL_FRAMEBUFFER, self.offscreen_fbo)
        glBindFramebuffer(GL_FRAMEBUFFER, self.offscreen_fbo)
        log("%s.do_present_fbo() done", self)