~ubuntu-branches/ubuntu/vivid/xmountains/vivid

« back to all changes in this revision

Viewing changes to artist.c

  • Committer: Bazaar Package Importer
  • Author(s): tony mancill
  • Date: 2002-02-21 21:18:02 UTC
  • Revision ID: james.westby@ubuntu.com-20020221211802-xogcpfrgio7hed45
Tags: upstream-2.6
ImportĀ upstreamĀ versionĀ 2.6

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *   routines to render a fractal landscape as an image
 
3
 */
 
4
#include <math.h>
 
5
#include <stdio.h>
 
6
#include "paint.h"
 
7
#include "crinkle.h"
 
8
 
 
9
char artist_Id[] = "$Id: artist.c,v 1.40 1997/12/03 17:21:10 spb Exp spb $";
 
10
#define SIDE 1.0
 
11
#ifndef PI
 
12
#define PI 3.14159265
 
13
#endif
 
14
 
 
15
 
 
16
 
 
17
int base=0;      /* parity flag for mirror routine */
 
18
 
 
19
extern Parm fold_param;
 
20
extern Graph g;
 
21
 
 
22
Fold *top;
 
23
 
 
24
 
 
25
Height varience;
 
26
Height delta_shadow;
 
27
Height shift;
 
28
double shadow_slip;
 
29
double shadow_register;
 
30
double cos_phi;
 
31
double sin_phi;
 
32
double tan_phi;
 
33
double x_fact;
 
34
double y_fact;
 
35
double vangle;
 
36
double vscale;
 
37
double tan_vangle;                                     
 
38
float viewpos;        /* position of viewpoint */
 
39
float viewheight;      /* height of viewpoint */
 
40
float focal;
 
41
float vstrength; /* strength of vertical light source */
 
42
float lstrength; /* strength of vertical light source */
 
43
 
 
44
 
 
45
 
 
46
Height *shadow;               /* height of the shadows */
 
47
Height *a_strip, *b_strip;    /* the two most recent strips */
 
48
 
 
49
 
 
50
float uni();
 
51
/* {{{   void set_clut(int max_col, Gun *red, Gun *green, Gun *blue)*/
 
52
/*
 
53
 * setup the colour lookup table
 
54
 */
 
55
void set_clut (max_col,red,green,blue)
 
56
int max_col;
 
57
Gun *red;
 
58
Gun *green;
 
59
Gun *blue;
 
