import { CoordinateController , InteractiveConfig , InteractiveType , SceneMouseEvent } from '@turbox3d/event-manager' ; import { BaseScene , BaseSceneProps , SceneType } from '@turbox3d/graphic-view' ; import { Vec2 , Vec3 } from '@turbox3d/shared' ; import * as PIXI from 'pixi.js' ; import React from 'react' ; import { Scene2dContext } from './context' ; const interactiveMgr = new PIXI . InteractionManager ( { } as any ) ; export const Scene2DSymbol = Symbol ( 'scene2d' ) ; class CoordinateControllerPixi extends CoordinateController { scene2d : Scene2D ; constructor ( canvas , scene ) { super ( canvas ) ; this . scene2d = scene ; } canvasToSceneImpl ( point ) { const { x , y } = this . scene2d . view . position ; let scale = this . scene2d . view . scale . x ; if ( this . scene2d . props . coordinateType && ( this . scene2d . props . coordinateType === 'front' || this . scene2d . props . coordinateType === 'left' ) ) { scale = - scale ; } let newX = ( point . x - x ) / this . scene2d . view . scale . x ; let newY = ( point . y - y ) / scale ; if ( this . scene2d . props . viewport ) { newX = ( point . x - this . scene2d . props . viewport . x - x ) / this . scene2d . view . scale . x ; newY = ( point . y - this . scene2d . props . viewport . y - y ) / scale ; } return { x : newX , y : newY , } ; } sceneToCanvasImpl ( point ) { const { x , y } = this . scene2d . view . position ; let scale = this . scene2d . view . scale . x ; if ( this . scene2d . props . coordinateType && ( this . scene2d . props . coordinateType === 'front' || this . scene2d . props . coordinateType === 'left' ) ) { scale = - scale ; } let newX = point . x * this . scene2d . view . scale . x + x ; let newY = point . y * scale + y ; if ( this . scene2d . props . viewport ) { newX = point . x * this . scene2d . view . scale . x + x + this . scene2d . props . viewport . x ; newY = point . y * scale + y + this . scene2d . props . viewport . y ; } return { x : newX , y : newY , } ; } } export class Scene2D extends BaseScene < PIXI . Application , never , never , never , PIXI . Container , PIXI . DisplayObject , PIXI . Sprite > { defaultSceneViewType = Scene2DSymbol ; sceneType = SceneType . Scene2D ; private offsetCenter : Vec2 = { x : 0 , y : 0 } ; private brt ? : PIXI . BaseRenderTexture ; private rt ? : PIXI . RenderTexture ; private originalResizeFramebufferFunction : Function ; constructor ( props ) { super ( props ) ; this . view . sortableChildren = true ; } render ( ) { if ( ! Scene2dContext ) { return null ; } return ( < Scene2dContext . Provider value = { this . sceneContext } > { this . props . children } < /Scene2dContext.Provider>); } createView ( ) { return new PIXI . Container ( ) ; } getViewInfo ( ) { return { position : { x : this . view . position . x , y : this . view . position . y } , scale : { x : this . view . scale . x , y : this . view . scale . y } , visible : this . view . visible , } ; } setViewPosition ( position ) { if ( position . x !== void 0 ) { this . view . position . x = position . x ; } if ( position . y !== void 0 ) { this . view . position . y = position . y ; } } setViewScale ( scale ) { if ( scale . x !== void 0 ) { this . view . scale . x = scale . x ; } if ( scale . y !== void 0 ) { this . view . scale . y = scale . y ; } } setViewVisible ( visible ) { this . view . visible = visible ; } setViewportPosition ( position ) { if ( ! this . viewport ) { return ; } if ( position . x !== void 0 ) { this . viewport . position . x = position . x ; } if ( position . y !== void 0 ) { this . viewport . position . y = position . y ; } } setViewportScale ( scale ) { if ( ! this . viewport ) { return ; } if ( scale . x !== void 0 ) { this . viewport . scale . x = scale . x ; } if ( scale . y !== void 0 ) { this . viewport . scale . y = scale . y ; } } setViewportVisible ( visible ) { if ( ! this . viewport ) { return ; } this . viewport . visible = visible ; } addRootViewContainer ( app ) { const { viewport } = this . props ; if ( viewport ) { this . createViewport ( ) ; const vp = this . getViewport ( ) ; if ( vp ) { vp . position . x = viewport . x ; vp . position . y = viewport . y ; vp . visible = viewport . visible ; app . stage . addChild ( vp ) ; } app . ticker . add ( ( ) => { if ( this . viewport ?. visible ) { app . renderer . render ( this . view , this . rt ) ; app . renderer . framebuffer . blit ( ) ; } } ) ; } else { app . stage . addChild ( this . view ) ; } } createViewport ( ) { const { viewport } = this . props ; if ( ! viewport ) { return ; } this . brt = new PIXI . BaseRenderTexture ( { width : viewport . width , height : viewport . height , resolution : this . resolution , } ) ; this . rt = new PIXI . RenderTexture ( this . brt ) ; this . rt . framebuffer . multisample = PIXI . MSAA_QUALITY . HIGH ; if ( viewport ) { this . viewport = new PIXI . Sprite ( this . rt ) ; } } getViewport ( ) { return this . viewport ; } getViewportInfo ( ) { if ( ! this . viewport ) { return ; } return { position : { x : this . viewport . position . x , y : this . viewport . position . y } , scale : { x : this . viewport . scale . x , y : this . viewport . scale . y } , visible : this . viewport . visible , width : this . viewport . width , height : this . viewport . height , } ; } createApp ( ) { const { backgroundColor = BaseScene . BACKGROUND_COLOR , transparent = BaseScene . TRANSPARENT , width = BaseScene . DEFAULT_WIDTH , height = BaseScene . DEFAULT_HEIGHT , resizeTo , allowUseData = false , resizeFramebuffer } = this . props ; const resizeContainer = typeof resizeTo === 'string' ? document . getElementById ( resizeTo ) : resizeTo ; const app = new PIXI . Application ( { width , height , backgroundColor , transparent , antialias : true , autoDensity : true , resolution : this . resolution , resizeTo : resizeContainer || window , preserveDrawingBuffer : allowUseData , } ) ; this . originalResizeFramebufferFunction = ( app . renderer . framebuffer as any ) . resizeFramebuffer ; return app ; } updateCameraTarget ( ) { } updateCameraPosition ( ) { } /**
     * 修复 PIXI bug，改写 resizeFramebuffer，解决 pixi frame buffer 只能由大变小但不能由小变大 resize 的问题
     * 因为修复此 bug 会导致性能问题，所以只在必要的时候使用，通过参数控制改写的内容
     */ private fixResizeFramebufferBug ( app , resizeFramebuffer = false ) { const _this = this ; if ( resizeFramebuffer ) { ( app . renderer . framebuffer as any ) . resizeFramebuffer = function ( framebuffer ) { _this . originalResizeFramebufferFunction . call ( this , framebuffer ) ; this . updateFramebuffer ( framebuffer ) ; } ; } else { ( app . renderer . framebuffer as any ) . resizeFramebuffer = function ( framebuffer ) { _this . originalResizeFramebufferFunction . call ( this , framebuffer ) ; } ; } } param PixiWorld destroyRendererInteraction ( app ) { if ( app . renderer . plugins && app . renderer . plugins . interaction && app . renderer . plugins . interaction . destroy ) { app . renderer . plugins . interaction . destroy ( ) ; } } addChildView ( view ) { this . view . addChild ( view ) ; } getCanvasView ( app ) { return app . view ; } getHitTargetOriginal ( ) { return ( point , container , configMap , interactiveType ) => { const originalTarget = interactiveMgr . hitTest ( new PIXI . Point ( point . x , point . y ) , container ) ; let hitTarget ; for ( let target = originalTarget ; target && target !== container ; target = target . parent ) { const config = configMap . get ( target ) ; if ( config && config [ interactiveType ] ) { hitTarget = target ; break ; } } return { originalTarget , target : hitTarget } ; } ; } updateCursor = ( app , cursor ) => { this . getCanvasView ( app ) . style . cursor = cursor ; } ; createCoordinateController ( app ) { return new CoordinateControllerPixi ( this . getCanvasView ( app ) , this ) ; } resizeStage = ( app ) => { app . resize ( ) ; } ; initBackGroundImage ( app ) { const { width , height , props : { backgroundImage } } = this ; if ( backgroundImage ) { const image = PIXI . Sprite . from ( backgroundImage ) ; image . width = width ; image . height = height ; app . stage . addChild ( image ) ; } } initSkyBox ( ) { } updateResolution ( app ) { const { viewport } = this . props ; if ( this . brt && viewport ) { this . brt . setResolution ( this . resolution ) ; } else { app . renderer . resolution = this . resolution ; } } resizeViewport ( app ) { const { viewport , resizeFramebuffer } = this . props ; if ( this . brt && viewport ) { this . brt . resize ( viewport . width , viewport . height ) ; } } destroyApp ( app ) { app . destroy ( true , { children : false , texture : true , baseTexture : true } ) ; } removeAppChildrenView ( app ) { app . stage . removeChildren ( ) ; } /** 获取截图 */ getScreenShot ( ) { if ( this . view . scale . y > 0 ) { this . view . position . set ( 0 , 0 ) ; this . view . scale . set ( 1 , 1 ) ; } else { this . view . position . set ( 0 , this . view . getLocalBounds ( ) . height ) ; this . view . scale . set ( 1 , - 1 ) ; } const app = this . getCurrentApp ( ) ; if ( ! app ) { return '' ; } return app . renderer . plugins . extract . base64 ( this . view , 'image/jpeg' ) ; } canvasScaleImpl ( event ) { const { coordinateType } = this . props ; const ratio = event . deltaY > 0 ? BaseScene . SCALE_SMALLER : BaseScene . SCALE_BIGGER ; const currentScale = this . getViewInfo ( ) . scale . x ; if ( coordinateType === 'front' || coordinateType === 'left' ) { this . setViewScale ( { x : currentScale * ratio , y : - currentScale * ratio } ) ; } else { this . setViewScale ( { x : currentScale * ratio , y : currentScale * ratio } ) ; } let { offsetX , offsetY } = event ; const vpi = this . getViewportInfo ( ) ; if ( vpi ) { offsetX -= vpi . position . x ; offsetY -= vpi . position . y ; } const { x , y } = this . getViewInfo ( ) . position ; this . setViewPosition ( { x : offsetX + ( x - offsetX ) * ratio , y : offsetY + ( y - offsetY ) * ratio } ) ; } canvasDragImpl ( event , type ) { if ( type === 'start' ) { const { x : offsetX , y : offsetY } = event . canvasPosition ; const { x , y } = this . getViewInfo ( ) . position ; this . offsetCenter = { x : x - offsetX , y : y - offsetY , } ; } else if ( type === 'move' ) { const { x , y } = event . canvasPosition ; this . setViewPosition ( { x : this . offsetCenter . x + x , y : this . offsetCenter . y + y } ) ; } } }