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.
 
 
 
 
 

875 lines
26 KiB

  1. unit uMainForm;
  2. {$mode objfpc}{$H+}
  3. {$IFDEF LINUX}
  4. {$DEFINE USE_FREETYPE}
  5. {$ENDIF}
  6. interface
  7. uses
  8. Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  9. ulibTextSuite, dglOpenGL
  10. {$IF DEFINED(WIN32) OR DEFINED(WIN64)}
  11. , Windows
  12. {$ELSEIF DEFINED(LINUX)}
  13. , LCLType, LMessages, XUtil, XLib, gdk2x, gtk2, gdk2, WSLCLClasses, X, glib2
  14. , Gtk2Def, Gtk2Int, InterfaceBase, WSControls
  15. {$ENDIF};
  16. type
  17. {$IF DEFINED(LINUX)}
  18. TRenderControl = class(TWinControl)
  19. private
  20. fIntWidget: PGtkWidget;
  21. fVisualID: TVisualID;
  22. fTarget: TWinControl;
  23. protected
  24. function WSCreateHandle({%H-}const WSPrivate: TWSPrivateClass; const AParams: TCreateParams): TLCLIntfHandle;
  25. procedure WSBeforeDestroyHandle;
  26. procedure WndProc(var Message: TLMessage); override;
  27. public
  28. property Widget: PGtkWidget read FIntWidget;
  29. property Target: TWinControl read fTarget write fTarget;
  30. constructor Create(TheOwner: TComponent; const aVisualID: TVisualID); overload;
  31. end;
  32. TWSCustomVisualControl = class(TWSWinControl)
  33. published
  34. class function CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle; override;
  35. class procedure DestroyHandle(const AWinControl: TWinControl); override;
  36. end;
  37. {$ENDIF}
  38. TMainForm = class(TForm)
  39. procedure FormCreate(Sender: TObject);
  40. procedure FormDestroy(Sender: TObject);
  41. procedure FormPaint(Sender: TObject);
  42. procedure FormResize(Sender: TObject);
  43. private
  44. fCanRender: Boolean;
  45. fHasRenderContext: Boolean;
  46. {$IF DEFINED(WIN32) OR DEFINED(WIN64)}
  47. fDC: HDC;
  48. fRC: HGLRC;
  49. procedure CreateRenderContext;
  50. procedure DestroyRenderContext;
  51. procedure SwapBuffers;
  52. {$ELSEIF DEFINED(LINUX)}
  53. fVisual: PXVisualInfo;
  54. fDisplay: PDisplay;
  55. fWidget: PGtkWidget;
  56. fContext: GLXContext;
  57. fRenderControl: TRenderControl;
  58. procedure CreateRenderContext;
  59. procedure DestroyRenderContext;
  60. procedure SwapBuffers;
  61. {$ENDIF}
  62. private
  63. fltsContext: TltsContext;
  64. fltsRenderer: TltsRendererOpenGL;
  65. fltsCreator: {$IFDEF USE_FREETYPE}TltsFontCreatorFreeType{$ELSE}TltsFontCreatorGDI{$ENDIF};
  66. fltsFont: TltsFont;
  67. fltsPostProcessorList: TltsPostProcessorList;
  68. procedure Render;
  69. end;
  70. var
  71. MainForm: TMainForm;
  72. implementation
  73. {$R *.lfm}
  74. const
  75. {$IF DEFINED(WIN32)}
  76. LibName = '..\..\..\libTextSuite-i386-win32.dll';
  77. {$ELSEIF DEFINED(WIN64)}
  78. LibName = '..\..\..\libTextSuite-x86_64-win64.dll';
  79. {$ELSEIF DEFINED(LINUX) AND DEFINED(CPU32)}
  80. LibName = '../../../libTextSuite-i386-linux.so';
  81. {$ELSEIF DEFINED(LINUX) AND DEFINED(CPU64)}
  82. LibName = '../../../libTextSuite-x86_64-linux.so';
  83. {$ELSE}
  84. {$ERROR 'unknown operation system'}
  85. {$IFEND}
  86. TEST_TEXT = 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.';
  87. PATTER_DATA: array[0..15] of Byte = (
  88. $FF, $BF, $7F, $BF,
  89. $BF, $FF, $BF, $7F,
  90. $7F, $BF, $FF, $BF,
  91. $BF, $7F, $BF, $FF);
  92. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  93. {$IFDEF LINUX}
  94. type
  95. TGLIntArray = packed array of GLInt;
  96. PGtkCustomWidget = ^TGtkCustomWidget;
  97. TGtkCustomWidget = record
  98. darea: TGtkDrawingArea;
  99. end;
  100. PGtkCustomWidgetClass = ^TGtkCustomWidgetClass;
  101. TGtkCustomWidgetClass = record
  102. parent_class: TGtkDrawingAreaClass;
  103. end;
  104. var
  105. custom_widget_type: TGtkType = 0;
  106. custom_widget_parent_class: Pointer = nil;
  107. function GTK_TYPE_CUSTOM_WIDGET: TGtkType; forward;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. procedure g_return_if_fail(b: boolean; const Msg: string);
  110. begin
  111. if not b then raise Exception.Create(Msg);
  112. end;
  113. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  114. procedure g_return_if_fail(b: boolean);
  115. begin
  116. g_return_if_fail(b,'');
  117. end;
  118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  119. function GTK_IS_CUSTOM_WIDGET(obj: Pointer): Boolean;
  120. begin
  121. GTK_IS_CUSTOM_WIDGET:=GTK_CHECK_TYPE(obj,GTK_TYPE_CUSTOM_WIDGET);
  122. end;
  123. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  124. function GTK_CUSTOM_WIDGET(obj: Pointer): PGtkCustomWidget;
  125. begin
  126. g_return_if_fail(GTK_IS_CUSTOM_WIDGET(obj),'');
  127. Result := PGtkCustomWidget(obj);
  128. end;
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. procedure gtk_custom_widget_init(custom_widget: PGTypeInstance; theClass: gpointer); cdecl;
  131. begin
  132. gtk_widget_set_double_buffered(PGtkWidget(custom_widget),gdkFALSE);
  133. GTK_WIDGET_UNSET_FLAGS(PGtkWidget(custom_widget),GTK_NO_WINDOW);
  134. end;
  135. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  136. procedure gtk_custom_widget_destroy(obj: PGtkObject); cdecl;
  137. begin
  138. g_return_if_fail (obj <>nil,'');
  139. g_return_if_fail (GTK_IS_CUSTOM_WIDGET(obj),'');
  140. if Assigned(GTK_OBJECT_CLASS(custom_widget_parent_class)^.destroy) then
  141. GTK_OBJECT_CLASS(custom_widget_parent_class)^.destroy(obj);
  142. end;
  143. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  144. procedure gtk_custom_widget_class_init(klass: Pointer); cdecl;
  145. var
  146. object_class: PGtkObjectClass;
  147. begin
  148. custom_widget_parent_class := gtk_type_class(gtk_drawing_area_get_type());
  149. g_return_if_fail(custom_widget_parent_class<>nil,'gtk_custom_widget_class_init parent_class=nil');
  150. object_class := PGtkObjectClass(klass);
  151. g_return_if_fail(object_class<>nil,'gtk_custom_widget_class_init object_class=nil');
  152. object_class^.destroy := @gtk_custom_widget_destroy;
  153. end;
  154. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155. function custom_widget_size_allocateCB(Widget: PGtkWidget; Size: pGtkAllocation; Data: gPointer): GBoolean; cdecl;
  156. const
  157. CallBackDefaultReturn = {$IFDEF GTK2}false{$ELSE}true{$ENDIF};
  158. var
  159. SizeMsg: TLMSize;
  160. GtkWidth, GtkHeight: integer;
  161. LCLControl: TWinControl;
  162. begin
  163. Result := CallBackDefaultReturn;
  164. if not GTK_WIDGET_REALIZED(Widget) then begin
  165. // the widget is not yet realized, so this GTK resize was not a user change.
  166. // => ignore
  167. exit;
  168. end;
  169. if Size=nil then ;
  170. LCLControl:=TWinControl(Data);
  171. if LCLControl=nil then exit;
  172. //DebugLn(['gtkglarea_size_allocateCB ',DbgSName(LCLControl)]);
  173. gtk_widget_get_size_request(Widget, @GtkWidth, @GtkHeight);
  174. SizeMsg.Msg:=0;
  175. FillChar(SizeMsg,SizeOf(SizeMsg),0);
  176. with SizeMsg do
  177. begin
  178. Result := 0;
  179. Msg := LM_SIZE;
  180. SizeType := Size_SourceIsInterface;
  181. Width := SmallInt(GtkWidth);
  182. Height := SmallInt(GtkHeight);
  183. end;
  184. //DebugLn(['gtkglarea_size_allocateCB ',GtkWidth,',',GtkHeight]);
  185. LCLControl.WindowProc(TLMessage(SizeMsg));
  186. end;
  187. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  188. function GTK_TYPE_CUSTOM_WIDGET: TGtkType;
  189. const
  190. custom_widget_type_name = 'GtkGLArea';
  191. custom_widget_info: TGtkTypeInfo = (
  192. type_name: custom_widget_type_name;
  193. object_size: SizeOf(TGtkCustomWidget);
  194. class_size: SizeOf(TGtkCustomWidgetClass);
  195. class_init_func: @gtk_custom_widget_class_init;
  196. object_init_func: @gtk_custom_widget_init;
  197. reserved_1: nil;
  198. reserved_2: nil;
  199. base_class_init_func: nil;);
  200. begin
  201. if (custom_widget_type=0) then begin
  202. custom_widget_type:=gtk_type_unique(gtk_drawing_area_get_type(),@custom_widget_info);
  203. end;
  204. Result:=custom_widget_type;
  205. end;
  206. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  207. function CreateOpenGLContextAttrList(UseFB: boolean; aDoubleBuffered: Boolean; aColorBits, aDepthBits: Integer): TGLIntArray;
  208. var
  209. p: integer;
  210. procedure Add(i: integer);
  211. begin
  212. SetLength(Result, p+1);
  213. Result[p]:=i;
  214. inc(p);
  215. end;
  216. procedure CreateList;
  217. begin
  218. if UseFB then begin Add(GLX_X_RENDERABLE); Add(1); end;
  219. if aDoubleBuffered then begin
  220. if UseFB then begin
  221. Add(GLX_DOUBLEBUFFER); Add(1);
  222. end else
  223. Add(GLX_DOUBLEBUFFER);
  224. end;
  225. if not UseFB and (aColorBits > 24) then Add(GLX_RGBA);
  226. if UseFB then begin
  227. Add(GLX_DRAWABLE_TYPE);
  228. Add(GLX_WINDOW_BIT);
  229. end;
  230. Add(GLX_RED_SIZE); Add(8);
  231. Add(GLX_GREEN_SIZE); Add(8);
  232. Add(GLX_BLUE_SIZE); Add(8);
  233. if (aColorBits > 24) then
  234. Add(GLX_ALPHA_SIZE); Add(8);
  235. Add(GLX_DEPTH_SIZE); Add(aDepthBits);
  236. Add(GLX_STENCIL_SIZE); Add(0);
  237. Add(GLX_AUX_BUFFERS); Add(0);
  238. Add(0); { 0 = X.None (be careful: GLX_NONE is something different) }
  239. end;
  240. begin
  241. SetLength(Result, 0);
  242. p := 0;
  243. CreateList;
  244. end;
  245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. function FBglXChooseVisual(dpy:PDisplay; screen:longint; attrib_list:Plongint):PXVisualInfo;
  247. type
  248. PGLXFBConfig = ^GLXFBConfig;
  249. var
  250. FBConfigsCount: integer;
  251. FBConfigs: PGLXFBConfig;
  252. FBConfig: GLXFBConfig;
  253. begin
  254. Result:= nil;
  255. FBConfigsCount:=0;
  256. FBConfigs:= glXChooseFBConfig(dpy, screen, attrib_list, @FBConfigsCount);
  257. if FBConfigsCount = 0 then
  258. exit;
  259. { just choose the first FB config from the FBConfigs list.
  260. More involved selection possible. }
  261. FBConfig := FBConfigs^;
  262. Result:=glXGetVisualFromFBConfig(dpy, FBConfig);
  263. end;
  264. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  265. //TRenderControl////////////////////////////////////////////////////////////////////////////////////////////////////////
  266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. function TRenderControl.WSCreateHandle(const WSPrivate: TWSPrivateClass; const AParams: TCreateParams): TLCLIntfHandle;
  268. var
  269. cmap: PGdkColormap;
  270. gdkvis: PGdkVisual;
  271. begin
  272. // is the requested VisualID different from what the widget would get?
  273. cmap := gdk_colormap_get_system;
  274. gdkvis:= gdk_colormap_get_visual(cmap);
  275. if XVisualIDFromVisual(gdk_x11_visual_get_xvisual(gdkvis)) <> FVisualID then begin
  276. gdkvis := gdkx_visual_get(FVisualID);
  277. cmap := gdk_colormap_new(gdkvis, false);
  278. end;
  279. fIntWidget := gtk_type_new(GTK_TYPE_CUSTOM_WIDGET);
  280. gtk_widget_set_colormap(fIntWidget, cmap);
  281. Result := TLCLIntfHandle({%H-}PtrUInt(fIntWidget));
  282. PGtkobject(fIntWidget)^.flags:= PGtkobject(fIntWidget)^.flags or GTK_CAN_FOCUS;
  283. TGTK2WidgetSet(WidgetSet).FinishCreateHandle(Self,fIntWidget,AParams);
  284. g_signal_connect_after(fIntWidget, 'size-allocate', TGTKSignalFunc(@custom_widget_size_allocateCB), Self);
  285. end;
  286. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  287. procedure TRenderControl.WSBeforeDestroyHandle;
  288. begin
  289. if not HandleAllocated then exit;
  290. end;
  291. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  292. procedure TRenderControl.WndProc(var Message: TLMessage);
  293. begin
  294. case Message.msg of
  295. //LM_ACTIVATEITEM,
  296. //LM_CHANGED,
  297. //LM_FOCUS,
  298. LM_CLICKED,
  299. //LM_RELEASED,
  300. LM_ENTER,
  301. LM_LEAVE,
  302. //LM_CHECKRESIZE,
  303. //LM_SETEDITABLE,
  304. //LM_MOVEWORD,
  305. //LM_MOVEPAGE,
  306. //LM_MOVETOROW,
  307. //LM_MOVETOCOLUMN,
  308. //LM_KILLCHAR,
  309. //LM_KILLWORD,
  310. //LM_KILLLINE,
  311. //LM_CLOSEQUERY,
  312. //LM_DRAGSTART,
  313. //LM_MONTHCHANGED,
  314. //LM_YEARCHANGED,
  315. //LM_DAYCHANGED,
  316. LM_LBUTTONTRIPLECLK,
  317. LM_LBUTTONQUADCLK,
  318. LM_MBUTTONTRIPLECLK,
  319. LM_MBUTTONQUADCLK,
  320. LM_RBUTTONTRIPLECLK,
  321. LM_RBUTTONQUADCLK,
  322. LM_MOUSEENTER,
  323. LM_MOUSELEAVE,
  324. LM_XBUTTONTRIPLECLK,
  325. LM_XBUTTONQUADCLK,
  326. //SC_SIZE,
  327. //SC_MOVE,
  328. //SC_MINIMIZE,
  329. //SC_MAXIMIZE,
  330. //SC_NEXTWINDOW,
  331. //SC_PREVWINDOW,
  332. //SC_CLOSE,
  333. SC_VSCROLL,
  334. SC_HSCROLL,
  335. SC_MOUSEMENU,
  336. SC_KEYMENU,
  337. //SC_ARRANGE,
  338. //SC_RESTORE,
  339. //SC_TASKLIST,
  340. //SC_SCREENSAVE,
  341. //SC_HOTKEY,
  342. //SC_DEFAULT,
  343. //SC_MONITORPOWER,
  344. //SC_CONTEXTHELP,
  345. //SC_SEPARATOR,
  346. //LM_MOVE,
  347. //LM_SIZE,
  348. LM_ACTIVATE,
  349. LM_SETFOCUS,
  350. LM_KILLFOCUS,
  351. //LM_ENABLE,
  352. //LM_GETTEXTLENGTH,
  353. //LM_SHOWWINDOW,
  354. //LM_CANCELMODE,
  355. //LM_DRAWITEM,
  356. //LM_MEASUREITEM,
  357. //LM_DELETEITEM,
  358. //LM_VKEYTOITEM,
  359. //LM_CHARTOITEM,
  360. //LM_COMPAREITEM,
  361. //LM_WINDOWPOSCHANGING,
  362. //LM_WINDOWPOSCHANGED,
  363. //LM_NOTIFY,
  364. //LM_HELP,
  365. //LM_NOTIFYFORMAT,
  366. //LM_CONTEXTMENU,
  367. //LM_NCCALCSIZE,
  368. //LM_NCHITTEST,
  369. //LM_NCPAINT,
  370. //LM_NCACTIVATE,
  371. //LM_GETDLGCODE,
  372. LM_NCMOUSEMOVE,
  373. LM_NCLBUTTONDOWN,
  374. LM_NCLBUTTONUP,
  375. LM_NCLBUTTONDBLCLK,
  376. LM_KEYDOWN,
  377. LM_KEYUP,
  378. LM_CHAR,
  379. LM_SYSKEYDOWN,
  380. LM_SYSKEYUP,
  381. LM_SYSCHAR,
  382. LM_COMMAND,
  383. LM_SYSCOMMAND,
  384. LM_TIMER,
  385. LM_HSCROLL,
  386. LM_VSCROLL,
  387. //LM_CTLCOLORMSGBOX,
  388. //LM_CTLCOLOREDIT,
  389. //LM_CTLCOLORLISTBOX,
  390. //LM_CTLCOLORBTN,
  391. //LM_CTLCOLORDLG,
  392. //LM_CTLCOLORSCROLLBAR,
  393. //LM_CTLCOLORSTATIC,
  394. LM_MOUSEMOVE,
  395. LM_LBUTTONDOWN,
  396. LM_LBUTTONUP,
  397. LM_LBUTTONDBLCLK,
  398. LM_RBUTTONDOWN,
  399. LM_RBUTTONUP,
  400. LM_RBUTTONDBLCLK,
  401. LM_MBUTTONDOWN,
  402. LM_MBUTTONUP,
  403. LM_MBUTTONDBLCLK,
  404. LM_MOUSEWHEEL,
  405. LM_XBUTTONDOWN,
  406. LM_XBUTTONUP,
  407. LM_XBUTTONDBLCLK,
  408. //LM_PARENTNOTIFY,
  409. //LM_CAPTURECHANGED,
  410. //LM_DROPFILES,
  411. //LM_SELCHANGE,
  412. LM_CUT,
  413. LM_COPY,
  414. LM_PASTE,
  415. //LM_CLEAR,
  416. //LM_CONFIGUREEVENT,
  417. //LM_EXIT,
  418. //LM_QUIT,
  419. //LM_NULL,
  420. //LM_PAINT,
  421. //LM_ERASEBKGND,
  422. //LM_SETCURSOR,
  423. //LM_SETFONT:
  424. //CM_ACTIVATE,
  425. //CM_DEACTIVATE,
  426. //CM_FOCUSCHANGED,
  427. //CM_PARENTFONTCHANGED,
  428. //CM_PARENTCOLORCHANGED,
  429. //CM_HITTEST,
  430. //CM_VISIBLECHANGED,
  431. //CM_ENABLEDCHANGED,
  432. //CM_COLORCHANGED,
  433. //CM_FONTCHANGED,
  434. //CM_CURSORCHANGED,
  435. //CM_TEXTCHANGED,
  436. CM_MOUSEENTER,
  437. CM_MOUSELEAVE,
  438. //CM_MENUCHANGED,
  439. //CM_APPSYSCOMMAND,
  440. //CM_BUTTONPRESSED,
  441. //CM_SHOWINGCHANGED,
  442. //CM_ENTER,
  443. //CM_EXIT,
  444. //CM_DESIGNHITTEST,
  445. //CM_ICONCHANGED,
  446. //CM_WANTSPECIALKEY,
  447. //CM_RELEASE,
  448. //CM_FONTCHANGE,
  449. //CM_TABSTOPCHANGED,
  450. //CM_UIACTIVATE,
  451. //CM_CONTROLLISTCHANGE,
  452. //CM_GETDATALINK,
  453. //CM_CHILDKEY,
  454. //CM_HINTSHOW,
  455. //CM_SYSFONTCHANGED,
  456. //CM_CONTROLCHANGE,
  457. //CM_CHANGED,
  458. //CM_BORDERCHANGED,
  459. //CM_BIDIMODECHANGED,
  460. //CM_PARENTBIDIMODECHANGED,
  461. //CM_ALLCHILDRENFLIPPED,
  462. //CM_ACTIONUPDATE,
  463. //CM_ACTIONEXECUTE,
  464. //CM_HINTSHOWPAUSE,
  465. //CM_DOCKNOTIFICATION,
  466. CM_MOUSEWHEEL,
  467. //CM_APPSHOWBTNGLYPHCHANGED,
  468. //CM_APPSHOWMENUGLYPHCHANGED,
  469. //CN_BASE,
  470. //CN_CHARTOITEM,
  471. //CN_COMMAND,
  472. //CN_COMPAREITEM,
  473. //CN_CTLCOLORBTN,
  474. //CN_CTLCOLORDLG,
  475. //CN_CTLCOLOREDIT,
  476. //CN_CTLCOLORLISTBOX,
  477. //CN_CTLCOLORMSGBOX,
  478. //CN_CTLCOLORSCROLLBAR,
  479. //CN_CTLCOLORSTATIC,
  480. //CN_DELETEITEM,
  481. //CN_DRAWITEM,
  482. CN_HSCROLL,
  483. //CN_MEASUREITEM,
  484. //CN_PARENTNOTIFY,
  485. //CN_VKEYTOITEM,
  486. CN_VSCROLL,
  487. CN_KEYDOWN,
  488. CN_KEYUP,
  489. CN_CHAR,
  490. CN_SYSKEYUP,
  491. CN_SYSKEYDOWN,
  492. CN_SYSCHAR,
  493. CN_NOTIFY:
  494. begin
  495. if Assigned(fTarget) then
  496. Message.Result := fTarget.Perform(Message.msg, Message.wParam, Message.lParam);
  497. end;
  498. end;
  499. inherited WndProc(Message);
  500. end;
  501. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  502. constructor TRenderControl.Create(TheOwner: TComponent; const aVisualID: TVisualID);
  503. begin
  504. inherited Create(TheOwner);
  505. fIntWidget := nil;
  506. fVisualID := aVisualID;
  507. SetBounds(0, 0, 200, 200);
  508. end;
  509. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  510. //TWSCustomVisualControl////////////////////////////////////////////////////////////////////////////////////////////////
  511. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  512. class function TWSCustomVisualControl.CreateHandle(const AWinControl: TWinControl; const AParams: TCreateParams): TLCLIntfHandle;
  513. begin
  514. if csDesigning in AWinControl.ComponentState then begin
  515. // do not use "inherited CreateHandle", because the LCL changes the hierarchy at run time
  516. Result:= TWSWinControlClass(ClassParent).CreateHandle(AWinControl,AParams);
  517. end else
  518. Result:= (AWinControl as TRenderControl).WSCreateHandle(WSPrivate, AParams);
  519. end;
  520. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  521. class procedure TWSCustomVisualControl.DestroyHandle(const AWinControl: TWinControl);
  522. begin
  523. (AWinControl as TRenderControl).WSBeforeDestroyHandle;
  524. // do not use "inherited DestroyHandle", because the LCL changes the hierarchy at run time
  525. TWSWinControlClass(ClassParent).DestroyHandle(AWinControl);
  526. end;
  527. {$ENDIF}
  528. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  529. //MainForm//////////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  531. procedure TMainForm.FormCreate(Sender: TObject);
  532. var
  533. pp: TltsPostProcessor;
  534. img: TltsImage;
  535. begin
  536. CreateRenderContext;
  537. glDisable(GL_DEPTH_TEST);
  538. glDisable(GL_CULL_FACE);
  539. glClearColor(1.0, 1.0, 1.0, 1.0);
  540. ltsInitialize(LibName);
  541. Caption := 'libTextSuite example (Version: ' + ltsGetVersion() + ')';
  542. fltsContext := TltsContext.Create;
  543. fltsRenderer := TltsRendererOpenGL.Create(fltsContext, ltsFormatRGBA8);
  544. fltsCreator := {$IFDEF USE_FREETYPE}TltsFontCreatorFreeType{$ELSE}TltsFontCreatorGDI{$ENDIF}.Create(fltsContext);
  545. fltsPostProcessorList := TltsPostProcessorList.Create(fltsContext, true);
  546. img := TltsImage.Create(fltsContext);
  547. img.CreateEmpty(ltsFormatAlpha8, 4, 4);
  548. Move(PATTER_DATA[0], img.Data^, 16);
  549. pp := TltsPostProcessorFillPattern.Create(fltsContext, img, true, ltsPosition(0, 0), LTS_IMAGE_MODES_MODULATE_ALL, LTS_COLOR_CHANNELS_RGBA);
  550. pp.AddChars(ltsUsageInclude, 'Lorem');
  551. fltsPostProcessorList.Add(pp);
  552. pp := TltsPostProcessorFillColor.Create(fltsContext, ltsColor4f(0, 0, 0.5, 1), LTS_IMAGE_MODES_REPLACE_ALL, LTS_COLOR_CHANNELS_RGB);
  553. pp.AddChars(ltsUsageExclude, 'e');
  554. fltsPostProcessorList.Add(pp);
  555. pp := TltsPostProcessorBorder.Create(fltsContext, 3.0, 0.5, ltsColor4f(0.0, 0.5, 0.0, 1.0), true);
  556. pp.AddChars(ltsUsageInclude, 'e');
  557. fltsPostProcessorList.Add(pp);
  558. fltsFont := fltsCreator.GetFontByFile(ExpandFileName('../Prototype.ttf'), 40, [], ltsAANormal);
  559. fltsFont.PostProcessor := fltsPostProcessorList;
  560. fCanRender := true;
  561. end;
  562. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  563. procedure TMainForm.FormDestroy(Sender: TObject);
  564. begin
  565. FreeAndNil(fltsFont);
  566. FreeAndNil(fltsPostProcessorList);
  567. FreeAndNil(fltsCreator);
  568. FreeAndNil(fltsRenderer);
  569. FreeAndNil(fltsContext);
  570. ltsFinalize;
  571. DestroyRenderContext;
  572. end;
  573. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574. procedure TMainForm.FormPaint(Sender: TObject);
  575. begin
  576. if fCanRender then
  577. Render;
  578. end;
  579. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  580. procedure TMainForm.FormResize(Sender: TObject);
  581. begin
  582. if fHasRenderContext then begin
  583. glViewport(0, 0, ClientWidth, ClientHeight);
  584. glMatrixMode(GL_PROJECTION);
  585. glLoadIdentity;
  586. glOrtho(0, ClientWidth, ClientHeight, 0, 10, -10);
  587. glMatrixMode(GL_MODELVIEW);
  588. glLoadIdentity;
  589. end;
  590. end;
  591. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  592. {$IF DEFINED(WIN32) OR DEFINED(WIN64)}
  593. procedure TMainForm.CreateRenderContext;
  594. function FindPixelFormat: Integer;
  595. const
  596. MemoryDCs = [OBJ_MEMDC, OBJ_METADC, OBJ_ENHMETADC];
  597. var
  598. AType: DWord;
  599. PFDescriptor: TPixelFormatDescriptor;
  600. begin
  601. result := 0;
  602. FillChar(PFDescriptor{%H-}, SizeOf(PFDescriptor), #0);
  603. with PFDescriptor do begin
  604. nSize := SizeOf(PFDescriptor);
  605. nVersion := 1;
  606. dwFlags := PFD_SUPPORT_OPENGL;
  607. AType := GetObjectType(fDC);
  608. if AType = 0 then
  609. raise Exception.Create('unable to get device context object type');
  610. dwFlags := dwFlags or PFD_DOUBLEBUFFER;
  611. if AType in MemoryDCs then
  612. dwFlags := dwFlags or PFD_DRAW_TO_BITMAP
  613. else
  614. dwFlags := dwFlags or PFD_DRAW_TO_WINDOW;
  615. iPixelType := PFD_TYPE_RGBA;
  616. cColorBits := 32;
  617. cDepthBits := 24;
  618. cStencilBits := 0;
  619. cAccumBits := 0;
  620. cAuxBuffers := 0;
  621. iLayerType := PFD_MAIN_PLANE;
  622. end;
  623. result := ChoosePixelFormat(fDC, @PFDescriptor);
  624. end;
  625. var
  626. pf: Integer;
  627. err: DWORD;
  628. begin
  629. InitOpenGL;
  630. fDC := GetDC(Handle);
  631. if (fDC = 0) then
  632. raise Exception.Create('unable to get device context');
  633. pf := FindPixelFormat;
  634. if not SetPixelFormat(fDC, pf, nil) then begin
  635. ReleaseDC(Handle, fDC);
  636. raise Exception.CreateFmt('Cannot set PF %d on Control %x DC %d', [pf, Handle, FDC]);
  637. end;
  638. fRC := wglCreateContext(FDC);
  639. if (fRC = 0) then begin
  640. ReleaseDC(Handle, FDC);
  641. raise Exception.CreateFmt('Cannot create context on Control %x DC %d', [pf, Handle, FDC]);
  642. end;
  643. if not wglMakeCurrent(fDC, fRC) then begin
  644. err := GetLastError;
  645. raise Exception.Create('unable to activate context: (' + IntToStr(err) + ') ' + SysErrorMessage(err));
  646. end;
  647. ReadOpenGLCore;
  648. ReadExtensions;
  649. ReadImplementationProperties;
  650. fHasRenderContext := true;
  651. end;
  652. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  653. procedure TMainForm.DestroyRenderContext;
  654. begin
  655. wglMakeCurrent(0, 0);
  656. DestroyRenderingContext(fRC);
  657. ReleaseDC(Handle, fDC);
  658. end;
  659. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  660. procedure TMainForm.SwapBuffers;
  661. begin
  662. Windows.SwapBuffers(fDC);
  663. end;
  664. {$ELSEIF DEFINED(LINUX)}
  665. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  666. procedure TMainForm.CreateRenderContext;
  667. procedure UpdateVisual;
  668. var
  669. attrList: TGLIntArray;
  670. drawable: PGdkDrawable;
  671. begin
  672. { Temporary (realized) widget to get to display }
  673. fWidget:= {%H-}PGtkWidget(PtrUInt(Handle));
  674. gtk_widget_realize(fWidget);
  675. drawable := GTK_WIDGET(fWidget)^.window;
  676. fDisplay := GDK_WINDOW_XDISPLAY(drawable);
  677. { Find a suitable visual from PixelFormat using GLX 1.3 FBConfigs or
  678. old-style Visuals }
  679. if Assigned(glXChooseFBConfig) then begin
  680. attrList := CreateOpenGLContextAttrList(true, true, 32, 24);
  681. fVisual := FBglXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
  682. end;
  683. if not Assigned(fVisual) then begin
  684. attrList := CreateOpenGLContextAttrList(false, true, 32, 24);
  685. fVisual := glXChooseVisual(FDisplay, DefaultScreen(FDisplay), @attrList[0]);
  686. end;
  687. if not Assigned(fVisual) then
  688. raise Exception.Create('choose visual failed');
  689. { Most widgets inherit the drawable of their parent. In contrast to Windows, descending from
  690. TWinControl does not mean it's actually always a window of its own.
  691. Famous example: TPanel is just a frame painted on a canvas.
  692. Also, the LCL does somethin weird to colormaps in window creation, so we have
  693. to use a custom widget here to have full control about visual selection. }
  694. fRenderControl:= TRenderControl.Create(self, fVisual^.visual^.visualid);
  695. try
  696. fRenderControl.Parent := self;
  697. fRenderControl.HandleNeeded;
  698. fRenderControl.Target := self;
  699. except
  700. FreeAndNil(fRenderControl);
  701. raise;
  702. end;
  703. { Real Widget handle, unrealized!!! }
  704. fWidget := fRenderControl.Widget;
  705. gtk_widget_realize(fWidget);
  706. drawable := GTK_WIDGET(fWidget)^.window;
  707. FDisplay := GDK_WINDOW_XDISPLAY(drawable);
  708. // fRenderControl.Align:= alClient breaks the context or something
  709. fRenderControl.BoundsRect := ClientRect;
  710. fRenderControl.Anchors := [akLeft, akTop, akRight, akBottom];
  711. end;
  712. var
  713. glxID: GLXDrawable;
  714. begin
  715. InitOpenGL;
  716. UpdateVisual;
  717. if not Assigned(FVisual) then
  718. raise Exception.Create('Failed to find Visual');
  719. fContext := glXCreateContext(FDisplay, FVisual, nil, true);
  720. if not Assigned(fContext) then
  721. raise Exception.Create('Failed to create Context');
  722. gtk_widget_realize(fWidget);
  723. if not GTK_WIDGET_REALIZED(fWidget) then
  724. exit;
  725. glxID := GDK_DRAWABLE_XID(GTK_WIDGET(fWidget)^.window);
  726. glXMakeCurrent(fDisplay, glxID, fContext);
  727. ReadOpenGLCore;
  728. ReadExtensions;
  729. ReadImplementationProperties;
  730. fHasRenderContext := true;
  731. end;
  732. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  733. procedure TMainForm.DestroyRenderContext;
  734. var
  735. glxID: GLXDrawable;
  736. begin
  737. glxID := GDK_DRAWABLE_XID(GTK_WIDGET(fWidget)^.window);
  738. glXMakeCurrent(FDisplay, glxID, nil);
  739. if Assigned(fContext) then
  740. glXDestroyContext(fDisplay, fContext);
  741. FreeAndNil(fRenderControl);
  742. end;
  743. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  744. procedure TMainForm.SwapBuffers;
  745. var
  746. glxID: GLXDrawable;
  747. begin
  748. if not Assigned(fWidget) then
  749. exit;
  750. glxID := GDK_DRAWABLE_XID(GTK_WIDGET(fWidget)^.window);
  751. glXSwapBuffers(fDisplay, glxID);
  752. end;
  753. {$ENDIF}
  754. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  755. procedure TMainForm.Render;
  756. var
  757. block: TltsTextBlock;
  758. begin
  759. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  760. glLoadIdentity;
  761. glEnable(GL_BLEND);
  762. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  763. block := fltsRenderer.BeginBlock(10, 10, ClientWidth-20, ClientHeight-20, [ltsBlockFlagWordWrap]);
  764. try
  765. block.HorzAlign := ltsHorzAlignJustify;
  766. block.ChangeFont(fltsFont);
  767. block.ChangeColor(ltsColor4f(1.0, 1.0, 1.0, 1.0));
  768. block.TextOutW(TEST_TEXT);
  769. finally
  770. fltsRenderer.EndBlock(block);
  771. end;
  772. SwapBuffers;
  773. end;
  774. {$IFDEF LINUX}
  775. initialization
  776. RegisterWSComponent(TRenderControl, TWSCustomVisualControl);
  777. {$ENDIF}
  778. end.