Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - AtomicBob

Pages: [1] 2 3 ... 5
NGUI 3 Support / Multiple import when modifying an atlas
« on: March 24, 2016, 04:21:03 PM »
I'm in the process of fixing some paint points for our artists and a few of the issues revolve around updating the NGUI atlas. We've started using crunch compression for our atlas because the quality is acceptable and the size is excellent (2 MB for a 4k atlas, versus 64 MB truecolor and 16 MB compressed). However, the crunch process takes a while, about 80 seconds on some machines.

The problem is that this longer import time is greatly exacerbated by NGUI. When deleting a sprite from the atlas, for example, the atlas is reimported 5 times. I looked into a bit and it looks like the general flow is:
  • Make atlas readable and extract sprites
  • Make atlas non-readable
  • Make atlas readable so it can be encoded to PNG
  • Overwrite the atlas file on disk and refresh assets
  • Make atlas non-readable

It seems only one of these reimports is actually necessary. Do you think you'd be able to optimize this? It appears you can work with raw texture data without marking the texture readable. If so, you can use GetRawTextureData, create a temp texture in memory, and LoadRawTextureData to get the atlas in memory for modifications. Then overwrite the file on disk (which shouldn't require the original file being readable either), and reimport once at the very end.

  1. Importing 'Assets/GUI/Atlas/GUIAtlas.png'
  2. 0. AtlasProcessor.OnPreprocessTexture() at Assets/GUI/Editor/AtlasProcessor.cs:10
  3. 1. UnityEditor.AssetDatabase.ImportAsset()
  4. 2. NGUIEditorTools.MakeTextureReadable() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:457
  5. 3. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:512
  6. 4. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:532
  7. 5. UIAtlasMaker.ExtractSprites() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:493
  8. 6. UIAtlasMaker.OnGUI() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:1013
  10. Importing 'Assets/GUI/Atlas/GUIAtlas.png'
  11. 0. AtlasProcessor.OnPreprocessTexture() at Assets/GUI/Editor/AtlasProcessor.cs:10
  12. 1. UnityEditor.AssetDatabase.ImportAsset()
  13. 2. NGUIEditorTools.MakeTextureAnAtlas() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:499
  14. 3. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:513
  15. 4. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:532
  16. 5. UIAtlasMaker.ExtractSprites() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:530
  17. 6. UIAtlasMaker.OnGUI() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:1013
  19. Importing 'Assets/GUI/Atlas/GUIAtlas.png'
  20. 0. AtlasProcessor.OnPreprocessTexture() at Assets/GUI/Editor/AtlasProcessor.cs:10
  21. 1. UnityEditor.AssetDatabase.ImportAsset()
  22. 2. NGUIEditorTools.MakeTextureReadable() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:457
  23. 3. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:512
  24. 4. UIAtlasMaker.UpdateTexture() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:570
  25. 5. UIAtlasMaker.UpdateAtlas() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:689
  26. 6. UIAtlasMaker.OnGUI() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:1027
  28. Importing 'Assets/GUI/Atlas/GUIAtlas.png'
  29. 0. AtlasProcessor.OnPreprocessTexture() at Assets/GUI/Editor/AtlasProcessor.cs:10
  30. 1. UnityEditor.AssetDatabase.Refresh()
  31. 2. UIAtlasMaker.UpdateTexture() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:582
  32. 3. UIAtlasMaker.UpdateAtlas() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:689
  33. 4. UIAtlasMaker.OnGUI() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:1027
  35. Importing 'Assets/GUI/Atlas/GUIAtlas.png'
  36. 0. AtlasProcessor.OnPreprocessTexture() at Assets/GUI/Editor/AtlasProcessor.cs:10
  37. 1. UnityEditor.AssetDatabase.ImportAsset()
  38. 2. NGUIEditorTools.MakeTextureAnAtlas() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:499
  39. 3. NGUIEditorTools.ImportTexture() at Assets/Plugins/NGUI/Scripts/Editor/NGUIEditorTools.cs:513
  40. 4. UIAtlasMaker.UpdateTexture() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:583
  41. 5. UIAtlasMaker.UpdateAtlas() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:689
  42. 6. UIAtlasMaker.OnGUI() at Assets/Plugins/NGUI/Scripts/Editor/UIAtlasMaker.cs:1027

