/* 
   make_city.c
   Program to make a pov ray scene file with a city in it.
   created by Peter C. Capasso and released in to the
   public domain.
   For usage, see readme or look at the code, duh.
*/

#include<exec/types.h>
#include<ctype.h>
#include<stdio.h>
#include<stdlib.h>
#include<stddef.h>
#include<time.h>  /* for random */


/* defines */
#define mod %
#define eq ==
#define neq !=
#define OKDOKEY 0
#define DOOPS 20
#ifndef MAX_STR
#define MAX_STR 1024
#endif
#define SMALL 0
#define BIG 1
#define HUGE 2


/* forward references that C loves so much.  YECH! */
/* -------------------------------------------------------------------------- */
unsigned int rnd(unsigned int);
void declare_texture(int, int);
void do_building(int, int, int);


/* global variables */
/* -------------------------------------------------------------------------- */
unsigned long chad_seed;
int height_index[16] = {  8,  8, 10, 12,
                         14, 16, 18, 20,
                         22, 24, 26, 28,
                         30, 32, 40, 52 };
int size_flag = SMALL;
static char amiga_version[] = "$VER: Version 0.90\n";


/* the actual routines */
/* -------------------------------------------------------------------------- */


unsigned long do_chadabe()
{
  unsigned long temp;

  temp = (chad_seed >> 1) | 0x80000000;
  chad_seed ^= temp;
  return(chad_seed);
}


unsigned int rnd(r)
unsigned int r;
{
  unsigned long temp;
  temp = rand() ^ do_chadabe();
  return((unsigned int) (temp mod r));
}


void do_camera()
{
  printf("\
camera {\n\
  location <0, 0, 0>\n\
  direction <0, 0, 1.5>\n\
  up  <0, 1, 0>\n\
  right <1.37, 0, 0>\n\
  rotate x*5\n\
  rotate y*35\n");
  switch (size_flag) {
    case BIG :
    case HUGE :
      printf("  translate <-90, 55, -140>\n");
      break;
    default :
      printf("  translate <-90, 37, -140>\n");
  }
printf("}\n\n\n");
}


void declare_texture(color, direction)
int color;  /* which color scheme */
int direction; /* which direction for the gradient */
{
  switch (direction) {
    case 0 :
      printf("#declare xtexture%d = texture {\n", color);
      break;
    case 1 :
      printf("#declare ytexture%d = texture {\n", color);
      break;
    default :
      printf("#declare ztexture%d = texture {\n", color);
  }
  printf("\
    pigment {\n");
  switch (direction) {
    case 0 :
      printf("      gradient <1, 0, 0>\n");
      break;
    case 1 :
      printf("      gradient <0, 1, 0>\n");
      break;
    default :
      printf("      gradient <0, 0, 1>\n");
  }
  printf("\
      color_map {\n");
  if (direction eq 2) { /* if it is Z, make it clear */
    printf("\
        [ 0.0 clear ]\n\
        [ 0.1 clear ]\n");
  } else {
    printf("\
        [ 0.0 beam%d ]\n\
        [ 0.1 beam%d ]\n", color, color);
  }
  if (direction eq 1) { /* if it is Y, make it clear */
    printf("\
        [ 0.1 clear ]\n\
        [ 0.9 clear ]\n");
  } else {
    printf("\
        [ 0.1 window%d ]\n\
        [ 0.9 window%d ]\n", color, color);
  }
  if (direction eq 2) { /* if it is Z, make it clear */
    printf("\
        [ 0.9 clear ]\n\
        [ 1.0 clear ]\n");
  } else {
    printf("\
        [ 0.9 beam%d ]\n\
        [ 1.0 beam%d ]\n", color, color);
  }
  printf("\
      }\n\
    }\n");
  printf("\
    finish { ambient 0.3 diffuse 0.7 }\n\
    scale <2, 2, 2>\n\
  }\n\n\n");
}


void do_declares()
{
  int color, dir;

  printf("\
#declare beam1 = color red 0.2 green 0.2 blue 0.2\n\
#declare window1 = color red 0.9 green 0.9 blue 0.9\n\
#declare clear = color red 1 green 1 blue 1 filter 1\n");
  printf("\
#declare beam2 = color red 1.0 green 1.0 blue 1.0\n\
#declare window2 = color red 0.7 green 0.7 blue 0.7\n");
  printf("\
#declare beam3 = color red 0.8 green 0.5 blue 0.5\n\
#declare window3 = color red 0.6 green 0.6 blue 0.6\n");
  printf("\
#declare beam4 = color red 0.9 green 0.9 blue 0.9\n\
#declare window4 = color red 1.0 green 1.0 blue 1.0\n");
  printf("\n\n");
  for (color = 1; color neq 5; color++)  /* color 1 - 4 inclusive */
    for (dir = 0; dir neq 3; dir++) 
      declare_texture(color, dir);
}


