Compare commits

...

3 Commits

Author SHA1 Message Date
4e0598e321 cleaned code, custom boundbox (works for anim.nodes too), targetting
nodes in the middle of a hierarchy or nodes with multiple childs is now
possible
2026-07-08 01:09:08 +02:00
565d4c31f4 control mode for objects (view space or object space) 2026-07-04 11:53:09 +02:00
61c7a29113 relying on implicit.context.js to set drawto and listening to world
events
2026-07-04 11:22:52 +02:00
2 changed files with 467 additions and 304 deletions

View File

@@ -9,16 +9,49 @@
"modernui": 1
},
"classnamespace": "box",
"rect": [ 636.0, 100.0, 1444.0, 848.0 ],
"rect": [ 400.0, 100.0, 967.0, 848.0 ],
"integercoordinates": 1,
"boxes": [
{
"box": {
"id": "obj-46",
"maxclass": "message",
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 160.0, 70.0, 48.0, 22.0 ],
"text": "fps 120"
}
},
{
"box": {
"id": "obj-25",
"maxclass": "message",
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 287.0, 86.0, 107.0, 22.0 ],
"text": "sendnode getanim"
}
},
{
"box": {
"id": "obj-22",
"maxclass": "message",
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 203.0, 78.0, 41.0, 22.0 ],
"text": "fps 30"
}
},
{
"box": {
"id": "obj-21",
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 1395.0, 188.0, 88.0, 22.0 ],
"patching_rect": [ 1408.0, 188.0, 88.0, 22.0 ],
"text": "s object_select"
}
},
@@ -39,7 +72,7 @@
"numinlets": 0,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 273.0, 493.0, 86.0, 22.0 ],
"patching_rect": [ 327.0, 482.0, 86.0, 22.0 ],
"text": "r object_select"
}
},
@@ -50,7 +83,7 @@
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 1299.0, 188.0, 93.0, 22.0 ],
"patching_rect": [ 1312.0, 188.0, 93.0, 22.0 ],
"text": "s to_tc.fpcontrol"
}
},
@@ -860,7 +893,7 @@
}
]
},
"patching_rect": [ 1299.0, 155.0, 115.0, 22.0 ],
"patching_rect": [ 1312.0, 155.0, 115.0, 22.0 ],
"text": "p gamepad_buttons"
}
},
@@ -868,11 +901,11 @@
"box": {
"id": "obj-4",
"maxclass": "newobj",
"numinlets": 2,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 239.0, 374.0, 55.0, 22.0 ],
"text": "route init"
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 211.0, 405.0, 125.0, 22.0 ],
"text": "loadmess controllable"
}
},
{
@@ -882,8 +915,8 @@
"maxclass": "comment",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 315.0, 532.0, 272.0, 24.0 ],
"text": "Select which object to control in camera space"
"patching_rect": [ 369.0, 521.0, 181.0, 24.0 ],
"text": "Select which object to control"
}
},
{
@@ -893,21 +926,10 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 53.0, 612.0, 72.0, 22.0 ],
"patching_rect": [ 53.0, 595.0, 72.0, 22.0 ],
"text": "prepend set"
}
},
{
"box": {
"color": [ 0.282352941176471, 0.537254901960784, 0.905882352941176, 1.0 ],
"id": "obj-32",
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 211.0, 589.0, 93.0, 22.0 ],
"text": "s to_tc.fpcontrol"
}
},
{
"box": {
"id": "obj-31",
@@ -915,7 +937,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 211.0, 561.0, 61.0, 22.0 ],
"patching_rect": [ 265.0, 550.0, 61.0, 22.0 ],
"text": "control $2"
}
},
@@ -969,7 +991,7 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "int" ],
"patching_rect": [ 249.0, 218.0, 22.0, 22.0 ],
"patching_rect": [ 208.0, 217.0, 22.0, 22.0 ],
"text": "t 1"
}
},
@@ -1002,8 +1024,8 @@
"numinlets": 2,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 184.0, 186.0, 310.0, 22.0 ],
"text": "zl.sect jit.gl.skybox jit.gl.sketch jit.gl.camera jit.anim.node"
"patching_rect": [ 184.0, 186.0, 239.0, 22.0 ],
"text": "zl.sect jit.gl.skybox jit.gl.sketch jit.gl.camera"
}
},
{
@@ -1014,7 +1036,7 @@
"maxclass": "comment",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 499.0, 165.0, 200.0, 64.0 ],
"patching_rect": [ 425.0, 165.0, 200.0, 64.0 ],
"text": "For the purpose of a seamless experience, filtering out objects we don't want to control in this patch, even if you could!"
}
},
@@ -1138,19 +1160,19 @@
}
]
},
"patching_rect": [ 129.0, 493.0, 133.0, 22.0 ],
"patching_rect": [ 183.0, 482.0, 133.0, 22.0 ],
"text": "p controllable_populate"
}
},
{
"box": {
"id": "obj-5",
"linecount": 27,
"linecount": 26,
"maxclass": "comment",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 611.0, 459.0, 568.0, 368.0 ],
"text": "HOW TO USE IN YOUR OWN PATCH\n\n0. Add [tc.fpcontrol] and, depending on the controls you want, [p mouse_keyboard_controls] and/or [gamepad.drive] . You can also create your own input method as it relies on simple 'move X 0 Z' and 'turn X Y 0' messages\n\n1. In order to initialize [tc.fpcontrol] you need to send 'camera' followed by the name of your jit.gl.camera or a jit.anid.node attached to it. Will serve as the basis for moving objects in view space. This is necessary to control any object. A caveheat is that this message must be sent after the world has been initalized. You can [route init] from [jit.world] right outlet for that.\n\n2. Send 'controllable' to get a list of all controllable jit.gl objects in your patch.\n \n4. Send 'control_camera' followed by the the name of your jit.gl.camera or a jit.anid.node attached to it to control the camera. If flymode is disabled, the camera will remain on the same elevation (Y world pos) unless using the elevation controls (gamepad triggers). If flymode is enabled, the camera will go in the direction it faces and elevation controls will make it move up-down relatively to that direction. \n\n5. Send 'control' followed by the name of a jit.gl or jit.anim.node object to control it in camera space. When using the name of a jit.gl object, its top-level user-created jit.anim.node will be used as entry point for the controls from v8. If there is no user-created jit.anim.node used by this object, its implicit internal jit.anim.node will be used as entry point. When using the name of a jit.anim.node directly, it will be the entry point for the controls comming from v8. If show_bounds is enabled and the target object is a bounds-compatible jit.gl object (or a jit.anim.node controlling bounds-compatible jit.gl objects), its bounds will be displayed\n\n6. Use the mouse+keyboard or gamepad to control the object or camera."
"patching_rect": [ 611.0, 459.0, 568.0, 355.0 ],
"text": "HOW TO USE IN YOUR OWN PATCH\n\n0. Add [tc.fpcontrol] and, depending on the controls you want, [p mouse_keyboard_controls] and/or [gamepad.drive] . You can also create your own input method as it relies on simple 'move X 0 Z' and 'turn X Y 0' messages\n\n1. In order to use [tc.fpcontrol] you to tell it which camera (or jit.anid.node attached to it) to use. You can pass that as an attribute as shown here. This camera/anim.node will serve as the basis for moving objects in view space. This is necessary to control any object.\n\n2. Send 'controllable' to get a list of all controllable jit.gl objects in your patch.\n \n4. Send 'control_camera' followed by the the name of your jit.gl.camera or a jit.anid.node attached to it to control the camera. If flymode is disabled, the camera will remain on the same elevation (Y world pos) unless using the elevation controls (gamepad triggers). If flymode is enabled, the camera will go in the direction it faces and elevation controls will make it move up-down relatively to that direction. \n\n5. Send 'control' followed by the name of a jit.gl or jit.anim.node object to control it in camera space. When using the name of a jit.gl object, its top-level user-created jit.anim.node will be used as entry point for the controls from v8. If there is no user-created jit.anim.node used by this object, its implicit internal jit.anim.node will be used as entry point. When using the name of a jit.anim.node directly, it will be the entry point for the controls comming from v8. If show_bounds is enabled and the target object is a bounds-compatible jit.gl object (or a jit.anim.node controlling bounds-compatible jit.gl objects), its bounds will be displayed\n\n6. Use the mouse+keyboard or gamepad to control the object or camera."
}
},
{
@@ -1170,9 +1192,42 @@
"modernui": 1
},
"classnamespace": "box",
"rect": [ 478.0, 100.0, 405.0, 755.0 ],
"rect": [ 573.0, 140.0, 866.0, 755.0 ],
"integercoordinates": 1,
"boxes": [
{
"box": {
"id": "obj-15",
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 448.0, 296.0, 275.0, 22.0 ],
"text": "jit.anim.node @name plato_anim @position -4 0 0"
}
},
{
"box": {
"id": "obj-14",
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 27.0, 296.0, 272.0, 22.0 ],
"text": "jit.anim.node @name torus_anim @position 4 0 0"
}
},
{
"box": {
"id": "obj-3",
"maxclass": "newobj",
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 27.0, 231.0, 199.0, 22.0 ],
"text": "jit.anim.node @name torus_&_plato"
}
},
{
"box": {
"id": "obj-6",
@@ -1180,7 +1235,7 @@
"numinlets": 0,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 59.0, 595.0, 61.0, 22.0 ],
"patching_rect": [ 20.0, 635.0, 61.0, 22.0 ],
"text": "r reset_all"
}
},
@@ -1192,7 +1247,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 59.0, 625.0, 91.0, 35.0 ],
"patching_rect": [ 20.0, 665.0, 91.0, 35.0 ],
"text": "anim_reset, position 0 0 0"
}
},
@@ -1203,7 +1258,7 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 163.0, 514.0, 54.0, 22.0 ],
"patching_rect": [ 124.0, 554.0, 54.0, 22.0 ],
"text": "deferlow"
}
},
@@ -1216,7 +1271,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 531.0, 638.0, 137.0, 23.0 ],
"patching_rect": [ 492.0, 678.0, 137.0, 23.0 ],
"text": "read baluster-vase.gltf"
}
},
@@ -1229,7 +1284,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 330.0, 638.0, 189.0, 23.0 ],
"patching_rect": [ 291.0, 678.0, 189.0, 23.0 ],
"text": "read pocillopora-damicornis.gltf"
}
},
@@ -1240,7 +1295,7 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 483.0, 547.0, 70.0, 22.0 ],
"patching_rect": [ 444.0, 587.0, 70.0, 22.0 ],
"text": "loadmess 2"
}
},
@@ -1253,7 +1308,7 @@
"numoutlets": 2,
"outlettype": [ "", "bang" ],
"parameter_enable": 0,
"patching_rect": [ 576.0, 576.0, 50.0, 22.0 ]
"patching_rect": [ 537.0, 616.0, 50.0, 22.0 ]
}
},
{
@@ -1263,7 +1318,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 576.0, 603.0, 86.0, 22.0 ],
"patching_rect": [ 537.0, 643.0, 86.0, 22.0 ],
"text": "metalness $1"
}
},
@@ -1276,7 +1331,7 @@
"numoutlets": 2,
"outlettype": [ "", "bang" ],
"parameter_enable": 0,
"patching_rect": [ 483.0, 576.0, 50.0, 22.0 ]
"patching_rect": [ 444.0, 616.0, 50.0, 22.0 ]
}
},
{
@@ -1286,7 +1341,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 483.0, 603.0, 87.0, 22.0 ],
"patching_rect": [ 444.0, 643.0, 87.0, 22.0 ],
"text": "roughness $1"
}
},
@@ -1297,7 +1352,7 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "bang" ],
"patching_rect": [ 163.0, 482.0, 58.0, 22.0 ],
"patching_rect": [ 124.0, 522.0, 58.0, 22.0 ],
"text": "loadbang"
}
},
@@ -1308,7 +1363,7 @@
"numinlets": 2,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 163.0, 603.0, 264.0, 22.0 ],
"patching_rect": [ 124.0, 643.0, 264.0, 22.0 ],
"text": "substitute jit_gl_texture environment_texture"
}
},
@@ -1319,7 +1374,7 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 163.0, 638.0, 145.0, 22.0 ],
"patching_rect": [ 124.0, 678.0, 145.0, 22.0 ],
"text": "prepend sendmaterial 1"
}
},
@@ -1330,7 +1385,7 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 163.0, 671.0, 378.0, 22.0 ],
"patching_rect": [ 124.0, 711.0, 378.0, 22.0 ],
"text": "jit.gl.model @file baluster-vase.gltf @material_mode 3 @name model"
}
},
@@ -1341,7 +1396,7 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 249.0, 514.0, 100.0, 22.0 ],
"patching_rect": [ 210.0, 554.0, 100.0, 22.0 ],
"text": "jit.gl.skybox"
}
},
@@ -1352,7 +1407,7 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "jit_gl_texture", "" ],
"patching_rect": [ 163.0, 547.0, 293.0, 22.0 ],
"patching_rect": [ 124.0, 587.0, 293.0, 22.0 ],
"text": "jit.gl.environment @file umhlanga_sunrise_2k.exr"
}
},
@@ -1363,7 +1418,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 210.0, 301.0, 265.0, 22.0 ],
"patching_rect": [ 780.0, 351.0, 265.0, 22.0 ],
"text": "position 0 -2 0, rotatexyz -90 0 0, scale 10 10 10"
}
},
@@ -1374,7 +1429,7 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "bang", "bang" ],
"patching_rect": [ 27.0, 236.0, 32.0, 22.0 ],
"patching_rect": [ 780.0, 187.0, 32.0, 22.0 ],
"text": "t b b"
}
},
@@ -1385,7 +1440,7 @@
"numinlets": 0,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 27.0, 209.0, 61.0, 22.0 ],
"patching_rect": [ 780.0, 160.0, 61.0, 22.0 ],
"text": "r reset_all"
}
},
@@ -1396,7 +1451,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 119.0, 301.0, 84.0, 22.0 ],
"patching_rect": [ 448.0, 267.0, 84.0, 22.0 ],
"text": "position -4 0 0"
}
},
@@ -1407,7 +1462,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 27.0, 301.0, 80.0, 22.0 ],
"patching_rect": [ 220.0, 267.0, 80.0, 22.0 ],
"text": "position 4 0 0"
}
},
@@ -1429,7 +1484,7 @@
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 40.0, 268.0, 68.0, 22.0 ],
"patching_rect": [ 793.0, 216.0, 68.0, 22.0 ],
"text": "anim_reset"
}
},
@@ -1440,8 +1495,8 @@
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 440.0, 140.0, 559.0, 22.0 ],
"text": "jit.gl.light @shadows 1 @shadowquality hi @direction 0.4 -0.8 -1. @shadowblur 0.1 @shadowrange 50."
"patching_rect": [ 364.0, 110.0, 650.0, 22.0 ],
"text": "jit.gl.light @name dir_light @shadows 1 @shadowquality hi @direction 0.4 -0.8 -1. @shadowblur 0.1 @shadowrange 50."
}
},
{
@@ -1462,7 +1517,7 @@
"numinlets": 8,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 210.0, 236.0, 117.0, 22.0 ],
"patching_rect": [ 27.0, 453.0, 117.0, 22.0 ],
"text": "jit.gl.pbr @name pbr"
}
},
@@ -1473,7 +1528,7 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 27.0, 404.0, 613.0, 22.0 ],
"patching_rect": [ 27.0, 402.0, 613.0, 22.0 ],
"text": "jit.gl.gridshape @name plane @shape plane @material pbr @position 0 -2 0 @rotatexyz -90 0 0 @scale 10 10 10"
}
},
@@ -1484,8 +1539,8 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 27.0, 368.0, 383.0, 22.0 ],
"text": "jit.gl.plato @name plato @shape icosa @material pbr @position -4 0 0",
"patching_rect": [ 448.0, 351.0, 293.0, 22.0 ],
"text": "jit.gl.plato @name plato @shape icosa @material pbr",
"varname": "icosa"
}
},
@@ -1496,8 +1551,8 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 27.0, 332.0, 405.0, 22.0 ],
"text": "jit.gl.gridshape @name torus @shape torus @material pbr @position 4 0 0",
"patching_rect": [ 27.0, 351.0, 319.0, 22.0 ],
"text": "jit.gl.gridshape @name torus @shape torus @material pbr",
"varname": "torus"
}
},
@@ -1522,7 +1577,7 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 440.0, 109.0, 206.0, 22.0 ]
"patching_rect": [ 364.0, 79.0, 206.0, 22.0 ]
}
},
{
@@ -1546,7 +1601,7 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 654.0, 109.0, 150.0, 22.0 ]
"patching_rect": [ 585.0, 79.0, 150.0, 22.0 ]
}
},
{
@@ -1558,7 +1613,7 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 812.0, 109.0, 210.0, 22.0 ]
"patching_rect": [ 736.0, 79.0, 210.0, 22.0 ]
}
}
],
@@ -1581,6 +1636,12 @@
"source": [ "obj-12", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-5", 0 ],
"source": [ "obj-14", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-30", 0 ],
@@ -1595,13 +1656,19 @@
},
{
"patchline": {
"destination": [ "obj-5", 0 ],
"destination": [ "obj-7", 0 ],
"source": [ "obj-15", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-14", 0 ],
"source": [ "obj-170", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-7", 0 ],
"destination": [ "obj-15", 0 ],
"source": [ "obj-172", 0 ]
}
},
@@ -1629,6 +1696,20 @@
"source": [ "obj-29", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-14", 0 ],
"order": 1,
"source": [ "obj-3", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-15", 0 ],
"order": 0,
"source": [ "obj-3", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-4", 0 ],
@@ -1703,22 +1784,29 @@
},
{
"patchline": {
"destination": [ "obj-5", 0 ],
"destination": [ "obj-14", 0 ],
"order": 2,
"source": [ "obj-83", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-7", 0 ],
"order": 1,
"destination": [ "obj-15", 0 ],
"order": 0,
"source": [ "obj-83", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-3", 0 ],
"order": 3,
"source": [ "obj-83", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-8", 0 ],
"order": 0,
"order": 1,
"source": [ "obj-83", 0 ]
}
},
@@ -1855,13 +1943,13 @@
{
"box": {
"id": "obj-56",
"items": [ "jit.gl.gridshape", "torus", ",", "jit.gl.plato", "plato", ",", "jit.gl.gridshape", "plane", ",", "jit.gl.light", "u966000628", ",", "jit.gl.model", "model" ],
"items": [ "jit.gl.gridshape", "torus", ",", "jit.gl.plato", "plato", ",", "jit.gl.gridshape", "plane", ",", "jit.gl.light", "dir_light", ",", "jit.gl.model", "model", ",", "jit.anim.node", "torus_&_plato", ",", "jit.anim.node", "torus_anim", ",", "jit.anim.node", "plato_anim" ],
"maxclass": "umenu",
"numinlets": 1,
"numoutlets": 3,
"outlettype": [ "int", "", "" ],
"parameter_enable": 0,
"patching_rect": [ 129.0, 533.0, 184.0, 22.0 ]
"patching_rect": [ 183.0, 522.0, 184.0, 22.0 ]
}
},
{
@@ -1886,7 +1974,7 @@
"maxclass": "comment",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 18.0, 684.0, 257.0, 66.0 ],
"patching_rect": [ 36.0, 654.0, 257.0, 66.0 ],
"text": "'control' outputs the given object name to be controlled (jit.gl or jit.anim.node), followed by the actual one being controlled (jit.anim.node)"
}
},
@@ -2427,19 +2515,8 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 720.0, 121.0, 598.0, 22.0 ],
"text": "gamepad.drive @l_deadzone 0.1 @r_deadzone 0.2 @l_sensitivity 0.4 @r_sensitivity 3 @trigger_sensitivity 0.4"
}
},
{
"box": {
"id": "obj-125",
"maxclass": "message",
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 239.0, 405.0, 143.0, 22.0 ],
"text": "camera cam, controllable"
"patching_rect": [ 720.0, 121.0, 611.0, 22.0 ],
"text": "gamepad.drive @l_deadzone 0.15 @r_deadzone 0.15 @l_sensitivity 0.4 @r_sensitivity 3 @trigger_sensitivity 0.4"
}
},
{
@@ -2451,12 +2528,12 @@
"numinlets": 1,
"numoutlets": 2,
"outlettype": [ "", "" ],
"patching_rect": [ 53.0, 448.0, 95.0, 22.0 ],
"patching_rect": [ 53.0, 448.0, 149.0, 22.0 ],
"saved_object_attributes": {
"embed": 0,
"parameter_enable": 0
},
"text": "tc.fpcontrol",
"text": "tc.fpcontrol @camera cam",
"textfile": {
"filename": "tc.controller.js",
"flags": 0,
@@ -2472,8 +2549,8 @@
"maxclass": "comment",
"numinlets": 1,
"numoutlets": 0,
"patching_rect": [ 444.0, 987.0, 567.0, 114.0 ],
"text": "TODO:\n- use worldtolocal anim.node feature instead of manually calculating transform matrix?\n- better object rotation logic?\n- other ideas?\n\nWHAT DOESN'T WORK\n- using the implicit anim node of a jit.gl.camera doesn't work (need to declare an explicit anim node)\n- controlling a skybox doesn't work although it's technically possible and works when done manually"
"patching_rect": [ 612.0, 834.0, 567.0, 114.0 ],
"text": "TODO:\n- use worldtolocal anim.node feature instead of manually calculating transform matrix?\n- better object rotation logic?\n- other ideas?\n\nWHAT DOESN'T WORK\n- using the implicit anim node of a jit.gl.camera doesn't work (need to create an anim.node for it)\n- controlling a skybox doesn't work although it's technically possible and works when done manually"
}
},
{
@@ -2503,13 +2580,11 @@
"box": {
"dontreplace": 1,
"id": "obj-60",
"linecount": 2,
"maxclass": "message",
"numinlets": 2,
"numoutlets": 1,
"outlettype": [ "" ],
"patching_rect": [ 53.0, 647.0, 222.0, 35.0 ],
"text": "control camera_node_implicit camera_node_implicit"
"patching_rect": [ 53.0, 630.0, 222.0, 22.0 ]
}
},
{
@@ -2569,7 +2644,7 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 53.0, 346.0, 97.0, 22.0 ],
"patching_rect": [ 53.0, 274.0, 97.0, 22.0 ],
"text_width": 46.0
}
},
@@ -2582,7 +2657,7 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 53.0, 318.0, 87.0, 22.0 ],
"patching_rect": [ 53.0, 298.0, 87.0, 22.0 ],
"text_width": 63.0
}
},
@@ -2595,7 +2670,8 @@
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 53.0, 376.0, 121.0, 22.0 ]
"patching_rect": [ 53.0, 346.0, 121.0, 22.0 ],
"text_width": 97.0
}
},
{
@@ -2610,6 +2686,32 @@
"patching_rect": [ 35.5, 63.0, 83.0, 22.0 ],
"text_width": 61.0
}
},
{
"box": {
"attr": "camera",
"id": "obj-7",
"maxclass": "attrui",
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 53.0, 370.0, 186.0, 22.0 ],
"text_width": 61.0
}
},
{
"box": {
"attr": "controlmode",
"id": "obj-8",
"maxclass": "attrui",
"numinlets": 1,
"numoutlets": 1,
"outlettype": [ "" ],
"parameter_enable": 0,
"patching_rect": [ 53.0, 322.0, 186.0, 22.0 ],
"text_width": 87.0
}
}
],
"lines": [
@@ -2637,12 +2739,6 @@
"source": [ "obj-11", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-109", 0 ],
"source": [ "obj-125", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-109", 0 ],
@@ -2685,6 +2781,18 @@
"source": [ "obj-202", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-3", 0 ],
"source": [ "obj-22", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-3", 0 ],
"source": [ "obj-25", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-56", 0 ],
@@ -2699,13 +2807,8 @@
},
{
"patchline": {
"destination": [ "obj-4", 0 ],
"source": [ "obj-3", 2 ]
}
},
{
"patchline": {
"destination": [ "obj-32", 0 ],
"destination": [ "obj-109", 0 ],
"midpoints": [ 274.5, 573.0, 39.0, 573.0, 39.0, 444.0, 62.5, 444.0 ],
"source": [ "obj-31", 0 ]
}
},
@@ -2729,10 +2832,16 @@
},
{
"patchline": {
"destination": [ "obj-125", 0 ],
"destination": [ "obj-109", 0 ],
"source": [ "obj-4", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-3", 0 ],
"source": [ "obj-46", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-109", 0 ],
@@ -2762,6 +2871,18 @@
"destination": [ "obj-109", 0 ],
"source": [ "obj-62", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-109", 0 ],
"source": [ "obj-7", 0 ]
}
},
{
"patchline": {
"destination": [ "obj-109", 0 ],
"source": [ "obj-8", 0 ]
}
}
],
"autosave": 0

View File

@@ -22,8 +22,9 @@ autowatch = 1;
outlets = 2;
var drawto = "";
declareattribute({ name: "drawto", setter: "setdrawto" });
let world_bangs = false; // is the world banging?
const ctx_finder = require("implicit.context.js");
ctx_finder.register_drawto(this, dosetdrawto, set_root);
var ease = 0.1;
declareattribute({
@@ -35,10 +36,10 @@ declareattribute({
default: 0.1,
});
var camera_node = "";
var camera = "";
declareattribute({
name: "camera_node",
setter: "camera",
name: "camera",
setter: "set_camera",
label: "Camera anim node",
type: "string",
});
@@ -51,6 +52,15 @@ declareattribute({
default: 0,
});
var controlmode = 0;
declareattribute({
name: "controlmode",
setter: "set_controlmode",
style: "enumindex",
enumvals: ["View space", "Object space"],
label: "Control Mode",
})
var show_bounds = 1;
declareattribute({
name: "show_bounds",
@@ -81,7 +91,6 @@ const ANIMABLE_GL_OBJECTS = [
"jit_gl_camera",
];
let controlled_gl_objects = []; // Used for enabling.disabling drawbounds on object(s) animated by the controller
let controllable_objects = []; // Used for listing all controllable objects in a patch
let top_level_patcher;
@@ -92,7 +101,9 @@ class Controller {
this.ease = 0.1; // anim.drive easing
this.flymode = false;
this.flymode_applyed = false; // Flag
this.control_mode; // 'cam' if the camera is the target, 'obj' otherwise
this.control_obj_type; // 'cam' if the camera is the target, 'obj' otherwise
this.root_anim_node = null; // The implicit drawto context anim node
this.world_up = [0, 1, 0];
this.camera_target = {
@@ -100,7 +111,7 @@ class Controller {
class: '',
anim: '',
}
this.camera_node_implicit = new JitterObject("jit.anim.node"); // Used if camera isn't attached to an anim.node
this.camera_node_implicit = new JitterObject("jit.anim.node"); // Used if camera isn't attached to an anim.node (using the pre-made anim node of a jit.gl.camera doesn't work for some reason, so we use our own "implicit" one)
this.camera_node_implicit.name = "camera_node_implicit";
this.camera_node = new JitterObject("jit.proxy"); // Either proxy of a jit.anim.node defined by user, or of this.camera_node_implicit
this.cam_direction, this.cam_up, this.cam_right;
@@ -122,6 +133,7 @@ class Controller {
// pitch_node used with pitch_drive for pitch rotation (over the objects local x axis)
this.pitch_node = new JitterObject("jit.anim.node");
this.pitch_node.name = "fp_pitch_node";
this.pitch_node.anim = this.main_node.name;
this.pitch_node.turnmode = "parent";
this.pitch_node.movemode = "parent";
@@ -131,57 +143,107 @@ class Controller {
this.pitch_drive.ease = this.ease;
this.pitch_drive.targetname = this.pitch_node.name;
this.target = new JitterObject("jit.proxy"); // Stores the object to control
this.target = new JitterObject("jit.proxy"); // Stores the object to control (always an anim.node)
this.last_target_anim_node = null; // Stores which parent anim.node was bound to our target, so we can restore it later
this.target_type; // Class of the target object
// For displaying bounds, we rely on our own jit.gl.mesh cube. It's simpler than keeping track of each objects draw_bounds attribute, and we can customize its appearance.
this.show_bounds = show_bounds;
this.cube_matrix = new JitterMatrix(3, "float32", 8);
const cube_points = new Float32Array([-1., -1., 1., 1., -1., 1., 1., 1., 1., -1., 1., 1., -1., -1., -1., 1., -1., -1., 1., 1., -1., -1., 1., -1.]);
this.cube_matrix.copyarraytomatrix(cube_points);
this.cube_indexes = new JitterMatrix(1, "char", 24);
const cube_point_indexes = new Uint8Array([0, 1, 1, 2, 2, 3, 3, 0, 0, 4, 1, 5, 2, 6, 3, 7, 4, 5, 5, 6, 6, 7, 7, 4]);
this.cube_indexes.copyarraytomatrix(cube_point_indexes);
this.bounds = new JitterObject("jit.gl.mesh");
this.bounds.drawto = drawto;
this.bounds.draw_mode = "lines";
this.bounds.vertex_matrix(this.cube_matrix.name);
this.bounds.index_matrix(this.cube_indexes.name);
this.bounds.anim = this.pitch_node.name;
this.bounds.enable = 0;
this.dummy_node = new JitterObject("jit.anim.node"); // Only used for quat to euler conversion
}
// Taking control over a new target
control(obj_name, ctrl_mode) {
control(obj_name, obj_type) {
if (!this.camera_target.name) {
error("No camera defined. Cannot control object.\n");
return false;
}
// Make sure the requested object is a jit.anim.node or a controllable object (a jit.gl object with an anim attribute)
let new_target;
if (obj_name != undefined) {
new_target = get_anim_node(obj_name, this.pitch_node.name);
const p = new JitterObject("jit.proxy");
p.name = obj_name;
if (p.class === "jit_anim_node") {
new_target = obj_name;
} else if (p.class && is_controllable(p.class)) {
new_target = p.send("getanim");
};
this.target_type = p.class;
p.freepeer();
}
if (
new_target != undefined &&
(this.target.name != "" || this.target.name != new_target)
) {
this.control_mode = ctrl_mode;
// New object to target
this.control_obj_type = obj_type;
if (this.target.name != "") {
const transform = this.target.send("getworldtransform"); // Get the current targets tranfsorm,
this.target.send("anim"); // Unbind it (makes it loose its transform part coming from Controller nodes)
this.target.send("anim_reset"); // Reset it
this.target.send("transform", transform); // And re-apply the transform so it stays in place
// If there is already a targeted object, we unbind it and make it preserve its transform
const world_pos = this.target.send("getworldpos");
const world_quat = this.target.send("getworldquat");
const world_scale = this.target.send("getworldscale");
if (this.last_target_anim_node) {
this.target.send("anim", this.last_target_anim_node);
} else {
this.target.send("anim");
}
this.target.send("anim_reset");
const local = this.world_to_local(this.last_target_anim_node, world_pos, world_quat);
this.target.send("position", local.pos);
this.target.send("quat", local.quat);
this.target.send("scale", world_scale);
}
this.target.name = new_target; // Bind to new target
this.reset(); // Reset this.Controller anim nodes
this.main_node.position = this.target.send("getworldpos"); // Take the target position, rotatexyz and scale and pass them to this.Controller anim nodes
let target_rotatexyz = this.target.send("getrotatexyz");
this.main_node.rotatexyz = [0, target_rotatexyz[1], 0];
this.pitch_node.rotatexyz = [target_rotatexyz[0], 0, target_rotatexyz[2]];
this.pitch_node.scale = this.target.send("getscale");
this.reset(); // Reset controller anim nodes
// Get target transform
const world_pos = this.target.send("getworldpos");
const world_quat = this.target.send("getworldquat");
const world_scale = this.target.send("getworldscale");
this.dummy_node.quat = world_quat;
const world_rotatexyz = this.dummy_node.rotatexyz;
// Apply it to our control nodes
this.main_node.position = world_pos;
this.main_node.rotatexyz = [0, world_rotatexyz[1], 0];
this.pitch_node.rotatexyz = [world_rotatexyz[0], 0, world_rotatexyz[2]];
this.pitch_node.scale = world_scale;
// And select the new target
this.last_target_anim_node = this.target.send("getanim");
this.target.send("anim_reset");
this.target.send("anim", this.pitch_node.name);
this.target.send("update_node"); //Sometimes targetting an anim.node parent with anim.node children doesn't work (children don't get their transform updated). This solves it for some reason.
// Apply specific rules depending on if controlling the camera or an object
if (this.control_mode == "cam") {
// If this.camera() is set before the jit.world starts, there is a chance that camera_node is bound to the wrong node.
// this.camera(this.camera_target.name);
if (this.control_obj_type == "cam") {
this.main_node.movemode = "local";
this.main_node.turnmode = "local";
this.pitch_node.turnmode = "parent";
this.has_rotated = false;
this.set_flymode(this.flymode);
} else {
this.flymode_applyed = false;
if (controlmode == 0) {
// When controlling an object, we convert the translation vector
// from screen space to world space in this.move
// So we need the cam base matrix
@@ -189,15 +251,35 @@ class Controller {
this.main_node.turnmode = "world";
this.pitch_node.turnmode = "world";
this.get_cam_base_matrix();
} else {
this.main_node.movemode = "local";
this.main_node.turnmode = "local";
this.pitch_node.turnmode = "parent";
}
}
// No target
} else if (obj_name == undefined && this.target.name != "") {
// No target, unbinding previous target
const world_pos = this.target.send("getworldpos");
const world_quat = this.target.send("getworldquat");
const world_scale = this.target.send("getworldscale");
if (this.last_target_anim_node) {
this.target.send("anim", this.last_target_anim_node);
} else {
this.target.send("anim");
}
this.target.send("anim_reset");
this.target.send("transform", this.pitch_node.worldtransform);
const local = this.world_to_local(this.last_target_anim_node, world_pos, world_quat);
this.target.send("position", local.pos);
this.target.send("quat", local.quat);
this.target.send("scale", world_scale);
this.last_target_anim_node = null;
this.target.name = "";
}
this.set_bounds();
outlet(0, "control", obj_name, this.target.name);
return true;
}
@@ -219,7 +301,6 @@ class Controller {
const transform = cam_anim.send("getworldtransform");
cam_anim.freepeer();
// Then we attach our camera_node_implicit to the camera and restore its world transform
// this.camera_node_implicit.anim_reset();
proxy.send("anim_reset");
proxy.send("anim", this.camera_node_implicit.name);
this.camera_node_implicit.transform = transform;
@@ -227,13 +308,12 @@ class Controller {
}
if (target) {
this.camera_node.name = target;
camera_node = target;
this.camera_node.send("animmode", "world");
this.get_cam_base_matrix();
// this.get_cam_base_matrix();
this.camera_target.name = proxy.name;
this.camera_target.class = proxy.class;
this.camera_target.anim = proxy.anim;
camera_node = target;
camera = target;
} else {
this.unbind_camera();
}
@@ -248,11 +328,11 @@ class Controller {
} else if (this.camera_target.class === "jit_gl_camera") {
// If it was a camera, we set it back as it was, but with the current transform
const transform = this.camera_node.send("getworldtransform");
const cam = new JitterObject("jit_proxy");
const cam = new JitterObject("jit.proxy");
cam.name = this.camera_target.name;
cam.send("anim");
cam.send("anim_reset");
const cam_anim = new JitterObject("jit_proxy");
const cam_anim = new JitterObject("jit.proxy");
cam_anim.name = cam.send("getanim");
cam_anim.send("transform", transform);
cam.freepeer();
@@ -262,7 +342,7 @@ class Controller {
this.camera_target.name = "";
this.camera_target.class = "";
this.camera_target.anim = "";
camera_node = "";
camera = "";
}
}
@@ -283,7 +363,8 @@ class Controller {
move(x, y, z) {
let translat_vec = [x, y, z];
if (this.control_mode == "obj") {
if (this.control_obj_type == "obj" && controlmode == 0) {
this.get_cam_base_matrix();
let cam_x_rot = this.camera_node.send("getrotatexyz")[0];
// Inverse translation direction if cam is upside down
if (cam_x_rot < -90 || cam_x_rot > 90) {
@@ -297,11 +378,12 @@ class Controller {
turn(x, y, z) {
let rot_vec = [x, y, z];
if (this.control_mode == "obj") {
if (this.control_obj_type == "obj") {
this.get_cam_base_matrix();
rot_vec = multiplyMatrixVector(this.camera_base_matrix, [-x, 0, 0]);
rot_vec[1] = -y;
}
if (this.flymode && this.control_mode == "cam") {
if (this.flymode && this.control_obj_type == "cam") {
// When flymode is enabled, we apply all rotations to the main_node
// so that the cam can move toward the direction it is pointing to
this.main_drive.turn(rot_vec[0], rot_vec[1], 0);
@@ -328,7 +410,7 @@ class Controller {
}
apply_flymode() {
if (this.control_mode == "cam") {
if (this.control_obj_type == "cam") {
if (this.flymode) {
// When enabling flymode, we move all rotations to main_node
this.main_node.rotatexyz = [
@@ -352,6 +434,7 @@ class Controller {
set_drawto(v) {
this.main_drive.drawto = v;
this.pitch_drive.drawto = v;
this.bounds.drawto = v;
}
set_ease(v) {
@@ -367,10 +450,43 @@ class Controller {
resync() {
if (this.target.name != "") {
this.control(this.target.name, this.control_mode);
this.control(this.target.name, this.control_obj_type);
}
}
set_show_bounds(v) {
this.show_bounds = v ? 1 : 0;
this.set_bounds();
}
set_bounds() {
if (this.show_bounds && this.control_obj_type === "obj") {
switch (this.target_type) {
case "jit_anim_node":
this.bounds.color = [1, 0, 1, 1];
break;
default:
this.bounds.color = [1, 1, 1, 1];
break;
}
this.bounds.enable = 1;
} else {
this.bounds.enable = 0;
}
}
world_to_local(anim_node_name, world_pos, world_quat) {
if (!anim_node_name) {
return { pos: world_pos, quat: world_quat };
}
const parent = new JitterObject("jit.proxy");
parent.name = anim_node_name;
const pos = parent.send("worldtolocal", world_pos);
const quat = parent.send("worldtolocal_quat", world_quat);
parent.freepeer();
return { pos, quat };
}
destroy() {
if (this.target.name != "") {
this.target.send("anim");
@@ -382,35 +498,33 @@ class Controller {
this.pitch_node.freepeer();
this.pitch_drive.freepeer();
this.target.freepeer();
this.cube_indexes.freepeer();
this.cube_matrix.freepeer();
this.bounds.freepeer();
this.dummy_node.freepeer();
}
}
loadbang();
// Select the object to use as basis for view-space transforms
function camera(name) {
function set_camera(name) {
camera = name;
if (world_bangs) {
ctlr.camera(name);
camera_node = ctlr.camera_node.name;
}
}
// Select which object to control in view-space
function control(obj_name) {
ctlr.control(obj_name, "obj");
if (show_bounds) {
do_show_bounds(0);
}
controlled_gl_objects = [];
get_gl_obj_controlled_by_ctlr();
if (show_bounds) {
do_show_bounds(show_bounds);
}
}
// Select which camera to control
function control_camera(obj_name) {
if (obj_name !== undefined) {
const answer = ctlr.control(obj_name, "cam");
if (answer) do_show_bounds(0);
// if (answer) do_show_bounds(0);
}
}
@@ -472,31 +586,26 @@ function set_ease(v) {
ctlr.set_ease(v);
ease = v;
}
set_ease.local = 1;
function set_flymode(v) {
flymode = v == undefined ? !flymode : v == 1; // If flymode with no argument is provided, act as a toggle
ctlr.set_flymode(flymode);
}
set_flymode.local = 1;
function set_show_bounds(v) {
show_bounds = v == true;
// ctlr.show_bounds = show_bounds;
do_show_bounds(show_bounds);
ctlr.set_show_bounds(show_bounds);
}
set_show_bounds.local = 1;
function do_show_bounds(v) {
const objects_without_bounds = [
"jit.gl.sketch",
"jit.gl.skybox",
"jit.gl.camera",
];
for (const obj of controlled_gl_objects) {
if (!objects_without_bounds.includes(obj.maxclass)) {
obj.setattr("drawbounds", v);
}
}
function set_controlmode(v) {
const new_val = v > 0 ? 1 : 0;
if (controlmode === new_val) return;
controlmode = new_val;
ctlr.control(ctlr.target.name, ctlr.control_obj_type);
}
do_show_bounds.local = 1;
function bang() {
outlet(0, ctlr.pitch_node.worldtransform);
@@ -511,63 +620,21 @@ function loadbang() {
function notifydeleted() {
ctlr.destroy();
implicit_tracker.freepeer();
ctx_finder.dispose();
if (ctx_lstnr) ctx_lstnr.freepeer();
// implicit_tracker.freepeer();
}
/////////////////////////////////////////////
// HELPER METHODS
/////////////////////////////////////////////
function get_anim_node(jit_obj_name, ctlr_node) {
const proxy = new JitterObject("jit.proxy");
proxy.name = jit_obj_name;
const proxy_class = proxy.class;
proxy.freepeer();
if (proxy_class == "jit_anim_node") {
return jit_obj_name;
} else if (proxy_class != "" && is_controllable(proxy_class)) {
const context_anim = get_context_anim(jit_obj_name);
return get_top_level_anim_node(jit_obj_name, context_anim, ctlr_node);
}
return;
}
get_anim_node.local = 1;
function is_controllable(obj_class) {
// Using jit.proxy syntax (ie 'jit_gl_mesh' and not 'jit.gl.mesh')
return ANIMABLE_GL_OBJECTS.includes(obj_class);
}
is_controllable.local = 1;
function get_context_anim(jit_obj_name) {
// Get the first implicit jit.anim.node level for the object's rendering context
const proxy = new JitterObject("jit.proxy");
proxy.name = jit_obj_name;
proxy.name = proxy.send("getdrawto");
const context_name = proxy.send("getanim");
proxy.freepeer();
return context_name;
}
get_context_anim.local = 1;
function get_top_level_anim_node(jit_obj_name, context_anim, ctlr_node) {
// Recursively get the top level jit.anim.node before reaching context_anim, or no anim.node, or this.pitch_node (if trying to controller currently controlled object)
const proxy = new JitterObject("jit.proxy");
proxy.name = jit_obj_name;
const parent_name = proxy.send("getanim").toString();
proxy.freepeer();
if (
parent_name == "" ||
parent_name == context_anim ||
parent_name == ctlr_node
) {
return jit_obj_name;
} else {
return get_top_level_anim_node(parent_name, context_anim, ctlr_node);
}
}
get_top_level_anim_node.local = 1;
function get_top_level_patcher() {
let prev = 0;
let owner = this.patcher.box;
@@ -579,37 +646,6 @@ function get_top_level_patcher() {
}
get_top_level_patcher.local = 1;
// Get gl object(s) controlled by ctlr (for the sole purpose of drawing bounds of selected object)
function get_gl_obj_controlled_by_ctlr() {
top_level_patcher.applydeepif(
add_to_controlled_obj_list,
is_controlled_by_ctlr
);
}
get_gl_obj_controlled_by_ctlr.local = 1;
function is_controlled_by_ctlr(obj) {
if (is_controllable(obj.maxclass.replaceAll(".", "_"))) {
const obj_anim = obj.getattr("anim");
if (obj_anim == ctlr.pitch_node.name) {
return true;
} else if (obj_anim != "") {
const proxy = new JitterObject("jit.proxy");
proxy.name = obj_anim;
const parent_name = proxy.send("getanim").toString();
proxy.freepeer();
return parent_name == ctlr.pitch_node.name;
}
}
return false;
}
is_controlled_by_ctlr.local = 1;
function add_to_controlled_obj_list(obj) {
controlled_gl_objects.push(obj);
}
add_to_controlled_obj_list.local = 1;
/////////////////////////////////////////////
// MATHS
/////////////////////////////////////////////
@@ -647,29 +683,33 @@ multiplyMatrixVector.local = 1;
/////////////////////////////////////////////
// GL Context
/////////////////////////////////////////////
let ctx_root;
let ctx_lstnr;
function set_root(new_root) {
ctx_root = new_root;
if (ctx_lstnr) {
ctx_lstnr.freepeer();
ctw_lstnr = null;
}
ctx_lstnr = new JitterListener(new_root, ctx_callback);
}
set_root.local = 1;
let implicitdrawto = "";
let explicitdrawto = false;
const implicit_tracker = new JitterObject("jit_gl_implicit");
const implicit_lstnr = new JitterListener(
implicit_tracker.name,
implicit_callback
);
function implicit_callback(event) {
if (!explicitdrawto && implicitdrawto != implicit_tracker.drawto[0]) {
// important! drawto is an array so get first element
implicitdrawto = implicit_tracker.drawto[0];
dosetdrawto(implicitdrawto);
function ctx_callback(event) {
switch (event.eventname) {
case "swap": case "draw":
if (!world_bangs) {
// First world bang: world initialized, we can set the camera
world_bangs = true;
set_camera(camera);
}
break;
default:
// post(event.args); post();
break;
}
}
implicit_callback.local = 1;
function setdrawto(val) {
explicitdrawto = true;
dosetdrawto(val);
}
setdrawto.local = 1;
ctx_callback.local = 1;
function dosetdrawto(arg) {
if (arg === drawto || !arg) {
@@ -679,5 +719,7 @@ function dosetdrawto(arg) {
drawto = arg;
ctlr.set_drawto(drawto);
ctx_proxy.name = drawto;
}
dosetdrawto.local = 1;