#include "Scene.h"
#include "vObject.h"
#include "SurfManager.h"
#include "RingManager.h"
#include "CelSphere.h"
#include "CloudManager.h"
#include "ParticleStream.h"

Scene *SC = NULL;

Scene::Scene( D3D11Client *_gc, D3D11Config *_cfg ) {
	GObject = NULL;
	GObjCount = 0;

	Vessel = NULL;
	VesselCount = 0;

	Proxy_new = Proxy = NULL;

	SC = this;

	APRM = NULL;

	PStream = NULL;
	nstream = 0;

	//local light params
	gc->clbkGetRenderParam( RP_MAXLIGHTS, &maxlight );
	bLocalLights = *(bool*)gc->GetConfigParam( CFGPRM_LOCALLIGHT );
	if( !bLocalLights )
		maxlight = 0;

	LL = new D3D11Light [12];
	memset( LL, 0, sizeof(D3D11Light)*12 );
	nLights = 0;

	if( maxlight ) {
		LList = new LIGHTLIST [maxlight];
		memset( LList, 0, sizeof(LIGHTLIST)*maxlight );
	}

	bPause = bPause = false;
}

Scene::~Scene() {
	DeleteGlobalVars();

//delete all planets and stars:
	if( GObjCount ) {
		for( DWORD j = 0; j < GObjCount; j++ )
			if( GObject[j].type == OBJTP_PLANET )
				delete ((vPlanet*)GObject[j].vobj);
			else
				delete ((vStar*)GObject[j].vobj);
		delete [ ] GObject;
	}
	
//delete all vessels:
	if( VesselCount ) {
		for( DWORD j = 0; j < VesselCount; j++ )
			delete ((vVessel*)Vessel[j]);
		delete [ ] Vessel;
	}

//delete all particle streams
	if( PStream ) {
		for( DWORD j = 0; j < nstream; j++ )
			delete PStream[j];
		delete [ ] PStream;
	}

//	delete pSketch;

	delete CB;
	delete CS;

	REL( PBuffer_Surf );
	REL( PBuffer_RTV );
	REL( PBuffer_SRV );
	REL( PBuffer );
	if( cfg->RThread ) {		
		REL( RTarget_RTV );
		REL( RTarget_SRV );
		REL( RTarget );
	}
	REL( BackBuffer_RTV );
	REL( BackBuffer );
	REL( RTarget_DSV );
}

//=================================================
//			Update.
//=================================================

bool Scene::IsVisibleInCamera( D3DXVECTOR3 *pCnt, float radius ) {
//tilemanger, cloudmanager:
	float z = camera_z.x*pCnt->x + camera_z.y*pCnt->y + camera_z.z*pCnt->z;
	if( z < (-radius) ) return false; 
	if( z < 0) z=-z;
	float y = camera_y.x*pCnt->x + camera_y.y*pCnt->y + camera_y.z*pCnt->z;
	if( y < 0) y=-y;
	if( y - (radius*vhf) > (vh*z) ) return false; 
	float x = camera_x.x*pCnt->x + camera_x.y*pCnt->y + camera_x.z*pCnt->z;
	if( x < 0 ) x=-x;
	if( x - (radius*vwf) > (vw*z) ) return false;
	return true;
}

void Scene::UpdateSkyColor() {
	cBackground.x = 0.0f;
	cBackground.y = 0.0f;
	cBackground.z = 0.0f;
	if( Proxy && oapiPlanetHasAtmosphere( Proxy ) ) {
		const ATMCONST *atmp = oapiGetPlanetAtmConstants( Proxy );
		VECTOR3 gpos, ppos;
		oapiGetGlobalPos( Proxy, &gpos );
		ppos = CamPos_new - gpos;
		double cdist = length( ppos );
		if( cdist < atmp->radlimit ) {
			ATMPARAM prm;
			oapiGetPlanetAtmParams( Proxy, cdist, &prm );
			normalise( gpos );
			double coss = dotp( ppos, gpos )/-cdist;
			double intens = min( 1.0, (1.0839*coss + 0.4581) )*sqrt( prm.rho/atmp->rho0);
			// => intensity=0 at sun zenith distance 115°
			//    intensity=1 at sun zenith distance 60°
			if( intens > 0.0 ) {
				cBackground.x = atmp->color0.x*intens;
				cBackground.y = atmp->color0.y*intens;
				cBackground.z = atmp->color0.z*intens;
				
				cBackground.x = cBackground.x > 1.0 ? 1.0 : cBackground.x;
				cBackground.y = cBackground.y > 1.0 ? 1.0 : cBackground.y;
				cBackground.z = cBackground.z > 1.0 ? 1.0 : cBackground.z;
			}
		}		
	}
	dSkyBrt = (cBackground.x + cBackground.y + cBackground.z)/3.0;

	BYTE
		r = (BYTE)(cBackground.x*255.0),
		g = (BYTE)(cBackground.y*255.0),
		b = (BYTE)(cBackground.z*255.0);

	bg_rgba = ((255<<24) | (r<<16) | (g<<8) | (b<<0));

	BgLvl = 0;
	if( bg_rgba ) {
		BgLvl = (bg_rgba & 0xff) + ((bg_rgba >> 8) & 0xff) + ((bg_rgba >> 16) & 0xff);
		BgLvl = min( BgLvl/2, 255 );
	}
}

