Jump to content

Toolbar buttons are fuzzy in 1.4.1


Recommended Posts

For anyone who need to know, I figured this out.

It's Unity :-(

The old way of getting textures from the game database:

Texture2D texture = GameDatabase.Instance.GetTexture(MainMenu.flagURL, false);

doesn't work well because of Unity needed it to be a power of 2.

You need to manually read the file using something like:

tex.LoadImage(System.IO.File.ReadAllBytes(fileNamePath));

 

Link to comment
Share on other sites

  • 2 weeks later...

Thank you for figuring out the solution!

I have encountered more or less the same issue, just that in my case the texture didn't show up at all. I just got a black square instead.
In the end I had to change this code:

_settingsTexture = GameDatabase.Instance.GetTexture("KerbalImprovedSaveSystem/icons/settings", false);

into this:

_settingsTexture = new Texture2D(20, 20, TextureFormat.ARGB32, false);
_settingsTexture.LoadImage(System.IO.File.ReadAllBytes("GameData/KerbalImprovedSaveSystem/icons/settings.png"));

Although I'm not sure that the first line is required? I have to admit that is copy and paste coding of the most embarrassing kind. :wink:

Edited by Aerospike
better readable code
Link to comment
Share on other sites

Oh... thanks for the heads up! :)

KISS used to have the startup type

[KSPAddon(KSPAddon.Startup.FlightAndKSC, false)]

so I had to rework that.

Since KISS is pretty lightweight (just a save dialog with a bunch of ui styles and some custom settings) I decided to just keep it around permanently (set "once" to true in the above line) and check the currently loaded scene in update to make sure it only reacts to user input in the appropriate scenes.

Link to comment
Share on other sites

  • 3 weeks later...

Sorry to revive a month-quiet thread, but I was hoping for some clarification on things discussed here as I'm also running into texture issues building a mod for 1.4.

@sarbian, can you expand on what you mean by "they are never removed from memory"? Is any Texture2D persisted forever, whether loaded or created (a la Transfer Window Planner, with a call to new Texture2D() and then bitmap created during runtime)? Or is it just the Texture.LoadImage() method that puts something in memory until the game closes?

@linuxgurugamer, Any idea why Unity needs a power of 2? Does it have to be square or just each dimension needs a power of 2? Also, with the method outlined here, can you have textures of arbitrary size?

Thanks everyone!

Link to comment
Share on other sites

1 minute ago, Booots said:

Sorry to revive a month-quiet thread, but I was hoping for some clarification on things discussed here as I'm also running into texture issues building a mod for 1.4.

@sarbian, can you expand on what you mean by "they are never removed from memory"? Is any Texture2D persisted forever, whether loaded or created (a la Transfer Window Planner, with a call to new Texture2D() and then bitmap created during runtime)? Or is it just the Texture.LoadImage() method that puts something in memory until the game closes?

@linuxgurugamer, Any idea why Unity needs a power of 2? Does it have to be square or just each dimension needs a power of 2? Also, with the method outlined here, can you have textures of arbitrary size?

Thanks everyone!

You need to destroy the texture yourself, when done with it, otherwise it will remain in memory.  Use something like:

Destroy(tex);

I have no idea why it needs a power of two, probably something to do with the compression.  My method will load any size without a problem

Link to comment
Share on other sites

7 minutes ago, linuxgurugamer said:

You need to destroy the texture yourself, when done with it, otherwise it will remain in memory.  Use something like:

Destroy(tex);

I have no idea why it needs a power of two, probably something to do with the compression.  My method will load any size without a problem

Okay, thanks! So if I keep reusing the same Texture2D variable for a texture that changes through the life of the plugin and then Destroy it in the OnDestroy method of the main plugin it'll be all good? Or do I need to Destroy the Texture2D prior to each change/load of a new image for safety?

Edited by Booots
Link to comment
Share on other sites

5 hours ago, Booots said:

