1 /* 2 3 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. 4 ("Apple") in consideration of your agreement to the following terms, and your 5 use, installation, modification or redistribution of this Apple software 6 constitutes acceptance of these terms. If you do not agree with these terms, 7 please do not use, install, modify or redistribute this Apple software. 8 9 In consideration of your agreement to abide by the following terms, and subject 10 to these terms, Apple grants you a personal, non-exclusive license, under Apple�s 11 copyrights in this original Apple software (the "Apple Software"), to use, 12 reproduce, modify and redistribute the Apple Software, with or without 13 modifications, in source and/or binary forms; provided that if you redistribute 14 the Apple Software in its entirety and without modifications, you must retain 15 this notice and the following text and disclaimers in all such redistributions of 16 the Apple Software. Neither the name, trademarks, service marks or logos of 17 Apple Computer, Inc. may be used to endorse or promote products derived from the 18 Apple Software without specific prior written permission from Apple. Except as 19 expressly stated in this notice, no other rights or licenses, express or implied, 20 are granted by Apple herein, including but not limited to any patent rights that 21 may be infringed by your derivative works or by other works in which the Apple 22 Software may be incorporated. 23 24 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO 25 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 26 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 28 COMBINATION WITH YOUR PRODUCTS. 29 30 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 31 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 32 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 34 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT 35 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 36 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 38 */ 39 40 // Note that this is modified Apple source code, and not in its entireity (some classes are, some aren't), 41 // but we might as well leave it in here, even though it doesn't sound like we have to. 42 // -bob 43 44 #include <mach/mach.h> 45 #include <Carbon/Carbon.h> 46 // Celestia's DPRINTF is different than Carbon's 47 #undef DPRINTF 48 #include <celutil/debug.h> 49 50 class CGFrame : public CGRect 51 { 52 public: 53 CGFrame(float x0,float y0,float w,float h)54 CGFrame(float x0, float y0, float w, float h) 55 { 56 *this = CGRectMake(x0,y0,w,h); 57 } 58 59 explicit CGFrame(float w = 0, float h = 0) 60 { 61 *this = CGRectMake(0,0,w,h); 62 } 63 CGFrame(const Rect & rect)64 CGFrame(const Rect& rect) 65 { 66 origin.x = rect.left, size.width = rect.right - rect.left; 67 origin.y = rect.top, size.height = rect.bottom - rect.top; 68 } 69 CGFrame(const CGRect & copy)70 CGFrame(const CGRect& copy) 71 { 72 origin = copy.origin; 73 size = copy.size; 74 } 75 CGFrame(const CGSize & size)76 CGFrame(const CGSize& size) 77 { 78 origin.x = origin.y = 0; 79 this->size = size; 80 } 81 CGFrame(float x,float y,const CGSize & size)82 CGFrame(float x, float y, const CGSize& size) 83 { 84 *this = CGRectMake(x, y, size.width, size.height); 85 } 86 CGFrame(const CGPoint & pos,const CGSize & size)87 CGFrame(const CGPoint& pos, const CGSize& size) 88 { 89 *this = CGRectMake(pos.x, pos.y, size.width, size.height); 90 } 91 Offset(float dx,float dy)92 void Offset(float dx, float dy) 93 { 94 origin.x += dx, origin.y += dy; 95 } 96 Inset(float dx,float dy)97 void Inset(float dx, float dy) 98 { 99 origin.x += dx, origin.y += dy; 100 size.width -= dx*2, size.height -= dy*2; 101 } 102 }; 103 104 class MemoryBuffer 105 { 106 size_t size; 107 int ref_count; 108 MemoryBuffer(char * const data,size_t size)109 MemoryBuffer(char* const data, size_t size) : size(size), ref_count(1), data(data) 110 { 111 } 112 ~MemoryBuffer()113 ~MemoryBuffer() 114 { 115 vm_deallocate((vm_map_t) mach_task_self(), (vm_address_t) data, size); 116 } 117 118 public: 119 120 friend class _MemoryBuffer; // to shut the compiler up 121 122 char* const data; 123 Retain()124 MemoryBuffer* Retain() 125 { 126 ++ref_count; 127 return this; 128 } 129 Release()130 void Release() 131 { 132 if (--ref_count == 0) 133 delete this; 134 } 135 Create(size_t size)136 static MemoryBuffer* Create(size_t size) 137 { 138 char* data; 139 kern_return_t err = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*) &data, size, TRUE); 140 141 return (err == KERN_SUCCESS) ? new MemoryBuffer(data, size) : NULL; 142 } 143 }; 144 145 class Datafile 146 { 147 int ref_count; 148 FILE* file; 149 150 public: 151 MemoryBuffer* data_buffer; 152 unsigned long data_size; 153 Datafile()154 Datafile() : ref_count(1), file(NULL), data_buffer(NULL), data_size(0) 155 { 156 } 157 ~Datafile()158 ~Datafile() 159 { 160 Reset(); 161 } 162 Retain()163 Datafile* Retain() 164 { 165 ++ref_count; 166 return this; 167 } 168 Release()169 void Release() 170 { 171 if (--ref_count==0) 172 delete this; 173 } 174 Open(const char * path)175 int Open(const char* path) 176 { 177 file = fopen(path,"r"); 178 if (!file) { 179 DPRINTF(0,"Datafile::Open() - Couldn't open %s\n", path); 180 Reset(); 181 return 0; 182 } 183 fseek(file, 0, SEEK_END); 184 data_size = ftell(file); 185 data_buffer = MemoryBuffer::Create(data_size); 186 if (!data_buffer) { 187 DPRINTF(0,"Datafile::Open() - Couldn't allocate MemoryBuffer of size %d\n", data_size); 188 Reset(); 189 return 0; 190 } 191 //DPRINTF(0,"Datafile::Open() - Successfully opened '%s' %d bytes\n", path, data_size); 192 return 1; 193 } 194 Read()195 int Read() 196 { 197 if ((file == NULL) || (data_buffer == NULL) || (data_size == 0)) { 198 DPRINTF(0,"Datafile::Read() - No file open, file of zero size, or no valid MemoryBuffer\n"); 199 Reset(); 200 return 0; 201 } 202 203 fseek(file, 0, SEEK_SET); 204 if (fread((void*)data_buffer->data, 1, data_size, file) != data_size) { 205 DPRINTF(0,"Datafile::Read() - Didn't read to finish?"); 206 Reset(); 207 return 0; 208 } 209 210 //DPRINTF(0,"Datafile::Read() - Successfully read all %d bytes into buffer\n",data_size); 211 return 1; 212 } 213 Close()214 void Close() 215 { 216 if (file) { 217 fclose(file); 218 file = NULL; 219 } 220 } 221 Reset()222 void Reset() 223 { 224 Close(); 225 if (data_buffer) { 226 data_buffer->Release(); 227 data_buffer = NULL; 228 } 229 } 230 }; 231 232 class CGBuffer 233 { 234 Datafile file; 235 CGImageRef image_ref; 236 CGContextRef context_ref; 237 238 int ref_count; 239 Init()240 void Init() 241 { 242 ref_count = 1; 243 buffer = NULL; 244 image_ref = NULL; 245 context_ref = NULL; 246 image_finished = false; 247 } 248 CreateCGContext()249 bool CreateCGContext() 250 { 251 if (context_ref) 252 { 253 CGContextRelease(context_ref); 254 context_ref = NULL; 255 } 256 257 if (buffer) 258 { 259 buffer->Release(); 260 buffer = NULL; 261 } 262 263 size_t buffer_rowbytes = (size_t)(image_size.width * ((image_depth == 8) ? 1 : 4)); //CGImageGetBytesPerRow(image_ref); 264 265 buffer = MemoryBuffer::Create(buffer_rowbytes * (size_t)image_size.height); 266 267 if (!buffer) 268 return false; 269 270 CGColorSpaceRef colorspace_ref = (image_depth == 8) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB(); 271 272 if (!colorspace_ref) 273 return false; 274 275 CGImageAlphaInfo alpha_info = (image_depth == 8) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast; //kCGImageAlphaLast; //RGBA format 276 277 context_ref = CGBitmapContextCreate(buffer->data, (size_t)image_size.width, (size_t)image_size.height, 8, buffer_rowbytes, colorspace_ref, alpha_info); 278 279 if (context_ref) 280 { 281 CGContextSetFillColorSpace(context_ref, colorspace_ref); 282 CGContextSetStrokeColorSpace(context_ref, colorspace_ref); 283 // move down, and flip vertically 284 // to turn postscript style coordinates to "screen style" 285 CGContextTranslateCTM(context_ref, 0.0, image_size.height); 286 CGContextScaleCTM(context_ref, 1.0, -1.0); 287 } 288 289 CGColorSpaceRelease(colorspace_ref); 290 colorspace_ref = NULL; 291 292 return !!context_ref; 293 } 294 RenderCGImage(const CGRect & dst_rect)295 void RenderCGImage(const CGRect& dst_rect) 296 { 297 if (!context_ref || !image_ref) 298 return; 299 300 CGContextDrawImage(context_ref, dst_rect, image_ref); 301 } 302 303 public: 304 305 MemoryBuffer* buffer; 306 CGSize image_size; 307 size_t image_depth; 308 bool image_finished; 309 CGBuffer(const char * path)310 CGBuffer(const char* path) 311 { 312 Init(); 313 Open(path); 314 } 315 ~CGBuffer()316 ~CGBuffer() 317 { 318 Reset(); 319 } 320 Retain()321 CGBuffer* Retain() 322 { 323 ++ref_count; 324 return this; 325 } 326 Release()327 void Release() 328 { 329 if (--ref_count == 0) 330 delete this; 331 } 332 Open(const char * path)333 bool Open(const char* path) 334 { 335 file.Reset(); 336 return file.Open(path); 337 } 338 LoadJPEG()339 bool LoadJPEG() 340 { 341 if (!file.Read()) 342 return false; 343 344 file.Close(); 345 346 CGDataProviderRef src_provider_ref = CGDataProviderCreateWithData(this, file.data_buffer->data, file.data_size, NULL); 347 348 if (!src_provider_ref) 349 return false; 350 351 image_ref = CGImageCreateWithJPEGDataProvider(src_provider_ref, NULL, true, kCGRenderingIntentDefault); 352 353 CGDataProviderRelease(src_provider_ref); 354 src_provider_ref = NULL; 355 356 if (!image_ref) 357 return false; 358 359 image_size = CGSizeMake(CGImageGetWidth(image_ref), CGImageGetHeight(image_ref)); 360 image_depth = CGImageGetBitsPerPixel(image_ref); 361 362 return !!image_ref; 363 } 364 Render()365 bool Render() 366 { 367 if (!image_ref) 368 return false; 369 370 if (!CreateCGContext()) 371 return false; 372 373 RenderCGImage(CGFrame(image_size)); 374 375 CGContextRelease(context_ref); 376 context_ref = NULL; 377 378 CGImageRelease(image_ref); 379 image_ref = NULL; 380 381 file.Reset(); 382 383 return true; 384 } 385 Reset()386 void Reset() 387 { 388 if (buffer) 389 { 390 buffer->Release(); 391 buffer = NULL; 392 } 393 394 if (image_ref) 395 { 396 CGImageRelease(image_ref); 397 image_ref = NULL; 398 } 399 400 if (context_ref) 401 { 402 CGContextRelease(context_ref); 403 context_ref = NULL; 404 } 405 } 406 };