This project is read-only.

CCTexture2D - Load texture from PNG ( not XNB )

Topics: Windows Phone 8
Sep 26, 2013 at 10:07 AM
Cocos2D-xna has Zlib library to decode PNG image to raw data but method "FromStream" in Texture.cs from MonoGame said that "NotImplementedException".

I downloaded a PNG image and create a CCTexture2D instance successful. Can you implement this method in Cocos2d-xna?
Oct 1, 2013 at 4:26 PM
The "FromStream" method of pulling raw images should work. We use this technique to create the atlas for the stats labels.

If you can post actual code of how you are finding the exception, that would help.
Oct 2, 2013 at 4:10 AM
Edited Oct 2, 2013 at 4:29 AM
NotImplementedException occurs in:
public static Texture2D FromStream(GraphicsDevice graphicsDevice, Stream stream)
        {
                 ...
                 ...
                 ...
                 
                 #elif WINDOWS_PHONE
                        throw new NotImplementedException();
                 ...
                 ...
I found that StatsLabel's texture create by method CCTextureCache.AddImage will throw this Exception but catched in CCDirector
Oct 2, 2013 at 6:46 AM
Oct 2, 2013 at 7:51 AM
Oct 6, 2013 at 12:43 AM
Edited Oct 6, 2013 at 12:58 AM
Oct 8, 2013 at 7:56 AM
Hi oxosi,
 Thank oxosi for this solution ( JPEG decoding  instead of PNG ) but i think these solution should be implemented in MonoGame develop branch. Currently, i have to handle PNG decoding in my own class.
Jan 18, 2014 at 5:27 PM
Anyone still experiencing issues with this?

I am unable to load raw assets (PNG) because of an invalid cross-thread access exception that is thrown by this code found in Texture2D's FromStream method:
            Threading.BlockOnUIThread(() =>
            {
                // Note that contrary to the method name this works for both JPEG and PNGs.
                writableBitmap = Microsoft.Phone.PictureDecoder.DecodeJpeg(stream);
            });

System.UnauthorizedAccessException: Invalid cross-thread access.
at MS.Internal.XcpImports.CheckThread()
at System.Windows.DependencyObject..ctor(UInt32 nativeTypeIndex, IntPtr constructDO)
at System.Windows.Media.Imaging.WriteableBitmap..ctor(Int32 pixelWidth, Int32 pixelHeight)
at Microsoft.Phone.PictureDecoder.DecodeJpegInternal(Stream source, Int32 maxPixelWidth, Int32 maxPixelHeight)
at Microsoft.Phone.PictureDecoder.DecodeJpeg(Stream source)
at Microsoft.Xna.Framework.Graphics.Texture2D.<>c__DisplayClass4.<FromStream>b__2()
at Microsoft.Xna.Framework.Threading.BlockOnUIThread(Action action)
at Microsoft.Xna.Framework.Graphics.Texture2D.FromStream(GraphicsDevice graphicsDevice, Stream stream)


I am able to load XNBs just fine, but want to avoid those since converting spritesheets to XNB results in them becoming huge (16MB). It seems simpler to just load the raw assets (a PNG spritesheet), but this exception is preventing me from doing so.

Thanks for any assistance.
Jan 19, 2014 at 5:13 PM
I just ran the Texture tests on Windows Phone 8 and the GL Clamp test worked. This test loads a PNG file using CCSprite("foo.png"). Since this path works, I know that texture.FromStream() works for us.

I don't see a Cocos2D-XNA path in your stack trace. It would seem that you are loading the Texture2D directly through MonoGame instead of using CCTexture2D using the shared texture cache. I can't help you there. We strongly urge you to stay within Cocos2D-XNA when loading content, especially textures.

Also make sure you are using the MonoGame that we have forked. We test and tune that version to work properly with Cocos2D-XNA.
Jan 19, 2014 at 7:47 PM
Edited Jan 19, 2014 at 7:58 PM
I am actually running this through Cocos2D-XNA and not directly through MonoGame's Texture2d. This is the line of code I'm using to try to load my PNG spritesheet (found in my CCLayer code):
        CCTexture2D wheelSheet = CCTextureCache.SharedTextureCache.AddImage("Wheel\\Wheel.png");
//Note, I've tried this with and without the .PNG extension and they both fail with the same exception.

Here is a more complete call stack, where you can see I'm calling through CCTexture2D:
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Graphics.Texture2D.FromStream(Microsoft.Xna.Framework.Graphics.GraphicsDevice graphicsDevice, System.IO.Stream stream) Line 848  C#
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Content.ContentManager.ReadRawAsset<Microsoft.Xna.Framework.Graphics.Texture2D>(string assetName, string originalAssetName) Line 393 C#
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Content.ContentManager.ReadAsset<Microsoft.Xna.Framework.Graphics.Texture2D>(string assetName, System.Action<System.IDisposable> recordDisposableObject) Line 336    C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.InternalLoad<Microsoft.Xna.Framework.Graphics.Texture2D>(string assetName, string path, bool weakReference) Line 278   C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.Load<Microsoft.Xna.Framework.Graphics.Texture2D>(string assetName, bool weakReference) Line 230    C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.TryLoad<Microsoft.Xna.Framework.Graphics.Texture2D>(string assetName, bool weakReference) Line 166 C#
cocos2d-xna.DLL!Cocos2D.CCTexture2D.InitWithFile(string file) Line 716  C#
cocos2d-xna.DLL!Cocos2D.CCTextureCache.AddImage(string fileimage) Line 140 C#
I did a fresh pull of the entire repository via Git and updating the submodules per the instructions, so I'm assuming that would include the version of MonoGame that is forked.

What test are you finding to run for this? I searched the entire repository and can't find any reference to foo.png.

Thanks again for any help.
Jan 19, 2014 at 7:52 PM
BTW, another interesting item to note is that this commit from RCGame for MonoGame worked in loading the PNG if I manually update my MonoGame Texture2D:
https://github.com/RCGame/MonoGame/commit/3773837d81dcedb28195bc43647f27c8c029e05b

But then I see that you made a more recent commit in the Cocos2d-XNA branch to update that code to fix a deadlock on resume in WP8 when using Texture from stream:
https://github.com/Cocos2DXNA/MonoGame/commit/1dc1738ec64e04eaf5af16700ae06a5c6767dd6d

The previous version works in loading a PNG for me, but the latest update to the forked MonoGame Texture2D that uses Threading./BlockOnUIThread (instead of Deployment.Current.Dispatcher.BeginInvoke) seems to not work.
Jan 20, 2014 at 1:34 AM
The test case is the "Texture" test and in there search for anything that ends with .png and you will see the GL Clamp test uses a PNG. file which is loaded successfully.

The texture code in our fork should pass through the current dispatcher - we got rid of the explicit "UI Thread" notion because it doesn't work on Windows Xaml.

Our version of BlockOnUIThread uses the current deployment object (the dispatcher) for the lock.

https://github.com/Cocos2DXNA/MonoGame/commit/1ff733b95aa30d57529981ce56ec402b2af54451

Line 154 - you see that for windows phone we are explicitly uses the dispatcher object and not the UI thread.
Jan 20, 2014 at 5:27 AM
Thanks - looks like running the standard git commands as listed here:
https://github.com/Cocos2DXNA/cocos2d-xna/

Does not pull down the develop branch of MonoGame? It seems to pull master, which doesn't have all of these recent changes in it.

I pulled everything down like this:
git clone https://github.com/Cocos2DXNA/cocos2d-xna.git
cd Cocos2DXNA
git submodule init
git submodule update
cd MonoGame
git submodule init
git submodule update ThirdParty/Libs

Is this not the correct way to pull everything needed for a brand new Cocos2d-xna project?

Thanks.
Jan 20, 2014 at 7:19 AM
the way you list is the way that I do a new clone of the project.
Jan 22, 2014 at 6:56 AM
Thanks totallyevil. Just to close the loop on this thread I did have to do the following to get this working:
  1. Follow the instructions for a new clone
  2. Delete the contents of the cocos2d-xna/MonoGame folder
  3. replace with the contents of the develop branch of the MonoGame fork within Cocos2d-XNA
  4. Copy/replace the latest SharpDX libs (MonoGame/ThirdParty/Libs/SharpDX)
  5. Manually edit the MonoGame.Framework.WindowsPhone.csproj file to add the following (which is not present in the original version that is pulled):
<ItemGroup Condition=" '$(Platform)' == 'x86' ">
<Reference Include="SharpDX">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.Direct3D11">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.Direct3D11.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.DXGI">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.DXGI.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.MediaFoundation">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.MediaFoundation.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.WP8">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.WP8.winmd</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.XAudio2">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\x86\SharpDX.XAudio2.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
</ItemGroup>
<ItemGroup Condition=" '$(Platform)' == 'ARM' ">
<Reference Include="SharpDX">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.Direct3D11">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.Direct3D11.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.DXGI">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.DXGI.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.MediaFoundation">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.MediaFoundation.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.WP8">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.WP8.winmd</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
<Reference Include="SharpDX.XAudio2">
  <HintPath>..\ThirdParty\Libs\SharpDX\Windows Phone\ARM\SharpDX.XAudio2.dll</HintPath>
  <SpecificVersion>False</SpecificVersion>
</Reference>
</ItemGroup>

That was the only way I could get a PNG spritesheet to load as well as to be able to play back sound effects.

Thanks.
Jan 22, 2014 at 4:51 PM
That looks like you are still on the master branch of MonoGame.

The default branch for MonoGame is develop. If you clone MonoGame then it should clone the develop branch. If you are using the mono/MonoGame repository, then WP8 may not work properly for you. Our fork is a few commits ahead of the upstream.

Make sure you are using the latest version of git. On windows there are two git installations, one for the core git client, and one for the gi UI client, e.g. TortoiseGIT.
git clone https://github.com/Cocos2DXNA/cocos2d-xna
cd cocos2d-xna
git submodule update --init
cd MonoGame
git co develop
git pull
That should get you on the develop branch of MonoGame from our fork. This is how our automated build bot does the nightly build of cocos2d-xna.
Jan 25, 2014 at 1:18 AM
Thanks for the help again - I was actually on the forked branch of MonoGame (for Cocos2d-XNA) but not on the develop branch, but the master. I've updated that and things are working better, however now that I'm just loading my content as PNG (and I have plist and CCBI files) things are working but I see all sorts of exceptions in the debug output. Looks like it's trying to load every single piece of content as an XNB first - for e.g. it will try to find "wheel.plist.xnb" even though my content file is just wheel.plist.

I'm getting dozens of these:
A first chance exception of type 'System.IO.FileNotFoundException' occurred in MonoGame.Framework.DLL
A first chance exception of type 'Microsoft.Xna.Framework.Content.ContentLoadException' occurred in MonoGame.Framework.DLL

When I look at the stack trace and debug it into the MonoGame.Framework.WindowsPhone project I see it trying to load them as XNBs first.
Call stack:
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Content.ContentLoadException.ContentLoadException(string message, System.Exception innerException) Line 56 C#
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Content.ContentManager.OpenStream(string assetName) Line 258 C#
MonoGame.Framework.DLL!Microsoft.Xna.Framework.Content.ContentManager.ReadAsset<Cocos2D.PlistDocument>(string assetName, System.Action<System.IDisposable> recordDisposableObject) Line 300 C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.InternalLoad<Cocos2D.PlistDocument>(string assetName, string path, bool weakReference) Line 278    C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.Load<Cocos2D.PlistDocument>(string assetName, bool weakReference) Line 230 C#
cocos2d-xna.DLL!Cocos2D.CCContentManager.Load<Cocos2D.PlistDocument>(string assetName) Line 185 C#
cocos2d-xna.DLL!Cocos2D.CCSpriteFrameCache.AddSpriteFramesWithFile(string pszPlist) Line 192    C#
cocos2d-xna.DLL!Cocos2D.CCNodeLoader.ParsePropTypeSpriteFrame(Cocos2D.CCNode node, Cocos2D.CCNode parent, Cocos2D.CCBReader reader, string propertyName) Line 605   C#
cocos2d-xna.DLL!Cocos2D.CCNodeLoader.ParseProperties(Cocos2D.CCNode node, Cocos2D.CCNode parent, Cocos2D.CCBReader reader) Line 245 C#
cocos2d-xna.DLL!Cocos2D.CCBReader.ReadNodeGraph(Cocos2D.CCNode parent) Line 1000    C#
cocos2d-xna.DLL!Cocos2D.CCBReader.ReadNodeGraph(Cocos2D.CCNode parent) Line 1119    C#
cocos2d-xna.DLL!Cocos2D.CCBReader.ReadFileWithCleanUp(bool bCleanUp, System.Collections.Generic.Dictionary<Cocos2D.CCNode,Cocos2D.CCBAnimationManager> am) Line 697 C#
cocos2d-xna.DLL!Cocos2D.CCBReader.ReadNodeGraphFromData(byte[] bytes, object owner, Cocos2D.CCSize parentSize) Line 359 C#
cocos2d-xna.DLL!Cocos2D.CCBReader.ReadNodeGraphFromFile(string fileName, object owner, Cocos2D.CCSize parentSize) Line 341  C#
cocos2d-xna.DLL!Cocos2D.CCBReader.CreateSceneWithNodeGraphFromFile(string fileName, object owner, Cocos2D.CCSize parentSize) Line 401   C#

I'm also using CocosBuilder scene files (CCBI).
Is there any way to turn off the XNB logic completely, or is this considered "normal" behavior?

Thanks!
Jan 27, 2014 at 7:09 AM
it is normal behavior, but it could likely be disabled.