|
@@ -0,0 +1,492 @@
|
|
|
+program es2example1;
|
|
|
+// By Benjamin 'BeRo' Rosseaux - [email protected] - http://www.rosseaux.com
|
|
|
+// Tested on desktop linux and the Nokia N900 with Maemo 5
|
|
|
+{$ifdef fpc}
|
|
|
+ {$mode delphi}
|
|
|
+ {$ifdef CPUARM}
|
|
|
+ {$define ogles}
|
|
|
+ {$endif}
|
|
|
+ {$ifdef CPUI386}
|
|
|
+ {$define CPU386}
|
|
|
+ {$endif}
|
|
|
+ {$ifdef CPU386}
|
|
|
+ {$asmmode intel}
|
|
|
+ {$endif}
|
|
|
+{$endif}
|
|
|
+
|
|
|
+uses SysUtils,Classes,BaseUnix,Unix,UnixType,X,XLib,XUtil,XAtom{$ifdef ogles},gles20{$else},xf86vmode,GL,GLX,GLExt{$endif};
|
|
|
+
|
|
|
+const VertexArray:array[0..11] of single=(0,-1,0,1,
|
|
|
+ 1,1,0,1,
|
|
|
+ -1,1,0,1);
|
|
|
+
|
|
|
+ ShaderPrecode={$ifdef ogles}''{$else}'#version 120'#10{$endif};
|
|
|
+
|
|
|
+ VertexShaderSource:string=ShaderPrecode+'attribute vec4 position;'#10+
|
|
|
+ 'varying mediump vec2 pos;'#10+
|
|
|
+ 'void main(){'#10+
|
|
|
+ ' gl_Position=position;'#10+
|
|
|
+ ' pos=position.xy;'#10+
|
|
|
+ '}';
|
|
|
+
|
|
|
+ FragmentShaderSource:string=ShaderPrecode+'varying mediump vec2 pos;'#10+
|
|
|
+ 'uniform mediump float phase;'#10+
|
|
|
+ 'void main(){'#10+
|
|
|
+ ' gl_FragColor=vec4(1.0,1.0,1.0,1.0)*sin(((pos.x*pos.x)+(pos.y*pos.y))*40.0+phase);'#10+
|
|
|
+ '}';
|
|
|
+
|
|
|
+var ReturnCode,CanvasWidth,CanvasHeight:integer;
|
|
|
+ Running:boolean;
|
|
|
+ VertexShader,FragmentShader,ShaderProgram:TGLuint;
|
|
|
+ PhaseLocation:TGLint;
|
|
|
+ CurrentTime:int64;
|
|
|
+
|
|
|
+function GetTime:int64;
|
|
|
+var NowTime:TDateTime;
|
|
|
+ Year,Month,Day,hour,min,sec,msec:word;
|
|
|
+begin
|
|
|
+ NowTime:=Now;
|
|
|
+ DecodeDate(NowTime,Year,Month,Day);
|
|
|
+ DecodeTime(NowTime,hour,min,sec,msec);
|
|
|
+ result:=(((((((((((Year*365)+Month)*31)+Day)*24)+hour)*60)+min)*60)+sec)*1000)+msec;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure PrintShaderInfoLog(Shader:TGLUint;ShaderType:string);
|
|
|
+var len,Success:TGLint;
|
|
|
+ Buffer:pchar;
|
|
|
+begin
|
|
|
+ glGetShaderiv(Shader,GL_COMPILE_STATUS,@Success);
|
|
|
+ if Success<>GL_TRUE then begin
|
|
|
+ glGetShaderiv(Shader,GL_INFO_LOG_LENGTH,@len);
|
|
|
+ if len>0 then begin
|
|
|
+ getmem(Buffer,len+1);
|
|
|
+ glGetShaderInfoLog(Shader,len,nil,Buffer);
|
|
|
+ writeln(ShaderType,': ',Buffer);
|
|
|
+ freemem(Buffer);
|
|
|
+ Running:=false;
|
|
|
+ ReturnCode:=1;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+function CreateShader(ShaderType:TGLenum;Source:pchar):TGLuint;
|
|
|
+begin
|
|
|
+ result:=glCreateShader(ShaderType);
|
|
|
+ glShaderSource(result,1,@Source,nil);
|
|
|
+ glCompileShader(result);
|
|
|
+ if ShaderType=GL_VERTEX_SHADER then begin
|
|
|
+ PrintShaderInfoLog(result,'Vertex shader');
|
|
|
+ end else begin
|
|
|
+ PrintShaderInfoLog(result,'Fragment shader');
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure Init;
|
|
|
+begin
|
|
|
+ ShaderProgram:=glCreateProgram();
|
|
|
+
|
|
|
+ VertexShader:=CreateShader(GL_VERTEX_SHADER,pchar(VertexShaderSource));
|
|
|
+ FragmentShader:=CreateShader(GL_FRAGMENT_SHADER,pchar(FragmentShaderSource));
|
|
|
+
|
|
|
+ glAttachShader(ShaderProgram,VertexShader);
|
|
|
+ glAttachShader(ShaderProgram,FragmentShader);
|
|
|
+
|
|
|
+ glLinkProgram(ShaderProgram);
|
|
|
+
|
|
|
+ glUseProgram(ShaderProgram);
|
|
|
+
|
|
|
+ PhaseLocation:=glGetUniformLocation(ShaderProgram,'phase');
|
|
|
+ if PhaseLocation<0 then begin
|
|
|
+ writeln('Error: Cannot get phase shader uniform location');
|
|
|
+ Running:=false;
|
|
|
+ ReturnCode:=1;
|
|
|
+ end;
|
|
|
+end;
|
|
|
+
|
|
|
+procedure Done;
|
|
|
+begin
|
|
|
+end;
|
|
|
+
|
|
|
+procedure Render;
|
|
|
+begin
|
|
|
+ glViewPort(0,0,CanvasWidth,CanvasHeight);
|
|
|
+ glClearColor(0,1,0,1);
|
|
|
+ glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
|
|
|
+
|
|
|
+ glUniform1f(PhaseLocation,(GetTime mod 2000)*0.001*pi);
|
|
|
+
|
|
|
+ glVertexAttribPointer(0,4,GL_FLOAT,0,0,@VertexArray);
|
|
|
+ glEnableVertexAttribArray(0);
|
|
|
+ glDrawArrays(GL_TRIANGLE_STRIP,0,3);
|
|
|
+
|
|
|
+end;
|
|
|
+
|
|
|
+const MOUSE_MASK=ButtonPressMask or ButtonReleaseMask or PointerMotionMask or ButtonMotionMask;
|
|
|
+ KEY_MASK=KeyPressMask or KeyReleaseMask or KeymapStateMask;
|
|
|
+ X_MASK=KEY_MASK or MOUSE_MASK or VisibilityChangeMask or StructureNotifymask or ExposureMask;
|
|
|
+
|
|
|
+{$ifdef ogles}
|
|
|
+ Attr:array[0..6] of EGLint=(EGL_BUFFER_SIZE,16,
|
|
|
+ EGL_DEPTH_SIZE,8,
|
|
|
+ EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
|
|
|
+ EGL_NONE);
|
|
|
+{ Attr:array[0..12] of EGLint=(EGL_BUFFER_SIZE,16,
|
|
|
+ EGL_RED_SIZE,6,
|
|
|
+ EGL_GREEN_SIZE,5,
|
|
|
+ EGL_BLUE_SIZE,6,
|
|
|
+ EGL_DEPTH_SIZE,8,
|
|
|
+ EGL_RENDERABLE_TYPE,EGL_OPENGL_ES2_BIT,
|
|
|
+ EGL_NONE);}
|
|
|
+ CtxAttr:array[0..2] of EGLint=(EGL_CONTEXT_CLIENT_VERSION,2,EGL_NONE);
|
|
|
+{$else}
|
|
|
+ Attr:array[0..8] of TGLint=(GLX_RGBA,
|
|
|
+ GLX_RED_SIZE,1,
|
|
|
+ GLX_GREEN_SIZE,1,
|
|
|
+ GLX_BLUE_SIZE,1,
|
|
|
+ GLX_DOUBLEBUFFER,
|
|
|
+ none);
|
|
|
+{$endif}
|
|
|
+
|
|
|
+ Title:string='GL test';
|
|
|
+
|
|
|
+var dpy:PXDisplay;
|
|
|
+ win,root:TWindow;
|
|
|
+ screennum,ScreenWidth,ScreenHeight:integer;
|
|
|
+ screen:PScreen;
|
|
|
+ visual:PVisual;
|
|
|
+ Event:TXEvent;
|
|
|
+{$ifdef ogles}
|
|
|
+ swa:TXSetWindowAttributes;
|
|
|
+ ecfg:EGLConfig;
|
|
|
+ num_config:EGLint;
|
|
|
+ esfc:EGLSurface;
|
|
|
+ ectxt:EGLContext;
|
|
|
+ edpy:EGLDisplay;
|
|
|
+ mouse_accel_numerator,mouse_accel_denominator,mouse_threshold:integer;
|
|
|
+{$else}
|
|
|
+ WinAttr:TXSetWindowAttributes;
|
|
|
+ GLXCont:GLXContext;
|
|
|
+ WindowTitleProperty:TXTextProperty;
|
|
|
+ visualinfo:PXVisualInfo;
|
|
|
+ ErrorBase,EventBase:integer;
|
|
|
+{$endif}
|
|
|
+ WM_DELETE_WINDOW:TAtom;
|
|
|
+
|
|
|
+procedure DisableComposition;
|
|
|
+{$ifdef ogles}
|
|
|
+const one:integer=1;
|
|
|
+{$endif}
|
|
|
+var xclient:TXClientMessageEvent;
|
|
|
+ wm_state,fullscreen{$ifdef ogles},non_composited{$endif}:TAtom;
|
|
|
+begin
|
|
|
+ wm_state:=XInternAtom(dpy,'_NET_WM_STATE',false);
|
|
|
+ fullscreen:=XInternAtom(dpy,'_NET_WN_STATE_FULLSCREEN',false);
|
|
|
+ XChangeProperty(dpy,win,wm_state,XA_ATOM,32,PropModeReplace,@fullscreen,1);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+{$ifdef ogles}
|
|
|
+ non_composited:=XInternAtom(dpy,'_HILDON_NON_COMPOSITED_WINDOW',false);
|
|
|
+ XChangeProperty(dpy,win,non_composited,XA_INTEGER,32,PropModeReplace,@one,1);
|
|
|
+ XFlush(dpy);
|
|
|
+{$endif}
|
|
|
+
|
|
|
+ xclient._type:=ClientMessage;
|
|
|
+ xclient.window:=win;
|
|
|
+ xclient.message_type:=XInternAtom(dpy,'_NET_WM_STATE',false);
|
|
|
+ xclient.format:=32;
|
|
|
+ xclient.data.l[0]:=1;
|
|
|
+ xclient.data.l[1]:=XInternAtom(dpy,'_NET_WM_STATE_FULLSCREEN',false);
|
|
|
+ xclient.data.l[2]:=0;
|
|
|
+ xclient.data.l[3]:=0;
|
|
|
+ xclient.data.l[4]:=0;
|
|
|
+ XSendEvent(dpy,root,false,SubstructureRedirectMask or SubstructureNotifyMask,PXEvent(pointer(@xclient)));
|
|
|
+ XFlush(dpy);
|
|
|
+end;
|
|
|
+
|
|
|
+procedure SetEmptyMouseCursor;
|
|
|
+const bm_no_data:array[0..7] of byte=(0,0,0,0,0,0,0,0);
|
|
|
+var bm_no:TPixmap;
|
|
|
+ cmap:TColormap;
|
|
|
+ no_ptr:TCursor;
|
|
|
+ black,dummy:TXColor;
|
|
|
+begin
|
|
|
+ cmap:=DefaultColormap(Dpy,screennum);
|
|
|
+ XAllocNamedColor(Dpy,cmap,'black',@black,@dummy);
|
|
|
+ bm_no:=XCreateBitmapFromData(Dpy,Win,POINTER(@bm_no_data),8,8);
|
|
|
+ no_ptr:=XCreatePixmapCursor(Dpy,bm_no,bm_no,@black,@black,0,0);
|
|
|
+ XDefineCursor(Dpy,Win,no_ptr);
|
|
|
+ XFreeCursor(Dpy,no_ptr);
|
|
|
+ if bm_no<>None then begin
|
|
|
+ XFreePixmap(Dpy,bm_no);
|
|
|
+ end;
|
|
|
+ XFreeColors(Dpy,cmap,@black.pixel,1,0);
|
|
|
+end;
|
|
|
+
|
|
|
+begin
|
|
|
+ CurrentTime:=0;
|
|
|
+
|
|
|
+ dpy:=XOpenDisplay(nil);
|
|
|
+ if not assigned(dpy) then begin
|
|
|
+ writeln('Error: Cannot connect to X server');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ root:=DefaultRootWindow(dpy);
|
|
|
+
|
|
|
+ screen:=XDefaultScreenOfDisplay(dpy);
|
|
|
+ if not assigned(screen) then begin
|
|
|
+ writeln('Error: Cannot get default screen');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ ScreenWidth:=screen^.Width;
|
|
|
+ ScreenHeight:=screen^.Height;
|
|
|
+
|
|
|
+ screennum:=XDefaultScreen(dpy);
|
|
|
+
|
|
|
+ visual:=XDefaultVisualOfScreen(screen);
|
|
|
+
|
|
|
+ CanvasWidth:=ScreenWidth;
|
|
|
+ CanvasHeight:=ScreenHeight;
|
|
|
+{$ifdef ogles}
|
|
|
+
|
|
|
+ swa.event_mask:=X_MASK;
|
|
|
+
|
|
|
+ win:=XCreateWindow(dpy,root,0,0,ScreenWidth,ScreenHeight,0,CopyFromParent,InputOutput,Visual,CWEventMask,@swa);
|
|
|
+
|
|
|
+ WM_DELETE_WINDOW:=XInternAtom(dpy,'WM_DELETE_WINDOW',FALSE);
|
|
|
+ XSetWMProtocols(dpy,win,@WM_DELETE_WINDOW,1);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ DisableComposition;
|
|
|
+
|
|
|
+ XMapWindow(dpy,win);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ DisableComposition;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ XStoreName(dpy,win,pchar(Title));
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XMoveWindow(dpy,win,0,0);
|
|
|
+ XRaiseWindow(dpy,win);
|
|
|
+ //XWarpPointer(dpy,None,win,0,0,0,0,0,0);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ SetEmptyMouseCursor;
|
|
|
+
|
|
|
+ XGrabPointer(dpy,win,true,MOUSE_MASK,GrabModeAsync,GrabModeAsync,win,None,CurrentTime);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XGetPointerControl(dpy,@mouse_accel_numerator,@mouse_accel_denominator,@mouse_threshold);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XChangePointerControl(dpy,1,1,1,1,0);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XGrabKeyboard(dpy,win,false,GrabModeAsync,GrabModeAsync,CurrentTime);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ edpy:=eglGetDisplay(dpy);
|
|
|
+ if edpy=EGL_NO_DISPLAY then begin
|
|
|
+ writeln('Error: Got no EGL display');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ if eglInitialize(edpy,nil,nil)=0 then begin
|
|
|
+ writeln('Error: Unable to initialize EGL');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ num_config:=0;
|
|
|
+ if eglChooseConfig(edpy,@Attr,@ecfg,1,@num_config)=0 then begin
|
|
|
+ writeln('Error: Failed to choose config (',eglGetError,')');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+ if num_config<>1 then begin
|
|
|
+ writeln('Error: Didn''t get exactly config but ',num_config);
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ esfc:=eglCreateWindowSurface(edpy,ecfg,win,nil);
|
|
|
+ if esfc=EGL_NO_SURFACE then begin
|
|
|
+ writeln('Error: Unable to create EGL surface (',eglGetError,')');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ ectxt:=eglCreateContext(edpy,ecfg,EGL_NO_CONTEXT,@CtxAttr);
|
|
|
+ if ectxt=EGL_NO_CONTEXT then begin
|
|
|
+ writeln('Error: Unable to create EGL context (',eglGetError,')');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ eglMakeCurrent(edpy,esfc,esfc,ectxt);
|
|
|
+
|
|
|
+{$else}
|
|
|
+ InitGLX;
|
|
|
+
|
|
|
+ if not glXQueryExtension(dpy,ErrorBase,EventBase) then begin
|
|
|
+ writeln('Error: GLX extension not supported');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ visualinfo:=glXChooseVisual(dpy,screennum,Attr);
|
|
|
+ if not assigned(Visualinfo) THEN BEGIN
|
|
|
+ writeln('Error: Could not find visual info');
|
|
|
+ exit;
|
|
|
+ end;
|
|
|
+
|
|
|
+ WinAttr.colormap:=XCreateColormap(dpy,root,VisualInfo.Visual,AllocNone);
|
|
|
+ WinAttr.border_pixel:=0;
|
|
|
+ WinAttr.background_pixel:=0;
|
|
|
+ WinAttr.event_mask:=X_MASK;
|
|
|
+ WinAttr.override_redirect:=1;
|
|
|
+ WinAttr.backing_store:=NotUseful;
|
|
|
+ WinAttr.save_under:=0;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ XStringListToTextProperty(@Title,1,@WindowTitleProperty);
|
|
|
+ XSetWMName(Dpy,Win,@WindowTitleProperty);
|
|
|
+
|
|
|
+ glXCont:=glXCreateContext(Dpy,VisualInfo,none,true);
|
|
|
+ if not assigned(glXCont) then begin
|
|
|
+ writeln('Error: Could not create an OpenGL rendering context');
|
|
|
+ halt(1);
|
|
|
+ end;
|
|
|
+
|
|
|
+ DisableComposition;
|
|
|
+
|
|
|
+ XMapWindow(Dpy,Win);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ DisableComposition;
|
|
|
+
|
|
|
+ glXMakeCurrent(Dpy,Win,glXCont);
|
|
|
+
|
|
|
+ SetEmptyMouseCursor;
|
|
|
+
|
|
|
+ XMoveWindow(dpy,win,0,0);
|
|
|
+ XRaiseWindow(dpy,win);
|
|
|
+ XWarpPointer(dpy,None,win,0,0,0,0,0,0);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XF86VidmodeSetViewPort(dpy,screennum,0,0);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XGrabPointer(dpy,win,true,MOUSE_MASK,GrabModeAsync,GrabModeAsync,win,None,CurrentTime);
|
|
|
+ XGrabKeyboard(dpy,win,false,GrabModeAsync,GrabModeAsync,CurrentTime);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ XAutoRepeatOn(Dpy);
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ WM_DELETE_WINDOW:=XInternAtom(dpy,'WM_DELETE_WINDOW',FALSE);
|
|
|
+ XSetWMProtocols(dpy,win,@WM_DELETE_WINDOW,1);
|
|
|
+ XFlush(Dpy);
|
|
|
+
|
|
|
+ CanvasWidth:=ScreenWidth;
|
|
|
+ CanvasHeight:=ScreenHeight;
|
|
|
+
|
|
|
+ if assigned(visual) then begin
|
|
|
+ // Den Compiler befriedigen, so dass der kein Warning deswegen ausspuckt :)
|
|
|
+ end;
|
|
|
+{$endif}
|
|
|
+
|
|
|
+ Running:=true;
|
|
|
+ ReturnCode:=0;
|
|
|
+{$ifndef ogles}
|
|
|
+ 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
|
|
|
+ Running:=false;
|
|
|
+ writeln('Error: Cannot load OpenGL 2.0 API');
|
|
|
+ ReturnCode:=1;
|
|
|
+ end;
|
|
|
+{$endif}
|
|
|
+ if Running then begin
|
|
|
+ Init;
|
|
|
+ CurrentTime:=GetTime;
|
|
|
+ end;
|
|
|
+ while Running do begin
|
|
|
+
|
|
|
+ while XPending(Dpy)>0 do begin
|
|
|
+ XNextEvent(Dpy,@Event);
|
|
|
+
|
|
|
+ case Event._type of
|
|
|
+
|
|
|
+ ClientMessage:BEGIN
|
|
|
+ if (Event.xclient.format=32) and (longword(Event.xclient.Data.l[0])=longword(WM_DELETE_WINDOW)) then begin
|
|
|
+ Running:=false;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
+
|
|
|
+ Expose:begin
|
|
|
+ end;
|
|
|
+
|
|
|
+ ConfigureNotify:begin
|
|
|
+ end;
|
|
|
+
|
|
|
+ MotionNotify:begin
|
|
|
+// Running:=false;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ButtonPress:begin
|
|
|
+ Running:=false;
|
|
|
+ end;
|
|
|
+
|
|
|
+ ButtonRelease:begin
|
|
|
+ Running:=false;
|
|
|
+ end;
|
|
|
+
|
|
|
+ KeyMapNotify:begin
|
|
|
+ end;
|
|
|
+
|
|
|
+ KeyPress:begin
|
|
|
+ Running:=false;
|
|
|
+ end;
|
|
|
+
|
|
|
+ KeyRelease:begin
|
|
|
+ Running:=false;
|
|
|
+ end;
|
|
|
+
|
|
|
+ end;
|
|
|
+
|
|
|
+ end;
|
|
|
+
|
|
|
+ CurrentTime:=GetTime;
|
|
|
+ Render;
|
|
|
+
|
|
|
+{$ifdef ogles}
|
|
|
+ eglSwapBuffers(edpy,esfc);
|
|
|
+{$else}
|
|
|
+ glXSwapBuffers(dpy,win);
|
|
|
+{$endif}
|
|
|
+
|
|
|
+ XFlush(dpy);
|
|
|
+
|
|
|
+ end;
|
|
|
+ if ReturnCode=0 then begin
|
|
|
+ Done;
|
|
|
+ end;
|
|
|
+
|
|
|
+{$ifdef ogles}
|
|
|
+ XChangePointerControl(dpy,1,1,mouse_accel_numerator,mouse_accel_denominator,mouse_threshold);
|
|
|
+ XUngrabPointer(dpy,CurrentTime);
|
|
|
+ XUngrabKeyboard(dpy,CurrentTime);
|
|
|
+ eglDestroyContext(edpy,ectxt);
|
|
|
+ eglDestroySurface(edpy,esfc);
|
|
|
+ eglTerminate(edpy);
|
|
|
+{$else}
|
|
|
+ XUngrabPointer(dpy,CurrentTime);
|
|
|
+ XUngrabKeyboard(dpy,CurrentTime);
|
|
|
+ glXDestroyContext(dpy,glxCont);
|
|
|
+{$endif}
|
|
|
+
|
|
|
+ XDestroyWindow(dpy,win);
|
|
|
+ XCloseDisplay(dpy);
|
|
|
+
|
|
|
+ halt(ReturnCode);
|
|
|
+end.
|