#include "Mesh.h"
#include "Texture.h"
#include "Overlay.h"
#include "D3D11Effect.h"
#include "CelSphere.h"

#pragma region static
ID3D11InputLayout
	*D3D11Mesh::IL_D3DXVECTOR3	= NULL,
	*D3D11Mesh::IL_MESH_VERTEX	= NULL;

ID3D11VertexShader
	*D3D11Mesh::VS_Mesh			= NULL,
	*D3D11Mesh::VS_VC			= NULL,
	*D3D11Mesh::VS_Shadow		= NULL,
	*D3D11Mesh::VS_BaseTile		= NULL;

ID3D11PixelShader
	*D3D11Mesh::PS_Mesh			= NULL,
	*D3D11Mesh::PS_VC[3]		= { NULL },
	*D3D11Mesh::PS_Shadow		= NULL,
	*D3D11Mesh::PS_BaseTile		= NULL;

ID3D11SamplerState
	*D3D11Mesh::SS_BaseTile		= NULL,
	*D3D11Mesh::SS_Texture		= NULL,
	*D3D11Mesh::SS_HUD			= NULL;

ID3D11DepthStencilState
	*D3D11Mesh::DSS_Shadow		= NULL,
	*D3D11Mesh::DSS_Mesh		= NULL;

ID3D11Buffer
	*D3D11Mesh::cb_VS_VC_per_frame	= NULL,
	*D3D11Mesh::cb_VS_per_frame		= NULL,
	*D3D11Mesh::cb_VS_per_object	= NULL,
	*D3D11Mesh::cb_VS_per_group		= NULL,
	*D3D11Mesh::cb_PS_per_object	= NULL,
	*D3D11Mesh::cb_PS_per_group		= NULL,
	*D3D11Mesh::cb_VS_BaseTile		= NULL;

cb_VSCB_per_frame D3D11Mesh::VSCB_per_frame;
cb_VSCB_per_object D3D11Mesh::VSCB_per_object;
cb_VSCB_per_group D3D11Mesh::VSCB_per_group;
cb_PSCB_per_object D3D11Mesh::PSCB_per_object;
cb_VSCB_BaseTile D3D11Mesh::VSCB_BaseTile;

const UINT
	D3D11Mesh::MVertexStride = sizeof(MESH_VERTEX),
	D3D11Mesh::VBOffset = 0;

const float D3D11Mesh::blend_factors[4] = { 1.0f };

D3D11Material D3D11Mesh::DefaultMat = {
	D3DXVECTOR3( 1, 1, 1 ), 1.0f,
	D3DXVECTOR3( 1, 1, 1 ), 0,
	D3DXVECTOR3( 0, 0, 0 ), 10.0f,
	D3DXVECTOR3( 0, 0, 0 ), 0 
};

Sun_spec D3D11Mesh::WhiteSunLight;

void D3D11Mesh::GlobalInit() {
//shaders:
//Without Normal maps:
	HRESULT hr;
	ID3DBlob *SBlob = NULL, *EBlob = NULL;

	D3D11_INPUT_ELEMENT_DESC ldesc0[ ] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "NORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TANGENT", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0 },
		{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 36, D3D11_INPUT_PER_VERTEX_DATA, 0 },
	};

	//======================================
	//		Meshes
	//======================================

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh.fx", NULL, NULL, "VS_Mesh", vs_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreateInputLayout( ldesc0, 4, SBlob->GetBufferPointer(), SBlob->GetBufferSize(), &IL_MESH_VERTEX ) );
	HR( Dev->CreateVertexShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &VS_Mesh ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh.fx", NULL, NULL, "PS_Mesh", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_Mesh ) );
	REL( SBlob );
	REL( EBlob );

	//======================================
	//		VC
	//======================================

	CompileFromFile( "Modules\\D3D11Shaders\\VC.fx", NULL, NULL, "VS_VC", vs_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreateVertexShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &VS_VC ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\VC.fx", NULL, NULL, "PS_VC", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_VC[0] ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\VC.fx", NULL, NULL, "PS_MFD", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_VC[1] ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\VC.fx", NULL, NULL, "PS_HUD", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_VC[2] ) );
	REL( SBlob );
	REL( EBlob );

	//======================================
	//		Shadows
	//======================================

	D3D11_INPUT_ELEMENT_DESC ldesc1[ ] = {
		{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
	};

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh_Shadow.fx", NULL, NULL, "VS_Shadow", vs_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreateInputLayout( ldesc1, 1, SBlob->GetBufferPointer(), SBlob->GetBufferSize(), &IL_D3DXVECTOR3 ) );
	HR( Dev->CreateVertexShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &VS_Shadow ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh_Shadow.fx", NULL, NULL, "PS_Shadow", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_Shadow ) );
	REL( SBlob );
	REL( EBlob );

	//======================================
	//		Base Tiles
	//======================================

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh_BaseTile.fx", NULL, NULL, "VS_BaseTile", vs_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
//	HR( Dev->CreateInputLayout( ldesc0, 4, SBlob->GetBufferPointer(), SBlob->GetBufferSize(), &IL_MESH_VERTEX ) );
	HR( Dev->CreateVertexShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &VS_BaseTile ) );
	REL( SBlob );
	REL( EBlob );

	CompileFromFile( "Modules\\D3D11Shaders\\Mesh_BaseTile.fx", NULL, NULL, "PS_BaseTile", ps_ver, ShaderCompileFlag, 0, NULL, &SBlob, &EBlob, &hr );
	ShowShaderCompilationError( hr, EBlob );
	HR( Dev->CreatePixelShader( SBlob->GetBufferPointer(), SBlob->GetBufferSize(), NULL, &PS_BaseTile ) );
	REL( SBlob );
	REL( EBlob );

	//======================================
	//		Samplers
	//======================================

//sampler states:
	D3D11_SAMPLER_DESC sdesc;
	ZeroMemory( &sdesc, sizeof( sdesc ) );
	sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sdesc.AddressU = D3D11_TEXTURE_ADDRESS_MIRROR;
	sdesc.AddressV = D3D11_TEXTURE_ADDRESS_MIRROR;
	sdesc.AddressW = D3D11_TEXTURE_ADDRESS_MIRROR;
	sdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
	sdesc.MaxAnisotropy = 1;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_BaseTile ) );

	ZeroMemory( &sdesc, sizeof( sdesc ) );
	sdesc.Filter = cfg->FILTER_MeshTexture;
	sdesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
	sdesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
	sdesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
	sdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
	sdesc.MaxAnisotropy = cfg->AF_FACTOR_MeshTexture;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_Texture ) );

	ZeroMemory( &sdesc, sizeof( sdesc ) );
	sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	sdesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
	sdesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
	sdesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
	sdesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
	sdesc.MaxAnisotropy = 1;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_HUD ) );

	//======================================
	//		D.S.S.
	//======================================

