rngine 0.5.0 → 0.7.0
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 +25 -17
- package/android/CMakeLists.txt +1 -0
- package/android/kls_database.db +0 -0
- package/android/src/main/cpp/GameLoopJNI.cpp +117 -27
- package/android/src/main/java/com/margelo/nitro/rngine/GameAssets.kt +11 -1
- package/android/src/main/java/com/margelo/nitro/rngine/GameView.kt +138 -52
- package/android/src/main/java/com/margelo/nitro/rngine/Screen.kt +9 -0
- package/android/src/main/java/com/margelo/nitro/rngine/Shape.kt +26 -0
- package/android/src/main/java/com/margelo/nitro/rngine/Snapshot.kt +3 -0
- package/android/src/main/java/com/margelo/nitro/rngine/SnapshotSerializer.kt +53 -0
- package/lib/typescript/src/nativeTypes.d.ts +33 -44
- package/lib/typescript/src/nativeTypes.d.ts.map +1 -1
- package/nitrogen/generated/shared/c++/Circle.hpp +83 -0
- package/nitrogen/generated/shared/c++/Entity.hpp +12 -10
- package/nitrogen/generated/shared/c++/EntityUpdate.hpp +12 -10
- package/nitrogen/generated/shared/c++/Rect.hpp +87 -0
- package/package.json +1 -1
- package/shared/CollisionUtils.cpp +67 -0
- package/shared/CollisionUtils.hpp +19 -0
- package/shared/GameLoop.cpp +6 -45
- package/shared/GameLoop.hpp +0 -2
- package/shared/GameMethods.cpp +2 -5
- package/src/nativeTypes.ts +41 -46
- package/android/src/main/java/com/margelo/nitro/rngine/Rect.kt +0 -11
- package/android/src/main/java/com/margelo/nitro/rngine/RectSerializer.kt +0 -25
- package/shared/Rect.hpp +0 -16
- /package/{shared → android/src/main/cpp}/ColorUtils.hpp +0 -0
package/README.md
CHANGED
|
@@ -21,28 +21,33 @@ configure({
|
|
|
21
21
|
entities: [
|
|
22
22
|
{
|
|
23
23
|
id: 'player',
|
|
24
|
-
px:
|
|
25
|
-
py:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
px: 420,
|
|
25
|
+
py: 420,
|
|
26
|
+
color: '#0f0',
|
|
27
|
+
shape: {
|
|
28
|
+
radius: 20,
|
|
29
|
+
},
|
|
29
30
|
},
|
|
30
31
|
{
|
|
31
32
|
id: 'enemy_1',
|
|
32
|
-
px:
|
|
33
|
-
py:
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
px: 120,
|
|
34
|
+
py: 120,
|
|
35
|
+
color: '#f00',
|
|
36
|
+
shape: {
|
|
37
|
+
width: 40,
|
|
38
|
+
height: 40,
|
|
39
|
+
},
|
|
37
40
|
vx: 1000,
|
|
38
41
|
},
|
|
39
42
|
{
|
|
40
43
|
id: 'enemy_2',
|
|
41
|
-
px:
|
|
42
|
-
py:
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
px: 220,
|
|
45
|
+
py: 220,
|
|
46
|
+
color: '#f00',
|
|
47
|
+
shape: {
|
|
48
|
+
width: 40,
|
|
49
|
+
height: 40,
|
|
50
|
+
},
|
|
46
51
|
vx: -1000,
|
|
47
52
|
},
|
|
48
53
|
],
|
|
@@ -53,7 +58,10 @@ configure({
|
|
|
53
58
|
onTick: (enemies) => {
|
|
54
59
|
enemies.forEach((enemy) => {
|
|
55
60
|
// reverse direction when reaching screen edges
|
|
56
|
-
if (
|
|
61
|
+
if (
|
|
62
|
+
enemy.px - enemy.width / 2 <= 0 ||
|
|
63
|
+
enemy.px + enemy.width / 2 >= 800
|
|
64
|
+
) {
|
|
57
65
|
update({ id: enemy.id, vx: -enemy.vx });
|
|
58
66
|
}
|
|
59
67
|
});
|
|
@@ -70,7 +78,7 @@ export default function App() {
|
|
|
70
78
|
|
|
71
79
|
## Concepts
|
|
72
80
|
|
|
73
|
-
**Entities** are the objects in your game world. Each entity has a position,
|
|
81
|
+
**Entities** are the objects in your game world. Each entity has a position, shape, color, and velocity. See [`Entity`](./src/nativeTypes.ts).
|
|
74
82
|
|
|
75
83
|
**Systems** define your game logic. Each system optionally declares which entities it cares about via `entities`, which collision pairs to watch via `collisions`, or both. Systems run every tick receiving the resolved entities and any active collisions. See [`System`](./src/types.ts).
|
|
76
84
|
|
package/android/CMakeLists.txt
CHANGED
package/android/kls_database.db
CHANGED
|
Binary file
|
|
@@ -1,36 +1,126 @@
|
|
|
1
|
+
#include "ColorUtils.hpp"
|
|
1
2
|
#include "GameLoop.hpp"
|
|
3
|
+
#include <cstdint>
|
|
2
4
|
#include <jni.h>
|
|
5
|
+
#include <mutex>
|
|
6
|
+
#include <variant>
|
|
3
7
|
|
|
4
8
|
extern "C" {
|
|
5
|
-
JNIEXPORT
|
|
6
|
-
|
|
7
|
-
auto
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
uint8_t
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
9
|
+
JNIEXPORT jbyteArray JNICALL
|
|
10
|
+
Java_com_margelo_nitro_rngine_GameView_getSnapshot(JNIEnv *env, jobject) {
|
|
11
|
+
auto &gameLoop = margelo::nitro::rngine::GameLoop::getInstance();
|
|
12
|
+
auto &snapshotMutex = gameLoop.getSnapshotMutexInternal();
|
|
13
|
+
|
|
14
|
+
std::lock_guard<std::mutex> snapshotLock(snapshotMutex);
|
|
15
|
+
auto &screenSnapshot = gameLoop.getScreenSnapshotInternal();
|
|
16
|
+
auto &entitiesSnapshot = gameLoop.getEntitiesSnapshotInternal();
|
|
17
|
+
|
|
18
|
+
std::vector<uint8_t> buffer;
|
|
19
|
+
|
|
20
|
+
auto writeFloat = [&](float v) {
|
|
21
|
+
const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
|
|
22
|
+
buffer.insert(buffer.end(), bytes, bytes + sizeof(float));
|
|
23
|
+
};
|
|
24
|
+
auto writeI32 = [&](int32_t v) {
|
|
25
|
+
const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
|
|
26
|
+
buffer.insert(buffer.end(), bytes, bytes + sizeof(int32_t));
|
|
27
|
+
};
|
|
28
|
+
auto writeU32 = [&](uint32_t v) {
|
|
29
|
+
const auto *bytes = reinterpret_cast<const uint8_t *>(&v);
|
|
30
|
+
buffer.insert(buffer.end(), bytes, bytes + sizeof(uint32_t));
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const auto screenSnapshotWidth = static_cast<float>(screenSnapshot.width);
|
|
34
|
+
const auto screenSnapshotHeight = static_cast<float>(screenSnapshot.height);
|
|
35
|
+
const auto screenSnapshotColor =
|
|
36
|
+
margelo::nitro::rngine::parseHexColor(screenSnapshot.color);
|
|
37
|
+
const auto screenSnapshotAsset =
|
|
38
|
+
static_cast<int32_t>(screenSnapshot.asset.value_or(0));
|
|
39
|
+
|
|
40
|
+
writeFloat(screenSnapshotWidth);
|
|
41
|
+
writeFloat(screenSnapshotHeight);
|
|
42
|
+
writeU32(screenSnapshotColor);
|
|
43
|
+
writeI32(screenSnapshotAsset);
|
|
44
|
+
|
|
45
|
+
if (screenSnapshotAsset < 0) {
|
|
46
|
+
writeFloat(static_cast<float>(screenSnapshot.progress.value_or(0)));
|
|
31
47
|
}
|
|
32
48
|
|
|
33
|
-
|
|
49
|
+
for (const auto &[_, entitySnapshot] : entitiesSnapshot) {
|
|
50
|
+
uint8_t shapeType{0};
|
|
51
|
+
float entitySnapshotLeft{0}, entitySnapshotRight{0}, entitySnapshotTop{0},
|
|
52
|
+
entitySnapshotBottom{0}, circleRadius{0};
|
|
53
|
+
|
|
54
|
+
std::visit(
|
|
55
|
+
[&](const auto &shape) {
|
|
56
|
+
using T = std::decay_t<decltype(shape)>;
|
|
57
|
+
if constexpr (std::is_same_v<T, margelo::nitro::rngine::Rect>) {
|
|
58
|
+
shapeType = 0;
|
|
59
|
+
entitySnapshotLeft =
|
|
60
|
+
static_cast<float>(entitySnapshot.px - shape.width / 2.0);
|
|
61
|
+
entitySnapshotRight =
|
|
62
|
+
static_cast<float>(entitySnapshot.px + shape.width / 2.0);
|
|
63
|
+
entitySnapshotTop =
|
|
64
|
+
static_cast<float>(entitySnapshot.py - shape.height / 2.0);
|
|
65
|
+
entitySnapshotBottom =
|
|
66
|
+
static_cast<float>(entitySnapshot.py + shape.height / 2.0);
|
|
67
|
+
} else {
|
|
68
|
+
shapeType = 1;
|
|
69
|
+
circleRadius = static_cast<float>(shape.radius);
|
|
70
|
+
entitySnapshotLeft =
|
|
71
|
+
static_cast<float>(entitySnapshot.px - shape.radius);
|
|
72
|
+
entitySnapshotRight =
|
|
73
|
+
static_cast<float>(entitySnapshot.px + shape.radius);
|
|
74
|
+
entitySnapshotTop =
|
|
75
|
+
static_cast<float>(entitySnapshot.py - shape.radius);
|
|
76
|
+
entitySnapshotBottom =
|
|
77
|
+
static_cast<float>(entitySnapshot.py + shape.radius);
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
entitySnapshot.shape);
|
|
81
|
+
|
|
82
|
+
if (entitySnapshotRight < 0 || entitySnapshotLeft > screenSnapshot.width ||
|
|
83
|
+
entitySnapshotBottom < 0 || entitySnapshotTop > screenSnapshot.height) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const auto entitySnapshotColor =
|
|
88
|
+
margelo::nitro::rngine::parseHexColor(entitySnapshot.color);
|
|
89
|
+
const auto entitySnapshotAsset =
|
|
90
|
+
static_cast<int32_t>(entitySnapshot.asset.value_or(0));
|
|
91
|
+
|
|
92
|
+
buffer.push_back(shapeType);
|
|
93
|
+
|
|
94
|
+
if (shapeType == 0) {
|
|
95
|
+
writeFloat(entitySnapshotLeft);
|
|
96
|
+
writeFloat(entitySnapshotRight);
|
|
97
|
+
writeFloat(entitySnapshotTop);
|
|
98
|
+
writeFloat(entitySnapshotBottom);
|
|
99
|
+
} else {
|
|
100
|
+
writeFloat(static_cast<float>(entitySnapshot.px));
|
|
101
|
+
writeFloat(static_cast<float>(entitySnapshot.py));
|
|
102
|
+
writeFloat(circleRadius);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
writeU32(entitySnapshotColor);
|
|
106
|
+
writeI32(entitySnapshotAsset);
|
|
107
|
+
|
|
108
|
+
if (entitySnapshotAsset < 0) {
|
|
109
|
+
writeFloat(static_cast<float>(entitySnapshot.progress.value_or(0)));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
auto bufferSize = static_cast<jsize>(buffer.size());
|
|
114
|
+
jbyteArray result = env->NewByteArray(bufferSize);
|
|
115
|
+
|
|
116
|
+
if (result == nullptr) {
|
|
117
|
+
return nullptr;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
env->SetByteArrayRegion(result, 0, bufferSize,
|
|
121
|
+
reinterpret_cast<const jbyte *>(buffer.data()));
|
|
122
|
+
|
|
123
|
+
return result;
|
|
34
124
|
}
|
|
35
125
|
|
|
36
126
|
JNIEXPORT void JNICALL
|
|
@@ -6,6 +6,7 @@ import com.airbnb.lottie.LottieDrawable
|
|
|
6
6
|
import com.caverock.androidsvg.SVG
|
|
7
7
|
import com.margelo.nitro.core.Promise
|
|
8
8
|
import java.net.URL
|
|
9
|
+
import com.margelo.nitro.NitroModules
|
|
9
10
|
|
|
10
11
|
class GameAssets : HybridGameAssetsSpec() {
|
|
11
12
|
private external fun registerLottieDuration(id: Double, duration: Double)
|
|
@@ -22,7 +23,16 @@ class GameAssets : HybridGameAssetsSpec() {
|
|
|
22
23
|
override fun registerSvg(id: Double, uri: String): Promise<Unit> {
|
|
23
24
|
return Promise.async {
|
|
24
25
|
try {
|
|
25
|
-
val stream =
|
|
26
|
+
val stream = if (uri.startsWith("http://") || uri.startsWith("https://")) {
|
|
27
|
+
URL(uri).openStream()
|
|
28
|
+
} else {
|
|
29
|
+
val context = NitroModules.applicationContext ?: throw Error("No Context available!")
|
|
30
|
+
val resId = context.resources.getIdentifier(uri, "raw", context.packageName)
|
|
31
|
+
if (resId == 0) {
|
|
32
|
+
throw IllegalStateException("Could not resolve drawable resource for asset: $uri")
|
|
33
|
+
}
|
|
34
|
+
context.resources.openRawResource(resId)
|
|
35
|
+
}
|
|
26
36
|
assetCache[id.toInt()] = Asset.Svg(SVG.getFromInputStream(stream).renderToPicture())
|
|
27
37
|
Log.d("GameAssets", "assetCache: $assetCache")
|
|
28
38
|
} catch (e: Exception) {
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
package com.margelo.nitro.rngine
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
-
import android.graphics.
|
|
4
|
+
import android.graphics.Canvas
|
|
5
5
|
import android.graphics.Paint
|
|
6
6
|
import android.util.AttributeSet
|
|
7
|
-
import android.util.Log
|
|
8
7
|
import android.view.SurfaceView
|
|
9
8
|
import android.view.View
|
|
10
|
-
import java.nio.ByteBuffer
|
|
11
9
|
import androidx.core.graphics.withTranslation
|
|
12
10
|
import androidx.core.graphics.withClip
|
|
13
11
|
|
|
@@ -20,15 +18,98 @@ class GameView(
|
|
|
20
18
|
attrs,
|
|
21
19
|
defStyleAttr,
|
|
22
20
|
) {
|
|
23
|
-
private external fun
|
|
21
|
+
private external fun getSnapshot(): ByteArray
|
|
24
22
|
var onAttached: () -> Unit = {}
|
|
25
23
|
var onDetached: () -> Unit = {}
|
|
26
24
|
|
|
27
25
|
private val paint = Paint().apply {
|
|
28
|
-
color = Color.TRANSPARENT
|
|
29
26
|
style = Paint.Style.FILL
|
|
30
27
|
}
|
|
31
28
|
|
|
29
|
+
private fun drawAsset(
|
|
30
|
+
canvas: Canvas,
|
|
31
|
+
left: Float,
|
|
32
|
+
top: Float,
|
|
33
|
+
right: Float,
|
|
34
|
+
bottom: Float,
|
|
35
|
+
asset: Int,
|
|
36
|
+
progress: Float?,
|
|
37
|
+
) {
|
|
38
|
+
canvas.withTranslation(left, top) {
|
|
39
|
+
when (val resolvedAsset = GameAssets.getAsset(asset)) {
|
|
40
|
+
is Asset.Svg -> {
|
|
41
|
+
scale(
|
|
42
|
+
(right - left) / resolvedAsset.picture.width,
|
|
43
|
+
(bottom - top) / resolvedAsset.picture.height
|
|
44
|
+
)
|
|
45
|
+
drawPicture(resolvedAsset.picture)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
is Asset.Lottie -> {
|
|
49
|
+
progress?.let {
|
|
50
|
+
resolvedAsset.drawable.progress = it
|
|
51
|
+
}
|
|
52
|
+
resolvedAsset.drawable.setBounds(0, 0, (right - left).toInt(), (bottom - top).toInt())
|
|
53
|
+
resolvedAsset.drawable.draw(canvas)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
null -> {}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private fun drawRect(
|
|
62
|
+
canvas: Canvas,
|
|
63
|
+
left: Float,
|
|
64
|
+
top: Float,
|
|
65
|
+
right: Float,
|
|
66
|
+
bottom: Float,
|
|
67
|
+
color: Int,
|
|
68
|
+
asset: Int,
|
|
69
|
+
progress: Float?,
|
|
70
|
+
) {
|
|
71
|
+
paint.color = color
|
|
72
|
+
canvas.drawRect(left, top, right, bottom, paint)
|
|
73
|
+
|
|
74
|
+
drawAsset(
|
|
75
|
+
canvas,
|
|
76
|
+
left,
|
|
77
|
+
top,
|
|
78
|
+
right,
|
|
79
|
+
bottom,
|
|
80
|
+
asset,
|
|
81
|
+
progress
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
private fun drawCircle(
|
|
86
|
+
canvas: Canvas,
|
|
87
|
+
cx: Float,
|
|
88
|
+
cy: Float,
|
|
89
|
+
radius: Float,
|
|
90
|
+
color: Int,
|
|
91
|
+
asset: Int,
|
|
92
|
+
progress: Float?,
|
|
93
|
+
) {
|
|
94
|
+
val left = cx - radius
|
|
95
|
+
val top = cy - radius
|
|
96
|
+
val right = cx + radius
|
|
97
|
+
val bottom = cy + radius
|
|
98
|
+
|
|
99
|
+
paint.color = color
|
|
100
|
+
canvas.drawCircle(cx, cy, radius, paint)
|
|
101
|
+
|
|
102
|
+
drawAsset(
|
|
103
|
+
canvas,
|
|
104
|
+
left,
|
|
105
|
+
top,
|
|
106
|
+
right,
|
|
107
|
+
bottom,
|
|
108
|
+
asset,
|
|
109
|
+
progress,
|
|
110
|
+
)
|
|
111
|
+
}
|
|
112
|
+
|
|
32
113
|
init {
|
|
33
114
|
addOnAttachStateChangeListener(
|
|
34
115
|
object : OnAttachStateChangeListener {
|
|
@@ -40,60 +121,65 @@ class GameView(
|
|
|
40
121
|
fun drawFrame() {
|
|
41
122
|
if (!holder.surface.isValid) return
|
|
42
123
|
val canvas = holder.lockCanvas() ?: return
|
|
124
|
+
val snapshot = SnapshotSerializer.decode(getSnapshot())
|
|
43
125
|
|
|
44
|
-
val
|
|
45
|
-
|
|
46
|
-
val worldRect = rects.first()
|
|
47
|
-
val scaleX = canvas.width / worldRect.right
|
|
48
|
-
val scaleY = canvas.height / worldRect.bottom
|
|
126
|
+
val scaleX = canvas.width / snapshot.screen.width
|
|
127
|
+
val scaleY = canvas.height / snapshot.screen.height
|
|
49
128
|
val scale = minOf(scaleX, scaleY)
|
|
50
129
|
|
|
51
|
-
val
|
|
52
|
-
val
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
130
|
+
val screenLeft = (canvas.width - snapshot.screen.width * scale) / 2f
|
|
131
|
+
val screenTop = (canvas.height - snapshot.screen.height * scale) / 2f
|
|
132
|
+
val screenRight = screenLeft + snapshot.screen.width * scale
|
|
133
|
+
val screenBottom = screenTop + snapshot.screen.height * scale
|
|
134
|
+
|
|
135
|
+
drawRect(
|
|
136
|
+
canvas,
|
|
137
|
+
screenLeft,
|
|
138
|
+
screenTop,
|
|
139
|
+
screenRight,
|
|
140
|
+
screenBottom,
|
|
141
|
+
snapshot.screen.color,
|
|
142
|
+
snapshot.screen.asset,
|
|
143
|
+
snapshot.screen.progress,
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
canvas.withClip(screenLeft, screenTop, screenRight, screenBottom) {
|
|
147
|
+
snapshot.shapes.forEach { shape ->
|
|
148
|
+
when (shape) {
|
|
149
|
+
is Shape.Rect -> {
|
|
150
|
+
val left = shape.left * scale + screenLeft
|
|
151
|
+
val top = shape.top * scale + screenTop
|
|
152
|
+
val right = shape.right * scale + screenLeft
|
|
153
|
+
val bottom = shape.bottom * scale + screenTop
|
|
154
|
+
|
|
155
|
+
drawRect(
|
|
156
|
+
canvas,
|
|
157
|
+
left,
|
|
158
|
+
top,
|
|
159
|
+
right,
|
|
160
|
+
bottom,
|
|
161
|
+
shape.color,
|
|
162
|
+
shape.asset,
|
|
163
|
+
shape.progress,
|
|
164
|
+
)
|
|
83
165
|
}
|
|
84
|
-
}
|
|
85
166
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
167
|
+
is Shape.Circle -> {
|
|
168
|
+
val cx = shape.px * scale + screenLeft
|
|
169
|
+
val cy = shape.py * scale + screenTop
|
|
170
|
+
val radius = shape.radius * scale
|
|
171
|
+
|
|
172
|
+
drawCircle(
|
|
173
|
+
canvas,
|
|
174
|
+
cx,
|
|
175
|
+
cy,
|
|
176
|
+
radius,
|
|
177
|
+
shape.color,
|
|
178
|
+
shape.asset,
|
|
179
|
+
shape.progress,
|
|
180
|
+
)
|
|
93
181
|
}
|
|
94
182
|
}
|
|
95
|
-
|
|
96
|
-
null -> {}
|
|
97
183
|
}
|
|
98
184
|
}
|
|
99
185
|
holder.unlockCanvasAndPost(canvas)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
package com.margelo.nitro.rngine
|
|
2
|
+
|
|
3
|
+
sealed class Shape(
|
|
4
|
+
val color: Int,
|
|
5
|
+
val asset: Int,
|
|
6
|
+
val progress: Float?,
|
|
7
|
+
) {
|
|
8
|
+
class Rect(
|
|
9
|
+
val left: Float,
|
|
10
|
+
val right: Float,
|
|
11
|
+
val top: Float,
|
|
12
|
+
val bottom: Float,
|
|
13
|
+
color: Int,
|
|
14
|
+
asset: Int,
|
|
15
|
+
progress: Float?,
|
|
16
|
+
) : Shape(color, asset, progress)
|
|
17
|
+
|
|
18
|
+
class Circle(
|
|
19
|
+
val px: Float,
|
|
20
|
+
val py: Float,
|
|
21
|
+
val radius: Float,
|
|
22
|
+
color: Int,
|
|
23
|
+
asset: Int,
|
|
24
|
+
progress: Float?,
|
|
25
|
+
) : Shape(color, asset, progress)
|
|
26
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
package com.margelo.nitro.rngine
|
|
2
|
+
|
|
3
|
+
import android.util.Log
|
|
4
|
+
import java.nio.ByteBuffer
|
|
5
|
+
import java.nio.ByteOrder
|
|
6
|
+
|
|
7
|
+
object SnapshotSerializer {
|
|
8
|
+
fun decode(bytes: ByteArray): Snapshot {
|
|
9
|
+
val buffer = ByteBuffer.wrap(bytes).order(ByteOrder.nativeOrder())
|
|
10
|
+
|
|
11
|
+
val width = buffer.float
|
|
12
|
+
val height = buffer.float
|
|
13
|
+
val color = buffer.int
|
|
14
|
+
val asset = buffer.int
|
|
15
|
+
val progress = if (asset < 0) buffer.float else null
|
|
16
|
+
|
|
17
|
+
val screen = Screen(width, height, color, asset, progress)
|
|
18
|
+
val shapes = ArrayList<Shape>()
|
|
19
|
+
|
|
20
|
+
while (buffer.hasRemaining()) {
|
|
21
|
+
when (val shapeType = buffer.get().toInt()) {
|
|
22
|
+
0 -> {
|
|
23
|
+
val left = buffer.float
|
|
24
|
+
val right = buffer.float
|
|
25
|
+
val top = buffer.float
|
|
26
|
+
val bottom = buffer.float
|
|
27
|
+
|
|
28
|
+
val color = buffer.int
|
|
29
|
+
val asset = buffer.int
|
|
30
|
+
val progress = if (asset < 0) buffer.float else null
|
|
31
|
+
|
|
32
|
+
shapes.add(Shape.Rect(left, right, top, bottom, color, asset, progress))
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
1 -> {
|
|
36
|
+
val px = buffer.float
|
|
37
|
+
val py = buffer.float
|
|
38
|
+
val radius = buffer.float
|
|
39
|
+
|
|
40
|
+
val color = buffer.int
|
|
41
|
+
val asset = buffer.int
|
|
42
|
+
val progress = if (asset < 0) buffer.float else null
|
|
43
|
+
|
|
44
|
+
shapes.add(Shape.Circle(px, py, radius, color, asset, progress))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
else -> Log.e("SnapshotSerializer", "Unknown shapeType: $shapeType")
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return Snapshot(screen, shapes)
|
|
52
|
+
}
|
|
53
|
+
}
|