/// <summary> /// Builds the standard scene. /// </summary> /// <param name="newScene">The scenegraph to be updated.</param> /// <param name="newCamera">The camera to be updated.</param> public static void BuildStandardFloor(SceneManipulator manipulator, string sceneLayer) { SceneLayer bgLayer = manipulator.AddLayer("BACKGROUND"); manipulator.SetLayerOrderID(bgLayer, 0); manipulator.SetLayerOrderID(Scene.DEFAULT_LAYER_NAME, 1); ResourceLink sourceBackgroundTexture = new AssemblyResourceLink( typeof(SeeingSharpSampleResources), "Textures.Background.dds"); ResourceLink sourceTileTexture = new AssemblyResourceLink( typeof(SeeingSharpSampleResources), "Textures.Floor.dds"); var resBackgroundTexture = manipulator.AddTexture(sourceBackgroundTexture); manipulator.Add(new FullscreenTextureObject(resBackgroundTexture), bgLayer.Name); // Define textures and materials var resTileTexture = manipulator.AddResource(() => new StandardTextureResource(sourceTileTexture)); var resTileMaterial = manipulator.AddResource(() => new SimpleColoredMaterialResource(resTileTexture)); // Define floor geometry FloorType floorType = new FloorType(new Vector2(4f, 4f), 0f); floorType.BottomMaterial = resTileMaterial; floorType.DefaultFloorMaterial = resTileMaterial; floorType.SideMaterial = resTileMaterial; floorType.SetTilemap(25, 25); // Add floor to scene var resFloorGeometry = manipulator.AddResource((() => new GeometryResource(floorType))); var floorObject = manipulator.AddGeneric(resFloorGeometry, sceneLayer); }
public void Check_OpenForReading_AnotherFile() { var resLink = new AssemblyResourceLink(this.GetType(), "Dummy", "CommonPixelShader.hlsl"); resLink = resLink.GetForAnotherFile("CommonPixelShader.hlsl", "..", "Dummy2"); var foundIncludeLine = false; using (var inStream = resLink.OpenRead()) using (var inStreamReader = new StreamReader(inStream)) { string?actLine; while (null != (actLine = inStreamReader.ReadLine())) { if (actLine.StartsWith("#include")) { foundIncludeLine = true; break; } } } Assert.IsTrue(foundIncludeLine); }
public async Task ReadSimple_WmvVideo_Seek() { await UnitTestHelper.InitializeWithGrahicsAsync(); ResourceLink videoLink = new AssemblyResourceLink( this.GetType().Assembly, "SeeingSharp.Tests.Rendering.Ressources.Videos", "DummyVideo.wmv"); GDI.Bitmap bitmapFrame = null; using (FrameByFrameVideoReader videoReader = new FrameByFrameVideoReader(videoLink)) using (MemoryMappedTexture32bpp actFrameBuffer = new MemoryMappedTexture32bpp(videoReader.FrameSize)) { videoReader.SetCurrentPosition(TimeSpan.FromSeconds(2.0)); videoReader.ReadFrame(actFrameBuffer); actFrameBuffer.SetAllAlphaValuesToOne_ARGB(); using (bitmapFrame = GraphicsHelper.LoadBitmapFromMappedTexture(actFrameBuffer)) { Assert.NotNull(bitmapFrame); Assert.True(videoReader.CurrentPosition > TimeSpan.FromSeconds(1.9)); Assert.True(videoReader.CurrentPosition < TimeSpan.FromSeconds(2.1)); Assert.True(videoReader.Duration > TimeSpan.FromSeconds(3.9)); Assert.True(videoReader.Duration < TimeSpan.FromSeconds(4.1)); Assert.True(videoReader.IsSeekable); Assert.True( BitmapComparison.IsNearEqual(bitmapFrame, Properties.Resources.ReferenceImage_VideoFrameWmv_Seek)); } } }
/// <summary> /// Builds a floor to the given scene. /// </summary> protected void BuildStandardFloor(SceneManipulator manipulator, string sceneLayer) { var bgLayer = manipulator.AddLayer("BACKGROUND"); manipulator.SetLayerOrderId(bgLayer, 0); manipulator.SetLayerOrderId(Scene.DEFAULT_LAYER_NAME, 1); ResourceLink sourceBackgroundTexture = new AssemblyResourceLink( typeof(SampleBase), "Assets.Background.dds"); ResourceLink sourceTileTexture = new AssemblyResourceLink( typeof(SampleBase), "Assets.Floor.dds"); var resBackgroundTexture = manipulator.AddTextureResource(sourceBackgroundTexture); manipulator.AddObject(new FullscreenTexture(resBackgroundTexture), bgLayer.Name); // Define textures and materials var resTileTexture = manipulator.AddResource(device => new StandardTextureResource(sourceTileTexture)); var resTileMaterial = manipulator.AddResource(device => new StandardMaterialResource(resTileTexture)); // Define floor geometry var floorType = new FloorGeometryFactory(new Vector2(4f, 4f)); floorType.SetTilemap(25, 25); // AddObject floor to scene var resFloorGeometry = manipulator.AddResource(device => new GeometryResource(floorType)); manipulator.AddMeshObject(resFloorGeometry, sceneLayer, resTileMaterial); }
public void GetFileExtension_AssemblyResourceLink() { ResourceLink extPNG = new AssemblyResourceLink(this.GetType(), "DummyNamespace.DummyFile.png"); ResourceLink extJPG = extPNG.GetForAnotherFile("Dummy.jpg"); Assert.True(extPNG.FileExtension == "png"); Assert.True(extJPG.FileExtension == "jpg"); }
public void Load_DummyData_Txt() { ResourceLink tableSource = new AssemblyResourceLink( typeof(TableDataTests), "Resources.TableData.DummyData.txt"); CsvTableImporter tableImporter = new CsvTableImporter(); Load_DummyData_GenericPart(tableSource, tableImporter, tableImporter.CreateDefaultConfig(tableSource), "CSV"); }
private async Task LoadSampleImageAsync(AssemblyResourceLink sourceLink) { var source = new BitmapImage(); using (var randomAccessStream = sourceLink.OpenRead().AsRandomAccessStream()) { await source.SetSourceAsync(randomAccessStream); } _bitmapSource = source; this.RaisePropertyChanged(nameof(this.BitmapSource)); }
public async Task Render3D_VideoTexture() { await UnitTestHelper.InitializeWithGrahicsAsync(); ResourceLink videoLink = new AssemblyResourceLink( this.GetType().Assembly, "SeeingSharp.Tests.Rendering.Ressources.Videos", "DummyVideo.mp4"); using (MemoryRenderTarget memRenderTarget = new MemoryRenderTarget(1024, 1024)) { memRenderTarget.ClearColor = Color4.CornflowerBlue; // Get and configure the camera PerspectiveCamera3D camera = memRenderTarget.Camera as PerspectiveCamera3D; camera.Position = new Vector3(0f, 5f, -7f); camera.Target = new Vector3(0f, 0f, 0f); camera.UpdateCamera(); // Define scene await memRenderTarget.Scene.ManipulateSceneAsync((manipulator) => { var resVideoTexture = manipulator.AddResource <VideoThumbnailTextureResource>( () => new VideoThumbnailTextureResource(videoLink, TimeSpan.FromMilliseconds(300.0))); var resVideoMaterial = manipulator.AddSimpleColoredMaterial(resVideoTexture, addToAlpha: 1f); var geoResource = manipulator.AddResource <GeometryResource>( () => new GeometryResource(new PalletType( palletMaterial: NamedOrGenericKey.Empty, contentMaterial: resVideoMaterial))); GenericObject newObject = manipulator.AddGeneric(geoResource); newObject.RotationEuler = new Vector3(0f, EngineMath.RAD_90DEG / 2f, 0f); newObject.Scaling = new Vector3(2f, 2f, 2f); }); // Take screenshot GDI.Bitmap screenshot = await memRenderTarget.RenderLoop.GetScreenshotGdiAsync(); screenshot = await memRenderTarget.RenderLoop.GetScreenshotGdiAsync(); //screenshot.DumpToDesktop("Blub.png"); // Calculate and check difference bool isNearEqual = BitmapComparison.IsNearEqual( screenshot, Properties.Resources.ReferenceImage_SimpleObject_VideoTexture); Assert.True(isNearEqual, "Difference to reference image is to big!"); } // Finishing checks Assert.True(GraphicsCore.Current.MainLoop.RegisteredRenderLoopCount == 0, "RenderLoops where not disposed correctly!"); }
public void GpxVersion1_0() { var resLink = new AssemblyResourceLink( typeof(FileLoadTests), "Test_Gpx1_0.gpx"); using var inStream = resLink.OpenRead(); var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility); Assert.IsNotNull(gpxFile); Assert.IsNotNull(gpxFile.Metadata); Assert.AreEqual("Kösseine", gpxFile !.Metadata !.Name); Assert.AreEqual(1, gpxFile.Tracks.Count); }
public void Check_ReadAndMergeFromAssemblyResources() { var resLink = new AssemblyResourceLink(this.GetType(), "Dummy", "CommonPixelShader.hlsl"); var singleShaderFileBuilder = new StringBuilder(1024); SingleShaderFileBuilder.ReadShaderFileAndResolveIncludes(resLink, singleShaderFileBuilder); var result = singleShaderFileBuilder.ToString(); Assert.IsTrue(result.Contains("constants.hlsl")); Assert.IsTrue(result.Contains("struct VSInputStandard")); Assert.IsTrue(result.Contains("float4 ApplyColorBorders(float4 inputColor, float distanceToCamera, float2 texCoord)")); }
/// <summary> /// Called when the sample has to startup. /// </summary> /// <param name="targetRenderLoop">The target render loop.</param> public override async Task OnStartupAsync(RenderLoop targetRenderLoop) { targetRenderLoop.EnsureNotNull(nameof(targetRenderLoop)); // Get and configure the camera Camera3DBase camera = targetRenderLoop.Camera as PerspectiveCamera3D; camera.Position = new Vector3(0f, 5f, -7f); camera.Target = new Vector3(0f, 0f, 0f); camera.UpdateCamera(); // Open the video file // see original vide at: https://www.flickr.com/photos/mlinksva/20939860191/in/photolist-xUofUg-xzKr45-xzKn65-xzhfV1-xPfMqh-wTxmUk-wSd5bL-xwAUF3-wSbSW3-xNqVYR-xNqUyB-xKte5J-xKtbMh-wQKVu5-wQVbiV-wQLHns-xKsHiQ-xvapef-xKsF1y-xMMyY2-xvbbXC-xvb5Xy-xNqkBK-xvb25o-xvafSW-xvb4FW-xKsavw-xMM69V-wQUtWn-xvgDSv-xLW62q-xvbig9-wQL8p7-xMMFog-wQV8CK-wQLGcS-wQLLZY-wQKN9U-xvhorD-xNq5we-xvbh7f-wQU3KF-xLWiZE-xvgVqe-wQKKEq-xvaJN3-xNqjhF-wQUEhH-xKspPw-wQRXGt // Licensed under public domain ResourceLink videoLink = new AssemblyResourceLink( typeof(SeeingSharpSampleResources), "Videos.DummyVideoLandscape.mp4"); m_videoReader = new AsyncRealtimeVideoReader(videoLink); m_videoReader.VideoReachedEnd += (sender, eArgs) => { m_videoReader.SetCurrentPosition(TimeSpan.Zero); }; // Define scene await targetRenderLoop.Scene.ManipulateSceneAsync((manipulator) => { // Create floor SampleSceneBuilder.BuildStandardFloor( manipulator, Scene.DEFAULT_LAYER_NAME); // Define texture and resource var resVideoTexture = manipulator.AddResource <VideoTextureResource>( () => new VideoTextureResource(m_videoReader)); var resVideoMaterial = manipulator.AddSimpleColoredMaterial(resVideoTexture, addToAlpha: 1f); var geoResource = manipulator.AddResource <GeometryResource>( () => new GeometryResource(new PalletType( palletMaterial: NamedOrGenericKey.Empty, contentMaterial: resVideoMaterial))); // Add the object GenericObject newObject = manipulator.AddGeneric(geoResource); newObject.RotationEuler = new Vector3(0f, EngineMath.RAD_90DEG / 2f, 0f); newObject.Scaling = new Vector3(2f, 2f, 2f); newObject.EnableShaderGeneratedBorder(); }); }
public static async Task ResetScene(RenderLoop targetRenderLoop) { await targetRenderLoop.Scene.ManipulateSceneAsync(manipulator => { // Clear the scene first manipulator.Clear(); // Define layers var bgLayer = manipulator.AddLayer("BACKGROUND"); var gridLayer = manipulator.AddLayer("GRID"); manipulator.SetLayerOrderId(bgLayer, 0); manipulator.SetLayerOrderId(gridLayer, 1); manipulator.SetLayerOrderId(Scene.DEFAULT_LAYER_NAME, 2); // Build new background layer with fullscreen texture (layer BACKGROUND) var sourceBackgroundTexture = new AssemblyResourceLink( typeof(App), "Assets.Background.dds"); var resBackgroundTexture = manipulator.AddTextureResource(sourceBackgroundTexture); var objBackgroundTexture = new FullscreenTexture(resBackgroundTexture); objBackgroundTexture.Tag1 = new ModelViewerSceneObjectMetadata(true); manipulator.AddObject(objBackgroundTexture, bgLayer.Name); // Add bottom grid (layer GRID) var resGridGeometry = manipulator.AddResource( _ => new GeometryResource(new Grid3DGeometryFactory { TileWidth = 0.05f, TilesX = 50, TilesZ = 50 })); var gridMesh = manipulator.AddMeshObject(resGridGeometry, gridLayer.Name); gridMesh.YPos = -0.5f; gridMesh.Name = Constants.OBJ_NAME_GRID; gridMesh.Tag1 = new ModelViewerSceneObjectMetadata(true); // Add bounding box (layer GRID) var unitCube = new WireObject( Color4.GreenColor, new BoundingBox( new Vector3(-0.5f, -0.5f, -0.5f), new Vector3(0.5f, 0.5f, 0.5f))); unitCube.Name = Constants.OBJ_NAME_UNIT_CUBE; unitCube.Tag1 = new ModelViewerSceneObjectMetadata(true); manipulator.AddObject(unitCube, gridLayer.Name); }); }
public void SimpleUpload_ColorBitmap_WrongTextureSize() { var coreConfig = new GraphicsCoreConfiguration(); coreConfig.DebugEnabled = true; var testResource = new AssemblyResourceLink( typeof(TextureUploaderTests), "Resources.TextureUploader", "TestTexture.png"); using (var engineFactory = new EngineFactory(coreConfig)) using (var device = EngineDevice.CreateSoftwareDevice(engineFactory)) using (var colorTexture = GraphicsHelper.CreateTexture(device, testResource)) using (var texUploader = new TextureUploader(device, 100, 100, GraphicsHelper.Internals.DEFAULT_TEXTURE_FORMAT, true)) using (texUploader.UploadToMemoryMappedTexture <int>(colorTexture)) { } }
public void SimpleUpload_ColorBitmap_WrongUploadFormat() { var coreConfig = new GraphicsCoreConfiguration(); coreConfig.DebugEnabled = true; var testResource = new AssemblyResourceLink( typeof(TextureUploaderTests), "Resources.TextureUploader", "TestTexture.png"); using (var engineFactory = new EngineFactory(coreConfig)) using (var device = EngineDevice.CreateSoftwareDevice(engineFactory)) using (var colorTexture = GraphicsHelper.CreateTexture(device, testResource)) using (var texUploader = TextureUploader.ConstructUsingPropertiesFromTexture(device, colorTexture)) using (texUploader.UploadToMemoryMappedTexture <Vector3>(colorTexture)) { } }
public static AssemblyResourceLink GetShaderResourceLink(string subdirectory, string shaderNameWithoutExt) { AssemblyResourceLink resourceLink; if (string.IsNullOrEmpty(subdirectory)) { resourceLink = new AssemblyResourceLink( typeof(SeeingSharpResources), "Shaders", $"{shaderNameWithoutExt}.hlsl"); } else { resourceLink = new AssemblyResourceLink( typeof(SeeingSharpResources), $"Shaders.{subdirectory}", $"{shaderNameWithoutExt}.hlsl"); } return(resourceLink); }
public void SimpleUpload_ColorBitmap() { var coreConfig = new GraphicsCoreConfiguration(); coreConfig.DebugEnabled = true; var testResource = new AssemblyResourceLink( typeof(TextureUploaderTests), "Resources.TextureUploader", "TestTexture.png"); using (var engineFactory = new EngineFactory(coreConfig)) using (var device = EngineDevice.CreateSoftwareDevice(engineFactory)) using (var colorTexture = GraphicsHelper.CreateTexture(device, testResource)) using (var texUploader = TextureUploader.ConstructUsingPropertiesFromTexture(device, colorTexture)) using (var uploaded = texUploader.UploadToMemoryMappedTexture <int>(colorTexture)) { Assert.IsTrue(new Color4(uploaded[224, 326]).EqualsWithTolerance(Color4.RedColor)); Assert.IsTrue(new Color4(uploaded[10, 10]).EqualsWithTolerance(Color4.White)); Assert.IsTrue(new Color4(uploaded[561, 261]).EqualsWithTolerance(new Color4(0, 38, 255))); Assert.IsTrue(new Color4(uploaded[538, 669]).EqualsWithTolerance(new Color4(255, 0, 220))); } }
public async Task ImportAndRender_ACShadedObject() { await UnitTestHelper.InitializeWithGrahicsAsync(); IEnumerable <SceneObject> importedObjects = null; using (MemoryRenderTarget memRenderTarget = new MemoryRenderTarget(1024, 1024)) { memRenderTarget.ClearColor = Color4.CornflowerBlue; // Get and configure the camera PerspectiveCamera3D camera = memRenderTarget.Camera as PerspectiveCamera3D; camera.Position = new Vector3(-1.5f, 3f, -1.5f); camera.Target = new Vector3(1f, 0f, 1f); camera.UpdateCamera(); ResourceLink objSource = new AssemblyResourceLink( typeof(ModelLoadingAndRenderingTests), "Ressources.Models.ModelShaded.ac"); importedObjects = await memRenderTarget.Scene.ImportAsync(objSource); // Wait until ac file is completely loaded await memRenderTarget.Scene.WaitUntilVisibleAsync(importedObjects, memRenderTarget.RenderLoop); // Take screenshot GDI.Bitmap screenshot = await memRenderTarget.RenderLoop.GetScreenshotGdiAsync(); //screenshot.DumpToDesktop(TEST_DUMMY_FILE_NAME); // Calculate and check difference bool isNearEqual = BitmapComparison.IsNearEqual( screenshot, Properties.Resources.ReferenceImage_ShadedObject); Assert.True(isNearEqual, "Difference to reference image is to big!"); } // Finishing checks Assert.True(GraphicsCore.Current.MainLoop.RegisteredRenderLoopCount == 0, "RenderLoops where not disposed correctly!"); Assert.NotNull(importedObjects); Assert.True(importedObjects.Count() == 1); }
public async Task ReadSimple_WmvVideo() { await UnitTestHelper.InitializeWithGrahicsAsync(); ResourceLink videoLink = new AssemblyResourceLink( this.GetType().Assembly, "SeeingSharp.Tests.Rendering.Ressources.Videos", "DummyVideo.wmv"); GDI.Bitmap bitmapFrame10 = null; using (FrameByFrameVideoReader videoReader = new FrameByFrameVideoReader(videoLink)) using (MemoryMappedTexture32bpp actFrameBuffer = new MemoryMappedTexture32bpp(videoReader.FrameSize)) { int frameIndex = 0; while (!videoReader.EndReached) { if (videoReader.ReadFrame(actFrameBuffer)) { actFrameBuffer.SetAllAlphaValuesToOne_ARGB(); frameIndex++; if (frameIndex != 10) { continue; } bitmapFrame10 = GraphicsHelper.LoadBitmapFromMappedTexture(actFrameBuffer); break; } } Assert.NotNull(bitmapFrame10); Assert.True(videoReader.Duration > TimeSpan.FromSeconds(3.9)); Assert.True(videoReader.Duration < TimeSpan.FromSeconds(4.1)); Assert.True(videoReader.IsSeekable); Assert.True( BitmapComparison.IsNearEqual(bitmapFrame10, Properties.Resources.ReferenceImage_VideoFrameWmv)); } }
public void Check_OpenForReading_FullNamespace() { var resLink = new AssemblyResourceLink(this.GetType().Assembly, "SeeingSharp.Tests.AssemblyResourcesAndShaderTests.Dummy", "CommonPixelShader.hlsl"); var foundIncludeLine = false; using (var inStream = resLink.OpenRead()) using (var inStreamReader = new StreamReader(inStream)) { string?actLine; while (null != (actLine = inStreamReader.ReadLine())) { if (actLine.StartsWith("#include")) { foundIncludeLine = true; break; } } } Assert.IsTrue(foundIncludeLine); }
public void GpxVersion1_0_SaveAs1_1() { var resLink = new AssemblyResourceLink( typeof(FileLoadTests), "Test_Gpx1_0.gpx"); using var inStream = resLink.OpenRead(); var gpxFile = GpxFile.Deserialize(inStream, GpxFileDeserializationMethod.Compatibility); var outStrBuilder = new StringBuilder(33000); using (var strWriter = new StringWriter(outStrBuilder)) { GpxFile.Serialize(gpxFile, strWriter); } var writtenFile = outStrBuilder.ToString(); // Check output Assert.IsTrue(writtenFile.Contains("version=\"1.1\""), "Version attribute"); Assert.IsTrue(writtenFile.Contains("xmlns=\"http://www.topografix.com/GPX/1/1\""), "Default namespace"); // Check original data Assert.AreEqual("1.0", gpxFile.Version, "Original version"); }
/// <summary> /// Gets or creates the material resource for the given VertexStructure object. /// </summary> internal static MaterialResource GetOrCreateMaterialResource(this ResourceDictionary resourceDict, VertexStructureSurface targetSurface) { NamedOrGenericKey materialKey = targetSurface.Material; NamedOrGenericKey textureKey = targetSurface.TextureKey; // Get the material if it is already created if ((!materialKey.IsEmpty) && (resourceDict.ContainsResource(materialKey))) { return(resourceDict.GetResource <MaterialResource>(materialKey)); } // Generate a dynamic material key if (materialKey.IsEmpty) { materialKey = new NamedOrGenericKey(targetSurface.MaterialProperties.GetDynamicResourceKey()); } // Get the material if it is already created if (resourceDict.ContainsResource(materialKey)) { return(resourceDict.GetResource <MaterialResource>(materialKey)); } if (textureKey.IsEmpty) { // Create a default material without any texture SimpleColoredMaterialResource result = resourceDict.AddResource <SimpleColoredMaterialResource>(materialKey, new SimpleColoredMaterialResource()); result.MaterialDiffuseColor = targetSurface.MaterialProperties.DiffuseColor; return(result); } else { // Create texture resource if needed try { if ((!resourceDict.ContainsResource(textureKey)) && (!string.IsNullOrEmpty(textureKey.NameKey))) { // Try to find and create the texture resource by its name if (targetSurface.ResourceLink != null) { var textureResourceLink = targetSurface.ResourceLink.GetForAnotherFile(textureKey.NameKey); resourceDict.AddResource <StandardTextureResource>( textureKey, new StandardTextureResource( targetSurface.ResourceLink.GetForAnotherFile(textureKey.NameKey))); } else if (targetSurface.ResourceSourceAssembly != null) { var textureResourceLink = new AssemblyResourceLink( targetSurface.ResourceSourceAssembly, targetSurface.ResourceSourceAssembly.GetName().Name + ".Resources.Textures", textureKey.NameKey); if (textureResourceLink.IsValid()) { resourceDict.AddResource <StandardTextureResource>( textureKey, new StandardTextureResource(textureResourceLink)); } else { // Unable to resolve texture textureKey = NamedOrGenericKey.Empty; } } else { // Unable to resolve texture textureKey = NamedOrGenericKey.Empty; } } } catch { } // Create a default textured material if (!textureKey.IsEmpty) { SimpleColoredMaterialResource result = resourceDict.AddResource <SimpleColoredMaterialResource>( materialKey, new SimpleColoredMaterialResource(textureKey)); result.MaterialDiffuseColor = targetSurface.MaterialProperties.DiffuseColor; return(result); } else { SimpleColoredMaterialResource result = resourceDict.AddResource <SimpleColoredMaterialResource>( materialKey, new SimpleColoredMaterialResource()); result.MaterialDiffuseColor = targetSurface.MaterialProperties.DiffuseColor; return(result); } } }
/// <summary> /// Initializes a new instance of the <see cref="AssemblyResourceLinkSource" /> class. /// </summary> /// <param name="resourceLink">The link to the resource.</param> public AssemblyResourceLinkSource(AssemblyResourceLink resourceLink) { resourceLink.EnsureNotNull(nameof(resourceLink)); _resourceLink = resourceLink; }