void Scene::SaveParams() {
	DWORD j;
	MATRIX3 Rot;

	TM->FrameRendered();

	bPause_new = !oapiGetPause();
	//set view matrix
	CamAperture_new = oapiCameraAperture();
	cfg->Aspect = Aspect = (float)cfg->cWidth/(float)cfg->cHeight;
	oapiCameraRotationMatrix( &Rot );
	M3ToDM( &View_new, &Rot );

	//find proxy planet/sun
	oapiCameraGlobalPos( &CamPos_new );
	Proxy_new = oapiCameraProxyGbody();	

	//update vessels, planets, bases and etc.
	for( j = 0; j < GObjCount; j++ )
		if( GObject[j].type == OBJTP_PLANET )
			((vPlanet*)GObject[j].vobj)->Update();
		else
			((vStar*)GObject[j].vobj)->Update();

	for( j = 0; j < VesselCount; j++ )
		Vessel[j]->SaveData();

	CB->SaveParams( 8, BgLvl );

	//current planetarium mode config
	PlanetariumFlag = *(DWORD*)gc->GetConfigParam( CFGPRM_PLANETARIUMFLAG );

	//get debug string
	char *line = oapiDebugString();
	if( line ) {
		strcpy( debug_str, line );
		debug_len = strlen( debug_str );
	}
	else
		debug_len = 0;

	//find focus vessel, cockpit mode and find appropriate near frame distance
	OBJHANDLE hFocus = oapiGetFocusObject();
	near_plane = 30.0f;
	int FocusType;
	if( hFocus && (FocusType = oapiGetObjectType( hFocus )) == OBJTP_VESSEL ) {
		vFocus = NULL;
		for( j = 0; j < VesselCount; j++ )
			if( Vessel[j]->obj == hFocus ) {
				vFocus = Vessel[j];

				float delta = vFocus->CDist_new - vFocus->GetBoundingSphereRad() - 2.0f;
				near_plane = ( delta < 0.0f ? 1.0f : (delta > 300.0f ? 30.0f : delta/10.0 ));
			}
		if( vFocus )	bCockpit = oapiCameraInternal();
		else			bCockpit = false;
		bVC = (bCockpit && oapiCockpitMode() == COCKPIT_VIRTUAL);

		if( bVC ) {
			const VCMFDSPEC *tmp = NULL;
			for( j = 0; j < MAXMFD; j++ ) {
				tmp = NULL;
				texMFD[j] = (Texture*)gc->GetVCMFDSurface( j, &tmp );
				if( tmp ) {
					specMFD[j].ngroup = tmp->ngroup;
					specMFD[j].nmesh = tmp->nmesh;
				}
				else {
					specMFD[j].nmesh = (DWORD)-1;
					texMFD[j] = NULL;
				}
			}
			const VCHUDSPEC *hud = NULL;
			texHUD = (Texture*)gc->GetVCHUDSurface( &hud );
			if( hud ) {
				specHUD.ngroup = hud->ngroup;
				specHUD.nmesh = hud->nmesh;
			}
			else {
				specHUD.nmesh = (DWORD)-1;
				texHUD = NULL;
			}
		}
	}
	else {
		vFocus = NULL;
		bCockpit = bVC = false;
	}

	//virtual cockpit projection matrix
	D3DXMatrixPerspectiveFovLH( &Proj_new, (float)(CamAperture_new*2.0), cfg->Aspect, 0.15f, 1e6 );
	ViewProj_VC_new = View_new*Proj_new;

	//external projection matrix
	D3DXMatrixPerspectiveFovLH( &Proj_new, (float)(CamAperture_new*2.0), cfg->Aspect, near_plane, far_plane );
	ViewProj_new = View_new*Proj_new;

	//update local lights and find maxlight nearest to camera light sources
	int nlight = 1;
	DWORD nEmitter = 0;
	nLights = 0;
	if( bLocalLights && LList ) {
		DWORD i, k;
		for( j = 0; j < VesselCount; j++ ) {
			if( !Vessel[j]->active )	continue;
			DWORD nemitter = Vessel[j]->VSL->LightEmitterCount();
			for( i = 0; i < nemitter; i++ ) {
				const LightEmitter *em = Vessel[j]->VSL->GetLightEmitter( i );
				if( !em->IsActive() || em->GetIntensity() == 0.0 )		continue;
				nEmitter++;
				const VECTOR3 *pos = em->GetPositionRef();
				D3DXVECTOR3 q, p( (float)pos->x, (float)pos->y, (float)pos->z );
				D3DXVec3TransformCoord( &q, &p, &Vessel[j]->mWorld );
				double dist2 = q.x*q.x + q.y*q.y + q.z*q.z;
				for( k = nlight-1; k >= 1; k-- ) {			//1 ???
					if( LList[k].camdist2 < dist2 )	break;
					else if( k < maxlight-1 )	LList[k+1] = LList[k];
					else	nlight++;
				}
				if( k == maxlight-1 )	continue;
				LList[k+1].em = em;
				LList[k+1].vobj = Vessel[j];
				LList[k+1].camdist2 = dist2;
				nlight++;
			}
		}
		for( j = 1; j < nlight; j++ )
			if( j < maxlight ) {
				AddLocalLight( LList[j].em, LList[j].vobj, &LL[j-1] );	//1 ???
				nLights = j;
			}
	}
}

void Scene::AddLocalLight( const LightEmitter *em, vVessel *vobj, D3D11Light *L ) {
	if( !LL )	return;

	switch( em->GetType() ) {
	case LightEmitter::LT_POINT:
		{
			L->Type = D3DLIGHT_POINT;			
			const double *att = ((PointLight*)em)->GetAttenuation();
			L->Att.x = (float)att[0];
			L->Att.y = (float)att[1];
			L->Att.z = (float)att[2];
			
			L->Range = (float)((SpotLight*)em)->GetRange();
		}
		break;
	case LightEmitter::LT_SPOT:
		{
			L->Type = D3DLIGHT_SPOT;
			//range...
			const double *att = ((SpotLight*)em)->GetAttenuation();
			L->Att.x = (float)att[0];
			L->Att.y = (float)att[1];
			L->Att.z = (float)att[2];

			L->Range = (float)((SpotLight*)em)->GetRange();
			L->Falloff = 1.0f;
			L->Theta = (float)((SpotLight*)em)->GetUmbra();
			L->Phi = (float)((SpotLight*)em)->GetPenumbra();

			L->Theta = 1.0f / (cos( L->Theta *0.5f ) - L->Phi);
			L->Phi = cos( L->Phi*0.5f );
		}
		break;
	}

	double intensity = em->GetIntensity();

	const COLOUR4 &col_a = em->GetAmbientColour();
	L->ambient.x = (float)(col_a.r*intensity);
	L->ambient.y = (float)(col_a.g*intensity);
	L->ambient.z = (float)(col_a.b*intensity);

	const COLOUR4 &col_d = em->GetDiffuseColour();
	L->diffuse.x = (float)(col_d.r*intensity);
	L->diffuse.y = (float)(col_d.g*intensity);
	L->diffuse.z = (float)(col_d.b*intensity);

	const COLOUR4 &col_s = em->GetSpecularColour();
	L->specular.x = (float)(col_s.r*intensity);
	L->specular.y = (float)(col_s.g*intensity);
	L->specular.z = (float)(col_s.b*intensity);

	if( L->Type != D3DLIGHT_DIRECTIONAL ) {
		const VECTOR3 pos = em->GetPosition();
		D3DXVECTOR3 p( (float)pos.x, (float)pos.y, (float)pos.z );
		D3DXVec3TransformCoord( &L->PosW, &p, &vobj->mWorld_new );
	}

	if( L->Type != D3DLIGHT_POINT ) {
		const VECTOR3 dir = em->GetDirection();
		D3DXVECTOR3 d( (float)dir.x, (float)dir.y, (float)dir.z );
		D3DXVec3TransformCoord( &L->DirW, &d, &vobj->mWorld_new );
		D3DXVec3Normalize( &L->DirW, &L->DirW );
	}
}

