#include "Script.hpp"
#include "ezmatrix.hpp"
//===========================================================================//
// File:	 Pane.cpp														 //
// Project:  GOSScript				                                         //
// Contents: Representation of bitmap in 3D environment						 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 07/31/98  JTR    Created													 //
//																			 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000, Microsoft, Inc.										//
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//

#include <math.h>

extern _SCRIPT * pScript;
extern HGOSHEAP gScriptHeap[];
#ifdef LAB_ONLY
extern DWORD gEnableScriptPanes;
extern bool gScriptPaneFlicker;
#endif

char PaneName[256];

PaneTextureList * gMasterPaneTextureList = NULL;

// We keep separate lists of textures for each alpha type, subdivided further into
// textures which contain 256-texel-high slivers, 256-texel-wide slivers, and small subrects.
// Whole 256x256 pieces of large panes are allocated as complete textures
SharedTexture * gSharedTextureList[6][3]	// [(alphatype<<1)+isVolatile][ (( width & 0x100 ) >> 7 ) | ((height & 0x100 ) >> 8 ) ]
	= { { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL }, { NULL, NULL, NULL } };
const char *gSharedTextureName[6][3] =
{
	{ "Shared_Solid_Static_Small",  "Shared_Solid_Static_256High",  "Shared_Solid_Static_256Wide" },
	{ "Shared_Solid_Dynamic_Small", "Shared_Solid_Dynamic_256High", "Shared_Solid_Dynamic_256Wide" },
	{ "Shared_Alpha_Static_Small",  "Shared_Alpha_Static_256High",  "Shared_Alpha_Static_256Wide" },
	{ "Shared_Alpha_Dynamic_Small", "Shared_Alpha_Dynamic_256High", "Shared_Alpha_Dynamic_256Wide" },
	{ "Shared_Keyed_Static_Small",  "Shared_Keyed_Static_256High",  "Shared_Keyed_Static_256Wide" },
	{ "Shared_Keyed_Dynamic_Small", "Shared_Keyed_Dynamic_256High", "Shared_Keyed_Dynamic_256Wide" }
};
#define SHARED_TEXTURE_LIST(width,height,alphatype,isVolatile) gSharedTextureList[(alphatype<<1)+isVolatile][ (( width & 0x100 ) >> 7 ) | ((height & 0x100 ) >> 8 ) ]
#define SHARED_TEXTURE_NAME(width,height,alphatype,isVolatile) gSharedTextureName[(alphatype<<1)+isVolatile][ (( width & 0x100 ) >> 7 ) | ((height & 0x100 ) >> 8 ) ]

gos_Pane::gos_Pane(char * name)
{
	//
	// This type of pane has movies rendered to it....
	//
	currentOffset.x = currentOffset.y = currentOffset.z = 0.0f;
	currentTranslation.x = currentTranslation.y = currentTranslation.z = 0.0f;
	currentRotation.x = currentRotation.y = currentRotation.z = 0.0f;
	currentScaleX = currentScaleY = 1.0f;

	m_color = 0xffffffff;
	m_alphaMode = gos_Alpha_OneZero;
	m_fIsVolatile = false;
	hVideo = NULL;
	hVideoTexture = NULL;

	// flesh it out!
	m_pTextureList = (PaneTextureList *) gos_Malloc(sizeof(PaneTextureList)+strlen(name)+1, gScriptHeap[1]);

	gosVideo_CreateResourceAsTexture(&hVideo, &hVideoTexture, name);
	gosVideo_ResourceInfo gvri;
	gosVideo_GetResourceInfo( hVideo, &gvri);

	if (gvri.dwHeight == 0)
	{
		// movies must be disabled... hmmm
		// let's fake it with a 32 x 32!
		gvri.dwHeight = 32;
		gvri.dwWidth = 32;
		gvri.dwSurfaceHeight = 32;
		gvri.dwSurfaceWidth = 32;
	}
	m_pTextureList->m_height = gvri.dwHeight;
	m_pTextureList->m_width = gvri.dwWidth;
	m_latticeX = gvri.dwWidth;
	m_latticeY = gvri.dwHeight;

	m_pTextureList->hasAlpha = 0;
	m_pTextureList->pListStart =  NULL;
	m_pTextureList->refCount = 1;
	m_pTextureList->hSurf = 0;
	m_pTextureList->m_pListOfQuads = NULL;
	strcpy(m_pTextureList->LongFileName, name);

	// can't use addquad
//
// Create a new Quad
//
	Quad* rect = (Quad *) gos_Malloc(sizeof(Quad), gScriptHeap[1]);

	rect->pSharedRect = NULL;
	rect->width = (WORD)gvri.dwWidth;
	rect->height = (WORD)gvri.dwHeight;

//
// Fill in Quad information
//
	rect->texture=hVideoTexture;

	rect->v[0].x=0.0f;
	rect->v[0].y=0.0f;

	rect->v[1].x=0.0f;
	rect->v[1].y=(float)(gvri.dwHeight);

	rect->v[2].x=(float)(gvri.dwWidth);
	rect->v[2].y=(float)(gvri.dwHeight);

	rect->v[3].x=(float)(gvri.dwWidth);
	rect->v[3].y=0.0f;
//
// Now add texel coordinates
//
	rect->v[0].u=0;
	rect->v[0].v=0;

	rect->v[1].u=0;
	rect->v[1].v=(float) gvri.dwHeight / (float) gvri.dwSurfaceHeight;

	rect->v[2].u=(float) gvri.dwWidth / (float) gvri.dwSurfaceWidth;
	rect->v[2].v=(float) gvri.dwHeight / (float) gvri.dwSurfaceHeight;

	rect->v[3].u=(float) gvri.dwWidth / (float) gvri.dwSurfaceWidth;
	rect->v[3].v=0;
//
// Clear all unused fields
//
	rect->v[0].z=0;
	rect->v[0].z    = rect->v[1].z    = rect->v[2].z    = rect->v[3].z		= 0;
	rect->v[0].argb = rect->v[1].argb = rect->v[2].argb = rect->v[3].argb	= 0xffffffff;
	rect->v[0].frgb	= rect->v[1].frgb = rect->v[2].frgb	= rect->v[3].frgb	= 0x0;
	rect->v[0].rhw	= rect->v[1].rhw  =	rect->v[2].rhw	= rect->v[3].rhw	= 1.0f;
//
// Add to chain of quads
//
	rect->pNext=m_pTextureList->m_pListOfQuads;
	m_pTextureList->m_pListOfQuads = rect;

	// add it to the global list.
	m_pTextureList->pNext =	gMasterPaneTextureList;

	gMasterPaneTextureList = m_pTextureList; 
}


