void SpriteBatch::Impl::FlushBatch() { SortSprites(); // Walk through sprite list, looking for entries that share a texture. size_t batchStart = 0; std::shared_ptr<Texture> batchTexture = nullptr; for (size_t index = 0; index < m_queueCount; ++index) { std::shared_ptr<Texture> texture = m_sortedSprites[index]->texture; if (texture != batchTexture) { if (index > batchStart) RenderBatch(batchTexture, &m_sortedSprites[batchStart], index - batchStart); batchTexture = texture; batchStart = index; } } // Render final batch RenderBatch(batchTexture, &m_sortedSprites[batchStart], m_queueCount - batchStart); // Reset queue m_queueCount = 0; m_sortedSprites.clear(); }
void SpriteRenderer::RenderBatch(ID3D11ShaderResourceView* texture, const SpriteDrawData* drawData, uint64 numSprites) { _ASSERT(context); _ASSERT(initialized); D3DPERF_BeginEvent(0xFFFFFFFF, L"SpriteRenderer RenderBatch"); // Set the vertex shader context->VSSetShader(vertexShaderInstanced, nullptr, 0); // Set the input layout context->IASetInputLayout(inputLayoutInstanced); // Set per-batch constants D3D11_TEXTURE2D_DESC desc = SetPerBatchData(texture); // Make sure the draw rects are all valid for (uint64 i = 0; i < numSprites; ++i) { Float4 drawRect = drawData[i].DrawRect; _ASSERT(drawRect.x >= 0 && drawRect.x < desc.Width); _ASSERT(drawRect.y >= 0 && drawRect.y < desc.Height); _ASSERT(drawRect.z > 0 && drawRect.x + drawRect.z <= desc.Width); _ASSERT(drawRect.w > 0 && drawRect.y + drawRect.w <= desc.Height); } uint64 numSpritesToDraw = std::min(numSprites, MaxBatchSize); // Copy in the instance data D3D11_MAPPED_SUBRESOURCE mapped; DXCall(context->Map(instanceDataBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)); CopyMemory(mapped.pData, drawData, static_cast<size_t>(sizeof(SpriteDrawData) * numSpritesToDraw)); context->Unmap(instanceDataBuffer, 0); // Set the constant buffer ID3D11Buffer* constantBuffers [1] = { vsPerBatchCB }; context->VSSetConstantBuffers(0, 1, constantBuffers); // Set the vertex buffers UINT strides [2] = { sizeof(SpriteVertex), sizeof(SpriteDrawData) }; UINT offsets [2] = { 0, 0 }; ID3D11Buffer* vertexBuffers [2] = { vertexBuffer, instanceDataBuffer }; context->IASetVertexBuffers(0, 2, vertexBuffers, strides, offsets); // Set the texture context->PSSetShaderResources(0, 1, &texture); // Draw context->DrawIndexedInstanced(6, static_cast<UINT>(numSpritesToDraw), 0, 0, 0); D3DPERF_EndEvent(); // If there's any left to be rendered, do it recursively if(numSprites > numSpritesToDraw) RenderBatch(texture, drawData + numSpritesToDraw, numSprites - numSpritesToDraw); }
void SpriteRenderer::End() { SortSpriteData(spriteSortMode); Texture2D* batchTexture = sprites[0].texture; vector<InstanceData> instanceData; while(!sprites.empty()) { const SpriteData& nextSprite = sprites.back(); if (nextSprite.texture != batchTexture) { RenderBatch(instanceData.begin(), instanceData.end(), batchTexture); instanceData.clear(); batchTexture = nextSprite.texture; } else { InstanceData instance(nextSprite.transform, nextSprite.color); instanceData.push_back(instance); sprites.pop_back(); } } if (!instanceData.empty()) { RenderBatch(instanceData.begin(), instanceData.end(), batchTexture); } sprites.clear(); }
void SpriteRenderer::RenderText(const SpriteFont& font, const wchar* text, const Float4x4& transform, const Float4& color) { D3DPERF_BeginEvent(0xFFFFFFFF, L"SpriteRenderer RenderText"); size_t length = wcslen(text); Float4x4 textTransform; uint64 numCharsToDraw = std::min(length, MaxBatchSize); uint64 currentDraw = 0; for(uint64 i = 0; i < numCharsToDraw; ++i) { wchar character = text[i]; if(character == ' ') textTransform._41 += font.SpaceWidth(); else if(character == '\n') { textTransform._42 += font.CharHeight(); textTransform._41 = 0; } else { SpriteFont::CharDesc desc = font.GetCharDescriptor(character); textDrawData[currentDraw].Transform = textTransform * transform; textDrawData[currentDraw].Color = color; textDrawData[currentDraw].DrawRect.x = desc.X; textDrawData[currentDraw].DrawRect.y = desc.Y; textDrawData[currentDraw].DrawRect.z = desc.Width; textDrawData[currentDraw].DrawRect.w = desc.Height; currentDraw++; textTransform._41 += desc.Width + 1; } } // Submit a batch RenderBatch(font.SRView(), textDrawData, currentDraw); D3DPERF_EndEvent(); if(length > numCharsToDraw) RenderText(font, text + numCharsToDraw, textTransform, color); }
void SpriteRenderer::RenderText(const SpriteFont& font, const WCHAR* text, const XMMATRIX& transform, const XMFLOAT4& color) { D3DPERF_BeginEvent(0xFFFFFFFF, L"SpriteRenderer RenderText"); size_t length = wcslen(text); XMMATRIX textTransform = XMMatrixIdentity(); UINT64 numCharsToDraw = min(length, MaxBatchSize); UINT64 currentDraw = 0; for (UINT64 i = 0; i < numCharsToDraw; ++i) { WCHAR character = text[i]; if(character == ' ') textTransform._41 += font.SpaceWidth(); else if(character == '\n') { textTransform._42 += font.CharHeight(); textTransform._41 = 0; } else { SpriteFont::CharDesc desc = font.GetCharDescriptor(character); textDrawData[currentDraw].Transform = XMMatrixMultiply(textTransform, transform); textDrawData[currentDraw].Color = color; textDrawData[currentDraw].DrawRect.x = desc.X; textDrawData[currentDraw].DrawRect.y = desc.Y; textDrawData[currentDraw].DrawRect.z = desc.Width; textDrawData[currentDraw].DrawRect.w = desc.Height; currentDraw++; textTransform._41 += desc.Width + 1; } } // Submit a batch RenderBatch(font.SRView(), textDrawData, currentDraw); D3DPERF_EndEvent(); if(length > numCharsToDraw) RenderText(font, text + numCharsToDraw, textTransform, color); }
void VBOBatcher2D::prepare(bool splitEveryGlyph) { if (glyphs.size() == 0) return; std::vector<Vertex2D> verticies; int c = 0; for (unsigned int i = 0; i < glyphs.size(); i++) { c += glyphs[i]->vertexes.size(); } verticies.resize(c); unsigned int offset = 0; unsigned int cv = 0; batches.emplace_back(RenderBatch(*glyphs[0], offset)); for (unsigned int i = 0; i < glyphs[0]->vertexes.size(); i++) { verticies[cv++] = glyphs[0]->vertexes[i]; offset++; } for (unsigned int cg = 1; cg < glyphs.size(); cg++) { if (splitEveryGlyph || batches.back() != *(glyphs[cg])) { batches.emplace_back(*(glyphs[cg]), offset); } else { batches.back().size += glyphs[cg]->vertexes.size(); } for (unsigned int i = 0; i < glyphs[cg]->vertexes.size(); i++) { verticies[cv++] = glyphs[cg]->vertexes[i]; offset++; } } vbo.bufferData(verticies); }