Infinity Engine v0.6.20
C++ API Documentation
Loading...
Searching...
No Matches
Working with Procedural Systems

ProceduralSystems are the core execution units in the Infinity Engine - complete directed acyclic graphs of interconnected components that generate procedural content. This tutorial covers everything you need to know about configuring inputs, controlling execution, and working with outputs.

Understanding Procedural Systems

A ProceduralSystem represents a complete workflow:

  • Input ports: Parameters and data the system needs to operate
  • Internal components: Connected graph of processing components
  • Output ports: Generated results available after execution
  • Execution model: Dependency-ordered component execution
  • Random seed: Reproducible generation control

Basic System Operations

Loading and Inspecting a System

#include <Infinity/Engine/InfinityEngine.h>
#include <Infinity/Types/All.hpp>
void inspectSystem() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
if (!system) {
std::cerr << "System not found!" << std::endl;
return;
}
std::cout << "System ID: " << system->id() << std::endl;
// Systems are ready to configure and execute
std::cout << "System loaded and ready for configuration" << std::endl;
}
Main entry point to the InfinityEngine API for procedural generation.
Definition InfinityEngine.hpp:26
INFINITY_API_PUBLIC void InfinityInit(void)
Initializes the Infinity Engine.

Setting Input Parameters

void configureSystemInputs() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
// Set various input types
system->setIn("Resolution", 1024); // Integer
system->setIn("Scale", 50.0f); // Float
system->setIn("EnableErosion", true); // Boolean
system->setIn("TerrainName", std::string("MyTerrain")); // String
// Set vector inputs
system->setIn("Offset", Vec3(10.0f, 0.0f, 15.0f));
// Set more complex data types
Array2D heightmapData(256, 256, 0.0f);
// Fill with data...
system->setIn("InputHeightmap", std::move(heightmapData));
}
Two-dimensional array container for grid-based data in procedural generation.
Definition Array2D.hpp:82
t_Vector3< float > Vector3
Alias for t_Vector3<float>, the default 3D vector type.
Definition Vector3.hpp:580

Executing the System

void executeSystem() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
try {
// Configure inputs
system->setIn("Resolution", 512);
system->setIn("Scale", 100.0f);
system->setSeed(12345); // For reproducible results
// Execute the system
std::cout << "Executing system..." << std::endl;
auto start = std::chrono::high_resolution_clock::now();
system->execute();
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
std::cout << "Execution completed in " << duration.count() << " ms" << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Execution failed: " << e.what() << std::endl;
}
}

Retrieving Output Data

void retrieveSystemOutputs() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
// Configure and execute
system->setIn("Resolution", 256);
system->setSeed(54321);
system->execute();
try {
// Retrieve different output types
using Texture = Infinity::Types::Rendering::Texture;
// Get mesh output
const auto& terrainMesh = system->getOut<Mesh>("TerrainMesh");
std::cout << "Generated mesh with " << terrainMesh.vertexBuffer.positions.size()
<< " vertices" << std::endl;
// Get heightmap data
const auto& heightmap = system->getOut<Array2D>("Heightmap");
std::cout << "Heightmap dimensions: " << heightmap.width() << "x"
<< heightmap.height() << std::endl;
// Get texture output
const auto& colorMap = system->getOut<Texture>("Albedo");
std::cout << "Color texture: " << colorMap.width() << "x" << colorMap.height()
<< ", " << colorMap.channels << " channels" << std::endl;
// Get simple value outputs
float actualScale = system->getOut<float>("ActualScale");
int triangleCount = system->getOut<int>("TriangleCount");
std::cout << "Generated " << triangleCount << " triangles at scale "
<< actualScale << std::endl;
}
catch (const std::bad_cast& e) {
std::cerr << "Output type mismatch: " << e.what() << std::endl;
}
catch (const std::runtime_error& e) {
std::cerr << "Output retrieval error: " << e.what() << std::endl;
}
}
size_t size() const noexcept override
Gets the number of elements in the array.
Definition Array.hpp:696
Complete 3D geometry definition with vertices, indices, and material partitioning.
Definition Mesh.hpp:135

Random Seed Management

Basic Seed Control

