1 // haip.c
2 // weed plugin
3 // (c) G. Finch (salsaman) 2006 - 2012
4 //
5 // released under the GNU GPL 3 or later
6 // see file COPYING or www.gnu.org for details
7 
8 ///////////////////////////////////////////////////////////////////
9 
10 static int package_version = 1; // version of this package
11 
12 //////////////////////////////////////////////////////////////////
13 
14 #define NEED_PALETTE_CONVERSIONS
15 #define NEED_RANDOM
16 
17 #ifndef NEED_LOCAL_WEED_PLUGIN
18 #include <weed/weed-plugin.h>
19 #include <weed/weed-utils.h> // optional
20 #include <weed/weed-plugin-utils.h> // optional
21 #else
22 #include "../../libweed/weed-plugin.h"
23 #include "../../libweed/weed-utils.h" // optional
24 #include "../../libweed/weed-plugin-utils.h" // optional
25 #endif
26 
27 #include "weed-plugin-utils.c" // optional
28 
29 /////////////////////////////////////////////////////////////
30 
31 typedef struct {
32   int x;
33   int y;
34   int *px;
35   int *py;
36   int *wt;
37   uint64_t fastrand_val;
38   int old_width;
39   int old_height;
40 } _sdata;
41 
42 static int ress[8];
43 
haip_init(weed_plant_t * inst)44 static weed_error_t haip_init(weed_plant_t *inst) {
45   _sdata *sdata = weed_malloc(sizeof(_sdata));
46   if (sdata == NULL) return WEED_ERROR_MEMORY_ALLOCATION;
47   else {
48     weed_plant_t **in_params = weed_get_in_params(inst, NULL);
49     int num_wurms = weed_param_get_value_int(in_params[0]);
50     weed_free(in_params);
51 
52     sdata->x = sdata->y = -1;
53 
54     weed_set_voidptr_value(inst, "plugin_internal", sdata);
55 
56     sdata->px = weed_malloc(num_wurms * sizeof(int));
57     sdata->py = weed_malloc(num_wurms * sizeof(int));
58     sdata->wt = weed_malloc(num_wurms * sizeof(int));
59 
60     for (int i = 0; i < num_wurms; i++) {
61       sdata->px[i] = sdata->py[i] = -1;
62     }
63 
64     sdata->old_width = sdata->old_height = -1;
65     sdata->fastrand_val = fastrand(0);
66     return WEED_SUCCESS;
67   }
68 }
69 
70 
haip_deinit(weed_plant_t * inst)71 static weed_error_t haip_deinit(weed_plant_t *inst) {
72   _sdata *sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
73   if (sdata) {
74     if (sdata->wt) weed_free(sdata->wt);
75     if (sdata->px) weed_free(sdata->px);
76     if (sdata->py) weed_free(sdata->py);
77     weed_free(sdata);
78     weed_set_voidptr_value(inst, "plugin_internal", NULL);
79   }
80   return WEED_SUCCESS;
81 }
82 
83 
make_eight_table(unsigned char * pt,int row,int luma,int adj,int pal)84 static int make_eight_table(unsigned char *pt, int row, int luma, int adj, int pal) {
85   int n = 0;
86   for (n = 0; n < 8; n++) ress[n] = -1;
87   n = 0;
88   if (calc_luma(&pt[-row - 3], pal, 0) >= (luma - adj)) {
89     ress[n] = 0;
90     n++;
91   }
92   if (calc_luma(&pt[-row], pal, 0) >= (luma - adj)) {
93     ress[n] = 1;
94     n++;
95   }
96   if (calc_luma(&pt[-row + 3], pal, 0) >= (luma - adj)) {
97     ress[n] = 2;
98     n++;
99   }
100   if (calc_luma(&pt[-3], pal, 0) >= (luma - adj)) {
101     ress[n] = 3;
102     n++;
103   }
104   if (calc_luma(&pt[3], pal, 0) >= (luma - adj)) {
105     ress[n] = 4;
106     n++;
107   }
108   if (calc_luma(&pt[row - 3], pal, 0) >= (luma - adj)) {
109     ress[n] = 5;
110     n++;
111   }
112   if (calc_luma(&pt[row], pal, 0) >= (luma - adj)) {
113     ress[n] = 6;
114     n++;
115   }
116   if (calc_luma(&pt[row + 3], pal, 0) >= (luma - adj)) {
117     ress[n] = 7;
118     n++;
119   }
120   return n;
121 }
122 
123 
select_dir(_sdata * sdata)124 static int select_dir(_sdata *sdata) {
125   int num_choices = 1;
126   int i;
127   int mychoice;
128   float fval;
129 
130   for (i = 0; i < 8; i++) {
131     if (ress[i] != -1) num_choices++;
132   }
133 
134   if (num_choices == 0) return 1;
135   sdata->fastrand_val = fastrand(sdata->fastrand_val);
136   fval = (float)((sdata->fastrand_val >> 16) & 0XFFFF) / 65535.;
137   mychoice = (int)(fval * (float)(num_choices));
138 
139   switch (ress[mychoice]) {
140   case 0:
141     sdata->x--;
142     sdata->y--;
143     break;
144   case 1:
145     sdata->y--;
146     break;
147   case 2:
148     sdata->x++;
149     sdata->y--;
150     break;
151   case 3:
152     sdata->x--;
153     break;
154   case 4:
155     sdata->x++;
156     break;
157   case 5:
158     sdata->x--;
159     sdata->y++;
160     break;
161   case 6:
162     sdata->y++;
163     break;
164   case 7:
165     sdata->x++;
166     sdata->y++;
167     break;
168   }
169   return 0;
170 }
171 
172 
nine_fill(unsigned char * new_data,int row,unsigned char o0,unsigned char o1,unsigned char o2)173 static inline void nine_fill(unsigned char *new_data, int row, unsigned char o0, unsigned char o1, unsigned char o2) {
174   // fill nine pixels with the centre colour
175   new_data[-row - 3] = new_data[-row] = new_data[-row + 3] = new_data[-3] = new_data[0] =
176                                           new_data[3] = new_data[row - 3] = new_data[row] = new_data[row + 3] = o0;
177   new_data[-row - 2] = new_data[-row + 1] = new_data[-row + 4] = new_data[-2] = new_data[1] =
178                          new_data[4] = new_data[row - 2] = new_data[row + 1] = new_data[row + 4] = o1;
179   new_data[-row - 1] = new_data[-row + 2] = new_data[-row + 5] = new_data[-1] = new_data[2] =
180                          new_data[5] = new_data[row - 1] = new_data[row + 2] = new_data[row + 5] = o2;
181 }
182 
183 
black_fill(unsigned char * new_data,int row)184 static inline void black_fill(unsigned char *new_data, int row) {
185   // fill nine pixels with black
186   nine_fill(new_data, row, 0, 0, 0);
187 }
188 
189 
white_fill(unsigned char * new_data,int row)190 static inline void white_fill(unsigned char *new_data, int row) {
191   // fill nine pixels with white
192   nine_fill(new_data, row, 255, 255, 255);
193 }
194 
195 
proc_pt(unsigned char * dest,unsigned char * src,int x,int y,int orows,int irows,int wt)196 static void proc_pt(unsigned char *dest, unsigned char *src, int x, int y, int orows,
197                     int irows, int wt) {
198   size_t offs;
199   switch (wt) {
200   case 0:
201     black_fill(&dest[orows * y + x * 3], orows);
202     break;
203   case 1:
204     white_fill(&dest[orows * y + x * 3], orows);
205     break;
206   case 2:
207     offs = irows * y + x * 3;
208     nine_fill(&dest[orows * y + x * 3], orows, src[offs], src[offs + 1], src[offs + 2]);
209     break;
210   }
211 }
212 
213 
haip_process(weed_plant_t * inst,weed_timecode_t timestamp)214 static weed_error_t haip_process(weed_plant_t *inst, weed_timecode_t timestamp) {
215   _sdata *sdata;
216 
217   weed_plant_t *in_channel = weed_get_in_channel(inst, 0),
218                 *out_channel = weed_get_out_channel(inst, 0);
219 
220   unsigned char *src = weed_channel_get_pixel_data(in_channel);
221   unsigned char *dst = weed_channel_get_pixel_data(out_channel);
222   weed_plant_t **in_params = weed_get_in_params(inst, NULL);
223   int num_wurms = weed_param_get_value_int(in_params[0]);
224   unsigned char *pt;
225 
226   int width = weed_channel_get_width(in_channel), width3 = width * 3;
227   int height = weed_channel_get_height(in_channel);
228   int irowstride = weed_channel_get_stride(in_channel);
229   int orowstride = weed_channel_get_stride(out_channel);
230   int palette = weed_channel_get_palette(in_channel);
231 
232   int count;
233   int luma, adj;
234 
235   uint64_t fastrand_val;
236   float scalex, scaley;
237 
238   register int i;
239 
240   weed_free(in_params);
241 
242   sdata = weed_get_voidptr_value(inst, "plugin_internal", NULL);
243   sdata->fastrand_val = fastrand_val = fastrand(0);
244 
245   for (i = 0; i < height; i++) {
246     weed_memcpy(&dst[i * orowstride], &src[i * irowstride], width3);
247   }
248 
249   if (sdata->old_width == -1) {
250     sdata->old_width = width;
251     sdata->old_height = height;
252   }
253 
254   scalex = (float)width / (float)sdata->old_width;
255   scaley = (float)height / (float)sdata->old_height;
256 
257   for (i = 0; i < num_wurms; i++) {
258     count = 1000;
259     if (sdata->px[i] == -1) {
260       sdata->fastrand_val = fastrand(sdata->fastrand_val);
261       sdata->px[i] = (int)(((sdata->fastrand_val & 0xFF) / 255.*(width - 2))) + 1;
262       sdata->fastrand_val = fastrand(sdata->fastrand_val);
263       sdata->py[i] = (int)(((sdata->fastrand_val & 0xFF) / 255.*(height - 2))) + 1;
264       sdata->fastrand_val = fastrand(sdata->fastrand_val);
265       sdata->wt[i] = (int)(((sdata->fastrand_val & 0xFF) / 255.*2));
266     }
267 
268     sdata->x = (float)sdata->px[i] * scalex;
269     sdata->y = (float)sdata->py[i] * scaley;
270 
271     while (count > 0) {
272       if (sdata->x < 1) sdata->x++;
273       if (sdata->x > width - 2) sdata->x = width - 2;
274       if (sdata->y < 1) sdata->y++;
275       if (sdata->y > height - 2) sdata->y = height - 2;
276 
277       proc_pt(dst, src, sdata->x, sdata->y, orowstride, irowstride, sdata->wt[i]);
278 
279       if (sdata->x < 1) sdata->x++;
280       if (sdata->x > width - 2) sdata->x = width - 2;
281       if (sdata->y < 1) sdata->y++;
282       if (sdata->y > height - 2) sdata->y = height - 2;
283       pt = &src[sdata->y * irowstride + sdata->x * 3];
284 
285       luma = calc_luma(pt, palette, 0);
286       adj = 0;
287 
288       make_eight_table(pt, irowstride, luma, adj, palette);
289       if (((count << 7) >> 7) == count) select_dir(sdata);
290       count--;
291     }
292     sdata->px[i] = sdata->x;
293     sdata->py[i] = sdata->y;
294   }
295 
296   sdata->old_width = width;
297   sdata->old_height = height;
298 
299   return WEED_SUCCESS;
300 }
301 
302 
303 WEED_SETUP_START(200, 200) {
304   int palette_list[] = {WEED_PALETTE_RGB24, WEED_PALETTE_BGR24, WEED_PALETTE_END};
305   weed_plant_t *in_params[] = {weed_integer_init("nwurms", "Number of Wurms", 200, 1, 4092), NULL};
306   weed_plant_t *in_chantmpls[] = {weed_channel_template_init("in channel 0", 0), NULL};
307   weed_plant_t *out_chantmpls[] = {weed_channel_template_init("out channel 0", 0), NULL};
308   weed_plant_t *filter_class = weed_filter_class_init("haip", "salsaman", 1, 0, palette_list,
309                                haip_init, haip_process, haip_deinit,
310                                in_chantmpls, out_chantmpls, in_params, NULL);
311   weed_paramtmpl_set_flags(in_params[0], WEED_PARAMETER_REINIT_ON_VALUE_CHANGE);
312   weed_plugin_info_add_filter_class(plugin_info, filter_class);
313   weed_set_int_value(plugin_info, WEED_LEAF_VERSION, package_version);
314 }
315 WEED_SETUP_END;
316