├── .project ├── Imakefile ├── Makefile.alt ├── NEWS ├── README ├── X_graphics.c ├── Xgrab.c ├── artist.c ├── calcalt.c ├── copyright.h ├── crinkle.h ├── docs ├── about_xmountains.html ├── cone.gif ├── crease.gif ├── cushion.gif ├── google4108777847be7f63.html ├── index.html ├── normal.gif └── quilt.gif ├── global.c ├── global.h ├── mountainbench.c ├── paint.h ├── patchlevel.h ├── print_alg.c ├── random.c ├── vroot.h ├── xmountains.c ├── xmountains.desktop ├── xmountains.fr.man └── xmountains.man /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | xmountains 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Imakefile: -------------------------------------------------------------------------------- 1 | LOCAL_LIBRARIES = -lX11 2 | SYS_LIBRARIES = -lm 3 | SRCS = calcalt.c random.c artist.c xmountains.c X_graphics.c print_alg.c 4 | OBJS = calcalt.o random.o artist.o xmountains.o X_graphics.o print_alg.o 5 | HDRS = crinkle.h paint.h patchlevel.h copyright.h vroot.h 6 | SHARS = README $(SRCS) $(HDRS) Imakefile xmountains.man Makefile.alt 7 | ComplexProgramTarget(xmountains) 8 | 9 | 10 | xmountains.shar: $(SHARS) 11 | shar -o xmountains.shar README $(HDRS) Imakefile xmountains.man $(SRCS) 12 | 13 | xmountains.tar: $(SHARS) 14 | tar cvf xmountains.tar $(SHARS) 15 | 16 | -------------------------------------------------------------------------------- /Makefile.alt: -------------------------------------------------------------------------------- 1 | # 2 | # Generic makefile for xmountins. You will have to add the locations 3 | # of your X include files and libraries to the appropriate macros 4 | # 5 | CC=cc 6 | CFLAGS=-I/usr/iclude/X11 7 | LDFLAGS=-L/usr/lib/X11 8 | 9 | LOCAL_LIBRARIES = -lX11 10 | SYS_LIBRARIES = -lm 11 | SRCS = calcalt.c random.c artist.c global.c xmountains.c X_graphics.c print_alg.c 12 | OBJS = calcalt.o random.o artist.o global.o xmountains.o X_graphics.o print_alg.o 13 | HDRS = crinkle.h global.h paint.h patchlevel.h copyright.h 14 | 15 | xmountains: $(OBJS) 16 | $(CC) $(LDFLAGS) -o xmountains $(OBJS) -lX11 -lm 17 | 18 | 19 | calcalt.o: crinkle.h 20 | artist.o: global.h paint.h crinkle.h 21 | global.o: crinkle.h paint.h 22 | xmountains.o: paint.h global.h patchlevel.h copyright.h crinkle.h 23 | X_graphics.o: paint.h crinkle.h 24 | 25 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | CHANGES from V2.1 2 | Added a -n flag to set the number of colours. This changes the same 3 | parameter as -B but you request total number of colours. 4 | 5 | CHANGES from V1.4 6 | The fractal generation code has been reworked. There algorithm has been 7 | extended significantly and should be able to generate much better 8 | looking surfaces. There may be a performance hit for some options though. 9 | 10 | CHANGES from V1.3 11 | 1) There is now a flag to control the horizontal light angle. 12 | 2) negative values of the scroll parameter make the image scroll in the 13 | opposite direction. 14 | 3) water reflections have been implemented. 15 | 16 | CHANGES from V1.2 17 | 1) program now sleeps after a scroll rather than once per column. 18 | 2) added a -B flag to control the number of colours needed. 19 | 3) added a -q flag that clears the root window when the program exits. 20 | 4) fixed memory leak when in `map' mode. 21 | 22 | CHANGES from V1.1 23 | Several changes including: 24 | 1) There is now a secondary (vertical) light source to add some detail to 25 | the shadows. 26 | 2) There is a -Z flag to reduce the CPU load, once the initial screen has 27 | been generated the program will call sleep once for each column of 28 | pixels. 29 | 3) Xmountains creates a pixmap containing the current state of the image. 30 | This is now installed as the background pixmap of the window. This means 31 | that root-window images will remain in place if the program is stopped. 32 | The -E flag disables this feature and explicitly traps expose events 33 | instead. There may be some delay in repainting the window if both the -E 34 | and -Z flags are used at the same time. 35 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Xmountains is a X11 based fractal landscape generator. It generates random 2 | fractal surfaces and displays them in a window. While the program is running 3 | the fractal is continuously extended on the right and the image is scrolled 4 | from right to left to expose the newly generated area. 5 | 6 | This is a very old piece of code but the algorithms 7 | https://spbooth.github.io/xmountains/about_xmountains.html 8 | are still quite interesting 9 | 10 | This distribution contains an Imakefile. If your X-window software has been 11 | correctly installed a Makefile appropriate to your system can be generated 12 | from this using the command "xmkmf". Once this has been done the program is 13 | compiled with the command "make". 14 | 15 | == Commandline options == 16 | 17 | ./xmountains: version 2.9 18 | usage: ./xmountains -[bqgdPEmMrBZIASFTCapcevfRltxsXYH] 19 | -b [false] use root window 20 | -q [false] reset root window on exit 21 | -g string window geometry 22 | -d string display 23 | -P filename write PID to file 24 | -E [false] toggle explicit expose events 25 | -m [false] print map 26 | -M [false] disable reflections 27 | -r int [20] # columns before scrolling 28 | -B int [80] # shades in a colour band 29 | -n int [245] # number of colours 30 | -Z int [10] time to sleep before scrolling 31 | -I float [40.000000] vertical angle of light 32 | -A float [0.000000] horizontal angle of light 33 | -S float [0.600000] vertical stretch 34 | -T float [0.500000] vertical shift 35 | -W float [0.000000] sealevel 36 | -F int [1] reduce variation in the foreground 37 | -G float [-1.000000] average foreground height 38 | -C float [0.300000] contour parameter 39 | -a float [2.500000] altitude of viewpoint 40 | -p float [4.000000] distance of viewpoint 41 | -c float [1.000000] contrast 42 | -e float [0.300000] ambient light level 43 | -v float [0.600000] vertical light level 44 | Fractal options: 45 | -f float [0.650000] fractal dimension 46 | -R int [0] rng seed, read clock if 0 47 | -l int [10] # levels of recursion 48 | -t int [2] # non fractal iterations 49 | -x [true] cross update 50 | -s [1] smoothing (0-7) 51 | -X float [0.000000] fraction of old value for rg2 & rg3 52 | -Y float [0.000000] fraction of old value for rg1 53 | -H print short description of algorithm. 54 | 55 | This program works best on a colour display. It will work on monochrome 56 | displays but the default parameter values are not optimal for this. 57 | 58 | The program breaks down into three sections 59 | 1) Fractal generation (calcalt.c random.c crinkle.h) This code should be fairly 60 | solid, It also contains some algorithmic tricks I had to invent (though it 61 | is not inconceivable that somebody else has also thought of them) 62 | 2) Image rendering & main program (artist.c global.c scroll.c global.h paint.h) 63 | This code is a bit more sloppy but seems to work OK. 64 | 3) The X interface (X_graphics.c) The X interface was retro-fitted to an earlier 65 | version of the program that was designed to use memory mapped video hardware. 66 | As a result this code is a little crude. A more experienced X hacker could 67 | do better but ... 68 | 69 | == PROBLEMS == 70 | * All parameters are set on the command line. 71 | * The choice of colours looks strange on some hardware. 72 | * The program will not work with Xscreensaver or virtual window managers. This 73 | can be fixed by including vroot.h in X_graphics.c (define VROOT to cpp to do 74 | this) but I was a little wary of putting this in by default. 75 | 76 | == Contact == 77 | If you have any comments/fixes etc for this program, 78 | Email me at: S.Booth@epcc.ed.ac.uk or send pull request. 79 | 80 | Copyright 1994 Stephen Booth, see copyright.h 81 | 82 | -------------------------------------------------------------------------------- /X_graphics.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | # define VROOT /* always do this */ 7 | #ifdef VROOT 8 | #include"vroot.h" 9 | #endif 10 | #include "paint.h" 11 | char X_graphics_Id[]="$Id: X_graphics.c,v 1.26 2009/08/28 09:09:17 spb Exp $"; 12 | 13 | char *display=NULL; /* name of display to open, NULL for default */ 14 | char *geom=NULL; /* geometry of window, NULL for default */ 15 | 16 | Atom wm_protocols; 17 | Atom wm_delete_window; 18 | 19 | #ifndef FALSE 20 | #define TRUE 1 21 | #define FALSE 0 22 | #endif 23 | 24 | int quit_xmount=FALSE; 25 | Display *dpy; 26 | int screen; 27 | unsigned int graph_width; 28 | unsigned int graph_height; 29 | Window parent, win, root; 30 | int use_root=FALSE; 31 | int do_clear=FALSE; 32 | int pixmap_installed=FALSE; 33 | 34 | int swosh=FALSE; 35 | 36 | /* plot history */ 37 | int plot_x, plot_y1, plot_y2; 38 | unsigned long plot_col; 39 | int plot_saved=FALSE; 40 | 41 | #include 42 | 43 | Pixmap stip; 44 | unsigned int depth=0; 45 | GC gc; 46 | Pixmap pix; 47 | Pixmap bg_pix; 48 | Colormap map, defaultmap; 49 | XColor *table=NULL; 50 | void zap_events(); 51 | void finish_graphics(); 52 | 53 | Graph g={ 54 | 1024, 55 | 768, 56 | 0, 57 | 0, 58 | 0.3, 59 | 1.0, 60 | 0.3, 61 | 0.6, 62 | 2.5, 63 | 4.0, 64 | (40.0 * PI)/180.0, 65 | 0.0, 66 | 0.5, 67 | 0.0, 68 | 0.6, 69 | DEF_COL, 70 | 60, 71 | 10, 72 | 2, 73 | FALSE, 74 | TRUE, 75 | 20, 76 | 0, 77 | 0 78 | }; 79 | 80 | void finish_artist(); 81 | 82 | /*{{{void zap_events(int snooze)*/ 83 | void zap_events(snooze) 84 | int snooze; 85 | { 86 | XEvent event; 87 | XExposeEvent *expose = (XExposeEvent *)&event; 88 | int exw, exh; 89 | 90 | while( XPending(dpy) ){ 91 | XNextEvent(dpy, &event); 92 | switch(event.type) { 93 | case ClientMessage: 94 | if (event.xclient.message_type == wm_protocols && 95 | event.xclient.data.l[0] == wm_delete_window) { 96 | quit_xmount=TRUE; 97 | } 98 | break; 99 | case ButtonPress: 100 | break; 101 | case ButtonRelease: 102 | quit_xmount=TRUE; 103 | break; 104 | case Expose: 105 | if( (expose->x < graph_width) && (expose->y < graph_height)) 106 | { 107 | if( (expose->x + expose->width) > graph_width) 108 | { 109 | exw=graph_width - expose->x; 110 | }else{ 111 | exw = expose->width; 112 | } 113 | if( (expose->y + expose->height) > graph_height) 114 | { 115 | exh=graph_height - expose->y; 116 | }else{ 117 | exh = expose->height; 118 | } 119 | if(g.repeat < 0) 120 | { 121 | XCopyArea(dpy, pix, win, gc, expose->x - g.repeat, expose->y, 122 | exw, exh, 123 | expose->x,expose->y); 124 | } 125 | else 126 | { 127 | XCopyArea(dpy,pix,win,gc,expose->x,expose->y, 128 | exw,exh, 129 | expose->x,expose->y); 130 | } 131 | } 132 | break; 133 | default: 134 | fprintf(stderr,"xmountains: unrecognized event %d\n",event.type); 135 | /* XCloseDisplay(dpy); 136 | * exit(1); 137 | */ 138 | break; 139 | } 140 | } 141 | if( quit_xmount ) 142 | { 143 | finish_graphics(); 144 | finish_artist(); 145 | exit(0); 146 | } 147 | } 148 | /*}}}*/ 149 | 150 | /*{{{void finish_graphics()*/ 151 | void finish_graphics() 152 | { 153 | unsigned long attmask; 154 | XSetWindowAttributes attributes; 155 | int x,y; 156 | unsigned int border; 157 | int count; 158 | 159 | XFreePixmap(dpy,pix); 160 | XFreeGC(dpy,gc); 161 | XFreePixmap(dpy,stip); 162 | 163 | /* reset things if this was the root window. */ 164 | if( use_root ) 165 | { 166 | if( pixmap_installed && do_clear ) 167 | { 168 | /* restore default pixmap for the root window */ 169 | XSetWindowBackgroundPixmap(dpy,win,ParentRelative); 170 | XClearWindow(dpy,win); 171 | }else{ 172 | XGetGeometry(dpy,win,&root,&x,&y,&graph_width,&graph_height,&border,&depth); 173 | XClearArea(dpy,win,0,0,graph_width,graph_height,FALSE); 174 | } 175 | if( map != defaultmap ) 176 | { 177 | attmask = 0; 178 | attmask |= CWColormap; 179 | attributes.colormap = defaultmap; 180 | XChangeWindowAttributes(dpy,win,attmask,&attributes); 181 | } 182 | } 183 | if( map != defaultmap ) 184 | { 185 | XFreeColormap(dpy, map ); 186 | } 187 | if((count = XPending(dpy))) 188 | { 189 | fprintf(stderr,"WARNING: %d events still pending\n",count); 190 | } 191 | XCloseDisplay(dpy); 192 | } 193 | /*}}}*/ 194 | 195 | /*{{{void blank_region(lx,ly,ux,uy)*/ 196 | void blank_region(lx,ly,ux,uy) 197 | int lx,ly,ux,uy; 198 | { 199 | if( depth < 4 ) 200 | { 201 | /* use a textured gray sky on monochrome displays 202 | * we may need this on any low-depth display 203 | */ 204 | XSetForeground(dpy,gc,WhitePixel(dpy,screen)); 205 | XSetFillStyle(dpy,gc,FillOpaqueStippled); 206 | XFillRectangle(dpy,pix,gc,lx,ly,ux,uy); 207 | XSetFillStyle(dpy,gc,FillSolid); 208 | }else{ 209 | XSetForeground(dpy,gc,table[SKY].pixel); 210 | XFillRectangle(dpy,pix,gc,lx,ly,ux,uy); 211 | } 212 | } 213 | /*}}}*/ 214 | 215 | /*{{{void blank_col( pos )*/ 216 | void blank_col( pos ) 217 | int pos; 218 | { 219 | blank_region(pos,0,pos,graph_height); 220 | } 221 | /*}}}*/ 222 | 223 | /*{{{void init_graphics( ... )*/ 224 | void init_graphics( want_use_root, use_window, use_background, want_clear,gptr,red,green,blue ) 225 | 226 | int want_use_root; /* display on the root window */ 227 | Window use_window; /* display on external window */ 228 | int use_background; /* install the pixmap as the background-pixmap */ 229 | int want_clear; 230 | Graph *gptr; 231 | 232 | Gun *red; 233 | Gun *green; 234 | Gun *blue; 235 | { 236 | /*{{{defs*/ 237 | Visual *vis; 238 | 239 | 240 | int x=0; 241 | int y=0; 242 | int gbits=0; 243 | unsigned long attmask; 244 | XSetWindowAttributes attributes; 245 | char * winname="Xmountains"; 246 | XTextProperty textprop; 247 | 248 | unsigned int border; 249 | unsigned long gcvmask; 250 | XGCValues gcv; 251 | XWindowAttributes xgwa; 252 | 253 | int i; 254 | int newmap=FALSE; 255 | 256 | /*}}}*/ 257 | 258 | if (use_window) use_root = 0; 259 | 260 | do_clear = want_clear; 261 | use_root = want_use_root; 262 | pixmap_installed = use_background; 263 | graph_width = gptr->graph_width; 264 | graph_height = gptr->graph_height; 265 | /*{{{open display*/ 266 | 267 | dpy = XOpenDisplay(display); 268 | 269 | if( ! dpy ) 270 | { 271 | fprintf(stderr,"failed to open display\n"); 272 | exit(1); 273 | } 274 | screen = DefaultScreen(dpy); 275 | parent = (use_window ? use_window : RootWindow(dpy, screen)); 276 | /*}}}*/ 277 | /*{{{find appropriate vis*/ 278 | /* map=defaultmap=DefaultColormap(dpy,screen); */ 279 | XGetWindowAttributes (dpy, parent, &xgwa); 280 | map=defaultmap=xgwa.colormap; 281 | vis = DefaultVisual(dpy,screen); 282 | depth = DefaultDepth(dpy,screen); 283 | /*}}}*/ 284 | /*{{{set colormap*/ 285 | table = (XColor *)malloc(gptr->n_col * sizeof(XColor)); 286 | if( NULL == table ) 287 | { 288 | fprintf(stderr,"malloc failed for colour table\n"); 289 | exit(1); 290 | } 291 | for(i = 0; i < gptr->n_col; i++) 292 | { 293 | table[i].red = red[i]; 294 | table[i].green = green[i]; 295 | table[i].blue = blue[i]; 296 | while( ! XAllocColor(dpy,map,table+i) ) 297 | { 298 | if( newmap ){ 299 | fprintf(stderr,"failed to allocate colour %d\n",i); 300 | XCloseDisplay(dpy); 301 | exit(1); 302 | }else{ 303 | map = XCopyColormapAndFree(dpy,map); 304 | newmap=TRUE; 305 | } 306 | } 307 | } 308 | /*}}}*/ 309 | /*{{{create window*/ 310 | attmask = 0; 311 | if( use_root || use_window ) 312 | { 313 | win = (use_window ? use_window : parent); 314 | if( ! use_background ) 315 | { 316 | attmask |= CWEventMask; 317 | attributes.event_mask = ExposureMask; /* catch expose events */ 318 | } 319 | attmask |= CWColormap; 320 | attributes.colormap = map; 321 | XChangeWindowAttributes(dpy,win,attmask,&attributes); 322 | }else{ 323 | if( geom ) 324 | { 325 | gbits =XParseGeometry(geom,&x,&y,&graph_width,&graph_height); 326 | if((gbits & XValue) && (gbits & XNegative)) 327 | { 328 | x += DisplayWidth(dpy,screen) - graph_width; 329 | } 330 | if((gbits & YValue) && (gbits & YNegative)) 331 | { 332 | y += DisplayHeight(dpy,screen) - graph_height; 333 | } 334 | } 335 | attmask |= CWEventMask; 336 | if( ! use_background ) 337 | { 338 | attributes.event_mask = ButtonPressMask|ButtonReleaseMask|ExposureMask; 339 | }else{ 340 | attributes.event_mask = ButtonPressMask|ButtonReleaseMask; 341 | } 342 | attmask |= CWBackPixel; 343 | attributes.background_pixel = BlackPixel(dpy,screen); 344 | attmask |= CWBackingStore; 345 | attributes.backing_store = NotUseful; 346 | attmask |= CWColormap; 347 | attributes.colormap = map; 348 | win = XCreateWindow(dpy,parent,x,y,graph_width,graph_height,0, 349 | depth,InputOutput,vis,attmask,&attributes); 350 | 351 | /* Setup for ICCCM delete window. */ 352 | wm_protocols = XInternAtom(dpy, "WM_PROTOCOLS", False); 353 | wm_delete_window = XInternAtom(dpy, "WM_DELETE_WINDOW", False); 354 | (void) XSetWMProtocols (dpy, win, &wm_delete_window, 1); 355 | textprop.value = (unsigned char *) winname; 356 | textprop.encoding = XA_STRING; 357 | textprop.format = 8; 358 | textprop.nitems = strlen(winname); 359 | XSetWMName(dpy,win,&textprop); 360 | } 361 | /*}}}*/ 362 | /*{{{create pixmap*/ 363 | XGetGeometry(dpy,win,&root,&x,&y,&graph_width,&graph_height,&border,&depth); 364 | stip = XCreateBitmapFromData(dpy,win,gray_bits,gray_width,gray_height); 365 | 366 | gcvmask = 0; 367 | gcvmask |= GCForeground; 368 | gcv.foreground = WhitePixel(dpy,screen); 369 | gcvmask |= GCBackground; 370 | gcv.background = BlackPixel(dpy,screen); 371 | gcvmask |= GCGraphicsExposures; 372 | gcv.graphics_exposures = FALSE; 373 | gcvmask |= GCStipple; 374 | gcv.stipple = stip; 375 | gcvmask |= GCFillStyle; 376 | gcv.fill_style = FillSolid; 377 | gcv.graphics_exposures = FALSE; 378 | 379 | gc = XCreateGC(dpy,win,gcvmask,&gcv); 380 | 381 | /* if we are going to install this as a root pixmap, throw away 382 | * the old one FIRST. this reduces fragmentation 383 | */ 384 | if( use_background && (use_root || use_window)) 385 | { 386 | XSetWindowBackgroundPixmap(dpy,win,None); 387 | } 388 | if( use_root ) 389 | { 390 | /* in case of virtual window manager set to size of display */ 391 | /* This is bogus -- always obey the size of the window itself */ 392 | /* graph_width = DisplayWidth(dpy,screen); */ 393 | /* graph_height = DisplayHeight(dpy,screen); */ 394 | } 395 | 396 | if(swosh) 397 | { 398 | if(gptr->repeat < 0) 399 | { 400 | gptr->pixmap_width = graph_width - gptr->repeat; 401 | bg_pix = XCreatePixmap(dpy, win, graph_width, graph_height, depth); 402 | } 403 | else 404 | { 405 | if(gptr->repeat == 0) 406 | { 407 | gptr->repeat = graph_width; 408 | } 409 | gptr->pixmap_width = graph_width + gptr->repeat; 410 | } 411 | } 412 | else 413 | { 414 | gptr->pixmap_width = graph_width; 415 | } 416 | pix = XCreatePixmap(dpy, win, gptr->pixmap_width, graph_height, depth); 417 | 418 | /*}}}*/ 419 | blank_region(0, 0, gptr->pixmap_width, graph_height); 420 | 421 | if( use_background ) 422 | { 423 | XSetWindowBackgroundPixmap(dpy,win,pix); 424 | } 425 | if( ! use_root ) 426 | { 427 | XMapWindow(dpy, win ); 428 | } 429 | XClearWindow(dpy,win); 430 | zap_events(0); 431 | 432 | gptr->graph_width = graph_width; 433 | gptr->graph_height = graph_height; 434 | } 435 | /*}}}*/ 436 | 437 | /*{{{void scroll_screen( int dist )*/ 438 | void scroll_screen( dist ) 439 | int dist; 440 | { 441 | int reverse=FALSE; 442 | 443 | if( dist < 0 ) 444 | { 445 | dist = -dist; 446 | reverse=TRUE; 447 | } 448 | /* scroll the pixmap */ 449 | if( dist > g.pixmap_width ) 450 | { 451 | dist = g.pixmap_width; 452 | } 453 | if( reverse ) 454 | { 455 | /* copy the data */ 456 | XCopyArea(dpy, pix, pix, gc, 0, 0, g.pixmap_width - dist, graph_height, dist, 0); 457 | /* blank new region */ 458 | blank_region(0,0,dist,graph_height); 459 | }else{ 460 | /* copy the data */ 461 | XCopyArea(dpy, pix, pix, gc, dist, 0, g.pixmap_width - dist, graph_height, 0, 0); 462 | /* blank new region */ 463 | blank_region(g.pixmap_width - dist, 0, dist, graph_height); 464 | } 465 | /* update the window to match */ 466 | if( pixmap_installed ) 467 | { 468 | /* this line never seems to be needed on any system I know about 469 | * but the manual says an X server 470 | * may make a copy of a background pixmap 471 | * so in principle we should re-install. 472 | */ 473 | XSetWindowBackgroundPixmap(dpy,win,None); 474 | 475 | if(swosh && reverse) 476 | { 477 | XCopyArea(dpy, pix, bg_pix, gc, dist, 0, graph_width, graph_height, 0, 0); 478 | XSetWindowBackgroundPixmap(dpy, win, bg_pix); 479 | } 480 | else 481 | { 482 | XSetWindowBackgroundPixmap(dpy,win,pix); 483 | } 484 | XClearWindow(dpy,win); 485 | }else{ 486 | if(reverse) 487 | { 488 | XCopyArea(dpy, pix, win, gc, dist, 0, graph_width, graph_height, 0, 0); 489 | } 490 | else 491 | { 492 | XCopyArea(dpy, pix, win, gc, 0, 0, graph_width, graph_height, 0, 0); 493 | } 494 | } 495 | 496 | } 497 | /*}}}*/ 498 | 499 | /*{{{void plot_pixel( int x, int y, Gun value )*/ 500 | void plot_pixel( x, y, value ) 501 | int x; 502 | int y; 503 | Gun value; 504 | { 505 | int do_draw, draw_x, draw_y1, draw_y2; 506 | unsigned long draw_colour; 507 | 508 | /* if x is negative this means flush the stored request */ 509 | if(! plot_saved) /* no stored values */ 510 | { 511 | plot_x = x; 512 | plot_y1=plot_y2 = y; 513 | plot_col=table[value].pixel; 514 | do_draw=FALSE; 515 | plot_saved = (x >=0); 516 | }else{ 517 | if( x < 0 ) /* requesting a flush */ 518 | { 519 | draw_x=plot_x; 520 | draw_y1=plot_y1; 521 | draw_y2=plot_y2; 522 | draw_colour = plot_col; 523 | plot_saved=FALSE; 524 | do_draw=TRUE; 525 | }else{ /* plot request with saved value */ 526 | if( (x==plot_x) && (plot_col == table[value].pixel)) /* add to line */ 527 | { 528 | if(yplot_y2) plot_y2=y; 530 | do_draw=FALSE; 531 | }else{ 532 | draw_x=plot_x; 533 | draw_y1=plot_y1; 534 | draw_y2=plot_y2; 535 | draw_colour=plot_col; 536 | do_draw=TRUE; 537 | plot_x=x; 538 | plot_y1=plot_y2=y; 539 | plot_col=table[value].pixel; 540 | } 541 | } 542 | } 543 | if( do_draw ) 544 | { 545 | XSetForeground(dpy,gc,draw_colour); 546 | if( draw_y1 == draw_y2 ) 547 | { 548 | XDrawPoint(dpy,pix,gc,draw_x,draw_y1); 549 | }else{ 550 | XDrawLine(dpy,pix,gc,draw_x,draw_y1,draw_x,draw_y2); 551 | } 552 | } 553 | } 554 | /*}}}*/ 555 | 556 | /*{{{void flush_region(int x, int y, int w, int h)*/ 557 | void flush_region( x, y, w, h) 558 | int x; 559 | int y; 560 | int w; 561 | int h; 562 | { 563 | /* flush outstanding plots */ 564 | plot_pixel(-1,0,0); 565 | if(!swosh) 566 | { 567 | XCopyArea(dpy,pix,win,gc,x,y,w,h,x,y); 568 | } 569 | } 570 | /*}}}*/ 571 | 572 | -------------------------------------------------------------------------------- /Xgrab.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #ifdef VROOT 6 | #include"vroot.h" 7 | #endif 8 | char X_graphics_Id[]="$Id: Xgrab.c,v 1.1 2009/08/28 09:09:17 spb Exp $"; 9 | 10 | char *display=NULL; /* name of display to open, NULL for default */ 11 | char *geom=NULL; /* geometry of window, NULL for default */ 12 | 13 | #ifndef FALSE 14 | #define TRUE 1 15 | #define FALSE 0 16 | #endif 17 | 18 | Display *dpy; 19 | int screen; 20 | 21 | main(int argc, char *argv[]){ 22 | int ierr; 23 | dpy = XOpenDisplay(display); 24 | 25 | if( ! dpy ) 26 | { 27 | fprintf(stderr,"failed to open display\n"); 28 | exit(1); 29 | } 30 | screen = DefaultScreen(dpy); 31 | printf("screen in %d\n",screen); 32 | if(ierr=XGrabServer(dpy)){ 33 | printf("problem grabbing server %d \n",ierr); 34 | } 35 | sleep(10); 36 | XUngrabServer(dpy); 37 | 38 | XCloseDisplay(dpy); 39 | } 40 | 41 | -------------------------------------------------------------------------------- /artist.c: -------------------------------------------------------------------------------- 1 | /* 2 | * routines to render a fractal landscape as an image 3 | */ 4 | #include 5 | #include 6 | #include 7 | #include "paint.h" 8 | #include "crinkle.h" 9 | 10 | char artist_Id[] = "$Id: artist.c,v 1.41 2009/08/28 09:09:17 spb Exp $"; 11 | #define SIDE 1.0 12 | #ifndef PI 13 | #define PI 3.14159265 14 | #endif 15 | 16 | 17 | 18 | int base=0; /* parity flag for mirror routine */ 19 | 20 | extern Parm fold_param; 21 | extern Graph g; 22 | 23 | extern int swosh; 24 | 25 | Fold *top; 26 | 27 | 28 | Height varience; 29 | Height delta_shadow; 30 | Height shift; 31 | double shadow_slip; 32 | double shadow_register; 33 | double cos_phi; 34 | double sin_phi; 35 | double tan_phi; 36 | double x_fact; 37 | double y_fact; 38 | double vangle; 39 | double vscale; 40 | double tan_vangle; 41 | float viewpos; /* position of viewpoint */ 42 | float viewheight; /* height of viewpoint */ 43 | float focal; 44 | float vstrength; /* strength of vertical light source */ 45 | float lstrength; /* strength of vertical light source */ 46 | 47 | 48 | 49 | Height *shadow; /* height of the shadows */ 50 | Height *a_strip, *b_strip; /* the two most recent strips */ 51 | 52 | 53 | float uni(); 54 | /* {{{ void set_clut(int max_col, Gun *red, Gun *green, Gun *blue)*/ 55 | /* 56 | * setup the colour lookup table 57 | */ 58 | void set_clut (max_col,red,green,blue) 59 | int max_col; 60 | Gun *red; 61 | Gun *green; 62 | Gun *blue; 63 | { 64 | int band,shade; 65 | float top, bot; 66 | float intensity; 67 | int tmp; 68 | /* 69 | * float rb[N_BANDS] = { 0.167,0.200,0.333,0.450,0.600,1.000 }; 70 | * float gb[N_BANDS] = { 0.667,0.667,0.500,0.500,0.600,1.000 }; 71 | * float bb[N_BANDS] = { 0.500,0.450,0.333,0.200,0.000,1.000 }; 72 | */ 73 | 74 | float rb[N_BANDS]; 75 | float gb[N_BANDS]; 76 | float bb[N_BANDS]; 77 | 78 | /* band base colours as RGB fractions */ 79 | rb[0] = 0.450; rb[1] = 0.600; rb[2] = 1.000; 80 | gb[0] = 0.500; gb[1] = 0.600; gb[2] = 1.000; 81 | bb[0] = 0.333; bb[1] = 0.000; bb[2] = 1.000; 82 | 83 | /* {{{ black */ 84 | red[BLACK] = 0; 85 | green[BLACK] = 0; 86 | blue[BLACK] = 0; 87 | /* }}} */ 88 | /* {{{ white */ 89 | red[WHITE] = COL_RANGE; 90 | green[WHITE] = COL_RANGE; 91 | blue[WHITE] = COL_RANGE; 92 | /* }}} */ 93 | /* {{{ sky*/ 94 | red[SKY] = 0.404*COL_RANGE; 95 | green[SKY] = 0.588*COL_RANGE; 96 | blue[SKY] = COL_RANGE; 97 | /* }}} */ 98 | /* {{{ sea (lit) */ 99 | red[SEA_LIT] = 0; 100 | green[SEA_LIT] = 0.500*COL_RANGE; 101 | blue[SEA_LIT] = 0.700*COL_RANGE; 102 | /* }}} */ 103 | /* {{{ sea (unlit)*/ 104 | red[SEA_UNLIT] = 0; 105 | green[SEA_UNLIT] = ((g.ambient+(g.vfract/(1.0+g.vfract)))*0.500)*COL_RANGE; 106 | blue[SEA_UNLIT] = ((g.ambient+(g.vfract/(1.0+g.vfract)))*0.700)*COL_RANGE; 107 | /* }}} */ 108 | 109 | if( MIN_COL > max_col ) 110 | { 111 | fprintf(stderr,"set_clut: less than the minimum number of colours available\n"); 112 | exit(1); 113 | } 114 | /* max_col can over-rule band_size */ 115 | while( (BAND_BASE +g.band_size*N_BANDS) > max_col ) 116 | { 117 | g.band_size--; 118 | } 119 | 120 | for( band=0 ; band= max_col ) 125 | { 126 | fprintf(stderr,"INTERNAL ERROR, overflowed clut\n"); 127 | exit(1); 128 | } 129 | /* {{{ set red */ 130 | top = rb[band]; 131 | bot = g.ambient * top; 132 | intensity = bot + ((shade * (top - bot))/(g.band_size-1)); 133 | tmp = COL_RANGE * intensity; 134 | if (tmp < 0) 135 | { 136 | fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp); 137 | exit(2); 138 | } 139 | if( tmp > COL_RANGE ) 140 | { 141 | tmp = COL_RANGE; 142 | } 143 | red[BAND_BASE + (band*g.band_size) + shade] = tmp; 144 | /* }}} */ 145 | /* {{{ set green */ 146 | top = gb[band]; 147 | bot = g.ambient * top; 148 | intensity = bot + ((shade * (top - bot))/(g.band_size-1)); 149 | tmp = COL_RANGE * intensity; 150 | if (tmp < 0) 151 | { 152 | fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp); 153 | exit(2); 154 | } 155 | if( tmp > COL_RANGE ) 156 | { 157 | tmp = COL_RANGE; 158 | } 159 | green[BAND_BASE + (band*g.band_size) + shade] = tmp; 160 | /* }}} */ 161 | /* {{{ set blue */ 162 | top = bb[band]; 163 | bot = g.ambient * top; 164 | intensity = bot + ((shade * (top - bot))/(g.band_size-1)); 165 | tmp = COL_RANGE * intensity; 166 | if (tmp < 0) 167 | { 168 | fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp); 169 | exit(2); 170 | } 171 | if( tmp > COL_RANGE ) 172 | { 173 | tmp = COL_RANGE; 174 | } 175 | blue[BAND_BASE + (band*g.band_size) + shade] = tmp; 176 | /* }}} */ 177 | } 178 | } 179 | } 180 | /* }}} */ 181 | /* {{{ Height *extract(Strip *s) */ 182 | /* 183 | * extract the table of heights from the Strip struct 184 | * and discard the rest of the struct. 185 | */ 186 | Height *extract (s) 187 | Strip *s; 188 | { 189 | int i; 190 | 191 | Height *p; 192 | p = s->d; 193 | free(s); 194 | for(i=0 ; i= 0 ){ 270 | g.pos=0; 271 | }else{ 272 | g.pos = g.pixmap_width - 1; 273 | } 274 | } 275 | /* }}} */ 276 | /* {{{ Col get_col(Height p, Height p_minus_x, Height p_minus_y, Height shadow) */ 277 | /* 278 | * calculate the colour of a point. 279 | */ 280 | Col get_col (p,p_minus_x,p_minus_y,shadow) 281 | Height p; 282 | Height p_minus_x; 283 | Height p_minus_y; 284 | Height shadow; 285 | { 286 | Height delta_x, delta_y; 287 | Height delta_x_sqr, delta_y_sqr; 288 | Height hypot_sqr; 289 | 290 | double norm, dshade; 291 | Height effective; 292 | Col result; 293 | int band, shade; 294 | /* {{{ if underwater*/ 295 | if ( p < g.sealevel ) 296 | { 297 | if( shadow > g.sealevel ) 298 | { 299 | return( SEA_UNLIT ); 300 | }else{ 301 | return( SEA_LIT ); 302 | } 303 | } 304 | /* }}} */ 305 | /* 306 | * We have three light sources, one slanting in from the left 307 | * one directly from above and an ambient light. 308 | * For the directional sources illumination is proportional to the 309 | * cosine between the normal to the surface and the light. 310 | * 311 | * The surface contains two vectors 312 | * ( 1, 0, delta_x ) 313 | * ( 0, 1, delta_y ) 314 | * 315 | * The normal therefore is parallel to 316 | * ( -delta_x, -delta_y, 1)/sqrt( 1 + delta_x^2 + delta_y^2) 317 | * 318 | * For light parallel to ( cos_phi, 0, -sin_phi) the cosine is 319 | * (cos_phi*delta_x + sin_phi)/sqrt( 1 + delta_x^2 + delta_y^2) 320 | * 321 | * For light parallel to ( cos_phi*cos_alpha, cos_phi*sin_alpha, -sin_phi) 322 | * the cosine is 323 | * (cos_phi*cos_alpha*delta_x + cos_phi*sin_alpha*delta_y+ sin_phi)/sqrt( 1 + delta_x^2 + delta_y^2) 324 | * 325 | * For vertical light the cosine is 326 | * 1 / sqrt( 1 + delta_x^2 + delta_y^2) 327 | */ 328 | 329 | delta_x = p - p_minus_x; 330 | delta_y = p - p_minus_y; 331 | delta_x_sqr = delta_x * delta_x; 332 | delta_y_sqr = delta_y * delta_y; 333 | hypot_sqr = delta_x_sqr + delta_y_sqr; 334 | norm = sqrt( 1.0 + hypot_sqr ); 335 | 336 | /* {{{ calculate effective height */ 337 | effective = (p + (varience * g.contour * 338 | (1.0/ ( 1.0 + hypot_sqr)))); 339 | /* }}} */ 340 | /* {{{ calculate colour band. */ 341 | band = ( effective / varience) * N_BANDS; 342 | if ( band < 0 ) 343 | { 344 | band = 0; 345 | } 346 | if( band > (N_BANDS - 1)) 347 | { 348 | band = (N_BANDS -1); 349 | } 350 | result = (BAND_BASE + (band * g.band_size)); 351 | /* }}} */ 352 | 353 | /* {{{ calculate the illumination stength*/ 354 | /* 355 | * add in a contribution for the vertical light. The normalisation factor 356 | * is applied later 357 | * 358 | */ 359 | dshade = vstrength; 360 | 361 | if( p >= shadow ) 362 | { 363 | /* 364 | * add in contribution from the main light source 365 | */ 366 | /* dshade += ((double) lstrength * ((delta_x * cos_phi) + sin_phi));*/ 367 | dshade += ((double) lstrength * 368 | ((delta_x * x_fact) + (delta_y * y_fact) + sin_phi)); 369 | } 370 | /* divide by the normalisation factor (the same for both light sources) */ 371 | dshade /= norm; 372 | /* }}} */ 373 | /* {{{ calculate shading */ 374 | /* dshade should be in the range 0.0 -> 1.0 375 | * if the light intensities add to 1.0 376 | * now convert to an integer 377 | */ 378 | shade = dshade * (double) g.band_size; 379 | if( shade > (g.band_size-1)) 380 | { 381 | shade = (g.band_size-1); 382 | } 383 | /* {{{ if shade is negative then point is really in deep shadow */ 384 | if( shade < 0 ) 385 | { 386 | shade = 0; 387 | } 388 | /* }}} */ 389 | /* }}} */ 390 | result += shade; 391 | if( (result >= g.n_col) || (result < 0) ) 392 | { 393 | fprintf(stderr,"INTERNAL ERROR colour out of range %d max %d\n",result,g.n_col); 394 | exit(1); 395 | } 396 | return(result); 397 | } 398 | /* }}} */ 399 | /* {{{ Col *makemap(Height *a, Height *b, Height *shadow) */ 400 | Col *makemap (a,b,shadow) 401 | Height *a; 402 | Height *b; 403 | Height *shadow; 404 | { 405 | Col *res; 406 | int i; 407 | 408 | /* This routine returns a plan view of the surface */ 409 | res = (Col *) malloc(g.width * sizeof(Col) ); 410 | if (res == NULL) 411 | { 412 | fprintf(stderr,"malloc failed for colour strip\n"); 413 | exit(1); 414 | } 415 | res[0] = BLACK; 416 | for(i=1 ; i last ) 454 | { 455 | /* get the colour of this point, the front strip should be black */ 456 | if( i==0 ) 457 | { 458 | col = BLACK; 459 | }else{ 460 | col = get_col(b[i],a[i],b[i-1],shadow[i]); 461 | } 462 | if( coord > g.graph_height ) 463 | { 464 | coord = g.graph_height; 465 | } 466 | for(;last0;i--) 514 | { 515 | if(map[i] < BAND_BASE) 516 | { 517 | /* {{{ stipple water values*/ 518 | for(j=last_bottom;j<=last_top;j++) 519 | { 520 | res[j]=last_col; 521 | } 522 | last_col=map[i]; 523 | /* invalidate strip so last stip does not exist */ 524 | last_bottom=g.graph_height; 525 | last_top= -1; 526 | /* fill in water values */ 527 | coord=1+project(i,g.sealevel); 528 | for(j=0;j last_top) 552 | { 553 | last_top=top; 554 | } 555 | if( bottom < last_bottom) 556 | { 557 | last_bottom=bottom; 558 | } 559 | }else{ 560 | if(top < last_top) 561 | { 562 | for(j=top+1;j<=last_top;j++) 563 | { 564 | res[j]=last_col; 565 | } 566 | } 567 | if(bottom > last_bottom) 568 | { 569 | for(j=last_bottom;j (g.graph_height-1)) 625 | { 626 | pos = g.graph_height-1; 627 | } 628 | else if( pos < 0 ) 629 | { 630 | pos = 0; 631 | } 632 | return( pos ); 633 | } 634 | /* }}} */ 635 | /* {{{ void finish_artist() */ 636 | /* 637 | * Tidy up and free everything. 638 | */ 639 | void finish_artist() 640 | { 641 | free(a_strip); 642 | free(b_strip); 643 | free(shadow); 644 | free_fold(top); 645 | } 646 | /* }}} */ 647 | /* {{{ void init_parameters() */ 648 | 649 | void init_parameters() 650 | { 651 | g.graph_height=768; 652 | g.graph_width=1024; 653 | g.levels = 10; 654 | g.stop=2; 655 | g.n_col=DEF_COL; 656 | g.band_size=BAND_SIZE; 657 | g.ambient=0.3; 658 | g.contrast=1.0; 659 | g.contour=0.3; 660 | g.vfract=0.6; 661 | g.altitude=2.5; 662 | g.distance=4.0; 663 | g.phi=(40.0 * PI)/180.0; 664 | g.alpha=0.0; 665 | g.base_shift=0.5; 666 | g.sealevel=0.0; 667 | g.stretch=0.6; 668 | g.map=FALSE; 669 | g.reflec=TRUE; 670 | g.repeat=20; 671 | g.pos=0; 672 | g.scroll=0; 673 | 674 | fold_param.mean=0; 675 | fold_param.rg1=FALSE; 676 | fold_param.rg2=FALSE; 677 | fold_param.rg3=TRUE; 678 | fold_param.cross=TRUE; 679 | fold_param.force_front=TRUE; 680 | fold_param.force_back=FALSE; 681 | fold_param.forceval=-1.0; 682 | fold_param.fdim = 0.65; 683 | fold_param.mix =0.0; 684 | fold_param.midmix=0.0; 685 | 686 | } 687 | 688 | /* }}} */ 689 | /* {{{ Col *next_col(int paint, int reflec) */ 690 | 691 | Col *next_col (paint, reflec) 692 | int paint; 693 | int reflec; 694 | { 695 | Col *res; 696 | int i,offset=0; 697 | 698 | /* {{{ update strips */ 699 | if(paint) 700 | { 701 | if(reflec) 702 | { 703 | res = mirror( a_strip,b_strip,shadow); 704 | }else{ 705 | res = camera( a_strip,b_strip,shadow); 706 | } 707 | }else{ 708 | res = makemap(a_strip,b_strip,shadow); 709 | } 710 | free(a_strip); 711 | a_strip=b_strip; 712 | b_strip = extract( next_strip(top) ); 713 | /* }}} */ 714 | 715 | /* {{{ update the shadows*/ 716 | 717 | /* shadow_slip is the Y component of the light vector. 718 | * The shadows can only step an integer number of points in the Y 719 | * direction so we maintain shadow_register as the deviation between 720 | * where the shadows are and where they should be. When the magnitude of 721 | * this gets larger then 1 the shadows are slipped by the required number of 722 | * points. 723 | * This will not work for very oblique angles so the horizontal angle 724 | * of illumination should be constrained. 725 | */ 726 | shadow_register += shadow_slip; 727 | if( shadow_register >= 1.0 ) 728 | { 729 | /* {{{ negative offset*/ 730 | 731 | while( shadow_register >= 1.0 ) 732 | { 733 | shadow_register -= 1.0; 734 | offset++; 735 | } 736 | for(i=g.width-1 ; i>=offset ; i--) 737 | { 738 | shadow[i] = shadow[i-offset]-delta_shadow; 739 | if( shadow[i] < b_strip[i] ) 740 | { 741 | shadow[i] = b_strip[i]; 742 | } 743 | /* {{{ stop shadow at sea level */ 744 | 745 | if( shadow[i] < g.sealevel ) 746 | { 747 | shadow[i] = g.sealevel; 748 | } 749 | 750 | 751 | 752 | /* }}} */ 753 | } 754 | for(i=0;irepeat >= 0){ 838 | if(g->pos == 0){ 839 | blank_region(0,0,g->graph_width,g->graph_height); 840 | flush_region(0,0,g->graph_width,g->graph_height); 841 | } 842 | }else{ 843 | if( g->pos == g->graph_width-1){ 844 | blank_region(0,0,g->graph_width,g->graph_height); 845 | flush_region(0,0,g->graph_width,g->graph_height); 846 | } 847 | } 848 | if( g->scroll && !swosh ){ 849 | scroll_screen(g->scroll); 850 | } 851 | 852 | l = next_col(1-g->map,g->reflec); 853 | if( g->map ) 854 | { 855 | if( g->graph_height > g->width ){ 856 | mapwid=g->width; 857 | }else{ 858 | mapwid=g->graph_height; 859 | } 860 | for( j=0 ;j<(g->graph_height-mapwid); j++) 861 | { 862 | plot_pixel(g->pos,((g->graph_height-1)-j),BLACK); 863 | } 864 | for(j=0; jpos,((mapwid-1)-j),l[j]); 867 | } 868 | }else{ 869 | for(j=0 ; jgraph_height ; j++) 870 | { 871 | /* we assume that the scroll routine fills the 872 | * new region with a SKY value. This allows us to 873 | * use a testured sky for B/W displays 874 | */ 875 | if( l[j] != SKY ) 876 | { 877 | plot_pixel(g->pos,((g->graph_height-1)-j),l[j]); 878 | } 879 | } 880 | } 881 | free(l); 882 | flush_region(g->pos,0,1,g->graph_height); 883 | g->scroll = 0; 884 | /* now update pos ready for next time */ 885 | if( g->repeat >=0 ){ 886 | g->pos++; 887 | if(g->pos >= g->pixmap_width) 888 | { 889 | g->pos -= g->repeat; 890 | if( g->pos < 0 || g->pos > g->pixmap_width-1 ) 891 | { 892 | g->pos=0; 893 | }else{ 894 | g->scroll = g->repeat; 895 | } 896 | } 897 | }else{ 898 | g->pos--; 899 | if( g->pos < 0 ){ 900 | g->pos -= g->repeat; 901 | if( g->pos < 0 || g->pos > (g->pixmap_width-1) ){ 902 | g->pos=g->pixmap_width-1; 903 | }else{ 904 | g->scroll = g->repeat; 905 | } 906 | } 907 | } 908 | 909 | if(g->scroll && swosh) 910 | { 911 | scroll_screen(g->scroll); 912 | } 913 | } 914 | /* }}} */ 915 | 916 | 917 | -------------------------------------------------------------------------------- /calcalt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Recursive update procedure for fractal landscapes 3 | * 4 | * The only procedures needed outside this file are 5 | * make_fold, called once to initialise the data structs. 6 | * next_strip, each call returns a new strip off the side of the surface 7 | * you can keep calling this as often as you want. 8 | * free_strip, get rid of the strip when finished with it. 9 | * free_fold, get rid of the data structs when finished with this surface. 10 | * 11 | * Apart from make_fold all these routines get their parameters from their 12 | * local Fold struct, make_fold initialises all these values and has to 13 | * get it right for the fractal to work. If you want to change the fractal 14 | * dim in mid run you will have to change values at every level. 15 | * each recursive level only calls the level below once for every two times it 16 | * is called itself so it will take a number of iterations for any changes to 17 | * be notices by the bottom (long length scale) level. 18 | */ 19 | #include 20 | #include 21 | #include 22 | #include "crinkle.h" 23 | 24 | char calcalt_Id[] = "$Id: calcalt.c,v 2.18 2009/08/28 09:09:17 spb Exp $"; 25 | 26 | #ifdef DEBUG 27 | #define DB(A,B) dump_pipeline(A,B) 28 | #else 29 | #define DB(A,B) 30 | #endif 31 | 32 | 33 | /* {{{ Strip *make_strip(Fold *f) */ 34 | #ifdef ANSI 35 | Strip *make_strip(Fold *f) 36 | #else 37 | Strip *make_strip (f) 38 | Fold *f; 39 | #endif 40 | { 41 | Strip *p; 42 | int n; 43 | 44 | p = (Strip *) malloc( sizeof(Strip) ); 45 | if( p == NULL ) 46 | { 47 | fprintf(stderr,"make_strip: malloc failed\n"); 48 | exit(1); 49 | } 50 | p->f = f; 51 | n = f->count; 52 | p->d = (Height *)malloc( n * sizeof(Height) ); 53 | if( p->d == NULL ) 54 | { 55 | fprintf(stderr,"make_strip: malloc failed\n"); 56 | exit(1); 57 | } 58 | return(p); 59 | } 60 | 61 | /* }}} */ 62 | /* {{{ void free_strip(Strip *p) */ 63 | #ifdef ANSI 64 | void free_strip(Strip *p) 65 | #else 66 | void free_strip (p) 67 | Strip *p; 68 | #endif 69 | { 70 | if( p->d ) 71 | { 72 | free(p->d); 73 | p->d = NULL; 74 | } 75 | free(p); 76 | } 77 | /* }}} */ 78 | /* {{{ Strip *double_strip(Strip *s) */ 79 | #ifdef ANSI 80 | Strip *double_strip(Strip *s) 81 | #else 82 | Strip *double_strip (s) 83 | Strip *s; 84 | #endif 85 | { 86 | Strip *p; 87 | Height *a, *b; 88 | int i; 89 | int count; 90 | 91 | p = make_strip(s->f->parent); 92 | a = s->d; 93 | b = p->d; 94 | count = s->f->count; 95 | for(i=0; i < count-1; i++) 96 | { 97 | *b = *a; 98 | a++; 99 | b++; 100 | *b = 0.0; 101 | b++; 102 | } 103 | *b = *a; 104 | return(p); 105 | } 106 | /* }}} */ 107 | /* {{{ Strip *set_strip(Fold *f, Height value)*/ 108 | #ifdef ANSI 109 | Strip *set_strip(Fold *f, Height value) 110 | #else 111 | Strip *set_strip (f,value) 112 | Fold *f; 113 | Height value; 114 | #endif 115 | { 116 | int i; 117 | Strip *s; 118 | Height *h; 119 | int count; 120 | 121 | s = make_strip(f); 122 | h = s->d; 123 | count = f->count; 124 | for( i=0 ; i < count ; i++) 125 | { 126 | *h = value; 127 | h++; 128 | } 129 | return(s); 130 | } 131 | 132 | /* }}} */ 133 | /* {{{ Strip *random_strip(Fold *f)*/ 134 | #ifdef ANSI 135 | Strip *random_strip(Fold *f) 136 | #else 137 | Strip *random_strip(f) 138 | Fold *f; 139 | #endif 140 | { 141 | Strip *result; 142 | int i, count; 143 | 144 | result=make_strip(f); 145 | count = f->count; 146 | for( i=0 ; i < count ; i++) 147 | { 148 | result->d[i] = f->p->mean + (f->scale * gaussian()); 149 | } 150 | return(result); 151 | } 152 | /* }}} */ 153 | 154 | /* {{{ void reset_fold(Fold *f) */ 155 | #ifdef ANSI 156 | void reset_fold(Fold *f) 157 | #else 158 | void reset_fold(f) 159 | Fold *f; 160 | #endif 161 | { 162 | /* 163 | * resets any cached values within the fold structure 164 | * this should be called if the param struct is changed. 165 | */ 166 | Length scale, midscale; 167 | double root2; 168 | 169 | root2=sqrt((double) 2.0 ); 170 | scale = pow((double) f->length, (double) (2.0 * f->p->fdim)); 171 | midscale = pow((((double) f->length)*root2), (double) (2.0 * f->p->fdim)); 172 | f->scale = scale; 173 | f->midscale = midscale; 174 | 175 | if( f->next ){ 176 | reset_fold(f->next); 177 | } 178 | } 179 | 180 | /* }}} */ 181 | /* {{{ Fold *make_fold(Fold *parent,Parm *param, int levels, int stop, Length len) */ 182 | /* 183 | * Initialise the fold structures. 184 | * As everything else reads the parameters from their fold 185 | * structs we need to set these here, 186 | * p is the parameter struct common to all update levels. 187 | * levels is the number of levels of recursion below this one. 188 | * Number of points = 2^levels+1 189 | * stop is the number of levels that are generated as random offsets from a 190 | * constant rather than from an average. 191 | * fractal_start, if true we start in the middle of a mountain range 192 | * if false we build up mountains from the start height. 193 | * length is the length of the side of the square at this level. 194 | * N.B this means the update square NOT the width of the fractal. 195 | * len gets smaller as the level increases. 196 | * start, the starting height for a non-fractal start. 197 | */ 198 | #ifdef ANSI 199 | Fold *make_fold(Fold *parent,Parm *param, int levels, int stop, Length length) 200 | #else 201 | Fold *make_fold (parent,param,levels,stop,length) 202 | struct fold *parent; 203 | struct parm *param; 204 | int levels; 205 | int stop; 206 | Length length; 207 | #endif 208 | { 209 | Fold *p; 210 | int i; 211 | 212 | if( (levels < stop) || (stop<0) ) 213 | { 214 | fprintf(stderr,"make_fold: invalid parameters\n"); 215 | fprintf(stderr,"make_fold: levels = %d , stop = %d \n",levels,stop); 216 | exit(1); 217 | } 218 | p = (Fold *)malloc(sizeof(Fold)); 219 | if( p == NULL ) 220 | { 221 | fprintf(stderr,"make_fold: malloc failed\n"); 222 | exit(1); 223 | } 224 | p->length=length; 225 | p->level = levels; 226 | p->count = (1 << levels) +1; 227 | p->stop = stop; 228 | p->state = START; 229 | p->save =NULL; 230 | p->p = param; 231 | for(i=0;is[i] = NULL; 234 | } 235 | p->parent=parent; 236 | 237 | p->next = NULL; /* truncate recursion in reset */ 238 | reset_fold(p); 239 | 240 | if( levels > stop ) 241 | { 242 | p->next = make_fold(p,param,(levels-1),stop,(2.0*length)); 243 | }else{ 244 | p->next = NULL; 245 | } 246 | return( p ); 247 | } 248 | /* }}} */ 249 | /* {{{ void free_fold(Fold *f) */ 250 | #ifdef ANSI 251 | void free_fold(Fold *f) 252 | #else 253 | void free_fold (f) 254 | Fold *f; 255 | #endif 256 | { 257 | int i; 258 | if( f->next ){ 259 | free_fold(f->next); 260 | f->next=NULL; 261 | } 262 | if( f->save ){ 263 | free_strip(f->save); 264 | f->save=NULL; 265 | } 266 | for(i=0;is[i] != NULL ) 269 | { 270 | free_strip(f->s[i]); 271 | f->s[i] = NULL; 272 | } 273 | } 274 | free(f); 275 | return; 276 | } 277 | /* }}} */ 278 | 279 | /* {{{ Strip *next_strip(Fold *fold) */ 280 | #ifdef ANSI 281 | Strip *next_strip(Fold *fold) 282 | #else 283 | Strip *next_strip (fold) 284 | Fold *fold; 285 | #endif 286 | { 287 | Strip *result=NULL; 288 | Strip *tmp; 289 | Strip **t; 290 | int i, iter; 291 | int count=fold->count; 292 | 293 | if( fold->level == fold->stop) 294 | { 295 | /* {{{ generate values from scratch */ 296 | result=random_strip(fold); 297 | /* }}} */ 298 | }else{ 299 | /* 300 | * There are two types of strip, 301 | * A strips - generated by the lower recursion layers. 302 | * these contain the corner points and half the side points 303 | * B strips - added by this layer, this contains the mid points and 304 | * half the side points. 305 | * 306 | * The various update routines test for NULL pointer arguments so 307 | * that this routine will not fail while filling the pipeline. 308 | */ 309 | while( result == NULL ) 310 | { 311 | /* {{{ iterate*/ 312 | switch(fold->state) 313 | { 314 | case START: 315 | /* {{{ perform an update. return first result*/ 316 | DB("S1",fold); 317 | t=fold->s; 318 | /* read in a new A strip at the start of the pipeline */ 319 | tmp =next_strip(fold->next); 320 | t[0] = double_strip(tmp); 321 | free_strip(tmp); 322 | /* make the new B strip */ 323 | t[1]=set_strip(fold,0.0); 324 | if( ! t[2] ) 325 | { 326 | /* we want to have an A B A pattern of strips at the 327 | * start of the pipeline. 328 | * force this when starting the pipe 329 | */ 330 | t[2]=t[0]; 331 | tmp =next_strip(fold->next); 332 | t[0] = double_strip(tmp); 333 | free_strip(tmp); 334 | } 335 | DB("E1",fold); 336 | 337 | /* 338 | * create the mid point 339 | * t := A B A 340 | */ 341 | DB("S2",fold); 342 | x_update(fold,fold->midscale,0.0,t[0],t[1],t[2]); 343 | DB("E2",fold); 344 | 345 | if(fold->p->rg1) 346 | { 347 | DB("S3",fold); 348 | /* 349 | * first possible regeneration step 350 | * use the midpoints to regenerate the corner values 351 | * increment t by 2 so we still have and A B A pattern 352 | */ 353 | if( t[3] == NULL ) 354 | { 355 | /* rather than do no update add offset to old value */ 356 | v_update(fold,fold->midscale,1.0,t[1],t[2],t[1]); 357 | }else{ 358 | v_update(fold,fold->midscale,fold->p->midmix,t[1],t[2],t[3]); 359 | } 360 | t+=2; 361 | DB("E3",fold); 362 | 363 | } 364 | 365 | /* 366 | * fill in the edge points 367 | * increment t by 2 to preserve the A B A pattern 368 | */ 369 | DB("S4",fold); 370 | 371 | if( fold->p->cross ) 372 | { 373 | t_update(fold,fold->scale,0.0,t[0],t[1],t[2]); 374 | p_update(fold,fold->scale,0.0,t[1],t[2],t[3]); 375 | t+=2; 376 | }else{ 377 | hside_update(fold,fold->scale,0.0,t[0],t[1],t[2]); 378 | vside_update(fold,fold->scale,0.0,t[2]); 379 | t+=2; 380 | } 381 | DB("E4",fold); 382 | 383 | if(fold->p->rg2) 384 | { 385 | DB("S5",fold); 386 | /* 387 | * second regeneration step update midpoint 388 | * from the new edge values 389 | */ 390 | if( fold->p->cross ) 391 | { 392 | if( t[2] == NULL ) 393 | { 394 | /* add random offset to old rather than skip update */ 395 | p_update(fold,fold->scale,fold->p->mix,t[0],t[1],t[0]); 396 | }else{ 397 | p_update(fold,fold->scale,fold->p->mix,t[0],t[1],t[2]); 398 | } 399 | }else{ 400 | vside_update(fold,fold->scale,fold->p->mix,t[1]); 401 | } 402 | DB("E5",fold); 403 | 404 | } 405 | /* increment t by 1 406 | * this gives a B A B pattern to regen-3 407 | * if regen 3 is not being used it leaves t pointing to the 408 | * 2 new result strips 409 | */ 410 | t++; 411 | if(fold->p->rg3) 412 | { 413 | DB("S6",fold); 414 | 415 | /* final regenration step 416 | * regenerate the corner points from the new edge values 417 | * this needs a B A B pattern 418 | * leave t pointing to the 2 new result strips 419 | * 420 | * this has to be a t_update 421 | */ 422 | if( t[2] == NULL ) 423 | { 424 | /* add random offset to old rather than skip update */ 425 | t_update(fold,fold->scale,1.0,t[0],t[1],t[0]); 426 | }else{ 427 | t_update(fold,fold->scale,fold->p->mix,t[0],t[1],t[2]); 428 | } 429 | t++; 430 | DB("E6",fold); 431 | 432 | } 433 | result=t[1]; 434 | fold->save=t[0]; 435 | t[0]=t[1]=NULL; 436 | fold->state = STORE; 437 | break; 438 | /* }}} */ 439 | case STORE: 440 | /* {{{ return second value from previous update. */ 441 | result = fold->save; 442 | fold->save=NULL; 443 | for(i=NSTRIP-1;i>1;i--) 444 | { 445 | fold->s[i] =fold->s[i-2]; 446 | } 447 | fold->s[0] = fold->s[1]=NULL; 448 | fold->state = START; 449 | break; 450 | /* }}} */ 451 | default: 452 | fprintf(stderr,"next_strip: invalid state level %d state %d\n", 453 | fold->level,fold->state); 454 | exit(3); 455 | } 456 | /* }}} */ 457 | } 458 | } 459 | iter = fold->level - fold->stop; 460 | if( fold->p->force_front > iter){ 461 | result->d[0] = fold->p->forceval; 462 | } 463 | if( fold->p->force_back > iter){ 464 | result->d[count-1] = fold->p->forceval; 465 | } 466 | return(result); 467 | } 468 | /* }}} */ 469 | 470 | /* {{{ void x_update(Fold *fold,float scale, float mix, Strip *a, Strip *b, Strip *c)*/ 471 | #ifdef ANSI 472 | void x_update(Fold *fold,float scale, float mix, Strip *a, Strip *b, Strip *c) 473 | #else 474 | void x_update(fold, scale, mix, a, b, c) 475 | Fold *fold; 476 | float scale; 477 | float mix; 478 | Strip *a; 479 | Strip *b; 480 | Strip *c; 481 | #endif 482 | { 483 | int i; 484 | int count=fold->count; 485 | float w; 486 | Height *mp, *lp, *rp; 487 | 488 | /* don't run unless we have all the parameters */ 489 | if( !a || !c ) return; 490 | if( !b ) 491 | { 492 | fprintf(stderr,"x_update: attempt to update NULL strip\n"); 493 | exit(1); 494 | } 495 | 496 | w = (1.0 - mix)*0.25; 497 | mp=b->d; 498 | lp=a->d; 499 | rp=c->d; 500 | 501 | if( mix <= 0.0 ){ 502 | /* {{{ random offset to average of new points*/ 503 | for(i=0; i= 1.0 ){ 513 | /* {{{ random offset to old value*/ 514 | for(i=0; icount; 552 | float w; 553 | Height *mp, *lp, *rp; 554 | 555 | /* don't run if we have no parameters */ 556 | if( !a || !b ) return; 557 | 558 | /* if c is missing we can do a vside update instead 559 | * should really be a sideways t but what the heck we only 560 | * need this at the start 561 | */ 562 | if( !c ) 563 | { 564 | vside_update(fold,scale,mix,b); 565 | return; 566 | } 567 | 568 | w = (1.0 - mix)*0.25; 569 | mp=b->d; 570 | lp=a->d; 571 | rp=c->d; 572 | 573 | if( mix <= 0.0 ){ 574 | /* {{{ random offset to average of new points*/ 575 | for(i=0; i= 1.0){ 585 | /* {{{ random offset to old values*/ 586 | for(i=0; icount; 625 | float w, we; 626 | Height *mp, *lp, *rp; 627 | float third=(1.0/3.0); 628 | 629 | /* don't run unless we have all the parameters */ 630 | if( !a || !c ) return; 631 | if( !b ) 632 | { 633 | fprintf(stderr,"t_update: attempt to update NULL strip\n"); 634 | exit(1); 635 | } 636 | 637 | w = (1.0 - mix)*0.25; 638 | we = (1.0 - mix)*third; 639 | mp=b->d; 640 | lp=a->d; 641 | rp=c->d; 642 | 643 | if( mix <= 0.0){ 644 | /* {{{ random offset to average of new points*/ 645 | mp[0] = third * ( lp[0] + rp[0] + mp[1] ) 646 | + (scale * gaussian()); 647 | mp++; 648 | lp++; 649 | rp++; 650 | for(i=1; i= 1.0){ 662 | /* {{{ random offset to old values*/ 663 | for(i=0; icount; 710 | float w, we; 711 | Height *mp, *lp, *rp; 712 | 713 | /* don't run unless we have all the parameters */ 714 | if( !a || !c ) return; 715 | if( !b ) 716 | { 717 | fprintf(stderr,"v_update: attempt to update NULL strip\n"); 718 | exit(1); 719 | } 720 | 721 | w = (1.0 - mix)*0.25; 722 | we = (1.0 - mix)*0.5; 723 | mp=b->d; 724 | lp=a->d; 725 | rp=c->d; 726 | 727 | if( mix <= 0.0){ 728 | /* {{{ random offset of average of new points*/ 729 | mp[0] = 0.5 * ( lp[1] + rp[1] ) 730 | + (scale * gaussian()); 731 | mp++; 732 | lp++; 733 | rp++; 734 | for(i=1; i= 1.0){ 746 | /* {{{ random offset to old values*/ 747 | for(i=0; icount; 791 | float w; 792 | Height *mp; 793 | 794 | /* don't run unless we have all the parameters */ 795 | if( !a ) return; 796 | 797 | 798 | w = (1.0 - mix)*0.5; 799 | mp=a->d; 800 | 801 | if( mix <= 0.0){ 802 | /* {{{ random offset to average of new points*/ 803 | for(i=0; i= 1.0){ 811 | /* {{{ random offset to old values*/ 812 | for(i=0; icount; 848 | float w; 849 | Height *mp, *lp, *rp; 850 | 851 | /* don't run unless we have all the parameters */ 852 | if( !a || !c ) return; 853 | if( !b ) 854 | { 855 | fprintf(stderr,"x_update: attempt to update NULL strip\n"); 856 | exit(1); 857 | } 858 | 859 | w = (1.0 - mix)*0.5; 860 | mp=b->d; 861 | lp=a->d; 862 | rp=c->d; 863 | 864 | if( mix <= 0.0 ){ 865 | /* {{{ random offset to average of new points*/ 866 | for(i=0; i= 1.0){ 876 | /* {{{ random offset to old points*/ 877 | for(i=0; ilevel, 911 | f->s[0],f->s[1],f->s[2],f->s[3],f->s[4],f->s[5],f->s[6],f->s[7]); 912 | } 913 | #endif 914 | -------------------------------------------------------------------------------- /copyright.h: -------------------------------------------------------------------------------- 1 | /* $Id: copyright.h,v 1.2 1994/03/28 15:21:32 spb Exp $ */ 2 | /* 3 | 4 | Copyright 1994 by Stephen Booth, the University of Edinburgh 5 | 6 | Permission to use, copy, modify, distribute, and sell this software and its 7 | documentation for any purpose is hereby granted without fee, provided that 8 | the above copyright notice appear in all copies and that both that 9 | copyright notice and this permission notice appear in supporting 10 | documentation, and that the name of the author not be used in advertising or 11 | publicity pertaining to distribution of the software without specific, 12 | written prior permission. The author makes no representations about the 13 | suitability of this software for any purpose. It is provided "as is" 14 | without express or implied warranty. 15 | 16 | */ 17 | -------------------------------------------------------------------------------- /crinkle.h: -------------------------------------------------------------------------------- 1 | /* $Id: crinkle.h,v 2.9 1997/10/24 14:52:10 spb Exp $ */ 2 | #ifndef CRINKLE 3 | #define CRINKLE 4 | /* {{{ typedefs */ 5 | typedef float Height; 6 | typedef float Length; 7 | /* }}} */ 8 | /* {{{ defines */ 9 | #ifndef NULL 10 | #define NULL (void *) 0 11 | #endif 12 | #ifndef FALSE 13 | #define FALSE 0 14 | #define TRUE 1 15 | #endif 16 | 17 | #define START 0 18 | #define STORE 1 19 | 20 | #define NSTRIP 8 21 | /* }}} */ 22 | /* {{{ structs */ 23 | 24 | /* parameters for the update */ 25 | typedef struct parm{ 26 | Height mean; /* mean altitude */ 27 | int rg1; /* optional regeneration steps */ 28 | int rg2; 29 | int rg3; 30 | int cross; /* use four point average on edges rather than 2 */ 31 | int force_front; /* keep front edge low */ 32 | int force_back; /* keep back edge low */ 33 | Height forceval; /* value to force to */ 34 | float mix; /* fraction of old value to include in average */ 35 | float midmix; /* same but for cross updates */ 36 | float fdim; 37 | }Parm; 38 | 39 | /* The parameter struct for the recursive procedure */ 40 | typedef struct fold{ 41 | int level; /* levels of recursion below us */ 42 | int count; /* number of points at this level */ 43 | Length length; /* width of the update square */ 44 | Length scale; /* scale factor for perturbations */ 45 | Length midscale; /* as above but for diagonal offsets */ 46 | struct parm *p; /* update parameters */ 47 | struct strip *s[NSTRIP]; /* pointers to the pipeline strips */ 48 | struct strip *save; /* save position for STORE state */ 49 | int stop; /* level to stop recursion */ 50 | int state; /* internal stat of algorithm */ 51 | struct fold *next; /* next iteration down */ 52 | struct fold *parent; /* next iteration up */ 53 | } Fold; 54 | 55 | /* strip of altitudes */ 56 | typedef struct strip{ 57 | struct fold *f; /* parent fold structure */ 58 | Height *d; /* should have 2^level + 1 (f->count) points */ 59 | }Strip; 60 | 61 | 62 | /* }}} */ 63 | /* {{{ prototypes */ 64 | #ifdef ANSI 65 | Strip *make_strip (Fold *); 66 | void free_strip (Strip *); 67 | Strip *double_strip (Strip *); 68 | Strip *set_strip(Fold *, Height ); 69 | Strip *random_strip (Fold *); 70 | Strip *next_strip (Fold *); 71 | void reset_fold(Fold *f); 72 | Fold *make_fold (Fold *,Parm *,int, int, Length); 73 | void free_fold (Fold *); 74 | Length gaussian (); 75 | void x_update(Fold *, float, float, Strip *, Strip *, Strip *); 76 | void p_update(Fold *, float, float, Strip *, Strip *, Strip *); 77 | void t_update(Fold *, float, float, Strip *, Strip *, Strip *); 78 | void v_update(Fold *, float, float, Strip *, Strip *, Strip *); 79 | void vside_update(Fold *, float, float, Strip *); 80 | void hside_update(Fold *, float, float, Strip *, Strip *, Strip *); 81 | #else 82 | Strip *make_strip (); 83 | void free_strip (); 84 | Strip *double_strip (); 85 | Strip *set_strip (); 86 | Strip *random_strip (); 87 | Strip *next_strip (); 88 | void reset_fold(); 89 | Fold *make_fold (); 90 | void free_fold (); 91 | Length gaussian (); 92 | void x_update(); 93 | void p_update(); 94 | void t_update(); 95 | void v_update(); 96 | void vside_update(); 97 | void hside_update(); 98 | 99 | #endif 100 | /* }}} */ 101 | #endif 102 | -------------------------------------------------------------------------------- /docs/about_xmountains.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | About xmountains 4 | 5 | 6 |

