/*
Copyright (C) 1997-2001 Id Software, Inc.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

#include "sw_local.h"

/*
** Start Added by Lewey
**
** This is where the real SIRDS code is
*/

//width of the repeating pattern. Increasing this will
//increase the quality of the SIRD by giving it more
//height levels.
//
//Make sure: ((R_SIRDw % 3) == 0)
//			&& (((R_SIRDw / 3) % R_SIRDExponents) == 0)
#define R_SIRDw 144

//height of the repeating pattern (not really important)
#define R_SIRDh 50

//maximum offset. This is the max number of pixels
//an item can be moved due to it's height, this is
//is also obviously then the number of different
//height layers you can have. A large R_SIRDw will
//make it harder and harder to see the image, a larger
//ratio of R_SIRDw (i.e. less than 3) will eventually
//cause your eyes to be unable to see the pattern.
#define R_SIRDmaxDiff (R_SIRDw / 3)

//the number of lower powers to ignore
#define R_SIRDIgnoreExponents	5

//the number of exponents (after ignored ones) to have different
//height values (ones after it are rounded to the max difference)
#define R_SIRDExponents			6

//the number of height levels each exponent is given
#define R_SIRDstepsPerExponent (R_SIRDmaxDiff / R_SIRDExponents)

//this is the z value of the sky, which logically should be 0, but
//for implimentation reasons is made very high. Not my doing by the
//way. If you move to a different platform, you may need to change this
#define R_SIRD_ZofSky 0x8ccc

//this is the number of random numbers
//defined in "rand1k.h"
#define R_SIRDnumRand 103

//this hold the background pattern
byte r_SIRDBackground[R_SIRDw * R_SIRDh];

//these are the actual random numbers
byte r_SIRDrandValues[] = {
#include "rand1k.h"
};


//Only used if id386 is false, this acts as a
// reverse bit-scanner, and uses a sort of binary
// search to find the index of the highest set bit.
//You could also expand the loop 4 times to remove
// the 'while'
#if !id386 || !( defined _MSC_VER )
int UShortLog(int val)
{
	int mask = 0xff00;
	int p = 0;
	int b = 8;
	while (b)
	{
		if (val & mask)
		{
			p += b;
			b >>= 1;
			mask &= (mask << b);
		}
		else
		{
			mask &= (mask << (b >> 1));
			mask >>= b;
			b >>= 1;
		}
	}
	return p;
}
#endif

int R_SIRDZFunc(int sub)
{
	int e;

	//special case the sky.
	if (sub == 	R_SIRD_ZofSky)
		return 0;

#if id386 && ( defined _MSC_VER )
	e = sub;
	//calculate the log (base 2) of the number. In other
	//words the index of the highest set bit. bsr is undefined
	//if it's input is 0, so special case that.
	if (e!=0)
	{
		__asm 
		{
			mov ebx, e
			bsr eax, ebx
			mov e, eax
		}
	}
#else
	e = UShortLog(sub);
#endif

	//clip the exponent
	if (e < R_SIRDIgnoreExponents)
		return 0;

	// based on the power, shift the z so that
	// it's as high as it can get while still staying
	// under 0x100
	if (e > 8)
	{
		sub >>= (e-8);
	}
	else
	{
		if (e < 8)
		{
			sub <<= (8-e);
		}
	}

	// Lower the power of the number, this helps scaling and removes
	// small z values.
	e -= R_SIRDIgnoreExponents;

	// contruct the height value. The power is used as the primary calculator,
	// and then the extra bits are used to offset. In this way you
	// get more detail than just the log of the z value, and it works
	// as a pretty good approximation of it.
	e *= R_SIRDstepsPerExponent;
	e += ((sub * R_SIRDstepsPerExponent) >> 8);

	//make sure we stay under maximum height.
	return ((e<=R_SIRDmaxDiff)? e : R_SIRDmaxDiff );
}

void R_ApplySIRDAlgorithum( void )
{
	unsigned short* curz, *oldz;
	unsigned short cz = 0, lastz = 0;
	byte* curp;
	byte* curbp, j = 0;
	int x, y, i, zinc, k;
	int mode = sw_drawsird->integer;

	//note of interest: I've made this static so that
	//if you like you could make it not static and see
	//what would happen if you didn't change the background
	static int ji = 0;

	//create the background image to tile
	//basically done by shifting the values around
	//each time and xoring them with a randomly
	//selected pixel
	for (i=0; i<R_SIRDw * R_SIRDh; i++)
	{
		if ((i%R_SIRDnumRand)==0)
		{
			ji++; 
			ji %= R_SIRDnumRand;
			j = r_SIRDrandValues[r_SIRDrandValues[ji] % R_SIRDnumRand];
		}
		r_SIRDBackground[i] = r_SIRDrandValues[ (i%R_SIRDnumRand) ] ^ j;
	}

	//if we are under water:
	if ((r_dowarp) && (vid.width != WARP_WIDTH))
	{
		//the rendering is only in the top left
		//WARP_WIDTH by WARP_HEIGHT area, so scale the z-values
		//to span over the whole screen


		//why are we going backwards? so that we don't write over the
		//values before we read from them

		zinc = ((WARP_WIDTH * 0x10000) / vid.width);
		for (y=vid.height-1; y>=0; y--)
		{
			curz = (d_pzbuffer + (vid.width * y));
			oldz = (d_pzbuffer + (vid.width * ((y*WARP_HEIGHT)/vid.height) ));
			k = (zinc * (vid.width-1));

			for (x=vid.width-1; x>=0; x--)
			{
				curz[x] = oldz[k >> 16];
				k -= zinc;
			}
		}
	}


	//SIRDify each line
	for (y=0; y<vid.height; y++)
	{
		curp = (vid.buffer + (vid.rowbytes * y));
		curz = (d_pzbuffer + (vid.width * y ));

		if (mode != 3)
		{
			// draw the SIRD

			// copy the background into the left most column
			curbp = &(r_SIRDBackground[ R_SIRDw * (y % R_SIRDh) ]);
			for (x=0; x<R_SIRDw; x++)
			{
				*curp = *curbp;
				curp++;
				curbp++; 
			}

			lastz = 0;
			cz = 0;
			curz += R_SIRDw;
			curbp = curp - R_SIRDw;

			// now calculate the SIRD
			for (x=R_SIRDw; x<vid.width; x++)
			{
				//only call the z-function with a new
				//value, it is slow so this saves quite
				//some time.
				if (lastz != *curz)
				{
					lastz = *curz;

					//convert from z to height offset
					cz = ( mode == 2 ) ? R_SIRDmaxDiff - R_SIRDZFunc(lastz) : R_SIRDZFunc(lastz);

					//the "height offset" used in making SIRDS
					//can be considered an adjustment of the 
					//frequency of repetition in the pattern.
					//so here we are copying from bp to p, and so
					//it simply increases or decreases the distance
					//between the two.
					curbp = (curp - R_SIRDw + cz);
				}

				*curp = *curbp;

				curp++;
				curbp++;
				curz++;
			}
		}
		else
		{
			//if we are just drawing the height map
			//this lets you see which layers are used to
			//create the SIRD
			//
			//NOTE: even though it may sort of look like
			//a grey-scale height map, that is merely a
			//coincidence because of how the colours are
			//organized in the pallette.

			for (x=0; x<vid.width; x++)
			{
				if (lastz != *curz)
				{
					lastz = *curz;
					cz = R_SIRDZFunc(*curz);
				}

				*curp = cz;

				curp++;
				curz++;
			}
		}
	}
}

/*
** End Added by Lewey
*/
