CmOSXWindow.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. -----------------------------------------------------------------------------
  3. This source file is part of OGRE
  4. (Object-oriented Graphics Rendering Engine)
  5. For the latest info, see http://www.ogre3d.org/
  6. Copyright (c) 2000-2011 Torus Knot Software Ltd
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in
  14. all copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. THE SOFTWARE.
  22. -----------------------------------------------------------------------------
  23. */
  24. #include "CmOSXWindow.h"
  25. #include "CmOSXCGLContext.h"
  26. #include "CmGLRenderSystem.h"
  27. #include "CmException.h"
  28. #include "CmStringConverter.h"
  29. #include "CmGLPixelFormat.h"
  30. #include <OpenGL/gl.h>
  31. #define GL_EXT_texture_env_combine 1
  32. #include <OpenGL/glext.h>
  33. #include <OpenGL/glu.h>
  34. namespace CamelotEngine
  35. {
  36. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  37. uint32 OSXWindow::bitDepthFromDisplayMode(CGDisplayModeRef mode)
  38. {
  39. uint32 depth = 0;
  40. CFStringRef pixEnc = CGDisplayModeCopyPixelEncoding(mode);
  41. if(CFStringCompare(pixEnc, CFSTR(IO32BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
  42. depth = 32;
  43. else if(CFStringCompare(pixEnc, CFSTR(IO16BitDirectPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
  44. depth = 16;
  45. else if(CFStringCompare(pixEnc, CFSTR(IO8BitIndexedPixels), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
  46. depth = 8;
  47. return depth;
  48. }
  49. #endif
  50. //-------------------------------------------------------------------------------------------------//
  51. OSXWindow::OSXWindow() : mContext(NULL), mCGLContextObj(NULL), mOriginalDisplayMode(NULL)
  52. {
  53. }
  54. //-------------------------------------------------------------------------------------------------//
  55. OSXWindow::~OSXWindow()
  56. {
  57. }
  58. //-------------------------------------------------------------------------------------------------//
  59. void OSXWindow::copyContentsToMemory(const PixelBox &dst, FrameBuffer buffer)
  60. {
  61. if ((dst.left < 0) || (dst.right > mWidth) ||
  62. (dst.top < 0) || (dst.bottom > mHeight) ||
  63. (dst.front != 0) || (dst.back != 1))
  64. {
  65. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  66. "Invalid box.",
  67. "OSXWindow::copyContentsToMemory" );
  68. }
  69. if (buffer == FB_AUTO)
  70. {
  71. buffer = mIsFullScreen? FB_FRONT : FB_BACK;
  72. }
  73. GLenum format = Ogre::GLPixelUtil::getGLOriginFormat(dst.format);
  74. GLenum type = Ogre::GLPixelUtil::getGLOriginDataType(dst.format);
  75. if ((format == GL_NONE) || (type == 0))
  76. {
  77. OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS,
  78. "Unsupported format.",
  79. "OSXWindow::copyContentsToMemory" );
  80. }
  81. if((dst.getWidth()*Ogre::PixelUtil::getNumElemBytes(dst.format)) & 3)
  82. {
  83. // Standard alignment of 4 is not right
  84. glPixelStorei(GL_PACK_ALIGNMENT, 1);
  85. }
  86. glReadBuffer((buffer == FB_FRONT)? GL_FRONT : GL_BACK);
  87. glReadPixels((GLint)dst.left, (GLint)dst.top,
  88. (GLsizei)dst.getWidth(), (GLsizei)dst.getHeight(),
  89. format, type, dst.data);
  90. glPixelStorei(GL_PACK_ALIGNMENT, 4);
  91. //vertical flip
  92. {
  93. size_t rowSpan = dst.getWidth() * PixelUtil::getNumElemBytes(dst.format);
  94. size_t height = dst.getHeight();
  95. uchar *tmpData = (uchar *)OGRE_MALLOC_ALIGN(rowSpan * height, MEMCATEGORY_GENERAL, false);
  96. uchar *srcRow = (uchar *)dst.data, *tmpRow = tmpData + (height - 1) * rowSpan;
  97. while (tmpRow >= tmpData)
  98. {
  99. memcpy(tmpRow, srcRow, rowSpan);
  100. srcRow += rowSpan;
  101. tmpRow -= rowSpan;
  102. }
  103. memcpy(dst.data, tmpData, rowSpan * height);
  104. OGRE_FREE_ALIGN(tmpData, MEMCATEGORY_GENERAL, false);
  105. }
  106. }
  107. //-------------------------------------------------------------------------------------------------//
  108. void OSXWindow::createCGLFullscreen(unsigned int width, unsigned int height, unsigned int depth, unsigned int fsaa, CGLContextObj sharedContext)
  109. {
  110. // Find the best match to what was requested
  111. boolean_t exactMatch = 0;
  112. unsigned int reqWidth = 0, reqHeight = 0, reqDepth = 0;
  113. CGLError cglErr = kCGLNoError;
  114. CGError cgErr = kCGErrorSuccess;
  115. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  116. // Get a copy of the current display mode
  117. CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
  118. // Loop through all display modes to determine the closest match.
  119. // CGDisplayBestModeForParameters is deprecated on 10.6 so we will emulate it's behavior
  120. // Try to find a mode with the requested depth and equal or greater dimensions first.
  121. // If no match is found, try to find a mode with greater depth and same or greater dimensions.
  122. // If still no match is found, just use the current mode.
  123. CFArrayRef allModes = CGDisplayCopyAllDisplayModes(kCGDirectMainDisplay, NULL);
  124. for(int i = 0; i < CFArrayGetCount(allModes); i++)
  125. {
  126. CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
  127. String modeString = StringConverter::toString(CGDisplayModeGetWidth(mode)) + String(" x ") +
  128. StringConverter::toString(CGDisplayModeGetHeight(mode)) + String(" @ ") +
  129. StringConverter::toString(bitDepthFromDisplayMode(mode)) + "bpp.";
  130. // LogManager::getSingleton().logMessage(modeString);
  131. if(bitDepthFromDisplayMode(mode) != depth)
  132. continue;
  133. if((CGDisplayModeGetWidth(mode) == width) && (CGDisplayModeGetHeight(mode) == height))
  134. {
  135. displayMode = mode;
  136. exactMatch = 1;
  137. break;
  138. }
  139. }
  140. // No depth match was found
  141. if(!exactMatch)
  142. {
  143. for(int i = 0; i < CFArrayGetCount(allModes); i++)
  144. {
  145. CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
  146. if(bitDepthFromDisplayMode(mode) >= depth)
  147. continue;
  148. if((CGDisplayModeGetWidth(mode) >= width) && (CGDisplayModeGetHeight(mode) >= height))
  149. {
  150. displayMode = mode;
  151. exactMatch = 1;
  152. break;
  153. }
  154. }
  155. }
  156. reqWidth = CGDisplayModeGetWidth(displayMode);
  157. reqHeight = CGDisplayModeGetHeight(displayMode);
  158. reqDepth = bitDepthFromDisplayMode(displayMode);
  159. #else
  160. const void *value = NULL;
  161. CFDictionaryRef displayMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, depth, width, height, &exactMatch);
  162. value = CFDictionaryGetValue(displayMode, kCGDisplayWidth);
  163. CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &reqWidth);
  164. value = CFDictionaryGetValue(displayMode, kCGDisplayHeight);
  165. CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &reqHeight);
  166. value = CFDictionaryGetValue(displayMode, kCGDisplayBitsPerPixel);
  167. CFNumberGetValue((CFNumberRef)value, kCFNumberSInt32Type, &reqDepth);
  168. #endif
  169. if(!exactMatch)
  170. {
  171. // That mode is not available, using the closest match
  172. String request = StringConverter::toString(width) + String(" x ") + StringConverter::toString(height) + String(" @ ") +
  173. StringConverter::toString(depth) + "bpp. ";
  174. String received = StringConverter::toString(reqWidth) + String(" x ") +
  175. StringConverter::toString(reqHeight) + String(" @ ") +
  176. StringConverter::toString(reqDepth) + "bpp. ";
  177. LogManager::getSingleton().logMessage(String("RenderSystem Warning: You requested a fullscreen mode of ") + request +
  178. String(" This mode is not available and you will receive the closest match. The best display mode for the parameters requested is: ")
  179. + received);
  180. }
  181. // Do the fancy display fading
  182. CGDisplayFadeReservationToken reservationToken = 0;
  183. cgErr = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval,
  184. &reservationToken);
  185. if(reservationToken)
  186. {
  187. cgErr = CGDisplayFade(reservationToken,
  188. 0.5f,
  189. kCGDisplayBlendNormal,
  190. kCGDisplayBlendSolidColor,
  191. 0.0f, 0.0f, 0.0f,
  192. true);
  193. CG_CHECK_ERROR(cgErr)
  194. cgErr = CGReleaseDisplayFadeReservation(reservationToken);
  195. reservationToken = 0;
  196. CG_CHECK_ERROR(cgErr)
  197. }
  198. // Grab the main display and save it for later.
  199. // You could render to any display, but picking what display
  200. // to render to could be interesting.
  201. cgErr = CGDisplayCapture(kCGDirectMainDisplay);
  202. CG_CHECK_ERROR(cgErr)
  203. // Switch to the correct resolution
  204. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  205. mOriginalDisplayMode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
  206. cgErr = CGDisplaySetDisplayMode(kCGDirectMainDisplay, displayMode, NULL);
  207. #else
  208. mOriginalDisplayMode = CGDisplayCurrentMode(kCGDirectMainDisplay);
  209. cgErr = CGDisplaySwitchToMode(kCGDirectMainDisplay, displayMode);
  210. #endif
  211. CG_CHECK_ERROR(cgErr)
  212. // Get a pixel format that best matches what we are looking for
  213. CGLPixelFormatAttribute attribs[] = {
  214. kCGLPFADoubleBuffer,
  215. kCGLPFAAlphaSize, (CGLPixelFormatAttribute)8,
  216. kCGLPFADepthSize, (CGLPixelFormatAttribute)reqDepth,
  217. kCGLPFAStencilSize, (CGLPixelFormatAttribute)8,
  218. kCGLPFASampleBuffers, (CGLPixelFormatAttribute)0,
  219. kCGLPFASamples, (CGLPixelFormatAttribute)0,
  220. kCGLPFAFullScreen,
  221. kCGLPFASingleRenderer,
  222. kCGLPFAAccelerated,
  223. kCGLPFADisplayMask, (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay),
  224. (CGLPixelFormatAttribute)0
  225. };
  226. // Set up FSAA if it was requested
  227. if(fsaa > 1)
  228. {
  229. // Turn on kCGLPFASampleBuffers
  230. attribs[8] = (CGLPixelFormatAttribute)1;
  231. // Set the samples for kCGLPFASamples
  232. attribs[10] = (CGLPixelFormatAttribute)fsaa;
  233. }
  234. CGLPixelFormatObj pixelFormatObj = NULL;
  235. #if defined(MAC_OS_X_VERSION_10_4) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
  236. long numPixelFormats = 0;
  237. cglErr = CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);
  238. #else
  239. GLint numPixelFormats = 0;
  240. cglErr = CGLChoosePixelFormat(attribs, &pixelFormatObj, &numPixelFormats);
  241. #endif
  242. CGL_CHECK_ERROR(cglErr)
  243. if(pixelFormatObj && !mCGLContextObj)
  244. {
  245. // Create the CGL context from our pixel format, share it with the sharedContext passed in
  246. cglErr = CGLCreateContext(pixelFormatObj, sharedContext, &mCGLContextObj);
  247. CGL_CHECK_ERROR(cglErr)
  248. }
  249. if(mCGLContextObj)
  250. {
  251. // Set the context as current
  252. cglErr = CGLSetCurrentContext(mCGLContextObj);
  253. CGL_CHECK_ERROR(cglErr)
  254. // Set the context to full screen
  255. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  256. cglErr = CGLSetFullScreenOnDisplay(mCGLContextObj, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay));
  257. #else
  258. cglErr = CGLSetFullScreen(mCGLContextObj);
  259. #endif
  260. CGL_CHECK_ERROR(cglErr)
  261. // This synchronizes CGL with the vertical retrace
  262. // Apple docs suggest that OpenGL blocks rendering calls when waiting for
  263. // a vertical retrace anyhow.
  264. #if defined(MAC_OS_X_VERSION_10_4) && MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_4
  265. long swapInterval = 1;
  266. cgErr = CGLSetParameter(mCGLContextObj, kCGLCPSwapInterval, &swapInterval);
  267. #else
  268. GLint swapInterval = 1;
  269. cgErr = CGLSetParameter(mCGLContextObj, kCGLCPSwapInterval, &swapInterval);
  270. #endif
  271. CG_CHECK_ERROR(cgErr)
  272. // Give a copy of our context to the rendersystem
  273. if(!mContext)
  274. mContext = OGRE_NEW OSXCGLContext(mCGLContextObj, pixelFormatObj);
  275. // Once we have the context we can destroy the pixel format
  276. // In order to share contexts you must keep a pointer to the context object around
  277. // Our context class will now manage the life of the pixelFormatObj
  278. cglErr = CGLDestroyPixelFormat(pixelFormatObj);
  279. CGL_CHECK_ERROR(cglErr)
  280. // Let everyone know we are fullscreen now
  281. mIsFullScreen = true;
  282. }
  283. // Set some other variables. Just in case we got a different value from CGDisplayBestModeForParameters than we requested
  284. mWidth = reqWidth;
  285. mHeight = reqHeight;
  286. mColourDepth = reqDepth;
  287. cgErr = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval,
  288. &reservationToken);
  289. if(cgErr == kCGErrorSuccess)
  290. {
  291. cgErr = CGDisplayFade(reservationToken,
  292. 2.0f,
  293. kCGDisplayBlendSolidColor,
  294. kCGDisplayBlendNormal,
  295. 0.0f, 0.0f, 0.0f,
  296. false);
  297. CG_CHECK_ERROR(cgErr)
  298. cgErr = CGReleaseDisplayFadeReservation(reservationToken);
  299. CG_CHECK_ERROR(cgErr)
  300. }
  301. }
  302. //-------------------------------------------------------------------------------------------------//
  303. void OSXWindow::destroyCGLFullscreen(void)
  304. {
  305. CGError cgErr = kCGErrorSuccess;
  306. // Do the fancy display fading
  307. CGDisplayFadeReservationToken reservationToken = 0;
  308. cgErr = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval,
  309. &reservationToken);
  310. if(cgErr == kCGErrorSuccess)
  311. {
  312. cgErr = CGDisplayFade(reservationToken,
  313. 2.0f,
  314. kCGDisplayBlendSolidColor,
  315. kCGDisplayBlendNormal,
  316. 0.0f, 0.0f, 0.0f,
  317. false);
  318. CG_CHECK_ERROR(cgErr)
  319. cgErr = CGReleaseDisplayFadeReservation(reservationToken);
  320. reservationToken = 0;
  321. CG_CHECK_ERROR(cgErr)
  322. }
  323. // Release the main display
  324. cgErr = CGDisplayRelease( kCGDirectMainDisplay );
  325. CG_CHECK_ERROR(cgErr)
  326. cgErr = CGAcquireDisplayFadeReservation(kCGMaxDisplayReservationInterval,
  327. &reservationToken);
  328. if(cgErr == kCGErrorSuccess)
  329. {
  330. cgErr = CGDisplayFade(reservationToken,
  331. 0.5f,
  332. kCGDisplayBlendNormal,
  333. kCGDisplayBlendSolidColor,
  334. 0.0f, 0.0f, 0.0f,
  335. true);
  336. CG_CHECK_ERROR(cgErr)
  337. cgErr = CGReleaseDisplayFadeReservation(reservationToken);
  338. CG_CHECK_ERROR(cgErr)
  339. }
  340. if(mCGLContextObj)
  341. {
  342. CGLDestroyContext(mCGLContextObj);
  343. mCGLContextObj = 0;
  344. }
  345. // Switch back to the original screen resolution
  346. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  347. CGDisplaySetDisplayMode(kCGDirectMainDisplay, mOriginalDisplayMode, NULL);
  348. #else
  349. CGDisplaySwitchToMode(kCGDirectMainDisplay, mOriginalDisplayMode);
  350. #endif
  351. }
  352. //-------------------------------------------------------------------------------------------------//
  353. void OSXWindow::swapCGLBuffers(void)
  354. {
  355. CGLFlushDrawable(mCGLContextObj);
  356. CGLContextObj curCtx = CGLGetCurrentContext();
  357. if(curCtx != mCGLContextObj)
  358. {
  359. CGLSetCurrentContext(mCGLContextObj);
  360. #if defined(MAC_OS_X_VERSION_10_6) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
  361. CGLSetFullScreenOnDisplay(mCGLContextObj, CGDisplayIDToOpenGLDisplayMask(kCGDirectMainDisplay));
  362. #else
  363. CGLSetFullScreen(mCGLContextObj);
  364. #endif
  365. }
  366. }
  367. }