All about xmountains

7 | 8 |

9 | 10 | Xmountains is a fractal terrain generator written by 11 | Stephen Booth 12 | This document describes what it does and how it works. 13 |

14 | 15 |

16 | The basic idea behind a fractal landscape is to generate a continuous surface 17 | which varies in height randomly but with the random variation obeying a 18 | particular statistical law. 19 |

20 | 21 |

22 | In the case of a fractal landscape the average difference in height 23 | between pairs of points separated by a distance l should go as 24 | a power law in l. If you are only interested in random terrain 25 | generation rather than fractal self-similarity then you could use other 26 | functions of l that tend to zero as l tends to zero. 27 | If the function does not tend to zero then the result will not be 28 | continuous. I use the following definition: 29 |

30 | 31 | 32 |
                      2H
 33 |     <|H1 - H2|>  =  l
 34 | 
35 |
36 |
37 |

38 | For values of H below 0.5 as l gets small the variation in height 39 | is greater than the 40 | horizontal distance between the points (l) so the surface becomes 41 | space-filling. For values of H at 0.5 or above the surface becomes 42 | smoother as H increases. This is because the variation in height at 43 | short length scales is a smaller fraction of the variation at longer 44 | length scales. When displaying the surface you usually re-scale the whole 45 | lot by a constant factor so it is the relative variation that matters. 46 |

