@luminocity/lemonate-engine 26.4.3 → 26.4.6
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/dist/Renderer.d.ts +0 -2
- package/dist/SceneGraph.d.ts +1 -1
- package/dist/lemonate.es.js +257 -224
- package/dist/lemonate.js +257 -224
- package/dist/lemonate.min.js +3 -3
- package/dist/lemonate.umd.js +257 -224
- package/dist/player.zip +0 -0
- package/dist/scenegraph/SgItem.d.ts +1 -1
- package/dist/tools/Profiler.d.ts +4 -0
- package/package.json +1 -1
package/dist/lemonate.es.js
CHANGED
|
@@ -11390,7 +11390,7 @@ class Item extends EventEmitter {
|
|
|
11390
11390
|
}
|
|
11391
11391
|
}
|
|
11392
11392
|
|
|
11393
|
-
var engine$1 = "26.4.
|
|
11393
|
+
var engine$1 = "26.4.6";
|
|
11394
11394
|
var bullet = "3.26";
|
|
11395
11395
|
var lua = "5.4.3";
|
|
11396
11396
|
var packageVersionInfo = {
|
|
@@ -67293,222 +67293,222 @@ class RenderView {
|
|
|
67293
67293
|
}
|
|
67294
67294
|
async render(renderPassInfo) {
|
|
67295
67295
|
this.renderPassInfo = renderPassInfo;
|
|
67296
|
-
|
|
67297
|
-
|
|
67298
|
-
|
|
67299
|
-
|
|
67300
|
-
|
|
67301
|
-
|
|
67302
|
-
|
|
67303
|
-
}
|
|
67304
|
-
// Activate our scene graph collection
|
|
67305
|
-
// ----------------------------------------------------------------------------------
|
|
67306
|
-
const sceneGraphCollection = renderPassInfo.sceneGraphCollection;
|
|
67307
|
-
this.engine.setActiveSceneGraphCollection(sceneGraphCollection);
|
|
67308
|
-
const rootScene = sceneGraphCollection.getRootScene();
|
|
67309
|
-
let primaryScene = sceneGraphCollection.getPrimaryScene();
|
|
67310
|
-
// We do no physics particles and scripting unless we're in the main scene graph collection.
|
|
67311
|
-
// This is temporarily, until everything has been untangled properly and every sceneGraphCollection
|
|
67312
|
-
// is completely independant from all others
|
|
67313
|
-
// ----------------------------------------------------------------------------------
|
|
67314
|
-
const isMainSceneGraphCollection = this.engine.mainSceneGraphCollection === sceneGraphCollection;
|
|
67315
|
-
const doPhysics = isMainSceneGraphCollection;
|
|
67316
|
-
const doParticleSystemUpdate = isMainSceneGraphCollection;
|
|
67317
|
-
const doScripting = isMainSceneGraphCollection;
|
|
67318
|
-
// Update physics objects and call update/tick methods
|
|
67319
|
-
// ----------------------------------------------------------------------------------
|
|
67320
|
-
if (!renderPassInfo.playerIsPaused) {
|
|
67321
|
-
if (doPhysics) {
|
|
67322
|
-
this.engine.profiler.measure("Physics", "processUpdate", async () => {
|
|
67323
|
-
this.engine.physics.processPhysicsUpdate();
|
|
67324
|
-
});
|
|
67296
|
+
await this.engine.profiler.measureAsync("RenderView", "render", async () => {
|
|
67297
|
+
try {
|
|
67298
|
+
// Activate our canvas for use with canvas Lua API
|
|
67299
|
+
// ----------------------------------------------------------------------------------
|
|
67300
|
+
if (this.canvas) {
|
|
67301
|
+
this.renderer.setActiveCanvas(this.canvas);
|
|
67302
|
+
this.canvas.checkResize(renderPassInfo.resolution);
|
|
67325
67303
|
}
|
|
67326
|
-
|
|
67327
|
-
|
|
67328
|
-
|
|
67329
|
-
|
|
67304
|
+
// Activate our scene graph collection
|
|
67305
|
+
// ----------------------------------------------------------------------------------
|
|
67306
|
+
const sceneGraphCollection = renderPassInfo.sceneGraphCollection;
|
|
67307
|
+
this.engine.setActiveSceneGraphCollection(sceneGraphCollection);
|
|
67308
|
+
const rootScene = sceneGraphCollection.getRootScene();
|
|
67309
|
+
let primaryScene = sceneGraphCollection.getPrimaryScene();
|
|
67310
|
+
// We do no physics particles and scripting unless we're in the main scene graph collection.
|
|
67311
|
+
// This is temporarily, until everything has been untangled properly and every sceneGraphCollection
|
|
67312
|
+
// is completely independant from all others
|
|
67313
|
+
// ----------------------------------------------------------------------------------
|
|
67314
|
+
const isMainSceneGraphCollection = this.engine.mainSceneGraphCollection === sceneGraphCollection;
|
|
67315
|
+
const doPhysics = isMainSceneGraphCollection;
|
|
67316
|
+
const doParticleSystemUpdate = isMainSceneGraphCollection;
|
|
67317
|
+
const doScripting = isMainSceneGraphCollection;
|
|
67318
|
+
// Update physics objects and call update/tick methods
|
|
67319
|
+
// ----------------------------------------------------------------------------------
|
|
67320
|
+
if (!renderPassInfo.playerIsPaused) {
|
|
67321
|
+
if (doPhysics) {
|
|
67322
|
+
this.engine.profiler.measure("Physics", "processUpdate", async () => {
|
|
67323
|
+
this.engine.physics.processPhysicsUpdate();
|
|
67324
|
+
});
|
|
67325
|
+
}
|
|
67326
|
+
if (doScripting) {
|
|
67327
|
+
await this.engine.profiler.measureAsync("Scripting", "update", async () => {
|
|
67328
|
+
return this.engine.player.update();
|
|
67329
|
+
});
|
|
67330
|
+
}
|
|
67330
67331
|
}
|
|
67331
|
-
|
|
67332
|
-
|
|
67333
|
-
|
|
67334
|
-
|
|
67335
|
-
|
|
67336
|
-
|
|
67337
|
-
|
|
67338
|
-
|
|
67339
|
-
|
|
67340
|
-
|
|
67341
|
-
this.cameraMode = this.cameraModeOverride;
|
|
67342
|
-
}
|
|
67343
|
-
else {
|
|
67344
|
-
const primarySceneItem = sceneGraphCollection.getPrimarySceneItem();
|
|
67345
|
-
if (primarySceneItem && typeof primarySceneItem.getCameraMode === 'function')
|
|
67346
|
-
this.cameraMode = primarySceneItem.getCameraMode();
|
|
67347
|
-
else
|
|
67348
|
-
this.cameraMode = CameraMode.AutomaticUserControllable;
|
|
67349
|
-
}
|
|
67350
|
-
// Set clear color
|
|
67351
|
-
// ----------------------------------------------------------------------------------
|
|
67352
|
-
if (primaryScene.userData?.customRenderSettings) {
|
|
67353
|
-
const clearColor = primaryScene.userData.customRenderSettings.clearColor;
|
|
67354
|
-
if (clearColor) {
|
|
67355
|
-
const clearColorRGB = (clearColor.r << 16) + (clearColor.g << 8) + clearColor.b;
|
|
67356
|
-
this.webGlRenderer.setClearColor(clearColorRGB, clearColor.a / 255);
|
|
67332
|
+
// Call beforeRender hook on all items
|
|
67333
|
+
// ----------------------------------------------------------------------------------
|
|
67334
|
+
const itemInstances = this.engine.loadingManager.getAllItemInstances();
|
|
67335
|
+
for (const item of itemInstances) {
|
|
67336
|
+
item.beforeRender();
|
|
67337
|
+
}
|
|
67338
|
+
// Set camera mode
|
|
67339
|
+
// ----------------------------------------------------------------------------------
|
|
67340
|
+
if (this.cameraModeOverride !== CameraMode.None) {
|
|
67341
|
+
this.cameraMode = this.cameraModeOverride;
|
|
67357
67342
|
}
|
|
67358
67343
|
else {
|
|
67359
|
-
|
|
67344
|
+
const primarySceneItem = sceneGraphCollection.getPrimarySceneItem();
|
|
67345
|
+
if (primarySceneItem && typeof primarySceneItem.getCameraMode === 'function')
|
|
67346
|
+
this.cameraMode = primarySceneItem.getCameraMode();
|
|
67347
|
+
else
|
|
67348
|
+
this.cameraMode = CameraMode.AutomaticUserControllable;
|
|
67360
67349
|
}
|
|
67361
|
-
|
|
67362
|
-
|
|
67363
|
-
|
|
67364
|
-
|
|
67365
|
-
|
|
67366
|
-
|
|
67367
|
-
|
|
67368
|
-
rootScene.fog = primaryScene.fog;
|
|
67369
|
-
// Animate scene
|
|
67370
|
-
// ----------------------------------------------------------------------------------
|
|
67371
|
-
if (!renderPassInfo.playerIsPaused) {
|
|
67372
|
-
this.engine.profiler.measure("RenderView", "animate", async () => {
|
|
67373
|
-
this._animate(sceneGraphCollection, renderPassInfo.deltaPlayerTimeMs);
|
|
67374
|
-
});
|
|
67375
|
-
}
|
|
67376
|
-
// Init GUI
|
|
67377
|
-
// ----------------------------------------------------------------------------------
|
|
67378
|
-
const needToRenderGui = this.engine.player.needToRenderGui();
|
|
67379
|
-
if (needToRenderGui) {
|
|
67380
|
-
renderPassInfo.guiCaptureInfo = this.engine.imgui.newFrame(renderPassInfo.currentPlayerTimeMs);
|
|
67381
|
-
}
|
|
67382
|
-
if (doParticleSystemUpdate)
|
|
67383
|
-
this.renderer.renderParticleSystems(renderPassInfo);
|
|
67384
|
-
this.renderer.updateViewHelper(renderPassInfo);
|
|
67385
|
-
this.renderer.updateControls(renderPassInfo);
|
|
67386
|
-
// whenever we playback, we assume, we're moving
|
|
67387
|
-
if (this.engine.player && this.engine.player.isPlaying()) {
|
|
67388
|
-
renderPassInfo.didMove = true;
|
|
67389
|
-
}
|
|
67390
|
-
if (!renderPassInfo.cameraIsStill && renderPassInfo.currentTimeMs - renderPassInfo.lastMovementMs > 500) {
|
|
67391
|
-
renderPassInfo.cameraIsStill = true;
|
|
67392
|
-
renderPassInfo.didMove = true;
|
|
67393
|
-
}
|
|
67394
|
-
// Check if we actually need to render a frame due to movements or data updates
|
|
67395
|
-
// ----------------------------------------------------------------------------------
|
|
67396
|
-
if (renderPassInfo.didMove ||
|
|
67397
|
-
renderPassInfo.screenWasResized ||
|
|
67398
|
-
this.renderer.alwaysRender ||
|
|
67399
|
-
this.renderer.updateRender) {
|
|
67400
|
-
if (this.webGlRenderer && this.renderer.activeCamera) {
|
|
67401
|
-
renderPassInfo.cameraDidMove = renderPassInfo.didMove || renderPassInfo.screenWasResized;
|
|
67402
|
-
// We'll remove the scene environment, because it will be applied to anything including
|
|
67403
|
-
// helpers and we don't want that. We'll apply it manually in the hooks and set it back after rendering
|
|
67404
|
-
// ----------------------------------------------------------------------------------
|
|
67405
|
-
renderPassInfo.sceneEnvironment = primaryScene.environment;
|
|
67406
|
-
renderPassInfo.sceneEnvironmentIntensity =
|
|
67407
|
-
primaryScene.environmentIntensity !== undefined
|
|
67408
|
-
? primaryScene.environmentIntensity
|
|
67409
|
-
: 1;
|
|
67410
|
-
// Call before render to set any overrides like visibility, material or envmap
|
|
67411
|
-
// ----------------------------------------------------------------------------------
|
|
67412
|
-
this.beforeRender(renderPassInfo);
|
|
67413
|
-
// Do light, material, etc. updates
|
|
67414
|
-
// ----------------------------------------------------------------------------------
|
|
67415
|
-
this.setRendererSettingsFromScene();
|
|
67416
|
-
this.renderer.updateMaterialUniforms(renderPassInfo.currentPlayerTimeMs, renderPassInfo.resolution);
|
|
67417
|
-
// Check if we have transform controls which we need to hide
|
|
67418
|
-
// ----------------------------------------------------------------------------------
|
|
67419
|
-
let transformControlsWereDisabled = false;
|
|
67420
|
-
if (rootScene.transformControls &&
|
|
67421
|
-
rootScene.transformControls.visible &&
|
|
67422
|
-
(!renderPassInfo.renderOptions.showHelpers || this.renderer.editorOutputOption.outputMode !== OutputMode.EditorCamera)) {
|
|
67423
|
-
transformControlsWereDisabled = true;
|
|
67424
|
-
rootScene.transformControls.visible = false;
|
|
67425
|
-
}
|
|
67426
|
-
// Check if we need to render background and transfer to root scene
|
|
67427
|
-
// ----------------------------------------------------------------------------------
|
|
67428
|
-
rootScene.backgroundBlurriness = primaryScene.backgroundBlurriness;
|
|
67429
|
-
rootScene.backgroundIntensity = primaryScene.backgroundIntensity;
|
|
67430
|
-
if (!renderPassInfo.renderOptions.showBackground) {
|
|
67431
|
-
rootScene.background = null;
|
|
67432
|
-
rootScene.backgroundShader = undefined;
|
|
67433
|
-
}
|
|
67434
|
-
else if (this.renderer.backgroundOverrideColor) {
|
|
67435
|
-
rootScene.background = tools.hexColorToColor(this.renderer.backgroundOverrideColor);
|
|
67436
|
-
rootScene.backgroundShader = undefined;
|
|
67350
|
+
// Set clear color
|
|
67351
|
+
// ----------------------------------------------------------------------------------
|
|
67352
|
+
if (primaryScene.userData?.customRenderSettings) {
|
|
67353
|
+
const clearColor = primaryScene.userData.customRenderSettings.clearColor;
|
|
67354
|
+
if (clearColor) {
|
|
67355
|
+
const clearColorRGB = (clearColor.r << 16) + (clearColor.g << 8) + clearColor.b;
|
|
67356
|
+
this.webGlRenderer.setClearColor(clearColorRGB, clearColor.a / 255);
|
|
67437
67357
|
}
|
|
67438
67358
|
else {
|
|
67439
|
-
|
|
67440
|
-
rootScene.backgroundShader = primaryScene.backgroundShader;
|
|
67441
|
-
}
|
|
67442
|
-
// Render any items that need to be rendered first
|
|
67443
|
-
// ----------------------------------------------------------------------------------
|
|
67444
|
-
for (const item of itemInstances) {
|
|
67445
|
-
item.render(rootScene, renderPassInfo);
|
|
67359
|
+
this.webGlRenderer.setClearColor(0x000000, 1);
|
|
67446
67360
|
}
|
|
67447
|
-
|
|
67448
|
-
|
|
67449
|
-
|
|
67450
|
-
|
|
67451
|
-
|
|
67452
|
-
|
|
67453
|
-
|
|
67454
|
-
|
|
67455
|
-
|
|
67456
|
-
|
|
67457
|
-
|
|
67458
|
-
|
|
67459
|
-
|
|
67460
|
-
|
|
67461
|
-
|
|
67462
|
-
|
|
67463
|
-
|
|
67464
|
-
|
|
67465
|
-
|
|
67466
|
-
|
|
67467
|
-
|
|
67468
|
-
|
|
67469
|
-
|
|
67361
|
+
}
|
|
67362
|
+
else {
|
|
67363
|
+
this.webGlRenderer.setClearColor(0x000000, 1);
|
|
67364
|
+
}
|
|
67365
|
+
// Set fog of the primary scene if any
|
|
67366
|
+
// ----------------------------------------------------------------------------------
|
|
67367
|
+
// @ts-ignore
|
|
67368
|
+
rootScene.fog = primaryScene.fog;
|
|
67369
|
+
// Animate scene
|
|
67370
|
+
// ----------------------------------------------------------------------------------
|
|
67371
|
+
if (!renderPassInfo.playerIsPaused) {
|
|
67372
|
+
this.engine.profiler.measure("RenderView", "animate", async () => {
|
|
67373
|
+
this._animate(sceneGraphCollection, renderPassInfo.deltaPlayerTimeMs);
|
|
67374
|
+
});
|
|
67375
|
+
}
|
|
67376
|
+
// Init GUI
|
|
67377
|
+
// ----------------------------------------------------------------------------------
|
|
67378
|
+
const needToRenderGui = this.engine.player.needToRenderGui();
|
|
67379
|
+
if (needToRenderGui) {
|
|
67380
|
+
renderPassInfo.guiCaptureInfo = this.engine.imgui.newFrame(renderPassInfo.currentPlayerTimeMs);
|
|
67381
|
+
}
|
|
67382
|
+
if (doParticleSystemUpdate)
|
|
67383
|
+
this.renderer.renderParticleSystems(renderPassInfo);
|
|
67384
|
+
this.renderer.updateViewHelper(renderPassInfo);
|
|
67385
|
+
this.renderer.updateControls(renderPassInfo);
|
|
67386
|
+
// whenever we playback, we assume, we're moving
|
|
67387
|
+
if (this.engine.player && this.engine.player.isPlaying()) {
|
|
67388
|
+
renderPassInfo.didMove = true;
|
|
67389
|
+
}
|
|
67390
|
+
if (!renderPassInfo.cameraIsStill && renderPassInfo.currentTimeMs - renderPassInfo.lastMovementMs > 500) {
|
|
67391
|
+
renderPassInfo.cameraIsStill = true;
|
|
67392
|
+
renderPassInfo.didMove = true;
|
|
67393
|
+
}
|
|
67394
|
+
// Check if we actually need to render a frame due to movements or data updates
|
|
67395
|
+
// ----------------------------------------------------------------------------------
|
|
67396
|
+
if (renderPassInfo.didMove ||
|
|
67397
|
+
renderPassInfo.screenWasResized ||
|
|
67398
|
+
this.renderer.alwaysRender ||
|
|
67399
|
+
this.renderer.updateRender) {
|
|
67400
|
+
if (this.webGlRenderer && this.renderer.activeCamera) {
|
|
67401
|
+
renderPassInfo.cameraDidMove = renderPassInfo.didMove || renderPassInfo.screenWasResized;
|
|
67402
|
+
// We'll remove the scene environment, because it will be applied to anything including
|
|
67403
|
+
// helpers and we don't want that. We'll apply it manually in the hooks and set it back after rendering
|
|
67404
|
+
// ----------------------------------------------------------------------------------
|
|
67405
|
+
renderPassInfo.sceneEnvironment = primaryScene.environment;
|
|
67406
|
+
renderPassInfo.sceneEnvironmentIntensity =
|
|
67407
|
+
primaryScene.environmentIntensity !== undefined
|
|
67408
|
+
? primaryScene.environmentIntensity
|
|
67409
|
+
: 1;
|
|
67410
|
+
// Call before render to set any overrides like visibility, material or envmap
|
|
67411
|
+
// ----------------------------------------------------------------------------------
|
|
67412
|
+
this.beforeRender(renderPassInfo);
|
|
67413
|
+
// Do light, material, etc. updates
|
|
67414
|
+
// ----------------------------------------------------------------------------------
|
|
67415
|
+
this.setRendererSettingsFromScene();
|
|
67416
|
+
this.renderer.updateMaterialUniforms(renderPassInfo.currentPlayerTimeMs, renderPassInfo.resolution);
|
|
67417
|
+
// Check if we have transform controls which we need to hide
|
|
67418
|
+
// ----------------------------------------------------------------------------------
|
|
67419
|
+
let transformControlsWereDisabled = false;
|
|
67420
|
+
if (rootScene.transformControls &&
|
|
67421
|
+
rootScene.transformControls.visible &&
|
|
67422
|
+
(!renderPassInfo.renderOptions.showHelpers || this.renderer.editorOutputOption.outputMode !== OutputMode.EditorCamera)) {
|
|
67423
|
+
transformControlsWereDisabled = true;
|
|
67424
|
+
rootScene.transformControls.visible = false;
|
|
67425
|
+
}
|
|
67426
|
+
// Check if we need to render background and transfer to root scene
|
|
67427
|
+
// ----------------------------------------------------------------------------------
|
|
67428
|
+
rootScene.backgroundBlurriness = primaryScene.backgroundBlurriness;
|
|
67429
|
+
rootScene.backgroundIntensity = primaryScene.backgroundIntensity;
|
|
67430
|
+
if (!renderPassInfo.renderOptions.showBackground) {
|
|
67431
|
+
rootScene.background = null;
|
|
67432
|
+
rootScene.backgroundShader = undefined;
|
|
67433
|
+
}
|
|
67434
|
+
else if (this.renderer.backgroundOverrideColor) {
|
|
67435
|
+
rootScene.background = tools.hexColorToColor(this.renderer.backgroundOverrideColor);
|
|
67436
|
+
rootScene.backgroundShader = undefined;
|
|
67437
|
+
}
|
|
67438
|
+
else {
|
|
67439
|
+
rootScene.background = primaryScene.background;
|
|
67440
|
+
rootScene.backgroundShader = primaryScene.backgroundShader;
|
|
67441
|
+
}
|
|
67442
|
+
// Render any items that need to be rendered first
|
|
67443
|
+
// ----------------------------------------------------------------------------------
|
|
67444
|
+
for (const item of itemInstances) {
|
|
67445
|
+
item.render(rootScene, renderPassInfo);
|
|
67446
|
+
}
|
|
67447
|
+
// Update physics debug geometry
|
|
67448
|
+
// ----------------------------------------------------------------------------------
|
|
67449
|
+
if (doPhysics) {
|
|
67450
|
+
this.engine.profiler.measure("Physics", "renderDebugInfo", () => {
|
|
67451
|
+
this.engine.physics.renderDebugInfo();
|
|
67470
67452
|
});
|
|
67471
67453
|
}
|
|
67472
|
-
|
|
67473
|
-
|
|
67474
|
-
|
|
67475
|
-
|
|
67476
|
-
|
|
67477
|
-
|
|
67478
|
-
|
|
67479
|
-
|
|
67480
|
-
|
|
67481
|
-
|
|
67482
|
-
|
|
67483
|
-
|
|
67484
|
-
|
|
67485
|
-
|
|
67486
|
-
|
|
67487
|
-
|
|
67488
|
-
|
|
67489
|
-
|
|
67490
|
-
|
|
67491
|
-
|
|
67492
|
-
|
|
67493
|
-
|
|
67494
|
-
|
|
67495
|
-
|
|
67496
|
-
|
|
67497
|
-
|
|
67454
|
+
// Render the scene
|
|
67455
|
+
// ----------------------------------------------------------------------------------
|
|
67456
|
+
this._renderScene(renderPassInfo);
|
|
67457
|
+
// Call render hook
|
|
67458
|
+
// ----------------------------------------------------------------------------------
|
|
67459
|
+
if (!renderPassInfo.playerIsPaused && doScripting) {
|
|
67460
|
+
await this.engine.profiler.measureAsync("Scripting", "render", () => {
|
|
67461
|
+
return this.engine.player.render();
|
|
67462
|
+
});
|
|
67463
|
+
}
|
|
67464
|
+
// Create GUI
|
|
67465
|
+
// ----------------------------------------------------------------------------------
|
|
67466
|
+
if (needToRenderGui && doScripting) {
|
|
67467
|
+
if (!renderPassInfo.playerIsPaused) {
|
|
67468
|
+
await this.engine.profiler.measureAsync("Scripting", "renderGui", () => {
|
|
67469
|
+
return this.engine.player.renderGui();
|
|
67470
|
+
});
|
|
67471
|
+
}
|
|
67472
|
+
this.engine.imgui.endFrame();
|
|
67473
|
+
}
|
|
67474
|
+
// Call the after render function to revert all the overrides
|
|
67475
|
+
// ----------------------------------------------------------------------------------
|
|
67476
|
+
this.afterRender(renderPassInfo);
|
|
67477
|
+
// Render the canvas
|
|
67478
|
+
// ----------------------------------------------------------------------------------
|
|
67479
|
+
if (this.canvas)
|
|
67480
|
+
this.canvas.render();
|
|
67481
|
+
// Finish rendering GUI
|
|
67482
|
+
// ----------------------------------------------------------------------------------
|
|
67483
|
+
if (needToRenderGui && doScripting) {
|
|
67484
|
+
this.engine.imgui.render();
|
|
67485
|
+
}
|
|
67486
|
+
this.webGlRenderer.resetState();
|
|
67487
|
+
// Emit framebuffer as event, if queued
|
|
67488
|
+
// ----------------------------------------------------------------------------------
|
|
67489
|
+
if (this.renderer.emitFramebuffer) {
|
|
67490
|
+
const frame = textureTools.grabFramebufferImage(this, renderPassInfo.viewport);
|
|
67491
|
+
this.engine.eventBus.$emit("engine:frameBufferResult", frame);
|
|
67492
|
+
this.renderer.emitFramebuffer = false;
|
|
67493
|
+
}
|
|
67494
|
+
// Restore transform controls
|
|
67495
|
+
// ----------------------------------------------------------------------------------
|
|
67496
|
+
if (transformControlsWereDisabled) {
|
|
67497
|
+
rootScene.transformControls.visible = true;
|
|
67498
|
+
}
|
|
67498
67499
|
}
|
|
67499
67500
|
}
|
|
67500
67501
|
}
|
|
67501
|
-
|
|
67502
|
-
|
|
67503
|
-
|
|
67504
|
-
|
|
67505
|
-
|
|
67506
|
-
|
|
67507
|
-
|
|
67508
|
-
|
|
67509
|
-
|
|
67510
|
-
|
|
67511
|
-
}
|
|
67502
|
+
catch (err) {
|
|
67503
|
+
console.error(err);
|
|
67504
|
+
}
|
|
67505
|
+
finally {
|
|
67506
|
+
// we keep the canvas active for now since async script operations might still access it.
|
|
67507
|
+
// needs to be properly solved later.
|
|
67508
|
+
//this.renderer.setActiveCanvas(null);
|
|
67509
|
+
this.engine.setActiveSceneGraphCollection(undefined);
|
|
67510
|
+
}
|
|
67511
|
+
});
|
|
67512
67512
|
}
|
|
67513
67513
|
_animate(sceneGraphCollection, deltaTimeMs) {
|
|
67514
67514
|
const deltaTimeSecs = deltaTimeMs / 1000;
|
|
@@ -68260,7 +68260,7 @@ class Renderer {
|
|
|
68260
68260
|
options;
|
|
68261
68261
|
renderView = null;
|
|
68262
68262
|
webGlRenderer;
|
|
68263
|
-
webGpuRenderer;
|
|
68263
|
+
//webGpuRenderer: WebGPURenderer;
|
|
68264
68264
|
raycaster;
|
|
68265
68265
|
renderers = {};
|
|
68266
68266
|
requestFrameFuncs = [];
|
|
@@ -68337,7 +68337,7 @@ class Renderer {
|
|
|
68337
68337
|
this.layers.push(`Layer ${i + 1}`);
|
|
68338
68338
|
}
|
|
68339
68339
|
this.webGlRenderer = this._createWebGlRenderer(options);
|
|
68340
|
-
this.webGpuRenderer = this._createWebGpuRenderer();
|
|
68340
|
+
//this.webGpuRenderer = this._createWebGpuRenderer();
|
|
68341
68341
|
this.setDevicePixelRatio();
|
|
68342
68342
|
this.setShadowType(ShadowMode.Pcf);
|
|
68343
68343
|
this.setRendererSettings();
|
|
@@ -68427,12 +68427,6 @@ class Renderer {
|
|
|
68427
68427
|
return webGpuRenderer;
|
|
68428
68428
|
}
|
|
68429
68429
|
async init() {
|
|
68430
|
-
try {
|
|
68431
|
-
await this.webGpuRenderer.init();
|
|
68432
|
-
}
|
|
68433
|
-
catch (err) {
|
|
68434
|
-
console.error("Failed to initialize WebGPU Renderer: ", err);
|
|
68435
|
-
}
|
|
68436
68430
|
try {
|
|
68437
68431
|
await loadFontFace("OpenSansRegular", openSansRegularUrl);
|
|
68438
68432
|
}
|
|
@@ -68444,9 +68438,9 @@ class Renderer {
|
|
|
68444
68438
|
getWebGLRenderer() {
|
|
68445
68439
|
return this.webGlRenderer;
|
|
68446
68440
|
}
|
|
68447
|
-
getWebGPURenderer() {
|
|
68441
|
+
/*getWebGPURenderer(): WebGPURenderer {
|
|
68448
68442
|
return this.webGpuRenderer;
|
|
68449
|
-
}
|
|
68443
|
+
}*/
|
|
68450
68444
|
hookEvents() {
|
|
68451
68445
|
if (this.renderView) {
|
|
68452
68446
|
// We have to remember the pressed buttons of the pointer controller because we will only ever receive a single
|
|
@@ -70552,7 +70546,7 @@ class SgItem extends SgResourceOwner {
|
|
|
70552
70546
|
* this item's container to its parent directly. But in case where this item has a subNodeId, it is not directly
|
|
70553
70547
|
* a child of its parent but to one of its subnodes. We need to check if this subnode exists and then add
|
|
70554
70548
|
* ourselves to it. If that subnode does not exist, we will instead add to the parent directly again.
|
|
70555
|
-
* This function needs to be called
|
|
70549
|
+
* This function needs to be called whenever the parent updates its subnodes, because this would mean
|
|
70556
70550
|
* the subnode will suddenly appear/disappear and we need to update parenting again
|
|
70557
70551
|
*/
|
|
70558
70552
|
updateParenting() {
|
|
@@ -73559,7 +73553,6 @@ class SgMesh extends SgPhysicsItem {
|
|
|
73559
73553
|
this.mixer = undefined;
|
|
73560
73554
|
this.animations = [];
|
|
73561
73555
|
this.activeTweens = undefined;
|
|
73562
|
-
this.setFieldValue("Animations", []);
|
|
73563
73556
|
}
|
|
73564
73557
|
isAnimated() {
|
|
73565
73558
|
return Boolean(this.mixer);
|
|
@@ -88201,9 +88194,15 @@ class SceneGraph {
|
|
|
88201
88194
|
* @param node
|
|
88202
88195
|
* @return {boolean}
|
|
88203
88196
|
*/
|
|
88204
|
-
traverse(callback, node) {
|
|
88197
|
+
traverse(callback, node, depthFirst = false) {
|
|
88205
88198
|
node = node || this.root;
|
|
88206
88199
|
if (node) {
|
|
88200
|
+
if (depthFirst) {
|
|
88201
|
+
for (const child of node.children) {
|
|
88202
|
+
if (!this.traverse(callback, child, true))
|
|
88203
|
+
return false;
|
|
88204
|
+
}
|
|
88205
|
+
}
|
|
88207
88206
|
const result = callback(node);
|
|
88208
88207
|
if (result === false)
|
|
88209
88208
|
return false;
|
|
@@ -88212,13 +88211,15 @@ class SceneGraph {
|
|
|
88212
88211
|
if (sceneItem) {
|
|
88213
88212
|
const sceneGraph = sceneItem.getSceneGraph();
|
|
88214
88213
|
if (sceneGraph)
|
|
88215
|
-
if (!sceneGraph.traverse(callback))
|
|
88214
|
+
if (!sceneGraph.traverse(callback, undefined, depthFirst))
|
|
88216
88215
|
return false;
|
|
88217
88216
|
}
|
|
88218
88217
|
}
|
|
88219
|
-
|
|
88220
|
-
|
|
88221
|
-
|
|
88218
|
+
if (!depthFirst) {
|
|
88219
|
+
for (const child of node.children) {
|
|
88220
|
+
if (!this.traverse(callback, child, false))
|
|
88221
|
+
return false;
|
|
88222
|
+
}
|
|
88222
88223
|
}
|
|
88223
88224
|
}
|
|
88224
88225
|
return true;
|
|
@@ -88562,7 +88563,7 @@ class SceneGraph {
|
|
|
88562
88563
|
return false;
|
|
88563
88564
|
}
|
|
88564
88565
|
return true;
|
|
88565
|
-
});
|
|
88566
|
+
}, undefined, true);
|
|
88566
88567
|
return result;
|
|
88567
88568
|
}
|
|
88568
88569
|
findSelectedItems() {
|
|
@@ -97453,9 +97454,9 @@ var lua_api_internal = "\nlocal msgpack = require('engine/msgpack');\nlocal pack
|
|
|
97453
97454
|
|
|
97454
97455
|
var lua_api_audio = "\nlocal _internal = require('engine/_internal');\n\n--- @module audio\nlocal audio = {}\n\n---Get an FFT analysis from the audio engine. It returns an array of 256 samples\n---@function getAnalysis\nfunction audio.getAnalysis()\n return _internal.sendMessage('audio.getAnalysis')\nend\n\nreturn audio\n";
|
|
97455
97456
|
|
|
97456
|
-
var lua_api_behaviour = "local SceneObject = require('engine/sceneobject')\nlocal Canvas = require('engine/canvas')\nlocal JE = require('engine/json/jsonencoder')()\n\nlocal _behavioursMapByNodeId = {}\nlocal _behavioursMapByScriptId = {}\n\nlocal Behaviour = Class.new()\n\n-- Put the class in the global scope (Behaviour is the old deprecated name)\n_G.Behaviour = Behaviour\n_G.Entity = Behaviour\n\n--- Constructor hook called when a new Behaviour is created.\n---@private\nfunction Behaviour:__new()\n self._isBehaviour = true\n self._type = \"Behaviour\"\n self._nodeId = nil\n self._scriptName = \"\"\n self._isActive = true\n self._isInitialized = false\n\n -- Adds a default node property\n self:addProperty(\"node\", Property.Node)\nend\n\n--- Destructor hook called before the Behaviour is destroyed.\n---@private\nfunction Behaviour:__destroy()\n print(\"__destroy called for: \", self._nodeId)\nend\n\n--- Get all behaviours attached to a specific node ID.\n---@param nodeId string The ID of the scene graph node\n---@return table A table containing all behaviours attached to the node\nfunction Behaviour.getByNodeId(nodeId)\n local result = {}\n local nodeBehaviours = _behavioursMapByNodeId[nodeId]\n if nodeBehaviours then\n for k,v in pairs(nodeBehaviours) do\n table.insert(result, v.behaviour)\n end\n end\n return result\nend\n\n--- Get a single behaviour attached to a node ID with a specific script name.\n---@param nodeId string The ID of the scene graph node\n---@param scriptName string The script name of the behaviour\n---@return Behaviour|nil The behaviour if found, or nil\nfunction Behaviour.getByNodeIdAndScriptName(nodeId, scriptName)\n local nodeEntities = _behavioursMapByNodeId[nodeId]\n if nodeEntities then\n for k,v in pairs(nodeEntities) do\n if v.scriptName == scriptName then\n return v.behaviour\n end\n end\n end\n return nil\nend\n\n--- Returns the node ID this Behaviour is attached to.\n---@return string|nil Node ID of the attached scene object\nfunction Behaviour:getNodeId()\n return self._nodeId\nend\n\n--- Returns the script name of this Behaviour.\n---@return string Script name\nfunction Behaviour:getScriptName()\n return self._scriptName\nend\n\n--- Returns a table of all properties defined on the behaviour class.\n---@return table A table with fields: name, defaultValue, type, order\nfunction Behaviour:getProperties()\n local props = {}\n local class = self.getClass()\n\n for k,v in pairs(class) do\n if type(v) == 'table' and v._isProperty then\n table.insert(props, { name=k, defaultValue=v.value, type=v.datatype, order=v.order, info=v.info })\n end\n end\n\n for k,v in pairs(class.properties) do\n if type(v) == 'table' and v._isProperty then\n table.insert(props, { name=k, defaultValue=v.value, type=v.datatype, order=v.order, info=v.info })\n end\n end\n\n return props\nend\n\n--- When a script is destroyed, we need to call this to clear the behaviour out of the list\n---@private\nfunction Behaviour:_disposeBehaviour()\n local scripts = _behavioursMapByNodeId[self._nodeId]\n if scripts then\n scripts[self._scriptId] = nil\n end\n\n _behavioursMapByScriptId[self._scriptId] = nil\nend\n\n--- Internal setter for a property\n---@private\n---@param name string Property name\n---@param value any Value to set\nfunction Behaviour:_setProperty(name, value)\n self[name] = value\nend\n\n--- Internal method to attach a scene node to this Behaviour\n---@private\n---@param msg table Contains fields: value=nodeId, scriptName, scriptId\nfunction Behaviour:_setNode(msg)\n __assertTrace(type(msg) == 'table', \"_setNode() called with nil or a non-table.\")\n\n if self.node then\n error(\"Node is already set on behaviour!\")\n end\n\n local nodeId = msg.value\n __assertTrace(type(nodeId) == 'string', \"_setNode() needs a nodeId of type string.\")\n\n local node = SceneObject.findById(nodeId)\n __assertTrace(node, \"_setNode() node not found\")\n\n local scriptName = msg.scriptName\n __assertTrace(scriptName, \"_setNode() needs a scriptName\")\n\n local scriptId = msg.scriptId\n __assertTrace(scriptId, \"_setNode() needs a scriptId\")\n\n self.node = node\n self._nodeId = nodeId\n self._scriptName = msg.scriptName\n self._scriptId = scriptId\n\n _behavioursMapByScriptId[scriptId] = self\n\n if not _behavioursMapByNodeId[nodeId] then\n _behavioursMapByNodeId[nodeId] = {}\n end\n _behavioursMapByNodeId[nodeId][scriptId] = {\n node = node,\n scriptName = scriptName,\n behaviour = self\n }\nend\n\n--- Return the properties of this Behaviour as JSON\n---@private\n---@return string JSON string of properties\nfunction Behaviour:_getPropsJson()\n return JE(self:getProperties())\nend\n\n--- Returns the active state of the behaviour. If the owner item is inactive, so are all attached behaviours\n---@return boolean true, if active, othersise false\nfunction Behaviour:isActive()\n return self._isActive\nend\n\n--- Returns the initialized state of the behaviour. If true, init ran through or there is no init\n---@return boolean true, if initialized, othersise false\nfunction Behaviour:isInitialized()\n return self._isInitialized\nend\n\n--- Clears all registered behaviours (used internally). They are expected to be empty anyway due to scripts\n--- cleaning up behind themselves. This function will assert this\n---@private\nfunction Behaviour._clearBehaviours()\n -- Clear in-place to avoid any stale references to the _behaviours table object\n -- preventing Lua GC from reclaiming behaviour instances.\n for nodeId, nodeBehaviours in pairs(_behavioursMapByNodeId) do\n -- nodeBehaviours is a keyed table (scriptId -> { ... })\n if nodeBehaviours and next(nodeBehaviours) ~= nil then\n -- This warning is useful when scripts forget to dispose their behaviours,\n -- but the check previously used `#nodeBehaviours` which is incorrect for keyed tables.\n print(\"WARNING: Some behaviours did not get cleaned properly. This is an engine bug!\")\n -- Keep clearing anyway to enable GC.\n end\n\n if nodeBehaviours then\n for scriptId in pairs(nodeBehaviours) do\n nodeBehaviours[scriptId] = nil\n end\n end\n\n _behavioursMapByNodeId[nodeId] = nil\n end\n\n -- Also clear the second map that has the behaviours by their script ID directly\n _behavioursMapByScriptId = {}\nend\n\nfunction Behaviour:_init()\n if type(self.init) == 'function' then\n local ok, err = pcall(self.init, self)\n if not ok then\n print(self._scriptName .. \":init() failed:\", err)\n end\n end\n self._isInitialized = true\n self._isActive = true\nend\n\nfunction Behaviour:_ondisable()\n self._isActive = false\n if type(self.ondisable) == 'function' then\n local ok, err = pcall(self.ondisable, self)\n if not ok then\n print(self._scriptName .. \":ondisable() failed:\", err)\n end\n end\nend\n\nfunction Behaviour:_onenable()\n self._isActive = true\n if type(self.onenable) == 'function' then\n local ok, err = pcall(self.onenable, self)\n if not ok then\n print(self._scriptName .. \":onenable() failed:\", err)\n end\n end\nend\n\nfunction Behaviour:_ondestroy()\n if type(self.ondestroy) == 'function' then\n local ok, err = pcall(self.ondestroy, self)\n if not ok then\n print(self._scriptName .. \":ondestroy() failed:\", err)\n end\n end\n self._isActive = false\n self._isInitialized = false\nend\n\nfunction Behaviour._updateAll(deltaTime, deltaTimeSmooth)\n local callcount = 0\n\n for _, behaviour in pairs(_behavioursMapByScriptId) do\n if behaviour._isActive and behaviour._isInitialized and type(behaviour.update) == 'function' then\n callcount = callcount + 1\n local ok, err = pcall(behaviour.update, behaviour, deltaTime, deltaTimeSmooth)\n if not ok then\n print(behaviour._scriptName .. \":update() failed:\", err)\n end\n end\n\n -- call the deprecated prerender hook if it exists\n if behaviour._isActive and behaviour._isInitialized and type(behaviour.prerender) == 'function' then\n callcount = callcount + 1\n local ok, err = pcall(behaviour.prerender, behaviour)\n if not ok then\n print(behaviour._scriptName .. \":prerender() failed:\", err)\n end\n end\n end\n\n return callcount\nend\n\nfunction Behaviour._renderAll()\n local callcount = 0\n\n for _, behaviour in pairs(_behavioursMapByScriptId) do\n if behaviour._isActive and behaviour._isInitialized and type(behaviour.render) == 'function' then\n callcount = callcount + 1\n local ok, err = pcall(behaviour.render, behaviour, deltaTime, deltaTimeSmooth)\n if not ok then\n print(behaviour._scriptName .. \":render() failed:\", err)\n end\n end\n end\n\n Canvas.commit()\n\n return callcount\nend\n\nfunction Behaviour._renderguiAll()\n local callcount = 0\n\n for _, behaviour in pairs(_behavioursMapByScriptId) do\n if behaviour._isActive and behaviour._isInitialized and type(behaviour.rendergui) == 'function' then\n callcount = callcount + 1\n local ok, err = pcall(behaviour.rendergui, behaviour, deltaTime, deltaTimeSmooth)\n if not ok then\n print(behaviour._scriptName .. \":rendergui() failed:\", err)\n end\n end\n end\n\n return callcount\nend\n\nfunction Behaviour._setActive(nodes)\n for scriptId, active in pairs(nodes) do\n local node = _behavioursMapByScriptId[scriptId]\n if node then\n node._isActive = active\n else\n print(\"ERROR: Behaviour._setActive() cannot find script: \" .. scriptId)\n end\n end\nend\n\nfunction Behaviour._debugStats()\n local nodeCount = 0\n local behaviourCount = 0\n for _, nodeBehaviours in pairs(_behavioursMapByNodeId) do\n nodeCount = nodeCount + 1\n if nodeBehaviours then\n for _ in pairs(nodeBehaviours) do\n behaviourCount = behaviourCount + 1\n end\n end\n end\n\n return {\n nodeCount = nodeCount,\n behaviourCount = behaviourCount\n }\nend\n\nreturn Behaviour\n";
|
|
97457
|
+
var lua_api_behaviour = "local SceneObject = require('engine/sceneobject')\nlocal Canvas = require('engine/canvas')\nlocal JE = require('engine/json/jsonencoder')()\n\nlocal _behavioursMapByNodeId = {}\nlocal _behavioursMapByScriptId = {}\nlocal _behavioursMapByExecutionOrder = {}\nlocal _executionIndex = 1\n\nlocal Behaviour = Class.new()\n\n-- Put the class in the global scope (Behaviour is the old deprecated name)\n_G.Behaviour = Behaviour\n_G.Entity = Behaviour\n\n--- Constructor hook called when a new Behaviour is created.\n---@private\nfunction Behaviour:__new()\n self._isBehaviour = true\n self._type = \"Behaviour\"\n self._nodeId = nil\n self._scriptName = \"\"\n self._executionIndex = _executionIndex\n self._isActive = true\n self._isInitialized = false\n\n _executionIndex = _executionIndex + 1\n\n -- Adds a default node property\n self:addProperty(\"node\", Property.Node)\nend\n\n--- Destructor hook called before the Behaviour is destroyed.\n---@private\nfunction Behaviour:__destroy()\n print(\"__destroy called for: \", self._nodeId)\nend\n\n--- Get all behaviours attached to a specific node ID.\n---@param nodeId string The ID of the scene graph node\n---@return table A table containing all behaviours attached to the node\nfunction Behaviour.getByNodeId(nodeId)\n local result = {}\n local nodeBehaviours = _behavioursMapByNodeId[nodeId]\n if nodeBehaviours then\n for k,v in pairs(nodeBehaviours) do\n table.insert(result, v.behaviour)\n end\n end\n return result\nend\n\n--- Get a single behaviour attached to a node ID with a specific script name.\n---@param nodeId string The ID of the scene graph node\n---@param scriptName string The script name of the behaviour\n---@return Behaviour|nil The behaviour if found, or nil\nfunction Behaviour.getByNodeIdAndScriptName(nodeId, scriptName)\n local nodeEntities = _behavioursMapByNodeId[nodeId]\n if nodeEntities then\n for k,v in pairs(nodeEntities) do\n if v.scriptName == scriptName then\n return v.behaviour\n end\n end\n end\n return nil\nend\n\n--- Returns the node ID this Behaviour is attached to.\n---@return string|nil Node ID of the attached scene object\nfunction Behaviour:getNodeId()\n return self._nodeId\nend\n\n--- Returns the script name of this Behaviour.\n---@return string Script name\nfunction Behaviour:getScriptName()\n return self._scriptName\nend\n\n--- Returns a table of all properties defined on the behaviour class.\n---@return table A table with fields: name, defaultValue, type, order\nfunction Behaviour:getProperties()\n local props = {}\n local class = self.getClass()\n\n for k,v in pairs(class) do\n if type(v) == 'table' and v._isProperty then\n table.insert(props, { name=k, defaultValue=v.value, type=v.datatype, order=v.order, info=v.info })\n end\n end\n\n for k,v in pairs(class.properties) do\n if type(v) == 'table' and v._isProperty then\n table.insert(props, { name=k, defaultValue=v.value, type=v.datatype, order=v.order, info=v.info })\n end\n end\n\n return props\nend\n\n--- When a script is destroyed, we need to call this to clear the behaviour out of the list\n---@private\nfunction Behaviour:_disposeBehaviour()\n local scripts = _behavioursMapByNodeId[self._nodeId]\n if scripts then\n scripts[self._scriptId] = nil\n end\n\n _behavioursMapByScriptId[self._scriptId] = nil\n _behavioursMapByExecutionOrder[self._executionIndex] = nil\nend\n\n--- Internal setter for a property\n---@private\n---@param name string Property name\n---@param value any Value to set\nfunction Behaviour:_setProperty(name, value)\n self[name] = value\nend\n\n--- Internal method to attach a scene node to this Behaviour\n---@private\n---@param msg table Contains fields: value=nodeId, scriptName, scriptId\nfunction Behaviour:_setNode(msg)\n __assertTrace(type(msg) == 'table', \"_setNode() called with nil or a non-table.\")\n\n if self.node then\n error(\"Node is already set on behaviour!\")\n end\n\n local nodeId = msg.value\n __assertTrace(type(nodeId) == 'string', \"_setNode() needs a nodeId of type string.\")\n\n local node = SceneObject.findById(nodeId)\n __assertTrace(node, \"_setNode() node not found\")\n\n local scriptName = msg.scriptName\n __assertTrace(scriptName, \"_setNode() needs a scriptName\")\n\n local scriptId = msg.scriptId\n __assertTrace(scriptId, \"_setNode() needs a scriptId\")\n\n self.node = node\n self._nodeId = nodeId\n self._scriptName = msg.scriptName\n self._scriptId = scriptId\n\n _behavioursMapByScriptId[scriptId] = self\n _behavioursMapByExecutionOrder[self._executionIndex] = self\n\n if not _behavioursMapByNodeId[nodeId] then\n _behavioursMapByNodeId[nodeId] = {}\n end\n _behavioursMapByNodeId[nodeId][scriptId] = {\n node = node,\n scriptName = scriptName,\n behaviour = self\n }\nend\n\n--- Return the properties of this Behaviour as JSON\n---@private\n---@return string JSON string of properties\nfunction Behaviour:_getPropsJson()\n return JE(self:getProperties())\nend\n\n--- Returns the active state of the behaviour. If the owner item is inactive, so are all attached behaviours\n---@return boolean true, if active, othersise false\nfunction Behaviour:isActive()\n return self._isActive\nend\n\n--- Returns the initialized state of the behaviour. If true, init ran through or there is no init\n---@return boolean true, if initialized, othersise false\nfunction Behaviour:isInitialized()\n return self._isInitialized\nend\n\n--- Clears all registered behaviours (used internally). They are expected to be empty anyway due to scripts\n--- cleaning up behind themselves. This function will assert this\n---@private\nfunction Behaviour._clearBehaviours()\n -- Clear in-place to avoid any stale references to the _behaviours table object\n -- preventing Lua GC from reclaiming behaviour instances.\n for nodeId, nodeBehaviours in pairs(_behavioursMapByNodeId) do\n -- nodeBehaviours is a keyed table (scriptId -> { ... })\n if nodeBehaviours and next(nodeBehaviours) ~= nil then\n -- This warning is useful when scripts forget to dispose their behaviours,\n -- but the check previously used `#nodeBehaviours` which is incorrect for keyed tables.\n print(\"WARNING: Some behaviours did not get cleaned properly. This is an engine bug!\")\n -- Keep clearing anyway to enable GC.\n end\n\n if nodeBehaviours then\n for scriptId in pairs(nodeBehaviours) do\n nodeBehaviours[scriptId] = nil\n end\n end\n\n _behavioursMapByNodeId[nodeId] = nil\n end\n\n -- Also clear the second map that has the behaviours by their script ID directly and the execution order map\n _behavioursMapByScriptId = {}\n _behavioursMapByExecutionOrder = {}\n _executionIndex = 1\nend\n\nfunction Behaviour:_init()\n if type(self.init) == 'function' then\n local ok, err = pcall(self.init, self)\n if not ok then\n print(self._scriptName .. \":init() failed:\", err)\n end\n end\n self._isInitialized = true\n self._isActive = true\nend\n\nfunction Behaviour:_ondisable()\n self._isActive = false\n if type(self.ondisable) == 'function' then\n local ok, err = pcall(self.ondisable, self)\n if not ok then\n print(self._scriptName .. \":ondisable() failed:\", err)\n end\n end\nend\n\nfunction Behaviour:_onenable()\n self._isActive = true\n if type(self.onenable) == 'function' then\n local ok, err = pcall(self.onenable, self)\n if not ok then\n print(self._scriptName .. \":onenable() failed:\", err)\n end\n end\nend\n\nfunction Behaviour:_ondestroy()\n if type(self.ondestroy) == 'function' then\n local ok, err = pcall(self.ondestroy, self)\n if not ok then\n print(self._scriptName .. \":ondestroy() failed:\", err)\n end\n end\n self._isActive = false\n self._isInitialized = false\nend\n\nfunction Behaviour._callHookOnAll(hookName, deltaTime, deltaTimeSmooth)\n local callcount = 0\n\n for _, behaviour in pairs(_behavioursMapByExecutionOrder) do\n local hookFunc = behaviour[hookName]\n if behaviour._isActive and behaviour._isInitialized and type(hookFunc) == 'function' then\n callcount = callcount + 1\n local ok, err = pcall(hookFunc, behaviour, deltaTime, deltaTimeSmooth)\n if not ok then\n print(behaviour._scriptName .. \":\" .. hookName .. \"() failed:\", err)\n end\n end\n end\n\n return callcount\nend\n\nfunction Behaviour._updateAll(deltaTime, deltaTimeSmooth)\n local callcount = 0\n\n callcount = callcount + Behaviour._callHookOnAll(\"preUpdate\", deltaTime, deltaTimeSmooth)\n callcount = callcount + Behaviour._callHookOnAll(\"update\", deltaTime, deltaTimeSmooth)\n callcount = callcount + Behaviour._callHookOnAll(\"lateUpdate\", deltaTime, deltaTimeSmooth)\n\n return callcount\nend\n\nfunction Behaviour._renderAll()\n\n if Canvas.autoClear then\n Canvas.clear()\n end\n\n local callcount = 0\n\n callcount = Behaviour._callHookOnAll(\"prerender\")\n callcount = Behaviour._callHookOnAll(\"render\")\n\n Canvas.commit()\n\n return callcount\nend\n\nfunction Behaviour._renderguiAll()\n return Behaviour._callHookOnAll(\"rendergui\")\nend\n\nfunction Behaviour._setActive(nodes)\n for scriptId, active in pairs(nodes) do\n local behaviour = _behavioursMapByScriptId[scriptId]\n if behaviour then\n behaviour._isActive = active\n else\n print(\"ERROR: Behaviour._setActive() cannot find script: \" .. scriptId)\n end\n end\nend\n\nfunction Behaviour._debugStats()\n local nodeCount = 0\n local behaviourCount = 0\n for _, nodeBehaviours in pairs(_behavioursMapByNodeId) do\n nodeCount = nodeCount + 1\n if nodeBehaviours then\n for _ in pairs(nodeBehaviours) do\n behaviourCount = behaviourCount + 1\n end\n end\n end\n\n return {\n nodeCount = nodeCount,\n behaviourCount = behaviourCount\n }\nend\n\nreturn Behaviour\n";
|
|
97457
97458
|
|
|
97458
|
-
var lua_api_canvas = "\nlocal _internal = require('engine/_internal');\n\n---@module canvas\nlocal canvas = {}\n\n-- Lua-side command buffer for canvas calls.\nlocal _cmds = {}\n\nlocal function _captureSendMessage(target, payload, buffers)\n table.insert(_cmds, {\n target = target,\n payload = payload,\n buffers = buffers\n })\n return nil\nend\n\nlocal function _runWithCapturedSend(fn, ...)\n local oldSendMessage = _internal.sendMessage\n _internal.sendMessage = _captureSendMessage\n\n local result = { pcall(fn, ...) }\n\n _internal.sendMessage = oldSendMessage\n\n if not result[1] then\n error(result[2])\n end\n\n return table.unpack(result, 2)\nend\n\nlocal function _commitIfNeeded()\n if #_cmds == 0 then\n return { committed = 0 }\n end\n\n local result = _internal.sendMessage('canvas.commit', { cmds = _cmds })\n _cmds = {}\n return result\nend\n\n---Commit all pending buffered canvas commands.\n---@return table|nil result Optional engine-side debug info.\nfunction canvas.commit()\n return _commitIfNeeded()\nend\n\n---Debug helper: returns count of pending buffered commands in Lua.\n---@return number\nfunction canvas.getPendingCommandCount()\n return #_cmds\nend\n\n---Debug helper: returns current pending buffered commands in Lua.\n---@return table\nfunction canvas.getPendingCommands()\n return _cmds\nend\n\n---Debug helper: returns most recently committed command list on engine side.\n---@return table\nfunction canvas.getLastCommittedCommands()\n _commitIfNeeded()\n return _internal.sendMessage('canvas.getLastCommittedCommands')\nend\n\n---Clear the canvas.\n---@function\nfunction canvas.clear()\n _internal.sendMessage('canvas.clear')\nend\n\n---Returns the width of the canvas in pixels.\n---@function\nfunction canvas.getWidth()\n return _internal.sendMessage('canvas.getWidth')\nend\n\n---Returns the height of the canvas in pixels.\n---@function\nfunction canvas.getHeight()\n return _internal.sendMessage('canvas.getHeight')\nend\n\n---Sets the width of lines in the canvas.\n---@param w number the width to set the lines to.\nfunction canvas.setLineWidth(w)\n _internal.sendMessage('canvas.setLineWidth', { w=w })\nend\n\n---Sets the type of endings applied to the ends of a line.\n---@param cap string the type of corner to create on a line. One of \"butt\", \"round\", \"square\".\nfunction canvas.setLineCap(cap)\n _internal.sendMessage('canvas.setLineCap', { cap=cap })\nend\n\n---Sets the type of corner created when two lines meet.\n---@param join string the type of connection to create between two lines. One of \"bevel\", \"round\", or \"miter\".\nfunction canvas.setLineJoin(join)\n _internal.sendMessage('canvas.setLineJoin', { join=join })\nend\n\n---Sets the maximum miter length. Miter length is the distance between the inner corner and the outer corner of the join.\n---@param limit number the maximum miter length. When the miter length exceeds this value, the corner is trimmed.\nfunction canvas.setMiterLimit(limit)\n _internal.sendMessage('canvas.setMiterLimit', { limit=limit })\nend\n\n---Sets the color of the stroke (outline) for shapes drawn on the canvas.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setStrokeColor(r, g, b, a)\n _internal.sendMessage('canvas.setStrokeColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the color that is used to fill in shapes and text when they are drawn on the canvas.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setFillColor(r, g, b, a)\n _internal.sendMessage('canvas.setFillColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the color to use for shadows.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setShadowColor(r, g, b, a)\n _internal.sendMessage('canvas.setShadowColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the blur level for shadows.\n---@param level number the level of blur to be applied to shadows (in pixels).\nfunction canvas.setShadowBlurLevel(level)\n _internal.sendMessage('canvas.setShadowBlurLevel', { level=level })\nend\n\n---Sets the blur level for shadows.\n---@param x number the vertical offset of the shadow in pixels.\n---@param y number the horizontal offset of the shadow in pixels.\nfunction canvas.setShadowOffset(x, y)\n _internal.sendMessage('canvas.setShadowOffset', { x=x, y=y })\nend\n\n---Begins a new path.\n---@function\nfunction canvas.beginPath()\n _internal.sendMessage('canvas.beginPath')\nend\n\n---Close the current path by connecting the last and first point in the path, creating a loop.\n---@function\nfunction canvas.closePath()\n _internal.sendMessage('canvas.closePath')\nend\n\n---Determines if the specified point is in the current path.\n---@param x number x-coordinate of the point to check.\n---@param y number y-coordinate of the point to check.\n---@return boolean indicating if the point is in the path or not.\nfunction canvas.isPointInPath(x, y)\n return _internal.sendMessage('canvas.isPointInPath', { x=x, y=y })\nend\n\n---Sets the clipping path to the current drawing path.\n---@function\nfunction canvas.clip()\n _internal.sendMessage('canvas.clip')\nend\n\n---Draws the outline of a shape or path using the current stroke style, line width and styles.\n---@function\nfunction canvas.stroke()\n _internal.sendMessage('canvas.stroke')\nend\n\n---Fills a shape or path with the current fill style.\n---@function\nfunction canvas.fill()\n _internal.sendMessage('canvas.fill')\nend\n\n---Moves the current drawing position to the specified coordinates.\n---@param x number x-coordinate of the new current drawing position.\n---@param y number y-coordinate of the new current drawing position.\nfunction canvas.moveTo(x, y)\n _internal.sendMessage('canvas.moveTo', { x=x, y=y })\nend\n\n---Draws a straight line from the current position to the specified coordinates.\n---@param x number the x-coordinate to draw the line to.\n---@param y number the y-coordinate to draw the line to.\nfunction canvas.lineTo(x, y)\n _internal.sendMessage('canvas.lineTo', { x=x, y=y })\nend\n\n---Sets the type of compositing operation to apply when drawing new shapes.\n---@param operation string the compositing operation to use, possible values are:\n---\"source-over\", \"source-in\", \"source-out\", \"source-atop\", \"destination-over\",\n---\"destination-in\", \"destination-out\", \"destination-atop\", \"lighter\", \"copy\", \"xor\".\nfunction canvas.setCompositeOperation(operation)\n _internal.sendMessage('canvas.setCompositeOperation', { operation=operation })\nend\n\n---Sets the transparency value that is applied to all rendering operations.\n---@param value number a value between 0.0 (fully transparent) and 1.0 (fully opaque).\nfunction canvas.setGlobalAlpha(value)\n _internal.sendMessage('canvas.setGlobalAlpha', { value=value })\nend\n\n---Creates a rectangle path which is only drawn after calling stroke() or fill().\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.pathRect(x, y, w, h)\n _internal.sendMessage('canvas.pathRect', { x=x, y=y, w=w, h=h })\nend\n\n---Adds a rounded rectangle to the current path. Must be followed by stroke() or fill().\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\n---@param radius number|table corner radius applied to all four corners (uniform), or a table\n---of 1–4 values to set individual corner radius in the order [top-left, top-right,\n---bottom-right, bottom-left], following the HTML Canvas API specification.\nfunction canvas.roundRect(x, y, w, h, radius)\n _internal.sendMessage('canvas.roundRect', { x=x, y=y, w=w, h=h, radius=radius })\nend\n\n---Draw a rectangle outline using the current stroke style.\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.strokeRect(x, y, w, h)\n _internal.sendMessage('canvas.strokeRect', { x=x, y=y, w=w, h=h })\nend\n\n---Draw a rectangle with a filled interior using the current fill style,\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.fillRect(x, y, w, h)\n _internal.sendMessage('canvas.fillRect', { x=x, y=y, w=w, h=h })\nend\n\n---Clears the specified rectangle by setting its pixels to transparent.\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.clearRect(x, y, w, h)\n _internal.sendMessage('canvas.clearRect', { x=x, y=y, w=w, h=h })\nend\n\n---Draws a circle with given parameters. Must be followed by stroke() or fill().\n---@param x number x-coordinates of the center of the circle.\n---@param y number y-coordinates of the center of the circle.\n---@param r number the radius of the circle\nfunction canvas.circle(x, y, r)\n _internal.sendMessage('canvas.circle', { x=x, y=y, r=r })\nend\n\n---Draws an arc with given parameters. Must be followed by stroke() or fill().\n---@param x number x-coordinates of the center of the circle.\n---@param y number y-coordinates of the center of the circle.\n---@param r number the radius of the circle.\n---@param startAngle number the starting angle in radians.\n---@param endAngle number the ending angle, in radians.\n---@param anticlockwise boolean a flag which specifies whether the drawing should be counterclockwise or clockwise.\nfunction canvas.arc(x, y, r, startAngle, endAngle, anticlockwise)\n _internal.sendMessage('canvas.arc', { x=x, y=y, r=r, startAngle=startAngle,\n endAngle=endAngle, anticlockwise=anticlockwise })\nend\n\n---Adds a quadratic Bézier curve to the path with given control point and end point.\n---@param cpx number x-coordinate of the control point.\n---@param cpy number y-coordinate of the control point.\n---@param x number x-coordinate of the end point.\n---@param y number y-coordinate of the end point.\nfunction canvas.quadraticCurve(cpx, cpy, x, y)\n _internal.sendMessage('canvas.quadraticCurve', { cpx=cpx, cpy=cpy, x=x, y=y })\nend\n\n---Draws a bezier curve from the current position to the specified point, using the specified control points.\n---@param cp1x number x-coordinate of the first control point.\n---@param cp1y number y-coordinate of the first control point.\n---@param cp2x number x-coordinate of the second control point.\n---@param cp2y number y-coordinate of the second control point.\n---@param x number x-coordinate of the end point.\n---@param y number y-coordinate of the end point.\nfunction canvas.bezierCurve(cp1x, cp1y, cp2x, cp2y, x, y)\n _internal.sendMessage('canvas.bezierCurve', { cp1x=cp1x, cp1y=cp1y,\n cp2x=cp2x, cp2y=cp2y,\n x=x, y=y })\nend\n\n---@class Gradient\n---A class to internally link gradient objects from the Lua environment to Lumino codebase.\n---A Gradient object can be create using @{createLinearGradient} or @{createRadialGradient}\n---@private\nlocal Gradient = {}\n\n---Creates a new gradient object with the given index\n---@param idx number index of the gradient object\n---@private\nfunction Gradient:new(idx)\n -- Store the gradient object in a field of the class instance metatable\n local obj = { idx = idx}\n Class.__setmetatable(obj, self)\n self.__index = self\n -- Return the instance\n return obj\nend\n\n---Hook that runs before an object is deleted by the garbage collector.\n---It calls a function to delete the gradient object in JS\n---@private\nfunction Gradient:__gc()\n -- Keep deletion ordering deterministic when gradient operations are buffered.\n _commitIfNeeded()\n _internal.sendMessage('canvas.deleteGradient', { gradientIdx = self.idx })\nend\n-- Add the Gradient class to the Canvas namespace\ncanvas.Gradient = Gradient\n\n---Sets a gradient object to active.\n---@param gradient Gradient a gradient object\nfunction canvas.setGradientActive(gradient)\n if gradient.idx >= 0 then\n _internal.sendMessage('canvas.setGradientActive', { gradientIdx = gradient.idx })\n end\nend\n\n---Adds a new stop, defined by an offset and a color, to a gradient object.\n---@param gradient Gradient a gradient object\n---@param offset number a value between 0.0 and 1.0 where the new color stop is positioned.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.colorStop(gradient, offset, r, g, b, a)\n _internal.sendMessage('canvas.colorStop', { gradientIdx=gradient.idx, offset=offset, r=r, g=g, b=b, a=a })\nend\n\n---Creates a linear gradient object.\n---@param x1 number the x-coordinate of the start point of the gradient\n---@param y1 number the y-coordinate of the start point of the gradient\n---@param x2 number the x-coordinate of the end point of the gradient\n---@param y2 number the y-coordinate of the end point of the gradient\n---@return Gradient a new gradient object\n---@usage local gradient = Canvas.createLinearGradient(0, 0, 50, 0)\nfunction canvas.createLinearGradient(x1, y1, x2, y2)\n local idx = _internal.sendMessage('canvas.createLinearGradient', { x1=x1, y1=y1,\n x2=x2, y2=y2 })\n local gradient = Gradient:new(idx)\n return gradient\nend\n\n---Creates a radial gradient object.\n---@param x1 number x-coordinate of the start circle\n---@param y1 number y-coordinate of the start circle\n---@param r1 number radius of the start circle\n---@param x2 number x-coordinate of the end circle\n---@param y2 number y-coordinate of the end circle\n---@param r2 number radius of the end circle\n---@return Gradient a new gradient object\nfunction canvas.createRadialGradient(x1, y1, r1, x2, y2, r2)\n local idx = _internal.sendMessage('canvas.createRadialGradient', { x1=x1, y1=y1, r1=r1,\n x2=x2, y2=y2, r2=r2})\n local gradient = Gradient:new(idx)\n return gradient\nend\n\n---Returns an array with strings of all available fonts. This will list all custom loaded fonts through Loader.loadFont and\n---fonts registered in Canvas Fonts in your project. It will also probe for common system fonts although the list might not be complete.\n---It is strongly recommended to use only custom uploaded fonts to have reliable results on all platforms.\n---@return table an array with all the available fonts as strings\nfunction canvas.getAvailableFonts()\n return _internal.sendMessage('canvas.getAvailableFonts')\nend\n\n---Sets a font style.\n---@param font string The font style to be set, in the format of 'font-style font-size font-family'. Example: 'italic 20px Arial'.\nfunction canvas.setFont(font)\n _internal.sendMessage('canvas.setFont', { font=font })\nend\n\n---Sets the current text alignment\n---@param align string The new text alignment to be set. One of 'start', 'end', 'left', 'right', or 'center'.\nfunction canvas.setTextAlign(align)\n _internal.sendMessage('canvas.setTextAlign', { align=align })\nend\n\n---Sets the text baseline used when drawing text.\n---@param baseline string The text baseline to set. One of 'alphabetic', 'top', 'hanging', 'middle', 'ideographic', or 'bottom'.\nfunction canvas.setTextBaseline(baseline)\n _internal.sendMessage('canvas.setTextBaseline', { baseline=baseline })\nend\n\n---Measures the width of the specified text in pixels.\n---@param text string The text to measure.\nfunction canvas.measureTextWidth(text)\n return _internal.sendMessage('canvas.measureTextWidth', { text=text })\nend\n\n---Draws and fills a given text string at the specified coordinates.\n---@param text string The text string to be drawn and filled.\n---@param x number The x-coordinate where the text will be drawn.\n---@param y number The y-coordinate where the text will be drawn.\nfunction canvas.fillText(text, x, y)\n _internal.sendMessage('canvas.fillText', { text=text, x=x, y=y })\nend\n\n---Draws the outline of the given text at the specified coordinates.\n---@param text string The text string to be drawn.\n---@param x number The x-coordinate where the text will be drawn.\n---@param y number The y-coordinate where the text will be drawn.\nfunction canvas.strokeText(text, x, y)\n _internal.sendMessage('canvas.strokeText', { text=text, x=x, y=y })\nend\n\n-- -TODO: ImageData is not yet ready for deployment because using it for pixel manipulation would be\n-- -inefficient and slow due to the need for JSON communication with JavaScript. While JSON\n-- -communication is necessary for the security of the application, it is not well-suited for tasks\n-- -that require frequent or high-volume data transfer. It is better to use ImageData for low\n-- -frequency tasks such as updating UI and handling events, rather than trying to use it for more\n-- -demanding tasks that may be slowed down by the use of JSON objects.\n\n-- --- Image class to link imageData objects in the canvas to Lua\n-- ---@class imageData\n-- local Image = {}\n\n-- --- Creates a new Image object with the given index\n-- ---@param idx number index of the imageData object in the canvas\n-- function Image:new(idx)\n-- local obj = {}\n-- Class.__setmetatable(obj, self)\n-- self.__index = self\n-- self.idx = idx\n-- return obj\n-- end\n-- canvas.Image = Image\n\n-- ---Creates a new, blank Image object with the specified dimensions.\n-- ---All of the pixels in the new object are transparent black.\n-- ---@param width number the width of the Image object\n-- ---@param height number the height of the Image object\n-- ---@return Image a new Image object\n-- function canvas.createImage(width, height)\n-- local idx = _internal.sendMessage('canvas.createImage', { width=width, height=height })\n-- local image = Image:new(idx)\n-- return image\n-- end\n\n-- ---Write the RGBA channels of an Image object\n-- ---@param r number the r channel of the Image object\n-- ---@param g number the g channel of the Image object\n-- ---@param b number the b channel of the Image object\n-- ---@param a number the a channel of the Image object\n-- function canvas.writeImageChannels(image, r, g, b, a)\n-- _internal.sendMessage('canvas.writeImageChannels', { imageIdx=image.idx, r=r, g=g, b=b, a=a })\n-- end\n\n-- ---Draws an image given by an url at the specified position and dimensions.\n-- ---@param url string\n-- ---@param x number\n-- ---@param y number\n-- ---@param width number\n-- ---@param height number\n-- function canvas.drawImageFromUrl(url, x, y, width, height)\n-- _internal.sendMessage('canvas.drawImageFromUrl', { url=url, x=x, y=y, width=width, height=height })\n-- end\n\n-- ---Repeats a given image on the canvas with a given pattern.\n-- ---@param image imageSource an image object\n-- ---@param repeat string one of repeat, repeat-x, repeat-y, no-repeat\n-- function canvas.imagePattern(image, repeatPattern)\n-- _internal.sendMessage('canvas.pattern', { image=image, repeatPattern=repeatPattern })\n-- end\n\n---Draws the image data at the given coordinates.\n---@param image Texture the image data to paint\n---@param x number x-coordinate of the top left corner where the image data will be painted\n---@param y number y-coordinate of the top left corner where the image data will be painted\n---@param width number width of the image on screen (optional)\n---@param height number height of the image on screen (optional)\n---@param mode number mode to use for stretching. possible values are 0 = stretch, 1 = fit, 2 = cover\nfunction canvas.drawImage(image, x, y, width, height, mode)\n __assertTrace(image and image._isTexture, \"image is not a Texture object\")\n _internal.sendMessage('canvas.drawImage', { image= image._handle, x=x, y=y, width=width, height=height, mode=mode })\nend\n\n---Draws the image data at the given coordinates.\n---@param image Texture the image data to paint\n---@param x number x-coordinate of the top left corner where the image data will be painted\n---@param y number y-coordinate of the top left corner where the image data will be painted\n---@param width number width of the image on screen (optional)\n---@param height number height of the image on screen (optional)\nfunction canvas.drawSubImage(image, x, y, width, height, sourceX, sourceY, sourceWidth, sourceHeight)\n __assertTrace(image and image._isTexture, \"image is not a Texture object\")\n _internal.sendMessage('canvas.drawSubImage', { image= image._handle,\n x=x, y=y, width=width, height=height,\n sourceX=sourceX, sourceY=sourceY, sourceWidth=sourceWidth, sourceHeight=sourceHeight })\nend\n\n--- Scales the canvas by the specified factors along the x and y axes.\n--- Transformations are applied relative to the canvas origin (0,0).\n--- To scale around a different point, use `translate()` to move the origin before scaling.\n---@param x number Scale factor along the x-axis.\n---@param y number Scale factor along the y-axis.\nfunction canvas.scale(x, y)\n _internal.sendMessage('canvas.scale', { x=x, y=y })\nend\n\n--- Rotates the canvas by the specified angle in radians.\n--- Rotation is performed around the canvas origin (0,0).\n--- To rotate around a different point, translate the canvas to that point before calling rotate().\n---@param a number Angle in radians.\nfunction canvas.rotate(a)\n _internal.sendMessage('canvas.rotate', { a=a })\nend\n\n\n--- Moves (translates) the canvas origin by the specified amounts.\n--- All subsequent drawing and transformations (scale, rotate, etc.) are relative to the new origin.\n---@param x number Amount to translate along the x-axis.\n---@param y number Amount to translate along the y-axis.\nfunction canvas.translate(x, y)\n _internal.sendMessage('canvas.translate', { x=x, y=y })\nend\n\n---Applies a 2D transformation matrix to the canvas.\n---@param horizontal_scale number The amount to scale horizontally.\n---@param horizontal_skew number The amount of horizontal skew.\n---@param vertical_skew number The amount of vertical skew.\n---@param vertical_scale number The amount to scale vertically.\n---@param horizontal_translation number The amount of horizontal translation.\n---@param vertical_translation number The amount of vertical translation.\nfunction canvas.transform(horizontal_scale, horizontal_skew, vertical_skew,\n vertical_scale, horizontal_translation, vertical_translation)\n _internal.sendMessage('canvas.transform', { a=horizontal_scale, b=horizontal_skew,\n c=vertical_skew, d=vertical_scale,\n e=horizontal_translation, f=vertical_translation })\nend\n\n---Resets the current canvas transform to the identity matrix and then invokes the transform() function with the given parameters.\n---@param horizontal_scale number The amount to scale horizontally.\n---@param horizontal_skew number The amount of horizontal skew.\n---@param vertical_skew number The amount of vertical skew.\n---@param vertical_scale number The amount to scale vertically.\n---@param horizontal_translation number The amount of horizontal translation.\n---@param vertical_translation number The amount of vertical translation.\nfunction canvas.resetAndSetTransform(horizontal_scale, horizontal_skew, vertical_skew,\n vertical_scale, horizontal_translation, vertical_translation)\n _internal.sendMessage('canvas.resetAndSetTransform', { a=horizontal_scale, b=horizontal_skew,\n c=vertical_skew, d=vertical_scale,\n e=horizontal_translation, f=vertical_translation })\nend\n\n---Reset the transformation matrix to the identity matrix.\n---@function\nfunction canvas.resetTransform()\n _internal.sendMessage('canvas.resetTransform')\nend\n\n---Pushes the current canvas state to a stack so that you can restore it.\n---This can be useful for performing multiple transformations or styles on the canvas, and\n---then restoring it to its original state. The canvas state in fact includes current transformation matrix\n---stroke and fill styles, shadow styles, and other attributes. To restore the canvas state you call\n---the restoreState() function.\n---@function\nfunction canvas.saveState()\n _internal.sendMessage('canvas.saveState')\nend\n\n---Pops the the most recently saved canvas from the saved state stack and restores it.\n---@function\nfunction canvas.restoreState()\n _internal.sendMessage('canvas.restoreState')\nend\n\n--- Resets the canvas to its default state, clearing the canvas and restoring all\n--- context -properties (transforms, styles, clipping region, etc.) to their\n--- defaults. Reset() is more thorough than -calling clear() alone, which only\n--- erases pixels but leaves context state intact.\n---@function\nfunction canvas.reset()\n _internal.sendMessage('canvas.reset')\nend\n\n-- Automatically wrap canvas methods for buffering, so non-query calls are queued\n-- and query/result-producing calls force an immediate commit first.\nlocal _passthroughMethods = {\n commit = true,\n getPendingCommandCount = true,\n getPendingCommands = true,\n}\n\nlocal _immediateMethods = {\n getLastCommittedCommands = true,\n getWidth = true,\n getHeight = true,\n isPointInPath = true,\n createLinearGradient = true,\n createRadialGradient = true,\n getAvailableFonts = true,\n measureTextWidth = true,\n}\n\nfor name, fn in pairs(canvas) do\n if type(fn) == \"function\" and name ~= \"Gradient\" then\n if _passthroughMethods[name] then\n -- keep as-is\n elseif _immediateMethods[name] then\n canvas[name] = function(...)\n _commitIfNeeded()\n return fn(...)\n end\n else\n canvas[name] = function(...)\n return _runWithCapturedSend(fn, ...)\n end\n end\n end\nend\n\nreturn canvas\n";
|
|
97459
|
+
var lua_api_canvas = "\nlocal _internal = require('engine/_internal');\n\n---@module canvas\nlocal canvas = {\n autoClear = false\n}\n\n-- Lua-side command buffer for canvas calls.\nlocal _cmds = {}\n\nlocal function _captureSendMessage(target, payload, buffers)\n table.insert(_cmds, {\n target = target,\n payload = payload,\n buffers = buffers\n })\n return nil\nend\n\nlocal function _runWithCapturedSend(fn, ...)\n local oldSendMessage = _internal.sendMessage\n _internal.sendMessage = _captureSendMessage\n\n local result = { pcall(fn, ...) }\n\n _internal.sendMessage = oldSendMessage\n\n if not result[1] then\n error(result[2])\n end\n\n return table.unpack(result, 2)\nend\n\nlocal function _commitIfNeeded()\n if #_cmds == 0 then\n return { committed = 0 }\n end\n\n local result = _internal.sendMessage('canvas.commit', { cmds = _cmds })\n _cmds = {}\n return result\nend\n\n---If set to true, the canvas will automatically clear once before the render hook is called\n---@param value boolean the flag value\nfunction canvas.setAutoClear(value)\n self.autoClear = value\nend\n\n---Returns the value of the auto clear flag\n---@return boolean the flag value\nfunction canvas.getAutoClear()\n return self.autoClear\nend\n\n---Commit all pending buffered canvas commands.\n---@return table|nil result Optional engine-side debug info.\nfunction canvas.commit()\n return _commitIfNeeded()\nend\n\n---Debug helper: returns count of pending buffered commands in Lua.\n---@return number\nfunction canvas.getPendingCommandCount()\n return #_cmds\nend\n\n---Debug helper: returns current pending buffered commands in Lua.\n---@return table\nfunction canvas.getPendingCommands()\n return _cmds\nend\n\n---Debug helper: returns most recently committed command list on engine side.\n---@return table\nfunction canvas.getLastCommittedCommands()\n _commitIfNeeded()\n return _internal.sendMessage('canvas.getLastCommittedCommands')\nend\n\n---Clear the canvas.\n---@function\nfunction canvas.clear()\n _internal.sendMessage('canvas.clear')\nend\n\n---Returns the width of the canvas in pixels.\n---@function\nfunction canvas.getWidth()\n return _internal.sendMessage('canvas.getWidth')\nend\n\n---Returns the height of the canvas in pixels.\n---@function\nfunction canvas.getHeight()\n return _internal.sendMessage('canvas.getHeight')\nend\n\n---Sets the width of lines in the canvas.\n---@param w number the width to set the lines to.\nfunction canvas.setLineWidth(w)\n _internal.sendMessage('canvas.setLineWidth', { w=w })\nend\n\n---Sets the type of endings applied to the ends of a line.\n---@param cap string the type of corner to create on a line. One of \"butt\", \"round\", \"square\".\nfunction canvas.setLineCap(cap)\n _internal.sendMessage('canvas.setLineCap', { cap=cap })\nend\n\n---Sets the type of corner created when two lines meet.\n---@param join string the type of connection to create between two lines. One of \"bevel\", \"round\", or \"miter\".\nfunction canvas.setLineJoin(join)\n _internal.sendMessage('canvas.setLineJoin', { join=join })\nend\n\n---Sets the maximum miter length. Miter length is the distance between the inner corner and the outer corner of the join.\n---@param limit number the maximum miter length. When the miter length exceeds this value, the corner is trimmed.\nfunction canvas.setMiterLimit(limit)\n _internal.sendMessage('canvas.setMiterLimit', { limit=limit })\nend\n\n---Sets the color of the stroke (outline) for shapes drawn on the canvas.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setStrokeColor(r, g, b, a)\n _internal.sendMessage('canvas.setStrokeColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the color that is used to fill in shapes and text when they are drawn on the canvas.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setFillColor(r, g, b, a)\n _internal.sendMessage('canvas.setFillColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the color to use for shadows.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.setShadowColor(r, g, b, a)\n _internal.sendMessage('canvas.setShadowColor', { r=r, g=g, b=b, a=a })\nend\n\n---Sets the blur level for shadows.\n---@param level number the level of blur to be applied to shadows (in pixels).\nfunction canvas.setShadowBlurLevel(level)\n _internal.sendMessage('canvas.setShadowBlurLevel', { level=level })\nend\n\n---Sets the blur level for shadows.\n---@param x number the vertical offset of the shadow in pixels.\n---@param y number the horizontal offset of the shadow in pixels.\nfunction canvas.setShadowOffset(x, y)\n _internal.sendMessage('canvas.setShadowOffset', { x=x, y=y })\nend\n\n---Begins a new path.\n---@function\nfunction canvas.beginPath()\n _internal.sendMessage('canvas.beginPath')\nend\n\n---Close the current path by connecting the last and first point in the path, creating a loop.\n---@function\nfunction canvas.closePath()\n _internal.sendMessage('canvas.closePath')\nend\n\n---Determines if the specified point is in the current path.\n---@param x number x-coordinate of the point to check.\n---@param y number y-coordinate of the point to check.\n---@return boolean indicating if the point is in the path or not.\nfunction canvas.isPointInPath(x, y)\n return _internal.sendMessage('canvas.isPointInPath', { x=x, y=y })\nend\n\n---Sets the clipping path to the current drawing path.\n---@function\nfunction canvas.clip()\n _internal.sendMessage('canvas.clip')\nend\n\n---Draws the outline of a shape or path using the current stroke style, line width and styles.\n---@function\nfunction canvas.stroke()\n _internal.sendMessage('canvas.stroke')\nend\n\n---Fills a shape or path with the current fill style.\n---@function\nfunction canvas.fill()\n _internal.sendMessage('canvas.fill')\nend\n\n---Moves the current drawing position to the specified coordinates.\n---@param x number x-coordinate of the new current drawing position.\n---@param y number y-coordinate of the new current drawing position.\nfunction canvas.moveTo(x, y)\n _internal.sendMessage('canvas.moveTo', { x=x, y=y })\nend\n\n---Draws a straight line from the current position to the specified coordinates.\n---@param x number the x-coordinate to draw the line to.\n---@param y number the y-coordinate to draw the line to.\nfunction canvas.lineTo(x, y)\n _internal.sendMessage('canvas.lineTo', { x=x, y=y })\nend\n\n---Sets the type of compositing operation to apply when drawing new shapes.\n---@param operation string the compositing operation to use, possible values are:\n---\"source-over\", \"source-in\", \"source-out\", \"source-atop\", \"destination-over\",\n---\"destination-in\", \"destination-out\", \"destination-atop\", \"lighter\", \"copy\", \"xor\".\nfunction canvas.setCompositeOperation(operation)\n _internal.sendMessage('canvas.setCompositeOperation', { operation=operation })\nend\n\n---Sets the transparency value that is applied to all rendering operations.\n---@param value number a value between 0.0 (fully transparent) and 1.0 (fully opaque).\nfunction canvas.setGlobalAlpha(value)\n _internal.sendMessage('canvas.setGlobalAlpha', { value=value })\nend\n\n---Creates a rectangle path which is only drawn after calling stroke() or fill().\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.pathRect(x, y, w, h)\n _internal.sendMessage('canvas.pathRect', { x=x, y=y, w=w, h=h })\nend\n\n---Adds a rounded rectangle to the current path. Must be followed by stroke() or fill().\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\n---@param radius number|table corner radius applied to all four corners (uniform), or a table\n---of 1–4 values to set individual corner radius in the order [top-left, top-right,\n---bottom-right, bottom-left], following the HTML Canvas API specification.\nfunction canvas.roundRect(x, y, w, h, radius)\n _internal.sendMessage('canvas.roundRect', { x=x, y=y, w=w, h=h, radius=radius })\nend\n\n---Draw a rectangle outline using the current stroke style.\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.strokeRect(x, y, w, h)\n _internal.sendMessage('canvas.strokeRect', { x=x, y=y, w=w, h=h })\nend\n\n---Draw a rectangle with a filled interior using the current fill style,\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.fillRect(x, y, w, h)\n _internal.sendMessage('canvas.fillRect', { x=x, y=y, w=w, h=h })\nend\n\n---Clears the specified rectangle by setting its pixels to transparent.\n---@param x number x-coordinate of the rectangle upper-left corner.\n---@param y number y-coordinate of the rectangle upper-left corner.\n---@param w number width of the rectangle.\n---@param h number height of the rectangle.\nfunction canvas.clearRect(x, y, w, h)\n _internal.sendMessage('canvas.clearRect', { x=x, y=y, w=w, h=h })\nend\n\n---Draws a circle with given parameters. Must be followed by stroke() or fill().\n---@param x number x-coordinates of the center of the circle.\n---@param y number y-coordinates of the center of the circle.\n---@param r number the radius of the circle\nfunction canvas.circle(x, y, r)\n _internal.sendMessage('canvas.circle', { x=x, y=y, r=r })\nend\n\n---Draws an arc with given parameters. Must be followed by stroke() or fill().\n---@param x number x-coordinates of the center of the circle.\n---@param y number y-coordinates of the center of the circle.\n---@param r number the radius of the circle.\n---@param startAngle number the starting angle in radians.\n---@param endAngle number the ending angle, in radians.\n---@param anticlockwise boolean a flag which specifies whether the drawing should be counterclockwise or clockwise.\nfunction canvas.arc(x, y, r, startAngle, endAngle, anticlockwise)\n _internal.sendMessage('canvas.arc', { x=x, y=y, r=r, startAngle=startAngle,\n endAngle=endAngle, anticlockwise=anticlockwise })\nend\n\n---Adds a quadratic Bézier curve to the path with given control point and end point.\n---@param cpx number x-coordinate of the control point.\n---@param cpy number y-coordinate of the control point.\n---@param x number x-coordinate of the end point.\n---@param y number y-coordinate of the end point.\nfunction canvas.quadraticCurve(cpx, cpy, x, y)\n _internal.sendMessage('canvas.quadraticCurve', { cpx=cpx, cpy=cpy, x=x, y=y })\nend\n\n---Draws a bezier curve from the current position to the specified point, using the specified control points.\n---@param cp1x number x-coordinate of the first control point.\n---@param cp1y number y-coordinate of the first control point.\n---@param cp2x number x-coordinate of the second control point.\n---@param cp2y number y-coordinate of the second control point.\n---@param x number x-coordinate of the end point.\n---@param y number y-coordinate of the end point.\nfunction canvas.bezierCurve(cp1x, cp1y, cp2x, cp2y, x, y)\n _internal.sendMessage('canvas.bezierCurve', { cp1x=cp1x, cp1y=cp1y,\n cp2x=cp2x, cp2y=cp2y,\n x=x, y=y })\nend\n\n---@class Gradient\n---A class to internally link gradient objects from the Lua environment to Lumino codebase.\n---A Gradient object can be create using @{createLinearGradient} or @{createRadialGradient}\n---@private\nlocal Gradient = {}\n\n---Creates a new gradient object with the given index\n---@param idx number index of the gradient object\n---@private\nfunction Gradient:new(idx)\n -- Store the gradient object in a field of the class instance metatable\n local obj = { idx = idx}\n Class.__setmetatable(obj, self)\n self.__index = self\n -- Return the instance\n return obj\nend\n\n---Hook that runs before an object is deleted by the garbage collector.\n---It calls a function to delete the gradient object in JS\n---@private\nfunction Gradient:__gc()\n -- Keep deletion ordering deterministic when gradient operations are buffered.\n _commitIfNeeded()\n _internal.sendMessage('canvas.deleteGradient', { gradientIdx = self.idx })\nend\n-- Add the Gradient class to the Canvas namespace\ncanvas.Gradient = Gradient\n\n---Sets a gradient object to active.\n---@param gradient Gradient a gradient object\nfunction canvas.setGradientActive(gradient)\n if gradient.idx >= 0 then\n _internal.sendMessage('canvas.setGradientActive', { gradientIdx = gradient.idx })\n end\nend\n\n---Adds a new stop, defined by an offset and a color, to a gradient object.\n---@param gradient Gradient a gradient object\n---@param offset number a value between 0.0 and 1.0 where the new color stop is positioned.\n---@param r number Red channel value (0–255)\n---@param g number Green channel value (0–255)\n---@param b number Blue channel value (0–255)\n---@param a number Alpha channel value (0–1)\nfunction canvas.colorStop(gradient, offset, r, g, b, a)\n _internal.sendMessage('canvas.colorStop', { gradientIdx=gradient.idx, offset=offset, r=r, g=g, b=b, a=a })\nend\n\n---Creates a linear gradient object.\n---@param x1 number the x-coordinate of the start point of the gradient\n---@param y1 number the y-coordinate of the start point of the gradient\n---@param x2 number the x-coordinate of the end point of the gradient\n---@param y2 number the y-coordinate of the end point of the gradient\n---@return Gradient a new gradient object\n---@usage local gradient = Canvas.createLinearGradient(0, 0, 50, 0)\nfunction canvas.createLinearGradient(x1, y1, x2, y2)\n local idx = _internal.sendMessage('canvas.createLinearGradient', { x1=x1, y1=y1,\n x2=x2, y2=y2 })\n local gradient = Gradient:new(idx)\n return gradient\nend\n\n---Creates a radial gradient object.\n---@param x1 number x-coordinate of the start circle\n---@param y1 number y-coordinate of the start circle\n---@param r1 number radius of the start circle\n---@param x2 number x-coordinate of the end circle\n---@param y2 number y-coordinate of the end circle\n---@param r2 number radius of the end circle\n---@return Gradient a new gradient object\nfunction canvas.createRadialGradient(x1, y1, r1, x2, y2, r2)\n local idx = _internal.sendMessage('canvas.createRadialGradient', { x1=x1, y1=y1, r1=r1,\n x2=x2, y2=y2, r2=r2})\n local gradient = Gradient:new(idx)\n return gradient\nend\n\n---Returns an array with strings of all available fonts. This will list all custom loaded fonts through Loader.loadFont and\n---fonts registered in Canvas Fonts in your project. It will also probe for common system fonts although the list might not be complete.\n---It is strongly recommended to use only custom uploaded fonts to have reliable results on all platforms.\n---@return table an array with all the available fonts as strings\nfunction canvas.getAvailableFonts()\n return _internal.sendMessage('canvas.getAvailableFonts')\nend\n\n---Sets a font style.\n---@param font string The font style to be set, in the format of 'font-style font-size font-family'. Example: 'italic 20px Arial'.\nfunction canvas.setFont(font)\n _internal.sendMessage('canvas.setFont', { font=font })\nend\n\n---Sets the current text alignment\n---@param align string The new text alignment to be set. One of 'start', 'end', 'left', 'right', or 'center'.\nfunction canvas.setTextAlign(align)\n _internal.sendMessage('canvas.setTextAlign', { align=align })\nend\n\n---Sets the text baseline used when drawing text.\n---@param baseline string The text baseline to set. One of 'alphabetic', 'top', 'hanging', 'middle', 'ideographic', or 'bottom'.\nfunction canvas.setTextBaseline(baseline)\n _internal.sendMessage('canvas.setTextBaseline', { baseline=baseline })\nend\n\n---Measures the width of the specified text in pixels.\n---@param text string The text to measure.\nfunction canvas.measureTextWidth(text)\n return _internal.sendMessage('canvas.measureTextWidth', { text=text })\nend\n\n---Draws and fills a given text string at the specified coordinates.\n---@param text string The text string to be drawn and filled.\n---@param x number The x-coordinate where the text will be drawn.\n---@param y number The y-coordinate where the text will be drawn.\nfunction canvas.fillText(text, x, y)\n _internal.sendMessage('canvas.fillText', { text=text, x=x, y=y })\nend\n\n---Draws the outline of the given text at the specified coordinates.\n---@param text string The text string to be drawn.\n---@param x number The x-coordinate where the text will be drawn.\n---@param y number The y-coordinate where the text will be drawn.\nfunction canvas.strokeText(text, x, y)\n _internal.sendMessage('canvas.strokeText', { text=text, x=x, y=y })\nend\n\n-- -TODO: ImageData is not yet ready for deployment because using it for pixel manipulation would be\n-- -inefficient and slow due to the need for JSON communication with JavaScript. While JSON\n-- -communication is necessary for the security of the application, it is not well-suited for tasks\n-- -that require frequent or high-volume data transfer. It is better to use ImageData for low\n-- -frequency tasks such as updating UI and handling events, rather than trying to use it for more\n-- -demanding tasks that may be slowed down by the use of JSON objects.\n\n-- --- Image class to link imageData objects in the canvas to Lua\n-- ---@class imageData\n-- local Image = {}\n\n-- --- Creates a new Image object with the given index\n-- ---@param idx number index of the imageData object in the canvas\n-- function Image:new(idx)\n-- local obj = {}\n-- Class.__setmetatable(obj, self)\n-- self.__index = self\n-- self.idx = idx\n-- return obj\n-- end\n-- canvas.Image = Image\n\n-- ---Creates a new, blank Image object with the specified dimensions.\n-- ---All of the pixels in the new object are transparent black.\n-- ---@param width number the width of the Image object\n-- ---@param height number the height of the Image object\n-- ---@return Image a new Image object\n-- function canvas.createImage(width, height)\n-- local idx = _internal.sendMessage('canvas.createImage', { width=width, height=height })\n-- local image = Image:new(idx)\n-- return image\n-- end\n\n-- ---Write the RGBA channels of an Image object\n-- ---@param r number the r channel of the Image object\n-- ---@param g number the g channel of the Image object\n-- ---@param b number the b channel of the Image object\n-- ---@param a number the a channel of the Image object\n-- function canvas.writeImageChannels(image, r, g, b, a)\n-- _internal.sendMessage('canvas.writeImageChannels', { imageIdx=image.idx, r=r, g=g, b=b, a=a })\n-- end\n\n-- ---Draws an image given by an url at the specified position and dimensions.\n-- ---@param url string\n-- ---@param x number\n-- ---@param y number\n-- ---@param width number\n-- ---@param height number\n-- function canvas.drawImageFromUrl(url, x, y, width, height)\n-- _internal.sendMessage('canvas.drawImageFromUrl', { url=url, x=x, y=y, width=width, height=height })\n-- end\n\n-- ---Repeats a given image on the canvas with a given pattern.\n-- ---@param image imageSource an image object\n-- ---@param repeat string one of repeat, repeat-x, repeat-y, no-repeat\n-- function canvas.imagePattern(image, repeatPattern)\n-- _internal.sendMessage('canvas.pattern', { image=image, repeatPattern=repeatPattern })\n-- end\n\n---Draws the image data at the given coordinates.\n---@param image Texture the image data to paint\n---@param x number x-coordinate of the top left corner where the image data will be painted\n---@param y number y-coordinate of the top left corner where the image data will be painted\n---@param width number width of the image on screen (optional)\n---@param height number height of the image on screen (optional)\n---@param mode number mode to use for stretching. possible values are 0 = stretch, 1 = fit, 2 = cover\nfunction canvas.drawImage(image, x, y, width, height, mode)\n __assertTrace(image and image._isTexture, \"image is not a Texture object\")\n _internal.sendMessage('canvas.drawImage', { image= image._handle, x=x, y=y, width=width, height=height, mode=mode })\nend\n\n---Draws the image data at the given coordinates.\n---@param image Texture the image data to paint\n---@param x number x-coordinate of the top left corner where the image data will be painted\n---@param y number y-coordinate of the top left corner where the image data will be painted\n---@param width number width of the image on screen (optional)\n---@param height number height of the image on screen (optional)\nfunction canvas.drawSubImage(image, x, y, width, height, sourceX, sourceY, sourceWidth, sourceHeight)\n __assertTrace(image and image._isTexture, \"image is not a Texture object\")\n _internal.sendMessage('canvas.drawSubImage', { image= image._handle,\n x=x, y=y, width=width, height=height,\n sourceX=sourceX, sourceY=sourceY, sourceWidth=sourceWidth, sourceHeight=sourceHeight })\nend\n\n--- Scales the canvas by the specified factors along the x and y axes.\n--- Transformations are applied relative to the canvas origin (0,0).\n--- To scale around a different point, use `translate()` to move the origin before scaling.\n---@param x number Scale factor along the x-axis.\n---@param y number Scale factor along the y-axis.\nfunction canvas.scale(x, y)\n _internal.sendMessage('canvas.scale', { x=x, y=y })\nend\n\n--- Rotates the canvas by the specified angle in radians.\n--- Rotation is performed around the canvas origin (0,0).\n--- To rotate around a different point, translate the canvas to that point before calling rotate().\n---@param a number Angle in radians.\nfunction canvas.rotate(a)\n _internal.sendMessage('canvas.rotate', { a=a })\nend\n\n\n--- Moves (translates) the canvas origin by the specified amounts.\n--- All subsequent drawing and transformations (scale, rotate, etc.) are relative to the new origin.\n---@param x number Amount to translate along the x-axis.\n---@param y number Amount to translate along the y-axis.\nfunction canvas.translate(x, y)\n _internal.sendMessage('canvas.translate', { x=x, y=y })\nend\n\n---Applies a 2D transformation matrix to the canvas.\n---@param horizontal_scale number The amount to scale horizontally.\n---@param horizontal_skew number The amount of horizontal skew.\n---@param vertical_skew number The amount of vertical skew.\n---@param vertical_scale number The amount to scale vertically.\n---@param horizontal_translation number The amount of horizontal translation.\n---@param vertical_translation number The amount of vertical translation.\nfunction canvas.transform(horizontal_scale, horizontal_skew, vertical_skew,\n vertical_scale, horizontal_translation, vertical_translation)\n _internal.sendMessage('canvas.transform', { a=horizontal_scale, b=horizontal_skew,\n c=vertical_skew, d=vertical_scale,\n e=horizontal_translation, f=vertical_translation })\nend\n\n---Resets the current canvas transform to the identity matrix and then invokes the transform() function with the given parameters.\n---@param horizontal_scale number The amount to scale horizontally.\n---@param horizontal_skew number The amount of horizontal skew.\n---@param vertical_skew number The amount of vertical skew.\n---@param vertical_scale number The amount to scale vertically.\n---@param horizontal_translation number The amount of horizontal translation.\n---@param vertical_translation number The amount of vertical translation.\nfunction canvas.resetAndSetTransform(horizontal_scale, horizontal_skew, vertical_skew,\n vertical_scale, horizontal_translation, vertical_translation)\n _internal.sendMessage('canvas.resetAndSetTransform', { a=horizontal_scale, b=horizontal_skew,\n c=vertical_skew, d=vertical_scale,\n e=horizontal_translation, f=vertical_translation })\nend\n\n---Reset the transformation matrix to the identity matrix.\n---@function\nfunction canvas.resetTransform()\n _internal.sendMessage('canvas.resetTransform')\nend\n\n---Pushes the current canvas state to a stack so that you can restore it.\n---This can be useful for performing multiple transformations or styles on the canvas, and\n---then restoring it to its original state. The canvas state in fact includes current transformation matrix\n---stroke and fill styles, shadow styles, and other attributes. To restore the canvas state you call\n---the restoreState() function.\n---@function\nfunction canvas.saveState()\n _internal.sendMessage('canvas.saveState')\nend\n\n---Pops the the most recently saved canvas from the saved state stack and restores it.\n---@function\nfunction canvas.restoreState()\n _internal.sendMessage('canvas.restoreState')\nend\n\n--- Resets the canvas to its default state, clearing the canvas and restoring all\n--- context -properties (transforms, styles, clipping region, etc.) to their\n--- defaults. Reset() is more thorough than -calling clear() alone, which only\n--- erases pixels but leaves context state intact.\n---@function\nfunction canvas.reset()\n _internal.sendMessage('canvas.reset')\nend\n\n-- Automatically wrap canvas methods for buffering, so non-query calls are queued\n-- and query/result-producing calls force an immediate commit first.\nlocal _passthroughMethods = {\n commit = true,\n getPendingCommandCount = true,\n getPendingCommands = true,\n}\n\nlocal _immediateMethods = {\n getLastCommittedCommands = true,\n getWidth = true,\n getHeight = true,\n isPointInPath = true,\n createLinearGradient = true,\n createRadialGradient = true,\n getAvailableFonts = true,\n measureTextWidth = true,\n}\n\nfor name, fn in pairs(canvas) do\n if type(fn) == \"function\" and name ~= \"Gradient\" then\n if _passthroughMethods[name] then\n -- keep as-is\n elseif _immediateMethods[name] then\n canvas[name] = function(...)\n _commitIfNeeded()\n return fn(...)\n end\n else\n canvas[name] = function(...)\n return _runWithCapturedSend(fn, ...)\n end\n end\n end\nend\n\nreturn canvas\n";
|
|
97459
97460
|
|
|
97460
97461
|
var lua_api_class = "\nlocal Class = {}\n\nClass.__setmetatable = setmetatable\n_G.setmetatable = function()\n error(\"Do not use setmetatable. Use Class.new() instead!\")\nend\n\n-- Put the class in the global scope\n_G.Class = Class\n\nfunction Class.new(self, super)\n if self ~= Class then\n -- new was called with dot syntax, so we need to move self to super.\n super = self\n end\n\n local class, metatable, properties = {}, {}, {}\n class.metatable = metatable\n class.properties = properties\n\n function metatable:__index(key)\n local prop = properties[key]\n if prop then\n return prop:get()\n elseif class[key] ~= nil then\n return class[key]\n elseif class.__customIndex then\n return class.__customIndex(self, key)\n elseif super then\n return super.metatable.__index(self, key)\n else\n return nil\n end\n end\n\n function metatable:__newindex(key, value)\n local prop = properties[key]\n if prop then\n prop:set(value)\n elseif class.__customNewIndex then\n class.__customNewIndex(self, key, value)\n else\n if (super and super.metatable.__customnewindex(self, key, value)) then\n return\n end\n rawset(self, key, value)\n end\n end\n\n function metatable:__customnewindex(key, value)\n if class.__customNewIndex then\n class.__customNewIndex(self, key, value)\n return true\n elseif super then\n return super.metatable.__customnewindex(self, key, value)\n end\n return false\n end\n\n function class:getClass()\n return class\n end\n\n function class.new(self, ...)\n local obj = Class.__setmetatable({}, class.metatable)\n\n if obj.__new then\n if self ~= class then\n -- new was called with dot syntax\n obj:__new(self, ...)\n else\n obj:__new(...)\n end\n end\n\n return obj\n end\n\n function tableLength(T)\n local count = 0\n for _ in pairs(T) do\n count = count + 1\n end\n return count\n end\n\n function class:addProperty(key, propType, defaultValue, options)\n options = options or {}\n if type(options) == 'string' then\n options = { info=options }\n end\n\n if class.properties[key] then\n error(\"A property with the name '\" .. key .. \"' already exists!\");\n return;\n end\n class.properties[key] = Property.new(propType, defaultValue, tableLength(class.properties), options);\n end\n\n return class\nend\n\nreturn Class\n";
|
|
97461
97462
|
|
|
@@ -115768,6 +115769,26 @@ class ProfilerTask {
|
|
|
115768
115769
|
pushChildTask(task) {
|
|
115769
115770
|
this.childTasks.push(task);
|
|
115770
115771
|
}
|
|
115772
|
+
findPerformanceIssuePath(limit) {
|
|
115773
|
+
limit = limit || this.profiler.performanceWarningLimitMs;
|
|
115774
|
+
let path = "";
|
|
115775
|
+
if (this.duration > limit) {
|
|
115776
|
+
path += ` -> ${this.subsystem}/${this.taskname} (${Math.ceil(this.duration)}ms)`;
|
|
115777
|
+
}
|
|
115778
|
+
let worstChild = undefined;
|
|
115779
|
+
for (const child of this.childTasks) {
|
|
115780
|
+
if (!worstChild || child.duration > worstChild.duration) {
|
|
115781
|
+
worstChild = child;
|
|
115782
|
+
}
|
|
115783
|
+
}
|
|
115784
|
+
if (worstChild) {
|
|
115785
|
+
const subPath = worstChild.findPerformanceIssuePath(limit);
|
|
115786
|
+
if (subPath) {
|
|
115787
|
+
path += subPath;
|
|
115788
|
+
}
|
|
115789
|
+
}
|
|
115790
|
+
return path;
|
|
115791
|
+
}
|
|
115771
115792
|
toData() {
|
|
115772
115793
|
return {
|
|
115773
115794
|
subsystem: this.subsystem,
|
|
@@ -115789,6 +115810,8 @@ class Profiler {
|
|
|
115789
115810
|
lastRecording;
|
|
115790
115811
|
loggedCalls = new Map();
|
|
115791
115812
|
lastLoggedCalls = undefined;
|
|
115813
|
+
performanceWaningEnabled = false;
|
|
115814
|
+
performanceWarningLimitMs = 20;
|
|
115792
115815
|
constructor(engine) {
|
|
115793
115816
|
this.engine = engine;
|
|
115794
115817
|
this.dummyTask = {
|
|
@@ -115828,11 +115851,21 @@ class Profiler {
|
|
|
115828
115851
|
}
|
|
115829
115852
|
return null;
|
|
115830
115853
|
}
|
|
115854
|
+
testPerformanceWarning(task, limit) {
|
|
115855
|
+
limit = limit || this.performanceWarningLimitMs;
|
|
115856
|
+
if (task.duration > limit) {
|
|
115857
|
+
const path = task.findPerformanceIssuePath(limit);
|
|
115858
|
+
console.warn(`Profiler performance warning! Task took ${Math.ceil(task.duration)}ms! Path: ${path}`);
|
|
115859
|
+
}
|
|
115860
|
+
}
|
|
115831
115861
|
endRecord() {
|
|
115832
115862
|
try {
|
|
115833
115863
|
if (!this.root)
|
|
115834
115864
|
return null;
|
|
115835
115865
|
this.root.done();
|
|
115866
|
+
if (this.performanceWaningEnabled) {
|
|
115867
|
+
this.testPerformanceWarning(this.root);
|
|
115868
|
+
}
|
|
115836
115869
|
this.lastRecording = this.root.toData();
|
|
115837
115870
|
this.lastLoggedCalls = Array.from(this.loggedCalls.values());
|
|
115838
115871
|
this.engine.eventBus.$emit("profiler:update", this.lastRecording, this.lastLoggedCalls);
|