2 * psychlops_g_canvas_API_OSX.cpp
3 * Psychlops Standard Library (MacOSX)
5 * Last Modified 2005/12/24 by Kenchi HOSOKAWA
6 * (C) 2005 Kenchi HOSOKAWA, Kazushi MARUYA, Takao SATO
16 #import <Cocoa/Cocoa.h>
17 #include <ApplicationServices/ApplicationServices.h>
18 #include <CoreServices/CoreServices.h>
19 #include <mach/mach.h>
20 #include <mach/mach_time.h>
23 #include <OpenGL/OpenGL.h>
24 #include <OpenGL/gl.h>
26 #include "psychlops_g_API_OSX.h"
27 #include "psychlops_g_API_objc_osx.h"
28 #include "../../core/ApplicationInterfaces/psychlops_code_exception.h"
29 #include "../../core/graphic/psychlops_g_color.h"
30 #include "../../core/graphic/psychlops_g_image.h"
31 #include "../../core/graphic/psychlops_g_font.h"
32 #include "psychlops_io_display_OSX.h"
35 //#define __PSYCHLOPS__OSX_LION
39 APICanvasProperties::APICanvasProperties() : has_instance_(false), quartz_context_(NULL) {}
40 APICanvasProperties::~APICanvasProperties() {}
42 // Getting Display Settings : requires CGDirectDisplayID(the_display_), CFDictionaryRef(mode_)
43 WindowMetrix APICanvasProperties::getDisplayMetrix(CGDirectDisplayID target) {
45 tmp.width = CGDisplayPixelsWide( target );
46 tmp.height = CGDisplayPixelsHigh( target );
47 #if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_6
48 CGDisplayModeRef mode = CGDisplayCopyDisplayMode(target);
49 CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode);
50 if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
52 else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
54 else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
57 tmp.colordepth = CGDisplayBitsPerPixel( target );
59 tmp.refreshrate = 0.0;
61 CFNumberRef ref_refreshrate;
62 CFDictionaryRef mode_ = CGDisplayCurrentMode( target );
63 ref_refreshrate = (CFNumberRef) CFDictionaryGetValue(mode_, kCGDisplayRefreshRate);
65 CFNumberGetValue(ref_refreshrate, kCFNumberDoubleType, &(tmp.refreshrate));
66 if(tmp.refreshrate == 0.0) tmp.refreshrate = 60.0; // Assume LCD screen
71 // Hardware Gamma Settings : requires CGDirectDisplayID(target_display_)
72 void APICanvasProperties::setGammaValue(const double gamma_r, const double gamma_g, const double gamma_b) {
75 err = CGSetDisplayTransferByFormula( target_display_,
76 0.0, 1.0, (1.0/gamma_r),
77 0.0, 1.0, (1.0/gamma_g),
78 0.0, 1.0, (1.0/gamma_b));
79 // 0.0, 1.0, (1.0/gamma_r)*savedRedGamma_,
80 // 0.0, 1.0, (1.0/gamma_g)*savedGreenGamma_,
81 // 0.0, 1.0, (1.0/gamma_b)*savedBlueGamma_);
82 if(err!=kCGErrorSuccess) throw Exception(typeid(*this), "API ERROR", "Failed to set color calibration table for the video renderer.");
83 gamma_mode_ = Color::GAMMA_VALUE;
86 void APICanvasProperties::setGammaTable(const std::vector<double> &table_r, const std::vector<double> &table_g, const std::vector<double> &table_b) {
87 if(table_r.size()!=256 || table_g.size()!=256 || table_b.size()!=256)
88 throw Exception(typeid(*this), "Gamma Table Error", "Table size is out of order (not 256).");
89 int num_steps = table_r.size();
92 CGGammaValue *(table[3]);
93 for(int i=0; i<3; i++) table[i] = new CGGammaValue[num_steps];
94 for(int j=0; j<num_steps; j++) {
95 table[0][j] = (CGGammaValue)table_r[j];
96 table[1][j] = (CGGammaValue)table_g[j];
97 table[2][j] = (CGGammaValue)table_b[j];
99 err = CGSetDisplayTransferByTable(target_display_, num_steps, table[0], table[1], table[2]);
100 if(err!=kCGErrorSuccess) throw Exception(typeid(*this), "API ERROR", "Failed to set color calibration table for the video renderer.");
101 gamma_mode_ = Color::TABLE;
102 for(int i=0; i<3; i++) delete [] table[i];
105 void APICanvasProperties::setGammaTable(const CGGammaValue * const table_r, const CGGammaValue * const table_g, const CGGammaValue * const table_b, const int num_steps) {
108 err = CGSetDisplayTransferByTable(target_display_, num_steps, table_r, table_g, table_b);
109 gamma_mode_ = Color::TABLE;
112 void APICanvasProperties::saveGammaValue() {
114 if(gamma_mode_==Color::NOTHING) {
115 err = CGGetDisplayTransferByFormula( target_display_,
116 &savedRedMin_, &savedRedMax_, &savedRedGamma_,
117 &savedGreenMin_, &savedGreenMax_, &savedGreenGamma_,
118 &savedBlueMin_, &savedBlueMax_, &savedBlueGamma_);
122 void APICanvasProperties::destroyGammaSettings() {
124 switch(gamma_mode_) {
125 case Color::GAMMA_VALUE:
128 err = CGSetDisplayTransferByFormula( target_display_,
129 savedRedMin_, savedRedMax_, savedRedGamma_,
130 savedGreenMin_, savedGreenMax_, savedGreenGamma_,
131 savedBlueMin_, savedBlueMax_, savedBlueGamma_);
134 gamma_mode_ = Color::NOTHING;
138 // Letters API : requires CGContextRef(quartz_context_)
139 //void APICanvasProperties::uncacheLetters(Letters &letters) {
140 void APICanvasProperties::uncache(Letters &letters) {
141 if(letters.caches.count(outer)!=0) {
142 letters.caches[outer].id->uncache(quartz_context_, letters);
143 letters.caches.erase(outer);
146 //void APICanvasProperties::cacheLetters(Letters &letters) {
147 void APICanvasProperties::cache(Letters &letters) {
148 if(letters.caches.count(outer)!=0) { this->uncache(letters); }
149 letters.caches.insert(std::pair<DrawableWithCache*, Letters::Cache>(outer, Letters::Cache(new APIFontProperties, false)));
150 letters.caches[outer].id->cache(quartz_context_, letters, *outer);
152 void APICanvasProperties::drawLetters(Letters &letters, const double x, const double y, const Color &col, const int horiz_align, const int vertical_align, const double max_width) {
153 if(letters.caches.count(outer)==0) {
154 outer->cacheLetters(letters);
156 // letters.caches[outer].id->draw(quartz_context_, letters, x,y,col,horiz_align,vertical_align,max_width, *outer);
157 letters.caches[outer].id->draw(quartz_context_, letters, x,y,col,horiz_align,max_width, *outer);
161 void APICanvasProperties::uncacheLetters(Letters &letters) {
162 if(!letters.cache_id.empty()) {
163 delete letters.cache_id.at(0);
164 letters.cache_id.clear();
167 void APICanvasProperties::cacheLetters(Letters &letters) {
168 if(letters.cache_id.empty()) {
169 letters.cache_id.push_back(new APIFontProperties);
170 letters.cache_id.at(0)->cache(quartz_context_, letters);
173 void APICanvasProperties::drawLetters(const Letters &letters, const double x, const double y, const Color &col, const int horiz_align, const double max_width) {
174 if(!letters.cache_id.empty()) {
175 letters.cache_id.at(0)->draw(quartz_context_, letters, x, y, col, horiz_align, max_width);
181 //////// APICanvasPropertiesFullscreen ////////
182 APICanvasPropertiesFullscreen::APICanvasPropertiesFullscreen(const Display &target) {
183 generateCanvasInstance(target);
185 APICanvasPropertiesFullscreen::APICanvasPropertiesFullscreen(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display &target) {
186 generateCanvasInstance(d_width, d_height, d_colordepth, d_refreshrate, target);
188 APICanvasPropertiesFullscreen::~APICanvasPropertiesFullscreen() {
189 destroyCanvasInstance();
192 void APICanvasPropertiesFullscreen::generateCanvasInstance(const Display &target) {
193 target_display_ = target.api_->did;//CGMainDisplayID();
194 CFDictionaryRef mode_ = CGDisplayCurrentMode( target_display_ );
195 generateCanvasInstance(mode_, target_display_);
197 void APICanvasPropertiesFullscreen::generateCanvasInstance(int d_width, int d_height, int d_colordepth, double d_refreshrate, const Display &target) {
198 // note: true refresh rate is not integer
199 target_display_ = target.api_->did;//CGMainDisplayID();
200 boolean_t exactMatch;
201 CFDictionaryRef mode_ = CGDisplayBestModeForParametersAndRefreshRate(target_display_, (size_t)d_colordepth, (size_t)d_width, (size_t)d_height, (CGRefreshRate)d_refreshrate, &exactMatch );
202 if(!exactMatch) throw Exception(typeid(*this), "API Error", "Specified display mode was not available.");
203 generateCanvasInstance(mode_, target_display_);
205 void APICanvasPropertiesFullscreen::generateCanvasInstance(CFDictionaryRef d_mode, CGDirectDisplayID target) {
206 original_mode_ = CGDisplayCurrentMode( target );
208 dispOpenGLDisplayMask = 0;
209 CGDisplayCapture( target );
210 CGDisplaySwitchToMode( target, d_mode );
212 CGDisplayHideCursor( target );
213 CGOpenGLDisplayMask displayMask = CGDisplayIDToOpenGLDisplayMask( target );
214 WindowMetrix metrix = getDisplayMetrix(target);
215 width_=metrix.width; height_=metrix.height; colordepth_=metrix.colordepth; refreshrate_=metrix.refreshrate;
217 CGLPixelFormatObj dispPixFormatObj;
218 CGLPixelFormatAttribute dispPixFormatAtt[32] = {
223 (_CGLPixelFormatAttribute)2,
225 (_CGLPixelFormatAttribute)displayMask,
226 (_CGLPixelFormatAttribute)dispOpenGLDisplayMask,
228 GLint syncronizeSwapIntervalWithVerticalRetraceOfTheDisplay = 1;
232 if( ! CGLChoosePixelFormat(dispPixFormatAtt, &dispPixFormatObj, &num) ) {
233 if( ! CGLCreateContext( dispPixFormatObj, NULL, &cgl_context_) ) {
235 error = CGLSetParameter( cgl_context_, kCGLCPSwapInterval, &syncronizeSwapIntervalWithVerticalRetraceOfTheDisplay );
236 vsync_available_ = error ? false : true;
237 CGLSetCurrentContext( cgl_context_ );
238 CGLSetFullScreen( cgl_context_ );
239 has_instance_ = true;
241 CGLDestroyPixelFormat( dispPixFormatObj );
244 quartz_context_ = CGDisplayGetDrawingContext(target);
245 gamma_mode_ = Color::NOTHING;
246 CGRect rect = CGDisplayBounds(target);
247 lefttop.set(rect.origin.x, rect.origin.y);
249 void APICanvasPropertiesFullscreen::destroyCanvasInstance() {
251 destroyGammaSettings();
252 CGDisplayShowCursor( kCGDirectMainDisplay );
253 CGLSetCurrentContext( NULL );
254 CGLClearDrawable( cgl_context_ );
255 CGLDestroyContext( cgl_context_ ); // error has occured
257 CGDisplaySwitchToMode( kCGDirectMainDisplay, original_mode_ );
258 CGDisplayRelease( kCGDirectMainDisplay );
259 //CGDisplayErr disperr =
260 CGDisplayRelease( kCGDirectMainDisplay );
261 has_instance_ = false;
264 void APICanvasPropertiesFullscreen::flip() {
265 CGLFlushDrawable( cgl_context_ );
267 void APICanvasPropertiesFullscreen::waitRefresh() {
268 CGDisplayWaitForBeamPositionOutsideLines(target_display_, 1, height_-1);
269 CGDisplayWaitForBeamPositionOutsideLines(target_display_, 0, 1);
271 Point APICanvasPropertiesFullscreen::left_top() {
276 //////// APICanvasPropertiesWindow ////////
277 APICanvasPropertiesWindow::APICanvasPropertiesWindow()
281 APICanvasPropertiesWindow::APICanvasPropertiesWindow(int d_width, int d_height, const Display& dd)
284 target_display_ = dd.api_->did;
285 generateCanvasInstance(dd.area.getLeft() + 10, dd.area.getTop() + 30, d_width, d_height);
287 APICanvasPropertiesWindow::APICanvasPropertiesWindow(int d_left, int d_top, int d_width, int d_height)
290 target_display_ = CGMainDisplayID();
291 generateCanvasInstance(d_left, d_top, d_width, d_height);
293 APICanvasPropertiesWindow::~APICanvasPropertiesWindow() {
294 destroyCanvasInstance();
295 APICanvasPropertiesObjc *api_objc = reinterpret_cast<APICanvasPropertiesObjc*>(api_objc_);
296 // [api_objc->pool release];
300 void APICanvasPropertiesWindow::generateCanvasInstance(int d_left, int d_top, int d_width, int d_height) {
301 //OSStatus err = noErr;
302 APICanvasPropertiesObjc *api_objc = new APICanvasPropertiesObjc();
303 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
304 //api_objc->pool = [[NSAutoreleasePool alloc] init];
305 api_objc->app = [NSApplication sharedApplication];
306 // [api_objc->app finishLaunching];
307 // [api_objc->app setMainMenu: [[NSMenu alloc] initWithTitle:@"Psychlops"] ];
308 api_objc_ = api_objc;
310 //NS *window = [[NSWindow alloc] init];
312 const GLint swap = 1;
314 width_ = d_width, height_ =d_height;
319 rectPort.left = d_left;
320 rectPort.right = rectPort.left + d_width;
321 rectPort.top = d_top;
322 rectPort.bottom= rectPort.top + d_height;
323 const Rect* rp = &rectPort;
324 CreateNewWindow( /*kOverlayWindowClass*/kDocumentWindowClass , 0, rp, &window_ );
325 // replace NSWindow next time
327 GLint attributes[] = { AGL_RGBA, AGL_DOUBLEBUFFER, AGL_DEPTH_SIZE, 24, AGL_AUX_BUFFERS, 2, AGL_NONE };
330 AGLPixelFormat myAGLPixelFormat;
331 myAGLPixelFormat = aglChoosePixelFormat (NULL, 0, attributes);
332 //err = MyAGLReportError();
333 if (myAGLPixelFormat) {
334 agl_context_ = aglCreateContext (myAGLPixelFormat, NULL);
335 //err = MyAGLReportError ();
339 // if we are in debug mode
340 aglEnable (agl_context_, AGL_FS_CAPTURE_SINGLE);
342 aglDisable (agl_context_, AGL_FS_CAPTURE_SINGLE);
344 if(!aglSetDrawable(agl_context_, GetWindowPort(window_))) throw Exception("AGL: failed to attactch context to the window.");
345 // if(!aglSetWindowRef(agl_context_, window_)) throw Exception("AGL: failed to attactch context to the window.");
346 if(!aglSetCurrentContext(agl_context_)) throw Exception("AGL: failed to set current context.");
347 if (!aglSetInteger (agl_context_, AGL_SWAP_INTERVAL, &swap)) throw Exception("AGL: failed to set vsync.");
349 // add codes to get window quartz context.
352 CGDisplayHideCursor( target_display_ );
354 void APICanvasPropertiesWindow::destroyCanvasInstance() {
356 destroyGammaSettings();
357 aglSetDrawable (agl_context_, NULL);
358 aglSetCurrentContext (NULL);
359 aglDestroyContext (agl_context_);
361 DisposeWindow(window_);
362 CGDisplayShowCursor( target_display_ );
363 has_instance_ = false;
366 void APICanvasPropertiesWindow::flip() {
367 aglSwapBuffers( agl_context_ );
369 Point APICanvasPropertiesWindow::left_top() {
371 GetWindowBounds(window_, kWindowContentRgn, &rect);
372 return Point(rect.left, rect.top);
375 //////// APIFontProperties ////////
377 APIFontProperties::APIFontProperties() : cached(false), layout_defined(false), theUnicodeText(0) {
379 APIFontProperties::~APIFontProperties() {
381 if(theUnicodeText!=0) free(theUnicodeText);
382 ATSUDisposeStyle(theStyle);
383 ATSUDisposeTextLayout(theLayout);
384 layout_defined = false;
390 void APIFontProperties::cache(const CGContextRef &ctx, Letters &letters, DrawableWithCache &target) {
391 cache_on_image(letters, target);
393 void APIFontProperties::uncache(const CGContextRef &ctx, Letters &letters) {
394 //cache_img.uncache();
398 void APIFontProperties::draw(const CGContextRef &ctx, const Letters &letters, const double x, const double y, const Color &col, const int horiz_align, const double max_width, DrawableWithCache &target) {
399 draw_cached_image(x, y, col, target);
401 void APIFontProperties::setLayout(Letters &letters) {
402 if(!layout_defined) {
403 #if defined(PANTHER) && ( PANTHER ==1 )
404 CFStringRef str = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)(letters.str.c_str()), letters.str.length()*4, kCFStringEncodingUnicode, false);
405 CFStringRef fontfaceName = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)(letters.font.family.at(0).c_str()), letters.font.family.at(0).length()*4, kCFStringEncodingUnicode, false);
407 CFStringRef str = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)(letters.str.c_str()), letters.str.length()*4, kCFStringEncodingUTF32LE, false);
408 CFStringRef fontfaceName = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)(letters.font.family.at(0).c_str()), letters.font.family.at(0).length()*4, kCFStringEncodingUTF32LE, false);
411 const char * fontName = CFStringGetCStringPtr(fontfaceName, kCFStringEncodingMacRoman);
412 int fontNameLength = CFStringGetLength(fontfaceName);
415 size_t textLength = CFStringGetLength(str);
416 if(theUnicodeText!=0) free(theUnicodeText);
417 theUnicodeText = (UniChar*)calloc(textLength, sizeof(UniChar));
418 CFStringGetCharacters(str, CFRangeMake(0, textLength), theUnicodeText);
420 ATSUFontID atsuFontID;
421 err = ATSUFindFontFromName(fontName, fontNameLength, kFontPostscriptName, kFontNoPlatformCode, kFontNoScriptCode, kFontNoLanguageCode, &atsuFontID);
423 Fixed atsuSize = FloatToFixed(letters.font.size);
426 ATSUAttributeTag theTags[] = {
427 kATSUFontTag, kATSUSizeTag, kATSUVerticalCharacterTag,
428 kATSUQDBoldfaceTag, kATSUQDItalicTag, kATSUQDUnderlineTag,
429 kATSUQDCondensedTag, kATSUQDExtendedTag
431 ByteCount theSizes[] = {
432 sizeof(ATSUFontID), sizeof(Fixed), sizeof(UInt16),
433 sizeof(Boolean), sizeof(Boolean), sizeof(Boolean),
434 sizeof(Boolean), sizeof(Boolean)
436 ATSUAttributeValuePtr theValues[] = {
437 NULL, NULL, NULL, NULL,
438 NULL, NULL, NULL, NULL
441 Boolean trueV=true, falseV=false;
442 short atsuOrientation = kATSUStronglyHorizontal;
443 theValues[0] = &atsuFontID;
444 theValues[1] = &atsuSize;
445 theValues[2] = &atsuOrientation;
446 theValues[3] = (letters.font.weight==Font::normal_weight ? &falseV : &trueV);
447 theValues[4] = (letters.font.style==Font::normal_style ? &falseV : &trueV);
448 theValues[5] = &falseV; //underline
449 theValues[6] = &falseV; //condense
450 theValues[7] = &falseV; //extend
452 ATSUCreateStyle(&theStyle);
453 ATSUSetAttributes( theStyle, 8, theTags, theSizes, theValues );
455 ATSUCreateTextLayoutWithTextPtr(theUnicodeText, 0, textLength, textLength, 1, &textLength, &theStyle, &theLayout);
458 ATSUMeasureTextImage(theLayout, 0, textLength, 0, 0, &metrix);
459 cache_w = letters.width_ = abs(metrix.right-metrix.left);
460 cache_h = letters.height_ = abs(metrix.bottom-metrix.top);
461 cache_baseX = metrix.left;
462 cache_baseY = abs(metrix.top);
464 layout_defined = true;
467 void APIFontProperties::cache_on_context(const CGContextRef &ctx) {
469 ATSUAttributeTag theTags [1];//2
470 ByteCount theSizes [1];//2
471 ATSUAttributeValuePtr theValues[1];//2
473 theTags [0] = kATSUCGContextTag;
474 theSizes [0] = sizeof(CGContextRef);
475 theValues[0] = (void *)&ctx;
476 ATSUSetLayoutControls(theLayout, 1, theTags, theSizes, theValues);
481 void APIFontProperties::draw_on_context(const CGContextRef &ctx, const float posX, const float posY, const double r, const double g, const double b, const double a) {
483 CGContextSetRGBFillColor (ctx, r, g, b, a);
484 ATSUDrawText(theLayout, kATSUFromTextBeginning, kATSUToTextEnd, FloatToFixed(posX), FloatToFixed(posY) );
487 void APIFontProperties::cache_on_image(Letters &letters, DrawableWithCache &target) {
490 if(cache_w<=0) cache_w=1;
491 if(cache_h<=0) cache_h=1;
492 cache_img.set(cache_w,cache_h,Image::RGBA);
493 cache_img.clear(Color(0.0,0.0,0.0,0.0,false));
495 if(cache_img.api_->pic_!=0) {
496 cache_on_context(cache_img.api_->pic_);
497 draw_on_context(cache_img.api_->pic_, -cache_baseX, cache_h-cache_baseY, 0,0,0,1);
501 const size_t lineb = cache_img.lineBytes_, h = cache_img.height_-1;
502 unsigned char *tmp = new unsigned char[lineb];
503 unsigned char *bitmapub_ = cache_img.bitmapub_;
504 for(size_t i=0; i<(size_t)((h+1)/2); i++) {
505 memcpy(tmp, bitmapub_+lineb*i, lineb);
506 memcpy(bitmapub_+lineb*i, bitmapub_+lineb*(h-i), lineb);
507 memcpy(bitmapub_+lineb*(h-i), tmp, lineb);
510 cache_img.cache(target);
514 void APIFontProperties::draw_cached_image(const double posX, const double posY, const Color &col, DrawableWithCache& target) {
516 const Color zero_alpha(1,1,1,0,false);
517 glPushAttrib(GL_COLOR_BUFFER_BIT);
518 cache_img.move_to(posX, posY-cache_baseY);
520 // clear destination alpha
521 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
522 cache_img.targetarea_.draw(zero_alpha, target);
524 // draw font in alpha channel
525 glBlendFunc(GL_ONE, GL_ONE);
526 cache_img.draw(target);
528 // apply alpha factor
530 Color alpha_mask(1,1,1,col.getA(),false);
531 glBlendFunc(GL_ZERO, GL_SRC_COLOR);
532 cache_img.targetarea_.draw(alpha_mask, target);
535 // drawing in specified color by destination alpha
536 glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
537 cache_img.targetarea_.draw(col, target);
539 // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
548 //////// APIImageProperties ////////
550 // int APIImageProperties::max_reg = 10;
551 // int APIImageProperties::rights_[10+1], APIImageProperties::bottoms_[10+1];
553 APIImageProperties::APIImageProperties() : pic_(NULL), outer_(NULL) {
554 // for(int i=0; i<max_reg; i++) { rights_[i]=-1; bottoms_[i]=0; }
555 // rights_[0]=-1; bottoms_[0]=-1;
557 APIImageProperties::APIImageProperties(Image *outer) : pic_(NULL), outer_(outer) {
560 APIImageProperties::~APIImageProperties() {
563 void APIImageProperties::attach() {
564 colorSpace = CGColorSpaceCreateDeviceRGB();
565 if(pic_==NULL && outer_!=NULL && outer_->pixprec_==Image::BYTE && outer_->pixcomp_==Image::RGBA) {
566 pic_ = CGBitmapContextCreate(outer_->bitmapub_, outer_->width_, outer_->height_, 8, outer_->lineBytes_, colorSpace, kCGImageAlphaPremultipliedLast);
567 //std::cout << pic_ << std::endl;
570 void APIImageProperties::detach() {
571 if (pic_ != NULL) { CGContextRelease(pic_); pic_=NULL; }
572 CGColorSpaceRelease( colorSpace );
574 /* void APIImageProperties::drawLetters(
575 Letters &letters, const double x, const double y,
576 const double r, const double g, const double b, const double a,
577 const int horiz_align, const double max_width) {
579 if(!letters.cache_id.empty()) {
580 letters.cache_id.push_back(new APIFontProperties);
581 CFStringRef cftext = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8*)(letters.str.c_str()), letters.str.length()*4, kCFStringEncodingUTF32LE, false);
582 letters.cache_id.at(0)->setLayout(cftext, letters.font);
583 letters.cache_id.at(0)->cache_on_context(pic_);
585 letters.cache_id.at(0)->draw(pic_, x, y, r, g, b, a);
589 unsigned int APIImageCache::getTexIndex() {
593 bool APIImageProperties::regist(int maxwidth, int maxheight, int width, int height, int &left, int &top) {
594 for(int i=1; i<max_reg; i++) {
595 if( (rights_[i]+width <= maxwidth && (bottoms_[i-1]+height<=bottoms_[i]) || (bottoms_[i-1]+height <= maxheight && bottoms_[i+1]==0) ) ) {
597 top = bottoms_[i-1]+1;
598 rights_[i] = left+width-1;
599 bottoms_[i] = (bottoms_[i-1]+height<bottoms_[i]) ? bottoms_[i] : bottoms_[i-1]+height;
603 throw Exception(typeid(APIImageProperties), "Memory Error", "Image accelerater failed to allocate VRAM.");
608 } /* <- namespace Psychlops */