gos_Pane::gos_Pane(char * name, int alpha, bool is_volatile)
{
	currentOffset.x = currentOffset.y = currentOffset.z = 0.0f;
	currentTranslation.x = currentTranslation.y = currentTranslation.z = 0.0f;
	currentRotation.x = currentRotation.y = currentRotation.z = 0.0f;
	currentScaleX = currentScaleY = 1.0f;

	m_color = 0xffffffff;
	m_alphaMode = gos_Alpha_OneZero;
	m_fIsVolatile = is_volatile;
	hVideo = NULL;
	hVideoTexture = NULL;

	// check if texture exists in the panetextureList
	PaneTextureList * itr = gMasterPaneTextureList;
	m_pTextureList = NULL;
	while(itr)
	{
		if (!is_volatile && (alpha == -1 || alpha == itr->hasAlpha) && stricmp(name, itr->LongFileName) == 0)
		{
			// it's there, inc refCount and use it!
			itr->refCount++;
			m_pTextureList = itr;
			break;
		}
		else
			itr = itr->pNext;
	}

	if (!m_pTextureList)
	{
		// flesh it out!
		m_pTextureList = (PaneTextureList *) gos_Malloc(sizeof(PaneTextureList)+strlen(name)+1, gScriptHeap[1]);

		gos_LoadSurface(name, &m_pTextureList->hSurf, is_volatile);
		m_pTextureList->m_height = gos_GetSurfaceHeight(m_pTextureList->hSurf);
		m_pTextureList->m_width = gos_GetSurfaceWidth(m_pTextureList->hSurf);

		m_pTextureList->hasAlpha = alpha;
		m_pTextureList->pListStart =  NULL;
		m_pTextureList->refCount = 1;
		m_pTextureList->m_pListOfQuads = NULL;
		strcpy(m_pTextureList->LongFileName, name);

//
// if the texture type wasn't specified, determine it.
//
		if (m_pTextureList->hasAlpha == -1)
		{
			// now, blast through the A channel looking for non-255 & non-0
			unsigned char * where = m_pTextureList->hSurf->m_nativeFormat.m_lpDynData+3;
			for(int i=0; i < m_pTextureList->hSurf->m_nativeFormat.m_height * m_pTextureList->hSurf->m_nativeFormat.m_width; i++)
			{
				if (*where != 0xff && *where != 0x00)
				{
					m_pTextureList->hasAlpha = 1;
					break;
				}
				else
				{
					if (*where == 0x00)
						m_pTextureList->hasAlpha = 2;
				}
				where += 4;
			}
			if (m_pTextureList->hasAlpha == -1)
				m_pTextureList->hasAlpha = 0;
		}

		MakeQuads();

		// add it to the global list.
		m_pTextureList->pNext =	gMasterPaneTextureList;

		gMasterPaneTextureList = m_pTextureList; 

		Update();
	
		// if the pane isn't volatile (the user never "updates" or "fills" or "blits" to it,
		//   destroy the surface 
		if (!is_volatile)
			gos_DestroySurface(&m_pTextureList->hSurf);

	}
}







gos_Pane::gos_Pane(int w, int h, int alpha, bool is_volatile)
{
	currentOffset.x = currentOffset.y = currentOffset.z = 0.0f;
	currentTranslation.x = currentTranslation.y = currentTranslation.z = 0.0f;
	currentRotation.x = currentRotation.y = currentRotation.z = 0.0f;
	currentScaleX = currentScaleY = 1.0f;

	m_color = 0xffffffff;
	m_alphaMode = gos_Alpha_OneZero;
	m_fIsVolatile = is_volatile;
	hVideo = NULL;
	hVideoTexture = NULL;

	// flesh it out!

	if (is_volatile)
	{
		m_pTextureList = (PaneTextureList *) gos_Malloc(sizeof(PaneTextureList)+strlen("Volatile")+1, gScriptHeap[1]);
		strcpy(m_pTextureList->LongFileName, "Volatile");
	}
	else
	{
		m_pTextureList = (PaneTextureList *) gos_Malloc(sizeof(PaneTextureList)+strlen("Non-Volatile")+1, gScriptHeap[1]);
		strcpy(m_pTextureList->LongFileName, "Non-Volatile");
	}
	gos_CreateSurface(&m_pTextureList->hSurf,w,h);
	m_pTextureList->m_height = h;
	m_pTextureList->m_width = w;
	m_pTextureList->hasAlpha = alpha;
	m_pTextureList->pListStart =  NULL;
	m_pTextureList->refCount = 1;
	m_pTextureList->m_pListOfQuads = NULL;

//
// if the texture type wasn't specified, determine it.
//
	if (m_pTextureList->hasAlpha == -1)
	{
		// now, blast through the A channel looking for non-255 & non-0
		unsigned char * where = m_pTextureList->hSurf->m_nativeFormat.m_lpRawData+3;
		for(int i=0; i < m_pTextureList->hSurf->m_nativeFormat.m_height * m_pTextureList->hSurf->m_nativeFormat.m_width; i++)
		{
			if (*where != 0xff && *where != 0x00)
			{
				m_pTextureList->hasAlpha = 1;
				break;
			}
			else
			{
				if (*where == 0x00)
					m_pTextureList->hasAlpha = 2;
			}
			where += 4;
		}
		if (m_pTextureList->hasAlpha == -1)
			m_pTextureList->hasAlpha = 0;
	}

   
	MakeQuads();

	// add it to the global list.
	m_pTextureList->pNext =	gMasterPaneTextureList;

	gMasterPaneTextureList = m_pTextureList; 

	Update();

	// if the pane isn't volatile (the user never "updates" or "fills" or "blits" to it,
	//   destroy the surface 
	if (!is_volatile)
		gos_DestroySurface(&m_pTextureList->hSurf);
}


gos_Pane::~gos_Pane()
{
	m_pTextureList->refCount--;

	if (m_pTextureList->refCount == 0)
	{
		// Delete all textures totally dedicated to this pane
		PaneTextures* this_texture = m_pTextureList->pListStart;
		while( this_texture )
		{
			PaneTextures* tmp = this_texture;
			this_texture = this_texture->pNext;
			gos_DestroyTexture(tmp->Handle);
			gos_Free(tmp);
		}
		// Now remove the quads
		Quad * this_q = m_pTextureList->m_pListOfQuads;
		while(this_q)
		{
			// If this Quad is from a shared texture, free the subrect which may also free the shared texture
			if( this_q->pSharedRect )
				FreeSharedQuad( this_q->pSharedRect );
			Quad * tmp = this_q;
			this_q = this_q->pNext;
			gos_Free(tmp);
		}
		if (m_pTextureList->hSurf)
			gos_DestroySurface(&m_pTextureList->hSurf);

		// Remove the PaneTextureList from the gMasterPaneList linked list
		PaneTextureList * itr = gMasterPaneTextureList;
		PaneTextureList * prev = NULL;
		while(itr)
		{
			if (itr == m_pTextureList)
			{
				// rearrange pointers is masterlist
				if (prev != NULL)
					prev->pNext = itr->pNext;
				else
					gMasterPaneTextureList = itr->pNext;
				gos_Free(m_pTextureList);
				break;
			}
			else
			{
				prev = itr;
				itr = itr->pNext;
			}
		}
		// Check that the PaneTextureList was indeed encountered/removed
		gosASSERT(itr);
	}

	if (hVideo)
		gosVideo_DestroyResource(&hVideo);
}







