From 565d2e1389b0a72e6eca7068988a9312991abfb1 Mon Sep 17 00:00:00 2001
From: elektrahesse
Date: Sat, 9 Oct 2010 19:05:40 +0200
Subject: Mac Only: Implemented initial CoreGraphics image decoding to support
 uploads, both single and bulk, bypassing viewer's internal decoding classes
 and using osx native frameworks. Also pushing non-fully-working-yet (and thus
 disabled) code for native j2c decoding.

---
 linden/indra/llcommon/stdtypes.h                 |   9 +-
 linden/indra/llimagej2coj/CMakeLists.txt         |  19 ++-
 linden/indra/llimagej2coj/llimagej2cquartz.h     |   9 ++
 linden/indra/llimagej2coj/llimagej2cquartz.mm    | 147 +++++++++++++++++++++++
 linden/indra/llwindow/llwindowmacosx-objc.h      |  10 ++
 linden/indra/llwindow/llwindowmacosx-objc.mm     |  60 +++++++++
 linden/indra/newview/floaterlocalassetbrowse.cpp |  11 ++
 linden/indra/newview/llfloaterimagepreview.cpp   |  12 +-
 linden/indra/newview/llviewerimagelist.cpp       |  11 +-
 9 files changed, 282 insertions(+), 6 deletions(-)
 create mode 100644 linden/indra/llimagej2coj/llimagej2cquartz.h
 create mode 100644 linden/indra/llimagej2coj/llimagej2cquartz.mm

(limited to 'linden')

diff --git a/linden/indra/llcommon/stdtypes.h b/linden/indra/llcommon/stdtypes.h
index af0b4dd..aed1e46 100644
--- a/linden/indra/llcommon/stdtypes.h
+++ b/linden/indra/llcommon/stdtypes.h
@@ -64,10 +64,17 @@ typedef long long unsigned int		U64;
 #endif
 #endif
 
+#ifdef LL_DARWIN
+	#ifndef BOOL
+		#define BOOL S32
+	#endif
+#else
+	typedef S32				BOOL;
+#endif
+
 typedef float				F32;
 typedef double				F64;
 
-typedef S32				BOOL;
 typedef U8				KEY;
 typedef U32				MASK;
 typedef U32             		TPACKETID;