Okay, thanks! So if I keep reusing the same Texture2D variable for a texture that changes through the life of the plugin and then Destroy it in the OnDestroy method of the main plugin it'll be all good? Or do I need to Destroy the Texture2D prior to each change/load of a new image for safety?

If you "new" or load a texture you ll have to destroy it once you do not use it. A "variable" is just a reference to the texture, not the texture itself.

Link to comment
Share on other sites

1 hour ago, sarbian said:

If you "new" or load a texture you ll have to destroy it once you do not use it. A "variable" is just a reference to the texture, not the texture itself.

Gotcha. So what you're saying is that Unity won't let the GC clean up the texture once the reference is changed and it goes out of scope.

Confirmed from this: https://forum.unity.com/threads/unused-textures-do-not-trigger-garbage-collector.476758/

Edited by Booots
Found source.
Link to comment
Share on other sites

You have to keep in mind that Unity is not a C# game engine. It's a C++ game engine with C# scripting. Texture (and most Unity object) are on the C++ side and not managed by the GC at all. Some are cleaned up on scene change (gameobject that are not marked dontdestroy) but most just stay in memory unless explicitly removed.

Link to comment
Share on other sites

  • 3 months later...

Oh, hate to necro an older thread but I couldn't find anything else on this and it's relevant.

@SpannerMonkey(smce) and I have been having a private chat about the code KAX uses to load it's icon and my attempt to duplicate it.  His code looks like this:

            var normIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_normal.png"); // icon to be present in same folder as dll
            normIcon.LoadImage(File.ReadAllBytes(normIconFile));

It uses the Texture2D.LoadImage.  I can get that code to compile just fine.  However, when I load up KSP and jump into the editor, I get this in the log file:

[ERR 10:01:11.562] Exception handling event onGUIEditorToolbarReady in class KAXFilter:System.MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
  at KAE_Ltd.BaseFilter.SubCategories () [0x00000] in <filename unknown>:0 
  at EventVoid.Fire () [0x00000] in <filename unknown>:0 

[EXC 10:01:11.563] MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
	KAE_Ltd.BaseFilter.SubCategories ()
	EventVoid.Fire ()
	UnityEngine.Debug:LogException(Exception)
	EventVoid:Fire()
	KSP.UI.Screens.<SetInitialState>c__Iterator1:MoveNext()
	UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
	KSP.UI.Screens.PartCategorizer:Setup()
	EventVoid:Fire()
	KSP.UI.Screens.EditorPanels:ShowPartsList(Action)
	EditorLogic:SelectPanelParts(Boolean)
	EditorLogic:StartEditor(Boolean)
	<Start>c__Iterator0:MoveNext()
	UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

and no icon of course.

Spanner however is able to compile that code, run KSP and get  it to load up his icon with no problems.

The only workaround I have found that works on my install is this:

            var normIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_off.png"); // icon to be present in same folder as dll
            WWW www = new WWW(normIconFile);
            normIcon = www.texture;
            normIcon.Apply();

Now, the next thing is, the only reference I can find in the Unity docs to Texture2D.LoadImage is for version 5.3 and older.  In the latest docs, the Texture2D.LoadImage method doesn't even exist.

And, as per this post, the icons I get on the toolbar are 'fuzzy'

*EDIT*

Ah hah. I fixed the fuzzy buy doing this:

www.LoadImageIntoTexture(normIcon);
//normIcon = www.texture;

but it still doesn't explain why Spanner can get the LoadImage to work and I can't.

Edited by Fengist
Link to comment
Share on other sites

2 hours ago, Fengist said:

Oh, hate to necro an older thread but I couldn't find anything else on this and it's relevant.

@SpannerMonkey(smce) and I have been having a private chat about the code KAX uses to load it's icon and my attempt to duplicate it.  His code looks like this:


            var normIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_normal.png"); // icon to be present in same folder as dll
            normIcon.LoadImage(File.ReadAllBytes(normIconFile));

It uses the Texture2D.LoadImage.  I can get that code to compile just fine.  However, when I load up KSP and jump into the editor, I get this in the log file:


