#define VIEW_HEIGHT 600	//растяжение
#define XDOTS       320
#define YDOTS       200
#define MAXCOLOR    219
#define MINCOLOR    64
#define BPL         320
#define MAXDEPTH    20	//сглаживание поверхности
#define K0          3
#define K2          64	//высота

int invtab[MAXDEPTH];
unsigned char height[256*256], color[256*256];
int oldy[XDOTS];
int oldc[XDOTS];
int retraces;

int val(int x1,y1,x2,y2,len)
{
	$push EBX,ESI
	y1&=255;
	y2&=255;
	EBX=random(4)-1*len;
	EAX = height[x1&255*256+y1]+height[x2&255*256+y2]>>1+EBX;
	IF(long EAX<1)EAX=1;
	IF(EAX>255)EAX=255;
	$pop ESI,EBX
}

void makeplasma(int x1,y1,x2,y2)
{
int xc,yc,len;
	if(len=x2-x1 >= 2){
		xc=x1+x2>>1;
		yc=y1+y2>>1;
		EBX=y1&255;
		ESI=xc*256;
		IF(!height[ESI+EBX])height[ESI+EBX]=val(x1,y1,x2,y1,len);
		EBX=y2&255;
		IF(!height[ESI+EBX])height[ESI+EBX]=val(x1,y2,x2,y2,len);
		ESI=x1&255*256+yc;
		IF(!height[ESI])height[ESI]=val(x1,y1,x1,y2,len);
		ESI=x2&255*256+yc;
		IF(!height[ESI])height[ESI]=val(x2,y1,x2,y2,len);
		val(x1,yc,x2,yc,len);
		$push EAX
		EAX=val(xc,y1,xc,y2,len);
		$pop EBX
		height[xc*256+yc]=long EAX+EBX>>1;
		makeplasma(x1,y1,xc,yc);
		makeplasma(xc,y1,x2,yc);
		makeplasma(x1,yc,xc,y2);
		makeplasma(xc,yc,x2,y2);
	}
}

// voxel routines
void initvoxels()
{
int i,j;
// make inverse "1/x" table
	FOR(ESI=0;ESI<MAXDEPTH;ESI++){
		EBX=ESI+1;
		invtab[ESI*4]=256/EBX;
	}
// make surface height table
	ES=DS;
	memset(#height,sizeof(height),0);
	makeplasma(0,0,256,256);
// make surface color table
	FOR(ESI=0;ESI<256;ESI++){
		FOR(EBX=0;EBX<256;EBX++){
			EDI=ESI*256+EBX;
			EDX=ESI+3&0xff*256;
			EDX+=EBX;
			EAX=long height[EDI]-height[EDX]<<2+128;
			IF(long EAX<0)EAX=0;
			ELSE IF(EAX>255)EAX=255;
			ECX=EAX;
			EAX=MAXCOLOR-MINCOLOR*ECX/256+MINCOLOR;
			color[EDI]=AL;
		}
	}
// remove noise in the surface height table
	FOR(i=0;i<256;i++){
		FOR(j=0;j<256;j++){
			EBX=j+1&0xff;
			EDX=i*256+j;
			EDI=i+1&0xff*256;
			height[EDX]=long height[EDX]+height[EDI+j]+
			height[i*256+EBX]+height[EDI+EBX]>>2;
		}
	}
}

void draw(int posx,posy,posz)
{
int du;
int u,basey,adj;
	ES=DS;
	ECX=XDOTS;
	EDI=#oldy;
	EAX=YDOTS-1;
	$rep $stosd
	ECX=XDOTS;
	EDI=#oldc;
	EAX=0;
	$rep $stosd
	for(ESI=0;ESI<MAXDEPTH;ESI++,posy+=256){
		adj=invtab[ESI*4];
		EBX=EAX*posz>>16;
		basey=YDOTS/2+EBX;
		adj+=K2;
		EBX=XDOTS*K0>>1*ESI;
		u=posx-EBX;
		du=K0*ESI;
		$push ESI
		for(ESI=0;ESI<XDOTS;ESI++){
			EAX = u>>8&255;
			EDX = posy>>8&255;
			EDI=EAX*256+EDX;
			EBX = height[EDI];
			ECX = color[EDI];
			EDI=EAX+1&255*256;
			EDI+=EDX;
			EDX=SSBYTE[#u];
			$push EDX
			EAX=int height[EDI]-EBX*EDX>>8;
			EBX +=EAX;
			$pop EDX
			EAX=int color[EDI]-ECX*EDX>>8;
			ECX += EAX;
			EBX=EBX*adj>>8;
			EAX = basey - EBX;
			IF(MINUSFLAG) EAX = 0;
			EBX=oldy[ESI*4];
			if(int EBX>EAX){
				EBX><EAX;
				oldy[ESI*4]=EBX;
				EDI=EAX-EBX;
				EBX=EAX*BPL;
				EAX=oldc[ESI*4];
				ECX><EAX;
				oldc[ESI*4]=EAX;
				EAX=int EAX-ECX<<8/EDI;
				EDX=EAX;
// EAX хранит в себе col
				EAX=ECX<<8;
				ECX=ESI+EBX+buf;
				IF($test EDI,7){
					EBX = EDI&7;
					FOR(;EBX>0; ECX-=BPL,EBX--){
						DSBYTE[ECX]=AH;
						EAX+=EDX;
					}
				}
				EDI>>=3;
				FOR(;EDI>0;EDI--){
					ECX-=8*BPL;
					DSBYTE[8*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[7*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[6*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[5*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[4*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[3*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[2*BPL+ECX]=AH;
					EAX+=EDX;
					DSBYTE[ECX+BPL]=AH;
					EAX+=EDX;
				}
			}
			ELSE oldc[ESI*4]=ECX;
			u += du;
		}
		$pop ESI
	}
}

void voxels()
{
	retraces=real_time;
	EBX=EAX<<5;
	EDI=EAX*3;
	ESI=EAX>>8&255*256;
	EDX=EBX>>8&255;
	draw(EDI,EBX,VIEW_HEIGHT+height[ESI+EDX]<<8);
}
