diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d44b36e1..925fb34b 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -17,6 +17,6 @@ on:
jobs:
build:
- uses: KSPModdingLibs/KSPBuildTools/.github/workflows/build.yml@0.0.4
+ uses: KSPModdingLibs/KSPBuildTools/.github/workflows/build.yml@1.1.1
with:
use-ckan: true
diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
index 0094e516..fb45e092 100644
--- a/.github/workflows/create-release.yml
+++ b/.github/workflows/create-release.yml
@@ -9,7 +9,7 @@ on:
jobs:
create-release:
- uses: KSPModdingLibs/KSPBuildTools/.github/workflows/create-release.yml@0.0.4
+ uses: KSPModdingLibs/KSPBuildTools/.github/workflows/create-release.yml@1.1.1
with:
version-string: ${{ inputs.version-string }}
use-ckan: true
diff --git a/.github/workflows/publish-to-spacedock.yml b/.github/workflows/publish-to-spacedock.yml
index 183d1fbe..d1b0a0ae 100644
--- a/.github/workflows/publish-to-spacedock.yml
+++ b/.github/workflows/publish-to-spacedock.yml
@@ -6,7 +6,7 @@ on:
jobs:
publish-to-spacedock:
- uses: KSPModdingLibs/KSPBuildTools/.github/workflows/publish-to-spacedock.yml@0.0.4
+ uses: KSPModdingLibs/KSPBuildTools/.github/workflows/publish-to-spacedock.yml@1.1.1
with:
spacedock-username: ${{ vars.SPACEDOCK_USERNAME }}
mod-id: ${{ vars.SPACEDOCK_MOD_ID }}
diff --git a/.gitignore b/.gitignore
index 197a1a8f..2e20bb5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,9 @@
bin/
obj/
*.user
+*.dll
+*.pdb
+SCANsat.Unity/Properties/launchSettings.json
GameData/SCANsat/Plugins/SCAN*
GameData/SCANsat/PluginData/Settings.cfg
GameData/SCANsat/Parts/@thumbs/
diff --git a/GameData/SCANsat/Resources/SCANcolors.cfg b/GameData/SCANsat/Resources/SCANcolors.cfg
index 48295284..f5ba69b5 100644
--- a/GameData/SCANsat/Resources/SCANcolors.cfg
+++ b/GameData/SCANsat/Resources/SCANcolors.cfg
@@ -10,7 +10,6 @@ SCAN_Color_Config
Item
{
name = Kerbin
- index = 1
minHeightRange = -1500
maxHeightRange = 6500
clampHeight = 0
@@ -25,7 +24,6 @@ SCAN_Color_Config
Item
{
name = Sun
- index = 0
minHeightRange = 0
maxHeightRange = 1000
clampHeight = Null
@@ -40,7 +38,6 @@ SCAN_Color_Config
Item
{
name = Mun
- index = 2
minHeightRange = -500
maxHeightRange = 7000
clampHeight = Null
@@ -55,7 +52,6 @@ SCAN_Color_Config
Item
{
name = Minmus
- index = 3
minHeightRange = -500
maxHeightRange = 5500
clampHeight = Null
@@ -70,7 +66,6 @@ SCAN_Color_Config
Item
{
name = Moho
- index = 4
minHeightRange = -300
maxHeightRange = 6500
clampHeight = Null
@@ -85,7 +80,6 @@ SCAN_Color_Config
Item
{
name = Eve
- index = 5
minHeightRange = -2000
maxHeightRange = 7000
clampHeight = 0
@@ -100,7 +94,6 @@ SCAN_Color_Config
Item
{
name = Duna
- index = 6
minHeightRange = 0
maxHeightRange = 7000
clampHeight = Null
@@ -115,7 +108,6 @@ SCAN_Color_Config
Item
{
name = Ike
- index = 7
minHeightRange = 0
maxHeightRange = 12000
clampHeight = Null
@@ -130,7 +122,6 @@ SCAN_Color_Config
Item
{
name = Jool
- index = 8
minHeightRange = 0
maxHeightRange = 1000
clampHeight = Null
@@ -145,7 +136,6 @@ SCAN_Color_Config
Item
{
name = Laythe
- index = 9
minHeightRange = -3000
maxHeightRange = 6000
clampHeight = 0
@@ -160,7 +150,6 @@ SCAN_Color_Config
Item
{
name = Vall
- index = 10
minHeightRange = -500
maxHeightRange = 7500
clampHeight = Null
@@ -175,7 +164,6 @@ SCAN_Color_Config
Item
{
name = Bop
- index = 11
minHeightRange = 2000
maxHeightRange = 21500
clampHeight = Null
@@ -190,7 +178,6 @@ SCAN_Color_Config
Item
{
name = Tylo
- index = 12
minHeightRange = 0
maxHeightRange = 11000
clampHeight = Null
@@ -205,7 +192,6 @@ SCAN_Color_Config
Item
{
name = Gilly
- index = 13
minHeightRange = 1500
maxHeightRange = 6000
clampHeight = Null
@@ -220,7 +206,6 @@ SCAN_Color_Config
Item
{
name = Pol
- index = 14
minHeightRange = 500
maxHeightRange = 5500
clampHeight = Null
@@ -235,7 +220,6 @@ SCAN_Color_Config
Item
{
name = Dres
- index = 15
minHeightRange = -200
maxHeightRange = 5500
clampHeight = Null
@@ -250,7 +234,6 @@ SCAN_Color_Config
Item
{
name = Eeloo
- index = 16
minHeightRange = -500
maxHeightRange = 3500
clampHeight = Null
diff --git a/GameData/SCANsat/SCANsat.version b/GameData/SCANsat/SCANsat.version
index af2031d8..2b4319d5 100644
--- a/GameData/SCANsat/SCANsat.version
+++ b/GameData/SCANsat/SCANsat.version
@@ -1,6 +1,7 @@
{
"NAME": "SCANsat",
- "URL": "https://github.com/KSPModStewards/SCANsat/releases/latest/download/SCANsat.version",
- "DOWNLOAD": "https://github.com/KSPModStewards/SCANsat/releases"
-
+ "VERSION": "21.1.0.0",
+ "KSP_VERSION": "1.12",
+ "KSP_VERSION_MIN": "1.12.3",
+ "KSP_VERSION_MAX": "1.12"
}
diff --git a/README.md b/README.md
index 9647d41c..09645688 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@
> ![scan your planetoid like the big boys do][bigmap-scan-10000x]
> ###### **Example SAR scan of Kerbin at 1000x and then 10,000x warp**
+[![][shield:support-ksptl]][ksptl:release]
[![][shield:support-rpm]][RPM:release]
[![][shield:support-mm]][mm:release]
[![][shield:support-toolbar]][toolbar:release]
@@ -25,7 +26,8 @@
* [1. Installation and Interoperability][1]
* [a. Installation][1a]
* [b. GameData Layout][1b]
- * [c. Other Add-Ons][1c]
+ * [c. Texture Configurations][1c]
+ * [d. Other Add-Ons][1d]
* [2. Types of Scans][2]
* [a. Native SCANsat][2a]
* [3. Resource Scanning][3]
@@ -165,7 +167,25 @@ For licensing information, please see the [included LICENSE.txt][SCANsat:rel-lic
![][SCANsat:gamedata]
-#### [:top:][top] 1c. Other Add-Ons
+#### [:top:][top] 1c. Texture Configurations
+
+S.C.A.N. was originally designed to load all visual and normal textures into RAM directly from the game, as this doesn't require any additional configuration steps for planet packs to integrate directly with the mod. This, however, has led to performance issues with large scale textures and planet packs (notoriously Real Solar System scale packs like Sol).
+
+To get around this, support has been added for memory mapping external textures through KSPTextureLoader. This works by defining the relative path to the height, normal and color textures for each planet, and defining them in a config file as shown below (recommend making one for each body titled "BodyName_SCANsat.cfg"):
+
+```
+SCANSAT_BODY_TEXTURES
+{
+ name = Mercury // Use name of body in Kopernicus
+ heightMap = GameData/Sol-Textures/PluginData/01_Mercury/Kopernicus/Mercury_Height.dds
+ normalMap = GameData/Sol-Textures/PluginData/01_Mercury/Kopernicus/Mercury_Normal.dds
+ colorMap = GameData/Sol-Textures/PluginData/01_Mercury/Kopernicus/Mercury_Color.dds
+}
+```
+
+With these paths defined, the CPU is able to pull data directly out of the texture from the file system without loading it into RAM. Planet pack makers are encouraged to use this new interface with their packs as this directly specifies the textures SCANsat will display in game.
+
+#### [:top:][top] 1d. Other Add-Ons
S.C.A.N. is proud to collaborate with other KSP mods and modding teams. Following is a table of all of the mods, add-ons, or software that we interoperate with.
@@ -175,14 +195,14 @@ S.C.A.N. is proud to collaborate with other KSP mods and modding teams. Followin
[**Blizzy78's Toolbar**][toolbar:release] | [![Support for Karbonite][karbonite:logo]][karbonite:release]
[**ModuleManager**][mm:release] | [![Support for ALCOR][alcor:logo]][alcor:release]
[**RasterPropMonitor**][rpm:release] |
+[**KSPTextureLoader**][ksptl:release] |
-* **SCANsat**
- * [x] [**v16.0**][SCANsat:rel-thread] SCANsat Release **version: v16.0**
- * [x] [**v15.0**][SCANsat:dev-thread] SCANsat Dev **version: v15.0**
+ **MM**, **RPM**, **MechJeb** and **Toolbar** are all **soft** dependencies. This means your experience with SCANsat will be enhanced if you are using these mods, but they are not necessary.
- **MM**, **RPM**, **MechJeb**, and **Toolbar** are all **soft** dependencies. This means your experience with SCANsat will be enhanced if you are using these mods, but they are not necessary.
+**KSPTextureLoader** is a built dependency, however, as all planets that have external texture files are strongly recommended to use memory mapped textures, with RAM cached variants only being a fallback. This ensures that no errors occur with shader configs and that the exact texture desired ends up displayed in game.
**SCANsat** is built against the following mods:
+ * [x] [![][shield:support-ksptl]][ksptl:release]
* [x] [![][shield:support-mm]][mm:release]
* [x] [![][shield:support-rpm]][rpm:release]
* [x] [![][shield:support-alcor]][alcor:release]
@@ -200,6 +220,8 @@ scanning modules or parts).
* **RadarHi**: Advanced, High-Resolution RADAR Altimetry (in color, unlimited zoom)
* **Slope**: Slope Data converted from RADAR data
* **Biome**: Biome Detection and Classification (in color, unlimited zoom)
+ * **VisualLo**: Basic, Low-Resolution Visual Imaging (b&w, limited zoom)
+ * **VisualHi**: Full Color, High Resolution Visual Imaging
* **Anomaly**: Anomaly Detection and Labeling
* **Resource**: Scan for chemical or mineral resource on the surface.
@@ -815,7 +837,8 @@ sneaky then they can of course be sneaky.
[1]: #top-1-installation-and-interoperability
[1a]: #top-1a-installation
[1b]: #top-1b-gamedata-layout
-[1c]: #top-1c-other-add-ons
+[1c]: #top-1c-texture-configurations
+[1d]: #top-1d-other-add-ons
[2]: #top-2-types-of-scans
[2a]: #top-2a-scansat-scans
[3]: #top-3-resource-scanning
@@ -863,8 +886,9 @@ sneaky then they can of course be sneaky.
[shield:jenkins-dev]: http://img.shields.io/jenkins/s/https/ksp.sarbian.com/jenkins/SCANsat-dev.svg
[shield:jenkins-rel]: http://img.shields.io/jenkins/s/https/ksp.sarbian.com/jenkins/SCANsat-release.svg
-[shield:support-ksp]: http://img.shields.io/badge/for%20KSP-v1.4.1-bad455.svg
+[shield:support-ksp]: http://img.shields.io/badge/for%20KSP-v1.12.x-bad455.svg
[shield:support-rpm]: http://img.shields.io/badge/works%20with%20RPM-v0.28.x-a31f34.svg
+[shield:support-ksptl]: https://img.shields.io/badge/requires%20KSPTextureLoader-1.0.34+-84e0d7.svg
[shield:support-mm]: http://img.shields.io/badge/works%20with%20MM-v3.x-40b7c0.svg
[shield:support-toolbar]: http://img.shields.io/badge/works%20with%20Blizzy's%20Toolbar-1.7.x-7c69c0.svg
[shield:support-alcor]: http://img.shields.io/badge/works%20with%20ALCOR-0.9-299bc7.svg
@@ -961,7 +985,9 @@ sneaky then they can of course be sneaky.
[toolbar:release]: http://forum.kerbalspaceprogram.com/threads/60863
-[rpm:release]: http://forum.kerbalspaceprogram.com/threads/117471
+[rpm:release]: https://github.com/FirstPersonKSP/RasterPropMonitor/releases
+
+[ksptl:release]: https://github.com/Phantomical/KSPTextureLoader/releases
[cconfig:release]: http://forum.kerbalspaceprogram.com/threads/101604
diff --git a/SCANmechjeb/SCANmechjeb.cs b/SCANmechjeb/SCANmechjeb.cs
index f98c2c73..64258f3b 100644
--- a/SCANmechjeb/SCANmechjeb.cs
+++ b/SCANmechjeb/SCANmechjeb.cs
@@ -14,12 +14,12 @@
using System.Collections;
using SCANsat;
using SCANsat.SCAN_Data;
-using log = SCANsat.SCAN_Platform.Logging.ConsoleLogger;
-using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
+using Log = KSPCommunityLib.Logging.Log;
using MuMech;
using UnityEngine;
using UnityEngine.Events;
+using System.Reflection;
namespace SCANmechjeb
{
@@ -36,6 +36,55 @@ class SCANmechjeb : MonoBehaviour
private Vector2d coords = new Vector2d();
private bool shutdown, mjOnboard, mjTechTreeLocked;
+ // Store references to required fields - type name changes between Target / Hidden and target / hidden across MechJeb versions
+ private readonly static FieldInfo targetField;
+ private readonly static FieldInfo hiddenField;
+
+ ///
+ /// Reflectively fetches MechJebCore fields, tolerating the
+ /// 'Target'/'target' field rename across MechJeb versions. Returns null
+ /// (and logs) if the field can't be resolved under any known name.
+ ///
+ static SCANmechjeb()
+ {
+ var t = new MechJebCore().GetType();
+ targetField = t.GetField("Target") ?? t.GetField("target");
+ if (targetField == null)
+ {
+ Log.Message("MechJebCore 'target' field could not be found under any known name; MechJeb support broken.");
+ }
+
+ hiddenField = t.GetField("Hidden") ?? t.GetField("hidden");
+ if (hiddenField == null)
+ {
+ Log.Message("MechJebGuidanceModule 'hidden' field could not be found under any known name; MechJeb support broken.");
+ }
+ }
+
+ #region Helpers
+
+ ///
+ /// Reflectively fetches MechJebCore's target controller, tolerating the
+ /// 'Target'/'target' field rename across MechJeb versions. Returns null
+ /// (and logs) if the field can't be resolved under any known name.
+ ///
+ private static MechJebModuleTargetController GetMJCoreTarget(MechJebCore mjc)
+ {
+ return targetField?.GetValue(mjc) as MechJebModuleTargetController;
+ }
+
+ ///
+ /// Reflectively reads the guidance module's hidden flag, tolerating the
+ /// 'Hidden'/'hidden' field rename across MechJeb versions. Returns null
+ /// (and logs) if the field can't be resolved under any known name.
+ ///
+ private static bool? IsMJGuidanceModuleHidden(DisplayModule gm)
+ {
+ return hiddenField?.GetValue(gm) as bool?;
+ }
+
+ #endregion
+
private void Start()
{
GameEvents.onVesselWasModified.Add(VesselChange);
@@ -227,7 +276,7 @@ private void RefereshAfterVesselChange()
return;
}
- target = mjCore.target;
+ target = GetMJCoreTarget(mjCore);
if (target == null)
{
@@ -256,7 +305,8 @@ private void RefereshAfterVesselChange()
guidanceModule.UnlockCheck();
- if (guidanceModule.hidden)
+ var hidden = IsMJGuidanceModuleHidden(guidanceModule);
+ if (hidden ?? true) // Defaults to a hidden state if the field cannot be found
{
SCANcontroller.controller.MechJebLoaded = false;
way = null;
@@ -270,4 +320,4 @@ private void RefereshAfterVesselChange()
mjTechTreeLocked = false;
}
}
-}
+}
\ No newline at end of file
diff --git a/SCANmechjeb/SCANmechjeb.csproj b/SCANmechjeb/SCANmechjeb.csproj
index 161bf44a..f673f0eb 100644
--- a/SCANmechjeb/SCANmechjeb.csproj
+++ b/SCANmechjeb/SCANmechjeb.csproj
@@ -3,23 +3,22 @@
Library
SCANmechjeb
SCANmechjeb
- net4.8
+ net48
- true
- true
+ true
+ true
-
- False
- $(KSPRoot)\GameData\MechJeb2\Plugins\MechJeb2.dll
- False
+
+ GameData/MechJeb2/Plugins/MechJeb2.dll
MechJeb2
- 2.5
-
+ 2.5
+
-
+
+
diff --git a/SCANsat.Unity/InputHandler.cs b/SCANsat.Unity/InputHandler.cs
index 291a7746..00cbcba6 100644
--- a/SCANsat.Unity/InputHandler.cs
+++ b/SCANsat.Unity/InputHandler.cs
@@ -11,12 +11,8 @@
*/
#endregion
-using System;
-using System.Collections.Generic;
using UnityEngine;
-using UnityEngine.UI;
using UnityEngine.Events;
-using UnityEngine.EventSystems;
namespace SCANsat.Unity
{
diff --git a/SCANsat.Unity/Interfaces/ISCAN_MainMap.cs b/SCANsat.Unity/Interfaces/ISCAN_MainMap.cs
index 677e2348..3c3a66b4 100644
--- a/SCANsat.Unity/Interfaces/ISCAN_MainMap.cs
+++ b/SCANsat.Unity/Interfaces/ISCAN_MainMap.cs
@@ -17,6 +17,13 @@
namespace SCANsat.Unity.Interfaces
{
+ public enum MainMapDisplayMode
+ {
+ Terrain = 0,
+ Visual = 1,
+ Biome = 2
+ }
+
public interface ISCAN_MainMap
{
string Version { get; }
@@ -27,7 +34,7 @@ public interface ISCAN_MainMap
bool TerminatorToggle { get; set; }
- bool MapType { get; set; }
+ MainMapDisplayMode MapType { get; set; }
bool Minimized { get; set; }
diff --git a/SCANsat.Unity/SCANsat.Unity.csproj b/SCANsat.Unity/SCANsat.Unity.csproj
index cc67fc8b..09ff5a8a 100644
--- a/SCANsat.Unity/SCANsat.Unity.csproj
+++ b/SCANsat.Unity/SCANsat.Unity.csproj
@@ -6,9 +6,11 @@
net4.8
- false
+ false
+ true
-
+
+
\ No newline at end of file
diff --git a/SCANsat.Unity/Unity/SCAN_MainMap.cs b/SCANsat.Unity/Unity/SCAN_MainMap.cs
index 52c06d1d..b362c9be 100644
--- a/SCANsat.Unity/Unity/SCAN_MainMap.cs
+++ b/SCANsat.Unity/Unity/SCAN_MainMap.cs
@@ -140,7 +140,28 @@ public void setMap(ISCAN_MainMap map)
if (m_TypeToggle != null)
{
- m_TypeToggle.isOn = map.MapType;
+ // Map display mode to toggle state for UI purposes
+ // We'll cycle through modes on click
+ m_TypeToggle.interactable = true;
+ }
+
+ if (m_TypeLabel != null)
+ {
+ // Show initial display mode
+ string label = "Altimetry";
+ switch (map.MapType)
+ {
+ case (MainMapDisplayMode.Terrain):
+ label = "Altimetry";
+ break;
+ case (MainMapDisplayMode.Biome):
+ label = "Biome";
+ break;
+ case (MainMapDisplayMode.Visual):
+ label = "Visual";
+ break;
+ }
+ m_TypeLabel.OnTextUpdate.Invoke(label);
}
if (m_MinimizeToggle != null)
@@ -148,19 +169,13 @@ public void setMap(ISCAN_MainMap map)
m_MinimizeToggle.isOn = map.Minimized;
}
- //if (m_M700Text != null && !map.ResourcesOn)
- // m_M700Text.gameObject.SetActive(false);
-
- //if (m_OreText != null && !map.ResourcesOn)
- // m_OreText.gameObject.SetActive(false);
-
CreateVessels(map.VesselInfoList);
SetScale(map.Scale);
SetPosition(map.Position);
- if (!map.MapType)
+ if (map.MapType == MainMapDisplayMode.Terrain)
{
SetGeneratingText(map.MapGenerating);
}
@@ -525,17 +540,57 @@ public void ToggleTerminator(bool isOn)
public void ToggleType(bool isOn)
{
- if (m_TypeLabel != null)
+ if (!loaded || mapInterface == null)
{
- m_TypeLabel.OnTextUpdate.Invoke(isOn ? "Biome" : "Terrain");
+ return;
}
- if (!loaded || mapInterface == null)
+ // Cycle through display modes: Terrain -> Visual -> Biome -> Terrain
+ MainMapDisplayMode currentMode = mapInterface.MapType;
+ MainMapDisplayMode nextMode;
+
+ switch (currentMode)
{
- return;
+ case MainMapDisplayMode.Terrain:
+ nextMode = MainMapDisplayMode.Visual;
+ break;
+ case MainMapDisplayMode.Visual:
+ nextMode = MainMapDisplayMode.Biome;
+ break;
+ case MainMapDisplayMode.Biome:
+ nextMode = MainMapDisplayMode.Terrain;
+ break;
+ default:
+ nextMode = MainMapDisplayMode.Terrain;
+ break;
+ }
+
+ mapInterface.MapType = nextMode;
+
+ // Update label
+ if (m_TypeLabel != null)
+ {
+ string label = "";
+ switch (nextMode)
+ {
+ case (MainMapDisplayMode.Terrain):
+ label = "Altimetry";
+ break;
+ case (MainMapDisplayMode.Biome):
+ label = "Biome";
+ break;
+ case (MainMapDisplayMode.Visual):
+ label = "Visual";
+ break;
+ }
+ m_TypeLabel.OnTextUpdate.Invoke(label);
}
- mapInterface.MapType = isOn;
+ // Update toggle appearance (cycle through states visually)
+ if (m_TypeToggle != null)
+ {
+ m_TypeToggle.isOn = (nextMode != MainMapDisplayMode.Terrain);
+ }
}
public void ToggleSize(bool isOn)
diff --git a/SCANsat.sln b/SCANsat.sln
deleted file mode 100644
index 94f9398d..00000000
--- a/SCANsat.sln
+++ /dev/null
@@ -1,247 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.11.35312.102
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCANsat", "SCANsat\SCANsat.csproj", "{3AE13948-477D-4375-8AB4-B45664966D9E}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCANmechjeb", "SCANmechjeb\SCANmechjeb.csproj", "{A2B942AF-3AB2-4A9F-9211-FFC47364128D}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SCANsat.Unity", "SCANsat.Unity\SCANsat.Unity.csproj", "{4ED5E40D-273A-4643-9009-04C1DD02F3E2}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{63914E47-3B9A-4298-BAA4-362B47D8F105}"
- ProjectSection(SolutionItems) = preProject
- .editorconfig = .editorconfig
- .gitignore = .gitignore
- CHANGELOG.md = CHANGELOG.md
- CONTRIBUTING.md = CONTRIBUTING.md
- LICENSE.txt = LICENSE.txt
- README.md = README.md
- SCANsat.props = SCANsat.props
- SCANsat.props.user = SCANsat.props.user
- SCANsat.version.props = SCANsat.version.props
- EndProjectSection
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {3AE13948-477D-4375-8AB4-B45664966D9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3AE13948-477D-4375-8AB4-B45664966D9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3AE13948-477D-4375-8AB4-B45664966D9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3AE13948-477D-4375-8AB4-B45664966D9E}.Release|Any CPU.Build.0 = Release|Any CPU
- {A2B942AF-3AB2-4A9F-9211-FFC47364128D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A2B942AF-3AB2-4A9F-9211-FFC47364128D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A2B942AF-3AB2-4A9F-9211-FFC47364128D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A2B942AF-3AB2-4A9F-9211-FFC47364128D}.Release|Any CPU.Build.0 = Release|Any CPU
- {4ED5E40D-273A-4643-9009-04C1DD02F3E2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4ED5E40D-273A-4643-9009-04C1DD02F3E2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4ED5E40D-273A-4643-9009-04C1DD02F3E2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4ED5E40D-273A-4643-9009-04C1DD02F3E2}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {316FD7A6-78EB-48DD-92DE-595FE8DD957D}
- EndGlobalSection
- GlobalSection(MonoDevelopProperties) = preSolution
- StartupItem = SCANdebug\SCANdebug.csproj
- Policies = $0
- $0.DotNetNamingPolicy = $1
- $1.DirectoryNamespaceAssociation = None
- $1.ResourceNamePolicy = FileFormatDefault
- $0.StandardHeader = $2
- $2.Text =
- $2.IncludeInNewFiles = True
- $0.TextStylePolicy = $39
- $3.inheritsSet = null
- $3.scope = text/x-csharp
- $0.CSharpFormattingPolicy = $4
- $4.IndentSwitchBody = True
- $4.NamespaceBraceStyle = EndOfLine
- $4.ClassBraceStyle = EndOfLine
- $4.InterfaceBraceStyle = EndOfLine
- $4.StructBraceStyle = EndOfLine
- $4.EnumBraceStyle = EndOfLine
- $4.MethodBraceStyle = EndOfLine
- $4.ConstructorBraceStyle = EndOfLine
- $4.DestructorBraceStyle = EndOfLine
- $4.WithinMethodDeclarationParentheses = True
- $4.WithinConstructorDeclarationParentheses = True
- $4.BeforeIndexerDeclarationBracket = False
- $4.AfterDelegateDeclarationParameterComma = True
- $4.WithinDelegateDeclarationParentheses = True
- $4.AroundShiftOperatorParentheses = False
- $4.SpacesBeforeBrackets = False
- $4.BlankLinesBetweenTypes = 2
- $4.inheritsSet = Mono
- $4.inheritsScope = text/x-csharp
- $4.scope = text/x-csharp
- $5.FileWidth = 120
- $5.TabWidth = 2
- $5.NoTabsAfterNonTabs = True
- $5.EolMarker = Windows
- $5.inheritsSet = Mono
- $5.inheritsScope = text/plain
- $5.scope = text/plain
- $6.inheritsSet = null
- $6.scope = application/octet-stream
- $0.NameConventionPolicy = $7
- $7.Rules = $8
- $8.NamingRule = $33
- $9.Name = Namespaces
- $9.AffectedEntity = Namespace
- $9.VisibilityMask = VisibilityMask
- $9.NamingStyle = PascalCase
- $9.IncludeInstanceMembers = True
- $9.IncludeStaticEntities = True
- $10.Name = Types
- $10.AffectedEntity = Class, Struct, Enum, Delegate
- $10.VisibilityMask = VisibilityMask
- $10.NamingStyle = PascalCase
- $10.IncludeInstanceMembers = True
- $10.IncludeStaticEntities = True
- $11.Name = Interfaces
- $11.RequiredPrefixes = $12
- $12.String = I
- $11.AffectedEntity = Interface
- $11.VisibilityMask = VisibilityMask
- $11.NamingStyle = PascalCase
- $11.IncludeInstanceMembers = True
- $11.IncludeStaticEntities = True
- $13.Name = Attributes
- $13.RequiredSuffixes = $14
- $14.String = Attribute
- $13.AffectedEntity = CustomAttributes
- $13.VisibilityMask = VisibilityMask
- $13.NamingStyle = PascalCase
- $13.IncludeInstanceMembers = True
- $13.IncludeStaticEntities = True
- $15.Name = Event Arguments
- $15.RequiredSuffixes = $16
- $16.String = EventArgs
- $15.AffectedEntity = CustomEventArgs
- $15.VisibilityMask = VisibilityMask
- $15.NamingStyle = PascalCase
- $15.IncludeInstanceMembers = True
- $15.IncludeStaticEntities = True
- $17.Name = Exceptions
- $17.RequiredSuffixes = $18
- $18.String = Exception
- $17.AffectedEntity = CustomExceptions
- $17.VisibilityMask = VisibilityMask
- $17.NamingStyle = PascalCase
- $17.IncludeInstanceMembers = True
- $17.IncludeStaticEntities = True
- $19.Name = Methods
- $19.AffectedEntity = Methods
- $19.VisibilityMask = VisibilityMask
- $19.NamingStyle = PascalCase
- $19.IncludeInstanceMembers = True
- $19.IncludeStaticEntities = True
- $20.Name = Static Readonly Fields
- $20.AffectedEntity = ReadonlyField
- $20.VisibilityMask = Internal, Protected, Public
- $20.NamingStyle = PascalCase
- $20.IncludeInstanceMembers = False
- $20.IncludeStaticEntities = True
- $21.Name = Fields (Non Private)
- $21.AffectedEntity = Field
- $21.VisibilityMask = Internal, Protected, Public
- $21.NamingStyle = PascalCase
- $21.IncludeInstanceMembers = True
- $21.IncludeStaticEntities = True
- $22.Name = ReadOnly Fields (Non Private)
- $22.AffectedEntity = ReadonlyField
- $22.VisibilityMask = Internal, Protected, Public
- $22.NamingStyle = PascalCase
- $22.IncludeInstanceMembers = True
- $22.IncludeStaticEntities = False
- $23.Name = Fields (Private)
- $23.AllowedPrefixes = $24
- $24.String = m_
- $23.AffectedEntity = Field, ReadonlyField
- $23.VisibilityMask = Private
- $23.NamingStyle = CamelCase
- $23.IncludeInstanceMembers = True
- $23.IncludeStaticEntities = False
- $25.Name = Static Fields (Private)
- $25.AffectedEntity = Field
- $25.VisibilityMask = Private
- $25.NamingStyle = CamelCase
- $25.IncludeInstanceMembers = False
- $25.IncludeStaticEntities = True
- $26.Name = ReadOnly Fields (Private)
- $26.AllowedPrefixes = $27
- $27.String = m_
- $26.AffectedEntity = ReadonlyField
- $26.VisibilityMask = Private
- $26.NamingStyle = CamelCase
- $26.IncludeInstanceMembers = True
- $26.IncludeStaticEntities = False
- $28.Name = Constant Fields
- $28.AffectedEntity = ConstantField
- $28.VisibilityMask = VisibilityMask
- $28.NamingStyle = PascalCase
- $28.IncludeInstanceMembers = True
- $28.IncludeStaticEntities = True
- $29.Name = Properties
- $29.AffectedEntity = Property
- $29.VisibilityMask = VisibilityMask
- $29.NamingStyle = PascalCase
- $29.IncludeInstanceMembers = True
- $29.IncludeStaticEntities = True
- $30.Name = Events
- $30.AffectedEntity = Event
- $30.VisibilityMask = VisibilityMask
- $30.NamingStyle = PascalCase
- $30.IncludeInstanceMembers = True
- $30.IncludeStaticEntities = True
- $31.Name = Enum Members
- $31.AffectedEntity = EnumMember
- $31.VisibilityMask = VisibilityMask
- $31.NamingStyle = PascalCase
- $31.IncludeInstanceMembers = True
- $31.IncludeStaticEntities = True
- $32.Name = Parameters
- $32.AffectedEntity = Parameter
- $32.VisibilityMask = VisibilityMask
- $32.NamingStyle = CamelCase
- $32.IncludeInstanceMembers = True
- $32.IncludeStaticEntities = True
- $33.Name = Type Parameters
- $33.RequiredPrefixes = $34
- $34.String = T
- $33.AffectedEntity = TypeParameter
- $33.VisibilityMask = VisibilityMask
- $33.NamingStyle = PascalCase
- $33.IncludeInstanceMembers = True
- $33.IncludeStaticEntities = True
- $35.inheritsSet = null
- $35.scope = application/x-csproject
- $0.XmlFormattingPolicy = $40
- $36.inheritsSet = null
- $36.scope = application/x-csproject
- $37.inheritsSet = null
- $37.scope = application/x-msbuild
- $38.inheritsSet = null
- $38.scope = application/x-msbuild
- $39.inheritsSet = null
- $39.scope = application/xml
- $40.inheritsSet = Mono
- $40.inheritsScope = application/xml
- $40.scope = application/xml
- $0.VersionControlPolicy = $41
- $41.inheritsSet = Mono
- $0.ChangeLogPolicy = $42
- $42.UpdateMode = None
- $42.MessageStyle = $43
- $43.LineAlign = 0
- $42.inheritsSet = Mono
- version = 1.0.8.0
- outputpath = ..\..\GameData\SCANsat
- EndGlobalSection
-EndGlobal
diff --git a/SCANsat.slnx b/SCANsat.slnx
new file mode 100644
index 00000000..f31b42ab
--- /dev/null
+++ b/SCANsat.slnx
@@ -0,0 +1,213 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SCANsat/SCAN_Color_Config.cs b/SCANsat/SCAN_Color_Config.cs
index 97eca564..8c630e78 100644
--- a/SCANsat/SCAN_Color_Config.cs
+++ b/SCANsat/SCAN_Color_Config.cs
@@ -14,9 +14,6 @@
using System.Collections.Generic;
using SCANsat.SCAN_Data;
using SCANsat.SCAN_Platform;
-using SCANsat.SCAN_Palettes;
-using UnityEngine;
-using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
namespace SCANsat
{
diff --git a/SCANsat/SCAN_Data/SCANdata.cs b/SCANsat/SCAN_Data/SCANdata.cs
index 39715d47..c0d8ee1d 100644
--- a/SCANsat/SCAN_Data/SCANdata.cs
+++ b/SCANsat/SCAN_Data/SCANdata.cs
@@ -11,22 +11,19 @@
*/
#endregion
-using System;
-using System.Linq;
-using System.Collections.Generic;
-using UnityEngine;
using Contracts;
using FinePrint;
using FinePrint.Contracts;
using FinePrint.Contracts.Parameters;
-using FinePrint.Utilities;
-using System.IO;
-using System.Runtime.Serialization.Formatters.Binary;
using SCANsat.SCAN_Platform;
-using SCANsat.SCAN_Palettes;
using SCANsat.SCAN_Unity;
-using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
-using Log = KSPBuildTools.Log;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Runtime.Serialization.Formatters.Binary;
+using UnityEngine;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Data
{
@@ -37,7 +34,6 @@ public class SCANdata
/* MAP: state */
internal Int16[,] coverage;
private CelestialBody body;
- private SCANterrainConfig terrainConfig;
private bool mapBuilding, overlayBuilding, controllerBuilding, built;
private float[,] tempHeightMap;
@@ -56,38 +52,11 @@ internal SCANdata(CelestialBody b)
{
built = true;
}
-
- terrainConfig = SCANcontroller.getTerrainNode(b.bodyName);
-
- if (terrainConfig == null)
- {
- float? clamp = null;
- if (b.ocean)
- {
- clamp = 0;
- }
-
- float newMax;
-
- try
- {
- newMax = ((float)CelestialUtilities.GetHighestPeak(b)).Mathf_Round(-2);
- }
- catch (Exception e)
- {
- SCANUtil.SCANlog("Error in calculating Max Height for {0}; using default value\n{1}", b.displayName.LocalizeBodyName(), e);
- newMax = SCANconfigLoader.SCANNode.DefaultMaxHeightRange;
- }
-
- terrainConfig = new SCANterrainConfig(SCANconfigLoader.SCANNode.DefaultMinHeightRange, newMax, clamp, SCAN_Palette_Config.DefaultPalette.GetPalette(0), 7, false, false, body);
- SCANcontroller.addToTerrainConfigData(body.bodyName, terrainConfig);
- }
}
public SCANdata(SCANdata copy)
{
coverage = copy.coverage;
- terrainConfig = new SCANterrainConfig(copy.terrainConfig);
if (!heightMaps.ContainsKey(copy.body.flightGlobalsIndex))
{
@@ -135,12 +104,6 @@ public CelestialBody Body
get { return body; }
}
- public SCANterrainConfig TerrainConfig
- {
- get { return terrainConfig; }
- internal set { terrainConfig = value; }
- }
-
public bool Disabled
{
get { return disabled; }
@@ -914,6 +877,8 @@ internal void generateHeightMap(ref int step, ref int xStart, int width)
xStart += width;
}
+
+
#endregion
#region Map Utilities
diff --git a/SCANsat/SCAN_Data/SCANresourceGlobal.cs b/SCANsat/SCAN_Data/SCANresourceGlobal.cs
index 50338095..56db170d 100644
--- a/SCANsat/SCAN_Data/SCANresourceGlobal.cs
+++ b/SCANsat/SCAN_Data/SCANresourceGlobal.cs
@@ -17,7 +17,7 @@
using UnityEngine;
using SCANsat.SCAN_Platform;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Data
{
diff --git a/SCANsat/SCAN_Data/SCANterrainConfig.cs b/SCANsat/SCAN_Data/SCANterrainConfig.cs
index a1e39d18..02c6df7e 100644
--- a/SCANsat/SCAN_Data/SCANterrainConfig.cs
+++ b/SCANsat/SCAN_Data/SCANterrainConfig.cs
@@ -22,8 +22,6 @@ public class SCANterrainConfig : SCAN_ConfigNodeStorage
[Persistent]
private string name;
[Persistent]
- private int index;
- [Persistent]
private float minHeightRange;
[Persistent]
private float maxHeightRange;
@@ -80,7 +78,6 @@ internal SCANterrainConfig(float min, float max, float? clamp, SCANPalette color
paletteDiscrete = discrete;
body = b;
name = body.bodyName;
- index = body.flightGlobalsIndex;
setDefaultValues();
}
@@ -113,16 +110,6 @@ internal SCANterrainConfig(SCANterrainConfig copy)
public override void OnDecodeFromConfigNode()
{
- body = FlightGlobals.Bodies.FirstOrDefault(b => b.flightGlobalsIndex == index);
- if (body != null)
- {
- name = body.bodyName;
- }
- else
- {
- name = "WrongBody" + index;
- }
-
colorPal = SCANUtil.PaletteLoader(paletteName, paletteSize);
float tempClamp = 0;
diff --git a/SCANsat/SCAN_Map/SCANmap.cs b/SCANsat/SCAN_Map/SCANmap.cs
index cbf75931..6cf3545a 100644
--- a/SCANsat/SCAN_Map/SCANmap.cs
+++ b/SCANsat/SCAN_Map/SCANmap.cs
@@ -892,9 +892,6 @@ internal Texture2D getPartialMap(bool apply = true)
}
}
- Texture2D readableScaledSpaceMap = SCANcontroller.controller.getVisualMapTexture(body);
- Texture2D readableScaledSpaceNormalMap = SCANcontroller.controller.getVisualMapNormalTexture(body);
-
for (int i = 0; i < map.width; i++)
{
/* Introduce altimetry check here; Use unprojected lat/long coordinates
@@ -906,7 +903,7 @@ internal Texture2D getPartialMap(bool apply = true)
double cacheLat = ((mapstep + 1) * 1.0f / mapscale) - 90f + lat_offset;
double lon = (i * 1.0f / mapscale) - 180f + lon_offset;
- if (mType != mapType.Visual)
+ if (mType == mapType.Altimetry || mType == mapType.Slope)
{
if (body.pqsController != null && cache && mapstep + 1 < map.height)
{
@@ -1017,13 +1014,14 @@ internal Texture2D getPartialMap(bool apply = true)
else if (SCANUtil.isCovered(lon, lat, data, SCANtype.Altimetry))
{
projVal = terrainElevation(lon, lat, mapwidth, mapheight, big_heightmap, cache, data, out nowColor);
+
if (useCustomRange)
{
- baseColor = palette.heightToColor(projVal, nowColor, data.TerrainConfig, customMin, customMax, customRange, true);
+ baseColor = palette.heightToColor(projVal, nowColor, SCANUtil.getTerrainConfig(data), customMin, customMax, customRange, true);
}
else
{
- baseColor = palette.heightToColor(projVal, nowColor, data.TerrainConfig);
+ baseColor = palette.heightToColor(projVal, nowColor, SCANUtil.getTerrainConfig(data));
}
}
else
@@ -1122,7 +1120,7 @@ internal Texture2D getPartialMap(bool apply = true)
}
else
{
- elevation = palette.lerp(palette.Black, palette.White, Mathf.Clamp(projVal + (-1f * data.TerrainConfig.MinTerrain), 0, data.TerrainConfig.TerrainRange) / data.TerrainConfig.TerrainRange);
+ elevation = palette.lerp(palette.Black, palette.White, Mathf.Clamp(projVal + (-1f * SCANUtil.getTerrainConfig(data).MinTerrain), 0, SCANUtil.getTerrainConfig(data).TerrainRange) / SCANUtil.getTerrainConfig(data).TerrainRange);
}
}
}
@@ -1173,120 +1171,39 @@ internal Texture2D getPartialMap(bool apply = true)
break;
}
case mapType.Visual:
+ {
+ if (!SCANcontroller.controller.isVisualTextureLoaded(body))
{
- if (readableScaledSpaceMap == null)
- {
- baseColor = palette.lerp(palette.Black, palette.White, UnityEngine.Random.value);
- }
- else if (SCANUtil.isCovered(lon, lat, data, SCANtype.VisualHiRes))
- {
- float fLat = ((float)lat + 90f) / 180f;
- float fLon = ((float)lon + 270f) / 360f;
-
- if (fLon < 0)
- {
- fLon += 1;
- }
-
- if (fLon > 1)
- {
- fLon -= 1;
- }
-
- fLon = 1 - fLon;
-
- fLat = Mathf.Clamp01(fLat);
- fLon = Mathf.Clamp01(fLon);
-
- baseColor = readableScaledSpaceMap.GetPixelBilinear(fLon, fLat);
-
- if (readableScaledSpaceNormalMap != null)
- {
- HslColor hslBase = palette.ConvertRgbToHsl(baseColor);
-
- double opacity = 0.8;
-
- double lumOver = readableScaledSpaceNormalMap.GetPixelBilinear(fLon, fLat).b;
- double lum = hslBase.L;
+ baseColor = palette.lerp(palette.Black, palette.White, UnityEngine.Random.value);
+ break;
+ }
- if (colorMap)
- {
- if (lum > 0.5d)
- {
- lum = (opacity * (1 - (1 - (2 * (lumOver - 0.5))) * (1 - lum))) + (1 - opacity) * lum;
- }
- else
- {
- lum = (opacity * (2 * lumOver * lum)) + (1 - opacity) * lum;
- }
+ bool highResCovered = SCANUtil.isCovered(lon, lat, data, SCANtype.VisualHiRes);
+ bool lowResCovered = SCANUtil.isCovered(lon, lat, data, SCANtype.VisualLoRes);
- baseColor = palette.ConvertHslToRgb(hslBase.H, hslBase.S, lum);
- }
- else
- {
- if (lum > 0.5d)
- {
- lum = (1 - (1 - (2 * (lumOver - 0.5))) * (1 - lum));
- }
- else
- {
- lum = 2 * lumOver * lum;
- }
-
- baseColor = palette.ConvertToGrayscale(baseColor);
- }
- }
- }
- else if (SCANUtil.isCovered(lon, lat, data, SCANtype.VisualLoRes))
+ if (highResCovered || lowResCovered)
+ {
+ if (!highResCovered)
{
- float fLat = ((float)lat + 90f) / 180f;
- float fLon = ((float)lon + 270f) / 360f;
-
- if (fLon < 0)
- {
- fLon += 1;
- }
-
- if (fLon > 1)
- {
- fLon -= 1;
- }
-
- fLon = 1 - fLon;
-
- fLat = Mathf.Clamp01(fLat);
- fLon = Mathf.Clamp01(fLon);
-
- float width = readableScaledSpaceMap.width / (512f);
- float height = readableScaledSpaceMap.height / (256f);
-
- int ilon = Mathf.RoundToInt((int)(fLon * 512f) * width);
- int ilat = Mathf.RoundToInt((int)(fLat * 256f) * height);
-
- if (ilon > readableScaledSpaceMap.width)
- {
- ilon = readableScaledSpaceMap.width - 1;
- }
-
- if (ilat > readableScaledSpaceMap.height)
- {
- ilat = readableScaledSpaceMap.height - 1;
- }
+ // Scale data to create a 512 x 256 map of blocky, low-res pixels
+ lon = Mathf.RoundToInt((float)lon * 512) / 512;
+ lat = Mathf.RoundToInt((float)lat * 256) / 256;
+ }
- baseColor = readableScaledSpaceMap.GetPixel(ilon, ilat);
+ baseColor = SCANcontroller.controller.GetShadedVisualPixel(body, lon, lat);
- if (!colorMap)
- {
- baseColor = palette.ConvertToGrayscale(baseColor);
- }
- }
- else
+ if (!colorMap || !highResCovered)
{
- baseColor = unscanned;
+ baseColor = palette.ConvertToGrayscale(baseColor);
}
-
- break;
}
+ else
+ {
+ baseColor = unscanned;
+ }
+
+ break;
+ }
}
if (resourceOn)
diff --git a/SCANsat/SCAN_Map/SCANmapExporter.cs b/SCANsat/SCAN_Map/SCANmapExporter.cs
index 23eed94b..2cf98fdb 100644
--- a/SCANsat/SCAN_Map/SCANmapExporter.cs
+++ b/SCANsat/SCAN_Map/SCANmapExporter.cs
@@ -5,7 +5,7 @@
using UnityEngine;
using SCANsat.SCAN_Data;
using SCANsat.SCAN_Platform;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Map
{
@@ -71,7 +71,7 @@ public void exportPNG(SCANmap map, SCANdata data)
ScreenMessages.PostScreenMessage("SCANsat Map saved: GameData/SCANsat/PluginData/" + filename, 8, ScreenMessageStyle.UPPER_CENTER);
- SCANUtil.SCANlog("Map of [{0}] saved\nMap Size: {1} X {2}\nMinimum Altitude: {3:F0}m; Maximum Altitude: {4:F0}m\nPixel Width At Equator: {5:F6}m", map.Body.displayName.LocalizeBodyName(), map.Map.width, map.Map.height, data.TerrainConfig.MinTerrain, data.TerrainConfig.MaxTerrain, (map.Body.Radius * 2 * Math.PI) / (map.Map.width * 1f));
+ SCANUtil.SCANlog("Map of [{0}] saved\nMap Size: {1} X {2}\nMinimum Altitude: {3:F0}m; Maximum Altitude: {4:F0}m\nPixel Width At Equator: {5:F6}m", map.Body.displayName.LocalizeBodyName(), map.Map.width, map.Map.height, SCANUtil.getTerrainConfig(data).MinTerrain, SCANUtil.getTerrainConfig(data).MaxTerrain, (map.Body.Radius * 2 * Math.PI) / (map.Map.width * 1f));
if (SCAN_Settings_Config.Instance.ExportCSV && map.MType == mapType.Altimetry)
{
diff --git a/SCANsat/SCAN_Map/SCANmapLegend.cs b/SCANsat/SCAN_Map/SCANmapLegend.cs
index 34bf08f0..40de0cf4 100644
--- a/SCANsat/SCAN_Map/SCANmapLegend.cs
+++ b/SCANsat/SCAN_Map/SCANmapLegend.cs
@@ -17,6 +17,7 @@
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
using UnityEngine;
+using System.Collections.Generic;
namespace SCANsat.SCAN_Map
{
@@ -100,67 +101,28 @@ public Texture2D getLegend(SCANdata data, bool color, bool stock, CBAttributeMap
Color32[] pix = new Color32[256];
int count = biomes.Length;
-
- int blockSize = (int)Math.Truncate(256 / (count * 1d));
-
- int total = 0;
-
- for (int i = 0; i < count; i++)
+ for (int biome_idx = 0; biome_idx < count; biome_idx++)
{
- for (int j = 0; j < blockSize; j++)
- {
- if (total >= 256)
- {
- break;
- }
-
- int current = i * blockSize + j;
+ int start = (int)Math.Round(biome_idx * 256 / (count * 1d));
+ int end = (int)Math.Round((biome_idx + 1) * 256 / (count * 1d));
+ for (int i = start; i < end; i++)
+ {
if (stock && color)
{
- pix[current] = biomes[i].mapColor;
+ pix[i] = biomes[biome_idx].mapColor;
}
else if (color)
{
- pix[current] = palette.lerp(SCANcontroller.controller.lowBiomeColor32, SCANcontroller.controller.highBiomeColor32, (float)((i * 1f) / (count * 1f)));
+ pix[i] = palette.lerp(SCANcontroller.controller.lowBiomeColor32, SCANcontroller.controller.highBiomeColor32, (float)((biome_idx * 1f) / (count * 1f)));
}
else
{
- pix[current] = palette.lerp(palette.Black, palette.White, (float)(i * 1f) / (count * 1f));
+ pix[i] = palette.lerp(palette.Black, palette.White, (float)(biome_idx * 1f) / (count * 1f));
}
-
- total++;
}
}
- int remaining = 256 - count * blockSize;
- int backCount = remaining;
-
- for (int i = 0; i < remaining; i++)
- {
- if (total > 256 || backCount <= 0)
- {
- break;
- }
-
- if (SCAN_Settings_Config.Instance.BigMapStockBiomes && color)
- {
- pix[256 - backCount] = biomes[count - 1].mapColor;
- }
- else if (color)
- {
- pix[256 - backCount] = palette.lerp(SCANcontroller.controller.lowBiomeColor32, SCANcontroller.controller.highBiomeColor32, (float)(((count - 1) * 1f) / (count * 1f)));
- }
- else
- {
- pix[256 - backCount] = palette.lerp(palette.Black, palette.White, (float)(((count - 1) * 1f) / (count * 1f)));
- }
-
- backCount--;
-
- total++;
- }
-
legend.SetPixels32(pix);
legend.Apply();
return legend;
@@ -193,5 +155,39 @@ public static Texture2D getStaticLegend(float max, float min, float range, float
t.Apply();
return t;
}
+
+ /// For a given min and max terrain height, generate a set of label strings to 2 significant figures precision between max and min. Used in Big and Zoom maps to display total range.
+ ///
+ /// Value in Minimum Label
+ /// Value in Maximum Label
+ /// IList containing the three legend labels to display.
+ public static IList LegendLabels(double terrainMin, double terrainMax)
+ {
+ int digits = (int)Math.Floor(Math.Log10(terrainMax - terrainMin));
+ int round = (int)Math.Pow(10, digits - 1);
+
+ string one = string.Format("|\n{0}", (((int)Math.Round(terrainMin / round)) * round).ToString("N0"));
+
+ string two = string.Format("|\n{0}", (((int)Math.Round(((terrainMin + terrainMax) / 2) / round)) * round).ToString("N0"));
+
+ string three = string.Format("|\n{0}", (((int)Math.Round(terrainMax / round)) * round).ToString("N0"));
+
+ return new List(3) { one, two, three };
+ }
+
+ ///
+ /// For a given SCANterrainConfig, generate a set of label strings to 3 significant figures precision. Used in Big and Zoom maps to display total range.
+ ///
+ /// SCANterrainConfig instance for a celestial body
+ /// IList containing the three legend labels to display.
+ public static IList LegendLabels(SCANterrainConfig config)
+ {
+ if (config == null)
+ {
+ return null;
+ }
+
+ return LegendLabels(config.MinTerrain, config.MaxTerrain);
+ }
}
-}
+}
\ No newline at end of file
diff --git a/SCANsat/SCAN_PartModules/SCANsat.cs b/SCANsat/SCAN_PartModules/SCANsat.cs
index ed6e4b3c..1903be86 100644
--- a/SCANsat/SCAN_PartModules/SCANsat.cs
+++ b/SCANsat/SCAN_PartModules/SCANsat.cs
@@ -23,7 +23,7 @@
using UnityEngine;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_PartModules
{
diff --git a/SCANsat/SCAN_Platform/Extensions/ConfigNodes/ConfigExtensions.cs b/SCANsat/SCAN_Platform/Extensions/ConfigNodes/ConfigExtensions.cs
index 3cab8e8c..d84e994b 100644
--- a/SCANsat/SCAN_Platform/Extensions/ConfigNodes/ConfigExtensions.cs
+++ b/SCANsat/SCAN_Platform/Extensions/ConfigNodes/ConfigExtensions.cs
@@ -2,7 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Platform.Extensions.ConfigNodes
{
diff --git a/SCANsat/SCAN_Platform/Logging.cs b/SCANsat/SCAN_Platform/Logging.cs
index 76295b40..12fe087b 100644
--- a/SCANsat/SCAN_Platform/Logging.cs
+++ b/SCANsat/SCAN_Platform/Logging.cs
@@ -1,5 +1,5 @@
using System;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
// TODO: remove this file and fixup references to call KSPBuildTools.Log directly
diff --git a/SCANsat/SCAN_Reflection/SCANkopernicus.cs b/SCANsat/SCAN_Reflection/SCANkopernicus.cs
index 45c5254c..8c35c382 100644
--- a/SCANsat/SCAN_Reflection/SCANkopernicus.cs
+++ b/SCANsat/SCAN_Reflection/SCANkopernicus.cs
@@ -15,7 +15,7 @@
using System.Linq;
using System.Reflection;
using UnityEngine;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Reflection
{
diff --git a/SCANsat/SCAN_Reflection/SCANparallaxContinued.cs b/SCANsat/SCAN_Reflection/SCANparallaxContinued.cs
index 803ef84f..a517d6eb 100644
--- a/SCANsat/SCAN_Reflection/SCANparallaxContinued.cs
+++ b/SCANsat/SCAN_Reflection/SCANparallaxContinued.cs
@@ -2,7 +2,7 @@
using System.Linq;
using System.Reflection;
using UnityEngine;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Reflection
{
diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANcolorUtil.cs b/SCANsat/SCAN_UI/UI_Framework/SCANcolorUtil.cs
index 3fc24d36..73f4e970 100644
--- a/SCANsat/SCAN_UI/UI_Framework/SCANcolorUtil.cs
+++ b/SCANsat/SCAN_UI/UI_Framework/SCANcolorUtil.cs
@@ -162,6 +162,10 @@ public static Color32 combineColors(Color32[] colors)
public static Color32 heightToColor(float val, bool color, SCANterrainConfig terrain, float min = 0, float max = 0, float range = 0, bool useCustomRange = false)
{
+ if (terrain == null)
+ {
+ return lerp(Black, White, UnityEngine.Random.value);
+ }
Color32[] c = terrain.ColorPal.ColorsArray;
if (terrain.PalRev)
{
diff --git a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs
index e737f511..5eb3fb7b 100644
--- a/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs
+++ b/SCANsat/SCAN_UI/UI_Framework/SCANuiUtil.cs
@@ -19,7 +19,6 @@
using SCANsat.SCAN_Data;
using SCANsat.SCAN_Map;
using SCANsat.SCAN_Unity;
-using SCANsat.SCAN_UI.UI_Framework;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
using UnityEngine;
@@ -967,7 +966,7 @@ internal static void drawTerrainMap(ref Color32[] pix, ref float[,] values, SCAN
{
if (SCANUtil.isCovered(lon, lat, data, SCANtype.AltimetryHiRes))
{
- c = palette.heightToColor(values[i, j], true, data.TerrainConfig);
+ c = palette.heightToColor(values[i, j], true, SCANUtil.getTerrainConfig(data));
}
else
{
@@ -975,7 +974,7 @@ internal static void drawTerrainMap(ref Color32[] pix, ref float[,] values, SCAN
int ilat = SCANUtil.icLAT(lat);
int lo = ((int)(ilon * scale * 5)) / 5;
int la = ((int)(ilat * scale * 5)) / 5;
- c = palette.heightToColor(values[lo, la], false, data.TerrainConfig);
+ c = palette.heightToColor(values[lo, la], false, SCANUtil.getTerrainConfig(data));
}
c = palette.lerp(c, palette.Clear, 0.1f);
@@ -1189,11 +1188,11 @@ internal static Texture2D drawLoDetailMap(ref Color32[] pix, ref float[,] values
{
if (map.UseCustomRange)
{
- pix[j * width + i] = palette.heightToColor(values[i, j], true, data.TerrainConfig, map.CustomMin, map.CustomMax, map.CustomRange, true);
+ pix[j * width + i] = palette.heightToColor(values[i, j], true, SCANUtil.getTerrainConfig(data), map.CustomMin, map.CustomMax, map.CustomRange, true);
}
else
{
- pix[j * width + i] = palette.heightToColor(values[i, j], true, data.TerrainConfig);
+ pix[j * width + i] = palette.heightToColor(values[i, j], true, SCANUtil.getTerrainConfig(data));
}
}
}
diff --git a/SCANsat/SCAN_Unity/SCAN_UI_BigMap.cs b/SCANsat/SCAN_Unity/SCAN_UI_BigMap.cs
index df9fe220..835f7990 100644
--- a/SCANsat/SCAN_Unity/SCAN_UI_BigMap.cs
+++ b/SCANsat/SCAN_Unity/SCAN_UI_BigMap.cs
@@ -1780,11 +1780,11 @@ public Texture2D LegendImage
switch (bigmap.MType)
{
case mapType.Altimetry:
- return bigmap.MapLegend.getLegend(SCANcontroller.controller.bigMapColor, data.TerrainConfig);
+ return bigmap.MapLegend.getLegend(SCANcontroller.controller.bigMapColor, SCANUtil.getTerrainConfig(data));
case mapType.Biome:
if (body != null && body.BiomeMap != null && body.BiomeMap.Attributes != null)
{
- return bigmap.MapLegend.getLegend(data, SCANcontroller.controller.bigMapColor, SCAN_Settings_Config.Instance.BigMapStockBiomes, body.BiomeMap.Attributes);
+ return bigmap.MapLegend.getLegend(data, SCANcontroller.controller.bigMapColor, SCAN_Settings_Config.Instance.BigMapStockBiomes, SCANUtil.GetOrBuildPalette(body));
}
else
{
@@ -1963,18 +1963,7 @@ public IList LegendLabels
{
get
{
- if (data == null)
- {
- return null;
- }
-
- string one = string.Format("|\n{0}", (((int)(data.TerrainConfig.MinTerrain / 100)) * 100).ToString("N0"));
-
- string two = string.Format("|\n{0}", (((int)((data.TerrainConfig.MinTerrain + (data.TerrainConfig.TerrainRange / 2)) / 100)) * 100).ToString("N0"));
-
- string three = string.Format("|\n{0}", (((int)(data.TerrainConfig.MaxTerrain / 100)) * 100).ToString("N0"));
-
- return new List(3) { one, two, three };
+ return SCANmapLegend.LegendLabels(SCANUtil.getTerrainConfig(body));
}
}
@@ -2459,7 +2448,7 @@ public string TooltipText(float xPos)
return Localizer.Format(body.BiomeMap.Attributes[current].displayname);
case mapType.Altimetry:
- float terrain = xPos * data.TerrainConfig.TerrainRange + data.TerrainConfig.MinTerrain;
+ float terrain = xPos * SCANUtil.getTerrainConfig(data).TerrainRange + SCANUtil.getTerrainConfig(data).MinTerrain;
return string.Format("{0}m", terrain.ToString("N0"));
}
diff --git a/SCANsat/SCAN_Unity/SCAN_UI_Color.cs b/SCANsat/SCAN_Unity/SCAN_UI_Color.cs
index 77d5301e..4f7d65d6 100644
--- a/SCANsat/SCAN_Unity/SCAN_UI_Color.cs
+++ b/SCANsat/SCAN_Unity/SCAN_UI_Color.cs
@@ -122,7 +122,7 @@ public void Refresh()
_resourceTransparency = currentResource.Transparency;
}
- currentTerrain = SCANcontroller.getTerrainNode(_terrainPlanet);
+ currentTerrain = SCANUtil.getTerrainConfig(_terrainPlanet);
if (currentTerrain != null)
{
@@ -211,7 +211,7 @@ public string TerrainPlanet
_terrainPlanet = body;
- currentTerrain = SCANcontroller.getTerrainNode(body);
+ currentTerrain = SCANUtil.getTerrainConfig(body);
if (currentTerrain != null)
{
@@ -690,7 +690,7 @@ public void BiomeApply(Color one, Color two)
SCAN_UI_BigMap.Instance.RefreshMap();
}
- if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType)
+ if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType == MainMapDisplayMode.Biome)
{
SCAN_UI_MainMap.Instance.resetImages();
}
@@ -727,7 +727,7 @@ public void BiomeDefault()
SCAN_UI_BigMap.Instance.RefreshMap();
}
- if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType)
+ if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType == MainMapDisplayMode.Biome)
{
SCAN_UI_MainMap.Instance.resetImages();
}
@@ -944,7 +944,7 @@ public void TerrainApply()
SCAN_UI_BigMap.Instance.RefreshMap();
}
- if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && !SCAN_UI_MainMap.Instance.MapType)
+ if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType == MainMapDisplayMode.Terrain)
{
SCAN_UI_MainMap.Instance.resetImages();
}
@@ -979,7 +979,7 @@ public void TerrainDefault()
SCAN_UI_BigMap.Instance.RefreshMap();
}
- if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && !SCAN_UI_MainMap.Instance.MapType)
+ if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType == MainMapDisplayMode.Terrain)
{
SCAN_UI_MainMap.Instance.resetImages();
}
@@ -1013,7 +1013,7 @@ public void TerrainSaveToConfig()
SCAN_UI_BigMap.Instance.RefreshMap();
}
- if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && !SCAN_UI_MainMap.Instance.MapType)
+ if (SCAN_UI_MainMap.Instance != null && SCAN_UI_MainMap.Instance.IsVisible && SCAN_UI_MainMap.Instance.MapType == MainMapDisplayMode.Terrain)
{
SCAN_UI_MainMap.Instance.resetImages();
}
diff --git a/SCANsat/SCAN_Unity/SCAN_UI_MainMap.cs b/SCANsat/SCAN_Unity/SCAN_UI_MainMap.cs
index 5591a156..ffe870c3 100644
--- a/SCANsat/SCAN_Unity/SCAN_UI_MainMap.cs
+++ b/SCANsat/SCAN_Unity/SCAN_UI_MainMap.cs
@@ -11,17 +11,17 @@
*/
#endregion
-using System;
-using System.Collections.Generic;
-using System.Text;
-using UnityEngine;
+using KSP.UI;
+using SCANsat.SCAN_Data;
+using SCANsat.SCAN_Map;
using SCANsat.SCAN_Toolbar;
-using SCANsat.Unity.Interfaces;
+using SCANsat.SCAN_UI.UI_Framework;
using SCANsat.Unity;
+using SCANsat.Unity.Interfaces;
using SCANsat.Unity.Unity;
-using SCANsat.SCAN_Data;
-using SCANsat.SCAN_UI.UI_Framework;
-using KSP.UI;
+using System;
+using System.Collections.Generic;
+using UnityEngine;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
namespace SCANsat.SCAN_Unity
@@ -108,6 +108,7 @@ private void soiChange(GameEvents.HostedFromToAction VC)
v = FlightGlobals.ActiveVessel;
data = SCANUtil.getData(v.mainBody);
+ SCANcontroller.controller.LoadVisualMapTexture_Renamed(v.mainBody, mapSource.Data);
if (data == null)
{
@@ -138,6 +139,7 @@ private void RefreshAfterVesselChanged()
// TODO: make this smarter about not doing work if it doesn't need to
data = SCANUtil.getData(v.mainBody);
+ SCANcontroller.controller.LoadVisualMapTexture_Renamed(v.mainBody, mapSource.Data);
if (data == null)
{
@@ -183,24 +185,12 @@ public void Update()
sensors = SCANcontroller.controller.activeSensorsOnVessel(v.id, false);
- if (!SCANcontroller.controller.mainMapBiome)
+ if (SCAN_Settings_Config.Instance.MapGenerationSpeed > 1)
{
- if (SCAN_Settings_Config.Instance.MapGenerationSpeed > 1)
- {
- drawPartialMap(sensors, false);
- }
-
- drawPartialMap(sensors, true);
+ drawPartialMap(SCANcontroller.controller.mainMapDisplayMode, false);
}
- else
- {
- if (SCAN_Settings_Config.Instance.MapGenerationSpeed > 1)
- {
- drawBiomeMap(sensors, false);
- }
- drawBiomeMap(sensors, true);
- }
+ drawPartialMap(SCANcontroller.controller.mainMapDisplayMode, true);
lastUpdate++;
@@ -402,6 +392,7 @@ public void Open()
v = FlightGlobals.ActiveVessel;
data = SCANUtil.getData(v.mainBody);
+ SCANcontroller.controller.LoadVisualMapTexture_Renamed(v.mainBody, mapSource.Data);
if (data == null)
{
@@ -515,12 +506,12 @@ public bool TerminatorToggle
}
}
- public bool MapType
+ public MainMapDisplayMode MapType
{
- get { return SCANcontroller.controller.mainMapBiome; }
+ get { return SCANcontroller.controller.mainMapDisplayMode; }
set
{
- SCANcontroller.controller.mainMapBiome = value;
+ SCANcontroller.controller.mainMapDisplayMode = value;
resetImages();
}
@@ -811,7 +802,7 @@ public string VesselInfo(Guid id)
float lat = (float)SCANUtil.fixLatShift(ves.latitude);
string units = "";
- if (SCANcontroller.controller.mainMapBiome)
+ if (SCANcontroller.controller.mainMapDisplayMode == MainMapDisplayMode.Biome)
{
if (SCANUtil.isCovered(lon, lat, data, SCANtype.Biome))
{
@@ -852,9 +843,15 @@ public string VesselInfo(Guid id)
return string.Format("({0}°,{1}°{2})", lat.ToString("F1"), lon.ToString("F1"), units);
}
- private void drawPartialMap(SCANtype type, bool apply)
+ private void drawPartialMap(MainMapDisplayMode display, bool apply)
{
bool pqsController = data.Body.pqsController != null;
+ bool biomeMap = data.Body.BiomeMap != null;
+
+ if (biomeBuilding && biomeMap && display == MainMapDisplayMode.Biome)
+ {
+ buildBiomeCache();
+ }
if (data.ControllerBuilding || data.OverlayBuilding)
{
@@ -901,30 +898,7 @@ private void drawPartialMap(SCANtype type, bool apply)
continue;
}
- Color32 c = palette.Grey;
- float val = data.HeightMapValue(data.Body.flightGlobalsIndex, ilon, scanline);
- if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.Altimetry))
- {
- if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.AltimetryHiRes))
- {
- c = palette.heightToColor(val, Color, data.TerrainConfig);
- }
- else
- {
- c = palette.heightToColor(val, false, data.TerrainConfig);
- }
- }
- else
- {
- if (scanline % 30 == 0 && ilon % 3 == 0)
- {
- c = palette.White;
- }
- else if (ilon % 30 == 0 && scanline % 3 == 0)
- {
- c = palette.White;
- }
- }
+ Color32 c = getMapPixelColor(display, scanline, ilon);
if (TerminatorToggle)
{
@@ -945,16 +919,6 @@ private void drawPartialMap(SCANtype type, bool apply)
}
}
}
- else
- {
- if (type != SCANtype.Nothing)
- {
- if (!SCANUtil.isCoveredByAll(ilon, scanline, data, type))
- {
- c = palette.lerp(c, palette.Black, 0.5f);
- }
- }
- }
cols_height_map_small[ilon] = c;
}
@@ -982,102 +946,85 @@ private void drawPartialMap(SCANtype type, bool apply)
}
}
- private void drawBiomeMap(SCANtype type, bool apply)
+ private Color32 getMapPixelColor(MainMapDisplayMode display, int scanline, int ilon)
{
+ bool pqsController = data.Body.pqsController != null;
bool biomeMap = data.Body.BiomeMap != null;
-
- if (biomeBuilding && biomeMap)
- {
- buildBiomeCache();
- }
-
- if (scanline == 0 && TerminatorToggle)
- {
- double sunLon = data.Body.GetLongitude(Planetarium.fetch.Sun.position, false);
- double sunLat = data.Body.GetLatitude(Planetarium.fetch.Sun.position, false);
-
- sunLatCenter = SCANUtil.fixLatShift(sunLat);
-
- if (sunLatCenter >= 0)
- {
- sunLonCenter = SCANUtil.fixLonShift(sunLon + 90);
- }
- else
- {
- sunLonCenter = SCANUtil.fixLonShift(sunLon - 90);
- }
-
- gamma = Math.Abs(sunLatCenter) < 0.55 ? 100 : Math.Tan(Mathf.Deg2Rad * (90 - Math.Abs(sunLatCenter)));
- }
-
- for (int ilon = 0; ilon < 360; ilon++)
+ Color32 c = palette.Grey;
+ switch (display)
{
- if (!biomeMap)
- {
- cols_height_map_small[ilon] = palette.lerp(palette.black, palette.white, UnityEngine.Random.value);
- continue;
- }
-
- Color32 c = biomeCache[scanline * 360 + ilon];
- if (!SCANUtil.isCovered(ilon, scanline, data, SCANtype.Biome))
- {
- c = palette.Grey;
- }
-
- if (TerminatorToggle)
- {
- double crossingLat = Math.Atan(gamma * Math.Sin(Mathf.Deg2Rad * (ilon - 180) - Mathf.Deg2Rad * sunLonCenter));
-
- if (sunLatCenter >= 0)
+ case MainMapDisplayMode.Terrain:
+ if (!pqsController)
{
- if (scanline - 90 < crossingLat * Mathf.Rad2Deg)
- {
- c = palette.lerp(c, palette.Black, 0.5f);
- }
+ c = palette.lerp(palette.black, palette.white, UnityEngine.Random.value);
}
- else
+ else if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.Altimetry))
{
- if (scanline - 90 > crossingLat * Mathf.Rad2Deg)
+ float val = data.HeightMapValue(data.Body.flightGlobalsIndex, ilon, scanline);
+ if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.AltimetryHiRes))
{
- c = palette.lerp(c, palette.Black, 0.5f);
+ c = palette.heightToColor(val, Color, SCANUtil.getTerrainConfig(data));
}
- }
- }
- else
- {
- if (type != SCANtype.Nothing)
- {
- if (!SCANUtil.isCoveredByAll(ilon, scanline, data, type))
+ else
{
- c = palette.lerp(c, palette.Black, 0.5f);
+ c = palette.heightToColor(val, false, SCANUtil.getTerrainConfig(data));
}
+ return c;
}
- }
+ break;
- cols_height_map_small[ilon] = c;
- }
+ case MainMapDisplayMode.Biome:
+ if (!biomeMap)
+ {
+ c = palette.lerp(palette.black, palette.white, UnityEngine.Random.value);
+ }
+ else if (SCANUtil.isCovered(ilon, scanline, data, SCANtype.Biome))
+ {
+ c = biomeCache[scanline * 360 + ilon];
+ return c;
+ }
+ break;
- map_small.SetPixels32(0, scanline, 360, 1, cols_height_map_small);
+ case MainMapDisplayMode.Visual:
- if (apply)
- {
- if (scanline < 179)
- {
- map_small.SetPixels32(0, scanline + 1, 360, 1, palette.small_redline);
- }
- }
+ if (!SCANcontroller.controller.isVisualTextureLoaded(data.Body))
+ {
+ c = palette.lerp(palette.black, palette.white, UnityEngine.Random.value);
+ break;
+ }
- scanline++;
+ bool highResCovered = SCANUtil.isCovered(ilon, scanline, data, SCANtype.VisualHiRes);
+ bool lowResCovered = SCANUtil.isCovered(ilon, scanline, data, SCANtype.VisualLoRes);
- if (apply || scanline >= 180)
- {
- map_small.Apply();
+ if (highResCovered || lowResCovered)
+ {
+ double lat = scanline - 90;
+ double lon = ilon - 180;
+
+ if (highResCovered || lowResCovered)
+ {
+ c = SCANcontroller.controller.GetShadedVisualPixel(data.Body, lon, lat);
+
+ if (!highResCovered)
+ {
+ c = palette.ConvertToGrayscale(c); // Default to grayscale for low res
+ }
+ }
+
+ return c;
+ }
+ break;
}
- if (scanline >= 180)
+ if (scanline % 30 == 0 && ilon % 3 == 0)
{
- scanline = 0;
+ c = palette.White;
+ }
+ else if (ilon % 30 == 0 && scanline % 3 == 0)
+ {
+ c = palette.White;
}
+ return c;
}
private void buildBiomeCache()
@@ -1130,7 +1077,7 @@ internal void resetImages()
map_small.Apply();
- if (SCANcontroller.controller.mainMapBiome)
+ if (SCANcontroller.controller.mainMapDisplayMode == MainMapDisplayMode.Biome)
{
biomeBuilding = true;
scanline = 0;
diff --git a/SCANsat/SCAN_Unity/SCAN_UI_Overlay.cs b/SCANsat/SCAN_Unity/SCAN_UI_Overlay.cs
index f1b089b9..bd0c5dc7 100644
--- a/SCANsat/SCAN_Unity/SCAN_UI_Overlay.cs
+++ b/SCANsat/SCAN_Unity/SCAN_UI_Overlay.cs
@@ -26,7 +26,7 @@
using SCANsat.SCAN_UI.UI_Framework;
using KSP.UI;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat.SCAN_Unity
{
diff --git a/SCANsat/SCAN_Unity/SCAN_UI_ZoomMap.cs b/SCANsat/SCAN_Unity/SCAN_UI_ZoomMap.cs
index 9b489ed8..1ccaf601 100644
--- a/SCANsat/SCAN_Unity/SCAN_UI_ZoomMap.cs
+++ b/SCANsat/SCAN_Unity/SCAN_UI_ZoomMap.cs
@@ -1633,7 +1633,7 @@ public Texture2D LegendImage
switch (spotmap.MType)
{
case mapType.Altimetry:
- return spotmap.MapLegend.getLegend(SCANcontroller.controller.zoomMapColor, data.TerrainConfig);
+ return spotmap.MapLegend.getLegend(SCANcontroller.controller.zoomMapColor, SCANUtil.getTerrainConfig(data));
case mapType.Biome:
if (body != null && body.BiomeMap != null && body.BiomeMap.Attributes != null)
{
@@ -1747,18 +1747,7 @@ public IList LegendLabels
{
get
{
- if (data == null)
- {
- return null;
- }
-
- string one = string.Format("|\n{0}", (((int)(terrainMin / 100)) * 100).ToString("N0"));
-
- string two = string.Format("|\n{0}", (((int)((terrainMin + ((terrainMax - terrainMin) / 2)) / 100)) * 100).ToString("N0"));
-
- string three = string.Format("|\n{0}", (((int)(terrainMax / 100)) * 100).ToString("N0"));
-
- return new List(3) { one, two, three };
+ return SCANmapLegend.LegendLabels(terrainMin, terrainMax);
}
}
diff --git a/SCANsat/SCANcontroller.cs b/SCANsat/SCANcontroller.cs
index 0f8f4243..649bb124 100644
--- a/SCANsat/SCANcontroller.cs
+++ b/SCANsat/SCANcontroller.cs
@@ -12,31 +12,346 @@
*/
#endregion
-using System;
-using System.Linq;
-using System.Collections;
-using System.Collections.Generic;
-using System.IO;
-using UnityEngine;
-using UnityEngine.Events;
using Contracts;
using FinePrint.Contracts;
-using FinePrint.Utilities;
-using SCANsat.SCAN_UI.UI_Framework;
-using SCANsat.SCAN_Unity;
+using FinePrint.Contracts.Parameters;
+using KSPTextureLoader;
using SCANsat.SCAN_Data;
using SCANsat.SCAN_Map;
using SCANsat.SCAN_Platform.Extensions.ConfigNodes;
-using SCANsat.SCAN_Palettes;
+using SCANsat.SCAN_Reflection;
using SCANsat.SCAN_Toolbar;
+using SCANsat.SCAN_UI.UI_Framework;
+using SCANsat.SCAN_Unity;
+using SCANsat.Unity.Interfaces;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using UnityEngine.Events;
+using Log = KSPCommunityLib.Logging.Log;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
-using FinePrint.Contracts.Parameters;
-using UnityEngine.Profiling;
-using Log = KSPBuildTools.Log;
-using SCANsat.SCAN_Reflection;
namespace SCANsat
{
+ public class SCANtextures
+ {
+ /* Game Loaded Data */
+ public CelestialBody body;
+ public Texture2D cachedVisualMap = null;
+ public Texture2D cachedNormalMap = null;
+
+ /* Memory Mapped Data (requires SCANSAT_BODY_TEXTURES config) */
+ public CPUTexture2D memoryMappedHeightMap = null;
+ public CPUTexture2D memoryMappedNormalMap = null;
+ public CPUTexture2D memoryMappedVisualMap = null;
+
+ public SCANtextures(CelestialBody b)
+ {
+ body = b;
+
+ ConfigNode[] visualOverrides = GameDatabase.Instance.GetConfigNodes("SCANSAT_BODY_TEXTURES");
+
+ for (int i = 0; i < visualOverrides.Length; i++)
+ {
+ ConfigNode node = visualOverrides[i];
+ if (node.HasValue("name"))
+ {
+ string bodyName = node.GetValue("name");
+ if (bodyName == b.name)
+ {
+ GetMemoryMappedTexturesFromConfig(node);
+ break;
+ }
+ }
+ }
+
+ CacheMapTexturesFromBody();
+ SCANUtil.SCANlog(TextureState()); // Log whether using memory mapped or RAM buffered textures
+ }
+
+ private Texture2D readableTexture(Texture tex, Material mat)
+ {
+ if (tex == null)
+ {
+ return null;
+ }
+
+ Texture2D readable = new Texture2D(tex.width, tex.height);
+
+ var rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB, 1);
+
+ if (mat != null)
+ {
+ Graphics.Blit(tex, rt, mat);
+ }
+ else
+ {
+ Graphics.Blit(tex, rt);
+ }
+
+ RenderTexture.active = rt;
+
+ readable.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
+
+ RenderTexture.active = null;
+ RenderTexture.ReleaseTemporary(rt);
+
+ rt = null;
+
+ readable.Apply();
+
+ tex = null;
+
+ return readable;
+ }
+
+ public void GetMemoryMappedTexturesFromConfig(ConfigNode node)
+ {
+ string bodyName = node.GetValue("name");
+ if (bodyName == body.name)
+ {
+ string baseFolder = System.IO.Directory.GetParent(KSPUtil.ApplicationRootPath).FullName;
+
+ // Attempt to load heightMap
+ string heightMapPath = node.GetValue("heightMap");
+ if (memoryMappedHeightMap == null && heightMapPath != null)
+ {
+ string heightMapCPUTextureName = (baseFolder + '/' + heightMapPath).Replace("\\", "/");
+ CPUTextureHandle heightMap = TextureLoader.LoadCPUTexture(heightMapCPUTextureName);
+ try
+ {
+ memoryMappedHeightMap = heightMap.GetTexture();
+ }
+ catch (Exception e)
+ {
+ Log.Error($"[{body.name}] Height Map Path not defined: {heightMapCPUTextureName}");
+ Log.Exception(e);
+ }
+ }
+
+ // Attempt to load normalMap
+ string normalMapPath = node.GetValue("normalMap");
+ if (memoryMappedNormalMap == null && normalMapPath != null)
+ {
+ string normalMapCPUTextureName = (baseFolder + '/' + normalMapPath).Replace("\\", "/");
+ CPUTextureHandle normalMap = TextureLoader.LoadCPUTexture(normalMapCPUTextureName);
+ try
+ {
+ memoryMappedNormalMap = normalMap.GetTexture();
+ }
+ catch (Exception e)
+ {
+ Log.Error($"[{body.name}] Normal Map Path not defined: {normalMapCPUTextureName}");
+ Log.Exception(e);
+ }
+ }
+
+ // Attempt to load colorMap
+ string visualMapPath = node.GetValue("colorMap");
+ if (memoryMappedVisualMap == null && visualMapPath != null)
+ {
+ string colorMapCPUTextureName = (baseFolder + '/' + visualMapPath).Replace("\\", "/");
+ CPUTextureHandle colorMap = TextureLoader.LoadCPUTexture(colorMapCPUTextureName);
+ try
+ {
+ memoryMappedVisualMap = colorMap.GetTexture();
+ }
+ catch (Exception e)
+ {
+ Log.Error($"[{body.name}] Visual Data path not loaded: {colorMapCPUTextureName}");
+ Log.Exception(e);
+ }
+ }
+ }
+ }
+
+ public void CacheMapTexturesFromBody()
+ {
+ Material material = null;
+ string colorMapTextureName = null;
+ string normalMapTextureName = null;
+ bool useMaterialForColorMap = true;
+
+ if (body.scaledBody == null)
+ {
+ return;
+ }
+
+ MeshRenderer scaledMesh = body.scaledBody.GetComponent();
+
+ if (scaledMesh == null)
+ {
+ return;
+ }
+
+ material = scaledMesh.sharedMaterial; // TODO: what if there are multiple materials? do we need to check all of them?
+ string shaderName = material.shader.name;
+
+ if (shaderName == "Terrain/Gas Giant")
+ {
+ colorMapTextureName = "_DetailCloudPatternTexture";
+ normalMapTextureName = "_NormalMap";
+ }
+ // HapkeScaled is the Sol shader which is also a Parallax-dependent instance
+ else if (shaderName.Contains("ParallaxScaled") || shaderName.Contains("HapkeScaled"))
+ {
+ SCANparallaxContinued.LoadParallax(body, ref material);
+ useMaterialForColorMap = false;
+ colorMapTextureName = "_ColorMap";
+ normalMapTextureName = "_BumpMap";
+ }
+ else if (material.HasProperty("_MainTex"))
+ {
+ colorMapTextureName = "_MainTex";
+ }
+ else if (material.HasProperty("_ColorMap"))
+ {
+ colorMapTextureName = "_ColorMap";
+ }
+
+ if (material.HasProperty("_BumpMap"))
+ {
+ normalMapTextureName = "_BumpMap";
+ }
+ else if (material.HasProperty("_NormalMap"))
+ {
+ normalMapTextureName = "_NormalMap";
+ }
+
+ // Only cache color / visual map if memory mapped visual map is not available and map not previously cached
+ if (memoryMappedVisualMap == null && cachedVisualMap == null && colorMapTextureName != null)
+ {
+ var sourceColorTexture = material.GetTexture(colorMapTextureName) as Texture2D;
+ if (sourceColorTexture != null)
+ {
+ cachedVisualMap = sourceColorTexture.isReadable ? sourceColorTexture : readableTexture(sourceColorTexture, useMaterialForColorMap ? material : null);
+ }
+ else
+ {
+ Log.Error($"Visual Map cached null texture for body {body.name}, material {material.name} and texture name {colorMapTextureName}");
+ }
+ }
+
+ // Only cache normal map if memory mapped normal map is not available and map not previously cached
+ if (memoryMappedNormalMap == null && cachedNormalMap == null && normalMapTextureName != null)
+ {
+ var sourceNormalTexture = material.GetTexture(normalMapTextureName) as Texture2D;
+ if (sourceNormalTexture != null)
+ {
+ cachedNormalMap = sourceNormalTexture.isReadable ? sourceNormalTexture : readableTexture(sourceNormalTexture, null);
+ }
+ else
+ {
+ Log.Error($"Normal Map cached null texture for body {body.name}, material {material.name} and texture name {normalMapTextureName}");
+ }
+ }
+ }
+
+ public TextureFormat GetNormalFormat()
+ {
+ if (memoryMappedNormalMap != null)
+ {
+ return memoryMappedNormalMap.Format;
+ }
+ else if (cachedNormalMap != null)
+ {
+ return cachedNormalMap.format;
+ }
+ Log.Error($"No normal map textures defined for {body.bodyName}");
+ throw new NullReferenceException($"No normal map textures defined for {body.bodyName}");
+ }
+ public Color32 GetShadedVisualPixel(double lon, double lat)
+ {
+
+ float fLat = ((float)lat + 90f) / 180f;
+ float fLon = ((float)lon + 270f) / 360f;
+
+ if (fLon < 0) { fLon += 1; }
+ if (fLon > 1) { fLon -= 1; }
+ fLon = 1 - fLon;
+
+ fLat = Mathf.Clamp01(fLat);
+ fLon = Mathf.Clamp01(fLon);
+
+ Color32 c = palette.Grey;
+
+ // If no textures are loaded, return static
+ if (memoryMappedVisualMap != null)
+ {
+ c = memoryMappedVisualMap.GetPixelBilinear(fLon, fLat);
+ }
+ else if (cachedVisualMap != null)
+ {
+ c = cachedVisualMap.GetPixelBilinear(fLon, fLat);
+ }
+ else
+ {
+ return palette.lerp(palette.Black, palette.White, UnityEngine.Random.value);
+ }
+
+ // Set c to be fully opaque
+ c.a = 255;
+
+ // Attempt to load Normal map values
+ Color32 n;
+ if (memoryMappedNormalMap != null)
+ {
+ n = memoryMappedNormalMap.GetPixelBilinear(fLon, fLat);
+ }
+ else if (cachedNormalMap != null)
+ {
+ n = cachedNormalMap.GetPixelBilinear(fLon, fLat);
+ }
+ else
+ {
+ return c; // No normal map, return the color as is
+ }
+
+ // Extract the Y channel from the normal map and normalize to range [0, 1]. lumOver of 0.5 is neutral
+ double lumOver = n.b / 255f; // Base game KSP blue channel to store Y axis normal data
+
+ switch (GetNormalFormat())
+ {
+ case TextureFormat.BC5:
+ lumOver = n.g / 255f; // BC5 stores X in red and Y in green (Z not stored)
+ break;
+ case TextureFormat.DXT5:
+ lumOver = n.g / 255f; // DXT5 stores X in alpha and Y in green (Z not stored)
+ break;
+ default:
+ break;
+ }
+
+ HslColor hslBase = palette.ConvertRgbToHsl(c);
+
+ double opacity = 0.8;
+ double lum = hslBase.L;
+
+ if (lum > 0.5d)
+ {
+ lum = (opacity * (1 - (1 - (2 * (lumOver - 0.5))) * (1 - lum))) + (1 - opacity) * lum;
+ lum = (opacity * lum) + (1 - opacity) * lum;
+ }
+ else
+ {
+ lum = (opacity * (2 * lumOver * lum)) + (1 - opacity) * lum;
+ }
+
+ c = palette.ConvertHslToRgb(hslBase.H, hslBase.S, lum);
+ return c;
+ }
+
+ public string TextureState()
+ {
+ string colorMapState = memoryMappedVisualMap != null ? "Memory Mapped" : (cachedVisualMap != null ? "RAM Buffered" : "None");
+ string normalMapState = memoryMappedNormalMap != null ? "Memory Mapped" : (cachedNormalMap != null ? "RAM Buffered" : "None");
+
+ return $"{body.name} Visual Map Texture: {colorMapState}, Normal Map Texture: {normalMapState}";
+ }
+ }
+
[KSPScenario(ScenarioCreationOptions.AddToAllGames | ScenarioCreationOptions.AddToExistingGames, GameScenes.FLIGHT, GameScenes.SPACECENTER, GameScenes.TRACKSTATION)]
public class SCANcontroller : ScenarioModule
{
@@ -58,7 +373,7 @@ public static SCANcontroller controller
[KSPField(isPersistant = true)]
public bool mainMapTerminator = false;
[KSPField(isPersistant = true)]
- public bool mainMapBiome = false;
+ public MainMapDisplayMode mainMapDisplayMode = MainMapDisplayMode.Terrain;
[KSPField(isPersistant = true)]
public bool mainMapMinimized = false;
[KSPField(isPersistant = true)]
@@ -139,7 +454,7 @@ public static SCANcontroller controller
/* Primary SCANsat vessel dictionary; loaded every time */
public DictionaryValueList knownVessels = new DictionaryValueList();
- /* Primary SCANdata dictionary; loaded every time*/
+ /* Primary SCANdata dictionary; loaded every time */
private DictionaryValueList body_data = new DictionaryValueList();
/* MechJeb Landing Target Integration */
@@ -154,8 +469,7 @@ public static SCANcontroller controller
private CelestialBody zoomMapBodyVisual;
/* Visual Map Texture Data */
- private Dictionary readableScaledSpaceMaps = new Dictionary();
- private Dictionary readableScaledSpaceNormalMaps = new Dictionary();
+ private Dictionary mapTextureHandler = new Dictionary();
private CelestialBody bigMapBodyScaledSpace;
private CelestialBody zoomMapBodyScaledSpace;
@@ -234,31 +548,39 @@ public void addToBodyData(CelestialBody b, SCANdata data)
}
}
- public Texture2D getVisualMapTexture(CelestialBody b)
+ public bool isVisualTextureLoaded(CelestialBody b)
{
if (!SCAN_Settings_Config.Instance.VisibleMapsActive)
{
- return null;
+ return false;
}
- if (readableScaledSpaceMaps.ContainsKey(b))
+ // Check if a texture is present in either dictionary
+ if (mapTextureHandler.GetValueOrDefault(b) != null)
{
- return readableScaledSpaceMaps[b];
+ if (mapTextureHandler[b].memoryMappedVisualMap != null || mapTextureHandler[b].cachedVisualMap != null)
+ {
+ return true;
+ }
}
- return null;
+ return false;
}
- public Texture2D getVisualMapNormalTexture(CelestialBody b)
+ public Color32 GetShadedVisualPixel(CelestialBody b, double lon, double lat)
{
- if (readableScaledSpaceNormalMaps.ContainsKey(b))
+ Color32 c = palette.Grey;
+
+ SCANtextures bodyTextures = mapTextureHandler.GetValueOrDefault(b);
+ if (bodyTextures != null)
{
- return readableScaledSpaceNormalMaps[b];
+ return bodyTextures.GetShadedVisualPixel(lon, lat);
}
- return null;
+ return c;
}
+
public static List EncodeTerrainConfigs
{
get
@@ -289,6 +611,7 @@ public static void setMasterTerrainNodes(List terrainConfigs)
}
}
+
public static void checkLoadedTerrainNodes()
{
for (int i = 0; i < FlightGlobals.Bodies.Count; i++)
@@ -300,29 +623,9 @@ public static void checkLoadedTerrainNodes()
continue;
}
- if (getTerrainNode(b.bodyName) == null)
+ if (SCANUtil.getTerrainConfig(b) == null)
{
- float? clamp = null;
- if (b.ocean)
- {
- clamp = 0;
- }
-
- float newMax;
-
- try
- {
- newMax = ((float)CelestialUtilities.GetHighestPeak(b)).Mathf_Round(-2);
- }
- catch (Exception e)
- {
- SCANUtil.SCANlog("Error in calculating Max Height for {0}; using default value/n{1}", b.bodyName, e);
- newMax = SCANconfigLoader.SCANNode.DefaultMaxHeightRange;
- }
-
- SCANUtil.SCANlog("Generating new SCANsat Terrain Config for [{0}] - Max Height: [{1:F0}m]", b.bodyName, newMax);
-
- addToTerrainConfigData(b.bodyName, new SCANterrainConfig(SCANconfigLoader.SCANNode.DefaultMinHeightRange, newMax, clamp, SCANUtil.PaletteLoader(SCANconfigLoader.SCANNode.DefaultPalette, 7), 7, false, false, b));
+ SCANUtil.generateTerrainConfig(b); // Sets the terrain config in the dictionary
}
}
}
@@ -333,11 +636,8 @@ public static SCANterrainConfig getTerrainNode(string name)
{
return masterTerrainNodes[name];
}
- else
- {
- SCANUtil.SCANlog("SCANsat terrain config [{0}] cannot be found in master terrain storage list", name);
- }
+ SCANUtil.SCANlog("SCANsat terrain config [{0}] cannot be found in master terrain storage list", name);
return null;
}
@@ -358,14 +658,13 @@ public static void updateTerrainConfig(SCANterrainConfig t)
public static void addToTerrainConfigData(string name, SCANterrainConfig data)
{
- if (!masterTerrainNodes.ContainsKey(name))
- {
- masterTerrainNodes.Add(name, data);
- }
- else
+ if (masterTerrainNodes.ContainsKey(name))
{
- Log.Error("SCANterrain Data Dictionary Already Contains Key Of This Type");
+ Log.Warning($"[{name}] Terrain Config already stored in SCANterrain Data Dictionary");
+ return;
}
+
+ masterTerrainNodes.Add(name, data);
}
public static int MasterResourceCount
@@ -406,7 +705,7 @@ public static void setMasterResourceNodes(List resourceConfi
{
continue;
}
- //SCANUtil.SCANlog("Loading SCANsat resource config settings: {0}", r.Name);
+
if (!masterResourceNodes.Contains(r.Name))
{
masterResourceNodes.Add(r.Name, r);
@@ -720,42 +1019,6 @@ public override void OnLoad(ConfigNode node)
}
data.Disabled = node_body.parse("Disabled", false);
-
- float min = node_body.parse("MinHeightRange", data.TerrainConfig.DefaultMinHeight);
- float max = node_body.parse("MaxHeightRange", data.TerrainConfig.DefaultMaxHeight);
- float? clampState = node_body.parse("ClampHeight", (float?)null);
-
- int pSize = node_body.parse("PaletteSize", data.TerrainConfig.DefaultPaletteSize);
- bool pRev = node_body.parse("PaletteReverse", data.TerrainConfig.DefaultReverse);
- bool pDis = node_body.parse("PaletteDiscrete", data.TerrainConfig.DefaultDiscrete);
-
- string paletteName = node_body.parse("PaletteName", "");
-
- if (string.IsNullOrEmpty(paletteName))
- {
- paletteName = data.TerrainConfig.DefaultPalette.Name;
- }
-
- SCANPalette dataPalette = SCANUtil.PaletteLoader(paletteName, pSize);
-
- if (dataPalette.Hash == SCAN_Palette_Config.DefaultPalette.GetPalette(0).Hash)
- {
- paletteName = "Default";
- pSize = 7;
- }
-
- SCANterrainConfig dataTerrainConfig = getTerrainNode(body.bodyName);
-
- if (dataTerrainConfig == null)
- {
- dataTerrainConfig = new SCANterrainConfig(min, max, clampState, dataPalette, pSize, pRev, pDis, body);
- }
- else
- {
- setNewTerrainConfigValues(dataTerrainConfig, min, max, clampState, dataPalette, pSize, pRev, pDis);
- }
-
- data.TerrainConfig = dataTerrainConfig;
}
catch (Exception e)
{
@@ -826,17 +1089,22 @@ public override void OnSave(ConfigNode node)
node_body.AddValue("LandingTarget", string.Format("{0:N4},{1:N4}", w.Latitude, w.Longitude));
}
}
- node_body.AddValue("MinHeightRange", body_scan.TerrainConfig.MinTerrain / body_scan.TerrainConfig.MinHeightMultiplier);
- node_body.AddValue("MaxHeightRange", body_scan.TerrainConfig.MaxTerrain / body_scan.TerrainConfig.MaxHeightMultiplier);
- if (body_scan.TerrainConfig.ClampTerrain != null)
+
+ SCANterrainConfig body_config = SCANUtil.getTerrainConfig(body_scan);
+ if (body_config != null)
{
- node_body.AddValue("ClampHeight", body_scan.TerrainConfig.ClampTerrain / body_scan.TerrainConfig.ClampHeightMultiplier);
- }
+ node_body.AddValue("MinHeightRange", body_config.MinTerrain / body_config.MinHeightMultiplier);
+ node_body.AddValue("MaxHeightRange", body_config.MaxTerrain / body_config.MaxHeightMultiplier);
+ if (body_config.ClampTerrain != null)
+ {
+ node_body.AddValue("ClampHeight", body_config.ClampTerrain / body_config.ClampHeightMultiplier);
+ }
- node_body.AddValue("PaletteName", body_scan.TerrainConfig.ColorPal.Name);
- node_body.AddValue("PaletteSize", body_scan.TerrainConfig.PalSize);
- node_body.AddValue("PaletteReverse", body_scan.TerrainConfig.PalRev);
- node_body.AddValue("PaletteDiscrete", body_scan.TerrainConfig.PalDis);
+ node_body.AddValue("PaletteName", body_config.ColorPal.Name);
+ node_body.AddValue("PaletteSize", body_config.PalSize);
+ node_body.AddValue("PaletteReverse", body_config.PalRev);
+ node_body.AddValue("PaletteDiscrete", body_config.PalDis);
+ }
node_body.AddValue("Map", body_scan.shortSerialize());
node_progress.AddNode(node_body);
}
@@ -1600,78 +1868,6 @@ internal void LoadVisualMapTexture(CelestialBody b, mapSource s)
}
- void GetVisualMapTexturesForBody(CelestialBody b, out Material material, out bool useMaterialForColorMap, out string colorMapTextureName, out string normalMapTextureName)
- {
- material = null;
- colorMapTextureName = null;
- normalMapTextureName = null;
- useMaterialForColorMap = true;
-
- if (b.scaledBody == null)
- {
- return;
- }
-
- MeshRenderer scaledMesh = b.scaledBody.GetComponent();
-
- if (scaledMesh == null)
- {
- return;
- }
-
- material = scaledMesh.sharedMaterial; // TODO: what if there are multiple materials? do we need to check all of them?
- string shaderName = material.shader.name;
-
- if (shaderName == "Terrain/Gas Giant")
- {
- colorMapTextureName = "_DetailCloudPatternTexture";
- normalMapTextureName = "_NormalMap";
- return;
- }
- else if (shaderName.Contains("ParallaxScaled"))
- {
- SCANparallaxContinued.LoadParallax(b, ref material);
- useMaterialForColorMap = false;
- colorMapTextureName = "_ColorMap";
- normalMapTextureName = null; // for whatever reason, the logic in ScANmap that uses the normal map doesn't work with parallax's normal maps
- return;
- }
- else if (material.HasProperty("_MainTex"))
- {
- colorMapTextureName = "_MainTex";
- }
- else if (material.HasProperty("_ColorMap"))
- {
- colorMapTextureName = "_ColorMap";
- }
-
- if (material.HasProperty("_BumpMap"))
- {
- normalMapTextureName = "_BumpMap";
- }
- else if (material.HasProperty("_NormalMap"))
- {
- normalMapTextureName = "_NormalMap";
- }
- }
-
- void CacheScaledSpaceTexture(Dictionary cache, CelestialBody b, Material material, string textureName, bool useMaterial)
- {
- if (cache.GetValueOrDefault(b) == null && textureName != null)
- {
- var sourceTexture = material.GetTexture(textureName) as Texture2D;
- if (sourceTexture == null)
- {
- Log.Error($"GetTexture returned a null texture for body {b.name}, material {material.name} and texture name {textureName}");
- }
- else
- {
- var colorMap = sourceTexture.isReadable ? sourceTexture : readableTexture(sourceTexture, useMaterial ? material : null);
- cache.Add(b, colorMap);
- }
- }
- }
-
internal void LoadVisualMapTexture_Renamed(CelestialBody b, mapSource s)
{
if (!SCAN_Settings_Config.Instance.VisibleMapsActive)
@@ -1684,18 +1880,6 @@ internal void LoadVisualMapTexture_Renamed(CelestialBody b, mapSource s)
return;
}
- GetVisualMapTexturesForBody(b, out Material material, out bool useMaterialForColorMap, out string colorMapTextureName, out string normalMapTextureName);
-
- if (material == null)
- {
- Log.Error($"GetVisualMapTexturesForBody returned a null material for body {b.name}");
- }
- else
- {
- CacheScaledSpaceTexture(readableScaledSpaceMaps, b, material, colorMapTextureName, useMaterialForColorMap);
- CacheScaledSpaceTexture(readableScaledSpaceNormalMaps, b, material, normalMapTextureName, false);
- }
-
switch (s)
{
case mapSource.BigMap:
@@ -1705,6 +1889,14 @@ internal void LoadVisualMapTexture_Renamed(CelestialBody b, mapSource s)
zoomMapBodyScaledSpace = b;
break;
}
+
+ if (mapTextureHandler.GetValueOrDefault(b) != null)
+ {
+ return; // Already cached
+ }
+
+ // Load the textures for this body (either memory mapped, or RAM cached if memory mapping not available)
+ mapTextureHandler.Add(b, new SCANtextures(b));
}
internal void UnloadVisualMapTexture(CelestialBody b, mapSource s)
@@ -1741,57 +1933,22 @@ internal void UnloadVisualMapTexture(CelestialBody b, mapSource s)
break;
}
- if (readableScaledSpaceMaps.ContainsKey(b))
+ if (mapTextureHandler.ContainsKey(b))
{
- GameObject.Destroy(readableScaledSpaceMaps[b]);
- readableScaledSpaceMaps[b] = null;
- readableScaledSpaceMaps.Remove(b);
- }
+ if (mapTextureHandler[b].cachedVisualMap != null)
+ {
+ GameObject.Destroy(mapTextureHandler[b].cachedVisualMap);
+ }
+ if (mapTextureHandler[b].cachedNormalMap != null)
+ {
+ GameObject.Destroy(mapTextureHandler[b].cachedNormalMap);
+ }
- if (readableScaledSpaceNormalMaps.ContainsKey(b))
- {
- GameObject.Destroy(readableScaledSpaceNormalMaps[b]);
- readableScaledSpaceNormalMaps[b] = null;
- readableScaledSpaceNormalMaps.Remove(b);
+ mapTextureHandler[b] = null;
+ mapTextureHandler.Remove(b);
}
}
- private Texture2D readableTexture(Texture tex, Material mat)
- {
- if (tex == null)
- {
- return null;
- }
-
- Texture2D readable = new Texture2D(tex.width, tex.height);
-
- var rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB, 1);
-
- if (mat != null)
- {
- Graphics.Blit(tex, rt, mat);
- }
- else
- {
- Graphics.Blit(tex, rt);
- }
-
- RenderTexture.active = rt;
-
- readable.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
-
- RenderTexture.active = null;
- RenderTexture.ReleaseTemporary(rt);
-
- rt = null;
-
- readable.Apply();
-
- tex = null;
-
- return readable;
- }
-
private void OnGUI()
{
if (HighLogic.LoadedSceneIsFlight || HighLogic.LoadedScene == GameScenes.TRACKSTATION)
@@ -2178,17 +2335,12 @@ private void SOIChange(GameEvents.HostedFromToAction VC)
{
body_data.Add(VC.to.bodyName, new SCANdata(VC.to));
}
- }
- private void setNewTerrainConfigValues(SCANterrainConfig terrain, float min, float max, float? clamp, SCANPalette c, int size, bool reverse, bool discrete)
- {
- terrain.MinTerrain = min * terrain.MinHeightMultiplier;
- terrain.MaxTerrain = max * terrain.MaxHeightMultiplier;
- terrain.ClampTerrain = clamp * terrain.ClampHeightMultiplier;
- terrain.ColorPal = c;
- terrain.PalSize = size;
- terrain.PalRev = reverse;
- terrain.PalDis = discrete;
+ // Generate terrain config if it doesn't exist
+ if (SCANUtil.getTerrainConfig(VC.to) == null)
+ {
+ SCANUtil.generateTerrainConfig(VC.to);
+ }
}
private string saveResources(SCANresourceGlobal resource)
@@ -2283,8 +2435,6 @@ private void loadCustomResourceValues(ConfigNode node)
res.MinValue = min;
res.MaxValue = max;
}
- //else
- //SCANUtil.SCANlog("No resources found assigned for Celestial Body: {0}, skipping...", b.bodyName);
}
else
{
diff --git a/SCANsat/SCANmainMenuLoader.cs b/SCANsat/SCANmainMenuLoader.cs
index 59b60941..e8e1c061 100644
--- a/SCANsat/SCANmainMenuLoader.cs
+++ b/SCANsat/SCANmainMenuLoader.cs
@@ -17,7 +17,7 @@
using System.Diagnostics;
using System.Linq;
using UnityEngine;
-using Log = KSPBuildTools.Log;
+using Log = KSPCommunityLib.Logging.Log;
using SCANsat.SCAN_Reflection;
namespace SCANsat
diff --git a/SCANsat/SCANsat.csproj b/SCANsat/SCANsat.csproj
index 3350596d..b3c8f2d3 100644
--- a/SCANsat/SCANsat.csproj
+++ b/SCANsat/SCANsat.csproj
@@ -6,19 +6,27 @@
net4.8
- true
- true
+ true
+ true
-
- $(RepoRootPath)\GameData\SCANsat\SCANsat.version
+
+ $(KSPBT_ModRoot)/SCANsat.version
1.12.3
-
+
+ GameData/KSPTextureLoader/Plugins/KSPTextureLoader.dll
+ KSPTextureLoader
+ 1.0.34
+
-
+
+
+
+
+
\ No newline at end of file
diff --git a/SCANsat/SCANutil.cs b/SCANsat/SCANutil.cs
index b03926ed..49665f37 100644
--- a/SCANsat/SCANutil.cs
+++ b/SCANsat/SCANutil.cs
@@ -27,6 +27,7 @@
using SCANsat.SCAN_UI.UI_Framework;
using palette = SCANsat.SCAN_UI.UI_Framework.SCANcolorUtil;
using SCANsat.SCAN_Unity;
+using Log = KSPCommunityLib.Logging.Log;
namespace SCANsat
{
@@ -265,6 +266,84 @@ public static SCANdata getData(string BodyName)
return SCANcontroller.controller.getData(BodyName);
}
+ ///
+ /// For a given Celestial Body, this returns the SCANterrainConfig instance if it exists in the SCANcontroller master dictionary; return is null if the SCANterrainConfig does not exist for that body (likely not generated or loaded properly), or if the SCANcontroller Scenario Module has not been loaded.
+ ///
+ /// Instance of celestial body
+ /// SCANterrainConfig instance for the given Celestial Body; null if none exists
+ public static SCANterrainConfig getTerrainConfig(CelestialBody body)
+ {
+ return getTerrainConfig(body.bodyName);
+ }
+
+ ///
+ /// For a given SCANdata instance of a celestial body, this returns the SCANterrainConfig instance if it exists in the SCANcontroller master dictionary; return is null if the SCANterrainConfig does not exist for that body (likely not generated or loaded properly), or if the SCANcontroller Scenario Module has not been loaded.
+ ///
+ /// SCANdata instance for a celestial body
+ /// SCANterrainConfig instance for the given Celestial Body; null if none exists
+ public static SCANterrainConfig getTerrainConfig(SCANdata data)
+ {
+ return getTerrainConfig(data.Body.bodyName);
+ }
+
+ ///
+ /// For a given Celestial Body name, this returns the SCANterrainConfig instance if it exists in the SCANcontroller master dictionary; return is null if the SCANterrainConfig does not exist for that body (likely not generated or loaded properly), or if the SCANcontroller Scenario Module has not been loaded.
+ ///
+ /// Name of celestial body (do not use displayName string)
+ /// SCANterrainConfig instance for the given Celestial Body; null if none exists
+ public static SCANterrainConfig getTerrainConfig(string BodyName)
+ {
+ if (SCANcontroller.controller == null)
+ {
+ return null;
+ }
+
+ return SCANcontroller.getTerrainNode(BodyName);
+ }
+
+ ///
+ /// Generate the default SCANterrainConfig for the provided body and set / update its entry in the masterTerrainNodes.
+ ///
+ /// CelestialBody instance to generate the SCANterrainConfig for
+ /// SCANterrainConfig instance for the given Celestial Body
+ public static SCANterrainConfig generateTerrainConfig(CelestialBody b)
+ {
+ if (b.pqsController == null)
+ {
+ SCANUtil.SCANlog($"[{b.name}] PQS Controller not loaded - no terrain data generated.");
+ return null;
+ }
+
+ float? clamp = null;
+ if (b.ocean)
+ {
+ clamp = 0;
+ }
+
+ float newMin;
+ float newMax;
+
+ try
+ {
+ newMin = ((float)(b.pqsController.radiusMin - b.pqsController.radius)).Mathf_Round(-1);
+ newMax = ((float)(b.pqsController.radiusMax - b.pqsController.radius)).Mathf_Round(-1);
+ if (newMin == newMax)
+ {
+ throw new Exception("Gas Giant / Flat Body"); // Clamp altimetry if body is perfectly smooth / gas giant
+ }
+ }
+ catch (Exception e)
+ {
+ SCANlog($"[{b.name}] Error in calculating Max Height; using default value\n{e}");
+ newMin = SCANconfigLoader.SCANNode.DefaultMinHeightRange;
+ newMax = SCANconfigLoader.SCANNode.DefaultMaxHeightRange;
+ }
+
+ SCANterrainConfig config = new SCANterrainConfig(newMin, newMax, clamp, PaletteLoader(SCANconfigLoader.SCANNode.DefaultPalette, 7), 7, false, false, b);
+ SCANcontroller.addToTerrainConfigData(b.bodyName, config); // Add to masterTerrainNodes dictionary in SCANcontroller
+ return config;
+ }
+
///
/// Do SCANsat maps automatically update with the stock, instant-scan orbital surveys?
///
@@ -535,6 +614,10 @@ public static bool scanTypeValid(SCANtype type)
public static double[] cosLookUp = new double[180];
public static DictionaryValueList localizedBodyNames = new DictionaryValueList();
+ /* Biome Map Encoding Data */
+ private static Dictionary _scanBiomePaletteCache
+ = new Dictionary();
+
internal static bool isCovered(double lon, double lat, SCANdata data, SCANtype type)
{
int ilon = icLON(lon);
@@ -834,6 +917,44 @@ internal static float ResourceOverlay(double lat, double lon, string name, Celes
return amount;
}
+ private static bool IsGrayscaleEncoded(CBAttributeMapSO.MapAttribute[] attrs)
+ {
+ foreach (var a in attrs)
+ {
+ if (a == null) continue;
+ if (Mathf.Abs(a.mapColor.g - 1f) > 0.01f) return false;
+ if (Mathf.Abs(a.mapColor.b - 1f) > 0.01f) return false;
+ }
+ return true;
+ }
+
+ public static CBAttributeMapSO.MapAttribute[] GetOrBuildPalette(CelestialBody body)
+ {
+ if (_scanBiomePaletteCache.TryGetValue(body.name, out var cached))
+ {
+ return cached;
+ }
+
+ var src = body.BiomeMap.Attributes;
+ if (!IsGrayscaleEncoded(src))
+ {
+ _scanBiomePaletteCache[body.name] = body.BiomeMap.Attributes;
+ return body.BiomeMap.Attributes;
+ }
+
+ // Build replacements with categorical hues via golden-ratio HSV
+ var replacements = new CBAttributeMapSO.MapAttribute[src.Length];
+ for (int i = 0; i < src.Length; i++)
+ {
+ if (src[i] == null) { continue; }
+ var clone = new CBAttributeMapSO.MapAttribute(src[i]); // Copy all attributes
+ clone.mapColor = Color.HSVToRGB((i * 0.61803398875f) % 1f, 1f, 1f);
+ replacements[i] = clone;
+ }
+ _scanBiomePaletteCache[body.name] = replacements;
+ return replacements;
+ }
+
private static int getBiomeIndex(CelestialBody body, double lon, double lat)
{
if (body.BiomeMap == null)
@@ -850,6 +971,7 @@ private static int getBiomeIndex(CelestialBody body, double lon, double lat)
}
CBAttributeMapSO.MapAttribute att = body.BiomeMap.GetAtt(Mathf.Deg2Rad * lat, Mathf.Deg2Rad * lon);
+
for (int i = 0; i < body.BiomeMap.Attributes.Length; ++i)
{
if (body.BiomeMap.Attributes[i] == att)
@@ -883,6 +1005,10 @@ internal static CBAttributeMapSO.MapAttribute getBiome(CelestialBody body, doubl
return null;
}
+ var palette = GetOrBuildPalette(body);
+ if (palette != null && i < palette.Length && palette[i] != null)
+ return palette[i];
+
return body.BiomeMap.Attributes[i];
}
@@ -929,6 +1055,19 @@ internal static void getBiomeDisplayName(StringBuilder sb, CelestialBody body, d
sb.Append(string.IsNullOrEmpty(a.displayname) ? a.name : Localizer.Format(a.displayname));
}
+ internal static Color getBiomeDisplayColor(CelestialBody body, int idx)
+ {
+ if (body == null || body.BiomeMap == null)
+ return Color.gray;
+ if (idx < 0 || idx >= body.BiomeMap.Attributes.Length)
+ return Color.gray;
+
+ var palette = GetOrBuildPalette(body);
+ if (palette != null && palette[idx] != null)
+ return palette[idx].mapColor;
+
+ return body.BiomeMap.Attributes[idx].mapColor;
+ }
internal static int countBits(int i)
{
@@ -1342,13 +1481,13 @@ public void ToDMS(StringBuilder sb)
internal static void SCANlog(string log, params object[] stringObjects)
{
- KSPBuildTools.Log.Message(string.Format(log, stringObjects));
+ Log.Message(string.Format(log, stringObjects));
}
[System.Diagnostics.Conditional("DEBUG")]
internal static void SCANdebugLog(string log, params object[] stringObjects)
{
- KSPBuildTools.Log.Debug(string.Format(log, stringObjects));
+ Log.Debug(string.Format(log, stringObjects));
}
#endregion
@@ -1591,4 +1730,3 @@ public static bool IsInIVA()
}
}
#endregion
-