oriverse-engine 0.1.1 → 0.1.3
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/LICENSE.md +30 -30
- package/README.md +76 -76
- package/dist/AGENT_ONBOARDING.md +74 -74
- package/dist/CODEX_PROMPT.md +7 -7
- package/dist/GAME_AUTHORING.md +6 -6
- package/dist/examples/coin_collector.weave +70 -70
- package/dist/examples/dodge_blocks.weave +70 -70
- package/dist/examples/target_range.weave +82 -82
- package/dist/ktx_bridge.js +121 -121
- package/dist/ktx_lib.js +1 -5236
- package/dist/ktx_lib.wasm +0 -0
- package/dist/oriverse_wgpu.d.ts +40 -40
- package/dist/oriverse_wgpu.js +1005 -354
- package/dist/oriverse_wgpu_bg.wasm +0 -0
- package/dist/oriverse_wgpu_bg.wasm.d.ts +40 -40
- package/dist/snippets/oriverse_market_client-0cd3013288f3c49c/inline0.js +6 -0
- package/dist/snippets/oriverse_networking_shared-e43478064e11e46c/inline0.js +4 -1
- package/dist/snippets/oriverse_wgpu-255445ce6d9a0851/inline0.js +20 -58
- package/dist/snippets/oriverse_wgpu-255445ce6d9a0851/inline1.js +58 -19
- package/dist/starter/AGENTS.md +2 -2
- package/dist/starter/CLAUDE.md +2 -2
- package/dist/starter/game.html +5 -5
- package/dist/templates/game_cdn.html +5 -5
- package/dist/weave_documentation.txt +730 -4897
- package/package.json +18 -18
|
@@ -1,70 +1,70 @@
|
|
|
1
|
-
// Dodge the Falling Blocks — red cubes rain down; touching one ends the run. Press R to retry.
|
|
2
|
-
// Demonstrates: a hidden manager object, timed spawning with Timer, dynamic physics objects,
|
|
3
|
-
// cross-object variable writes (block -> manager), survival-seconds score, lose + restart flow.
|
|
4
|
-
// Movement uses the engine's default player controller (no #class player).
|
|
5
|
-
|
|
6
|
-
#class FallingBlock
|
|
7
|
-
var LifeTmr : Timer
|
|
8
|
-
event OnSpawned {
|
|
9
|
-
LifeTmr.StartCountDown(8) // despawn landed blocks so the arena stays playable
|
|
10
|
-
forever {
|
|
11
|
-
if LifeTmr.IsDone() {
|
|
12
|
-
Destroy()
|
|
13
|
-
}
|
|
14
|
-
var p = NearestPlayer()
|
|
15
|
-
if p.Exists() and SurfaceGapTo(p) < 5 {
|
|
16
|
-
NearestObjectWithTag(Tag.Manager).GameOver = true
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
#end
|
|
21
|
-
|
|
22
|
-
#class GameManager
|
|
23
|
-
var GameOver = false
|
|
24
|
-
var Score = 0
|
|
25
|
-
event OnPreSpawn {
|
|
26
|
-
AddTag(Tag.Manager)
|
|
27
|
-
}
|
|
28
|
-
event OnSpawned {
|
|
29
|
-
var secondTmr = Timer()
|
|
30
|
-
var dropTmr = Timer()
|
|
31
|
-
var scoreLabel = ResolveObjectByNameOnce("ScoreText")
|
|
32
|
-
var midLabel = ResolveObjectByNameOnce("MidText")
|
|
33
|
-
forever {
|
|
34
|
-
if GameOver {
|
|
35
|
-
midLabel.SetText("GAME OVER — survived " + Score + " s. Press R to retry")
|
|
36
|
-
continue
|
|
37
|
-
}
|
|
38
|
-
if secondTmr.IsDone() {
|
|
39
|
-
secondTmr.StartCountDown(1)
|
|
40
|
-
Score += 1
|
|
41
|
-
scoreLabel.SetText("Survived: " + Score + " s")
|
|
42
|
-
}
|
|
43
|
-
if dropTmr.IsDone() {
|
|
44
|
-
dropTmr.StartCountDown(0.35)
|
|
45
|
-
var pos = Position(RandomNumber(-900, 900), RandomNumber(-900, 900), 1300)
|
|
46
|
-
SpawnObject(SavedObject.block, pos)
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
event KeyboardDown[R] {
|
|
51
|
-
RestartGame()
|
|
52
|
-
}
|
|
53
|
-
#end
|
|
54
|
-
|
|
55
|
-
saved block {
|
|
56
|
-
physics block : FallingBlock { model = "cube" size = (120, 120, 120) color = (0.85, 0.25, 0.2) }
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
object Ground {
|
|
60
|
-
model = "cube"
|
|
61
|
-
position = (0, 0, -50)
|
|
62
|
-
size = (2200, 2200, 100)
|
|
63
|
-
color = (0.4, 0.42, 0.5)
|
|
64
|
-
}
|
|
65
|
-
display manager : GameManager { visible = false }
|
|
66
|
-
|
|
67
|
-
screenCanvas HUD {
|
|
68
|
-
textLabel ScoreText { offset = (20, 20) text = "Survived: 0 s" color = (1, 1, 1) }
|
|
69
|
-
textLabel MidText { align = (center, center) text = "" color = (1, 0.45, 0.35) }
|
|
70
|
-
}
|
|
1
|
+
// Dodge the Falling Blocks — red cubes rain down; touching one ends the run. Press R to retry.
|
|
2
|
+
// Demonstrates: a hidden manager object, timed spawning with Timer, dynamic physics objects,
|
|
3
|
+
// cross-object variable writes (block -> manager), survival-seconds score, lose + restart flow.
|
|
4
|
+
// Movement uses the engine's default player controller (no #class player).
|
|
5
|
+
|
|
6
|
+
#class FallingBlock
|
|
7
|
+
var LifeTmr : Timer
|
|
8
|
+
event OnSpawned {
|
|
9
|
+
LifeTmr.StartCountDown(8) // despawn landed blocks so the arena stays playable
|
|
10
|
+
forever {
|
|
11
|
+
if LifeTmr.IsDone() {
|
|
12
|
+
Destroy()
|
|
13
|
+
}
|
|
14
|
+
var p = NearestPlayer()
|
|
15
|
+
if p.Exists() and SurfaceGapTo(p) < 5 {
|
|
16
|
+
NearestObjectWithTag(Tag.Manager).GameOver = true
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
#end
|
|
21
|
+
|
|
22
|
+
#class GameManager
|
|
23
|
+
var GameOver = false
|
|
24
|
+
var Score = 0
|
|
25
|
+
event OnPreSpawn {
|
|
26
|
+
AddTag(Tag.Manager)
|
|
27
|
+
}
|
|
28
|
+
event OnSpawned {
|
|
29
|
+
var secondTmr = Timer()
|
|
30
|
+
var dropTmr = Timer()
|
|
31
|
+
var scoreLabel = ResolveObjectByNameOnce("ScoreText")
|
|
32
|
+
var midLabel = ResolveObjectByNameOnce("MidText")
|
|
33
|
+
forever {
|
|
34
|
+
if GameOver {
|
|
35
|
+
midLabel.SetText("GAME OVER — survived " + Score + " s. Press R to retry")
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
38
|
+
if secondTmr.IsDone() {
|
|
39
|
+
secondTmr.StartCountDown(1)
|
|
40
|
+
Score += 1
|
|
41
|
+
scoreLabel.SetText("Survived: " + Score + " s")
|
|
42
|
+
}
|
|
43
|
+
if dropTmr.IsDone() {
|
|
44
|
+
dropTmr.StartCountDown(0.35)
|
|
45
|
+
var pos = Position(RandomNumber(-900, 900), RandomNumber(-900, 900), 1300)
|
|
46
|
+
SpawnObject(SavedObject.block, pos)
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
event KeyboardDown[R] {
|
|
51
|
+
RestartGame()
|
|
52
|
+
}
|
|
53
|
+
#end
|
|
54
|
+
|
|
55
|
+
saved block {
|
|
56
|
+
physics block : FallingBlock { model = "cube" size = (120, 120, 120) color = (0.85, 0.25, 0.2) }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
object Ground {
|
|
60
|
+
model = "cube"
|
|
61
|
+
position = (0, 0, -50)
|
|
62
|
+
size = (2200, 2200, 100)
|
|
63
|
+
color = (0.4, 0.42, 0.5)
|
|
64
|
+
}
|
|
65
|
+
display manager : GameManager { visible = false }
|
|
66
|
+
|
|
67
|
+
screenCanvas HUD {
|
|
68
|
+
textLabel ScoreText { offset = (20, 20) text = "Survived: 0 s" color = (1, 1, 1) }
|
|
69
|
+
textLabel MidText { align = (center, center) text = "" color = (1, 0.45, 0.35) }
|
|
70
|
+
}
|
|
@@ -1,82 +1,82 @@
|
|
|
1
|
-
// Target Range — aim at the floating spheres and left-click to score. 30-second round, R restarts.
|
|
2
|
-
// Demonstrates: a custom #class player (movement + jump + click-to-shoot with the crosshair ray),
|
|
3
|
-
// user-defined funcs called cross-object, TeleportTo respawn, countdown round timer, HUD score.
|
|
4
|
-
|
|
5
|
-
#class player
|
|
6
|
-
event OnSpawned {
|
|
7
|
-
forever {
|
|
8
|
-
var dir = GetMoveVectorCamera()
|
|
9
|
-
MoveInDirectionContinuouslyFacing(dir, 900)
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
event
|
|
13
|
-
if IsOnGround() {
|
|
14
|
-
Jump(1000)
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
event ActionDownByThisPlayer[Primary] {
|
|
18
|
-
var t = GetMouseTargetObjectWithTag(Tag.Target)
|
|
19
|
-
if t.Exists() and not NearestObjectWithTag(Tag.Manager).RoundOver {
|
|
20
|
-
t.Pop()
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
#end
|
|
24
|
-
|
|
25
|
-
#class Target
|
|
26
|
-
func Pop() {
|
|
27
|
-
SpawnFloatingText("+1", Vector(0.3, 1, 0.4))
|
|
28
|
-
NearestObjectWithTag(Tag.Manager).Hits += 1
|
|
29
|
-
TeleportTo(Position(RandomNumber(-1200, 1200), RandomNumber(500, 1600), RandomNumber(100, 500)))
|
|
30
|
-
}
|
|
31
|
-
event OnPreSpawn {
|
|
32
|
-
AddTag(Tag.Target)
|
|
33
|
-
}
|
|
34
|
-
#end
|
|
35
|
-
|
|
36
|
-
#class GameManager
|
|
37
|
-
var Hits = 0
|
|
38
|
-
var TimeLeft = 30
|
|
39
|
-
var RoundOver = false
|
|
40
|
-
event OnPreSpawn {
|
|
41
|
-
AddTag(Tag.Manager)
|
|
42
|
-
}
|
|
43
|
-
event OnSpawned {
|
|
44
|
-
var secondTmr = Timer()
|
|
45
|
-
secondTmr.StartCountDown(1)
|
|
46
|
-
var scoreLabel = ResolveObjectByNameOnce("ScoreText")
|
|
47
|
-
var midLabel = ResolveObjectByNameOnce("MidText")
|
|
48
|
-
forever {
|
|
49
|
-
scoreLabel.SetText("Hits: " + Hits + " Time: " + TimeLeft)
|
|
50
|
-
if RoundOver {
|
|
51
|
-
continue
|
|
52
|
-
}
|
|
53
|
-
if secondTmr.IsDone() {
|
|
54
|
-
secondTmr.StartCountDown(1)
|
|
55
|
-
TimeLeft -= 1
|
|
56
|
-
if TimeLeft <= 0 {
|
|
57
|
-
RoundOver = true
|
|
58
|
-
midLabel.SetText("TIME! Final score: " + Hits + " — press R to retry")
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
event KeyboardDown[R] {
|
|
64
|
-
RestartGame()
|
|
65
|
-
}
|
|
66
|
-
#end
|
|
67
|
-
|
|
68
|
-
object Ground {
|
|
69
|
-
model = "cube"
|
|
70
|
-
position = (0, 0, -50)
|
|
71
|
-
size = (4000, 4000, 100)
|
|
72
|
-
color = (0.45, 0.4, 0.35)
|
|
73
|
-
}
|
|
74
|
-
object TargetA : Target { model = "sphere" position = (-600, 900, 250) size = 90 color = (1, 0.3, 0.3) }
|
|
75
|
-
object TargetB : Target { model = "sphere" position = (0, 1200, 350) size = 90 color = (1, 0.3, 0.3) }
|
|
76
|
-
object TargetC : Target { model = "sphere" position = (700, 800, 200) size = 90 color = (1, 0.3, 0.3) }
|
|
77
|
-
display manager : GameManager { visible = false }
|
|
78
|
-
|
|
79
|
-
screenCanvas HUD {
|
|
80
|
-
textLabel ScoreText { offset = (20, 20) text = "Hits: 0 Time: 30" color = (1, 1, 0.85) }
|
|
81
|
-
textLabel MidText { align = (center, center) text = "" color = (0.4, 1, 0.5) }
|
|
82
|
-
}
|
|
1
|
+
// Target Range — aim at the floating spheres and left-click to score. 30-second round, R restarts.
|
|
2
|
+
// Demonstrates: a custom #class player (movement + jump + click-to-shoot with the crosshair ray),
|
|
3
|
+
// user-defined funcs called cross-object, TeleportTo respawn, countdown round timer, HUD score.
|
|
4
|
+
|
|
5
|
+
#class player
|
|
6
|
+
event OnSpawned {
|
|
7
|
+
forever {
|
|
8
|
+
var dir = GetMoveVectorCamera()
|
|
9
|
+
MoveInDirectionContinuouslyFacing(dir, 900)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
event ActionDownByThisPlayer[Jump] {
|
|
13
|
+
if IsOnGround() {
|
|
14
|
+
Jump(1000)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
event ActionDownByThisPlayer[Primary] {
|
|
18
|
+
var t = GetMouseTargetObjectWithTag(Tag.Target)
|
|
19
|
+
if t.Exists() and not NearestObjectWithTag(Tag.Manager).RoundOver {
|
|
20
|
+
t.Pop()
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
#end
|
|
24
|
+
|
|
25
|
+
#class Target
|
|
26
|
+
func Pop() {
|
|
27
|
+
SpawnFloatingText("+1", Vector(0.3, 1, 0.4))
|
|
28
|
+
NearestObjectWithTag(Tag.Manager).Hits += 1
|
|
29
|
+
TeleportTo(Position(RandomNumber(-1200, 1200), RandomNumber(500, 1600), RandomNumber(100, 500)))
|
|
30
|
+
}
|
|
31
|
+
event OnPreSpawn {
|
|
32
|
+
AddTag(Tag.Target)
|
|
33
|
+
}
|
|
34
|
+
#end
|
|
35
|
+
|
|
36
|
+
#class GameManager
|
|
37
|
+
var Hits = 0
|
|
38
|
+
var TimeLeft = 30
|
|
39
|
+
var RoundOver = false
|
|
40
|
+
event OnPreSpawn {
|
|
41
|
+
AddTag(Tag.Manager)
|
|
42
|
+
}
|
|
43
|
+
event OnSpawned {
|
|
44
|
+
var secondTmr = Timer()
|
|
45
|
+
secondTmr.StartCountDown(1)
|
|
46
|
+
var scoreLabel = ResolveObjectByNameOnce("ScoreText")
|
|
47
|
+
var midLabel = ResolveObjectByNameOnce("MidText")
|
|
48
|
+
forever {
|
|
49
|
+
scoreLabel.SetText("Hits: " + Hits + " Time: " + TimeLeft)
|
|
50
|
+
if RoundOver {
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
if secondTmr.IsDone() {
|
|
54
|
+
secondTmr.StartCountDown(1)
|
|
55
|
+
TimeLeft -= 1
|
|
56
|
+
if TimeLeft <= 0 {
|
|
57
|
+
RoundOver = true
|
|
58
|
+
midLabel.SetText("TIME! Final score: " + Hits + " — press R to retry")
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
event KeyboardDown[R] {
|
|
64
|
+
RestartGame()
|
|
65
|
+
}
|
|
66
|
+
#end
|
|
67
|
+
|
|
68
|
+
object Ground {
|
|
69
|
+
model = "cube"
|
|
70
|
+
position = (0, 0, -50)
|
|
71
|
+
size = (4000, 4000, 100)
|
|
72
|
+
color = (0.45, 0.4, 0.35)
|
|
73
|
+
}
|
|
74
|
+
object TargetA : Target { model = "sphere" position = (-600, 900, 250) size = 90 color = (1, 0.3, 0.3) }
|
|
75
|
+
object TargetB : Target { model = "sphere" position = (0, 1200, 350) size = 90 color = (1, 0.3, 0.3) }
|
|
76
|
+
object TargetC : Target { model = "sphere" position = (700, 800, 200) size = 90 color = (1, 0.3, 0.3) }
|
|
77
|
+
display manager : GameManager { visible = false }
|
|
78
|
+
|
|
79
|
+
screenCanvas HUD {
|
|
80
|
+
textLabel ScoreText { offset = (20, 20) text = "Hits: 0 Time: 30" color = (1, 1, 0.85) }
|
|
81
|
+
textLabel MidText { align = (center, center) text = "" color = (0.4, 1, 0.5) }
|
|
82
|
+
}
|
package/dist/ktx_bridge.js
CHANGED
|
@@ -1,121 +1,121 @@
|
|
|
1
|
-
// ktx_bridge.js
|
|
2
|
-
try { console.log("ktx_bridge sees Module:", typeof Module !== 'undefined' ? Module : undefined); } catch (_) {}
|
|
3
|
-
|
|
4
|
-
// Helper views that do not require EXPORTED_RUNTIME_METHODS
|
|
5
|
-
let __ktx_warned_fallback = false;
|
|
6
|
-
function __ktx_warn_fallback_once() {
|
|
7
|
-
if (!__ktx_warned_fallback) {
|
|
8
|
-
console.warn("ktx_bridge: using wasmMemory fallback (HEAPU8/HEAPU32 not exported)");
|
|
9
|
-
__ktx_warned_fallback = true;
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
function heapU8() {
|
|
13
|
-
if (Module.HEAPU8) return Module.HEAPU8;
|
|
14
|
-
const mem = Module.wasmMemory || (typeof wasmMemory !== 'undefined' ? wasmMemory : undefined);
|
|
15
|
-
if (!mem) throw new Error("WASM memory not available (u8)");
|
|
16
|
-
__ktx_warn_fallback_once();
|
|
17
|
-
return new Uint8Array(mem.buffer);
|
|
18
|
-
}
|
|
19
|
-
function heapU32() {
|
|
20
|
-
if (Module.HEAPU32) return Module.HEAPU32;
|
|
21
|
-
const mem = Module.wasmMemory || (typeof wasmMemory !== 'undefined' ? wasmMemory : undefined);
|
|
22
|
-
if (!mem) throw new Error("WASM memory not available (u32)");
|
|
23
|
-
__ktx_warn_fallback_once();
|
|
24
|
-
return new Uint32Array(mem.buffer);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Extract a WasmTextureDataC from a pointer, read its fields, and free it.
|
|
29
|
-
*
|
|
30
|
-
* @param {number} wasmTextureDataCPtr pointer to a WasmTextureDataC in WASM memory
|
|
31
|
-
*/
|
|
32
|
-
function extractWasmTextureData(wasmTextureDataCPtr) {
|
|
33
|
-
if (wasmTextureDataCPtr === 0) {
|
|
34
|
-
throw new Error("KTX decode returned a null pointer");
|
|
35
|
-
}
|
|
36
|
-
const base = wasmTextureDataCPtr >>> 2; // pointer in i32 indices
|
|
37
|
-
const u32 = heapU32();
|
|
38
|
-
const width = u32[base + 0];
|
|
39
|
-
const height = u32[base + 1];
|
|
40
|
-
const faceCount = u32[base + 2];
|
|
41
|
-
const mipCount = u32[base + 3];
|
|
42
|
-
const dataPtr = u32[base + 4];
|
|
43
|
-
const dataLen = u32[base + 5];
|
|
44
|
-
const offsetsPtr = u32[base + 6];
|
|
45
|
-
|
|
46
|
-
// Copy the texture bytes
|
|
47
|
-
const u8 = heapU8();
|
|
48
|
-
const textureData = u8.slice(dataPtr, dataPtr + dataLen);
|
|
49
|
-
|
|
50
|
-
// Flattened offsets array, if any
|
|
51
|
-
const totalOffsets = faceCount * mipCount;
|
|
52
|
-
const faceToMipOffsets = u32.slice(
|
|
53
|
-
offsetsPtr >>> 2,
|
|
54
|
-
(offsetsPtr >>> 2) + totalOffsets
|
|
55
|
-
);
|
|
56
|
-
|
|
57
|
-
// Free the struct
|
|
58
|
-
Module.ccall("wasm_free_texture_data", null, ["number"], [wasmTextureDataCPtr]);
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
width,
|
|
62
|
-
height,
|
|
63
|
-
faceCount,
|
|
64
|
-
mipCount,
|
|
65
|
-
textureData,
|
|
66
|
-
faceToMipOffsets,
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* loadAndTranscodeKtxTexture
|
|
72
|
-
* Calls the WASM function "wasm_load_and_transcode_ktx_texture"
|
|
73
|
-
* with a given format string (e.g. "bc1", "bc1-srgb" or "bc5").
|
|
74
|
-
*
|
|
75
|
-
* @param {Uint8Array} ktxData
|
|
76
|
-
* @param {string} formatStr
|
|
77
|
-
*/
|
|
78
|
-
window.loadAndTranscodeKtxTexture = function(ktxData, formatStr) {
|
|
79
|
-
const ktxPtr = Module._malloc(ktxData.length);
|
|
80
|
-
heapU8().set(ktxData, ktxPtr);
|
|
81
|
-
|
|
82
|
-
// Allocate memory for the format string
|
|
83
|
-
const enc = new TextEncoder();
|
|
84
|
-
const fmtBytes = enc.encode(formatStr);
|
|
85
|
-
const fmtPtr = Module._malloc(fmtBytes.length);
|
|
86
|
-
heapU8().set(fmtBytes, fmtPtr);
|
|
87
|
-
|
|
88
|
-
// Call the Emscripten-compiled function
|
|
89
|
-
const wasmTextureDataCPtr = Module.ccall(
|
|
90
|
-
"wasm_load_and_transcode_ktx_texture",
|
|
91
|
-
"number",
|
|
92
|
-
["number","number","number","number"],
|
|
93
|
-
[ktxPtr, ktxData.length, fmtPtr, fmtBytes.length]
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
// Free our input buffers
|
|
97
|
-
Module._free(ktxPtr);
|
|
98
|
-
Module._free(fmtPtr);
|
|
99
|
-
|
|
100
|
-
return extractWasmTextureData(wasmTextureDataCPtr);
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* loadKtxCubemap
|
|
105
|
-
* @param {Uint8Array} ktxData
|
|
106
|
-
*/
|
|
107
|
-
window.loadKtxCubemap = function(ktxData) {
|
|
108
|
-
const ktxPtr = Module._malloc(ktxData.length);
|
|
109
|
-
heapU8().set(ktxData, ktxPtr);
|
|
110
|
-
|
|
111
|
-
const wasmTextureDataCPtr = Module.ccall(
|
|
112
|
-
"wasm_load_ktx_cubemap",
|
|
113
|
-
"number",
|
|
114
|
-
["number","number"],
|
|
115
|
-
[ktxPtr, ktxData.length]
|
|
116
|
-
);
|
|
117
|
-
|
|
118
|
-
Module._free(ktxPtr);
|
|
119
|
-
|
|
120
|
-
return extractWasmTextureData(wasmTextureDataCPtr);
|
|
121
|
-
};
|
|
1
|
+
// ktx_bridge.js
|
|
2
|
+
try { console.log("ktx_bridge sees Module:", typeof Module !== 'undefined' ? Module : undefined); } catch (_) {}
|
|
3
|
+
|
|
4
|
+
// Helper views that do not require EXPORTED_RUNTIME_METHODS
|
|
5
|
+
let __ktx_warned_fallback = false;
|
|
6
|
+
function __ktx_warn_fallback_once() {
|
|
7
|
+
if (!__ktx_warned_fallback) {
|
|
8
|
+
console.warn("ktx_bridge: using wasmMemory fallback (HEAPU8/HEAPU32 not exported)");
|
|
9
|
+
__ktx_warned_fallback = true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function heapU8() {
|
|
13
|
+
if (Module.HEAPU8) return Module.HEAPU8;
|
|
14
|
+
const mem = Module.wasmMemory || (typeof wasmMemory !== 'undefined' ? wasmMemory : undefined);
|
|
15
|
+
if (!mem) throw new Error("WASM memory not available (u8)");
|
|
16
|
+
__ktx_warn_fallback_once();
|
|
17
|
+
return new Uint8Array(mem.buffer);
|
|
18
|
+
}
|
|
19
|
+
function heapU32() {
|
|
20
|
+
if (Module.HEAPU32) return Module.HEAPU32;
|
|
21
|
+
const mem = Module.wasmMemory || (typeof wasmMemory !== 'undefined' ? wasmMemory : undefined);
|
|
22
|
+
if (!mem) throw new Error("WASM memory not available (u32)");
|
|
23
|
+
__ktx_warn_fallback_once();
|
|
24
|
+
return new Uint32Array(mem.buffer);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Extract a WasmTextureDataC from a pointer, read its fields, and free it.
|
|
29
|
+
*
|
|
30
|
+
* @param {number} wasmTextureDataCPtr pointer to a WasmTextureDataC in WASM memory
|
|
31
|
+
*/
|
|
32
|
+
function extractWasmTextureData(wasmTextureDataCPtr) {
|
|
33
|
+
if (wasmTextureDataCPtr === 0) {
|
|
34
|
+
throw new Error("KTX decode returned a null pointer");
|
|
35
|
+
}
|
|
36
|
+
const base = wasmTextureDataCPtr >>> 2; // pointer in i32 indices
|
|
37
|
+
const u32 = heapU32();
|
|
38
|
+
const width = u32[base + 0];
|
|
39
|
+
const height = u32[base + 1];
|
|
40
|
+
const faceCount = u32[base + 2];
|
|
41
|
+
const mipCount = u32[base + 3];
|
|
42
|
+
const dataPtr = u32[base + 4];
|
|
43
|
+
const dataLen = u32[base + 5];
|
|
44
|
+
const offsetsPtr = u32[base + 6];
|
|
45
|
+
|
|
46
|
+
// Copy the texture bytes
|
|
47
|
+
const u8 = heapU8();
|
|
48
|
+
const textureData = u8.slice(dataPtr, dataPtr + dataLen);
|
|
49
|
+
|
|
50
|
+
// Flattened offsets array, if any
|
|
51
|
+
const totalOffsets = faceCount * mipCount;
|
|
52
|
+
const faceToMipOffsets = u32.slice(
|
|
53
|
+
offsetsPtr >>> 2,
|
|
54
|
+
(offsetsPtr >>> 2) + totalOffsets
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
// Free the struct
|
|
58
|
+
Module.ccall("wasm_free_texture_data", null, ["number"], [wasmTextureDataCPtr]);
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
width,
|
|
62
|
+
height,
|
|
63
|
+
faceCount,
|
|
64
|
+
mipCount,
|
|
65
|
+
textureData,
|
|
66
|
+
faceToMipOffsets,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* loadAndTranscodeKtxTexture
|
|
72
|
+
* Calls the WASM function "wasm_load_and_transcode_ktx_texture"
|
|
73
|
+
* with a given format string (e.g. "bc1", "bc1-srgb" or "bc5").
|
|
74
|
+
*
|
|
75
|
+
* @param {Uint8Array} ktxData
|
|
76
|
+
* @param {string} formatStr
|
|
77
|
+
*/
|
|
78
|
+
window.loadAndTranscodeKtxTexture = function(ktxData, formatStr) {
|
|
79
|
+
const ktxPtr = Module._malloc(ktxData.length);
|
|
80
|
+
heapU8().set(ktxData, ktxPtr);
|
|
81
|
+
|
|
82
|
+
// Allocate memory for the format string
|
|
83
|
+
const enc = new TextEncoder();
|
|
84
|
+
const fmtBytes = enc.encode(formatStr);
|
|
85
|
+
const fmtPtr = Module._malloc(fmtBytes.length);
|
|
86
|
+
heapU8().set(fmtBytes, fmtPtr);
|
|
87
|
+
|
|
88
|
+
// Call the Emscripten-compiled function
|
|
89
|
+
const wasmTextureDataCPtr = Module.ccall(
|
|
90
|
+
"wasm_load_and_transcode_ktx_texture",
|
|
91
|
+
"number",
|
|
92
|
+
["number","number","number","number"],
|
|
93
|
+
[ktxPtr, ktxData.length, fmtPtr, fmtBytes.length]
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
// Free our input buffers
|
|
97
|
+
Module._free(ktxPtr);
|
|
98
|
+
Module._free(fmtPtr);
|
|
99
|
+
|
|
100
|
+
return extractWasmTextureData(wasmTextureDataCPtr);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* loadKtxCubemap
|
|
105
|
+
* @param {Uint8Array} ktxData
|
|
106
|
+
*/
|
|
107
|
+
window.loadKtxCubemap = function(ktxData) {
|
|
108
|
+
const ktxPtr = Module._malloc(ktxData.length);
|
|
109
|
+
heapU8().set(ktxData, ktxPtr);
|
|
110
|
+
|
|
111
|
+
const wasmTextureDataCPtr = Module.ccall(
|
|
112
|
+
"wasm_load_ktx_cubemap",
|
|
113
|
+
"number",
|
|
114
|
+
["number","number"],
|
|
115
|
+
[ktxPtr, ktxData.length]
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
Module._free(ktxPtr);
|
|
119
|
+
|
|
120
|
+
return extractWasmTextureData(wasmTextureDataCPtr);
|
|
121
|
+
};
|