60
{
 
61
  int band,shade;
 
62
  float top, bot;
 
63
  float intensity;
 
64
  int tmp;
 
65
/*
 
66
*  float rb[N_BANDS] = { 0.167,0.200,0.333,0.450,0.600,1.000 };
 
67
*  float gb[N_BANDS] = { 0.667,0.667,0.500,0.500,0.600,1.000 };
 
68
*  float bb[N_BANDS] = { 0.500,0.450,0.333,0.200,0.000,1.000 };
 
69
*/
 
70
 
 
71
  float rb[N_BANDS];
 
72
  float gb[N_BANDS];
 
73
  float bb[N_BANDS];
 
74
 
 
75
  /* band base colours as RGB fractions */
 
76
  rb[0] = 0.450; rb[1] = 0.600; rb[2] = 1.000;
 
77
  gb[0] = 0.500; gb[1] = 0.600; gb[2] = 1.000;
 
78
  bb[0] = 0.333; bb[1] = 0.000; bb[2] = 1.000;
 
79
 
 
80
  /* {{{   black */
 
81
  red[BLACK]       = 0;
 
82
  green[BLACK]     = 0;
 
83
  blue[BLACK]      = 0;
 
84
  /* }}} */
 
85
  /* {{{   white */
 
86
  red[WHITE]       = COL_RANGE;
 
87
  green[WHITE]     = COL_RANGE;
 
88
  blue[WHITE]      = COL_RANGE;
 
89
  /* }}} */
 
90
  /* {{{   sky*/
 
91
  red[SKY]         = 0.404*COL_RANGE;
 
92
  green[SKY]       = 0.588*COL_RANGE;
 
93
  blue[SKY]        = COL_RANGE;
 
94
  /* }}} */
 
95
  /* {{{   sea (lit) */
 
96
  red[SEA_LIT]     = 0;
 
97
  green[SEA_LIT]   = 0.500*COL_RANGE;
 
98
  blue[SEA_LIT]    = 0.700*COL_RANGE;
 
99
  /* }}} */
 
100
  /* {{{   sea (unlit)*/
 
101
  red[SEA_UNLIT]   = 0;
 
102
  green[SEA_UNLIT] = ((g.ambient+(g.vfract/(1.0+g.vfract)))*0.500)*COL_RANGE;
 
103
  blue[SEA_UNLIT]  = ((g.ambient+(g.vfract/(1.0+g.vfract)))*0.700)*COL_RANGE;
 
104
  /* }}} */
 
105
 
 
106
  if( MIN_COL > max_col )
 
107
  {
 
108
    fprintf(stderr,"set_clut: less than the minimum number of colours available\n");
 
109
    exit(1);
 
110
  }
 
111
  /* max_col can over-rule band_size */
 
112
  while( (BAND_BASE +g.band_size*N_BANDS) > max_col )
 
113
  {
 
114
    g.band_size--;
 
115
  }
 
116
    
 
117
  for( band=0 ; band<N_BANDS; band++)
 
118
  {
 
119
    for(shade=0 ; shade < g.band_size ; shade++)
 
120
    {
 
121
      if( (BAND_BASE + (band*g.band_size) + shade) >= max_col )
 
122
      {
 
123
        fprintf(stderr,"INTERNAL ERROR, overflowed clut\n");
 
124
        exit(1);
 
125
      }
 
126
      /* {{{   set red */
 
127
      top = rb[band];
 
128
      bot = g.ambient * top;
 
129
      intensity = bot + ((shade * (top - bot))/(g.band_size-1));
 
130
      tmp = COL_RANGE * intensity;
 
131
      if (tmp < 0)
 
132
      {
 
133
        fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp);
 
134
        exit(2);
 
135
      }
 
136
      if( tmp > COL_RANGE )
 
137
      {
 
138
        tmp = COL_RANGE;
 
139
      }
 
140
      red[BAND_BASE + (band*g.band_size) + shade] = tmp;
 
141
      /* }}} */
 
142
      /* {{{   set green */
 
143
      top = gb[band];
 
144
      bot = g.ambient * top;
 
145
      intensity = bot + ((shade * (top - bot))/(g.band_size-1));
 
146
      tmp = COL_RANGE * intensity;
 
147
      if (tmp < 0)
 
148
      {
 
149
        fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp);
 
150
        exit(2);
 
151
      }
 
152
      if( tmp > COL_RANGE )
 
153
      {
 
154
        tmp = COL_RANGE;
 
155
      }
 
156
      green[BAND_BASE + (band*g.band_size) + shade] = tmp;
 
157
      /* }}} */
 
158
      /* {{{   set blue */
 
159
      top = bb[band];
 
160
      bot = g.ambient * top;
 
161
      intensity = bot + ((shade * (top - bot))/(g.band_size-1));
 
162
      tmp = COL_RANGE * intensity;
 
163
      if (tmp < 0)
 
164
      {
 
165
        fprintf(stderr,"set_clut: internal error: invalid code %d\n",tmp);
 
166
        exit(2);
 
167
      }
 
168
      if( tmp > COL_RANGE )
 
169
      {
 
170
        tmp = COL_RANGE;
 
171
      }
 
172
      blue[BAND_BASE + (band*g.band_size) + shade] = tmp;
 
173
      /* }}} */
 
174
    }
 
175
  }
 
176
}
 
177
/* }}} */
 
178
/* {{{   Height *extract(Strip *s) */
 
179
/*
 
180
 * extract the table of heights from the Strip struct
 
181
 * and discard the rest of the struct.
 
182
 */
 
183
Height *extract (s)
 
184
Strip *s;
 
185
{
 
186
  int i;
 
187
  
 
188
  Height *p;
 
189
  p = s->d;
 
190
  free(s);
 
191
  for(i=0 ; i<g.width; i++ )
 
192
  {
 
193
    p[i] = shift + (vscale * p[i]);
 
194
  }
 
195
  return(p);
 
196
}
 
197
/* }}} */
 
198
/* {{{   void init_artist_variables() */
 
199
/*
 
200
 * initialise the variables for the artist routines.
 
201
 */
 
202
void init_artist_variables()
 
