sokol_debugtext_test.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. //------------------------------------------------------------------------------
  2. // sokol-debugtext-test.c
  3. // For best results, run with ASAN and UBSAN.
  4. //------------------------------------------------------------------------------
  5. #include "sokol_gfx.h"
  6. #define SOKOL_DEBUGTEXT_IMPL
  7. #include "sokol_debugtext.h"
  8. #include "utest.h"
  9. #define T(b) EXPECT_TRUE(b)
  10. #define TFLT(f0,f1) {T(fabs((f0)-(f1))<=(0.000001));}
  11. static void init(void) {
  12. sg_setup(&(sg_desc){0});
  13. sdtx_setup(&(sdtx_desc_t){0});
  14. }
  15. static void init_with(const sdtx_desc_t* desc) {
  16. sg_setup(&(sg_desc){0});
  17. sdtx_setup(desc);
  18. }
  19. static void shutdown(void) {
  20. sdtx_shutdown();
  21. sg_shutdown();
  22. }
  23. UTEST(sokol_debugtext, default_init_shutdown) {
  24. init();
  25. T(_sdtx.init_cookie == _SDTX_INIT_COOKIE);
  26. T(_sdtx.desc.context_pool_size == _SDTX_DEFAULT_CONTEXT_POOL_SIZE);
  27. T(_sdtx.desc.printf_buf_size == _SDTX_DEFAULT_PRINTF_BUF_SIZE);
  28. T(_sdtx.desc.context.char_buf_size == _SDTX_DEFAULT_CHAR_BUF_SIZE);
  29. T(_sdtx.desc.context.canvas_width == _SDTX_DEFAULT_CANVAS_WIDTH);
  30. T(_sdtx.desc.context.canvas_height == _SDTX_DEFAULT_CANVAS_HEIGHT);
  31. T(_sdtx.desc.context.tab_width == _SDTX_DEFAULT_TAB_WIDTH);
  32. T(_sdtx.desc.context.color_format == 0);
  33. T(_sdtx.desc.context.depth_format == 0);
  34. T(_sdtx.desc.context.sample_count == 0);
  35. for (int i = 0; i < SDTX_MAX_FONTS; i++) {
  36. T(_sdtx.desc.fonts[i].data.ptr == 0);
  37. T(_sdtx.desc.fonts[i].data.size == 0);
  38. T(_sdtx.desc.fonts[i].first_char == 0);
  39. T(_sdtx.desc.fonts[i].last_char == 0);
  40. }
  41. T(_sdtx.font_img.id != SG_INVALID_ID);
  42. T(_sdtx.shader.id != SG_INVALID_ID);
  43. T(_sdtx.fmt_buf_size == (_SDTX_DEFAULT_CHAR_BUF_SIZE + 1));
  44. T(_sdtx.fmt_buf);
  45. T(_sdtx.def_ctx_id.id != 0);
  46. T(_sdtx.def_ctx_id.id == _sdtx.cur_ctx_id.id);
  47. T(_sdtx.cur_ctx == _sdtx_lookup_context(_sdtx.cur_ctx_id.id));
  48. T(_sdtx.cur_ctx->desc.char_buf_size == _sdtx.desc.context.char_buf_size);
  49. T(_sdtx.cur_ctx->desc.canvas_width == _sdtx.desc.context.canvas_width);
  50. T(_sdtx.cur_ctx->desc.canvas_height == _sdtx.desc.context.canvas_height);
  51. T(_sdtx.cur_ctx->desc.tab_width == _sdtx.desc.context.tab_width);
  52. T(_sdtx.cur_ctx->desc.color_format == 0);
  53. T(_sdtx.cur_ctx->desc.depth_format == 0);
  54. T(_sdtx.cur_ctx->desc.sample_count == 0);
  55. T(_sdtx.cur_ctx->vertices.cap == _SDTX_DEFAULT_CHAR_BUF_SIZE * 6);
  56. T(_sdtx.cur_ctx->vertices.next == 0);
  57. T(_sdtx.cur_ctx->vertices.ptr);
  58. T(_sdtx.cur_ctx->commands.cap == _SDTX_DEFAULT_MAX_COMMANDS);
  59. T(_sdtx.cur_ctx->commands.next == 1);
  60. T(_sdtx.cur_ctx->commands.ptr);
  61. T(_sdtx.cur_ctx->vbuf.id != 0);
  62. T(_sdtx.cur_ctx->pip.id != 0);
  63. TFLT(_sdtx.cur_ctx->canvas_size.x, 640.0f);
  64. TFLT(_sdtx.cur_ctx->canvas_size.y, 480.0f);
  65. TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 640.0f);
  66. TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 480.0f);
  67. TFLT(_sdtx.cur_ctx->origin.x, 0.0f);
  68. TFLT(_sdtx.cur_ctx->origin.y, 0.0f);
  69. TFLT(_sdtx.cur_ctx->pos.x, 0.0f);
  70. TFLT(_sdtx.cur_ctx->pos.y, 0.0f);
  71. TFLT(_sdtx.cur_ctx->tab_width, 4.0f);
  72. T(_sdtx.cur_ctx->color == _SDTX_DEFAULT_COLOR);
  73. T(_sdtx.context_pool.contexts);
  74. T(_sdtx.context_pool.pool.size == (_SDTX_DEFAULT_CONTEXT_POOL_SIZE + 1));
  75. shutdown();
  76. T(_sdtx.init_cookie == 0);
  77. }
  78. UTEST(sokol_debugtext, init_with_params) {
  79. init_with(&(sdtx_desc_t){
  80. .context_pool_size = 2,
  81. .printf_buf_size = 128,
  82. .context = {
  83. .char_buf_size = 256,
  84. .canvas_width = 320,
  85. .canvas_height = 200,
  86. .tab_width = 8,
  87. .color_format = SG_PIXELFORMAT_RGBA8,
  88. .depth_format = SG_PIXELFORMAT_DEPTH_STENCIL,
  89. .sample_count = 4,
  90. }
  91. });
  92. T(_sdtx.init_cookie == _SDTX_INIT_COOKIE);
  93. T(_sdtx.desc.context_pool_size == 2);
  94. T(_sdtx.desc.printf_buf_size == 128);
  95. T(_sdtx.desc.context.char_buf_size == 256);
  96. T(_sdtx.desc.context.canvas_width == 320);
  97. T(_sdtx.desc.context.canvas_height == 200);
  98. T(_sdtx.desc.context.tab_width == 8);
  99. T(_sdtx.desc.context.color_format == SG_PIXELFORMAT_RGBA8);
  100. T(_sdtx.desc.context.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL);
  101. T(_sdtx.desc.context.sample_count == 4);
  102. T(_sdtx.fmt_buf_size == 129);
  103. T(_sdtx.cur_ctx->desc.char_buf_size == _sdtx.desc.context.char_buf_size);
  104. T(_sdtx.cur_ctx->desc.canvas_width == _sdtx.desc.context.canvas_width);
  105. T(_sdtx.cur_ctx->desc.canvas_height == _sdtx.desc.context.canvas_height);
  106. T(_sdtx.cur_ctx->desc.tab_width == _sdtx.desc.context.tab_width);
  107. T(_sdtx.cur_ctx->desc.color_format == SG_PIXELFORMAT_RGBA8);
  108. T(_sdtx.cur_ctx->desc.depth_format == SG_PIXELFORMAT_DEPTH_STENCIL);
  109. T(_sdtx.cur_ctx->desc.sample_count == 4);
  110. T(_sdtx.cur_ctx->vertices.cap == (256 * 6));
  111. TFLT(_sdtx.cur_ctx->canvas_size.x, 320.0f);
  112. TFLT(_sdtx.cur_ctx->canvas_size.y, 200.0f);
  113. TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 320.0f);
  114. TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 200.0f);
  115. TFLT(_sdtx.cur_ctx->tab_width, 8.0f);
  116. T(_sdtx.context_pool.pool.size == 3);
  117. shutdown();
  118. }
  119. UTEST(sokol_debugtext, make_destroy_context) {
  120. init();
  121. sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){
  122. .char_buf_size = 64,
  123. .canvas_width = 1024,
  124. .canvas_height = 768,
  125. .tab_width = 3,
  126. .color_format = SG_PIXELFORMAT_RGBA32F,
  127. .sample_count = 2
  128. });
  129. T(ctx_id.id != 0);
  130. T(ctx_id.id != _sdtx.cur_ctx_id.id);
  131. _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id);
  132. T(ctx);
  133. T(ctx != _sdtx.cur_ctx);
  134. T(ctx->desc.char_buf_size == 64);
  135. T(ctx->desc.canvas_width == 1024);
  136. T(ctx->desc.canvas_height == 768);
  137. T(ctx->desc.tab_width == 3);
  138. T(ctx->desc.color_format == SG_PIXELFORMAT_RGBA32F);
  139. T(ctx->desc.depth_format == 0);
  140. T(ctx->desc.sample_count == 2);
  141. T(ctx->vertices.ptr);
  142. T(ctx->vertices.next == 0);
  143. T(ctx->vertices.cap == (64 * 6));
  144. TFLT(ctx->canvas_size.x, 1024.0f);
  145. TFLT(ctx->canvas_size.y, 768.0f);
  146. TFLT(ctx->glyph_size.x, 8.0f / 1024.0f);
  147. TFLT(ctx->glyph_size.y, 8.0f / 768.0f);
  148. TFLT(ctx->tab_width, 3.0f);
  149. sdtx_destroy_context(ctx_id);
  150. T(0 == _sdtx_lookup_context(ctx_id.id));
  151. T(ctx->desc.char_buf_size == 0);
  152. T(ctx->vertices.ptr == 0);
  153. shutdown();
  154. }
  155. UTEST(sokol_debugtext, get_default_context) {
  156. // getting the default context must always return SDTX_DEFAULT_CONTEXT
  157. init();
  158. T(sdtx_get_context().id == SDTX_DEFAULT_CONTEXT.id);
  159. shutdown();
  160. }
  161. UTEST(sokol_debugtext, set_get_context) {
  162. init();
  163. sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 });
  164. T(ctx_id.id != 0);
  165. T(ctx_id.id != _sdtx.cur_ctx_id.id);
  166. sdtx_set_context(ctx_id);
  167. T(sdtx_get_context().id == ctx_id.id);
  168. T(ctx_id.id == _sdtx.cur_ctx_id.id);
  169. const _sdtx_context_t* ctx = _sdtx_lookup_context(ctx_id.id);
  170. T(ctx == _sdtx.cur_ctx);
  171. sdtx_set_context(SDTX_DEFAULT_CONTEXT);
  172. T(sdtx_get_context().id == SDTX_DEFAULT_CONTEXT.id);
  173. T(_sdtx.cur_ctx);
  174. T(ctx != _sdtx.cur_ctx);
  175. T(_sdtx.cur_ctx == _sdtx_lookup_context(_sdtx.def_ctx_id.id));
  176. shutdown();
  177. }
  178. UTEST(sokol_debugtext, destroy_default_context) {
  179. // destroying the default context is not allowed
  180. init();
  181. sdtx_context def_ctx_id = _sdtx.def_ctx_id;
  182. T(def_ctx_id.id == _sdtx.cur_ctx_id.id);
  183. sdtx_destroy_context(def_ctx_id);
  184. T(def_ctx_id.id == _sdtx.def_ctx_id.id);
  185. T(def_ctx_id.id == _sdtx.cur_ctx_id.id);
  186. T(_sdtx.cur_ctx);
  187. shutdown();
  188. }
  189. UTEST(sokol_debugtext, destroy_current_context) {
  190. // destroying the current context has the same effect
  191. // as setting a current context with an invalid context handle
  192. init();
  193. sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 });
  194. sdtx_set_context(ctx_id);
  195. T(sdtx_get_context().id == ctx_id.id);
  196. T(ctx_id.id == _sdtx.cur_ctx_id.id);
  197. T(_sdtx_lookup_context(ctx_id.id) == _sdtx.cur_ctx);
  198. sdtx_destroy_context(ctx_id);
  199. T(_sdtx.cur_ctx_id.id == ctx_id.id);
  200. T(_sdtx.cur_ctx == 0);
  201. T(sdtx_get_context().id == ctx_id.id);
  202. shutdown();
  203. }
  204. UTEST(sokol_debugtext, ignore_invalid_context_handle) {
  205. // trying to render with an invalid context handle must not crash,
  206. // instead ignore all operations
  207. init();
  208. sdtx_context ctx_id = sdtx_make_context(&(sdtx_context_desc_t){ 0 });
  209. sdtx_set_context(ctx_id);
  210. sdtx_destroy_context(ctx_id);
  211. T(0 == _sdtx.cur_ctx);
  212. T(sdtx_get_context().id == ctx_id.id);
  213. sdtx_font(0);
  214. sdtx_canvas(100.0f, 200.0f);
  215. sdtx_origin(10.0f, 10.0f);
  216. sdtx_home();
  217. sdtx_pos(1.0f, 2.0f);
  218. sdtx_pos_x(1.0f);
  219. sdtx_pos_y(2.0f);
  220. sdtx_move(2.0f, 3.0f);
  221. sdtx_move_x(2.0f);
  222. sdtx_move_y(3.0f);
  223. sdtx_crlf();
  224. sdtx_color3b(255, 255, 255);
  225. sdtx_color3f(1.0f, 1.0f, 1.0f);
  226. sdtx_color4b(255, 255, 255, 255);
  227. sdtx_color4f(1.0f, 1.0f, 1.0f, 1.0f);
  228. sdtx_color1i(0xFFFFFFFF);
  229. sdtx_putc('A');
  230. sdtx_puts("Hello World!");
  231. sdtx_putr("Hello World!", 5);
  232. sdtx_printf("Hello World %d %d %d", 1, 2, 3);
  233. shutdown();
  234. }
  235. UTEST(sokol_debugtext, set_font) {
  236. init();
  237. T(0 == _sdtx.cur_ctx->cur_font);
  238. sdtx_font(1);
  239. T(1 == _sdtx.cur_ctx->cur_font);
  240. sdtx_font(2);
  241. T(2 == _sdtx.cur_ctx->cur_font);
  242. shutdown();
  243. }
  244. UTEST(sokol_debugtext, set_canvas) {
  245. init();
  246. sdtx_origin(10.0f, 11.0f);
  247. sdtx_pos(1.0f, 2.0f);
  248. sdtx_canvas(320.0f, 200.0f);
  249. TFLT(_sdtx.cur_ctx->canvas_size.x, 320.0f);
  250. TFLT(_sdtx.cur_ctx->canvas_size.y, 200.0f);
  251. TFLT(_sdtx.cur_ctx->glyph_size.x, 8.0f / 320.0f);
  252. TFLT(_sdtx.cur_ctx->glyph_size.y, 8.0f / 200.0f);
  253. // origin and pos must be reset to 0 when canvas is set
  254. TFLT(_sdtx.cur_ctx->origin.x, 0.0f);
  255. TFLT(_sdtx.cur_ctx->origin.y, 0.0f);
  256. TFLT(_sdtx.cur_ctx->pos.x, 0.0f);
  257. TFLT(_sdtx.cur_ctx->pos.y, 0.0f);
  258. shutdown();
  259. }
  260. UTEST(sokol_debugtext, set_origin) {
  261. init();
  262. sdtx_origin(10.0f, 20.0f);
  263. TFLT(_sdtx.cur_ctx->origin.x, 10.0f);
  264. TFLT(_sdtx.cur_ctx->origin.y, 20.0f);
  265. shutdown();
  266. }
  267. UTEST(sokol_debugtext, cursor_movement) {
  268. init();
  269. sdtx_pos(1.0f, 2.0f);
  270. TFLT(_sdtx.cur_ctx->pos.x, 1.0f);
  271. TFLT(_sdtx.cur_ctx->pos.y, 2.0f);
  272. sdtx_pos_x(5.0f);
  273. TFLT(_sdtx.cur_ctx->pos.x, 5.0f);
  274. TFLT(_sdtx.cur_ctx->pos.y, 2.0f);
  275. sdtx_pos_y(6.0f);
  276. TFLT(_sdtx.cur_ctx->pos.x, 5.0f);
  277. TFLT(_sdtx.cur_ctx->pos.y, 6.0f);
  278. sdtx_move(-1.0f, -3.0f);
  279. TFLT(_sdtx.cur_ctx->pos.x, 4.0f);
  280. TFLT(_sdtx.cur_ctx->pos.y, 3.0f);
  281. sdtx_move_x(+1.0f);
  282. TFLT(_sdtx.cur_ctx->pos.x, 5.0f);
  283. TFLT(_sdtx.cur_ctx->pos.y, 3.0f);
  284. sdtx_move_y(+3.0f);
  285. TFLT(_sdtx.cur_ctx->pos.x, 5.0f);
  286. TFLT(_sdtx.cur_ctx->pos.y, 6.0f);
  287. sdtx_crlf();
  288. TFLT(_sdtx.cur_ctx->pos.x, 0.0f);
  289. TFLT(_sdtx.cur_ctx->pos.y, 7.0f);
  290. sdtx_pos(20.0f, 30.0f);
  291. sdtx_home();
  292. TFLT(_sdtx.cur_ctx->pos.x, 0.0f);
  293. TFLT(_sdtx.cur_ctx->pos.y, 0.0f);
  294. shutdown();
  295. }
  296. UTEST(sokol_debugtext, set_color) {
  297. init();
  298. T(_sdtx.cur_ctx->color == _SDTX_DEFAULT_COLOR);
  299. sdtx_color3b(255, 127, 0);
  300. T(_sdtx.cur_ctx->color == 0xFF007FFF);
  301. sdtx_color4b(0, 127, 255, 255);
  302. T(_sdtx.cur_ctx->color == 0xFFFF7F00);
  303. sdtx_color3f(1.0f, 0.5f, 0.0f);
  304. T(_sdtx.cur_ctx->color == 0xFF007FFF);
  305. sdtx_color4f(0.0f, 0.5f, 1.0f, 1.0f);
  306. T(_sdtx.cur_ctx->color == 0xFFFF7F00);
  307. sdtx_color1i(0xFF000000);
  308. T(_sdtx.cur_ctx->color == 0xFF000000);
  309. shutdown();
  310. }
  311. UTEST(sokol_debugtext, vertex_overflow) {
  312. // overflowing the vertex buffer must not crash
  313. init_with(&(sdtx_desc_t){
  314. .context.char_buf_size = 8,
  315. });
  316. for (int i = 0; i < 32; i++) {
  317. sdtx_putc('A');
  318. }
  319. sdtx_puts("1234567890");
  320. sdtx_putr("1234567890", 5);
  321. sdtx_printf("Hello World %d!\n", 12);
  322. T(_sdtx.cur_ctx->vertices.next == _sdtx.cur_ctx->vertices.cap);
  323. shutdown();
  324. }
  325. UTEST(sokol_debugtext, context_overflow) {
  326. // creating too many contexts should not crash
  327. init_with(&(sdtx_desc_t){
  328. .context_pool_size = 4,
  329. });
  330. T(_sdtx.context_pool.pool.size == 5);
  331. // one slot is taken by the default context
  332. sdtx_context ctx[4];
  333. for (int i = 0; i < 4; i++) {
  334. ctx[i] = sdtx_make_context(&(sdtx_context_desc_t){ 0 });
  335. if (i < 3) {
  336. T(ctx[i].id != 0);
  337. }
  338. else {
  339. T(ctx[i].id == 0);
  340. }
  341. }
  342. // destroying an invalid context should not crash
  343. for (int i = 0; i < 4; i++) {
  344. sdtx_destroy_context(ctx[i]);
  345. }
  346. shutdown();
  347. }
  348. UTEST(sokol_debugtext, printf_overflow) {
  349. // overflowing the printf formatting buffer should not crash
  350. init_with(&(sdtx_desc_t){
  351. .printf_buf_size = 8
  352. });
  353. T(9 == _sdtx.fmt_buf_size);
  354. T(16 == sdtx_printf("Hello %d\n", 123456789));
  355. T('H' == _sdtx.fmt_buf[0])
  356. T('e' == _sdtx.fmt_buf[1])
  357. T('l' == _sdtx.fmt_buf[2])
  358. T('l' == _sdtx.fmt_buf[3])
  359. T('o' == _sdtx.fmt_buf[4])
  360. T(' ' == _sdtx.fmt_buf[5])
  361. T('1' == _sdtx.fmt_buf[6])
  362. T('2' == _sdtx.fmt_buf[7])
  363. T(0 == _sdtx.fmt_buf[8])
  364. shutdown();
  365. }
  366. UTEST(sokol_debugtext, rewind_after_draw) {
  367. // calling sdtx_draw() must rewind the cursor position, font and
  368. // vertex pointer, to keep canvas size and origin as is
  369. init();
  370. sdtx_canvas(256, 128);
  371. TFLT(_sdtx.cur_ctx->canvas_size.x, 256);
  372. TFLT(_sdtx.cur_ctx->canvas_size.y, 128);
  373. sdtx_origin(5, 5);
  374. TFLT(_sdtx.cur_ctx->origin.x, 5);
  375. TFLT(_sdtx.cur_ctx->origin.y, 5);
  376. sdtx_pos(10, 20);
  377. TFLT(_sdtx.cur_ctx->pos.x, 10);
  378. TFLT(_sdtx.cur_ctx->pos.y, 20);
  379. sdtx_font(3);
  380. T(_sdtx.cur_ctx->cur_font == 3);
  381. sdtx_printf("Hello World!\n");
  382. T(_sdtx.cur_ctx->vertices.next != 0);
  383. sg_begin_default_pass(&(sg_pass_action){ 0 }, 256, 256);
  384. sdtx_draw();
  385. sg_end_pass();
  386. sg_commit();
  387. TFLT(_sdtx.cur_ctx->canvas_size.x, 256);
  388. TFLT(_sdtx.cur_ctx->canvas_size.y, 128);
  389. TFLT(_sdtx.cur_ctx->origin.x, 5);
  390. TFLT(_sdtx.cur_ctx->origin.y, 5);
  391. TFLT(_sdtx.cur_ctx->pos.x, 0);
  392. TFLT(_sdtx.cur_ctx->pos.x, 0);
  393. T(_sdtx.cur_ctx->cur_font == 0);
  394. T(_sdtx.cur_ctx->vertices.next == 0);
  395. shutdown();
  396. }
  397. UTEST(sokol_debugtext, putr) {
  398. // test if sdtx_putr() draws the right amount of characters
  399. init();
  400. int start_index = _sdtx.cur_ctx->vertices.next;
  401. sdtx_putr("Hello World!", 5);
  402. T((5 * 6) == (_sdtx.cur_ctx->vertices.next - start_index));
  403. start_index = _sdtx.cur_ctx->vertices.next;
  404. sdtx_putr("Hello!\n\n\n\n\n\n\n\n\n\n\n", 10);
  405. // NOTE: the \n's don't result in rendered vertices
  406. T((6 * 6) == (_sdtx.cur_ctx->vertices.next - start_index));
  407. shutdown();
  408. }
  409. UTEST(sokol_debugtext, default_context) {
  410. init();
  411. T(sdtx_default_context().id == SDTX_DEFAULT_CONTEXT.id);
  412. shutdown();
  413. }
  414. // switching layers without any text inbetween should not advance the current draw command
  415. UTEST(sokol_debug_text, empty_layers) {
  416. init();
  417. T(_sdtx.cur_ctx->commands.next == 1);
  418. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0);
  419. sdtx_layer(1);
  420. T(_sdtx.cur_ctx->commands.next == 1);
  421. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 1);
  422. sdtx_layer(2);
  423. T(_sdtx.cur_ctx->commands.next == 1);
  424. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 2);
  425. sdtx_layer(0);
  426. T(_sdtx.cur_ctx->commands.next == 1);
  427. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0);
  428. shutdown();
  429. }
  430. // switching layers with text inbetween should advance the current draw command
  431. UTEST(sokol_debug_text, non_empty_layers) {
  432. init();
  433. T(_sdtx.cur_ctx->commands.next == 1);
  434. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0);
  435. T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0);
  436. T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == 0);
  437. sdtx_puts("123");
  438. T(_sdtx.cur_ctx->commands.next == 1);
  439. T(_sdtx.cur_ctx->commands.ptr[0].layer_id == 0);
  440. T(_sdtx.cur_ctx->commands.ptr[0].first_vertex == 0);
  441. T(_sdtx.cur_ctx->commands.ptr[0].num_vertices == (3 * 6));
  442. sdtx_layer(1);
  443. sdtx_puts("1234");
  444. T(_sdtx.cur_ctx->commands.next == 2);
  445. T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1);
  446. T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6));
  447. T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (4 * 6));
  448. // switching to same layer should not start a new draw commands
  449. sdtx_layer(1);
  450. sdtx_puts("12345");
  451. T(_sdtx.cur_ctx->commands.next == 2);
  452. T(_sdtx.cur_ctx->commands.ptr[1].layer_id == 1);
  453. T(_sdtx.cur_ctx->commands.ptr[1].first_vertex == (3 * 6));
  454. T(_sdtx.cur_ctx->commands.ptr[1].num_vertices == (9 * 6));
  455. sdtx_layer(0);
  456. sdtx_puts("123456");
  457. T(_sdtx.cur_ctx->commands.next == 3);
  458. T(_sdtx.cur_ctx->commands.ptr[2].layer_id == 0);
  459. T(_sdtx.cur_ctx->commands.ptr[2].first_vertex == (12 * 6));
  460. T(_sdtx.cur_ctx->commands.ptr[2].num_vertices == (6 * 6));
  461. shutdown();
  462. }
  463. UTEST(sokol_debug_text, command_buffer_overflow) {
  464. init_with(&(sdtx_desc_t){
  465. .context = {
  466. .max_commands = 4
  467. }
  468. });
  469. sdtx_puts("0");
  470. T(_sdtx.cur_ctx->commands.next == 1);
  471. sdtx_layer(1);
  472. sdtx_puts("1");
  473. T(_sdtx.cur_ctx->commands.next == 2);
  474. sdtx_layer(2);
  475. sdtx_puts("2");
  476. T(_sdtx.cur_ctx->commands.next == 3);
  477. sdtx_layer(3);
  478. sdtx_puts("3");
  479. T(_sdtx.cur_ctx->commands.next == 4);
  480. // from here on should fail
  481. sdtx_layer(4);
  482. sdtx_puts("4");
  483. T(_sdtx.cur_ctx->commands.next == 4);
  484. }