Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2019
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / JavaScript vector graphics bindings
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 :
27 : /*
28 : ANY CHANGE TO THE API MUST BE REFLECTED IN THE DOCUMENTATION IN gpac/share/doc/idl/evg.idl
29 : (no way to define inline JS doc with doxygen)
30 : */
31 :
32 :
33 : #include <gpac/setup.h>
34 :
35 : #if defined(GPAC_HAS_QJS)
36 :
37 : /*base SVG type*/
38 : #include <gpac/nodes_svg.h>
39 : #include <gpac/nodes_mpeg4.h>
40 : #include <gpac/nodes_x3d.h>
41 : /*dom events*/
42 : #include <gpac/evg.h>
43 :
44 : #include "../scenegraph/qjs_common.h"
45 :
46 : #include <gpac/internal/compositor_dev.h>
47 :
48 : /*for texture from png/rgb*/
49 : #include <gpac/bitstream.h>
50 : #include <gpac/avparse.h>
51 : #include <gpac/network.h>
52 :
53 :
54 : #define EVG_GET_FLOAT(_name, _jsval) { Double _v; if (JS_ToFloat64(ctx, &_v, _jsval)) return js_throw_err(ctx, GF_BAD_PARAM); _name = (Float) _v; }
55 : #define CLAMPCOLF(_name) if (_name<0) _name=0; else if (_name>1.0) _name=1.0;
56 :
57 : uint8_t *evg_get_array(JSContext *ctx, JSValueConst obj, u32 *size);
58 :
59 : //not used, wau too slow - we kept the code for future testing
60 : //#define EVG_USE_JS_SHADER
61 :
62 : typedef struct
63 : {
64 : u32 width, height, pf, stride, stride_uv, nb_comp;
65 : char *data;
66 : u32 data_size;
67 : Bool owns_data;
68 : u32 flags;
69 : GF_EVGStencil *stencil;
70 : JSValue param_fun, obj;
71 : JSContext *ctx;
72 : } GF_JSTexture;
73 :
74 : #define MAX_ATTR_DIM 4
75 : typedef struct
76 : {
77 : Float values[MAX_ATTR_DIM];
78 : u32 dim;
79 : u8 comp_type;
80 : } EVG_VAIRes;
81 :
82 : enum
83 : {
84 : GF_EVG_VAI_VERTEX_INDEX=0,
85 : GF_EVG_VAI_VERTEX,
86 : GF_EVG_VAI_PRIMITIVE,
87 : };
88 :
89 : typedef struct
90 : {
91 : u32 prim_idx;
92 : u32 nb_comp;
93 : Float *values;
94 : u32 nb_values;
95 : JSValue ab;
96 : #ifdef EVG_USE_JS_SHADER
97 : JSValue res;
98 : #endif
99 : u32 interp_type;
100 :
101 : Float anchors[3][MAX_ATTR_DIM];
102 : EVG_VAIRes result;
103 :
104 : Bool normalize;
105 : } EVG_VAI;
106 :
107 : typedef struct
108 : {
109 : u32 nb_comp, att_type;
110 : Float *values;
111 : u32 nb_values;
112 : JSValue ab;
113 : JSValue res;
114 : u32 interp_type;
115 :
116 : Bool normalize;
117 : } EVG_VA;
118 :
119 : enum
120 : {
121 : COMP_X = 1,//x or r or s
122 : COMP_Y = 1<<1,//y or g or t
123 : COMP_Z = 1<<2, //z or b
124 : COMP_Q = 1<<3, //w/q or a
125 : COMP_V2_XY = COMP_X|COMP_Y,
126 : COMP_V2_XZ = COMP_X|COMP_Z,
127 : COMP_V2_YZ = COMP_Y|COMP_Z,
128 : COMP_V3 = COMP_X|COMP_Y|COMP_Z,
129 : COMP_V4 = COMP_X|COMP_Y|COMP_Z|COMP_Q,
130 : COMP_BOOL,
131 : COMP_INT,
132 : COMP_FLOAT
133 : };
134 :
135 : typedef struct
136 : {
137 : u8 op_type;
138 : u8 cond_type;
139 : u8 left_value_type;
140 : u8 right_value_type;
141 : s32 left_value, right_value, right_value_second;
142 : char *uni_name;
143 : JSValue tx_ref;
144 : GF_JSTexture *tx;
145 :
146 : //we separate VAI/MX from base value in order to be able to assign a VAI value
147 : union {
148 : struct {
149 : EVG_VAI *vai;
150 : JSValue ref;
151 : } vai;
152 : struct {
153 : EVG_VA *va;
154 : JSValue ref;
155 : } va;
156 : struct {
157 : GF_Matrix *mx;
158 : JSValue ref;
159 : } mx;
160 : };
161 :
162 : union {
163 : Float vec[4];
164 : s32 ival;
165 : Bool bval;
166 : };
167 : } ShaderOp;
168 :
169 : enum
170 : {
171 : GF_EVG_SHADER_FRAGMENT=1,
172 : GF_EVG_SHADER_VERTEX,
173 : };
174 :
175 : typedef struct
176 : {
177 : char *name;
178 : union {
179 : GF_Vec4 vecval;
180 : s32 ival;
181 : Bool bval;
182 : };
183 : u8 value_type;
184 : } ShaderVar;
185 :
186 : typedef struct
187 : {
188 : u32 mode;
189 : u32 nb_ops, alloc_ops;
190 : ShaderOp *ops;
191 : u32 nb_vars, alloc_vars;
192 : ShaderVar *vars;
193 : Bool invalid, disable_early_z;
194 : } EVGShader;
195 :
196 : typedef struct
197 : {
198 : u32 width, height, pf, stride, stride_uv, mem_size;
199 : char *data;
200 : Bool owns_data;
201 : Bool center_coords;
202 : GF_EVGSurface *surface;
203 : u32 composite_op;
204 : JSValue alpha_cbk;
205 : JSValue frag_shader;
206 : Bool frag_is_cbk;
207 : JSValue vert_shader;
208 : Bool vert_is_cbk;
209 :
210 : JSValue depth_buffer;
211 :
212 :
213 : EVGShader *frag, *vert;
214 :
215 : JSContext *ctx;
216 : JSValue obj;
217 : #ifdef EVG_USE_JS_SHADER
218 : JSValue frag_obj;
219 : JSValue vert_obj;
220 : #endif
221 :
222 : } GF_JSCanvas;
223 :
224 :
225 :
226 : typedef struct
227 : {
228 : GF_FontManager *fm;
229 : GF_Path *path;
230 : char *fontname;
231 : Double font_size;
232 : u32 align;
233 : u32 baseline;
234 : u32 styles;
235 : GF_List *spans;
236 : Bool horizontal;
237 : Bool flip;
238 : Double maxWidth;
239 : Double lineSpacing;
240 : Fixed min_x, min_y, max_x, max_y, max_w, max_h;
241 : GF_Font *font;
242 : Bool path_for_centered;
243 : } GF_JSText;
244 :
245 :
246 : JSClassID canvas_class_id;
247 : JSClassID canvas3d_class_id;
248 : JSClassID path_class_id;
249 : JSClassID mx2d_class_id;
250 : JSClassID colmx_class_id;
251 : JSClassID stencil_class_id;
252 : JSClassID texture_class_id;
253 : JSClassID text_class_id;
254 : JSClassID matrix_class_id;
255 : #ifdef EVG_USE_JS_SHADER
256 : JSClassID fragment_class_id;
257 : JSClassID vertex_class_id;
258 : JSClassID vaires_class_id;
259 : #endif
260 : JSClassID vai_class_id;
261 : JSClassID va_class_id;
262 : JSClassID shader_class_id;
263 :
264 : static void text_set_path(GF_JSCanvas *canvas, GF_JSText *text);
265 :
266 : Bool get_color_from_args(JSContext *c, int argc, JSValueConst *argv, u32 idx, Double *a, Double *r, Double *g, Double *b);
267 : static Bool get_color(JSContext *c, JSValueConst obj, Double *a, Double *r, Double *g, Double *b);
268 :
269 10 : static void canvas_finalize(JSRuntime *rt, JSValue obj)
270 : {
271 10 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id);
272 10 : if (!canvas) return;
273 : JS_FreeValueRT(rt, canvas->alpha_cbk);
274 : JS_FreeValueRT(rt, canvas->frag_shader);
275 : JS_FreeValueRT(rt, canvas->vert_shader);
276 :
277 10 : if (canvas->owns_data)
278 3 : gf_free(canvas->data);
279 10 : if (canvas->surface)
280 10 : gf_evg_surface_delete(canvas->surface);
281 10 : gf_free(canvas);
282 : }
283 :
284 8 : static void canvas_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
285 : {
286 8 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id);
287 8 : if (!canvas) return;
288 8 : JS_MarkValue(rt, canvas->alpha_cbk, mark_func);
289 8 : JS_MarkValue(rt, canvas->frag_shader, mark_func);
290 8 : JS_MarkValue(rt, canvas->vert_shader, mark_func);
291 : }
292 :
293 : JSClassDef canvas_class = {
294 : "Canvas",
295 : .finalizer = canvas_finalize,
296 : .gc_mark = canvas_gc_mark
297 : };
298 :
299 19 : static void canvas3d_finalize(JSRuntime *rt, JSValue obj)
300 : {
301 19 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
302 19 : if (!canvas) return;
303 : JS_FreeValueRT(rt, canvas->alpha_cbk);
304 : JS_FreeValueRT(rt, canvas->frag_shader);
305 : JS_FreeValueRT(rt, canvas->vert_shader);
306 : #ifdef EVG_USE_JS_SHADER
307 : JS_FreeValueRT(rt, canvas->frag_obj);
308 : JS_FreeValueRT(rt, canvas->vert_obj);
309 : #endif
310 : JS_FreeValueRT(rt, canvas->depth_buffer);
311 :
312 19 : if (canvas->owns_data)
313 1 : gf_free(canvas->data);
314 19 : if (canvas->surface)
315 19 : gf_evg_surface_delete(canvas->surface);
316 19 : gf_free(canvas);
317 : }
318 :
319 108 : static void canvas3d_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
320 : {
321 108 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
322 108 : if (!canvas) return;
323 108 : JS_MarkValue(rt, canvas->alpha_cbk, mark_func);
324 108 : JS_MarkValue(rt, canvas->frag_shader, mark_func);
325 108 : JS_MarkValue(rt, canvas->vert_shader, mark_func);
326 : #ifdef EVG_USE_JS_SHADER
327 : JS_MarkValue(rt, canvas->frag_obj, mark_func);
328 : JS_MarkValue(rt, canvas->vert_obj, mark_func);
329 : #endif
330 108 : JS_MarkValue(rt, canvas->depth_buffer, mark_func);
331 : }
332 :
333 : JSClassDef canvas3d_class = {
334 : "Canvas3D",
335 : .finalizer = canvas3d_finalize,
336 : .gc_mark = canvas3d_gc_mark
337 : };
338 :
339 : enum
340 : {
341 : GF_EVG_CENTERED = 0,
342 : GF_EVG_PATH,
343 : GF_EVG_MATRIX,
344 : GF_EVG_MATRIX_3D,
345 : GF_EVG_CLIPPER,
346 : GF_EVG_COMPOSITE_OP,
347 : GF_EVG_ALPHA_FUN,
348 : GF_EVG_FRAG_SHADER,
349 : GF_EVG_VERT_SHADER,
350 : GF_EVG_CCW,
351 : GF_EVG_BACKCULL,
352 : GF_EVG_MINDEPTH,
353 : GF_EVG_MAXDEPTH,
354 : GF_EVG_DEPTHTEST,
355 : GF_EVG_ANTIALIAS,
356 : GF_EVG_POINTSIZE,
357 : GF_EVG_POINTSMOOTH,
358 : GF_EVG_LINESIZE,
359 : GF_EVG_CLIP_ZERO,
360 : GF_EVG_DEPTH_BUFFER,
361 : GF_EVG_DEPTH_TEST,
362 : GF_EVG_WRITE_DEPTH,
363 : };
364 :
365 307 : u8 evg_get_alpha(void *cbk, u8 src_alpha, s32 x, s32 y)
366 : {
367 307 : u32 res_a=0;
368 : GF_JSCanvas *canvas = cbk;
369 : JSValue ret, args[3];
370 614 : args[0] = JS_NewInt32(canvas->ctx, src_alpha);
371 307 : args[1] = JS_NewInt32(canvas->ctx, x);
372 307 : args[2] = JS_NewInt32(canvas->ctx, y);
373 307 : ret = JS_Call(canvas->ctx, canvas->alpha_cbk, canvas->obj, 3, args);
374 307 : JS_ToInt32(canvas->ctx, &res_a, ret);
375 307 : return res_a;
376 :
377 : }
378 :
379 29 : static JSValue canvas_constructor_internal(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv, Bool is_3d)
380 : {
381 29 : u32 width, height, pf=0, osize;
382 29 : size_t data_size=0;
383 : u8 *data=NULL;
384 29 : u32 stride = 0;
385 29 : u32 stride_uv = 0;
386 : GF_JSCanvas *canvas;
387 : GF_Err e;
388 :
389 29 : if (argc<3)
390 0 : return JS_EXCEPTION;
391 29 : if (JS_ToInt32(c, &width, argv[0]))
392 0 : return JS_EXCEPTION;
393 29 : if (JS_ToInt32(c, &height, argv[1]))
394 0 : return JS_EXCEPTION;
395 58 : if (JS_IsString(argv[2])) {
396 : const char *str = JS_ToCString(c, argv[2]);
397 27 : pf = gf_pixel_fmt_parse(str);
398 27 : JS_FreeCString(c, str);
399 2 : } else if (JS_ToInt32(c, &pf, argv[2])) {
400 0 : return JS_EXCEPTION;
401 : }
402 29 : if (!width || !height || !pf)
403 0 : return JS_EXCEPTION;
404 :
405 29 : if (argc>3) {
406 : s32 idx=0;
407 50 : if (JS_IsObject(argv[3])) {
408 25 : data = JS_GetArrayBuffer(c, &data_size, argv[3]);
409 25 : if (!data) return JS_EXCEPTION;
410 : idx=1;
411 0 : } else if (!JS_IsInteger(argv[3]))
412 0 : return JS_EXCEPTION;
413 :
414 25 : if (argc>3+idx) {
415 0 : if (JS_ToInt32(c, &stride, argv[3+idx]))
416 0 : return JS_EXCEPTION;
417 0 : if (argc>4+idx) {
418 0 : if (JS_ToInt32(c, &stride_uv, argv[4+idx]))
419 0 : return JS_EXCEPTION;
420 : }
421 : }
422 : }
423 29 : GF_SAFEALLOC(canvas, GF_JSCanvas);
424 :
425 29 : if (!canvas)
426 0 : return JS_EXCEPTION;
427 :
428 29 : if (!gf_pixel_get_size_info(pf, width, height, &osize, &stride, &stride_uv, NULL, NULL)) {
429 0 : gf_free(canvas);
430 0 : return JS_EXCEPTION;
431 : }
432 29 : if (data && (data_size<osize)) {
433 0 : gf_free(canvas);
434 0 : return JS_EXCEPTION;
435 : }
436 :
437 29 : canvas->mem_size = osize;
438 29 : canvas->width = width;
439 29 : canvas->height = height;
440 29 : canvas->pf = pf;
441 29 : canvas->stride = stride;
442 29 : canvas->alpha_cbk = JS_UNDEFINED;
443 29 : canvas->frag_shader = JS_UNDEFINED;
444 29 : canvas->vert_shader = JS_UNDEFINED;
445 : #ifdef EVG_USE_JS_SHADER
446 : canvas->frag_obj = JS_UNDEFINED;
447 : canvas->vert_obj = JS_UNDEFINED;
448 : #endif
449 29 : canvas->depth_buffer = JS_UNDEFINED;
450 29 : canvas->ctx = c;
451 29 : if (data) {
452 25 : canvas->data = data;
453 25 : canvas->owns_data = GF_FALSE;
454 : } else {
455 4 : canvas->data = gf_malloc(sizeof(u8)*osize);
456 4 : canvas->owns_data = GF_TRUE;
457 : }
458 29 : if (is_3d) {
459 19 : canvas->surface = gf_evg_surface3d_new();
460 : #ifdef EVG_USE_JS_SHADER
461 : canvas->frag_obj = JS_NewObjectClass(c, fragment_class_id);
462 : JS_SetOpaque(canvas->frag_obj, NULL);
463 : canvas->vert_obj = JS_NewObjectClass(c, vertex_class_id);
464 : JS_SetOpaque(canvas->vert_obj, NULL);
465 : #endif
466 : } else {
467 10 : canvas->surface = gf_evg_surface_new(GF_TRUE);
468 10 : canvas->center_coords = GF_TRUE;
469 : }
470 29 : if (!canvas->surface)
471 : e = GF_BAD_PARAM;
472 : else
473 29 : e = gf_evg_surface_attach_to_buffer(canvas->surface, canvas->data, canvas->width, canvas->height, 0, canvas->stride, canvas->pf);
474 29 : if (e) {
475 0 : if (canvas->owns_data) gf_free(canvas->data);
476 0 : gf_evg_surface_delete(canvas->surface);
477 0 : gf_free(canvas);
478 0 : return JS_EXCEPTION;
479 : }
480 29 : canvas->obj = JS_NewObjectClass(c, is_3d ? canvas3d_class_id : canvas_class_id);
481 58 : if (JS_IsException(canvas->obj)) return canvas->obj;
482 :
483 29 : JS_SetOpaque(canvas->obj, canvas);
484 29 : return canvas->obj;
485 : }
486 :
487 10 : static JSValue canvas_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
488 : {
489 10 : return canvas_constructor_internal(c, new_target, argc, argv, GF_FALSE);
490 : }
491 :
492 1 : static JSValue canvas_getProperty(JSContext *c, JSValueConst obj, int magic)
493 : {
494 1 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id);
495 1 : if (!canvas) return JS_EXCEPTION;
496 1 : switch (magic) {
497 1 : case GF_EVG_CENTERED: return JS_NewBool(c, canvas->center_coords);
498 0 : case GF_EVG_COMPOSITE_OP: return JS_NewInt32(c, canvas->composite_op);
499 0 : case GF_EVG_ALPHA_FUN: return JS_DupValue(c, canvas->alpha_cbk);
500 : }
501 0 : return JS_UNDEFINED;
502 : }
503 :
504 200 : Bool canvas_get_irect(JSContext *c, JSValueConst obj, GF_IRect *rc)
505 : {
506 : JSValue v;
507 : int res;
508 : memset(rc, 0, sizeof(GF_IRect));
509 :
510 : #define GET_PROP( _n, _f)\
511 : v = JS_GetPropertyStr(c, obj, _n);\
512 : res = JS_ToInt32(c, &(rc->_f), v);\
513 : JS_FreeValue(c, v);\
514 : if (res) return GF_FALSE;\
515 :
516 400 : GET_PROP("x", x)
517 400 : GET_PROP("y", y)
518 400 : GET_PROP("w", width)
519 400 : GET_PROP("h", height)
520 : #undef GET_PROP
521 200 : return GF_TRUE;
522 : }
523 :
524 1853 : static JSValue canvas_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
525 : {
526 1853 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id);
527 1853 : if (!canvas) return JS_EXCEPTION;
528 1853 : switch (magic) {
529 106 : case GF_EVG_CENTERED:
530 106 : canvas->center_coords = JS_ToBool(c, value) ? GF_TRUE : GF_FALSE;
531 106 : gf_evg_surface_set_center_coords(canvas->surface, canvas->center_coords);
532 106 : return JS_UNDEFINED;
533 :
534 722 : case GF_EVG_PATH:
535 722 : if (JS_IsNull(value)) {
536 0 : gf_evg_surface_set_path(canvas->surface, NULL);
537 : } else {
538 722 : GF_Path *gp = JS_GetOpaque(value, path_class_id);
539 722 : if (gp)
540 513 : gf_evg_surface_set_path(canvas->surface, gp);
541 : else {
542 209 : GF_JSText *text = JS_GetOpaque(value, text_class_id);
543 209 : if (text) {
544 209 : text_set_path(canvas, text);
545 : }
546 : }
547 : }
548 722 : return JS_UNDEFINED;
549 :
550 621 : case GF_EVG_MATRIX:
551 621 : if (JS_IsNull(value)) {
552 0 : gf_evg_surface_set_matrix(canvas->surface, NULL);
553 : } else {
554 621 : GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id);
555 621 : gf_evg_surface_set_matrix(canvas->surface, mx);
556 : }
557 621 : return JS_UNDEFINED;
558 :
559 1 : case GF_EVG_MATRIX_3D:
560 1 : if (JS_IsNull(value)) {
561 0 : gf_evg_surface_set_matrix(canvas->surface, NULL);
562 : } else {
563 1 : GF_Matrix *mx = JS_GetOpaque(value, matrix_class_id);
564 1 : gf_evg_surface_set_matrix_3d(canvas->surface, mx);
565 : }
566 1 : return JS_UNDEFINED;
567 301 : case GF_EVG_CLIPPER:
568 301 : if (JS_IsNull(value)) {
569 201 : gf_evg_surface_set_clipper(canvas->surface, NULL);
570 : } else {
571 : GF_IRect rc;
572 100 : canvas_get_irect(c, value, &rc);
573 100 : gf_evg_surface_set_clipper(canvas->surface, &rc);
574 : }
575 301 : return JS_UNDEFINED;
576 1 : case GF_EVG_COMPOSITE_OP:
577 1 : if (JS_ToInt32(c, &canvas->composite_op, value)) return JS_EXCEPTION;
578 1 : gf_evg_surface_set_composite_mode(canvas->surface, canvas->composite_op);
579 1 : break;
580 101 : case GF_EVG_ALPHA_FUN:
581 : JS_FreeValue(c, canvas->alpha_cbk);
582 101 : if (JS_IsNull(value) || !JS_IsFunction(c, value)) {
583 100 : canvas->alpha_cbk = JS_UNDEFINED;
584 100 : gf_evg_surface_set_alpha_callback(canvas->surface, NULL, NULL);
585 : } else {
586 1 : canvas->alpha_cbk = JS_DupValue(c, value);
587 1 : gf_evg_surface_set_alpha_callback(canvas->surface, evg_get_alpha, canvas);
588 : }
589 101 : return JS_UNDEFINED;
590 : }
591 1 : return JS_UNDEFINED;
592 : }
593 :
594 :
595 432 : static JSValue canvas_clear_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_float, Bool is_3d)
596 : {
597 : s32 i;
598 : s32 idx=0;
599 : GF_Err e;
600 : GF_IRect rc, *irc;
601 : u32 r=0, g=0, b=0, a=255;
602 : GF_Color col;
603 432 : GF_JSCanvas *canvas = JS_GetOpaque(obj, is_3d ? canvas3d_class_id : canvas_class_id);
604 432 : if (!canvas)
605 0 : return JS_EXCEPTION;
606 :
607 : irc = NULL;
608 864 : if (argc && JS_IsObject(argv[0])) {
609 : irc = &rc;
610 : idx=1;
611 100 : if (!canvas_get_irect(c, argv[0], &rc))
612 0 : return JS_EXCEPTION;
613 : }
614 1096 : if ((argc>idx) && JS_IsString(argv[idx])) {
615 : const char *str = JS_ToCString(c, argv[idx]);
616 232 : col = gf_color_parse(str);
617 232 : JS_FreeCString(c, str);
618 : } else {
619 200 : if (argc>4+idx) argc = 4+idx;
620 600 : for (i=idx; i<argc; i++) {
621 : s32 v;
622 400 : if (use_float) {
623 : Double d;
624 400 : if (JS_ToFloat64(c, &d, argv[i]))
625 0 : return JS_EXCEPTION;
626 400 : v = (s32) (d*255);
627 0 : } else if (JS_ToInt32(c, &v, argv[i])) {
628 0 : return JS_EXCEPTION;
629 : }
630 :
631 400 : if (v<0) v = 0;
632 400 : else if (v>255) v = 255;
633 :
634 400 : if (i==idx) r=v;
635 200 : else if (i==idx+1) g=v;
636 100 : else if (i==idx+2) b=v;
637 0 : else a=v;
638 : }
639 200 : col = GF_COL_ARGB(a, r, g, b) ;
640 : }
641 432 : e = gf_evg_surface_clear(canvas->surface, irc, col);
642 432 : if (e)
643 0 : return JS_EXCEPTION;
644 432 : return JS_UNDEFINED;
645 : }
646 1 : static JSValue canvas_clear(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
647 : {
648 1 : return canvas_clear_ex(c, obj, argc, argv, GF_FALSE, GF_FALSE);
649 : }
650 305 : static JSValue canvas_clearf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
651 : {
652 305 : return canvas_clear_ex(c, obj, argc, argv, GF_TRUE, GF_FALSE);
653 : }
654 :
655 4 : static JSValue canvas_rgb_yuv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool to_rgb, Bool is_3d)
656 : {
657 : GF_Err e;
658 4 : Double _r=0, _g=0, _b=0, _a=1.0;
659 : Float r=0, g=0, b=0, a=1.0;
660 : Bool as_array = GF_FALSE;
661 : u32 arg_idx=0;
662 : Float y, u, v;
663 : JSValue ret;
664 4 : GF_JSCanvas *canvas = JS_GetOpaque(obj, is_3d ? canvas3d_class_id : canvas_class_id);
665 4 : if (!canvas || !argc)
666 0 : return JS_EXCEPTION;
667 :
668 8 : if (JS_IsBool(argv[0])) {
669 0 : as_array = JS_ToBool(c, argv[0]);
670 : arg_idx=1;
671 : }
672 4 : if (!get_color_from_args(c, argc, argv, arg_idx, &_a, &_r, &_g, &_b))
673 0 : return JS_EXCEPTION;
674 4 : r = (Float) _r;
675 4 : g = (Float) _g;
676 4 : b = (Float) _b;
677 4 : a = (Float) _a;
678 4 : if (to_rgb) {
679 2 : e = gf_evg_yuv_to_rgb_f(canvas->surface, r, g, b, &y, &u, &v);
680 : } else {
681 2 : e = gf_gf_evg_rgb_to_yuv_f(canvas->surface, r, g, b, &y, &u, &v);
682 : }
683 4 : if (e)
684 0 : return JS_EXCEPTION;
685 4 : if (as_array) {
686 0 : ret = JS_NewArray(c);
687 0 : JS_SetPropertyStr(c, ret, "length", JS_NewInt32(c, 4) );
688 0 : JS_SetPropertyUint32(c, ret, 0, JS_NewFloat64(c, y) );
689 0 : JS_SetPropertyUint32(c, ret, 1, JS_NewFloat64(c, u) );
690 0 : JS_SetPropertyUint32(c, ret, 2, JS_NewFloat64(c, v) );
691 0 : JS_SetPropertyUint32(c, ret, 3, JS_NewFloat64(c, a) );
692 : } else {
693 4 : ret = JS_NewObject(c);
694 8 : JS_SetPropertyStr(c, ret, "r", JS_NewFloat64(c, y) );
695 8 : JS_SetPropertyStr(c, ret, "g", JS_NewFloat64(c, u) );
696 8 : JS_SetPropertyStr(c, ret, "b", JS_NewFloat64(c, v) );
697 8 : JS_SetPropertyStr(c, ret, "a", JS_NewFloat64(c, a) );
698 : }
699 4 : return ret;
700 : }
701 :
702 407 : static JSValue canvas_reassign_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_3d)
703 : {
704 : GF_Err e;
705 : u8 *data;
706 407 : size_t data_size=0;
707 407 : GF_JSCanvas *canvas = JS_GetOpaque(obj, is_3d ? canvas3d_class_id : canvas_class_id);
708 407 : if (!canvas || !argc) return JS_EXCEPTION;
709 814 : if (!JS_IsObject(argv[0])) return JS_EXCEPTION;
710 :
711 407 : if (canvas->owns_data) {
712 0 : gf_free(canvas->data);
713 0 : canvas->owns_data = GF_FALSE;
714 : }
715 407 : canvas->data = NULL;
716 407 : data = JS_GetArrayBuffer(c, &data_size, argv[0]);
717 407 : if (!data || (data_size<canvas->mem_size)) {
718 : e = GF_BAD_PARAM;
719 : } else {
720 407 : canvas->data = data;
721 407 : e = gf_evg_surface_attach_to_buffer(canvas->surface, canvas->data, canvas->width, canvas->height, 0, canvas->stride, canvas->pf);
722 : }
723 407 : if (e) return JS_EXCEPTION;
724 407 : return JS_UNDEFINED;
725 : }
726 :
727 199 : static JSValue canvas_reassign(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
728 : {
729 199 : return canvas_reassign_ex(c, obj, argc, argv, GF_FALSE);
730 : }
731 :
732 1 : static JSValue canvas_toYUV(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
733 : {
734 1 : return canvas_rgb_yuv(c, obj, argc, argv, GF_FALSE, GF_FALSE);
735 : }
736 :
737 1 : static JSValue canvas_toRGB(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
738 : {
739 1 : return canvas_rgb_yuv(c, obj, argc, argv, GF_TRUE, GF_FALSE);
740 : }
741 :
742 934 : static JSValue canvas_fill(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
743 : {
744 : GF_EVGStencil *stencil;
745 : GF_JSTexture *tx;
746 934 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id);
747 934 : if (!canvas || !argc) return JS_EXCEPTION;
748 934 : stencil = JS_GetOpaque(argv[0], stencil_class_id);
749 934 : if (stencil) {
750 614 : gf_evg_surface_fill(canvas->surface, stencil);
751 614 : return JS_UNDEFINED;
752 : }
753 320 : tx = JS_GetOpaque(argv[0], texture_class_id);
754 320 : if (tx) {
755 320 : gf_evg_surface_fill(canvas->surface, tx->stencil);
756 320 : return JS_UNDEFINED;
757 : }
758 0 : return JS_EXCEPTION;
759 : }
760 :
761 : static const JSCFunctionListEntry canvas_funcs[] =
762 : {
763 : JS_CGETSET_MAGIC_DEF("centered", canvas_getProperty, canvas_setProperty, GF_EVG_CENTERED),
764 : JS_CGETSET_MAGIC_DEF("path", NULL, canvas_setProperty, GF_EVG_PATH),
765 : JS_CGETSET_MAGIC_DEF("clipper", NULL, canvas_setProperty, GF_EVG_CLIPPER),
766 : JS_CGETSET_MAGIC_DEF("matrix", NULL, canvas_setProperty, GF_EVG_MATRIX),
767 : JS_CGETSET_MAGIC_DEF("matrix3d", NULL, canvas_setProperty, GF_EVG_MATRIX_3D),
768 : JS_CGETSET_MAGIC_DEF("compositeOperation", canvas_getProperty, canvas_setProperty, GF_EVG_COMPOSITE_OP),
769 : JS_CGETSET_MAGIC_DEF("on_alpha", canvas_getProperty, canvas_setProperty, GF_EVG_ALPHA_FUN),
770 : JS_CFUNC_DEF("clear", 0, canvas_clear),
771 : JS_CFUNC_DEF("clearf", 0, canvas_clearf),
772 : JS_CFUNC_DEF("fill", 0, canvas_fill),
773 : JS_CFUNC_DEF("reassign", 0, canvas_reassign),
774 : JS_CFUNC_DEF("toYUV", 0, canvas_toYUV),
775 : JS_CFUNC_DEF("toRGB", 0, canvas_toRGB),
776 : };
777 :
778 :
779 1 : static JSValue canvas3d_clear(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
780 : {
781 1 : return canvas_clear_ex(c, obj, argc, argv, GF_FALSE, GF_TRUE);
782 : }
783 125 : static JSValue canvas3d_clearf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
784 : {
785 125 : return canvas_clear_ex(c, obj, argc, argv, GF_TRUE, GF_TRUE);
786 : }
787 208 : static JSValue canvas3d_reassign(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
788 : {
789 208 : return canvas_reassign_ex(c, obj, argc, argv, GF_TRUE);
790 : }
791 :
792 1 : static JSValue canvas3d_toYUV(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
793 : {
794 1 : return canvas_rgb_yuv(c, obj, argc, argv, GF_FALSE, GF_TRUE);
795 : }
796 :
797 1 : static JSValue canvas3d_toRGB(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
798 : {
799 1 : return canvas_rgb_yuv(c, obj, argc, argv, GF_TRUE, GF_TRUE);
800 : }
801 :
802 : Bool vai_call_lerp(EVG_VAI *vai, GF_EVGFragmentParam *frag);
803 :
804 : #ifdef EVG_USE_JS_SHADER
805 : static Bool evg_frag_shader_fun(void *udta, GF_EVGFragmentParam *frag)
806 : {
807 : Bool frag_valid;
808 : JSValue res;
809 : GF_JSCanvas *canvas = (GF_JSCanvas *)udta;
810 : if (!canvas) return GF_FALSE;
811 :
812 : JS_SetOpaque(canvas->frag_obj, frag);
813 : res = JS_Call(canvas->ctx, canvas->frag_shader, canvas->obj, 1, &canvas->frag_obj);
814 : frag_valid = frag->frag_valid ? 1 : 0;
815 : if (JS_IsException(res)) frag_valid = GF_FALSE;
816 : else if (!JS_IsUndefined(res)) frag_valid = JS_ToBool(canvas->ctx, res) ? GF_TRUE : GF_FALSE;
817 : JS_FreeValue(canvas->ctx, res);
818 : return frag_valid;
819 : }
820 :
821 : static Bool evg_vert_shader_fun(void *udta, GF_EVGVertexParam *vertex)
822 : {
823 : Bool vert_valid=GF_TRUE;
824 : JSValue res;
825 : GF_JSCanvas *canvas = (GF_JSCanvas *)udta;
826 : if (!canvas) return GF_FALSE;
827 :
828 : JS_SetOpaque(canvas->vert_obj, vertex);
829 : res = JS_Call(canvas->ctx, canvas->frag_shader, canvas->obj, 1, &canvas->vert_obj);
830 : if (JS_IsException(res)) vert_valid = GF_FALSE;
831 : else if (!JS_IsUndefined(res)) vert_valid = JS_ToBool(canvas->ctx, res) ? GF_TRUE : GF_FALSE;
832 : JS_FreeValue(canvas->ctx, res);
833 : return vert_valid;
834 : }
835 : #endif
836 :
837 1 : static JSValue canvas3d_getProperty(JSContext *c, JSValueConst obj, int magic)
838 : {
839 1 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
840 1 : if (!canvas) return JS_EXCEPTION;
841 1 : switch (magic) {
842 0 : case GF_EVG_FRAG_SHADER: return JS_DupValue(c, canvas->frag_shader);
843 0 : case GF_EVG_VERT_SHADER: return JS_DupValue(c, canvas->vert_shader);
844 1 : case GF_EVG_DEPTH_BUFFER: return JS_DupValue(c, canvas->depth_buffer);
845 : }
846 0 : return JS_UNDEFINED;
847 : }
848 :
849 : static Bool evg_frag_shader_ops(void *udta, GF_EVGFragmentParam *frag);
850 : static Bool evg_vert_shader_ops(void *udta, GF_EVGVertexParam *frag);
851 :
852 1443 : static JSValue canvas3d_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic)
853 : {
854 : Float f;
855 : s32 ival;
856 : GF_Err e = GF_OK;
857 1443 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
858 1443 : if (!canvas) return JS_EXCEPTION;
859 1443 : switch (magic) {
860 0 : case GF_EVG_CLIPPER:
861 0 : if (JS_IsNull(value)) {
862 0 : e = gf_evg_surface_set_clipper(canvas->surface, NULL);
863 : } else {
864 : GF_IRect rc;
865 0 : canvas_get_irect(ctx, value, &rc);
866 0 : e = gf_evg_surface_set_clipper(canvas->surface, &rc);
867 : }
868 : break;
869 326 : case GF_EVG_FRAG_SHADER:
870 : JS_FreeValue(ctx, canvas->frag_shader);
871 326 : canvas->frag_shader = JS_UNDEFINED;
872 326 : canvas->frag = NULL;
873 326 : if (JS_IsNull(value)) {
874 0 : canvas->frag_shader = JS_UNDEFINED;
875 0 : e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL);
876 : #ifdef EVG_USE_JS_SHADER
877 : } else if (JS_IsFunction(ctx, value)) {
878 : canvas->frag_shader = JS_DupValue(ctx, value);
879 : e = gf_evg_surface_set_fragment_shader(canvas->surface, evg_frag_shader_fun, canvas);
880 : #endif
881 326 : } else if (JS_IsObject(value)) {
882 326 : canvas->frag = JS_GetOpaque(value, shader_class_id);
883 326 : if (!canvas->frag || (canvas->frag->mode != GF_EVG_SHADER_FRAGMENT))
884 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Invalid fragment shader object");
885 326 : canvas->frag_shader = JS_DupValue(ctx, value);
886 326 : e = gf_evg_surface_set_fragment_shader(canvas->surface, evg_frag_shader_ops, canvas);
887 326 : if (!e) e = gf_evg_surface_disable_early_depth(canvas->surface, canvas->frag->disable_early_z);
888 : } else {
889 0 : canvas->frag_shader = JS_UNDEFINED;
890 0 : e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL);
891 : }
892 : break;
893 225 : case GF_EVG_VERT_SHADER:
894 : JS_FreeValue(ctx, canvas->vert_shader);
895 225 : canvas->vert_shader = JS_UNDEFINED;
896 225 : canvas->vert = NULL;
897 225 : if (JS_IsNull(value)) {
898 100 : canvas->vert_shader = JS_UNDEFINED;
899 100 : e = gf_evg_surface_set_vertex_shader(canvas->surface, NULL, NULL);
900 : #ifdef EVG_USE_JS_SHADER
901 : } else if (JS_IsFunction(ctx, value)) {
902 : canvas->vert_shader = JS_DupValue(ctx, value);
903 : e = gf_evg_surface_set_vertex_shader(canvas->surface, evg_vert_shader_fun, canvas);
904 : #endif
905 125 : } else if (JS_IsObject(value)) {
906 125 : canvas->vert = JS_GetOpaque(value, shader_class_id);
907 125 : if (!canvas->vert || (canvas->vert->mode != GF_EVG_SHADER_VERTEX))
908 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "Invalid fragment shader object");
909 125 : canvas->vert_shader = JS_DupValue(ctx, value);
910 125 : e = gf_evg_surface_set_vertex_shader(canvas->surface, evg_vert_shader_ops, canvas);
911 : } else {
912 0 : canvas->frag_shader = JS_UNDEFINED;
913 0 : e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL);
914 : }
915 : break;
916 10 : case GF_EVG_CCW:
917 10 : e = gf_evg_surface_set_ccw(canvas->surface, JS_ToBool(ctx, value) );
918 10 : break;
919 226 : case GF_EVG_BACKCULL:
920 226 : e = gf_evg_surface_set_backcull(canvas->surface, JS_ToBool(ctx, value) );
921 226 : break;
922 226 : case GF_EVG_ANTIALIAS:
923 226 : e = gf_evg_surface_set_antialias(canvas->surface, JS_ToBool(ctx, value) );
924 226 : break;
925 :
926 19 : case GF_EVG_DEPTH_BUFFER:
927 : {
928 : Float *depthb;
929 : u32 dsize;
930 : JS_FreeValue(ctx, canvas->depth_buffer);
931 19 : canvas->depth_buffer = JS_UNDEFINED;
932 19 : depthb = (Float *) evg_get_array(ctx, value, &dsize);
933 19 : if (!depthb) {
934 0 : canvas->depth_buffer = JS_NULL;
935 0 : e = gf_evg_surface_set_depth_buffer(canvas->surface, NULL);
936 : } else {
937 19 : u32 req_size = canvas->width*canvas->height*sizeof(Float);
938 19 : if (req_size>dsize) {
939 : e = GF_BAD_PARAM;
940 0 : gf_evg_surface_set_depth_buffer(canvas->surface, NULL);
941 : } else {
942 19 : canvas->depth_buffer = JS_DupValue(ctx, value);
943 19 : e = gf_evg_surface_set_depth_buffer(canvas->surface, depthb);
944 : }
945 : }
946 : break;
947 : }
948 :
949 10 : case GF_EVG_MINDEPTH:
950 10 : EVG_GET_FLOAT(f, value);
951 10 : e = gf_evg_surface_set_min_depth(canvas->surface, f);
952 10 : break;
953 10 : case GF_EVG_MAXDEPTH:
954 10 : EVG_GET_FLOAT(f, value);
955 10 : e = gf_evg_surface_set_max_depth(canvas->surface, f);
956 10 : break;
957 0 : case GF_EVG_DEPTHTEST:
958 0 : if (JS_ToInt32(ctx, &ival, value))
959 0 : return js_throw_err(ctx, GF_BAD_PARAM);
960 0 : e = gf_evg_set_depth_test(canvas->surface, ival);
961 0 : break;
962 10 : case GF_EVG_POINTSIZE:
963 10 : EVG_GET_FLOAT(f, value);
964 10 : e = gf_evg_surface_set_point_size(canvas->surface, f);
965 10 : break;
966 10 : case GF_EVG_POINTSMOOTH:
967 10 : e = gf_evg_surface_set_point_smooth(canvas->surface, JS_ToBool(ctx, value) );
968 10 : break;
969 10 : case GF_EVG_LINESIZE:
970 10 : EVG_GET_FLOAT(f, value);
971 10 : e = gf_evg_surface_set_line_size(canvas->surface, f);
972 10 : break;
973 125 : case GF_EVG_CLIP_ZERO:
974 125 : e = gf_evg_surface_set_clip_zero(canvas->surface, JS_ToBool(ctx, value) ? GF_TRUE : GF_FALSE);
975 125 : break;
976 226 : case GF_EVG_DEPTH_TEST:
977 226 : if (JS_ToInt32(ctx, &ival, value)) return JS_EXCEPTION;
978 226 : e = gf_evg_set_depth_test(canvas->surface, ival);
979 226 : break;
980 10 : case GF_EVG_WRITE_DEPTH:
981 10 : e = gf_evg_surface_write_depth(canvas->surface, JS_ToBool(ctx, value) ? GF_TRUE : GF_FALSE);
982 10 : break;
983 : }
984 1443 : if (e) return js_throw_err(ctx, e);
985 :
986 1443 : return JS_UNDEFINED;
987 : }
988 :
989 402 : static JSValue canvas3d_set_matrix(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_proj)
990 : {
991 : GF_Err e;
992 : GF_Matrix mx;
993 402 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
994 402 : if (!canvas) return JS_EXCEPTION;
995 :
996 402 : gf_mx_init(mx);
997 402 : if (argc) {
998 402 : if (JS_IsArray(c, argv[0])) {
999 402 : u32 i, len=0;
1000 402 : JSValue v = JS_GetPropertyStr(c, argv[0], "length");
1001 402 : JS_ToInt32(c, &len, v);
1002 : JS_FreeValue(c, v);
1003 402 : if (len < 16) return JS_EXCEPTION;
1004 6432 : for (i=0; i<16; i++) {
1005 6432 : Double val=0;
1006 6432 : v = JS_GetPropertyUint32(c, argv[0], i);
1007 6432 : s32 res = JS_ToFloat64(c, &val, v);
1008 : JS_FreeValue(c, v);
1009 6432 : if (res) return JS_EXCEPTION;
1010 6432 : mx.m[i] = FLT2FIX(val);
1011 : }
1012 : } else {
1013 0 : return js_throw_err_msg(c, GF_NOT_SUPPORTED, "only float array currently supported for matrices");
1014 : }
1015 : }
1016 402 : if (is_proj)
1017 201 : e = gf_evg_surface_set_projection(canvas->surface, &mx);
1018 : else
1019 201 : e = gf_evg_surface_set_modelview(canvas->surface, &mx);
1020 402 : return e ? JS_EXCEPTION : JS_UNDEFINED;
1021 : }
1022 201 : static JSValue canvas3d_projection(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1023 : {
1024 201 : return canvas3d_set_matrix(c, obj, argc, argv, GF_TRUE);
1025 : }
1026 201 : static JSValue canvas3d_modelview(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1027 : {
1028 201 : return canvas3d_set_matrix(c, obj, argc, argv, GF_FALSE);
1029 : }
1030 :
1031 473 : uint8_t *evg_get_array(JSContext *ctx, JSValueConst obj, u32 *size)
1032 : {
1033 : JSValue v;
1034 : /*ArrayBuffer*/
1035 : size_t psize;
1036 473 : uint8_t *res = JS_GetArrayBuffer(ctx, &psize, obj);
1037 473 : if (res) {
1038 19 : *size = (u32) psize;
1039 19 : return res;
1040 : }
1041 : /*ArrayView*/
1042 454 : v = JS_GetPropertyStr(ctx, obj, "buffer");
1043 454 : if (JS_IsUndefined(v)) return NULL;
1044 454 : res = JS_GetArrayBuffer(ctx, &psize, v);
1045 : JS_FreeValue(ctx, v);
1046 454 : *size = (u32) psize;
1047 454 : return res;
1048 : }
1049 226 : static JSValue canvas3d_draw_array(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
1050 : {
1051 : uint8_t *indices=NULL;
1052 : uint8_t *vertices=NULL;
1053 226 : u32 idx_size=0, vx_size, nb_comp=3;
1054 : GF_Err e;
1055 226 : GF_EVGPrimitiveType prim_type=GF_EVG_TRIANGLES;
1056 226 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
1057 226 : if (!canvas || argc<2) return JS_EXCEPTION;
1058 :
1059 226 : indices = evg_get_array(c, argv[0], &idx_size);
1060 226 : vertices = evg_get_array(c, argv[1], &vx_size);
1061 226 : if (!indices || ! vertices) return JS_EXCEPTION;
1062 226 : if (argc>2) {
1063 226 : JS_ToInt32(c, (s32 *)&prim_type, argv[2]);
1064 226 : if (!prim_type) return JS_EXCEPTION;
1065 226 : if (argc>3) {
1066 0 : JS_ToInt32(c, &nb_comp, argv[3]);
1067 0 : if ((nb_comp<2) || (nb_comp>4)) return JS_EXCEPTION;
1068 : }
1069 : }
1070 226 : if (vx_size % nb_comp)
1071 0 : return JS_EXCEPTION;
1072 226 : idx_size /= sizeof(s32);
1073 226 : vx_size /= sizeof(Float);
1074 226 : e = gf_evg_surface_draw_array(canvas->surface, (u32 *)indices, idx_size, (Float *)vertices, vx_size, nb_comp, prim_type);
1075 226 : if (e) return JS_EXCEPTION;
1076 :
1077 226 : return JS_UNDEFINED;
1078 : }
1079 :
1080 : static void text_update_path(GF_JSText *txt, Bool for_centered);
1081 :
1082 100 : static JSValue canvas3d_draw_path(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
1083 : {
1084 : GF_Err e = GF_OK;
1085 : Float z = 0;
1086 100 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
1087 100 : if (!canvas || argc<1) return JS_EXCEPTION;
1088 100 : if (argc>1) {
1089 0 : EVG_GET_FLOAT(z, argv[1]);
1090 : }
1091 :
1092 100 : GF_Path *gp = JS_GetOpaque(argv[0], path_class_id);
1093 100 : if (gp) {
1094 0 : e = gf_evg_surface_draw_path(canvas->surface, gp, z);
1095 : } else {
1096 100 : GF_JSText *text = JS_GetOpaque(argv[0], text_class_id);
1097 100 : if (text) {
1098 100 : text_update_path(text, GF_TRUE);
1099 100 : e = gf_evg_surface_draw_path(canvas->surface, text->path, z);
1100 : }
1101 : }
1102 100 : if (e) return js_throw_err(ctx, e);
1103 100 : return JS_UNDEFINED;
1104 : }
1105 226 : static JSValue canvas3d_clear_depth(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
1106 : {
1107 : GF_Err e;
1108 : Float depth = 1.0;
1109 226 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
1110 226 : if (!canvas) return JS_EXCEPTION;
1111 226 : if (argc)
1112 226 : EVG_GET_FLOAT(depth, argv[0]);
1113 :
1114 226 : e = gf_evg_surface_clear_depth(canvas->surface, depth);
1115 226 : if (e) return JS_EXCEPTION;
1116 226 : return JS_UNDEFINED;
1117 : }
1118 226 : static JSValue canvas3d_viewport(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
1119 : {
1120 : s32 x, y, w, h;
1121 : GF_Err e;
1122 226 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
1123 226 : if (!canvas) return JS_EXCEPTION;
1124 226 : if (argc) {
1125 226 : if (argc<4) return js_throw_err(ctx, GF_BAD_PARAM);
1126 226 : if (JS_ToInt32(ctx, &x, argv[0])) return js_throw_err(ctx, GF_BAD_PARAM);;
1127 226 : if (JS_ToInt32(ctx, &y, argv[1])) return js_throw_err(ctx, GF_BAD_PARAM);;
1128 226 : if (JS_ToInt32(ctx, &w, argv[2])) return js_throw_err(ctx, GF_BAD_PARAM);;
1129 226 : if (JS_ToInt32(ctx, &h, argv[3])) return js_throw_err(ctx, GF_BAD_PARAM);;
1130 : } else {
1131 0 : x = y = 0;
1132 0 : w = canvas->width;
1133 0 : h = canvas->height;
1134 : }
1135 226 : e = gf_evg_surface_viewport(canvas->surface, x, y, w, h);
1136 226 : if (e) return JS_EXCEPTION;
1137 226 : return JS_UNDEFINED;
1138 : }
1139 :
1140 :
1141 : enum
1142 : {
1143 : EVG_OP_IF=1,
1144 : EVG_OP_ELSE,
1145 : EVG_OP_ELSEIF,
1146 : EVG_OP_END,
1147 : EVG_OP_GOTO,
1148 : EVG_OP_ASSIGN,
1149 : EVG_OP_DISCARD,
1150 : EVG_OP_ADD,
1151 : EVG_OP_SUB,
1152 : EVG_OP_MUL,
1153 : EVG_OP_DIV,
1154 : EVG_OP_NEG,
1155 : EVG_OP_LESS,
1156 : EVG_OP_LESS_EQUAL,
1157 : EVG_OP_GREATER,
1158 : EVG_OP_GREATER_EQUAL,
1159 : EVG_OP_EQUAL,
1160 : EVG_OP_NOT_EQUAL,
1161 : EVG_OP_SAMPLER,
1162 : EVG_OP_SAMPLER_YUV,
1163 :
1164 : EVG_OP_PRINT,
1165 :
1166 : EVG_OP_NORMALIZE,
1167 : EVG_OP_LENGTH,
1168 : EVG_OP_DISTANCE,
1169 : EVG_OP_DOT,
1170 : EVG_OP_CROSS,
1171 : EVG_OP_POW,
1172 : EVG_OP_SIN,
1173 : EVG_OP_ASIN,
1174 : EVG_OP_COS,
1175 : EVG_OP_ACOS,
1176 : EVG_OP_TAN,
1177 : EVG_OP_ATAN,
1178 : EVG_OP_LOG,
1179 : EVG_OP_EXP,
1180 : EVG_OP_LOG2,
1181 : EVG_OP_EXP2,
1182 : EVG_OP_SINH,
1183 : EVG_OP_COSH,
1184 : EVG_OP_SQRT,
1185 : EVG_OP_INVERSE_SQRT,
1186 : EVG_OP_ABS,
1187 : EVG_OP_SIGN,
1188 : EVG_OP_FLOOR,
1189 : EVG_OP_CEIL,
1190 : EVG_OP_FRACT,
1191 : EVG_OP_MOD,
1192 : EVG_OP_MIN,
1193 : EVG_OP_MAX,
1194 : EVG_OP_CLAMP,
1195 : EVG_OP_RGB2YUV,
1196 : EVG_OP_YUV2RGB,
1197 :
1198 : EVG_FIRST_VAR_ID
1199 : };
1200 :
1201 : enum
1202 : {
1203 : VAR_FRAG_ARGB=1,
1204 : VAR_FRAG_YUV,
1205 : VAR_FRAG_X,
1206 : VAR_FRAG_Y,
1207 : VAR_FRAG_DEPTH,
1208 : VAR_FRAG_W,
1209 : VAR_UNIFORM,
1210 : VAR_VERTEX_IN,
1211 : VAR_VERTEX_OUT,
1212 : VAR_VAI,
1213 : VAR_VA,
1214 : VAR_MATRIX,
1215 : };
1216 :
1217 :
1218 : static GFINLINE Float isqrtf(Float v)
1219 : {
1220 10800 : v = sqrtf(v);
1221 10800 : if (v) v = 1 / v;
1222 : return v;
1223 : }
1224 : static GFINLINE Float signf(Float v)
1225 : {
1226 10800 : if (v==0) return 0;
1227 10800 : if (v>0) return 1.0;
1228 : return -1.0;
1229 : }
1230 : static GFINLINE Float fractf(Float v)
1231 : {
1232 10800 : return v - floorf(v);
1233 : }
1234 : static GFINLINE Float _modf(Float x, Float y)
1235 : {
1236 10800 : if (!y) return 0.0;
1237 10800 : return x - y * floorf(x/y);
1238 : }
1239 :
1240 :
1241 :
1242 : #if defined(WIN32) && !defined(__GNUC__)
1243 : # include <intrin.h>
1244 : # define GPAC_HAS_SSE2
1245 : #else
1246 : # ifdef __SSE2__
1247 : # include <emmintrin.h>
1248 : # define GPAC_HAS_SSE2
1249 : # endif
1250 : #endif
1251 :
1252 : #ifdef GPAC_HAS_SSE2
1253 :
1254 : static Float evg_float_clamp(Float val, Float minval, Float maxval)
1255 : {
1256 : _mm_store_ss( &val, _mm_min_ss( _mm_max_ss(_mm_set_ss(val),_mm_set_ss(minval)), _mm_set_ss(maxval) ) );
1257 : return val;
1258 : }
1259 : #else
1260 :
1261 : #define evg_float_clamp(_val, _minval, _maxval)\
1262 : (_val<_minval) ? _minval : (_val>_maxval) ? _maxval : _val;
1263 :
1264 : #endif
1265 :
1266 :
1267 : /*
1268 :
1269 : */
1270 :
1271 4817326 : static Bool evg_shader_ops(GF_JSCanvas *canvas, EVGShader *shader, GF_EVGFragmentParam *frag, GF_EVGVertexParam *vert)
1272 : {
1273 : u32 op_idx, dim;
1274 : GF_Vec4 tmpl, tmpr;
1275 : GF_Vec4 *left_val, *right_val, *right2_val;
1276 : u32 if_level=0;
1277 : u32 nif_level=0;
1278 : Bool cond_res;
1279 :
1280 : //assign to dummy values, this will prevent any badly formatted shader to assign a value to a NULL left-val or read a null right-val
1281 4817326 : tmpl.x = tmpl.y = tmpl.z = tmpl.q = 0;
1282 : left_val = &tmpl;
1283 4817326 : tmpr.x = tmpr.y = tmpr.z = tmpr.q = 0;
1284 : right_val = &tmpr;
1285 :
1286 83733378 : for (op_idx=0; op_idx<shader->nb_ops; op_idx++) {
1287 : u32 next_idx, idx, var_idx;
1288 : Bool has_next, norm_result=GF_FALSE;
1289 : u8 right_val_type, left_val_type=0;
1290 : u8 *left_val_type_ptr=NULL;
1291 83733378 : ShaderOp *op = &shader->ops[op_idx];
1292 :
1293 83733378 : if (op->op_type==EVG_OP_GOTO) {
1294 1204487 : u32 stack_idx = op->left_value;
1295 1204487 : if (op->uni_name) stack_idx = op->ival;
1296 :
1297 1204487 : if (!stack_idx || (stack_idx > shader->nb_ops)) {
1298 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Shader] Invalid goto operation, stack index %d not in stack indices [1, %d]\n", op->left_value, shader->nb_ops));
1299 0 : shader->invalid = GF_TRUE;
1300 : return GF_FALSE;
1301 : }
1302 1204487 : op_idx = stack_idx - 1;
1303 1204487 : op = &shader->ops[op_idx];
1304 : }
1305 :
1306 83733378 : if (op->op_type==EVG_OP_ELSE) {
1307 1204487 : if (nif_level) {
1308 395087 : if (nif_level==1) {
1309 : nif_level=0;
1310 395087 : if_level++;
1311 : }
1312 809400 : } else if (if_level) {
1313 809400 : if_level--;
1314 : nif_level++;
1315 : }
1316 1204487 : continue;
1317 : }
1318 82528891 : if (op->op_type==EVG_OP_END) {
1319 : assert(nif_level || if_level);
1320 4239973 : if (nif_level) nif_level--;
1321 3430573 : else if (if_level) if_level--;
1322 4239973 : continue;
1323 : }
1324 78288918 : if (nif_level) {
1325 1204487 : if (op->op_type==EVG_OP_IF) {
1326 0 : nif_level++;
1327 : }
1328 1204487 : continue;
1329 : }
1330 :
1331 : dim=4;
1332 77084431 : if (op->left_value==VAR_FRAG_ARGB) {
1333 4313043 : left_val = &frag->color;
1334 : left_val_type = COMP_V4;
1335 4313043 : frag->frag_valid = GF_EVG_FRAG_RGB;
1336 72771388 : } else if (op->left_value==VAR_FRAG_YUV) {
1337 1204487 : left_val = &frag->color;
1338 : left_val_type = COMP_V4;
1339 1204487 : frag->frag_valid = GF_EVG_FRAG_YUV;
1340 71566901 : } else if (op->left_value==VAR_FRAG_X) {
1341 : left_val = &tmpl;
1342 0 : tmpl.x = frag->screen_x;
1343 : left_val_type = COMP_FLOAT;
1344 71566901 : } else if (op->left_value==VAR_FRAG_Y) {
1345 : left_val = &tmpl;
1346 0 : tmpl.x = frag->screen_y;
1347 : left_val_type = COMP_FLOAT;
1348 71566901 : } else if (op->left_value==VAR_FRAG_W) {
1349 : left_val = &tmpl;
1350 0 : tmpl.x = frag->persp_denum;
1351 : left_val_type = COMP_FLOAT;
1352 71566901 : } else if (op->left_value==VAR_FRAG_DEPTH) {
1353 0 : left_val = (GF_Vec4 *) &frag->depth;
1354 : left_val_type = COMP_FLOAT;
1355 71566901 : } else if (op->left_value==VAR_VERTEX_IN) {
1356 4500 : left_val = (GF_Vec4 *) &vert->in_vertex;
1357 : left_val_type = COMP_V4;
1358 71562401 : } else if (op->left_value==VAR_VERTEX_OUT) {
1359 4500 : left_val = (GF_Vec4 *) &vert->out_vertex;
1360 : left_val_type = COMP_V4;
1361 71557901 : } else if (op->left_value==VAR_VAI) {
1362 7200 : left_val = (GF_Vec4 *) &op->vai.vai->anchors[vert->vertex_idx_in_prim];
1363 : left_val_type = COMP_V4;
1364 7200 : norm_result = op->vai.vai->normalize;
1365 71550701 : } else if (op->left_value) {
1366 71550701 : u32 l_var_idx = op->left_value - EVG_FIRST_VAR_ID-1;
1367 71550701 : left_val = &shader->vars[l_var_idx].vecval;
1368 71550701 : left_val_type = shader->vars[l_var_idx].value_type;
1369 71550701 : left_val_type_ptr = & shader->vars[l_var_idx].value_type;
1370 : }
1371 :
1372 77084431 : if (op->right_value>EVG_FIRST_VAR_ID) {
1373 31904375 : var_idx = op->right_value - EVG_FIRST_VAR_ID-1;
1374 31904375 : right_val = &shader->vars[var_idx].vecval;
1375 31904375 : right_val_type = shader->vars[var_idx].value_type;
1376 45180056 : } else if ((op->right_value==VAR_VAI) && op->vai.vai) {
1377 7275459 : vai_call_lerp(op->vai.vai, frag);
1378 7275459 : dim = MIN(4, op->vai.vai->result.dim);
1379 7275459 : right_val = (GF_Vec4 *) &op->vai.vai->result.values[0];
1380 7275459 : right_val_type = op->vai.vai->result.comp_type;
1381 37904597 : } else if ((op->right_value==VAR_VA) && op->va.va) {
1382 : u32 va_idx, j, nb_v_per_prim=3;
1383 : EVG_VA *va = op->va.va;
1384 :
1385 3600 : if (vert->ptype == GF_EVG_LINES)
1386 : nb_v_per_prim=2;
1387 3600 : else if (vert->ptype == GF_EVG_POINTS)
1388 : nb_v_per_prim=1;
1389 :
1390 3600 : if (va->interp_type==GF_EVG_VAI_PRIMITIVE) {
1391 3600 : va_idx = vert->prim_index * va->nb_comp;
1392 : }
1393 0 : else if (va->interp_type==GF_EVG_VAI_VERTEX_INDEX) {
1394 0 : va_idx = vert->vertex_idx * va->nb_comp;
1395 : } else {
1396 0 : va_idx = vert->prim_index * nb_v_per_prim * va->nb_comp;
1397 : }
1398 :
1399 3600 : if (va_idx+va->nb_comp > va->nb_values)
1400 : return GF_FALSE;
1401 :
1402 : right_val = &tmpr;
1403 3600 : right_val->x = right_val->y = right_val->z = right_val->q = 0;
1404 : assert(va->nb_comp<=4);
1405 10800 : for (j=0; j<va->nb_comp; j++) {
1406 10800 : ((Float *)right_val)[j] = va->values[va_idx+j];
1407 : }
1408 3600 : if (va->normalize) {
1409 3600 : if (va->nb_comp==2) {
1410 : Float len;
1411 0 : if (!right_val->x) len = ABS(right_val->y);
1412 0 : else if (!right_val->y) len = ABS(right_val->x);
1413 0 : else len = sqrtf(right_val->x*right_val->x + right_val->y*right_val->y);
1414 0 : if (len) {
1415 0 : right_val->x/=len;
1416 0 : right_val->y/=len;
1417 : }
1418 : } else {
1419 3600 : gf_vec_norm((GF_Vec *) right_val);
1420 : }
1421 :
1422 : }
1423 3600 : right_val_type = va->att_type;
1424 37900997 : } else if ((op->right_value==VAR_MATRIX) && op->mx.mx) {
1425 8100 : if (op->op_type==EVG_OP_MUL) {
1426 8100 : gf_mx_apply_vec_4x4(op->mx.mx, left_val);
1427 8100 : continue;
1428 : }
1429 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Shader] Invalid operation for right value matrix\n"));
1430 0 : shader->invalid = GF_TRUE;
1431 : return GF_FALSE;
1432 37892897 : } else if (op->right_value==VAR_FRAG_ARGB) {
1433 0 : right_val = &frag->color;
1434 : right_val_type = COMP_V4;
1435 37892897 : } else if (op->right_value==VAR_FRAG_YUV) {
1436 0 : right_val = &frag->color;
1437 : right_val_type = COMP_V4;
1438 37892897 : } else if (op->right_value==VAR_FRAG_X) {
1439 : right_val = &tmpr;
1440 352352 : tmpr.x = frag->screen_x;
1441 : right_val_type = COMP_FLOAT;
1442 37540545 : } else if (op->right_value==VAR_FRAG_Y) {
1443 : right_val = &tmpr;
1444 0 : tmpr.x = frag->screen_y;
1445 : right_val_type = COMP_FLOAT;
1446 37540545 : } else if (op->right_value==VAR_FRAG_W) {
1447 : right_val = &tmpr;
1448 0 : tmpr.x = frag->persp_denum;
1449 : right_val_type = COMP_FLOAT;
1450 37540545 : } else if (op->right_value==VAR_FRAG_DEPTH) {
1451 : right_val = &tmpr;
1452 0 : tmpr.x = frag->depth;
1453 : right_val_type = COMP_FLOAT;
1454 37540545 : } else if (op->right_value==VAR_VERTEX_IN) {
1455 8100 : right_val = &vert->in_vertex;
1456 : right_val_type = COMP_V4;
1457 37532445 : } else if (op->right_value==VAR_VERTEX_OUT) {
1458 0 : right_val = &vert->out_vertex;
1459 : right_val_type = COMP_V4;
1460 37532445 : } else if (!op->right_value || (op->right_value==VAR_UNIFORM) ) {
1461 37532445 : right_val = (GF_Vec4 *) &op->vec[0];
1462 37532445 : right_val_type = op->right_value_type;
1463 : } else {
1464 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Shader] Invalid right-value in operation %d\n", op_idx));
1465 0 : shader->invalid = GF_TRUE;
1466 : return GF_FALSE;
1467 : }
1468 77076331 : if (!right_val_type) {
1469 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_PARSER, ("[Shader] Invalid right-value type in operation %d\n", op_idx));
1470 0 : shader->invalid = GF_TRUE;
1471 : return GF_FALSE;
1472 : }
1473 :
1474 : #define GET_FIRST_COMP\
1475 : idx=0;\
1476 : while (1) {\
1477 : if (op->right_value_type & (1<<idx))\
1478 : break;\
1479 : if (idx==3)\
1480 : break;\
1481 : idx++;\
1482 : }\
1483 :
1484 : #define GET_NEXT_COMP\
1485 : has_next = GF_FALSE;\
1486 : next_idx = idx;\
1487 : while (1) {\
1488 : if (next_idx==3)\
1489 : break;\
1490 : if (op->right_value_type & (1<< (next_idx+1)) ) {\
1491 : has_next = GF_TRUE;\
1492 : next_idx = idx+1;\
1493 : break;\
1494 : }\
1495 : next_idx++;\
1496 : }\
1497 : if (has_next) idx = next_idx;\
1498 :
1499 77076331 : switch (op->op_type) {
1500 29987160 : case EVG_OP_ASSIGN:
1501 : //full assignment
1502 29987160 : if (op->left_value_type==COMP_V4) {
1503 24864717 : if (left_val_type_ptr) {
1504 20392543 : left_val_type = *left_val_type_ptr = right_val_type;
1505 : }
1506 :
1507 24864717 : if (right_val_type==COMP_BOOL) {
1508 0 : if (left_val_type_ptr) {
1509 0 : *((Bool *) left_val) = *((Bool *) right_val) ? GF_TRUE : GF_FALSE;
1510 : } else {
1511 0 : left_val->x = (Float) ( *(Bool *) right_val ? 1.0 : 0.0 );
1512 0 : left_val->y = left_val->z = left_val->q = left_val->x;
1513 : }
1514 24864717 : } else if (right_val_type==COMP_INT) {
1515 3035486 : if (left_val_type_ptr || (left_val_type==COMP_INT)) {
1516 3035486 : *((s32 *) left_val) = *(s32 *) right_val;
1517 : } else {
1518 0 : left_val->x = (Float) *(s32 *) right_val;
1519 0 : left_val->y = left_val->z = left_val->q = left_val->x;
1520 : }
1521 21829231 : } else if (right_val_type==COMP_FLOAT) {
1522 352352 : if (left_val_type_ptr) {
1523 352352 : *((Float *) left_val) = *(Float *) right_val;
1524 : } else {
1525 0 : left_val->x = *(Float *) right_val;
1526 0 : left_val->y = left_val->z = left_val->q = left_val->x;
1527 : }
1528 21476879 : } else if ((right_val_type==COMP_V4) || (op->right_value_type==COMP_V4)) {
1529 21473279 : *left_val = *right_val;
1530 21473279 : if (dim<4) left_val->q = 1.0;
1531 : } else {
1532 3600 : Float *srcs = (Float *) &right_val->x;
1533 :
1534 3600 : GET_FIRST_COMP
1535 3600 : if (left_val_type & COMP_X) { left_val->x = srcs[idx]; GET_NEXT_COMP }
1536 3600 : if (left_val_type & COMP_Y) { left_val->y = srcs[idx]; GET_NEXT_COMP }
1537 3600 : if (left_val_type & COMP_Z) { left_val->z = srcs[idx]; GET_NEXT_COMP }
1538 3600 : if (dim<4) left_val->q = 1.0;
1539 3600 : else if (left_val_type & COMP_Q) { left_val->q = srcs[idx]; }
1540 : }
1541 : }
1542 : //partial assignment, only valid for float sources
1543 : else {
1544 : Bool use_const = GF_FALSE;
1545 : Float cval;
1546 5122443 : if (right_val_type==COMP_FLOAT) {
1547 : use_const = GF_TRUE;
1548 352352 : cval = right_val->x;
1549 4770091 : } else if (right_val_type==COMP_INT) {
1550 : use_const = GF_TRUE;
1551 1734605 : cval = (Float) ( *(s32*)right_val);
1552 : }
1553 : if (use_const) {
1554 2086957 : if (op->left_value_type & COMP_X) left_val->x = cval;
1555 2086957 : if (op->left_value_type & COMP_Y) left_val->y = cval;
1556 2086957 : if (op->left_value_type & COMP_Z) left_val->z = cval;
1557 2086957 : if (op->left_value_type & COMP_Q) left_val->q = cval;
1558 : } else {
1559 3035486 : Float *srcs = (Float *) &right_val->x;
1560 :
1561 3035486 : GET_FIRST_COMP
1562 3035486 : if (op->left_value_type & COMP_X) { left_val->x = srcs[idx]; GET_NEXT_COMP }
1563 3035486 : if (op->left_value_type & COMP_Y) { left_val->y = srcs[idx]; GET_NEXT_COMP }
1564 3035486 : if (op->left_value_type & COMP_Z) { left_val->z = srcs[idx]; GET_NEXT_COMP }
1565 3035486 : if (op->left_value_type & COMP_Q) { left_val->q = srcs[idx]; }
1566 : }
1567 : }
1568 29987160 : if (norm_result)
1569 3600 : gf_vec_norm((GF_Vec *)left_val);
1570 : break;
1571 :
1572 : #define BASE_OP(_opv, _opv2)\
1573 : if (op->left_value_type==COMP_V4) {\
1574 : if (right_val_type==COMP_INT) {\
1575 : if (left_val_type == COMP_INT) {\
1576 : *((s32 *) left_val) _opv *(s32 *) right_val;\
1577 : } else if (left_val_type == COMP_FLOAT) {\
1578 : left_val->x _opv *(s32 *) right_val;\
1579 : } else {\
1580 : left_val->x _opv *(s32 *) right_val;\
1581 : left_val->y _opv *(s32 *) right_val;\
1582 : left_val->z _opv *(s32 *) right_val;\
1583 : left_val->q _opv *(s32 *) right_val;\
1584 : }\
1585 : } else if (right_val_type==COMP_FLOAT) {\
1586 : if (left_val_type == COMP_INT) {\
1587 : left_val->x = *((s32 *) left_val) _opv2 right_val->x;\
1588 : *left_val_type_ptr = COMP_FLOAT;\
1589 : } else if (left_val_type == COMP_FLOAT) {\
1590 : left_val->x _opv right_val->x;\
1591 : } else {\
1592 : left_val->x _opv right_val->x;\
1593 : left_val->y _opv right_val->x;\
1594 : left_val->z _opv right_val->x;\
1595 : left_val->q _opv right_val->x;\
1596 : }\
1597 : } else if (right_val_type==COMP_BOOL) {\
1598 : } else {\
1599 : Float *srcs = (Float *) &right_val->x;\
1600 : GET_FIRST_COMP\
1601 : if (left_val_type & COMP_X) { left_val->x _opv srcs[idx]; GET_NEXT_COMP } \
1602 : if (left_val_type & COMP_Y) { left_val->y _opv srcs[idx]; GET_NEXT_COMP } \
1603 : if (left_val_type & COMP_Z) { left_val->z _opv srcs[idx]; GET_NEXT_COMP } \
1604 : if (left_val_type & COMP_Q) { left_val->q _opv srcs[idx]; }\
1605 : }\
1606 : }\
1607 : else {\
1608 : Bool use_const = GF_FALSE;\
1609 : Float cval;\
1610 : if (right_val_type==COMP_FLOAT) {\
1611 : use_const = GF_TRUE;\
1612 : cval = right_val->x;\
1613 : } else if (right_val_type==COMP_INT) {\
1614 : use_const = GF_TRUE;\
1615 : cval = (Float) ( *(s32*)right_val);\
1616 : }\
1617 : if (use_const) {\
1618 : if (op->left_value_type & COMP_X) left_val->x _opv cval;\
1619 : if (op->left_value_type & COMP_Y) left_val->y _opv cval;\
1620 : if (op->left_value_type & COMP_Z) left_val->z _opv cval;\
1621 : if (op->left_value_type & COMP_Q) left_val->q _opv cval;\
1622 : } else {\
1623 : Float *srcs = (Float *) &right_val->x;\
1624 : GET_FIRST_COMP\
1625 : if (op->left_value_type & COMP_X) { left_val->x _opv srcs[idx]; GET_NEXT_COMP }\
1626 : if (op->left_value_type & COMP_Y) { left_val->y _opv srcs[idx]; GET_NEXT_COMP }\
1627 : if (op->left_value_type & COMP_Z) { left_val->z _opv srcs[idx]; GET_NEXT_COMP }\
1628 : if (op->left_value_type & COMP_Q) left_val->q _opv srcs[idx];\
1629 : }\
1630 : }\
1631 :
1632 12754098 : case EVG_OP_MUL:
1633 12754098 : BASE_OP(*=, *)
1634 : break;
1635 352352 : case EVG_OP_DIV:
1636 352352 : BASE_OP(/=, /)
1637 : break;
1638 9106458 : case EVG_OP_ADD:
1639 9106458 : BASE_OP(+=, +)
1640 : break;
1641 0 : case EVG_OP_SUB:
1642 0 : BASE_OP(-=, -)
1643 : break;
1644 0 : case EVG_OP_NEG:
1645 0 : BASE_OP(= !, *)
1646 : break;
1647 4239973 : case EVG_OP_IF:
1648 : #define BASE_COND(_opv)\
1649 : cond_res=GF_FALSE;\
1650 : if (op->left_value_type==COMP_V4) {\
1651 : if ((right_val_type==COMP_INT) || (right_val_type==COMP_BOOL)) {\
1652 : if (left_val_type == COMP_INT) {\
1653 : cond_res = ( *((s32 *) left_val) _opv *(s32 *) right_val) ? GF_TRUE : GF_FALSE;\
1654 : } else if (left_val_type == COMP_FLOAT) {\
1655 : cond_res = (left_val->x _opv *(s32 *) right_val) ? GF_TRUE : GF_FALSE;\
1656 : } else {\
1657 : cond_res = ( (left_val->x _opv *(s32 *) right_val) && \
1658 : (left_val->y _opv *(s32 *) right_val) && \
1659 : (left_val->z _opv *(s32 *) right_val) && \
1660 : (left_val->q _opv *(s32 *) right_val) ) ? GF_TRUE : GF_FALSE;\
1661 : }\
1662 : } else if (right_val_type==COMP_FLOAT) {\
1663 : if (left_val_type == COMP_INT) {\
1664 : cond_res = ( *((s32 *) left_val) _opv right_val->x) ? GF_TRUE : GF_FALSE;\
1665 : } else if (left_val_type == COMP_FLOAT) {\
1666 : cond_res = (left_val->x _opv right_val->x) ? GF_TRUE : GF_FALSE;\
1667 : } else {\
1668 : cond_res = ( (left_val->x _opv right_val->x) &&\
1669 : (left_val->y _opv right_val->x) &&\
1670 : (left_val->z _opv right_val->x) && \
1671 : (left_val->q _opv right_val->x) ) ? GF_TRUE : GF_FALSE;\
1672 : }\
1673 : } else {\
1674 : cond_res=GF_TRUE;\
1675 : Float *srcs = (Float *) &right_val->x;\
1676 : GET_FIRST_COMP\
1677 : if (left_val_type & COMP_X) { if (! (left_val->x _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \
1678 : if (left_val_type & COMP_Y) { if (! (left_val->y _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \
1679 : if (left_val_type & COMP_Z) { if (! (left_val->z _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \
1680 : if (left_val_type & COMP_Q) { if (! (left_val->q _opv srcs[idx]) ) cond_res = GF_FALSE; }\
1681 : }\
1682 : }\
1683 : else {\
1684 : Bool use_const = GF_FALSE;\
1685 : Float cval;\
1686 : if (right_val_type==COMP_FLOAT) {\
1687 : use_const = GF_TRUE;\
1688 : cval = right_val->x;\
1689 : } else if (right_val_type==COMP_INT) {\
1690 : use_const = GF_TRUE;\
1691 : cval = (Float) ( *(s32*)right_val);\
1692 : }\
1693 : if (use_const) {\
1694 : cond_res=GF_TRUE;\
1695 : if (op->left_value_type & COMP_X) if (! (left_val->x _opv cval) ) cond_res=GF_FALSE;\
1696 : if (op->left_value_type & COMP_Y) if (! (left_val->y _opv cval) ) cond_res=GF_FALSE;\
1697 : if (op->left_value_type & COMP_Z) if (! (left_val->z _opv cval) ) cond_res=GF_FALSE;\
1698 : if (op->left_value_type & COMP_Q) if (! (left_val->q _opv cval) ) cond_res=GF_FALSE;\
1699 : } else {\
1700 : Float *srcs = (Float *) &right_val->x;\
1701 : GET_FIRST_COMP\
1702 : if (op->left_value_type & COMP_X) { if (! (left_val->x _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\
1703 : if (op->left_value_type & COMP_Y) { if (! (left_val->y _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\
1704 : if (op->left_value_type & COMP_Z) { if (! (left_val->z _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\
1705 : if (op->left_value_type & COMP_Q) { if (! (left_val->q _opv srcs[idx]) ) cond_res=GF_FALSE; }\
1706 : }\
1707 : }
1708 :
1709 4239973 : if (op->cond_type==EVG_OP_LESS) { BASE_COND(<) }
1710 3035486 : else if (op->cond_type==EVG_OP_LESS_EQUAL) { BASE_COND(<=) }
1711 3035486 : else if (op->cond_type==EVG_OP_GREATER) { BASE_COND(>) }
1712 0 : else if (op->cond_type==EVG_OP_GREATER_EQUAL) { BASE_COND(>=) }
1713 0 : else if (op->cond_type==EVG_OP_EQUAL) { BASE_COND(==) }
1714 0 : else if (op->cond_type==EVG_OP_NOT_EQUAL) { BASE_COND(!=) }
1715 : else break;
1716 :
1717 4239973 : if (cond_res) if_level++;
1718 : else nif_level++;
1719 :
1720 : break;
1721 :
1722 1204487 : case EVG_OP_SAMPLER:
1723 1204487 : if (left_val_type_ptr) {
1724 1204487 : *left_val_type_ptr = COMP_V4;
1725 : }
1726 1204487 : if (op->left_value_type==COMP_V4) {
1727 1204487 : gf_evg_stencil_get_pixel_f(op->tx->stencil, right_val->x, right_val->y, &left_val->x, &left_val->y, &left_val->z, &left_val->q);
1728 : } else {
1729 0 : gf_evg_stencil_get_pixel_f(op->tx->stencil, right_val->x, right_val->y, &tmpr.x, &tmpr.y, &tmpr.z, &tmpr.q);
1730 0 : if (op->left_value_type & COMP_X) left_val->x = tmpr.x;
1731 0 : if (op->left_value_type & COMP_Y) left_val->y = tmpr.y;
1732 0 : if (op->left_value_type & COMP_Z) left_val->z = tmpr.z;
1733 0 : if (op->left_value_type & COMP_Q) left_val->q = tmpr.q;
1734 : }
1735 : break;
1736 :
1737 1204487 : case EVG_OP_SAMPLER_YUV:
1738 1204487 : if (left_val_type_ptr) {
1739 1204487 : *left_val_type_ptr = COMP_V4;
1740 : }
1741 1204487 : if (op->left_value_type==COMP_V4) {
1742 1204487 : gf_evg_stencil_get_pixel_yuv_f(op->tx->stencil, right_val->x, right_val->y, &left_val->x, &left_val->y, &left_val->z, &left_val->q);
1743 : } else {
1744 0 : gf_evg_stencil_get_pixel_yuv_f(op->tx->stencil, right_val->x, right_val->y, &tmpr.x, &tmpr.y, &tmpr.z, &tmpr.q);
1745 0 : if (op->left_value_type & COMP_X) left_val->x = tmpr.x;
1746 0 : if (op->left_value_type & COMP_Y) left_val->y = tmpr.y;
1747 0 : if (op->left_value_type & COMP_Z) left_val->z = tmpr.z;
1748 0 : if (op->left_value_type & COMP_Q) left_val->q = tmpr.q;
1749 : }
1750 : break;
1751 0 : case EVG_OP_DISCARD:
1752 0 : frag->frag_valid = 0;
1753 : return GF_TRUE;
1754 6070972 : case EVG_OP_NORMALIZE:
1755 6070972 : if (left_val_type_ptr) {
1756 6070972 : *left_val_type_ptr = COMP_V4;
1757 : }
1758 6070972 : *left_val = *right_val;
1759 6070972 : gf_vec_norm((GF_Vec *)left_val);
1760 : break;
1761 0 : case EVG_OP_LENGTH:
1762 0 : if (left_val_type_ptr) {
1763 0 : *left_val_type_ptr = COMP_FLOAT;
1764 : }
1765 0 : left_val->x = gf_vec_len_p( (GF_Vec *) right_val);
1766 : break;
1767 0 : case EVG_OP_DISTANCE:
1768 0 : if (left_val_type_ptr) {
1769 0 : *left_val_type_ptr = COMP_FLOAT;
1770 : }
1771 0 : right2_val = &shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval;
1772 : //right2_val_type = shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type;
1773 0 : gf_vec_diff(tmpr, *right_val, *right2_val);
1774 0 : left_val->x = gf_vec_len_p( (GF_Vec *) &tmpr);
1775 : break;
1776 :
1777 6070972 : case EVG_OP_DOT:
1778 6070972 : if (left_val_type_ptr) {
1779 6070972 : *left_val_type_ptr = COMP_FLOAT;
1780 : }
1781 6070972 : right2_val = &shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval;
1782 : //right2_val_type = shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type;
1783 6070972 : left_val->x = gf_vec_dot_p( (GF_Vec *) right_val, (GF_Vec *) right2_val);
1784 : break;
1785 0 : case EVG_OP_CROSS:
1786 0 : if (left_val_type_ptr) {
1787 0 : *left_val_type_ptr = COMP_V4;
1788 : }
1789 0 : right2_val = &shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval;
1790 : //right2_val_type = shader->vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type;
1791 0 : * (GF_Vec *) left_val = gf_vec_cross_p( (GF_Vec *) right_val, (GF_Vec *) right2_val);
1792 : break;
1793 :
1794 : #define BASE_FUN2(__fun) \
1795 : if (left_val_type_ptr) {\
1796 : *left_val_type_ptr = right_val_type;\
1797 : }\
1798 : var_idx = op->right_value_second - EVG_FIRST_VAR_ID-1;\
1799 : right2_val = &shader->vars[var_idx].vecval;\
1800 : if (right_val_type==COMP_FLOAT) {\
1801 : left_val->x = __fun(right_val->x, right2_val->x);\
1802 : } else {\
1803 : if (right_val_type&COMP_X) {\
1804 : left_val->x = __fun(right_val->x, right2_val->x);\
1805 : }\
1806 : if (right_val_type&COMP_Y) {\
1807 : left_val->y = __fun(right_val->y, right2_val->y);\
1808 : }\
1809 : if (right_val_type&COMP_Z) {\
1810 : left_val->z = __fun(right_val->z, right2_val->z);\
1811 : }\
1812 : if (right_val_type&COMP_Q) {\
1813 : left_val->q = __fun(right_val->z, right2_val->q);\
1814 : }\
1815 : }\
1816 :
1817 :
1818 : #define BASE_FUN(__fun) \
1819 : if (left_val_type_ptr) {\
1820 : *left_val_type_ptr = right_val_type;\
1821 : }\
1822 : if (right_val_type==COMP_FLOAT) {\
1823 : left_val->x = (Float) __fun(right_val->x);\
1824 : } else {\
1825 : if (right_val_type&COMP_X) {\
1826 : left_val->x = (Float) __fun(right_val->x);\
1827 : }\
1828 : if (right_val_type&COMP_Y) {\
1829 : left_val->y = (Float) __fun(right_val->y);\
1830 : }\
1831 : if (right_val_type&COMP_Z) {\
1832 : left_val->z = (Float) __fun(right_val->z);\
1833 : }\
1834 : if (right_val_type&COMP_Q) {\
1835 : left_val->q = (Float) __fun(right_val->z);\
1836 : }\
1837 : }\
1838 :
1839 3035486 : case EVG_OP_POW:
1840 3035486 : BASE_FUN2(powf)
1841 : break;
1842 0 : case EVG_OP_SIN:
1843 0 : BASE_FUN(sinf)
1844 : break;
1845 0 : case EVG_OP_ASIN:
1846 0 : BASE_FUN(asinf)
1847 : break;
1848 0 : case EVG_OP_COS:
1849 0 : BASE_FUN(cosf)
1850 : break;
1851 0 : case EVG_OP_ACOS:
1852 0 : BASE_FUN(acosf)
1853 : break;
1854 0 : case EVG_OP_TAN:
1855 0 : BASE_FUN(tanf)
1856 : break;
1857 0 : case EVG_OP_ATAN:
1858 0 : BASE_FUN2(atan2f)
1859 : break;
1860 0 : case EVG_OP_LOG:
1861 0 : BASE_FUN(logf)
1862 : break;
1863 0 : case EVG_OP_EXP:
1864 0 : BASE_FUN(expf)
1865 : break;
1866 0 : case EVG_OP_LOG2:
1867 0 : BASE_FUN(log2f)
1868 : break;
1869 0 : case EVG_OP_EXP2:
1870 0 : BASE_FUN(exp2f)
1871 : break;
1872 0 : case EVG_OP_SINH:
1873 0 : BASE_FUN(sinhf)
1874 : break;
1875 0 : case EVG_OP_COSH:
1876 0 : BASE_FUN(coshf)
1877 : break;
1878 0 : case EVG_OP_SQRT:
1879 0 : BASE_FUN(sqrtf)
1880 : break;
1881 3600 : case EVG_OP_INVERSE_SQRT:
1882 14400 : BASE_FUN(isqrtf)
1883 : break;
1884 0 : case EVG_OP_ABS:
1885 0 : BASE_FUN(ABS)
1886 : break;
1887 3600 : case EVG_OP_SIGN:
1888 14400 : BASE_FUN(signf)
1889 : break;
1890 0 : case EVG_OP_FLOOR:
1891 0 : BASE_FUN(floorf)
1892 : break;
1893 0 : case EVG_OP_CEIL:
1894 0 : BASE_FUN(ceilf)
1895 : break;
1896 3600 : case EVG_OP_FRACT:
1897 14400 : BASE_FUN(fractf)
1898 : break;
1899 3600 : case EVG_OP_MOD:
1900 14400 : BASE_FUN2(_modf)
1901 : break;
1902 0 : case EVG_OP_MIN:
1903 0 : BASE_FUN2(MIN)
1904 : break;
1905 0 : case EVG_OP_MAX:
1906 0 : BASE_FUN2(MAX)
1907 : break;
1908 3035486 : case EVG_OP_CLAMP:
1909 3035486 : if (left_val_type_ptr) {
1910 3035486 : *left_val_type_ptr = right_val_type;
1911 : }
1912 3035486 : var_idx = op->right_value_second - EVG_FIRST_VAR_ID-1;
1913 3035486 : right2_val = &shader->vars[var_idx].vecval;
1914 : //right2_val_type = shader->vars[var_idx].value_type;
1915 3035486 : if (right_val_type==COMP_FLOAT) {
1916 0 : left_val->x = evg_float_clamp(left_val->x, right_val->x, right2_val->x);
1917 : } else {
1918 3035486 : if (right_val_type&COMP_X) {
1919 6070972 : left_val->x = evg_float_clamp(left_val->x, right_val->x, right2_val->x);
1920 : }
1921 3035486 : if (right_val_type&COMP_Y) {
1922 6070972 : left_val->y = evg_float_clamp(left_val->y, right_val->y, right2_val->x);
1923 : }
1924 3035486 : if (right_val_type&COMP_Z) {
1925 6070972 : left_val->z = evg_float_clamp(left_val->z, right_val->z, right2_val->x);
1926 : }
1927 3035486 : if (right_val_type&COMP_Q) {
1928 6070972 : left_val->q = evg_float_clamp(left_val->q, right_val->z, right2_val->x);
1929 : }
1930 : }
1931 : break;
1932 0 : case EVG_OP_RGB2YUV:
1933 0 : if (left_val_type_ptr) {
1934 0 : *left_val_type_ptr = right_val_type;
1935 : }
1936 0 : left_val->q = right_val->q;
1937 0 : gf_gf_evg_rgb_to_yuv_f(canvas->surface, right_val->x, right_val->y, right_val->z, &left_val->x, &left_val->y, &left_val->z);
1938 : break;
1939 0 : case EVG_OP_YUV2RGB:
1940 0 : if (left_val_type_ptr) {
1941 0 : *left_val_type_ptr = right_val_type;
1942 : }
1943 0 : left_val->q = right_val->q;
1944 0 : gf_evg_yuv_to_rgb_f(canvas->surface, right_val->x, right_val->y, right_val->z, &left_val->x, &left_val->y, &left_val->z);
1945 : break;
1946 :
1947 0 : case EVG_OP_PRINT:
1948 0 : if (op->right_value>EVG_FIRST_VAR_ID) {
1949 0 : fprintf(stderr, "%s: ", shader->vars[op->right_value - EVG_FIRST_VAR_ID - 1].name);
1950 : }
1951 0 : if (right_val_type==COMP_FLOAT) {
1952 0 : fprintf(stderr, "%g\n", right_val->x);
1953 0 : } else if (right_val_type==COMP_INT) {
1954 0 : fprintf(stderr, "%d\n", * (s32 *) &right_val);
1955 : } else {
1956 0 : if (right_val_type&COMP_X) fprintf(stderr, "x=%g ", right_val->x);
1957 0 : if (right_val_type&COMP_Y) fprintf(stderr, "y=%g ", right_val->y);
1958 0 : if (right_val_type&COMP_Z) fprintf(stderr, "z=%g ", right_val->z);
1959 0 : if (right_val_type&COMP_Q) fprintf(stderr, "q=%g ", right_val->q);
1960 0 : fprintf(stderr, "\n");
1961 : }
1962 :
1963 : break;
1964 : }
1965 : }
1966 : return GF_TRUE;
1967 : }
1968 :
1969 4812826 : static Bool evg_frag_shader_ops(void *udta, GF_EVGFragmentParam *frag)
1970 : {
1971 : GF_JSCanvas *canvas = (GF_JSCanvas *)udta;
1972 4812826 : if (!canvas->frag || canvas->frag->invalid) return GF_FALSE;
1973 4812826 : return evg_shader_ops(canvas, canvas->frag, frag, NULL);
1974 : }
1975 4500 : static Bool evg_vert_shader_ops(void *udta, GF_EVGVertexParam *vert)
1976 : {
1977 : GF_JSCanvas *canvas = (GF_JSCanvas *)udta;
1978 4500 : if (!canvas->vert || canvas->vert->invalid) return GF_FALSE;
1979 4500 : return evg_shader_ops(canvas, canvas->vert, NULL, vert);
1980 : }
1981 :
1982 36 : static void shader_reset(JSRuntime *rt, EVGShader *shader)
1983 : {
1984 : u32 i;
1985 166 : for (i=0; i<shader->nb_ops; i++) {
1986 130 : if (shader->ops[i].right_value==VAR_VAI) {
1987 : JS_FreeValueRT(rt, shader->ops[i].vai.ref);
1988 : }
1989 127 : else if (shader->ops[i].right_value==VAR_MATRIX) {
1990 : JS_FreeValueRT(rt, shader->ops[i].mx.ref);
1991 : }
1992 109 : else if (shader->ops[i].right_value==VAR_VA) {
1993 : JS_FreeValueRT(rt, shader->ops[i].va.ref);
1994 : }
1995 108 : else if (shader->ops[i].left_value==VAR_VAI) {
1996 : JS_FreeValueRT(rt, shader->ops[i].vai.ref);
1997 : }
1998 106 : else if (shader->ops[i].left_value==VAR_MATRIX) {
1999 : JS_FreeValueRT(rt, shader->ops[i].mx.ref);
2000 : }
2001 :
2002 130 : if (shader->ops[i].uni_name) {
2003 25 : gf_free(shader->ops[i].uni_name);
2004 25 : shader->ops[i].uni_name = NULL;
2005 : }
2006 130 : if (shader->ops[i].op_type==EVG_OP_SAMPLER) {
2007 : JS_FreeValueRT(rt, shader->ops[i].tx_ref);
2008 1 : shader->ops[i].tx_ref = JS_UNDEFINED;
2009 : }
2010 130 : shader->ops[i].right_value = 0;
2011 : }
2012 36 : shader->nb_ops = 0;
2013 69 : for (i=0; i<shader->nb_vars; i++) {
2014 33 : if (shader->vars[i].name) gf_free(shader->vars[i].name);
2015 33 : shader->vars[i].name = NULL;
2016 : }
2017 36 : shader->nb_vars = 0;
2018 36 : shader->invalid = GF_FALSE;
2019 36 : shader->disable_early_z = GF_FALSE;
2020 36 : }
2021 36 : static void shader_finalize(JSRuntime *rt, JSValue obj)
2022 : {
2023 36 : EVGShader *shader = JS_GetOpaque(obj, shader_class_id);
2024 36 : if (!shader) return;
2025 36 : shader_reset(rt, shader);
2026 36 : gf_free(shader->ops);
2027 36 : gf_free(shader->vars);
2028 36 : gf_free(shader);
2029 : }
2030 :
2031 136 : static void shader_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
2032 : {
2033 : u32 i;
2034 136 : EVGShader *shader = JS_GetOpaque(obj, shader_class_id);
2035 136 : if (!shader) return;
2036 384 : for (i=0; i<shader->nb_ops; i++) {
2037 384 : if (shader->ops[i].tx)
2038 8 : JS_MarkValue(rt, shader->ops[i].tx_ref, mark_func);
2039 :
2040 384 : if (shader->ops[i].right_value==VAR_VAI) {
2041 4 : JS_MarkValue(rt, shader->ops[i].vai.ref, mark_func);
2042 : }
2043 380 : else if (shader->ops[i].right_value==VAR_MATRIX) {
2044 64 : JS_MarkValue(rt, shader->ops[i].mx.ref, mark_func);
2045 : }
2046 316 : else if (shader->ops[i].right_value==VAR_VA) {
2047 0 : JS_MarkValue(rt, shader->ops[i].va.ref, mark_func);
2048 : }
2049 316 : else if (shader->ops[i].left_value==VAR_VAI) {
2050 0 : JS_MarkValue(rt, shader->ops[i].vai.ref, mark_func);
2051 : }
2052 316 : else if (shader->ops[i].left_value==VAR_MATRIX) {
2053 0 : JS_MarkValue(rt, shader->ops[i].mx.ref, mark_func);
2054 : }
2055 : }
2056 : }
2057 :
2058 : JSClassDef shader_class = {
2059 : .class_name = "Shader",
2060 : .finalizer = shader_finalize,
2061 : .gc_mark = shader_gc_mark
2062 : };
2063 :
2064 203 : static u32 get_builtin_var_name(EVGShader *shader, const char *val_name)
2065 : {
2066 : u32 i;
2067 203 : if (shader->mode==GF_EVG_SHADER_FRAGMENT) {
2068 142 : if (!strcmp(val_name, "fragColor") || !strcmp(val_name, "fragRGBA")) return VAR_FRAG_ARGB;
2069 122 : if (!strcmp(val_name, "fragYUVA")) return VAR_FRAG_YUV;
2070 121 : if (!strcmp(val_name, "fragDepth") || !strcmp(val_name, "fragZ")) return VAR_FRAG_DEPTH;
2071 121 : if (!strcmp(val_name, "fragX")) return VAR_FRAG_X;
2072 120 : if (!strcmp(val_name, "fragY")) return VAR_FRAG_Y;
2073 120 : if (!strcmp(val_name, "fragW")) return VAR_FRAG_W;
2074 : }
2075 181 : if (shader->mode==GF_EVG_SHADER_VERTEX) {
2076 61 : if (!strcmp(val_name, "vertex")) return VAR_VERTEX_IN;
2077 26 : if (!strcmp(val_name, "vertexOut")) return VAR_VERTEX_OUT;
2078 : }
2079 :
2080 129 : if (val_name[0] == '.') return VAR_UNIFORM;
2081 :
2082 159 : for (i=0; i<shader->nb_vars; i++) {
2083 231 : if (!strcmp(shader->vars[i].name, val_name)) {
2084 72 : return EVG_FIRST_VAR_ID+i+1;
2085 : }
2086 : }
2087 : return 0;
2088 : }
2089 23 : static u8 get_value_type(const char *comp)
2090 : {
2091 23 : if (!strcmp(comp, "x") || !strcmp(comp, "r") || !strcmp(comp, "s")) return COMP_X;
2092 22 : if (!strcmp(comp, "y") || !strcmp(comp, "g") || !strcmp(comp, "t")) return COMP_Y;
2093 22 : if (!strcmp(comp, "z") || !strcmp(comp, "b")) return COMP_Z;
2094 22 : if (!strcmp(comp, "q") || !strcmp(comp, "a")) return COMP_Q;
2095 1 : if (!strcmp(comp, "xyz") || !strcmp(comp, "rgb")) return COMP_V3;
2096 1 : if (!strcmp(comp, "xy") || !strcmp(comp, "rg") || !strcmp(comp, "st")) return COMP_V2_XY;
2097 1 : if (!strcmp(comp, "xz") || !strcmp(comp, "rb")) return COMP_V2_XZ;
2098 1 : if (!strcmp(comp, "yz") || !strcmp(comp, "gb")) return COMP_V2_YZ;
2099 0 : return COMP_V4;
2100 : }
2101 :
2102 :
2103 130 : static JSValue shader_push(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
2104 : {
2105 : const char *val_name=NULL, *arg_str;
2106 : const char *op_name;
2107 : char *uni_name=NULL;
2108 : Bool dual_right_val = GF_FALSE;
2109 : u32 var_idx=0;
2110 130 : u32 left_op_idx=0, right_op_idx=0, right_op2_idx=0;
2111 : u8 left_value_type=COMP_V4, right_value_type=COMP_V4;
2112 : u8 op_type=0;
2113 : u8 cond_type=0;
2114 : ShaderOp new_op;
2115 130 : EVGShader *shader = JS_GetOpaque(obj, shader_class_id);
2116 130 : if (!shader) return JS_EXCEPTION;
2117 130 : shader->invalid = GF_FALSE;
2118 130 : if (!argc) {
2119 0 : shader_reset(JS_GetRuntime(ctx), shader);
2120 0 : return JS_UNDEFINED;
2121 : }
2122 :
2123 : memset(&new_op, 0, sizeof(ShaderOp));
2124 : new_op.op_type = 0;
2125 130 : new_op.tx_ref = JS_UNDEFINED;
2126 :
2127 260 : if (JS_IsObject(argv[0])) {
2128 2 : new_op.vai.vai = JS_GetOpaque(argv[0], vai_class_id);
2129 2 : if (!new_op.vai.vai) {
2130 0 : shader->invalid = GF_TRUE;
2131 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid left-operand value, must be a VAI");
2132 : }
2133 2 : new_op.vai.ref = JS_DupValue(ctx, argv[0]);
2134 2 : left_op_idx = VAR_VAI;
2135 : } else {
2136 :
2137 : arg_str = JS_ToCString(ctx, argv[0]);
2138 128 : if (!arg_str) {
2139 0 : shader->invalid = GF_TRUE;
2140 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid left-operand value, must be a string");
2141 : }
2142 : val_name = arg_str;
2143 128 : while ((val_name[0]==' ') || (val_name[0]=='\t'))
2144 0 : val_name++;
2145 :
2146 128 : if (!strcmp(val_name, "if")) {
2147 : op_type = EVG_OP_IF;
2148 2 : JS_FreeCString(ctx, arg_str);
2149 : arg_str = JS_ToCString(ctx, argv[1]);
2150 2 : if (!arg_str) {
2151 0 : shader->invalid = GF_TRUE;
2152 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid if first var, must be a string");
2153 : }
2154 : var_idx=1;
2155 : val_name = arg_str;
2156 : }
2157 126 : else if (!strcmp(val_name, "else")) {
2158 : op_type = EVG_OP_ELSE;
2159 1 : JS_FreeCString(ctx, arg_str);
2160 1 : goto op_parsed;
2161 : }
2162 125 : else if (!strcmp(val_name, "discard")) {
2163 0 : if (shader->mode==GF_EVG_SHADER_VERTEX) {
2164 0 : shader->invalid = GF_TRUE;
2165 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "discard is invalid in vertex shader");
2166 : }
2167 : op_type = EVG_OP_DISCARD;
2168 0 : JS_FreeCString(ctx, arg_str);
2169 0 : goto op_parsed;
2170 : }
2171 125 : else if (!strcmp(val_name, "elseif")) {
2172 : op_type = EVG_OP_ELSEIF;
2173 : var_idx=1;
2174 : }
2175 125 : else if (!strcmp(val_name, "goto")) {
2176 : op_type = EVG_OP_GOTO;
2177 1 : JS_FreeCString(ctx, arg_str);
2178 :
2179 2 : if (JS_IsString(argv[1])) {
2180 : arg_str = JS_ToCString(ctx, argv[1]);
2181 1 : if (arg_str[0] != '.') {
2182 0 : shader->invalid = GF_TRUE;
2183 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid goto var, must be a uniform string");
2184 : }
2185 : right_op_idx = VAR_UNIFORM;
2186 1 : uni_name = gf_strdup(arg_str+1);
2187 1 : JS_FreeCString(ctx, arg_str);
2188 0 : } else if (JS_ToInt32(ctx, &left_op_idx, argv[1]) ) {
2189 0 : shader->invalid = GF_TRUE;
2190 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid goto var, must be a number greater than 1, 1 being the first instruction in the stack");
2191 : }
2192 : goto op_parsed;
2193 : }
2194 124 : else if (!strcmp(val_name, "end")) {
2195 : op_type = EVG_OP_END;
2196 2 : JS_FreeCString(ctx, arg_str);
2197 2 : goto op_parsed;
2198 : }
2199 122 : else if (!strcmp(val_name, "print")) {
2200 : op_type = EVG_OP_PRINT;
2201 0 : JS_FreeCString(ctx, arg_str);
2202 : var_idx=-1;
2203 0 : goto parse_right_val;
2204 : }
2205 122 : else if (!strcmp(val_name, "toRGB")) {
2206 : op_type = EVG_OP_YUV2RGB;
2207 0 : JS_FreeCString(ctx, arg_str);
2208 : var_idx=-1;
2209 0 : goto parse_right_val;
2210 : }
2211 122 : else if (!strcmp(val_name, "toYUV")) {
2212 : op_type = EVG_OP_RGB2YUV;
2213 0 : JS_FreeCString(ctx, arg_str);
2214 : var_idx=-1;
2215 0 : goto parse_right_val;
2216 : }
2217 :
2218 124 : char *sep = strchr(val_name, '.');
2219 124 : if (sep) sep[0] = 0;
2220 124 : left_op_idx = get_builtin_var_name(shader, val_name);
2221 124 : if (!left_op_idx) {
2222 33 : if (shader->alloc_vars <= shader->nb_vars) {
2223 33 : shader->alloc_vars = shader->nb_vars+1;
2224 33 : shader->vars = gf_realloc(shader->vars, sizeof(ShaderVar)*shader->alloc_vars);
2225 : }
2226 33 : shader->vars[shader->nb_vars].name = gf_strdup(val_name);
2227 33 : shader->nb_vars++;
2228 33 : left_op_idx = EVG_FIRST_VAR_ID + shader->nb_vars;
2229 : }
2230 124 : if (sep) {
2231 22 : left_value_type = get_value_type(sep+1);
2232 22 : sep[0] = '.';
2233 : }
2234 124 : JS_FreeCString(ctx, arg_str);
2235 : }
2236 :
2237 126 : op_name = JS_ToCString(ctx, argv[var_idx+1]);
2238 126 : if (!op_name) {
2239 0 : shader->invalid = GF_TRUE;
2240 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid operand type, must be a string");
2241 : }
2242 126 : if (!strcmp(op_name, "=")) {
2243 : op_type = EVG_OP_ASSIGN;
2244 85 : if (left_op_idx==VAR_FRAG_DEPTH)
2245 0 : shader->disable_early_z = GF_TRUE;
2246 41 : } else if (!strcmp(op_name, "+=")) {
2247 : op_type = EVG_OP_ADD;
2248 3 : if (left_op_idx==VAR_FRAG_DEPTH)
2249 0 : shader->disable_early_z = GF_TRUE;
2250 38 : } else if (!strcmp(op_name, "-=")) {
2251 : op_type = EVG_OP_SUB;
2252 0 : if (left_op_idx==VAR_FRAG_DEPTH)
2253 0 : shader->disable_early_z = GF_TRUE;
2254 38 : } else if (!strcmp(op_name, "*=")) {
2255 : op_type = EVG_OP_MUL;
2256 23 : if (left_op_idx==VAR_FRAG_DEPTH)
2257 0 : shader->disable_early_z = GF_TRUE;
2258 15 : } else if (!strcmp(op_name, "/=")) {
2259 : op_type = EVG_OP_DIV;
2260 1 : if (left_op_idx==VAR_FRAG_DEPTH)
2261 0 : shader->disable_early_z = GF_TRUE;
2262 14 : } else if (!strcmp(op_name, "=!")) {
2263 : op_type = EVG_OP_NEG;
2264 0 : if (left_op_idx==VAR_FRAG_DEPTH)
2265 0 : shader->disable_early_z = GF_TRUE;
2266 14 : } else if (!strcmp(op_name, "<")) {
2267 : cond_type = EVG_OP_LESS;
2268 13 : } else if (!strcmp(op_name, "<=")) {
2269 : cond_type = EVG_OP_LESS_EQUAL;
2270 13 : } else if (!strcmp(op_name, ">")) {
2271 : cond_type = EVG_OP_GREATER;
2272 12 : } else if (!strcmp(op_name, ">=")) {
2273 : cond_type = EVG_OP_GREATER_EQUAL;
2274 12 : } else if (!strcmp(op_name, "==")) {
2275 : cond_type = EVG_OP_EQUAL;
2276 12 : } else if (!strcmp(op_name, "!=")) {
2277 : cond_type = EVG_OP_NOT_EQUAL;
2278 12 : } else if (!strcmp(op_name, "sampler") || !strcmp(op_name, "samplerYUV") ) {
2279 2 : new_op.tx = JS_GetOpaque(argv[var_idx+2], texture_class_id);
2280 2 : if (!strcmp(op_name, "samplerYUV")) op_type = EVG_OP_SAMPLER_YUV;
2281 : else op_type = EVG_OP_SAMPLER;
2282 :
2283 2 : if (!new_op.tx) {
2284 0 : JS_FreeCString(ctx, val_name);
2285 0 : shader->invalid = GF_TRUE;
2286 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid texture object for 2D sampler");
2287 : }
2288 2 : new_op.tx_ref = argv[var_idx+2];
2289 2 : var_idx++;
2290 10 : } else if (!strcmp(op_name, "normalize")) {
2291 : op_type = EVG_OP_NORMALIZE;
2292 8 : } else if (!strcmp(op_name, "length")) {
2293 : op_type = EVG_OP_LENGTH;
2294 8 : } else if (!strcmp(op_name, "distance")) {
2295 : op_type = EVG_OP_DISTANCE;
2296 : dual_right_val = GF_TRUE;
2297 8 : } else if (!strcmp(op_name, "dot")) {
2298 : op_type = EVG_OP_DOT;
2299 : dual_right_val = GF_TRUE;
2300 6 : } else if (!strcmp(op_name, "cross")) {
2301 : op_type = EVG_OP_CROSS;
2302 : dual_right_val = GF_TRUE;
2303 6 : } else if (!strcmp(op_name, "pow")) {
2304 : op_type = EVG_OP_POW;
2305 : dual_right_val = GF_TRUE;
2306 5 : } else if (!strcmp(op_name, "sin")) {
2307 : op_type = EVG_OP_SIN;
2308 5 : } else if (!strcmp(op_name, "asin")) {
2309 : op_type = EVG_OP_ASIN;
2310 5 : } else if (!strcmp(op_name, "cos")) {
2311 : op_type = EVG_OP_COS;
2312 5 : } else if (!strcmp(op_name, "acos")) {
2313 : op_type = EVG_OP_ACOS;
2314 5 : } else if (!strcmp(op_name, "tan")) {
2315 : op_type = EVG_OP_TAN;
2316 5 : } else if (!strcmp(op_name, "atan")) {
2317 : op_type = EVG_OP_ATAN;
2318 : dual_right_val = GF_TRUE;
2319 5 : } else if (!strcmp(op_name, "log")) {
2320 : op_type = EVG_OP_LOG;
2321 5 : } else if (!strcmp(op_name, "exp")) {
2322 : op_type = EVG_OP_EXP;
2323 5 : } else if (!strcmp(op_name, "log2")) {
2324 : op_type = EVG_OP_LOG2;
2325 5 : } else if (!strcmp(op_name, "exp2")) {
2326 : op_type = EVG_OP_EXP2;
2327 5 : } else if (!strcmp(op_name, "sinh")) {
2328 : op_type = EVG_OP_SINH;
2329 5 : } else if (!strcmp(op_name, "cosh")) {
2330 : op_type = EVG_OP_COSH;
2331 5 : } else if (!strcmp(op_name, "sqrt")) {
2332 : op_type = EVG_OP_SQRT;
2333 5 : } else if (!strcmp(op_name, "inversesqrt")) {
2334 : op_type = EVG_OP_INVERSE_SQRT;
2335 4 : } else if (!strcmp(op_name, "abs")) {
2336 : op_type = EVG_OP_ABS;
2337 4 : } else if (!strcmp(op_name, "sign")) {
2338 : op_type = EVG_OP_SIGN;
2339 3 : } else if (!strcmp(op_name, "floor")) {
2340 : op_type = EVG_OP_FLOOR;
2341 3 : } else if (!strcmp(op_name, "ceil")) {
2342 : op_type = EVG_OP_CEIL;
2343 3 : } else if (!strcmp(op_name, "fract")) {
2344 : op_type = EVG_OP_FRACT;
2345 2 : } else if (!strcmp(op_name, "mod")) {
2346 : op_type = EVG_OP_MOD;
2347 : dual_right_val = GF_TRUE;
2348 1 : } else if (!strcmp(op_name, "min")) {
2349 : op_type = EVG_OP_MIN;
2350 : dual_right_val = GF_TRUE;
2351 1 : } else if (!strcmp(op_name, "max")) {
2352 : op_type = EVG_OP_MAX;
2353 : dual_right_val = GF_TRUE;
2354 1 : } else if (!strcmp(op_name, "clamp")) {
2355 : op_type = EVG_OP_CLAMP;
2356 : dual_right_val = GF_TRUE;
2357 : } else {
2358 0 : JS_FreeCString(ctx, val_name);
2359 0 : shader->invalid = GF_TRUE;
2360 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid operand type, must be a string");
2361 : }
2362 126 : JS_FreeCString(ctx, op_name);
2363 :
2364 126 : parse_right_val:
2365 252 : if (JS_IsString(argv[var_idx+2])) {
2366 : val_name = JS_ToCString(ctx, argv[var_idx+2]);
2367 74 : if (!val_name) {
2368 0 : shader->invalid = GF_TRUE;
2369 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid right-operand value, must be a string");
2370 : }
2371 :
2372 74 : char *sep = strchr(val_name+1, '.');
2373 74 : if (sep) sep[0] = 0;
2374 74 : right_op_idx = get_builtin_var_name(shader, val_name);
2375 74 : if (right_op_idx==VAR_UNIFORM) {
2376 24 : uni_name = gf_strdup(val_name+1);
2377 : }
2378 74 : if (sep) sep[0] = '.';
2379 :
2380 74 : if (!right_op_idx) {
2381 0 : JSValue ret = js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid right-operand value, undefined variable %s", val_name);
2382 0 : JS_FreeCString(ctx, val_name);
2383 0 : shader->invalid = GF_TRUE;
2384 0 : if (uni_name) gf_free(uni_name);
2385 0 : return ret;
2386 : }
2387 74 : if (sep) {
2388 1 : right_value_type = get_value_type(sep+1);
2389 : }
2390 74 : JS_FreeCString(ctx, val_name);
2391 : }
2392 52 : else if (JS_IsArray(ctx, argv[var_idx+2])) {
2393 : u32 idx, length;
2394 23 : JSValue comp = JS_GetPropertyStr(ctx, argv[var_idx+2], "length");
2395 23 : if (JS_ToInt32(ctx, &length, comp)) return JS_EXCEPTION;
2396 : JS_FreeValue(ctx, comp);
2397 23 : if (length>4) length=4;
2398 : right_value_type = 0;
2399 87 : for (idx=0;idx<length; idx++) {
2400 87 : comp = JS_GetPropertyUint32(ctx, argv[var_idx+2], idx);
2401 87 : EVG_GET_FLOAT(new_op.vec[idx], comp);
2402 87 : right_value_type |= 1<<idx;
2403 : JS_FreeValue(ctx, comp);
2404 : }
2405 : }
2406 58 : else if (JS_IsObject(argv[var_idx+2])) {
2407 22 : EVG_VAI *vai = JS_GetOpaque(argv[var_idx+2], vai_class_id);
2408 22 : GF_Matrix *mx = JS_GetOpaque(argv[var_idx+2], matrix_class_id);
2409 22 : EVG_VA *va = (shader->mode==GF_EVG_SHADER_VERTEX) ? JS_GetOpaque(argv[var_idx+2], va_class_id) : NULL;
2410 :
2411 22 : if (vai) {
2412 3 : new_op.vai.vai = vai;
2413 3 : new_op.vai.ref = JS_DupValue(ctx, argv[var_idx+2]);
2414 : right_op_idx = VAR_VAI;
2415 19 : } else if (mx) {
2416 18 : new_op.mx.mx = mx;
2417 18 : new_op.mx.ref = JS_DupValue(ctx, argv[var_idx+2]);
2418 : right_op_idx = VAR_MATRIX;
2419 1 : } else if (va) {
2420 1 : new_op.va.va = va;
2421 1 : new_op.va.ref = JS_DupValue(ctx, argv[var_idx+2]);
2422 : right_op_idx = VAR_VA;
2423 : } else {
2424 0 : shader->invalid = GF_TRUE;
2425 : if (uni_name) gf_free(uni_name);
2426 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "unknown object type for right operand");
2427 : }
2428 : }
2429 7 : else if (JS_IsBool(argv[var_idx+2])) {
2430 0 : new_op.bval = JS_ToBool(ctx, argv[var_idx+2]) ? GF_TRUE : GF_FALSE;
2431 : right_value_type = COMP_BOOL;
2432 : }
2433 7 : else if (JS_IsNumber(argv[var_idx+2])) {
2434 7 : if (JS_IsInteger(argv[var_idx+2])) {
2435 6 : JS_ToInt32(ctx, &new_op.ival, argv[var_idx+2]);
2436 : right_value_type = COMP_INT;
2437 : } else {
2438 : Double v;
2439 1 : JS_ToFloat64(ctx, &v, argv[var_idx+2]);
2440 1 : new_op.vec[0] = (Float) v;
2441 : right_value_type = COMP_FLOAT;
2442 : }
2443 : }
2444 :
2445 126 : if (dual_right_val) {
2446 : Bool is_ok=GF_FALSE;
2447 5 : if ((u32) argc<=var_idx+3) {}
2448 : else {
2449 5 : val_name = JS_ToCString(ctx, argv[var_idx+3]);
2450 5 : if (val_name) {
2451 5 : right_op2_idx = get_builtin_var_name(shader, val_name);
2452 5 : if (right_op2_idx >= EVG_FIRST_VAR_ID) {
2453 : is_ok=GF_TRUE;
2454 : }
2455 : }
2456 5 : JS_FreeCString(ctx, val_name);
2457 : }
2458 5 : if (!is_ok) {
2459 0 : JSValue ret = js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid second right-operand value, only local variable allowed");
2460 0 : JS_FreeCString(ctx, val_name);
2461 0 : shader->invalid = GF_TRUE;
2462 0 : if (uni_name) gf_free(uni_name);
2463 0 : return ret;
2464 : }
2465 : }
2466 :
2467 256 : op_parsed:
2468 :
2469 130 : if (dual_right_val && !right_op2_idx) {
2470 0 : shader->invalid = GF_TRUE;
2471 0 : if (uni_name) gf_free(uni_name);
2472 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid second right-operand value, only local variable allowed");
2473 : }
2474 130 : new_op.op_type = op_type;
2475 130 : if (!new_op.op_type) {
2476 0 : shader->invalid = GF_TRUE;
2477 0 : if (uni_name) gf_free(uni_name);
2478 0 : return js_throw_err_msg(ctx, GF_BAD_PARAM, "unknown operation type");
2479 : }
2480 130 : new_op.cond_type = cond_type;
2481 130 : new_op.left_value = left_op_idx;
2482 130 : new_op.right_value = right_op_idx;
2483 130 : new_op.left_value_type = left_value_type;
2484 130 : new_op.right_value_type = right_value_type;
2485 130 : new_op.right_value_second = right_op2_idx;
2486 130 : if (new_op.tx) {
2487 2 : new_op.tx_ref = JS_DupValue(ctx, new_op.tx_ref);
2488 : }
2489 :
2490 130 : if (shader->alloc_ops <= shader->nb_ops) {
2491 130 : shader->alloc_ops = shader->nb_ops+1;
2492 130 : shader->ops = gf_realloc(shader->ops, sizeof(ShaderOp)*shader->alloc_ops);
2493 130 : shader->ops[shader->nb_ops].uni_name = NULL;
2494 : }
2495 130 : if (shader->ops[shader->nb_ops].uni_name) {
2496 0 : gf_free(shader->ops[shader->nb_ops].uni_name);
2497 0 : shader->ops[shader->nb_ops].uni_name = NULL;
2498 : }
2499 :
2500 130 : shader->ops[shader->nb_ops] = new_op;
2501 130 : shader->ops[shader->nb_ops].uni_name = uni_name;
2502 130 : shader->nb_ops++;
2503 130 : return JS_NewInt32(ctx, shader->nb_ops);
2504 : }
2505 :
2506 226 : static JSValue shader_update(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
2507 : {
2508 : u32 i;
2509 226 : EVGShader *shader = JS_GetOpaque(obj, shader_class_id);
2510 226 : if (!shader) return JS_EXCEPTION;
2511 226 : if (shader->invalid) return JS_EXCEPTION;
2512 :
2513 3486 : for (i=0; i<shader->nb_ops; i++) {
2514 : JSValue v;
2515 3486 : ShaderOp *op = &shader->ops[i];
2516 3486 : if (!op->uni_name) continue;
2517 926 : v = JS_GetPropertyStr(ctx, obj, op->uni_name);
2518 926 : if (JS_IsUndefined(v)) return js_throw_err_msg(ctx, GF_BAD_PARAM, "uniform %s cannot be found in shader", op->uni_name);
2519 926 : if (JS_IsBool(v)) {
2520 0 : op->right_value_type = COMP_BOOL;
2521 0 : op->bval = JS_ToBool(ctx, v) ? GF_TRUE : GF_FALSE;
2522 : }
2523 926 : else if (JS_IsNumber(v)) {
2524 226 : if (JS_IsInteger(v)) {
2525 226 : op->right_value_type = COMP_INT;
2526 226 : if (JS_ToInt32(ctx, &op->ival, v)) return JS_EXCEPTION;
2527 : } else {
2528 0 : op->right_value_type = COMP_FLOAT;
2529 0 : EVG_GET_FLOAT(op->vec[0], v)
2530 : }
2531 : }
2532 700 : else if (JS_IsArray(ctx, v)) {
2533 : u32 idx, length;
2534 700 : JSValue comp = JS_GetPropertyStr(ctx, v, "length");
2535 700 : if (JS_ToInt32(ctx, &length, comp)) return JS_EXCEPTION;
2536 : JS_FreeValue(ctx, comp);
2537 700 : if (length>4) length=4;
2538 700 : op->right_value_type = 0;
2539 3400 : for (idx=0;idx<length; idx++) {
2540 2700 : comp = JS_GetPropertyUint32(ctx, v, idx);
2541 2700 : EVG_GET_FLOAT(op->vec[idx], comp);
2542 2700 : op->right_value_type |= 1<<idx;
2543 : JS_FreeValue(ctx, comp);
2544 : }
2545 : }
2546 0 : else if (JS_IsObject(v)) {
2547 : u32 data_size;
2548 : Float *vals;
2549 : u32 idx;
2550 0 : u8 *data = evg_get_array(ctx, v, &data_size);
2551 0 : if (data) {
2552 0 : if (data_size%4) return JS_EXCEPTION;
2553 : vals = (Float*)data;
2554 0 : data_size/= sizeof(Float);
2555 0 : if (data_size>4) data_size=4;
2556 0 : op->right_value_type = 0;
2557 0 : for (idx=0;idx<data_size; idx++) {
2558 0 : op->vec[idx] = vals[idx];
2559 0 : op->right_value_type |= 1<<idx;
2560 : }
2561 : } else {
2562 : JSValue comp;
2563 0 : op->right_value_type = 0;
2564 : #define GET_COMP(_name, _idx, _mask)\
2565 : comp = JS_GetPropertyStr(ctx, v, _name);\
2566 : if (!JS_IsUndefined(comp)) { EVG_GET_FLOAT(op->vec[_idx], comp); op->right_value_type |= _mask; }\
2567 : JS_FreeValue(ctx, comp);\
2568 :
2569 0 : GET_COMP("x", 0, COMP_X);
2570 0 : GET_COMP("r", 0, COMP_X);
2571 0 : GET_COMP("s", 0, COMP_X);
2572 :
2573 0 : GET_COMP("y", 1, COMP_Y);
2574 0 : GET_COMP("g", 1, COMP_Y);
2575 0 : GET_COMP("t", 1, COMP_Y);
2576 :
2577 0 : GET_COMP("z", 2, COMP_Z);
2578 0 : GET_COMP("b", 2, COMP_Z);
2579 :
2580 0 : GET_COMP("q", 3, COMP_Q);
2581 0 : GET_COMP("w", 3, COMP_Q);
2582 0 : GET_COMP("a", 3, COMP_Q);
2583 :
2584 : }
2585 : }
2586 : JS_FreeValue(ctx, v);
2587 :
2588 : }
2589 226 : return JS_UNDEFINED;
2590 : }
2591 :
2592 : static const JSCFunctionListEntry shader_funcs[] =
2593 : {
2594 : JS_CFUNC_DEF("push", 0, shader_push),
2595 : JS_CFUNC_DEF("update", 0, shader_update),
2596 : };
2597 :
2598 36 : static JSValue canvas3d_new_shader(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv)
2599 : {
2600 : EVGShader *shader;
2601 : u32 mode;
2602 : JSValue res;
2603 36 : GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas3d_class_id);
2604 36 : if (!canvas) return JS_EXCEPTION;
2605 36 : if (!argc) return JS_EXCEPTION;
2606 36 : JS_ToInt32(ctx, &mode, argv[0]);
2607 36 : GF_SAFEALLOC(shader, EVGShader);
2608 36 : if (!shader)
2609 0 : return js_throw_err(ctx, GF_OUT_OF_MEM);
2610 36 : shader->mode = mode;
2611 36 : res = JS_NewObjectClass(ctx, shader_class_id);
2612 36 : JS_SetOpaque(res, shader);
2613 36 : return res;
2614 : }
2615 :
2616 : static const JSCFunctionListEntry canvas3d_funcs[] =
2617 : {
2618 : JS_CGETSET_MAGIC_DEF("clipper", NULL, canvas3d_setProperty, GF_EVG_CLIPPER),
2619 : JS_CGETSET_MAGIC_DEF("fragment", canvas3d_getProperty, canvas3d_setProperty, GF_EVG_FRAG_SHADER),
2620 : JS_CGETSET_MAGIC_DEF("vertex", canvas3d_getProperty, canvas3d_setProperty, GF_EVG_VERT_SHADER),
2621 : JS_CGETSET_MAGIC_DEF("ccw", NULL, canvas3d_setProperty, GF_EVG_CCW),
2622 : JS_CGETSET_MAGIC_DEF("backcull", NULL, canvas3d_setProperty, GF_EVG_BACKCULL),
2623 : JS_CGETSET_MAGIC_DEF("antialias", NULL, canvas3d_setProperty, GF_EVG_ANTIALIAS),
2624 : JS_CGETSET_MAGIC_DEF("min_depth", NULL, canvas3d_setProperty, GF_EVG_MINDEPTH),
2625 : JS_CGETSET_MAGIC_DEF("max_depth", NULL, canvas3d_setProperty, GF_EVG_MAXDEPTH),
2626 : JS_CGETSET_MAGIC_DEF("point_size", NULL, canvas3d_setProperty, GF_EVG_POINTSIZE),
2627 : JS_CGETSET_MAGIC_DEF("point_smooth", NULL, canvas3d_setProperty, GF_EVG_POINTSMOOTH),
2628 : JS_CGETSET_MAGIC_DEF("line_size", NULL, canvas3d_setProperty, GF_EVG_LINESIZE),
2629 : JS_CGETSET_MAGIC_DEF("clip_zero", NULL, canvas3d_setProperty, GF_EVG_CLIP_ZERO),
2630 : JS_CGETSET_MAGIC_DEF("depth_test", NULL, canvas3d_setProperty, GF_EVG_DEPTH_TEST),
2631 : JS_CGETSET_MAGIC_DEF("write_depth", NULL, canvas3d_setProperty, GF_EVG_WRITE_DEPTH),
2632 : JS_CGETSET_MAGIC_DEF("depth_buffer", canvas3d_getProperty, canvas3d_setProperty, GF_EVG_DEPTH_BUFFER),
2633 :
2634 : JS_CFUNC_DEF("clear", 0, canvas3d_clear),
2635 : JS_CFUNC_DEF("clearf", 0, canvas3d_clearf),
2636 : JS_CFUNC_DEF("reassign", 0, canvas3d_reassign),
2637 : JS_CFUNC_DEF("projection", 0, canvas3d_projection),
2638 : JS_CFUNC_DEF("modelview", 0, canvas3d_modelview),
2639 : JS_CFUNC_DEF("draw_array", 0, canvas3d_draw_array),
2640 : JS_CFUNC_DEF("draw_path", 0, canvas3d_draw_path),
2641 : JS_CFUNC_DEF("clear_depth", 0, canvas3d_clear_depth),
2642 : JS_CFUNC_DEF("viewport", 0, canvas3d_viewport),
2643 : JS_CFUNC_DEF("new_shader", 0, canvas3d_new_shader),
2644 : JS_CFUNC_DEF("toYUV", 0, canvas3d_toYUV),
2645 : JS_CFUNC_DEF("toRGB", 0, canvas3d_toRGB),
2646 : };
2647 :
2648 19 : static JSValue canvas3d_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
2649 : {
2650 19 : return canvas_constructor_internal(c, new_target, argc, argv, GF_TRUE);
2651 : }
2652 :
2653 : #ifdef EVG_USE_JS_SHADER
2654 :
2655 : JSClassDef fragment_class = {
2656 : .class_name = "Fragment",
2657 : };
2658 :
2659 : enum {
2660 : EVG_FRAG_SCREENX,
2661 : EVG_FRAG_SCREENY,
2662 : EVG_FRAG_DEPTH,
2663 : EVG_FRAG_R,
2664 : EVG_FRAG_G,
2665 : EVG_FRAG_B,
2666 : EVG_FRAG_A,
2667 : EVG_FRAG_Y,
2668 : EVG_FRAG_U,
2669 : EVG_FRAG_V,
2670 : EVG_FRAG_RGBA,
2671 : EVG_FRAG_RGB,
2672 : EVG_FRAG_YUV,
2673 : EVG_FRAG_YUVA,
2674 : };
2675 :
2676 : static JSValue fragment_getProperty(JSContext *c, JSValueConst obj, int magic)
2677 : {
2678 : GF_EVGFragmentParam *frag = JS_GetOpaque(obj, fragment_class_id);
2679 : if (!frag) return JS_EXCEPTION;
2680 : switch (magic) {
2681 : case EVG_FRAG_SCREENX: return JS_NewFloat64(c, frag->screen_x);
2682 : case EVG_FRAG_SCREENY: return JS_NewFloat64(c, frag->screen_y);
2683 : case EVG_FRAG_DEPTH: return JS_NewFloat64(c, frag->depth);
2684 : }
2685 : return JS_UNDEFINED;
2686 : }
2687 : static JSValue fragment_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic)
2688 : {
2689 : EVG_VAIRes *vr;
2690 : GF_EVGFragmentType frag_type = GF_EVG_FRAG_RGB;
2691 :
2692 : GF_EVGFragmentParam *frag = JS_GetOpaque(obj, fragment_class_id);
2693 : if (!frag) return JS_EXCEPTION;
2694 : switch (magic) {
2695 : case EVG_FRAG_DEPTH:
2696 : EVG_GET_FLOAT(frag->depth, value)
2697 : break;
2698 : case EVG_FRAG_Y:
2699 : frag_type = GF_EVG_FRAG_YUV;
2700 : case EVG_FRAG_R:
2701 : EVG_GET_FLOAT(frag->color.x, value)
2702 : CLAMPCOLF(frag->color.x)
2703 : frag->frag_valid = frag_type;
2704 : break;
2705 : case EVG_FRAG_U:
2706 : frag_type = GF_EVG_FRAG_YUV;
2707 : case EVG_FRAG_G:
2708 : EVG_GET_FLOAT(frag->color.y, value)
2709 : CLAMPCOLF(frag->color.y)
2710 : frag->frag_valid = frag_type;
2711 : break;
2712 : case EVG_FRAG_V:
2713 : frag_type = GF_EVG_FRAG_YUV;
2714 : case EVG_FRAG_B:
2715 : EVG_GET_FLOAT(frag->color.z, value)
2716 : CLAMPCOLF(frag->color.z)
2717 : frag->frag_valid = frag_type;
2718 : break;
2719 : case EVG_FRAG_A:
2720 : EVG_GET_FLOAT(frag->color.q, value)
2721 : CLAMPCOLF(frag->color.q)
2722 : if (!frag->frag_valid)
2723 : frag->frag_valid = GF_EVG_FRAG_RGB;
2724 : break;
2725 : case EVG_FRAG_YUVA:
2726 : frag_type = GF_EVG_FRAG_YUV;
2727 : case EVG_FRAG_RGBA:
2728 : vr = JS_GetOpaque(value, vaires_class_id);
2729 : if (vr) {
2730 : frag->color.x = vr->values[0];
2731 : frag->color.y = vr->values[1];
2732 : frag->color.z = vr->values[2];
2733 : frag->color.q = vr->values[3];
2734 : frag->frag_valid = frag_type;
2735 : } else {
2736 : Double a, r, g, b;
2737 : a=1.0;
2738 : if (!get_color_from_args(ctx, 1, &value, 0, &a, &r, &g, &b))
2739 : return JS_EXCEPTION;
2740 : frag->color.q = (Float) a;
2741 : frag->color.x = (Float) r;
2742 : frag->color.y = (Float) g;
2743 : frag->color.z = (Float) b;
2744 : frag->frag_valid = GF_EVG_FRAG_RGB;
2745 : }
2746 : break;
2747 : case EVG_FRAG_YUV:
2748 : frag_type = GF_EVG_FRAG_YUV;
2749 : case EVG_FRAG_RGB:
2750 : vr = JS_GetOpaque(value, vaires_class_id);
2751 : if (vr) {
2752 : frag->color.x = vr->values[0];
2753 : frag->color.y = vr->values[1];
2754 : frag->color.z = vr->values[2];
2755 : frag->frag_valid = frag_type;
2756 : } else
2757 : return JS_EXCEPTION;
2758 : default:
2759 : return JS_UNDEFINED;
2760 : }
2761 : return JS_UNDEFINED;
2762 : }
2763 :
2764 : static const JSCFunctionListEntry fragment_funcs[] =
2765 : {
2766 : JS_CGETSET_MAGIC_DEF("x", fragment_getProperty, NULL, EVG_FRAG_SCREENX),
2767 : JS_CGETSET_MAGIC_DEF("y", fragment_getProperty, NULL, EVG_FRAG_SCREENY),
2768 : JS_CGETSET_MAGIC_DEF("z", fragment_getProperty, fragment_setProperty, EVG_FRAG_DEPTH),
2769 : JS_ALIAS_DEF("depth", "z"),
2770 : JS_CGETSET_MAGIC_DEF("r", NULL, fragment_setProperty, EVG_FRAG_R),
2771 : JS_CGETSET_MAGIC_DEF("g", NULL, fragment_setProperty, EVG_FRAG_G),
2772 : JS_CGETSET_MAGIC_DEF("b", NULL, fragment_setProperty, EVG_FRAG_B),
2773 : JS_CGETSET_MAGIC_DEF("a", NULL, fragment_setProperty, EVG_FRAG_A),
2774 : JS_ALIAS_DEF("Y", "r"),
2775 : JS_ALIAS_DEF("U", "g"),
2776 : JS_ALIAS_DEF("V", "b"),
2777 : JS_CGETSET_MAGIC_DEF("rgba", NULL, fragment_setProperty, EVG_FRAG_RGBA),
2778 : JS_CGETSET_MAGIC_DEF("rgb", NULL, fragment_setProperty, EVG_FRAG_RGB),
2779 : JS_CGETSET_MAGIC_DEF("yuv", NULL, fragment_setProperty, EVG_FRAG_YUV),
2780 : JS_CGETSET_MAGIC_DEF("yuva", NULL, fragment_setProperty, EVG_FRAG_YUVA),
2781 : };
2782 :
2783 : JSClassDef vertex_class = {
2784 : .class_name = "Vertex",
2785 : };
2786 :
2787 : enum {
2788 : EVG_VERTEX_IN,
2789 : EVG_VERTEX_OUT,
2790 : };
2791 :
2792 : static JSValue vertex_getProperty(JSContext *c, JSValueConst obj, int magic)
2793 : {
2794 : JSValue res;
2795 : GF_EVGVertexParam *vert= JS_GetOpaque(obj, vertex_class_id);
2796 : if (!vert) return JS_EXCEPTION;
2797 : switch (magic) {
2798 : case EVG_VERTEX_IN:
2799 : res = JS_NewObject(c);
2800 : JS_SetPropertyStr(c, res, "x", JS_NewFloat64(c, vert->in_vertex.x));
2801 : JS_SetPropertyStr(c, res, "y", JS_NewFloat64(c, vert->in_vertex.y));
2802 : JS_SetPropertyStr(c, res, "z", JS_NewFloat64(c, vert->in_vertex.z));
2803 : JS_SetPropertyStr(c, res, "q", JS_NewFloat64(c, vert->in_vertex.q));
2804 : return res;
2805 : }
2806 : return JS_UNDEFINED;
2807 : }
2808 : static JSValue vertex_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic)
2809 : {
2810 : Double _f;
2811 : JSValue v;
2812 : GF_EVGVertexParam *vert= JS_GetOpaque(obj, vertex_class_id);
2813 : if (!vert) return JS_EXCEPTION;
2814 : switch (magic) {
2815 : case EVG_VERTEX_OUT:
2816 : v = JS_GetPropertyStr(ctx, value, "x");
2817 : EVG_GET_FLOAT(_f, v);
2818 : vert->out_vertex.x = FLT2FIX(_f);
2819 : v = JS_GetPropertyStr(ctx, value, "y");
2820 : EVG_GET_FLOAT(_f, v);
2821 : vert->out_vertex.y = FLT2FIX(_f);
2822 : v = JS_GetPropertyStr(ctx, value, "z");
2823 : EVG_GET_FLOAT(_f, v);
2824 : vert->out_vertex.z = FLT2FIX(_f);
2825 : v = JS_GetPropertyStr(ctx, value, "q");
2826 : EVG_GET_FLOAT(_f, v);
2827 : vert->out_vertex.q = FLT2FIX(_f);
2828 :
2829 : break;
2830 : default:
2831 : return JS_UNDEFINED;
2832 : }
2833 : return JS_UNDEFINED;
2834 : }
2835 : static const JSCFunctionListEntry vertex_funcs[] =
2836 : {
2837 : JS_CGETSET_MAGIC_DEF("vertex", vertex_getProperty, NULL, EVG_VERTEX_IN),
2838 : JS_CGETSET_MAGIC_DEF("vertexOut", NULL, vertex_setProperty, EVG_VERTEX_OUT),
2839 : };
2840 : #endif // EVG_USE_JS_SHADER
2841 :
2842 7275459 : Bool vai_call_lerp(EVG_VAI *vai, GF_EVGFragmentParam *frag)
2843 : {
2844 : u32 i;
2845 :
2846 : //different primitive, setup inperpolation points
2847 7275459 : if (frag->prim_index != vai->prim_idx) {
2848 : u32 idx;
2849 1324 : vai->prim_idx = frag->prim_index;
2850 : //no values, this is a VAI filled by the vertex shader
2851 1324 : if (!vai->values) {
2852 572 : } else if (vai->interp_type==GF_EVG_VAI_PRIMITIVE) {
2853 0 : idx = frag->prim_index * vai->nb_comp;
2854 0 : if (idx+vai->nb_comp > vai->nb_values)
2855 : return GF_FALSE;
2856 :
2857 0 : for (i=0; i<vai->nb_comp; i++) {
2858 0 : vai->result.values[i] = vai->values[idx+i];
2859 : }
2860 572 : } else if (frag->ptype!=GF_EVG_POINTS) {
2861 : u32 nb_v_per_prim = 3;
2862 572 : if (frag->ptype==GF_EVG_LINES)
2863 : nb_v_per_prim=2;
2864 :
2865 572 : if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) {
2866 0 : idx = frag->idx1 * vai->nb_comp;
2867 : } else {
2868 572 : idx = frag->prim_index * nb_v_per_prim * vai->nb_comp;
2869 : }
2870 572 : if (idx+vai->nb_comp > vai->nb_values)
2871 : return GF_FALSE;
2872 1144 : for (i=0; i<vai->nb_comp; i++) {
2873 1144 : vai->anchors[0][i] = vai->values[idx+i];
2874 : }
2875 :
2876 572 : if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) {
2877 0 : idx = frag->idx2 * vai->nb_comp;
2878 : } else {
2879 572 : idx = (frag->prim_index * nb_v_per_prim + 1) * vai->nb_comp;
2880 : }
2881 572 : if (idx+vai->nb_comp > vai->nb_values)
2882 : return GF_FALSE;
2883 1144 : for (i=0; i<vai->nb_comp; i++) {
2884 1144 : vai->anchors[1][i] = vai->values[idx+i];
2885 : }
2886 572 : if (frag->ptype!=GF_EVG_LINES) {
2887 572 : if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) {
2888 0 : idx = frag->idx3 * vai->nb_comp;
2889 : } else {
2890 572 : idx = (frag->prim_index * nb_v_per_prim + 2) * vai->nb_comp;
2891 : }
2892 572 : if (idx+vai->nb_comp > vai->nb_values)
2893 : return GF_FALSE;
2894 1144 : for (i=0; i<vai->nb_comp; i++) {
2895 1144 : vai->anchors[2][i] = vai->values[idx+i];
2896 : }
2897 : }
2898 : }
2899 : }
2900 7275459 : if (vai->interp_type==GF_EVG_VAI_PRIMITIVE) {
2901 : return GF_TRUE;
2902 : }
2903 :
2904 7275459 : if (frag->ptype==GF_EVG_LINES) {
2905 0 : for (i=0; i<vai->nb_comp; i++) {
2906 0 : Float v = frag->pbc1 * vai->anchors[0][i] + frag->pbc2 * vai->anchors[1][i];
2907 0 : vai->result.values[i] = v / frag->persp_denum;
2908 : }
2909 : } else {
2910 20621890 : for (i=0; i<vai->nb_comp; i++) {
2911 20621890 : Float v = (Float) ( frag->pbc1 * vai->anchors[0][i] + frag->pbc2 * vai->anchors[1][i] + frag->pbc3 * vai->anchors[2][i] );
2912 20621890 : vai->result.values[i] = v / frag->persp_denum;
2913 : }
2914 : }
2915 7275459 : if (vai->normalize) {
2916 3035486 : if (vai->nb_comp==2) {
2917 : Float len;
2918 0 : if (!vai->result.values[0]) len = ABS(vai->result.values[1]);
2919 0 : else if (!vai->result.values[1]) len = ABS(vai->result.values[0]);
2920 0 : else len = sqrtf(vai->result.values[0]*vai->result.values[0] + vai->result.values[1]*vai->result.values[1]);
2921 0 : if (len) {
2922 0 : vai->result.values[0]/=len;
2923 0 : vai->result.values[1]/=len;
2924 : }
2925 : } else {
2926 3035486 : gf_vec_norm((GF_Vec *) &vai->result.values[0]);
2927 : }
2928 : }
2929 : return GF_TRUE;
2930 : }
2931 :
2932 : #ifdef EVG_USE_JS_SHADER
2933 : static JSValue vai_lerp(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
2934 : {
2935 : EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id);
2936 : if (!vai || !argc) return JS_EXCEPTION;
2937 : GF_EVGFragmentParam *frag = JS_GetOpaque(argv[0], fragment_class_id);
2938 : if (!frag) return JS_EXCEPTION;
2939 :
2940 : if (!vai_call_lerp(vai, frag))
2941 : return JS_EXCEPTION;
2942 : return JS_DupValue(c, vai->res);
2943 : }
2944 : #endif
2945 :
2946 1 : static JSValue vai_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
2947 : {
2948 1 : EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id);
2949 1 : if (!vai) return JS_EXCEPTION;
2950 1 : switch (magic) {
2951 1 : case 0:
2952 1 : vai->normalize = JS_ToBool(c, value) ? GF_TRUE : GF_FALSE;
2953 1 : break;
2954 : }
2955 1 : return JS_UNDEFINED;
2956 : }
2957 :
2958 3 : static JSValue vai_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
2959 : {
2960 : EVG_VAI *vai;
2961 : JSValue obj;
2962 : u8 *data=NULL;
2963 3 : u32 data_size=0;
2964 : u32 nb_comp;
2965 3 : s32 interp_type = GF_EVG_VAI_VERTEX_INDEX;
2966 3 : if (argc<1)
2967 0 : return js_throw_err_msg(c, GF_BAD_PARAM, "Missing parameter for VertexAttribInterpolator");
2968 :
2969 3 : if (argc>=2) {
2970 1 : data = evg_get_array(c, argv[0], &data_size);
2971 1 : if (!data) return JS_EXCEPTION;
2972 1 : if (JS_ToInt32(c, &nb_comp, argv[1])) return JS_EXCEPTION;
2973 1 : if (nb_comp>MAX_ATTR_DIM)
2974 0 : return js_throw_err_msg(c, GF_BAD_PARAM, "Dimension too big, max is %d", MAX_ATTR_DIM);
2975 :
2976 1 : if (data_size % sizeof(Float)) return JS_EXCEPTION;
2977 1 : data_size /= sizeof(Float);
2978 1 : if (data_size % nb_comp) return JS_EXCEPTION;
2979 :
2980 1 : if (argc>2) {
2981 1 : if (JS_ToInt32(c, &interp_type, argv[2])) return JS_EXCEPTION;
2982 : }
2983 : } else {
2984 2 : if (JS_ToInt32(c, &nb_comp, argv[0])) return JS_EXCEPTION;
2985 : }
2986 :
2987 3 : GF_SAFEALLOC(vai, EVG_VAI);
2988 3 : if (!vai)
2989 0 : return js_throw_err(c, GF_OUT_OF_MEM);
2990 3 : vai->nb_comp = nb_comp;
2991 3 : vai->values = (Float *)data;
2992 3 : vai->nb_values = data_size;
2993 3 : if (data)
2994 1 : vai->ab = JS_DupValue(c, argv[0]);
2995 :
2996 3 : vai->prim_idx = (u32) -1;
2997 3 : vai->interp_type = interp_type;
2998 :
2999 : #ifdef EVG_USE_JS_SHADER
3000 : vai->res = JS_NewObjectClass(c, vaires_class_id);
3001 : JS_SetOpaque(vai->res, &vai->result);
3002 : JS_SetPropertyStr(c, vai->res, "length", JS_NewInt32(c, nb_comp));
3003 : #endif
3004 3 : vai->result.dim = nb_comp;
3005 3 : if (nb_comp==1) vai->result.comp_type = COMP_X;
3006 3 : else if (nb_comp==2) vai->result.comp_type = COMP_V2_XY;
3007 2 : else if (nb_comp==3) vai->result.comp_type = COMP_V3;
3008 0 : else vai->result.comp_type = COMP_V4;
3009 :
3010 3 : obj = JS_NewObjectClass(c, vai_class_id);
3011 3 : JS_SetOpaque(obj, vai);
3012 3 : return obj;
3013 : }
3014 3 : static void vai_finalize(JSRuntime *rt, JSValue obj)
3015 : {
3016 3 : EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id);
3017 3 : if (!vai) return;
3018 : JS_FreeValueRT(rt, vai->ab);
3019 : #ifdef EVG_USE_JS_SHADER
3020 : JS_FreeValueRT(rt, vai->res);
3021 : #endif
3022 3 : gf_free(vai);
3023 : }
3024 :
3025 4 : static void vai_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
3026 : {
3027 4 : EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id);
3028 4 : if (!vai) return;
3029 4 : JS_MarkValue(rt, vai->ab, mark_func);
3030 : #ifdef EVG_USE_JS_SHADER
3031 : JS_MarkValue(rt, vai->res, mark_func);
3032 : #endif
3033 : }
3034 :
3035 : JSClassDef vai_class = {
3036 : .class_name = "VertexAttribInterpolator",
3037 : .finalizer = vai_finalize,
3038 : .gc_mark = vai_gc_mark
3039 : };
3040 : static const JSCFunctionListEntry vai_funcs[] =
3041 : {
3042 : JS_CGETSET_MAGIC_DEF("normalize", NULL, vai_setProperty, 0),
3043 : #ifdef EVG_USE_JS_SHADER
3044 : JS_CFUNC_DEF("lerp", 0, vai_lerp),
3045 : #endif
3046 : };
3047 :
3048 1 : static JSValue va_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
3049 : {
3050 : EVG_VA *va;
3051 : JSValue obj;
3052 : u8 *data=NULL;
3053 : u32 data_size;
3054 : u32 nb_comp;
3055 1 : s32 interp_type = GF_EVG_VAI_VERTEX_INDEX;
3056 1 : if (argc<2)
3057 0 : return js_throw_err_msg(c, GF_BAD_PARAM, "Missing parameter / data for VertexAttrib");
3058 :
3059 1 : data = evg_get_array(c, argv[0], &data_size);
3060 1 : if (!data) return JS_EXCEPTION;
3061 1 : if (JS_ToInt32(c, &nb_comp, argv[1])) return JS_EXCEPTION;
3062 1 : if (nb_comp>MAX_ATTR_DIM)
3063 0 : return js_throw_err_msg(c, GF_BAD_PARAM, "Dimension too big, max is %d", MAX_ATTR_DIM);
3064 :
3065 1 : if (data_size % sizeof(Float)) return JS_EXCEPTION;
3066 1 : data_size /= sizeof(Float);
3067 1 : if (data_size % nb_comp) return JS_EXCEPTION;
3068 :
3069 1 : if (argc>2) {
3070 1 : if (JS_ToInt32(c, &interp_type, argv[2])) return JS_EXCEPTION;
3071 : }
3072 :
3073 1 : GF_SAFEALLOC(va, EVG_VA);
3074 1 : if (!va)
3075 0 : return js_throw_err(c, GF_OUT_OF_MEM);
3076 1 : va->nb_comp = nb_comp;
3077 1 : va->values = (Float *)data;
3078 1 : va->nb_values = data_size;
3079 1 : va->ab = JS_DupValue(c, argv[0]);
3080 1 : va->interp_type = interp_type;
3081 1 : if (va->nb_comp==1) va->att_type = COMP_FLOAT;
3082 1 : else if (va->nb_comp==2) va->att_type = COMP_V2_XY;
3083 1 : else if (va->nb_comp==3) va->att_type = COMP_V3;
3084 0 : else va->att_type = COMP_V4;
3085 :
3086 1 : obj = JS_NewObjectClass(c, va_class_id);
3087 1 : JS_SetOpaque(obj, va);
3088 1 : return obj;
3089 : }
3090 :
3091 1 : static JSValue va_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
3092 : {
3093 1 : EVG_VA *va = JS_GetOpaque(obj, va_class_id);
3094 1 : if (!va) return JS_EXCEPTION;
3095 1 : switch (magic) {
3096 1 : case 0:
3097 1 : va->normalize = JS_ToBool(c, value) ? GF_TRUE : GF_FALSE;
3098 1 : break;
3099 : }
3100 1 : return JS_UNDEFINED;
3101 : }
3102 1 : static void va_finalize(JSRuntime *rt, JSValue obj)
3103 : {
3104 1 : EVG_VA *va = JS_GetOpaque(obj, va_class_id);
3105 1 : if (!va) return;
3106 : JS_FreeValueRT(rt, va->ab);
3107 1 : gf_free(va);
3108 : }
3109 :
3110 0 : static void va_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
3111 : {
3112 0 : EVG_VA *va = JS_GetOpaque(obj, va_class_id);
3113 0 : if (!va) return;
3114 0 : JS_MarkValue(rt, va->ab, mark_func);
3115 : }
3116 :
3117 : JSClassDef va_class = {
3118 : .class_name = "VertexAttrib",
3119 : .finalizer = va_finalize,
3120 : .gc_mark = va_gc_mark
3121 : };
3122 : static const JSCFunctionListEntry va_funcs[] =
3123 : {
3124 : JS_CGETSET_MAGIC_DEF("normalize", NULL, va_setProperty, 0),
3125 : };
3126 :
3127 : #ifdef EVG_USE_JS_SHADER
3128 :
3129 : static JSValue vaires_getProperty(JSContext *c, JSValueConst obj, int magic)
3130 : {
3131 : EVG_VAIRes *vr = JS_GetOpaque(obj, vaires_class_id);
3132 : if (!vr) return JS_EXCEPTION;
3133 : if (magic<MAX_ATTR_DIM) {
3134 : return JS_NewFloat64(c, vr->values[magic]);
3135 : }
3136 : return JS_UNDEFINED;
3137 : }
3138 : static const JSCFunctionListEntry vaires_funcs[] =
3139 : {
3140 : JS_CGETSET_MAGIC_DEF("x", vaires_getProperty, NULL, 0),
3141 : JS_CGETSET_MAGIC_DEF("y", vaires_getProperty, NULL, 1),
3142 : JS_CGETSET_MAGIC_DEF("z", vaires_getProperty, NULL, 2),
3143 : JS_CGETSET_MAGIC_DEF("w", vaires_getProperty, NULL, 3),
3144 : JS_ALIAS_DEF("r", "x"),
3145 : JS_ALIAS_DEF("g", "y"),
3146 : JS_ALIAS_DEF("b", "z"),
3147 : JS_ALIAS_DEF("a", "w"),
3148 : JS_ALIAS_DEF("s", "x"),
3149 : JS_ALIAS_DEF("t", "y"),
3150 : };
3151 :
3152 : JSClassDef vaires_class = {
3153 : .class_name = "VAIResult",
3154 : };
3155 :
3156 : #endif //EVG_USE_JS_SHADER
3157 :
3158 218 : static void mx2d_finalize(JSRuntime *rt, JSValue obj)
3159 : {
3160 218 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3161 218 : if (!mx) return;
3162 218 : gf_free(mx);
3163 : }
3164 : JSClassDef mx2d_class = {
3165 : "Matrix2D",
3166 : .finalizer = mx2d_finalize
3167 : };
3168 :
3169 : enum
3170 : {
3171 : //these 6 magics map to m[x] of the matrix, DO NOT MODIFY
3172 : MX2D_XX = 0,
3173 : MX2D_XY,
3174 : MX2D_TX,
3175 : MX2D_YX,
3176 : MX2D_YY,
3177 : MX2D_TY,
3178 : MX2D_IDENTITY,
3179 : };
3180 :
3181 1 : static JSValue mx2d_getProperty(JSContext *c, JSValueConst obj, int magic)
3182 : {
3183 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3184 1 : if (!mx) return JS_EXCEPTION;
3185 1 : if ((magic>=MX2D_XX) && (magic<=MX2D_TY)) {
3186 1 : return JS_NewFloat64(c, FIX2FLT(mx->m[magic]));
3187 : }
3188 0 : if (magic==MX2D_IDENTITY)
3189 0 : return JS_NewBool(c, gf_mx2d_is_identity(*mx));
3190 0 : return JS_UNDEFINED;
3191 : }
3192 17 : static JSValue mx2d_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
3193 : {
3194 17 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3195 17 : if (!mx) return JS_EXCEPTION;
3196 17 : if ((magic>=MX2D_XX) && (magic<=MX2D_TY)) {
3197 : Double d;
3198 1 : if (JS_ToFloat64(c, &d, value))
3199 0 : return JS_EXCEPTION;
3200 1 : mx->m[magic] = FIX2FLT(d);
3201 1 : return JS_UNDEFINED;
3202 : }
3203 16 : if (magic==MX2D_IDENTITY) {
3204 16 : if (JS_ToBool(c, value))
3205 32 : gf_mx2d_init(*mx);
3206 16 : return JS_UNDEFINED;
3207 : }
3208 0 : return JS_UNDEFINED;
3209 : }
3210 :
3211 201 : static JSValue mx2d_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3212 : {
3213 201 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3214 201 : if (!mx || !argc) return JS_EXCEPTION;
3215 201 : GF_Matrix2D *amx = JS_GetOpaque(argv[0], mx2d_class_id);
3216 201 : if (!mx) return JS_EXCEPTION;
3217 201 : if ((argc>1) && JS_ToBool(c, argv[1]))
3218 0 : gf_mx2d_pre_multiply(mx, amx);
3219 : else
3220 201 : gf_mx2d_add_matrix(mx, amx);
3221 : return JS_DupValue(c, obj);
3222 : }
3223 :
3224 219 : static JSValue mx2d_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3225 : {
3226 : Double tx, ty;
3227 219 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3228 219 : if (!mx || (argc<1)) return JS_EXCEPTION;
3229 :
3230 438 : if (JS_IsObject(argv[0])) {
3231 : JSValue v;
3232 : #define GETD(_arg, _name, _res)\
3233 : if (! JS_IsObject(_arg)) return JS_EXCEPTION;\
3234 : v = JS_GetPropertyStr(c, _arg, _name);\
3235 : JS_ToFloat64(c, &_res, v);\
3236 : JS_FreeValue(c, v);\
3237 :
3238 0 : GETD(argv[0], "x", tx);
3239 0 : GETD(argv[0], "y", ty);
3240 : #undef GETD
3241 :
3242 219 : } else if (argc==2) {
3243 219 : if (JS_ToFloat64(c, &tx, argv[0])) return JS_EXCEPTION;
3244 219 : if (JS_ToFloat64(c, &ty, argv[1])) return JS_EXCEPTION;
3245 : } else {
3246 0 : return JS_EXCEPTION;
3247 : }
3248 219 : gf_mx2d_add_translation(mx, FLT2FIX(tx), FLT2FIX(ty));
3249 : return JS_DupValue(c, obj);
3250 : }
3251 201 : static JSValue mx2d_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3252 : {
3253 : Double cx, cy, a;
3254 201 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3255 201 : if (!mx || (argc<3)) return JS_EXCEPTION;
3256 201 : if (JS_ToFloat64(c, &cx, argv[0])) return JS_EXCEPTION;
3257 201 : if (JS_ToFloat64(c, &cy, argv[1])) return JS_EXCEPTION;
3258 201 : if (JS_ToFloat64(c, &a, argv[2])) return JS_EXCEPTION;
3259 201 : gf_mx2d_add_rotation(mx, FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a) );
3260 : return JS_DupValue(c, obj);
3261 : }
3262 222 : static JSValue mx2d_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3263 : {
3264 : Double sx, sy;
3265 222 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3266 222 : if (!mx || (argc<2)) return JS_EXCEPTION;
3267 222 : if (JS_ToFloat64(c, &sx, argv[0])) return JS_EXCEPTION;
3268 222 : if (JS_ToFloat64(c, &sy, argv[1])) return JS_EXCEPTION;
3269 222 : if (argc==2) {
3270 222 : gf_mx2d_add_scale(mx, FLT2FIX(sx), FLT2FIX(sy));
3271 : return JS_DupValue(c, obj);
3272 0 : } else if (argc==5) {
3273 : Double cx, cy, a;
3274 0 : if (JS_ToFloat64(c, &cx, argv[2])) return JS_EXCEPTION;
3275 0 : if (JS_ToFloat64(c, &cy, argv[3])) return JS_EXCEPTION;
3276 0 : if (JS_ToFloat64(c, &a, argv[4])) return JS_EXCEPTION;
3277 0 : gf_mx2d_add_scale_at(mx, FLT2FIX(sx), FLT2FIX(sy), FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a));
3278 : return JS_DupValue(c, obj);
3279 : }
3280 0 : return JS_EXCEPTION;
3281 : }
3282 :
3283 1 : static JSValue mx2d_skew(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3284 : {
3285 : Double sx, sy;
3286 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3287 1 : if (!mx || (argc<2)) return JS_EXCEPTION;
3288 1 : if (JS_ToFloat64(c, &sx, argv[0])) return JS_EXCEPTION;
3289 1 : if (JS_ToFloat64(c, &sy, argv[1])) return JS_EXCEPTION;
3290 1 : gf_mx2d_add_skew(mx, FLT2FIX(sx), FLT2FIX(sy));
3291 : return JS_DupValue(c, obj);
3292 : }
3293 1 : static JSValue mx2d_skew_x(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3294 : {
3295 : Double s;
3296 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3297 1 : if (!mx || !argc) return JS_EXCEPTION;
3298 1 : if (JS_ToFloat64(c, &s, argv[0])) return JS_EXCEPTION;
3299 1 : gf_mx2d_add_skew_x(mx, FLT2FIX(s));
3300 : return JS_DupValue(c, obj);
3301 : }
3302 1 : static JSValue mx2d_skew_y(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3303 : {
3304 : Double s;
3305 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3306 1 : if (!mx || !argc) return JS_EXCEPTION;
3307 1 : if (JS_ToFloat64(c, &s, argv[0])) return JS_EXCEPTION;
3308 1 : gf_mx2d_add_skew_y(mx, FLT2FIX(s));
3309 : return JS_DupValue(c, obj);
3310 : }
3311 :
3312 1 : static JSValue mx2d_apply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3313 : {
3314 : Fixed x, y, w=0, h=0;
3315 : Double d;
3316 : JSValue v;
3317 : int res;
3318 : u32 is_rect=0;
3319 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3320 2 : if (!mx || !argc || !JS_IsObject(argv[0])) return JS_EXCEPTION;
3321 1 : v = JS_GetPropertyStr(c, argv[0], "x");
3322 1 : res = JS_ToFloat64(c, &d, v);
3323 : JS_FreeValue(c, v);
3324 1 : if (res) return JS_EXCEPTION;
3325 1 : x = FLT2FIX(d);
3326 :
3327 1 : v = JS_GetPropertyStr(c, argv[0], "y");
3328 1 : res = JS_ToFloat64(c, &d, v);
3329 : JS_FreeValue(c, v);
3330 1 : if (res) return JS_EXCEPTION;
3331 1 : y = FLT2FIX(d);
3332 :
3333 1 : v = JS_GetPropertyStr(c, argv[0], "w");
3334 1 : if (!JS_IsUndefined(v) && JS_IsNumber(v)) {
3335 0 : res = JS_ToFloat64(c, &d, v);
3336 : JS_FreeValue(c, v);
3337 0 : if (res) return JS_EXCEPTION;
3338 : is_rect++;
3339 0 : w = FLT2FIX(d);
3340 : }
3341 : JS_FreeValue(c, v);
3342 :
3343 1 : v = JS_GetPropertyStr(c, argv[0], "h");
3344 1 : if (!JS_IsUndefined(v) && JS_IsNumber(v)) {
3345 0 : res = JS_ToFloat64(c, &d, v);
3346 : JS_FreeValue(c, v);
3347 0 : if (res) return JS_EXCEPTION;
3348 0 : is_rect++;
3349 0 : h = FLT2FIX(d);
3350 : }
3351 : JS_FreeValue(c, v);
3352 :
3353 1 : if (is_rect) {
3354 : GF_Rect rc;
3355 0 : rc.x = x;
3356 0 : rc.y = y;
3357 0 : rc.width = w;
3358 0 : rc.height = h;
3359 0 : gf_mx2d_apply_rect(mx, &rc);
3360 0 : v = JS_NewObject(c);
3361 0 : JS_SetPropertyStr(c, v, "x", JS_NewFloat64(c, FIX2FLT(rc.x)));
3362 0 : JS_SetPropertyStr(c, v, "y", JS_NewFloat64(c, FIX2FLT(rc.y)));
3363 0 : JS_SetPropertyStr(c, v, "w", JS_NewFloat64(c, FIX2FLT(rc.width)));
3364 0 : JS_SetPropertyStr(c, v, "h", JS_NewFloat64(c, FIX2FLT(rc.height)));
3365 0 : return v;
3366 :
3367 : } else {
3368 : GF_Point2D pt;
3369 1 : pt.x = x;
3370 1 : pt.y = y;
3371 1 : gf_mx2d_apply_point(mx, &pt);
3372 1 : v = JS_NewObject(c);
3373 2 : JS_SetPropertyStr(c, v, "x", JS_NewFloat64(c, FIX2FLT(pt.x)));
3374 2 : JS_SetPropertyStr(c, v, "y", JS_NewFloat64(c, FIX2FLT(pt.y)));
3375 1 : return v;
3376 : }
3377 : return JS_EXCEPTION;
3378 : }
3379 :
3380 1 : static JSValue mx2d_inverse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3381 : {
3382 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3383 1 : if (!mx) return JS_EXCEPTION;
3384 1 : gf_mx2d_inverse(mx);
3385 : return JS_DupValue(c, obj);
3386 : }
3387 :
3388 1 : static JSValue mx2d_copy(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3389 : {
3390 : GF_Matrix2D *nmx;
3391 : JSValue nobj;
3392 1 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3393 1 : if (!mx) return JS_EXCEPTION;
3394 1 : GF_SAFEALLOC(nmx, GF_Matrix2D);
3395 1 : if (!nmx)
3396 0 : return js_throw_err(c, GF_OUT_OF_MEM);
3397 1 : gf_mx2d_copy(*nmx, *mx);
3398 1 : nobj = JS_NewObjectClass(c, mx2d_class_id);
3399 1 : JS_SetOpaque(nobj, nmx);
3400 1 : return nobj;
3401 : }
3402 :
3403 3 : static JSValue mx2d_decompose_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 opt)
3404 : {
3405 : GF_Point2D scale;
3406 : GF_Point2D translate;
3407 : Fixed rotate;
3408 3 : GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id);
3409 3 : if (!mx) return JS_EXCEPTION;
3410 3 : if (!gf_mx2d_decompose(mx, &scale, &rotate, &translate))
3411 3 : return JS_NULL;
3412 0 : if (opt==0) {
3413 0 : JSValue nobj = JS_NewObject(c);
3414 0 : JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, FIX2FLT(scale.x)) );
3415 0 : JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, FIX2FLT(scale.y)) );
3416 0 : return nobj;
3417 : }
3418 0 : if (opt==1) {
3419 0 : JSValue nobj = JS_NewObject(c);
3420 0 : JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, FIX2FLT(translate.x)) );
3421 0 : JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, FIX2FLT(translate.y)) );
3422 0 : return nobj;
3423 : }
3424 0 : if (opt==2) {
3425 0 : return JS_NewFloat64(c, FIX2FLT(rotate) );
3426 : }
3427 0 : return JS_EXCEPTION;
3428 : }
3429 :
3430 1 : static JSValue mx2d_get_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3431 : {
3432 1 : return mx2d_decompose_ex(c, obj, argc, argv, 0);
3433 : }
3434 1 : static JSValue mx2d_get_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3435 : {
3436 1 : return mx2d_decompose_ex(c, obj, argc, argv, 1);
3437 : }
3438 1 : static JSValue mx2d_get_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3439 : {
3440 1 : return mx2d_decompose_ex(c, obj, argc, argv, 2);
3441 : }
3442 :
3443 : static const JSCFunctionListEntry mx2d_funcs[] =
3444 : {
3445 : JS_CGETSET_MAGIC_DEF("xx", mx2d_getProperty, mx2d_setProperty, MX2D_XX),
3446 : JS_CGETSET_MAGIC_DEF("xy", mx2d_getProperty, mx2d_setProperty, MX2D_XY),
3447 : JS_CGETSET_MAGIC_DEF("tx", mx2d_getProperty, mx2d_setProperty, MX2D_TX),
3448 : JS_CGETSET_MAGIC_DEF("yx", mx2d_getProperty, mx2d_setProperty, MX2D_YX),
3449 : JS_CGETSET_MAGIC_DEF("yy", mx2d_getProperty, mx2d_setProperty, MX2D_YY),
3450 : JS_CGETSET_MAGIC_DEF("ty", mx2d_getProperty, mx2d_setProperty, MX2D_TY),
3451 : JS_CGETSET_MAGIC_DEF("identity", mx2d_getProperty, mx2d_setProperty, MX2D_IDENTITY),
3452 : JS_CFUNC_DEF("get_scale", 0, mx2d_get_scale),
3453 : JS_CFUNC_DEF("get_translate", 0, mx2d_get_translate),
3454 : JS_CFUNC_DEF("get_rotate", 0, mx2d_get_rotate),
3455 : JS_CFUNC_DEF("inverse", 0, mx2d_inverse),
3456 : JS_CFUNC_DEF("copy", 0, mx2d_copy),
3457 : JS_CFUNC_DEF("add", 0, mx2d_multiply),
3458 : JS_CFUNC_DEF("translate", 0, mx2d_translate),
3459 : JS_CFUNC_DEF("rotate", 0, mx2d_rotate),
3460 : JS_CFUNC_DEF("scale", 0, mx2d_scale),
3461 : JS_CFUNC_DEF("skew", 0, mx2d_skew),
3462 : JS_CFUNC_DEF("skew_x", 0, mx2d_skew_x),
3463 : JS_CFUNC_DEF("skew_y", 0, mx2d_skew_y),
3464 : JS_CFUNC_DEF("apply", 0, mx2d_apply),
3465 : };
3466 :
3467 217 : static JSValue mx2d_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
3468 : {
3469 : JSValue obj;
3470 : GF_Matrix2D *mx;
3471 217 : GF_SAFEALLOC(mx, GF_Matrix2D);
3472 217 : if (!mx)
3473 0 : return js_throw_err(c, GF_OUT_OF_MEM);
3474 217 : mx->m[MX2D_XX] = mx->m[MX2D_YY] = FIX_ONE;
3475 217 : obj = JS_NewObjectClass(c, mx2d_class_id);
3476 217 : JS_SetOpaque(obj, mx);
3477 218 : if ((argc==1) && JS_IsObject(argv[0])) {
3478 1 : GF_Matrix2D *amx = JS_GetOpaque(argv[0], mx2d_class_id);
3479 1 : if (amx) gf_mx2d_copy(*mx, *amx);
3480 : }
3481 216 : else if (argc==6) {
3482 : u32 i;
3483 : Double d;
3484 0 : for (i=0; i<6; i++) {
3485 0 : if (JS_ToFloat64(c, &d, argv[i])) return JS_EXCEPTION;
3486 0 : mx->m[i] = FLT2FIX(d);
3487 : }
3488 : }
3489 217 : return obj;
3490 : }
3491 :
3492 3 : static void colmx_finalize(JSRuntime *rt, JSValue obj)
3493 : {
3494 3 : GF_ColorMatrix *mx = JS_GetOpaque(obj, colmx_class_id);
3495 3 : if (!mx) return;
3496 3 : gf_free(mx);
3497 : }
3498 : JSClassDef colmx_class = {
3499 : "ColorMatrix",
3500 : .finalizer = colmx_finalize
3501 : };
3502 :
3503 3 : static JSValue colmx_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
3504 : {
3505 : JSValue obj;
3506 : GF_ColorMatrix *cmx;
3507 3 : GF_SAFEALLOC(cmx, GF_ColorMatrix);
3508 3 : if (!cmx)
3509 0 : return js_throw_err(c, GF_OUT_OF_MEM);
3510 3 : gf_cmx_init(cmx);
3511 3 : obj = JS_NewObjectClass(c, colmx_class_id);
3512 3 : JS_SetOpaque(obj, cmx);
3513 3 : if ((argc==1) && JS_IsObject(argv[0])) {
3514 0 : GF_ColorMatrix *acmx = JS_GetOpaque(argv[0], colmx_class_id);
3515 0 : if (acmx) gf_cmx_copy(cmx, acmx);
3516 : }
3517 3 : else if (argc==20) {
3518 : u32 i;
3519 : Double d;
3520 0 : for (i=0; i<20; i++) {
3521 0 : if (JS_ToFloat64(c, &d, argv[i])) return JS_EXCEPTION;
3522 0 : cmx->m[i] = FLT2FIX(d);
3523 : }
3524 0 : cmx->identity = 0;
3525 : }
3526 3 : return obj;
3527 : }
3528 : enum
3529 : {
3530 : //these 6 magics map to m[x] of the matrix, DO NOT MODIFY
3531 : CMX_MRR = 0,
3532 : CMX_MRG,
3533 : CMX_MRB,
3534 : CMX_MRA,
3535 : CMX_TR,
3536 : CMX_MGR,
3537 : CMX_MGG,
3538 : CMX_MGB,
3539 : CMX_MGA,
3540 : CMX_TG,
3541 : CMX_MBR,
3542 : CMX_MBG,
3543 : CMX_MBB,
3544 : CMX_MBA,
3545 : CMX_TB,
3546 : CMX_MAR,
3547 : CMX_MAG,
3548 : CMX_MAB,
3549 : CMX_MAA,
3550 : CMX_TA,
3551 : CMX_IDENTITY,
3552 : };
3553 :
3554 1 : static JSValue colmx_getProperty(JSContext *c, JSValueConst obj, int magic)
3555 : {
3556 1 : GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id);
3557 1 : if (!cmx) return JS_EXCEPTION;
3558 1 : if ((magic>=CMX_MRR) && (magic<=CMX_TA)) {
3559 1 : return JS_NewFloat64(c, FIX2FLT(cmx->m[magic]));
3560 : }
3561 0 : if (magic==CMX_IDENTITY)
3562 0 : return JS_NewBool(c, cmx->identity);
3563 0 : return JS_UNDEFINED;
3564 : }
3565 4 : static JSValue colmx_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
3566 : {
3567 4 : GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id);
3568 4 : if (!cmx) return JS_EXCEPTION;
3569 4 : if ((magic>=CMX_MRR) && (magic<=CMX_TA)) {
3570 : Double d;
3571 4 : if (JS_ToFloat64(c, &d, value))
3572 0 : return JS_EXCEPTION;
3573 4 : cmx->m[magic] = FIX2FLT(d);
3574 4 : cmx->identity = GF_FALSE;
3575 4 : return JS_UNDEFINED;
3576 : }
3577 0 : return JS_UNDEFINED;
3578 : }
3579 :
3580 1 : static JSValue colmx_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3581 : {
3582 1 : GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id);
3583 1 : if (!cmx || !argc) return JS_EXCEPTION;
3584 1 : GF_ColorMatrix *with = JS_GetOpaque(argv[0], colmx_class_id);
3585 1 : if (!cmx) return JS_EXCEPTION;
3586 1 : gf_cmx_multiply(cmx, with);
3587 : return JS_DupValue(c, obj);
3588 : }
3589 :
3590 103 : static Bool get_color(JSContext *c, JSValueConst obj, Double *a, Double *r, Double *g, Double *b)
3591 : {
3592 : JSValue v;
3593 : int res;
3594 103 : if (JS_IsArray(c, obj)) {
3595 : u32 i, len;
3596 1 : v = JS_GetPropertyStr(c, obj, "length");
3597 1 : res = JS_ToInt32(c, &len, v);
3598 : JS_FreeValue(c, v);
3599 1 : if (res) return GF_FALSE;
3600 1 : if (len>4) len=4;
3601 4 : for (i=0; i<len; i++) {
3602 : Double d;
3603 4 : v = JS_GetPropertyUint32(c, obj, i);
3604 4 : res = JS_ToFloat64(c, &d, v);
3605 4 : if (res) return GF_FALSE;
3606 : JS_FreeValue(c, v);
3607 4 : if (!i) *r = d;
3608 3 : else if (i==1) *g = d;
3609 2 : else if (i==2) *b = d;
3610 1 : else *a = d;
3611 : }
3612 : return GF_TRUE;
3613 : }
3614 102 : v = JS_GetPropertyStr(c, obj, "r");
3615 102 : res = JS_ToFloat64(c, r, v);
3616 : JS_FreeValue(c, v);
3617 102 : if (res) return GF_FALSE;
3618 102 : v = JS_GetPropertyStr(c, obj, "g");
3619 102 : res = JS_ToFloat64(c, g, v);
3620 : JS_FreeValue(c, v);
3621 102 : if (res) return GF_FALSE;
3622 102 : v = JS_GetPropertyStr(c, obj, "b");
3623 102 : res = JS_ToFloat64(c, b, v);
3624 : JS_FreeValue(c, v);
3625 102 : if (res) return GF_FALSE;
3626 102 : v = JS_GetPropertyStr(c, obj, "a");
3627 102 : JS_ToFloat64(c, a, v);
3628 : JS_FreeValue(c, v);
3629 :
3630 102 : if (*r<0) *r=0;
3631 102 : if (*g<0) *g=0;
3632 102 : if (*b<0) *b=0;
3633 102 : if (*a<0) *a=0;
3634 :
3635 : return GF_TRUE;
3636 : }
3637 101 : static JSValue colmx_apply_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int)
3638 : {
3639 : GF_Color col;
3640 : JSValue nobj;
3641 101 : Double r=0, g=0, b=0, a=1.0;
3642 101 : GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id);
3643 101 : if (!cmx || !argc) return JS_EXCEPTION;
3644 202 : if (JS_IsString(argv[0])) {
3645 : const char *str = JS_ToCString(c, argv[0]);
3646 100 : col = gf_color_parse(str);
3647 100 : JS_FreeCString(c, str);
3648 :
3649 100 : if (!use_int) {
3650 0 : a = GF_COL_A(col);
3651 0 : r = GF_COL_R(col);
3652 0 : g = GF_COL_G(col);
3653 0 : b = GF_COL_B(col);
3654 0 : r/=255;
3655 0 : g/=255;
3656 0 : b/=255;
3657 0 : a/=255;
3658 : }
3659 :
3660 1 : } else if (JS_IsObject(argv[0])) {
3661 1 : if (!get_color(c, argv[0], &a, &r, &g, &b))
3662 0 : return JS_EXCEPTION;
3663 1 : if (use_int) {
3664 0 : r*=255;
3665 0 : g*=255;
3666 0 : b*=255;
3667 0 : a*=255;
3668 0 : if (a>255) a=255;
3669 0 : if (r>255) r=255;
3670 0 : if (g>255) g=255;
3671 0 : if (b>255) b=255;
3672 0 : col = GF_COL_ARGB(a, r, g, b);
3673 : }
3674 : } else {
3675 0 : return JS_EXCEPTION;
3676 : }
3677 101 : if (use_int) {
3678 100 : GF_Color res = gf_cmx_apply(cmx, col);
3679 100 : nobj = JS_NewObject(c);
3680 200 : JS_SetPropertyStr(c, nobj, "r", JS_NewInt32(c, GF_COL_R(res)) );
3681 200 : JS_SetPropertyStr(c, nobj, "g", JS_NewInt32(c, GF_COL_G(res)) );
3682 200 : JS_SetPropertyStr(c, nobj, "b", JS_NewInt32(c, GF_COL_B(res)) );
3683 200 : JS_SetPropertyStr(c, nobj, "a", JS_NewInt32(c, GF_COL_A(res)) );
3684 100 : return nobj;
3685 : } else {
3686 1 : Fixed fr=FLT2FIX(r), fg=FLT2FIX(g), fb=FLT2FIX(b), fa=FLT2FIX(a);
3687 :
3688 1 : gf_cmx_apply_fixed(cmx, &fa, &fr, &fg, &fb);
3689 1 : nobj = JS_NewObject(c);
3690 2 : JS_SetPropertyStr(c, nobj, "r", JS_NewFloat64(c, FIX2FLT(fr)) );
3691 2 : JS_SetPropertyStr(c, nobj, "g", JS_NewFloat64(c, FIX2FLT(fg)) );
3692 2 : JS_SetPropertyStr(c, nobj, "b", JS_NewFloat64(c, FIX2FLT(fb)) );
3693 2 : JS_SetPropertyStr(c, nobj, "a", JS_NewFloat64(c, FIX2FLT(fa)) );
3694 1 : return nobj;
3695 : }
3696 : return JS_EXCEPTION;
3697 : }
3698 100 : static JSValue colmx_apply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3699 : {
3700 100 : return colmx_apply_color(c, obj, argc, argv, GF_TRUE);
3701 : }
3702 1 : static JSValue colmx_applyf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3703 : {
3704 1 : return colmx_apply_color(c, obj, argc, argv, GF_FALSE);
3705 : }
3706 :
3707 : static const JSCFunctionListEntry colmx_funcs[] =
3708 : {
3709 : JS_CGETSET_MAGIC_DEF("rr", colmx_getProperty, colmx_setProperty, CMX_MRR),
3710 : JS_CGETSET_MAGIC_DEF("rg", colmx_getProperty, colmx_setProperty, CMX_MRG),
3711 : JS_CGETSET_MAGIC_DEF("rb", colmx_getProperty, colmx_setProperty, CMX_MRB),
3712 : JS_CGETSET_MAGIC_DEF("ra", colmx_getProperty, colmx_setProperty, CMX_MRA),
3713 : JS_CGETSET_MAGIC_DEF("tr", colmx_getProperty, colmx_setProperty, CMX_TR),
3714 : JS_CGETSET_MAGIC_DEF("gr", colmx_getProperty, colmx_setProperty, CMX_MGR),
3715 : JS_CGETSET_MAGIC_DEF("gg", colmx_getProperty, colmx_setProperty, CMX_MGG),
3716 : JS_CGETSET_MAGIC_DEF("gb", colmx_getProperty, colmx_setProperty, CMX_MGB),
3717 : JS_CGETSET_MAGIC_DEF("ga", colmx_getProperty, colmx_setProperty, CMX_MGA),
3718 : JS_CGETSET_MAGIC_DEF("tg", colmx_getProperty, colmx_setProperty, CMX_TG),
3719 : JS_CGETSET_MAGIC_DEF("br", colmx_getProperty, colmx_setProperty, CMX_MBR),
3720 : JS_CGETSET_MAGIC_DEF("bg", colmx_getProperty, colmx_setProperty, CMX_MBG),
3721 : JS_CGETSET_MAGIC_DEF("bb", colmx_getProperty, colmx_setProperty, CMX_MBB),
3722 : JS_CGETSET_MAGIC_DEF("ba", colmx_getProperty, colmx_setProperty, CMX_MBA),
3723 : JS_CGETSET_MAGIC_DEF("tb", colmx_getProperty, colmx_setProperty, CMX_TB),
3724 : JS_CGETSET_MAGIC_DEF("ar", colmx_getProperty, colmx_setProperty, CMX_MAR),
3725 : JS_CGETSET_MAGIC_DEF("ag", colmx_getProperty, colmx_setProperty, CMX_MAG),
3726 : JS_CGETSET_MAGIC_DEF("ab", colmx_getProperty, colmx_setProperty, CMX_MAB),
3727 : JS_CGETSET_MAGIC_DEF("aa", colmx_getProperty, colmx_setProperty, CMX_MAA),
3728 : JS_CGETSET_MAGIC_DEF("ta", colmx_getProperty, colmx_setProperty, CMX_TA),
3729 : JS_CGETSET_MAGIC_DEF("identity", colmx_getProperty, NULL, CMX_IDENTITY),
3730 :
3731 : JS_CFUNC_DEF("multiply", 0, colmx_multiply),
3732 : JS_CFUNC_DEF("apply", 0, colmx_apply),
3733 : JS_CFUNC_DEF("applyf", 0, colmx_applyf),
3734 : };
3735 :
3736 :
3737 :
3738 19 : static void path_finalize(JSRuntime *rt, JSValue obj)
3739 : {
3740 19 : GF_Path *path = JS_GetOpaque(obj, path_class_id);
3741 19 : if (!path) return;
3742 19 : gf_path_del(path);
3743 : }
3744 : JSClassDef path_class = {
3745 : "Path",
3746 : .finalizer = path_finalize
3747 : };
3748 :
3749 9 : static JSValue path_close_reset(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 opt)
3750 : {
3751 9 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3752 9 : if (!gp) return JS_EXCEPTION;
3753 9 : if (opt==0) {
3754 2 : gf_path_close(gp);
3755 : return JS_DupValue(c, obj);
3756 : }
3757 7 : if (opt==1) {
3758 6 : gf_path_reset(gp);
3759 : return JS_DupValue(c, obj);
3760 : }
3761 1 : if (opt==2) {
3762 1 : JSValue nobj = JS_NewObjectClass(c, path_class_id);
3763 1 : if (JS_IsException(nobj)) return nobj;
3764 1 : JS_SetOpaque(nobj, gf_path_clone(gp));
3765 1 : gf_path_reset(gp);
3766 1 : return nobj;
3767 : }
3768 0 : return JS_EXCEPTION;
3769 : }
3770 6 : static JSValue path_reset(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3771 : {
3772 6 : return path_close_reset(c, obj, argc, argv, 1);
3773 : }
3774 2 : static JSValue path_close(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3775 : {
3776 2 : return path_close_reset(c, obj, argc, argv, 0);
3777 : }
3778 1 : static JSValue path_clone(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3779 : {
3780 1 : return path_close_reset(c, obj, argc, argv, 2);
3781 : }
3782 5 : static JSValue path_line_move(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_line)
3783 : {
3784 5 : Double x=0, y=0;
3785 : GF_Err e;
3786 5 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3787 5 : if (!gp || (argc<2)) return JS_EXCEPTION;
3788 5 : if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
3789 5 : if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
3790 5 : if (is_line)
3791 1 : e = gf_path_add_line_to(gp, FLT2FIX(x), FLT2FIX(y));
3792 : else
3793 4 : e = gf_path_add_move_to(gp, FLT2FIX(x), FLT2FIX(y));
3794 5 : if (e) return JS_EXCEPTION;
3795 : return JS_DupValue(c, obj);
3796 : }
3797 1 : static JSValue path_line_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3798 : {
3799 1 : return path_line_move(c, obj, argc, argv, GF_TRUE);
3800 : }
3801 4 : static JSValue path_move_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3802 : {
3803 4 : return path_line_move(c, obj, argc, argv, GF_FALSE);
3804 : }
3805 2 : static JSValue path_cubic_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3806 : {
3807 2 : Double c1_x=0, c1_y=0, c2_x=0, c2_y=0, x=0, y=0;
3808 : GF_Err e;
3809 2 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3810 2 : if (!gp || (argc<6)) return JS_EXCEPTION;
3811 2 : if (JS_ToFloat64(c, &c1_x, argv[0])) return JS_EXCEPTION;
3812 2 : if (JS_ToFloat64(c, &c1_y, argv[1])) return JS_EXCEPTION;
3813 2 : if (JS_ToFloat64(c, &c2_x, argv[2])) return JS_EXCEPTION;
3814 2 : if (JS_ToFloat64(c, &c2_y, argv[3])) return JS_EXCEPTION;
3815 2 : if (JS_ToFloat64(c, &x, argv[4])) return JS_EXCEPTION;
3816 2 : if (JS_ToFloat64(c, &y, argv[5])) return JS_EXCEPTION;
3817 2 : e = gf_path_add_cubic_to(gp, FLT2FIX(c1_x), FLT2FIX(c1_y), FLT2FIX(c2_x), FLT2FIX(c2_y), FLT2FIX(x), FLT2FIX(y));
3818 2 : if (e) return JS_EXCEPTION;
3819 : return JS_DupValue(c, obj);
3820 : }
3821 1 : static JSValue path_quadratic_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3822 : {
3823 1 : Double c_x=0, c_y=0, x=0, y=0;
3824 : GF_Err e;
3825 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3826 1 : if (!gp || (argc<4)) return JS_EXCEPTION;
3827 1 : if (JS_ToFloat64(c, &c_x, argv[0])) return JS_EXCEPTION;
3828 1 : if (JS_ToFloat64(c, &c_y, argv[1])) return JS_EXCEPTION;
3829 1 : if (JS_ToFloat64(c, &x, argv[2])) return JS_EXCEPTION;
3830 1 : if (JS_ToFloat64(c, &y, argv[3])) return JS_EXCEPTION;
3831 1 : e = gf_path_add_quadratic_to(gp, FLT2FIX(c_x), FLT2FIX(c_y), FLT2FIX(x), FLT2FIX(y));
3832 1 : if (e) return JS_EXCEPTION;
3833 : return JS_DupValue(c, obj);
3834 : }
3835 :
3836 12 : static JSValue path_rect(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3837 : {
3838 12 : Double ox=0, oy=0, w=0, h=0;
3839 : s32 idx=0;
3840 : GF_Err e;
3841 :
3842 12 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3843 12 : if (!gp || (argc<3)) return JS_EXCEPTION;
3844 :
3845 24 : if (JS_IsObject(argv[0])) {
3846 : JSValue v;
3847 : #define GETD(_arg, _name, _res)\
3848 : if (! JS_IsObject(_arg)) return JS_EXCEPTION;\
3849 : v = JS_GetPropertyStr(c, _arg, _name);\
3850 : JS_ToFloat64(c, &_res, v);\
3851 : JS_FreeValue(c, v);\
3852 :
3853 0 : GETD(argv[0], "x", ox);
3854 0 : GETD(argv[0], "y", oy);
3855 : #undef GETD
3856 :
3857 : idx=1;
3858 12 : } else if (argc>=4) {
3859 12 : if (JS_ToFloat64(c, &ox, argv[0])) return JS_EXCEPTION;
3860 12 : if (JS_ToFloat64(c, &oy, argv[1])) return JS_EXCEPTION;
3861 : idx=2;
3862 : } else {
3863 0 : return JS_EXCEPTION;
3864 : }
3865 12 : if (JS_ToFloat64(c, &w, argv[idx])) return JS_EXCEPTION;
3866 12 : if (JS_ToFloat64(c, &h, argv[idx+1])) return JS_EXCEPTION;
3867 12 : if ((argc>idx+2) && JS_ToBool(c, argv[idx+2])) {
3868 0 : e = gf_path_add_rect_center(gp, FLT2FIX(ox), FLT2FIX(oy), FLT2FIX(w), FLT2FIX(h));
3869 : } else {
3870 12 : e = gf_path_add_rect(gp, FLT2FIX(ox), FLT2FIX(oy), FLT2FIX(w), FLT2FIX(h));
3871 : }
3872 12 : if (e) return JS_EXCEPTION;
3873 : return JS_DupValue(c, obj);
3874 : }
3875 :
3876 3 : static JSValue path_ellipse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3877 : {
3878 3 : Double cx=0, cy=0, a_axis=0, b_axis=0;
3879 : GF_Err e;
3880 : u32 idx=0;
3881 3 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3882 3 : if (!gp) return JS_EXCEPTION;
3883 3 : if (argc==3) {
3884 : JSValue v;
3885 : #define GETD(_arg, _name, _res)\
3886 : if (! JS_IsObject(_arg)) return JS_EXCEPTION;\
3887 : v = JS_GetPropertyStr(c, _arg, _name);\
3888 : JS_ToFloat64(c, &_res, v);\
3889 : JS_FreeValue(c, v);\
3890 :
3891 0 : GETD(argv[0], "x", cx);
3892 0 : GETD(argv[0], "y", cy);
3893 : #undef GETD
3894 :
3895 : idx=1;
3896 3 : } else if (argc==4) {
3897 3 : if (JS_ToFloat64(c, &cx, argv[0])) return JS_EXCEPTION;
3898 3 : if (JS_ToFloat64(c, &cy, argv[1])) return JS_EXCEPTION;
3899 : idx=2;
3900 : } else {
3901 0 : return JS_EXCEPTION;
3902 : }
3903 3 : if (JS_ToFloat64(c, &a_axis, argv[idx])) return JS_EXCEPTION;
3904 3 : if (JS_ToFloat64(c, &b_axis, argv[idx+1])) return JS_EXCEPTION;
3905 3 : e = gf_path_add_ellipse(gp, FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a_axis), FLT2FIX(b_axis));
3906 3 : if (e) return JS_EXCEPTION;
3907 : return JS_DupValue(c, obj);
3908 : }
3909 :
3910 1 : static JSValue path_bezier(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3911 : {
3912 : GF_Err e;
3913 : s32 i;
3914 : GF_Point2D *pts;
3915 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3916 1 : if (!gp || (argc<3)) return JS_EXCEPTION;
3917 1 : pts = gf_malloc(sizeof(GF_Point2D)* argc);
3918 : memset(pts, 0, sizeof(GF_Point2D)* argc);
3919 7 : for (i=0; i<argc; i++) {
3920 : JSValue v;
3921 : Double d;
3922 12 : if (! JS_IsObject(argv[i]))
3923 0 : continue;
3924 6 : v = JS_GetPropertyStr(c, argv[i], "x");
3925 6 : JS_ToFloat64(c, &d, v);
3926 6 : pts[i].x = FLT2FIX(d);
3927 : JS_FreeValue(c, v);
3928 6 : v = JS_GetPropertyStr(c, argv[i], "y");
3929 6 : JS_ToFloat64(c, &d, v);
3930 6 : pts[i].x = FLT2FIX(d);
3931 : JS_FreeValue(c, v);
3932 : }
3933 1 : e = gf_path_add_bezier(gp, pts, argc);
3934 1 : gf_free(pts);
3935 1 : if (e) return JS_EXCEPTION;
3936 : return JS_DupValue(c, obj);
3937 : }
3938 :
3939 1 : static JSValue path_arc_bifs(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3940 : {
3941 1 : Double end_x=0, end_y=0, fa_x=0, fa_y=0, fb_x=0, fb_y=0;
3942 : Bool cw_flag = GF_FALSE;
3943 : GF_Err e;
3944 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3945 1 : if (!gp || (argc<6)) return JS_EXCEPTION;
3946 1 : if (JS_ToFloat64(c, &end_x, argv[0])) return JS_EXCEPTION;
3947 1 : if (JS_ToFloat64(c, &end_y, argv[1])) return JS_EXCEPTION;
3948 1 : if (JS_ToFloat64(c, &fa_x, argv[2])) return JS_EXCEPTION;
3949 1 : if (JS_ToFloat64(c, &fa_y, argv[3])) return JS_EXCEPTION;
3950 1 : if (JS_ToFloat64(c, &fb_x, argv[4])) return JS_EXCEPTION;
3951 1 : if (JS_ToFloat64(c, &fb_y, argv[5])) return JS_EXCEPTION;
3952 1 : if (argc>6) cw_flag = JS_ToBool(c, argv[6]);
3953 :
3954 1 : e = gf_path_add_svg_arc_to(gp, FLT2FIX(end_x), FLT2FIX(end_y), FLT2FIX(fa_x), FLT2FIX(fa_y), FLT2FIX(fb_x), FLT2FIX(fb_y), cw_flag);
3955 1 : if (e) return JS_EXCEPTION;
3956 : return JS_DupValue(c, obj);
3957 : }
3958 :
3959 :
3960 1 : static JSValue path_arc_svg(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3961 : {
3962 1 : Double end_x=0, end_y=0, r_x=0, r_y=0, x_axis_rotation=0;
3963 : Bool large_arc_flag=GF_FALSE, sweep_flag=GF_FALSE;
3964 : GF_Err e;
3965 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3966 1 : if (!gp || (argc<4)) return JS_EXCEPTION;
3967 1 : if (JS_ToFloat64(c, &end_x, argv[0])) return JS_EXCEPTION;
3968 1 : if (JS_ToFloat64(c, &end_y, argv[1])) return JS_EXCEPTION;
3969 1 : if (JS_ToFloat64(c, &r_x, argv[2])) return JS_EXCEPTION;
3970 1 : if (JS_ToFloat64(c, &r_y, argv[3])) return JS_EXCEPTION;
3971 1 : if (argc>4) {
3972 0 : if (JS_ToFloat64(c, &x_axis_rotation, argv[4])) return JS_EXCEPTION;
3973 0 : if (argc>5) large_arc_flag = JS_ToBool(c, argv[5]);
3974 0 : if (argc>6) sweep_flag = JS_ToBool(c, argv[6]);
3975 : }
3976 1 : e = gf_path_add_svg_arc_to(gp, FLT2FIX(end_x), FLT2FIX(end_y), FLT2FIX(r_x), FLT2FIX(r_y), FLT2FIX(x_axis_rotation), large_arc_flag, sweep_flag);
3977 :
3978 1 : if (e) return JS_EXCEPTION;
3979 : return JS_DupValue(c, obj);
3980 : }
3981 :
3982 1 : static JSValue path_arc(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
3983 : {
3984 1 : Double radius=0, start=0, end=0;
3985 1 : u32 close=0;
3986 : GF_Err e;
3987 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
3988 1 : if (!gp || (argc<3)) return JS_EXCEPTION;
3989 1 : if (JS_ToFloat64(c, &radius, argv[0])) return JS_EXCEPTION;
3990 1 : if (JS_ToFloat64(c, &start, argv[1])) return JS_EXCEPTION;
3991 1 : if (JS_ToFloat64(c, &end, argv[2])) return JS_EXCEPTION;
3992 1 : if (argc>3)
3993 0 : if (JS_ToInt32(c, &close, argv[3])) return JS_EXCEPTION;
3994 1 : e = gf_path_add_arc(gp, FLT2FIX(radius), FLT2FIX(start), FLT2FIX(end), close);
3995 1 : if (e) return JS_EXCEPTION;
3996 : return JS_DupValue(c, obj);
3997 : }
3998 :
3999 1 : static JSValue path_add_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4000 : {
4001 : GF_Err e;
4002 : GF_Matrix2D *mx=NULL;
4003 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4004 1 : if (!gp || !argc) return JS_EXCEPTION;
4005 1 : GF_Path *subgp = JS_GetOpaque(argv[0], path_class_id);
4006 1 : if (!gp) return JS_EXCEPTION;
4007 1 : if (argc>1)
4008 0 : mx = JS_GetOpaque(argv[1], mx2d_class_id);
4009 1 : e = gf_path_add_subpath(gp, subgp, mx);
4010 1 : if (e) return JS_EXCEPTION;
4011 : return JS_DupValue(c, obj);
4012 : }
4013 :
4014 1 : static JSValue path_flatten(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4015 : {
4016 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4017 1 : if (!gp) return JS_EXCEPTION;
4018 1 : gf_path_flatten(gp);
4019 : return JS_DupValue(c, obj);
4020 : }
4021 1 : static JSValue path_get_flat(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4022 : {
4023 : JSValue nobj;
4024 : GF_Path *gp_flat;
4025 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4026 1 : if (!gp) return JS_EXCEPTION;
4027 1 : gp_flat = gf_path_get_flatten(gp);
4028 : if (!gp) return JS_NULL;
4029 1 : nobj = JS_NewObjectClass(c, path_class_id);
4030 1 : if (JS_IsException(nobj)) return nobj;
4031 1 : JS_SetOpaque(nobj, gp_flat);
4032 1 : return nobj;
4033 : }
4034 :
4035 1 : static JSValue path_point_over(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4036 : {
4037 : Double x, y;
4038 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4039 1 : if (!gp || !argc) return JS_EXCEPTION;
4040 1 : if (argc==1) {
4041 : Double d;
4042 : int res;
4043 : JSValue v;
4044 0 : if (!JS_IsObject(argv[0])) return JS_EXCEPTION;
4045 : #define GETIT(_arg, _name, _var) \
4046 : v = JS_GetPropertyStr(c, _arg, _name);\
4047 : res = JS_ToFloat64(c, &d, v);\
4048 : JS_FreeValue(c, v);\
4049 : if (res) return JS_EXCEPTION;\
4050 : _var = FLT2FIX(d);\
4051 :
4052 0 : GETIT(argv[0], "x", x)
4053 0 : GETIT(argv[0], "y", y)
4054 : #undef GETIT
4055 1 : } else if (argc==2) {
4056 1 : if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
4057 1 : if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
4058 : } else {
4059 0 : return JS_EXCEPTION;
4060 : }
4061 1 : return JS_NewBool(c, gf_path_point_over(gp, FLT2FIX(x), FLT2FIX(y)));
4062 : }
4063 :
4064 :
4065 3 : static JSValue path_outline(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4066 : {
4067 : GF_Path *outline;
4068 : GF_PenSettings pen;
4069 : GF_DashSettings dash;
4070 : JSValue v, dashes;
4071 : Double d;
4072 : int i, res;
4073 3 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4074 6 : if (!gp || !argc || !JS_IsObject(argv[0]) ) return JS_EXCEPTION;
4075 : memset(&pen, 0, sizeof(GF_PenSettings));
4076 :
4077 : #define GETIT_F(_arg, _name, _var) \
4078 : v = JS_GetPropertyStr(c, _arg, _name);\
4079 : if (!JS_IsUndefined(v)) {\
4080 : res = JS_ToFloat64(c, &d, v);\
4081 : JS_FreeValue(c, v);\
4082 : if (res) return JS_EXCEPTION;\
4083 : _var = FLT2FIX(d);\
4084 : }\
4085 :
4086 : #define GETIT_I(_arg, _name, _var) \
4087 : v = JS_GetPropertyStr(c, _arg, _name);\
4088 : if (!JS_IsUndefined(v)) {\
4089 : res = JS_ToInt32(c, &i, v);\
4090 : JS_FreeValue(c, v);\
4091 : if (res) return JS_EXCEPTION;\
4092 : _var = i;\
4093 : }\
4094 :
4095 9 : GETIT_F(argv[0], "width", pen.width);
4096 6 : GETIT_F(argv[0], "miter", pen.miterLimit);
4097 6 : GETIT_F(argv[0], "offset", pen.dash_offset);
4098 6 : GETIT_F(argv[0], "length", pen.path_length);
4099 6 : GETIT_I(argv[0], "cap", pen.cap);
4100 8 : GETIT_I(argv[0], "join", pen.join);
4101 8 : GETIT_I(argv[0], "align", pen.align);
4102 8 : GETIT_I(argv[0], "dash", pen.dash);
4103 :
4104 :
4105 : #undef GETTIT_F
4106 : #undef GETTIT_I
4107 :
4108 3 : dash.num_dash = 0;
4109 3 : dash.dashes = NULL;
4110 3 : dashes = JS_GetPropertyStr(c, argv[0], "dashes");
4111 3 : if (JS_IsArray(c, dashes) && !JS_IsNull(v)) {
4112 2 : v = JS_GetPropertyStr(c, dashes, "length");
4113 2 : JS_ToInt32(c, &dash.num_dash, v);
4114 : JS_FreeValue(c, v);
4115 2 : pen.dash_set = ‐
4116 2 : dash.dashes = gf_malloc(sizeof(Fixed)*dash.num_dash);
4117 10 : for (i=0; i<(int) dash.num_dash; i++) {
4118 8 : v = JS_GetPropertyUint32(c, dashes, i);
4119 8 : JS_ToFloat64(c, &d, v);
4120 8 : dash.dashes[i] = FLT2FIX(d);
4121 : JS_FreeValue(c, v);
4122 : }
4123 : }
4124 : JS_FreeValue(c, dashes);
4125 :
4126 3 : outline = gf_path_get_outline(gp, pen);
4127 3 : if (dash.dashes) gf_free(dash.dashes);
4128 :
4129 3 : if (!outline) return JS_EXCEPTION;
4130 3 : v = JS_NewObjectClass(c, path_class_id);
4131 3 : JS_SetOpaque(v, outline);
4132 3 : return v;
4133 : }
4134 :
4135 : enum
4136 : {
4137 : PATH_EMPTY=0,
4138 : PATH_ZERO_NONZERO,
4139 : PATH_BOUNDS,
4140 : PATH_CONTROL_BOUNDS,
4141 : };
4142 :
4143 :
4144 1 : static JSValue path_bounds_ex(JSContext *c, GF_Path *gp, Bool is_ctrl)
4145 : {
4146 : JSValue nobj;
4147 : GF_Err e;
4148 : GF_Rect rc;
4149 1 : if (is_ctrl)
4150 0 : e = gf_path_get_control_bounds(gp, &rc);
4151 : else
4152 1 : e = gf_path_get_bounds(gp, &rc);
4153 1 : if (e) return JS_EXCEPTION;
4154 1 : nobj = JS_NewObject(c);
4155 2 : JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, rc.x));
4156 2 : JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, rc.y));
4157 2 : JS_SetPropertyStr(c, nobj, "w", JS_NewFloat64(c, rc.width));
4158 2 : JS_SetPropertyStr(c, nobj, "h", JS_NewFloat64(c, rc.height));
4159 1 : return nobj;
4160 : }
4161 1 : static JSValue path_getProperty(JSContext *c, JSValueConst obj, int magic)
4162 : {
4163 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4164 1 : if (!gp) return JS_EXCEPTION;
4165 1 : switch (magic) {
4166 0 : case PATH_EMPTY: return JS_NewBool(c, gf_path_is_empty(gp));
4167 0 : case PATH_ZERO_NONZERO: return JS_NewBool(c, gp->flags & GF_PATH_FILL_ZERO_NONZERO);
4168 1 : case PATH_BOUNDS: return path_bounds_ex(c, gp, GF_FALSE);
4169 0 : case PATH_CONTROL_BOUNDS: return path_bounds_ex(c, gp, GF_TRUE);
4170 : }
4171 0 : return JS_UNDEFINED;
4172 : }
4173 1 : static JSValue path_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
4174 : {
4175 1 : GF_Path *gp = JS_GetOpaque(obj, path_class_id);
4176 1 : if (!gp) return JS_EXCEPTION;
4177 1 : switch (magic) {
4178 1 : case PATH_ZERO_NONZERO:
4179 1 : if (JS_ToBool(c, value))
4180 0 : gp->flags |= GF_PATH_FILL_ZERO_NONZERO;
4181 : else
4182 1 : gp->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
4183 : }
4184 1 : return JS_UNDEFINED;
4185 : }
4186 13 : static JSValue path_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
4187 : {
4188 : JSValue obj;
4189 13 : GF_Path *path = gf_path_new();
4190 13 : if (!path) return JS_EXCEPTION;
4191 13 : obj = JS_NewObjectClass(c, path_class_id);
4192 13 : if (JS_IsException(obj)) return obj;
4193 13 : JS_SetOpaque(obj, path);
4194 13 : return obj;
4195 : }
4196 : static const JSCFunctionListEntry path_funcs[] =
4197 : {
4198 : JS_CGETSET_MAGIC_DEF("empty", path_getProperty, NULL, PATH_EMPTY),
4199 : JS_CGETSET_MAGIC_DEF("zero_fill", path_getProperty, path_setProperty, PATH_ZERO_NONZERO),
4200 : JS_CGETSET_MAGIC_DEF("bounds", path_getProperty, NULL, PATH_BOUNDS),
4201 : JS_CGETSET_MAGIC_DEF("ctrl_bounds", path_getProperty, NULL, PATH_CONTROL_BOUNDS),
4202 :
4203 : JS_CFUNC_DEF("point_over", 0, path_point_over),
4204 : JS_CFUNC_DEF("get_flatten", 0, path_get_flat),
4205 : JS_CFUNC_DEF("flatten", 0, path_flatten),
4206 : JS_CFUNC_DEF("add_path", 0, path_add_path),
4207 : JS_CFUNC_DEF("arc", 0, path_arc),
4208 : JS_CFUNC_DEF("arc_svg", 0, path_arc_svg),
4209 : JS_CFUNC_DEF("arc_bifs", 0, path_arc_bifs),
4210 : JS_CFUNC_DEF("bezier", 0, path_bezier),
4211 : JS_CFUNC_DEF("ellipse", 0, path_ellipse),
4212 : JS_CFUNC_DEF("rectangle", 0, path_rect),
4213 : JS_CFUNC_DEF("quadratic_to", 0, path_quadratic_to),
4214 : JS_CFUNC_DEF("cubic_to", 0, path_cubic_to),
4215 : JS_CFUNC_DEF("line_to", 0, path_line_to),
4216 : JS_CFUNC_DEF("move_to", 0, path_move_to),
4217 : JS_CFUNC_DEF("clone", 0, path_clone),
4218 : JS_CFUNC_DEF("reset", 0, path_reset),
4219 : JS_CFUNC_DEF("close", 0, path_close),
4220 : JS_CFUNC_DEF("outline", 0, path_outline),
4221 :
4222 : };
4223 :
4224 :
4225 44 : static void stencil_finalize(JSRuntime *rt, JSValue obj)
4226 : {
4227 44 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4228 44 : if (!stencil) return;
4229 44 : gf_evg_stencil_delete(stencil);
4230 : }
4231 : JSClassDef stencil_class = {
4232 : "Stencil",
4233 : .finalizer = stencil_finalize
4234 : };
4235 :
4236 : enum
4237 : {
4238 : STENCIL_CMX,
4239 : STENCIL_MAT,
4240 : STENCIL_GRADMOD,
4241 : };
4242 :
4243 1 : static JSValue stencil_set_linear(JSContext *c, GF_EVGStencil *stencil, int argc, JSValueConst *argv)
4244 : {
4245 : int res;
4246 : JSValue v;
4247 : Double d;
4248 : Fixed start_x=0, start_y=0, end_x=0, end_y=0;
4249 : s32 idx=0;
4250 1 : if (argc<2) return JS_EXCEPTION;
4251 :
4252 : #define GETIT(_arg, _name, _var) \
4253 : v = JS_GetPropertyStr(c, _arg, _name);\
4254 : res = JS_ToFloat64(c, &d, v);\
4255 : JS_FreeValue(c, v);\
4256 : if (res) return JS_EXCEPTION;\
4257 : _var = FLT2FIX(d);\
4258 :
4259 2 : if (JS_IsObject(argv[0])) {
4260 0 : GETIT(argv[0], "x", start_x)
4261 0 : GETIT(argv[0], "y", start_y)
4262 : idx=1;
4263 : } else {
4264 1 : if (JS_ToFloat64(c, &d, argv[0])) return JS_EXCEPTION;
4265 1 : start_x = FLT2FIX(d);
4266 1 : if (JS_ToFloat64(c, &d, argv[1])) return JS_EXCEPTION;
4267 1 : start_y = FLT2FIX(d);
4268 : idx=2;
4269 : }
4270 1 : if (argc<=idx) {
4271 : end_x = start_x;
4272 : end_y = start_y;
4273 : start_x = 0;
4274 : start_y = 0;
4275 2 : } else if (JS_IsObject(argv[idx])) {
4276 0 : GETIT(argv[idx], "x", end_x)
4277 0 : GETIT(argv[idx], "y", end_y)
4278 1 : } else if (argc>idx+1) {
4279 1 : if (JS_ToFloat64(c, &d, argv[idx])) return JS_EXCEPTION;
4280 1 : end_x = FLT2FIX(d);
4281 1 : if (JS_ToFloat64(c, &d, argv[idx+1])) return JS_EXCEPTION;
4282 1 : end_y = FLT2FIX(d);
4283 : }
4284 : #undef GETIT
4285 1 : gf_evg_stencil_set_linear_gradient(stencil, start_x, start_y, end_x, end_y);
4286 1 : return JS_UNDEFINED;
4287 : }
4288 :
4289 6 : static JSValue stencil_set_radial(JSContext *c, GF_EVGStencil *stencil, int argc, JSValueConst *argv)
4290 : {
4291 : int res;
4292 : JSValue v;
4293 : Double d;
4294 : Fixed cx=0, cy=0, fx=0, fy=0, rx=0, ry=0;
4295 : s32 idx=0;
4296 6 : if (argc<3) return JS_EXCEPTION;
4297 :
4298 : #define GETIT(_arg, _name, _var) \
4299 : v = JS_GetPropertyStr(c, _arg, _name);\
4300 : res = JS_ToFloat64(c, &d, v);\
4301 : JS_FreeValue(c, v);\
4302 : if (res) return JS_EXCEPTION;\
4303 : _var = FLT2FIX(d);\
4304 :
4305 12 : if (JS_IsObject(argv[0])) {
4306 0 : GETIT(argv[0], "x", cx)
4307 0 : GETIT(argv[0], "y", cy)
4308 : idx+=1;
4309 : } else {
4310 6 : if (JS_ToFloat64(c, &d, argv[0])) return JS_EXCEPTION;
4311 6 : cx = FLT2FIX(d);
4312 6 : if (JS_ToFloat64(c, &d, argv[1])) return JS_EXCEPTION;
4313 6 : cy = FLT2FIX(d);
4314 : idx+=2;
4315 : }
4316 :
4317 12 : if (JS_IsObject(argv[idx])) {
4318 0 : GETIT(argv[idx], "x", fx)
4319 0 : GETIT(argv[idx], "y", fy)
4320 0 : idx+=1;
4321 6 : } else if (argc>idx+1) {
4322 6 : if (JS_ToFloat64(c, &d, argv[idx])) return JS_EXCEPTION;
4323 6 : fx = FLT2FIX(d);
4324 6 : if (JS_ToFloat64(c, &d, argv[idx+1])) return JS_EXCEPTION;
4325 6 : fy = FLT2FIX(d);
4326 6 : idx+=2;
4327 : }
4328 :
4329 12 : if (JS_IsObject(argv[idx])) {
4330 0 : GETIT(argv[idx], "x", rx)
4331 0 : GETIT(argv[idx], "y", ry)
4332 6 : } else if (argc>idx+1) {
4333 6 : if (JS_ToFloat64(c, &d, argv[idx])) return JS_EXCEPTION;
4334 6 : rx = FLT2FIX(d);
4335 6 : if (JS_ToFloat64(c, &d, argv[idx+1])) return JS_EXCEPTION;
4336 6 : ry = FLT2FIX(d);
4337 : }
4338 : #undef GETIT
4339 6 : gf_evg_stencil_set_radial_gradient(stencil, cx, cy, fx, fy, rx, ry);
4340 6 : return JS_UNDEFINED;
4341 : }
4342 :
4343 :
4344 7 : static JSValue stencil_set_points(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4345 : {
4346 : GF_StencilType type;
4347 7 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4348 7 : if (!stencil) return JS_EXCEPTION;
4349 :
4350 7 : type = gf_evg_stencil_type(stencil);
4351 7 : if (type==GF_STENCIL_LINEAR_GRADIENT)
4352 1 : return stencil_set_linear(c, stencil, argc, argv);
4353 6 : if (type==GF_STENCIL_RADIAL_GRADIENT)
4354 6 : return stencil_set_radial(c, stencil, argc, argv);
4355 0 : return JS_EXCEPTION;
4356 : }
4357 :
4358 132 : Bool get_color_from_args(JSContext *c, int argc, JSValueConst *argv, u32 idx, Double *a, Double *r, Double *g, Double *b)
4359 : {
4360 132 : if (argc<(s32) idx) return GF_FALSE;
4361 264 : if (JS_IsString(argv[idx])) {
4362 : GF_Color col;
4363 : const char *str = JS_ToCString(c, argv[idx]);
4364 0 : col = gf_color_parse(str);
4365 0 : JS_FreeCString(c, str);
4366 0 : *a = ((Double)GF_COL_A(col)) / 255;
4367 0 : *r = ((Double)GF_COL_R(col)) / 255;
4368 0 : *g = ((Double)GF_COL_G(col)) / 255;
4369 0 : *b = ((Double)GF_COL_B(col)) / 255;
4370 132 : } else if (JS_IsObject(argv[idx])) {
4371 102 : if (!get_color(c, argv[idx], a, r, g, b)) {
4372 : return GF_FALSE;
4373 : }
4374 30 : } else if (argc>(s32) idx) {
4375 30 : if (JS_ToFloat64(c, r, argv[idx]))
4376 : return GF_FALSE;
4377 30 : if (argc>(s32)idx+1) {
4378 30 : if (JS_ToFloat64(c, g, argv[idx+1]))
4379 : return GF_FALSE;
4380 30 : if (argc>(s32) idx+2) {
4381 30 : if (JS_ToFloat64(c, b, argv[idx+2]))
4382 : return GF_FALSE;
4383 30 : if (argc>(s32)idx+3) {
4384 28 : if (JS_ToFloat64(c, a, argv[idx+3]))
4385 : return GF_FALSE;
4386 : }
4387 : }
4388 : }
4389 : }
4390 : return GF_TRUE;
4391 : }
4392 :
4393 27 : static JSValue stencil_set_stop_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int)
4394 : {
4395 27 : Double pos=0;
4396 : GF_StencilType type;
4397 : GF_Color col;
4398 27 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4399 27 : if (!stencil) return JS_EXCEPTION;
4400 27 : type = gf_evg_stencil_type(stencil);
4401 27 : if ((type!=GF_STENCIL_LINEAR_GRADIENT) && (type!=GF_STENCIL_RADIAL_GRADIENT)) return JS_EXCEPTION;
4402 27 : if (!argc) {
4403 0 : gf_evg_stencil_set_gradient_interpolation(stencil, NULL, NULL, 0);
4404 0 : return JS_UNDEFINED;
4405 : }
4406 27 : if (JS_ToFloat64(c, &pos, argv[0])) return JS_EXCEPTION;
4407 :
4408 54 : if (JS_IsString(argv[1])) {
4409 : const char *str = JS_ToCString(c, argv[1]);
4410 1 : col = gf_color_parse(str);
4411 1 : JS_FreeCString(c, str);
4412 : } else {
4413 26 : Double r=0, g=0, b=0, a=1.0;
4414 26 : if (!get_color_from_args(c, argc, argv, 1, &a, &r, &g, &b)) {
4415 0 : return JS_EXCEPTION;
4416 : }
4417 26 : if (!use_int) {
4418 26 : a *= 255;
4419 26 : r *= 255;
4420 26 : g *= 255;
4421 26 : b *= 255;
4422 : }
4423 26 : col = GF_COL_ARGB(a, r, g, b);
4424 : }
4425 27 : gf_evg_stencil_push_gradient_interpolation(stencil, FLT2FIX(pos), col);
4426 27 : return JS_UNDEFINED;
4427 : }
4428 1 : static JSValue stencil_set_stop(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4429 : {
4430 1 : return stencil_set_stop_ex(c, obj, argc, argv, GF_TRUE);
4431 : }
4432 26 : static JSValue stencil_set_stopf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4433 : {
4434 26 : return stencil_set_stop_ex(c, obj, argc, argv, GF_FALSE);
4435 : }
4436 :
4437 538 : static JSValue stencil_set_color_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int)
4438 : {
4439 538 : Double r=0, g=0, b=0, a=1.0;
4440 : GF_StencilType type;
4441 538 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4442 538 : if (!stencil) return JS_EXCEPTION;
4443 538 : type = gf_evg_stencil_type(stencil);
4444 538 : if (type!=GF_STENCIL_SOLID) return JS_EXCEPTION;
4445 :
4446 1076 : if (JS_IsString(argv[0])) {
4447 : GF_Color col;
4448 : const char *str = JS_ToCString(c, argv[0]);
4449 436 : col = gf_color_parse(str);
4450 436 : JS_FreeCString(c, str);
4451 436 : gf_evg_stencil_set_brush_color(stencil, col);
4452 436 : return JS_UNDEFINED;
4453 102 : } else if (!get_color_from_args(c, argc, argv, 0, &a, &r, &g, &b)) {
4454 0 : return JS_EXCEPTION;
4455 : }
4456 102 : if (!use_int) {
4457 2 : r*=255;
4458 2 : g*=255;
4459 2 : b*=255;
4460 2 : a*=255;
4461 : }
4462 102 : gf_evg_stencil_set_brush_color(stencil, GF_COL_ARGB(a, r, g, b));
4463 102 : return JS_UNDEFINED;
4464 : }
4465 :
4466 536 : static JSValue stencil_set_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4467 : {
4468 536 : return stencil_set_color_ex(c, obj, argc, argv, GF_TRUE);
4469 : }
4470 2 : static JSValue stencil_set_colorf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4471 : {
4472 2 : return stencil_set_color_ex(c, obj, argc, argv, GF_FALSE);
4473 : }
4474 :
4475 101 : static JSValue stencil_set_alpha_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int)
4476 : {
4477 101 : Double a=1.0;
4478 101 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4479 101 : if (!stencil) {
4480 100 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4481 100 : if (!tx || !tx->stencil)
4482 0 : return JS_EXCEPTION;
4483 : stencil = tx->stencil;
4484 : }
4485 :
4486 101 : if (argc) {
4487 101 : JS_ToFloat64(c, &a, argv[0]);
4488 : }
4489 101 : if (a<0) a=0;
4490 101 : if (!use_int) {
4491 100 : a*=255;
4492 : }
4493 101 : if (a>255) a = 255;
4494 101 : gf_evg_stencil_set_alpha(stencil, (u8) a);
4495 101 : return JS_UNDEFINED;
4496 : }
4497 :
4498 1 : static JSValue stencil_set_alpha(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4499 : {
4500 1 : return stencil_set_alpha_ex(c, obj, argc, argv, GF_TRUE);
4501 : }
4502 100 : static JSValue stencil_set_alphaf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4503 : {
4504 100 : return stencil_set_alpha_ex(c, obj, argc, argv, GF_FALSE);
4505 : }
4506 :
4507 1 : static JSValue stencil_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
4508 : {
4509 : u32 v;
4510 1 : GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id);
4511 1 : if (!stencil) return JS_EXCEPTION;
4512 :
4513 1 : switch (magic) {
4514 0 : case STENCIL_CMX:
4515 0 : if (JS_IsNull(value)) {
4516 0 : gf_evg_stencil_set_color_matrix(stencil, NULL);
4517 : } else {
4518 0 : GF_ColorMatrix *cmx = JS_GetOpaque(value, colmx_class_id);
4519 0 : gf_evg_stencil_set_color_matrix(stencil, cmx);
4520 : }
4521 0 : return JS_UNDEFINED;
4522 1 : case STENCIL_GRADMOD:
4523 1 : if (JS_ToInt32(c, &v, value)) return JS_EXCEPTION;
4524 1 : gf_evg_stencil_set_gradient_mode(stencil, v);
4525 1 : return JS_UNDEFINED;
4526 0 : case STENCIL_MAT:
4527 0 : if (JS_IsNull(value)) {
4528 0 : gf_evg_stencil_set_matrix(stencil, NULL);
4529 : } else {
4530 0 : GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id);
4531 0 : gf_evg_stencil_set_matrix(stencil, mx);
4532 : }
4533 0 : return JS_UNDEFINED;
4534 : }
4535 0 : return JS_UNDEFINED;
4536 : }
4537 :
4538 : static const JSCFunctionListEntry stencil_funcs[] =
4539 : {
4540 : JS_CGETSET_MAGIC_DEF("pad", NULL, stencil_setProperty, STENCIL_GRADMOD),
4541 : JS_CGETSET_MAGIC_DEF("cmx", NULL, stencil_setProperty, STENCIL_CMX),
4542 : JS_CGETSET_MAGIC_DEF("mx", NULL, stencil_setProperty, STENCIL_MAT),
4543 : JS_CFUNC_DEF("set_color", 0, stencil_set_color),
4544 : JS_CFUNC_DEF("set_colorf", 0, stencil_set_colorf),
4545 : JS_CFUNC_DEF("set_alpha", 0, stencil_set_alpha),
4546 : JS_CFUNC_DEF("set_alphaf", 0, stencil_set_alphaf),
4547 : JS_CFUNC_DEF("set_points", 0, stencil_set_points),
4548 : JS_CFUNC_DEF("set_stop", 0, stencil_set_stop),
4549 : JS_CFUNC_DEF("set_stopf", 0, stencil_set_stopf),
4550 : };
4551 :
4552 :
4553 44 : static JSValue stencil_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv, GF_StencilType type)
4554 : {
4555 : JSValue obj;
4556 44 : GF_EVGStencil *stencil = gf_evg_stencil_new(type);
4557 44 : if (!stencil) return JS_EXCEPTION;
4558 44 : obj = JS_NewObjectClass(c, stencil_class_id);
4559 44 : if (JS_IsException(obj)) return obj;
4560 44 : JS_SetOpaque(obj, stencil);
4561 44 : return obj;
4562 : }
4563 37 : static JSValue solid_brush_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
4564 : {
4565 37 : return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_SOLID);
4566 : }
4567 1 : static JSValue linear_gradient_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
4568 : {
4569 1 : return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_LINEAR_GRADIENT);
4570 : }
4571 6 : static JSValue radial_gradient_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
4572 : {
4573 6 : return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_RADIAL_GRADIENT);
4574 : }
4575 :
4576 133 : static void texture_reset(GF_JSTexture *tx)
4577 : {
4578 133 : if (tx->owns_data && tx->data) {
4579 22 : gf_free(tx->data);
4580 : }
4581 133 : tx->data = NULL;
4582 133 : tx->data_size = 0;
4583 133 : tx->owns_data = GF_FALSE;
4584 133 : }
4585 :
4586 133 : static void texture_finalize(JSRuntime *rt, JSValue obj)
4587 : {
4588 133 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4589 133 : if (!tx) return;
4590 133 : texture_reset(tx);
4591 133 : if (tx->stencil)
4592 133 : gf_evg_stencil_delete(tx->stencil);
4593 : JS_FreeValueRT(rt, tx->param_fun);
4594 133 : gf_free(tx);
4595 : }
4596 :
4597 16 : static void texture_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func)
4598 : {
4599 16 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4600 16 : if (!tx) return;
4601 16 : JS_MarkValue(rt, tx->param_fun, mark_func);
4602 : }
4603 :
4604 : JSClassDef texture_class = {
4605 : "Texture",
4606 : .finalizer = texture_finalize,
4607 : .gc_mark = texture_gc_mark
4608 : };
4609 :
4610 : enum
4611 : {
4612 : TX_MAPPING = 0,
4613 : TX_FILTER,
4614 : TX_CMX,
4615 : TX_REPEAT_S,
4616 : TX_REPEAT_T,
4617 : TX_FLIP_X,
4618 : TX_FLIP_Y,
4619 : TX_MAT,
4620 : TX_WIDTH,
4621 : TX_HEIGHT,
4622 : TX_NB_COMP,
4623 : TX_PIXFMT,
4624 : TX_DATA,
4625 : };
4626 :
4627 432 : static JSValue texture_getProperty(JSContext *c, JSValueConst obj, int magic)
4628 : {
4629 432 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4630 432 : if (!tx || !tx->stencil) return JS_EXCEPTION;
4631 432 : switch (magic) {
4632 0 : case TX_REPEAT_S:
4633 0 : return JS_NewBool(c, (tx->flags & GF_TEXTURE_REPEAT_S));
4634 0 : case TX_REPEAT_T:
4635 0 : return JS_NewBool(c, (tx->flags & GF_TEXTURE_REPEAT_T));
4636 0 : case TX_FLIP_X:
4637 0 : return JS_NewBool(c, (tx->flags & GF_TEXTURE_FLIP_X));
4638 0 : case TX_FLIP_Y:
4639 0 : return JS_NewBool(c, (tx->flags & GF_TEXTURE_FLIP_Y));
4640 221 : case TX_WIDTH:
4641 221 : return JS_NewInt32(c, tx->width);
4642 211 : case TX_HEIGHT:
4643 211 : return JS_NewInt32(c, tx->height);
4644 0 : case TX_PIXFMT:
4645 0 : return JS_NewInt32(c, tx->pf);
4646 0 : case TX_NB_COMP:
4647 0 : return JS_NewInt32(c, tx->nb_comp);
4648 0 : case TX_DATA:
4649 0 : if (tx->owns_data)
4650 0 : return JS_NewArrayBuffer(c, (u8 *) tx->data, tx->data_size, NULL, NULL, GF_TRUE);
4651 0 : return JS_NULL;
4652 : }
4653 0 : return JS_UNDEFINED;
4654 : }
4655 251 : static JSValue texture_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
4656 : {
4657 : u32 v;
4658 251 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4659 251 : if (!tx || !tx->stencil) return JS_EXCEPTION;
4660 :
4661 251 : switch (magic) {
4662 4 : case TX_FILTER:
4663 4 : if (JS_ToInt32(c, &v, value)) return JS_EXCEPTION;
4664 4 : gf_evg_stencil_set_filter(tx->stencil, v);
4665 4 : return JS_UNDEFINED;
4666 1 : case TX_CMX:
4667 1 : if (JS_IsNull(value)) {
4668 0 : gf_evg_stencil_set_color_matrix(tx->stencil, NULL);
4669 : } else {
4670 1 : GF_ColorMatrix *cmx = JS_GetOpaque(value, colmx_class_id);
4671 1 : gf_evg_stencil_set_color_matrix(tx->stencil, cmx);
4672 : }
4673 1 : return JS_UNDEFINED;
4674 16 : case TX_REPEAT_S:
4675 16 : if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_REPEAT_S;
4676 0 : else tx->flags &= ~GF_TEXTURE_REPEAT_S;
4677 16 : gf_evg_stencil_set_mapping(tx->stencil, tx->flags);
4678 16 : return JS_UNDEFINED;
4679 16 : case TX_REPEAT_T:
4680 16 : if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_REPEAT_T;
4681 0 : else tx->flags &= ~GF_TEXTURE_REPEAT_T;
4682 16 : gf_evg_stencil_set_mapping(tx->stencil, tx->flags);
4683 16 : return JS_UNDEFINED;
4684 0 : case TX_FLIP_X:
4685 0 : if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_FLIP_X;
4686 0 : else tx->flags &= ~GF_TEXTURE_FLIP_X;
4687 0 : gf_evg_stencil_set_mapping(tx->stencil, tx->flags);
4688 0 : return JS_UNDEFINED;
4689 3 : case TX_FLIP_Y:
4690 3 : if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_FLIP_Y;
4691 0 : else tx->flags &= ~GF_TEXTURE_FLIP_Y;
4692 3 : gf_evg_stencil_set_mapping(tx->stencil, tx->flags);
4693 3 : return JS_UNDEFINED;
4694 211 : case TX_MAT:
4695 211 : if (JS_IsNull(value)) {
4696 0 : gf_evg_stencil_set_matrix(tx->stencil, NULL);
4697 : } else {
4698 211 : GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id);
4699 211 : gf_evg_stencil_set_matrix(tx->stencil, mx);
4700 : }
4701 211 : return JS_UNDEFINED;
4702 : }
4703 0 : return JS_UNDEFINED;
4704 : }
4705 :
4706 :
4707 : #define min_f(a, b, c) (fminf(a, fminf(b, c)))
4708 : #define max_f(a, b, c) (fmaxf(a, fmaxf(b, c)))
4709 :
4710 16384 : void rgb2hsv(const u8 src_r, const u8 src_g, const u8 src_b, u8 *dst_h, u8 *dst_s, u8 *dst_v)
4711 : {
4712 : float h, s, v; // h:0-360.0, s:0.0-1.0, v:0.0-1.0
4713 16384 : float r = src_r / 255.0f;
4714 16384 : float g = src_g / 255.0f;
4715 16384 : float b = src_b / 255.0f;
4716 :
4717 16384 : float max = max_f(r, g, b);
4718 16384 : float min = min_f(r, g, b);
4719 :
4720 : v = max;
4721 16384 : if (max == 0.0f) {
4722 : s = 0;
4723 : h = 0;
4724 16020 : } else if (max - min == 0.0f) {
4725 : s = 0;
4726 : h = 0;
4727 : } else {
4728 3667 : s = (max - min) / max;
4729 :
4730 3667 : if (max == r) {
4731 3340 : h = 60 * ((g - b) / (max - min)) + 0;
4732 327 : } else if (max == g) {
4733 323 : h = 60 * ((b - r) / (max - min)) + 120;
4734 : } else {
4735 4 : h = 60 * ((r - g) / (max - min)) + 240;
4736 : }
4737 : }
4738 16384 : if (h < 0) h += 360.0f;
4739 :
4740 16384 : *dst_h = (u8)(h / 2); // dst_h : 0-180
4741 16384 : *dst_s = (u8)(s * 255); // dst_s : 0-255
4742 16384 : *dst_v = (u8)(v * 255); // dst_v : 0-255
4743 16384 : }
4744 :
4745 16384 : void hsv2rgb(u8 src_h, u8 src_s, u8 src_v, u8 *dst_r, u8 *dst_g, u8 *dst_b)
4746 : {
4747 : float r, g, b; // 0.0-1.0
4748 16384 : float h = src_h * 2.0f; // 0-360
4749 16384 : float s = src_s / 255.0f; // 0.0-1.0
4750 16384 : float v = src_v / 255.0f; // 0.0-1.0
4751 :
4752 16384 : int hi = (int)(h / 60.0f) % 6;
4753 16384 : float f = (h / 60.0f) - hi;
4754 16384 : float p = v * (1.0f - s);
4755 16384 : float q = v * (1.0f - s * f);
4756 16384 : float t = v * (1.0f - s * (1.0f - f));
4757 :
4758 16384 : switch(hi) {
4759 : case 0: r = v; g = t; b = p; break;
4760 3 : case 1: r = q; g = v; b = p; break;
4761 47 : case 2: r = p; g = v; b = t; break;
4762 277 : case 3: r = p; g = q; b = v; break;
4763 3 : case 4: r = t; g = p; b = v; break;
4764 173 : case 5:
4765 : default:
4766 173 : r = v; g = p; b = q; break;
4767 : }
4768 :
4769 16384 : *dst_r = (u8)(r * 255); // dst_r : 0-255
4770 16384 : *dst_g = (u8)(g * 255); // dst_r : 0-255
4771 16384 : *dst_b = (u8)(b * 255); // dst_r : 0-255
4772 16384 : }
4773 :
4774 : enum
4775 : {
4776 : EVG_CONV_RGB_TO_HSV=0,
4777 : EVG_CONV_HSV_TO_RGB,
4778 : EVG_CONV_YUV_TO_RGB,
4779 : EVG_CONV_RGB_TO_YUV,
4780 : };
4781 :
4782 4 : static JSValue texture_convert(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 conv_type)
4783 : {
4784 : JSValue nobj;
4785 : u32 i, j, dst_pf, nb_comp;
4786 : GF_JSCanvas *canvas=NULL;
4787 : GF_JSTexture *tx_hsv;
4788 4 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4789 4 : if (!tx || !tx->stencil) return JS_EXCEPTION;
4790 4 : if (argc) {
4791 2 : canvas = JS_GetOpaque(argv[0], canvas_class_id);
4792 2 : if (!canvas)
4793 1 : canvas = JS_GetOpaque(argv[0], canvas3d_class_id);
4794 : }
4795 4 : if ((conv_type==EVG_CONV_YUV_TO_RGB) || (conv_type==EVG_CONV_RGB_TO_YUV)) {
4796 2 : if (!canvas) return js_throw_err_msg(c, GF_BAD_PARAM, "Missing canvas parameter for RBG/YUV conversion");
4797 : }
4798 :
4799 4 : switch (tx->pf) {
4800 : case GF_PIXEL_ARGB:
4801 : case GF_PIXEL_RGBA:
4802 : case GF_PIXEL_BGRA:
4803 : case GF_PIXEL_ABGR:
4804 : case GF_PIXEL_ALPHAGREY:
4805 : case GF_PIXEL_GREYALPHA:
4806 : dst_pf = GF_PIXEL_RGBA;
4807 : nb_comp = 4;
4808 : break;
4809 0 : default:
4810 : dst_pf = GF_PIXEL_RGB;
4811 : nb_comp = 3;
4812 0 : break;
4813 : }
4814 :
4815 4 : GF_SAFEALLOC(tx_hsv, GF_JSTexture);
4816 4 : if (!tx_hsv)
4817 0 : return js_throw_err(c, GF_OUT_OF_MEM);
4818 4 : tx_hsv->width = tx->width;
4819 4 : tx_hsv->height = tx->height;
4820 4 : tx_hsv->pf = dst_pf;
4821 4 : tx_hsv->nb_comp = nb_comp;
4822 4 : gf_pixel_get_size_info(tx_hsv->pf, tx_hsv->width, tx_hsv->height, &tx_hsv->data_size, &tx_hsv->stride, &tx_hsv->stride_uv, NULL, NULL);
4823 4 : tx_hsv->data = gf_malloc(sizeof(char)*tx_hsv->data_size);
4824 4 : tx_hsv->owns_data = GF_TRUE;
4825 :
4826 516 : for (j=0; j<tx_hsv->height; j++) {
4827 512 : u8 *dst = tx_hsv->data + j*tx_hsv->stride;
4828 66048 : for (i=0; i<tx_hsv->width; i++) {
4829 : u8 a, r, g, b;
4830 65536 : u32 col = gf_evg_stencil_get_pixel(tx->stencil, i, j);
4831 :
4832 65536 : if (conv_type == EVG_CONV_RGB_TO_HSV ) {
4833 16384 : a = GF_COL_A(col);
4834 16384 : r = GF_COL_R(col);
4835 16384 : g = GF_COL_G(col);
4836 16384 : b = GF_COL_B(col);
4837 16384 : rgb2hsv(r, g, b, &r, &g, &b);
4838 49152 : } else if (conv_type == EVG_CONV_HSV_TO_RGB ) {
4839 16384 : a = GF_COL_A(col);
4840 16384 : r = GF_COL_R(col);
4841 16384 : g = GF_COL_G(col);
4842 16384 : b = GF_COL_B(col);
4843 16384 : hsv2rgb(r, g, b, &r, &g, &b);
4844 32768 : } else if (conv_type == EVG_CONV_RGB_TO_YUV ) {
4845 16384 : col = gf_evg_argb_to_ayuv(canvas->surface, col);
4846 16384 : a = GF_COL_A(col);
4847 16384 : r = GF_COL_R(col);
4848 16384 : g = GF_COL_G(col);
4849 16384 : b = GF_COL_B(col);
4850 : } else {
4851 16384 : col = gf_evg_ayuv_to_argb(canvas->surface, col);
4852 16384 : a = GF_COL_A(col);
4853 16384 : r = GF_COL_R(col);
4854 16384 : g = GF_COL_G(col);
4855 16384 : b = GF_COL_B(col);
4856 : }
4857 65536 : dst[0] = r;
4858 65536 : dst[1] = g;
4859 65536 : dst[2] = b;
4860 65536 : if (nb_comp==4) {
4861 65536 : dst[3] = a;
4862 65536 : dst += 4;
4863 : } else {
4864 0 : dst += 3;
4865 : }
4866 : }
4867 : }
4868 4 : tx_hsv->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
4869 4 : gf_evg_stencil_set_texture(tx_hsv->stencil, tx_hsv->data, tx_hsv->width, tx_hsv->height, tx_hsv->stride, tx_hsv->pf);
4870 4 : nobj = JS_NewObjectClass(c, texture_class_id);
4871 4 : JS_SetOpaque(nobj, tx_hsv);
4872 4 : return nobj;
4873 : }
4874 1 : static JSValue texture_rgb2hsv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4875 : {
4876 1 : return texture_convert(c, obj, argc, argv, EVG_CONV_RGB_TO_HSV);
4877 : }
4878 1 : static JSValue texture_hsv2rgb(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4879 : {
4880 1 : return texture_convert(c, obj, argc, argv, EVG_CONV_HSV_TO_RGB);
4881 : }
4882 1 : static JSValue texture_rgb2yuv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4883 : {
4884 1 : return texture_convert(c, obj, argc, argv, EVG_CONV_RGB_TO_YUV);
4885 : }
4886 1 : static JSValue texture_yuv2rgb(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4887 : {
4888 1 : return texture_convert(c, obj, argc, argv, EVG_CONV_YUV_TO_RGB);
4889 : }
4890 :
4891 1 : static JSValue texture_split(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4892 : {
4893 : JSValue nobj;
4894 : u32 i, j, idx, pix_shift=0;
4895 : GF_IRect src;
4896 : GF_JSTexture *tx_split;
4897 1 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4898 1 : if (!tx || !tx->stencil || !argc) return JS_EXCEPTION;
4899 :
4900 1 : if (JS_ToInt32(c, &idx, argv[0])) return JS_EXCEPTION;
4901 1 : if (idx>=tx->nb_comp) return JS_EXCEPTION;
4902 :
4903 1 : src.x = src.y = 0;
4904 1 : src.width = tx->width;
4905 1 : src.height = tx->height;
4906 1 : if (argc>1) {
4907 : JSValue v;
4908 : int res;
4909 0 : if (!JS_IsObject(argv[1])) return JS_EXCEPTION;
4910 :
4911 : #define GETIT(_name, _var) \
4912 : v = JS_GetPropertyStr(c, argv[1], _name);\
4913 : res = JS_ToInt32(c, &(src._var), v);\
4914 : JS_FreeValue(c, v);\
4915 : if (res) return JS_EXCEPTION;\
4916 : if (src._var<0) return JS_EXCEPTION;\
4917 :
4918 0 : GETIT("x", x)
4919 0 : GETIT("y", y)
4920 0 : GETIT("w", width)
4921 0 : GETIT("h", height)
4922 : #undef GETIT
4923 : }
4924 :
4925 1 : GF_SAFEALLOC(tx_split, GF_JSTexture);
4926 1 : if (!tx_split)
4927 0 : return js_throw_err(c, GF_OUT_OF_MEM);
4928 1 : tx_split->width = src.width;
4929 1 : tx_split->height = src.height;
4930 1 : tx_split->pf = GF_PIXEL_GREYSCALE;
4931 1 : tx_split->nb_comp = 1;
4932 1 : tx_split->stride = tx_split->width;
4933 1 : tx_split->data_size = tx_split->width * tx_split->height;
4934 1 : tx_split->data = gf_malloc(sizeof(char) * tx_split->data_size);
4935 1 : tx_split->owns_data = GF_TRUE;
4936 :
4937 : pix_shift = 0;
4938 1 : if (idx==0) {
4939 : pix_shift = 16; //R component
4940 0 : } else if (idx==1) {
4941 0 : if ((tx->pf == GF_PIXEL_ALPHAGREY) || (tx->pf == GF_PIXEL_GREYALPHA)) pix_shift = 24; //alpha
4942 : else pix_shift = 8; //green
4943 0 : } else if (idx==2) {
4944 : pix_shift = 0; //blue
4945 0 : } else if (idx==3) {
4946 : pix_shift = 24; //alpha
4947 : }
4948 129 : for (j=0; j<tx_split->height; j++) {
4949 128 : u8 *dst = tx_split->data + j*tx_split->stride;
4950 16512 : for (i=0; i<tx_split->width; i++) {
4951 16384 : u32 col = gf_evg_stencil_get_pixel(tx->stencil, src.x + i, src.y + j);
4952 16384 : *dst++ = (col >> pix_shift) & 0xFF;
4953 : }
4954 : }
4955 1 : tx_split->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
4956 1 : gf_evg_stencil_set_texture(tx_split->stencil, tx_split->data, tx_split->width, tx_split->height, tx_split->stride, tx_split->pf);
4957 1 : nobj = JS_NewObjectClass(c, texture_class_id);
4958 1 : JS_SetOpaque(nobj, tx_split);
4959 1 : return nobj;
4960 : }
4961 1 : static JSValue texture_convolution(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
4962 : {
4963 : JSValue v, kernv, nobj;
4964 1 : u32 i, j, kw=0, kh=0, kl=0, hkh, hkw;
4965 : s32 *kdata;
4966 1 : s32 knorm=0;
4967 : GF_JSTexture *tx_conv;
4968 1 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
4969 1 : if (!tx || !tx->stencil || !argc) return JS_EXCEPTION;
4970 :
4971 2 : if (!JS_IsObject(argv[0]))
4972 0 : return JS_EXCEPTION;
4973 :
4974 1 : v = JS_GetPropertyStr(c, argv[0], "w");
4975 1 : JS_ToInt32(c, &kw, v);
4976 : JS_FreeValue(c, v);
4977 1 : v = JS_GetPropertyStr(c, argv[0], "h");
4978 1 : JS_ToInt32(c, &kh, v);
4979 : JS_FreeValue(c, v);
4980 1 : v = JS_GetPropertyStr(c, argv[0], "norm");
4981 1 : if (!JS_IsUndefined(v))
4982 0 : JS_ToInt32(c, &knorm, v);
4983 : JS_FreeValue(c, v);
4984 1 : if (!kh || !kw)
4985 0 : return JS_EXCEPTION;
4986 1 : if (!(kh%2) || !(kw%2))
4987 0 : return JS_EXCEPTION;
4988 1 : kernv = JS_GetPropertyStr(c, argv[0], "k");
4989 1 : if (JS_IsUndefined(kernv))
4990 0 : return JS_EXCEPTION;
4991 :
4992 1 : v = JS_GetPropertyStr(c, kernv, "length");
4993 1 : JS_ToInt32(c, &kl, v);
4994 : JS_FreeValue(c, v);
4995 1 : if (kl < kw * kh) {
4996 : JS_FreeValue(c, kernv);
4997 0 : return JS_EXCEPTION;
4998 : }
4999 1 : kl = kw*kh;
5000 1 : kdata = gf_malloc(sizeof(s32)*kl);
5001 2 : for (j=0; j<kh; j++) {
5002 3 : for (i=0; i<kw; i++) {
5003 3 : u32 idx = j*kw + i;
5004 3 : v = JS_GetPropertyUint32(c, kernv, idx);
5005 3 : JS_ToInt32(c, &kdata[idx] , v);
5006 : JS_FreeValue(c, v);
5007 : }
5008 : }
5009 : JS_FreeValue(c, kernv);
5010 :
5011 1 : GF_SAFEALLOC(tx_conv, GF_JSTexture);
5012 1 : if (!tx_conv)
5013 0 : return js_throw_err(c, GF_OUT_OF_MEM);
5014 1 : tx_conv->width = tx->width;
5015 1 : tx_conv->height = tx->height;
5016 1 : tx_conv->pf = GF_PIXEL_RGB;
5017 1 : tx_conv->nb_comp = 3;
5018 1 : gf_pixel_get_size_info(tx_conv->pf, tx_conv->width, tx_conv->height, &tx_conv->data_size, &tx_conv->stride, &tx_conv->stride_uv, NULL, NULL);
5019 1 : tx_conv->data = gf_malloc(sizeof(char)*tx_conv->data_size);
5020 1 : tx_conv->owns_data = GF_TRUE;
5021 :
5022 1 : hkh = kh/2;
5023 1 : hkw = kw/2;
5024 129 : for (j=0; j<tx_conv->height; j++) {
5025 128 : u8 *dst = tx_conv->data + j*tx_conv->stride;
5026 16512 : for (i=0; i<tx_conv->width; i++) {
5027 : u32 k, l, nb_pix=0;
5028 : s32 kr = 0;
5029 : s32 kg = 0;
5030 : s32 kb = 0;
5031 :
5032 16384 : for (k=0; k<kh; k++) {
5033 16384 : if (j+k < hkh) continue;
5034 16384 : if (j+k >= tx_conv->height + hkh) continue;
5035 :
5036 49152 : for (l=0; l<kw; l++) {
5037 : s32 kv;
5038 49152 : if (i+l < hkw) continue;
5039 49024 : else if (i+l >= tx_conv->width + hkw) continue;
5040 :
5041 48896 : u32 col = gf_evg_stencil_get_pixel(tx->stencil, i+l-hkw, j+k-hkh);
5042 48896 : kv = kdata[k*kw + l];
5043 48896 : kr += kv * (s32) GF_COL_R(col);
5044 48896 : kg += kv * (s32) GF_COL_G(col);
5045 48896 : kb += kv * (s32) GF_COL_B(col);
5046 48896 : nb_pix++;
5047 : }
5048 : }
5049 :
5050 16384 : if (nb_pix!=kl) {
5051 256 : u32 n = knorm ? knorm : 1;
5052 256 : if (nb_pix) n *= nb_pix;
5053 256 : kr = (kr * kl / n);
5054 256 : kg = (kg * kl / n);
5055 256 : kb = (kb * kl / n);
5056 16128 : } else if (knorm) {
5057 0 : kr /= knorm;
5058 0 : kg /= knorm;
5059 0 : kb /= knorm;
5060 : }
5061 : #define SET_CLAMP(_d, _s)\
5062 : if (_s<0) _d = 0;\
5063 : else if (_s>255) _d = 255;\
5064 : else _d = (u8) _s;
5065 :
5066 16384 : SET_CLAMP(dst[0], kr)
5067 16384 : SET_CLAMP(dst[1], kg)
5068 16384 : SET_CLAMP(dst[2], kb)
5069 :
5070 16384 : dst += 3;
5071 : }
5072 : }
5073 1 : gf_free(kdata);
5074 :
5075 1 : tx_conv->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
5076 1 : gf_evg_stencil_set_texture(tx_conv->stencil, tx_conv->data, tx_conv->width, tx_conv->height, tx_conv->stride, tx_conv->pf);
5077 1 : nobj = JS_NewObjectClass(c, texture_class_id);
5078 1 : JS_SetOpaque(nobj, tx_conv);
5079 1 : return nobj;
5080 : }
5081 :
5082 :
5083 100 : static JSValue texture_update(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5084 : {
5085 : GF_Err e;
5086 100 : u32 width=0, height=0, pf=0, stride=0, stride_uv=0;
5087 100 : u8 *data=NULL;
5088 100 : u8 *p_u=NULL;
5089 100 : u8 *p_v=NULL;
5090 100 : u8 *p_a=NULL;
5091 :
5092 100 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
5093 100 : if (!tx || !tx->stencil || !argc) return JS_EXCEPTION;
5094 :
5095 200 : if (JS_IsObject(argv[0])) {
5096 : //create from canvas object
5097 100 : GF_JSCanvas *canvas = JS_GetOpaque(argv[0], canvas_class_id);
5098 100 : if (canvas) {
5099 0 : width = canvas->width;
5100 0 : height = canvas->height;
5101 0 : stride = canvas->stride;
5102 0 : stride_uv = canvas->stride_uv;
5103 0 : data = canvas->data;
5104 0 : pf = canvas->pf;
5105 : }
5106 : //create from filter packet
5107 100 : else if (jsf_is_packet(c, argv[0])) {
5108 100 : e = jsf_get_filter_packet_planes(c, argv[0], &width, &height, &pf, &stride, &stride_uv, (const u8 **)&data, (const u8 **)&p_u, (const u8 **)&p_v, (const u8 **)&p_a);
5109 100 : if (e) return js_throw_err(c, e);
5110 : } else {
5111 0 : return js_throw_err(c, GF_BAD_PARAM);
5112 : }
5113 : } else {
5114 0 : return js_throw_err(c, GF_BAD_PARAM);
5115 : }
5116 :
5117 100 : tx->owns_data = GF_FALSE;
5118 100 : tx->width = width;
5119 100 : tx->height = height;
5120 100 : tx->pf = pf;
5121 100 : tx->stride = stride;
5122 100 : tx->stride_uv = stride_uv;
5123 100 : tx->data = data;
5124 100 : if (p_u || p_v) {
5125 0 : e = gf_evg_stencil_set_texture_planes(tx->stencil, tx->width, tx->height, tx->pf, data, tx->stride, p_u, p_v, tx->stride_uv, p_a, tx->stride);
5126 0 : if (e) return js_throw_err(c, e);
5127 : } else {
5128 : assert(data);
5129 100 : e = gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf);
5130 100 : if (e) return js_throw_err(c, e);
5131 : }
5132 :
5133 100 : if (tx->pf) {
5134 100 : tx->nb_comp = gf_pixel_get_nb_comp(tx->pf);
5135 100 : gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, NULL, NULL, NULL, NULL);
5136 : }
5137 100 : return JS_UNDEFINED;
5138 : }
5139 :
5140 3 : static JSValue texture_get_pixel_internal(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_float)
5141 : {
5142 : Bool as_array=GF_FALSE;
5143 : JSValue ret;
5144 : Double x, y;
5145 : Float r, g, b, a;
5146 :
5147 3 : GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id);
5148 3 : if (!tx || !tx->stencil || (argc<2) ) return JS_EXCEPTION;
5149 :
5150 3 : if (is_float) {
5151 2 : if (JS_ToFloat64(c, &x, argv[0])) return JS_EXCEPTION;
5152 2 : if (JS_ToFloat64(c, &y, argv[1])) return JS_EXCEPTION;
5153 : } else {
5154 : s32 _x, _y;
5155 1 : if (JS_ToInt32(c, &_x, argv[0])) return JS_EXCEPTION;
5156 1 : if (JS_ToInt32(c, &_y, argv[1])) return JS_EXCEPTION;
5157 1 : x = ((Float)_x) / tx->width;
5158 1 : y = ((Float)_y) / tx->height;
5159 : }
5160 3 : if ((argc>2) && JS_ToBool(c, argv[2]))
5161 : as_array = GF_TRUE;
5162 :
5163 3 : gf_evg_stencil_get_pixel_f(tx->stencil, (Float) x, (Float) y, &r, &g, &b, &a);
5164 :
5165 3 : if (as_array) {
5166 0 : ret = JS_NewArray(c);
5167 0 : JS_SetPropertyStr(c, ret, "length", JS_NewInt32(c, 4) );
5168 0 : JS_SetPropertyUint32(c, ret, 0, JS_NewFloat64(c, r) );
5169 0 : JS_SetPropertyUint32(c, ret, 1, JS_NewFloat64(c, g) );
5170 0 : JS_SetPropertyUint32(c, ret, 2, JS_NewFloat64(c, b) );
5171 0 : JS_SetPropertyUint32(c, ret, 3, JS_NewFloat64(c, a) );
5172 : } else {
5173 3 : ret = JS_NewObject(c);
5174 6 : JS_SetPropertyStr(c, ret, "r", JS_NewFloat64(c, r) );
5175 6 : JS_SetPropertyStr(c, ret, "g", JS_NewFloat64(c, g) );
5176 6 : JS_SetPropertyStr(c, ret, "b", JS_NewFloat64(c, b) );
5177 6 : JS_SetPropertyStr(c, ret, "a", JS_NewFloat64(c, a) );
5178 : }
5179 3 : return ret;
5180 : }
5181 1 : static JSValue texture_get_pixel(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5182 : {
5183 1 : return texture_get_pixel_internal(c, obj, argc, argv, GF_FALSE);
5184 : }
5185 :
5186 2 : static JSValue texture_get_pixelf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5187 : {
5188 2 : return texture_get_pixel_internal(c, obj, argc, argv, GF_TRUE);
5189 : }
5190 :
5191 16 : static GF_Err texture_load_data(JSContext *c, GF_JSTexture *tx, u8 *data, u32 size)
5192 : {
5193 : GF_Err e;
5194 : GF_BitStream *bs;
5195 16 : u8 *dsi=NULL;
5196 : u32 codecid, width, height, pf, dsi_len, osize;
5197 :
5198 16 : bs = gf_bs_new(data, size, GF_BITSTREAM_READ);
5199 16 : gf_img_parse(bs, &codecid, &width, &height, &dsi, &dsi_len);
5200 16 : gf_bs_del(bs);
5201 :
5202 : e = GF_NOT_SUPPORTED;
5203 16 : if (codecid==GF_CODECID_PNG) {
5204 15 : e = gf_img_png_dec(data, size, &width, &height, &pf, NULL, &osize);
5205 15 : if (e ==GF_BUFFER_TOO_SMALL) {
5206 15 : tx->owns_data = GF_TRUE;
5207 15 : tx->data_size = osize;
5208 15 : tx->data = gf_malloc(sizeof(char) * osize);
5209 15 : e = gf_img_png_dec(data, size, &width, &height, &pf, tx->data, &osize);
5210 15 : if (e==GF_OK) {
5211 15 : tx->width = width;
5212 15 : tx->height = height;
5213 15 : tx->pf = pf;
5214 : }
5215 : }
5216 : }
5217 16 : if (codecid==GF_CODECID_JPEG) {
5218 1 : e = gf_img_jpeg_dec(data, size, &width, &height, &pf, NULL, &osize, 0);
5219 1 : if (e ==GF_BUFFER_TOO_SMALL) {
5220 1 : tx->owns_data = GF_TRUE;
5221 1 : tx->data_size = osize;
5222 1 : tx->data = gf_malloc(sizeof(char) * osize);
5223 1 : e = gf_img_jpeg_dec(data, size, &width, &height, &pf, tx->data, &osize, 0);
5224 1 : if (e==GF_OK) {
5225 1 : tx->width = width;
5226 1 : tx->height = height;
5227 1 : tx->pf = pf;
5228 : }
5229 : }
5230 : }
5231 16 : if (dsi) gf_free(dsi);
5232 :
5233 16 : if (e != GF_OK) {
5234 : return e;
5235 : }
5236 16 : tx->nb_comp = gf_pixel_get_nb_comp(tx->pf);
5237 16 : gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, &tx->stride, NULL, NULL, NULL);
5238 16 : e = gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf);
5239 16 : if (e != GF_OK) {
5240 : return e;
5241 : }
5242 : return GF_OK;
5243 : }
5244 16 : static GF_Err texture_load_file(JSContext *c, GF_JSTexture *tx, const char *fileName, Bool rel_to_script)
5245 : {
5246 : char szPath[GF_MAX_PATH];
5247 : u8 *data;
5248 : u32 size;
5249 : GF_Err e;
5250 : char *full_url = NULL;
5251 :
5252 16 : if (rel_to_script) {
5253 11 : const char *par_url = jsf_get_script_filename(c);
5254 11 : full_url = gf_url_concatenate(par_url, fileName);
5255 : fileName = full_url;
5256 : }
5257 16 : if (!strncmp(fileName, "$GSHARE/", 8)) {
5258 5 : gf_opts_default_shared_directory(szPath);
5259 5 : strcat(szPath, fileName + 7);
5260 : fileName = szPath;
5261 : }
5262 16 : if (!gf_file_exists(fileName) || (gf_file_load_data(fileName, &data, &size) != GF_OK)) {
5263 0 : if (full_url) gf_free(full_url);
5264 : return GF_URL_ERROR;
5265 : }
5266 16 : if (full_url) gf_free(full_url);
5267 16 : e = texture_load_data(c, tx, data, size);
5268 16 : gf_free(data);
5269 16 : return e;
5270 : }
5271 :
5272 : static const JSCFunctionListEntry texture_funcs[] =
5273 : {
5274 : JS_CGETSET_MAGIC_DEF("filtering", NULL, texture_setProperty, TX_FILTER),
5275 : JS_CGETSET_MAGIC_DEF("cmx", NULL, texture_setProperty, TX_CMX),
5276 : JS_CGETSET_MAGIC_DEF("mx", NULL, texture_setProperty, TX_MAT),
5277 : JS_CGETSET_MAGIC_DEF("repeat_s", texture_getProperty, texture_setProperty, TX_REPEAT_S),
5278 : JS_CGETSET_MAGIC_DEF("repeat_t", texture_getProperty, texture_setProperty, TX_REPEAT_T),
5279 : JS_CGETSET_MAGIC_DEF("flip_h", texture_getProperty, texture_setProperty, TX_FLIP_X),
5280 : JS_CGETSET_MAGIC_DEF("flip_v", texture_getProperty, texture_setProperty, TX_FLIP_Y),
5281 : JS_CGETSET_MAGIC_DEF("width", texture_getProperty, NULL, TX_WIDTH),
5282 : JS_CGETSET_MAGIC_DEF("height", texture_getProperty, NULL, TX_HEIGHT),
5283 : JS_CGETSET_MAGIC_DEF("pixfmt", texture_getProperty, NULL, TX_PIXFMT),
5284 : JS_CGETSET_MAGIC_DEF("comp", texture_getProperty, NULL, TX_NB_COMP),
5285 : JS_CGETSET_MAGIC_DEF("data", texture_getProperty, NULL, TX_DATA),
5286 :
5287 : JS_CFUNC_DEF("set_alpha", 0, stencil_set_alpha),
5288 : JS_CFUNC_DEF("set_alphaf", 0, stencil_set_alphaf),
5289 : JS_CFUNC_DEF("rgb2hsv", 0, texture_rgb2hsv),
5290 : JS_CFUNC_DEF("hsv2rgb", 0, texture_hsv2rgb),
5291 : JS_CFUNC_DEF("rgb2yuv", 0, texture_rgb2yuv),
5292 : JS_CFUNC_DEF("yuv2rgb", 0, texture_yuv2rgb),
5293 : JS_CFUNC_DEF("convolution", 0, texture_convolution),
5294 : JS_CFUNC_DEF("split", 0, texture_split),
5295 : JS_CFUNC_DEF("update", 0, texture_update),
5296 : JS_CFUNC_DEF("get_pixelf", 0, texture_get_pixelf),
5297 : JS_CFUNC_DEF("get_pixel", 0, texture_get_pixel),
5298 :
5299 : };
5300 :
5301 :
5302 62102 : static void evg_param_tex_callback(void *cbk, u32 x, u32 y, Float *r, Float *g, Float *b, Float *a)
5303 : {
5304 : Double compv;
5305 : JSValue ret, v, argv[2];
5306 : GF_JSTexture *tx = (GF_JSTexture *)cbk;
5307 124204 : argv[0] = JS_NewInt32(tx->ctx, x);
5308 124204 : argv[1] = JS_NewInt32(tx->ctx, y);
5309 62102 : ret = JS_Call(tx->ctx, tx->param_fun, tx->obj, 2, argv);
5310 62102 : JS_FreeValue(tx->ctx, argv[0]);
5311 62102 : JS_FreeValue(tx->ctx, argv[1]);
5312 :
5313 62102 : *r = *g = *b = 0.0;
5314 62102 : *a = 1.0;
5315 : #define GETCOMP(_comp)\
5316 : v = JS_GetPropertyStr(tx->ctx, ret, #_comp);\
5317 : if (!JS_IsUndefined(v)) {\
5318 : JS_ToFloat64(tx->ctx, &compv, v);\
5319 : JS_FreeValue(tx->ctx, v);\
5320 : *_comp = (Float) compv;\
5321 : }\
5322 :
5323 186306 : GETCOMP(r)
5324 124204 : GETCOMP(g)
5325 124204 : GETCOMP(b)
5326 186306 : GETCOMP(a)
5327 :
5328 : #undef GETCOMP
5329 62102 : JS_FreeValue(tx->ctx, ret);
5330 62102 : }
5331 :
5332 127 : static JSValue texture_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
5333 : {
5334 : Bool use_screen_coords=GF_FALSE;
5335 : JSValue obj;
5336 127 : JSValue tx_fun=JS_UNDEFINED;
5337 127 : u32 width=0, height=0, pf=0, stride=0, stride_uv=0;
5338 127 : size_t data_size=0;
5339 127 : u8 *data=NULL;
5340 127 : u8 *p_u=NULL;
5341 127 : u8 *p_v=NULL;
5342 127 : u8 *p_a=NULL;
5343 : GF_JSTexture *tx;
5344 127 : GF_SAFEALLOC(tx, GF_JSTexture);
5345 127 : if (!tx)
5346 0 : return js_throw_err(c, GF_OUT_OF_MEM);
5347 127 : tx->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE);
5348 127 : if (!tx->stencil) {
5349 0 : gf_free(tx);
5350 0 : return JS_EXCEPTION;
5351 : }
5352 127 : if (!argc) goto done;
5353 :
5354 254 : if (JS_IsString(argv[0])) {
5355 : GF_Err e;
5356 : Bool rel_to_script = GF_FALSE;
5357 : const char *str = JS_ToCString(c, argv[0]);
5358 16 : if (argc>1) rel_to_script = JS_ToBool(c, argv[1]);
5359 16 : e = texture_load_file(c, tx, str, rel_to_script);
5360 16 : JS_FreeCString(c, str);
5361 16 : if (e) {
5362 0 : if (tx->stencil) gf_evg_stencil_delete(tx->stencil);
5363 0 : gf_free(tx);
5364 0 : return js_throw_err_msg(c, e, "Failed to load texture: %s", gf_error_to_string(e));
5365 : }
5366 : goto done;
5367 : }
5368 111 : if (JS_IsObject(argv[0])) {
5369 :
5370 : //create from canvas object
5371 102 : GF_JSCanvas *canvas = JS_GetOpaque(argv[0], canvas_class_id);
5372 102 : if (canvas) {
5373 0 : width = canvas->width;
5374 0 : height = canvas->height;
5375 0 : stride = canvas->stride;
5376 0 : stride_uv = canvas->stride_uv;
5377 0 : data = canvas->data;
5378 0 : pf = canvas->pf;
5379 : }
5380 : //create from filter packet
5381 102 : else if (jsf_is_packet(c, argv[0])) {
5382 102 : GF_Err e = jsf_get_filter_packet_planes(c, argv[0], &width, &height, &pf, &stride, &stride_uv, (const u8 **)&data, (const u8 **)&p_u, (const u8 **)&p_v, (const u8 **)&p_a);
5383 102 : if (e) goto error;
5384 :
5385 102 : if (!stride) {
5386 0 : gf_pixel_get_size_info(pf, width, height, NULL, &stride, &stride_uv, NULL, NULL);
5387 : }
5388 : } else {
5389 0 : data = JS_GetArrayBuffer(c, &data_size, argv[0]);
5390 0 : if (data) {
5391 0 : GF_Err e = texture_load_data(c, tx, data, (u32) data_size);
5392 0 : if (e) {
5393 0 : if (tx->stencil) gf_evg_stencil_delete(tx->stencil);
5394 0 : gf_free(tx);
5395 0 : return js_throw_err_msg(c, e, "Failed to load texture: %s", gf_error_to_string(e));
5396 : }
5397 : goto done;
5398 : }
5399 : goto error;
5400 : }
5401 : }
5402 : //arraybuffer
5403 : else {
5404 9 : if (argc<4) goto error;
5405 9 : if (JS_ToInt32(c, &width, argv[0])) goto error;
5406 9 : if (JS_ToInt32(c, &height, argv[1])) goto error;
5407 18 : if (JS_IsString(argv[2])) {
5408 : const char *str = JS_ToCString(c, argv[2]);
5409 9 : pf = gf_pixel_fmt_parse(str);
5410 9 : JS_FreeCString(c, str);
5411 0 : } else if (JS_ToInt32(c, &pf, argv[2])) {
5412 : goto error;
5413 : }
5414 9 : if (JS_IsFunction(c, argv[3])) {
5415 2 : tx_fun = argv[3];
5416 : }
5417 14 : else if (JS_IsObject(argv[3])) {
5418 7 : data = JS_GetArrayBuffer(c, &data_size, argv[3]);
5419 : }
5420 38 : if (!width || !height || !pf || (!data && JS_IsUndefined(tx_fun)))
5421 : goto error;
5422 :
5423 9 : if (argc>4) {
5424 9 : if (JS_ToInt32(c, &stride, argv[4]))
5425 : goto error;
5426 9 : if (argc>5) {
5427 0 : if (JS_ToInt32(c, &stride_uv, argv[5]))
5428 : goto error;
5429 : }
5430 : }
5431 : }
5432 :
5433 111 : tx->owns_data = GF_FALSE;
5434 111 : tx->width = width;
5435 111 : tx->height = height;
5436 111 : tx->pf = pf;
5437 111 : tx->stride = stride;
5438 111 : tx->stride_uv = stride_uv;
5439 111 : tx->data = data;
5440 111 : if (p_u || p_v) {
5441 0 : if (gf_evg_stencil_set_texture_planes(tx->stencil, tx->width, tx->height, tx->pf, data, tx->stride, p_u, p_v, tx->stride_uv, p_a, tx->stride) != GF_OK)
5442 : goto error;
5443 111 : } else if (data) {
5444 109 : if (gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf) != GF_OK)
5445 : goto error;
5446 : } else {
5447 2 : use_screen_coords = stride ? GF_TRUE : GF_FALSE;
5448 2 : if (gf_evg_stencil_set_texture_parametric(tx->stencil, tx->width, tx->height, tx->pf, evg_param_tex_callback, tx, use_screen_coords) != GF_OK)
5449 : goto error;
5450 2 : tx->param_fun = JS_DupValue(c, tx_fun);
5451 2 : tx->ctx = c;
5452 : }
5453 :
5454 127 : done:
5455 127 : if (tx->pf) {
5456 127 : tx->nb_comp = gf_pixel_get_nb_comp(tx->pf);
5457 127 : gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, NULL, NULL, NULL, NULL);
5458 : }
5459 127 : obj = JS_NewObjectClass(c, texture_class_id);
5460 127 : if (JS_IsException(obj)) return obj;
5461 127 : JS_SetOpaque(obj, tx);
5462 127 : tx->obj = obj;
5463 127 : return obj;
5464 :
5465 0 : error:
5466 0 : if (tx->stencil) gf_evg_stencil_delete(tx->stencil);
5467 0 : gf_free(tx);
5468 0 : return js_throw_err_msg(c, GF_BAD_PARAM, "Failed to create texture");
5469 : }
5470 :
5471 2 : Bool js_evg_is_texture(JSContext *ctx, JSValue this_obj)
5472 : {
5473 2 : GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id);
5474 2 : if (!tx) return GF_FALSE;
5475 2 : return GF_TRUE;
5476 : }
5477 :
5478 6 : Bool js_evg_get_texture_info(JSContext *ctx, JSValue this_obj, u32 *width, u32 *height, u32 *pixfmt, u8 **p_data, u32 *stride, u8 **p_u, u8 **p_v, u32 *stride_uv, u8 **p_a)
5479 : {
5480 6 : GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id);
5481 6 : if (!tx) return GF_FALSE;
5482 6 : if (width) *width = tx->width;
5483 6 : if (height) *height = tx->height;
5484 6 : if (pixfmt) *pixfmt = tx->pf;
5485 6 : if (stride) *stride = tx->stride;
5486 6 : if (stride_uv) *stride_uv = tx->stride_uv;
5487 6 : if (!tx->data) return GF_TRUE;
5488 6 : if (p_data) *p_data = tx->data;
5489 6 : if (p_u) *p_u = NULL;
5490 6 : if (p_v) *p_v = NULL;
5491 6 : if (p_a) *p_a = NULL;
5492 : return GF_TRUE;
5493 : }
5494 :
5495 46 : static void text_reset(GF_JSText *txt)
5496 : {
5497 46 : if (txt->path) gf_path_del(txt->path);
5498 46 : txt->path = NULL;
5499 128 : while (gf_list_count(txt->spans)) {
5500 36 : GF_TextSpan *s = gf_list_pop_back(txt->spans);
5501 36 : gf_font_manager_delete_span(txt->fm, s);
5502 : }
5503 46 : txt->min_x = txt->min_y = txt->max_x = txt->max_y = txt->max_w = txt->max_h = 0;
5504 46 : }
5505 37 : static void text_finalize(JSRuntime *rt, JSValue obj)
5506 : {
5507 37 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5508 37 : if (!txt) return;
5509 37 : text_reset(txt);
5510 37 : if (txt->fontname) gf_free(txt->fontname);
5511 37 : gf_list_del(txt->spans);
5512 37 : gf_free(txt);
5513 : }
5514 :
5515 : enum{
5516 : TXT_FONT=0,
5517 : TXT_FONTSIZE,
5518 : TXT_ALIGN,
5519 : TXT_BASELINE,
5520 : TXT_HORIZ,
5521 : TXT_FLIP,
5522 : TXT_UNDERLINED,
5523 : TXT_BOLD,
5524 : TXT_ITALIC,
5525 : TXT_SMALLCAP,
5526 : TXT_STRIKEOUT,
5527 : TXT_MAX_WIDTH,
5528 : TXT_LINESPACING,
5529 : };
5530 :
5531 : enum
5532 : {
5533 : TXT_BL_TOP=0,
5534 : TXT_BL_HANGING,
5535 : TXT_BL_MIDDLE,
5536 : TXT_BL_ALPHABETIC,
5537 : TXT_BL_IDEOGRAPHIC,
5538 : TXT_BL_BOTTOM,
5539 : };
5540 : enum
5541 : {
5542 : TXT_AL_START=0,
5543 : TXT_AL_END,
5544 : TXT_AL_LEFT,
5545 : TXT_AL_RIGHT,
5546 : TXT_AL_CENTER
5547 : };
5548 :
5549 1 : static JSValue text_getProperty(JSContext *c, JSValueConst obj, int magic)
5550 : {
5551 1 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5552 1 : if (!txt) return JS_EXCEPTION;
5553 1 : switch (magic) {
5554 1 : case TXT_FONT: return JS_NewString(c, txt->fontname);
5555 0 : case TXT_BASELINE: return JS_NewInt32(c, txt->baseline);
5556 0 : case TXT_ALIGN: return JS_NewInt32(c, txt->align);
5557 0 : case TXT_FONTSIZE: return JS_NewFloat64(c, txt->font_size);
5558 0 : case TXT_HORIZ: return JS_NewBool(c, txt->horizontal);
5559 0 : case TXT_FLIP: return JS_NewBool(c, txt->flip);
5560 0 : case TXT_MAX_WIDTH: return JS_NewFloat64(c, txt->maxWidth);
5561 0 : case TXT_LINESPACING: return JS_NewFloat64(c, txt->lineSpacing);
5562 0 : case TXT_BOLD: return JS_NewBool(c, txt->styles & GF_FONT_WEIGHT_100);
5563 0 : case TXT_ITALIC: return JS_NewBool(c, txt->styles & GF_FONT_ITALIC);
5564 0 : case TXT_UNDERLINED: return JS_NewBool(c, txt->styles & GF_FONT_UNDERLINED);
5565 0 : case TXT_SMALLCAP: return JS_NewBool(c, txt->styles & GF_FONT_SMALLCAPS);
5566 0 : case TXT_STRIKEOUT: return JS_NewBool(c, txt->styles & GF_FONT_STRIKEOUT);
5567 : }
5568 0 : return JS_UNDEFINED;
5569 : }
5570 :
5571 310 : static void text_update_path(GF_JSText *txt, Bool for_centered)
5572 : {
5573 : Fixed cy, ascent, descent, scale_x, ls;
5574 : u32 i, nb_lines;
5575 :
5576 310 : if ((txt->path_for_centered == for_centered) && txt->path) {
5577 : return;
5578 : }
5579 8 : if (txt->path) gf_path_del(txt->path);
5580 8 : txt->path = NULL;
5581 8 : if (!txt->font)
5582 : return;
5583 :
5584 8 : txt->path_for_centered = for_centered;
5585 :
5586 8 : cy = FLT2FIX((txt->font_size * txt->font->baseline) / txt->font->em_size);
5587 :
5588 8 : ascent = FLT2FIX((txt->font_size*txt->font->ascent) / txt->font->em_size);
5589 8 : if (txt->lineSpacing)
5590 0 : ls = FLT2FIX((txt->lineSpacing*txt->font->line_spacing) / txt->font->em_size);
5591 : else
5592 8 : ls = FLT2FIX((txt->font_size*txt->font->line_spacing) / txt->font->em_size);
5593 8 : descent = -FLT2FIX((txt->font_size*txt->font->descent) / txt->font->em_size);
5594 : scale_x = 0;
5595 8 : if (txt->maxWidth && txt->max_w && (txt->max_w > txt->maxWidth)) {
5596 0 : scale_x = gf_divfix(FLT2FIX(txt->maxWidth), INT2FIX(txt->max_w) );
5597 : }
5598 :
5599 8 : if (txt->baseline==TXT_BL_TOP) {
5600 : cy = ascent;
5601 8 : } else if (txt->baseline==TXT_BL_BOTTOM) {
5602 : cy = -descent;
5603 8 : } else if (txt->baseline==TXT_BL_MIDDLE) {
5604 0 : Fixed mid = (ascent + descent)/2;
5605 : cy = mid;
5606 : }
5607 :
5608 8 : txt->path = gf_path_new();
5609 8 : nb_lines = gf_list_count(txt->spans);
5610 43 : for (i=0; i<nb_lines; i++) {
5611 : Fixed cx=0;
5612 : u32 flags;
5613 : GF_Path *path;
5614 : GF_Matrix2D mx;
5615 35 : GF_TextSpan *span = gf_list_get(txt->spans, i);
5616 35 : if ((txt->align == TXT_AL_LEFT)
5617 35 : || ((txt->align == TXT_AL_START) && !(span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT))
5618 35 : || ((txt->align == TXT_AL_END) && (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT))
5619 : ) {
5620 : cx = 0;
5621 : }
5622 35 : else if ((txt->align == TXT_AL_RIGHT)
5623 34 : || ((txt->align == TXT_AL_END) && !(span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT))
5624 34 : || ((txt->align == TXT_AL_START) && (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT))
5625 : ) {
5626 1 : cx = txt->max_w - span->bounds.width;
5627 34 : } else if (txt->align == TXT_AL_CENTER) {
5628 34 : cx = (txt->max_w - span->bounds.width) / 2;
5629 : }
5630 35 : gf_mx2d_init(mx);
5631 :
5632 35 : gf_mx2d_add_translation(&mx, cx, cy);
5633 35 : if (scale_x)
5634 0 : gf_mx2d_add_scale(&mx, scale_x, FIX_ONE);
5635 :
5636 35 : flags = span->flags;
5637 35 : if (txt->path_for_centered) {
5638 35 : if (txt->flip)
5639 0 : span->flags |= GF_TEXT_SPAN_FLIP;
5640 : } else {
5641 0 : if (!txt->flip)
5642 0 : span->flags |= GF_TEXT_SPAN_FLIP;
5643 : }
5644 :
5645 35 : path = gf_font_span_create_path(span);
5646 35 : gf_path_add_subpath(txt->path, path, &mx);
5647 35 : gf_path_del(path);
5648 35 : span->flags = flags;
5649 :
5650 35 : if (txt->path_for_centered)
5651 35 : cy -= ls;
5652 : else
5653 0 : cy += ls;
5654 : }
5655 : }
5656 : static void text_set_path(GF_JSCanvas *canvas, GF_JSText *txt)
5657 : {
5658 209 : text_update_path(txt, canvas->center_coords);
5659 209 : gf_evg_surface_set_path(canvas->surface, txt->path);
5660 : }
5661 :
5662 36 : static void text_set_text_from_value(GF_JSText *txt, GF_Font *font, JSContext *c, JSValueConst value)
5663 : {
5664 : const char *str = JS_ToCString(c, value);
5665 : char *start = (char *) str;
5666 72 : while (start) {
5667 : GF_TextSpan *span;
5668 36 : char *nline = strchr(str, '\n');
5669 36 : if (nline) nline[0] = 0;
5670 36 : span = gf_font_manager_create_span(txt->fm, font, (char *) str, FLT2FIX(txt->font_size), GF_FALSE, GF_FALSE, GF_FALSE, NULL, GF_FALSE, 0, NULL);
5671 36 : if (span) {
5672 36 : if (txt->horizontal)
5673 36 : span->flags |= GF_TEXT_SPAN_HORIZONTAL;
5674 36 : gf_list_add(txt->spans, span);
5675 : }
5676 :
5677 36 : if (!nline) break;
5678 0 : nline[0] = '\n';
5679 0 : start = nline + 1;
5680 : }
5681 36 : JS_FreeCString(c, str);
5682 36 : }
5683 :
5684 1 : static JSValue text_get_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5685 : {
5686 : JSValue nobj;
5687 : Bool is_center = GF_TRUE;
5688 1 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5689 1 : if (!txt) return JS_EXCEPTION;
5690 1 : if (argc) is_center = JS_ToBool(c, argv[0]);
5691 :
5692 1 : text_update_path(txt, is_center);
5693 1 : if (!txt->path) return JS_NULL;
5694 1 : nobj = JS_NewObjectClass(c, path_class_id);
5695 1 : JS_SetOpaque(nobj, gf_path_clone(txt->path));
5696 1 : return nobj;
5697 : }
5698 :
5699 9 : static JSValue text_set_text(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5700 : {
5701 : s32 i, j, nb_lines;
5702 9 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5703 9 : if (!txt) return JS_EXCEPTION;
5704 9 : text_reset(txt);
5705 9 : if (!argc) return JS_UNDEFINED;
5706 :
5707 9 : txt->font = gf_font_manager_set_font(txt->fm, &txt->fontname, 1, txt->styles);
5708 9 : if (!txt->font)
5709 0 : return js_throw_err_msg(c, GF_NOT_FOUND, "Font %s not found and no default font available!\n"
5710 : "Check your GPAC configuration, or use `-rescan-fonts` to refresh font directory.\n", txt->fontname);
5711 :
5712 9 : for (i=0; i<argc; i++) {
5713 9 : if (JS_IsArray(c, argv[i])) {
5714 9 : JSValue v = JS_GetPropertyStr(c, argv[i], "length");
5715 9 : JS_ToInt32(c, &nb_lines, v);
5716 : JS_FreeValue(c, v);
5717 :
5718 36 : for (j=0; j<nb_lines; j++) {
5719 36 : v = JS_GetPropertyUint32(c, argv[i], j);
5720 36 : text_set_text_from_value(txt, txt->font, c, v);
5721 : JS_FreeValue(c, v);
5722 : }
5723 : } else {
5724 0 : text_set_text_from_value(txt, txt->font, c, argv[i]);
5725 : }
5726 : }
5727 :
5728 9 : nb_lines = gf_list_count(txt->spans);
5729 45 : for (i=0; i<nb_lines; i++) {
5730 36 : GF_TextSpan *span = gf_list_get(txt->spans, i);
5731 36 : gf_font_manager_refresh_span_bounds(span);
5732 36 : span->bounds.y += FLT2FIX( i*txt->lineSpacing );
5733 :
5734 36 : if (!txt->max_h && !txt->max_w) {
5735 9 : txt->max_w = span->bounds.width;
5736 9 : txt->max_h = span->bounds.height;
5737 9 : txt->min_x = span->bounds.x;
5738 9 : txt->min_y = span->bounds.y;
5739 9 : txt->max_x = txt->min_x + span->bounds.width;
5740 9 : txt->max_y = txt->min_y + span->bounds.x;
5741 : } else {
5742 27 : if (txt->min_x > span->bounds.x)
5743 0 : txt->min_x = span->bounds.x;
5744 27 : if (txt->min_y > span->bounds.y)
5745 0 : txt->min_y = span->bounds.y;
5746 27 : if (txt->max_w < span->bounds.width)
5747 7 : txt->max_w = span->bounds.width;
5748 27 : if (txt->max_h < span->bounds.height)
5749 0 : txt->max_h = span->bounds.height;
5750 27 : if (txt->max_x < span->bounds.x + span->bounds.width)
5751 7 : txt->max_x = span->bounds.x + span->bounds.width;
5752 27 : if (txt->max_y < span->bounds.y + span->bounds.height)
5753 7 : txt->max_y = span->bounds.y + span->bounds.height;
5754 : }
5755 : }
5756 :
5757 9 : return JS_UNDEFINED;
5758 : }
5759 :
5760 202 : static JSValue text_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic)
5761 : {
5762 : const char *str;
5763 202 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5764 202 : if (!txt) return JS_EXCEPTION;
5765 :
5766 202 : switch (magic) {
5767 37 : case TXT_FONT:
5768 : str = JS_ToCString(c, value);
5769 37 : if (txt->fontname) gf_free(txt->fontname);
5770 37 : txt->fontname = str ? gf_strdup(str) : NULL;
5771 37 : JS_FreeCString(c, str);
5772 37 : break;
5773 37 : case TXT_BASELINE:
5774 37 : if (JS_ToInt32(c, &txt->baseline, value)) return JS_EXCEPTION;
5775 37 : return JS_UNDEFINED;
5776 47 : case TXT_ALIGN:
5777 47 : if (JS_ToInt32(c, &txt->align, value)) return JS_EXCEPTION;
5778 47 : return JS_UNDEFINED;
5779 42 : case TXT_FONTSIZE:
5780 42 : if (JS_ToFloat64(c, &txt->font_size, value)) return JS_EXCEPTION;
5781 : break;
5782 0 : case TXT_HORIZ:
5783 0 : txt->horizontal = JS_ToBool(c, value);
5784 0 : break;
5785 0 : case TXT_FLIP:
5786 0 : txt->flip = JS_ToBool(c, value);
5787 0 : break;
5788 : #define TOG_FLAG(_val) \
5789 : if (JS_ToBool(c, value)) \
5790 : txt->styles |= _val;\
5791 : else\
5792 : txt->styles &= ~_val;\
5793 :
5794 :
5795 0 : case TXT_UNDERLINED:
5796 0 : TOG_FLAG(GF_FONT_UNDERLINED);
5797 : break;
5798 2 : case TXT_ITALIC:
5799 2 : TOG_FLAG(GF_FONT_ITALIC);
5800 : break;
5801 0 : case TXT_BOLD:
5802 0 : TOG_FLAG(GF_FONT_WEIGHT_100);
5803 : break;
5804 0 : case TXT_STRIKEOUT:
5805 0 : TOG_FLAG(GF_FONT_STRIKEOUT);
5806 : break;
5807 0 : case TXT_SMALLCAP:
5808 0 : TOG_FLAG(GF_FONT_SMALLCAPS);
5809 : break;
5810 : #undef TOG_FLAG
5811 :
5812 0 : case TXT_MAX_WIDTH:
5813 0 : JS_ToFloat64(c, &txt->maxWidth, value);
5814 0 : break;
5815 37 : case TXT_LINESPACING:
5816 37 : JS_ToFloat64(c, &txt->lineSpacing, value);
5817 37 : break;
5818 : }
5819 118 : return JS_UNDEFINED;
5820 : }
5821 :
5822 1 : static JSValue text_measure(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv)
5823 : {
5824 : JSValue res;
5825 1 : GF_JSText *txt = JS_GetOpaque(obj, text_class_id);
5826 1 : if (!txt) return JS_EXCEPTION;
5827 1 : res = JS_NewObject(c);
5828 2 : JS_SetPropertyStr(c, res, "width", JS_NewFloat64(c, txt->max_w) );
5829 2 : JS_SetPropertyStr(c, res, "height", JS_NewFloat64(c, txt->max_y-txt->min_y) );
5830 1 : if (txt->font) {
5831 2 : JS_SetPropertyStr(c, res, "em_size", JS_NewInt32(c, txt->font->em_size) );
5832 2 : JS_SetPropertyStr(c, res, "ascent", JS_NewInt32(c, txt->font->ascent) );
5833 2 : JS_SetPropertyStr(c, res, "descent", JS_NewInt32(c, txt->font->descent) );
5834 2 : JS_SetPropertyStr(c, res, "line_spacing", JS_NewInt32(c, txt->font->line_spacing) );
5835 2 : JS_SetPropertyStr(c, res, "underlined", JS_NewInt32(c, txt->font->underline) );
5836 2 : JS_SetPropertyStr(c, res, "baseline", JS_NewInt32(c, txt->font->baseline) );
5837 2 : JS_SetPropertyStr(c, res, "max_advance_h", JS_NewInt32(c, txt->font->max_advance_h) );
5838 2 : JS_SetPropertyStr(c, res, "max_advance_v", JS_NewInt32(c, txt->font->max_advance_v) );
5839 : }
5840 1 : return res;
5841 : }
5842 :
5843 : static const JSCFunctionListEntry text_funcs[] =
5844 : {
5845 : JS_CGETSET_MAGIC_DEF("font", text_getProperty, text_setProperty, TXT_FONT),
5846 : JS_CGETSET_MAGIC_DEF("fontsize", text_getProperty, text_setProperty, TXT_FONTSIZE),
5847 : JS_CGETSET_MAGIC_DEF("align", text_getProperty, text_setProperty, TXT_ALIGN),
5848 : JS_CGETSET_MAGIC_DEF("baseline", text_getProperty, text_setProperty, TXT_BASELINE),
5849 : JS_CGETSET_MAGIC_DEF("horizontal", text_getProperty, text_setProperty, TXT_HORIZ),
5850 : JS_CGETSET_MAGIC_DEF("flip", text_getProperty, text_setProperty, TXT_FLIP),
5851 : JS_CGETSET_MAGIC_DEF("underline", text_getProperty, text_setProperty, TXT_UNDERLINED),
5852 : JS_CGETSET_MAGIC_DEF("bold", text_getProperty, text_setProperty, TXT_BOLD),
5853 : JS_CGETSET_MAGIC_DEF("italic", text_getProperty, text_setProperty, TXT_ITALIC),
5854 : JS_CGETSET_MAGIC_DEF("maxWidth", text_getProperty, text_setProperty, TXT_MAX_WIDTH),
5855 : JS_CGETSET_MAGIC_DEF("lineSpacing", text_getProperty, text_setProperty, TXT_LINESPACING),
5856 : JS_CFUNC_DEF("set_text", 0, text_set_text),
5857 : JS_CFUNC_DEF("measure", 0, text_measure),
5858 : JS_CFUNC_DEF("get_path", 0, text_get_path),
5859 : };
5860 :
5861 : JSClassDef text_class = {
5862 : "Text",
5863 : .finalizer = text_finalize
5864 : };
5865 37 : static JSValue text_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv)
5866 : {
5867 : JSValue obj;
5868 : GF_JSText *txt;
5869 37 : GF_SAFEALLOC(txt, GF_JSText);
5870 37 : if (!txt)
5871 0 : return js_throw_err(c, GF_OUT_OF_MEM);
5872 37 : txt->fm = jsf_get_font_manager(c);
5873 :
5874 37 : if (!txt->fm) {
5875 0 : gf_free(txt);
5876 0 : return js_throw_err_msg(c, GF_IO_ERR, "Failed to load font manager\n");
5877 : }
5878 37 : txt->spans = gf_list_new();
5879 37 : if (!txt->spans) {
5880 0 : gf_free(txt);
5881 0 : return JS_EXCEPTION;
5882 : }
5883 37 : if (argc) {
5884 : const char *str = JS_ToCString(c, argv[0]);
5885 0 : if (str) txt->fontname = gf_strdup(str);
5886 0 : JS_FreeCString(c, str);
5887 : }
5888 37 : txt->font_size = 12.0;
5889 37 : txt->horizontal = GF_TRUE;
5890 37 : txt->align = TXT_AL_START;
5891 37 : txt->baseline = TXT_BL_ALPHABETIC;
5892 :
5893 37 : obj = JS_NewObjectClass(c, text_class_id);
5894 37 : if (JS_IsException(obj)) return obj;
5895 37 : JS_SetOpaque(obj, txt);
5896 37 : return obj;
5897 : }
5898 :
5899 :
5900 :
5901 : enum
5902 : {
5903 : MX_PROP_IDENTITY=0,
5904 : MX_PROP_YAW,
5905 : MX_PROP_PITCH,
5906 : MX_PROP_ROLL,
5907 : MX_PROP_TRANLATE,
5908 : MX_PROP_SCALE,
5909 : MX_PROP_ROTATE,
5910 : MX_PROP_SHEAR,
5911 : MX_PROP_M,
5912 : };
5913 :
5914 1702 : static void mx_finalize(JSRuntime *rt, JSValue obj)
5915 : {
5916 1702 : GF_Matrix *mx = JS_GetOpaque(obj, matrix_class_id);
5917 1702 : if (mx) gf_free(mx);
5918 1702 : }
5919 :
5920 : JSClassDef matrix_class = {
5921 : .class_name = "Matrix",
5922 : .finalizer = mx_finalize
5923 : };
5924 :
5925 : #define MAKEVEC(_v) \
5926 : res = JS_NewObject(ctx);\
5927 : JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\
5928 : JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\
5929 : JS_SetPropertyStr(ctx, res, "z", JS_NewFloat64(ctx, FIX2FLT(_v.z) ));\
5930 : return res;\
5931 :
5932 : #define MAKEVEC4(_v) \
5933 : res = JS_NewObject(ctx);\
5934 : JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\
5935 : JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\
5936 : JS_SetPropertyStr(ctx, res, "z", JS_NewFloat64(ctx, FIX2FLT(_v.z) ));\
5937 : JS_SetPropertyStr(ctx, res, "w", JS_NewFloat64(ctx, FIX2FLT(_v.q) ));\
5938 : return res;\
5939 :
5940 : #define MAKERECT(_v) \
5941 : res = JS_NewObject(ctx);\
5942 : JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\
5943 : JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\
5944 : JS_SetPropertyStr(ctx, res, "width", JS_NewFloat64(ctx, FIX2FLT(_v.width) ));\
5945 : JS_SetPropertyStr(ctx, res, "height", JS_NewFloat64(ctx, FIX2FLT(_v.height) ));\
5946 : return res;\
5947 :
5948 1737 : static JSValue mx_getProperty(JSContext *ctx, JSValueConst this_val, int magic)
5949 : {
5950 : JSValue res;
5951 : Fixed yaw, pitch, roll;
5952 : GF_Vec tr, sc, sh;
5953 : GF_Vec4 ro;
5954 : u32 i;
5955 1737 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
5956 1737 : if (!mx) return JS_EXCEPTION;
5957 1737 : switch (magic) {
5958 0 : case MX_PROP_IDENTITY: return JS_NewBool(ctx, gf_mx2d_is_identity(*mx));
5959 0 : case MX_PROP_YAW:
5960 0 : gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll);
5961 0 : return JS_NewFloat64(ctx, FIX2FLT(yaw));
5962 0 : case MX_PROP_PITCH:
5963 0 : gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll);
5964 0 : return JS_NewFloat64(ctx, FIX2FLT(pitch));
5965 0 : case MX_PROP_ROLL:
5966 0 : gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll);
5967 0 : return JS_NewFloat64(ctx, FIX2FLT(roll));
5968 :
5969 0 : case MX_PROP_TRANLATE:
5970 0 : gf_mx_decompose(mx, &tr, &sc, &ro, &sh);
5971 0 : MAKEVEC(tr)
5972 :
5973 0 : case MX_PROP_SCALE:
5974 0 : gf_mx_decompose(mx, &tr, &sc, &ro, &sh);
5975 0 : MAKEVEC(sc)
5976 :
5977 0 : case MX_PROP_ROTATE:
5978 0 : gf_mx_decompose(mx, &tr, &sc, &ro, &sh);
5979 0 : MAKEVEC4(ro)
5980 :
5981 0 : case MX_PROP_SHEAR:
5982 0 : gf_mx_decompose(mx, &tr, &sc, &ro, &sh);
5983 0 : MAKEVEC(sh)
5984 :
5985 1737 : case MX_PROP_M:
5986 1737 : res = JS_NewArray(ctx);
5987 29529 : for (i=0; i<16; i++)
5988 55584 : JS_SetPropertyUint32(ctx, res, i, JS_NewFloat64(ctx, mx->m[i]));
5989 1737 : return res;
5990 : }
5991 0 : return JS_UNDEFINED;
5992 : }
5993 :
5994 225 : static JSValue mx_setProperty(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic)
5995 : {
5996 : JSValue v;
5997 : u32 i, len;
5998 225 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
5999 225 : if (!mx) return JS_EXCEPTION;
6000 :
6001 :
6002 225 : switch (magic) {
6003 100 : case MX_PROP_IDENTITY:
6004 200 : gf_mx_init(*mx);
6005 100 : break;
6006 125 : case MX_PROP_M:
6007 125 : if (!JS_IsArray(ctx, value)) return JS_EXCEPTION;
6008 125 : v = JS_GetPropertyStr(ctx, value, "length");
6009 125 : len=0;
6010 125 : JS_ToInt32(ctx, &len, v);
6011 : JS_FreeValue(ctx, v);
6012 125 : if (len != 16) return JS_EXCEPTION;
6013 2000 : for (i=0; i<len; i++) {
6014 : Double _d;
6015 2000 : v = JS_GetPropertyUint32(ctx, value, i);
6016 2000 : JS_ToFloat64(ctx, &_d, v);
6017 : JS_FreeValue(ctx, v);
6018 2000 : mx->m[i] = FLT2FIX(_d);
6019 : }
6020 : break;
6021 : }
6022 225 : return JS_UNDEFINED;
6023 : }
6024 :
6025 :
6026 250 : static JSValue mx_copy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6027 : {
6028 250 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6029 250 : if (!mx || !argc) return JS_EXCEPTION;
6030 250 : GF_Matrix *mx2 = JS_GetOpaque(argv[0], matrix_class_id);
6031 250 : if (!mx2) return JS_EXCEPTION;
6032 : gf_mx_copy(*mx, *mx2);
6033 : return JS_DupValue(ctx, this_val);
6034 : }
6035 1 : static JSValue mx_equal(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6036 : {
6037 1 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6038 1 : if (!mx || !argc) return JS_EXCEPTION;
6039 1 : GF_Matrix *mx2 = JS_GetOpaque(argv[0], matrix_class_id);
6040 1 : if (!mx2) return JS_EXCEPTION;
6041 1 : if (gf_mx_equal(mx, mx2)) return JS_TRUE;
6042 1 : return JS_FALSE;
6043 : }
6044 :
6045 : #define WGL_GET_VEC3(_x, _y, _z, _arg)\
6046 : {\
6047 : JSValue v;\
6048 : v = JS_GetPropertyStr(ctx, _arg, "x");\
6049 : EVG_GET_FLOAT(_x, v);\
6050 : JS_FreeValue(ctx, v);\
6051 : v = JS_GetPropertyStr(ctx, _arg, "y");\
6052 : EVG_GET_FLOAT(_y, v);\
6053 : JS_FreeValue(ctx, v);\
6054 : v = JS_GetPropertyStr(ctx, _arg, "z");\
6055 : EVG_GET_FLOAT(_z, v);\
6056 : JS_FreeValue(ctx, v);\
6057 : }
6058 :
6059 : #define WGL_GET_VEC3F(_v, _arg)\
6060 : {\
6061 : JSValue v;\
6062 : Double _f;\
6063 : v = JS_GetPropertyStr(ctx, _arg, "x");\
6064 : EVG_GET_FLOAT(_f, v);\
6065 : _v.x = FLT2FIX(_f);\
6066 : JS_FreeValue(ctx, v);\
6067 : v = JS_GetPropertyStr(ctx, _arg, "y");\
6068 : EVG_GET_FLOAT(_f, v);\
6069 : _v.y = FLT2FIX(_f);\
6070 : JS_FreeValue(ctx, v);\
6071 : v = JS_GetPropertyStr(ctx, _arg, "z");\
6072 : EVG_GET_FLOAT(_f, v);\
6073 : _v.z = FLT2FIX(_f);\
6074 : JS_FreeValue(ctx, v);\
6075 : }
6076 :
6077 : #define WGL_GET_VEC4(_x, _y, _z, _q, _arg)\
6078 : {\
6079 : JSValue v;\
6080 : v = JS_GetPropertyStr(ctx, _arg, "x");\
6081 : EVG_GET_FLOAT(_x, v);\
6082 : JS_FreeValue(ctx, v);\
6083 : v = JS_GetPropertyStr(ctx, _arg, "y");\
6084 : EVG_GET_FLOAT(_y, v);\
6085 : JS_FreeValue(ctx, v);\
6086 : v = JS_GetPropertyStr(ctx, _arg, "z");\
6087 : EVG_GET_FLOAT(_z, v);\
6088 : JS_FreeValue(ctx, v);\
6089 : v = JS_GetPropertyStr(ctx, _arg, "w");\
6090 : if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, _arg, "q");\
6091 : if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, _arg, "angle");\
6092 : EVG_GET_FLOAT(_q, v);\
6093 : JS_FreeValue(ctx, v);\
6094 : }
6095 :
6096 :
6097 931 : static JSValue mx_translate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6098 : {
6099 : Double vx, vy, vz;
6100 931 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6101 931 : if (!mx || !argc) return JS_EXCEPTION;
6102 1862 : if (!JS_IsObject(argv[0])) {
6103 931 : if (argc<3) return JS_EXCEPTION;
6104 931 : EVG_GET_FLOAT(vx, argv[0])
6105 931 : EVG_GET_FLOAT(vy, argv[1])
6106 931 : EVG_GET_FLOAT(vz, argv[2])
6107 : } else {
6108 0 : WGL_GET_VEC3(vx, vy, vz, argv[0])
6109 : }
6110 931 : gf_mx_add_translation(mx, FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz));
6111 : return JS_DupValue(ctx, this_val);
6112 : }
6113 1 : static JSValue mx_scale(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6114 : {
6115 : Double vx, vy, vz;
6116 1 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6117 1 : if (!mx || !argc) return JS_EXCEPTION;
6118 2 : if (!JS_IsObject(argv[0])) {
6119 1 : if (argc<3) return JS_EXCEPTION;
6120 1 : EVG_GET_FLOAT(vx, argv[0])
6121 1 : EVG_GET_FLOAT(vy, argv[1])
6122 1 : EVG_GET_FLOAT(vz, argv[2])
6123 : } else {
6124 0 : WGL_GET_VEC3(vx, vy, vz, argv[0])
6125 : }
6126 1 : gf_mx_add_scale(mx, FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz));
6127 : return JS_DupValue(ctx, this_val);
6128 : }
6129 931 : static JSValue mx_rotate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6130 : {
6131 : Double vx, vy, vz, angle;
6132 931 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6133 931 : if (!mx || !argc) return JS_EXCEPTION;
6134 1862 : if (!JS_IsObject(argv[0])) {
6135 931 : if (argc<4) return JS_EXCEPTION;
6136 931 : EVG_GET_FLOAT(vx, argv[0])
6137 931 : EVG_GET_FLOAT(vy, argv[1])
6138 931 : EVG_GET_FLOAT(vz, argv[2])
6139 931 : EVG_GET_FLOAT(angle, argv[3])
6140 : } else {
6141 0 : WGL_GET_VEC4(vx, vy, vz, angle, argv[0])
6142 : }
6143 931 : gf_mx_add_rotation(mx, FLT2FIX(angle), FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz));
6144 : return JS_DupValue(ctx, this_val);
6145 : }
6146 126 : static JSValue mx_add(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6147 : {
6148 126 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6149 126 : if (!mx || !argc) return JS_EXCEPTION;
6150 126 : GF_Matrix *mx2 = JS_GetOpaque(argv[0], matrix_class_id);
6151 126 : if (!mx2) return JS_EXCEPTION;
6152 126 : if ((argc>1) && JS_ToBool(ctx, argv[1])) {
6153 125 : gf_mx_add_matrix_4x4(mx, mx2);
6154 : } else {
6155 1 : gf_mx_add_matrix(mx, mx2);
6156 : }
6157 : return JS_DupValue(ctx, this_val);
6158 : }
6159 :
6160 125 : static JSValue mx_inverse(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6161 : {
6162 125 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6163 125 : if (!mx) return JS_EXCEPTION;
6164 125 : if (argc && JS_ToBool(ctx, argv[0])) {
6165 0 : gf_mx_inverse_4x4(mx);
6166 : } else {
6167 125 : gf_mx_inverse(mx);
6168 : }
6169 : return JS_DupValue(ctx, this_val);
6170 : }
6171 :
6172 125 : static JSValue mx_transpose(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6173 : {
6174 125 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6175 125 : if (!mx) return JS_EXCEPTION;
6176 125 : gf_mx_transpose(mx);
6177 : return JS_DupValue(ctx, this_val);
6178 : }
6179 :
6180 1 : static JSValue mx_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6181 : {
6182 : Fixed width, height, x, y;
6183 : GF_Vec pt;
6184 : GF_Vec4 pt4;
6185 : JSValue v, res;
6186 1 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6187 1 : if (!mx || !argc) return JS_EXCEPTION;
6188 2 : if (!JS_IsObject(argv[0])) return JS_EXCEPTION;
6189 :
6190 : /*try rect*/
6191 1 : v = JS_GetPropertyStr(ctx, argv[0], "width");
6192 1 : if (!JS_IsUndefined(v)) {
6193 : GF_Rect rc;
6194 0 : EVG_GET_FLOAT(width, v);
6195 : JS_FreeValue(ctx, v);
6196 0 : v = JS_GetPropertyStr(ctx, argv[0], "height");
6197 0 : EVG_GET_FLOAT(height, v);
6198 : JS_FreeValue(ctx, v);
6199 0 : v = JS_GetPropertyStr(ctx, argv[0], "x");
6200 0 : EVG_GET_FLOAT(x, v);
6201 : JS_FreeValue(ctx, v);
6202 0 : v = JS_GetPropertyStr(ctx, argv[0], "y");
6203 0 : EVG_GET_FLOAT(y, v);
6204 : JS_FreeValue(ctx, v);
6205 0 : rc.x = FLT2FIX(x);
6206 0 : rc.y = FLT2FIX(y);
6207 0 : rc.width = FLT2FIX(width);
6208 0 : rc.height = FLT2FIX(height);
6209 0 : gf_mx_apply_rect(mx, &rc);
6210 0 : MAKERECT(rc)
6211 : }
6212 : JS_FreeValue(ctx, v);
6213 :
6214 1 : v = JS_GetPropertyStr(ctx, argv[0], "q");
6215 1 : if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, argv[0], "w");
6216 1 : if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, argv[0], "angle");
6217 1 : if (!JS_IsUndefined(v)) {
6218 : Double _v;
6219 0 : if (JS_ToFloat64(ctx, &_v, v)) return JS_EXCEPTION;
6220 0 : pt4.q = FLT2FIX(_v);
6221 :
6222 0 : WGL_GET_VEC3F(pt4, argv[0])
6223 0 : gf_mx_apply_vec_4x4(mx, &pt4);
6224 0 : MAKEVEC4(pt4)
6225 : }
6226 : JS_FreeValue(ctx, v);
6227 :
6228 : /*try bbox ?*/
6229 :
6230 : /*try vec*/
6231 3 : WGL_GET_VEC3F(pt, argv[0])
6232 1 : gf_mx_apply_vec(mx, &pt);
6233 4 : MAKEVEC(pt)
6234 :
6235 : /*
6236 :
6237 : void gf_mx_apply_vec(GF_Matrix *mx, GF_Vec *pt);
6238 : void gf_mx_apply_rect(GF_Matrix *_this, GF_Rect *rc);
6239 : void gf_mx_apply_bbox(GF_Matrix *mx, GF_BBox *b);
6240 : void gf_mx_apply_bbox_sphere(GF_Matrix *mx, GF_BBox *box);
6241 : void gf_mx_apply_vec_4x4(GF_Matrix *mx, GF_Vec4 *vec);
6242 : */
6243 : return JS_UNDEFINED;
6244 : }
6245 :
6246 1 : static JSValue mx_ortho(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6247 : {
6248 : Double left, right, bottom, top, z_near, z_far;
6249 1 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6250 1 : if (!mx || (argc<6)) return JS_EXCEPTION;
6251 1 : EVG_GET_FLOAT(left, argv[0])
6252 1 : EVG_GET_FLOAT(right, argv[1])
6253 1 : EVG_GET_FLOAT(bottom, argv[2])
6254 1 : EVG_GET_FLOAT(top, argv[3])
6255 1 : EVG_GET_FLOAT(z_near, argv[4])
6256 1 : EVG_GET_FLOAT(z_far, argv[5])
6257 1 : if ((argc>6) && JS_ToBool(ctx, argv[6])) {
6258 0 : gf_mx_ortho_reverse_z(mx, FLT2FIX(left), FLT2FIX(right), FLT2FIX(bottom), FLT2FIX(top), FLT2FIX(z_near), FLT2FIX(z_far));
6259 : } else {
6260 1 : gf_mx_ortho(mx, FLT2FIX(left), FLT2FIX(right), FLT2FIX(bottom), FLT2FIX(top), FLT2FIX(z_near), FLT2FIX(z_far));
6261 : }
6262 : return JS_DupValue(ctx, this_val);
6263 : }
6264 832 : static JSValue mx_perspective(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6265 : {
6266 : Double fov, ar, z_near, z_far;
6267 832 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6268 832 : if (!mx || (argc<4)) return JS_EXCEPTION;
6269 832 : EVG_GET_FLOAT(fov, argv[0])
6270 832 : EVG_GET_FLOAT(ar, argv[1])
6271 832 : EVG_GET_FLOAT(z_near, argv[2])
6272 832 : EVG_GET_FLOAT(z_far, argv[3])
6273 832 : if ((argc>4) && JS_ToBool(ctx, argv[4])) {
6274 0 : gf_mx_perspective_reverse_z(mx, FLT2FIX(fov), FLT2FIX(ar), FLT2FIX(z_near), FLT2FIX(z_far));
6275 : } else {
6276 832 : gf_mx_perspective(mx, FLT2FIX(fov), FLT2FIX(ar), FLT2FIX(z_near), FLT2FIX(z_far));
6277 : }
6278 : return JS_DupValue(ctx, this_val);
6279 : }
6280 2 : static JSValue mx_lookat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6281 : {
6282 : GF_Vec pos, target, up;
6283 2 : GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id);
6284 2 : if (!mx || (argc!=3) ) return JS_EXCEPTION;
6285 :
6286 6 : WGL_GET_VEC3F(pos, argv[0]);
6287 6 : WGL_GET_VEC3F(target, argv[1]);
6288 6 : WGL_GET_VEC3F(up, argv[2]);
6289 :
6290 2 : gf_mx_lookat(mx, pos, target, up);
6291 : return JS_DupValue(ctx, this_val);
6292 : }
6293 :
6294 : static const JSCFunctionListEntry mx_funcs[] =
6295 : {
6296 : JS_CGETSET_MAGIC_DEF("identity", mx_getProperty, mx_setProperty, MX_PROP_IDENTITY),
6297 : JS_CGETSET_MAGIC_DEF("m", mx_getProperty, mx_setProperty, MX_PROP_M),
6298 : JS_CGETSET_MAGIC_DEF("yaw", mx_getProperty, NULL, MX_PROP_YAW),
6299 : JS_CGETSET_MAGIC_DEF("pitch", mx_getProperty, NULL, MX_PROP_PITCH),
6300 : JS_CGETSET_MAGIC_DEF("roll", mx_getProperty, NULL, MX_PROP_ROLL),
6301 : JS_CGETSET_MAGIC_DEF("dec_translate", mx_getProperty, NULL, MX_PROP_TRANLATE),
6302 : JS_CGETSET_MAGIC_DEF("dec_scale", mx_getProperty, NULL, MX_PROP_SCALE),
6303 : JS_CGETSET_MAGIC_DEF("dec_rotate", mx_getProperty, NULL, MX_PROP_ROTATE),
6304 : JS_CGETSET_MAGIC_DEF("dec_shear", mx_getProperty, NULL, MX_PROP_SHEAR),
6305 : JS_CFUNC_DEF("copy", 0, mx_copy),
6306 : JS_CFUNC_DEF("equal", 0, mx_equal),
6307 : JS_CFUNC_DEF("translate", 0, mx_translate),
6308 : JS_CFUNC_DEF("scale", 0, mx_scale),
6309 : JS_CFUNC_DEF("rotate", 0, mx_rotate),
6310 : JS_CFUNC_DEF("add", 0, mx_add),
6311 : JS_CFUNC_DEF("inverse", 0, mx_inverse),
6312 : JS_CFUNC_DEF("transpose", 0, mx_transpose),
6313 : JS_CFUNC_DEF("apply", 0, mx_apply),
6314 : JS_CFUNC_DEF("ortho", 0, mx_ortho),
6315 : JS_CFUNC_DEF("perspective", 0, mx_perspective),
6316 : JS_CFUNC_DEF("lookat", 0, mx_lookat),
6317 : };
6318 : /*
6319 : void gf_mx_rotate_vector(GF_Matrix *mx, GF_Vec *pt);
6320 : */
6321 :
6322 1702 : static JSValue mx_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv)
6323 : {
6324 : JSValue res;
6325 : GF_Matrix *mx;
6326 1702 : GF_SAFEALLOC(mx, GF_Matrix);
6327 1702 : if (!mx)
6328 0 : return js_throw_err(ctx, GF_OUT_OF_MEM);
6329 3404 : gf_mx_init(*mx);
6330 1702 : res = JS_NewObjectClass(ctx, matrix_class_id);
6331 1702 : JS_SetOpaque(res, mx);
6332 1702 : if (argc) {
6333 0 : GF_Matrix *from = JS_GetOpaque(argv[0], matrix_class_id);
6334 0 : if (from) {
6335 : gf_mx_copy(*mx, *from);
6336 0 : } else if (argc>=3) {
6337 : GF_Vec x_axis, y_axis, z_axis;
6338 0 : WGL_GET_VEC3F(x_axis, argv[0])
6339 0 : WGL_GET_VEC3F(y_axis, argv[1])
6340 0 : WGL_GET_VEC3F(z_axis, argv[2])
6341 0 : gf_mx_rotation_matrix_from_vectors(mx, x_axis, y_axis,z_axis);
6342 : }
6343 : }
6344 1702 : return res;
6345 : }
6346 :
6347 :
6348 15 : static JSValue evg_pixel_size(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv)
6349 : {
6350 15 : u32 pfmt=0;
6351 15 : if (!argc) return js_throw_err_msg(ctx, GF_BAD_PARAM, "missing pixel format parameter");
6352 30 : if (JS_IsString(argv[0])) {
6353 : const char *s = JS_ToCString(ctx, argv[0]);
6354 15 : if (s) {
6355 15 : pfmt = gf_pixel_fmt_parse(s);
6356 15 : JS_FreeCString(ctx, s);
6357 : }
6358 0 : } else if (JS_IsNumber(argv[0])) {
6359 0 : JS_ToInt32(ctx, &pfmt, argv[0]);
6360 : }
6361 15 : if (!pfmt) return js_throw_err_msg(ctx, GF_BAD_PARAM, "missing pixel format parameter");
6362 15 : return JS_NewInt32(ctx, gf_pixel_get_bytes_per_pixel(pfmt));
6363 : }
6364 :
6365 :
6366 58 : static int js_evg_load_module(JSContext *c, JSModuleDef *m)
6367 : {
6368 : JSValue ctor;
6369 : JSValue proto;
6370 : JSValue global;
6371 :
6372 58 : if (!canvas_class_id) {
6373 58 : JSRuntime *rt = JS_GetRuntime(c);
6374 :
6375 58 : JS_NewClassID(&canvas_class_id);
6376 58 : JS_NewClass(rt, canvas_class_id, &canvas_class);
6377 :
6378 58 : JS_NewClassID(&path_class_id);
6379 58 : JS_NewClass(rt, path_class_id, &path_class);
6380 :
6381 58 : JS_NewClassID(&mx2d_class_id);
6382 58 : JS_NewClass(rt, mx2d_class_id, &mx2d_class);
6383 :
6384 58 : JS_NewClassID(&colmx_class_id);
6385 58 : JS_NewClass(rt, colmx_class_id, &colmx_class);
6386 :
6387 58 : JS_NewClassID(&stencil_class_id);
6388 58 : JS_NewClass(rt, stencil_class_id, &stencil_class);
6389 :
6390 58 : JS_NewClassID(&texture_class_id);
6391 58 : JS_NewClass(rt, texture_class_id, &texture_class);
6392 :
6393 58 : JS_NewClassID(&text_class_id);
6394 58 : JS_NewClass(rt, text_class_id, &text_class);
6395 :
6396 58 : JS_NewClassID(&matrix_class_id);
6397 58 : JS_NewClass(rt, matrix_class_id, &matrix_class);
6398 :
6399 58 : JS_NewClassID(&canvas3d_class_id);
6400 58 : JS_NewClass(rt, canvas3d_class_id, &canvas3d_class);
6401 :
6402 58 : JS_NewClassID(&shader_class_id);
6403 58 : JS_NewClass(rt, shader_class_id, &shader_class);
6404 :
6405 58 : JS_NewClassID(&vai_class_id);
6406 58 : JS_NewClass(rt, vai_class_id, &vai_class);
6407 :
6408 58 : JS_NewClassID(&va_class_id);
6409 58 : JS_NewClass(rt, va_class_id, &va_class);
6410 :
6411 : #ifdef EVG_USE_JS_SHADER
6412 : JS_NewClassID(&fragment_class_id);
6413 : JS_NewClass(rt, fragment_class_id, &fragment_class);
6414 :
6415 : JS_NewClassID(&vertex_class_id);
6416 : JS_NewClass(rt, vertex_class_id, &vertex_class);
6417 :
6418 : JS_NewClassID(&vaires_class_id);
6419 : JS_NewClass(rt, vaires_class_id, &vaires_class);
6420 : #endif// EVG_USE_JS_SHADER
6421 :
6422 : }
6423 58 : proto = JS_NewObject(c);
6424 58 : JS_SetPropertyFunctionList(c, proto, canvas_funcs, countof(canvas_funcs));
6425 58 : JS_SetClassProto(c, canvas_class_id, proto);
6426 :
6427 58 : proto = JS_NewObject(c);
6428 58 : JS_SetPropertyFunctionList(c, proto, path_funcs, countof(path_funcs));
6429 58 : JS_SetClassProto(c, path_class_id, proto);
6430 :
6431 58 : proto = JS_NewObject(c);
6432 58 : JS_SetPropertyFunctionList(c, proto, mx2d_funcs, countof(mx2d_funcs));
6433 58 : JS_SetClassProto(c, mx2d_class_id, proto);
6434 :
6435 58 : proto = JS_NewObject(c);
6436 58 : JS_SetPropertyFunctionList(c, proto, colmx_funcs, countof(colmx_funcs));
6437 58 : JS_SetClassProto(c, colmx_class_id, proto);
6438 :
6439 58 : proto = JS_NewObject(c);
6440 58 : JS_SetPropertyFunctionList(c, proto, stencil_funcs, countof(stencil_funcs));
6441 58 : JS_SetClassProto(c, stencil_class_id, proto);
6442 :
6443 58 : proto = JS_NewObject(c);
6444 58 : JS_SetPropertyFunctionList(c, proto, texture_funcs, countof(texture_funcs));
6445 58 : JS_SetClassProto(c, texture_class_id, proto);
6446 :
6447 58 : proto = JS_NewObject(c);
6448 58 : JS_SetPropertyFunctionList(c, proto, text_funcs, countof(text_funcs));
6449 58 : JS_SetClassProto(c, text_class_id, proto);
6450 :
6451 58 : proto = JS_NewObject(c);
6452 58 : JS_SetPropertyFunctionList(c, proto, mx_funcs, countof(mx_funcs));
6453 58 : JS_SetClassProto(c, matrix_class_id, proto);
6454 :
6455 58 : proto = JS_NewObject(c);
6456 58 : JS_SetPropertyFunctionList(c, proto, canvas3d_funcs, countof(canvas3d_funcs));
6457 58 : JS_SetClassProto(c, canvas3d_class_id, proto);
6458 :
6459 : #ifdef EVG_USE_JS_SHADER
6460 : proto = JS_NewObject(c);
6461 : JS_SetPropertyFunctionList(c, proto, fragment_funcs, countof(fragment_funcs));
6462 : JS_SetClassProto(c, fragment_class_id, proto);
6463 :
6464 : proto = JS_NewObject(c);
6465 : JS_SetPropertyFunctionList(c, proto, vertex_funcs, countof(vertex_funcs));
6466 : JS_SetClassProto(c, vertex_class_id, proto);
6467 :
6468 : proto = JS_NewObject(c);
6469 : JS_SetPropertyFunctionList(c, proto, vaires_funcs, countof(vaires_funcs));
6470 : JS_SetClassProto(c, vaires_class_id, proto);
6471 : #endif
6472 :
6473 58 : proto = JS_NewObject(c);
6474 58 : JS_SetPropertyFunctionList(c, proto, shader_funcs, countof(shader_funcs));
6475 58 : JS_SetClassProto(c, shader_class_id, proto);
6476 :
6477 58 : proto = JS_NewObject(c);
6478 58 : JS_SetPropertyFunctionList(c, proto, vai_funcs, countof(vai_funcs));
6479 58 : JS_SetClassProto(c, vai_class_id, proto);
6480 :
6481 58 : proto = JS_NewObject(c);
6482 58 : JS_SetPropertyFunctionList(c, proto, va_funcs, countof(va_funcs));
6483 58 : JS_SetClassProto(c, va_class_id, proto);
6484 :
6485 :
6486 58 : global = JS_GetGlobalObject(c);
6487 58 : JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_PAD", JS_NewInt32(c, GF_GRADIENT_MODE_PAD));
6488 58 : JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_STREAD", JS_NewInt32(c, GF_GRADIENT_MODE_SPREAD));
6489 58 : JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_REPEAT", JS_NewInt32(c, GF_GRADIENT_MODE_REPEAT));
6490 :
6491 58 : JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_HIGH_SPEED", JS_NewInt32(c, GF_TEXTURE_FILTER_HIGH_SPEED));
6492 58 : JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_MID", JS_NewInt32(c, GF_TEXTURE_FILTER_MID));
6493 58 : JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_HIGH_QUALITY", JS_NewInt32(c, GF_TEXTURE_FILTER_HIGH_QUALITY));
6494 :
6495 58 : JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_OPEN", JS_NewInt32(c, GF_PATH2D_ARC_OPEN));
6496 58 : JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_OPEN", JS_NewInt32(c, GF_PATH2D_ARC_OPEN));
6497 58 : JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_PIE", JS_NewInt32(c, GF_PATH2D_ARC_PIE));
6498 :
6499 58 : JS_SetPropertyStr(c, global, "GF_PATH_LINE_CENTER", JS_NewInt32(c, GF_PATH_LINE_CENTER));
6500 58 : JS_SetPropertyStr(c, global, "GF_PATH_LINE_INSIDE", JS_NewInt32(c, GF_PATH_LINE_INSIDE));
6501 58 : JS_SetPropertyStr(c, global, "GF_PATH_LINE_OUTSIDE", JS_NewInt32(c, GF_PATH_LINE_OUTSIDE));
6502 58 : JS_SetPropertyStr(c, global, "GF_LINE_CAP_FLAT", JS_NewInt32(c, GF_LINE_CAP_FLAT));
6503 58 : JS_SetPropertyStr(c, global, "GF_LINE_CAP_ROUND", JS_NewInt32(c, GF_LINE_CAP_ROUND));
6504 58 : JS_SetPropertyStr(c, global, "GF_LINE_CAP_SQUARE", JS_NewInt32(c, GF_LINE_CAP_SQUARE));
6505 58 : JS_SetPropertyStr(c, global, "GF_LINE_CAP_TRIANGLE", JS_NewInt32(c, GF_LINE_CAP_TRIANGLE));
6506 58 : JS_SetPropertyStr(c, global, "GF_LINE_JOIN_MITER", JS_NewInt32(c, GF_LINE_JOIN_MITER));
6507 58 : JS_SetPropertyStr(c, global, "GF_LINE_JOIN_ROUND", JS_NewInt32(c, GF_LINE_JOIN_ROUND));
6508 58 : JS_SetPropertyStr(c, global, "GF_LINE_JOIN_BEVEL", JS_NewInt32(c, GF_LINE_JOIN_BEVEL));
6509 58 : JS_SetPropertyStr(c, global, "GF_LINE_JOIN_MITER_SVG", JS_NewInt32(c, GF_LINE_JOIN_MITER_SVG));
6510 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_PLAIN", JS_NewInt32(c, GF_DASH_STYLE_PLAIN));
6511 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH", JS_NewInt32(c, GF_DASH_STYLE_DASH));
6512 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DOT", JS_NewInt32(c, GF_DASH_STYLE_DOT));
6513 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DOT));
6514 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DASH_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DASH_DOT));
6515 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DOT_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DOT_DOT));
6516 58 : JS_SetPropertyStr(c, global, "GF_DASH_STYLE_SVG", JS_NewInt32(c, GF_DASH_STYLE_SVG));
6517 :
6518 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_TOP", JS_NewInt32(c, TXT_BL_TOP));
6519 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_HANGING", JS_NewInt32(c, TXT_BL_HANGING));
6520 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_MIDDLE", JS_NewInt32(c, TXT_BL_MIDDLE));
6521 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_ALPHABETIC", JS_NewInt32(c, TXT_BL_ALPHABETIC));
6522 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_IDEOGRAPHIC", JS_NewInt32(c, TXT_BL_IDEOGRAPHIC));
6523 58 : JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_BOTTOM", JS_NewInt32(c, TXT_BL_BOTTOM));
6524 :
6525 58 : JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_START", JS_NewInt32(c, TXT_AL_START));
6526 58 : JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_END", JS_NewInt32(c, TXT_AL_END));
6527 58 : JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_LEFT", JS_NewInt32(c, TXT_AL_LEFT));
6528 58 : JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_RIGHT", JS_NewInt32(c, TXT_AL_RIGHT));
6529 58 : JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_CENTER", JS_NewInt32(c, TXT_AL_CENTER));
6530 :
6531 58 : JS_SetPropertyStr(c, global, "GF_EVG_SRC_ATOP", JS_NewInt32(c, GF_EVG_SRC_ATOP));
6532 58 : JS_SetPropertyStr(c, global, "GF_EVG_SRC_IN", JS_NewInt32(c, GF_EVG_SRC_IN));
6533 58 : JS_SetPropertyStr(c, global, "GF_EVG_SRC_OUT", JS_NewInt32(c, GF_EVG_SRC_OUT));
6534 58 : JS_SetPropertyStr(c, global, "GF_EVG_SRC_OVER", JS_NewInt32(c, GF_EVG_SRC_OVER));
6535 58 : JS_SetPropertyStr(c, global, "GF_EVG_DST_ATOP", JS_NewInt32(c, GF_EVG_DST_ATOP));
6536 58 : JS_SetPropertyStr(c, global, "GF_EVG_DST_IN", JS_NewInt32(c, GF_EVG_DST_IN));
6537 58 : JS_SetPropertyStr(c, global, "GF_EVG_DST_OUT", JS_NewInt32(c, GF_EVG_DST_OUT));
6538 58 : JS_SetPropertyStr(c, global, "GF_EVG_DST_OVER", JS_NewInt32(c, GF_EVG_DST_OVER));
6539 58 : JS_SetPropertyStr(c, global, "GF_EVG_LIGHTER", JS_NewInt32(c, GF_EVG_LIGHTER));
6540 58 : JS_SetPropertyStr(c, global, "GF_EVG_COPY", JS_NewInt32(c, GF_EVG_COPY));
6541 58 : JS_SetPropertyStr(c, global, "GF_EVG_XOR", JS_NewInt32(c, GF_EVG_XOR));
6542 :
6543 58 : JS_SetPropertyStr(c, global, "GF_EVG_POINTS", JS_NewInt32(c, GF_EVG_POINTS));
6544 58 : JS_SetPropertyStr(c, global, "GF_EVG_POLYGON", JS_NewInt32(c, GF_EVG_POLYGON));
6545 58 : JS_SetPropertyStr(c, global, "GF_EVG_LINES", JS_NewInt32(c, GF_EVG_LINES));
6546 58 : JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLES", JS_NewInt32(c, GF_EVG_TRIANGLES));
6547 58 : JS_SetPropertyStr(c, global, "GF_EVG_QUADS", JS_NewInt32(c, GF_EVG_QUADS));
6548 58 : JS_SetPropertyStr(c, global, "GF_EVG_LINE_STRIP", JS_NewInt32(c, GF_EVG_LINE_STRIP));
6549 58 : JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLE_STRIP", JS_NewInt32(c, GF_EVG_TRIANGLE_STRIP));
6550 58 : JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLE_FAN", JS_NewInt32(c, GF_EVG_TRIANGLE_FAN));
6551 :
6552 58 : JS_SetPropertyStr(c, global, "GF_EVG_SHADER_FRAGMENT", JS_NewInt32(c, GF_EVG_SHADER_FRAGMENT));
6553 58 : JS_SetPropertyStr(c, global, "GF_EVG_SHADER_VERTEX", JS_NewInt32(c, GF_EVG_SHADER_VERTEX));
6554 :
6555 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEVER", JS_NewInt32(c, GF_EVGDEPTH_NEVER));
6556 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS));
6557 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS));
6558 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_EQUAL));
6559 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEQUAL", JS_NewInt32(c, GF_EVGDEPTH_NEQUAL));
6560 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS", JS_NewInt32(c, GF_EVGDEPTH_LESS));
6561 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_LESS_EQUAL));
6562 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER", JS_NewInt32(c, GF_EVGDEPTH_GREATER));
6563 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_GREATER_EQUAL));
6564 :
6565 58 : JS_SetPropertyStr(c, global, "GF_EVG_VAI_VERTEX_INDEX", JS_NewInt32(c, GF_EVG_VAI_VERTEX_INDEX));
6566 58 : JS_SetPropertyStr(c, global, "GF_EVG_VAI_VERTEX", JS_NewInt32(c, GF_EVG_VAI_VERTEX));
6567 58 : JS_SetPropertyStr(c, global, "GF_EVG_VAI_PRIMITIVE", JS_NewInt32(c, GF_EVG_VAI_PRIMITIVE));
6568 :
6569 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_DISABLE", JS_NewInt32(c, GF_EVGDEPTH_DISABLE));
6570 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEVER", JS_NewInt32(c, GF_EVGDEPTH_NEVER));
6571 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS));
6572 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_EQUAL));
6573 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEQUAL", JS_NewInt32(c, GF_EVGDEPTH_NEQUAL));
6574 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS", JS_NewInt32(c, GF_EVGDEPTH_LESS));
6575 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_LESS_EQUAL));
6576 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER", JS_NewInt32(c, GF_EVGDEPTH_GREATER));
6577 58 : JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_GREATER_EQUAL));
6578 :
6579 : JS_FreeValue(c, global);
6580 :
6581 :
6582 : /*export constructors*/
6583 58 : ctor = JS_NewCFunction2(c, canvas_constructor, "Canvas", 1, JS_CFUNC_constructor, 0);
6584 58 : JS_SetModuleExport(c, m, "Canvas", ctor);
6585 58 : ctor = JS_NewCFunction2(c, path_constructor, "Path", 1, JS_CFUNC_constructor, 0);
6586 58 : JS_SetModuleExport(c, m, "Path", ctor);
6587 58 : ctor = JS_NewCFunction2(c, mx2d_constructor, "Matrix2D", 1, JS_CFUNC_constructor, 0);
6588 58 : JS_SetModuleExport(c, m, "Matrix2D", ctor);
6589 58 : ctor = JS_NewCFunction2(c, colmx_constructor, "ColorMatrix", 1, JS_CFUNC_constructor, 0);
6590 58 : JS_SetModuleExport(c, m, "ColorMatrix", ctor);
6591 58 : ctor = JS_NewCFunction2(c, solid_brush_constructor, "SolidBrush", 1, JS_CFUNC_constructor, 0);
6592 58 : JS_SetModuleExport(c, m, "SolidBrush", ctor);
6593 58 : ctor = JS_NewCFunction2(c, linear_gradient_constructor, "LinearGradient", 1, JS_CFUNC_constructor, 0);
6594 58 : JS_SetModuleExport(c, m, "LinearGradient", ctor);
6595 58 : ctor = JS_NewCFunction2(c, radial_gradient_constructor, "RadialGradient", 1, JS_CFUNC_constructor, 0);
6596 58 : JS_SetModuleExport(c, m, "RadialGradient", ctor);
6597 58 : ctor = JS_NewCFunction2(c, texture_constructor, "Texture", 1, JS_CFUNC_constructor, 0);
6598 58 : JS_SetModuleExport(c, m, "Texture", ctor);
6599 58 : ctor = JS_NewCFunction2(c, canvas3d_constructor, "Canvas3D", 1, JS_CFUNC_constructor, 0);
6600 58 : JS_SetModuleExport(c, m, "Canvas3D", ctor);
6601 58 : ctor = JS_NewCFunction2(c, text_constructor, "Text", 1, JS_CFUNC_constructor, 0);
6602 58 : JS_SetModuleExport(c, m, "Text", ctor);
6603 58 : ctor = JS_NewCFunction2(c, mx_constructor, "Matrix", 1, JS_CFUNC_constructor, 0);
6604 58 : JS_SetModuleExport(c, m, "Matrix", ctor);
6605 58 : ctor = JS_NewCFunction2(c, vai_constructor, "VertexAttribInterpolator", 1, JS_CFUNC_constructor, 0);
6606 58 : JS_SetModuleExport(c, m, "VertexAttribInterpolator", ctor);
6607 58 : ctor = JS_NewCFunction2(c, va_constructor, "VertexAttrib", 1, JS_CFUNC_constructor, 0);
6608 58 : JS_SetModuleExport(c, m, "VertexAttrib", ctor);
6609 :
6610 58 : ctor = JS_NewCFunction2(c, evg_pixel_size, "PixelSize", 1, JS_CFUNC_generic, 0);
6611 58 : JS_SetModuleExport(c, m, "PixelSize", ctor);
6612 :
6613 58 : return 0;
6614 : }
6615 :
6616 64 : void qjs_module_init_evg(JSContext *ctx)
6617 : {
6618 : JSModuleDef *m;
6619 64 : m = JS_NewCModule(ctx, "evg", js_evg_load_module);
6620 64 : if (!m) return;
6621 :
6622 64 : JS_AddModuleExport(ctx, m, "Canvas");
6623 64 : JS_AddModuleExport(ctx, m, "Path");
6624 64 : JS_AddModuleExport(ctx, m, "Matrix2D");
6625 64 : JS_AddModuleExport(ctx, m, "ColorMatrix");
6626 64 : JS_AddModuleExport(ctx, m, "SolidBrush");
6627 64 : JS_AddModuleExport(ctx, m, "LinearGradient");
6628 64 : JS_AddModuleExport(ctx, m, "RadialGradient");
6629 64 : JS_AddModuleExport(ctx, m, "Texture");
6630 64 : JS_AddModuleExport(ctx, m, "Text");
6631 64 : JS_AddModuleExport(ctx, m, "Matrix");
6632 64 : JS_AddModuleExport(ctx, m, "Canvas3D");
6633 64 : JS_AddModuleExport(ctx, m, "VertexAttribInterpolator");
6634 64 : JS_AddModuleExport(ctx, m, "VertexAttrib");
6635 64 : JS_AddModuleExport(ctx, m, "PixelSize");
6636 64 : return;
6637 : }
6638 :
6639 : #else
6640 : void qjs_module_init_evg(void *ctx)
6641 : {
6642 :
6643 : }
6644 : #endif
6645 :
|