add missing files.

This commit is contained in:
Syoyo Fujita
2025-08-22 08:21:40 +09:00
parent 44314c7cd6
commit b50d35721f
5 changed files with 444 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
# JavaScript Scripting Example - Load USD as Layer and query LayerMetas
# Assume this cmake is called from tinyusdz root(../../)
set(EXAMPLE_TARGET "js-script")
set(JS_SCRIPT_SOURCES
main.cc
)
add_executable(${EXAMPLE_TARGET} ${JS_SCRIPT_SOURCES})
add_sanitizers(${EXAMPLE_TARGET})
target_include_directories(${EXAMPLE_TARGET} PRIVATE ${PROJECT_SOURCE_DIR}/src)
target_link_libraries(${EXAMPLE_TARGET} tinyusdz_static)
# This example requires QuickJS support
if(NOT TINYUSDZ_WITH_QJS)
message(WARNING "js-script example requires QuickJS support. Enable with -DTINYUSDZ_WITH_QJS=ON")
endif()
set_target_properties(${EXAMPLE_TARGET} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
# Copy JavaScript files to binary directory for easy access
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/query_layer.js"
"${CMAKE_BINARY_DIR}/query_layer.js"
COPYONLY
)

View File

@@ -0,0 +1,161 @@
# JavaScript Scripting Example
This example demonstrates how to load a USD file as a Layer in C++ and query LayerMeta information through the Tydra JavaScript interface.
## Overview
The example shows how to:
1. Load a USD file using TinyUSDZ's C++ API
2. Access the LayerMetas from the loaded Stage
3. Execute JavaScript code that can query layer metadata through the Tydra interface
4. Use the `getLayerMetas()` function from JavaScript to access USD layer properties
## Requirements
- TinyUSDZ built with QuickJS support (`-DTINYUSDZ_WITH_QJS=ON`)
- A USD file to query (sample provided)
## Building
From the TinyUSDZ root directory:
```bash
mkdir build && cd build
cmake -DTINYUSDZ_WITH_QJS=ON -DTINYUSDZ_BUILD_EXAMPLES=ON ..
make js-script
```
## Usage
```bash
./js-script <USD_FILE> <JAVASCRIPT_FILE>
```
### Example Usage
```bash
# Use the provided sample files
./js-script examples/js-script/sample.usda examples/js-script/query_layer.js
# Or use your own USD file
./js-script path/to/your/model.usd query_layer.js
```
## Files
- **`main.cc`** - C++ application that loads USD and executes JavaScript
- **`query_layer.js`** - Example JavaScript that demonstrates LayerMetas querying
- **`sample.usda`** - Sample USD file with various metadata for testing
- **`CMakeLists.txt`** - Build configuration
## JavaScript API
The JavaScript environment provides access to:
### `getLayerMetas()`
Returns a JavaScript object containing USD layer metadata:
```javascript
var layerMetas = getLayerMetas();
console.log("Up Axis: " + layerMetas.upAxis);
console.log("Default Prim: " + layerMetas.defaultPrim);
console.log("Meters Per Unit: " + layerMetas.metersPerUnit);
```
### Available LayerMetas Properties
- `upAxis` - Coordinate system up axis ("X", "Y", or "Z")
- `defaultPrim` - Name of the default prim
- `metersPerUnit` - Scale conversion factor
- `timeCodesPerSecond` - Time sampling rate
- `framesPerSecond` - Animation frame rate
- `startTimeCode` - Animation start time
- `endTimeCode` - Animation end time (null if infinite)
- `kilogramsPerUnit` - Mass unit conversion
- `comment` - Layer comment string
- `doc` - Layer documentation string
- `autoPlay` - USDZ auto-play setting
- `playbackMode` - USDZ playback mode
- `subLayers` - Array of sub-layer references
- `primChildren` - Array of root-level prim names
### Example Output
```
=== USD Layer Metadata Query Script ===
LayerMetas successfully retrieved!
=== Basic Layer Metadata ===
Up Axis: Y
Default Prim: Scene
Meters Per Unit: 1
Time Codes Per Second: 24
Frames Per Second: 24
=== Time Range ===
Start Time Code: 1
End Time Code: 100
=== Root Prim Children ===
Number of root prims: 1
Prim 0: Scene
=== Analysis ===
Has default prim: true
Has time range: true
Is animated: true
```
## Extending the Example
You can create your own JavaScript files to:
1. **Analyze USD structure** - Check metadata patterns, validate settings
2. **Report generation** - Extract metadata for external tools
3. **Conditional processing** - Make decisions based on USD properties
4. **Validation** - Verify USD files meet specific requirements
### Custom JavaScript Example
```javascript
// Custom validation script
var layerMetas = getLayerMetas();
// Check for required metadata
if (!layerMetas.defaultPrim) {
console.log("WARNING: No default prim set");
}
if (layerMetas.upAxis !== "Y") {
console.log("INFO: Using " + layerMetas.upAxis + " as up-axis");
}
// Generate report
console.log("=== USD File Report ===");
console.log("File appears to be: " +
(layerMetas.endTimeCode > layerMetas.startTimeCode ? "Animated" : "Static"));
console.log("Scale: " + layerMetas.metersPerUnit + " meters per unit");
console.log("Frame rate: " + layerMetas.framesPerSecond + " fps");
```
## Technical Notes
- The example uses QuickJS for JavaScript execution
- LayerMetas are converted to JSON and parsed in the JavaScript context
- The C++ side sets up a global `getLayerMetas()` function accessible from JavaScript
- JavaScript execution is sandboxed and stateless
- All USD data types are converted to appropriate JavaScript types
## Troubleshooting
**Error: "JavaScript is not supported in this build"**
- Rebuild TinyUSDZ with `-DTINYUSDZ_WITH_QJS=ON`
**Error: "Failed to load USD file"**
- Check that the USD file path is correct
- Verify the USD file is valid
**Error: "Failed to load JavaScript file"**
- Check that the JavaScript file path is correct
- Verify the JavaScript file contains valid JavaScript code

