Settings

The page will reload to apply your changes.
Theme

ASCII Art Font

ASCII Art Menu

Original Usenet thread from alt.ascii-art, started 14 Nov 1994.
 _   _                     _        _             _     _           
| | | |___  ___ _ __   ___| |_     / \   _ __ ___| |__ (_)_   _____ 
| | | / __|/ _ \ '_ \ / _ \ __|   / _ \ | '__/ __| '_ \| \ \ / / _ \
| |_| \__ \  __/ | | |  __/ |_   / ___ \| | | (__| | | | |\ V /  __/
 \___/|___/\___|_| |_|\___|\__| /_/   \_\_|  \___|_| |_|_| \_/ \___|
C-SOURCE: Ascii-Chaos v. 0.9

C-SOURCE: Ascii-Chaos v. 0.9

alt.ascii-art · 1 message · 14 Nov 1994
Tamminen Eero <t15...@proffa.cc.tut.fi> ASCII art 14 Nov 1994 18:49 · raw headers · report
Here's a little program i put together during the weekend.

It outputs chaotical pictures in modulo, height or shade coloring (8
ascii 'rasters') in 2D and 3D :) to the screen or file.

Compile it and give me comments...


	- Eero -

----
/*	Ascii-Chaos v. 0.9						*/
/*	1994 (C) Eero Tamminen						*/
/* 	Compile with : gcc -O -o aos aos.c				*/

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <memory.h>
#include <macros.h>

#ifndef	TRUE
#define	FALSE	0
#define	TRUE	!FALSE
#endif

/* Chaos type */
#define ANT	1
#define MANDEL	2
/* output view */
#define NORMAL	1
#define	EYE	2
/* coloring scheme */
#define MODULO	0
#define HEIGHT	1
#define ANGLE	2
/* save file format */
#define ASCII	1
#define PGM	2
/* percpective viewing direction */
#define TOP	1
#define BOTTOM	2

/* -------------------------------------------------------------------- */
/*			globals and defaults				*/

/* max. lenght for raster array */
#define	HEIGHTS	8
int  Heights = HEIGHTS;
char Rasters[HEIGHTS+1] = ".*#%=+:-.";

int   Columns = 38, Rows = 22;		/* 'screen' size		*/
short Seed = 0x2;			/* move sequence bin. string	*/
short Lenght = 2;			/* Lenght of seq. (2-16)	*/
long  Iterations  = 2000;
int   Chaos_mode = ANT;
int   View_mode = NORMAL;		/* 2D or perspective		*/
int   Color_mode = MODULO;		/* height / steepness / modulo	*/
int   Head_mode = BOTTOM;		/* viewing direction		*/
int   File_mode = FALSE;		/* Save to file (ascii / pgm)	*/
int   Pscale = FALSE;			/* perspective scaling 		*/

/* -------------------------------------------------------------------- */
int	parse(int argc, char *argv[]);		/* parser command line	*/
void	help();
short   do_mandel(short *grid);			/* do Mandelbrot	*/
short	do_ant(short *grid);			/* do 'The Ant Walk'	*/
int     do_color(short *grid, unsigned char *pict, int mode, short value);
int     do_ortho(unsigned char **pict, int range);
int     angle2num(int angle);

/* -------------------------------------------------------------------- */
/*				main					*/