NGUI 3 Support / Re: UIAtlasMaker exception
« on: March 24, 2016, 03:03:37 PM »
I just tracked down this problem as well and noticed something mildly interesting. According to the documentation

An asset is deemed to be unused if it isn't reached after walking the whole game object hierarchy, including script components. Static variables are also examined.

A quick test seems to confirm this applies to editor scripts like UIAtlasMaker. We're using an older version of NGUI (3.6.5) and can't upgrade this late in a project, so rather than merge in the hack from newer NGUI versions, I just add and remove the temporary textures from a static list. It's still a hack, but it's a bit simpler at least.

NGUI 3 Support / Re: Event Delegate Bug
« on: July 31, 2014, 10:52:49 AM »
Hmm. The only thing I've ever heard of was an issue with methods with default parameters inside a namespace. That used to cause Unity to choke and not allow you to add the script to a GameObject. That was fixed in 4.5. I use default parameters fairly often (usually for callbacks) and haven't run into any issues personally, but I don't use MonoDevelop.

NGUI 3 Support / Re: Event Delegate Bug
« on: July 30, 2014, 01:23:14 PM »
Yea, this one is a bit tricky to explain clearly. What it boils down to is that EventDelegate doesn't support default parameters or intentionally passing null.

I'll do my best to explain fully. There are 2 cases. 1:

You have a method that takes a parameter that is a reference type deriving from System.object. e.g.
  1. public void DoSomething ( Action onFinished )
You want to call this method with an EventDelegate on a UIButton.
You want to pass null for onFinished
You assign the relevant object to the EventDelegate.
You want to pass null so you don't specify the Arg0 target.
An exception will occur because the parameter that actually get's used will be either
  1. (System.void) null
  1. (UnityEngine.Object) null
instead of
  1. (System.Action) null

Supporting this would mean doing something like I posted above. At the end of EventDelegate.Parameter.value:

  1. if ( !expectedType.IsValueType ) return System.Convert.ChangeType(null, expectedType);
  2. return obj;


You have a method that has a default value for the parameter. e.g.
  1. public void DoSomething ( int index = 0 )
You want to call this method with an EventDelegate on a UIButton.
You want to not pass the int and let it use the default value.
You assign the relevant object to the EventDelegate.
You don't want to specify the argument, so you don't specify the Arg0 target.
An exception will occur.

I think to support this you'd have to do a little more reflection to see if the method has default parameters and if it does, invoke the method in a slightly different way.

These can be worked around with an overload for the method, but I wanted to point them out in case you want to support the scenarios. The first one seems very straight forward, though the second one may or may not be worth the effort.

NGUI 3 Support / Re: Feature Requests
« on: July 30, 2014, 10:06:54 AM »
I have in some more important circumstances, but it's not a great way to go, imo. NGUI scripts typically don't lend themselves to subclassing since usually stuff is private and not virtual. That leaves either modifying scripts directly, which means it's a pain to update NGUI, or copy-pasting NGUI code into new scripts, which makes updating a little easier but NGUI changes will have to be merged manually and things might break if changes aren't merged.

I may do it anyway though. Might be worth it on this project.

NGUI 3 Support / Re: Feature Requests
« on: July 29, 2014, 12:23:53 PM »
Added an idea for UIKeyNavigation

NGUI 3 Support / Re: Event Delegate Bug
« on: July 25, 2014, 01:52:03 PM »
I changed EventDelegate.cs:75 from

  1. return obj;


  1. if ( obj != null ) return obj;
  2. if ( expectedType.IsValueType ) return null;
  3. return System.Convert.ChangeType(null, expectedType);