203
{
 
204
  float dh, dd;
 
205
  int pwidth;  /* longest lengthscale for update */
 
206
  
 
207
  g.width= (1 << g.levels)+1;
 
208
  pwidth= (1 << (g.levels - g.stop))+1;
 
209
 
 
210
  /* make the fractal SIDE wide, this makes it easy to predict the
 
211
   * average height returned by calcalt. If we have stop != 0 then
 
212
   * make the largest update length = SIDE
 
213
   */
 
214
  cos_phi = cos( g.phi );
 
215
  sin_phi = sin( g.phi );
 
216
  tan_phi = tan( g.phi );
 
217
 
 
218
  x_fact = cos_phi* cos(g.alpha);
 
219
  y_fact = cos_phi* sin(g.alpha);
 
220
  vscale = g.stretch * pwidth;  /* have approx same height as fractal width
 
221
                               * this makes each pixel SIDE=1.0 wide.
 
222
                               * c.f. get_col
 
223
                               */
 
224
 
 
225
  delta_shadow = tan_phi /cos(g.alpha);
 
226
  shadow_slip = tan(g.alpha);
 
227
  /* guess the average height of the fractal */
 
228
  varience = pow( SIDE ,(2.0 * fold_param.fdim));
 
229
  varience = vscale * varience ;
 
230
  shift = g.base_shift * varience;
 
231
  varience = varience + shift;
 
232
 
 
233
 
 
234
  /* set the position of the view point */
 
235
  viewheight = g.altitude * g.width;
 
236
  viewpos = - g.distance * g.width;
 
237
 
 
238
  /* set viewing angle and focal length (vertical-magnification)
 
239
   * try mapping the bottom of the fractal to the bottom of the
 
240
   * screen. Try to get points in the middle of the fractal
 
241
   * to be 1 pixel high
 
242
   */
 
243
  dh = viewheight;
 
244
  dd = (g.width / 2.0) - viewpos;
 
245
  focal = sqrt( (dd*dd) + (dh*dh) );
 
246
#ifndef SLOPPY
 
247
  tan_vangle = (double) ((double)(viewheight-g.sealevel)/(double) - viewpos);
 
248
  vangle = atan ( tan_vangle );
 
249
  vangle -= atan( (double) (g.graph_height/2) / focal ); 
 
250
#else
 
251
  /* we are making some horrible approximations to avoid trig funtions */
 
252
  tan_vangle = (double) ((double)(viewheight-sealevel)/(double) - viewpos);
 
253
  tan_vangle = tan_vangle - ( (double) (height/2) / focal );
 
254
#endif
 
255
 
 
256
  top=make_fold(NULL, &fold_param, g.levels,g.stop,(SIDE / pwidth));
 
257
 
 
258
  /* use first set of heights to set shadow value */
 
259
  shadow = extract(next_strip(top));
 
260
  a_strip = extract( next_strip(top) ); 
 
261
  b_strip = extract( next_strip(top) );
 
262
 
 
263
  /* initialise the light strengths */
 
264
  vstrength = g.vfract * g.contrast /( 1.0 + g.vfract );
 
265
  lstrength = g.contrast /( 1.0 + g.vfract );
 
266
  if( g.repeat >= 0 ){
 
267
    g.pos=0;
 
268
  }else{
 
269
    g.pos=g.graph_width-1;
 
270
  }     
 
271
}
 
272
/* }}} */
 
273
/* {{{   Col get_col(Height p, Height p_minus_x, Height p_minus_y, Height shadow) */
 
274
/*
 
275
 * calculate the colour of a point.
 
276
 */
 
277
Col get_col (p,p_minus_x,p_minus_y,shadow)
 
278
Height p;
 
279
Height p_minus_x;
 
280
Height p_minus_y;
 
281
Height shadow;
 
