1 /* erode.c - erosion and cresting functions
2  *
3  * Copyright (C) 2001-2005 Patrice St-Gelais
4  *         patrstg@users.sourceforge.net
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20 
21 #include "hf.h"
22 #include "hf_calc.h"
23 #include "erode.h"
24 
25 #ifndef MAX_CACHE
26 #define MAX_CACHE 32768
27 #endif
28 
29 static gdouble **cache;
30 static gboolean if_cache_init=FALSE;
31 
rain_erosion_struct_new(gint drops,gint threshold,gint strength,gint hardness,gboolean progressive_refresh,gint interval,gboolean old_algorithm)32 rain_erosion_struct *rain_erosion_struct_new (gint drops, gint threshold, gint strength, gint hardness, gboolean progressive_refresh, gint interval, gboolean old_algorithm) {
33 	rain_erosion_struct *res;
34 	res = (rain_erosion_struct *) x_malloc(sizeof(rain_erosion_struct), "rain_erosion_struct");
35 	res->drops = drops;
36 	res->threshold = threshold;
37 	res->strength = MIN(100,MAX(strength,0));
38 	res->hardness = MIN(100,MAX(hardness,25));
39 	res->refresh = progressive_refresh;
40 	res->interval = interval;
41 	res->old_algorithm = old_algorithm;
42 	res->gener_frames = FALSE;
43 
44 	return res;
45 }
46 
rain_erosion_struct_free(rain_erosion_struct * res)47 void rain_erosion_struct_free (rain_erosion_struct *res) {
48 	if (res)
49 		x_free(res);
50 }
51 
gravity_struct_new(gint steps,gint slope_threshold)52 gravity_struct *gravity_struct_new (gint steps, gint slope_threshold) {
53 	gravity_struct *ges;
54 	ges = (gravity_struct *) x_malloc(sizeof(gravity_struct), "gravity_struct");
55 	ges->steps = steps;
56 	ges->threshold = slope_threshold;
57 	return ges;
58 }
59 
gravity_struct_free(gravity_struct * ges)60 void gravity_struct_free (gravity_struct *ges){
61 	if (ges)
62 		x_free(ges);
63 }
64 
oriented_gravity_struct_new(gint steps,gint threshold,gint direction)65 oriented_gravity_struct *oriented_gravity_struct_new (gint steps, gint threshold, gint direction) {
66 	oriented_gravity_struct *ogs;
67 	ogs = (oriented_gravity_struct *) x_malloc(sizeof(oriented_gravity_struct), "oriented_gravity_struct");
68 	ogs->steps = steps;
69 	ogs->threshold = threshold;
70 	ogs->direction = direction;
71 	return ogs;
72 }
73 
oriented_gravity_struct_free(oriented_gravity_struct * ogs)74 void oriented_gravity_struct_free (oriented_gravity_struct *ogs) {
75 	if (ogs)
76 		x_free(ogs);
77 }
78 
whimsical_erosion_struct_new(gint radius,gint smooth_ribs,gboolean auto_contrast)79 whimsical_erosion_struct *whimsical_erosion_struct_new (gint radius, gint smooth_ribs, gboolean auto_contrast) {
80 	whimsical_erosion_struct *wes;
81 	wes = (whimsical_erosion_struct *) x_malloc(sizeof(whimsical_erosion_struct), "whimsical_erosion_struct");
82 	wes->radius = radius;
83 	wes->smooth_ribs = smooth_ribs;
84 	wes->auto_contrast = auto_contrast;
85 	return wes;
86 }
87 
whimsical_erosion_struct_free(whimsical_erosion_struct * wes)88 void whimsical_erosion_struct_free (whimsical_erosion_struct *wes){
89 	if (wes)
90 		x_free(wes);
91 }
92 
craters_erosion_struct_new(gint qty,gint display_interval,gint peak_threshold,gint slope_threshold)93 craters_erosion_struct *craters_erosion_struct_new (gint qty, gint display_interval, gint peak_threshold, gint slope_threshold) {
94 	craters_erosion_struct *ces;
95 	ces = (craters_erosion_struct *) x_malloc(sizeof(craters_erosion_struct), "craters_erosion_struct");
96 	ces->qty = qty;
97 	ces->display_interval = display_interval;
98 	ces->peak_threshold = peak_threshold;
99 	ces->slope_threshold = slope_threshold;
100 	ces->crater_str = crater_struct_new();
101 	return ces;
102 }
103 
craters_erosion_struct_free(craters_erosion_struct * ces)104 void craters_erosion_struct_free (craters_erosion_struct *ces) {
105 	if (!ces)
106 		return;
107 	if (ces->crater_str)
108 		crater_struct_free(ces->crater_str);
109 	x_free(ces);
110 }
111 
hf_eroded_ribs(hf_type * hf_in,hf_type * hf_out,gint max)112 void hf_eroded_ribs (hf_type *hf_in, hf_type *hf_out, gint max) {
113 //	Build a "ribbed" (eroded) template by taking the minimum
114 //	absolute value of the difference between each pixel and its neighborus
115 //	Neighbours are numbered from 1 to 8, clockwise, 1 being (1,0)
116 //	The default for this version of the program is to wrap
117 	static gint z1, z2, z3, z4, z5, z6, z7, z8;
118 	hf_type value;
119 	static gint x,y, i;
120 	for (y=0; y<max; y++)
121 		for (x=0; x<max; x++) {
122 			i = VECTORIZE(x,y,max);
123 			value = *(hf_in + i);
124 			z1 =  *(hf_in+VECTORIZE(WRAP2(x+1,max),y,max))  ;
125 			z2 = *(hf_in+VECTORIZE(WRAP2(x+1,max),
126 				WRAP2(y+1,max),max)) ;
127 			z3 = *(hf_in+VECTORIZE(x,WRAP2(y+1,max),max));
128 			z4 = *(hf_in+VECTORIZE(WRAP2(x-1,max),WRAP2(y+1,max),max));
129 			z5 =  *(hf_in+VECTORIZE(WRAP2(x-1,max),y,max)) ;
130 			z6 = *(hf_in+VECTORIZE(WRAP2(x-1,max),
131 				WRAP2(y-1,max),max)) ;
132 			z7 = *(hf_in+VECTORIZE(x,WRAP2(y-1,max),max)) ;
133 			z8 = *(hf_in+VECTORIZE(WRAP2(x+1,max),
134 				WRAP2(y-1,max),max)) ;
135 
136 //			Absolute minimum (negative of)
137 			z1 = ABS(z1-value);
138 			z2 = ABS(z2-value);
139 			z3 = ABS(z3-value);
140 			z4 = ABS(z4-value);
141 			z5 = ABS(z5-value);
142 			z6 = ABS(z6-value);
143 			z7 = ABS(z7-value);
144 			z8 = ABS(z8-value);
145 
146 			*(hf_out + i)  = ~ (hf_type) MIN(z1,MIN(z2,MIN(z3,MIN(z4,MIN(z5,MIN(z6,MIN(z7,z8))))))) ;
147 
148 // if (!(i%512)) {
149 // printf("*(hf_out+i): %d; z1: %d, z2: %d, z3: %d, z4: %d, z5: %d, z6: %d, z7: %d, z8: %d\n",*(hf_out+i), z1, z2, z3, z4, z5, z6, z7, z8);
150 // }
151 		}
152 }
153 
hf_oriented_relax(hf_struct_type * hf,gint steps,gint max_slope,gint direction)154 void hf_oriented_relax (hf_struct_type *hf, gint steps, gint max_slope,  gint direction) {
155 	// Oriented gravity relaxation (for wind functions)
156 
157 	gint v1, v2, i, slope, x, y, iprec, step;
158 
159 	// Direction is one of NORTH (ymax to 0), SOUTH (0 to ymax), WEST (xmax to 0), EAST (0 to xmax)
160 	// Note: spreading the values with a 3x3 kernel gives no significant visible difference
161 	slope = iget_absolute_slope(max_slope,hf->max_x);
162 	for (step=0; step<steps; step++) {
163 		for (y=0; y<hf->max_y; y++) {
164 			for (x=0; x<hf->max_x; x++) {
165 				switch (direction) {
166 					case NORTH: // For N and S, swap x & y
167 						i = VECTORIZE(x,hf->max_x-y-1,hf->max_x);
168 						iprec = VECTORIZE (x, WRAP2(hf->max_x-y,hf->max_x), hf->max_x);
169 						break;
170 					case SOUTH:
171 						i = VECTORIZE(x,y,hf->max_x);
172 						iprec = VECTORIZE ( x, WRAP2(y-1,hf->max_x), hf->max_x);
173 						break;
174 					case WEST:
175 						i = VECTORIZE(hf->max_x-x-1,y,hf->max_x);
176 						iprec = VECTORIZE ( WRAP2(hf->max_x-x,hf->max_x), y, hf->max_x);
177 						break;
178 					default: // East
179 						i = VECTORIZE(x,y,hf->max_x);
180 						iprec = VECTORIZE ( WRAP2(x-1,hf->max_x), y, hf->max_x);
181 				}
182 
183 				v1 = *(hf->hf_buf+iprec);
184 				v2 =  ((gint) *(hf->hf_buf+i)) + slope;
185 				if ( v1 > v2 ) {
186 
187 					*(hf->hf_buf+iprec) -= (v1-v2) /2;
188 					*(hf->hf_buf+i) += (v1-v2) / 2  ;
189 
190 				}
191 			}
192 		}
193 	}
194 }
195 
relax_hex(hf_type * hf,gint max_x,gint max_y,gint slope_threshold,gint wrap)196 gboolean relax_hex (hf_type *hf, gint max_x, gint max_y, gint slope_threshold, gint wrap) {
197 
198 //	Gravity relaxation, on an hexagonally sampled buffer
199 //	Variation over cresting, more natural-like (I hope!)
200 //	Written 2005-02 for sand / wind processes
201 //	hf: buffer to transform
202 //	x,y: pixel to relax
203 //	max_x, max_y: size of the buffer (so it could work with non-square buffers!)
204 //	slope_threshold: maximum allowed slope, in absolute HF units (not degrees!)
205 //	max_steps: don't do more than this number of steps
206 //		The function can stop before if all slopes are lowver than max_slope
207 //	even, shift_right: hexagonal sampling parameters (see comments in other functions)
208 //	Returns: TRUE is relaxation done, FALSE if no relaxation to do
209 //
210 //	2006-11-08 Modified for randomizing the hexagonal approximation
211 //
212 
213 	static gint v0[6] = {0,0,0,0,0,0};
214 	static gint x,y,v[6],z1, z2, z3, z4, z5, z6, i, ii, ninf, shift, sumdif, axis, even, xx, yy;
215 	long int value;
216 	gboolean test, found=FALSE;
217 
218 	// The beginning is the same as find_all_neighbours
219 	// Then we take all the neighbour pixels inferior to the threshold
220 	// We average the difference between these pixels and the threshold
221 	// Then the current pixel is decreased and the "soil" is evenly
222 	// spread on the selected pixels
223 
224 	even = TRUE;
225 	axis = H_AXIS;
226 	for (x=0; x<max_x; x++) {
227 		for (y=0; y<max_y; y++) {
228 			ninf = 0;
229 			sumdif = 0;
230 			// 2006-11-08: better results with even and axis fixed
231 			even = rand()%2;
232 			if (rand()%2)
233 				axis = V_AXIS;
234 			else
235 				axis = H_AXIS;
236 
237 			memcpy(v,v0,6*sizeof(gint));
238 			value = *(hf+VECTORIZE(x,y,max_x)) - slope_threshold ;
239 	//		test = y & (gint) 1; // test = TRUE if value is odd
240 	if (axis==H_AXIS)
241 		test = y & (gint) 1; // test = TRUE if value is odd
242 	else
243 		test = x & (gint) 1; // test = TRUE if value is odd
244 
245 			if ( (test && even) || ((!test) && (!even)) )  //  XOR
246 				shift = 1;
247 			else
248 				shift = 0;
249 
250 			if (axis==H_AXIS) {
251 				xx = x+1;
252 				yy = y;
253 			}
254 			else {
255 				xx = x;
256 				yy = y+1;
257 			}
258 			if (wrap)
259 				ii=VECTORIZE(WRAP2(xx,max_x),WRAP2(yy,max_y), max_x);
260 			else
261 				ii=VECTORIZE(MIN(xx,max_x-1),MIN(yy,max_y-1), max_x);
262 
263 			z1 =  *(hf+ii);
264 			if (z1<value) {
265 				if (wrap || ( (x+1)<max_x ) ) {
266 					v[ninf] = ii;
267 					ninf++;
268 					sumdif += value-z1;
269 				}
270 			}
271 
272 			if (axis==H_AXIS) {
273 				xx = x+shift;
274 				yy = y+1;
275 			}
276 			else {
277 				xx = x+1;
278 				yy = y+shift;
279 			}
280 
281 			if (wrap)
282 				ii=VECTORIZE(WRAP2(xx,max_x), WRAP2(yy,max_y),max_x) ;
283 			else
284 				ii=VECTORIZE(MIN(xx,max_x-1), MIN(yy,max_y-1),max_x) ;
285 
286 			z2 = *(hf+ii);
287 			if (z2<value) {
288 				if (wrap || (((x+shift)<max_x) && ((y+1)<max_y)) ) {
289 					v[ninf] = ii;
290 					ninf++;
291 					sumdif += value-z2;
292 				}
293 			}
294 
295 			if (axis==H_AXIS) {
296 				xx = x-1+shift;
297 				yy = y+1;
298 			}
299 			else {
300 				xx = x+1;
301 				yy = y-1+shift;
302 			}
303 
304 			if (wrap)
305 				ii =VECTORIZE( WRAP2(xx,max_x), WRAP2(yy,max_y), max_x) ;
306 			else
307 				ii = VECTORIZE(MAX(0,xx),MIN(MAX(0,yy),max_y-1),max_x) ;
308 
309 			z3 = *(hf+ii) ;
310 			if (z3<value) {
311 				if (wrap || (((x+shift)>0) && ((y+1)<max_y)) ) {
312 					v[ninf] = ii;
313 					ninf++;
314 					sumdif += value-z3;
315 				}
316 			}
317 
318 			if (axis==H_AXIS) {
319 				xx = x-1;
320 				yy = y;
321 			}
322 			else {
323 				xx = x;
324 				yy = y-1;
325 			}
326 
327 			if (wrap)
328 				ii=VECTORIZE(WRAP2(xx,max_x), WRAP2(yy,max_x) , max_x)  ;
329 			else
330 				ii=VECTORIZE(MAX(xx,0), MAX(yy,0), max_x)  ;
331 
332 			z4 = *(hf+ii);
333 			if (z4<value) {
334 				if (wrap || (x>0)) {
335 					v[ninf] = ii;
336 					ninf++;
337 					sumdif += value-z4;
338 				}
339 			}
340 
341 
342 			if (axis==H_AXIS) {
343 				xx = x-1+shift;
344 				yy = y-1;
345 			}
346 			else {
347 				xx = x-1;
348 				yy = y-1+shift;
349 			}
350 			if (wrap)
351 				ii=VECTORIZE(WRAP2(xx,max_x),
352 				 WRAP2(yy,max_x),max_x) ;
353 			else
354 				ii=VECTORIZE(MAX(xx,0), MAX(yy,0),max_x) ;
355 
356 			z5 =  *(hf+ii) ;
357 			if (z5<value) {
358 				if (wrap || ((y>0) && ((x+shift)>0)) ) {
359 					v[ninf] = ii;
360 					ninf++;
361 					sumdif += value-z5;
362 				}
363 			}
364 
365 			if (axis==H_AXIS) {
366 				xx = x+shift;
367 				yy = y-1;
368 			}
369 			else {
370 				xx = x-1;
371 				yy = y+shift;
372 			}
373 			if (wrap)
374 				ii=VECTORIZE(WRAP2(xx,max_x),WRAP2(yy,max_y),max_x) ;
375 			else
376 				ii=VECTORIZE(MIN(MAX(0,xx),max_x-1),MAX(yy,0),max_x) ;
377 
378 			z6 = *(hf+ii);
379 			if (z6<value) {
380 				if (wrap || ((y>0) && ((x+shift)<max_x)) ) {
381 					v[ninf] = ii;
382 					ninf++;
383 					sumdif += value-z6;
384 				}
385 			}
386 
387 			if (ninf)
388 				found = TRUE;
389 			else
390 				continue;
391 
392 // if (y==255)
393 // printf("(X,Y): (%d,%d); ninf: %d; sl_max: %d; value: %d; sumdif: %d; sd/ninf+1: %d; sd/ninf*ninf+1: %d\n",x,y,ninf,slope_threshold, value, sumdif, sumdif/(ninf+1), sumdif / (ninf*(ninf+1))  );
394 
395 			*(hf+VECTORIZE(x,y,max_x)) -= sumdif / (ninf+1);
396 
397 			sumdif = sumdif / (ninf*(ninf+1));
398 
399 			for (i=0; i<ninf; i++) {
400 				*(hf+v[i]) += sumdif;
401 			}
402 
403 
404 		} // Y loop
405 
406 	} // X loop
407 
408 	return found;
409 }
410 
hf_relax_hex(hf_struct_type * hf,gint max_steps,gint max_slope)411 void hf_relax_hex (hf_struct_type *hf, gint max_steps, gint max_slope) {
412 
413 //	Wrapper for relax_hex - gravity erosion
414 
415 	gint steps=0, slope;
416 
417 	slope = iget_absolute_slope(max_slope,hf->max_x);
418 
419 	for (steps=0; steps<max_steps; steps++) {
420 //	printf("******************** STEP %d **********************\n",steps);
421 		if (!relax_hex (hf->hf_buf, hf->max_x, hf->max_y, slope, (hf->if_tiles==NULL) ? TRUE : *hf->if_tiles))
422 			break;
423 	}
424 
425 //	printf("Steps: %d / %d\n",steps, max_steps);
426 
427 }
428 
find_all_neighbours_hex(gint x,gint y,gint * newx,gint * newy,gint max,hf_type * hf,gint threshold)429 gboolean find_all_neighbours_hex( gint x, gint y, gint *newx, gint *newy,
430 	gint max, hf_type *hf, gint threshold) {
431 	//	Find all the inferior neighbours of (x,y) in hf
432 	//	Randomly select one of the neighbours,
433 	//	given its height difference with the minimum is < to threshold
434 	//	Returns the result in newx and newy
435 	//	If (x,y) is a minimum, returns FALSE
436 	//	This version emulates an hexagonal symmetry (six neighbours)
437 	//	We need to know if even or odd rows have been shifted (even=TRUE)
438 	//	and if they have been shifted right or left
439 	//	Neighbours are counted clockwise from 1 to 6, 1 being (1,0)
440 	//	2, 3, 5 and 6 are being shifted on x, depending on "even"
441 	//
442 	//             5 | 6
443 	//           4 | 0 | 1
444 	//             3 | 2
445 	//
446 	// 2006.11.07: when axis is V_AXIS, assume that Y is shifted instead of X
447 	// Axis and even/ood shift are randomized, for some kind of antialiasing
448 	// This is a better replacement of the preceding simili-hexagonal sampling
449 	//
450 	static gint v[6],z1, z2, z3, z4, z5, z6, i, ii, nx, ny, ninf, ok, shift;
451 	long int value;
452 	long int lower= (long int) 0xFFFF;
453 	gint even, axis;
454 	gboolean test;
455 	ninf = 0;
456 	ok = 0;
457 	value = *(hf+VECTORIZE(x,y,max)) ;
458 	if (rand()%2)
459 		axis = V_AXIS;
460 	else
461 		axis = H_AXIS;
462 	even = rand()%2; // TRUE or FALSE
463 	if (axis==H_AXIS)
464 		test = y & (gint) 1; // test = TRUE if value is odd
465 	else
466 		test = x & (gint) 1; // test = TRUE if value is odd
467 	if ( (test && even) || ((!test) && (!even)) )  //  XOR
468 		shift = 1;
469 	else
470 		shift = 0;
471 
472 	if (axis==H_AXIS)
473 		ii=VECTORIZE(WRAP2(x+1,max),y,max);
474 	else
475 		ii=VECTORIZE(x,WRAP2(y+1,max),max);
476 	z1 =  *(hf+ii);
477 	if (z1<value) {
478 		v[ninf] = ii;
479 		ninf++;
480 	}
481 	lower = z1;
482 
483 	if (axis==H_AXIS) {
484 		nx = WRAP2(x+shift,max);
485 		ny = WRAP2(y+1,max);
486 	}
487 	else {
488 		nx = WRAP2(x+1,max);
489 		ny = WRAP2(y+shift,max);
490 	}
491 	ii=VECTORIZE(nx, ny,max) ;
492 	z2 = *(hf+ii);
493 	if (z2<value) {
494 		v[ninf] = ii;
495 		ninf++;
496 	}
497 	if (z2<z1)
498 		lower = z2;
499 
500 	if (axis==H_AXIS) {
501 		nx = WRAP2(x-1+shift,max);
502 		ny = WRAP2(y+1,max) ;
503 	}
504 	else {
505 		nx = WRAP2(x+1,max);
506 		ny = WRAP2(y-1+shift,max) ;
507 	}
508 	ii =VECTORIZE(nx,ny,max) ;
509 	z3 = *(hf+ii) ;
510 	if (z3<value) {
511 		v[ninf] = ii;
512 		ninf++;
513 	}
514 	if (z3<lower)
515 		lower = z3;
516 
517 
518 	if (axis==H_AXIS) {
519 		nx = WRAP2(x-1,max);
520 		ii = VECTORIZE(nx,y,max)  ;
521 	}
522 	else {
523 		ny = WRAP2(y-1,max);
524 		ii = VECTORIZE(x,ny,max)  ;
525 	}
526 	z4 = *(hf+ii);
527 	if (z4<value) {
528 		v[ninf] = ii;
529 		ninf++;
530 	}
531 	if (z4<lower)
532 		lower = z4;
533 
534 	if (axis==H_AXIS) {
535 		nx = WRAP2(x-1+shift,max) ;
536 		ny = WRAP2(y-1,max) ;
537 	}
538 	else {
539 		nx = WRAP2(x-1,max) ;
540 		ny = WRAP2(y-1+shift,max) ;
541 	}
542 	ii =VECTORIZE(nx,ny,max) ;
543 	z5 =  *(hf+ii) ;
544 	if (z5<value) {
545 		v[ninf] = ii;
546 		ninf++;
547 	}
548 	if (z5<lower)
549 		lower = z5;
550 
551 	if (axis==H_AXIS) {
552 		nx = WRAP2(x+shift,max);
553 		ny = WRAP2(y-1,max);
554 	}
555 	else {
556 		nx = WRAP2(x-1,max);
557 		ny = WRAP2(y+shift,max);
558 	}
559 	ii = VECTORIZE(nx, ny,max) ;
560 	z6 = *(hf+ii);
561 	if (z6<value) {
562 		v[ninf] = ii;
563 		ninf++;
564 	}
565 	if (z6<lower)
566 		lower = z6;
567 
568 // printf("(X,Y): (%d,%d); ninf: %d; lower: %u; threshold: %d; value: %d; ",x,y,ninf, lower, threshold, value);
569 	if ( (lower+threshold) < value) {
570 		// Find all the pixels not farther away than "threshold" than the lower one
571 		for (i=0; i<ninf; i++) {
572 			if ((*(hf+v[i])-threshold)<=lower) {
573 				v[ok] = v[i];
574 				ok ++;
575 			}
576 		}
577 // printf("ok: %d; ",ok);
578 		ii = v[rand()%ok];
579 // printf("ii: %d; ",ii);
580 		*newx = ii%max;
581 		*newy = (gint) (ii / max);
582 // printf("(NEWX,NEWY) = (%d,%d) = (%d,%d)\n", ii%max,(gint) ii/max,*newx,*newy);
583 		return TRUE;
584 	}
585 	else {
586 // printf("Returning FALSE\n");
587 		return FALSE;
588 	}
589 }
590 
gflow_add_part(hf_type remainder,hf_type from_value,gint tox,gint toy,hf_type * hf,gint max,gboolean wrap)591 void gflow_add_part(hf_type remainder, hf_type from_value, gint tox, gint toy, hf_type *hf, gint max, gboolean wrap) {
592 	//	Flow some part of the H difference between (x,y) and (tox,toy)
593 	//	from (x,y) to (tox,toy)
594 	//	Float (double) version
595 //	Define a 3x3 matrix - proportion of the flowing chunk to displace
596 	static gdouble matrix[3][3]={{1.0,2.0,1.0},{2.0,4.0,2.0},{1.0,2.0,1.0}};
597 	static gdouble msum = 16.0;
598 //	static gdouble matrix[3][3]={0.0,1.0,0.0,1.0,2.0,1.0,0.0,1.0,0.0};
599 //	static gdouble msum = 6.0;
600 //	static gdouble matrix[3][3]={1.0,1.0,1.0,1.0,4.0,1.0,1.0,1.0,1.0};
601 //	static gdouble msum = 12.0;
602 
603 	gint i, m, n, xi, yi, qtytot=0;
604 	gdouble qty, ratio;
605 	hf_type to_value;
606 
607 	if (!remainder)
608 		return;
609 
610 	ratio = remainder / msum;
611 
612 //	if (x==64)
613 //		printf("FROM_VALUE: %d; TO_VALUE: %d; qtytot: %d\n",from_value, *(hf+VECTORIZE(tox,toy,max)),qtytot);
614 	for (m=0; m<3; m++)
615 		for (n=0; n<3; n++) {
616 			if (wrap)
617 				i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
618 			else {
619 				xi = tox-1+n;
620 				yi = toy-1+m;
621 				if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
622 					continue;
623 				else
624 					i = VECTORIZE(xi,yi,max);
625 			}
626 			qty = ((gdouble) remainder) * matrix[m][n] * ratio;
627 			// Flow up to the point where the target value is equal to
628 			// the source value
629 			// Keep the remainder for the target center
630 			to_value = *(hf+i);
631 			if (from_value>to_value) {
632 				*(hf+i) = (hf_type) MIN(from_value,MAX(0,(gint) to_value + (gint) qty));
633 				qtytot -= (*(hf+i) - to_value);
634 			}
635 			else
636 				qtytot -= (gint) qty;
637 		}
638 
639 	if (qtytot>0) {
640 //		printf("SOLDE QTYTOT (%d, %d): %d; NCHUNK: %d\n",x,y,qtytot, nchunk);
641 		*(hf+VECTORIZE(tox,toy,max)) -= qtytot;
642 	}
643 
644 }
645 
flow(gint x,gint y,gint tox,gint toy,hf_type * hf,gint max,gint hardness,gint strength,gboolean wrap)646 void flow(gint x, gint y, gint tox, gint toy, hf_type *hf, gint max, gint hardness, gint strength, gboolean wrap) {
647 	//	Flow some part of the H difference between (x,y) and (tox,toy)
648 	//	from (x,y) to (tox,toy)
649 //	Define a 3x3 matrix - proportion of the flowing chunk to displace
650 //	static gint matrix[3][3]={1,1,1,1,4,1,1,1,1};
651 //	static gint matrix[3][3]={0,1,0,1,2,1,0,1,0};
652 	static gint matrix[3][3]={{1,2,1},{1,4,1},{1,2,1}};
653 	gint i, m, n, qty, xi, yi, qtytot=0;
654 	hf_type nchunk, to_value, from_value, value;
655 	gdouble ratio;
656 
657 	// nchunk == soil (delta) to move
658 	nchunk =  *(hf+VECTORIZE(x,y,max)) - *(hf+VECTORIZE(tox,toy,max));
659 //	nchunk = nchunk / 12;
660 	nchunk = ((hf_type) ((((gfloat) nchunk) * ((gfloat) strength)) / 100.0)) >> 4;
661 //	if (x==64)
662 //		printf("NCHUNK (%d,%d): %d\n",x,y,nchunk);
663 	ratio = ((gdouble) hardness) / 100.0;
664 	// Remove soil at (x,y)
665 	for (m=0; m<3; m++)
666 		for (n=0; n<3; n++) {
667 			if (wrap)
668 				i = VECTORIZE(WRAP2(x-1+n,max),WRAP2(y-1+m,max),max);
669 			else {
670 				xi = x-1+n;
671 				yi = y-1+m;
672 				if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
673 					continue;
674 				else
675 					i = VECTORIZE(xi,yi,max);
676 			}
677 			qty = nchunk * matrix[m][n];
678 			qtytot += qty;
679 			*(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) - qty));
680 		}
681 	// Add soil at (tox,toy)
682 	from_value = *(hf+VECTORIZE(x,y,max));
683 //	if (x==64)
684 //		printf("FROM_VALUE: %d; TO_VALUE: %d; qtytot: %d\n",from_value, *(hf+VECTORIZE(tox,toy,max)),qtytot);
685 	for (m=0; m<3; m++)
686 		for (n=0; n<3; n++) {
687 			if (wrap)
688 				i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
689 			else {
690 				xi = tox-1+n;
691 				yi = toy-1+m;
692 				if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
693 					continue;
694 				else
695 					i = VECTORIZE(xi,yi,max);
696 			}
697 			qty = nchunk * matrix[m][n];
698 			// Flow up to the point where the target value is equal to
699 			// the source value
700 			// Keep the remainder for the target center
701 			to_value = *(hf+i);
702 			if (from_value>to_value) {
703 				*(hf+i) = (hf_type) MIN(from_value,MAX(0,(gint) to_value + qty));
704 				qtytot -= (*(hf+i) - to_value);
705 			}
706 			else
707 				qtytot -= qty;
708 		}
709 
710 	if (qtytot>0) {
711 //		printf("SOLDE QTYTOT (%d, %d): %d; NCHUNK: %d\n",x,y,qtytot, nchunk);
712 		value = (hf_type) (((gdouble) qtytot) * ratio);
713 		*(hf+VECTORIZE(tox,toy,max)) -= value;
714 		gflow_add_part((hf_type) qtytot - value, from_value, tox, toy, hf, max, wrap);
715 	}
716 
717 }
718 
hf_rain_erosion_hex(hf_struct_type * hf,rain_erosion_struct * res,gpointer (* display_function)(gpointer),gpointer display_data)719 void hf_rain_erosion_hex (hf_struct_type *hf, rain_erosion_struct *res, gpointer (*display_function) (gpointer), gpointer display_data) {
720 //	Simple iterative erosion
721 //	using hexagonal sampling for a more natural looking result
722 //	We generate random drops and follow their path
723 //	We don't flow a drop when the slope is more than 2 power threshold
724 //	Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
725 //	Not extensively tested when the HF doesn't wrap
726 
727 	static gint x,y, ii, s, threshold, nextx, nexty, steps;
728 	gboolean tiling;
729 
730 //	threshold is the future chunk... it must be at least 16, because the center
731 //	of the 3x3 averaging matrix == 4 and we divide the chunk by 16 before applying it
732 //	threshold = 15 + (gint) pow(2.0,(double) thresh);
733 	threshold = MAX(16,iget_absolute_slope(res->threshold,hf->max_x));
734 // printf("RAIN: Threshold (slope): %d = %d\n",slope_threshold,threshold);
735 //	In the 1st version, drops were given as an exponent
736 //	We could fallback to this in the future...
737 //	drops = (long int) pow(2.0,(gdouble) dr_log);
738 	if (hf->if_tiles)
739 		tiling = *hf->if_tiles;
740 	else
741 		tiling = TRUE;
742 
743 	if (!hf->tmp_buf)
744 		hf_backup(hf);
745 // printf("RAIN EROSION, DROPS: %d; THRESHOLD: %d\n", drops, threshold);
746 	for (s=0; s<res->drops; s++) {
747 
748 		x = rand()%hf->max_x;
749 		y = rand()%hf->max_y;
750 		// Make the (x,y) drop flow until it encounters a minimum
751 		steps = 0;
752 // printf("********** DROP: %u; (x,y): (%d,%d)\n",s,x,y);
753 		while (find_all_neighbours_hex(x,y,&nextx,&nexty,
754 				hf->max_x,hf->hf_buf,threshold))	{
755 			if (!tiling)
756 				if ( (x==0) || (y==0) ||
757 					(x==(hf->max_x-1)) ||
758 					(y==(hf->max_y-1)) )
759 						break;
760 			flow(x,y,nextx,nexty,hf->hf_buf,hf->max_x, res->hardness, res->strength, tiling);
761 			ii = VECTORIZE(nextx,nexty,hf->max_x);
762 			y = nexty;
763 			x = nextx;
764 			steps++;
765 			if (steps>hf->max_x)
766 				break;
767 		}
768 		if (res->refresh && res->interval)
769 			if ((!(s%res->interval)) && display_function && display_data)
770 				(*display_function) (display_data);
771 	}
772 
773 }
774 
find_all_neighbours_hex_old(gint x,gint y,gint * newx,gint * newy,gint max,hf_type * hf,gint threshold,gboolean even,gboolean shift_right)775 gboolean find_all_neighbours_hex_old( gint x, gint y, gint *newx, gint *newy,
776 	gint max, hf_type *hf, gint threshold,
777 	gboolean even, gboolean shift_right) {
778 	//	Find all the inferior neighbours of (x,y) in hf
779 	//	Randomly select one of the neighbours,
780 	//	given its height difference with the minimum is < to threshold
781 	//	Returns the result in newx and newy
782 	//	If (x,y) is a minimum, returns FALSE
783 	//	This version works on an hexagonally samplec HF (six neighbours)
784 	//	We need to know if even or odd rows have been shifted (even=TRUE)
785 	//	and if they have been shifted right or left
786 	//	Neighbours are counted clockwise from 1 to 6, 1 being (1,0)
787 	//	2, 3, 5 and 6 are being shifted on x, depending on "even" and "shift_right"
788 	//
789 	//             5 | 6
790 	//           4 | 0 | 1
791 	//             3 | 2
792 	//
793 	static gint v[6],z1, z2, z3, z4, z5, z6, i, ii, nx, ny, ninf, ok, shift;
794 	long int value;
795 	long int lower= (long int) 0xFFFF;
796 	gboolean test;
797 	ninf = 0;
798 	ok = 0;
799 	value = *(hf+VECTORIZE(x,y,max)) ;
800 
801 	test = y & (gint) 1; // test = TRUE if value is odd
802 	if ( (test && even) || ((!test) && (!even)) )  //  XOR
803 		shift = 1;
804 	else
805 		shift = 0;
806 
807 	ii=VECTORIZE(WRAP2(x+1,max),y,max);
808 	z1 =  *(hf+ii);
809 	if (z1<value) {
810 		v[ninf] = ii;
811 		ninf++;
812 	}
813 	lower = z1;
814 
815 	nx = WRAP2(x+shift,max);
816 	ny = WRAP2(y+1,max);
817 	ii=VECTORIZE(nx, ny,max) ;
818 	z2 = *(hf+ii);
819 	if (z2<value) {
820 		v[ninf] = ii;
821 		ninf++;
822 	}
823 	if (z2<z1)
824 		lower = z2;
825 
826 	nx = WRAP2(x-1+shift,max);
827 	ny = WRAP2(y+1,max) ;
828 	ii =VECTORIZE(nx,ny,max) ;
829 	z3 = *(hf+ii) ;
830 	if (z3<value) {
831 		v[ninf] = ii;
832 		ninf++;
833 	}
834 	if (z3<lower)
835 		lower = z3;
836 
837 	nx = WRAP2(x-1,max);
838 	ii = VECTORIZE(nx,y,max)  ;
839 	z4 = *(hf+ii);
840 	if (z4<value) {
841 		v[ninf] = ii;
842 		ninf++;
843 	}
844 	if (z4<lower)
845 		lower = z4;
846 
847 	nx = WRAP2(x-1+shift,max) ;
848 	ny = WRAP2(y-1,max) ;
849 	ii =VECTORIZE(nx,ny,max) ;
850 	z5 =  *(hf+ii) ;
851 	if (z5<value) {
852 		v[ninf] = ii;
853 		ninf++;
854 	}
855 	if (z5<lower)
856 		lower = z5;
857 
858 	nx = WRAP2(x+shift,max);
859 	ny = WRAP2(y-1,max);
860 	ii = VECTORIZE(nx, ny,max) ;
861 	z6 = *(hf+ii);
862 	if (z6<value) {
863 		v[ninf] = ii;
864 		ninf++;
865 	}
866 	if (z6<lower)
867 		lower = z6;
868 
869 	if ( (lower+threshold) < value) {
870 		// Find all the pixels not farther away than "threshold" than the lower one
871 		for (i=0; i<ninf; i++) {
872 			if ((*(hf+v[i])-threshold)<=lower) {
873 				v[ok] = v[i];
874 				ok ++;
875 			}
876 		}
877 		ii = v[rand()%ok];
878 		*newx = ii%max;
879 		*newy = (gint) (ii / max);
880 		return TRUE;
881 	}
882 	else {
883 		return FALSE;
884 	}
885 }
886 
flow_old(gint x,gint y,gint tox,gint toy,hf_type * hf,gint max,gboolean wrap)887 void flow_old(gint x, gint y, gint tox, gint toy, hf_type *hf, gint max, gboolean wrap) {
888 	//	Flow a quarter of the H difference between (x,y) and (tox,toy)
889 	//	from (x,y) to (tox,toy)
890 //	Define a 3x3 matrix - proportion of the flowing chunk to displace
891 	static gint matrix[3][3]={ {1,2,1}, {2,4,2}, {1,2,1} };
892 	gint i, m, n, qty, xi, yi;
893 	hf_type nchunk;
894 
895 	nchunk = *(hf+VECTORIZE(x,y,max)) - *(hf+VECTORIZE(tox,toy,max));
896 	nchunk = nchunk >> 2;
897 //	nchunk = nchunk >> 4;
898 	// Remove soil at (x,y)
899 	for (m=0; m<3; m++)
900 		for (n=0; n<3; n++) {
901 			if (wrap)
902 				i = VECTORIZE(WRAP2(x-1+n,max),WRAP2(y-1+m,max),max);
903 			else {
904 				xi = x-1+n;
905 				yi = y-1+m;
906 				if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
907 					continue;
908 				else
909 					i = VECTORIZE(xi,yi,max);
910 			}
911 			qty = nchunk * matrix[m][n];
912 			*(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) - qty));
913 		}
914 	// Add soil at (tox,toy)
915 	for (m=0; m<3; m++)
916 		for (n=0; n<3; n++) {
917 			if (wrap)
918 				i = VECTORIZE(WRAP2(tox-1+n,max),WRAP2(toy-1+m,max),max);
919 			else {
920 				xi = tox-1+n;
921 				yi = toy-1+m;
922 				if ( (xi<0) || (yi<0) || (xi>=max) || (yi>=max) )
923 					continue;
924 				else
925 					i = VECTORIZE(xi,yi,max);
926 			}
927 			qty = nchunk * matrix[m][n];
928 			*(hf+i) = (hf_type) MIN(0xFFFF,MAX(0,(gint) *(hf+i) + qty));
929 		}
930 
931 }
932 
hf_rain_erosion_hex_old(hf_struct_type * hf,rain_erosion_struct * res,gpointer (* display_function)(gpointer),gpointer display_data)933 void hf_rain_erosion_hex_old (hf_struct_type *hf, rain_erosion_struct *res, gpointer (*display_function) (gpointer), gpointer display_data) {
934 //	Simple iterative erosion
935 //	using hexagonal sampling for a more natural looking result
936 //	We generate random drops and follow their path
937 //	We don't flow a drop when the slope is more than 2 power thresh
938 //	Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
939 //	Not extensively tested when the HF doesn't wrap
940 
941 	static gint x,y, ii, s, threshold, nextx, nexty;
942 	unsigned long int steps;
943 	hf_type *tmp;
944 	gboolean even=TRUE, tiling;
945 
946 //	threshold is the future chunk... it must be at least 16, because the center
947 //	of the 3x3 averaging matrix == 4 and we divide the chunk by 16 before applying it
948 //	threshold = 15 + (gint) pow(2.0,(double) thresh);
949 	threshold = MAX(16,iget_absolute_slope(res->threshold,hf->max_x));
950 // printf("RAIN: Threshold (slope): %d = %d\n",slope_threshold,threshold);
951 //	In the 1st version, drops were given as an exponent
952 //	We could fallback to this in the future...
953 //	drops = (long int) pow(2.0,(gdouble) dr_log);
954 
955 	if (hf->if_tiles)
956 		tiling = *hf->if_tiles;
957 	else
958 		tiling = TRUE;
959 
960 	if (!hf->tmp_buf)
961 		hf_backup(hf);
962 
963 	tmp = hf->hf_buf;
964 	hf->hf_buf = hexagonal_row_sampling (hf->hf_buf, hf->max_x, tiling, even, TRUE);
965 	x_free(tmp);
966 
967 	for (s=0; s<res->drops; s++) {
968 		x = rand()%hf->max_x;
969 		y = rand()%hf->max_y;
970 		// Make the (x,y) drop flow until it encounters a minimum
971 		steps = 0;
972 		while (find_all_neighbours_hex_old(x,y,&nextx,&nexty,
973 				hf->max_x,hf->hf_buf,res->threshold, TRUE, TRUE))	{
974 			if (!tiling)
975 				if ( (x==0) || (y==0) ||
976 					(x==(hf->max_x-1)) ||
977 					(y==(hf->max_y-1)) )
978 						break;
979 			flow_old(x,y,nextx,nexty,hf->hf_buf,hf->max_x, tiling);
980 			ii = VECTORIZE(nextx,nexty,hf->max_x);
981 			y = nexty;
982 			x = nextx;
983 			steps++;
984 			if (steps>hf->max_x)
985 				break;
986 		}
987 		if (res->refresh && res->interval)
988 			if ((!(s%res->interval)) && display_function && display_data)
989 				(*display_function) (display_data);
990 	}
991 	// Restore the rectangular sampled hf
992 	tmp = hf->hf_buf;
993 	hf->hf_buf = hexagonal_row_sampling (hf->hf_buf, hf->max_x, tiling, even, FALSE);
994 	x_free(tmp);
995 }
996 
hf_crests_erosion_hex(hf_struct_type * hf,gint steps,gint slope_threshold)997 void hf_crests_erosion_hex (hf_struct_type *hf, gint steps, gint slope_threshold) {
998 //	Simple iterative erosion, giving crested mountains
999 //	Hexagonally sampled version (see hf_rain_erosion_hex) 2005-02
1000 //	2006-02 Replaced by randomized axis / even / odd flow
1001 //	We find the minimum neighbour
1002 //	If its value is superior to the current pixel one,
1003 //	we add half the difference to the current pixel
1004 //	If the minimum neighbour is inferior, we subtract half the current pixel
1005 //	This is like if half the difference was "flowing" from or to the current pixel
1006 //	Neighbours are numbered from 1 to 6, clockwise, 1 being (1,0)
1007 //	2004-03-11 Corrected to deal with wrapping
1008 
1009 	static gint z1, z2, z3, z4, z5, z6, x, y, xx, yy;
1010 	static gint  i, s, val, ii, minii, lower, threshold, shift, axis;
1011 	hf_type value;
1012 	gboolean test, even, tiling;
1013 	gfloat ratio; // Factor for dividing the weight of the minimum pixel, when it is on the diagonals
1014 
1015 	// Slope_threshold is in degrees
1016 	threshold = iget_absolute_slope(slope_threshold,hf->max_x);
1017 // printf("Threshold (slope): %d = %d\n",slope_threshold,threshold);
1018 	if (!hf->tmp_buf)
1019 		hf_backup(hf);
1020 
1021 	if (hf->if_tiles)
1022 		tiling = *hf->if_tiles;
1023 	else
1024 		tiling = TRUE;
1025 
1026 	test = y & (gint) 1; // test = TRUE if value is odd
1027 	if ( (test && even) || ((!test) && (!even)) )  //  XOR
1028 		shift = 1;
1029 	else
1030 		shift = 0;
1031 
1032 	// We need a second temporary buffer for storing
1033 	// the result of each step
1034 	if (!hf->result_buf) {
1035 		hf->result_buf = (hf_type *)x_malloc(hf->max_x*hf->max_y*sizeof(hf_type), "hf_type (hf->result_buf in hf_crests_erosion_hex)");
1036 	}
1037 // printf("CRESTS EROSION, STEPS: %d; THRESHOLD: %d\n", steps, threshold);
1038 	memcpy(hf->result_buf, hf->tmp_buf, hf->max_x*hf->max_y*sizeof(hf_type));
1039 	for (s=0; s<steps; s++) {
1040 	for (y=0; y<hf->max_y; y++) {
1041 		for (x=0; x<hf->max_x; x++) {
1042 			even = rand()%2;
1043 
1044 			if (rand()%2)
1045 				axis = V_AXIS;
1046 			else
1047 				axis = H_AXIS;
1048 
1049 			i = VECTORIZE(x,y,hf->max_x);
1050 			value = *(hf->hf_buf + i);
1051 			if (axis==H_AXIS) {
1052 				xx = x+1;
1053 				yy = y;
1054 			}
1055 			else {
1056 				xx = x;
1057 				yy = y+1;
1058 			}
1059 			if (tiling)
1060 				ii=VECTORIZE(WRAP2(xx,hf->max_x),WRAP2(yy,hf->max_y), hf->max_x);
1061 			else
1062 				ii=VECTORIZE(MIN(xx,hf->max_x-1),MIN(yy,hf->max_y-1), hf->max_x);
1063 			z1 =  *(hf->hf_buf+ii);
1064 			minii = ii;
1065 			lower = z1;
1066 			ratio = 1.0;
1067 
1068 			if (axis==H_AXIS) {
1069 				xx = x+shift;
1070 				yy = y+1;
1071 			}
1072 			else {
1073 				xx = x+1;
1074 				yy = y+shift;
1075 			}
1076 
1077 			if (tiling)
1078 				ii=VECTORIZE(WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_y),hf->max_x) ;
1079 			else
1080 				ii=VECTORIZE(MIN(xx,hf->max_x-1), MIN(yy,hf->max_y-1),hf->max_x) ;
1081 			z2 = *(hf->hf_buf+ii);
1082 			if (z2<z1) {
1083 				minii = ii;
1084 				lower = z2;
1085 				ratio = 1.155;
1086 			}
1087 
1088 			if (axis==H_AXIS) {
1089 				xx = x-1+shift;
1090 				yy = y+1;
1091 			}
1092 			else {
1093 				xx = x+1;
1094 				yy = y-1+shift;
1095 			}
1096 
1097 			if (tiling)
1098 				ii =VECTORIZE( WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_y),hf->max_x) ;
1099 			else
1100 				ii = VECTORIZE(MIN(MAX(xx,0),hf->max_x-1),MAX(0,yy),hf->max_x) ;
1101 			z3 = *(hf->hf_buf+ii) ;
1102 			if (z3<lower) {
1103 				minii = ii;
1104 				lower = z3;
1105 				ratio = 1.155;
1106 			}
1107 
1108 			if (axis==H_AXIS) {
1109 				xx = x-1;
1110 				yy = y;
1111 			}
1112 			else {
1113 				xx = x;
1114 				yy = y-1;
1115 			}
1116 
1117 			if (tiling)
1118 				ii=VECTORIZE(WRAP2(xx,hf->max_x), WRAP2(yy,hf->max_x) , hf->max_x)  ;
1119 			else
1120 				ii=VECTORIZE(MAX(xx,0), MAX(yy,0), hf->max_x)  ;
1121 			z4 = *(hf->hf_buf+ii);
1122 			if (z4<lower) {
1123 				minii = ii;
1124 				lower = z4;
1125 				ratio = 1.0;
1126 			}
1127 
1128 			if (axis==H_AXIS) {
1129 				xx = x-1+shift;
1130 				yy = y-1;
1131 			}
1132 			else {
1133 				xx = x-1;
1134 				yy = y-1+shift;
1135 			}
1136 			if (tiling)
1137 				ii=VECTORIZE(WRAP2(xx,hf->max_x),
1138 				 WRAP2(yy,hf->max_x),hf->max_x) ;
1139 			else
1140 				ii=VECTORIZE(MAX(xx,0), MAX(yy,0) ,hf->max_x) ;
1141 			z5 =  *(hf->hf_buf+ii) ;
1142 			if (z5<lower) {
1143 				minii = ii;
1144 				lower = z5;
1145 				ratio = 1.155;
1146 			}
1147 
1148 			if (axis==H_AXIS) {
1149 				xx = x+shift;
1150 				yy = y-1;
1151 			}
1152 			else {
1153 				xx = x-1;
1154 				yy = y+shift;
1155 			}
1156 			if (tiling)
1157 				ii=VECTORIZE(WRAP2(xx,hf->max_x),WRAP2(yy,hf->max_y),hf->max_x) ;
1158 			else
1159 				ii=VECTORIZE(MIN(MAX(0,xx),hf->max_x-1),MAX(yy,0),hf->max_x) ;
1160 			z6 = *(hf->hf_buf+ii);
1161 			if (z6<lower) {
1162 				minii = ii;
1163 				lower = z6;
1164 				ratio = 1.155;
1165 			}
1166 
1167 			val = ( ( ((gint) *(hf->hf_buf+minii)) - (gint) value ) / 2);
1168 			if (threshold < ABS(val)) {
1169 				*(hf->result_buf+i) = value + (gint) ( ((gfloat) val) / ratio);
1170 //				*(hf->hf_buf+minii) -= (gint) ( ((gfloat) val) / ratio);
1171 			}
1172 			else
1173 				*(hf->result_buf+i) = value;
1174 		}
1175 	}
1176 	memcpy(hf->hf_buf, hf->result_buf, hf->max_x*hf->max_y*sizeof(hf_type));
1177 	}
1178 
1179 // printf("MAX: %d; MIN: %d; DELTA: %d\n",hf->max, hf->min, hf->max-hf->min);
1180 
1181 }
1182 
1183 
dfind_all_neighbours(gint x,gint y,gint * newx,gint * newy,gint max,gdouble * hf,gdouble threshold)1184 gboolean dfind_all_neighbours( gint x, gint y, gint *newx, gint *newy,
1185 	gint max, gdouble *hf, gdouble threshold) {
1186 	//	Find all the inferior neighbours of (x,y) in hf
1187 	//	Randomly select one of the neighbours,
1188 	//	given its height difference with the minimum is < to threshold
1189 	//	Returns the result in newx and newy
1190 	//	If (x,y) is a minimum, returns FALSE
1191 	static gint v[8], i, ii, nx, ny, ninf, ok;
1192 	gdouble value,z1, z2, z3, z4, z5, z6, z7, z8;
1193 	gdouble lower= (gdouble) MAX_HF_VALUE;
1194 	ninf = 0;
1195 	ok = 0;
1196 	value = *(hf+VECTORIZE(x,y,max)) ;
1197 	ii=VECTORIZE(WRAP2(x+1,max),y,max);
1198 	z1 =  *(hf+ii);
1199 	if (z1<value) {
1200 		v[ninf] = ii;
1201 		ninf++;
1202 	}
1203 	lower = z1;
1204 	nx = WRAP2(x+1,max);
1205 	ny = WRAP2(y+1,max);
1206 	ii=VECTORIZE(nx, ny,max) ;
1207 	z2 = *(hf+ii);
1208 	if (z2<value) {
1209 		v[ninf] = ii;
1210 		ninf++;
1211 	}
1212 	if (z2<z1)
1213 		lower = z2;
1214 	ny=WRAP2(y+1,max) ;
1215 	ii =VECTORIZE(x,ny,max) ;
1216 	z3 = *(hf+ii) ;
1217 	if (z3<value) {
1218 		v[ninf] = ii;
1219 		ninf++;
1220 	}
1221 	if (z3<lower)
1222 		lower = z3;
1223 	nx = WRAP2(x-1,max);
1224 	ny = WRAP2(y+1,max);
1225 	ii=VECTORIZE(nx,ny,max)  ;
1226 	z4 = *(hf+ii);
1227 	if (z4<value) {
1228 		v[ninf] = ii;
1229 		ninf++;
1230 	}
1231 	if (z4<lower)
1232 		lower = z4;
1233 	nx = WRAP2(x-1,max) ;
1234 	ii =VECTORIZE(nx,y,max) ;
1235 	z5 =  *(hf+ii) ;
1236 	if (z5<value) {
1237 		v[ninf] = ii;
1238 		ninf++;
1239 	}
1240 	if (z5<lower)
1241 		lower = z5;
1242 	nx = WRAP2(x-1,max);
1243 	ny = WRAP2(y-1,max);
1244 	ii=VECTORIZE(nx, ny,max) ;
1245 	z6 = *(hf+ii);
1246 	if (z6<value) {
1247 		v[ninf] = ii;
1248 		ninf++;
1249 	}
1250 	if (z6<lower)
1251 		lower = z6;
1252 	ny = WRAP2(y-1,max) ;
1253 	ii =VECTORIZE(x,ny,max) ;
1254 	z7 = *(hf+ii);
1255 	if (z7<value) {
1256 		v[ninf] = ii;
1257 		ninf++;
1258 	}
1259 	if (z7<lower)
1260 		lower = z7;
1261 	nx = WRAP2(x+1,max);
1262 	ny = WRAP2(y-1,max) ;
1263 	ii=VECTORIZE(nx,ny,max)  ;
1264 	z8 = *(hf+ii);
1265 	if (z8<value) {
1266 		v[ninf] = ii;
1267 		ninf++;
1268 	}
1269 	if (z8<lower)
1270 		lower = z8;
1271 
1272 // printf("(%d, %d) => LOWER: %5.2f; THRESHOLD: %5.2f; VALUE: %5.2f\n", x, y, lower, threshold, value);
1273 	if ( (lower+threshold) < value) {
1274 		// Find all the pixels not farther away than "threshold" than the lower one
1275 		for (i=0; i<ninf; i++) {
1276 			if ((*(hf+v[i])-threshold)<=lower) {
1277 				v[ok] = v[i];
1278 				ok ++;
1279 			}
1280 		}
1281 // printf("ok: %d; ",ok);
1282 		ii = v[rand()%ok];
1283 // printf("ii: %d; ",ii);
1284 		*newx = ii%max;
1285 		*newy = (gint) (ii / max);
1286 // printf("(NEWX,NEWY) = (%d,%d) = (%d,%d)\n", ii%max,(gint) ii/max,*newx,*newy);
1287 		return TRUE;
1288 	}
1289 	else {
1290 // printf("Returning FALSE\n");
1291 		return FALSE;
1292 	}
1293 }
dadd_rain(gdouble * water,gint max_x,gint max_y,gdouble * v,gint vlength)1294 void dadd_rain (gdouble *water, gint max_x, gint max_y, gdouble *v, gint vlength) {
1295 	gint x,y;
1296 	for (y=0; y<max_y; y++) {
1297 		for (x=0; x<max_x; x++) {
1298 			// Generate water
1299 			*(water+VECTORIZE(x,y,max_x)) += v[rand()%vlength];
1300 		}
1301 	}
1302 }
1303 /*
1304 static gdouble *build_map (gint soil_qty, gint radius) {
1305 
1306 	gdouble *map, sum, dval, ratio;
1307 	gint i,j,map_size;
1308 
1309 	map_size = (2*radius) + 1;
1310 	map = (gdouble *) x_malloc(map_size*map_size*sizeof(gdouble), "gdouble (map in build_map in erode.c");
1311 	sum = 0.0;
1312 	if (!radius)
1313 		sum = (gdouble) soil_qty;
1314 	else {
1315 		for (i=-radius; i<radius+1; i++) {
1316 			for (j=-radius; j<radius+1; j++) {
1317 				dval = BELLD(CONST_E,2.0,i,radius) *
1318 					BELLD(CONST_E,2.0,j,radius);
1319 				sum += dval;
1320 			}
1321 		}
1322 	}
1323 
1324 	ratio = ((gdouble) soil_qty) / sum;
1325 */
1326 /*
1327 	printf("SUM: %6.3f; RADIUS: %5d; ",sum, radius);
1328 	printf("SOIL_QTY: %5d ",soil_qty);
1329 	printf("RATIO: %6.3f\n", ratio);
1330 */
1331 //	printf("MAP %d x %d:\n", (2*radius) + 1, (2*radius) + 1);
1332 /*
1333 	for (i=-radius; i<radius+1; i++) {
1334 		for (j=-radius; j<radius+1; j++) {
1335 			*(map+VECTORIZE(i+radius,j+radius,map_size)) = ratio * BELLD(CONST_E,2.0,i,radius) * 		BELLD(CONST_E,2.0,j,radius);
1336 //			if (radius<4) printf("(%d, %d) == %5.2f;  ",i,j,*(map+VECTORIZE(i,j,map_size)) );
1337 		}
1338 //		if (radius<4) printf("\n");
1339 	}
1340 	return map;
1341 }
1342 */
1343 
dflow_map(gint x,gint y,gint tox,gint toy,gdouble * hf,gdouble * water,gint max,gboolean wrap)1344 void dflow_map(gint x, gint y, gint tox, gint toy, gdouble *hf, gdouble *water, gint max, gboolean wrap) {
1345 	// Flow a quarter of the water (part considered as soil in suspension)
1346 	// between (x,y) and (tox,toy) from (x,y) to (tox,toy)
1347 
1348 	gint fromi, toi, isoil, radius, map_size;
1349 
1350 	gdouble soil;
1351 	// gdouble *map;
1352 
1353 	// 1. Check if required map is already cached
1354 	// 2. Build it if not, add to the cache
1355 
1356 	fromi = VECTORIZE(x,y,max);
1357 	toi = VECTORIZE(tox,toy,max);
1358 
1359 	soil = *(water + fromi);
1360 
1361 // printf("FROM (%d, %d) TO (%d, %d); SOIL: %5.2f; \n", x, y, tox, toy, soil);
1362 	isoil = MIN(MAX_CACHE-1,(gint) soil);
1363 
1364 	if (!isoil)
1365 		return;
1366 
1367 	radius = (gint) log((gdouble) isoil);
1368 	map_size = 2*radius +1;
1369 /*
1370 	map = *(cache+isoil);
1371 
1372 	if (! map ) {
1373 		map = build_map (isoil, radius);
1374 		*(cache+isoil) = map;
1375 	}
1376 */
1377 //	if (map_size==1)
1378 		*(water+VECTORIZE(tox,toy,max)) += soil;
1379 //	else
1380 //		generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) water, GDOUBLE_ID, max, max, tox, toy, ADD, wrap, FALSE);
1381 /*
1382 
1383 	if (map_size==1) {
1384 		*(hf+VECTORIZE(x,y,max)) -= soil;
1385 		*(hf+VECTORIZE(tox,toy,max)) += soil;
1386 	}
1387 	else {
1388 		generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) hf, GDOUBLE_ID, max, max, x, y, SUBTRACT, wrap, FALSE);
1389 
1390 		generalized_merge ((gpointer) map, GDOUBLE_ID, map_size, map_size, (gpointer) hf, GDOUBLE_ID, max, max, tox, toy, ADD, wrap, FALSE);
1391 	}
1392 
1393 
1394 	// We flow all the water mass
1395 	*(water+toi) += *(water+fromi);
1396 	*(water+fromi) = 0.0;
1397 */
1398 }
1399 
check_water(gdouble * water,gint max)1400 void check_water (gdouble *water, gint max) {
1401 
1402 	gint i, count=0;
1403 	gdouble sum=0.0;
1404 
1405 	for (i=0; i<max*max; i++) {
1406 		if (*(water+i)>0.0) {
1407 			count ++;
1408 			sum += *(water+i);
1409 		}
1410 	}
1411 	printf("WATER PIX > 0: %d; SUM: %5.2f; AVRG: %5.2f\n",count, sum, sum / (gdouble) count);
1412 
1413 }
1414 
check_hf(gdouble * hf,gint max)1415 void check_hf (gdouble *hf, gint max) {
1416 
1417 	gint i, countneg=0, countoverflow=0;
1418 	gdouble sumo=0.0, sumn=0.0;
1419 
1420 	for (i=0; i<max*max; i++) {
1421 		if (*(hf+i)<1.0) {
1422 			countneg ++;
1423 			sumn += *(hf+i);
1424 		}
1425 		else
1426 		if (*(hf+i)>(gdouble)MAX_HF_VALUE) {
1427 			countoverflow ++;
1428 			sumo += *(hf+i) - (gdouble) MAX_HF_VALUE;
1429 		}
1430 
1431 
1432 	}
1433 	printf("HF < 1: %d; AVRG: %7.2f HF > MAX: %d; AVRG: %7.2f\n",countneg, sumn / (gdouble) countneg, countoverflow, sumo / (gdouble) countoverflow);
1434 
1435 }
1436 
hf_water_erosion(hf_struct_type * hf,gint steps,gint slope_threshold)1437 void hf_water_erosion (hf_struct_type *hf, gint steps, gint slope_threshold) {
1438 	// Water / fluvial erosion
1439 	// Simple model without speed and direction matrix
1440 	// Derivated from the rain erosion
1441 	// Basically, we add drops in a water matrix
1442 	// We never spread water explicitly
1443 	// Howvever, we spread soil with a gaussian matrix which size depends
1444 	// on the water weight
1445 	// Buffers:
1446 	//	input, output: height field converted to gdouble, 0 - 0xFFFF -> 0 - 1.0
1447 	//	water = water mass;
1448 	gdouble threshold;
1449 	gdouble *water,*input;
1450 	gint i,s,x,y, nextx, nexty;
1451 	gboolean tiling;
1452 	gdouble vpow2[15] = {1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 2.0, 4.0, 4.0 ,8.0};
1453 
1454 //	for (i=0; i<15; i++)
1455 //		vpow2[i] /= (gdouble) MAX_HF_VALUE;
1456 
1457 	if (hf->if_tiles)
1458 		tiling = *hf->if_tiles;
1459 	else
1460 		tiling = TRUE;
1461 
1462 	if (!if_cache_init) {
1463 //		printf("@@@@@@@@@@@@@@@@ Initializing CACHE @@@@@@@@@@@@@@@@\n");
1464 		cache = (gdouble **) x_malloc(MAX_CACHE*sizeof(gdouble *), "gdouble * (cache in hf_water_erosion)");
1465 		for (i=0; i<MAX_CACHE; i++) {
1466 			*(cache+i) = NULL;
1467 		}
1468 		if_cache_init = TRUE;
1469 	}
1470 
1471 	threshold = dget_absolute_slope(slope_threshold,hf->max_x);
1472 
1473 	input = xalloc_double_hf(hf->max_x, "gdouble (input in hf_water_erosion");
1474 	water = xcalloc_double_hf(hf->max_x, "gdouble (water in hf_water_erosion");
1475 
1476 	hf_type_to_double (hf->hf_buf, hf->max_x, hf->max_y, input);
1477 
1478 	// For each step, for each pixel:
1479 	//	1. Add rain drops to the current water mass
1480 	//		Choice at random
1481 	//		water mass = power of 2, from 0 to 3), small chunks more frequent
1482 	//	2. Flow the water mass with a simple rule, like we do with rain
1483 	//		Modify the water matrix
1484 	//		Add / subtract the soil from input to output
1485 
1486 	for (s=0; s<steps; s++) {
1487 		printf("STEP : %d / %d\n",s, steps);
1488 		dadd_rain (water, hf->max_x, hf->max_y, vpow2, 15);
1489 
1490 		for (y=0; y<hf->max_y; y++) {
1491 			for (x=0; x<hf->max_x; x++) {
1492 				i = VECTORIZE(x,y,hf->max_x);
1493 
1494 				if (dfind_all_neighbours(x,y,&nextx,&nexty,
1495 						hf->max_x,input,threshold))	{
1496 					if (!tiling)
1497 						if ( (x==0) || (y==0) ||
1498 							(x==(hf->max_x-1)) ||
1499 							(y==(hf->max_y-1)) )
1500 								break;
1501 //					printf("Flowing from (%d, %d) to (%d, %d)\n",x,y,nextx,nexty);
1502 					dflow_map(x,y,nextx,nexty,input,water,hf->max_x, tiling);
1503 				}
1504 			}
1505 		}
1506 		for (i=0; i<hf->max_x*hf->max_y; i++)
1507 			*(input+i) = *(water+i) + *(input+i);
1508 //		check_water (water, hf->max_x);
1509 //		check_hf (input, hf->max_x);
1510 	}
1511 
1512 	double_clamp (hf->hf_buf, hf->max_x, hf->max_y, 0, MAX_HF_VALUE, water);
1513 //	double_clamp (hf->hf_buf, hf->max_x, hf->max_y, 0, MAX_HF_VALUE, input);
1514 
1515 	x_free(input);
1516 	x_free(water);
1517 }
1518