Show / Hide Table of Contents
    ///////////////////////////////////////////////////////////////////////////
    //
    //  System:    Simplygon
    //  File:      DXExample.cpp
    //  Language:  C++
    //
    //  Copyright (c) 2019 Microsoft. All rights reserved.
    //
    //  This is private property, and it is illegal to copy or distribute in
    //  any form, without written authorization by the copyright owner(s).
    //
    ///////////////////////////////////////////////////////////////////////////
    //
    //  #Description# 
    //
    //  A simple DirectX9 example which loads an OBJ-file, 
    //  converts it to DirectX format (from right-handed to left-handed 
    //  coordinate system) and reduces the Simplygon mesh.
    //  Both converted and reduced models are then displayed in a direct x window.
    //
    //  Note that manual linking to local dx9 libs is required for the example to run.
    //
    ///////////////////////////////////////////////////////////////////////////
    
    // include the basic windows header files and the Direct3D header file
    #include <windows.h>
    #include <windowsx.h>
    #include "../Common/Example.h"
    #include <d3d9.h>
    #include <d3dx9.h>
    #include "Mesh.h"
    #include <winerror.h>
    
    // Define the screen resolution and start points
    #define WINDOW_WIDTH  1000
    #define WINDOW_HEIGHT 1000
    #define WINDOW_START_X 150
    #define WINDOW_START_Y 150
    
    #define LocalScope if(true)
    
    
    
    D3DVERTEXELEMENT9 dwDecl3[] =
        {
            {0, 0,  D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
            {0, 12, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
            {0, 24, D3DDECLTYPE_FLOAT2,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
            {0, 36, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0},
            {0, 48, D3DDECLTYPE_FLOAT3,   D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
            D3DDECL_END()
        };
    
    // Interface and device pointer
    LPDIRECT3D9 D3D9Interface;                           // Pointer to D3D interface
    LPDIRECT3DDEVICE9 D3D9Device;                       // Pointer to D3D device
    
    // Mesh to be loaded and rendered
    Mesh* original_d3d_mesh = NULL;
    Mesh* lod_d3d_mesh = NULL;
    
    //Simplygon geometry containers
    spGeometryData original_simplygon_mesh = NULL;
    spMaterialTable original_simplygon_materials = NULL;
    spTextureTable original_simplygon_textable = NULL;
    
    ID3DXEffect* Shader = NULL;       // D3DX effect interface
    bool ShowLOD = false;
    bool visualize_debug = false;
    
    // Camera settings
    float OrbitRadius = 10.0f;
    float OrbitRotation = 90.0f;
    D3DXVECTOR3 OrbitCenter( 0, 0, 0 );
    
    // Function prototypes
    void InitializeD3D( HWND hWnd ); // Initializes D3D
    void DeInitializeD3D( void );   // De-initializes D3D
    void Render( void );           // Render function
    void RunProcessing( bool use_remeshing ); //Runs remeshing or reduction
    bool LoadOBJ( const std::string& import_path, spGeometryData geom ); //Reads an OBJ and its material from a file path and stores them as spGeometryData and spMaterialTable
    
    bool InitializeGraphics( void );                                                         // Initialize graphics
    HWND InitializeWindow( HINSTANCE hInstance, int nCmdShow );                           // Initialize window                                               
    LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam );  // Callback function
    
    bool CreateD3DMeshFromPackedGeometry( spPackedGeometryData PerVtxGeometry, Mesh * mesh );              // Simplygon geometry to dxGeometry
    bool SetMaterials( spPackedGeometryData PerVtxGeometry, spMaterialTable MaterialTable, spTextureTable TextureTable, Mesh * mesh );  // Simplygon material to dxMaterial
    
    // Desc: the main function
    int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )
        {
        // Initialize Simplygon SDK
        try
        {
            InitExample();
    
            // Sets the tangent space type. DirectX uses a left-handed coordinate system.
            sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL_LEFTHANDED);
    
            // Initialize window
            HWND hWnd = InitializeWindow(hInstance, nCmdShow);
    
            // Initialize Direct3D
            InitializeD3D(hWnd);
    
            // Initialize graphics, quit if initialization fails
            if (!InitializeGraphics())
                return -1;
    
            // Run a processing
            bool use_remeshing = false; // if false, do a mesh lod instead
            RunProcessing(use_remeshing);
    
            // Main loop
            MSG msg;
            while (TRUE)
            {
                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    TranslateMessage(&msg);
                    DispatchMessage(&msg);
                }
    
                if (msg.message == WM_QUIT)
                {
                    break;
                }
                else if (msg.message == WM_LBUTTONUP)
                {
                    ShowLOD = false;
                }
                else if (msg.message == WM_LBUTTONDOWN)
                {
                    ShowLOD = true;
                }
                else if (msg.message == WM_RBUTTONUP)
                {
                    visualize_debug = false;
                }
                else if (msg.message == WM_RBUTTONDOWN)
                {
                    visualize_debug = true;
                }
    
                // Render a frame
                Render();
            }
    
            // Deinitialize D3D
    
            DeInitializeD3D();
            delete original_d3d_mesh;
            delete lod_d3d_mesh;
            // Deinitialize Simplygon SDK
            original_simplygon_materials = NULL;
            original_simplygon_textable = NULL;
            original_simplygon_mesh = NULL;
            DeinitExample();
        }
        catch (const std::exception& ex)
        {
            std::cerr << ex.what() << std::endl;
            return -1;
        }
    
        return 0;
        }
    
    //Reads an OBJ and its material from a file path
    //and stores them as spGeometryData and spMaterialTable
    bool LoadOBJ( const std::string& import_path, spGeometryData geom )
        {
        spWavefrontImporter importer = sg->CreateWavefrontImporter();
    
        importer->SetImportFilePath( import_path.c_str() );
    
        if( !importer->RunImport() )
            {
            MessageBox( NULL, "No geometry loaded!", "FAILED", 0 );
            return false;
            }
    
        spGeometryData combined_geometry = importer->GetScene()->NewCombinedGeometry();
    
        geom->DeepCopy( combined_geometry, true );
    
        original_simplygon_materials = importer->GetScene()->GetMaterialTable();
        if( original_simplygon_materials.IsNull() )
            {
            MessageBox( NULL, "Material assignment failed!", "FAILED", 0 );
            return false;
            }
    
        original_simplygon_textable = importer->GetScene()->GetTextureTable();
        if( original_simplygon_textable.IsNull() )
            {
            MessageBox( NULL, "Material assignment failed!", "FAILED", 0 );
            return false;
            }
    
        return true;
        }
    
    //Run a processing of the geometry
    //If the use_remeshing flag is true, it performs a remeshing, 
    //otherwise a regular reduction
    //The processed mesh is converted back to a 
    void RunProcessing( bool use_remeshing )
        {
    
        std::string exePath = GetExecutablePath();
    
        std::string output_filename = exePath + "object.obj";
        std::string output_material_filename = exePath + "object.mtl";
        std::string output_diffuse_filename = exePath + "object_diffuse.png";
        std::string output_normals_filename = exePath + "object_normals.png";
    
        // Make a copy of the geometry, we need the original for texture casting later.
        // The remesher will replace the data of the geometry after it has processed it.
        spGeometryData reduction_geometry = original_simplygon_mesh->NewCopy( true );
    
        // Create a Scene-object and a SceneMesh-object. 
        // Place the reduction_geometry into the SceneMesh, 
        // and then the SceneMesh as a child to the RootNode.
        spScene scene = sg->CreateScene();
        spSceneMesh mesh = sg->CreateSceneMesh();
        mesh->SetGeometry( reduction_geometry );
        mesh->SetName( reduction_geometry->GetName().GetText() );
        scene->GetRootNode()->AddChild( mesh );
    
        spReductionProcessor red;
        spMappingImage mapping_image;
    
        if( use_remeshing )
            {
            // Remesh it
            spRemeshingProcessor remesher = sg->CreateRemeshingProcessor();
            // set settings
            remesher->GetRemeshingSettings()->SetOnScreenSize( 400 );
            remesher->GetMappingImageSettings()->SetGenerateMappingImage( true );
            remesher->GetMappingImageSettings()->SetWidth( 512 );
            remesher->GetMappingImageSettings()->SetHeight( 512 );
            remesher->GetMappingImageSettings()->SetTexCoordLevel( 0 );
            remesher->SetScene( scene );
            remesher->GetRemeshingSettings()->SetHardEdgeAngleInRadians(1.047f);
            // run it
            remesher->RunProcessing();
            // Mapping image is needed later on for texture casting.
            mapping_image = remesher->GetMappingImage();
            }
        else
            {
            // Reduce it
            red = sg->CreateReductionProcessor();
            // set settings
            red->GetReductionSettings()->SetTriangleRatio( 0.7f );
            red->GetNormalCalculationSettings()->SetReplaceNormals( true );
            red->GetNormalCalculationSettings()->SetHardEdgeAngleInRadians( 3.14159f );
            red->GetMappingImageSettings()->SetGenerateMappingImage( true );
            red->GetMappingImageSettings()->SetWidth( 1024 );
            red->GetMappingImageSettings()->SetHeight( 1024 );
            red->GetMappingImageSettings()->SetUseFullRetexturing( true );
            red->GetMappingImageSettings()->SetTexCoordLevel( 0 );
            red->GetReductionSettings()->SetDataCreationPreferences( SG_DATACREATIONPREFERENCES_PREFER_ORIGINAL_DATA );
            red->SetScene( scene );
            // run it
            red->RunProcessing();
            // Mapping image is needed later on for texture casting.
            mapping_image = red->GetMappingImage();
            }
    
        //Extract the processed scene mesh
        spSceneMesh topmesh = SimplygonSDK::Cast<ISceneMesh>( scene->GetRootNode()->GetChild( 0 ) );
    
        // Cast diffuse texture and normal map data into a new material
        // Create new material table.
        spMaterialTable output_materials = sg->CreateMaterialTable();
        spTextureTable output_textures = sg->CreateTextureTable();
    
        // Create new material for the table.
        spMaterial output_material = sg->CreateMaterial();
        output_materials->AddMaterial( output_material );
    
        // Cast diffuse texture data
        // Cast the data using a color caster
        spColorCaster color_caster = sg->CreateColorCaster();
        color_caster->SetColorType( SG_MATERIAL_CHANNEL_DIFFUSE );
        color_caster->SetSourceMaterials( original_simplygon_materials );
        color_caster->SetSourceTextures( original_simplygon_textable );
        color_caster->SetMappingImage( mapping_image );     // The mapping image we got from the remeshing process.
        color_caster->SetOutputChannels( 3 );              // RGB, 3 channels! (1 would be for gray scale, and 4 would be for RGBA.)
        color_caster->SetOutputChannelBitDepth( 8 );      // 8 bits per channel. So in this case we will have 24bit colors RGB.
        color_caster->SetDilation( 10 );                 // To avoid mip-map artifacts, the empty pixels on the map needs to be filled to a degree as well.
        color_caster->SetOutputFilePath( output_diffuse_filename.c_str() );  // Where the texture map will be saved to file.
        color_caster->RunProcessing();                              // Fetch!
        color_caster->SetOutputSRGB( true );
    
        // Set material to point to created texture filename.
        AddSimplygonTexture( output_material, output_textures, SG_MATERIAL_CHANNEL_DIFFUSE, output_diffuse_filename.c_str() );
    
        // cast normal map texture data
        // cast the data using a color caster
        spNormalCaster normal_caster = sg->CreateNormalCaster();
        normal_caster->SetSourceMaterials( original_simplygon_materials );
        normal_caster->SetSourceTextures( original_simplygon_textable );
        normal_caster->SetGenerateTangentSpaceNormals( true );
        normal_caster->SetMappingImage( mapping_image );
        normal_caster->SetOutputChannels( 3 ); // RGB, 3 channels! (But really the x, y and z values for the normal)
        normal_caster->SetOutputChannelBitDepth( 8 );
        normal_caster->SetDilation( 10 );
        normal_caster->SetOutputFilePath( output_normals_filename.c_str() );
        normal_caster->RunProcessing();
    
        // Set material to point to created texture filename.
        AddSimplygonTexture( output_material, output_textures, SG_MATERIAL_CHANNEL_NORMALS, output_normals_filename.c_str() );
    
        // Create a packed, left-handed version of the simplygon LOD for rendering
        spGeometryData leftHandedGeom = topmesh->GetGeometry()->NewCopy( true );
        leftHandedGeom->ConvertHandedness();
        spPackedGeometryData packed_geom = leftHandedGeom->NewPackedCopy();
    
        // fetch various data to be able to set up a new dxmesh
        D3DVERTEXELEMENT9 decl[MAXD3DDECLLENGTH];
        const DWORD options = original_d3d_mesh->GetD3D9Mesh()->GetOptions();
        const DWORD triCount = packed_geom->GetTriangleCount();
        const DWORD vertCount = packed_geom->GetVertexCount();
    
        // fetch vertex declaration
        HRESULT hr = original_d3d_mesh->GetD3D9Mesh()->GetDeclaration( decl );
        if( FAILED( hr ) )
            {
            return;
            }
    
        // if lod dxmesh exists, delete
        if( lod_d3d_mesh )
            {
            delete lod_d3d_mesh;
            }
    
        // create a new dxmesh
        lod_d3d_mesh = new Mesh();
        bool result = lod_d3d_mesh->Create( triCount, vertCount, options, decl, D3D9Device );
        if( !result )
            {
            return;
            }
    
        // copy simplygon data to dxmesh
        result = CreateD3DMeshFromPackedGeometry( packed_geom, lod_d3d_mesh );
        if( !result )
            {
            return;
            }
    
        // copy simplygon material data to dxmesh
        result = SetMaterials( packed_geom, output_materials, output_textures, lod_d3d_mesh );
        if( !result )
            {
            return;
            }
    
        }
    
    // Message handler
    LRESULT CALLBACK WindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
        {
        switch( message )
            {
                case WM_DESTROY:
                    {
                    PostQuitMessage( 0 );
                    return 0;
                    }
                    break;
            }
    
        return DefWindowProc( hWnd, message, wParam, lParam );
        }
    
    // Initializes D3D
    void InitializeD3D( HWND hWnd )
        {
        D3D9Interface = Direct3DCreate9( D3D_SDK_VERSION ); // Create the D3D9 Interface
        D3DPRESENT_PARAMETERS D3D9PresentParameters;     // Create D3D9 parameter struct
    
        ZeroMemory( &D3D9PresentParameters, sizeof( D3D9PresentParameters ) ); // Zero out the memory
        D3D9PresentParameters.Windowed = TRUE;                            // Run window in windowed mode
        D3D9PresentParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;
        D3D9PresentParameters.hDeviceWindow = hWnd;
        D3D9PresentParameters.BackBufferFormat = D3DFMT_X8R8G8B8;
        D3D9PresentParameters.BackBufferWidth = WINDOW_WIDTH;
        D3D9PresentParameters.BackBufferHeight = WINDOW_HEIGHT;
        D3D9PresentParameters.EnableAutoDepthStencil = TRUE;                          // Automatically use the z-buffer
        D3D9PresentParameters.AutoDepthStencilFormat = D3DFMT_D16;                   // 16-bit pixel format for z-buffer
        D3D9PresentParameters.FullScreen_RefreshRateInHz = 0;                       // Default refresh rate
        D3D9PresentParameters.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT;  // Vertical sync
    
        DWORD backBufferQualityLevels = 0;
        DWORD depthStencilQualityLevels = 0;
        D3DMULTISAMPLE_TYPE msaaType = D3DMULTISAMPLE_4_SAMPLES;
    
        // try to enable 4x msaa
        HRESULT hr = D3D9Interface->CheckDeviceMultiSampleType( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, D3D9PresentParameters.BackBufferFormat,
                                                                D3D9PresentParameters.Windowed, msaaType, &backBufferQualityLevels );
    
        if( SUCCEEDED( hr ) )
            {
            hr = D3D9Interface->CheckDeviceMultiSampleType( D3DADAPTER_DEFAULT,
                                                            D3DDEVTYPE_HAL, D3D9PresentParameters.AutoDepthStencilFormat, D3D9PresentParameters.Windowed, msaaType,
                                                            &depthStencilQualityLevels );
    
            if( SUCCEEDED( hr ) )
                {
                if( backBufferQualityLevels == depthStencilQualityLevels )
                    {
                    if( backBufferQualityLevels > 0 )
                        {
                        D3D9PresentParameters.MultiSampleQuality = backBufferQualityLevels - 1;
                        D3D9PresentParameters.MultiSampleType = msaaType;
                        }
                    else
                        {
                        D3D9PresentParameters.MultiSampleQuality = backBufferQualityLevels;
                        D3D9PresentParameters.MultiSampleType = D3DMULTISAMPLE_NONE;
                        }
                    }
                }
            }
    
        // Initialize the D3D9 Device
        hr = D3D9Interface->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
                                          D3DCREATE_HARDWARE_VERTEXPROCESSING, &D3D9PresentParameters, &D3D9Device );
    
        if( FAILED( hr ) )
            {
            return;
            }
        D3DCAPS9 caps;
        DWORD MaxAnisotrophy = 1;
    
        // Set max anisotrophy value
        if( !(D3D9Device->GetDeviceCaps( &caps )) )
            {
            if( caps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY )
                {
                MaxAnisotrophy = caps.MaxAnisotropy;
                }
            else
                {
                MaxAnisotrophy = 1;
                }
            }
        }
    
    // Renders the frame
    void Render( void )
        {
        // Clear window to gray (also clear depth buffer)
        D3D9Device->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 10, 10, 10 ), 1.0f, 0 );
        D3D9Device->Clear( 0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB( 0, 0, 0 ), 1.0f, 0 );
    
        // Ready scene for rendering
        D3D9Device->BeginScene();
    
        D3DXMATRIX matRotateY;
    
        OrbitRotation += 0.003f;    // Increase rotation for each frame
    
        D3DXMatrixRotationY( &matRotateY, OrbitRotation );
    
        D3DXMATRIX matView;    // The view transform matrix
    
        D3DXMatrixLookAtLH( &matView,
                            &D3DXVECTOR3( 0, OrbitRadius / 2.0f, OrbitRadius*1.45f ),    // The camera position
                            &D3DXVECTOR3( OrbitCenter ),                           // The look-at position
                            &D3DXVECTOR3( 0.0f, 1.0f, 0.0f ) );                     // The up direction
    
        D3DXMATRIX matProjection;                                   // The projection transform matrix
    
        D3DXMatrixPerspectiveFovLH( &matProjection,
                                    D3DXToRadian( 35 ),                                // The horizontal field of view
                                    (FLOAT)WINDOW_WIDTH / (FLOAT)WINDOW_HEIGHT,     // Aspect ratio
                                    1.0f,                                          // The near view-plane
                                    OrbitRadius * 3 );                               // The far view-plane
    
        D3DXMATRIX worldMatrix = matRotateY * matView;
        D3DXMATRIX finalMatrix = worldMatrix * matProjection;
    
        bool UseShader = true;
    
        // if shader, enable effects
        if( UseShader )
            {
            // send parameters to the shader
            Shader->SetTechnique( "TransformTechnique" );
    
            D3DXMATRIX m;
            Shader->SetMatrix( "World", &worldMatrix );
            Shader->SetMatrix( "WorldViewProj", &finalMatrix );
            Shader->SetVector( "gLightDir", &D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0 ) );
    
            Shader->SetBool( "visualize_debug", visualize_debug ); //Render only normal map shading
    
            // Apply the technique contained in the effect 
            UINT NumberOfPasses;
            Shader->Begin( &NumberOfPasses, 0 );
    
            uint p = 0;
            for( UINT p = 0; p < NumberOfPasses; ++p )
                {
                // Render dx mesh
                if( original_d3d_mesh && !ShowLOD )
                    {
                    Shader->BeginPass( p );
    
                    LPDIRECT3DTEXTURE9* DiffuseList = original_d3d_mesh->GetD3D9DiffuseTextures();
                    LPDIRECT3DTEXTURE9 DiffuseTex = DiffuseList[0];
    
                    Shader->SetTexture( "gDiffuseTexture", DiffuseTex );
    
                    LPDIRECT3DTEXTURE9* NormalsList = original_d3d_mesh->GetD3D9NormalsTextures();
                    LPDIRECT3DTEXTURE9 NormalsTex = NormalsList[0];
    
                    Shader->SetTexture( "NormalMap", NormalsTex );
                    original_d3d_mesh->Render( D3D9Device );
    
                    Shader->EndPass();
                    }
                else if( lod_d3d_mesh && ShowLOD )
                    {
                    Shader->BeginPass( p );
    
                    LPDIRECT3DTEXTURE9* DiffuseList = lod_d3d_mesh->GetD3D9DiffuseTextures();
                    LPDIRECT3DTEXTURE9 DiffuseTex = DiffuseList[0];
    
                    Shader->SetTexture( "gDiffuseTexture", DiffuseTex );
    
                    LPDIRECT3DTEXTURE9* NormalsList = lod_d3d_mesh->GetD3D9NormalsTextures();
                    LPDIRECT3DTEXTURE9 NormalsTex = NormalsList[0];
    
                    Shader->SetTexture( "NormalMap", NormalsTex );
                    lod_d3d_mesh->Render( D3D9Device );
    
                    Shader->EndPass();
                    }
    
                Shader->EndPass();
                }
            Shader->End();
            }
    
        // Finish scene
        D3D9Device->EndScene();
    
        // Render the scene on screen
        D3D9Device->Present( NULL, NULL, NULL, NULL );
        }
    
    // Desc: cleans up Direct3D
    void DeInitializeD3D( void )
        {
        D3D9Device->Release();        // Release device
        D3D9Interface->Release();    // Release interface
        }
    
    // Desc: initializes the graphics (mesh)
    bool InitializeGraphics( void )
        {
        std::string ImportGeometryPath = GetAssetPath() + "simplygonman.obj";
        std::string ImportShaderPath = GetAssetPath() + "shader.fx";
    
        //Load .obj to simplygon
        if( original_simplygon_mesh != NULL )
            original_simplygon_mesh->Release();
    
        //Load an OBJ from 
        original_simplygon_mesh = sg->CreateGeometryData();
        if( !LoadOBJ( ImportGeometryPath, original_simplygon_mesh ) )
            return false;
    
        //Calculate D3D tangent space for original geometry
        spTangentCalculator tangentspacecalc = sg->CreateTangentCalculator();
        tangentspacecalc->SetTexCoordsSetId( 0 );
        tangentspacecalc->CalculateTangents( original_simplygon_mesh );
    
        //Create a packed, left-handed version of the right-handed simplygon geometry to use for DX rendering
        spGeometryData leftHandedOriginalGeom = original_simplygon_mesh->NewCopy( true );
        leftHandedOriginalGeom->ConvertHandedness();
        spPackedGeometryData packed_geom = leftHandedOriginalGeom->NewPackedCopy();
    
        const DWORD triCount = packed_geom->GetTriangleCount();
        const DWORD vertCount = packed_geom->GetVertexCount();
    
        //Create D3D mesh from simplygon geometry
        original_d3d_mesh = new Mesh();
    
        bool result = original_d3d_mesh->Create( triCount, vertCount, 0, dwDecl3, D3D9Device );
        if( !result )
            {
            return false;
            }
    
        CreateD3DMeshFromPackedGeometry( packed_geom, original_d3d_mesh );
    
        // copy simplygon material data to dxmesh
        result = SetMaterials( packed_geom, original_simplygon_materials, original_simplygon_textable, original_d3d_mesh );
        if( !result )
            {
            return false;
            }
    
    
        // Load a texture/normal map shader
        LPD3DXBUFFER pBufferErrors = NULL;
        HRESULT hr = D3DXCreateEffectFromFile( D3D9Device, ImportShaderPath.c_str(), NULL, NULL, 0, NULL, &Shader, &pBufferErrors );
        if( FAILED( hr ) )
            {
            LPVOID pCompilErrors = pBufferErrors->GetBufferPointer();
            MessageBox( NULL, (const char*)pCompilErrors, "Effect Compile Error",
                        MB_OK | MB_ICONEXCLAMATION );
            }
    
        original_simplygon_mesh->CalculateExtents( false );
        D3DXVECTOR3 AABBMin, AABBMax;
        real inf[3];
        real sup[3];
        original_simplygon_mesh->GetInf( inf );
        original_simplygon_mesh->GetSup( sup );
        AABBMin = D3DXVECTOR3( inf );
        AABBMax = D3DXVECTOR3( sup );
    
        OrbitRadius = D3DXVec3Length( &(AABBMax - AABBMin) );
        OrbitCenter = AABBMin + ((AABBMax - AABBMin) / 2.0f);
    
        return true;
        }
    
    HWND InitializeWindow( HINSTANCE hInstance, int nCmdShow )
        {
        // Setup window class
        HWND hWnd;
        WNDCLASSEX wc;
    
        // Zero out the memory
        ZeroMemory( &wc, sizeof( WNDCLASSEX ) );
    
        // Fill window class with information
        wc.cbSize = sizeof( WNDCLASSEX );
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor( NULL, IDC_ARROW );
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = "WindowClass";
    
        // Register window class
        RegisterClassEx( &wc );
    
        // Create the window
        hWnd = CreateWindowEx( NULL, "WindowClass", "DirectX9 Processing example [press LMB to view LOD model. Press RMB to view only shading.]",
                               WS_OVERLAPPEDWINDOW, WINDOW_START_X, WINDOW_START_Y, WINDOW_WIDTH, WINDOW_HEIGHT,
                               NULL, NULL, hInstance, NULL );
    
        // Make the window visible
        ShowWindow( hWnd, nCmdShow );
    
        return hWnd;
        }
    
    bool CreateD3DMeshFromPackedGeometry( spPackedGeometryData PerVtxGeometry, Mesh * mesh )
        {
        LPD3DXMESH D3D9Mesh = mesh->GetD3D9Mesh();
        LPDIRECT3DVERTEXBUFFER9 VertexBuffer = NULL;
        LPDIRECT3DINDEXBUFFER9 IndexBuffer = NULL;
    
        // Get vertex buffer
        HRESULT hResult = D3D9Mesh->GetVertexBuffer( &VertexBuffer );
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        // Get index buffer
        hResult = D3D9Mesh->GetIndexBuffer( &IndexBuffer );
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        uint NumberOfVertices = PerVtxGeometry->GetVertexCount();
        uint NumberOfFaces = PerVtxGeometry->GetTriangleCount();
    
        spRidArray VertexIDs = PerVtxGeometry->GetVertexIds();
        spRealArray Coords = PerVtxGeometry->GetCoords();
        spRealArray Normals = PerVtxGeometry->GetNormals();
        spRealArray TexCoords = PerVtxGeometry->GetTexCoords( 0 );
    
        spRealArray BiTangents;
        spRealArray Tangents;
    
        if( PerVtxGeometry->GetTangents( 0 ) )
            Tangents = PerVtxGeometry->GetTangents( 0 );
    
        if( PerVtxGeometry->GetBitangents( 0 ) )
            BiTangents = PerVtxGeometry->GetBitangents( 0 );
    
    
    
        // Get the original declaration of the mesh (as when created)
        std::vector<D3DVERTEXELEMENT9> vecDeclaration( MAX_FVF_DECL_SIZE );
        hResult = D3D9Mesh->GetDeclaration( &*vecDeclaration.begin() );
    
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        void* VertexBufferPointer = NULL;
    
        // Get a writable handle to vertex buffer
        hResult = VertexBuffer->Lock( 0, sizeof( VertexBuffer ), (void**)&VertexBufferPointer, 0 );
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        // Get vertex size
        DWORD BytesPerVertex = D3D9Mesh->GetNumBytesPerVertex();
    
        // Copy data from simplygon geometry to d3d geometry
        for( uint i = 0; i < NumberOfVertices; ++i )
            {
            char *vertex_start = &(((char*)VertexBufferPointer)[i*BytesPerVertex]);
    
            spRealData normals_xyz = sg->CreateRealData();
            spRealData tangents_xyz = sg->CreateRealData();
            spRealData bitangents_xyz = sg->CreateRealData();
            Normals->GetTuple( i, normals_xyz );
            Tangents->GetTuple( i, tangents_xyz );
            BiTangents->GetTuple( i, bitangents_xyz );
    
    
            uint atDeclaration = 0;
            for( uint j = 0; j < vecDeclaration.size(); ++j )
                {
                // Vertices
                if( vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_POSITION )
                    {
                    // get simplygon data
                    spRealData xyz = sg->CreateRealData();
                    Coords->GetTuple( i, xyz );
    
                    // set data to dxMesh
                    float *dxyz = (float*)&(vertex_start[vecDeclaration[j].Offset]);
                    dxyz[0] = xyz[0];
                    dxyz[1] = xyz[1];
                    dxyz[2] = xyz[2];
                    }
    
                // Normals
                if( vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_NORMAL )
                    {
                    spRealData xyz = sg->CreateRealData();
                    Normals->GetTuple( i, xyz );
    
    
                    float *dxyz = (float*)&(vertex_start[vecDeclaration[j].Offset]);
                    dxyz[0] = xyz[0];
                    dxyz[1] = xyz[1];
                    dxyz[2] = xyz[2];
                    }
    
                // Texcoords
                if( vecDeclaration[j].Type == D3DDECLTYPE_FLOAT2 && vecDeclaration[j].Usage == D3DDECLUSAGE_TEXCOORD )
                    {
                    spRealData uv = sg->CreateRealData();
                    TexCoords->GetTuple( i, uv );
    
                    float *duv = (float*)&(vertex_start[vecDeclaration[j].Offset]);
                    duv[0] = uv[0];
                    duv[1] = uv[1];
                    }
    
                // Bitangents
                if( vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_BINORMAL )
                    {
                    spRealData xyz = sg->CreateRealData();
                    if( BiTangents )
                        {
                        BiTangents->GetTuple( i, xyz );
    
                        float *duv = (float*)&(vertex_start[vecDeclaration[j].Offset]);
                        duv[0] = xyz[0];
                        duv[1] = xyz[1];
                        duv[2] = xyz[2];
                        }
                    }
    
                // Tangents
                if( vecDeclaration[j].Type == D3DDECLTYPE_FLOAT3 && vecDeclaration[j].Usage == D3DDECLUSAGE_TANGENT )
                    {
                    spRealData xyz = sg->CreateRealData();
                    if( Tangents )
                        {
                        Tangents->GetTuple( i, xyz );
    
                        float *duv = (float*)&(vertex_start[vecDeclaration[j].Offset]);
                        duv[0] = xyz[0];
                        duv[1] = xyz[1];
                        duv[2] = xyz[2];
                        }
                    }
    
                // End of field, break
                if( vecDeclaration[j].Type == D3DDECLTYPE_UNUSED )
                    {
                    break;
                    }
                }
            }
    
        // Unlock the vertex buffer
        VertexBuffer->Unlock();
        VertexBuffer->Release();
    
        // Fetch index buffer information
        D3DINDEXBUFFER_DESC IndexBufferDescription;
        if( FAILED( IndexBuffer->GetDesc( &IndexBufferDescription ) ) )
            {
            return false;
            }
    
        // Set the index size (16 or 32 bits) to be able to traverse the index buffer
        int IndexSize;
        if( IndexBufferDescription.Format == D3DFMT_INDEX32 )
            {
            IndexSize = 4;
            }
        else
            {
            IndexSize = 2;
            }
    
        BYTE* IndexBufferPointer = NULL;
    
        // Lock buffer to access index buffer
        if( FAILED( IndexBuffer->Lock( 0, sizeof( IndexBuffer ), (void**)&IndexBufferPointer, 0 ) ) )
            {
            return false;
            }
    
        // Copy index data
        DWORD CurrentTri[3] = { 0,0,0 };
        for( uint i = 0; i < NumberOfFaces * 3; i += 3 )
            {
            CurrentTri[0] = VertexIDs->GetItem( i + 0 );
            CurrentTri[1] = VertexIDs->GetItem( i + 1 );
            CurrentTri[2] = VertexIDs->GetItem( i + 2 );
    
            for( uint e = 0; e < 3; ++e )
                {
                memcpy( IndexBufferPointer, &CurrentTri[e], IndexSize );
                IndexBufferPointer += IndexSize;
                }
            }
    
        // Unlock the index buffer
        IndexBuffer->Unlock();
        IndexBuffer->Release();
    
        real inf[3], sup[3];
    
        PerVtxGeometry->GetInf( inf );
        PerVtxGeometry->GetSup( sup );
    
        float dist = inf[2] - sup[2];
        dist = dist > inf[1] - sup[1] ? dist : inf[1] - sup[1];
        dist = dist > inf[0] - sup[0] ? dist : inf[0] - sup[0];
    
    
        return true;
        }
    
    
    bool SetMaterials( spPackedGeometryData PerVtxGeometry, spMaterialTable MaterialTable, spTextureTable TextureTable, Mesh * mesh )
        {
        LPD3DXMESH D3D9Mesh = mesh->GetD3D9Mesh();
    
        uint NumberOfFaces = PerVtxGeometry->GetTriangleCount();
    
        // Lock attribute buffer
        DWORD* AttributeBufferPointer = NULL;
    
        HRESULT hResult = D3D9Mesh->LockAttributeBuffer( 0, &AttributeBufferPointer );
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        // Copy over material ids (Proxy Lods only have one material)
        for( uint a = 0; a < NumberOfFaces; ++a )
            {
            AttributeBufferPointer[a] = 0;
            }
    
        // Unlock attribute buffer
        hResult = D3D9Mesh->UnlockAttributeBuffer();
        if( FAILED( hResult ) )
            {
            return false;
            }
    
        // Setup materials
        uint NumberOfMaterials = MaterialTable->GetMaterialsCount();
        mesh->SetNumMaterials( NumberOfMaterials );
    
        for( uint i = 0; i < NumberOfMaterials; ++i )
            {
            // get simplygon material
            spMaterial m = Cast<IMaterial>( MaterialTable->GetItem( i ) );
    
            std::string dpath = "";
            std::string npath = "";
            // get diffuse and normal map
            spShadingNode diffNode = m->GetShadingNetwork( SG_MATERIAL_CHANNEL_DIFFUSE );
            spShadingNode normNode = m->GetShadingNetwork( SG_MATERIAL_CHANNEL_NORMALS );
    
            if( diffNode != nullptr )
                {
                //This node is either mult-node or tex-node. If mult, the texnode is one of the inputs. Ignore the rest of the network for this renderings sake.
                spShadingTextureNode texNode;
                texNode = SafeCast<IShadingTextureNode>( diffNode );
                if( texNode == nullptr )
                    {
                    spShadingFilterNode filtNode = SafeCast<IShadingFilterNode>( diffNode );
                    if( filtNode != nullptr )
                        {
                        texNode = SafeCast<IShadingTextureNode>( filtNode->GetInput( 0 ) );
                        if( texNode == nullptr )
                            {
                            texNode = SafeCast<IShadingTextureNode>( filtNode->GetInput( 1 ) );
                            }
                        }
                    }
    
                //If we found the node, check the path in the tex table and set it
                if( texNode != nullptr )
                    {
                    spTexture tex = TextureTable->FindTexture( texNode->GetTextureName() );
                    if( tex != nullptr )
                        {
                        dpath = tex->GetFilePath();
                        }
                    }
                }
    
            if( normNode != nullptr )
                {
                //This node is either mult-node or tex-node. If mult, the texnode is one of the inputs. Ignore the rest of the network for this renderings sake.
                spShadingTextureNode texNode;
                texNode = SafeCast<IShadingTextureNode>( normNode );
                if( texNode == nullptr )
                    {
                    spShadingFilterNode filtNode = SafeCast<IShadingFilterNode>( normNode );
                    if( filtNode != nullptr )
                        {
                        texNode = SafeCast<IShadingTextureNode>( filtNode->GetInput( 0 ) );
                        if( texNode == nullptr )
                            {
                            texNode = SafeCast<IShadingTextureNode>( filtNode->GetInput( 1 ) );
                            }
                        }
                    }
    
                //If we found the node, check the path in the tex table and set it
                if( texNode != nullptr )
                    {
                    spTexture tex = TextureTable->FindTexture( texNode->GetTextureName() );
                    if( tex != nullptr )
                        {
                        npath = tex->GetFilePath();
                        }
                    }
                }
    
    
            D3DMATERIAL9 mat;
    
            // Set the RGBA for diffuse reflection.
            mat.Diffuse.r = 1.f;
            mat.Diffuse.g = 1.f;
            mat.Diffuse.b = 1.f;
            mat.Diffuse.a = 1.f;
    
            // store material and texture paths
            bool result = mesh->CreateTexture( D3D9Device, i, dpath, npath, mat );
            if( !result )
                {
                // material creation failed
                MessageBox( NULL, "material creation failed!", "FAILED", 0 );
                return false;
                }
            }
    
        return true;
        }
    
    Back to top Terms of Use | Privacy and cookies | Trademarks | Copyright © 2019 Microsoft