as a quick hack around. I'm not sure if it covers all cases, but it covers mine for the time being.

NGUI 3 Support / Event Delegate Bug
« on: July 25, 2014, 12:31:21 PM »
I have a method Show ( Action onHide = null ) that I call using a UIButton's OnClick delegate. I don't specify any parameter and let the Event Delegate pass null. This works in the first scene that's loaded, but not in subsequent scenes. It looks to be a bug/side-effect of the serialize-deserialize process Unity goes through when changing scenes. The mParameters array has a single element in my case with a value of null and a type of void. The serialization process ends up converting the null element to UnityEngine.Object instead of void. This causes the next invocation to throw an InvalidParameterException.

Reproduction should be very straightforward:
1) Assign a UIButton's OnClick to a method that takes a reference type parameter that doesn't derive from UnityEngine.Object
2) Play a scene and call DontDestroyOnLoad on the button's GameObject
3) Click the button in your first scene (so the EventDelegate caches stuff)
4) Move to another scene
5) Click the button again in the new scene
6) Exception

NGUI 3 Support / Re: Feature Requests
« on: July 12, 2014, 09:34:25 AM »
Saturday bump, as suggested.

NGUI 3 Support / Feature Requests
« on: July 08, 2014, 06:11:41 PM »
While working on a new GUI system for a game, I came across a few things that I thought worthy of mentioning.

  • Support for 'sticky selection' - I have a GUI system that will support a mouse and keyboard and controllers simultaneously. It ended up being problematic that you could potentially clear the current selection with the mouse (e.g. by clicking nothing) and then try to use the controller. With nothing selected UIKeyNavigation doesn't work. Maintaining a selection at all times didn't end up being too hard, but in order to keep things visually consistent I wanted to make sure the selected object is always highlighted as well. I ended up getting this working quite well, but it was a pain in the ass and I had to write a few ugly hacks to do it. Maybe there's already an easy way to do this, but I wasn't able to find it.

  • The ability to treat axes more like buttons for UICamera Vertical and Horizontal. In UICamera, when the vertical and horizontal axes are read there is a hard-coded delay of .25 seconds between sending OnKey events. This works great for holding something down, but the delay is very noticeable if you try to do something like tap down on the dpad repeatedly. The way I solved this is by setting the gravity on an axis to match the sensitivity so the axis value will always go back to zero in a single frame. This allows me to do a simple sign check on the axis to see if it has been pressed this frame. Alternatively, I think a better way would be to watch the axis value and just reset the timer each time it moves closer to 0. This means the user has released the button/axis and the next time it moves away from zero is a new press.

  • Support for non-trigger colliders. I'm integrating GUI into an existing game and the other devs are adamant that 'raycasts hit triggers' stay disabled. NGUI seems to work just fine when I change all my colliders to not be triggers. If there's no other issues involved, this may be as simple as setting auto-generated colliders to match the 'raycasts hit triggers' setting (such as the colliders created for UIPopupLists).

  • OnKey repeating. If I hold the left arrow with a slider selected, it would be nice if it continued to move.

  • Add the rest of the possible notifications to UIForwardEvents. I know it's marked as legacy, but it still provides functionality not found elsewhere (Event Triggers don't forward arguments, and don't call private methods the way UICamera.Notify/SendMessage does). It's missing OnKey, OnDragOver, OnDragOut, OnDragStart, OnDragEnd, and OnTooltip.

  • Ability to set the OnKey step size for UISliders. It's currently hardcoded to .125. I'd like to be able to fine tune it on a per-slider basis.

  • UIKeyNavigation should chain when disabled. Currently, they kind of break if you have dynamically enabled elements and overrides. For example, I have a horizontal skill tree and an 'Apply' button below the tree. Intuitively, I expect that pressing down enough times will take me to the Apply button. The problem is that relative to the leftmost and rightmost items in the skill tree, the Apply button is at an angle greater than 45 degrees, so pressing down won't reach it. So for the entire bottom row of skills, I have the down override set to the Apply button. When any of those bottom skills are disabled (locked, unreachable in the tree) you again can't reach the Apply button from the far left or right skills. It seems like a better algorithm for moving selection would try to move like it currently does, but keep track of disabled UIKeyNavigation if it would be reachable and closest, if no new selection is found to move to, use the disabled one and recalculate from there.

