diff --git a/spine-xna/example/data/spineboy.atlas b/spine-xna/example/data/spineboy.atlas index 1f482c0a1..7a1c53f57 100644 --- a/spine-xna/example/data/spineboy.atlas +++ b/spine-xna/example/data/spineboy.atlas @@ -1,166 +1,131 @@ spineboy.png format: RGBA8888 -filter: Linear,Linear +filter: Nearest,Nearest repeat: none -head +eyes rotate: false - xy: 1, 122 + xy: 447, 44 + size: 34, 27 + orig: 34, 27 + offset: 0, 0 + index: -1 +eyes-closed + rotate: true + xy: 483, 37 + size: 34, 27 + orig: 34, 27 + offset: 0, 0 + index: -1 +head + rotate: true + xy: 2, 5 size: 121, 132 orig: 121, 132 offset: 0, 0 index: -1 -torso - rotate: false - xy: 1, 28 - size: 68, 92 - orig: 68, 92 - offset: 0, 0 - index: -1 -left-pant-bottom - rotate: false - xy: 1, 4 - size: 44, 22 - orig: 44, 22 - offset: 0, 0 - index: -1 -right-pant-bottom - rotate: false - xy: 47, 8 - size: 46, 18 - orig: 46, 18 - offset: 0, 0 - index: -1 -right-upper-leg - rotate: false - xy: 71, 50 - size: 44, 70 - orig: 44, 70 - offset: 0, 0 - index: -1 -pelvis - rotate: false - xy: 95, 1 - size: 63, 47 - orig: 63, 47 - offset: 0, 0 - index: -1 -left-upper-leg - rotate: false - xy: 117, 53 - size: 33, 67 - orig: 33, 67 - offset: 0, 0 - index: -1 -right-foot - rotate: false - xy: 160, 224 - size: 67, 30 - orig: 67, 30 - offset: 0, 0 - index: -1 -left-shoulder - rotate: false - xy: 124, 201 - size: 34, 53 - orig: 34, 53 - offset: 0, 0 - index: -1 -left-ankle - rotate: false - xy: 229, 222 - size: 25, 32 - orig: 25, 32 - offset: 0, 0 - index: -1 -left-foot - rotate: false - xy: 160, 192 - size: 65, 30 - orig: 65, 30 - offset: 0, 0 - index: -1 -neck - rotate: false - xy: 124, 171 - size: 34, 28 - orig: 34, 28 - offset: 0, 0 - index: -1 -right-arm - rotate: false - xy: 124, 124 - size: 21, 45 - orig: 21, 45 - offset: 0, 0 - index: -1 -right-ankle - rotate: false - xy: 227, 190 - size: 25, 30 - orig: 25, 30 - offset: 0, 0 - index: -1 -left-hand - rotate: false - xy: 147, 131 - size: 35, 38 - orig: 35, 38 - offset: 0, 0 - index: -1 left-arm - rotate: false - xy: 184, 161 + rotate: true + xy: 382, 40 size: 35, 29 orig: 35, 29 offset: 0, 0 index: -1 -eyes-closed +left-foot rotate: false - xy: 221, 161 - size: 34, 27 - orig: 34, 27 + xy: 205, 2 + size: 65, 30 + orig: 65, 30 offset: 0, 0 index: -1 -right-lower-leg +left-hand rotate: false - xy: 152, 65 - size: 51, 64 - orig: 51, 64 - offset: 0, 0 - index: -1 -right-foot-idle - rotate: false - xy: 184, 131 - size: 53, 28 - orig: 53, 28 + xy: 272, 7 + size: 35, 38 + orig: 35, 38 offset: 0, 0 index: -1 left-lower-leg - rotate: false - xy: 205, 65 + rotate: true + xy: 331, 77 size: 49, 64 orig: 49, 64 offset: 0, 0 index: -1 -right-shoulder +left-shoulder rotate: false - xy: 160, 12 - size: 52, 51 - orig: 52, 51 + xy: 462, 73 + size: 34, 53 + orig: 34, 53 offset: 0, 0 index: -1 -eyes +left-upper-leg + rotate: true + xy: 259, 47 + size: 33, 67 + orig: 33, 67 + offset: 0, 0 + index: -1 +neck rotate: false - xy: 214, 36 - size: 34, 27 - orig: 34, 27 + xy: 382, 10 + size: 34, 28 + orig: 34, 28 + offset: 0, 0 + index: -1 +pelvis + rotate: false + xy: 397, 79 + size: 63, 47 + orig: 63, 47 + offset: 0, 0 + index: -1 +right-arm + rotate: true + xy: 206, 39 + size: 21, 45 + orig: 21, 45 + offset: 0, 0 + index: -1 +right-foot + rotate: false + xy: 136, 2 + size: 67, 30 + orig: 67, 30 offset: 0, 0 index: -1 right-hand rotate: false - xy: 214, 2 + xy: 413, 45 size: 32, 32 orig: 32, 32 offset: 0, 0 index: -1 +right-lower-leg + rotate: false + xy: 206, 62 + size: 51, 64 + orig: 51, 64 + offset: 0, 0 + index: -1 +right-shoulder + rotate: false + xy: 328, 24 + size: 52, 51 + orig: 52, 51 + offset: 0, 0 + index: -1 +right-upper-leg + rotate: true + xy: 259, 82 + size: 44, 70 + orig: 44, 70 + offset: 0, 0 + index: -1 +torso + rotate: false + xy: 136, 34 + size: 68, 92 + orig: 68, 92 + offset: 0, 0 + index: -1 diff --git a/spine-xna/example/data/spineboy.png b/spine-xna/example/data/spineboy.png index b8b493dfd..cc7c12778 100644 Binary files a/spine-xna/example/data/spineboy.png and b/spine-xna/example/data/spineboy.png differ diff --git a/spine-xna/example/src/ExampleGame.cs b/spine-xna/example/src/ExampleGame.cs index 2185a2eb8..fd981d329 100644 --- a/spine-xna/example/src/ExampleGame.cs +++ b/spine-xna/example/src/ExampleGame.cs @@ -69,6 +69,7 @@ namespace Spine { protected override void LoadContent () { skeletonRenderer = new SkeletonRenderer(GraphicsDevice); + skeletonRenderer.PremultipliedAlpha = true; String name = "spineboy"; // "goblins"; diff --git a/spine-xna/src/SkeletonRenderer.cs b/spine-xna/src/SkeletonRenderer.cs index 793875573..68000cc00 100644 --- a/spine-xna/src/SkeletonRenderer.cs +++ b/spine-xna/src/SkeletonRenderer.cs @@ -43,6 +43,10 @@ namespace Spine { BasicEffect effect; RasterizerState rasterizerState; float[] vertices = new float[8]; + BlendState defaultBlendState; + + private bool premultipliedAlpha; + public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } } public SkeletonRenderer (GraphicsDevice device) { this.device = device; @@ -62,8 +66,10 @@ namespace Spine { } public void Begin () { + defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied; + device.RasterizerState = rasterizerState; - device.BlendState = BlendState.AlphaBlend; // spine-xna textures are premultiplied on load, see Util.cs. + device.BlendState = defaultBlendState; effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0); } @@ -83,7 +89,7 @@ namespace Spine { Slot slot = drawOrder[i]; RegionAttachment regionAttachment = slot.Attachment as RegionAttachment; if (regionAttachment != null) { - BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : BlendState.AlphaBlend; + BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : defaultBlendState; if (device.BlendState != blend) { End(); device.BlendState = blend; @@ -93,8 +99,12 @@ namespace Spine { AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject; item.Texture = (Texture2D)region.page.rendererObject; + Color color; float a = skeletonA * slot.A; - Color color = new Color(skeletonR * slot.R * a, skeletonG * slot.G * a, skeletonB * slot.B * a, a); + if (premultipliedAlpha) + color = new Color(skeletonR * slot.R * a, skeletonG * slot.G * a, skeletonB * slot.B * a, a); + else + color = new Color(skeletonR * slot.R, skeletonG * slot.G, skeletonB * slot.B, a); item.vertexTL.Color = color; item.vertexBL.Color = color; item.vertexBR.Color = color; diff --git a/spine-xna/src/Util.cs b/spine-xna/src/Util.cs index 61c9cbea3..7e5900df7 100644 --- a/spine-xna/src/Util.cs +++ b/spine-xna/src/Util.cs @@ -71,56 +71,7 @@ namespace Spine { #endif static public Texture2D LoadTexture (GraphicsDevice device, Stream input) { - Texture2D file = Texture2D.FromStream(device, input); - - // Setup a render target to hold our final texture which will have premulitplied alpha values - RenderTarget2D result = new RenderTarget2D(device, file.Width, file.Height); - device.SetRenderTarget(result); - device.Clear(Color.Black); - - // Multiply each color by the source alpha, and write in just the color values into the final texture - BlendState blendColor = new BlendState(); - blendColor.ColorWriteChannels = ColorWriteChannels.Red | ColorWriteChannels.Green | ColorWriteChannels.Blue; - blendColor.AlphaDestinationBlend = Blend.Zero; - blendColor.ColorDestinationBlend = Blend.Zero; - blendColor.AlphaSourceBlend = Blend.SourceAlpha; - blendColor.ColorSourceBlend = Blend.SourceAlpha; - - SpriteBatch spriteBatch = new SpriteBatch(device); - spriteBatch.Begin(SpriteSortMode.Immediate, blendColor); - spriteBatch.Draw(file, file.Bounds, Color.White); - spriteBatch.End(); - - // Now copy over the alpha values from the PNG source texture to the final one, without multiplying them - BlendState blendAlpha = new BlendState(); - blendAlpha.ColorWriteChannels = ColorWriteChannels.Alpha; - blendAlpha.AlphaDestinationBlend = Blend.Zero; - blendAlpha.ColorDestinationBlend = Blend.Zero; - blendAlpha.AlphaSourceBlend = Blend.One; - blendAlpha.ColorSourceBlend = Blend.One; - - spriteBatch.Begin(SpriteSortMode.Immediate, blendAlpha); - spriteBatch.Draw(file, file.Bounds, Color.White); - spriteBatch.End(); - - // Release the GPU back to drawing to the screen. - device.SetRenderTarget(null); - spriteBatch.Dispose(); - file.Dispose(); - -#if IOS - return result as Texture2D; -#else - // RenderTarget2D are volatile and will be lost on screen resolution changes. - // So instead of using this directly, we create a non-voliate Texture2D. - // This is computationally slower, but should be safe as long as it is done on load. - Texture2D resultTexture = new Texture2D(device, file.Width, file.Height); - Color[] resultContent = new Color[Convert.ToInt32(file.Width * file.Height)]; - result.GetData(resultContent); - resultTexture.SetData(resultContent); - result.Dispose(); // Dispose of the RenderTarget2D immediately. - return resultTexture; -#endif + return Texture2D.FromStream(device, input); } } }