BioCore  5.0.0
A Windows .NET microscopy library and application for viewing, editing, and annotating images.
Loading...
Searching...
No Matches
BioCore.SlideRenderer Class Reference

Public Member Functions

 SlideRenderer (SlideGLArea glArea)
 
void SetSource (OpenSlideBase source)
 
void SetSource (SlideBase source)
 
void ClearCache ()
 
async Task UpdateViewAsync (PointD pyramidalOrigin, int viewportWidth, int viewportHeight, double resolution, ZCT coordinate, BioImage? rgbZarr=null, int[]? rgbSelection=null)
 

Properties

int CurrentLevel [get]
 
int CachedTextureCount [get]
 

Detailed Description

Definition at line 13 of file SlideRenderer.cs.

Constructor & Destructor Documentation

◆ SlideRenderer()

BioCore.SlideRenderer.SlideRenderer ( SlideGLArea glArea)

Definition at line 31 of file SlideRenderer.cs.

32 {
33 _glArea = glArea;
34 }

Member Function Documentation

◆ ClearCache()

void BioCore.SlideRenderer.ClearCache ( )

Definition at line 62 of file SlideRenderer.cs.

63 {
64 _renderVersion++;
65 _glArea.ClearTextureCache();
66 _uploadedTiles.Clear();
67 _currentLevel = -1;
68 _hasContentKey = false;
69 _contentRgbZarr = null;
70 _contentRgbSelection = null;
71 }
void ClearTextureCache()
Clear all cached textures.

◆ SetSource() [1/2]

void BioCore.SlideRenderer.SetSource ( OpenSlideBase source)

Definition at line 36 of file SlideRenderer.cs.

37 {
38 // Viewport updates reuse the source; only switching images should
39 // discard the textures currently being displayed.
40 if (_useOpenSlide && ReferenceEquals(_openSlideBase, source))
41 return;
42
43 _openSlideBase = source;
44 _slideBase = null;
45 _useOpenSlide = true;
46 _openTileCache = new OpenSlideGTK.TileCache(source, 200);
47 ClearCache();
48 }

◆ SetSource() [2/2]

void BioCore.SlideRenderer.SetSource ( SlideBase source)

Definition at line 50 of file SlideRenderer.cs.

51 {
52 if (!_useOpenSlide && ReferenceEquals(_slideBase, source))
53 return;
54
55 _slideBase = source;
56 _openSlideBase = null;
57 _useOpenSlide = false;
58 _tileCache = new BioLib.TileCache(source, 200);
59 ClearCache();
60 }

◆ UpdateViewAsync()

async Task BioCore.SlideRenderer.UpdateViewAsync ( PointD pyramidalOrigin,
int viewportWidth,
int viewportHeight,
double resolution,
ZCT coordinate,
BioImage? rgbZarr = null,
int?[] rgbSelection = null )

Definition at line 73 of file SlideRenderer.cs.