[ERR 10:01:11.562] Exception handling event onGUIEditorToolbarReady in class KAXFilter:System.MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
  at KAE_Ltd.BaseFilter.SubCategories () [0x00000] in <filename unknown>:0 
  at EventVoid.Fire () [0x00000] in <filename unknown>:0 

[EXC 10:01:11.563] MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
	KAE_Ltd.BaseFilter.SubCategories ()
	EventVoid.Fire ()
	UnityEngine.Debug:LogException(Exception)
	EventVoid:Fire()
	KSP.UI.Screens.<SetInitialState>c__Iterator1:MoveNext()
	UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
	KSP.UI.Screens.PartCategorizer:Setup()
	EventVoid:Fire()
	KSP.UI.Screens.EditorPanels:ShowPartsList(Action)
	EditorLogic:SelectPanelParts(Boolean)
	EditorLogic:StartEditor(Boolean)
	<Start>c__Iterator0:MoveNext()
	UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

and no icon of course.

Spanner however is able to compile that code, run KSP and get  it to load up his icon with no problems.

The only workaround I have found that works on my install is this:


            var normIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_off.png"); // icon to be present in same folder as dll
            WWW www = new WWW(normIconFile);
            normIcon = www.texture;
            normIcon.Apply();

Now, the next thing is, the only reference I can find in the Unity docs to Texture2D.LoadImage is for version 5.3 and older.  In the latest docs, the Texture2D.LoadImage method doesn't even exist.

 

 

So that code you are using is a modified version of DCK's editor category deal that was adapted from USI Tools

Post a link to your editorcategory code and I'll take a look .... I'm having no issues with it in DCK, DCK FutureTech, Enemy Mine and any of my other mods so only thing it can be is the adaptation you did to the code

Let me look at it and I'm sure I can spot what is going wrong

Edited by DoctorDavinci
Link to comment
Share on other sites

1 minute ago, DoctorDavinci said:

So that code you are using is a modified version of DCK's editor category deal that was adapted from USI Tools

Post a link to your editorcategory code and I'll take a look .... I'm having no issues with it in DCK, DCK FutureTech, Enemy Mine and any of my other mods so only thing it can be is the adaptation you did to the code

 

@DoctorDavinci

It's essentially the same as this code from KAX: https://github.com/SpannerMonkey/KAX/blob/master/KAXPartCatalog.cs   (Which Spanner tells me is also adapted from USI) The only difference is the strings for the the mod & category names and the changes I posted above (for both icons).

Here's what's puzzling us.  If I download the KAX distribution with that compiled DLL I still get the error posted above that it can't find the method LoadImage.  If I change the code to using WWW as I posted above, it works perfectly.  Spanner however is able to use the KAX .dll with no problems.  And I'm doing all of this in the Steam download folder so my KSP version is exactly what Steam sent.

I'll do a wipe and re-download of KSP and see what happens.  I did briefly install some mods (which I deleted) that seemed to have affected the tech tree. They may have affected other things but I can't imagine them wiping out the Texture2D.LoadImage.

I'm not at the machine with that code atm.  I'll post it in a bit.

Link to comment
Share on other sites

Just now, Fengist said:

@DoctorDavinci

It's essentially the same as this code from KAX: https://github.com/SpannerMonkey/KAX/blob/master/KAXPartCatalog.cs   (Which Spanner tells me is also adapted from USI) The only difference is the strings for the the mod & category names and the changes I posted above (for both icons).

Here's what's puzzling us.  If I download the KAX distribution with that compiled DLL I still get the error posted above that it can't find the method LoadImage.  If I change the code to using WWW as I posted above, it works perfectly.  Spanner however is able to use the KAX .dll with no problems.  And I'm doing all of this in the Steam download folder so my KSP version is exactly what Steam sent.

I'll do a wipe and re-download of KSP and see what happens.  I did briefly install some mods (which I deleted) that seemed to have affected the tech tree. They may have affected other things but I can't imagine them wiping out the Texture2D.LoadImage.