void Scene::Update() {
	DWORD j;

	View = View_new;
	Proj = Proj_new;
	ViewProj = ViewProj_new;			//VP matrix for exterior views
	ViewProj_VC = ViewProj_VC_new;		//VP matrix for VC
	CamPos = CamPos_new;
	CamAperture = CamAperture_new;

	vh   = tan(CamAperture);
	vw   = vh*cfg->Aspect;
	vhf  = (1.0f/cos(CamAperture));
	vwf  = vhf*cfg->Aspect;
	
	camera_x = D3DXVECTOR3(View._11, View._21, View._31);
	camera_y = D3DXVECTOR3(View._12, View._22, View._32);
	camera_z = D3DXVECTOR3(View._13, View._23, View._33);

	Proxy = Proxy_new;
	UpdateSkyColor();					//updates cBackground and skybrt using atm params of the nearest planet

	for( j = 0; j < VesselCount; j++ )
		Vessel[j]->Update();

	if( bPause ) {
		for( j = 0; j < nstream; j++ )
			PStream[j]->Update();
	}
	bPause = bPause_new;
}

bool Scene::IsVisiblePoint( D3DXVECTOR3 *vec ) {
	return (D3DXVec3Dot( vec, &camera_z ) > 0.0f ? false : true);
}

//=================================================
//			Rendering.
//=================================================