//
//
//

#if (DISTRIBUTED_GOSSCRIPT == 0)
#undef STRICT
#include "..\GameOS\pch.hpp"
#include "..\GameOS\Debugger.hpp"
#include "..\GameOS\DXRasterizer.hpp"
#include "..\GameOS\DirectX.hpp"
#include "..\GameOS\3DRasterizer.hpp"
#include "..\GameOS\Texture Manager.hpp"
#endif





void gos_Pane::Render(int x, int y)
{
//
// Any lines buffered up? - Flush them.
//
	FlushLineBuffer();

#if (DISTRIBUTED_GOSSCRIPT == 0)
//
// Fast path for blade.
//
	if( (!HardwareRenderer || 3==Environment.Renderer) &&
		0==RenderMode &&
		0==DontFastPath &&
		EnableFastPath &&
		0==currentRotation.x && 0==currentRotation.y && 0==currentRotation.z &&
		m_color==-1 &&
		(m_alphaMode==gos_Alpha_OneZero || m_alphaMode==gos_Alpha_AlphaInvAlpha) &&
		currentScaleX==1.0f && currentScaleY==1.0f )
	{
//
// Set them to script defaults
//
		gos_SetRenderState( gos_State_AlphaTest, 1 );
		gos_SetRenderState( gos_State_Perspective, 0 );
		gos_SetRenderState( gos_State_Specular, 0 );
		gos_SetRenderState( gos_State_Dither, 0 );
		gos_SetRenderState( gos_State_Filter, gos_FilterNone );
		gos_SetRenderState( gos_State_Clipping, 0 );
		gos_SetRenderState( gos_State_ZWrite, 0 );
		gos_SetRenderState( gos_State_ZCompare, 0 );
		gos_SetRenderState( gos_State_WireframeMode, 0 );
		gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
		gos_SetRenderState( gos_State_Fog, 0 );

		gos_SetRenderState( gos_State_AlphaMode, m_alphaMode );	

		if( m_alphaMode==gos_Alpha_OneZero && m_color==-1 )
			gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		else
		{
			if( (m_color&0xff000000)==0xff000000 )
				gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
			else
				gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		}

		float TOffset=gos_GetMachineInformation(gos_Info_TextureOffset) ? 0.0f : 0.5f;
		
		if( NeedClip( (float)x-TOffset, (float)y-TOffset) ) 
		{
			gos_SetRenderState( gos_State_Clipping, 2 );	// This uses guard band clipping (-2048 to +2047 is valid) - or crash could happen
		}

		DWORD lasttexture;
		gos_VERTEX temp[4];
		DDSURFACEDESC2 Textureddsd;
		DWORD LockedTexture;
		DWORD TextureX=0;
		DWORD TextureY=0;

		memset( &Textureddsd, 0, sizeof(Textureddsd) );
		lasttexture = 0xffffffff;
		LockedTexture=-1;
		Quad* itr = m_pTextureList->m_pListOfQuads;

 		while(itr)
		{
			int ScreenX=(int)(( itr->v[0].x - currentOffset.x ) * currentScaleX) + x;
			int ScreenY=(int)(( itr->v[0].y - currentOffset.y ) * currentScaleY) + y;
			int Width=(int)(( itr->v[2].x - currentOffset.x ) * currentScaleX) + x -ScreenX;
			int Height=(int)(( itr->v[2].y - currentOffset.y ) * currentScaleY) + y -ScreenY;

			if( ScreenX>=0 && (ScreenX+Width)<=Environment.screenWidth &&
				ScreenY>=0 && ScreenY<Environment.screenHeight &&							// Allow clipped with bottom
				itr->texture &&
				0==(TEXHANDLE_TO_PTR(itr->texture)->HasAlpha()) )
			{
				Textureddsd.dwSize = sizeof(Textureddsd);

				if( LockedTexture!=itr->texture )
				{
					if( lasttexture )
					{
						gos_SetRenderState( gos_State_Texture, 0 );					
						lasttexture=0;
						FlushRenderStates();
					}
					if( LockedTexture!=-1 )
					{
						wUnlock( TEXHANDLE_TO_PTR(LockedTexture)->GetSysMemSurf(true), NULL );
					}
					wLock( TEXHANDLE_TO_PTR(itr->texture)->GetSysMemSurf(true), NULL, &Textureddsd, DDLOCK_NOSYSLOCK | DDLOCK_WAIT | DDLOCK_READONLY, NULL );
					LockedTexture=itr->texture;
				}

				TextureX=(DWORD)(itr->v[0].u*Textureddsd.dwWidth);
				TextureY=(DWORD)(itr->v[0].v*Textureddsd.dwHeight);

				WORD* Source=(WORD*)Textureddsd.lpSurface+TextureX+(TextureY*Textureddsd.lPitch>>1);

				WORD* Dest=(WORD*)BackBufferddsd.lpSurface+ScreenX+(ScreenY*BackBufferddsd.lPitch>>1);
				
				if( ScreenY+Height > Environment.screenHeight )
					Height=Environment.screenHeight-ScreenY;								// Do bottom clipping

				if( ShowFastPane && (((int)(gos_GetElapsedTime(1)*2.0f))&1) )
				{			
					BYTE FillValue=(BYTE)((int)(gos_GetElapsedTime(1)*4.0f)&1 ? 255 : 0);
					for( int Y=0; Y<Height; Y++ )
					{
						memset( Dest, FillValue, Width*2 );
						Dest+=BackBufferddsd.lPitch>>1;										// Show fast path stuff flashing
					}
				}
				else
				{
					for( int Y=0; Y<Height; Y++ )
					{
						memcpy( Dest, Source, Width*2 );
						Dest+=BackBufferddsd.lPitch>>1;
						Source+=Textureddsd.lPitch>>1;
					}
				}
			}
			else
			{
//
// Render using Blade.
//
				if( LockedTexture!=-1 )
				{
					wUnlock( TEXHANDLE_TO_PTR(LockedTexture)->GetSysMemSurf(true), NULL );
					LockedTexture=-1;
				}
				if( lasttexture != itr->texture )
				{
					gos_SetRenderState( gos_State_Texture, itr->texture );
					lasttexture = itr->texture;
				}

				temp[0] = itr->v[0];
			  	temp[0].argb = temp[1].argb = temp[2].argb = temp[3].argb = m_color;
#ifdef LAB_ONLY
				if (gEnableScriptPanes && gScriptPaneFlicker)
				  	temp[0].argb = temp[1].argb = temp[2].argb = temp[3].argb = 0x7fffffff;
#endif
				temp[0].x = (( temp[0].x - currentOffset.x ) * currentScaleX);
				temp[0].y = (( temp[0].y - currentOffset.y ) * currentScaleY);
				temp[0].z = ( temp[0].z - currentOffset.z );

				temp[1] = itr->v[1];
				temp[1].x = (( temp[1].x - currentOffset.x ) * currentScaleX);
				temp[1].y = (( temp[1].y - currentOffset.y ) * currentScaleY);
				temp[1].z = ( temp[1].z - currentOffset.z );

				temp[2] = itr->v[2];
				temp[2].x = (( temp[2].x - currentOffset.x ) * currentScaleX);
				temp[2].y = (( temp[2].y - currentOffset.y ) * currentScaleY);
				temp[2].z = ( temp[2].z - currentOffset.z );

				temp[3] = itr->v[3];
				temp[3].x = (( temp[3].x - currentOffset.x ) * currentScaleX);
				temp[3].y = (( temp[3].y - currentOffset.y ) * currentScaleY);
				temp[3].z = ( temp[3].z - currentOffset.z );

				temp[0].x += -TOffset + x;
				temp[0].y += -TOffset + y;
				temp[1].x += -TOffset + x;
				temp[1].y += -TOffset + y;
				temp[2].x += -TOffset + x;
				temp[2].y += -TOffset + y;
				temp[3].x += -TOffset + x;
				temp[3].y += -TOffset + y;

				if( 0.0f==TOffset )
				{
					float TexOffset=0.0625f/gos_GetMachineInformation(gos_Info_TextureSize);

					temp[0].u +=TexOffset;
					temp[0].v +=TexOffset;
					temp[1].u +=TexOffset;
					temp[1].v +=TexOffset;
					temp[2].u +=TexOffset;
					temp[2].v +=TexOffset;
					temp[3].u +=TexOffset;
					temp[3].v +=TexOffset;
				}

#ifdef LAB_ONLY
				if (gEnableScriptPanes && gScriptPaneFlicker)
					gos_SetRenderState( gos_State_Texture, 0 );
#endif

				gos_DrawQuads(temp,4);

			}

			itr = itr->pNext;
		}
//
//
//
		if( LockedTexture!=-1 )
		{
			wUnlock( TEXHANDLE_TO_PTR(LockedTexture)->GetSysMemSurf(true), NULL );
			LockedTexture=-1;
		}

		return;
	}
#endif


//
// Set them to script defaults
//
	gos_SetRenderState( gos_State_AlphaTest, 1 );

// If the pane is rotated on the y axis, we need perspective correction
	if (currentRotation.y != 0.0f)
		gos_SetRenderState( gos_State_Perspective, 1 );
	else
		gos_SetRenderState( gos_State_Perspective, 0 );

	gos_SetRenderState( gos_State_Specular, 0 );
	gos_SetRenderState( gos_State_Dither, 0 );
	gos_SetRenderState( gos_State_Filter, gos_FilterNone );
	gos_SetRenderState( gos_State_Clipping, 0 );
	gos_SetRenderState( gos_State_ZWrite, 0 );
	gos_SetRenderState( gos_State_ZCompare, 0 );
	gos_SetRenderState( gos_State_WireframeMode, 0 );
	gos_SetRenderState( gos_State_ShadeMode, gos_ShadeFlat );
	gos_SetRenderState( gos_State_Fog, 0 );

	gos_SetRenderState( gos_State_AlphaMode, m_alphaMode );	

	if( gos_GetMachineInformation(gos_Info_CanAlphaTest) )
	{
		if( m_alphaMode==gos_Alpha_OneZero && m_color==-1 )
			gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendDecal );
		else
		{
			if( (m_color&0xff000000)==0xff000000 )
				gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulate );
			else
				gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
		}
	}
	else
	{
		gos_SetRenderState( gos_State_TextureMapBlend, gos_BlendModulateAlpha );
	}

	float TOffset=gos_GetMachineInformation(gos_Info_TextureOffset) ? 0.0f : 0.5f;
	
	if( NeedClip( (float)x-TOffset, (float)y-TOffset) ) 
	{
		gos_SetRenderState( gos_State_Clipping, 2 );	// This uses guard band clipping (-2048 to +2047 is valid) - or crash could happen
	}

	Quad * itr = m_pTextureList->m_pListOfQuads;
	
	DWORD lasttexture = 0xffffffff;

	gos_VERTEX temp[4];

 	while(itr)
	{
		if (lasttexture != itr->texture )
		{
			gos_SetRenderState( gos_State_Texture, itr->texture );
			lasttexture = itr->texture;
		}

		temp[0] = itr->v[0];
		temp[0].x = (( temp[0].x - currentOffset.x ) * currentScaleX);
		temp[0].y = (( temp[0].y - currentOffset.y ) * currentScaleY);
		temp[0].z = ( temp[0].z - currentOffset.z );

		temp[1] = itr->v[1];
		temp[1].x = (( temp[1].x - currentOffset.x ) * currentScaleX);
		temp[1].y = (( temp[1].y - currentOffset.y ) * currentScaleY);
		temp[1].z = ( temp[1].z - currentOffset.z );

		temp[2] = itr->v[2];
		temp[2].x = (( temp[2].x - currentOffset.x ) * currentScaleX);
		temp[2].y = (( temp[2].y - currentOffset.y ) * currentScaleY);
		temp[2].z = ( temp[2].z - currentOffset.z );

		temp[3] = itr->v[3];
		temp[3].x = (( temp[3].x - currentOffset.x ) * currentScaleX);
		temp[3].y = (( temp[3].y - currentOffset.y ) * currentScaleY);
		temp[3].z = ( temp[3].z - currentOffset.z );

		temp[0].argb = temp[1].argb = temp[2].argb = temp[3].argb = m_color;
#ifdef LAB_ONLY
		if (gEnableScriptPanes && gScriptPaneFlicker)
		  	temp[0].argb = temp[1].argb = temp[2].argb = temp[3].argb = 0x7fffffff;
#endif

		EZMatrix4x4 Final;
		EZMatrix4x4 Work;
		Work.Identity();
		if (currentRotation.x != 0.0f)
		{
			float s = (float) sin(currentRotation.x);
			float c = (float) cos(currentRotation.x);
			EZMatrix4x4 RotX;
			RotX.Identity();
			RotX.MakeRotX(s,c);
			EZMatrix4x4::Multiply(&Work, &RotX, &Final);
			Work.Copy(&Final);
		}

		if (currentRotation.y != 0.0f)
		{
			float s = (float) sin(currentRotation.y);
			float c = (float) cos(currentRotation.y);
			EZMatrix4x4 RotY;
			RotY.Identity();
			RotY.MakeRotY(s,c);
			EZMatrix4x4::Multiply(&Work, &RotY, &Final);
			Work.Copy(&Final);
		}

		if (currentRotation.z != 0.0f)
		{
			float s = (float) sin(currentRotation.z);
			float c = (float) cos(currentRotation.z);
			EZMatrix4x4 RotZ;
			RotZ.Identity();
			RotZ.MakeRotZ(s,c);
			EZMatrix4x4::Multiply(&Work, &RotZ, &Final);
		}

		if (currentRotation.x != 0.0f || currentRotation.y != 0.0f || currentRotation.z != 0.0f)
		{
			Final.Transform(&temp[0].x, &temp[0].y, &temp[0].z);
			Final.Transform(&temp[1].x, &temp[1].y, &temp[1].z);
			Final.Transform(&temp[2].x, &temp[2].y, &temp[2].z);
			Final.Transform(&temp[3].x, &temp[3].y, &temp[3].z);
		}

		temp[0].z += 277;
		temp[1].z += 277;
		temp[2].z += 277;
		temp[3].z += 277;

		temp[0].rhw = 1.0f / temp[0].z;
		temp[1].rhw = 1.0f / temp[1].z;
		temp[2].rhw = 1.0f / temp[2].z;
		temp[3].rhw = 1.0f / temp[3].z;

		temp[0].x = temp[0].x * 277 * temp[0].rhw;
		temp[0].y = temp[0].y * 277 * temp[0].rhw;
		temp[1].x = temp[1].x * 277 * temp[1].rhw;
		temp[1].y = temp[1].y * 277 * temp[1].rhw;
		temp[2].x = temp[2].x * 277 * temp[2].rhw;
		temp[2].y = temp[2].y * 277 * temp[2].rhw;
		temp[3].x = temp[3].x * 277 * temp[3].rhw;
		temp[3].y = temp[3].y * 277 * temp[3].rhw;

		temp[0].z = 0.0f;
	  	temp[1].z = 0.0f;
  		temp[2].z = 0.0f;
		temp[3].z = 0.0f;

		temp[0].x += -TOffset + x;
		temp[0].y += -TOffset + y;
		temp[1].x += -TOffset + x;
		temp[1].y += -TOffset + y;
		temp[2].x += -TOffset + x;
		temp[2].y += -TOffset + y;
		temp[3].x += -TOffset + x;
		temp[3].y += -TOffset + y;

		if( 0.0f==TOffset )
		{
			float TexOffset=0.0625f/gos_GetMachineInformation(gos_Info_TextureSize);

			temp[0].u +=TexOffset;
			temp[0].v +=TexOffset;
			temp[1].u +=TexOffset;
			temp[1].v +=TexOffset;
			temp[2].u +=TexOffset;
			temp[2].v +=TexOffset;
			temp[3].u +=TexOffset;
			temp[3].v +=TexOffset;
		}

#ifdef LAB_ONLY
		if (gEnableScriptPanes && gScriptPaneFlicker)
			gos_SetRenderState( gos_State_Texture, 0 );
#endif
			gos_DrawQuads(temp,4);

		itr = itr->pNext;
	}
}



