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.

1491 lines
45KB

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