void Scene::Render_0() {
	DWORD j;

	int distcomp( const void *arg1, const void *arg2 );	//compares object by their distance from camera

//	APRM = NULL;
	pSketch = new D3D11Pad( NULL );
	D3DXCOLOR ClearColor( cBackground.x, cBackground.y, cBackground.z, 0.0f );
	iCtx->OMSetRenderTargets( 1, &RTarget_RTV, NULL );
	iCtx->ClearRenderTargetView( RTarget_RTV, ClearColor );

	iCtx->OMSetRenderTargets( 1, &RTarget_RTV, RTarget_DSV );
//	iCtx->ClearRenderTargetView( RTarget_RTV, ClearColor );
	iCtx->ClearDepthStencilView( RTarget_DSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
	iCtx->OMSetDepthStencilState( DSS_NoDepth_NoStencil, 0 );

	D3D11_VIEWPORT VP;
    VP.Width = (FLOAT)cfg->cWidth;
    VP.Height = (FLOAT)cfg->cHeight;
    VP.MinDepth = 0.0f;
    VP.MaxDepth = 1.0f;
    VP.TopLeftX = 0;
    VP.TopLeftY = 0;
	iCtx->RSSetViewports( 1, &VP );

	//================================================
	//						Stars
	//================================================
	//background
	CB->Render();

	//stars, constellations...
	CS->RenderCelestialSphere( GetVP(), (float)dSkyBrt, &cBackground );

	//get a sketchpad for marker drawings (if any);
	pSketch->SetFont( LabelFont );
	pSketch->SetTextAlign( oapi::Sketchpad::CENTER, oapi::Sketchpad::BOTTOM );

	//================================================
	//				Planets and stars(Sun)
	//================================================
	//fill planet list with planets if they are close enough to camera:
	UINT np = 0;
	for( j = 0; j < GObjCount; j++ ) {
		if( GObject[j].vobj->GetAppRadius() < 0.01 && GObject[j].type != OBJTP_STAR )
			continue;
		PLIST[np].cdist = GObject[j].vobj->GetCDist();
		PLIST[np].vo = GObject[j].vobj;
		PLIST[np].type = GObject[j].type;
		np++;
	}

	//sort list...
	qsort( (void*)PLIST, np, sizeof(CELOBJ), distcomp );

	//render distant dots first
	vObject::InitRenderDot();
	for( j = 0; j < np; j++ )
		if( !PLIST[j].vo->active && PLIST[j].type != OBJTP_STAR )	PLIST[j].vo->RenderDot();

	//render nearest planets and planet markers
	for( j = 0; j < np; j++ ) {
		bool active = PLIST[j].vo->active;

		if( active || PLIST[j].type == OBJTP_STAR )	PLIST[j].vo->Render();

		if( PlanetariumFlag & PLN_ENABLE ) {		//planetarium mode
			if( PlanetariumFlag & PLN_CMARK ) {		//planet markers
				pSketch->SetTextColor( LabelCol[0] );
				pSketch->SetPen( LabelPen[0] );
				RenderObjectMarker( &PLIST[j].vo->GPos, PLIST[j].vo->name, NULL, 0, cfg->cHeight/80 );
			}
			if( active && (PlanetariumFlag & PLN_SURFMARK) && (PLIST[j].type == OBJTP_PLANET) ) {
				if( PlanetariumFlag & PLN_LMARK ) {		//surface labels
					const oapi::GraphicsClient::LABELLIST *list;

					double apprad = PLIST[j].vo->rad / (PLIST[j].cdist*GetCamAperture());
					DWORD nlist = gc->GetSurfaceMarkers( PLIST[j].vo->obj, &list );
					VECTOR3 cpos = tmul( PLIST[j].vo->mROT, CamPos-PLIST[j].vo->GPos );

					for( DWORD i = 0; i < nlist; i++ ) {
						if( list[i].active && apprad*list[i].distfac > LABEL_DISTLIMIT ) {
							int size = (int)(cfg->cHeight/80.0*list[i].size + 0.5 );
							int col = list[i].colour;

							pSketch->SetTextColor( LabelCol[col] );
							pSketch->SetPen( LabelPen[col] );

							const oapi::GraphicsClient::LABELSPEC *lspec = list[i].list;
							VECTOR3 sp;
							for( int ii = 0; ii < list[i].length; ii++ )
								if( dotp( lspec[ii].pos, cpos - lspec[ii].pos ) >= 0.0 ) {
									sp = mul( PLIST[j].vo->mROT, lspec[ii].pos ) + PLIST[j].vo->GPos;
									RenderObjectMarker( &sp, lspec[ii].label[0], lspec[ii].label[1], list[i].shape, size );
								}
						}
					}
				}

				if( PlanetariumFlag & PLN_BMARK ) {
					vPlanet *pln = (vPlanet*)PLIST[j].vo;

					DWORD nbase = pln->nbase;
					int size = (int)(cfg->cHeight/80.0);

					pSketch->SetTextColor( LabelCol[0] );
					pSketch->SetPen( LabelPen[0] );

					for( DWORD i = 0; i < nbase; i++ ) {
						vBase *Base = pln->Base[i];

						VECTOR3 cpos, bpos;
						cpos = tmul( pln->mROT, CamPos - pln->GPos );
						bpos = tmul( pln->mROT, Base->GPos - pln->GPos );

						double apprad = 8000e3 / (length( cpos - bpos )*tan( GetCamAperture() ));

						if( dotp( bpos, cpos - bpos ) >= 0.0 && apprad > LABEL_DISTLIMIT ) {
							VECTOR3 sp = mul( pln->mROT, bpos ) + pln->GPos;
							RenderObjectMarker( &sp, Base->name, NULL, 0, size );
						}
					}
				}
			}
		}
	}
}

int distcomp( const void *arg1, const void *arg2 ) {	//to do
	double d1 = ((CELOBJ*)arg1)->cdist;
	double d2 = ((CELOBJ*)arg2)->cdist;
	return (d1 > d2 ? -1 : d1 < d2 ? 1 : 0);
}

void Scene::RenderVesselShadows( vPlanet *PLN ) {
	iCtx->OMSetRenderTargets( 1, &RTarget_RTV, RTarget_DSV );

	//vessel shadows
	D3D11Mesh::InitRenderShadows();
	for( DWORD j = 0; j < VesselCount; j++ )
		if( Vessel[j]->active )	Vessel[j]->RenderShadows( PLN );

	//shadows of diffuse streams
	D3D11ParticleStream::InitRenderShadow();
	for( DWORD j = 0; j < nstream; j++ )
		PStream[j]->RenderShadow();
	iCtx->GSSetShader( NULL, NULL, NULL );
}

void Scene::Render_1() {
	DWORD j;

	//==========================================================================================================
	//		Vessels: Shadows -> Meshes -> Beacons -> Exhaust -> Particle Streams -> Markers
	//==========================================================================================================

	//render vessel dots
	vObject::InitRenderDot();
	for( j = 0; j < VesselCount; j++ )
		if( !Vessel[j]->active && Vessel[j]->CDist < 400000.0 )		Vessel[j]->RenderDot();

	iCtx->OMSetRenderTargets( 1, &RTarget_RTV, RTarget_DSV );
	//render bounding boxes if requested
	if( bBBRender )
		for( j = 0; j < VesselCount; j++ )
			if( Vessel[j]->active )
				Vessel[j]->RenderBoundingBox();

	//opaque:	
	//D3D11Mesh::InitRender();
	vVessel::InitRender();
	for( j = 0; j < VesselCount; j++ ) {
		if( vFocus && Vessel[j] == vFocus ) {
			//focus vessel
			if( !bCockpit ) {
				if( vFocus->active )					vFocus->Render();
			}
			else 
				if( !bVC )								vFocus->RenderCockpit();			
		}
		else 
			if( Vessel[j]->active )						Vessel[j]->Render();
	}
	vVessel::RenderCompleted();
	
	//exhaust + reentry
	vVessel::InitRenderExhaust();	
	for( j = 0; j < VesselCount; j++ ) {
		if( !Vessel[j]->active )	continue;
		Vessel[j]->RenderExhaust();

		if( Vessel[j] != vFocus )	Vessel[j]->RenderReentry();
		else if( !bCockpit )		vFocus->RenderReentry();
	}

	//beacons
	vVessel::InitRenderBeacons();
	for( j = 0; j < VesselCount; j++ ) {
		if( !Vessel[j]->active )	continue;
		Vessel[j]->RenderBeacons();
	}

	//particle streams
	D3D11ParticleStream::InitRender();		//distance !
	for( j = 0; j < nstream; j++ )
		PStream[j]->Render();
	iCtx->GSSetShader( NULL, NULL, NULL );

	//VC
	if( bCockpit && bVC ) {
		iCtx->ClearDepthStencilView( RTarget_DSV, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0 );
		vFocus->RenderVC();
	}

	//markers
	for( j = 0; j < VesselCount; j++ )
		if( Vessel[j]->CDist < 400000.0 && (PlanetariumFlag & (PLN_ENABLE | PLN_VMARK)) == (PLN_ENABLE | PLN_VMARK) )
			RenderObjectMarker( &Vessel[j]->GPos, Vessel[j]->name, NULL, 0, cfg->cHeight/80 );
	
	//================================================
	//				Debug string
	//================================================
	if( debug_len ) {
		pSketch->SetFont( DebugFont );
		pSketch->SetTextColor( 0xFFFFFFFF );
		pSketch->SetTextAlign( oapi::Sketchpad::LEFT, oapi::Sketchpad::BOTTOM );
		pSketch->SetPen( NullPen );
		pSketch->SetBrush( DebugBrush );

		DWORD
			width = pSketch->GetTextWidth( debug_str, debug_len ),
			height = 20;
				
		pSketch->Rectangle( -1, cfg->cHeight - height, width + 4, cfg->cHeight );
		pSketch->Text( 2, cfg->cHeight - 2, debug_str, debug_len );
	}

	pSketch->SetFont( NULL );
	pSketch->SetPen( NULL );

	delete pSketch;
}

void Scene::RenderOverlay( SURFHANDLE *surf, MESHHANDLE Mesh, MATRIX3 *T, bool transparent ) {
	D3DXCOLOR ClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
	
	iCtx->OMSetDepthStencilState( DSS_NoDepth_NoStencil, 0 );
	if( cfg->RThread ) {
		iCtx->OMSetRenderTargets( 1, &BackBuffer_RTV, NULL );
		OV->Render2DOverlay( surf, Mesh, T, transparent );
		iCtx->ClearRenderTargetView( PBuffer_RTV, ClearColor );
		iCtx->OMSetRenderTargets( 1, &RTarget_RTV, RTarget_DSV );	//PB => RT
	}
	else
		OV->Render2DOverlay( surf, Mesh, T, transparent );

	BBDrawCount = 0;
}

void Scene::RenderObjectMarker( VECTOR3 *dir, char *label0, char *label1, int mode, int scale ) {
	VECTOR3 tmp = *dir - CamPos;
	normalise( tmp );
	D3DXVECTOR3 dirH, dirW( (float)-tmp.x, (float)-tmp.y, (float)-tmp.z );

	if( !SC->IsVisiblePoint( &dirW ) )
		return;

	UINT x, y;
	D3DXVec3TransformCoord( &dirH, &dirW, SC->GetVP() );
	if( dirH.x >= -1.0f && dirH.x <= 1.0f && 
		dirH.y >= -1.0f && dirH.y <= 1.0f ) {

		if( _hypot( dirH.x, dirH.y ) < 1e-6 )
			x = cfg->cWidth/2, y = cfg->cHeight/2;
		else {
			x = (int)(cfg->cWidth*0.5*(1.0f + dirH.x) );
			y = (int)(cfg->cHeight*0.5*(1.0f - dirH.y) );
		}

		switch( mode ) {
		case 0:		//box
			pSketch->Rectangle( x-scale, y-scale, x+scale+1, y+scale+1 );
			break;
		case 1:		//circle
			pSketch->Ellipse( x-scale, y-scale, x+scale+1, y+scale+1 );
			break;
		case 2:		//diamond
			pSketch->MoveTo( x, y-scale );
			pSketch->LineTo( x+scale, y );
			pSketch->LineTo( x, y+scale );
			pSketch->LineTo( x-scale, y );
			pSketch->LineTo( x, y-scale );
			break;
		case 3:		//delta
			{
				int scl1 = (int)(scale*1.1547);
				pSketch->MoveTo( x, y-scale );
				pSketch->LineTo( x+scl1, y+scale );
				pSketch->LineTo( x-scl1, y+scale );
				pSketch->LineTo( x, y-scale );
			}
			break;
		case 4:		//nabla
			{
				int scl1 = (int)(scale*1.1547);
				pSketch->MoveTo( x, y+scale );
				pSketch->LineTo( x+scl1, y-scale );
				pSketch->LineTo( x-scl1, y-scale );
				pSketch->LineTo( x, y+scale );
			}
			break;
		case 5:		//cross
			{
				int scl1 = scale/4;
				pSketch->MoveTo( x, y-scale );
				pSketch->LineTo( x, y-scl1 );
				pSketch->MoveTo( x, y+scale );
				pSketch->LineTo( x, y+scl1 );
				pSketch->MoveTo( x-scale, y );
				pSketch->LineTo( x-scl1, y );
				pSketch->MoveTo( x+scale, y );
				pSketch->LineTo( x+scl1, y );
			}
			break;
		case 6:
			{
				int scl1 = scale/4;
				pSketch->MoveTo( x-scale, y-scale );
				pSketch->LineTo( x-scl1, y-scl1 );
				pSketch->MoveTo( x-scale, y+scale );
				pSketch->LineTo( x-scl1, y+scl1 );
				pSketch->MoveTo( x+scale, y-scale );
				pSketch->LineTo( x+scl1, y-scl1 );
				pSketch->MoveTo( x+scale, y+scale );
				pSketch->LineTo( x+scl1, y+scl1 );
			}
			break;
		}

		if( label0 )
			pSketch->Text( x, y-scale, label0, strlen(label0) );

		if( label1 )
			pSketch->Text( x, y+scale+15, label1, strlen(label1) );	//- labelsize[0]
	}
}

//===========================================================
//					INIT
//===========================================================
#pragma region init
void Scene::Init3D() {
//create swap chain with chosen AA setting:	
	DXGI_RATIONAL RR;
	RR.Numerator = 60;
	RR.Denominator = 1;

	DXGI_SWAP_CHAIN_DESC SWDesc;
	ZeroMemory( &SWDesc, sizeof( SWDesc ) );
	SWDesc.BufferCount = 1;
	SWDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	SWDesc.BufferDesc.Width = cfg->cWidth;
	SWDesc.BufferDesc.Height = cfg->cHeight;
	SWDesc.BufferDesc.RefreshRate.Numerator = 60;
	SWDesc.BufferDesc.RefreshRate.Denominator = 1;
	SWDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
	SWDesc.Flags = 0;
#ifdef _DEBUG
	SWDesc.Flags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
	SWDesc.OutputWindow = gc->hWindow;
	SWDesc.SampleDesc = cfg->CurrentAAMode;
	SWDesc.Windowed = TRUE;
		
	HR( Factory->CreateSwapChain( Dev, &SWDesc, &SwapChain ) );

//back buffer and depth/stencil buffer:
	HR( SwapChain->GetBuffer( 0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer ) );

	D3D11_RENDER_TARGET_VIEW_DESC rtdesc;
	ZeroMemory( &rtdesc, sizeof(rtdesc) );
	rtdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	rtdesc.ViewDimension = cfg->CurrentAAMode.Count != 1 ? D3D11_RTV_DIMENSION_TEXTURE2DMS : D3D11_RTV_DIMENSION_TEXTURE2D;
	rtdesc.Texture2D.MipSlice = 0;
	HR( Dev->CreateRenderTargetView( BackBuffer, &rtdesc, &BackBuffer_RTV ) );

	D3D11_TEXTURE2D_DESC DSDesc;
	ZeroMemory( &DSDesc, sizeof( D3D11_TEXTURE2D_DESC ) );
	DSDesc.Width = cfg->cWidth;
	DSDesc.Height = cfg->cHeight;
	DSDesc.MipLevels = 1;
	DSDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
	DSDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
	DSDesc.SampleDesc = cfg->CurrentAAMode;
	DSDesc.Usage = D3D11_USAGE_DEFAULT;
	DSDesc.CPUAccessFlags = 0;
	DSDesc.ArraySize = 1;
	DSDesc.MiscFlags = 0;
	
	ID3D11Texture2D *DepthStencil;
	HR( Dev->CreateTexture2D( &DSDesc, NULL, &DepthStencil ) );

	D3D11_DEPTH_STENCIL_VIEW_DESC DSVDesc;
	ZeroMemory( &DSVDesc, sizeof( DSVDesc ) );
	DSVDesc.Format = DSDesc.Format;
	DSVDesc.ViewDimension = cfg->CurrentAAMode.Count != 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
	DSVDesc.Texture2D.MipSlice = 0;

	HR( Dev->CreateDepthStencilView( DepthStencil, &DSVDesc, &RTarget_DSV ) );

//set correct viewport
	D3D11_VIEWPORT VP;
    VP.Width = (float)cfg->cWidth;
    VP.Height = (float)cfg->cHeight;
    VP.MinDepth = 0.0f;
    VP.MaxDepth = 1.0f;
    VP.TopLeftX = 0;
    VP.TopLeftY = 0;

	iCtx->RSSetViewports( 1, &VP );

	//==========================
	//GDI-compatible buffer:
	//==========================
	D3D11_TEXTURE2D_DESC tdesc;
	ZeroMemory( &tdesc, sizeof(tdesc) );
	tdesc.Width = cfg->cWidth;
	tdesc.Height = cfg->cHeight;
	tdesc.MipLevels = 1;
	tdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
	tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	tdesc.SampleDesc.Count = 1;
	tdesc.SampleDesc.Quality = 0;
	tdesc.Usage = D3D11_USAGE_DEFAULT;
	tdesc.CPUAccessFlags = 0;
	tdesc.ArraySize = 1;
	tdesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
		
	HR( Dev->CreateTexture2D( &tdesc, NULL, &PBuffer ) );

	//SRV:
	D3D11_SHADER_RESOURCE_VIEW_DESC sdesc;
	ZeroMemory( &sdesc, sizeof(sdesc));
	sdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	sdesc.Texture2D.MipLevels = 1;
	sdesc.Texture2D.MostDetailedMip = 0;
	sdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	HR( Dev->CreateShaderResourceView( PBuffer, &sdesc, &PBuffer_SRV ) );
	
	//RTV:
	ZeroMemory( &rtdesc, sizeof(rtdesc) );
	rtdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
	rtdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
	rtdesc.Texture2D.MipSlice = 0;
	
	HR( Dev->CreateRenderTargetView( PBuffer, &rtdesc, &PBuffer_RTV ) );

//additional buffers (if any).
	if( cfg->RThread ) {
		//==========================
		//GDI-compatible buffer:
		//==========================
/*
		D3D11_TEXTURE2D_DESC tdesc;
		ZeroMemory( &tdesc, sizeof(tdesc) );
		tdesc.Width = cfg->cWidth;
		tdesc.Height = cfg->cHeight;
		tdesc.MipLevels = 1;
		tdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
		tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		tdesc.SampleDesc.Count = 1;
		tdesc.SampleDesc.Quality = 0;
		tdesc.Usage = D3D11_USAGE_DEFAULT;
		tdesc.CPUAccessFlags = 0;
		tdesc.ArraySize = 1;
		tdesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
		
		HR( Dev->CreateTexture2D( &tdesc, NULL, &PBuffer ) );

		//SRV:
		D3D11_SHADER_RESOURCE_VIEW_DESC sdesc;
		ZeroMemory( &sdesc, sizeof(sdesc));
		sdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		sdesc.Texture2D.MipLevels = 1;
		sdesc.Texture2D.MostDetailedMip = 0;
		sdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		HR( Dev->CreateShaderResourceView( PBuffer, &sdesc, &PBuffer_SRV ) );
	
		//RTV:
		ZeroMemory( &rtdesc, sizeof(rtdesc) );
		rtdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		rtdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
		rtdesc.Texture2D.MipSlice = 0;
	
		HR( Dev->CreateRenderTargetView( PBuffer, &rtdesc, &PBuffer_RTV ) );*/
		//==========================
		//Render target:
		//==========================
	//	D3D11_TEXTURE2D_DESC tdesc;
		ZeroMemory( &tdesc, sizeof(tdesc) );
		tdesc.Width = cfg->cWidth;
		tdesc.Height = cfg->cHeight;
		tdesc.MipLevels = 1;
		tdesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
		tdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		tdesc.SampleDesc.Count = 1;
		tdesc.SampleDesc.Quality = 0;
		tdesc.Usage = D3D11_USAGE_DEFAULT;
		tdesc.CPUAccessFlags = 0;
		tdesc.ArraySize = 1;
		tdesc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;

		HR( Dev->CreateTexture2D( &tdesc, NULL, &RTarget ) );

		//SRV:
	//	D3D11_SHADER_RESOURCE_VIEW_DESC sdesc;
		ZeroMemory( &sdesc, sizeof(sdesc));
		sdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		sdesc.Texture2D.MipLevels = 1;
		sdesc.Texture2D.MostDetailedMip = 0;
		sdesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
		HR( Dev->CreateShaderResourceView( RTarget, &sdesc, &RTarget_SRV ) );

		//RTV:
		ZeroMemory( &rtdesc, sizeof(rtdesc) );
		rtdesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
		rtdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
		rtdesc.Texture2D.MipSlice = 0;
		HR( Dev->CreateRenderTargetView( RTarget, &rtdesc, &RTarget_RTV ) );
	}
	else {
		//no additional buffers needed:
		RTarget_RTV = BackBuffer_RTV;
		RTarget_SRV = NULL;
		RTarget = BackBuffer;
	}
	HR( PBuffer->QueryInterface( __uuidof(IDXGISurface1), reinterpret_cast<void**>(&PBuffer_Surf) ) );
//misc:
	InitGlobalVars();	//global constant buffers, states etc.

//check driver support of command lists and deffered rendering: (not used)
/*	D3D11_FEATURE Feature = D3D11_FEATURE_THREADING;
	D3D11_FEATURE_DATA_THREADING Result;
	ZeroMemory( &Feature, sizeof( Feature ) );
	Dev->CheckFeatureSupport( Feature, &Result, sizeof(D3D11_FEATURE_DATA_THREADING) );
	if( cfg->RThread ) {
		D3D11_FEATURE MT = D3D11_FEATURE_THREADING;
		D3D11_FEATURE_DATA_THREADING Result;
		ZeroMemory( &Result, sizeof(Result) );
		Dev->CheckFeatureSupport( MT, &Result, sizeof(Result) );
		if( Result.DriverCommandLists == 1 && Result.DriverConcurrentCreates == 1 ) {
		creating deferred context if supported
			HR( Dev->CreateDeferredContext( 0, &dCtx ) );
			HR( Dev->CreateDeferredContext( 0, &pCtx ) );
			HR( Dev->CreateDeferredContext( 0, &pCtx ) );
	
		}
		else
			cfg->RThread = false;
	}
*/
//global init
	
}

void Scene::InitStatics() {
	LabelFont = oapiCreateFont( 15, false, "Arial", FONT_NORMAL, 0 );
	DebugFont = oapiCreateFont( 15, true, "Consolas", FONT_NORMAL, 0 );
	NullPen = oapiCreatePen( 0, 1, 0xFFFFFF );
	DebugBrush = oapiCreateBrush( 0xB0000000 );

	LabelCol[0] = 0x00FFFF;
	LabelCol[1] = 0xFFFF00;
	LabelCol[2] = 0x4040FF;
	LabelCol[3] = 0xFF00FF;
	LabelCol[4] = 0x40FF40;
	LabelCol[5] = 0xFF8080;

	for( DWORD j = 0; j < 6; j++ )
		LabelPen[j] = oapiCreatePen( 1, 1, LabelCol[j] );

	pSketch = new D3D11Pad( NULL, true );

	D3D11Effect::InitGlobal( Dev, iCtx );
	TileManager::GlobalInit( cfg, Dev, iCtx );
	HazeManager::GlobalInit( cfg );
	CloudManager::InitCloudsEffect();
	RingManager::InitRingEffect();
	CB = new CelBackground();
	CS = new CelSphere();

	near_plane = 1.0f;
	far_plane = 1e6;

	D3D11Pad::GlobalInit();
	D3D11Text::GlobalInit();

	D3D11Mesh::GlobalInit();
	vStar::GlobalInit();
	vVessel::GlobalInit();
	D3D11ParticleStream::GlobalInit();
}

void Scene::InitGlobalVars() {
//constant buffers:
	D3D11_BUFFER_DESC desc;
	ZeroMemory( &desc, sizeof(desc) );
	desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
	desc.ByteWidth = 64;
	desc.CPUAccessFlags = 0;
	desc.MiscFlags = 0;
	desc.StructureByteStride = 0;
	desc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateBuffer( &desc, nullptr, &cb_D3DXMATRIX_x1 ) );

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

	HR( Dev->CreateBuffer( &desc, nullptr, &cb_D3DXMATRIX_x2 ) );

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

	HR( Dev->CreateBuffer( &desc, nullptr, &cb_D3DXVECTOR4 ) );

//blend states:
	D3D11_BLEND_DESC bdesc;
	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.AlphaToCoverageEnable = false;
	bdesc.IndependentBlendEnable = false;
	bdesc.RenderTarget[0].BlendEnable = false;
	bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;// D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;
	HR( Dev->CreateBlendState( &bdesc, &BS_NoBlend ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.AlphaToCoverageEnable = false;
	bdesc.IndependentBlendEnable = false;
	bdesc.RenderTarget[0].BlendEnable = true;
	bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
	bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
	bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].RenderTargetWriteMask = /*D3D11_COLOR_WRITE_ENABLE_ALL;//*/ D3D11_COLOR_WRITE_ENABLE_RED | D3D11_COLOR_WRITE_ENABLE_GREEN | D3D11_COLOR_WRITE_ENABLE_BLUE;//D3D11_COLOR_WRITE_ENABLE_ALL;
	HR( Dev->CreateBlendState( &bdesc, &BS_SrcAlpha ) );

	ZeroMemory( &bdesc, sizeof(bdesc) );
	bdesc.AlphaToCoverageEnable = false;
	bdesc.IndependentBlendEnable = false;
	bdesc.RenderTarget[0].BlendEnable = true;
	bdesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_COLOR;
	bdesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
	bdesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_COLOR;
	bdesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
	bdesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
	bdesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
	HR( Dev->CreateBlendState( &bdesc, &BS_InvSrcAlpha ) );

//rasterizer states:
	D3D11_RASTERIZER_DESC rdesc;
	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_BACK;
	rdesc.FillMode = D3D11_FILL_SOLID;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullBack_Solid ) );

	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_BACK;
	rdesc.FillMode = D3D11_FILL_WIREFRAME;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullBack_Wire ) );

	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_FRONT;
	rdesc.FillMode = D3D11_FILL_SOLID;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullFront_Solid ) );

	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_FRONT;
	rdesc.FillMode = D3D11_FILL_SOLID;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullFront_Wire ) );

	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_NONE;
	rdesc.FillMode = D3D11_FILL_SOLID;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullNone_Solid ) );

	ZeroMemory( &rdesc, sizeof( rdesc ) );
	rdesc.CullMode = D3D11_CULL_NONE;
	rdesc.FillMode = D3D11_FILL_WIREFRAME;
	rdesc.FrontCounterClockwise = FALSE;
	rdesc.MultisampleEnable = cfg->CurrentAAMode.Count != 1;
	HR( Dev->CreateRasterizerState( &rdesc, &RS_CullNone_Wire ) );

