es2example1.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. program es2example1;
  2. // By Benjamin 'BeRo' Rosseaux - [email protected] - http://www.rosseaux.com
  3. // Tested on desktop linux and the Nokia N900 with Maemo 5
  4. {$ifdef fpc}
  5. {$mode delphi}
  6. {$ifdef CPUARM}
  7. {$define ogles}
  8. {$endif}
  9. {$ifdef CPUI386}
  10. {$define CPU386}
  11. {$endif}
  12. {$ifdef CPU386}
  13. {$asmmode intel}
  14. {$endif}
  15. {$endif}
  16. uses SysUtils,Classes,BaseUnix,Unix,UnixType,X,XLib,XUtil,XAtom{$ifdef ogles},gles20{$else},xf86vmode,GL,GLX,GLExt{$endif};
  17. const VertexArray:array[0..11] of single=(0,-1,0,1,
  18. 1,1,0,1,
  19. -1,1,0,1);
  20. ShaderPrecode={$ifdef ogles}''{$else}'#version 120'#10{$endif};
  21. VertexShaderSource:string=ShaderPrecode+'attribute vec4 position;'#10+
  22. 'varying mediump vec2 pos;'#10+
  23. 'void main(){'#10+
  24. ' gl_Position=position;'#10+
  25. ' pos=position.xy;'#10+
  26. '}';
  27. FragmentShaderSource:string=ShaderPrecode+'varying mediump vec2 pos;'#10+
  28. 'uniform mediump float phase;'#10+
  29. 'void main(){'#10+
  30. ' gl_FragColor=vec4(1.0,1.0,1.0,1.0)*sin(((pos.x*pos.x)+(pos.y*pos.y))*40.0+phase);'#10+
  31. '}';
  32. var ReturnCode,CanvasWidth,CanvasHeight:integer;
  33. Running:boolean;
  34. VertexShader,FragmentShader,ShaderProgram:TGLuint;
  35. PhaseLocation:TGLint;
  36. CurrentTime:int64;
  37. function GetTime:int64;
  38. var NowTime:TDateTime;
  39. Year,Month,Day,hour,min,sec,msec:word;
  40. begin
  41. NowTime:=Now;
  42. DecodeDate(NowTime,Year,Month,Day);
  43. DecodeTime(NowTime,hour,min,sec,msec);
  44. result:=(((((((((((Year*365)+Month)*31)+Day)*24)+hour)*60)+min)*60)+sec)*1000)+msec;
  45. end;
  46. procedure PrintShaderInfoLog(Shader:TGLUint;ShaderType:string);
  47. var len,Success:TGLint;
  48. Buffer:pchar;
  49. begin
  50. glGetShaderiv(Shader,GL_COMPILE_STATUS,@Success);
  51. if Success<>GL_TRUE then begin
  52. glGetShaderiv(Shader,GL_INFO_LOG_LENGTH,@len);
  53. if len>0 then begin
  54. getmem(Buffer,len+1);
  55. glGetShaderInfoLog(Shader,len,nil,Buffer);
  56. writeln(ShaderType,': ',Buffer);
  57. freemem(Buffer);
  58. Running:=false;
  59. ReturnCode:=1;
  60. end;
  61. end;
  62. end;
  63. function CreateShader(ShaderType:TGLenum;Source:pchar):TGLuint;
  64. begin
  65. result:=glCreateShader(ShaderType);
  66. glShaderSource(result,1,@Source,nil);
  67. glCompileShader(result);
  68. if ShaderType=GL_VERTEX_SHADER then begin
  69. PrintShaderInfoLog(result,'Vertex shader');
  70. end else begin
  71. PrintShaderInfoLog(result,'Fragment shader');
  72. end;
  73. end;
  74. procedure Init;
  75. begin
  76. ShaderProgram:=glCreateProgram();
  77. VertexShader:=CreateShader(GL_VERTEX_SHADER,pchar(VertexShaderSource));
  78. FragmentShader:=CreateShader(GL_FRAGMENT_SHADER,pchar(FragmentShaderSource));
  79. glAttachShader(ShaderProgram,VertexShader);
  80. glAttachShader(ShaderProgram,FragmentShader);
  81. glLinkProgram(ShaderProgram);
  82. glUseProgram(ShaderProgram);
  83. PhaseLocation:=glGetUniformLocation(ShaderProgram,'phase');
  84. if PhaseLocation<0 then begin
  85. writeln('Error: Cannot get phase shader uniform location');
  86. Running:=false;
  87. ReturnCode:=1;
  88. end;
  89. end;
  90. procedure Done;
  91. begin
  92. end;
  93. procedure Render;
  94. begin
  95. glViewPort(0,0,CanvasWidth,CanvasHeight);
  96. glClearColor(0,1,0,1);
  97. glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  98. glUniform1f(PhaseLocation,(GetTime mod 2000)*0.001*pi);
  99. glVertexAttribPointer(0,4,GL_FLOAT,0,0,@VertexArray);
  100. glEnableVertexAttribArray(0);
  101. glDrawArrays(GL_TRIANGLE_STRIP,0,3);
  102. end;
  103. const MOUSE_MASK=ButtonPressMask or ButtonReleaseMask or PointerMotionMask or ButtonMotionMask;
  104. KEY_MASK=KeyPressMask or KeyReleaseMask or KeymapStateMask;
  105. X_MASK=KEY_MASK or MOUSE_MASK or VisibilityChangeMask or StructureNotifymask or ExposureMask;
  106. {$ifdef ogles}
  107. Attr:array[0..6] of EGLint=(EGL_BUFFER_SIZE,16,
  108. EGL_DEPTH_SIZE,8,
  109. EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
  110. EGL_NONE);
  111. { Attr:array[0..12] of EGLint=(EGL_BUFFER_SIZE,16,
  112. EGL_RED_SIZE,6,
  113. EGL_GREEN_SIZE,5,
  114. EGL_BLUE_SIZE,6,
  115. EGL_DEPTH_SIZE,8,
  116. EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
  117. EGL_NONE);}
  118. CtxAttr:array[0..2] of EGLint=(EGL_CONTEXT_CLIENT_VERSION,2,EGL_NONE);
  119. {$else}
  120. Attr:array[0..8] of TGLint=(GLX_RGBA,
  121. GLX_RED_SIZE,1,
  122. GLX_GREEN_SIZE,1,
  123. GLX_BLUE_SIZE,1,
  124. GLX_DOUBLEBUFFER,
  125. none);
  126. {$endif}
  127. Title:string='GL test';
  128. var dpy:PXDisplay;
  129. win,root:TWindow;
  130. screennum,ScreenWidth,ScreenHeight:integer;
  131. screen:PScreen;
  132. visual:PVisual;
  133. Event:TXEvent;
  134. {$ifdef ogles}
  135. swa:TXSetWindowAttributes;
  136. ecfg:EGLConfig;
  137. num_config:EGLint;
  138. esfc:EGLSurface;
  139. ectxt:EGLContext;
  140. edpy:EGLDisplay;
  141. mouse_accel_numerator,mouse_accel_denominator,mouse_threshold:integer;
  142. {$else}
  143. WinAttr:TXSetWindowAttributes;
  144. GLXCont:GLXContext;
  145. WindowTitleProperty:TXTextProperty;
  146. visualinfo:PXVisualInfo;
  147. ErrorBase,EventBase:integer;
  148. {$endif}
  149. WM_DELETE_WINDOW:TAtom;
  150. procedure DisableComposition;
  151. {$ifdef ogles}
  152. const one:integer=1;
  153. {$endif}
  154. var xclient:TXClientMessageEvent;
  155. wm_state,fullscreen{$ifdef ogles},non_composited{$endif}:TAtom;
  156. begin
  157. wm_state:=XInternAtom(dpy,'_NET_WM_STATE',false);
  158. fullscreen:=XInternAtom(dpy,'_NET_WN_STATE_FULLSCREEN',false);
  159. XChangeProperty(dpy,win,wm_state,XA_ATOM,32,PropModeReplace,@fullscreen,1);
  160. XFlush(dpy);
  161. {$ifdef ogles}
  162. non_composited:=XInternAtom(dpy,'_HILDON_NON_COMPOSITED_WINDOW',false);
  163. XChangeProperty(dpy,win,non_composited,XA_INTEGER,32,PropModeReplace,@one,1);
  164. XFlush(dpy);
  165. {$endif}
  166. xclient._type:=ClientMessage;
  167. xclient.window:=win;
  168. xclient.message_type:=XInternAtom(dpy,'_NET_WM_STATE',false);
  169. xclient.format:=32;
  170. xclient.data.l[0]:=1;
  171. xclient.data.l[1]:=XInternAtom(dpy,'_NET_WM_STATE_FULLSCREEN',false);
  172. xclient.data.l[2]:=0;
  173. xclient.data.l[3]:=0;
  174. xclient.data.l[4]:=0;
  175. XSendEvent(dpy,root,false,SubstructureRedirectMask or SubstructureNotifyMask,PXEvent(pointer(@xclient)));
  176. XFlush(dpy);
  177. end;
  178. procedure SetEmptyMouseCursor;
  179. const bm_no_data:array[0..7] of byte=(0,0,0,0,0,0,0,0);
  180. var bm_no:TPixmap;
  181. cmap:TColormap;
  182. no_ptr:TCursor;
  183. black,dummy:TXColor;
  184. begin
  185. cmap:=DefaultColormap(Dpy,screennum);
  186. XAllocNamedColor(Dpy,cmap,'black',@black,@dummy);
  187. bm_no:=XCreateBitmapFromData(Dpy,Win,POINTER(@bm_no_data),8,8);
  188. no_ptr:=XCreatePixmapCursor(Dpy,bm_no,bm_no,@black,@black,0,0);
  189. XDefineCursor(Dpy,Win,no_ptr);
  190. XFreeCursor(Dpy,no_ptr);
  191. if bm_no<>None then begin
  192. XFreePixmap(Dpy,bm_no);
  193. end;
  194. XFreeColors(Dpy,cmap,@black.pixel,1,0);
  195. end;
  196. begin
  197. CurrentTime:=0;
  198. dpy:=XOpenDisplay(nil);
  199. if not assigned(dpy) then begin
  200. writeln('Error: Cannot connect to X server');
  201. halt(1);
  202. end;
  203. root:=DefaultRootWindow(dpy);
  204. screen:=XDefaultScreenOfDisplay(dpy);
  205. if not assigned(screen) then begin
  206. writeln('Error: Cannot get default screen');
  207. halt(1);
  208. end;
  209. ScreenWidth:=screen^.Width;
  210. ScreenHeight:=screen^.Height;
  211. screennum:=XDefaultScreen(dpy);
  212. visual:=XDefaultVisualOfScreen(screen);
  213. CanvasWidth:=ScreenWidth;
  214. CanvasHeight:=ScreenHeight;
  215. {$ifdef ogles}
  216. swa.event_mask:=X_MASK;
  217. win:=XCreateWindow(dpy,root,0,0,ScreenWidth,ScreenHeight,0,CopyFromParent,InputOutput,Visual,CWEventMask,@swa);
  218. WM_DELETE_WINDOW:=XInternAtom(dpy,'WM_DELETE_WINDOW',FALSE);
  219. XSetWMProtocols(dpy,win,@WM_DELETE_WINDOW,1);
  220. XFlush(dpy);
  221. DisableComposition;
  222. XMapWindow(dpy,win);
  223. XFlush(dpy);
  224. DisableComposition;
  225. XSelectInput(Dpy,Win,FocusChangeMask or KeyPressMask or KeyReleaseMask or PropertyChangeMask or StructureNotifyMask or KeymapStateMask or PointerMotionMask or EnterWindowMask or LeaveWindowMask or ButtonPressMask or ButtonReleaseMask or ExposureMask);
  226. XStoreName(dpy,win,pchar(Title));
  227. XFlush(dpy);
  228. XMoveWindow(dpy,win,0,0);
  229. XRaiseWindow(dpy,win);
  230. //XWarpPointer(dpy,None,win,0,0,0,0,0,0);
  231. XFlush(dpy);
  232. SetEmptyMouseCursor;
  233. XGrabPointer(dpy,win,true,MOUSE_MASK,GrabModeAsync,GrabModeAsync,win,None,CurrentTime);
  234. XFlush(dpy);
  235. XGetPointerControl(dpy,@mouse_accel_numerator,@mouse_accel_denominator,@mouse_threshold);
  236. XFlush(dpy);
  237. XChangePointerControl(dpy,1,1,1,1,0);
  238. XFlush(dpy);
  239. XGrabKeyboard(dpy,win,false,GrabModeAsync,GrabModeAsync,CurrentTime);
  240. XFlush(dpy);
  241. edpy:=eglGetDisplay(dpy);
  242. if edpy=EGL_NO_DISPLAY then begin
  243. writeln('Error: Got no EGL display');
  244. halt(1);
  245. end;
  246. if eglInitialize(edpy,nil,nil)=0 then begin
  247. writeln('Error: Unable to initialize EGL');
  248. halt(1);
  249. end;
  250. num_config:=0;
  251. if eglChooseConfig(edpy,@Attr,@ecfg,1,@num_config)=0 then begin
  252. writeln('Error: Failed to choose config (',eglGetError,')');
  253. halt(1);
  254. end;
  255. if num_config<>1 then begin
  256. writeln('Error: Didn''t get exactly config but ',num_config);
  257. halt(1);
  258. end;
  259. esfc:=eglCreateWindowSurface(edpy,ecfg,win,nil);
  260. if esfc=EGL_NO_SURFACE then begin
  261. writeln('Error: Unable to create EGL surface (',eglGetError,')');
  262. halt(1);
  263. end;
  264. ectxt:=eglCreateContext(edpy,ecfg,EGL_NO_CONTEXT,@CtxAttr);
  265. if ectxt=EGL_NO_CONTEXT then begin
  266. writeln('Error: Unable to create EGL context (',eglGetError,')');
  267. halt(1);
  268. end;
  269. eglMakeCurrent(edpy,esfc,esfc,ectxt);
  270. {$else}
  271. InitGLX;
  272. if not glXQueryExtension(dpy,ErrorBase,EventBase) then begin
  273. writeln('Error: GLX extension not supported');
  274. halt(1);
  275. end;
  276. visualinfo:=glXChooseVisual(dpy,screennum,Attr);
  277. if not assigned(Visualinfo) THEN BEGIN
  278. writeln('Error: Could not find visual info');
  279. exit;
  280. end;
  281. WinAttr.colormap:=XCreateColormap(dpy,root,VisualInfo.Visual,AllocNone);
  282. WinAttr.border_pixel:=0;
  283. WinAttr.background_pixel:=0;
  284. WinAttr.event_mask:=X_MASK;
  285. WinAttr.override_redirect:=1;
  286. WinAttr.backing_store:=NotUseful;
  287. WinAttr.save_under:=0;
  288. Win:=XCreateWindow(dpy,root,0,0,ScreenWidth,ScreenHeight,0,VisualInfo.Depth,InputOutput,VisualInfo.Visual,CWOverrideRedirect or CWBackPixel or CWColormap or CWBackingStore or CWSaveUnder or CWEventMask,@WinAttr);
  289. XSelectInput(Dpy,Win,FocusChangeMask or KeyPressMask or KeyReleaseMask or PropertyChangeMask or StructureNotifyMask or KeymapStateMask or PointerMotionMask or EnterWindowMask or LeaveWindowMask or ButtonPressMask or ButtonReleaseMask or ExposureMask);
  290. XStringListToTextProperty(@Title,1,@WindowTitleProperty);
  291. XSetWMName(Dpy,Win,@WindowTitleProperty);
  292. glXCont:=glXCreateContext(Dpy,VisualInfo,none,true);
  293. if not assigned(glXCont) then begin
  294. writeln('Error: Could not create an OpenGL rendering context');
  295. halt(1);
  296. end;
  297. DisableComposition;
  298. XMapWindow(Dpy,Win);
  299. XFlush(dpy);
  300. DisableComposition;
  301. glXMakeCurrent(Dpy,Win,glXCont);
  302. SetEmptyMouseCursor;
  303. XMoveWindow(dpy,win,0,0);
  304. XRaiseWindow(dpy,win);
  305. XWarpPointer(dpy,None,win,0,0,0,0,0,0);
  306. XFlush(dpy);
  307. XF86VidmodeSetViewPort(dpy,screennum,0,0);
  308. XFlush(dpy);
  309. XGrabPointer(dpy,win,true,MOUSE_MASK,GrabModeAsync,GrabModeAsync,win,None,CurrentTime);
  310. XGrabKeyboard(dpy,win,false,GrabModeAsync,GrabModeAsync,CurrentTime);
  311. XFlush(dpy);
  312. XAutoRepeatOn(Dpy);
  313. XFlush(dpy);
  314. WM_DELETE_WINDOW:=XInternAtom(dpy,'WM_DELETE_WINDOW',FALSE);
  315. XSetWMProtocols(dpy,win,@WM_DELETE_WINDOW,1);
  316. XFlush(Dpy);
  317. CanvasWidth:=ScreenWidth;
  318. CanvasHeight:=ScreenHeight;
  319. if assigned(visual) then begin
  320. // Den Compiler befriedigen, so dass der kein Warning deswegen ausspuckt :)
  321. end;
  322. {$endif}
  323. Running:=true;
  324. ReturnCode:=0;
  325. {$ifndef ogles}
  326. if not (Load_GL_version_1_2 and Load_GL_version_1_3 and Load_GL_version_1_4 and Load_GL_version_2_0) then begin
  327. Running:=false;
  328. writeln('Error: Cannot load OpenGL 2.0 API');
  329. ReturnCode:=1;
  330. end;
  331. {$endif}
  332. if Running then begin
  333. Init;
  334. CurrentTime:=GetTime;
  335. end;
  336. while Running do begin
  337. while XPending(Dpy)>0 do begin
  338. XNextEvent(Dpy,@Event);
  339. case Event._type of
  340. ClientMessage:BEGIN
  341. if (Event.xclient.format=32) and (longword(Event.xclient.Data.l[0])=longword(WM_DELETE_WINDOW)) then begin
  342. Running:=false;
  343. end;
  344. end;
  345. Expose:begin
  346. end;
  347. ConfigureNotify:begin
  348. end;
  349. MotionNotify:begin
  350. // Running:=false;
  351. end;
  352. ButtonPress:begin
  353. Running:=false;
  354. end;
  355. ButtonRelease:begin
  356. Running:=false;
  357. end;
  358. KeyMapNotify:begin
  359. end;
  360. KeyPress:begin
  361. Running:=false;
  362. end;
  363. KeyRelease:begin
  364. Running:=false;
  365. end;
  366. end;
  367. end;
  368. CurrentTime:=GetTime;
  369. Render;
  370. {$ifdef ogles}
  371. eglSwapBuffers(edpy,esfc);
  372. {$else}
  373. glXSwapBuffers(dpy,win);
  374. {$endif}
  375. XFlush(dpy);
  376. end;
  377. if ReturnCode=0 then begin
  378. Done;
  379. end;
  380. {$ifdef ogles}
  381. XChangePointerControl(dpy,1,1,mouse_accel_numerator,mouse_accel_denominator,mouse_threshold);
  382. XUngrabPointer(dpy,CurrentTime);
  383. XUngrabKeyboard(dpy,CurrentTime);
  384. eglDestroyContext(edpy,ectxt);
  385. eglDestroySurface(edpy,esfc);
  386. eglTerminate(edpy);
  387. {$else}
  388. XUngrabPointer(dpy,CurrentTime);
  389. XUngrabKeyboard(dpy,CurrentTime);
  390. glXDestroyContext(dpy,glxCont);
  391. {$endif}
  392. XDestroyWindow(dpy,win);
  393. XCloseDisplay(dpy);
  394. halt(ReturnCode);
  395. end.