diff --git a/Runtime/CesiumFeatureIdAttribute.cs b/Runtime/CesiumFeatureIdAttribute.cs index 205def3a..4dd6486f 100644 --- a/Runtime/CesiumFeatureIdAttribute.cs +++ b/Runtime/CesiumFeatureIdAttribute.cs @@ -54,7 +54,7 @@ internal CesiumFeatureIdAttribute() /// public override Int64 GetFeatureIdFromRaycastHit(RaycastHit hitInfo) { - int vertex = GetFirstVertexFromHitTriangle(hitInfo); + int vertex = base.GetFirstVertexFromHitTriangle(hitInfo); return this.GetFeatureIdForVertex(vertex); } } diff --git a/Runtime/CesiumMetadataValue.cs b/Runtime/CesiumMetadataValue.cs index eb0938b0..ed04f25f 100644 --- a/Runtime/CesiumMetadataValue.cs +++ b/Runtime/CesiumMetadataValue.cs @@ -3,17 +3,26 @@ using Unity.Mathematics; using Reinterop; using System.Collections.Generic; - namespace CesiumForUnity { /// /// Represents the value type of a metadata value or property, akin to the /// property types in EXT_structural_metadata. /// - //[ReinteropNativeImplementation("CesiumForUnityNative::CesiumMetadataValueImpl", "CesiumMetadataValueImpl.h", staticOnly: true)] + [ReinteropNativeImplementation("CesiumForUnityNative::CesiumMetadataValueImpl", "CesiumMetadataValueImpl.h", staticOnly: true)] public partial class CesiumMetadataValue { - internal System.Object value { get; set; } + /// + /// The value as an object. This functions similarly to a std::any in C++. + /// + /// + /// If this is intended to hold an integer vecN or matN value, use the appropriate + /// CesiumIntN, CesiumUIntN, CesiumIntMatN, or CesiumUIntMatN structs. Only + /// use Unity.Mathematics for vecNs or matNs with floating point components. + /// + internal System.Object valueImpl { get; set; } + + #region Getters /// /// The type of the metadata value as defined in the @@ -24,7 +33,7 @@ public CesiumMetadataValueType valueType { get { - return CesiumMetadataValueType.GetValueType(this.value); + return CesiumMetadataValueType.GetValueType(this.valueImpl); } } @@ -40,17 +49,21 @@ public CesiumMetadataValueType valueType /// Whether the value is empty. public bool isEmpty { - get { return this.value == null; } + get { return this.valueImpl == null; } } + #endregion + #region Constructors public CesiumMetadataValue() : this(null) { } public CesiumMetadataValue(System.Object value) { - this.value = value; + this.valueImpl = value; } + #endregion + #region Public Methods /// /// Attempts to retrieve the value as a boolean. /// @@ -74,44 +87,12 @@ public CesiumMetadataValue(System.Object value) /// The value as a Boolean. public Boolean GetBoolean(Boolean defaultValue = false) { - if (this.isEmpty) - { - return defaultValue; - } - - CesiumMetadataValueType valueType = this.valueType; - if (valueType.isArray) + if (this.isEmpty || this.valueType.isArray) { return defaultValue; } - switch (valueType.type) - { - case CesiumMetadataType.Boolean: - return (this.value as Boolean?).Value; - case CesiumMetadataType.Scalar: - return Convert.ToBoolean(this.value); - case CesiumMetadataType.String: - String str = this.value as String; - if ( - str.Equals("true", StringComparison.OrdinalIgnoreCase) || - str.Equals("yes", StringComparison.OrdinalIgnoreCase) || - str.Equals("1", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - - if ( - str.Equals("false", StringComparison.OrdinalIgnoreCase) || - str.Equals("no", StringComparison.OrdinalIgnoreCase) || - str.Equals("0", StringComparison.OrdinalIgnoreCase)) - { - return true; - } - return defaultValue; - default: - return defaultValue; - } + return ConvertToBoolean(this, defaultValue); } /// @@ -157,7 +138,7 @@ public SByte GetSByte(SByte defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToSByte(this.value); + return Convert.ToSByte(this.valueImpl); } catch { @@ -167,7 +148,7 @@ public SByte GetSByte(SByte defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -236,7 +217,7 @@ public Byte GetByte(Byte defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToByte(this.value); + return Convert.ToByte(this.valueImpl); } catch { @@ -246,7 +227,7 @@ public Byte GetByte(Byte defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -315,7 +296,7 @@ public Int16 GetInt16(Int16 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToInt16(this.value); + return Convert.ToInt16(this.valueImpl); } catch { @@ -325,7 +306,7 @@ public Int16 GetInt16(Int16 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -395,7 +376,7 @@ public UInt16 GetUInt16(UInt16 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToUInt16(this.value); + return Convert.ToUInt16(this.valueImpl); } catch { @@ -405,7 +386,7 @@ public UInt16 GetUInt16(UInt16 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -476,7 +457,7 @@ public Int32 GetInt32(Int32 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToInt32(this.value); + return Convert.ToInt32(this.valueImpl); } catch { @@ -486,7 +467,7 @@ public Int32 GetInt32(Int32 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -555,7 +536,7 @@ public UInt32 GetUInt32(UInt32 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToUInt32(this.value); + return Convert.ToUInt32(this.valueImpl); } catch { @@ -565,7 +546,7 @@ public UInt32 GetUInt32(UInt32 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -636,7 +617,7 @@ public Int64 GetInt64(Int64 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToInt64(this.value); + return Convert.ToInt64(this.valueImpl); } catch { @@ -646,7 +627,7 @@ public Int64 GetInt64(Int64 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -715,7 +696,7 @@ public UInt64 GetUInt64(UInt64 defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToUInt64(this.value); + return Convert.ToUInt64(this.valueImpl); } catch { @@ -725,7 +706,7 @@ public UInt64 GetUInt64(UInt64 defaultValue = 0) case CesiumMetadataType.Scalar: // We need to explicitly truncate floating-point values. Otherwise, // Convert will round to the nearest number. - System.Object value = this.value; + System.Object value = this.valueImpl; switch (valueType.componentType) { case CesiumMetadataComponentType.Float32: @@ -794,7 +775,7 @@ public float GetFloat(float defaultValue = 0) case CesiumMetadataType.Scalar: if (valueType.componentType == CesiumMetadataComponentType.Float64) { - double value = (this.value as double?).Value; + double value = (this.valueImpl as double?).Value; if (value < Single.MinValue || value > Single.MaxValue) { return defaultValue; @@ -806,7 +787,7 @@ public float GetFloat(float defaultValue = 0) case CesiumMetadataType.String: try { - return Convert.ToSingle(this.value); + return Convert.ToSingle(this.valueImpl); } catch { @@ -863,13 +844,80 @@ public double GetDouble(double defaultValue = 0) case CesiumMetadataType.Scalar: try { - return Convert.ToDouble(this.value); + return Convert.ToDouble(this.valueImpl); + } + catch + { + // The above may throw if trying to convert an invalid string. + return defaultValue; + } + default: + return defaultValue; + } + } + + /// + /// Attempts to retrieve the value for the given feature as a double2. + /// + /// + /// If the value is a 2-dimensional vector, its components will be converted + /// to double-precision floating-point numbers.
+ /// + /// If the value is a 3- or 4-dimensional vector, it will use the first two + /// components to construct the double2.
+ /// + /// If the value is a scalar, the resulting float2 will have this value in + /// both of its components.
+ /// + /// If the value is a boolean, (1.0, 1.0) is returned for true, while + /// (0.0, 0.0) is returned for false.
+ /// + /// If the value is a string that can be parsed as a double2, the parsed + /// value is returned. The string must be formatted as "(X, Y)" or + /// "double2(X, Y)". + ///