//shader version:
	D3D_FEATURE_LEVEL feature = Dev->GetFeatureLevel();
	switch( feature ) {
	case D3D_FEATURE_LEVEL_9_1:
		strcpy( vs_ver, "vs_4_0_level_9_1" );
		strcpy( gs_ver, "gs_4_0_level_9_1" );
		strcpy( ps_ver, "ps_4_0_level_9_1" );
		break;
	case D3D_FEATURE_LEVEL_9_2:
		strcpy( vs_ver, "vs_4_0_level_9_1" );
		strcpy( gs_ver, "gs_4_0_level_9_1" );
		strcpy( ps_ver, "ps_4_0_level_9_1" );
		break;
	case D3D_FEATURE_LEVEL_9_3:
		strcpy( vs_ver, "vs_4_0_level_9_3" );
		strcpy( gs_ver, "gs_4_0_level_9_3" );
		strcpy( ps_ver, "ps_4_0_level_9_3" );
		break;
	case D3D_FEATURE_LEVEL_10_0:
		strcpy( vs_ver, "vs_4_0" );
		strcpy( gs_ver, "gs_4_0" );
		strcpy( ps_ver, "ps_4_0" );
		break;
	case D3D_FEATURE_LEVEL_10_1:
		strcpy( vs_ver, "vs_4_0" );
		strcpy( gs_ver, "gs_4_0" );
		strcpy( ps_ver, "ps_4_0" );
		break;
	case D3D_FEATURE_LEVEL_11_0:
		strcpy( vs_ver, "vs_5_0" );
		strcpy( gs_ver, "gs_5_0" );
		strcpy( ps_ver, "ps_5_0" );
		break;
	}

	ShaderCompileFlag = 
		D3D10_SHADER_ENABLE_STRICTNESS | D3D10_SHADER_OPTIMIZATION_LEVEL3;

