Original Usenet thread from alt.ascii-art, started 14 Nov 1994.
C-SOURCE: Ascii-Chaos v. 0.9
alt.ascii-art
· 1 message · 14 Nov 1994
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
*/
Related ASCII art in the Gallery
Explore these categories from our collection of 11,000+ artworks:
,sSSs ,SSSS_/ ,_ sS/`))\// sS//|_(_/ _, SS\\\ `""-.-'` / sSS` jgs-==-'`'-._\
___________ | _______ | | | | | | | | | | | | | | |_______| | |___________|
//O\\
|\/\/\/| | | | | | (o)(o) C _) | ,___| | / /____\
|HHHHH/"\"\HHHHHHH| |HH`\|_.-)'|/'dP,H| |Hb.`\\_/_//'.oddH| |HHHb|`.\/\,'|HHHH| |HHHHHb/\/\/|HHHHH| |"""""""""""""""""| | |"" /\ \ / |"" | | |__/--\ \/ __| |
_________
/___ ___\
//@@@\ /@@@\\
\\@@@/ \@@@//
\___ " ___/
| - |
\_/ jrjc Make your own ASCII art
Turn images, text or 3D into ASCII, or draw your own – right in your browser.
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.