void demonstrateSeedControl() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
// Configure consistent inputs
system->setIn("Resolution", 256);
system->setIn("Scale", 50.0f);
// Generate with specific seed
system->setSeed(12345);
system->execute();
// Save first result
const auto& result1 = system->getOut<Infinity::Types::Containers::Array2D<float>>("Heightmap");
// Generate again with same seed - should be identical
system->setSeed(12345);
system->execute();
const auto& result2 = system->getOut<Infinity::Types::Containers::Array2D<float>>("Heightmap");
// Verify they're identical
bool identical = (result1.width() == result2.width() &&
result1.height() == result2.height());
if (identical) {
for (size_t i = 0; i < result1.width() * result1.height() && identical; ++i) {
identical = (result1.data()[i] == result2.data()[i]);
}
}
std::cout << "Results with same seed are " << (identical ? "identical" : "different")
<< std::endl;
}

Systematic Seed Variation

void generateVariations() {
Infinity::Engine::InfinityEngine engine("terrain.infinitycore");
auto system = engine.system("TerrainGenerator");
// Base configuration
system->setIn("Resolution", 128);
system->setIn("Scale", 25.0f);
// Generate multiple variations
std::vector<uint64_t> seeds = {1000, 2000, 3000, 4000, 5000};
for (size_t i = 0; i < seeds.size(); ++i) {
std::cout << "Generating variation " << (i + 1) << " with seed " << seeds[i] << std::endl;
system->setSeed(seeds[i]);
system->execute();
// Could save each result with a unique name
const auto& mesh = system->getOut<Infinity::Types::Rendering::Mesh>("TerrainMesh");
std::cout << " Generated mesh with " << mesh.vertexBuffer.positions.size()
<< " vertices" << std::endl;
// In a real application, you'd save or process each variation
}
}
VertexBuffer vertexBuffer
Vertex attribute data for the mesh.
Definition Mesh.hpp:143
Containers::Array< Infinity::Types::Math::Vector3 > positions
Vertex positions in object/local space.
Definition VertexBuffer.hpp:117

Loop Configuration

Integer Range Loops

NOTE that the system looping feature is actively under development and subject to change.

void demonstrateIntegerLoops() {
Infinity::Engine::InfinityEngine engine("batch_processor.infinitycore");
auto system = engine.system("BatchTerrainGenerator");
// Configure base parameters
system->setIn("BaseScale", 50.0f);
system->setIn("Resolution", 256);
// Set up loop: generate 10 terrain chunks
// Loop variable will go from 0 to 9 (step 1)
bool loopSet = system->setLoop(0, 10, 1);
if (!loopSet) {
std::cerr << "Failed to configure loop" << std::endl;
return;
}
// Execute the loop - system runs 10 times
system->setSeed(12345);
system->execute();
std::cout << "Batch generation completed" << std::endl;
// Clear loop for normal execution
system->clearLoop();
}

Advanced Usage Patterns

Conditional System Configuration

void configureDynamicSystem() {
Infinity::Engine::InfinityEngine engine("adaptive_terrain.infinitycore");
auto system = engine.system("AdaptiveTerrainGenerator");
// Adaptive configuration based on target quality
enum class QualityLevel { Low, Medium, High, Ultra };
QualityLevel targetQuality = QualityLevel::High;
switch (targetQuality) {
case QualityLevel::Low:
system->setIn("Resolution", 128);
system->setIn("Subdivisions", 2);
system->setIn("EnableDetailPasses", false);
break;
case QualityLevel::Medium:
system->setIn("Resolution", 256);
system->setIn("Subdivisions", 4);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 2);
break;
case QualityLevel::High:
system->setIn("Resolution", 512);
system->setIn("Subdivisions", 6);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 4);
system->setIn("EnableErosion", true);
break;
case QualityLevel::Ultra:
system->setIn("Resolution", 1024);
system->setIn("Subdivisions", 8);
system->setIn("EnableDetailPasses", true);
system->setIn("DetailLevels", 6);
system->setIn("EnableErosion", true);
system->setIn("EnableVegetation", true);
break;
}
system->setSeed(12345);
system->execute();
std::cout << "Generated terrain at quality level "
<< static_cast<int>(targetQuality) << std::endl;
}

Pipeline System Coordination