//depth-stencil states:
	D3D11_DEPTH_STENCIL_DESC dsdesc;
	ZeroMemory( &dsdesc, sizeof(dsdesc) );
	dsdesc.DepthEnable = false;
	dsdesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
	dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	dsdesc.StencilEnable = true;
	dsdesc.StencilReadMask = 1;
	dsdesc.StencilWriteMask = 1;

	dsdesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;	//what to do if stencil test failed
	dsdesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;	//if stencil succeded
	dsdesc.FrontFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL;	//stencil will pass only if stencil != StencilRef
	dsdesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;

	dsdesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
	dsdesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE;
	dsdesc.BackFace.StencilFunc = D3D11_COMPARISON_NOT_EQUAL;
	dsdesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE;

	HR( Dev->CreateDepthStencilState( &dsdesc, &DSS_Shadow ) );

	ZeroMemory( &dsdesc, sizeof(dsdesc) );
	dsdesc.DepthEnable = true;
	dsdesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
	dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
	dsdesc.StencilEnable = false;
	dsdesc.StencilReadMask = 0;
	dsdesc.StencilWriteMask = 0;

	HR( Dev->CreateDepthStencilState( &dsdesc, &DSS_Mesh ) );

	//======================================
	//		Buffers
	//======================================

//cbuffers:
	//vertex shader
	D3D11_BUFFER_DESC bdesc;
	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 1184;
	bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DYNAMIC;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_VS_per_frame ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 144;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_VS_per_object ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 80;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_VS_per_group ) );

	//pixel shader
	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 64;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_PS_per_object ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 64;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_PS_per_group ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 112;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_VS_BaseTile ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	bdesc.ByteWidth = 64;
	bdesc.CPUAccessFlags = 0;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &bdesc, NULL, &cb_VS_VC_per_frame ) );

	WhiteSunLight.ambient = D3DXCOLOR( fAmbient, fAmbient, fAmbient, 1.0f );
	WhiteSunLight.diffuse = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
	WhiteSunLight.specular = D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f );
	WhiteSunLight.SunDir = D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f );
}

void D3D11Mesh::GlobalExit() {
	REL( IL_D3DXVECTOR3 );
	REL( IL_MESH_VERTEX );
	REL( VS_Mesh );
	REL( VS_Shadow );
	REL( VS_BaseTile );
	REL( PS_Mesh );
	REL( VS_VC );
	REL( PS_VC[0] );
	REL( PS_VC[1] );
	REL( PS_VC[2] );
	REL( PS_BaseTile );
	REL( PS_Shadow );
	REL( SS_Texture );
	REL( SS_HUD );
	REL( DSS_Shadow );
	REL( DSS_Mesh );
	REL( cb_VS_VC_per_frame );
	REL( cb_VS_per_frame );
	REL( cb_VS_per_object );
	REL( cb_VS_per_group );
	REL( cb_PS_per_object );
	REL( cb_PS_per_group );
	REL( cb_VS_BaseTile );
}
#pragma endregion

D3D11Mesh::D3D11Mesh( D3D11TPLMesh *tpl ) : D3D11TPLMesh() {
//Copies vertex and index data from template to mesh [vessel]
	ngrp = tpl->ngrp;
	nmat = tpl->nmat;
	ntex = tpl->ntex;
	nnorm = tpl->nnorm;
	vbsize = tpl->vbsize;
	ibsize = tpl->ibsize;

	bsPos = tpl->bsPos;
	bsRad = tpl->bsRad;
	VB = IB = shadow_VB = shadow_IB = NULL;
	bMeshT = false;
	D3DXMatrixIdentity( &mT );

	GR = new MGROUP [ngrp];
	_VB = new MESH_VERTEX [vbsize];
	_IB = new WORD [ibsize];
	_shadow_VB = new D3DXVECTOR3 [vbsize];
	_shadow_IB = new DWORD [ibsize];
	memcpy( GR, tpl->GR, sizeof(MGROUP)*ngrp );
	memcpy( _VB, tpl->_VB, sizeof(MESH_VERTEX)*vbsize );
	memcpy( _IB, tpl->_IB, 2*ibsize );	
	memcpy( _shadow_VB, tpl->_shadow_VB, 12*vbsize );
	memcpy( _shadow_IB, tpl->_shadow_IB, 4*ibsize );

	if( nmat ) {
		MAT = new D3D11Material [nmat];
		memcpy( MAT, tpl->MAT, sizeof(D3D11Material)*nmat );
	}

	if( ntex ) {
		TEX = new Texture *[ntex];
		memcpy( TEX, tpl->TEX, sizeof(Texture*)*ntex );
		
		NORM = new Texture *[ntex];
		memcpy( NORM, tpl->NORM, sizeof(Texture*)*ntex );

		SPEC = new Texture *[ntex];
		memcpy( SPEC, tpl->SPEC, sizeof(Texture*)*ntex );

		EMIS = new Texture *[ntex];
		memcpy( EMIS, tpl->EMIS, sizeof(Texture*)*ntex );
	}

	CreateBuffers( true );
	UpdateBoundings();
}

