private static void WeldDraftToMain(TerrainTile reference, TerrainTile welded, Coord weldDir) /// Lowers edges on welding to main tile { if (welded.draft.edges.heightEdges.IsEmpty) { welded.draft.edges.heightEdges.ReadFloats2D(welded.draft.terrain.terrainData.GetHeights(0, 0, welded.draft.terrain.terrainData.heightmapResolution, welded.draft.terrain.terrainData.heightmapResolution)); } //for an unknown reason ready chunks in scene do not have their edges (generated or saved). Leads to "Empty weld array" error. Forcing to read from terrain. EdgesSet refEdges = reference.main.edges; EdgesSet weldEdges = welded.draft.edges; //loading saved edges big array float[] refArr = refEdges.heightEdges.GetArr(weldDir); //duplicating neig saved edges short array float[] weldArr = weldEdges.heightEdges.GetArr(-weldDir); float[] weldArrCopy = new float[weldArr.Length]; //Array.Copy(weldArr, weldArrCopy, weldArr.Length); //will be re-filled anyways //welding and apply to terrain Weld.WeldArrays(refArr, weldArrCopy, lowerOnMismatch: true); Weld.ApplyToTerrain(welded.draft.terrain.terrainData, weldArrCopy, -weldDir); }
private static void RestoreDraftWeld(TerrainTile welded, Coord weldDir) /// Restoring height edges if they were lowered by welding with main { EdgesSet edges = welded.draft.edges; float[] arr = edges.heightEdges.GetArr(weldDir); Weld.ApplyToTerrain(welded.draft.terrain.terrainData, arr, weldDir); }
public static void WeldEdgesInThread(EdgesSet thisEdges, TerrainTileManager tileManager, Coord coord, bool isDraft = false) /// Welds edges (does not affect data) { if (tileManager == null) { return; } for (int d = 0; d < weldDirections.Length; d++) { TerrainTile neigTile = tileManager[coord + weldDirections[d]]; if (neigTile == null || (isDraft && neigTile.draft == null) || (isDraft && !neigTile.draft.generateReady) || (!isDraft && neigTile.main == null) || (!isDraft && !neigTile.main.generateReady)) { continue; } //if null or not generate-ready EdgesSet neigEdges = isDraft ? neigTile.draft?.edges : neigTile.main?.edges; if (neigEdges == null || !neigEdges.ready) { continue; } //height if (neigEdges.heightEdges != null && neigEdges.heightEdges.SizeX == thisEdges.heightEdges.SizeX) { Weld.WeldEdges(neigEdges.heightEdges, neigTile.coord, thisEdges.heightEdges, coord); } //splats if (neigEdges.splatEdges != null && thisEdges.splatEdges != null && thisEdges.splatEdges.Length == neigEdges.splatEdges.Length) { for (int i = 0; i < thisEdges.splatEdges.Length; i++) { if (thisEdges.splatEdges[i].SizeX == neigEdges.splatEdges[i].SizeX) { Weld.WeldEdges(neigEdges.splatEdges[i], neigTile.coord, thisEdges.splatEdges[i], coord); } } } //textures if (neigEdges.controlEdges != null && thisEdges.controlEdges != null && thisEdges.controlEdges.Length == neigEdges.controlEdges.Length) { for (int i = 0; i < thisEdges.controlEdges.Length; i++) { if (thisEdges.controlEdges[i].SizeX == neigEdges.controlEdges[i].SizeX) { Weld.WeldEdges(neigEdges.controlEdges[i], neigTile.coord, thisEdges.controlEdges[i], coord); } } } } }
private void Generate(Graph graph, TerrainTile tile, DetailLevel det, StopToken stop) /// Note that referencing det.task is illegal since task could be changed { OnBeforeTileGenerate?.Invoke(tile, det.data, stop); //do not return (for draft) until the end (apply) // if (!stop.stop) graph.CheckClear(det.data, stop); if (!stop.stop) { graph.Generate(det.data, stop); } if (!stop.stop) { graph.Finalize(det.data, stop); } //finalize event OnTileFinalized?.Invoke(tile, det.data, stop); //flushing products for playmode (all except apply) if (MapMagicObject.isPlaying) { det.data.Clear(clearApply: false); } //welding (before apply since apply will flush 2d array) if (!stop.stop) { Weld.ReadEdges(det.data, det.edges); } if (!stop.stop) { Weld.WeldEdgesInThread(det.edges, tile.mapMagic.tiles, tile.coord, det.data.isDraft); } if (!stop.stop) { Weld.WriteEdges(det.data, det.edges); } //enqueue apply //was: while the playmode is applied on SwitchLod to avoid unnecessary lags for main if (det.data.isDraft) { det.coroutine = CoroutineManager.Enqueue(() => ApplyNow(det, stop), Priority + 1000, "ApplyNow " + coord); } else //main { IEnumerator coroutine = ApplyRoutine(det, stop); det.coroutine = CoroutineManager.Enqueue(coroutine, Priority, "ApplyRoutine " + coord); } det.generateReady = true; }
private static void WeldDraftToMain(TerrainTile reference, TerrainTile welded, Coord weldDir) /// Lowers edges on welding to main tile { EdgesSet refEdges = reference.main.edges; EdgesSet weldEdges = welded.draft.edges; //loading saved edges big array float[] refArr = refEdges.heightEdges.GetArr(weldDir); //duplicating neig saved edges short array float[] weldArr = weldEdges.heightEdges.GetArr(-weldDir); float[] weldArrCopy = new float[weldArr.Length]; //Array.Copy(weldArr, weldArrCopy, weldArr.Length); //will be re-filled anyways //welding and apply to terrain Weld.WeldArrays(refArr, weldArrCopy, lowerOnMismatch: true); Weld.ApplyToTerrain(welded.draft.terrain.terrainData, weldArrCopy, -weldDir); }
public void SwitchLod() /// Changes detail level based on main and draft avaialability and readyness { if (this == null) { return; //happens after scene switch } Profiler.BeginSample("Switch Lod"); bool useMain = main != null; bool useDraft = draft != null; //if both using main //if none disabling terrain //in editor #if UNITY_EDITOR if (!MapMagicObject.isPlaying) { //if both detail levels are used - choosing the one should be displayed if (useMain && useDraft) { //if generating Draft in DraftData - switching to draft if (draft.data != null && mapMagic?.graph != null && !mapMagic.graph.AllOutputsReady(OutputLevel.Draft, draft.data)) { useMain = false; } //if generating Both in MainData - switching to draft too if (main.data != null && mapMagic?.graph != null && !mapMagic.graph.AllOutputsReady(OutputLevel.Draft | OutputLevel.Main, main.data)) { useMain = false; } //if dragging graph dragfield - do not switch from draft back to main if (mapMagic.guiDraggingField && ActiveTerrain == draft.terrain) { useMain = false; } } } else #endif //if playmode { //default case with drafts if (mapMagic.draftsInPlaymode) { if ((int)distance > mapMagic.draftSwitchRange) { useMain = false; } if ((int)distance > mapMagic.tiles.generateRange && mapMagic.hideFarTerrains) { useDraft = false; } if (!draft.applyReady) { useDraft = false; //hiding just moved terrains } } //case no drafts at all else { useDraft = false; if ((int)distance > mapMagic.tiles.generateRange && mapMagic.hideFarTerrains) { useMain = false; } } //starting apply if main is not fully applied yet if (useMain && !main.applyReady && main.generateReady && main.data.apply.Count != 0) { IEnumerator coroutine = ApplyRoutine(main, null); main.coroutine = CoroutineManager.Enqueue(coroutine, (int)(-distance * 100), "ApplyRoutinePlaymode " + coord); } //if main is not ready and using drafts if (useMain && useDraft && !main.applyReady) { useMain = false; } } //debugging //string was = ActiveTerrain==main.terrain ? "main" : (ActiveTerrain==draft.terrain ? "draft" : "null"); //string replaced = useMain ? "main" : (useDraft ? "draft" : "null"); //Debug.Log("Switching lod. Was " + was + ", replaced with " + replaced); //if (was == "draft" && replaced == "main") // Debug.Log("Test"); //finding if lod switch is for real and switching active terrain Terrain newActiveTerrain; if (useMain) { newActiveTerrain = main.terrain; } else if (useDraft) { newActiveTerrain = draft.terrain; } else { newActiveTerrain = null; } bool lodSwitched = false; if (ActiveTerrain != newActiveTerrain) { lodSwitched = true; ActiveTerrain = newActiveTerrain; } //disabling objects bool objsEnabled = useMain; // || (useDraft && mapMagic.draftsIfObjectsChanged); bool currentObjsEnabled = objectsPool.isActiveAndEnabled; if (!objsEnabled && currentObjsEnabled) { objectsPool.gameObject.SetActive(false); } if (objsEnabled && !currentObjsEnabled) { objectsPool.gameObject.SetActive(true); } //welding //TODO: check active terrain to know if the switch is for real if (lodSwitched && mapMagic.tiles.Contains(coord)) //otherwise error on SwitchLod called from Generate (when tile has been moved) { if (useMain) { Weld.WeldSurroundingDraftsToThisMain(mapMagic.tiles, coord); Weld.WeldCorners(mapMagic.tiles, coord); //Weld.SetNeighbors(mapMagic.tiles, coord); //Unity calls Terrain.SetConnectivityDirty on each terrain enable or disable that resets neighbors //using autoConnect instead. AutoConnect is a crap but neighbors are broken } else if (useDraft && draft.applyReady) { Weld.WeldThisDraftWithSurroundings(mapMagic.tiles, coord); } } if (lodSwitched) { OnLodSwitched?.Invoke(this, useMain, useDraft); } //CoroutineManager.Enqueue( ()=>Weld.SetNeighbors(mapMagic.tiles, coord) ); //CoroutineManager.Enqueue( mapMagic.Tmp ); //mapMagic.Tmp(); Profiler.EndSample(); }