Merge pull request #289 from eligovision/OpenSceneGraph-3.4_apple

IMAGEIO plugin tweak
This commit is contained in:
OpenSceneGraph git repository 2017-07-31 15:06:57 +01:00 committed by GitHub
commit c1585d3c17
2 changed files with 199 additions and 158 deletions

View File

@ -45,8 +45,10 @@
typedef char GLchar;
#endif
#if !defined(GL_VERSION_2_0)
#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
#endif
#ifndef GL_VERTEX_PROGRAM_TWO_SIDE
#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
#endif

View File

@ -35,7 +35,7 @@
// Used because CGDataProviderCreate became deprecated in 10.5
#include <AvailabilityMacros.h>
#include <osg/Config>
#include <osg/GL>
#include <osg/Notify>
#include <osg/Image>
@ -252,183 +252,222 @@ CGImageRef CreateCGImageFromFile(const char* the_path)
return image_ref;
}
namespace
{
template<typename T>
void consume4(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data)
{
T* dst_data_ptr = dst_data;
for (int y = height - 1; y >= 0; y--) // flip y
{
T* src_data_ptr = src_data + y*src_stride;
for (int x = 0; x < width; x++)
{
#if OSG_GLES2_FEATURES
*dst_data_ptr++ = *src_data_ptr++; // red
*dst_data_ptr++ = *src_data_ptr++; // green
*dst_data_ptr++ = *src_data_ptr++; // blue
#else
unsigned char r = *src_data_ptr++;
unsigned char g = *src_data_ptr++;
unsigned char b = *src_data_ptr++;
*dst_data_ptr++ = b; // blue
*dst_data_ptr++ = g; // green
*dst_data_ptr++ = r; // red
#endif
*dst_data_ptr++ = *src_data_ptr++; // alpha
}
}
}
template<typename T>
void consume3(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data)
{
T* dst_data_ptr = dst_data;
for (int y = height - 1; y >= 0; y--) // flip y
{
T* src_data_ptr = src_data + y*src_stride;
for (int x = 0; x < width; x++)
{
#if OSG_GLES2_FEATURES
*dst_data_ptr++ = *src_data_ptr++; // red
*dst_data_ptr++ = *src_data_ptr++; // green
*dst_data_ptr++ = *src_data_ptr++; // blue
#else
unsigned char r = *src_data_ptr++;
unsigned char g = *src_data_ptr++;
unsigned char b = *src_data_ptr++;
*dst_data_ptr++ = b; // blue
*dst_data_ptr++ = g; // green
*dst_data_ptr++ = r; // red
#endif
}
}
}
template<typename T>
void consume2(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data)
{
T* dst_data_ptr = dst_data;
for (int y = height - 1; y >= 0; y--) // flip y
{
T* src_data_ptr = src_data + y*src_stride;
for (int x = 0; x < width; x++)
{
*dst_data_ptr++ = *src_data_ptr++; // red (luminance)
*dst_data_ptr++ = *src_data_ptr++; // green (alpha)
}
}
}
template<typename T>
void consume1(size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data)
{
T* dst_data_ptr = dst_data;
for (int y = height - 1; y >= 0; y--) // flip y
{
T* src_data_ptr = src_data + y*src_stride;
for (int x = 0; x < width; x++)
*dst_data_ptr++ = *src_data_ptr++; // red
}
}
template<typename T>
bool consume(size_t channels, size_t width, size_t height, T* src_data, size_t src_stride, T* dst_data)
{
if (channels == 4)
{
consume4<T>(width, height, src_data, src_stride, dst_data);
return true;
}
else if (channels == 3)
{
consume3<T>(width, height, src_data, src_stride, dst_data);
return true;
}
else if (channels == 2)
{
consume2<T>(width, height, src_data, src_stride, dst_data);
return true;
}
else if (channels == 1)
{
consume1<T>(width, height, src_data, src_stride, dst_data);
return true;
}
return false;
}
}// anonymous namespace
/* Once we have our image (CGImageRef), we need to get it into an osg::Image */
// TODO: GL3 core profile
osg::Image* CreateOSGImageFromCGImage(CGImageRef image_ref)
{
/* This code is adapted from Apple's Documentation found here:
* http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
* Listing 9-4Using a Quartz image as a texture source.
* Unfortunately, this guide doesn't show what to do about
* non-RGBA image formats so I'm making the rest up
* (and it's probably all wrong).
*/
size_t src_width = CGImageGetWidth(image_ref);
size_t src_height = CGImageGetHeight(image_ref);
size_t src_bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
size_t src_bytes_per_row = CGImageGetBytesPerRow(image_ref);
size_t src_bits_per_component = CGImageGetBitsPerComponent(image_ref);
CGImageAlphaInfo src_alpha_info = CGImageGetAlphaInfo(image_ref);
// CGBitmapInfo src_bitmap_info = CGImageGetBitmapInfo(image_ref);
size_t the_width = CGImageGetWidth(image_ref);
size_t the_height = CGImageGetHeight(image_ref);
CGRect the_rect = {{0.0f, 0.0f}, {static_cast<CGFloat>(the_width), static_cast<CGFloat>(the_height)}};
CFDataRef rawData = CGDataProviderCopyData(CGImageGetDataProvider(image_ref));
const UInt8* src_data = CFDataGetBytePtr(rawData);
size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
// size_t bits_per_component = CGImageGetBitsPerComponent(image_ref);
size_t bits_per_component = 8;
size_t channels = src_bits_per_pixel/src_bits_per_component;
uint8_t* image_data = new uint8_t[int(src_width*src_height*channels*(src_bits_per_component/8.0))];
CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
size_t stride = src_bytes_per_row*(8.0/src_bits_per_component);
GLint internal_format;
GLenum pixel_format;
GLenum data_type;
// Suppose 4 channels
GLenum type = GL_UNSIGNED_BYTE;
GLint internal_format = GL_RGBA;
GLenum pixel_format = GL_BGRA; // Should be faster than RGBA on x86
void* image_data = calloc(the_width * 4, the_height);
CGColorSpaceRef color_space;
CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
switch(bits_per_pixel)
{
// Drat, if 8-bit, how do you distinguish
// between a 256 color GIF, a LUMINANCE map
// or an ALPHA map?
case 8:
{
// I probably did the formats all wrong for this case,
// especially the ALPHA case.
if(kCGImageAlphaNone == alpha_info)
{
/*
internal_format = GL_LUMINANCE;
pixel_format = GL_LUMINANCE;
*/
internal_format = GL_RGBA8;
pixel_format = GL_BGRA_EXT;
data_type = GL_UNSIGNED_INT_8_8_8_8_REV;
bytes_per_row = the_width*4;
// color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
color_space = CGColorSpaceCreateDeviceRGB();
// bitmap_info = kCGImageAlphaPremultipliedFirst;
#if __BIG_ENDIAN__
bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
if (channels == 3)
{
internal_format = GL_RGB;
pixel_format = GL_BGR;
}
else if (channels == 2)
{
#if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE)
internal_format = GL_RG; // GL_RG8
pixel_format = GL_RG;
#else
bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
internal_format = GL_LUMINANCE_ALPHA;
pixel_format = GL_LUMINANCE_ALPHA;
#endif
}
else
{
internal_format = GL_ALPHA;
pixel_format = GL_ALPHA;
data_type = GL_UNSIGNED_BYTE;
// bytes_per_row = the_width;
// color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericGray);
color_space = CGColorSpaceCreateDeviceGray();
}
break;
}
case 24:
{
internal_format = GL_RGBA8;
pixel_format = GL_BGRA_EXT;
data_type = GL_UNSIGNED_INT_8_8_8_8_REV;
bytes_per_row = the_width*4;
// color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
color_space = CGColorSpaceCreateDeviceRGB();
// bitmap_info = kCGImageAlphaNone;
#if __BIG_ENDIAN__
bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
}
else if (channels == 1)
{
#if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE)
internal_format = GL_RED; // GL_R8
pixel_format = GL_RED;
#else
bitmap_info = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
if (src_alpha_info == kCGImageAlphaOnly)
{
internal_format = GL_ALPHA;
pixel_format = GL_ALPHA;
}
else
{
internal_format = GL_LUMINANCE;
pixel_format = GL_LUMINANCE;
}
#endif
break;
}
//
// Tatsuhiro Nishioka
// 16 bpp grayscale (8 bit white and 8 bit alpha) causes invalid argument combination
// in CGBitmapContextCreate.
// I guess it is safer to handle 16 bit grayscale image as 32-bit RGBA image.
// It works at least on FlightGear
//
case 16:
case 32:
case 48:
case 64:
{
}
internal_format = GL_RGBA8;
pixel_format = GL_BGRA_EXT;
data_type = GL_UNSIGNED_INT_8_8_8_8_REV;
bytes_per_row = the_width*4;
// color_space = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
color_space = CGColorSpaceCreateDeviceRGB();
// bitmap_info = kCGImageAlphaPremultipliedFirst;
#if __BIG_ENDIAN__
bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big; /* XRGB Big Endian */
#else
bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
#if OSG_GLES2_FEATURES
pixel_format = internal_format; // Needed by spec
#endif
break;
}
default:
{
// OSG_WARN << "Unknown file type in " << fileName.c_str() << " with " << origDepth << std::endl;
return NULL;
break;
}
}
bool readSuccess = false;
if (src_bits_per_component == 8)
{
uint8_t* src_data_cast = (uint8_t*)(src_data);
uint8_t* dst_data = image_data;
readSuccess = consume<uint8_t>(channels, src_width, src_height, src_data_cast, stride, dst_data);
}
else if (src_bits_per_component == 16)
{
type = GL_UNSIGNED_SHORT;
uint16_t* src_data_cast = (uint16_t*)(src_data);
uint16_t* dst_data = (uint16_t*)image_data;
readSuccess = consume<uint16_t>(channels, src_width, src_height, src_data_cast, stride, dst_data);
}
else if (src_bits_per_component == 32)
{
type = GL_FLOAT;
float* src_data_cast = (float*)(src_data);
float* dst_data = (float*)image_data;
readSuccess = consume<float>(channels, src_width, src_height, src_data_cast, stride, dst_data);
}
// Sets up a context to be drawn to with image_data as the area to be drawn to
CGContextRef bitmap_context = CGBitmapContextCreate(
image_data,
the_width,
the_height,
bits_per_component,
bytes_per_row,
color_space,
bitmap_info
);
CFRelease(rawData);
CGContextTranslateCTM(bitmap_context, 0, the_height);
CGContextScaleCTM(bitmap_context, 1.0, -1.0);
// Draws the image into the context's image_data
CGContextDrawImage(bitmap_context, the_rect, image_ref);
CGContextRelease(bitmap_context);
if (!image_data)
return NULL;
// alpha is premultiplied with rgba, undo it
vImage_Buffer vb;
vb.data = image_data;
vb.height = the_height;
vb.width = the_width;
vb.rowBytes = the_width * 4;
vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0);
// changing it to GL_UNSIGNED_BYTE seems working, but I'm not sure if this is a right way.
//
data_type = GL_UNSIGNED_BYTE;
osg::Image* osg_image = new osg::Image;
osg_image->setImage(
the_width,
the_height,
1,
internal_format,
pixel_format,
data_type,
(unsigned char*)image_data,
osg::Image::USE_MALLOC_FREE // Assumption: osg_image takes ownership of image_data and will free
);
return osg_image;
if (!readSuccess)
{
OSG_WARN << "Can't load image (via imageio plugin): Unsupported number of channels";
delete[] image_data;
return NULL;
}
osg::Image* osg_image = new osg::Image;
osg_image->setImage(src_width, src_height, 1, internal_format, pixel_format,
type, image_data, osg::Image::USE_NEW_DELETE);
return osg_image;
}
/**************************************************************
***** End Support functions for reading (stream and file) *****