D3D11Mesh::D3D11Mesh( DWORD _ngrp, MESHGROUPEX **grps, SURFHANDLE *texs ) : D3D11TPLMesh() {	//MOD !!!
	DWORD j;

//Basetile mesh
	GR = NULL;
	shadow_IB = IB = shadow_VB = VB = NULL;
	bMeshT = false;
	D3DXMatrixIdentity( &mT );

	ngrp = _ngrp;
	LoadGroups( grps );

	for( j = 0; j < ngrp; j++ ) {
		GR[j].mat_idx = SPEC_DEFAULT;
		GR[j].tex_idx = j;
		GR[j].tex_idx_ex[0] = SPEC_DEFAULT;
		GR[j].tex_mix_idx[0] = 0.0f;
		GR[j].BlendMode = 2;
	}

	nmat = 0;
	ntex = ngrp + 1;
	TEX = new Texture *[ntex];
	NORM = new Texture *[ntex];
	SPEC = new Texture *[ntex];
	EMIS = new Texture *[ntex];
	memset( TEX, 0, sizeof(Texture*)*ntex );
	memset( NORM, 0, sizeof(Texture*)*ntex );
	memset( SPEC, 0, sizeof(Texture*)*ntex );
	memset( EMIS, 0, sizeof(Texture*)*ntex );

	LoadGroups( grps );

	for( j = 0; j < ngrp; j++ )
		GR[j].tex_idx = j;

	for( j = 1; j < ntex; j++ )
		TEX[j] = (Texture*)texs[j-1];

	ProcessInherit();

//	FindTransparent();
	for( j = 0; j < ngrp; j++ )
		ComputeTangents( &GR[j] );

//	SearchForNormalMaps();		//loads all existing normal maps
	for( DWORD j = 0; j < ngrp; j++ )	//compute bounding boxes and spheres for groups
		ComputeBoundingBox( GR[j] );

	bsPos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	bsRad = 0.0f;
	
	CreateBuffers( false );
	UpdateBoundings();
}

D3D11Mesh::D3D11Mesh( MESHHANDLE Mesh, bool shadows ) : D3D11TPLMesh( Mesh ) {
	VB = IB = shadow_VB = shadow_IB = NULL;
	bMeshT = false;
	D3DXMatrixIdentity( &mT );

	CreateBuffers( shadows );
	UpdateBoundings();
}

D3D11Mesh::~D3D11Mesh() {
	REL( VB );
	REL( IB );
	if( shadow_VB )		REL( shadow_VB );
	if( shadow_IB )		REL( shadow_IB );
}