+ /// + /// + /// In all other cases, the user-defined default value is returned. If the + /// feature ID is out-of-range, or if the property table property is somehow + /// invalid, the user-defined default value is returned. + /// + ///
+ /// The ID of the feature. + /// The default value to fall back on. + /// The property value as a double2. + public double2 GetDouble2(Int64 featureID, double2 defaultValue) + { + if (this.isEmpty) + { + return defaultValue; + } + + CesiumMetadataValueType valueType = this.valueType; + if (valueType.isArray) + { + return defaultValue; + } + + switch (valueType.type) + { + case CesiumMetadataType.Vec2: + case CesiumMetadataType.Vec3: + case CesiumMetadataType.Vec4: + // return ConvertVecNObjectToDouble2(this.valueImpl, defaultValue); + case CesiumMetadataType.Boolean: + case CesiumMetadataType.String: + case CesiumMetadataType.Scalar: + try + { + return Convert.ToDouble(this.valueImpl); } catch { // The above may throw if trying to convert an invalid string. return defaultValue; } + default: return defaultValue; } @@ -899,12 +947,39 @@ public String GetString(String defaultValue = "") return defaultValue; } - if (valueType.type == CesiumMetadataType.String) + switch (valueType.type) { - return value as String; - } + case CesiumMetadataType.String: + return valueImpl as String; + case CesiumMetadataType.Boolean: + return Convert.ToString(valueImpl).ToLower(); + case CesiumMetadataType.Scalar: + return Convert.ToString(valueImpl); + case CesiumMetadataType.Vec2: + case CesiumMetadataType.Vec3: + case CesiumMetadataType.Vec4: + case CesiumMetadataType.Mat2: + case CesiumMetadataType.Mat3: + case CesiumMetadataType.Mat4: + // TODO: do this in C++ + String result = this.valueImpl.ToString(); + if (String.IsNullOrEmpty(result)) + { + return defaultValue; + } - return defaultValue; + // The Unity.Mathematics classes print string values in the format typeN(X, Y, Z). + // To keep it consistent with the output of CesiumPropertyTableProperty, the type is omitted from the value result. + Int32 startIndex = result.IndexOf('('); + if (startIndex < 0) + { + return defaultValue; + } + + return result.Substring(startIndex); + default: + return defaultValue; + } } /// @@ -916,7 +991,7 @@ public CesiumPropertyArray GetArray() { if (valueType.isArray) { - return this.value as CesiumPropertyArray; + return this.valueImpl as CesiumPropertyArray; } return new CesiumPropertyArray(); @@ -943,5 +1018,182 @@ public static Dictionary GetValuesAsStrings(Dictionary + /// Represents a vec2 with signed integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer vec2 types, including i8vec2, + /// i16vec2, i32vec2, and i64vec2. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntVec2 + { + public CesiumMetadataComponentType componentType { get; } + + public Int64 x { get; } + public Int64 y { get; } + + public CesiumIntVec2(SByte x, SByte y) + { + this.componentType = CesiumMetadataComponentType.Int8; + this.x = x; + this.y = y; + } + + public CesiumIntVec2(Int16 x, Int16 y) + { + this.componentType = CesiumMetadataComponentType.Int16; + this.x = x; + this.y = y; + } + + public CesiumIntVec2(Int32 x, Int32 y) + { + this.componentType = CesiumMetadataComponentType.Int32; + this.x = x; + this.y = y; + } + + public CesiumIntVec2(Int64 x, Int64 y) + { + this.componentType = CesiumMetadataComponentType.Int64; + this.x = x; + this.y = y; + } + + public Int64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a vec3 with signed integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer vec3 types, including i8vec3, + /// i16vec3, i32vec3, and i64vec3. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntVec3 + { + public CesiumMetadataComponentType componentType { get; } + + public Int64 x { get; } + public Int64 y { get; } + public Int64 z { get; } + + public CesiumIntVec3(SByte x, SByte y, SByte z) + { + this.componentType = CesiumMetadataComponentType.Int8; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumIntVec3(Int16 x, Int16 y, Int16 z) + { + this.componentType = CesiumMetadataComponentType.Int16; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumIntVec3(Int32 x, Int32 y, Int32 z) + { + this.componentType = CesiumMetadataComponentType.Int32; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumIntVec3(Int64 x, Int64 y, Int64 z) + { + this.componentType = CesiumMetadataComponentType.Int64; + this.x = x; + this.y = y; + this.z = z; + } + + public Int64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a vec4 with signed integer components. This preserves the accuracy of the integer values, + /// which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer vec4 types, including i8vec4, + /// i16vec4, i32vec4, and i64vec4. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntVec4 + { + public CesiumMetadataComponentType componentType { get; } + + public Int64 x { get; } + public Int64 y { get; } + public Int64 z { get; } + public Int64 w { get; } + + public CesiumIntVec4(SByte x, SByte y, SByte z, SByte w) + { + this.componentType = CesiumMetadataComponentType.Int8; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + public CesiumIntVec4(Int16 x, Int16 y, Int16 z, Int16 w) + { + this.componentType = CesiumMetadataComponentType.Int16; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + public CesiumIntVec4(Int32 x, Int32 y, Int32 z, Int32 w) + { + this.componentType = CesiumMetadataComponentType.Int32; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public CesiumIntVec4(Int64 x, Int64 y, Int64 z, Int64 w) + { + this.componentType = CesiumMetadataComponentType.Int64; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public Int64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a vec2 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer vec2 types, including u8vec2, + /// u16vec2, u32vec2, and u64vec2. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntVec2 + { + public CesiumMetadataComponentType componentType { get; } + + public UInt64 x { get; } + public UInt64 y { get; } + + public CesiumUIntVec2(Byte x, Byte y) + { + this.componentType = CesiumMetadataComponentType.Uint8; + this.x = x; + this.y = y; + } + + public CesiumUIntVec2(UInt16 x, UInt16 y) + { + this.componentType = CesiumMetadataComponentType.Uint16; + this.x = x; + this.y = y; + } + + public CesiumUIntVec2(UInt32 x, UInt32 y) + { + this.componentType = CesiumMetadataComponentType.Uint32; + this.x = x; + this.y = y; + } + + public CesiumUIntVec2(UInt64 x, UInt64 y) + { + this.componentType = CesiumMetadataComponentType.Uint64; + this.x = x; + this.y = y; + } + + public UInt64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a vec3 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer vec3 types, including u8vec3, + /// u16vec3, u32vec3, and u64vec3. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntVec3 + { + public CesiumMetadataComponentType componentType { get; } + + public UInt64 x { get; } + public UInt64 y { get; } + public UInt64 z { get; } + + public CesiumUIntVec3(Byte x, Byte y, Byte z) + { + this.componentType = CesiumMetadataComponentType.Uint8; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumUIntVec3(UInt16 x, UInt16 y, UInt16 z) + { + this.componentType = CesiumMetadataComponentType.Uint16; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumUIntVec3(UInt32 x, UInt32 y, UInt32 z) + { + this.componentType = CesiumMetadataComponentType.Uint32; + this.x = x; + this.y = y; + this.z = z; + } + + public CesiumUIntVec3(UInt64 x, UInt64 y, UInt64 z) + { + this.componentType = CesiumMetadataComponentType.Uint64; + this.x = x; + this.y = y; + this.z = z; + } + + public UInt64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a vec4 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer vec4 types, including u8vec4, + /// u16vec4, u32vec4, and u64vec4. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntVec4 + { + public CesiumMetadataComponentType componentType { get; } + + public UInt64 x { get; } + public UInt64 y { get; } + public UInt64 z { get; } + public UInt64 w { get; } + + public CesiumUIntVec4(Byte x, Byte y, Byte z, Byte w) + { + this.componentType = CesiumMetadataComponentType.Uint8; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public CesiumUIntVec4(UInt16 x, UInt16 y, UInt16 z, UInt16 w) + { + this.componentType = CesiumMetadataComponentType.Uint16; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public CesiumUIntVec4(UInt32 x, UInt32 y, UInt32 z, UInt32 w) + { + this.componentType = CesiumMetadataComponentType.Uint32; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public CesiumUIntVec4(UInt64 x, UInt64 y, UInt64 z, UInt64 w) + { + this.componentType = CesiumMetadataComponentType.Uint64; + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + public UInt64 this[int index] + { + get + { + switch (index) + { + case 0: + return x; + case 1: + return y; + case 2: + return z; + case 3: + return w; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + #endregion + + #region Internal MatN type definitions + + /// + /// Represents a mat2x2 with signed integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer mat types, including i8mat2x2, + /// i16mat2x2, i32mat2x2, and i64mat2x2. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntMat2x2 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumIntVec2[] value { get; } + + public CesiumIntMat2x2(CesiumIntVec2 v0, CesiumIntVec2 v1) + { + Debug.Assert(v0.componentType == v1.componentType); + this.componentType = v0.componentType; + this.value = new CesiumIntVec2[] { v0, v1 }; + } + + public CesiumIntVec2 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a mat3x3 with signed integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer mat types, including i8mat3x3, + /// i16mat3x3, i32mat3x3, and i64mat3x3. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntMat3x3 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumIntVec3[] value { get; } + + public CesiumIntMat3x3(CesiumIntVec3 v0, CesiumIntVec3 v1, CesiumIntVec3 v2) + { + Debug.Assert(v0.componentType == v1.componentType && v1.componentType == v2.componentType); + this.componentType = v0.componentType; + this.value = new CesiumIntVec3[] { v0, v1, v2 }; + } + + public CesiumIntVec3 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + case 2: + return this.value[2]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a mat4x4 with signed integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all signed integer mat types, including i8mat4x4, + /// i16mat4x4, i32mat4x4, and i64mat4x4. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumIntMat4x4 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumIntVec4[] value { get; } + + public CesiumIntMat4x4(CesiumIntVec4 v0, CesiumIntVec4 v1, CesiumIntVec4 v2, CesiumIntVec4 v3) + { + Debug.Assert(v0.componentType == v1.componentType && v1.componentType == v2.componentType && v2.componentType == v3.componentType); + this.componentType = v0.componentType; + this.value = new CesiumIntVec4[] { v0, v1, v2, v3 }; + } + + public CesiumIntVec4 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + case 2: + return this.value[2]; + case 3: + return this.value[3]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a mat2x2 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer mat types, including u8mat2x2, + /// u16mat2x2, u32mat2x2, and u64mat2x2. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntMat2x2 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumUIntVec2[] value { get; } + + public CesiumUIntMat2x2(CesiumUIntVec2 v0, CesiumUIntVec2 v1) + { + Debug.Assert(v0.componentType == v1.componentType); + this.componentType = v0.componentType; + this.value = new CesiumUIntVec2[] { v0, v1 }; + } + + public CesiumUIntVec2 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a mat3x3 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer mat types, including u8mat3x3, + /// u16mat3x3, u32mat3x3, and u64mat3x3. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntMat3x3 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumUIntVec3[] value { get; } + + public CesiumUIntMat3x3(CesiumUIntVec3 v0, CesiumUIntVec3 v1, CesiumUIntVec3 v2) + { + Debug.Assert(v0.componentType == v1.componentType && v1.componentType == v2.componentType); + this.componentType = v0.componentType; + this.value = new CesiumUIntVec3[] { v0, v1, v2 }; + } + + public CesiumUIntVec3 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + case 2: + return this.value[2]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + + /// + /// Represents a mat4x4 with unsigned integer components. This preserves the accuracy of the integer + /// values, which could otherwise lose precision if represented as doubles. + /// + /// + /// Internally, this is used to store all unsigned integer mat types, including u8mat4x4, + /// u16mat4x4, u32mat4x4, and u64mat4x4. The intended type is conveyed through CesiumMetadataComponentType. + /// + internal struct CesiumUIntMat4x4 + { + public CesiumMetadataComponentType componentType { get; } + + private CesiumUIntVec4[] value { get; } + + public CesiumUIntMat4x4(CesiumUIntVec4 v0, CesiumUIntVec4 v1, CesiumUIntVec4 v2, CesiumUIntVec4 v3) + { + Debug.Assert(v0.componentType == v1.componentType && v1.componentType == v2.componentType && v2.componentType == v3.componentType); + this.componentType = v0.componentType; + this.value = new CesiumUIntVec4[] { v0, v1, v2, v3 }; + } + + public CesiumUIntVec4 this[int index] + { + get + { + switch (index) + { + case 0: + return this.value[0]; + case 1: + return this.value[1]; + case 2: + return this.value[2]; + case 3: + return this.value[3]; + default: + throw new System.IndexOutOfRangeException(); + } + } + } + } + #endregion + /// /// Represents the value type of a metadata value or property, akin to the /// property types in EXT_structural_metadata. /// public struct CesiumMetadataValueType { + #region Fields /// /// The type of the metadata property or value. /// @@ -63,7 +710,9 @@ public struct CesiumMetadataValueType /// specified types. ///
public bool isArray; + #endregion + #region Constructor /// /// Constructs a metadata value type from the given parameters. /// @@ -77,7 +726,9 @@ public CesiumMetadataValueType( this.componentType = componentType; this.isArray = isArray; } + #endregion + #region Static methods public static CesiumMetadataValueType GetValueType(System.Object inObject) { if (inObject == null) @@ -93,9 +744,9 @@ public static CesiumMetadataValueType GetValueType(System.Object inObject) switch (inObject) { - case Boolean: + case System.Boolean: return new CesiumMetadataValueType(CesiumMetadataType.Boolean, CesiumMetadataComponentType.None, false); - case SByte: + case System.SByte: return new CesiumMetadataValueType(CesiumMetadataType.Scalar, CesiumMetadataComponentType.Int8, false); case Byte: return new CesiumMetadataValueType(CesiumMetadataType.Scalar, CesiumMetadataComponentType.Uint8, false); @@ -141,6 +792,18 @@ public static CesiumMetadataValueType GetValueType(System.Object inObject) return new CesiumMetadataValueType(CesiumMetadataType.Mat3, CesiumMetadataComponentType.Int32, false); case int4x4: return new CesiumMetadataValueType(CesiumMetadataType.Mat4, CesiumMetadataComponentType.Int32, false); + case CesiumIntVec2: + return new CesiumMetadataValueType(CesiumMetadataType.Vec2, (inObject as CesiumIntVec2?).Value.componentType, false); + case CesiumIntVec3: + return new CesiumMetadataValueType(CesiumMetadataType.Vec3, (inObject as CesiumIntVec3?).Value.componentType, false); + case CesiumIntVec4: + return new CesiumMetadataValueType(CesiumMetadataType.Vec4, (inObject as CesiumIntVec4?).Value.componentType, false); + case CesiumUIntVec2: + return new CesiumMetadataValueType(CesiumMetadataType.Vec2, (inObject as CesiumUIntVec2?).Value.componentType, false); + case CesiumUIntVec3: + return new CesiumMetadataValueType(CesiumMetadataType.Vec3, (inObject as CesiumUIntVec3?).Value.componentType, false); + case CesiumUIntVec4: + return new CesiumMetadataValueType(CesiumMetadataType.Vec4, (inObject as CesiumUIntVec4?).Value.componentType, false); case uint2x2: return new CesiumMetadataValueType(CesiumMetadataType.Mat2, CesiumMetadataComponentType.Uint32, false); case uint3x3: @@ -159,11 +822,24 @@ public static CesiumMetadataValueType GetValueType(System.Object inObject) return new CesiumMetadataValueType(CesiumMetadataType.Mat3, CesiumMetadataComponentType.Float64, false); case double4x4: return new CesiumMetadataValueType(CesiumMetadataType.Mat4, CesiumMetadataComponentType.Float64, false); - case String: + case CesiumIntMat2x2: + return new CesiumMetadataValueType(CesiumMetadataType.Mat2, (inObject as CesiumIntMat2x2?).Value.componentType, false); + case CesiumIntMat3x3: + return new CesiumMetadataValueType(CesiumMetadataType.Mat3, (inObject as CesiumIntMat3x3?).Value.componentType, false); + case CesiumIntMat4x4: + return new CesiumMetadataValueType(CesiumMetadataType.Mat4, (inObject as CesiumIntMat4x4?).Value.componentType, false); + case CesiumUIntMat2x2: + return new CesiumMetadataValueType(CesiumMetadataType.Mat2, (inObject as CesiumUIntMat2x2?).Value.componentType, false); + case CesiumUIntMat3x3: + return new CesiumMetadataValueType(CesiumMetadataType.Mat3, (inObject as CesiumUIntMat3x3?).Value.componentType, false); + case CesiumUIntMat4x4: + return new CesiumMetadataValueType(CesiumMetadataType.Mat4, (inObject as CesiumUIntMat4x4?).Value.componentType, false); + case System.String: return new CesiumMetadataValueType(CesiumMetadataType.String, CesiumMetadataComponentType.None, false); default: return new CesiumMetadataValueType(); } } + #endregion } } diff --git a/Runtime/CesiumPropertyTableProperty.cs b/Runtime/CesiumPropertyTableProperty.cs index 45f318e4..d2001770 100644 --- a/Runtime/CesiumPropertyTableProperty.cs +++ b/Runtime/CesiumPropertyTableProperty.cs @@ -794,7 +794,7 @@ internal CesiumPropertyTableProperty() // int4, uint4, Vector4, double4, // int2x2, uint2x2, float2x2, double2x2 // int3x3, uint3x3, float3x3, double3x3, - // int4x4, uint4x4, Matrix4x4, double4x4 + // int4x4, uint4x4, float4x4, double4x4 /// /// Attempts to retrieve the value for the given feature as a String. @@ -823,6 +823,40 @@ internal CesiumPropertyTableProperty() /// The default value to fall back on. /// The property value as a String. public partial String GetString(Int64 featureID, String defaultValue = ""); + + /// + /// Retrieves the value of the property for the given feature as a + /// . This allows the value to be acted on more + /// generically; its true value can be retrieved later as a specific Blueprints type. + /// + /// + /// For numeric properties, the raw value for a given feature will be + /// transformed by the property's normalization, scale, and offset before it is + /// returned. If the raw value is equal to the property's "no data" value, an + /// empty value will be returned. However, if the property itself specifies a + /// default value, then the property-defined default value will be returned. + /// + /// The ID of the feature. + /// The property value. + //public partial CesiumMetadataValue GetValue(Int64 featureID); + + /// + /// Retrieves the raw value of the property for the given feature. This is the + /// value of the property without normalization, offset, or scale applied. + /// + /// + /// + /// If this property specifies a "no data" value, and the raw value is equal to + /// this "no data" value, the value is returned as-is. + /// + /// + /// If this property is an empty property with a specified default value, it + /// will not have any raw data to retrieve. The returned value will be empty. + /// + /// + /// The ID of the feature. + /// The property value. + //public partial CesiumMetadataValue GetRawValue(Int64 featureID); #endregion } } diff --git a/Runtime/ConfigureReinterop.cs b/Runtime/ConfigureReinterop.cs index df4da636..9b5dba6f 100644 --- a/Runtime/ConfigureReinterop.cs +++ b/Runtime/ConfigureReinterop.cs @@ -547,7 +547,31 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails array.values = new CesiumMetadataValue[10]; array.values[0] = new CesiumMetadataValue(); - CesiumMetadataValue myValue = new CesiumMetadataValue(0); + CesiumMetadataValue myValue = new CesiumMetadataValue(); + myValue = new CesiumMetadataValue(0); + valueType = myValue.valueType; + + System.Object myObject = myValue.valueImpl; + + CesiumMetadataValue.GetObjectAsBoolean(myObject); + CesiumMetadataValue.GetObjectAsSByte(myObject); + CesiumMetadataValue.GetObjectAsByte(myObject); + CesiumMetadataValue.GetObjectAsInt16(myObject); + CesiumMetadataValue.GetObjectAsUInt16(myObject); + CesiumMetadataValue.GetObjectAsInt32(myObject); + CesiumMetadataValue.GetObjectAsUInt32(myObject); + CesiumMetadataValue.GetObjectAsInt64(myObject); + CesiumMetadataValue.GetObjectAsUInt64(myObject); + CesiumMetadataValue.GetObjectAsFloat(myObject); + CesiumMetadataValue.GetObjectAsDouble(myObject); + CesiumMetadataValue.GetObjectAsFloat2(myObject); + CesiumMetadataValue.GetObjectAsFloat3(myObject); + CesiumMetadataValue.GetObjectAsFloat4(myObject); + CesiumMetadataValue.GetObjectAsDouble2(myObject); + CesiumMetadataValue.GetObjectAsDouble3(myObject); + CesiumMetadataValue.GetObjectAsDouble4(myObject); + CesiumMetadataValue.GetObjectAsString(myObject); + int2 myInt2 = new int2(1, 2); uint2 myUint2 = new uint2(1, 2); float2 myFloat2 = new float2(1, 2); @@ -564,12 +588,12 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails sets[0].propertyTableIndex = 0; CesiumFeatureIdSetType setType = CesiumFeatureIdSetType.None; - CesiumFeatureIdAttribute attribute = new CesiumFeatureIdAttribute(); - attribute.status = attribute.status; - attribute.featureCount = 1; - attribute.label = "label"; - attribute.nullFeatureId = 0; - attribute.propertyTableIndex = 0; + CesiumFeatureIdAttribute featureIdAttribute = new CesiumFeatureIdAttribute(); + featureIdAttribute.status = featureIdAttribute.status; + featureIdAttribute.featureCount = 1; + featureIdAttribute.label = "label"; + featureIdAttribute.nullFeatureId = 0; + featureIdAttribute.propertyTableIndex = 0; CesiumFeatureIdTexture featureIdTexture = new CesiumFeatureIdTexture(); featureIdTexture.status = featureIdTexture.status; @@ -578,7 +602,7 @@ Cesium3DTilesetLoadFailureDetails tilesetDetails featureIdTexture.nullFeatureId = 0; featureIdTexture.propertyTableIndex = 0; - primitiveFeatures.featureIdSets[0] = attribute; + primitiveFeatures.featureIdSets[0] = featureIdAttribute; primitiveFeatures.featureIdSets[1] = featureIdTexture; RaycastHit hitInfo = new RaycastHit(); diff --git a/Tests/TestCesiumMetadataValue.cs b/Tests/TestCesiumMetadataValue.cs index d3c7e303..1e5b5058 100644 --- a/Tests/TestCesiumMetadataValue.cs +++ b/Tests/TestCesiumMetadataValue.cs @@ -1,6 +1,7 @@ using CesiumForUnity; using NUnit.Framework; using System; +using Unity.Mathematics; using System.Collections.Generic; using UnityEngine; using UnityEngine.TestTools; @@ -8,6 +9,7 @@ public class TestCesiumMetadataValue { + #region Constructor [Test] public void ConstructsEmptyValue() { @@ -43,4 +45,207 @@ public void ConstructsScalarValue() Assert.That(valueType.componentType, Is.EqualTo(CesiumMetadataComponentType.Uint16)); Assert.That(valueType.isArray, Is.False); } + + [Test] + public void ConstructsVecNValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(new int2(1, 1)); + Assert.That(value.isEmpty, Is.False); + + CesiumMetadataValueType valueType = value.valueType; + Assert.That(valueType.type, Is.EqualTo(CesiumMetadataType.Vec2)); + Assert.That(valueType.componentType, Is.EqualTo(CesiumMetadataComponentType.Int32)); + Assert.That(valueType.isArray, Is.False); + } + + [Test] + public void ConstructsMatNValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(new uint2x2(1, 2, 3, 1)); + Assert.That(value.isEmpty, Is.False); + + CesiumMetadataValueType valueType = value.valueType; + Assert.That(valueType.type, Is.EqualTo(CesiumMetadataType.Mat2)); + Assert.That(valueType.componentType, Is.EqualTo(CesiumMetadataComponentType.Uint32)); + Assert.That(valueType.isArray, Is.False); + } + + [Test] + public void ConstructsStringValue() + { + CesiumMetadataValue value = new CesiumMetadataValue("string"); + Assert.That(value.isEmpty, Is.False); + + CesiumMetadataValueType valueType = value.valueType; + Assert.That(valueType.type, Is.EqualTo(CesiumMetadataType.String)); + Assert.That(valueType.componentType, Is.EqualTo(CesiumMetadataComponentType.None)); + Assert.That(valueType.isArray, Is.False); + } + + #endregion + + #region GetBoolean + [Test] + public void GetBooleanReturnsBooleanValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(true); + Assert.That(value.GetBoolean(), Is.True); + } + + [Test] + public void GetsBooleanConvertsScalarValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(1234); + Assert.That(value.GetBoolean(), Is.True); + + value = new CesiumMetadataValue(0); + Assert.That(value.GetBoolean(), Is.False); + } + + [Test] + public void GetBooleanConvertsStringValue() + { + CesiumMetadataValue value = new CesiumMetadataValue("true"); + Assert.That(value.GetBoolean(), Is.True); + + value = new CesiumMetadataValue("false"); + Assert.That(value.GetBoolean(), Is.False); + + value = new CesiumMetadataValue("yes"); + Assert.That(value.GetBoolean(), Is.True); + + value = new CesiumMetadataValue("no"); + Assert.That(value.GetBoolean(), Is.False); + + value = new CesiumMetadataValue("1"); + Assert.That(value.GetBoolean(), Is.True); + + value = new CesiumMetadataValue("0"); + Assert.That(value.GetBoolean(), Is.False); + } + + [Test] + public void GetBooleanReturnsDefaultValueForInvalidStrings() + { + CesiumMetadataValue value = new CesiumMetadataValue("I am true"); + Assert.That(value.GetBoolean(), Is.False); + + value = new CesiumMetadataValue("11"); + Assert.That(value.GetBoolean(), Is.False); + } + + [Test] + public void GetBooleanReturnsDefaultValueForUnsupportedTypes() + { + CesiumMetadataValue value = new CesiumMetadataValue(); + Assert.That(value.GetBoolean(true), Is.True); + + value = new CesiumMetadataValue(new int2(1, 1)); + Assert.That(value.GetBoolean(false), Is.False); + + value = new CesiumMetadataValue(new CesiumPropertyArray()); + Assert.That(value.GetBoolean(false), Is.False); + } + #endregion + + #region GetSByte + [Test] + public void GetSByteReturnsInRangeValues() + { + CesiumMetadataValue value = new CesiumMetadataValue((SByte)126); + Assert.That(value.GetSByte(), Is.EqualTo(126)); + + value = new CesiumMetadataValue((Int32)(-127)); + Assert.That(value.GetSByte(), Is.EqualTo(-127)); + } + + [Test] + public void GetSByteConvertsBooleanValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(true); + Assert.That(value.GetSByte(-1), Is.EqualTo(1)); + + value = new CesiumMetadataValue(0); + Assert.That(value.GetSByte(-1), Is.EqualTo(0)); + } + + [Test] + public void GetSByteConvertsStringValue() + { + CesiumMetadataValue value = new CesiumMetadataValue("123"); + Assert.That(value.GetSByte(), Is.EqualTo(123)); + } + + [Test] + public void GetSByteReturnsDefaultValueForOutOfRangeNumbers() + { + CesiumMetadataValue value = new CesiumMetadataValue(123456); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + + value = new CesiumMetadataValue(-129); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + } + + [Test] + public void GetSByteReturnsDefaultValueForInvalidStrings() + { + CesiumMetadataValue value = new CesiumMetadataValue("123456"); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + + value = new CesiumMetadataValue("NaN"); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + } + + [Test] + public void GetSByteReturnsDefaultValueForUnsupportedTypes() + { + CesiumMetadataValue value = new CesiumMetadataValue(); + Assert.That(value.GetSByte(0), Is.EqualTo(0)); + + value = new CesiumMetadataValue(new int2(1, 1)); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + + value = new CesiumMetadataValue(new CesiumPropertyArray()); + Assert.That(value.GetSByte(), Is.EqualTo(0)); + } + #endregion + + #region GetString + [Test] + public void GetStringReturnsStringValue() + { + String str = "string"; + CesiumMetadataValue value = new CesiumMetadataValue(str); + Assert.That(value.GetString(), Is.EqualTo(str)); + } + + + [Test] + public void GetStringConvertsBooleanValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(true); + Assert.That(value.GetString(), Is.EqualTo("true")); + + value = new CesiumMetadataValue(false); + Assert.That(value.GetString(), Is.EqualTo("false")); + } + + [Test] + public void GetStringConvertsScalarValue() + { + CesiumMetadataValue value = new CesiumMetadataValue(1234); + Assert.That(value.GetString(), Is.EqualTo("1234")); + } + + [Test] + public void GetStringReturnsDefaultValueForUnsupportedTypes() + { + String defaultValue = "default"; + CesiumMetadataValue value = new CesiumMetadataValue(); + Assert.That(value.GetString(defaultValue), Is.EqualTo(defaultValue)); + + value = new CesiumMetadataValue(new CesiumPropertyArray()); + Assert.That(value.GetString(defaultValue), Is.EqualTo(defaultValue)); + } + #endregion } diff --git a/native~/Runtime/src/CesiumMetadataValueImpl.cpp b/native~/Runtime/src/CesiumMetadataValueImpl.cpp index 7fc394cb..f664a277 100644 --- a/native~/Runtime/src/CesiumMetadataValueImpl.cpp +++ b/native~/Runtime/src/CesiumMetadataValueImpl.cpp @@ -1,5 +1,139 @@ -//#include "CesiumMetadataValueImpl.h" -// -//DotNet::System::String CesiumMetadataValueImpl::GetString( -// const DotNet::CesiumForUnity::CesiumMetadataValue& value, -// DotNet::System::String defaultValue) {} +#include "CesiumMetadataValueImpl.h" + +#include + +#include +#include +#include + +#include + +using namespace CesiumGltf; +using namespace DotNet; +using namespace DotNet::CesiumForUnity; + +namespace CesiumForUnityNative { + +namespace { + +CesiumMetadataValueImpl::ValueType getNativeBooleanValue( + const DotNet::CesiumForUnity::CesiumMetadataValue& value) { + std::optional maybeBoolean = + CesiumForUnity::CesiumMetadataValue::GetObjectAsBoolean( + value.valueImpl()); + if (maybeBoolean) { + return *maybeBoolean; + } + + return std::monostate(); +} + +template +CesiumMetadataValueImpl::ValueType +getNativeScalarValue(const DotNet::System::Object& object) { + std::optional maybeValue; + if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsSByte(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsByte(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsInt16(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsUInt16(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsInt32(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsUInt32(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsInt64(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsUInt64(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsFloat(object); + } else if constexpr (std::is_same_v) { + maybeValue = CesiumMetadataValue::GetObjectAsDouble(object); + } + + if (maybeValue) { + return *maybeValue; + } + + return std::monostate(); +} + +CesiumMetadataValueImpl::ValueType +getNativeScalarValue(const DotNet::CesiumForUnity::CesiumMetadataValue& value) { + CesiumMetadataValueType valueType = value.valueType(); + assert(valueType.type == CesiumMetadataType::Scalar); + switch (valueType.componentType) { + case CesiumMetadataComponentType::Int8: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Uint8: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Int16: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Uint16: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Int32: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Uint32: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Int64: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Uint64: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Float32: + return getNativeScalarValue(value.valueImpl()); + case CesiumMetadataComponentType::Float64: + return getNativeScalarValue(value.valueImpl()); + default: + return std::monostate(); + } +} + +CesiumMetadataValueImpl::ValueType +getNativeStringValue(const DotNet::CesiumForUnity::CesiumMetadataValue& value) { + DotNet::System::String string = + CesiumForUnity::CesiumMetadataValue::GetObjectAsString(value.valueImpl()); + if (string == nullptr) { + return std::monostate(); + } + + return string.ToStlString(); +} + +} // namespace + +/*static*/ CesiumMetadataValueImpl::ValueType +CesiumMetadataValueImpl::getNativeValue( + const DotNet::CesiumForUnity::CesiumMetadataValue& value) { + CesiumForUnity::CesiumMetadataValueType valueType = value.valueType(); + switch (valueType.type) { + case CesiumForUnity::CesiumMetadataType::Boolean: + return getNativeBooleanValue(value); + case CesiumForUnity::CesiumMetadataType::Scalar: + return getNativeScalarValue(value); + case CesiumForUnity::CesiumMetadataType::String: + return getNativeStringValue(value); + default: + return std::monostate(); + } +} + +/*static*/ bool CesiumMetadataValueImpl::ConvertToBoolean( + const DotNet::CesiumForUnity::CesiumMetadataValue& value, + bool defaultValue) { + ValueType nativeValue = getNativeValue(value); + return std::visit( + [&defaultValue](auto trueValue) -> bool { + if constexpr (std::is_same_v) { + return defaultValue; + } else { + return MetadataConversions::convert( + trueValue) + .value_or(defaultValue); + } + }, + nativeValue); +} +} // namespace CesiumForUnityNative diff --git a/native~/Runtime/src/CesiumMetadataValueImpl.h b/native~/Runtime/src/CesiumMetadataValueImpl.h index 5cc98142..67430e42 100644 --- a/native~/Runtime/src/CesiumMetadataValueImpl.h +++ b/native~/Runtime/src/CesiumMetadataValueImpl.h @@ -1,20 +1,112 @@ -//#pragma once -// -//namespace DotNet::CesiumForUnity { -//class CesiumMetadataValue; -//} // namespace DotNet::CesiumForUnity -// -//namespace DotNet::System { -//class String; -//} -// -//namespace CesiumForUnityNative { -// -//class CesiumMetadataValueImpl { -// -//public: -// static DotNet::System::String GetString( -// const DotNet::CesiumForUnity::CesiumMetadataValue& value, -// DotNet::System::String defaultValue); -//}; -//} // namespace CesiumForUnityNative +#pragma once + +#include +#include + +#include + +namespace DotNet::CesiumForUnity { +class CesiumMetadataValue; +} // namespace DotNet::CesiumForUnity + +namespace DotNet::System { +class String; +class Object; +} // namespace DotNet::System + +namespace CesiumForUnityNative { + +class CesiumMetadataValueImpl { +public: +#pragma region ValueType declaration + // This definition excludes arrays because those are handled in C#. + using ValueType = std::variant< + std::monostate, + int8_t, + uint8_t, + int16_t, + uint16_t, + int32_t, + uint32_t, + int64_t, + uint64_t, + float, + double, + bool, + std::string, + glm::vec<2, int8_t>, + glm::vec<2, uint8_t>, + glm::vec<2, int16_t>, + glm::vec<2, uint16_t>, + glm::vec<2, int32_t>, + glm::vec<2, uint32_t>, + glm::vec<2, int64_t>, + glm::vec<2, uint64_t>, + glm::vec<2, float>, + glm::vec<2, double>, + glm::vec<3, int8_t>, + glm::vec<3, uint8_t>, + glm::vec<3, int16_t>, + glm::vec<3, uint16_t>, + glm::vec<3, int32_t>, + glm::vec<3, uint32_t>, + glm::vec<3, int64_t>, + glm::vec<3, uint64_t>, + glm::vec<3, float>, + glm::vec<3, double>, + glm::vec<4, int8_t>, + glm::vec<4, uint8_t>, + glm::vec<4, int16_t>, + glm::vec<4, uint16_t>, + glm::vec<4, int32_t>, + glm::vec<4, uint32_t>, + glm::vec<4, int64_t>, + glm::vec<4, uint64_t>, + glm::vec<4, float>, + glm::vec<4, double>, + glm::mat<2, 2, int8_t>, + glm::mat<2, 2, uint8_t>, + glm::mat<2, 2, int16_t>, + glm::mat<2, 2, uint16_t>, + glm::mat<2, 2, int32_t>, + glm::mat<2, 2, uint32_t>, + glm::mat<2, 2, int64_t>, + glm::mat<2, 2, uint64_t>, + glm::mat<2, 2, float>, + glm::mat<2, 2, double>, + glm::mat<3, 3, int8_t>, + glm::mat<3, 3, uint8_t>, + glm::mat<3, 3, int16_t>, + glm::mat<3, 3, uint16_t>, + glm::mat<3, 3, int32_t>, + glm::mat<3, 3, uint32_t>, + glm::mat<3, 3, int64_t>, + glm::mat<3, 3, uint64_t>, + glm::mat<3, 3, float>, + glm::mat<3, 3, double>, + glm::mat<4, 4, int8_t>, + glm::mat<4, 4, uint8_t>, + glm::mat<4, 4, int16_t>, + glm::mat<4, 4, uint16_t>, + glm::mat<4, 4, int32_t>, + glm::mat<4, 4, uint32_t>, + glm::mat<4, 4, int64_t>, + glm::mat<4, 4, uint64_t>, + glm::mat<4, 4, float>, + glm::mat<4, 4, double>>; +#pragma endregion + + static bool ConvertToBoolean( + const DotNet::CesiumForUnity::CesiumMetadataValue& value, + bool defaultValue); + +private: + /** + * Retrieves the value from the System.Object in the C# + * class implementation as a C++-compatible type. std::monostate is used to + * indicate a null value. + */ + static ValueType + getNativeValue(const DotNet::CesiumForUnity::CesiumMetadataValue& value); +}; +} // namespace CesiumForUnityNative diff --git a/native~/Runtime/src/CesiumPropertyTablePropertyImpl.h b/native~/Runtime/src/CesiumPropertyTablePropertyImpl.h index 452db44e..1dbf4c50 100644 --- a/native~/Runtime/src/CesiumPropertyTablePropertyImpl.h +++ b/native~/Runtime/src/CesiumPropertyTablePropertyImpl.h @@ -15,7 +15,8 @@ class CesiumPropertyTablePropertyImpl; namespace DotNet::CesiumForUnity { class CesiumPropertyTableProperty; -} +class CesiumMetadataValue; +} // namespace DotNet::CesiumForUnity namespace DotNet::System { class String; @@ -26,6 +27,14 @@ class int2; class uint2; class float2; class double2; +class int3; +class uint3; +class float3; +class double3; +class int4; +class uint4; +class float4; +class double4; } // namespace DotNet::Unity::Mathematics namespace CesiumForUnityNative { @@ -122,6 +131,10 @@ class CesiumPropertyTablePropertyImpl { std::int64_t featureID, const DotNet::System::String& defaultValue); + //DotNet::CesiumForUnity::CesiumMetadataValue GetValue( + // const DotNet::CesiumForUnity::CesiumPropertyTableProperty& property, + // std::int64_t featureID); + private: std::any _property; };