void gos_Pane::Texture(HGOSSURFACE surf)
{
	surf = surf;
	STOP(("This function isn't implemented"));
}

void gos_Pane::Rotate(float x, float y, float z)
{
	currentRotation.x = x;
	currentRotation.y = y;
	currentRotation.z = z;
}

void gos_Pane::Scale(float x, float y, float z)
{
	currentScaleX = x;
	currentScaleY = y;
	z=z;
}

void gos_Pane::Origin(int x, int y, int z)
{
	currentOffset.x = (float) x;
	currentOffset.y = (float) y;
	currentOffset.z = (float) z;
}

void gos_Pane::Color( DWORD color )
{
	m_color = color;
}

void gos_Pane::AlphaMode(enum gos_AlphaMode mode)
{
	m_alphaMode = mode;
}

	








#define NOREBUILD 1




void gos_Pane::Update()
{

	if( (unsigned long)this < 0x00100000 )
		STOP(("Invalid this pointer"));


	if (m_pTextureList->hSurf == NULL)
		ScriptError( "This pane has not been marked as volatile. You can't update it" );
	TEXTUREPTR ptr;
	memset(&ptr,0,sizeof(TEXTUREPTR));
	int count = 0;
	long top;
	long left;


	DWORD lastHandle = 0xffffffff;
	char *sdata = 0;
#if NOREBUILD
	DWORD *tdata = 0;
	long ty;
#endif
	unsigned long sp = (unsigned long) gos_GetSurfacePitch( m_pTextureList->hSurf );


	char * surfptr = (char *) m_pTextureList->hSurf->m_nativeFormat.m_lpDynData;

	Quad * rect = m_pTextureList->m_pListOfQuads;


	while(rect)
	{
#if NOREBUILD
		if (rect->texture != lastHandle)
		{
			if (lastHandle != 0xffffffff)
			{
				gos_UnLockTexture(lastHandle);
			}
			lastHandle = rect->texture;

//
// Lock 32bpp intermediate in "read-only" mode so conversion isn't performed on unlock
//
			gos_LockTexture(lastHandle,  0, 1, &ptr);
		}
#endif
		sdata = surfptr;
		sdata += (int) (rect->v[0].y*sp);

		if( rect->pSharedRect )
		{
//			if( rect->pSharedRect->left + rect->pSharedRect->width !=  ( long) (((float)rect->v[2].u*ptr.Pitch)) )
//				STOP(("WHOA!"));

			top = rect->pSharedRect->top;  //  ( long) (((float)rect->v[0].v*ptr.Pitch));
//			bottom = rect->pSharedRect->top + rect->pSharedRect->height; // ( long) (((float)rect->v[2].v*ptr.Pitch)); 
			left =  rect->pSharedRect->left; // ( long) (((float)rect->v[0].u*ptr.Pitch));
////			right =  /* rect->pSharedRect->left + rect->pSharedRect->width; */ ( long) (((float)rect->v[2].u*ptr.Pitch));
//			right =  rect->pSharedRect->left + rect->pSharedRect->width;
		}
		else
		{
			top = 0;
			left = 0;
//			right = ptr.Width;
//			bottom = ptr.Height;
		}

//		gosASSERT( right >= left);
//		gosASSERT( bottom >= top);

		int off = (int) rect->v[0].x;

		gos_ConvertTextureRect( rect->texture, left, top, &((DWORD*)sdata)[off], sp, rect->width, rect->height );	
#if NOREBUILD
//
// Copy to 32bpp backup just in case the surface is lost
//
		
		tdata = ptr.pTexture;
		tdata += top*ptr.Pitch;

		for(ty=0; ty < rect->height; ty++)
		{
			memcpy(&((DWORD *)tdata)[left],&((DWORD*)sdata)[off],(rect->width)*4);
			tdata += ptr.Pitch;
			sdata += sp;
		}
#endif
		count++;
		rect = rect->pNext;
	}
	if( lastHandle!=0xffffffff )
		gos_UnLockTexture(lastHandle);
}