void D3D11Mesh::CreateBuffers( bool shadows ) {
	D3D11_BUFFER_DESC bdesc;
	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
	bdesc.ByteWidth = vbsize*sizeof(MESH_VERTEX);
	bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DYNAMIC;

	D3D11_SUBRESOURCE_DATA sdata;
	ZeroMemory( &sdata, sizeof(sdata) );
	sdata.pSysMem = _VB;

	HR( Dev->CreateBuffer( &bdesc, &sdata, &VB ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
	bdesc.ByteWidth = ibsize*2;
	bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
	bdesc.MiscFlags = 0;
	bdesc.StructureByteStride = 0;
	bdesc.Usage = D3D11_USAGE_DYNAMIC;

	ZeroMemory( &sdata, sizeof(sdata) );
	sdata.pSysMem = _IB;

	HR( Dev->CreateBuffer( &bdesc, &sdata, &IB ) );

	if( shadows ) {
		ZeroMemory( &bdesc, sizeof(bdesc) );
		bdesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
		bdesc.ByteWidth = vbsize*12;
		bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		bdesc.MiscFlags = 0;
		bdesc.StructureByteStride = 0;
		bdesc.Usage = D3D11_USAGE_DYNAMIC;

		ZeroMemory( &sdata, sizeof(sdata) );
		sdata.pSysMem = _shadow_VB;

		HR( Dev->CreateBuffer( &bdesc, &sdata, &shadow_VB ) );

		ZeroMemory( &bdesc, sizeof(bdesc) );
		bdesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
		bdesc.ByteWidth = ibsize*4;
		bdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
		bdesc.MiscFlags = 0;
		bdesc.StructureByteStride = 0;
		bdesc.Usage = D3D11_USAGE_DYNAMIC;

		ZeroMemory( &sdata, sizeof(sdata) );
		sdata.pSysMem = _shadow_IB;

		HR( Dev->CreateBuffer( &bdesc, &sdata, &shadow_IB ) );
	}
}

//================================================
//			Night/Day texture
//================================================

void D3D11Mesh::SetTextureMix( DWORD ntex, float mix ) {

	ntex--;
	for( DWORD j = 0; j < ngrp; j++ )
		if( GR[j].tex_idx_ex[ntex] != SPEC_DEFAULT )
			GR[j].tex_mix_idx[ntex] = mix;
}

//================================================
//			Update
//================================================

void D3D11Mesh::TransformGroup( UINT grp, D3DXMATRIX *T ) {
	GR[grp].T_new *= *T;
	GR[grp].upd_once = true;
	GR[grp].scale_new = D3DMAT_BSScaleFactor( &GR[grp].T_new );
	bRecomputeBoundings = true;
}

void D3D11Mesh::TransformAll( D3DXMATRIX *T ) {
	bRecomputeBoundings = true;
	bMeshT = true;
	mT_new *= *T;
}

void D3D11Mesh::Update() {
	for( DWORD j = 0; j < ngrp; j++ )
		if( GR[j].upd_once ) {
			GR[j].T = GR[j].T_new;
			GR[j].scale = GR[j].scale_new;
		}
	if( bMeshT )
		mT = mT_new;
	if( bRecomputeBoundings )
		UpdateBoundings();
}

//================================================
//			Basic
//================================================

void D3D11Mesh::InitRender() {
	//set vars
	iCtx->IASetInputLayout( IL_MESH_VERTEX );
	iCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	iCtx->VSSetShader( VS_Mesh, NULL, NULL );
	iCtx->RSSetState( RS_CullBack_Solid );
	iCtx->OMSetDepthStencilState( DSS_Mesh, 0 );

	iCtx->VSSetConstantBuffers( 0, 1, &cb_VS_per_frame );
	iCtx->VSSetConstantBuffers( 1, 1, &cb_VS_per_object );
	iCtx->VSSetConstantBuffers( 2, 1, &cb_VS_per_group );

	iCtx->PSSetShader( PS_Mesh, NULL, NULL );
	iCtx->PSSetConstantBuffers( 0, 1, &cb_PS_per_object );
	iCtx->PSSetConstantBuffers( 1, 1, &cb_PS_per_group );

	iCtx->PSSetSamplers( 0, 1, &SS_Texture );

	//update per frame data
	D3D11_MAPPED_SUBRESOURCE SRes;
	memset( &SRes, 0, sizeof(SRes) );
	iCtx->Map( cb_VS_per_frame, 0, D3D11_MAP_WRITE_DISCARD, 0, &SRes );
	BYTE *data = (BYTE*)SRes.pData;

	ATM_FOG_PARAMS *AP = SC->GetAtmParams();	//get atmosphere params of the nearest planet (if any).
	if( AP ) {
		VSCB_per_frame.FogColor = D3DXVECTOR3( AP->FogColor.r, AP->FogColor.g, AP->FogColor.b );
		VSCB_per_frame.FogDensity = AP->FogDensity;
		VSCB_per_frame.HazeMode = AP->HazeMode;
		memcpy( data, &VSCB_per_frame, 20 );
	}
	else {
		VSCB_per_frame.HazeMode = 0;
		memcpy( data, &VSCB_per_frame, 4 );
	}

	UINT cnt = SC->GetLocalLightCount();
	if( cnt ) {
		D3D11Light *LL = SC->GetLocalLights();
		memcpy( data+32, LL, cnt*96 );
	}
	iCtx->Unmap( cb_VS_per_frame, 0 );
}

void D3D11Mesh::Render( vObject *vobj, D3DXMATRIX *mOfsWorld, bool mesh_cull, bool grp_cull ) {
	D3D11Material *Mat;
	DWORD pSDR, SDR, p_TEX, _TEX, BLND, p_BLND;
	const UINT MeshVertexStride = 44, VBOffset = 0;

//
//check mesh visibility and cull invisible meshes:
	float
		ap = (float)SC->GetCamAperture(),
		h = tan( ap ),
		dfr = 0.0015f*h,
		hf = 1.0f/cos( ap ),
		as = cfg->Aspect,
		w = h*as,
		wf = hf*as;

	if( mesh_cull ) {
		D3DXVECTOR3 vP;
		D3DXMATRIX mWorldView = *mOfsWorld * *SC->GetV();
		D3DXVec3TransformCoord( &vP, &bsPos, &mWorldView );
		float r = bsRad;
	
		if( r < 0 )						r = -r;
		if( vP.z < (-r) )				return;
		if( vP.z < 0 )					vP.z = -vP.z;
		if( vP.y < 0 )					vP.y = -vP.y;
		if( vP.x < 0 )					vP.x = -vP.x;
		if( (r/vP.z) < dfr )			return;
		if( vP.y - (r*hf) > (h*vP.z) )	return;
		if( vP.x - (r*wf) > (w*vP.z) )	return;
	}

//data buffers:
	iCtx->IASetVertexBuffers( 0, 1, &VB, &MeshVertexStride, &VBOffset );
	iCtx->IASetIndexBuffer( IB, DXGI_FORMAT_R16_UINT, 0 );

	p_TEX = 10;
	p_BLND = 10;
	if( bMeshT ) {
		D3DXMATRIX tmp = *mOfsWorld;
		*mOfsWorld = mT * tmp;
	}
	for( UINT j = 0; j < ngrp; j++ ) {
		if( GR[j].userflag & 0x2 )	continue;

		//cull invisible groups
		VSCB_per_group.W = GR[j].upd_once ? GR[j].T * *mOfsWorld : *mOfsWorld;
		if( grp_cull ) {
			D3DXVECTOR3 vP;
			D3DXMATRIX WV = VSCB_per_group.W * *SC->GetV();
			D3DXVec3TransformCoord( &vP, &GR[j].bsPos, &WV );

			float r = GR[j].bsRad * GR[j].scale;

			if( vP.z < (-r) )		continue;
			if( vP.z < 0.0f )		vP.z = -vP.z;
			if( (r/vP.z) < dfr )	continue;
			if( vP.y < 0.0f )		vP.y = -vP.y;
			if( (vP.y - (r*hf)) > (h*vP.z) )	continue;
			if( vP.x < 0.0f )		vP.x = -vP.x;
			if( (vP.x - (r*wf)) > (w*vP.z) )	continue;
		}
				
		VSCB_per_group.spec_power = ( GR[j].mat_idx == SPEC_DEFAULT ? 1.0f : MAT[GR[j].mat_idx].spec_power );
		iCtx->UpdateSubresource( cb_VS_per_group, 0, NULL, &VSCB_per_group, 0, 0 );

		if( GR[j].mat_idx != SPEC_DEFAULT )		Mat = &MAT[GR[j].mat_idx];
		else									Mat = &DefaultMat;
		
		Mat->flags = 0;
		if( GR[j].userflag & 0x4 )
			Mat->flags |= 64;
		if( TEX[GR[j].tex_idx] ) {
			Mat->flags |= 1;
			if( bMixMatAlpha )
				Mat->flags |= 2;
			if( NORM[GR[j].tex_idx] )
				Mat->flags |= 4;
			if( SPEC[GR[j].tex_idx] )
				Mat->flags |= 8;
			if( EMIS[GR[j].tex_idx] )
				Mat->flags |= 16;
			if( GR[j].tex_idx_ex[0] && GR[j].tex_mix_idx[0] > 0.5f && TEX[GR[j].tex_idx_ex[0]] ) {
				Mat->flags |= 32;
				Mat->TexEx_mix = GR[j].tex_mix_idx[0];
			}
		}

		iCtx->UpdateSubresource( cb_PS_per_group, 0, NULL, Mat, 0, 0 );
		
		_TEX = GR[j].tex_idx;
		if( _TEX && _TEX != p_TEX && TEX[GR[j].tex_idx] ) {
			iCtx->PSSetShaderResources( 0, 1, TEX[GR[j].tex_idx]->GetSRV() );
			if( NORM[GR[j].tex_idx] )
				iCtx->PSSetShaderResources( 1, 1, NORM[GR[j].tex_idx]->GetSRV() );
			if( SPEC[GR[j].tex_idx] )
				iCtx->PSSetShaderResources( 2, 1, SPEC[GR[j].tex_idx]->GetSRV() );
			if( EMIS[GR[j].tex_idx] )
				iCtx->PSSetShaderResources( 3, 1, EMIS[GR[j].tex_idx]->GetSRV() );
			if( TEX[GR[j].tex_idx_ex[0]] )
				iCtx->PSSetShaderResources( 4, 1, TEX[GR[j].tex_idx_ex[0]]->GetSRV() );		
		}

		BLND = GR[j].BlendMode;
		if( BLND != p_BLND )
			iCtx->OMSetBlendState( ( BLND == 2 ? BS_NoBlend : BS_SrcAlpha ), D3DXVECTOR4( 1, 1, 1, 1 ), 0xFFFFFFFF );

		iCtx->DrawIndexed( GR[j].nidx, GR[j].sidx, GR[j].svtx );

		p_TEX = _TEX;
		p_BLND = BLND;
	}
}

//================================================
//			Render VC
//================================================

void D3D11Mesh::RenderVC( vObject *vobj, D3DXMATRIX *mOfsWorld, DWORD nmsh, bool mesh_cull, bool grp_cull ) {
	DWORD p_TEX, _TEX, j, grp = 0;
	const UINT MeshVertexStride = 44, VBOffset = 0;
	D3D11Material *Mat;
	D3DXMATRIX tmp;
	VCMFDSPEC *specMFD;
	VCHUDSPEC *specHUD;
	Texture **texHUD, **texMFD;

	float
		ap = (float)SC->GetCamAperture(),
		h = tan( ap ),
		dfr = 0.0015f*h,
		hf = 1.0f/cos( ap ),
		as = cfg->Aspect,
		w = h*as,
		wf = hf*as;

	//cull invisible meshes...
	if( mesh_cull ) {
		D3DXVECTOR3 vP;
		D3DXMATRIX mWorldView = *mOfsWorld * *SC->GetV();
		D3DXVec3TransformCoord( &vP, &bsPos, &mWorldView );
		float r = bsRad;
	
		if( r < 0 )						r = -r;
		if( vP.z < (-r) )				return;
		if( vP.z < 0 )					vP.z = -vP.z;
		if( vP.y < 0 )					vP.y = -vP.y;
		if( vP.x < 0 )					vP.x = -vP.x;
		if( (r/vP.z) < dfr )			return;
		if( vP.y - (r*hf) > (h*vP.z) )	return;
		if( vP.x - (r*wf) > (w*vP.z) )	return;
	}

	iCtx->IASetVertexBuffers( 0, 1, &VB, &MeshVertexStride, &VBOffset );
	iCtx->IASetIndexBuffer( IB, DXGI_FORMAT_R16_UINT, 0 );
	
	specHUD = SC->GetHUDSpec();
	texHUD = SC->GetHUDTex();
	iCtx->PSSetShader( PS_VC[2], NULL, NULL );
	if( specHUD->nmesh != (DWORD)-1 && specHUD->nmesh == nmsh ) {
		if( *texHUD ) {
			GR[grp].userflag &= ~0x2;

			grp = specHUD->ngroup;
			if( GR[grp].upd_once )	tmp = GR[grp].T * *mOfsWorld;
			else					tmp = *mOfsWorld;
			//check mesh group visibility
			if( grp_cull ) {
				D3DXVECTOR3 vP;
				D3DXMATRIX WV = tmp * *SC->GetV();
				D3DXVec3TransformCoord( &vP, &GR[grp].bsPos, &WV );

				float r = GR[grp].bsRad * GR[grp].scale;

				if( vP.z < (-r) )		return;
				if( vP.z < 0.0f )		vP.z = -vP.z;
				if( (r/vP.z) < dfr )	return;
				if( vP.y < 0.0f )		vP.y = -vP.y;
				if( (vP.y - (r*hf)) > (h*vP.z) )	return;
				if( vP.x < 0.0f )		vP.x = -vP.x;
				if( (vP.x - (r*wf)) > (w*vP.z) )	return;
			}
			iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );

			iCtx->OMSetDepthStencilState( DSS_NoDepth_NoStencil, 0 );
			iCtx->PSSetSamplers( 0, 1, &SS_HUD );

			Mat = &DefaultMat;
			Mat->flags = ( *texHUD ? 0 : 1 );
			iCtx->UpdateSubresource( cb_PS_per_group, 0, NULL, Mat, 0, 0 );

			if( *texHUD ) {
				gc->HUDTEX = *texHUD;
				iCtx->PSSetShaderResources( 0, 1, (*texHUD)->GetSRV() );
			}

			iCtx->DrawIndexed( GR[grp].nidx, GR[grp].sidx, GR[grp].svtx );

			GR[grp].userflag |= 0x2;
		}
	}

	specMFD = SC->GetMFDSpec();
	texMFD = SC->GetMFDTex();
	iCtx->PSSetShader( PS_VC[1], NULL, NULL );
	iCtx->PSSetSamplers( 0, 1, &SS_Texture );
	iCtx->OMSetDepthStencilState( DSS_Mesh, 0 );
	for( j = 0; j < MAXMFD; j++ ) {
		if( specMFD[j].nmesh != (DWORD)-1 && specMFD[j].nmesh == nmsh ) {				
						
			grp = specMFD[j].ngroup;
			GR[grp].userflag &= ~0x2;

			if( GR[grp].upd_once )	tmp = GR[grp].T * *mOfsWorld;
			else					tmp = *mOfsWorld;
			//check mesh group visibility
			if( grp_cull ) {
				D3DXVECTOR3 vP;
				D3DXMATRIX WV = tmp * *SC->GetV();
				D3DXVec3TransformCoord( &vP, &GR[grp].bsPos, &WV );

				float r = GR[grp].bsRad * GR[grp].scale;

				if( vP.z < (-r) )		continue;
				if( vP.z < 0.0f )		vP.z = -vP.z;
				if( (r/vP.z) < dfr )	continue;
				if( vP.y < 0.0f )		vP.y = -vP.y;
				if( (vP.y - (r*hf)) > (h*vP.z) )	continue;
				if( vP.x < 0.0f )		vP.x = -vP.x;
				if( (vP.x - (r*wf)) > (w*vP.z) )	continue;
			}
			iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );

			//material
			if( GR[grp].mat_idx != SPEC_DEFAULT )		Mat = &MAT[GR[grp].mat_idx];
			else										Mat = &DefaultMat;
			Mat->flags = 0;
			if( texMFD[j] )		Mat->flags |= 1;
			iCtx->UpdateSubresource( cb_PS_per_group, 0, NULL, Mat, 0, 0 );

			if( texMFD[j] )
				iCtx->PSSetShaderResources( 0, 1, texMFD[j]->GetSRV() );

			iCtx->DrawIndexed( GR[grp].nidx, GR[grp].sidx, GR[grp].svtx );

			GR[grp].userflag |= 0x2;
		}
	}

	p_TEX = 10;
	iCtx->PSSetShader( PS_VC[0], NULL, NULL );
	for( j = 0; j < ngrp; j++ ) {
		if( GR[j].userflag & 0x2 )	continue;

		//check group visibility...
		if( GR[j].upd_once )	tmp = GR[j].T * *mOfsWorld;
		else					tmp = *mOfsWorld;
		if( grp_cull ) {
			D3DXVECTOR3 vP;
			D3DXMATRIX WV = tmp * *SC->GetV();
			D3DXVec3TransformCoord( &vP, &GR[j].bsPos, &WV );
			
			float r = GR[j].bsRad * GR[j].scale;

			if( vP.z < (-r) )		continue;
			if( vP.z < 0.0f )		vP.z = -vP.z;
			if( (r/vP.z) < dfr )	continue;
			if( vP.y < 0.0f )		vP.y = -vP.y;
			if( (vP.y - (r*hf)) > (h*vP.z) )	continue;
			if( vP.x < 0.0f )		vP.x = -vP.x;
			if( (vP.x - (r*wf)) > (w*vP.z) )	continue;
		}
		iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );		
		
		if( GR[j].mat_idx != SPEC_DEFAULT )		Mat = &MAT[GR[j].mat_idx];
		else									Mat = &DefaultMat;
		Mat->flags = 0;
		if( GR[j].userflag & 0x4 )
			Mat->flags |= 64;
		if( TEX[GR[j].tex_idx] ) {
			Mat->flags |= 1;
			if( bMixMatAlpha )
				Mat->flags |= 2;
		}
		iCtx->UpdateSubresource( cb_PS_per_group, 0, NULL, Mat, 0, 0 );

		_TEX = GR[j].tex_idx;
		if( _TEX && _TEX != p_TEX && TEX[GR[j].tex_idx] )
			iCtx->PSSetShaderResources( 0, 1, TEX[GR[j].tex_idx]->GetSRV() );

		iCtx->DrawIndexed( GR[j].nidx, GR[j].sidx, GR[j].svtx );

		p_TEX = _TEX;
	}
}