282
{
 
283
  Height delta_x, delta_y;
 
284
  Height delta_x_sqr, delta_y_sqr;
 
285
  Height hypot_sqr;
 
286
  
 
287
  double norm, dshade;
 
288
  Height effective;
 
289
  Col result;
 
290
  int band, shade;
 
291
  /* {{{   if underwater*/
 
292
  if ( p < g.sealevel )
 
293
  {
 
294
    if( shadow > g.sealevel )
 
295
    {
 
296
      return( SEA_UNLIT );
 
297
    }else{
 
298
      return( SEA_LIT );
 
299
    }
 
300
  }
 
301
  /* }}} */
 
302
  /*
 
303
   * We have three light sources, one slanting in from the left
 
304
   * one directly from above and an ambient light.
 
305
   * For the directional sources illumination is proportional to the
 
306
   * cosine between the normal to the surface and the light.
 
307
   *
 
308
   * The surface contains two vectors
 
309
   * ( 1, 0, delta_x )
 
310
   * ( 0, 1, delta_y )
 
311
   *
 
312
   * The normal therefore is parallel to
 
313
   * (  -delta_x, -delta_y, 1)/sqrt( 1 + delta_x^2 + delta_y^2)
 
314
   *
 
315
   * For light parallel to ( cos_phi, 0, -sin_phi) the cosine is
 
316
   *        (cos_phi*delta_x + sin_phi)/sqrt( 1 + delta_x^2 + delta_y^2)
 
317
   *
 
318
   * For light parallel to ( cos_phi*cos_alpha, cos_phi*sin_alpha, -sin_phi)
 
319
   * the cosine is
 
320
   * (cos_phi*cos_alpha*delta_x + cos_phi*sin_alpha*delta_y+ sin_phi)/sqrt( 1 + delta_x^2 + delta_y^2)
 
321
   *
 
322
   * For vertical light the cosine is
 
323
   *        1 / sqrt( 1 + delta_x^2 + delta_y^2)
 
324
   */
 
325
   
 
326
  delta_x = p - p_minus_x;
 
327
  delta_y = p - p_minus_y;
 
328
  delta_x_sqr = delta_x * delta_x;
 
329
  delta_y_sqr = delta_y * delta_y;
 
330
  hypot_sqr = delta_x_sqr + delta_y_sqr;
 
331
  norm = sqrt( 1.0 + hypot_sqr );
 
332
 
 
333
  /* {{{   calculate effective height */
 
334
  effective = (p + (varience * g.contour *
 
335
          (1.0/ ( 1.0 + hypot_sqr))));
 
336
  /* }}} */
 
337
  /* {{{   calculate colour band. */
 
338
  band = ( effective / varience) * N_BANDS;
 
339
  if ( band < 0 )
 
340
  {
 
341
    band = 0;
 
342
  }
 
343
  if( band > (N_BANDS - 1))
 
344
  {
 
345
    band = (N_BANDS -1);
 
346
  }
 
347
  result = (BAND_BASE + (band * g.band_size));
 
348
  /* }}} */
 
349
 
 
350
  /* {{{ calculate the illumination stength*/
 
351
  /*
 
352
   * add in a contribution for the vertical light. The normalisation factor
 
353
   * is applied later
 
354
   *
 
355
   */
 
356
  dshade = vstrength;
 
357
  
 
358
  if( p >= shadow )
 
359
  {
 
360
    /*
 
361
     * add in contribution from the main light source
 
362
     */
 
363
    /* dshade += ((double) lstrength * ((delta_x * cos_phi) + sin_phi));*/
 
364
    dshade += ((double) lstrength *
 
365
               ((delta_x * x_fact) + (delta_y * y_fact) + sin_phi));
 
366
  }
 
367
  /* divide by the normalisation factor (the same for both light sources) */
 
368
  dshade /= norm;
 
369
  /* }}} */
 
370
  /* {{{   calculate shading */
 
371
  /* dshade should be in the range 0.0 -> 1.0
 
372
   * if the light intensities add to 1.0
 
373
   * now convert to an integer
 
374
   */
 
375
  shade = dshade * (double) g.band_size;
 
376
  if( shade > (g.band_size-1))
 
377
  {
 
378
    shade = (g.band_size-1);
 
379
  }
 
380
  /* {{{   if shade is negative then point is really in deep shadow */
 
381
  if( shade < 0 )
 
382
  {
 
383
      shade = 0;
 
384
  }
 
385
  /* }}} */
 
386
  /* }}} */
 
387
  result += shade;
 
388
  if( (result >= g.n_col) || (result < 0) )
 
389
  {
 
390
    fprintf(stderr,"INTERNAL ERROR colour out of range %d max %d\n",result,g.n_col);
 
391
    exit(1);
 
392
  }
 
393
  return(result);
 
394
}
 
395
/* }}} */
 
396
/* {{{   Col *makemap(Height *a, Height *b, Height *shadow) */
 
397
Col *makemap (a,b,shadow)
 
398
Height *a;
 
399
Height *b;
 
400
Height *shadow;
 
