def readCameraData(self): if self.__cameraData is None: userFile = FilePath(currentProjectFilePath() + '.user') xCamera = None if userFile.exists(): xRoot = parseXMLWithIncludes(userFile) for xSub in xRoot: if xSub.attrib['name'] == self.__filePath.name(): 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 readChannelTemplates(): templatesDir = currentTemplatesDirectory() channelTemplates = templatesDir.join('uniforms.xml') result = OrderedDict() # legacy fallback if not channelTemplates.exists(): 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): assert isinstance(templatePath, FilePath) 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 _deserializeSceneShots(sceneName): sceneFile = currentScenesDirectory().join(sceneName.ensureExt(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']] = FilePath( 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 run(): shots = [] scenes = [] scenesDir = currentScenesDirectory() for scenePath in scenesDir.iter(join=True): if not scenePath.hasExt(SCENE_EXT): continue sceneDir = FilePath(scenePath.strip()).stripExt() xScene = parseXMLWithIncludes(scenePath) templatePath = scenesDir.join(scenesDir, xScene.attrib['template']) templateDir = templatePath.stripExt() 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 = baseDir.join(xSection.attrib['path']).abs() 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 = FilePath(__file__).abs().parent().parent().join( 'Player', 'generated.hpp') with dst.edit() as fh: fh.write(''.join(data))
def _saveSceneShots(sceneName, shots): sceneFile = currentScenesDirectory().join(sceneName.ensureExt(SCENE_EXT)) xScene = parseXMLWithIncludes(sceneFile) # save user camera position per scene userFile = currentProjectFilePath().ensureExt('user') if userFile.exists(): 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 userFile.edit() 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 sceneFile.edit() as fh: fh.write(toPrettyXml(xScene))
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