//================================================
//			Base Tiles
//================================================

void D3D11Mesh::InitRenderBaseTiles() {
	iCtx->IASetInputLayout( IL_MESH_VERTEX );
	iCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	iCtx->VSSetShader( VS_BaseTile, NULL, NULL );
	iCtx->PSSetShader( PS_BaseTile, NULL, NULL );
	iCtx->PSSetSamplers( 0, 1, &SS_BaseTile );
	iCtx->OMSetBlendState( BS_SrcAlpha, D3DXCOLOR( 1, 1, 1, 1 ), 0xFFFFFFFF );
	iCtx->RSSetState( RS_CullBack_Solid );
	iCtx->OMSetDepthStencilState( DSS_NoDepth_NoStencil, 0 );

	iCtx->VSSetConstantBuffers( 0, 1, &cb_VS_BaseTile );
	iCtx->VSSetConstantBuffers( 1, 1, &cb_D3DXMATRIX_x2 );

	iCtx->PSSetConstantBuffers( 0, 1, &cb_PS_per_object );
	
	iCtx->PSSetSamplers( 0, 1, &SS_BaseTile );

	VSCB_BaseTile.VP = *SC->GetVP();
	ATM_FOG_PARAMS *AP = SC->GetAtmParams();
	if( AP ) {
		VSCB_BaseTile.HazeMode = AP->HazeMode;
		VSCB_BaseTile.Ambient0 = AP->Ambient0;
		VSCB_BaseTile.Dispersion = AP->Dispersion;
		VSCB_BaseTile.FogColor = D3DXVECTOR3( AP->FogColor.r, AP->FogColor.g, AP->FogColor.b );
		VSCB_BaseTile.FogDensity = AP->FogDensity;
		VSCB_BaseTile.GlobalAmb = AP->GlobalAmb;
		VSCB_BaseTile.SunAppRad = AP->SunAppRad;
		VSCB_BaseTile.SunDir = D3DXVECTOR3( AP->SunDir.x, AP->SunDir.y, AP->SunDir.z );
		iCtx->UpdateSubresource( cb_VS_BaseTile, 0, NULL, &VSCB_BaseTile, 0, 0 );
	}
}

