Commit Graph

766 Commits

Author SHA1 Message Date
Hans Goudey
14a42c0928 Cleanup: Use C++ vector types for convex hull API
Pull Request: https://projects.blender.org/blender/blender/pulls/140233
2025-06-11 22:46:27 +02:00
Hans Goudey
fa03c53d4a Point Cloud: Use AttributeStorage instead of CustomData
This moves `PointCloud` to use the recently added `AttributeStorage`
at runtime. Mainly this involves implementing the higher level attribute
API on top, and implementing the RNA API as well. The attribute RNA type
is now backed by either CustomDataLayer or bke::Attribute. For now the
new code is specific to point clouds but next steps can reuse it for
Grease Pencil layer attributes, curves, and eventually meshes.

Point cloud attributes no longer have a name length limit.

Internally, the `AttributeStorage` API is extended with a few additions:
- The data structs have static constructors for convenience.
- A few functions give index-based access to attributes
- A "rename" function is added.

The `Attribute` RNA type now exposes a `storage_type` property.
For now the "single value" option is still unused at runtime, and
accessing the single value data isn't implemented yet.

Pull Request: https://projects.blender.org/blender/blender/pulls/139165
2025-06-09 21:53:20 +02:00
Jacques Lucke
3ce212b9ac Fix #139981: volume transform crash with bad matrix 2025-06-09 09:09:18 +02:00
Campbell Barton
bb8c0b4397 Cleanup: spelling, use doxygen comments, move doc-string to declaration 2025-06-08 19:49:24 +10:00
Laurynas Duburas
46bc894570 Fix: Curves: Custom knots in Curves and GP operators
Current strategy to deal with operators not supporting custom NURBS
knots is to fall back to calculated knots for curves of the custom mode
but with no `CurvesGeometry::custom_knots` allocated. Such curves are
the result of operators that copy only `Point` and `Curve` domains. This
way the problem is only postponed. It is not possible to add new custom
knot curves to such `CurvesGeometry` as custom knot offsets are
calculated all together and there is no way to distinguish between old
curves with lost knots and new ones. This is more a future problem.

The actual problem in `main` can be shown with an attached blend file
(see PR) by applying `Subdivide` to some points and then adding new
`Bezier` curve to the same object. This particular problem could be
addressed somewhere in `realize_instances.cc` but the actual problem
would persist.

This PR handles custom knots in all places where `BKE_defgroup_copy_list`
is iused, and where `bke::curves::copy_only_curve_domain` is called.
Here the assumption is made that only these places can copy custom knots
modes without copying custom knots. Depending on operator logic knots are
handled most often in one of two ways:
 - `bke::curves::nurbs::copy_custom_knots`:
   copies custom knots for all curves excluding `selection`. Knot modes
   for excluded curves are altered from the custom mode to calculated.
   This way only curves modified by the operator will loose custom knots.
 - `bke::curves::nurbs::update_custom_knot_modes;`
   alters all curves to calculated mode.

In some places (e.g. `reorder.cc`) it is possible to deal with knots
without side effects.

PR also adds `BLI_assert` in `load_curve_knots` function to check if
`CurvesGeometry::custom_knots` exists for custom mode curves. Thus
versioning code is needed addressing the issue in files in case such
already exists.
Pull Request: https://projects.blender.org/blender/blender/pulls/139554
2025-06-04 20:43:15 +02:00
Falk David
889751b0c5 Grease Pencil: Add Convert Curve Type operator
Adds a new operator in Grease Pencil edit mode to convert between curve
types. This acts as a replacment for the `Set Curve Type` operator as
the new operator better aligns with previous workflows and artist
expectations. Specifically using a threshold to adjust how well the
resulting curves fit to the original.

It can be found in the `Stroke` > `Convert Type` menu.

This operator aims at keeping visual fidelity between the curves. When
converting to a non-poly curve type, there's a `threshold` parameter
that dictates how closley the shapes will match (a value of zero meaning
an almost perfect match, and higher values will result in less accuracy
but lower control point count).

The conversion to `Catmull-Rom` does not do an actual curve fitting.
For now, this will resample the curves and then do an adaptive
simplification of the line (using the threshold parameter)
to simulate a curve fitting.

The `Set Curve Type` operator is no longer exposed in the
`Stroke` menu.

This also adds a new `geometry::fit_curves` function.

The function will fit a selection of curves to bézier curves. The
selected curves are treated as if they were poly curves.

The `thresholds` virtual array is the error threshold distance
 for each curve that the fit should be within. The size of the virtual
 array is assumed to have the same size as the total number of
 input curves.

The `corners` virtual array allows specific input points to be treated
as sharp corners. The resulting bezier curve will have this point and
the handles will be set to "free".

There are two fitting methods:
* **Split**: Uses a least squares solver to find the control
                     points (faster, but less accurate).
* **Refit**: Iteratively removes knots with the least error starting
                     with a dense curve (slower, more accurate fit).

Co-authored-by: Casey Bianco-Davis <caseycasey739@gmail.com>
Co-authored-by: Hans Goudey <hans@blender.org>

Pull Request: https://projects.blender.org/blender/blender/pulls/137808
2025-06-04 11:48:15 +02:00
YimingWu
0ed1429fd3 Fix #139776: Grease Pencil: Prevent fillet on empty curves
`blender::geometry::fillet_curves` should check for situations where empty
curves are passed in (this could happen in geometry nodes) and in those
cases it should not run.

Pull Request: https://projects.blender.org/blender/blender/pulls/139787
2025-06-03 16:08:03 +02:00
Hans Goudey
881199d92c Fix #139256: For each element uses incorrect default curve type
curves_new_nomain_single should only really be used for creating new
curves completely from scratch.
2025-05-22 10:18:24 -04:00
Campbell Barton
e97e9c2904 Cleanup: various non functional changes for C++ 2025-05-15 10:26:47 +10:00
Hans Goudey
92de7a4cbf Fix #138279: Realize instances node with depth input can crash
When not all the meshes referenced by the instances recursively
are realized because of the limit of the depth input, and those
meshes have vertex groups, a crash is possible because of an
un-checked VectorSet lookup. `all_meshes_info.order` includes
all meshes regardless of the depth and mask arguments.

Pull Request: https://projects.blender.org/blender/blender/pulls/138519
2025-05-07 02:15:04 +02:00
Hans Goudey
3445a191cb Fix: Potential use after free in realize instances node
These attributes are handled specifically in execute_instances_tasks
anyway so the generic code path doesn't make sense. Referencing
those attributes is incorrect since the temporary geometry set built
for collections goes out of scope after foreach_geometry_in_reference.

Part of #138279

Pull Request: https://projects.blender.org/blender/blender/pulls/138508
2025-05-06 18:08:28 +02:00
Lukas Tönne
ce8f30f92c Fix #138447: Invalid voxel size due to arbitrary threshold
OpenVDB has a voxel size limit defined by the determinant of the grid
transform, which is equivalent to a uniform voxel size of
`sqrt3(3e-15) ~= 1.44e-5`.
The `mesh_to_density_grid` function was using an arbitrary threshold of
`1.0e-5` for the uniform voxel size.
In this case the voxel size is `~1.343e-5` so it passes the Blender
threshold but crashes in OpenVDB.

This fix adds some convenience functions to check for valid grid voxel
size and transform based on the same determinant metric. This is now
employed consistently in the mesh_to_density_grid, mesh_to_sdf_grid, and
points_to_sdf_grid functions to avoid exceptions in OpenVDB.

MOD_volume_to_mesh, node_geo_volume_to_mesh, BKE_mesh_remesh_voxel have
not been modified, since they have their own error checks with larger
thresholds.

Pull Request: https://projects.blender.org/blender/blender/pulls/138481
2025-05-06 16:08:24 +02:00
Hans Goudey
71ac8eee68 Cleanup: Use const arguments for realize instances function
OrderedAttributes was passed by value unnecessarily.
2025-05-03 15:25:24 -04:00
Campbell Barton
43af16a4c1 Cleanup: spelling in comments, correct comment block formatting
Also use doxygen comments more consistently.
2025-05-01 11:44:33 +10:00
Philipp Oeser
1ae6d13b5f Fix #138178: Grease Pencil strokes loose vertexgroups after Re-Arrange
Caused by 9d13e39585

Compared to meshes (which in that commit did a
`BKE_mesh_copy_parameters_for_eval` on the new Mesh
[mesh_new_no_attributes] -- this includes copying `vertex_group_names`)
Curves were missing that.

Now added.

