Merge pull request #289 from eligovision/OpenSceneGraph-3.4_apple
IMAGEIO plugin tweak
This commit is contained in:
commit
c1585d3c17
@ -45,8 +45,10 @@
|
|||||||
typedef char GLchar;
|
typedef char GLchar;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(GL_VERSION_2_0)
|
#ifndef GL_VERTEX_PROGRAM_POINT_SIZE
|
||||||
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
|
#define GL_VERTEX_PROGRAM_POINT_SIZE 0x8642
|
||||||
|
#endif
|
||||||
|
#ifndef GL_VERTEX_PROGRAM_TWO_SIDE
|
||||||
#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
|
#define GL_VERTEX_PROGRAM_TWO_SIDE 0x8643
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
// Used because CGDataProviderCreate became deprecated in 10.5
|
// Used because CGDataProviderCreate became deprecated in 10.5
|
||||||
#include <AvailabilityMacros.h>
|
#include <AvailabilityMacros.h>
|
||||||
|
|
||||||
|
#include <osg/Config>
|
||||||
#include <osg/GL>
|
#include <osg/GL>
|
||||||
#include <osg/Notify>
|
#include <osg/Notify>
|
||||||
#include <osg/Image>
|
#include <osg/Image>
|
||||||
@ -252,183 +252,222 @@ CGImageRef CreateCGImageFromFile(const char* the_path)
|
|||||||
return image_ref;
|
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 */
|
/* 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)
|
osg::Image* CreateOSGImageFromCGImage(CGImageRef image_ref)
|
||||||
{
|
{
|
||||||
/* This code is adapted from Apple's Documentation found here:
|
size_t src_width = CGImageGetWidth(image_ref);
|
||||||
* http://developer.apple.com/documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/index.html
|
size_t src_height = CGImageGetHeight(image_ref);
|
||||||
* Listing 9-4Using a Quartz image as a texture source.
|
size_t src_bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
|
||||||
* Unfortunately, this guide doesn't show what to do about
|
size_t src_bytes_per_row = CGImageGetBytesPerRow(image_ref);
|
||||||
* non-RGBA image formats so I'm making the rest up
|
size_t src_bits_per_component = CGImageGetBitsPerComponent(image_ref);
|
||||||
* (and it's probably all wrong).
|
CGImageAlphaInfo src_alpha_info = CGImageGetAlphaInfo(image_ref);
|
||||||
*/
|
// CGBitmapInfo src_bitmap_info = CGImageGetBitmapInfo(image_ref);
|
||||||
|
|
||||||
size_t the_width = CGImageGetWidth(image_ref);
|
CFDataRef rawData = CGDataProviderCopyData(CGImageGetDataProvider(image_ref));
|
||||||
size_t the_height = CGImageGetHeight(image_ref);
|
const UInt8* src_data = CFDataGetBytePtr(rawData);
|
||||||
CGRect the_rect = {{0.0f, 0.0f}, {static_cast<CGFloat>(the_width), static_cast<CGFloat>(the_height)}};
|
|
||||||
|
|
||||||
size_t bits_per_pixel = CGImageGetBitsPerPixel(image_ref);
|
size_t channels = src_bits_per_pixel/src_bits_per_component;
|
||||||
size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
|
uint8_t* image_data = new uint8_t[int(src_width*src_height*channels*(src_bits_per_component/8.0))];
|
||||||
// size_t bits_per_component = CGImageGetBitsPerComponent(image_ref);
|
|
||||||
size_t bits_per_component = 8;
|
|
||||||
|
|
||||||
CGImageAlphaInfo alpha_info = CGImageGetAlphaInfo(image_ref);
|
size_t stride = src_bytes_per_row*(8.0/src_bits_per_component);
|
||||||
|
|
||||||
GLint internal_format;
|
// Suppose 4 channels
|
||||||
GLenum pixel_format;
|
GLenum type = GL_UNSIGNED_BYTE;
|
||||||
GLenum data_type;
|
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);
|
if (channels == 3)
|
||||||
|
{
|
||||||
CGColorSpaceRef color_space;
|
internal_format = GL_RGB;
|
||||||
CGBitmapInfo bitmap_info = CGImageGetBitmapInfo(image_ref);
|
pixel_format = GL_BGR;
|
||||||
|
}
|
||||||
switch(bits_per_pixel)
|
else if (channels == 2)
|
||||||
{
|
{
|
||||||
// Drat, if 8-bit, how do you distinguish
|
#if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE)
|
||||||
// between a 256 color GIF, a LUMINANCE map
|
internal_format = GL_RG; // GL_RG8
|
||||||
// or an ALPHA map?
|
pixel_format = GL_RG;
|
||||||
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 */
|
|
||||||
#else
|
#else
|
||||||
bitmap_info = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Little; /* XRGB Little Endian */
|
internal_format = GL_LUMINANCE_ALPHA;
|
||||||
|
pixel_format = GL_LUMINANCE_ALPHA;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else
|
else if (channels == 1)
|
||||||
{
|
{
|
||||||
internal_format = GL_ALPHA;
|
#if defined(OSG_GL3_AVAILABLE) && !defined(OSG_GL2_AVAILABLE) && !defined(OSG_GL1_AVAILABLE)
|
||||||
pixel_format = GL_ALPHA;
|
internal_format = GL_RED; // GL_R8
|
||||||
data_type = GL_UNSIGNED_BYTE;
|
pixel_format = GL_RED;
|
||||||
// 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
|
#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
|
#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;
|
#if OSG_GLES2_FEATURES
|
||||||
pixel_format = GL_BGRA_EXT;
|
pixel_format = internal_format; // Needed by spec
|
||||||
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 */
|
|
||||||
#endif
|
#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
|
CFRelease(rawData);
|
||||||
CGContextRef bitmap_context = CGBitmapContextCreate(
|
|
||||||
image_data,
|
|
||||||
the_width,
|
|
||||||
the_height,
|
|
||||||
bits_per_component,
|
|
||||||
bytes_per_row,
|
|
||||||
color_space,
|
|
||||||
bitmap_info
|
|
||||||
);
|
|
||||||
|
|
||||||
CGContextTranslateCTM(bitmap_context, 0, the_height);
|
if (!readSuccess)
|
||||||
CGContextScaleCTM(bitmap_context, 1.0, -1.0);
|
{
|
||||||
// Draws the image into the context's image_data
|
OSG_WARN << "Can't load image (via imageio plugin): Unsupported number of channels";
|
||||||
CGContextDrawImage(bitmap_context, the_rect, image_ref);
|
delete[] image_data;
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
|
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) *****
|
***** End Support functions for reading (stream and file) *****
|
||||||
|
Loading…
Reference in New Issue
Block a user