diff --git a/linden/indra/llimagej2coj/CMakeLists.txt b/linden/indra/llimagej2coj/CMakeLists.txt
index 97d22cf..30f73ab 100644
--- a/linden/indra/llimagej2coj/CMakeLists.txt
+++ b/linden/indra/llimagej2coj/CMakeLists.txt
@@ -19,10 +19,26 @@ set(llimagej2coj_SOURCE_FILES
 
 set(llimagej2coj_HEADER_FILES
     CMakeLists.txt
-
     llimagej2coj.h
     )
 
+set(COREIMAGE_LIBRARIES)
+
+if (DARWIN)
+  list(APPEND llimagej2coj_SOURCE_FILES
+    llimagej2cquartz.mm
+    )
+  list(APPEND llimagej2coj_HEADER_FILES
+    llimagej2cquartz.h
+    )
+	
+	find_library(QUARTZCORE_LIBRARY QuartzCore)
+	find_library(ACCELERATE_LIBRARY Accelerate)
+
+	list(APPEND COREIMAGE_LIBRARIES ${QUARTZCORE_LIBRARY})
+	list(APPEND COREIMAGE_LIBRARIES	${ACCELERATE_LIBRARY})
+endif (DARWIN)
+
 set_source_files_properties(${llimagej2coj_HEADER_FILES}
                             PROPERTIES HEADER_FILE_ONLY TRUE)
 
@@ -32,4 +48,5 @@ add_library (llimagej2coj ${llimagej2coj_SOURCE_FILES})
 target_link_libraries(
     llimagej2coj
     ${OPENJPEG_LIBRARIES}
+	${COREIMAGE_LIBRARIES}
     )
diff --git a/linden/indra/llimagej2coj/llimagej2cquartz.h b/linden/indra/llimagej2coj/llimagej2cquartz.h
new file mode 100644
index 0000000..ba11bfd
--- /dev/null
+++ b/linden/indra/llimagej2coj/llimagej2cquartz.h
@@ -0,0 +1,9 @@
+#include "llimagej2c.h"
+
+#ifdef __OBJC__
+	#ifdef BOOL
+		#undef BOOL
+	#endif
+#endif // __OBJC__
+
+BOOL decodeJ2CQuartz(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count);
\ No newline at end of file
diff --git a/linden/indra/llimagej2coj/llimagej2cquartz.mm b/linden/indra/llimagej2coj/llimagej2cquartz.mm
new file mode 100644
index 0000000..d5eefd1
--- /dev/null
+++ b/linden/indra/llimagej2coj/llimagej2cquartz.mm
@@ -0,0 +1,147 @@
+#import <Accelerate/Accelerate.h>
+#import <QuartzCore/QuartzCore.h>
+#import <Quartz/Quartz.h>
+
+#include "llimagej2cquartz.h"
+
+#if defined(__BIG_ENDIAN__)
+	CGImageAlphaInfo const kDefaultAlphaLocation = kCGImageAlphaPremultipliedLast;
+#else
+	CGImageAlphaInfo const kDefaultAlphaLocation = kCGImageAlphaPremultipliedFirst;
+#endif
+
+BOOL decodeJ2CQuartz(LLImageJ2C &base, LLImageRaw &raw_image, F32 decode_time, S32 first_channel, S32 max_channel_count)
+{
+	U8 *srcData = (U8*)base.getData();
+	int srcLen = base.getDataSize();
+
+	llinfos << "[1] compressed image size: '" << srcLen << "'" << llendl;
+
+	int width = base.getWidth();
+	int height = base.getHeight();
+	int components = base.getComponents();
+
+	S32 channels = components - first_channel;
+	if( channels > max_channel_count )
+		channels = max_channel_count;
+
+	llinfos << "[2] components: '" << components << "' - channels: '" << channels << "' - first_channel: '" << first_channel << "' - max_channel_count: '" << max_channel_count << "'" << llendl;
+
+	if(components <= first_channel || components > 4)
+		return FALSE;
+
+	llinfos << "[3] attempting to decode a texture: '" << width << "'X'" << height << "'@'" << components * 8 << "'" << llendl;
+
+	U8 *tgt = (U8*)raw_image.getData();
+	if (!tgt)
+		return FALSE;
+
+	raw_image.resize(width, height, channels);
+
+	size_t rowBytes = width * components;
+	int realLen = width * height * components;
+
+	llinfos << "[4] allocating buffer of size: '" << realLen << "' to hold temp texture data" << llendl;
+	unsigned char* dataplane;
+
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+	NSBitmapImageRep *rep = [NSBitmapImageRep alloc];
+
+	switch (components)
+	{
+		case 1:
+		{
+			rep = [[rep
+				   initWithBitmapDataPlanes:nil
+				   pixelsWide:width
+				   pixelsHigh:height
+				   bitsPerSample:8
+				   samplesPerPixel:1
+				   hasAlpha:NO
+				   isPlanar:NO
+				   colorSpaceName:NSDeviceWhiteColorSpace
+				   bytesPerRow:rowBytes
+				   bitsPerPixel:8
+				   ] autorelease];
+
+			memcpy([rep bitmapData], srcData, srcLen);
+
+			dataplane = (unsigned char*)malloc(realLen);
+			memcpy(dataplane, [rep bitmapData], realLen);
+
+			[rep release];
+		}
+		break;
+
+		case 3:
+		{
+			NSData *data = [NSData dataWithBytes:srcData length:srcLen];
+			rep = [rep initWithData:data];
+
+			dataplane = (unsigned char*)malloc(realLen);
+			memcpy(dataplane, [rep bitmapData], realLen);
+
+			[data release];
+			[rep release];
+		}
+		break;
+
+		case 4:
+		{
+			NSData *data = [NSData dataWithBytes:srcData length:srcLen];
+			rep = [rep initWithData:data];
+
+			int imgLen = [rep pixelsHigh] * [rep bytesPerRow];
+			if (imgLen != realLen)
+			{
+				llwarns << "decoded image buffer size (" << imgLen << ") != expected buffer size (" << realLen << ") !" << llendl;
+				[rep release];
+				[data release];
+				return FALSE;
+			}
+			
+			dataplane = (unsigned char*)malloc(realLen);
+			memcpy(dataplane, [rep bitmapData], realLen);
+
+			vImage_Buffer vb;
+			vb.data = dataplane;
+			vb.height = [rep pixelsHigh];
+			vb.width = [rep pixelsWide];
+			vb.rowBytes = [rep bytesPerRow];
+
+			llinfos << "Attempting Alpha Unpremultiplication" << llendl;
+			vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0);
+			llinfos << "Unpremultiplied Alpha" << llendl;
+
+			llwarns << "after decoding: " << [rep pixelsWide] << "'X'" << [rep pixelsHigh] << "'@'" << [rep bitsPerPixel] << "'" << llendl;
+
+			[rep release];
+			[data release];
+		}
+		break;
+	}
+
+	if (dataplane)
+	{
+		for (int h=height-1; h>=0; h--)
+		{
+			for (int w=0; w<rowBytes; w+=(first_channel + channels))
+			{
+				for (int c=first_channel; c<(first_channel + channels); c++)
+					memcpy(tgt++, &dataplane[h*rowBytes + w + c], sizeof(unsigned char));
+			}
+		}
+
+		free(dataplane);
+
+		llinfos << "[5] size of decoded image is: '" << width*height*channels << "'" << llendl;
+
+		return TRUE;
+	}
+	else
+	{
+		llwarns << "[5] cannot decode image !" << llendl;
+	}
+
+	return FALSE;
+}
diff --git a/linden/indra/llwindow/llwindowmacosx-objc.h b/linden/indra/llwindow/llwindowmacosx-objc.h
index 14cddaa..14c9c92 100644
--- a/linden/indra/llwindow/llwindowmacosx-objc.h
+++ b/linden/indra/llwindow/llwindowmacosx-objc.h
@@ -31,6 +31,14 @@
  * $/LicenseInfo$
  */
 
