private static void ReadFoliageCellDataSubdivided(BinaryReader a, out int key, out FoliageCellSubdividedData data) { // Read the key key = a.ReadInt32(); // Create new data data = new FoliageCellSubdividedData(); data.m_Bounds = ReadBounds(a); data.m_Position = ReadFoliageCell(a); int entries = a.ReadInt32(); for (int i = 0; i < entries; i++) { int dataKey = a.ReadInt32(); // Add the data with the key data.m_TypeHashLocationsEditor.Add(dataKey, new Dictionary <string, List <FoliageInstance> >()); // Read the content int entriesLabeled = a.ReadInt32(); for (int j = 0; j < entriesLabeled; j++) { string dataKeyLabel = a.ReadString(); List <FoliageInstance> instances = ReadListFoliageInstance(a, false); data.m_TypeHashLocationsEditor[dataKey].Add(dataKeyLabel, instances); } } }
private void RemoveEmptyTypeDataCellSubdivided(FoliageCellSubdividedData data) { if (data.m_TypeHashLocationsEditor.Count > 0) { HashSet <int> removeTypes = null; // Remove labeled data foreach (var pair in data.m_TypeHashLocationsEditor) { Dictionary <string, List <FoliageInstance> > labeled = pair.Value; HashSet <string> removeLabels = null; // Iterate through the label data foreach (var pairLabeled in labeled) { if (pairLabeled.Value.Count <= 0) { if (removeLabels == null) { removeLabels = new HashSet <string>(); } removeLabels.Add(pairLabeled.Key); } } // Labels to remove if (removeLabels != null) { foreach (string label in removeLabels) { labeled.Remove(label); } } // If we ended up with an empty list of data if (labeled.Count <= 0) { if (removeTypes == null) { removeTypes = new HashSet <int>(); } removeTypes.Add(pair.Key); } } if (removeTypes != null) { foreach (int type in removeTypes) { data.m_TypeHashLocationsEditor.Remove(type); } } } }
private bool IsSubCellEmpty(FoliageCellSubdividedData cell) { foreach (var data in cell.m_TypeHashLocationsEditor.Values) { foreach (var instances in data.Values) { // If we have a count return that we are not empty if (instances.Count > 0) { return(false); } } } return(true); }
private static void WriteFoliageCellDataSubdivided(BinaryWriter a, int key, FoliageCellSubdividedData data) { // Write key a.Write(key); WriteBounds(a, data.m_Bounds); WriteFoliageCell(a, data.m_Position); // Write inner cell data a.Write(data.m_TypeHashLocationsEditor.Count); foreach (int dataKey in data.m_TypeHashLocationsEditor.Keys) { a.Write(dataKey); var labeled = data.m_TypeHashLocationsEditor[dataKey]; a.Write(labeled.Count); foreach (string dataKeyLabel in labeled.Keys) { a.Write(dataKeyLabel); WriteListFoliageInstance(a, labeled[dataKeyLabel], false, true); } } }
/** * Add a new foliage instance to the underlaying data. * * The painter should decide if our data is added to the subdivisions or if it is a tree type and must not be added to the subdivision. */ public void AddInstance(int typeHash, FoliageInstance instance, bool subdivision, string label = FoliageGlobals.LABEL_PAINTED) { int hash = FoliageCell.MakeHash(instance.m_Position); if (m_FoliageData.ContainsKey(hash) == false) { FoliageCellData data = new FoliageCellData(); data.m_Position = new FoliageCell(); data.m_Position.Set(instance.m_Position); data.m_Bounds = data.m_Position.GetBounds(); data.m_BoundsExtended = data.m_Bounds; // Add the foliage cell m_FoliageData.Add(hash, data); } FoliageCellData cellData = m_FoliageData[hash]; if (subdivision == false) { if (cellData.m_TypeHashLocationsEditor.ContainsKey(typeHash) == false) { cellData.m_TypeHashLocationsEditor.Add(typeHash, new Dictionary <string, List <FoliageInstance> >()); } var labeled = cellData.m_TypeHashLocationsEditor[typeHash]; if (labeled.ContainsKey(label) == false) { labeled.Add(label, new List <FoliageInstance>()); } // Add the foliage data labeled[label].Add(instance); // Make the extended bounds larger. Encapsulate anything that might make the bounds larger. Only applied to trees m_FoliageData[hash].m_BoundsExtended.Encapsulate(instance.m_Bounds); } else { var foliageSubdividedData = cellData.m_FoliageDataSubdivided; Vector3 localPosition = GetLocalInCell(instance.m_Position, cellData); int hashSubdivided = FoliageCell.MakeHashSubdivided(localPosition); if (foliageSubdividedData.ContainsKey(hashSubdivided) == false) { FoliageCellSubdividedData data = new FoliageCellSubdividedData(); data.m_Position = new FoliageCell(); data.m_Position.SetSubdivided(localPosition); // Get bounds in world space data.m_Bounds = data.m_Position.GetBoundsSubdivided(); data.m_Bounds.center = GetWorldInCell(data.m_Bounds.center, cellData); foliageSubdividedData.Add(hashSubdivided, data); } FoliageCellSubdividedData cellDataSubdivided = foliageSubdividedData[hashSubdivided]; if (cellDataSubdivided.m_TypeHashLocationsEditor.ContainsKey(typeHash) == false) { cellDataSubdivided.m_TypeHashLocationsEditor.Add(typeHash, new Dictionary <string, List <FoliageInstance> >()); } var labeled = cellDataSubdivided.m_TypeHashLocationsEditor[typeHash]; if (labeled.ContainsKey(label) == false) { labeled.Add(label, new List <FoliageInstance>()); } labeled[label].Add(instance); } }
/** * Load from file the runtime version of the data */ public static FoliageDataRuntime LoadFromFileRuntime(string filename) { FoliageData data = LoadFromFileEditTime(filename); // Build the runtime data from the edit time data FoliageDataRuntime runtime = new FoliageDataRuntime(); foreach (var hashedCell in data.m_FoliageData) { FoliageCellData editCell = hashedCell.Value; FoliageCellDataRuntime runtimeCell = new FoliageCellDataRuntime(); // Set the data. Note that we only need the extended bounds runtimeCell.m_Bounds = editCell.m_BoundsExtended; runtimeCell.m_Position = editCell.m_Position; // Build the tree instance data int idx = -1; runtimeCell.m_TypeHashLocationsRuntime = new FoliageKeyValuePair <int, FoliageTuple <FoliageInstance[]> > [editCell.m_TypeHashLocationsEditor.Count]; foreach (var instances in editCell.m_TypeHashLocationsEditor) { idx++; List <FoliageInstance> allTreeInstances = new List <FoliageInstance>(); var labeledInstances = instances.Value; // Build all the data from the labeled data foreach (List <FoliageInstance> inst in labeledInstances.Values) { allTreeInstances.AddRange(inst); } // We will build the world matrix for trees for (int i = 0; i < allTreeInstances.Count; i++) { FoliageInstance inst = allTreeInstances[i]; inst.BuildWorldMatrix(); allTreeInstances[i] = inst; } // Don't forget to trim all excess instances! allTreeInstances.TrimExcess(); #if UNITY_EDITOR if (allTreeInstances.Count == 0) { Debug.Assert(false, "Count 0!"); } #endif runtimeCell.m_TypeHashLocationsRuntime[idx] = new FoliageKeyValuePair <int, FoliageTuple <FoliageInstance[]> >(instances.Key, new FoliageTuple <FoliageInstance[]>(allTreeInstances.ToArray())); } // Build the grass instance data from the subdivided cells List <FoliageKeyValuePair <int, FoliageCellSubdividedDataRuntime> > foliageCellDataSubdivided = new List <FoliageKeyValuePair <int, FoliageCellSubdividedDataRuntime> >(editCell.m_FoliageDataSubdivided.Count); foreach (var hashedSubdividedCell in editCell.m_FoliageDataSubdivided) { FoliageCellSubdividedData editSubdividedCell = hashedSubdividedCell.Value; FoliageCellSubdividedDataRuntime runtimeSubdividedCell = new FoliageCellSubdividedDataRuntime(); // Set the data runtimeSubdividedCell.m_Bounds = editSubdividedCell.m_Bounds; runtimeSubdividedCell.m_Position = editSubdividedCell.m_Position; idx = -1; runtimeSubdividedCell.m_TypeHashLocationsRuntime = new FoliageKeyValuePair <int, FoliageTuple <Matrix4x4[][]> > [editSubdividedCell.m_TypeHashLocationsEditor.Count]; foreach (var instances in editSubdividedCell.m_TypeHashLocationsEditor) { idx++; List <FoliageInstance> allGrassInstances = new List <FoliageInstance>(); var labeledInstances = instances.Value; foreach (List <FoliageInstance> inst in labeledInstances.Values) { allGrassInstances.AddRange(inst); } #if UNITY_EDITOR if (allGrassInstances.Count == 0) { Debug.Assert(false, "Count 0!"); } #endif // Build the multi-array data int ranges = Mathf.CeilToInt(allGrassInstances.Count / (float)FoliageGlobals.RENDER_BATCH_SIZE); Matrix4x4[][] batches = new Matrix4x4[ranges][]; for (int i = 0; i < ranges; i++) { List <FoliageInstance> range = allGrassInstances.GetRange(i * FoliageGlobals.RENDER_BATCH_SIZE, i * FoliageGlobals.RENDER_BATCH_SIZE + FoliageGlobals.RENDER_BATCH_SIZE > allGrassInstances.Count ? allGrassInstances.Count - i * FoliageGlobals.RENDER_BATCH_SIZE : FoliageGlobals.RENDER_BATCH_SIZE); batches[i] = range.ConvertAll <Matrix4x4>((x) => x.GetWorldTransform()).ToArray(); } // Set the data runtimeSubdividedCell.m_TypeHashLocationsRuntime[idx] = new FoliageKeyValuePair <int, FoliageTuple <Matrix4x4[][]> >(instances.Key, new FoliageTuple <Matrix4x4[][]>(batches)); } // Add the subdivided runtime cell foliageCellDataSubdivided.Add(new FoliageKeyValuePair <int, FoliageCellSubdividedDataRuntime>(hashedSubdividedCell.Key, runtimeSubdividedCell)); } // Build the subdivided data runtimeCell.m_FoliageDataSubdivided = foliageCellDataSubdivided.ToArray(); // Add the runtime cell runtime.m_FoliageData.Add(hashedCell.Key, runtimeCell); } // Good for GC data = null; return(runtime); }