void D3D11Mesh::RenderBaseTiles( vObject *vobj, D3DXMATRIX *mWorld ) {
	D3DXVECTOR4 SDIR;
	D3DXMATRIX M[2];
	const UINT MeshVertexStride = 44, VBOffset = 0;

//tile visibility
	float
		ap = (float)SC->GetCamAperture(),
		h = tan( ap ),
		dfr = 0.0015f*h,
		hf = 1.0f/cos( ap ),
		as = cfg->Aspect,
		w = h*as,
		wf = hf*as;

	iCtx->IASetVertexBuffers( 0, 1, &VB, &MeshVertexStride, &VBOffset );
	iCtx->IASetIndexBuffer( IB, DXGI_FORMAT_R16_UINT, 0 );

	D3DXVECTOR3 vP;
	D3DXMATRIX mWorldView = *mWorld * *SC->GetV();
	for( DWORD j = 0; j < ngrp; j++ ) {
		//cull invisible tiles
		D3DXVec3TransformCoord( &vP, &GR[j].bsPos, &mWorldView );
		float r = GR[j].bsRad;

		if( r < 0 )						r = -r;
		if( vP.z < (-r) )				continue;
		if( vP.z < 0 )					vP.z = -vP.z;
		if( vP.y < 0 )					vP.y = -vP.y;
		if( vP.x < 0 )					vP.x = -vP.x;
		if( (r/vP.z) < dfr )			continue;
		if( vP.y - (r*hf) > (h*vP.z) )	continue;
		if( vP.x - (r*wf) > (w*vP.z) )	continue;

		M[0] = *mWorld;
		M[1] = *SC->GetVP();
		iCtx->UpdateSubresource( cb_D3DXMATRIX_x2, 0, NULL, M, 0, 0 );

		SDIR = vobj->SunDir;
		iCtx->UpdateSubresource( cb_D3DXVECTOR4, 0, NULL, &SDIR, 0, 0 );

		if( TEX[GR[j].tex_idx] )
			iCtx->PSSetShaderResources( 0, 1, TEX[GR[j].tex_idx]->GetSRV() );
		

		iCtx->DrawIndexed( GR[j].nidx, GR[j].sidx, GR[j].svtx );
	}
}

