def _saveSceneShots(sceneName, shots): sceneFile = os.path.join(ScenesPath(), sceneName + SCENE_EXT) xScene = ParseXMLWithIncludes(sceneFile) # save user camera position per scene userFile = ProjectFile() + '.user' if fileutil.exists(userFile): xUser = ParseXMLWithIncludes(userFile) else: xUser = cElementTree.Element('user') if sceneFile in Scene.cache: cameraData = Scene.cache[sceneFile].cameraData() if cameraData: for xSub in xUser: if xSub.tag == 'scene' and xSub.attrib['name'] == sceneName: xSub.attrib['camera'] = ','.join([str(x) for x in cameraData]) break else: cElementTree.SubElement(xUser, 'scene', {'name': sceneName, 'camera': ','.join([str(x) for x in cameraData])}) with fileutil.edit(userFile) as fh: fh.write(toPrettyXml(xUser)) # remove old shots r = [] for xShot in xScene: r.append(xShot) for s in r: xScene.remove(s) targets = [] for shot in shots: if shot.sceneName == sceneName: targets.append(shot) for shot in targets: xShot = cElementTree.SubElement(xScene, 'Shot', {'name': shot.name, 'scene': sceneName, 'start': str(shot.start), 'end': str(shot.end), 'enabled': str(shot.enabled), 'speed': str(shot.speed), 'preroll': str(shot.preroll)}) for curveName in shot.curves: xChannel = cElementTree.SubElement(xShot, 'Channel', {'name': curveName, 'mode': 'hermite'}) data = [] for key in shot.curves[curveName]: data.append(str(key.inTangent.x)) data.append(str(key.inTangent.y)) data.append(str(key.point().x)) data.append(str(key.point().y)) data.append(str(key.outTangent.x)) data.append(str(key.outTangent.y)) data.append(str(int(key.tangentBroken))) data.append(str(key.tangentMode)) xChannel.text = ','.join(data) for texName in shot.textures: cElementTree.SubElement(xShot, 'Texture', {'name': texName, 'path': shot.textures[texName]}) with fileutil.edit(sceneFile) as fh: fh.write(toPrettyXml(xScene))
def readCameraData(self): if self.__cameraData is None: userFile = ProjectFile() + '.user' xCamera = None if fileutil.exists(userFile): xRoot = ParseXMLWithIncludes(userFile) for xSub in xRoot: if xSub.attrib['name'] == os.path.splitext(os.path.basename(self.__filePath))[0]: xCamera = xSub break if xCamera is None: # legacy support xCamera = ParseXMLWithIncludes(self.__filePath) self.__cameraData = CameraTransform(*[float(x) for x in xCamera.attrib['camera'].split(',')]) return self.__cameraData
def _deserializeSceneShots(sceneName): sceneFile = os.path.join(ScenesPath(), sceneName + SCENE_EXT) xScene = ParseXMLWithIncludes(sceneFile) for xShot in xScene: name = xShot.attrib['name'] start = float(xShot.attrib['start']) end = float(xShot.attrib['end']) speed = float(xShot.attrib.get('speed', 1.0)) # using get for legacy file support preroll = float(xShot.attrib.get('preroll', 0.0)) curves = OrderedDict() textures = OrderedDict() for xEntry in xShot: if xEntry.tag.lower() == 'channel': curveName = xEntry.attrib['name'] keys = [] if xEntry.text: keys = xEntry.text.split(',') curve = Curve() for i in range(0, len(keys), 8): curve.addKeyWithTangents(tangentBroken=int(keys[i + 6]), tangentMode=int(keys[i + 7]), *[float(x) for x in keys[i:i + 6]]) curves[curveName] = curve if xEntry.tag.lower() == 'texture': textures[xEntry.attrib['name']] = xEntry.attrib['path'] shot = Shot(name, sceneName, start, end, curves, textures, speed, preroll) if 'enabled' in xShot.attrib: shot.enabled = xShot.attrib['enabled'] == str(True) yield shot
def readChannelTemplates(): templatesDir = TemplatesPath() channelTemplates = os.path.join(templatesDir, 'uniforms.xml') result = OrderedDict() # legacy fallback if not os.path.exists(channelTemplates): curves = OrderedDict() curves['uOrigin.x'] = Curve() curves['uOrigin.y'] = Curve() curves['uOrigin.z'] = Curve() curves['uAngles.x'] = Curve() curves['uAngles.y'] = Curve() curves['uAngles.z'] = Curve() result['default'] = curves return result xRoot = ParseXMLWithIncludes(channelTemplates) for xTemplate in xRoot: name = xTemplate.attrib['name'] curves = OrderedDict() result[name] = curves for xChannel in xTemplate: curve = Curve() curves[xChannel.attrib['name']] = curve Key(0.0, float(xChannel.attrib['value']), curve).reInsert() return result
def Template(templatePath): global _templates key = os.path.abspath(templatePath).lower() try: return _templates[key] except: xTemplate = ParseXMLWithIncludes(templatePath) if _templates: raise RuntimeError( 'Found multiple templates in project, this is currently not supported by the player code.' ) _templates[key] = xTemplate return xTemplate
def _deserializePasses(sceneFile): """ :type sceneFile: str :rtype: list[PassData] """ sceneDir = os.path.splitext(sceneFile)[0] templatePath = TemplateForScene(sceneFile) templateDir = os.path.splitext(templatePath)[0] 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 = os.path.dirname(ProjectFile()) fullName = os.path.join(parentPath, xPass.attrib[key]) if fileutil.exists(fullName): inputs.append(xPass.attrib[key]) else: 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: stitches = vertStitches if xElement.attrib['path'].lower().endswith('.vert') else fragStitches if xElement.tag.lower() == 'section': stitches.append(os.path.join(sceneDir, xElement.attrib['path'])) elif xElement.tag.lower() == 'shared': stitches.append(os.path.join(templateDir, xElement.attrib['path'])) elif xElement.tag.lower() == 'global': stitches.append(os.path.join(templateDir, xElement.attrib['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 run(): shots = [] scenes = [] scenesDir = ScenesPath() for scene in os.listdir(scenesDir): if not scene.endswith(SCENE_EXT): continue scenePath = os.path.join(scenesDir, scene) sceneDir = os.path.splitext(scenePath)[0] xScene = ParseXMLWithIncludes(scenePath) templatePath = os.path.join(scenesDir, xScene.attrib['template']) templateDir = os.path.splitext(templatePath)[0] xTemplate = Template(templatePath) scene = [] for xPass in xTemplate: stitchIds = [] uniforms = {} for xSection in xPass: baseDir = sceneDir if xSection.tag in ('global', 'shared'): baseDir = templateDir shaderFile = os.path.join(baseDir, xSection.attrib['path']) stitchIds.append(text.addFile(shaderFile)) for xUniform in xSection: name = xUniform.attrib['name'] values = [ float(x.strip()) for x in xUniform.attrib['value'].split(',') ] uniforms[text.addString(name)] = len( values), floats.addFloats(values, name) programId = shaders.fromStitches(stitchIds) buffer = int(xPass.attrib.get('buffer', -1)) outputs = int(xPass.attrib.get('outputs', 1)) size = int(xPass.attrib.get('size', 0)) width = int(xPass.attrib.get('width', size)) height = int(xPass.attrib.get('height', size)) factor = int(xPass.attrib.get('factor', 1)) static = int(xPass.attrib.get('static', 0)) is3d = int(xPass.attrib.get('is3d', 0)) if buffer != -1: buffer = framebuffers.add(buffer, outputs, width, height, factor, static, is3d) i = 0 key = 'input%s' % i inputs = [] while key in xPass.attrib: v = xPass.attrib[key] if '.' in v: a, b = v.split('.') else: a, b = v, 0 inputs.append((int(a), int(b))) i += 1 key = 'input%s' % i scene.append(passes.add(programId, buffer, inputs, uniforms)) sceneIndex = len(scenes) scenes.append(len(scene)) scenes += scene for xShot in xScene: if xShot.attrib.get('enabled', 'True') == 'False': continue animations = {} for xChannel in xShot: uname = xChannel.attrib['name'] n = uname x = 0 if '.' in uname: n, x = uname.rsplit('.', 1) x = 'xyzw'.index(x) n = text.addString(n) if n not in animations: animations[n] = [] if not xChannel.text: keyframes = [] else: keyframes = [] for i, v in enumerate( float(v.strip()) for v in xChannel.text.split(',')): j = i % 8 if j == 0 or j == 4 or j > 5: continue if j == 5: # out tangent y if v == float( 'inf' ): # stepped tangents are implemented as out tangentY = positive infinity v = 'FLT_MAX' keyframes.append(v) assert len(keyframes) / 4.0 == int(len(keyframes) / 4), len(keyframes) while len(animations[n]) <= x: animations[n].append(None) assert animations[n][x] is None animations[n][x] = floats.addFloats(keyframes), len(keyframes) for channelStack in animations.values(): # TODO we can not / do not check if the channelStack length matches the uniform dimensions inside the shader (e.g. are we sure we're not gonna call glUniform2f for a vec3?) assert None not in channelStack, 'Animation provided for multiple channels but there is one missing (Y if a vec3 or also Z if a vec4).' shots.append((float(xShot.attrib['start']), float(xShot.attrib['end']), sceneIndex, animations)) # sort shots by start time def _serializeShots(shots): shots.sort(key=lambda x: x[0]) shotTimesStart = floats.addFloats( [x for shot in shots for x in (shot[0], shot[1])]) yield '\n\n__forceinline int shotAtBeats(float beats, float& localBeats)\n{\n' if len(shots) == 1: yield '\tlocalBeats = beats - gFloatData[%s];\n' % shotTimesStart yield '\treturn 0;\n' else: yield '\tint shotTimeCursor = 0;\n' yield '\tdo\n\t{\n' yield '\t\tif(beats < gFloatData[shotTimeCursor * 2 + %s])\n\t\t{\n' % ( shotTimesStart + 1) yield '\t\t\tlocalBeats = beats - gFloatData[shotTimeCursor * 2 + %s];\n' % shotTimesStart yield '\t\t\treturn shotTimeCursor;\n' yield '\t\t}\n' yield '\t}\n\twhile(++shotTimeCursor < %s);\n' % len(shots) yield '\treturn -1;\n' yield '}\n' global gShotScene gShotScene = ints.addInts([shot[2] for shot in shots]) flatAnimationData = [] animationDataPtrs = [] for shot in shots: animationDataPtrs += [len(flatAnimationData), len(shot[3].keys())] global gAnimEntriesMax gAnimEntriesMax = max(gAnimEntriesMax, len(shot[3].keys())) for uniformStringId in shot[3]: animationData = shot[3][uniformStringId] flatAnimationData += [uniformStringId, len(animationData)] for pair in animationData: flatAnimationData += pair flatAnimationData += [0] * (2 * (4 - len(animationData))) global gShotAnimationDataIds gShotAnimationDataIds = ints.addInts(animationDataPtrs) global gShotUniformData gShotUniformData = ints.addInts(flatAnimationData) def _serializeAll(scenes, shots): buffer = list(_serializeShots(shots)) for serializable in (text, floats): for ln in serializable.serialize(): yield ln buffer2 = [] for serializable in (shaders, framebuffers, passes): buffer2 += list(serializable.serialize()) global gScenePassIds gScenePassIds = ints.addInts(scenes) for ln in ints.serialize(): yield ln for ln in buffer2: yield ln for ln in buffer: yield ln data = [''.join(_serializeAll(scenes, shots))] data.append( """\n\n__forceinline float evalCurve(const float* data, int numFloats, float beats) { \tif(numFloats == 4 || beats <= data[1]) // 1 key or evaluating before first frame \t\treturn data[2]; \t// Find index of first key that has a bigger time than our current time \t// if none, this will be the index of the last key. \tint keyValueCount = numFloats; \tint rightKeyIndex = 4; \twhile (rightKeyIndex < keyValueCount - 4 && data[rightKeyIndex + 1] < beats) \t\trightKeyIndex += 4; \t// Clamp our sampling time to our range \tfloat sampleTime = (beats > data[rightKeyIndex + 1]) ? data[rightKeyIndex + 1] : beats; \t// Retrieve our spline points \tfloat y0 = data[rightKeyIndex - 2]; \tfloat y1 = data[rightKeyIndex - 1]; \t// handle stepped tangents \tif(y1 == FLT_MAX) return y0; \tfloat y2 = data[rightKeyIndex]; \tfloat y3 = data[rightKeyIndex + 2]; \tfloat dy = y3 - y0; \tfloat c0 = y1 + y2 - dy - dy; \tfloat c1 = dy + dy + dy - y1 - y1 - y2; \tfloat c2 = y1; \tfloat c3 = y0; \t// Determine factor \tfloat dt = data[rightKeyIndex + 1] - data[rightKeyIndex - 3]; \tfloat t = (sampleTime - data[rightKeyIndex - 3]) / dt; \treturn t * (t * (t * c0 + c1) + c2) + c3; } #define gAnimEntriesMax %s #define gShotAnimationDataIds %s #define gShotScene %s #define gScenePassIds %s #define gPassProgramsAndTargets %s #define gShotUniformData %s #define gFrameBufferData %s #define gFrameBufferBlockSize %s #define gProgramCount %s """ % (gAnimEntriesMax, gShotAnimationDataIds, gShotScene, gScenePassIds, gPassProgramsAndTargets, gShotUniformData, gFrameBufferData, FrameBufferPool.BLOCK_SIZE, len(shaders.offsets))) dst = os.path.join( os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'Player', 'generated.hpp') with fileutil.edit(dst, 'w') as fh: fh.write(''.join(data))