10 Renderer2D::RendererData* Renderer2D::s_Data{
nullptr };
12 void Renderer2D::Init() {
15 s_Data =
new RendererData();
17 constexpr auto params = Texture::Params();
18 constexpr uint32_t white[4] = { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
25 s_Data->QuadInstanceVertexBuffer->SetLayout({
33 s_Data->QuadInstanceVertexBuffer->Init(
nullptr, RendererData::MaxInstanceCount * s_Data->QuadInstanceVertexBuffer->GetLayout().GetStride(),
VertexBuffer::DRAW_TYPE::DYNAMIC);
34 s_Data->QuadInstanceVertexArray->AddVertexBuffer(s_Data->QuadInstanceVertexBuffer);
36 uint32_t quadIndices[6] = { 0, 1, 2, 2, 3, 0 };
38 s_Data->QuadInstanceVertexArray->AddIndexBuffer(s_Data->QuadInstanceIndexBuffer);
40 s_Data->QuadInstanceBufferBase =
new Quad[RendererData::MaxInstanceCount];
44 s_Data->WorldSpaceTransparentQuadQueue.reserve(RendererData::WorldSpaceTransparentQuadQueueInitialSize);
45 s_Data->WorldSpaceOpaqueQuadQueue.reserve(RendererData::WorldSpaceOpaqueQuadQueueInitialSize);
46 s_Data->ScreenSpaceTransparentQuadQueue.reserve(RendererData::ScreenSpaceTransparentQuadQueueInitialSize);
47 s_Data->ScreenSpaceOpaqueQuadQueue.reserve(RendererData::ScreenSpaceOpaqueQuadQueueInitialSize);
53 s_Data->CharInstanceVertexBuffer->SetLayout({
61 s_Data->CharInstanceVertexBuffer->Init(
nullptr, RendererData::MaxCharInstanceCount * s_Data->CharInstanceVertexBuffer->GetLayout().GetStride(),
VertexBuffer::DRAW_TYPE::DYNAMIC);
62 s_Data->CharInstanceVertexArray->AddVertexBuffer(s_Data->CharInstanceVertexBuffer);
65 s_Data->CharInstanceVertexArray->AddIndexBuffer(s_Data->CharInstanceIndexBuffer);
67 s_Data->CharInstanceBufferBase =
new Char[RendererData::MaxCharInstanceCount];
71 s_Data->WorldSpaceTransparentTextQueue.reserve(RendererData::WorldSpaceTransparentTextQueueInitialSize);
73 s_Data->ScreenSpaceTransparentTextQueue.reserve(RendererData::ScreenSpaceTransparentTextQueueInitialSize);
78 void Renderer2D::Shutdown() {
81 delete[] s_Data->QuadInstanceBufferBase;
82 delete[] s_Data->CharInstanceBufferBase;
94 bool Renderer2D::BeginWorldSpacePass() {
97 s_Data->CurrentViewProjectionMatrix = s_Data->WorldSpaceViewProjectionMatrix;
105 bool Renderer2D::BeginScreenSpacePass() {
108 s_Data->CurrentViewProjectionMatrix = s_Data->ScreenSpaceViewProjectionMatrix;
127 for (
const auto entity : view) {
129 if (__builtin_expect(renderer.m_Visible, 1)) {
130 const auto texture = renderer.GetTexture().get();
131 if (__builtin_expect(!texture, 0)) {
135 auto& transform = view.Get<World::Components::Entity::Transform>(entity);
138 if (AABBOverlapCheck(camera.m_CameraBounds, entityBounds)) {
140 if (!renderer.GetSemiTransparencyState()) {
141 SubmitQuad(
WORLD_SPACE,
OPAQUE, transform.m_WorldTransform, renderer.GetHalfSize(), renderer.GetColor(), texture, renderer.GetUVs(), transform.m_WorldDepth, renderer.m_FlipX, renderer.m_FlipY, renderer.m_FlatColored);
144 SubmitQuad(
WORLD_SPACE,
SEMI_TRANSPARENT, transform.m_WorldTransform, renderer.GetHalfSize(), renderer.GetColor(), texture, renderer.GetUVs(), transform.m_WorldDepth, renderer.m_FlipX, renderer.m_FlipY, renderer.m_FlatColored);
151 void Renderer2D::FlushRenderQueues() {
154 FlushTransparentQueues();
157 void Renderer2D::SubmitQuad(
const DrawSpace space,
const ObjectTransparency transparencyMode,
const glm::mat3& transform,
const glm::vec2 halfSize,
const glm::vec4& tintColor,
Texture2D* texture,
const UVs& uvs,
const uint8_t depth,
const bool flipX,
const bool flipY,
const bool flatColored) {
159 if (transparencyMode ==
OPAQUE) {
160 SubmitQuadToQueue(s_Data->WorldSpaceOpaqueQuadQueue, transform, halfSize, tintColor, texture, uvs, depth, flipX, flipY, flatColored);
164 SubmitQuadToQueue(s_Data->WorldSpaceTransparentQuadQueue, transform, halfSize, tintColor, texture, uvs, depth, flipX, flipY, flatColored);
168 if (transparencyMode ==
OPAQUE) {
169 SubmitQuadToQueue(s_Data->ScreenSpaceOpaqueQuadQueue, transform, halfSize, tintColor, texture, uvs, depth, flipX, flipY, flatColored);
173 SubmitQuadToQueue(s_Data->ScreenSpaceTransparentQuadQueue, transform, halfSize, tintColor, texture, uvs, depth, flipX, flipY, flatColored);
176 void Renderer2D::BeginQuadInstancedSet() {
179 s_Data->QuadInstanceCount = 0;
180 s_Data->QuadInstanceBufferPtr = s_Data->QuadInstanceBufferBase;
184 void Renderer2D::EndQuadInstancedSet() {
185 if (s_Data->QuadInstanceCount != 0) {
186 if (s_Data->CurrentVertexArray != s_Data->QuadInstanceVertexArray.get()) {
187 s_Data->QuadInstanceVertexArray->Bind();
188 s_Data->CurrentVertexArray = s_Data->QuadInstanceVertexArray.get();
190 if (s_Data->CurrentVertexBuffer != s_Data->QuadInstanceVertexBuffer.get()) {
191 s_Data->QuadInstanceVertexBuffer->Bind();
192 s_Data->CurrentVertexBuffer = s_Data->QuadInstanceVertexBuffer.get();
194 if (s_Data->CurrentIndexBuffer != s_Data->QuadInstanceIndexBuffer.get()) {
195 s_Data->QuadInstanceIndexBuffer->Bind();
196 s_Data->CurrentIndexBuffer = s_Data->QuadInstanceIndexBuffer.get();
198 if (s_Data->CurrentShader != s_Data->QuadInstanceShader.get()) {
199 s_Data->QuadInstanceShader->Bind();
200 s_Data->CurrentShader = s_Data->QuadInstanceShader.get();
202 FlushInstancedQuads();
206 void Renderer2D::BeginCharInstancedSet() {
207 s_Data->CharInstanceCount = 0;
208 s_Data->CharInstanceBufferPtr = s_Data->CharInstanceBufferBase;
211 void Renderer2D::EndCharInstancedSet(
Texture2D* atlas,
const glm::mat3& modelMatrix) {
212 if (s_Data->CharInstanceCount != 0) {
213 if (s_Data->CurrentVertexArray != s_Data->CharInstanceVertexArray.get()) {
214 s_Data->CharInstanceVertexArray->Bind();
215 s_Data->CurrentVertexArray = s_Data->CharInstanceVertexArray.get();
217 if (s_Data->CurrentVertexBuffer != s_Data->CharInstanceVertexBuffer.get()) {
218 s_Data->CharInstanceVertexBuffer->Bind();
219 s_Data->CurrentVertexBuffer = s_Data->CharInstanceVertexBuffer.get();
221 if (s_Data->CurrentIndexBuffer != s_Data->CharInstanceIndexBuffer.get()) {
222 s_Data->CharInstanceIndexBuffer->Bind();
223 s_Data->CurrentIndexBuffer = s_Data->CharInstanceIndexBuffer.get();
225 if (s_Data->CurrentShader != s_Data->CharInstanceShader.get()) {
226 s_Data->CharInstanceShader->Bind();
227 s_Data->CurrentShader = s_Data->CharInstanceShader.get();
229 FlushInstancedChars(atlas, modelMatrix);
233 void Renderer2D::SubmitQuadToQueue(std::vector<QuadInstance>& queue,
const glm::mat3& transform,
const glm::vec2 halfSize,
const glm::vec4& tintColor,
Texture2D* texture,
const UVs& uvs,
const uint8_t depth,
const bool flipX,
const bool flipY,
const bool flatColored) {
235 texture = s_Data->WhiteTexture.get();
241 if (!flipX && !flipY) {
247 static_cast<glm::vec4
>(uvs),
251 else if (flipX && !flipY) {
257 glm::vec4{uvs.UVmax.x, uvs.UVmin.y, uvs.UVmin.x, uvs.UVmax.y},
267 glm::vec4{uvs.UVmin.x, uvs.UVmax.y, uvs.UVmax.x, uvs.UVmin.y},
277 glm::vec4{uvs.UVmax.x, uvs.UVmax.y, uvs.UVmin.x, uvs.UVmin.y},
285 const glm::mat3 transform = glm::translate(glm::mat3(1.0f), position);
286 SubmitQuad(space,
OPAQUE, transform, halfSize, glm::vec4(color, 1.0f),
nullptr, {}, 255,
false,
false,
true);
298 void Renderer2D::SubmitTextToQueue(std::vector<TextInstance>& queue,
const TextAlignment alignment,
const glm::mat3& transform,
const float fontSize,
const std::u32string_view& text,
const glm::vec4& color,
Font* font,
const uint8_t depth,
const float limitX,
const float lineSpacing,
const float kerning) {
313 void Renderer2D::SubmitTextToQueue(std::vector<TextInstance>& queue,
const TextAlignment alignment,
const glm::mat3& transform,
const float fontSize,
const std::string_view& text,
const glm::vec4& color, Font* font,
const uint8_t depth,
const float limitX,
const float lineSpacing,
const float kerning) {
328 void Renderer2D::SubmitText(
const DrawSpace space,
const TextAlignment alignment,
const glm::mat3& transform,
const float fontSize,
const std::u32string_view& text,
const glm::vec4& color,
Font* font,
const uint8_t depth,
const float limitX,
const float lineSpacing,
const float kerning) {
336 font = placeholder.get();
345 SubmitTextToQueue(s_Data->WorldSpaceTransparentTextQueue, alignment, transform, fontSize, text, color, font, depth, limitX, lineSpacing, kerning);
349 SubmitTextToQueue(s_Data->ScreenSpaceTransparentTextQueue, alignment, transform, fontSize, text, color, font, depth, limitX, lineSpacing, kerning);
352 void Renderer2D::SubmitText(
const DrawSpace space,
const TextAlignment alignment,
const glm::mat3& transform,
const float fontSize,
const std::string_view& text,
const glm::vec4& color,
Font* font,
const uint8_t depth,
const float limitX,
const float lineSpacing,
const float kerning) {
360 font = placeholder.get();
369 SubmitTextToQueue(s_Data->WorldSpaceTransparentTextQueue, alignment, transform, fontSize, text, color, font, depth, limitX, lineSpacing, kerning);
373 SubmitTextToQueue(s_Data->ScreenSpaceTransparentTextQueue, alignment, transform, fontSize, text, color, font, depth, limitX, lineSpacing, kerning);
378 return s_Data->Stats;
383 s_Data->Stats.QuadCount = 0;
388 void Renderer2D::DrawQuadInstanced(
const QuadInstance& quad) {
389 if (!quad.m_Texture) {
394 if (s_Data->QuadInstanceCount >= RendererData::MaxInstanceCount) {
395 StartNewQuadInstancedSet();
398 if (s_Data->NecessaryTexture != quad.m_Texture) {
399 if (!s_Data->NecessaryTexture) {
400 s_Data->NecessaryTexture = quad.m_Texture;
403 StartNewQuadInstancedSet();
404 s_Data->NecessaryTexture = quad.m_Texture;
408 s_Data->QuadInstanceBufferPtr->m_Transform = quad.m_Transform;
409 s_Data->QuadInstanceBufferPtr->m_TexturePosition = quad.m_UVs;
410 s_Data->QuadInstanceBufferPtr->m_Size = quad.m_Size;
411 s_Data->QuadInstanceBufferPtr->m_TintColor = quad.m_TintColor;
412 s_Data->QuadInstanceBufferPtr->m_Layer = quad.m_Depth;
413 s_Data->QuadInstanceBufferPtr++;
415 s_Data->QuadInstanceCount++;
418 void Renderer2D::DrawTextInstanced(
const TextInstance& text) {
428 BeginCharInstancedSet();
430 const auto& fontGeometry = text.m_Font->GetData()->m_FontGeometry;
431 const auto& metrics = fontGeometry.getMetrics();
432 const auto atlas = text.m_Font->GetData()->m_Atlas;
434 const float scale = 1.0f / (metrics.ascenderY - metrics.descenderY) * text.m_FontSize;
440 float totalLineLength = 0.0f;
442 const float spaceGlyphAdvance = fontGeometry.getGlyph(
' ')->getAdvance() * scale;
445 const std::u32string_view view(text.m_Text);
448 size_t currentOffset = 0;
451 uint32_t currentGlobalCharIndex = 0;
453 constexpr std::u32string_view SEPARATORS = U
" \a\b\t\n\v\f\r";
455 auto FindNextWord = [&](
const std::u32string_view textView,
const size_t startIndex) -> std::tuple<std::u32string_view, std::u32string_view, size_t> {
456 if (startIndex >= textView.length()) {
458 return {{}, {}, std::u32string_view::npos};
461 const size_t wordStart = textView.find_first_not_of(SEPARATORS, startIndex);
463 if (wordStart == std::u32string_view::npos) {
465 return {textView.substr(startIndex), {}, std::u32string_view::npos};
468 std::u32string_view skipped = textView.substr(startIndex, wordStart - startIndex);
470 size_t wordEnd = textView.find_first_of(SEPARATORS, wordStart);
473 if (wordEnd == std::u32string_view::npos) {
474 std::u32string_view word = textView.substr(wordStart);
475 return {skipped, word, std::u32string_view::npos};
479 std::u32string_view word = textView.substr(wordStart, wordEnd - wordStart);
480 return {skipped, word, wordEnd};
483 auto GetNextChar = [&](
const uint32_t currentIndex,
const std::u32string_view& localView) ->
char32_t {
484 if (currentIndex + 1 < localView.size()) {
486 return localView[currentIndex + 1];
489 if (localView.data() + localView.size() == view.data() + view.size()) {
496 return *(localView.data() + localView.size() + 1);
499 auto ProcessGlyph = [&](
const uint32_t index,
const std::u32string_view& localView) {
500 if (s_Data->CharInstanceCount > RendererData::MaxCharInstanceCount) {
505 const char32_t c = localView[index];
507 auto glyph = fontGeometry.getGlyph(c);
509 glyph = fontGeometry.getGlyph(
'#');
517 double x0, y0, x1, y1;
518 glyph->getQuadPlaneBounds(x0, y0, x1, y1);
520 const glm::vec4 charQuad = { x0 * scale + x, y0 * scale + y, x1 * scale + x, y1 * scale + y };
522 double u0, v0, u1, v1;
523 glyph->getQuadAtlasBounds(u0, v0, u1, v1);
525 const float texelWidth = 1.0f /
static_cast<float>(atlas->GetWidth());
526 const float texelHeight = 1.0f /
static_cast<float>(atlas->GetHeight());
528 const glm::vec4 UV = { u0 * texelWidth, v0 * texelHeight, u1 * texelWidth, v1 * texelHeight };
530 s_Data->CharInstanceBufferPtr->m_Transform = text.m_Transform;
531 s_Data->CharInstanceBufferPtr->m_TexturePosition = UV;
532 s_Data->CharInstanceBufferPtr->m_CharQuad = charQuad;
533 s_Data->CharInstanceBufferPtr->m_Color = text.m_Color;
534 s_Data->CharInstanceBufferPtr->m_Layer = text.m_Depth;
535 s_Data->CharInstanceBufferPtr++;
537 s_Data->CharInstanceCount++;
539 const char32_t nextChar = GetNextChar(index, localView);
540 if (nextChar !=
'\0') {
542 fontGeometry.getAdvance(advance, c, nextChar);
543 x += scale * advance + text.m_Kerning;
546 const float sizeX = x1 - x0;
547 totalLineLength += sizeX * scale;
552 auto PreprocessWord = [&](
const std::u32string_view& word) ->
float {
553 float totalWordAdvance = 0.0f;
555 for (uint32_t i = 0; i < word.size(); i++) {
556 const char32_t nextChar = GetNextChar(i, word);
557 if (nextChar !=
'\0') {
559 fontGeometry.getAdvance(advance, word[i], nextChar);
560 totalWordAdvance += scale * advance + text.m_Kerning;
564 return totalWordAdvance;
567 auto GoToNewLine = [&] {
568 switch (text.m_Alignment) {
571 const float offset = totalLineLength;
578 const float offset = -(totalLineLength / 2.0f);
580 EndCharInstancedSet(atlas.get(), glm::translate(glm::mat3(1.0f), glm::vec2(offset, 0.0f)));
581 BeginCharInstancedSet();
586 const float offset = -totalLineLength;
588 EndCharInstancedSet(atlas.get(), glm::translate(glm::mat3(1.0f), glm::vec2(offset, 0.0f)));
589 BeginCharInstancedSet();
596 y -= scale * metrics.lineHeight + text.m_LineSpacing;
600 auto [skippedPart, currentWord, nextOffset] = FindNextWord(view, currentOffset);
601 if (nextOffset != std::u32string_view::npos) {
602 currentOffset = nextOffset;
607 bool longWord =
false;
610 bool ignoreSpaces =
false;
611 bool globalAdvanceChanged =
false;
613 float wordAdvance = 0.0f;
614 if (text.m_Alignment ==
RIGHT) {
615 wordAdvance = PreprocessWord(currentWord);
616 if (x + wordAdvance > text.m_LimitX) {
621 for (uint32_t i = 0; i < skippedPart.size(); ++i) {
622 if (skippedPart[i] ==
' ') {
623 const char32_t nextChar = GetNextChar(i, view);
624 if (nextChar !=
'\0' && !ignoreSpaces) {
625 ++currentGlobalCharIndex;
627 fontGeometry.getAdvance(advance, skippedPart[i], nextChar);
628 const float nextX = x + scale * advance + text.m_Kerning;
629 if (nextX > text.m_LimitX) {
639 if (skippedPart[i] ==
'\t') {
641 const uint32_t nextTabStop = ((currentGlobalCharIndex - 1) / spacesInTab + 1) * spacesInTab;
643 uint8_t spaces = nextTabStop - currentGlobalCharIndex;
648 currentGlobalCharIndex += spaces;
650 const float advance =
static_cast<float>(spaces) * spaceGlyphAdvance;
652 const float nextX = x + advance;
653 if (nextX > text.m_LimitX) {
661 globalAdvanceChanged =
true;
665 if (skippedPart[i] ==
'\n') {
670 switch (text.m_Alignment) {
674 wordAdvance = PreprocessWord(currentWord);
675 if (wordAdvance < text.m_LimitX) {
676 if (x + wordAdvance > text.m_LimitX) {
686 if (ignoreSpaces && !globalAdvanceChanged) {
687 if (wordAdvance < text.m_LimitX) {
693 wordAdvance = PreprocessWord(currentWord);
694 if (wordAdvance < text.m_LimitX) {
695 if (x + wordAdvance > text.m_LimitX) {
706 for (uint32_t i = 0; i < currentWord.size(); ++i) {
708 if (x > text.m_LimitX) {
713 ++currentGlobalCharIndex;
715 ProcessGlyph(i, currentWord);
720 switch (text.m_Alignment) {
723 const float offset = totalLineLength;
725 EndCharInstancedSet(atlas.get(), glm::mat3(1.0f));
730 const float offset = -(totalLineLength / 2.0f);
732 EndCharInstancedSet(atlas.get(), glm::translate(glm::mat3(1.0f), glm::vec2(offset, 0.0f)));
737 const float offset = -totalLineLength;
739 EndCharInstancedSet(atlas.get(), glm::translate(glm::mat3(1.0f), glm::vec2(offset, 0.0f)));
745 void Renderer2D::StartNewQuadInstancedSet() {
746 EndQuadInstancedSet();
747 BeginQuadInstancedSet();
750 void Renderer2D::FlushOpaqueQueues() {
753 static auto SortOpaqueQuadQueue = [](std::vector<QuadInstance>& queue) {
754 if (!queue.empty()) {
759 [](
const QuadInstance& quad) -> uint64_t {
760 return reinterpret_cast<uint64_t>(quad.m_Texture);
766 SortOpaqueQuadQueue(s_Data->WorldSpaceOpaqueQuadQueue);
767 SortOpaqueQuadQueue(s_Data->ScreenSpaceOpaqueQuadQueue);
769 if (!s_Data->WorldSpaceOpaqueQuadQueue.empty()) {
770 BeginWorldSpacePass();
772 BeginQuadInstancedSet();
774 for (
const auto& quad : s_Data->WorldSpaceOpaqueQuadQueue) {
775 DrawQuadInstanced(quad);
778 EndQuadInstancedSet();
781 s_Data->WorldSpaceOpaqueQuadQueue.clear();
784 if (!s_Data->ScreenSpaceOpaqueQuadQueue.empty()) {
785 BeginScreenSpacePass();
787 BeginQuadInstancedSet();
789 for (
const auto& quad : s_Data->ScreenSpaceOpaqueQuadQueue) {
790 DrawQuadInstanced(quad);
793 EndQuadInstancedSet();
795 s_Data->ScreenSpaceOpaqueQuadQueue.clear();
799 void Renderer2D::FlushTransparentQueues() {
800 static auto SortTransparentQuadQueue = [](std::vector<QuadInstance>& queue) {
802 if (!queue.empty()) {
806 [](
const QuadInstance& quad) -> uint64_t {
807 return reinterpret_cast<uint64_t>(quad.m_Texture);
814 [](
const QuadInstance& quad) -> uint8_t {
821 static auto SortTextQueue = [](std::vector<TextInstance>& queue) {
823 if (!queue.empty()) {
827 [](
const TextInstance& text) -> uint64_t {
828 return reinterpret_cast<uint64_t>(text.m_Font);
835 [](
const TextInstance& text) -> uint8_t {
842 static auto ClearQuadQueue = [](std::vector<QuadInstance>& queue) {
844 if (!queue.empty()) {
849 static auto ClearTextQueue = [](std::vector<TextInstance>& queue) {
851 if (!queue.empty()) {
856 SortTransparentQuadQueue(s_Data->WorldSpaceTransparentQuadQueue);
857 SortTransparentQuadQueue(s_Data->ScreenSpaceTransparentQuadQueue);
858 SortTextQueue(s_Data->WorldSpaceTransparentTextQueue);
859 SortTextQueue(s_Data->ScreenSpaceTransparentTextQueue);
861 auto it_wsq = s_Data->WorldSpaceTransparentQuadQueue.begin();
862 auto it_ssq = s_Data->ScreenSpaceTransparentQuadQueue.begin();
863 auto it_wst = s_Data->WorldSpaceTransparentTextQueue.begin();
864 auto it_sst = s_Data->ScreenSpaceTransparentTextQueue.begin();
866 const auto end_wsq = s_Data->WorldSpaceTransparentQuadQueue.end();
867 const auto end_ssq = s_Data->ScreenSpaceTransparentQuadQueue.end();
868 const auto end_wst = s_Data->WorldSpaceTransparentTextQueue.end();
869 const auto end_sst = s_Data->ScreenSpaceTransparentTextQueue.end();
871 std::priority_queue<ElementView, std::vector<ElementView>, std::greater<>> pq;
873 if (it_wsq != end_wsq) pq.push({&*it_wsq, it_wsq->m_Depth, WORLD_SPACE_QUAD});
874 if (it_ssq != end_ssq) pq.push({&*it_ssq, it_ssq->m_Depth, SCREEN_SPACE_QUAD});
875 if (it_wst != end_wst) pq.push({&*it_wst, it_wst->m_Depth, WORLD_SPACE_TEXT});
876 if (it_sst != end_sst) pq.push({&*it_sst, it_sst->m_Depth, SCREEN_SPACE_TEXT});
885 while (!pq.empty()) {
886 ElementView top = pq.top();
889 switch (top.m_QueueType) {
890 case WORLD_SPACE_QUAD:
892 const auto elem = std::get<const QuadInstance*>(top.m_ElementVariant);
893 if (s_Data->CurrentDrawSpace !=
WORLD_SPACE && s_Data->QuadInstanceCount != 0) {
894 StartNewQuadInstancedSet();
897 BeginWorldSpacePass();
899 DrawQuadInstanced(*elem);
901 if (++it_wsq != end_wsq) {
902 pq.push({&*it_wsq, it_wsq->m_Depth, WORLD_SPACE_QUAD});
906 case SCREEN_SPACE_QUAD:
908 const auto elem = std::get<const QuadInstance*>(top.m_ElementVariant);
909 if (s_Data->CurrentDrawSpace !=
SCREEN_SPACE && s_Data->QuadInstanceCount != 0) {
910 StartNewQuadInstancedSet();
913 BeginScreenSpacePass();
915 DrawQuadInstanced(*elem);
917 if (++it_ssq != end_ssq) {
918 pq.push({&*it_ssq, it_ssq->m_Depth, SCREEN_SPACE_QUAD});
922 case WORLD_SPACE_TEXT:
924 const auto elem = std::get<const TextInstance*>(top.m_ElementVariant);
925 if (s_Data->QuadInstanceCount != 0) {
926 EndQuadInstancedSet();
929 BeginWorldSpacePass();
930 DrawTextInstanced(*elem);
932 if (++it_wst != end_wst) {
933 pq.push({&*it_wst, it_wst->m_Depth, WORLD_SPACE_TEXT});
937 case SCREEN_SPACE_TEXT:
939 const auto elem = std::get<const TextInstance*>(top.m_ElementVariant);
940 if (s_Data->QuadInstanceCount != 0) {
941 EndQuadInstancedSet();
944 BeginScreenSpacePass();
945 DrawTextInstanced(*elem);
947 if (++it_sst != end_sst) {
948 pq.push({&*it_sst, it_sst->m_Depth, SCREEN_SPACE_TEXT});
955 if (s_Data->QuadInstanceCount != 0) {
956 EndQuadInstancedSet();
962 ClearQuadQueue(s_Data->WorldSpaceTransparentQuadQueue);
963 ClearQuadQueue(s_Data->ScreenSpaceTransparentQuadQueue);
964 ClearTextQueue(s_Data->WorldSpaceTransparentTextQueue);
965 ClearTextQueue(s_Data->ScreenSpaceTransparentTextQueue);
968 void Renderer2D::FlushInstancedQuads() {
971 const auto size =
reinterpret_cast<uint8_t*
>(s_Data->QuadInstanceBufferPtr) -
reinterpret_cast<uint8_t*
>(s_Data->QuadInstanceBufferBase);
972 s_Data->QuadInstanceVertexBuffer->SetData(s_Data->QuadInstanceBufferBase, size);
974 s_Data->QuadInstanceShader->SetMat4(
"u_ViewProjection", s_Data->CurrentViewProjectionMatrix);
975 s_Data->QuadInstanceShader->SetInt(
"u_Texture", 0);
977 if (s_Data->CurrentTexture != s_Data->NecessaryTexture) {
978 s_Data->NecessaryTexture->Bind(0);
979 s_Data->CurrentTexture = s_Data->NecessaryTexture;
984 s_Data->Stats.DrawCalls++;
985 s_Data->Stats.QuadCount += s_Data->QuadInstanceCount;
987 s_Data->QuadInstanceCount = 0;
990 void Renderer2D::FlushInstancedChars(
Texture2D* atlas,
const glm::mat3& modelMatrix) {
993 const auto size =
reinterpret_cast<uint8_t*
>(s_Data->CharInstanceBufferPtr) -
reinterpret_cast<uint8_t*
>(s_Data->CharInstanceBufferBase);
994 s_Data->CharInstanceVertexBuffer->SetData(s_Data->CharInstanceBufferBase, size);
996 const glm::vec2 unitRange = glm::vec2(2.0f) / glm::vec2(atlas->GetWidth(), atlas->GetHeight());
998 s_Data->CharInstanceShader->SetMat4(
"u_ViewProjection", s_Data->CurrentViewProjectionMatrix);
999 s_Data->CharInstanceShader->SetMat3(
"u_ModelMatrix", modelMatrix);
1000 s_Data->CharInstanceShader->SetInt(
"u_Texture", 0);
1001 s_Data->CharInstanceShader->SetVec2(
"u_UnitRange", unitRange);
1003 if (s_Data->CurrentTexture != atlas) {
1005 s_Data->CurrentTexture = atlas;
1010 s_Data->Stats.DrawCalls++;
1011 s_Data->Stats.CharCount += s_Data->CharInstanceCount;
1013 s_Data->CharInstanceCount = 0;
#define CORI_CORE_ERROR_TAGGED(...)
#define CORI_CORE_INFO_TAGGED(...)
#define CORI_PROFILE_FUNCTION()
#define CORI_SPACES_PER_TAB
static std::shared_ptr< AssetType > GetPlaceholder()
Retrieves the instance of placeholder for a specified asset type.
static std::filesystem::path GetAliasedPath(const std::string &alias)
Retries the full aliased path defined in fsgame.json.
Font asset to be used when rendering text. Pretty expensive to create if not cached,...
AssetStatus GetStatus() const
static std::shared_ptr< IndexBuffer > Create(uint32_t *indices, uint32_t count)
static void EnableBlending()
static void SetDepthMask(const bool mode)
static void DisableBlending()
static void DrawElementsInstancedTriangles(const uint32_t instanceCount)
static void SubmitText(const DrawSpace space, const TextAlignment alignment, const glm::mat3 &transform, const float fontSize, const std::u32string_view &text, const glm::vec4 &color, Font *font, const uint8_t depth, const float limitX, const float lineSpacing, const float kerning)
Draws a UTF-32 fixed length encoded string.
DrawSpace
Defines where to draw the object, in what space.
static void SubmitColoredQuad(const DrawSpace space, const glm::vec2 position, const glm::vec2 halfSize, const glm::vec3 &color)
Convenience function mainly for debugging, draws a plain colored quad.
static Statistics GetStatistics()
Gives you the rendering stats of the last rendered frame.
static void SubmitAABB(const Utility::AABB &aabb, const float lineThickness, const glm::vec3 &color)
Draws the AABB, also a debug convenience function, always draws in world space.
static void SubmitQuad(const DrawSpace space, const ObjectTransparency transparencyMode, const glm::mat3 &transform, const glm::vec2 halfSize, const glm::vec4 &tintColor, Texture2D *texture, const UVs &uvs, const uint8_t depth, const bool flipX, const bool flipY, const bool flatColored)
Submits the quad to the render queue.
TextAlignment
Available text alignment options.
static void BeginScene(const World::Components::Scene::Camera &camera)
static std::shared_ptr< ShaderProgram > Create(const std::filesystem::path &vertexPath, const std::filesystem::path &fragmentPath, const std::filesystem::path &geometryPath={})
A regular 2D texture with 1 layer.
static std::shared_ptr< Texture2D > Create(const std::shared_ptr< Image > &image)
Creates a Texture2D from the Image.
static std::shared_ptr< VertexArray > Create()
static std::shared_ptr< VertexBuffer > Create()
T & GetContextComponent()
A wrapper for an EnTT compile-time view that provides an iterator to access Entity instances directly...
Almost everything connected to graphics is in this namespace.
AABB CalculateAABB(const glm::mat3 &transform, const glm::vec2 halfSize)
Calculates the AABB for the quad taking into account rotation and scale.
Axis-Aligned bounding box.
Renders a quad the transform.
A Scene context component with all the graphical camera data.
glm::mat4 m_ProjectionMatrix
glm::mat4 m_ViewProjectionMatrix
Helper to exclude certain components from a static view.