int main(int argc, char *argv[])
{
  FILE *fp;
  int antx, anty;
  short *grid, value;
  unsigned char *pict;
  long line;

  puts("\nAscii-Chaos v. 0.9 (C) 1994 Eero Tamminen");
  puts("");

  /* get command line args */
  if(parse(argc, argv))
  {
    /* create and initialize the grid 'arrays' */
    grid = (short *) malloc(2L * Columns * Rows);
    pict = (unsigned char *) malloc((long)Columns * Rows);
    if(!(grid && pict))
    {
      puts("Not enough memory!");
      return(1);
    }
    for(anty = 0; anty < Rows; anty ++)
    {
      line = (long)anty * Columns;
      for(antx = 0; antx < Columns; antx ++)
      {
        *(grid + line + antx) = 0;
        *(pict + line + antx) = ' ';
      }
      *(pict + line + antx - 1) = '\0';
    }

    /* make the view */
    puts("Building Chaos...");
    if(Chaos_mode == ANT)
      value = do_ant(grid);
    else
      value = do_mandel(grid);

    puts("Visualizing it...");
    if(View_mode == EYE)
    {
      value = do_color(grid, pict, (Color_mode == ANGLE ? HEIGHT : Color_mode), value);
      puts("Putting it into perspective...");
      do_ortho(&pict, value);
    }
    else
      do_color(grid, pict, Color_mode, value);

    if(File_mode != PGM && View_mode == EYE)
          *Rasters = ' ';

    /* initialize save files */
    if(File_mode)
    {
      puts("Saving...");
      fp = fopen((File_mode == ASCII ? "aos_out.asc" : "aos_out.ppm"), "wb");
      if(File_mode == PGM)
        fprintf(fp, "P2\n%d %d\n255\n", Columns-1, Rows);
      fprintf(fp, "# Produced with Ascii-Chaos v 0.9 (C) 1994 by Eero Tamminen.\n");
    }
    else
      fp = stdout;

    /* save / show the results */
    for(anty = 0; anty < Rows; anty ++)
    {
      line = (long)anty * Columns;
      for(antx = 0; antx < Columns - 1; antx ++)
        if(File_mode == PGM)
          fprintf(fp, "%d ", *(pict + line + antx));
        else
          fprintf(fp, "%c", Rasters[*(pict + line + antx)]);
      fprintf(fp, "\n");
    }
    if(File_mode)
    {
      puts("Done.");
      fclose(fp);
    }

    /* free 'arrays' */
    free(pict);
    free(grid);
  }
  return(0);
}

int parse(int argc, char *argv[])
{
  /* change global variables etc. */
  int i, idx;
  char mark;

  i = 0;
  while(++i < argc)
    {						/* check all arguments	*/
      mark = toupper(argv[i][0]);		/* first character...	*/
      switch(mark)
      {
	case '-':				/* get 'color' string	*/
          switch(toupper(argv[i][1]))
          {
            case 'D':
              View_mode = EYE;
              break;
            case 'Z':
              Pscale = max(2, atoi(&argv[i][2]) & 0xFF);
              break;
            case 'T':
              Head_mode = TOP;
              break;
            case 'B':
              Head_mode = BOTTOM;
              break;
            case 'A':
              File_mode = ASCII;
              break;
            case 'P':
              File_mode = PGM;
              Heights = 256;
              break;
            case 'H':
              Color_mode = HEIGHT;
              break;
            case 'S':
              Color_mode = ANGLE;
              break;
            case 'M':
              Color_mode = MODULO;
              break;
            case 'X':				/* screen width		*/
              Columns = max(8, atoi(&argv[i][2]) & 0xFFF);
              break;
            case 'Y':				/* screen height	*/
              Rows = max(8, atoi(&argv[i][2])) & 0xFFF;
              break;
            default:				/* unrecogniced option	*/
              help();
              return(FALSE);
          }
	  break;
	case 'M':
	  Chaos_mode = MANDEL;
	  Lenght = HEIGHTS;
	  Iterations = 8;
	  break;
	case 'R':				/* new Seed		*/
	case 'L':
	  Seed = 0;
	  idx = 1;
	  do
	    {
	      Seed =(Seed << 1);
	      if(mark == 'R')
		Seed |= 1;
	      idx++;
	      mark = toupper(argv[i][idx]);
	    }
	  while(idx < HEIGHTS && (mark == 'R' || mark == 'L'));
	  Lenght = idx - 1;
	  break;
	case '0':
	case '1':
	case '2':
	case '3':
	case '4':
	case '5':
	case '6':
	case '7':
	case '8':
	case '9':
	  Iterations = max(4, atol(argv[i]));
	  break;
	default:				/* unrecogniced option	*/
	  help();
	  return(FALSE);
      }
    }
  return(TRUE);
}

