
#include "scenesystem/iscenesystem.h"

native enum SceneSystemRenderTargetSize_t as NativeEngine.SceneSystemRenderTargetSize;
native enum SceneSystemWellKnownMaterialObjectID_t as NativeEngine.SceneSystemWellKnownMaterialObjectID;
native enum SceneSystemWellKnownTextureObjectID_t as NativeEngine.SceneSystemWellKnownTextureObjectID;

native struct SceneVolumetricFogVolume_t is NativeEngine.SceneVolumetricFogVolume;

native enum SceneSystemGPUProfilerMode_t as NativeEngine.SceneSystemGPUProfilerMode;

native class SceneSystemPerFrameStats_t
{
	uint m_nTrianglesRendered;
	uint m_nArtistTrianglesRendered;
	uint m_nRenderBatchDraws;
	uint m_nDrawCalls;
	uint m_nDrawPrimitives;
	uint m_nBaseSceneObjectPrimDraws;
	uint m_nAnimatableObjectPrimDraws;
	uint m_nAggregateSceneObjectPrimDraws;
	uint m_nAggregateSceneObjectsFullyCulled;
	uint m_nAggregateSceneObjectDrawCalls;
	uint m_nNumMaterialCompute;
	uint m_nNumMaterialSet;
	uint m_nNumSimilarMaterialSet;
	uint m_nNumTextureOnlyMaterialSet;
	uint m_nNumVfxEval;
	uint m_nNumVfxRule;
	uint m_nNumConstantBufferUpdates;
	uint m_nNumConstantBufferBytes;
	uint m_nMaterialChangesNonShadow;
	uint m_nMaterialChangesNonShadowInitial;
	uint m_nMaterialChangesShadow;
	uint m_nMaterialChangesShadowInitial;
	uint m_nMaterialChangesShadowAlphaTested;
	uint m_nCopyMaterialChangesNonShadow;
	uint m_nMaxTransformRow;
	uint m_nNumRowsUsed;
	uint m_nNumObjectsTested;
	uint m_nNumObjectsPreCullCheck;
	uint m_nNumObjectsPassingCullCheck;
	uint m_nNumVerticesReferenced;
	uint m_nNumPrimaryContexts;
	uint m_nNumSecondaryContexts;
	uint m_nNumDisplayListsSubmitted;
	int m_nNumViewsRendered;
	uint m_nNumResolves;
	uint m_nNumCullBoxes;
	ulong m_nCullingBoxCycleCount;
	uint m_nNumObjectsTestedAgainstCullingBoxes;
	uint m_nNumObjectsRejectedByBoundsIndex;
	uint m_nNumObjectsRejectedByCullBoxes;
	uint m_nNumObjectsRejectedByVis;
	uint m_nNumObjectsRejectedByBackfaceCulling;
	uint m_nNumObjectsRejectedByScreenSizeCulling;
	uint m_nNumObjectsRejectedByFading;
	uint m_nNumFadingObjects;
	uint m_nNumUniqueMaterialsSeen;
	uint m_nNumUnshadowedLightsInView;
	uint m_nNumShadowedLightsInView;
	uint m_nNumShadowMaps;
	uint m_nNumRenderTargetBinds;
	uint m_nPushConstantSets;
}

