Created the data to allow thumbnails to be cached by mesh id

Estimated memory size for mesh
Mesh Render Id
Get long hash for color
default constructor for face and vertex

issue: MatterHackers/MCCentral#3519
Improve thumbnail generation for complicated models
This commit is contained in:
Lars Brubaker 2018-06-19 17:04:04 -07:00
parent 1b4a617da2
commit c1588fcd04
7 changed files with 121 additions and 97 deletions

View file

@ -48,9 +48,9 @@ namespace MatterHackers.MatterControl
private static readonly bool Is32Bit = IntPtr.Size == 4;
// For 32 bit max size to ray trace is 8 MB mesh for 64 bit the max size is 40 MB.
private long MaxFileSizeForTracing => Is32Bit ? 8 * 1000 * 1000 : 40 * 1000 * 1000;
private long MaxFileSizeForTracing => Is32Bit ? 8 * 1000 * 1000 : 16 * 1000 * 1000;
private long MaxFileSizeForThumbnail => Is32Bit ? 16 * 1000 * 1000 : 100 * 1000 * 1000;
private long MaxFileSizeForThumbnail => Is32Bit ? 16 * 1000 * 1000 : 32 * 1000 * 1000;
public Task<IObject3D> CreateItem(ILibraryItem item, Action<double, string> progressReporter)
{
@ -101,12 +101,12 @@ namespace MatterHackers.MatterControl
}
public async Task GetThumbnail(ILibraryItem item, int width, int height, ThumbnailSetter imageCallback)
public async Task GetThumbnail(ILibraryItem libraryItem, int width, int height, ThumbnailSetter imageCallback)
{
IObject3D object3D = null;
long fileSize = 0;
if (item is ILibraryAssetStream contentModel
if (libraryItem is ILibraryAssetStream contentModel
// Only load the stream if it's available - prevents download of Internet content simply for thumbnails
&& contentModel.LocalContentExists
&& contentModel.FileSize < MaxFileSizeForThumbnail)
@ -115,17 +115,65 @@ namespace MatterHackers.MatterControl
// TODO: Wire up limits for thumbnail generation. If content is too big, return null allowing the thumbnail to fall back to content default
object3D = await contentModel.CreateContent();
}
else if (item is ILibraryObject3D)
else if (libraryItem is ILibraryObject3D)
{
object3D = await (item as ILibraryObject3D)?.GetObject3D(null);
object3D = await (libraryItem as ILibraryObject3D)?.GetObject3D(null);
}
var thumbnail = GetThumbnail(object3D, width, height, forceOrthographic: fileSize > MaxFileSizeForTracing);
string thumbnailId = libraryItem.ID;
if (libraryItem is IThumbnail thumbnailKey)
{
thumbnailId = thumbnailKey.ThumbnailKey;
}
var thumbnail = GetThumbnail(object3D, thumbnailId, width, height, false);
imageCallback?.Invoke(thumbnail, true);
}
public ImageBuffer GetThumbnail(IObject3D item, string thumbnailId, int width, int height, bool onlyUseCache)
{
if (item == null)
{
return DefaultImage.CreateScaledImage(width, height);
}
var image = LoadCachedImage(thumbnailId, width, height);
if(image != null)
{
return image;
}
if(onlyUseCache)
{
return DefaultImage.CreateScaledImage(width, height);
}
int estimatedMemorySize = item.EstimatedMemory();
if (estimatedMemorySize > MaxFileSizeForThumbnail)
{
return null;
}
bool forceOrthographic = false;
if (estimatedMemorySize > MaxFileSizeForTracing)
{
forceOrthographic = true;
}
bool RenderOrthographic = (forceOrthographic) ? true : UserSettings.Instance.ThumbnailRenderingMode == "orthographic";
var thumbnail = ThumbnailEngine.Generate(
item,
RenderOrthographic ? RenderType.ORTHOGROPHIC : RenderType.RAY_TRACE,
width,
height,
allowMultiThreading: !ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPrinting);
if (thumbnail != null)
{
// Cache at requested size
string cachePath = ApplicationController.Instance.ThumbnailCachePath(item, width, height);
string cachePath = ApplicationController.Instance.ThumbnailCachePath(thumbnailId, width, height);
// TODO: Lookup best large image and downscale if required
if (false)
@ -134,40 +182,61 @@ namespace MatterHackers.MatterControl
}
AggContext.ImageIO.SaveImageData(cachePath, thumbnail);
if (ApplicationController.Instance.Library.ActiveContainer is ILibraryWritableContainer writableContainer)
var meshCachePath = ApplicationController.Instance.ThumbnailCachePath(item.MeshRenderId().ToString(), width, height);
if (meshCachePath != cachePath)
{
writableContainer.SetThumbnail(item, thumbnail.Width, thumbnail.Height, thumbnail);
// also save it to the mesh cache
AggContext.ImageIO.SaveImageData(meshCachePath, thumbnail);
}
}
return thumbnail ?? DefaultImage.CreateScaledImage(width, height);
}
internal static ImageBuffer LoadCachedImage(string cacheId, int width, int height)
{
ImageBuffer cachedItem = LoadImage(ApplicationController.Instance.ThumbnailCachePath(cacheId, width, height));
if (cachedItem != null)
{
return cachedItem;
}
if (width < 100
&& height < 100)
{
// check for a 100x100 image
var cachedAt100x100 = LoadImage(ApplicationController.Instance.ThumbnailCachePath(cacheId, 100, 100));
if (cachedAt100x100 != null)
{
return cachedAt100x100.CreateScaledImage(width, height);
}
}
return null;
}
private static ImageBuffer LoadImage(string filePath)
{
ImageBuffer thumbnail = null;
try
{
if (File.Exists(filePath))
{
var temp = new ImageBuffer();
AggContext.ImageIO.LoadImageData(filePath, temp);
temp.SetRecieveBlender(new BlenderPreMultBGRA());
thumbnail = temp;
}
imageCallback(thumbnail, raytracedImage: true);
}
else
{
// If thumbnail generation was aborted or failed, return the default icon for this content type
imageCallback(DefaultImage, raytracedImage: true);
return thumbnail;
}
catch { } // Suppress exceptions, return null on any errors
return thumbnail;
}
public ImageBuffer GetThumbnail(IObject3D object3D, int width, int height, bool forceOrthographic)
{
if (object3D == null)
{
return DefaultImage;
}
bool RenderOrthographic = (forceOrthographic) ? true : UserSettings.Instance.ThumbnailRenderingMode == "orthographic";
var thumbnail = ThumbnailEngine.Generate(
object3D,
RenderOrthographic ? RenderType.ORTHOGROPHIC : RenderType.RAY_TRACE,
width,
height,
allowMultiThreading: !ApplicationController.Instance.ActivePrinter.Connection.PrinterIsPrinting);
return thumbnail ?? DefaultImage;
}
public ImageBuffer DefaultImage => AggContext.StaticData.LoadIcon("mesh.png");
}
}