@@ -1316,11 +1316,15 @@ self.onmessage = ({ data: msg }) => {
13161316 }
13171317
13181318 _getCameraState ( ) {
1319+ return this . _getCameraStateByName ( this . cameraFollowName || 'default' ) ;
1320+ }
1321+
1322+ _getCameraStateByName ( name ) {
13191323 if ( ! isPenguinMod ) return null ;
13201324 const runtime = Scratch . vm . runtime ;
13211325 if ( typeof runtime . getCamera !== 'function' ) return null ;
13221326 try {
1323- return runtime . getCamera ( this . cameraFollowName || 'default' ) ;
1327+ return runtime . getCamera ( name ) ;
13241328 } catch ( e ) {
13251329 return null ;
13261330 }
@@ -1336,6 +1340,39 @@ self.onmessage = ({ data: msg }) => {
13361340 this . _markDirty ( ) ;
13371341 }
13381342
1343+ setLightCameraFollow ( args ) {
1344+ const id = Scratch . Cast . toString ( args . ID ) ;
1345+ const state = Scratch . Cast . toString ( args . STATE ) ;
1346+ if ( ! this . lights [ id ] ) return ;
1347+ if ( state === 'none' ) {
1348+ this . lights [ id ] . cameraOverride = 'none' ;
1349+ } else if ( state === 'global' ) {
1350+ this . lights [ id ] . cameraOverride = null ;
1351+ } else if ( state === 'custom' ) {
1352+ if ( this . lights [ id ] . cameraOverride === null || this . lights [ id ] . cameraOverride === 'none' ) {
1353+ this . lights [ id ] . cameraOverride = this . cameraFollowName || 'default' ;
1354+ }
1355+ }
1356+ this . _markDirty ( ) ;
1357+ }
1358+
1359+ setLightCameraName ( args ) {
1360+ const id = Scratch . Cast . toString ( args . ID ) ;
1361+ const name = Scratch . Cast . toString ( args . NAME ) || 'default' ;
1362+ if ( ! this . lights [ id ] ) return ;
1363+ this . lights [ id ] . cameraOverride = name ;
1364+ this . _markDirty ( ) ;
1365+ }
1366+
1367+ getLightCameraFollow ( args ) {
1368+ const id = Scratch . Cast . toString ( args . ID ) ;
1369+ if ( ! this . lights [ id ] ) return '' ;
1370+ const ov = this . lights [ id ] . cameraOverride ;
1371+ if ( ov === null || ov === undefined ) return 'global' ;
1372+ if ( ov === 'none' ) return 'none' ;
1373+ return ov ;
1374+ }
1375+
13391376 _fillUBOData ( w , h ) {
13401377 const lights = Object . values ( this . lights ) ;
13411378 const n = lights . length ;
@@ -1345,24 +1382,50 @@ self.onmessage = ({ data: msg }) => {
13451382 }
13461383 const buf = this . _uboData ;
13471384
1348- let camX = 0 , camY = 0 , camScale = 1 , camDirRad = 0 ;
1385+ let globalCamX = 0 , globalCamY = 0 , globalCamScale = 1 , globalCamDirRad = 0 ;
13491386 if ( this . cameraFollow && isPenguinMod ) {
13501387 const cam = this . _getCameraState ( ) ;
13511388 if ( cam ) {
1352- camX = cam . pos [ 0 ] ;
1353- camY = cam . pos [ 1 ] ;
1354- camScale = cam . scale || 1 ;
1355- camDirRad = cam . dir * ( Math . PI / 180 ) ;
1389+ globalCamX = cam . pos [ 0 ] ;
1390+ globalCamY = cam . pos [ 1 ] ;
1391+ globalCamScale = cam . scale || 1 ;
1392+ globalCamDirRad = cam . dir * ( Math . PI / 180 ) ;
13561393 }
13571394 }
13581395
1359- const cosA = Math . cos ( - camDirRad ) ;
1360- const sinA = Math . sin ( - camDirRad ) ;
1396+ const _camCache = { } ;
1397+ const _resolveCamera = ( name ) => {
1398+ if ( _camCache [ name ] !== undefined ) return _camCache [ name ] ;
1399+ const cam = this . _getCameraStateByName ( name ) ;
1400+ _camCache [ name ] = cam ;
1401+ return cam ;
1402+ } ;
13611403
13621404 for ( let i = 0 ; i < n ; i ++ ) {
13631405 const li = lights [ i ] ;
13641406 const base = i * 12 ;
13651407
1408+ let camX = globalCamX , camY = globalCamY , camScale = globalCamScale , camDirRad = globalCamDirRad ;
1409+
1410+ if ( isPenguinMod && li . cameraOverride !== undefined && li . cameraOverride !== null ) {
1411+ if ( li . cameraOverride === 'none' ) {
1412+ camX = 0 ; camY = 0 ; camScale = 1 ; camDirRad = 0 ;
1413+ } else {
1414+ const cam = _resolveCamera ( li . cameraOverride ) ;
1415+ if ( cam ) {
1416+ camX = cam . pos [ 0 ] ;
1417+ camY = cam . pos [ 1 ] ;
1418+ camScale = cam . scale || 1 ;
1419+ camDirRad = cam . dir * ( Math . PI / 180 ) ;
1420+ } else {
1421+ camX = 0 ; camY = 0 ; camScale = 1 ; camDirRad = 0 ;
1422+ }
1423+ }
1424+ }
1425+
1426+ const cosA = Math . cos ( - camDirRad ) ;
1427+ const sinA = Math . sin ( - camDirRad ) ;
1428+
13661429 let lx = li . x - camX ;
13671430 let ly = li . y - camY ;
13681431 const rx = ( lx * cosA - ly * sinA ) / camScale ;
@@ -1753,6 +1816,51 @@ self.onmessage = ({ data: msg }) => {
17531816 }
17541817 } ,
17551818 '---' ,
1819+ {
1820+ opcode : 'setLightCameraFollow' ,
1821+ blockType : Scratch . BlockType . COMMAND ,
1822+ hideFromPalette : ! isPenguinMod ,
1823+ text : 'set light [ID] camera follow [STATE]' ,
1824+ arguments : {
1825+ ID : {
1826+ type : Scratch . ArgumentType . STRING ,
1827+ defaultValue : 'light1'
1828+ } ,
1829+ STATE : {
1830+ type : Scratch . ArgumentType . STRING ,
1831+ menu : 'lightCameraFollowMenu'
1832+ }
1833+ }
1834+ } ,
1835+ {
1836+ opcode : 'setLightCameraName' ,
1837+ blockType : Scratch . BlockType . COMMAND ,
1838+ hideFromPalette : ! isPenguinMod ,
1839+ text : 'set light [ID] to follow camera [NAME]' ,
1840+ arguments : {
1841+ ID : {
1842+ type : Scratch . ArgumentType . STRING ,
1843+ defaultValue : 'light1'
1844+ } ,
1845+ NAME : {
1846+ type : Scratch . ArgumentType . STRING ,
1847+ defaultValue : 'default'
1848+ }
1849+ }
1850+ } ,
1851+ {
1852+ opcode : 'getLightCameraFollow' ,
1853+ blockType : Scratch . BlockType . REPORTER ,
1854+ hideFromPalette : ! isPenguinMod ,
1855+ text : 'light [ID] camera follow' ,
1856+ arguments : {
1857+ ID : {
1858+ type : Scratch . ArgumentType . STRING ,
1859+ defaultValue : 'light1'
1860+ }
1861+ }
1862+ } ,
1863+ '---' ,
17561864 '---' ,
17571865 {
17581866 blockType : Scratch . BlockType . LABEL ,
@@ -1963,7 +2071,6 @@ self.onmessage = ({ data: msg }) => {
19632071 }
19642072 }
19652073 } ,
1966- '---' ,
19672074 {
19682075 blockType : Scratch . BlockType . LABEL ,
19692076 text : 'Read Lights'
@@ -2208,6 +2315,10 @@ self.onmessage = ({ data: msg }) => {
22082315 acceptReporters : false ,
22092316 items : [ 'on' , 'off' ]
22102317 } ,
2318+ lightCameraFollowMenu : {
2319+ acceptReporters : false ,
2320+ items : [ 'global' , 'none' , 'custom' ]
2321+ } ,
22112322 settingMenu : {
22122323 acceptReporters : false ,
22132324 items : [ 'shadowOpacity' , 'ambient' , 'bloomAmount' , 'bloomRadius' , 'bloomThreshold' , 'pixelated' , 'pixelSize' , 'contrast' , 'colorTemp' , 'resetLightsOnStart' , 'renderThread' , 'cameraFollow' , 'cameraFollowName' ]
0 commit comments