fna-workbench

fna-workbench Commit Details


Date:2016-02-05 11:47:52 (9 years 7 months ago)
Author:Ethan Lee
Branch:master
Commit:eb6291126466fd2f12254eb7f8fa22e7e1963f4e
Parents: 6d2d2abe6dc0827c726548641a236d22b25ec726
Message:Optimize vertex sprite calculation

Changes:

File differences

src/Graphics/SpriteBatch.cs
4646
4747
4848
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
4965
5066
5167
......
108124
109125
110126
127
128
129
130
111131
112132
113133
......
299319
300320
301321
302
322
323
303324
304325
305326
......
323344
324345
325346
326
347
348
327349
328350
329351
......
352374
353375
354376
355
377
378
356379
357380
358381
......
381404
382405
383406
384
407
408
385409
386410
387411
......
404428
405429
406430
407
431
432
408433
409434
410435
......
428453
429454
430455
431
456
457
432458
433459
434460
......
456482
457483
458484
459
485
486
460487
461488
462489
......
628655
629656
630657
631
658
659
632660
633661
634662
......
791819
792820
793821
794
822
823
795824
796825
797826
......
813842
814843
815844
816
845
846
817847
818848
819849
......
821851
822852
823853
824
825
854
855
856
857
858
826859
827860
828
829
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
830877
831
832
878
879
833880
834
835881
836882
837883
838
839
840
841
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
842917
843918
844
845
846
847
848
849
850
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
851939
852
853940
854941
855
942
943
944
945
946
947
856948
857
949
950
951
952
953
954
858955
859956
860957
861958
862959
863
960
961
864962
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
963
964
965
966
974967
975968
976969
......
11461139
11471140
11481141
1149
1150
1151
1152
1153
1154
1142
11551143
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1144
11671145
11681146
11691147
new Vector2(1, 1)
};
// Used to calculate texture coordinates
private static readonly float[] CornerOffsetX = new float[]
{
0.0f,
1.0f,
0.0f,
1.0f
};
private static readonly float[] CornerOffsetY = new float[]
{
0.0f,
0.0f,
1.0f,
1.0f
};
#endregion
#region Private Variables
vertexInfo = new VertexPositionColorTexture[MAX_VERTICES];
spriteData = new SpriteInfo[MAX_SPRITES];
for (int i = 0; i < MAX_SPRITES; i += 1)
{
spriteData[i].vertices = new VertexPositionColorTexture[4];
}
vertexBuffer = new DynamicVertexBuffer(
graphicsDevice,
typeof(VertexPositionColorTexture),
Vector2.Zero,
0.0f,
0.0f,
0
0,
false
);
}
Vector2.Zero,
0.0f,
0.0f,
0
0,
false
);
}
origin,
rotation,
layerDepth,
(byte) effects
(byte) effects,
false
);
}
origin,
rotation,
layerDepth,
(byte) effects
(byte) effects,
false
);
}
Vector2.Zero,
0.0f,
0.0f,
SpriteInfo.DestSizeInPixels
0,
true
);
}
Vector2.Zero,
0.0f,
0.0f,
SpriteInfo.DestSizeInPixels
0,
true
);
}
origin,
rotation,
layerDepth,
(byte) ((int) effects | SpriteInfo.DestSizeInPixels)
(byte) effects,
true
);
}
offset,
rotation,
layerDepth,
(byte) effects
(byte) effects,
false
);
/* Add the character width and right-side bearing to the line
offset,
rotation,
layerDepth,
(byte) effects
(byte) effects,
false
);
/* Add the character width and right-side bearing to the line
Vector2 origin,
float rotation,
float depth,
byte effects
byte effects,
bool destSizeInPixels
) {
if (numSprites >= MAX_SPRITES)
{
FlushBatch();
}
// Calculate source/destination
spriteData[numSprites].destination = destination;
// Source/Destination/Origin Calculations
float sourceX, sourceY, sourceW, sourceH;
float destW = destination.Z;
float destH = destination.W;
float originX, originY;
if (sourceRectangle.HasValue)
{
spriteData[numSprites].source = sourceRectangle.Value;
if ((effects & SpriteInfo.DestSizeInPixels) != SpriteInfo.DestSizeInPixels)
float inverseTexW = 1.0f / (float) texture.Width;
float inverseTexH = 1.0f / (float) texture.Height;
sourceX = sourceRectangle.Value.X * inverseTexW;
sourceY = sourceRectangle.Value.Y * inverseTexH;
sourceW = Math.Max(
sourceRectangle.Value.Width,
MathHelper.MachineEpsilonFloat
) * inverseTexW;
sourceH = Math.Max(
sourceRectangle.Value.Height,
MathHelper.MachineEpsilonFloat
) * inverseTexH;
originX = (origin.X / sourceW) * inverseTexW;
originY = (origin.Y / sourceH) * inverseTexH;
if (!destSizeInPixels)
{
spriteData[numSprites].destination.Z *= sourceRectangle.Value.Width;
spriteData[numSprites].destination.W *= sourceRectangle.Value.Height;
destW *= sourceRectangle.Value.Width;
destH *= sourceRectangle.Value.Height;
}
effects |= SpriteInfo.SourceInTexels | SpriteInfo.DestSizeInPixels;
}
else
{
spriteData[numSprites].source.X = 0;
spriteData[numSprites].source.Y = 0;
spriteData[numSprites].source.Width = 1;
spriteData[numSprites].source.Height = 1;
sourceX = 0.0f;
sourceY = 0.0f;
sourceW = 1.0f;
sourceH = 1.0f;
originX = origin.X * (1.0f / (float) texture.Width);
originY = origin.Y * (1.0f / (float) texture.Height);
if (!destSizeInPixels)
{
destW *= texture.Width;
destH *= texture.Height;
}
}
// Rotation Calculations
float rotationMatrix1X;
float rotationMatrix1Y;
float rotationMatrix2X;
float rotationMatrix2Y;
if (!MathHelper.WithinEpsilon(rotation, 0.0f))
{
float sin = (float) Math.Sin(rotation);
float cos = (float) Math.Cos(rotation);
rotationMatrix1X = cos;
rotationMatrix1Y = sin;
rotationMatrix2X = -sin;
rotationMatrix2Y = cos;
}
else
{
rotationMatrix1X = 1.0f;
rotationMatrix1Y = 0.0f;
rotationMatrix2X = 0.0f;
rotationMatrix2Y = 1.0f;
}
// Everything else passed is just copied
spriteData[numSprites].texture = texture;
spriteData[numSprites].color = color;
spriteData[numSprites].origin = origin;
spriteData[numSprites].rotation = rotation;
spriteData[numSprites].depth = depth;
spriteData[numSprites].effects = effects;
// Calculate vertices, finally.
for (int j = 0, curVertex = numSprites * 4; j < 4; j += 1, curVertex += 1)
{
float cornerX = (CornerOffsetX[j] - originX) * destW;
float cornerY = (CornerOffsetY[j] - originY) * destH;
spriteData[numSprites].vertices[j].Position.X = (
(rotationMatrix2X * cornerY) +
(rotationMatrix1X * cornerX) +
destination.X
);
spriteData[numSprites].vertices[j].Position.Y = (
(rotationMatrix2Y * cornerY) +
(rotationMatrix1Y * cornerX) +
destination.Y
);
spriteData[numSprites].vertices[j].Position.Z = depth;
spriteData[numSprites].vertices[j].Color = color;
spriteData[numSprites].vertices[j].TextureCoordinate.X = (CornerOffsetX[j ^ effects] * sourceW) + sourceX;
spriteData[numSprites].vertices[j].TextureCoordinate.Y = (CornerOffsetY[j ^ effects] * sourceH) + sourceY;
}
numSprites += 1;
if (sortMode == SpriteSortMode.Immediate)
{
PushVertices();
// FIXME: Make sorting less dump, then remove this -flibit
vertexInfo[0] = spriteData[0].vertices[0];
vertexInfo[1] = spriteData[0].vertices[1];
vertexInfo[2] = spriteData[0].vertices[2];
vertexInfo[3] = spriteData[0].vertices[3];
vertexBuffer.SetData(vertexInfo, 0, 4, SetDataOptions.None);
DrawPrimitives(texture, 0, 1);
numSprites = 0;
}
else
{
spriteData[numSprites].texture = texture;
spriteData[numSprites].depth = depth;
numSprites += 1;
}
}
private void PushVertices()
{
for (int i = 0; i < numSprites; i += 1)
// FIXME: Make sorting less dump, then remove this -flibit
for (int i = 0, curVertex = 0; i < numSprites; i += 1, curVertex += 4)
{
/* FIXME: OPTIMIZATION POINT: This method
* allocates like fuck right now! In general,
* it's by far the slowest block of code in the
* whole file, and needs fixing.
* -flibit
*/
// Current sprite being calculated
SpriteInfo info = spriteData[i];
// Calculate initial sprite information
Vector2 source = new Vector2(
info.source.X,
info.source.Y
);
Vector2 destination = new Vector2(
info.destination.X,
info.destination.Y
);
Vector2 sourceSize = new Vector2(
Math.Max(
info.source.Width,
MathHelper.MachineEpsilonFloat
),
Math.Max(
info.source.Height,
MathHelper.MachineEpsilonFloat
)
);
Vector2 destinationSize = new Vector2(
info.destination.Z,
info.destination.W
);
Vector2 origin = info.origin / sourceSize;
// Calculations performed with inverse texture size
Vector2 inverseTexSize = new Vector2(
(1.0f / (float) info.texture.Width),
(1.0f / (float) info.texture.Height)
);
if ((info.effects & SpriteInfo.SourceInTexels) == SpriteInfo.SourceInTexels)
{
source *= inverseTexSize;
sourceSize *= inverseTexSize;
}
else
{
origin *= inverseTexSize;
}
// Calculations done with texture size
if ((info.effects & SpriteInfo.DestSizeInPixels) != SpriteInfo.DestSizeInPixels)
{
destinationSize.X *= info.texture.Width;
destinationSize.Y *= info.texture.Height;
}
// Calculations performed with rotation
Vector2 rotationMatrix1;
Vector2 rotationMatrix2;
if (!MathHelper.WithinEpsilon(info.rotation, 0.0f))
{
float sin = (float) Math.Sin(info.rotation);
float cos = (float) Math.Cos(info.rotation);
rotationMatrix1.X = cos;
rotationMatrix1.Y = sin;
rotationMatrix2.X = -sin;
rotationMatrix2.Y = cos;
}
else
{
rotationMatrix1.X = 1.0f;
rotationMatrix1.Y = 0.0f;
rotationMatrix2.X = 0.0f;
rotationMatrix2.Y = 1.0f;
}
// Calculate vertices, finally.
for (int j = 0, curVertex = i * 4; j < 4; j += 1, curVertex += 1)
{
Vector2 cornerOffset = (
SpriteInfo.CornerOffsets[j] - origin
) * destinationSize;
Vector2 position = Vector2.Add(
Vector2.Multiply(
rotationMatrix2,
cornerOffset.Y
),
Vector2.Add(
Vector2.Multiply(
rotationMatrix1,
cornerOffset.X
),
destination
)
);
vertexInfo[curVertex].Position.X = position.X;
vertexInfo[curVertex].Position.Y = position.Y;
vertexInfo[curVertex].Position.Z = info.depth;
vertexInfo[curVertex].Color = info.color;
vertexInfo[curVertex].TextureCoordinate = Vector2.Add(
Vector2.Multiply(
SpriteInfo.CornerOffsets[j ^ (info.effects & 0x3)],
sourceSize
),
source
);
}
vertexInfo[curVertex] = spriteData[i].vertices[0];
vertexInfo[curVertex + 1] = spriteData[i].vertices[1];
vertexInfo[curVertex + 2] = spriteData[i].vertices[2];
vertexInfo[curVertex + 3] = spriteData[i].vertices[3];
}
vertexBuffer.SetData(vertexInfo, 0, numSprites * 4, SetDataOptions.None);
}
private struct SpriteInfo
{
public Rectangle source;
public Vector4 destination;
public Color color;
public Vector2 origin;
public float rotation;
public float depth;
public VertexPositionColorTexture[] vertices;
public Texture2D texture;
public byte effects;
public const int SourceInTexels = 0x4;
public const int DestSizeInPixels = 0x8;
public static readonly Vector2[] CornerOffsets = new Vector2[]
{
new Vector2(0.0f, 0.0f),
new Vector2(1.0f, 0.0f),
new Vector2(0.0f, 1.0f),
new Vector2(1.0f, 1.0f)
};
public float depth;
}
#endregion

Archive Download the corresponding diff file

Branches

Number of commits:
Page rendered in 0.65187s using 13 queries.