Jump to content
  • Advertisement
Sign in to follow this  
piecuch.p

QLMesh - Quicklook generator based on Assimp

This topic is 853 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Apple has just accepted my application on AppStore: QLMesh. It is a QuickLook plugin for displaying a preview of many 3d formats, base on Open Assets Import Library. All 3d formats are supported plus some 2d compressed textures.

[attachment=31149:qlmesh1.png]

 

Mipmaps are displayed with multi-page view - quite handy and useful feature - also because you can browse within mipmaps directly in finder.

[attachment=31150:mipmaps.png]

CGContextRef kcontext = QLPreviewRequestCreatePDFContext(preview, NULL, NULL, properties);
...
CGImageRef cimage = ...;
// Fill 3/4 of the rect
const float enlarge = 1.0 + 0.48*i*i;
CGRect canvasRect = CGRectMake((image[0].width - w*enlarge)/2, (image[0].height - h*enlarge)/2, w*enlarge, h*enlarge);
CGContextBeginPage(kcontext, &pageRect);
CGContextDrawImage(kcontext, canvasRect, cimage);
CGContextEndPage(kcontext);

Part of the QLMesh is control application for quicklook plugin.

[attachment=31151:qlmesh5.png]

Usually that would not be anything special, however for MacStore applications this is a very different story. MacStore applications are all sanboxed. There are ways to communicate and share data between such applications, eg. using App groups, but quicklook plugins do not support that feature. After struggling for some time with this problem I came out with this simple solution: 

1. register additional file type/extension managed by your plugin - dedicated for passing settings to the plugin
2. when you want to pass some settings to the plugin - save settings in a file with  a special extension and request  a quicklook thumbnail for that file
3. you plugin will be executed with settings file - you can now configure your plugin
 
That's easy. Now hardest part: how to send some data (eg. current configuration) from plugin to Control application. Solution: encode data in thumbnail image and send it back from plugin.
 
Some coding - function for decoding CGDictionary to CGImage:
CGImageRef _decodeDictToCGImage(CFDictionaryRef dictref, const int thsize)
{
    NSDictionary *dict = (__bridge NSDictionary *)dictref;

    // Get a color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    NSData *decodedData = [NSKeyedArchiver archivedDataWithRootObject:dict];
    const long decodedDataSize = decodedData.length;
    NSMutableData *paddedData = [NSMutableData dataWithBytes:&decodedDataSize length:sizeof(long)];
    [paddedData appendData:decodedData];
    int sz = thsize; // min. thumbnail size
    if (decodedData.length < sz*sz*3)
        [paddedData increaseLengthBy:sz*sz*3-decodedData.length];
    else {
        sz = ceil(sqrtf(decodedData.length/3));
        [paddedData increaseLengthBy:sz*sz*3-decodedData.length];
    }
    const char* rgb = [paddedData bytes];
    char* rgba = (char*)malloc(sz*sz*4);
    for(int i=0; i < sz*sz; ++i)
    {
        rgba[4*i]   = rgb[3*i];
        rgba[4*i+1] = rgb[3*i+1];
        rgba[4*i+2] = rgb[3*i+2];
        rgba[4*i+3] = 0xff;
    }
    // Assuming the decoded data is only pixel data
    CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, rgba, sz*sz*4, NULL);
    // Given size_t width, height which you should already have somehow
    CGImageRef image = CGImageCreate(
                                     sz, sz,
                                     /* bpc */ 8, /* bpp */ 32, /* pitch */ sz*4,
                                     colorSpace, kCGBitmapByteOrderDefault|kCGImageAlphaNone,
                                     dataProvider, /* decode array */ NULL, /* interpolate? */ FALSE,
                                     kCGRenderingIntentDefault /* adjust intent according to use */ );
    if (image == nil)
        NSLog(@"Failed to create image from %@.", decodedData);
#if 0
    NSData *data = (id)CFBridgingRelease(CGDataProviderCopyData(CGImageGetDataProvider(image)));
    NSLog(@"output image: %zux%zu %zu, %zu, %@ %lu",
          CGImageGetWidth(image), CGImageGetHeight(image),
          CGImageGetBitsPerPixel(image), CGImageGetBitsPerComponent(image),
          data, [(id)data length]);
#endif
    // Release things the image took ownership of.
    CGDataProviderRelease(dataProvider);
    CGColorSpaceRelease(colorSpace);
    if (rgba) free(rgba);
    
    return image;
}

What's next:

 

1. Rendering is done using off-screen Mesa extension (this is static build). Currently it is software rasterizer (swsoft) but next version should use llvmpipe engine.

 

2. I am working on may optimisations - mostly related to speeding-up file loading. Current Xcode QL generator for OBJ models seems to be much faster in many cases.

 

3. Texture access in sandboxed environment - tricky but some workarounds could be found.

 

 

Best regards

 

Share this post


Link to post
Share on other sites
Advertisement
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!