import { expect } from "chai" ; import { ClipStyle , ColorDef , FeatureAppearance , FeatureAppearanceProvider , Hilite , RenderMode , RgbColor } from "@itwin/core-common" ; import { DecorateContext , Decorator , FeatureOverrideProvider , FeatureSymbology , GraphicBranch , GraphicBranchOptions , GraphicType , IModelApp , IModelConnection , OffScreenViewport , Pixel , RenderSystem , SnapshotConnection , SpatialViewState , Viewport , ViewRect , } from "@itwin/core-frontend" ; import { ClipVector , Point2d , Point3d , Transform } from "@itwin/core-geometry" ; import { TestUtility } from "../TestUtility" ; import { Color , comparePixelData , createOnScreenTestViewport , testOnScreenViewport , TestViewport , testViewports , testViewportsWithDpr , } from "../TestViewport" ; describe ( "Vertex buffer objects" , ( ) => { let imodel ; before ( async ( ) => { const renderSysOpts = { useWebGL2 : false } ; renderSysOpts . disabledExtensions = [ "OES_vertex_array_object" ] ; await TestUtility . startFrontend ( { renderSys : renderSysOpts } ) ; imodel = await SnapshotConnection . openFile ( "mirukuru.ibim" ) ; } ) ; after ( async ( ) => { if ( imodel ) await imodel . close ( ) ; await TestUtility . shutdownFrontend ( ) ; } ) ; it ( "should render correctly" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { vp . view . viewFlags = vp . view . viewFlags . with ( "visibleEdges" , true ) ; await vp . waitForAllTilesToRender ( ) ; expect ( vp . numRequestedTiles ) . to . equal ( 0 ) ; expect ( vp . numSelectedTiles ) . to . equal ( 1 ) ; const colors = vp . readUniqueColors ( ) ; const bgColor = Color . fromRgba ( 0 , 0 , 0 , 0xff ) ; expect ( colors . length ) . least ( 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; const expectWhitish = ( c ) => { expect ( c . r ) . least ( 0x7f ) ; expect ( c . g ) . least ( 0x7f ) ; expect ( c . b ) . least ( 0x7f ) ; expect ( c . a ) . to . equal ( 0xff ) ; } ; for ( const c of colors . array ) { if ( 0 !== c . compare ( bgColor ) ) expectWhitish ( c ) ; } let color = vp . readColor ( rect . left , rect . top ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . right - 1 , rect . top ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . right - 1 , rect . bottom - 1 ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . left , rect . bottom - 1 ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . width / 2 , rect . height / 2 ) ; expectWhitish ( color ) ; const elemId = "0x29" ; const subcatId = "0x18" ; const pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 3 ) ; expect ( pixels . containsFeature ( elemId , subcatId ) ) ; expect ( pixels . containsGeometry ( Pixel . GeometryType . Surface , Pixel . Planarity . Planar ) ) ; expect ( pixels . containsGeometry ( Pixel . GeometryType . Edge , Pixel . Planarity . Planar ) ) ; } ) ; } ) ; } ) ; describe ( "RenderTarget" , ( ) => { let imodel ; before ( async ( ) => { await TestUtility . startFrontend ( ) ; imodel = await SnapshotConnection . openFile ( "mirukuru.ibim" ) ; } ) ; after ( async ( ) => { if ( imodel ) await imodel . close ( ) ; await TestUtility . shutdownFrontend ( ) ; } ) ; it ( "should have expected view definition" , async ( ) => { const viewState = await imodel . views . load ( "0x24" ) ; expect ( viewState ) . instanceof ( SpatialViewState ) ; } ) ; it ( "should render empty view" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewports ( "0x24" , imodel , rect . width , rect . height , async ( vp ) => { vp . changeViewedModels ( [ ] ) ; await vp . drawFrame ( ) ; let colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 1 ) ; expect ( colors . contains ( Color . fromRgba ( 0 , 0 , 0 , 0xff ) ) ) . to . be . true ; vp . view . displayStyle . backgroundColor = ColorDef . green ; vp . invalidateRenderPlan ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 1 ) ; expect ( colors . contains ( Color . fromRgba ( 0 , 0x80 , 0 , 0xff ) ) ) . to . be . true ; const pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 1 ) ; const backgroundPixel = new Pixel . Data ( undefined , 0 , Pixel . GeometryType . None , Pixel . Planarity . None ) ; expect ( comparePixelData ( backgroundPixel , pixels . array [ 0 ] ) ) . to . equal ( 0 ) ; const coords = [ [ - 1 , - 1 , - 2 , - 2 ] , [ rect . width + 1 , rect . height + 1 , rect . width + 2 , rect . height + 2 ] ] ; for ( const coord of coords ) { const readRect = new ViewRect ( coord [ 0 ] , coord [ 1 ] , coord [ 2 ] , coord [ 3 ] ) ; const oob = vp . readUniquePixelData ( readRect ) ; expect ( oob ) . to . not . be . undefined ; expect ( oob . array . length ) . to . equal ( 0 ) ; } } , 1.0 ) ; } ) ; it ( "should render the model" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { await vp . waitForAllTilesToRender ( ) ; expect ( vp . numRequestedTiles ) . to . equal ( 0 ) ; expect ( vp . numSelectedTiles ) . to . equal ( 1 ) ; let colors = vp . readUniqueColors ( ) ; const bgColor = Color . fromRgba ( 0 , 0 , 0 , 0xff ) ; expect ( colors . length ) . least ( 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; const expectWhitish = ( c ) => { expect ( c . r ) . least ( 0x7f ) ; expect ( c . g ) . least ( 0x7f ) ; expect ( c . b ) . least ( 0x7f ) ; expect ( c . a ) . to . equal ( 0xff ) ; } ; for ( const c of colors . array ) { if ( 0 !== c . compare ( bgColor ) ) expectWhitish ( c ) ; } let color = vp . readColor ( rect . left , rect . top ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . right - 1 , rect . top ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . right - 1 , rect . bottom - 1 ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . left , rect . bottom - 1 ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; color = vp . readColor ( rect . width / 2 , rect . height / 2 ) ; expectWhitish ( color ) ; const elemId = "0x29" ; const subcatId = "0x18" ; let pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 3 ) ; expect ( pixels . containsFeature ( elemId , subcatId ) ) ; expect ( pixels . containsGeometry ( Pixel . GeometryType . Surface , Pixel . Planarity . Planar ) ) ; expect ( pixels . containsGeometry ( Pixel . GeometryType . Edge , Pixel . Planarity . Planar ) ) ; vp . viewFlags = vp . viewFlags . with ( "lighting" , false ) ; await vp . drawFrame ( ) ; const white = Color . from ( 0xffffffff ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; expect ( colors . contains ( white ) ) . to . be . true ; vp . viewFlags = vp . viewFlags . withRenderMode ( RenderMode . Wireframe ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; expect ( colors . contains ( white ) ) . to . be . true ; color = vp . readColor ( rect . width / 2 , rect . height / 2 ) ; expect ( color . compare ( bgColor ) ) . to . equal ( 0 ) ; pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 2 ) ; expect ( pixels . containsFeature ( elemId , subcatId ) ) ; expect ( pixels . containsGeometry ( Pixel . GeometryType . Edge , Pixel . Planarity . Planar ) ) ; } ) ; } ) ; it ( "should read image at expected sizes" , async ( ) => { const cssRect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , cssRect , async ( vp ) => { await vp . waitForAllTilesToRender ( ) ; const expectImageDimensions = ( readRect , targetSize , expectedWidth , expectedHeight ) => { const img = vp . readImageBuffer ( { rect : readRect , size : targetSize } ) ! ; expect ( img ) . not . to . be . undefined ; expect ( img . width ) . to . equal ( Math . floor ( expectedWidth ) ) ; expect ( img . height ) . to . equal ( Math . floor ( expectedHeight ) ) ; } ; const devRect = vp . target . viewRect ; expectImageDimensions ( undefined , undefined , devRect . width , devRect . height ) ; expectImageDimensions ( undefined , new Point2d ( devRect . width , devRect . height ) , devRect . width , devRect . height ) ; const cssHalfWidth = cssRect . width / 2 ; const cssQuarterHeight = cssRect . height / 4 ; const devHalfWidth = Math . floor ( devRect . width / 2 ) ; const devQuarterHeight = Math . floor ( devRect . height / 4 ) ; expectImageDimensions ( new ViewRect ( 0 , 0 , cssHalfWidth , cssQuarterHeight ) , undefined , devHalfWidth , devQuarterHeight ) ; expectImageDimensions ( new ViewRect ( cssHalfWidth , cssQuarterHeight , cssRect . right , cssRect . bottom ) , undefined , devRect . width - devHalfWidth , devRect . height - devQuarterHeight ) ; expectImageDimensions ( new ViewRect ( 0 , 0 , cssHalfWidth , cssRect . bottom ) , undefined , devHalfWidth , devRect . height ) ; expectImageDimensions ( undefined , new Point2d ( 256 , 128 ) , 256 , 128 ) ; expectImageDimensions ( undefined , new Point2d ( 50 , 200 ) , 50 , 200 ) ; expectImageDimensions ( cssRect , new Point2d ( 10 , 10 ) , 10 , 10 ) ; expectImageDimensions ( undefined , new Point2d ( devRect . width , devRect . height ) , devRect . width , devRect . height ) ; expectImageDimensions ( new ViewRect ( 0 , 0 , cssHalfWidth , cssQuarterHeight ) , new Point2d ( 512 , 768 ) , 512 , 768 ) ; } ) ; } ) ; it ( "should override symbology" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 200 , 150 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { const elemId = "0x29" ; const subcatId = "0x18" ; vp . viewFlags = vp . viewFlags . copy ( { visibleEdges : false , hiddenEdges : false , lighting : false } ) ; type AddFeatureOverrides = ( overrides : FeatureSymbology . Overrides , viewport : Viewport ) => void ; class RenderTestOverrideProvider implements FeatureOverrideProvider { public ovrFunc ? : AddFeatureOverrides ; public addFeatureOverrides ( overrides , viewport ) { if ( undefined !== this . ovrFunc ) this . ovrFunc ( overrides , viewport ) ; } } const ovrProvider = new RenderTestOverrideProvider ( ) ; vp . addFeatureOverrideProvider ( ovrProvider ) ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . setNeverDrawn ( elemId ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . waitForAllTilesToRender ( ) ; const bgColor = Color . fromRgba ( 0 , 0 , 0 , 0xff ) ; let colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 1 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; let pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 1 ) ; ovrProvider . ovrFunc = ( ovrs ) => ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromJSON ( { nonLocatable : true } ) } ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; pixels = vp . readUniquePixelData ( undefined , true ) ; expect ( pixels . length ) . to . equal ( 1 ) ; expect ( pixels . containsElement ( elemId ) ) . to . be . false ; pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 2 ) ; expect ( pixels . containsElement ( elemId ) ) . to . be . true ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromRgb ( ColorDef . blue ) } ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( Color . fromRgba ( 0 , 0 , 0xff , 0xff ) ) ) . to . be . true ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . setDefaultOverrides ( FeatureAppearance . fromRgb ( ColorDef . red ) ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( Color . fromRgba ( 0xff , 0 , 0 , 0xff ) ) ) . to . be . true ; ovrProvider . ovrFunc = ( ovrs , _ ) => { ovrs . setDefaultOverrides ( FeatureAppearance . fromRgb ( ColorDef . green ) ) ; ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromRgb ( ColorDef . create ( 0x7f0000 ) ) } ) ; } ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( Color . fromRgba ( 0 , 0 , 0x7f , 0xff ) ) ) . to . be . true ; expect ( colors . contains ( Color . fromRgba ( 0xff , 0 , 0 , 0xff ) ) ) . to . be . false ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . override ( { subCategoryId : subcatId , appearance : FeatureAppearance . fromRgb ( ColorDef . red ) } ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . contains ( Color . fromRgba ( 0xff , 0 , 0 , 0xff ) ) ) . to . be . true ; ovrProvider . ovrFunc = ( ovrs , _ ) => { ovrs . override ( { subCategoryId : subcatId , appearance : FeatureAppearance . fromRgb ( ColorDef . blue ) } ) ; ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromRgb ( ColorDef . red ) } ) ; } ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . contains ( Color . fromRgba ( 0xff , 0 , 0 , 0xff ) ) ) . to . be . true ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromTransparency ( 1.0 ) } ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 1 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; pixels = vp . readUniquePixelData ( ) ; expect ( pixels . length ) . to . equal ( 1 ) ; expect ( pixels . containsElement ( elemId ) ) . to . be . false ; vp . view . displayStyle . backgroundColor = ColorDef . red ; vp . invalidateRenderPlan ( ) ; ovrProvider . ovrFunc = ( ovrs , _ ) => ovrs . override ( { elementId : elemId , appearance : FeatureAppearance . fromJSON ( { rgb : new RgbColor ( 0 , 0 , 0xff ) , transparency : 0.5 } ) } ) ; vp . setFeatureOverrideProviderChanged ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; const red = Color . fromRgba ( 0xff , 0 , 0 , 0xff ) ; expect ( colors . contains ( red ) ) . to . be . true ; for ( const c of colors . array ) { if ( 0 !== c . compare ( red ) ) { expect ( c . r ) . least ( 0x70 ) ; expect ( c . r ) . most ( 0x90 ) ; expect ( c . g ) . to . equal ( 0 ) ; expect ( c . b ) . least ( 0x70 ) ; expect ( c . b ) . most ( 0x90 ) ; expect ( c . a ) . to . equal ( 0xff ) ; } } } ) ; } ) ; it ( "should augment symbology" , async ( ) => { await testOnScreenViewport ( "0x24" , imodel , 200 , 150 , async ( vp ) => { vp . viewFlags = vp . viewFlags . copy ( { visibleEdges : false , hiddenEdges : false , lighting : false } ) ; const expectSurfaceColor = async ( color ) => { await vp . waitForAllTilesToRender ( ) ; const colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( Color . fromRgba ( 0 , 0 , 0 , 0xff ) ) ) . to . be . true ; const expected = Color . fromRgba ( color . colors . r , color . colors . g , color . colors . b , 0xff ) ; expect ( colors . contains ( expected ) ) . to . be . true ; } ; await expectSurfaceColor ( ColorDef . white ) ; const overrideColor = ( color ) => ( ) => FeatureAppearance . fromRgb ( color ) ; const appearanceProvider = { getFeatureAppearance : overrideColor ( ColorDef . red ) } ; const createGraphicBranch = IModelApp . renderSystem . createGraphicBranch ; IModelApp . renderSystem . createGraphicBranch = ( branch , transform , options ? ) => { options = options ?? { } ; return createGraphicBranch . call ( IModelApp . renderSystem , branch , transform , { ... options , appearanceProvider } ) ; } ; await expectSurfaceColor ( ColorDef . white ) ; IModelApp . viewManager . invalidateSymbologyOverridesAllViews ( ) ; await expectSurfaceColor ( ColorDef . white ) ; IModelApp . viewManager . invalidateViewportScenes ( ) ; await expectSurfaceColor ( ColorDef . white ) ; IModelApp . viewManager . invalidateViewportScenes ( ) ; IModelApp . viewManager . invalidateSymbologyOverridesAllViews ( ) ; await expectSurfaceColor ( ColorDef . red ) ; interface OvrAug { ovr ? : ColorDef ; aug ? : ColorDef ; } const testNestedBranch = async ( parent , child , expected ) => { const applyOvrs = ( branch , ovraug ? ) => { if ( ovraug ?. ovr ) { branch . symbologyOverrides = new FeatureSymbology . Overrides ( vp ) ; branch . symbologyOverrides . setDefaultOverrides ( FeatureAppearance . fromRgb ( ovraug . ovr ) ) ; } } ; const getBranchOptions = ( opts ? , ovraug ? ) => { if ( ovraug ?. aug ) opts = { ... opts , appearanceProvider : { getFeatureAppearance : overrideColor ( ovraug . aug ) } } ; return opts ; } ; IModelApp . renderSystem . createGraphicBranch = ( branch , transform , options ? ) => { options = options ?? { } ; const childOptions = getBranchOptions ( options , child ) ; applyOvrs ( branch , child ) ; const childBranch = createGraphicBranch . call ( IModelApp . renderSystem , branch , transform , childOptions ) ; const childGraphics = new GraphicBranch ( ) ; childGraphics . add ( childBranch ) ; applyOvrs ( childGraphics , parent ) ; const parentOptions = getBranchOptions ( undefined , parent ) ; return createGraphicBranch . call ( IModelApp . renderSystem , childGraphics , Transform . createIdentity ( ) , parentOptions ) ; } ; vp . invalidateScene ( ) ; vp . setFeatureOverrideProviderChanged ( ) ; await expectSurfaceColor ( expected ) ; } ; interface TestCase { parent ? : OvrAug ; child ? : OvrAug ; color : ColorDef ; } const testCases = [ { color : ColorDef . white } , { child : { ovr : ColorDef . blue } , color : ColorDef . blue } , { child : { aug : ColorDef . green } , color : ColorDef . green } , { child : { ovr : ColorDef . blue , aug : ColorDef . green } , color : ColorDef . green } , { parent : { ovr : ColorDef . blue } , color : ColorDef . blue } , { parent : { aug : ColorDef . green } , color : ColorDef . green } , { parent : { ovr : ColorDef . blue , aug : ColorDef . green } , color : ColorDef . green } , { child : { ovr : ColorDef . blue } , parent : { ovr : ColorDef . red , aug : ColorDef . green } , color : ColorDef . blue } , { child : { aug : ColorDef . red } , parent : { ovr : ColorDef . green , aug : ColorDef . blue } , color : ColorDef . red } , ] ; for ( const testCase of testCases ) await testNestedBranch ( testCase . parent , testCase . child , testCase . color ) ; IModelApp . renderSystem . createGraphicBranch = createGraphicBranch ; } ) ; } ) ; it ( "should show transparency for polylines" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 200 , 150 ) ; await testOnScreenViewport ( "0x24" , imodel , rect . width , rect . height , async ( vp ) => { class TestPolylineDecorator implements Decorator { public decorate ( context ) { expect ( context . viewport === vp ) ; const overlayBuilder = context . createGraphicBuilder ( GraphicType . ViewOverlay ) ; const polylineColor = ColorDef . from ( 0 , 255 , 0 , 128 ) ; overlayBuilder . setSymbology ( polylineColor , polylineColor , 4 ) ; overlayBuilder . addLineString ( [ new Point3d ( 0 , 0 , 0 ) , new Point3d ( rect . width - 1 , rect . height - 1 , 0 ) , ] ) ; context . addDecorationFromBuilder ( overlayBuilder ) ; } } const decorator = new TestPolylineDecorator ( ) ; IModelApp . viewManager . addDecorator ( decorator ) ; await vp . drawFrame ( ) ; IModelApp . viewManager . dropDecorator ( decorator ) ; const testColor = vp . readColor ( 0 , 0 ) ; expect ( testColor . r ) . equals ( 0 ) ; expect ( testColor . g ) . approximately ( 128 , 3 ) ; expect ( testColor . b ) . equals ( 0 ) ; } ) ; } ) ; it ( "should render hilite" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 200 , 150 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { vp . viewFlags = vp . viewFlags . copy ( { visibleEdges : false , hiddenEdges : false , lighting : false } ) ; vp . hilite = new Hilite . Settings ( ColorDef . red , 1.0 , 0.0 , Hilite . Silhouette . Thin ) ; await vp . waitForAllTilesToRender ( ) ; const hilites = imodel . hilited ; const tests = [ { id : "0x29" , otherId : "0x30" , set : hilites . elements } , { id : "0x18" , otherId : "0x19" , set : hilites . subcategories } , { id : "0x1c" , otherId : "0x1d" , set : hilites . models } , ] ; const update = ( vp instanceof OffScreenViewport ) ? ( ( ) => ( vp as any ) . _selectionSetDirty = true ) : ( ( ) => undefined ) ; const white = Color . from ( 0xffffffff ) ; const black = Color . from ( 0xff000000 ) ; const hilite = Color . from ( 0xff0000ff ) ; for ( const test of tests ) { test . set . addId ( test . otherId ) ; update ( ) ; await vp . drawFrame ( ) ; let colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( white ) ) . to . be . true ; expect ( colors . contains ( black ) ) . to . be . true ; test . set . addId ( test . id ) ; update ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( hilite ) ) . to . be . true ; expect ( colors . contains ( black ) ) . to . be . true ; hilites . clear ( ) ; update ( ) ; await vp . drawFrame ( ) ; colors = vp . readUniqueColors ( ) ; expect ( colors . length ) . to . equal ( 2 ) ; expect ( colors . contains ( white ) ) . to . be . true ; expect ( colors . contains ( black ) ) . to . be . true ; } } ) ; } ) ; it ( "should determine visible depth range" , async ( ) => { const fullRect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , fullRect , async ( vp ) => { await vp . waitForAllTilesToRender ( ) ; const fullRange = vp . determineVisibleDepthRange ( fullRect ) ; expect ( fullRange ) . not . to . be . undefined ; expect ( fullRange ! . minimum ) . least ( 0.45 ) ; expect ( fullRange ! . minimum ) . most ( 0.55 ) ; expect ( fullRange ! . minimum ) . to . equal ( fullRange ! . maximum ) ; const myRange = { minimum : 0 , maximum : 1 } ; let range = vp . determineVisibleDepthRange ( fullRect , myRange ) ; expect ( range ) . to . equal ( myRange ) ; expect ( range ! . maximum ) . to . equal ( fullRange ! . maximum ) ; expect ( range ! . minimum ) . to . equal ( fullRange ! . minimum ) ; const centerRect = new ViewRect ( 40 , 40 , 60 , 60 ) ; range = vp . determineVisibleDepthRange ( centerRect ) ; expect ( range ! . maximum ) . to . equal ( fullRange ! . maximum ) ; expect ( range ! . minimum ) . to . equal ( fullRange ! . minimum ) ; const topLeftRect = new ViewRect ( 0 , 0 , 5 , 5 ) ; range = vp . determineVisibleDepthRange ( topLeftRect ) ; expect ( range ) . to . be . undefined ; range = vp . determineVisibleDepthRange ( topLeftRect , myRange ) ; expect ( range ) . to . be . undefined ; expect ( myRange . minimum ) . to . equal ( 1 ) ; expect ( myRange . maximum ) . to . equal ( 0 ) ; } ) ; } ) ; it ( "should use GCS to transform map tiles" , async ( ) => { const extents = imodel . projectExtents . clone ( ) ; const linearRangeSquared = extents . diagonal ( ) . magnitudeSquared ( ) ; if ( linearRangeSquared < 1000 * 1000 ) { extents . scaleAboutCenterInPlace ( 1000 ) ; imodel . projectExtents = extents ; } expect ( imodel . projectExtents . diagonal ( ) . magnitudeSquared ( ) ) . least ( 1000 * 1000 ) ; const fullRect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewports ( "0x24" , imodel , fullRect . width , fullRect . height , async ( vp ) => { vp . viewFlags = vp . viewFlags . with ( "backgroundMap" , true ) ; await vp . waitForAllTilesToRender ( ) ; const mapTreeRef = vp . backgroundMap ! ; const mapTree = mapTreeRef . treeOwner . tileTree ! ; expect ( mapTree ) . not . to . be . undefined ; } ) ; } ) ; it ( "should render to screen if only a single viewport exists" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testOnScreenViewport ( "0x24" , imodel , rect . width , rect . height , async ( vp ) => { expect ( vp . rendersToScreen ) . to . be . true ; } ) ; } ) ; it ( "should render off-screen if multiple viewports exist" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; const vp0 = await createOnScreenTestViewport ( "0x24" , imodel , rect . width , rect . height ) ; expect ( vp0 . rendersToScreen ) . to . be . true ; const vp1 = await createOnScreenTestViewport ( "0x24" , imodel , rect . width , rect . height ) ; expect ( vp0 . rendersToScreen ) . to . be . false ; expect ( vp1 . rendersToScreen ) . to . be . false ; vp0 . dispose ( ) ; vp1 . dispose ( ) ; } ) ; it ( "should clip using a single plane" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { vp . viewFlags = vp . viewFlags . with ( "visibleEdges" , false ) ; const clip = ClipVector . fromJSON ( [ { shape : { points : [ [ - 58.57249751634662 , - 261.9870625343174 , 0 ] , [ 297.4029912650585 , - 261.9870625343174 , 0 ] , [ 297.4029912650585 , 111.24234024435282 , 0 ] , [ - 58.57249751634662 , 111.24234024435282 , 0 ] , [ - 58.57249751634662 , - 261.9870625343174 , 0 ] ] , trans : [ [ 1 , 0 , 0 , 289076.52682419703 ] , [ 0 , 1 , 0 , 3803926.4450675533 ] , [ 0 , 0 , 1 , 0 ] ] } } ] ) ; expect ( clip ) . to . not . be . undefined ; vp . view . setViewClip ( clip ) ; vp . displayStyle . settings . clipStyle = ClipStyle . fromJSON ( { ... vp . displayStyle . settings . clipStyle . toJSON ( ) , outsideColor : { r : 255 , g : 0 , b : 0 } , insideColor : { r : 0 , g : 255 , b : 0 } } ) ; await vp . waitForAllTilesToRender ( ) ; expect ( vp . numRequestedTiles ) . to . equal ( 0 ) ; expect ( vp . numSelectedTiles ) . to . equal ( 1 ) ; const colors = vp . readUniqueColors ( ) ; const bgColor = Color . fromRgba ( 0 , 0 , 0 , 0xff ) ; expect ( colors . length ) . least ( 3 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; const isReddish = ( c ) : boolean => { return c . r >= 0x50 && c . g < 0xa && c . b < 0xa && c . a === 0xff ; } ; const isGreenish = ( c ) => { return c . r < 0xa && c . g >= 0x50 && c . b < 0xa && c . a === 0xff ; } ; for ( const c of colors . array ) { if ( 0 !== c . compare ( bgColor ) ) { expect ( isReddish ( c ) || isGreenish ( c ) ) . to . be . true ; } } } ) ; } ) ; describe ( "Model appearance overrides" , ( ) => { function isReddish ( c ) { return c . r > c . g && c . g < 0xa && c . b < 0xa && c . a === 0xff ; } const bgColor = Color . fromRgba ( 0 , 0 , 0 , 0xff ) ; function expectCorrectColors ( vp ) { const colors = vp . readUniqueColors ( ) ; expect ( colors . length === 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; colors . forEach ( ( color ) => expect ( color === bgColor || isReddish ( color ) ) ) ; } function expectAlmostTransparent ( vp ) { const colors = vp . readUniqueColors ( ) ; expect ( colors . length === 2 ) ; expect ( colors . contains ( bgColor ) ) . to . be . true ; colors . forEach ( ( color ) => expect ( color . r < 20 && color . b < 20 && color . g < 20 ) ) ; } it ( "should override color" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { expect ( vp . view . is3d ( ) ) ; const colorOverride = FeatureAppearance . fromJSON ( { rgb : new RgbColor ( 0xff , 0 , 0 ) } ) ; vp . view . forEachModel ( ( model ) => vp . overrideModelAppearance ( model . id , colorOverride ) ) ; await vp . waitForAllTilesToRender ( ) ; expect ( vp . numRequestedTiles ) . to . equal ( 0 ) ; expect ( vp . numSelectedTiles ) . to . equal ( 1 ) ; expectCorrectColors ( vp ) ; } ) ; } ) ; it ( "should override tranparency" , async ( ) => { const rect = new ViewRect ( 0 , 0 , 100 , 100 ) ; await testViewportsWithDpr ( imodel , rect , async ( vp ) => { expect ( vp . view . is3d ( ) ) ; const colorOverride = FeatureAppearance . fromJSON ( { transparency : .95 } ) ; vp . view . forEachModel ( ( model ) => vp . overrideModelAppearance ( model . id , colorOverride ) ) ; await vp . waitForAllTilesToRender ( ) ; expect ( vp . numRequestedTiles ) . to . equal ( 0 ) ; expect ( vp . numSelectedTiles ) . to . equal ( 1 ) ; expectAlmostTransparent ( vp ) ; } ) ; } ) ; } ) ; } ) ;