I'm not at the machine with that code atm.  I'll post it in a bit.

Take your time ... Spanner mentioned this issue to me so I figured I'd lend a hand

Worst case scenario is I slap a category module together for you and you import the .cs into your project (would take all of 5 minutes) .... easy peasy

We'll get you up and running by the end of the day :wink:

Link to comment
Share on other sites

14 minutes ago, DoctorDavinci said:

Take your time ... Spanner mentioned this issue to me so I figured I'd lend a hand

Worst case scenario is I slap a category module together for you and you import the .cs into your project (would take all of 5 minutes) .... easy peasy

We'll get you up and running by the end of the day :wink:

Oh, I'm up and running just fine. The code I have works great now. I get the icons and all my parts are under those icons.  Now I'm just trying to figure out why the code everyone else uses doesn't work for me and whether this is my issue or if I'm just the first to stumble into this problem.  As I said earlier  Texture2D.LoadImage doesn't even appear in the current Unity docs: https://docs.unity3d.com/ScriptReference/Texture2D.html.

There's a post here: https://forum.unity.com/threads/unityengine-texture2d-loadimage-is-missing.467202/ where one of the Unity devs says that LoadImage was being moved to ImageConversion.LoadImage.  I wasn't able to find any ImageConversion class so I found the WWW class solution.

Here's my code:

using KSP.UI.Screens;
using RUI.Icons.Selectable;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;

namespace MPUtils
{

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class MPFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Fengist's Shipyard and Gedunk Shoppe"; }// part manufacturer in cfgs and agents files 
            set { }
        }
        protected override string categoryTitle
        {
            get { return "Maritime Pack"; } // the category name 
            set { }
        }
    }

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class SteampunkFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Fengist's Clock and Watch Factory"; }
            set { }
        }
        protected override string categoryTitle
        {
            get { return "1869"; }
            set { }
        }
    }

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class KerbalElectricFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Kerbal Electric"; }
            set { }
        }
        protected override string categoryTitle
        {
            get { return "Kerbal Electric"; }
            set { }
        }
    }

    public abstract class BaseFilter : MonoBehaviour
    {
        private readonly List<AvailablePart> parts = new List<AvailablePart>();
        internal string category = "Filter by function";
        internal bool filter = true;
        protected abstract string Manufacturer { get; set; }
        protected abstract string categoryTitle { get; set; }

        void Awake()
        {
            if (!MPConfig.MPLoadIcons)
            {
                return;
            }
            parts.Clear();
            var count = PartLoader.LoadedPartsList.Count;
            for (int i = 0; i < count; ++i)
            {
                var avPart = PartLoader.LoadedPartsList[i];
                if (!avPart.partPrefab) continue;
                if (avPart.manufacturer == Manufacturer)
                {
                    parts.Add(avPart);
                }
            }

            print(categoryTitle + "  Filter Count: " + parts.Count);
            if (parts.Count > 0)
                GameEvents.onGUIEditorToolbarReady.Add(SubCategories);
        }

        private bool EditorItemsFilter(AvailablePart avPart)
        {
            return parts.Contains(avPart);
        }

        private void SubCategories()
        {
            var icon = GenIcon(categoryTitle);
            var filter = PartCategorizer.Instance.filters.Find(f => f.button.categorydisplayName == "#autoLOC_453547");//change for 1.3.1
            PartCategorizer.AddCustomSubcategoryFilter(filter, categoryTitle, categoryTitle, icon, EditorItemsFilter);
        }

        private Icon GenIcon(string iconName)
        {
            
            var normIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_off.png"); // icon to be present in same folder as dll
            WWW www = new WWW(normIconFile);
            www.LoadImageIntoTexture(normIcon);
            //normIcon = www.texture;
            //normIcon.LoadRawTextureData(File.ReadAllBytes(normIconFile));
            normIcon.Apply();

            var selIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var selIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_on.png");// icon to be present in same folder as dll
            www = new WWW(selIconFile);
            www.LoadImageIntoTexture(selIcon);
            //selIcon = www.texture;
            //selIcon.LoadRawTextureData(File.ReadAllBytes(selIconFile));
            selIcon.Apply();
            www.Dispose();

            print("*****Adding icon for " + categoryTitle);
            var icon = new Icon(iconName + "Icon", normIcon, selIcon);
            return icon;
        }
    }

}

 