//sampler states:
	D3D11_SAMPLER_DESC sdesc;
	ZeroMemory( &sdesc, sizeof( sdesc ) );
	sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	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 = 4;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_Linear_Wrap ) );

	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 = 4;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_Linear_Clamp ) );

	ZeroMemory( &sdesc, sizeof( sdesc ) );
	sdesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT ;
	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 = 4;
	sdesc.MipLODBias = 0;
	sdesc.MinLOD = 0;
	sdesc.MaxLOD = D3D11_FLOAT32_MAX;
	HR( Dev->CreateSamplerState( &sdesc, &SS_Point_Wrap ) );

//texture for pixel/dot blits:
	D3D11_TEXTURE2D_DESC tdesc;
	ZeroMemory( &tdesc, sizeof(tdesc) );
	tdesc.ArraySize = 1;
	tdesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
	tdesc.CPUAccessFlags = 0;
	tdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	tdesc.Height = 2;
	tdesc.Width = 2;
	tdesc.MipLevels = 1;
	tdesc.MiscFlags = 0;
	tdesc.SampleDesc.Count = 1;
	tdesc.Usage = D3D11_USAGE_DEFAULT;

	HR( Dev->CreateTexture2D( &tdesc, NULL, &Tex_2x2 ) );

	D3D11_RENDER_TARGET_VIEW_DESC rtvdesc;
	ZeroMemory( &rtvdesc, sizeof( rtvdesc ) );
	rtvdesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
	rtvdesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
	rtvdesc.Texture2D.MipSlice = 0;

	HR( Dev->CreateRenderTargetView( Tex_2x2, &rtvdesc, &RTV_Tex_2x2 ) );

//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_ZERO;
	dsdesc.StencilEnable = false;

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

	ZeroMemory( &dsdesc, sizeof(dsdesc) );
	dsdesc.DepthEnable = true;
	dsdesc.DepthFunc = D3D11_COMPARISON_LESS_EQUAL;
	dsdesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO;
	dsdesc.StencilEnable = false;

	HR( Dev->CreateDepthStencilState( &dsdesc, &DSS_TestDepthOnly_NoStencil ) );
}

void Scene::DeleteGlobalVars() {
	REL( SS_Point_Wrap );
	REL( SS_Linear_Wrap );

	REL( cb_D3DXMATRIX_x1 );
	REL( cb_D3DXMATRIX_x2 );
	REL( cb_D3DXVECTOR4 );

	REL( RS_CullBack_Solid );
	REL( RS_CullBack_Wire );
	REL( RS_CullFront_Solid );
	REL( RS_CullFront_Wire );
	REL( RS_CullNone_Solid );
	REL( RS_CullNone_Wire );

	REL( BS_SrcAlpha );
	REL( BS_NoBlend );

	REL( Tex_2x2 );
	REL( RTV_Tex_2x2 );

	REL( SwapChain );
}

//=================================================
//			Object creation.
//=================================================

void Scene::InitObjects() {
	DWORD j, starcount = 0, i = 0;
	OBJHANDLE obj;

	//create list of planets and stars:
	GObjCount = oapiGetGbodyCount();
	GObject = new GBODY [GObjCount];
	for( j = 0; j < GObjCount; j++ ) {
		obj = oapiGetGbodyByIndex( j );
		if( oapiGetObjectType( obj ) == OBJTP_PLANET ) {
			GObject[j].type = OBJTP_PLANET;
			GObject[j].vobj = new vPlanet( obj );
		}
		else {
			GObject[j].type = OBJTP_STAR;
			GObject[j].vobj = new vStar( obj );
		}
	}

	VesselCount = oapiGetVesselCount();
	Vessel = new vVessel *[VesselCount];
	for( j = 0; j < VesselCount; j++ ) {
		obj = oapiGetVesselByIndex( j );
		Vessel[j] = new vVessel( obj );
		gc->RegisterVisObject( obj, Vessel[j] );
	}

	D3DXMatrixIdentity( &ViewProj );
	CamPos.x = CamPos.y = CamPos.z = 0.0;
	//all bases should be created in their planets.
}