bool gos_Pane::NeedClip(float x, float y)
{
	if( currentRotation.x != 0.0f || currentRotation.y != 0.0f || currentRotation.z != 0.0f )
		return true;
	if( (x-(currentOffset.x*currentScaleX) < 0) || (y-(currentOffset.y*currentScaleY) < 0) )
		return true;
	if( (x + ((m_pTextureList->m_width-currentOffset.x)*currentScaleX) > Environment.screenWidth) || (y + ((m_pTextureList->m_height-currentOffset.y)*currentScaleY) > Environment.screenHeight) )
		return true;
	return false;
}












//
// Add's a texture to the current pane
//
DWORD gos_Pane::AddTexture( DWORD Size )
{
	DWORD Handle;
	
	if( m_pTextureList->hasAlpha==2 )
		Handle = gos_NewEmptyTexture( gos_Texture_Keyed, PaneName, Size, gosHint_DisableMipmap | gosHint_DontShrink );
	else
	if( m_pTextureList->hasAlpha==1 )
		Handle = gos_NewEmptyTexture( gos_Texture_Alpha, PaneName, Size, gosHint_DisableMipmap | gosHint_DontShrink );
	else
		Handle = gos_NewEmptyTexture( gos_Texture_Solid, PaneName, Size, gosHint_DisableMipmap | gosHint_DontShrink );

	PaneTextures* pTexture = (PaneTextures*)gos_Malloc( sizeof(PaneTextures), gScriptHeap[1] );
	pTexture->Handle=Handle;
	pTexture->pNext=m_pTextureList->pListStart;
	m_pTextureList->pListStart=pTexture;

	return Handle;
}






