You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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