100
examples/js-script/main.cc Normal file
View File

@@ -0,0 +1,100 @@
#include <iostream>
#include <fstream>
#include <string>
// TinyUSDZ core
#include "tinyusdz.hh"
#include "pprinter.hh"
#if defined(TINYUSDZ_WITH_QJS)
#include "tydra/js-script.hh"
#endif
static std::string LoadJavaScriptFile(const std::string& filename) {
std::ifstream file(filename);
if (!file.is_open()) {
return "";
}
std::string content;
std::string line;
while (std::getline(file, line)) {
content += line + "\n";
}
return content;
}
int main(int argc, char** argv) {
if (argc < 3) {
std::cout << "Usage: " << argv[0] << " <USD_FILE> <JS_SCRIPT>" << std::endl;
std::cout << "Example: " << argv[0] << " model.usd query_layer.js" << std::endl;
return -1;
}
std::string usd_filename = argv[1];
std::string js_filename = argv[2];
std::cout << "Loading USD file: " << usd_filename << std::endl;
std::cout << "Loading JavaScript: " << js_filename << std::endl;
#if defined(TINYUSDZ_WITH_QJS)
// Load USD file as Stage (which contains Layer metadata)
tinyusdz::Stage stage;
std::string warn, err;
bool ret = tinyusdz::LoadUSDFromFile(usd_filename, &stage, &warn, &err);
if (!warn.empty()) {
std::cerr << "WARN: " << warn << std::endl;
}
if (!ret) {
std::cerr << "ERROR: Failed to load USD file: " << err << std::endl;
return -1;
}
std::cout << "Successfully loaded USD file" << std::endl;
// Get LayerMetas from the Stage
const tinyusdz::LayerMetas& layer_metas = stage.metas();
std::cout << "Stage LayerMetas loaded" << std::endl;
std::cout << " - upAxis: " << tinyusdz::to_string(layer_metas.upAxis.get_value()) << std::endl;
std::cout << " - defaultPrim: " << layer_metas.defaultPrim.str() << std::endl;
std::cout << " - metersPerUnit: " << layer_metas.metersPerUnit.get_value() << std::endl;
std::cout << " - timeCodesPerSecond: " << layer_metas.timeCodesPerSecond.get_value() << std::endl;
// Load JavaScript code
std::string js_code = LoadJavaScriptFile(js_filename);
if (js_code.empty()) {
std::cerr << "ERROR: Failed to load JavaScript file: " << js_filename << std::endl;
return -1;
}
std::cout << "Loaded JavaScript code (" << js_code.length() << " bytes)" << std::endl;
// Execute JavaScript with LayerMetas access
std::cout << "Executing JavaScript with LayerMetas access..." << std::endl;
std::cout << "----------------------------------------" << std::endl;
std::string js_err;
bool js_ret = tinyusdz::tydra::RunJSScriptWithLayerMetas(js_code, &layer_metas, js_err);
std::cout << "----------------------------------------" << std::endl;
if (!js_ret) {
std::cerr << "ERROR: JavaScript execution failed: " << js_err << std::endl;
return -1;
}
std::cout << "JavaScript executed successfully" << std::endl;
#else
std::cerr << "ERROR: This example requires QuickJS support (TINYUSDZ_WITH_QJS=ON)" << std::endl;
std::cerr << "Please rebuild TinyUSDZ with QuickJS enabled." << std::endl;
return -1;
#endif
return 0;
}

View File

