feat: finalize corrected-route planning and Rerun recording review
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,25 @@
|
||||
Copyright (c) 2022 Rerun Technologies AB <opensource@rerun.io>
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the
|
||||
Software without restriction, including without
|
||||
limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software
|
||||
is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice
|
||||
shall be included in all copies or substantial portions
|
||||
of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
|
||||
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
|
||||
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
|
||||
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,361 @@
|
||||
--- a/crates/viewer/re_view_spatial/src/eye.rs
|
||||
+++ b/crates/viewer/re_view_spatial/src/eye.rs
|
||||
@@ -2,7 +2,7 @@
|
||||
use glam::{Mat4, Quat, Vec3, vec3};
|
||||
use macaw::IsoTransform;
|
||||
use re_log_types::EntityPath;
|
||||
-use re_sdk_types::blueprint::archetypes::EyeControls3D;
|
||||
+use re_sdk_types::blueprint::archetypes::{EyeControls3D, LineGrid3D};
|
||||
use re_sdk_types::blueprint::components::{AngularSpeed, Eye3DKind};
|
||||
use re_sdk_types::components::{LinearSpeed, Position3D, Vector3D};
|
||||
use re_view::controls::{
|
||||
@@ -214,6 +214,8 @@
|
||||
pub last_look_target: Option<Vec3>,
|
||||
pub last_orbit_radius: Option<f32>,
|
||||
pub last_eye_up: Option<Vec3>,
|
||||
+ /// NODE.DC: time of the last rendered eye, for the read-only WebViewer snapshot.
|
||||
+ pub last_render_time: f64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, re_byte_size::SizeBytes)]
|
||||
@@ -241,6 +243,7 @@
|
||||
fov_y: Option<f32>,
|
||||
|
||||
did_interact: bool,
|
||||
+ grid_plane: macaw::Plane3,
|
||||
}
|
||||
|
||||
impl EyeController {
|
||||
@@ -250,16 +253,8 @@
|
||||
/// Avoids breaking the view by zooming in too far.
|
||||
pub const MIN_ORBIT_DISTANCE: f32 = Eye::PERSPECTIVE_NEAR_PLANE * 2.0;
|
||||
|
||||
- /// Cap on the orbital camera radius, as a multiple of the scene bounding box diagonal.
|
||||
- ///
|
||||
- /// Only applied when scroll-to-zoom wants to grow the radius further. Zoom-in, rotate,
|
||||
- /// pan, WASD, and every other form of motion are left alone — this is intentionally a
|
||||
- /// local restriction on orbital zoom-out only, not a general movement envelope. The 2D
|
||||
- /// view has its own, separate zoom-out cap (see `ui_2d::MAX_ZOOM_OUT_FACTOR`).
|
||||
- ///
|
||||
- /// If the radius already exceeds this (e.g. right after loading) the current radius is
|
||||
- /// used as the cap instead, so the camera isn't pulled back in.
|
||||
- const MAX_ORBITAL_ZOOM_OUT_FACTOR: f32 = 5.0;
|
||||
+ // NODE.DC: finite arithmetic guard only, independent of route/scene bounds.
|
||||
+ const MAX_ORBITAL_RADIUS: f32 = 1.0e17;
|
||||
|
||||
fn get_eye(&self) -> Eye {
|
||||
Eye {
|
||||
@@ -317,6 +312,10 @@
|
||||
.0,
|
||||
);
|
||||
|
||||
+ let grid = ViewProperty::from_archetype::<LineGrid3D>(ctx);
|
||||
+ let grid_plane = grid.component_or_fallback::<re_sdk_types::components::Plane3D>(
|
||||
+ ctx, LineGrid3D::descriptor_plane().component,
|
||||
+ )?;
|
||||
Ok(Self {
|
||||
pos,
|
||||
look_target,
|
||||
@@ -325,6 +324,7 @@
|
||||
eye_up,
|
||||
did_interact: false,
|
||||
fov_y,
|
||||
+ grid_plane: grid_plane.into(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -482,12 +482,45 @@
|
||||
let up = rot * Vec3::Y;
|
||||
let right = rot * -Vec3::X; // TODO(emilk): why do we need a negation here? O.o
|
||||
|
||||
+ // Mission Core's map grid is XY. Screen-plane pan otherwise lifts the
|
||||
+ // orbit target into the air, leaving scroll-to-target stranded there.
|
||||
+ // First-person navigation intentionally retains upstream 3D movement.
|
||||
+ let (right, up) = if self.kind == Eye3DKind::Orbital {
|
||||
+ let normal = self.grid_plane.normal;
|
||||
+ let project = |v: Vec3| v - normal * normal.dot(v);
|
||||
+ let right = project(right).normalize_or(project(Vec3::X).normalize_or(Vec3::Y));
|
||||
+ let up = project(up).normalize_or(normal.cross(-right));
|
||||
+ (right, up)
|
||||
+ } else {
|
||||
+ (right, up)
|
||||
+ };
|
||||
let translate = delta_in_view.x * right + delta_in_view.y * up;
|
||||
|
||||
self.pos += translate;
|
||||
self.look_target += translate;
|
||||
}
|
||||
|
||||
+ /// Translate the whole rig, not its orientation/radius, onto the grid.
|
||||
+ /// Called only by deliberate navigation while not following an entity.
|
||||
+ fn anchor_orbit_to_grid(&mut self) {
|
||||
+ if self.kind == Eye3DKind::Orbital {
|
||||
+ let correction = self.grid_plane.normal
|
||||
+ * (self.grid_plane.d - self.grid_plane.normal.dot(self.look_target));
|
||||
+ self.pos += correction;
|
||||
+ self.look_target += correction;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ fn zoom_orbit(&mut self, zoom_factor: f32) {
|
||||
+ if !zoom_factor.is_finite() || zoom_factor <= 0.0 {
|
||||
+ return;
|
||||
+ }
|
||||
+ let new_radius = (self.radius() / zoom_factor)
|
||||
+ .clamp(Self::MIN_ORBIT_DISTANCE, Self::MAX_ORBITAL_RADIUS);
|
||||
+ self.pos = self.look_target - self.fwd() * new_radius;
|
||||
+ self.did_interact = true;
|
||||
+ }
|
||||
+
|
||||
fn handle_drag(&mut self, response: &egui::Response, drag_threshold: f32) {
|
||||
if response.drag_delta().length() > drag_threshold {
|
||||
let roll = response.dragged_by(ROLL_MOUSE)
|
||||
@@ -513,7 +546,7 @@
|
||||
}
|
||||
|
||||
/// Handle zoom/scroll input.
|
||||
- fn handle_zoom(&mut self, egui_ctx: &egui::Context, scene_bounding_box: &macaw::BoundingBox) {
|
||||
+ fn handle_zoom(&mut self, egui_ctx: &egui::Context, _scene_bounding_box: &macaw::BoundingBox) {
|
||||
let zoom_factor = egui_ctx.input(|input| {
|
||||
// egui's default horizontal_scroll_modifier is shift, which is also our speed-up modifier.
|
||||
// This means that a user who wants to speed up scroll-to-zoom will generate a horizontal scroll delta.
|
||||
@@ -528,22 +561,7 @@
|
||||
|
||||
match self.kind {
|
||||
Eye3DKind::Orbital => {
|
||||
- let radius = self.pos.distance(self.look_target);
|
||||
-
|
||||
- // Cap zoom-out against the scene bounding box. If we're already past the cap
|
||||
- // (e.g. right after loading) use the current radius instead — no snap-back.
|
||||
- let max_radius = max_orbital_radius(scene_bounding_box).max(radius);
|
||||
- let new_radius = (radius / zoom_factor).clamp(Self::MIN_ORBIT_DISTANCE, max_radius);
|
||||
-
|
||||
- // The user may be scrolling to move the camera closer, but are not realizing
|
||||
- // the radius is now tiny.
|
||||
- // TODO(emilk): inform the users somehow that scrolling won't help, and that they should use WSAD instead.
|
||||
- // It might be tempting to start moving the camera here on scroll, but that would is bad for other reasons.
|
||||
-
|
||||
- if f32::MIN_POSITIVE < new_radius {
|
||||
- self.pos = self.look_target - self.fwd() * new_radius;
|
||||
- self.did_interact = true;
|
||||
- }
|
||||
+ self.zoom_orbit(zoom_factor);
|
||||
}
|
||||
Eye3DKind::FirstPerson => {
|
||||
// Move along the forward axis when zooming in first person mode.
|
||||
@@ -707,25 +725,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
-/// Cap on the orbital zoom-out radius, derived from the scene bounding box diagonal.
|
||||
-///
|
||||
-/// Returns `1.0e17` (a large fallback that avoids infinities downstream) when no usable scene
|
||||
-/// bounding box is available.
|
||||
-fn max_orbital_radius(scene_bounding_box: &macaw::BoundingBox) -> f32 {
|
||||
- // `1.0e17` fallback is chosen with generous margin of an observed crash due to infinity.
|
||||
- let fallback = 1.0e17;
|
||||
-
|
||||
- if !scene_bounding_box.is_finite() || scene_bounding_box.is_nothing() {
|
||||
- return fallback;
|
||||
- }
|
||||
- let scene_diagonal = scene_bounding_box.size().length();
|
||||
- if !scene_diagonal.is_finite() || scene_diagonal <= 0.0 {
|
||||
- return fallback;
|
||||
- }
|
||||
- (scene_diagonal * EyeController::MAX_ORBITAL_ZOOM_OUT_FACTOR)
|
||||
- .max(EyeController::MIN_ORBIT_DISTANCE)
|
||||
-}
|
||||
-
|
||||
pub fn find_camera(cameras: &[PinholeWrapper], needle: &EntityPath) -> Option<Eye> {
|
||||
let mut found_camera = None;
|
||||
|
||||
@@ -744,6 +743,103 @@
|
||||
|
||||
fn ease_out(t: f32) -> f32 {
|
||||
1. - (1. - t) * (1. - t)
|
||||
+}
|
||||
+
|
||||
+#[cfg(test)]
|
||||
+mod nodedc_navigation_tests {
|
||||
+ use super::*;
|
||||
+
|
||||
+ fn controller() -> EyeController {
|
||||
+ EyeController {
|
||||
+ pos: vec3(305.0, -80.0, 22.0),
|
||||
+ look_target: vec3(290.0, -60.0, 4.0),
|
||||
+ kind: Eye3DKind::Orbital,
|
||||
+ speed: 30.0,
|
||||
+ eye_up: Vec3::Z,
|
||||
+ fov_y: Some(Eye::DEFAULT_FOV_Y),
|
||||
+ did_interact: false,
|
||||
+ grid_plane: macaw::Plane3 { normal: Vec3::Z, d: 0.0 },
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn pan_is_on_grid_and_moves_the_whole_rig() {
|
||||
+ let mut c = controller();
|
||||
+ let offset = c.pos - c.look_target;
|
||||
+ c.anchor_orbit_to_grid();
|
||||
+ for _ in 0..100 {
|
||||
+ c.translate(egui::vec2(0.5, 0.7));
|
||||
+ }
|
||||
+ assert_eq!(c.look_target.z, 0.0);
|
||||
+ assert!((c.pos - c.look_target - offset).length() < 0.001);
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn rotation_keeps_selected_pivot_and_radius() {
|
||||
+ let mut c = controller();
|
||||
+ c.anchor_orbit_to_grid();
|
||||
+ let target = c.look_target;
|
||||
+ let radius = c.radius();
|
||||
+ for _ in 0..200 {
|
||||
+ c.rotate(egui::vec2(2.0, 0.1));
|
||||
+ }
|
||||
+ assert_eq!(c.look_target, target);
|
||||
+ assert!((c.radius() - radius).abs() < 0.01);
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn zoom_passes_map_scale_without_moving_pivot() {
|
||||
+ let mut c = controller();
|
||||
+ c.anchor_orbit_to_grid();
|
||||
+ let target = c.look_target;
|
||||
+ c.zoom_orbit(0.001);
|
||||
+ assert!(c.radius() > 20_000.0);
|
||||
+ for _ in 0..12 {
|
||||
+ c.zoom_orbit(4.0);
|
||||
+ }
|
||||
+ assert!(c.radius() < 0.03);
|
||||
+ assert_eq!(c.look_target, target);
|
||||
+ assert!(c.get_eye().world_from_rub_view.translation().is_finite());
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn vertical_view_pan_stays_finite_on_grid() {
|
||||
+ let mut c = controller();
|
||||
+ c.pos = vec3(0.0, 0.0, 30.0);
|
||||
+ c.look_target = Vec3::ZERO;
|
||||
+ c.eye_up = Vec3::Y;
|
||||
+ c.translate(egui::vec2(1.0, 1.0));
|
||||
+ assert_eq!(c.look_target.z, 0.0);
|
||||
+ assert!(c.pos.is_finite());
|
||||
+ assert!(c.look_target.length() > 1.0);
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn navigation_respects_the_actual_grid_plane() {
|
||||
+ let mut c = controller();
|
||||
+ c.grid_plane = macaw::Plane3 { normal: Vec3::Y, d: 3.0 };
|
||||
+ c.anchor_orbit_to_grid();
|
||||
+ let target = c.look_target;
|
||||
+ c.translate(egui::vec2(2.0, 4.0));
|
||||
+ c.rotate(egui::vec2(10.0, 3.0));
|
||||
+ assert_eq!(c.look_target.y, 3.0);
|
||||
+ assert_ne!(c.look_target, target);
|
||||
+ }
|
||||
+
|
||||
+ #[test]
|
||||
+ fn invalid_zoom_is_ignored_and_first_person_is_unchanged() {
|
||||
+ let mut c = controller();
|
||||
+ let before = c.pos;
|
||||
+ for factor in [0.0, -1.0, f32::NAN, f32::INFINITY] {
|
||||
+ c.zoom_orbit(factor);
|
||||
+ assert_eq!(c.pos, before);
|
||||
+ }
|
||||
+ c.kind = Eye3DKind::FirstPerson;
|
||||
+ c.anchor_orbit_to_grid();
|
||||
+ assert_eq!(c.look_target.z, 4.0);
|
||||
+ c.translate(egui::vec2(0.0, 1.0));
|
||||
+ assert_ne!(c.look_target.z, 4.0);
|
||||
+ }
|
||||
}
|
||||
|
||||
impl EyeState {
|
||||
@@ -804,9 +900,32 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ // Anchor before the first paint, not on the first orbit drag. This
|
||||
+ // avoids a one-off camera jump when the scene-bounds fallback is high.
|
||||
+ if tracking_entity.is_none() && eye_controller.kind == Eye3DKind::Orbital
|
||||
+ && (eye_controller.grid_plane.normal.dot(eye_controller.look_target)
|
||||
+ - eye_controller.grid_plane.d).abs() > 1.0e-5
|
||||
+ {
|
||||
+ eye_controller.anchor_orbit_to_grid();
|
||||
+ eye_controller.did_interact = true;
|
||||
+ }
|
||||
+
|
||||
// Handle spinning before inputs because some inputs depend on view direction.
|
||||
self.handle_spinning(ctx, eye_property, &mut eye_controller)?;
|
||||
|
||||
+ // NODE.DC: pin manual map navigation to the XY grid. Tracking and
|
||||
+ // explicit camera presets retain their own target until manual input.
|
||||
+ let manual_input = response.drag_delta().length_sq() > 0.0
|
||||
+ || (response.hovered() && response.ctx.input(|i| {
|
||||
+ i.smooth_scroll_delta != egui::Vec2::ZERO || i.zoom_delta() != 1.0
|
||||
+ }));
|
||||
+ if manual_input {
|
||||
+ self.stop_interpolation();
|
||||
+ if tracking_entity.is_none() {
|
||||
+ eye_controller.anchor_orbit_to_grid();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
// We do input before tracking entity, because the input can cause the eye
|
||||
// to stop tracking.
|
||||
let gamepad_navigation_status = eye_controller.handle_input(
|
||||
@@ -1241,6 +1360,7 @@
|
||||
};
|
||||
|
||||
self.last_eye = Some(eye);
|
||||
+ self.last_render_time = ctx.egui_ctx().time();
|
||||
|
||||
Ok(eye)
|
||||
}
|
||||
--- a/crates/viewer/re_viewer_context/src/view/view_states.rs
|
||||
+++ b/crates/viewer/re_viewer_context/src/view/view_states.rs
|
||||
@@ -173,6 +173,13 @@
|
||||
}
|
||||
|
||||
impl ViewStates {
|
||||
+ /// NODE.DC: read-only per-recording state access for native camera snapshots.
|
||||
+ pub fn states_for_store<'a>(&'a self, store_id: &'a StoreId) -> impl Iterator<Item = &'a dyn ViewState> {
|
||||
+ self.states.iter().filter_map(move |((id, _), state)| {
|
||||
+ (id == store_id).then_some(state.as_ref())
|
||||
+ })
|
||||
+ }
|
||||
+
|
||||
pub fn get(&self, store_id: &StoreId, view_id: ViewId) -> Option<&dyn ViewState> {
|
||||
self.states
|
||||
.get(&(store_id.clone(), view_id))
|
||||
--- a/crates/viewer/re_viewer/src/web.rs
|
||||
+++ b/crates/viewer/re_viewer/src/web.rs
|
||||
@@ -384,6 +384,26 @@
|
||||
let recording = hub.entity_db(recording_id)?;
|
||||
|
||||
Some(recording.store_id().recording_id().to_string())
|
||||
+ }
|
||||
+
|
||||
+ /// NODE.DC navigation/v1. Last rendered native eye, never a replay of DOM deltas.
|
||||
+ /// Each Mission Core iframe admits one active 3D pane. Timestamp selection
|
||||
+ /// excludes states retained for a previously selected/reset pane.
|
||||
+ #[wasm_bindgen]
|
||||
+ pub fn nodedc_camera_eye(&self) -> Option<String> {
|
||||
+ let app = self.runner.app_mut::<crate::App>()?;
|
||||
+ let store_id = app.active_recording_id()?;
|
||||
+ let eye_state = app.state.view_states.states_for_store(store_id)
|
||||
+ .filter_map(|state| state.as_any().downcast_ref::<re_view_spatial::SpatialViewState>())
|
||||
+ .map(|state| &state.state_3d.eye_state)
|
||||
+ .filter(|state| state.last_eye.is_some() && state.last_look_target.is_some())
|
||||
+ .max_by(|a, b| a.last_render_time.total_cmp(&b.last_render_time))?;
|
||||
+ let eye = eye_state.last_eye?;
|
||||
+ Some(serde_json::json!({
|
||||
+ "position": eye.pos_in_world().to_array(),
|
||||
+ "lookTarget": eye_state.last_look_target?.to_array(),
|
||||
+ "eyeUp": eye_state.last_eye_up?.to_array(),
|
||||
+ }).to_string())
|
||||
}
|
||||
|
||||
//TODO(#10737): we should refer to logical recordings using store id (recording id is ambiguous)
|
||||
@@ -0,0 +1,44 @@
|
||||
# Rerun 0.36.3 · NODE.DC navigation/v1
|
||||
|
||||
This is the bounded native camera amendment in ADR 0052, not the archived
|
||||
0.34.1 renderer fork. `navigation-build.json` binds the exact upstream commit,
|
||||
portable source patch and paired generated runtime. Keep the upstream licenses.
|
||||
|
||||
## Rebuild
|
||||
|
||||
1. Download the source archive for the manifest's `upstreamCommit` from
|
||||
`https://codeload.github.com/rerun-io/rerun/tar.gz/<commit>` and verify its hash.
|
||||
2. Extract into a new temporary directory and run `git apply --check` followed
|
||||
by `git apply` with `NODEDC_NAVIGATION.patch` at the extracted root.
|
||||
3. Pack that root as `patched-source.tar.gz`. On macOS use
|
||||
`COPYFILE_DISABLE=1 tar --no-mac-metadata --exclude='._*'`; AppleDouble files
|
||||
are not shaders and must not enter the build.
|
||||
4. On Worker006, create a temporary container from the pinned Rust image in
|
||||
the manifest, with 4 CPUs, 16 GB memory, no GPU, no ports and no private data.
|
||||
Use the `ndc-` name and NODE.DC ownership labels required by AGENTS.md.
|
||||
Copy the archive to `/work/patched-source.tar.gz` and the repository's
|
||||
`scripts/build-rerun-navigation.sh` to `/work/build-rerun-navigation.sh`.
|
||||
Entrypoint: `bash /work/build-rerun-navigation.sh`.
|
||||
5. Require the native navigation tests to pass. The upstream
|
||||
`rerun_js/web-viewer/build-wasm.mjs --mode release` produces the matching
|
||||
`re_viewer.js`, `re_viewer.d.ts` and `re_viewer_bg.wasm`. Copy all three,
|
||||
never only WASM, to the artifact names in this directory's manifest.
|
||||
6. Recheck source patch, build script and generated file hashes. Update the
|
||||
manifest, run the installer twice (idempotency), vendor ABI checks, frontend
|
||||
contracts/build, then real product-browser QA. Remove the temporary build
|
||||
container after copying artifacts and evidence.
|
||||
|
||||
The source archive and build cache are not runtime dependencies. No compiler,
|
||||
Docker or hardware access is needed on a clean operator install: the existing
|
||||
exact npm package plus `postinstall` installs the audited paired artifacts.
|
||||
An unfamiliar package or artifact is rejected before any file is changed.
|
||||
|
||||
## Upgrade / rollback
|
||||
|
||||
Rebase against the next exact upstream source, not against minified JS. Retest
|
||||
grid-plane pan, fixed-pivot orbit, close/far zoom, explicit reset/top/follow,
|
||||
display updates, normal/expanded views and disposable-iframe cleanup.
|
||||
|
||||
To roll back, disable `postinstall`/`prebuild`, restore the official exact npm
|
||||
package and rebuild. Missing snapshots are represented as null, not simulated
|
||||
camera state. Recordings, corrected maps and scanner sessions are unchanged.
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"schema": "nodedc.rerun-navigation/v1",
|
||||
"upstreamVersion": "0.36.3",
|
||||
"upstreamCommit": "6ded109d33c549e98185f7c95fa8009d44e4adef",
|
||||
"upstreamArchiveSha256": "3f92aef3f33f63c79b275b5c66a65d73192e75967cbcd3d1f16c75010996f896",
|
||||
"patchSha256": "a893a4b4e7523cca88284316c88b930c3b91ba973ed3f954c9ca632f71252e64",
|
||||
"cargoLockSha256": "74cdf9c3c8c5dbe5a368f1a9a58b011e2a45720843b30e552bc7b1d8ac21d791",
|
||||
"buildScriptSha256": "e3cbd5da889403eda3ffba7c020b6075bdfb025b823d1bf503b639f59688135a",
|
||||
"buildDate": "2026-09-21",
|
||||
"rustImage": "rust:1.95-bookworm@sha256:6258907abe69656e41cd992e0b705cdcfabcbbe3db374f92ed2d47121282d4a1",
|
||||
"binaryenVersion": "117",
|
||||
"binaryenArchiveSha256": "3dc677006555b355ea2da5e82602065a161d5e83eaefd3f759afa00b96e83212",
|
||||
"wasmBindgenVersion": "0.2.126",
|
||||
"nativeTestsPassed": 6,
|
||||
"files": {
|
||||
"index.js": { "upstreamSha256": "009aa5f66c8674ea268a91926c00e2f82cc7a7b7e5535056d93bd4656d6f6812" },
|
||||
"index.ts": { "upstreamSha256": "087b25170f720a28aa69c411903133286238900050ac775d2cc511b919846696" },
|
||||
"index.d.ts": { "upstreamSha256": "649637dad4e50ef4f2310fc1920b580d16832226a0dda5238355059bf167efba" },
|
||||
"re_viewer.js": {
|
||||
"upstreamSha256": "d2a94836dd0e6de40538c4d657cfb423b1803e354e6ee0cd550735eb5aaab09b",
|
||||
"artifact": "re_viewer.nodedc.js",
|
||||
"sha256": "610d89abffcc5c329797e77794ae2ab5b426c80a5b23fd24064c7d47c6583d3a"
|
||||
},
|
||||
"re_viewer.d.ts": {
|
||||
"upstreamSha256": "9a77a4e1e1aa8311185a3f275bf326a8fff2844e468e561c59d5f0ee7aa6debe",
|
||||
"artifact": "re_viewer.nodedc.d.ts",
|
||||
"sha256": "cfbf010d66560af919aa68d255a6ddc7120829f8ee8f27a41f56d943cd54e598"
|
||||
},
|
||||
"re_viewer_bg.wasm": {
|
||||
"upstreamSha256": "02d6d9c3a569d3faceb01cf89104342d970fc85e7c31a08dedd357b6c7104d2f",
|
||||
"artifact": "re_viewer_bg.nodedc.wasm",
|
||||
"sha256": "2b661de545ac90bb950eda1a28fc5a7c3ce4ca7f5bb24894789acf7589495185"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
|
||||
declare namespace wasm_bindgen {
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/**
|
||||
* The `ReadableStreamType` enum.
|
||||
*
|
||||
* *This API requires the following crate features to be activated: `ReadableStreamType`*
|
||||
*/
|
||||
|
||||
export type ReadableStreamType = "bytes";
|
||||
|
||||
export class IntoUnderlyingByteSource {
|
||||
private constructor();
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
cancel(): void;
|
||||
pull(controller: ReadableByteStreamController): Promise<any>;
|
||||
start(controller: ReadableByteStreamController): void;
|
||||
readonly autoAllocateChunkSize: number;
|
||||
readonly type: ReadableStreamType;
|
||||
}
|
||||
|
||||
export class IntoUnderlyingSink {
|
||||
private constructor();
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
abort(reason: any): Promise<any>;
|
||||
close(): Promise<any>;
|
||||
write(chunk: any): Promise<any>;
|
||||
}
|
||||
|
||||
export class IntoUnderlyingSource {
|
||||
private constructor();
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
cancel(): void;
|
||||
pull(controller: ReadableStreamDefaultController): Promise<any>;
|
||||
}
|
||||
|
||||
export class WebHandle {
|
||||
free(): void;
|
||||
[Symbol.dispose](): void;
|
||||
/**
|
||||
* Add a new receiver streaming data from the given url.
|
||||
*
|
||||
* Websocket streams are always opened in `Following` mode.
|
||||
*
|
||||
* It is an error to open a channel twice with the same id.
|
||||
*/
|
||||
add_receiver(url: string): void;
|
||||
/**
|
||||
* Close an existing channel for streaming data.
|
||||
*
|
||||
* No-op if the channel is already closed.
|
||||
*/
|
||||
close_channel(id: string): void;
|
||||
destroy(): void;
|
||||
get_active_recording_id(): string | undefined;
|
||||
get_active_timeline(recording_id: string): string | undefined;
|
||||
get_playing(recording_id: string): boolean | undefined;
|
||||
get_time_for_timeline(recording_id: string, timeline_name: string): number | undefined;
|
||||
get_timeline_time_range(recording_id: string, timeline_name: string): any;
|
||||
has_panicked(): boolean;
|
||||
constructor(app_options: any);
|
||||
/**
|
||||
* NODE.DC navigation/v1. Last rendered native eye, never a replay of DOM deltas.
|
||||
* Each Mission Core iframe admits one active 3D pane. Timestamp selection
|
||||
* excludes states retained for a previously selected/reset pane.
|
||||
*/
|
||||
nodedc_camera_eye(): string | undefined;
|
||||
/**
|
||||
* Open a new channel for streaming data.
|
||||
*
|
||||
* It is an error to open a channel twice with the same id.
|
||||
*/
|
||||
open_channel(id: string, channel_name: string): void;
|
||||
override_panel_state(panel: string, state?: string | null): void;
|
||||
panic_callstack(): string | undefined;
|
||||
panic_message(): string | undefined;
|
||||
remove_receiver(url: string): void;
|
||||
/**
|
||||
* Add an rrd to the viewer directly from a byte array.
|
||||
*/
|
||||
send_rrd_to_channel(id: string, data: Uint8Array): void;
|
||||
send_table_to_channel(id: string, data: Uint8Array): void;
|
||||
set_active_recording_id(recording_id: string): void;
|
||||
/**
|
||||
* Set the active timeline.
|
||||
*
|
||||
* This does nothing if the timeline can't be found.
|
||||
*/
|
||||
set_active_timeline(recording_id: string, timeline_name: string): void;
|
||||
set_credentials(access_token: string, email: string): void;
|
||||
set_playing(recording_id: string, value: boolean): void;
|
||||
set_time_for_timeline(recording_id: string, timeline_name: string, time: number): void;
|
||||
start(canvas: any): Promise<void>;
|
||||
toggle_panel_overrides(value?: boolean | null): void;
|
||||
}
|
||||
|
||||
}
|
||||
declare type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module;
|
||||
|
||||
declare interface InitOutput {
|
||||
readonly memory: WebAssembly.Memory;
|
||||
readonly __wbg_webhandle_free: (a: number, b: number) => void;
|
||||
readonly webhandle_add_receiver: (a: number, b: number, c: number) => void;
|
||||
readonly webhandle_close_channel: (a: number, b: number, c: number) => void;
|
||||
readonly webhandle_destroy: (a: number) => void;
|
||||
readonly webhandle_get_active_recording_id: (a: number) => [number, number];
|
||||
readonly webhandle_get_active_timeline: (a: number, b: number, c: number) => [number, number];
|
||||
readonly webhandle_get_playing: (a: number, b: number, c: number) => number;
|
||||
readonly webhandle_get_time_for_timeline: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
||||
readonly webhandle_get_timeline_time_range: (a: number, b: number, c: number, d: number, e: number) => any;
|
||||
readonly webhandle_has_panicked: (a: number) => number;
|
||||
readonly webhandle_new: (a: any) => [number, number, number];
|
||||
readonly webhandle_nodedc_camera_eye: (a: number) => [number, number];
|
||||
readonly webhandle_open_channel: (a: number, b: number, c: number, d: number, e: number) => void;
|
||||
readonly webhandle_override_panel_state: (a: number, b: number, c: number, d: number, e: number) => [number, number];
|
||||
readonly webhandle_panic_callstack: (a: number) => [number, number];
|
||||
readonly webhandle_panic_message: (a: number) => [number, number];
|
||||
readonly webhandle_remove_receiver: (a: number, b: number, c: number) => void;
|
||||
readonly webhandle_send_rrd_to_channel: (a: number, b: number, c: number, d: number, e: number) => void;
|
||||
readonly webhandle_send_table_to_channel: (a: number, b: number, c: number, d: number, e: number) => void;
|
||||
readonly webhandle_set_active_recording_id: (a: number, b: number, c: number) => void;
|
||||
readonly webhandle_set_active_timeline: (a: number, b: number, c: number, d: number, e: number) => void;
|
||||
readonly webhandle_set_credentials: (a: number, b: number, c: number, d: number, e: number) => void;
|
||||
readonly webhandle_set_playing: (a: number, b: number, c: number, d: number) => void;
|
||||
readonly webhandle_set_time_for_timeline: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
|
||||
readonly webhandle_start: (a: number, b: any) => any;
|
||||
readonly webhandle_toggle_panel_overrides: (a: number, b: number) => void;
|
||||
readonly rust_lz4_wasm_shim_calloc: (a: number, b: number) => number;
|
||||
readonly rust_lz4_wasm_shim_free: (a: number) => void;
|
||||
readonly rust_lz4_wasm_shim_malloc: (a: number) => number;
|
||||
readonly rust_lz4_wasm_shim_memcmp: (a: number, b: number, c: number) => number;
|
||||
readonly rust_lz4_wasm_shim_memcpy: (a: number, b: number, c: number) => number;
|
||||
readonly rust_lz4_wasm_shim_memmove: (a: number, b: number, c: number) => number;
|
||||
readonly rust_lz4_wasm_shim_memset: (a: number, b: number, c: number) => number;
|
||||
readonly rust_zstd_wasm_shim_calloc: (a: number, b: number) => number;
|
||||
readonly rust_zstd_wasm_shim_free: (a: number) => void;
|
||||
readonly rust_zstd_wasm_shim_malloc: (a: number) => number;
|
||||
readonly rust_zstd_wasm_shim_memcmp: (a: number, b: number, c: number) => number;
|
||||
readonly rust_zstd_wasm_shim_memcpy: (a: number, b: number, c: number) => number;
|
||||
readonly rust_zstd_wasm_shim_memmove: (a: number, b: number, c: number) => number;
|
||||
readonly rust_zstd_wasm_shim_memset: (a: number, b: number, c: number) => number;
|
||||
readonly rust_zstd_wasm_shim_qsort: (a: number, b: number, c: number, d: number) => void;
|
||||
readonly __wbg_intounderlyingbytesource_free: (a: number, b: number) => void;
|
||||
readonly __wbg_intounderlyingsink_free: (a: number, b: number) => void;
|
||||
readonly __wbg_intounderlyingsource_free: (a: number, b: number) => void;
|
||||
readonly intounderlyingbytesource_autoAllocateChunkSize: (a: number) => number;
|
||||
readonly intounderlyingbytesource_cancel: (a: number) => void;
|
||||
readonly intounderlyingbytesource_pull: (a: number, b: any) => any;
|
||||
readonly intounderlyingbytesource_start: (a: number, b: any) => void;
|
||||
readonly intounderlyingbytesource_type: (a: number) => number;
|
||||
readonly intounderlyingsink_abort: (a: number, b: any) => any;
|
||||
readonly intounderlyingsink_close: (a: number) => any;
|
||||
readonly intounderlyingsink_write: (a: number, b: any) => any;
|
||||
readonly intounderlyingsource_cancel: (a: number) => void;
|
||||
readonly intounderlyingsource_pull: (a: number, b: any) => any;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__ha28703b0fc0ac5f5: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h17feb392561402d4: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__hd1708d5debff0eb7: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h17feb392561402d4_10: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h17feb392561402d4_11: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h68d110bc138a9729: (a: number, b: number, c: any) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h4a090e5af75dc439: (a: number, b: number, c: any, d: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h72e0675ea71ceaf9: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h76e373640bdbaace: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h912ec1a6c04fd19b: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h76e373640bdbaace_4: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__ha366fcce789d0db1: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h3d976baa4adbebda: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h912ec1a6c04fd19b_9: (a: number, b: number, c: any) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__hbf8a291ae3f8f46d: (a: number, b: number) => [number, number];
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h0e2ab714131e0149: (a: number, b: number) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h2a38a854c15eed3d: (a: number, b: number) => void;
|
||||
readonly wasm_bindgen__convert__closures_____invoke__h46084f6dced1097a: (a: number, b: number) => void;
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __externref_table_alloc: () => number;
|
||||
readonly __wbindgen_externrefs: WebAssembly.Table;
|
||||
readonly __wbindgen_exn_store: (a: number) => void;
|
||||
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||
readonly __wbindgen_destroy_closure: (a: number, b: number) => void;
|
||||
readonly __externref_table_dealloc: (a: number) => void;
|
||||
readonly __wbindgen_start: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* If `module_or_path` is {RequestInfo} or {URL}, makes a request and
|
||||
* for everything else, calls `WebAssembly.instantiate` directly.
|
||||
*
|
||||
* @param {{ module_or_path: InitInput | Promise<InitInput> }} module_or_path - Passing `InitInput` directly is deprecated.
|
||||
*
|
||||
* @returns {Promise<InitOutput>}
|
||||
*/
|
||||
declare function wasm_bindgen (module_or_path: { module_or_path: InitInput | Promise<InitInput> } | InitInput | Promise<InitInput>): Promise<InitOutput>;
|
||||
|
||||
export type WebHandle = wasm_bindgen.WebHandle;
|
||||
export default function(): wasm_bindgen;
|
||||
File diff suppressed because it is too large
Load Diff
BIN
Binary file not shown.
Reference in New Issue
Block a user