Files
2026-05-23 22:10:14 +08:00

252 lines
7.6 KiB
JavaScript

/*******************************************************************************
*
* Nx JS扩展
*
*
*
* 2021.12.10
******************************************************************************/
const NxObject = require( "nx.object" );
// DataView扩展
const exDataView = function() {
// DataView 64位UINT解析
DataView.prototype.getUint64 = function( byteOffset, littleEndian ) {
const left = this.getUint32( byteOffset, littleEndian );
const right = this.getUint32( byteOffset + 4, littleEndian );
const combine = littleEndian ? ( left + 2 ** 32 * right ) : ( 2 ** 32 * left + right );
if( !Number.isSafeInteger( combine ) ) {
cc.warn( "64Int精度丢失!" );
}
return combine;
}
};
// MeshBuffer扩展
const exMeshBuffer = function() {
const FIX_IOS14_BUFFER = ( cc.sys.os === cc.sys.OS_IOS || cc.sys.os === cc.sys.MACOS ) && cc.sys.isBrowser && /(OS 1[4-9])|(Version\/1[4-9])/.test( window.navigator.userAgent );
if( FIX_IOS14_BUFFER ) {
cc.MeshBuffer.prototype.checkAndSwitchBuffer = function( vertexCount ) {
if( this.vertexOffset + vertexCount > 65535 ) {
this.uploadData();
this._batcher._flush();
}
};
}
};
// RenderFlower扩展
const exRenderFlower = function() {
let FlagOfset = 0;
const DONOTHING = 1 << FlagOfset++;
const BREAK_FLOW = 1 << FlagOfset++;
const LOCAL_TRANSFORM = 1 << FlagOfset++;
const WORLD_TRANSFORM = 1 << FlagOfset++;
const TRANSFORM = LOCAL_TRANSFORM | WORLD_TRANSFORM;
const UPDATE_RENDER_DATA = 1 << FlagOfset++;
const OPACITY = 1 << FlagOfset++;
const COLOR = 1 << FlagOfset++;
const OPACITY_COLOR = OPACITY | COLOR;
const RENDER = 1 << FlagOfset++;
const CHILDREN = 1 << FlagOfset++;
const POST_RENDER = 1 << FlagOfset++;
const FINAL = 1 << FlagOfset++;
const renderFlow = cc[ "RenderFlow" ];
const _batcher = renderFlow.getBachther();
let __levelBatcher = [];
let __renderQueue = [];
Object.defineProperty( renderFlow.prototype, "_opacity", {
value: function( node ) {
_batcher.parentOpacityDirty++;
if( node[ "__levelRender" ] && __levelBatcher[ node[ "__itemIndex" ] ] ) {
__levelBatcher[ node[ "__itemIndex" ] ].parentOpacityDirty = 1;
}
this._next._func( node );
node._renderFlag &= ~OPACITY;
if( node[ "__levelRender" ] && __levelBatcher[ node[ "__itemIndex" ] ] && node[ "__lastChildren" ] ) {
__levelBatcher[ node.__itemIndex ].parentOpacityDirty = 0;
}
_batcher.parentOpacityDirty--;
}
} )
Object.defineProperty( renderFlow.prototype, "_worldTransform", {
value: function( node ) {
_batcher.worldMatDirty++;
if( node[ "__levelRender" ] && __levelBatcher[ node[ "__itemIndex" ] ] ) {
__levelBatcher[ node[ "__itemIndex" ] ].worldMatDirty = 1;
}
let t = node._matrix;
let trs = node._trs;
let tm = t.m;
tm[ 12 ] = trs[ 0 ];
tm[ 13 ] = trs[ 1 ];
tm[ 14 ] = trs[ 2 ];
node._mulMat( node._worldMatrix, node._parent._worldMatrix, t );
node._renderFlag &= ~WORLD_TRANSFORM;
this._next._func( node );
if( node[ "__levelRender" ] && __levelBatcher[ node[ "__itemIndex" ] ] && node[ "__lastChildren" ] ) {
__levelBatcher[ node.__itemIndex ].worldMatDirty = 0;
}
_batcher.worldMatDirty--;
}
} );
const levelSplit = ( node, lv, itemIndex ) => {
if( !__renderQueue[ lv ] ) {
__renderQueue[ lv ] = [];
}
__renderQueue[ lv ].push( node );
lv++;
node[ "__renderLv" ] = lv;
node[ "__levelRender" ] = true;
node[ "__itemIndex" ] = itemIndex;
const cs = node.children;
for( let i = 0; i < cs.length; ++i ) {
const c = cs[ i ];
if( !__renderQueue[ lv ] ) {
__renderQueue[ lv ] = [];
}
lv = levelSplit( c, lv, itemIndex );
}
return lv;
}
const checkLevelRender = ( levelRenderNode ) => {
const cs = levelRenderNode.children;
let rootOpacityInHierarchy = levelRenderNode[ "opacity" ] / 255;
__levelBatcher = [];
for( let i = 0; i < cs.length; ++i ) {
__levelBatcher.push( { worldMatDirty: 0, parentOpacityDirty: 0 } );
levelSplit( cs[ i ], 0, i );
}
while( __renderQueue.length > 0 ) {
const list = __renderQueue.shift();
if( list.length > 0 ) {
while( list.length > 0 ) {
const n = list.shift();
n[ "__lastChildren" ] = __renderQueue.length == 0;
n[ "__levelRender" ] = true;
let opacityInHierarchy = n.parent[ "__opacityInHierarchy" ];
if( opacityInHierarchy === undefined ) {
opacityInHierarchy = rootOpacityInHierarchy;
}
let opacity = ( opacityInHierarchy * ( n[ "_opacity" ] / 255 ) );
n[ "__opacityInHierarchy" ] = opacity;
let cullingMask = n[ "_cullingMask" ];
let worldMatDirty = 0;
if( __levelBatcher[ n[ "__itemIndex" ] ] ) {
worldMatDirty = __levelBatcher[ n[ "__itemIndex" ] ].worldMatDirty || 0;
}
let parentOpacityDirty = 0;
if( __levelBatcher[ n[ "__itemIndex" ] ] ) {
parentOpacityDirty = __levelBatcher[ n[ "__itemIndex" ] ].parentOpacityDirty || 0;
}
let worldTransformFlag = ( worldMatDirty || _batcher.worldMatDirty ) ? WORLD_TRANSFORM : 0;
let worldOpacityFlag = ( parentOpacityDirty || _batcher.parentOpacityDirty ) ? OPACITY_COLOR : 0;
let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
n[ "_renderFlag" ] |= worldDirtyFlag;
if( !n[ "_activeInHierarchy" ] || n[ "_opacity" ] === 0 ) continue;
n[ "_cullingMask" ] = n.groupIndex === 0 ? cullingMask : 1 << n.groupIndex;
// TODO: Maybe has better way to implement cascade opacity
let colorVal = n[ "_color" ]._val;
n[ "_color" ]._fastSetA( n[ "_opacity" ] * opacity );
renderFlow.flows[ n[ "_renderFlag" ] ]._func( n );
n[ "_color" ]._val = colorVal;
}
}
}
}
Object.defineProperty( renderFlow.prototype, "_children", {
value: function( node ) {
if( node.__levelRender ) return;
let cullingMask = node._cullingMask;
let enableLevelRender = node[ "__enableLevelRender" ];
const parentOpacityInHierarchy = node.parent ? node.parent[ "__opacityInHierarchy" ] : undefined;
let parentOpacity = parentOpacityInHierarchy !== undefined ? parentOpacityInHierarchy : _batcher.parentOpacity;
if( !enableLevelRender && !node.__levelRender ) {
let opacity = ( parentOpacity *= ( node._opacity / 255 ) );
node[ "__opacityInHierarchy" ] = opacity;
let worldTransformFlag = _batcher.worldMatDirty ? WORLD_TRANSFORM : 0;
let worldOpacityFlag = _batcher.parentOpacityDirty ? OPACITY_COLOR : 0;
let worldDirtyFlag = worldTransformFlag | worldOpacityFlag;
let children = node._children;
for( let i = 0, l = children.length; i < l; i++ ) {
let c = children[ i ];
// Advance the modification of the flag to avoid node attribute modification is invalid when opacity === 0.
c._renderFlag |= worldDirtyFlag;
c[ "__opacityInHierarchy" ] = c._opacity * opacity / 255;
if( !c._activeInHierarchy || c._opacity === 0 ) continue;
c._cullingMask = c.groupIndex === 0 ? cullingMask : 1 << c.groupIndex;
// TODO: Maybe has better way to implement cascade opacity
let colorVal = c._color._val;
c._color._fastSetA( c._opacity * opacity );
renderFlow.flows[ c._renderFlag ]._func( c )
c._color._val = colorVal;
}
} else {
checkLevelRender( node );
}
_batcher.parentOpacity = parentOpacity;
this._next._func( node );
}
} )
};
const nxJS = cc.Class( {
extends: NxObject,
name: "nxJS",
// 初始化
initialize: function( _args ) {
// USPER
this._super( _args );
// DataView扩展
exDataView();
// MeshBuffer扩展
exMeshBuffer();
// RenderFlower扩展
exRenderFlower();
return true;
},
// 销毁
uninitialize: function() {
// USPER
return this._super();
},
} );
// 模块导出
module.exports = nxJS;