void do_sky()
{
  printf("\
sky_sphere {\n\
  pigment {\n\
    gradient <0, 1, 0>\n\
    color_map {\n\
      [0.0 color red 1 green 1 blue 1 ]\n\
      [0.02 color red 0 green 0.5 blue 1 ]\n\
      [0.25 color red 0 green 0.41 blue 1 ]\n\
      [1.1 color red 0 green 0.1 blue 1 ]\n\
    }\n\
  }\n\
}\n\n");
}


void do_floor()
{
  printf("\n\
plane {\n\
  <0.0, 1.0, 0.0>, -0.001\n\
  pigment { color red 1.0 green 0.9 blue 0.8 }\n\
  finish { ambient 0.4 diffuse 0.6 }\n\
}\n\n");
}


void do_building(x, z, color)
int x;
int z;
int color;
{
  int x1, x2, z1, z2, y;

  x1 = rnd(4) * 2 - 10;
  x2 = rnd(4) * 2 + 4;
  z1 = rnd(4) * 2 - 10;
  z2 = rnd(4) * 2 + 4;
  y = height_index[rnd(16)];
  printf("\
box {\n\
  <%d, 0, %d>, <%d, %d, %d>\n", x1, z1, x2, y, z2);
  printf("  texture { xtexture%d } \n", color);
  printf("  texture { ztexture%d } \n", color);
  printf("  texture { ytexture%d } \n", color);
  printf("  translate <%d, 0, %d>\n", x, z);
  printf("}\n\n\n");
}


do_city_block()
{
  int x, z, color;

  for (x = -34; x < 35; x += 22) {
    for (z = -34; z < 35; z += 22) {
      color = 1 + rnd(4);
      /* we call do_building twice to get stepped
         buildings.  IE - a short wide building with a tall
         then projection on top.  This also allows allows
         buildings with complex cross sections */
      do_building(x, z, color);
      do_building(x, z, color);
      if (size_flag neq SMALL)
        printf("\n\n");
    }
  }
}


void do_city()
{
  int x, z, dimension = 3;

  switch (size_flag) {
    case HUGE :
      dimension = 9;
    case BIG :
      for (x = 0; x neq dimension; x++)
        for (z = 0; z neq dimension; z++) {
          printf("union {\n");
          do_city_block();
          printf("translate <%d, 0, %d>\n", x * 90, z * 90);
          printf("}\n\n\n");
        }
      break;
    default:
      do_city_block();
  }
}


void do_light()
{
  printf("\
light_source {\n\
  <-404.0, 478.2, -364.0>\n\
  color red 1.0 green 1.0 blue 1.0\n\
}\n\n\n");
}


long mess_it_up(seed)
long seed;
{
  unsigned char temp;
  unsigned char *f;

  chad_seed = seed;
  f = (unsigned char *) &seed;
  temp = f[1];
  f[1] = f[2];
  f[2] = temp;
  return(seed);
}


void usage()
{
  fprintf(stderr, "make_city.\
  \033[1mUsage\033[m: make_city [-h|big|huge]\n");
}


void usage_exit()
{
  usage();
  exit(DOOPS);
}


main(argc, argv)
int argc;
char *argv[];
{
  long the_seed;

  if (argc eq 0)
    exit(DOOPS);
  if (argc > 1) {
    if (stricmp(argv[1], "big") eq 0) {
      size_flag = BIG;
      fprintf(stderr, "making a BIG city\n");
    }
    if (stricmp(argv[1], "huge") eq 0) {
      size_flag = HUGE;
      fprintf(stderr, "making a HUGE city\n");
    }
    if (
        (strcmp(argv[1], "?") eq 0) ||
        (strcmp(argv[1], "-h") eq 0)
       ) {
      usage_exit();
    }
  }
  the_seed = time(NULL);  /* simple way to initialize random seed */
  the_seed = mess_it_up(the_seed);
  srand((unsigned int) the_seed);

  do_camera();
  do_declares();
  do_sky();
  do_floor();
  do_light();
  do_city();
  exit(OKDOKEY);
}

/* actual end of this file */