401
{
 
402
Col *res;
 
403
int i;
 
404
 
 
405
  /* This routine returns a plan view of the surface */
 
406
  res = (Col *) malloc(g.width * sizeof(Col) );
 
407
  if (res == NULL)
 
408
  {
 
409
    fprintf(stderr,"malloc failed for colour strip\n");
 
410
    exit(1);
 
411
  }
 
412
  res[0] = BLACK;
 
413
  for(i=1 ; i<g.width ; i++)
 
414
  {
 
415
    res[i] = get_col(b[i],a[i],b[i-1],shadow[i]);
 
416
  }
 
417
  return(res);
 
418
}
 
419
  
 
420
/* }}} */
 
421
/* {{{   Col *camera(Height *a, Height *b, Height *shadow) */
 
422
Col *camera(a,b,shadow)
 
423
Height *a;
 
424
Height *b;
 
425
Height *shadow;
 
426
{
 
427
  int i, j, coord, last;
 
428
  Col *res, col;
 
429
 
 
430
  /* this routine returns a perspective view of the surface */
 
431
  res = (Col *) malloc( g.graph_height * sizeof(Col) );
 
432
  if( res == NULL )
 
433
  {
 
434
    fprintf(stderr,"malloc failed for picture strip\n");
 
435
    exit(1);
 
436
  }
 
437
  /*
 
438
   * optimised painters algorithm
 
439
   *
 
440
   * scan from front to back, we can avoid calculating the
 
441
   * colour if the point is not visable.
 
442
   */
 
443
  for( i=0, last=0 ; (i < g.width)&&(last < g.graph_height) ; i++ )
 
444
  {
 
445
    if( a[i] < g.sealevel )
 
446
    {
 
447
      a[i] = g.sealevel;
 
448
    }
 
449
    coord = 1 + project( i, a[i] );
 
450
    if( coord > last )
 
451
    {
 
452
      /* get the colour of this point, the front strip should be black */
 
453
      if( i==0 )
 
454
      {
 
455
        col = BLACK;
 
456
      }else{
 
457
        col = get_col(b[i],a[i],b[i-1],shadow[i]);
 
458
      }
 
459
      if( coord > g.graph_height )
 
460
      {
 
461
        coord = g.graph_height;
 
462
      }
 
463
      for(;last<coord;last++)
 
464
      {
 
465
        res[last]=col;
 
466
      }
 
467
    }
 
468
  }
 
469
  for(;last<g.graph_height;last++)
 
470
  {
 
471
    res[last]=SKY;
 
472
  }
 
473
  return(res);
 
474
}
 
475
/* }}} */
 
476
/* {{{   Col *mirror(Height *a, Height *b, Height *shadow)*/
 
477
Col *mirror(a,b,shadow)
 
478
Height *a;
 
479
Height *b;
 
480
Height *shadow;
 