47 | 48 |

49 | This program uses a modified form the mid-point displacement algorithm 50 |

51 | 52 |

53 | The mid-point displacement algorithm is a recursive algorithm. 54 | Starting from a crude outline of the surface more and more detail is 55 | added at progressively smaller length scales. 56 | Each iteration doubles the resolution of a 2 dimensional grid of altitudes. 57 |

58 |

59 | This is done in 2 stages: 60 |

61 |
A           B                  A           B
 62 |                 stage1
 63 |                --------->            E
 64 | 
 65 | C           D                  C           D
 66 | 
 67 | 
 68 | 
 69 | A           B                  A     F     B
 70 |                  stage2
 71 |       E         -------->      G     E     H
 72 | 
 73 | C           D                  C     I     D
 74 | 
75 |

76 | More detail can then be filled in by recursion: 77 |

78 |
 79 | A     F     B                  A     F     B
 80 |                  stage1           *     *
 81 | G     E     H   -------->      G     E     H
 82 |                                   *     *
 83 | C     I     D                  C     I     D
 84 | 
 85 | 
 86 | A     F     B                  A  +  F  +  B
 87 |    *     *       stage2        +  *  +  *  +
 88 | G     E     H   -------->      G  +  E  +  H
 89 |    *     *                     +  *  +  *  +
 90 | C     I     D                  C  +  I  +  D
 91 | 
 92 | 
