# Event handling
Simplygon uses an event system to report e.g. processing progress. By implementing and registering an event callback object, the calling function can receive event updates from the system.
This example shows how to use the Simplygon observer to get progress events.
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#include <string>
#include <stdlib.h>
#include <filesystem>
#include <future>
#include "SimplygonLoader.h"
class CustomObserver : public Simplygon::Observer
{
public:
bool OnProgress(Simplygon::spObject subject, Simplygon::real progressPercent) override
{
printf("Progress: %f\n", progressPercent);
// return false to abort the processing
return true;
}
} customObserver;
void CheckLog(Simplygon::ISimplygon* sg)
{
// Check if any errors occurred.
bool hasErrors = sg->ErrorOccurred();
if (hasErrors)
{
Simplygon::spStringArray errors = sg->CreateStringArray();
sg->GetErrorMessages(errors);
auto errorCount = errors->GetItemCount();
if (errorCount > 0)
{
printf("%s\n", "Errors:");
for (auto errorIndex = 0U; errorIndex < errorCount; ++errorIndex)
{
Simplygon::spString errorString = errors->GetItem((int)errorIndex);
printf("%s\n", errorString.c_str());
}
sg->ClearErrorMessages();
}
}
else
{
printf("%s\n", "No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg->WarningOccurred();
if (hasWarnings)
{
Simplygon::spStringArray warnings = sg->CreateStringArray();
sg->GetWarningMessages(warnings);
auto warningCount = warnings->GetItemCount();
if (warningCount > 0)
{
printf("%s\n", "Warnings:");
for (auto warningIndex = 0U; warningIndex < warningCount; ++warningIndex)
{
Simplygon::spString warningString = warnings->GetItem((int)warningIndex);
printf("%s\n", warningString.c_str());
}
sg->ClearWarningMessages();
}
}
else
{
printf("%s\n", "No warnings.");
}
// Error out if Simplygon has errors.
if (hasErrors)
{
throw std::exception("Processing failed with an error");
}
}
void RunReduction(Simplygon::ISimplygon* sg)
{
// Create the reduction pipeline.
Simplygon::spReductionPipeline sgReductionPipeline = sg->CreateReductionPipeline();
// Add the custom observer to the reduction pipeline.
sgReductionPipeline->AddObserver(&customObserver);
std::string outputScenePath = std::string("output\\") + std::string("ProgressEvent") + std::string("_Output.fbx");
// Start the reduction pipeline.
printf("%s\n", "Start the reduction pipeline.");
sgReductionPipeline->RunSceneFromFile("../../../Assets/SimplygonMan/SimplygonMan.obj", outputScenePath.c_str(), Simplygon::EPipelineRunMode::RunInNewProcess);
// Check log for any warnings or errors.
printf("%s\n", "Check log for any warnings or errors.");
CheckLog(sg);
}
int main()
{
Simplygon::ISimplygon* sg = NULL;
Simplygon::EErrorCodes initval = Simplygon::Initialize( &sg );
if( initval != Simplygon::EErrorCodes::NoError )
{
printf( "Failed to initialize Simplygon: ErrorCode(%d)", (int)initval );
return int(initval);
}
RunReduction(sg);
Simplygon::Deinitialize(sg);
return 0;
}
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System;
using System.IO;
using System.Threading.Tasks;
public class CustomObserver : Simplygon.Observer
{
public override bool OnProgress(Simplygon.spObject subject, float progressPercent)
{
Console.WriteLine($"Progress: {progressPercent}");
// return false to abort the processing
return true;
}
}
public class Program
{
static private CustomObserver customObserver;
static void CheckLog(Simplygon.ISimplygon sg)
{
// Check if any errors occurred.
bool hasErrors = sg.ErrorOccurred();
if (hasErrors)
{
Simplygon.spStringArray errors = sg.CreateStringArray();
sg.GetErrorMessages(errors);
var errorCount = errors.GetItemCount();
if (errorCount > 0)
{
Console.WriteLine("Errors:");
for (uint errorIndex = 0; errorIndex < errorCount; ++errorIndex)
{
string errorString = errors.GetItem((int)errorIndex);
Console.WriteLine(errorString);
}
sg.ClearErrorMessages();
}
}
else
{
Console.WriteLine("No errors.");
}
// Check if any warnings occurred.
bool hasWarnings = sg.WarningOccurred();
if (hasWarnings)
{
Simplygon.spStringArray warnings = sg.CreateStringArray();
sg.GetWarningMessages(warnings);
var warningCount = warnings.GetItemCount();
if (warningCount > 0)
{
Console.WriteLine("Warnings:");
for (uint warningIndex = 0; warningIndex < warningCount; ++warningIndex)
{
string warningString = warnings.GetItem((int)warningIndex);
Console.WriteLine(warningString);
}
sg.ClearWarningMessages();
}
}
else
{
Console.WriteLine("No warnings.");
}
// Error out if Simplygon has errors.
if (hasErrors)
{
throw new System.Exception("Processing failed with an error");
}
}
static void RunReduction(Simplygon.ISimplygon sg)
{
// Create the reduction pipeline.
using Simplygon.spReductionPipeline sgReductionPipeline = sg.CreateReductionPipeline();
// Add the custom observer to the reduction pipeline.
sgReductionPipeline.AddObserver(customObserver);
string outputScenePath = string.Join("", new string[] { "output\\", "ProgressEvent", "_Output.fbx" });
// Start the reduction pipeline.
Console.WriteLine("Start the reduction pipeline.");
sgReductionPipeline.RunSceneFromFile("../../../Assets/SimplygonMan/SimplygonMan.obj", outputScenePath, Simplygon.EPipelineRunMode.RunInNewProcess);
// Check log for any warnings or errors.
Console.WriteLine("Check log for any warnings or errors.");
CheckLog(sg);
}
static int Main(string[] args)
{
using var sg = Simplygon.Loader.InitSimplygon(out var errorCode, out var errorMessage);
if (errorCode != Simplygon.EErrorCodes.NoError)
{
Console.WriteLine( $"Failed to initialize Simplygon: ErrorCode({(int)errorCode}) {errorMessage}" );
return (int)errorCode;
}
customObserver = new CustomObserver();
RunReduction(sg);
return 0;
}
}
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
import math
import os
import sys
import glob
import gc
import threading
from pathlib import Path
from simplygon10 import simplygon_loader
from simplygon10 import Simplygon
class CustomObserver(Simplygon.Observer):
def OnProgress(self, subject: Simplygon.spObject, progressPercent: float):
print("Progress: %f" %(progressPercent))
# return False to abort the processing
return True
customObserver = CustomObserver()
def CheckLog(sg: Simplygon.ISimplygon):
# Check if any errors occurred.
hasErrors = sg.ErrorOccurred()
if hasErrors:
errors = sg.CreateStringArray()
sg.GetErrorMessages(errors)
errorCount = errors.GetItemCount()
if errorCount > 0:
print('Errors:')
for errorIndex in range(errorCount):
errorString = errors.GetItem(errorIndex)
print(errorString)
sg.ClearErrorMessages()
else:
print('No errors.')
# Check if any warnings occurred.
hasWarnings = sg.WarningOccurred()
if hasWarnings:
warnings = sg.CreateStringArray()
sg.GetWarningMessages(warnings)
warningCount = warnings.GetItemCount()
if warningCount > 0:
print('Warnings:')
for warningIndex in range(warningCount):
warningString = warnings.GetItem(warningIndex)
print(warningString)
sg.ClearWarningMessages()
else:
print('No warnings.')
# Error out if Simplygon has errors.
if hasErrors:
raise Exception('Processing failed with an error')
def RunReduction(sg: Simplygon.ISimplygon):
# Create the reduction pipeline.
sgReductionPipeline = sg.CreateReductionPipeline()
# Add the custom observer to the reduction pipeline.
sgReductionPipeline.AddObserver(customObserver)
outputScenePath = ''.join(['output\\', 'ProgressEvent', '_Output.fbx'])
# Start the reduction pipeline.
print("Start the reduction pipeline.")
sgReductionPipeline.RunSceneFromFile('../../../Assets/SimplygonMan/SimplygonMan.obj', outputScenePath, Simplygon.EPipelineRunMode_RunInNewProcess)
# Check log for any warnings or errors.
print("Check log for any warnings or errors.")
CheckLog(sg)
if __name__ == '__main__':
sg = simplygon_loader.init_simplygon()
if sg is None:
exit(Simplygon.GetLastInitializationError())
RunReduction(sg)
sg = None
gc.collect()