[comp.sys.amiga] Scenery generator in Draco

cg@myrias.UUCP (03/09/87)

Generating good-looking pseudo-random scenery (terrain) has interested me
for a while (I'm into computer game playing as well as compilers). A couple
of years ago I tried to generate scenery using a "volcano" type generator
(lead on by the "Empire" manual). I got one going, but it was VERY slow. I
eventually came up with a method that touches each point only once, and
uses only small integer calculations. The first version I did (in Draco of
course) for the Spectrum card (128 x 192 x 2) in my Compupro CP/M system.
Here follows a version I whipped up for the Amiga. It's in Draco, so you
won't be able to compile it (also you don't have the include files :-( ).
So, following it is the uuencoded object. It takes a few seconds to produce
the image, so have patience.

	Chris Gray (ubc-vision,sask)!alberta!myrias!cg

-------------------cut here--------file: sc.d---------------------------
#include:intuition/miscellaneous.g
#include:intuition/screen.g
#include:intuition/window.g
#include:intuition/intuitext.g
#include:intuition/requester.g
#include:graphics/gfx.g
#include:graphics/view.g
#include:graphics/rastport.g
#include:libraries/dos.g

/*
 * sc.d - fractalish terrain generator.
 *
 *	Date:	  March 5, 1987 (original version sometime in 1985)
 *	Author:	  Chris Gray
 *	Language: Draco
 *	System:	  Amiga
 */

/*
 * The nature of the terrain can be changed by playing with the numbers
 * in 'Range'. If you change SIZE, you must also change the number of
 * values given for 'Range'. The created terrain with SIZE = 8 is 256 pixels
 * by 256 pixels, which doesn't fit on a non-interlaced screen, so only the
 * top 200 pixels are displayed. The terrain is a torus, i.e. wraps around
 * both vertically and horizontally.
 */

/*
 * Feel free to use this algorithm in any games you write, so long as you
 * give me credit for it. (I THINK I invented it, since I've never heard of
 * anything similar, and other programs I've seen use much slower methods.)
 */

uint
    SIZE = 8,
    COUNT = 1 << SIZE,

    SCREEN_WIDTH = 320,
    SCREEN_HEIGHT = 200,
    SCREEN_DEPTH = 5,
    COLOURS = 1 << SCREEN_DEPTH,
    WINDOW_WIDTH = if COUNT < SCREEN_WIDTH then COUNT else SCREEN_WIDTH fi,
    WINDOW_HEIGHT = if COUNT < SCREEN_HEIGHT then COUNT else SCREEN_HEIGHT fi;

[SIZE] uint Range = (32, 32, 32, 22, 14, 8, 4, 2);

[COLOURS] uint ColourMap = (
    0x00f, 0x050, 0x070, 0x0a0, 0x0c0, 0x0e0, 0x4f4, 0x8f8,
    0xdf0, 0xff0, 0xfd0, 0xfb0, 0xf90, 0xf70, 0xe50, 0xe33,
    0xe11, 0xf01, 0xf03, 0xf05, 0xf07, 0xf09, 0xf0b, 0xf0d,
    0xf1f, 0xf3f, 0xf5f, 0xf7f, 0xf9f, 0xfbf, 0xfdf, 0xfff
);

*Screen_t Screen;
*Window_t Window;

uint Seed;

[COUNT, COUNT] int Cell;

/*
 * random - return a random number 0 - passed range.
 */

proc random(uint rang)uint:

    if rang = 0 then
	0
    else
	Seed := Seed * 17137 + 4287;
	Seed := (Seed >> 8) >< (Seed << 8);
	Seed % rang
    fi
corp;

/*
 * set - set a given spot in Cell.
 */

proc set(uint l, c, size; int height)void:
    uint rang;

    rang := Range[size];
    height := height + random(rang) - (rang + 1) / 2;
    Cell[l, c] := height;
corp;

/*
 * grow - grow the basic scenery heights.
 */

proc grow()void:
    uint l, c, i, step, nextStep, l1, l2, c1, c2;

    Cell[0, 0] := 0;
    step := COUNT;
    for i from 0 upto SIZE - 1 do
	nextStep := step / 2;
	for l from 0 by step upto COUNT - 1 do
	    l1 := l + nextStep;
	    l2 := l + step;
	    if l2 = COUNT then
		l2 := 0;
	    fi;
	    for c from 0 by step upto COUNT - 1 do
		c1 := c + nextStep;
		c2 := c + step;
		if c2 = COUNT then
		    c2 := 0;
		fi;
		set(l, c1, i, (Cell[l, c] + Cell[l, c2] + 1) / 2);
		set(l1, c, i, (Cell[l, c] + Cell[l2, c] + 1) / 2);
		set(l1, c1, i, (Cell[l, c] + Cell[l, c2] +
				Cell[l2, c] + Cell[l2, c2] + 2) / 4);
	    od;
	od;
	step := nextStep;
    od;
corp;

/*
 * display - display the resulting scenery.
 */

proc display()void:
    uint l, c;
    int height;

    for l from 0 upto WINDOW_HEIGHT - 1 do
	for c from 0 upto WINDOW_WIDTH - 1 do
	    height := Cell[l, c];
	    SetAPen(Window*.w_RPort,
		    if height < 0 then
			0
		    elif height >= COLOURS then
			COLOURS - 1
		    else
			height
		    fi);
	    pretend(WritePixel(Window*.w_RPort, c, l), void);
	od;
    od;
corp;

/*
 * main program.
 */

proc main()void:
    NewWindow_t newWindow;
    DateStamp_t ds;
    IntuiText_t bodyText, positiveText, negativeText;

    bodyText := IntuiText_t(COLOURS - 1, 0, 0, 51, 5, nil, nil, nil);
    bodyText.it_IText := "Done";
    positiveText := IntuiText_t(COLOURS - 1, 0, 0, 7, 3, nil, nil, nil);
    positiveText.it_IText := "Next";
    negativeText := IntuiText_t(COLOURS - 1, 0, 0, 7, 3, nil, nil, nil);
    negativeText.it_IText := "Quit";
    if OpenIntuitionLibrary(0) ~= nil then
	if OpenGraphicsLibrary(0) ~= nil then
	    if OpenDosLibrary(0) ~= nil then
		Screen := OpenScreen(&NewScreen_t(
		    0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, 0, 1,
		    0x0, CUSTOMSCREEN, nil, nil, nil, nil));
		if Screen ~= nil then
		    LoadRGB4(&Screen*.sc_ViewPort, &ColourMap[0], COLOURS);
		    newWindow := NewWindow_t(
			0, 0, WINDOW_WIDTH, WINDOW_HEIGHT,
			FREEPEN, FREEPEN,
			0x0, BORDERLESS | ACTIVATE | NOCAREREFRESH,
			nil, nil, nil, nil, nil, 0, 0, 0, 0,
			CUSTOMSCREEN);
		    newWindow.nw_Screen := Screen;
		    Window := OpenWindow(&newWindow);
		    if Window ~= nil then
			DateStamp(&ds);
			Seed := (ds.ds_Minute >< ds.ds_Tick) | 1;
			while
			    grow();
			    display();
			    AutoRequest(Window, &bodyText, &positiveText,
					&negativeText, 0x0, 0x0, 150, 50)
			do
			od;
			CloseWindow(Window);
		    fi;
		    CloseScreen(Screen);
		fi;
		CloseDosLibrary();
	    fi;
	    CloseGraphicsLibrary();
	fi;
	CloseIntuitionLibrary();
    fi;
corp;
-------------------cut here--------file: sc.uue-------------------------
begin 644 sc
M```#\P`````````#``````````(````"``"`!@```BD```/I`````D[Y````
M```````#[`````$````"`````@````````/R```#ZP``@`8```/R```#Z0``
M`BDCP````!(CR````!9.^0``!#0`````````````2.<_/DIO`#!F```(0H=@
M``!&/CD````(SOQ"\=Y\$+\SQP````@^.0````C@3SPY````".%.O4<SQP``
M``@^.0````@"AP``__^.[P`P2$<"AP``__\@!TS??/PB7U2/3M$``$CG/SY5
MCT'Z`&)-T#XO`#0"AP``___CCSZV>``^+P`R/Q=.N0```!P\`-Y&/!=21N).
MGD8_1P`R/B\`.`*'``#__^&//"\`-@*&``#__]Z&XX\@?`````HQKP`R>`!4
MCTS??/PB7U"/3M$`(``@`"``%@`.``@`!``"``!(YS\^GOP`$D)Y````"C]\
M`0``"D)'/T<`#'X',"\`##]```RP1V(``BX\+P`*XDX_1@`(0D8_1@`0/"\`
M"CH\`/\P+P`0/T``$+!%8@`!^#@O`!#8;P`(/T0`!C@O`!#8;P`*/T0`!`QO
M`0``!&8```9";P`$0D0_1``.."\`"C8\`/\P+P`./T``#K!#8@`!K#0O``[4
M;P`(/T(``C0O``[4;P`*/H(,5P$`9@``!$)7/R\`$#\O``0_+P`0-"\`%@*"
M``#__^&*+P<^+P`8`H<``/__U(?CBB!\````"C0P*``^+P`:`H<``/__X8\O
M!CPO``X"A@``___>AN./('P````*U'!X`%)"XD(L'RX?/P).N0```(`_+P`&
M/R\`$#\O`!`T+P`6`H(``/__X8HO!SXO`!@"AP``___4A^.*('P````*-#`H
M`#XO``X"AP``___ACR\&/"\`'`*&``#__]Z&XX\@?`````K4<'@`4D+B0BP?
M+A\_`DZY````@#\O``8_+P`$/R\`$#0O`!8"@@``___ABB\'/B\`&`*'``#_
M_]2'XXH@?`````HT,"@`/B\`&@*'``#__^&/+P8\+P`.`H8``/__WH;CCR!\
M````"M1P>``^+P`2`H<``/__X8\\+P`<`H8``/__WH;CCR!\````"M1P>``^
M+P`2`H<``/__X8\\+P`.`H8``/__WH;CCR!\````"M1P>`!40N1"+!\N'S\"
M3KD```"`,"\`#M!$9`#^3C`O`!#01F0`_@(_;P`(``HP+P`,4D!D`/W,WOP`
M$DS??/Q.=4CG/SY=CT)'/T<`!#X\`,<P+P`$/T``!+!'8@``LD)&/T8``CP\
M`/\P+P`"/T```K!&8@``D#HO``0"A0``___AC3@O``("A```___:A..-('P`
M```*/K!8`"QY````!"\N`#)*;P`$;```"$*%8```&`QO`"``!&T```AZ'V``
M``@Z+P`$2,4O!4ZY```'1"QY````!"\N`#(Z+P`&`H4``/__+P4Z+P`,`H4`
M`/__+P5.N0``!R`:`#`O``)20&0`_VHP+P`$4D!D`/](7(],WWS\3G4``$CG
M/SZ>_`!X3>\`*&$4'P`````S``4````````````````@7TO0<!0<W5.`9OIA
M!D1O;F4``"!?+T@`-$WO`!1A%!\`````!P`#````````````````(%]+T'`4
M'-U3@&;Z809.97AT```@7R](`"!-UT'Z_\Y+T'`4'-U3@&;Z8091=6ET```@
M7R](``PO/`````!.N0``!V`L0"`.9P`!DB\\`````$ZY```&L"Q`(`YG``%X
M+SP`````3KD```A(+$`@#F<``5YA(``````!0`#(``4``0````\`````````
M````````````(%]-T"\.3KD```?<+$`CS@`````L>0````"]_`````!G``$2
M+'D`````3>X`+"\.0?H!'DW0+PXO/````"!.N0``!OQ-[P!(83```````0``
MR/__```````"&`````````````````````````````````````````\@7TO0
M<#`<W5.`9OHO>0``````9DWO`$@O#DZY```']"Q`(\X````$+'D````$O?P`
M````9P``>$WO`#PO#DZY```(C"XO`$`L+P!$O8=\`8Z&,\<````(3KD```#\
M3KD```-<+SD````$3>\`+"\.3>\`'"\.3>\`#"\.+SP`````+SP`````+SP`
M``"6+SP````R3KD```@,'@!*!V8`_[@O.0````1.N0``!\0O.0````!.N0``
M!ZQ.N0``"'1.N0``!N1.N0``!Y3>_`!X3-]\_$YU``\`4`!P`*``P`#@!/0(
M^`WP#_`/T`^P#Y`/<`Y0#C,.$0\!#P,/!0\'#PD/"P\-#Q\//P]?#W\/GP^_
M#]\/_R)?(!\O"4/Z`!@O#BQY````!$ZN_=@L7R/```(`#$YU9W)A<&AI8W,N
M;&EB<F%R>0`````B>0`"``PO#BQY````!$ZN_F(L7TYU```O#B!O`!`B;P`,
M("\`""QY``(`#$ZN_T`L7R)?WOP`#$[1```O#B)O`!`@+P`,(B\`""QY``(`
M#$ZN_KPL7R)?WOP`#$[1```O#B)O``P@+P`(+'D``@`,3J[^JBQ?(E]0CT[1
M(E\@'R\)0_H`&"\.+'D````$3J[]V"Q?(\```@`03G5I;G1U:71I;VXN;&EB
M<F%R>0```")Y``(`$"\.+'D````$3J[^8BQ?3G4``"\.(&\`""QY``(`$$ZN
M_[XL7R)?6(].T2\.(&\`""QY``(`$$ZN_[@L7R)?6(].T2\.(&\`""QY``(`
M$$ZN_SHL7R)?6(].T2\.(&\`""QY``(`$$ZN_S0L7R)?6(].T4CG#`X@;P`T
M(F\`,"1O`"PF;P`H("\`)"(O`"`D+P`<)B\`&"QY``(`$$ZN_J1,WW`P(E_>
M_``@3M$``")?(!\O"4/Z`!@O#BQY````!$ZN_=@L7R/```(`%$YU9&]S+FQI
M8G)A<GD`(GD``@`4+PXL>0````1.KOYB+%].=0``+PXB+P`(+'D``@`43J[_
M0"Q?(E]8CT[1```#[````"P````!```(E```"'8```AB```(,@``!_P```?D
M```'S```![0```>6```'>@``!U````<P```'#```!N8```;*```%[@``!CX`
M``8````%Q```!;X```9*```%J```!48```4V```%,````^X```.X```#K@``
M`Q8```+R```"S@```J@```)F```"0````?X```'8```!!@```-0```!<````
M5@```$P```!$````/@```#`````8`````@``!,H```9B```%]```!6````7Z
M```%V@``!2@```6V```&4```!D0```8P```$\@``!E8```3>```&7````^@`
G``00```"$@```GH```,J````I`````X````(`````@````````/R
`
end