import { mat4 , ReadonlyMat4 } from 'gl-matrix' ; import * as GX from './gx_enum' ; import * as GX_Material from './gx_material' ; import * as GX_Texture from './gx_texture' ; import * as Viewer from '../viewer' ; import { assert , nArray , assertExists , setBitFlagEnabled } from '../util' ; import { LoadedVertexData , LoadedVertexDraw , LoadedVertexLayout , VertexAttributeInput } from './gx_displaylist' ; import ArrayBufferSlice from '../ArrayBufferSlice' ; import { TextureMapping , TextureHolder , LoadedTexture } from '../TextureHolder' ; import { GfxBufferCoalescerCombo , makeStaticDataBuffer } from '../gfx/helpers/BufferHelpers' ; import { fillColor , fillMatrix4x3 , fillVec4 , fillMatrix4x4 , fillVec3v , fillMatrix4x2 } from '../gfx/helpers/UniformBufferHelpers' ; import { GfxFormat , GfxDevice , GfxWrapMode , GfxTexFilterMode , GfxMipFilterMode , GfxBindingLayoutDescriptor , GfxVertexBufferDescriptor , GfxBufferUsage , GfxVertexAttributeDescriptor , GfxBuffer , GfxInputLayout , GfxInputState , GfxMegaStateDescriptor , GfxProgram , GfxVertexBufferFrequency , GfxRenderPass , GfxIndexBufferDescriptor , GfxInputLayoutBufferDescriptor , makeTextureDescriptor2D , GfxChannelWriteMask , GfxCullMode , GfxBlendFactor , GfxCompareMode , GfxFrontFaceMode , GfxBlendMode } from '../gfx/platform/GfxPlatform' ; import { makeBackbufferDescSimple , pushAntialiasingPostProcessPass , standardFullClearRenderPassDescriptor } from '../gfx/helpers/RenderGraphHelpers' ; import { GfxRenderInst , GfxRenderInstManager , setSortKeyProgramKey } from '../gfx/render/GfxRenderInstManager' ; import { GfxRenderCache } from '../gfx/render/GfxRenderCache' ; import { GfxRenderHelper } from '../gfx/render/GfxRenderHelper' ; import { Color , TransparentBlack , colorNewCopy , colorFromRGBA } from '../Color' ; import { AttachmentStateSimple , setAttachmentStateSimple } from '../gfx/helpers/GfxMegaStateDescriptorHelpers' ; import { reverseDepthForCompareMode } from '../gfx/helpers/ReversedDepthHelpers' ; import { GfxrAttachmentSlot } from '../gfx/render/GfxRenderGraph' ; import { convertToCanvasData } from '../gfx/helpers/TextureConversionHelpers' ; export enum ColorKind { MAT0 , MAT1 , AMB0 , AMB1 , K0 , K1 , K2 , K3 , CPREV , C0 , C1 , C2 , COUNT } export class SceneParams { public u_Projection : mat4 = mat4 . create ( ) ; public u_SceneTextureLODBias : number = 0 ; } export class MaterialParams { public m_TextureMapping : TextureMapping [ ] = nArray ( 8 , ( ) => new TextureMapping ( ) ) ; public u_Color : Color [ ] = nArray ( ColorKind . COUNT , ( ) => colorNewCopy ( TransparentBlack ) ) ; public u_TexMtx : mat4 [ ] = nArray ( 10 , ( ) => mat4 . create ( ) ) ; public u_PostTexMtx : mat4 [ ] = nArray ( 20 , ( ) => mat4 . create ( ) ) ; public u_IndTexMtx : mat4 [ ] = nArray ( 3 , ( ) => mat4 . create ( ) ) ; public u_Lights : GX_Material . Light [ ] = nArray ( 8 , ( ) => new GX_Material . Light ( ) ) ; public u_FogBlock = new GX_Material . FogBlock ( ) ; public u_DynamicAlphaRefA : number = 0 ; public u_DynamicAlphaRefB : number = 0 ; constructor ( ) { colorFromRGBA ( this . u_Color [ ColorKind . MAT0 ] , 1.0 , 1.0 , 1.0 , 1.0 ) ; colorFromRGBA ( this . u_Color [ ColorKind . MAT1 ] , 1.0 , 1.0 , 1.0 , 1.0 ) ; } public clear ( ) { for ( let i = 0 ; i < 8 ; i ++ ) this . m_TextureMapping [ i ] . reset ( ) ; } } export class PacketParams { public u_PosMtx : mat4 [ ] = nArray ( 10 , ( ) => mat4 . create ( ) ) ; public clear ( ) { for ( let i = 0 ; i < 10 ; i ++ ) mat4 . identity ( this . u_PosMtx [ i ] ) ; } } export const ub_SceneParamsBufferSize = 4 * 4 + 4 ; export function fillSceneParamsData ( d , bOffs , sceneParams ) { let offs = bOffs ; offs += fillMatrix4x4 ( d , offs , sceneParams . u_Projection ) ; offs += fillVec4 ( d , offs , sceneParams . u_SceneTextureLODBias ) ; assert ( offs === bOffs + ub_SceneParamsBufferSize ) ; assert ( d . length >= offs ) ; } export function fillLightData ( d , offs , light ) { offs += fillColor ( d , offs , light . Color ) ; offs += fillVec3v ( d , offs , light . Position ) ; offs += fillVec3v ( d , offs , light . Direction ) ; offs += fillVec3v ( d , offs , light . DistAtten ) ; offs += fillVec3v ( d , offs , light . CosAtten ) ; return 4 * 5 ; } export function fillFogBlock ( d , offs , fog ) { offs += fillVec4 ( d , offs , fog . A , fog . B , fog . C , fog . AdjCenter ) ; offs += fillVec4 ( d , offs , fog . AdjTable [ 0 ] , fog . AdjTable [ 1 ] , fog . AdjTable [ 2 ] , fog . AdjTable [ 3 ] ) ; offs += fillVec4 ( d , offs , fog . AdjTable [ 4 ] , fog . AdjTable [ 5 ] , fog . AdjTable [ 6 ] , fog . AdjTable [ 7 ] ) ; offs += fillVec4 ( d , offs , fog . AdjTable [ 8 ] , fog . AdjTable [ 9 ] ) ; offs += fillColor ( d , offs , fog . Color ) ; return 4 * 5 ; } export function fillTextureSize ( d , offs , m ) { d [ offs ++ ] = m . width ; d [ offs ++ ] = m . height * ( m . flipY ? - 1 : 1 ) ; return 2 ; } export function fillTextureBias ( d , offs , m ) { d [ offs ++ ] = m . lodBias ; return 1 ; } function fillMaterialParamsDataWithOptimizations ( material , d , bOffs , materialParams ) { let offs = bOffs ; for ( let i = 0 ; i < 12 ; i ++ ) offs += fillColor ( d , offs , materialParams . u_Color [ i ] ) ; for ( let i = 0 ; i < 10 ; i ++ ) offs += fillMatrix4x3 ( d , offs , materialParams . u_TexMtx [ i ] ) ; for ( let i = 0 ; i < 8 ; i ++ ) offs += fillTextureSize ( d , offs , materialParams . m_TextureMapping [ i ] ) ; for ( let i = 0 ; i < 8 ; i ++ ) offs += fillTextureBias ( d , offs , materialParams . m_TextureMapping [ i ] ) ; for ( let i = 0 ; i < 3 ; i ++ ) offs += fillMatrix4x2 ( d , offs , materialParams . u_IndTexMtx [ i ] ) ; if ( GX_Material . materialHasPostTexMtxBlock ( material ) ) for ( let i = 0 ; i < 20 ; i ++ ) offs += fillMatrix4x3 ( d , offs , materialParams . u_PostTexMtx [ i ] ) ; if ( GX_Material . materialHasLightsBlock ( material ) ) for ( let i = 0 ; i < 8 ; i ++ ) offs += fillLightData ( d , offs , materialParams . u_Lights [ i ] ) ; if ( GX_Material . materialHasFogBlock ( material ) ) offs += fillFogBlock ( d , offs , materialParams . u_FogBlock ) ; if ( GX_Material . materialHasDynamicAlphaTest ( material ) ) offs += fillVec4 ( d , offs , materialParams . u_DynamicAlphaRefA , materialParams . u_DynamicAlphaRefB ) ; assert ( d . length >= offs ) ; } function fillDrawParamsDataWithOptimizations ( material , d , bOffs , packetParams ) { let offs = bOffs ; if ( GX_Material . materialUsePnMtxIdx ( material ) ) for ( let i = 0 ; i < 10 ; i ++ ) offs += fillMatrix4x3 ( d , offs , packetParams . u_PosMtx [ i ] ) ; else offs += fillMatrix4x3 ( d , offs , packetParams . u_PosMtx [ 0 ] ) ; assert ( d . length >= offs ) ; } export function fillSceneParams ( sceneParams , projectionMatrix , viewportWidth , viewportHeight , customLODBias = null ) { mat4 . copy ( sceneParams . u_Projection , projectionMatrix ) ; if ( customLODBias !== null ) { sceneParams . u_SceneTextureLODBias = customLODBias ; } else { const textureLODBias = Math . log2 ( Math . min ( viewportWidth / GX_Material . EFB_WIDTH , viewportHeight / GX_Material . EFB_HEIGHT ) ) ; sceneParams . u_SceneTextureLODBias = textureLODBias ; } } export function loadedDataCoalescerComboGfx ( device , loadedVertexDatas ) { return new GfxBufferCoalescerCombo ( device , loadedVertexDatas . map ( ( data ) => data . vertexBuffers . map ( ( buffer ) => new ArrayBufferSlice ( buffer ) ) ) , loadedVertexDatas . map ( ( data ) => new ArrayBufferSlice ( data . indexData ) ) ) ; } export class GXViewerTexture implements Viewer . Texture { public surfaces : HTMLCanvasElement [ ] = [ ] ; constructor ( public mipChain , public extraInfo = null , public name = mipChain . name ) { } public activate ( ) { assert ( this . surfaces . length === 0 ) ; const promises = [ ] ; for ( let i = 0 ; i < this . mipChain . mipLevels . length ; i ++ ) { const mipLevel = this . mipChain . mipLevels [ i ] ; const canvas = document . createElement ( 'canvas' ) ; canvas . width = mipLevel . width ; canvas . height = mipLevel . height ; canvas . title = mipLevel . name ; this . surfaces . push ( canvas ) ; promises . push ( GX_Texture . decodeTexture ( mipLevel ) . then ( ( rgbaTexture ) => { convertToCanvasData ( canvas , ArrayBufferSlice . fromView ( rgbaTexture . pixels ) ) ; } ) ) ; } return Promise . all ( promises ) as any as Promise < void > ; } } export function loadTextureFromMipChain ( device , mipChain ) { const firstMipLevel = mipChain . mipLevels [ 0 ] ; const gfxTexture = device . createTexture ( makeTextureDescriptor2D ( GfxFormat . U8_RGBA_NORM , firstMipLevel . width , firstMipLevel . height , mipChain . mipLevels . length ) ) ; device . setResourceName ( gfxTexture , mipChain . name ) ; const promises = [ ] ; for ( let i = 0 ; i < mipChain . mipLevels . length ; i ++ ) { const level = i ; const mipLevel = mipChain . mipLevels [ i ] ; promises . push ( GX_Texture . decodeTexture ( mipLevel ) . then ( ( rgbaTexture ) => { device . uploadTextureData ( gfxTexture , level , [ rgbaTexture . pixels ] ) ; } ) ) ; } const viewerExtraInfo = new Map < string , string > ( ) ; viewerExtraInfo . set ( "Format" , GX_Texture . getFormatName ( firstMipLevel . format , firstMipLevel . paletteFormat ) ) ; const viewerTexture = new GXViewerTexture ( mipChain , viewerExtraInfo ) ; return { gfxTexture , viewerTexture } ; } export function translateWrapModeGfx ( wrapMode ) { switch ( wrapMode ) { case GX . WrapMode . CLAMP : return GfxWrapMode . Clamp ; case GX . WrapMode . MIRROR : return GfxWrapMode . Mirror ; case GX . WrapMode . REPEAT : return GfxWrapMode . Repeat ; } } export function translateTexFilterGfx ( texFilter ) { switch ( texFilter ) { case GX . TexFilter . LINEAR : return [ GfxTexFilterMode . Bilinear , GfxMipFilterMode . NoMip ] ; case GX . TexFilter . NEAR : return [ GfxTexFilterMode . Point , GfxMipFilterMode . NoMip ] ; case GX . TexFilter . LIN_MIP_LIN : return [ GfxTexFilterMode . Bilinear , GfxMipFilterMode . Linear ] ; case GX . TexFilter . NEAR_MIP_LIN : return [ GfxTexFilterMode . Point , GfxMipFilterMode . Linear ] ; case GX . TexFilter . LIN_MIP_NEAR : return [ GfxTexFilterMode . Bilinear , GfxMipFilterMode . Nearest ] ; case GX . TexFilter . NEAR_MIP_NEAR : return [ GfxTexFilterMode . Point , GfxMipFilterMode . Nearest ] ; } } export class GXTextureHolder < TextureType extends GX_Texture . TextureInputGX = GX_Texture . TextureInputGX > extends TextureHolder < TextureType > { protected loadTexture ( device , texture ) { if ( texture . data === null ) return null ; const mipChain = GX_Texture . calcMipChain ( texture , texture . mipCount ) ; return loadTextureFromMipChain ( device , mipChain ) ; } } export function fillIndTexMtx ( dst , src ) { const a = src [ 0 ] , c = src [ 1 ] , tx = src [ 2 ] , scale = src [ 3 ] ; const b = src [ 4 ] , d = src [ 5 ] , ty = src [ 6 ] ; mat4 . set ( dst , a , b , 0 , 0 , c , d , 0 , 0 , tx , ty , 0 , 0 , scale , 0 , 0 , 0 ) ; } function autoOptimizeMaterialHasPostTexMtxBlock ( material ) { for ( let i = 0 ; i < material . texGens . length ; i ++ ) if ( material . texGens [ i ] . postMatrix !== GX . PostTexGenMatrix . PTIDENTITY ) return true ; return false ; } function channelControlUsesLights ( chan ) { return chan . lightingEnabled && chan . litMask !== 0 ; } function autoOptimizeMaterialHasLightsBlock ( material ) { if ( material . lightChannels [ 0 ] !== undefined ) { if ( channelControlUsesLights ( material . lightChannels [ 0 ] . colorChannel ) ) return true ; if ( channelControlUsesLights ( material . lightChannels [ 0 ] . alphaChannel ) ) return true ; } if ( material . lightChannels [ 1 ] !== undefined ) { if ( channelControlUsesLights ( material . lightChannels [ 1 ] . colorChannel ) ) return true ; if ( channelControlUsesLights ( material . lightChannels [ 1 ] . alphaChannel ) ) return true ; } return false ; } function autoOptimizeMaterialHasFogBlock ( material ) { return material . ropInfo . fogType !== GX . FogType . NONE ; } export function autoOptimizeMaterial ( material ) { if ( material . hasPostTexMtxBlock === undefined ) material . hasPostTexMtxBlock = autoOptimizeMaterialHasPostTexMtxBlock ( material ) ; if ( material . hasLightsBlock === undefined ) material . hasLightsBlock = autoOptimizeMaterialHasLightsBlock ( material ) ; if ( material . hasFogBlock === undefined ) material . hasFogBlock = autoOptimizeMaterialHasFogBlock ( material ) ; } export function translateCullMode ( cullMode ) { switch ( cullMode ) { case GX . CullMode . ALL : return GfxCullMode . FrontAndBack ; case GX . CullMode . FRONT : return GfxCullMode . Front ; case GX . CullMode . BACK : return GfxCullMode . Back ; case GX . CullMode . NONE : return GfxCullMode . None ; } } function translateBlendFactorCommon ( blendFactor ) { switch ( blendFactor ) { case GX . BlendFactor . ZERO : return GfxBlendFactor . Zero ; case GX . BlendFactor . ONE : return GfxBlendFactor . One ; case GX . BlendFactor . SRCALPHA : return GfxBlendFactor . SrcAlpha ; case GX . BlendFactor . INVSRCALPHA : return GfxBlendFactor . OneMinusSrcAlpha ; case GX . BlendFactor . DSTALPHA : return GfxBlendFactor . DstAlpha ; case GX . BlendFactor . INVDSTALPHA : return GfxBlendFactor . OneMinusDstAlpha ; default : throw new Error ( "whoops" ) ; } } function translateBlendSrcFactor ( blendFactor ) { switch ( blendFactor ) { case GX . BlendFactor . SRCCLR : return GfxBlendFactor . Dst ; case GX . BlendFactor . INVSRCCLR : return GfxBlendFactor . OneMinusDst ; default : return translateBlendFactorCommon ( blendFactor ) ; } } function translateBlendDstFactor ( blendFactor ) { switch ( blendFactor ) { case GX . BlendFactor . SRCCLR : return GfxBlendFactor . Src ; case GX . BlendFactor . INVSRCCLR : return GfxBlendFactor . OneMinusSrc ; default : return translateBlendFactorCommon ( blendFactor ) ; } } function translateCompareType ( compareType ) { switch ( compareType ) { case GX . CompareType . NEVER : return GfxCompareMode . Never ; case GX . CompareType . LESS : return GfxCompareMode . Less ; case GX . CompareType . EQUAL : return GfxCompareMode . Equal ; case GX . CompareType . LEQUAL : return GfxCompareMode . LessEqual ; case GX . CompareType . GREATER : return GfxCompareMode . Greater ; case GX . CompareType . NEQUAL : return GfxCompareMode . NotEqual ; case GX . CompareType . GEQUAL : return GfxCompareMode . GreaterEqual ; case GX . CompareType . ALWAYS : return GfxCompareMode . Always ; } } function translateGfxMegaState ( material ) { const megaState = { } ; megaState . cullMode = translateCullMode ( material . cullMode ) ; megaState . depthWrite = material . ropInfo . depthWrite ; megaState . depthCompare = material . ropInfo . depthTest ? reverseDepthForCompareMode ( translateCompareType ( material . ropInfo . depthFunc ) ) : GfxCompareMode . Always ; megaState . frontFace = GfxFrontFaceMode . CW ; const attachmentStateSimple = { } ; if ( material . ropInfo . blendMode === GX . BlendMode . NONE ) { attachmentStateSimple . blendMode = GfxBlendMode . Add ; attachmentStateSimple . blendSrcFactor = GfxBlendFactor . One ; attachmentStateSimple . blendDstFactor = GfxBlendFactor . Zero ; } else if ( material . ropInfo . blendMode === GX . BlendMode . BLEND ) { attachmentStateSimple . blendMode = GfxBlendMode . Add ; attachmentStateSimple . blendSrcFactor = translateBlendSrcFactor ( material . ropInfo . blendSrcFactor ) ; attachmentStateSimple . blendDstFactor = translateBlendDstFactor ( material . ropInfo . blendDstFactor ) ; } else if ( material . ropInfo . blendMode === GX . BlendMode . SUBTRACT ) { attachmentStateSimple . blendMode = GfxBlendMode . ReverseSubtract ; attachmentStateSimple . blendSrcFactor = GfxBlendFactor . One ; attachmentStateSimple . blendDstFactor = GfxBlendFactor . One ; } else if ( material . ropInfo . blendMode === GX . BlendMode . LOGIC ) { attachmentStateSimple . blendMode = GfxBlendMode . Add ; attachmentStateSimple . blendSrcFactor = GfxBlendFactor . One ; attachmentStateSimple . blendDstFactor = GfxBlendFactor . Zero ; console . warn ( `Unimplemented LOGIC blend mode` ) ; } attachmentStateSimple . channelWriteMask = GfxChannelWriteMask . None ; if ( material . ropInfo . colorUpdate ) attachmentStateSimple . channelWriteMask |= GfxChannelWriteMask . RGB ; if ( material . ropInfo . alphaUpdate ) attachmentStateSimple . channelWriteMask |= GfxChannelWriteMask . Alpha ; setAttachmentStateSimple ( megaState , attachmentStateSimple ) ; return megaState ; } export class GXMaterialHelperGfx { public programKey : number ; public megaStateFlags : Partial < GfxMegaStateDescriptor > ; public materialParamsBufferSize : number ; public drawParamsBufferSize : number ; private materialHacks : GX_Material . GXMaterialHacks = { } ; private program ! : GX_Material . GX_Program ; private gfxProgram : GfxProgram | null = null ; constructor ( public material , materialHacks ? ) { if ( materialHacks ) Object . assign ( this . materialHacks , materialHacks ) ; this . materialInvalidated ( ) ; } public autoOptimizeMaterial ( ) { autoOptimizeMaterial ( this . material ) ; this . materialInvalidated ( ) ; } public materialInvalidated ( ) { this . materialParamsBufferSize = GX_Material . getMaterialParamsBlockSize ( this . material ) ; this . drawParamsBufferSize = GX_Material . getDrawParamsBlockSize ( this . material ) ; this . createProgram ( ) ; this . megaStateFlags = translateGfxMegaState ( this . material ) ; } public cacheProgram ( cache ) { if ( this . gfxProgram === null ) { this . gfxProgram = cache . createProgram ( this . program ) ; this . programKey = this . gfxProgram . ResourceUniqueId ; } } public createProgram ( ) { this . program = new GX_Material . GX_Program ( this . material , this . materialHacks ) ; this . gfxProgram = null ; } public setMaterialHacks ( materialHacks ) { Object . assign ( this . materialHacks , materialHacks ) ; this . createProgram ( ) ; } public fillMaterialParamsData ( renderInstManager , offs , materialParams ) { const uniformBuffer = renderInstManager . getTemplateRenderInst ( ) . getUniformBuffer ( ) ; const d = uniformBuffer . mapBufferF32 ( ) ; fillMaterialParamsDataWithOptimizations ( this . material , d , offs , materialParams ) ; } public allocateMaterialParamsBlock ( renderInstManager ) { const uniformBuffer = renderInstManager . getTemplateRenderInst ( ) . getUniformBuffer ( ) ; return uniformBuffer . allocateChunk ( this . materialParamsBufferSize ) ; } public allocateMaterialParamsDataOnInst ( renderInst , materialParams ) { const offs = renderInst . allocateUniformBuffer ( GX_Material . GX_Program . ub_MaterialParams , this . materialParamsBufferSize ) ; const d = renderInst . mapUniformBufferF32 ( GX_Material . GX_Program . ub_MaterialParams ) ; fillMaterialParamsDataWithOptimizations ( this . material , d , offs , materialParams ) ; } public allocatePacketParamsDataOnInst ( renderInst , drawParams ) { const offs = renderInst . allocateUniformBuffer ( GX_Material . GX_Program . ub_DrawParams , this . drawParamsBufferSize ) ; const d = renderInst . mapUniformBufferF32 ( GX_Material . GX_Program . ub_DrawParams ) ; fillDrawParamsDataWithOptimizations ( this . material , d , offs , drawParams ) ; } public setOnRenderInst ( device , cache , renderInst ) { this . cacheProgram ( cache ) ; renderInst . setMegaStateFlags ( this . megaStateFlags ) ; renderInst . setGfxProgram ( this . gfxProgram ! ) ; setSortKeyProgramKey ( renderInst . sortKey , this . programKey ) ; } } export function setChanWriteEnabled ( materialHelper , bits , en ) { let channelWriteMask = materialHelper . megaStateFlags . attachmentsState ! [ 0 ] . channelWriteMask ; channelWriteMask = setBitFlagEnabled ( channelWriteMask , bits , en ) ; setAttachmentStateSimple ( materialHelper . megaStateFlags , { channelWriteMask } ) ; } export function createInputLayout ( cache , loadedVertexLayout ) { const vertexAttributeDescriptors = [ ] ; for ( let attrInput = 0 ; attrInput < VertexAttributeInput . COUNT ; attrInput ++ ) { const attribLocation = GX_Material . getVertexInputLocation ( attrInput ) ; const attrib = loadedVertexLayout . singleVertexInputLayouts . find ( ( attrib ) => attrib . attrInput === attrInput ) ; if ( attrib !== undefined ) { const bufferByteOffset = attrib . bufferOffset ; const bufferIndex = attrib . bufferIndex ; vertexAttributeDescriptors . push ( { location : attribLocation , format : attrib . format , bufferIndex , bufferByteOffset } ) ; } } const vertexBufferDescriptors = [ ] ; for ( let i = 0 ; i < loadedVertexLayout . vertexBufferStrides . length ; i ++ ) { vertexBufferDescriptors . push ( { byteStride : loadedVertexLayout . vertexBufferStrides [ i ] , frequency : GfxVertexBufferFrequency . PerVertex , } ) ; } const indexBufferFormat = loadedVertexLayout . indexFormat ; return cache . createInputLayout ( { vertexAttributeDescriptors , vertexBufferDescriptors , indexBufferFormat , } ) ; } export class GXShapeHelperGfx { public inputState : GfxInputState ; public inputLayout : GfxInputLayout ; private zeroBuffer : GfxBuffer | null = null ; constructor ( device , cache , public vertexBuffers , public indexBuffer , public loadedVertexLayout , public loadedVertexData = null ) { let usesZeroBuffer = false ; for ( let attrInput = 0 ; attrInput < VertexAttributeInput . COUNT ; attrInput ++ ) { const attrib = loadedVertexLayout . singleVertexInputLayouts . find ( ( attrib ) => attrib . attrInput === attrInput ) ; if ( attrib === undefined ) { usesZeroBuffer = true ; break ; } } const buffers = vertexBuffers . slice ( ) ; if ( usesZeroBuffer ) { this . zeroBuffer = makeStaticDataBuffer ( device , GfxBufferUsage . Vertex , new Uint8Array ( 16 ) . buffer ) ; buffers . push ( { buffer : this . zeroBuffer , byteOffset : 0 , } ) ; } this . inputLayout = createInputLayout ( cache , loadedVertexLayout ) ; this . inputState = device . createInputState ( this . inputLayout , buffers , indexBuffer ) ; } public setOnRenderInst ( renderInst , draw = null ) { renderInst . setInputLayoutAndState ( this . inputLayout , this . inputState ) ; if ( draw === null ) { const loadedVertexData = assertExists ( this . loadedVertexData ) ; assert ( loadedVertexData . draws . length === 1 ) ; draw = loadedVertexData . draws [ 0 ] ; } renderInst . drawIndexes ( draw . indexCount , draw . indexOffset ) ; } public destroy ( device ) { device . destroyInputState ( this . inputState ) ; if ( this . zeroBuffer !== null ) device . destroyBuffer ( this . zeroBuffer ) ; } } export const gxBindingLayouts = [ { numUniformBuffers : 3 , numSamplers : 8 , } , ] ; const sceneParams = new SceneParams ( ) ; export function fillSceneParamsDataOnTemplate ( renderInst , viewerInput , customLODBias = null , sceneParamsScratch = sceneParams ) { fillSceneParams ( sceneParamsScratch , viewerInput . camera . projectionMatrix , viewerInput . backbufferWidth , viewerInput . backbufferHeight , customLODBias ) ; let offs = renderInst . getUniformBufferOffset ( GX_Material . GX_Program . ub_SceneParams ) ; const d = renderInst . mapUniformBufferF32 ( GX_Material . GX_Program . ub_SceneParams ) ; fillSceneParamsData ( d , offs , sceneParams ) ; } export class GXRenderHelperGfx extends GfxRenderHelper { public pushTemplateRenderInst ( ) { const template = super . pushTemplateRenderInst ( ) ; template . setBindingLayouts ( gxBindingLayouts ) ; template . allocateUniformBuffer ( GX_Material . GX_Program . ub_SceneParams , ub_SceneParamsBufferSize ) ; return template ; } } export abstract class BasicGXRendererHelper implements Viewer . SceneGfx { public renderHelper : GXRenderHelperGfx ; public clearRenderPassDescriptor = standardFullClearRenderPassDescriptor ; constructor ( device ) { this . renderHelper = new GXRenderHelperGfx ( device ) ; } protected abstract prepareToRender ( device , viewerInput ) ; public getCache ( ) { return this . renderHelper . renderInstManager . gfxRenderCache ; } public render ( device , viewerInput ) { const renderInstManager = this . renderHelper . renderInstManager ; const mainColorDesc = makeBackbufferDescSimple ( GfxrAttachmentSlot . Color0 , viewerInput , standardFullClearRenderPassDescriptor ) ; const mainDepthDesc = makeBackbufferDescSimple ( GfxrAttachmentSlot . DepthStencil , viewerInput , standardFullClearRenderPassDescriptor ) ; const builder = this . renderHelper . renderGraph . newGraphBuilder ( ) ; const mainColorTargetID = builder . createRenderTargetID ( mainColorDesc , 'Main Color' ) ; const mainDepthTargetID = builder . createRenderTargetID ( mainDepthDesc , 'Main Depth' ) ; builder . pushPass ( ( pass ) => { pass . setDebugName ( 'Main' ) ; pass . attachRenderTargetID ( GfxrAttachmentSlot . Color0 , mainColorTargetID ) ; pass . attachRenderTargetID ( GfxrAttachmentSlot . DepthStencil , mainDepthTargetID ) ; pass . exec ( ( passRenderer ) => { renderInstManager . drawOnPassRenderer ( passRenderer ) ; } ) ; } ) ; pushAntialiasingPostProcessPass ( builder , this . renderHelper , viewerInput , mainColorTargetID ) ; builder . resolveRenderTargetToExternalTexture ( mainColorTargetID , viewerInput . onscreenTexture ) ; this . prepareToRender ( device , viewerInput ) ; this . renderHelper . renderGraph . execute ( builder ) ; renderInstManager . resetRenderInsts ( ) ; } public destroy ( device ) { this . renderHelper . destroy ( ) ; } }