void coordinateSystemPipeline() {
Infinity::Engine::InfinityEngine engine("world_generation.infinitycore");
// Get systems for different generation stages
auto terrainSystem = engine.system("TerrainGeneration");
auto vegetationSystem = engine.system("VegetationPlacement");
auto weatherSystem = engine.system("WeatherSimulation");
if (!terrainSystem || !vegetationSystem || !weatherSystem) {
std::cerr << "Missing required systems" << std::endl;
return;
}
uint64_t masterSeed = 12345;
// Stage 1: Generate base terrain
std::cout << "Stage 1: Generating terrain..." << std::endl;
terrainSystem->setSeed(masterSeed);
terrainSystem->setIn("WorldSize", 1000.0f);
terrainSystem->setIn("Resolution", 512);
terrainSystem->execute();
// Extract terrain data for next stage
const auto& terrainMesh = terrainSystem->getOut<Infinity::Types::Rendering::Mesh>("Terrain");
const auto& heightmap = terrainSystem->getOut<Infinity::Types::Containers::Array2D<float>>("Heightmap");
// Stage 2: Place vegetation based on terrain
std::cout << "Stage 2: Placing vegetation..." << std::endl;
vegetationSystem->setSeed(masterSeed + 1); // Related but different seed
vegetationSystem->setIn("TerrainMesh", terrainMesh);
vegetationSystem->setIn("Heightmap", heightmap);
vegetationSystem->setIn("Density", 0.7f);
vegetationSystem->execute();
// Stage 3: Weather effects
std::cout << "Stage 3: Generating weather..." << std::endl;
weatherSystem->setSeed(masterSeed + 2);
weatherSystem->setIn("Terrain", terrainMesh);
weatherSystem->setIn("Temperature", 15.0f);
weatherSystem->execute();
std::cout << "World generation pipeline completed" << std::endl;
}

Error Handling and Debugging

Comprehensive Error Handling

void robustSystemExecution() {
try {
Infinity::Engine::InfinityEngine engine("complex_system.infinitycore");
auto system = engine.system("ComplexGenerator");
if (!system) {
throw std::runtime_error("Required system not found");
}
// Validate inputs before execution
try {
system->setIn("Resolution", 512);
system->setIn("Scale", 100.0f);
system->setSeed(12345);
}
catch (const std::exception& e) {
std::cerr << "Input configuration failed: " << e.what() << std::endl;
throw;
}
// Execute with timeout monitoring
std::cout << "Starting system execution..." << std::endl;
auto startTime = std::chrono::steady_clock::now();
system->execute();
auto endTime = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(endTime - startTime);
if (duration.count() > 30) {
std::cerr << "Warning: Execution took " << duration.count() << " seconds" << std::endl;
}
// Validate outputs
try {
const auto& mesh = system->getOut<Infinity::Types::Rendering::Mesh>("result");
if (mesh.vertexBuffer.positions.empty()) {
std::cerr << "Warning: Generated mesh is empty" << std::endl;
} else {
std::cout << "Successfully generated mesh with "
<< mesh.vertexBuffer.positions.size() << " vertices" << std::endl;
}
}
catch (const std::bad_cast& e) {
std::cerr << "Output type validation failed: " << e.what() << std::endl;
}
}
catch (const std::runtime_error& e) {
std::cerr << "System execution failed: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Unknown error during system execution" << std::endl;
}
}

Best Practices

  1. Always validate system existence before configuration
  2. Set inputs before calling execute() - order matters
  3. Use consistent seed management for reproducible results
  4. Handle execution exceptions gracefully
  5. Verify output types match your expectations
  6. Clear loops when switching between different execution modes
  7. Cache expensive system results when appropriate
  8. Monitor execution time for performance optimization
  9. Use meaningful variable names for clarity
  10. Document system dependencies when coordinating multiple systems

Troubleshooting

Input configuration fails:

  • Verify input port names match the system definition
  • Check input data types are compatible
  • Ensure required inputs are provided

Execution hangs or fails:

  • Check for missing input dependencies
  • Verify all component plugins are available

Output retrieval fails:

  • Ensure execute() completed successfully
  • Verify output port names and types
  • Check that the system actually produces the expected outputs

Inconsistent results:

  • Verify seed is being set consistently
  • Check for unintended input variations

Next Steps

Now that you understand system operations: