pixospritz-core 0.10.1 → 1.0.1
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 +36 -286
- package/dist/bundle.js +13 -3
- package/dist/bundle.js.map +1 -1
- package/dist/style.css +1 -0
- package/package.json +43 -44
- package/src/components/WebGLView.jsx +318 -0
- package/src/css/pixos.css +372 -0
- package/src/engine/actions/animate.js +41 -0
- package/src/engine/actions/changezone.js +135 -0
- package/src/engine/actions/chat.js +109 -0
- package/src/engine/actions/dialogue.js +90 -0
- package/src/engine/actions/face.js +22 -0
- package/src/engine/actions/greeting.js +28 -0
- package/src/engine/actions/interact.js +86 -0
- package/src/engine/actions/move.js +67 -0
- package/src/engine/actions/patrol.js +109 -0
- package/src/engine/actions/prompt.js +185 -0
- package/src/engine/actions/script.js +42 -0
- package/src/engine/core/audio/AudioSystem.js +543 -0
- package/src/engine/core/cutscene/PxcPlayer.js +956 -0
- package/src/engine/core/cutscene/manager.js +243 -0
- package/src/engine/core/database/index.js +75 -0
- package/src/engine/core/debug/index.js +371 -0
- package/src/engine/core/hud/index.js +765 -0
- package/src/engine/core/index.js +540 -0
- package/src/engine/core/input/gamepad/Controller.js +71 -0
- package/src/engine/core/input/gamepad/ControllerButtons.js +231 -0
- package/src/engine/core/input/gamepad/ControllerStick.js +173 -0
- package/src/engine/core/input/gamepad/index.js +592 -0
- package/src/engine/core/input/keyboard.js +196 -0
- package/src/engine/core/input/manager.js +485 -0
- package/src/engine/core/input/mouse.js +203 -0
- package/src/engine/core/input/touch.js +175 -0
- package/src/engine/core/mode/manager.js +199 -0
- package/src/engine/core/net/manager.js +535 -0
- package/src/engine/core/queue/action.js +83 -0
- package/src/engine/core/queue/event.js +82 -0
- package/src/engine/core/queue/index.js +44 -0
- package/src/engine/core/queue/loadable.js +33 -0
- package/src/engine/core/render/CameraEffects.js +494 -0
- package/src/engine/core/render/FrustumCuller.js +417 -0
- package/src/engine/core/render/LODManager.js +285 -0
- package/src/engine/core/render/ParticleManager.js +529 -0
- package/src/engine/core/render/TextureAtlas.js +465 -0
- package/src/engine/core/render/camera.js +338 -0
- package/src/engine/core/render/light.js +197 -0
- package/src/engine/core/render/manager.js +1079 -0
- package/src/engine/core/render/shaders.js +110 -0
- package/src/engine/core/render/skybox.js +342 -0
- package/src/engine/core/resource/manager.js +133 -0
- package/src/engine/core/resource/object.js +611 -0
- package/src/engine/core/resource/texture.js +103 -0
- package/src/engine/core/resource/tileset.js +177 -0
- package/src/engine/core/scene/avatar.js +215 -0
- package/src/engine/core/scene/speech.js +138 -0
- package/src/engine/core/scene/sprite.js +702 -0
- package/src/engine/core/scene/spritz.js +189 -0
- package/src/engine/core/scene/world.js +681 -0
- package/src/engine/core/scene/zone.js +1167 -0
- package/src/engine/core/store/index.js +110 -0
- package/src/engine/dynamic/animatedSprite.js +64 -0
- package/src/engine/dynamic/animatedTile.js +98 -0
- package/src/engine/dynamic/avatar.js +110 -0
- package/src/engine/dynamic/map.js +174 -0
- package/src/engine/dynamic/sprite.js +255 -0
- package/src/engine/dynamic/spritz.js +119 -0
- package/src/engine/events/EventSystem.js +609 -0
- package/src/engine/events/camera.js +142 -0
- package/src/engine/events/chat.js +75 -0
- package/src/engine/events/menu.js +186 -0
- package/src/engine/scripting/CallbackManager.js +514 -0
- package/src/engine/scripting/PixoScriptInterpreter.js +81 -0
- package/src/engine/scripting/PixoScriptLibrary.js +704 -0
- package/src/engine/shaders/effects/index.js +450 -0
- package/src/engine/shaders/fs.js +222 -0
- package/src/engine/shaders/particles/fs.js +41 -0
- package/src/engine/shaders/particles/vs.js +61 -0
- package/src/engine/shaders/picker/fs.js +34 -0
- package/src/engine/shaders/picker/init.js +62 -0
- package/src/engine/shaders/picker/vs.js +42 -0
- package/src/engine/shaders/pxsl/README.md +250 -0
- package/src/engine/shaders/pxsl/index.js +25 -0
- package/src/engine/shaders/pxsl/library.js +608 -0
- package/src/engine/shaders/pxsl/manager.js +338 -0
- package/src/engine/shaders/pxsl/specification.js +363 -0
- package/src/engine/shaders/pxsl/transpiler.js +753 -0
- package/src/engine/shaders/skybox/cosmic/fs.js +147 -0
- package/src/engine/shaders/skybox/cosmic/vs.js +23 -0
- package/src/engine/shaders/skybox/matrix/fs.js +127 -0
- package/src/engine/shaders/skybox/matrix/vs.js +23 -0
- package/src/engine/shaders/skybox/morning/fs.js +109 -0
- package/src/engine/shaders/skybox/morning/vs.js +23 -0
- package/src/engine/shaders/skybox/neon/fs.js +119 -0
- package/src/engine/shaders/skybox/neon/vs.js +23 -0
- package/src/engine/shaders/skybox/sky/fs.js +114 -0
- package/src/engine/shaders/skybox/sky/vs.js +23 -0
- package/src/engine/shaders/skybox/sunset/fs.js +101 -0
- package/src/engine/shaders/skybox/sunset/vs.js +23 -0
- package/src/engine/shaders/transition/blur/fs.js +42 -0
- package/src/engine/shaders/transition/blur/vs.js +26 -0
- package/src/engine/shaders/transition/cross/fs.js +36 -0
- package/src/engine/shaders/transition/cross/vs.js +26 -0
- package/src/engine/shaders/transition/crossBlur/fs.js +41 -0
- package/src/engine/shaders/transition/crossBlur/vs.js +25 -0
- package/src/engine/shaders/transition/dissolve/fs.js +78 -0
- package/src/engine/shaders/transition/dissolve/vs.js +24 -0
- package/src/engine/shaders/transition/fade/fs.js +31 -0
- package/src/engine/shaders/transition/fade/vs.js +27 -0
- package/src/engine/shaders/transition/iris/fs.js +52 -0
- package/src/engine/shaders/transition/iris/vs.js +24 -0
- package/src/engine/shaders/transition/pixelate/fs.js +44 -0
- package/src/engine/shaders/transition/pixelate/vs.js +24 -0
- package/src/engine/shaders/transition/slide/fs.js +53 -0
- package/src/engine/shaders/transition/slide/vs.js +24 -0
- package/src/engine/shaders/transition/swirl/fs.js +39 -0
- package/src/engine/shaders/transition/swirl/vs.js +26 -0
- package/src/engine/shaders/transition/wipe/fs.js +50 -0
- package/src/engine/shaders/transition/wipe/vs.js +24 -0
- package/src/engine/shaders/vs.js +60 -0
- package/src/engine/utils/CameraController.js +506 -0
- package/src/engine/utils/ObjHelper.js +551 -0
- package/src/engine/utils/debug-logger.js +110 -0
- package/src/engine/utils/enums.js +305 -0
- package/src/engine/utils/generator.js +156 -0
- package/src/engine/utils/index.js +21 -0
- package/src/engine/utils/loaders/ActionLoader.js +77 -0
- package/src/engine/utils/loaders/AudioLoader.js +157 -0
- package/src/engine/utils/loaders/EventLoader.js +66 -0
- package/src/engine/utils/loaders/ObjectLoader.js +67 -0
- package/src/engine/utils/loaders/SpriteLoader.js +77 -0
- package/src/engine/utils/loaders/TilesetLoader.js +103 -0
- package/src/engine/utils/loaders/index.js +21 -0
- package/src/engine/utils/math/matrix4.js +367 -0
- package/src/engine/utils/math/vector.js +458 -0
- package/src/engine/utils/obj/_old_js/index.js +46 -0
- package/src/engine/utils/obj/_old_js/layout.js +308 -0
- package/src/engine/utils/obj/_old_js/material.js +711 -0
- package/src/engine/utils/obj/_old_js/mesh.js +761 -0
- package/src/engine/utils/obj/_old_js/utils.js +647 -0
- package/src/engine/utils/obj/index.js +24 -0
- package/src/engine/utils/obj/js/index.js +277 -0
- package/src/engine/utils/obj/js/loader.js +232 -0
- package/src/engine/utils/obj/layout.js +246 -0
- package/src/engine/utils/obj/material.js +665 -0
- package/src/engine/utils/obj/mesh.js +657 -0
- package/src/engine/utils/obj/ts/index.ts +72 -0
- package/src/engine/utils/obj/ts/layout.ts +265 -0
- package/src/engine/utils/obj/ts/material.ts +760 -0
- package/src/engine/utils/obj/ts/mesh.ts +785 -0
- package/src/engine/utils/obj/ts/utils.ts +501 -0
- package/src/engine/utils/obj/utils.js +428 -0
- package/src/engine/utils/resources.js +18 -0
- package/src/index.jsx +55 -0
- package/src/spritz/player.js +18 -0
- package/src/spritz/readme.md +18 -0
- package/LICENSE +0 -437
- package/dist/bundle.js.LICENSE.txt +0 -31
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
/* *\
|
|
2
|
+
** ----------------------------------------------- **
|
|
3
|
+
** Calliope - Pixos Game Engine **
|
|
4
|
+
** ----------------------------------------------- **
|
|
5
|
+
** Copyright (c) 2020-2025 - Kyle Derby MacInnis **
|
|
6
|
+
** **
|
|
7
|
+
** Any unauthorized distribution or transfer **
|
|
8
|
+
** of this work is strictly prohibited. **
|
|
9
|
+
** **
|
|
10
|
+
** All Rights Reserved. **
|
|
11
|
+
** ----------------------------------------------- **
|
|
12
|
+
\* */
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Runs all updates for debug information.
|
|
16
|
+
* @param {import('../index.js').default} self - The engine core instance.
|
|
17
|
+
*/
|
|
18
|
+
import { create, set, translate, rotate } from '../../utils/math/matrix4.js';
|
|
19
|
+
import { Vector } from '../../utils/math/vector.js';
|
|
20
|
+
|
|
21
|
+
export const updateDebugInformation = (self) => {
|
|
22
|
+
updateWebglDebugInformation(self);
|
|
23
|
+
updateFlagDebugInformation(self);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Updates WebGL debug information panel.
|
|
28
|
+
* @param {import('../index.js').default} self - The engine core instance.
|
|
29
|
+
*/
|
|
30
|
+
export const updateWebglDebugInformation = (self) => {
|
|
31
|
+
if (self.showWebglDebug && self.webglDebugDiv) {
|
|
32
|
+
const now = (typeof performance !== 'undefined' ? performance.now() : Date.now());
|
|
33
|
+
const delta = now - self.lastDebugTime;
|
|
34
|
+
const fps = delta > 0 ? (1000.0 / delta).toFixed(1) : '0';
|
|
35
|
+
self.lastDebugTime = now;
|
|
36
|
+
|
|
37
|
+
const gl = self.gl;
|
|
38
|
+
let renderer = '';
|
|
39
|
+
let vendor = '';
|
|
40
|
+
let version = '';
|
|
41
|
+
if (gl) {
|
|
42
|
+
try {
|
|
43
|
+
renderer = gl.getParameter(gl.RENDERER);
|
|
44
|
+
vendor = gl.getParameter(gl.VENDOR);
|
|
45
|
+
version = gl.getParameter(gl.VERSION);
|
|
46
|
+
} catch (e) {
|
|
47
|
+
// WebGL context may be lost or parameters unavailable
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const debug = self.renderManager.debug || {};
|
|
52
|
+
self.webglDebugDiv.innerHTML =
|
|
53
|
+
'FPS: ' + fps + '<br>' +
|
|
54
|
+
'Tiles Drawn: ' + (debug.tilesDrawn || 0) + '<br>' +
|
|
55
|
+
'Sprites Drawn: ' + (debug.spritesDrawn || 0) + '<br>' +
|
|
56
|
+
'Objects Drawn: ' + (debug.objectsDrawn || 0) + '<br>' +
|
|
57
|
+
'Renderer: ' + renderer + '<br>' +
|
|
58
|
+
'Vendor: ' + vendor + '<br>' +
|
|
59
|
+
'GL Version: ' + version;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Updates flag debug information based on latest values.
|
|
65
|
+
* @param {import('../index.js').default} self - The engine core instance.
|
|
66
|
+
*/
|
|
67
|
+
export const updateFlagDebugInformation = (self) => {
|
|
68
|
+
if (self.showFlagDebug && self.flagDebugDiv) {
|
|
69
|
+
self.store.set('Debug::Flag::UpdateTime', Date.now());
|
|
70
|
+
const flags = self.store.all();
|
|
71
|
+
console.log({ self, keys: JSON.stringify(flags), store: self.store.keys() });
|
|
72
|
+
const data = Object.keys(flags).map((key) => {
|
|
73
|
+
return '' + key + ': ' + JSON.stringify(flags[key]) + '<br>'
|
|
74
|
+
});
|
|
75
|
+
self.flagDebugDiv.innerHTML = 'FLAGS:<br>' + data.join('');
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Attaches flag debug information window to the top-right corner.
|
|
81
|
+
* @param {import('../index.js').default} self - The engine core instance.
|
|
82
|
+
*/
|
|
83
|
+
export const attachFlagDebugInfo = (self) => {
|
|
84
|
+
const div = document.createElement('div');
|
|
85
|
+
div.style.position = 'absolute';
|
|
86
|
+
div.style.top = '0';
|
|
87
|
+
div.style.right = '0';
|
|
88
|
+
div.style.background = 'rgba(0, 0, 0, 0.6)';
|
|
89
|
+
div.style.color = '#0f0';
|
|
90
|
+
div.style.padding = '4px';
|
|
91
|
+
div.style.fontFamily = 'monospace';
|
|
92
|
+
div.style.fontSize = '12px';
|
|
93
|
+
div.style.zIndex = '10000';
|
|
94
|
+
div.style.pointerEvents = 'none';
|
|
95
|
+
div.style.display = 'none';
|
|
96
|
+
self.flagDebugDiv = div;
|
|
97
|
+
document.body.appendChild(div);
|
|
98
|
+
window.addEventListener('keydown', (e) => {
|
|
99
|
+
if (e.key === 'F4') {
|
|
100
|
+
self.showFlagDebug = !self.showFlagDebug;
|
|
101
|
+
self.store.set('Debug::Flag::showDebug', self.showFlagDebug);
|
|
102
|
+
self.flagDebugDiv.style.display = self.showFlagDebug ? 'block' : 'none';
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Attaches WebGL debug window to the instance.
|
|
109
|
+
* @param {import('../index.js').default} self - The engine core instance.
|
|
110
|
+
*/
|
|
111
|
+
export const attachWebglDebugInfo = (self) => {
|
|
112
|
+
const div = document.createElement('div');
|
|
113
|
+
div.style.position = 'absolute';
|
|
114
|
+
div.style.top = '0';
|
|
115
|
+
div.style.left = '0';
|
|
116
|
+
div.style.background = 'rgba(0, 0, 0, 0.6)';
|
|
117
|
+
div.style.color = '#0f0';
|
|
118
|
+
div.style.padding = '4px';
|
|
119
|
+
div.style.fontFamily = 'monospace';
|
|
120
|
+
div.style.fontSize = '12px';
|
|
121
|
+
div.style.zIndex = '10000';
|
|
122
|
+
div.style.pointerEvents = 'none';
|
|
123
|
+
div.style.display = 'none';
|
|
124
|
+
self.webglDebugDiv = div;
|
|
125
|
+
document.body.appendChild(div);
|
|
126
|
+
window.addEventListener('keydown', (e) => {
|
|
127
|
+
if (e.key === 'F3') {
|
|
128
|
+
self.showWebglDebug = !self.showWebglDebug;
|
|
129
|
+
self.store.set('Debug::Webgl::showDebug', self.showWebglDebug);
|
|
130
|
+
self.webglDebugDiv.style.display = self.showWebglDebug ? 'block' : 'none';
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// Free Camera toggle (F5) - register with engine keyboard so behavior matches other controls
|
|
134
|
+
try {
|
|
135
|
+
const kb = self.keyboard;
|
|
136
|
+
const kbHook = (ev, type) => {
|
|
137
|
+
// only handle keydown events here for toggles
|
|
138
|
+
if (type !== 'down') return;
|
|
139
|
+
if (ev.key !== 'F5') return;
|
|
140
|
+
try { ev.preventDefault(); ev.stopPropagation(); } catch (err) { }
|
|
141
|
+
// toggle and kick off same activation path below
|
|
142
|
+
self.showFreeCam = !self.showFreeCam;
|
|
143
|
+
self.store.set('Debug::FreeCam::show', self.showFreeCam);
|
|
144
|
+
// trigger a synthetic event to the same handler path by dispatching a custom event on window
|
|
145
|
+
const e = new CustomEvent('pixos:freecam:toggle');
|
|
146
|
+
window.dispatchEvent(e);
|
|
147
|
+
};
|
|
148
|
+
kb.addHook && kb.addHook(kbHook);
|
|
149
|
+
// store hook so it can be removed later if attachWebglDebugInfo is called multiple times
|
|
150
|
+
self._debugFreeCamHook = kbHook;
|
|
151
|
+
} catch (err) { }
|
|
152
|
+
|
|
153
|
+
// central handler for activation/deactivation triggered by keyboard hook
|
|
154
|
+
window.addEventListener('pixos:freecam:toggle', () => {
|
|
155
|
+
const rm = self.renderManager;
|
|
156
|
+
if (!rm || !rm.camera) return;
|
|
157
|
+
const canvas = self.canvas || document.body;
|
|
158
|
+
const panSpeed = 0.2;
|
|
159
|
+
const rotSpeed = 0.002;
|
|
160
|
+
|
|
161
|
+
// wheel handler -> zoom in/out using camera.zoom
|
|
162
|
+
const onWheel = (we) => {
|
|
163
|
+
try { we.preventDefault(); we.stopPropagation(); } catch (err) { };
|
|
164
|
+
const dz = (we.deltaY > 0 ? 1 : -1) * 0.5;
|
|
165
|
+
try { rm.camera.zoom && rm.camera.zoom(dz); moveCounter++; } catch (err) { }
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
// pointer move handler (pointer lock) -> rotate view matrix directly
|
|
169
|
+
const onPointerMove = (me) => {
|
|
170
|
+
const mx = (me.movementX || 0) * 0.002;
|
|
171
|
+
const my = (me.movementY || 0) * 0.002;
|
|
172
|
+
try {
|
|
173
|
+
// convert to angular delta and apply via rotateCam
|
|
174
|
+
const yawDelta = -mx * 1.5; // scale for responsiveness
|
|
175
|
+
const pitchDelta = -my * 1.5;
|
|
176
|
+
if (rm.camera) {
|
|
177
|
+
rm.camera.yaw += yawDelta;
|
|
178
|
+
rm.camera.pitch = Math.max(-Math.PI / 2 + 0.01, Math.min(Math.PI / 2 - 0.01, rm.camera.pitch + pitchDelta));
|
|
179
|
+
rm.camera.updateViewFromAngles && rm.camera.updateViewFromAngles();
|
|
180
|
+
moveCounter++;
|
|
181
|
+
}
|
|
182
|
+
} catch (err) { }
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// keyboard-driven movement uses keyboard.activeCodes from engine.keyboard
|
|
186
|
+
let rafId = null;
|
|
187
|
+
let statusEl = null;
|
|
188
|
+
let moveCounter = 0;
|
|
189
|
+
let firstTick = true;
|
|
190
|
+
const tick = () => {
|
|
191
|
+
// Use activeCodes which stores the unambiguous key strings (eg 'w', 'ArrowUp')
|
|
192
|
+
const codes = (self.keyboard && self.keyboard.activeCodes) || [];
|
|
193
|
+
const lower = codes.map((c) => (c || '').toString().toLowerCase());
|
|
194
|
+
// WASD movement - translate the view matrix in local camera space
|
|
195
|
+
try {
|
|
196
|
+
const step = 0.5;
|
|
197
|
+
if (rm.camera) {
|
|
198
|
+
if (lower.indexOf('w') >= 0 || lower.indexOf('arrowup') >= 0) { rm.camera.translateCam('UP'); moveCounter++; }
|
|
199
|
+
if (lower.indexOf('s') >= 0 || lower.indexOf('arrowdown') >= 0) { rm.camera.translateCam('DOWN'); moveCounter++; }
|
|
200
|
+
if (lower.indexOf('a') >= 0 || lower.indexOf('arrowleft') >= 0) { rm.camera.translateCam('LEFT'); moveCounter++; }
|
|
201
|
+
if (lower.indexOf('d') >= 0 || lower.indexOf('arrowright') >= 0) { rm.camera.translateCam('RIGHT'); moveCounter++; }
|
|
202
|
+
// Q/E yaw
|
|
203
|
+
if (lower.indexOf('q') >= 0) { rm.camera.yaw -= 0.03; rm.camera.updateViewFromAngles(); moveCounter++; }
|
|
204
|
+
if (lower.indexOf('e') >= 0) { rm.camera.yaw += 0.03; rm.camera.updateViewFromAngles(); moveCounter++; }
|
|
205
|
+
// R/F pitch
|
|
206
|
+
if (lower.indexOf('r') >= 0) { rm.camera.pitch = Math.max(-Math.PI / 2 + 0.01, rm.camera.pitch - 0.03); rm.camera.updateViewFromAngles(); moveCounter++; }
|
|
207
|
+
if (lower.indexOf('f') >= 0) { rm.camera.pitch = Math.min(Math.PI / 2 - 0.01, rm.camera.pitch + 0.03); rm.camera.updateViewFromAngles(); moveCounter++; }
|
|
208
|
+
}
|
|
209
|
+
} catch (err) { }
|
|
210
|
+
|
|
211
|
+
rafId = requestAnimationFrame(tick);
|
|
212
|
+
// update status element so user can see what keys are active (helps debug focus)
|
|
213
|
+
if (!statusEl) {
|
|
214
|
+
statusEl = document.createElement('div');
|
|
215
|
+
statusEl.id = 'pixos-freecam-status';
|
|
216
|
+
statusEl.style.position = 'absolute';
|
|
217
|
+
statusEl.style.top = '8px';
|
|
218
|
+
statusEl.style.left = '50%';
|
|
219
|
+
statusEl.style.transform = 'translateX(-50%)';
|
|
220
|
+
statusEl.style.background = 'rgba(0,0,0,0.6)';
|
|
221
|
+
statusEl.style.color = '#fff';
|
|
222
|
+
statusEl.style.padding = '6px 10px';
|
|
223
|
+
statusEl.style.fontFamily = 'monospace';
|
|
224
|
+
statusEl.style.fontSize = '12px';
|
|
225
|
+
statusEl.style.zIndex = '10002';
|
|
226
|
+
document.body.appendChild(statusEl);
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
// collect camera state safely
|
|
230
|
+
const cam = rm.camera || {};
|
|
231
|
+
if (firstTick) {
|
|
232
|
+
try { console.log('[FreeCam] FIRST TICK viewMat:', Array.from(rm.camera.uViewMat)); } catch (err) { }
|
|
233
|
+
firstTick = false;
|
|
234
|
+
}
|
|
235
|
+
const pos = cam.cameraPosition ? [cam.cameraPosition.x, cam.cameraPosition.y, cam.cameraPosition.z] : ['n/a'];
|
|
236
|
+
const yaw = typeof cam.yaw !== 'undefined' ? cam.yaw.toFixed(3) : 'n/a';
|
|
237
|
+
const pitch = typeof cam.pitch !== 'undefined' ? cam.pitch.toFixed(3) : 'n/a';
|
|
238
|
+
const vm = rm.camera && rm.camera.uViewMat ? Array.from(rm.camera.uViewMat).slice(0, 8).map((n) => n.toFixed(3)) : [];
|
|
239
|
+
statusEl.innerText = 'Keys: ' + JSON.stringify(lower) + '\n' +
|
|
240
|
+
'pointerLock: ' + ((document.pointerLockElement === canvas) ? 'yes' : 'no') + '\n' +
|
|
241
|
+
'pos: ' + JSON.stringify(pos) + ' yaw:' + yaw + ' pitch:' + pitch + '\n' +
|
|
242
|
+
'uViewMat (trim): ' + JSON.stringify(vm) + '\n' +
|
|
243
|
+
'moves: ' + moveCounter;
|
|
244
|
+
} catch (err) { }
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
if (self.showFreeCam) {
|
|
248
|
+
// enter freecam
|
|
249
|
+
// keep raw camera matrix; avoid decomposing it here (fragile)
|
|
250
|
+
self._freeCamSaved = create();
|
|
251
|
+
// log the incoming view matrix for diagnosis
|
|
252
|
+
try { console.log('[FreeCam] ENTER - current viewMat:', Array.from(rm.camera.uViewMat)); } catch (err) { }
|
|
253
|
+
set(rm.camera.uViewMat, self._freeCamSaved);
|
|
254
|
+
try {
|
|
255
|
+
self._freeCamSavedState = {
|
|
256
|
+
position: new Vector(rm.camera.cameraPosition.x, rm.camera.cameraPosition.y, rm.camera.cameraPosition.z),
|
|
257
|
+
yaw: rm.camera.yaw,
|
|
258
|
+
pitch: rm.camera.pitch,
|
|
259
|
+
distance: rm.camera.cameraDistance,
|
|
260
|
+
target: rm.camera.cameraTarget ? new Vector(rm.camera.cameraTarget.x, rm.camera.cameraTarget.y, rm.camera.cameraTarget.z) : null,
|
|
261
|
+
viewMat: create(),
|
|
262
|
+
};
|
|
263
|
+
set(rm.camera.uViewMat, self._freeCamSavedState.viewMat);
|
|
264
|
+
try { console.log('[FreeCam] ENTER - savedState.viewMat:', Array.from(self._freeCamSavedState.viewMat)); } catch (err) { }
|
|
265
|
+
} catch (err) { }
|
|
266
|
+
if (self.spritz?.world) self.spritz.world.isPaused = true;
|
|
267
|
+
self._freecamActive = true;
|
|
268
|
+
|
|
269
|
+
const info = document.createElement('div');
|
|
270
|
+
info.style.position = 'absolute';
|
|
271
|
+
info.style.bottom = '8px';
|
|
272
|
+
info.style.left = '50%';
|
|
273
|
+
info.style.transform = 'translateX(-50%)';
|
|
274
|
+
info.style.background = 'rgba(0,0,0,0.6)';
|
|
275
|
+
info.style.color = '#fff';
|
|
276
|
+
info.style.padding = '6px 10px';
|
|
277
|
+
info.style.fontFamily = 'monospace';
|
|
278
|
+
info.style.fontSize = '12px';
|
|
279
|
+
info.style.zIndex = '10001';
|
|
280
|
+
info.id = 'pixos-freecam-info';
|
|
281
|
+
info.innerHTML = 'FREE CAM (F5 to exit) WASD/Arrows: move & strafe Q/E: yaw R/F: pitch Wheel: zoom';
|
|
282
|
+
document.body.appendChild(info);
|
|
283
|
+
|
|
284
|
+
const onPointerLockChange = () => {
|
|
285
|
+
const locked = document.pointerLockElement === canvas || document.mozPointerLockElement === canvas;
|
|
286
|
+
try {
|
|
287
|
+
const s = document.getElementById('pixos-freecam-status');
|
|
288
|
+
if (s) s.innerText = 'Keys: ' + JSON.stringify((self.keyboard && self.keyboard.activeCodes) || []) + ' | pointerLock: ' + (locked ? 'yes' : 'no');
|
|
289
|
+
try { console.log('[FreeCam] pointerLock change - locked:', locked, 'viewMat:', Array.from(rm.camera.uViewMat)); } catch (err) { }
|
|
290
|
+
} catch (err) { }
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
const captureClick = (ev) => {
|
|
294
|
+
ev && ev.preventDefault();
|
|
295
|
+
// focus the wrapper if available (WebGLView sets tabIndex on wrapper)
|
|
296
|
+
try {
|
|
297
|
+
if (canvas && canvas.parentElement) {
|
|
298
|
+
canvas.parentElement.focus && canvas.parentElement.focus();
|
|
299
|
+
}
|
|
300
|
+
} catch (err) { }
|
|
301
|
+
// request pointer lock on canvas
|
|
302
|
+
try { canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock; canvas.requestPointerLock(); } catch (err) { }
|
|
303
|
+
};
|
|
304
|
+
|
|
305
|
+
// also mousedown as a final fallback
|
|
306
|
+
document.addEventListener('pointerlockchange', onPointerLockChange);
|
|
307
|
+
document.addEventListener('mozpointerlockchange', onPointerLockChange);
|
|
308
|
+
|
|
309
|
+
try { self._bodyOverflowSaved = document.body.style.overflow; document.body.style.overflow = 'hidden'; } catch (err) { }
|
|
310
|
+
|
|
311
|
+
// pointer lock request
|
|
312
|
+
try { canvas.requestPointerLock = canvas.requestPointerLock || canvas.mozRequestPointerLock; canvas.requestPointerLock(); } catch (err) { }
|
|
313
|
+
|
|
314
|
+
window.addEventListener('wheel', onWheel, { passive: false, capture: true });
|
|
315
|
+
document.addEventListener('pointermove', onPointerMove, { capture: true });
|
|
316
|
+
// also listen for mousemove for browsers that don't support pointermove while locked
|
|
317
|
+
document.addEventListener('mousemove', onPointerMove, { capture: true });
|
|
318
|
+
rafId = requestAnimationFrame(tick);
|
|
319
|
+
self._freecamHandlers = { onWheel, onPointerMove, rafId, captureClick, onPointerLockChange };
|
|
320
|
+
} else {
|
|
321
|
+
// exit freecam
|
|
322
|
+
if (self._freeCamSavedState) {
|
|
323
|
+
try {
|
|
324
|
+
try { console.log('[FreeCam] EXIT - restoring savedState.viewMat:', Array.from(self._freeCamSavedState.viewMat)); } catch (err) { }
|
|
325
|
+
// restore raw view matrix snapshot
|
|
326
|
+
set(self._freeCamSavedState.viewMat, rm.camera.uViewMat);
|
|
327
|
+
// restore camera params to ensure consistent tileset-style behavior
|
|
328
|
+
try {
|
|
329
|
+
if (rm.camera) {
|
|
330
|
+
if (typeof self._freeCamSavedState.yaw !== 'undefined') rm.camera.yaw = self._freeCamSavedState.yaw;
|
|
331
|
+
if (typeof self._freeCamSavedState.pitch !== 'undefined') rm.camera.pitch = self._freeCamSavedState.pitch;
|
|
332
|
+
if (typeof self._freeCamSavedState.distance !== 'undefined') rm.camera.cameraDistance = self._freeCamSavedState.distance;
|
|
333
|
+
if (self._freeCamSavedState.target) rm.camera.cameraTarget = self._freeCamSavedState.target;
|
|
334
|
+
rm.camera.updateViewFromAngles && rm.camera.updateViewFromAngles();
|
|
335
|
+
}
|
|
336
|
+
} catch (err) { }
|
|
337
|
+
} catch (err) { }
|
|
338
|
+
self._freeCamSavedState = null;
|
|
339
|
+
} else if (self._freeCamSaved) {
|
|
340
|
+
try {
|
|
341
|
+
try { console.log('[FreeCam] EXIT - restoring _freeCamSaved:', Array.from(self._freeCamSaved)); } catch (err) { }
|
|
342
|
+
set(self._freeCamSaved, rm.camera.uViewMat);
|
|
343
|
+
try { rm.camera.setFromViewMatrix(rm.camera.uViewMat); } catch (err) { }
|
|
344
|
+
} catch (err) { }
|
|
345
|
+
}
|
|
346
|
+
if (self.spritz?.world) self.spritz.world.isPaused = false;
|
|
347
|
+
self._freecamActive = false;
|
|
348
|
+
const info = document.getElementById('pixos-freecam-info'); if (info) document.body.removeChild(info);
|
|
349
|
+
try { document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock; document.exitPointerLock(); } catch (err) { }
|
|
350
|
+
|
|
351
|
+
if (self._freecamHandlers) {
|
|
352
|
+
window.removeEventListener('wheel', self._freecamHandlers.onWheel, { capture: true });
|
|
353
|
+
document.removeEventListener('pointermove', self._freecamHandlers.onPointerMove, { capture: true });
|
|
354
|
+
document.removeEventListener('mousemove', self._freecamHandlers.onPointerMove, { capture: true });
|
|
355
|
+
try {
|
|
356
|
+
if (self._freecamHandlers.onPointerLockChange) {
|
|
357
|
+
document.removeEventListener('pointerlockchange', self._freecamHandlers.onPointerLockChange);
|
|
358
|
+
document.removeEventListener('mozpointerlockchange', self._freecamHandlers.onPointerLockChange);
|
|
359
|
+
}
|
|
360
|
+
} catch (err) { }
|
|
361
|
+
cancelAnimationFrame(self._freecamHandlers.rafId);
|
|
362
|
+
self._freecamHandlers = null;
|
|
363
|
+
}
|
|
364
|
+
try { document.body.style.overflow = self._bodyOverflowSaved ?? ''; } catch (err) { }
|
|
365
|
+
try {
|
|
366
|
+
const s = document.getElementById('pixos-freecam-status');
|
|
367
|
+
if (s) document.body.removeChild(s);
|
|
368
|
+
} catch (err) { }
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|