81 {
82 if (_openSlideBase == null && _slideBase == null)
83 return;
84 if (viewportWidth <= 1 && viewportHeight <= 1)
85 return;
86 var schema = _useOpenSlide ? _openSlideBase.Schema : _slideBase.Schema;
87
88 int level = TileUtil.GetLevel(schema.Resolutions, resolution);
89 var levelRes = schema.Resolutions[level];
90 double levelUnitsPerPixel = levelRes.UnitsPerPixel;
91
92 int[]? requestedRgbSelection = rgbSelection?.ToArray();
93 if (rgbZarr != null && requestedRgbSelection == null)
94 requestedRgbSelection = new[] { 0, 1, 2 };
95 bool contentChanged = !_hasContentKey
96 || coordinate.Z != _contentZ
97 || coordinate.C != _contentC
98 || coordinate.T != _contentT
99 || !ReferenceEquals(rgbZarr, _contentRgbZarr)
100 || !SelectionsEqual(requestedRgbSelection, _contentRgbSelection);
101
102 // Every invocation supersedes an older asynchronous viewport request.
103 // A content or pyramid-level change also invalidates GPU textures because
104 // their cache key is only TileIndex and does not include Z/C/T or RGB state.
105 int renderVersion = ++_renderVersion;
106 if (contentChanged || level != _currentLevel)
107 {
108 _glArea.ClearTextureCache();
109 _uploadedTiles.Clear();
110 _currentLevel = level;
111 }
112
113 _hasContentKey = true;
114 _contentZ = coordinate.Z;
115 _contentC = coordinate.C;
116 _contentT = coordinate.T;
117 _contentRgbZarr = rgbZarr;
118 _contentRgbSelection = requestedRgbSelection;
119
120 // Calculate world extent for the viewport
121 double minX = pyramidalOrigin.X * resolution;
122 double minY = -pyramidalOrigin.Y * resolution;
123 double width = viewportWidth * resolution;
124 double height = viewportHeight * resolution;
125 var worldExtent = new Extent(minX, minY - height, minX + width, minY);
126
127 // Get tiles that intersect the viewport
128 var tileInfos = schema.GetTileInfos(worldExtent, level).ToList();
129
130 if (tileInfos.Count == 0)
131 {
132 var pixelExtent = OpenSlideGTK.ExtentEx.WorldToPixelInvertedY(worldExtent, resolution);
133 tileInfos = schema.GetTileInfos(pixelExtent, level).ToList();
134 }
135
136 int[]? rgbChannels = requestedRgbSelection;
137 // OpenSlide tiles are fetched below through GetTileAsync. Its bulk
138 // prefetch uses separate stitch state that this renderer never reads,
139 // and fetching both ways can fail or duplicate the work.
140 if (rgbZarr == null && !_useOpenSlide)
141 await _slideBase.FetchTilesAsync(tileInfos.ToList(), level, coordinate, pyramidalOrigin, new AForge.Size(viewportWidth, viewportHeight));
142 if (renderVersion != _renderVersion)
143 return;
144
145 var renderInfos = new List<TileRenderInfo>();
146 foreach (var tileInfo in tileInfos)
147 {
148 if (!_glArea.HasTileTexture(tileInfo.Index))
149 {
150 byte[] tileData;
151 if (rgbZarr != null)
152 {
153 int tileWidth = schema.GetTileWidth(level);
154 int tileHeight = schema.GetTileHeight(level);
155 int tilePixelWidth = (int)Math.Round(tileInfo.Extent.Width / levelUnitsPerPixel);
156 int tilePixelHeight = (int)Math.Round(tileInfo.Extent.Height / levelUnitsPerPixel);
157 tileData = await ZarrChannelView.ReadRgbTileAsync(rgbZarr, level,
158 tileInfo.Index.Col * tileWidth, tileInfo.Index.Row * tileHeight,
159 tilePixelWidth, tilePixelHeight, coordinate, rgbChannels!);
160 }
161 else if (_useOpenSlide)
162 tileData = await _openSlideBase.GetTileAsync(tileInfo);
163 else
164 tileData = await _slideBase.GetTileAsync(tileInfo, coordinate);
165 if (renderVersion != _renderVersion)
166 return;
167 if (tileData != null && rgbZarr == null && rgbChannels != null)
168 {
169 tileData = (byte[])tileData.Clone();
170 for (int i = 0; i + 3 < tileData.Length; i += 4)
171 for (int color = 0; color < 3; color++)
172 if (rgbChannels[color] < 0) tileData[i + color] = 0;
173 }
174 if (tileData != null)
175 {
176 int tW = (int)Math.Round(tileInfo.Extent.Width / levelUnitsPerPixel);
177 int tH = (int)Math.Round(tileInfo.Extent.Height / levelUnitsPerPixel);
178
179 // BioLib/OpenSlide return schema-sized buffers with black
180 // padding at image edges, while TileInfo exposes the clipped
181 // edge extent. Repack a padded edge tile before uploading it;
182 // otherwise OpenGL treats the clipped width as the source row
183 // stride and the lower rows come from unrelated buffer offsets.
184 if (rgbZarr == null)
185 {
186 int sourceWidth = schema.GetTileWidth(level);
187 int sourceHeight = schema.GetTileHeight(level);
188 if ((tW != sourceWidth || tH != sourceHeight) &&
189 tileData.Length >= sourceWidth * sourceHeight * 4)
190 {
191 byte[] clipped = new byte[tW * tH * 4];
192 int copyBytes = tW * 4;
193 for (int row = 0; row < tH; row++)
194 Buffer.BlockCopy(tileData, row * sourceWidth * 4,
195 clipped, row * copyBytes, copyBytes);
196 tileData = clipped;
197 }
198 }
199
200 _glArea.UploadTileTexture(tileInfo.Index, tileData, tW, tH);
201 _uploadedTiles.Add(tileInfo.Index);
202 }
203 }
204
205 if (_glArea.HasTileTexture(tileInfo.Index))
206 {
207 var renderInfo = CalculateScreenPosition(
208 tileInfo,
209 pyramidalOrigin,
210 resolution,
211 level,
212 schema);
213 renderInfos.Add(renderInfo);
214 }
215 }
216
217 _glArea.SetTilesToRender(renderInfos);
218 _glArea.RequestRedraw();
219 }
void RequestRedraw()
Request a redraw of the GLArea.
bool HasTileTexture(TileIndex index)
Check if a tile texture is already in the GPU cache.
bool UploadTileTexture(TileIndex index, byte[] pixelData, int tileWidth, int tileHeight)
Upload a tile texture to the GPU. Call from the main thread. Returns true if upload succeeded.
void SetTilesToRender(IEnumerable< TileRenderInfo > tiles)
Prepare tiles for rendering. Call before RequestRedraw().

Property Documentation

◆ CachedTextureCount

int BioCore.SlideRenderer.CachedTextureCount
get

Definition at line 291 of file SlideRenderer.cs.

◆ CurrentLevel

int BioCore.SlideRenderer.CurrentLevel
get

Definition at line 290 of file SlideRenderer.cs.


The documentation for this class was generated from the following file: