Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ysfx_api_gfx_lice.hpp 44KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  1. //
  2. // This file is based in part on modified source code from `WDL/eel2/eel_lice.h`.
  3. // The zlib license from the WDL applies to this source file.
  4. //
  5. //------------------------------------------------------------------------------
  6. //
  7. // Copyright (C) 2021 and later Jean Pierre Cimalando
  8. // Copyright (C) 2005 and later Cockos Incorporated
  9. //
  10. //
  11. // Portions copyright other contributors, see each source file for more information
  12. //
  13. // This software is provided 'as-is', without any express or implied
  14. // warranty. In no event will the authors be held liable for any damages
  15. // arising from the use of this software.
  16. //
  17. // Permission is granted to anyone to use this software for any purpose,
  18. // including commercial applications, and to alter it and redistribute it
  19. // freely, subject to the following restrictions:
  20. //
  21. // 1. The origin of this software must not be misrepresented; you must not
  22. // claim that you wrote the original software. If you use this software
  23. // in a product, an acknowledgment in the product documentation would be
  24. // appreciated but is not required.
  25. // 2. Altered source versions must be plainly marked as such, and must not be
  26. // misrepresented as being the original software.
  27. // 3. This notice may not be removed or altered from any source distribution.
  28. //
  29. // SPDX-License-Identifier: Zlib
  30. //
  31. #pragma once
  32. #include "ysfx_api_eel.hpp"
  33. #include "WDL/wdlstring.h"
  34. #include "WDL/wdlcstring.h"
  35. #include "WDL/wdlutf8.h"
  36. #include <algorithm>
  37. #include <cmath>
  38. #include <cstdio>
  39. #include <cstring>
  40. // help clangd to figure things out
  41. #if defined(__CLANGD__)
  42. # include "ysfx_api_gfx.cpp"
  43. #endif
  44. #define EEL_LICE_GET_CONTEXT(opaque) ((opaque) ? ((ysfx_t *)(opaque))->gfx.state->lice.get() : nullptr)
  45. //------------------------------------------------------------------------------
  46. #define LICE_FUNCTION_VALID(x) (sizeof(int) > 0)
  47. static HDC LICE__GetDC(LICE_IBitmap *bm)
  48. {
  49. return bm->getDC();
  50. }
  51. static int LICE__GetWidth(LICE_IBitmap *bm)
  52. {
  53. return bm->getWidth();
  54. }
  55. static int LICE__GetHeight(LICE_IBitmap *bm)
  56. {
  57. return bm->getHeight();
  58. }
  59. static void LICE__Destroy(LICE_IBitmap *bm)
  60. {
  61. delete bm;
  62. }
  63. static void LICE__SetFromHFont(LICE_IFont * ifont, HFONT font, int flags)
  64. {
  65. if (ifont) ifont->SetFromHFont(font,flags);
  66. }
  67. static LICE_pixel LICE__SetTextColor(LICE_IFont* ifont, LICE_pixel color)
  68. {
  69. if (ifont) return ifont->SetTextColor(color);
  70. return 0;
  71. }
  72. static void LICE__SetTextCombineMode(LICE_IFont* ifont, int mode, float alpha)
  73. {
  74. if (ifont) ifont->SetCombineMode(mode, alpha);
  75. }
  76. static int LICE__DrawText(LICE_IFont* ifont, LICE_IBitmap *bm, const char *str, int strcnt, RECT *rect, UINT dtFlags)
  77. {
  78. if (ifont) return ifont->DrawText(bm, str, strcnt, rect, dtFlags);
  79. return 0;
  80. }
  81. static LICE_IFont *LICE_CreateFont()
  82. {
  83. return new LICE_CachedFont();
  84. }
  85. static void LICE__DestroyFont(LICE_IFont *bm)
  86. {
  87. delete bm;
  88. }
  89. static bool LICE__resize(LICE_IBitmap *bm, int w, int h)
  90. {
  91. return bm->resize(w,h);
  92. }
  93. static LICE_IBitmap *__LICE_CreateBitmap(int mode, int w, int h)
  94. {
  95. if (mode==1) return new LICE_SysBitmap(w,h);
  96. return new LICE_MemBitmap(w,h);
  97. }
  98. class eel_lice_state
  99. {
  100. public:
  101. eel_lice_state(NSEEL_VMCTX vm, void *ctx, int image_slots, int font_slots);
  102. ~eel_lice_state();
  103. LICE_IBitmap *m_framebuffer, *m_framebuffer_extra;
  104. int m_framebuffer_dirty;
  105. WDL_TypedBuf<LICE_IBitmap *> m_gfx_images;
  106. struct gfxFontStruct {
  107. LICE_IFont *font;
  108. char last_fontname[128];
  109. char actual_fontname[128];
  110. int last_fontsize;
  111. int last_fontflag;
  112. int use_fonth;
  113. };
  114. WDL_TypedBuf<gfxFontStruct> m_gfx_fonts;
  115. enum {
  116. EELFONT_FLAG_BOLD = (1<<24),
  117. EELFONT_FLAG_ITALIC = (2<<24),
  118. EELFONT_FLAG_UNDERLINE = (4<<24),
  119. EELFONT_FLAG_MASK = EELFONT_FLAG_BOLD|EELFONT_FLAG_ITALIC|EELFONT_FLAG_UNDERLINE
  120. };
  121. int m_gfx_font_active; // -1 for default, otherwise index into gfx_fonts (NOTE: this differs from the exposed API, which defines 0 as default, 1-n)
  122. LICE_IFont *GetActiveFont() { return m_gfx_font_active>=0&&m_gfx_font_active<m_gfx_fonts.GetSize() && m_gfx_fonts.Get()[m_gfx_font_active].use_fonth ? m_gfx_fonts.Get()[m_gfx_font_active].font : NULL; }
  123. LICE_IBitmap *GetImageForIndex(EEL_F idx, const char *callername)
  124. {
  125. if (idx>-2.0)
  126. {
  127. if (idx < 0.0) return m_framebuffer;
  128. const int a = (int)idx;
  129. if (a >= 0 && a < m_gfx_images.GetSize()) return m_gfx_images.Get()[a];
  130. }
  131. return NULL;
  132. };
  133. void SetImageDirty(LICE_IBitmap *bm)
  134. {
  135. if (bm == m_framebuffer && !m_framebuffer_dirty)
  136. {
  137. if (m_gfx_clear && *m_gfx_clear > -1.0)
  138. {
  139. const int a=(int)*m_gfx_clear;
  140. if (LICE_FUNCTION_VALID(LICE_Clear)) LICE_Clear(m_framebuffer,LICE_RGBA((a&0xff),((a>>8)&0xff),((a>>16)&0xff),0));
  141. }
  142. m_framebuffer_dirty=1;
  143. }
  144. }
  145. // R, G, B, A, w, h, x, y, mode(1=add,0=copy)
  146. EEL_F *m_gfx_r, *m_gfx_g, *m_gfx_b, *m_gfx_w, *m_gfx_h, *m_gfx_a, *m_gfx_x, *m_gfx_y, *m_gfx_mode, *m_gfx_clear, *m_gfx_texth,*m_gfx_dest, *m_gfx_a2;
  147. EEL_F *m_mouse_x, *m_mouse_y, *m_mouse_cap, *m_mouse_wheel, *m_mouse_hwheel;
  148. EEL_F *m_gfx_ext_retina;
  149. NSEEL_VMCTX m_vmref;
  150. void *m_user_ctx;
  151. void gfx_lineto(EEL_F xpos, EEL_F ypos, EEL_F aaflag);
  152. void gfx_rectto(EEL_F xpos, EEL_F ypos);
  153. void gfx_line(int np, EEL_F **parms);
  154. void gfx_rect(int np, EEL_F **parms);
  155. void gfx_roundrect(int np, EEL_F **parms);
  156. void gfx_arc(int np, EEL_F **parms);
  157. void gfx_set(int np, EEL_F **parms);
  158. void gfx_grad_or_muladd_rect(int mode, int np, EEL_F **parms);
  159. void gfx_setpixel(EEL_F r, EEL_F g, EEL_F b);
  160. void gfx_getpixel(EEL_F *r, EEL_F *g, EEL_F *b);
  161. void gfx_drawnumber(EEL_F n, EEL_F ndigits);
  162. void gfx_drawchar(EEL_F ch);
  163. void gfx_getimgdim(EEL_F img, EEL_F *w, EEL_F *h);
  164. EEL_F gfx_setimgdim(int img, EEL_F *w, EEL_F *h);
  165. void gfx_blurto(EEL_F x, EEL_F y);
  166. void gfx_blitext(EEL_F img, EEL_F *coords, EEL_F angle);
  167. void gfx_blitext2(int np, EEL_F **parms, int mode); // 0=blit, 1=deltablit
  168. void gfx_transformblit(EEL_F **parms, int div_w, int div_h, EEL_F *tab); // parms[0]=src, 1-4=x,y,w,h
  169. void gfx_circle(float x, float y, float r, bool fill, bool aaflag);
  170. void gfx_triangle(EEL_F** parms, int nparms);
  171. void gfx_drawstr(void *opaque, EEL_F **parms, int nparms, int formatmode); // formatmode=1 for format, 2 for purely measure no format, 3 for measure char
  172. EEL_F gfx_loadimg(void *opaque, int img, EEL_F loadFrom);
  173. EEL_F gfx_setfont(void *opaque, int np, EEL_F **parms);
  174. EEL_F gfx_getfont(void *opaque, int np, EEL_F **parms);
  175. LICE_pixel getCurColor();
  176. int getCurMode();
  177. int getCurModeForBlit(bool isFBsrc);
  178. // these have to be **parms because of the hack for getting string from parm index
  179. EEL_F gfx_setcursor(void* opaque, EEL_F** parms, int nparms);
  180. };
  181. eel_lice_state::eel_lice_state(NSEEL_VMCTX vm, void *ctx, int image_slots, int font_slots)
  182. {
  183. m_user_ctx=ctx;
  184. m_vmref= vm;
  185. m_gfx_font_active=-1;
  186. m_gfx_fonts.Resize(font_slots);
  187. memset(m_gfx_fonts.Get(),0,m_gfx_fonts.GetSize()*sizeof(m_gfx_fonts.Get()[0]));
  188. m_gfx_images.Resize(image_slots);
  189. memset(m_gfx_images.Get(),0,m_gfx_images.GetSize()*sizeof(m_gfx_images.Get()[0]));
  190. m_framebuffer=m_framebuffer_extra=0;
  191. m_framebuffer_dirty=0;
  192. m_gfx_r = NSEEL_VM_regvar(vm,"gfx_r");
  193. m_gfx_g = NSEEL_VM_regvar(vm,"gfx_g");
  194. m_gfx_b = NSEEL_VM_regvar(vm,"gfx_b");
  195. m_gfx_a = NSEEL_VM_regvar(vm,"gfx_a");
  196. m_gfx_a2 = NSEEL_VM_regvar(vm,"gfx_a2");
  197. m_gfx_w = NSEEL_VM_regvar(vm,"gfx_w");
  198. m_gfx_h = NSEEL_VM_regvar(vm,"gfx_h");
  199. m_gfx_x = NSEEL_VM_regvar(vm,"gfx_x");
  200. m_gfx_y = NSEEL_VM_regvar(vm,"gfx_y");
  201. m_gfx_mode = NSEEL_VM_regvar(vm,"gfx_mode");
  202. m_gfx_clear = NSEEL_VM_regvar(vm,"gfx_clear");
  203. m_gfx_texth = NSEEL_VM_regvar(vm,"gfx_texth");
  204. m_gfx_dest = NSEEL_VM_regvar(vm,"gfx_dest");
  205. m_gfx_ext_retina = NSEEL_VM_regvar(vm,"gfx_ext_retina");
  206. m_mouse_x = NSEEL_VM_regvar(vm,"mouse_x");
  207. m_mouse_y = NSEEL_VM_regvar(vm,"mouse_y");
  208. m_mouse_cap = NSEEL_VM_regvar(vm,"mouse_cap");
  209. m_mouse_wheel=NSEEL_VM_regvar(vm,"mouse_wheel");
  210. m_mouse_hwheel=NSEEL_VM_regvar(vm,"mouse_hwheel");
  211. if (m_gfx_texth) *m_gfx_texth=8;
  212. }
  213. eel_lice_state::~eel_lice_state()
  214. {
  215. if (LICE_FUNCTION_VALID(LICE__Destroy))
  216. {
  217. LICE__Destroy(m_framebuffer_extra);
  218. LICE__Destroy(m_framebuffer);
  219. int x;
  220. for (x=0;x<m_gfx_images.GetSize();x++)
  221. {
  222. LICE__Destroy(m_gfx_images.Get()[x]);
  223. }
  224. }
  225. if (LICE_FUNCTION_VALID(LICE__DestroyFont))
  226. {
  227. int x;
  228. for (x=0;x<m_gfx_fonts.GetSize();x++)
  229. {
  230. if (m_gfx_fonts.Get()[x].font) LICE__DestroyFont(m_gfx_fonts.Get()[x].font);
  231. }
  232. }
  233. }
  234. int eel_lice_state::getCurMode()
  235. {
  236. const int gmode = (int) (*m_gfx_mode);
  237. const int sm=(gmode>>4)&0xf;
  238. if (sm > LICE_BLIT_MODE_COPY && sm <= LICE_BLIT_MODE_HSVADJ) return sm;
  239. return (gmode&1) ? LICE_BLIT_MODE_ADD : LICE_BLIT_MODE_COPY;
  240. }
  241. int eel_lice_state::getCurModeForBlit(bool isFBsrc)
  242. {
  243. const int gmode = (int) (*m_gfx_mode);
  244. const int sm=(gmode>>4)&0xf;
  245. int mode;
  246. if (sm > LICE_BLIT_MODE_COPY && sm <= LICE_BLIT_MODE_HSVADJ) mode=sm;
  247. else mode=((gmode&1) ? LICE_BLIT_MODE_ADD : LICE_BLIT_MODE_COPY);
  248. if (!isFBsrc && !(gmode&2)) mode|=LICE_BLIT_USE_ALPHA;
  249. if (!(gmode&4)) mode|=LICE_BLIT_FILTER_BILINEAR;
  250. return mode;
  251. }
  252. LICE_pixel eel_lice_state::getCurColor()
  253. {
  254. int red=(int) (*m_gfx_r*255.0);
  255. int green=(int) (*m_gfx_g*255.0);
  256. int blue=(int) (*m_gfx_b*255.0);
  257. int a2=(int) (*m_gfx_a2*255.0);
  258. if (red<0) red=0;else if (red>255)red=255;
  259. if (green<0) green=0;else if (green>255)green=255;
  260. if (blue<0) blue=0; else if (blue>255) blue=255;
  261. if (a2<0) a2=0; else if (a2>255) a2=255;
  262. return LICE_RGBA(red,green,blue,a2);
  263. }
  264. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_lineto(void *opaque, EEL_F *xpos, EEL_F *ypos, EEL_F *useaa)
  265. {
  266. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  267. if (ctx) ctx->gfx_lineto(*xpos, *ypos, *useaa);
  268. return xpos;
  269. }
  270. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_lineto2(void *opaque, EEL_F *xpos, EEL_F *ypos)
  271. {
  272. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  273. if (ctx) ctx->gfx_lineto(*xpos, *ypos, 1.0f);
  274. return xpos;
  275. }
  276. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_rectto(void *opaque, EEL_F *xpos, EEL_F *ypos)
  277. {
  278. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  279. if (ctx) ctx->gfx_rectto(*xpos, *ypos);
  280. return xpos;
  281. }
  282. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_line(void *opaque, INT_PTR np, EEL_F **parms)
  283. {
  284. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  285. if (ctx) ctx->gfx_line((int)np,parms);
  286. return 0.0;
  287. }
  288. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_rect(void *opaque, INT_PTR np, EEL_F **parms)
  289. {
  290. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  291. if (ctx) ctx->gfx_rect((int)np,parms);
  292. return 0.0;
  293. }
  294. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_roundrect(void *opaque, INT_PTR np, EEL_F **parms)
  295. {
  296. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  297. if (ctx) ctx->gfx_roundrect((int)np,parms);
  298. return 0.0;
  299. }
  300. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_arc(void *opaque, INT_PTR np, EEL_F **parms)
  301. {
  302. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  303. if (ctx) ctx->gfx_arc((int)np,parms);
  304. return 0.0;
  305. }
  306. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_set(void *opaque, INT_PTR np, EEL_F **parms)
  307. {
  308. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  309. if (ctx) ctx->gfx_set((int)np,parms);
  310. return 0.0;
  311. }
  312. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_gradrect(void *opaque, INT_PTR np, EEL_F **parms)
  313. {
  314. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  315. if (ctx) ctx->gfx_grad_or_muladd_rect(0,(int)np,parms);
  316. return 0.0;
  317. }
  318. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_muladdrect(void *opaque, INT_PTR np, EEL_F **parms)
  319. {
  320. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  321. if (ctx) ctx->gfx_grad_or_muladd_rect(1,(int)np,parms);
  322. return 0.0;
  323. }
  324. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_deltablit(void *opaque, INT_PTR np, EEL_F **parms)
  325. {
  326. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  327. if (ctx) ctx->gfx_blitext2((int)np,parms,1);
  328. return 0.0;
  329. }
  330. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_transformblit(void *opaque, INT_PTR np, EEL_F **parms)
  331. {
  332. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  333. if (ctx)
  334. {
  335. #ifndef EEL_LICE_NO_RAM
  336. const int divw = (int) (parms[5][0]+0.5);
  337. const int divh = (int) (parms[6][0]+0.5);
  338. if (divw < 1 || divh < 1) return 0.0;
  339. const int sz = divw*divh*2;
  340. #ifdef EEL_LICE_RAMFUNC
  341. EEL_F *d = EEL_LICE_RAMFUNC(opaque,7,sz);
  342. if (!d) return 0.0;
  343. #else
  344. EEL_F **blocks = ctx->m_vmref ? ((compileContext*)ctx->m_vmref)->ram_state->blocks : 0;
  345. if (!blocks || np < 8) return 0.0;
  346. const int addr1= (int) (parms[7][0]+0.5);
  347. EEL_F *d=__NSEEL_RAMAlloc(blocks,addr1);
  348. if (sz>NSEEL_RAM_ITEMSPERBLOCK)
  349. {
  350. int x;
  351. for(x=NSEEL_RAM_ITEMSPERBLOCK;x<sz-1;x+=NSEEL_RAM_ITEMSPERBLOCK)
  352. if (__NSEEL_RAMAlloc(blocks,addr1+x) != d+x) return 0.0;
  353. }
  354. EEL_F *end=__NSEEL_RAMAlloc(blocks,addr1+sz-1);
  355. if (end != d+sz-1) return 0.0; // buffer not contiguous
  356. #endif
  357. ctx->gfx_transformblit(parms,divw,divh,d);
  358. #endif
  359. }
  360. return 0.0;
  361. }
  362. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_circle(void *opaque, INT_PTR np, EEL_F **parms)
  363. {
  364. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  365. bool aa = true, fill = false;
  366. if (np>3) fill = parms[3][0] > 0.5;
  367. if (np>4) aa = parms[4][0] > 0.5;
  368. if (ctx) ctx->gfx_circle((float)parms[0][0], (float)parms[1][0], (float)parms[2][0], fill, aa);
  369. return 0.0;
  370. }
  371. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_triangle(void* opaque, INT_PTR np, EEL_F **parms)
  372. {
  373. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  374. if (ctx) ctx->gfx_triangle(parms, (int)np);
  375. return 0.0;
  376. }
  377. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_drawnumber(void *opaque, EEL_F *n, EEL_F *nd)
  378. {
  379. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  380. if (ctx) ctx->gfx_drawnumber(*n, *nd);
  381. return n;
  382. }
  383. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_drawchar(void *opaque, EEL_F *n)
  384. {
  385. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  386. if (ctx) ctx->gfx_drawchar(*n);
  387. return n;
  388. }
  389. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_measurestr(void *opaque, EEL_F *str, EEL_F *xOut, EEL_F *yOut)
  390. {
  391. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  392. if (ctx)
  393. {
  394. EEL_F *p[3]={str,xOut,yOut};
  395. ctx->gfx_drawstr(opaque,p,3,2);
  396. }
  397. return str;
  398. }
  399. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_measurechar(void *opaque, EEL_F *str, EEL_F *xOut, EEL_F *yOut)
  400. {
  401. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  402. if (ctx)
  403. {
  404. EEL_F *p[3]={str,xOut,yOut};
  405. ctx->gfx_drawstr(opaque,p,3,3);
  406. }
  407. return str;
  408. }
  409. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_drawstr(void *opaque, INT_PTR nparms, EEL_F **parms)
  410. {
  411. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  412. if (ctx) ctx->gfx_drawstr(opaque,parms,(int)nparms,0);
  413. return parms[0][0];
  414. }
  415. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_printf(void *opaque, INT_PTR nparms, EEL_F **parms)
  416. {
  417. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  418. if (ctx && nparms>0)
  419. {
  420. EEL_F v= **parms;
  421. ctx->gfx_drawstr(opaque,parms,(int)nparms,1);
  422. return v;
  423. }
  424. return 0.0;
  425. }
  426. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_setpixel(void *opaque, EEL_F *r, EEL_F *g, EEL_F *b)
  427. {
  428. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  429. if (ctx) ctx->gfx_setpixel(*r, *g, *b);
  430. return r;
  431. }
  432. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_getpixel(void *opaque, EEL_F *r, EEL_F *g, EEL_F *b)
  433. {
  434. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  435. if (ctx) ctx->gfx_getpixel(r, g, b);
  436. return r;
  437. }
  438. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_setfont(void *opaque, INT_PTR np, EEL_F **parms)
  439. {
  440. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  441. if (ctx) return ctx->gfx_setfont(opaque,(int)np,parms);
  442. return 0.0;
  443. }
  444. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_getfont(void *opaque, INT_PTR np, EEL_F **parms)
  445. {
  446. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  447. if (ctx)
  448. {
  449. const int idx=ctx->m_gfx_font_active;
  450. if (idx>=0 && idx < ctx->m_gfx_fonts.GetSize())
  451. {
  452. eel_lice_state::gfxFontStruct* f=ctx->m_gfx_fonts.Get()+idx;
  453. EEL_STRING_MUTEXLOCK_SCOPE
  454. #ifdef NOT_EEL_STRING_UPDATE_STRING
  455. NOT_EEL_STRING_UPDATE_STRING(parms[0][0],f->actual_fontname);
  456. #else
  457. WDL_FastString *fs=NULL;
  458. EEL_STRING_GET_FOR_WRITE(parms[0][0],&fs);
  459. if (fs) fs->Set(f->actual_fontname);
  460. #endif
  461. }
  462. return idx;
  463. }
  464. return 0.0;
  465. }
  466. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_blit2(void *opaque, INT_PTR np, EEL_F **parms)
  467. {
  468. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  469. if (ctx && np>=3)
  470. {
  471. ctx->gfx_blitext2((int)np,parms,0);
  472. return *(parms[0]);
  473. }
  474. return 0.0;
  475. }
  476. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_blitext(void *opaque, EEL_F *img, EEL_F *coordidx, EEL_F *rotate)
  477. {
  478. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  479. if (ctx)
  480. {
  481. #ifndef EEL_LICE_NO_RAM
  482. #ifdef EEL_LICE_RAMFUNC
  483. EEL_F *buf = EEL_LICE_RAMFUNC(opaque,1,10);
  484. if (!buf) return img;
  485. #else
  486. EEL_F fc = *coordidx;
  487. if (fc < -0.5 || fc >= NSEEL_RAM_BLOCKS*NSEEL_RAM_ITEMSPERBLOCK) return img;
  488. int a=(int)fc;
  489. if (a<0) return img;
  490. EEL_F buf[10];
  491. int x;
  492. EEL_F **blocks = ctx->m_vmref ? ((compileContext*)ctx->m_vmref)->ram_state->blocks : 0;
  493. if (!blocks) return img;
  494. for (x = 0;x < 10; x ++)
  495. {
  496. EEL_F *d=__NSEEL_RAMAlloc(blocks,a++);
  497. if (!d || d==&nseel_ramalloc_onfail) return img;
  498. buf[x]=*d;
  499. }
  500. #endif
  501. // read megabuf
  502. ctx->gfx_blitext(*img,buf,*rotate);
  503. #endif
  504. }
  505. return img;
  506. }
  507. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_blurto(void *opaque, EEL_F *x, EEL_F *y)
  508. {
  509. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  510. if (ctx) ctx->gfx_blurto(*x,*y);
  511. return x;
  512. }
  513. static EEL_F * NSEEL_CGEN_CALL ysfx_api_gfx_getimgdim(void *opaque, EEL_F *img, EEL_F *w, EEL_F *h)
  514. {
  515. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  516. if (ctx) ctx->gfx_getimgdim(*img,w,h);
  517. return img;
  518. }
  519. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_loadimg(void *opaque, EEL_F *img, EEL_F *fr)
  520. {
  521. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  522. if (ctx) return ctx->gfx_loadimg(opaque,(int)*img,*fr);
  523. return 0.0;
  524. }
  525. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_setimgdim(void *opaque, EEL_F *img, EEL_F *w, EEL_F *h)
  526. {
  527. eel_lice_state *ctx=EEL_LICE_GET_CONTEXT(opaque);
  528. if (ctx) return ctx->gfx_setimgdim((int)*img,w,h);
  529. return 0.0;
  530. }
  531. static EEL_F NSEEL_CGEN_CALL ysfx_api_gfx_getsyscol(void* ctxe, INT_PTR np, EEL_F **parms)
  532. {
  533. return (EEL_F)LICE_RGBA_FROMNATIVE(GetSysColor(COLOR_3DFACE));
  534. }
  535. void eel_lice_state::gfx_lineto(EEL_F xpos, EEL_F ypos, EEL_F aaflag)
  536. {
  537. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_lineto");
  538. if (!dest) return;
  539. int x1=(int)floor(xpos),y1=(int)floor(ypos),x2=(int)floor(*m_gfx_x), y2=(int)floor(*m_gfx_y);
  540. if (LICE_FUNCTION_VALID(LICE__GetWidth) && LICE_FUNCTION_VALID(LICE__GetHeight) && LICE_FUNCTION_VALID(LICE_Line) &&
  541. LICE_FUNCTION_VALID(LICE_ClipLine) &&
  542. LICE_ClipLine(&x1,&y1,&x2,&y2,0,0,LICE__GetWidth(dest),LICE__GetHeight(dest)))
  543. {
  544. SetImageDirty(dest);
  545. LICE_Line(dest,x1,y1,x2,y2,getCurColor(),(float) *m_gfx_a,getCurMode(),aaflag > 0.5);
  546. }
  547. *m_gfx_x = xpos;
  548. *m_gfx_y = ypos;
  549. }
  550. void eel_lice_state::gfx_circle(float x, float y, float r, bool fill, bool aaflag)
  551. {
  552. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_circle");
  553. if (!dest) return;
  554. if (LICE_FUNCTION_VALID(LICE_Circle) && LICE_FUNCTION_VALID(LICE_FillCircle))
  555. {
  556. SetImageDirty(dest);
  557. if(fill)
  558. LICE_FillCircle(dest, x, y, r, getCurColor(), (float) *m_gfx_a, getCurMode(), aaflag);
  559. else
  560. LICE_Circle(dest, x, y, r, getCurColor(), (float) *m_gfx_a, getCurMode(), aaflag);
  561. }
  562. }
  563. void eel_lice_state::gfx_triangle(EEL_F** parms, int np)
  564. {
  565. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest, "gfx_triangle");
  566. if (np >= 6)
  567. {
  568. np &= ~1;
  569. SetImageDirty(dest);
  570. if (np == 6)
  571. {
  572. if (!LICE_FUNCTION_VALID(LICE_FillTriangle)) return;
  573. LICE_FillTriangle(dest, (int)parms[0][0], (int)parms[1][0], (int)parms[2][0], (int)parms[3][0],
  574. (int)parms[4][0], (int)parms[5][0], getCurColor(), (float)*m_gfx_a, getCurMode());
  575. }
  576. else
  577. {
  578. if (!LICE_FUNCTION_VALID(LICE_FillConvexPolygon)) return;
  579. const int maxpt = 512;
  580. const int n = wdl_min(np/2, maxpt);
  581. int i, rdi=0;
  582. int x[maxpt], y[maxpt];
  583. for (i=0; i < n; i++)
  584. {
  585. x[i]=(int)parms[rdi++][0];
  586. y[i]=(int)parms[rdi++][0];
  587. }
  588. LICE_FillConvexPolygon(dest, x, y, n, getCurColor(), (float)*m_gfx_a, getCurMode());
  589. }
  590. }
  591. }
  592. void eel_lice_state::gfx_rectto(EEL_F xpos, EEL_F ypos)
  593. {
  594. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_rectto");
  595. if (!dest) return;
  596. EEL_F x1=xpos,y1=ypos,x2=*m_gfx_x, y2=*m_gfx_y;
  597. if (x2<x1) { x1=x2; x2=xpos; }
  598. if (y2<y1) { y1=y2; y2=ypos; }
  599. if (LICE_FUNCTION_VALID(LICE_FillRect) && x2-x1 > 0.5 && y2-y1 > 0.5)
  600. {
  601. SetImageDirty(dest);
  602. LICE_FillRect(dest,(int)x1,(int)y1,(int)(x2-x1),(int)(y2-y1),getCurColor(),(float)*m_gfx_a,getCurMode());
  603. }
  604. *m_gfx_x = xpos;
  605. *m_gfx_y = ypos;
  606. }
  607. void eel_lice_state::gfx_line(int np, EEL_F **parms)
  608. {
  609. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_line");
  610. if (!dest) return;
  611. int x1=(int)floor(parms[0][0]),y1=(int)floor(parms[1][0]),x2=(int)floor(parms[2][0]), y2=(int)floor(parms[3][0]);
  612. if (LICE_FUNCTION_VALID(LICE__GetWidth) &&
  613. LICE_FUNCTION_VALID(LICE__GetHeight) &&
  614. LICE_FUNCTION_VALID(LICE_Line) &&
  615. LICE_FUNCTION_VALID(LICE_ClipLine) && LICE_ClipLine(&x1,&y1,&x2,&y2,0,0,LICE__GetWidth(dest),LICE__GetHeight(dest)))
  616. {
  617. SetImageDirty(dest);
  618. LICE_Line(dest,x1,y1,x2,y2,getCurColor(),(float)*m_gfx_a,getCurMode(),np< 5 || parms[4][0] > 0.5);
  619. }
  620. }
  621. void eel_lice_state::gfx_rect(int np, EEL_F **parms)
  622. {
  623. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_rect");
  624. if (!dest) return;
  625. int x1=(int)floor(parms[0][0]),y1=(int)floor(parms[1][0]),w=(int)floor(parms[2][0]),h=(int)floor(parms[3][0]);
  626. int filled=(np < 5 || parms[4][0] > 0.5);
  627. if (LICE_FUNCTION_VALID(LICE_FillRect) && LICE_FUNCTION_VALID(LICE_DrawRect) && w>0 && h>0)
  628. {
  629. SetImageDirty(dest);
  630. if (filled) LICE_FillRect(dest,x1,y1,w,h,getCurColor(),(float)*m_gfx_a,getCurMode());
  631. else LICE_DrawRect(dest, x1, y1, w-1, h-1, getCurColor(), (float)*m_gfx_a, getCurMode());
  632. }
  633. }
  634. void eel_lice_state::gfx_roundrect(int np, EEL_F **parms)
  635. {
  636. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_roundrect");
  637. if (!dest) return;
  638. const bool aa = np <= 5 || parms[5][0]>0.5;
  639. if (LICE_FUNCTION_VALID(LICE_RoundRect) && parms[2][0]>0 && parms[3][0]>0)
  640. {
  641. SetImageDirty(dest);
  642. LICE_RoundRect(dest, (float)parms[0][0], (float)parms[1][0], (float)parms[2][0], (float)parms[3][0], (int)parms[4][0], getCurColor(), (float)*m_gfx_a, getCurMode(), aa);
  643. }
  644. }
  645. void eel_lice_state::gfx_arc(int np, EEL_F **parms)
  646. {
  647. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_arc");
  648. if (!dest) return;
  649. const bool aa = np <= 5 || parms[5][0]>0.5;
  650. if (LICE_FUNCTION_VALID(LICE_Arc))
  651. {
  652. SetImageDirty(dest);
  653. LICE_Arc(dest, (float)parms[0][0], (float)parms[1][0], (float)parms[2][0], (float)parms[3][0], (float)parms[4][0], getCurColor(), (float)*m_gfx_a, getCurMode(), aa);
  654. }
  655. }
  656. void eel_lice_state::gfx_grad_or_muladd_rect(int whichmode, int np, EEL_F **parms)
  657. {
  658. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,whichmode==0?"gfx_gradrect":"gfx_muladdrect");
  659. if (!dest) return;
  660. const int x1=(int)floor(parms[0][0]),y1=(int)floor(parms[1][0]),w=(int)floor(parms[2][0]), h=(int)floor(parms[3][0]);
  661. if (w>0 && h>0)
  662. {
  663. SetImageDirty(dest);
  664. if (whichmode==0 && LICE_FUNCTION_VALID(LICE_GradRect) && np > 7)
  665. {
  666. LICE_GradRect(dest,x1,y1,w,h,(float)parms[4][0],(float)parms[5][0],(float)parms[6][0],(float)parms[7][0],
  667. np > 8 ? (float)parms[8][0]:0.0f, np > 9 ? (float)parms[9][0]:0.0f, np > 10 ? (float)parms[10][0]:0.0f, np > 11 ? (float)parms[11][0]:0.0f,
  668. np > 12 ? (float)parms[12][0]:0.0f, np > 13 ? (float)parms[13][0]:0.0f, np > 14 ? (float)parms[14][0]:0.0f, np > 15 ? (float)parms[15][0]:0.0f,
  669. getCurMode());
  670. }
  671. else if (whichmode==1 && LICE_FUNCTION_VALID(LICE_MultiplyAddRect) && np > 6)
  672. {
  673. const double sc = 255.0;
  674. LICE_MultiplyAddRect(dest,x1,y1,w,h,(float)parms[4][0],(float)parms[5][0],(float)parms[6][0],np>7 ? (float)parms[7][0]:1.0f,
  675. (float)(np > 8 ? sc*parms[8][0]:0.0), (float)(np > 9 ? sc*parms[9][0]:0.0), (float)(np > 10 ? sc*parms[10][0]:0.0), (float)(np > 11 ? sc*parms[11][0]:0.0));
  676. }
  677. }
  678. }
  679. void eel_lice_state::gfx_setpixel(EEL_F r, EEL_F g, EEL_F b)
  680. {
  681. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_setpixel");
  682. if (!dest) return;
  683. int red=(int) (r*255.0);
  684. int green=(int) (g*255.0);
  685. int blue=(int) (b*255.0);
  686. if (red<0) red=0;else if (red>255)red=255;
  687. if (green<0) green=0;else if (green>255)green=255;
  688. if (blue<0) blue=0; else if (blue>255) blue=255;
  689. if (LICE_FUNCTION_VALID(LICE_PutPixel))
  690. {
  691. SetImageDirty(dest);
  692. LICE_PutPixel(dest,(int)*m_gfx_x, (int)*m_gfx_y,LICE_RGBA(red,green,blue,255), (float)*m_gfx_a,getCurMode());
  693. }
  694. }
  695. void eel_lice_state::gfx_getimgdim(EEL_F img, EEL_F *w, EEL_F *h)
  696. {
  697. *w=*h=0;
  698. #ifdef DYNAMIC_LICE
  699. if (!LICE__GetWidth || !LICE__GetHeight) return;
  700. #endif
  701. LICE_IBitmap *bm=GetImageForIndex(img,"gfx_getimgdim");
  702. if (bm)
  703. {
  704. *w=LICE__GetWidth(bm);
  705. *h=LICE__GetHeight(bm);
  706. }
  707. }
  708. EEL_F eel_lice_state::gfx_loadimg(void *opaque, int img, EEL_F loadFrom)
  709. {
  710. #ifdef DYNAMIC_LICE
  711. if (!__LICE_LoadImage || !LICE__Destroy) return 0.0;
  712. #endif
  713. if (img >= 0 && img < m_gfx_images.GetSize())
  714. {
  715. WDL_FastString fs;
  716. bool ok = EEL_LICE_GET_FILENAME_FOR_STRING(loadFrom,&fs,0);
  717. if (ok && fs.GetLength())
  718. {
  719. LICE_IBitmap *bm = LICE_LoadImage(fs.Get(),NULL,false);
  720. if (bm)
  721. {
  722. LICE__Destroy(m_gfx_images.Get()[img]);
  723. m_gfx_images.Get()[img]=bm;
  724. return img;
  725. }
  726. }
  727. }
  728. return -1.0;
  729. }
  730. EEL_F eel_lice_state::gfx_setimgdim(int img, EEL_F *w, EEL_F *h)
  731. {
  732. int rv=0;
  733. #ifdef DYNAMIC_LICE
  734. if (!LICE__resize ||!LICE__GetWidth || !LICE__GetHeight||!__LICE_CreateBitmap) return 0.0;
  735. #endif
  736. int use_w = (int)*w;
  737. int use_h = (int)*h;
  738. if (use_w<1 || use_h < 1) use_w=use_h=0;
  739. if (use_w > 8192) use_w=8192;
  740. if (use_h > 8192) use_h=8192;
  741. LICE_IBitmap *bm=NULL;
  742. if (img >= 0 && img < m_gfx_images.GetSize())
  743. {
  744. bm=m_gfx_images.Get()[img];
  745. if (!bm)
  746. {
  747. m_gfx_images.Get()[img] = bm = __LICE_CreateBitmap(1,use_w,use_h);
  748. rv=!!bm;
  749. }
  750. else
  751. {
  752. rv=LICE__resize(bm,use_w,use_h);
  753. }
  754. }
  755. return rv?1.0:0.0;
  756. }
  757. void eel_lice_state::gfx_blurto(EEL_F x, EEL_F y)
  758. {
  759. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_blurto");
  760. if (!dest
  761. #ifdef DYNAMIC_LICE
  762. ||!LICE_Blur
  763. #endif
  764. ) return;
  765. SetImageDirty(dest);
  766. int srcx = (int)x;
  767. int srcy = (int)y;
  768. int srcw=(int) (*m_gfx_x-x);
  769. int srch=(int) (*m_gfx_y-y);
  770. if (srch < 0) { srch=-srch; srcy = (int)*m_gfx_y; }
  771. if (srcw < 0) { srcw=-srcw; srcx = (int)*m_gfx_x; }
  772. LICE_Blur(dest,dest,srcx,srcy,srcx,srcy,srcw,srch);
  773. *m_gfx_x = x;
  774. *m_gfx_y = y;
  775. }
  776. static bool CoordsSrcDestOverlap(EEL_F *coords)
  777. {
  778. if (coords[0]+coords[2] < coords[4]) return false;
  779. if (coords[0] > coords[4] + coords[6]) return false;
  780. if (coords[1]+coords[3] < coords[5]) return false;
  781. if (coords[1] > coords[5] + coords[7]) return false;
  782. return true;
  783. }
  784. void eel_lice_state::gfx_transformblit(EEL_F **parms, int div_w, int div_h, EEL_F *tab)
  785. {
  786. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_transformblit");
  787. if (!dest
  788. #ifdef DYNAMIC_LICE
  789. ||!LICE_ScaledBlit || !LICE_TransformBlit2 ||!LICE__GetWidth||!LICE__GetHeight
  790. #endif
  791. ) return;
  792. LICE_IBitmap *bm=GetImageForIndex(parms[0][0],"gfx_transformblit:src");
  793. if (!bm) return;
  794. const int bmw=LICE__GetWidth(bm);
  795. const int bmh=LICE__GetHeight(bm);
  796. const bool isFromFB = bm==m_framebuffer;
  797. SetImageDirty(dest);
  798. if (bm == dest)
  799. {
  800. if (!m_framebuffer_extra && LICE_FUNCTION_VALID(__LICE_CreateBitmap)) m_framebuffer_extra=__LICE_CreateBitmap(0,bmw,bmh);
  801. if (m_framebuffer_extra)
  802. {
  803. LICE__resize(bm=m_framebuffer_extra,bmw,bmh);
  804. LICE_ScaledBlit(bm,dest, // copy the entire image
  805. 0,0,bmw,bmh,
  806. 0.0f,0.0f,(float)bmw,(float)bmh,
  807. 1.0f,LICE_BLIT_MODE_COPY);
  808. }
  809. }
  810. LICE_TransformBlit2(dest,bm,(int)floor(parms[1][0]),(int)floor(parms[2][0]),(int)floor(parms[3][0]),(int)floor(parms[4][0]),tab,div_w,div_h, (float)*m_gfx_a,getCurModeForBlit(isFromFB));
  811. }
  812. EEL_F eel_lice_state::gfx_setfont(void *opaque, int np, EEL_F **parms)
  813. {
  814. int a = np>0 ? ((int)floor(parms[0][0]))-1 : -1;
  815. if (a>=0 && a < m_gfx_fonts.GetSize())
  816. {
  817. gfxFontStruct *s = m_gfx_fonts.Get()+a;
  818. if (np>1 && LICE_FUNCTION_VALID(LICE_CreateFont) && LICE_FUNCTION_VALID(LICE__SetFromHFont))
  819. {
  820. const int sz=np>2 ? (int)parms[2][0] : 10;
  821. bool doCreate=false;
  822. int fontflag=0;
  823. if (!s->font) s->actual_fontname[0]=0;
  824. {
  825. EEL_STRING_MUTEXLOCK_SCOPE
  826. const char *face=EEL_STRING_GET_FOR_INDEX(parms[1][0],NULL);
  827. #ifdef EEL_STRING_DEBUGOUT
  828. if (!face) EEL_STRING_DEBUGOUT("gfx_setfont: invalid string identifier %f",parms[1][0]);
  829. #endif
  830. if (!face || !*face) face="Arial";
  831. {
  832. unsigned int c = np > 3 ? (unsigned int) parms[3][0] : 0;
  833. while (c)
  834. {
  835. switch (toupper(c&0xff))
  836. {
  837. case 'B': fontflag|=EELFONT_FLAG_BOLD; break;
  838. case 'I': fontflag|=EELFONT_FLAG_ITALIC; break;
  839. case 'U': fontflag|=EELFONT_FLAG_UNDERLINE; break;
  840. case 'R': fontflag|=16; break; //LICE_FONT_FLAG_FX_BLUR
  841. case 'V': fontflag|=32; break; //LICE_FONT_FLAG_FX_INVERT
  842. case 'M': fontflag|=64; break; //LICE_FONT_FLAG_FX_MONO
  843. case 'S': fontflag|=128; break; //LICE_FONT_FLAG_FX_SHADOW
  844. case 'O': fontflag|=256; break; //LICE_FONT_FLAG_FX_OUTLINE
  845. case 'Z': fontflag|=1; break; //LICE_FONT_FLAG_VERTICAL
  846. case 'Y': fontflag|=1|2; break; //LICE_FONT_FLAG_VERTICAL|LICE_FONT_FLAG_VERTICAL_BOTTOMUP
  847. }
  848. c>>=8;
  849. }
  850. }
  851. if (fontflag != s->last_fontflag || sz!=s->last_fontsize || strncmp(s->last_fontname,face,sizeof(s->last_fontname)-1))
  852. {
  853. lstrcpyn_safe(s->last_fontname,face,sizeof(s->last_fontname));
  854. s->last_fontsize=sz;
  855. s->last_fontflag=fontflag;
  856. doCreate=1;
  857. }
  858. }
  859. if (doCreate)
  860. {
  861. s->actual_fontname[0]=0;
  862. if (!s->font) s->font=LICE_CreateFont();
  863. if (s->font)
  864. {
  865. const int fw = (fontflag&EELFONT_FLAG_BOLD) ? FW_BOLD : FW_NORMAL;
  866. const bool italic = !!(fontflag&EELFONT_FLAG_ITALIC);
  867. const bool underline = !!(fontflag&EELFONT_FLAG_UNDERLINE);
  868. HFONT hf=NULL;
  869. #if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
  870. WCHAR wf[256];
  871. if (WDL_DetectUTF8(s->last_fontname)>0 &&
  872. GetVersion()<0x80000000 &&
  873. MultiByteToWideChar(CP_UTF8,MB_ERR_INVALID_CHARS,s->last_fontname,-1,wf,256))
  874. {
  875. hf = CreateFontW(sz,0,0,0,fw,italic,underline,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,wf);
  876. }
  877. #endif
  878. if (!hf) hf = CreateFont(sz,0,0,0,fw,italic,underline,FALSE,DEFAULT_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH,s->last_fontname);
  879. if (!hf)
  880. {
  881. s->use_fonth=0; // disable this font
  882. }
  883. else
  884. {
  885. TEXTMETRIC tm;
  886. tm.tmHeight = sz;
  887. if (!m_framebuffer && LICE_FUNCTION_VALID(__LICE_CreateBitmap)) m_framebuffer=__LICE_CreateBitmap(1,64,64);
  888. if (m_framebuffer && LICE_FUNCTION_VALID(LICE__GetDC))
  889. {
  890. HGDIOBJ oldFont = 0;
  891. HDC hdc=LICE__GetDC(m_framebuffer);
  892. if (hdc)
  893. {
  894. oldFont = SelectObject(hdc,hf);
  895. GetTextMetrics(hdc,&tm);
  896. #if defined(_WIN32) && !defined(WDL_NO_SUPPORT_UTF8)
  897. if (GetVersion()<0x80000000 &&
  898. GetTextFaceW(hdc,sizeof(wf)/sizeof(wf[0]),wf) &&
  899. WideCharToMultiByte(CP_UTF8,0,wf,-1,s->actual_fontname,sizeof(s->actual_fontname),NULL,NULL))
  900. {
  901. s->actual_fontname[sizeof(s->actual_fontname)-1]=0;
  902. }
  903. else
  904. #endif
  905. GetTextFace(hdc, sizeof(s->actual_fontname), s->actual_fontname);
  906. SelectObject(hdc,oldFont);
  907. }
  908. }
  909. s->use_fonth=wdl_max(tm.tmHeight,1);
  910. LICE__SetFromHFont(s->font,hf, (fontflag & ~EELFONT_FLAG_MASK) | 512 /*LICE_FONT_FLAG_OWNS_HFONT*/);
  911. }
  912. }
  913. }
  914. }
  915. if (s->font && s->use_fonth)
  916. {
  917. m_gfx_font_active=a;
  918. if (m_gfx_texth) *m_gfx_texth=s->use_fonth;
  919. return 1.0;
  920. }
  921. // try to init this font
  922. }
  923. #ifdef EEL_STRING_DEBUGOUT
  924. if (a >= m_gfx_fonts.GetSize()) EEL_STRING_DEBUGOUT("gfx_setfont: invalid font %d specified",a);
  925. #endif
  926. if (a<0||a>=m_gfx_fonts.GetSize()||!m_gfx_fonts.Get()[a].font)
  927. {
  928. m_gfx_font_active=-1;
  929. if (m_gfx_texth) *m_gfx_texth=8;
  930. return 1.0;
  931. }
  932. return 0.0;
  933. }
  934. void eel_lice_state::gfx_blitext2(int np, EEL_F **parms, int blitmode)
  935. {
  936. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_blitext2");
  937. if (!dest
  938. #ifdef DYNAMIC_LICE
  939. ||!LICE_ScaledBlit || !LICE_RotatedBlit||!LICE__GetWidth||!LICE__GetHeight
  940. #endif
  941. ) return;
  942. LICE_IBitmap *bm=GetImageForIndex(parms[0][0],"gfx_blitext2:src");
  943. if (!bm) return;
  944. const int bmw=LICE__GetWidth(bm);
  945. const int bmh=LICE__GetHeight(bm);
  946. // 0=img, 1=scale, 2=rotate
  947. double coords[8];
  948. const double sc = blitmode==0 && np > 1 ? parms[1][0] : 1.0,
  949. angle = blitmode==0 && np > 2 ? parms[2][0] : 0.0;
  950. if (blitmode==0)
  951. {
  952. parms+=2;
  953. np -= 2;
  954. }
  955. coords[0]=np > 1 ? parms[1][0] : 0.0f;
  956. coords[1]=np > 2 ? parms[2][0] : 0.0f;
  957. coords[2]=np > 3 ? parms[3][0] : bmw;
  958. coords[3]=np > 4 ? parms[4][0] : bmh;
  959. coords[4]=np > 5 ? parms[5][0] : *m_gfx_x;
  960. coords[5]=np > 6 ? parms[6][0] : *m_gfx_y;
  961. coords[6]=np > 7 ? parms[7][0] : coords[2]*sc;
  962. coords[7]=np > 8 ? parms[8][0] : coords[3]*sc;
  963. const bool isFromFB = bm == m_framebuffer;
  964. SetImageDirty(dest);
  965. if (bm == dest &&
  966. (blitmode != 0 || np > 1) && // legacy behavior to matech previous gfx_blit(3parm), do not use temp buffer
  967. CoordsSrcDestOverlap(coords))
  968. {
  969. if (!m_framebuffer_extra && LICE_FUNCTION_VALID(__LICE_CreateBitmap)) m_framebuffer_extra=__LICE_CreateBitmap(0,bmw,bmh);
  970. if (m_framebuffer_extra)
  971. {
  972. LICE__resize(bm=m_framebuffer_extra,bmw,bmh);
  973. LICE_ScaledBlit(bm,dest, // copy the source portion
  974. (int)coords[0],(int)coords[1],(int)coords[2],(int)coords[3],
  975. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3],
  976. 1.0f,LICE_BLIT_MODE_COPY);
  977. }
  978. }
  979. if (blitmode==1)
  980. {
  981. if (LICE_FUNCTION_VALID(LICE_DeltaBlit))
  982. LICE_DeltaBlit(dest,bm,(int)coords[4],(int)coords[5],(int)coords[6],(int)coords[7],
  983. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3],
  984. np > 9 ? (float)parms[9][0]:1.0f, // dsdx
  985. np > 10 ? (float)parms[10][0]:0.0f, // dtdx
  986. np > 11 ? (float)parms[11][0]:0.0f, // dsdy
  987. np > 12 ? (float)parms[12][0]:1.0f, // dtdy
  988. np > 13 ? (float)parms[13][0]:0.0f, // dsdxdy
  989. np > 14 ? (float)parms[14][0]:0.0f, // dtdxdy
  990. np <= 15 || parms[15][0] > 0.5, (float)*m_gfx_a,getCurModeForBlit(isFromFB));
  991. }
  992. else if (fabs(angle)>0.000000001)
  993. {
  994. LICE_RotatedBlit(dest,bm,(int)coords[4],(int)coords[5],(int)coords[6],(int)coords[7],
  995. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3],
  996. (float)angle,true, (float)*m_gfx_a,getCurModeForBlit(isFromFB),
  997. np > 9 ? (float)parms[9][0] : 0.0f,
  998. np > 10 ? (float)parms[10][0] : 0.0f);
  999. }
  1000. else
  1001. {
  1002. LICE_ScaledBlit(dest,bm,(int)coords[4],(int)coords[5],(int)coords[6],(int)coords[7],
  1003. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3], (float)*m_gfx_a,getCurModeForBlit(isFromFB));
  1004. }
  1005. }
  1006. void eel_lice_state::gfx_blitext(EEL_F img, EEL_F *coords, EEL_F angle)
  1007. {
  1008. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_blitext");
  1009. if (!dest
  1010. #ifdef DYNAMIC_LICE
  1011. ||!LICE_ScaledBlit || !LICE_RotatedBlit||!LICE__GetWidth||!LICE__GetHeight
  1012. #endif
  1013. ) return;
  1014. LICE_IBitmap *bm=GetImageForIndex(img,"gfx_blitext:src");
  1015. if (!bm) return;
  1016. SetImageDirty(dest);
  1017. const bool isFromFB = bm == m_framebuffer;
  1018. int bmw=LICE__GetWidth(bm);
  1019. int bmh=LICE__GetHeight(bm);
  1020. if (bm == dest && CoordsSrcDestOverlap(coords))
  1021. {
  1022. if (!m_framebuffer_extra && LICE_FUNCTION_VALID(__LICE_CreateBitmap)) m_framebuffer_extra=__LICE_CreateBitmap(0,bmw,bmh);
  1023. if ( m_framebuffer_extra)
  1024. {
  1025. LICE__resize(bm=m_framebuffer_extra,bmw,bmh);
  1026. LICE_ScaledBlit(bm,dest, // copy the source portion
  1027. (int)coords[0],(int)coords[1],(int)coords[2],(int)coords[3],
  1028. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3],
  1029. 1.0f,LICE_BLIT_MODE_COPY);
  1030. }
  1031. }
  1032. if (fabs(angle)>0.000000001)
  1033. {
  1034. LICE_RotatedBlit(dest,bm,(int)coords[4],(int)coords[5],(int)coords[6],(int)coords[7],
  1035. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3],(float)angle,
  1036. true, (float)*m_gfx_a,getCurModeForBlit(isFromFB),
  1037. (float)coords[8],(float)coords[9]);
  1038. }
  1039. else
  1040. {
  1041. LICE_ScaledBlit(dest,bm,(int)coords[4],(int)coords[5],(int)coords[6],(int)coords[7],
  1042. (float)coords[0],(float)coords[1],(float)coords[2],(float)coords[3], (float)*m_gfx_a,getCurModeForBlit(isFromFB));
  1043. }
  1044. }
  1045. void eel_lice_state::gfx_set(int np, EEL_F **parms)
  1046. {
  1047. if (np < 1) return;
  1048. if (m_gfx_r) *m_gfx_r = parms[0][0];
  1049. if (m_gfx_g) *m_gfx_g = np > 1 ? parms[1][0] : parms[0][0];
  1050. if (m_gfx_b) *m_gfx_b = np > 2 ? parms[2][0] : parms[0][0];
  1051. if (m_gfx_a) *m_gfx_a = np > 3 ? parms[3][0] : 1.0;
  1052. if (m_gfx_mode) *m_gfx_mode = np > 4 ? parms[4][0] : 0;
  1053. if (np > 5 && m_gfx_dest) *m_gfx_dest = parms[5][0];
  1054. if (m_gfx_a2) *m_gfx_a2 = np > 6 ? parms[6][0] : 1.0;
  1055. }
  1056. void eel_lice_state::gfx_getpixel(EEL_F *r, EEL_F *g, EEL_F *b)
  1057. {
  1058. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_getpixel");
  1059. if (!dest) return;
  1060. int ret=LICE_FUNCTION_VALID(LICE_GetPixel)?LICE_GetPixel(dest,(int)*m_gfx_x, (int)*m_gfx_y):0;
  1061. *r=LICE_GETR(ret)/255.0;
  1062. *g=LICE_GETG(ret)/255.0;
  1063. *b=LICE_GETB(ret)/255.0;
  1064. }
  1065. static int __drawTextWithFont(LICE_IBitmap *dest, const RECT *rect, LICE_IFont *font, const char *buf, int buflen,
  1066. int fg, int mode, float alpha, int flags, EEL_F *wantYoutput, EEL_F **measureOnly)
  1067. {
  1068. if (font && LICE_FUNCTION_VALID(LICE__DrawText))
  1069. {
  1070. RECT tr=*rect;
  1071. LICE__SetTextColor(font,fg);
  1072. LICE__SetTextCombineMode(font,mode,alpha);
  1073. int maxx=0;
  1074. RECT r={0,0,tr.left,0};
  1075. while (buflen>0)
  1076. {
  1077. int thislen = 0;
  1078. while (thislen < buflen && buf[thislen] != '\n') thislen++;
  1079. memset(&r,0,sizeof(r));
  1080. int lineh = LICE__DrawText(font,dest,buf,thislen?thislen:1,&r,DT_SINGLELINE|DT_NOPREFIX|DT_CALCRECT);
  1081. if (!measureOnly)
  1082. {
  1083. r.right += tr.left;
  1084. lineh = LICE__DrawText(font,dest,buf,thislen?thislen:1,&tr,DT_SINGLELINE|DT_NOPREFIX|flags);
  1085. if (wantYoutput) *wantYoutput = tr.top;
  1086. }
  1087. else
  1088. {
  1089. if (r.right > maxx) maxx=r.right;
  1090. }
  1091. tr.top += lineh;
  1092. buflen -= thislen+1;
  1093. buf += thislen+1;
  1094. }
  1095. if (measureOnly)
  1096. {
  1097. measureOnly[0][0] = maxx;
  1098. measureOnly[1][0] = tr.top;
  1099. }
  1100. return r.right;
  1101. }
  1102. else
  1103. {
  1104. int xpos=rect->left, ypos=rect->top;
  1105. int x;
  1106. int maxx=0,maxy=0;
  1107. LICE_SubBitmap sbm(
  1108. #ifdef DYNAMIC_LICE
  1109. (LICE_IBitmap_disabledAPI*)
  1110. #endif
  1111. dest,rect->left,rect->top,rect->right-rect->left,rect->bottom-rect->top);
  1112. if (!measureOnly)
  1113. {
  1114. if (!(flags & DT_NOCLIP))
  1115. {
  1116. if (rect->right <= rect->left || rect->bottom <= rect->top) return 0; // invalid clip rect hm
  1117. xpos = ypos = 0;
  1118. dest = &sbm;
  1119. }
  1120. if (flags & (DT_RIGHT|DT_BOTTOM|DT_CENTER|DT_VCENTER))
  1121. {
  1122. EEL_F w=0.0,h=0.0;
  1123. EEL_F *mo[2] = { &w,&h};
  1124. RECT tr={0,};
  1125. __drawTextWithFont(dest,&tr,NULL,buf,buflen,0,0,0.0f,0,NULL,mo);
  1126. if (flags & DT_RIGHT) xpos += (rect->right-rect->left) - (int)floor(w);
  1127. else if (flags & DT_CENTER) xpos += (rect->right-rect->left)/2 - (int)floor(w*.5);
  1128. if (flags & DT_BOTTOM) ypos += (rect->bottom-rect->top) - (int)floor(h);
  1129. else if (flags & DT_VCENTER) ypos += (rect->bottom-rect->top)/2 - (int)floor(h*.5);
  1130. }
  1131. }
  1132. const int sxpos = xpos;
  1133. if (LICE_FUNCTION_VALID(LICE_DrawChar)) for(x=0;x<buflen;x++)
  1134. {
  1135. switch (buf[x])
  1136. {
  1137. case '\n':
  1138. ypos += 8;
  1139. case '\r':
  1140. xpos = sxpos;
  1141. break;
  1142. case ' ': xpos += 8; break;
  1143. case '\t': xpos += 8*5; break;
  1144. default:
  1145. if (!measureOnly) LICE_DrawChar(dest,xpos,ypos,buf[x], fg,alpha,mode);
  1146. xpos += 8;
  1147. if (xpos > maxx) maxx=xpos;
  1148. maxy = ypos + 8;
  1149. break;
  1150. }
  1151. }
  1152. if (measureOnly)
  1153. {
  1154. measureOnly[0][0]=maxx;
  1155. measureOnly[1][0]=maxy;
  1156. }
  1157. else
  1158. {
  1159. if (wantYoutput) *wantYoutput=ypos;
  1160. }
  1161. return xpos;
  1162. }
  1163. }
  1164. void eel_lice_state::gfx_drawstr(void *opaque, EEL_F **parms, int nparms, int formatmode)// formatmode=1 for format, 2 for purely measure no format
  1165. {
  1166. int nfmtparms = nparms-1;
  1167. EEL_F **fmtparms = parms+1;
  1168. const char *funcname = formatmode==1?"gfx_printf":
  1169. formatmode==2?"gfx_measurestr":
  1170. formatmode==3?"gfx_measurechar" : "gfx_drawstr";
  1171. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,funcname);
  1172. if (!dest) return;
  1173. #ifdef DYNAMIC_LICE
  1174. if (!LICE__GetWidth || !LICE__GetHeight) return;
  1175. #endif
  1176. EEL_STRING_MUTEXLOCK_SCOPE
  1177. WDL_FastString *fs=NULL;
  1178. char buf[4096];
  1179. int s_len=0;
  1180. const char *s;
  1181. if (formatmode==3)
  1182. {
  1183. s_len = WDL_MakeUTFChar(buf, (int)parms[0][0], sizeof(buf));
  1184. s=buf;
  1185. }
  1186. else
  1187. {
  1188. s=EEL_STRING_GET_FOR_INDEX(parms[0][0],&fs);
  1189. #ifdef EEL_STRING_DEBUGOUT
  1190. if (!s) EEL_STRING_DEBUGOUT("gfx_%s: invalid string identifier %f",funcname,parms[0][0]);
  1191. #endif
  1192. if (!s)
  1193. {
  1194. s="<bad string>";
  1195. s_len = 12;
  1196. }
  1197. else if (formatmode==1)
  1198. {
  1199. extern int eel_format_strings(void *, const char *s, const char *ep, char *, int, int, EEL_F **);
  1200. s_len = eel_format_strings(opaque,s,fs?(s+fs->GetLength()):NULL,buf,sizeof(buf),nfmtparms,fmtparms);
  1201. if (s_len<1) return;
  1202. s=buf;
  1203. }
  1204. else
  1205. {
  1206. s_len = fs?fs->GetLength():(int)strlen(s);
  1207. }
  1208. }
  1209. if (s_len)
  1210. {
  1211. SetImageDirty(dest);
  1212. if (formatmode>=2)
  1213. {
  1214. if (nfmtparms==2)
  1215. {
  1216. RECT r={0,0,0,0};
  1217. __drawTextWithFont(dest,&r,GetActiveFont(),s,s_len,
  1218. getCurColor(),getCurMode(),(float)*m_gfx_a,0,NULL,fmtparms);
  1219. }
  1220. }
  1221. else
  1222. {
  1223. RECT r={(int)floor(*m_gfx_x),(int)floor(*m_gfx_y),0,0};
  1224. int flags=DT_NOCLIP;
  1225. if (formatmode == 0 && nparms >= 4)
  1226. {
  1227. flags=(int)*parms[1];
  1228. flags &= (DT_CENTER|DT_RIGHT|DT_VCENTER|DT_BOTTOM|DT_NOCLIP);
  1229. r.right=(int)*parms[2];
  1230. r.bottom=(int)*parms[3];
  1231. }
  1232. *m_gfx_x=__drawTextWithFont(dest,&r,GetActiveFont(),s,s_len,
  1233. getCurColor(),getCurMode(),(float)*m_gfx_a,flags,m_gfx_y,NULL);
  1234. }
  1235. }
  1236. }
  1237. void eel_lice_state::gfx_drawchar(EEL_F ch)
  1238. {
  1239. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_drawchar");
  1240. if (!dest) return;
  1241. SetImageDirty(dest);
  1242. int a=(int)(ch+0.5);
  1243. if (a == '\r' || a=='\n') a=' ';
  1244. char buf[32];
  1245. const int buflen = WDL_MakeUTFChar(buf, a, sizeof(buf));
  1246. RECT r={(int)floor(*m_gfx_x),(int)floor(*m_gfx_y),0,0};
  1247. *m_gfx_x = __drawTextWithFont(dest,&r,
  1248. GetActiveFont(),buf,buflen,
  1249. getCurColor(),getCurMode(),(float)*m_gfx_a,DT_NOCLIP,NULL,NULL);
  1250. }
  1251. void eel_lice_state::gfx_drawnumber(EEL_F n, EEL_F ndigits)
  1252. {
  1253. LICE_IBitmap *dest = GetImageForIndex(*m_gfx_dest,"gfx_drawnumber");
  1254. if (!dest) return;
  1255. SetImageDirty(dest);
  1256. char buf[512];
  1257. int a=(int)(ndigits+0.5);
  1258. if (a <0)a=0;
  1259. else if (a > 16) a=16;
  1260. snprintf(buf,sizeof(buf),"%.*f",a,n);
  1261. RECT r={(int)floor(*m_gfx_x),(int)floor(*m_gfx_y),0,0};
  1262. *m_gfx_x = __drawTextWithFont(dest,&r,
  1263. GetActiveFont(),buf,(int)strlen(buf),
  1264. getCurColor(),getCurMode(),(float)*m_gfx_a,DT_NOCLIP,NULL,NULL);
  1265. }