| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314 |
- // ================================================================================
- // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
- // == See tb_core.h for more information. ==
- // ================================================================================
- #include "renderers/tb_renderer_batcher.h"
- #include "tb_bitmap_fragment.h"
- #include "tb_system.h"
- #ifdef TB_RENDERER_BATCHER
- namespace tb {
- // == TBRendererBatcher::Batch ==========================================================
- #ifdef TB_RUNTIME_DEBUG_INFO
- uint32 dbg_begin_paint_batch_id = 0;
- uint32 dbg_frame_triangle_count = 0;
- #endif // TB_RUNTIME_DEBUG_INFO
- #define VER_COL(r, g, b, a) (((a)<<24) + ((b)<<16) + ((g)<<8) + r)
- #define VER_COL_OPACITY(a) (0x00ffffff + (((uint32)a) << 24))
- void TBRendererBatcher::Batch::Flush(TBRendererBatcher *batch_renderer)
- {
- if (!vertex_count || is_flushing)
- return;
- // Prevent re-entrancy. Calling fragment->GetBitmap may end up calling TBBitmap::SetData
- // which will end up flushing any existing batch with that bitmap.
- is_flushing = true;
- if (fragment)
- {
- // Now it's time to ensure the bitmap data is up to date. A call to GetBitmap
- // with TB_VALIDATE_ALWAYS should guarantee that its data is validated.
- TBBitmap *frag_bitmap = fragment->GetBitmap(TB_VALIDATE_ALWAYS);
- ((void)frag_bitmap); // silence warning about unused variable
- assert(frag_bitmap == bitmap);
- }
- batch_renderer->RenderBatch(this);
- #ifdef TB_RUNTIME_DEBUG_INFO
- if (TB_DEBUG_SETTING(RENDER_BATCHES))
- {
- // This assumes we're drawing triangles. Need to modify this
- // if we start using strips, fans or whatever.
- dbg_frame_triangle_count += vertex_count / 3;
- // Draw the triangles again using a random color based on the batch
- // id. This indicates which triangles belong to the same batch.
- uint32 id = batch_id - dbg_begin_paint_batch_id;
- uint32 hash = id * (2166136261U ^ id);
- uint32 color = 0xAA000000 + (hash & 0x00FFFFFF);
- for (int i = 0; i < vertex_count; i++)
- vertex[i].col = color;
- bitmap = nullptr;
- batch_renderer->RenderBatch(this);
- }
- #endif // TB_RUNTIME_DEBUG_INFO
- vertex_count = 0;
- batch_id++; // Will overflow eventually, but that doesn't really matter.
- is_flushing = false;
- }
- TBRendererBatcher::Vertex *TBRendererBatcher::Batch::Reserve(TBRendererBatcher *batch_renderer, int count)
- {
- assert(count < VERTEX_BATCH_SIZE);
- if (vertex_count + count > VERTEX_BATCH_SIZE)
- Flush(batch_renderer);
- Vertex *ret = &vertex[vertex_count];
- vertex_count += count;
- return ret;
- }
- // == TBRendererBatcher ===================================================================
- TBRendererBatcher::TBRendererBatcher()
- : m_opacity(255), m_translation_x(0), m_translation_y(0)
- , m_u(0), m_v(0), m_uu(0), m_vv(0)
- {
- }
- TBRendererBatcher::~TBRendererBatcher()
- {
- }
- void TBRendererBatcher::BeginPaint(int render_target_w, int render_target_h)
- {
- #ifdef TB_RUNTIME_DEBUG_INFO
- dbg_begin_paint_batch_id = batch.batch_id;
- dbg_frame_triangle_count = 0;
- #endif // TB_RUNTIME_DEBUG_INFO
- m_screen_rect.Set(0, 0, render_target_w, render_target_h);
- m_clip_rect = m_screen_rect;
- }
- void TBRendererBatcher::EndPaint()
- {
- FlushAllInternal();
- #ifdef TB_RUNTIME_DEBUG_INFO
- if (TB_DEBUG_SETTING(RENDER_BATCHES))
- TBDebugPrint("Frame rendered using %d batches and a total of %d triangles.\n",
- batch.batch_id - dbg_begin_paint_batch_id,
- dbg_frame_triangle_count);
- #endif // TB_RUNTIME_DEBUG_INFO
- }
- void TBRendererBatcher::Translate(int dx, int dy)
- {
- m_translation_x += dx;
- m_translation_y += dy;
- }
- void TBRendererBatcher::SetOpacity(float opacity)
- {
- int8 opacity8 = (uint8) (opacity * 255);
- if (opacity8 == m_opacity)
- return;
- m_opacity = opacity8;
- }
- float TBRendererBatcher::GetOpacity()
- {
- return m_opacity / 255.f;
- }
- TBRect TBRendererBatcher::SetClipRect(const TBRect &rect, bool add_to_current)
- {
- TBRect old_clip_rect = m_clip_rect;
- m_clip_rect = rect;
- m_clip_rect.x += m_translation_x;
- m_clip_rect.y += m_translation_y;
- if (add_to_current)
- m_clip_rect = m_clip_rect.Clip(old_clip_rect);
- FlushAllInternal();
- SetClipRect(m_clip_rect);
- old_clip_rect.x -= m_translation_x;
- old_clip_rect.y -= m_translation_y;
- return old_clip_rect;
- }
- TBRect TBRendererBatcher::GetClipRect()
- {
- TBRect curr_clip_rect = m_clip_rect;
- curr_clip_rect.x -= m_translation_x;
- curr_clip_rect.y -= m_translation_y;
- return curr_clip_rect;
- }
- void TBRendererBatcher::DrawBitmap(const TBRect &dst_rect, const TBRect &src_rect, TBBitmapFragment *bitmap_fragment)
- {
- if (TBBitmap *bitmap = bitmap_fragment->GetBitmap(TB_VALIDATE_FIRST_TIME))
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
- src_rect.Offset(bitmap_fragment->m_rect.x, bitmap_fragment->m_rect.y),
- VER_COL_OPACITY(m_opacity), bitmap, bitmap_fragment);
- }
- void TBRendererBatcher::DrawBitmap(const TBRect &dst_rect, const TBRect &src_rect, TBBitmap *bitmap)
- {
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y), src_rect, VER_COL_OPACITY(m_opacity), bitmap, nullptr);
- }
- void TBRendererBatcher::DrawBitmapColored(const TBRect &dst_rect, const TBRect &src_rect, const TBColor &color, TBBitmapFragment *bitmap_fragment)
- {
- if (TBBitmap *bitmap = bitmap_fragment->GetBitmap(TB_VALIDATE_FIRST_TIME))
- {
- uint32 a = (color.a * m_opacity) / 255;
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
- src_rect.Offset(bitmap_fragment->m_rect.x, bitmap_fragment->m_rect.y),
- VER_COL(color.r, color.g, color.b, a), bitmap, bitmap_fragment);
- }
- }
- void TBRendererBatcher::DrawBitmapColored(const TBRect &dst_rect, const TBRect &src_rect, const TBColor &color, TBBitmap *bitmap)
- {
- uint32 a = (color.a * m_opacity) / 255;
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
- src_rect, VER_COL(color.r, color.g, color.b, a), bitmap, nullptr);
- }
- void TBRendererBatcher::DrawBitmapTile(const TBRect &dst_rect, TBBitmap *bitmap)
- {
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
- TBRect(0, 0, dst_rect.w, dst_rect.h),
- VER_COL_OPACITY(m_opacity), bitmap, nullptr);
- }
- void TBRendererBatcher::DrawRect(const TBRect &dst_rect, const TBColor &color)
- {
- if (dst_rect.IsEmpty())
- return;
- // Top
- DrawRectFill(TBRect(dst_rect.x, dst_rect.y, dst_rect.w, 1), color);
- // Bottom
- DrawRectFill(TBRect(dst_rect.x, dst_rect.y + dst_rect.h - 1, dst_rect.w, 1), color);
- // Left
- DrawRectFill(TBRect(dst_rect.x, dst_rect.y + 1, 1, dst_rect.h - 2), color);
- // Right
- DrawRectFill(TBRect(dst_rect.x + dst_rect.w - 1, dst_rect.y + 1, 1, dst_rect.h - 2), color);
- }
- void TBRendererBatcher::DrawRectFill(const TBRect &dst_rect, const TBColor &color)
- {
- if (dst_rect.IsEmpty())
- return;
- uint32 a = (color.a * m_opacity) / 255;
- AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
- TBRect(), VER_COL(color.r, color.g, color.b, a), nullptr, nullptr);
- }
- void TBRendererBatcher::AddQuadInternal(const TBRect &dst_rect, const TBRect &src_rect, uint32 color, TBBitmap *bitmap, TBBitmapFragment *fragment)
- {
- if (batch.bitmap != bitmap)
- {
- batch.Flush(this);
- batch.bitmap = bitmap;
- }
- batch.fragment = fragment;
- if (bitmap)
- {
- int bitmap_w = bitmap->Width();
- int bitmap_h = bitmap->Height();
- m_u = (float)src_rect.x / bitmap_w;
- m_v = (float)src_rect.y / bitmap_h;
- m_uu = (float)(src_rect.x + src_rect.w) / bitmap_w;
- m_vv = (float)(src_rect.y + src_rect.h) / bitmap_h;
- }
- #ifdef _MSC_VER
- //Direct3D9 Adjustment
- #ifdef ATOMIC_D3D11
- float posAdjust = 0.0f;
- #else
- float posAdjust = 0.5f;
- #endif
- #else
- float posAdjust = 0.0f;
- #endif
- Vertex *ver = batch.Reserve(this, 6);
- ver[0].x = (float) dst_rect.x + posAdjust;
- ver[0].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
- ver[0].u = m_u;
- ver[0].v = m_vv;
- ver[0].col = color;
- ver[1].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
- ver[1].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
- ver[1].u = m_uu;
- ver[1].v = m_vv;
- ver[1].col = color;
- ver[2].x = (float) dst_rect.x + posAdjust;
- ver[2].y = (float) dst_rect.y + posAdjust;
- ver[2].u = m_u;
- ver[2].v = m_v;
- ver[2].col = color;
- ver[3].x = (float) dst_rect.x + posAdjust;
- ver[3].y = (float) dst_rect.y + posAdjust;
- ver[3].u = m_u;
- ver[3].v = m_v;
- ver[3].col = color;
- ver[4].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
- ver[4].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
- ver[4].u = m_uu;
- ver[4].v = m_vv;
- ver[4].col = color;
- ver[5].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
- ver[5].y = (float) dst_rect.y + posAdjust;
- ver[5].u = m_uu;
- ver[5].v = m_v;
- ver[5].col = color;
- // Update fragments batch id (See FlushBitmapFragment)
- if (fragment)
- fragment->m_batch_id = batch.batch_id;
- }
- void TBRendererBatcher::FlushAllInternal()
- {
- batch.Flush(this);
- }
- void TBRendererBatcher::FlushBitmap(TBBitmap *bitmap)
- {
- // Flush the batch if it's using this bitmap (that is about to change or be deleted)
- if (batch.vertex_count && bitmap == batch.bitmap)
- batch.Flush(this);
- }
- void TBRendererBatcher::FlushBitmapFragment(TBBitmapFragment *bitmap_fragment)
- {
- // Flush the batch if it is using this fragment (that is about to change or be deleted)
- // We know if it is in use in the current batch if its batch_id matches the current
- // batch_id in our (one and only) batch.
- // If we switch to a more advance batching system with multiple batches, we need to
- // solve this a bit differently.
- if (batch.vertex_count && bitmap_fragment->m_batch_id == batch.batch_id)
- batch.Flush(this);
- }
- }; // namespace tb
- #endif // TB_RENDERER_BATCHER
|