481
{
 
482
  Col *res, *map;
 
483
  Col last_col;
 
484
  int i,j, top, bottom, coord;
 
485
  int last_top, last_bottom;
 
486
  Height pivot;
 
487
  /* this routine returns a perspective view of the surface
 
488
   * with reflections in the water
 
489
   *
 
490
   */
 
491
  res = (Col *) malloc( g.graph_height * sizeof(Col) );
 
492
  if( res == NULL )
 
493
  {
 
494
    fprintf(stderr,"malloc failed for picture strip\n");
 
495
    exit(1);
 
496
  }
 
497
  last_col=SKY;
 
498
  last_top=g.graph_height-1;
 
499
  last_bottom=0;
 
500
  /*
 
501
   * many of the optimisation in the camera routine are
 
502
   * hard to implement in this case so we revert to the
 
503
   * simple painters algorithm modified to produce reflections
 
504
   * scan from back to front drawing strips between the
 
505
   * projected position of height and -height.
 
506
   * for water stipple the colour so the reflection is still visable
 
507
   */
 
508
  map=makemap(a,b,shadow);
 
509
  pivot=2.0*g.sealevel;
 
510
  for(i=g.width-1;i>0;i--)
 
511
  {
 
512
    if(map[i] < BAND_BASE)
 
513
    {
 
514
      /* {{{ stipple water values*/
 
515
      for(j=last_bottom;j<=last_top;j++)
 
516
      {
 
517
        res[j]=last_col;
 
518
      }
 
519
      last_col=map[i];
 
520
      /* invalidate strip so last stip does not exist */
 
521
      last_bottom=g.graph_height;
 
522
      last_top= -1;
 
523
      /* fill in water values */
 
524
      coord=1+project(i,g.sealevel);
 
525
      for(j=0;j<coord;j++)
 
526
      {
 
527
        /* do not print on every other point
 
528
         * if the current value is a land value
 
529
         */
 
530
        if( (j+base)%2 || (res[j]<BAND_BASE) )
 
531
        {
 
532
          res[j]=map[i];
 
533
        }
 
534
      }
 
535
      /* skip any adjacent bits of water with the same colour */
 
536
      while(map[i]==last_col)
 
537
      {
 
538
        i--;
 
539
      }
 
540
      i++;  /* the end of the for loop will decrement as well */
 
541
      /* }}} */
 
542
    }else{
 
543
      /* {{{ draw land values*/
 
544
      top = project(i,a[i]);
 
545
      bottom=project(i,pivot-a[i]);
 
546
      if(last_col == map[i])
 
547
      {
 
548
        if( top > last_top)
 
549
        {
 
550
          last_top=top;
 
551
        }
 
552
        if( bottom < last_bottom)
 
553
        {
 
554
          last_bottom=bottom;
 
555
        }
 
556
      }else{
 
557
        if(top < last_top)
 
558
        {
 
559
          for(j=top+1;j<=last_top;j++)
 
560
          {
 
561
            res[j]=last_col;
 
562
          }
 
563
        }
 
564
        if(bottom > last_bottom)
 
565
        {
 
566
          for(j=last_bottom;j<bottom;j++)
 
567
          {
 
568
            res[j]=last_col;
 
569
          }
 
570
        }
 
571
        last_top=top;
 
572
        last_bottom=bottom;
 
573
        last_col=map[i];
 
574
      }
 
575
      /* }}} */
 
576
    }
 
577
  }
 
578
  /* {{{ draw in front face*/
 
579
  for(j=last_bottom;j<=last_top;j++)
 
580
  {
 
581
    res[j]=last_col;
 
582
  }
 
583
  if( a[0] < g.sealevel )
 
584
  {
 
585
    coord=1+project(0,g.sealevel);
 
586
  }else{
 
587
    coord=1+project(0,a[0]);
 
588
  }
 
589
  for(j=0;j<coord;j++)
 
590
  {
 
591
    res[j] = map[0];
 
592
  }
 
593
  /* }}} */
 
594
  base=1-base;
 
595
  free(map);
 
596
  return(res);
 
597
}
 
598
/* }}} */
 
599
/* {{{   int project( int x , Height y ) */
 
600
/*
 
601
 *  project a point onto the screen position
 
602
 */
 
603
int project (x,y)
 
604
int x;
 
605
Height y;
 
606
{
 
607
  int pos;
 
608
#ifndef SLOPPY
 
609
  double theta;
 
610
 
 
611
  theta = atan( (double) ((viewheight - y)/( x - viewpos)) );
 
612
  theta = theta - vangle;
 
613
  pos = (g.graph_height/2) - (focal * tan( theta));
 
614
#else
 
615
  float tan_theta;
 
616
 
 
617
  /* nast approx to avoid trig functions */
 
618
  tan_theta = (viewheight -y)/(x-viewpos) - tan_vangle;
 
619
  pos = (height/2) - (focal * tan_theta);
 
620
#endif
 
621
  if( pos > (g.graph_height-1))
 
622
  {
 
623
    pos = g.graph_height-1;
 
624
  }
 
625
  else if( pos < 0 )
 
626
  {
 
627
    pos = 0;
 
628
  }
 
629
  return( pos );
 
630
}
 
631
/* }}} */
 
632
/* {{{   void finish_artist() */
 
633
/*
 
634
 * Tidy up and free everything.
 
635
 */
 
636
void finish_artist()
 
637
{
 
638
  free(a_strip);
 
639
  free(b_strip);
 
640
  free(shadow);
 
641
  free_fold(top);
 
642
}
 
643
/* }}} */
 
644
/* {{{  void init_parameters() */
 
645
 
 
646
void init_parameters()
 
