![]() |
Shadowrun: Awakened 29 September 2011 - Build 871
|
00001 /* 00002 Copyright 2005-2010 Intel Corporation. All Rights Reserved. 00003 00004 This file is part of Threading Building Blocks. 00005 00006 Threading Building Blocks is free software; you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License 00008 version 2 as published by the Free Software Foundation. 00009 00010 Threading Building Blocks is distributed in the hope that it will be 00011 useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00012 of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with Threading Building Blocks; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00018 00019 As a special exception, you may use this file as part of a free software 00020 library without restriction. Specifically, if other files instantiate 00021 templates or use macros or inline functions from this file, or you compile 00022 this file and link it with other files to produce an executable, this 00023 file does not by itself cause the resulting executable to be covered by 00024 the GNU General Public License. This exception does not however 00025 invalidate any other reasons why the executable file might be covered by 00026 the GNU General Public License. 00027 */ 00028 00029 /* 00030 * Based on "OpenGL Image" example from http://developer.apple.com/samplecode/OpenGL_Image/ 00031 */ 00032 00033 #include "video.h" 00034 #include <sched.h> 00035 #include <sys/time.h> 00036 #include <stdio.h> 00037 #include <string.h> 00038 #include <pthread.h> 00039 00040 #include <AvailabilityMacros.h> 00041 #undef DEPRECATED_ATTRIBUTE 00042 #define DEPRECATED_ATTRIBUTE 00043 #include <Carbon/Carbon.h> 00044 #include <AGL/agl.h> 00045 #include <OpenGL/gl.h> // for OpenGL API 00046 #include <OpenGL/glext.h> // for OpenGL extension support 00047 00048 unsigned int * g_pImg = 0; 00049 int g_sizex, g_sizey; 00050 WindowRef g_window = 0; 00051 static video * g_video = 0; 00052 static int g_fps = 0; 00053 struct timeval g_time; 00054 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; 00055 00056 00057 static OSStatus AppEventHandler( EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon ); 00058 WindowRef HandleNew(); 00059 static OSStatus WindowEventHandler( EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon ); 00060 00061 static IBNibRef sNibRef; 00062 00063 //-------------------------------------------------------------------------------------------- 00064 00065 // structure for creating a fullscreen context 00066 struct structGLInfo // storage for setup info 00067 { 00068 SInt16 width; // input: width of drawable (screen width in full screen mode), return: actual width allocated 00069 SInt16 height; // input: height of drawable (screen height in full screen mode), return: actual height allocated 00070 UInt32 pixelDepth; // input: requested pixel depth 00071 Boolean fDepthMust; // input: pixel depth must be set (if false then current depth will be used if able) 00072 Boolean fAcceleratedMust; // input: must renderer be accelerated? 00073 GLint aglAttributes[64]; // input: pixel format attributes always required (reset to what was actually allocated) 00074 SInt32 VRAM; // input: minimum VRAM; output: actual (if successful otherwise input) 00075 SInt32 textureRAM; // input: amount of texture RAM required on card; output: same (used in allcoation to ensure enough texture 00076 AGLPixelFormat fmt; // input: none; output pixel format... 00077 }; 00078 typedef struct structGLInfo structGLInfo; 00079 typedef struct structGLInfo * pstructGLInfo; 00080 00081 // structure for creating a context from a window 00082 struct structGLWindowInfo // storage for setup info 00083 { 00084 Boolean fAcceleratedMust; // input: must renderer be accelerated? 00085 GLint aglAttributes[64]; // input: pixel format attributes always required (reset to what was actually allocated) 00086 SInt32 VRAM; // input: minimum VRAM; output: actual (if successful otherwise input) 00087 SInt32 textureRAM; // input: amount of texture RAM required on card; output: same (used in allcoation to ensure enough texture 00088 AGLPixelFormat fmt; // input: none; output pixel format... 00089 Boolean fDraggable; // input: is window going to be dragable, 00090 // if so renderer check (accel, VRAM, textureRAM) will look at all renderers vice just the current one 00091 // if window is not dragable renderer check will either check the single device or short 00092 // circuit to software if window spans multiple devices 00093 // software renderer is consider to have unlimited VRAM, unlimited textureRAM and to not be accelerated 00094 }; 00095 typedef struct structGLWindowInfo structGLWindowInfo; 00096 typedef struct structGLWindowInfo * pstructGLWindowInfo; 00097 00098 //-------------------------------------------------------------------------------------------- 00099 00100 struct recGLCap // structure to store minimum OpenGL capabilites across all displays and GPUs 00101 { 00102 Boolean f_ext_texture_rectangle; // is texture rectangle extension supported 00103 Boolean f_ext_client_storage; // is client storage extension supported 00104 Boolean f_ext_packed_pixel; // is packed pixel extension supported 00105 Boolean f_ext_texture_edge_clamp; // is SGI texture edge clamp extension supported 00106 Boolean f_gl_texture_edge_clamp; // is OpenGL texture edge clamp support (1.2+) 00107 unsigned long edgeClampParam; // the param that is passed to the texturing parmeteres 00108 long maxTextureSize; // the minimum max texture size across all GPUs 00109 long maxNOPTDTextureSize; // the minimum max texture size across all GPUs that support non-power of two texture dimensions 00110 }; 00111 typedef struct recGLCap recGLCap; 00112 typedef recGLCap * pRecGLCap; 00113 00114 struct recImage // OpenGL and image information associated with each window 00115 { 00116 // genric OpenGL stuff 00117 structGLWindowInfo glInfo; // gl info used with SetupGL to build context 00118 AGLContext aglContext; // the OpenGL context (read: state) 00119 GLuint fontList; // the display list storing the bitmap font created for the context to display info 00120 00121 Boolean fAGPTexturing; // 10.1+ only: texture from AGP memory without loading to GPU 00122 00123 // texture display stuff 00124 Boolean fNPOTTextures; // are we using Non-Power Of Two (NPOT) textures? 00125 Boolean fTileTextures; // are multiple tiled textures used to display image? 00126 Boolean fOverlapTextures; // do tiled textures overlapped to create correct filtering between tiles? (only applies if using tiled textures) 00127 Boolean fClientTextures; // 10.1+ only: texture from client memory 00128 00129 unsigned char * pImageBuffer; // image buffer that contains data for image (disposed after loading into texture if not using client textures) 00130 long imageWidth; // height of orginal image 00131 long imageHeight; // width of orginal image 00132 float imageAspect; // width / height or aspect ratio of orginal image 00133 long imageDepth; // depth of image (after loading into gworld, will be either 32 or 16 bits) 00134 long textureX; // number of horizontal textures 00135 long textureY; // number of vertical textures 00136 long maxTextureSize; // max texture size for image 00137 GLuint * pTextureName; // array for texture names (# = textureX * textureY) 00138 long textureWidth; // total width of texels with cover image (including any border on image, but not internal texture overlaps) 00139 long textureHeight; // total height of texels with cover image (including any border on image, but not internal texture overlaps) 00140 float zoomX; // zoom from on texel = one pixel is 1.0 00141 float zoomY; // zoom from on texel = one pixel is 1.0 00142 }; 00143 typedef struct recImage recImage; // typedef for easy declaration 00144 typedef recImage * pRecImage; // pointer type 00145 00146 // ================================== 00147 00148 // public function declarations ------------------------------------- 00149 00150 // Destroys drawable and context 00151 // Ouputs: *paglDraw, *paglContext should be 0 on exit 00152 // destorys a context that was associated with an existing window, window is left intacted 00153 OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo); 00154 00155 short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice); 00156 00157 // disposes OpenGL context, and associated texture list 00158 OSStatus DisposeGLForWindow (WindowRef window); 00159 00160 // builds the GL context and associated state for the window 00161 // loads image into a texture or textures 00162 // disposes of GWorld and image buffer when finished loading textures 00163 OSStatus BuildGLForWindow (WindowRef window); 00164 00165 // Handle updating context for window moves and resizing 00166 OSStatus ResizeMoveGLWindow (WindowRef window); 00167 00168 // main GL drawing routine, should be valid window passed in (will setupGL if require). Draw image 00169 void DrawGL (WindowRef window); 00170 00171 pRecGLCap gpOpenGLCaps; 00172 00173 // prototypes (internal/private) -------------------------------------------- 00174 00175 static Boolean CheckRenderer (GDHandle hGD, long *VRAM, long *textureRAM, GLint* , Boolean fAccelMust); 00176 static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust); 00177 static void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, pstructGLInfo pcontextInfo); 00178 static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext); 00179 00180 static long GetNextTextureSize (long textureDimension, long maxTextureSize, Boolean textureRectangle); 00181 static long GetTextureNumFromTextureDim (long textureDimension, long maxTextureSize, Boolean texturesOverlap, Boolean textureRectangle); 00182 00183 // ---------------------------------------------------------------------------------------- 00184 00185 // functions (internal/private) --------------------------------------------- 00186 00187 #pragma mark - 00188 // -------------------------------------------------------------------------- 00189 00190 // central error reporting 00191 00192 void ReportErrorNum (char * strError, long numError) 00193 { 00194 char errMsgPStr [257]; 00195 00196 errMsgPStr[0] = (char)snprintf (errMsgPStr+1, 255, "%s %ld (0x%lx)\n", strError, numError, numError); 00197 00198 // ensure we are faded in 00199 DebugStr ( (ConstStr255Param) errMsgPStr ); 00200 } 00201 00202 // -------------------------------------------------------------------------- 00203 00204 void ReportError (char * strError) 00205 { 00206 char errMsgPStr [257]; 00207 00208 errMsgPStr[0] = (char)snprintf (errMsgPStr+1, 255, "%s\n", strError); 00209 00210 // ensure we are faded in 00211 DebugStr ( (ConstStr255Param) errMsgPStr ); 00212 } 00213 00214 //----------------------------------------------------------------------------------------------------------------------- 00215 00216 // if error dump agl errors to debugger string, return error 00217 00218 OSStatus aglReportError (void) 00219 { 00220 GLenum err = aglGetError(); 00221 if (AGL_NO_ERROR != err) 00222 ReportError ((char *)aglErrorString(err)); 00223 // ensure we are returning an OSStatus noErr if no error condition 00224 if (err == AGL_NO_ERROR) 00225 return noErr; 00226 else 00227 return (OSStatus) err; 00228 } 00229 00230 //----------------------------------------------------------------------------------------------------------------------- 00231 00232 // if error dump gl errors to debugger string, return error 00233 00234 OSStatus glReportError (void) 00235 { 00236 GLenum err = glGetError(); 00237 switch (err) 00238 { 00239 case GL_NO_ERROR: 00240 break; 00241 case GL_INVALID_ENUM: 00242 ReportError ("GL Error: Invalid enumeration"); 00243 break; 00244 case GL_INVALID_VALUE: 00245 ReportError ("GL Error: Invalid value"); 00246 break; 00247 case GL_INVALID_OPERATION: 00248 ReportError ("GL Error: Invalid operation"); 00249 break; 00250 case GL_STACK_OVERFLOW: 00251 ReportError ("GL Error: Stack overflow"); 00252 break; 00253 case GL_STACK_UNDERFLOW: 00254 ReportError ("GL Error: Stack underflow"); 00255 break; 00256 case GL_OUT_OF_MEMORY: 00257 ReportError ("GL Error: Out of memory"); 00258 break; 00259 } 00260 // ensure we are returning an OSStatus noErr if no error condition 00261 if (err == GL_NO_ERROR) 00262 return noErr; 00263 else 00264 return (OSStatus) err; 00265 } 00266 00267 //-------------------------------------------------------------------------------------------- 00268 00269 // functions (internal/private) --------------------------------------------- 00270 00271 // CheckRenderer 00272 00273 // looks at renderer attributes it has at least the VRAM is accelerated 00274 00275 // Inputs: hGD: GDHandle to device to look at 00276 // pVRAM: pointer to VRAM in bytes required; out is actual VRAM if a renderer was found, otherwise it is the input parameter 00277 // pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) 00278 // fAccelMust: do we check for acceleration 00279 00280 // Returns: true if renderer for the requested device complies, false otherwise 00281 00282 static Boolean CheckRenderer (GDHandle hGD, long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) 00283 { 00284 AGLRendererInfo info, head_info; 00285 GLint inum; 00286 GLint dAccel = 0; 00287 GLint dVRAM = 0, dMaxVRAM = 0; 00288 Boolean canAccel = false, found = false; 00289 head_info = aglQueryRendererInfo(&hGD, 1); 00290 aglReportError (); 00291 if(!head_info) 00292 { 00293 ReportError ("aglQueryRendererInfo error"); 00294 return false; 00295 } 00296 else 00297 { 00298 info = head_info; 00299 inum = 0; 00300 // see if we have an accelerated renderer, if so ignore non-accelerated ones 00301 // this prevents returning info on software renderer when actually we'll get the hardware one 00302 while (info) 00303 { 00304 aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); 00305 aglReportError (); 00306 if (dAccel) 00307 canAccel = true; 00308 info = aglNextRendererInfo(info); 00309 aglReportError (); 00310 inum++; 00311 } 00312 00313 info = head_info; 00314 inum = 0; 00315 while (info) 00316 { 00317 aglDescribeRenderer (info, AGL_ACCELERATED, &dAccel); 00318 aglReportError (); 00319 // if we can accel then we will choose the accelerated renderer 00320 // how about compliant renderers??? 00321 if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) 00322 { 00323 aglDescribeRenderer (info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required 00324 aglReportError (); 00325 if (dVRAM >= (*pVRAM + *pTextureRAM)) 00326 { 00327 if (dVRAM >= dMaxVRAM) // find card with max VRAM 00328 { 00329 aglDescribeRenderer (info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported 00330 aglReportError (); 00331 dMaxVRAM = dVRAM; // store max 00332 found = true; 00333 } 00334 } 00335 } 00336 info = aglNextRendererInfo(info); 00337 aglReportError (); 00338 inum++; 00339 } 00340 } 00341 aglDestroyRendererInfo(head_info); 00342 if (found) // if we found a card that has enough VRAM and meets the accel criteria 00343 { 00344 *pVRAM = dMaxVRAM; // return VRAM 00345 return true; 00346 } 00347 // VRAM will remain to same as it did when sent in 00348 return false; 00349 } 00350 00351 //----------------------------------------------------------------------------------------------------------------------- 00352 00353 // CheckAllDeviceRenderers 00354 00355 // looks at renderer attributes and each device must have at least one renderer that fits the profile 00356 00357 // Inputs: pVRAM: pointer to VRAM in bytes required; out is actual min VRAM of all renderers found, otherwise it is the input parameter 00358 // pTextureRAM: pointer to texture RAM in bytes required; out is same (implementation assume VRAM returned by card is total so we add texture and VRAM) 00359 // fAccelMust: do we check fro acceleration 00360 00361 // Returns: true if any renderer for on each device complies (not necessarily the same renderer), false otherwise 00362 00363 static Boolean CheckAllDeviceRenderers (long* pVRAM, long* pTextureRAM, GLint* pDepthSizeSupport, Boolean fAccelMust) 00364 { 00365 AGLRendererInfo info, head_info; 00366 GLint inum; 00367 GLint dAccel = 0; 00368 GLint dVRAM = 0, dMaxVRAM = 0; 00369 Boolean canAccel = false, found = false, goodCheck = true; // can the renderer accelerate, did we find a valid renderer for the device, are we still successfully on all the devices looked at 00370 long MinVRAM = 0x8FFFFFFF; // max long 00371 GDHandle hGD = GetDeviceList (); // get the first screen 00372 while (hGD && goodCheck) 00373 { 00374 head_info = aglQueryRendererInfo(&hGD, 1); 00375 aglReportError (); 00376 if(!head_info) 00377 { 00378 ReportError ("aglQueryRendererInfo error"); 00379 return false; 00380 } 00381 else 00382 { 00383 info = head_info; 00384 inum = 0; 00385 // see if we have an accelerated renderer, if so ignore non-accelerated ones 00386 // this prevents returning info on software renderer when actually we'll get the hardware one 00387 while (info) 00388 { 00389 aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); 00390 aglReportError (); 00391 if (dAccel) 00392 canAccel = true; 00393 info = aglNextRendererInfo(info); 00394 aglReportError (); 00395 inum++; 00396 } 00397 00398 info = head_info; 00399 inum = 0; 00400 while (info) 00401 { 00402 aglDescribeRenderer(info, AGL_ACCELERATED, &dAccel); 00403 aglReportError (); 00404 // if we can accel then we will choose the accelerated renderer 00405 // how about compliant renderers??? 00406 if ((canAccel && dAccel) || (!canAccel && (!fAccelMust || dAccel))) 00407 { 00408 aglDescribeRenderer(info, AGL_VIDEO_MEMORY, &dVRAM); // we assume that VRAM returned is total thus add texture and VRAM required 00409 aglReportError (); 00410 if (dVRAM >= (*pVRAM + *pTextureRAM)) 00411 { 00412 if (dVRAM >= dMaxVRAM) // find card with max VRAM 00413 { 00414 aglDescribeRenderer(info, AGL_DEPTH_MODES, pDepthSizeSupport); // which depth buffer modes are supported 00415 aglReportError (); 00416 dMaxVRAM = dVRAM; // store max 00417 found = true; 00418 } 00419 } 00420 } 00421 info = aglNextRendererInfo(info); 00422 aglReportError (); 00423 inum++; 00424 } 00425 } 00426 aglDestroyRendererInfo(head_info); 00427 if (found) // if we found a card that has enough VRAM and meets the accel criteria 00428 { 00429 if (MinVRAM > dMaxVRAM) 00430 MinVRAM = dMaxVRAM; // return VRAM 00431 00432 } 00433 else 00434 goodCheck = false; // one device failed thus entire requirement fails 00435 hGD = GetNextDevice (hGD); // get next device 00436 } // while 00437 if (goodCheck) // we check all devices and each was good 00438 { 00439 *pVRAM = MinVRAM; // return VRAM 00440 return true; 00441 } 00442 return false; //at least one device failed to have mins 00443 } 00444 00445 //----------------------------------------------------------------------------------------------------------------------- 00446 00447 // DumpCurrent 00448 00449 // Kills currently allocated context 00450 // does not care about being pretty (assumes display is likely faded) 00451 00452 // Inputs: paglDraw, paglContext: things to be destroyed 00453 00454 void DumpCurrent (AGLDrawable* paglDraw, AGLContext* paglContext, pstructGLInfo pcontextInfo) 00455 { 00456 if (*paglContext) 00457 { 00458 aglSetCurrentContext (NULL); 00459 aglReportError (); 00460 aglSetDrawable (*paglContext, NULL); 00461 aglReportError (); 00462 aglDestroyContext (*paglContext); 00463 aglReportError (); 00464 *paglContext = NULL; 00465 } 00466 00467 if (pcontextInfo->fmt) 00468 { 00469 aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer needed 00470 aglReportError (); 00471 } 00472 pcontextInfo->fmt = 0; 00473 00474 if (*paglDraw) // do not destory a window on DSp since there is no window built in X 00475 DisposeWindow (GetWindowFromPort (*paglDraw)); 00476 *paglDraw = NULL; 00477 } 00478 00479 #pragma mark - 00480 // -------------------------------------------------------------------------- 00481 00482 // BuildGLonWindow 00483 00484 static OSStatus BuildGLonWindow (WindowPtr pWindow, AGLContext* paglContext, pstructGLWindowInfo pcontextInfo, AGLContext aglShareContext) 00485 { 00486 GDHandle hGD = NULL; 00487 GrafPtr cgrafSave = NULL; 00488 short numDevices; 00489 GLint depthSizeSupport; 00490 OSStatus err = noErr; 00491 00492 if (!pWindow || !pcontextInfo) 00493 { 00494 ReportError ("NULL parameter passed to BuildGLonWindow."); 00495 return paramErr; 00496 } 00497 00498 GetPort (&cgrafSave); 00499 SetPortWindowPort(pWindow); 00500 00501 // check renderere VRAM and acceleration 00502 numDevices = FindGDHandleFromWindow (pWindow, &hGD); 00503 if (!pcontextInfo->fDraggable) // if numDevices > 1 then we will only be using the software renderer otherwise check only window device 00504 { 00505 if ((numDevices > 1) || (numDevices == 0)) // this window spans mulitple devices thus will be software only 00506 { 00507 // software renderer 00508 // infinite VRAM, infinite textureRAM, not accelerated 00509 if (pcontextInfo->fAcceleratedMust) 00510 { 00511 ReportError ("Unable to accelerate window that spans multiple devices"); 00512 return err; 00513 } 00514 } 00515 else // not draggable on single device 00516 { 00517 if (!CheckRenderer (hGD, &(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) 00518 { 00519 ReportError ("Renderer check failed"); 00520 return err; 00521 } 00522 } 00523 } 00524 // else draggable so must check all for support (each device should have at least one renderer that meets the requirements) 00525 else if (!CheckAllDeviceRenderers (&(pcontextInfo->VRAM), &(pcontextInfo->textureRAM), &depthSizeSupport, pcontextInfo->fAcceleratedMust)) 00526 { 00527 ReportError ("Renderer check failed"); 00528 return err; 00529 } 00530 00531 // do agl 00532 if ((Ptr) kUnresolvedCFragSymbolAddress == (Ptr) aglChoosePixelFormat) // check for existance of OpenGL 00533 { 00534 ReportError ("OpenGL not installed"); 00535 return noErr; 00536 } 00537 // we successfully passed the renderer check 00538 00539 if ((!pcontextInfo->fDraggable && (numDevices == 1))) // not draggable on a single device 00540 pcontextInfo->fmt = aglChoosePixelFormat (&hGD, 1, pcontextInfo->aglAttributes); // get an appropriate pixel format 00541 else 00542 pcontextInfo->fmt = aglChoosePixelFormat (NULL, 0, pcontextInfo->aglAttributes); // get an appropriate pixel format 00543 aglReportError (); 00544 if (NULL == pcontextInfo->fmt) 00545 { 00546 ReportError("Could not find valid pixel format"); 00547 return noErr; 00548 } 00549 00550 *paglContext = aglCreateContext (pcontextInfo->fmt, aglShareContext); // Create an AGL context 00551 if (AGL_BAD_MATCH == aglGetError()) 00552 *paglContext = aglCreateContext (pcontextInfo->fmt, 0); // unable to sahre context, create without sharing 00553 aglReportError (); 00554 if (NULL == *paglContext) 00555 { 00556 ReportError ("Could not create context"); 00557 return noErr; 00558 } 00559 00560 if (!aglSetDrawable (*paglContext, GetWindowPort (pWindow))) // attach the CGrafPtr to the context 00561 return aglReportError (); 00562 00563 if(!aglSetCurrentContext (*paglContext)) // make the context the current context 00564 return aglReportError (); 00565 00566 SetPort (cgrafSave); 00567 00568 return err; 00569 } 00570 00571 #pragma mark - 00572 00573 // functions (public) ------------------------------------------------------- 00574 00575 // DestroyGLFromWindow 00576 00577 // Destroys context that waas allocated with BuildGLonWindow 00578 // Ouputs: *paglContext should be NULL on exit 00579 00580 OSStatus DestroyGLFromWindow (AGLContext* paglContext, pstructGLWindowInfo pcontextInfo) 00581 { 00582 OSStatus err; 00583 00584 if ((!paglContext) || (!*paglContext)) 00585 return paramErr; // not a valid context 00586 glFinish (); 00587 aglSetCurrentContext (NULL); 00588 err = aglReportError (); 00589 aglSetDrawable (*paglContext, NULL); 00590 err = aglReportError (); 00591 aglDestroyContext (*paglContext); 00592 err = aglReportError (); 00593 *paglContext = NULL; 00594 00595 if (pcontextInfo->fmt) 00596 { 00597 aglDestroyPixelFormat (pcontextInfo->fmt); // pixel format is no longer valid 00598 err = aglReportError (); 00599 } 00600 pcontextInfo->fmt = 0; 00601 00602 return err; 00603 } 00604 00605 //----------------------------------------------------------------------------------------------------------------------- 00606 00607 // GetWindowDevice 00608 00609 // Inputs: a valid WindowPtr 00610 00611 // Outputs: the GDHandle that that window is mostly on 00612 00613 // returns the number of devices that the windows content touches 00614 00615 short FindGDHandleFromWindow (WindowPtr pWindow, GDHandle * phgdOnThisDevice) 00616 { 00617 GrafPtr pgpSave; 00618 Rect rectWind, rectSect; 00619 long greatestArea, sectArea; 00620 short numDevices = 0; 00621 GDHandle hgdNthDevice; 00622 00623 if (!pWindow || !phgdOnThisDevice) 00624 return 0; 00625 00626 *phgdOnThisDevice = NULL; 00627 00628 GetPort (&pgpSave); 00629 SetPortWindowPort (pWindow); 00630 00631 00632 GetWindowPortBounds (pWindow, &rectWind); 00633 LocalToGlobal ((Point*)& rectWind.top); // convert to global coordinates 00634 LocalToGlobal ((Point*)& rectWind.bottom); 00635 hgdNthDevice = GetDeviceList (); 00636 greatestArea = 0; 00637 // check window against all gdRects in gDevice list and remember 00638 // which gdRect contains largest area of window} 00639 while (hgdNthDevice) 00640 { 00641 if (TestDeviceAttribute (hgdNthDevice, screenDevice)) 00642 if (TestDeviceAttribute (hgdNthDevice, screenActive)) 00643 { 00644 // The SectRect routine calculates the intersection 00645 // of the window rectangle and this gDevice 00646 // rectangle and returns TRUE if the rectangles intersect, 00647 // FALSE if they don't. 00648 SectRect (&rectWind, &(**hgdNthDevice).gdRect, &rectSect); 00649 // determine which screen holds greatest window area 00650 // first, calculate area of rectangle on current device 00651 sectArea = (long) (rectSect.right - rectSect.left) * (rectSect.bottom - rectSect.top); 00652 if (sectArea > 0) 00653 numDevices++; 00654 if (sectArea > greatestArea) 00655 { 00656 greatestArea = sectArea; // set greatest area so far 00657 *phgdOnThisDevice = hgdNthDevice; // set zoom device 00658 } 00659 hgdNthDevice = GetNextDevice(hgdNthDevice); 00660 } 00661 } 00662 00663 SetPort (pgpSave); 00664 return numDevices; 00665 } 00666 00667 //-------------------------------------------------------------------------------------------- 00668 // private 00669 00670 // returns the largest power of 2 texture <= textureDimension 00671 // or in the case of texture rectangle returns the next texture size (can be non-power of two) 00672 00673 static long GetNextTextureSize (long textureDimension, long maxTextureSize, Boolean textureRectangle) 00674 { 00675 long targetTextureSize = maxTextureSize; // start at max texture size 00676 if (textureRectangle) 00677 { 00678 if (textureDimension >= targetTextureSize) // the texture dimension is greater than the target texture size (i.e., it fits) 00679 return targetTextureSize; // return corresponding texture size 00680 else 00681 return textureDimension; // jusr return the dimension 00682 } 00683 else 00684 { 00685 do // while we have txture sizes check for texture value being equal or greater 00686 { 00687 if (textureDimension >= targetTextureSize) // the texture dimension is greater than the target texture size (i.e., it fits) 00688 return targetTextureSize; // return corresponding texture size 00689 } 00690 while (targetTextureSize >>= 1); // step down to next texture size smaller 00691 } 00692 return 0; // no textures fit so return zero 00693 } 00694 00695 // --------------------------------- 00696 00697 // returns the nuber of textures need to represent a size of textureDimension given 00698 // requirement for power of 2 textures as the maximum texture size 00699 // for the overlap case each texture effectively covers two less pixels so must iterate through using whole statement 00700 00701 static long GetTextureNumFromTextureDim (long textureDimension, long maxTextureSize, Boolean texturesOverlap, Boolean textureRectangle) 00702 { 00703 // start at max texture size 00704 // loop through each texture size, removing textures in turn which are less than the remaining texture dimension 00705 // each texture has 2 pixels of overlap (one on each side) thus effective texture removed is 2 less than texture size 00706 00707 long i = 0; // initially no textures 00708 long bitValue = maxTextureSize; // start at max texture size 00709 long texOverlapx2 = texturesOverlap ? 2 : 0; 00710 textureDimension -= texOverlapx2; // ignore texture border since we are using effective texure size (by subtracting 2 from the initial size) 00711 if (textureRectangle) 00712 { 00713 // count number of full textures 00714 while (textureDimension > (bitValue - texOverlapx2)) // while our texture dimension is greater than effective texture size (i.e., minus the border) 00715 { 00716 i++; // count a texture 00717 textureDimension -= bitValue - texOverlapx2; // remove effective texture size 00718 } 00719 // add one partial texture 00720 i++; 00721 } 00722 else 00723 { 00724 do 00725 { 00726 while (textureDimension >= (bitValue - texOverlapx2)) // while our texture dimension is greater than effective texture size (i.e., minus the border) 00727 { 00728 i++; // count a texture 00729 textureDimension -= bitValue - texOverlapx2; // remove effective texture size 00730 } 00731 } 00732 while ((bitValue >>= 1) > texOverlapx2); // step down to next texture while we are greater than two (less than 4 can't be used due to 2 pixel overlap) 00733 if (textureDimension > 0x0) // if any textureDimension is left there is an error, because we can't texture these small segments and in anycase should not have image pixels left 00734 ReportErrorNum ("GetTextureNumFromTextureDim error: Texture to small to draw, should not ever get here, texture size remaining:", textureDimension); 00735 } 00736 return i; // return textures counted 00737 } 00738 00739 #pragma mark - 00740 // ================================== 00741 // public 00742 00743 // disposes OpenGL context, and associated texture list 00744 00745 OSStatus DisposeGLForWindow (WindowRef window) 00746 { 00747 if (window) 00748 { 00749 pRecImage pWindowInfo = (pRecImage) GetWRefCon (window); // get gl data stored in refcon 00750 SetWRefCon (window, 0); // ensure the refcon is not used again 00751 if (NULL == pWindowInfo) // if this is non-existant 00752 return paramErr; // then drop out 00753 if (NULL != pWindowInfo->aglContext) 00754 { 00755 aglSetCurrentContext (pWindowInfo->aglContext); // ensaure the context we are working with is set to current 00756 aglUpdateContext (pWindowInfo->aglContext); // ensaure the context we are working with is set to current 00757 glFinish (); // ensure all gl commands are complete 00758 glDeleteTextures (pWindowInfo->textureX * pWindowInfo->textureY, pWindowInfo->pTextureName); // delete the complete set of textures used for the window 00759 DestroyGLFromWindow (&pWindowInfo->aglContext, &pWindowInfo->glInfo); // preoperly destroy GL context and any associated structures 00760 pWindowInfo->aglContext = NULL; // ensure we don't use invlad context 00761 } 00762 if (NULL != pWindowInfo->pTextureName) 00763 { 00764 DisposePtr ((Ptr) pWindowInfo->pTextureName); // dispose of the allocate4d texture name storage 00765 pWindowInfo->pTextureName = NULL; // ensure we do not use it again 00766 } 00767 if (pWindowInfo->pImageBuffer) // MUST preserve the buffer if texturing from client memory 00768 { 00769 //DisposePtr ((Ptr) pWindowInfo->pImageBuffer); // or image buffer 00770 pWindowInfo->pImageBuffer = NULL; 00771 } 00772 DisposePtr ((Ptr) pWindowInfo); 00773 return noErr; // we are good to go 00774 } 00775 else 00776 return paramErr; // NULL window ref passed in 00777 } 00778 00779 // --------------------------------- 00780 00781 // builds the GL context and associated state for the window 00782 // loads image into a texture or textures 00783 // disposes of GWorld and image buffer when finished loading textures 00784 00785 OSStatus BuildGLForWindow (WindowRef window) 00786 { 00787 GrafPtr portSave = NULL; // port which is set on entrance to this routine 00788 pRecImage pWindowInfo = (pRecImage) GetWRefCon (window); // the info structure for the window stored in the refcon 00789 short i; // iterator 00790 GLenum textureTarget = GL_TEXTURE_2D; 00791 00792 if (!pWindowInfo->aglContext) // if we get here and do not have a context built, build one 00793 { 00794 GetPort (&portSave); // save current port 00795 SetPort ((GrafPtr) GetWindowPort (window)); // set port to the current window 00796 // set parameters for Carbon SetupGL 00797 pWindowInfo->glInfo.fAcceleratedMust = false; // must renderer be accelerated? 00798 pWindowInfo->glInfo.VRAM = 0 * 1048576; // minimum VRAM (if not zero this is always required) 00799 pWindowInfo->glInfo.textureRAM = 0 * 1048576; // minimum texture RAM (if not zero this is always required) 00800 pWindowInfo->glInfo.fDraggable = true; // is this a draggable window 00801 pWindowInfo->glInfo.fmt = 0; // output pixel format 00802 00803 i = 0; // first attribute in array 00804 pWindowInfo->glInfo.aglAttributes [i++] = AGL_RGBA; // RGB + Alpha pixels 00805 pWindowInfo->glInfo.aglAttributes [i++] = AGL_DOUBLEBUFFER; // doble buffered context 00806 pWindowInfo->glInfo.aglAttributes [i++] = AGL_ACCELERATED; // require hardware acceleration 00807 pWindowInfo->glInfo.aglAttributes [i++] = AGL_NO_RECOVERY; // 10.0.4 has problems with the GL (disregards UNPACK_ROW_LENGTH) resulting from using no recovery 00808 // normally we would use no recovery to ensure the minimum pixel size textures are stored by GL. 00809 pWindowInfo->glInfo.aglAttributes [i++] = AGL_NONE; // end parameter list 00810 BuildGLonWindow (window, &(pWindowInfo->aglContext), &(pWindowInfo->glInfo), NULL); // build opengl context for our window 00811 if (!pWindowInfo->aglContext) // if could not create context 00812 DestroyGLFromWindow (&pWindowInfo->aglContext, &pWindowInfo->glInfo); // ensure context is destroyed correctly 00813 else // we have a valid context 00814 { 00815 GLint swap = 0; // swap interval (i.e., VBL sync) setting 1 = sync, 0 = no sync 00816 Rect rectPort; // window port rectangle 00817 long width = pWindowInfo->imageWidth, height = pWindowInfo->imageHeight; // image width and height 00818 GDHandle device; // GDevice to find the constrain the window to 00819 Rect deviceRect, availRect, rect; // rect of device which window is on (mostly, area wise at least). avialable area for window (minus dock and menu if req), working rect 00820 00821 GetWindowGreatestAreaDevice (window, kWindowContentRgn, &device, &deviceRect); // find device the window is mostly on 00822 GetAvailableWindowPositioningBounds (device, &availRect); // get the geretest available area for te windoew (mminus doc and menu if applicable) 00823 if (width > (availRect.right - availRect.left)) // adjust window width if it is greater than available area (orginally set to image width, see above) 00824 width = (availRect.right - availRect.left); 00825 if (height > (availRect.bottom - availRect.top)) // adjust window height if it is greater than available area (orginally set to image width, see above) 00826 height = (availRect.bottom - availRect.top); 00827 SizeWindow (window, (short) width, (short) height, true); // size the window to new width and height 00828 ConstrainWindowToScreen(window, kWindowStructureRgn, kWindowConstrainMayResize, NULL, &rect); // ensure window structure region is on the screen 00829 GetWindowPortBounds (window, &rectPort); // get port rect for viewport reset 00830 00831 aglSetCurrentContext (pWindowInfo->aglContext); // set our GL context to this one 00832 aglUpdateContext (pWindowInfo->aglContext); // update the context to account for the resize 00833 InvalWindowRect (window, &rectPort); // inval the entire window to ensure we get a redraw 00834 glViewport (0, 0, rectPort.right - rectPort.left, rectPort.bottom - rectPort.top); // reset viewport to entier window area 00835 00836 aglSetInteger (pWindowInfo->aglContext, AGL_SWAP_INTERVAL, &swap); // set swap interval to account for vbl syncing or not 00837 00838 // set correct texture target // if building on 10.0 or 9 this will be undefined 00839 #ifdef GL_TEXTURE_RECTANGLE_EXT 00840 if (pWindowInfo->fNPOTTextures) 00841 textureTarget = GL_TEXTURE_RECTANGLE_EXT; 00842 #endif 00843 00844 // Set texture mapping parameters 00845 glEnable (textureTarget); // enable texturing 00846 00847 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // set clear color buffer to dark gray 00848 glClear (GL_COLOR_BUFFER_BIT); // clear just to color buffer 00849 aglSwapBuffers (pWindowInfo->aglContext); // swap the cleared buffer to front 00850 00851 //GetFNum ("\pMonaco", &fNum); // get font number for named font 00852 //pWindowInfo->fontList = BuildFontGL (pWindowInfo->aglContext, fNum, normal, 9); // build display list for fonts for this context (see aglString for more info) 00853 00854 // if we can use texture rectangle // if building on 10.0 or 9 this will be undefined 00855 #ifdef GL_TEXTURE_RECTANGLE_EXT 00856 if (pWindowInfo->fNPOTTextures) 00857 glEnable(GL_TEXTURE_RECTANGLE_EXT); 00858 #endif 00859 if (pWindowInfo->fAGPTexturing) 00860 glTextureRangeAPPLE(textureTarget, pWindowInfo->textureHeight * pWindowInfo->textureWidth * (pWindowInfo->imageDepth >> 3), pWindowInfo->pImageBuffer); 00861 glPixelStorei (GL_UNPACK_ROW_LENGTH, pWindowInfo->textureWidth); // set image width in groups (pixels), accounts for border this ensures proper image alignment row to row 00862 // get number of textures x and y 00863 // extract the number of horiz. textures needed to tile image 00864 pWindowInfo->textureX = GetTextureNumFromTextureDim (pWindowInfo->textureWidth, pWindowInfo->maxTextureSize, pWindowInfo->fOverlapTextures, pWindowInfo->fNPOTTextures); 00865 // extract the number of horiz. textures needed to tile image 00866 pWindowInfo->textureY = GetTextureNumFromTextureDim (pWindowInfo->textureHeight, pWindowInfo->maxTextureSize, pWindowInfo->fOverlapTextures, pWindowInfo->fNPOTTextures); 00867 pWindowInfo->pTextureName = (GLuint *) NewPtrClear ((long) sizeof (GLuint) * pWindowInfo->textureX * pWindowInfo->textureY); // allocate storage for texture name lists 00868 glGenTextures (pWindowInfo->textureX * pWindowInfo->textureY, pWindowInfo->pTextureName); // generate textures names need to support tiling 00869 { 00870 long x, y, k = 0, offsetY, offsetX = 0, currWidth, currHeight; // texture iterators, texture name iterator, image offsets for tiling, current texture width and height 00871 for (x = 0; x < pWindowInfo->textureX; x++) // for all horizontal textures 00872 { 00873 currWidth = GetNextTextureSize (pWindowInfo->textureWidth - offsetX, pWindowInfo->maxTextureSize, pWindowInfo->fNPOTTextures); // use remaining to determine next texture size 00874 // (basically greatest power of 2 which fits into remaining space) 00875 offsetY = 0; // reset vertical offest for every column 00876 for (y = 0; y < pWindowInfo->textureY; y++) // for all vertical textures 00877 { 00878 // buffer pointer is at base + rows * row size + columns 00879 unsigned char * pBuffer = pWindowInfo->pImageBuffer + 00880 offsetY * pWindowInfo->textureWidth * (pWindowInfo->imageDepth >> 3) + 00881 offsetX * (pWindowInfo->imageDepth >> 3); 00882 currHeight = GetNextTextureSize (pWindowInfo->textureHeight - offsetY, pWindowInfo->maxTextureSize, pWindowInfo->fNPOTTextures); // use remaining to determine next texture size 00883 glBindTexture (textureTarget, pWindowInfo->pTextureName[k++]); 00884 if (pWindowInfo->fAGPTexturing) { 00885 glTexParameterf (textureTarget, GL_TEXTURE_PRIORITY, 0.0f); // AGP texturing 00886 glTexParameteri (textureTarget, GL_TEXTURE_STORAGE_HINT_APPLE, GL_STORAGE_SHARED_APPLE); 00887 } 00888 else 00889 glTexParameterf (textureTarget, GL_TEXTURE_PRIORITY, 1.0f); 00890 00891 #ifdef GL_UNPACK_CLIENT_STORAGE_APPLE 00892 if (pWindowInfo->fClientTextures) 00893 glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, 1); 00894 else 00895 glPixelStorei (GL_UNPACK_CLIENT_STORAGE_APPLE, 0); 00896 #endif 00897 00898 glTexParameteri (textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 00899 glTexParameteri (textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00900 glTexParameteri (textureTarget, GL_TEXTURE_WRAP_S, gpOpenGLCaps->edgeClampParam); 00901 glTexParameteri (textureTarget, GL_TEXTURE_WRAP_T, gpOpenGLCaps->edgeClampParam); 00902 glReportError (); // report any errors so far 00903 glTexImage2D (textureTarget, 0, GL_RGBA, currWidth, currHeight, 0, 00904 GL_BGRA_EXT, pWindowInfo->imageDepth == 32 ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_SHORT_1_5_5_5_REV, 00905 pBuffer); // texture with current width and height at pBuffer location in image buffer with image size as GL_UNPACK_ROW_LENGTH 00906 glReportError (); // report any errors 00907 offsetY += currHeight - 2 * pWindowInfo->fOverlapTextures; // offset in for the amount of texture used, 00908 // since we are overlapping the effective texture used is 2 texels less than texture width 00909 } 00910 offsetX += currWidth - 2 * pWindowInfo->fOverlapTextures; // offset in for the amount of texture used, 00911 // since we are overlapping the effective texture used is 2 texels less than texture width 00912 } 00913 } 00914 if (false == pWindowInfo->fClientTextures) // MUST preserve the buffer if texturing from client memory 00915 { 00916 DisposePtr ((Ptr) pWindowInfo->pImageBuffer); // or image buffer 00917 pWindowInfo->pImageBuffer = NULL; 00918 } 00919 } 00920 SetPort (portSave); //reset port 00921 } 00922 return noErr; // we done 00923 } 00924 00925 // --------------------------------- 00926 00927 // Handle updating context for window moves and resizing 00928 00929 OSStatus ResizeMoveGLWindow (WindowRef window) 00930 { 00931 OSStatus err = noErr; // no errors to start 00932 Rect rectPort; // new port rect 00933 pRecImage pWindowInfo = (pRecImage) GetWRefCon (window); // get GL info; 00934 if (window && pWindowInfo) // if we have a window 00935 { 00936 GetWindowPortBounds (window, &rectPort); 00937 pWindowInfo->zoomX = (float) (rectPort.right - rectPort.left) / (float) pWindowInfo->imageWidth; 00938 pWindowInfo->zoomY = (float) (rectPort.bottom - rectPort.top) / (float) pWindowInfo->imageHeight; 00939 00940 if (!aglUpdateContext (pWindowInfo->aglContext)) // update the context to ensure gl knows about the move or resize 00941 aglReportError (); // report any error with update context 00942 if (noErr != err) 00943 ReportErrorNum ("ResizeMoveGLWindow error with InvalWindowRect on window: ", err); // should not get erro here, but who knows 00944 err = InvalWindowRect (window, &rectPort); 00945 } 00946 else 00947 err = paramErr; // bad window 00948 return err; // return any error 00949 } 00950 00951 // --------------------------------- 00952 00953 // main GL drawing routine, should be valid window passed in (will setupGL if require). Draw image 00954 00955 void DrawGL (WindowRef window) 00956 { 00957 Rect rectPort; // rectangle for port 00958 pRecImage pWindowInfo; // the gl info for the target window 00959 long width, height; // width and height or the port and the row of the raster position 00960 long effectiveTextureMod = 0; // texture size modification (inset) to account for borders 00961 long x, y, k = 0, offsetY, offsetX = 0, currTextureWidth, currTextureHeight; 00962 GLenum textureTarget = GL_TEXTURE_2D; 00963 00964 if (NULL == window) // if we do not have a window 00965 return; // drop out 00966 pWindowInfo = (pRecImage) GetWRefCon (window); // get the gl info for the window 00967 if (NULL == pWindowInfo) // if this is non-existant 00968 return; // then drop out 00969 if (NULL == pWindowInfo->aglContext) // try to buld the context if we don't have one (safety check) 00970 BuildGLForWindow (window); 00971 if (NULL == pWindowInfo->aglContext) // if we still don't have one then drop out 00972 return; 00973 00974 if (pWindowInfo->fOverlapTextures) 00975 effectiveTextureMod = 2; // if we overlap then we need to inset the textures passed to the drawing code 00976 // set texture target 00977 #ifdef GL_TEXTURE_RECTANGLE_EXT 00978 if (pWindowInfo->fNPOTTextures) 00979 textureTarget = GL_TEXTURE_RECTANGLE_EXT; 00980 #endif 00981 00982 aglSetCurrentContext (pWindowInfo->aglContext); // ensaure the context we are working with is set to current 00983 aglUpdateContext (pWindowInfo->aglContext); // ensaure the context we are working with is set to current 00984 00985 GetWindowPortBounds (window, &rectPort); // get the current port (window) bounds 00986 width = rectPort.right - rectPort.left; // find width 00987 height = rectPort.bottom - rectPort.top; // and height 00988 glViewport (0, 0, width, height); // set the viewport to cover entire window 00989 00990 glMatrixMode (GL_PROJECTION); // set projection matrix 00991 glLoadIdentity (); // to indetity 00992 glMatrixMode (GL_MODELVIEW); // set modelview matrix 00993 glLoadIdentity (); // to identity 00994 glReportError (); // report any GL errors so far 00995 00996 // set the model view matrix for an orthographic view scaled to one screen pixel equal image pixel (independent of image zoom) 00997 glScalef (2.0f / width, -2.0f / height, 1.0f); // scale to port per pixel scale 00998 //glTranslatef (pWindowInfo->centerX, pWindowInfo->centerY, 0.0f); // translate for image movement 00999 //glRotatef (0.0f, 0.0f, 0.0f, 1.0f); // ratate matrix for image rotation 01000 glReportError (); // report any GL errors 01001 01002 glClear (GL_COLOR_BUFFER_BIT); // clear the color buffer before drawing 01003 01004 // draw image 01005 glEnable (textureTarget); // enable texturing 01006 glColor3f (1.0f, 1.0f, 1.0f); // white polygons 01007 // offset x and y are used to draw the polygon and need to represent the texture effective edges (without borders) 01008 // so walk the texture size images adjusting for each border 01009 for (x = 0; x < pWindowInfo->textureX; x++) // for all horizontal textures 01010 { 01011 // use remaining to determine next texture size 01012 currTextureWidth = GetNextTextureSize (pWindowInfo->textureWidth - offsetX, pWindowInfo->maxTextureSize, pWindowInfo->fNPOTTextures) - effectiveTextureMod; // current effective texture width for drawing 01013 offsetY = 0; // start at top 01014 for (y = 0; y < pWindowInfo->textureY; y++) // for a complete column 01015 { 01016 // use remaining to determine next texture size 01017 currTextureHeight = GetNextTextureSize (pWindowInfo->textureHeight - offsetY, pWindowInfo->maxTextureSize, pWindowInfo->fNPOTTextures) - effectiveTextureMod; // effective texture height for drawing 01018 glBindTexture(textureTarget, pWindowInfo->pTextureName[k++]); // work through textures in same order as stored, setting each texture name as current in turn 01019 if (!pWindowInfo->fAGPTexturing) 01020 glTexSubImage2D(textureTarget, 0, 0, 0, currTextureWidth, currTextureHeight, GL_BGRA, pWindowInfo->imageDepth == 32 ? GL_UNSIGNED_INT_8_8_8_8_REV : GL_UNSIGNED_SHORT_1_5_5_5_REV, pWindowInfo->pImageBuffer); 01021 glReportError (); // report any errors 01022 { 01023 float endX = pWindowInfo->fTileTextures ? currTextureWidth + offsetX : pWindowInfo->imageWidth; 01024 float endY = pWindowInfo->fTileTextures ? currTextureHeight + offsetY : pWindowInfo->imageHeight; 01025 float startXDraw = (offsetX - pWindowInfo->imageWidth * 0.5f) * pWindowInfo->zoomX; // left edge of poly: offset is in image local coordinates convert to world coordinates 01026 float endXDraw = (endX - pWindowInfo->imageWidth * 0.5f) * pWindowInfo->zoomX; // right edge of poly: offset is in image local coordinates convert to world coordinates 01027 float startYDraw = (offsetY - pWindowInfo->imageHeight * 0.5f) * pWindowInfo->zoomY; // top edge of poly: offset is in image local coordinates convert to world coordinates 01028 float endYDraw = (endY - pWindowInfo->imageHeight * 0.5f) * pWindowInfo->zoomY; // bottom edge of poly: offset is in image local coordinates convert to world coordinates 01029 float texOverlap = pWindowInfo->fOverlapTextures ? 1.0f : 0.0f; // size of texture overlap, switch based on whether we are using overlap or not 01030 float startXTexCoord = texOverlap / (currTextureWidth + 2.0f * texOverlap); // texture right edge coordinate (stepped in one pixel for border if required) 01031 float endXTexCoord = 1.0f - startXTexCoord; // texture left edge coordinate (stepped in one pixel for border if required) 01032 float startYTexCoord = texOverlap / (currTextureHeight + 2.0f * texOverlap); // texture top edge coordinate (stepped in one pixel for border if required) 01033 float endYTexCoord = 1.0f - startYTexCoord; // texture bottom edge coordinate (stepped in one pixel for border if required) 01034 if (pWindowInfo->fNPOTTextures) 01035 { 01036 startXTexCoord = texOverlap; // texture right edge coordinate (stepped in one pixel for border if required) 01037 endXTexCoord = currTextureWidth + texOverlap; // texture left edge coordinate (stepped in one pixel for border if required) 01038 startYTexCoord = texOverlap; // texture top edge coordinate (stepped in one pixel for border if required) 01039 endYTexCoord = currTextureHeight + texOverlap; // texture bottom edge coordinate (stepped in one pixel for border if required) 01040 } 01041 if (endX > (pWindowInfo->imageWidth + 0.5)) // handle odd image sizes, (+0.5 is to ensure there is no fp resolution problem in comparing two fp numbers) 01042 { 01043 endXDraw = (pWindowInfo->imageWidth * 0.5f) * pWindowInfo->zoomX; // end should never be past end of image, so set it there 01044 if (pWindowInfo->fNPOTTextures) 01045 endXTexCoord -= 1.0f; 01046 else 01047 endXTexCoord = 1.0f - 2.0f * startXTexCoord; // for the last texture in odd size images there are two texels of padding so step in 2 01048 } 01049 if (endY > (pWindowInfo->imageHeight + 0.5f)) // handle odd image sizes, (+0.5 is to ensure there is no fp resolution problem in comparing two fp numbers) 01050 { 01051 endYDraw = (pWindowInfo->imageHeight * 0.5f) * pWindowInfo->zoomY; // end should never be past end of image, so set it there 01052 if (pWindowInfo->fNPOTTextures) 01053 endYTexCoord -= 1.0f; 01054 else 01055 endYTexCoord = 1.0f - 2.0f * startYTexCoord; // for the last texture in odd size images there are two texels of padding so step in 2 01056 } 01057 01058 glBegin (GL_TRIANGLE_STRIP); // draw either tri strips of line strips 01059 glTexCoord2f (startXTexCoord, startYTexCoord); // draw upper left in world coordinates 01060 glVertex3d (startXDraw, startYDraw, 0.0); 01061 01062 glTexCoord2f (endXTexCoord, startYTexCoord); // draw lower left in world coordinates 01063 glVertex3d (endXDraw, startYDraw, 0.0); 01064 01065 glTexCoord2f (startXTexCoord, endYTexCoord); // draw upper right in world coordinates 01066 glVertex3d (startXDraw, endYDraw, 0.0); 01067 01068 glTexCoord2f (endXTexCoord, endYTexCoord); // draw lower right in world coordinates 01069 glVertex3d (endXDraw, endYDraw, 0.0); 01070 glEnd(); 01071 01072 } 01073 01075 01076 glReportError (); // report any errors 01077 offsetY += currTextureHeight; // offset drawing position for next texture vertically 01078 } 01079 offsetX += currTextureWidth; // offset drawing position for next texture horizontally 01080 } 01081 glReportError (); // report any errors 01082 01083 glDisable (textureTarget); // done with texturing 01084 01085 aglSwapBuffers (pWindowInfo->aglContext); 01086 } 01087 01088 // finds the minimum OpenGL capabilites across all displays and GPUs attached to machine. 01089 01090 static void FindMinimumOpenGLCapabilities (pRecGLCap pOpenGLCaps) 01091 { 01092 WindowPtr pWin = NULL; 01093 Rect rectWin = {0, 0, 10, 10}; 01094 GLint attrib[] = { AGL_RGBA, AGL_NONE }; 01095 AGLPixelFormat fmt = NULL; 01096 AGLContext ctx = NULL; 01097 GLint deviceMaxTextureSize = 0, NPOTDMaxTextureSize = 0; 01098 01099 if (NULL != gpOpenGLCaps) 01100 { 01101 // init desired caps to max values 01102 pOpenGLCaps->f_ext_texture_rectangle = true; 01103 pOpenGLCaps->f_ext_client_storage = true; 01104 pOpenGLCaps->f_ext_packed_pixel = true; 01105 pOpenGLCaps->f_ext_texture_edge_clamp = true; 01106 pOpenGLCaps->f_gl_texture_edge_clamp = true; 01107 pOpenGLCaps->maxTextureSize = 0x7FFFFFFF; 01108 pOpenGLCaps->maxNOPTDTextureSize = 0x7FFFFFFF; 01109 01110 // build window 01111 pWin = NewCWindow (0L, &rectWin, NULL, false, 01112 plainDBox, (WindowPtr) -1L, true, 0L); 01113 01114 // build context 01115 fmt = aglChoosePixelFormat(NULL, 0, attrib); 01116 if (fmt) 01117 ctx = aglCreateContext(fmt, NULL); 01118 if (ctx) 01119 { 01120 GDHandle hgdNthDevice; 01121 01122 aglSetDrawable(ctx, GetWindowPort (pWin)); 01123 aglSetCurrentContext(ctx); 01124 01125 // for each display 01126 hgdNthDevice = GetDeviceList (); 01127 while (hgdNthDevice) 01128 { 01129 if (TestDeviceAttribute (hgdNthDevice, screenDevice)) 01130 if (TestDeviceAttribute (hgdNthDevice, screenActive)) 01131 { 01132 // move window to display 01133 MoveWindow (pWin, (**hgdNthDevice).gdRect.left + 5, (**hgdNthDevice).gdRect.top + 5, false); 01134 aglUpdateContext(ctx); 01135 01136 // for each cap (this can obviously be expanded) 01137 // if this driver/GPU/display is less capable 01138 // save this minimum capability 01139 { 01140 // get strings 01141 enum { kShortVersionLength = 32 }; 01142 const GLubyte * strVersion = glGetString (GL_VERSION); // get version string 01143 const GLubyte * strExtension = glGetString (GL_EXTENSIONS); // get extension string 01144 01145 // get just the non-vendor specific part of version string 01146 GLubyte strShortVersion [kShortVersionLength]; 01147 short i = 0; 01148 while ((((strVersion[i] <= '9') && (strVersion[i] >= '0')) || (strVersion[i] == '.')) && (i < kShortVersionLength)) // get only basic version info (until first space) 01149 strShortVersion [i] = strVersion[i++]; 01150 strShortVersion [i] = 0; //truncate string 01151 01152 // compare capabilities based on extension string and GL version 01153 pOpenGLCaps->f_ext_texture_rectangle = 01154 pOpenGLCaps->f_ext_texture_rectangle && (NULL != strstr ((const char *) strExtension, "GL_EXT_texture_rectangle")); 01155 pOpenGLCaps->f_ext_client_storage = 01156 pOpenGLCaps->f_ext_client_storage && (NULL != strstr ((const char *) strExtension, "GL_APPLE_client_storage")); 01157 pOpenGLCaps->f_ext_packed_pixel = 01158 pOpenGLCaps->f_ext_packed_pixel && (NULL != strstr ((const char *) strExtension, "GL_APPLE_packed_pixel")); 01159 pOpenGLCaps->f_ext_texture_edge_clamp = 01160 pOpenGLCaps->f_ext_texture_edge_clamp && (NULL != strstr ((const char *) strExtension, "GL_SGIS_texture_edge_clamp")); 01161 pOpenGLCaps->f_gl_texture_edge_clamp = 01162 pOpenGLCaps->f_gl_texture_edge_clamp && (!strstr ((const char *) strShortVersion, "1.0") && !strstr ((const char *) strShortVersion, "1.1")); // if not 1.0 and not 1.1 must be 1.2 or greater 01163 01164 // get device max texture size 01165 glGetIntegerv (GL_MAX_TEXTURE_SIZE, &deviceMaxTextureSize); 01166 if (deviceMaxTextureSize < pOpenGLCaps->maxTextureSize) 01167 pOpenGLCaps->maxTextureSize = deviceMaxTextureSize; 01168 // get max size of non-power of two texture on devices which support 01169 if (NULL != strstr ((const char *) strExtension, "GL_EXT_texture_rectangle")) 01170 { 01171 #ifdef GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT 01172 glGetIntegerv (GL_MAX_RECTANGLE_TEXTURE_SIZE_EXT, &NPOTDMaxTextureSize); 01173 if (NPOTDMaxTextureSize < pOpenGLCaps->maxNOPTDTextureSize) 01174 pOpenGLCaps->maxNOPTDTextureSize = NPOTDMaxTextureSize; 01175 #endif 01176 } 01177 } 01178 // next display 01179 hgdNthDevice = GetNextDevice(hgdNthDevice); 01180 } 01181 } 01182 aglDestroyContext( ctx ); 01183 } 01184 else 01185 { // could not build context set caps to min 01186 pOpenGLCaps->f_ext_texture_rectangle = false; 01187 pOpenGLCaps->f_ext_client_storage = false; 01188 pOpenGLCaps->f_ext_packed_pixel = false; 01189 pOpenGLCaps->f_ext_texture_edge_clamp = false; 01190 pOpenGLCaps->f_gl_texture_edge_clamp = false; 01191 pOpenGLCaps->maxTextureSize = 0; 01192 } 01193 01194 // set clamp param based on retrieved capabilities 01195 if (pOpenGLCaps->f_gl_texture_edge_clamp) // if OpenGL 1.2 or later and texture edge clamp is supported natively 01196 pOpenGLCaps->edgeClampParam = GL_CLAMP_TO_EDGE; // use 1.2+ constant to clamp texture coords so as to not sample the border color 01197 else if (pOpenGLCaps->f_ext_texture_edge_clamp) // if GL_SGIS_texture_edge_clamp extension supported 01198 pOpenGLCaps->edgeClampParam = GL_CLAMP_TO_EDGE_SGIS; // use extension to clamp texture coords so as to not sample the border color 01199 else 01200 pOpenGLCaps->edgeClampParam = GL_CLAMP; // clamp texture coords to [0, 1] 01201 01202 aglDestroyPixelFormat( fmt ); 01203 DisposeWindow( pWin ); 01204 } 01205 } 01206 01207 //-------------------------------------------------------------------------------------------- 01208 01209 static OSStatus 01210 WindowEventHandler( EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon ) 01211 { 01212 OSStatus err = eventNotHandledErr; 01213 WindowRef window = (WindowRef) inRefcon; 01214 01215 if( GetEventClass(inEvent) == kEventClassMouse ) 01216 { 01217 Point mousePoint; // UInt32 modifiers; 01218 verify_noerr( GetEventParameter(inEvent, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &mousePoint) ); 01219 pRecImage pWindowInfo = (pRecImage) GetWRefCon (window); // get the gl info for the window 01220 if(pWindowInfo) { 01221 SetPortWindowPort(window); 01222 GlobalToLocal (&mousePoint); //convert mouse coordinates to local coordintes prior to recording 01223 mousePoint.h /= pWindowInfo->zoomX; mousePoint.v /= pWindowInfo->zoomY; 01224 if(mousePoint.h >= 0 && mousePoint.h < pWindowInfo->imageWidth && mousePoint.v >= 0 && mousePoint.v < pWindowInfo->imageHeight) 01225 g_video->on_mouse(mousePoint.h, mousePoint.v, GetEventKind(inEvent) == kEventMouseUp?-1:1), err = noErr; 01226 } 01227 } 01228 else if( GetEventClass(inEvent) == kEventClassKeyboard ) 01229 { 01230 char ch; 01231 verify_noerr( GetEventParameter( inEvent, kEventParamKeyMacCharCodes, typeChar, NULL, sizeof( ch ), NULL, &ch ) ); 01232 if(g_video) 01233 g_video->on_key(ch); 01234 } 01235 else //if( GetEventClass(inEvent) == kEventClassWindow ) 01236 { 01237 if (GetEventKind(inEvent) == kEventWindowDrawContent) 01238 { 01239 //DrawGL(window); 01240 err = noErr; 01241 } 01242 else if (GetEventKind(inEvent) == kEventWindowClose) 01243 { 01244 if (window) 01245 { 01246 g_video->running = false; 01247 } 01248 err = noErr; 01249 } 01250 else if (GetEventKind(inEvent) == kEventWindowShowing) 01251 { 01252 err = BuildGLForWindow (window); 01253 } 01254 else if ((GetEventKind(inEvent) == kEventWindowResizeCompleted) || (GetEventKind(inEvent) == kEventWindowDragCompleted)) 01255 { 01256 err = ResizeMoveGLWindow (window); 01257 } 01258 else if (GetEventKind(inEvent) == kEventWindowZoomed) 01259 { 01260 err = ResizeMoveGLWindow (window); 01261 } 01262 } 01263 01264 return err; 01265 } 01266 //-------------------------------------------------------------------------------------------- 01267 DEFINE_ONE_SHOT_HANDLER_GETTER( WindowEventHandler ) 01268 01269 //-------------------------------------------------------------------------------------------- 01270 WindowRef HandleNew() 01271 { 01272 OSStatus err; 01273 WindowRef window; 01274 pRecImage pWindowInfo = NULL; 01275 static const EventTypeSpec kWindowEvents[] = 01276 { 01277 { kEventClassMouse, kEventMouseUp }, 01278 { kEventClassMouse, kEventMouseDown }, 01279 { kEventClassKeyboard, kEventRawKeyDown }, 01280 // { kEventClassCommand, kEventCommandProcess }, 01281 { kEventClassWindow, kEventWindowShowing }, 01282 { kEventClassWindow, kEventWindowClose }, 01283 { kEventClassWindow, kEventWindowDrawContent }, 01284 { kEventClassWindow, kEventWindowResizeCompleted }, 01285 { kEventClassWindow, kEventWindowDragCompleted }, 01286 { kEventClassWindow, kEventWindowZoomed} 01287 }; 01288 if (!gpOpenGLCaps) 01289 { 01290 gpOpenGLCaps = (pRecGLCap) NewPtrClear (sizeof (recGLCap)); 01291 FindMinimumOpenGLCapabilities (gpOpenGLCaps); 01292 } 01293 01294 // Create a window. "MainWindow" is the name of the window object. This name is set in 01295 // InterfaceBuilder when the nib is created. 01296 err = CreateWindowFromNib( sNibRef, CFSTR("MainWindow"), &window ); 01297 require_noerr( err, CantCreateWindow ); 01298 // We don't need the nib reference anymore. 01299 DisposeNibReference(sNibRef); 01300 01301 pWindowInfo = (recImage *) NewPtrClear (sizeof (recImage)); 01302 pWindowInfo->textureWidth = pWindowInfo->imageWidth = g_sizex; 01303 pWindowInfo->textureHeight = pWindowInfo->imageHeight = g_sizey; 01304 pWindowInfo->imageDepth = 32; 01305 pWindowInfo->fTileTextures = true; 01306 pWindowInfo->fOverlapTextures = false; // TODO: ??? 01307 pWindowInfo->maxTextureSize = gpOpenGLCaps->maxTextureSize; 01308 pWindowInfo->fNPOTTextures = gpOpenGLCaps->f_ext_texture_rectangle; 01309 pWindowInfo->fClientTextures = gpOpenGLCaps->f_ext_client_storage; // texture from client memory if available 01310 pWindowInfo->fAGPTexturing = false; // if AGP texturing selected 01311 pWindowInfo->pImageBuffer = (unsigned char*) g_pImg; 01312 // set default parameters for this image 01313 pWindowInfo->zoomX = 1.0f; // pixel 1 to 1 size 01314 pWindowInfo->zoomY = 1.0f; // pixel 1 to 1 size 01315 SetWRefCon (window, (long) pWindowInfo); 01316 char buffer[256]; buffer[0] = snprintf(buffer+1, 255, "%s", g_video->title); 01317 SetWTitle (window, (ConstStr255Param)buffer); 01318 // Install a command handler on the window. We don't use this handler yet, but nearly all 01319 // Carbon apps will need to handle commands, so this saves everyone a little typing. 01320 InstallStandardEventHandler(GetWindowEventTarget(window)); 01321 InstallWindowEventHandler( window, GetWindowEventHandlerUPP(), 01322 GetEventTypeCount( kWindowEvents ), kWindowEvents, window, NULL ); 01323 if (noErr != BuildGLForWindow (window)) 01324 { 01325 DisposeGLForWindow (window); 01326 DisposeWindow (window); 01327 return 0; 01328 } 01329 01330 // Position new windows in a staggered arrangement on the main screen 01331 RepositionWindow( window, NULL, kWindowCascadeOnMainScreen ); 01332 01333 // The window was created hidden, so show it 01334 ShowWindow( window ); 01335 return window; 01336 01337 CantCreateWindow: 01338 return 0; 01339 } 01340 01341 01342 //-------------------------------------------------------------------------------------------- 01343 static OSStatus 01344 AppEventHandler( EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon ) 01345 { 01346 OSStatus result = eventNotHandledErr; 01347 01348 return result; 01349 } 01350 01351 //======================================================================================================= 01352 01353 video::video() 01354 : red_mask(0xff0000), red_shift(16), green_mask(0xff00), 01355 green_shift(8), blue_mask(0xff), blue_shift(0), depth(24) 01356 { 01357 assert(g_video == 0); 01358 g_video = this; title = "Video"; updating = true; calc_fps = false; 01359 } 01360 01361 bool video::init_window(int x, int y) 01362 { 01363 g_sizex = x; g_sizey = y; g_window = 0; 01364 g_pImg = new unsigned int[x*y]; 01365 01366 // Check for graphics availability 01367 if( CGGetOnlineDisplayList(0, NULL, NULL) ) { 01368 running = true; // console mode 01369 return false; 01370 } 01371 01372 OSStatus err; 01373 static const EventTypeSpec kAppEvents[] = 01374 { 01375 { kEventClassCommand, kEventCommandProcess } 01376 }; 01377 01378 // Create a Nib reference, passing the name of the nib file (without the .nib extension). 01379 // CreateNibReference only searches into the application bundle. 01380 err = CreateNibReference( CFSTR("main"), &sNibRef ); 01381 require_noerr( err, ReturnLabel ); 01382 01383 // Install our handler for common commands on the application target 01384 // Register for standard event handlers 01385 InstallStandardEventHandler(GetApplicationEventTarget()); // Doesn't work? 01386 verify_noerr( InstallApplicationEventHandler( NewEventHandlerUPP( AppEventHandler ), 01387 GetEventTypeCount( kAppEvents ), kAppEvents, 0, NULL ) ); 01388 01389 // Once the nib reference is created, set the menu bar. "MainMenu" is the name of the menu bar 01390 // object. This name is set in InterfaceBuilder when the nib is created. 01391 //err = SetMenuBarFromNib( sNibRef, CFSTR("MenuBar") ); 01392 //require_noerr( err, ReturnLabel ); 01393 InstallStandardEventHandler(GetMenuEventTarget(AcquireRootMenu())); 01394 01395 // Create a new window. A full-fledged application would do this from an AppleEvent handler for kAEOpenApplication. 01396 g_window = HandleNew(); 01397 01398 ReturnLabel: 01399 return running = g_window != 0; 01400 } 01401 01402 bool video::init_console() 01403 { 01404 running = true; 01405 return true; 01406 } 01407 01408 void video::terminate() 01409 { 01410 g_video = 0; running = false; 01411 if(g_pImg) { delete[] g_pImg; g_pImg = 0; } 01412 if(g_window) { 01413 DisposeGLForWindow (g_window); 01414 DisposeWindow (g_window); 01415 g_window = 0; 01416 } 01417 } 01418 01419 video::~video() 01420 { 01421 if(g_video) terminate(); 01422 } 01423 01425 bool video::next_frame() 01426 { 01427 if(!running) return false; 01428 if(!g_window) return running; 01430 if(threaded && pthread_mutex_trylock(&g_mutex)) 01431 return running; 01432 g_fps++; 01433 struct timezone tz; struct timeval now_time; gettimeofday(&now_time, &tz); 01434 double sec = (now_time.tv_sec+1.0*now_time.tv_usec/1000000.0) - (g_time.tv_sec+1.0*g_time.tv_usec/1000000.0); 01435 if(sec > 1) { 01436 memcpy(&g_time, &now_time, sizeof(g_time)); 01437 if(calc_fps) { 01438 double fps = g_fps; g_fps = 0; 01439 char buffer[256]; buffer[0] = snprintf(buffer+1, 255, "%s%s: %d fps", title, updating?"":" (no updating)", int(fps/sec)); 01440 SetWTitle (g_window, (ConstStr255Param) buffer ); 01441 } 01442 } 01443 01444 EventRef theEvent; 01445 EventTargetRef theTarget; 01446 OSStatus err; 01447 // Run the event loop 01448 01449 theTarget = GetEventDispatcherTarget(); 01450 while( (err = ReceiveNextEvent(0, NULL, kEventDurationNoWait, true, &theEvent)) == noErr) 01451 { 01452 SendEventToEventTarget(theEvent, theTarget); 01453 ReleaseEvent(theEvent); 01454 } 01455 if(err != eventLoopTimedOutErr) running = false; 01456 if(updating) { 01457 pRecImage pWindowInfo = (pRecImage) GetWRefCon (g_window); // get the gl info for the window 01458 if(pWindowInfo) DrawGL(g_window); 01459 } 01460 if(threaded) pthread_mutex_unlock(&g_mutex); 01461 return true; 01462 } 01463 01465 void video::main_loop() 01466 { 01467 struct timezone tz; gettimeofday(&g_time, &tz); 01468 //RunApplicationEventLoop(); -- using another application loop model 01469 on_process(); 01470 } 01471 01473 void video::show_title() 01474 { 01475 char buffer[256]; buffer[0] = snprintf(buffer+1, 255, "%s", title); 01476 SetWTitle (g_window, (ConstStr255Param) buffer ); 01477 } 01478 01480 01481 drawing_area::drawing_area(int x, int y, int sizex, int sizey) 01482 : start_x(x), start_y(y), size_x(sizex), size_y(sizey), pixel_depth(24), 01483 base_index(y*g_sizex + x), max_index(g_sizex*g_sizey), index_stride(g_sizex), ptr32(g_pImg) 01484 { 01485 assert(x < g_sizex); assert(y < g_sizey); 01486 assert(x+sizex <= g_sizex); assert(y+sizey <= g_sizey); 01487 01488 index = base_index; // current index 01489 } 01490 01491 drawing_area::~drawing_area() {}
Copyright © 2007-2010 by The Shadowrun: Awakened Team. This work is licensed under the GNU Lesser General Public License 3.