//
// Add's a Quad to the list for the current pane
//
void gos_Pane::AddQuad( DWORD X, DWORD Y, DWORD Width, DWORD Height, DWORD Texture, DWORD U, DWORD V, DWORD TextureSize, SharedTextureRect *pSharedRect )
{
//
// Create a new Quad
//
	Quad* rect = (Quad *) gos_Malloc(sizeof(Quad), gScriptHeap[1]);

	if( 0xff81ff81 == (unsigned long)(pSharedRect) )
		gosASSERT(0);
	
	rect->pSharedRect = pSharedRect;
	rect->width = (WORD)Width;
	rect->height = (WORD)Height;

//
// Fill in Quad information
//
	rect->texture=Texture;

	rect->v[0].x=(float)X;
	rect->v[0].y=(float)Y;

	rect->v[1].x=(float)X;
	rect->v[1].y=(float)(Y+Height);

	rect->v[2].x=(float)(X+Width);
	rect->v[2].y=(float)(Y+Height);

	rect->v[3].x=(float)(X+Width);
	rect->v[3].y=(float)Y;
//
// Now add texel coordinates
//
	float Texel=1.0f/TextureSize;
	
	rect->v[0].u=U*Texel;
	rect->v[0].v=V*Texel;

	rect->v[1].u=U*Texel;
	rect->v[1].v=(V+Height)*Texel;

	rect->v[2].u=(U+Width)*Texel;
	rect->v[2].v=(V+Height)*Texel;

	rect->v[3].u=(U+Width)*Texel;
	rect->v[3].v=V*Texel;
//
// Clear all unused fields
//
	rect->v[0].z=0;
	rect->v[0].z    = rect->v[1].z    = rect->v[2].z    = rect->v[3].z		= 0;
	rect->v[0].argb = rect->v[1].argb = rect->v[2].argb = rect->v[3].argb	= 0xffffffff;
	rect->v[0].frgb	= rect->v[1].frgb = rect->v[2].frgb	= rect->v[3].frgb	= 0x0;
	rect->v[0].rhw	= rect->v[1].rhw  =	rect->v[2].rhw	= rect->v[3].rhw	= 1.0f;
//
// Add to chain of quads
//
	rect->pNext=m_pTextureList->m_pListOfQuads;
	m_pTextureList->m_pListOfQuads = rect;
}







// GetClosest recursively finds the closest(least waste) available subrect
bool GetClosest( SharedTextureRect *pRect, DWORD width, DWORD height, DWORD *pSmallest, SharedTextureRect **ppBestRect )
{
	if( ( width > pRect->width ) || ( height > pRect->height ) )
		return false;	// this rect (and all sub-rects) is too small
	if( ( pRect->status == SharedTextureRect::parent_h ) || ( pRect->status == SharedTextureRect::parent_v ) )
		return GetClosest(pRect->pChild1,width,height,pSmallest,ppBestRect) || GetClosest(pRect->pChild2,width,height,pSmallest,ppBestRect);
	if( ( pRect->status == SharedTextureRect::free ) && ( pRect->height * pRect->width < *pSmallest ) )
	{
		// this rect is available and a better fit than any found so far
		*pSmallest = pRect->height * pRect->width;
		*ppBestRect = pRect;
		return true;
	}
	return false;
}