Link to comment
Share on other sites

1 hour ago, Fengist said:

Oh, I'm up and running just fine. The code I have works great now. I get the icons and all my parts are under those icons.  Now I'm just trying to figure out why the code everyone else uses doesn't work for me and whether this is my issue or if I'm just the first to stumble into this problem.  As I said earlier  Texture2D.LoadImage doesn't even appear in the current Unity docs: https://docs.unity3d.com/ScriptReference/Texture2D.html.

There's a post here: https://forum.unity.com/threads/unityengine-texture2d-loadimage-is-missing.467202/ where one of the Unity devs says that LoadImage was being moved to ImageConversion.LoadImage.  I wasn't able to find any ImageConversion class so I found the WWW class solution.

Here's my code:


using KSP.UI.Screens;
using RUI.Icons.Selectable;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using UnityEngine;

namespace MPUtils
{

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class MPFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Fengist's Shipyard and Gedunk Shoppe"; }// part manufacturer in cfgs and agents files 
            set { }
        }
        protected override string categoryTitle
        {
            get { return "Maritime Pack"; } // the category name 
            set { }
        }
    }

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class SteampunkFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Fengist's Clock and Watch Factory"; }
            set { }
        }
        protected override string categoryTitle
        {
            get { return "1869"; }
            set { }
        }
    }

    [KSPAddon(KSPAddon.Startup.MainMenu, true)]
    public class KerbalElectricFilter : BaseFilter
    {
        protected override string Manufacturer
        {
            get { return "Kerbal Electric"; }
            set { }
        }
        protected override string categoryTitle
        {
            get { return "Kerbal Electric"; }
            set { }
        }
    }

    public abstract class BaseFilter : MonoBehaviour
    {
        private readonly List<AvailablePart> parts = new List<AvailablePart>();
        internal string category = "Filter by function";
        internal bool filter = true;
        protected abstract string Manufacturer { get; set; }
        protected abstract string categoryTitle { get; set; }

        void Awake()
        {
            if (!MPConfig.MPLoadIcons)
            {
                return;
            }
            parts.Clear();
            var count = PartLoader.LoadedPartsList.Count;
            for (int i = 0; i < count; ++i)
            {
                var avPart = PartLoader.LoadedPartsList[i];
                if (!avPart.partPrefab) continue;
                if (avPart.manufacturer == Manufacturer)
                {
                    parts.Add(avPart);
                }
            }

            print(categoryTitle + "  Filter Count: " + parts.Count);
            if (parts.Count > 0)
                GameEvents.onGUIEditorToolbarReady.Add(SubCategories);
        }

        private bool EditorItemsFilter(AvailablePart avPart)
        {
            return parts.Contains(avPart);
        }

        private void SubCategories()
        {
            var icon = GenIcon(categoryTitle);
            var filter = PartCategorizer.Instance.filters.Find(f => f.button.categorydisplayName == "#autoLOC_453547");//change for 1.3.1
            PartCategorizer.AddCustomSubcategoryFilter(filter, categoryTitle, categoryTitle, icon, EditorItemsFilter);
        }

        private Icon GenIcon(string iconName)
        {
            
            var normIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_off.png"); // icon to be present in same folder as dll
            WWW www = new WWW(normIconFile);
            www.LoadImageIntoTexture(normIcon);
            //normIcon = www.texture;
            //normIcon.LoadRawTextureData(File.ReadAllBytes(normIconFile));
            normIcon.Apply();

            var selIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var selIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_on.png");// icon to be present in same folder as dll
            www = new WWW(selIconFile);
            www.LoadImageIntoTexture(selIcon);
            //selIcon = www.texture;
            //selIcon.LoadRawTextureData(File.ReadAllBytes(selIconFile));
            selIcon.Apply();
            www.Dispose();

            print("*****Adding icon for " + categoryTitle);
            var icon = new Icon(iconName + "Icon", normIcon, selIcon);
            return icon;
        }
    }

}

  

