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
|
spineboy.png
|
||||||
format: RGBA8888
|
format: RGBA8888
|
||||||
filter: Linear,Linear
|
filter: Nearest,Nearest
|
||||||
repeat: none
|
repeat: none
|
||||||
head
|
eyes
|
||||||
rotate: false
|
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
|
size: 121, 132
|
||||||
orig: 121, 132
|
orig: 121, 132
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
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
|
left-arm
|
||||||
rotate: false
|
rotate: true
|
||||||
xy: 184, 161
|
xy: 382, 40
|
||||||
size: 35, 29
|
size: 35, 29
|
||||||
orig: 35, 29
|
orig: 35, 29
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
eyes-closed
|
left-foot
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 221, 161
|
xy: 205, 2
|
||||||
size: 34, 27
|
size: 65, 30
|
||||||
orig: 34, 27
|
orig: 65, 30
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
right-lower-leg
|
left-hand
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 152, 65
|
xy: 272, 7
|
||||||
size: 51, 64
|
size: 35, 38
|
||||||
orig: 51, 64
|
orig: 35, 38
|
||||||
offset: 0, 0
|
|
||||||
index: -1
|
|
||||||
right-foot-idle
|
|
||||||
rotate: false
|
|
||||||
xy: 184, 131
|
|
||||||
size: 53, 28
|
|
||||||
orig: 53, 28
|
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
left-lower-leg
|
left-lower-leg
|
||||||
rotate: false
|
rotate: true
|
||||||
xy: 205, 65
|
xy: 331, 77
|
||||||
size: 49, 64
|
size: 49, 64
|
||||||
orig: 49, 64
|
orig: 49, 64
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
right-shoulder
|
left-shoulder
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 160, 12
|
xy: 462, 73
|
||||||
size: 52, 51
|
size: 34, 53
|
||||||
orig: 52, 51
|
orig: 34, 53
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
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
|
rotate: false
|
||||||
xy: 214, 36
|
xy: 382, 10
|
||||||
size: 34, 27
|
size: 34, 28
|
||||||
orig: 34, 27
|
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
|
offset: 0, 0
|
||||||
index: -1
|
index: -1
|
||||||
right-hand
|
right-hand
|
||||||
rotate: false
|
rotate: false
|
||||||
xy: 214, 2
|
xy: 413, 45
|
||||||
size: 32, 32
|
size: 32, 32
|
||||||
orig: 32, 32
|
orig: 32, 32
|
||||||
offset: 0, 0
|
offset: 0, 0
|
||||||
index: -1
|
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 () {
|
protected override void LoadContent () {
|
||||||
skeletonRenderer = new SkeletonRenderer(GraphicsDevice);
|
skeletonRenderer = new SkeletonRenderer(GraphicsDevice);
|
||||||
|
skeletonRenderer.PremultipliedAlpha = true;
|
||||||
|
|
||||||
String name = "spineboy"; // "goblins";
|
String name = "spineboy"; // "goblins";
|
||||||
|
|
||||||
|
|||||||
@ -43,6 +43,10 @@ namespace Spine {
|
|||||||
BasicEffect effect;
|
BasicEffect effect;
|
||||||
RasterizerState rasterizerState;
|
RasterizerState rasterizerState;
|
||||||
float[] vertices = new float[8];
|
float[] vertices = new float[8];
|
||||||
|
BlendState defaultBlendState;
|
||||||
|
|
||||||
|
private bool premultipliedAlpha;
|
||||||
|
public bool PremultipliedAlpha { get { return premultipliedAlpha; } set { premultipliedAlpha = value; } }
|
||||||
|
|
||||||
public SkeletonRenderer (GraphicsDevice device) {
|
public SkeletonRenderer (GraphicsDevice device) {
|
||||||
this.device = device;
|
this.device = device;
|
||||||
@ -62,8 +66,10 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Begin () {
|
public void Begin () {
|
||||||
|
defaultBlendState = premultipliedAlpha ? BlendState.AlphaBlend : BlendState.NonPremultiplied;
|
||||||
|
|
||||||
device.RasterizerState = rasterizerState;
|
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);
|
effect.Projection = Matrix.CreateOrthographicOffCenter(0, device.Viewport.Width, device.Viewport.Height, 0, 1, 0);
|
||||||
}
|
}
|
||||||
@ -83,7 +89,7 @@ namespace Spine {
|
|||||||
Slot slot = drawOrder[i];
|
Slot slot = drawOrder[i];
|
||||||
RegionAttachment regionAttachment = slot.Attachment as RegionAttachment;
|
RegionAttachment regionAttachment = slot.Attachment as RegionAttachment;
|
||||||
if (regionAttachment != null) {
|
if (regionAttachment != null) {
|
||||||
BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : BlendState.AlphaBlend;
|
BlendState blend = slot.Data.AdditiveBlending ? BlendState.Additive : defaultBlendState;
|
||||||
if (device.BlendState != blend) {
|
if (device.BlendState != blend) {
|
||||||
End();
|
End();
|
||||||
device.BlendState = blend;
|
device.BlendState = blend;
|
||||||
@ -93,8 +99,12 @@ namespace Spine {
|
|||||||
AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject;
|
AtlasRegion region = (AtlasRegion)regionAttachment.RendererObject;
|
||||||
item.Texture = (Texture2D)region.page.rendererObject;
|
item.Texture = (Texture2D)region.page.rendererObject;
|
||||||
|
|
||||||
|
Color color;
|
||||||
float a = skeletonA * slot.A;
|
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.vertexTL.Color = color;
|
||||||
item.vertexBL.Color = color;
|
item.vertexBL.Color = color;
|
||||||
item.vertexBR.Color = color;
|
item.vertexBR.Color = color;
|
||||||
|
|||||||
@ -71,56 +71,7 @@ namespace Spine {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static public Texture2D LoadTexture (GraphicsDevice device, Stream input) {
|
static public Texture2D LoadTexture (GraphicsDevice device, Stream input) {
|
||||||
Texture2D file = Texture2D.FromStream(device, input);
|
return 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user