Pull Request: https://projects.blender.org/blender/blender/pulls/138202
2025-04-30 15:34:45 +02:00
Howard Trickey
15623b26b9 Fix #137968: Bad custom normals after Manifold boolean.
Custom normals are interpolated with the new Manifold boolean
code. In the other two solvers, there is no interplation for the
CD_PROP_INT16_2D type so custom normals were left at (0,0) when
an exact copy from the input corner isn't possible.
The new code for manifold first does a join mesh, which converts
custom normals to float3, which can be (and are) interpolated.
However, if the input face (or face fragment) has flipped normal
in the boolean output, then the custom normal should be flipped to.
The fix is to do that for attributes called "custom_normal".
The general case of a "normal-like" thing with a different name
remains unsolved, but I doubt that case comes up often.
2025-04-27 19:36:28 -04:00
Howard Trickey
5f57d9ac94 Modeling: fix face merging issue with manifold boolean.
The new manifold boolean operation would merge coplanar faces
even if they had different faceIDs. This doesn't fit user
expectations.
By using the manifold library's "OriginalID" mechanism, we can
prevent that from happening. However, it slows the code by
almost a factor of 2 on large examples.
The Manifold maintainers going to work on a better solution.
2025-04-24 21:32:52 -04:00
Campbell Barton
8ccdea1934 Cleanup: typos & references to variable names from recent refactor 2025-04-24 02:43:52 +00:00
Hans Goudey
8db322f1f5 Fix #137902: Manifold boolean modifier solver doubles object transform
The object to world transform was applied to the result (which was
meant to be in world space), rather than the inverse. However, the
processing of transforms is more complicated than necessary. Instead
of passing around a separate "target transform" that's meant to be used
inverted after the boolean operation, just make the input transforms
transform the input meshes into the desired transform space of the
output (object-local space for the modifier).

Pull Request: https://projects.blender.org/blender/blender/pulls/137919
2025-04-23 20:37:53 +02:00
Hans Goudey
ba99f6832e Mesh: Tag no loose vertices for Manifold Boolean output
Saves a tiny amount of time computing the loose vertices cache
after a boolean operation. Since the boolean output is just created
from faces, there are no loose vertices (there are also no loose
edges because of the call to `mesh_calc_edges`, which itself
tags the loose edge cache).
2025-04-23 12:08:10 -04:00
Campbell Barton
22d0391583 Cleanup: spelling in comments, use doxygen comments for doc-strings 2025-04-23 13:16:20 +10:00
Howard Trickey
dd559259d8 Modeling: Add a new boolean solver based on the Manifold library.
Adds the 'manifold' solver option to the Boolean geo node and to
the Boolean modifier. This solver is about as fast, or faster,
than the current float solver, and is robust against floating
point issues like the Exact solver. But currently it only
works on mesh arguments that are strictly manifold.

See https://projects.blender.org/blender/blender/issues/120182
for many more details.
2025-04-22 21:23:37 -04:00
Brecht Van Lommel
fb2ba20b67 Refactor: Use more typed MEM_calloc<> and MEM_malloc<>
Pull Request: https://projects.blender.org/blender/blender/pulls/137822
2025-04-22 11:22:18 +02:00
Brecht Van Lommel
637c6497e9 Refactor: Use more typed MEM_calloc<>, avoid unnecessary size_t cast
Handle some cases that were missed in previous refactor. And eliminate
unnecessary size_t casts as these could hide issues.

Pull Request: https://projects.blender.org/blender/blender/pulls/137404
2025-04-21 17:59:41 +02:00
Falk David
3a7b2f713f Fix #137523: Grease Pencil: Crash in realize instance node
In the function `gather_attributes_to_propagate` all the instance
attributes were set to be propagated to the `Point` domain.

For Grease Pencil, we want to make sure to propagate these
attributes to the `Layer` domain instead.

Pull Request: https://projects.blender.org/blender/blender/pulls/137665
2025-04-17 18:43:43 +02:00
Jacques Lucke
3ae20bf166 Cleanup: remove foreach macro from .clang-format
The usage of that macro was removed in 60bec183cb,
but it was still in our .clang-format file. This lead to worse formatting when other code
used methods named `foreach`.

