def __initSoundtrack(self): if muteState(): return if self.__soundtrack: return self.__soundtrack path = None song = None for ext in ('.wav', '.mp3'): for path in currentProjectDirectory().iter(join=True): if not path.hasExt(ext): continue try: song = createSong(path) except: print ('Found a soundtrack that we could not play. pyglet or mp3 libs missing?\n%s' % e.message) return break if song: break if not song: return self.__soundtrackPath = path self.__soundtrack = song return self.__soundtrack
def __onAddImage(self): uniformName = QInputDialog.getText(self, 'Add texture', 'Uniform name', QLineEdit.Normal, 'uTextures[0]') if not uniformName[0] or not uniformName[1]: return uniformName = uniformName[0] imagePath = FileDialog.getOpenFileName(self, currentProjectDirectory(), '', 'Image files (*.png;*.bmp;*.jpg;*.jpeg;*.tiff);;Raw Gray F32 map (*.r32)') if imagePath and imagePath.exists(): relPath = imagePath.relativeTo(currentProjectDirectory()) self.__target.textures[uniformName] = relPath nameItem = QStandardItem(uniformName) nameItem.setIcon(QIcon(imagePath)) pathItem = QStandardItem(relPath) pathItem.setFlags(pathItem.flags() & ~Qt.ItemIsEditable) self.__model.appendRow([nameItem, pathItem])
def fetchAndUse(fileName): assert not '\\' in fileName key = fileName.lower().replace('//', '/') if key in TexturePool.__cache: glBindTexture(GL_TEXTURE_2D, TexturePool.__cache[key]) return TexturePool.__cache[key] parentPath = currentProjectDirectory() fullName = parentPath.join(fileName) # texture is a single channel raw32 heightmap if fileName.endswith('.r32'): tex = loadHeightfield(fullName) TexturePool.__cache[key] = tex.id() return tex.id() # read file into openGL texture img = QImage(fullName) if img.isNull(): print('Warning, could not load texture %s.' % fullName) TexturePool.__cache[key] = 0 # no texture return 0 img = QGLWidget.convertToGLFormat(img) tex = glGenTextures(1) glBindTexture(GL_TEXTURE_2D, tex) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img.width(), img.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, ctypes.c_void_p(int(img.bits()))) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) TexturePool.__cache[key] = tex return tex
def paintGL(self): newTime = time.time() deltaTime = newTime - self._prevTime # work around double repaint events collecting in the queue if deltaTime == 0.0: return self._prevTime = newTime width, height = self.calculateAspect(self.width(), self.height()) viewport = (int((self.width() - width) * 0.5), int((self.height() - height) * 0.5), width, height) if self._scene: uniforms = self._animator.evaluate(self._timer.time) textureUniforms = self._animator.additionalTextures(self._timer.time) cameraData = self._cameraData scene = self._scene modifier = currentProjectDirectory().join('animationprocessor.py') if modifier.exists(): beats = self._timer.time execfile(modifier, globals(), locals()) for name in self._textures: uniforms[name] = self._textures[name]._id self._scene.drawToScreen(self._timer.beatsToSeconds(self._timer.time), self._timer.time, uniforms, viewport, additionalTextureUniforms=textureUniforms) else: # no scene active, time cursor outside any enabled shots? global _noSignalImage if _noSignalImage is None: _noSignalImage = loadImage(FilePath(__file__).parent().join('icons', 'nosignal.png')) glDisable(GL_DEPTH_TEST) if _noSignalImage: glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) Scene.drawColorBufferToScreen(_noSignalImage, viewport) glDisable(GL_BLEND) if self.__overlays: image = self.__overlays.colorBuffer() if image: color = (self.__overlays.overlayColor().red() / 255.0, self.__overlays.overlayColor().green() / 255.0, self.__overlays.overlayColor().blue() / 255.0, self.__overlays.overlayColor().alpha() / 255.0) glDisable(GL_DEPTH_TEST) glEnable(GL_BLEND) glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) Scene.drawColorBufferToScreen(image, viewport, color) glDisable(GL_BLEND)
def __init__(self, target, parent=None): super(TextureManager, self).__init__(parent) self.setWindowTitle('TextureManager') main = vlayout() self.setLayout(main) belt = hlayout() main.addLayout(belt) addImage = QPushButton(icons.get('Add Image-48'), '') addImage.clicked.connect(self.__onAddImage) addImage.setIconSize(QSize(24, 24)) addImage.setToolTip('Add texture') addImage.setStatusTip('Add texture') belt.addWidget(addImage) delImage = QPushButton(icons.get('Remove Image-48'), '') delImage.clicked.connect(self.__onDeleteImages) delImage.setIconSize(QSize(24, 24)) delImage.setToolTip('Delete selected images') delImage.setStatusTip('Delete selected images') belt.addWidget(delImage) belt.addStretch(1) self.__model = QStandardItemModel() self.__view = QTableView() self.__view.setModel(self.__model) self.__view.horizontalHeader().hide() self.__view.setSelectionBehavior(QAbstractItemView.SelectRows) self.__view.verticalHeader().hide() main.addWidget(self.__view) main.setStretch(1, 1) self.__target = target for uniformName in target.textures: relPath = target.textures[uniformName] nameItem = QStandardItem(uniformName) nameItem.setIcon(QIcon(currentProjectDirectory().join(relPath))) pathItem = QStandardItem(relPath) pathItem.setFlags(pathItem.flags() & ~Qt.ItemIsEditable) self.__model.appendRow([nameItem, pathItem])
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))
def _deserializePasses(sceneFile): """ :type sceneFile: FilePath :rtype: list[PassData] """ assert isinstance(sceneFile, FilePath) sceneDir = sceneFile.stripExt() templatePath = templatePathFromScenePath(sceneFile) templateDir = templatePath.stripExt() xTemplate = parseXMLWithIncludes(templatePath) passes = [] frameBufferMap = {} for xPass in xTemplate: buffer = -1 if 'buffer' in xPass.attrib: buffer = xPass.attrib['buffer'] if buffer not in frameBufferMap: frameBufferMap[buffer] = len(frameBufferMap) size = None if 'size' in xPass.attrib: size = int(xPass.attrib['size']), int(xPass.attrib['size']) elif 'width' in xPass.attrib and 'height' in xPass.attrib: size = int(xPass.attrib['width']), int(xPass.attrib['height']) tile = size is not None if 'tile' in xPass.attrib: tile = xPass.attrib['tile'].lower() == 'true' factor = None if 'factor' in xPass.attrib: factor = int(xPass.attrib['factor']) realtime = int(xPass.attrib.get('static', 0)) == 0 is3d = int(xPass.attrib.get('is3d', 0)) != 0 if is3d: assert (size[0]**0.5) == size[1] size = size[0], size[1] outputs = int(xPass.attrib.get('outputs', 1)) inputs = [] i = 0 key = 'input%s' % i while key in xPass.attrib: # input is filename? parentPath = currentProjectDirectory() fullName = parentPath.join(xPass.attrib[key]) if fullName.exists(): inputs.append(FilePath(xPass.attrib[key])) else: # input is buffer if '.' in xPass.attrib[key]: frameBuffer, subTexture = xPass.attrib[key].split('.') frameBuffer, subTexture = frameBuffer, int(subTexture) else: frameBuffer, subTexture = xPass.attrib[key], 0 if frameBuffer not in frameBufferMap: frameBufferMap[frameBuffer] = len(frameBufferMap) inputs.append((frameBufferMap[frameBuffer], subTexture)) i += 1 key = 'input%s' % i vertStitches = [] fragStitches = [] uniforms = {} for xElement in xPass: path = FilePath(xElement.attrib['path']) stitches = vertStitches if path.hasExt('vert') else fragStitches if xElement.tag.lower() == 'section': stitches.append(sceneDir.join(path)) elif xElement.tag.lower() in ('shared', 'global'): stitches.append(templateDir.join(path)) else: raise ValueError('Unknown XML tag in pass: "******"' % xElement.tag) for xUniform in xElement: uniforms[xUniform.attrib['name']] = [ float(x.strip()) for x in xUniform.attrib['value'].split(',') ] passes.append( PassData(vertStitches, fragStitches, uniforms, inputs, frameBufferMap.get(buffer, -1), realtime, size, tile, factor, outputs, xPass.attrib.get('drawcommand', None), is3d, xPass.attrib.get('name', None))) return passes
def _deserializePasses(sceneFile, models): """ :type sceneFile: FilePath :rtype: list[PassData] """ assert isinstance(sceneFile, FilePath) sceneDir = sceneFile.stripExt() templatePath = templatePathFromScenePath(sceneFile) templateDir = templatePath.stripExt() modelsDir = currentModelsDirectory() xTemplate = parseXMLWithIncludes(templatePath) passes = [] frameBufferMap = {} # # Start with adding the models here as passes. Stored by their model name # for model in models.models: # inputs = [] # if model.name not in frameBufferMap: # frameBufferMap[model.name] = len(frameBufferMap) # size = 256,256 # fragStitches = [] # fragStitches.append(templateDir.join("header.glsl")) # fragStitches.append(templateDir.join("noiselib.glsl")) # fragStitches.append(templateDir.join("sdf.glsl")) # #fragStitches.append(templateDir.join("test3d.glsl")) # fragStitches.append(modelsDir.join("%s.glsl" % model.name)) # # # Add a pass for rendering a 3D texture # passes.append( # PassData([], fragStitches, {}, inputs, frameBufferMap.get(model.name, -1), False, size, False, False, 1, None, True, None)) for xPass in xTemplate: buffer = -1 if 'buffer' in xPass.attrib: buffer = xPass.attrib['buffer'] if buffer not in frameBufferMap: frameBufferMap[buffer] = len(frameBufferMap) size = None if 'size' in xPass.attrib: size = int(xPass.attrib['size']), int(xPass.attrib['size']) elif 'width' in xPass.attrib and 'height' in xPass.attrib: size = int(xPass.attrib['width']), int(xPass.attrib['height']) tile = size is not None if 'tile' in xPass.attrib: tile = xPass.attrib['tile'].lower() == 'true' factor = None if 'factor' in xPass.attrib: factor = int(xPass.attrib['factor']) realtime = int(xPass.attrib.get('static', 0)) == 0 is3d = int(xPass.attrib.get('is3d', 0)) != 0 if is3d: assert (size[0] == size[1]) size = size[0], size[0] outputs = int(xPass.attrib.get('outputs', 1)) inputs = [] inputsUniformOverrideNames = {} i = 0 key = 'input%s' % i while key in xPass.attrib: # input is filename? parentPath = currentProjectDirectory() fullName = parentPath.join(xPass.attrib[key]) if fullName.exists(): inputs.append(FilePath(xPass.attrib[key])) else: # input is buffer if '.' in xPass.attrib[key]: frameBuffer, subTexture = xPass.attrib[key].split('.') frameBuffer, subTexture = frameBuffer, int(subTexture) else: frameBuffer, subTexture = xPass.attrib[key], 0 if frameBuffer not in frameBufferMap: frameBufferMap[frameBuffer] = len(frameBufferMap) inputs.append((frameBufferMap[frameBuffer], subTexture)) i += 1 key = 'input%s' % i inputModels = False if 'inputModels' in xPass.attrib: inputModels = xPass.attrib['inputModels'].lower() == 'true' # Add all model's output buffers as inputs to this pass if inputModels: for model in models.models: bufferIndex = (frameBufferMap[model.name], 0) inputs.append(bufferIndex) inputsUniformOverrideNames[ bufferIndex] = "uModel%s" % model.name vertStitches = [] fragStitches = [] uniforms = {} for xElement in xPass: if xElement.tag.lower() == 'section': path = FilePath(xElement.attrib['path']) stitches = vertStitches if path.hasExt( 'vert') else fragStitches stitches.append(sceneDir.join(path)) elif xElement.tag.lower() in ('shared', 'global'): path = FilePath(xElement.attrib['path']) stitches = vertStitches if path.hasExt( 'vert') else fragStitches stitches.append(templateDir.join(path)) elif xElement.tag.lower() == 'models': for model in models.models: fragStitches.append(modelsDir.join("%s.glsl" % model.name)) else: raise ValueError('Unknown XML tag in pass: "******"' % xElement.tag) for xUniform in xElement: uniforms[xUniform.attrib['name']] = [ float(x.strip()) for x in xUniform.attrib['value'].split(',') ] passes.append( PassData(vertStitches, fragStitches, uniforms, inputs, frameBufferMap.get(buffer, -1), realtime, size, tile, factor, outputs, xPass.attrib.get('drawcommand', None), is3d, xPass.attrib.get('name', None), inputsUniformOverrideNames)) return passes