NGUI 3 Support / Re: Small Feature Requests
« on: June 12, 2014, 02:50:08 PM »
One more small one.

It would be nice to be able to define the center for UICenterOnChild. I want to snap children into place, but I want the snap point somewhere other than the center of the panel clipping. I'm doing this in an unsafe way on a project by modifying how UICenterOnChild calculates the center of the relevant panel:

  1. Vector3[] corners = mScrollView.panel.localCorners;
  2. Vector3 panelCenter = (corners[2] + corners[0]) * 0.5f;
  4. //Respect offset
  5. Vector3 offset = new Vector3(
  6.         mScrollView.panel.baseClipRegion.x,
  7.         mScrollView.panel.baseClipRegion.y);
  8. panelCenter = mScrollView.panel.cachedTransform.TransformPoint(panelCenter - offset);

Obviously, this doesn't guarantee the 'center' will actually be inside the clipping at all, that would need a separate field and validation.

NGUI 3 Support / Small Feature Requests
« on: June 09, 2014, 02:48:59 PM »
Just a couple small requests:

1) Editor-only Anchors - I've been making better use of the anchoring system lately and I really like it. Once objects are set up properly, making layout changes is incredibly easy. The only thing I'd like to see different is the ability to completely disable anchoring at runtime. I know they can be set to "OnEnable", but I only use the anchoring in the Editor and I've actually had it cause some small problems with updating anchors OnEnable. Sometimes I want a objects to be positioned or sized based on other objects that they aren't truly 'anchored' to.

2) Automatically resized collider on scroll bar foreground - Currently, the foreground sprite on a scroll bar is 'clipped', not resized. This means the foreground collider is actually the entire scroll bar. It'd be better if the collider matched the sprite. It can be done manually, but it seems like a more intuitive default behavior.

NGUI 3 Support / Re: On Screen Keyboard
« on: May 16, 2014, 12:29:18 PM »
True, and I should be able to use uiInput.SendMessage(ProcessEvents, myEvent) to retain advanced behavior. I may go that route. Thanks.

NGUI 3 Support / Re: On Screen Keyboard
« on: May 15, 2014, 12:17:24 PM »
I'm working on a contract that requires a game on a giant touchscreen run by a Windows machine. There will be no keyboard, but there will be a leaderboard where players can enter initials. If there's a better way, I'm certainly open to ideas.

If I haven't misunderstood, UIInput reads from Input.inputString in Update() and sticks that text in the label. It also listens for Events in OnGUI and processes though, but that seems to only handle stuff like arrow keys, cut, copy, paste, etc.

My current plan is to create my own InputShim that mirrors the interface of Input and relays the calls, but allows me to insert my own stuff when I want. Then I can add

  1. using Input = InputShim;

to UIInput to utilize it, without having to start from scratch or heavily modify UIInput.

NGUI 3 Support / On Screen Keyboard
« on: May 15, 2014, 09:59:44 AM »
I'm attempting to implement an on screen keyboard capable of leveraging NGUIs UIInput. Since NGUI uses the Unity Input class directly, it's difficult to send fake presses through SendMessage or reflection like I was hoping. It seems I'll have to fool Unity itself into handling keyboard events that I create in code.

Anyone have any clever ideas how I would go about doing that?

Pages: [1] 2 3 ... 5