void gos_Pane::AddSharedQuad( DWORD left, DWORD top, DWORD width, DWORD height )
{

	// look for an available rect of an existing shared texture which is closest to
	// the desired dimensions

	SharedTexture *pSharedTexture;
	SharedTexture *pBestSharedTexture = NULL;
	SharedTextureRect *pRect = NULL;
	DWORD smallestArea = 0x10001;	// i.e. larger than 256x256
	DWORD requiredArea = width * height;
	DWORD requestedWidth = width;
	
	width = (width + 3) & ~3L;

	for( pSharedTexture = SHARED_TEXTURE_LIST(width,height,m_pTextureList->hasAlpha,m_fIsVolatile); pSharedTexture; pSharedTexture = pSharedTexture->pNext )
	{
		if( requiredArea > pSharedTexture->totalFreeTexels )
			continue;	// this texture is too full

		if( GetClosest( pSharedTexture->pRootRect, width, height, &smallestArea, &pRect ) )
			pBestSharedTexture = pSharedTexture;
	}

	pSharedTexture = pBestSharedTexture;

	if( !pSharedTexture )
	{
		// No available shared texture had enough room, - create a new 256x256 shared texture
		pSharedTexture = (SharedTexture *)gos_Malloc( sizeof(SharedTexture), gScriptHeap[1] );
		// Add to double-linked list of shared textures
		pSharedTexture->pPrev_pNext = &(SHARED_TEXTURE_LIST(width,height,m_pTextureList->hasAlpha,m_fIsVolatile));
		pSharedTexture->pNext = SHARED_TEXTURE_LIST(width,height,m_pTextureList->hasAlpha,m_fIsVolatile);
		if( pSharedTexture->pNext )
			pSharedTexture->pNext->pPrev_pNext = &(pSharedTexture->pNext);
		pSharedTexture->totalFreeTexels = 65536;
		SHARED_TEXTURE_LIST(width,height,m_pTextureList->hasAlpha,m_fIsVolatile) = pSharedTexture;
		// create root rectangle (square)
		pSharedTexture->pRootRect = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		if( m_pTextureList->hasAlpha==2 )
			pSharedTexture->texture = gos_NewEmptyTexture( gos_Texture_Keyed, SHARED_TEXTURE_NAME(width,height,m_pTextureList->hasAlpha,m_fIsVolatile), 256, gosHint_DisableMipmap | gosHint_DontShrink );
		else if( m_pTextureList->hasAlpha==1 )
			pSharedTexture->texture = gos_NewEmptyTexture( gos_Texture_Alpha, SHARED_TEXTURE_NAME(width,height,m_pTextureList->hasAlpha,m_fIsVolatile), 256, gosHint_DisableMipmap | gosHint_DontShrink );
		else
			pSharedTexture->texture = gos_NewEmptyTexture( gos_Texture_Solid, SHARED_TEXTURE_NAME(width,height,m_pTextureList->hasAlpha,m_fIsVolatile), 256, gosHint_DisableMipmap | gosHint_DontShrink );
		pRect = pSharedTexture->pRootRect;
		pRect->height = 256;
		pRect->width = 256;
		pRect->pChild1 = NULL;
		pRect->pChild2 = NULL;
		pRect->pParent = NULL;
		pRect->status = SharedTextureRect::free;
		pRect->top = 0;
		pRect->left =0;
		pRect->pSharedTexture = pSharedTexture;
	}

	// split the best rectangle as required to create a subrect of the desired size
	if( ( width < pRect->width ) && ( height > width ) )
	{
		// split into left & right pieces, - use left piece

		SharedTextureRect * pChild1 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild1, pRect, sizeof(SharedTextureRect) );
		pChild1->width = width;
		pChild1->pParent = pRect;
		SharedTextureRect * pChild2 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild2, pRect, sizeof(SharedTextureRect) );
		pChild2->width -= width;
		pChild2->left += width;
		pChild2->pParent = pRect;
		pRect->status = SharedTextureRect::parent_h;
		pRect->pChild1 = pChild1;
		pRect->pChild2 = pChild2;
		pRect = pRect->pChild1;

		// FillQuadRandom(pChild2);
	}
	if( height < pRect->height )
	{
		// split into top & bottom pieces, - use top piece
		SharedTextureRect * pChild1 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild1, pRect, sizeof(SharedTextureRect) );
		pChild1->height = height;
		pChild1->pParent = pRect;
		SharedTextureRect * pChild2 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild2, pRect, sizeof(SharedTextureRect) );
		pChild2->height -= height;
		pChild2->top += height;
		pChild2->pParent = pRect;
		pRect->status = SharedTextureRect::parent_v;
		pRect->pChild1 = pChild1;
		pRect->pChild2 = pChild2;
		pRect = pRect->pChild1;

		// FillQuadRandom(pChild2);
	}
	if( width < pRect->width )
	{
		// split into left & right pieces, - use left piece
		SharedTextureRect * pChild1 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild1, pRect, sizeof(SharedTextureRect) );
		pChild1->width = width;
		pChild1->pParent = pRect;
		SharedTextureRect * pChild2 = (SharedTextureRect *)gos_Malloc( sizeof(SharedTextureRect), gScriptHeap[1] );
		memcpy( pChild2, pRect, sizeof(SharedTextureRect) );
		pChild2->width -= width;
		pChild2->left += width;
		pChild2->pParent = pRect;
		pRect->status = SharedTextureRect::parent_h;
		pRect->pChild1 = pChild1;
		pRect->pChild2 = pChild2;
		pRect = pRect->pChild1;

		// FillQuadRandom(pChild2);
	}

	pRect->status = SharedTextureRect::used;
	pSharedTexture->totalFreeTexels -= width * height;

	AddQuad(  left, top, requestedWidth, height, pSharedTexture->texture, pRect->left, pRect->top, 256, pRect );
}





void EliminateSharedRect( SharedTextureRect *pNode )
{
	// This routine is called after all size adjustments have been made
	// Both pNode and its parent are removed, the parent is replaced by pNode's sibling
	SharedTextureRect *pParent = pNode->pParent;
	SharedTextureRect *pSibling = ( pNode->pParent->pChild1 == pNode )?pNode->pParent->pChild2:pNode->pParent->pChild1;

	if( pParent->pParent )
	{
		if( pParent->pParent->pChild1 == pParent )
			pParent->pParent->pChild1 = pSibling;
		else
			pParent->pParent->pChild2 = pSibling;
	}
	else
	{
		// the sibling becomes the new root node
		pNode->pSharedTexture->pRootRect = pSibling;
	}

	pSibling->pParent = pParent->pParent;

	gos_Free( pParent );
	gos_Free( pNode );
}







