Max 5 API Reference
00001 // jit.gl.sys.c 00002 // 00003 // 00004 // author: joshua kit clayton 00005 // Copyright 2001-2005 cycling '74 00006 // 00007 00008 /****************************************************************************/ 00009 00010 #include "jit.common.h" 00011 #include "jit.gl.h" 00012 #include "jit.gl.procs.h" 00013 #include "jit.gl.pixelformat.h" 00014 #include "ext_user.h" //for patcher testing 00015 00016 /****************************************************************************/ 00017 00018 static long _jit_gl_sys_inited = 0; 00019 00020 // utilites for win jit_gl_create_context 00021 #ifdef WIN_VERSION 00022 00023 // rbs -- if we ever want to subclass the window, here is the code. 00024 // it turned out we didn't need this complex stuff after all. 00025 #ifdef USE_SUBCLASS_HACK 00026 #include "ext_obex.h" 00027 #include <windowsx.h> // for GET_X_LPARAM 00028 #endif 00029 00030 #include "jit.wglext.h" 00031 #include "jit.glext.h" 00032 00033 #define JIT_GL_WINDCLASSNAME "Jitter Window" 00034 00035 static HINSTANCE _jit_gl_hinst = NULL; 00036 static WNDCLASS _jit_gl_wc; 00037 00038 void copyDIBtoMatrix(t_jit_gl_context ctx); 00039 HWND jit_gl_create_window(HWND hwnd, t_box *rect); 00040 LRESULT CALLBACK jit_gl_windproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); 00041 PROC SpecialWglGetProcAddress(HWND hwnd, char *str); 00042 long WGLisExtensionSupported(const char *extension); 00043 00044 #endif 00045 00046 /****************************************************************************/ 00047 00048 #ifdef WIN_VERSION 00049 00050 #endif // WIN_VERSION 00051 00052 /****************************************************************************/ 00053 00054 /* 00055 * TODO: 00056 * 00057 * Figure out how to eliminate need to use these functions since 00058 * they are not available in the same way on windows. 00059 * need the following for vram query, make it's own function 00060 * 00061 * vram_required 00062 * aglSetRendererInfo 00063 * aglQueryRendererInfo 00064 * aglDescribeRenderer 00065 * aglNextRendererInfo 00066 * aglDestroyRendererInfo 00067 * 00068 * In general, we need to add more renderer querying capabilities 00069 * 00070 * For pwindow on mac, should move the following code into jit.gl.sys.c: 00071 * 00072 * aglEnable (x->agl_context, AGL_CLIP_REGION); 00073 * aglSetInteger (x->agl_context, AGL_CLIP_REGION, (const GLint *)rgn2); 00074 * 00075 */ 00076 00077 /****************************************************************************/ 00078 00079 void jit_gl_sys_init(void) 00080 { 00081 00082 if (_jit_gl_sys_inited) 00083 return ; 00084 00085 #ifdef WIN_VERSION 00086 00087 _jit_gl_hinst = GetModuleHandle(NULL); //is this right? 00088 memset(&_jit_gl_wc, 0, sizeof(WNDCLASS)); 00089 _jit_gl_wc.style = CS_OWNDC; 00090 _jit_gl_wc.lpfnWndProc = jit_gl_windproc; 00091 _jit_gl_wc.hInstance = _jit_gl_hinst; 00092 _jit_gl_wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); 00093 _jit_gl_wc.hCursor = LoadIcon(_jit_gl_hinst, IDC_ARROW); 00094 _jit_gl_wc.hbrBackground = NULL; 00095 _jit_gl_wc.lpszMenuName = NULL; 00096 _jit_gl_wc.lpszClassName = JIT_GL_WINDCLASSNAME; 00097 if (!RegisterClass(&_jit_gl_wc)) 00098 { 00099 error("jit_gl_sys_init: RegisterClass %d", GetLastError()); 00100 } 00101 00102 #endif 00103 _jit_gl_sys_inited = 1; 00104 } 00105 00106 /****************************************************************************/ 00107 00108 GLboolean jit_gl_context_swap_buffers(t_jit_gl_context ctx) 00109 { 00110 #ifdef MAC_VERSION 00111 00112 if (ctx && ctx->context) 00113 { 00114 aglSwapBuffers(ctx->context); 00115 #ifdef JIT_LITTLE_ENDIAN 00116 // byte swap, with temporary matrix 00117 if (ctx->targettype == JIT_GL_TARGET_MATRIX) 00118 { 00119 t_matrix_conv_info mcinfo; 00120 mcinfo.flags = 0; 00121 mcinfo.planemap[0] = 3; 00122 mcinfo.planemap[1] = 2; 00123 mcinfo.planemap[2] = 1; 00124 mcinfo.planemap[3] = 0; 00125 jit_object_method(ctx->auxdata,_jit_sym_frommatrix,ctx->target,&mcinfo); 00126 } 00127 #endif 00128 return TRUE; 00129 } 00130 else 00131 return FALSE; 00132 00133 #endif 00134 #ifdef WIN_VERSION 00135 00136 GLboolean rv = FALSE; 00137 00138 if (ctx) 00139 { 00140 if (ctx->drawable) 00141 rv = SwapBuffers((HDC)ctx->drawable); 00142 00143 if (rv && (ctx->targettype == JIT_GL_TARGET_MATRIX)) 00144 copyDIBtoMatrix(ctx); 00145 } 00146 00147 return rv; 00148 #endif 00149 } 00150 00151 GLboolean jit_gl_configure(GLenum pname, GLuint param) 00152 { 00153 #ifdef MAC_VERSION 00154 return aglConfigure(pname, param); 00155 #endif 00156 #ifdef WIN_VERSION 00157 //WORK???no windows equivalent? we use this for AGL_RETAIN_RENDERERS_FLAG 00158 return TRUE; 00159 #endif 00160 } 00161 00162 long jit_gl_set_swap_interval(t_jit_gl_context ctx, long interval) 00163 { 00164 #ifdef MAC_VERSION 00165 00166 GLint val = interval; 00167 if(!ctx) 00168 return FALSE; 00169 00170 return aglSetInteger(ctx->context, AGL_SWAP_INTERVAL, &val); 00171 00172 #endif // MAC_VERSION 00173 00174 #ifdef WIN_VERSION 00175 00176 static PROC _set_swap_interval = NULL; 00177 static init = 0; 00178 00179 if(!ctx) 00180 return FALSE; 00181 00182 if (!init) 00183 { 00184 jit_gl_set_context(ctx); 00185 _set_swap_interval = wglGetProcAddress("wglSwapIntervalEXT"); 00186 init = 1; 00187 } 00188 00189 if (_set_swap_interval) 00190 _set_swap_interval((int)interval); 00191 00192 return TRUE; 00193 00194 #endif // WIN_VERSION 00195 00196 } 00197 00198 #ifdef WIN_VERSION 00199 00200 #ifdef USE_SUBCLASS_HACK 00201 t_hashtab *s_patcherwind_to_windowdata; 00202 00203 // We want to filter out WM_MOUSELEAVE messages to patcher 00204 // when mouse moves over a GL window. 00205 // For each patcher, we can have more than one GL HWND windows though. 00206 // So, we put each in a list, only subclass the first time, and unsubclass when 00207 // the last window is destroyed. 00208 typedef struct _windowdata 00209 { 00210 HWND w_hwndPatcher; 00211 WNDPROC w_origProc; 00212 BOOL w_ateone; // true if we ate a WM_MOUSELEAVE message 00213 t_linklist *w_glwindows; // list of jit.pwindwow GL HWNDs inside this patcher 00214 } t_windowdata; 00215 00216 LRESULT CALLBACK jit_gl_subclassproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam); 00217 #endif 00218 00219 HWND jit_gl_create_window(HWND hwnd, t_box *box) 00220 { 00221 method meth; 00222 00223 #ifdef USE_SUBCLASS_HACK 00224 if (!s_patcherwind_to_windowdata) { 00225 s_patcherwind_to_windowdata = hashtab_new(0); 00226 } 00227 #endif 00228 00229 if(!box) 00230 return NULL; 00231 00232 if (meth=zgetfn((t_object *)box,gensym("nativeparentwind"))) { 00233 double jr[4]; 00234 HWND hWndNew; 00235 00236 //object_attr_getdouble_array((t_object *)box, gensym("patch_rect"), 4, jr); 00237 object_method((t_object *)box, gensym("patch_rect"), jr); 00238 // rbs -- WS_DISABLED is the key to letting mouse stuff go to our parent window 00239 // actually, with it, our WNDPROC is almost never called as the mouse stuff 00240 // goes straight to our parent. 00241 hWndNew = CreateWindow( 00242 JIT_GL_WINDCLASSNAME, 00243 JIT_GL_WINDCLASSNAME, 00244 WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_DISABLED, 00245 (int)jr[0], (int)jr[1], (int)jr[2], (int)jr[3], 00246 //0, 0, 320, 240, 00247 hwnd, NULL, _jit_gl_hinst, 0 00248 ); 00249 #ifdef USE_SUBCLASS_HACK 00250 if (hWndNew) { 00251 t_windowdata *wd = NULL; 00252 hashtab_lookup(s_patcherwind_to_windowdata, (t_symbol*) hwnd, (t_object**) &wd); 00253 if (!wd) { 00254 // init this entry 00255 wd = (t_windowdata*) sysmem_newptr(sizeof(t_windowdata)); 00256 wd->w_hwndPatcher = hwnd; 00257 wd->w_origProc = (WNDPROC) GetWindowLongPtr(hwnd, GWL_WNDPROC); 00258 wd->w_glwindows = linklist_new(); 00259 wd->w_ateone = FALSE; 00260 SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR) jit_gl_subclassproc); 00261 hashtab_store(s_patcherwind_to_windowdata, (t_symbol*) hwnd, (t_object*) wd); 00262 } 00263 if (wd) { 00264 linklist_append(wd->w_glwindows, (t_object*) hWndNew); 00265 } 00266 } 00267 #endif 00268 if(!hWndNew) { 00269 LPSTR lpMsgBuf; 00270 DWORD dw = GetLastError(); 00271 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 00272 FORMAT_MESSAGE_FROM_SYSTEM | 00273 FORMAT_MESSAGE_IGNORE_INSERTS, 00274 NULL, 00275 dw, 00276 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 00277 (LPSTR)&lpMsgBuf, 00278 0, NULL); 00279 error("error jit_gl_create_window failed to create window: %s", (char *)lpMsgBuf); 00280 } 00281 return hWndNew; 00282 } 00283 else { 00284 error("create window: not using Max 5"); 00285 return 0; 00286 } 00287 } 00288 00289 #ifdef USE_SUBCLASS_HACK 00290 LRESULT CALLBACK jit_gl_subclassproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 00291 { 00292 // we want to trap the WM_MOUSELEAVE messages if mouse is over our window 00293 t_windowdata *wd = NULL; 00294 WNDPROC origproc; 00295 hashtab_lookup(s_patcherwind_to_windowdata, (t_symbol*)hwnd, (t_object**) &wd); 00296 if (wd) { 00297 origproc = wd->w_origProc; // in case we free it below 00298 if (message == WM_PARENTNOTIFY && (LOWORD(wparam) == WM_DESTROY)) { 00299 // remove from list and possibly unsubclass the window 00300 if (wd) { 00301 HWND glwind = (HWND)lparam; 00302 int i, num=linklist_getsize(wd->w_glwindows); 00303 for (i=num-1; i >= 0; i--) { // top down for removal purposes 00304 HWND h = (HWND) linklist_getindex(wd->w_glwindows, i); 00305 if (h == glwind) { 00306 linklist_chuckindex(wd->w_glwindows, i); 00307 } 00308 } 00309 if (!linklist_getsize(wd->w_glwindows)) { 00310 cpost("unsubclassing\n"); 00311 SetWindowLongPtr(hwnd, GWL_WNDPROC, (LONG_PTR) wd->w_origProc); 00312 linklist_chuck(wd->w_glwindows); 00313 hashtab_chuckkey(s_patcherwind_to_windowdata, (t_symbol*) hwnd); 00314 } 00315 } 00316 } 00317 else if ((message == WM_MOUSELEAVE) || ((wd->w_ateone && (message == WM_MOUSEMOVE)))) { 00318 // eat this if the mouse is over one of the GL windows 00319 int i, num = linklist_getsize(wd->w_glwindows); 00320 DWORD pos = GetMessagePos(); 00321 POINT point; 00322 HWND hwndMouseOver; 00323 BOOL overaglwind = FALSE; 00324 point.x = GET_X_LPARAM(pos); 00325 point.y = GET_Y_LPARAM(pos); 00326 hwndMouseOver = WindowFromPoint(point); 00327 for (i=0; i < num; i++) { 00328 HWND glwnd = (HWND) linklist_getindex(wd->w_glwindows, i); 00329 if (hwndMouseOver == glwnd) { 00330 overaglwind = TRUE; 00331 break; 00332 } 00333 } 00334 if (overaglwind && (message == WM_MOUSELEAVE)) { 00335 wd->w_ateone = TRUE; 00336 cpost("eating one\n"); 00337 return 0; 00338 } 00339 if (!overaglwind && (message == WM_MOUSEMOVE)) { 00340 // since we ate one before we sign back up for the leave notification 00341 TRACKMOUSEEVENT tme; 00342 tme.cbSize = sizeof(tme); 00343 tme.dwFlags = TME_LEAVE; 00344 tme.hwndTrack = hwnd; 00345 tme.dwHoverTime = 0; 00346 TrackMouseEvent(&tme); 00347 wd->w_ateone = FALSE; // eat the next one 00348 cpost("signed up again\n"); 00349 } 00350 if (message == WM_MOUSELEAVE) 00351 cpost("not eating it\n"); 00352 } 00353 if (wd && (message == WM_DESTROY)) { 00354 linklist_chuck(wd->w_glwindows); 00355 hashtab_chuckkey(s_patcherwind_to_windowdata, (t_symbol*) hwnd); 00356 } 00357 // otherwise, just pass on 00358 CallWindowProc(origproc, hwnd, message, wparam, lparam); 00359 } 00360 return DefWindowProc(hwnd, message, wparam, lparam); 00361 } 00362 #endif 00363 00364 LRESULT CALLBACK jit_gl_windproc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) 00365 { 00366 HWND parent; 00367 WINDOWINFO pwinfo; 00368 RECT prect; 00369 RECT crect; 00370 short xpos, ypos; 00371 00372 parent = GetParent(hwnd); 00373 00374 switch (message) 00375 { 00376 00377 case WM_LBUTTONDOWN: 00378 00379 case WM_MBUTTONDOWN: 00380 case WM_RBUTTONDOWN: 00381 case WM_LBUTTONUP: 00382 case WM_MBUTTONUP: 00383 case WM_RBUTTONUP: 00384 case WM_MOUSEMOVE: 00385 { 00386 GetWindowInfo(parent, &pwinfo); 00387 prect = pwinfo.rcClient; 00388 GetWindowRect(hwnd, &crect); 00389 xpos = ((int)(short)LOWORD(lparam)) + (crect.left - prect.left); 00390 ypos = ((int)(short)HIWORD(lparam)) + (crect.top - prect.top); 00391 lparam = MAKELPARAM(xpos, ypos); 00392 } 00393 case WM_KEYDOWN: 00394 case WM_KEYUP: 00395 case WM_SYSKEYDOWN: 00396 case WM_SYSKEYUP: 00397 case WM_CHAR: 00398 { 00399 //always a child for now 00400 return SendMessage(parent, message, wparam, lparam); 00401 } 00402 default: 00403 { 00404 return DefWindowProc(hwnd, message, wparam, lparam); 00405 } 00406 } 00407 } 00408 00409 long WGLisExtensionSupported(const char *extension) 00410 { 00411 const size_t extlen = strlen(extension); 00412 char *supported = NULL; 00413 char* p = NULL; 00414 PROC wglGetExtString; 00415 00416 // Try To Use wglGetExtensionStringARB On Current DC, If Possible 00417 wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB"); 00418 00419 if (wglGetExtString) 00420 supported = ((char * (__stdcall*)(HDC))wglGetExtString)(wglGetCurrentDC()); 00421 00422 // If That Failed, Try Standard Opengl Extensions String 00423 if (supported == NULL) 00424 supported = (char*)glGetString(GL_EXTENSIONS); 00425 00426 // If That Failed Too, Must Be No Extensions Supported 00427 if (supported == NULL) 00428 return FALSE; 00429 00430 // Begin Examination At Start Of String, Increment By 1 On False Match 00431 for (p = supported; ; p++) 00432 { 00433 // Advance p Up To The Next Possible Match 00434 p = strstr(p, extension); 00435 00436 if (p == NULL) 00437 return FALSE; // No Match 00438 00439 // Make Sure That Match Is At The Start Of The String Or That 00440 // The Previous Char Is A Space, Or Else We Could Accidentally 00441 // Match "wglFunkywglExtension" With "wglExtension" 00442 00443 // Also, Make Sure That The Following Character Is Space Or NULL 00444 // Or Else "wglExtensionTwo" Might Match "wglExtension" 00445 if ((p == supported || p[ -1] == ' ') && (p[extlen] == '\0' || p[extlen] == ' ')) 00446 return TRUE; // Match 00447 } 00448 } 00449 00450 // this is super lame. with wgl, we need to create a context before we can 00451 // query the renderer to get the renderer's entry points, which is a pain for fsaa. 00452 PROC SpecialWglGetProcAddress(HWND hwnd, char *str) 00453 { 00454 GLboolean ok = FALSE; 00455 long fmt = 0; 00456 HDC hdc = NULL; 00457 HGLRC ctx = NULL; 00458 PIXELFORMATDESCRIPTOR pfd; 00459 PROC p; 00460 00461 if (!hwnd || !str) 00462 return NULL; 00463 00464 //create a dummy sub window + context 00465 hwnd = CreateWindow(JIT_GL_WINDCLASSNAME, JIT_GL_WINDCLASSNAME, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 00466 0, 0, 32, 32, hwnd, NULL, _jit_gl_hinst, 0); 00467 00468 if (!hwnd) 00469 { 00470 //post ("SpecialWglGetProcAddress: could not create window for new gl context!"); 00471 return NULL; 00472 } 00473 00474 //ShowWindow(hwnd,SW_SHOWNORMAL); 00475 hdc = GetDC(hwnd); 00476 00477 if (!hdc) 00478 { 00479 //post ("SpecialWglGetProcAddress: no device for new gl context!"); 00480 return NULL; 00481 } 00482 00483 memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR)); 00484 00485 pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR); 00486 pfd.nVersion = 1; 00487 pfd.dwFlags = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; 00488 pfd.iPixelType = PFD_TYPE_RGBA; 00489 pfd.cColorBits = 32; 00490 pfd.iLayerType = PFD_MAIN_PLANE; 00491 00492 fmt = ChoosePixelFormat(hdc, &pfd); 00493 00494 ok = SetPixelFormat(hdc, fmt, &pfd); 00495 00496 if (!ok) 00497 { 00498 //post("SpecialWglGetProcAddress: SetPixelFormat failed - %d", GetLastError()); 00499 goto out; 00500 } 00501 00502 // Create GL context 00503 ctx = wglCreateContext(hdc); 00504 00505 if (ctx == NULL) 00506 { 00507 //post("SpecialWglGetProcAddress: wglCreateContext failed - %d", GetLastError()); 00508 goto out; 00509 } 00510 00511 // Make the context the current context 00512 SelectClipRgn(hdc, NULL); 00513 00514 ok = wglMakeCurrent(hdc, ctx); 00515 00516 if (!ok) 00517 { 00518 //post("SpecialWglGetProcAddress: wglMakeCurrent failed - %d", GetLastError()); 00519 goto out; 00520 } 00521 00522 p = wglGetProcAddress(str); 00523 00524 out: 00525 00526 if (ctx) 00527 { 00528 wglDeleteContext(ctx); 00529 ctx = NULL; 00530 } 00531 00532 if (hdc) 00533 { 00534 ReleaseDC(hwnd, hdc); 00535 } 00536 00537 if (hwnd) 00538 DestroyWindow(hwnd); 00539 00540 //post("SpecialWglGetProcAddress: %s is %x",str,p); 00541 return p; 00542 } 00543 00544 #endif 00545 00546 /****************************************************************************/ 00547 00548 #ifdef WIN_VERSION 00549 00550 void copyDIBtoMatrix(t_jit_gl_context ctx) 00551 { 00552 HBITMAP hbm; 00553 DIBSECTION dib; 00554 void *matrix; 00555 long width = 0; 00556 long height = 0; 00557 t_jit_matrix_info info; 00558 long i, j, src_rowstride, dst_rowstride; 00559 unsigned char *src_bp, *dst_bp; 00560 unsigned long tmp, *src, *dst; 00561 00562 if ((matrix = ctx->target) && (hbm = ctx->auxdata)) 00563 { 00564 if (!GetObject(hbm, sizeof(DIBSECTION), &dib)) 00565 { 00566 error("copyDIBtoMatrix: GetObject %d", GetLastError()); 00567 return ; 00568 } 00569 00570 jit_object_method(matrix, _jit_sym_getinfo, &info); 00571 00572 if (info.type != _jit_sym_char) 00573 { 00574 error("copyDIBtoMatrix: invalid matrix type"); 00575 return ; 00576 } 00577 00578 if (info.planecount != 4) 00579 { 00580 error("copyDIBtoMatrix: invalid matrix planecount"); 00581 return ; 00582 } 00583 00584 width = MIN(dib.dsBm.bmWidth, info.dim[0]); 00585 height = MIN(dib.dsBm.bmHeight, info.dim[1]); 00586 src_rowstride = dib.dsBm.bmWidthBytes; 00587 dst_rowstride = info.dimstride[1]; 00588 src_bp = dib.dsBm.bmBits; 00589 jit_object_method(matrix, _jit_sym_getdata, &dst_bp); 00590 00591 if (!src_bp || !dst_bp) 00592 { 00593 error("copyDIBtoMatrix: invalid pointer"); 00594 return ; 00595 } 00596 00597 for (i = 0;i < height;i++) 00598 { 00599 src = (unsigned long *)(src_bp + src_rowstride * (height - 1 - i)); //bottom to top layout 00600 dst = (unsigned long *)(dst_bp + dst_rowstride * i); 00601 00602 for (j = 0;j < width;j++) 00603 { 00604 tmp = *src++; 00605 *dst++ = SWAP32(tmp); 00606 } 00607 } 00608 } 00609 } 00610 00611 #endif //WIN_VERSION 00612
Copyright © 2008, Cycling '74