Pull Request: https://projects.blender.org/blender/blender/pulls/137468
2025-04-14 16:17:00 +02:00
Falk David
5aea7b4591 Fix #136243: Grease Pencil: Automerge doesn't propagate vertex groups
The `vertex_group_names` of the `CurvesGeometry` was not being
propagated leading to vertex group data getting lost.

Pull Request: https://projects.blender.org/blender/blender/pulls/137296
2025-04-11 10:53:58 +02:00
Hans Goudey
d3f84449ad Mesh: Add "free" custom normals
Add a "dumb vector" storage option for custom normals, with the
"custom_normal" attribute. Adjust the mesh normals caching to
provide this attribute if it's available, and add a geometry node to
store custom normals.

## Free Normals
They're called "free" in the sense that they're just direction vectors
in the object's local space, rather than the existing "smooth corner
fan space" storage. They're also "free" in that they make further
normals calculation very inexpensive, since we just use the custom
normals instead. That's a big improvement from the existing custom
normals storage, which usually significantly decreases
viewport performance. For example, in a simple test file just storing
the vertex normals on a UV sphere, using free normals gives 25 times
better playback performance and 10% lower memory usage.

Free normals are adjusted when applying a transformation to the entire
mesh or when realizing instances, but in general they're not updated for
vertex deformations.

## Set Mesh Normal Node
The new geometry node allows storing free custom normals as well as
the existing corner fan space normals. When free normals are chosen,
free normals can be stored on vertices, faces, or face corners. Using
the face corner domain is necessary to bake existing mixed sharp and
smooth edges into the custom normal vectors.

The node also has a mode for storing edge and mesh sharpness, meant
as a "soft" replacement to the "Set Shade Smooth" node that's a bit
more convenient.

## Normal Input Node
The normal node outputs free custom normals mixed to whatever domain is
requested. A "true normal" output that ignores custom normals and
sharpness is added as well.

Across Blender, custom normals are generally accessed via face and
vertex normals, when "true normals" are not requested explicitly.
In many cases that means they are mixed from the face corner domain.

## Future Work
1. There are many places where propagation of free normals could be
   improved. They should probably be normalized after mixing, and it
   may be useful to not just use 0 vectors for new elements. To keep
   the scope of this change smaller, that sort of thing generally isn't
   handled here. Searching `CD_NORMAL` gives a hint of where better
   propagation could be useful.
2. Free normals are displayed properly in edit mode, but the existing
   custom normal editing operators don't work with free normals yet.
   This will hopefully be fairly straightforward since custom normals
   are usually converted to `float3` for editing anyway. Edit mode
   changes aren't included here because they're unnecessary for the
   procedural custom normals use cases.
3. Most importers can probably switch to using free normals instead,
   or at least provide an option for it. That will give a significant
   import performance improvement, and an improvement of Blender's
   FPS for imported scenes too.

Pull Request: https://projects.blender.org/blender/blender/pulls/132583
2025-04-04 19:16:51 +02:00
Laurynas Duburas
8f6af72a3f Curves: Custom NURBS knots
Adds new NURBS knot mode NURBS_KNOT_MODE_FREE. Knots are stored in
`CurvesGeometry::custom_knots`. Knot offsets binding them to their
curves are calculated at runtime and held in a cache. This commit adds
custom knots support to OBJ import. It is the only way create such
curves for now. Legacy curve's tools don't support this knot mode,
thus on any modification knots get regenerated and whole shape changes.
If to convert imported legacy curve to new curves, point deletion,
duplicate and extrude preserve custom knots.

Rel #99891

Pull Request: https://projects.blender.org/blender/blender/pulls/130132
2025-04-01 20:22:47 +02:00
Hans Goudey
448d3d04d9 Cleanup: Unify and clean up mesh transform & translation functions
Use C++ types, move to C++ header, use them consistently in the
geometry transform function.
2025-03-28 11:36:39 -04:00
Jacques Lucke
ce4a152c64 Geometry: avoid invalidating caches when transforming by identity
Transforming e.g. a mesh can invalidate caches like bvh trees. Therefore,
if it can be skipped, it should be skipped.
2025-03-27 19:41:30 +01:00
Bastien Montagne
015f8150a2 Cleanup: geometry: Replace 'void' MEM_[cm]allocN with templated, type-safe MEM_[cm]allocN<T>.
The main issue of 'type-less' standard C allocations is that there is no check on
allocated type possible.