//================================================
//			Vessel shadows
//================================================

void D3D11Mesh::InitRenderShadows() {

	iCtx->IASetInputLayout( IL_D3DXVECTOR3 );
	iCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
	iCtx->VSSetShader( VS_Shadow, NULL, NULL );
	iCtx->PSSetShader( PS_Shadow, NULL, NULL );
	iCtx->OMSetBlendState( BS_SrcAlpha, D3DXCOLOR( 1, 1, 1, 1 ), 0xFFFFFFFF );
	iCtx->RSSetState( RS_CullBack_Solid );
	iCtx->OMSetDepthStencilState( DSS_Shadow, 1 );

	iCtx->VSSetConstantBuffers( 0, 1, &cb_D3DXMATRIX_x1 );
	iCtx->PSSetConstantBuffers( 0, 1, &cb_D3DXVECTOR4 );
}

void D3D11Mesh::RenderShadows( D3DXMATRIX *mOfsProj, float shadow_alpha ) {
	const UINT D3DXVec3Stride = 12, VBOffset = 0;

	iCtx->IASetVertexBuffers( 0, 1, &shadow_VB, &D3DXVec3Stride, &VBOffset );
	iCtx->IASetIndexBuffer( shadow_IB, DXGI_FORMAT_R32_UINT, 0 );
	iCtx->UpdateSubresource( cb_D3DXVECTOR4, 0, NULL, D3DXVECTOR4( shadow_alpha, shadow_alpha, shadow_alpha, shadow_alpha ), 0, 0 );

	D3DXMATRIX TW, tmp;
	if( !bMeshT )	tmp = *mOfsProj * *SC->GetVP();
	else			tmp = mT * *mOfsProj * *SC->GetVP();
	DWORD j, nidx = 0, sidx = 0;
	for( DWORD j = 0; j < ngrp; j++ ) {
		if( GR[j].upd_once || (GR[j].userflag & 0x2) ) {

			if( nidx ) {
				iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );
				iCtx->DrawIndexed( nidx, sidx, 0 );
			}

			if( !(GR[j].userflag & 0x2) ) {
				TW = GR[j].T * tmp;
				iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &TW, 0, 0 );
				iCtx->DrawIndexed( GR[j].nidx, GR[j].sidx, 0 );
			}

			sidx += (nidx + GR[j].nidx);
			nidx = 0;
		}
		else	nidx += GR[j].nidx;
	}

	if( nidx ) {
		iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );
		iCtx->DrawIndexed( nidx, sidx, 0 );
	}
}

