Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

CGBuffer.h

Go to the documentation of this file.
00001 /*
00002 
00003 Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
00004                 ("Apple") in consideration of your agreement to the following terms, and your
00005                 use, installation, modification or redistribution of this Apple software
00006                 constitutes acceptance of these terms.  If you do not agree with these terms,
00007                 please do not use, install, modify or redistribute this Apple software.
00008 
00009                 In consideration of your agreement to abide by the following terms, and subject
00010                 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
00011                 copyrights in this original Apple software (the "Apple Software"), to use,
00012                 reproduce, modify and redistribute the Apple Software, with or without
00013                 modifications, in source and/or binary forms; provided that if you redistribute
00014                 the Apple Software in its entirety and without modifications, you must retain
00015                 this notice and the following text and disclaimers in all such redistributions of
00016                 the Apple Software.  Neither the name, trademarks, service marks or logos of
00017                 Apple Computer, Inc. may be used to endorse or promote products derived from the
00018                 Apple Software without specific prior written permission from Apple.  Except as
00019                 expressly stated in this notice, no other rights or licenses, express or implied,
00020                 are granted by Apple herein, including but not limited to any patent rights that
00021                 may be infringed by your derivative works or by other works in which the Apple
00022                 Software may be incorporated.
00023 
00024                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
00025                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
00026                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00027                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
00028                 COMBINATION WITH YOUR PRODUCTS.
00029 
00030                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
00031                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00032                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00033                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
00034                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
00035                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
00036                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00037 
00038 */
00039 
00040 // Note that this is modified Apple source code, and not in its entireity (some classes are, some aren't), 
00041 // but we might as well leave it in here, even though it doesn't sound like we have to.
00042 // -bob
00043 
00044 #include <mach/mach.h>
00045 #include <Carbon/Carbon.h>
00046 // Celestia's DPRINTF is different than Carbon's
00047 #undef DPRINTF
00048 #include <celutil/debug.h>
00049 
00050 class CGFrame : public CGRect
00051 {
00052 public:
00053 
00054         CGFrame(float x0, float y0, float w, float h)
00055         {
00056                 *this = CGRectMake(x0,y0,w,h);
00057         }
00058         
00059         explicit CGFrame(float w = 0, float h = 0)
00060         {
00061                 *this = CGRectMake(0,0,w,h);
00062         }
00063         
00064         CGFrame(const Rect& rect)
00065         {
00066                 origin.x = rect.left, size.width = rect.right - rect.left;
00067                 origin.y = rect.top, size.height = rect.bottom - rect.top;
00068         }
00069         
00070         CGFrame(const CGRect& copy)
00071         {
00072                 origin = copy.origin;
00073                 size = copy.size;
00074         }
00075         
00076         CGFrame(const CGSize& size)
00077         {
00078                 origin.x = origin.y = 0;
00079                 this->size = size;
00080         }
00081         
00082         CGFrame(float x, float y, const CGSize& size)
00083         {
00084                 *this = CGRectMake(x, y, size.width, size.height);
00085         }
00086         
00087         CGFrame(const CGPoint& pos, const CGSize& size)
00088         {
00089                 *this = CGRectMake(pos.x, pos.y, size.width, size.height);
00090         }       
00091         
00092         void Offset(float dx, float dy)
00093         {
00094                 origin.x += dx, origin.y += dy;
00095         }
00096         
00097         void Inset(float dx, float dy)
00098         {
00099                 origin.x += dx, origin.y += dy;
00100                 size.width -= dx*2, size.height -= dy*2;
00101         }
00102 };
00103 
00104 class MemoryBuffer
00105 {
00106   size_t size;
00107   int ref_count;
00108 
00109   MemoryBuffer(char* const data, size_t size) : size(size), ref_count(1), data(data)
00110   {
00111   }
00112 
00113   ~MemoryBuffer()
00114   {
00115     vm_deallocate((vm_map_t) mach_task_self(), (vm_address_t) data, size);
00116   }
00117 
00118 public:
00119 
00120   friend class _MemoryBuffer; // to shut the compiler up
00121 
00122   char* const data;
00123 
00124   MemoryBuffer* Retain()
00125   {
00126     ++ref_count;
00127     return this;
00128   }
00129 
00130   void Release()
00131   {
00132     if (--ref_count == 0)
00133       delete this;
00134   }
00135 
00136   static MemoryBuffer* Create(size_t size)
00137   {
00138     char* data;
00139     kern_return_t err = vm_allocate((vm_map_t) mach_task_self(), (vm_address_t*) &data, size, TRUE);
00140 
00141     return (err == KERN_SUCCESS) ? new MemoryBuffer(data, size) : NULL;
00142   }
00143 };
00144 
00145 class Datafile
00146 {
00147     int ref_count;
00148     FILE* file;
00149     
00150 public:        
00151     MemoryBuffer* data_buffer;
00152     unsigned long data_size;
00153 
00154     Datafile() : ref_count(1), file(NULL), data_buffer(NULL), data_size(0)
00155     {
00156     }
00157 
00158     ~Datafile()
00159     {
00160         Reset();
00161     }
00162 
00163     Datafile* Retain()
00164     {
00165         ++ref_count;
00166         return this;
00167     }
00168     
00169     void Release()
00170     {
00171         if (--ref_count==0) 
00172             delete this;
00173     }
00174     
00175     int Open(const char* path)
00176     {
00177         file = fopen(path,"r");
00178         if (!file) {
00179             DPRINTF(0,"Datafile::Open() - Couldn't open %s\n", path);
00180             Reset();
00181             return 0;
00182         }
00183         fseek(file, 0, SEEK_END);
00184         data_size = ftell(file);
00185         data_buffer = MemoryBuffer::Create(data_size);
00186         if (!data_buffer) {
00187             DPRINTF(0,"Datafile::Open() - Couldn't allocate MemoryBuffer of size %d\n", data_size);
00188             Reset();
00189             return 0;
00190         }
00191         //DPRINTF(0,"Datafile::Open() - Successfully opened '%s' %d bytes\n", path, data_size);
00192         return 1;
00193     }
00194     
00195     int Read()
00196     {
00197         if ((file == NULL) || (data_buffer == NULL) || (data_size == 0)) {
00198             DPRINTF(0,"Datafile::Read() - No file open, file of zero size, or no valid MemoryBuffer\n");
00199             Reset();
00200             return 0;
00201         }
00202         
00203         fseek(file, 0, SEEK_SET);        
00204         if (fread((void*)data_buffer->data, 1, data_size, file) != data_size) {
00205             DPRINTF(0,"Datafile::Read() - Didn't read to finish?");
00206             Reset();
00207             return 0;
00208         }
00209         
00210         //DPRINTF(0,"Datafile::Read() - Successfully read all %d bytes into buffer\n",data_size);
00211         return 1;
00212     }
00213     
00214     void Close()
00215     {
00216         if (file) {
00217             fclose(file);
00218             file = NULL;
00219         }
00220     }
00221     
00222     void Reset()
00223     {
00224         Close();
00225         if (data_buffer) {
00226             data_buffer->Release();
00227             data_buffer = NULL;
00228         }
00229     }
00230 };
00231 
00232 class CGBuffer
00233 {
00234         Datafile file;
00235         CGImageRef image_ref;
00236         CGContextRef context_ref;
00237 
00238         int ref_count;
00239 
00240         void Init()
00241         {
00242                 ref_count = 1;
00243                 buffer = NULL;
00244                 image_ref = NULL;
00245                 context_ref = NULL;
00246                 image_finished = false;
00247         }
00248 
00249         bool CreateCGContext()
00250         {
00251                 if (context_ref)
00252                 {
00253                         CGContextRelease(context_ref);
00254                         context_ref = NULL;
00255                 }
00256 
00257                 if (buffer)
00258                 {
00259                         buffer->Release();
00260                         buffer = NULL;
00261                 }
00262 
00263                 size_t buffer_rowbytes = (size_t)(image_size.width * ((image_depth == 8) ? 1 : 4)); //CGImageGetBytesPerRow(image_ref);
00264         
00265                 buffer = MemoryBuffer::Create(buffer_rowbytes * (size_t)image_size.height); 
00266 
00267                 if (!buffer)
00268                         return false;
00269 
00270                 CGColorSpaceRef colorspace_ref = (image_depth == 8) ? CGColorSpaceCreateDeviceGray() : CGColorSpaceCreateDeviceRGB();
00271                 
00272                 if (!colorspace_ref)
00273                         return false;
00274                 
00275                 CGImageAlphaInfo alpha_info = (image_depth == 8) ? kCGImageAlphaNone : kCGImageAlphaPremultipliedLast; //kCGImageAlphaLast; //RGBA format
00276 
00277                 context_ref = CGBitmapContextCreate(buffer->data, (size_t)image_size.width, (size_t)image_size.height, 8, buffer_rowbytes, colorspace_ref, alpha_info);
00278 
00279                 if (context_ref)
00280                 {
00281                         CGContextSetFillColorSpace(context_ref, colorspace_ref);
00282                         CGContextSetStrokeColorSpace(context_ref, colorspace_ref);
00283                         // move down, and flip vertically 
00284                         // to turn postscript style coordinates to "screen style"
00285                         CGContextTranslateCTM(context_ref, 0.0, image_size.height);
00286                         CGContextScaleCTM(context_ref, 1.0, -1.0);
00287                 }
00288                 
00289                 CGColorSpaceRelease(colorspace_ref);
00290                 colorspace_ref = NULL;
00291 
00292                 return !!context_ref;
00293         }
00294 
00295         void RenderCGImage(const CGRect& dst_rect)
00296         {
00297                 if (!context_ref || !image_ref)
00298                         return;
00299                         
00300                 CGContextDrawImage(context_ref, dst_rect, image_ref);
00301         }
00302         
00303 public:
00304 
00305         MemoryBuffer* buffer;
00306         CGSize image_size;
00307         size_t image_depth;
00308         bool image_finished;
00309         
00310         CGBuffer(const char* path)
00311         {
00312                 Init();
00313                 Open(path);
00314         }
00315 
00316         ~CGBuffer()
00317         {
00318                 Reset();
00319         }
00320 
00321         CGBuffer* Retain()
00322         {
00323                 ++ref_count;
00324                 return this;
00325         }
00326 
00327         void Release()
00328         {
00329                 if (--ref_count == 0)
00330                         delete this;
00331         }
00332 
00333         bool Open(const char* path)
00334         {
00335                 file.Reset();
00336                 return file.Open(path);
00337         }
00338 
00339         bool LoadJPEG()
00340         {
00341                 if (!file.Read())
00342                         return false;
00343 
00344                 file.Close();
00345 
00346                 CGDataProviderRef src_provider_ref = CGDataProviderCreateWithData(this, file.data_buffer->data, file.data_size, NULL);
00347 
00348                 if (!src_provider_ref)
00349                         return false;
00350 
00351                 image_ref = CGImageCreateWithJPEGDataProvider(src_provider_ref, NULL, true, kCGRenderingIntentDefault);
00352 
00353                 CGDataProviderRelease(src_provider_ref);
00354                 src_provider_ref = NULL;
00355 
00356                 if (!image_ref)
00357                         return false;
00358 
00359                 image_size = CGSizeMake(CGImageGetWidth(image_ref), CGImageGetHeight(image_ref));
00360                 image_depth = CGImageGetBitsPerPixel(image_ref);
00361                 
00362                 return !!image_ref;
00363         }
00364 
00365         bool Render()
00366         {
00367                 if (!image_ref)
00368                         return false;
00369                 
00370                 if (!CreateCGContext())
00371                         return false;
00372         
00373                 RenderCGImage(CGFrame(image_size));
00374                 
00375                 CGContextRelease(context_ref);
00376                 context_ref = NULL;
00377 
00378                 CGImageRelease(image_ref);
00379                 image_ref = NULL;
00380                 
00381                 file.Reset();
00382 
00383                 return true;
00384         }
00385         
00386         void Reset()
00387         {
00388                 if (buffer)
00389                 {
00390                         buffer->Release();
00391                         buffer = NULL;
00392                 }
00393 
00394                 if (image_ref)
00395                 {
00396                         CGImageRelease(image_ref);
00397                         image_ref = NULL;
00398                 }
00399                 
00400                 if (context_ref)
00401                 {
00402                         CGContextRelease(context_ref);
00403                         context_ref = NULL;
00404                 }
00405         }
00406 };

Generated on Sat Jan 14 22:30:26 2006 for Celestia by  doxygen 1.4.1