/****************************************************************************************/

/*  Span_AffineLoop.H                                                                   */

/*                                                                                      */

/*  Author: Mike Sandige                                                                */

/*  Description:  This is a template to create multiple affine span line drawing        */

/*                routines.  See Span, Span_Factory                                     */

/*                                                                                      */

/*  The contents of this file are subject to the Jet3D Public License                   */

/*  Version 1.02 (the "License"); you may not use this file except in                   */

/*  compliance with the License. You may obtain a copy of the License at                */

/*  http://www.jet3d.com                                                                */

/*                                                                                      */

/*  Software distributed under the License is distributed on an "AS IS"                 */

/*  basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See                */

/*  the License for the specific language governing rights and limitations              */

/*  under the License.                                                                  */

/*                                                                                      */

/*  The Original Code is Jet3D, released December 12, 1999.                             */

/*  Copyright (C) 1996-1999 Eclipse Entertainment, L.L.C. All Rights Reserved           */

/*                                                                                      */

/****************************************************************************************/



// SPANROP can possibly have these bits defined:

//  SPANROP & TMAP		source has texture

//  SPANROP & LSHADE	gouraud shade using vertex rgb values (interpolate rgb across span)

//  SPANROP & ZTEST		test z buffer  - write only pixels that pass test

//  SPANROP & ZSET		set z buffer - write to z buffer

//  SPANROP & D565		destination format is 565  (otherwise it's 555)

//  SPANROP & BFILT		use bilinear filter on source texture



// also

// RGB		pixels are RGB lit - gouraud or lightmap

// ZBUF		zbuffer is used at all