//================================================
//			Bounding boxes
//================================================

void D3D11Mesh::RenderBoundingBox( D3DXMATRIX *mOfsWorld ) {
	const UINT CVertexStride = 16, VBOffset = 0;
	STARVERTEX BB[24];

	iCtx->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINELIST );
	iCtx->IASetInputLayout( D3D11Effect::IL_CVertex );
	iCtx->IASetVertexBuffers( 0, 1, &Overlay::VB, &CVertexStride, &VBOffset );
	iCtx->VSSetConstantBuffers( 0, 1, &cb_D3DXMATRIX_x1 );
	iCtx->VSSetShader( D3D11Effect::VS_Star_Line, NULL, NULL );
	iCtx->PSSetConstantBuffers( 1, 1, &cb_D3DXVECTOR4 );
	iCtx->PSSetShader( D3D11Effect::PS_Line, NULL, NULL );
	iCtx->OMSetBlendState( BS_NoBlend, D3DXVECTOR4( 1, 1, 1, 1 ), 0xFFFFFFFF );
	iCtx->OMSetDepthStencilState( DSS_Mesh, 0 );

	BB[8].pos = BB[0].pos = BB[7].pos = AABB[0];
	BB[10].pos = BB[1].pos = BB[2].pos = D3DXVECTOR3( AABB[0].x, AABB[0].y, AABB[1].z );
	BB[12].pos = BB[3].pos = BB[4].pos = D3DXVECTOR3( AABB[1].x, AABB[0].y, AABB[1].z );
	BB[14].pos = BB[5].pos = BB[6].pos = D3DXVECTOR3( AABB[1].x, AABB[0].y, AABB[0].z );
	BB[9].pos = BB[16].pos = BB[23].pos = D3DXVECTOR3( AABB[0].x, AABB[1].y, AABB[0].z );
	BB[11].pos = BB[17].pos = BB[18].pos = D3DXVECTOR3( AABB[0].x, AABB[1].y, AABB[1].z );
	BB[13].pos = BB[19].pos = BB[20].pos = D3DXVECTOR3( AABB[1].x, AABB[1].y, AABB[1].z );
	BB[15].pos = BB[21].pos = BB[22].pos = D3DXVECTOR3( AABB[1].x, AABB[1].y, AABB[0].z );

	D3DXMATRIX tmp = *mOfsWorld * *SC->GetVP();
	iCtx->UpdateSubresource( cb_D3DXMATRIX_x1, 0, NULL, &tmp, 0, 0 );
	iCtx->UpdateSubresource( cb_D3DXVECTOR4, 0, NULL, D3DXVECTOR4( 0.3f, 1.0f, 0.3f, 1.0f ), 0, 0 );

	D3D11_MAPPED_SUBRESOURCE SRes;
	memset( &SRes, 0, sizeof(SRes) );
	iCtx->Map( Overlay::VB , 0, D3D11_MAP_WRITE_DISCARD, 0, &SRes );
	memcpy( SRes.pData, BB, 16*24 );
	iCtx->Unmap( Overlay::VB, 0 );

	iCtx->Draw( 24, 0 );
}

void D3D11Mesh::UpdateBoundings() {
	bRecomputeBoundings = false;

	float a, b, c, d, e, f;
	a = b = c = 1e12f;
	d = e = f = -1e12f;

	for( DWORD j = 0; j < ngrp; j++ ) {
		D3DXVECTOR3 q;

		if( bMeshT )	D3DXVec3TransformCoord( &q, &GR[j].bsPos, &mT );
		else			q = GR[j].bsPos;

		D3DXVec3TransformCoord( &q, &q, &GR[j].T );

		float r = GR[j].bsRad*GR[j].scale;

		if( (q.x - r) < a )		a = q.x - r;
		if( (q.y - r) < b )		b = q.y - r;
		if( (q.z - r) < c )		c = q.z - r;
		if( (q.x + r) > d )		d = q.x + r;
		if( (q.y + r) > e )		e = q.y + r;
		if( (q.z + r) > f )		f = q.z + r;
	}

	AABB[0] = D3DXVECTOR3( a, b, c );
	AABB[1] = D3DXVECTOR3( d, e, f );

	bsPos = (AABB[0] + AABB[1])*0.5f;
	a -= d;	b -= e;	c -= f;
	bsRad = 0.5f*sqrt( a*a + b*b + c*c );
}

void D3D11Mesh::ResetTransforms() {
	bMeshT = false;
	D3DXMatrixIdentity( &mT_new );
	mT = mT_new;
	for( DWORD j = 0; j < ngrp; j++ ) {
		GR[j].upd_once = false;
		D3DXMatrixIdentity( &GR[j].T_new );
		GR[j].T = GR[j].T_new;
	}
}

int D3D11Mesh::EditGroup( DWORD grp, GROUPEDITSPEC *ges ) {
	if( grp >= ngrp )		return 1;

	D3D11TPLMesh::EditGroup( grp, ges );

	MGROUP &G = GR[grp];

	DWORD j, idx;
	if( ges->flags & GRPEDIT_VTX ) {
		D3D11_MAPPED_SUBRESOURCE SRes0, SRes1;
		memset( &SRes0, 0, sizeof(SRes0) );
		memset( &SRes1, 0, sizeof(SRes1) );
		iCtx->Map( VB, 0, D3D11_MAP_WRITE_DISCARD, 0, &SRes0 );
		iCtx->Map( shadow_VB, 0, D3D11_MAP_WRITE_DISCARD, 0, &SRes1 );

		memcpy( SRes0.pData, _VB, sizeof(MESH_VERTEX)*vbsize );
		memcpy( SRes1.pData, _shadow_VB, 12*vbsize );

		iCtx->Unmap( VB, 0 );
		iCtx->Unmap( shadow_VB, 0 );
	}

	return 0;
}