void help()
{
  puts("Options controlling the output:");
  puts("  -x32      Set area width to 32 characters / pixels.");
  puts("  -y32      Set area height to 32 characters / pixels.");
  puts("  -h/-s/-m  Color according to height / steepness / sequence modulo.");
  puts("  -d        Select a 3D (perspective) view instead of a flat 2D.");
  puts("  -z32      Scale perspective view height to an absolute value 32.");
  puts("  -t/-b     Set perspective viewing direction to top or bottom.");
  puts("");
  puts("  -a/-p     Output into a file in ascii / portable greymap format.");
  puts("");
  puts("Ant-walk (default):");
  puts("  An example: aos rllllr 2000");
  puts("  rllllr    Ant's movement sequence (R = right, L = left).");
  puts("  2000      How many moves are put into doing the Anthill.");
  puts("");
  puts("Mandelbrot:");
  puts("  An example: m 32 -h -p -x64 -y64");
  puts("  m         Use Mandelbrot instead of Ant-walk.");
  puts("  32        How many iterations before deciding point to be inside.");
}

/* Calculate the 'standard' Mandelbrot's image:
 * Iterate 'Z = Z� + c' until it zooms to infinity or count is reached.
 * z and c are complex numbers!
 * Point's color = count.
 */
short do_mandel(short *grid)
{
  /* Values x1 = -2.75, y1 = -2.4, x2 = 2.0, y2 = 2.4, limit = 8.0
   * are shifted left 10 times to be able to calculate with integers.
   */

  /* Define the place of the calculation on the imaginary plane. */
  long x1 = -2816L, y1 = -2457L, x2 = 2048L, y2 = 2457L;

  /* Define 'step's and 'infinity'^2 and max. iteration count. */
  long dx, dy, limit = 0x2000000L;

  /* Variables for calculation: */
  long imag, real, x, y, a;

  int count, xx, yy = 0;
  long line;

  dx = (x2 - x1) / Columns;
  dy = (y2 - y1) / Rows;

  /* imaginary axis */
  for(imag = y1; imag < y2; imag += dy)
  {
    xx = 0;
    line = (long)yy * Columns;
    /* real axis */
    for(real = x1; real < x2; real += dx)
    {
      /* calculate one pixel's 'escape' value ie. color/height */
      x = y = 0L;
      count = 0;
      do
      {
        a = x;
        x = ((x * x - y * y) >> 10) + real;
        y = (2 * a * y >> 10) + imag;
        count ++;
      } while((count < Iterations) && (x * x + y * y <= limit));
      *(grid + line + xx) = count;
      xx ++;
    }
    yy ++;
  }
  return(Iterations);
}

/* -------------------------------------------------------------------- */
/*			'Do the Ant Walk'				*/
short do_ant(short *grid)
{
  int antx, anty, heading = 0;
  short *value, max_val = 0;
  long move = 0;

  antx = Columns >> 1;				/* initial position	*/
  anty = Rows >> 1;				/* at center		*/

  do
    {
      value = grid + anty * Columns + antx;
      /* use modulo to get new heading and increase the grid value */
      if(Seed & (1 << (*value % Lenght)))
      {
        if((++ heading) > 3)			/* new heading		*/
          heading = 0;
      }
      else
        if((-- heading) < 0)
          heading = 3;

      if(++(*value) > max_val)
      {
        max_val = *value;
        /* check for short overshoot */
        if(max_val > 32000)
          move = Iterations;
      }

      switch(heading)
	{			/* new place	*/
	case 0:
	  anty ++;		/* down		*/
	  break;
	case 1:
	  antx --;		/* left		*/
	  break;
	case 2:
	  anty --;		/* up		*/
	  break;
	case 3:
	  antx ++;		/* right	*/
	  break;
	}
      if(antx >= Columns)	/* check boundarys	*/
	antx = 0;
      if(anty >= Rows)
	anty = 0;
      if(antx < 0)
	antx = Columns - 1;
      if(anty < 0)
	anty = Rows - 1;
    }
  while(move++ < Iterations);			/* until a key is hit	*/

  return(max_val);
}

