mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
spine-xna no longer premultiplies alpha on load. Do it when packing the atlas.
This is just simpler all around. The renderer has a setting to know if premultiplied is being used. #121
This commit is contained in:
parent
1f3dceed40
commit
6f2cc72aaf
@ -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
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 60 KiB |
@ -69,6 +69,7 @@ namespace Spine {
|
||||
|
||||
protected override void LoadContent () {
|
||||
skeletonRenderer = new SkeletonRenderer(GraphicsDevice);
|
||||
skeletonRenderer.PremultipliedAlpha = true;
|
||||
|
||||
String name = "spineboy"; // "goblins";
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user