void gos_Pane::FreeSharedQuad( SharedTextureRect *pQuad )
{
	SharedTexture *pSharedTexture = pQuad->pSharedTexture;
	bool tryMerge;
	SharedTextureRect *pNode;	// temporary pointer for traversing tree
	SharedTextureRect *pMergeRoot;
	SharedTextureRect *pTmp;

	do
	{
		tryMerge = false;
		pQuad->status = SharedTextureRect::free;	// mark this quad as free

		// Attempt to merge this quad with quad to left/above
		pNode = pQuad;
		// scan upwards to find point where this quad is on the Child2 side (if at all)
		while( pNode->pParent && ( pNode->pParent->pChild1 == pNode ) && ( pNode->pParent->status == pQuad->pParent->status ) )
			pNode = pNode->pParent;
		if( pNode->pParent && ( pNode->pParent->pChild2 == pNode ) && ( pNode->pParent->status == pQuad->pParent->status ) )
		{
			// Succesfully found place where this node is on child2 branch
			// And also all parent types so far are same  (can't merge between horizontal & vertical parent types)
			// Now traverse downwards on the child1->child2->child2->child2... path to find a free or busy node
			pMergeRoot = pNode->pParent;
			pNode = pNode->pParent->pChild1;
			while( pNode->status == pQuad->pParent->status )
				pNode = pNode->pChild2;
			if( pNode->status == SharedTextureRect::free )
			{
				// pNode can be merged with pQuad
				tryMerge = true;
				if( pQuad->pParent->status == SharedTextureRect::parent_h )
				{
					int width = pNode->width;
					// Adjust widths & lefts from mergeroot down
					for( pTmp=pMergeRoot->pChild1; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild2 )
					{
						pTmp->width -= width;
					}
					for( pTmp=pMergeRoot->pChild2; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild1 )
					{
						pTmp->left -= width;
						pTmp->width += width;
					}
					pQuad->left -= width;
					pQuad->width += width;
				}
				else
				{
					int height = pNode->height;
					// Adjust heights & tops from mergeroot down
					for( pTmp=pMergeRoot->pChild1; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild2 )
					{
						pTmp->height -= height;
					}
					for( pTmp=pMergeRoot->pChild2; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild1 )
					{
						pTmp->top -= height;
						pTmp->height += height;
					}
					pQuad->top -= height;
					pQuad->height += height;
				}

				EliminateSharedRect( pNode );
			}
		}


		// Attempt to merge this quad with quad to right/below

		pNode = pQuad;
		// scan upwards to find point where this quad is on the Child1 side (if at all)
		while( pNode->pParent && ( pNode->pParent->pChild2 == pNode ) && ( pNode->pParent->status == pQuad->pParent->status ) )
			pNode = pNode->pParent;
		if( pNode->pParent && ( pNode->pParent->pChild1 == pNode ) && ( pNode->pParent->status == pQuad->pParent->status ) )
		{
			// Succesfully found place where this node is on Child1 branch
			// And also all parent types so far are same  (can't merge between horizontal & vertical parent types)
			// Now traverse downwards on the Child2->Child1->Child1->Child1... path to find a free or busy node
			pMergeRoot = pNode->pParent;
			pNode = pNode->pParent->pChild2;
			while( pNode->status == pQuad->pParent->status )
				pNode = pNode->pChild1;
			if( pNode->status == SharedTextureRect::free )
			{
				// pNode can be merged with pQuad
				tryMerge = true;
				if( pQuad->pParent->status == SharedTextureRect::parent_h )
				{
					int width = pNode->width;
					// Adjust widths & lefts from mergeroot down
					for( pTmp=pMergeRoot->pChild2; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild1 )
					{
						pTmp->width -= width;
						pTmp->left += width;
					}
					for( pTmp=pMergeRoot->pChild1; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild2 )
					{
						pTmp->width += width;
					}
					pQuad->width += width;
				}
				else
				{
					int height = pNode->height;
					// Adjust heights & tops from mergeroot down
					for( pTmp=pMergeRoot->pChild2; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild1 )
					{
						pTmp->height -= height;
						pTmp->top += height;
					}
					for( pTmp=pMergeRoot->pChild1; pTmp->status == pQuad->pParent->status; pTmp = pTmp->pChild2 )
					{
						pTmp->height += height;
					}
					pQuad->height += height;
				}

				EliminateSharedRect( pNode );
			}
		}



	} while ( tryMerge );
	
	if( pQuad->pParent )
	{
		// Fill remaining quad with a random color for identification
		// FillQuadRandom( pQuad );
	}
	else
	{
		// this is now the root Quad so the entire shared texture can be freed
		gos_Free( pQuad );
		gos_DestroyTexture( pSharedTexture->texture );
		*(pSharedTexture->pPrev_pNext) = pSharedTexture->pNext;
		if( pSharedTexture->pNext )
			pSharedTexture->pNext->pPrev_pNext = pSharedTexture->pPrev_pNext;
		gos_Free( pSharedTexture );
	}



}



DWORD gRandomColor = 0;


void gos_Pane::FillQuadRandom( SharedTextureRect *pQuad )
{

	TEXTUREPTR ptr;
	memset(&ptr,0,sizeof(TEXTUREPTR));

	gos_LockTexture(pQuad->pSharedTexture->texture, 0, 0, &ptr);

	DWORD *pRow = ptr.pTexture;
	pRow += pQuad->top * ptr.Pitch;
	pRow += pQuad->left;

	DWORD color = gRandomColor | 0xFF000000;
	gRandomColor = ( gRandomColor ^ ( gRandomColor << 3 ) ) + 0x31abd1;

	int row, col;

	for( row=0; row<pQuad->height; row++ )
	{
		for( col=0; col<pQuad->width; col++ )
			pRow[col] = color;
		pRow += ptr.Pitch;
	}

	gos_UnLockTexture(pQuad->pSharedTexture->texture);
}







//
//
// Given a surface, this routine breaks it into QUADs in as many textures as are required.
//
// It is important that no T junctions are created and the minimum number of vertices are used.
//
//
void gos_Pane::MakeQuads()
{
//
// Create a good default name for panes
//
	char* Name=gos_GetSurfacePath(m_pTextureList->hSurf);
	if( Name==NULL )
	{
		sprintf( PaneName, "User Pane: %dx%d ",m_pTextureList->m_width,m_pTextureList->m_height );
	}
	else
	{
		for( int t0=strlen(Name); t0!=0; t0-- )
		{
			if( Name[t0]=='\\' )
				break;
		}
		if( t0==0 )
			t0=-1;
		sprintf( PaneName, "%s: %dx%d ",&Name[t0+1],m_pTextureList->m_width,m_pTextureList->m_height );
	}


	// split into pieces which are at most 256x256 and allocate.
	// dimensions which are >128 and <256 are further split into 128+remainder
	int top,left,height,width;


	// This is reordered so that textures are less likely to swap on the right & bottom fragments
	// left-to-right, top-to-bottom while remaining height >= 256

	for( left=0; left<m_pTextureList->m_width; left += width )
	{
		width = (m_pTextureList->m_width-left > 256) ? 256 : m_pTextureList->m_width-left;
		if( ( width & 255 ) > 128 )
			width = 128;
		for( top=0; top < (m_pTextureList->m_height & ~255L); top+=height )
		{
			height = (m_pTextureList->m_height-top > 256) ? 256 : m_pTextureList->m_height-top;
			if( ( height & 255 ) > 128 )
				height = 128;
			// square powers of two can be handled as dedicated textures
			if( ( ( height | width ) & ( ( height | width ) - 1 ) ) == 0 )
			{
				// Add a dedicated  texture for this piece (square power of two)
				DWORD Texture = AddTexture(height);
				AddQuad( left, top, width, height, Texture, 0, 0, width );
				continue;
			}
			AddSharedQuad( left, top, width, height );
		}
	}

	// top-to-bottom, left-to-right once remaining height < 256
	for( top = (m_pTextureList->m_height & ~255L); top<m_pTextureList->m_height; top+=height )
	{
		height = (m_pTextureList->m_height-top > 256) ? 256 : m_pTextureList->m_height-top;
		if( ( height & 255 ) > 128 )
			height = 128;
		for( left=0; left<m_pTextureList->m_width; left += width )
		{
			width = (m_pTextureList->m_width-left > 256) ? 256 : m_pTextureList->m_width-left;
			if( ( width & 255 ) > 128 )
				width = 128;
			// square powers of two can be handled as dedicated textures
			if( ( ( height | width ) & ( ( height | width ) - 1 ) ) == 0 )
			{
				// Add a dedicated  texture for this piece (square power of two)
				DWORD Texture = AddTexture(height);
				AddQuad( left, top, width, height, Texture, 0, 0, width );
				continue;
			}
			AddSharedQuad( left, top, width, height );
		}
	}
}


void gos_Pane::Play()
{
	if (hVideo)
	{
		gosVideo_SetPlayMode(hVideo, gosVideo_PlayOnceHold);
	}
}

void gos_Pane::Loop()
{
	if (hVideo)
	{
		gosVideo_SetPlayMode(hVideo, gosVideo_Loop);
	}
}

void gos_Pane::Stop()
{
	if (hVideo)
	{
		gosVideo_SetPlayMode(hVideo, gosVideo_Stop);
	}
}