int do_color(short *grid, unsigned char *pict, int mode, short divide)
{
  int i, antx, anty, angle, mini = 0;
  long place, line;

  if(mode == HEIGHT)
  { /* search the smallest value on grid (for bump map scaling) */
    mini = divide;
    for(anty = 0; anty < Rows; anty ++)
      line = (long)anty * Columns;
      for(antx = 0; antx < Columns - 1; antx ++)
      {
        i = *(grid + line + antx);
        if(i < mini)
          mini = i;
      }
    divide -= mini;
  }

  for(anty = 0; anty < Rows; anty ++)
  {
    line = (long)anty * Columns;
    for(antx = 0; antx < Columns - 1; antx ++)
    {
      place = line + antx;
      switch(mode)
      {
        case MODULO:
          *(pict + place) = *(grid + place) % Lenght;
          break;
        case HEIGHT:
            *(pict + place) = (long)(*(grid + place) - mini) * Heights / divide;
          break;
        case ANGLE:
          angle = angle2num(*(grid + place + 1) - *(grid + place));
          *(pict + place) = angle;
          if(angle > mini)
            mini = angle;
          break;
      }
    }
  }
  switch(mode)
  {
    case MODULO:
      return(Lenght);
    case HEIGHT:
      return(Heights);
    case ANGLE:
      return(mini);
    default:
      return(256);
  }
}

int angle2num(int angle)
{
  if(File_mode == PGM)
    angle += 127;
  else
  {
    angle += 4;
    if(angle > 8)
      angle = 8;
    else
      if(angle < 2)
        angle = 2;
  }
  return(angle);
}

int do_ortho(unsigned char **pict, int range)
{
  int i, x, y, xx, yy, ox, oy, offset, oy1, oy2, hz, oz, eye, height;
  unsigned char *view, tag;
  long place, line;

  /* relative eye place & orthogonal view area */
  eye = Rows * 2;
  oz = Columns / 2;
  xx = Columns;
  if(Pscale)
    height = Pscale;
  else
    height = range;
  oy = height / 2;
  offset = oy / 2;
  height += oy;
  yy = height - offset + 1;
  if(!(view = (unsigned char *)malloc((long)xx * yy)))
  {
    puts("Not enough memory!");
    return(FALSE);
  }

  /* empty area */
  for(place = 0; place < (long)xx*yy; place ++)
    view[place] = '\0';

  /* move calculated values into orhtogonal an 'area' */
  for(y = Rows; --y >= 0;)
  {
    if(Head_mode == TOP)
      line = (long)y * Columns;
    else
      line = (long)(Rows - y - 1) * Columns;
    oy2 = eye * height / (eye + y);
    for(x = 0; x < Columns - 1; x ++)
    {
      tag = *((*pict) + line + x);
      if(Pscale)
        hz = tag * Pscale / range;
      else
        hz = tag;
      if(Color_mode == ANGLE)
          tag = angle2num(*((*pict) + line + x + 1) - tag);

      ox = eye * (x - oz) / (eye + y) + oz;
      oy1 = eye * (height - hz) / (eye + y);
      place = (long)(oy1 - offset) * xx + ox;
      for(i = oy1; i < oy2; i ++)
      {
        view[place] = tag;
        place += xx;
      }
    }
    view[(long)y * xx + x] = '\0';
  }

  free(*pict);
  (*pict) = view;
  Columns = xx;
  Rows = yy;
  return(TRUE);
}

/* Perspective used:
 *
 *   Z
 *
 *   ^   Y
 *   | _
 *   | /|
 *   |/
 *   \------> X
 *
 * Normal 2D view for the 'anthill':
 *
 *   Y
 *
 *   ^
 *   |
 *   |
 *   \-----> X
 */

About this thread. These messages were posted publicly to the newsgroup alt.ascii-art in 1994 and are mirrored here unchanged as part of the Historic Archives – only email addresses are masked. The artwork and text belong to their original authors: if you copy a piece, keep the artist's initials or signature intact and credit them where you can. Are you one of the authors? Contact us to get your posts attributed, connected to your artist profile, or removed.

Report this message

Help us keep the archive clean and accurate. Reports are reviewed by a person – nothing is changed automatically.

Help classify this post