647
{
 
648
  g.graph_height=768;
 
649
  g.graph_width=1024;
 
650
  g.levels = 10;
 
651
  g.stop=2;
 
652
  g.n_col=DEF_COL;
 
653
  g.band_size=BAND_SIZE;
 
654
  g.ambient=0.3;
 
655
  g.contrast=1.0;
 
656
  g.contour=0.3;
 
657
  g.vfract=0.6;
 
658
  g.altitude=2.5;
 
659
  g.distance=4.0;
 
660
  g.phi=(40.0 * PI)/180.0;
 
661
  g.alpha=0.0;
 
662
  g.base_shift=0.5;
 
663
  g.sealevel=0.0;
 
664
  g.stretch=0.6;
 
665
  g.map=FALSE;
 
666
  g.reflec=TRUE;
 
667
  g.repeat=20;
 
668
  g.pos=0;
 
669
  g.scroll=0;
 
670
 
 
671
  fold_param.mean=0;
 
672
  fold_param.rg1=FALSE;
 
673
  fold_param.rg2=FALSE;
 
674
  fold_param.rg3=TRUE;
 
675
  fold_param.cross=TRUE;
 
676
  fold_param.force_front=TRUE;
 
677
  fold_param.force_back=FALSE;
 
678
  fold_param.forceval=-1.0;
 
679
  fold_param.fdim = 0.65;
 
680
  fold_param.mix   =0.0;
 
681
  fold_param.midmix=0.0;
 
682
 
 
683
}
 
684
 
 
685
/* }}} */
 
686
/* {{{   Col *next_col(int paint, int reflec) */
 
687
 
 
688
Col *next_col (paint, reflec)
 
689
int paint;
 
690
int reflec;
 
691
{
 
692
  Col *res;
 
693
  int i,offset=0;
 
694
  
 
695
  /* {{{    update strips */
 
696
  if(paint)
 
697
  {
 
698
    if(reflec)
 
699
    {
 
700
      res = mirror( a_strip,b_strip,shadow);
 
701
    }else{
 
702
      res = camera( a_strip,b_strip,shadow);
 
703
    }
 
704
  }else{
 
705
    res = makemap(a_strip,b_strip,shadow);
 
706
  }
 
707
  free(a_strip);
 
708
  a_strip=b_strip;
 
709
  b_strip = extract( next_strip(top) );
 
710
  /* }}} */
 
711
 
 
712
  /* {{{  update the shadows*/
 
713
 
 
714
  /* shadow_slip is the Y component of the light vector.
 
715
   * The shadows can only step an integer number of points in the Y
 
716
   * direction so we maintain shadow_register as the deviation between
 
717
   * where the shadows are and where they should be. When the magnitude of
 
718
   * this gets larger then 1 the shadows are slipped by the required number of
 
719
   * points.
 
720
   * This will not work for very oblique angles so the horizontal angle
 
721
   * of illumination should be constrained.
 
722
   */
 
723
  shadow_register += shadow_slip;
 
724
  if( shadow_register >= 1.0 )
 
725
  {
 
726
    /* {{{  negative offset*/
 
727
 
 
728
    while( shadow_register >= 1.0 )
 
729
    {
 
730
      shadow_register -= 1.0;
 
731
      offset++;
 
732
    }
 
733
    for(i=g.width-1 ; i>=offset ; i--)
 
734
    {
 
735
      shadow[i] = shadow[i-offset]-delta_shadow;
 
736
      if( shadow[i] < b_strip[i] )
 
737
      {
 
738
        shadow[i] = b_strip[i];
 
739
      }
 
740
      /* {{{    stop shadow at sea level */
 
741
 
 
742
      if( shadow[i] < g.sealevel )
 
743
      {
 
744
        shadow[i] = g.sealevel;
 
745
      }
 
746
 
 
747
 
 
748
 
 
749
      /* }}} */
 
750
    }
 
751
    for(i=0;i<offset;i++)
 
752
    {
 
753
      shadow[i] = b_strip[i];
 
754
      /* {{{    stop shadow at sea level*/
 
755
      if( shadow[i] < g.sealevel )
 
756
      {
 
757
        shadow[i] = g.sealevel;
 
758
      }
 
759
      /* }}} */
 
760
    }
 
761
 
 
762
    /* }}} */
 
763
  }else if( shadow_register <= -1.0 ){
 
764
    /* {{{  positive offset*/
 
765
    while( shadow_register <= -1.0 )
 
766
    {
 
767
      shadow_register += 1.0;
 
768
      offset++;
 
769
    }
 
770
    for(i=0 ; i<g.width-offset ; i++)
 
771
    {
 
772
      shadow[i] = shadow[i+offset]-delta_shadow;
 
773
      if( shadow[i] < b_strip[i] )
 
774
      {
 
775
        shadow[i] = b_strip[i];
 
776
      }
 
777
      /* {{{    stop shadow at sea level */
 
778
      if( shadow[i] < g.sealevel )
 
779
      {
 
780
        shadow[i] = g.sealevel;
 
781
      }
 
782
      /* }}} */
 
783
    }
 
784
    for(;i<g.width;i++)
 
785
    {
 
786
      shadow[i] = b_strip[i];
 
787
      /* {{{    stop shadow at sea level*/
 
788
      if( shadow[i] < g.sealevel )
 
789
      {
 
790
        shadow[i] = g.sealevel;
 
791
      }
 
792
      /* }}} */
 
793
    }
 
794
    /* }}} */
 
795
  }else{
 
796
    /* {{{  no offset*/
 
797
    for(i=0 ; i<g.width ; i++)
 
798
    {
 
799
      shadow[i] -= delta_shadow;
 
800
      if( shadow[i] < b_strip[i] )
 
801
      {
 
802
        shadow[i] = b_strip[i];
 
803
      }
 
804
      /* {{{    stop shadow at sea level */
 
805
      if( shadow[i] < g.sealevel )
 
806
      {
 
807
        shadow[i] = g.sealevel;
 
808
      }
 
809
      /* }}} */
 
810
    }
 
811
    /* }}} */
 
812
  }
 
813
 
 
814
  /* }}} */
 
815
  
 
816
  return(res);
 
817
}
 
