public static LSystemStepper FloatSystem( IEnumerable <string> rules, string[] globalParameters = null, string includedCharacters = "[]ABCDEFD", int branchOpenSymbol = '[', int branchCloseSymbol = ']') { var compiledRules = RuleParser.CompileRules( rules, out var nativeRuleData, branchOpenSymbol, branchCloseSymbol, globalParameters ); var customSymbols = new CustomRuleSymbols { branchOpenSymbol = branchOpenSymbol, branchCloseSymbol = branchCloseSymbol }; return(new LSystemStepper( compiledRules, nativeRuleData, customSymbols, globalParameters?.Length ?? 0, includedContextualCharactersByRuleIndex: new[] { new HashSet <int>(includedCharacters.Select(x => (int)x)) } )); }
public LSystemStepper( IEnumerable <BasicRule> rules, SystemLevelRuleNativeData nativeRuleData, CustomRuleSymbols customSymbols, int expectedGlobalParameters = 0, ISet <int>[] includedContextualCharactersByRuleIndex = null) { GlobalParameters = expectedGlobalParameters; this.customSymbols = customSymbols; includedCharacters = includedContextualCharactersByRuleIndex == null ? new HashSet <int> [0] : includedContextualCharactersByRuleIndex; rulesByTargetSymbol = new Dictionary <int, IList <BasicRule> >(); foreach (var rule in rules) { var targetSymbols = rule.TargetSymbol; if (!rulesByTargetSymbol.TryGetValue(targetSymbols, out var ruleList)) { rulesByTargetSymbol[targetSymbols] = ruleList = new List <BasicRule>(); } ruleList.Add(rule); } var maxMemoryRequirementsPerSymbol = new NativeHashMap <int, MaxMatchMemoryRequirements>(rulesByTargetSymbol.Keys.Count(), Allocator.Persistent); foreach (var symbol in rulesByTargetSymbol.Keys.ToList()) { rulesByTargetSymbol[symbol] = rulesByTargetSymbol[symbol] .OrderByDescending(x => (x.ContextPrefix.IsValid ? x.ContextPrefix.graphNodeMemSpace.length : 0) + (x.ContextSuffix.IsCreated ? x.ContextSuffix.graphNodeMemSpace.length : 0)) .ToList(); var maxParamCapturedByAnyRule = rulesByTargetSymbol[symbol] .Select(x => x.CapturedLocalParameterCount) .DefaultIfEmpty().Max(); // Greedy estimate for maximum possible parameter match. // there need to be enough space for any rule's parameters to fit, since we don't know which ones will match. var maximumPossibleParameterMatch = maxParamCapturedByAnyRule; if (maximumPossibleParameterMatch > ushort.MaxValue) { throw new LSystemRuntimeException($"Rules with more than {ushort.MaxValue} captured local parameters over all conditional options"); } maxMemoryRequirementsPerSymbol[symbol] = new MaxMatchMemoryRequirements { maxParameters = maximumPossibleParameterMatch }; } nativeRuleData.blittableRulesByTargetSymbol = NativeOrderedMultiDictionary <BasicRule.Blittable> .WithMapFunction( rulesByTargetSymbol, rule => rule.AsBlittable(), Allocator.Persistent); nativeRuleData.maxParameterMemoryRequirementsPerSymbol = maxMemoryRequirementsPerSymbol; this.nativeRuleData = new DependencyTracker <SystemLevelRuleNativeData>(nativeRuleData); }
public LSystemStepper CompileSystem(Dictionary <string, string> globalCompileTimeOverrides = null) { UnityEngine.Profiling.Profiler.BeginSample("L System compilation"); var openSymbol = GetSymbol(originFile, '['); var closeSymbol = GetSymbol(originFile, ']'); var allReplacementDirectives = GetCompileTimeReplacementsWithOverrides(globalCompileTimeOverrides); var compiledRules = CompileAllRules( allReplacementDirectives, out var nativeRuleData, openSymbol, closeSymbol); var includedByFile = allFiles.data .Select(x => new HashSet <int>(x.GetAllIncludedContextualSymbols())) .ToArray(); var customSymbols = new CustomRuleSymbols(); customSymbols.branchOpenSymbol = openSymbol; customSymbols.branchCloseSymbol = closeSymbol; foreach (var file in allFiles.data) { file.SetCustomRuleSymbols(ref customSymbols); } if (allReplacementDirectives.TryGetValue("diffusionStepsPerStep", out var defineValue)) { if (!int.TryParse(defineValue, out var stepsPerStep)) { throw new LinkException(LinkExceptionType.BAD_GLOBAL_PARAMETER, $"global parameter 'diffusionStepsPerStep' is defined, but is not an integer. this parameter must be an integer: '{defineValue}'"); } customSymbols.diffusionStepsPerStep = stepsPerStep; } customSymbols.independentDiffusionUpdate = false; customSymbols.diffusionConstantRuntimeGlobalMultiplier = 1f; if (allReplacementDirectives.TryGetValue("independentDiffusionStep", out defineValue)) { if (!bool.TryParse(defineValue, out var stepsIndependent)) { throw new LinkException(LinkExceptionType.BAD_GLOBAL_PARAMETER, $"global parameter 'independentDiffusionStep' is defined, but is not a boolean. this parameter must be either 'true' or 'false': '{defineValue}'"); } customSymbols.independentDiffusionUpdate = stepsIndependent; } var result = new LSystemStepper( compiledRules, nativeRuleData, customSymbols, expectedGlobalParameters: allGlobalRuntimeParams.Count, includedContextualCharactersByRuleIndex: includedByFile ); UnityEngine.Profiling.Profiler.EndSample(); return(result); }
public JobHandle ApplySunlightToSymbols( LSystemState <float> systemState, CustomRuleSymbols customSymbols) { var idsNativeArray = uniqueSunlightAssignments.ActiveData; if (idsNativeArray == null) { Debug.LogError("no sunlight data available"); return(default);
public DiffusionWorkingDataPack(int estimatedEdges, int estimatedNodes, int estimatedUniqueResources, CustomRuleSymbols customSymbols, Allocator allocator = Allocator.TempJob) { this.customSymbols = customSymbols; UnityEngine.Profiling.Profiler.BeginSample("allocating"); allEdges = new NativeList <DiffusionEdge>(estimatedEdges, allocator); nodes = new NativeList <DiffusionNode>(estimatedNodes, allocator); UnityEngine.Profiling.Profiler.EndSample(); nodeMaxCapacities = new NativeList <float>(estimatedNodes * estimatedUniqueResources, allocator); nodeAmountsListA = new NativeList <float>(estimatedNodes * estimatedUniqueResources, allocator); nodeAmountsListB = new NativeList <float>(estimatedNodes * estimatedUniqueResources, allocator); IsCreated = true; }
public LSystemParameterSizeCountingCompletable( LSystemState <float> systemState, DependencyTracker <SystemLevelRuleNativeData> lSystemNativeData, float[] globalParameters, ISet <int>[] includedCharactersByRuleIndex, CustomRuleSymbols customSymbols, JobHandle parameterModificationJobDependency) { currentJobHandle = default; this.globalParameters = globalParameters; this.paramModificationDependency = parameterModificationJobDependency; this.systemState = systemState; this.customSymbols = customSymbols; nativeData = lSystemNativeData; // 1. UnityEngine.Profiling.Profiler.BeginSample("Paramter counts"); UnityEngine.Profiling.Profiler.BeginSample("allocating"); matchSingletonData = new NativeArray <LSystemSingleSymbolMatchData>(systemState.currentSymbols.Data.Length, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); parameterTotalSum = new NativeArray <int>(1, Allocator.TempJob); UnityEngine.Profiling.Profiler.EndSample(); var memorySizeJob = new SymbolStringMemoryRequirementsJob { matchSingletonData = matchSingletonData, memoryRequirementsPerSymbol = nativeData.Data.maxParameterMemoryRequirementsPerSymbol, parameterTotalSum = parameterTotalSum, sourceSymbolString = systemState.currentSymbols.Data }; currentJobHandle = memorySizeJob.Schedule(); systemState.currentSymbols.RegisterDependencyOnData(currentJobHandle); nativeData.RegisterDependencyOnData(currentJobHandle); UnityEngine.Profiling.Profiler.EndSample(); // 2.1 UnityEngine.Profiling.Profiler.BeginSample("branch cache"); branchingCache = new SymbolStringBranchingCache( customSymbols.branchOpenSymbol, customSymbols.branchCloseSymbol, includedCharactersByRuleIndex, nativeData.Data); branchingCache.BuildJumpIndexesFromSymbols(systemState.currentSymbols); UnityEngine.Profiling.Profiler.EndSample(); }
private JobHandle ScheduleIndependentDiffusion(JobHandle dependency, CustomRuleSymbols customSymbols) { // diffusion is only dependent on the target symbol data. don't need to register as dependent on native data/source symbols if (customSymbols.hasDiffusion && customSymbols.independentDiffusionUpdate) { diffusionHelper = new DiffusionWorkingDataPack(10, 5, 2, customSymbols, Allocator.TempJob); var diffusionJob = new IndependentDiffusionReplacementJob { inPlaceSymbols = target, customSymbols = customSymbols, working = diffusionHelper }; dependency = diffusionJob.Schedule(dependency); } return(dependency); }
private JobHandle ScheduleAutophagyJob(JobHandle dependency, CustomRuleSymbols customSymbols) { // autophagy is only dependent on the source string. don't need to register as dependent on native data/source symbols if (customSymbols.hasAutophagy) { var helperStack = new TmpNativeStack <AutophagyPostProcess.BranchIdentity>(10, Allocator.TempJob); var autophagicJob = new AutophagyPostProcess { symbols = target, lastIdentityStack = helperStack, customSymbols = customSymbols }; dependency = autophagicJob.Schedule(dependency); dependency = helperStack.Dispose(dependency); } return(dependency); }
public TurtleInterpretor( List <TurtleOperationSet> operationSets, TurtleState defaultState, LinkedFileSet linkedFiles, CustomRuleSymbols customSymbols, OrganVolumetricWorld volumetricWorld, VoxelCapReachedTimestampEffect damageCapFlags, char startChar = '[', char endChar = ']') { foreach (var operationSet in operationSets) { operationSet.InternalCacheOperations(); } var totalRequirements = operationSets.Select(x => x.DataReqs).Aggregate(new TurtleDataRequirements(), (agg, req) => agg + req); var nativeData = new NativeTurtleData(totalRequirements); var nativeWriter = new TurtleNativeDataWriter(); foreach (var operationSet in operationSets) { operationSet.WriteIntoNativeData(nativeData, nativeWriter); } submeshMaterials = nativeWriter.materialsInOrder.ToArray(); nativeData.operationsByKey = new NativeHashMap <int, TurtleOperation>(nativeWriter.operators.Count(), Allocator.Persistent); foreach (var ops in nativeWriter.operators) { var realSymbol = linkedFiles.GetSymbolFromRoot(ops.characterInRootFile); nativeData.operationsByKey[realSymbol] = ops.operation; } branchStartChar = linkedFiles.GetSymbolFromRoot(startChar); branchEndChar = linkedFiles.GetSymbolFromRoot(endChar); this.customSymbols = customSymbols; nativeDataTracker = new DependencyTracker <NativeTurtleData>(nativeData); this.defaultState = defaultState; this.volumetricWorld = volumetricWorld; this.damageCapFlags = damageCapFlags; RefreshVolumetricWriters(); }
private JobHandle ScheduleIdAssignmentJob( JobHandle dependency, CustomRuleSymbols customSymbols, LSystemState <float> lastSystemState) { // identity assignment job is not dependent on the source string or any other native data. can skip assigning it as a dependent maxIdReached = new NativeArray <uint>(1, Allocator.TempJob); var identityAssignmentJob = new IdentityAssignmentPostProcessRule { targetData = target, maxIdentityId = maxIdReached, customSymbols = customSymbols, lastMaxIdReached = lastSystemState.maxUniqueOrganIds, uniquePlantId = lastSystemState.uniquePlantId, originOfUniqueIndexes = lastSystemState.firstUniqueOrganId, }; return(identityAssignmentJob.Schedule(dependency)); }
public TurtleStringReadingCompletable( Mesh targetMesh, int totalSubmeshes, DependencyTracker <SymbolString <float> > symbols, DependencyTracker <NativeTurtleData> nativeData, int branchStartChar, int branchEndChar, TurtleState defaultState, CustomRuleSymbols customSymbols, TurtleVolumeWorldReferences volumetrics, Matrix4x4 localToWorldTransform) { this.targetMesh = targetMesh; this.nativeData = nativeData; UnityEngine.Profiling.Profiler.BeginSample("turtling job"); JobHandleWrapper volumetricJobHandle = currentJobHandle; var volumetricHandles = new TurtleVolumetricHandles { durabilityWriter = volumetrics.durabilityWriter.GetNextNativeWritableHandle(localToWorldTransform, ref volumetricJobHandle), universalWriter = volumetrics.universalLayerWriter.GetNextNativeWritableHandle(localToWorldTransform), volumetricData = volumetrics.world.NativeVolumeData.openReadData.AsReadOnly() }; currentJobHandle = volumetricJobHandle; UnityEngine.Profiling.Profiler.BeginSample("allocating"); var tmpHelperStack = new TmpNativeStack <TurtleState>(50, Allocator.TempJob); organInstances = new NativeList <TurtleOrganInstance>(100, Allocator.TempJob); newMeshSizeBySubmesh = new NativeArray <TurtleMeshAllocationCounter>(totalSubmeshes, Allocator.TempJob); UnityEngine.Profiling.Profiler.EndSample(); NativeArray <float> destructionCommandTimestamps; if (volumetrics.damageFlags != null) { destructionCommandTimestamps = volumetrics.damageFlags.GetDestructionCommandTimestampsReadOnly(); } else { destructionCommandTimestamps = new NativeArray <float>(0, Allocator.TempJob); } var entitySpawningSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem <BeginSimulationEntityCommandBufferSystem>(); var entitySpawnBuffer = entitySpawningSystem.CreateCommandBuffer(); var turtleCompileJob = new TurtleCompilationJob { symbols = symbols.Data, operationsByKey = nativeData.Data.operationsByKey, organData = nativeData.Data.allOrganData, organInstances = organInstances, newMeshSizeBySubmesh = newMeshSizeBySubmesh, spawnEntityBuffer = entitySpawnBuffer, nativeTurtleStack = tmpHelperStack, branchStartChar = branchStartChar, branchEndChar = branchEndChar, currentState = defaultState, customRules = customSymbols, volumetricHandles = volumetricHandles, hasVolumetricDestruction = volumetrics.damageFlags != null, volumetricDestructionTimestamps = destructionCommandTimestamps, earliestValidDestructionCommand = volumetrics.damageFlags != null ? Time.time - volumetrics.damageFlags.timeCommandStaysActive : -1 }; currentJobHandle = turtleCompileJob.Schedule(currentJobHandle); volumetrics.world.NativeVolumeData.RegisterReadingDependency(currentJobHandle); entitySpawningSystem.AddJobHandleForProducer(currentJobHandle); volumetrics.damageFlags?.RegisterReaderOfDestructionFlags(currentJobHandle); volumetrics.durabilityWriter.RegisterWriteDependency(currentJobHandle); volumetrics.universalLayerWriter.RegisterWriteDependency(currentJobHandle); nativeData.RegisterDependencyOnData(currentJobHandle); symbols.RegisterDependencyOnData(currentJobHandle); currentJobHandle = tmpHelperStack.Dispose(currentJobHandle); if (volumetrics.damageFlags == null) { currentJobHandle = destructionCommandTimestamps.Dispose(currentJobHandle); } UnityEngine.Profiling.Profiler.EndSample(); }
public LSystemSymbolReplacementCompletable( Unity.Mathematics.Random randResult, LSystemState <float> lastSystemState, int totalNewSymbolSize, int totalNewParamSize, NativeArray <float> globalParamNative, NativeArray <float> tmpParameterMemory, NativeArray <LSystemSingleSymbolMatchData> matchSingletonData, DependencyTracker <SystemLevelRuleNativeData> nativeData, SymbolStringBranchingCache branchingCache, CustomRuleSymbols customSymbols) { this.lastSystemState = lastSystemState; this.matchSingletonData = matchSingletonData; this.branchingCache = branchingCache; UnityEngine.Profiling.Profiler.BeginSample("allocating"); target = new SymbolString <float>(totalNewSymbolSize, totalNewParamSize, Allocator.Persistent); UnityEngine.Profiling.Profiler.EndSample(); this.randResult = randResult; this.nativeData = nativeData; // 5 UnityEngine.Profiling.Profiler.BeginSample("generating replacements"); var replacementJob = new RuleReplacementJob { globalParametersArray = globalParamNative, parameterMatchMemory = tmpParameterMemory, matchSingletonData = matchSingletonData, sourceData = lastSystemState.currentSymbols.Data, structExpressionSpace = nativeData.Data.structExpressionMemorySpace, globalOperatorData = nativeData.Data.dynamicOperatorMemory, replacementSymbolData = nativeData.Data.replacementsSymbolMemorySpace, outcomeData = nativeData.Data.ruleOutcomeMemorySpace, targetData = target, blittableRulesByTargetSymbol = nativeData.Data.blittableRulesByTargetSymbol, branchingCache = branchingCache, customSymbols = customSymbols }; currentJobHandle = replacementJob.Schedule( matchSingletonData.Length, 100 ); if (customSymbols.hasDiffusion && !customSymbols.independentDiffusionUpdate) { diffusionHelper = new DiffusionWorkingDataPack(10, 5, 2, customSymbols, Allocator.TempJob); var diffusionJob = new ParallelDiffusionReplacementJob { matchSingletonData = matchSingletonData, sourceData = lastSystemState.currentSymbols.Data, targetData = target, customSymbols = customSymbols, working = diffusionHelper }; currentJobHandle = JobHandle.CombineDependencies( currentJobHandle, diffusionJob.Schedule() ); } // only parameter modifications beyond this point lastSystemState.currentSymbols.RegisterDependencyOnData(currentJobHandle); nativeData.RegisterDependencyOnData(currentJobHandle); currentJobHandle = JobHandle.CombineDependencies( JobHandle.CombineDependencies( ScheduleIdAssignmentJob(currentJobHandle, customSymbols, lastSystemState), ScheduleIndependentDiffusion(currentJobHandle, customSymbols) ), JobHandle.CombineDependencies( ScheduleAutophagyJob(currentJobHandle, customSymbols), ScheduleImmaturityJob(currentJobHandle) )); UnityEngine.Profiling.Profiler.EndSample(); }
/// <summary> /// /// </summary> /// <param name="lastSystemState"></param> /// <param name="lSystemNativeData"></param> /// <param name="globalParameters"></param> /// <param name="maxMemoryRequirementsPerSymbol"></param> /// <param name="branchOpenSymbol"></param> /// <param name="branchCloseSymbol"></param> /// <param name="includedCharactersByRuleIndex"></param> /// <param name="customSymbols"></param> /// <param name="parameterModificationJobDependency">A dependency on a job which only makes changes to the parameters of the source symbol string. /// the symbols themselves must be constant</param> public LSystemRuleMatchCompletable( NativeArray <LSystemSingleSymbolMatchData> matchSingletonData, int parameterTotalSum, SymbolStringBranchingCache branchingCache, LSystemState <float> lastSystemState, DependencyTracker <SystemLevelRuleNativeData> lSystemNativeData, float[] globalParameters, CustomRuleSymbols customSymbols, JobHandle parameterModificationJobDependency) { this.customSymbols = customSymbols; this.lastSystemState = lastSystemState; randResult = lastSystemState.randomProvider; nativeData = lSystemNativeData; this.matchSingletonData = matchSingletonData; this.branchingCache = branchingCache; // 1. UnityEngine.Profiling.Profiler.BeginSample("allocating"); tmpParameterMemory = new NativeArray <float>(parameterTotalSum, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); globalParamNative = new NativeArray <float>(globalParameters, Allocator.Persistent); UnityEngine.Profiling.Profiler.EndSample(); // 2. UnityEngine.Profiling.Profiler.BeginSample("matching"); var prematchJob = new RuleCompleteMatchJob { matchSingletonData = matchSingletonData, sourceData = lastSystemState.currentSymbols.Data, tmpParameterMemory = tmpParameterMemory, globalOperatorData = nativeData.Data.dynamicOperatorMemory, outcomes = nativeData.Data.ruleOutcomeMemorySpace, globalParams = globalParamNative, blittableRulesByTargetSymbol = nativeData.Data.blittableRulesByTargetSymbol, branchingCache = branchingCache, seed = randResult.NextUInt() }; var matchingJobHandle = prematchJob.ScheduleBatch( matchSingletonData.Length, 100, parameterModificationJobDependency); UnityEngine.Profiling.Profiler.EndSample(); // 4. UnityEngine.Profiling.Profiler.BeginSample("replacement counting"); UnityEngine.Profiling.Profiler.BeginSample("allocating"); totalSymbolCount = new NativeArray <int>(1, Allocator.Persistent); totalSymbolParameterCount = new NativeArray <int>(1, Allocator.Persistent); UnityEngine.Profiling.Profiler.EndSample(); var totalSymbolLengthJob = new RuleReplacementSizeJob { matchSingletonData = matchSingletonData, totalResultSymbolCount = totalSymbolCount, totalResultParameterCount = totalSymbolParameterCount, sourceData = lastSystemState.currentSymbols.Data, customSymbols = customSymbols }; currentJobHandle = totalSymbolLengthJob.Schedule(matchingJobHandle); lastSystemState.currentSymbols.RegisterDependencyOnData(currentJobHandle); nativeData.RegisterDependencyOnData(currentJobHandle); UnityEngine.Profiling.Profiler.EndSample(); }
public virtual void SetCustomRuleSymbols(ref CustomRuleSymbols customSymbols) { }