93 | 94 |

95 | The new points are generated by taking an average of the surrounding points 96 | and adding a random offset. In order to generate the power law behaviour 97 | described above the random offset is scaled by a factor 98 | proportional to a power (2H in my notation) of the distance between the new 99 | points and the 100 | surrounding points. The results seem to be a little better if the random 101 | offsets are taken from a gaussian distribution. The basic idea is very 102 | similar to that used by the Koch snowflake. 103 |

104 |

105 | The modifications to the standard algorithm are as follows: 106 | There are three optional regeneration steps to reduce 107 | creasing. These are controlled by the 108 | -s flag. 109 |

110 |

111 | The -x flag (cross update) controls whether the 112 | midpoints (E) are included 113 | in the average when performing the stage2 update or if only the corner 114 | points are used. 115 |

116 | 117 |

Creasing

118 |

119 | When I started in this game "creasing" was a big problem with square 120 | grid mid-point displacement surfaces 121 | and explicit smoothing steps were introduced to get rid of these. 122 | You can make my program revert to these early algorithms by specifying 123 | "-s 0" Things are particularly bad if you calculate the middle of the sides 124 | independently of the middle of the square ("-x" in my program) 125 | This was not uncommon in the other programs I have seen. 126 |

127 |

Cross updates

128 |

