@rafaelaugusto/jolt-native 0.1.0-beta.13 → 0.1.0-beta.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ Optional NativeScript plugin for `@rafaelaugusto/jolt/native`. Install this pack
|
|
|
6
6
|
npm install @rafaelaugusto/jolt @rafaelaugusto/jolt-native
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Includes compiled scalar/compound playback, MapKit and SceneKit sinks on iOS, and a MapLibre sink on Android. It does not install MapLibre; the app chooses its SDK version. Reference demo: MapLibre Android 11.8.0, NativeScript 9.1, iOS 26 / Android 16. Minimum NativeScript 8.9; native helper APIs require iOS 13+ / Android API 23+ (the app/runtime or SDK may require newer).
|
|
9
|
+
Includes compiled scalar/compound playback, MapKit and SceneKit pose/light/material sinks on iOS, and a MapLibre sink on Android. It does not install MapLibre; the app chooses its SDK version. Reference demo: MapLibre Android 11.8.0, NativeScript 9.1, iOS 26 / Android 16. Minimum NativeScript 8.9; native helper APIs require iOS 13+ / Android API 23+ (the app/runtime or SDK may require newer).
|
|
10
|
+
|
|
11
|
+
SceneKit appearance supports light intensity/color and material transparency/solid diffuse/emission colors; textures are rejected. See the [lighting guide](https://jolt.rafaelaugusto.dev/guide/scene-lighting) for interpolation and lifecycle limits.
|
|
10
12
|
|
|
11
13
|
See the [native properties guide](https://jolt.rafaelaugusto.dev/guide/native-properties) for capabilities, authoring, ownership and execution limits.
|
|
12
14
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rafaelaugusto/jolt-native",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.14",
|
|
4
4
|
"description": "Optional compiled property adapters for Jolt (MapKit, MapLibre and SceneKit).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
],
|
|
15
15
|
"sideEffects": false,
|
|
16
16
|
"peerDependencies": {
|
|
17
|
-
"@rafaelaugusto/jolt": ">=0.1.0-beta.
|
|
17
|
+
"@rafaelaugusto/jolt": ">=0.1.0-beta.14",
|
|
18
18
|
"@nativescript/core": ">=8.9.0"
|
|
19
19
|
},
|
|
20
20
|
"nativescript": {
|
|
@@ -4,5 +4,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|
|
4
4
|
+ (JoltPropertySink *)mapCoordinate:(NSObject *)annotation;
|
|
5
5
|
+ (JoltPropertySink *)mapCamera:(NSObject *)mapView;
|
|
6
6
|
+ (JoltPropertySink *)scenePose:(NSObject *)node;
|
|
7
|
+
+ (JoltPropertySink *)sceneLightIntensity:(NSObject *)light;
|
|
8
|
+
+ (JoltPropertySink *)sceneLightColor:(NSObject *)light;
|
|
9
|
+
+ (JoltPropertySink *)sceneMaterialTransparency:(NSObject *)material;
|
|
10
|
+
+ (JoltPropertySink *)sceneMaterialDiffuse:(NSObject *)material;
|
|
11
|
+
+ (JoltPropertySink *)sceneMaterialEmission:(NSObject *)material;
|
|
12
|
+
/** Diagnostic count of undisposed appearance sinks (native targets are weak). */
|
|
13
|
+
+ (NSUInteger)sceneAppearanceSinkCount;
|
|
14
|
+
+ (NSUInteger)sceneAppearanceWriteCount;
|
|
7
15
|
@end
|
|
8
16
|
NS_ASSUME_NONNULL_END
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#import "JoltReferenceProperties.h"
|
|
2
2
|
#import <MapKit/MapKit.h>
|
|
3
3
|
#import <SceneKit/SceneKit.h>
|
|
4
|
+
#import <UIKit/UIKit.h>
|
|
4
5
|
|
|
5
6
|
static double longitude(double value) { return fmod(fmod(value+180,360)+360,360)-180; }
|
|
6
7
|
@interface JoltMapCoordinateSink : JoltPropertySink @end
|
|
@@ -47,7 +48,125 @@ static double longitude(double value) { return fmod(fmod(value+180,360)+360,360)
|
|
|
47
48
|
[SCNTransaction commit];
|
|
48
49
|
}
|
|
49
50
|
@end
|
|
51
|
+
// Appearance is read from the model: SceneKit exposes presentationNode, but no public
|
|
52
|
+
// presentation object for a standalone SCNLight/SCNMaterial. Our immediate writes keep
|
|
53
|
+
// the model current. Apps must remove competing animations before transferring control.
|
|
54
|
+
typedef NS_ENUM(NSUInteger, JoltSceneAppearanceKind) {
|
|
55
|
+
JoltSceneIntensity, JoltSceneLightColor, JoltSceneTransparency, JoltSceneDiffuse, JoltSceneEmission
|
|
56
|
+
};
|
|
57
|
+
static NSUInteger appearanceSinks, appearanceWrites;
|
|
58
|
+
static CGFloat unitComponent(CGFloat value) { return MAX(0, MIN(1, value)); }
|
|
59
|
+
static CGColorRef copySceneColor(id value) CF_RETURNS_RETAINED {
|
|
60
|
+
CGColorRef original = NULL;
|
|
61
|
+
if ([value isKindOfClass:UIColor.class])
|
|
62
|
+
original = [[value resolvedColorWithTraitCollection:UITraitCollection.currentTraitCollection] CGColor];
|
|
63
|
+
else if (value && CFGetTypeID((__bridge CFTypeRef)value) == CGColorGetTypeID())
|
|
64
|
+
original = (__bridge CGColorRef)value;
|
|
65
|
+
if (!original) return NULL;
|
|
66
|
+
CGColorSpaceRef space = CGColorSpaceCreateWithName(kCGColorSpaceSRGB);
|
|
67
|
+
CGColorRef converted = CGColorCreateCopyByMatchingToColorSpace(space, kCGRenderingIntentDefault, original, NULL);
|
|
68
|
+
CGColorSpaceRelease(space);
|
|
69
|
+
if (converted && (CGColorGetNumberOfComponents(converted) != 4 || CGColorSpaceGetModel(CGColorGetColorSpace(converted)) != kCGColorSpaceModelRGB)) {
|
|
70
|
+
CGColorRelease(converted); return NULL;
|
|
71
|
+
}
|
|
72
|
+
return converted;
|
|
73
|
+
}
|
|
74
|
+
@interface JoltSceneAppearanceSink : JoltPropertySink
|
|
75
|
+
@property(nonatomic) JoltSceneAppearanceKind kind;
|
|
76
|
+
@property(nonatomic) BOOL released;
|
|
77
|
+
+ (instancetype)target:(NSObject *)target kind:(JoltSceneAppearanceKind)kind;
|
|
78
|
+
@end
|
|
79
|
+
@implementation JoltSceneAppearanceSink
|
|
80
|
+
+ (instancetype)target:(NSObject *)target kind:(JoltSceneAppearanceKind)kind {
|
|
81
|
+
NSParameterAssert(NSThread.isMainThread);
|
|
82
|
+
BOOL light = kind == JoltSceneIntensity || kind == JoltSceneLightColor;
|
|
83
|
+
if (![target isKindOfClass:light ? SCNLight.class : SCNMaterial.class])
|
|
84
|
+
[NSException raise:NSInvalidArgumentException format:@"Jolt SceneKit adapter requires %@", light ? @"SCNLight" : @"SCNMaterial"];
|
|
85
|
+
JoltSceneAppearanceSink *sink = [[self alloc] initWithTarget:target dimensions:(kind == JoltSceneIntensity || kind == JoltSceneTransparency) ? 1 : 4];
|
|
86
|
+
sink.kind = kind; appearanceSinks++;
|
|
87
|
+
if (!sink.alive) {
|
|
88
|
+
[sink dispose];
|
|
89
|
+
[NSException raise:NSInvalidArgumentException format:@"Jolt SceneKit adapter requires a valid scalar or solid UIColor/CGColor; textures, images, numbers, patterns and nil color contents are unsupported"];
|
|
90
|
+
}
|
|
91
|
+
return sink;
|
|
92
|
+
}
|
|
93
|
+
- (id)contents {
|
|
94
|
+
switch (self.kind) {
|
|
95
|
+
case JoltSceneLightColor: return [(SCNLight *)self.target color];
|
|
96
|
+
case JoltSceneDiffuse: return [(SCNMaterial *)self.target diffuse].contents;
|
|
97
|
+
case JoltSceneEmission: return [(SCNMaterial *)self.target emission].contents;
|
|
98
|
+
default: return nil;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
- (BOOL)alive {
|
|
102
|
+
if (!self.target) return NO;
|
|
103
|
+
if (self.kind == JoltSceneIntensity || self.kind == JoltSceneTransparency) {
|
|
104
|
+
double value = self.kind == JoltSceneIntensity ? [(SCNLight *)self.target intensity] : [(SCNMaterial *)self.target transparency];
|
|
105
|
+
return isfinite(value) && value >= 0 && (self.kind != JoltSceneTransparency || value <= 1);
|
|
106
|
+
}
|
|
107
|
+
CGColorRef color = copySceneColor(self.contents);
|
|
108
|
+
BOOL valid = color != NULL;
|
|
109
|
+
if (color) CGColorRelease(color);
|
|
110
|
+
return valid;
|
|
111
|
+
}
|
|
112
|
+
- (NSArray<NSNumber *> *)read {
|
|
113
|
+
NSParameterAssert(NSThread.isMainThread);
|
|
114
|
+
if (!self.alive) [NSException raise:NSInvalidArgumentException format:@"Jolt SceneKit target or solid color contents are no longer valid"];
|
|
115
|
+
if (self.kind == JoltSceneIntensity) return @[@([(SCNLight *)self.target intensity])];
|
|
116
|
+
if (self.kind == JoltSceneTransparency) return @[@([(SCNMaterial *)self.target transparency])];
|
|
117
|
+
CGColorRef color = copySceneColor(self.contents);
|
|
118
|
+
const CGFloat *v = CGColorGetComponents(color);
|
|
119
|
+
CGFloat a = unitComponent(v[3]);
|
|
120
|
+
NSArray *result = @[@(unitComponent(v[0])*a), @(unitComponent(v[1])*a), @(unitComponent(v[2])*a), @(a)];
|
|
121
|
+
CGColorRelease(color);
|
|
122
|
+
return result;
|
|
123
|
+
}
|
|
124
|
+
- (void)write:(NSArray<NSNumber *> *)values {
|
|
125
|
+
NSParameterAssert(NSThread.isMainThread);
|
|
126
|
+
if (!self.alive) [NSException raise:NSInvalidArgumentException format:@"Jolt will not overwrite unsupported SceneKit contents"];
|
|
127
|
+
if (values.count != self.dimensions) [NSException raise:NSInvalidArgumentException format:@"Invalid SceneKit component count"];
|
|
128
|
+
for (NSNumber *value in values)
|
|
129
|
+
if (!isfinite(value.doubleValue)) [NSException raise:NSInvalidArgumentException format:@"Nonfinite SceneKit component"];
|
|
130
|
+
if (self.dimensions == 1 && (values[0].doubleValue < 0 || (self.kind == JoltSceneTransparency && values[0].doubleValue > 1)))
|
|
131
|
+
[NSException raise:NSInvalidArgumentException format:@"SceneKit scalar is outside its range"];
|
|
132
|
+
UIColor *color = nil;
|
|
133
|
+
if (self.dimensions == 4) {
|
|
134
|
+
double a = values[3].doubleValue;
|
|
135
|
+
if (a < 0 || a > 1) [NSException raise:NSInvalidArgumentException format:@"Invalid SceneKit alpha"];
|
|
136
|
+
for (NSUInteger i=0; i<3; i++)
|
|
137
|
+
if (values[i].doubleValue < 0 || values[i].doubleValue > a + 1e-9)
|
|
138
|
+
[NSException raise:NSInvalidArgumentException format:@"Invalid premultiplied SceneKit color"];
|
|
139
|
+
color = [UIColor colorWithRed:a ? unitComponent(values[0].doubleValue/a) : 0
|
|
140
|
+
green:a ? unitComponent(values[1].doubleValue/a) : 0
|
|
141
|
+
blue:a ? unitComponent(values[2].doubleValue/a) : 0 alpha:a];
|
|
142
|
+
}
|
|
143
|
+
[SCNTransaction begin]; [SCNTransaction setDisableActions:YES];
|
|
144
|
+
@try {
|
|
145
|
+
switch (self.kind) {
|
|
146
|
+
case JoltSceneIntensity: [(SCNLight *)self.target setIntensity:values[0].doubleValue]; break;
|
|
147
|
+
case JoltSceneTransparency: [(SCNMaterial *)self.target setTransparency:values[0].doubleValue]; break;
|
|
148
|
+
case JoltSceneLightColor: [(SCNLight *)self.target setColor:color]; break;
|
|
149
|
+
case JoltSceneDiffuse: [(SCNMaterial *)self.target diffuse].contents = color; break;
|
|
150
|
+
case JoltSceneEmission: [(SCNMaterial *)self.target emission].contents = color; break;
|
|
151
|
+
}
|
|
152
|
+
appearanceWrites++;
|
|
153
|
+
} @finally { [SCNTransaction commit]; }
|
|
154
|
+
}
|
|
155
|
+
- (void)dispose {
|
|
156
|
+
if (!self.released) { self.released = YES; appearanceSinks--; }
|
|
157
|
+
[super dispose];
|
|
158
|
+
}
|
|
159
|
+
- (void)dealloc { if (!self.released) appearanceSinks--; }
|
|
160
|
+
@end
|
|
161
|
+
|
|
50
162
|
@implementation JoltReferenceProperties
|
|
163
|
+
+ (JoltPropertySink *)sceneLightIntensity:(NSObject *)light { return [JoltSceneAppearanceSink target:light kind:JoltSceneIntensity]; }
|
|
164
|
+
+ (JoltPropertySink *)sceneLightColor:(NSObject *)light { return [JoltSceneAppearanceSink target:light kind:JoltSceneLightColor]; }
|
|
165
|
+
+ (JoltPropertySink *)sceneMaterialTransparency:(NSObject *)material { return [JoltSceneAppearanceSink target:material kind:JoltSceneTransparency]; }
|
|
166
|
+
+ (JoltPropertySink *)sceneMaterialDiffuse:(NSObject *)material { return [JoltSceneAppearanceSink target:material kind:JoltSceneDiffuse]; }
|
|
167
|
+
+ (JoltPropertySink *)sceneMaterialEmission:(NSObject *)material { return [JoltSceneAppearanceSink target:material kind:JoltSceneEmission]; }
|
|
168
|
+
+ (NSUInteger)sceneAppearanceSinkCount { return appearanceSinks; }
|
|
169
|
+
+ (NSUInteger)sceneAppearanceWriteCount { return appearanceWrites; }
|
|
51
170
|
+ (JoltPropertySink *)mapCoordinate:(NSObject *)annotation {
|
|
52
171
|
NSParameterAssert([annotation conformsToProtocol:@protocol(MKAnnotation)] && [annotation respondsToSelector:@selector(setCoordinate:)]);
|
|
53
172
|
return [[JoltMapCoordinateSink alloc] initWithTarget:annotation dimensions:2];
|