/src/gpac/src/jsmods/evg.c
Line | Count | Source |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2019-2023 |
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) && !defined(GPAC_DISABLE_EVG) |
36 | | |
37 | | |
38 | | /*base SVG type*/ |
39 | | #include <gpac/nodes_svg.h> |
40 | | #include <gpac/nodes_mpeg4.h> |
41 | | #include <gpac/nodes_x3d.h> |
42 | | /*dom events*/ |
43 | | #include <gpac/evg.h> |
44 | | |
45 | | #include "../scenegraph/qjs_common.h" |
46 | | |
47 | | #include <gpac/internal/compositor_dev.h> |
48 | | |
49 | | /*for texture from png/rgb*/ |
50 | | #include <gpac/bitstream.h> |
51 | | #include <gpac/avparse.h> |
52 | | #include <gpac/network.h> |
53 | | |
54 | | #ifdef GPAC_HAS_FFMPEG |
55 | | #include "../filters/ff_common.h" |
56 | | #endif |
57 | | |
58 | | #ifndef GPAC_DISABLE_3D |
59 | | #include <gpac/internal/mesh.h> |
60 | | #endif |
61 | | |
62 | | |
63 | 0 | #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; } |
64 | | #define CLAMPCOLF(_name) if (_name<0) _name=0; else if (_name>1.0) _name=1.0; |
65 | | |
66 | | uint8_t *evg_get_array(JSContext *ctx, JSValueConst obj, u32 *size); |
67 | | |
68 | | //test code, unused |
69 | | //#define BUILTIN_SHADERS |
70 | | |
71 | | //not used, wau too slow - we kept the code for future testing |
72 | | //#define EVG_USE_JS_SHADER |
73 | | |
74 | | typedef struct |
75 | | { |
76 | | u32 width, height, pf, stride, stride_uv, nb_comp; |
77 | | char *data; |
78 | | u32 data_size; |
79 | | u8 owns_data; |
80 | | u8 wide; |
81 | | u32 flags; |
82 | | GF_EVGStencil *stencil; |
83 | | JSValue param_fun, obj, par_obj; |
84 | | JSContext *ctx; |
85 | | |
86 | | #ifndef GPAC_DISABLE_3D |
87 | | char *named_tx; |
88 | | void *gl_named_tx; |
89 | | u8 force_resetup; |
90 | | #endif //GPAC_DISABLE_3D |
91 | | |
92 | | |
93 | | #ifdef GPAC_HAS_FFMPEG |
94 | | struct SwsContext *swscaler; |
95 | | #endif |
96 | | } GF_JSTexture; |
97 | | |
98 | 0 | #define MAX_ATTR_DIM 4 |
99 | | typedef struct |
100 | | { |
101 | | u32 dim; |
102 | | u8 comp_type; |
103 | | } EVG_VAIRes; |
104 | | |
105 | | enum |
106 | | { |
107 | | GF_EVG_VAI_VERTEX_INDEX=0, |
108 | | GF_EVG_VAI_VERTEX, |
109 | | GF_EVG_VAI_PRIMITIVE, |
110 | | }; |
111 | | |
112 | | typedef struct |
113 | | { |
114 | | u32 prim_idx; |
115 | | u32 nb_comp; |
116 | | Float *values; |
117 | | u32 nb_values; |
118 | | JSValue ab; |
119 | | #ifdef EVG_USE_JS_SHADER |
120 | | JSValue res; |
121 | | #endif |
122 | | u32 interp_type; |
123 | | |
124 | | Float anchors[3][MAX_ATTR_DIM]; |
125 | | EVG_VAIRes result; |
126 | | |
127 | | Bool normalize; |
128 | | } EVG_VAI; |
129 | | |
130 | | typedef struct |
131 | | { |
132 | | u32 nb_comp, att_type; |
133 | | Float *values; |
134 | | u32 nb_values; |
135 | | JSValue ab; |
136 | | JSValue res; |
137 | | u32 interp_type; |
138 | | |
139 | | Bool normalize; |
140 | | } EVG_VA; |
141 | | |
142 | | enum |
143 | | { |
144 | | COMP_X = 1,//x or r or s |
145 | | COMP_Y = 1<<1,//y or g or t |
146 | | COMP_Z = 1<<2, //z or b |
147 | | COMP_Q = 1<<3, //w/q or a |
148 | | COMP_V2_XY = COMP_X|COMP_Y, |
149 | | COMP_V2_XZ = COMP_X|COMP_Z, |
150 | | COMP_V2_YZ = COMP_Y|COMP_Z, |
151 | | COMP_V3 = COMP_X|COMP_Y|COMP_Z, |
152 | | COMP_V4 = COMP_X|COMP_Y|COMP_Z|COMP_Q, |
153 | | |
154 | | COMP_BOOL, |
155 | | COMP_INT, |
156 | | COMP_FLOAT, |
157 | | //for builtin shaders only |
158 | | COMP_TX, |
159 | | |
160 | | COMP_FLAG_INT = 1<<6 |
161 | | }; |
162 | | |
163 | | typedef struct |
164 | | { |
165 | | s32 x; |
166 | | s32 y; |
167 | | s32 z; |
168 | | s32 q; |
169 | | } GF_IVec4; |
170 | | |
171 | | typedef struct |
172 | | { |
173 | | u8 op_type; |
174 | | u8 cond_type; |
175 | | u8 left_value_type; |
176 | | u8 right_value_type; |
177 | | s32 left_value, right_value, right_value_second; |
178 | | char *uni_name; |
179 | | JSValue tx_ref; |
180 | | GF_JSTexture *tx; |
181 | | |
182 | | //we separate VAI/MX from base value in order to be able to assign a VAI value |
183 | | union { |
184 | | struct { |
185 | | EVG_VAI *vai; |
186 | | JSValue ref; |
187 | | } vai; |
188 | | struct { |
189 | | EVG_VA *va; |
190 | | JSValue ref; |
191 | | } va; |
192 | | struct { |
193 | | GF_Matrix *mx; |
194 | | JSValue ref; |
195 | | } mx; |
196 | | }; |
197 | | |
198 | | union { |
199 | | Float vec[4]; |
200 | | s32 veci[4]; |
201 | | s32 ival; |
202 | | Bool bval; |
203 | | }; |
204 | | } ShaderOp; |
205 | | |
206 | | enum |
207 | | { |
208 | | GF_EVG_SHADER_FRAGMENT=1, |
209 | | GF_EVG_SHADER_VERTEX, |
210 | | }; |
211 | | |
212 | | typedef struct |
213 | | { |
214 | | char *name; |
215 | | union { |
216 | | GF_Vec4 vecval; |
217 | | s32 ival; |
218 | | Bool bval; |
219 | | void *ptr; |
220 | | }; |
221 | | u8 value_type; |
222 | | } ShaderVar; |
223 | | |
224 | | |
225 | | typedef struct __evg_shader |
226 | | { |
227 | | u32 mode; |
228 | | u32 nb_ops, alloc_ops; |
229 | | ShaderOp *ops; |
230 | | u32 nb_vars, alloc_vars; |
231 | | ShaderVar *vars; |
232 | | Bool invalid, disable_early_z; |
233 | | Bool has_branches; |
234 | | GF_List *vars_stack; |
235 | | |
236 | | #ifdef BUILTIN_SHADERS |
237 | | //native shaders |
238 | | Bool (*frag_shader)(void *udta, GF_EVGFragmentParam *frag); |
239 | | Bool (*frag_shader_init)(void *udta, GF_EVGFragmentParam *frag, u32 th_id, Bool is_cleanup); |
240 | | #endif |
241 | | } EVGShader; |
242 | | |
243 | | typedef struct |
244 | | { |
245 | | u32 width, height, pf, stride, stride_uv, mem_size; |
246 | | char *data; |
247 | | Bool owns_data; |
248 | | Bool center_coords; |
249 | | GF_EVGSurface *surface; |
250 | | u32 composite_op; |
251 | | JSValue alpha_cbk; |
252 | | JSValue frag_shader; |
253 | | Bool frag_is_cbk; |
254 | | JSValue vert_shader; |
255 | | Bool vert_is_cbk; |
256 | | |
257 | | JSValue depth_buffer; |
258 | | |
259 | | |
260 | | EVGShader *frag, *vert; |
261 | | |
262 | | JSContext *ctx; |
263 | | JSValue obj; |
264 | | #ifdef EVG_USE_JS_SHADER |
265 | | JSValue frag_obj; |
266 | | JSValue vert_obj; |
267 | | #endif |
268 | | |
269 | | } GF_JSCanvas; |
270 | | |
271 | | |
272 | | |
273 | | typedef struct |
274 | | { |
275 | | GF_FontManager *fm; |
276 | | GF_Path *path; |
277 | | char **fontnames; |
278 | | u32 nb_fonts; |
279 | | |
280 | | Double font_size; |
281 | | u32 align; |
282 | | u32 baseline; |
283 | | u32 styles; |
284 | | GF_List *spans; |
285 | | Bool horizontal; |
286 | | Bool flip; |
287 | | Double maxWidth; |
288 | | Double lineSpacing; |
289 | | Fixed min_x, min_y, max_x, max_y, max_w, max_h; |
290 | | GF_Font *font; |
291 | | Bool path_for_centered; |
292 | | Bool right_to_left; |
293 | | } GF_JSText; |
294 | | |
295 | | |
296 | | JSClassID canvas_class_id; |
297 | | JSClassID path_class_id; |
298 | | JSClassID mx2d_class_id; |
299 | | JSClassID colmx_class_id; |
300 | | JSClassID stencil_class_id; |
301 | | JSClassID texture_class_id; |
302 | | JSClassID text_class_id; |
303 | | JSClassID matrix_class_id; |
304 | | JSClassID mesh_class_id; |
305 | | #ifdef EVG_USE_JS_SHADER |
306 | | JSClassID fragment_class_id; |
307 | | JSClassID vertex_class_id; |
308 | | JSClassID vaires_class_id; |
309 | | #endif |
310 | | JSClassID vai_class_id; |
311 | | JSClassID va_class_id; |
312 | | JSClassID shader_class_id; |
313 | | |
314 | | #ifndef GPAC_DISABLE_FONTS |
315 | | static void text_set_path(GF_JSCanvas *canvas, GF_JSText *text); |
316 | | #endif |
317 | | |
318 | | Bool get_color_from_args(JSContext *c, int argc, JSValueConst *argv, u32 idx, Double *a, Double *r, Double *g, Double *b); |
319 | | static Bool get_color(JSContext *c, JSValueConst obj, Double *a, Double *r, Double *g, Double *b); |
320 | | |
321 | | static void canvas_finalize(JSRuntime *rt, JSValue obj) |
322 | 0 | { |
323 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
324 | 0 | if (!canvas) return; |
325 | 0 | JS_FreeValueRT(rt, canvas->alpha_cbk); |
326 | 0 | JS_FreeValueRT(rt, canvas->frag_shader); |
327 | 0 | JS_FreeValueRT(rt, canvas->vert_shader); |
328 | | |
329 | |
|
330 | | #ifdef EVG_USE_JS_SHADER |
331 | | JS_FreeValueRT(rt, canvas->frag_obj); |
332 | | JS_FreeValueRT(rt, canvas->vert_obj); |
333 | | #endif |
334 | 0 | JS_FreeValueRT(rt, canvas->depth_buffer); |
335 | |
|
336 | 0 | if (canvas->owns_data) |
337 | 0 | gf_free(canvas->data); |
338 | 0 | if (canvas->surface) |
339 | 0 | gf_evg_surface_delete(canvas->surface); |
340 | 0 | gf_free(canvas); |
341 | 0 | } |
342 | | |
343 | | static void canvas_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func) |
344 | 0 | { |
345 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
346 | 0 | if (!canvas) return; |
347 | 0 | JS_MarkValue(rt, canvas->alpha_cbk, mark_func); |
348 | 0 | JS_MarkValue(rt, canvas->frag_shader, mark_func); |
349 | 0 | JS_MarkValue(rt, canvas->vert_shader, mark_func); |
350 | |
|
351 | | #ifdef EVG_USE_JS_SHADER |
352 | | JS_MarkValue(rt, canvas->frag_obj, mark_func); |
353 | | JS_MarkValue(rt, canvas->vert_obj, mark_func); |
354 | | #endif |
355 | 0 | JS_MarkValue(rt, canvas->depth_buffer, mark_func); |
356 | 0 | } |
357 | | |
358 | | JSClassDef canvas_class = { |
359 | | "Canvas", |
360 | | .finalizer = canvas_finalize, |
361 | | .gc_mark = canvas_gc_mark |
362 | | }; |
363 | | |
364 | | enum |
365 | | { |
366 | | GF_EVG_CENTERED = 0, |
367 | | GF_EVG_PATH, |
368 | | GF_EVG_MATRIX, |
369 | | GF_EVG_MATRIX_3D, |
370 | | GF_EVG_CLIPPER, |
371 | | GF_EVG_COMPOSITE_OP, |
372 | | GF_EVG_ALPHA_FUN, |
373 | | GF_EVG_IS_YUV, |
374 | | GF_EVG_BIT_DEPTH, |
375 | | GF_EVG_MASK_MODE, |
376 | | GF_EVG_FRAG_SHADER, |
377 | | GF_EVG_VERT_SHADER, |
378 | | GF_EVG_CCW, |
379 | | GF_EVG_BACKCULL, |
380 | | GF_EVG_MINDEPTH, |
381 | | GF_EVG_MAXDEPTH, |
382 | | GF_EVG_DEPTHTEST, |
383 | | GF_EVG_ANTIALIAS, |
384 | | GF_EVG_POINTSIZE, |
385 | | GF_EVG_POINTSMOOTH, |
386 | | GF_EVG_LINESIZE, |
387 | | GF_EVG_CLIP_ZERO, |
388 | | GF_EVG_DEPTH_BUFFER, |
389 | | GF_EVG_DEPTH_TEST, |
390 | | GF_EVG_WRITE_DEPTH, |
391 | | GF_EVG_RASTER_LEVEL, |
392 | | }; |
393 | | |
394 | | u8 evg_get_alpha(void *cbk, u8 src_alpha, s32 x, s32 y) |
395 | 0 | { |
396 | 0 | u32 res_a=0; |
397 | 0 | GF_JSCanvas *canvas = cbk; |
398 | 0 | JSValue ret, args[3]; |
399 | 0 | args[0] = JS_NewInt32(canvas->ctx, src_alpha); |
400 | 0 | args[1] = JS_NewInt32(canvas->ctx, x); |
401 | 0 | args[2] = JS_NewInt32(canvas->ctx, y); |
402 | 0 | ret = JS_Call(canvas->ctx, canvas->alpha_cbk, canvas->obj, 3, args); |
403 | 0 | JS_ToInt32(canvas->ctx, &res_a, ret); |
404 | 0 | return res_a; |
405 | |
|
406 | 0 | } |
407 | | |
408 | | static JSValue canvas_constructor_internal(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv, GF_JSCanvas *canvas_reconfig) |
409 | 0 | { |
410 | 0 | u32 width, height, pf=0, osize; |
411 | 0 | size_t data_size=0; |
412 | 0 | u8 *data=NULL; |
413 | 0 | u32 stride = 0; |
414 | 0 | u32 stride_uv = 0; |
415 | 0 | GF_JSCanvas *the_canvas = NULL; |
416 | 0 | GF_JSCanvas *canvas = NULL; |
417 | 0 | GF_Err e; |
418 | |
|
419 | 0 | if (argc<3) |
420 | 0 | return GF_JS_EXCEPTION(c); |
421 | 0 | if (JS_ToInt32(c, &width, argv[0])) |
422 | 0 | return GF_JS_EXCEPTION(c); |
423 | 0 | if (JS_ToInt32(c, &height, argv[1])) |
424 | 0 | return GF_JS_EXCEPTION(c); |
425 | 0 | if (JS_IsString(argv[2])) { |
426 | 0 | const char *str = JS_ToCString(c, argv[2]); |
427 | 0 | pf = gf_pixel_fmt_parse(str); |
428 | 0 | JS_FreeCString(c, str); |
429 | 0 | } else if (JS_ToInt32(c, &pf, argv[2])) { |
430 | 0 | return GF_JS_EXCEPTION(c); |
431 | 0 | } |
432 | 0 | if (!width || !height || !pf) |
433 | 0 | return GF_JS_EXCEPTION(c); |
434 | | |
435 | 0 | if (argc>3) { |
436 | 0 | s32 idx=0; |
437 | 0 | if (JS_IsObject(argv[3])) { |
438 | 0 | data = JS_GetArrayBuffer(c, &data_size, argv[3]); |
439 | 0 | if (!data) return GF_JS_EXCEPTION(c); |
440 | 0 | idx=1; |
441 | 0 | } else if (!JS_IsInteger(argv[3])) |
442 | 0 | return GF_JS_EXCEPTION(c); |
443 | | |
444 | 0 | if (argc>3+idx) { |
445 | 0 | if (JS_ToInt32(c, &stride, argv[3+idx])) |
446 | 0 | return GF_JS_EXCEPTION(c); |
447 | 0 | if (argc>4+idx) { |
448 | 0 | if (JS_ToInt32(c, &stride_uv, argv[4+idx])) |
449 | 0 | return GF_JS_EXCEPTION(c); |
450 | 0 | } |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | 0 | if (!canvas_reconfig) { |
455 | 0 | GF_SAFEALLOC(the_canvas, GF_JSCanvas); |
456 | |
|
457 | 0 | if (!the_canvas) |
458 | 0 | return GF_JS_EXCEPTION(c); |
459 | 0 | } |
460 | | |
461 | 0 | if (!gf_pixel_get_size_info(pf, width, height, &osize, &stride, &stride_uv, NULL, NULL)) { |
462 | 0 | if (canvas) |
463 | 0 | gf_free(canvas); |
464 | 0 | return GF_JS_EXCEPTION(c); |
465 | 0 | } |
466 | 0 | if (data && (data_size<osize)) { |
467 | 0 | if (the_canvas) |
468 | 0 | gf_free(the_canvas); |
469 | 0 | return GF_JS_EXCEPTION(c); |
470 | 0 | } |
471 | 0 | canvas = canvas_reconfig ? canvas_reconfig : the_canvas; |
472 | |
|
473 | 0 | canvas->mem_size = osize; |
474 | 0 | canvas->width = width; |
475 | 0 | canvas->height = height; |
476 | 0 | canvas->pf = pf; |
477 | 0 | canvas->stride = stride; |
478 | 0 | if (the_canvas) { |
479 | 0 | canvas->alpha_cbk = JS_UNDEFINED; |
480 | 0 | canvas->frag_shader = JS_UNDEFINED; |
481 | 0 | canvas->vert_shader = JS_UNDEFINED; |
482 | | #ifdef EVG_USE_JS_SHADER |
483 | | canvas->frag_obj = JS_UNDEFINED; |
484 | | canvas->vert_obj = JS_UNDEFINED; |
485 | | #endif |
486 | 0 | canvas->depth_buffer = JS_UNDEFINED; |
487 | 0 | } |
488 | 0 | canvas->ctx = c; |
489 | 0 | if (data) { |
490 | 0 | canvas->data = data; |
491 | 0 | canvas->owns_data = GF_FALSE; |
492 | 0 | } else { |
493 | 0 | canvas->data = gf_malloc(sizeof(u8)*osize); |
494 | 0 | canvas->owns_data = GF_TRUE; |
495 | 0 | } |
496 | |
|
497 | 0 | e = GF_OK; |
498 | 0 | if (the_canvas) { |
499 | 0 | canvas->surface = gf_evg_surface_new(GF_TRUE); |
500 | 0 | canvas->center_coords = GF_TRUE; |
501 | 0 | } |
502 | |
|
503 | 0 | if (!canvas->surface) { |
504 | 0 | e = GF_BAD_PARAM; |
505 | 0 | } else if (!e) { |
506 | 0 | e = gf_evg_surface_attach_to_buffer(canvas->surface, canvas->data, canvas->width, canvas->height, 0, canvas->stride, canvas->pf); |
507 | 0 | } |
508 | |
|
509 | 0 | if (e) { |
510 | 0 | if (canvas_reconfig) |
511 | 0 | return GF_JS_EXCEPTION(c); |
512 | 0 | if (canvas->owns_data) gf_free(canvas->data); |
513 | 0 | gf_evg_surface_delete(canvas->surface); |
514 | 0 | gf_free(canvas); |
515 | 0 | return GF_JS_EXCEPTION(c); |
516 | 0 | } |
517 | 0 | if (canvas_reconfig) |
518 | 0 | return JS_UNDEFINED; |
519 | | |
520 | 0 | canvas->obj = JS_NewObjectClass(c, canvas_class_id); |
521 | 0 | if (JS_IsException(canvas->obj)) return canvas->obj; |
522 | | |
523 | 0 | JS_SetOpaque(canvas->obj, canvas); |
524 | 0 | return canvas->obj; |
525 | 0 | } |
526 | | |
527 | | static JSValue canvas_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
528 | 0 | { |
529 | 0 | return canvas_constructor_internal(c, new_target, argc, argv, NULL); |
530 | 0 | } |
531 | | |
532 | | static JSValue canvas_getProperty(JSContext *c, JSValueConst obj, int magic) |
533 | 0 | { |
534 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
535 | 0 | if (!canvas) return GF_JS_EXCEPTION(c); |
536 | 0 | switch (magic) { |
537 | 0 | case GF_EVG_CENTERED: return JS_NewBool(c, canvas->center_coords); |
538 | 0 | case GF_EVG_COMPOSITE_OP: return JS_NewInt32(c, canvas->composite_op); |
539 | 0 | case GF_EVG_ALPHA_FUN: return JS_DupValue(c, canvas->alpha_cbk); |
540 | 0 | case GF_EVG_FRAG_SHADER: return JS_DupValue(c, canvas->frag_shader); |
541 | 0 | case GF_EVG_VERT_SHADER: return JS_DupValue(c, canvas->vert_shader); |
542 | 0 | case GF_EVG_DEPTH_BUFFER: return JS_DupValue(c, canvas->depth_buffer); |
543 | 0 | case GF_EVG_RASTER_LEVEL: return JS_NewInt32(c, gf_evg_surface_get_raster_level(canvas->surface)); |
544 | 0 | case GF_EVG_IS_YUV: |
545 | 0 | if (gf_pixel_fmt_is_yuv(canvas->pf)) return JS_TRUE; |
546 | 0 | return JS_FALSE; |
547 | 0 | case GF_EVG_BIT_DEPTH: |
548 | 0 | return JS_NewInt32(c, gf_pixel_is_wide_depth(canvas->pf)); |
549 | 0 | case GF_EVG_MASK_MODE: |
550 | 0 | return JS_NewInt32(c, gf_evg_surface_get_mask_mode(canvas->surface) ); |
551 | 0 | case GF_EVG_CLIPPER: |
552 | 0 | return gf_evg_surface_use_clipper(canvas->surface) ? JS_TRUE : JS_FALSE; |
553 | 0 | } |
554 | 0 | return JS_UNDEFINED; |
555 | 0 | } |
556 | | |
557 | | Bool canvas_get_irect(JSContext *c, JSValueConst obj, GF_IRect *rc, Bool reset) |
558 | 0 | { |
559 | 0 | JSValue v; |
560 | 0 | Double fval; |
561 | 0 | int res; |
562 | 0 | if (reset) |
563 | 0 | memset(rc, 0, sizeof(GF_IRect)); |
564 | |
|
565 | 0 | #define GET_PROP( _n, _f, _mandat)\ |
566 | 0 | v = JS_GetPropertyStr(c, obj, _n);\ |
567 | 0 | if (JS_IsUndefined(v)) {\ |
568 | 0 | if (_mandat) return GF_FALSE;\ |
569 | 0 | } else {\ |
570 | 0 | if (JS_IsInteger(v)) \ |
571 | 0 | res = JS_ToInt32(c, &(rc->_f), v);\ |
572 | 0 | else {\ |
573 | 0 | res = JS_ToFloat64(c, &fval, v);\ |
574 | 0 | rc->_f = (s32) fval;\ |
575 | 0 | }\ |
576 | 0 | JS_FreeValue(c, v);\ |
577 | 0 | if (res) return GF_FALSE;\ |
578 | 0 | }\ |
579 | 0 |
|
580 | 0 | GET_PROP("x", x, 0) |
581 | 0 | GET_PROP("y", y, 0) |
582 | 0 | GET_PROP("w", width, 1) |
583 | 0 | GET_PROP("h", height, 1) |
584 | 0 | #undef GET_PROP |
585 | | |
586 | 0 | return GF_TRUE; |
587 | 0 | } |
588 | | |
589 | | static Bool evg_frag_shader_ops(void *udta, GF_EVGFragmentParam *frag); |
590 | | static Bool evg_frag_shader_ops_init(void *udta, GF_EVGFragmentParam *frag, u32 th_id, Bool is_cleanup); |
591 | | static Bool evg_vert_shader_ops(void *udta, GF_EVGVertexParam *frag); |
592 | | |
593 | | static JSValue canvas_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic) |
594 | 0 | { |
595 | 0 | Float f; |
596 | 0 | s32 ival; |
597 | 0 | GF_Err e = GF_OK; |
598 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
599 | 0 | if (!canvas) return GF_JS_EXCEPTION(ctx); |
600 | 0 | switch (magic) { |
601 | 0 | case GF_EVG_CENTERED: |
602 | 0 | canvas->center_coords = JS_ToBool(ctx, value) ? GF_TRUE : GF_FALSE; |
603 | 0 | gf_evg_surface_set_center_coords(canvas->surface, canvas->center_coords); |
604 | 0 | return JS_UNDEFINED; |
605 | | |
606 | 0 | case GF_EVG_PATH: |
607 | 0 | if (JS_IsNull(value)) { |
608 | 0 | gf_evg_surface_set_path(canvas->surface, NULL); |
609 | 0 | } else { |
610 | 0 | GF_Path *gp = JS_GetOpaque(value, path_class_id); |
611 | 0 | if (gp) |
612 | 0 | gf_evg_surface_set_path(canvas->surface, gp); |
613 | 0 | else { |
614 | 0 | GF_JSText *text = JS_GetOpaque(value, text_class_id); |
615 | 0 | if (text) { |
616 | 0 | #ifndef GPAC_DISABLE_FONTS |
617 | 0 | text_set_path(canvas, text); |
618 | | #else |
619 | | return GF_JS_EXCEPTION(ctx); |
620 | | #endif |
621 | 0 | } |
622 | 0 | } |
623 | 0 | } |
624 | 0 | return JS_UNDEFINED; |
625 | | |
626 | 0 | case GF_EVG_MATRIX: |
627 | 0 | if (JS_IsNull(value)) { |
628 | 0 | gf_evg_surface_set_matrix(canvas->surface, NULL); |
629 | 0 | } else { |
630 | 0 | GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id); |
631 | 0 | gf_evg_surface_set_matrix(canvas->surface, mx); |
632 | 0 | } |
633 | 0 | return JS_UNDEFINED; |
634 | | |
635 | 0 | case GF_EVG_MATRIX_3D: |
636 | 0 | if (JS_IsNull(value)) { |
637 | 0 | gf_evg_surface_set_matrix(canvas->surface, NULL); |
638 | 0 | } else { |
639 | 0 | GF_Matrix *mx = JS_GetOpaque(value, matrix_class_id); |
640 | 0 | gf_evg_surface_set_matrix_3d(canvas->surface, mx); |
641 | 0 | } |
642 | 0 | return JS_UNDEFINED; |
643 | 0 | case GF_EVG_RASTER_LEVEL: |
644 | 0 | JS_ToInt32(ctx, &ival, value); |
645 | 0 | gf_evg_surface_set_raster_level(canvas->surface, ival); |
646 | 0 | return JS_UNDEFINED; |
647 | | |
648 | 0 | case GF_EVG_CLIPPER: |
649 | 0 | if (JS_IsNull(value)) { |
650 | 0 | gf_evg_surface_set_clipper(canvas->surface, NULL); |
651 | 0 | } else { |
652 | 0 | GF_IRect rc; |
653 | 0 | canvas_get_irect(ctx, value, &rc, GF_TRUE); |
654 | 0 | gf_evg_surface_set_clipper(canvas->surface, &rc); |
655 | 0 | } |
656 | 0 | return JS_UNDEFINED; |
657 | | |
658 | 0 | case GF_EVG_COMPOSITE_OP: |
659 | 0 | if (JS_ToInt32(ctx, &canvas->composite_op, value)) return GF_JS_EXCEPTION(ctx); |
660 | 0 | gf_evg_surface_set_composite_mode(canvas->surface, canvas->composite_op); |
661 | 0 | break; |
662 | 0 | case GF_EVG_ALPHA_FUN: |
663 | 0 | JS_FreeValue(ctx, canvas->alpha_cbk); |
664 | 0 | if (JS_IsNull(value) || !JS_IsFunction(ctx, value)) { |
665 | 0 | canvas->alpha_cbk = JS_UNDEFINED; |
666 | 0 | gf_evg_surface_set_alpha_callback(canvas->surface, NULL, NULL); |
667 | 0 | } else { |
668 | 0 | canvas->alpha_cbk = JS_DupValue(ctx, value); |
669 | 0 | gf_evg_surface_set_alpha_callback(canvas->surface, evg_get_alpha, canvas); |
670 | 0 | } |
671 | 0 | return JS_UNDEFINED; |
672 | | |
673 | | //3D extensions |
674 | 0 | case GF_EVG_FRAG_SHADER: |
675 | 0 | JS_FreeValue(ctx, canvas->frag_shader); |
676 | 0 | canvas->frag_shader = JS_UNDEFINED; |
677 | 0 | canvas->frag = NULL; |
678 | 0 | if (JS_IsNull(value)) { |
679 | 0 | canvas->frag_shader = JS_UNDEFINED; |
680 | 0 | e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL, NULL); |
681 | | #ifdef EVG_USE_JS_SHADER |
682 | | } else if (JS_IsFunction(ctx, value)) { |
683 | | canvas->frag_shader = JS_DupValue(ctx, value); |
684 | | e = gf_evg_surface_set_fragment_shader(canvas->surface, evg_frag_shader_fun, NULL, canvas); |
685 | | #endif |
686 | 0 | } else if (JS_IsObject(value)) { |
687 | 0 | canvas->frag = JS_GetOpaque(value, shader_class_id); |
688 | 0 | if (!canvas->frag || (canvas->frag->mode != GF_EVG_SHADER_FRAGMENT)) |
689 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "Invalid fragment shader object"); |
690 | 0 | canvas->frag_shader = JS_DupValue(ctx, value); |
691 | |
|
692 | | #ifdef BUILTIN_SHADERS |
693 | | if (canvas->frag->frag_shader) { |
694 | | e = gf_evg_surface_set_fragment_shader(canvas->surface, canvas->frag->frag_shader, canvas->frag->frag_shader_init, canvas->frag); |
695 | | } else |
696 | | #endif |
697 | 0 | { |
698 | 0 | e = gf_evg_surface_set_fragment_shader(canvas->surface, evg_frag_shader_ops, evg_frag_shader_ops_init, canvas); |
699 | 0 | } |
700 | 0 | if (!e) e = gf_evg_surface_disable_early_depth(canvas->surface, canvas->frag->disable_early_z); |
701 | 0 | } else { |
702 | 0 | canvas->frag_shader = JS_UNDEFINED; |
703 | 0 | e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL, NULL); |
704 | 0 | } |
705 | 0 | break; |
706 | 0 | case GF_EVG_VERT_SHADER: |
707 | 0 | JS_FreeValue(ctx, canvas->vert_shader); |
708 | 0 | canvas->vert_shader = JS_UNDEFINED; |
709 | 0 | canvas->vert = NULL; |
710 | 0 | if (JS_IsNull(value)) { |
711 | 0 | canvas->vert_shader = JS_UNDEFINED; |
712 | 0 | e = gf_evg_surface_set_vertex_shader(canvas->surface, NULL, NULL); |
713 | | #ifdef EVG_USE_JS_SHADER |
714 | | } else if (JS_IsFunction(ctx, value)) { |
715 | | canvas->vert_shader = JS_DupValue(ctx, value); |
716 | | e = gf_evg_surface_set_vertex_shader(canvas->surface, evg_vert_shader_fun, canvas); |
717 | | #endif |
718 | 0 | } else if (JS_IsObject(value)) { |
719 | 0 | canvas->vert = JS_GetOpaque(value, shader_class_id); |
720 | 0 | if (!canvas->vert || (canvas->vert->mode != GF_EVG_SHADER_VERTEX)) |
721 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "Invalid fragment shader object"); |
722 | 0 | canvas->vert_shader = JS_DupValue(ctx, value); |
723 | 0 | e = gf_evg_surface_set_vertex_shader(canvas->surface, evg_vert_shader_ops, canvas); |
724 | 0 | } else { |
725 | 0 | canvas->frag_shader = JS_UNDEFINED; |
726 | 0 | e = gf_evg_surface_set_fragment_shader(canvas->surface, NULL, NULL, NULL); |
727 | 0 | } |
728 | 0 | break; |
729 | 0 | case GF_EVG_CCW: |
730 | 0 | e = gf_evg_surface_set_ccw(canvas->surface, JS_ToBool(ctx, value) ); |
731 | 0 | break; |
732 | 0 | case GF_EVG_BACKCULL: |
733 | 0 | e = gf_evg_surface_set_backcull(canvas->surface, JS_ToBool(ctx, value) ); |
734 | 0 | break; |
735 | 0 | case GF_EVG_ANTIALIAS: |
736 | 0 | e = gf_evg_surface_set_antialias(canvas->surface, JS_ToBool(ctx, value) ); |
737 | 0 | break; |
738 | | |
739 | 0 | case GF_EVG_DEPTH_BUFFER: |
740 | 0 | { |
741 | 0 | Float *depthb; |
742 | 0 | u32 dsize; |
743 | 0 | JS_FreeValue(ctx, canvas->depth_buffer); |
744 | 0 | canvas->depth_buffer = JS_UNDEFINED; |
745 | 0 | depthb = (Float *) evg_get_array(ctx, value, &dsize); |
746 | 0 | if (!depthb) { |
747 | 0 | canvas->depth_buffer = JS_NULL; |
748 | 0 | e = gf_evg_surface_set_depth_buffer(canvas->surface, NULL); |
749 | 0 | } else { |
750 | 0 | u32 req_size = canvas->width*canvas->height*sizeof(Float); |
751 | 0 | if (req_size>dsize) { |
752 | 0 | e = GF_BAD_PARAM; |
753 | 0 | gf_evg_surface_set_depth_buffer(canvas->surface, NULL); |
754 | 0 | } else { |
755 | 0 | canvas->depth_buffer = JS_DupValue(ctx, value); |
756 | 0 | e = gf_evg_surface_set_depth_buffer(canvas->surface, depthb); |
757 | 0 | } |
758 | 0 | } |
759 | 0 | break; |
760 | 0 | } |
761 | | |
762 | 0 | case GF_EVG_MINDEPTH: |
763 | 0 | EVG_GET_FLOAT(f, value); |
764 | 0 | e = gf_evg_surface_set_min_depth(canvas->surface, f); |
765 | 0 | break; |
766 | 0 | case GF_EVG_MAXDEPTH: |
767 | 0 | EVG_GET_FLOAT(f, value); |
768 | 0 | e = gf_evg_surface_set_max_depth(canvas->surface, f); |
769 | 0 | break; |
770 | 0 | case GF_EVG_DEPTHTEST: |
771 | 0 | if (JS_ToInt32(ctx, &ival, value)) |
772 | 0 | return js_throw_err(ctx, GF_BAD_PARAM); |
773 | 0 | e = gf_evg_set_depth_test(canvas->surface, ival); |
774 | 0 | break; |
775 | 0 | case GF_EVG_POINTSIZE: |
776 | 0 | EVG_GET_FLOAT(f, value); |
777 | 0 | e = gf_evg_surface_set_point_size(canvas->surface, f); |
778 | 0 | break; |
779 | 0 | case GF_EVG_POINTSMOOTH: |
780 | 0 | e = gf_evg_surface_set_point_smooth(canvas->surface, JS_ToBool(ctx, value) ); |
781 | 0 | break; |
782 | 0 | case GF_EVG_LINESIZE: |
783 | 0 | EVG_GET_FLOAT(f, value); |
784 | 0 | e = gf_evg_surface_set_line_size(canvas->surface, f); |
785 | 0 | break; |
786 | 0 | case GF_EVG_CLIP_ZERO: |
787 | 0 | e = gf_evg_surface_set_clip_zero(canvas->surface, JS_ToBool(ctx, value) ? GF_TRUE : GF_FALSE); |
788 | 0 | break; |
789 | 0 | case GF_EVG_DEPTH_TEST: |
790 | 0 | if (JS_ToInt32(ctx, &ival, value)) return GF_JS_EXCEPTION(ctx); |
791 | 0 | e = gf_evg_set_depth_test(canvas->surface, ival); |
792 | 0 | break; |
793 | 0 | case GF_EVG_WRITE_DEPTH: |
794 | 0 | e = gf_evg_surface_write_depth(canvas->surface, JS_ToBool(ctx, value) ? GF_TRUE : GF_FALSE); |
795 | 0 | break; |
796 | 0 | case GF_EVG_MASK_MODE: |
797 | 0 | if (JS_ToInt32(ctx, &ival, value)) |
798 | 0 | return js_throw_err(ctx, GF_BAD_PARAM); |
799 | 0 | e = gf_evg_surface_set_mask_mode(canvas->surface, ival); |
800 | 0 | break; |
801 | 0 | } |
802 | 0 | if (e) |
803 | 0 | return js_throw_err(ctx, e); |
804 | | |
805 | 0 | return JS_UNDEFINED; |
806 | 0 | } |
807 | | |
808 | | |
809 | | static JSValue canvas_clear_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_float) |
810 | 0 | { |
811 | 0 | s32 i; |
812 | 0 | s32 idx=0; |
813 | 0 | GF_Err e; |
814 | 0 | GF_IRect rc, *irc; |
815 | 0 | u32 r=0, g=0, b=0, a=255; |
816 | 0 | GF_Color col; |
817 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
818 | 0 | if (!canvas) |
819 | 0 | return GF_JS_EXCEPTION(c); |
820 | | |
821 | 0 | irc = NULL; |
822 | 0 | if (argc && JS_IsObject(argv[0])) { |
823 | 0 | irc = &rc; |
824 | 0 | idx=1; |
825 | 0 | if (!canvas_get_irect(c, argv[0], &rc, GF_TRUE)) |
826 | 0 | return GF_JS_EXCEPTION(c); |
827 | 0 | } |
828 | 0 | if ((argc>idx) && JS_IsString(argv[idx])) { |
829 | 0 | const char *str = JS_ToCString(c, argv[idx]); |
830 | 0 | col = gf_color_parse(str); |
831 | 0 | JS_FreeCString(c, str); |
832 | 0 | } else { |
833 | 0 | if (argc>4+idx) argc = 4+idx; |
834 | 0 | for (i=idx; i<argc; i++) { |
835 | 0 | s32 v; |
836 | 0 | if (use_float) { |
837 | 0 | Double d; |
838 | 0 | if (JS_ToFloat64(c, &d, argv[i])) |
839 | 0 | return GF_JS_EXCEPTION(c); |
840 | 0 | v = (s32) (d*255); |
841 | 0 | } else if (JS_ToInt32(c, &v, argv[i])) { |
842 | 0 | return GF_JS_EXCEPTION(c); |
843 | 0 | } |
844 | | |
845 | 0 | if (v<0) v = 0; |
846 | 0 | else if (v>255) v = 255; |
847 | |
|
848 | 0 | if (i==idx) r=v; |
849 | 0 | else if (i==idx+1) g=v; |
850 | 0 | else if (i==idx+2) b=v; |
851 | 0 | else a=v; |
852 | 0 | } |
853 | 0 | col = GF_COL_ARGB(a, r, g, b) ; |
854 | 0 | } |
855 | 0 | e = gf_evg_surface_clear(canvas->surface, irc, col); |
856 | 0 | if (e) |
857 | 0 | return GF_JS_EXCEPTION(c); |
858 | 0 | return JS_UNDEFINED; |
859 | 0 | } |
860 | | static JSValue canvas_clear(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
861 | 0 | { |
862 | 0 | return canvas_clear_ex(c, obj, argc, argv, GF_FALSE); |
863 | 0 | } |
864 | | static JSValue canvas_clearf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
865 | 0 | { |
866 | 0 | return canvas_clear_ex(c, obj, argc, argv, GF_TRUE); |
867 | 0 | } |
868 | | |
869 | | static JSValue canvas_rgb_yuv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool to_rgb) |
870 | 0 | { |
871 | 0 | GF_Err e; |
872 | 0 | Double _r=0, _g=0, _b=0, _a=1.0; |
873 | 0 | Float r=0, g=0, b=0, a=1.0; |
874 | 0 | Bool as_array = GF_FALSE; |
875 | 0 | u32 arg_idx=0; |
876 | 0 | Float y, u, v; |
877 | 0 | JSValue ret; |
878 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
879 | 0 | if (!canvas || !argc) |
880 | 0 | return GF_JS_EXCEPTION(c); |
881 | | |
882 | 0 | if (JS_IsBool(argv[0])) { |
883 | 0 | as_array = JS_ToBool(c, argv[0]); |
884 | 0 | arg_idx=1; |
885 | 0 | } |
886 | 0 | if (!get_color_from_args(c, argc, argv, arg_idx, &_a, &_r, &_g, &_b)) |
887 | 0 | return GF_JS_EXCEPTION(c); |
888 | 0 | r = (Float) _r; |
889 | 0 | g = (Float) _g; |
890 | 0 | b = (Float) _b; |
891 | 0 | a = (Float) _a; |
892 | 0 | if (to_rgb) { |
893 | 0 | e = gf_evg_yuv_to_rgb_f(canvas->surface, r, g, b, &y, &u, &v); |
894 | 0 | } else { |
895 | 0 | e = gf_gf_evg_rgb_to_yuv_f(canvas->surface, r, g, b, &y, &u, &v); |
896 | 0 | } |
897 | 0 | if (e) |
898 | 0 | return GF_JS_EXCEPTION(c); |
899 | 0 | if (as_array) { |
900 | 0 | ret = JS_NewArray(c); |
901 | 0 | JS_SetPropertyStr(c, ret, "length", JS_NewInt32(c, 4) ); |
902 | 0 | JS_SetPropertyUint32(c, ret, 0, JS_NewFloat64(c, y) ); |
903 | 0 | JS_SetPropertyUint32(c, ret, 1, JS_NewFloat64(c, u) ); |
904 | 0 | JS_SetPropertyUint32(c, ret, 2, JS_NewFloat64(c, v) ); |
905 | 0 | JS_SetPropertyUint32(c, ret, 3, JS_NewFloat64(c, a) ); |
906 | 0 | } else { |
907 | 0 | ret = JS_NewObject(c); |
908 | 0 | JS_SetPropertyStr(c, ret, "r", JS_NewFloat64(c, y) ); |
909 | 0 | JS_SetPropertyStr(c, ret, "g", JS_NewFloat64(c, u) ); |
910 | 0 | JS_SetPropertyStr(c, ret, "b", JS_NewFloat64(c, v) ); |
911 | 0 | JS_SetPropertyStr(c, ret, "a", JS_NewFloat64(c, a) ); |
912 | 0 | } |
913 | 0 | return ret; |
914 | 0 | } |
915 | | |
916 | | static JSValue canvas_reassign(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
917 | 0 | { |
918 | 0 | GF_Err e; |
919 | 0 | u8 *data; |
920 | 0 | size_t data_size=0; |
921 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
922 | 0 | if (!canvas || !argc) return GF_JS_EXCEPTION(c); |
923 | | |
924 | 0 | if (canvas->owns_data) { |
925 | 0 | gf_free(canvas->data); |
926 | 0 | canvas->owns_data = GF_FALSE; |
927 | 0 | } |
928 | 0 | canvas->data = NULL; |
929 | |
|
930 | 0 | if (argc==1) { |
931 | 0 | if (!JS_IsObject(argv[0])) return GF_JS_EXCEPTION(c); |
932 | 0 | } else { |
933 | 0 | return canvas_constructor_internal(c, obj, argc, argv, canvas); |
934 | 0 | } |
935 | | |
936 | 0 | data = JS_GetArrayBuffer(c, &data_size, argv[0]); |
937 | 0 | if (!data || (data_size<canvas->mem_size)) { |
938 | 0 | e = GF_BAD_PARAM; |
939 | 0 | } else { |
940 | 0 | canvas->data = data; |
941 | 0 | e = gf_evg_surface_attach_to_buffer(canvas->surface, canvas->data, canvas->width, canvas->height, 0, canvas->stride, canvas->pf); |
942 | 0 | } |
943 | 0 | if (e) return GF_JS_EXCEPTION(c); |
944 | 0 | return JS_UNDEFINED; |
945 | 0 | } |
946 | | |
947 | | static JSValue canvas_toYUV(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
948 | 0 | { |
949 | 0 | return canvas_rgb_yuv(c, obj, argc, argv, GF_FALSE); |
950 | 0 | } |
951 | | |
952 | | static JSValue canvas_toRGB(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
953 | 0 | { |
954 | 0 | return canvas_rgb_yuv(c, obj, argc, argv, GF_TRUE); |
955 | 0 | } |
956 | | |
957 | | static GF_EVGStencil *get_stencil(JSContext *c, JSValue v) |
958 | 0 | { |
959 | 0 | GF_JSTexture *tx; |
960 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(v, stencil_class_id); |
961 | 0 | if (stencil) return stencil; |
962 | 0 | tx = JS_GetOpaque(v, texture_class_id); |
963 | 0 | if (tx) return tx->stencil; |
964 | 0 | return NULL; |
965 | 0 | } |
966 | | |
967 | | static JSValue canvas_fill(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
968 | 0 | { |
969 | 0 | GF_EVGStencil *sten1 = NULL; |
970 | 0 | GF_EVGStencil *sten2 = NULL; |
971 | 0 | GF_EVGStencil *sten3 = NULL; |
972 | 0 | u32 sten_idx=1; |
973 | 0 | u32 operand = 0; |
974 | 0 | GF_Err e; |
975 | 0 | Float op_params[4] = {0}; |
976 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
977 | 0 | if (!canvas) return GF_JS_EXCEPTION(c); |
978 | | |
979 | 0 | if (!argc) { |
980 | 0 | if (!JS_IsUndefined(canvas->frag_shader)) { |
981 | 0 | gf_evg_surface_fill(canvas->surface, NULL); |
982 | 0 | return JS_UNDEFINED; |
983 | 0 | } |
984 | 0 | return GF_JS_EXCEPTION(c); |
985 | 0 | } |
986 | | |
987 | 0 | if (JS_IsObject(argv[0])) { |
988 | 0 | sten1 = get_stencil(c, argv[0]); |
989 | 0 | if (!sten1) return GF_JS_EXCEPTION(c); |
990 | 0 | e = gf_evg_surface_fill(canvas->surface, sten1); |
991 | 0 | return e ? GF_JS_EXCEPTION(c) : JS_UNDEFINED; |
992 | 0 | } |
993 | | |
994 | 0 | if (JS_ToInt32(c, &operand, argv[0])) |
995 | 0 | return GF_JS_EXCEPTION(c); |
996 | 0 | if (JS_IsArray(c, argv[1])) { |
997 | 0 | JSValue v; |
998 | 0 | u32 i, nb_items; |
999 | 0 | v = JS_GetPropertyStr(c, argv[1], "length"); |
1000 | 0 | JS_ToInt32(c, &nb_items, v); |
1001 | 0 | JS_FreeValue(c, v); |
1002 | 0 | if (nb_items>4) nb_items=3; |
1003 | 0 | for (i=0; i<nb_items; i++) { |
1004 | 0 | Double d; |
1005 | 0 | v = JS_GetPropertyUint32(c, argv[1], i); |
1006 | 0 | JS_ToFloat64(c, &d, v); |
1007 | 0 | JS_FreeValue(c, v); |
1008 | 0 | op_params[i] = (Float) d; |
1009 | 0 | } |
1010 | 0 | sten_idx = 2; |
1011 | 0 | } |
1012 | 0 | else if (JS_IsNumber(argv[1])) { |
1013 | 0 | Double d; |
1014 | 0 | JS_ToFloat64(c, &d, argv[1]); |
1015 | 0 | op_params[0] = (Float) d; |
1016 | 0 | sten_idx = 2; |
1017 | 0 | } |
1018 | 0 | sten1 = get_stencil(c, argv[sten_idx]); |
1019 | 0 | if (!sten1) return GF_JS_EXCEPTION(c); |
1020 | 0 | if ((u32) argc>sten_idx+1) |
1021 | 0 | sten2 = get_stencil(c, argv[sten_idx+1]); |
1022 | 0 | if ((u32) argc>sten_idx+2) |
1023 | 0 | sten3 = get_stencil(c, argv[sten_idx+2]); |
1024 | 0 | e = gf_evg_surface_multi_fill(canvas->surface, operand, sten1, sten2, sten3, op_params); |
1025 | 0 | return e ? GF_JS_EXCEPTION(c) : JS_UNDEFINED; |
1026 | 0 | } |
1027 | | |
1028 | | static JSValue canvas_blit(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1029 | 0 | { |
1030 | | #ifdef GPAC_HAS_FFMPEG |
1031 | | GF_JSTexture *tx; |
1032 | | GF_IRect dst_rc, src_rc; |
1033 | | enum AVPixelFormat pf_src, pf_dst; |
1034 | | double par_p[2]; |
1035 | | u8 *src_data[5]; |
1036 | | u8 *dst_data[5]; |
1037 | | u32 src_stride[5]; |
1038 | | u32 dst_stride[5]; |
1039 | | u32 swsmode = 0; |
1040 | | u32 bpp, arg_idx=0; |
1041 | | |
1042 | | GF_Err gf_evg_stencil_get_texture_planes(GF_EVGStencil *stencil, u8 **pY_or_RGB, u8 **pU, u8 **pV, u8 **pA, u32 *stride, u32 *stride_uv); |
1043 | | |
1044 | | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1045 | | if (!canvas || !argc) return GF_JS_EXCEPTION(c); |
1046 | | |
1047 | | if (!JS_IsObject(argv[0])) |
1048 | | return GF_JS_EXCEPTION(c); |
1049 | | |
1050 | | tx = JS_GetOpaque(argv[0], texture_class_id); |
1051 | | if (!tx) return GF_JS_EXCEPTION(c); |
1052 | | |
1053 | | pf_src = ffmpeg_pixfmt_from_gpac(tx->pf, GF_FALSE); |
1054 | | pf_dst = ffmpeg_pixfmt_from_gpac(canvas->pf, GF_FALSE); |
1055 | | if ((pf_src==AV_PIX_FMT_NONE) || (pf_dst==AV_PIX_FMT_NONE)) |
1056 | | return js_throw_err(c, GF_NOT_SUPPORTED); |
1057 | | |
1058 | | dst_rc.x = dst_rc.y = 0; |
1059 | | dst_rc.width = canvas->width; |
1060 | | dst_rc.height = canvas->height; |
1061 | | |
1062 | | src_rc.x = src_rc.y = 0; |
1063 | | src_rc.width = tx->width; |
1064 | | src_rc.height = tx->height; |
1065 | | |
1066 | | //get dst and src rectangles |
1067 | | if ((1+arg_idx < (u32) argc) && (JS_IsNull(argv[1+arg_idx]) || canvas_get_irect(c, argv[1+arg_idx], &dst_rc, GF_FALSE))) { |
1068 | | arg_idx++; |
1069 | | if ((1+arg_idx < (u32) argc) && (JS_IsNull(argv[1+arg_idx]) || canvas_get_irect(c, argv[1+arg_idx], &src_rc, GF_FALSE))) { |
1070 | | arg_idx++; |
1071 | | } |
1072 | | } |
1073 | | |
1074 | | if (!dst_rc.width || !dst_rc.height) return JS_UNDEFINED; |
1075 | | if (!src_rc.width || !src_rc.height) return JS_UNDEFINED; |
1076 | | |
1077 | | |
1078 | | if ((1+arg_idx < (u32) argc) && JS_IsObject(argv[1+arg_idx])) { |
1079 | | u32 nb_params=0; |
1080 | | JSValue v = JS_GetPropertyStr(c, argv[1+arg_idx], "mode"); |
1081 | | if (JS_IsString(v)) { |
1082 | | const char *smode = JS_ToCString(c, v); |
1083 | | if (!strcmp(smode, "fastbilinear")) swsmode = SWS_FAST_BILINEAR; |
1084 | | else if (!strcmp(smode, "bilinear")) swsmode = SWS_BILINEAR; |
1085 | | else if (!strcmp(smode, "bicubic")) { swsmode = SWS_BICUBIC; nb_params=2; } |
1086 | | else if (!strcmp(smode, "X")) swsmode = SWS_X; |
1087 | | else if (!strcmp(smode, "point")) swsmode = SWS_POINT; |
1088 | | else if (!strcmp(smode, "area")) swsmode = SWS_AREA; |
1089 | | else if (!strcmp(smode, "bicublin")) swsmode = SWS_BICUBLIN; |
1090 | | else if (!strcmp(smode, "gauss")) { swsmode = SWS_GAUSS; nb_params=1; } |
1091 | | else if (!strcmp(smode, "sinc")) swsmode = SWS_SINC; |
1092 | | else if (!strcmp(smode, "lanzcos")) { swsmode = SWS_LANCZOS; nb_params=1; } |
1093 | | else if (!strcmp(smode, "spline")) swsmode = SWS_SPLINE; |
1094 | | |
1095 | | JS_FreeCString(c, smode); |
1096 | | } |
1097 | | JS_FreeValue(c, v); |
1098 | | if (nb_params) { |
1099 | | v = JS_GetPropertyStr(c, argv[1+arg_idx], "p1"); |
1100 | | JS_ToFloat64(c, &par_p[0], v); |
1101 | | JS_FreeValue(c, v); |
1102 | | if (nb_params>1) { |
1103 | | v = JS_GetPropertyStr(c, argv[1+arg_idx], "p2"); |
1104 | | JS_ToFloat64(c, &par_p[0], v); |
1105 | | JS_FreeValue(c, v); |
1106 | | } |
1107 | | } |
1108 | | } |
1109 | | |
1110 | | if ((dst_rc.x<0) || (dst_rc.x+dst_rc.width > (s32) canvas->width) |
1111 | | || (dst_rc.y<0) || (dst_rc.y+dst_rc.height > (s32) canvas->height) |
1112 | | ) { |
1113 | | return js_throw_err(c, GF_BAD_PARAM); |
1114 | | } |
1115 | | |
1116 | | if ((src_rc.x<0) || (src_rc.x+src_rc.width > (s32) tx->width) |
1117 | | || (src_rc.y<0) || (src_rc.y+src_rc.height > (s32) tx->height) |
1118 | | ) { |
1119 | | return js_throw_err(c, GF_BAD_PARAM); |
1120 | | } |
1121 | | |
1122 | | par_p[0] = par_p[1] = 0; |
1123 | | tx->swscaler = sws_getCachedContext(tx->swscaler, src_rc.width, src_rc.height, pf_src, dst_rc.width, dst_rc.height, pf_dst, swsmode, NULL, NULL, par_p); |
1124 | | |
1125 | | if (!tx->swscaler) { |
1126 | | return js_throw_err(c, GF_BAD_PARAM); |
1127 | | } |
1128 | | memset(src_data, 0, sizeof(u8*) * 5); |
1129 | | memset(dst_data, 0, sizeof(u8*) * 5); |
1130 | | memset(src_stride, 0, sizeof(u32) * 5); |
1131 | | memset(dst_stride, 0, sizeof(u32) * 5); |
1132 | | |
1133 | | bpp = gf_pixel_get_bytes_per_pixel(canvas->pf); |
1134 | | dst_data[0] = canvas->data + dst_rc.x*bpp + dst_rc.y * canvas->stride; |
1135 | | dst_stride[0] = canvas->stride; |
1136 | | |
1137 | | if (gf_pixel_fmt_is_yuv(canvas->pf)) { |
1138 | | u32 nb_planes, uv_height, off_x, off_y; |
1139 | | |
1140 | | gf_pixel_get_size_info(canvas->pf, canvas->width, canvas->height, NULL, &dst_stride[0], &dst_stride[1], &nb_planes, &uv_height); |
1141 | | |
1142 | | off_x = dst_rc.x * dst_stride[1] / dst_stride[0]; |
1143 | | off_y = dst_rc.y * uv_height / canvas->height; |
1144 | | |
1145 | | if (nb_planes==1) { |
1146 | | } else if (nb_planes==2) { |
1147 | | dst_data[1] = canvas->data + dst_stride[0] * canvas->height; |
1148 | | dst_data[1] += off_x * bpp + off_y * dst_stride[1]; |
1149 | | |
1150 | | } else if (nb_planes==3) { |
1151 | | dst_stride[2] = dst_stride[1]; |
1152 | | dst_data[1] = canvas->data + dst_stride[0] * canvas->height; |
1153 | | dst_data[2] = dst_data[1] + dst_stride[1] * uv_height; |
1154 | | |
1155 | | dst_data[1] += off_x * bpp + off_y * dst_stride[1]; |
1156 | | dst_data[2] += off_x * bpp + off_y * dst_stride[2]; |
1157 | | } else if (nb_planes==4) { |
1158 | | dst_stride[2] = dst_stride[1]; |
1159 | | dst_stride[3] = dst_stride[0]; |
1160 | | dst_data[1] = canvas->data + dst_stride[0] * canvas->height; |
1161 | | dst_data[2] = dst_data[1] + dst_stride[1] * uv_height; |
1162 | | dst_data[3] = dst_data[2] + dst_stride[2] * uv_height; |
1163 | | |
1164 | | dst_data[1] += off_x * bpp + off_y * dst_stride[1]; |
1165 | | dst_data[2] += off_x * bpp + off_y * dst_stride[2]; |
1166 | | dst_data[3] += dst_rc.x * bpp + dst_rc.y * dst_stride[3]; |
1167 | | } |
1168 | | } |
1169 | | |
1170 | | gf_evg_stencil_get_texture_planes((GF_EVGStencil *) tx->stencil, &src_data[0], &src_data[1], &src_data[2], &src_data[3], &src_stride[0], &src_stride[1]); |
1171 | | |
1172 | | if (src_data[3]) |
1173 | | src_stride[3] = src_stride[0]; |
1174 | | if (src_data[2]) |
1175 | | src_stride[2] = src_stride[1]; |
1176 | | |
1177 | | bpp = gf_pixel_get_bytes_per_pixel(tx->pf); |
1178 | | src_data[0] += src_rc.x*bpp + src_rc.y * tx->stride; |
1179 | | |
1180 | | if (gf_pixel_fmt_is_yuv(tx->pf)) { |
1181 | | u32 nb_planes, uv_height, off_x, off_y; |
1182 | | |
1183 | | gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, &src_stride[0], &src_stride[1], &nb_planes, &uv_height); |
1184 | | |
1185 | | off_x = src_rc.x * src_stride[1] / src_stride[0]; |
1186 | | off_y = src_rc.y * uv_height / tx->height; |
1187 | | if (off_y != src_rc.y) { |
1188 | | while (off_y % 2) |
1189 | | off_y--; |
1190 | | } |
1191 | | |
1192 | | if (nb_planes==1) { |
1193 | | } else if (nb_planes==2) { |
1194 | | src_data[1] += (off_x/2) * 2*bpp + off_y * src_stride[1]; |
1195 | | src_data[2] = NULL; |
1196 | | src_stride[2] = 0; |
1197 | | |
1198 | | } else if (nb_planes==3) { |
1199 | | src_data[1] += off_x * bpp + off_y * src_stride[1]; |
1200 | | src_data[2] += off_x * bpp + off_y * src_stride[2]; |
1201 | | } else if (nb_planes==4) { |
1202 | | src_data[1] += off_x * bpp + off_y * src_stride[1]; |
1203 | | src_data[2] += off_x * bpp + off_y * src_stride[2]; |
1204 | | src_data[3] += src_rc.x * bpp + src_rc.y * src_stride[3]; |
1205 | | } |
1206 | | } |
1207 | | |
1208 | | |
1209 | | int res = sws_scale(tx->swscaler, (const u8**) src_data, src_stride, 0, src_rc.height, dst_data, dst_stride); |
1210 | | if (res != dst_rc.height) |
1211 | | return js_throw_err(c, GF_BAD_PARAM); |
1212 | | |
1213 | | return JS_UNDEFINED; |
1214 | | #else |
1215 | 0 | return js_throw_err(c, GF_NOT_SUPPORTED); |
1216 | 0 | #endif |
1217 | 0 | } |
1218 | | |
1219 | | |
1220 | | static JSValue canvas_enable_threading(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1221 | 0 | { |
1222 | 0 | GF_Err e; |
1223 | 0 | s32 nb_threads = -1; |
1224 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1225 | 0 | if (!canvas) return GF_JS_EXCEPTION(c); |
1226 | 0 | if (argc) { |
1227 | 0 | if (JS_ToInt32(c, &nb_threads, argv[0])) |
1228 | 0 | return GF_JS_EXCEPTION(c); |
1229 | 0 | } |
1230 | 0 | e = gf_evg_enable_threading(canvas->surface, nb_threads); |
1231 | 0 | if (e) return js_throw_err(c, e); |
1232 | 0 | return JS_UNDEFINED; |
1233 | 0 | } |
1234 | | |
1235 | | static JSValue canvas_enable_3d(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1236 | 0 | { |
1237 | 0 | GF_Err e; |
1238 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1239 | 0 | if (!canvas) return GF_JS_EXCEPTION(c); |
1240 | 0 | e = gf_evg_surface_enable_3d(canvas->surface); |
1241 | 0 | if (e) return js_throw_err(c, e); |
1242 | | |
1243 | | #ifdef EVG_USE_JS_SHADER |
1244 | | JS_FreeValue(c, the_canvas->frag_obj); |
1245 | | the_canvas->frag_obj = JS_NewObjectClass(c, fragment_class_id); |
1246 | | JS_SetOpaque(the_canvas->frag_obj, NULL); |
1247 | | |
1248 | | JS_FreeValue(c, the_canvas->vert_obj); |
1249 | | the_canvas->vert_obj = JS_NewObjectClass(c, vertex_class_id); |
1250 | | JS_SetOpaque(the_canvas->vert_obj, NULL); |
1251 | | #endif |
1252 | | |
1253 | 0 | return JS_UNDEFINED; |
1254 | 0 | } |
1255 | | |
1256 | | static Bool vai_call_lerp(EVG_VAI *vai, GF_EVGFragmentParam *frag, Float *values); |
1257 | | static Bool vai_call_lerp_init(EVG_VAI *vai, GF_EVGFragmentParam *frag); |
1258 | | |
1259 | | #ifdef EVG_USE_JS_SHADER |
1260 | | static Bool evg_frag_shader_fun(void *udta, GF_EVGFragmentParam *frag) |
1261 | | { |
1262 | | Bool frag_valid; |
1263 | | JSValue res; |
1264 | | GF_JSCanvas *canvas = (GF_JSCanvas *)udta; |
1265 | | if (!canvas) return GF_FALSE; |
1266 | | |
1267 | | JS_SetOpaque(canvas->frag_obj, frag); |
1268 | | res = JS_Call(canvas->ctx, canvas->frag_shader, canvas->obj, 1, &canvas->frag_obj); |
1269 | | frag_valid = frag->frag_valid ? 1 : 0; |
1270 | | if (JS_IsException(res)) frag_valid = GF_FALSE; |
1271 | | else if (!JS_IsUndefined(res)) frag_valid = JS_ToBool(canvas->ctx, res) ? GF_TRUE : GF_FALSE; |
1272 | | JS_FreeValue(canvas->ctx, res); |
1273 | | return frag_valid; |
1274 | | } |
1275 | | |
1276 | | static Bool evg_vert_shader_fun(void *udta, GF_EVGVertexParam *vertex) |
1277 | | { |
1278 | | Bool vert_valid=GF_TRUE; |
1279 | | JSValue res; |
1280 | | GF_JSCanvas *canvas = (GF_JSCanvas *)udta; |
1281 | | if (!canvas) return GF_FALSE; |
1282 | | |
1283 | | JS_SetOpaque(canvas->vert_obj, vertex); |
1284 | | res = JS_Call(canvas->ctx, canvas->frag_shader, canvas->obj, 1, &canvas->vert_obj); |
1285 | | if (JS_IsException(res)) vert_valid = GF_FALSE; |
1286 | | else if (!JS_IsUndefined(res)) vert_valid = JS_ToBool(canvas->ctx, res) ? GF_TRUE : GF_FALSE; |
1287 | | JS_FreeValue(canvas->ctx, res); |
1288 | | return vert_valid; |
1289 | | } |
1290 | | #endif |
1291 | | |
1292 | | static JSValue canvas_set_matrix_3d(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_proj) |
1293 | 0 | { |
1294 | 0 | GF_Err e; |
1295 | 0 | GF_Matrix mx; |
1296 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1297 | 0 | if (!canvas) return GF_JS_EXCEPTION(c); |
1298 | | |
1299 | 0 | gf_mx_init(mx); |
1300 | 0 | if (argc) { |
1301 | 0 | if (JS_IsArray(c, argv[0])) { |
1302 | 0 | u32 i, len=0; |
1303 | 0 | JSValue v = JS_GetPropertyStr(c, argv[0], "length"); |
1304 | 0 | JS_ToInt32(c, &len, v); |
1305 | 0 | JS_FreeValue(c, v); |
1306 | 0 | if (len < 16) return GF_JS_EXCEPTION(c); |
1307 | 0 | for (i=0; i<16; i++) { |
1308 | 0 | Double val=0; |
1309 | 0 | v = JS_GetPropertyUint32(c, argv[0], i); |
1310 | 0 | s32 res = JS_ToFloat64(c, &val, v); |
1311 | 0 | JS_FreeValue(c, v); |
1312 | 0 | if (res) return GF_JS_EXCEPTION(c); |
1313 | 0 | mx.m[i] = FLT2FIX(val); |
1314 | 0 | } |
1315 | 0 | } else { |
1316 | 0 | return js_throw_err_msg(c, GF_NOT_SUPPORTED, "only float array currently supported for matrices"); |
1317 | 0 | } |
1318 | 0 | } |
1319 | 0 | if (is_proj) |
1320 | 0 | e = gf_evg_surface_set_projection(canvas->surface, &mx); |
1321 | 0 | else |
1322 | 0 | e = gf_evg_surface_set_modelview(canvas->surface, &mx); |
1323 | 0 | return e ? GF_JS_EXCEPTION(c) : JS_UNDEFINED; |
1324 | 0 | } |
1325 | | static JSValue canvas_projection(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1326 | 0 | { |
1327 | 0 | return canvas_set_matrix_3d(c, obj, argc, argv, GF_TRUE); |
1328 | 0 | } |
1329 | | static JSValue canvas_modelview(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1330 | 0 | { |
1331 | 0 | return canvas_set_matrix_3d(c, obj, argc, argv, GF_FALSE); |
1332 | 0 | } |
1333 | | |
1334 | | uint8_t *evg_get_array(JSContext *ctx, JSValueConst obj, u32 *size) |
1335 | 0 | { |
1336 | 0 | JSValue v; |
1337 | | /*ArrayBuffer*/ |
1338 | 0 | size_t psize; |
1339 | 0 | uint8_t *res = JS_GetArrayBuffer(ctx, &psize, obj); |
1340 | 0 | if (res) { |
1341 | 0 | *size = (u32) psize; |
1342 | 0 | return res; |
1343 | 0 | } |
1344 | | /*ArrayView*/ |
1345 | 0 | v = JS_GetPropertyStr(ctx, obj, "buffer"); |
1346 | 0 | if (JS_IsUndefined(v)) return NULL; |
1347 | 0 | res = JS_GetArrayBuffer(ctx, &psize, v); |
1348 | 0 | JS_FreeValue(ctx, v); |
1349 | 0 | *size = (u32) psize; |
1350 | 0 | return res; |
1351 | 0 | } |
1352 | | static JSValue canvas_draw_array(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
1353 | 0 | { |
1354 | 0 | uint8_t *indices=NULL; |
1355 | 0 | uint8_t *vertices=NULL; |
1356 | 0 | u32 idx_size=0, vx_size, nb_comp=3; |
1357 | 0 | GF_Err e; |
1358 | 0 | GF_EVGPrimitiveType prim_type=GF_EVG_TRIANGLES; |
1359 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1360 | 0 | if (!canvas || argc<2) return GF_JS_EXCEPTION(c); |
1361 | | |
1362 | 0 | indices = evg_get_array(c, argv[0], &idx_size); |
1363 | 0 | vertices = evg_get_array(c, argv[1], &vx_size); |
1364 | 0 | if (!indices || ! vertices) return GF_JS_EXCEPTION(c); |
1365 | 0 | if (argc>2) { |
1366 | 0 | JS_ToInt32(c, (s32 *)&prim_type, argv[2]); |
1367 | 0 | if (!prim_type) return GF_JS_EXCEPTION(c); |
1368 | 0 | if (argc>3) { |
1369 | 0 | JS_ToInt32(c, &nb_comp, argv[3]); |
1370 | 0 | if ((nb_comp<2) || (nb_comp>4)) return GF_JS_EXCEPTION(c); |
1371 | 0 | } |
1372 | 0 | } |
1373 | 0 | if (vx_size % nb_comp) |
1374 | 0 | return GF_JS_EXCEPTION(c); |
1375 | 0 | idx_size /= sizeof(s32); |
1376 | 0 | vx_size /= sizeof(Float); |
1377 | 0 | e = gf_evg_surface_draw_array(canvas->surface, (u32 *)indices, idx_size, (Float *)vertices, vx_size, nb_comp, prim_type); |
1378 | 0 | if (e) return GF_JS_EXCEPTION(c); |
1379 | | |
1380 | 0 | return JS_UNDEFINED; |
1381 | 0 | } |
1382 | | |
1383 | | #ifndef GPAC_DISABLE_FONTS |
1384 | | static void text_update_path(GF_JSText *txt, Bool for_centered); |
1385 | | #endif |
1386 | | |
1387 | | static JSValue canvas_draw_path(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
1388 | 0 | { |
1389 | 0 | GF_Err e = GF_OK; |
1390 | 0 | Float z = 0; |
1391 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1392 | 0 | if (!canvas || argc<1) return GF_JS_EXCEPTION(ctx); |
1393 | 0 | if (argc>1) { |
1394 | 0 | EVG_GET_FLOAT(z, argv[1]); |
1395 | 0 | } |
1396 | | |
1397 | 0 | GF_Path *gp = JS_GetOpaque(argv[0], path_class_id); |
1398 | 0 | if (gp) { |
1399 | 0 | e = gf_evg_surface_draw_path(canvas->surface, gp, z); |
1400 | 0 | } else { |
1401 | 0 | GF_JSText *text = JS_GetOpaque(argv[0], text_class_id); |
1402 | 0 | if (text) { |
1403 | 0 | #ifndef GPAC_DISABLE_FONTS |
1404 | 0 | text_update_path(text, GF_TRUE); |
1405 | 0 | e = gf_evg_surface_draw_path(canvas->surface, text->path, z); |
1406 | | #else |
1407 | | e = GF_NOT_SUPPORTED; |
1408 | | #endif |
1409 | 0 | } |
1410 | 0 | } |
1411 | 0 | if (e) return js_throw_err(ctx, e); |
1412 | 0 | return JS_UNDEFINED; |
1413 | 0 | } |
1414 | | static JSValue canvas_clear_depth(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
1415 | 0 | { |
1416 | 0 | GF_Err e; |
1417 | 0 | Float depth = 1.0; |
1418 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1419 | 0 | if (!canvas) return GF_JS_EXCEPTION(ctx); |
1420 | 0 | if (argc) |
1421 | 0 | EVG_GET_FLOAT(depth, argv[0]); |
1422 | |
|
1423 | 0 | e = gf_evg_surface_clear_depth(canvas->surface, depth); |
1424 | 0 | if (e) return GF_JS_EXCEPTION(ctx); |
1425 | 0 | return JS_UNDEFINED; |
1426 | 0 | } |
1427 | | static JSValue canvas_viewport(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
1428 | 0 | { |
1429 | 0 | s32 x, y, w, h; |
1430 | 0 | GF_Err e; |
1431 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
1432 | 0 | if (!canvas) return GF_JS_EXCEPTION(ctx); |
1433 | 0 | if (argc) { |
1434 | 0 | if (argc<4) return js_throw_err(ctx, GF_BAD_PARAM); |
1435 | 0 | if (JS_ToInt32(ctx, &x, argv[0])) return js_throw_err(ctx, GF_BAD_PARAM); |
1436 | 0 | if (JS_ToInt32(ctx, &y, argv[1])) return js_throw_err(ctx, GF_BAD_PARAM); |
1437 | 0 | if (JS_ToInt32(ctx, &w, argv[2])) return js_throw_err(ctx, GF_BAD_PARAM); |
1438 | 0 | if (JS_ToInt32(ctx, &h, argv[3])) return js_throw_err(ctx, GF_BAD_PARAM); |
1439 | 0 | } else { |
1440 | 0 | x = y = 0; |
1441 | 0 | w = canvas->width; |
1442 | 0 | h = canvas->height; |
1443 | 0 | } |
1444 | 0 | e = gf_evg_surface_viewport(canvas->surface, x, y, w, h); |
1445 | 0 | if (e) return GF_JS_EXCEPTION(ctx); |
1446 | 0 | return JS_UNDEFINED; |
1447 | 0 | } |
1448 | | |
1449 | | |
1450 | | enum |
1451 | | { |
1452 | | //0 reserved for last op |
1453 | | EVG_OP_IF=1, |
1454 | | EVG_OP_ELSE, |
1455 | | EVG_OP_ELSEIF, |
1456 | | EVG_OP_END, |
1457 | | EVG_OP_GOTO, |
1458 | | EVG_OP_ASSIGN, |
1459 | | EVG_OP_DISCARD, |
1460 | | EVG_OP_ADD, |
1461 | | EVG_OP_SUB, |
1462 | | EVG_OP_MUL, |
1463 | | EVG_OP_DIV, |
1464 | | EVG_OP_NEG, |
1465 | | EVG_OP_LESS, |
1466 | | EVG_OP_LESS_EQUAL, |
1467 | | EVG_OP_GREATER, |
1468 | | EVG_OP_GREATER_EQUAL, |
1469 | | EVG_OP_EQUAL, |
1470 | | EVG_OP_NOT_EQUAL, |
1471 | | EVG_OP_SAMPLER, |
1472 | | EVG_OP_SAMPLER_YUV, |
1473 | | |
1474 | | EVG_OP_PRINT, |
1475 | | |
1476 | | EVG_OP_NORMALIZE, |
1477 | | EVG_OP_LENGTH, |
1478 | | EVG_OP_DISTANCE, |
1479 | | EVG_OP_DOT, |
1480 | | EVG_OP_CROSS, |
1481 | | EVG_OP_POW, |
1482 | | EVG_OP_SIN, |
1483 | | EVG_OP_ASIN, |
1484 | | EVG_OP_COS, |
1485 | | EVG_OP_ACOS, |
1486 | | EVG_OP_TAN, |
1487 | | EVG_OP_ATAN, |
1488 | | EVG_OP_LOG, |
1489 | | EVG_OP_EXP, |
1490 | | EVG_OP_LOG2, |
1491 | | EVG_OP_EXP2, |
1492 | | EVG_OP_SINH, |
1493 | | EVG_OP_COSH, |
1494 | | EVG_OP_SQRT, |
1495 | | EVG_OP_INVERSE_SQRT, |
1496 | | EVG_OP_ABS, |
1497 | | EVG_OP_SIGN, |
1498 | | EVG_OP_FLOOR, |
1499 | | EVG_OP_CEIL, |
1500 | | EVG_OP_FRACT, |
1501 | | EVG_OP_MOD, |
1502 | | EVG_OP_MIN, |
1503 | | EVG_OP_MAX, |
1504 | | EVG_OP_CLAMP, |
1505 | | EVG_OP_RGB2YUV, |
1506 | | EVG_OP_YUV2RGB, |
1507 | | |
1508 | | EVG_FIRST_VAR_ID |
1509 | | }; |
1510 | | |
1511 | | enum |
1512 | | { |
1513 | | VAR_FRAG_ARGB=1, |
1514 | | VAR_FRAG_YUV, |
1515 | | VAR_FRAG_X, |
1516 | | VAR_FRAG_Y, |
1517 | | VAR_FRAG_DEPTH, |
1518 | | VAR_FRAG_W, |
1519 | | VAR_FRAG_TX_COORD, |
1520 | | VAR_FRAG_TX_COORDI, |
1521 | | VAR_FRAG_ODD, |
1522 | | VAR_UNIFORM, |
1523 | | VAR_VERTEX_IN, |
1524 | | VAR_VERTEX_OUT, |
1525 | | VAR_VAI, |
1526 | | VAR_VA, |
1527 | | VAR_MATRIX, |
1528 | | }; |
1529 | | |
1530 | | |
1531 | | static GFINLINE Float isqrtf(Float v) |
1532 | 0 | { |
1533 | 0 | v = sqrtf(v); |
1534 | 0 | if (v) v = 1 / v; |
1535 | 0 | return v; |
1536 | 0 | } |
1537 | | static GFINLINE Float signf(Float v) |
1538 | 0 | { |
1539 | 0 | if (v==0) return 0; |
1540 | 0 | if (v>0) return 1.0; |
1541 | 0 | return -1.0; |
1542 | 0 | } |
1543 | | static GFINLINE Float fractf(Float v) |
1544 | 0 | { |
1545 | 0 | return v - floorf(v); |
1546 | 0 | } |
1547 | | static GFINLINE Float _modf(Float x, Float y) |
1548 | 0 | { |
1549 | 0 | if (!y) return 0.0; |
1550 | 0 | return x - y * floorf(x/y); |
1551 | 0 | } |
1552 | | |
1553 | | |
1554 | | |
1555 | | #if defined(WIN32) && !defined(__GNUC__) |
1556 | | # include <intrin.h> |
1557 | | # define GPAC_HAS_SSE2 |
1558 | | #else |
1559 | | # ifdef __SSE2__ |
1560 | | # include <emmintrin.h> |
1561 | | # define GPAC_HAS_SSE2 |
1562 | | # endif |
1563 | | #endif |
1564 | | |
1565 | | #ifdef GPAC_HAS_SSE2 |
1566 | | |
1567 | | static Float evg_float_clamp(Float val, Float minval, Float maxval) |
1568 | 0 | { |
1569 | 0 | _mm_store_ss( &val, _mm_min_ss( _mm_max_ss(_mm_set_ss(val),_mm_set_ss(minval)), _mm_set_ss(maxval) ) ); |
1570 | 0 | return val; |
1571 | 0 | } |
1572 | | #else |
1573 | | |
1574 | | #define evg_float_clamp(_val, _minval, _maxval)\ |
1575 | | (_val<_minval) ? _minval : (_val>_maxval) ? _maxval : _val; |
1576 | | |
1577 | | #endif |
1578 | | |
1579 | | |
1580 | | /* |
1581 | | |
1582 | | */ |
1583 | | |
1584 | | static Bool evg_shader_ops(GF_JSCanvas *canvas, EVGShader *shader, GF_EVGFragmentParam *frag, GF_EVGVertexParam *vert, ShaderVar *vars) |
1585 | 0 | { |
1586 | 0 | register u32 dim; |
1587 | 0 | Bool frag_valid = GF_FALSE; |
1588 | 0 | GF_Vec4 tmpl, tmpr; |
1589 | 0 | GF_Vec4 *left_val, *right_val, *right2_val; |
1590 | 0 | GF_IVec4 *right_vali; |
1591 | 0 | register u32 if_level=0; |
1592 | 0 | register u32 nif_level=0; |
1593 | 0 | register Bool cond_res=GF_FALSE; |
1594 | 0 | register ShaderOp *op = &shader->ops[0]; |
1595 | | |
1596 | | //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 |
1597 | | // tmpl.x = tmpl.y = tmpl.z = tmpl.q = 0; |
1598 | | // tmpr.x = tmpr.y = tmpr.z = tmpr.q = 0; |
1599 | | // memset(&tmpl, 0, sizeof(tmpl)); |
1600 | | // tmpr = tmpl; |
1601 | |
|
1602 | 0 | left_val = &tmpl; |
1603 | 0 | right_val = &tmpr; |
1604 | 0 | right_vali = (GF_IVec4 *) &tmpr; |
1605 | |
|
1606 | 0 | while ((++op)->op_type) { |
1607 | 0 | u32 next_idx, idx, var_idx; |
1608 | 0 | Bool has_next, norm_result=GF_FALSE; |
1609 | 0 | u8 right_val_type, left_val_type=0; |
1610 | 0 | u8 *left_val_type_ptr=NULL; |
1611 | |
|
1612 | 0 | if (shader->has_branches) { |
1613 | 0 | if (op->op_type == EVG_OP_GOTO) { |
1614 | 0 | u32 stack_idx = op->left_value; |
1615 | 0 | if (op->uni_name) stack_idx = op->ival; |
1616 | |
|
1617 | 0 | if (!stack_idx || (stack_idx > shader->nb_ops)) { |
1618 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Shader] Invalid goto operation, stack index %d not in stack indices [1, %d]\n", op->left_value, shader->nb_ops)); |
1619 | 0 | shader->invalid = GF_TRUE; |
1620 | 0 | return GF_FALSE; |
1621 | 0 | } |
1622 | | //op index in goto are 1-based, and our first op is a dummy one |
1623 | 0 | op = &shader->ops[stack_idx]; |
1624 | 0 | } else if (op->op_type == EVG_OP_ELSE) { |
1625 | 0 | if (nif_level) { |
1626 | 0 | if (nif_level==1) { |
1627 | 0 | nif_level=0; |
1628 | 0 | if_level++; |
1629 | 0 | } |
1630 | 0 | } else if (if_level) { |
1631 | 0 | if_level--; |
1632 | 0 | nif_level++; |
1633 | 0 | } |
1634 | 0 | continue; |
1635 | 0 | } else if (op->op_type == EVG_OP_END) { |
1636 | 0 | gf_assert(nif_level || if_level); |
1637 | 0 | if (nif_level) nif_level--; |
1638 | 0 | else if (if_level) if_level--; |
1639 | 0 | continue; |
1640 | 0 | } |
1641 | | |
1642 | 0 | if (nif_level) { |
1643 | 0 | if (op->op_type==EVG_OP_IF) { |
1644 | 0 | nif_level++; |
1645 | 0 | } |
1646 | 0 | continue; |
1647 | 0 | } |
1648 | 0 | } |
1649 | | |
1650 | 0 | dim=4; |
1651 | 0 | switch (op->left_value) { |
1652 | 0 | case VAR_FRAG_ARGB: |
1653 | 0 | left_val = &frag->color; |
1654 | 0 | left_val_type = COMP_V4; |
1655 | 0 | frag->frag_valid = GF_EVG_FRAG_RGB; |
1656 | 0 | frag_valid=GF_TRUE; |
1657 | 0 | break; |
1658 | 0 | case VAR_FRAG_YUV: |
1659 | 0 | left_val = &frag->color; |
1660 | 0 | left_val_type = COMP_V4; |
1661 | 0 | frag->frag_valid = GF_EVG_FRAG_YUV; |
1662 | 0 | frag_valid=GF_TRUE; |
1663 | 0 | break; |
1664 | 0 | case VAR_FRAG_X: |
1665 | 0 | left_val = &tmpl; |
1666 | 0 | tmpl.x = frag->screen_x; |
1667 | 0 | left_val_type = COMP_FLOAT; |
1668 | 0 | break; |
1669 | 0 | case VAR_FRAG_Y: |
1670 | 0 | left_val = &tmpl; |
1671 | 0 | tmpl.x = frag->screen_y; |
1672 | 0 | left_val_type = COMP_FLOAT; |
1673 | 0 | break; |
1674 | 0 | case VAR_FRAG_W: |
1675 | 0 | left_val = &tmpl; |
1676 | 0 | tmpl.x = frag->persp_denum; |
1677 | 0 | left_val_type = COMP_FLOAT; |
1678 | 0 | break; |
1679 | 0 | case VAR_FRAG_DEPTH: |
1680 | 0 | left_val = (GF_Vec4 *) &frag->depth; |
1681 | 0 | left_val_type = COMP_FLOAT; |
1682 | 0 | break; |
1683 | 0 | case VAR_FRAG_ODD: |
1684 | 0 | left_val = &tmpl; |
1685 | 0 | tmpl.x = frag->odd_flag; |
1686 | 0 | left_val_type = COMP_BOOL; |
1687 | 0 | break; |
1688 | 0 | case VAR_VERTEX_IN: |
1689 | 0 | left_val = (GF_Vec4 *) &vert->in_vertex; |
1690 | 0 | left_val_type = COMP_V4; |
1691 | 0 | break; |
1692 | 0 | case VAR_VERTEX_OUT: |
1693 | 0 | left_val = (GF_Vec4 *) &vert->out_vertex; |
1694 | 0 | left_val_type = COMP_V4; |
1695 | 0 | break; |
1696 | 0 | case VAR_VAI: |
1697 | 0 | left_val = (GF_Vec4 *) &op->vai.vai->anchors[vert->vertex_idx_in_prim]; |
1698 | 0 | left_val_type = COMP_V4; |
1699 | 0 | norm_result = op->vai.vai->normalize; |
1700 | 0 | break; |
1701 | 0 | case 0: |
1702 | 0 | break; |
1703 | 0 | default: |
1704 | 0 | { |
1705 | 0 | u32 l_var_idx = op->left_value - EVG_FIRST_VAR_ID-1; |
1706 | 0 | left_val = &vars[l_var_idx].vecval; |
1707 | 0 | left_val_type = vars[l_var_idx].value_type; |
1708 | 0 | left_val_type_ptr = & vars[l_var_idx].value_type; |
1709 | 0 | } |
1710 | 0 | break; |
1711 | 0 | } |
1712 | | |
1713 | 0 | if (op->right_value>EVG_FIRST_VAR_ID) { |
1714 | 0 | var_idx = op->right_value - EVG_FIRST_VAR_ID-1; |
1715 | 0 | right_val = &vars[var_idx].vecval; |
1716 | 0 | right_val_type = vars[var_idx].value_type; |
1717 | 0 | } else { |
1718 | 0 | right_val_type = 0; |
1719 | |
|
1720 | 0 | switch (op->right_value) { |
1721 | 0 | case VAR_VAI: |
1722 | 0 | if (op->vai.vai) { |
1723 | 0 | vai_call_lerp(op->vai.vai, frag, (Float *) &tmpr); |
1724 | | // dim = MIN(4, op->vai.vai->result.dim); |
1725 | 0 | dim = op->vai.vai->result.dim; |
1726 | 0 | right_val = &tmpr; |
1727 | 0 | right_val_type = op->vai.vai->result.comp_type; |
1728 | 0 | } |
1729 | 0 | break; |
1730 | 0 | case VAR_VA: |
1731 | 0 | if (op->va.va) { |
1732 | 0 | u32 va_idx, j, nb_v_per_prim=3; |
1733 | 0 | EVG_VA *va = op->va.va; |
1734 | |
|
1735 | 0 | if (vert->ptype == GF_EVG_LINES) |
1736 | 0 | nb_v_per_prim=2; |
1737 | 0 | else if (vert->ptype == GF_EVG_POINTS) |
1738 | 0 | nb_v_per_prim=1; |
1739 | |
|
1740 | 0 | if (va->interp_type==GF_EVG_VAI_PRIMITIVE) { |
1741 | 0 | va_idx = vert->prim_index * va->nb_comp; |
1742 | 0 | } |
1743 | 0 | else if (va->interp_type==GF_EVG_VAI_VERTEX_INDEX) { |
1744 | 0 | va_idx = vert->vertex_idx * va->nb_comp; |
1745 | 0 | } else { |
1746 | 0 | va_idx = vert->prim_index * nb_v_per_prim * va->nb_comp; |
1747 | 0 | } |
1748 | |
|
1749 | 0 | if (va_idx+va->nb_comp > va->nb_values) |
1750 | 0 | return GF_FALSE; |
1751 | | |
1752 | 0 | right_val = &tmpr; |
1753 | 0 | right_val->x = right_val->y = right_val->z = right_val->q = 0; |
1754 | 0 | gf_assert(va->nb_comp<=4); |
1755 | 0 | for (j=0; j<va->nb_comp; j++) { |
1756 | 0 | ((Float *)right_val)[j] = va->values[va_idx+j]; |
1757 | 0 | } |
1758 | 0 | if (va->normalize) { |
1759 | 0 | if (va->nb_comp==2) { |
1760 | 0 | Float len; |
1761 | 0 | if (!right_val->x) len = ABS(right_val->y); |
1762 | 0 | else if (!right_val->y) len = ABS(right_val->x); |
1763 | 0 | else len = sqrtf(right_val->x*right_val->x + right_val->y*right_val->y); |
1764 | 0 | if (len) { |
1765 | 0 | right_val->x/=len; |
1766 | 0 | right_val->y/=len; |
1767 | 0 | } |
1768 | 0 | } else { |
1769 | 0 | gf_vec_norm((GF_Vec *) right_val); |
1770 | 0 | } |
1771 | |
|
1772 | 0 | } |
1773 | 0 | right_val_type = va->att_type; |
1774 | 0 | } |
1775 | 0 | break; |
1776 | 0 | case VAR_MATRIX: |
1777 | 0 | if (op->mx.mx) { |
1778 | 0 | if (op->op_type==EVG_OP_MUL) { |
1779 | 0 | gf_mx_apply_vec_4x4(op->mx.mx, left_val); |
1780 | 0 | continue; |
1781 | 0 | } |
1782 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Shader] Invalid operation for right value matrix\n")); |
1783 | 0 | shader->invalid = GF_TRUE; |
1784 | 0 | return GF_FALSE; |
1785 | 0 | } |
1786 | 0 | break; |
1787 | 0 | case VAR_FRAG_ARGB: |
1788 | 0 | right_val = &frag->color; |
1789 | 0 | right_val_type = COMP_V4; |
1790 | 0 | break; |
1791 | 0 | case VAR_FRAG_YUV: |
1792 | 0 | right_val = &frag->color; |
1793 | 0 | right_val_type = COMP_V4; |
1794 | 0 | break; |
1795 | 0 | case VAR_FRAG_X: |
1796 | 0 | right_val = &tmpr; |
1797 | 0 | tmpr.x = frag->screen_x; |
1798 | 0 | right_val_type = COMP_FLOAT; |
1799 | 0 | break; |
1800 | 0 | case VAR_FRAG_Y: |
1801 | 0 | right_val = &tmpr; |
1802 | 0 | tmpr.x = frag->screen_y; |
1803 | 0 | right_val_type = COMP_FLOAT; |
1804 | 0 | break; |
1805 | 0 | case VAR_FRAG_W: |
1806 | 0 | right_val = &tmpr; |
1807 | 0 | tmpr.x = frag->persp_denum; |
1808 | 0 | right_val_type = COMP_FLOAT; |
1809 | 0 | break; |
1810 | 0 | case VAR_FRAG_DEPTH: |
1811 | 0 | right_val = &tmpr; |
1812 | 0 | tmpr.x = frag->depth; |
1813 | 0 | right_val_type = COMP_FLOAT; |
1814 | 0 | break; |
1815 | 0 | case VAR_VERTEX_IN: |
1816 | 0 | right_val = &vert->in_vertex; |
1817 | 0 | right_val_type = COMP_V4; |
1818 | 0 | break; |
1819 | 0 | case VAR_VERTEX_OUT: |
1820 | 0 | right_val = &vert->out_vertex; |
1821 | 0 | right_val_type = COMP_V4; |
1822 | 0 | break; |
1823 | 0 | case VAR_FRAG_TX_COORD: |
1824 | 0 | right_val = &tmpr; |
1825 | 0 | right_val->x = ((Float)frag->tx_x) / frag->tx_width; |
1826 | 0 | right_val->y = ((Float)frag->tx_y) / frag->tx_height; |
1827 | 0 | right_val_type = COMP_V2_XY; |
1828 | 0 | break; |
1829 | 0 | case VAR_FRAG_TX_COORDI: |
1830 | 0 | right_val = &tmpr; |
1831 | 0 | right_vali->x = frag->tx_x; |
1832 | 0 | right_vali->y = frag->tx_y; |
1833 | 0 | right_val_type = COMP_V2_XY | COMP_FLAG_INT; |
1834 | 0 | break; |
1835 | 0 | case VAR_FRAG_ODD: |
1836 | 0 | right_val = &tmpr; |
1837 | 0 | right_val->x = frag->odd_flag; |
1838 | 0 | right_val_type = COMP_BOOL; |
1839 | 0 | break; |
1840 | 0 | default: |
1841 | 0 | if (!op->right_value || (op->right_value==VAR_UNIFORM) ) { |
1842 | 0 | right_val = (GF_Vec4 *) &op->vec[0]; |
1843 | 0 | right_val_type = op->right_value_type; |
1844 | 0 | } |
1845 | 0 | break; |
1846 | 0 | } |
1847 | 0 | } |
1848 | 0 | if (!right_val_type) { |
1849 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Shader] Invalid right-value type in operation (stack index %d)\n", (u32) ((op - shader->ops) / sizeof(ShaderOp)) )); |
1850 | 0 | shader->invalid = GF_TRUE; |
1851 | 0 | return GF_FALSE; |
1852 | 0 | } |
1853 | | |
1854 | 0 | #define GET_FIRST_COMP\ |
1855 | 0 | idx=0;\ |
1856 | 0 | while (1) {\ |
1857 | 0 | if (op->right_value_type & (1<<idx))\ |
1858 | 0 | break;\ |
1859 | 0 | if (idx==3)\ |
1860 | 0 | break;\ |
1861 | 0 | idx++;\ |
1862 | 0 | }\ |
1863 | 0 | |
1864 | 0 | #define GET_NEXT_COMP\ |
1865 | 0 | has_next = GF_FALSE;\ |
1866 | 0 | next_idx = idx;\ |
1867 | 0 | while (1) {\ |
1868 | 0 | if (next_idx==3)\ |
1869 | 0 | break;\ |
1870 | 0 | if (op->right_value_type & (1<< (next_idx+1)) ) {\ |
1871 | 0 | has_next = GF_TRUE;\ |
1872 | 0 | next_idx = idx+1;\ |
1873 | 0 | break;\ |
1874 | 0 | }\ |
1875 | 0 | next_idx++;\ |
1876 | 0 | }\ |
1877 | 0 | if (has_next) idx = next_idx;\ |
1878 | 0 |
|
1879 | 0 | switch (op->op_type) { |
1880 | 0 | case EVG_OP_ASSIGN: |
1881 | | //full assignment |
1882 | 0 | if (op->left_value_type==COMP_V4) { |
1883 | 0 | if (left_val_type_ptr) { |
1884 | 0 | left_val_type = *left_val_type_ptr = right_val_type; |
1885 | 0 | } |
1886 | |
|
1887 | 0 | if (op->right_value_type==COMP_V4) { |
1888 | 0 | *left_val = *right_val; |
1889 | 0 | if (dim<4) left_val->q = 1.0; |
1890 | 0 | } else { |
1891 | 0 | switch (right_val_type) { |
1892 | 0 | case COMP_BOOL: |
1893 | 0 | if (left_val_type_ptr) { |
1894 | 0 | *((Bool *) left_val) = *((Bool *) right_val) ? GF_TRUE : GF_FALSE; |
1895 | 0 | } else { |
1896 | 0 | left_val->x = (Float) ( *(Bool *) right_val ? 1.0 : 0.0 ); |
1897 | 0 | left_val->y = left_val->z = left_val->q = left_val->x; |
1898 | 0 | } |
1899 | 0 | break; |
1900 | 0 | case COMP_INT: |
1901 | 0 | if (left_val_type_ptr || (left_val_type==COMP_INT)) { |
1902 | 0 | *((s32 *) left_val) = *(s32 *) right_val; |
1903 | 0 | } else { |
1904 | 0 | left_val->x = (Float) *(s32 *) right_val; |
1905 | 0 | left_val->y = left_val->z = left_val->q = left_val->x; |
1906 | 0 | } |
1907 | 0 | break; |
1908 | 0 | case COMP_FLOAT: |
1909 | 0 | if (left_val_type_ptr) { |
1910 | 0 | *((Float *) left_val) = *(Float *) right_val; |
1911 | 0 | } else { |
1912 | 0 | left_val->x = *(Float *) right_val; |
1913 | 0 | left_val->y = left_val->z = left_val->q = left_val->x; |
1914 | 0 | } |
1915 | 0 | break; |
1916 | 0 | case COMP_V4: |
1917 | 0 | *left_val = *right_val; |
1918 | 0 | if (dim<4) left_val->q = 1.0; |
1919 | 0 | break; |
1920 | 0 | default: |
1921 | 0 | { |
1922 | 0 | Float *srcs = (Float *) &right_val->x; |
1923 | |
|
1924 | 0 | GET_FIRST_COMP |
1925 | 0 | if (left_val_type & COMP_X) { left_val->x = srcs[idx]; GET_NEXT_COMP } |
1926 | 0 | if (left_val_type & COMP_Y) { left_val->y = srcs[idx]; GET_NEXT_COMP } |
1927 | 0 | if (left_val_type & COMP_Z) { left_val->z = srcs[idx]; GET_NEXT_COMP } |
1928 | 0 | if (dim<4) left_val->q = 1.0; |
1929 | 0 | else if (left_val_type & COMP_Q) { left_val->q = srcs[idx]; } |
1930 | 0 | } |
1931 | 0 | break; |
1932 | 0 | } |
1933 | 0 | } |
1934 | 0 | } |
1935 | | //partial assignment, only valid for float sources |
1936 | 0 | else { |
1937 | 0 | Bool use_const; |
1938 | 0 | Float cval; |
1939 | 0 | if (right_val_type==COMP_FLOAT) { |
1940 | 0 | use_const = GF_TRUE; |
1941 | 0 | cval = right_val->x; |
1942 | 0 | } else if (right_val_type==COMP_INT) { |
1943 | 0 | use_const = GF_TRUE; |
1944 | 0 | cval = (Float) ( *(s32*)right_val); |
1945 | 0 | } else { |
1946 | 0 | use_const = GF_FALSE; |
1947 | 0 | } |
1948 | |
|
1949 | 0 | if (use_const) { |
1950 | 0 | if (op->left_value_type & COMP_X) left_val->x = cval; |
1951 | 0 | if (op->left_value_type & COMP_Y) left_val->y = cval; |
1952 | 0 | if (op->left_value_type & COMP_Z) left_val->z = cval; |
1953 | 0 | if (op->left_value_type & COMP_Q) left_val->q = cval; |
1954 | 0 | } else { |
1955 | 0 | Float *srcs = (Float *) &right_val->x; |
1956 | |
|
1957 | 0 | GET_FIRST_COMP |
1958 | 0 | if (op->left_value_type & COMP_X) { left_val->x = srcs[idx]; GET_NEXT_COMP } |
1959 | 0 | if (op->left_value_type & COMP_Y) { left_val->y = srcs[idx]; GET_NEXT_COMP } |
1960 | 0 | if (op->left_value_type & COMP_Z) { left_val->z = srcs[idx]; GET_NEXT_COMP } |
1961 | 0 | if (op->left_value_type & COMP_Q) { left_val->q = srcs[idx]; } |
1962 | 0 | } |
1963 | 0 | } |
1964 | 0 | if (norm_result) |
1965 | 0 | gf_vec_norm((GF_Vec *)left_val); |
1966 | 0 | break; |
1967 | | |
1968 | 0 | #define BASE_OP(_opv, _opv2)\ |
1969 | 0 | if (op->left_value_type==COMP_V4) {\ |
1970 | 0 | switch (right_val_type) {\ |
1971 | 0 | case COMP_INT: \ |
1972 | 0 | if (left_val_type == COMP_INT) {\ |
1973 | 0 | *((s32 *) left_val) _opv *(s32 *) right_val;\ |
1974 | 0 | } else if (left_val_type == COMP_FLOAT) {\ |
1975 | 0 | left_val->x _opv *(s32 *) right_val;\ |
1976 | 0 | } else {\ |
1977 | 0 | left_val->x _opv *(s32 *) right_val;\ |
1978 | 0 | left_val->y _opv *(s32 *) right_val;\ |
1979 | 0 | left_val->z _opv *(s32 *) right_val;\ |
1980 | 0 | left_val->q _opv *(s32 *) right_val;\ |
1981 | 0 | }\ |
1982 | 0 | break;\ |
1983 | 0 | case COMP_FLOAT:\ |
1984 | 0 | if (left_val_type == COMP_INT) {\ |
1985 | 0 | left_val->x = *((s32 *) left_val) _opv2 right_val->x;\ |
1986 | 0 | *left_val_type_ptr = COMP_FLOAT;\ |
1987 | 0 | } else if (left_val_type == COMP_FLOAT) {\ |
1988 | 0 | left_val->x _opv right_val->x;\ |
1989 | 0 | } else {\ |
1990 | 0 | left_val->x _opv right_val->x;\ |
1991 | 0 | left_val->y _opv right_val->x;\ |
1992 | 0 | left_val->z _opv right_val->x;\ |
1993 | 0 | left_val->q _opv right_val->x;\ |
1994 | 0 | }\ |
1995 | 0 | break;\ |
1996 | 0 | case COMP_BOOL:\ |
1997 | 0 | break;\ |
1998 | 0 | default:\ |
1999 | 0 | {\ |
2000 | 0 | Float *srcs = (Float *) &right_val->x;\ |
2001 | 0 | GET_FIRST_COMP\ |
2002 | 0 | if (left_val_type & COMP_X) { left_val->x _opv srcs[idx]; GET_NEXT_COMP } \ |
2003 | 0 | if (left_val_type & COMP_Y) { left_val->y _opv srcs[idx]; GET_NEXT_COMP } \ |
2004 | 0 | if (left_val_type & COMP_Z) { left_val->z _opv srcs[idx]; GET_NEXT_COMP } \ |
2005 | 0 | if (left_val_type & COMP_Q) { left_val->q _opv srcs[idx]; }\ |
2006 | 0 | }\ |
2007 | 0 | break;\ |
2008 | 0 | }\ |
2009 | 0 | }\ |
2010 | 0 | else {\ |
2011 | 0 | Bool use_const = GF_FALSE;\ |
2012 | 0 | Float cval;\ |
2013 | 0 | if (right_val_type==COMP_FLOAT) {\ |
2014 | 0 | use_const = GF_TRUE;\ |
2015 | 0 | cval = right_val->x;\ |
2016 | 0 | } else if (right_val_type==COMP_INT) {\ |
2017 | 0 | use_const = GF_TRUE;\ |
2018 | 0 | cval = (Float) ( *(s32*)right_val);\ |
2019 | 0 | }\ |
2020 | 0 | if (use_const) {\ |
2021 | 0 | if (op->left_value_type & COMP_X) left_val->x _opv cval;\ |
2022 | 0 | if (op->left_value_type & COMP_Y) left_val->y _opv cval;\ |
2023 | 0 | if (op->left_value_type & COMP_Z) left_val->z _opv cval;\ |
2024 | 0 | if (op->left_value_type & COMP_Q) left_val->q _opv cval;\ |
2025 | 0 | } else {\ |
2026 | 0 | Float *srcs = (Float *) &right_val->x;\ |
2027 | 0 | GET_FIRST_COMP\ |
2028 | 0 | if (op->left_value_type & COMP_X) { left_val->x _opv srcs[idx]; GET_NEXT_COMP }\ |
2029 | 0 | if (op->left_value_type & COMP_Y) { left_val->y _opv srcs[idx]; GET_NEXT_COMP }\ |
2030 | 0 | if (op->left_value_type & COMP_Z) { left_val->z _opv srcs[idx]; GET_NEXT_COMP }\ |
2031 | 0 | if (op->left_value_type & COMP_Q) left_val->q _opv srcs[idx];\ |
2032 | 0 | }\ |
2033 | 0 | }\ |
2034 | 0 |
|
2035 | 0 | case EVG_OP_MUL: |
2036 | 0 | BASE_OP(*=, *) |
2037 | 0 | break; |
2038 | 0 | case EVG_OP_DIV: |
2039 | 0 | BASE_OP(/=, /) |
2040 | 0 | break; |
2041 | 0 | case EVG_OP_ADD: |
2042 | 0 | BASE_OP(+=, +) |
2043 | 0 | break; |
2044 | 0 | case EVG_OP_SUB: |
2045 | 0 | BASE_OP(-=, -) |
2046 | 0 | break; |
2047 | 0 | case EVG_OP_NEG: |
2048 | 0 | BASE_OP(= !, *) |
2049 | 0 | break; |
2050 | 0 | case EVG_OP_IF: |
2051 | 0 | #define BASE_COND(_opv)\ |
2052 | 0 | cond_res=GF_FALSE;\ |
2053 | 0 | if (op->left_value_type==COMP_V4) {\ |
2054 | 0 | switch (right_val_type) {\ |
2055 | 0 | case COMP_INT:\ |
2056 | 0 | case COMP_BOOL:\ |
2057 | 0 | if ((left_val_type == COMP_INT) || (left_val_type == COMP_BOOL)) {\ |
2058 | 0 | cond_res = ( *((s32 *) left_val) _opv *(s32 *) right_val) ? GF_TRUE : GF_FALSE;\ |
2059 | 0 | } else if (left_val_type == COMP_FLOAT) {\ |
2060 | 0 | cond_res = (left_val->x _opv *(s32 *) right_val) ? GF_TRUE : GF_FALSE;\ |
2061 | 0 | } else {\ |
2062 | 0 | cond_res = ( (left_val->x _opv *(s32 *) right_val) && \ |
2063 | 0 | (left_val->y _opv *(s32 *) right_val) && \ |
2064 | 0 | (left_val->z _opv *(s32 *) right_val) && \ |
2065 | 0 | (left_val->q _opv *(s32 *) right_val) ) ? GF_TRUE : GF_FALSE;\ |
2066 | 0 | }\ |
2067 | 0 | break;\ |
2068 | 0 | case COMP_FLOAT:\ |
2069 | 0 | if (left_val_type == COMP_INT) {\ |
2070 | 0 | cond_res = ( *((s32 *) left_val) _opv right_val->x) ? GF_TRUE : GF_FALSE;\ |
2071 | 0 | } else if (left_val_type == COMP_FLOAT) {\ |
2072 | 0 | cond_res = (left_val->x _opv right_val->x) ? GF_TRUE : GF_FALSE;\ |
2073 | 0 | } else {\ |
2074 | 0 | cond_res = ( (left_val->x _opv right_val->x) &&\ |
2075 | 0 | (left_val->y _opv right_val->x) &&\ |
2076 | 0 | (left_val->z _opv right_val->x) && \ |
2077 | 0 | (left_val->q _opv right_val->x) ) ? GF_TRUE : GF_FALSE;\ |
2078 | 0 | }\ |
2079 | 0 | break;\ |
2080 | 0 | default:\ |
2081 | 0 | {\ |
2082 | 0 | cond_res=GF_TRUE;\ |
2083 | 0 | Float *srcs = (Float *) &right_val->x;\ |
2084 | 0 | GET_FIRST_COMP\ |
2085 | 0 | if (left_val_type & COMP_X) { if (! (left_val->x _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \ |
2086 | 0 | if (left_val_type & COMP_Y) { if (! (left_val->y _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \ |
2087 | 0 | if (left_val_type & COMP_Z) { if (! (left_val->z _opv srcs[idx]) ) cond_res = GF_FALSE; GET_NEXT_COMP } \ |
2088 | 0 | if (left_val_type & COMP_Q) { if (! (left_val->q _opv srcs[idx]) ) cond_res = GF_FALSE; }\ |
2089 | 0 | }\ |
2090 | 0 | break;\ |
2091 | 0 | }\ |
2092 | 0 | }\ |
2093 | 0 | else {\ |
2094 | 0 | Bool use_const = GF_FALSE;\ |
2095 | 0 | Float cval;\ |
2096 | 0 | if (right_val_type==COMP_FLOAT) {\ |
2097 | 0 | use_const = GF_TRUE;\ |
2098 | 0 | cval = right_val->x;\ |
2099 | 0 | } else if (right_val_type==COMP_INT) {\ |
2100 | 0 | use_const = GF_TRUE;\ |
2101 | 0 | cval = (Float) ( *(s32*)right_val);\ |
2102 | 0 | }\ |
2103 | 0 | if (use_const) {\ |
2104 | 0 | cond_res=GF_TRUE;\ |
2105 | 0 | if (op->left_value_type & COMP_X) if (! (left_val->x _opv cval) ) cond_res=GF_FALSE;\ |
2106 | 0 | if (op->left_value_type & COMP_Y) if (! (left_val->y _opv cval) ) cond_res=GF_FALSE;\ |
2107 | 0 | if (op->left_value_type & COMP_Z) if (! (left_val->z _opv cval) ) cond_res=GF_FALSE;\ |
2108 | 0 | if (op->left_value_type & COMP_Q) if (! (left_val->q _opv cval) ) cond_res=GF_FALSE;\ |
2109 | 0 | } else {\ |
2110 | 0 | Float *srcs = (Float *) &right_val->x;\ |
2111 | 0 | GET_FIRST_COMP\ |
2112 | 0 | if (op->left_value_type & COMP_X) { if (! (left_val->x _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\ |
2113 | 0 | if (op->left_value_type & COMP_Y) { if (! (left_val->y _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\ |
2114 | 0 | if (op->left_value_type & COMP_Z) { if (! (left_val->z _opv srcs[idx]) ) cond_res=GF_FALSE; GET_NEXT_COMP }\ |
2115 | 0 | if (op->left_value_type & COMP_Q) { if (! (left_val->q _opv srcs[idx]) ) cond_res=GF_FALSE; }\ |
2116 | 0 | }\ |
2117 | 0 | } |
2118 | |
|
2119 | 0 | switch (op->cond_type) { |
2120 | 0 | case EVG_OP_LESS: |
2121 | 0 | { BASE_COND(<) } |
2122 | 0 | break; |
2123 | 0 | case EVG_OP_LESS_EQUAL: |
2124 | 0 | { BASE_COND(<=) } |
2125 | 0 | break; |
2126 | 0 | case EVG_OP_GREATER: |
2127 | 0 | { BASE_COND(>) } |
2128 | 0 | break; |
2129 | 0 | case EVG_OP_GREATER_EQUAL: |
2130 | 0 | { BASE_COND(>=) } |
2131 | 0 | break; |
2132 | 0 | case EVG_OP_EQUAL: |
2133 | 0 | { BASE_COND(==) } |
2134 | 0 | break; |
2135 | 0 | case EVG_OP_NOT_EQUAL: |
2136 | 0 | { BASE_COND(!=) } |
2137 | 0 | break; |
2138 | 0 | } |
2139 | | |
2140 | 0 | if (cond_res) if_level++; |
2141 | 0 | else nif_level++; |
2142 | |
|
2143 | 0 | break; |
2144 | | |
2145 | 0 | case EVG_OP_SAMPLER: |
2146 | 0 | if (left_val_type_ptr) { |
2147 | 0 | *left_val_type_ptr = COMP_V4; |
2148 | 0 | } |
2149 | 0 | if ((right_val_type==(COMP_V2_XY|COMP_FLAG_INT)) && (op->left_value == VAR_FRAG_ARGB)) { |
2150 | 0 | u32 tx = ((GF_IVec4 *)right_val)->x * op->tx->width / frag->tx_width; |
2151 | 0 | u32 ty = ((GF_IVec4 *)right_val)->y * op->tx->height / frag->tx_height; |
2152 | 0 | if (op->tx->wide) { |
2153 | 0 | frag->color_pack_wide = gf_evg_stencil_get_pixel_wide(op->tx->stencil, tx, ty); |
2154 | 0 | } else { |
2155 | 0 | frag->color_pack = gf_evg_stencil_get_pixel(op->tx->stencil, tx, ty); |
2156 | 0 | } |
2157 | 0 | frag->frag_valid = GF_EVG_FRAG_RGB_PACK; |
2158 | 0 | frag_valid=GF_TRUE; |
2159 | 0 | } |
2160 | 0 | else if (op->left_value_type==COMP_V4) { |
2161 | 0 | *left_val = gf_evg_stencil_get_pixel_f(op->tx->stencil, right_val->x, right_val->y); |
2162 | 0 | } else { |
2163 | 0 | tmpr = gf_evg_stencil_get_pixel_f(op->tx->stencil, right_val->x, right_val->y); |
2164 | 0 | if (op->left_value_type & COMP_X) left_val->x = tmpr.x; |
2165 | 0 | if (op->left_value_type & COMP_Y) left_val->y = tmpr.y; |
2166 | 0 | if (op->left_value_type & COMP_Z) left_val->z = tmpr.z; |
2167 | 0 | if (op->left_value_type & COMP_Q) left_val->q = tmpr.q; |
2168 | 0 | } |
2169 | 0 | break; |
2170 | | |
2171 | 0 | case EVG_OP_SAMPLER_YUV: |
2172 | 0 | if (left_val_type_ptr) { |
2173 | 0 | *left_val_type_ptr = COMP_V4; |
2174 | 0 | } |
2175 | |
|
2176 | 0 | if ((right_val_type==(COMP_V2_XY|COMP_FLAG_INT)) && (op->left_value == VAR_FRAG_YUV)) { |
2177 | 0 | u32 tx = ((GF_IVec4 *)right_val)->x * op->tx->width / frag->tx_width; |
2178 | 0 | u32 ty = ((GF_IVec4 *)right_val)->y * op->tx->height / frag->tx_height; |
2179 | 0 | if (op->tx->wide) { |
2180 | 0 | frag->color_pack_wide = gf_evg_stencil_get_pixel_yuv_wide(op->tx->stencil, tx, ty); |
2181 | 0 | } else { |
2182 | 0 | frag->color_pack = gf_evg_stencil_get_pixel_yuv(op->tx->stencil, tx, ty); |
2183 | 0 | } |
2184 | 0 | frag->frag_valid = GF_EVG_FRAG_YUV_PACK; |
2185 | 0 | frag_valid=GF_TRUE; |
2186 | 0 | } |
2187 | 0 | else if (op->left_value_type==COMP_V4) { |
2188 | 0 | *left_val = gf_evg_stencil_get_pixel_yuv_f(op->tx->stencil, right_val->x, right_val->y); |
2189 | 0 | } else { |
2190 | 0 | tmpr = gf_evg_stencil_get_pixel_yuv_f(op->tx->stencil, right_val->x, right_val->y); |
2191 | 0 | if (op->left_value_type & COMP_X) left_val->x = tmpr.x; |
2192 | 0 | if (op->left_value_type & COMP_Y) left_val->y = tmpr.y; |
2193 | 0 | if (op->left_value_type & COMP_Z) left_val->z = tmpr.z; |
2194 | 0 | if (op->left_value_type & COMP_Q) left_val->q = tmpr.q; |
2195 | 0 | } |
2196 | 0 | break; |
2197 | 0 | case EVG_OP_DISCARD: |
2198 | 0 | frag->frag_valid = 0; |
2199 | 0 | return GF_FALSE; |
2200 | 0 | case EVG_OP_NORMALIZE: |
2201 | 0 | if (left_val_type_ptr) { |
2202 | 0 | *left_val_type_ptr = COMP_V4; |
2203 | 0 | } |
2204 | 0 | *left_val = *right_val; |
2205 | 0 | gf_vec_norm((GF_Vec *)left_val); |
2206 | 0 | break; |
2207 | 0 | case EVG_OP_LENGTH: |
2208 | 0 | if (left_val_type_ptr) { |
2209 | 0 | *left_val_type_ptr = COMP_FLOAT; |
2210 | 0 | } |
2211 | 0 | left_val->x = gf_vec_len_p( (GF_Vec *) right_val); |
2212 | 0 | break; |
2213 | 0 | case EVG_OP_DISTANCE: |
2214 | 0 | if (left_val_type_ptr) { |
2215 | 0 | *left_val_type_ptr = COMP_FLOAT; |
2216 | 0 | } |
2217 | 0 | right2_val = &vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval; |
2218 | | //right2_val_type = vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type; |
2219 | 0 | gf_vec_diff(tmpr, *right_val, *right2_val); |
2220 | 0 | left_val->x = gf_vec_len_p( (GF_Vec *) &tmpr); |
2221 | 0 | break; |
2222 | | |
2223 | 0 | case EVG_OP_DOT: |
2224 | 0 | if (left_val_type_ptr) { |
2225 | 0 | *left_val_type_ptr = COMP_FLOAT; |
2226 | 0 | } |
2227 | 0 | right2_val = &vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval; |
2228 | | //right2_val_type = vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type; |
2229 | 0 | left_val->x = gf_vec_dot_p( (GF_Vec *) right_val, (GF_Vec *) right2_val); |
2230 | 0 | break; |
2231 | 0 | case EVG_OP_CROSS: |
2232 | 0 | if (left_val_type_ptr) { |
2233 | 0 | *left_val_type_ptr = COMP_V4; |
2234 | 0 | } |
2235 | 0 | right2_val = &vars[op->right_value_second - EVG_FIRST_VAR_ID-1].vecval; |
2236 | | //right2_val_type = vars[op->right_value_second - EVG_FIRST_VAR_ID-1].value_type; |
2237 | 0 | * (GF_Vec *) left_val = gf_vec_cross_p( (GF_Vec *) right_val, (GF_Vec *) right2_val); |
2238 | 0 | break; |
2239 | | |
2240 | 0 | #define BASE_FUN2(__fun) \ |
2241 | 0 | if (left_val_type_ptr) {\ |
2242 | 0 | *left_val_type_ptr = right_val_type;\ |
2243 | 0 | }\ |
2244 | 0 | var_idx = op->right_value_second - EVG_FIRST_VAR_ID-1;\ |
2245 | 0 | right2_val = &vars[var_idx].vecval;\ |
2246 | 0 | if (right_val_type==COMP_FLOAT) {\ |
2247 | 0 | left_val->x = __fun(right_val->x, right2_val->x);\ |
2248 | 0 | } else {\ |
2249 | 0 | if (right_val_type&COMP_X) {\ |
2250 | 0 | left_val->x = __fun(right_val->x, right2_val->x);\ |
2251 | 0 | }\ |
2252 | 0 | if (right_val_type&COMP_Y) {\ |
2253 | 0 | left_val->y = __fun(right_val->y, right2_val->y);\ |
2254 | 0 | }\ |
2255 | 0 | if (right_val_type&COMP_Z) {\ |
2256 | 0 | left_val->z = __fun(right_val->z, right2_val->z);\ |
2257 | 0 | }\ |
2258 | 0 | if (right_val_type&COMP_Q) {\ |
2259 | 0 | left_val->q = __fun(right_val->z, right2_val->q);\ |
2260 | 0 | }\ |
2261 | 0 | }\ |
2262 | 0 |
|
2263 | | |
2264 | 0 | #define BASE_FUN(__fun) \ |
2265 | 0 | if (left_val_type_ptr) {\ |
2266 | 0 | *left_val_type_ptr = right_val_type;\ |
2267 | 0 | }\ |
2268 | 0 | if (right_val_type==COMP_FLOAT) {\ |
2269 | 0 | left_val->x = (Float) __fun(right_val->x);\ |
2270 | 0 | } else {\ |
2271 | 0 | if (right_val_type&COMP_X) {\ |
2272 | 0 | left_val->x = (Float) __fun(right_val->x);\ |
2273 | 0 | }\ |
2274 | 0 | if (right_val_type&COMP_Y) {\ |
2275 | 0 | left_val->y = (Float) __fun(right_val->y);\ |
2276 | 0 | }\ |
2277 | 0 | if (right_val_type&COMP_Z) {\ |
2278 | 0 | left_val->z = (Float) __fun(right_val->z);\ |
2279 | 0 | }\ |
2280 | 0 | if (right_val_type&COMP_Q) {\ |
2281 | 0 | left_val->q = (Float) __fun(right_val->z);\ |
2282 | 0 | }\ |
2283 | 0 | }\ |
2284 | 0 |
|
2285 | 0 | case EVG_OP_POW: |
2286 | 0 | BASE_FUN2(powf) |
2287 | 0 | break; |
2288 | 0 | case EVG_OP_SIN: |
2289 | 0 | BASE_FUN(sinf) |
2290 | 0 | break; |
2291 | 0 | case EVG_OP_ASIN: |
2292 | 0 | BASE_FUN(asinf) |
2293 | 0 | break; |
2294 | 0 | case EVG_OP_COS: |
2295 | 0 | BASE_FUN(cosf) |
2296 | 0 | break; |
2297 | 0 | case EVG_OP_ACOS: |
2298 | 0 | BASE_FUN(acosf) |
2299 | 0 | break; |
2300 | 0 | case EVG_OP_TAN: |
2301 | 0 | BASE_FUN(tanf) |
2302 | 0 | break; |
2303 | 0 | case EVG_OP_ATAN: |
2304 | 0 | BASE_FUN2(atan2f) |
2305 | 0 | break; |
2306 | 0 | case EVG_OP_LOG: |
2307 | 0 | BASE_FUN(logf) |
2308 | 0 | break; |
2309 | 0 | case EVG_OP_EXP: |
2310 | 0 | BASE_FUN(expf) |
2311 | 0 | break; |
2312 | 0 | case EVG_OP_LOG2: |
2313 | 0 | BASE_FUN(log2f) |
2314 | 0 | break; |
2315 | 0 | case EVG_OP_EXP2: |
2316 | 0 | BASE_FUN(exp2f) |
2317 | 0 | break; |
2318 | 0 | case EVG_OP_SINH: |
2319 | 0 | BASE_FUN(sinhf) |
2320 | 0 | break; |
2321 | 0 | case EVG_OP_COSH: |
2322 | 0 | BASE_FUN(coshf) |
2323 | 0 | break; |
2324 | 0 | case EVG_OP_SQRT: |
2325 | 0 | BASE_FUN(sqrtf) |
2326 | 0 | break; |
2327 | 0 | case EVG_OP_INVERSE_SQRT: |
2328 | 0 | BASE_FUN(isqrtf) |
2329 | 0 | break; |
2330 | 0 | case EVG_OP_ABS: |
2331 | 0 | BASE_FUN(ABS) |
2332 | 0 | break; |
2333 | 0 | case EVG_OP_SIGN: |
2334 | 0 | BASE_FUN(signf) |
2335 | 0 | break; |
2336 | 0 | case EVG_OP_FLOOR: |
2337 | 0 | BASE_FUN(floorf) |
2338 | 0 | break; |
2339 | 0 | case EVG_OP_CEIL: |
2340 | 0 | BASE_FUN(ceilf) |
2341 | 0 | break; |
2342 | 0 | case EVG_OP_FRACT: |
2343 | 0 | BASE_FUN(fractf) |
2344 | 0 | break; |
2345 | 0 | case EVG_OP_MOD: |
2346 | 0 | BASE_FUN2(_modf) |
2347 | 0 | break; |
2348 | 0 | case EVG_OP_MIN: |
2349 | 0 | BASE_FUN2(MIN) |
2350 | 0 | break; |
2351 | 0 | case EVG_OP_MAX: |
2352 | 0 | BASE_FUN2(MAX) |
2353 | 0 | break; |
2354 | 0 | case EVG_OP_CLAMP: |
2355 | 0 | if (left_val_type_ptr) { |
2356 | 0 | *left_val_type_ptr = right_val_type; |
2357 | 0 | } |
2358 | 0 | var_idx = op->right_value_second - EVG_FIRST_VAR_ID-1; |
2359 | 0 | right2_val = &vars[var_idx].vecval; |
2360 | | //right2_val_type = vars[var_idx].value_type; |
2361 | 0 | if (right_val_type==COMP_FLOAT) { |
2362 | 0 | left_val->x = evg_float_clamp(left_val->x, right_val->x, right2_val->x); |
2363 | 0 | } else { |
2364 | 0 | if (right_val_type&COMP_X) { |
2365 | 0 | left_val->x = evg_float_clamp(left_val->x, right_val->x, right2_val->x); |
2366 | 0 | } |
2367 | 0 | if (right_val_type&COMP_Y) { |
2368 | 0 | left_val->y = evg_float_clamp(left_val->y, right_val->y, right2_val->x); |
2369 | 0 | } |
2370 | 0 | if (right_val_type&COMP_Z) { |
2371 | 0 | left_val->z = evg_float_clamp(left_val->z, right_val->z, right2_val->x); |
2372 | 0 | } |
2373 | 0 | if (right_val_type&COMP_Q) { |
2374 | 0 | left_val->q = evg_float_clamp(left_val->q, right_val->z, right2_val->x); |
2375 | 0 | } |
2376 | 0 | } |
2377 | 0 | break; |
2378 | 0 | case EVG_OP_RGB2YUV: |
2379 | 0 | if (left_val_type_ptr) { |
2380 | 0 | *left_val_type_ptr = right_val_type; |
2381 | 0 | } |
2382 | 0 | left_val->q = right_val->q; |
2383 | 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); |
2384 | 0 | break; |
2385 | 0 | case EVG_OP_YUV2RGB: |
2386 | 0 | if (left_val_type_ptr) { |
2387 | 0 | *left_val_type_ptr = right_val_type; |
2388 | 0 | } |
2389 | 0 | left_val->q = right_val->q; |
2390 | 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); |
2391 | 0 | break; |
2392 | | |
2393 | 0 | case EVG_OP_PRINT: |
2394 | 0 | if (op->right_value>EVG_FIRST_VAR_ID) { |
2395 | 0 | fprintf(stderr, "%s: ", vars[op->right_value - EVG_FIRST_VAR_ID - 1].name); |
2396 | 0 | } |
2397 | 0 | if (right_val_type==COMP_FLOAT) { |
2398 | 0 | fprintf(stderr, "%g\n", right_val->x); |
2399 | 0 | } else if (right_val_type==COMP_INT) { |
2400 | 0 | fprintf(stderr, "%d\n", * (s32 *) &right_val); |
2401 | 0 | } else { |
2402 | 0 | if (right_val_type&COMP_X) fprintf(stderr, "x=%g ", right_val->x); |
2403 | 0 | if (right_val_type&COMP_Y) fprintf(stderr, "y=%g ", right_val->y); |
2404 | 0 | if (right_val_type&COMP_Z) fprintf(stderr, "z=%g ", right_val->z); |
2405 | 0 | if (right_val_type&COMP_Q) fprintf(stderr, "q=%g ", right_val->q); |
2406 | 0 | fprintf(stderr, "\n"); |
2407 | 0 | } |
2408 | |
|
2409 | 0 | break; |
2410 | 0 | } |
2411 | 0 | } |
2412 | 0 | return frag_valid; |
2413 | 0 | } |
2414 | | |
2415 | | static GF_JSTexture *tx = NULL; |
2416 | | |
2417 | | static Bool evg_frag_shader_ops(void *udta, GF_EVGFragmentParam *frag) |
2418 | 0 | { |
2419 | 0 | GF_JSCanvas *canvas = (GF_JSCanvas *)udta; |
2420 | 0 | return evg_shader_ops(canvas, canvas->frag, frag, NULL, frag->shader_udta); |
2421 | 0 | } |
2422 | | |
2423 | | static Bool evg_frag_shader_ops_init(void *udta, GF_EVGFragmentParam *frag, u32 th_id, Bool is_cleanup) |
2424 | 0 | { |
2425 | 0 | u32 i; |
2426 | 0 | GF_JSCanvas *canvas = (GF_JSCanvas *)udta; |
2427 | 0 | if (!canvas->frag || canvas->frag->invalid) return GF_FALSE; |
2428 | | |
2429 | 0 | if (!th_id) { |
2430 | 0 | for (i=0; i<canvas->frag->nb_ops; i++) { |
2431 | 0 | if (canvas->frag->ops[i].right_value==VAR_VAI) { |
2432 | 0 | if (!vai_call_lerp_init(canvas->frag->ops[i].vai.vai, frag)) |
2433 | 0 | return GF_FALSE; |
2434 | 0 | } |
2435 | 0 | } |
2436 | 0 | frag->shader_udta = canvas->frag->vars; |
2437 | 0 | tx = canvas->frag->ops[1].tx; |
2438 | 0 | return GF_TRUE; |
2439 | 0 | } |
2440 | | |
2441 | 0 | if (is_cleanup) { |
2442 | 0 | if (frag->shader_udta) { |
2443 | 0 | gf_list_add(canvas->frag->vars_stack, frag->shader_udta); |
2444 | 0 | frag->shader_udta = NULL; |
2445 | 0 | } |
2446 | 0 | } else { |
2447 | 0 | ShaderVar *vars = gf_list_pop_back(canvas->frag->vars_stack); |
2448 | 0 | if (!vars) { |
2449 | 0 | vars = gf_malloc(sizeof(ShaderVar) * canvas->frag->nb_vars); |
2450 | 0 | if (!vars) return GF_FALSE; |
2451 | 0 | memcpy(vars, canvas->frag->vars, sizeof(ShaderVar) * canvas->frag->nb_vars); |
2452 | 0 | } |
2453 | 0 | frag->shader_udta = vars; |
2454 | 0 | } |
2455 | | |
2456 | 0 | return GF_TRUE; |
2457 | 0 | } |
2458 | | |
2459 | | static Bool evg_vert_shader_ops(void *udta, GF_EVGVertexParam *vert) |
2460 | 0 | { |
2461 | 0 | GF_JSCanvas *canvas = (GF_JSCanvas *)udta; |
2462 | 0 | if (!canvas->vert || canvas->vert->invalid) return GF_FALSE; |
2463 | 0 | return evg_shader_ops(canvas, canvas->vert, NULL, vert, canvas->vert->vars); |
2464 | 0 | } |
2465 | | |
2466 | | static void shader_reset(JSRuntime *rt, EVGShader *shader) |
2467 | 0 | { |
2468 | 0 | u32 i; |
2469 | 0 | for (i=0; i<shader->nb_ops; i++) { |
2470 | 0 | if (shader->ops[i].right_value==VAR_VAI) { |
2471 | 0 | JS_FreeValueRT(rt, shader->ops[i].vai.ref); |
2472 | 0 | } |
2473 | 0 | else if (shader->ops[i].right_value==VAR_MATRIX) { |
2474 | 0 | JS_FreeValueRT(rt, shader->ops[i].mx.ref); |
2475 | 0 | } |
2476 | 0 | else if (shader->ops[i].right_value==VAR_VA) { |
2477 | 0 | JS_FreeValueRT(rt, shader->ops[i].va.ref); |
2478 | 0 | } |
2479 | 0 | else if (shader->ops[i].left_value==VAR_VAI) { |
2480 | 0 | JS_FreeValueRT(rt, shader->ops[i].vai.ref); |
2481 | 0 | } |
2482 | 0 | else if (shader->ops[i].left_value==VAR_MATRIX) { |
2483 | 0 | JS_FreeValueRT(rt, shader->ops[i].mx.ref); |
2484 | 0 | } |
2485 | |
|
2486 | 0 | if (shader->ops[i].uni_name) { |
2487 | 0 | gf_free(shader->ops[i].uni_name); |
2488 | 0 | shader->ops[i].uni_name = NULL; |
2489 | 0 | } |
2490 | 0 | if ((shader->ops[i].op_type==EVG_OP_SAMPLER) || (shader->ops[i].op_type==EVG_OP_SAMPLER_YUV)) { |
2491 | 0 | JS_FreeValueRT(rt, shader->ops[i].tx_ref); |
2492 | 0 | shader->ops[i].tx_ref = JS_UNDEFINED; |
2493 | 0 | } |
2494 | 0 | shader->ops[i].right_value = 0; |
2495 | 0 | } |
2496 | 0 | shader->nb_ops = 0; |
2497 | 0 | for (i=0; i<shader->nb_vars; i++) { |
2498 | 0 | if ( |
2499 | | #ifdef BUILTIN_SHADERS |
2500 | | !shader->frag_shader && |
2501 | | #endif |
2502 | 0 | shader->vars[i].name |
2503 | 0 | ) { |
2504 | 0 | gf_free(shader->vars[i].name); |
2505 | 0 | } |
2506 | 0 | shader->vars[i].name = NULL; |
2507 | 0 | } |
2508 | 0 | shader->nb_vars = 0; |
2509 | 0 | shader->invalid = GF_FALSE; |
2510 | 0 | shader->disable_early_z = GF_FALSE; |
2511 | 0 | shader->has_branches = GF_FALSE; |
2512 | 0 | } |
2513 | | |
2514 | | static void shader_reset_vars_stack(EVGShader *shader) |
2515 | 0 | { |
2516 | 0 | while (gf_list_count(shader->vars_stack)) { |
2517 | 0 | ShaderVar *vars = gf_list_pop_back(shader->vars_stack); |
2518 | 0 | gf_free(vars); |
2519 | 0 | } |
2520 | 0 | } |
2521 | | static void shader_finalize(JSRuntime *rt, JSValue obj) |
2522 | 0 | { |
2523 | 0 | EVGShader *shader = JS_GetOpaque(obj, shader_class_id); |
2524 | 0 | if (!shader) return; |
2525 | 0 | shader_reset(rt, shader); |
2526 | 0 | gf_free(shader->ops); |
2527 | 0 | gf_free(shader->vars); |
2528 | 0 | shader_reset_vars_stack(shader); |
2529 | 0 | gf_list_del(shader->vars_stack); |
2530 | 0 | gf_free(shader); |
2531 | 0 | } |
2532 | | |
2533 | | static void shader_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func) |
2534 | 0 | { |
2535 | 0 | u32 i; |
2536 | 0 | EVGShader *shader = JS_GetOpaque(obj, shader_class_id); |
2537 | 0 | if (!shader) return; |
2538 | 0 | for (i=0; i<shader->nb_ops; i++) { |
2539 | 0 | if (shader->ops[i].tx) |
2540 | 0 | JS_MarkValue(rt, shader->ops[i].tx_ref, mark_func); |
2541 | |
|
2542 | 0 | if (shader->ops[i].right_value==VAR_VAI) { |
2543 | 0 | JS_MarkValue(rt, shader->ops[i].vai.ref, mark_func); |
2544 | 0 | } |
2545 | 0 | else if (shader->ops[i].right_value==VAR_MATRIX) { |
2546 | 0 | JS_MarkValue(rt, shader->ops[i].mx.ref, mark_func); |
2547 | 0 | } |
2548 | 0 | else if (shader->ops[i].right_value==VAR_VA) { |
2549 | 0 | JS_MarkValue(rt, shader->ops[i].va.ref, mark_func); |
2550 | 0 | } |
2551 | 0 | else if (shader->ops[i].left_value==VAR_VAI) { |
2552 | 0 | JS_MarkValue(rt, shader->ops[i].vai.ref, mark_func); |
2553 | 0 | } |
2554 | 0 | else if (shader->ops[i].left_value==VAR_MATRIX) { |
2555 | 0 | JS_MarkValue(rt, shader->ops[i].mx.ref, mark_func); |
2556 | 0 | } |
2557 | 0 | } |
2558 | 0 | } |
2559 | | |
2560 | | JSClassDef shader_class = { |
2561 | | .class_name = "Shader", |
2562 | | .finalizer = shader_finalize, |
2563 | | .gc_mark = shader_gc_mark |
2564 | | }; |
2565 | | |
2566 | | static u32 get_builtin_var_name(EVGShader *shader, const char *val_name) |
2567 | 0 | { |
2568 | 0 | u32 i; |
2569 | 0 | if (shader->mode==GF_EVG_SHADER_FRAGMENT) { |
2570 | 0 | if (!strcmp(val_name, "fragColor") || !strcmp(val_name, "fragRGBA")) return VAR_FRAG_ARGB; |
2571 | 0 | if (!strcmp(val_name, "fragYUVA")) return VAR_FRAG_YUV; |
2572 | 0 | if (!strcmp(val_name, "fragDepth") || !strcmp(val_name, "fragZ")) return VAR_FRAG_DEPTH; |
2573 | 0 | if (!strcmp(val_name, "fragX")) return VAR_FRAG_X; |
2574 | 0 | if (!strcmp(val_name, "fragY")) return VAR_FRAG_Y; |
2575 | 0 | if (!strcmp(val_name, "fragW")) return VAR_FRAG_W; |
2576 | 0 | if (!strcmp(val_name, "txCoord")) return VAR_FRAG_TX_COORD; |
2577 | 0 | if (!strcmp(val_name, "txCoordi")) return VAR_FRAG_TX_COORDI; |
2578 | 0 | if (!strcmp(val_name, "fragOdd")) return VAR_FRAG_ODD; |
2579 | 0 | } |
2580 | 0 | if (shader->mode==GF_EVG_SHADER_VERTEX) { |
2581 | 0 | if (!strcmp(val_name, "vertex")) return VAR_VERTEX_IN; |
2582 | 0 | if (!strcmp(val_name, "vertexOut")) return VAR_VERTEX_OUT; |
2583 | 0 | } |
2584 | | |
2585 | 0 | if (val_name[0] == '.') return VAR_UNIFORM; |
2586 | | |
2587 | 0 | for (i=0; i<shader->nb_vars; i++) { |
2588 | 0 | if (!strcmp(shader->vars[i].name, val_name)) { |
2589 | 0 | return EVG_FIRST_VAR_ID+i+1; |
2590 | 0 | } |
2591 | 0 | } |
2592 | 0 | return 0; |
2593 | 0 | } |
2594 | | static u8 get_value_type(const char *comp) |
2595 | 0 | { |
2596 | 0 | if (!strcmp(comp, "x") || !strcmp(comp, "r") || !strcmp(comp, "s")) return COMP_X; |
2597 | 0 | if (!strcmp(comp, "y") || !strcmp(comp, "g") || !strcmp(comp, "t")) return COMP_Y; |
2598 | 0 | if (!strcmp(comp, "z") || !strcmp(comp, "b")) return COMP_Z; |
2599 | 0 | if (!strcmp(comp, "q") || !strcmp(comp, "a")) return COMP_Q; |
2600 | 0 | if (!strcmp(comp, "xyz") || !strcmp(comp, "rgb")) return COMP_V3; |
2601 | 0 | if (!strcmp(comp, "xy") || !strcmp(comp, "rg") || !strcmp(comp, "st")) return COMP_V2_XY; |
2602 | 0 | if (!strcmp(comp, "xz") || !strcmp(comp, "rb")) return COMP_V2_XZ; |
2603 | 0 | if (!strcmp(comp, "yz") || !strcmp(comp, "gb")) return COMP_V2_YZ; |
2604 | 0 | return COMP_V4; |
2605 | 0 | } |
2606 | | |
2607 | | #ifdef BUILTIN_SHADERS |
2608 | | static JSValue shader_push_builtin(JSContext *ctx, EVGShader *shader, int argc, JSValueConst *argv) |
2609 | | { |
2610 | | u32 i; |
2611 | | Double dval; |
2612 | | const char *pname; |
2613 | | if (argc<2) return JS_UNDEFINED; |
2614 | | if (!JS_IsString(argv[0])) return GF_JS_EXCEPTION(ctx); |
2615 | | pname = JS_ToCString(ctx, argv[0]); |
2616 | | for (i=0; i<shader->nb_vars; i++) { |
2617 | | ShaderVar *var = &shader->vars[i]; |
2618 | | if (!var->name || strcmp(var->name, pname)) continue; |
2619 | | switch (var->value_type) { |
2620 | | case COMP_INT: |
2621 | | if (JS_ToInt32(ctx, &var->ival, argv[1])) return js_throw_err_msg(ctx, GF_BAD_PARAM, "Bad value specified for %s (int type)", var->name); |
2622 | | break; |
2623 | | case COMP_BOOL: |
2624 | | var->bval = JS_ToBool(ctx, argv[1]); |
2625 | | break; |
2626 | | case COMP_FLOAT: |
2627 | | if (JS_ToFloat64(ctx, &dval, argv[1])) return js_throw_err_msg(ctx, GF_BAD_PARAM, "Bad value specified for %s (float type)", var->name); |
2628 | | var->vecval.x = (Float) dval; |
2629 | | break; |
2630 | | case COMP_TX: |
2631 | | var->ptr = JS_GetOpaque(argv[1], texture_class_id); |
2632 | | if (!var->ptr) return js_throw_err_msg(ctx, GF_BAD_PARAM, "Bad value specified for %s (texture type)", var->name); |
2633 | | break; |
2634 | | } |
2635 | | break; |
2636 | | } |
2637 | | return JS_UNDEFINED; |
2638 | | } |
2639 | | #endif |
2640 | | |
2641 | | static JSValue shader_push(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
2642 | 0 | { |
2643 | 0 | const char *val_name=NULL, *arg_str; |
2644 | 0 | const char *op_name; |
2645 | 0 | char *uni_name=NULL; |
2646 | 0 | Bool dual_right_val = GF_FALSE; |
2647 | 0 | u32 var_idx=0; |
2648 | 0 | u32 left_op_idx=0, right_op_idx=0, right_op2_idx=0; |
2649 | 0 | u8 left_value_type=COMP_V4, right_value_type=COMP_V4; |
2650 | 0 | u8 op_type=0; |
2651 | 0 | u8 cond_type=0; |
2652 | 0 | ShaderOp new_op; |
2653 | 0 | EVGShader *shader = JS_GetOpaque(obj, shader_class_id); |
2654 | 0 | if (!shader) return GF_JS_EXCEPTION(ctx); |
2655 | | |
2656 | | #ifdef BUILTIN_SHADERS |
2657 | | if (shader->frag_shader) |
2658 | | return shader_push_builtin(ctx, shader, argc, argv); |
2659 | | #endif |
2660 | | |
2661 | 0 | shader->invalid = GF_FALSE; |
2662 | 0 | if (!argc) { |
2663 | 0 | shader_reset(JS_GetRuntime(ctx), shader); |
2664 | 0 | return JS_UNDEFINED; |
2665 | 0 | } |
2666 | 0 | if (!shader->nb_ops) { |
2667 | 0 | if (shader->alloc_ops <= 2) { |
2668 | 0 | shader->alloc_ops = 2; |
2669 | 0 | shader->ops = gf_realloc(shader->ops, sizeof(ShaderOp)*shader->alloc_ops); |
2670 | 0 | shader->ops[shader->nb_ops].uni_name = NULL; |
2671 | 0 | } |
2672 | 0 | shader->ops[0].op_type = 0; |
2673 | 0 | shader->ops[1].op_type = 0; |
2674 | 0 | shader->nb_ops = 1; |
2675 | 0 | } |
2676 | |
|
2677 | 0 | memset(&new_op, 0, sizeof(ShaderOp)); |
2678 | 0 | new_op.op_type = 0; |
2679 | 0 | new_op.tx_ref = JS_UNDEFINED; |
2680 | |
|
2681 | 0 | if (JS_IsObject(argv[0])) { |
2682 | 0 | new_op.vai.vai = JS_GetOpaque(argv[0], vai_class_id); |
2683 | 0 | if (!new_op.vai.vai) { |
2684 | 0 | shader->invalid = GF_TRUE; |
2685 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid left-operand value, must be a VAI"); |
2686 | 0 | } |
2687 | 0 | new_op.vai.ref = JS_DupValue(ctx, argv[0]); |
2688 | 0 | left_op_idx = VAR_VAI; |
2689 | 0 | } else { |
2690 | |
|
2691 | 0 | arg_str = JS_ToCString(ctx, argv[0]); |
2692 | 0 | if (!arg_str) { |
2693 | 0 | shader->invalid = GF_TRUE; |
2694 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid left-operand value, must be a string"); |
2695 | 0 | } |
2696 | 0 | val_name = arg_str; |
2697 | 0 | while ((val_name[0]==' ') || (val_name[0]=='\t')) |
2698 | 0 | val_name++; |
2699 | |
|
2700 | 0 | if (!strcmp(val_name, "if")) { |
2701 | 0 | op_type = EVG_OP_IF; |
2702 | 0 | JS_FreeCString(ctx, arg_str); |
2703 | 0 | arg_str = JS_ToCString(ctx, argv[1]); |
2704 | 0 | if (!arg_str) { |
2705 | 0 | shader->invalid = GF_TRUE; |
2706 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid if first var, must be a string"); |
2707 | 0 | } |
2708 | 0 | var_idx=1; |
2709 | 0 | val_name = arg_str; |
2710 | 0 | shader->has_branches = GF_TRUE; |
2711 | 0 | } |
2712 | 0 | else if (!strcmp(val_name, "else")) { |
2713 | 0 | op_type = EVG_OP_ELSE; |
2714 | 0 | shader->has_branches = GF_TRUE; |
2715 | 0 | JS_FreeCString(ctx, arg_str); |
2716 | 0 | goto op_parsed; |
2717 | 0 | } |
2718 | 0 | else if (!strcmp(val_name, "discard")) { |
2719 | 0 | if (shader->mode==GF_EVG_SHADER_VERTEX) { |
2720 | 0 | shader->invalid = GF_TRUE; |
2721 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "discard is invalid in vertex shader"); |
2722 | 0 | } |
2723 | 0 | op_type = EVG_OP_DISCARD; |
2724 | 0 | JS_FreeCString(ctx, arg_str); |
2725 | 0 | goto op_parsed; |
2726 | 0 | } |
2727 | 0 | else if (!strcmp(val_name, "elseif")) { |
2728 | 0 | op_type = EVG_OP_ELSEIF; |
2729 | 0 | shader->has_branches = GF_TRUE; |
2730 | 0 | var_idx=1; |
2731 | 0 | } |
2732 | 0 | else if (!strcmp(val_name, "goto")) { |
2733 | 0 | op_type = EVG_OP_GOTO; |
2734 | 0 | shader->has_branches = GF_TRUE; |
2735 | 0 | JS_FreeCString(ctx, arg_str); |
2736 | |
|
2737 | 0 | if (JS_IsString(argv[1])) { |
2738 | 0 | arg_str = JS_ToCString(ctx, argv[1]); |
2739 | 0 | if (arg_str[0] != '.') { |
2740 | 0 | shader->invalid = GF_TRUE; |
2741 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid goto var, must be a uniform string"); |
2742 | 0 | } |
2743 | 0 | right_op_idx = VAR_UNIFORM; |
2744 | 0 | uni_name = gf_strdup(arg_str+1); |
2745 | 0 | JS_FreeCString(ctx, arg_str); |
2746 | 0 | } else if (JS_ToInt32(ctx, &left_op_idx, argv[1]) ) { |
2747 | 0 | shader->invalid = GF_TRUE; |
2748 | 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"); |
2749 | 0 | } |
2750 | 0 | goto op_parsed; |
2751 | 0 | } |
2752 | 0 | else if (!strcmp(val_name, "end")) { |
2753 | 0 | shader->has_branches = GF_TRUE; |
2754 | 0 | op_type = EVG_OP_END; |
2755 | 0 | JS_FreeCString(ctx, arg_str); |
2756 | 0 | goto op_parsed; |
2757 | 0 | } |
2758 | 0 | else if (!strcmp(val_name, "print")) { |
2759 | 0 | op_type = EVG_OP_PRINT; |
2760 | 0 | JS_FreeCString(ctx, arg_str); |
2761 | 0 | var_idx=-1; |
2762 | 0 | goto parse_right_val; |
2763 | 0 | } |
2764 | 0 | else if (!strcmp(val_name, "toRGB")) { |
2765 | 0 | op_type = EVG_OP_YUV2RGB; |
2766 | 0 | JS_FreeCString(ctx, arg_str); |
2767 | 0 | var_idx=-1; |
2768 | 0 | goto parse_right_val; |
2769 | 0 | } |
2770 | 0 | else if (!strcmp(val_name, "toYUV")) { |
2771 | 0 | op_type = EVG_OP_RGB2YUV; |
2772 | 0 | JS_FreeCString(ctx, arg_str); |
2773 | 0 | var_idx=-1; |
2774 | 0 | goto parse_right_val; |
2775 | 0 | } |
2776 | | |
2777 | 0 | char *sep = strchr(val_name, '.'); |
2778 | 0 | if (sep) sep[0] = 0; |
2779 | 0 | left_op_idx = get_builtin_var_name(shader, val_name); |
2780 | 0 | if (!left_op_idx) { |
2781 | 0 | if (shader->alloc_vars <= shader->nb_vars) { |
2782 | 0 | shader->alloc_vars = shader->nb_vars+1; |
2783 | 0 | shader->vars = gf_realloc(shader->vars, sizeof(ShaderVar)*shader->alloc_vars); |
2784 | 0 | shader_reset_vars_stack(shader); |
2785 | 0 | } |
2786 | 0 | shader->vars[shader->nb_vars].name = gf_strdup(val_name); |
2787 | 0 | shader->nb_vars++; |
2788 | 0 | left_op_idx = EVG_FIRST_VAR_ID + shader->nb_vars; |
2789 | 0 | } |
2790 | 0 | if (sep) { |
2791 | 0 | left_value_type = get_value_type(sep+1); |
2792 | 0 | sep[0] = '.'; |
2793 | 0 | } |
2794 | 0 | JS_FreeCString(ctx, arg_str); |
2795 | 0 | } |
2796 | | |
2797 | 0 | op_name = JS_ToCString(ctx, argv[var_idx+1]); |
2798 | 0 | if (!op_name) { |
2799 | 0 | shader->invalid = GF_TRUE; |
2800 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid operand type, must be a string"); |
2801 | 0 | } |
2802 | 0 | if (!strcmp(op_name, "=")) { |
2803 | 0 | op_type = EVG_OP_ASSIGN; |
2804 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2805 | 0 | shader->disable_early_z = GF_TRUE; |
2806 | 0 | } else if (!strcmp(op_name, "+=")) { |
2807 | 0 | op_type = EVG_OP_ADD; |
2808 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2809 | 0 | shader->disable_early_z = GF_TRUE; |
2810 | 0 | } else if (!strcmp(op_name, "-=")) { |
2811 | 0 | op_type = EVG_OP_SUB; |
2812 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2813 | 0 | shader->disable_early_z = GF_TRUE; |
2814 | 0 | } else if (!strcmp(op_name, "*=")) { |
2815 | 0 | op_type = EVG_OP_MUL; |
2816 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2817 | 0 | shader->disable_early_z = GF_TRUE; |
2818 | 0 | } else if (!strcmp(op_name, "/=")) { |
2819 | 0 | op_type = EVG_OP_DIV; |
2820 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2821 | 0 | shader->disable_early_z = GF_TRUE; |
2822 | 0 | } else if (!strcmp(op_name, "=!")) { |
2823 | 0 | op_type = EVG_OP_NEG; |
2824 | 0 | if (left_op_idx==VAR_FRAG_DEPTH) |
2825 | 0 | shader->disable_early_z = GF_TRUE; |
2826 | 0 | } else if (!strcmp(op_name, "<")) { |
2827 | 0 | cond_type = EVG_OP_LESS; |
2828 | 0 | } else if (!strcmp(op_name, "<=")) { |
2829 | 0 | cond_type = EVG_OP_LESS_EQUAL; |
2830 | 0 | } else if (!strcmp(op_name, ">")) { |
2831 | 0 | cond_type = EVG_OP_GREATER; |
2832 | 0 | } else if (!strcmp(op_name, ">=")) { |
2833 | 0 | cond_type = EVG_OP_GREATER_EQUAL; |
2834 | 0 | } else if (!strcmp(op_name, "==")) { |
2835 | 0 | cond_type = EVG_OP_EQUAL; |
2836 | 0 | } else if (!strcmp(op_name, "!=")) { |
2837 | 0 | cond_type = EVG_OP_NOT_EQUAL; |
2838 | 0 | } else if (!strcmp(op_name, "sampler") || !strcmp(op_name, "samplerYUV") ) { |
2839 | 0 | new_op.tx = JS_GetOpaque(argv[var_idx+2], texture_class_id); |
2840 | 0 | if (!strcmp(op_name, "samplerYUV")) op_type = EVG_OP_SAMPLER_YUV; |
2841 | 0 | else op_type = EVG_OP_SAMPLER; |
2842 | |
|
2843 | 0 | if (!new_op.tx) { |
2844 | 0 | JS_FreeCString(ctx, val_name); |
2845 | 0 | shader->invalid = GF_TRUE; |
2846 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid texture object for 2D sampler"); |
2847 | 0 | } |
2848 | 0 | new_op.tx_ref = argv[var_idx+2]; |
2849 | 0 | var_idx++; |
2850 | 0 | } else if (!strcmp(op_name, "normalize")) { |
2851 | 0 | op_type = EVG_OP_NORMALIZE; |
2852 | 0 | } else if (!strcmp(op_name, "length")) { |
2853 | 0 | op_type = EVG_OP_LENGTH; |
2854 | 0 | } else if (!strcmp(op_name, "distance")) { |
2855 | 0 | op_type = EVG_OP_DISTANCE; |
2856 | 0 | dual_right_val = GF_TRUE; |
2857 | 0 | } else if (!strcmp(op_name, "dot")) { |
2858 | 0 | op_type = EVG_OP_DOT; |
2859 | 0 | dual_right_val = GF_TRUE; |
2860 | 0 | } else if (!strcmp(op_name, "cross")) { |
2861 | 0 | op_type = EVG_OP_CROSS; |
2862 | 0 | dual_right_val = GF_TRUE; |
2863 | 0 | } else if (!strcmp(op_name, "pow")) { |
2864 | 0 | op_type = EVG_OP_POW; |
2865 | 0 | dual_right_val = GF_TRUE; |
2866 | 0 | } else if (!strcmp(op_name, "sin")) { |
2867 | 0 | op_type = EVG_OP_SIN; |
2868 | 0 | } else if (!strcmp(op_name, "asin")) { |
2869 | 0 | op_type = EVG_OP_ASIN; |
2870 | 0 | } else if (!strcmp(op_name, "cos")) { |
2871 | 0 | op_type = EVG_OP_COS; |
2872 | 0 | } else if (!strcmp(op_name, "acos")) { |
2873 | 0 | op_type = EVG_OP_ACOS; |
2874 | 0 | } else if (!strcmp(op_name, "tan")) { |
2875 | 0 | op_type = EVG_OP_TAN; |
2876 | 0 | } else if (!strcmp(op_name, "atan")) { |
2877 | 0 | op_type = EVG_OP_ATAN; |
2878 | 0 | dual_right_val = GF_TRUE; |
2879 | 0 | } else if (!strcmp(op_name, "log")) { |
2880 | 0 | op_type = EVG_OP_LOG; |
2881 | 0 | } else if (!strcmp(op_name, "exp")) { |
2882 | 0 | op_type = EVG_OP_EXP; |
2883 | 0 | } else if (!strcmp(op_name, "log2")) { |
2884 | 0 | op_type = EVG_OP_LOG2; |
2885 | 0 | } else if (!strcmp(op_name, "exp2")) { |
2886 | 0 | op_type = EVG_OP_EXP2; |
2887 | 0 | } else if (!strcmp(op_name, "sinh")) { |
2888 | 0 | op_type = EVG_OP_SINH; |
2889 | 0 | } else if (!strcmp(op_name, "cosh")) { |
2890 | 0 | op_type = EVG_OP_COSH; |
2891 | 0 | } else if (!strcmp(op_name, "sqrt")) { |
2892 | 0 | op_type = EVG_OP_SQRT; |
2893 | 0 | } else if (!strcmp(op_name, "inversesqrt")) { |
2894 | 0 | op_type = EVG_OP_INVERSE_SQRT; |
2895 | 0 | } else if (!strcmp(op_name, "abs")) { |
2896 | 0 | op_type = EVG_OP_ABS; |
2897 | 0 | } else if (!strcmp(op_name, "sign")) { |
2898 | 0 | op_type = EVG_OP_SIGN; |
2899 | 0 | } else if (!strcmp(op_name, "floor")) { |
2900 | 0 | op_type = EVG_OP_FLOOR; |
2901 | 0 | } else if (!strcmp(op_name, "ceil")) { |
2902 | 0 | op_type = EVG_OP_CEIL; |
2903 | 0 | } else if (!strcmp(op_name, "fract")) { |
2904 | 0 | op_type = EVG_OP_FRACT; |
2905 | 0 | } else if (!strcmp(op_name, "mod")) { |
2906 | 0 | op_type = EVG_OP_MOD; |
2907 | 0 | dual_right_val = GF_TRUE; |
2908 | 0 | } else if (!strcmp(op_name, "min")) { |
2909 | 0 | op_type = EVG_OP_MIN; |
2910 | 0 | dual_right_val = GF_TRUE; |
2911 | 0 | } else if (!strcmp(op_name, "max")) { |
2912 | 0 | op_type = EVG_OP_MAX; |
2913 | 0 | dual_right_val = GF_TRUE; |
2914 | 0 | } else if (!strcmp(op_name, "clamp")) { |
2915 | 0 | op_type = EVG_OP_CLAMP; |
2916 | 0 | dual_right_val = GF_TRUE; |
2917 | 0 | } else { |
2918 | 0 | JS_FreeCString(ctx, op_name); |
2919 | 0 | shader->invalid = GF_TRUE; |
2920 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid operand type, must be a string"); |
2921 | 0 | } |
2922 | 0 | JS_FreeCString(ctx, op_name); |
2923 | |
|
2924 | 0 | parse_right_val: |
2925 | 0 | if (JS_IsString(argv[var_idx+2])) { |
2926 | 0 | val_name = JS_ToCString(ctx, argv[var_idx+2]); |
2927 | 0 | if (!val_name) { |
2928 | 0 | shader->invalid = GF_TRUE; |
2929 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid right-operand value, must be a string"); |
2930 | 0 | } |
2931 | | |
2932 | 0 | char *sep = strchr(val_name+1, '.'); |
2933 | 0 | if (sep) sep[0] = 0; |
2934 | 0 | right_op_idx = get_builtin_var_name(shader, val_name); |
2935 | 0 | if (right_op_idx==VAR_UNIFORM) { |
2936 | 0 | uni_name = gf_strdup(val_name+1); |
2937 | 0 | } |
2938 | 0 | if (sep) sep[0] = '.'; |
2939 | |
|
2940 | 0 | if (!right_op_idx) { |
2941 | 0 | JSValue ret = js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid right-operand value, undefined variable %s", val_name); |
2942 | 0 | JS_FreeCString(ctx, val_name); |
2943 | 0 | shader->invalid = GF_TRUE; |
2944 | 0 | if (uni_name) gf_free(uni_name); |
2945 | 0 | return ret; |
2946 | 0 | } |
2947 | 0 | if (sep) { |
2948 | 0 | right_value_type = get_value_type(sep+1); |
2949 | 0 | } |
2950 | 0 | JS_FreeCString(ctx, val_name); |
2951 | 0 | } |
2952 | 0 | else if (JS_IsArray(ctx, argv[var_idx+2])) { |
2953 | 0 | u32 idx, length; |
2954 | 0 | JSValue comp = JS_GetPropertyStr(ctx, argv[var_idx+2], "length"); |
2955 | 0 | if (JS_ToInt32(ctx, &length, comp)) return GF_JS_EXCEPTION(ctx); |
2956 | 0 | JS_FreeValue(ctx, comp); |
2957 | 0 | if (length>4) length=4; |
2958 | 0 | right_value_type = 0; |
2959 | 0 | for (idx=0;idx<length; idx++) { |
2960 | 0 | comp = JS_GetPropertyUint32(ctx, argv[var_idx+2], idx); |
2961 | 0 | EVG_GET_FLOAT(new_op.vec[idx], comp); |
2962 | 0 | right_value_type |= 1<<idx; |
2963 | 0 | JS_FreeValue(ctx, comp); |
2964 | 0 | } |
2965 | 0 | } |
2966 | 0 | else if (JS_IsObject(argv[var_idx+2])) { |
2967 | 0 | EVG_VAI *vai = JS_GetOpaque(argv[var_idx+2], vai_class_id); |
2968 | 0 | GF_Matrix *mx = JS_GetOpaque(argv[var_idx+2], matrix_class_id); |
2969 | 0 | EVG_VA *va = (shader->mode==GF_EVG_SHADER_VERTEX) ? JS_GetOpaque(argv[var_idx+2], va_class_id) : NULL; |
2970 | |
|
2971 | 0 | if (vai) { |
2972 | 0 | new_op.vai.vai = vai; |
2973 | 0 | new_op.vai.ref = JS_DupValue(ctx, argv[var_idx+2]); |
2974 | 0 | right_op_idx = VAR_VAI; |
2975 | 0 | } else if (mx) { |
2976 | 0 | new_op.mx.mx = mx; |
2977 | 0 | new_op.mx.ref = JS_DupValue(ctx, argv[var_idx+2]); |
2978 | 0 | right_op_idx = VAR_MATRIX; |
2979 | 0 | } else if (va) { |
2980 | 0 | new_op.va.va = va; |
2981 | 0 | new_op.va.ref = JS_DupValue(ctx, argv[var_idx+2]); |
2982 | 0 | right_op_idx = VAR_VA; |
2983 | 0 | } else { |
2984 | 0 | shader->invalid = GF_TRUE; |
2985 | 0 | if (uni_name) gf_free(uni_name); |
2986 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "unknown object type for right operand"); |
2987 | 0 | } |
2988 | 0 | } |
2989 | 0 | else if (JS_IsBool(argv[var_idx+2])) { |
2990 | 0 | new_op.bval = JS_ToBool(ctx, argv[var_idx+2]) ? GF_TRUE : GF_FALSE; |
2991 | 0 | right_value_type = COMP_BOOL; |
2992 | 0 | } |
2993 | 0 | else if (JS_IsNumber(argv[var_idx+2])) { |
2994 | 0 | if (JS_IsInteger(argv[var_idx+2])) { |
2995 | 0 | JS_ToInt32(ctx, &new_op.ival, argv[var_idx+2]); |
2996 | 0 | right_value_type = COMP_INT; |
2997 | 0 | } else { |
2998 | 0 | Double v; |
2999 | 0 | JS_ToFloat64(ctx, &v, argv[var_idx+2]); |
3000 | 0 | new_op.vec[0] = (Float) v; |
3001 | 0 | right_value_type = COMP_FLOAT; |
3002 | 0 | } |
3003 | 0 | } |
3004 | | |
3005 | 0 | if (dual_right_val) { |
3006 | 0 | Bool is_ok=GF_FALSE; |
3007 | 0 | if ((u32) argc<=var_idx+3) {} |
3008 | 0 | else { |
3009 | 0 | val_name = JS_ToCString(ctx, argv[var_idx+3]); |
3010 | 0 | if (val_name) { |
3011 | 0 | right_op2_idx = get_builtin_var_name(shader, val_name); |
3012 | 0 | if (right_op2_idx >= EVG_FIRST_VAR_ID) { |
3013 | 0 | is_ok=GF_TRUE; |
3014 | 0 | } |
3015 | 0 | } |
3016 | 0 | JS_FreeCString(ctx, val_name); |
3017 | 0 | } |
3018 | 0 | if (!is_ok) { |
3019 | 0 | JSValue ret = js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid second right-operand value, only local variable allowed"); |
3020 | 0 | JS_FreeCString(ctx, val_name); |
3021 | 0 | shader->invalid = GF_TRUE; |
3022 | 0 | if (uni_name) gf_free(uni_name); |
3023 | 0 | return ret; |
3024 | 0 | } |
3025 | 0 | } |
3026 | | |
3027 | 0 | op_parsed: |
3028 | |
|
3029 | 0 | if (dual_right_val && !right_op2_idx) { |
3030 | 0 | shader->invalid = GF_TRUE; |
3031 | 0 | if (uni_name) gf_free(uni_name); |
3032 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "invalid second right-operand value, only local variable allowed"); |
3033 | 0 | } |
3034 | 0 | new_op.op_type = op_type; |
3035 | 0 | if (!new_op.op_type) { |
3036 | 0 | shader->invalid = GF_TRUE; |
3037 | 0 | if (uni_name) gf_free(uni_name); |
3038 | 0 | return js_throw_err_msg(ctx, GF_BAD_PARAM, "unknown operation type"); |
3039 | 0 | } |
3040 | 0 | new_op.cond_type = cond_type; |
3041 | 0 | new_op.left_value = left_op_idx; |
3042 | 0 | new_op.right_value = right_op_idx; |
3043 | 0 | new_op.left_value_type = left_value_type; |
3044 | 0 | new_op.right_value_type = right_value_type; |
3045 | 0 | new_op.right_value_second = right_op2_idx; |
3046 | 0 | if (new_op.tx) { |
3047 | 0 | new_op.tx_ref = JS_DupValue(ctx, new_op.tx_ref); |
3048 | 0 | } |
3049 | |
|
3050 | 0 | if (shader->alloc_ops <= shader->nb_ops+1) { |
3051 | 0 | shader->alloc_ops = shader->nb_ops+2; |
3052 | 0 | shader->ops = gf_realloc(shader->ops, sizeof(ShaderOp)*shader->alloc_ops); |
3053 | 0 | shader->ops[shader->nb_ops].uni_name = NULL; |
3054 | 0 | } |
3055 | 0 | if (shader->ops[shader->nb_ops].uni_name) { |
3056 | 0 | gf_free(shader->ops[shader->nb_ops].uni_name); |
3057 | 0 | shader->ops[shader->nb_ops].uni_name = NULL; |
3058 | 0 | } |
3059 | |
|
3060 | 0 | shader->ops[shader->nb_ops] = new_op; |
3061 | 0 | shader->ops[shader->nb_ops].uni_name = uni_name; |
3062 | 0 | shader->nb_ops++; |
3063 | 0 | shader->ops[shader->nb_ops].op_type = 0; |
3064 | | //return 1-based index of op, excluding first dummy op (we hide it) |
3065 | 0 | return JS_NewInt32(ctx, shader->nb_ops-1); |
3066 | 0 | } |
3067 | | |
3068 | | static JSValue shader_update(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
3069 | 0 | { |
3070 | 0 | u32 i; |
3071 | 0 | EVGShader *shader = JS_GetOpaque(obj, shader_class_id); |
3072 | 0 | if (!shader) return GF_JS_EXCEPTION(ctx); |
3073 | 0 | if (shader->invalid) return GF_JS_EXCEPTION(ctx); |
3074 | | |
3075 | 0 | for (i=0; i<shader->nb_ops; i++) { |
3076 | 0 | JSValue v; |
3077 | 0 | ShaderOp *op = &shader->ops[i]; |
3078 | 0 | if (!op->uni_name) continue; |
3079 | 0 | v = JS_GetPropertyStr(ctx, obj, op->uni_name); |
3080 | 0 | if (JS_IsUndefined(v)) return js_throw_err_msg(ctx, GF_BAD_PARAM, "uniform %s cannot be found in shader", op->uni_name); |
3081 | 0 | if (JS_IsBool(v)) { |
3082 | 0 | op->right_value_type = COMP_BOOL; |
3083 | 0 | op->bval = JS_ToBool(ctx, v) ? GF_TRUE : GF_FALSE; |
3084 | 0 | } |
3085 | 0 | else if (JS_IsNumber(v)) { |
3086 | 0 | if (JS_IsInteger(v)) { |
3087 | 0 | op->right_value_type = COMP_INT; |
3088 | 0 | if (JS_ToInt32(ctx, &op->ival, v)) return GF_JS_EXCEPTION(ctx); |
3089 | 0 | } else { |
3090 | 0 | op->right_value_type = COMP_FLOAT; |
3091 | 0 | EVG_GET_FLOAT(op->vec[0], v) |
3092 | 0 | } |
3093 | 0 | } |
3094 | 0 | else if (JS_IsArray(ctx, v)) { |
3095 | 0 | u32 idx, length; |
3096 | 0 | JSValue comp = JS_GetPropertyStr(ctx, v, "length"); |
3097 | 0 | if (JS_ToInt32(ctx, &length, comp)) return GF_JS_EXCEPTION(ctx); |
3098 | 0 | JS_FreeValue(ctx, comp); |
3099 | 0 | if (length>4) length=4; |
3100 | 0 | op->right_value_type = 0; |
3101 | 0 | for (idx=0;idx<length; idx++) { |
3102 | 0 | comp = JS_GetPropertyUint32(ctx, v, idx); |
3103 | 0 | EVG_GET_FLOAT(op->vec[idx], comp); |
3104 | 0 | op->right_value_type |= 1<<idx; |
3105 | 0 | JS_FreeValue(ctx, comp); |
3106 | 0 | } |
3107 | 0 | } |
3108 | 0 | else if (JS_IsObject(v)) { |
3109 | 0 | u32 data_size; |
3110 | 0 | Float *vals; |
3111 | 0 | u32 idx; |
3112 | 0 | u8 *data = evg_get_array(ctx, v, &data_size); |
3113 | 0 | if (data) { |
3114 | 0 | if (data_size%4) return GF_JS_EXCEPTION(ctx); |
3115 | 0 | vals = (Float*)data; |
3116 | 0 | data_size/= sizeof(Float); |
3117 | 0 | if (data_size>4) data_size=4; |
3118 | 0 | op->right_value_type = 0; |
3119 | 0 | for (idx=0;idx<data_size; idx++) { |
3120 | 0 | op->vec[idx] = vals[idx]; |
3121 | 0 | op->right_value_type |= 1<<idx; |
3122 | 0 | } |
3123 | 0 | } else { |
3124 | 0 | JSValue comp; |
3125 | 0 | op->right_value_type = 0; |
3126 | 0 | #define GET_COMP(_name, _idx, _mask)\ |
3127 | 0 | comp = JS_GetPropertyStr(ctx, v, _name);\ |
3128 | 0 | if (!JS_IsUndefined(comp)) { EVG_GET_FLOAT(op->vec[_idx], comp); op->right_value_type |= _mask; }\ |
3129 | 0 | JS_FreeValue(ctx, comp);\ |
3130 | 0 |
|
3131 | 0 | GET_COMP("x", 0, COMP_X); |
3132 | 0 | GET_COMP("r", 0, COMP_X); |
3133 | 0 | GET_COMP("s", 0, COMP_X); |
3134 | |
|
3135 | 0 | GET_COMP("y", 1, COMP_Y); |
3136 | 0 | GET_COMP("g", 1, COMP_Y); |
3137 | 0 | GET_COMP("t", 1, COMP_Y); |
3138 | |
|
3139 | 0 | GET_COMP("z", 2, COMP_Z); |
3140 | 0 | GET_COMP("b", 2, COMP_Z); |
3141 | |
|
3142 | 0 | GET_COMP("q", 3, COMP_Q); |
3143 | 0 | GET_COMP("w", 3, COMP_Q); |
3144 | 0 | GET_COMP("a", 3, COMP_Q); |
3145 | |
|
3146 | 0 | } |
3147 | 0 | } |
3148 | 0 | JS_FreeValue(ctx, v); |
3149 | |
|
3150 | 0 | } |
3151 | 0 | return JS_UNDEFINED; |
3152 | 0 | } |
3153 | | |
3154 | | static const JSCFunctionListEntry shader_funcs[] = |
3155 | | { |
3156 | | JS_CFUNC_DEF("push", 0, shader_push), |
3157 | | JS_CFUNC_DEF("update", 0, shader_update), |
3158 | | }; |
3159 | | |
3160 | | //test code |
3161 | | #ifdef BUILTIN_SHADERS |
3162 | | Bool rvideo_shader(void *udta, GF_EVGFragmentParam *frag) |
3163 | | { |
3164 | | EVGShader *shader = udta; |
3165 | | GF_JSTexture *tx = shader->vars[0].ptr; |
3166 | | |
3167 | | u32 col = gf_evg_stencil_get_pixel_yuv(tx->stencil, frag->tx_x * tx->width / frag->tx_width, frag->tx_y * tx->height / frag->tx_height); |
3168 | | if (shader->vars[1].ival) { |
3169 | | if (frag->odd_flag) { |
3170 | | u8 a, r, g, b; |
3171 | | a = GF_COL_A(col); |
3172 | | r = 0xFF - GF_COL_R(col); |
3173 | | g = 0xFF - GF_COL_G(col); |
3174 | | b = 0xFF - GF_COL_B(col); |
3175 | | col = GF_COL_ARGB(a, r, g, b); |
3176 | | } |
3177 | | } |
3178 | | frag->color_pack = col; |
3179 | | frag->frag_valid = GF_EVG_FRAG_YUV_PACK; |
3180 | | return GF_TRUE; |
3181 | | } |
3182 | | Bool builtin_shader_check(void *udta, GF_EVGFragmentParam *frag, u32 th_id, Bool is_cleanup) |
3183 | | { |
3184 | | u32 i; |
3185 | | EVGShader *shader; |
3186 | | if (is_cleanup) return GF_TRUE; |
3187 | | shader = udta; |
3188 | | for (i=0; i<shader->nb_vars; i++) { |
3189 | | if ((shader->vars[i].value_type == COMP_TX) && !shader->vars[i].ptr) |
3190 | | return GF_FALSE; |
3191 | | } |
3192 | | return GF_TRUE; |
3193 | | } |
3194 | | |
3195 | | EVGShader *load_builtin_shader(const char *sname, GF_Err *e) |
3196 | | { |
3197 | | EVGShader *shader; |
3198 | | if (!strcmp(sname, "rvideo")) { |
3199 | | GF_SAFEALLOC(shader, EVGShader); |
3200 | | if (!shader) { *e = GF_OUT_OF_MEM; return NULL;} |
3201 | | |
3202 | | shader->nb_vars = 4; |
3203 | | shader->vars = gf_malloc(sizeof(ShaderVar)*shader->nb_vars); |
3204 | | if (!shader->vars) { *e = GF_OUT_OF_MEM; gf_free(shader); return NULL;} |
3205 | | shader->vars[0].name = "tx"; |
3206 | | shader->vars[0].value_type = COMP_TX; |
3207 | | shader->vars[1].name = "odd"; |
3208 | | shader->vars[1].value_type = COMP_INT; |
3209 | | shader->frag_shader = rvideo_shader; |
3210 | | shader->frag_shader_init = builtin_shader_check; |
3211 | | return shader; |
3212 | | } |
3213 | | return NULL; |
3214 | | } |
3215 | | #endif |
3216 | | |
3217 | | static JSValue canvas_new_shader(JSContext *ctx, JSValueConst obj, int argc, JSValueConst *argv) |
3218 | 0 | { |
3219 | 0 | EVGShader *shader; |
3220 | 0 | u32 mode; |
3221 | 0 | JSValue res; |
3222 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(obj, canvas_class_id); |
3223 | 0 | if (!canvas) return GF_JS_EXCEPTION(ctx); |
3224 | 0 | if (!argc) return GF_JS_EXCEPTION(ctx); |
3225 | | |
3226 | | #ifdef BUILTIN_SHADERS |
3227 | | if (JS_IsString(argv[0])) { |
3228 | | GF_Err e = GF_OK; |
3229 | | const char *sname = JS_ToCString(ctx, argv[0]); |
3230 | | shader = load_builtin_shader(sname, &e); |
3231 | | if (!shader) { |
3232 | | res = js_throw_err_msg(ctx, GF_BAD_PARAM, "Error loading native shader %s: %s", sname, gf_error_to_string(e) ); |
3233 | | JS_FreeCString(ctx, sname); |
3234 | | return res; |
3235 | | } |
3236 | | JS_FreeCString(ctx, sname); |
3237 | | shader->mode = GF_EVG_SHADER_FRAGMENT; |
3238 | | |
3239 | | res = JS_NewObjectClass(ctx, shader_class_id); |
3240 | | JS_SetOpaque(res, shader); |
3241 | | return res; |
3242 | | } |
3243 | | #endif |
3244 | | |
3245 | 0 | if (JS_ToInt32(ctx, &mode, argv[0])) |
3246 | 0 | return GF_JS_EXCEPTION(ctx); |
3247 | | |
3248 | 0 | if ((mode != GF_EVG_SHADER_FRAGMENT) && (mode != GF_EVG_SHADER_VERTEX)) |
3249 | 0 | return GF_JS_EXCEPTION(ctx); |
3250 | 0 | GF_SAFEALLOC(shader, EVGShader); |
3251 | 0 | if (!shader) { |
3252 | 0 | return js_throw_err(ctx, GF_OUT_OF_MEM); |
3253 | 0 | } |
3254 | 0 | shader->mode = mode; |
3255 | 0 | shader->vars_stack = gf_list_new(); |
3256 | |
|
3257 | 0 | res = JS_NewObjectClass(ctx, shader_class_id); |
3258 | 0 | JS_SetOpaque(res, shader); |
3259 | 0 | return res; |
3260 | 0 | } |
3261 | | |
3262 | | |
3263 | | static const JSCFunctionListEntry canvas_funcs[] = |
3264 | | { |
3265 | | JS_CGETSET_MAGIC_DEF("centered", canvas_getProperty, canvas_setProperty, GF_EVG_CENTERED), |
3266 | | JS_CGETSET_MAGIC_DEF("path", NULL, canvas_setProperty, GF_EVG_PATH), |
3267 | | JS_CGETSET_MAGIC_DEF("clipper", NULL, canvas_setProperty, GF_EVG_CLIPPER), |
3268 | | JS_CGETSET_MAGIC_DEF("has_clipper", canvas_getProperty, NULL, GF_EVG_CLIPPER), |
3269 | | JS_CGETSET_MAGIC_DEF("matrix", NULL, canvas_setProperty, GF_EVG_MATRIX), |
3270 | | JS_CGETSET_MAGIC_DEF("matrix3d", NULL, canvas_setProperty, GF_EVG_MATRIX_3D), |
3271 | | JS_CGETSET_MAGIC_DEF("compositeOperation", canvas_getProperty, canvas_setProperty, GF_EVG_COMPOSITE_OP), |
3272 | | JS_CGETSET_MAGIC_DEF("level", canvas_getProperty, canvas_setProperty, GF_EVG_RASTER_LEVEL), |
3273 | | JS_CGETSET_MAGIC_DEF("on_alpha", canvas_getProperty, canvas_setProperty, GF_EVG_ALPHA_FUN), |
3274 | | JS_CGETSET_MAGIC_DEF("is_yuv", canvas_getProperty, NULL, GF_EVG_IS_YUV), |
3275 | | JS_CGETSET_MAGIC_DEF("depth", canvas_getProperty, NULL, GF_EVG_BIT_DEPTH), |
3276 | | JS_CGETSET_MAGIC_DEF("mask_mode", canvas_getProperty, canvas_setProperty, GF_EVG_MASK_MODE), |
3277 | | JS_CFUNC_DEF("enable_threading", 0, canvas_enable_threading), |
3278 | | JS_CFUNC_DEF("enable_3d", 0, canvas_enable_3d), |
3279 | | JS_CFUNC_DEF("clear", 0, canvas_clear), |
3280 | | JS_CFUNC_DEF("clearf", 0, canvas_clearf), |
3281 | | JS_CFUNC_DEF("fill", 0, canvas_fill), |
3282 | | JS_CFUNC_DEF("reassign", 0, canvas_reassign), |
3283 | | JS_CFUNC_DEF("toYUV", 0, canvas_toYUV), |
3284 | | JS_CFUNC_DEF("toRGB", 0, canvas_toRGB), |
3285 | | JS_CFUNC_DEF("blit", 0, canvas_blit), |
3286 | | |
3287 | | //3D extensions |
3288 | | JS_CGETSET_MAGIC_DEF("fragment", canvas_getProperty, canvas_setProperty, GF_EVG_FRAG_SHADER), |
3289 | | JS_CGETSET_MAGIC_DEF("vertex", canvas_getProperty, canvas_setProperty, GF_EVG_VERT_SHADER), |
3290 | | JS_CGETSET_MAGIC_DEF("ccw", NULL, canvas_setProperty, GF_EVG_CCW), |
3291 | | JS_CGETSET_MAGIC_DEF("backcull", NULL, canvas_setProperty, GF_EVG_BACKCULL), |
3292 | | JS_CGETSET_MAGIC_DEF("antialias", NULL, canvas_setProperty, GF_EVG_ANTIALIAS), |
3293 | | JS_CGETSET_MAGIC_DEF("min_depth", NULL, canvas_setProperty, GF_EVG_MINDEPTH), |
3294 | | JS_CGETSET_MAGIC_DEF("max_depth", NULL, canvas_setProperty, GF_EVG_MAXDEPTH), |
3295 | | JS_CGETSET_MAGIC_DEF("point_size", NULL, canvas_setProperty, GF_EVG_POINTSIZE), |
3296 | | JS_CGETSET_MAGIC_DEF("point_smooth", NULL, canvas_setProperty, GF_EVG_POINTSMOOTH), |
3297 | | JS_CGETSET_MAGIC_DEF("line_size", NULL, canvas_setProperty, GF_EVG_LINESIZE), |
3298 | | JS_CGETSET_MAGIC_DEF("clip_zero", NULL, canvas_setProperty, GF_EVG_CLIP_ZERO), |
3299 | | JS_CGETSET_MAGIC_DEF("depth_test", NULL, canvas_setProperty, GF_EVG_DEPTH_TEST), |
3300 | | JS_CGETSET_MAGIC_DEF("write_depth", NULL, canvas_setProperty, GF_EVG_WRITE_DEPTH), |
3301 | | JS_CGETSET_MAGIC_DEF("depth_buffer", canvas_getProperty, canvas_setProperty, GF_EVG_DEPTH_BUFFER), |
3302 | | |
3303 | | JS_CFUNC_DEF("projection", 0, canvas_projection), |
3304 | | JS_CFUNC_DEF("modelview", 0, canvas_modelview), |
3305 | | JS_CFUNC_DEF("draw_array", 0, canvas_draw_array), |
3306 | | JS_CFUNC_DEF("draw_path", 0, canvas_draw_path), |
3307 | | JS_CFUNC_DEF("clear_depth", 0, canvas_clear_depth), |
3308 | | JS_CFUNC_DEF("viewport", 0, canvas_viewport), |
3309 | | JS_CFUNC_DEF("new_shader", 0, canvas_new_shader), |
3310 | | }; |
3311 | | |
3312 | | #ifdef EVG_USE_JS_SHADER |
3313 | | |
3314 | | JSClassDef fragment_class = { |
3315 | | .class_name = "Fragment", |
3316 | | }; |
3317 | | |
3318 | | enum { |
3319 | | EVG_FRAG_SCREENX, |
3320 | | EVG_FRAG_SCREENY, |
3321 | | EVG_FRAG_DEPTH, |
3322 | | EVG_FRAG_R, |
3323 | | EVG_FRAG_G, |
3324 | | EVG_FRAG_B, |
3325 | | EVG_FRAG_A, |
3326 | | EVG_FRAG_Y, |
3327 | | EVG_FRAG_U, |
3328 | | EVG_FRAG_V, |
3329 | | EVG_FRAG_RGBA, |
3330 | | EVG_FRAG_RGB, |
3331 | | EVG_FRAG_YUV, |
3332 | | EVG_FRAG_YUVA, |
3333 | | }; |
3334 | | |
3335 | | static JSValue fragment_getProperty(JSContext *c, JSValueConst obj, int magic) |
3336 | | { |
3337 | | GF_EVGFragmentParam *frag = JS_GetOpaque(obj, fragment_class_id); |
3338 | | if (!frag) return GF_JS_EXCEPTION(c); |
3339 | | switch (magic) { |
3340 | | case EVG_FRAG_SCREENX: return JS_NewFloat64(c, frag->screen_x); |
3341 | | case EVG_FRAG_SCREENY: return JS_NewFloat64(c, frag->screen_y); |
3342 | | case EVG_FRAG_DEPTH: return JS_NewFloat64(c, frag->depth); |
3343 | | } |
3344 | | return JS_UNDEFINED; |
3345 | | } |
3346 | | static JSValue fragment_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic) |
3347 | | { |
3348 | | EVG_VAIRes *vr; |
3349 | | GF_EVGFragmentType frag_type = GF_EVG_FRAG_RGB; |
3350 | | |
3351 | | GF_EVGFragmentParam *frag = JS_GetOpaque(obj, fragment_class_id); |
3352 | | if (!frag) return GF_JS_EXCEPTION(c); |
3353 | | switch (magic) { |
3354 | | case EVG_FRAG_DEPTH: |
3355 | | EVG_GET_FLOAT(frag->depth, value) |
3356 | | break; |
3357 | | case EVG_FRAG_Y: |
3358 | | frag_type = GF_EVG_FRAG_YUV; |
3359 | | case EVG_FRAG_R: |
3360 | | EVG_GET_FLOAT(frag->color.x, value) |
3361 | | CLAMPCOLF(frag->color.x) |
3362 | | frag->frag_valid = frag_type; |
3363 | | break; |
3364 | | case EVG_FRAG_U: |
3365 | | frag_type = GF_EVG_FRAG_YUV; |
3366 | | case EVG_FRAG_G: |
3367 | | EVG_GET_FLOAT(frag->color.y, value) |
3368 | | CLAMPCOLF(frag->color.y) |
3369 | | frag->frag_valid = frag_type; |
3370 | | break; |
3371 | | case EVG_FRAG_V: |
3372 | | frag_type = GF_EVG_FRAG_YUV; |
3373 | | case EVG_FRAG_B: |
3374 | | EVG_GET_FLOAT(frag->color.z, value) |
3375 | | CLAMPCOLF(frag->color.z) |
3376 | | frag->frag_valid = frag_type; |
3377 | | break; |
3378 | | case EVG_FRAG_A: |
3379 | | EVG_GET_FLOAT(frag->color.q, value) |
3380 | | CLAMPCOLF(frag->color.q) |
3381 | | if (!frag->frag_valid) |
3382 | | frag->frag_valid = GF_EVG_FRAG_RGB; |
3383 | | break; |
3384 | | case EVG_FRAG_YUVA: |
3385 | | frag_type = GF_EVG_FRAG_YUV; |
3386 | | case EVG_FRAG_RGBA: |
3387 | | vr = JS_GetOpaque(value, vaires_class_id); |
3388 | | if (vr) { |
3389 | | frag->color.x = vr->values[0]; |
3390 | | frag->color.y = vr->values[1]; |
3391 | | frag->color.z = vr->values[2]; |
3392 | | frag->color.q = vr->values[3]; |
3393 | | frag->frag_valid = frag_type; |
3394 | | } else { |
3395 | | Double a, r, g, b; |
3396 | | a=1.0; |
3397 | | if (!get_color_from_args(ctx, 1, &value, 0, &a, &r, &g, &b)) |
3398 | | return GF_JS_EXCEPTION(c); |
3399 | | frag->color.q = (Float) a; |
3400 | | frag->color.x = (Float) r; |
3401 | | frag->color.y = (Float) g; |
3402 | | frag->color.z = (Float) b; |
3403 | | frag->frag_valid = GF_EVG_FRAG_RGB; |
3404 | | } |
3405 | | break; |
3406 | | case EVG_FRAG_YUV: |
3407 | | frag_type = GF_EVG_FRAG_YUV; |
3408 | | case EVG_FRAG_RGB: |
3409 | | vr = JS_GetOpaque(value, vaires_class_id); |
3410 | | if (vr) { |
3411 | | frag->color.x = vr->values[0]; |
3412 | | frag->color.y = vr->values[1]; |
3413 | | frag->color.z = vr->values[2]; |
3414 | | frag->frag_valid = frag_type; |
3415 | | } else |
3416 | | return GF_JS_EXCEPTION(c); |
3417 | | default: |
3418 | | return JS_UNDEFINED; |
3419 | | } |
3420 | | return JS_UNDEFINED; |
3421 | | } |
3422 | | |
3423 | | static const JSCFunctionListEntry fragment_funcs[] = |
3424 | | { |
3425 | | JS_CGETSET_MAGIC_DEF("x", fragment_getProperty, NULL, EVG_FRAG_SCREENX), |
3426 | | JS_CGETSET_MAGIC_DEF("y", fragment_getProperty, NULL, EVG_FRAG_SCREENY), |
3427 | | JS_CGETSET_MAGIC_DEF("z", fragment_getProperty, fragment_setProperty, EVG_FRAG_DEPTH), |
3428 | | JS_ALIAS_DEF("depth", "z"), |
3429 | | JS_CGETSET_MAGIC_DEF("r", NULL, fragment_setProperty, EVG_FRAG_R), |
3430 | | JS_CGETSET_MAGIC_DEF("g", NULL, fragment_setProperty, EVG_FRAG_G), |
3431 | | JS_CGETSET_MAGIC_DEF("b", NULL, fragment_setProperty, EVG_FRAG_B), |
3432 | | JS_CGETSET_MAGIC_DEF("a", NULL, fragment_setProperty, EVG_FRAG_A), |
3433 | | JS_ALIAS_DEF("Y", "r"), |
3434 | | JS_ALIAS_DEF("U", "g"), |
3435 | | JS_ALIAS_DEF("V", "b"), |
3436 | | JS_CGETSET_MAGIC_DEF("rgba", NULL, fragment_setProperty, EVG_FRAG_RGBA), |
3437 | | JS_CGETSET_MAGIC_DEF("rgb", NULL, fragment_setProperty, EVG_FRAG_RGB), |
3438 | | JS_CGETSET_MAGIC_DEF("yuv", NULL, fragment_setProperty, EVG_FRAG_YUV), |
3439 | | JS_CGETSET_MAGIC_DEF("yuva", NULL, fragment_setProperty, EVG_FRAG_YUVA), |
3440 | | }; |
3441 | | |
3442 | | JSClassDef vertex_class = { |
3443 | | .class_name = "Vertex", |
3444 | | }; |
3445 | | |
3446 | | enum { |
3447 | | EVG_VERTEX_IN, |
3448 | | EVG_VERTEX_OUT, |
3449 | | }; |
3450 | | |
3451 | | static JSValue vertex_getProperty(JSContext *c, JSValueConst obj, int magic) |
3452 | | { |
3453 | | JSValue res; |
3454 | | GF_EVGVertexParam *vert= JS_GetOpaque(obj, vertex_class_id); |
3455 | | if (!vert) return GF_JS_EXCEPTION(c); |
3456 | | switch (magic) { |
3457 | | case EVG_VERTEX_IN: |
3458 | | res = JS_NewObject(c); |
3459 | | JS_SetPropertyStr(c, res, "x", JS_NewFloat64(c, vert->in_vertex.x)); |
3460 | | JS_SetPropertyStr(c, res, "y", JS_NewFloat64(c, vert->in_vertex.y)); |
3461 | | JS_SetPropertyStr(c, res, "z", JS_NewFloat64(c, vert->in_vertex.z)); |
3462 | | JS_SetPropertyStr(c, res, "q", JS_NewFloat64(c, vert->in_vertex.q)); |
3463 | | return res; |
3464 | | } |
3465 | | return JS_UNDEFINED; |
3466 | | } |
3467 | | static JSValue vertex_setProperty(JSContext *ctx, JSValueConst obj, JSValueConst value, int magic) |
3468 | | { |
3469 | | Double _f; |
3470 | | JSValue v; |
3471 | | GF_EVGVertexParam *vert= JS_GetOpaque(obj, vertex_class_id); |
3472 | | if (!vert) return GF_JS_EXCEPTION(c); |
3473 | | switch (magic) { |
3474 | | case EVG_VERTEX_OUT: |
3475 | | v = JS_GetPropertyStr(ctx, value, "x"); |
3476 | | EVG_GET_FLOAT(_f, v); |
3477 | | vert->out_vertex.x = FLT2FIX(_f); |
3478 | | v = JS_GetPropertyStr(ctx, value, "y"); |
3479 | | EVG_GET_FLOAT(_f, v); |
3480 | | vert->out_vertex.y = FLT2FIX(_f); |
3481 | | v = JS_GetPropertyStr(ctx, value, "z"); |
3482 | | EVG_GET_FLOAT(_f, v); |
3483 | | vert->out_vertex.z = FLT2FIX(_f); |
3484 | | v = JS_GetPropertyStr(ctx, value, "q"); |
3485 | | EVG_GET_FLOAT(_f, v); |
3486 | | vert->out_vertex.q = FLT2FIX(_f); |
3487 | | |
3488 | | break; |
3489 | | default: |
3490 | | return JS_UNDEFINED; |
3491 | | } |
3492 | | return JS_UNDEFINED; |
3493 | | } |
3494 | | static const JSCFunctionListEntry vertex_funcs[] = |
3495 | | { |
3496 | | JS_CGETSET_MAGIC_DEF("vertex", vertex_getProperty, NULL, EVG_VERTEX_IN), |
3497 | | JS_CGETSET_MAGIC_DEF("vertexOut", NULL, vertex_setProperty, EVG_VERTEX_OUT), |
3498 | | }; |
3499 | | #endif // EVG_USE_JS_SHADER |
3500 | | |
3501 | | static Bool vai_call_lerp_init(EVG_VAI *vai, GF_EVGFragmentParam *frag) |
3502 | 0 | { |
3503 | 0 | u32 i; |
3504 | | |
3505 | | //different primitive, setup inperpolation points |
3506 | 0 | if (frag->prim_index != vai->prim_idx) { |
3507 | 0 | u32 idx; |
3508 | 0 | vai->prim_idx = frag->prim_index; |
3509 | | //no values, this is a VAI filled by the vertex shader |
3510 | 0 | if (!vai->values) { |
3511 | 0 | } else if (vai->interp_type==GF_EVG_VAI_PRIMITIVE) { |
3512 | |
|
3513 | 0 | } else if (frag->ptype!=GF_EVG_POINTS) { |
3514 | 0 | u32 nb_v_per_prim = 3; |
3515 | 0 | if (frag->ptype==GF_EVG_LINES) |
3516 | 0 | nb_v_per_prim=2; |
3517 | |
|
3518 | 0 | if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) { |
3519 | 0 | idx = frag->idx1 * vai->nb_comp; |
3520 | 0 | } else { |
3521 | 0 | idx = frag->prim_index * nb_v_per_prim * vai->nb_comp; |
3522 | 0 | } |
3523 | 0 | if (idx+vai->nb_comp > vai->nb_values) |
3524 | 0 | return GF_FALSE; |
3525 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3526 | 0 | vai->anchors[0][i] = vai->values[idx+i]; |
3527 | 0 | } |
3528 | |
|
3529 | 0 | if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) { |
3530 | 0 | idx = frag->idx2 * vai->nb_comp; |
3531 | 0 | } else { |
3532 | 0 | idx = (frag->prim_index * nb_v_per_prim + 1) * vai->nb_comp; |
3533 | 0 | } |
3534 | 0 | if (idx+vai->nb_comp > vai->nb_values) |
3535 | 0 | return GF_FALSE; |
3536 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3537 | 0 | vai->anchors[1][i] = vai->values[idx+i]; |
3538 | 0 | } |
3539 | 0 | if (frag->ptype!=GF_EVG_LINES) { |
3540 | 0 | if (vai->interp_type==GF_EVG_VAI_VERTEX_INDEX) { |
3541 | 0 | idx = frag->idx3 * vai->nb_comp; |
3542 | 0 | } else { |
3543 | 0 | idx = (frag->prim_index * nb_v_per_prim + 2) * vai->nb_comp; |
3544 | 0 | } |
3545 | 0 | if (idx+vai->nb_comp > vai->nb_values) |
3546 | 0 | return GF_FALSE; |
3547 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3548 | 0 | vai->anchors[2][i] = vai->values[idx+i]; |
3549 | 0 | } |
3550 | 0 | } |
3551 | 0 | } |
3552 | 0 | } |
3553 | 0 | return GF_TRUE; |
3554 | 0 | } |
3555 | | |
3556 | | static Bool vai_call_lerp(EVG_VAI *vai, GF_EVGFragmentParam *frag, Float *values) |
3557 | 0 | { |
3558 | 0 | u32 i; |
3559 | |
|
3560 | 0 | if (vai->interp_type==GF_EVG_VAI_PRIMITIVE) { |
3561 | 0 | u32 idx; |
3562 | 0 | idx = vai->prim_idx * vai->nb_comp; |
3563 | 0 | if (idx+vai->nb_comp > vai->nb_values) |
3564 | 0 | return GF_FALSE; |
3565 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3566 | 0 | values[i] = vai->values[idx+i]; |
3567 | 0 | } |
3568 | 0 | return GF_TRUE; |
3569 | 0 | } |
3570 | | |
3571 | 0 | if (frag->ptype==GF_EVG_LINES) { |
3572 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3573 | 0 | Float v = frag->pbc1 * vai->anchors[0][i] + frag->pbc2 * vai->anchors[1][i]; |
3574 | 0 | values[i] = v / frag->persp_denum; |
3575 | 0 | } |
3576 | 0 | } else { |
3577 | 0 | for (i=0; i<vai->nb_comp; i++) { |
3578 | 0 | Float v = (Float) ( frag->pbc1 * vai->anchors[0][i] + frag->pbc2 * vai->anchors[1][i] + frag->pbc3 * vai->anchors[2][i] ); |
3579 | 0 | values[i] = v / frag->persp_denum; |
3580 | 0 | } |
3581 | 0 | } |
3582 | 0 | if (vai->normalize) { |
3583 | 0 | if (vai->nb_comp==2) { |
3584 | 0 | Float len; |
3585 | 0 | if (!values[0]) len = ABS(values[1]); |
3586 | 0 | else if (!values[1]) len = ABS(values[0]); |
3587 | 0 | else len = sqrtf(values[0]*values[0] + values[1]*values[1]); |
3588 | 0 | if (len) { |
3589 | 0 | values[0]/=len; |
3590 | 0 | values[1]/=len; |
3591 | 0 | } |
3592 | 0 | } else { |
3593 | 0 | gf_vec_norm((GF_Vec *) &values[0]); |
3594 | 0 | } |
3595 | 0 | } |
3596 | 0 | return GF_TRUE; |
3597 | 0 | } |
3598 | | |
3599 | | #ifdef EVG_USE_JS_SHADER |
3600 | | static JSValue vai_lerp(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3601 | | { |
3602 | | EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id); |
3603 | | if (!vai || !argc) return GF_JS_EXCEPTION(c); |
3604 | | GF_EVGFragmentParam *frag = JS_GetOpaque(argv[0], fragment_class_id); |
3605 | | if (!frag) return GF_JS_EXCEPTION(c); |
3606 | | |
3607 | | if (!vai_call_lerp(vai, frag)) |
3608 | | return GF_JS_EXCEPTION(c); |
3609 | | return JS_DupValue(c, vai->res); |
3610 | | } |
3611 | | #endif |
3612 | | |
3613 | | static JSValue vai_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
3614 | 0 | { |
3615 | 0 | EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id); |
3616 | 0 | if (!vai) return GF_JS_EXCEPTION(c); |
3617 | 0 | switch (magic) { |
3618 | 0 | case 0: |
3619 | 0 | vai->normalize = JS_ToBool(c, value) ? GF_TRUE : GF_FALSE; |
3620 | 0 | break; |
3621 | 0 | } |
3622 | 0 | return JS_UNDEFINED; |
3623 | 0 | } |
3624 | | |
3625 | | static JSValue vai_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
3626 | 0 | { |
3627 | 0 | EVG_VAI *vai; |
3628 | 0 | JSValue obj; |
3629 | 0 | u8 *data=NULL; |
3630 | 0 | u32 data_size=0; |
3631 | 0 | u32 nb_comp; |
3632 | 0 | s32 interp_type = GF_EVG_VAI_VERTEX_INDEX; |
3633 | 0 | if (argc<1) |
3634 | 0 | return js_throw_err_msg(c, GF_BAD_PARAM, "Missing parameter for VertexAttribInterpolator"); |
3635 | | |
3636 | 0 | if (argc>=2) { |
3637 | 0 | data = evg_get_array(c, argv[0], &data_size); |
3638 | 0 | if (!data) return GF_JS_EXCEPTION(c); |
3639 | 0 | if (JS_ToInt32(c, &nb_comp, argv[1])) return GF_JS_EXCEPTION(c); |
3640 | 0 | if (nb_comp>MAX_ATTR_DIM) |
3641 | 0 | return js_throw_err_msg(c, GF_BAD_PARAM, "Dimension too big, max is %d", MAX_ATTR_DIM); |
3642 | | |
3643 | 0 | if (data_size % sizeof(Float)) return GF_JS_EXCEPTION(c); |
3644 | 0 | data_size /= sizeof(Float); |
3645 | 0 | if (data_size % nb_comp) return GF_JS_EXCEPTION(c); |
3646 | | |
3647 | 0 | if (argc>2) { |
3648 | 0 | if (JS_ToInt32(c, &interp_type, argv[2])) return GF_JS_EXCEPTION(c); |
3649 | 0 | } |
3650 | 0 | } else { |
3651 | 0 | if (JS_ToInt32(c, &nb_comp, argv[0])) return GF_JS_EXCEPTION(c); |
3652 | 0 | } |
3653 | | |
3654 | 0 | GF_SAFEALLOC(vai, EVG_VAI); |
3655 | 0 | if (!vai) |
3656 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
3657 | 0 | vai->nb_comp = nb_comp; |
3658 | 0 | vai->values = (Float *)data; |
3659 | 0 | vai->nb_values = data_size; |
3660 | 0 | if (data) |
3661 | 0 | vai->ab = JS_DupValue(c, argv[0]); |
3662 | |
|
3663 | 0 | vai->prim_idx = (u32) -1; |
3664 | 0 | vai->interp_type = interp_type; |
3665 | |
|
3666 | | #ifdef EVG_USE_JS_SHADER |
3667 | | vai->res = JS_NewObjectClass(c, vaires_class_id); |
3668 | | JS_SetOpaque(vai->res, &vai->result); |
3669 | | JS_SetPropertyStr(c, vai->res, "length", JS_NewInt32(c, nb_comp)); |
3670 | | #endif |
3671 | 0 | vai->result.dim = nb_comp; |
3672 | 0 | if (nb_comp==1) vai->result.comp_type = COMP_X; |
3673 | 0 | else if (nb_comp==2) vai->result.comp_type = COMP_V2_XY; |
3674 | 0 | else if (nb_comp==3) vai->result.comp_type = COMP_V3; |
3675 | 0 | else vai->result.comp_type = COMP_V4; |
3676 | |
|
3677 | 0 | obj = JS_NewObjectClass(c, vai_class_id); |
3678 | 0 | JS_SetOpaque(obj, vai); |
3679 | 0 | return obj; |
3680 | 0 | } |
3681 | | static void vai_finalize(JSRuntime *rt, JSValue obj) |
3682 | 0 | { |
3683 | 0 | EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id); |
3684 | 0 | if (!vai) return; |
3685 | 0 | JS_FreeValueRT(rt, vai->ab); |
3686 | | #ifdef EVG_USE_JS_SHADER |
3687 | | JS_FreeValueRT(rt, vai->res); |
3688 | | #endif |
3689 | 0 | gf_free(vai); |
3690 | 0 | } |
3691 | | |
3692 | | static void vai_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func) |
3693 | 0 | { |
3694 | 0 | EVG_VAI *vai = JS_GetOpaque(obj, vai_class_id); |
3695 | 0 | if (!vai) return; |
3696 | 0 | JS_MarkValue(rt, vai->ab, mark_func); |
3697 | | #ifdef EVG_USE_JS_SHADER |
3698 | | JS_MarkValue(rt, vai->res, mark_func); |
3699 | | #endif |
3700 | 0 | } |
3701 | | |
3702 | | JSClassDef vai_class = { |
3703 | | .class_name = "VertexAttribInterpolator", |
3704 | | .finalizer = vai_finalize, |
3705 | | .gc_mark = vai_gc_mark |
3706 | | }; |
3707 | | static const JSCFunctionListEntry vai_funcs[] = |
3708 | | { |
3709 | | JS_CGETSET_MAGIC_DEF("normalize", NULL, vai_setProperty, 0), |
3710 | | #ifdef EVG_USE_JS_SHADER |
3711 | | JS_CFUNC_DEF("lerp", 0, vai_lerp), |
3712 | | #endif |
3713 | | }; |
3714 | | |
3715 | | static JSValue va_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
3716 | 0 | { |
3717 | 0 | EVG_VA *va; |
3718 | 0 | JSValue obj; |
3719 | 0 | u8 *data=NULL; |
3720 | 0 | u32 data_size; |
3721 | 0 | u32 nb_comp; |
3722 | 0 | s32 interp_type = GF_EVG_VAI_VERTEX_INDEX; |
3723 | 0 | if (argc<2) |
3724 | 0 | return js_throw_err_msg(c, GF_BAD_PARAM, "Missing parameter / data for VertexAttrib"); |
3725 | | |
3726 | 0 | data = evg_get_array(c, argv[0], &data_size); |
3727 | 0 | if (!data) return GF_JS_EXCEPTION(c); |
3728 | 0 | if (JS_ToInt32(c, &nb_comp, argv[1])) return GF_JS_EXCEPTION(c); |
3729 | 0 | if (nb_comp>MAX_ATTR_DIM) |
3730 | 0 | return js_throw_err_msg(c, GF_BAD_PARAM, "Dimension too big, max is %d", MAX_ATTR_DIM); |
3731 | | |
3732 | 0 | if (data_size % sizeof(Float)) return GF_JS_EXCEPTION(c); |
3733 | 0 | data_size /= sizeof(Float); |
3734 | 0 | if (data_size % nb_comp) return GF_JS_EXCEPTION(c); |
3735 | | |
3736 | 0 | if (argc>2) { |
3737 | 0 | if (JS_ToInt32(c, &interp_type, argv[2])) return GF_JS_EXCEPTION(c); |
3738 | 0 | } |
3739 | | |
3740 | 0 | GF_SAFEALLOC(va, EVG_VA); |
3741 | 0 | if (!va) |
3742 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
3743 | 0 | va->nb_comp = nb_comp; |
3744 | 0 | va->values = (Float *)data; |
3745 | 0 | va->nb_values = data_size; |
3746 | 0 | va->ab = JS_DupValue(c, argv[0]); |
3747 | 0 | va->interp_type = interp_type; |
3748 | 0 | if (va->nb_comp==1) va->att_type = COMP_FLOAT; |
3749 | 0 | else if (va->nb_comp==2) va->att_type = COMP_V2_XY; |
3750 | 0 | else if (va->nb_comp==3) va->att_type = COMP_V3; |
3751 | 0 | else va->att_type = COMP_V4; |
3752 | |
|
3753 | 0 | obj = JS_NewObjectClass(c, va_class_id); |
3754 | 0 | JS_SetOpaque(obj, va); |
3755 | 0 | return obj; |
3756 | 0 | } |
3757 | | |
3758 | | static JSValue va_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
3759 | 0 | { |
3760 | 0 | EVG_VA *va = JS_GetOpaque(obj, va_class_id); |
3761 | 0 | if (!va) return GF_JS_EXCEPTION(c); |
3762 | 0 | switch (magic) { |
3763 | 0 | case 0: |
3764 | 0 | va->normalize = JS_ToBool(c, value) ? GF_TRUE : GF_FALSE; |
3765 | 0 | break; |
3766 | 0 | } |
3767 | 0 | return JS_UNDEFINED; |
3768 | 0 | } |
3769 | | static void va_finalize(JSRuntime *rt, JSValue obj) |
3770 | 0 | { |
3771 | 0 | EVG_VA *va = JS_GetOpaque(obj, va_class_id); |
3772 | 0 | if (!va) return; |
3773 | 0 | JS_FreeValueRT(rt, va->ab); |
3774 | 0 | gf_free(va); |
3775 | 0 | } |
3776 | | |
3777 | | static void va_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func) |
3778 | 0 | { |
3779 | | #ifdef GPAC_ENABLE_COVERAGE |
3780 | | if (!rt) return; |
3781 | | #endif |
3782 | 0 | EVG_VA *va = JS_GetOpaque(obj, va_class_id); |
3783 | 0 | if (!va) return; |
3784 | 0 | JS_MarkValue(rt, va->ab, mark_func); |
3785 | 0 | } |
3786 | | |
3787 | | JSClassDef va_class = { |
3788 | | .class_name = "VertexAttrib", |
3789 | | .finalizer = va_finalize, |
3790 | | .gc_mark = va_gc_mark |
3791 | | }; |
3792 | | static const JSCFunctionListEntry va_funcs[] = |
3793 | | { |
3794 | | JS_CGETSET_MAGIC_DEF("normalize", NULL, va_setProperty, 0), |
3795 | | }; |
3796 | | |
3797 | | #ifdef EVG_USE_JS_SHADER |
3798 | | |
3799 | | static JSValue vaires_getProperty(JSContext *c, JSValueConst obj, int magic) |
3800 | | { |
3801 | | EVG_VAIRes *vr = JS_GetOpaque(obj, vaires_class_id); |
3802 | | if (!vr) return GF_JS_EXCEPTION(c); |
3803 | | if (magic<MAX_ATTR_DIM) { |
3804 | | return JS_NewFloat64(c, vr->values[magic]); |
3805 | | } |
3806 | | return JS_UNDEFINED; |
3807 | | } |
3808 | | static const JSCFunctionListEntry vaires_funcs[] = |
3809 | | { |
3810 | | JS_CGETSET_MAGIC_DEF("x", vaires_getProperty, NULL, 0), |
3811 | | JS_CGETSET_MAGIC_DEF("y", vaires_getProperty, NULL, 1), |
3812 | | JS_CGETSET_MAGIC_DEF("z", vaires_getProperty, NULL, 2), |
3813 | | JS_CGETSET_MAGIC_DEF("w", vaires_getProperty, NULL, 3), |
3814 | | JS_ALIAS_DEF("r", "x"), |
3815 | | JS_ALIAS_DEF("g", "y"), |
3816 | | JS_ALIAS_DEF("b", "z"), |
3817 | | JS_ALIAS_DEF("a", "w"), |
3818 | | JS_ALIAS_DEF("s", "x"), |
3819 | | JS_ALIAS_DEF("t", "y"), |
3820 | | }; |
3821 | | |
3822 | | JSClassDef vaires_class = { |
3823 | | .class_name = "VAIResult", |
3824 | | }; |
3825 | | |
3826 | | #endif //EVG_USE_JS_SHADER |
3827 | | |
3828 | | static void mx2d_finalize(JSRuntime *rt, JSValue obj) |
3829 | 0 | { |
3830 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3831 | 0 | if (!mx) return; |
3832 | 0 | gf_free(mx); |
3833 | 0 | } |
3834 | | JSClassDef mx2d_class = { |
3835 | | "Matrix2D", |
3836 | | .finalizer = mx2d_finalize |
3837 | | }; |
3838 | | |
3839 | | enum |
3840 | | { |
3841 | | //these 6 magics map to m[x] of the matrix, DO NOT MODIFY |
3842 | | MX2D_XX = 0, |
3843 | | MX2D_XY, |
3844 | | MX2D_TX, |
3845 | | MX2D_YX, |
3846 | | MX2D_YY, |
3847 | | MX2D_TY, |
3848 | | MX2D_IDENTITY, |
3849 | | MX2D_3D, |
3850 | | }; |
3851 | | |
3852 | | static JSValue mx2d_getProperty(JSContext *c, JSValueConst obj, int magic) |
3853 | 0 | { |
3854 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3855 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
3856 | 0 | if ((magic>=MX2D_XX) && (magic<=MX2D_TY)) { |
3857 | 0 | return JS_NewFloat64(c, FIX2FLT(mx->m[magic])); |
3858 | 0 | } |
3859 | 0 | if (magic==MX2D_IDENTITY) |
3860 | 0 | return JS_NewBool(c, gf_mx2d_is_identity(*mx)); |
3861 | 0 | if (magic==MX2D_3D) |
3862 | 0 | return JS_FALSE; |
3863 | 0 | return JS_UNDEFINED; |
3864 | 0 | } |
3865 | | static JSValue mx2d_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
3866 | 0 | { |
3867 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3868 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
3869 | 0 | if ((magic>=MX2D_XX) && (magic<=MX2D_TY)) { |
3870 | 0 | Double d; |
3871 | 0 | if (JS_ToFloat64(c, &d, value)) |
3872 | 0 | return GF_JS_EXCEPTION(c); |
3873 | 0 | mx->m[magic] = FIX2FLT(d); |
3874 | 0 | return JS_UNDEFINED; |
3875 | 0 | } |
3876 | 0 | if (magic==MX2D_IDENTITY) { |
3877 | 0 | if (JS_ToBool(c, value)) |
3878 | 0 | gf_mx2d_init(*mx); |
3879 | 0 | return JS_UNDEFINED; |
3880 | 0 | } |
3881 | 0 | return JS_UNDEFINED; |
3882 | 0 | } |
3883 | | |
3884 | | static JSValue mx2d_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3885 | 0 | { |
3886 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3887 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(c); |
3888 | 0 | GF_Matrix2D *amx = JS_GetOpaque(argv[0], mx2d_class_id); |
3889 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
3890 | 0 | if ((argc>1) && JS_ToBool(c, argv[1])) |
3891 | 0 | gf_mx2d_pre_multiply(mx, amx); |
3892 | 0 | else |
3893 | 0 | gf_mx2d_add_matrix(mx, amx); |
3894 | 0 | return JS_DupValue(c, obj); |
3895 | 0 | } |
3896 | | |
3897 | | static JSValue mx2d_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3898 | 0 | { |
3899 | 0 | Double tx, ty; |
3900 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3901 | 0 | if (!mx || (argc<1)) return GF_JS_EXCEPTION(c); |
3902 | | |
3903 | 0 | if (JS_IsObject(argv[0])) { |
3904 | 0 | JSValue v; |
3905 | 0 | #define GETD(_arg, _name, _res)\ |
3906 | 0 | if (! JS_IsObject(_arg)) return GF_JS_EXCEPTION(c);\ |
3907 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
3908 | 0 | JS_ToFloat64(c, &_res, v);\ |
3909 | 0 | JS_FreeValue(c, v);\ |
3910 | 0 |
|
3911 | 0 | GETD(argv[0], "x", tx); |
3912 | 0 | GETD(argv[0], "y", ty); |
3913 | 0 | #undef GETD |
3914 | |
|
3915 | 0 | } else if (argc==2) { |
3916 | 0 | if (JS_ToFloat64(c, &tx, argv[0])) return GF_JS_EXCEPTION(c); |
3917 | 0 | if (JS_ToFloat64(c, &ty, argv[1])) return GF_JS_EXCEPTION(c); |
3918 | 0 | } else { |
3919 | 0 | return GF_JS_EXCEPTION(c); |
3920 | 0 | } |
3921 | 0 | gf_mx2d_add_translation(mx, FLT2FIX(tx), FLT2FIX(ty)); |
3922 | 0 | return JS_DupValue(c, obj); |
3923 | 0 | } |
3924 | | static JSValue mx2d_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3925 | 0 | { |
3926 | 0 | Double cx, cy, a; |
3927 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3928 | 0 | if (!mx || (argc<3)) return GF_JS_EXCEPTION(c); |
3929 | 0 | if (JS_ToFloat64(c, &cx, argv[0])) return GF_JS_EXCEPTION(c); |
3930 | 0 | if (JS_ToFloat64(c, &cy, argv[1])) return GF_JS_EXCEPTION(c); |
3931 | 0 | if (JS_ToFloat64(c, &a, argv[2])) return GF_JS_EXCEPTION(c); |
3932 | 0 | gf_mx2d_add_rotation(mx, FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a) ); |
3933 | 0 | return JS_DupValue(c, obj); |
3934 | 0 | } |
3935 | | static JSValue mx2d_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3936 | 0 | { |
3937 | 0 | Double sx, sy; |
3938 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3939 | 0 | if (!mx || (argc<2)) return GF_JS_EXCEPTION(c); |
3940 | 0 | if (JS_ToFloat64(c, &sx, argv[0])) return GF_JS_EXCEPTION(c); |
3941 | 0 | if (JS_ToFloat64(c, &sy, argv[1])) return GF_JS_EXCEPTION(c); |
3942 | 0 | if (argc==2) { |
3943 | 0 | gf_mx2d_add_scale(mx, FLT2FIX(sx), FLT2FIX(sy)); |
3944 | 0 | return JS_DupValue(c, obj); |
3945 | 0 | } else if (argc==5) { |
3946 | 0 | Double cx, cy, a; |
3947 | 0 | if (JS_ToFloat64(c, &cx, argv[2])) return GF_JS_EXCEPTION(c); |
3948 | 0 | if (JS_ToFloat64(c, &cy, argv[3])) return GF_JS_EXCEPTION(c); |
3949 | 0 | if (JS_ToFloat64(c, &a, argv[4])) return GF_JS_EXCEPTION(c); |
3950 | 0 | gf_mx2d_add_scale_at(mx, FLT2FIX(sx), FLT2FIX(sy), FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a)); |
3951 | 0 | return JS_DupValue(c, obj); |
3952 | 0 | } |
3953 | 0 | return GF_JS_EXCEPTION(c); |
3954 | 0 | } |
3955 | | |
3956 | | static JSValue mx2d_skew(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3957 | 0 | { |
3958 | 0 | Double sx, sy; |
3959 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3960 | 0 | if (!mx || (argc<2)) return GF_JS_EXCEPTION(c); |
3961 | 0 | if (JS_ToFloat64(c, &sx, argv[0])) return GF_JS_EXCEPTION(c); |
3962 | 0 | if (JS_ToFloat64(c, &sy, argv[1])) return GF_JS_EXCEPTION(c); |
3963 | 0 | gf_mx2d_add_skew(mx, FLT2FIX(sx), FLT2FIX(sy)); |
3964 | 0 | return JS_DupValue(c, obj); |
3965 | 0 | } |
3966 | | static JSValue mx2d_skew_x(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3967 | 0 | { |
3968 | 0 | Double s; |
3969 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3970 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(c); |
3971 | 0 | if (JS_ToFloat64(c, &s, argv[0])) return GF_JS_EXCEPTION(c); |
3972 | 0 | gf_mx2d_add_skew_x(mx, FLT2FIX(s)); |
3973 | 0 | return JS_DupValue(c, obj); |
3974 | 0 | } |
3975 | | static JSValue mx2d_skew_y(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3976 | 0 | { |
3977 | 0 | Double s; |
3978 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3979 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(c); |
3980 | 0 | if (JS_ToFloat64(c, &s, argv[0])) return GF_JS_EXCEPTION(c); |
3981 | 0 | gf_mx2d_add_skew_y(mx, FLT2FIX(s)); |
3982 | 0 | return JS_DupValue(c, obj); |
3983 | 0 | } |
3984 | | |
3985 | | static JSValue mx2d_apply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
3986 | 0 | { |
3987 | 0 | Fixed x, y, w=0, h=0; |
3988 | 0 | Double d; |
3989 | 0 | JSValue v; |
3990 | 0 | int res; |
3991 | 0 | u32 is_rect=0; |
3992 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
3993 | 0 | if (!mx || !argc || !JS_IsObject(argv[0])) return GF_JS_EXCEPTION(c); |
3994 | 0 | v = JS_GetPropertyStr(c, argv[0], "x"); |
3995 | 0 | res = JS_ToFloat64(c, &d, v); |
3996 | 0 | JS_FreeValue(c, v); |
3997 | 0 | if (res) return GF_JS_EXCEPTION(c); |
3998 | 0 | x = FLT2FIX(d); |
3999 | |
|
4000 | 0 | v = JS_GetPropertyStr(c, argv[0], "y"); |
4001 | 0 | res = JS_ToFloat64(c, &d, v); |
4002 | 0 | JS_FreeValue(c, v); |
4003 | 0 | if (res) return GF_JS_EXCEPTION(c); |
4004 | 0 | y = FLT2FIX(d); |
4005 | |
|
4006 | 0 | v = JS_GetPropertyStr(c, argv[0], "w"); |
4007 | 0 | if (!JS_IsUndefined(v) && JS_IsNumber(v)) { |
4008 | 0 | res = JS_ToFloat64(c, &d, v); |
4009 | 0 | JS_FreeValue(c, v); |
4010 | 0 | if (res) return GF_JS_EXCEPTION(c); |
4011 | 0 | is_rect++; |
4012 | 0 | w = FLT2FIX(d); |
4013 | 0 | } |
4014 | 0 | JS_FreeValue(c, v); |
4015 | |
|
4016 | 0 | v = JS_GetPropertyStr(c, argv[0], "h"); |
4017 | 0 | if (!JS_IsUndefined(v) && JS_IsNumber(v)) { |
4018 | 0 | res = JS_ToFloat64(c, &d, v); |
4019 | 0 | JS_FreeValue(c, v); |
4020 | 0 | if (res) return GF_JS_EXCEPTION(c); |
4021 | 0 | is_rect++; |
4022 | 0 | h = FLT2FIX(d); |
4023 | 0 | } |
4024 | 0 | JS_FreeValue(c, v); |
4025 | |
|
4026 | 0 | if (is_rect) { |
4027 | 0 | GF_Rect rc; |
4028 | 0 | rc.x = x; |
4029 | 0 | rc.y = y; |
4030 | 0 | rc.width = w; |
4031 | 0 | rc.height = h; |
4032 | 0 | gf_mx2d_apply_rect(mx, &rc); |
4033 | 0 | v = JS_NewObject(c); |
4034 | 0 | JS_SetPropertyStr(c, v, "x", JS_NewFloat64(c, FIX2FLT(rc.x))); |
4035 | 0 | JS_SetPropertyStr(c, v, "y", JS_NewFloat64(c, FIX2FLT(rc.y))); |
4036 | 0 | JS_SetPropertyStr(c, v, "w", JS_NewFloat64(c, FIX2FLT(rc.width))); |
4037 | 0 | JS_SetPropertyStr(c, v, "h", JS_NewFloat64(c, FIX2FLT(rc.height))); |
4038 | 0 | return v; |
4039 | |
|
4040 | 0 | } else { |
4041 | 0 | GF_Point2D pt; |
4042 | 0 | pt.x = x; |
4043 | 0 | pt.y = y; |
4044 | 0 | gf_mx2d_apply_point(mx, &pt); |
4045 | 0 | v = JS_NewObject(c); |
4046 | 0 | JS_SetPropertyStr(c, v, "x", JS_NewFloat64(c, FIX2FLT(pt.x))); |
4047 | 0 | JS_SetPropertyStr(c, v, "y", JS_NewFloat64(c, FIX2FLT(pt.y))); |
4048 | 0 | return v; |
4049 | 0 | } |
4050 | 0 | return GF_JS_EXCEPTION(c); |
4051 | 0 | } |
4052 | | |
4053 | | static JSValue mx2d_inverse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4054 | 0 | { |
4055 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
4056 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
4057 | 0 | gf_mx2d_inverse(mx); |
4058 | 0 | return JS_DupValue(c, obj); |
4059 | 0 | } |
4060 | | |
4061 | | static JSValue mx2d_copy(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4062 | 0 | { |
4063 | 0 | GF_Matrix2D *nmx; |
4064 | 0 | JSValue nobj; |
4065 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
4066 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
4067 | 0 | if (argc) { |
4068 | 0 | GF_Matrix2D *mx_from = JS_GetOpaque(argv[0], mx2d_class_id); |
4069 | 0 | if (!mx_from) return GF_JS_EXCEPTION(c); |
4070 | 0 | gf_mx2d_copy(*mx, *mx_from); |
4071 | 0 | return JS_UNDEFINED; |
4072 | 0 | } |
4073 | 0 | GF_SAFEALLOC(nmx, GF_Matrix2D); |
4074 | 0 | if (!nmx) |
4075 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
4076 | 0 | gf_mx2d_copy(*nmx, *mx); |
4077 | 0 | nobj = JS_NewObjectClass(c, mx2d_class_id); |
4078 | 0 | JS_SetOpaque(nobj, nmx); |
4079 | 0 | return nobj; |
4080 | 0 | } |
4081 | | |
4082 | | static JSValue mx2d_decompose_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 opt) |
4083 | 0 | { |
4084 | 0 | GF_Point2D scale; |
4085 | 0 | GF_Point2D translate; |
4086 | 0 | Fixed rotate; |
4087 | 0 | GF_Matrix2D *mx = JS_GetOpaque(obj, mx2d_class_id); |
4088 | 0 | if (!mx) return GF_JS_EXCEPTION(c); |
4089 | 0 | if (!gf_mx2d_decompose(mx, &scale, &rotate, &translate)) |
4090 | 0 | return JS_NULL; |
4091 | 0 | if (opt==0) { |
4092 | 0 | JSValue nobj = JS_NewObject(c); |
4093 | 0 | JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, FIX2FLT(scale.x)) ); |
4094 | 0 | JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, FIX2FLT(scale.y)) ); |
4095 | 0 | return nobj; |
4096 | 0 | } |
4097 | 0 | if (opt==1) { |
4098 | 0 | JSValue nobj = JS_NewObject(c); |
4099 | 0 | JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, FIX2FLT(translate.x)) ); |
4100 | 0 | JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, FIX2FLT(translate.y)) ); |
4101 | 0 | return nobj; |
4102 | 0 | } |
4103 | 0 | if (opt==2) { |
4104 | 0 | return JS_NewFloat64(c, FIX2FLT(rotate) ); |
4105 | 0 | } |
4106 | 0 | return GF_JS_EXCEPTION(c); |
4107 | 0 | } |
4108 | | |
4109 | | static JSValue mx2d_get_scale(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4110 | 0 | { |
4111 | 0 | return mx2d_decompose_ex(c, obj, argc, argv, 0); |
4112 | 0 | } |
4113 | | static JSValue mx2d_get_translate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4114 | 0 | { |
4115 | 0 | return mx2d_decompose_ex(c, obj, argc, argv, 1); |
4116 | 0 | } |
4117 | | static JSValue mx2d_get_rotate(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4118 | 0 | { |
4119 | 0 | return mx2d_decompose_ex(c, obj, argc, argv, 2); |
4120 | 0 | } |
4121 | | |
4122 | | static const JSCFunctionListEntry mx2d_funcs[] = |
4123 | | { |
4124 | | JS_CGETSET_MAGIC_DEF("xx", mx2d_getProperty, mx2d_setProperty, MX2D_XX), |
4125 | | JS_CGETSET_MAGIC_DEF("xy", mx2d_getProperty, mx2d_setProperty, MX2D_XY), |
4126 | | JS_CGETSET_MAGIC_DEF("tx", mx2d_getProperty, mx2d_setProperty, MX2D_TX), |
4127 | | JS_CGETSET_MAGIC_DEF("yx", mx2d_getProperty, mx2d_setProperty, MX2D_YX), |
4128 | | JS_CGETSET_MAGIC_DEF("yy", mx2d_getProperty, mx2d_setProperty, MX2D_YY), |
4129 | | JS_CGETSET_MAGIC_DEF("ty", mx2d_getProperty, mx2d_setProperty, MX2D_TY), |
4130 | | JS_CGETSET_MAGIC_DEF("identity", mx2d_getProperty, mx2d_setProperty, MX2D_IDENTITY), |
4131 | | JS_CGETSET_MAGIC_DEF("is3D", mx2d_getProperty, NULL, MX2D_3D), |
4132 | | JS_CFUNC_DEF("get_scale", 0, mx2d_get_scale), |
4133 | | JS_CFUNC_DEF("get_translate", 0, mx2d_get_translate), |
4134 | | JS_CFUNC_DEF("get_rotate", 0, mx2d_get_rotate), |
4135 | | JS_CFUNC_DEF("inverse", 0, mx2d_inverse), |
4136 | | JS_CFUNC_DEF("copy", 0, mx2d_copy), |
4137 | | JS_CFUNC_DEF("add", 0, mx2d_multiply), |
4138 | | JS_CFUNC_DEF("translate", 0, mx2d_translate), |
4139 | | JS_CFUNC_DEF("rotate", 0, mx2d_rotate), |
4140 | | JS_CFUNC_DEF("scale", 0, mx2d_scale), |
4141 | | JS_CFUNC_DEF("skew", 0, mx2d_skew), |
4142 | | JS_CFUNC_DEF("skew_x", 0, mx2d_skew_x), |
4143 | | JS_CFUNC_DEF("skew_y", 0, mx2d_skew_y), |
4144 | | JS_CFUNC_DEF("apply", 0, mx2d_apply), |
4145 | | }; |
4146 | | |
4147 | | static JSValue mx2d_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
4148 | 0 | { |
4149 | 0 | JSValue obj; |
4150 | 0 | GF_Matrix2D *mx; |
4151 | 0 | GF_SAFEALLOC(mx, GF_Matrix2D); |
4152 | 0 | if (!mx) |
4153 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
4154 | 0 | mx->m[MX2D_XX] = mx->m[MX2D_YY] = FIX_ONE; |
4155 | 0 | obj = JS_NewObjectClass(c, mx2d_class_id); |
4156 | 0 | JS_SetOpaque(obj, mx); |
4157 | 0 | if ((argc==1) && JS_IsObject(argv[0])) { |
4158 | 0 | GF_Matrix2D *amx = JS_GetOpaque(argv[0], mx2d_class_id); |
4159 | 0 | if (amx) gf_mx2d_copy(*mx, *amx); |
4160 | 0 | } |
4161 | 0 | else if (argc==6) { |
4162 | 0 | u32 i; |
4163 | 0 | Double d; |
4164 | 0 | for (i=0; i<6; i++) { |
4165 | 0 | if (JS_ToFloat64(c, &d, argv[i])) return GF_JS_EXCEPTION(c); |
4166 | 0 | mx->m[i] = FLT2FIX(d); |
4167 | 0 | } |
4168 | 0 | } |
4169 | 0 | return obj; |
4170 | 0 | } |
4171 | | |
4172 | | static void colmx_finalize(JSRuntime *rt, JSValue obj) |
4173 | 0 | { |
4174 | 0 | GF_ColorMatrix *mx = JS_GetOpaque(obj, colmx_class_id); |
4175 | 0 | if (!mx) return; |
4176 | 0 | gf_free(mx); |
4177 | 0 | } |
4178 | | JSClassDef colmx_class = { |
4179 | | "ColorMatrix", |
4180 | | .finalizer = colmx_finalize |
4181 | | }; |
4182 | | |
4183 | | static JSValue colmx_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
4184 | 0 | { |
4185 | 0 | JSValue obj; |
4186 | 0 | GF_ColorMatrix *cmx; |
4187 | 0 | GF_SAFEALLOC(cmx, GF_ColorMatrix); |
4188 | 0 | if (!cmx) |
4189 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
4190 | 0 | gf_cmx_init(cmx); |
4191 | 0 | obj = JS_NewObjectClass(c, colmx_class_id); |
4192 | 0 | JS_SetOpaque(obj, cmx); |
4193 | 0 | if ((argc==1) && JS_IsObject(argv[0])) { |
4194 | 0 | GF_ColorMatrix *acmx = JS_GetOpaque(argv[0], colmx_class_id); |
4195 | 0 | if (acmx) gf_cmx_copy(cmx, acmx); |
4196 | 0 | else if (JS_IsArray(c, argv[0])) { |
4197 | 0 | u32 i; |
4198 | 0 | Double d; |
4199 | 0 | for (i=0; i<20; i++) { |
4200 | 0 | JSValue v = JS_GetPropertyUint32(c, argv[0], i); |
4201 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
4202 | 0 | if (JS_ToFloat64(c, &d, v)) { |
4203 | 0 | JS_FreeValue(c, v); |
4204 | 0 | return GF_JS_EXCEPTION(c); |
4205 | 0 | } |
4206 | 0 | cmx->m[i] = FLT2FIX(d); |
4207 | 0 | JS_FreeValue(c, v); |
4208 | 0 | } |
4209 | 0 | cmx->identity = 0; |
4210 | 0 | } |
4211 | 0 | } |
4212 | 0 | else if (argc==20) { |
4213 | 0 | u32 i; |
4214 | 0 | Double d; |
4215 | 0 | for (i=0; i<20; i++) { |
4216 | 0 | if (JS_ToFloat64(c, &d, argv[i])) return GF_JS_EXCEPTION(c); |
4217 | 0 | cmx->m[i] = FLT2FIX(d); |
4218 | 0 | } |
4219 | 0 | cmx->identity = 0; |
4220 | 0 | } |
4221 | 0 | return obj; |
4222 | 0 | } |
4223 | | enum |
4224 | | { |
4225 | | //these 6 magics map to m[x] of the matrix, DO NOT MODIFY |
4226 | | CMX_MRR = 0, |
4227 | | CMX_MRG, |
4228 | | CMX_MRB, |
4229 | | CMX_MRA, |
4230 | | CMX_TR, |
4231 | | CMX_MGR, |
4232 | | CMX_MGG, |
4233 | | CMX_MGB, |
4234 | | CMX_MGA, |
4235 | | CMX_TG, |
4236 | | CMX_MBR, |
4237 | | CMX_MBG, |
4238 | | CMX_MBB, |
4239 | | CMX_MBA, |
4240 | | CMX_TB, |
4241 | | CMX_MAR, |
4242 | | CMX_MAG, |
4243 | | CMX_MAB, |
4244 | | CMX_MAA, |
4245 | | CMX_TA, |
4246 | | CMX_IDENTITY, |
4247 | | }; |
4248 | | |
4249 | | static JSValue colmx_getProperty(JSContext *c, JSValueConst obj, int magic) |
4250 | 0 | { |
4251 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id); |
4252 | 0 | if (!cmx) return GF_JS_EXCEPTION(c); |
4253 | 0 | if ((magic>=CMX_MRR) && (magic<=CMX_TA)) { |
4254 | 0 | return JS_NewFloat64(c, FIX2FLT(cmx->m[magic])); |
4255 | 0 | } |
4256 | 0 | if (magic==CMX_IDENTITY) |
4257 | 0 | return JS_NewBool(c, cmx->identity); |
4258 | 0 | return JS_UNDEFINED; |
4259 | 0 | } |
4260 | | static JSValue colmx_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
4261 | 0 | { |
4262 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id); |
4263 | 0 | if (!cmx) return GF_JS_EXCEPTION(c); |
4264 | 0 | if ((magic>=CMX_MRR) && (magic<=CMX_TA)) { |
4265 | 0 | Double d; |
4266 | 0 | if (JS_ToFloat64(c, &d, value)) |
4267 | 0 | return GF_JS_EXCEPTION(c); |
4268 | 0 | cmx->m[magic] = FIX2FLT(d); |
4269 | 0 | cmx->identity = GF_FALSE; |
4270 | 0 | return JS_UNDEFINED; |
4271 | 0 | } |
4272 | 0 | if (magic==CMX_IDENTITY) { |
4273 | 0 | gf_cmx_init(cmx); |
4274 | 0 | return JS_UNDEFINED; |
4275 | 0 | } |
4276 | 0 | return JS_UNDEFINED; |
4277 | 0 | } |
4278 | | |
4279 | | static JSValue colmx_multiply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4280 | 0 | { |
4281 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id); |
4282 | 0 | if (!cmx || !argc) return GF_JS_EXCEPTION(c); |
4283 | 0 | GF_ColorMatrix *with = JS_GetOpaque(argv[0], colmx_class_id); |
4284 | 0 | if (!cmx) return GF_JS_EXCEPTION(c); |
4285 | 0 | gf_cmx_multiply(cmx, with); |
4286 | 0 | return JS_DupValue(c, obj); |
4287 | 0 | } |
4288 | | |
4289 | | static Bool get_color(JSContext *c, JSValueConst obj, Double *a, Double *r, Double *g, Double *b) |
4290 | 0 | { |
4291 | 0 | JSValue v; |
4292 | 0 | int res; |
4293 | 0 | if (JS_IsArray(c, obj)) { |
4294 | 0 | u32 i, len; |
4295 | 0 | v = JS_GetPropertyStr(c, obj, "length"); |
4296 | 0 | res = JS_ToInt32(c, &len, v); |
4297 | 0 | JS_FreeValue(c, v); |
4298 | 0 | if (res) return GF_FALSE; |
4299 | 0 | if (len>4) len=4; |
4300 | 0 | for (i=0; i<len; i++) { |
4301 | 0 | Double d; |
4302 | 0 | v = JS_GetPropertyUint32(c, obj, i); |
4303 | 0 | res = JS_ToFloat64(c, &d, v); |
4304 | 0 | if (res) return GF_FALSE; |
4305 | 0 | JS_FreeValue(c, v); |
4306 | 0 | if (!i) *r = d; |
4307 | 0 | else if (i==1) *g = d; |
4308 | 0 | else if (i==2) *b = d; |
4309 | 0 | else *a = d; |
4310 | 0 | } |
4311 | 0 | return GF_TRUE; |
4312 | 0 | } |
4313 | 0 | v = JS_GetPropertyStr(c, obj, "r"); |
4314 | 0 | res = JS_ToFloat64(c, r, v); |
4315 | 0 | JS_FreeValue(c, v); |
4316 | 0 | if (res) return GF_FALSE; |
4317 | 0 | v = JS_GetPropertyStr(c, obj, "g"); |
4318 | 0 | res = JS_ToFloat64(c, g, v); |
4319 | 0 | JS_FreeValue(c, v); |
4320 | 0 | if (res) return GF_FALSE; |
4321 | 0 | v = JS_GetPropertyStr(c, obj, "b"); |
4322 | 0 | res = JS_ToFloat64(c, b, v); |
4323 | 0 | JS_FreeValue(c, v); |
4324 | 0 | if (res) return GF_FALSE; |
4325 | 0 | v = JS_GetPropertyStr(c, obj, "a"); |
4326 | 0 | JS_ToFloat64(c, a, v); |
4327 | 0 | JS_FreeValue(c, v); |
4328 | |
|
4329 | 0 | if (*r<0) *r=0; |
4330 | 0 | if (*g<0) *g=0; |
4331 | 0 | if (*b<0) *b=0; |
4332 | 0 | if (*a<0) *a=0; |
4333 | |
|
4334 | 0 | return GF_TRUE; |
4335 | 0 | } |
4336 | | static JSValue colmx_apply_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int) |
4337 | 0 | { |
4338 | 0 | GF_Color col; |
4339 | 0 | JSValue nobj; |
4340 | 0 | Double r=0, g=0, b=0, a=1.0; |
4341 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(obj, colmx_class_id); |
4342 | 0 | if (!cmx || !argc) return GF_JS_EXCEPTION(c); |
4343 | 0 | if (JS_IsString(argv[0])) { |
4344 | 0 | const char *str = JS_ToCString(c, argv[0]); |
4345 | 0 | col = gf_color_parse(str); |
4346 | 0 | JS_FreeCString(c, str); |
4347 | |
|
4348 | 0 | if (!use_int) { |
4349 | 0 | a = GF_COL_A(col); |
4350 | 0 | r = GF_COL_R(col); |
4351 | 0 | g = GF_COL_G(col); |
4352 | 0 | b = GF_COL_B(col); |
4353 | 0 | r/=255; |
4354 | 0 | g/=255; |
4355 | 0 | b/=255; |
4356 | 0 | a/=255; |
4357 | 0 | } |
4358 | |
|
4359 | 0 | } else if (JS_IsObject(argv[0])) { |
4360 | 0 | if (!get_color(c, argv[0], &a, &r, &g, &b)) |
4361 | 0 | return GF_JS_EXCEPTION(c); |
4362 | 0 | if (use_int) { |
4363 | 0 | r*=255; |
4364 | 0 | g*=255; |
4365 | 0 | b*=255; |
4366 | 0 | a*=255; |
4367 | 0 | if (a>255) a=255; |
4368 | 0 | if (r>255) r=255; |
4369 | 0 | if (g>255) g=255; |
4370 | 0 | if (b>255) b=255; |
4371 | 0 | col = GF_COL_ARGB(a, r, g, b); |
4372 | 0 | } |
4373 | 0 | } else { |
4374 | 0 | return GF_JS_EXCEPTION(c); |
4375 | 0 | } |
4376 | 0 | if (use_int) { |
4377 | 0 | GF_Color res = gf_cmx_apply(cmx, col); |
4378 | 0 | nobj = JS_NewObject(c); |
4379 | 0 | JS_SetPropertyStr(c, nobj, "r", JS_NewInt32(c, GF_COL_R(res)) ); |
4380 | 0 | JS_SetPropertyStr(c, nobj, "g", JS_NewInt32(c, GF_COL_G(res)) ); |
4381 | 0 | JS_SetPropertyStr(c, nobj, "b", JS_NewInt32(c, GF_COL_B(res)) ); |
4382 | 0 | JS_SetPropertyStr(c, nobj, "a", JS_NewInt32(c, GF_COL_A(res)) ); |
4383 | 0 | return nobj; |
4384 | 0 | } else { |
4385 | 0 | Fixed fr=FLT2FIX(r), fg=FLT2FIX(g), fb=FLT2FIX(b), fa=FLT2FIX(a); |
4386 | |
|
4387 | 0 | gf_cmx_apply_fixed(cmx, &fa, &fr, &fg, &fb); |
4388 | 0 | nobj = JS_NewObject(c); |
4389 | 0 | JS_SetPropertyStr(c, nobj, "r", JS_NewFloat64(c, FIX2FLT(fr)) ); |
4390 | 0 | JS_SetPropertyStr(c, nobj, "g", JS_NewFloat64(c, FIX2FLT(fg)) ); |
4391 | 0 | JS_SetPropertyStr(c, nobj, "b", JS_NewFloat64(c, FIX2FLT(fb)) ); |
4392 | 0 | JS_SetPropertyStr(c, nobj, "a", JS_NewFloat64(c, FIX2FLT(fa)) ); |
4393 | 0 | return nobj; |
4394 | 0 | } |
4395 | 0 | return GF_JS_EXCEPTION(c); |
4396 | 0 | } |
4397 | | static JSValue colmx_apply(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4398 | 0 | { |
4399 | 0 | return colmx_apply_color(c, obj, argc, argv, GF_TRUE); |
4400 | 0 | } |
4401 | | static JSValue colmx_applyf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4402 | 0 | { |
4403 | 0 | return colmx_apply_color(c, obj, argc, argv, GF_FALSE); |
4404 | 0 | } |
4405 | | |
4406 | | static const JSCFunctionListEntry colmx_funcs[] = |
4407 | | { |
4408 | | JS_CGETSET_MAGIC_DEF("rr", colmx_getProperty, colmx_setProperty, CMX_MRR), |
4409 | | JS_CGETSET_MAGIC_DEF("rg", colmx_getProperty, colmx_setProperty, CMX_MRG), |
4410 | | JS_CGETSET_MAGIC_DEF("rb", colmx_getProperty, colmx_setProperty, CMX_MRB), |
4411 | | JS_CGETSET_MAGIC_DEF("ra", colmx_getProperty, colmx_setProperty, CMX_MRA), |
4412 | | JS_CGETSET_MAGIC_DEF("tr", colmx_getProperty, colmx_setProperty, CMX_TR), |
4413 | | JS_CGETSET_MAGIC_DEF("gr", colmx_getProperty, colmx_setProperty, CMX_MGR), |
4414 | | JS_CGETSET_MAGIC_DEF("gg", colmx_getProperty, colmx_setProperty, CMX_MGG), |
4415 | | JS_CGETSET_MAGIC_DEF("gb", colmx_getProperty, colmx_setProperty, CMX_MGB), |
4416 | | JS_CGETSET_MAGIC_DEF("ga", colmx_getProperty, colmx_setProperty, CMX_MGA), |
4417 | | JS_CGETSET_MAGIC_DEF("tg", colmx_getProperty, colmx_setProperty, CMX_TG), |
4418 | | JS_CGETSET_MAGIC_DEF("br", colmx_getProperty, colmx_setProperty, CMX_MBR), |
4419 | | JS_CGETSET_MAGIC_DEF("bg", colmx_getProperty, colmx_setProperty, CMX_MBG), |
4420 | | JS_CGETSET_MAGIC_DEF("bb", colmx_getProperty, colmx_setProperty, CMX_MBB), |
4421 | | JS_CGETSET_MAGIC_DEF("ba", colmx_getProperty, colmx_setProperty, CMX_MBA), |
4422 | | JS_CGETSET_MAGIC_DEF("tb", colmx_getProperty, colmx_setProperty, CMX_TB), |
4423 | | JS_CGETSET_MAGIC_DEF("ar", colmx_getProperty, colmx_setProperty, CMX_MAR), |
4424 | | JS_CGETSET_MAGIC_DEF("ag", colmx_getProperty, colmx_setProperty, CMX_MAG), |
4425 | | JS_CGETSET_MAGIC_DEF("ab", colmx_getProperty, colmx_setProperty, CMX_MAB), |
4426 | | JS_CGETSET_MAGIC_DEF("aa", colmx_getProperty, colmx_setProperty, CMX_MAA), |
4427 | | JS_CGETSET_MAGIC_DEF("ta", colmx_getProperty, colmx_setProperty, CMX_TA), |
4428 | | JS_CGETSET_MAGIC_DEF("identity", colmx_getProperty, colmx_setProperty, CMX_IDENTITY), |
4429 | | |
4430 | | JS_CFUNC_DEF("multiply", 0, colmx_multiply), |
4431 | | JS_CFUNC_DEF("apply", 0, colmx_apply), |
4432 | | JS_CFUNC_DEF("applyf", 0, colmx_applyf), |
4433 | | }; |
4434 | | |
4435 | | |
4436 | | |
4437 | | static void path_finalize(JSRuntime *rt, JSValue obj) |
4438 | 0 | { |
4439 | 0 | GF_Path *path = JS_GetOpaque(obj, path_class_id); |
4440 | 0 | if (!path) return; |
4441 | 0 | gf_path_del(path); |
4442 | 0 | } |
4443 | | JSClassDef path_class = { |
4444 | | "Path", |
4445 | | .finalizer = path_finalize |
4446 | | }; |
4447 | | |
4448 | | static JSValue path_close_reset(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 opt) |
4449 | 0 | { |
4450 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4451 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4452 | 0 | if (opt==0) { |
4453 | 0 | gf_path_close(gp); |
4454 | 0 | return JS_DupValue(c, obj); |
4455 | 0 | } |
4456 | 0 | if (opt==1) { |
4457 | 0 | gf_path_reset(gp); |
4458 | 0 | return JS_DupValue(c, obj); |
4459 | 0 | } |
4460 | 0 | if (opt==2) { |
4461 | 0 | JSValue nobj = JS_NewObjectClass(c, path_class_id); |
4462 | 0 | if (JS_IsException(nobj)) return nobj; |
4463 | 0 | JS_SetOpaque(nobj, gf_path_clone(gp)); |
4464 | 0 | return nobj; |
4465 | 0 | } |
4466 | 0 | return GF_JS_EXCEPTION(c); |
4467 | 0 | } |
4468 | | static JSValue path_reset(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4469 | 0 | { |
4470 | 0 | return path_close_reset(c, obj, argc, argv, 1); |
4471 | 0 | } |
4472 | | static JSValue path_close(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4473 | 0 | { |
4474 | 0 | return path_close_reset(c, obj, argc, argv, 0); |
4475 | 0 | } |
4476 | | static JSValue path_clone(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4477 | 0 | { |
4478 | 0 | return path_close_reset(c, obj, argc, argv, 2); |
4479 | 0 | } |
4480 | | static JSValue path_line_move(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_line) |
4481 | 0 | { |
4482 | 0 | Double x=0, y=0; |
4483 | 0 | GF_Err e; |
4484 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4485 | 0 | if (!gp || (argc<2)) return GF_JS_EXCEPTION(c); |
4486 | 0 | if (JS_ToFloat64(c, &x, argv[0])) return GF_JS_EXCEPTION(c); |
4487 | 0 | if (JS_ToFloat64(c, &y, argv[1])) return GF_JS_EXCEPTION(c); |
4488 | 0 | if (is_line) |
4489 | 0 | e = gf_path_add_line_to(gp, FLT2FIX(x), FLT2FIX(y)); |
4490 | 0 | else |
4491 | 0 | e = gf_path_add_move_to(gp, FLT2FIX(x), FLT2FIX(y)); |
4492 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4493 | 0 | return JS_DupValue(c, obj); |
4494 | 0 | } |
4495 | | static JSValue path_line_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4496 | 0 | { |
4497 | 0 | return path_line_move(c, obj, argc, argv, GF_TRUE); |
4498 | 0 | } |
4499 | | static JSValue path_move_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4500 | 0 | { |
4501 | 0 | return path_line_move(c, obj, argc, argv, GF_FALSE); |
4502 | 0 | } |
4503 | | static JSValue path_cubic_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4504 | 0 | { |
4505 | 0 | Double c1_x=0, c1_y=0, c2_x=0, c2_y=0, x=0, y=0; |
4506 | 0 | GF_Err e; |
4507 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4508 | 0 | if (!gp || (argc<6)) return GF_JS_EXCEPTION(c); |
4509 | 0 | if (JS_ToFloat64(c, &c1_x, argv[0])) return GF_JS_EXCEPTION(c); |
4510 | 0 | if (JS_ToFloat64(c, &c1_y, argv[1])) return GF_JS_EXCEPTION(c); |
4511 | 0 | if (JS_ToFloat64(c, &c2_x, argv[2])) return GF_JS_EXCEPTION(c); |
4512 | 0 | if (JS_ToFloat64(c, &c2_y, argv[3])) return GF_JS_EXCEPTION(c); |
4513 | 0 | if (JS_ToFloat64(c, &x, argv[4])) return GF_JS_EXCEPTION(c); |
4514 | 0 | if (JS_ToFloat64(c, &y, argv[5])) return GF_JS_EXCEPTION(c); |
4515 | 0 | e = gf_path_add_cubic_to(gp, FLT2FIX(c1_x), FLT2FIX(c1_y), FLT2FIX(c2_x), FLT2FIX(c2_y), FLT2FIX(x), FLT2FIX(y)); |
4516 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4517 | 0 | return JS_DupValue(c, obj); |
4518 | 0 | } |
4519 | | static JSValue path_quadratic_to(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4520 | 0 | { |
4521 | 0 | Double c_x=0, c_y=0, x=0, y=0; |
4522 | 0 | GF_Err e; |
4523 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4524 | 0 | if (!gp || (argc<4)) return GF_JS_EXCEPTION(c); |
4525 | 0 | if (JS_ToFloat64(c, &c_x, argv[0])) return GF_JS_EXCEPTION(c); |
4526 | 0 | if (JS_ToFloat64(c, &c_y, argv[1])) return GF_JS_EXCEPTION(c); |
4527 | 0 | if (JS_ToFloat64(c, &x, argv[2])) return GF_JS_EXCEPTION(c); |
4528 | 0 | if (JS_ToFloat64(c, &y, argv[3])) return GF_JS_EXCEPTION(c); |
4529 | 0 | e = gf_path_add_quadratic_to(gp, FLT2FIX(c_x), FLT2FIX(c_y), FLT2FIX(x), FLT2FIX(y)); |
4530 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4531 | 0 | return JS_DupValue(c, obj); |
4532 | 0 | } |
4533 | | |
4534 | | static JSValue path_rect(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4535 | 0 | { |
4536 | 0 | Double ox=0, oy=0, w=0, h=0; |
4537 | 0 | s32 idx=0; |
4538 | 0 | GF_Err e; |
4539 | |
|
4540 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4541 | 0 | if (!gp || (argc<3)) return GF_JS_EXCEPTION(c); |
4542 | | |
4543 | 0 | if (JS_IsObject(argv[0])) { |
4544 | 0 | JSValue v; |
4545 | 0 | #define GETD(_arg, _name, _res)\ |
4546 | 0 | if (! JS_IsObject(_arg)) return GF_JS_EXCEPTION(c);\ |
4547 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
4548 | 0 | JS_ToFloat64(c, &_res, v);\ |
4549 | 0 | JS_FreeValue(c, v);\ |
4550 | 0 |
|
4551 | 0 | GETD(argv[0], "x", ox); |
4552 | 0 | GETD(argv[0], "y", oy); |
4553 | 0 | #undef GETD |
4554 | |
|
4555 | 0 | idx=1; |
4556 | 0 | } else if (argc>=4) { |
4557 | 0 | if (JS_ToFloat64(c, &ox, argv[0])) return GF_JS_EXCEPTION(c); |
4558 | 0 | if (JS_ToFloat64(c, &oy, argv[1])) return GF_JS_EXCEPTION(c); |
4559 | 0 | idx=2; |
4560 | 0 | } else { |
4561 | 0 | return GF_JS_EXCEPTION(c); |
4562 | 0 | } |
4563 | 0 | if (JS_ToFloat64(c, &w, argv[idx])) return GF_JS_EXCEPTION(c); |
4564 | 0 | if (JS_ToFloat64(c, &h, argv[idx+1])) return GF_JS_EXCEPTION(c); |
4565 | 0 | if ((argc>idx+2) && JS_ToBool(c, argv[idx+2])) { |
4566 | 0 | e = gf_path_add_rect_center(gp, FLT2FIX(ox), FLT2FIX(oy), FLT2FIX(w), FLT2FIX(h)); |
4567 | 0 | } else { |
4568 | 0 | e = gf_path_add_rect(gp, FLT2FIX(ox), FLT2FIX(oy), FLT2FIX(w), FLT2FIX(h)); |
4569 | 0 | } |
4570 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4571 | 0 | return JS_DupValue(c, obj); |
4572 | 0 | } |
4573 | | |
4574 | | static JSValue path_ellipse(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4575 | 0 | { |
4576 | 0 | Double cx=0, cy=0, a_axis=0, b_axis=0; |
4577 | 0 | GF_Err e; |
4578 | 0 | Bool valid = GF_TRUE; |
4579 | 0 | u32 idx=0; |
4580 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4581 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4582 | 0 | if (argc==3) { |
4583 | 0 | JSValue v; |
4584 | 0 | #define GETD(_arg, _name, _res)\ |
4585 | 0 | if (! JS_IsObject(_arg)) return GF_JS_EXCEPTION(c);\ |
4586 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
4587 | 0 | if (JS_ToFloat64(c, &_res, v)) valid = GF_FALSE;\ |
4588 | 0 | JS_FreeValue(c, v);\ |
4589 | 0 |
|
4590 | 0 | GETD(argv[0], "x", cx); |
4591 | 0 | GETD(argv[0], "y", cy); |
4592 | 0 | #undef GETD |
4593 | |
|
4594 | 0 | idx=1; |
4595 | 0 | } else if (argc==4) { |
4596 | 0 | if (JS_ToFloat64(c, &cx, argv[0])) return GF_JS_EXCEPTION(c); |
4597 | 0 | if (JS_ToFloat64(c, &cy, argv[1])) return GF_JS_EXCEPTION(c); |
4598 | 0 | idx=2; |
4599 | 0 | } else { |
4600 | 0 | return GF_JS_EXCEPTION(c); |
4601 | 0 | } |
4602 | 0 | if (!valid) return GF_JS_EXCEPTION(c); |
4603 | | |
4604 | 0 | if (JS_ToFloat64(c, &a_axis, argv[idx])) return GF_JS_EXCEPTION(c); |
4605 | 0 | if (JS_ToFloat64(c, &b_axis, argv[idx+1])) return GF_JS_EXCEPTION(c); |
4606 | 0 | e = gf_path_add_ellipse(gp, FLT2FIX(cx), FLT2FIX(cy), FLT2FIX(a_axis), FLT2FIX(b_axis)); |
4607 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4608 | 0 | return JS_DupValue(c, obj); |
4609 | 0 | } |
4610 | | |
4611 | | static JSValue path_bezier(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4612 | 0 | { |
4613 | 0 | GF_Err e; |
4614 | 0 | s32 i; |
4615 | 0 | GF_Point2D *pts; |
4616 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4617 | 0 | if (!gp || (argc<3)) return GF_JS_EXCEPTION(c); |
4618 | 0 | pts = gf_malloc(sizeof(GF_Point2D)* argc); |
4619 | 0 | memset(pts, 0, sizeof(GF_Point2D)* argc); |
4620 | 0 | for (i=0; i<argc; i++) { |
4621 | 0 | JSValue v; |
4622 | 0 | Double d; |
4623 | 0 | if (! JS_IsObject(argv[i])) |
4624 | 0 | continue; |
4625 | 0 | v = JS_GetPropertyStr(c, argv[i], "x"); |
4626 | 0 | JS_ToFloat64(c, &d, v); |
4627 | 0 | pts[i].x = FLT2FIX(d); |
4628 | 0 | JS_FreeValue(c, v); |
4629 | 0 | v = JS_GetPropertyStr(c, argv[i], "y"); |
4630 | 0 | JS_ToFloat64(c, &d, v); |
4631 | 0 | pts[i].x = FLT2FIX(d); |
4632 | 0 | JS_FreeValue(c, v); |
4633 | 0 | } |
4634 | 0 | e = gf_path_add_bezier(gp, pts, argc); |
4635 | 0 | gf_free(pts); |
4636 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4637 | 0 | return JS_DupValue(c, obj); |
4638 | 0 | } |
4639 | | |
4640 | | static JSValue path_arc_bifs(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4641 | 0 | { |
4642 | 0 | Double end_x=0, end_y=0, fa_x=0, fa_y=0, fb_x=0, fb_y=0; |
4643 | 0 | Bool cw_flag = GF_FALSE; |
4644 | 0 | GF_Err e; |
4645 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4646 | 0 | if (!gp || (argc<6)) return GF_JS_EXCEPTION(c); |
4647 | 0 | if (JS_ToFloat64(c, &end_x, argv[0])) return GF_JS_EXCEPTION(c); |
4648 | 0 | if (JS_ToFloat64(c, &end_y, argv[1])) return GF_JS_EXCEPTION(c); |
4649 | 0 | if (JS_ToFloat64(c, &fa_x, argv[2])) return GF_JS_EXCEPTION(c); |
4650 | 0 | if (JS_ToFloat64(c, &fa_y, argv[3])) return GF_JS_EXCEPTION(c); |
4651 | 0 | if (JS_ToFloat64(c, &fb_x, argv[4])) return GF_JS_EXCEPTION(c); |
4652 | 0 | if (JS_ToFloat64(c, &fb_y, argv[5])) return GF_JS_EXCEPTION(c); |
4653 | 0 | if (argc>6) cw_flag = JS_ToBool(c, argv[6]); |
4654 | |
|
4655 | 0 | 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); |
4656 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4657 | 0 | return JS_DupValue(c, obj); |
4658 | 0 | } |
4659 | | |
4660 | | |
4661 | | static JSValue path_arc_svg(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4662 | 0 | { |
4663 | 0 | Double end_x=0, end_y=0, r_x=0, r_y=0, x_axis_rotation=0; |
4664 | 0 | Bool large_arc_flag=GF_FALSE, sweep_flag=GF_FALSE; |
4665 | 0 | GF_Err e; |
4666 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4667 | 0 | if (!gp || (argc<4)) return GF_JS_EXCEPTION(c); |
4668 | 0 | if (JS_ToFloat64(c, &end_x, argv[0])) return GF_JS_EXCEPTION(c); |
4669 | 0 | if (JS_ToFloat64(c, &end_y, argv[1])) return GF_JS_EXCEPTION(c); |
4670 | 0 | if (JS_ToFloat64(c, &r_x, argv[2])) return GF_JS_EXCEPTION(c); |
4671 | 0 | if (JS_ToFloat64(c, &r_y, argv[3])) return GF_JS_EXCEPTION(c); |
4672 | 0 | if (argc>4) { |
4673 | 0 | if (JS_ToFloat64(c, &x_axis_rotation, argv[4])) return GF_JS_EXCEPTION(c); |
4674 | 0 | if (argc>5) large_arc_flag = JS_ToBool(c, argv[5]); |
4675 | 0 | if (argc>6) sweep_flag = JS_ToBool(c, argv[6]); |
4676 | 0 | } |
4677 | 0 | 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); |
4678 | |
|
4679 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4680 | 0 | return JS_DupValue(c, obj); |
4681 | 0 | } |
4682 | | |
4683 | | static JSValue path_arc(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4684 | 0 | { |
4685 | 0 | Double radius=0, start=0, end=0; |
4686 | 0 | u32 close=0; |
4687 | 0 | GF_Err e; |
4688 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4689 | 0 | if (!gp || (argc<3)) return GF_JS_EXCEPTION(c); |
4690 | 0 | if (JS_ToFloat64(c, &radius, argv[0])) return GF_JS_EXCEPTION(c); |
4691 | 0 | if (JS_ToFloat64(c, &start, argv[1])) return GF_JS_EXCEPTION(c); |
4692 | 0 | if (JS_ToFloat64(c, &end, argv[2])) return GF_JS_EXCEPTION(c); |
4693 | 0 | if (argc>3) |
4694 | 0 | if (JS_ToInt32(c, &close, argv[3])) return GF_JS_EXCEPTION(c); |
4695 | 0 | e = gf_path_add_arc(gp, FLT2FIX(radius), FLT2FIX(start), FLT2FIX(end), close); |
4696 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4697 | 0 | return JS_DupValue(c, obj); |
4698 | 0 | } |
4699 | | |
4700 | | static JSValue path_add_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4701 | 0 | { |
4702 | 0 | GF_Err e; |
4703 | 0 | GF_Matrix2D *mx=NULL; |
4704 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4705 | 0 | if (!gp || !argc) return GF_JS_EXCEPTION(c); |
4706 | 0 | GF_Path *subgp = JS_GetOpaque(argv[0], path_class_id); |
4707 | 0 | if (!subgp) return GF_JS_EXCEPTION(c); |
4708 | 0 | if (argc>1) |
4709 | 0 | mx = JS_GetOpaque(argv[1], mx2d_class_id); |
4710 | 0 | e = gf_path_add_subpath(gp, subgp, mx); |
4711 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4712 | 0 | return JS_DupValue(c, obj); |
4713 | 0 | } |
4714 | | |
4715 | | static JSValue path_flatten(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4716 | 0 | { |
4717 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4718 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4719 | 0 | gf_path_flatten(gp); |
4720 | 0 | return JS_DupValue(c, obj); |
4721 | 0 | } |
4722 | | static JSValue path_get_flat(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4723 | 0 | { |
4724 | 0 | JSValue nobj; |
4725 | 0 | GF_Path *gp_flat; |
4726 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4727 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4728 | 0 | gp_flat = gf_path_get_flatten(gp); |
4729 | 0 | if (!gp) return JS_NULL; |
4730 | 0 | nobj = JS_NewObjectClass(c, path_class_id); |
4731 | 0 | if (JS_IsException(nobj)) return nobj; |
4732 | 0 | JS_SetOpaque(nobj, gp_flat); |
4733 | 0 | return nobj; |
4734 | 0 | } |
4735 | | |
4736 | | static JSValue path_point_over(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4737 | 0 | { |
4738 | 0 | Double x, y; |
4739 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4740 | 0 | if (!gp || !argc) return GF_JS_EXCEPTION(c); |
4741 | 0 | if (argc==1) { |
4742 | 0 | Double d; |
4743 | 0 | int res; |
4744 | 0 | JSValue v; |
4745 | 0 | if (!JS_IsObject(argv[0])) return GF_JS_EXCEPTION(c); |
4746 | 0 | #define GETIT(_arg, _name, _var) \ |
4747 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
4748 | 0 | res = JS_ToFloat64(c, &d, v);\ |
4749 | 0 | JS_FreeValue(c, v);\ |
4750 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
4751 | 0 | _var = FLT2FIX(d);\ |
4752 | 0 |
|
4753 | 0 | GETIT(argv[0], "x", x) |
4754 | 0 | GETIT(argv[0], "y", y) |
4755 | 0 | #undef GETIT |
4756 | 0 | } else if (argc==2) { |
4757 | 0 | if (JS_ToFloat64(c, &x, argv[0])) return GF_JS_EXCEPTION(c); |
4758 | 0 | if (JS_ToFloat64(c, &y, argv[1])) return GF_JS_EXCEPTION(c); |
4759 | 0 | } else { |
4760 | 0 | return GF_JS_EXCEPTION(c); |
4761 | 0 | } |
4762 | 0 | return gf_path_point_over(gp, FLT2FIX(x), FLT2FIX(y)) ? JS_TRUE : JS_FALSE; |
4763 | 0 | } |
4764 | | |
4765 | | |
4766 | | static JSValue path_outline(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4767 | 0 | { |
4768 | 0 | GF_Path *outline; |
4769 | 0 | GF_PenSettings pen; |
4770 | 0 | GF_DashSettings dash; |
4771 | 0 | JSValue v, dashes; |
4772 | 0 | Double d; |
4773 | 0 | int i, res; |
4774 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4775 | 0 | if (!gp || !argc || !JS_IsObject(argv[0]) ) return GF_JS_EXCEPTION(c); |
4776 | 0 | memset(&pen, 0, sizeof(GF_PenSettings)); |
4777 | |
|
4778 | 0 | #define GETIT_F(_arg, _name, _var) \ |
4779 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
4780 | 0 | if (!JS_IsUndefined(v)) {\ |
4781 | 0 | res = JS_ToFloat64(c, &d, v);\ |
4782 | 0 | JS_FreeValue(c, v);\ |
4783 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
4784 | 0 | _var = FLT2FIX(d);\ |
4785 | 0 | }\ |
4786 | 0 |
|
4787 | 0 | #define GETIT_I(_arg, _name, _var) \ |
4788 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
4789 | 0 | if (!JS_IsUndefined(v)) {\ |
4790 | 0 | res = JS_ToInt32(c, &i, v);\ |
4791 | 0 | JS_FreeValue(c, v);\ |
4792 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
4793 | 0 | _var = i;\ |
4794 | 0 | }\ |
4795 | 0 |
|
4796 | 0 | GETIT_F(argv[0], "width", pen.width); |
4797 | 0 | GETIT_F(argv[0], "miter", pen.miterLimit); |
4798 | 0 | GETIT_F(argv[0], "offset", pen.dash_offset); |
4799 | 0 | GETIT_F(argv[0], "length", pen.path_length); |
4800 | 0 | GETIT_I(argv[0], "cap", pen.cap); |
4801 | 0 | GETIT_I(argv[0], "join", pen.join); |
4802 | 0 | GETIT_I(argv[0], "align", pen.align); |
4803 | 0 | GETIT_I(argv[0], "dash", pen.dash); |
4804 | | |
4805 | |
|
4806 | 0 | #undef GETTIT_F |
4807 | 0 | #undef GETTIT_I |
4808 | |
|
4809 | 0 | dash.num_dash = 0; |
4810 | 0 | dash.dashes = NULL; |
4811 | 0 | dashes = JS_GetPropertyStr(c, argv[0], "dashes"); |
4812 | 0 | if (JS_IsArray(c, dashes) && !JS_IsNull(v)) { |
4813 | 0 | v = JS_GetPropertyStr(c, dashes, "length"); |
4814 | 0 | JS_ToInt32(c, &dash.num_dash, v); |
4815 | 0 | JS_FreeValue(c, v); |
4816 | 0 | if (dash.num_dash) { |
4817 | 0 | pen.dash_set = ‐ |
4818 | 0 | dash.dashes = gf_malloc(sizeof(Fixed)*dash.num_dash); |
4819 | 0 | for (i=0; i<(int) dash.num_dash; i++) { |
4820 | 0 | v = JS_GetPropertyUint32(c, dashes, i); |
4821 | 0 | JS_ToFloat64(c, &d, v); |
4822 | 0 | dash.dashes[i] = FLT2FIX(d); |
4823 | 0 | JS_FreeValue(c, v); |
4824 | 0 | } |
4825 | 0 | if (!pen.dash) |
4826 | 0 | pen.dash = GF_DASH_STYLE_CUSTOM; |
4827 | 0 | } |
4828 | 0 | } |
4829 | 0 | JS_FreeValue(c, dashes); |
4830 | |
|
4831 | 0 | outline = gf_path_get_outline(gp, pen); |
4832 | 0 | if (dash.dashes) gf_free(dash.dashes); |
4833 | |
|
4834 | 0 | if (!outline) return GF_JS_EXCEPTION(c); |
4835 | 0 | v = JS_NewObjectClass(c, path_class_id); |
4836 | 0 | JS_SetOpaque(v, outline); |
4837 | 0 | return v; |
4838 | 0 | } |
4839 | | |
4840 | | |
4841 | | static JSValue path_transform(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
4842 | 0 | { |
4843 | 0 | GF_Err e; |
4844 | 0 | GF_Matrix2D *mx=NULL; |
4845 | 0 | GF_Path *path; |
4846 | 0 | JSValue v; |
4847 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4848 | 0 | if (!gp || !argc) return GF_JS_EXCEPTION(c); |
4849 | 0 | mx = JS_GetOpaque(argv[0], mx2d_class_id); |
4850 | |
|
4851 | 0 | path = gf_path_new(); |
4852 | 0 | if (!path) return GF_JS_EXCEPTION(c); |
4853 | 0 | e = gf_path_add_subpath(path, gp, mx); |
4854 | 0 | if (e) { |
4855 | 0 | gf_path_del(path); |
4856 | 0 | return GF_JS_EXCEPTION(c); |
4857 | 0 | } |
4858 | 0 | v = JS_NewObjectClass(c, path_class_id); |
4859 | 0 | JS_SetOpaque(v, path); |
4860 | 0 | return v; |
4861 | 0 | } |
4862 | | |
4863 | | enum |
4864 | | { |
4865 | | PATH_EMPTY=0, |
4866 | | PATH_ZERO_NONZERO, |
4867 | | PATH_FILL_EVEN, |
4868 | | PATH_BOUNDS, |
4869 | | PATH_CONTROL_BOUNDS, |
4870 | | PATH_IS_RECTANGLE |
4871 | | }; |
4872 | | |
4873 | | |
4874 | | static JSValue path_bounds_ex(JSContext *c, GF_Path *gp, Bool is_ctrl) |
4875 | 0 | { |
4876 | 0 | JSValue nobj; |
4877 | 0 | GF_Err e; |
4878 | 0 | GF_Rect rc; |
4879 | 0 | if (is_ctrl) |
4880 | 0 | e = gf_path_get_control_bounds(gp, &rc); |
4881 | 0 | else |
4882 | 0 | e = gf_path_get_bounds(gp, &rc); |
4883 | 0 | if (e) return GF_JS_EXCEPTION(c); |
4884 | 0 | nobj = JS_NewObject(c); |
4885 | 0 | JS_SetPropertyStr(c, nobj, "x", JS_NewFloat64(c, rc.x)); |
4886 | 0 | JS_SetPropertyStr(c, nobj, "y", JS_NewFloat64(c, rc.y)); |
4887 | 0 | JS_SetPropertyStr(c, nobj, "w", JS_NewFloat64(c, rc.width)); |
4888 | 0 | JS_SetPropertyStr(c, nobj, "h", JS_NewFloat64(c, rc.height)); |
4889 | 0 | return nobj; |
4890 | 0 | } |
4891 | | static Bool path_check_rect(GF_Path *gp) |
4892 | 0 | { |
4893 | 0 | u32 i; |
4894 | 0 | if (gp->n_contours != 1) return GF_FALSE; |
4895 | 0 | if (gp->contours[0] != 4) return GF_FALSE; |
4896 | | |
4897 | 0 | for (i=0; i<4; i++) { |
4898 | 0 | if ((gp->points[i].x != gp->points[0].x) && (gp->points[i].x != gp->points[2].x)) return GF_FALSE; |
4899 | 0 | if ((gp->points[i].y != gp->points[0].y) && (gp->points[i].y != gp->points[2].y)) return GF_FALSE; |
4900 | 0 | } |
4901 | 0 | return GF_TRUE; |
4902 | 0 | } |
4903 | | |
4904 | | static JSValue path_getProperty(JSContext *c, JSValueConst obj, int magic) |
4905 | 0 | { |
4906 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4907 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4908 | 0 | switch (magic) { |
4909 | 0 | case PATH_EMPTY: return JS_NewBool(c, gf_path_is_empty(gp)); |
4910 | 0 | case PATH_ZERO_NONZERO: return JS_NewBool(c, gp->flags & GF_PATH_FILL_ZERO_NONZERO); |
4911 | 0 | case PATH_FILL_EVEN: return JS_NewBool(c, gp->flags & GF_PATH_FILL_EVEN); |
4912 | 0 | case PATH_BOUNDS: return path_bounds_ex(c, gp, GF_FALSE); |
4913 | 0 | case PATH_CONTROL_BOUNDS: return path_bounds_ex(c, gp, GF_TRUE); |
4914 | 0 | case PATH_IS_RECTANGLE: return path_check_rect(gp) ? JS_TRUE : JS_FALSE; |
4915 | 0 | } |
4916 | 0 | return JS_UNDEFINED; |
4917 | 0 | } |
4918 | | static JSValue path_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
4919 | 0 | { |
4920 | 0 | GF_Path *gp = JS_GetOpaque(obj, path_class_id); |
4921 | 0 | if (!gp) return GF_JS_EXCEPTION(c); |
4922 | 0 | switch (magic) { |
4923 | 0 | case PATH_ZERO_NONZERO: |
4924 | 0 | if (JS_ToBool(c, value)) |
4925 | 0 | gp->flags |= GF_PATH_FILL_ZERO_NONZERO; |
4926 | 0 | else |
4927 | 0 | gp->flags &= ~GF_PATH_FILL_ZERO_NONZERO; |
4928 | 0 | break; |
4929 | 0 | case PATH_FILL_EVEN: |
4930 | 0 | if (JS_ToBool(c, value)) |
4931 | 0 | gp->flags |= GF_PATH_FILL_EVEN; |
4932 | 0 | else |
4933 | 0 | gp->flags &= ~GF_PATH_FILL_EVEN; |
4934 | 0 | break; |
4935 | 0 | } |
4936 | 0 | return JS_UNDEFINED; |
4937 | 0 | } |
4938 | | static JSValue path_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
4939 | 0 | { |
4940 | 0 | JSValue obj; |
4941 | 0 | GF_Path *path = gf_path_new(); |
4942 | 0 | if (!path) return GF_JS_EXCEPTION(c); |
4943 | 0 | obj = JS_NewObjectClass(c, path_class_id); |
4944 | 0 | if (JS_IsException(obj)) return obj; |
4945 | 0 | JS_SetOpaque(obj, path); |
4946 | 0 | return obj; |
4947 | 0 | } |
4948 | | static const JSCFunctionListEntry path_funcs[] = |
4949 | | { |
4950 | | JS_CGETSET_MAGIC_DEF("empty", path_getProperty, NULL, PATH_EMPTY), |
4951 | | JS_CGETSET_MAGIC_DEF("zero_fill", path_getProperty, path_setProperty, PATH_ZERO_NONZERO), |
4952 | | JS_CGETSET_MAGIC_DEF("even_fill", path_getProperty, path_setProperty, PATH_FILL_EVEN), |
4953 | | JS_CGETSET_MAGIC_DEF("bounds", path_getProperty, NULL, PATH_BOUNDS), |
4954 | | JS_CGETSET_MAGIC_DEF("ctrl_bounds", path_getProperty, NULL, PATH_CONTROL_BOUNDS), |
4955 | | JS_CGETSET_MAGIC_DEF("is_rectangle", path_getProperty, NULL, PATH_IS_RECTANGLE), |
4956 | | |
4957 | | JS_CFUNC_DEF("point_over", 0, path_point_over), |
4958 | | JS_CFUNC_DEF("get_flatten", 0, path_get_flat), |
4959 | | JS_CFUNC_DEF("flatten", 0, path_flatten), |
4960 | | JS_CFUNC_DEF("add_path", 0, path_add_path), |
4961 | | JS_CFUNC_DEF("arc", 0, path_arc), |
4962 | | JS_CFUNC_DEF("arc_svg", 0, path_arc_svg), |
4963 | | JS_CFUNC_DEF("arc_bifs", 0, path_arc_bifs), |
4964 | | JS_CFUNC_DEF("bezier", 0, path_bezier), |
4965 | | JS_CFUNC_DEF("ellipse", 0, path_ellipse), |
4966 | | JS_CFUNC_DEF("rectangle", 0, path_rect), |
4967 | | JS_CFUNC_DEF("quadratic_to", 0, path_quadratic_to), |
4968 | | JS_CFUNC_DEF("cubic_to", 0, path_cubic_to), |
4969 | | JS_CFUNC_DEF("line_to", 0, path_line_to), |
4970 | | JS_CFUNC_DEF("move_to", 0, path_move_to), |
4971 | | JS_CFUNC_DEF("clone", 0, path_clone), |
4972 | | JS_CFUNC_DEF("reset", 0, path_reset), |
4973 | | JS_CFUNC_DEF("close", 0, path_close), |
4974 | | JS_CFUNC_DEF("outline", 0, path_outline), |
4975 | | JS_CFUNC_DEF("transform", 0, path_transform), |
4976 | | |
4977 | | }; |
4978 | | |
4979 | | |
4980 | | static void stencil_finalize(JSRuntime *rt, JSValue obj) |
4981 | 0 | { |
4982 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
4983 | 0 | if (!stencil) return; |
4984 | 0 | gf_evg_stencil_delete(stencil); |
4985 | 0 | } |
4986 | | JSClassDef stencil_class = { |
4987 | | "Stencil", |
4988 | | .finalizer = stencil_finalize |
4989 | | }; |
4990 | | |
4991 | | enum |
4992 | | { |
4993 | | STENCIL_SOLID, |
4994 | | STENCIL_CMX, |
4995 | | STENCIL_MAT, |
4996 | | STENCIL_GRADMOD, |
4997 | | STENCIL_MAT_AUTO, |
4998 | | }; |
4999 | | |
5000 | | static JSValue stencil_set_linear(JSContext *c, GF_EVGStencil *stencil, int argc, JSValueConst *argv) |
5001 | 0 | { |
5002 | 0 | int res; |
5003 | 0 | JSValue v; |
5004 | 0 | Double d; |
5005 | 0 | Fixed start_x=0, start_y=0, end_x=0, end_y=0; |
5006 | 0 | s32 idx=0; |
5007 | 0 | if (argc<2) return GF_JS_EXCEPTION(c); |
5008 | | |
5009 | 0 | #define GETIT(_arg, _name, _var) \ |
5010 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
5011 | 0 | res = JS_ToFloat64(c, &d, v);\ |
5012 | 0 | JS_FreeValue(c, v);\ |
5013 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
5014 | 0 | _var = FLT2FIX(d);\ |
5015 | 0 |
|
5016 | 0 | if (JS_IsObject(argv[0])) { |
5017 | 0 | GETIT(argv[0], "x", start_x) |
5018 | 0 | GETIT(argv[0], "y", start_y) |
5019 | 0 | idx=1; |
5020 | 0 | } else { |
5021 | 0 | if (JS_ToFloat64(c, &d, argv[0])) return GF_JS_EXCEPTION(c); |
5022 | 0 | start_x = FLT2FIX(d); |
5023 | 0 | if (JS_ToFloat64(c, &d, argv[1])) return GF_JS_EXCEPTION(c); |
5024 | 0 | start_y = FLT2FIX(d); |
5025 | 0 | idx=2; |
5026 | 0 | } |
5027 | 0 | if (argc<=idx) { |
5028 | 0 | end_x = start_x; |
5029 | 0 | end_y = start_y; |
5030 | 0 | start_x = 0; |
5031 | 0 | start_y = 0; |
5032 | 0 | } else if (JS_IsObject(argv[idx])) { |
5033 | 0 | GETIT(argv[idx], "x", end_x) |
5034 | 0 | GETIT(argv[idx], "y", end_y) |
5035 | 0 | } else if (argc>idx+1) { |
5036 | 0 | if (JS_ToFloat64(c, &d, argv[idx])) return GF_JS_EXCEPTION(c); |
5037 | 0 | end_x = FLT2FIX(d); |
5038 | 0 | if (JS_ToFloat64(c, &d, argv[idx+1])) return GF_JS_EXCEPTION(c); |
5039 | 0 | end_y = FLT2FIX(d); |
5040 | 0 | } |
5041 | 0 | #undef GETIT |
5042 | 0 | gf_evg_stencil_set_linear_gradient(stencil, start_x, start_y, end_x, end_y); |
5043 | 0 | return JS_UNDEFINED; |
5044 | 0 | } |
5045 | | |
5046 | | static JSValue stencil_set_radial(JSContext *c, GF_EVGStencil *stencil, int argc, JSValueConst *argv) |
5047 | 0 | { |
5048 | 0 | int res; |
5049 | 0 | JSValue v; |
5050 | 0 | Double d; |
5051 | 0 | Fixed cx=0, cy=0, fx=0, fy=0, rx=0, ry=0; |
5052 | 0 | s32 idx=0; |
5053 | 0 | if (argc<3) return GF_JS_EXCEPTION(c); |
5054 | | |
5055 | 0 | #define GETIT(_arg, _name, _var) \ |
5056 | 0 | v = JS_GetPropertyStr(c, _arg, _name);\ |
5057 | 0 | res = JS_ToFloat64(c, &d, v);\ |
5058 | 0 | JS_FreeValue(c, v);\ |
5059 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
5060 | 0 | _var = FLT2FIX(d);\ |
5061 | 0 |
|
5062 | 0 | if (JS_IsObject(argv[0])) { |
5063 | 0 | GETIT(argv[0], "x", cx) |
5064 | 0 | GETIT(argv[0], "y", cy) |
5065 | 0 | idx+=1; |
5066 | 0 | } else { |
5067 | 0 | if (JS_ToFloat64(c, &d, argv[0])) return GF_JS_EXCEPTION(c); |
5068 | 0 | cx = FLT2FIX(d); |
5069 | 0 | if (JS_ToFloat64(c, &d, argv[1])) return GF_JS_EXCEPTION(c); |
5070 | 0 | cy = FLT2FIX(d); |
5071 | 0 | idx+=2; |
5072 | 0 | } |
5073 | | |
5074 | 0 | if (JS_IsObject(argv[idx])) { |
5075 | 0 | GETIT(argv[idx], "x", fx) |
5076 | 0 | GETIT(argv[idx], "y", fy) |
5077 | 0 | idx+=1; |
5078 | 0 | } else if (argc>idx+1) { |
5079 | 0 | if (JS_ToFloat64(c, &d, argv[idx])) return GF_JS_EXCEPTION(c); |
5080 | 0 | fx = FLT2FIX(d); |
5081 | 0 | if (JS_ToFloat64(c, &d, argv[idx+1])) return GF_JS_EXCEPTION(c); |
5082 | 0 | fy = FLT2FIX(d); |
5083 | 0 | idx+=2; |
5084 | 0 | } |
5085 | | |
5086 | 0 | if (JS_IsObject(argv[idx])) { |
5087 | 0 | GETIT(argv[idx], "x", rx) |
5088 | 0 | GETIT(argv[idx], "y", ry) |
5089 | 0 | } else if (argc>idx+1) { |
5090 | 0 | if (JS_ToFloat64(c, &d, argv[idx])) return GF_JS_EXCEPTION(c); |
5091 | 0 | rx = FLT2FIX(d); |
5092 | 0 | if (JS_ToFloat64(c, &d, argv[idx+1])) return GF_JS_EXCEPTION(c); |
5093 | 0 | ry = FLT2FIX(d); |
5094 | 0 | } |
5095 | 0 | #undef GETIT |
5096 | 0 | gf_evg_stencil_set_radial_gradient(stencil, cx, cy, fx, fy, rx, ry); |
5097 | 0 | return JS_UNDEFINED; |
5098 | 0 | } |
5099 | | |
5100 | | |
5101 | | static JSValue stencil_set_points(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5102 | 0 | { |
5103 | 0 | GF_StencilType type; |
5104 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5105 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5106 | | |
5107 | 0 | type = gf_evg_stencil_type(stencil); |
5108 | 0 | if (type==GF_STENCIL_LINEAR_GRADIENT) |
5109 | 0 | return stencil_set_linear(c, stencil, argc, argv); |
5110 | 0 | if (type==GF_STENCIL_RADIAL_GRADIENT) |
5111 | 0 | return stencil_set_radial(c, stencil, argc, argv); |
5112 | 0 | return GF_JS_EXCEPTION(c); |
5113 | 0 | } |
5114 | | |
5115 | | Bool get_color_from_args(JSContext *c, int argc, JSValueConst *argv, u32 idx, Double *a, Double *r, Double *g, Double *b) |
5116 | 0 | { |
5117 | 0 | if (argc<(s32) idx) return GF_FALSE; |
5118 | 0 | if (JS_IsString(argv[idx])) { |
5119 | 0 | GF_Color col; |
5120 | 0 | const char *str = JS_ToCString(c, argv[idx]); |
5121 | 0 | col = gf_color_parse(str); |
5122 | 0 | JS_FreeCString(c, str); |
5123 | 0 | *a = ((Double)GF_COL_A(col)) / 255; |
5124 | 0 | *r = ((Double)GF_COL_R(col)) / 255; |
5125 | 0 | *g = ((Double)GF_COL_G(col)) / 255; |
5126 | 0 | *b = ((Double)GF_COL_B(col)) / 255; |
5127 | 0 | } else if (JS_IsNull(argv[idx])) { |
5128 | 0 | *a = *r = *g = *b = 0; |
5129 | 0 | } else if (JS_IsObject(argv[idx])) { |
5130 | 0 | if (!get_color(c, argv[idx], a, r, g, b)) { |
5131 | 0 | return GF_FALSE; |
5132 | 0 | } |
5133 | 0 | } else if (argc>(s32) idx) { |
5134 | 0 | if (JS_ToFloat64(c, r, argv[idx])) |
5135 | 0 | return GF_FALSE; |
5136 | 0 | if (argc>(s32)idx+1) { |
5137 | 0 | if (JS_ToFloat64(c, g, argv[idx+1])) |
5138 | 0 | return GF_FALSE; |
5139 | 0 | if (argc>(s32) idx+2) { |
5140 | 0 | if (JS_ToFloat64(c, b, argv[idx+2])) |
5141 | 0 | return GF_FALSE; |
5142 | 0 | if (argc>(s32)idx+3) { |
5143 | 0 | if (JS_ToFloat64(c, a, argv[idx+3])) |
5144 | 0 | return GF_FALSE; |
5145 | 0 | } |
5146 | 0 | } |
5147 | 0 | } |
5148 | 0 | } |
5149 | 0 | return GF_TRUE; |
5150 | 0 | } |
5151 | | |
5152 | | static JSValue stencil_set_stop_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int) |
5153 | 0 | { |
5154 | 0 | Double pos=0; |
5155 | 0 | GF_StencilType type; |
5156 | 0 | GF_Color col; |
5157 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5158 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5159 | 0 | type = gf_evg_stencil_type(stencil); |
5160 | 0 | if ((type!=GF_STENCIL_LINEAR_GRADIENT) && (type!=GF_STENCIL_RADIAL_GRADIENT)) return GF_JS_EXCEPTION(c); |
5161 | 0 | if (!argc) { |
5162 | 0 | gf_evg_stencil_set_gradient_interpolation(stencil, NULL, NULL, 0); |
5163 | 0 | return JS_UNDEFINED; |
5164 | 0 | } |
5165 | 0 | if (JS_ToFloat64(c, &pos, argv[0])) return GF_JS_EXCEPTION(c); |
5166 | | |
5167 | 0 | if (JS_IsString(argv[1])) { |
5168 | 0 | const char *str = JS_ToCString(c, argv[1]); |
5169 | 0 | col = gf_color_parse(str); |
5170 | 0 | JS_FreeCString(c, str); |
5171 | 0 | } else { |
5172 | 0 | Double r=0, g=0, b=0, a=1.0; |
5173 | 0 | if (!get_color_from_args(c, argc, argv, 1, &a, &r, &g, &b)) { |
5174 | 0 | return GF_JS_EXCEPTION(c); |
5175 | 0 | } |
5176 | 0 | if (!use_int) { |
5177 | 0 | a *= 255; |
5178 | 0 | r *= 255; |
5179 | 0 | g *= 255; |
5180 | 0 | b *= 255; |
5181 | 0 | } |
5182 | 0 | col = GF_COL_ARGB(a, r, g, b); |
5183 | 0 | } |
5184 | 0 | gf_evg_stencil_push_gradient_interpolation(stencil, FLT2FIX(pos), col); |
5185 | 0 | return JS_UNDEFINED; |
5186 | 0 | } |
5187 | | static JSValue stencil_set_stop(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5188 | 0 | { |
5189 | 0 | return stencil_set_stop_ex(c, obj, argc, argv, GF_TRUE); |
5190 | 0 | } |
5191 | | static JSValue stencil_set_stopf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5192 | 0 | { |
5193 | 0 | return stencil_set_stop_ex(c, obj, argc, argv, GF_FALSE); |
5194 | 0 | } |
5195 | | |
5196 | | static JSValue stencil_set_color_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int) |
5197 | 0 | { |
5198 | 0 | Double r=0, g=0, b=0, a=1.0; |
5199 | 0 | GF_StencilType type; |
5200 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5201 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5202 | 0 | type = gf_evg_stencil_type(stencil); |
5203 | 0 | if (type!=GF_STENCIL_SOLID) return GF_JS_EXCEPTION(c); |
5204 | | |
5205 | 0 | if (JS_IsString(argv[0])) { |
5206 | 0 | GF_Color col; |
5207 | 0 | const char *str = JS_ToCString(c, argv[0]); |
5208 | 0 | col = gf_color_parse(str); |
5209 | 0 | JS_FreeCString(c, str); |
5210 | 0 | gf_evg_stencil_set_brush_color(stencil, col); |
5211 | 0 | return JS_UNDEFINED; |
5212 | 0 | } else if (!get_color_from_args(c, argc, argv, 0, &a, &r, &g, &b)) { |
5213 | 0 | return GF_JS_EXCEPTION(c); |
5214 | 0 | } |
5215 | 0 | if (!use_int) { |
5216 | 0 | r*=255; |
5217 | 0 | g*=255; |
5218 | 0 | b*=255; |
5219 | 0 | a*=255; |
5220 | 0 | } |
5221 | 0 | gf_evg_stencil_set_brush_color(stencil, GF_COL_ARGB(a, r, g, b)); |
5222 | 0 | return JS_UNDEFINED; |
5223 | 0 | } |
5224 | | |
5225 | | static JSValue stencil_set_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5226 | 0 | { |
5227 | 0 | return stencil_set_color_ex(c, obj, argc, argv, GF_TRUE); |
5228 | 0 | } |
5229 | | static JSValue stencil_set_colorf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5230 | 0 | { |
5231 | 0 | return stencil_set_color_ex(c, obj, argc, argv, GF_FALSE); |
5232 | 0 | } |
5233 | | |
5234 | | |
5235 | | static JSValue stencil_get_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5236 | 0 | { |
5237 | 0 | GF_StencilType type; |
5238 | 0 | GF_Color col; |
5239 | 0 | char szCol[11]; |
5240 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5241 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5242 | 0 | type = gf_evg_stencil_type(stencil); |
5243 | 0 | if (type!=GF_STENCIL_SOLID) return GF_JS_EXCEPTION(c); |
5244 | | |
5245 | 0 | col = gf_evg_stencil_get_brush_color(stencil); |
5246 | 0 | sprintf(szCol, "0x%02X%02X%02X%02X", GF_COL_A(col), GF_COL_R(col), GF_COL_G(col), GF_COL_B(col) ); |
5247 | 0 | return JS_NewString(c, szCol); |
5248 | 0 | } |
5249 | | |
5250 | | |
5251 | | static JSValue stencil_set_alpha_ex(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool use_int) |
5252 | 0 | { |
5253 | 0 | Double a=1.0; |
5254 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5255 | 0 | if (!stencil) { |
5256 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5257 | 0 | if (!tx || !tx->stencil) |
5258 | 0 | return GF_JS_EXCEPTION(c); |
5259 | 0 | stencil = tx->stencil; |
5260 | 0 | } |
5261 | | |
5262 | 0 | if (argc) { |
5263 | 0 | JS_ToFloat64(c, &a, argv[0]); |
5264 | 0 | } |
5265 | 0 | if (a<0) a=0; |
5266 | 0 | if (!use_int) { |
5267 | 0 | a*=255; |
5268 | 0 | } |
5269 | 0 | if (a>255) a = 255; |
5270 | 0 | gf_evg_stencil_set_alpha(stencil, (u8) a); |
5271 | 0 | return JS_UNDEFINED; |
5272 | 0 | } |
5273 | | |
5274 | | static JSValue stencil_set_alpha(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5275 | 0 | { |
5276 | 0 | return stencil_set_alpha_ex(c, obj, argc, argv, GF_TRUE); |
5277 | 0 | } |
5278 | | static JSValue stencil_set_alphaf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5279 | 0 | { |
5280 | 0 | return stencil_set_alpha_ex(c, obj, argc, argv, GF_FALSE); |
5281 | 0 | } |
5282 | | |
5283 | | |
5284 | | static JSValue stencil_get_alphaf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5285 | 0 | { |
5286 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5287 | 0 | if (!stencil) { |
5288 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5289 | 0 | if (!tx || !tx->stencil) |
5290 | 0 | return GF_JS_EXCEPTION(c); |
5291 | 0 | stencil = tx->stencil; |
5292 | 0 | } |
5293 | 0 | Double res = gf_evg_stencil_get_alpha(stencil); |
5294 | 0 | return JS_NewFloat64(c, res/255.0); |
5295 | 0 | } |
5296 | | |
5297 | | |
5298 | | static JSValue stencil_getProperty(JSContext *c, JSValueConst obj, int magic) |
5299 | 0 | { |
5300 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5301 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5302 | 0 | switch (magic) { |
5303 | 0 | case STENCIL_SOLID: |
5304 | 0 | if (gf_evg_stencil_type(stencil) == GF_STENCIL_SOLID) return JS_TRUE; |
5305 | 0 | return JS_FALSE; |
5306 | 0 | case STENCIL_MAT: |
5307 | 0 | { |
5308 | 0 | GF_Matrix2D mx, *mxp; |
5309 | 0 | if (! gf_evg_stencil_get_matrix(stencil, &mx)) return JS_NULL; |
5310 | 0 | GF_SAFEALLOC(mxp, GF_Matrix2D); |
5311 | 0 | if (!mxp) return js_throw_err(c, GF_OUT_OF_MEM); |
5312 | 0 | gf_mx2d_copy(*mxp, mx); |
5313 | 0 | JSValue res = JS_NewObjectClass(c, mx2d_class_id); |
5314 | 0 | JS_SetOpaque(res, mxp); |
5315 | 0 | return res; |
5316 | 0 | } |
5317 | 0 | break; |
5318 | 0 | case STENCIL_MAT_AUTO: |
5319 | 0 | if (gf_evg_stencil_get_auto_matrix(stencil)) return JS_TRUE; |
5320 | 0 | return JS_FALSE; |
5321 | 0 | case STENCIL_CMX: |
5322 | 0 | { |
5323 | 0 | GF_ColorMatrix *cmx; |
5324 | 0 | GF_SAFEALLOC(cmx, GF_ColorMatrix); |
5325 | 0 | if (!cmx) return js_throw_err(c, GF_OUT_OF_MEM); |
5326 | 0 | gf_evg_stencil_get_color_matrix(stencil, cmx); |
5327 | 0 | obj = JS_NewObjectClass(c, colmx_class_id); |
5328 | 0 | JS_SetOpaque(obj, cmx); |
5329 | 0 | return obj; |
5330 | 0 | } |
5331 | 0 | } |
5332 | | |
5333 | 0 | return JS_UNDEFINED; |
5334 | 0 | } |
5335 | | static JSValue stencil_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
5336 | 0 | { |
5337 | 0 | u32 v; |
5338 | 0 | GF_EVGStencil *stencil = JS_GetOpaque(obj, stencil_class_id); |
5339 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5340 | | |
5341 | 0 | switch (magic) { |
5342 | 0 | case STENCIL_CMX: |
5343 | 0 | if (JS_IsNull(value)) { |
5344 | 0 | gf_evg_stencil_set_color_matrix(stencil, NULL); |
5345 | 0 | } else { |
5346 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(value, colmx_class_id); |
5347 | 0 | gf_evg_stencil_set_color_matrix(stencil, cmx); |
5348 | 0 | } |
5349 | 0 | return JS_UNDEFINED; |
5350 | 0 | case STENCIL_GRADMOD: |
5351 | 0 | if (JS_ToInt32(c, &v, value)) return GF_JS_EXCEPTION(c); |
5352 | 0 | gf_evg_stencil_set_gradient_mode(stencil, v); |
5353 | 0 | return JS_UNDEFINED; |
5354 | 0 | case STENCIL_MAT: |
5355 | 0 | if (JS_IsNull(value)) { |
5356 | 0 | gf_evg_stencil_set_matrix(stencil, NULL); |
5357 | 0 | } else { |
5358 | 0 | GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id); |
5359 | 0 | gf_evg_stencil_set_matrix(stencil, mx); |
5360 | 0 | } |
5361 | 0 | return JS_UNDEFINED; |
5362 | 0 | case STENCIL_MAT_AUTO: |
5363 | 0 | gf_evg_stencil_set_auto_matrix(stencil, JS_ToBool(c, value) ? GF_TRUE : GF_FALSE); |
5364 | 0 | return JS_UNDEFINED; |
5365 | 0 | } |
5366 | 0 | return JS_UNDEFINED; |
5367 | 0 | } |
5368 | | |
5369 | | static const JSCFunctionListEntry stencil_funcs[] = |
5370 | | { |
5371 | | JS_CGETSET_MAGIC_DEF("solid_brush", stencil_getProperty, NULL, STENCIL_SOLID), |
5372 | | JS_CGETSET_MAGIC_DEF("pad", NULL, stencil_setProperty, STENCIL_GRADMOD), |
5373 | | JS_CGETSET_MAGIC_DEF("cmx", stencil_getProperty, stencil_setProperty, STENCIL_CMX), |
5374 | | JS_CGETSET_MAGIC_DEF("mx", stencil_getProperty, stencil_setProperty, STENCIL_MAT), |
5375 | | JS_CGETSET_MAGIC_DEF("auto_mx", stencil_getProperty, stencil_setProperty, STENCIL_MAT_AUTO), |
5376 | | JS_CFUNC_DEF("set_color", 0, stencil_set_color), |
5377 | | JS_CFUNC_DEF("set_colorf", 0, stencil_set_colorf), |
5378 | | JS_CFUNC_DEF("set_alpha", 0, stencil_set_alpha), |
5379 | | JS_CFUNC_DEF("set_alphaf", 0, stencil_set_alphaf), |
5380 | | JS_CFUNC_DEF("get_alphaf", 0, stencil_get_alphaf), |
5381 | | JS_CFUNC_DEF("get_color", 0, stencil_get_color), |
5382 | | JS_CFUNC_DEF("set_points", 0, stencil_set_points), |
5383 | | JS_CFUNC_DEF("set_stop", 0, stencil_set_stop), |
5384 | | JS_CFUNC_DEF("set_stopf", 0, stencil_set_stopf), |
5385 | | }; |
5386 | | |
5387 | | |
5388 | | static JSValue stencil_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv, GF_StencilType type) |
5389 | 0 | { |
5390 | 0 | JSValue obj; |
5391 | 0 | GF_EVGStencil *stencil = gf_evg_stencil_new(type); |
5392 | 0 | if (!stencil) return GF_JS_EXCEPTION(c); |
5393 | 0 | obj = JS_NewObjectClass(c, stencil_class_id); |
5394 | 0 | if (JS_IsException(obj)) return obj; |
5395 | 0 | JS_SetOpaque(obj, stencil); |
5396 | 0 | return obj; |
5397 | 0 | } |
5398 | | static JSValue solid_brush_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
5399 | 0 | { |
5400 | 0 | return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_SOLID); |
5401 | 0 | } |
5402 | | static JSValue linear_gradient_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
5403 | 0 | { |
5404 | 0 | return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_LINEAR_GRADIENT); |
5405 | 0 | } |
5406 | | static JSValue radial_gradient_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
5407 | 0 | { |
5408 | 0 | return stencil_constructor(c, new_target, argc, argv, GF_STENCIL_RADIAL_GRADIENT); |
5409 | 0 | } |
5410 | | |
5411 | | static void texture_reset(GF_JSTexture *tx) |
5412 | 0 | { |
5413 | 0 | if (tx->owns_data && tx->data) { |
5414 | 0 | gf_free(tx->data); |
5415 | 0 | } |
5416 | 0 | tx->data = NULL; |
5417 | 0 | tx->data_size = 0; |
5418 | 0 | tx->owns_data = GF_FALSE; |
5419 | 0 | } |
5420 | | |
5421 | | static void texture_finalize(JSRuntime *rt, JSValue obj) |
5422 | 0 | { |
5423 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5424 | 0 | if (!tx) return; |
5425 | 0 | texture_reset(tx); |
5426 | 0 | if (tx->stencil) |
5427 | 0 | gf_evg_stencil_delete(tx->stencil); |
5428 | 0 | JS_FreeValueRT(rt, tx->param_fun); |
5429 | 0 | JS_FreeValueRT(rt, tx->par_obj); |
5430 | |
|
5431 | | #ifndef GPAC_DISABLE_3D |
5432 | | if (tx->named_tx) { |
5433 | | gf_free(tx->named_tx); |
5434 | | } |
5435 | | #endif |
5436 | |
|
5437 | | #ifdef GPAC_HAS_FFMPEG |
5438 | | if (tx->swscaler) |
5439 | | sws_freeContext(tx->swscaler); |
5440 | | #endif |
5441 | |
|
5442 | 0 | gf_free(tx); |
5443 | 0 | } |
5444 | | |
5445 | | static void texture_gc_mark(JSRuntime *rt, JSValueConst obj, JS_MarkFunc *mark_func) |
5446 | 0 | { |
5447 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5448 | 0 | if (!tx) return; |
5449 | 0 | JS_MarkValue(rt, tx->param_fun, mark_func); |
5450 | 0 | JS_MarkValue(rt, tx->par_obj, mark_func); |
5451 | 0 | } |
5452 | | |
5453 | | JSClassDef texture_class = { |
5454 | | "Texture", |
5455 | | .finalizer = texture_finalize, |
5456 | | .gc_mark = texture_gc_mark |
5457 | | }; |
5458 | | |
5459 | | enum |
5460 | | { |
5461 | | TX_MAPPING = 0, |
5462 | | TX_FILTER, |
5463 | | TX_CMX, |
5464 | | TX_REPEAT_S, |
5465 | | TX_REPEAT_T, |
5466 | | TX_FLIP_X, |
5467 | | TX_FLIP_Y, |
5468 | | TX_MAT, |
5469 | | TX_MAT_AUTO, |
5470 | | TX_WIDTH, |
5471 | | TX_HEIGHT, |
5472 | | TX_NB_COMP, |
5473 | | TX_PIXFMT, |
5474 | | TX_DATA, |
5475 | | }; |
5476 | | |
5477 | | static JSValue texture_getProperty(JSContext *c, JSValueConst obj, int magic) |
5478 | 0 | { |
5479 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5480 | 0 | if (!tx || !tx->stencil) return GF_JS_EXCEPTION(c); |
5481 | 0 | switch (magic) { |
5482 | 0 | case TX_REPEAT_S: |
5483 | 0 | return JS_NewBool(c, (tx->flags & GF_TEXTURE_REPEAT_S)); |
5484 | 0 | case TX_REPEAT_T: |
5485 | 0 | return JS_NewBool(c, (tx->flags & GF_TEXTURE_REPEAT_T)); |
5486 | 0 | case TX_FLIP_X: |
5487 | 0 | return JS_NewBool(c, (tx->flags & GF_TEXTURE_FLIP_X)); |
5488 | 0 | case TX_FLIP_Y: |
5489 | 0 | return JS_NewBool(c, (tx->flags & GF_TEXTURE_FLIP_Y)); |
5490 | 0 | case TX_WIDTH: |
5491 | 0 | return JS_NewInt32(c, tx->width); |
5492 | 0 | case TX_HEIGHT: |
5493 | 0 | return JS_NewInt32(c, tx->height); |
5494 | 0 | case TX_PIXFMT: |
5495 | 0 | return JS_NewInt32(c, tx->pf); |
5496 | 0 | case TX_NB_COMP: |
5497 | 0 | return JS_NewInt32(c, tx->nb_comp); |
5498 | 0 | case TX_DATA: |
5499 | 0 | if (tx->owns_data) |
5500 | 0 | return JS_NewArrayBuffer(c, (u8 *) tx->data, tx->data_size, NULL, NULL, 0/*1*/); |
5501 | 0 | return JS_NULL; |
5502 | | |
5503 | 0 | case TX_MAT: |
5504 | 0 | { |
5505 | 0 | GF_Matrix2D mx, *mxp; |
5506 | 0 | if (! gf_evg_stencil_get_matrix(tx->stencil, &mx)) return JS_NULL; |
5507 | 0 | GF_SAFEALLOC(mxp, GF_Matrix2D); |
5508 | 0 | if (!mxp) return js_throw_err(c, GF_OUT_OF_MEM); |
5509 | 0 | gf_mx2d_copy(*mxp, mx); |
5510 | 0 | JSValue res = JS_NewObjectClass(c, mx2d_class_id); |
5511 | 0 | JS_SetOpaque(res, mxp); |
5512 | 0 | return res; |
5513 | 0 | } |
5514 | 0 | case TX_MAT_AUTO: |
5515 | 0 | if (gf_evg_stencil_get_auto_matrix(tx->stencil)) return JS_TRUE; |
5516 | 0 | return JS_FALSE; |
5517 | 0 | case TX_CMX: |
5518 | 0 | { |
5519 | 0 | GF_ColorMatrix *cmx; |
5520 | 0 | GF_SAFEALLOC(cmx, GF_ColorMatrix); |
5521 | 0 | if (!cmx) return js_throw_err(c, GF_OUT_OF_MEM); |
5522 | 0 | gf_evg_stencil_get_color_matrix(tx->stencil, cmx); |
5523 | 0 | obj = JS_NewObjectClass(c, colmx_class_id); |
5524 | 0 | JS_SetOpaque(obj, cmx); |
5525 | 0 | return obj; |
5526 | 0 | } |
5527 | 0 | } |
5528 | 0 | return JS_UNDEFINED; |
5529 | 0 | } |
5530 | | static JSValue texture_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
5531 | 0 | { |
5532 | 0 | u32 v; |
5533 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5534 | 0 | if (!tx || !tx->stencil) return GF_JS_EXCEPTION(c); |
5535 | | |
5536 | 0 | switch (magic) { |
5537 | 0 | case TX_FILTER: |
5538 | 0 | if (JS_ToInt32(c, &v, value)) return GF_JS_EXCEPTION(c); |
5539 | 0 | gf_evg_stencil_set_filter(tx->stencil, v); |
5540 | 0 | return JS_UNDEFINED; |
5541 | 0 | case TX_CMX: |
5542 | 0 | if (JS_IsNull(value)) { |
5543 | 0 | gf_evg_stencil_set_color_matrix(tx->stencil, NULL); |
5544 | 0 | } else { |
5545 | 0 | GF_ColorMatrix *cmx = JS_GetOpaque(value, colmx_class_id); |
5546 | 0 | gf_evg_stencil_set_color_matrix(tx->stencil, cmx); |
5547 | 0 | } |
5548 | 0 | return JS_UNDEFINED; |
5549 | 0 | case TX_REPEAT_S: |
5550 | 0 | if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_REPEAT_S; |
5551 | 0 | else tx->flags &= ~GF_TEXTURE_REPEAT_S; |
5552 | 0 | gf_evg_stencil_set_mapping(tx->stencil, tx->flags); |
5553 | 0 | return JS_UNDEFINED; |
5554 | 0 | case TX_REPEAT_T: |
5555 | 0 | if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_REPEAT_T; |
5556 | 0 | else tx->flags &= ~GF_TEXTURE_REPEAT_T; |
5557 | 0 | gf_evg_stencil_set_mapping(tx->stencil, tx->flags); |
5558 | 0 | return JS_UNDEFINED; |
5559 | 0 | case TX_FLIP_X: |
5560 | 0 | if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_FLIP_X; |
5561 | 0 | else tx->flags &= ~GF_TEXTURE_FLIP_X; |
5562 | 0 | gf_evg_stencil_set_mapping(tx->stencil, tx->flags); |
5563 | 0 | return JS_UNDEFINED; |
5564 | 0 | case TX_FLIP_Y: |
5565 | 0 | if (JS_ToBool(c, value)) tx->flags |= GF_TEXTURE_FLIP_Y; |
5566 | 0 | else tx->flags &= ~GF_TEXTURE_FLIP_Y; |
5567 | 0 | gf_evg_stencil_set_mapping(tx->stencil, tx->flags); |
5568 | 0 | return JS_UNDEFINED; |
5569 | 0 | case TX_MAT: |
5570 | 0 | if (JS_IsNull(value)) { |
5571 | 0 | gf_evg_stencil_set_matrix(tx->stencil, NULL); |
5572 | 0 | } else { |
5573 | 0 | GF_Matrix2D *mx = JS_GetOpaque(value, mx2d_class_id); |
5574 | 0 | gf_evg_stencil_set_matrix(tx->stencil, mx); |
5575 | 0 | } |
5576 | 0 | return JS_UNDEFINED; |
5577 | 0 | case TX_MAT_AUTO: |
5578 | 0 | gf_evg_stencil_set_auto_matrix(tx->stencil, JS_ToBool(c, value) ? GF_TRUE : GF_FALSE); |
5579 | 0 | return JS_UNDEFINED; |
5580 | 0 | } |
5581 | 0 | return JS_UNDEFINED; |
5582 | 0 | } |
5583 | | |
5584 | | |
5585 | 0 | #define min_f(a, b, c) (fminf(a, fminf(b, c))) |
5586 | 0 | #define max_f(a, b, c) (fmaxf(a, fmaxf(b, c))) |
5587 | | |
5588 | | void rgb2hsv(const u8 src_r, const u8 src_g, const u8 src_b, u8 *dst_h, u8 *dst_s, u8 *dst_v) |
5589 | 0 | { |
5590 | 0 | float h, s, v; // h:0-360.0, s:0.0-1.0, v:0.0-1.0 |
5591 | 0 | float r = src_r / 255.0f; |
5592 | 0 | float g = src_g / 255.0f; |
5593 | 0 | float b = src_b / 255.0f; |
5594 | |
|
5595 | 0 | float max = max_f(r, g, b); |
5596 | 0 | float min = min_f(r, g, b); |
5597 | |
|
5598 | 0 | v = max; |
5599 | 0 | if (max == 0.0f) { |
5600 | 0 | s = 0; |
5601 | 0 | h = 0; |
5602 | 0 | } else if (max - min == 0.0f) { |
5603 | 0 | s = 0; |
5604 | 0 | h = 0; |
5605 | 0 | } else { |
5606 | 0 | s = (max - min) / max; |
5607 | |
|
5608 | 0 | if (max == r) { |
5609 | 0 | h = 60 * ((g - b) / (max - min)) + 0; |
5610 | 0 | } else if (max == g) { |
5611 | 0 | h = 60 * ((b - r) / (max - min)) + 120; |
5612 | 0 | } else { |
5613 | 0 | h = 60 * ((r - g) / (max - min)) + 240; |
5614 | 0 | } |
5615 | 0 | } |
5616 | 0 | if (h < 0) h += 360.0f; |
5617 | |
|
5618 | 0 | *dst_h = (u8)(h / 2); // dst_h : 0-180 |
5619 | 0 | *dst_s = (u8)(s * 255); // dst_s : 0-255 |
5620 | 0 | *dst_v = (u8)(v * 255); // dst_v : 0-255 |
5621 | 0 | } |
5622 | | |
5623 | | void hsv2rgb(u8 src_h, u8 src_s, u8 src_v, u8 *dst_r, u8 *dst_g, u8 *dst_b) |
5624 | 0 | { |
5625 | 0 | float r, g, b; // 0.0-1.0 |
5626 | 0 | float h = src_h * 2.0f; // 0-360 |
5627 | 0 | float s = src_s / 255.0f; // 0.0-1.0 |
5628 | 0 | float v = src_v / 255.0f; // 0.0-1.0 |
5629 | |
|
5630 | 0 | int hi = (int)(h / 60.0f) % 6; |
5631 | 0 | float f = (h / 60.0f) - hi; |
5632 | 0 | float p = v * (1.0f - s); |
5633 | 0 | float q = v * (1.0f - s * f); |
5634 | 0 | float t = v * (1.0f - s * (1.0f - f)); |
5635 | |
|
5636 | 0 | switch(hi) { |
5637 | 0 | case 0: r = v; g = t; b = p; break; |
5638 | 0 | case 1: r = q; g = v; b = p; break; |
5639 | 0 | case 2: r = p; g = v; b = t; break; |
5640 | 0 | case 3: r = p; g = q; b = v; break; |
5641 | 0 | case 4: r = t; g = p; b = v; break; |
5642 | 0 | case 5: |
5643 | 0 | default: |
5644 | 0 | r = v; g = p; b = q; break; |
5645 | 0 | } |
5646 | | |
5647 | 0 | *dst_r = (u8)(r * 255); // dst_r : 0-255 |
5648 | 0 | *dst_g = (u8)(g * 255); // dst_r : 0-255 |
5649 | 0 | *dst_b = (u8)(b * 255); // dst_r : 0-255 |
5650 | 0 | } |
5651 | | |
5652 | | enum |
5653 | | { |
5654 | | EVG_CONV_RGB_TO_HSV=0, |
5655 | | EVG_CONV_HSV_TO_RGB, |
5656 | | EVG_CONV_YUV_TO_RGB, |
5657 | | EVG_CONV_RGB_TO_YUV, |
5658 | | }; |
5659 | | |
5660 | | static JSValue texture_convert(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, u32 conv_type) |
5661 | 0 | { |
5662 | 0 | JSValue nobj; |
5663 | 0 | GF_Err e; |
5664 | 0 | u32 i, j, dst_pf, nb_comp; |
5665 | 0 | GF_JSCanvas *canvas=NULL; |
5666 | 0 | GF_JSTexture *tx_conv; |
5667 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5668 | 0 | if (!tx || !tx->stencil) return GF_JS_EXCEPTION(c); |
5669 | 0 | if (argc) { |
5670 | 0 | canvas = JS_GetOpaque(argv[0], canvas_class_id); |
5671 | 0 | } |
5672 | 0 | if ((conv_type==EVG_CONV_YUV_TO_RGB) || (conv_type==EVG_CONV_RGB_TO_YUV)) { |
5673 | 0 | if (!canvas) return js_throw_err_msg(c, GF_BAD_PARAM, "Missing canvas parameter for RBG/YUV conversion"); |
5674 | 0 | } |
5675 | | |
5676 | 0 | switch (tx->pf) { |
5677 | 0 | case GF_PIXEL_ARGB: |
5678 | 0 | case GF_PIXEL_RGBA: |
5679 | 0 | case GF_PIXEL_BGRA: |
5680 | 0 | case GF_PIXEL_ABGR: |
5681 | 0 | case GF_PIXEL_ALPHAGREY: |
5682 | 0 | case GF_PIXEL_GREYALPHA: |
5683 | 0 | if (conv_type == EVG_CONV_RGB_TO_YUV ) { |
5684 | 0 | dst_pf = GF_PIXEL_YUVA444_PACK; |
5685 | 0 | } else { |
5686 | 0 | dst_pf = GF_PIXEL_RGBA; |
5687 | 0 | } |
5688 | 0 | nb_comp = 4; |
5689 | 0 | break; |
5690 | 0 | default: |
5691 | 0 | if (conv_type == EVG_CONV_RGB_TO_YUV ) { |
5692 | 0 | dst_pf = GF_PIXEL_YUV444_PACK; |
5693 | 0 | } else { |
5694 | 0 | dst_pf = GF_PIXEL_RGB; |
5695 | 0 | } |
5696 | 0 | nb_comp = 3; |
5697 | 0 | break; |
5698 | 0 | } |
5699 | | |
5700 | 0 | GF_SAFEALLOC(tx_conv, GF_JSTexture); |
5701 | 0 | if (!tx_conv) |
5702 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
5703 | 0 | tx_conv->width = tx->width; |
5704 | 0 | tx_conv->height = tx->height; |
5705 | 0 | tx_conv->pf = dst_pf; |
5706 | 0 | tx_conv->nb_comp = nb_comp; |
5707 | 0 | 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); |
5708 | 0 | tx_conv->data = gf_malloc(sizeof(char)*tx_conv->data_size); |
5709 | 0 | tx_conv->owns_data = GF_TRUE; |
5710 | |
|
5711 | 0 | for (j=0; j<tx_conv->height; j++) { |
5712 | 0 | u8 *dst = tx_conv->data + j*tx_conv->stride; |
5713 | 0 | for (i=0; i<tx_conv->width; i++) { |
5714 | 0 | u8 a, r, g, b; |
5715 | 0 | u32 col = gf_evg_stencil_get_pixel(tx->stencil, i, j); |
5716 | |
|
5717 | 0 | if (conv_type == EVG_CONV_RGB_TO_HSV ) { |
5718 | 0 | a = GF_COL_A(col); |
5719 | 0 | r = GF_COL_R(col); |
5720 | 0 | g = GF_COL_G(col); |
5721 | 0 | b = GF_COL_B(col); |
5722 | 0 | rgb2hsv(r, g, b, &r, &g, &b); |
5723 | 0 | } else if (conv_type == EVG_CONV_HSV_TO_RGB ) { |
5724 | 0 | a = GF_COL_A(col); |
5725 | 0 | r = GF_COL_R(col); |
5726 | 0 | g = GF_COL_G(col); |
5727 | 0 | b = GF_COL_B(col); |
5728 | 0 | hsv2rgb(r, g, b, &r, &g, &b); |
5729 | 0 | } else if (conv_type == EVG_CONV_RGB_TO_YUV ) { |
5730 | 0 | col = gf_evg_argb_to_ayuv(canvas->surface, col); |
5731 | 0 | a = GF_COL_A(col); |
5732 | 0 | r = GF_COL_R(col); |
5733 | 0 | g = GF_COL_G(col); |
5734 | 0 | b = GF_COL_B(col); |
5735 | 0 | } else { |
5736 | 0 | col = gf_evg_ayuv_to_argb(canvas->surface, col); |
5737 | 0 | a = GF_COL_A(col); |
5738 | 0 | r = GF_COL_R(col); |
5739 | 0 | g = GF_COL_G(col); |
5740 | 0 | b = GF_COL_B(col); |
5741 | 0 | } |
5742 | 0 | dst[0] = r; |
5743 | 0 | dst[1] = g; |
5744 | 0 | dst[2] = b; |
5745 | 0 | if (nb_comp==4) { |
5746 | 0 | dst[3] = a; |
5747 | 0 | dst += 4; |
5748 | 0 | } else { |
5749 | 0 | dst += 3; |
5750 | 0 | } |
5751 | 0 | } |
5752 | 0 | } |
5753 | 0 | tx_conv->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE); |
5754 | 0 | if (!tx_conv->stencil) { |
5755 | 0 | e = GF_OUT_OF_MEM; |
5756 | 0 | } else { |
5757 | 0 | e = gf_evg_stencil_set_texture(tx_conv->stencil, tx_conv->data, tx_conv->width, tx_conv->height, tx_conv->stride, tx_conv->pf); |
5758 | 0 | } |
5759 | 0 | if (e) { |
5760 | 0 | gf_evg_stencil_delete(tx_conv->stencil); |
5761 | 0 | gf_free(tx_conv->data); |
5762 | 0 | gf_free(tx_conv); |
5763 | 0 | return js_throw_err_msg(c, e, "Failed to convert image: %s", gf_error_to_string(e)); |
5764 | 0 | } |
5765 | | |
5766 | 0 | nobj = JS_NewObjectClass(c, texture_class_id); |
5767 | 0 | JS_SetOpaque(nobj, tx_conv); |
5768 | 0 | return nobj; |
5769 | 0 | } |
5770 | | static JSValue texture_rgb2hsv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5771 | 0 | { |
5772 | 0 | return texture_convert(c, obj, argc, argv, EVG_CONV_RGB_TO_HSV); |
5773 | 0 | } |
5774 | | static JSValue texture_hsv2rgb(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5775 | 0 | { |
5776 | 0 | return texture_convert(c, obj, argc, argv, EVG_CONV_HSV_TO_RGB); |
5777 | 0 | } |
5778 | | static JSValue texture_rgb2yuv(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5779 | 0 | { |
5780 | 0 | return texture_convert(c, obj, argc, argv, EVG_CONV_RGB_TO_YUV); |
5781 | 0 | } |
5782 | | static JSValue texture_yuv2rgb(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5783 | 0 | { |
5784 | 0 | return texture_convert(c, obj, argc, argv, EVG_CONV_YUV_TO_RGB); |
5785 | 0 | } |
5786 | | |
5787 | | static JSValue texture_split(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5788 | 0 | { |
5789 | 0 | JSValue nobj; |
5790 | 0 | u32 i, j, idx, pix_shift=0; |
5791 | 0 | GF_IRect src; |
5792 | 0 | GF_JSTexture *tx_split; |
5793 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5794 | 0 | if (!tx || !tx->stencil || !argc) return GF_JS_EXCEPTION(c); |
5795 | | |
5796 | 0 | if (JS_ToInt32(c, &idx, argv[0])) return GF_JS_EXCEPTION(c); |
5797 | 0 | if (idx>=tx->nb_comp) return GF_JS_EXCEPTION(c); |
5798 | | |
5799 | 0 | src.x = src.y = 0; |
5800 | 0 | src.width = tx->width; |
5801 | 0 | src.height = tx->height; |
5802 | 0 | if (argc>1) { |
5803 | 0 | JSValue v; |
5804 | 0 | int res; |
5805 | 0 | if (!JS_IsObject(argv[1])) return GF_JS_EXCEPTION(c); |
5806 | | |
5807 | 0 | #define GETIT(_name, _var) \ |
5808 | 0 | v = JS_GetPropertyStr(c, argv[1], _name);\ |
5809 | 0 | res = JS_ToInt32(c, &(src._var), v);\ |
5810 | 0 | JS_FreeValue(c, v);\ |
5811 | 0 | if (res) return GF_JS_EXCEPTION(c);\ |
5812 | 0 | if (src._var<0) return GF_JS_EXCEPTION(c);\ |
5813 | 0 |
|
5814 | 0 | GETIT("x", x) |
5815 | 0 | GETIT("y", y) |
5816 | 0 | GETIT("w", width) |
5817 | 0 | GETIT("h", height) |
5818 | 0 | #undef GETIT |
5819 | 0 | } |
5820 | | |
5821 | 0 | GF_SAFEALLOC(tx_split, GF_JSTexture); |
5822 | 0 | if (!tx_split) |
5823 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
5824 | 0 | tx_split->width = src.width; |
5825 | 0 | tx_split->height = src.height; |
5826 | 0 | tx_split->pf = GF_PIXEL_GREYSCALE; |
5827 | 0 | tx_split->nb_comp = 1; |
5828 | 0 | tx_split->stride = tx_split->width; |
5829 | 0 | tx_split->data_size = tx_split->width * tx_split->height; |
5830 | 0 | tx_split->data = gf_malloc(sizeof(char) * tx_split->data_size); |
5831 | 0 | tx_split->owns_data = GF_TRUE; |
5832 | |
|
5833 | 0 | pix_shift = 0; |
5834 | 0 | if (idx==0) { |
5835 | 0 | pix_shift = 16; //R component |
5836 | 0 | } else if (idx==1) { |
5837 | 0 | if ((tx->pf == GF_PIXEL_ALPHAGREY) || (tx->pf == GF_PIXEL_GREYALPHA)) pix_shift = 24; //alpha |
5838 | 0 | else pix_shift = 8; //green |
5839 | 0 | } else if (idx==2) { |
5840 | 0 | pix_shift = 0; //blue |
5841 | 0 | } else if (idx==3) { |
5842 | 0 | pix_shift = 24; //alpha |
5843 | 0 | } |
5844 | 0 | for (j=0; j<tx_split->height; j++) { |
5845 | 0 | u8 *dst = tx_split->data + j*tx_split->stride; |
5846 | 0 | for (i=0; i<tx_split->width; i++) { |
5847 | 0 | u32 col = gf_evg_stencil_get_pixel(tx->stencil, src.x + i, src.y + j); |
5848 | 0 | *dst++ = (col >> pix_shift) & 0xFF; |
5849 | 0 | } |
5850 | 0 | } |
5851 | 0 | tx_split->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE); |
5852 | 0 | gf_evg_stencil_set_texture(tx_split->stencil, tx_split->data, tx_split->width, tx_split->height, tx_split->stride, tx_split->pf); |
5853 | 0 | nobj = JS_NewObjectClass(c, texture_class_id); |
5854 | 0 | JS_SetOpaque(nobj, tx_split); |
5855 | 0 | return nobj; |
5856 | 0 | } |
5857 | | static JSValue texture_convolution(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5858 | 0 | { |
5859 | 0 | JSValue v, kernv, nobj; |
5860 | 0 | u32 i, j, kw=0, kh=0, kl=0, hkh, hkw; |
5861 | 0 | s32 *kdata; |
5862 | 0 | s32 knorm=0; |
5863 | 0 | GF_JSTexture *tx_conv; |
5864 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5865 | 0 | if (!tx || !tx->stencil || !argc) return GF_JS_EXCEPTION(c); |
5866 | | |
5867 | 0 | if (!JS_IsObject(argv[0])) |
5868 | 0 | return GF_JS_EXCEPTION(c); |
5869 | | |
5870 | 0 | v = JS_GetPropertyStr(c, argv[0], "w"); |
5871 | 0 | JS_ToInt32(c, &kw, v); |
5872 | 0 | JS_FreeValue(c, v); |
5873 | 0 | v = JS_GetPropertyStr(c, argv[0], "h"); |
5874 | 0 | JS_ToInt32(c, &kh, v); |
5875 | 0 | JS_FreeValue(c, v); |
5876 | 0 | v = JS_GetPropertyStr(c, argv[0], "norm"); |
5877 | 0 | if (!JS_IsUndefined(v)) |
5878 | 0 | JS_ToInt32(c, &knorm, v); |
5879 | 0 | JS_FreeValue(c, v); |
5880 | 0 | if (!kh || !kw) |
5881 | 0 | return GF_JS_EXCEPTION(c); |
5882 | 0 | if (!(kh%2) || !(kw%2)) |
5883 | 0 | return GF_JS_EXCEPTION(c); |
5884 | 0 | kernv = JS_GetPropertyStr(c, argv[0], "k"); |
5885 | 0 | if (JS_IsUndefined(kernv)) |
5886 | 0 | return GF_JS_EXCEPTION(c); |
5887 | | |
5888 | 0 | v = JS_GetPropertyStr(c, kernv, "length"); |
5889 | 0 | JS_ToInt32(c, &kl, v); |
5890 | 0 | JS_FreeValue(c, v); |
5891 | 0 | if (kl < kw * kh) { |
5892 | 0 | JS_FreeValue(c, kernv); |
5893 | 0 | return GF_JS_EXCEPTION(c); |
5894 | 0 | } |
5895 | 0 | kl = kw*kh; |
5896 | 0 | kdata = gf_malloc(sizeof(s32)*kl); |
5897 | 0 | for (j=0; j<kh; j++) { |
5898 | 0 | for (i=0; i<kw; i++) { |
5899 | 0 | u32 idx = j*kw + i; |
5900 | 0 | v = JS_GetPropertyUint32(c, kernv, idx); |
5901 | 0 | JS_ToInt32(c, &kdata[idx] , v); |
5902 | 0 | JS_FreeValue(c, v); |
5903 | 0 | } |
5904 | 0 | } |
5905 | 0 | JS_FreeValue(c, kernv); |
5906 | |
|
5907 | 0 | GF_SAFEALLOC(tx_conv, GF_JSTexture); |
5908 | 0 | if (!tx_conv) |
5909 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
5910 | 0 | tx_conv->width = tx->width; |
5911 | 0 | tx_conv->height = tx->height; |
5912 | 0 | tx_conv->pf = GF_PIXEL_RGB; |
5913 | 0 | tx_conv->nb_comp = 3; |
5914 | 0 | 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); |
5915 | 0 | tx_conv->data = gf_malloc(sizeof(char)*tx_conv->data_size); |
5916 | 0 | tx_conv->owns_data = GF_TRUE; |
5917 | |
|
5918 | 0 | hkh = kh/2; |
5919 | 0 | hkw = kw/2; |
5920 | 0 | for (j=0; j<tx_conv->height; j++) { |
5921 | 0 | u8 *dst = tx_conv->data + j*tx_conv->stride; |
5922 | 0 | for (i=0; i<tx_conv->width; i++) { |
5923 | 0 | u32 k, l, nb_pix=0; |
5924 | 0 | s32 kr = 0; |
5925 | 0 | s32 kg = 0; |
5926 | 0 | s32 kb = 0; |
5927 | |
|
5928 | 0 | for (k=0; k<kh; k++) { |
5929 | 0 | if (j+k < hkh) continue; |
5930 | 0 | if (j+k >= tx_conv->height + hkh) continue; |
5931 | | |
5932 | 0 | for (l=0; l<kw; l++) { |
5933 | 0 | s32 kv; |
5934 | 0 | if (i+l < hkw) continue; |
5935 | 0 | else if (i+l >= tx_conv->width + hkw) continue; |
5936 | | |
5937 | 0 | u32 col = gf_evg_stencil_get_pixel(tx->stencil, i+l-hkw, j+k-hkh); |
5938 | 0 | kv = kdata[k*kw + l]; |
5939 | 0 | kr += kv * (s32) GF_COL_R(col); |
5940 | 0 | kg += kv * (s32) GF_COL_G(col); |
5941 | 0 | kb += kv * (s32) GF_COL_B(col); |
5942 | 0 | nb_pix++; |
5943 | 0 | } |
5944 | 0 | } |
5945 | |
|
5946 | 0 | if (nb_pix!=kl) { |
5947 | 0 | u32 n = knorm ? knorm : 1; |
5948 | 0 | if (nb_pix) n *= nb_pix; |
5949 | 0 | kr = (kr * kl / n); |
5950 | 0 | kg = (kg * kl / n); |
5951 | 0 | kb = (kb * kl / n); |
5952 | 0 | } else if (knorm) { |
5953 | 0 | kr /= knorm; |
5954 | 0 | kg /= knorm; |
5955 | 0 | kb /= knorm; |
5956 | 0 | } |
5957 | 0 | #define SET_CLAMP(_d, _s)\ |
5958 | 0 | if (_s<0) _d = 0;\ |
5959 | 0 | else if (_s>255) _d = 255;\ |
5960 | 0 | else _d = (u8) _s; |
5961 | |
|
5962 | 0 | SET_CLAMP(dst[0], kr) |
5963 | 0 | SET_CLAMP(dst[1], kg) |
5964 | 0 | SET_CLAMP(dst[2], kb) |
5965 | |
|
5966 | 0 | dst += 3; |
5967 | 0 | } |
5968 | 0 | } |
5969 | 0 | gf_free(kdata); |
5970 | |
|
5971 | 0 | tx_conv->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE); |
5972 | 0 | gf_evg_stencil_set_texture(tx_conv->stencil, tx_conv->data, tx_conv->width, tx_conv->height, tx_conv->stride, tx_conv->pf); |
5973 | 0 | nobj = JS_NewObjectClass(c, texture_class_id); |
5974 | 0 | JS_SetOpaque(nobj, tx_conv); |
5975 | 0 | return nobj; |
5976 | 0 | } |
5977 | | |
5978 | | static JSValue texture_update(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
5979 | 0 | { |
5980 | 0 | GF_Err e; |
5981 | 0 | u32 width=0, height=0, pf=0, stride=0, stride_uv=0; |
5982 | 0 | u8 *data=NULL; |
5983 | 0 | u8 *p_u=NULL; |
5984 | 0 | u8 *p_v=NULL; |
5985 | 0 | u8 *p_a=NULL; |
5986 | |
|
5987 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
5988 | 0 | if (!tx || !tx->stencil || !argc) return GF_JS_EXCEPTION(c); |
5989 | | |
5990 | 0 | JS_FreeValue(c, tx->par_obj); |
5991 | 0 | tx->par_obj = JS_UNDEFINED; |
5992 | |
|
5993 | 0 | if (JS_IsObject(argv[0])) { |
5994 | | //create from canvas object |
5995 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(argv[0], canvas_class_id); |
5996 | 0 | if (canvas) { |
5997 | 0 | width = canvas->width; |
5998 | 0 | height = canvas->height; |
5999 | 0 | stride = canvas->stride; |
6000 | 0 | stride_uv = canvas->stride_uv; |
6001 | 0 | data = canvas->data; |
6002 | 0 | pf = canvas->pf; |
6003 | 0 | tx->par_obj = JS_DupValue(c, argv[0]); |
6004 | 0 | } |
6005 | | //create from filter packet |
6006 | 0 | else if (jsf_is_packet(c, argv[0])) { |
6007 | 0 | 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); |
6008 | 0 | if (e) return js_throw_err(c, e); |
6009 | | #ifndef GPAC_DISABLE_3D |
6010 | | if (tx->gl_named_tx) { |
6011 | | JSValue wgl_named_texture_upload(JSContext *c, JSValueConst pck_obj, void *named_tx, Bool force_resetup); |
6012 | | |
6013 | | if (pf != tx->pf) { |
6014 | | tx->pf = pf; |
6015 | | tx->force_resetup = GF_TRUE; |
6016 | | } |
6017 | | JSValue res = wgl_named_texture_upload(c, argv[0], tx->gl_named_tx, tx->force_resetup); |
6018 | | tx->force_resetup = GF_FALSE; |
6019 | | if (JS_IsException(res)) return res; |
6020 | | } |
6021 | | #endif //GPAC_DISABLE_3D |
6022 | 0 | } else { |
6023 | 0 | return js_throw_err(c, GF_BAD_PARAM); |
6024 | 0 | } |
6025 | 0 | } else { |
6026 | 0 | return js_throw_err(c, GF_BAD_PARAM); |
6027 | 0 | } |
6028 | | |
6029 | 0 | tx->owns_data = GF_FALSE; |
6030 | 0 | tx->width = width; |
6031 | 0 | tx->height = height; |
6032 | 0 | tx->pf = pf; |
6033 | 0 | tx->stride = stride; |
6034 | 0 | tx->stride_uv = stride_uv; |
6035 | 0 | tx->data = data; |
6036 | 0 | if (p_u || p_v) { |
6037 | 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); |
6038 | 0 | if (e) return js_throw_err(c, e); |
6039 | 0 | } else { |
6040 | 0 | gf_assert(data); |
6041 | 0 | e = gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf); |
6042 | 0 | if (e) return js_throw_err(c, e); |
6043 | 0 | } |
6044 | | |
6045 | 0 | if (tx->pf) { |
6046 | 0 | tx->nb_comp = gf_pixel_get_nb_comp(tx->pf); |
6047 | 0 | gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, NULL, NULL, NULL, NULL); |
6048 | 0 | } |
6049 | 0 | return JS_UNDEFINED; |
6050 | 0 | } |
6051 | | |
6052 | | static JSValue texture_get_pixel_internal(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv, Bool is_float) |
6053 | 0 | { |
6054 | 0 | Bool as_array=GF_FALSE; |
6055 | 0 | JSValue ret; |
6056 | 0 | Double x, y; |
6057 | 0 | GF_Vec4 col; |
6058 | |
|
6059 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6060 | 0 | if (!tx || !tx->stencil || (argc<2) ) return GF_JS_EXCEPTION(c); |
6061 | | |
6062 | 0 | if (is_float) { |
6063 | 0 | if (JS_ToFloat64(c, &x, argv[0])) return GF_JS_EXCEPTION(c); |
6064 | 0 | if (JS_ToFloat64(c, &y, argv[1])) return GF_JS_EXCEPTION(c); |
6065 | 0 | } else { |
6066 | 0 | s32 _x, _y; |
6067 | 0 | if (JS_ToInt32(c, &_x, argv[0])) return GF_JS_EXCEPTION(c); |
6068 | 0 | if (JS_ToInt32(c, &_y, argv[1])) return GF_JS_EXCEPTION(c); |
6069 | 0 | x = ((Float)_x) / tx->width; |
6070 | 0 | y = ((Float)_y) / tx->height; |
6071 | 0 | } |
6072 | 0 | if ((argc>2) && JS_ToBool(c, argv[2])) |
6073 | 0 | as_array = GF_TRUE; |
6074 | |
|
6075 | 0 | col = gf_evg_stencil_get_pixel_f(tx->stencil, (Float) x, (Float) y); |
6076 | |
|
6077 | 0 | if (as_array) { |
6078 | 0 | ret = JS_NewArray(c); |
6079 | 0 | JS_SetPropertyStr(c, ret, "length", JS_NewInt32(c, 4) ); |
6080 | 0 | JS_SetPropertyUint32(c, ret, 0, JS_NewFloat64(c, col.x) ); |
6081 | 0 | JS_SetPropertyUint32(c, ret, 1, JS_NewFloat64(c, col.y) ); |
6082 | 0 | JS_SetPropertyUint32(c, ret, 2, JS_NewFloat64(c, col.z) ); |
6083 | 0 | JS_SetPropertyUint32(c, ret, 3, JS_NewFloat64(c, col.q) ); |
6084 | 0 | } else { |
6085 | 0 | ret = JS_NewObject(c); |
6086 | 0 | JS_SetPropertyStr(c, ret, "r", JS_NewFloat64(c, col.x) ); |
6087 | 0 | JS_SetPropertyStr(c, ret, "g", JS_NewFloat64(c, col.y) ); |
6088 | 0 | JS_SetPropertyStr(c, ret, "b", JS_NewFloat64(c, col.z) ); |
6089 | 0 | JS_SetPropertyStr(c, ret, "a", JS_NewFloat64(c, col.q) ); |
6090 | 0 | } |
6091 | 0 | return ret; |
6092 | 0 | } |
6093 | | static JSValue texture_get_pixel(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6094 | 0 | { |
6095 | 0 | return texture_get_pixel_internal(c, obj, argc, argv, GF_FALSE); |
6096 | 0 | } |
6097 | | |
6098 | | static JSValue texture_get_pixelf(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6099 | 0 | { |
6100 | 0 | return texture_get_pixel_internal(c, obj, argc, argv, GF_TRUE); |
6101 | 0 | } |
6102 | | |
6103 | | static GF_Err texture_load_data(JSContext *c, GF_JSTexture *tx, u8 *data, u32 size) |
6104 | 0 | { |
6105 | 0 | #ifndef GPAC_DISABLE_AV_PARSERS |
6106 | 0 | GF_Err e; |
6107 | 0 | GF_BitStream *bs; |
6108 | 0 | u8 *dsi=NULL; |
6109 | 0 | u32 codecid, width, height, pf, dsi_len, osize; |
6110 | |
|
6111 | 0 | bs = gf_bs_new(data, size, GF_BITSTREAM_READ); |
6112 | 0 | gf_img_parse(bs, &codecid, &width, &height, &dsi, &dsi_len); |
6113 | 0 | gf_bs_del(bs); |
6114 | |
|
6115 | 0 | e = GF_NOT_SUPPORTED; |
6116 | 0 | if (codecid==GF_CODECID_PNG) { |
6117 | 0 | e = gf_img_png_dec(data, size, &width, &height, &pf, NULL, &osize); |
6118 | 0 | if (e ==GF_BUFFER_TOO_SMALL) { |
6119 | 0 | tx->owns_data = GF_TRUE; |
6120 | 0 | tx->data_size = osize; |
6121 | 0 | tx->data = gf_malloc(sizeof(char) * osize); |
6122 | 0 | e = gf_img_png_dec(data, size, &width, &height, &pf, tx->data, &osize); |
6123 | 0 | if (e==GF_OK) { |
6124 | 0 | tx->width = width; |
6125 | 0 | tx->height = height; |
6126 | 0 | tx->pf = pf; |
6127 | 0 | } |
6128 | 0 | } |
6129 | 0 | } |
6130 | 0 | if (codecid==GF_CODECID_JPEG) { |
6131 | 0 | e = gf_img_jpeg_dec(data, size, &width, &height, &pf, NULL, &osize, 0); |
6132 | 0 | if (e ==GF_BUFFER_TOO_SMALL) { |
6133 | 0 | tx->owns_data = GF_TRUE; |
6134 | 0 | tx->data_size = osize; |
6135 | 0 | tx->data = gf_malloc(sizeof(char) * osize); |
6136 | 0 | e = gf_img_jpeg_dec(data, size, &width, &height, &pf, tx->data, &osize, 0); |
6137 | 0 | if (e==GF_OK) { |
6138 | 0 | tx->width = width; |
6139 | 0 | tx->height = height; |
6140 | 0 | tx->pf = pf; |
6141 | 0 | } |
6142 | 0 | } |
6143 | 0 | } |
6144 | 0 | if (dsi) gf_free(dsi); |
6145 | |
|
6146 | 0 | if (e != GF_OK) { |
6147 | 0 | return e; |
6148 | 0 | } |
6149 | 0 | tx->nb_comp = gf_pixel_get_nb_comp(tx->pf); |
6150 | 0 | gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, &tx->stride, NULL, NULL, NULL); |
6151 | 0 | e = gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf); |
6152 | 0 | if (e != GF_OK) { |
6153 | 0 | return e; |
6154 | 0 | } |
6155 | 0 | return GF_OK; |
6156 | | #else |
6157 | | return GF_NOT_SUPPORTED; |
6158 | | #endif |
6159 | 0 | } |
6160 | | static GF_Err texture_load_file(JSContext *c, GF_JSTexture *tx, const char *fileName, Bool rel_to_script) |
6161 | 0 | { |
6162 | 0 | char szPath[GF_MAX_PATH]; |
6163 | 0 | u8 *data; |
6164 | 0 | u32 size; |
6165 | 0 | GF_Err e; |
6166 | 0 | char *full_url = NULL; |
6167 | |
|
6168 | 0 | if (rel_to_script) { |
6169 | 0 | const char *par_url = jsf_get_script_filename(c); |
6170 | 0 | full_url = gf_url_concatenate(par_url, fileName); |
6171 | 0 | fileName = full_url; |
6172 | 0 | } |
6173 | 0 | if (!strncmp(fileName, "$GSHARE/", 8)) { |
6174 | 0 | gf_opts_default_shared_directory(szPath); |
6175 | 0 | strcat(szPath, fileName + 7); |
6176 | 0 | fileName = szPath; |
6177 | 0 | } |
6178 | 0 | if (!gf_file_exists(fileName) || (gf_file_load_data(fileName, &data, &size) != GF_OK)) { |
6179 | 0 | if (full_url) gf_free(full_url); |
6180 | 0 | return GF_URL_ERROR; |
6181 | 0 | } |
6182 | 0 | if (full_url) gf_free(full_url); |
6183 | 0 | e = texture_load_data(c, tx, data, size); |
6184 | 0 | gf_free(data); |
6185 | 0 | return e; |
6186 | 0 | } |
6187 | | |
6188 | | static JSValue texture_load(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6189 | 0 | { |
6190 | 0 | GF_Err e; |
6191 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6192 | 0 | if (!tx || !tx->stencil || (argc<1) ) return GF_JS_EXCEPTION(c); |
6193 | | |
6194 | 0 | if (JS_IsString(argv[0])) { |
6195 | 0 | JSValue ret = JS_UNDEFINED; |
6196 | 0 | Bool rel_to_script = GF_FALSE; |
6197 | 0 | const char *str = JS_ToCString(c, argv[0]); |
6198 | 0 | if (argc>1) rel_to_script = JS_ToBool(c, argv[1]); |
6199 | 0 | e = texture_load_file(c, tx, str, rel_to_script); |
6200 | 0 | if (e) { |
6201 | 0 | ret = js_throw_err_msg(c, e, "Failed to load texture file %s: %s", str, gf_error_to_string(e)); |
6202 | 0 | } |
6203 | 0 | JS_FreeCString(c, str); |
6204 | 0 | return ret; |
6205 | 0 | } |
6206 | 0 | if (JS_IsArrayBuffer(c, argv[0])) { |
6207 | 0 | size_t data_size; |
6208 | 0 | u8 *data = JS_GetArrayBuffer(c, &data_size, argv[0]); |
6209 | 0 | if (!data) { |
6210 | 0 | e = GF_BAD_PARAM; |
6211 | 0 | } else { |
6212 | 0 | e = texture_load_data(c, tx, data, (u32) data_size); |
6213 | 0 | } |
6214 | 0 | if (e) { |
6215 | 0 | return js_throw_err_msg(c, e, "Failed to load texture: %s", gf_error_to_string(e)); |
6216 | 0 | } |
6217 | 0 | return JS_UNDEFINED; |
6218 | 0 | } |
6219 | | |
6220 | 0 | return GF_JS_EXCEPTION(c); |
6221 | 0 | } |
6222 | | |
6223 | | static JSValue texture_set_named(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6224 | 0 | { |
6225 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6226 | 0 | if (!tx || !tx->stencil || (argc<1) ) return GF_JS_EXCEPTION(c); |
6227 | | |
6228 | | #ifndef GPAC_DISABLE_3D |
6229 | | const char *str = JS_ToCString(c, argv[0]); |
6230 | | if (tx->named_tx) gf_free(tx->named_tx); |
6231 | | tx->named_tx = str ? gf_strdup(str) : NULL; |
6232 | | JS_FreeCString(c, str); |
6233 | | #endif |
6234 | 0 | return JS_UNDEFINED; |
6235 | 0 | } |
6236 | | |
6237 | | static JSValue texture_set_pad_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6238 | 0 | { |
6239 | 0 | u32 color = 0; |
6240 | 0 | GF_Err e; |
6241 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6242 | 0 | if (!tx || !tx->stencil) return GF_JS_EXCEPTION(c); |
6243 | 0 | if (argc) { |
6244 | 0 | Double a, r, g, b; |
6245 | 0 | if (!get_color_from_args(c, argc, argv, 0, &a, &r, &g, &b)) |
6246 | 0 | return GF_JS_EXCEPTION(c); |
6247 | | |
6248 | 0 | a*=255; |
6249 | 0 | r*=255; |
6250 | 0 | g*=255; |
6251 | 0 | b*=255; |
6252 | 0 | color = GF_COL_ARGB(a, r, g, b); |
6253 | 0 | } |
6254 | 0 | e = gf_evg_stencil_set_pad_color(tx->stencil, color); |
6255 | 0 | if (e) { |
6256 | 0 | return js_throw_err_msg(c, e, "Failed to set texture pad color: %s", gf_error_to_string(e)); |
6257 | 0 | } |
6258 | 0 | return JS_UNDEFINED; |
6259 | 0 | } |
6260 | | |
6261 | | static JSValue texture_get_pad_color(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6262 | 0 | { |
6263 | 0 | char szCol[12]; |
6264 | 0 | u32 color = 0; |
6265 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6266 | 0 | if (!tx || !tx->stencil) return GF_JS_EXCEPTION(c); |
6267 | | |
6268 | 0 | color = gf_evg_stencil_get_pad_color(tx->stencil); |
6269 | 0 | if (!color) return JS_NewString(c, "none"); |
6270 | 0 | sprintf(szCol, "0x%02X%02X%02X%02X", GF_COL_A(color), GF_COL_R(color), GF_COL_G(color), GF_COL_B(color) ); |
6271 | 0 | return JS_NewString(c, szCol); |
6272 | 0 | } |
6273 | | |
6274 | | u32 gf_evg_stencil_get_pixel_fast(GF_EVGStencil *st, s32 x, s32 y); |
6275 | | |
6276 | | static JSValue texture_diff_score(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6277 | 0 | { |
6278 | 0 | u32 i, j; |
6279 | 0 | Bool is_yuv=GF_FALSE; |
6280 | 0 | Bool has_alpha=GF_FALSE; |
6281 | 0 | Bool split_sums=GF_FALSE; |
6282 | 0 | Bool do_mae = GF_FALSE, do_mse = GF_FALSE; |
6283 | 0 | Double mae_r=0, mae_g=0, mae_b=0, mae_a=0; |
6284 | 0 | Double mse_r=0, mse_g=0, mse_b=0, mse_a=0; |
6285 | 0 | GF_JSTexture *tx = JS_GetOpaque(obj, texture_class_id); |
6286 | 0 | if (!tx || !tx->stencil || !argc) return GF_JS_EXCEPTION(c); |
6287 | 0 | GF_JSTexture *tx_with = JS_GetOpaque(argv[0], texture_class_id); |
6288 | 0 | if (!tx_with || !tx_with->stencil) return GF_JS_EXCEPTION(c); |
6289 | | |
6290 | 0 | if (tx_with->width != tx->width) return GF_JS_EXCEPTION(c); |
6291 | 0 | if (tx_with->height != tx->height) return GF_JS_EXCEPTION(c); |
6292 | 0 | if (tx_with->pf != tx->pf) return GF_JS_EXCEPTION(c); |
6293 | | |
6294 | 0 | if (argc>1) { |
6295 | 0 | int idx=1; |
6296 | 0 | if (JS_IsString(argv[1])) { |
6297 | 0 | const char * str = JS_ToCString(c, argv[1]); |
6298 | 0 | if (strstr(str, "mae")) do_mae = GF_TRUE; |
6299 | 0 | if (strstr(str, "mse")) do_mse = GF_TRUE; |
6300 | 0 | idx++; |
6301 | 0 | JS_FreeCString(c, str); |
6302 | 0 | } |
6303 | 0 | if ((argc>idx) && JS_ToBool(c, argv[idx])) { |
6304 | 0 | split_sums = GF_TRUE; |
6305 | 0 | } |
6306 | 0 | } |
6307 | 0 | if (!do_mae && !do_mse) do_mae = GF_TRUE; |
6308 | |
|
6309 | 0 | if (!split_sums && gf_pixel_fmt_is_yuv(tx->pf)) { |
6310 | 0 | is_yuv = GF_TRUE; |
6311 | 0 | } |
6312 | |
|
6313 | 0 | has_alpha = gf_pixel_fmt_is_transparent(tx->pf); |
6314 | |
|
6315 | 0 | for (j=0; j<tx->height; j++) { |
6316 | 0 | u64 mae_line_r=0, mae_line_g=0, mae_line_b=0, mae_line_a=0; |
6317 | 0 | u64 mse_line_r=0, mse_line_g=0, mse_line_b=0, mse_line_a=0; |
6318 | 0 | for (i=0; i<tx->width; i++) { |
6319 | 0 | u32 pval, pval2; |
6320 | 0 | if (is_yuv) { |
6321 | 0 | pval = gf_evg_stencil_get_pixel_fast(tx->stencil, i, j); |
6322 | 0 | pval2 = gf_evg_stencil_get_pixel_fast(tx_with->stencil, i, j); |
6323 | 0 | } else { |
6324 | 0 | pval = gf_evg_stencil_get_pixel_fast(tx->stencil, i, j); |
6325 | 0 | pval2 = gf_evg_stencil_get_pixel_fast(tx_with->stencil, i, j); |
6326 | 0 | } |
6327 | 0 | s32 this_c = GF_COL_R(pval); |
6328 | 0 | s32 prev_c = GF_COL_R(pval2); |
6329 | 0 | if (do_mse) mse_line_r += (this_c-prev_c)*(this_c-prev_c); |
6330 | 0 | if (do_mae) { |
6331 | 0 | if (prev_c<this_c) mae_line_r += this_c-prev_c; |
6332 | 0 | else mae_line_r += prev_c-this_c; |
6333 | 0 | } |
6334 | |
|
6335 | 0 | if (has_alpha) { |
6336 | 0 | this_c = GF_COL_A(pval); |
6337 | 0 | prev_c = GF_COL_A(pval2); |
6338 | 0 | if (do_mse) mse_line_a += (this_c-prev_c)*(this_c-prev_c); |
6339 | 0 | if (do_mae) { |
6340 | 0 | if (prev_c<this_c) mae_line_a += this_c-prev_c; |
6341 | 0 | else mae_line_a += prev_c-this_c; |
6342 | 0 | } |
6343 | 0 | } |
6344 | |
|
6345 | 0 | if (is_yuv) continue; |
6346 | | |
6347 | 0 | this_c = GF_COL_G(pval); |
6348 | 0 | prev_c = GF_COL_G(pval2); |
6349 | 0 | if (do_mse) mse_line_g += (this_c-prev_c)*(this_c-prev_c); |
6350 | 0 | if (do_mae) { |
6351 | 0 | if (prev_c<this_c) mae_line_g += this_c-prev_c; |
6352 | 0 | else mae_line_g += prev_c-this_c; |
6353 | 0 | } |
6354 | |
|
6355 | 0 | this_c = GF_COL_B(pval); |
6356 | 0 | prev_c = GF_COL_B(pval2); |
6357 | 0 | if (do_mse) mse_line_b += (this_c-prev_c)*(this_c-prev_c); |
6358 | 0 | if (do_mae) { |
6359 | 0 | if (prev_c<this_c) mae_line_b += this_c-prev_c; |
6360 | 0 | else mae_line_b += prev_c-this_c; |
6361 | 0 | } |
6362 | 0 | } |
6363 | 0 | mae_r += mae_line_r; |
6364 | 0 | mae_g += mae_line_g; |
6365 | 0 | mae_b += mae_line_b; |
6366 | 0 | mae_a += mae_line_a; |
6367 | |
|
6368 | 0 | mse_r += mse_line_r; |
6369 | 0 | mse_g += mse_line_g; |
6370 | 0 | mse_b += mse_line_b; |
6371 | 0 | mse_a += mse_line_a; |
6372 | 0 | } |
6373 | |
|
6374 | 0 | u64 div = tx->height * tx->width * 255; |
6375 | 0 | u64 div_mse = div * 255; |
6376 | |
|
6377 | 0 | u32 nb_p=1; |
6378 | 0 | Double mae = mae_r; |
6379 | 0 | Double mse = mse_r; |
6380 | 0 | mae_r /= div; |
6381 | 0 | mse_r /= div_mse; |
6382 | 0 | if (has_alpha) { |
6383 | 0 | mae += mae_a; |
6384 | 0 | mse += mse_a; |
6385 | 0 | nb_p=2; |
6386 | 0 | mae_a /= div; |
6387 | 0 | mse_a /= div_mse; |
6388 | 0 | } |
6389 | 0 | if (!is_yuv) { |
6390 | 0 | mae += mae_g + mae_b; |
6391 | 0 | mse += mse_g + mse_b; |
6392 | 0 | nb_p = 4; |
6393 | 0 | mae_g /= div; |
6394 | 0 | mae_b /= div; |
6395 | 0 | mse_g /= div_mse; |
6396 | 0 | mse_b /= div_mse; |
6397 | 0 | } |
6398 | 0 | #define FCLAMP(_v)\ |
6399 | 0 | if (_v<0) _v = 0;\ |
6400 | 0 | else if (_v>1.0) _v = 1.0;\ |
6401 | 0 |
|
6402 | |
|
6403 | 0 | if (!split_sums) { |
6404 | 0 | JSValue ar = JS_NewArray(c); |
6405 | 0 | if (JS_IsException(ar)) return GF_JS_EXCEPTION(c); |
6406 | 0 | JSValue v = JS_NewObject(c); |
6407 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
6408 | | |
6409 | 0 | mae /= div * nb_p; |
6410 | 0 | mse /= div_mse * nb_p; |
6411 | 0 | FCLAMP(mae) |
6412 | 0 | FCLAMP(mse) |
6413 | 0 | JS_SetPropertyStr(c, v, "mae", JS_NewFloat64(c, mae*100)); |
6414 | 0 | JS_SetPropertyStr(c, v, "mse", JS_NewFloat64(c, mse*100)); |
6415 | 0 | JS_SetPropertyUint32(c, ar, 0, v); |
6416 | 0 | return ar; |
6417 | 0 | } |
6418 | | |
6419 | 0 | JSValue ar = JS_NewArray(c); |
6420 | 0 | if (JS_IsException(ar)) return GF_JS_EXCEPTION(c); |
6421 | 0 | FCLAMP(mae_r) |
6422 | 0 | FCLAMP(mae_g) |
6423 | 0 | FCLAMP(mae_b) |
6424 | 0 | FCLAMP(mae_a) |
6425 | 0 | FCLAMP(mse_r) |
6426 | 0 | FCLAMP(mse_g) |
6427 | 0 | FCLAMP(mse_b) |
6428 | 0 | FCLAMP(mse_a) |
6429 | |
|
6430 | 0 | JSValue v = JS_NewObject(c); |
6431 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
6432 | 0 | JS_SetPropertyStr(c, v, "mae", JS_NewFloat64(c, mae_r*100)); |
6433 | 0 | JS_SetPropertyStr(c, v, "mse", JS_NewFloat64(c, mse_r*100)); |
6434 | 0 | JS_SetPropertyUint32(c, ar, 0, v); |
6435 | |
|
6436 | 0 | v = JS_NewObject(c); |
6437 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
6438 | 0 | JS_SetPropertyStr(c, v, "mae", JS_NewFloat64(c, mae_g*100)); |
6439 | 0 | JS_SetPropertyStr(c, v, "mse", JS_NewFloat64(c, mse_g*100)); |
6440 | 0 | JS_SetPropertyUint32(c, ar, 1, v); |
6441 | |
|
6442 | 0 | v = JS_NewObject(c); |
6443 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
6444 | 0 | JS_SetPropertyStr(c, v, "mae", JS_NewFloat64(c, mae_b*100)); |
6445 | 0 | JS_SetPropertyStr(c, v, "mse", JS_NewFloat64(c, mse_b*100)); |
6446 | 0 | JS_SetPropertyUint32(c, ar, 2, v); |
6447 | |
|
6448 | 0 | if (has_alpha) { |
6449 | 0 | v = JS_NewObject(c); |
6450 | 0 | if (JS_IsException(v)) return GF_JS_EXCEPTION(c); |
6451 | 0 | JS_SetPropertyStr(c, v, "mae", JS_NewFloat64(c, mae_a*100)); |
6452 | 0 | JS_SetPropertyStr(c, v, "mse", JS_NewFloat64(c, mse_a*100)); |
6453 | 0 | JS_SetPropertyUint32(c, ar, 3, v); |
6454 | 0 | } |
6455 | 0 | return ar; |
6456 | 0 | } |
6457 | | |
6458 | | static const JSCFunctionListEntry texture_funcs[] = |
6459 | | { |
6460 | | JS_CGETSET_MAGIC_DEF("filtering", NULL, texture_setProperty, TX_FILTER), |
6461 | | JS_CGETSET_MAGIC_DEF("cmx", texture_getProperty, texture_setProperty, TX_CMX), |
6462 | | JS_CGETSET_MAGIC_DEF("mx", texture_getProperty, texture_setProperty, TX_MAT), |
6463 | | JS_CGETSET_MAGIC_DEF("auto_mx", texture_getProperty, texture_setProperty, TX_MAT_AUTO), |
6464 | | JS_CGETSET_MAGIC_DEF("repeat_s", texture_getProperty, texture_setProperty, TX_REPEAT_S), |
6465 | | JS_CGETSET_MAGIC_DEF("repeat_t", texture_getProperty, texture_setProperty, TX_REPEAT_T), |
6466 | | JS_CGETSET_MAGIC_DEF("flip_h", texture_getProperty, texture_setProperty, TX_FLIP_X), |
6467 | | JS_CGETSET_MAGIC_DEF("flip_v", texture_getProperty, texture_setProperty, TX_FLIP_Y), |
6468 | | JS_CGETSET_MAGIC_DEF("width", texture_getProperty, NULL, TX_WIDTH), |
6469 | | JS_CGETSET_MAGIC_DEF("height", texture_getProperty, NULL, TX_HEIGHT), |
6470 | | JS_CGETSET_MAGIC_DEF("pixfmt", texture_getProperty, NULL, TX_PIXFMT), |
6471 | | JS_CGETSET_MAGIC_DEF("comp", texture_getProperty, NULL, TX_NB_COMP), |
6472 | | JS_CGETSET_MAGIC_DEF("data", texture_getProperty, NULL, TX_DATA), |
6473 | | |
6474 | | JS_CFUNC_DEF("set_alpha", 0, stencil_set_alpha), |
6475 | | JS_CFUNC_DEF("set_alphaf", 0, stencil_set_alphaf), |
6476 | | JS_CFUNC_DEF("get_alphaf", 0, stencil_get_alphaf), |
6477 | | JS_CFUNC_DEF("rgb2hsv", 0, texture_rgb2hsv), |
6478 | | JS_CFUNC_DEF("hsv2rgb", 0, texture_hsv2rgb), |
6479 | | JS_CFUNC_DEF("rgb2yuv", 0, texture_rgb2yuv), |
6480 | | JS_CFUNC_DEF("yuv2rgb", 0, texture_yuv2rgb), |
6481 | | JS_CFUNC_DEF("convolution", 0, texture_convolution), |
6482 | | JS_CFUNC_DEF("split", 0, texture_split), |
6483 | | JS_CFUNC_DEF("update", 0, texture_update), |
6484 | | JS_CFUNC_DEF("get_pixelf", 0, texture_get_pixelf), |
6485 | | JS_CFUNC_DEF("get_pixel", 0, texture_get_pixel), |
6486 | | JS_CFUNC_DEF("load", 0, texture_load), |
6487 | | JS_CFUNC_DEF("set_named", 0, texture_set_named), |
6488 | | JS_CFUNC_DEF("set_pad_color", 0, texture_set_pad_color), |
6489 | | JS_CFUNC_DEF("get_pad_color", 0, texture_get_pad_color), |
6490 | | JS_CFUNC_DEF("diff_score", 0, texture_diff_score), |
6491 | | }; |
6492 | | |
6493 | | |
6494 | | static void evg_param_tex_callback(void *cbk, u32 x, u32 y, Float *r, Float *g, Float *b, Float *a) |
6495 | 0 | { |
6496 | 0 | Double compv; |
6497 | 0 | JSValue ret, v, argv[2]; |
6498 | 0 | GF_JSTexture *tx = (GF_JSTexture *)cbk; |
6499 | |
|
6500 | 0 | if (!gf_js_try_lock(tx->ctx)) { |
6501 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CONSOLE, ("[JS] Failed to lock JS context in parametric texture, cannot fetch pixel\n" )); |
6502 | 0 | return; |
6503 | 0 | } |
6504 | | |
6505 | 0 | argv[0] = JS_NewInt32(tx->ctx, x); |
6506 | 0 | argv[1] = JS_NewInt32(tx->ctx, y); |
6507 | 0 | ret = JS_Call(tx->ctx, tx->param_fun, tx->obj, 2, argv); |
6508 | 0 | JS_FreeValue(tx->ctx, argv[0]); |
6509 | 0 | JS_FreeValue(tx->ctx, argv[1]); |
6510 | |
|
6511 | 0 | *r = *g = *b = 0.0; |
6512 | 0 | *a = 1.0; |
6513 | 0 | #define GETCOMP(_comp)\ |
6514 | 0 | v = JS_GetPropertyStr(tx->ctx, ret, #_comp);\ |
6515 | 0 | if (!JS_IsUndefined(v)) {\ |
6516 | 0 | JS_ToFloat64(tx->ctx, &compv, v);\ |
6517 | 0 | JS_FreeValue(tx->ctx, v);\ |
6518 | 0 | *_comp = (Float) compv;\ |
6519 | 0 | }\ |
6520 | 0 |
|
6521 | 0 | GETCOMP(r) |
6522 | 0 | GETCOMP(g) |
6523 | 0 | GETCOMP(b) |
6524 | 0 | GETCOMP(a) |
6525 | |
|
6526 | 0 | #undef GETCOMP |
6527 | 0 | JS_FreeValue(tx->ctx, ret); |
6528 | |
|
6529 | 0 | gf_js_lock(tx->ctx, GF_FALSE); |
6530 | 0 | } |
6531 | | |
6532 | | static JSValue texture_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
6533 | 0 | { |
6534 | 0 | Bool use_screen_coords=GF_FALSE; |
6535 | 0 | JSValue obj; |
6536 | 0 | JSValue tx_fun=JS_UNDEFINED; |
6537 | 0 | u32 width=0, height=0, pf=0, stride=0, stride_uv=0; |
6538 | 0 | size_t data_size=0; |
6539 | 0 | u8 *data=NULL; |
6540 | 0 | u8 *p_u=NULL; |
6541 | 0 | u8 *p_v=NULL; |
6542 | 0 | u8 *p_a=NULL; |
6543 | 0 | GF_JSTexture *tx; |
6544 | 0 | GF_SAFEALLOC(tx, GF_JSTexture); |
6545 | 0 | if (!tx) |
6546 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
6547 | 0 | tx->stencil = gf_evg_stencil_new(GF_STENCIL_TEXTURE); |
6548 | 0 | if (!tx->stencil) { |
6549 | 0 | gf_free(tx); |
6550 | 0 | return GF_JS_EXCEPTION(c); |
6551 | 0 | } |
6552 | 0 | tx->param_fun = JS_UNDEFINED; |
6553 | 0 | tx->obj = JS_UNDEFINED; |
6554 | 0 | tx->par_obj = JS_UNDEFINED; |
6555 | 0 | if (!argc) goto done; |
6556 | | |
6557 | 0 | if (JS_IsString(argv[0])) { |
6558 | 0 | GF_Err e; |
6559 | 0 | Bool rel_to_script = GF_FALSE; |
6560 | 0 | const char *str = JS_ToCString(c, argv[0]); |
6561 | 0 | if (argc>1) rel_to_script = JS_ToBool(c, argv[1]); |
6562 | 0 | e = texture_load_file(c, tx, str, rel_to_script); |
6563 | 0 | JS_FreeCString(c, str); |
6564 | 0 | if (e) { |
6565 | 0 | if (tx->stencil) gf_evg_stencil_delete(tx->stencil); |
6566 | 0 | gf_free(tx); |
6567 | 0 | return js_throw_err_msg(c, e, "Failed to load texture: %s", gf_error_to_string(e)); |
6568 | 0 | } |
6569 | 0 | goto done; |
6570 | 0 | } |
6571 | 0 | if (JS_IsObject(argv[0])) { |
6572 | | |
6573 | | //create from canvas object |
6574 | 0 | GF_JSCanvas *canvas = JS_GetOpaque(argv[0], canvas_class_id); |
6575 | 0 | if (canvas) { |
6576 | 0 | width = canvas->width; |
6577 | 0 | height = canvas->height; |
6578 | 0 | stride = canvas->stride; |
6579 | 0 | stride_uv = canvas->stride_uv; |
6580 | 0 | data = canvas->data; |
6581 | 0 | pf = canvas->pf; |
6582 | 0 | tx->par_obj = JS_DupValue(c, argv[0]); |
6583 | 0 | } |
6584 | | //create from filter packet |
6585 | 0 | else if (jsf_is_packet(c, argv[0])) { |
6586 | 0 | 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); |
6587 | 0 | if (e) goto error; |
6588 | | |
6589 | 0 | if (!stride) { |
6590 | 0 | gf_pixel_get_size_info(pf, width, height, NULL, &stride, &stride_uv, NULL, NULL); |
6591 | 0 | } |
6592 | 0 | } else { |
6593 | 0 | data = JS_GetArrayBuffer(c, &data_size, argv[0]); |
6594 | 0 | if (data) { |
6595 | 0 | GF_Err e = texture_load_data(c, tx, data, (u32) data_size); |
6596 | 0 | if (e) { |
6597 | 0 | if (tx->stencil) gf_evg_stencil_delete(tx->stencil); |
6598 | 0 | gf_free(tx); |
6599 | 0 | return js_throw_err_msg(c, e, "Failed to load texture: %s", gf_error_to_string(e)); |
6600 | 0 | } |
6601 | 0 | tx->par_obj = JS_DupValue(c, argv[0]); |
6602 | 0 | goto done; |
6603 | 0 | } |
6604 | 0 | goto error; |
6605 | 0 | } |
6606 | 0 | } |
6607 | | //arraybuffer |
6608 | 0 | else { |
6609 | 0 | Bool is_ab = GF_FALSE; |
6610 | 0 | if (argc<4) goto error; |
6611 | 0 | if (JS_ToInt32(c, &width, argv[0])) goto error; |
6612 | 0 | if (JS_ToInt32(c, &height, argv[1])) goto error; |
6613 | 0 | if (JS_IsString(argv[2])) { |
6614 | 0 | const char *str = JS_ToCString(c, argv[2]); |
6615 | 0 | pf = gf_pixel_fmt_parse(str); |
6616 | 0 | JS_FreeCString(c, str); |
6617 | 0 | } else if (JS_ToInt32(c, &pf, argv[2])) { |
6618 | 0 | goto error; |
6619 | 0 | } |
6620 | 0 | if (JS_IsFunction(c, argv[3])) { |
6621 | 0 | tx_fun = argv[3]; |
6622 | 0 | } |
6623 | 0 | else if (JS_IsObject(argv[3])) { |
6624 | 0 | data = JS_GetArrayBuffer(c, &data_size, argv[3]); |
6625 | 0 | is_ab = GF_TRUE; |
6626 | 0 | } |
6627 | 0 | if (!width || !height || !pf || (!data && JS_IsUndefined(tx_fun))) |
6628 | 0 | goto error; |
6629 | | |
6630 | 0 | if (argc>4) { |
6631 | 0 | if (JS_ToInt32(c, &stride, argv[4])) |
6632 | 0 | goto error; |
6633 | 0 | if (argc>5) { |
6634 | 0 | if (JS_ToInt32(c, &stride_uv, argv[5])) |
6635 | 0 | goto error; |
6636 | 0 | } |
6637 | 0 | } |
6638 | 0 | if (is_ab) { |
6639 | 0 | tx->par_obj = JS_DupValue(c, argv[3]); |
6640 | 0 | } |
6641 | 0 | } |
6642 | | |
6643 | 0 | tx->owns_data = GF_FALSE; |
6644 | 0 | tx->width = width; |
6645 | 0 | tx->height = height; |
6646 | 0 | tx->pf = pf; |
6647 | 0 | tx->stride = stride; |
6648 | 0 | tx->stride_uv = stride_uv; |
6649 | 0 | tx->data = data; |
6650 | 0 | if (p_u || p_v) { |
6651 | 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) |
6652 | 0 | goto error; |
6653 | 0 | } else if (data) { |
6654 | 0 | if (gf_evg_stencil_set_texture(tx->stencil, tx->data, tx->width, tx->height, tx->stride, tx->pf) != GF_OK) |
6655 | 0 | goto error; |
6656 | 0 | } else { |
6657 | 0 | use_screen_coords = stride ? GF_TRUE : GF_FALSE; |
6658 | 0 | 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) |
6659 | 0 | goto error; |
6660 | 0 | tx->param_fun = JS_DupValue(c, tx_fun); |
6661 | 0 | tx->ctx = c; |
6662 | 0 | } |
6663 | | |
6664 | 0 | done: |
6665 | 0 | if (tx->pf) { |
6666 | 0 | tx->nb_comp = gf_pixel_get_nb_comp(tx->pf); |
6667 | 0 | tx->wide = (gf_pixel_is_wide_depth(tx->pf)>8) ? 1 : 0; |
6668 | 0 | gf_pixel_get_size_info(tx->pf, tx->width, tx->height, NULL, NULL, NULL, NULL, NULL); |
6669 | 0 | } |
6670 | 0 | obj = JS_NewObjectClass(c, texture_class_id); |
6671 | 0 | if (JS_IsException(obj)) return obj; |
6672 | 0 | JS_SetOpaque(obj, tx); |
6673 | 0 | tx->obj = obj; |
6674 | 0 | return obj; |
6675 | | |
6676 | 0 | error: |
6677 | 0 | if (tx->stencil) gf_evg_stencil_delete(tx->stencil); |
6678 | 0 | gf_free(tx); |
6679 | 0 | return js_throw_err_msg(c, GF_BAD_PARAM, "Failed to create texture"); |
6680 | 0 | } |
6681 | | |
6682 | | Bool js_evg_is_texture(JSContext *ctx, JSValue this_obj) |
6683 | 0 | { |
6684 | 0 | GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id); |
6685 | 0 | if (!tx) return GF_FALSE; |
6686 | 0 | return GF_TRUE; |
6687 | 0 | } |
6688 | | |
6689 | | 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) |
6690 | 0 | { |
6691 | 0 | GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id); |
6692 | 0 | if (!tx) return GF_FALSE; |
6693 | 0 | if (width) *width = tx->width; |
6694 | 0 | if (height) *height = tx->height; |
6695 | 0 | if (pixfmt) *pixfmt = tx->pf; |
6696 | 0 | if (stride) *stride = tx->stride; |
6697 | 0 | if (stride_uv) *stride_uv = tx->stride_uv; |
6698 | 0 | if (!tx->data) return GF_TRUE; |
6699 | 0 | if (p_data) *p_data = tx->data; |
6700 | 0 | if (p_u) *p_u = NULL; |
6701 | 0 | if (p_v) *p_v = NULL; |
6702 | 0 | if (p_a) *p_a = NULL; |
6703 | 0 | return GF_TRUE; |
6704 | 0 | } |
6705 | | |
6706 | | #ifndef GPAC_DISABLE_3D |
6707 | | const char *js_evg_get_texture_named(JSContext *ctx, JSValue this_obj) |
6708 | | { |
6709 | | GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id); |
6710 | | if (!tx) return NULL; |
6711 | | return tx->named_tx; |
6712 | | } |
6713 | | |
6714 | | void js_evg_set_named_texture_gl(JSContext *ctx, JSValue this_obj, void *gl_named_tx) |
6715 | | { |
6716 | | GF_JSTexture *tx = JS_GetOpaque(this_obj, texture_class_id); |
6717 | | if (!tx) return; |
6718 | | tx->gl_named_tx = gl_named_tx; |
6719 | | tx->force_resetup = GF_TRUE; |
6720 | | } |
6721 | | #endif |
6722 | | |
6723 | | #ifndef GPAC_DISABLE_FONTS |
6724 | | static void text_reset(GF_JSText *txt) |
6725 | 0 | { |
6726 | 0 | if (txt->path) gf_path_del(txt->path); |
6727 | 0 | txt->path = NULL; |
6728 | 0 | while (gf_list_count(txt->spans)) { |
6729 | 0 | GF_TextSpan *s = gf_list_pop_back(txt->spans); |
6730 | 0 | gf_font_manager_delete_span(txt->fm, s); |
6731 | 0 | } |
6732 | 0 | txt->min_x = txt->min_y = txt->max_x = txt->max_y = txt->max_w = txt->max_h = 0; |
6733 | 0 | } |
6734 | | |
6735 | | static void text_reset_fonts(GF_JSText *txt) |
6736 | 0 | { |
6737 | 0 | if (txt->fontnames) { |
6738 | 0 | u32 i; |
6739 | 0 | for (i=0; i<txt->nb_fonts; i++) { |
6740 | 0 | gf_free(txt->fontnames[i]); |
6741 | 0 | } |
6742 | 0 | gf_free(txt->fontnames); |
6743 | 0 | txt->fontnames = NULL; |
6744 | 0 | txt->nb_fonts = 0; |
6745 | 0 | } |
6746 | 0 | } |
6747 | | |
6748 | | static void text_finalize(JSRuntime *rt, JSValue obj) |
6749 | 0 | { |
6750 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
6751 | 0 | if (!txt) return; |
6752 | 0 | text_reset(txt); |
6753 | 0 | text_reset_fonts(txt); |
6754 | 0 | gf_list_del(txt->spans); |
6755 | 0 | gf_free(txt); |
6756 | 0 | } |
6757 | | |
6758 | | enum{ |
6759 | | TXT_FONT=0, |
6760 | | TXT_FONTSIZE, |
6761 | | TXT_ALIGN, |
6762 | | TXT_BASELINE, |
6763 | | TXT_HORIZ, |
6764 | | TXT_FLIP, |
6765 | | TXT_UNDERLINED, |
6766 | | TXT_BOLD, |
6767 | | TXT_ITALIC, |
6768 | | TXT_SMALLCAP, |
6769 | | TXT_STRIKEOUT, |
6770 | | TXT_MAX_WIDTH, |
6771 | | TXT_LINESPACING, |
6772 | | }; |
6773 | | |
6774 | | enum |
6775 | | { |
6776 | | TXT_BL_TOP=0, |
6777 | | TXT_BL_HANGING, |
6778 | | TXT_BL_MIDDLE, |
6779 | | TXT_BL_ALPHABETIC, |
6780 | | TXT_BL_IDEOGRAPHIC, |
6781 | | TXT_BL_BOTTOM, |
6782 | | }; |
6783 | | enum |
6784 | | { |
6785 | | TXT_AL_START=0, |
6786 | | TXT_AL_END, |
6787 | | TXT_AL_LEFT, |
6788 | | TXT_AL_RIGHT, |
6789 | | TXT_AL_CENTER |
6790 | | }; |
6791 | | |
6792 | | static JSValue text_getProperty(JSContext *c, JSValueConst obj, int magic) |
6793 | 0 | { |
6794 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
6795 | 0 | if (!txt) return GF_JS_EXCEPTION(c); |
6796 | 0 | switch (magic) { |
6797 | 0 | case TXT_FONT: |
6798 | 0 | { |
6799 | 0 | u32 i; |
6800 | 0 | JSValue res = JS_NewArray(c); |
6801 | 0 | JS_SetPropertyStr(c, res, "length", JS_NewInt32(c, txt->nb_fonts) ); |
6802 | 0 | for (i=0; i<txt->nb_fonts; i++) { |
6803 | 0 | JS_SetPropertyUint32(c, res, i, JS_NewString(c, txt->fontnames[i]) ); |
6804 | 0 | } |
6805 | 0 | return res; |
6806 | 0 | } |
6807 | 0 | case TXT_BASELINE: return JS_NewInt32(c, txt->baseline); |
6808 | 0 | case TXT_ALIGN: return JS_NewInt32(c, txt->align); |
6809 | 0 | case TXT_FONTSIZE: return JS_NewFloat64(c, txt->font_size); |
6810 | 0 | case TXT_HORIZ: return JS_NewBool(c, txt->horizontal); |
6811 | 0 | case TXT_FLIP: return JS_NewBool(c, txt->flip); |
6812 | 0 | case TXT_MAX_WIDTH: return JS_NewFloat64(c, txt->maxWidth); |
6813 | 0 | case TXT_LINESPACING: return JS_NewFloat64(c, txt->lineSpacing); |
6814 | 0 | case TXT_BOLD: return JS_NewBool(c, txt->styles & GF_FONT_WEIGHT_100); |
6815 | 0 | case TXT_ITALIC: return JS_NewBool(c, txt->styles & GF_FONT_ITALIC); |
6816 | 0 | case TXT_UNDERLINED: return JS_NewBool(c, txt->styles & GF_FONT_UNDERLINED); |
6817 | 0 | case TXT_SMALLCAP: return JS_NewBool(c, txt->styles & GF_FONT_SMALLCAPS); |
6818 | 0 | case TXT_STRIKEOUT: return JS_NewBool(c, txt->styles & GF_FONT_STRIKEOUT); |
6819 | 0 | } |
6820 | 0 | return JS_UNDEFINED; |
6821 | 0 | } |
6822 | | |
6823 | | #ifndef GPAC_DISABLE_FONTS |
6824 | | static void text_update_path(GF_JSText *txt, Bool for_centered) |
6825 | 0 | { |
6826 | 0 | Fixed cy, off_x, ascent, descent, scale_x, ls; |
6827 | 0 | u32 i, nb_lines; |
6828 | |
|
6829 | 0 | if ((txt->path_for_centered == for_centered) && txt->path) { |
6830 | 0 | return; |
6831 | 0 | } |
6832 | 0 | if (txt->path) gf_path_del(txt->path); |
6833 | 0 | txt->path = NULL; |
6834 | 0 | if (!txt->font) |
6835 | 0 | return; |
6836 | | |
6837 | 0 | txt->path_for_centered = for_centered; |
6838 | |
|
6839 | 0 | cy = FLT2FIX((txt->font_size * txt->font->baseline) / txt->font->em_size); |
6840 | |
|
6841 | 0 | ascent = FLT2FIX((txt->font_size*txt->font->ascent) / txt->font->em_size); |
6842 | 0 | if (txt->lineSpacing) |
6843 | 0 | ls = FLT2FIX((txt->lineSpacing*txt->font->line_spacing) / txt->font->em_size); |
6844 | 0 | else |
6845 | 0 | ls = FLT2FIX((txt->font_size*txt->font->line_spacing) / txt->font->em_size); |
6846 | 0 | descent = -FLT2FIX((txt->font_size*txt->font->descent) / txt->font->em_size); |
6847 | 0 | scale_x = 0; |
6848 | 0 | if (txt->maxWidth && txt->max_w && (txt->max_w > txt->maxWidth)) { |
6849 | 0 | scale_x = gf_divfix(FLT2FIX(txt->maxWidth), INT2FIX(txt->max_w) ); |
6850 | 0 | } |
6851 | |
|
6852 | 0 | if (txt->baseline==TXT_BL_TOP) { |
6853 | 0 | cy = ascent; |
6854 | 0 | } else if (txt->baseline==TXT_BL_BOTTOM) { |
6855 | 0 | cy = -descent; |
6856 | 0 | } else if (txt->baseline==TXT_BL_MIDDLE) { |
6857 | 0 | Fixed mid = (ascent + descent)/2; |
6858 | 0 | cy = mid; |
6859 | 0 | } |
6860 | 0 | off_x = 0; |
6861 | |
|
6862 | 0 | txt->right_to_left = GF_FALSE; |
6863 | 0 | txt->path = gf_path_new(); |
6864 | 0 | nb_lines = gf_list_count(txt->spans); |
6865 | 0 | for (i=0; i<nb_lines; i++) { |
6866 | 0 | Fixed cx=0; |
6867 | 0 | u32 flags; |
6868 | 0 | GF_Path *path; |
6869 | 0 | GF_Matrix2D mx; |
6870 | 0 | GF_TextSpan *span = gf_list_get(txt->spans, i); |
6871 | |
|
6872 | 0 | if (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT) |
6873 | 0 | txt->right_to_left = GF_TRUE; |
6874 | |
|
6875 | 0 | if ((txt->align == TXT_AL_LEFT) |
6876 | 0 | || ((txt->align == TXT_AL_START) && !(span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT)) |
6877 | 0 | || ((txt->align == TXT_AL_END) && (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT)) |
6878 | 0 | ) { |
6879 | 0 | cx = 0; |
6880 | 0 | } |
6881 | 0 | else if ((txt->align == TXT_AL_RIGHT) |
6882 | 0 | || ((txt->align == TXT_AL_END) && !(span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT)) |
6883 | 0 | || ((txt->align == TXT_AL_START) && (span->flags & GF_TEXT_SPAN_RIGHT_TO_LEFT)) |
6884 | 0 | ) { |
6885 | 0 | cx = txt->max_w - span->bounds.width; |
6886 | 0 | } else if (txt->align == TXT_AL_CENTER) { |
6887 | 0 | cx = (txt->max_w - span->bounds.width) / 2; |
6888 | 0 | } |
6889 | 0 | gf_mx2d_init(mx); |
6890 | |
|
6891 | 0 | gf_mx2d_add_translation(&mx, off_x+cx, cy); |
6892 | 0 | if (scale_x) |
6893 | 0 | gf_mx2d_add_scale(&mx, scale_x, FIX_ONE); |
6894 | |
|
6895 | 0 | flags = span->flags; |
6896 | 0 | if (txt->path_for_centered) { |
6897 | 0 | if (txt->flip) |
6898 | 0 | span->flags |= GF_TEXT_SPAN_FLIP; |
6899 | 0 | } else { |
6900 | 0 | if (!txt->flip) |
6901 | 0 | span->flags |= GF_TEXT_SPAN_FLIP; |
6902 | 0 | } |
6903 | |
|
6904 | 0 | path = gf_font_span_create_path(span); |
6905 | 0 | gf_path_add_subpath(txt->path, path, &mx); |
6906 | 0 | gf_path_del(path); |
6907 | 0 | span->flags = flags; |
6908 | |
|
6909 | 0 | if (!txt->horizontal) { |
6910 | 0 | off_x += ls; |
6911 | 0 | } else { |
6912 | 0 | if (txt->path_for_centered) |
6913 | 0 | cy -= ls; |
6914 | 0 | else |
6915 | 0 | cy += ls; |
6916 | 0 | } |
6917 | 0 | } |
6918 | 0 | } |
6919 | | |
6920 | | static void text_set_path(GF_JSCanvas *canvas, GF_JSText *txt) |
6921 | 0 | { |
6922 | 0 | text_update_path(txt, canvas->center_coords); |
6923 | 0 | gf_evg_surface_set_path(canvas->surface, txt->path); |
6924 | 0 | gf_evg_surface_force_aa(canvas->surface); |
6925 | 0 | } |
6926 | | #endif |
6927 | | |
6928 | | static void text_set_text_from_value(GF_JSText *txt, GF_Font *font, JSContext *c, JSValueConst value) |
6929 | 0 | { |
6930 | 0 | const char *str = JS_ToCString(c, value); |
6931 | 0 | char *start = (char *) str; |
6932 | 0 | while (start) { |
6933 | 0 | GF_TextSpan *span; |
6934 | 0 | char *nline = strchr(start, '\n'); |
6935 | 0 | if (nline) nline[0] = 0; |
6936 | 0 | span = gf_font_manager_create_span(txt->fm, font, (char *) start, FLT2FIX(txt->font_size), GF_FALSE, GF_FALSE, GF_FALSE, NULL, GF_FALSE, 0, NULL); |
6937 | 0 | if (span) { |
6938 | 0 | if (txt->horizontal) |
6939 | 0 | span->flags |= GF_TEXT_SPAN_HORIZONTAL; |
6940 | 0 | gf_list_add(txt->spans, span); |
6941 | 0 | } |
6942 | |
|
6943 | 0 | if (!nline) break; |
6944 | 0 | nline[0] = '\n'; |
6945 | 0 | start = nline + 1; |
6946 | 0 | } |
6947 | 0 | JS_FreeCString(c, str); |
6948 | 0 | } |
6949 | | |
6950 | | static JSValue text_get_path(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6951 | 0 | { |
6952 | 0 | JSValue nobj; |
6953 | 0 | Bool is_center = GF_TRUE; |
6954 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
6955 | 0 | if (!txt) return GF_JS_EXCEPTION(c); |
6956 | 0 | if (argc) is_center = JS_ToBool(c, argv[0]); |
6957 | |
|
6958 | 0 | text_update_path(txt, is_center); |
6959 | 0 | if (!txt->path) return JS_NULL; |
6960 | 0 | nobj = JS_NewObjectClass(c, path_class_id); |
6961 | 0 | JS_SetOpaque(nobj, gf_path_clone(txt->path)); |
6962 | 0 | return nobj; |
6963 | 0 | } |
6964 | | |
6965 | | static JSValue text_set_text(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
6966 | 0 | { |
6967 | 0 | s32 i, j, nb_lines; |
6968 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
6969 | 0 | if (!txt) return GF_JS_EXCEPTION(c); |
6970 | 0 | text_reset(txt); |
6971 | 0 | if (!argc) return JS_UNDEFINED; |
6972 | | |
6973 | 0 | txt->font = gf_font_manager_set_font(txt->fm, txt->fontnames, txt->nb_fonts, txt->styles); |
6974 | 0 | if (!txt->font) |
6975 | 0 | return js_throw_err_msg(c, GF_NOT_FOUND, "Fonts not found (first was %s) and no default font available!\n" |
6976 | 0 | "Check your GPAC configuration, or use `-rescan-fonts` to refresh font directory.\n", txt->fontnames ? txt->fontnames[0] : "none"); |
6977 | | |
6978 | 0 | for (i=0; i<argc; i++) { |
6979 | 0 | if (JS_IsArray(c, argv[i])) { |
6980 | 0 | JSValue v = JS_GetPropertyStr(c, argv[i], "length"); |
6981 | 0 | JS_ToInt32(c, &nb_lines, v); |
6982 | 0 | JS_FreeValue(c, v); |
6983 | |
|
6984 | 0 | for (j=0; j<nb_lines; j++) { |
6985 | 0 | v = JS_GetPropertyUint32(c, argv[i], j); |
6986 | 0 | text_set_text_from_value(txt, txt->font, c, v); |
6987 | 0 | JS_FreeValue(c, v); |
6988 | 0 | } |
6989 | 0 | } else { |
6990 | 0 | text_set_text_from_value(txt, txt->font, c, argv[i]); |
6991 | 0 | } |
6992 | 0 | } |
6993 | |
|
6994 | 0 | nb_lines = gf_list_count(txt->spans); |
6995 | 0 | for (i=0; i<nb_lines; i++) { |
6996 | 0 | GF_TextSpan *span = gf_list_get(txt->spans, i); |
6997 | 0 | gf_font_manager_refresh_span_bounds(span); |
6998 | 0 | span->bounds.y += FLT2FIX( i*txt->lineSpacing ); |
6999 | |
|
7000 | 0 | if (!txt->max_h && !txt->max_w) { |
7001 | 0 | txt->max_w = span->bounds.width; |
7002 | 0 | txt->max_h = span->bounds.height; |
7003 | 0 | txt->min_x = span->bounds.x; |
7004 | 0 | txt->min_y = span->bounds.y; |
7005 | 0 | txt->max_x = txt->min_x + span->bounds.width; |
7006 | 0 | txt->max_y = txt->min_y + span->bounds.height; |
7007 | 0 | } else { |
7008 | 0 | if (txt->min_x > span->bounds.x) |
7009 | 0 | txt->min_x = span->bounds.x; |
7010 | 0 | if (txt->min_y > span->bounds.y) |
7011 | 0 | txt->min_y = span->bounds.y; |
7012 | 0 | if (txt->max_w < span->bounds.width) |
7013 | 0 | txt->max_w = span->bounds.width; |
7014 | 0 | if (txt->max_h < span->bounds.height) |
7015 | 0 | txt->max_h = span->bounds.height; |
7016 | 0 | if (txt->max_x < span->bounds.x + span->bounds.width) |
7017 | 0 | txt->max_x = span->bounds.x + span->bounds.width; |
7018 | 0 | if (txt->max_y < span->bounds.y + span->bounds.height) |
7019 | 0 | txt->max_y = span->bounds.y + span->bounds.height; |
7020 | 0 | } |
7021 | 0 | } |
7022 | |
|
7023 | 0 | return JS_UNDEFINED; |
7024 | 0 | } |
7025 | | |
7026 | | static JSValue text_setProperty(JSContext *c, JSValueConst obj, JSValueConst value, int magic) |
7027 | 0 | { |
7028 | 0 | const char *str; |
7029 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
7030 | 0 | if (!txt) return GF_JS_EXCEPTION(c); |
7031 | | |
7032 | 0 | switch (magic) { |
7033 | 0 | case TXT_FONT: |
7034 | 0 | { |
7035 | 0 | text_reset_fonts(txt); |
7036 | 0 | if (JS_IsArray(c, value)) { |
7037 | 0 | u32 i, nb_fonts; |
7038 | 0 | JSValue res = JS_GetPropertyStr(c, value, "length"); |
7039 | 0 | if (JS_ToInt32(c, &nb_fonts, res)) { |
7040 | 0 | JS_FreeValue(c, res); |
7041 | 0 | return GF_JS_EXCEPTION(c); |
7042 | 0 | } |
7043 | 0 | JS_FreeValue(c, res); |
7044 | 0 | txt->nb_fonts = nb_fonts; |
7045 | 0 | txt->fontnames = gf_malloc(sizeof(char *) * nb_fonts); |
7046 | 0 | for (i=0; i<nb_fonts; i++) { |
7047 | 0 | res = JS_GetPropertyUint32(c, value, i); |
7048 | 0 | str = JS_ToCString(c, res); |
7049 | 0 | txt->fontnames[i] = gf_strdup(str ? str : "SANS"); |
7050 | 0 | JS_FreeCString(c, str); |
7051 | 0 | JS_FreeValue(c, res); |
7052 | 0 | } |
7053 | 0 | } else { |
7054 | 0 | txt->nb_fonts = 1; |
7055 | 0 | txt->fontnames = gf_malloc(sizeof(char *)); |
7056 | 0 | str = JS_ToCString(c, value); |
7057 | 0 | txt->fontnames[0] = gf_strdup(str ? str : "SANS"); |
7058 | 0 | JS_FreeCString(c, str); |
7059 | 0 | } |
7060 | 0 | } |
7061 | 0 | break; |
7062 | 0 | case TXT_BASELINE: |
7063 | 0 | if (JS_ToInt32(c, &txt->baseline, value)) return GF_JS_EXCEPTION(c); |
7064 | 0 | return JS_UNDEFINED; |
7065 | 0 | case TXT_ALIGN: |
7066 | 0 | if (JS_ToInt32(c, &txt->align, value)) return GF_JS_EXCEPTION(c); |
7067 | 0 | return JS_UNDEFINED; |
7068 | 0 | case TXT_FONTSIZE: |
7069 | 0 | if (JS_ToFloat64(c, &txt->font_size, value)) return GF_JS_EXCEPTION(c); |
7070 | 0 | break; |
7071 | 0 | case TXT_HORIZ: |
7072 | 0 | txt->horizontal = JS_ToBool(c, value); |
7073 | 0 | break; |
7074 | 0 | case TXT_FLIP: |
7075 | 0 | txt->flip = JS_ToBool(c, value); |
7076 | 0 | break; |
7077 | 0 | #define TOG_FLAG(_val) \ |
7078 | 0 | if (JS_ToBool(c, value)) \ |
7079 | 0 | txt->styles |= _val;\ |
7080 | 0 | else\ |
7081 | 0 | txt->styles &= ~_val;\ |
7082 | 0 |
|
7083 | | |
7084 | 0 | case TXT_UNDERLINED: |
7085 | 0 | TOG_FLAG(GF_FONT_UNDERLINED); |
7086 | 0 | break; |
7087 | 0 | case TXT_ITALIC: |
7088 | 0 | TOG_FLAG(GF_FONT_ITALIC); |
7089 | 0 | break; |
7090 | 0 | case TXT_BOLD: |
7091 | 0 | TOG_FLAG(GF_FONT_WEIGHT_100); |
7092 | 0 | break; |
7093 | 0 | case TXT_STRIKEOUT: |
7094 | 0 | TOG_FLAG(GF_FONT_STRIKEOUT); |
7095 | 0 | break; |
7096 | 0 | case TXT_SMALLCAP: |
7097 | 0 | TOG_FLAG(GF_FONT_SMALLCAPS); |
7098 | 0 | break; |
7099 | 0 | #undef TOG_FLAG |
7100 | | |
7101 | 0 | case TXT_MAX_WIDTH: |
7102 | 0 | JS_ToFloat64(c, &txt->maxWidth, value); |
7103 | 0 | break; |
7104 | 0 | case TXT_LINESPACING: |
7105 | 0 | JS_ToFloat64(c, &txt->lineSpacing, value); |
7106 | 0 | break; |
7107 | 0 | } |
7108 | 0 | return JS_UNDEFINED; |
7109 | 0 | } |
7110 | | |
7111 | | static JSValue text_measure(JSContext *c, JSValueConst obj, int argc, JSValueConst *argv) |
7112 | 0 | { |
7113 | 0 | JSValue res; |
7114 | 0 | GF_JSText *txt = JS_GetOpaque(obj, text_class_id); |
7115 | 0 | if (!txt) return GF_JS_EXCEPTION(c); |
7116 | 0 | res = JS_NewObject(c); |
7117 | |
|
7118 | 0 | if (txt->horizontal) { |
7119 | 0 | JS_SetPropertyStr(c, res, "width", JS_NewFloat64(c, txt->max_w) ); |
7120 | 0 | JS_SetPropertyStr(c, res, "height", JS_NewFloat64(c, txt->max_y-txt->min_y) ); |
7121 | 0 | } else { |
7122 | 0 | GF_Rect rc; |
7123 | 0 | if (txt->path) gf_path_del(txt->path); |
7124 | 0 | txt->path = NULL; |
7125 | 0 | text_update_path(txt, GF_TRUE); |
7126 | 0 | gf_path_get_bounds(txt->path, &rc); |
7127 | 0 | if (txt->path) gf_path_del(txt->path); |
7128 | 0 | txt->path = NULL; |
7129 | 0 | JS_SetPropertyStr(c, res, "width", JS_NewFloat64(c, rc.width) ); |
7130 | 0 | JS_SetPropertyStr(c, res, "height", JS_NewFloat64(c, rc.height) ); |
7131 | 0 | } |
7132 | |
|
7133 | 0 | JS_SetPropertyStr(c, res, "right_to_left", JS_NewBool(c, txt->right_to_left) ); |
7134 | 0 | if (txt->font) { |
7135 | 0 | JS_SetPropertyStr(c, res, "em_size", JS_NewInt32(c, txt->font->em_size) ); |
7136 | 0 | JS_SetPropertyStr(c, res, "ascent", JS_NewInt32(c, txt->font->ascent) ); |
7137 | 0 | JS_SetPropertyStr(c, res, "descent", JS_NewInt32(c, txt->font->descent) ); |
7138 | 0 | JS_SetPropertyStr(c, res, "line_spacing", JS_NewInt32(c, txt->font->line_spacing) ); |
7139 | 0 | JS_SetPropertyStr(c, res, "underlined", JS_NewInt32(c, txt->font->underline) ); |
7140 | 0 | JS_SetPropertyStr(c, res, "baseline", JS_NewInt32(c, txt->font->baseline) ); |
7141 | 0 | JS_SetPropertyStr(c, res, "max_advance_h", JS_NewInt32(c, txt->font->max_advance_h) ); |
7142 | 0 | JS_SetPropertyStr(c, res, "max_advance_v", JS_NewInt32(c, txt->font->max_advance_v) ); |
7143 | 0 | } |
7144 | 0 | return res; |
7145 | 0 | } |
7146 | | |
7147 | | static const JSCFunctionListEntry text_funcs[] = |
7148 | | { |
7149 | | JS_CGETSET_MAGIC_DEF("font", text_getProperty, text_setProperty, TXT_FONT), |
7150 | | JS_CGETSET_MAGIC_DEF("fontsize", text_getProperty, text_setProperty, TXT_FONTSIZE), |
7151 | | JS_CGETSET_MAGIC_DEF("align", text_getProperty, text_setProperty, TXT_ALIGN), |
7152 | | JS_CGETSET_MAGIC_DEF("baseline", text_getProperty, text_setProperty, TXT_BASELINE), |
7153 | | JS_CGETSET_MAGIC_DEF("horizontal", text_getProperty, text_setProperty, TXT_HORIZ), |
7154 | | JS_CGETSET_MAGIC_DEF("flip", text_getProperty, text_setProperty, TXT_FLIP), |
7155 | | JS_CGETSET_MAGIC_DEF("underline", text_getProperty, text_setProperty, TXT_UNDERLINED), |
7156 | | JS_CGETSET_MAGIC_DEF("bold", text_getProperty, text_setProperty, TXT_BOLD), |
7157 | | JS_CGETSET_MAGIC_DEF("italic", text_getProperty, text_setProperty, TXT_ITALIC), |
7158 | | JS_CGETSET_MAGIC_DEF("maxWidth", text_getProperty, text_setProperty, TXT_MAX_WIDTH), |
7159 | | JS_CGETSET_MAGIC_DEF("lineSpacing", text_getProperty, text_setProperty, TXT_LINESPACING), |
7160 | | JS_CFUNC_DEF("set_text", 0, text_set_text), |
7161 | | JS_CFUNC_DEF("measure", 0, text_measure), |
7162 | | JS_CFUNC_DEF("get_path", 0, text_get_path), |
7163 | | }; |
7164 | | |
7165 | | JSClassDef text_class = { |
7166 | | "Text", |
7167 | | .finalizer = text_finalize |
7168 | | }; |
7169 | | static JSValue text_constructor(JSContext *c, JSValueConst new_target, int argc, JSValueConst *argv) |
7170 | 0 | { |
7171 | 0 | JSValue obj; |
7172 | 0 | GF_JSText *txt; |
7173 | 0 | GF_SAFEALLOC(txt, GF_JSText); |
7174 | 0 | if (!txt) |
7175 | 0 | return js_throw_err(c, GF_OUT_OF_MEM); |
7176 | 0 | txt->fm = jsf_get_font_manager(c); |
7177 | |
|
7178 | 0 | if (!txt->fm) { |
7179 | 0 | gf_free(txt); |
7180 | 0 | return js_throw_err_msg(c, GF_IO_ERR, "Failed to load font manager\n"); |
7181 | 0 | } |
7182 | 0 | txt->spans = gf_list_new(); |
7183 | 0 | if (!txt->spans) { |
7184 | 0 | gf_free(txt); |
7185 | 0 | return GF_JS_EXCEPTION(c); |
7186 | 0 | } |
7187 | | |
7188 | 0 | txt->font_size = 12.0; |
7189 | 0 | txt->horizontal = GF_TRUE; |
7190 | 0 | txt->align = TXT_AL_START; |
7191 | 0 | txt->baseline = TXT_BL_ALPHABETIC; |
7192 | |
|
7193 | 0 | obj = JS_NewObjectClass(c, text_class_id); |
7194 | 0 | if (JS_IsException(obj)) return obj; |
7195 | 0 | JS_SetOpaque(obj, txt); |
7196 | 0 | return obj; |
7197 | 0 | } |
7198 | | |
7199 | | #endif // GPAC_DISABLE_FONTS |
7200 | | |
7201 | | |
7202 | | enum |
7203 | | { |
7204 | | MX_PROP_IDENTITY=0, |
7205 | | MX_PROP_3D, |
7206 | | MX_PROP_YAW, |
7207 | | MX_PROP_PITCH, |
7208 | | MX_PROP_ROLL, |
7209 | | MX_PROP_TRANLATE, |
7210 | | MX_PROP_SCALE, |
7211 | | MX_PROP_ROTATE, |
7212 | | MX_PROP_SHEAR, |
7213 | | MX_PROP_M, |
7214 | | }; |
7215 | | |
7216 | | static void mx_finalize(JSRuntime *rt, JSValue obj) |
7217 | 0 | { |
7218 | 0 | GF_Matrix *mx = JS_GetOpaque(obj, matrix_class_id); |
7219 | 0 | if (mx) gf_free(mx); |
7220 | 0 | } |
7221 | | |
7222 | | JSClassDef matrix_class = { |
7223 | | .class_name = "Matrix", |
7224 | | .finalizer = mx_finalize |
7225 | | }; |
7226 | | |
7227 | | #define MAKEVEC(_v) \ |
7228 | 0 | res = JS_NewObject(ctx);\ |
7229 | 0 | JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\ |
7230 | 0 | JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\ |
7231 | 0 | JS_SetPropertyStr(ctx, res, "z", JS_NewFloat64(ctx, FIX2FLT(_v.z) ));\ |
7232 | 0 | return res;\ |
7233 | | |
7234 | | #define MAKEVEC4(_v) \ |
7235 | 0 | res = JS_NewObject(ctx);\ |
7236 | 0 | JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\ |
7237 | 0 | JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\ |
7238 | 0 | JS_SetPropertyStr(ctx, res, "z", JS_NewFloat64(ctx, FIX2FLT(_v.z) ));\ |
7239 | 0 | JS_SetPropertyStr(ctx, res, "w", JS_NewFloat64(ctx, FIX2FLT(_v.q) ));\ |
7240 | 0 | return res;\ |
7241 | | |
7242 | | #define MAKERECT(_v) \ |
7243 | 0 | res = JS_NewObject(ctx);\ |
7244 | 0 | JS_SetPropertyStr(ctx, res, "x", JS_NewFloat64(ctx, FIX2FLT(_v.x) ));\ |
7245 | 0 | JS_SetPropertyStr(ctx, res, "y", JS_NewFloat64(ctx, FIX2FLT(_v.y) ));\ |
7246 | 0 | JS_SetPropertyStr(ctx, res, "width", JS_NewFloat64(ctx, FIX2FLT(_v.width) ));\ |
7247 | 0 | JS_SetPropertyStr(ctx, res, "height", JS_NewFloat64(ctx, FIX2FLT(_v.height) ));\ |
7248 | 0 | return res;\ |
7249 | | |
7250 | | static JSValue mx_getProperty(JSContext *ctx, JSValueConst this_val, int magic) |
7251 | 0 | { |
7252 | 0 | JSValue res; |
7253 | 0 | Fixed yaw, pitch, roll; |
7254 | 0 | GF_Vec tr, sc, sh; |
7255 | 0 | GF_Vec4 ro; |
7256 | 0 | u32 i; |
7257 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7258 | 0 | if (!mx) return GF_JS_EXCEPTION(ctx); |
7259 | 0 | switch (magic) { |
7260 | 0 | case MX_PROP_IDENTITY: |
7261 | 0 | return JS_NewBool(ctx, gf_mx_is_identity(*mx)); |
7262 | 0 | case MX_PROP_3D: |
7263 | 0 | return JS_TRUE; |
7264 | 0 | case MX_PROP_YAW: |
7265 | 0 | gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll); |
7266 | 0 | return JS_NewFloat64(ctx, FIX2FLT(yaw)); |
7267 | 0 | case MX_PROP_PITCH: |
7268 | 0 | gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll); |
7269 | 0 | return JS_NewFloat64(ctx, FIX2FLT(pitch)); |
7270 | 0 | case MX_PROP_ROLL: |
7271 | 0 | gf_mx_get_yaw_pitch_roll(mx, &yaw, &pitch, &roll); |
7272 | 0 | return JS_NewFloat64(ctx, FIX2FLT(roll)); |
7273 | | |
7274 | 0 | case MX_PROP_TRANLATE: |
7275 | 0 | gf_mx_decompose(mx, &tr, &sc, &ro, &sh); |
7276 | 0 | MAKEVEC(tr) |
7277 | | |
7278 | 0 | case MX_PROP_SCALE: |
7279 | 0 | gf_mx_decompose(mx, &tr, &sc, &ro, &sh); |
7280 | 0 | MAKEVEC(sc) |
7281 | | |
7282 | 0 | case MX_PROP_ROTATE: |
7283 | 0 | gf_mx_decompose(mx, &tr, &sc, &ro, &sh); |
7284 | 0 | MAKEVEC4(ro) |
7285 | | |
7286 | 0 | case MX_PROP_SHEAR: |
7287 | 0 | gf_mx_decompose(mx, &tr, &sc, &ro, &sh); |
7288 | 0 | MAKEVEC(sh) |
7289 | | |
7290 | 0 | case MX_PROP_M: |
7291 | 0 | res = JS_NewArray(ctx); |
7292 | 0 | for (i=0; i<16; i++) |
7293 | 0 | JS_SetPropertyUint32(ctx, res, i, JS_NewFloat64(ctx, mx->m[i])); |
7294 | 0 | return res; |
7295 | 0 | } |
7296 | 0 | return JS_UNDEFINED; |
7297 | 0 | } |
7298 | | |
7299 | | static JSValue mx_setProperty(JSContext *ctx, JSValueConst this_val, JSValueConst value, int magic) |
7300 | 0 | { |
7301 | 0 | JSValue v; |
7302 | 0 | u32 i, len; |
7303 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7304 | 0 | if (!mx) return GF_JS_EXCEPTION(ctx); |
7305 | | |
7306 | | |
7307 | 0 | switch (magic) { |
7308 | 0 | case MX_PROP_IDENTITY: |
7309 | 0 | gf_mx_init(*mx); |
7310 | 0 | break; |
7311 | 0 | case MX_PROP_M: |
7312 | 0 | if (!JS_IsArray(ctx, value)) return GF_JS_EXCEPTION(ctx); |
7313 | 0 | v = JS_GetPropertyStr(ctx, value, "length"); |
7314 | 0 | len=0; |
7315 | 0 | JS_ToInt32(ctx, &len, v); |
7316 | 0 | JS_FreeValue(ctx, v); |
7317 | 0 | if (len != 16) return GF_JS_EXCEPTION(ctx); |
7318 | 0 | for (i=0; i<len; i++) { |
7319 | 0 | Double _d; |
7320 | 0 | v = JS_GetPropertyUint32(ctx, value, i); |
7321 | 0 | JS_ToFloat64(ctx, &_d, v); |
7322 | 0 | JS_FreeValue(ctx, v); |
7323 | 0 | mx->m[i] = FLT2FIX(_d); |
7324 | 0 | } |
7325 | 0 | break; |
7326 | 0 | } |
7327 | 0 | return JS_UNDEFINED; |
7328 | 0 | } |
7329 | | |
7330 | | |
7331 | | static JSValue mx_copy(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7332 | 0 | { |
7333 | 0 | GF_Matrix *mx2; |
7334 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7335 | 0 | if (!mx) |
7336 | 0 | return GF_JS_EXCEPTION(ctx); |
7337 | 0 | if (argc) { |
7338 | 0 | mx2 = JS_GetOpaque(argv[0], matrix_class_id); |
7339 | 0 | if (!mx2) |
7340 | 0 | return GF_JS_EXCEPTION(ctx); |
7341 | 0 | gf_mx_copy(*mx, *mx2); |
7342 | 0 | return JS_DupValue(ctx, this_val); |
7343 | 0 | } |
7344 | 0 | GF_SAFEALLOC(mx2, GF_Matrix); |
7345 | 0 | if (!mx2) return GF_JS_EXCEPTION(ctx); |
7346 | 0 | JSValue res = JS_NewObjectClass(ctx, matrix_class_id); |
7347 | 0 | JS_SetOpaque(res, mx2); |
7348 | 0 | gf_mx_copy(*mx2, *mx); |
7349 | 0 | return res; |
7350 | 0 | } |
7351 | | static JSValue mx_equal(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7352 | 0 | { |
7353 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7354 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(ctx); |
7355 | 0 | GF_Matrix *mx2 = JS_GetOpaque(argv[0], matrix_class_id); |
7356 | 0 | if (!mx2) return GF_JS_EXCEPTION(ctx); |
7357 | 0 | if (gf_mx_equal(mx, mx2)) return JS_TRUE; |
7358 | 0 | return JS_FALSE; |
7359 | 0 | } |
7360 | | |
7361 | 0 | #define WGL_GET_VEC3(_x, _y, _z, _arg)\ |
7362 | 0 | {\ |
7363 | 0 | JSValue v;\ |
7364 | 0 | v = JS_GetPropertyStr(ctx, _arg, "x");\ |
7365 | 0 | EVG_GET_FLOAT(_x, v);\ |
7366 | 0 | JS_FreeValue(ctx, v);\ |
7367 | 0 | v = JS_GetPropertyStr(ctx, _arg, "y");\ |
7368 | 0 | EVG_GET_FLOAT(_y, v);\ |
7369 | 0 | JS_FreeValue(ctx, v);\ |
7370 | 0 | v = JS_GetPropertyStr(ctx, _arg, "z");\ |
7371 | 0 | EVG_GET_FLOAT(_z, v);\ |
7372 | 0 | JS_FreeValue(ctx, v);\ |
7373 | 0 | } |
7374 | | |
7375 | 0 | #define WGL_GET_VEC3F(_v, _arg)\ |
7376 | 0 | {\ |
7377 | 0 | JSValue v;\ |
7378 | 0 | Double _f;\ |
7379 | 0 | v = JS_GetPropertyStr(ctx, _arg, "x");\ |
7380 | 0 | EVG_GET_FLOAT(_f, v);\ |
7381 | 0 | _v.x = FLT2FIX(_f);\ |
7382 | 0 | JS_FreeValue(ctx, v);\ |
7383 | 0 | v = JS_GetPropertyStr(ctx, _arg, "y");\ |
7384 | 0 | EVG_GET_FLOAT(_f, v);\ |
7385 | 0 | _v.y = FLT2FIX(_f);\ |
7386 | 0 | JS_FreeValue(ctx, v);\ |
7387 | 0 | v = JS_GetPropertyStr(ctx, _arg, "z");\ |
7388 | 0 | EVG_GET_FLOAT(_f, v);\ |
7389 | 0 | _v.z = FLT2FIX(_f);\ |
7390 | 0 | JS_FreeValue(ctx, v);\ |
7391 | 0 | } |
7392 | | |
7393 | 0 | #define WGL_GET_VEC4(_x, _y, _z, _q, _arg)\ |
7394 | 0 | {\ |
7395 | 0 | JSValue v;\ |
7396 | 0 | v = JS_GetPropertyStr(ctx, _arg, "x");\ |
7397 | 0 | EVG_GET_FLOAT(_x, v);\ |
7398 | 0 | JS_FreeValue(ctx, v);\ |
7399 | 0 | v = JS_GetPropertyStr(ctx, _arg, "y");\ |
7400 | 0 | EVG_GET_FLOAT(_y, v);\ |
7401 | 0 | JS_FreeValue(ctx, v);\ |
7402 | 0 | v = JS_GetPropertyStr(ctx, _arg, "z");\ |
7403 | 0 | EVG_GET_FLOAT(_z, v);\ |
7404 | 0 | JS_FreeValue(ctx, v);\ |
7405 | 0 | v = JS_GetPropertyStr(ctx, _arg, "w");\ |
7406 | 0 | if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, _arg, "q");\ |
7407 | 0 | if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, _arg, "angle");\ |
7408 | 0 | EVG_GET_FLOAT(_q, v);\ |
7409 | 0 | JS_FreeValue(ctx, v);\ |
7410 | 0 | } |
7411 | | |
7412 | | |
7413 | | static JSValue mx_translate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7414 | 0 | { |
7415 | 0 | Double vx, vy, vz; |
7416 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7417 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(ctx); |
7418 | 0 | if (!JS_IsObject(argv[0])) { |
7419 | 0 | if (argc<2) return GF_JS_EXCEPTION(ctx); |
7420 | 0 | EVG_GET_FLOAT(vx, argv[0]) |
7421 | 0 | EVG_GET_FLOAT(vy, argv[1]) |
7422 | 0 | if (argc==3) { |
7423 | 0 | EVG_GET_FLOAT(vz, argv[2]) |
7424 | 0 | } else { |
7425 | 0 | vz = 0; |
7426 | 0 | } |
7427 | 0 | } else { |
7428 | 0 | WGL_GET_VEC3(vx, vy, vz, argv[0]) |
7429 | 0 | } |
7430 | 0 | gf_mx_add_translation(mx, FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz)); |
7431 | 0 | return JS_DupValue(ctx, this_val); |
7432 | 0 | } |
7433 | | static JSValue mx_scale(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7434 | 0 | { |
7435 | 0 | Double vx, vy, vz; |
7436 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7437 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(ctx); |
7438 | 0 | if (!JS_IsObject(argv[0])) { |
7439 | 0 | if (argc<3) return GF_JS_EXCEPTION(ctx); |
7440 | 0 | EVG_GET_FLOAT(vx, argv[0]) |
7441 | 0 | EVG_GET_FLOAT(vy, argv[1]) |
7442 | 0 | EVG_GET_FLOAT(vz, argv[2]) |
7443 | 0 | } else { |
7444 | 0 | WGL_GET_VEC3(vx, vy, vz, argv[0]) |
7445 | 0 | } |
7446 | 0 | gf_mx_add_scale(mx, FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz)); |
7447 | 0 | return JS_DupValue(ctx, this_val); |
7448 | 0 | } |
7449 | | static JSValue mx_rotate(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7450 | 0 | { |
7451 | 0 | Double vx, vy, vz, angle; |
7452 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7453 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(ctx); |
7454 | 0 | if (!JS_IsObject(argv[0])) { |
7455 | 0 | if (argc<4) return GF_JS_EXCEPTION(ctx); |
7456 | 0 | EVG_GET_FLOAT(vx, argv[0]) |
7457 | 0 | EVG_GET_FLOAT(vy, argv[1]) |
7458 | 0 | EVG_GET_FLOAT(vz, argv[2]) |
7459 | 0 | EVG_GET_FLOAT(angle, argv[3]) |
7460 | 0 | } else { |
7461 | 0 | WGL_GET_VEC4(vx, vy, vz, angle, argv[0]) |
7462 | 0 | } |
7463 | 0 | gf_mx_add_rotation(mx, FLT2FIX(angle), FLT2FIX(vx), FLT2FIX(vy), FLT2FIX(vz)); |
7464 | 0 | return JS_DupValue(ctx, this_val); |
7465 | 0 | } |
7466 | | static JSValue mx_add(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7467 | 0 | { |
7468 | 0 | GF_Matrix *_mx2 = NULL; |
7469 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7470 | 0 | if (!mx || !argc) |
7471 | 0 | return GF_JS_EXCEPTION(ctx); |
7472 | 0 | GF_Matrix *mx2 = JS_GetOpaque(argv[0], matrix_class_id); |
7473 | |
|
7474 | 0 | if (!mx2) { |
7475 | 0 | GF_Matrix2D *mx2_2D = JS_GetOpaque(argv[0], mx2d_class_id); |
7476 | 0 | if (!mx2_2D) |
7477 | 0 | return GF_JS_EXCEPTION(ctx); |
7478 | | |
7479 | 0 | GF_SAFEALLOC(_mx2, GF_Matrix); |
7480 | 0 | if (!_mx2) |
7481 | 0 | return GF_JS_EXCEPTION(ctx); |
7482 | 0 | gf_mx_from_mx2d(_mx2, mx2_2D); |
7483 | 0 | mx2 = _mx2; |
7484 | 0 | } |
7485 | 0 | if ((argc>1) && JS_ToBool(ctx, argv[1])) { |
7486 | 0 | gf_mx_add_matrix_4x4(mx, mx2); |
7487 | 0 | } else { |
7488 | 0 | gf_mx_add_matrix(mx, mx2); |
7489 | 0 | } |
7490 | 0 | if (_mx2) gf_free(_mx2); |
7491 | |
|
7492 | 0 | return JS_DupValue(ctx, this_val); |
7493 | 0 | } |
7494 | | |
7495 | | static JSValue mx_inverse(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7496 | 0 | { |
7497 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7498 | 0 | if (!mx) return GF_JS_EXCEPTION(ctx); |
7499 | 0 | if (argc && JS_ToBool(ctx, argv[0])) { |
7500 | 0 | gf_mx_inverse_4x4(mx); |
7501 | 0 | } else { |
7502 | 0 | gf_mx_inverse(mx); |
7503 | 0 | } |
7504 | 0 | return JS_DupValue(ctx, this_val); |
7505 | 0 | } |
7506 | | |
7507 | | static JSValue mx_transpose(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7508 | 0 | { |
7509 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7510 | 0 | if (!mx) return GF_JS_EXCEPTION(ctx); |
7511 | 0 | gf_mx_transpose(mx); |
7512 | 0 | return JS_DupValue(ctx, this_val); |
7513 | 0 | } |
7514 | | |
7515 | | static JSValue mx_apply(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7516 | 0 | { |
7517 | 0 | Fixed width, height, x, y; |
7518 | 0 | GF_Vec pt; |
7519 | 0 | GF_Vec4 pt4; |
7520 | 0 | JSValue v, res; |
7521 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7522 | 0 | if (!mx || !argc) return GF_JS_EXCEPTION(ctx); |
7523 | 0 | if (!JS_IsObject(argv[0])) return GF_JS_EXCEPTION(ctx); |
7524 | | |
7525 | | /*try rect*/ |
7526 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "width"); |
7527 | 0 | if (JS_IsUndefined(v)) |
7528 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "w"); |
7529 | |
|
7530 | 0 | if (!JS_IsUndefined(v)) { |
7531 | 0 | GF_Rect rc; |
7532 | 0 | EVG_GET_FLOAT(width, v); |
7533 | 0 | JS_FreeValue(ctx, v); |
7534 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "height"); |
7535 | 0 | if (JS_IsUndefined(v)) |
7536 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "h"); |
7537 | 0 | EVG_GET_FLOAT(height, v); |
7538 | 0 | JS_FreeValue(ctx, v); |
7539 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "x"); |
7540 | 0 | EVG_GET_FLOAT(x, v); |
7541 | 0 | JS_FreeValue(ctx, v); |
7542 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "y"); |
7543 | 0 | EVG_GET_FLOAT(y, v); |
7544 | 0 | JS_FreeValue(ctx, v); |
7545 | 0 | rc.x = FLT2FIX(x); |
7546 | 0 | rc.y = FLT2FIX(y); |
7547 | 0 | rc.width = FLT2FIX(width); |
7548 | 0 | rc.height = FLT2FIX(height); |
7549 | 0 | gf_mx_apply_rect(mx, &rc); |
7550 | 0 | MAKERECT(rc) |
7551 | 0 | } |
7552 | 0 | JS_FreeValue(ctx, v); |
7553 | |
|
7554 | 0 | v = JS_GetPropertyStr(ctx, argv[0], "q"); |
7555 | 0 | if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, argv[0], "w"); |
7556 | 0 | if (JS_IsUndefined(v)) v = JS_GetPropertyStr(ctx, argv[0], "angle"); |
7557 | 0 | if (!JS_IsUndefined(v)) { |
7558 | 0 | Double _v; |
7559 | 0 | if (JS_ToFloat64(ctx, &_v, v)) return GF_JS_EXCEPTION(ctx); |
7560 | 0 | pt4.q = FLT2FIX(_v); |
7561 | |
|
7562 | 0 | WGL_GET_VEC3F(pt4, argv[0]) |
7563 | 0 | gf_mx_apply_vec_4x4(mx, &pt4); |
7564 | 0 | MAKEVEC4(pt4) |
7565 | 0 | } |
7566 | 0 | JS_FreeValue(ctx, v); |
7567 | | |
7568 | | /*try bbox ?*/ |
7569 | | |
7570 | | /*try vec*/ |
7571 | 0 | WGL_GET_VEC3F(pt, argv[0]) |
7572 | 0 | gf_mx_apply_vec(mx, &pt); |
7573 | 0 | MAKEVEC(pt) |
7574 | | |
7575 | | /* |
7576 | | |
7577 | | void gf_mx_apply_vec(GF_Matrix *mx, GF_Vec *pt); |
7578 | | void gf_mx_apply_rect(GF_Matrix *_this, GF_Rect *rc); |
7579 | | void gf_mx_apply_bbox(GF_Matrix *mx, GF_BBox *b); |
7580 | | void gf_mx_apply_bbox_sphere(GF_Matrix *mx, GF_BBox *box); |
7581 | | void gf_mx_apply_vec_4x4(GF_Matrix *mx, GF_Vec4 *vec); |
7582 | | */ |
7583 | 0 | return JS_UNDEFINED; |
7584 | 0 | } |
7585 | | |
7586 | | static JSValue mx_ortho(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7587 | 0 | { |
7588 | 0 | Double left, right, bottom, top, z_near, z_far; |
7589 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7590 | 0 | if (!mx || (argc<6)) return GF_JS_EXCEPTION(ctx); |
7591 | 0 | EVG_GET_FLOAT(left, argv[0]) |
7592 | 0 | EVG_GET_FLOAT(right, argv[1]) |
7593 | 0 | EVG_GET_FLOAT(bottom, argv[2]) |
7594 | 0 | EVG_GET_FLOAT(top, argv[3]) |
7595 | 0 | EVG_GET_FLOAT(z_near, argv[4]) |
7596 | 0 | EVG_GET_FLOAT(z_far, argv[5]) |
7597 | 0 | if ((argc>6) && JS_ToBool(ctx, argv[6])) { |
7598 | 0 | gf_mx_ortho_reverse_z(mx, FLT2FIX(left), FLT2FIX(right), FLT2FIX(bottom), FLT2FIX(top), FLT2FIX(z_near), FLT2FIX(z_far)); |
7599 | 0 | } else { |
7600 | 0 | gf_mx_ortho(mx, FLT2FIX(left), FLT2FIX(right), FLT2FIX(bottom), FLT2FIX(top), FLT2FIX(z_near), FLT2FIX(z_far)); |
7601 | 0 | } |
7602 | 0 | return JS_DupValue(ctx, this_val); |
7603 | 0 | } |
7604 | | static JSValue mx_perspective(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7605 | 0 | { |
7606 | 0 | Double fov, ar, z_near, z_far; |
7607 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7608 | 0 | if (!mx || (argc<4)) return GF_JS_EXCEPTION(ctx); |
7609 | 0 | EVG_GET_FLOAT(fov, argv[0]) |
7610 | 0 | EVG_GET_FLOAT(ar, argv[1]) |
7611 | 0 | EVG_GET_FLOAT(z_near, argv[2]) |
7612 | 0 | EVG_GET_FLOAT(z_far, argv[3]) |
7613 | 0 | if ((argc>4) && JS_ToBool(ctx, argv[4])) { |
7614 | 0 | gf_mx_perspective_reverse_z(mx, FLT2FIX(fov), FLT2FIX(ar), FLT2FIX(z_near), FLT2FIX(z_far)); |
7615 | 0 | } else { |
7616 | 0 | gf_mx_perspective(mx, FLT2FIX(fov), FLT2FIX(ar), FLT2FIX(z_near), FLT2FIX(z_far)); |
7617 | 0 | } |
7618 | 0 | return JS_DupValue(ctx, this_val); |
7619 | 0 | } |
7620 | | static JSValue mx_lookat(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7621 | 0 | { |
7622 | 0 | GF_Vec pos, target, up; |
7623 | 0 | GF_Matrix *mx = JS_GetOpaque(this_val, matrix_class_id); |
7624 | 0 | if (!mx || (argc!=3) ) return GF_JS_EXCEPTION(ctx); |
7625 | | |
7626 | 0 | WGL_GET_VEC3F(pos, argv[0]); |
7627 | 0 | WGL_GET_VEC3F(target, argv[1]); |
7628 | 0 | WGL_GET_VEC3F(up, argv[2]); |
7629 | |
|
7630 | 0 | gf_mx_lookat(mx, pos, target, up); |
7631 | 0 | return JS_DupValue(ctx, this_val); |
7632 | 0 | } |
7633 | | |
7634 | | static const JSCFunctionListEntry mx_funcs[] = |
7635 | | { |
7636 | | JS_CGETSET_MAGIC_DEF("identity", mx_getProperty, mx_setProperty, MX_PROP_IDENTITY), |
7637 | | JS_CGETSET_MAGIC_DEF("is3D", mx_getProperty, mx_setProperty, MX_PROP_3D), |
7638 | | JS_CGETSET_MAGIC_DEF("m", mx_getProperty, mx_setProperty, MX_PROP_M), |
7639 | | JS_CGETSET_MAGIC_DEF("yaw", mx_getProperty, NULL, MX_PROP_YAW), |
7640 | | JS_CGETSET_MAGIC_DEF("pitch", mx_getProperty, NULL, MX_PROP_PITCH), |
7641 | | JS_CGETSET_MAGIC_DEF("roll", mx_getProperty, NULL, MX_PROP_ROLL), |
7642 | | JS_CGETSET_MAGIC_DEF("dec_translate", mx_getProperty, NULL, MX_PROP_TRANLATE), |
7643 | | JS_CGETSET_MAGIC_DEF("dec_scale", mx_getProperty, NULL, MX_PROP_SCALE), |
7644 | | JS_CGETSET_MAGIC_DEF("dec_rotate", mx_getProperty, NULL, MX_PROP_ROTATE), |
7645 | | JS_CGETSET_MAGIC_DEF("dec_shear", mx_getProperty, NULL, MX_PROP_SHEAR), |
7646 | | JS_CFUNC_DEF("copy", 0, mx_copy), |
7647 | | JS_CFUNC_DEF("equal", 0, mx_equal), |
7648 | | JS_CFUNC_DEF("translate", 0, mx_translate), |
7649 | | JS_CFUNC_DEF("scale", 0, mx_scale), |
7650 | | JS_CFUNC_DEF("rotate", 0, mx_rotate), |
7651 | | JS_CFUNC_DEF("add", 0, mx_add), |
7652 | | JS_CFUNC_DEF("inverse", 0, mx_inverse), |
7653 | | JS_CFUNC_DEF("transpose", 0, mx_transpose), |
7654 | | JS_CFUNC_DEF("apply", 0, mx_apply), |
7655 | | JS_CFUNC_DEF("ortho", 0, mx_ortho), |
7656 | | JS_CFUNC_DEF("perspective", 0, mx_perspective), |
7657 | | JS_CFUNC_DEF("lookat", 0, mx_lookat), |
7658 | | }; |
7659 | | /* |
7660 | | void gf_mx_rotate_vector(GF_Matrix *mx, GF_Vec *pt); |
7661 | | */ |
7662 | | |
7663 | | static JSValue mx_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) |
7664 | 0 | { |
7665 | 0 | JSValue res; |
7666 | 0 | GF_Matrix *mx; |
7667 | 0 | GF_SAFEALLOC(mx, GF_Matrix); |
7668 | 0 | if (!mx) |
7669 | 0 | return js_throw_err(ctx, GF_OUT_OF_MEM); |
7670 | 0 | gf_mx_init(*mx); |
7671 | 0 | res = JS_NewObjectClass(ctx, matrix_class_id); |
7672 | 0 | JS_SetOpaque(res, mx); |
7673 | 0 | if (argc) { |
7674 | 0 | GF_Matrix *from = JS_GetOpaque(argv[0], matrix_class_id); |
7675 | 0 | GF_Matrix2D *from2D = JS_GetOpaque(argv[0], mx2d_class_id); |
7676 | 0 | if (from) { |
7677 | 0 | gf_mx_copy(*mx, *from); |
7678 | 0 | } else if (from2D) { |
7679 | 0 | gf_mx_from_mx2d(mx, from2D); |
7680 | 0 | } else if (argc>=3) { |
7681 | 0 | GF_Vec x_axis, y_axis, z_axis; |
7682 | 0 | WGL_GET_VEC3F(x_axis, argv[0]) |
7683 | 0 | WGL_GET_VEC3F(y_axis, argv[1]) |
7684 | 0 | WGL_GET_VEC3F(z_axis, argv[2]) |
7685 | 0 | gf_mx_rotation_matrix_from_vectors(mx, x_axis, y_axis,z_axis); |
7686 | 0 | } |
7687 | 0 | } |
7688 | 0 | return res; |
7689 | 0 | } |
7690 | | |
7691 | | |
7692 | | #ifndef GPAC_DISABLE_3D |
7693 | | static void mesh_finalize(JSRuntime *rt, JSValue obj) |
7694 | | { |
7695 | | GF_Mesh *mesh = JS_GetOpaque(obj, mesh_class_id); |
7696 | | if (mesh) mesh_free(mesh); |
7697 | | } |
7698 | | |
7699 | | JSClassDef mesh_class = { |
7700 | | .class_name = "Mesh", |
7701 | | .finalizer = mesh_finalize |
7702 | | }; |
7703 | | |
7704 | | |
7705 | | Bool mesh_gl_update_buffers(GF_Mesh *mesh); |
7706 | | |
7707 | | static JSValue mesh_update_gl(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7708 | | { |
7709 | | GF_Mesh *mesh = JS_GetOpaque(this_val, mesh_class_id); |
7710 | | if (!mesh) return GF_JS_EXCEPTION(ctx); |
7711 | | Bool res = mesh_gl_update_buffers(mesh); |
7712 | | if (!res) return GF_JS_EXCEPTION(ctx); |
7713 | | return JS_UNDEFINED; |
7714 | | } |
7715 | | |
7716 | | JSValue mesh_gl_draw(JSContext *ctx, GF_Mesh *mesh, int argc, JSValueConst *argv); |
7717 | | |
7718 | | static JSValue mesh_draw(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7719 | | { |
7720 | | GF_Mesh *mesh = JS_GetOpaque(this_val, mesh_class_id); |
7721 | | if (!mesh) return GF_JS_EXCEPTION(ctx); |
7722 | | return mesh_gl_draw(ctx, mesh, argc, argv); |
7723 | | } |
7724 | | |
7725 | | static const JSCFunctionListEntry mesh_funcs[] = |
7726 | | { |
7727 | | JS_CFUNC_DEF("update_gl", 0, mesh_update_gl), |
7728 | | JS_CFUNC_DEF("draw", 0, mesh_draw), |
7729 | | }; |
7730 | | |
7731 | | static JSValue mesh_constructor(JSContext *ctx, JSValueConst new_target, int argc, JSValueConst *argv) |
7732 | | { |
7733 | | JSValue res; |
7734 | | GF_Mesh *mesh; |
7735 | | GF_Path *gp = NULL; |
7736 | | |
7737 | | if (argc==1) { |
7738 | | gp = JS_GetOpaque(argv[0], path_class_id); |
7739 | | if (!gp) return GF_JS_EXCEPTION(ctx); |
7740 | | } |
7741 | | |
7742 | | mesh = new_mesh(); |
7743 | | if (!mesh) |
7744 | | return js_throw_err(ctx, GF_OUT_OF_MEM); |
7745 | | |
7746 | | res = JS_NewObjectClass(ctx, mesh_class_id); |
7747 | | JS_SetOpaque(res, mesh); |
7748 | | |
7749 | | if (gp) |
7750 | | mesh_from_path(mesh, gp); |
7751 | | |
7752 | | return res; |
7753 | | } |
7754 | | |
7755 | | |
7756 | | #endif //GPAC_DISABLE_3D |
7757 | | |
7758 | | |
7759 | | static JSValue evg_pixel_size(JSContext *ctx, JSValueConst this_val, int argc, JSValueConst *argv) |
7760 | 0 | { |
7761 | 0 | u32 pfmt=0; |
7762 | 0 | if (!argc) return js_throw_err_msg(ctx, GF_BAD_PARAM, "missing pixel format parameter"); |
7763 | 0 | if (JS_IsString(argv[0])) { |
7764 | 0 | const char *s = JS_ToCString(ctx, argv[0]); |
7765 | 0 | if (s) { |
7766 | 0 | pfmt = gf_pixel_fmt_parse(s); |
7767 | 0 | JS_FreeCString(ctx, s); |
7768 | 0 | } |
7769 | 0 | } else if (JS_IsNumber(argv[0])) { |
7770 | 0 | JS_ToInt32(ctx, &pfmt, argv[0]); |
7771 | 0 | } |
7772 | 0 | if (!pfmt) return js_throw_err_msg(ctx, GF_BAD_PARAM, "missing pixel format parameter"); |
7773 | 0 | return JS_NewInt32(ctx, gf_pixel_get_bytes_per_pixel(pfmt)); |
7774 | 0 | } |
7775 | | |
7776 | | |
7777 | | static int js_evg_load_module(JSContext *c, JSModuleDef *m) |
7778 | 0 | { |
7779 | 0 | JSValue ctor; |
7780 | 0 | JSValue proto; |
7781 | 0 | JSValue global; |
7782 | |
|
7783 | 0 | if (!canvas_class_id) { |
7784 | 0 | JSRuntime *rt = JS_GetRuntime(c); |
7785 | |
|
7786 | 0 | JS_NewClassID(&canvas_class_id); |
7787 | 0 | JS_NewClass(rt, canvas_class_id, &canvas_class); |
7788 | |
|
7789 | 0 | JS_NewClassID(&path_class_id); |
7790 | 0 | JS_NewClass(rt, path_class_id, &path_class); |
7791 | |
|
7792 | 0 | JS_NewClassID(&mx2d_class_id); |
7793 | 0 | JS_NewClass(rt, mx2d_class_id, &mx2d_class); |
7794 | |
|
7795 | 0 | JS_NewClassID(&colmx_class_id); |
7796 | 0 | JS_NewClass(rt, colmx_class_id, &colmx_class); |
7797 | |
|
7798 | 0 | JS_NewClassID(&stencil_class_id); |
7799 | 0 | JS_NewClass(rt, stencil_class_id, &stencil_class); |
7800 | |
|
7801 | 0 | JS_NewClassID(&texture_class_id); |
7802 | 0 | JS_NewClass(rt, texture_class_id, &texture_class); |
7803 | |
|
7804 | 0 | #ifndef GPAC_DISABLE_FONTS |
7805 | 0 | JS_NewClassID(&text_class_id); |
7806 | 0 | JS_NewClass(rt, text_class_id, &text_class); |
7807 | 0 | #endif |
7808 | |
|
7809 | 0 | JS_NewClassID(&matrix_class_id); |
7810 | 0 | JS_NewClass(rt, matrix_class_id, &matrix_class); |
7811 | |
|
7812 | | #ifndef GPAC_DISABLE_3D |
7813 | | JS_NewClassID(&mesh_class_id); |
7814 | | JS_NewClass(rt, mesh_class_id, &mesh_class); |
7815 | | #endif |
7816 | |
|
7817 | 0 | JS_NewClassID(&shader_class_id); |
7818 | 0 | JS_NewClass(rt, shader_class_id, &shader_class); |
7819 | |
|
7820 | 0 | JS_NewClassID(&vai_class_id); |
7821 | 0 | JS_NewClass(rt, vai_class_id, &vai_class); |
7822 | |
|
7823 | 0 | JS_NewClassID(&va_class_id); |
7824 | 0 | JS_NewClass(rt, va_class_id, &va_class); |
7825 | |
|
7826 | | #ifdef GPAC_ENABLE_COVERAGE |
7827 | | if (gf_sys_is_cov_mode()) |
7828 | | va_gc_mark(NULL, JS_NULL, NULL); |
7829 | | #endif |
7830 | |
|
7831 | | #ifdef EVG_USE_JS_SHADER |
7832 | | JS_NewClassID(&fragment_class_id); |
7833 | | JS_NewClass(rt, fragment_class_id, &fragment_class); |
7834 | | |
7835 | | JS_NewClassID(&vertex_class_id); |
7836 | | JS_NewClass(rt, vertex_class_id, &vertex_class); |
7837 | | |
7838 | | JS_NewClassID(&vaires_class_id); |
7839 | | JS_NewClass(rt, vaires_class_id, &vaires_class); |
7840 | | #endif// EVG_USE_JS_SHADER |
7841 | |
|
7842 | 0 | } |
7843 | 0 | proto = JS_NewObject(c); |
7844 | 0 | JS_SetPropertyFunctionList(c, proto, canvas_funcs, countof(canvas_funcs)); |
7845 | 0 | JS_SetClassProto(c, canvas_class_id, proto); |
7846 | |
|
7847 | 0 | proto = JS_NewObject(c); |
7848 | 0 | JS_SetPropertyFunctionList(c, proto, path_funcs, countof(path_funcs)); |
7849 | 0 | JS_SetClassProto(c, path_class_id, proto); |
7850 | |
|
7851 | 0 | proto = JS_NewObject(c); |
7852 | 0 | JS_SetPropertyFunctionList(c, proto, mx2d_funcs, countof(mx2d_funcs)); |
7853 | 0 | JS_SetClassProto(c, mx2d_class_id, proto); |
7854 | |
|
7855 | 0 | proto = JS_NewObject(c); |
7856 | 0 | JS_SetPropertyFunctionList(c, proto, colmx_funcs, countof(colmx_funcs)); |
7857 | 0 | JS_SetClassProto(c, colmx_class_id, proto); |
7858 | |
|
7859 | 0 | proto = JS_NewObject(c); |
7860 | 0 | JS_SetPropertyFunctionList(c, proto, stencil_funcs, countof(stencil_funcs)); |
7861 | 0 | JS_SetClassProto(c, stencil_class_id, proto); |
7862 | |
|
7863 | 0 | proto = JS_NewObject(c); |
7864 | 0 | JS_SetPropertyFunctionList(c, proto, texture_funcs, countof(texture_funcs)); |
7865 | 0 | JS_SetClassProto(c, texture_class_id, proto); |
7866 | |
|
7867 | 0 | #ifndef GPAC_DISABLE_FONTS |
7868 | 0 | proto = JS_NewObject(c); |
7869 | 0 | JS_SetPropertyFunctionList(c, proto, text_funcs, countof(text_funcs)); |
7870 | 0 | JS_SetClassProto(c, text_class_id, proto); |
7871 | 0 | #endif |
7872 | | |
7873 | |
|
7874 | 0 | proto = JS_NewObject(c); |
7875 | 0 | JS_SetPropertyFunctionList(c, proto, mx_funcs, countof(mx_funcs)); |
7876 | 0 | JS_SetClassProto(c, matrix_class_id, proto); |
7877 | |
|
7878 | | #ifdef EVG_USE_JS_SHADER |
7879 | | proto = JS_NewObject(c); |
7880 | | JS_SetPropertyFunctionList(c, proto, fragment_funcs, countof(fragment_funcs)); |
7881 | | JS_SetClassProto(c, fragment_class_id, proto); |
7882 | | |
7883 | | proto = JS_NewObject(c); |
7884 | | JS_SetPropertyFunctionList(c, proto, vertex_funcs, countof(vertex_funcs)); |
7885 | | JS_SetClassProto(c, vertex_class_id, proto); |
7886 | | |
7887 | | proto = JS_NewObject(c); |
7888 | | JS_SetPropertyFunctionList(c, proto, vaires_funcs, countof(vaires_funcs)); |
7889 | | JS_SetClassProto(c, vaires_class_id, proto); |
7890 | | #endif |
7891 | |
|
7892 | 0 | proto = JS_NewObject(c); |
7893 | 0 | JS_SetPropertyFunctionList(c, proto, shader_funcs, countof(shader_funcs)); |
7894 | 0 | JS_SetClassProto(c, shader_class_id, proto); |
7895 | |
|
7896 | 0 | proto = JS_NewObject(c); |
7897 | 0 | JS_SetPropertyFunctionList(c, proto, vai_funcs, countof(vai_funcs)); |
7898 | 0 | JS_SetClassProto(c, vai_class_id, proto); |
7899 | |
|
7900 | 0 | proto = JS_NewObject(c); |
7901 | 0 | JS_SetPropertyFunctionList(c, proto, va_funcs, countof(va_funcs)); |
7902 | 0 | JS_SetClassProto(c, va_class_id, proto); |
7903 | |
|
7904 | | #ifndef GPAC_DISABLE_3D |
7905 | | proto = JS_NewObject(c); |
7906 | | JS_SetPropertyFunctionList(c, proto, mesh_funcs, countof(mesh_funcs)); |
7907 | | JS_SetClassProto(c, mesh_class_id, proto); |
7908 | | #endif |
7909 | |
|
7910 | 0 | global = JS_GetGlobalObject(c); |
7911 | 0 | JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_PAD", JS_NewInt32(c, GF_GRADIENT_MODE_PAD)); |
7912 | 0 | JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_SPREAD", JS_NewInt32(c, GF_GRADIENT_MODE_SPREAD)); |
7913 | 0 | JS_SetPropertyStr(c, global, "GF_GRADIENT_MODE_REPEAT", JS_NewInt32(c, GF_GRADIENT_MODE_REPEAT)); |
7914 | |
|
7915 | 0 | JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_HIGH_SPEED", JS_NewInt32(c, GF_TEXTURE_FILTER_HIGH_SPEED)); |
7916 | 0 | JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_MID", JS_NewInt32(c, GF_TEXTURE_FILTER_MID)); |
7917 | 0 | JS_SetPropertyStr(c, global, "GF_TEXTURE_FILTER_HIGH_QUALITY", JS_NewInt32(c, GF_TEXTURE_FILTER_HIGH_QUALITY)); |
7918 | |
|
7919 | 0 | JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_OPEN", JS_NewInt32(c, GF_PATH2D_ARC_OPEN)); |
7920 | 0 | JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_OPEN", JS_NewInt32(c, GF_PATH2D_ARC_OPEN)); |
7921 | 0 | JS_SetPropertyStr(c, global, "GF_PATH2D_ARC_PIE", JS_NewInt32(c, GF_PATH2D_ARC_PIE)); |
7922 | |
|
7923 | 0 | JS_SetPropertyStr(c, global, "GF_PATH_LINE_CENTER", JS_NewInt32(c, GF_PATH_LINE_CENTER)); |
7924 | 0 | JS_SetPropertyStr(c, global, "GF_PATH_LINE_INSIDE", JS_NewInt32(c, GF_PATH_LINE_INSIDE)); |
7925 | 0 | JS_SetPropertyStr(c, global, "GF_PATH_LINE_OUTSIDE", JS_NewInt32(c, GF_PATH_LINE_OUTSIDE)); |
7926 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_CAP_FLAT", JS_NewInt32(c, GF_LINE_CAP_FLAT)); |
7927 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_CAP_ROUND", JS_NewInt32(c, GF_LINE_CAP_ROUND)); |
7928 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_CAP_SQUARE", JS_NewInt32(c, GF_LINE_CAP_SQUARE)); |
7929 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_CAP_TRIANGLE", JS_NewInt32(c, GF_LINE_CAP_TRIANGLE)); |
7930 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_JOIN_MITER", JS_NewInt32(c, GF_LINE_JOIN_MITER)); |
7931 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_JOIN_ROUND", JS_NewInt32(c, GF_LINE_JOIN_ROUND)); |
7932 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_JOIN_BEVEL", JS_NewInt32(c, GF_LINE_JOIN_BEVEL)); |
7933 | 0 | JS_SetPropertyStr(c, global, "GF_LINE_JOIN_MITER_SVG", JS_NewInt32(c, GF_LINE_JOIN_MITER_SVG)); |
7934 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_PLAIN", JS_NewInt32(c, GF_DASH_STYLE_PLAIN)); |
7935 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH", JS_NewInt32(c, GF_DASH_STYLE_DASH)); |
7936 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DOT", JS_NewInt32(c, GF_DASH_STYLE_DOT)); |
7937 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DOT)); |
7938 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DASH_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DASH_DOT)); |
7939 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_DASH_DOT_DOT", JS_NewInt32(c, GF_DASH_STYLE_DASH_DOT_DOT)); |
7940 | 0 | JS_SetPropertyStr(c, global, "GF_DASH_STYLE_SVG", JS_NewInt32(c, GF_DASH_STYLE_SVG)); |
7941 | |
|
7942 | 0 | #ifndef GPAC_DISABLE_FONTS |
7943 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_TOP", JS_NewInt32(c, TXT_BL_TOP)); |
7944 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_HANGING", JS_NewInt32(c, TXT_BL_HANGING)); |
7945 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_MIDDLE", JS_NewInt32(c, TXT_BL_MIDDLE)); |
7946 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_ALPHABETIC", JS_NewInt32(c, TXT_BL_ALPHABETIC)); |
7947 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_IDEOGRAPHIC", JS_NewInt32(c, TXT_BL_IDEOGRAPHIC)); |
7948 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_BASELINE_BOTTOM", JS_NewInt32(c, TXT_BL_BOTTOM)); |
7949 | |
|
7950 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_START", JS_NewInt32(c, TXT_AL_START)); |
7951 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_END", JS_NewInt32(c, TXT_AL_END)); |
7952 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_LEFT", JS_NewInt32(c, TXT_AL_LEFT)); |
7953 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_RIGHT", JS_NewInt32(c, TXT_AL_RIGHT)); |
7954 | 0 | JS_SetPropertyStr(c, global, "GF_TEXT_ALIGN_CENTER", JS_NewInt32(c, TXT_AL_CENTER)); |
7955 | 0 | #endif |
7956 | |
|
7957 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SRC_ATOP", JS_NewInt32(c, GF_EVG_SRC_ATOP)); |
7958 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SRC_IN", JS_NewInt32(c, GF_EVG_SRC_IN)); |
7959 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SRC_OUT", JS_NewInt32(c, GF_EVG_SRC_OUT)); |
7960 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SRC_OVER", JS_NewInt32(c, GF_EVG_SRC_OVER)); |
7961 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_DST_ATOP", JS_NewInt32(c, GF_EVG_DST_ATOP)); |
7962 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_DST_IN", JS_NewInt32(c, GF_EVG_DST_IN)); |
7963 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_DST_OUT", JS_NewInt32(c, GF_EVG_DST_OUT)); |
7964 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_DST_OVER", JS_NewInt32(c, GF_EVG_DST_OVER)); |
7965 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_LIGHTER", JS_NewInt32(c, GF_EVG_LIGHTER)); |
7966 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_COPY", JS_NewInt32(c, GF_EVG_COPY)); |
7967 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_XOR", JS_NewInt32(c, GF_EVG_XOR)); |
7968 | |
|
7969 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_POINTS", JS_NewInt32(c, GF_EVG_POINTS)); |
7970 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_POLYGON", JS_NewInt32(c, GF_EVG_POLYGON)); |
7971 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_LINES", JS_NewInt32(c, GF_EVG_LINES)); |
7972 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLES", JS_NewInt32(c, GF_EVG_TRIANGLES)); |
7973 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_QUADS", JS_NewInt32(c, GF_EVG_QUADS)); |
7974 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_LINE_STRIP", JS_NewInt32(c, GF_EVG_LINE_STRIP)); |
7975 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLE_STRIP", JS_NewInt32(c, GF_EVG_TRIANGLE_STRIP)); |
7976 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_TRIANGLE_FAN", JS_NewInt32(c, GF_EVG_TRIANGLE_FAN)); |
7977 | |
|
7978 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SHADER_FRAGMENT", JS_NewInt32(c, GF_EVG_SHADER_FRAGMENT)); |
7979 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_SHADER_VERTEX", JS_NewInt32(c, GF_EVG_SHADER_VERTEX)); |
7980 | |
|
7981 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEVER", JS_NewInt32(c, GF_EVGDEPTH_NEVER)); |
7982 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS)); |
7983 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS)); |
7984 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_EQUAL)); |
7985 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEQUAL", JS_NewInt32(c, GF_EVGDEPTH_NEQUAL)); |
7986 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS", JS_NewInt32(c, GF_EVGDEPTH_LESS)); |
7987 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_LESS_EQUAL)); |
7988 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER", JS_NewInt32(c, GF_EVGDEPTH_GREATER)); |
7989 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_GREATER_EQUAL)); |
7990 | |
|
7991 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_VAI_VERTEX_INDEX", JS_NewInt32(c, GF_EVG_VAI_VERTEX_INDEX)); |
7992 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_VAI_VERTEX", JS_NewInt32(c, GF_EVG_VAI_VERTEX)); |
7993 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_VAI_PRIMITIVE", JS_NewInt32(c, GF_EVG_VAI_PRIMITIVE)); |
7994 | |
|
7995 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_DISABLE", JS_NewInt32(c, GF_EVGDEPTH_DISABLE)); |
7996 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEVER", JS_NewInt32(c, GF_EVGDEPTH_NEVER)); |
7997 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_ALWAYS", JS_NewInt32(c, GF_EVGDEPTH_ALWAYS)); |
7998 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_EQUAL)); |
7999 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_NEQUAL", JS_NewInt32(c, GF_EVGDEPTH_NEQUAL)); |
8000 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS", JS_NewInt32(c, GF_EVGDEPTH_LESS)); |
8001 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_LESS_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_LESS_EQUAL)); |
8002 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER", JS_NewInt32(c, GF_EVGDEPTH_GREATER)); |
8003 | 0 | JS_SetPropertyStr(c, global, "GF_EVGDEPTH_GREATER_EQUAL", JS_NewInt32(c, GF_EVGDEPTH_GREATER_EQUAL)); |
8004 | |
|
8005 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_NONE", JS_NewInt32(c, GF_EVG_OPERAND_NONE)); |
8006 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_MIX", JS_NewInt32(c, GF_EVG_OPERAND_MIX)); |
8007 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_MIX_ALPHA", JS_NewInt32(c, GF_EVG_OPERAND_MIX_ALPHA)); |
8008 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_REPLACE_ALPHA", JS_NewInt32(c, GF_EVG_OPERAND_REPLACE_ALPHA)); |
8009 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_REPLACE_ONE_MINUS_ALPHA", JS_NewInt32(c, GF_EVG_OPERAND_REPLACE_ONE_MINUS_ALPHA)); |
8010 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_MIX_DYN", JS_NewInt32(c, GF_EVG_OPERAND_MIX_DYN)); |
8011 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_MIX_DYN_ALPHA", JS_NewInt32(c, GF_EVG_OPERAND_MIX_DYN_ALPHA)); |
8012 | 0 | JS_SetPropertyStr(c, global, "GF_EVG_OPERAND_ODD_FILL", JS_NewInt32(c, GF_EVG_OPERAND_ODD_FILL)); |
8013 | |
|
8014 | 0 | JS_SetPropertyStr(c, global, "GF_RASTER_HIGH_SPEED", JS_NewInt32(c, GF_RASTER_HIGH_SPEED)); |
8015 | 0 | JS_SetPropertyStr(c, global, "GF_RASTER_MID", JS_NewInt32(c, GF_RASTER_MID)); |
8016 | 0 | JS_SetPropertyStr(c, global, "GF_RASTER_HIGH_QUALITY", JS_NewInt32(c, GF_RASTER_HIGH_QUALITY)); |
8017 | |
|
8018 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_NONE", JS_NewInt32(c, GF_EVGMASK_NONE)); |
8019 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_DRAW", JS_NewInt32(c, GF_EVGMASK_DRAW)); |
8020 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_DRAW_NO_CLEAR", JS_NewInt32(c, GF_EVGMASK_DRAW_NO_CLEAR)); |
8021 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_USE", JS_NewInt32(c, GF_EVGMASK_USE)); |
8022 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_USE_INV", JS_NewInt32(c, GF_EVGMASK_USE_INV)); |
8023 | 0 | JS_SetPropertyStr(c, global, "GF_EVGMASK_RECORD", JS_NewInt32(c, GF_EVGMASK_RECORD)); |
8024 | |
|
8025 | 0 | JS_FreeValue(c, global); |
8026 | | |
8027 | | |
8028 | | /*export constructors*/ |
8029 | 0 | ctor = JS_NewCFunction2(c, canvas_constructor, "Canvas", 1, JS_CFUNC_constructor, 0); |
8030 | 0 | JS_SetModuleExport(c, m, "Canvas", ctor); |
8031 | 0 | ctor = JS_NewCFunction2(c, path_constructor, "Path", 1, JS_CFUNC_constructor, 0); |
8032 | 0 | JS_SetModuleExport(c, m, "Path", ctor); |
8033 | 0 | ctor = JS_NewCFunction2(c, mx2d_constructor, "Matrix2D", 1, JS_CFUNC_constructor, 0); |
8034 | 0 | JS_SetModuleExport(c, m, "Matrix2D", ctor); |
8035 | 0 | ctor = JS_NewCFunction2(c, colmx_constructor, "ColorMatrix", 1, JS_CFUNC_constructor, 0); |
8036 | 0 | JS_SetModuleExport(c, m, "ColorMatrix", ctor); |
8037 | 0 | ctor = JS_NewCFunction2(c, solid_brush_constructor, "SolidBrush", 1, JS_CFUNC_constructor, 0); |
8038 | 0 | JS_SetModuleExport(c, m, "SolidBrush", ctor); |
8039 | 0 | ctor = JS_NewCFunction2(c, linear_gradient_constructor, "LinearGradient", 1, JS_CFUNC_constructor, 0); |
8040 | 0 | JS_SetModuleExport(c, m, "LinearGradient", ctor); |
8041 | 0 | ctor = JS_NewCFunction2(c, radial_gradient_constructor, "RadialGradient", 1, JS_CFUNC_constructor, 0); |
8042 | 0 | JS_SetModuleExport(c, m, "RadialGradient", ctor); |
8043 | 0 | ctor = JS_NewCFunction2(c, texture_constructor, "Texture", 1, JS_CFUNC_constructor, 0); |
8044 | 0 | JS_SetModuleExport(c, m, "Texture", ctor); |
8045 | 0 | #ifndef GPAC_DISABLE_FONTS |
8046 | 0 | ctor = JS_NewCFunction2(c, text_constructor, "Text", 1, JS_CFUNC_constructor, 0); |
8047 | 0 | JS_SetModuleExport(c, m, "Text", ctor); |
8048 | 0 | #endif |
8049 | 0 | ctor = JS_NewCFunction2(c, mx_constructor, "Matrix", 1, JS_CFUNC_constructor, 0); |
8050 | 0 | JS_SetModuleExport(c, m, "Matrix", ctor); |
8051 | 0 | ctor = JS_NewCFunction2(c, vai_constructor, "VertexAttribInterpolator", 1, JS_CFUNC_constructor, 0); |
8052 | 0 | JS_SetModuleExport(c, m, "VertexAttribInterpolator", ctor); |
8053 | 0 | ctor = JS_NewCFunction2(c, va_constructor, "VertexAttrib", 1, JS_CFUNC_constructor, 0); |
8054 | 0 | JS_SetModuleExport(c, m, "VertexAttrib", ctor); |
8055 | |
|
8056 | | #ifndef GPAC_DISABLE_3D |
8057 | | ctor = JS_NewCFunction2(c, mesh_constructor, "Mesh", 1, JS_CFUNC_constructor, 0); |
8058 | | JS_SetModuleExport(c, m, "Mesh", ctor); |
8059 | | #endif |
8060 | |
|
8061 | 0 | ctor = JS_NewCFunction2(c, evg_pixel_size, "PixelSize", 1, JS_CFUNC_generic, 0); |
8062 | 0 | JS_SetModuleExport(c, m, "PixelSize", ctor); |
8063 | |
|
8064 | | #ifdef GPAC_HAS_FFMPEG |
8065 | | JS_SetModuleExport(c, m, "BlitEnabled", JS_TRUE); |
8066 | | #else |
8067 | 0 | JS_SetModuleExport(c, m, "BlitEnabled", JS_FALSE); |
8068 | 0 | #endif |
8069 | 0 | return 0; |
8070 | 0 | } |
8071 | | |
8072 | | void qjs_module_init_evg(JSContext *ctx) |
8073 | 0 | { |
8074 | 0 | JSModuleDef *m; |
8075 | 0 | m = JS_NewCModule(ctx, "evg", js_evg_load_module); |
8076 | 0 | if (!m) return; |
8077 | | |
8078 | 0 | JS_AddModuleExport(ctx, m, "Canvas"); |
8079 | 0 | JS_AddModuleExport(ctx, m, "Path"); |
8080 | 0 | JS_AddModuleExport(ctx, m, "Matrix2D"); |
8081 | 0 | JS_AddModuleExport(ctx, m, "ColorMatrix"); |
8082 | 0 | JS_AddModuleExport(ctx, m, "SolidBrush"); |
8083 | 0 | JS_AddModuleExport(ctx, m, "LinearGradient"); |
8084 | 0 | JS_AddModuleExport(ctx, m, "RadialGradient"); |
8085 | 0 | JS_AddModuleExport(ctx, m, "Texture"); |
8086 | 0 | JS_AddModuleExport(ctx, m, "Text"); |
8087 | 0 | JS_AddModuleExport(ctx, m, "Matrix"); |
8088 | 0 | JS_AddModuleExport(ctx, m, "Mesh"); |
8089 | 0 | JS_AddModuleExport(ctx, m, "VertexAttribInterpolator"); |
8090 | 0 | JS_AddModuleExport(ctx, m, "VertexAttrib"); |
8091 | 0 | JS_AddModuleExport(ctx, m, "PixelSize"); |
8092 | 0 | JS_AddModuleExport(ctx, m, "BlitEnabled"); |
8093 | 0 | return; |
8094 | 0 | } |
8095 | | |
8096 | | #else // defined(GPAC_HAS_QJS) && !defined(GPAC_DISABLE_EVG) |
8097 | | void qjs_module_init_evg(void *ctx) |
8098 | | { |
8099 | | |
8100 | | } |
8101 | | #endif |
8102 | | |