@@ -0,0 +1,116 @@
// Example JavaScript script to query LayerMeta information
// This script demonstrates how to access USD Layer metadata through the Tydra JavaScript interface
console.log("=== USD Layer Metadata Query Script ===");
console.log("This script demonstrates querying LayerMetas through the Tydra JavaScript interface.");
console.log("");
// Get the LayerMetas object from the C++ side
var layerMetas = getLayerMetas();
if (layerMetas === null) {
console.log("ERROR: No LayerMetas available");
} else {
console.log("LayerMetas successfully retrieved!");
console.log("");
// Display basic metadata
console.log("=== Basic Layer Metadata ===");
console.log("Up Axis: " + layerMetas.upAxis);
console.log("Default Prim: " + layerMetas.defaultPrim);
console.log("Meters Per Unit: " + layerMetas.metersPerUnit);
console.log("Time Codes Per Second: " + layerMetas.timeCodesPerSecond);
console.log("Frames Per Second: " + layerMetas.framesPerSecond);
console.log("Kilograms Per Unit: " + layerMetas.kilogramsPerUnit);
console.log("");
// Display time range information
console.log("=== Time Range ===");
console.log("Start Time Code: " + layerMetas.startTimeCode);
if (layerMetas.endTimeCode === null) {
console.log("End Time Code: (infinite/not set)");
} else {
console.log("End Time Code: " + layerMetas.endTimeCode);
}
console.log("");
// Display documentation and comments
console.log("=== Documentation ===");
if (layerMetas.comment && layerMetas.comment.length > 0) {
console.log("Comment: " + layerMetas.comment);
} else {
console.log("Comment: (none)");
}
if (layerMetas.doc && layerMetas.doc.length > 0) {
console.log("Documentation: " + layerMetas.doc);
} else {
console.log("Documentation: (none)");
}
console.log("");
// Display USDZ-specific metadata
console.log("=== USDZ Extensions ===");
console.log("Auto Play: " + layerMetas.autoPlay);
console.log("Playback Mode: " + layerMetas.playbackMode);
console.log("");
// Display sub-layers information
console.log("=== Sub-Layers ===");
if (layerMetas.subLayers.length > 0) {
console.log("Number of sub-layers: " + layerMetas.subLayers.length);
for (var i = 0; i < layerMetas.subLayers.length; i++) {
var subLayer = layerMetas.subLayers[i];
console.log(" Sub-layer " + i + ":");
console.log(" Asset Path: " + subLayer.assetPath);
console.log(" Layer Offset: " + subLayer.layerOffset.offset);
console.log(" Layer Scale: " + subLayer.layerOffset.scale);
}
} else {
console.log("No sub-layers defined");
}
console.log("");
// Display root prim children
console.log("=== Root Prim Children ===");
if (layerMetas.primChildren.length > 0) {
console.log("Number of root prims: " + layerMetas.primChildren.length);
for (var i = 0; i < layerMetas.primChildren.length; i++) {
console.log(" Prim " + i + ": " + layerMetas.primChildren[i]);
}
} else {
console.log("No root prims defined");
}
console.log("");
// Perform some analysis
console.log("=== Analysis ===");
// Check if this looks like a typical scene setup
var hasDefaultPrim = layerMetas.defaultPrim && layerMetas.defaultPrim.length > 0;
var hasTimeRange = layerMetas.startTimeCode !== undefined && layerMetas.endTimeCode !== null;
var isAnimated = hasTimeRange && (layerMetas.endTimeCode > layerMetas.startTimeCode);
console.log("Has default prim: " + hasDefaultPrim);
console.log("Has time range: " + hasTimeRange);
console.log("Is animated: " + isAnimated);
if (layerMetas.upAxis !== "Y") {
console.log("NOTE: This USD file uses " + layerMetas.upAxis + " as up-axis (not Y)");
}
if (layerMetas.metersPerUnit !== 1.0) {
console.log("NOTE: This USD file has custom scale: " + layerMetas.metersPerUnit + " meters per unit");
}
if (layerMetas.subLayers.length > 0) {
console.log("NOTE: This USD file references " + layerMetas.subLayers.length + " sub-layer(s)");
}
console.log("");
console.log("=== JSON Representation ===");
console.log(JSON.stringify(layerMetas, null, 2));
}
console.log("");
console.log("=== Script Complete ===");

View File

@@ -0,0 +1,39 @@
#usda 1.0
(
comment = "Simple USD sample file for JavaScript LayerMetas demo"
defaultPrim = "Scene"
doc = "This USD file demonstrates basic layer metadata that can be queried via JavaScript"
endTimeCode = 100
framesPerSecond = 24
metersPerUnit = 1
startTimeCode = 1
timeCodesPerSecond = 24
upAxis = "Y"
)
def Xform "Scene"
{
def Sphere "Ball"
{
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
double radius = 1
# Animated transform
float3 xformOp:translate.timeSamples = {
1: (0, 0, 0),
50: (2, 1, 0),
100: (0, 0, 0)
}
uniform token[] xformOpOrder = ["xformOp:translate"]
}
def Cube "Box"
{
float3[] extent = [(-1, -1, -1), (1, 1, 1)]
double size = 2
# Static transform
float3 xformOp:translate = (3, 0, 0)
uniform token[] xformOpOrder = ["xformOp:translate"]
}
}