1 // weed-effects-utils.c
2 // - will probaly become libweed-effects-utils or something
3 // LiVES
4 // (c) G. Finch 2003 - 2019 <salsaman+lives@gmail.com>
5 // released under the GNU GPL 3 or later
6 // see file ../COPYING for licensing details
7 
8 // weed filter utility functions
9 
10 // TODO: get in_paramtmpl(ptmpl, n)
11 /// get_colorspace
12 /// get_max / min
13 
14 #include <string.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #include "main.h" // TODO
19 
20 #if NEED_LOCAL_WEED
21 #include "../libweed/weed-host.h"
22 #include "../libweed/weed.h"
23 #include "../libweed/weed-utils.h"
24 #include "../libweed/weed-effects.h"
25 #include "../libweed/weed-palettes.h"
26 #else
27 #include <weed/weed-host.h>
28 #include <weed/weed.h>
29 #include <weed/weed-utils.h>
30 #include <weed/weed-effects.h>
31 #include <weed/weed-palettes.h>
32 #endif
33 
34 #include "weed-effects-utils.h"
35 
36 #ifndef WEED_GLOBAL_INLINE
37 #define WEED_GLOBAL_INLINE inline
38 #endif
39 
40 #ifndef WEED_LOCAL_INLINE
41 #define WEED_LOCAL_INLINE static inline
42 #endif
43 
weed_plant_get_type(weed_plant_t * plant)44 WEED_GLOBAL_INLINE int32_t weed_plant_get_type(weed_plant_t *plant) {
45   if (!plant) return WEED_PLANT_UNKNOWN;
46   return weed_get_int_value(plant, WEED_LEAF_TYPE, NULL);
47 }
48 
weed_leaf_set_flagbits(weed_plant_t * plant,const char * leaf,uint32_t flagbits)49 WEED_GLOBAL_INLINE uint32_t weed_leaf_set_flagbits(weed_plant_t *plant, const char *leaf, uint32_t flagbits) {
50   uint32_t flags = 0;
51   if (plant) {
52     flags = weed_leaf_get_flags(plant, leaf);
53     weed_leaf_set_flags(plant, leaf, flags | flagbits);
54   }
55   return flags;
56 }
57 
weed_leaf_clear_flagbits(weed_plant_t * plant,const char * leaf,uint32_t flagbits)58 WEED_GLOBAL_INLINE uint32_t weed_leaf_clear_flagbits(weed_plant_t *plant, const char *leaf, uint32_t flagbits) {
59   uint32_t flags = 0;
60   if (plant) {
61     flags = weed_leaf_get_flags(plant, leaf);
62     weed_leaf_set_flags(plant, leaf, flags & ~flagbits);
63   }
64   return flags;
65 }
66 
weed_add_plant_flags(weed_plant_t * plant,uint32_t flags,const char * ign_prefix)67 void weed_add_plant_flags(weed_plant_t *plant, uint32_t flags, const char *ign_prefix) {
68   if (!plant) return;
69   else {
70     size_t ign_prefix_len = 0;
71     char **leaves = weed_plant_list_leaves(plant, NULL);
72     if (leaves) {
73       if (ign_prefix) ign_prefix_len = strlen(ign_prefix);
74       for (register int i = 0; leaves[i]; i++) {
75         if (!ign_prefix || strncmp(leaves[i], ign_prefix, ign_prefix_len)) {
76           weed_leaf_set_flagbits(plant, leaves[i], flags);
77         }
78         free(leaves[i]);
79       }
80       free(leaves);
81     }
82   }
83 }
84 
weed_clear_plant_flags(weed_plant_t * plant,uint32_t flags,const char * ign_prefix)85 void weed_clear_plant_flags(weed_plant_t *plant, uint32_t flags, const char *ign_prefix) {
86   if (!plant) return;
87   else {
88     size_t ign_prefix_len = 0;
89     char **leaves = weed_plant_list_leaves(plant, NULL);
90     if (leaves) {
91       if (ign_prefix) ign_prefix_len = strlen(ign_prefix);
92       for (register int i = 0; leaves[i]; i++) {
93         if (!ign_prefix || strncmp(leaves[i], ign_prefix, ign_prefix_len)) {
94           weed_leaf_clear_flagbits(plant, leaves[i], flags);
95         }
96         free(leaves[i]);
97       }
98       free(leaves);
99     }
100   }
101 }
102 
_weed_get_gui(weed_plant_t * plant,int create_if_not_exists)103 WEED_LOCAL_INLINE weed_plant_t *_weed_get_gui(weed_plant_t *plant,  int create_if_not_exists) {
104   weed_plant_t *gui = NULL;
105   int type = weed_plant_get_type(plant);
106   if (type != WEED_PLANT_FILTER_CLASS && type != WEED_PLANT_PARAMETER_TEMPLATE
107       && type != WEED_PLANT_PARAMETER && type != WEED_PLANT_FILTER_INSTANCE) return NULL;
108   gui = weed_get_plantptr_value(plant, WEED_LEAF_GUI, NULL);
109   if (!gui && create_if_not_exists == WEED_TRUE) {
110     gui = weed_plant_new(WEED_PLANT_GUI);
111     weed_leaf_set(plant, WEED_LEAF_GUI, WEED_SEED_PLANTPTR, 1, &gui);
112   }
113   return gui;
114 }
115 
weed_host_info_get_flags(weed_plant_t * hinfo)116 WEED_GLOBAL_INLINE int weed_host_info_get_flags(weed_plant_t *hinfo) {
117   if (!WEED_PLANT_IS_HOST_INFO(hinfo)) return 0;
118   return weed_get_int_value(hinfo, WEED_LEAF_FLAGS, NULL);
119 }
120 
weed_host_info_set_flags(weed_plant_t * hinfo,int flags)121 WEED_GLOBAL_INLINE void weed_host_info_set_flags(weed_plant_t *hinfo, int flags) {
122   if (!WEED_PLANT_IS_HOST_INFO(hinfo)) return;
123   weed_set_int_value(hinfo, WEED_LEAF_FLAGS, flags);
124 }
125 
weed_host_set_verbosity(weed_plant_t * hinfo,int verbosity)126 WEED_GLOBAL_INLINE void weed_host_set_verbosity(weed_plant_t *hinfo, int verbosity) {
127   if (WEED_PLANT_IS_HOST_INFO(hinfo))
128     weed_set_int_value(hinfo, WEED_LEAF_VERBOSITY, verbosity);
129 }
130 
weed_host_set_supports_linear_gamma(weed_plant_t * hinfo)131 WEED_GLOBAL_INLINE void weed_host_set_supports_linear_gamma(weed_plant_t *hinfo) {
132   if (WEED_PLANT_IS_HOST_INFO(hinfo))
133     weed_host_info_set_flags(hinfo, weed_host_info_get_flags(hinfo) | WEED_HOST_SUPPORTS_LINEAR_GAMMA);
134 }
135 
weed_host_set_supports_premult_alpha(weed_plant_t * hinfo)136 WEED_GLOBAL_INLINE void weed_host_set_supports_premult_alpha(weed_plant_t *hinfo) {
137   if (WEED_PLANT_IS_HOST_INFO(hinfo))
138     weed_host_info_set_flags(hinfo, weed_host_info_get_flags(hinfo) | WEED_HOST_SUPPORTS_PREMULTIPLIED_ALPHA);
139 }
140 
weed_plugin_info_get_package_name(weed_plant_t * pinfo)141 WEED_GLOBAL_INLINE char *weed_plugin_info_get_package_name(weed_plant_t *pinfo) {
142   if (!WEED_PLANT_IS_PLUGIN_INFO(pinfo)) return NULL;
143   return weed_get_string_value(pinfo, WEED_LEAF_PACKAGE_NAME, NULL);
144 }
145 
weed_filter_get_gui(weed_plant_t * filter,int create_if_not_exists)146 WEED_GLOBAL_INLINE weed_plant_t *weed_filter_get_gui(weed_plant_t *filter, int create_if_not_exists) {
147   return _weed_get_gui(filter, create_if_not_exists);
148 }
149 
weed_filter_get_plugin_info(weed_plant_t * filter)150 WEED_GLOBAL_INLINE weed_plant_t *weed_filter_get_plugin_info(weed_plant_t *filter) {
151   return weed_get_plantptr_value(filter, WEED_LEAF_PLUGIN_INFO, NULL);
152 }
153 
weed_filter_get_package_name(weed_plant_t * filter)154 WEED_GLOBAL_INLINE char *weed_filter_get_package_name(weed_plant_t *filter) {
155   return weed_plugin_info_get_package_name(weed_filter_get_plugin_info(filter));
156 }
157 
weed_instance_get_gui(weed_plant_t * inst,int create_if_not_exists)158 WEED_GLOBAL_INLINE weed_plant_t *weed_instance_get_gui(weed_plant_t *inst, int create_if_not_exists) {
159   return _weed_get_gui(inst, create_if_not_exists);
160 }
161 
weed_paramtmpl_get_gui(weed_plant_t * paramt,int create_if_not_exists)162 WEED_GLOBAL_INLINE weed_plant_t *weed_paramtmpl_get_gui(weed_plant_t *paramt, int create_if_not_exists) {
163   return _weed_get_gui(paramt, create_if_not_exists);
164 }
165 
weed_param_get_gui(weed_plant_t * param,int create_if_not_exists)166 WEED_GLOBAL_INLINE weed_plant_t *weed_param_get_gui(weed_plant_t *param, int create_if_not_exists) {
167   return _weed_get_gui(param, create_if_not_exists);
168 }
169 
weed_param_is_hidden(weed_plant_t * param,int temporary)170 WEED_GLOBAL_INLINE int weed_param_is_hidden(weed_plant_t *param, int temporary) {
171   weed_plant_t *gui = weed_param_get_gui(param, WEED_FALSE);
172   if (!temporary || !gui) return weed_paramtmpl_hints_hidden(weed_param_get_template(param));
173   return weed_get_boolean_value(gui, WEED_LEAF_HIDDEN, NULL);
174 }
175 
weed_filter_get_flags(weed_plant_t * filter)176 WEED_GLOBAL_INLINE int weed_filter_get_flags(weed_plant_t *filter) {
177   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return 0;
178   return weed_get_int_value(filter, WEED_LEAF_FLAGS, NULL);
179 }
180 
weed_filter_hints_unstable(weed_plant_t * filter)181 WEED_GLOBAL_INLINE int weed_filter_hints_unstable(weed_plant_t *filter) {
182   if (weed_filter_get_flags(filter) & WEED_FILTER_HINT_MAYBE_UNSTABLE) return WEED_TRUE;
183   return WEED_FALSE;
184 }
185 
weed_filter_hints_stateless(weed_plant_t * filter)186 WEED_GLOBAL_INLINE int weed_filter_hints_stateless(weed_plant_t *filter) {
187   if (weed_filter_get_flags(filter) & WEED_FILTER_HINT_STATELESS) return WEED_TRUE;
188   return WEED_FALSE;
189 }
190 
weed_filter_non_realtime(weed_plant_t * filter)191 WEED_GLOBAL_INLINE int weed_filter_non_realtime(weed_plant_t *filter) {
192   if (weed_filter_get_flags(filter) & WEED_FILTER_NON_REALTIME) return WEED_TRUE;
193   return WEED_FALSE;
194 }
195 
weed_filter_may_thread(weed_plant_t * filter)196 WEED_GLOBAL_INLINE int weed_filter_may_thread(weed_plant_t *filter) {
197   if (weed_filter_get_flags(filter) & WEED_FILTER_HINT_MAY_THREAD) return WEED_TRUE;
198   return WEED_FALSE;
199 }
200 
weed_filter_channel_sizes_vary(weed_plant_t * filter)201 WEED_GLOBAL_INLINE int weed_filter_channel_sizes_vary(weed_plant_t *filter) {
202   if (weed_filter_get_flags(filter) & WEED_FILTER_CHANNEL_SIZES_MAY_VARY) return WEED_TRUE;
203   return WEED_FALSE;
204 }
205 
weed_filter_palettes_vary(weed_plant_t * filter)206 WEED_GLOBAL_INLINE int weed_filter_palettes_vary(weed_plant_t *filter) {
207   if (weed_filter_get_flags(filter) & WEED_FILTER_PALETTES_MAY_VARY) return WEED_TRUE;
208   return WEED_FALSE;
209 }
210 
weed_filter_prefers_linear_gamma(weed_plant_t * filter)211 WEED_GLOBAL_INLINE int weed_filter_prefers_linear_gamma(weed_plant_t *filter) {
212   if (weed_filter_get_flags(filter) & WEED_FILTER_PREF_LINEAR_GAMMA) return WEED_TRUE;
213   return WEED_FALSE;
214 }
215 
weed_filter_prefers_premult_alpha(weed_plant_t * filter)216 WEED_GLOBAL_INLINE int weed_filter_prefers_premult_alpha(weed_plant_t *filter) {
217   if (weed_filter_get_flags(filter) & WEED_FILTER_PREF_PREMULTIPLIED_ALPHA) return WEED_TRUE;
218   return WEED_FALSE;
219 }
220 
weed_filter_is_converter(weed_plant_t * filter)221 WEED_GLOBAL_INLINE int weed_filter_is_converter(weed_plant_t *filter) {
222   if (weed_filter_get_flags(filter) & WEED_FILTER_IS_CONVERTER) return WEED_TRUE;
223   return WEED_FALSE;
224 }
225 
weed_filter_is_process_last(weed_plant_t * filter)226 WEED_GLOBAL_INLINE int weed_filter_is_process_last(weed_plant_t *filter) {
227   if (weed_filter_get_flags(filter) & WEED_FILTER_HINT_PROCESS_LAST) return WEED_TRUE;
228   return WEED_FALSE;
229 }
230 
weed_filter_hints_hidden(weed_plant_t * filter)231 WEED_GLOBAL_INLINE int weed_filter_hints_hidden(weed_plant_t *filter) {
232   weed_plant_t *gui;
233   if (WEED_PLANT_IS_FILTER_CLASS(filter)
234       && (gui = weed_filter_get_gui(filter, WEED_FALSE))
235       && weed_get_boolean_value(gui, WEED_LEAF_HIDDEN, NULL) == WEED_TRUE)
236     return WEED_TRUE;
237   return WEED_FALSE;
238 }
239 
weed_filter_get_name(weed_plant_t * filter)240 WEED_GLOBAL_INLINE char *weed_filter_get_name(weed_plant_t *filter) {
241   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
242   return weed_get_string_value(filter, WEED_LEAF_NAME, NULL);
243 }
244 
weed_filter_get_in_chantmpls(weed_plant_t * filter,int * ntmpls)245 WEED_GLOBAL_INLINE weed_plant_t **weed_filter_get_in_chantmpls(weed_plant_t *filter, int *ntmpls) {
246   if (ntmpls) *ntmpls = 0;
247   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
248   return weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_CHANNEL_TEMPLATES, ntmpls);
249 }
250 
weed_filter_get_out_chantmpls(weed_plant_t * filter,int * ntmpls)251 WEED_GLOBAL_INLINE weed_plant_t **weed_filter_get_out_chantmpls(weed_plant_t *filter, int *ntmpls) {
252   if (ntmpls) *ntmpls = 0;
253   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
254   return weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_CHANNEL_TEMPLATES, ntmpls);
255 }
256 
weed_filter_get_in_paramtmpls(weed_plant_t * filter,int * ntmpls)257 WEED_GLOBAL_INLINE weed_plant_t **weed_filter_get_in_paramtmpls(weed_plant_t *filter, int *ntmpls) {
258   if (ntmpls) *ntmpls = 0;
259   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
260   return weed_get_plantptr_array_counted(filter, WEED_LEAF_IN_PARAMETER_TEMPLATES, ntmpls);
261 }
262 
weed_filter_get_out_paramtmpls(weed_plant_t * filter,int * ntmpls)263 WEED_GLOBAL_INLINE weed_plant_t **weed_filter_get_out_paramtmpls(weed_plant_t *filter, int *ntmpls) {
264   if (ntmpls) *ntmpls = 0;
265   if (!WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
266   return weed_get_plantptr_array_counted(filter, WEED_LEAF_OUT_PARAMETER_TEMPLATES, ntmpls);
267 }
268 
269 /* int weed_filter_get_transition_param(weed_plant_t *filter, const char *skip) { */
270 /*   int num_params, count = 0; */
271 /*   weed_plant_t **in_ptmpls = weed_filter_get_in_paramtmpls(filter, &num_params); */
272 /*   if (num_params == 0) return -1; */
273 /*   for (int i = 0; i < num_params; i++) { */
274 /*     if (skip != NULL && weed_plant_has_leaf(in_ptmpls[i], skip)) continue; */
275 /*     if (weed_get_boolean_value(in_ptmpls[i], WEED_LEAF_IS_TRANSITION, NULL) == WEED_TRUE) { */
276 /*       free_func(in_ptmpls); */
277 /*       return count; */
278 /*     } */
279 /*     count++; */
280 /*   } */
281 /*   free_func(in_ptmpls); */
282 /*   return -1; */
283 /* } */
284 
weed_chantmpl_get_name(weed_plant_t * chantmpl)285 WEED_GLOBAL_INLINE char *weed_chantmpl_get_name(weed_plant_t *chantmpl) {
286   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return NULL;
287   return weed_get_string_value(chantmpl, WEED_LEAF_NAME, NULL);
288 }
289 
weed_chantmpl_get_flags(weed_plant_t * chantmpl)290 WEED_GLOBAL_INLINE int weed_chantmpl_get_flags(weed_plant_t *chantmpl) {
291   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return 0;
292   return weed_get_int_value(chantmpl, WEED_LEAF_FLAGS, NULL);
293 }
294 
weed_chantmpl_get_max_audio_length(weed_plant_t * chantmpl)295 WEED_GLOBAL_INLINE int weed_chantmpl_get_max_audio_length(weed_plant_t *chantmpl) {
296   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return 0;
297   return weed_get_int_value(chantmpl, WEED_LEAF_MAX_AUDIO_LENGTH, NULL);
298 }
299 
weed_paramtmpl_get_flags(weed_plant_t * paramtmpl)300 WEED_GLOBAL_INLINE int weed_paramtmpl_get_flags(weed_plant_t *paramtmpl) {
301   if (!WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) return 0;
302   return weed_get_int_value(paramtmpl, WEED_LEAF_FLAGS, NULL);
303 }
304 
weed_paramtmpl_value_type(weed_plant_t * paramtmpl)305 WEED_GLOBAL_INLINE uint32_t weed_paramtmpl_value_type(weed_plant_t *paramtmpl) {
306   if (!WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) return WEED_SEED_INVALID;
307   if (weed_paramtmpl_has_variable_size(paramtmpl) && weed_plant_has_leaf(paramtmpl, WEED_LEAF_NEW_DEFAULT))
308     return weed_leaf_seed_type(paramtmpl, WEED_LEAF_NEW_DEFAULT);
309   return weed_leaf_seed_type(paramtmpl, WEED_LEAF_DEFAULT);
310 }
311 
weed_paramtmpl_get_type(weed_plant_t * paramtmpl)312 WEED_GLOBAL_INLINE int weed_paramtmpl_get_type(weed_plant_t *paramtmpl) {
313   if (!WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) return 0;
314   return weed_get_int_value(paramtmpl, WEED_LEAF_PARAM_TYPE, NULL);
315 }
316 
weed_paramtmpl_get_name(weed_plant_t * paramtmpl)317 WEED_GLOBAL_INLINE char *weed_paramtmpl_get_name(weed_plant_t *paramtmpl) {
318   if (!WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) return NULL;
319   return weed_get_string_value(paramtmpl, WEED_LEAF_NAME, NULL);
320 }
321 
weed_paramtmpl_has_variable_size(weed_plant_t * paramtmpl)322 WEED_GLOBAL_INLINE int weed_paramtmpl_has_variable_size(weed_plant_t *paramtmpl) {
323   if (WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)
324       && (weed_paramtmpl_get_flags(paramtmpl) & WEED_PARAMETER_VARIABLE_SIZE)) return WEED_TRUE;
325   return WEED_FALSE;
326 }
327 
weed_paramtmpl_has_value_perchannel(weed_plant_t * paramtmpl)328 WEED_GLOBAL_INLINE int weed_paramtmpl_has_value_perchannel(weed_plant_t *paramtmpl) {
329   if (WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)
330       && (weed_paramtmpl_get_flags(paramtmpl) & WEED_PARAMETER_VALUE_PER_CHANNEL)) return WEED_TRUE;
331   return WEED_FALSE;
332 }
333 
weed_paramtmpl_does_wrap(weed_plant_t * paramtmpl)334 WEED_GLOBAL_INLINE int weed_paramtmpl_does_wrap(weed_plant_t *paramtmpl) {
335   weed_plant_t *gui;
336   if (!WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) return -1;
337   if ((gui = weed_paramtmpl_get_gui(paramtmpl, WEED_FALSE))
338       && weed_get_boolean_value(gui, WEED_LEAF_WRAP, NULL) == WEED_TRUE) return WEED_TRUE;
339   return WEED_FALSE;
340 }
341 
weed_paramtmpl_hints_string_choice(weed_plant_t * paramtmpl)342 WEED_GLOBAL_INLINE int weed_paramtmpl_hints_string_choice(weed_plant_t *paramtmpl) {
343   weed_plant_t *gui;
344   if (WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)
345       && (gui = weed_paramtmpl_get_gui(weed_param_get_template(paramtmpl), WEED_FALSE))
346       && weed_plant_has_leaf(gui, WEED_LEAF_CHOICES))
347     return WEED_TRUE;
348   return WEED_FALSE;
349 }
350 
weed_paramtmpl_hints_hidden(weed_plant_t * paramtmpl)351 WEED_GLOBAL_INLINE int weed_paramtmpl_hints_hidden(weed_plant_t *paramtmpl) {
352   weed_plant_t *gui;
353   if (WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)
354       && (gui = weed_paramtmpl_get_gui(paramtmpl, WEED_FALSE))
355       && weed_get_boolean_value(gui, WEED_LEAF_HIDDEN, NULL) == WEED_TRUE)
356     return WEED_TRUE;
357   return WEED_FALSE;
358 }
359 
weed_paramtmpl_value_irrelevant(weed_plant_t * paramtmpl)360 WEED_GLOBAL_INLINE int weed_paramtmpl_value_irrelevant(weed_plant_t *paramtmpl) {
361   if (WEED_PLANT_IS_PARAMETER_TEMPLATE(paramtmpl)) {
362     if (weed_paramtmpl_get_flags(paramtmpl) & WEED_PARAMETER_VALUE_IRRELEVANT) return WEED_TRUE;
363   }
364   return WEED_FALSE;
365 }
366 
weed_chantmpl_is_optional(weed_plant_t * chantmpl)367 WEED_GLOBAL_INLINE int weed_chantmpl_is_optional(weed_plant_t *chantmpl) {
368   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return WEED_TRUE;
369   if (weed_chantmpl_get_flags(chantmpl) & WEED_CHANNEL_OPTIONAL) return WEED_TRUE;
370   return WEED_FALSE;
371 }
372 
weed_chantmpl_get_max_repeats(weed_plant_t * chantmpl)373 WEED_GLOBAL_INLINE int weed_chantmpl_get_max_repeats(weed_plant_t *chantmpl) {
374   /// a return value of zero means unlimited repeats
375   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return -1;
376   if (weed_plant_has_leaf(chantmpl, WEED_LEAF_MAX_REPEATS))
377     return weed_get_int_value(chantmpl, WEED_LEAF_MAX_REPEATS, NULL);
378   return 1;
379 }
380 
weed_chantmpl_is_audio(weed_plant_t * chantmpl)381 WEED_GLOBAL_INLINE int weed_chantmpl_is_audio(weed_plant_t *chantmpl) {
382   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl)) return WEED_TRUE;
383   return weed_get_boolean_value(chantmpl, WEED_LEAF_IS_AUDIO, NULL);
384 }
385 
weed_chantmpl_get_palette_list(weed_plant_t * filter,weed_plant_t * chantmpl,int * nvals)386 WEED_GLOBAL_INLINE int *weed_chantmpl_get_palette_list(weed_plant_t *filter, weed_plant_t *chantmpl, int *nvals) {
387   int *pals, npals;
388   if (nvals) *nvals = 0;
389   if (!WEED_PLANT_IS_CHANNEL_TEMPLATE(chantmpl) || !WEED_PLANT_IS_FILTER_CLASS(filter)) return NULL;
390   if ((weed_filter_get_flags(filter) & WEED_FILTER_PALETTES_MAY_VARY)
391       && weed_plant_has_leaf(chantmpl, WEED_LEAF_PALETTE_LIST)) {
392     pals = weed_get_int_array_counted(chantmpl, WEED_LEAF_PALETTE_LIST, &npals);
393     for (register int i = 0; i < npals; i++) {
394     }
395   } else {
396     if (!weed_plant_has_leaf(filter, WEED_LEAF_PALETTE_LIST)) return NULL;
397     pals = weed_get_int_array_counted(filter, WEED_LEAF_PALETTE_LIST, &npals);
398   }
399   if (npals > 0 && pals[npals - 1] == WEED_PALETTE_END) npals--;
400   if (nvals) *nvals = npals;
401   return pals;
402 }
403 
weed_channel_get_pixel_data(weed_plant_t * channel)404 WEED_GLOBAL_INLINE void *weed_channel_get_pixel_data(weed_plant_t *channel) {
405   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
406   return weed_get_voidptr_value(channel, WEED_LEAF_PIXEL_DATA, NULL);
407 }
408 
weed_channel_get_pixel_data_planar(weed_plant_t * channel,int * nplanes)409 WEED_GLOBAL_INLINE void **weed_channel_get_pixel_data_planar(weed_plant_t *channel, int *nplanes) {
410   if (nplanes) *nplanes = 0;
411   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
412   return weed_get_voidptr_array_counted(channel, WEED_LEAF_PIXEL_DATA, NULL);
413 }
414 
weed_channel_get_width(weed_plant_t * channel)415 WEED_GLOBAL_INLINE int weed_channel_get_width(weed_plant_t *channel) {
416   /// width in macropixels
417   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
418   return weed_get_int_value(channel, WEED_LEAF_WIDTH, NULL);
419 }
420 
weed_channel_set_width(weed_plant_t * channel,int width)421 WEED_GLOBAL_INLINE void weed_channel_set_width(weed_plant_t *channel, int width) {
422   /// width in macropixels
423   if (!WEED_PLANT_IS_CHANNEL(channel)) return;
424   weed_set_int_value(channel, WEED_LEAF_WIDTH, width);
425 }
426 
weed_channel_get_width_pixels(weed_plant_t * channel)427 WEED_GLOBAL_INLINE int weed_channel_get_width_pixels(weed_plant_t *channel) {
428   /// width in pixels: only relevant when comparing widths of diferrent palettes
429   return  weed_channel_get_width(channel) * weed_palette_get_pixels_per_macropixel(weed_channel_get_palette(channel));
430 }
431 
weed_channel_get_height(weed_plant_t * channel)432 WEED_GLOBAL_INLINE int weed_channel_get_height(weed_plant_t *channel) {
433   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
434   return weed_get_int_value(channel, WEED_LEAF_HEIGHT, NULL);
435 }
436 
weed_channel_set_height(weed_plant_t * channel,int height)437 WEED_GLOBAL_INLINE void weed_channel_set_height(weed_plant_t *channel, int height) {
438   if (!WEED_PLANT_IS_CHANNEL(channel)) return;
439   weed_set_int_value(channel, WEED_LEAF_HEIGHT, height);
440 }
441 
weed_channel_set_size(weed_plant_t * channel,int width,int height)442 WEED_GLOBAL_INLINE void weed_channel_set_size(weed_plant_t *channel, int width, int height) {
443   if (!WEED_PLANT_IS_CHANNEL(channel)) return;
444   weed_set_int_value(channel, WEED_LEAF_WIDTH, width);
445   weed_set_int_value(channel, WEED_LEAF_HEIGHT, height);
446 }
447 
weed_channel_set_palette(weed_plant_t * channel,int palette)448 WEED_GLOBAL_INLINE void weed_channel_set_palette(weed_plant_t *channel, int palette) {
449   if (!WEED_PLANT_IS_CHANNEL(channel)) return;
450   weed_set_int_value(channel, WEED_LEAF_CURRENT_PALETTE, palette);
451 }
452 
weed_channel_get_palette(weed_plant_t * channel)453 WEED_GLOBAL_INLINE int weed_channel_get_palette(weed_plant_t *channel) {
454   if (!WEED_PLANT_IS_CHANNEL(channel)) return WEED_PALETTE_NONE;
455   return weed_get_int_value(channel, WEED_LEAF_CURRENT_PALETTE, NULL);
456 }
457 
weed_channel_get_gamma_type(weed_plant_t * channel)458 WEED_GLOBAL_INLINE int weed_channel_get_gamma_type(weed_plant_t *channel) {
459   if (!WEED_PLANT_IS_CHANNEL(channel)) return WEED_PALETTE_NONE;
460   return weed_get_int_value(channel, WEED_LEAF_GAMMA_TYPE, NULL);
461 }
462 
weed_channel_set_gamma_type(weed_plant_t * channel,int gamma_type)463 WEED_GLOBAL_INLINE weed_plant_t *weed_channel_set_gamma_type(weed_plant_t *channel, int gamma_type) {
464   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
465   weed_set_int_value(channel, WEED_LEAF_GAMMA_TYPE, gamma_type);
466   return channel;
467 }
468 
weed_channel_get_palette_yuv(weed_plant_t * channel,int * clamping,int * sampling,int * subspace)469 WEED_GLOBAL_INLINE int weed_channel_get_palette_yuv(weed_plant_t *channel, int *clamping, int *sampling, int *subspace) {
470   if (!WEED_PLANT_IS_CHANNEL(channel)) return WEED_PALETTE_NONE;
471   else {
472     int palette = weed_channel_get_palette(channel);
473     if (weed_palette_is_yuv(palette)) {
474       if (clamping) *clamping = weed_get_int_value(channel, WEED_LEAF_YUV_CLAMPING, NULL);
475       if (sampling) *sampling = weed_get_int_value(channel, WEED_LEAF_YUV_SAMPLING, NULL);
476       if (subspace) *subspace = weed_get_int_value(channel, WEED_LEAF_YUV_SUBSPACE, NULL);
477     }
478     return palette;
479   }
480 }
481 
weed_channel_get_rowstride(weed_plant_t * channel)482 WEED_GLOBAL_INLINE int weed_channel_get_rowstride(weed_plant_t *channel) {
483   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
484   return weed_get_int_value(channel, WEED_LEAF_ROWSTRIDES, NULL);
485 }
486 
weed_channel_get_rowstrides(weed_plant_t * channel,int * nplanes)487 WEED_GLOBAL_INLINE int *weed_channel_get_rowstrides(weed_plant_t *channel, int *nplanes) {
488   if (nplanes) *nplanes = 0;
489   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
490   return weed_get_int_array_counted(channel, WEED_LEAF_ROWSTRIDES, nplanes);
491 }
492 
weed_channel_get_audio_rate(weed_plant_t * channel)493 WEED_GLOBAL_INLINE int weed_channel_get_audio_rate(weed_plant_t *channel) {
494   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
495   return weed_get_int_value(channel, WEED_LEAF_AUDIO_RATE, NULL);
496 }
497 
weed_channel_get_naudchans(weed_plant_t * channel)498 WEED_GLOBAL_INLINE int weed_channel_get_naudchans(weed_plant_t *channel) {
499   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
500   return weed_get_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, NULL);
501 }
502 
weed_channel_get_audio_length(weed_plant_t * channel)503 WEED_GLOBAL_INLINE int weed_channel_get_audio_length(weed_plant_t *channel) {
504   if (!WEED_PLANT_IS_CHANNEL(channel)) return 0;
505   return weed_get_int_value(channel, WEED_LEAF_AUDIO_DATA_LENGTH, NULL);
506 }
507 
weed_channel_is_disabled(weed_plant_t * channel)508 WEED_GLOBAL_INLINE int weed_channel_is_disabled(weed_plant_t *channel) {
509   if (!WEED_PLANT_IS_CHANNEL(channel)) return WEED_TRUE;
510   return weed_get_boolean_value(channel, WEED_LEAF_DISABLED, NULL);
511 }
512 
weed_channel_get_template(weed_plant_t * channel)513 WEED_GLOBAL_INLINE weed_plant_t *weed_channel_get_template(weed_plant_t *channel) {
514   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
515   return weed_get_plantptr_value(channel, WEED_LEAF_TEMPLATE, NULL);
516 }
517 
weed_param_get_template(weed_plant_t * param)518 WEED_GLOBAL_INLINE weed_plant_t *weed_param_get_template(weed_plant_t *param) {
519   if (!WEED_PLANT_IS_PARAMETER(param)) return NULL;
520   return weed_get_plantptr_value(param, WEED_LEAF_TEMPLATE, NULL);
521 }
522 
weed_param_get_type(weed_plant_t * param)523 WEED_GLOBAL_INLINE int weed_param_get_type(weed_plant_t *param) {
524   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_PARAM_UNSPECIFIED;
525   return weed_paramtmpl_get_type(weed_param_get_template(param));
526 }
527 
weed_param_get_value_type(weed_plant_t * param)528 WEED_GLOBAL_INLINE int weed_param_get_value_type(weed_plant_t *param) {
529   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_SEED_INVALID;
530   return weed_paramtmpl_value_type(weed_param_get_template(param));
531 }
532 
weed_param_has_variable_size(weed_plant_t * param)533 WEED_GLOBAL_INLINE int weed_param_has_variable_size(weed_plant_t *param) {
534   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_FALSE;
535   return weed_paramtmpl_has_variable_size(weed_param_get_template(param));
536 }
537 
weed_param_has_value_perchannel(weed_plant_t * param)538 WEED_GLOBAL_INLINE int weed_param_has_value_perchannel(weed_plant_t *param) {
539   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_FALSE;
540   return weed_paramtmpl_has_value_perchannel(weed_param_get_template(param));
541 }
542 
weed_param_value_irrelevant(weed_plant_t * param)543 WEED_GLOBAL_INLINE int weed_param_value_irrelevant(weed_plant_t *param) {
544   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_FALSE;
545   return weed_paramtmpl_value_irrelevant(weed_param_get_template(param));
546 }
547 
weed_param_does_wrap(weed_plant_t * param)548 WEED_GLOBAL_INLINE int weed_param_does_wrap(weed_plant_t *param) {
549   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_FALSE;
550   return weed_paramtmpl_does_wrap(weed_param_get_template(param));
551 }
552 
weed_param_get_nchoices(weed_plant_t * param)553 WEED_GLOBAL_INLINE int weed_param_get_nchoices(weed_plant_t *param) {
554   weed_plant_t *gui;
555   if (!WEED_PLANT_IS_PARAMETER(param)) return 0;
556   if ((gui = weed_param_get_gui(param, WEED_FALSE)) != NULL && weed_plant_has_leaf(gui, WEED_LEAF_CHOICES))
557     return weed_leaf_num_elements(gui, WEED_LEAF_CHOICES);
558   if ((gui = weed_paramtmpl_get_gui(weed_param_get_template(param), WEED_FALSE))
559       && weed_plant_has_leaf(gui, WEED_LEAF_CHOICES))
560     return weed_leaf_num_elements(gui, WEED_LEAF_CHOICES);
561   return 0;
562 }
563 
weed_channel_get_audio_data(weed_plant_t * channel,int * naudchans)564 WEED_GLOBAL_INLINE float **weed_channel_get_audio_data(weed_plant_t *channel, int *naudchans) {
565   if (naudchans) *naudchans = 0;
566   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
567   return (float **)weed_get_voidptr_array_counted(channel, WEED_LEAF_AUDIO_DATA, naudchans);
568 }
569 
weed_channel_set_audio_data(weed_plant_t * channel,float ** data,int arate,int naudchans,int nsamps)570 WEED_GLOBAL_INLINE weed_layer_t *weed_channel_set_audio_data(weed_plant_t *channel, float **data,
571     int arate, int naudchans, int nsamps) {
572   if (!WEED_PLANT_IS_CHANNEL(channel)) return NULL;
573   weed_set_voidptr_array(channel, WEED_LEAF_AUDIO_DATA, naudchans, (void **)data);
574   weed_set_int_value(channel, WEED_LEAF_AUDIO_RATE, arate);
575   weed_set_int_value(channel, WEED_LEAF_AUDIO_DATA_LENGTH, nsamps);
576   weed_set_int_value(channel, WEED_LEAF_AUDIO_CHANNELS, naudchans);
577   return channel;
578 }
579 
weed_instance_get_flags(weed_plant_t * inst)580 WEED_GLOBAL_INLINE int weed_instance_get_flags(weed_plant_t *inst) {
581   if (!WEED_PLANT_IS_FILTER_INSTANCE(inst)) return 0;
582   return weed_get_int_value(inst, WEED_LEAF_FLAGS, NULL);
583 }
584 
weed_instance_set_flags(weed_plant_t * inst,int flags)585 WEED_GLOBAL_INLINE void weed_instance_set_flags(weed_plant_t *inst, int flags) {
586   if (!WEED_PLANT_IS_FILTER_INSTANCE(inst)) return;
587   weed_set_int_value(inst, WEED_LEAF_FLAGS, flags);
588 }
589 
weed_instance_get_in_channels(weed_plant_t * instance,int * nchans)590 WEED_GLOBAL_INLINE weed_plant_t **weed_instance_get_in_channels(weed_plant_t *instance, int *nchans) {
591   if (nchans) *nchans = 0;
592   if (!WEED_PLANT_IS_FILTER_INSTANCE(instance)) return NULL;
593   return weed_get_plantptr_array_counted(instance, WEED_LEAF_IN_CHANNELS, nchans);
594 }
595 
weed_instance_get_out_channels(weed_plant_t * instance,int * nchans)596 WEED_GLOBAL_INLINE weed_plant_t **weed_instance_get_out_channels(weed_plant_t *instance, int *nchans) {
597   if (nchans) *nchans = 0;
598   if (!WEED_PLANT_IS_FILTER_INSTANCE(instance)) return NULL;
599   return weed_get_plantptr_array_counted(instance, WEED_LEAF_OUT_CHANNELS, nchans);
600 }
601 
weed_instance_get_in_params(weed_plant_t * instance,int * nparams)602 WEED_GLOBAL_INLINE weed_plant_t **weed_instance_get_in_params(weed_plant_t *instance, int *nparams) {
603   if (nparams) *nparams = 0;
604   if (!WEED_PLANT_IS_FILTER_INSTANCE(instance)) return NULL;
605   return weed_get_plantptr_array_counted(instance, WEED_LEAF_IN_PARAMETERS, nparams);
606 }
607 
weed_instance_get_out_params(weed_plant_t * instance,int * nparams)608 WEED_GLOBAL_INLINE weed_plant_t **weed_instance_get_out_params(weed_plant_t *instance, int *nparams) {
609   if (nparams) *nparams = 0;
610   if (!WEED_PLANT_IS_FILTER_INSTANCE(instance)) return NULL;
611   return weed_get_plantptr_array_counted(instance, WEED_LEAF_OUT_PARAMETERS, nparams);
612 }
613 
weed_param_get_value_int(weed_plant_t * param)614 WEED_GLOBAL_INLINE int weed_param_get_value_int(weed_plant_t *param) {
615   if (!WEED_PLANT_IS_PARAMETER(param)) return 0;
616   return weed_get_int_value(param, WEED_LEAF_VALUE, NULL);
617 }
618 
weed_param_get_value_boolean(weed_plant_t * param)619 WEED_GLOBAL_INLINE int weed_param_get_value_boolean(weed_plant_t *param) {
620   if (!WEED_PLANT_IS_PARAMETER(param)) return WEED_FALSE;
621   return weed_get_boolean_value(param, WEED_LEAF_VALUE, NULL);
622 }
623 
weed_param_get_value_double(weed_plant_t * param)624 WEED_GLOBAL_INLINE double weed_param_get_value_double(weed_plant_t *param) {
625   if (!WEED_PLANT_IS_PARAMETER(param)) return 0.;
626   return weed_get_double_value(param, WEED_LEAF_VALUE, NULL);
627 }
628 
weed_param_get_value_int64(weed_plant_t * param)629 WEED_GLOBAL_INLINE int64_t weed_param_get_value_int64(weed_plant_t *param) {
630   if (!WEED_PLANT_IS_PARAMETER(param)) return 0;
631   return weed_get_int64_value(param, WEED_LEAF_VALUE, NULL);
632 }
633 
weed_param_get_value_string(weed_plant_t * param)634 WEED_GLOBAL_INLINE char *weed_param_get_value_string(weed_plant_t *param) {
635   if (!WEED_PLANT_IS_PARAMETER(param)) return NULL;
636   if (weed_leaf_num_elements(param, WEED_LEAF_VALUE) == 0) return NULL;
637   return weed_get_string_value(param, WEED_LEAF_VALUE, NULL);
638 }
639 
weed_gui_get_flags(weed_plant_t * gui)640 WEED_GLOBAL_INLINE int weed_gui_get_flags(weed_plant_t *gui) {
641   if (!WEED_PLANT_IS_GUI(gui)) return 0;
642   return weed_get_int_value(gui, WEED_LEAF_FLAGS, NULL);
643 }
644 
645 //////////////////////////////////////////// utilities ///////////////////////
646 
weed_error_to_text(weed_error_t error)647 char *weed_error_to_text(weed_error_t error) {
648   // return value should be freed after use
649   switch (error) {
650   case (WEED_ERROR_MEMORY_ALLOCATION):
651     return strdup("Memory allocation error");
652     /* case (WEED_ERROR_CONCURRENCY): */
653     return strdup("Thread concurrency failure");
654   case (WEED_ERROR_IMMUTABLE):
655     return strdup("Read only property");
656   case (WEED_ERROR_UNDELETABLE):
657     return strdup("Undeletable property");
658   case (WEED_ERROR_BADVERSION):
659     return strdup("Bad version number");
660   case (WEED_ERROR_NOSUCH_ELEMENT):
661     return strdup("Invalid element");
662   case (WEED_ERROR_NOSUCH_LEAF):
663     return strdup("Invalid property");
664   case (WEED_ERROR_WRONG_SEED_TYPE):
665     return strdup("Incorrect property type");
666   case (WEED_ERROR_TOO_MANY_INSTANCES):
667     return strdup("Too many instances");
668   case (WEED_ERROR_PLUGIN_INVALID):
669     return strdup("Fatal plugin error");
670   case (WEED_ERROR_FILTER_INVALID):
671     return strdup("Invalid filter in plugin");
672   case (WEED_ERROR_REINIT_NEEDED):
673     return strdup("Filter needs reiniting");
674   default:
675     break;
676   }
677   return strdup("No error");
678 }
679 
weed_seed_type_to_text(uint32_t seed_type)680 char *weed_seed_type_to_text(uint32_t seed_type) {
681   switch (seed_type) {
682   case WEED_SEED_INT:
683     return strdup("integer");
684   case WEED_SEED_INT64:
685     return strdup("int64");
686   case WEED_SEED_BOOLEAN:
687     return strdup("boolean");
688   case WEED_SEED_DOUBLE:
689     return strdup("double");
690   case WEED_SEED_STRING:
691     return strdup("string");
692   case WEED_SEED_FUNCPTR:
693     return strdup("function pointer");
694   case WEED_SEED_VOIDPTR:
695     return strdup("void *");
696   case WEED_SEED_PLANTPTR:
697     return strdup("weed_plant_t *");
698   default:
699     return strdup("custom pointer type");
700   }
701 }
702 
weed_palette_get_name(int pal)703 const char *weed_palette_get_name(int pal) {
704   switch (pal) {
705   case WEED_PALETTE_RGB24:
706     return "RGB24";
707   case WEED_PALETTE_RGBA32:
708     return "RGBA32";
709   case WEED_PALETTE_BGR24:
710     return "BGR24";
711   case WEED_PALETTE_BGRA32:
712     return "BGRA32";
713   case WEED_PALETTE_ARGB32:
714     return "ARGB32";
715   case WEED_PALETTE_RGBFLOAT:
716     return "RGBFLOAT";
717   case WEED_PALETTE_RGBAFLOAT:
718     return "RGBAFLOAT";
719   case WEED_PALETTE_YUV888:
720     return "YUV888";
721   case WEED_PALETTE_YUVA8888:
722     return "YUVA8888";
723   case WEED_PALETTE_YUV444P:
724     return "YUV444P";
725   case WEED_PALETTE_YUVA4444P:
726     return "YUVA4444P";
727   case WEED_PALETTE_YUV422P:
728     return "YUV4422P";
729   case WEED_PALETTE_YUV420P:
730     return "YUV420P";
731   case WEED_PALETTE_YVU420P:
732     return "YVU420P";
733   case WEED_PALETTE_YUV411:
734     return "YUV411";
735   case WEED_PALETTE_UYVY8888:
736     return "UYVY";
737   case WEED_PALETTE_YUYV8888:
738     return "YUYV";
739   case WEED_PALETTE_A8:
740     return "8 BIT ALPHA";
741   case WEED_PALETTE_A1:
742     return "1 BIT ALPHA";
743   case WEED_PALETTE_AFLOAT:
744     return "FLOAT ALPHA";
745   default:
746     if (pal >= 2048) return "custom";
747     return "unknown";
748   }
749 }
750 
weed_yuv_clamping_get_name(int clamping)751 const char *weed_yuv_clamping_get_name(int clamping) {
752   if (clamping == WEED_YUV_CLAMPING_UNCLAMPED) return "unclamped";
753   if (clamping == WEED_YUV_CLAMPING_CLAMPED) return "clamped";
754   return NULL;
755 }
756 
weed_yuv_subspace_get_name(int subspace)757 const char *weed_yuv_subspace_get_name(int subspace) {
758   if (subspace == WEED_YUV_SUBSPACE_YUV) return "Y'UV";
759   if (subspace == WEED_YUV_SUBSPACE_YCBCR) return "Y'CbCr";
760   if (subspace == WEED_YUV_SUBSPACE_BT709) return "BT.709";
761   return NULL;
762 }
763 
weed_palette_get_name_full(int pal,int clamping,int subspace)764 char *weed_palette_get_name_full(int pal, int clamping, int subspace) {
765   const char *pname = weed_palette_get_name(pal);
766   if (weed_palette_is_yuv(pal)) {
767     const char *clamp = weed_yuv_clamping_get_name(clamping);
768     const char *sspace = weed_yuv_subspace_get_name(subspace);
769     return lives_strdup_printf("%s:%s (%s)", pname, sspace, clamp); // TODO
770   }
771   return strdup(pname);
772 }
773 
weed_gamma_get_name(int gamma)774 const char *weed_gamma_get_name(int gamma) {
775   if (gamma == WEED_GAMMA_LINEAR) return "linear";
776   if (gamma == WEED_GAMMA_SRGB) return "sRGB";
777   if (gamma == WEED_GAMMA_BT709) return "bt709";
778   return "unknown";
779 }
780 
781 #ifndef WEED_ADVANCED_PALETTES
782 
weed_palette_get_bits_per_macropixel(int pal)783 WEED_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal) {
784   if (pal == WEED_PALETTE_A8 || pal == WEED_PALETTE_YUV420P || pal == WEED_PALETTE_YVU420P ||
785       pal == WEED_PALETTE_YUV422P || pal == WEED_PALETTE_YUV444P || pal == WEED_PALETTE_YUVA4444P) return 8;
786   if (pal == WEED_PALETTE_RGB24 || pal == WEED_PALETTE_BGR24) return 24;
787   if (pal == WEED_PALETTE_RGBA32 || pal == WEED_PALETTE_BGRA32 || pal == WEED_PALETTE_ARGB32 ||
788       pal == WEED_PALETTE_UYVY8888 || pal == WEED_PALETTE_YUYV8888 || pal == WEED_PALETTE_YUV888
789       || pal == WEED_PALETTE_YUVA8888)
790     return 32;
791   if (pal == WEED_PALETTE_YUV411) return 48;
792   if (pal == WEED_PALETTE_AFLOAT) return sizeof(float);
793   if (pal == WEED_PALETTE_A1) return 1;
794   if (pal == WEED_PALETTE_RGBFLOAT) return (3 * sizeof(float));
795   if (pal == WEED_PALETTE_RGBAFLOAT) return (4 * sizeof(float));
796   return 0; // unknown palette
797 }
798 
799 #endif
800 
801 // just as an example: 1.0 == RGB(A), 0.5 == compressed to 50%, etc
802 
weed_palette_get_compression_ratio(int pal)803 double weed_palette_get_compression_ratio(int pal) {
804   double tbits = 0.;
805 
806   int nplanes = weed_palette_get_nplanes(pal);
807   int pbits;
808 
809   register int i;
810 
811   if (!weed_palette_is_valid(pal)) return 0.;
812   if (weed_palette_is_alpha(pal)) return 0.; // invalid for alpha palettes
813   for (i = 0; i < nplanes; i++) {
814     pbits = weed_palette_get_bits_per_macropixel(pal) / weed_palette_get_pixels_per_macropixel(pal);
815     tbits += pbits * weed_palette_get_plane_ratio_vertical(pal, i) * weed_palette_get_plane_ratio_horizontal(pal, i);
816   }
817   if (weed_palette_has_alpha(pal)) return tbits / 32.;
818   return tbits / 24.;
819 }
820 
821 
weed_filter_is_resizer(weed_plant_t * filter)822 WEED_GLOBAL_INLINE int weed_filter_is_resizer(weed_plant_t *filter) {
823   if (weed_filter_is_converter(filter) && weed_filter_channel_sizes_vary(filter)) return WEED_TRUE;
824   return WEED_FALSE;
825 }
826 
weed_filter_is_palette_converter(weed_plant_t * filter)827 WEED_GLOBAL_INLINE int weed_filter_is_palette_converter(weed_plant_t *filter) {
828   if (weed_filter_is_converter(filter) && weed_filter_palettes_vary(filter)) return WEED_TRUE;
829   return WEED_FALSE;
830 }
831 
weed_audio_filter_is_resampler(weed_plant_t * filter)832 WEED_GLOBAL_INLINE int weed_audio_filter_is_resampler(weed_plant_t *filter) {
833   int flags = weed_filter_get_flags(filter);
834   if (weed_filter_is_converter(filter)
835       && (flags & WEED_FILTER_AUDIO_RATES_MAY_VARY)) return WEED_TRUE;
836   return WEED_FALSE;
837 }
838 
839