while(i-- > 0)

	{

		#if SPANROP & ZTEST

		ZFromMap = *(ZMapBits);

		if (ZFromMap > (Z>>16))

		#endif

			{

				#if SPANROP & ZSET

				*(ZMapBits++) = (ZMAPPIXEL)(Z>>16);

				#else

					#if SPANROP & ZTEST

					ZMapBits++;

					#endif

				#endif



				// if source is texture: get texture color

				#if (SPANROP & TMAP) 

					#if !(SPANROP & AMAP)	// texture mapped (but not with any alpha)

						#if !(SPANROP & BFILT)

							Color = Palette[*(TextureBits + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift))];

						#else

							{	// use bilinear filter to sample the texture

								unsigned char *LM0,*LM1;

								unsigned char *LM2,*LM3;

								int C0,C1,C2,C3;

								int P0,P2;



								int C01,C23;

								int UFract01,VFract01;

								

								// address base corner into lightmap by LMU,LMV

								LM0 = (TextureBits + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift));

								

								// address other corners, clamping

								if ( ((V>>16)&VMask) < VMask )

									{

										LM2 = LM0 + TOPDOWN_OR_BOTTOMUP((VMask+1));

									}

								else

									{

										if (UVClamping)

											{

												LM2 = LM0;

											}

										else

											{

												LM2 = (TextureBits + ((U>>16)&UMask) );

											}

									}

								if ( ((U>>16)&UMask) < UMask )

									{

										LM1 = LM0 + 1;

										LM3 = LM2 + 1;

									}

								else

									{

										if (UVClamping)

											{

												LM1 = LM0;

												LM3 = LM2;

											}

										else

											{

												LM1 = LM0 - UMask + 1;

												LM3 = LM2 - UMask + 1;

											}

									}

								#define RES 7

								UFract01 = (U&0xFFFF)>>(16-RES);

								VFract01 = (V&0xFFFF)>>(16-RES);

								C0 = Palette[*LM0];

								C1 = Palette[*LM1];

								C2 = Palette[*LM2];

								C3 = Palette[*LM3];



								P0 = C0 & 0xFF00FF;

								P2 = C2 & 0xFF00FF;

								C01 = (P0 + (( ( (C1&0xFF00FF) - P0 ) * UFract01)>>RES))&0xFF00FF;

								C23 = (P2 + (( ( (C3&0xFF00FF) - P2 ) * UFract01)>>RES))&0xFF00FF;

								Color =(   C01     + (((  C23 -  C01 ) * VFract01)>>RES))&0xFF00FF;//R&B



								P0 = C0 & 0xFF00;

								P2 = C2 & 0xFF00;

								C01 = P0 + (( ( ((C1)&0xFF00) - P0 ) * UFract01)>>RES);

								C23 = P2 + (( ( ((C3)&0xFF00) - P2 ) * UFract01)>>RES);

								Color |= (   C01     + (((  C23 -  C01 ) * VFract01)>>RES))&0xFF00; //G

							}

						#endif  // BFILT

					#else	//  (SPANROP & AMAP)	// texture mapped (with alpha)

						#if !(SPANROP & BFILT)

							Color = *( ((ALPHAMAPPIXEL *)TextureBits) + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift));	//4444 argb

						#else

							{	// use bilinear filter to sample the texture

								unsigned short *LM0,*LM1;

								unsigned short *LM2,*LM3;

								int C0,C1,C2,C3;

								int P0,P2;



								int C01,C23;

								int UFract01,VFract01;



								// address base corner into lightmap by LMU,LMV

								LM0 = ( ((ALPHAMAPPIXEL *)TextureBits) + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift));	//4444 argb



								// address other corners, clamping

								if ( ((V>>16)&VMask) < VMask )

									{

										LM2 = LM0 + TOPDOWN_OR_BOTTOMUP((VMask+1));

									}

								else

									{

										if (UVClamping)

											{

												LM2 = LM0;

											}

										else

											{

												LM2 = ((ALPHAMAPPIXEL *)TextureBits + ((U>>16)&UMask) );

											}

									}

								if ( ((U>>16)&UMask) < UMask )

									{

										LM1 = LM0 + 1;

										LM3 = LM2 + 1;

									}

								else

									{

										if (UVClamping)

											{

												LM1 = LM0;

												LM3 = LM2;

											}

										else

											{

												LM1 = LM0 - UMask + 1;

												LM3 = LM2 - UMask + 1;

											}

									}

								#define RES 7

								UFract01 = (U&0xFFFF)>>(16-RES);

								VFract01 = (V&0xFFFF)>>(16-RES);

							

								C0 = ((*LM0 & 0xF000)<<12) | ((*LM0 & 0xF00)>>4) | ((*LM0 & 0xF0)<<8) | ((*LM0 & 0xF)<<20);

								C1 = ((*LM1 & 0xF000)<<12) | ((*LM1 & 0xF00)>>4) | ((*LM1 & 0xF0)<<8) | ((*LM1 & 0xF)<<20);

								C2 = ((*LM2 & 0xF000)<<12) | ((*LM2 & 0xF00)>>4) | ((*LM2 & 0xF0)<<8) | ((*LM2 & 0xF)<<20);

								C3 = ((*LM3 & 0xF000)<<12) | ((*LM3 & 0xF00)>>4) | ((*LM3 & 0xF0)<<8) | ((*LM3 & 0xF)<<20);

								

								P0  = C0 & 0xFF00FF;

								P2  = C2 & 0xFF00FF;

								C01 = (P0 + (( ( (C1&0xFF00FF) - P0 ) * UFract01)>>RES))&0xFF00FF;

								C23 = (P2 + (( ( (C3&0xFF00FF) - P2 ) * UFract01)>>RES))&0xFF00FF;

								P0  = C01     + (((  C23 -  C01 ) * VFract01)>>RES);

								AR  = P0&0xFF;

								AB  = (P0>>16)&0xFF; 



								C1 = (C1>>8)&0xFF00FF;

								C3 = (C3>>8)&0xFF00FF;

								P0  = (C0>>8) & 0xFF00FF;

								P2  = (C2>>8) & 0xFF00FF;

								C01 = P0 + (( ( ( C1 - P0 ) * UFract01)>>RES))&0xFF00FF;

								C23 = P2 + (( ( ( C3 - P2 ) * UFract01)>>RES))&0xFF00FF;

								P0  = C01     + (((  C23 -  C01 ) * VFract01)>>RES);

								AG  = P0 & 0xFF;

								Color = (P0 & 0x0F0000)>>4;

							}

						#endif

					#endif

				#endif	//#if (SPANROP & TMAP) 

				



				#if !(( SPANROP & AFLAT) || (SPANROP & AMAP))		// NO alpha

					#if (SPANROP & TMAP) 

						#if SPANROP & D565 

							#ifdef RGB

								#ifdef USE_2X_MODULATION

									*(DestBits++) = RLUT_4X[((Color&0xFF)*R)>>23] | GLUT_4X[(((Color&0xFF00)>>8)*G)>>23] | BLUT_4X[(((Color&0xFF0000)>>16)*B)>>23];

								#else

									*(DestBits++) = (DESTPIXEL) (	((((Color&0xFF)*R)>>15)&0xF800) | (((((Color&0xFF00)>>8)*G)>>20)&0x7E0) | ((((Color&0xFF0000)>>16)*B)>>26) );

								#endif

							#else

								*(DestBits++) = (DESTPIXEL) (	((Color&0xF8)<<8) /*R*/ | ((Color&0xFC00)>>5) /*G*/ | ((Color&0xF80000)>>19)/*B*/ );

							#endif

						#else

							#ifdef RGB

								#ifdef USE_2X_MODULATION

									*(DestBits++) = RLUT_4X[((Color&0xFF)*R)>>23] | GLUT_4X[(((Color&0xFF00)>>8)*G)>>23] | BLUT_4X[(((Color&0xFF0000)>>16)*B)>>23];

								#else

									*(DestBits++) = (DESTPIXEL) (	((((Color&0xFF)*R)>>16)&0x7C00) | (((((Color&0xFF00)>>8)*G)>>21)&0x3E0) | ((((Color&0xFF0000)>>16)*B)>>26));

								#endif

							#else

								*(DestBits++) = (DESTPIXEL) (	((Color&0xF8)<<7) /*R*/ | ((Color&0xF800)>>6) /*G*/ | ((Color&0xF80000)>>19)/*B*/ );

							#endif

						#endif

						

					#else

						#if SPANROP & D565

							#ifdef RGB

								*(DestBits++) = (DESTPIXEL)	(  ((R>>(RGB_FXP_SHIFTER + 3))<<11) | ((G>>(RGB_FXP_SHIFTER + 2))<<5) | (B>>(RGB_FXP_SHIFTER + 3))  );

							#else

								*(DestBits++) = (DESTPIXEL) Color;

							#endif

						#else

							#ifdef RGB

								*(DestBits++) = (DESTPIXEL)(  ((R>>(RGB_FXP_SHIFTER + 3))<<10) | ((G>>(RGB_FXP_SHIFTER + 3))<<5) | (B>>(RGB_FXP_SHIFTER + 3))  );

							#else

								*(DestBits++) = (DESTPIXEL) Color;

							#endif

						#endif

					#endif

				#endif



				#if (SPANROP & AFLAT) || (SPANROP & AMAP)		// alpha map or alpha flat or both

					{

						int32 DColor;

						#if (SPANROP & AMAP) && (SPANROP & AFLAT)

						int32 Alpha,OneMinusAlpha;

						#endif 



						DColor = *DestBits;

						

						#if SPANROP & TMAP	

							#if (SPANROP & AMAP) 

								//Color = *( ((ALPHAMAPPIXEL *)TextureBits) + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift));	//4444 argb

								#if !(SPANROP & BFILT)	// filter version of alpha cracks open AR,AG,AB

									#ifdef RGB 	// alpha map and rgb shading 

										AR = (((Color & 0xF00)>>8 ) * R) >>(4+RGB_FXP_SHIFTER);

										AG = (((Color & 0x0F0)>>4 ) * G) >>(4+RGB_FXP_SHIFTER);

										AB = ( (Color & 0x00F)      * B) >>(4+RGB_FXP_SHIFTER);

									#else		// alpha map only

										AR = ((Color & 0xF00)>>4 ) ;

										AG = ((Color & 0x0F0)    ) ;

										AB = ((Color & 0x00F)<<4 ) ;

									#endif

								#endif

								#if (SPANROP & AFLAT)

									Alpha  = ((Color>>12) * A)>>4;

								//	OneMinusAlpha = 16-Alpha;

									OneMinusAlpha = Span_OneMinusAlpha[Alpha];

								#else

									A = (Color>>12);

								//	OneMinusA = 16-A;

									OneMinusA = Span_OneMinusAlpha[A];

								#endif

							#else	// texture map without alpha

								//Color = Palette[*(TextureBits + ((U>>16)&UMask) + TOPDOWN_OR_BOTTOMUP(((V>>16)&VMask) << StrideShift))];						

								#ifdef RGB

									AR = (( Color & 0xFF    )      * R) >>(8+RGB_FXP_SHIFTER);

									AG = (((Color & 0xFF00  )>>8 ) * G) >>(8+RGB_FXP_SHIFTER);

									AB = (((Color & 0xFF0000)>>16) * B) >>(8+RGB_FXP_SHIFTER);

								#else

									AR = (Color & 0xFF    );

									AG = (Color & 0xFF00  )>>8;

									AB = (Color & 0xFF0000)>>16;

								#endif

							#endif

						#else	

							// no texture

							#ifdef RGB	

								AR = R >>RGB_FXP_SHIFTER;

								AG = G >>RGB_FXP_SHIFTER;

								AB = B >>RGB_FXP_SHIFTER;

							#else	

								AR = (Color & 0xFF    );

								AG = (Color & 0xFF00  )>>8;

								AB = (Color & 0xFF0000)>>16; 

							#endif

						#endif

						

						#if (SPANROP & AMAP) && (SPANROP & AFLAT)

							#if SPANROP & D565

								AR = (((DColor&0xF800)>>8) * OneMinusAlpha) + (AR * Alpha);

								AG = (((DColor&0x7E0)>>3)  * OneMinusAlpha) + (AG * Alpha);

								AB = (((DColor&0x1F)<<3)   * OneMinusAlpha) + (AB * Alpha);

								*(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<11) | ( (AG>>6)<<5 ) | (AB>>7) );

							#else

								AR = (((DColor&0x7C00)>>7) * OneMinusAlpha) + (AR * Alpha);

								AG = (((DColor&0x3E0)>>2)  * OneMinusAlpha) + (AG * Alpha);

								AB = (((DColor&0x1F)<<3)   * OneMinusAlpha) + (AB * Alpha);

								*(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<10) | ( (AG>>7)<<5 ) | (AB>>7) );

							#endif

						#else

							#if SPANROP & D565

								AR = (((DColor&0xF800)>>8) * OneMinusA) + (AR * A);

								AG = (((DColor&0x7E0)>>3)  * OneMinusA) + (AG * A);

								AB = (((DColor&0x1F)<<3)   * OneMinusA) + (AB * A);

								*(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<11) | ( (AG>>6)<<5 ) | (AB>>7) );

							#else

								AR = (((DColor&0x7C00)>>7) * OneMinusA) + (AR * A);

								AG = (((DColor&0x3E0)>>2)  * OneMinusA) + (AG * A);

								AB = (((DColor&0x1F)<<3)   * OneMinusA) + (AB * A);

								*(DestBits++) = (DESTPIXEL) ( ( (AR>>7)<<10) | ( (AG>>7)<<5 ) | (AB>>7) );

							#endif

						#endif



					}

				#endif

												

			}

		#if SPANROP & ZTEST

		else

			{

				ZMapBits++;

				DestBits++;

			}

		#endif

	

		#if SPANROP & TMAP

		U += dU;

		V += dV;

		#endif

		#ifdef RGB

		R += dR;

		G += dG;

		B += dB;

		#endif

		#ifdef ZBUF

		Z += dZ;

		#endif

	}