129 | If you only use a pair of points to perform the average for the middle 130 | of the sides then for any point that lies on one of the sides of a 131 | large length scale square its value depends ONLY on the values of other 132 | points that lie along that side. This line then forms a crease. Because 133 | no information ever crosses this line it acts as a kind of "event 134 | horizon". The heights of points on the crease are calculated 135 | independently of everything else and then the surfaces on the 2 sides 136 | form to match this line but the 2 surfaces are independent of each 137 | other. The crease is a mis-match between the 2 independent surfaces that 138 | are only constrained to follow a common boundary that has been specified 139 | independently of each of them 140 |
141 | A fractal landscape with creases 142 |

143 |

144 | When you split the update into 2 steps: 145 |

    146 |
  1. generate the middle of the square with an average of the 147 | 4 corners and a random offset based on a length scale of L/sqrt(2). 148 |
  2. 149 |
  3. generate the sides as an average over 4 points (2 corner points and 150 | 2 middle of square points) followed by a random offset based on a 151 | length scale of L/2. 152 |
  4. 153 |
154 | the information flows sideways into the sides of the large squares. 155 | The problem does not go away but instead of creases along the sides of 156 | the squares you get conical deformations at the corners of the squares: 157 |
158 | A fractal landscape with conical deformations 159 |
160 | This is an improvement but not the whole story. 161 |

162 |

Regeneration steps

163 |

164 | 165 | The root cause of creasing and the conical 166 | deformations is that the position 167 | of some points are fixed by the early (long-distance) iterations of the 168 | fractal algorithm. We are trying to generate a surface where the average 169 | difference in height between points on the surface is a function of the 170 | distance between them. Ideally two points should have an equal effect on 171 | each other. Instead we have implemented a hierarchy of points where the 172 | information only flows in one direction. 173 |

174 |

175 | The solution I came up with was to use the early iteration to set the 176 | overall trend of the surface rather than setting the exact position of 177 | particular points. This is done by a 2 steps forward/1 step back method. 178 | In the original algorithm the results at the end of one iteration are 179 | used to generate a new set of points with each iteration adding detail at a 180 | length scale of half the previous iteration. I added a second stage to 181 | each iteration that consisted of discarding all of the points generated 182 | by previous iterations and regenerating them from the new points. 183 | I think this is a lot closer to the desired result because every point 184 | is the result of updates at all length scales. 185 |
186 | a fractal landscape 187 |
188 | However I have a 189 | suspicion that it may result in a slight shift in the fractal dimension. 190 | It would be nice to measure the fractal dimension produced as a function 191 | of the input parameter to the algorithm. 192 |

193 |

194 | A regeneration step recalculates the height of existing points using an 195 | average and offset from a newer generation of points. In xmountains the three 196 | regeneration steps are: 197 |

198 |
199 |
Step 1
200 |
recalculate corner points (A,B,C,D) from the midpoints (E) 201 | after the stage1 update.
202 |
Step 2
203 |
recalculate midpoints (E) from the edge points (F,G,H,I) 204 | after the stage2 update
205 |
Step 3
206 |
recalculate corner points (A,B,C,D) from the edge points (F,G,H,I) 207 | after the stage2 update
208 |
209 |

210 | The regeneration stages are turned on by the smoothing parameter 211 | (-s flag) 212 |

213 |
  flag	Step-3	Step-2	Step-1
214 |   0	off	off	off
215 |   1	on	off	off
216 |   2	off	on	off
217 |   3	on	on	off
218 |   4	off	off	on
219 |   5	on	off	on
220 |   6	off	on	on
221 |   7	on	on	on
222 | 
223 |

