monogame笔记(二)spritebatch

SpriteBatch的Draw和DrawString

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public void  (Texture2D texture, Rectangle rectangle, Color color)
{
if (texture == null )
{
throw new ArgumentException("texture");
}

SpriteBatchItem item = _batcher.CreateBatchItem();

item.Depth = 0;
item.TextureID = (int) texture.ID;

Vector2 texCoordTL = texture.Image.GetTextureCoord ( 0, 0 );
Vector2 texCoordBR = texture.Image.GetTextureCoord ( texture.Image.ImageWidth, texture.Image.ImageHeight );

item.Set
(
rectangle.X,
rectangle.Y,
rectangle.Width,
rectangle.Height,
color,
texCoordTL,
texCoordBR
);
}


public void DrawString(SpriteFont spriteFont, string text, Vector2 position, Color color)
{
if (spriteFont == null )
{
throw new ArgumentException("spriteFont");
}

Vector2 p = position;

foreach (char c in text)
{
if (c == 'n')
{
p.Y += spriteFont.LineSpacing;
p.X = position.X;
continue;
}
if (spriteFont.characterData.ContainsKey(c) == false)
continue;
GlyphData g = spriteFont.characterData[c];

SpriteBatchItem item = _batcher.CreateBatchItem();

item.Depth = 0.0f;
item.TextureID = (int) spriteFont._texture.ID;

Vector2 texCoordTL = spriteFont._texture.Image.GetTextureCoord ( g.Glyph.X, g.Glyph.Y );
Vector2 texCoordBR = spriteFont._texture.Image.GetTextureCoord ( g.Glyph.X+g.Glyph.Width, g.Glyph.Y+g.Glyph.Height );

item.Set
(
p.X,
p.Y+g.Cropping.Y,
g.Glyph.Width,
g.Glyph.Height,
color,
texCoordTL,
texCoordBR
);

p.X += (g.Kerning.Y + g.Kerning.Z + spriteFont.Spacing);
}
}

SpriteBatchItem item = _batcher.CreateBatchItem();
其实是从对象”池”中取一个; 三者关系如下: SpriteBatchItem的结构可以参考

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
_batchItemList = new SpriteBatchItem[InitialBatchSize];

public SpriteBatchItem CreateBatchItem()
{
if (_batchItemCount >= _batchItemList.Length)
{
var oldSize = _batchItemList.Length;
var newSize = oldSize + oldSize/2; // grow by x1.5
newSize = (newSize + 63) & (~63); // grow in chunks of 64.
Array.Resize(ref _batchItemList, newSize);
for(int i=oldSize; i<newSize; i++)
_batchItemList[i]=new SpriteBatchItem();

EnsureArrayCapacity(Math.Min(newSize, MaxBatchSize));
}
var item = _batchItemList[_batchItemCount++];
return item;
}

什么时候进行绘制呢?在调用End的时候

1
2
3
4
5
6
7
8
9
public void End ()
{
_beginCalled = false;

if (_sortMode != SpriteSortMode.Immediate)
Setup();

_batcher.DrawBatch(_sortMode, _effect);
}

DrawBatch其中一段代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
foreach ( SpriteBatchItem item in _batchItemList )
{
// if the texture changed, we need to flush and bind the new texture
if ( item.TextureID != texID )
{
FlushVertexArray( startIndex, index );
startIndex = index;
texID = item.TextureID;
GL.BindTexture ( All.Texture2D, texID );
}
// store the SpriteBatchItem data in our vertexArray
_vertexArray[index++] = item.vertexTL;
_vertexArray[index++] = item.vertexTR;
_vertexArray[index++] = item.vertexBL;
_vertexArray[index++] = item.vertexBR;

_freeBatchItemQueue.Enqueue ( item );
}

1
2
3
4
5
6
void FlushVertexArray ( int start, int end )
{
// draw stuff
if ( start != end )
GL.DrawElements ( All.Triangles, (end-start)/2*3, All.UnsignedShort,(IntPtr)((uint)_indexHandle.AddrOfPinnedObject()+(uint)(start/2*3*sizeof(short))) );
}

GL.DrawElements调用的是OpenTK