/* Fractal mountain landscape generator */
/* Version   A 1.21                     */
/* Author    Colin Cassidy              */
/* RISC User August 1994                */
/* Program   Subject to Copyright       */
/*           Not Public Domain 		*/

#include "DeskLib:Sprite.h"
#include "DeskLib:Time.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <roslib.h>
#include <math.h>

#define SIZE (1<<8)
#define S (SIZE+1)
#define PI 3.1415927
#define ff 8
#define f (1<<ff)

typedef struct {int x, y;} scr_crd;

struct {
  int zoom;
  int ax, ay, az;
  int ofx, ofy, ofz;
  } pos;

static int cax, cay, caz, sax, say, saz;

int *h;
int ruff = 10;
int mxh = 0;

void main(void);
void frac(int lev);
void draw(void);
void xy(int x, int y, int z, scr_crd *d);
double rad(int ang);
void init_view(int xpos);
void col(int y, int h);

void main(void)
{
  int n;

  os_mode(12);
  os_cursor(0);
  /*os_rnd(-Time_Monotonic());*/
  os_rnd(-1);

  for (n=0; n<16; n++) os_palette(n, 16, n*17, n*17, n*17);
  os_colour(12+128);
  os_colour(0);
  os_cls();

  h = malloc(sizeof(int) * S*S);
  if (!h)
  {
    puts("Not enough memory to create the scenery map");
    return;
  }
  memset(h, 0, sizeof(int) * S*S);

  frac(SIZE);

  init_view(-1);
  draw();
  Sprite_ScreenSave("<Obey$Dir>.^.Output.1", TRUE);

  os_cls();
  init_view(+1);
  draw();
  Sprite_ScreenSave("<Obey$Dir>.^.Output.2", TRUE);

  return;
}


void frac(int lev)
{
  int x, y, lv, n;

  while(lev>1)
  {
    lv = lev >> 1;
    if (lev<32) ruff=5;

    for (x=0; x<SIZE; x+=lev)
    {
      for(y=0; y<SIZE; y+=lev)
      {
        *(h+(x+lv)*S+y) = *(h+x*S+y) + *(h+(x+lev)*S+y) >> 1;
        *(h+x*S+y+lv)   = *(h+x*S+y) + *(h+x*S+y+lev) >> 1;
        *(h+(x+lv)*S+y+lv) = *(h+(x+lv)*S+y)
        		   + (*(h+x*S+y+lev)
        		   + *(h+(x+lev)*S+y+lev) >> 1) >> 1;

        if (lev<SIZE) *(h+(x+lv)*S+y+lv) = *(h+(x+lv)*S+y+lv) + os_rnd(lev*ruff);
        *(h+x*S+y) = *(h+x*S+y) + (os_rnd((lev*ruff) - lv*ruff) >> 2);
        if (*(h+(x+lv)*S+y+lv) > mxh) mxh=*(h+(x+lv)*S+y+lv);

      }
    }

    lev = lv;
  }

  return;
}


void draw(void)
{
  int x, y;
  scr_crd d;

  os_rnd(-1);

  for(y=SIZE-1; y>=0; y--)
  {
    for (x=0; x<SIZE; x++)
    {

      xy(x+1, *(h+(x+1)*S+y), y, &d)     ; os_move(d.x, d.y);
      xy(x  , *(h+x*S+y), y, &d)         ; os_move(d.x, d.y);
      col(y , *(h+x*S+y));
      xy(x+1, *(h+(x+1)*S+y-1), y-1, &d) ; os_plot(85, d.x, d.y);
      col(y , *(h+x*S+y));
      xy(x  , *(h+x*S+y-1), y-1, &d)     ; os_plot(85, d.x, d.y);
    }
  }

  return;
}


void init_view(int xpos)
{
  pos.zoom = 420000/SIZE;
  pos.ax   = 160;
  pos.ay   = 10;
  pos.az   = 0;
  pos.ofx  = xpos * 25;
  pos.ofy  = 600;
  pos.ofz  = -600;

  cax = cos(rad(pos.ax))*(f) ; sax = sin(rad(pos.ax))*(f);
  cay = cos(rad(pos.ay))*(f) ; say = sin(rad(pos.ay))*(f);
  caz = cos(rad(pos.az))*(f) ; saz = sin(rad(pos.az))*(f);

  os_origin(640,450);

  return;
}


double rad(int ang)
{
  return ang*PI/180;
}


void xy(int x, int y, int z, scr_crd *d)
{
  int xn, yn;

  x -= SIZE >> 1;
  x *= 12;
  z *= 10;

  xn=x*caz-y*saz ; y=y*caz+x*saz ; x=xn>>ff ; y=y>>ff;
  xn=x*cay-z*say ; z=z*cay+x*say ; x=xn>>ff ; z=z>>ff;
  yn=y*cax-z*sax ; z=z*cax+y*cax ; y=yn>>ff ; z=z>>ff;
  x+=pos.ofx ; y+=pos.ofy ; z+=pos.ofz;
  d->x = pos.zoom*x/z;
  d->y = pos.zoom*y/z;
  return;
}


void col(int y, int h)
{
  int c;

  c = 150 - ((mxh-h)/8) * (24 - (15*y)/SIZE) / 15;
  c = c >> 3;

  if (c>13) c=13;
  if (c<2) c=2;
  c += os_rnd(3);

  os_gcol(0, c);

  return;
}


