diff --git a/lib/src/base/accessor.dart b/lib/src/base/accessor.dart index 0e60a20b..5ff86830 100644 --- a/lib/src/base/accessor.dart +++ b/lib/src/base/accessor.dart @@ -38,6 +38,7 @@ class Accessor extends GltfChildOfRootProperty { int _componentLength = -1; bool _isUnit = false; bool _isXyzSign = false; + bool _isCubicSpline = false; AccessorUsage _usage; Accessor._( @@ -115,6 +116,7 @@ class Accessor extends GltfChildOfRootProperty { bool get isUnit => _isUnit; bool get isXyzSign => _isXyzSign; + bool get isCubicSpline => _isCubicSpline; AccessorUsage get usage => _usage; @@ -339,6 +341,8 @@ class Accessor extends GltfChildOfRootProperty { void setXyzSign() => _isXyzSign = true; + void setCubicSpline() => _isCubicSpline = true; + Iterable getElements({bool normalize: false}) sync* { // Ensure required fields to not check for them each time if (componentType == -1 || count == -1 || type == null) { @@ -533,7 +537,7 @@ class Accessor extends GltfChildOfRootProperty { return false; } - if (byteOffset % componentLength != 0) { + if (byteOffset.remainder(componentLength) != 0) { if (context != null) { context.addIssue(SemanticError.accessorOffsetAlignment, name: BYTE_OFFSET, args: [byteOffset, componentLength]); @@ -548,7 +552,7 @@ class Accessor extends GltfChildOfRootProperty { } final totalOffset = bufferView.byteOffset + byteOffset; - if (totalOffset % componentLength != 0) { + if (totalOffset.remainder(componentLength) != 0) { if (context != null) { context.addIssue(LinkError.accessorTotalOffsetAlignment, name: BYTE_OFFSET, args: [totalOffset, componentLength]); diff --git a/lib/src/base/animation.dart b/lib/src/base/animation.dart index 55244405..b72f0ec2 100644 --- a/lib/src/base/animation.dart +++ b/lib/src/base/animation.dart @@ -196,6 +196,7 @@ class Animation extends GltfChildOfRootProperty { if (channel._sampler.interpolation == CUBICSPLINE) { outputCount *= 3; + channel._sampler._output.setCubicSpline(); } if (channel.target.path == WEIGHTS) { diff --git a/lib/src/base/buffer_view.dart b/lib/src/base/buffer_view.dart index 8a68e39b..58db0405 100644 --- a/lib/src/base/buffer_view.dart +++ b/lib/src/base/buffer_view.dart @@ -93,7 +93,7 @@ class BufferView extends GltfChildOfRootProperty { name: BYTE_STRIDE, args: [byteStride, byteLength]); } - if (byteStride % 4 != 0) { + if (byteStride.remainder(4) != 0) { context.addIssue(SchemaError.valueMultipleOf, name: BYTE_STRIDE, args: [byteStride, 4]); } diff --git a/lib/src/base/mesh.dart b/lib/src/base/mesh.dart index 3d2c9b74..1d18b16b 100644 --- a/lib/src/base/mesh.dart +++ b/lib/src/base/mesh.dart @@ -321,8 +321,9 @@ class MeshPrimitive extends GltfProperty { args: [format, validFormats]); } - if ((accessor.byteOffset != -1 && accessor.byteOffset % 4 != 0) || - (accessor.elementLength % 4 != 0 && + if ((accessor.byteOffset != -1 && + accessor.byteOffset.remainder(4) != 0) || + (accessor.elementLength.remainder(4) != 0 && accessor.bufferView != null && accessor.bufferView.byteStride == -1)) { context.addIssue(LinkError.meshPrimitiveAccessorUnaligned, @@ -396,9 +397,9 @@ class MeshPrimitive extends GltfProperty { */ if ((context.validate && _count != -1) && - ((mode == 1 && _count % 2 != 0) || + ((mode == 1 && _count.remainder(2) != 0) || ((mode == 2 || mode == 3) && _count < 2) || - (mode == 4 && _count % 3 != 0) || + (mode == 4 && _count.remainder(3) != 0) || ((mode == 5 || mode == 6) && _count < 3))) { context.addIssue(LinkError.meshPrimitiveIncompatibleMode, args: [_count, gl.MODES_NAMES[mode]]); @@ -467,8 +468,9 @@ class MeshPrimitive extends GltfProperty { args: [format, validFormats]); } - if ((accessor.byteOffset != -1 && accessor.byteOffset % 4 != 0) || - (accessor.elementLength % 4 != 0 && + if ((accessor.byteOffset != -1 && + accessor.byteOffset.remainder(4) != 0) || + (accessor.elementLength.remainder(4) != 0 && accessor.bufferView != null && accessor.bufferView.byteStride == -1)) { context.addIssue(LinkError.meshPrimitiveAccessorUnaligned, diff --git a/lib/src/data_access/validate_accessors.dart b/lib/src/data_access/validate_accessors.dart index 008578db..be793769 100644 --- a/lib/src/data_access/validate_accessors.dart +++ b/lib/src/data_access/validate_accessors.dart @@ -75,6 +75,10 @@ void validateAccessorsData(Gltf gltf, Context context) { return; } + if (accessor.isCubicSpline && accessor.count.remainder(3) != 0) { + return; + } + // Skip empty accessors if (accessor.bufferView == null && accessor.sparse == null) { return; @@ -109,6 +113,9 @@ void validateAccessorsData(Gltf gltf, Context context) { var index = 0; var componentIndex = 0; + // 0: in; 1: value; 2: out + var cubicSplineState = 0; + final iterator = gltf.accessors[i].getElements().iterator; var hasNext = iterator.moveNext(); @@ -184,7 +191,8 @@ void validateAccessorsData(Gltf gltf, Context context) { } else if (accessor.usage == AccessorUsage.IBM) { matrix.storage[componentIndex] = value; } else if (accessor.isUnit && - !(accessor.isXyzSign && componentIndex == 3)) { + !(accessor.isXyzSign && componentIndex == 3) && + !(accessor.isCubicSpline && cubicSplineState != 1)) { sum += value * value; } } @@ -194,7 +202,8 @@ void validateAccessorsData(Gltf gltf, Context context) { if (!isTrsDecomposable(matrix)) { context.addIssue(DataError.indecomposableMatrix, args: [index]); } - } else if (accessor.isUnit) { + } else if (accessor.isUnit && + !(accessor.isCubicSpline && cubicSplineState != 1)) { if ((sum - 1.0).abs() > 0.0005) { context.addIssue(DataError.accessorNonUnit, args: [index, sqrt(sum)]); @@ -207,6 +216,10 @@ void validateAccessorsData(Gltf gltf, Context context) { } } + if (accessor.isCubicSpline && ++cubicSplineState == 3) { + cubicSplineState = 0; + } + componentIndex = 0; }