imgui.cpp 35 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568
  1. /*
  2. * Copyright 2011-2014 Branimir Karadzic. All rights reserved.
  3. * License: http://www.opensource.org/licenses/BSD-2-Clause
  4. */
  5. // This code is based on:
  6. //
  7. // Copyright (c) 2009-2010 Mikko Mononen [email protected]
  8. //
  9. // This software is provided 'as-is', without any express or implied
  10. // warranty. In no event will the authors be held liable for any damages
  11. // arising from the use of this software.
  12. // Permission is granted to anyone to use this software for any purpose,
  13. // including commercial applications, and to alter it and redistribute it
  14. // freely, subject to the following restrictions:
  15. // 1. The origin of this software must not be misrepresented; you must not
  16. // claim that you wrote the original software. If you use this software
  17. // in a product, an acknowledgment in the product documentation would be
  18. // appreciated but is not required.
  19. // 2. Altered source versions must be plainly marked as such, and must not be
  20. // misrepresented as being the original software.
  21. // 3. This notice may not be removed or altered from any source distribution.
  22. //
  23. // Source altered and distributed from https://github.com/AdrienHerubel/imgui
  24. #include <stdio.h>
  25. #include <bx/string.h>
  26. #include <bx/uint32_t.h>
  27. #include <bx/fpumath.h>
  28. #include <bgfx.h>
  29. #include "../entry/dbg.h"
  30. #include "imgui.h"
  31. #include "vs_imgui_color.bin.h"
  32. #include "fs_imgui_color.bin.h"
  33. #include "vs_imgui_texture.bin.h"
  34. #include "fs_imgui_texture.bin.h"
  35. #define MAX_TEMP_COORDS 100
  36. #define NUM_CIRCLE_VERTS (8 * 4)
  37. static const int32_t BUTTON_HEIGHT = 20;
  38. static const int32_t SLIDER_HEIGHT = 20;
  39. static const int32_t SLIDER_MARKER_WIDTH = 10;
  40. static const int32_t CHECK_SIZE = 8;
  41. static const int32_t DEFAULT_SPACING = 4;
  42. static const int32_t TEXT_HEIGHT = 8;
  43. static const int32_t SCROLL_AREA_PADDING = 6;
  44. static const int32_t INDENT_SIZE = 16;
  45. static const int32_t AREA_HEADER = 28;
  46. static const float s_tabStops[4] = {150, 210, 270, 330};
  47. static void* imguiMalloc(size_t size, void* /*_userptr*/)
  48. {
  49. return malloc(size);
  50. }
  51. static void imguiFree(void* _ptr, void* /*_userptr*/)
  52. {
  53. free(_ptr);
  54. }
  55. #define STBTT_malloc(_x, _y) imguiMalloc(_x, _y)
  56. #define STBTT_free(_x, _y) imguiFree(_x, _y)
  57. #define STB_TRUETYPE_IMPLEMENTATION
  58. #include <stb_truetype/stb_truetype.h>
  59. namespace
  60. {
  61. struct PosColorVertex
  62. {
  63. float m_x;
  64. float m_y;
  65. uint32_t m_abgr;
  66. static void init()
  67. {
  68. ms_decl
  69. .begin()
  70. .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
  71. .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
  72. .end();
  73. }
  74. static bgfx::VertexDecl ms_decl;
  75. };
  76. bgfx::VertexDecl PosColorVertex::ms_decl;
  77. struct PosColorUvVertex
  78. {
  79. float m_x;
  80. float m_y;
  81. float m_u;
  82. float m_v;
  83. uint32_t m_abgr;
  84. static void init()
  85. {
  86. ms_decl
  87. .begin()
  88. .add(bgfx::Attrib::Position, 2, bgfx::AttribType::Float)
  89. .add(bgfx::Attrib::TexCoord0, 2, bgfx::AttribType::Float)
  90. .add(bgfx::Attrib::Color0, 4, bgfx::AttribType::Uint8, true)
  91. .end();
  92. }
  93. static bgfx::VertexDecl ms_decl;
  94. };
  95. bgfx::VertexDecl PosColorUvVertex::ms_decl;
  96. } // namespace
  97. struct Imgui
  98. {
  99. Imgui()
  100. : m_mx(-1)
  101. , m_my(-1)
  102. , m_scroll(0)
  103. , m_active(0)
  104. , m_hot(0)
  105. , m_hotToBe(0)
  106. , m_dragX(0)
  107. , m_dragY(0)
  108. , m_dragOrig(0)
  109. , m_widgetX(0)
  110. , m_widgetY(0)
  111. , m_widgetW(100)
  112. , m_left(false)
  113. , m_leftPressed(false)
  114. , m_leftReleased(false)
  115. , m_isHot(false)
  116. , m_isActive(false)
  117. , m_wentActive(false)
  118. , m_insideCurrentScroll(false)
  119. , m_areaId(0)
  120. , m_widgetId(0)
  121. , m_scissor(UINT16_MAX)
  122. , m_scrollTop(0)
  123. , m_scrollBottom(0)
  124. , m_scrollRight(0)
  125. , m_scrollAreaTop(0)
  126. , m_scrollVal(NULL)
  127. , m_focusTop(0)
  128. , m_focusBottom(0)
  129. , m_scrollId(0)
  130. , m_insideScrollArea(false)
  131. , m_textureWidth(512)
  132. , m_textureHeight(512)
  133. , m_halfTexel(0.0f)
  134. , m_view(31)
  135. {
  136. m_invTextureWidth = 1.0f/m_textureWidth;
  137. m_invTextureHeight = 1.0f/m_textureHeight;
  138. u_texColor.idx = bgfx::invalidHandle;
  139. m_fontTexture.idx = bgfx::invalidHandle;
  140. m_colorProgram.idx = bgfx::invalidHandle;
  141. m_textureProgram.idx = bgfx::invalidHandle;
  142. }
  143. bool create(const void* _data)
  144. {
  145. for (int32_t ii = 0; ii < NUM_CIRCLE_VERTS; ++ii)
  146. {
  147. float a = (float)ii / (float)NUM_CIRCLE_VERTS * (float)(M_PI * 2.0);
  148. m_circleVerts[ii * 2 + 0] = cosf(a);
  149. m_circleVerts[ii * 2 + 1] = sinf(a);
  150. }
  151. PosColorVertex::init();
  152. PosColorUvVertex::init();
  153. u_texColor = bgfx::createUniform("u_texColor", bgfx::UniformType::Uniform1i);
  154. const bgfx::Memory* vs_imgui_color;
  155. const bgfx::Memory* fs_imgui_color;
  156. const bgfx::Memory* vs_imgui_texture;
  157. const bgfx::Memory* fs_imgui_texture;
  158. switch (bgfx::getRendererType() )
  159. {
  160. case bgfx::RendererType::Direct3D9:
  161. vs_imgui_color = bgfx::makeRef(vs_imgui_color_dx9, sizeof(vs_imgui_color_dx9) );
  162. fs_imgui_color = bgfx::makeRef(fs_imgui_color_dx9, sizeof(fs_imgui_color_dx9) );
  163. vs_imgui_texture = bgfx::makeRef(vs_imgui_texture_dx9, sizeof(vs_imgui_texture_dx9) );
  164. fs_imgui_texture = bgfx::makeRef(fs_imgui_texture_dx9, sizeof(fs_imgui_texture_dx9) );
  165. m_halfTexel = 0.5f;
  166. break;
  167. case bgfx::RendererType::Direct3D11:
  168. vs_imgui_color = bgfx::makeRef(vs_imgui_color_dx11, sizeof(vs_imgui_color_dx11) );
  169. fs_imgui_color = bgfx::makeRef(fs_imgui_color_dx11, sizeof(fs_imgui_color_dx11) );
  170. vs_imgui_texture = bgfx::makeRef(vs_imgui_texture_dx11, sizeof(vs_imgui_texture_dx11) );
  171. fs_imgui_texture = bgfx::makeRef(fs_imgui_texture_dx11, sizeof(fs_imgui_texture_dx11) );
  172. break;
  173. default:
  174. vs_imgui_color = bgfx::makeRef(vs_imgui_color_glsl, sizeof(vs_imgui_color_glsl) );
  175. fs_imgui_color = bgfx::makeRef(fs_imgui_color_glsl, sizeof(fs_imgui_color_glsl) );
  176. vs_imgui_texture = bgfx::makeRef(vs_imgui_texture_glsl, sizeof(vs_imgui_texture_glsl) );
  177. fs_imgui_texture = bgfx::makeRef(fs_imgui_texture_glsl, sizeof(fs_imgui_texture_glsl) );
  178. break;
  179. }
  180. bgfx::ShaderHandle vsh;
  181. bgfx::ShaderHandle fsh;
  182. vsh = bgfx::createShader(vs_imgui_color);
  183. fsh = bgfx::createShader(fs_imgui_color);
  184. m_colorProgram = bgfx::createProgram(vsh, fsh);
  185. bgfx::destroyShader(vsh);
  186. bgfx::destroyShader(fsh);
  187. vsh = bgfx::createShader(vs_imgui_texture);
  188. fsh = bgfx::createShader(fs_imgui_texture);
  189. m_textureProgram = bgfx::createProgram(vsh, fsh);
  190. bgfx::destroyShader(vsh);
  191. bgfx::destroyShader(fsh);
  192. const bgfx::Memory* mem = bgfx::alloc(m_textureWidth * m_textureHeight);
  193. stbtt_BakeFontBitmap( (uint8_t*)_data, 0, 15.0f, mem->data, m_textureWidth, m_textureHeight, 32, 96, m_cdata);
  194. m_fontTexture = bgfx::createTexture2D(m_textureWidth, m_textureHeight, 1, bgfx::TextureFormat::R8, BGFX_TEXTURE_NONE, mem);
  195. return true;
  196. }
  197. void destroy()
  198. {
  199. bgfx::destroyUniform(u_texColor);
  200. bgfx::destroyTexture(m_fontTexture);
  201. bgfx::destroyProgram(m_colorProgram);
  202. bgfx::destroyProgram(m_textureProgram);
  203. }
  204. bool anyActive() const
  205. {
  206. return m_active != 0;
  207. }
  208. bool isActive(uint32_t _id) const
  209. {
  210. return m_active == _id;
  211. }
  212. bool isHot(uint32_t _id) const
  213. {
  214. return m_hot == _id;
  215. }
  216. bool inRect(int32_t _x, int32_t _y, int32_t _width, int32_t _height, bool _checkScroll = true) const
  217. {
  218. return (!_checkScroll || m_insideCurrentScroll)
  219. && m_mx >= _x
  220. && m_mx <= _x + _width
  221. && m_my >= _y
  222. && m_my <= _y + _height;
  223. }
  224. void clearInput()
  225. {
  226. m_leftPressed = false;
  227. m_leftReleased = false;
  228. m_scroll = 0;
  229. }
  230. void clearActive()
  231. {
  232. m_active = 0;
  233. // mark all UI for this frame as processed
  234. clearInput();
  235. }
  236. void setActive(uint32_t _id)
  237. {
  238. m_active = _id;
  239. m_wentActive = true;
  240. }
  241. void setHot(uint32_t _id)
  242. {
  243. m_hotToBe = _id;
  244. }
  245. bool buttonLogic(uint32_t _id, bool _over)
  246. {
  247. bool res = false;
  248. // process down
  249. if (!anyActive() )
  250. {
  251. if (_over)
  252. {
  253. setHot(_id);
  254. }
  255. if (isHot(_id)
  256. && m_leftPressed)
  257. {
  258. setActive(_id);
  259. }
  260. }
  261. // if button is active, then react on left up
  262. if (isActive(_id) )
  263. {
  264. m_isActive = true;
  265. if (_over)
  266. {
  267. setHot(_id);
  268. }
  269. if (m_leftReleased)
  270. {
  271. if (isHot(_id) )
  272. {
  273. res = true;
  274. }
  275. clearActive();
  276. }
  277. }
  278. if (isHot(_id) )
  279. {
  280. m_isHot = true;
  281. }
  282. return res;
  283. }
  284. void updateInput(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll)
  285. {
  286. bool left = (_button & IMGUI_MBUT_LEFT) != 0;
  287. m_mx = _mx;
  288. m_my = _my;
  289. m_leftPressed = !m_left && left;
  290. m_leftReleased = m_left && !left;
  291. m_left = left;
  292. m_scroll = _scroll;
  293. }
  294. void beginFrame(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll, uint16_t _width, uint16_t _height, uint8_t _view)
  295. {
  296. m_view = _view;
  297. bgfx::setViewSeq(_view, true);
  298. bgfx::setViewRect(_view, 0, 0, _width, _height);
  299. float proj[16];
  300. bx::mtxOrtho(proj, 0.0f, (float)_width, (float)_height, 0.0f, 0.0f, 1000.0f);
  301. bgfx::setViewTransform(_view, NULL, proj);
  302. updateInput(_mx, _my, _button, _scroll);
  303. m_hot = m_hotToBe;
  304. m_hotToBe = 0;
  305. m_wentActive = false;
  306. m_isActive = false;
  307. m_isHot = false;
  308. m_widgetX = 0;
  309. m_widgetY = 0;
  310. m_widgetW = 0;
  311. m_areaId = 1;
  312. m_widgetId = 1;
  313. }
  314. void endFrame()
  315. {
  316. clearInput();
  317. }
  318. bool beginScrollArea(const char* _name, int32_t _x, int32_t _y, int32_t _width, int32_t _height, int32_t* _scroll)
  319. {
  320. m_areaId++;
  321. m_widgetId = 0;
  322. m_scrollId = (m_areaId << 16) | m_widgetId;
  323. m_widgetX = _x + SCROLL_AREA_PADDING;
  324. m_widgetY = _y + AREA_HEADER + (*_scroll);
  325. m_widgetW = _width - SCROLL_AREA_PADDING * 4;
  326. m_scrollTop = _y + SCROLL_AREA_PADDING;
  327. m_scrollBottom = _y - AREA_HEADER + _height;
  328. m_scrollRight = _x + _width - SCROLL_AREA_PADDING * 3;
  329. m_scrollVal = _scroll;
  330. m_scrollAreaTop = m_widgetY - AREA_HEADER;
  331. m_focusTop = _y - AREA_HEADER;
  332. m_focusBottom = _y - AREA_HEADER + _height;
  333. m_insideScrollArea = inRect(_x, _y, _width, _height, false);
  334. m_insideCurrentScroll = m_insideScrollArea;
  335. drawRoundedRect( (float)_x
  336. , (float)_y
  337. , (float)_width
  338. , (float)_height
  339. , 6
  340. , imguiRGBA(0, 0, 0, 192)
  341. );
  342. drawText(_x + AREA_HEADER / 2
  343. , _y + AREA_HEADER / 2
  344. , ImguiTextAlign::Left
  345. , _name
  346. , imguiRGBA(255, 255, 255, 128)
  347. );
  348. m_scissor = bgfx::setScissor(_x + SCROLL_AREA_PADDING, _y + SCROLL_AREA_PADDING, _width - SCROLL_AREA_PADDING * 4, _height - AREA_HEADER - SCROLL_AREA_PADDING);
  349. return m_insideScrollArea;
  350. }
  351. void endScrollArea()
  352. {
  353. // Disable scissoring.
  354. m_scissor = UINT16_MAX;
  355. // Draw scroll bar
  356. int32_t xx = m_scrollRight + SCROLL_AREA_PADDING / 2;
  357. int32_t yy = m_scrollTop;
  358. int32_t width = SCROLL_AREA_PADDING * 2;
  359. int32_t height = m_scrollBottom - m_scrollTop;
  360. int32_t stop = m_scrollAreaTop;
  361. int32_t sbot = m_widgetY;
  362. int32_t sh = sbot - stop; // The scrollable area height.
  363. float barHeight = (float)height / (float)sh;
  364. if (barHeight < 1)
  365. {
  366. float barY = (float)(yy - stop) / (float)sh;
  367. if (barY < 0)
  368. {
  369. barY = 0;
  370. }
  371. if (barY > 1)
  372. {
  373. barY = 1;
  374. }
  375. // Handle scroll bar logic.
  376. uint32_t hid = m_scrollId;
  377. int32_t hx = xx;
  378. int32_t hy = yy + (int)(barY * height);
  379. int32_t hw = width;
  380. int32_t hh = (int)(barHeight * height);
  381. const int32_t range = height - (hh - 1);
  382. bool over = inRect(hx, hy, hw, hh);
  383. buttonLogic(hid, over);
  384. if (isActive(hid) )
  385. {
  386. float u = (float)(hy - yy) / (float)range;
  387. if (m_wentActive)
  388. {
  389. m_dragY = m_my;
  390. m_dragOrig = u;
  391. }
  392. if (m_dragY != m_my)
  393. {
  394. u = m_dragOrig + (m_my - m_dragY) / (float)range;
  395. if (u < 0)
  396. {
  397. u = 0;
  398. }
  399. if (u > 1)
  400. {
  401. u = 1;
  402. }
  403. *m_scrollVal = (int)(u * (height - sh) );
  404. }
  405. }
  406. // BG
  407. drawRoundedRect( (float)xx
  408. , (float)yy
  409. , (float)width
  410. , (float)height
  411. , (float)width / 2 - 1
  412. , imguiRGBA(0, 0, 0, 196)
  413. );
  414. // Bar
  415. if (isActive(hid) )
  416. {
  417. drawRoundedRect( (float)hx
  418. , (float)hy
  419. , (float)hw
  420. , (float)hh
  421. , (float)width / 2 - 1
  422. , imguiRGBA(255, 196, 0, 196)
  423. );
  424. }
  425. else
  426. {
  427. drawRoundedRect( (float)hx
  428. , (float)hy
  429. , (float)hw
  430. , (float)hh
  431. , (float)width / 2 - 1
  432. , isHot(hid) ? imguiRGBA(255, 196, 0, 96) : imguiRGBA(255, 255, 255, 64)
  433. );
  434. }
  435. // Handle mouse scrolling.
  436. if (m_insideScrollArea) // && !anyActive())
  437. {
  438. if (m_scroll)
  439. {
  440. *m_scrollVal += 20 * m_scroll;
  441. if (*m_scrollVal < 0)
  442. {
  443. *m_scrollVal = 0;
  444. }
  445. if (*m_scrollVal > (sh - height) )
  446. {
  447. *m_scrollVal = (sh - height);
  448. }
  449. }
  450. }
  451. }
  452. m_insideCurrentScroll = false;
  453. }
  454. bool button(const char* _text, bool _enabled)
  455. {
  456. m_widgetId++;
  457. uint32_t id = (m_areaId << 16) | m_widgetId;
  458. int32_t xx = m_widgetX;
  459. int32_t yy = m_widgetY;
  460. int32_t width = m_widgetW;
  461. int32_t height = BUTTON_HEIGHT;
  462. m_widgetY += BUTTON_HEIGHT + DEFAULT_SPACING;
  463. bool over = _enabled && inRect(xx, yy, width, height);
  464. bool res = buttonLogic(id, over);
  465. drawRoundedRect( (float)xx
  466. , (float)yy
  467. , (float)width
  468. , (float)height
  469. , (float)BUTTON_HEIGHT / 2 - 1
  470. , imguiRGBA(128, 128, 128, isActive(id) ? 196 : 96)
  471. );
  472. if (_enabled)
  473. {
  474. drawText(xx + BUTTON_HEIGHT / 2
  475. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  476. , ImguiTextAlign::Left
  477. , _text
  478. , isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200)
  479. );
  480. }
  481. else
  482. {
  483. drawText(xx + BUTTON_HEIGHT / 2
  484. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  485. , ImguiTextAlign::Left
  486. , _text
  487. , imguiRGBA(128, 128, 128, 200)
  488. );
  489. }
  490. return res;
  491. }
  492. bool item(const char* _text, bool _enabled)
  493. {
  494. m_widgetId++;
  495. uint32_t id = (m_areaId << 16) | m_widgetId;
  496. int32_t xx = m_widgetX;
  497. int32_t yy = m_widgetY;
  498. int32_t width = m_widgetW;
  499. int32_t height = BUTTON_HEIGHT;
  500. m_widgetY += BUTTON_HEIGHT + DEFAULT_SPACING;
  501. bool over = _enabled && inRect(xx, yy, width, height);
  502. bool res = buttonLogic(id, over);
  503. if (isHot(id) )
  504. {
  505. drawRoundedRect( (float)xx
  506. , (float)yy
  507. , (float)width
  508. , (float)height
  509. , 2.0f
  510. , imguiRGBA(255, 196, 0, isActive(id) ? 196 : 96)
  511. );
  512. }
  513. if (_enabled)
  514. {
  515. drawText(xx + BUTTON_HEIGHT / 2
  516. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  517. , ImguiTextAlign::Left
  518. , _text
  519. , imguiRGBA(255, 255, 255, 200)
  520. );
  521. }
  522. else
  523. {
  524. drawText(xx + BUTTON_HEIGHT / 2
  525. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  526. , ImguiTextAlign::Left
  527. , _text
  528. , imguiRGBA(128, 128, 128, 200)
  529. );
  530. }
  531. return res;
  532. }
  533. bool check(const char* _text, bool _checked, bool _enabled)
  534. {
  535. m_widgetId++;
  536. uint32_t id = (m_areaId << 16) | m_widgetId;
  537. int32_t xx = m_widgetX;
  538. int32_t yy = m_widgetY;
  539. int32_t width = m_widgetW;
  540. int32_t height = BUTTON_HEIGHT;
  541. m_widgetY += BUTTON_HEIGHT + DEFAULT_SPACING;
  542. bool over = _enabled && inRect(xx, yy, width, height);
  543. bool res = buttonLogic(id, over);
  544. const int32_t cx = xx + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
  545. const int32_t cy = yy + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
  546. drawRoundedRect( (float)cx - 3
  547. , (float)cy - 3
  548. , (float)CHECK_SIZE + 6
  549. , (float)CHECK_SIZE + 6
  550. , 4
  551. , imguiRGBA(128, 128, 128, isActive(id) ? 196 : 96)
  552. );
  553. if (_checked)
  554. {
  555. if (_enabled)
  556. {
  557. drawRoundedRect( (float)cx
  558. , (float)cy
  559. , (float)CHECK_SIZE
  560. , (float)CHECK_SIZE
  561. , (float)CHECK_SIZE / 2 - 1
  562. , imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200)
  563. );
  564. }
  565. else
  566. {
  567. drawRoundedRect( (float)cx
  568. , (float)cy
  569. , (float)CHECK_SIZE
  570. , (float)CHECK_SIZE
  571. , (float)CHECK_SIZE / 2 - 1
  572. , imguiRGBA(128, 128, 128, 200)
  573. );
  574. }
  575. }
  576. if (_enabled)
  577. {
  578. drawText(xx + BUTTON_HEIGHT
  579. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  580. , ImguiTextAlign::Left
  581. , _text
  582. , isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200)
  583. );
  584. }
  585. else
  586. {
  587. drawText(xx + BUTTON_HEIGHT
  588. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  589. , ImguiTextAlign::Left
  590. , _text
  591. , imguiRGBA(128, 128, 128, 200)
  592. );
  593. }
  594. return res;
  595. }
  596. bool collapse(const char* _text, const char* _subtext, bool _checked, bool _enabled)
  597. {
  598. m_widgetId++;
  599. uint32_t id = (m_areaId << 16) | m_widgetId;
  600. int32_t xx = m_widgetX;
  601. int32_t yy = m_widgetY;
  602. int32_t width = m_widgetW;
  603. int32_t height = BUTTON_HEIGHT;
  604. m_widgetY += BUTTON_HEIGHT + DEFAULT_SPACING;
  605. const int32_t cx = xx + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
  606. const int32_t cy = yy + BUTTON_HEIGHT / 2 - CHECK_SIZE / 2;
  607. bool over = _enabled && inRect(xx, yy, width, height);
  608. bool res = buttonLogic(id, over);
  609. if (_checked)
  610. {
  611. drawTriangle(cx
  612. , cy
  613. , CHECK_SIZE
  614. , CHECK_SIZE
  615. , 2
  616. , imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200)
  617. );
  618. }
  619. else
  620. {
  621. drawTriangle(cx
  622. , cy
  623. , CHECK_SIZE
  624. , CHECK_SIZE
  625. , 1
  626. , imguiRGBA(255, 255, 255, isActive(id) ? 255 : 200)
  627. );
  628. }
  629. if (_enabled)
  630. {
  631. drawText(xx + BUTTON_HEIGHT
  632. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  633. , ImguiTextAlign::Left
  634. , _text
  635. , isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200)
  636. );
  637. }
  638. else
  639. {
  640. drawText(xx + BUTTON_HEIGHT
  641. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  642. , ImguiTextAlign::Left
  643. , _text
  644. , imguiRGBA(128, 128, 128, 200)
  645. );
  646. }
  647. if (_subtext)
  648. {
  649. drawText(xx + width - BUTTON_HEIGHT / 2
  650. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  651. , ImguiTextAlign::Right
  652. , _subtext
  653. , imguiRGBA(255, 255, 255, 128)
  654. );
  655. }
  656. return res;
  657. }
  658. void labelVargs(const char* _format, va_list _argList)
  659. {
  660. char temp[8192];
  661. char* out = temp;
  662. int32_t len = bx::vsnprintf(out, sizeof(temp), _format, _argList);
  663. if ( (int32_t)sizeof(temp) < len)
  664. {
  665. out = (char*)alloca(len+1);
  666. len = bx::vsnprintf(out, len, _format, _argList);
  667. }
  668. out[len] = '\0';
  669. int32_t xx = m_widgetX;
  670. int32_t yy = m_widgetY;
  671. m_widgetY += BUTTON_HEIGHT;
  672. drawText(xx
  673. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  674. , ImguiTextAlign::Left
  675. , out
  676. , imguiRGBA(255, 255, 255, 255)
  677. );
  678. }
  679. void value(const char* _text)
  680. {
  681. const int32_t xx = m_widgetX;
  682. const int32_t yy = m_widgetY;
  683. const int32_t ww = m_widgetW;
  684. m_widgetY += BUTTON_HEIGHT;
  685. drawText(xx + ww - BUTTON_HEIGHT / 2
  686. , yy + BUTTON_HEIGHT / 2 + TEXT_HEIGHT / 2
  687. , ImguiTextAlign::Right
  688. , _text
  689. , imguiRGBA(255, 255, 255, 200)
  690. );
  691. }
  692. bool slider(const char* _text, float* _val, float _vmin, float _vmax, float _vinc, bool _enabled)
  693. {
  694. m_widgetId++;
  695. uint32_t id = (m_areaId << 16) | m_widgetId;
  696. int32_t xx = m_widgetX;
  697. int32_t yy = m_widgetY;
  698. int32_t width = m_widgetW;
  699. int32_t height = SLIDER_HEIGHT;
  700. m_widgetY += SLIDER_HEIGHT + DEFAULT_SPACING;
  701. drawRoundedRect( (float)xx, (float)yy, (float)width, (float)height, 4.0f, imguiRGBA(0, 0, 0, 128) );
  702. const int32_t range = width - SLIDER_MARKER_WIDTH;
  703. float uu = (*_val - _vmin) / (_vmax - _vmin);
  704. if (uu < 0)
  705. {
  706. uu = 0;
  707. }
  708. if (uu > 1)
  709. {
  710. uu = 1;
  711. }
  712. int32_t m = (int)(uu * range);
  713. bool over = _enabled && inRect(xx + m, yy, SLIDER_MARKER_WIDTH, SLIDER_HEIGHT);
  714. bool res = buttonLogic(id, over);
  715. bool valChanged = false;
  716. if (isActive(id) )
  717. {
  718. if (m_wentActive)
  719. {
  720. m_dragX = m_mx;
  721. m_dragOrig = uu;
  722. }
  723. if (m_dragX != m_mx)
  724. {
  725. uu = m_dragOrig + (float)(m_mx - m_dragX) / (float)range;
  726. if (uu < 0)
  727. {
  728. uu = 0;
  729. }
  730. if (uu > 1)
  731. {
  732. uu = 1;
  733. }
  734. *_val = _vmin + uu * (_vmax - _vmin);
  735. *_val = floorf(*_val / _vinc + 0.5f) * _vinc; // Snap to vinc
  736. m = (int)(uu * range);
  737. valChanged = true;
  738. }
  739. }
  740. if (isActive(id) )
  741. {
  742. drawRoundedRect( (float)(xx + m)
  743. , (float)yy
  744. , (float)SLIDER_MARKER_WIDTH
  745. , (float)SLIDER_HEIGHT
  746. , 4.0f
  747. , imguiRGBA(255, 255, 255, 255)
  748. );
  749. }
  750. else
  751. {
  752. drawRoundedRect( (float)(xx + m)
  753. , (float)yy
  754. , (float)SLIDER_MARKER_WIDTH
  755. , (float)SLIDER_HEIGHT
  756. , 4.0f
  757. , isHot(id) ? imguiRGBA(255, 196, 0, 128) : imguiRGBA(255, 255, 255, 64)
  758. );
  759. }
  760. // TODO: fix this, take a look at 'nicenum'.
  761. int32_t digits = (int)(ceilf(log10f(_vinc) ) );
  762. char fmt[16];
  763. bx::snprintf(fmt, 16, "%%.%df", digits >= 0 ? 0 : -digits);
  764. char msg[128];
  765. bx::snprintf(msg, 128, fmt, *_val);
  766. if (_enabled)
  767. {
  768. drawText(xx + SLIDER_HEIGHT / 2
  769. , yy + SLIDER_HEIGHT / 2 + TEXT_HEIGHT / 2
  770. , ImguiTextAlign::Left
  771. , _text
  772. , isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200)
  773. );
  774. drawText(xx + width - SLIDER_HEIGHT / 2
  775. , yy + SLIDER_HEIGHT / 2 + TEXT_HEIGHT / 2
  776. , ImguiTextAlign::Right
  777. , msg
  778. , isHot(id) ? imguiRGBA(255, 196, 0, 255) : imguiRGBA(255, 255, 255, 200)
  779. );
  780. }
  781. else
  782. {
  783. drawText(xx + SLIDER_HEIGHT / 2
  784. , yy + SLIDER_HEIGHT / 2 + TEXT_HEIGHT / 2
  785. , ImguiTextAlign::Left
  786. , _text
  787. , imguiRGBA(128, 128, 128, 200)
  788. );
  789. drawText(xx + width - SLIDER_HEIGHT / 2
  790. , yy + SLIDER_HEIGHT / 2 + TEXT_HEIGHT / 2
  791. , ImguiTextAlign::Right
  792. , msg
  793. , imguiRGBA(128, 128, 128, 200)
  794. );
  795. }
  796. return res || valChanged;
  797. }
  798. void indent()
  799. {
  800. m_widgetX += INDENT_SIZE;
  801. m_widgetW -= INDENT_SIZE;
  802. }
  803. void unindent()
  804. {
  805. m_widgetX -= INDENT_SIZE;
  806. m_widgetW += INDENT_SIZE;
  807. }
  808. void separator()
  809. {
  810. m_widgetY += DEFAULT_SPACING * 3;
  811. }
  812. void separatorLine()
  813. {
  814. int32_t xx = m_widgetX;
  815. int32_t yy = m_widgetY;
  816. int32_t width = m_widgetW;
  817. int32_t height = 1;
  818. m_widgetY += DEFAULT_SPACING * 4;
  819. drawRect( (float)xx
  820. , (float)yy
  821. , (float)width
  822. , (float)height
  823. , imguiRGBA(255, 255, 255, 32)
  824. );
  825. }
  826. void drawPolygon(const float* _coords, uint32_t _numCoords, float _r, uint32_t _abgr)
  827. {
  828. _numCoords = bx::uint32_min(_numCoords, MAX_TEMP_COORDS);
  829. for (uint32_t ii = 0, jj = _numCoords - 1; ii < _numCoords; jj = ii++)
  830. {
  831. const float* v0 = &_coords[jj * 2];
  832. const float* v1 = &_coords[ii * 2];
  833. float dx = v1[0] - v0[0];
  834. float dy = v1[1] - v0[1];
  835. float d = sqrtf(dx * dx + dy * dy);
  836. if (d > 0)
  837. {
  838. d = 1.0f / d;
  839. dx *= d;
  840. dy *= d;
  841. }
  842. m_tempNormals[jj * 2 + 0] = dy;
  843. m_tempNormals[jj * 2 + 1] = -dx;
  844. }
  845. for (uint32_t ii = 0, jj = _numCoords - 1; ii < _numCoords; jj = ii++)
  846. {
  847. float dlx0 = m_tempNormals[jj * 2 + 0];
  848. float dly0 = m_tempNormals[jj * 2 + 1];
  849. float dlx1 = m_tempNormals[ii * 2 + 0];
  850. float dly1 = m_tempNormals[ii * 2 + 1];
  851. float dmx = (dlx0 + dlx1) * 0.5f;
  852. float dmy = (dly0 + dly1) * 0.5f;
  853. float dmr2 = dmx * dmx + dmy * dmy;
  854. if (dmr2 > 0.000001f)
  855. {
  856. float scale = 1.0f / dmr2;
  857. if (scale > 10.0f)
  858. {
  859. scale = 10.0f;
  860. }
  861. dmx *= scale;
  862. dmy *= scale;
  863. }
  864. m_tempCoords[ii * 2 + 0] = _coords[ii * 2 + 0] + dmx * _r;
  865. m_tempCoords[ii * 2 + 1] = _coords[ii * 2 + 1] + dmy * _r;
  866. }
  867. uint32_t numVertices = _numCoords*6 + (_numCoords-2)*3;
  868. if (bgfx::checkAvailTransientVertexBuffer(numVertices, PosColorVertex::ms_decl) )
  869. {
  870. bgfx::TransientVertexBuffer tvb;
  871. bgfx::allocTransientVertexBuffer(&tvb, numVertices, PosColorVertex::ms_decl);
  872. uint32_t trans = _abgr&0xffffff;
  873. PosColorVertex* vertex = (PosColorVertex*)tvb.data;
  874. for (uint32_t ii = 0, jj = _numCoords-1; ii < _numCoords; jj = ii++)
  875. {
  876. vertex->m_x = _coords[ii*2+0];
  877. vertex->m_y = _coords[ii*2+1];
  878. vertex->m_abgr = _abgr;
  879. ++vertex;
  880. vertex->m_x = _coords[jj*2+0];
  881. vertex->m_y = _coords[jj*2+1];
  882. vertex->m_abgr = _abgr;
  883. ++vertex;
  884. vertex->m_x = m_tempCoords[jj*2+0];
  885. vertex->m_y = m_tempCoords[jj*2+1];
  886. vertex->m_abgr = trans;
  887. ++vertex;
  888. vertex->m_x = m_tempCoords[jj*2+0];
  889. vertex->m_y = m_tempCoords[jj*2+1];
  890. vertex->m_abgr = trans;
  891. ++vertex;
  892. vertex->m_x = m_tempCoords[ii*2+0];
  893. vertex->m_y = m_tempCoords[ii*2+1];
  894. vertex->m_abgr = trans;
  895. ++vertex;
  896. vertex->m_x = _coords[ii*2+0];
  897. vertex->m_y = _coords[ii*2+1];
  898. vertex->m_abgr = _abgr;
  899. ++vertex;
  900. }
  901. for (uint32_t ii = 2; ii < _numCoords; ++ii)
  902. {
  903. vertex->m_x = _coords[0];
  904. vertex->m_y = _coords[1];
  905. vertex->m_abgr = _abgr;
  906. ++vertex;
  907. vertex->m_x = _coords[(ii-1)*2+0];
  908. vertex->m_y = _coords[(ii-1)*2+1];
  909. vertex->m_abgr = _abgr;
  910. ++vertex;
  911. vertex->m_x = _coords[ii*2+0];
  912. vertex->m_y = _coords[ii*2+1];
  913. vertex->m_abgr = _abgr;
  914. ++vertex;
  915. }
  916. bgfx::setVertexBuffer(&tvb);
  917. bgfx::setState(0
  918. | BGFX_STATE_RGB_WRITE
  919. | BGFX_STATE_ALPHA_WRITE
  920. | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
  921. );
  922. bgfx::setProgram(m_colorProgram);
  923. bgfx::setScissor(m_scissor);
  924. bgfx::submit(m_view);
  925. }
  926. }
  927. void drawRect(float _x, float _y, float w, float h, uint32_t _argb, float _fth = 1.0f)
  928. {
  929. float verts[4 * 2] =
  930. {
  931. _x + 0.5f, _y + 0.5f,
  932. _x + w - 0.5f, _y + 0.5f,
  933. _x + w - 0.5f, _y + h - 0.5f,
  934. _x + 0.5f, _y + h - 0.5f,
  935. };
  936. drawPolygon(verts, 4, _fth, _argb);
  937. }
  938. void drawRoundedRect(float _x, float _y, float w, float h, float r, uint32_t _argb, float _fth = 1.0f)
  939. {
  940. const uint32_t num = NUM_CIRCLE_VERTS / 4;
  941. const float* cverts = m_circleVerts;
  942. float verts[(num + 1) * 4 * 2];
  943. float* vv = verts;
  944. for (uint32_t ii = 0; ii <= num; ++ii)
  945. {
  946. *vv++ = _x + w - r + cverts[ii * 2] * r;
  947. *vv++ = _y + h - r + cverts[ii * 2 + 1] * r;
  948. }
  949. for (uint32_t ii = num; ii <= num * 2; ++ii)
  950. {
  951. *vv++ = _x + r + cverts[ii * 2] * r;
  952. *vv++ = _y + h - r + cverts[ii * 2 + 1] * r;
  953. }
  954. for (uint32_t ii = num * 2; ii <= num * 3; ++ii)
  955. {
  956. *vv++ = _x + r + cverts[ii * 2] * r;
  957. *vv++ = _y + r + cverts[ii * 2 + 1] * r;
  958. }
  959. for (uint32_t ii = num * 3; ii < num * 4; ++ii)
  960. {
  961. *vv++ = _x + w - r + cverts[ii * 2] * r;
  962. *vv++ = _y + r + cverts[ii * 2 + 1] * r;
  963. }
  964. *vv++ = _x + w - r + cverts[0] * r;
  965. *vv++ = _y + r + cverts[1] * r;
  966. drawPolygon(verts, (num + 1) * 4, _fth, _argb);
  967. }
  968. void drawLine(float _x0, float _y0, float _x1, float _y1, float _r, uint32_t _abgr, float _fth = 1.0f)
  969. {
  970. float dx = _x1 - _x0;
  971. float dy = _y1 - _y0;
  972. float d = sqrtf(dx * dx + dy * dy);
  973. if (d > 0.0001f)
  974. {
  975. d = 1.0f / d;
  976. dx *= d;
  977. dy *= d;
  978. }
  979. float nx = dy;
  980. float ny = -dx;
  981. float verts[4 * 2];
  982. _r -= _fth;
  983. _r *= 0.5f;
  984. if (_r < 0.01f)
  985. {
  986. _r = 0.01f;
  987. }
  988. dx *= _r;
  989. dy *= _r;
  990. nx *= _r;
  991. ny *= _r;
  992. verts[0] = _x0 - dx - nx;
  993. verts[1] = _y0 - dy - ny;
  994. verts[2] = _x0 - dx + nx;
  995. verts[3] = _y0 - dy + ny;
  996. verts[4] = _x1 + dx + nx;
  997. verts[5] = _y1 + dy + ny;
  998. verts[6] = _x1 + dx - nx;
  999. verts[7] = _y1 + dy - ny;
  1000. drawPolygon(verts, 4, _fth, _abgr);
  1001. }
  1002. void drawTriangle(int32_t _x, int32_t _y, int32_t _width, int32_t _height, int32_t _flags, uint32_t _abgr)
  1003. {
  1004. if (1 == _flags)
  1005. {
  1006. const float verts[3 * 2] =
  1007. {
  1008. (float)_x + 0.5f, (float)_y + 0.5f,
  1009. (float)_x + 0.5f + (float)_width * 1.0f, (float)_y + 0.5f + (float)_height / 2.0f - 0.5f,
  1010. (float)_x + 0.5f, (float)_y + 0.5f + (float)_height - 1.0f,
  1011. };
  1012. drawPolygon(verts, 3, 1.0f, _abgr);
  1013. }
  1014. else
  1015. {
  1016. const float verts[3 * 2] =
  1017. {
  1018. (float)_x + 0.5f, (float)_y + 0.5f + (float)_height - 1.0f,
  1019. (float)_x + 0.5f + (float)_width / 2.0f - 0.5f, (float)_y + 0.5f,
  1020. (float)_x + 0.5f + (float)_width - 1.0f, (float)_y + 0.5f + (float)_height - 1.0f,
  1021. };
  1022. drawPolygon(verts, 3, 1.0f, _abgr);
  1023. }
  1024. }
  1025. void getBakedQuad(stbtt_bakedchar* _chardata, int32_t char_index, float* _xpos, float* _ypos, stbtt_aligned_quad* _quad)
  1026. {
  1027. stbtt_bakedchar* b = _chardata + char_index;
  1028. int32_t round_x = STBTT_ifloor(*_xpos + b->xoff);
  1029. int32_t round_y = STBTT_ifloor(*_ypos + b->yoff);
  1030. _quad->x0 = (float)round_x;
  1031. _quad->y0 = (float)round_y;
  1032. _quad->x1 = (float)round_x + b->x1 - b->x0;
  1033. _quad->y1 = (float)round_y + b->y1 - b->y0;
  1034. _quad->s0 = (b->x0 + m_halfTexel) * m_invTextureWidth;
  1035. _quad->t0 = (b->y0 + m_halfTexel) * m_invTextureWidth;
  1036. _quad->s1 = (b->x1 + m_halfTexel) * m_invTextureHeight;
  1037. _quad->t1 = (b->y1 + m_halfTexel) * m_invTextureHeight;
  1038. *_xpos += b->xadvance;
  1039. }
  1040. float getTextLength(stbtt_bakedchar* _chardata, const char* _text, uint32_t& _numVertices)
  1041. {
  1042. float xpos = 0;
  1043. float len = 0;
  1044. uint32_t numVertices = 0;
  1045. while (*_text)
  1046. {
  1047. int32_t ch = (uint8_t)*_text;
  1048. if (ch == '\t')
  1049. {
  1050. for (int32_t ii = 0; ii < 4; ++ii)
  1051. {
  1052. if (xpos < s_tabStops[ii])
  1053. {
  1054. xpos = s_tabStops[ii];
  1055. break;
  1056. }
  1057. }
  1058. }
  1059. else if (ch >= ' '
  1060. && ch < 128)
  1061. {
  1062. stbtt_bakedchar* b = _chardata + ch - ' ';
  1063. int32_t round_x = STBTT_ifloor( (xpos + b->xoff) + 0.5);
  1064. len = round_x + b->x1 - b->x0 + 0.5f;
  1065. xpos += b->xadvance;
  1066. numVertices += 6;
  1067. }
  1068. ++_text;
  1069. }
  1070. _numVertices = numVertices;
  1071. return len;
  1072. }
  1073. void drawText(int32_t _x, int32_t _y, ImguiTextAlign::Enum _align, const char* _text, uint32_t _abgr)
  1074. {
  1075. drawText( (float)_x, (float)_y, _text, _align, _abgr);
  1076. }
  1077. void drawText(float _x, float _y, const char* _text, ImguiTextAlign::Enum _align, uint32_t _abgr)
  1078. {
  1079. if (!_text)
  1080. {
  1081. return;
  1082. }
  1083. uint32_t numVertices = 0;
  1084. if (_align == ImguiTextAlign::Center)
  1085. {
  1086. _x -= getTextLength(m_cdata, _text, numVertices) / 2;
  1087. }
  1088. else if (_align == ImguiTextAlign::Right)
  1089. {
  1090. _x -= getTextLength(m_cdata, _text, numVertices);
  1091. }
  1092. else // just count vertices
  1093. {
  1094. getTextLength(m_cdata, _text, numVertices);
  1095. }
  1096. if (bgfx::checkAvailTransientVertexBuffer(numVertices, PosColorUvVertex::ms_decl) )
  1097. {
  1098. bgfx::TransientVertexBuffer tvb;
  1099. bgfx::allocTransientVertexBuffer(&tvb, numVertices, PosColorUvVertex::ms_decl);
  1100. PosColorUvVertex* vertex = (PosColorUvVertex*)tvb.data;
  1101. const float ox = _x;
  1102. while (*_text)
  1103. {
  1104. int32_t ch = (uint8_t)*_text;
  1105. if (ch == '\t')
  1106. {
  1107. for (int32_t i = 0; i < 4; ++i)
  1108. {
  1109. if (_x < s_tabStops[i] + ox)
  1110. {
  1111. _x = s_tabStops[i] + ox;
  1112. break;
  1113. }
  1114. }
  1115. }
  1116. else if (ch >= ' '
  1117. && ch < 128)
  1118. {
  1119. stbtt_aligned_quad quad;
  1120. getBakedQuad(m_cdata, ch - 32, &_x, &_y, &quad);
  1121. vertex->m_x = quad.x0;
  1122. vertex->m_y = quad.y0;
  1123. vertex->m_u = quad.s0;
  1124. vertex->m_v = quad.t0;
  1125. vertex->m_abgr = _abgr;
  1126. ++vertex;
  1127. vertex->m_x = quad.x1;
  1128. vertex->m_y = quad.y1;
  1129. vertex->m_u = quad.s1;
  1130. vertex->m_v = quad.t1;
  1131. vertex->m_abgr = _abgr;
  1132. ++vertex;
  1133. vertex->m_x = quad.x1;
  1134. vertex->m_y = quad.y0;
  1135. vertex->m_u = quad.s1;
  1136. vertex->m_v = quad.t0;
  1137. vertex->m_abgr = _abgr;
  1138. ++vertex;
  1139. vertex->m_x = quad.x0;
  1140. vertex->m_y = quad.y0;
  1141. vertex->m_u = quad.s0;
  1142. vertex->m_v = quad.t0;
  1143. vertex->m_abgr = _abgr;
  1144. ++vertex;
  1145. vertex->m_x = quad.x0;
  1146. vertex->m_y = quad.y1;
  1147. vertex->m_u = quad.s0;
  1148. vertex->m_v = quad.t1;
  1149. vertex->m_abgr = _abgr;
  1150. ++vertex;
  1151. vertex->m_x = quad.x1;
  1152. vertex->m_y = quad.y1;
  1153. vertex->m_u = quad.s1;
  1154. vertex->m_v = quad.t1;
  1155. vertex->m_abgr = _abgr;
  1156. ++vertex;
  1157. }
  1158. ++_text;
  1159. }
  1160. bgfx::setTexture(0, u_texColor, m_fontTexture);
  1161. bgfx::setVertexBuffer(&tvb);
  1162. bgfx::setState(0
  1163. | BGFX_STATE_RGB_WRITE
  1164. | BGFX_STATE_ALPHA_WRITE
  1165. | BGFX_STATE_BLEND_FUNC(BGFX_STATE_BLEND_SRC_ALPHA, BGFX_STATE_BLEND_INV_SRC_ALPHA)
  1166. );
  1167. bgfx::setProgram(m_textureProgram);
  1168. bgfx::setScissor(m_scissor);
  1169. bgfx::submit(m_view);
  1170. }
  1171. }
  1172. int32_t m_mx;
  1173. int32_t m_my;
  1174. int32_t m_scroll;
  1175. uint32_t m_active;
  1176. uint32_t m_hot;
  1177. uint32_t m_hotToBe;
  1178. int32_t m_dragX;
  1179. int32_t m_dragY;
  1180. float m_dragOrig;
  1181. int32_t m_widgetX;
  1182. int32_t m_widgetY;
  1183. int32_t m_widgetW;
  1184. bool m_left;
  1185. bool m_leftPressed;
  1186. bool m_leftReleased;
  1187. bool m_isHot;
  1188. bool m_isActive;
  1189. bool m_wentActive;
  1190. bool m_insideCurrentScroll;
  1191. uint32_t m_areaId;
  1192. uint32_t m_widgetId;
  1193. uint16_t m_scissor;
  1194. float m_tempCoords[MAX_TEMP_COORDS * 2];
  1195. float m_tempNormals[MAX_TEMP_COORDS * 2];
  1196. float m_circleVerts[NUM_CIRCLE_VERTS * 2];
  1197. int32_t m_scrollTop;
  1198. int32_t m_scrollBottom;
  1199. int32_t m_scrollRight;
  1200. int32_t m_scrollAreaTop;
  1201. int32_t* m_scrollVal;
  1202. int32_t m_focusTop;
  1203. int32_t m_focusBottom;
  1204. uint32_t m_scrollId;
  1205. bool m_insideScrollArea;
  1206. stbtt_bakedchar m_cdata[96]; // ASCII 32..126 is 95 glyphs
  1207. uint16_t m_textureWidth;
  1208. uint16_t m_textureHeight;
  1209. float m_invTextureWidth;
  1210. float m_invTextureHeight;
  1211. float m_halfTexel;
  1212. uint8_t m_view;
  1213. bgfx::UniformHandle u_texColor;
  1214. bgfx::TextureHandle m_fontTexture;
  1215. bgfx::ProgramHandle m_colorProgram;
  1216. bgfx::ProgramHandle m_textureProgram;
  1217. };
  1218. static Imgui s_imgui;
  1219. bool imguiCreate(const void* _data)
  1220. {
  1221. return s_imgui.create(_data);
  1222. }
  1223. void imguiDestroy()
  1224. {
  1225. s_imgui.destroy();
  1226. }
  1227. void imguiBeginFrame(int32_t _mx, int32_t _my, uint8_t _button, int32_t _scroll, uint16_t _width, uint16_t _height, uint8_t _view)
  1228. {
  1229. s_imgui.beginFrame(_mx, _my, _button, _scroll, _width, _height, _view);
  1230. }
  1231. void imguiEndFrame()
  1232. {
  1233. s_imgui.endFrame();
  1234. }
  1235. bool imguiBeginScrollArea(const char* _name, int32_t _x, int32_t _y, int32_t _width, int32_t _height, int32_t* _scroll)
  1236. {
  1237. return s_imgui.beginScrollArea(_name, _x, _y, _width, _height, _scroll);
  1238. }
  1239. void imguiEndScrollArea()
  1240. {
  1241. return s_imgui.endScrollArea();
  1242. }
  1243. void imguiIndent()
  1244. {
  1245. s_imgui.indent();
  1246. }
  1247. void imguiUnindent()
  1248. {
  1249. s_imgui.unindent();
  1250. }
  1251. void imguiSeparator()
  1252. {
  1253. s_imgui.separator();
  1254. }
  1255. void imguiSeparatorLine()
  1256. {
  1257. s_imgui.separatorLine();
  1258. }
  1259. bool imguiButton(const char* _text, bool _enabled)
  1260. {
  1261. return s_imgui.button(_text, _enabled);
  1262. }
  1263. bool imguiItem(const char* _text, bool _enabled)
  1264. {
  1265. return s_imgui.item(_text, _enabled);
  1266. }
  1267. bool imguiCheck(const char* _text, bool _checked, bool _enabled)
  1268. {
  1269. return s_imgui.check(_text, _checked, _enabled);
  1270. }
  1271. bool imguiCollapse(const char* _text, const char* _subtext, bool _checked, bool _enabled)
  1272. {
  1273. return s_imgui.collapse(_text, _subtext, _checked, _enabled);
  1274. }
  1275. void imguiLabel(const char* _format, ...)
  1276. {
  1277. va_list argList;
  1278. va_start(argList, _format);
  1279. s_imgui.labelVargs(_format, argList);
  1280. va_end(argList);
  1281. }
  1282. void imguiValue(const char* _text)
  1283. {
  1284. s_imgui.value(_text);
  1285. }
  1286. bool imguiSlider(const char* _text, float* _val, float _vmin, float _vmax, float _vinc, bool _enabled)
  1287. {
  1288. return s_imgui.slider(_text, _val, _vmin, _vmax, _vinc, _enabled);
  1289. }
  1290. bool imguiSlider(const char* _text, int32_t* _val, int32_t _vmin, int32_t _vmax, bool _enabled)
  1291. {
  1292. float val = (float)*_val;
  1293. bool result = s_imgui.slider(_text, &val, (float)_vmin, (float)_vmax, 1.0f, _enabled);
  1294. *_val = (int32_t)val;
  1295. return result;
  1296. }
  1297. uint32_t imguiChooseUseMacroInstead(uint32_t _selected, ...)
  1298. {
  1299. va_list argList;
  1300. va_start(argList, _selected);
  1301. const char* str = va_arg(argList, const char*);
  1302. for (uint32_t ii = 0; str != NULL; ++ii, str = va_arg(argList, const char*))
  1303. {
  1304. if (imguiCheck(str, ii == _selected) )
  1305. {
  1306. _selected = ii;
  1307. }
  1308. }
  1309. va_end(argList);
  1310. return _selected;
  1311. }
  1312. void imguiDrawText(int32_t _x, int32_t _y, ImguiTextAlign::Enum _align, const char* _text, uint32_t _argb)
  1313. {
  1314. s_imgui.drawText(_x, _y, _align, _text, _argb);
  1315. }
  1316. void imguiDrawLine(float _x0, float _y0, float _x1, float _y1, float _r, uint32_t _argb)
  1317. {
  1318. s_imgui.drawLine(_x0, _y0, _x1, _y1, _r, _argb);
  1319. }
  1320. void imguiDrawRoundedRect(float _x, float _y, float _width, float _height, float _r, uint32_t _argb)
  1321. {
  1322. s_imgui.drawRoundedRect(_x, _y, _width, _height, _r, _argb);
  1323. }
  1324. void imguiDrawRect(float _x, float _y, float _width, float _height, uint32_t _argb)
  1325. {
  1326. s_imgui.drawRect(_x, _y, _width, _height, _argb);
  1327. }
  1328. int imguiReserve(int _y)
  1329. {
  1330. const int yy = s_imgui.m_widgetY;
  1331. s_imgui.m_widgetY += _y;
  1332. return yy;
  1333. }