2 using Microsoft.Xna.Framework;
3 using Microsoft.Xna.Framework.Graphics;
5 using System.Collections.Generic;
11 partial class DeformableSprite
13 private static List<DeformableSprite> list =
new List<DeformableSprite>();
15 private bool initialized =
false;
17 private int triangleCount;
19 private VertexBuffer vertexBuffer, flippedVertexBuffer;
20 private IndexBuffer indexBuffer;
22 private Vector2 uvTopLeft, uvBottomRight;
23 private Vector2 uvTopLeftFlipped, uvBottomRightFlipped;
25 private Vector2[] deformAmount;
26 private int deformArrayWidth, deformArrayHeight;
28 private int subDivX, subDivY;
30 private static Effect effect;
33 get {
return effect; }
38 private Point spritePos;
39 private Point spriteSize;
41 partial
void InitProjSpecific(XElement element,
int? subdivisionsX,
int? subdivisionsY,
bool lazyLoad,
bool invert)
45 effect = EffectLoader.Load(
"Effects/deformshader");
51 Vector2 subdivisionsInXml = element.GetAttributeVector2(
"subdivisions", Vector2.One);
52 subDivX = subdivisionsX ?? (int)subdivisionsInXml.X;
53 subDivY = subdivisionsY ?? (
int)subdivisionsInXml.Y;
55 if (subDivX <= 0 || subDivY <= 0)
57 throw new ArgumentException(
"Deformable sprites must have one or more subdivisions on each axis.");
70 if (!initialized) { Init(); }
75 if (initialized) {
return; }
80 if (!existing.initialized || existing ==
this) {
continue; }
84 existing.subDivX == subDivX &&
85 existing.subDivY == subDivY &&
88 vertexBuffer = existing.vertexBuffer;
89 flippedVertexBuffer = existing.flippedVertexBuffer;
90 indexBuffer = existing.indexBuffer;
91 triangleCount = existing.triangleCount;
92 uvTopLeft = existing.uvTopLeft;
93 uvBottomRight = existing.uvBottomRight;
94 uvTopLeftFlipped = existing.uvTopLeftFlipped;
95 uvBottomRightFlipped = existing.uvBottomRightFlipped;
99 { Vector2.Zero, Vector2.Zero },
100 { Vector2.Zero, Vector2.Zero }
108 SetupVertexBuffers();
113 private void SetupVertexBuffers()
119 uvTopLeft = Vector2.Divide(pos.ToVector2(), textureSize);
120 uvBottomRight = Vector2.Divide((pos + size).ToVector2(), textureSize);
121 uvTopLeftFlipped = Vector2.Divide(
new Vector2(pos.X + size.X, pos.Y), textureSize);
122 uvBottomRightFlipped = Vector2.Divide(
new Vector2(pos.X, pos.Y + size.Y), textureSize);
125 var temp = uvBottomRightFlipped;
126 uvBottomRightFlipped = uvTopLeftFlipped;
127 uvTopLeftFlipped = temp;
130 for (
int i = 0; i < 2; i++)
134 var vertices =
new VertexPositionColorTexture[(subDivX + 1) * (subDivY + 1)];
135 for (
int x = 0; x <= subDivX; x++)
137 for (
int y = 0; y <= subDivY; y++)
140 Vector2 relativePos =
new Vector2(x / (
float)subDivX, y / (
float)subDivY);
142 Vector2 uvCoord = flip ?
143 uvTopLeftFlipped + (uvBottomRightFlipped - uvTopLeftFlipped) * relativePos :
144 uvTopLeft + (uvBottomRight - uvTopLeft) * relativePos;
146 vertices[x + y * (subDivX + 1)] =
new VertexPositionColorTexture(
149 textureCoordinate: uvCoord);
155 if (flippedVertexBuffer !=
null && flippedVertexBuffer.VertexCount != vertices.Length)
157 flippedVertexBuffer.Dispose();
158 flippedVertexBuffer =
null;
160 if (flippedVertexBuffer ==
null)
162 flippedVertexBuffer =
new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.None);
164 flippedVertexBuffer.SetData(vertices);
168 if (vertexBuffer !=
null && vertexBuffer.VertexCount != vertices.Length)
170 vertexBuffer.Dispose();
173 if (vertexBuffer ==
null)
175 vertexBuffer =
new VertexBuffer(GameMain.Instance.GraphicsDevice, VertexPositionColorTexture.VertexDeclaration, vertices.Length, BufferUsage.None);
177 vertexBuffer.SetData(vertices);
185 private void SetupIndexBuffer()
187 triangleCount = subDivX * subDivY * 2;
188 var indices =
new ushort[triangleCount * 3];
190 for (
int i = 0; i < triangleCount / 2; i++)
192 indices[i * 6] = (ushort)(i + offset + 1);
193 indices[i * 6 + 1] = (ushort)(i + offset + (subDivX + 1) + 1);
194 indices[i * 6 + 2] = (ushort)(i + offset + (subDivX + 1));
196 indices[i * 6 + 3] = (ushort)(i + offset);
197 indices[i * 6 + 4] = (ushort)(i + offset + 1);
198 indices[i * 6 + 5] = (ushort)(i + offset + (subDivX + 1));
200 if ((i + 1) % subDivX == 0) offset++;
203 indexBuffer?.Dispose();
206 indexBuffer =
new IndexBuffer(GameMain.Instance.GraphicsDevice, IndexElementSize.SixteenBits, indices.Length, BufferUsage.None);
207 indexBuffer.SetData(indices);
211 { Vector2.Zero, Vector2.Zero },
212 { Vector2.Zero, Vector2.Zero }
221 public void Deform(Func<Vector2, Vector2> deformFunction)
223 if (!initialized) { Init(); }
225 var deformAmount =
new Vector2[subDivX + 1, subDivY + 1];
226 for (
int x = 0; x <= subDivX; x++)
228 for (
int y = 0; y <= subDivY; y++)
230 deformAmount[x, y] = deformFunction(
new Vector2(x / (
float)subDivX, y / (
float)subDivY));
238 if (!initialized) { Init(); }
240 deformArrayWidth = deform.GetLength(0);
241 deformArrayHeight = deform.GetLength(1);
242 if (deformAmount ==
null || deformAmount.Length != deformArrayWidth * deformArrayHeight)
244 deformAmount =
new Vector2[deformArrayWidth * deformArrayHeight];
246 for (
int x = 0; x < deformArrayWidth; x++)
248 for (
int y = 0; y < deformArrayHeight; y++)
250 deformAmount[x + y * deformArrayWidth] = deform[x, y];
259 { Vector2.Zero, Vector2.Zero },
260 { Vector2.Zero, Vector2.Zero }
264 public Matrix
GetTransform(Vector3 pos, Vector2 origin,
float rotate, Vector2 scale)
266 if (!initialized) { Init(); }
269 Matrix.CreateTranslation(-origin.X, -origin.Y, 0) *
270 Matrix.CreateScale(scale.X, -scale.Y, 1.0f) *
271 Matrix.CreateRotationZ(-rotate) *
272 Matrix.CreateTranslation(pos);
275 public void Draw(
Camera cam, Vector3 pos, Vector2 origin,
float rotate, Vector2 scale, Color color,
bool mirror =
false,
bool invert =
false)
278 if (!initialized) { Init(); }
283 SetupVertexBuffers();
287 effect.Parameters[
"TextureSampler+xTexture"].SetValue(
Sprite.
Texture);
292 Matrix matrix =
GetTransform(pos, origin, rotate, scale);
295 effect.Parameters[
"tintColor"].SetValue(color.ToVector4());
296 effect.Parameters[
"deformArray"].SetValue(deformAmount);
297 effect.Parameters[
"deformArrayWidth"].SetValue(deformArrayWidth);
298 effect.Parameters[
"deformArrayHeight"].SetValue(deformArrayHeight);
303 effect.Parameters[
"uvTopLeft"].SetValue(mirror ? uvTopLeftFlipped : uvTopLeft);
304 effect.Parameters[
"uvBottomRight"].SetValue(mirror ? uvBottomRightFlipped : uvBottomRight);
305 effect.GraphicsDevice.SetVertexBuffer(mirror ? flippedVertexBuffer : vertexBuffer);
306 effect.GraphicsDevice.Indices = indexBuffer;
307 effect.CurrentTechnique.Passes[0].Apply();
308 effect.GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, triangleCount);
321 if (otherSprite.vertexBuffer == vertexBuffer)
return;
324 vertexBuffer?.Dispose();
326 flippedVertexBuffer?.Dispose();
327 flippedVertexBuffer =
null;
328 indexBuffer?.Dispose();
342 new GUITextBlock(
new RectTransform(
new Point(container.Rect.Width, (
int)(60 * GUI.Scale)), container.RectTransform) { IsFixedSize = true },
343 "Sprite Deformations", textAlignment: Alignment.BottomCenter, font: GUIStyle.LargeFont);
345 var resolutionField = GUI.CreatePointField(
new Point(subDivX + 1, subDivY + 1), (
int)(30 * GUI.Scale),
"Resolution", container.RectTransform,
346 "How many vertices the deformable sprite has on the x and y axes. Larger values make the deformations look smoother, but are more performance intensive.");
347 resolutionField.RectTransform.IsFixedSize =
true;
359 if (xField !=
null)
break;
364 xField.OnValueChanged = (numberInput) => { ChangeResolution(); };
365 yField.MinValueInt = 2;
367 yField.OnValueChanged = (numberInput) => { ChangeResolution(); };
369 void ChangeResolution()
371 subDivX = xField.IntValue - 1;
372 subDivY = yField.IntValue - 1;
376 deformation.
SetResolution(
new Point(xField.IntValue, yField.IntValue));
378 SetupVertexBuffers();
385 inGame:
false, showName:
true, titleFont: GUIStyle.SubHeadingFont);
386 deformEditor.RectTransform.MinSize =
new Point(deformEditor.Rect.Width, deformEditor.Rect.Height);
389 var deformationDD =
new GUIDropDown(
new RectTransform(
new Point(container.Rect.Width, 30), container.RectTransform),
"Add new sprite deformation");
390 deformationDD.OnSelected = (selected, userdata) =>
393 deformationDD.Text =
"Add new sprite deformation";
399 deformationDD.AddItem(deformationType, deformationType);
402 container.RectTransform.Resize(
new Point(
403 container.Rect.Width, container.Children.Sum(c => c.Rect.Height + container.AbsoluteSpacing)),
false);
405 container.RectTransform.MinSize =
new Point(0, container.Rect.Height);
406 container.RectTransform.MaxSize =
new Point(
int.MaxValue, container.Rect.Height);
407 container.RectTransform.IsFixedSize =
true;
408 container.Recalculate();
IEnumerable< GUIComponent > GetAllChildren()
Returns all child elements in the hierarchy.
RectTransform RectTransform