252 lines
7.6 KiB
JavaScript
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;
|
|
|