tb_renderer_batcher.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #include "renderers/tb_renderer_batcher.h"
  6. #include "tb_bitmap_fragment.h"
  7. #include "tb_system.h"
  8. #ifdef TB_RENDERER_BATCHER
  9. namespace tb {
  10. // == TBRendererBatcher::Batch ==========================================================
  11. #ifdef TB_RUNTIME_DEBUG_INFO
  12. uint32 dbg_begin_paint_batch_id = 0;
  13. uint32 dbg_frame_triangle_count = 0;
  14. #endif // TB_RUNTIME_DEBUG_INFO
  15. #define VER_COL(r, g, b, a) (((a)<<24) + ((b)<<16) + ((g)<<8) + r)
  16. #define VER_COL_OPACITY(a) (0x00ffffff + (((uint32)a) << 24))
  17. void TBRendererBatcher::Batch::Flush(TBRendererBatcher *batch_renderer)
  18. {
  19. if (!vertex_count || is_flushing)
  20. return;
  21. // Prevent re-entrancy. Calling fragment->GetBitmap may end up calling TBBitmap::SetData
  22. // which will end up flushing any existing batch with that bitmap.
  23. is_flushing = true;
  24. if (fragment)
  25. {
  26. // Now it's time to ensure the bitmap data is up to date. A call to GetBitmap
  27. // with TB_VALIDATE_ALWAYS should guarantee that its data is validated.
  28. TBBitmap *frag_bitmap = fragment->GetBitmap(TB_VALIDATE_ALWAYS);
  29. ((void)frag_bitmap); // silence warning about unused variable
  30. assert(frag_bitmap == bitmap);
  31. }
  32. batch_renderer->RenderBatch(this);
  33. #ifdef TB_RUNTIME_DEBUG_INFO
  34. if (TB_DEBUG_SETTING(RENDER_BATCHES))
  35. {
  36. // This assumes we're drawing triangles. Need to modify this
  37. // if we start using strips, fans or whatever.
  38. dbg_frame_triangle_count += vertex_count / 3;
  39. // Draw the triangles again using a random color based on the batch
  40. // id. This indicates which triangles belong to the same batch.
  41. uint32 id = batch_id - dbg_begin_paint_batch_id;
  42. uint32 hash = id * (2166136261U ^ id);
  43. uint32 color = 0xAA000000 + (hash & 0x00FFFFFF);
  44. for (int i = 0; i < vertex_count; i++)
  45. vertex[i].col = color;
  46. bitmap = nullptr;
  47. batch_renderer->RenderBatch(this);
  48. }
  49. #endif // TB_RUNTIME_DEBUG_INFO
  50. vertex_count = 0;
  51. batch_id++; // Will overflow eventually, but that doesn't really matter.
  52. is_flushing = false;
  53. }
  54. TBRendererBatcher::Vertex *TBRendererBatcher::Batch::Reserve(TBRendererBatcher *batch_renderer, int count)
  55. {
  56. assert(count < VERTEX_BATCH_SIZE);
  57. if (vertex_count + count > VERTEX_BATCH_SIZE)
  58. Flush(batch_renderer);
  59. Vertex *ret = &vertex[vertex_count];
  60. vertex_count += count;
  61. return ret;
  62. }
  63. // == TBRendererBatcher ===================================================================
  64. TBRendererBatcher::TBRendererBatcher()
  65. : m_opacity(255), m_translation_x(0), m_translation_y(0)
  66. , m_u(0), m_v(0), m_uu(0), m_vv(0)
  67. {
  68. }
  69. TBRendererBatcher::~TBRendererBatcher()
  70. {
  71. }
  72. void TBRendererBatcher::BeginPaint(int render_target_w, int render_target_h)
  73. {
  74. #ifdef TB_RUNTIME_DEBUG_INFO
  75. dbg_begin_paint_batch_id = batch.batch_id;
  76. dbg_frame_triangle_count = 0;
  77. #endif // TB_RUNTIME_DEBUG_INFO
  78. m_screen_rect.Set(0, 0, render_target_w, render_target_h);
  79. m_clip_rect = m_screen_rect;
  80. }
  81. void TBRendererBatcher::EndPaint()
  82. {
  83. FlushAllInternal();
  84. #ifdef TB_RUNTIME_DEBUG_INFO
  85. if (TB_DEBUG_SETTING(RENDER_BATCHES))
  86. TBDebugPrint("Frame rendered using %d batches and a total of %d triangles.\n",
  87. batch.batch_id - dbg_begin_paint_batch_id,
  88. dbg_frame_triangle_count);
  89. #endif // TB_RUNTIME_DEBUG_INFO
  90. }
  91. void TBRendererBatcher::Translate(int dx, int dy)
  92. {
  93. m_translation_x += dx;
  94. m_translation_y += dy;
  95. }
  96. void TBRendererBatcher::SetOpacity(float opacity)
  97. {
  98. int8 opacity8 = (uint8) (opacity * 255);
  99. if (opacity8 == m_opacity)
  100. return;
  101. m_opacity = opacity8;
  102. }
  103. float TBRendererBatcher::GetOpacity()
  104. {
  105. return m_opacity / 255.f;
  106. }
  107. TBRect TBRendererBatcher::SetClipRect(const TBRect &rect, bool add_to_current)
  108. {
  109. TBRect old_clip_rect = m_clip_rect;
  110. m_clip_rect = rect;
  111. m_clip_rect.x += m_translation_x;
  112. m_clip_rect.y += m_translation_y;
  113. if (add_to_current)
  114. m_clip_rect = m_clip_rect.Clip(old_clip_rect);
  115. FlushAllInternal();
  116. SetClipRect(m_clip_rect);
  117. old_clip_rect.x -= m_translation_x;
  118. old_clip_rect.y -= m_translation_y;
  119. return old_clip_rect;
  120. }
  121. TBRect TBRendererBatcher::GetClipRect()
  122. {
  123. TBRect curr_clip_rect = m_clip_rect;
  124. curr_clip_rect.x -= m_translation_x;
  125. curr_clip_rect.y -= m_translation_y;
  126. return curr_clip_rect;
  127. }
  128. void TBRendererBatcher::DrawBitmap(const TBRect &dst_rect, const TBRect &src_rect, TBBitmapFragment *bitmap_fragment)
  129. {
  130. if (TBBitmap *bitmap = bitmap_fragment->GetBitmap(TB_VALIDATE_FIRST_TIME))
  131. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
  132. src_rect.Offset(bitmap_fragment->m_rect.x, bitmap_fragment->m_rect.y),
  133. VER_COL_OPACITY(m_opacity), bitmap, bitmap_fragment);
  134. }
  135. void TBRendererBatcher::DrawBitmap(const TBRect &dst_rect, const TBRect &src_rect, TBBitmap *bitmap)
  136. {
  137. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y), src_rect, VER_COL_OPACITY(m_opacity), bitmap, nullptr);
  138. }
  139. void TBRendererBatcher::DrawBitmapColored(const TBRect &dst_rect, const TBRect &src_rect, const TBColor &color, TBBitmapFragment *bitmap_fragment)
  140. {
  141. if (TBBitmap *bitmap = bitmap_fragment->GetBitmap(TB_VALIDATE_FIRST_TIME))
  142. {
  143. uint32 a = (color.a * m_opacity) / 255;
  144. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
  145. src_rect.Offset(bitmap_fragment->m_rect.x, bitmap_fragment->m_rect.y),
  146. VER_COL(color.r, color.g, color.b, a), bitmap, bitmap_fragment);
  147. }
  148. }
  149. void TBRendererBatcher::DrawBitmapColored(const TBRect &dst_rect, const TBRect &src_rect, const TBColor &color, TBBitmap *bitmap)
  150. {
  151. uint32 a = (color.a * m_opacity) / 255;
  152. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
  153. src_rect, VER_COL(color.r, color.g, color.b, a), bitmap, nullptr);
  154. }
  155. void TBRendererBatcher::DrawBitmapTile(const TBRect &dst_rect, TBBitmap *bitmap)
  156. {
  157. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
  158. TBRect(0, 0, dst_rect.w, dst_rect.h),
  159. VER_COL_OPACITY(m_opacity), bitmap, nullptr);
  160. }
  161. void TBRendererBatcher::DrawRect(const TBRect &dst_rect, const TBColor &color)
  162. {
  163. if (dst_rect.IsEmpty())
  164. return;
  165. // Top
  166. DrawRectFill(TBRect(dst_rect.x, dst_rect.y, dst_rect.w, 1), color);
  167. // Bottom
  168. DrawRectFill(TBRect(dst_rect.x, dst_rect.y + dst_rect.h - 1, dst_rect.w, 1), color);
  169. // Left
  170. DrawRectFill(TBRect(dst_rect.x, dst_rect.y + 1, 1, dst_rect.h - 2), color);
  171. // Right
  172. DrawRectFill(TBRect(dst_rect.x + dst_rect.w - 1, dst_rect.y + 1, 1, dst_rect.h - 2), color);
  173. }
  174. void TBRendererBatcher::DrawRectFill(const TBRect &dst_rect, const TBColor &color)
  175. {
  176. if (dst_rect.IsEmpty())
  177. return;
  178. uint32 a = (color.a * m_opacity) / 255;
  179. AddQuadInternal(dst_rect.Offset(m_translation_x, m_translation_y),
  180. TBRect(), VER_COL(color.r, color.g, color.b, a), nullptr, nullptr);
  181. }
  182. void TBRendererBatcher::AddQuadInternal(const TBRect &dst_rect, const TBRect &src_rect, uint32 color, TBBitmap *bitmap, TBBitmapFragment *fragment)
  183. {
  184. if (batch.bitmap != bitmap)
  185. {
  186. batch.Flush(this);
  187. batch.bitmap = bitmap;
  188. }
  189. batch.fragment = fragment;
  190. if (bitmap)
  191. {
  192. int bitmap_w = bitmap->Width();
  193. int bitmap_h = bitmap->Height();
  194. m_u = (float)src_rect.x / bitmap_w;
  195. m_v = (float)src_rect.y / bitmap_h;
  196. m_uu = (float)(src_rect.x + src_rect.w) / bitmap_w;
  197. m_vv = (float)(src_rect.y + src_rect.h) / bitmap_h;
  198. }
  199. #ifdef _MSC_VER
  200. //Direct3D9 Adjustment
  201. #ifdef ATOMIC_D3D11
  202. float posAdjust = 0.0f;
  203. #else
  204. float posAdjust = 0.5f;
  205. #endif
  206. #else
  207. float posAdjust = 0.0f;
  208. #endif
  209. Vertex *ver = batch.Reserve(this, 6);
  210. ver[0].x = (float) dst_rect.x + posAdjust;
  211. ver[0].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
  212. ver[0].u = m_u;
  213. ver[0].v = m_vv;
  214. ver[0].col = color;
  215. ver[1].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
  216. ver[1].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
  217. ver[1].u = m_uu;
  218. ver[1].v = m_vv;
  219. ver[1].col = color;
  220. ver[2].x = (float) dst_rect.x + posAdjust;
  221. ver[2].y = (float) dst_rect.y + posAdjust;
  222. ver[2].u = m_u;
  223. ver[2].v = m_v;
  224. ver[2].col = color;
  225. ver[3].x = (float) dst_rect.x + posAdjust;
  226. ver[3].y = (float) dst_rect.y + posAdjust;
  227. ver[3].u = m_u;
  228. ver[3].v = m_v;
  229. ver[3].col = color;
  230. ver[4].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
  231. ver[4].y = (float) (dst_rect.y + dst_rect.h) + posAdjust;
  232. ver[4].u = m_uu;
  233. ver[4].v = m_vv;
  234. ver[4].col = color;
  235. ver[5].x = (float) (dst_rect.x + dst_rect.w) + posAdjust;
  236. ver[5].y = (float) dst_rect.y + posAdjust;
  237. ver[5].u = m_uu;
  238. ver[5].v = m_v;
  239. ver[5].col = color;
  240. // Update fragments batch id (See FlushBitmapFragment)
  241. if (fragment)
  242. fragment->m_batch_id = batch.batch_id;
  243. }
  244. void TBRendererBatcher::FlushAllInternal()
  245. {
  246. batch.Flush(this);
  247. }
  248. void TBRendererBatcher::FlushBitmap(TBBitmap *bitmap)
  249. {
  250. // Flush the batch if it's using this bitmap (that is about to change or be deleted)
  251. if (batch.vertex_count && bitmap == batch.bitmap)
  252. batch.Flush(this);
  253. }
  254. void TBRendererBatcher::FlushBitmapFragment(TBBitmapFragment *bitmap_fragment)
  255. {
  256. // Flush the batch if it is using this fragment (that is about to change or be deleted)
  257. // We know if it is in use in the current batch if its batch_id matches the current
  258. // batch_id in our (one and only) batch.
  259. // If we switch to a more advance batching system with multiple batches, we need to
  260. // solve this a bit differently.
  261. if (batch.vertex_count && bitmap_fragment->m_batch_id == batch.batch_id)
  262. batch.Flush(this);
  263. }
  264. }; // namespace tb
  265. #endif // TB_RENDERER_BATCHER