diff --git a/moon.mod.json b/moon.mod.json index 0bb964d..9dde6ec 100644 --- a/moon.mod.json +++ b/moon.mod.json @@ -1,9 +1,9 @@ { "name": "tiye/caterfoil", - "version": "0.1.0", + "version": "0.0.2", "deps": { "tiye/quaternion": "0.0.4", - "tiye/dom-ffi": "0.0.6" + "tiye/dom-ffi": "0.0.8" }, "readme": "README.md", "repository": "", diff --git a/src/lib/caterfoil.mbt b/src/lib/caterfoil.mbt index d654c1d..8011e63 100644 --- a/src/lib/caterfoil.mbt +++ b/src/lib/caterfoil.mbt @@ -3,6 +3,8 @@ pub extern "js" fn initialize_context() -> Promise = #| () => Caterfoil.initializeContext() ///| +/// Triggers a redraw of the current Caterfoil render tree. Updates the WebGPU +/// canvas with the latest state of all render objects in the scene graph. pub extern "js" fn paint_caterfoil_tree() -> Unit = #| () => Caterfoil.paintCaterfoilTree() @@ -14,10 +16,19 @@ pub extern "js" fn render_caterfoil_tree( #| (el, dispatch) => Caterfoil.renderCaterfoilTree(el, dispatch) ///| +/// Adjusts the canvas size to match its display size, ensuring proper rendering +/// and preventing scaling artifacts. +/// +/// Parameters: +/// +/// * `canvas` : The HTML canvas element to be resized. Must be a valid DOM +/// Element object obtained through methods like `Document::query_selector`. pub extern "js" fn reset_canvas_size(canvas : Element) -> Unit = #| (canvas) => Caterfoil.resetCanvasSize(canvas) ///| +/// Initializes textures required for WebGPU rendering on the canvas. Sets up +/// necessary texture configurations and bindings for the rendering pipeline. pub extern "js" fn initialize_canvas_textures() -> Unit = #| () => Caterfoil.initializeCanvasTextures() @@ -26,6 +37,10 @@ pub extern "js" fn setup_mouse_events() -> Unit = #| () => Caterfoil.setupMouseEvents() ///| +/// Sets up gamepad input handling for WebGPU rendering. Initializes event +/// listeners and state management for gamepad connections, button presses, and +/// axis movements. Enables real-time input detection from connected gamepads to +/// control the WebGPU rendering viewport and scene. pub extern "js" fn load_gamepad_control() -> Unit = #| () => Caterfoil.loadGamepadControl() @@ -34,10 +49,38 @@ pub extern "js" fn lines_wgsl() -> String = #| () => Caterfoil.triangleWgsl ///| +/// Returns the WebGPU Shader Language (WGSL) code used for rendering polylines +/// in Caterfoil. The shader includes vertex and fragment stages necessary for +/// drawing thick lines with proper width and direction handling. +/// +/// Returns a string containing the WGSL shader code for polyline rendering. pub extern "js" fn polyline_wgsl() -> String = #| () => Caterfoil.polylineWgsl -///| get viewer states saved in localStorage so that it can be restored +///| +/// Connects a retained atom to browser's localStorage for persistent state +/// management. The connection can be configured to enable/disable reading from +/// or writing to localStorage. +/// +/// Parameters: +/// +/// * `name` : A unique identifier string for the retained atom. This name is +/// used as the key in localStorage. +/// * `read` : Optional boolean flag to control loading from localStorage. +/// Defaults to `true`. When set to `false`, disables loading stored values. +/// * `write` : Optional boolean flag to control saving to localStorage. Defaults +/// to `true`. When set to `false`, disables saving values. +/// +/// Example: +/// +/// ```moonbit +/// test "connect_retained_atom_to_srorage" { +/// // Connect an atom named "viewer-state" with both read and write enabled +/// connect_retained_atom_to_srorage("viewer-state") +/// // Connect an atom that only reads from storage +/// connect_retained_atom_to_srorage("read-only-state", write=false) +/// } +/// ``` pub fn connect_retained_atom_to_srorage( name : String, /// false to disable loading from localStorage @@ -61,6 +104,39 @@ extern "js" fn caterfoil_connect_retained_atom_to_srorage( #| (name, read, write) => Caterfoil.connectRetainedAtomToStorage(name, {read, write}) ///| +/// Represents the vertex data used in Caterfoil rendering objects. Provides two +/// variants for different rendering approaches: +/// basic vertices for simple shapes and polyline vertices for thick lines with +/// proper width handling. +/// +/// Parameters: +/// +/// For `WithPoints`: +/// +/// * `vertices` : An array of basic vertices, each containing position and color +/// information. +/// +/// For `WithTriangles`: +/// +/// * `vertices` : An array of polyline vertices, each containing position, +/// color, direction, and side information for thick line rendering. +/// +/// Example: +/// +/// ```moonbit +/// test "ObjectData" { +/// let points = ObjectData::WithPoints([ +/// Vertex::{ +/// position: @quaternion.new(0.0, 0.0, 0.0, 1.0), +/// color: Color::red(), +/// }, +/// ]) +/// match points { +/// WithPoints(vertices) => inspect!(vertices.length(), content="1") +/// WithTriangles(_) => inspect!(false, content="true") +/// } +/// } +/// ``` pub(all) enum ObjectData { WithPoints(Array[Vertex]) WithTriangles(Array[PolylineVertex]) @@ -89,6 +165,41 @@ fn ObjectData::to_data( } ///| +/// Represents configuration options for creating a WebGPU render object in +/// Caterfoil. Contains essential information about the rendering pipeline, +/// including shader configuration, vertex data, and rendering topology. +/// +/// Fields: +/// +/// * `label` : A string identifier for the render object, useful for debugging +/// purposes. +/// * `shader` : The WebGPU shader code as a string, defining how vertices should +/// be processed and rendered. +/// * `topology` : The primitive topology type that determines how vertices are +/// interpreted (e.g., point list, line list, triangle list). +/// * `data` : The vertex data to be rendered, can be either basic vertices or +/// polyline vertices with additional attributes. +/// * `indices` : Optional array of unsigned integers specifying the vertex +/// indices for indexed rendering. +/// * `get_params` : Optional callback function that returns an array of +/// floating-point values used as shader parameters. +/// +/// Example: +/// +/// ```moonbit +/// test "CaterfoilObjectOptions" { +/// let options = CaterfoilObjectOptions::{ +/// label: "triangle", +/// shader: @caterfoil.lines_wgsl(), +/// topology: ShaderPrimitiveTopology::TriangleList, +/// data: ObjectData::WithPoints([]), +/// indices: None, +/// get_params: None, +/// } +/// inspect!(options.label, content="\"triangle\"") +/// inspect!(options.topology, content="TriangleList") +/// } +/// ``` pub(all) struct CaterfoilObjectOptions { label : String shader : String @@ -164,13 +275,50 @@ fn CaterfoilAttribute::as_value(self : CaterfoilAttribute) -> JsValue { ///| type CaterfoilRenderObject -///| +///| Creates a new Caterfoil render object with the specified configuration extern "js" fn CaterfoilRenderObject::as_value( self : CaterfoilRenderObject ) -> JsValue = #| (self) => self ///| +/// Creates a new WebGPU render object in the Caterfoil rendering system with +/// specified vertex data and rendering configuration. +/// +/// Parameters: +/// +/// * `data` : The vertex data to be rendered. Can be either basic vertices +/// (`WithPoints`) or polyline vertices (`WithTriangles`) with additional +/// attributes for thick line rendering. +/// * `shader` : Optional WebGPU shader code as a string. If not provided, +/// automatically selects an appropriate shader based on the vertex data type +/// (`lines_wgsl` for `WithPoints`, `polyline_wgsl` for `WithTriangles`). +/// * `label` : Optional string identifier for the render object, useful for +/// debugging. Defaults to "object". +/// * `topology` : Optional primitive topology type that determines how vertices +/// are interpreted (e.g., point list, line list). Defaults to `TriangleList`. +/// * `get_params` : Optional callback function that returns an array of +/// floating-point values used as shader parameters. +/// * `indices` : Optional array of unsigned integers specifying the vertex +/// indices for indexed rendering. +/// +/// Returns a new `CaterfoilRenderObject` that can be used in the Caterfoil +/// rendering system. +/// +/// Example: +/// +/// ```moonbit +/// test "object/basic" { +/// let vertices = [ +/// Vertex::{ +/// position: @quaternion.new(0.0, 0.0, 0.0, 1.0), +/// color: Color::red(), +/// }, +/// ] +/// let triangle = object(data=ObjectData::WithPoints(vertices)) +/// inspect!(triangle, content="[object Object]") +/// } +/// ``` pub fn object( data~ : ObjectData, /// by default, pick the shader based on the data type @@ -201,6 +349,28 @@ pub fn object( } ///| +/// Creates a group of render objects in the Caterfoil rendering system, allowing +/// multiple render objects to be combined and managed as a single unit. +/// +/// Parameters: +/// +/// * `children` : An array of `CaterfoilRenderObject`s that will be grouped +/// together. These objects can be created using functions like `object()` or +/// other `group()` calls. +/// +/// Returns a new `CaterfoilRenderObject` that represents the group of render +/// objects. +/// +/// Example: +/// +/// ```moonbit +/// test "group" { +/// let triangle = @caterfoil.object(data=ObjectData::WithPoints([])) +/// let circle = @caterfoil.object(data=ObjectData::WithPoints([])) +/// let scene = @caterfoil.group([triangle, circle]) +/// inspect!(scene, content="[object Object]") +/// } +/// ``` pub fn group(children : Array[CaterfoilRenderObject]) -> CaterfoilRenderObject { let arr = JsArray::new() for child in children { diff --git a/src/lib/ffi.mbt b/src/lib/ffi.mbt index 615339b..3ff47eb 100644 --- a/src/lib/ffi.mbt +++ b/src/lib/ffi.mbt @@ -1,4 +1,4 @@ -///| +///| a very naive ffi implementation for JS Promise type Promise ///| diff --git a/src/lib/gpu.mbt b/src/lib/gpu.mbt index 1dcecba..9e645ba 100644 --- a/src/lib/gpu.mbt +++ b/src/lib/gpu.mbt @@ -24,6 +24,46 @@ fn ShaderPrimitiveTopology::to_string(self : ShaderPrimitiveTopology) -> String } ///| +/// Represents the format of vertex attributes in WebGPU shaders. Each variant +/// describes the data type, size, and normalization of vertex data. +/// +/// The format strings follow the WebGPU specification naming convention: +/// +/// * First part indicates the data type (`uint`, `sint`, `float`) and bit width +/// (8, 16, 32) +/// * Second part (if present) indicates the number of components (x2, x3, x4) +/// * Prefix `unorm` or `snorm` indicates normalized integer formats +/// * Special case `unorm10_10_10_2` for packed 32-bit format with normalized +/// components +/// +/// Parameters: +/// +/// * `Uint8x2`, `Uint8x4`: Two or four unsigned 8-bit integers +/// * `Sint8x2`, `Sint8x4`: Two or four signed 8-bit integers +/// * `Unorm8x2`, `Unorm8x4`: Two or four normalized unsigned 8-bit integers +/// * `Snorm8x2`, `Snorm8x4`: Two or four normalized signed 8-bit integers +/// * `Uint16x2`, `Uint16x4`: Two or four unsigned 16-bit integers +/// * `Sint16x2`, `Sint16x4`: Two or four signed 16-bit integers +/// * `Unorm16x2`, `Unorm16x4`: Two or four normalized unsigned 16-bit integers +/// * `Snorm16x2`, `Snorm16x4`: Two or four normalized signed 16-bit integers +/// * `Float16x2`, `Float16x4`: Two or four 16-bit floating point numbers +/// * `Float32`, `Float32x2`, `Float32x3`, `Float32x4`: One to four 32-bit +/// floating point numbers +/// * `Uint32`, `Uint32x2`, `Uint32x3`, `Uint32x4`: One to four unsigned 32-bit +/// integers +/// * `Sint32`, `Sint32x2`, `Sint32x3`, `Sint32x4`: One to four signed 32-bit +/// integers +/// * `Unorm10_10_10_2`: Packed format with three 10-bit normalized unsigned +/// integers and one 2-bit normalized unsigned integer +/// +/// Example: +/// +/// ```moonbit +/// test "GPUVertexFormat" { +/// let format = GPUVertexFormat::Float32x4 +/// inspect!(format.to_string(), content="\"float32x4\"") +/// } +/// ``` pub(all) enum GPUVertexFormat { Uint8x2 Uint8x4 diff --git a/src/lib/vertex.mbt b/src/lib/vertex.mbt index d55f42c..acd5273 100644 --- a/src/lib/vertex.mbt +++ b/src/lib/vertex.mbt @@ -28,6 +28,32 @@ pub fn Vertex::to_value( } ///| +/// Represents a vertex in a polyline with position, color, direction, and side +/// information. Used for rendering thick lines with proper width and direction. +/// +/// Fields: +/// +/// * `position` : The position of the vertex in 3D space represented as a +/// quaternion. +/// * `color` : The color of the vertex. +/// * `direction` : The direction vector of the line segment at this vertex, +/// represented as a quaternion. +/// * `side` : An integer flag indicating which side of the line this vertex +/// represents (0 for left side, 1 for right side). +/// +/// Example: +/// +/// ```moonbit +/// test "PolylineVertex" { +/// let vertex = PolylineVertex::{ +/// position: @quaternion.new(1.0, 0.0, 0.0, 1.0), +/// color: Color::red(), +/// direction: @quaternion.new(0.0, 1.0, 0.0, 0.0), +/// side: 0, +/// } +/// inspect!(vertex.side, content="0") +/// } +/// ``` pub(all) struct PolylineVertex { position : @quaternion.Quaternion color : Color @@ -36,6 +62,39 @@ pub(all) struct PolylineVertex { } ///| +/// Converts a `PolylineVertex` instance into a hashmap representation suitable +/// for WebGPU vertex buffer data. The resulting hashmap contains the vertex's +/// position, color, direction, and side information as arrays of floating-point +/// numbers. +/// +/// Parameters: +/// +/// * `self` : The `PolylineVertex` instance to convert. +/// +/// Returns a hashmap with the following key-value pairs: +/// +/// * `"position"` : Array of 4 floats representing the vertex position as XYZW +/// coordinates +/// * `"color"` : Array of 4 floats representing RGBA color components +/// * `"direction"` : Array of 4 floats representing the direction vector as XYZW +/// coordinates +/// * `"side"` : Single-element array containing the side flag as a float +/// +/// Example: +/// +/// ```moonbit +/// test "PolylineVertex::to_value" { +/// let vertex = PolylineVertex::{ +/// position: @quaternion.new(1.0, 0.0, 0.0, 1.0), +/// color: Color::red(), +/// direction: @quaternion.new(0.0, 1.0, 0.0, 0.0), +/// side: 0, +/// } +/// let dict = vertex.to_value() +/// inspect!(dict["position"], content="[1.0, 0.0, 0.0, 1.0]") +/// inspect!(dict["color"], content="[1.0, 0.0, 0.0, 1.0]") +/// } +/// ``` pub fn PolylineVertex::to_value( self : PolylineVertex ) -> @moonbitlang/core/hashmap.T[String, Array[Float]] { @@ -48,6 +107,29 @@ pub fn PolylineVertex::to_value( } ///| +/// Returns an array of vertex attributes required for rendering a polyline +/// vertex in WebGPU. +/// +/// Returns an array of `CaterfoilAttribute` containing the following vertex +/// attributes: +/// +/// * `position`: A 4D float vector (x, y, z, w) representing the vertex position +/// * `color`: A 4D float vector (r, g, b, a) representing the vertex color +/// * `direction`: A 4D float vector representing the direction of the line +/// segment +/// * `side`: A 32-bit signed integer indicating which side of the line this +/// vertex represents (0 for left, 1 for right) +/// +/// Example: +/// +/// ```moonbit +/// test "PolylineVertex::attrs" { +/// let attrs = PolylineVertex::attrs() +/// inspect!(attrs.length(), content="4") +/// inspect!(attrs[0].field, content="\"position\"") +/// inspect!(attrs[0].format, content="Float32x4") +/// } +/// ``` pub fn PolylineVertex::attrs() -> Array[CaterfoilAttribute] { [ { field: "position", format: Float32x4 }, @@ -58,6 +140,18 @@ pub fn PolylineVertex::attrs() -> Array[CaterfoilAttribute] { } ///| +/// Represents an error that can occur during vertex data building process. +/// +/// Returns a new error type that wraps a string message. +/// +/// Example: +/// +/// ```moonbit +/// test "BuilderError" { +/// let err = BuilderError("chunk size must be at least 2") +/// inspect!(err, content="BuilderError(\"chunk size must be at least 2\")") +/// } +/// ``` pub(all) type! BuilderError String derive(Show) ///| turn a chunk of vertices into triangles data diff --git a/src/main/alias.mbt b/src/main/alias.mbt index bb4bea6..9ce68dc 100644 --- a/src/main/alias.mbt +++ b/src/main/alias.mbt @@ -2,10 +2,61 @@ typealias Quaternion = @quaternion.Quaternion ///| +/// Creates an alias for the `Vertex` type from the caterfoil package, providing +/// a convenient way to reference vertices in 4D space with color information. +/// +/// A vertex represents a point in 4D space along with its color attributes, +/// commonly used in rendering geometric shapes and visual elements in the +/// caterfoil graphics system. +/// +/// Example: +/// +/// ```moonbit +/// test "vertex" { +/// let v : Vertex = { position: Quaternion::new(x=1.0), color: Color::white() } +/// inspect!(v.position.x, content="1.0") +/// } +/// ``` typealias Vertex = @caterfoil.Vertex ///| +/// Creates an alias for the `PolylineVertex` type from the caterfoil package, +/// which represents a vertex in a polyline with additional attributes for +/// rendering. +/// +/// A polyline vertex contains position, color, direction and side information, +/// commonly used in rendering line segments with width in 4D space. +/// +/// Example: +/// +/// ```moonbit +/// test "polyline-vertex" { +/// let vertex : PolylineVertex = { +/// position: Quaternion::new(), +/// color: Color::white(), +/// direction: Quaternion::new(x=1.0), +/// side: 0, +/// } +/// inspect!(vertex.side, content="0") +/// } +/// ``` typealias PolylineVertex = @caterfoil.PolylineVertex ///| +/// Creates an alias for the `Color` type from the caterfoil package, providing a +/// convenient way to work with color values in the visualization system. +/// +/// A color represents an RGBA color value used for rendering geometric shapes +/// and visual elements. Each component (red, green, blue, alpha) is represented +/// as a floating-point number between 0.0 and 1.0. +/// +/// Example: +/// +/// ```moonbit +/// test "color" { +/// let white = Color::white() +/// let semi_transparent = Color::new(r=1.0, g=0.5, b=0.2, a=0.6) +/// inspect!(semi_transparent.a, content="0.6") +/// } +/// ``` typealias Color = @caterfoil.Color diff --git a/src/main/axis.mbt b/src/main/axis.mbt index 8e2069a..5542b1b 100644 --- a/src/main/axis.mbt +++ b/src/main/axis.mbt @@ -1,4 +1,33 @@ ///| +/// Creates a visual representation of the 4D coordinate system axes, with each +/// axis having a different color and extending in both positive and negative +/// directions. The negative parts of the axes are rendered with more +/// transparency. +/// +/// Parameters: +/// +/// * `width` : Optional line width for the axes. If not specified, defaults to +/// 1.0. +/// +/// Returns a `CaterfoilRenderObject` that can be used for rendering the +/// coordinate axes. The axes are colored as follows: +/// +/// * X-axis: yellow +/// * Y-axis: orange +/// * Z-axis: gray +/// * W-axis: bright blue +/// +/// Throws a `BuilderError` if there's an error during the creation of the render +/// object. +/// +/// Example: +/// +/// ```moonbit +/// test "comp_axis" { +/// let axes = comp_axis!(width=2.0) +/// inspect!(axes.label, content="\"axis\"") +/// } +/// ``` fn comp_axis( width? : Float ) -> @caterfoil.CaterfoilRenderObject!@caterfoil.BuilderError { diff --git a/src/main/container.mbt b/src/main/container.mbt index 4eea3ce..bcfd2b6 100644 --- a/src/main/container.mbt +++ b/src/main/container.mbt @@ -58,13 +58,13 @@ fn comp_container( mode=Grid, times=400, width=2, - multiplicand=@quaternion.new(w=1, x=0.01, y=0.02, z=0.0) - .normalize() - .scale(1.003), + multiplicand=@quaternion.Quaternion::new(w=1, x=0.01, y=0.02, z=0.0) + ..normalize_mut() + ..scale_mut(1.003), ) PrimeWalk => comp_prime_walk!() SphereTessellation => comp_sphere_tessellation(times=params.times.or(5)) - CubicArray => comp_cubic_array!(width=2) + CubicArray => comp_cubic_array!(width=1) }, if params.show_axis { comp_axis!(width=4) diff --git a/src/main/main.mbt b/src/main/main.mbt index b5443bc..585f941 100644 --- a/src/main/main.mbt +++ b/src/main/main.mbt @@ -3,14 +3,6 @@ ///| struct Store {} derive(Default) -///| -pub(all) enum Action {} - -///| -pub let store : @caterfoil.Atom[Store] = @caterfoil.Atom::with_value( - Store::default(), -) - ///| fn dispatch() -> Unit { match render_app?() { @@ -20,14 +12,76 @@ fn dispatch() -> Unit { } ///| +/// Represents parameters parsed from URL search string for configuring +/// visualization options. +/// +/// Parameters: +/// +/// * `tab` : The current visualization tab, indicating which visualization to +/// display. Valid values include `QuatCurve`, `HyperCube`, `HyperCubeGrid`, +/// `FlyCity`, `LampTree`, `QuatTree`, `QuatProduct`, `PrimeWalk`, +/// `SphereTessellation`, and `CubicArray`. +/// * `read` : Controls whether to read data from storage. Defaults to `true` if +/// not specified in URL. +/// * `show_axis` : Controls the visibility of coordinate axes in the +/// visualization. Defaults to `true` if not specified in URL. +/// * `times` : Optional integer between 0 and 10 controlling iteration count for +/// recursive visualizations. When not specified in URL or invalid, defaults to +/// `None`. +/// +/// Example: +/// +/// ```moonbit +/// test "search_params" { +/// let params = SearchParams::{ +/// tab: QuatCurve, +/// read: true, +/// show_axis: true, +/// times: Some(5), +/// } +/// inspect!(params.show_axis, content="true") +/// inspect!(params.times, content="Some(5)") +/// } +/// ``` struct SearchParams { + ///| The current visualization tab tab : Tab + ///| Whether to read camera position from localStorage read : Bool + ///| Whether to show coordinate axes show_axis : Bool + ///| Iteration count for recursive visualizations(0-10), only work for some tabs times : Int? } ///| +/// Reads and parses URL search parameters into a structured format. Handles +/// specific parameters: +/// +/// * "tab": Determines which visualization to display +/// * "read": Controls if data should be read +/// * "axis": Controls the visibility of coordinate axes +/// * "times": Controls iteration times for certain visualizations +/// +/// Returns a `SearchParams` structure containing the parsed parameters with the +/// following fields: +/// +/// * `tab`: The current visualization tab, parsed from "tab" parameter +/// * `read`: A boolean indicating whether to read data, defaults to `true` +/// * `show_axis`: A boolean controlling axis visibility, defaults to `true` +/// * `times`: An optional integer between 0 and 10 controlling iteration count +/// +/// Example: +/// +/// ```moonbit +/// test "read_params" { +/// // Assuming URL: "http://example.com?tab=quat-curve&read=false&axis=true×=5" +/// let params = read_params() +/// inspect!(params.read, content="false") +/// inspect!(params.show_axis, content="true") +/// inspect!(params.times, content="Some(5)") +/// } +/// ``` fn read_params() -> SearchParams { let location = @dom_ffi.window().location() let params = @dom_ffi.new_url_search_params(location.search()) diff --git a/src/main/quat-product.mbt b/src/main/quat-product.mbt index b2e298e..ac7ec96 100644 --- a/src/main/quat-product.mbt +++ b/src/main/quat-product.mbt @@ -1,5 +1,5 @@ ///| -pub(all) enum DemoMode { +enum DemoMode { Single Grid } @@ -13,7 +13,7 @@ pub fn comp_quat_product( ) -> @caterfoil.CaterfoilRenderObject { let mut data : Array[PolylineVertex] = [] let multiplicand = multiplicand.or( - @quaternion.new(w=1.0, x=0.08).normalize().scale(1.006), + @quaternion.Quaternion::new(w=1.0, x=0.08).normalize().scale(1.006), ) fn iterate(p0 : Quaternion, times : Int) -> Unit { let mut p = p0 diff --git a/src/main/quat-tree.mbt b/src/main/quat-tree.mbt index 4a71c6e..a8a77d5 100644 --- a/src/main/quat-tree.mbt +++ b/src/main/quat-tree.mbt @@ -44,8 +44,9 @@ fn generate_lines( return ([{ from: base, to: line_to }].iter() + next.iter()).iter() } + ///| -pub fn comp_quat_tree(times? : UInt) -> @caterfoil.CaterfoilRenderObject { +fn comp_quat_tree(times? : UInt) -> @caterfoil.CaterfoilRenderObject { let p0 = @quaternion.q(0, 0, -15, 0) let l0 = @quaternion.q(0, 0, 20, 0) let lines = generate_lines(p0, l0, times.or(8))