Editor/MeshEditHandlers.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Sandbox;
using HalfEdgeMesh;
using Editor.MeshEditor;
namespace SboxMcpServer;
/// <summary>
/// General-purpose mesh manipulation MCP tools for S&box.
/// Provides tools for creating primitive meshes, editing vertices, faces, and materials,
/// and querying mesh information. Integrates with S&box's native mesh editing system.
/// </summary>
internal static class MeshEditHandlers
{
private static readonly JsonSerializerOptions _json = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull
};
// ── create_block ─────────────────────────────────────────────────────────
/// <summary>
/// Creates a primitive block using PrimitiveBuilder and PolygonMesh.
/// This creates proper mesh geometry compatible with S&box's mesh editing tools.
/// </summary>
internal static object CreateBlock( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
// Extract parameters
float x = OzmiumSceneHelpers.Get( args, "x", 0f );
float y = OzmiumSceneHelpers.Get( args, "y", 0f );
float z = OzmiumSceneHelpers.Get( args, "z", 0f );
float sizeX = OzmiumSceneHelpers.Get( args, "sizeX", 100f );
float sizeY = OzmiumSceneHelpers.Get( args, "sizeY", 100f );
float sizeZ = OzmiumSceneHelpers.Get( args, "sizeZ", 100f );
string materialPath = OzmiumSceneHelpers.Get( args, "materialPath", "materials/dev/reflectivity_30.vmat" );
string name = OzmiumSceneHelpers.Get( args, "name", "Block" );
try
{
// Create the GameObject
var gameObject = scene.CreateObject();
gameObject.Name = name;
gameObject.WorldPosition = new Vector3( x, y, z );
// Load material
var material = MaterialHelper.LoadMaterialOrDefault( materialPath );
// Create a box primitive using the PrimitiveBuilder pattern
var boxMins = new Vector3( -sizeX / 2f, -sizeY / 2f, -sizeZ / 2f );
var boxMaxs = new Vector3( sizeX / 2f, sizeY / 2f, sizeZ / 2f );
var box = new BBox( boxMins, boxMaxs );
// Create vertices for a cube (winding matches S&box BlockPrimitive)
var vertices = new List<Vector3>
{
// Front face (z = maxs.z, normal +Z)
new( boxMins.x, boxMins.y, boxMaxs.z ),
new( boxMaxs.x, boxMins.y, boxMaxs.z ),
new( boxMaxs.x, boxMaxs.y, boxMaxs.z ),
new( boxMins.x, boxMaxs.y, boxMaxs.z ),
// Back face (z = mins.z, normal -Z)
new( boxMins.x, boxMaxs.y, boxMins.z ),
new( boxMaxs.x, boxMaxs.y, boxMins.z ),
new( boxMaxs.x, boxMins.y, boxMins.z ),
new( boxMins.x, boxMins.y, boxMins.z ),
// Top face (y = maxs.y, normal +Y)
new( boxMaxs.x, boxMaxs.y, boxMins.z ),
new( boxMins.x, boxMaxs.y, boxMins.z ),
new( boxMins.x, boxMaxs.y, boxMaxs.z ),
new( boxMaxs.x, boxMaxs.y, boxMaxs.z ),
// Bottom face (y = mins.y, normal -Y)
new( boxMaxs.x, boxMins.y, boxMaxs.z ),
new( boxMins.x, boxMins.y, boxMaxs.z ),
new( boxMins.x, boxMins.y, boxMins.z ),
new( boxMaxs.x, boxMins.y, boxMins.z ),
// Right face (x = maxs.x, normal +X)
new( boxMaxs.x, boxMaxs.y, boxMaxs.z ),
new( boxMaxs.x, boxMins.y, boxMaxs.z ),
new( boxMaxs.x, boxMins.y, boxMins.z ),
new( boxMaxs.x, boxMaxs.y, boxMins.z ),
// Left face (x = mins.x, normal -X)
new( boxMins.x, boxMaxs.y, boxMins.z ),
new( boxMins.x, boxMins.y, boxMins.z ),
new( boxMins.x, boxMins.y, boxMaxs.z ),
new( boxMins.x, boxMaxs.y, boxMaxs.z )
};
// Create new PolygonMesh and populate it
var mesh = new PolygonMesh();
var hVertices = mesh.AddVertices( vertices.ToArray() );
// Define faces using vertex indices (counter-clockwise winding)
var faceDefinitions = new[]
{
new[] { 0, 1, 2, 3 }, // Front
new[] { 4, 5, 6, 7 }, // Back
new[] { 8, 9, 10, 11 }, // Top
new[] { 12, 13, 14, 15 }, // Bottom
new[] { 16, 17, 18, 19 }, // Right
new[] { 20, 21, 22, 23 } // Left
};
var hFaces = new List<FaceHandle>();
foreach ( var faceIndices in faceDefinitions )
{
var faceVerts = faceIndices.Select( i => hVertices[i] ).ToArray();
var hFace = mesh.AddFace( faceVerts );
hFaces.Add( hFace );
}
// Apply material to all faces
foreach ( var hFace in hFaces )
{
mesh.SetFaceMaterial( hFace, material );
}
// Align textures to grid and set smoothing
mesh.TextureAlignToGrid( mesh.Transform );
mesh.SetSmoothingAngle( 40.0f );
// Create MeshComponent and assign mesh to trigger RebuildMesh()
var meshComponent = gameObject.Components.Create<MeshComponent>();
meshComponent.Mesh = mesh;
// Add tags
gameObject.Tags.Add( "mesh" );
gameObject.Tags.Add( "block" );
gameObject.Tags.Add( "building" );
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Created block '{name}' ({sizeX}x{sizeY}x{sizeZ}) at ({x}, {y}, {z})",
id = gameObject.Id.ToString(),
name = gameObject.Name,
position = OzmiumSceneHelpers.V3( gameObject.WorldPosition ),
tags = OzmiumSceneHelpers.GetTags( gameObject ),
faceCount = hFaces.Count,
vertexCount = hVertices.Length,
material = materialPath
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error creating block: {ex.Message}" );
}
}
// ── set_face_material ─────────────────────────────────────────────────────
/// <summary>
/// Applies a material to a specific face or all faces of a mesh.
/// </summary>
internal static object SetFaceMaterial( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
int faceIndex = OzmiumSceneHelpers.Get( args, "faceIndex", -1 );
string materialPath = OzmiumSceneHelpers.Get( args, "materialPath", "" );
if ( string.IsNullOrEmpty( materialPath ) )
return OzmiumSceneHelpers.Txt( "Error: materialPath is required." );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var material = MaterialHelper.LoadMaterial( materialPath );
if ( material == null )
return OzmiumSceneHelpers.Txt( $"Error: Failed to load material '{materialPath}'." );
if ( faceIndex >= 0 )
{
// Apply to specific face
if ( !MaterialHelper.ApplyMaterialToFace( mesh, faceIndex, material ) )
return OzmiumSceneHelpers.Txt( $"Error: Invalid face index {faceIndex}." );
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Applied material '{materialPath}' to face {faceIndex}",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
faceIndex = faceIndex
}, _json ) );
}
else
{
// Apply to all faces
int count = 0;
foreach ( var hFace in mesh.FaceHandles )
{
mesh.SetFaceMaterial( hFace, material );
count++;
}
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Applied material '{materialPath}' to {count} faces",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name
}, _json ) );
}
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error setting face material: {ex.Message}" );
}
}
// ── set_texture_parameters ─────────────────────────────────────────────────
/// <summary>
/// Sets texture mapping parameters (UV axes and scale) for a specific face.
/// </summary>
internal static object SetTextureParameters( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
int faceIndex = OzmiumSceneHelpers.Get( args, "faceIndex", -1 );
float uX = OzmiumSceneHelpers.Get( args, "uAxisX", 1f );
float uY = OzmiumSceneHelpers.Get( args, "uAxisY", 0f );
float uZ = OzmiumSceneHelpers.Get( args, "uAxisZ", 0f );
float vX = OzmiumSceneHelpers.Get( args, "vAxisX", 0f );
float vY = OzmiumSceneHelpers.Get( args, "vAxisY", 0f );
float vZ = OzmiumSceneHelpers.Get( args, "vAxisZ", 1f );
float scaleU = OzmiumSceneHelpers.Get( args, "scaleU", 1f );
float scaleV = OzmiumSceneHelpers.Get( args, "scaleV", 1f );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var vAxisU = new Vector3( uX, uY, uZ );
var vAxisV = new Vector3( vX, vY, vZ );
var scale = new Vector2( scaleU, scaleV );
if ( faceIndex >= 0 )
{
if ( !MaterialHelper.SetTextureParameters( mesh, faceIndex, vAxisU, vAxisV, scale ) )
return OzmiumSceneHelpers.Txt( $"Error: Invalid face index {faceIndex}." );
}
else
{
// Apply to all faces
foreach ( var hFace in mesh.FaceHandles )
{
mesh.SetFaceTextureParameters( hFace, vAxisU, vAxisV, scale );
}
}
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = faceIndex >= 0
? $"Set texture parameters for face {faceIndex}"
: "Set texture parameters for all faces",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
faceIndex = faceIndex,
uAxis = OzmiumSceneHelpers.V3( vAxisU ),
vAxis = OzmiumSceneHelpers.V3( vAxisV ),
scale = new { x = scaleU, y = scaleV }
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error setting texture parameters: {ex.Message}" );
}
}
// ── set_vertex_position ────────────────────────────────────────────────────
/// <summary>
/// Sets the position of a vertex by handle/index (displacement).
/// </summary>
internal static object SetVertexPosition( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
int vertexIndex = OzmiumSceneHelpers.Get( args, "vertexIndex", -1 );
float x = OzmiumSceneHelpers.Get( args, "x", 0f );
float y = OzmiumSceneHelpers.Get( args, "y", 0f );
float z = OzmiumSceneHelpers.Get( args, "z", 0f );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var hVertex = mesh.VertexHandleFromIndex( vertexIndex );
if ( !hVertex.IsValid )
return OzmiumSceneHelpers.Txt( $"Error: Invalid vertex index {vertexIndex}." );
var newPosition = new Vector3( x, y, z );
mesh.SetVertexPosition( hVertex, newPosition );
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Set vertex {vertexIndex} position to ({x}, {y}, {z})",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
vertexIndex = vertexIndex,
position = OzmiumSceneHelpers.V3( newPosition )
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error setting vertex position: {ex.Message}" );
}
}
// ── set_vertex_color ────────────────────────────────────────────────────────
/// <summary>
/// Sets the color of a vertex (for vertex coloring).
/// </summary>
internal static object SetVertexColor( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
int vertexIndex = OzmiumSceneHelpers.Get( args, "vertexIndex", -1 );
float r = OzmiumSceneHelpers.Get( args, "r", 1f );
float g = OzmiumSceneHelpers.Get( args, "g", 1f );
float b = OzmiumSceneHelpers.Get( args, "b", 1f );
float a = OzmiumSceneHelpers.Get( args, "a", 1f );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var hVertex = mesh.VertexHandleFromIndex( vertexIndex );
if ( !hVertex.IsValid )
return OzmiumSceneHelpers.Txt( $"Error: Invalid vertex index {vertexIndex}." );
// Get the half-edge handle for this vertex
var hHalfEdge = mesh.HalfEdgeHandleFromIndex( vertexIndex );
if ( !hHalfEdge.IsValid )
return OzmiumSceneHelpers.Txt( $"Error: Invalid half-edge for vertex {vertexIndex}." );
var color = new Color( r, g, b, a );
mesh.SetVertexColor( hHalfEdge, color );
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Set vertex {vertexIndex} color to ({r}, {g}, {b}, {a})",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
vertexIndex = vertexIndex,
color = new { r, g, b, a }
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error setting vertex color: {ex.Message}" );
}
}
// ── set_vertex_blend ─────────────────────────────────────────────────────────
/// <summary>
/// Sets the blend weight of a vertex (4-channel blend for terrain/texturing).
/// </summary>
internal static object SetVertexBlend( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
int vertexIndex = OzmiumSceneHelpers.Get( args, "vertexIndex", -1 );
float r = OzmiumSceneHelpers.Get( args, "r", 0f );
float g = OzmiumSceneHelpers.Get( args, "g", 0f );
float b = OzmiumSceneHelpers.Get( args, "b", 0f );
float a = OzmiumSceneHelpers.Get( args, "blend", 0f );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var hVertex = mesh.VertexHandleFromIndex( vertexIndex );
if ( !hVertex.IsValid )
return OzmiumSceneHelpers.Txt( $"Error: Invalid vertex index {vertexIndex}." );
var hHalfEdge = mesh.HalfEdgeHandleFromIndex( vertexIndex );
if ( !hHalfEdge.IsValid )
return OzmiumSceneHelpers.Txt( $"Error: Invalid half-edge for vertex {vertexIndex}." );
var blend = new Color( r, g, b, a );
mesh.SetVertexBlend( hHalfEdge, blend );
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Set vertex {vertexIndex} blend to ({r}, {g}, {b}, {a})",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
vertexIndex = vertexIndex,
blend = new { r, g, b, a }
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error setting vertex blend: {ex.Message}" );
}
}
// ── get_mesh_info ─────────────────────────────────────────────────────────
/// <summary>
/// Queries detailed information about a mesh including counts and per-face data.
/// </summary>
internal static object GetMeshInfo( JsonElement args )
{
var scene = OzmiumSceneHelpers.ResolveScene();
if ( scene == null ) return OzmiumSceneHelpers.Txt( "No active scene." );
string id = OzmiumSceneHelpers.Get( args, "gameObjectId", "" );
string name = OzmiumSceneHelpers.Get( args, "name", "" );
var gameObject = OzmiumSceneHelpers.FindGo( scene, id, name );
if ( gameObject == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject not found (id: {id}, name: {name})." );
try
{
var meshComponent = gameObject.Components.Get<MeshComponent>();
if ( meshComponent == null )
return OzmiumSceneHelpers.Txt( $"Error: GameObject '{gameObject.Name}' has no MeshComponent." );
var mesh = meshComponent.Mesh;
var faceCount = MaterialHelper.GetFaceCount( mesh );
var vertexCount = MaterialHelper.GetVertexCount( mesh );
var edgeCount = MaterialHelper.GetEdgeCount( mesh );
// Collect per-face material info
var faceData = new List<object>();
int idx = 0;
foreach ( var hFace in mesh.FaceHandles )
{
var material = mesh.GetFaceMaterial( hFace );
faceData.Add( new
{
index = idx++,
material = material?.ResourcePath ?? "default",
materialName = material?.Name ?? "default"
} );
}
// Calculate bounds
var bounds = mesh.CalculateBounds();
return OzmiumSceneHelpers.Txt( JsonSerializer.Serialize( new
{
message = $"Mesh info for '{gameObject.Name}'",
gameObjectId = gameObject.Id.ToString(),
gameObjectName = gameObject.Name,
faceCount = faceCount,
vertexCount = vertexCount,
edgeCount = edgeCount,
bounds = new
{
mins = OzmiumSceneHelpers.V3( bounds.Mins ),
maxs = OzmiumSceneHelpers.V3( bounds.Maxs )
},
faces = faceData
}, _json ) );
}
catch ( Exception ex )
{
return OzmiumSceneHelpers.Txt( $"Error getting mesh info: {ex.Message}" );
}
}
// ── Tool schemas (used by ToolDefinitions.All) ───────────────────────────
internal static Dictionary<string, object> SchemaCreateBlock => OzmiumSceneHelpers.S( "create_block",
"Creates a primitive block mesh using PolygonMesh. Compatible with S&box mesh editing tools.",
new Dictionary<string, object>
{
["x"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "World X position (default: 0)." },
["y"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "World Y position (default: 0)." },
["z"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "World Z position (default: 0)." },
["sizeX"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Size along X axis (default: 100)." },
["sizeY"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Size along Y axis (default: 100)." },
["sizeZ"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Size along Z axis (default: 100)." },
["materialPath"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "Path to material asset (default: materials/dev/reflectivity_30.vmat)." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "Name of the block (default: 'Block')." }
} );
internal static Dictionary<string, object> SchemaSetFaceMaterial => OzmiumSceneHelpers.S( "set_face_material",
"Applies a material to a specific face or all faces of a mesh.",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID (use name instead if not provided)." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name (used if gameObjectId not provided)." },
["faceIndex"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Face index to apply material to, or -1 for all faces (default: -1)." },
["materialPath"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "Path to material asset (required)." }
}, new[] { "materialPath" } );
internal static Dictionary<string, object> SchemaSetTextureParameters => OzmiumSceneHelpers.S( "set_texture_parameters",
"Sets texture mapping parameters (UV axes and scale) for faces.",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name." },
["faceIndex"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Face index, or -1 for all faces (default: -1)." },
["uAxisX"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "U axis X component (default: 1)." },
["uAxisY"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "U axis Y component (default: 0)." },
["uAxisZ"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "U axis Z component (default: 0)." },
["vAxisX"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "V axis X component (default: 0)." },
["vAxisY"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "V axis Y component (default: 0)." },
["vAxisZ"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "V axis Z component (default: 1)." },
["scaleU"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Texture U scale (default: 1)." },
["scaleV"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Texture V scale (default: 1)." }
} );
internal static Dictionary<string, object> SchemaSetVertexPosition => OzmiumSceneHelpers.S( "set_vertex_position",
"Sets the position of a vertex by index (for displacement/sculpting).",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name." },
["vertexIndex"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Vertex index (required)." },
["x"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "New X position." },
["y"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "New Y position." },
["z"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "New Z position." }
}, new[] { "vertexIndex" } );
internal static Dictionary<string, object> SchemaSetVertexColor => OzmiumSceneHelpers.S( "set_vertex_color",
"Sets the vertex color for vertex painting.",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name." },
["vertexIndex"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Vertex index (required)." },
["r"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Red component 0-1 (default: 1)." },
["g"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Green component 0-1 (default: 1)." },
["b"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Blue component 0-1 (default: 1)." },
["a"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Alpha component 0-1 (default: 1)." }
}, new[] { "vertexIndex" } );
internal static Dictionary<string, object> SchemaSetVertexBlend => OzmiumSceneHelpers.S( "set_vertex_blend",
"Sets the vertex blend weights for terrain/texturing.",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name." },
["vertexIndex"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Vertex index (required)." },
["r"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Red blend channel 0-1 (default: 0)." },
["g"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Green blend channel 0-1 (default: 0)." },
["b"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Blue blend channel 0-1 (default: 0)." },
["blend"] = new Dictionary<string, object> { ["type"] = "number", ["description"] = "Alpha blend channel 0-1 (default: 0)." }
}, new[] { "vertexIndex" } );
internal static Dictionary<string, object> SchemaGetMeshInfo => OzmiumSceneHelpers.S( "get_mesh_info",
"Queries detailed information about a mesh including counts, bounds, and per-face materials.",
new Dictionary<string, object>
{
["gameObjectId"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject GUID." },
["name"] = new Dictionary<string, object> { ["type"] = "string", ["description"] = "GameObject name." }
} );
}