Skip to content

Creating an Entropy App

This guide walks you through creating a C++ application that connects to the Entropy Engine and orchestrates a 3D scene. We will use the transient_scene example as a template.

  • Entropy Engine compiled and running (local or remote).
  • CMake 3.20+.
  • C++ 20 compiler.

Your application links against EntropyCanvasSDK and EntropyNetworking.

cmake_minimum_required(VERSION 3.20)
project(MyEntropyApp)
find_package(EntropyCanvasSDK REQUIRED)
find_package(EntropyNetworking REQUIRED)
add_executable(MyEntropyApp main.cpp)
target_link_libraries(MyEntropyApp PRIVATE
EntropyCanvasSDK
EntropyNetworking::Networking
)
# Optional: Link USD for mesh serialization
if(TARGET EntropyCanvasUSD)
target_link_libraries(MyEntropyApp PRIVATE EntropyCanvasUSD)
endif()

The core of an Entropy app is the CanvasClient. It connects to the engine and synchronizes state.

#include <EntropyCanvas/Network/CanvasClient.h>
#include <EntropyCanvas/Scene/SceneGraph.h>
using namespace EntropyCanvas;
int main() {
// 1. Create a transient SceneGraph (local ECS)
SceneGraph scene;
// 2. Connect to the Engine
// Connects to localhost:4433 by default, secure=true
CanvasClient client("127.0.0.1", 4433, true);
if (!client.connect()) {
std::cerr << "Failed to connect to Entropy Engine" << std::endl;
return 1;
}
// 3. Application Loop
while (true) {
// Process network messages
client.poll();
// Push local changes to the engine
// (In a real app, you would update ECS components here)
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
return 0;
}

You can upload ephemeral (transient) assets programmatically. These exist only for the session duration.

#include <EntropyCanvas/Assets/TextureLoader.h>
#include <EntropyCanvas/Network/TextureClient.h>
void uploadMyTexture(CanvasClient& client) {
// Load texture from disk
auto texture = TextureLoader::loadFromFile("Textures/MyTexture.tga");
// Upload synchronously
auto result = client.textureClient()->uploadTextureSync(texture, false /* not persistent */);
if (result.success()) {
std::cout << "Texture ID: " << result.value.toShortHex() << std::endl;
}
}

Meshes are typically serialized to USD format before upload.

#include <EntropyCanvas/USD/MeshData.h>
#include <EntropyCanvas/USD/UsdMeshSerializer.h>
void uploadBox(CanvasClient& client) {
// Create a procedural box
auto mesh = MeshData::box(1.0f);
// Serialize to USD
auto serializeResult = UsdMeshSerializer::serialize(mesh);
// Upload raw bytes
auto* assetClient = client.assetClient();
auto handle = assetClient->upload(serializeResult.data, ContentType::Mesh, false);
// Wait for completion...
}

You can create custom materials with your own shaders.

First, define a ShaderBundle with source code and metadata, then upload it.

#include <EntropyCanvas/Network/ShaderClient.h>
AssetId uploadCustomShader(CanvasClient& client) {
std::string source = R"(
// Custom Slang Shader
#include "EntropyShaderLibrary/Surface.slang"
// Exposed parameters
[vk::binding(0, 1)] Texture2D baseColorTexture;
[vk::binding(1, 1)] SamplerState baseColorSampler;
// ... shader implementation ...
)";
ShaderBundle bundle;
bundle.mainSource = source;
bundle.metadata.name = "MyCustomShader";
auto* shaderClient = client.shaderClient();
auto handle = shaderClient->uploadShader(bundle, false);
// Poll until complete
while (!handle->isComplete()) client.poll();
return handle->result();
}

Once you have a Shader AssetId and a Texture AssetId, you can combine them into a Material.

#include <EntropyCanvas/Assets/MaterialData.h>
AssetId createMyMaterial(CanvasClient& client, AssetId shaderId, AssetId textureId) {
MaterialData mat;
mat.name = "MyMaterial";
mat.shaderAssetId = shaderId;
// Set material properties
mat.setVec4("baseColor", glm::vec4(1.0f));
mat.setFloat("roughness", 0.5f);
mat.setFloat("metallic", 0.0f);
// Bind texture to the shader parameter "baseColorTexture"
mat.setTextureRef("baseColorTexture", textureId);
// Create on server
auto handle = client.createMaterial(mat);
while (!handle->isComplete()) client.poll();
return handle->result();
}

Finally, link everything together in the ECS.

// Create an entity in the local registry
auto entity = scene.getWorld().entity("MyCube");
// Add Transform component
entity.set<Transform>({
.position = {0, 0, 0},
.scale = {1, 1, 1}
});
// Add Mesh component
// Links the Mesh Asset ID + List of Material IDs
entity.set<Mesh>({
.meshAssetId = myMeshId,
.materialIds = {myMaterialId} // [0] corresponds to submesh 0
});
// Sync to Engine
client.syncEntity(entity);
// Bind materials (triggers subscription on server)
client.bindMeshMaterials(entity.id(), {myMaterialId});

Lights are added as components.

// Create a Point Light
auto light = scene.getWorld().entity("LightSource");
light.set<Transform>({.position = {0, 5, 0}});
light.set<Light>(Light::sphere(10.0f, glm::vec3(1, 0.9, 0.8)));
client.syncEntity(light);
  1. Link EntropyCanvasSDK.
  2. Connect via CanvasClient.
  3. Upload Assets:
    • Textures: TextureClient::uploadTextureSync
    • Shaders: ShaderClient::uploadShader
    • Meshes: AssetClient::upload
  4. Create Materials: Define MaterialData, set properties, bind Textures, and call client.createMaterial.
  5. Create Entities: Add Transform and Mesh components, utilizing the upload AssetIds.
  6. Sync: Call client.syncEntity to replicate to the engine.

See EntropyCanvasSDK/examples/transient_scene/main.cpp for a complete working example.