224 | The default is to just use step 3 (-s 1) 225 |

226 | When performing the regeneration steps the random offset is added to an 227 | average of the new points. 228 |

229 |

230 | I came across a different solution in the xmnts program by 231 | 232 | Paul Sharpe @ DEC, Reading, England. 233 | 234 | who also modified the old points at each iteration, but he only added an 235 | additional random offset to the old points. 236 |

237 |

238 | I added this capability to my program. The -X and -Y parameters 239 | trade off the two methods if you leave them at 0.0 (the default) you get 240 | my algorithm. If you set them to 1.0 you get Paul's and values 241 | in-between give you a mixture of the two, i.e. a weighted average of the 242 | new points and the old value of the point. 243 |

244 |

How well does this all work

245 | The relative importance of the different algorithms can easily be seen 246 | if we remove the random element from the algorithm and replace the 247 | gaussian random number with a constant value. Without any random 248 | variation we should get a completely smooth surface. Without any 249 | regeneration steps or cross updates we get a surface 250 | consisting only of creases. 251 |
252 | A surface that looks like a quilt 253 |
254 | 255 | The addition of cross updates generate 256 | a very interesting surface. 257 |
258 | a surface that looks like a cushion 259 |
260 | 261 | This is an 262 | improvement as the surface has better rotational symmetry but it still 263 | has significant artifacts. These are completely missing when regeneration 264 | steps are used. 265 | 266 |

Pipelining

267 |

268 | The other trick I came up with was to pipeline the code. This is also 269 | responsible for much of the speed because it reduces swapping and 270 | improves cache use. I don't think that anyone else does this but 271 | the idea is straightforward once you think of it. 272 |

273 |

274 | If you think of the normal algorithm it is possible to add extra detail 275 | to a region of the surface without adding this level of detail to the 276 | entire surface. Each iteration of the algorithm increases the number of 277 | squares by 4. You can then add further detail to a restricted region of 278 | the surface by only applying the next level of recursion to a subset of 279 | these squares. Obviously some squares you choose not to update 280 | will end up partially updated because they share sides with updated 281 | squares. 282 |

283 |

284 | As an aside this selective updating allows you to zoom-in on a surface 285 | efficiently. You don't bother updating squares outside of your field of 286 | view and you keep adding more detail to the squares you can see until 287 | the sides of the smallest level squares subtends less than a maximum 288 | angle at your point of view (i.e. the sides always look short). 289 |

290 |

291 | What I do in xmountains is slightly different. 292 | I only perform updates necessary to fully update the left hand 293 | row of squares. These fully updated points are used to generate a column 294 | of pixels in the output and then discarded. The new left hand edge is 295 | not fully updated so additional updates are now required. 296 | Imagine I have a level-1 surface as follows: 297 |

298 | 1   1   1
299 | 
300 | 1   1   1
301 | 
302 | 1   1   1
303 | 
304 | 
305 | And that I have some method of generating new points on the right hand 306 | side of this surface (I will show how I do this later but for the time 307 | being assume this is the top iteration level and we can generate new 308 | points by applying random offsets to a constant value). 309 |

310 |

311 | I can use these points to fill in part of the left hand squares 312 |

313 | 1 2 1   1
314 | 2 2
315 | 1 2 1   1
316 | 2 2
317 | 1 2 1   1
318 | 
319 | 
320 | Now scroll everything to the left 321 |
322 | 1   1
323 | 
324 | 1   1
325 | 
326 | 1   1
327 | 
328 | 
329 | and add in a new third column on the right hand side 330 |
331 | 1   1   1
332 | 
333 | 1   1   1
334 | 
335 | 1   1   1
336 | 
337 | 
338 | This returns us to our original state. This process can be repeated 339 | indefinitely. For each column of points it inputs on the right it outputs 340 | 2 columns on the left with level of detail doubled. If you want to 341 | perform N levels of update then you chain together N of these steps. 342 | If you want to use a more complicated update (For example the 343 | regeneration steps and the cross update) then the same basic approach 344 | applies but the details get more complicated. 345 | In the xmountains the equivalent to the step described above is a 346 | routine called next_strip. 347 | 348 |

xmountain command line flags

349 |
xmountains: version 2.3
350 | usage: xmountains -[bqgdPEmMrBZIASFTCapcevfRltxsXYH]
351 |  -b       [false] use root window 
352 |  -q       [false] reset root window on exit
353 |  -g string     window geometry
354 |  -d string     display
355 |  -P filename   write PID to file
356 |  -E       [false] toggle explicit expose events 
357 |  -m       [false] print map 
358 |  -M       [false] implement reflections 
359 |  -r int   [20] # columns before scrolling 
360 |  -B int   [80] # shades in a colour band
361 |  -n int   [245] # number of colours
362 |  -Z int   [10] time to sleep before scrolling
363 |  -I float [40.000000] vertical angle of light 
364 |  -A float [0.000000] horizontal angle of light 
365 |  -S float [0.600000] vertical stretch 
366 |  -T float [0.500000] vertical shift 
367 |  -W float [0.000000] sealevel 
368 |  -F int   [1] reduce variation in the foreground 
369 |  -G float [-1.000000] average foreground height 
370 |  -C float [0.300000] contour parameter 
371 |  -a float [2.500000] altitude of viewpoint 
372 |  -p float [4.000000] distance of viewpoint 
373 |  -c float [1.000000] contrast
374 |  -e float [0.300000] ambient light level
375 |  -v float [0.600000] vertical light level
376 | Fractal options:
377 |  -f float [0.650000] fractal dimension 
378 |  -R int   [0] rng seed, read clock if 0 
379 |  -l int   [10] # levels of recursion 
380 |  -t int   [2] # non fractal iterations 
381 |  -x       [true] cross update 
382 |  -s       [1] smoothing (0-7)
383 |  -X float [0.000000] fraction of old value for rg2 & rg3
384 |  -Y float [0.000000] fraction of old value for rg1
385 |  -H            print short description of algorithm.
386 | 
387 | 388 |

X window graphics

389 | The algorithms and code for xmountains were originally developed for to 390 | drive particular graphics hardware and then ported to the X-window 391 | system. This history can still be seen in the following ways 392 | 393 |
    394 |
  • All the options are given as command line flags. 395 |
  • The code assume a CLUT based colour model rather than direct RGB values. 396 |
397 | 398 | Most of the suggestions I get for changes to xmountains involve either 399 | adding a X control panel to set parameters or implementing 24-bit 400 | graphics. Actually neither of these makes a great deal of sense. 401 |

402 | To save memory the program does not retain any knowledge of currently 403 | displayed surface. The only information that is retained is the final bitmap 404 | image. This makes it very difficult to change the viewpoint while the 405 | program is running (though you could probably get away with slow gradual 406 | changes). 407 |

408 | The program can already utilise 24-bit colour displays the default parameters 409 | are set to use less than 256 colours but the -B or -n flags can be used 410 | to increase the number of colours. The quality of the final image 411 | remains pretty much the same though because there are already 80 shades 412 | of each base colour. If you only ever run on a 24-bit display you may 413 | want to try increasing the number of base colours by increasing N_BANDS 414 | in paint.h and modifying the set_clut routine in artist.c 415 | 416 |

417 | 418 |

419 | -------------------------------------------------------------------------------- /docs/cone.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spbooth/xmountains/5ed87c3b68c91dbae93290182e2c9d247223cae3/docs/cone.gif -------------------------------------------------------------------------------- /docs/crease.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spbooth/xmountains/5ed87c3b68c91dbae93290182e2c9d247223cae3/docs/crease.gif -------------------------------------------------------------------------------- /docs/cushion.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spbooth/xmountains/5ed87c3b68c91dbae93290182e2c9d247223cae3/docs/cushion.gif -------------------------------------------------------------------------------- /docs/google4108777847be7f63.html: -------------------------------------------------------------------------------- 1 | google-site-verification: google4108777847be7f63.html -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Xmountains site 4 | 5 | 10 |

This is the xmountains home page

11 | 12 | 13 | 14 | 15 | 16 | A fractal landscape 17 | 18 |
19 | 22 | 23 |

24 | Xmountains is a fractal terrain generator written by Stephen Booth 25 | 26 | There is also a 27 | 28 | Java version, a Android and a Javascript version of this code. 29 | 30 | 31 |

32 |

33 | If you find any bugs send me an Email 34 |

35 |

36 | 37 | There is a page describing how the program works. 38 |

39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /docs/normal.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spbooth/xmountains/5ed87c3b68c91dbae93290182e2c9d247223cae3/docs/normal.gif -------------------------------------------------------------------------------- /docs/quilt.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spbooth/xmountains/5ed87c3b68c91dbae93290182e2c9d247223cae3/docs/quilt.gif -------------------------------------------------------------------------------- /global.c: -------------------------------------------------------------------------------- 1 | #include "crinkle.h" 2 | #include "paint.h" 3 | 4 | Fold *top; 5 | int levels = 10; 6 | int stop = 2; 7 | int smooth = 1; 8 | int cross = TRUE; 9 | int slope = 1; 10 | int snooze_time = 10; 11 | int n_col=DEF_COL; 12 | int band_size=BAND_SIZE; 13 | int request_clear = FALSE; 14 | #ifdef USE_E_EVENTS 15 | int e_events = TRUE; 16 | #else 17 | int e_events = FALSE; 18 | #endif 19 | Height start=0.0; /* starting value for the surface */ 20 | Height mean=0.0; /* mean value of surface */ 21 | Height varience; /* rough estimate of the height of the range */ 22 | Height shift=0.5; 23 | Height delta_shadow; /* offset of shadow at each step */ 24 | float stretch=0.6; 25 | float contour = 0.3; 26 | float ambient = 0.3; 27 | float contrast = 1.0; 28 | float vfract = 0.6; 29 | float altitude = 2.5; 30 | float distance = 4.0; 31 | double phi=(40.0 * PI)/180.0; 32 | double alpha=0.0; 33 | 34 | double shadow_slip; 35 | double shadow_register=0.0; 36 | double cos_phi; 37 | double sin_phi; 38 | double tan_phi; 39 | double x_fact; 40 | double y_fact; 41 | Height sealevel = 0.0; 42 | Height forceheight = -1.0; 43 | int width; /* width of the landscape, (function of levels) */ 44 | int seed=0; /* zero means read the clock */ 45 | 46 | /* 47 | * viewport parameters 48 | */ 49 | int height; /* height of the screen */ 50 | double vangle; /* view angle 0 == horizontal 51 | *increase to look down 52 | */ 53 | double tan_vangle; 54 | float vscale; 55 | float viewpos; 56 | float viewheight; /* height of viewpoint */ 57 | float focal; /* focal length, calc to preserve aspect ratio */ 58 | 59 | Height *shadow; /* height of the shadows */ 60 | Height *a_strip, *b_strip; /* the two most recent strips */ 61 | 62 | -------------------------------------------------------------------------------- /global.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBAL 2 | #define GLOBAL 3 | 4 | extern Fold *top; 5 | extern int levels; 6 | extern int stop; 7 | extern int smooth; 8 | extern int cross; 9 | extern int slope; 10 | extern int snooze_time; 11 | extern int request_clear; 12 | extern int n_col; 13 | extern int band_size; 14 | extern int e_events; 15 | extern float mix; 16 | extern float midmix; 17 | extern float fdim; 18 | extern Height start; 19 | extern Height mean; 20 | extern Height varience; 21 | extern Height shift; 22 | extern Height delta_shadow; 23 | extern float stretch; 24 | extern float contour; 25 | extern float ambient; 26 | extern float contrast; 27 | extern float vfract; 28 | extern float altitude; 29 | extern float distance; 30 | extern double phi; 31 | extern double alpha; 32 | extern double shadow_slip; 33 | extern double shadow_register; 34 | extern double cos_phi; 35 | extern double sin_phi; 36 | extern double tan_phi; 37 | extern double x_fact; 38 | extern double y_fact; 39 | extern Height sealevel; 40 | extern Height forceheight; 41 | extern int width; 42 | extern int seed; 43 | extern int height; 44 | extern double vangle; 45 | extern double tan_vangle; 46 | extern float vscale; 47 | extern float viewpos; 48 | extern float viewheight; 49 | extern float focal; 50 | extern Height *shadow; 51 | extern Height *a_strip, *b_strip; 52 | 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /mountainbench.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "crinkle.h" 5 | 6 | Parm fold_param; 7 | 8 | #include 9 | 10 | long get_millis() 11 | { 12 | 13 | struct timeval ts; 14 | long t; 15 | int err; 16 | 17 | err = gettimeofday(&ts, NULL); 18 | 19 | t = (ts.tv_sec *1000) + ts.tv_usec/1000 ; 20 | 21 | return t; 22 | 23 | } 24 | 25 | void main(int argc, char *argv[]){ 26 | Fold *f; 27 | int i; 28 | double sum; 29 | Strip *s; 30 | long stop,start; 31 | 32 | 33 | seed_uni(121265); 34 | f = make_fold(NULL,&fold_param,10,2,1.0); 35 | for(i=0;i<1000;i++){ 36 | s = next_strip(f); 37 | free_strip(s); 38 | } 39 | start = get_millis(); 40 | for(i=0;i<1000;i++){ 41 | s = next_strip(f); 42 | free_strip(s); 43 | } 44 | stop = get_millis(); 45 | printf("time was %ld \n",(stop - start)); 46 | } 47 | -------------------------------------------------------------------------------- /paint.h: -------------------------------------------------------------------------------- 1 | /* $Id: paint.h,v 1.16 2009/08/28 09:09:17 spb Exp $ */ 2 | #ifndef PAINT 3 | #define PAINT 4 | 5 | #include "crinkle.h" 6 | 7 | /* colour code definitions */ 8 | typedef int Col; 9 | typedef unsigned short Gun; 10 | 11 | typedef struct graph{ 12 | int graph_height; /* height of display */ 13 | int graph_width ; /* width of display */ 14 | 15 | int pixmap_width; /* width of pixmap buffer */ 16 | 17 | int width; /* width of terrain strip */ 18 | 19 | float ambient; /* level of ambient light */ 20 | float contrast; /* contrast, 21 | * increases or decreases effect of cosine rule */ 22 | float contour; 23 | float vfract; /* relative strength of vertical light relative 24 | * to the main light source 25 | */ 26 | float altitude; 27 | float distance; 28 | double phi; /* angle of the light (vertical plane)*/ 29 | double alpha; /* angle of the light (horizontal plane) 30 | * must have -pi/4 < alpha < pi/4 31 | */ 32 | Height base_shift; /* offset from calcalt to artist coordinates */ 33 | Height sealevel; 34 | double stretch; /* vertical stretch */ 35 | int n_col; 36 | int band_size; 37 | int levels; 38 | int stop; 39 | int map; 40 | int reflec; 41 | int repeat; 42 | int pos; 43 | int scroll; 44 | }Graph; 45 | 46 | #define BLACK 0 47 | #define WHITE 1 48 | #define SEA_LIT 2 49 | #define SEA_UNLIT 3 50 | #define SKY 4 51 | #define BAND_BASE 5 52 | #ifndef BAND_SIZE 53 | #define BAND_SIZE 80 54 | #endif 55 | #define N_BANDS 3 56 | #define DEF_COL (BAND_BASE + (N_BANDS * BAND_SIZE)) 57 | #define MIN_COL (BAND_BASE + (N_BANDS * 2)) 58 | #define COL_RANGE 65535 59 | 60 | #define PI 3.14159265 61 | 62 | #ifdef ANSI 63 | void set_clut(int, Gun *, Gun *, Gun *); 64 | Height *extract(Strip *s); 65 | void init_artist_variables(); 66 | Col get_col(Height p, Height p_plus_x, Height p_plus_y, Height shadow); 67 | Col *makemap(Height *a, Height *b, Height *shadow); 68 | Col *camera(Height *a, Height *b, Height *shadow); 69 | Col *mirror(Height *a, Height *b, Height *shadow); 70 | int project( int x , Height y ); 71 | #else 72 | void set_clut(); 73 | Height *extract(); 74 | void init_artist_variables(); 75 | Col get_col(); 76 | Col *makemap(); 77 | Col *camera(); 78 | Col *mirror(); 79 | int project(); 80 | #endif 81 | 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /patchlevel.h: -------------------------------------------------------------------------------- 1 | #define PATCHLEVEL 10 2 | -------------------------------------------------------------------------------- /print_alg.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define P(A) fprintf(stderr,"%s\n",A) 4 | void print_algorithm() 5 | { 6 | P("This program uses a modified form of the mid-point displacement algorithm"); 7 | P(""); 8 | P("The mid-point displacement algorithm is a recursive algorithm, each iteration"); 9 | P("doubles the resolution of the grid. This is done in 2 stages."); 10 | P(""); 11 | P("A B A B A F B"); 12 | P(" stage1 stage2"); 13 | P(" ---------> E --------> G E H"); 14 | P(""); 15 | P("C D C D C I D"); 16 | P(""); 17 | P("The new points are generated by taking an average of the surrounding points"); 18 | P("and adding a random offset."); 19 | P("The modifications to the standard algorithm are as follows:"); 20 | P("There are three optional regeneration steps to reduce \"creasing\". A"); 21 | P("regeneration step recalculates the height of existing points using an"); 22 | P("average and offset from a newer generation of points. The three"); 23 | P("regeneration steps are:"); 24 | P(" rg1: recalculate corner points (A,B,C,D) from the midpoints (E)"); 25 | P(" after the stage1 update."); 26 | P(" rg2: recalculate midpoints (E) from the edge points (F,G,H,I)"); 27 | P(" after the stage2 update"); 28 | P(" rg3: recalculate corner points (A,B,C,D) from the edge points (F,G,H,I)"); 29 | P(" after the stage2 update"); 30 | P("The regeneration stages are turned on by the smoothing parameter (-s flag)"); 31 | P(""); 32 | P(" flag rg3 rg2 rg1"); 33 | P(" 0 off off off"); 34 | P(" 1 on off off"); 35 | P(" 2 off on off"); 36 | P(" 3 on on off"); 37 | P(" 4 off off on"); 38 | P(" 5 on off on"); 39 | P(" 6 off on on"); 40 | P(" 7 on on on"); 41 | P(""); 42 | P("When performing the regeneration steps the random offset is added to a"); 43 | P("weighted average of the previous value of the point and a the average of"); 44 | P("the new points. The weighting factors are controlled by the -X and -Y flags."); 45 | P(""); 46 | P("The -x flag (cross update) controls whether the midpoints (E) are included"); 47 | P("in the average when performing the stage2 update or if only the corner"); 48 | P("points are used."); 49 | P(""); 50 | } 51 | -------------------------------------------------------------------------------- /random.c: -------------------------------------------------------------------------------- 1 | /* 2 | * C version of Marsaglia's UNI random number generator 3 | * More or less transliterated from the Fortran -- with 1 bug fix 4 | * Hence horrible style 5 | * 6 | * Features: 7 | * ANSI C 8 | * not callable from Fortran (yet) 9 | */ 10 | 11 | 12 | 13 | char uni_id[] = "$Id: random.c,v 1.7 2009/08/28 09:09:17 spb Exp $" ; 14 | /* 15 | * Global variables for rstart & uni 16 | */ 17 | 18 | #define PARANOID 19 | /* need types and time */ 20 | #include 21 | /* #include 22 | * #include 23 | */ 24 | #include 25 | #include 26 | #include 27 | typedef struct 28 | { 29 | float u[98]; 30 | float c; 31 | float cd; 32 | float cm; 33 | int ui; 34 | int uj; 35 | } 36 | Uni_save; 37 | 38 | Uni_save uni_data; 39 | 40 | float uni() 41 | { 42 | float luni; /* local variable for uni */ 43 | 44 | luni = uni_data.u[uni_data.ui] - uni_data.u[uni_data.uj]; 45 | if (luni < 0.0) 46 | luni += 1.0; 47 | uni_data.u[uni_data.ui] = luni; 48 | if (--uni_data.ui == 0) 49 | uni_data.ui = 97; 50 | if (--uni_data.uj == 0) 51 | uni_data.uj = 97; 52 | if ((uni_data.c -= uni_data.cd) < 0.0) 53 | uni_data.c += uni_data.cm; 54 | if ((luni -= uni_data.c) < 0.0) 55 | luni += 1.0; 56 | return ((float) luni); 57 | } 58 | 59 | void rstart(i,j,k,l) 60 | int i; 61 | int j; 62 | int k; 63 | int l; 64 | { 65 | int ii, jj, m; 66 | float s, t; 67 | 68 | for (ii = 1; ii <= 97; ii++) { 69 | s = 0.0; 70 | t = 0.5; 71 | for (jj = 1; jj <= 24; jj++) { 72 | m = ((i*j % 179) * k) % 179; 73 | i = j; 74 | j = k; 75 | k = m; 76 | l = (53*l+1) % 169; 77 | if (l*m % 64 >= 32) 78 | s += t; 79 | t *= 0.5; 80 | } 81 | uni_data.u[ii] = s; 82 | } 83 | uni_data.c = 362436.0 / 16777216.0; 84 | uni_data.cd = 7654321.0 / 16777216.0; 85 | uni_data.cm = 16777213.0 / 16777216.0; 86 | uni_data.ui = 97; /* There is a bug in the original Fortran version */ 87 | uni_data.uj = 33; /* of UNI -- i and j should be SAVEd in UNI() */ 88 | } 89 | 90 | 91 | /* ~seed_uni: this takes a single integer in the range 92 | * 0 <= ijkl <= 900 000 000 93 | * and produces the four smaller integers needed for rstart. It is 94 | * based on the ideas contained in the RMARIN subroutine in 95 | * F. James, "A Review of Pseudorandom Number Generators", 96 | * Comp. Phys. Commun. Oct 1990, p.340 97 | * To reduce the modifications to the existing code, seed_uni now 98 | * takes the role of a preprocessor for rstart. 99 | * 100 | */ 101 | 102 | void seed_uni(ijkl) 103 | int ijkl; 104 | { 105 | int i, j, k, l, ij, kl; 106 | 107 | if( ijkl == 0 ) 108 | { 109 | ijkl = time((time_t *) 0); 110 | ijkl %= 900000000; 111 | } 112 | /* check ijkl is within range */ 113 | if( (ijkl < 0) || (ijkl > 900000000) ) 114 | { 115 | fprintf(stderr,"seed_uni: ijkl = %d -- out of range\n\n", ijkl); 116 | exit(3); 117 | } 118 | 119 | 120 | /* decompose the long integer into the the equivalent four 121 | * integers for rstart. This should be a 1-1 mapping 122 | * ijkl <--> (i, j, k, l) 123 | * though not quite all of the possible sets of (i, j, k, l) 124 | * can be produced. 125 | */ 126 | 127 | ij = ijkl/30082; 128 | kl = ijkl - (30082 * ij); 129 | 130 | i = ((ij/177) % 177) + 2; 131 | j = (ij % 177) + 2; 132 | k = ((kl/169) % 178) + 1; 133 | l = kl % 169; 134 | 135 | #ifdef PARANOID 136 | if( (i <= 0) || (i > 178) ) 137 | { 138 | fprintf(stderr,"seed_uni: i = %d -- out of range\n\n", i); 139 | exit(3); 140 | } 141 | 142 | if( (j <= 0) || (j > 178) ) 143 | { 144 | fprintf(stderr,"seed_uni: j = %d -- out of range\n\n", j); 145 | exit(3); 146 | } 147 | 148 | if( (k <= 0) || (k > 178) ) 149 | { 150 | fprintf(stderr,"seed_uni: k = %d -- out of range\n\n", k); 151 | exit(3); 152 | } 153 | 154 | if( (l < 0) || (l > 168) ) 155 | { 156 | fprintf(stderr,"seed_uni: l = %d -- out of range\n\n", l); 157 | exit(3); 158 | } 159 | 160 | if (i == 1 && j == 1 && k == 1) 161 | { 162 | fprintf(stderr,"seed_uni: 1 1 1 not allowed for 1st 3 seeds\n\n"); 163 | exit(4); 164 | } 165 | #endif 166 | 167 | 168 | rstart(i, j, k, l); 169 | 170 | } 171 | 172 | float gaussian() 173 | { 174 | double pi = 3.1415926536, two = 2.0, zero = 0.0; 175 | double ran1, ran2; 176 | 177 | do { 178 | ran1 = (double) uni(); 179 | } while (ran1 == zero); 180 | 181 | ran2 = (double) uni(); 182 | return (float) ( sqrt(-two * log(ran1)) * cos(two * pi * ran2) ); 183 | } 184 | 185 | -------------------------------------------------------------------------------- /vroot.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 2 -*- */ 2 | /*****************************************************************************/ 3 | /** Copyright 1991 by Andreas Stolcke **/ 4 | /** Copyright 1990 by Solbourne Computer Inc. **/ 5 | /** Longmont, Colorado **/ 6 | /** **/ 7 | /** All Rights Reserved **/ 8 | /** **/ 9 | /** Permission to use, copy, modify, and distribute this software and **/ 10 | /** its documentation for any purpose and without fee is hereby **/ 11 | /** granted, provided that the above copyright notice appear in all **/ 12 | /** copies and that both that copyright notice and this permis- **/ 13 | /** sion notice appear in supporting documentation, and that the **/ 14 | /** name of Solbourne not be used in advertising **/ 15 | /** in publicity pertaining to distribution of the software without **/ 16 | /** specific, written prior permission. **/ 17 | /** **/ 18 | /** ANDREAS STOLCKE AND SOLBOURNE COMPUTER INC. DISCLAIMS ALL WARRANTIES **/ 19 | /** WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF **/ 20 | /** MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ANDREAS STOLCKE **/ 21 | /** OR SOLBOURNE BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL **/ 22 | /** DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 23 | /** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 24 | /** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 25 | /** OR PERFORMANCE OF THIS SOFTWARE. **/ 26 | /*****************************************************************************/ 27 | /* 28 | * vroot.h -- Virtual Root Window handling header file 29 | * 30 | * This header file redefines the X11 macros RootWindow and DefaultRootWindow, 31 | * making them look for a virtual root window as provided by certain `virtual' 32 | * window managers like swm and tvtwm. If none is found, the ordinary root 33 | * window is returned, thus retaining backward compatibility with standard 34 | * window managers. 35 | * The function implementing the virtual root lookup remembers the result of 36 | * its last invocation to avoid overhead in the case of repeated calls 37 | * on the same display and screen arguments. 38 | * The lookup code itself is taken from Tom LaStrange's ssetroot program. 39 | * 40 | * Most simple root window changing X programs can be converted to using 41 | * virtual roots by just including 42 | * 43 | * #include 44 | * 45 | * after all the X11 header files. It has been tested on such popular 46 | * X clients as xphoon, xfroot, xloadimage, and xaqua. 47 | * It also works with the core clients xprop, xwininfo, xwd, and editres 48 | * (and is necessary to get those clients working under tvtwm). 49 | * It does NOT work with xsetroot; get the xsetroot replacement included in 50 | * the tvtwm distribution instead. 51 | * 52 | * Andreas Stolcke , 9/7/90 53 | * - replaced all NULL's with properly cast 0's, 5/6/91 54 | * - free children list (suggested by Mark Martin ), 5/16/91 55 | * - include X11/Xlib.h and support RootWindowOfScreen, too 9/17/91 56 | * 57 | * Jamie Zawinski , 28-Apr-1997 58 | * - use ANSI C 59 | * 60 | * Jamie Zawinski , 3-Sep-2003 61 | * - if the environment variable "XSCREENSAVER_WINDOW" is set, use that 62 | * as the root window instead of searching for __SWM_VROOT. 63 | */ 64 | 65 | #ifndef _VROOT_H_ 66 | #define _VROOT_H_ 67 | #define _XSCREENSAVER_VROOT_H_ 68 | 69 | #if !defined(lint) && !defined(SABER) 70 | static const char vroot_rcsid[] = 71 | "#Id: vroot.h,v 1.5 2003/09/04 01:04:38 jwz Exp #" "\n" 72 | "#Id: vroot.h,v 1.4 1991/09/30 19:23:16 stolcke Exp stolcke #"; 73 | #endif 74 | 75 | #include 76 | #include 77 | #include 78 | 79 | #include 80 | 81 | static Window 82 | #ifdef __STDC__ /* ANSIfication added by jwz, to avoid superfluous warnings. */ 83 | VirtualRootWindowOfScreen(Screen *screen) 84 | #else /* !__STDC__ */ 85 | VirtualRootWindowOfScreen(screen) Screen *screen; 86 | #endif /* !__STDC__ */ 87 | { 88 | static Screen *save_screen = (Screen *)0; 89 | static Window root = (Window)0; 90 | 91 | if (screen != save_screen) { 92 | Display *dpy = DisplayOfScreen(screen); 93 | Atom __SWM_VROOT = None; 94 | int i; 95 | Window rootReturn, parentReturn, *children; 96 | unsigned int numChildren; 97 | 98 | /* first check for a hex or decimal window ID in the environment */ 99 | const char *xss_id = getenv("XSCREENSAVER_WINDOW"); 100 | if (xss_id && *xss_id) { 101 | unsigned long id = 0; 102 | char c; 103 | if (1 == sscanf (xss_id, " 0x%lx %c", &id, &c) || 104 | 1 == sscanf (xss_id, " %lu %c", &id, &c)) { 105 | root = (Window) id; 106 | save_screen = screen; 107 | return root; 108 | } 109 | } 110 | 111 | root = RootWindowOfScreen(screen); 112 | 113 | /* go look for a virtual root */ 114 | __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); 115 | if (XQueryTree(dpy, root, &rootReturn, &parentReturn, 116 | &children, &numChildren)) { 117 | for (i = 0; i < numChildren; i++) { 118 | Atom actual_type; 119 | int actual_format; 120 | unsigned long nitems, bytesafter; 121 | Window *newRoot = (Window *)0; 122 | 123 | if (XGetWindowProperty(dpy, children[i], 124 | __SWM_VROOT, 0, 1, False, XA_WINDOW, 125 | &actual_type, &actual_format, 126 | &nitems, &bytesafter, 127 | (unsigned char **) &newRoot) == Success 128 | && newRoot) { 129 | root = *newRoot; 130 | break; 131 | } 132 | } 133 | if (children) 134 | XFree((char *)children); 135 | } 136 | 137 | save_screen = screen; 138 | } 139 | 140 | return root; 141 | } 142 | 143 | #undef RootWindowOfScreen 144 | #define RootWindowOfScreen(s) VirtualRootWindowOfScreen(s) 145 | 146 | #undef RootWindow 147 | #define RootWindow(dpy,screen) VirtualRootWindowOfScreen(ScreenOfDisplay(dpy,screen)) 148 | 149 | #undef DefaultRootWindow 150 | #define DefaultRootWindow(dpy) VirtualRootWindowOfScreen(DefaultScreenOfDisplay(dpy)) 151 | 152 | #endif /* _VROOT_H_ */ 153 | -------------------------------------------------------------------------------- /xmountains.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "crinkle.h" 9 | #include "paint.h" 10 | #include "patchlevel.h" 11 | #include "copyright.h" 12 | 13 | #define VERSION 2 14 | #define SIDE 1.0 15 | 16 | char scroll_Id[]="$Id: xmountains.c,v 1.43 2010/12/17 09:25:36 spb Exp $"; 17 | extern Graph g; 18 | Parm fold_param; 19 | extern char *display; 20 | extern char *geom; 21 | 22 | extern int swosh; 23 | 24 | /* {{{ my version on getopt*/ 25 | int optind=1; 26 | char *optarg; 27 | int opterr=1; 28 | 29 | int my_getopt (int argc, char **argv, char *pat) 30 | { 31 | char *flag; 32 | 33 | if((optind >= argc) || (argv[optind][0] != '-')) 34 | { 35 | return -1; 36 | } 37 | if( argv[optind][1] == '-' ) 38 | { 39 | optind++; 40 | return -1; 41 | } 42 | if( argv[optind][1] == ':' ) 43 | { 44 | if( opterr ) 45 | { 46 | fprintf(stderr,"getopt: found \":\" in optstring\n"); 47 | } 48 | return '?'; 49 | } 50 | for(flag=pat;*flag;flag++) 51 | { 52 | if( *flag == argv[optind][1] ) 53 | { 54 | optind++; 55 | if( *(flag+1) == ':' ) 56 | { 57 | if(optind >= argc ) 58 | { 59 | if( opterr ) 60 | { 61 | fprintf(stderr,"getopt: no option for flag %c\n",*flag); 62 | } 63 | return '?'; 64 | } 65 | optarg = argv[optind]; 66 | optind++; 67 | } 68 | return *flag; 69 | } 70 | 71 | } 72 | if( opterr ) 73 | { 74 | fprintf(stderr,"getopt: flag %s not recognized\n",argv[optind]); 75 | } 76 | optind++; 77 | return '?'; 78 | } 79 | /* }}} */ 80 | 81 | double atof(); 82 | #ifdef ANSI 83 | void init_graphics (int, Window, int,int, Graph *, Gun *, Gun *, Gun *); 84 | void clear_col( int ); 85 | void finish_graphics(); 86 | void plot_pixel (int, int, unsigned char); 87 | void scroll_screen ( int ); 88 | void zap_events(); 89 | #else 90 | void init_graphics (); 91 | void clear_col(); 92 | void finish_graphics(); 93 | void plot_pixel (); 94 | void scroll_screen (); 95 | void zap_events(); 96 | #endif 97 | 98 | void finish_prog(); 99 | 100 | int s_height=768, s_width=1024; 101 | int mapwid; 102 | 103 | /* Go through argv and find and extract any "-window-id NNNN" or 104 | "-window-id 0xXXXX" option. (Maybe this can be done with 105 | getopt, but I can't be bothered to figure it out.) 106 | */ 107 | static unsigned long window_id_kludge (int *argcP, char **argv) 108 | { 109 | unsigned long id = 0; 110 | int i; 111 | int j; 112 | for (i = 1; i < *argcP; i++) 113 | { 114 | if (!strcmp (argv[i], "-window-id") && i+1 < *argcP) 115 | { 116 | char c; 117 | char *str = argv[i+1]; 118 | 119 | if (1 != ((str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) 120 | ? sscanf (str+2, "%lx %c", &id, &c) 121 | : sscanf (str, "%lu %c", &id, &c))) 122 | continue; 123 | 124 | /* remove "-window-id xxx" from the arglist */ 125 | for (j = i+2; j < *argcP; j++) 126 | argv[j-2] = argv[j]; 127 | *argcP -= 2; 128 | } 129 | } 130 | return id; 131 | } 132 | 133 | 134 | void init_parameters(); 135 | void print_algorithm(); 136 | void seed_uni(int ijkl); 137 | void plot_column(Graph *g); 138 | 139 | /* Note, Robbie Hatley, 2024-07-16: When installing xmountains as an AUR package, 140 | "main" no-longer compiles without being declared "int", presumably due to 141 | recent changes in gcc. */ 142 | int main (int argc, char **argv) 143 | { 144 | int i; 145 | int e_events=FALSE; 146 | int request_clear=FALSE; 147 | int smooth=1; 148 | int snooze=10; 149 | int root= 0; 150 | unsigned long window_id = 0; 151 | int seed=0; 152 | 153 | int c, errflg=0; 154 | extern char *optarg; 155 | extern int optind; 156 | char *mesg[2]; 157 | Gun *clut[3]; 158 | FILE *pidfile; 159 | swosh = 0; /* default is ! -w */ 160 | 161 | init_parameters(); 162 | /* {{{ handle command line flags*/ 163 | 164 | window_id = window_id_kludge (&argc, argv); 165 | 166 | mesg[0]="false"; 167 | mesg[1]="true"; 168 | while((c = my_getopt(argc,argv,"whbxmqMEHl:r:f:t:I:A:S:T:W:C:a:p:B:n:R:g:d:c:e:v:Z:s:X:Y:P:F:G:"))!= -1) 169 | { 170 | switch(c){ 171 | case 'w': 172 | swosh = TRUE; /* update window only when pixmap is complete */ 173 | break; 174 | case 'b': 175 | root = 1- root; 176 | break; /* run on root window */ 177 | case 'x': 178 | fold_param.cross = 1- fold_param.cross; 179 | break; /* use cross updates */ 180 | case 'E': 181 | e_events = 1 - e_events; 182 | break; 183 | case 'q': 184 | request_clear = 1 - request_clear; 185 | break; 186 | case 'm': /* Map view only */ 187 | g.map = 1 - g.map; 188 | break; 189 | case 'M': /* put in reflections */ 190 | g.reflec = 1 - g.reflec; 191 | break; 192 | case 'l': /* Set # levels of recursion */ 193 | g.levels = atoi( optarg ); 194 | if( g.levels < 2 ) 195 | { 196 | g.levels = 2; 197 | } 198 | break; 199 | case 'F': /* Set # levels to force front to mean */ 200 | fold_param.force_front = atoi( optarg ); 201 | break; 202 | case 's': /* Set smoothing parameter */ 203 | smooth = atoi( optarg ); 204 | fold_param.rg1 = smooth & 1; 205 | fold_param.rg2 = smooth & 2; 206 | fold_param.rg3 = smooth & 4; 207 | break; 208 | case 't': /* Set width of lowest level */ 209 | g.stop = atoi( optarg ); 210 | if( g.stop < 0 ) 211 | { 212 | g.stop = 0; 213 | } 214 | break; 215 | case 'r': 216 | g.repeat = atoi( optarg ); 217 | if( g.repeat < 0 ) 218 | { 219 | g.repeat = -g.repeat; 220 | i= -1; 221 | }else{ 222 | i=1; 223 | } 224 | /* we want repeat to be a multiple of 2 as we are using 225 | * a textured field for the sky. 226 | */ 227 | g.repeat = i*(2 * ((g.repeat +1)/2)); 228 | break; 229 | case 'B': /* set band_size */ 230 | g.band_size = atoi( optarg ); 231 | if( g.band_size < 2 ) 232 | { 233 | g.band_size=2; 234 | } 235 | g.n_col = (BAND_BASE + (N_BANDS * g.band_size)); 236 | break; 237 | case 'n': /* set max number of colours */ 238 | g.n_col = atoi( optarg ); 239 | if( g.n_col < MIN_COL ) 240 | { 241 | g.n_col = MIN_COL; 242 | } 243 | g.band_size = (g.n_col - BAND_BASE)/N_BANDS; 244 | g.n_col = (BAND_BASE + (N_BANDS * g.band_size)); 245 | break; 246 | case 'R': /* set seed, read clock if 0 */ 247 | seed = atoi( optarg ); 248 | break; 249 | case 'Z': /* put sleep into wait events */ 250 | snooze = atoi( optarg ); 251 | if( snooze < 0 ) 252 | { 253 | snooze = 0; 254 | } 255 | break; 256 | case 'P': 257 | pidfile = fopen(optarg,"w"); 258 | if( pidfile ) 259 | { 260 | fprintf(pidfile,"%d\n",getpid()); 261 | fclose(pidfile); 262 | }else{ 263 | perror(optarg); 264 | } 265 | break; 266 | case 'f': /* set fractal dimension */ 267 | fold_param.fdim = atof( optarg ); 268 | if( fold_param.fdim < 0.5 ) 269 | { 270 | fold_param.fdim=0.5; 271 | } 272 | if( fold_param.fdim > 1.0 ) 273 | { 274 | fold_param.fdim=1.0; 275 | } 276 | break; 277 | case 'I': /* set Illumination angle */ 278 | g.phi = ((PI * atof( optarg ))/180.0); 279 | if ( g.phi < 0.0 ) 280 | { 281 | g.phi=0.0; 282 | } 283 | if( g.phi > PI/2.0 ) 284 | { 285 | g.phi = PI/2.0; 286 | } 287 | break; 288 | case 'A': /* set Illumination angle (horizontal)*/ 289 | g.alpha = ((PI * atof( optarg ))/180.0); 290 | if( g.alpha < -PI/3.0 ) 291 | { 292 | g.alpha = -PI/3.0; 293 | } 294 | if( g.alpha > PI/3.0 ) 295 | { 296 | g.alpha = PI/3.0; 297 | } 298 | break; 299 | case 'X': /* set mix */ 300 | fold_param.mix = atof( optarg ); 301 | break; 302 | case 'Y': /* set midmix */ 303 | fold_param.midmix = atof( optarg ); 304 | break; 305 | case 'S': /* set stretch */ 306 | g.stretch = atof( optarg ); 307 | break; 308 | case 'W': /* set sealevel */ 309 | g.sealevel = atof( optarg ); 310 | break; 311 | case 'G': /* set forceheight */ 312 | fold_param.forceval = atof( optarg ); 313 | break; 314 | case 'T': /* set shift */ 315 | g.base_shift = atof( optarg ); 316 | break; 317 | case 'C': 318 | g.contour = atof( optarg ); 319 | break; 320 | case 'a': /* set altitude */ 321 | g.altitude = atof( optarg ); 322 | break; 323 | case 'p': /* set distance */ 324 | g.distance = atof( optarg ); 325 | break; 326 | case 'c': 327 | g.contrast = atof( optarg ); 328 | if( g.contrast < 0.0 ) 329 | { 330 | g.contrast=0.0; 331 | } 332 | break; 333 | case 'e': 334 | g.ambient = atof( optarg ); 335 | if( g.ambient < 0.0 ) 336 | { 337 | g.ambient = 0.0; 338 | } 339 | if( g.ambient > 1.0 ) 340 | { 341 | g.ambient=1.0; 342 | } 343 | break; 344 | case 'v': 345 | g.vfract = atof( optarg ); 346 | if( g.vfract < 0.0 ) 347 | { 348 | g.vfract = 0.0; 349 | } 350 | break; 351 | case 'g': 352 | geom = optarg; 353 | break; 354 | case 'd': 355 | display = optarg; 356 | break; 357 | case 'H': 358 | print_algorithm(); 359 | errflg++; 360 | break; 361 | case 'h': 362 | case '?': 363 | errflg++; 364 | } 365 | } 366 | if( errflg ) 367 | { 368 | fprintf(stderr,"%s: version %d.%d\n",argv[0],VERSION,PATCHLEVEL); 369 | fprintf(stderr,"usage: %s -[hwbqgdPEmMrBZIASFTCapcevfRltxsXYH]\n",argv[0]); 370 | fprintf(stderr," -h Print this message\n"); 371 | fprintf(stderr," -w [%s] update window with complete images only\n",mesg[swosh]); 372 | fprintf(stderr," -b [%s] use root window \n",mesg[root]); 373 | fprintf(stderr," -q [%s] reset root window on exit\n",mesg[request_clear]); 374 | fprintf(stderr," -g string window geometry\n"); 375 | fprintf(stderr," -d string display\n"); 376 | fprintf(stderr," -P filename write PID to file\n"); 377 | fprintf(stderr," -E [%s] toggle explicit expose events \n",mesg[e_events]); 378 | fprintf(stderr," -m [%s] print map \n",mesg[g.map]); 379 | fprintf(stderr," -M [%s] implement reflections \n",mesg[g.reflec]); 380 | fprintf(stderr," -r int [%d] # columns before scrolling \n",g.repeat); 381 | fprintf(stderr," -B int [%d] # shades in a colour band\n",g.band_size); 382 | fprintf(stderr," -n int [%d] # number of colours\n",g.n_col); 383 | fprintf(stderr," -Z int [%d] time to sleep before scrolling\n",snooze); 384 | fprintf(stderr," -I float [%f] vertical angle of light \n",(g.phi*180.0)/PI); 385 | fprintf(stderr," -A float [%f] horizontal angle of light \n",(g.alpha*180.0)/PI); 386 | fprintf(stderr," -S float [%f] vertical stretch \n",g.stretch); 387 | fprintf(stderr," -T float [%f] vertical shift \n",g.base_shift); 388 | fprintf(stderr," -W float [%f] sealevel \n",g.sealevel); 389 | fprintf(stderr," -F int [%d] reduce variation in the foreground \n",fold_param.force_front); 390 | fprintf(stderr," -G float [%f] average foreground height \n",fold_param.forceval); 391 | fprintf(stderr," -C float [%f] contour parameter \n",g.contour); 392 | fprintf(stderr," -a float [%f] altitude of viewpoint \n",g.altitude); 393 | fprintf(stderr," -p float [%f] distance of viewpoint \n",g.distance); 394 | fprintf(stderr," -c float [%f] contrast\n",g.contrast); 395 | fprintf(stderr," -e float [%f] ambient light level\n",g.ambient); 396 | fprintf(stderr," -v float [%f] vertical light level\n",g.vfract); 397 | fprintf(stderr,"Fractal options:\n"); 398 | fprintf(stderr," -f float [%f] fractal dimension \n",fold_param.fdim); 399 | fprintf(stderr," -R int [%d] rng seed, read clock if 0 \n",seed); 400 | fprintf(stderr," -l int [%d] # levels of recursion \n",g.levels); 401 | fprintf(stderr," -t int [%d] # non fractal iterations \n",g.stop); 402 | fprintf(stderr," -x [%s] cross update \n",mesg[fold_param.cross]); 403 | fprintf(stderr," -s [%x] smoothing (0-7)\n",smooth); 404 | fprintf(stderr," -X float [%f] fraction of old value for rg2 & rg3\n",fold_param.mix); 405 | fprintf(stderr," -Y float [%f] fraction of old value for rg1\n",fold_param.midmix); 406 | fprintf(stderr," -window-id 0xNNNNN draw on existing external window.\n"); 407 | fprintf(stderr," -H print short description of algorithm.\n"); 408 | exit(1); 409 | } 410 | 411 | /* }}} */ 412 | for(i=0 ;i<3 ;i++) 413 | { 414 | clut[i] = (Gun *) malloc(g.n_col * sizeof(Gun)); 415 | if( ! clut[i] ) 416 | { 417 | fprintf(stderr,"malloc failed for clut\n"); 418 | exit(1); 419 | } 420 | } 421 | set_clut(g.n_col,clut[0], clut[1], clut[2]); 422 | init_graphics(root,window_id, !e_events, request_clear, &g, clut[0], clut[1], clut[2]); 423 | 424 | for(i=0;i<3;i++) 425 | { 426 | free(clut[i]); 427 | } 428 | 429 | 430 | seed_uni(seed); 431 | 432 | init_artist_variables(); 433 | if( SIG_ERR == signal(SIGINT, finish_prog )) 434 | { 435 | perror(argv[0]); 436 | exit(1); 437 | } 438 | if( SIG_ERR == signal(SIGTERM, finish_prog )) 439 | { 440 | perror(argv[0]); 441 | exit(1); 442 | } 443 | if( SIG_ERR == signal(SIGHUP, finish_prog )) 444 | { 445 | perror(argv[0]); 446 | exit(1); 447 | } 448 | if( SIG_ERR == signal(SIGQUIT, finish_prog )) 449 | { 450 | perror(argv[0]); 451 | exit(1); 452 | } 453 | 454 | 455 | /* This is a stand in for the event loop in a Widget set implementation 456 | * where we would call plot_column at regular intervals using 457 | * XTtimeout. However xmountains is an Xlib program 458 | * so I do the following. 459 | */ 460 | while( TRUE ) 461 | { 462 | plot_column(&g); 463 | zap_events(); 464 | #ifndef NO_SLEEP 465 | if( g.scroll ){ 466 | /* sleep if we are due a scroll next time */ 467 | /* sleeping is very bad because it will prevent 468 | * events being processed but I suppose it is better 469 | * than being a CPU hog, as a compremise always check for 470 | * events at least once a second, looping for longer sleep times. 471 | * process the events before a sleep to make sure the screen is up to date. 472 | * the events must always be processed at least once. 473 | */ 474 | for(i=0;i