This is a serious source of annoyance (and crashes) when making some
low-level structs non-trivial, as tracking down all usages of these
structs in higher-level other structs and their allocation is... really
painful.

MEM_[cm]allocN<T> templates on the other hand do check that the
given type is trivial, at build time (static assert), which makes such issue...
trivial to catch.

NOTE: New code should strive to use MEM_new (i.e. allocation and
construction) as much as possible, even for trivial PoD types.

Pull Request: https://projects.blender.org/blender/blender/pulls/136116
2025-03-18 11:58:05 +01:00
Falk David
15d71a02ff Merge branch 'blender-v4.4-release' 2025-03-10 14:55:02 +01:00
YimingWu
d443932c73 Fix #135728: Grease Pencil: Correct point count in length modifier
In Grease Pencil length modifier, if a stroke is not filtered, it
may not have a valid point count/offset. This fix ensures that we
get valid point count by copying it beforehand.

Pull Request: https://projects.blender.org/blender/blender/pulls/135733
2025-03-10 14:54:28 +01:00
Sybren A. Stüvel
5597e01aa6 Merge remote-tracking branch 'origin/blender-v4.4-release' 2025-03-07 11:25:30 +01:00
YimingWu
8ebeafa6b9 Fix #135586: Grease Pencil: Crash in length modifier extending curves
Previously in 43fde8c39c the point span
for calling `extend_curves_straight` was set to a fixed `{1}` with only
1 element, this causes index access to go out of range, which is the
cause of crash #135586. However there are some other issues within the
code path, mainly:

- The meaning of `start/end_points` are unclear
- Behaviour of extending a 2-point stroke is undefined

This PR clarifies these by adding some comments and change a bit of the
logic in the code so it's more understandable.

Pull Request: https://projects.blender.org/blender/blender/pulls/135608
2025-03-07 11:24:21 +01:00
Hans Goudey
d88d6331fd Cleanup: Modernize mesh variable naming in some cases
Simplify naming of vertex and corner indices, and replace "loop".
2025-03-05 23:16:09 -05:00
Bastien Montagne
dd168a35c5 Refactor: Replace MEM_cnew with a type-aware template version of MEM_callocN.
The general idea is to keep the 'old', C-style MEM_callocN signature, and slowly
replace most of its usages with the new, C++-style type-safer template version.

* `MEM_cnew<T>` allocation version is renamed to `MEM_callocN<T>`.
* `MEM_cnew_array<T>` allocation version is renamed to `MEM_calloc_arrayN<T>`.
* `MEM_cnew<T>` duplicate version is renamed to `MEM_dupallocN<T>`.

Similar templates type-safe version of `MEM_mallocN` will be added soon
as well.

Following discussions in !134452.

NOTE: For now static type checking in `MEM_callocN` and related are slightly
different for Windows MSVC. This compiler seems to consider structs using the
`DNA_DEFINE_CXX_METHODS` macro as non-trivial (likely because their default
copy constructors are deleted). So using checks on trivially
constructible/destructible instead on this compiler/system.

Pull Request: https://projects.blender.org/blender/blender/pulls/134771
2025-03-05 16:35:09 +01:00
Hans Goudey
a48d155c87 Geometry Nodes: Add "Face" option to Mesh to Curve node
Adds a mode option to the node to choose between the existing
behavior and new behavior that converts each face to a cyclic curve.
Generally this is much faster than the existing mode because it's
easy to parallelize and because curve offsets and face and corner
attributes can be implicitly shared to avoid copies.
Resolves #134671.

Pull Request: https://projects.blender.org/blender/blender/pulls/134773
2025-03-04 19:16:36 +01:00
Falk David
0db9486057 Merge branch 'blender-v4.4-release' 2025-02-24 14:12:27 +01:00
Janne Nylander
cefc6626f1 Fix #134985: Merging layers resets layer opacity
Layer had their opacity reset whenever a modifier was applied.
This was due to the property not being transferred when a new GreasePencil
object was created in `geometry::merge_layers` function. This PR makes sure
to transfer the Layer opacity (similar to other layer properties).

Pull Request: https://projects.blender.org/blender/blender/pulls/135006
2025-02-24 11:45:02 +01:00
Lukas Tönne
8a1e29be0d Merge branch 'blender-v4.4-release' 2025-02-24 10:27:39 +01:00
Lukas Tönne
63c460d93d Fix #134482: Grease Pencil: Interpolation creates uninitialized values
This was partially fixed in ef844bad but left some unhandled corner cases with
uninitialized memory.