native accessor g_pSceneSystem as NativeEngine.CSceneSystem
{
    void DeleteSceneObject( CSceneObject pObj );
    void DeleteSceneObjectAtFrameEnd( CSceneObject pObj );

    CSceneSkyBoxObject CreateSkyBox( IMaterial skyMaterial, ISceneWorld world );
    CDecalSceneObject CreateDecal( ISceneWorld world );

    void BeginRenderingDynamicView( ISceneView pView );
    //ISceneView AddDynamicView( string pszDebugName, ISceneView pParentView, CFrustum frustum, void* hSwapChain, ISceneWorld pWorld, RenderViewport mainViewport, void* pVis, int nPriority, int nViewProducerIndex );

    ITexture GetWellKnownTexture( SceneSystemWellKnownTextureObjectID a );
    IMaterial GetWellKnownMaterialHandle( SceneSystemWellKnownMaterialObjectID a );
	
    inline SceneSystemPerFrameStats_t GetPerFrameStats()
    {
        return &(g_pSceneSystem->GetPerFrameStats());
    }

    ISceneWorld CreateWorld( string debugName );
    void DestroyWorld( ISceneWorld world );

    void PerformEndOfFrameDeletes();

    inline void SetupPerObjectLighting( CRenderAttributes renderAttributes, CSceneObject pSceneObject, ISceneLayer pSceneLayerInterface )
    {
        g_pSceneSystem->SetupPerObjectLighting( *renderAttributes, pSceneObject, pSceneLayerInterface );
    }

    inline CSceneLightObject CreatePointLight( ISceneWorld pWorld )
    {
        LightDesc_t desc;
		desc.Clear();
		desc.InitPoint( vec3_origin, Vector( 100, 0, 100 ) );
        desc.m_Attenuation0 = 0; // if this is 1 then the light has no falloff
		return g_pSceneSystem->CreateLight( desc, pWorld, false );
    }

    inline CSceneLightObject CreateSpotLight( ISceneWorld pWorld )
    {
        LightDesc_t desc;
		desc.Clear();
		desc.InitSpot( vec3_origin, Vector( 100, 0, 100 ), Vector( 10, 0, 0 ), 15, 30 );
        desc.m_Attenuation0 = 0; // if this is 1 then the light has no falloff
		return g_pSceneSystem->CreateLight( desc, pWorld, false );
    }

    inline CSceneLightObject CreateOrthoLight( ISceneWorld pWorld )
    {
        LightDesc_t desc;
        desc.Clear();
        desc.m_Type = MATERIAL_LIGHT_ORTHO;
        desc.RecalculateDerivedValues();
        return g_pSceneSystem->CreateLight( desc, pWorld, false );
    }

    inline CSceneLightObject CreateDirectionalLight( ISceneWorld pWorld, Vector3 direction )
    {
        LightDesc_t desc;
		desc.Clear();
		desc.InitDirectional( direction, Vector( 100, 0, 100 ) );
        desc.m_nShadowCascadeCount = 3;

		return g_pSceneSystem->CreateLight( desc, pWorld, false );
    }

    inline CSceneLightObject CreateEnvMap( ISceneWorld pWorld, int nProjectionMode )
    {
        LightDesc_t desc;
        desc.InitEnvironmentProbe( vec3_origin, 512 );
        desc.m_nEnvProbeId = 0;
        desc.RecalculateDerivedValues();
        CEnvMapSceneObject* pSceneObject = ( CEnvMapSceneObject* )g_pSceneSystem->CreateLight( desc, pWorld, false );
        pSceneObject->m_nProjectionMode = ( CubemapProjectionMode_t )nProjectionMode;
        return pSceneObject;
    }

    CSceneLightProbeVolumeObject CreateLightProbeVolume( ISceneWorld pWorld );

    void MarkEnvironmentMapObjectUpdated( CEnvMapSceneObject pEnvMap );
    void MarkLightProbeVolumeObjectUpdated( CSceneLightProbeVolumeObject pLightProbe );

    inline uint AddCullingBox( ISceneWorld pWorld, bool nCullMode, Vector3 vOrigin, Angles vAngles, Vector3 vExtents )
    {
        return g_pSceneSystem->AddCullingBox( pWorld, nCullMode ? SCENESYSTEM_BOX_CULL_INSIDE : SCENESYSTEM_BOX_CULL_OUTSIDE, vOrigin, vAngles, vExtents );
    }

    void RemoveCullingBox( ISceneWorld pWorld, uint nBoxId );

    uint AddVolumetricFogVolume( ISceneWorld pWorld, SceneVolumetricFogVolume_t volume );
    void RemoveVolumetricFogVolume( ISceneWorld pWorld, uint nId );

	inline void DownsampleTexture( IRenderContext ctx, ITexture src, byte nDownsampleType )
	{
		return g_pSceneSystem->DownsampleTexture( ctx, src, nullptr, nDownsampleType );
	}

	void BindTransformSlot( IRenderContext pCtx, int nVBSlot, int nTransformSlotIndex );

	// Ray Tracing
	IRayTraceSceneWorld CreateRayTraceWorld( string pWorldDebugName, int nMaxRayTypes );
	void DestroyRayTraceWorld( IRayTraceSceneWorld pRayTraceSceneWorld );

	// GPU Profiler
	void SetGPUProfilerMode( SceneSystemGPUProfilerMode_t eProfilerMode );
	SceneSystemGPUProfilerMode_t GetGPUProfilerMode();

	inline int GetGpuTimestampCount()
	{
		CUtlVector< SceneSystemTimestampFrameData_t > timestamps;
		g_pSceneSystem->GetMostRecentTimestampFrameSummary( SWAP_CHAIN_HANDLE_INVALID, timestamps );
		return timestamps.Count();
	}

	inline float GetGpuTimestampDuration( int index )
	{
		CUtlVector< SceneSystemTimestampFrameData_t > timestamps;
		g_pSceneSystem->GetMostRecentTimestampFrameSummary( SWAP_CHAIN_HANDLE_INVALID, timestamps );
		if ( index >= 0 && index < timestamps.Count() )
		{
			return timestamps[index].m_flDurationInMilliseconds;
		}
		return 0.0f;
	}

	inline string GetGpuTimestampName( int index )
	{
		CUtlVector< SceneSystemTimestampFrameData_t > timestamps;
		g_pSceneSystem->GetMostRecentTimestampFrameSummary( SWAP_CHAIN_HANDLE_INVALID, timestamps );
		if ( index >= 0 && index < timestamps.Count() )
		{
			return timestamps[index].m_sGroupName.Get();
		}
		return "";
	}

	// Managed timestamp support for CommandList etc.
	bool SetManagedPerfMarker( IRenderContext ctx, string markerName );
}
