Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

454 linhas
14 KiB

  1. unit uglcContextWGL;
  2. { Package: OpenGLCore
  3. Prefix: glc - OpenGL Core
  4. Beschreibung: diese Unit enthält eine Klassen-Kapselung für OpenGL Kontexte für Windows
  5. Hint: diese Unit sollte niemals direkt genutzt werden (siehe uglcContext) }
  6. interface
  7. uses
  8. Classes, SysUtils, Forms, Windows, uglcContext, dglOpenGL, Controls;
  9. type
  10. EWGLError = class(EGLError);
  11. { TglcContextWGL }
  12. TglcContextWGL = class(TglcContext)
  13. private
  14. FDC: HDC;
  15. FRC: HGLRC;
  16. fHandle: THandle;
  17. fPixelFormat: Integer;
  18. {%H-}constructor Create(const aControl: TWinControl); overload;
  19. protected
  20. procedure UpdatePixelFormat;
  21. procedure OpenContext; override;
  22. function FindPixelFormat: Integer;
  23. function FindPixelFormatNoAA: Integer;
  24. procedure OpenFromPF(PixelFormat: Integer);
  25. public
  26. constructor Create(const aControl: TWinControl;
  27. const aPixelFormatSettings: TglcContextPixelFormatSettings;
  28. const aShareContext: TglcContext = nil); overload; override;
  29. constructor Create(const aControl: TWinControl;
  30. const aPixelFormatSettings: TglcContextPixelFormatSettings;
  31. const aVersionSettings: TglcContextVersionSettings;
  32. const aShareContext: TglcContext = nil); overload; override;
  33. procedure CloseContext; override;
  34. procedure Activate; override;
  35. procedure Deactivate; override;
  36. function IsActive: boolean; override;
  37. procedure SwapBuffers; override;
  38. procedure SetSwapInterval(const aInterval: GLint); override;
  39. function GetSwapInterval: GLint; override;
  40. class function ChangeDisplaySettings(const aWidth, aHeight, aBitPerPixel, aFreq: Integer;
  41. const aFlags: TglcDisplayFlags): Boolean; override;
  42. class function IsAnyContextActive: boolean; override;
  43. end;
  44. implementation
  45. { TglcContextWGL }
  46. constructor TglcContextWGL.Create(const aControl: TWinControl);
  47. begin
  48. inherited Create(aControl, MakePF());
  49. fHandle := aControl.Handle;
  50. end;
  51. procedure TglcContextWGL.UpdatePixelFormat;
  52. begin
  53. fPixelFormat := FindPixelFormat;
  54. if (fPixelFormat = 0) then begin
  55. // try without MS
  56. fPixelFormatSettings.MultiSampling := 1;
  57. fPixelFormat := FindPixelFormat;
  58. end;
  59. end;
  60. procedure TglcContextWGL.OpenContext;
  61. begin
  62. inherited OpenContext;
  63. OpenFromPF(fPixelFormat);
  64. end;
  65. function TglcContextWGL.FindPixelFormat: Integer;
  66. var
  67. OldRC: HGLRC; OldDC: HDC;
  68. tmpWnd: TForm;
  69. tmpContext: TglcContextWGL;
  70. pf, i, max: integer;
  71. Count: GLuint;
  72. PFList, SampleList: array[0..31] of GLint;
  73. procedure ChoosePF(pPFList, pSampleList: PGLint; MaxCount: integer);
  74. var
  75. //ARB_Erweiterung vorhanden
  76. //| EXT_Erweiterung vorhanden
  77. MultiARBSup, MultiEXTSup: Boolean;
  78. //Liste der Integer Attribute
  79. IAttrib: array[0..22] of GLint;
  80. //Liste der Float Attribute (nur 0, da kein Wert)
  81. FAttrib: GLFloat;
  82. QueryAtrib, i: Integer;
  83. PPosiblePF, PSample: PglInt;
  84. begin
  85. //Pixelformate mit AA auslesen
  86. MultiARBSup := false;
  87. MultiEXTSup := false;
  88. if WGL_ARB_extensions_string and
  89. WGL_ARB_pixel_format and
  90. (WGL_ARB_MULTISAMPLE or GL_ARB_MULTISAMPLE) then
  91. multiARBSup := true;
  92. if WGL_EXT_extensions_string and
  93. WGL_EXT_pixel_format and
  94. (WGL_EXT_MULTISAMPLE or GL_EXT_MULTISAMPLE) then
  95. multiEXTSup := true;
  96. if multiARBSup then
  97. Read_WGL_ARB_pixel_format
  98. else if multiEXTSup then
  99. Read_WGL_EXT_pixel_format;
  100. if not (MultiARBSup or MultiEXTSup) then
  101. exit;
  102. IAttrib[00] := WGL_DRAW_TO_WINDOW_ARB;
  103. IAttrib[01] := 1;
  104. IAttrib[02] := WGL_SUPPORT_OPENGL_ARB;
  105. IAttrib[03] := 1;
  106. IAttrib[04] := WGL_DOUBLE_BUFFER_ARB;
  107. if (fPixelFormatSettings.DoubleBuffered) then
  108. IAttrib[05] := 1
  109. else
  110. IAttrib[05] := 0;
  111. IAttrib[06] := WGL_PIXEL_TYPE_ARB;
  112. IAttrib[07] := WGL_TYPE_RGBA_ARB;
  113. IAttrib[08] := WGL_COLOR_BITS_ARB;
  114. IAttrib[09] := fPixelFormatSettings.ColorBits;
  115. IAttrib[10] := WGL_ALPHA_BITS_ARB;
  116. IAttrib[11] := 0; //TODO: fPixelFormatSettings.AlphaBits;
  117. IAttrib[12] := WGL_DEPTH_BITS_ARB;
  118. IAttrib[13] := fPixelFormatSettings.DepthBits;
  119. IAttrib[14] := WGL_STENCIL_BITS_ARB;
  120. IAttrib[15] := fPixelFormatSettings.StencilBits;
  121. IAttrib[16] := WGL_ACCUM_BITS_ARB;
  122. IAttrib[17] := fPixelFormatSettings.AccumBits;
  123. IAttrib[18] := WGL_AUX_BUFFERS_ARB;
  124. IAttrib[19] := fPixelFormatSettings.AuxBuffers;
  125. IAttrib[20] := WGL_SAMPLE_BUFFERS_ARB;
  126. IAttrib[21] := 1;
  127. IAttrib[22] := 0;
  128. FAttrib := 0;
  129. if multiARBSup then
  130. wglChoosePixelFormatARB(tmpContext.FDC, @IAttrib[0], @FAttrib, MaxCount, pPFList, @Count)
  131. else if multiEXTSup then
  132. wglChoosePixelFormatEXT(tmpContext.FDC, @IAttrib[0], @FAttrib, MaxCount, pPFList, @Count);
  133. if Count > length(PFList) then
  134. Count := length(PFList);
  135. QueryAtrib := WGL_SAMPLES_ARB;
  136. PSample := pSampleList;
  137. PPosiblePF := @PFList[0];
  138. for i := 0 to Count-1 do begin
  139. if multiARBSup then
  140. wglGetPixelFormatAttribivARB(tmpContext.FDC, PPosiblePF^, 0, 1, @QueryAtrib, PSample)
  141. else if multiEXTSup then
  142. wglGetPixelFormatAttribivEXT(tmpContext.FDC, PPosiblePF^, 0, 1, @QueryAtrib, PSample);
  143. inc(PSample);
  144. inc(PPosiblePF);
  145. end;
  146. end;
  147. begin
  148. if (fPixelFormatSettings.MultiSampling = 1) then begin
  149. Result := FindPixelFormatNoAA;
  150. exit;
  151. end;
  152. Result := 0;
  153. OldDC := wglGetCurrentDC();
  154. OldRC := wglGetCurrentContext();
  155. try
  156. tmpWnd := TForm.Create(nil);
  157. tmpContext := TglcContextWGL.Create(tmpWnd);
  158. try
  159. pf := tmpContext.FindPixelFormatNoAA;
  160. tmpContext.OpenFromPF(pf);
  161. tmpContext.Activate;
  162. FillChar({%H-}PFList[0], Length(PFList), 0);
  163. FillChar({%H-}SampleList[0], Length(SampleList), 0);
  164. ChoosePF(@PFList[0], @SampleList[0], length(SampleList));
  165. max := 0;
  166. for i := 0 to Count-1 do begin
  167. if (max < SampleList[i]) and (SampleList[i] <= fPixelFormatSettings.MultiSampling) and (PFList[i] <> 0) then begin
  168. max := SampleList[i];
  169. result := PFList[i];
  170. if (max = fPixelFormatSettings.MultiSampling) then
  171. break;
  172. end;
  173. end;
  174. tmpContext.Deactivate;
  175. finally
  176. FreeAndNil(tmpContext);
  177. FreeAndNil(tmpWnd);
  178. end;
  179. finally
  180. if (OldDC <> 0) and (OldRC <> 0) then
  181. ActivateRenderingContext(OldDC, OldRC);
  182. end;
  183. end;
  184. function TglcContextWGL.FindPixelFormatNoAA: Integer;
  185. const
  186. MemoryDCs = [OBJ_MEMDC, OBJ_METADC, OBJ_ENHMETADC];
  187. var
  188. //DeviceContext
  189. DC: HDC;
  190. //Objekttyp des DCs
  191. AType: DWord;
  192. //Beschreibung zum passenden Pixelformat
  193. PFDescriptor: TPixelFormatDescriptor;
  194. begin
  195. result := 0;
  196. DC := GetDC(fHandle);
  197. if DC = 0 then begin
  198. exit;
  199. end;
  200. FillChar(PFDescriptor{%H-}, SizeOf(PFDescriptor), #0);
  201. with PFDescriptor do begin
  202. nSize := SizeOf(PFDescriptor);
  203. nVersion := 1;
  204. dwFlags := PFD_SUPPORT_OPENGL;
  205. AType := GetObjectType(DC);
  206. if AType = 0 then begin
  207. exit;
  208. end;
  209. if fPixelFormatSettings.DoubleBuffered then
  210. dwFlags := dwFlags or PFD_DOUBLEBUFFER;
  211. if fPixelFormatSettings.Stereo then
  212. dwFlags := dwFlags or PFD_STEREO;
  213. if AType in MemoryDCs then
  214. dwFlags := dwFlags or PFD_DRAW_TO_BITMAP
  215. else
  216. dwFlags := dwFlags or PFD_DRAW_TO_WINDOW;
  217. iPixelType := PFD_TYPE_RGBA;
  218. cColorBits := fPixelFormatSettings.ColorBits;
  219. //TODO: cAlphaBits := fPixelFormatSettings.AlphaBits;
  220. cDepthBits := fPixelFormatSettings.DepthBits;
  221. cStencilBits := fPixelFormatSettings.StencilBits;
  222. cAccumBits := fPixelFormatSettings.AccumBits;
  223. cAuxBuffers := fPixelFormatSettings.AuxBuffers;
  224. if fPixelFormatSettings.Layer = 0 then
  225. iLayerType := PFD_MAIN_PLANE
  226. else if fPixelFormatSettings.Layer > 0 then
  227. iLayerType := PFD_OVERLAY_PLANE
  228. else
  229. iLayerType := Byte(PFD_UNDERLAY_PLANE);
  230. end;
  231. result := ChoosePixelFormat(DC, @PFDescriptor);
  232. end;
  233. procedure TglcContextWGL.OpenFromPF(PixelFormat: Integer);
  234. var
  235. tmpRC: HGLRC;
  236. err: DWORD;
  237. Attribs: array of GLint;
  238. CreateContextAttribs: TwglCreateContextAttribsARB;
  239. begin
  240. if PixelFormat = 0 then begin
  241. raise EWGLError.Create('Invalid PixelFormat');
  242. end;
  243. FDC := GetDC(fHandle);
  244. if FDC = 0 then begin
  245. raise EWGLError.CreateFmt('Cannot create DC on %x',[fHandle]);
  246. end;
  247. if not SetPixelFormat(FDC, PixelFormat, nil) then begin
  248. ReleaseDC(fHandle, FDC);
  249. raise EWGLError.CreateFmt('Cannot set PF %d on Control %x DC %d',[PixelFormat, fHandle, FDC]);
  250. end;
  251. tmpRC := wglCreateContext(FDC);
  252. if tmpRC = 0 then begin
  253. ReleaseDC(fHandle, FDC);
  254. raise EWGLError.CreateFmt('Cannot create context on Control %x DC %d',[PixelFormat, fHandle, FDC]);
  255. end;
  256. if fUseVersion and
  257. (fVersionSettings.Major <> GLC_CONTEXT_VERSION_UNKNOWN) and
  258. (fVersionSettings.Minor <> GLC_CONTEXT_VERSION_UNKNOWN) then
  259. begin
  260. { Code from dglOpenGL.pas (modified) }
  261. wglMakeCurrent(FDC, tmpRC);
  262. // Set attributes to describe our requested context
  263. SetLength(Attribs, 5);
  264. Attribs[0] := WGL_CONTEXT_MAJOR_VERSION_ARB;
  265. Attribs[1] := fVersionSettings.Major;
  266. Attribs[2] := WGL_CONTEXT_MINOR_VERSION_ARB;
  267. Attribs[3] := fVersionSettings.Minor;
  268. // Add context flag for forward compatible context
  269. // Forward compatible means no more support for legacy functions like
  270. // immediate mode (glvertex, glrotate, gltranslate, etc.)
  271. if fVersionSettings.ForwardCompatible then begin
  272. SetLength(Attribs, Length(Attribs)+2);
  273. Attribs[4] := WGL_CONTEXT_FLAGS_ARB;
  274. Attribs[5] := WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
  275. end;
  276. // Attribute flags must be finalized with a zero
  277. Attribs[High(Attribs)] := 0;
  278. // Get function pointer for new context creation function
  279. CreateContextAttribs := TwglCreateContextAttribsARB(wglGetProcAddress('wglCreateContextAttribsARB'));
  280. if not Assigned(CreateContextAttribs) then begin
  281. wglMakeCurrent(0, 0);
  282. wglDeleteContext(tmpRC);
  283. ReleaseDC(fHandle, FDC);
  284. raise Exception.Create('Could not get function pointer adress for wglCreateContextAttribsARB - OpenGL 3.x and above not supported!');
  285. end;
  286. // Create context
  287. FRC := CreateContextAttribs(FDC, 0, @Attribs[0]);
  288. if (FRC = 0) then begin
  289. wglMakeCurrent(0, 0);
  290. wglDeleteContext(tmpRC);
  291. ReleaseDC(fHandle, FDC);
  292. raise Exception.Create('Could not create the desired OpenGL rendering context!');
  293. end;
  294. wglMakeCurrent(0, 0);
  295. wglDeleteContext(tmpRC);
  296. end else
  297. FRC := tmpRC;
  298. if Assigned(ShareContext) then begin
  299. if (ShareContext.ClassName <> ClassName) then
  300. raise Exception.Create('share context has invalid type: ' + ShareContext.ClassName);
  301. if not wglShareLists((ShareContext as TglcContextWGL).FRC, FRC) then begin
  302. err := GetLastError();
  303. raise EGLError.Create('wglShareLists failed (' + IntToStr(err) + ') ' + SysErrorMessage(err));
  304. end;
  305. end;
  306. end;
  307. constructor TglcContextWGL.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aShareContext: TglcContext);
  308. begin
  309. inherited Create(aControl, aPixelFormatSettings, aShareContext);
  310. fHandle := aControl.Handle;
  311. UpdatePixelFormat;
  312. end;
  313. constructor TglcContextWGL.Create(const aControl: TWinControl; const aPixelFormatSettings: TglcContextPixelFormatSettings; const aVersionSettings: TglcContextVersionSettings; const aShareContext: TglcContext);
  314. begin
  315. inherited Create(aControl, aPixelFormatSettings, aVersionSettings, aShareContext);
  316. fHandle := aControl.Handle;
  317. UpdatePixelFormat;
  318. end;
  319. procedure TglcContextWGL.CloseContext;
  320. begin
  321. if (FRC <> 0) then begin
  322. Deactivate;
  323. DestroyRenderingContext(FRC);
  324. ReleaseDC(fHandle, FDC);
  325. FRC := 0;
  326. FDC := 0;
  327. end;
  328. end;
  329. procedure TglcContextWGL.Activate;
  330. var
  331. err: DWORD;
  332. begin
  333. if (FDC = 0) or (FRC = 0) then
  334. raise Exception.Create('invalid context. did you call build context first?');
  335. if (not wglMakeCurrent(FDC, FRC)) then begin
  336. err := GetLastError;
  337. raise Exception.Create('unable to activate context: (' + IntToStr(err) + ') ' + SysErrorMessage(err));
  338. end;
  339. inherited Activate;
  340. end;
  341. procedure TglcContextWGL.Deactivate;
  342. var
  343. err: DWORD;
  344. begin
  345. if (wglGetCurrentContext()=FRC) and not wglMakeCurrent(0, 0) then begin
  346. err := GetLastError;
  347. raise Exception.Create('unable to deactivate context: (' + IntToStr(err) + ') ' + SysErrorMessage(err));
  348. end;
  349. end;
  350. function TglcContextWGL.IsActive: boolean;
  351. begin
  352. Result:= (FRC <> 0) and
  353. (FRC = wglGetCurrentContext()) and
  354. (FDC = wglGetCurrentDC());
  355. end;
  356. procedure TglcContextWGL.SwapBuffers;
  357. begin
  358. Windows.SwapBuffers(FDC);
  359. end;
  360. procedure TglcContextWGL.SetSwapInterval(const aInterval: GLint);
  361. begin
  362. wglSwapIntervalEXT(aInterval);
  363. end;
  364. function TglcContextWGL.GetSwapInterval: GLint;
  365. begin
  366. result := wglGetSwapIntervalEXT();
  367. end;
  368. class function TglcContextWGL.ChangeDisplaySettings(const aWidth, aHeight,
  369. aBitPerPixel, aFreq: Integer; const aFlags: TglcDisplayFlags): Boolean;
  370. var
  371. dm: TDeviceMode;
  372. flags: Cardinal;
  373. begin
  374. FillChar(dm{%H-}, SizeOf(dm), 0);
  375. with dm do begin
  376. dmSize := SizeOf(dm);
  377. dmPelsWidth := aWidth;
  378. dmPelsHeight := aHeight;
  379. dmDisplayFrequency := aFreq;
  380. dmBitsPerPel := aBitPerPixel;
  381. dmFields := DM_PELSWIDTH or DM_PELSHEIGHT or DM_BITSPERPEL or DM_DISPLAYFREQUENCY;
  382. end;
  383. flags := 0; //CDS_TEST;
  384. if (dfFullscreen in aFlags) then
  385. flags := flags or CDS_FULLSCREEN;
  386. result := (Windows.ChangeDisplaySettings(dm, flags) = DISP_CHANGE_SUCCESSFUL);
  387. end;
  388. class function TglcContextWGL.IsAnyContextActive: boolean;
  389. begin
  390. Result:= (wglGetCurrentContext()<>0) and (wglGetCurrentDC()<>0);
  391. end;
  392. end.