全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2149
推到 Plurk!
推到 Facebook!

OpenGL, Windows and 3dfx FAQs

 
jackkcg
站務副站長


發表:891
回覆:1050
積分:848
註冊:2002-03-23

發送簡訊給我
#1 引用回覆 回覆 發表時間:2002-09-28 12:12:49 IP:61.221.xxx.xxx 未訂閱
此為轉貼資料 http://www.wischik.com/lu/programmer/wingl.html    OpenGL, Windows and 3dfx FAQs These questions are commonly asked in the comp.graphics.api.opengl newsgroup. Hopefully, when a FAQ is written, these answers can be incorporated in it.    How can I get OpenGL/Glut working with my Voodoo1/2 card under Windows?  How can I get a list of OpenGL drivers, like Quake does?  How can I load the OpenGL driver at runtime?  Why does ChoosePixelFormat fail in this minimal program?  How do I choose an accelerated pixel format under Windows?  How can I get OpenGL and Glut to work with my Voodoo1/2 card? If you have a voodoo1/2 card, then you need to do a bit of work to get hardware acceleration for OpenGL. First, some overview about how things fit together...    Normally, whenever you use any gl function, then the call gets handled by OPENGL32.DLL in your system directory.  If your machine has an integrated 2d+3d card, and OpenGL drivers have been installed, then opengl32.dll simply forwards the gl function call straight to the hardware acceleration.  Otherwise, opengl32.dll will handle all gl functions itself in software.  If you have a voodoo1/2 card (which is not integrated 2d+3d), then opengl32.dll will not be able to use your 3d hardware acceleration. You will have to use one of two possible workarounds.    But first, go to www.3dfx.com and download the latest voodoo1/2 reference drivers. (As of March 2000 they are at the bottom of the page and are called "Voodoo2 Windows 9x DirectX7 Drivers - Version 3.02.02"). When you install them, you will find a file called "3DFXVGL.DLL". This is the 3dfx opengl driver.    The easiest solution is to stick a copy of 3dfxgl.dll into your application's directory, but rename it to "opengl32.dll". Therefore, when you run your application, and it tries to load the opengl driver, it will automatically load the 3dfx driver. You can use GLU and GLUT as normal. Please, do NOT try to delete or rename the existing opengl32.dll from the system directory. That will screw everyone else up.  The more user-friendly solution is to implement "runtime loading" of the opengl driver. See the following FAQ for details. Dynamic loading will take some work! And it will require workarounds on your part to get GLU and GLUT working.  Extra notes: When you create a context and make it current, the 3dfx opengl driver will examine the size of your window. If it is a 512x384 window, then the graphics card will initialize itself to full-screen at 512x384 resolution. Similarly for 640x480, 800x600 and 1024x768. (But this highest resolution is only supported with two cards in SLI mode). If you create a window bigger than it can handle, then it will choose the most fitting screen resolution. It is always 16bit colour depth.    Even when the voodoo screen mode has changed, Windows still believes that you are in your regular 2d desktop. You must do something about this! Otherwise, you might end up with the user clicking their mouse on some other window that the 2d desktop thinks is still visible, even though the monitor doesn't show it. There are two ways: (None of this applies if you're using glut. I don't know how glut works).    By far the easiest is to change screen mode to the appropriate resolution. Then create a popup window the size of the entire screen and make it topmost. Then, enter OpenGL mode. Once you are finished, restore the screen to its normal mode.  A slightly harder technique is possible for those who think that the 'double mode change' above is inelegant. Call ClipCursor to restrict mouse movement to your opengl window. Also, alter the mouse ballistics so that the same mouse-movement that before would have moved the mouse across the entire screen, now moves it across the entire window. Once you're finished, restore everything.  // // (1) Change screen mode and create popup window // DEVMODE dm; ZeroMemory(&dm,sizeof(dm)); dm.dmSize=sizeof(dm); dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; dm.dmPelsWidth = 640; dm.dmPelsHeight = 480; LONG res = ChangeDisplaySettings(&dm,CDS_TEST); if (res!=DISP_CHANGE_SUCCESFULL) return; // error ChangeDisplaySettings(&dm,CDS_FULLSCREEN); CreateWindow(WS_EX_TOPMOST,WS_POPUP|WS_VISIBLE,..,0,0,640,480...);    ... and then create your opengl context on that window    ... and do stuff with it DestroyWindow(...); ChangeDisplaySettings(NULL,NULL); // // (2) Clip mouse // HWND hwnd=CreateWindow(WS_POPUP|WS_VISIBLE,...0,0,640,480,..); int sw=GetSystemMetrics(SM_CXSCREEN); int sh=GetSystemMetrics(SM_CYSCREEN); int cw=640, ch=480; // First, move the mouse proportionately inside our window POINT tl; tl.x=0; tl.y=0; ::ClientToScreen(hwnd,&tl); POINT pt; GetCursorPos(&pt); pt.x=pt.x*cw/sw+tl.x; pt.y=pt.y*ch/sh+tl.y; SetCursorPos(pt.x,pt.y); // Second, clip the mouse RECT rc; pt.x=0; pt.y=0; ClientToScreen(hwnd,&pt); rc.left=pt.x; rc.top=pt.y; pt.x=640; pt.y=480; ClientToScreen(hwnd,&pt); rc.right=pt.x; rc.bottom=pt.y; ClipCursor(&rc); // Finally, adjust mouse ballistics proportionately DWORD param[3]; SystemParametersInfo(SPI_GETMOUSE,0,¶m,FALSE); OldMouseSpeed=param[2]; param[2]=param[2]*cw/sw; SystemParametersInfo(SPI_SETMOUSE,0,¶m,FALSE);    ... now create opengl stuff in the window    ... and run your program // First, restore mouse ballistics DWORD param[3]; SystemParametersInfo(SPI_GETMOUSE,0,¶m,FALSE); param[2]=OldMouseSpeed; SystemParametersInfo(SPI_SETMOUSE,0,¶m,FALSE); // Next, restore the mouse clip rectangle RECT rc; rc.left=0; rc.top=0; rc.right=GetSystemMetrics(SM_CXSCREEN); rc.bottom=GetSystemMetrics(SM_CYSCREEN); ClipCursor(&rc); // Finally, move it to the same place on the screen proportionately POINT tl; tl.x=0; tl.y=0; ClientToScreen(hwnd,&tl); POINT pt; GetCursorPos(&pt); pt.x=(pt.x-tl.x)*sw/cw; pt.y=(pt.y-tl.y)*sh/ch; SetCursorPos(pt.x,pt.y); How can I get a list of OpenGL drivers, like Quake? You first search for appropriate DLL files in appropriate directories, and display them in a list. Then you use dynamic loading to load the dll. (See following question about dynamic loading).    There is no system-defined location for where opengl drivers should go, and there is no naming convention. The only thing you know is that there is OPENGL32.DLL in the windows system directory, and that this file provides a software opengl driver, and also a hardware opengl driver for your integrated 2d+3d graphics card if you have an integrated 2d+3d graphics card and if your drivers are installed.    Other drivers (e.g. MESA, Cosmo, MiniGL, 3dfxvgl.dll) might be in any location at all.    The best thing to do is to have a list of search-paths, and to search for files in them. You might have \drivers\*.dll, \opengl32.dll. And also have a 'Driver...' button in your configuration dialog which lets users select other files in other directories. Then, use FindFirstFile/FindNextFile to find all files that match those paths. You might be tempted to load up each DLL, just to test whether it includes particular GL entry points (and therefore confirm that it is an OpenGL dll and not some other random DLL). But you should not do this! If it happens to be an opengl driver for some hardware that is not already on your system, then loading it will probably cause a system crash. Therefore, you must stick to querying its version info and checking its filename. Next, you want to extract version information about the driver. The only safe way to do this is to use the Windows API function GetFileVersionInfo, to extract the details. These are the same version details you see if you right-click on a dll and click on the 'version' tab. Source code for this is given below. There are two issues. First, binary distributions of Mesa typically do not include version information. This is really pants. If you are as irritated by this as I am, then email the people who do mesa and tell them to put version information in their DLLs. Second, opengl32.dll only displays the version string "microsoft generic software driver". That's not much use! Especially not on a machine where there is an integrated 2d 3d driver, and you want its name! One way to find the name of this is to look in the registry under HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\OpenGLDrivers (under Windows NT and Win2000, that's ...\WindowsNT\...) Here it may list several different drivers. I don't know how to tell which one it will use. Below there's a function to retrieve the filename of the ICD, if there is one. A different solution is to load up opengl32.dll, create a window, set its pixel format, create a context, make the context current, and then call glGetString(GL_VENDOR) &c. Then destroy it all. Very tedious! typedef struct { char FileName[MAX_PATH]; char CompanyName[MAX_PATH]; char FileDescription[MAX_PATH]; char FileVersion[MAX_PATH]; bool Uses3dfxStyle; } TGLDriverDetails; // // GETDRIVERDETAILS - given a filename, extracts version info // bool GetDriverDetails(char *fn,TGLDriverDetails *d) { strcpy(d->FileName,fn); strcpy(d->CompanyName,""); strcpy(d->FileDescription,""); strcpy(d->FileVersion,""); d->Uses3dfxStyle=false; DWORD dummy; DWORD vis=GetFileVersionInfoSize(fn,&dummy); if (vis==0) return true; void *vData; vData=(void *)new char[(UINT)vis]; if (!GetFileVersionInfo(fn,dummy,vis,vData)) {delete vData;return true;} char vn[100]; strcpy(vn,"\\VarFileInfo\\Translation"); LPVOID transblock; UINT vsize; BOOL res=VerQueryValue(vData,vn,&transblock,&vsize); if (!res) {delete vData;return true;} // Swap the words so wsprintf will print the lang-charset in the correct format. DWORD *dw=(DWORD*)transblock; DWORD dwhi=HIWORD(*dw); DWORD dwlo=LOWORD(*dw); *dw = dwhi | (dwlo << 16); char *info; info="CompanyName"; wsprintf(vn,"\\StringFileInfo\\lx\\%s",*(DWORD *)transblock,info); char *CompanyName=NULL; VerQueryValue(vData,vn,(LPVOID*)&CompanyName,&vsize); info="FileDescription"; wsprintf(vn,"\\StringFileInfo\\lx\\%s",*(DWORD *)transblock,info); char *FileDescription=NULL; VerQueryValue(vData,vn,(LPVOID*)&FileDescription,&vsize); info="FileVersion"; wsprintf(vn,"\\StringFileInfo\\lx\\%s",*(DWORD *)transblock,info); char *FileVersion=NULL; VerQueryValue(vData,vn,(LPVOID*)&FileVersion,&vsize); strcpy(d->CompanyName,CompanyName); strcpy(d->FileDescription,FileDescription); strcpy(d->FileVersion,FileVersion); delete vData; // tidy up in case of duplication char *de=d->FileDescription, *ce=d->CompanyName; char *inde=strstr(de,ce); if (inde!=NULL) { int i1 = (int)(inde-de); int i2=i1 strlen(ce); char t[MAX_PATH]; strcpy(t,""); strncpy(t,de,i1); strncat(t,de i2,strlen(de)-i2); strcpy(d->FileDescription,t); } inde=strstr(d->CompanyName,"3dfx"); if (inde==NULL) inde=strstr(d->FileDescription,"3dfx"); if (inde==NULL) inde=strstr(d->FileVersion,"3dfx"); if (inde==NULL) d->Uses3dfxStyle=false; else d->Uses3dfxStyle=true; return true; } // // GETMAINDRIVER - retrieves the filename of the opengl icd driver, // if you have an integrated 2d 3d card and the opengl driver has been // installed. You can subsequently use GetDriverDetails on the returned // driver string. // returns 'true' or 'false' for whether or not it succeeded. // bool GetMainDriver(char *fn,int maxsize) { OSVERSIONINFO oi; ZeroMemory(&oi,sizeof(oi)); oi.dwOSVersionInfoSize=sizeof(oi); GetVersionEx(&oi); char *regpath; if (oi.dwPlatformId==VER_PLATFORM_WIN32_NT) regpath="SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\OpenGLDrivers"; else regpath="SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\OpenGLDrivers"; HKEY hkey; LONG res=RegOpenKeyEx(HKEY_LOCAL_MACHINE,regpath,0,KEY_QUERY_VALUE,&hkey); if (res!=ERROR_SUCCESS) return false; DWORD index=0; char t[MAX_PATH]; DWORD size=MAX_PATH; char dat[MAX_PATH]; DWORD dsize=MAX_PATH; res=RegEnumValue(hkey,index,t,&size,NULL,NULL,(LPBYTE)dat,&dsize); if (res==ERROR_SUCCESS && size==0) { index ; res=RegEnumValue(hkey,index,t,&size,NULL,NULL,(LPBYTE)dat,&dsize); } RegCloseKey(hkey); if (res!=ERROR_SUCCESS) return false; GetSystemDirectory(t,MAX_PATH); strcat(t,"\\"); strcat(t,dat); strncpy(fn,t,maxsize-1); strcat(fn,"\0"); return true; } How can I runtime-load an OpenGL driver DLL? Normally, when you make a call to any gl function, your program gets linked against the opengl32.lib import library. This means that, when your program is loaded, the opengl32.dll driver gets loaded as well. But if you want to load a particular OpenGL DLL at runtime (perhaps one that the user has selected from a list of drivers) then you cannot use the opengl32.lib import library. Instead, you must LoadLibrary(..) and then GetProcAddress(..) to get the address of each and ever gl* function. There are a number of problems. GLU32.DLL and GLUT32.DLL implicitly link against opengl32.lib. Therefore, if you attempt to use glu or glut functions, then these will be routed via opengl32.dll while the rest of your code is routed via your runtime-loaded DLL. This will not work. There is no good solution. You simply cannot use GLU and GLUT functions 'as is' with runtime loading. The only thing to do is to find the source code for the functions you use, and copy and paste them into your own program. A neat place to get source code is from Mesa, http://mesa3d.sourceforge.net/download.html. It works differently depending on whether the opengl driver is OPENGL32.DLL, or one from 3dfx. If the "GetDriverDetails" function above says that your driver is a 3dfx driver, then you must bypass certain particular GDI functions. Source code for dynamic loading of a DLL, and bypassing appropriate GDI functions, is available from Ryan Haski at http://members.home.com/borealis/opengl_usingq3.html Why does ChoosePixelFormat fail in my minimal test program? Internally, ChoosePixelFormat (and SetPixelFormat and all those functions) make calls to OPENGL32.DLL. If your program does not make any gl* calls, then your compiler's smart-linker will probably not link opengl32.lib, so when you run your program then opengl32.dll will not be loaded, and so ChoosePixelFormat will fail. The solution, simply, is to add a gl* function call somewhere inside your code, and rebuild. How do I choose an accelerated pixel format under Windows? Note: many consumer graphics cards cannot accelerate when the display is 24bpp, and many cannot accelerate when the desktop is at 32bpp in high-resolution. I always change to 800x600 x16bpp for my full-screen games. That ensures that the graphics card will have enough memory. Normally, you call ChoosePixelFormat to choose a pixel format. But it's hard to know whether this will give you an accelerated pixel format. For us gamers, acceleration is the most important thing: we'd be happy to settle for a 16bpp accelerated surface, rather than a 32bpp unaccelerated surface. The following code uses a gamer's heuristics to choose a suitable pixel format. Call it like this: int bpp=-1; // don't care. (or a positive integer) int depth=-1; // don't care. (or a positive integer) int dbl=1; // we want double-buffering. (or -1 for 'don't care', or 0 for 'none') int acc=1; // we want acceleration. (or -1 or 0) int pf=ChoosePixelFormatEx(hdc,&bpp,&depth,&dbl,&acc); The function will return, in those variables, the pixel format that it choose. int ChoosePixelFormatEx(HDC hdc,int *p_bpp,int *p_depth,int *p_dbl,int *p_acc) { int wbpp; if (p_bpp==NULL) wbpp=-1; else wbpp=*p_bpp; int wdepth; if (p_depth==NULL) wdepth=16; else wdepth=*p_depth; int wdbl; if (p_dbl==NULL) wdbl=-1; else wdbl=*p_dbl; int wacc; if (p_acc==NULL) wacc=1; else wacc=*p_acc; PIXELFORMATDESCRIPTOR pfd; ZeroMemory(&pfd,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1; int num=DescribePixelFormat(hdc,1,sizeof(pfd),&pfd); if (num==0) return 0; unsigned int maxqual=0; int maxindex=0; int max_bpp, max_depth, max_dbl, max_acc; for (int i=1; i<=num; i ) { ZeroMemory(&pfd,sizeof(pfd)); pfd.nSize=sizeof(pfd); pfd.nVersion=1; DescribePixelFormat(hdc,i,sizeof(pfd),&pfd); int bpp=pfd.cColorBits; int depth=pfd.cDepthBits; bool pal=(pfd.iPixelType==PFD_TYPE_COLORINDEX); bool mcd=((pfd.dwFlags & PFD_GENERIC_FORMAT) && (pfd.dwFlags & PFD_GENERIC_ACCELERATED)); bool soft=((pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)); bool icd=(!(pfd.dwFlags & PFD_GENERIC_FORMAT) && !(pfd.dwFlags & PFD_GENERIC_ACCELERATED)); bool opengl=(pfd.dwFlags & PFD_SUPPORT_OPENGL); bool window=(pfd.dwFlags & PFD_DRAW_TO_WINDOW); bool bitmap=(pfd.dwFlags & PFD_DRAW_TO_BITMAP); bool dbuff=(pfd.dwFlags & PFD_DOUBLEBUFFER); // unsigned int q=0; if (opengl && window) q=q 0x8000; if (wdepth==-1 || (wdepth>0 && depth>0)) q=q 0x4000; if (wdbl==-1 || (wdbl==0 && !dbuff) || (wdbl==1 && dbuff)) q=q 0x2000; if (wacc==-1 || (wacc==0 && soft) || (wacc==1 && (mcd || icd))) q=q 0x1000; if (mcd || icd) q=q 0x0040; if (icd) q=q 0x0002; if (wbpp==-1 || (wbpp==bpp)) q=q 0x0800; if (bpp>=16) q=q 0x0020; if (bpp==16) q=q 0x0008; if (wdepth==-1 || (wdepth==depth)) q=q 0x0400; if (depth>=16) q=q 0x0010; if (depth==16) q=q 0x0004; if (!pal) q=q 0x0080; if (bitmap) q=q 0x0001; if (q>maxqual) {maxqual=q; maxindex=i;max_bpp=bpp; max_depth=depth; max_dbl=dbuff?1:0; max_acc=soft?0:1;} } if (maxindex==0) return maxindex; if (p_bpp!=NULL) *p_bpp=max_bpp; if (p_depth!=NULL) *p_depth=max_depth; if (p_dbl!=NULL) *p_dbl=max_dbl; if (p_acc!=NULL) *p_acc=max_acc; return maxindex; }
------
**********************************************************
哈哈&兵燹
最會的2大絕招 這個不會與那個也不會 哈哈哈 粉好

Delphi K.Top的K.Top分兩個字解釋Top代表尖端的意思,希望本討論區能提供Delphi的尖端新知
K.表Knowlege 知識,就是本站的標語:Open our mind
系統時間:2024-06-29 16:14:17
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!