Honestly I have no clue .... the only real difference is in the GenIcon ... this is what I have there and it compiles no issue and works flawlessly

Quote

        private Icon GenIcon(string iconName)
        {
            var normIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_normal.png");
            normIcon.LoadImage(File.ReadAllBytes(normIconFile));

            var selIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var selIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_selected.png");
            selIcon.LoadImage(File.ReadAllBytes(selIconFile));

            print("*****Adding icon for " + categoryTitle);
            var icon = new Icon(iconName + "Icon", normIcon, selIcon);
            return icon;
        }

 

EDIT: this is a quote from a unity dev on the matter of texture2d.loadimage ... it is there but was moved to code that is inherited by texture2d so still accesible through texture2d

" Texture2D.LoadImage has been moved to a Texture2D extension method ImageConversion.LoadImage: https://docs.unity3d.com/2017.1/Documentation/ScriptReference/ImageConversion.LoadImage.html

Since it is an extension method of Texture2D, you can still use it the same way, and any existing code using it, should compile without changes "

https://forum.unity.com/threads/unityengine-texture2d-loadimage-is-missing.467202/
 

@Fengist - just a thought but is your MPConfig running at startup and if so do all the checks it does run before the category code? .... could be that the reference in the awake section is trying to access the MPConfig but it is either not loaded or the values that are being looked for haven't been grabbed yet

 

Edited by DoctorDavinci
Link to comment
Share on other sites

[ERR 13:28:14.381] Exception handling event onGUIEditorToolbarReady in class KerbalElectricFilter:System.MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
  at MPUtils.BaseFilter.SubCategories () [0x00000] in <filename unknown>:0 
  at EventVoid.Fire () [0x00000] in <filename unknown>:0 

[EXC 13:28:14.383] MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
	MPUtils.BaseFilter.SubCategories ()
	EventVoid.Fire ()
	UnityEngine.Debug:LogException(Exception)
	EventVoid:Fire()
	KSP.UI.Screens.<SetInitialState>c__Iterator1:MoveNext()
	UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
	KSP.UI.Screens.PartCategorizer:Setup()
	EventVoid:Fire()
	KSP.UI.Screens.EditorPanels:ShowPartsList(Action)
	EditorLogic:SelectPanelParts(Boolean)
	EditorLogic:StartEditor(Boolean)
	<Start>c__Iterator0:MoveNext()
	UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

And that's after copying your code exactly and only changing the icon extension string.

All 3 of my icons cause that error as well as KAX which I still have installed.

Let me delete and reinstall KSP and see what happens.

Link to comment
Share on other sites

Reinstalled KSP
Copied the GameData folder back over and ran it
Texture2D.LoadImage error

Removed all of my KSP references from VS 2015
Replace the references pointing to those in the KSP 64 bit folder
Recompiled
My Icons are now there and working using your code.
but
KAX distribution still produced the error and didn't load the icon.

Now I know damned well I told VS to use the references in the KSP game folder.  But it appears it didn't pick up the new ones when I updated KSP and it decided to keep using the ones in the bin/Debug folder (that's my guess).

So, either way it appears that both your solution and the one I floundered into works. If Unity does ever move/remove LoadIcon there is a workaround.

As for KAX, since that's not a fuzzy icon issue, if you want to private me I'll be glad to test any .dll you or Spanner have for KAX and we can stop bombing this thread.

Either way, thanks to both you and @SpannerMonkey(smce)

 

Edited by Fengist
Link to comment
Share on other sites

11 hours ago, Fengist said:

Oh, hate to necro an older thread but I couldn't find anything else on this and it's relevant.

