/* waves.c - waves deformation processing * * Copyright (C) 2002 Patrice St-Gelais * patrstg@users.sourceforge.net * www.oricom.ca/patrice.st-gelais * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "waves.h" #include "img_process.h" #include wave_struct *wave_new(gint shape, gint axis, gint order) { // Builds a linear structure with some defaults wave_struct *ws; ws = (wave_struct *) malloc(sizeof(wave_struct)); ws->order = order; ws->shape = shape; ws->axis = axis; ws->angle = 0; ws->period = 5; ws->amplitude = 0; ws->phase = 0; ws->randomness = 0; ws->seed = rand(); return ws; } void wave_free(wave_struct *ws) { if (ws) free(ws); } gint compare_wave_struct (gpointer data1, gpointer data2) { // For use with g_list_sort wave_struct *n1, *n2; n1 = (wave_struct *) data1; n2 = (wave_struct *) data2; if (n1->orderorder) return -1; else if (n1->order>n2->order) return 1; else return 0; } void smooth_line(shape_type *line, gint length, gint radius) { // Simple line "block" smoothing gint i,j; shape_type *tmp; long int value; tmp = (shape_type *) malloc(sizeof(shape_type)*length); for (i=0; i>1) * (1.0 + sin(DWRAP(rad-PIx0_5,PIx2)))); } break; case CONCAVE_WAVE: // Simple quadratic function, with minima at 0 & length-1 end = 1+ (length >> 1); for (i=0; i2049 for (i=0; i> 1; ratio = ((gdouble) MAX_HF_VALUE) / (gdouble) end; for (i=0; i>2); i++) { *(shape_data+i) = (shape_type) 0.0; } end = (length>>2) + (length >>1); for (i=(length>>2); iperiod) = size >> ws->period // ADDITIVE merge if (!ws->amplitude) return; ampl = (ws->period*ws->amplitude) / 1000.0; diff = ( (shape_type) (0xFFFF>>1) ) * ampl; // diff=0.0; step_exp = MAX(0,MIN(11,(10-ws->period+11-log2i(max_x)) )); nb_wav_val = 4096>>step_exp; // printf("AMPL: %5.2f, DIFF: %5.2f; NB_WAV_VAL: %d; step_exp: %d; randomness: %d\n",(gfloat) ampl, (gfloat) diff, nb_wav_val, step_exp, ws->randomness); sine = sin(PI * ((gdouble) -ws->angle) / 180.0) ; cosine = cos(PI * ((gdouble) -ws->angle) / 180.0) ; tmp_sh = (shape_type *) malloc(nb_wav_val*sizeof(shape_type)); step = pow(2,step_exp); min = HUGE_VAL; for (i=0; iphase) * ((gdouble) nb_wav_val) / 100.0; // Random displacement: we don't need more periods than // ~ sqrt(2)*(max_x/nb_wav_val) (diagonal of a 1x1 square) maxperiod = MAX(1,(gint) (1.5 * ((gdouble) max_x) / (gdouble) nb_wav_val)); // printf("MAXPERIOD: %d\n",maxperiod); if (ws->randomness) srand(ws->seed); random_displacement = (gdouble *) malloc(sizeof(gdouble)*maxperiod); for (i=0; irandomness) { *(random_displacement+i) = 1.0 + ((gdouble) ((rand()%ws->randomness) - (ws->randomness>>1))) / 50.0; } else *(random_displacement+i) = 1.0; // printf("Random displacement[%d]: %5.2f\n",i,*(random_displacement+i)); } for (y=0; yperiod) = size >> ws->period // HF_IN and HF_OUT must be different if (!ws->amplitude) return; if (hf_in == hf_outx) hf_out = (hf_type *) malloc(max_x*max_y*sizeof(hf_type)); else hf_out = hf_outx; // DIFF: the sine / cosine vectors are in absolute values from 0 to 0xFFFF // We transform the values to + / - displacements by subtracting half the max diff = (shape_type) (0xFFFF>>1); step_exp = MAX(0,MIN(11,(10-ws->period+11-log2i(max_x)) )); nb_wav_val = 4096>>step_exp; delta_x = (gdouble *) malloc(nb_wav_val*sizeof(gdouble)); delta_y = (gdouble *) malloc(nb_wav_val*sizeof(gdouble)); step = pow(2,step_exp); phase = (gint) ((gfloat) ws->phase * 4096.0 / 100.0); // printf("STEP_EXP: %d; STEP: %d; DIFF: %d; NB_WAV_VAL: %d\n",step_exp, step, diff, nb_wav_val); // Rotate "in" (angle) = Rotate "out" (-angle) sine = sin(PI * ((gdouble) -ws->angle) / 180.0) ; cosine = cos(PI * ((gdouble) -ws->angle) / 180.0) ; cos2 = cos(PI * ((gdouble) ws->angle) / 180.0) ; sin2 = sin(PI * ((gdouble) ws->angle) / 180.0) ; div = pow(2,16-(gint) log2i(max_x)); ampl = ws->amplitude*ws->period*ws->period/200.0; // printf("AMPL: %d\n",ampl); min_x = min_y = HUGE_VAL; for (i=0; i*(delta_x+i)) min_x = *(delta_x+i); if (min_y>*(delta_y+i)) min_y = *(delta_y+i); } // Adjust to 0.0 to avoid non continuous waves if (min_x!=0.0) for (i=0; irandomness) srand(ws->seed); for (i=0; irandomness) { *(random_displacement+i) = 1.0 + ((gdouble) ((rand()%ws->randomness) - (ws->randomness>>1))) / 50.0; } else *(random_displacement+i) = 1.0; for (y=0; yrandomness) { period = WRAP((gint) d_indx,max_x) / nb_wav_val ; d_indx = DWRAP(d_indx,nb_wav_val); vector_interpolate (d_indx, delta_x, nb_wav_val, &valx, GDOUBLE_ID, OVERFLOW_WRAP); vector_interpolate (d_indx, delta_y, nb_wav_val, &valy, GDOUBLE_ID, OVERFLOW_WRAP); interpolate ( ((gdouble) x) +(*(random_displacement+ period) * valx), ((gdouble) y) + (*(random_displacement+ period) * valy) , hf_in, max_x, max_y, &value, HF_TYPE_ID, OVERFLOW_WRAP); } else { d_indx = DWRAP(d_indx,nb_wav_val); vector_interpolate (d_indx, delta_x, nb_wav_val, &valx, GDOUBLE_ID, OVERFLOW_WRAP); vector_interpolate (d_indx, delta_y, nb_wav_val, &valy, GDOUBLE_ID, OVERFLOW_WRAP); interpolate ( ((gdouble) x) + valx, ((gdouble) y) + valy, hf_in, max_x, max_y, &value, HF_TYPE_ID, OVERFLOW_WRAP); } *(hf_out+y*max_x +x) = value; } } if (delta_x) free(delta_x); if (delta_y) free(delta_y); if (hf_in == hf_outx) { memcpy(hf_outx, hf_out, sizeof(hf_type)*max_x*max_y); free(hf_out); } } void waves_apply(hf_struct_type *hf, shape_type **wave_shapes, gint nb_wav, GList *wav_data) { gint i; hf_type *in; GList *ordered_list = NULL,*node = NULL; wave_struct *ws; shape_type *sh; if (!hf->tmp_buf) hf_backup(hf); // Reorder the list on ws->order for (node = wav_data; node; node = node->next) ordered_list = g_list_append(ordered_list,node->data); ordered_list = g_list_sort(ordered_list, (GCompareFunc) compare_wave_struct); i = 0; for (node = ordered_list; node; node=node->next) { ws = (wave_struct *) node->data; // printf("Ordre: %d; axe: %d; amplitude: %d; période: %d\n",ws->order, ws->axis, ws->amplitude,ws->period); sh = *(wave_shapes+ws->shape); if (!i) // 1st step, we start with the backuped buffer in = hf->tmp_buf; else // We apply the next deformations on the output buffer in = hf->hf_buf; if (ws->amplitude) // Added 2006-01 - deals with the case when the 1st tab does nothing i++; if (!sh) { // "on demand" initialization sh = shape_type_new(ws->shape, MAX_HF_SIZE); *(wave_shapes+ws->shape) = sh; } switch (ws->axis) { case VERTICAL_WAVE: vertical_wave(in, hf->hf_buf, hf->max_x, hf->max_y,ws, sh); break; case HORIZONTAL_WAVE: horizontal_wave(in, hf->hf_buf, hf->max_x, hf->max_y,ws, sh); break; case CIRCULAR_WAVE: break; } } g_list_free(ordered_list); }