+#include "llimagej2c.h"
+#include <Carbon/Carbon.h>
+
+#ifdef __OBJC__
+#ifdef BOOL
+#undef BOOL
+#endif
+#endif // __OBJC__
 
 // This will actually hold an NSCursor*, but that type is only available in objective C.
 typedef void *CursorRef;
@@ -40,3 +48,5 @@ void setupCocoa();
 CursorRef createImageCursor(const char *fullpath, int hotspotX, int hotspotY);
 OSErr releaseImageCursor(CursorRef ref);
 OSErr setImageCursor(CursorRef ref);
+BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image);
+BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image);
diff --git a/linden/indra/llwindow/llwindowmacosx-objc.mm b/linden/indra/llwindow/llwindowmacosx-objc.mm
index bc47164..5f33764 100644
--- a/linden/indra/llwindow/llwindowmacosx-objc.mm
+++ b/linden/indra/llwindow/llwindowmacosx-objc.mm
@@ -32,6 +32,8 @@
  */
 
 #include <AppKit/AppKit.h>
+#include <Accelerate/Accelerate.h>
+#include <Quartz/Quartz.h>
 
 /*
  * These functions are broken out into a separate file because the
@@ -42,6 +44,64 @@
 
 #include "llwindowmacosx-objc.h"
 
+BOOL decodeImageQuartz(const UInt8* data, int len, LLImageRaw *raw_image)
+{
+	CFDataRef theData = CFDataCreate(kCFAllocatorDefault, data, len);
+	CGImageSourceRef srcRef = CGImageSourceCreateWithData(theData, NULL);
+	CGImageRef image_ref = CGImageSourceCreateImageAtIndex(srcRef, 0, NULL);
+
+	size_t width = CGImageGetWidth(image_ref);
+	size_t height = CGImageGetHeight(image_ref);
+	size_t comps = CGImageGetBitsPerPixel(image_ref) / 8;
+	size_t bytes_per_row = CGImageGetBytesPerRow(image_ref);
+	CFDataRef result = CGDataProviderCopyData(CGImageGetDataProvider(image_ref));
+	UInt8* bitmap = (UInt8*)CFDataGetBytePtr(result);
+
+	CGImageAlphaInfo format = CGImageGetAlphaInfo(image_ref);
+	if (format & kCGImageAlphaPremultipliedFirst)
+	{
+		vImage_Buffer vb;
+		vb.data = bitmap;
+		vb.height = height;
+		vb.width = width;
+		vb.rowBytes = bytes_per_row;
+		llinfos << "Unpremultiplying ARGB888" << llendl;
+		vImageUnpremultiplyData_ARGB8888(&vb, &vb, 0);
+	}
+	else if (format & kCGImageAlphaPremultipliedLast)
+	{
+		vImage_Buffer vb;
+		vb.data = bitmap;
+		vb.height = height;
+		vb.width = width;
+		vb.rowBytes = bytes_per_row;
+		llinfos << "Unpremultiplying RGBA888" << llendl;
+		vImageUnpremultiplyData_RGBA8888(&vb, &vb, 0);
+	}
+
+	raw_image->resize(width, height, comps);
+	llinfos << "Decoding an image of width: " << width << " and height: " << height << " and components: " << comps << llendl;
+	memcpy(raw_image->getData(), bitmap, height * bytes_per_row);
+	raw_image->verticalFlip();
+
+	CFRelease(theData);
+	CFRelease(srcRef);
+	CGImageRelease(image_ref);
+	CFRelease(result);
+
+	return TRUE;
+}
+
+BOOL decodeImageQuartz(std::string filename, LLImageRaw *raw_image)
+{
+	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+	NSURL *url = [[NSURL alloc] initFileURLWithPath:[NSString stringWithCString:filename.c_str()]];
+	NSData *data = [NSData dataWithContentsOfURL:url];
+	BOOL result = decodeImageQuartz((UInt8*)[data bytes], [data length], raw_image);
+	[pool release];
+	return result;
+}
+
 void setupCocoa()
 {
 	static bool inited = false;
diff --git a/linden/indra/newview/floaterlocalassetbrowse.cpp b/linden/indra/newview/floaterlocalassetbrowse.cpp
index 6564528..443b5bf 100644
--- a/linden/indra/newview/floaterlocalassetbrowse.cpp
+++ b/linden/indra/newview/floaterlocalassetbrowse.cpp
@@ -74,6 +74,9 @@ this feature is still a work in progress.
 #include "llvovolume.h"
 #include "llface.h"
 
+#ifdef LL_DARWIN
+#include "llwindowmacosx-objc.h"
+#endif
 
 /*=======================================*/
 /*     Instantiating manager class       */