818
 
 
819
/* }}} */
 
820
/* {{{  void plot_column(g)*/
 
821
void plot_column(g)
 
822
Graph *g;
 
823
{
 
824
  Col *l;
 
825
  int j;
 
826
  int mapwid;
 
827
 
 
828
  /* blank if we are doing the full window */
 
829
  if( g->repeat >= 0){
 
830
    if(g->pos == 0){
 
831
      blank_region(0,0,g->graph_width,g->graph_height);
 
832
      flush_region(0,0,g->graph_width,g->graph_height);
 
833
    }
 
834
  }else{
 
835
    if( g->pos == g->graph_width-1){
 
836
      blank_region(0,0,g->graph_width,g->graph_height);
 
837
      flush_region(0,0,g->graph_width,g->graph_height);
 
838
    }
 
839
  }
 
840
  if( g->scroll ){
 
841
    scroll_screen(g->scroll);
 
842
  }
 
843
 
 
844
  l = next_col(1-g->map,g->reflec); 
 
845
  if( g->map )
 
846
  {
 
847
    if( g->graph_height > g->width ){
 
848
      mapwid=g->width;
 
849
    }else{
 
850
      mapwid=g->graph_height;
 
851
    }
 
852
    for( j=0 ;j<(g->graph_height-mapwid); j++)
 
853
    {
 
854
      plot_pixel(g->pos,((g->graph_height-1)-j),BLACK);
 
855
    }
 
856
    for(j=0; j<mapwid ; j++)
 
857
    {
 
858
      plot_pixel(g->pos,((mapwid-1)-j),l[j]);
 
859
    }
 
860
  }else{
 
861
    for(j=0 ; j<g->graph_height ; j++)
 
862
    {
 
863
      /* we assume that the scroll routine fills the
 
864
       * new region with a SKY value. This allows us to
 
865
       * use a testured sky for B/W displays
 
866
       */
 
867
      if( l[j] != SKY )
 
868
      {
 
869
        plot_pixel(g->pos,((g->graph_height-1)-j),l[j]);
 
870
      }
 
871
    }
 
872
  }
 
873
  free(l);
 
874
  flush_region(g->pos,0,1,g->graph_height);
 
875
  g->scroll = 0;
 
876
  /* now update pos ready for next time */
 
877
  if( g->repeat >=0 ){
 
878
    g->pos++;
 
879
    if(g->pos >= g->graph_width)
 
880
    {
 
881
      g->pos -=  g->repeat;
 
882
      if( g->pos < 0 || g->pos > g->graph_width-1 )
 
883
      {
 
884
        g->pos=0; 
 
885
      }else{
 
886
        g->scroll = g->repeat;
 
887
      }
 
888
    }
 
889
  }else{
 
890
    g->pos--;
 
891
    if( g->pos < 0 ){
 
892
      g->pos -=   g->repeat;
 
893
      if( g->pos < 0 || g->pos > (g->graph_width-1) ){
 
894
        g->pos=g->graph_width-1;
 
895
      }else{
 
896
        g->scroll = g->repeat;
 
897
      }
 
898
    }
 
899
  }
 
900
 
 
901
}
 
902
/* }}} */
 
903
 
 
904