Line |
Branch |
Exec |
Source |
1 |
|
|
/* GATE PROJECT LICENSE: |
2 |
|
|
+----------------------------------------------------------------------------+ |
3 |
|
|
| Copyright(c) 2018-2025, Stefan Meislinger | |
4 |
|
|
| All rights reserved. | |
5 |
|
|
| | |
6 |
|
|
| Redistribution and use in source and binary forms, with or without | |
7 |
|
|
| modification, are permitted provided that the following conditions are met:| |
8 |
|
|
| | |
9 |
|
|
| 1. Redistributions of source code must retain the above copyright notice, | |
10 |
|
|
| this list of conditions and the following disclaimer. | |
11 |
|
|
| 2. Redistributions in binary form must reproduce the above copyright | |
12 |
|
|
| notice, this list of conditions and the following disclaimer in the | |
13 |
|
|
| documentation and/or other materials provided with the distribution. | |
14 |
|
|
| | |
15 |
|
|
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"| |
16 |
|
|
| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
17 |
|
|
| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
18 |
|
|
| ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE | |
19 |
|
|
| LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
20 |
|
|
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
21 |
|
|
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
22 |
|
|
| INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
23 |
|
|
| CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
24 |
|
|
| ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | |
25 |
|
|
| THE POSSIBILITY OF SUCH DAMAGE. | |
26 |
|
|
+----------------------------------------------------------------------------+ |
27 |
|
|
*/ |
28 |
|
|
#ifndef GATE_GRAPHICS_PLATFORM_OPENGL_XLIB_IMPL_H_INCLUDED |
29 |
|
|
#define GATE_GRAPHICS_PLATFORM_OPENGL_XLIB_IMPL_H_INCLUDED |
30 |
|
|
|
31 |
|
|
#include "gate/platform/posix/xlib.h" |
32 |
|
|
#include <GL/glx.h> |
33 |
|
|
|
34 |
|
|
typedef struct gate_glx |
35 |
|
|
{ |
36 |
|
|
XVisualInfo* (*glXChooseVisual)(Display* dpy, int screen, int* attribList); |
37 |
|
|
} gate_glx_t; |
38 |
|
|
|
39 |
|
|
static gate_glx_t glx = GATE_INIT_EMPTY; |
40 |
|
|
static gate_bool_t volatile glx_loaded = false; |
41 |
|
|
|
42 |
|
✗ |
static gate_result_t gate_glx_load_functions() |
43 |
|
|
{ |
44 |
|
|
static gate_string_t glx_lib_name = GATE_STRING_INIT_STATIC("libGL.so"); |
45 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
46 |
|
|
static gate_library_t glx_lib = NULL; |
47 |
|
|
|
48 |
|
|
do |
49 |
|
|
{ |
50 |
|
✗ |
if (glx_loaded) |
51 |
|
|
{ |
52 |
|
✗ |
ret = GATE_RESULT_OK; |
53 |
|
✗ |
break; |
54 |
|
|
} |
55 |
|
|
|
56 |
|
✗ |
if (glx_lib == NULL) |
57 |
|
|
{ |
58 |
|
✗ |
ret = gate_library_open(&glx_lib_name, &glx_lib, GATE_LIBRARY_FLAG_DEFAULT); |
59 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
60 |
|
|
} |
61 |
|
|
|
62 |
|
✗ |
GATE_BREAK_IF_FAILED(ret = gate_library_get_function_name(glx_lib, "glXChooseVisual", &glx.glXChooseVisual)); |
63 |
|
|
|
64 |
|
✗ |
glx_loaded = true; |
65 |
|
✗ |
ret = GATE_RESULT_OK; |
66 |
|
|
} while (0); |
67 |
|
✗ |
return ret; |
68 |
|
|
} |
69 |
|
|
|
70 |
|
|
|
71 |
|
|
typedef struct gate_xlib_handle |
72 |
|
|
{ |
73 |
|
|
Display* display; |
74 |
|
|
Window root_win; |
75 |
|
|
Window surface_win; |
76 |
|
|
int cancel_events; |
77 |
|
|
Atom wm_protocols; |
78 |
|
|
Atom wm_delete_window; |
79 |
|
|
|
80 |
|
|
} gate_xlib_handle_t; |
81 |
|
|
|
82 |
|
|
static int default_xlib_visual_attribs_doublebuffer[] = |
83 |
|
|
{ |
84 |
|
|
GLX_RGBA, |
85 |
|
|
GLX_DOUBLEBUFFER, |
86 |
|
|
GLX_RED_SIZE, 4, |
87 |
|
|
GLX_GREEN_SIZE, 4, |
88 |
|
|
GLX_BLUE_SIZE, 4, |
89 |
|
|
GLX_DEPTH_SIZE, 16, |
90 |
|
|
None |
91 |
|
|
}; |
92 |
|
|
static int default_xlib_visual_attribs_singlebuffer[] = |
93 |
|
|
{ |
94 |
|
|
GLX_RGBA, |
95 |
|
|
GLX_RED_SIZE, 4, |
96 |
|
|
GLX_GREEN_SIZE, 4, |
97 |
|
|
GLX_BLUE_SIZE, 4, |
98 |
|
|
GLX_DEPTH_SIZE, 16, |
99 |
|
|
None |
100 |
|
|
}; |
101 |
|
|
|
102 |
|
✗ |
static void gate_xlib_surface_destroy(void* xlib_surface) |
103 |
|
|
{ |
104 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
105 |
|
✗ |
if (xhandle->surface_win) |
106 |
|
|
{ |
107 |
|
✗ |
xlib.XDestroyWindow(xhandle->display, xhandle->surface_win); |
108 |
|
|
} |
109 |
|
✗ |
if (xhandle->display) |
110 |
|
|
{ |
111 |
|
✗ |
xlib.XCloseDisplay(xhandle->display); |
112 |
|
|
|
113 |
|
|
} |
114 |
|
✗ |
gate_mem_dealloc(xhandle); |
115 |
|
✗ |
} |
116 |
|
|
|
117 |
|
✗ |
void* gate_xlib_surface_create(gate_int32_t x, gate_int32_t y, gate_uint32_t width, gate_uint32_t height) |
118 |
|
|
{ |
119 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)gate_mem_alloc(sizeof(gate_xlib_handle_t)); |
120 |
|
✗ |
gate_bool_t completed = false; |
121 |
|
|
int xdefaultscreen; |
122 |
|
|
XVisualInfo visualinfo; |
123 |
|
|
XVisualInfo* vi; |
124 |
|
|
XWindowAttributes windowattrs; |
125 |
|
|
|
126 |
|
|
|
127 |
|
✗ |
if (xhandle == NULL) |
128 |
|
|
{ |
129 |
|
✗ |
return NULL; |
130 |
|
|
} |
131 |
|
|
|
132 |
|
✗ |
xhandle->display = NULL; |
133 |
|
✗ |
xhandle->root_win = 0; |
134 |
|
✗ |
xhandle->surface_win = 0; |
135 |
|
✗ |
xhandle->cancel_events = 0; |
136 |
|
|
|
137 |
|
|
do |
138 |
|
|
{ |
139 |
|
✗ |
xhandle->display = xlib.XOpenDisplay(NULL); |
140 |
|
✗ |
if (xhandle->display == NULL) |
141 |
|
|
{ |
142 |
|
✗ |
xhandle->display = xlib.XOpenDisplay(":0"); |
143 |
|
|
} |
144 |
|
✗ |
if (xhandle->display == NULL) |
145 |
|
|
{ |
146 |
|
✗ |
GATE_DEBUG_TRACE("XOpenDisplay() failed"); |
147 |
|
✗ |
break; |
148 |
|
|
} |
149 |
|
✗ |
xhandle->root_win = xlib.XDefaultRootWindow(xhandle->display); |
150 |
|
✗ |
xdefaultscreen = xlib.XDefaultScreen(xhandle->display); |
151 |
|
|
|
152 |
|
✗ |
gate_mem_clear(&visualinfo, sizeof(visualinfo)); |
153 |
|
|
|
154 |
|
✗ |
if (glx.glXChooseVisual) |
155 |
|
|
{ |
156 |
|
✗ |
vi = glx.glXChooseVisual(xhandle->display, xdefaultscreen, default_xlib_visual_attribs_doublebuffer); |
157 |
|
✗ |
if (vi == NULL) |
158 |
|
|
{ |
159 |
|
✗ |
vi = glx.glXChooseVisual(xhandle->display, xdefaultscreen, default_xlib_visual_attribs_singlebuffer); |
160 |
|
|
} |
161 |
|
✗ |
if (vi == NULL) |
162 |
|
|
{ |
163 |
|
✗ |
GATE_DEBUG_TRACE("glXChooseVisual() failed"); |
164 |
|
✗ |
break; |
165 |
|
|
} |
166 |
|
✗ |
visualinfo = *vi; |
167 |
|
|
} |
168 |
|
|
else |
169 |
|
|
{ |
170 |
|
✗ |
xlib.XMatchVisualInfo(xhandle->display, xdefaultscreen, 16, TrueColor, &visualinfo); |
171 |
|
|
} |
172 |
|
|
|
173 |
|
|
|
174 |
|
|
XSetWindowAttributes swa; |
175 |
|
✗ |
gate_mem_clear(&swa, sizeof(swa)); |
176 |
|
✗ |
swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask; |
177 |
|
✗ |
swa.background_pixel = 0; |
178 |
|
✗ |
swa.border_pixel = 0; |
179 |
|
✗ |
swa.colormap = xlib.XCreateColormap(xhandle->display, xhandle->root_win, visualinfo.visual, AllocNone); |
180 |
|
|
|
181 |
|
✗ |
if ((width == 0) || (height == 0)) |
182 |
|
|
{ |
183 |
|
✗ |
xlib.XGetWindowAttributes(xhandle->display, xhandle->root_win, &windowattrs); |
184 |
|
✗ |
if (width == 0) |
185 |
|
|
{ |
186 |
|
✗ |
width = windowattrs.width; |
187 |
|
|
} |
188 |
|
✗ |
if (height == 0) |
189 |
|
|
{ |
190 |
|
✗ |
height = windowattrs.height; |
191 |
|
|
} |
192 |
|
|
} |
193 |
|
|
|
194 |
|
✗ |
xhandle->surface_win = xlib.XCreateWindow(xhandle->display, xhandle->root_win, |
195 |
|
|
x, y, width, height, 0, |
196 |
|
|
/*CopyFromParent*/ visualinfo.depth, |
197 |
|
|
InputOutput, |
198 |
|
|
/*CopyFromParent*/ visualinfo.visual, |
199 |
|
|
CWEventMask | CWBackPixel | CWBorderPixel | CWColormap, |
200 |
|
|
&swa); |
201 |
|
|
|
202 |
|
✗ |
xhandle->wm_protocols = xlib.XInternAtom(xhandle->display, "WM_PROTOCOLS", False); |
203 |
|
✗ |
xhandle->wm_delete_window = xlib.XInternAtom(xhandle->display, "WM_DELETE_WINDOW", False); |
204 |
|
✗ |
xlib.XSetWMProtocols(xhandle->display, xhandle->surface_win, &xhandle->wm_delete_window, 1); |
205 |
|
|
|
206 |
|
✗ |
xlib.XMapWindow(xhandle->display, xhandle->surface_win); |
207 |
|
✗ |
xlib.XFlush(xhandle->display); |
208 |
|
|
|
209 |
|
|
//xlib.XGetWindowAttributes(xhandle->surface_win |
210 |
|
|
|
211 |
|
✗ |
completed = true; |
212 |
|
|
} while (0); |
213 |
|
|
|
214 |
|
✗ |
if (!completed) |
215 |
|
|
{ |
216 |
|
✗ |
gate_xlib_surface_destroy(xhandle); |
217 |
|
✗ |
return NULL; |
218 |
|
|
} |
219 |
|
✗ |
return xhandle; |
220 |
|
|
} |
221 |
|
|
|
222 |
|
✗ |
static void gate_xlib_surface_resize(void* xlib_surface, gate_uint32_t width, gate_uint32_t height) |
223 |
|
|
{ |
224 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
225 |
|
✗ |
xlib.XResizeWindow(xhandle->display, xhandle->surface_win, width, height); |
226 |
|
|
/* TODO */ |
227 |
|
✗ |
} |
228 |
|
✗ |
static void gate_xlib_surface_get_client_size(void* xlib_surface, gate_uint32_t* ptr_width, gate_uint32_t* ptr_height) |
229 |
|
|
{ |
230 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
231 |
|
✗ |
XWindowAttributes windowattrs = GATE_INIT_EMPTY; |
232 |
|
✗ |
xlib.XGetWindowAttributes(xhandle->display, xhandle->surface_win, &windowattrs); |
233 |
|
✗ |
if (ptr_width) |
234 |
|
|
{ |
235 |
|
✗ |
*ptr_width = windowattrs.width; |
236 |
|
|
} |
237 |
|
✗ |
if (ptr_height) |
238 |
|
|
{ |
239 |
|
✗ |
*ptr_height = windowattrs.height; |
240 |
|
|
} |
241 |
|
✗ |
} |
242 |
|
|
|
243 |
|
✗ |
static void* gate_xlib_surface_get_handle(void* xlib_surface) |
244 |
|
|
{ |
245 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
246 |
|
✗ |
return (void*)xhandle->surface_win; |
247 |
|
|
} |
248 |
|
|
|
249 |
|
✗ |
static void gate_xlib_surface_handle_events(void* xlib_surface, gate_gl_surface_events_t* callbacks, void* user_param) |
250 |
|
|
{ |
251 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
252 |
|
✗ |
gate_gl_surface_t* ptr_gl_surface = NULL; |
253 |
|
|
|
254 |
|
✗ |
long mask = FocusChangeMask | PropertyChangeMask |
255 |
|
|
| KeyPressMask | KeyReleaseMask | KeymapStateMask |
256 |
|
|
| ButtonPressMask | ButtonReleaseMask | PointerMotionMask | PointerMotionHintMask |
257 |
|
|
| ExposureMask | VisibilityChangeMask |
258 |
|
|
| StructureNotifyMask | SubstructureNotifyMask |
259 |
|
|
; |
260 |
|
|
|
261 |
|
|
|
262 |
|
|
XEvent xevent; |
263 |
|
|
KeySym keysym; |
264 |
|
|
gate_input_keycode_t keycode; |
265 |
|
|
gate_input_keystates_t keystates; |
266 |
|
|
|
267 |
|
✗ |
xlib.XSelectInput(xhandle->display, xhandle->surface_win, mask); |
268 |
|
|
for (;;) |
269 |
|
|
{ |
270 |
|
✗ |
if (xhandle->cancel_events) |
271 |
|
|
{ |
272 |
|
✗ |
xhandle->cancel_events = 0; |
273 |
|
✗ |
break; |
274 |
|
|
} |
275 |
|
✗ |
if (callbacks) |
276 |
|
|
{ |
277 |
|
✗ |
if (callbacks->on_render) |
278 |
|
|
{ |
279 |
|
✗ |
callbacks->on_render(ptr_gl_surface, user_param); |
280 |
|
|
} |
281 |
|
|
} |
282 |
|
|
/* |
283 |
|
|
if(!xlib.XCheckMaskEvent(xhandle->display, mask, &xevent)) |
284 |
|
|
{ |
285 |
|
|
gate_thread_sleep(10); |
286 |
|
|
} |
287 |
|
|
else |
288 |
|
|
{ |
289 |
|
|
*/ |
290 |
|
✗ |
if (xlib.XPending(xhandle->display) <= 0) |
291 |
|
|
{ |
292 |
|
✗ |
gate_thread_sleep(10); |
293 |
|
|
} |
294 |
|
|
else |
295 |
|
|
{ |
296 |
|
✗ |
gate_mem_clear(&xevent, sizeof(xevent)); |
297 |
|
✗ |
xlib.XNextEvent(xhandle->display, &xevent); |
298 |
|
|
|
299 |
|
✗ |
if (callbacks && (xevent.xany.window == xhandle->surface_win)) |
300 |
|
|
{ |
301 |
|
✗ |
switch (xevent.type) |
302 |
|
|
{ |
303 |
|
✗ |
case ConfigureNotify: |
304 |
|
|
{ |
305 |
|
✗ |
if (callbacks->on_resize) |
306 |
|
|
{ |
307 |
|
✗ |
callbacks->on_resize(ptr_gl_surface, |
308 |
|
✗ |
xevent.xconfigure.width, |
309 |
|
✗ |
xevent.xconfigure.height, |
310 |
|
|
user_param); |
311 |
|
|
} |
312 |
|
✗ |
break; |
313 |
|
|
} |
314 |
|
✗ |
case KeyPress: |
315 |
|
|
{ |
316 |
|
✗ |
if (callbacks->on_key_down) |
317 |
|
|
{ |
318 |
|
✗ |
keysym = xlib.XLookupKeysym(&xevent.xkey, 0); |
319 |
|
✗ |
keycode = 0; |
320 |
|
✗ |
keystates = 0; |
321 |
|
✗ |
if (xevent.xkey.state & ShiftMask) |
322 |
|
|
{ |
323 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_SHIFT; |
324 |
|
|
} |
325 |
|
✗ |
if (xevent.xkey.state & LockMask) |
326 |
|
|
{ |
327 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_MENU; |
328 |
|
|
} |
329 |
|
✗ |
if (xevent.xkey.state & ControlMask) |
330 |
|
|
{ |
331 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_CTRL; |
332 |
|
|
} |
333 |
|
✗ |
gate_xlib_convert_keysym(keysym, &keycode); |
334 |
|
✗ |
callbacks->on_key_down(ptr_gl_surface, keycode, keystates, user_param); |
335 |
|
|
} |
336 |
|
✗ |
break; |
337 |
|
|
} |
338 |
|
✗ |
case KeyRelease: |
339 |
|
|
{ |
340 |
|
✗ |
if (callbacks->on_key_up) |
341 |
|
|
{ |
342 |
|
✗ |
keysym = xlib.XLookupKeysym(&xevent.xkey, 0); |
343 |
|
✗ |
keycode = 0; |
344 |
|
✗ |
keystates = 0; |
345 |
|
✗ |
if (xevent.xkey.state & ShiftMask) |
346 |
|
|
{ |
347 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_SHIFT; |
348 |
|
|
} |
349 |
|
✗ |
if (xevent.xkey.state & LockMask) |
350 |
|
|
{ |
351 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_MENU; |
352 |
|
|
} |
353 |
|
✗ |
if (xevent.xkey.state & ControlMask) |
354 |
|
|
{ |
355 |
|
✗ |
keystates |= GATE_KBD_KEYSTATE_CTRL; |
356 |
|
|
} |
357 |
|
✗ |
gate_xlib_convert_keysym(keysym, &keycode); |
358 |
|
✗ |
callbacks->on_key_up(ptr_gl_surface, keycode, keystates, user_param); |
359 |
|
|
} |
360 |
|
✗ |
break; |
361 |
|
|
} |
362 |
|
✗ |
case ButtonPress: |
363 |
|
|
{ |
364 |
|
✗ |
if (callbacks->on_pointer_down) |
365 |
|
|
{ |
366 |
|
✗ |
callbacks->on_pointer_down(ptr_gl_surface, xevent.xbutton.button, |
367 |
|
✗ |
xevent.xbutton.x, xevent.xbutton.y, user_param); |
368 |
|
|
} |
369 |
|
✗ |
break; |
370 |
|
|
} |
371 |
|
✗ |
case ButtonRelease: |
372 |
|
|
{ |
373 |
|
✗ |
if (callbacks->on_pointer_up) |
374 |
|
|
{ |
375 |
|
✗ |
callbacks->on_pointer_up(ptr_gl_surface, xevent.xbutton.button, |
376 |
|
✗ |
xevent.xbutton.x, xevent.xbutton.y, user_param); |
377 |
|
|
} |
378 |
|
✗ |
break; |
379 |
|
|
} |
380 |
|
✗ |
case ClientMessage: |
381 |
|
|
{ |
382 |
|
✗ |
if (xevent.xclient.message_type == xhandle->wm_protocols) |
383 |
|
|
{ |
384 |
|
✗ |
if (xevent.xclient.data.l[0] == (long)xhandle->wm_delete_window) |
385 |
|
|
{ |
386 |
|
✗ |
if (callbacks->on_exit) |
387 |
|
|
{ |
388 |
|
✗ |
callbacks->on_exit(ptr_gl_surface, user_param); |
389 |
|
|
} |
390 |
|
✗ |
break; |
391 |
|
|
} |
392 |
|
|
} |
393 |
|
✗ |
break; |
394 |
|
|
} |
395 |
|
✗ |
default: |
396 |
|
|
{ |
397 |
|
✗ |
break; |
398 |
|
|
} |
399 |
|
|
} |
400 |
|
✗ |
} |
401 |
|
|
} |
402 |
|
|
} |
403 |
|
✗ |
} |
404 |
|
✗ |
static void gate_xlib_surface_cancel_events(void* xlib_surface) |
405 |
|
|
{ |
406 |
|
✗ |
gate_xlib_handle_t* xhandle = (gate_xlib_handle_t*)xlib_surface; |
407 |
|
✗ |
if (xhandle) |
408 |
|
|
{ |
409 |
|
✗ |
xhandle->cancel_events = 1; |
410 |
|
|
} |
411 |
|
✗ |
} |
412 |
|
|
|
413 |
|
|
|
414 |
|
|
|
415 |
|
|
|
416 |
|
|
|
417 |
|
|
|
418 |
|
|
|
419 |
|
|
|
420 |
|
|
|
421 |
|
|
|
422 |
|
|
|
423 |
|
✗ |
gate_result_t gate_gl_surface_init(gate_gl_surface_t* surface) |
424 |
|
|
{ |
425 |
|
|
gate_result_t ret; |
426 |
|
|
do |
427 |
|
|
{ |
428 |
|
✗ |
ret = gate_xlib_load_functions(); |
429 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
430 |
|
✗ |
ret = gate_egl_load_functions(); |
431 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
432 |
|
✗ |
ret = gate_gl_api_load_functions(); |
433 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
434 |
|
✗ |
ret = gate_glx_load_functions(); |
435 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
436 |
|
✗ |
gate_mem_clear(surface, sizeof(gate_gl_surface_t)); |
437 |
|
|
} while (0); |
438 |
|
|
|
439 |
|
✗ |
return ret; |
440 |
|
|
} |
441 |
|
✗ |
gate_result_t gate_gl_surface_uninit(gate_gl_surface_t* surface) |
442 |
|
|
{ |
443 |
|
✗ |
gate_mem_clear(surface, sizeof(gate_gl_surface_t)); |
444 |
|
✗ |
return GATE_RESULT_OK; |
445 |
|
|
} |
446 |
|
|
|
447 |
|
|
|
448 |
|
|
|
449 |
|
|
static EGLint gate_egl_attribs_pbuffer[] = |
450 |
|
|
{ |
451 |
|
|
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, |
452 |
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, |
453 |
|
|
//EGL_RED_SIZE, (EGLint)5, |
454 |
|
|
//EGL_GREEN_SIZE, (EGLint)6, |
455 |
|
|
//EGL_BLUE_SIZE, (EGLint)5, |
456 |
|
|
//EGL_ALPHA_SIZE, (EGLint)0, |
457 |
|
|
EGL_DEPTH_SIZE, (EGLint)16, |
458 |
|
|
//EGL_STENCIL_SIZE, (EGLint)0, |
459 |
|
|
EGL_NONE |
460 |
|
|
}; |
461 |
|
|
|
462 |
|
|
static EGLint gate_egl_attribs_window[] = |
463 |
|
|
{ |
464 |
|
|
EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
465 |
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT, |
466 |
|
|
EGL_RED_SIZE, (EGLint)5, |
467 |
|
|
EGL_GREEN_SIZE, (EGLint)5, |
468 |
|
|
EGL_BLUE_SIZE, (EGLint)5, |
469 |
|
|
EGL_ALPHA_SIZE, (EGLint)0, |
470 |
|
|
EGL_DEPTH_SIZE, (EGLint)16, |
471 |
|
|
//EGL_STENCIL_SIZE, (EGLint)0, |
472 |
|
|
EGL_NONE |
473 |
|
|
}; |
474 |
|
|
|
475 |
|
✗ |
static gate_result_t gate_gl_surface_egl_prepare(EGLint const* egl_attrib_list, EGLDisplay* ptr_egl_display, |
476 |
|
|
EGLContext* ptr_egl_context, EGLConfig* ptr_egl_config) |
477 |
|
|
{ |
478 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
479 |
|
✗ |
EGLDisplay egl_display = EGL_NO_DISPLAY; |
480 |
|
|
EGLint egl_version_major, egl_version_minor; |
481 |
|
✗ |
int egl_configs = 0; |
482 |
|
✗ |
EGLConfig all_configs[64] = GATE_INIT_EMPTY; |
483 |
|
✗ |
EGLint all_configs_count = sizeof(all_configs) / sizeof(all_configs[0]); |
484 |
|
✗ |
EGLConfig egl_current_config[64] = GATE_INIT_EMPTY; |
485 |
|
|
EGLint ndx; |
486 |
|
✗ |
EGLint egl_current_configs_count = sizeof(egl_current_config) / sizeof(egl_current_config[0]); |
487 |
|
✗ |
EGLContext egl_context = EGL_NO_CONTEXT; |
488 |
|
✗ |
EGLConfig* ptr_egl_current_config = NULL; |
489 |
|
|
|
490 |
|
|
do |
491 |
|
|
{ |
492 |
|
✗ |
egl_display = egl.GetDisplay(EGL_DEFAULT_DISPLAY); |
493 |
|
✗ |
if (egl_display == EGL_NO_DISPLAY) |
494 |
|
|
{ |
495 |
|
✗ |
GATE_DEBUG_TRACE("eglGetDisplay() failed"); |
496 |
|
✗ |
ret = GATE_RESULT_FAILED; |
497 |
|
✗ |
break; |
498 |
|
|
} |
499 |
|
✗ |
if (EGL_FALSE == egl.Initialize(egl_display, &egl_version_major, &egl_version_minor)) |
500 |
|
|
{ |
501 |
|
✗ |
GATE_DEBUG_TRACE("eglInitialize() failed"); |
502 |
|
✗ |
ret = GATE_RESULT_FAILED; |
503 |
|
✗ |
break; |
504 |
|
|
} |
505 |
|
✗ |
if (EGL_FALSE == egl.GetConfigs(egl_display, all_configs, all_configs_count, &egl_configs)) |
506 |
|
|
{ |
507 |
|
✗ |
GATE_DEBUG_TRACE("eglGetConfigs() failed"); |
508 |
|
✗ |
ret = GATE_RESULT_FAILED; |
509 |
|
✗ |
break; |
510 |
|
|
} |
511 |
|
|
|
512 |
|
✗ |
if (EGL_FALSE == egl.ChooseConfig(egl_display, egl_attrib_list, |
513 |
|
|
egl_current_config, egl_current_configs_count, |
514 |
|
|
&egl_current_configs_count)) |
515 |
|
|
{ |
516 |
|
✗ |
GATE_DEBUG_TRACE("eglChooseConfig() failed"); |
517 |
|
✗ |
ret = GATE_RESULT_FAILED; |
518 |
|
✗ |
break; |
519 |
|
|
} |
520 |
|
|
|
521 |
|
✗ |
if (egl_current_configs_count == 0) |
522 |
|
|
{ |
523 |
|
✗ |
GATE_DEBUG_TRACE("eglChooseConfig() failed"); |
524 |
|
✗ |
ret = GATE_RESULT_FAILED; |
525 |
|
✗ |
break; |
526 |
|
|
} |
527 |
|
|
|
528 |
|
✗ |
for (ndx = 0; ndx < egl_current_configs_count; ++ndx) |
529 |
|
|
{ |
530 |
|
✗ |
egl_context = egl.CreateContext(egl_display, egl_current_config[ndx], EGL_NO_CONTEXT, NULL); |
531 |
|
✗ |
if (egl_context != EGL_NO_CONTEXT) |
532 |
|
|
{ |
533 |
|
✗ |
ptr_egl_current_config = &egl_current_config[ndx]; |
534 |
|
✗ |
break; |
535 |
|
|
} |
536 |
|
|
} |
537 |
|
|
|
538 |
|
✗ |
if (egl_context == EGL_NO_CONTEXT) |
539 |
|
|
{ |
540 |
|
✗ |
EGLint egl_error = egl.GetError(); |
541 |
|
✗ |
GATE_DEBUG_TRACE("eglCreateContext() failed"); |
542 |
|
✗ |
GATE_DEBUG_TRACE_VALUE(egl_error); |
543 |
|
✗ |
ret = GATE_RESULT_OUTOFRESOURCES; |
544 |
|
✗ |
break; |
545 |
|
|
} |
546 |
|
|
|
547 |
|
✗ |
*ptr_egl_display = egl_display; |
548 |
|
✗ |
*ptr_egl_context = egl_context; |
549 |
|
✗ |
gate_mem_copy(ptr_egl_config, ptr_egl_current_config, sizeof(EGLConfig)); |
550 |
|
✗ |
egl_display = EGL_NO_DISPLAY; |
551 |
|
✗ |
egl_context = EGL_NO_DISPLAY; |
552 |
|
✗ |
ret = GATE_RESULT_OK; |
553 |
|
|
} while (0); |
554 |
|
|
|
555 |
|
✗ |
if (egl_context != EGL_NO_CONTEXT) |
556 |
|
|
{ |
557 |
|
✗ |
egl.DestroyContext(egl_display, egl_context); |
558 |
|
|
} |
559 |
|
|
|
560 |
|
✗ |
if (egl_display != EGL_NO_DISPLAY) |
561 |
|
|
{ |
562 |
|
✗ |
egl.Terminate(egl_display); |
563 |
|
|
} |
564 |
|
|
|
565 |
|
✗ |
return ret; |
566 |
|
|
} |
567 |
|
|
|
568 |
|
|
|
569 |
|
✗ |
gate_result_t gate_gl_surface_open(gate_gl_surface_t* surface, gate_gl_surface_type_t type, |
570 |
|
|
gate_uint32_t width, gate_uint32_t height, gate_enumint_t flags) |
571 |
|
|
{ |
572 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
573 |
|
✗ |
EGLDisplay egl_display = EGL_NO_DISPLAY; |
574 |
|
✗ |
EGLContext egl_context = EGL_NO_CONTEXT; |
575 |
|
✗ |
EGLSurface egl_surface = EGL_NO_SURFACE; |
576 |
|
✗ |
void* xlib_surface = NULL; |
577 |
|
|
NativeWindowType egl_native_window; |
578 |
|
|
EGLConfig egl_config; |
579 |
|
|
|
580 |
|
✗ |
EGLint gate_egl_pbuffer_surface_attribs[] = |
581 |
|
|
{ |
582 |
|
✗ |
EGL_WIDTH, (EGLint)width, |
583 |
|
✗ |
EGL_HEIGHT, (EGLint)height, |
584 |
|
|
//EGL_COLORSPACE, (EGLint)GL_RGBA, |
585 |
|
|
//EGL_TEXTURE_FORMAT, (EGLint)EGL_TEXTURE_RGB, |
586 |
|
|
//EGL_TEXTURE_TARGET, (EGLint)EGL_TEXTURE_2D, |
587 |
|
|
EGL_LARGEST_PBUFFER, (EGLint)EGL_TRUE, |
588 |
|
|
EGL_NONE |
589 |
|
|
}; |
590 |
|
|
|
591 |
|
|
do |
592 |
|
|
{ |
593 |
|
✗ |
switch (type) |
594 |
|
|
{ |
595 |
|
✗ |
case gate_gl_surface_type_external: |
596 |
|
|
{ |
597 |
|
✗ |
break; |
598 |
|
|
} |
599 |
|
✗ |
case gate_gl_surface_type_screen: |
600 |
|
|
{ |
601 |
|
✗ |
xlib_surface = gate_xlib_surface_create(0, 0, width, height); |
602 |
|
✗ |
if (xlib_surface == NULL) |
603 |
|
|
{ |
604 |
|
✗ |
GATE_DEBUG_TRACE("gate_xlib_surface_create() failed"); |
605 |
|
✗ |
ret = GATE_RESULT_OUTOFRESOURCES; |
606 |
|
✗ |
break; |
607 |
|
|
} |
608 |
|
|
|
609 |
|
✗ |
ret = gate_gl_surface_egl_prepare(gate_egl_attribs_window, &egl_display, &egl_context, &egl_config); |
610 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
611 |
|
|
|
612 |
|
|
|
613 |
|
✗ |
egl_native_window = (NativeWindowType)gate_xlib_surface_get_handle(xlib_surface); |
614 |
|
|
|
615 |
|
✗ |
egl_surface = egl.CreateWindowSurface(egl_display, egl_config, egl_native_window, NULL); |
616 |
|
✗ |
if (egl_surface == EGL_NO_SURFACE) |
617 |
|
|
{ |
618 |
|
✗ |
GATE_DEBUG_TRACE("eglCreateWindowSurface() failed"); |
619 |
|
✗ |
ret = GATE_RESULT_OUTOFRESOURCES; |
620 |
|
✗ |
break; |
621 |
|
|
} |
622 |
|
|
|
623 |
|
✗ |
gate_xlib_surface_get_client_size(xlib_surface, &width, &height); |
624 |
|
|
|
625 |
|
✗ |
gate_gl_api.glViewport(0, 0, width, height); |
626 |
|
|
|
627 |
|
✗ |
ret = GATE_RESULT_OK; |
628 |
|
✗ |
break; |
629 |
|
|
} |
630 |
|
✗ |
case gate_gl_surface_type_image: |
631 |
|
|
{ |
632 |
|
✗ |
ret = gate_gl_surface_egl_prepare(gate_egl_attribs_pbuffer, &egl_display, &egl_context, &egl_config); |
633 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
634 |
|
|
|
635 |
|
✗ |
egl_surface = egl.CreatePbufferSurface(egl_display, egl_config, gate_egl_pbuffer_surface_attribs); |
636 |
|
✗ |
if (egl_surface == EGL_NO_SURFACE) |
637 |
|
|
{ |
638 |
|
✗ |
GATE_DEBUG_TRACE("eglCreateWindowSurface() failed"); |
639 |
|
✗ |
ret = GATE_RESULT_OUTOFRESOURCES; |
640 |
|
✗ |
break; |
641 |
|
|
} |
642 |
|
|
|
643 |
|
✗ |
ret = GATE_RESULT_OK; |
644 |
|
✗ |
break; |
645 |
|
|
} |
646 |
|
✗ |
default: |
647 |
|
|
{ |
648 |
|
✗ |
return GATE_RESULT_NOTSUPPORTED; |
649 |
|
|
} |
650 |
|
|
} |
651 |
|
|
|
652 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
653 |
|
|
|
654 |
|
✗ |
if (EGL_FALSE == egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_context)) |
655 |
|
|
{ |
656 |
|
✗ |
GATE_DEBUG_TRACE("eglMakeCurrent() failed"); |
657 |
|
✗ |
ret = GATE_RESULT_INVALIDSTATE; |
658 |
|
✗ |
break; |
659 |
|
|
} |
660 |
|
|
|
661 |
|
|
|
662 |
|
✗ |
surface->surface_type = type; |
663 |
|
✗ |
surface->width = width; |
664 |
|
✗ |
surface->height = height; |
665 |
|
✗ |
surface->native_surface = (void*)egl_surface; |
666 |
|
✗ |
surface->native_context = (void*)egl_context; |
667 |
|
✗ |
surface->special_resources[0] = (void*)xlib_surface; /* gate_xlib_handle */ |
668 |
|
✗ |
surface->special_resources[1] = (void*)egl_display; |
669 |
|
✗ |
surface->event_handler = NULL; |
670 |
|
✗ |
surface->event_handler_param = NULL; |
671 |
|
|
|
672 |
|
✗ |
egl_surface = EGL_NO_SURFACE; |
673 |
|
✗ |
egl_context = EGL_NO_CONTEXT; |
674 |
|
✗ |
egl_display = EGL_NO_DISPLAY; |
675 |
|
✗ |
xlib_surface = NULL; |
676 |
|
|
|
677 |
|
|
} while (0); |
678 |
|
|
|
679 |
|
✗ |
if (egl_surface != EGL_NO_SURFACE) |
680 |
|
|
{ |
681 |
|
✗ |
egl.DestroySurface(egl_display, egl_surface); |
682 |
|
|
} |
683 |
|
|
|
684 |
|
✗ |
if (xlib_surface != NULL) |
685 |
|
|
{ |
686 |
|
✗ |
gate_xlib_surface_destroy(xlib_surface); |
687 |
|
|
} |
688 |
|
|
|
689 |
|
✗ |
if (egl_context != EGL_NO_CONTEXT) |
690 |
|
|
{ |
691 |
|
✗ |
egl.DestroyContext(egl_display, egl_context); |
692 |
|
|
} |
693 |
|
|
|
694 |
|
✗ |
if (egl_display != EGL_NO_DISPLAY) |
695 |
|
|
{ |
696 |
|
✗ |
egl.Terminate(egl_display); |
697 |
|
|
} |
698 |
|
|
|
699 |
|
✗ |
return ret; |
700 |
|
|
} |
701 |
|
✗ |
gate_result_t gate_gl_surface_close(gate_gl_surface_t* surface) |
702 |
|
|
{ |
703 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
704 |
|
✗ |
EGLDisplay egl_display = EGL_NO_DISPLAY; |
705 |
|
✗ |
EGLSurface egl_surface = EGL_NO_SURFACE; |
706 |
|
✗ |
EGLContext egl_context = EGL_NO_CONTEXT; |
707 |
|
✗ |
gate_xlib_handle_t* xlib_handle = NULL; |
708 |
|
|
|
709 |
|
|
do |
710 |
|
|
{ |
711 |
|
✗ |
if (surface->surface_type == gate_gl_surface_type_external) |
712 |
|
|
{ |
713 |
|
✗ |
gate_mem_clear(surface, sizeof(gate_gl_surface_t)); |
714 |
|
✗ |
ret = GATE_RESULT_OK; |
715 |
|
✗ |
break; |
716 |
|
|
} |
717 |
|
|
|
718 |
|
✗ |
egl_surface = (EGLSurface)surface->native_surface; |
719 |
|
✗ |
egl_context = (EGLContext)surface->native_context; |
720 |
|
✗ |
xlib_handle = (gate_xlib_handle_t*)surface->special_resources[0]; |
721 |
|
✗ |
egl_display = (EGLDisplay)surface->special_resources[1]; |
722 |
|
|
|
723 |
|
✗ |
egl.MakeCurrent(egl_display, NULL, NULL, EGL_NO_CONTEXT); |
724 |
|
✗ |
egl.DestroySurface(egl_display, egl_surface); |
725 |
|
✗ |
egl.DestroyContext(egl_display, egl_context); |
726 |
|
|
|
727 |
|
✗ |
if (xlib_handle) |
728 |
|
|
{ |
729 |
|
✗ |
gate_xlib_surface_destroy(xlib_handle); |
730 |
|
|
} |
731 |
|
|
|
732 |
|
✗ |
gate_mem_clear(surface, sizeof(gate_gl_surface_t)); |
733 |
|
✗ |
ret = GATE_RESULT_OK; |
734 |
|
|
} while (0); |
735 |
|
|
|
736 |
|
✗ |
return ret; |
737 |
|
|
} |
738 |
|
|
|
739 |
|
✗ |
gate_result_t gate_gl_surface_resize(gate_gl_surface_t* surface, gate_uint32_t width, gate_uint32_t height) |
740 |
|
|
{ |
741 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
742 |
|
✗ |
EGLDisplay egl_display = EGL_NO_DISPLAY; |
743 |
|
✗ |
EGLSurface egl_surface = EGL_NO_SURFACE; |
744 |
|
✗ |
EGLContext egl_context = EGL_NO_CONTEXT; |
745 |
|
✗ |
gate_xlib_handle_t* xlib_surface = NULL; |
746 |
|
✗ |
gate_gl_surface_t temp_surface = GATE_INIT_EMPTY; |
747 |
|
|
NativeWindowType native_window; |
748 |
|
|
EGLConfig egl_config; |
749 |
|
|
|
750 |
|
|
do |
751 |
|
|
{ |
752 |
|
✗ |
egl_surface = (EGLSurface)surface->native_surface; |
753 |
|
✗ |
egl_context = (EGLContext)surface->native_context; |
754 |
|
✗ |
xlib_surface = (gate_xlib_handle_t*)surface->special_resources[0]; |
755 |
|
✗ |
egl_display = (EGLDisplay)surface->special_resources[1]; |
756 |
|
|
|
757 |
|
✗ |
switch (surface->surface_type) |
758 |
|
|
{ |
759 |
|
✗ |
case gate_gl_surface_type_external: |
760 |
|
|
{ |
761 |
|
✗ |
surface->width = width; |
762 |
|
✗ |
surface->height = height; |
763 |
|
✗ |
ret = GATE_RESULT_OK; |
764 |
|
✗ |
break; |
765 |
|
|
} |
766 |
|
✗ |
case gate_gl_surface_type_image: |
767 |
|
|
{ |
768 |
|
✗ |
if ((surface->width != width) || (surface->height != height)) |
769 |
|
|
{ |
770 |
|
✗ |
ret = gate_gl_surface_open(&temp_surface, gate_gl_surface_type_image, width, height, 0); |
771 |
|
✗ |
GATE_BREAK_IF_FAILED(ret); |
772 |
|
✗ |
gate_gl_surface_close(surface); |
773 |
|
✗ |
gate_mem_copy(surface, &temp_surface, sizeof(temp_surface)); |
774 |
|
|
} |
775 |
|
✗ |
break; |
776 |
|
|
} |
777 |
|
✗ |
case gate_gl_surface_type_screen: |
778 |
|
|
{ |
779 |
|
|
/* |
780 |
|
|
egl.MakeCurrent(egl_display, NULL, NULL, EGL_NO_CONTEXT); |
781 |
|
|
|
782 |
|
|
egl.DestroySurface(egl_display, egl_surface); |
783 |
|
|
egl.DestroyContext(egl_display, egl_context); |
784 |
|
|
egl.Terminate(egl_display); |
785 |
|
|
|
786 |
|
|
ret = gate_gl_surface_egl_prepare(gate_egl_attribs_window, &egl_display, &egl_context, &egl_config); |
787 |
|
|
GATE_BREAK_IF_FAILED(ret); |
788 |
|
|
|
789 |
|
|
native_window = (NativeWindowType)gate_xlib_surface_get_handle(xlib_surface); |
790 |
|
|
|
791 |
|
|
egl_surface = egl.CreateWindowSurface(egl_display, egl_config, native_window, NULL); |
792 |
|
|
if(egl_surface == EGL_NO_SURFACE) |
793 |
|
|
{ |
794 |
|
|
GATE_DEBUG_TRACE("eglCreateWindowSurface() failed"); |
795 |
|
|
ret = GATE_RESULT_OUTOFRESOURCES; |
796 |
|
|
break; |
797 |
|
|
} |
798 |
|
|
*/ |
799 |
|
✗ |
gate_xlib_surface_get_client_size(xlib_surface, &width, &height); |
800 |
|
|
|
801 |
|
|
/* |
802 |
|
|
if(EGL_FALSE == egl.MakeCurrent(egl_display, egl_surface, egl_surface, egl_context)) |
803 |
|
|
{ |
804 |
|
|
GATE_DEBUG_TRACE("eglMakeCurrent() failed"); |
805 |
|
|
ret = GATE_RESULT_INVALIDSTATE; |
806 |
|
|
break; |
807 |
|
|
} |
808 |
|
|
*/ |
809 |
|
✗ |
gate_gl_api.glViewport(0, 0, width, height); |
810 |
|
✗ |
surface->native_surface = egl_surface; |
811 |
|
✗ |
surface->native_context = egl_context; |
812 |
|
✗ |
surface->special_resources[0] = xlib_surface; |
813 |
|
✗ |
surface->special_resources[1] = egl_display; |
814 |
|
✗ |
surface->width = width; |
815 |
|
✗ |
surface->height = height; |
816 |
|
|
|
817 |
|
✗ |
ret = GATE_RESULT_OK; |
818 |
|
✗ |
break; |
819 |
|
|
} |
820 |
|
|
} |
821 |
|
|
|
822 |
|
✗ |
} while (0); |
823 |
|
|
|
824 |
|
✗ |
return ret; |
825 |
|
|
} |
826 |
|
|
|
827 |
|
✗ |
gate_result_t gate_gl_surface_get_size(gate_gl_surface_t* surface, gate_uint32_t* width, gate_uint32_t* height) |
828 |
|
|
{ |
829 |
|
✗ |
if (width != NULL) |
830 |
|
|
{ |
831 |
|
✗ |
*width = surface->width; |
832 |
|
|
} |
833 |
|
✗ |
if (height != NULL) |
834 |
|
|
{ |
835 |
|
✗ |
*height = surface->height; |
836 |
|
|
} |
837 |
|
✗ |
return GATE_RESULT_OK; |
838 |
|
|
} |
839 |
|
|
|
840 |
|
✗ |
gate_result_t gate_gl_surface_print_image(gate_gl_surface_t* surface, gate_rasterimage_t* target_image) |
841 |
|
|
{ |
842 |
|
✗ |
gate_result_t ret = GATE_RESULT_FAILED; |
843 |
|
✗ |
gate_size_t image_size = surface->width * surface->height * 4; |
844 |
|
✗ |
GLubyte* gl_image_bytes = NULL; |
845 |
|
✗ |
gate_rasterimage_t raster = GATE_INIT_EMPTY; |
846 |
|
|
GLubyte const* ptr_src; |
847 |
|
|
gate_color_t* ptr_dst; |
848 |
|
|
gate_uint32_t y; |
849 |
|
|
gate_uint32_t x; |
850 |
|
|
|
851 |
|
|
do |
852 |
|
|
{ |
853 |
|
✗ |
gl_image_bytes = gate_mem_alloc(image_size); |
854 |
|
✗ |
if (NULL != gl_image_bytes) |
855 |
|
|
{ |
856 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
857 |
|
✗ |
break; |
858 |
|
|
} |
859 |
|
✗ |
gate_mem_clear(gl_image_bytes, image_size); |
860 |
|
|
|
861 |
|
✗ |
if (NULL == gate_rasterimage_create(&raster, GATE_IMAGE_PIXELFORMAT_DEFAULT, surface->width, surface->height, NULL)) |
862 |
|
|
{ |
863 |
|
✗ |
ret = GATE_RESULT_OUTOFMEMORY; |
864 |
|
✗ |
break; |
865 |
|
|
} |
866 |
|
|
|
867 |
|
✗ |
gate_gl_api.glPixelStorei(GL_UNPACK_ALIGNMENT, 1); |
868 |
|
✗ |
gate_gl_api.glReadPixels(0, 0, surface->width, surface->height, GL_RGBA, GL_UNSIGNED_BYTE, gl_image_bytes); |
869 |
|
|
|
870 |
|
✗ |
ptr_src = gl_image_bytes; |
871 |
|
✗ |
y = surface->height; |
872 |
|
✗ |
while (y != 0) |
873 |
|
|
{ |
874 |
|
✗ |
--y; |
875 |
|
✗ |
ptr_dst = (gate_color_t*)gate_rasterimage_get_line_ptr(&raster, y); |
876 |
|
✗ |
for (x = 0; x != surface->width; ++x) |
877 |
|
|
{ |
878 |
|
✗ |
ptr_dst->r = *(ptr_src++); |
879 |
|
✗ |
ptr_dst->g = *(ptr_src++); |
880 |
|
✗ |
ptr_dst->b = *(ptr_src++); |
881 |
|
✗ |
ptr_dst->a = 255; |
882 |
|
✗ |
++ptr_src; |
883 |
|
✗ |
++ptr_dst; |
884 |
|
|
} |
885 |
|
|
} |
886 |
|
|
|
887 |
|
✗ |
if (target_image) |
888 |
|
|
{ |
889 |
|
✗ |
gate_mem_copy(target_image, &raster, sizeof(raster)); |
890 |
|
✗ |
gate_mem_clear(&raster, sizeof(raster)); |
891 |
|
|
} |
892 |
|
|
|
893 |
|
✗ |
ret = GATE_RESULT_OK; |
894 |
|
|
|
895 |
|
|
} while (0); |
896 |
|
|
|
897 |
|
✗ |
gate_rasterimage_release(&raster); |
898 |
|
|
|
899 |
|
✗ |
if (NULL != gl_image_bytes) |
900 |
|
|
{ |
901 |
|
✗ |
gate_mem_dealloc(gl_image_bytes); |
902 |
|
|
} |
903 |
|
✗ |
return ret; |
904 |
|
|
} |
905 |
|
✗ |
gate_result_t gate_gl_surface_run_event_loop(gate_gl_surface_t* surface, gate_gl_surface_events_t* event_callbacks, void* user_param) |
906 |
|
|
{ |
907 |
|
✗ |
void* xlib_surface = surface->special_resources[0]; |
908 |
|
✗ |
gate_xlib_surface_handle_events(xlib_surface, event_callbacks, user_param); |
909 |
|
✗ |
return GATE_RESULT_OK; |
910 |
|
|
} |
911 |
|
✗ |
gate_result_t gate_gl_surface_exit_event_loop(gate_gl_surface_t* surface) |
912 |
|
|
{ |
913 |
|
✗ |
void* xlib_surface = surface->special_resources[0]; |
914 |
|
✗ |
gate_xlib_surface_cancel_events(xlib_surface); |
915 |
|
✗ |
return GATE_RESULT_OK; |
916 |
|
|
} |
917 |
|
|
|
918 |
|
✗ |
gate_result_t gate_gl_surface_swap_buffers(gate_gl_surface_t* surface) |
919 |
|
|
{ |
920 |
|
✗ |
EGLSurface egl_surface = (EGLSurface)surface->native_surface; |
921 |
|
✗ |
EGLDisplay egl_display = (EGLDisplay)surface->special_resources[1]; |
922 |
|
|
|
923 |
|
✗ |
egl.SwapBuffers(egl_display, egl_surface); |
924 |
|
✗ |
return true; |
925 |
|
|
} |
926 |
|
|
|
927 |
|
|
|
928 |
|
|
|
929 |
|
|
#endif |
930 |
|
|
|