def export(self, path): filePath = FilePath(path) filePath = filePath.join("%s.glsl" % self._name) filePath.ensureExists() str = self.getFieldFragmentShaderText() with filePath.edit() as fh: fh.write(str) return
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))