Skip to content

Instantly share code, notes, and snippets.

@oteguro
Last active May 10, 2023 17:58
Show Gist options
  • Save oteguro/9505967daf942c939a5bf4183412bafe to your computer and use it in GitHub Desktop.
Save oteguro/9505967daf942c939a5bf4183412bafe to your computer and use it in GitHub Desktop.
// simplygon_minimal_example.cpp
#define WIN32_LEAN_AND_MEAN
#include <fstream>
#include <cassert>
#include <cstdio>
#include <cstdint>
#include <vector>
#include <string>
#include <windows.h>
#include <tchar.h>
#include <SimplygonSDK.h>
namespace
{
typedef int (CALLBACK* PROC_INITIALIZE_SIMPLYGON)(const char* license_data, SimplygonSDK::ISimplygonSDK **pInterfacePtr);
typedef void (CALLBACK* PROC_DEINITIALIZE_SIMPLYGON)();
void LoadLicenseTextFromFile(std::string& text, LPCTSTR licencePath)
{
text.clear();
std::ifstream t;
t.open(licencePath);
std::string line;
while (t)
{
std::getline(t, line);
text += line;
}
t.close();
}
// Simplygon error callback.
class SimplygonErrorHandler : public SimplygonSDK::rerrorhandler
{ // Error handler.
virtual void HandleError(
SimplygonSDK::IObject *object,
const char *interfacename,
const char *methodname,
SimplygonSDK::rid errortype,
const char *errortext
)
{
std::fprintf(stderr, "A SimplygonSDK error occured!\n");
std::fprintf(stderr, "\tInterface: %s (%p)\n", interfacename, object);
std::fprintf(stderr, "\tMethod: %s\n", methodname);
std::fprintf(stderr, "\tError Type: %d\n", errortype);
std::fprintf(stderr, "\tError Description: %s\n", errortext);
#if _DEBUG
__debugbreak();
#endif
exit(1);
}
}; // class SimplygonErrorHandler
static SimplygonErrorHandler s_errorHandler;
class SimpleSimplygonInterface
{
SimplygonSDK::ISimplygonSDK* sdkInterface;
HINSTANCE dllHandle;
PROC_INITIALIZE_SIMPLYGON InitializeSimplygonSDKPtr;
PROC_DEINITIALIZE_SIMPLYGON DeinitializeSimplygonSDKPtr;
public:
SimpleSimplygonInterface()
: sdkInterface(nullptr)
, dllHandle (nullptr)
, InitializeSimplygonSDKPtr (nullptr)
, DeinitializeSimplygonSDKPtr(nullptr)
{
}
bool Initialize(LPCTSTR dllPath, LPCTSTR licencePath)
{
// Load library DLL.
dllHandle = LoadLibrary (dllPath);
assert(dllHandle != nullptr); // Please check your DLL path.
if (dllHandle == nullptr)
{
return false;
}
// Retrieve Simplygon SDK API.
InitializeSimplygonSDKPtr = (PROC_INITIALIZE_SIMPLYGON) GetProcAddress(dllHandle, "InitializeSimplygonSDK");
DeinitializeSimplygonSDKPtr = (PROC_DEINITIALIZE_SIMPLYGON)GetProcAddress(dllHandle, "DeinitializeSimplygonSDK");
assert(InitializeSimplygonSDKPtr != nullptr);
assert(DeinitializeSimplygonSDKPtr != nullptr);
// Load license.
std::string licenseText;
LoadLicenseTextFromFile(licenseText, licencePath);
assert(!licenseText.empty()); // Please check your license path.
// Initialize Simplygon.
int retval = InitializeSimplygonSDKPtr(licenseText.c_str(), &sdkInterface);
if (retval != SimplygonSDK::SG_ERROR_NOERROR)
{
return false;
}
sdk().SetErrorHandler(&s_errorHandler);
fprintf(stderr, "Initialize Simplygon SDK[%s]\n", sdkInterface->GetVersion());
return true;
}
void Deinitialize()
{
if (dllHandle == nullptr)
{
return;
}
DeinitializeSimplygonSDKPtr();
FreeLibrary(dllHandle);
dllHandle = nullptr;
InitializeSimplygonSDKPtr = nullptr;
DeinitializeSimplygonSDKPtr = nullptr;
sdkInterface = nullptr;
}
SimplygonSDK::ISimplygonSDK& sdk()
{
assert( sdkInterface != nullptr); // Not initialized yet.
return *sdkInterface;
}
}; // class SimpleSimplygonInterface
} // unnamed namespace
namespace sample
{
struct Vertex { float x, y, z; Vertex() :x(0), y(0), z(0) {} }; // struct Vertex
void GenerateTrianglePolygonMesh(std::vector<Vertex>& vtx, std::vector<int32_t>& idx)
{
const int gridX = 4;
const int gridY = 4;
for (int y = 0; y < gridY; ++y)
{
for (int x = 0; x < gridX; ++x)
{
Vertex v;
v.x = static_cast<float>(x);
v.y = static_cast<float>(y);
v.z = 0;
vtx.push_back(v);
}
}
int triangleCount = (gridX - 1) * (gridY - 1) * 2;
for (int t = 0; t < triangleCount; ++t)
{
int quadIndex = (t / 2);
int quadX = (quadIndex) % (gridX - 1);
int quadY = (quadIndex) / (gridX - 1);
if((t%2) == 0)
{
int i0 = ((quadY ) * gridX) + quadX;
int i1 = i0 + 1;
int i2 = ((quadY + 1) * gridX) + quadX;
idx.push_back(i0);
idx.push_back(i1);
idx.push_back(i2);
}
else
{
int i0 = ((quadY ) * gridX) + quadX + 1;
int i1 = ((quadY + 1) * gridX) + quadX + 1;
int i2 = i1 - 1;
idx.push_back(i0);
idx.push_back(i1);
idx.push_back(i2);
}
}
}
void DumpTrianglePolygonMesh(std::vector<Vertex>& vtx, std::vector<int32_t>& idx, const char* annotation)
{
fprintf(stderr, "----------------\n[%s]\n", annotation);
fprintf(stderr, "vtx count = %d / idx count = %d\n", static_cast<int>(vtx.size()), static_cast<int>(idx.size()));
for (auto& v : vtx)
{
fprintf(stderr, "vtx [%1.1f, %1.1f, %1.1f]\n", v.x, v.y, v.z);
}
fprintf(stderr, "\n");
int triangleCount = static_cast<int>(idx.size()) / 3;
for (int i = 0; i < triangleCount; ++i)
{
int ix = i * 3;
fprintf(stderr, "tri [%2d]-[%2d]-[%2d]\n", idx[ix], idx[ix + 1], idx[ix + 2]);
}
fprintf(stderr, "\n");
}
void SetReductionSettings(SimplygonSDK::spReductionProcessor rp, unsigned int screenSize)
{
SimplygonSDK::spReductionSettings reductionSettings = rp->GetReductionSettings();
reductionSettings->SetReductionTargets(SimplygonSDK::SG_REDUCTIONTARGET_ONSCREENSIZE);
reductionSettings->SetUseAutomaticSymmetryDetection(true);
reductionSettings->SetSymmetryDetectionTolerance(0.01f);
reductionSettings->SetDataCreationPreferences(SimplygonSDK::SG_DATACREATIONPREFERENCES_PREFER_ORIGINAL_DATA); // SG_DATACREATIONPREFERENCES_ONLY_USE_ORIGINAL_DATA かな.
reductionSettings->SetOnScreenSize(screenSize);
reductionSettings->SetStopCondition(SimplygonSDK::SG_STOPCONDITION_ANY);
reductionSettings->SetMaxDeviation(0.01f);
reductionSettings->SetInwardMoveMultiplier(0.01f);
reductionSettings->SetOutwardMoveMultiplier(0.0f);
}
#define SDK() simplygon.sdk()
void DoSimplePolygonReduction(SimpleSimplygonInterface& simplygon, std::vector<Vertex>& vtx, std::vector<int32_t>& idx)
{
int32_t vertexCount = static_cast<int32_t>(vtx.size());
int32_t indexCount = static_cast<int32_t>(idx.size());
int32_t triangleCount = indexCount / 3;
//----------------
// Import geometry data.
SimplygonSDK::spScene scene = SDK().CreateScene();
SimplygonSDK::spGeometryData geometry = SDK().CreateGeometryData();
SimplygonSDK::spRealArray position = geometry->GetCoords();
geometry->SetVertexCount(vertexCount);
geometry->SetTriangleCount(triangleCount);
SimplygonSDK::spRealArray vertexPositionArray = geometry->GetCoords();
SimplygonSDK::spRidArray indexArray = geometry->GetVertexIds();
for (int i = 0; i < vertexCount; ++i)
{
vertexPositionArray->SetTuple(i, &(vtx[i].x));
}
for (int i = 0; i < indexCount; ++i)
{
indexArray->SetItem(i, idx[i]);
}
SimplygonSDK::spSceneMesh sceneMesh = SDK().CreateSceneMesh();
sceneMesh->SetGeometry(geometry);
scene->GetRootNode()->AddChild(sceneMesh);
//----------------
// Execute polygon reduction.
const unsigned int screenSize = 1000;
SimplygonSDK::spReductionProcessor rp = SDK().CreateReductionProcessor();
SetReductionSettings(rp, screenSize); // You can choose various settings in simplygon...
rp->SetScene(scene);
rp->RunProcessing();
//----------------
// Retrieve geometry data.
SimplygonSDK::spGeometryData simplifiedGeometry = sceneMesh->GetGeometry();
SimplygonSDK::spRealArray simplifiedVertexArray = simplifiedGeometry->GetCoords();
SimplygonSDK::spRidArray simplifiedIndexArray = simplifiedGeometry->GetVertexIds();
unsigned int newVertexCount = simplifiedGeometry->GetVertexCount ();
unsigned int newIndexCount = simplifiedGeometry->GetTriangleCount() * 3;
assert(newVertexCount > 0);
assert(newIndexCount > 0);
std::vector<Vertex> ov(newVertexCount, Vertex());
std::vector<int32_t> oi(newIndexCount, 0);
for (unsigned int i = 0; i < newVertexCount; ++i)
{
SimplygonSDK::spRealData vertexTuple = SDK().CreateRealData();
simplifiedVertexArray->GetTuple(i, vertexTuple);
ov[i].x = vertexTuple[0];
ov[i].y = vertexTuple[1];
ov[i].z = vertexTuple[2];
}
for (unsigned int i = 0; i < newIndexCount; ++i)
{
uint32_t newIndex = simplifiedIndexArray->GetItem(i);
oi[i] = newIndex;
}
std::swap(ov, vtx);
std::swap(oi, idx);
}
#ifdef SDK
#undef SDK
#endif
} // namespace sample
using namespace sample;
int main(int argc, char* argv[])
{
// DLL / license path.
// Note : If you would like to use multibyte code set, use LPCSTR instead.
LPCTSTR dllPath = L"C:\\Program Files\\Simplygon\\8\\Tools\\SimplygonRedistUE4\\Dependencies\\Common\\Engine\\Binaries\\ThirdParty\\NotForLicensees\\Simplygon\\SimplygonSDKRuntimeReleasex64.dll";
LPCTSTR licPath = L"C:\\Users\\[Your user name]\\AppData\\Local\\DonyaLabs\\SimplygonSDK\\Simplygon_8_license.dat";
SimpleSimplygonInterface simplygon;
simplygon.Initialize(dllPath, licPath);
{
std::vector<Vertex> vtx;
std::vector<int32_t> idx;
GenerateTrianglePolygonMesh(vtx, idx);
DumpTrianglePolygonMesh(vtx, idx, "before reduction.");
DoSimplePolygonReduction(simplygon, vtx, idx);
DumpTrianglePolygonMesh(vtx, idx, "after reduction.");
}
simplygon.Deinitialize();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment