///////////////////////////////////////////////////////////////////////////
//
//  System:    Simplygon
//  File:      VertexColorBakingExample.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# 
//
//  Utilizes the VertexColorBaker to bake all a specific channel of the 
//  materials into a vertex color field.
//
//
///////////////////////////////////////////////////////////////////////////
#include "../Common/Example.h"
void RunBakingTesting( const std::string& readFrom, const std::string& writeToBaked );
int main( int argc, char* argv[] )
    {
    try
    {
        InitExample();
        // Set global variable. Using Orthonormal method for calculating tangentspace.
        sg->SetGlobalSetting("DefaultTBNType", SG_TANGENTSPACEMETHOD_ORTHONORMAL);
        std::string assetPath = GetAssetPath();
        // Run the example code
        //
        RunBakingTesting(assetPath + "SimplygonMan/SimplygonMan.obj", "SimplygonMan_bakedDiffuse");
        DeinitExample();
    }
    catch (const std::exception& ex)
    {
        std::cerr << ex.what() << std::endl;
        return -1;
    }
    return 0;
    }
void RunBakingTesting( const std::string& readFrom, const std::string& writeToBaked )
    {
    // Import geometries from a file and optimize them. Generate a mapping image
    // from the LOD to the original that will be used to sample the materials and
    // populate the vertex color field.
    // Generate the output filenames
    //
    std::string output_geometry_baked_filename = writeToBaked + ".sgscene";
    // Load object from file
    //
    spWavefrontImporter objReader = sg->CreateWavefrontImporter();
    objReader->SetImportFilePath( readFrom.c_str() );
    if( !objReader->RunImport() )
        throw std::exception("Failed to load input file!");
    spScene scene = objReader->GetScene();
    // Reducer
    //
    spReductionProcessor reducer = sg->CreateReductionProcessor();
    reducer->SetScene( scene );
    // Set the Repair Settings.
    //
    spRepairSettings repairSettings = reducer->GetRepairSettings();
    repairSettings->SetWeldDist( 0.0f );
    repairSettings->SetTjuncDist( 0.0f );
    // Set the Reduction Settings.
    //
    spReductionSettings reductionSettings = reducer->GetReductionSettings();
    reductionSettings->SetTriangleRatio( 0.5 );
    // Set the Image Mapping Settings.
    //
    spMappingImageSettings mappingSettings = reducer->GetMappingImageSettings();
    // Without this we cannot fetch data from the original geometry, and thus not
    // populate the vertex color field
    //
    mappingSettings->SetGenerateMappingImage( true );
    // The higher the number, the fewer texture-borders.
    //
    mappingSettings->SetParameterizerMaxStretch( 0.5f );
    mappingSettings->SetGutterSpace( 1 );
    // When only using the mapping image to bake to vert colors, the resolution and super-sampling
    // effectively decides how many samples will be used for each vertex. Higher sizes means better quality.
    //
    mappingSettings->SetWidth( 1024 );
    mappingSettings->SetHeight( 1024 );
    mappingSettings->SetMultisamplingLevel( 1 );
    // If the asset does not already have unique UVs per vertex, i.e. many textures or mirrored UVs,
    // a new unique UV set will need to be generated for the mapping image.
    //
    mappingSettings->SetGenerateTexCoords( true );
    mappingSettings->SetTexCoordLevel( (SG_NUM_SUPPORTED_TEXTURE_CHANNELS - 1) );
    reducer->RunProcessing();
    // Mapping image has now been generated
    //
    spMappingImage mappingImage = reducer->GetMappingImage();
    // Now, finally, bake the entire diffuse channel into color field 0
    //
    spVertexColorBaker baker = sg->CreateVertexColorBaker();
    baker->SetScene( scene ); // The geometry in which you want to create the new vertex color field
    baker->SetMappingImage( mappingImage ); // The mapping image mapping the original geometry to the geometry set above
    baker->SetSourceMaterials( scene->GetMaterialTable() ); // The material table from which the sampling will be done
    baker->SetSourceTextures( scene->GetTextureTable() );
    baker->SetChannelName( SG_MATERIAL_CHANNEL_DIFFUSE ); // The channel that will be cast to the color field
    baker->SetOutputColorLevelName( "0" ); // The output color level
    baker->SetColorSpaceEdgeThreshold( 3.0 ); // This will determine how many "hard borders" will exist in the color field
    // It is essentially a RGBA color space difference threshold, where smaller distances are merged.
    // This means that the largest distance is sqrt(4) = 2, so 3.0 will produce all smooth borders.
    baker->Bake();
    // Since .obj does not support colors, we export the result as a scene binary.
    //
    scene->SaveToFile( output_geometry_baked_filename.c_str() );
    ///////////////////////////////////
    //Output a map of the vertex colors
    spScene sceneWithVertexColors = sg->CreateScene();
    sceneWithVertexColors->LoadFromFile(output_geometry_baked_filename.c_str());
    spGeometryData geom = sceneWithVertexColors->NewCombinedGeometry();
    spRealArray colors = geom->GetColors(0);
    sceneWithVertexColors->GetTextureTable()->Clear();
    sceneWithVertexColors->GetMaterialTable()->Clear();
    spShadingVertexColorNode exitNode = sg->CreateShadingVertexColorNode();
    exitNode->SetVertexColorIndex(0);
    spMaterial mat = sg->CreateMaterial();
    mat->SetShadingNetwork(SG_MATERIAL_CHANNEL_DIFFUSE, exitNode);
    sceneWithVertexColors->GetMaterialTable()->AddMaterial(mat);
    //Use the reduction processor to generate the mapping image needed for outputting the vertex color map
    spReductionProcessor red = sg->CreateReductionProcessor();
    red->SetScene(sceneWithVertexColors);
    red->GetMappingImageSettings()->SetGenerateMappingImage(true);
    red->GetMappingImageSettings()->SetUseFullRetexturing(true);
    red->RunProcessing();
    int id = sceneWithVertexColors->SelectNodes("ISceneMesh");
    spSelectionSet set = sceneWithVertexColors->GetSelectionSetTable()->GetSelectionSet(id);
    for (uint i = 0; i < set->GetItemCount(); ++i)
        {
        spGeometryData geomWithVertexColors = SafeCast<ISceneMesh>(sceneWithVertexColors->GetNodeByGUID(set->GetItem(i)))->GetGeometry();
        for (uint m = 0; m < geomWithVertexColors->GetMaterialIds()->GetItemCount(); ++m)
            {
            geomWithVertexColors->GetMaterialIds()->SetItem(m, 0);
            }
        }
    //Use a colorcaster to output the vertex colors
    spColorCaster caster = sg->CreateColorCaster();
    caster->SetSourceMaterials(sceneWithVertexColors->GetMaterialTable());
    caster->SetMappingImage(red->GetMappingImage());
    caster->SetColorType(SG_MATERIAL_CHANNEL_DIFFUSE);
    caster->SetOutputFilePath("vertexcolors.png");
    caster->RunProcessing();
    }