/// <summary> /// Reuse a previously allocated SpriteBatchItem from the item pool. /// if there is none available grow the pool and initialize new items. /// </summary> public NeoBatchItem 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 NeoBatchItem(); } EnsureArrayCapacity(Math.Min(newSize, MaxBatchSize)); } var item = _batchItemList[_batchItemCount++]; return(item); }
public void DrawGlyph(Texture2D atlas, Rectangle destinationRectangle, float left, float bottom, float right, float top, Color color) { var ntop = atlas.Height - top; var nbottom = atlas.Height - bottom; NeoBatchItem item = _batcher.CreateBatchItem(); item.Texture = atlas; _texCoordTL.X = left * (1f / (float)atlas.Width); _texCoordTL.Y = ntop * (1f / (float)atlas.Height); _texCoordBR.X = right * (1f / (float)atlas.Width); _texCoordBR.Y = nbottom * (1f / (float)atlas.Height); item.Set(destinationRectangle.X, destinationRectangle.Y, destinationRectangle.Width, destinationRectangle.Height, color, _texCoordTL, _texCoordBR); item.Type = NeoBatchItem.ItemType.Glyph; }
public NeoBatcher(GraphicsDevice device, Effect effect, int capacity = 0) { _device = device; _effect = effect; if (capacity <= 0) { capacity = InitialBatchSize; } else { capacity = (capacity + 63) & (~63); // ensure chunks of 64. } _batchItemList = new NeoBatchItem[capacity]; _batchItemCount = 0; for (int i = 0; i < capacity; i++) { _batchItemList[i] = new NeoBatchItem(); } EnsureArrayCapacity(capacity); }
/// <summary> /// Sorts the batch items and then groups batch drawing into maximal allowed batch sets that do not /// overflow the 16 bit array indices for vertices. /// </summary> public unsafe void DrawBatch() { // Determine how many iterations through the drawing code we need to make int batchIndex = 0; int batchCount = _batchItemCount; // Iterate through the batches, doing short.MaxValue sets of vertices only. while (batchCount > 0) { // setup the vertexArray array var startIndex = 0; var index = 0; Texture2D tex = null; int numBatchesToProcess = batchCount; if (numBatchesToProcess > MaxBatchSize) { numBatchesToProcess = MaxBatchSize; } NeoBatchItem.ItemType lastType; // Avoid the array checking overhead by using pointer indexing! fixed(BlockVertex *vertexArrayFixedPtr = _vertexArray) { var vertexArrayPtr = vertexArrayFixedPtr; if (_batchItemList[0] != null) { lastType = _batchItemList[0].Type; } else { lastType = NeoBatchItem.ItemType.Texture; } // Draw the batches for (int i = 0; i < numBatchesToProcess; i++, batchIndex++, index += 4, vertexArrayPtr += 4) { NeoBatchItem item = _batchItemList[batchIndex]; // if the texture changed, we need to flush and bind the new texture var shouldFlush = !(ReferenceEquals(item.Texture, tex) && (lastType == item.Type)); if (shouldFlush) { FlushVertexArray(startIndex, index, tex, lastType); tex = item.Texture; startIndex = index = 0; vertexArrayPtr = vertexArrayFixedPtr; _device.Textures[0] = tex; } // store the SpriteBatchItem data in our vertexArray *(vertexArrayPtr + 0) = item.vertexTL; *(vertexArrayPtr + 1) = item.vertexTR; *(vertexArrayPtr + 2) = item.vertexBL; *(vertexArrayPtr + 3) = item.vertexBR; // Release the texture. item.Texture = null; lastType = item.Type; } } // flush the remaining vertexArray data FlushVertexArray(startIndex, index, tex, lastType); // Update our batch count to continue the process of culling down // large batches batchCount -= numBatchesToProcess; } // return items to the pool. _batchItemCount = 0; }