@@ -227,6 +230,13 @@ void LocalBitmap::updateSelf()
 
 bool LocalBitmap::decodeSelf(LLImageRaw* rawimg)
 {
+#ifdef LL_DARWIN
+	if (decodeImageQuartz(filename, rawimg))
+	{
+		rawimg->biasedScaleToPowerOfTwo( LLViewerImage::MAX_IMAGE_SIZE_DEFAULT );
+		return true;
+	}
+#else
 	switch (this->extension)
 	{
 		case IMG_EXTEN_BMP:
@@ -275,6 +285,7 @@ bool LocalBitmap::decodeSelf(LLImageRaw* rawimg)
 		default:
 			break;
 	}
+#endif
 	return false;
 }
 
diff --git a/linden/indra/newview/llfloaterimagepreview.cpp b/linden/indra/newview/llfloaterimagepreview.cpp
index 9827a31..c81081f 100644
--- a/linden/indra/newview/llfloaterimagepreview.cpp
+++ b/linden/indra/newview/llfloaterimagepreview.cpp
@@ -62,6 +62,10 @@
 
 #include "hippoGridManager.h"
 
+#ifdef LL_DARWIN
+#include "llwindowmacosx-objc.h"
+#endif
+
 //static
 S32 LLFloaterImagePreview::sUploadAmount = 10;
 
@@ -353,7 +357,10 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
 	}
 
 	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-
+#ifdef LL_DARWIN
+	if (! decodeImageQuartz(src_filename, raw_image))
+		return false;
+#else
 	switch (codec)
 	{
 	case IMG_CODEC_BMP:
@@ -428,8 +435,9 @@ bool LLFloaterImagePreview::loadImage(const std::string& src_filename)
 	}
 
 	raw_image->biasedScaleToPowerOfTwo(1024);
+#endif
+
 	mRawImagep = raw_image;
-	
 	return true;
 }
 
diff --git a/linden/indra/newview/llviewerimagelist.cpp b/linden/indra/newview/llviewerimagelist.cpp
index cb02b09..869c9d7 100644
--- a/linden/indra/newview/llviewerimagelist.cpp
+++ b/linden/indra/newview/llviewerimagelist.cpp
@@ -65,6 +65,10 @@
 
 #include <sys/stat.h>
 
+#ifdef LL_DARWIN
+#include "llwindowmacosx-objc.h"
+#endif
+
 ////////////////////////////////////////////////////////////////////////////
 
 void (*LLViewerImageList::sUUIDCallback)(void **, const LLUUID&) = NULL;
@@ -920,7 +924,10 @@ BOOL LLViewerImageList::createUploadFile(const std::string& filename,
 {
 	// First, load the image.
 	LLPointer<LLImageRaw> raw_image = new LLImageRaw;
-	
+#ifdef LL_DARWIN
+	if (!decodeImageQuartz(filename, raw_image))
+		return FALSE;
+#else
 	switch (codec)
 	{
 		case IMG_CODEC_BMP:
@@ -993,7 +1000,7 @@ BOOL LLViewerImageList::createUploadFile(const std::string& filename,
 		default:
 			return FALSE;
 	}
-	
+#endif
 	LLPointer<LLImageJ2C> compressedImage = convertToUploadFile(raw_image);
 	
 	if( !compressedImage->save(out_filename) )
-- 
cgit v1.1