#pragma endregion

void Scene::AddParticleStream( D3D11ParticleStream *ps ) {
	D3D11ParticleStream **tmp = new D3D11ParticleStream *[nstream+1];
	if( PStream ) {
		memcpy( tmp, PStream, sizeof(D3D11ParticleStream*)*nstream );
		delete [ ] PStream;
	}
	PStream = tmp;
	PStream[nstream] = ps;
	nstream++;
}

//=================================================
//		Adds a new or deletes an existing vessel.
//=================================================

void Scene::NewVessel( OBJHANDLE obj ) {

	vVessel **tmp = new vVessel *[VesselCount+1];
	if( Vessel ) {
		memcpy( tmp, Vessel, sizeof(vVessel*)*VesselCount );
		delete [ ] Vessel;
	}
	Vessel = tmp;
	Vessel[VesselCount] = new vVessel( obj );
	gc->RegisterVisObject( obj, Vessel[VesselCount] );
	VesselCount++;
}

void Scene::DeleteVessel( OBJHANDLE obj ) {

	vVessel **tmp = new vVessel *[VesselCount-1];	
	DWORD j;
	int idx = -1;
	for( j = 0; j < VesselCount; j++ )
		if( Vessel[j]->obj == obj )
			idx = j;

	if( idx == -1 )		return;

	delete Vessel[idx];
	Vessel[idx] = Vessel[VesselCount-1];
	VesselCount--;
	memcpy( tmp, Vessel, sizeof(vVessel*)*VesselCount );
	delete [ ] Vessel;
	Vessel = tmp;
}

void Scene::Exit3D() {
	D3D11Mesh::GlobalExit();
	vStar::GlobalExit();
	vVessel::GlobalExit();
	TileManager::GlobalExit();
	HazeManager::GlobalExit();
	D3D11Pad::GlobalExit();
	D3D11Text::GlobalExit();
	D3D11ParticleStream::GlobalExit();
}

vVessel *Scene::GetVessel( OBJHANDLE obj ) {
	for( DWORD j = 0; j < VesselCount; j++ )
		if( Vessel[j]->obj == obj )
			return Vessel[j];
	return NULL;	//not found
}

vPlanet *Scene::GetPlanet( OBJHANDLE obj ) {
	for( DWORD j = 0; j < GObjCount; j++ )
		if( GObject[j].vobj->obj == obj )
			return (vPlanet*)GObject[j].vobj;
	return NULL;	//not found
}