@SpannerMonkey(smce) and I have been having a private chat about the code KAX uses to load it's icon and my attempt to duplicate it.  His code looks like this:


            var normIcon = new Texture2D(64, 64, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_normal.png"); // icon to be present in same folder as dll
            normIcon.LoadImage(File.ReadAllBytes(normIconFile));

It uses the Texture2D.LoadImage.  I can get that code to compile just fine.  However, when I load up KSP and jump into the editor, I get this in the log file:


[ERR 10:01:11.562] Exception handling event onGUIEditorToolbarReady in class KAXFilter:System.MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
  at KAE_Ltd.BaseFilter.SubCategories () [0x00000] in <filename unknown>:0 
  at EventVoid.Fire () [0x00000] in <filename unknown>:0 

[EXC 10:01:11.563] MissingMethodException: Method not found: 'UnityEngine.Texture2D.LoadImage'.
	KAE_Ltd.BaseFilter.SubCategories ()
	EventVoid.Fire ()
	UnityEngine.Debug:LogException(Exception)
	EventVoid:Fire()
	KSP.UI.Screens.<SetInitialState>c__Iterator1:MoveNext()
	UnityEngine.MonoBehaviour:StartCoroutine(IEnumerator)
	KSP.UI.Screens.PartCategorizer:Setup()
	EventVoid:Fire()
	KSP.UI.Screens.EditorPanels:ShowPartsList(Action)
	EditorLogic:SelectPanelParts(Boolean)
	EditorLogic:StartEditor(Boolean)
	<Start>c__Iterator0:MoveNext()
	UnityEngine.SetupCoroutine:InvokeMoveNext(IEnumerator, IntPtr)

and no icon of course.

Spanner however is able to compile that code, run KSP and get  it to load up his icon with no problems.

The only workaround I have found that works on my install is this:


            var normIcon = new Texture2D(32, 32, TextureFormat.RGBA32, false);
            var normIconFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), iconName + "_off.png"); // icon to be present in same folder as dll
            WWW www = new WWW(normIconFile);
            normIcon = www.texture;
            normIcon.Apply();

Now, the next thing is, the only reference I can find in the Unity docs to Texture2D.LoadImage is for version 5.3 and older.  In the latest docs, the Texture2D.LoadImage method doesn't even exist.

And, as per this post, the icons I get on the toolbar are 'fuzzy'

*EDIT*

Ah hah. I fixed the fuzzy buy doing this:


www.LoadImageIntoTexture(normIcon);
//normIcon = www.texture;

but it still doesn't explain why Spanner can get the LoadImage to work and I can't.

Really stupid questions:

  1. Is the project net to .Net 3.5?
  2. You are compiling against the correct version of the game?
  3. You are testing the right version of the game?
Link to comment
Share on other sites

52 minutes ago, linuxgurugamer said:

Really stupid questions:

  1. Is the project net to .Net 3.5?
  2. You are compiling against the correct version of the game?
  3. You are testing the right version of the game?

Yep
That was essentially the problem.  Using references from what I guess was an older version.
Yep

Spanner recompiled the KAX.dll and it then worked on my install.  My guess was that he compiled the distribution with the same .dll's I was compiling with and that's why it was showing that loadicon wasn't a method.  Just coincidence that both his .dll and mine were producing the same error. 

That one link I posted was one where people were getting the same error I was.  I assume it was a bug in the Unity.dll which got fixed.

Link to comment
Share on other sites

  • 9 months later...

Old thread, but leaving a note for future people searching for a solution.

The fuzzy / blurry textures discussed here, are not caused by compression per se but by mipmapping.
The problem can be avoided by understanding how KSP / Unity handles textures when loading them, and making textures encoded and saved in the right format to ensure you get the correct behavior.
The workaround offered above is not needed -- in fact it incurs unnecessary file I/O costs and consumes extra RAM / graphics memory by making essentially a duplicate of the texture when one is already loaded in GameDatabase.

Further details:

 

Edited by cakepie
Link to comment
Share on other sites

This thread is quite old. Please consider starting a new thread rather than reviving this one.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...