The core problem is that the `dst_curve_mask` used by the interpolation
functions can contain indices that don't actually exist in either the "from" or
"to" source drawings. Specifically when the "from" drawing has more curves, the
indices are still used but the supplemental `to_curve_indices` array contains
`-1` entries, indicating that only the "from" curve should be used.

The main copy code for positions takes this into account, but the generic copy
of attributes below that does not! It passes the `dst_curve_mask` straight into
the `array_utils` functions and that causes crashes. The original fix in
ef844bad was to clamp the size of the index mask, but the way this was done
could lead to empty index masks, leaving attribute values uninitialized.

The correct solution is to use index masks that exclude invalid entries for the
respective source curves. The new masks are non-overlapping, so the full set of
destination curves can be filled by combining these masks.

Pull Request: https://projects.blender.org/blender/blender/pulls/134865
2025-02-24 10:26:53 +01:00
Dalai Felinto
1584cd9aa5 Cleanup: Rename point cloud to pointcloud / POINT_CLOUD to POINTCLOUD
Though "Point Cloud" written as two words is technically correct and should be used in the UI, as one word it's typically easier to write and parse when reading. We had a mix of both before this patch, so better to unify this as well.

This commit also renames the editor/intern/ files to remove pointcloud_ prefix.
point_cloud was only preserved on the user facing strings:

* is_type_point_cloud
* use_new_point_cloud_type

Pull Request: https://projects.blender.org/blender/blender/pulls/134803
2025-02-19 17:11:08 +01:00
Hans Goudey
a99f9496a0 Curves: Separate to object operator
Use the existing "remove_points_and_split" utility added
for grease pencil to implement the operator for the curves
object type. The whole structure is similar to the recently
added point cloud separate operator (4cd3540579).

Pull Request: https://projects.blender.org/blender/blender/pulls/134763
2025-02-18 19:31:30 +01:00
Hans Goudey
947658d1b2 Refactor: Simplify CustomData functions by requiring ImplicitSharingInfo
Previously we generally expected CustomData layers to have implicit
sharing info, but we didn't require it. This PR clarifies that we do
require layers with non-null data to have implicit sharing info. This
generally makes code simpler because we don't have to have a separate
code path for non-shared layers. For example, it makes the "totelem"
arguments for layer freeing functions unnecessary, since shared data
knows how to free itself. Those arguments are removed in this PR.

Pull Request: https://projects.blender.org/blender/blender/pulls/134578
2025-02-17 19:44:54 +01:00
Jacques Lucke
bb715caf94 Fix #134100: hair curves disappear when adding new curves without radius interpolation
The issue is that the existing curves did not have an explicitly set radius.
When adding new curves with an explicit radius, the radius of the old curves was
initialized to 0 and thus becoming invisible. This patch changes it so that all
the existing curves do get a default radius. The `radius_for_write` methods is
currently only used in places that overwrite the entire array, so adding the
default there shouldn't affect anything unintentionally.

Pull Request: https://projects.blender.org/blender/blender/pulls/134445
2025-02-14 17:41:59 +01:00
Jacques Lucke
808635e52a Fix #102598: Resample Curve node collapses curves to a single point
Collapsing curves to a single point when just resampling is unexpected. This
patch changes it so that non-zero-length curves keep at least one segment.

The fix is fairly straight forward, but a bunch of additional code is added to
support the legacy option to avoid breaking backward compatibility.

Pull Request: https://projects.blender.org/blender/blender/pulls/133659
2025-02-13 16:47:10 +01:00
YimingWu
ef844badd6 Fix #134482: Grease Pencil: Correct mask for stroke interpolation
Selection mask is included in the stroke interpolation tool in
297b97f2df, however sometimes there will
be mismatches for when start/end curve count isn't the same. This fix
ensures that the interpolation operator only works on the max amount of
curves that can fit in both start and end side of the interpolation.

Pull Request: https://projects.blender.org/blender/blender/pulls/134484
2025-02-13 12:45:53 +01:00
Campbell Barton
4ed5776990 Cleanup: avoid double precision loss when converting to/from floats 2025-02-05 14:38:56 +11:00