diff --git a/About/About.xml b/About/About.xml index 5c68e47..ff33264 100644 --- a/About/About.xml +++ b/About/About.xml @@ -3,7 +3,7 @@ Progress Renderer Lanilor https://github.com/Lanilor/Progress-Renderer - 1.0.0 + 1.0.2096 <size=20>Progress Renderer (scheduled map renderings)</size> diff --git a/About/Manifest.xml b/About/Manifest.xml new file mode 100644 index 0000000..d1b2957 --- /dev/null +++ b/About/Manifest.xml @@ -0,0 +1,8 @@ + + + ProgressRenderer + 1.0.1 + true + https://raw.githubusercontent.com/Lanilor/Progress-Renderer/master/About/Manifest.xml + https://github.com/Lanilor/Progress-Renderer/releases/latest + diff --git a/Assemblies/ProgressRenderer.dll b/Assemblies/ProgressRenderer.dll index 02053aa..b65b699 100644 Binary files a/Assemblies/ProgressRenderer.dll and b/Assemblies/ProgressRenderer.dll differ diff --git a/Defs/Misc/KeyBindings/KeyBindings.xml b/Defs/Misc/KeyBindings/KeyBindings.xml new file mode 100644 index 0000000..25c4f4f --- /dev/null +++ b/Defs/Misc/KeyBindings/KeyBindings.xml @@ -0,0 +1,18 @@ + + + + + + + LPR_ManualRendering + + Alpha9 + + + + LPR_ManualRendering_ForceFullMap + + Alpha0 + + + diff --git a/Progress Renderer 1.0.0.zip b/Progress Renderer 1.0.0.zip deleted file mode 100644 index 42e5802..0000000 Binary files a/Progress Renderer 1.0.0.zip and /dev/null differ diff --git a/Source/DefOf/KeyBindingDefOf.cs b/Source/DefOf/KeyBindingDefOf.cs new file mode 100644 index 0000000..658ee03 --- /dev/null +++ b/Source/DefOf/KeyBindingDefOf.cs @@ -0,0 +1,21 @@ +using RimWorld; +using Verse; + +namespace ProgressRenderer +{ + + [DefOf] + public static class KeyBindingDefOf + { + + static KeyBindingDefOf() + { + DefOfHelper.EnsureInitializedInCtor(typeof(KeyBindingDefOf)); + } + + public static KeyBindingDef LPR_ManualRendering; + public static KeyBindingDef LPR_ManualRendering_ForceFullMap; + + } + +} diff --git a/Source/Harmony_Patches/Harmony_ScreenshotModeHandler.cs b/Source/Harmony_Patches/Harmony_ScreenshotModeHandler.cs new file mode 100644 index 0000000..a47799f --- /dev/null +++ b/Source/Harmony_Patches/Harmony_ScreenshotModeHandler.cs @@ -0,0 +1,29 @@ +using Harmony; +using UnityEngine; +using Verse; + +namespace ProgressRenderer +{ + + [HarmonyPatch(typeof(ScreenshotModeHandler))] + [HarmonyPatch("ScreenshotModesOnGUI")] + public class Harmony_ScreenshotModeHandler_ScreenshotModesOnGUI + { + + public static void Postfix() + { + if (KeyBindingDefOf.LPR_ManualRendering.KeyDownEvent) + { + MapComponent_RenderManager.TriggerCurrentMapManualRendering(); + Event.current.Use(); + } + else if (KeyBindingDefOf.LPR_ManualRendering_ForceFullMap.KeyDownEvent) + { + MapComponent_RenderManager.TriggerCurrentMapManualRendering(true); + Event.current.Use(); + } + } + + } + +} diff --git a/Source/MapComponents/MapComponent_RenderManager.cs b/Source/MapComponents/MapComponent_RenderManager.cs index e190658..53c08f8 100644 --- a/Source/MapComponents/MapComponent_RenderManager.cs +++ b/Source/MapComponents/MapComponent_RenderManager.cs @@ -2,7 +2,6 @@ using System.Collections; using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; using System.Threading; using FluxJpeg.Core; using FluxJpeg.Core.Encoder; @@ -20,6 +19,9 @@ public class MapComponent_RenderManager : MapComponent private const int RenderTextureSize = 4096; + public static int nextGlobalRenderManagerTickOffset = 0; + + private int tickOffset = -1; private int lastRenderedHour = -999; private int lastRenderedCounter = 0; private float rsOldStartX = -1f; @@ -37,7 +39,8 @@ public class MapComponent_RenderManager : MapComponent private int imageTextureWidth; private int imageTextureHeight; - public bool renderingInt = false; + private bool manuallyTriggered = false; + private bool renderingInt = false; private bool encodingInt = false; Thread encodeThread; private bool ctrlEncodingPost = false; @@ -55,15 +58,18 @@ public bool Rendering } } - /* - public override void FinalizeInit() + public override void FinalizeInit() // New map and after loading { - // New map and after loading + if (tickOffset < 0) + { + tickOffset = nextGlobalRenderManagerTickOffset; + nextGlobalRenderManagerTickOffset = (nextGlobalRenderManagerTickOffset + 5) % GenTicks.TickRareInterval; + } } - public override void MapGenerated() + /* + public override void MapGenerated() // Only new map { - // Only new map } */ @@ -80,7 +86,7 @@ public override void MapComponentUpdate() public override void MapComponentTick() { // TickRare - if (Find.TickManager.TicksGame % 250 != 0) + if (Find.TickManager.TicksGame % 250 != tickOffset) { return; } @@ -110,6 +116,41 @@ public override void MapComponentTick() return; } // Show message window or print message + ShowCurrentRenderMessage(); + // Start rendering + Find.CameraDriver.StartCoroutine(DoRendering()); + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref lastRenderedHour, "lastRenderedHour", -999); + Scribe_Values.Look(ref lastRenderedCounter, "lastRenderedCounter", 0); + Scribe_Values.Look(ref rsOldStartX, "rsOldStartX", -1f); + Scribe_Values.Look(ref rsOldStartZ, "rsOldStartZ", -1f); + Scribe_Values.Look(ref rsOldEndX, "rsOldEndX", -1f); + Scribe_Values.Look(ref rsOldEndZ, "rsOldEndZ", -1f); + Scribe_Values.Look(ref rsTargetStartX, "rsTargetStartX", -1f); + Scribe_Values.Look(ref rsTargetStartZ, "rsTargetStartZ", -1f); + Scribe_Values.Look(ref rsTargetEndX, "rsTargetEndX", -1f); + Scribe_Values.Look(ref rsTargetEndZ, "rsTargetEndZ", -1f); + Scribe_Values.Look(ref rsCurrentPosition, "rsCurrentPosition", 1f); + } + + public static void TriggerCurrentMapManualRendering(bool forceRenderFullMap = false) + { + Find.CurrentMap.GetComponent().DoManualRendering(forceRenderFullMap); + } + + public void DoManualRendering(bool forceRenderFullMap = false) + { + ShowCurrentRenderMessage(); + manuallyTriggered = true; + Find.CameraDriver.StartCoroutine(DoRendering(forceRenderFullMap)); + } + + private void ShowCurrentRenderMessage() + { if (PRModSettings.renderFeedback == RenderFeedback.Window && PRModSettings.encoding != "jpg_fluxthreaded") { messageBox = new SmallMessageBox("LPR_Rendering".Translate()); @@ -119,32 +160,14 @@ public override void MapComponentTick() { Messages.Message("LPR_Rendering".Translate(), MessageTypeDefOf.CautionInput, false); } - // Start rendering - Find.CameraDriver.StartCoroutine(DoRendering()); - } - - public override void ExposeData() - { - base.ExposeData(); - Scribe_Values.Look(ref lastRenderedHour, "lastRenderedHour", -999); - Scribe_Values.Look(ref lastRenderedCounter, "lastRenderedCounter", 0); - Scribe_Values.Look(ref rsOldStartX, "rsOldStartX", -1f); - Scribe_Values.Look(ref rsOldStartZ, "rsOldStartZ", -1f); - Scribe_Values.Look(ref rsOldEndX, "rsOldEndX", -1f); - Scribe_Values.Look(ref rsOldEndZ, "rsOldEndZ", -1f); - Scribe_Values.Look(ref rsTargetStartX, "rsTargetStartX", -1f); - Scribe_Values.Look(ref rsTargetStartZ, "rsTargetStartZ", -1f); - Scribe_Values.Look(ref rsTargetEndX, "rsTargetEndX", -1f); - Scribe_Values.Look(ref rsTargetEndZ, "rsTargetEndZ", -1f); - Scribe_Values.Look(ref rsCurrentPosition, "rsCurrentPosition", 1f); } - private IEnumerator DoRendering() + private IEnumerator DoRendering(bool forceRenderFullMap = false) { yield return new WaitForFixedUpdate(); if (renderingInt) { - Log.Error("Progress Renderer is still rendering an image while a new rendering was requested. This can lead to missing or wrong data."); + Log.Error("Progress Renderer is still rendering an image while a new rendering was requested. This can lead to missing or wrong data. (This can also happen in rare situations when you trigger manual rendering the exact same time as an automatic rendering happens. If you did that, just check your export folder if both renderings were done corrently and ignore this error.)"); } renderingInt = true; @@ -169,54 +192,61 @@ private IEnumerator DoRendering() float startZ = 0; float endX = map.Size.x; float endZ = map.Size.z; - List cornerMarkers = map.designationManager.allDesignations.FindAll(des => des.def == DesignationDefOf.CornerMarker); - if (cornerMarkers.Count > 1) - { - startX = endX; - startZ = endZ; - endX = 0; - endZ = 0; - foreach (Designation des in cornerMarkers) + if (!forceRenderFullMap) + { + List cornerMarkers = map.designationManager.allDesignations.FindAll(des => des.def == DesignationDefOf.CornerMarker); + if (cornerMarkers.Count > 1) { - IntVec3 cell = des.target.Cell; - if (cell.x < startX) { startX = cell.x; } - if (cell.z < startZ) { startZ = cell.z; } - if (cell.x > endX) { endX = cell.x; } - if (cell.z > endZ) { endZ = cell.z; } + startX = endX; + startZ = endZ; + endX = 0; + endZ = 0; + foreach (Designation des in cornerMarkers) + { + IntVec3 cell = des.target.Cell; + if (cell.x < startX) { startX = cell.x; } + if (cell.z < startZ) { startZ = cell.z; } + if (cell.x > endX) { endX = cell.x; } + if (cell.z > endZ) { endZ = cell.z; } + } + endX += 1; + endZ += 1; } - endX += 1; - endZ += 1; } - // Test if target render area changed to reset smoothing - if (rsTargetStartX != startX || rsTargetStartZ != startZ || rsTargetEndX != endX || rsTargetEndZ != endZ) + // Only use smoothing when rendering was not triggered manually + if (!manuallyTriggered) { - // Check if area was manually reset or uninitialized (-1) to not smooth - if (rsTargetStartX == -1f && rsTargetStartZ == -1f && rsTargetEndX == -1f && rsTargetEndZ == -1f) + // Test if target render area changed to reset smoothing + if (rsTargetStartX != startX || rsTargetStartZ != startZ || rsTargetEndX != endX || rsTargetEndZ != endZ) { - rsCurrentPosition = 1f; + // Check if area was manually reset or uninitialized (-1) to not smooth + if (rsTargetStartX == -1f && rsTargetStartZ == -1f && rsTargetEndX == -1f && rsTargetEndZ == -1f) + { + rsCurrentPosition = 1f; + } + else + { + rsCurrentPosition = 1f / (PRModSettings.smoothRenderAreaSteps + 1); + } + rsOldStartX = rsTargetStartX; + rsOldStartZ = rsTargetStartZ; + rsOldEndX = rsTargetEndX; + rsOldEndZ = rsTargetEndZ; + rsTargetStartX = startX; + rsTargetStartZ = startZ; + rsTargetEndX = endX; + rsTargetEndZ = endZ; } - else + // Apply smoothing to render area + if (rsCurrentPosition < 1f) { - rsCurrentPosition = 1f / (PRModSettings.smoothRenderAreaSteps + 1); + startX = rsOldStartX + (rsTargetStartX - rsOldStartX) * rsCurrentPosition; + startZ = rsOldStartZ + (rsTargetStartZ - rsOldStartZ) * rsCurrentPosition; + endX = rsOldEndX + (rsTargetEndX - rsOldEndX) * rsCurrentPosition; + endZ = rsOldEndZ + (rsTargetEndZ - rsOldEndZ) * rsCurrentPosition; + rsCurrentPosition += 1f / (PRModSettings.smoothRenderAreaSteps + 1); } - rsOldStartX = rsTargetStartX; - rsOldStartZ = rsTargetStartZ; - rsOldEndX = rsTargetEndX; - rsOldEndZ = rsTargetEndZ; - rsTargetStartX = startX; - rsTargetStartZ = startZ; - rsTargetEndX = endX; - rsTargetEndZ = endZ; - } - // Apply smoothing to render area - if (rsCurrentPosition < 1f) - { - startX = rsOldStartX + (rsTargetStartX - rsOldStartX) * rsCurrentPosition; - startZ = rsOldStartZ + (rsTargetStartZ - rsOldStartZ) * rsCurrentPosition; - endX = rsOldEndX + (rsTargetEndX - rsOldEndX) * rsCurrentPosition; - endZ = rsOldEndZ + (rsTargetEndZ - rsOldEndZ) * rsCurrentPosition; - rsCurrentPosition += 1f / (PRModSettings.smoothRenderAreaSteps + 1); } float distX = endX - startX; @@ -372,6 +402,7 @@ private void DoEncodingPost() imageTextureHeight = 0; // Signal finished encoding + manuallyTriggered = false; encodingInt = false; // Hide message box @@ -396,9 +427,11 @@ private void EncodeUnityJpg() private void SaveUnityEncoding(byte[] encodedImage) { + // Create file and save encoded image string filePath = CreateCurrentFilePath(); File.WriteAllBytes(filePath, encodedImage); - if (PRModSettings.fileNamePattern == FileNamePattern.BothTmpCopy) + // Create tmp copy to file if needed + if (!manuallyTriggered && PRModSettings.fileNamePattern == FileNamePattern.BothTmpCopy) { File.Copy(filePath, CreateFilePath(FileNamePattern.Numbered, true)); } @@ -408,6 +441,10 @@ private void SaveUnityEncoding(byte[] encodedImage) private void EncodeFluxJpeg() { Log.Message("0 - start"); + // Get all needed data which could collide as fast as possible + bool localManuallyTriggered = manuallyTriggered; + string filePath = CreateCurrentFilePath(); + // Convert temp data to local raw data byte[][,] rawImage = new byte[3][,]; Log.Message("1"); rawImage[0] = new byte[imageTextureWidth, imageTextureHeight]; @@ -425,24 +462,26 @@ private void EncodeFluxJpeg() } } Log.Message("3 - post raw"); - // TODO: Hier invoke zum leeren der textur (oder aller tmp daten?) + // Tmp cleanup + ctrlEncodingPost = true; + // Encode raw data and save the final image ColorModel model = new ColorModel { colorspace = FluxJpeg.Core.ColorSpace.RGB }; Log.Message("4"); FluxJpeg.Core.Image image = new FluxJpeg.Core.Image(model, rawImage); Log.Message("5 - post image"); - string filePath = CreateCurrentFilePath(); FileStream fileStream = new FileStream(filePath, FileMode.Create); Log.Message("6 . post fs"); JpegEncoder encoder = new JpegEncoder(image, 75, fileStream); Log.Message("7 - post encode"); encoder.Encode(); Log.Message("8 - post save"); + // Local cleanup fileStream.Dispose(); image = null; rawImage = null; Log.Message("end - 9"); // Create tmp copy to file if needed - if (PRModSettings.fileNamePattern == FileNamePattern.BothTmpCopy) + if (!localManuallyTriggered && PRModSettings.fileNamePattern == FileNamePattern.BothTmpCopy) { File.Copy(filePath, CreateFilePath(FileNamePattern.Numbered, true)); } @@ -450,7 +489,7 @@ private void EncodeFluxJpeg() private string CreateCurrentFilePath() { - return CreateFilePath(PRModSettings.fileNamePattern); + return CreateFilePath(manuallyTriggered ? FileNamePattern.DateTime : PRModSettings.fileNamePattern); } private string CreateFilePath(FileNamePattern fileNamePattern, bool addTmpSubdir = false) @@ -472,6 +511,12 @@ private string CreateFilePath(FileNamePattern fileNamePattern, bool addTmpSubdir path = Path.Combine(path, Find.World.info.seedString); } Directory.CreateDirectory(path); + // Add subdir for manually triggered renderings + if (manuallyTriggered) + { + path = Path.Combine(path, "manually"); + Directory.CreateDirectory(path); + } // Create additional subdir for numbered symlinks if (addTmpSubdir) {