RDK Documentation (Open Sourced RDK Components)
rne-triangle.cpp
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2018 RDK Management
6  * Copyright 2005-2018 John Robinson
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 /*
21  * Copyright © 2010 Intel Corporation
22  * Copyright © 2011 Benjamin Franzke
23  * Copyright © 2012-2013 Collabora, Ltd.
24  *
25  * Permission is hereby granted, free of charge, to any person obtaining a
26  * copy of this software and associated documentation files (the "Software"),
27  * to deal in the Software without restriction, including without limitation
28  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29  * and/or sell copies of the Software, and to permit persons to whom the
30  * Software is furnished to do so, subject to the following conditions:
31  *
32  * The above copyright notice and this permission notice (including the next
33  * paragraph) shall be included in all copies or substantial portions of the
34  * Software.
35  *
36  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
37  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
38  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
39  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
40  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
41  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
42  * DEALINGS IN THE SOFTWARE.
43  */
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <memory.h>
47 #include <assert.h>
48 #include <errno.h>
49 #include <unistd.h>
50 #include <signal.h>
51 #include <termios.h>
52 #include <sys/mman.h>
53 #include <sys/time.h>
54 
55 #include <EGL/egl.h>
56 #include <EGL/eglext.h>
57 
58 #include <GLES2/gl2.h>
59 #include <GLES2/gl2ext.h>
60 
61 #include <xkbcommon/xkbcommon.h>
62 
63 #include "wayland-client.h"
64 #include "wayland-egl.h"
65 #include "simpleshell-client-protocol.h"
66 
67 #define UNUSED(x) ((void)x)
68 
69 #if !defined (XKB_KEYMAP_COMPILE_NO_FLAGS)
70 #define XKB_KEYMAP_COMPILE_NO_FLAGS XKB_MAP_COMPILE_NO_FLAGS
71 #endif
72 
73 static void registryHandleGlobal(void *data,
74  struct wl_registry *registry, uint32_t id,
75  const char *interface, uint32_t version);
76 static void registryHandleGlobalRemove(void *data,
77  struct wl_registry *registry,
78  uint32_t name);
79 
80 static const struct wl_registry_listener registryListener =
81 {
82  registryHandleGlobal,
83  registryHandleGlobalRemove
84 };
85 
86 static void shellSurfaceId(void *data,
87  struct wl_simple_shell *wl_simple_shell,
88  struct wl_surface *surface,
89  uint32_t surfaceId);
90 static void shellSurfaceCreated(void *data,
91  struct wl_simple_shell *wl_simple_shell,
92  uint32_t surfaceId,
93  const char *name);
94 static void shellSurfaceDestroyed(void *data,
95  struct wl_simple_shell *wl_simple_shell,
96  uint32_t surfaceId,
97  const char *name);
98 static void shellSurfaceStatus(void *data,
99  struct wl_simple_shell *wl_simple_shell,
100  uint32_t surfaceId,
101  const char *name,
102  uint32_t visible,
103  int32_t x,
104  int32_t y,
105  int32_t width,
106  int32_t height,
107  wl_fixed_t opacity,
108  wl_fixed_t zorder);
109 static void shellGetSurfacesDone(void *data,
110  struct wl_simple_shell *wl_simple_shell);
111 
112 static const struct wl_simple_shell_listener shellListener =
113 {
114  shellSurfaceId,
115  shellSurfaceCreated,
116  shellSurfaceDestroyed,
117  shellSurfaceStatus,
118  shellGetSurfacesDone
119 };
120 
121 typedef enum _InputState
122 {
123  InputState_main,
124  InputState_attribute,
125 } InputState;
126 
127 typedef enum _Attribute
128 {
129  Attribute_position,
130  Attribute_size,
131  Attribute_visibility,
132  Attribute_opacity,
133  Attribute_zorder
134 } Attribute;
135 
136 typedef struct _AppCtx
137 {
138  struct wl_display *display;
139  struct wl_registry *registry;
140  struct wl_shm *shm;
141  struct wl_compositor *compositor;
142  struct wl_simple_shell *shell;
143  struct wl_seat *seat;
144  struct wl_keyboard *keyboard;
145  struct wl_pointer *pointer;
146  struct wl_touch *touch;
147  struct wl_surface *surface;
148  struct wl_output *output;
149  struct wl_egl_window *native;
150  struct wl_callback *frameCallback;
151 
152  struct xkb_context *xkbCtx;
153  struct xkb_keymap *xkbKeymap;
154  struct xkb_state *xkbState;
155  xkb_mod_index_t modAlt;
156  xkb_mod_index_t modCtrl;
157 
158  EGLDisplay eglDisplay;
159  EGLConfig eglConfig;
160  EGLSurface eglSurfaceWindow;
161  EGLContext eglContext;
162  EGLImageKHR eglImage;
163  EGLNativePixmapType eglPixmap;
164 
165  bool getShell;
166  InputState inputState;
167  Attribute attribute;
168 
169  int planeX;
170  int planeY;
171  int planeWidth;
172  int planeHeight;
173 
174  uint32_t surfaceIdOther;
175  uint32_t surfaceIdCurrent;
176  float surfaceOpacity;
177  float surfaceZOrder;
178  bool surfaceVisible;
179  int surfaceX;
180  int surfaceY;
181  int surfaceWidth;
182  int surfaceHeight;
183 
184  int surfaceDX;
185  int surfaceDY;
186  int surfaceDWidth;
187  int surfaceDHeight;
188 
189  struct
190  {
191  GLuint rotation_uniform;
192  GLuint pos;
193  GLuint col;
194  } gl;
195  long long startTime;
196  long long currTime;
197  bool noAnimation;
198  bool needRedraw;
199  bool verboseLog;
200  int pointerX, pointerY;
201 } AppCtx;
202 
203 
204 static void processInput( AppCtx *ctx, uint32_t sym );
205 static void drawFrame( AppCtx *ctx );
206 static bool setupEGL( AppCtx *ctx );
207 static void termEGL( AppCtx *ctx );
208 static bool createSurface( AppCtx *ctx );
209 static void resizeSurface( AppCtx *ctx, int dx, int dy, int width, int height );
210 static void destroySurface( AppCtx *ctx );
211 static bool setupGL( AppCtx *ctx );
212 static bool renderGL( AppCtx *ctx );
213 
214 int g_running= 0;
215 int g_log= 0;
216 
217 static void signalHandler(int signum)
218 {
219  printf("signalHandler: signum %d\n", signum);
220  g_running = 0;
221 }
222 
223 static long long currentTimeMillis()
224 {
225  long long timeMillis;
226  struct timeval tv;
227 
228  gettimeofday(&tv, NULL);
229  timeMillis = tv.tv_sec * 1000 + tv.tv_usec / 1000;
230 
231  return timeMillis;
232 }
233 
234 static void shmFormat(void *data, struct wl_shm *wl_shm, uint32_t format)
235 {
236  AppCtx *ctx = (AppCtx*)data;
237 
238  printf("shm format: %X\n", format);
239 }
240 
241 struct wl_shm_listener shmListener = {
242  shmFormat
243 };
244 
245 static void keyboardKeymap( void *data, struct wl_keyboard *keyboard, uint32_t format, int32_t fd, uint32_t size )
246 {
247  AppCtx *ctx= (AppCtx*)data;
248 
249  if ( format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 )
250  {
251  void *map= mmap( 0, size, PROT_READ, MAP_SHARED, fd, 0 );
252  if ( map != MAP_FAILED )
253  {
254  if ( !ctx->xkbCtx )
255  {
256  ctx->xkbCtx= xkb_context_new( XKB_CONTEXT_NO_FLAGS );
257  }
258  else
259  {
260  printf("error: xkb_context_new failed\n");
261  }
262  if ( ctx->xkbCtx )
263  {
264  if ( ctx->xkbKeymap )
265  {
266  xkb_keymap_unref( ctx->xkbKeymap );
267  ctx->xkbKeymap= 0;
268  }
269  ctx->xkbKeymap= xkb_keymap_new_from_string( ctx->xkbCtx, (char*)map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
270  if ( !ctx->xkbKeymap )
271  {
272  printf("error: xkb_keymap_new_from_string failed\n");
273  }
274  if ( ctx->xkbState )
275  {
276  xkb_state_unref( ctx->xkbState );
277  ctx->xkbState= 0;
278  }
279  ctx->xkbState= xkb_state_new( ctx->xkbKeymap );
280  if ( !ctx->xkbState )
281  {
282  printf("error: xkb_state_new failed\n");
283  }
284  if ( ctx->xkbKeymap )
285  {
286  ctx->modAlt= xkb_keymap_mod_get_index( ctx->xkbKeymap, XKB_MOD_NAME_ALT );
287  ctx->modCtrl= xkb_keymap_mod_get_index( ctx->xkbKeymap, XKB_MOD_NAME_CTRL );
288  }
289  munmap( map, size );
290  }
291  }
292  }
293 
294  close( fd );
295 }
296 
297 static void keyboardEnter( void *data, struct wl_keyboard *keyboard, uint32_t serial,
298  struct wl_surface *surface, struct wl_array *keys )
299 {
300  UNUSED(data);
301  UNUSED(keyboard);
302  UNUSED(serial);
303  UNUSED(keys);
304 
305  printf("keyboard enter surface %p\n", surface );
306 }
307 
308 static void keyboardLeave( void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface )
309 {
310  UNUSED(data);
311  UNUSED(keyboard);
312  UNUSED(serial);
313 
314  printf("keyboard leave surface %p\n", surface );
315 }
316 
317 static void keyboardKey( void *data, struct wl_keyboard *keyboard, uint32_t serial,
318  uint32_t time, uint32_t key, uint32_t state )
319 {
320  AppCtx *ctx= (AppCtx*)data;
321  UNUSED(keyboard);
322  UNUSED(serial);
323  xkb_keycode_t keyCode;
324  uint32_t sym;
325 
326  if ( ctx->xkbState )
327  {
328  // As per wayland protocol for XKB_V1 map, we must add 8 to the key code
329  keyCode= key+8;
330 
331  sym= xkb_state_key_get_one_sym( ctx->xkbState, keyCode );
332 
333  if ( ctx->verboseLog )
334  {
335  int ctrl= 0;
336  int alt= 0;
337 
338  if ( xkb_state_mod_index_is_active( ctx->xkbState, ctx->modCtrl, XKB_STATE_MODS_DEPRESSED) == 1 )
339  {
340  ctrl= 1;
341  }
342 
343  if ( xkb_state_mod_index_is_active( ctx->xkbState, ctx->modAlt, XKB_STATE_MODS_DEPRESSED) == 1 )
344  {
345  alt= 1;
346  }
347 
348  printf("keyboardKey: sym %X state %s ctrl %d alt %d time %u\n",
349  sym, (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "Down" : "Up"), ctrl, alt, time);
350  }
351 
352  if ( state == WL_KEYBOARD_KEY_STATE_PRESSED )
353  {
354  processInput( ctx, sym );
355  }
356  }
357 }
358 
359 static void keyboardModifiers( void *data, struct wl_keyboard *keyboard, uint32_t serial,
360  uint32_t mods_depressed, uint32_t mods_latched,
361  uint32_t mods_locked, uint32_t group )
362 {
363  AppCtx *ctx= (AppCtx*)data;
364  if ( ctx->xkbState )
365  {
366  xkb_state_update_mask( ctx->xkbState, mods_depressed, mods_latched, mods_locked, 0, 0, group );
367  }
368 }
369 
370 static void keyboardRepeatInfo( void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay )
371 {
372  UNUSED(data);
373  UNUSED(keyboard);
374  UNUSED(rate);
375  UNUSED(delay);
376 }
377 
378 static const struct wl_keyboard_listener keyboardListener= {
379  keyboardKeymap,
380  keyboardEnter,
381  keyboardLeave,
382  keyboardKey,
383  keyboardModifiers,
384  keyboardRepeatInfo
385 };
386 
387 static void pointerEnter( void* data, struct wl_pointer *pointer, uint32_t serial,
388  struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy )
389 {
390  UNUSED(pointer);
391  UNUSED(serial);
392  AppCtx *ctx= (AppCtx*)data;
393  int x, y;
394 
395  x= wl_fixed_to_int( sx );
396  y= wl_fixed_to_int( sy );
397 
398  ctx->pointerX= x;
399  ctx->pointerY= y;
400 
401  printf("pointer enter surface %p (%d,%d)\n", surface, x, y );
402 }
403 
404 static void pointerLeave( void* data, struct wl_pointer *pointer, uint32_t serial, struct wl_surface *surface )
405 {
406  UNUSED(data);
407  UNUSED(pointer);
408  UNUSED(serial);
409 
410  printf("pointer leave surface %p\n", surface );
411 }
412 
413 static void pointerMotion( void *data, struct wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy )
414 {
415  UNUSED(pointer);
416  AppCtx *ctx= (AppCtx*)data;
417  int x, y;
418 
419  x= wl_fixed_to_int( sx );
420  y= wl_fixed_to_int( sy );
421 
422  ctx->pointerX= x;
423  ctx->pointerY= y;
424 
425  if ( ctx->verboseLog )
426  {
427  printf("pointer motion surface (%d,%d) time %u\n", x, y, time );
428  }
429 }
430 
431 static void pointerButton( void *data, struct wl_pointer *pointer, uint32_t serial,
432  uint32_t time, uint32_t button, uint32_t state )
433 {
434  UNUSED(pointer);
435  UNUSED(serial);
436  AppCtx *ctx= (AppCtx*)data;
437 
438  printf("pointer button %u state %u (%d, %d)\n", button, state, ctx->pointerX, ctx->pointerY);
439  ctx->verboseLog= (state == WL_POINTER_BUTTON_STATE_PRESSED);
440 }
441 
442 static void pointerAxis( void *data, struct wl_pointer *pointer, uint32_t time,
443  uint32_t axis, wl_fixed_t value )
444 {
445  UNUSED(data);
446  UNUSED(pointer);
447  UNUSED(time);
448  int v;
449 
450  v= wl_fixed_to_int( value );
451  printf("pointer axis %u value %d\n", axis, v);
452 }
453 
454 static const struct wl_pointer_listener pointerListener = {
455  pointerEnter,
456  pointerLeave,
457  pointerMotion,
458  pointerButton,
459  pointerAxis
460 };
461 
462 static void seatCapabilities( void *data, struct wl_seat *seat, uint32_t capabilities )
463 {
464  AppCtx *ctx = (AppCtx*)data;
465 
466  printf("seat %p caps: %X\n", seat, capabilities );
467 
468  if ( capabilities & WL_SEAT_CAPABILITY_KEYBOARD )
469  {
470  printf(" seat has keyboard\n");
471  ctx->keyboard= wl_seat_get_keyboard( ctx->seat );
472  printf(" keyboard %p\n", ctx->keyboard );
473  wl_keyboard_add_listener( ctx->keyboard, &keyboardListener, ctx );
474  }
475  if ( capabilities & WL_SEAT_CAPABILITY_POINTER )
476  {
477  printf(" seat has pointer\n");
478  ctx->pointer= wl_seat_get_pointer( ctx->seat );
479  printf(" pointer %p\n", ctx->pointer );
480  wl_pointer_add_listener( ctx->pointer, &pointerListener, ctx );
481  }
482  if ( capabilities & WL_SEAT_CAPABILITY_TOUCH )
483  {
484  printf(" seat has touch\n");
485  ctx->touch= wl_seat_get_touch( ctx->seat );
486  printf(" touch %p\n", ctx->touch );
487  }
488 }
489 
490 static void seatName( void *data, struct wl_seat *seat, const char *name )
491 {
492  AppCtx *ctx = (AppCtx*)data;
493  printf("seat %p name: %s\n", seat, name);
494 }
495 
496 static const struct wl_seat_listener seatListener = {
497  seatCapabilities,
498  seatName
499 };
500 
501 static void outputGeometry( void *data, struct wl_output *output, int32_t x, int32_t y,
502  int32_t physical_width, int32_t physical_height, int32_t subpixel,
503  const char *make, const char *model, int32_t transform )
504 {
505  UNUSED(data);
506  UNUSED(output);
507  UNUSED(x);
508  UNUSED(y);
509  UNUSED(physical_width);
510  UNUSED(physical_height);
511  UNUSED(subpixel);
512  UNUSED(make);
513  UNUSED(model);
514  UNUSED(transform);
515 }
516 
517 static void outputMode( void *data, struct wl_output *output, uint32_t flags,
518  int32_t width, int32_t height, int32_t refresh )
519 {
520  AppCtx *ctx = (AppCtx*)data;
521 
522  if ( flags & WL_OUTPUT_MODE_CURRENT )
523  {
524  if ( (width != ctx->planeWidth) || (height != ctx->planeHeight) )
525  {
526  ctx->planeWidth= width;
527  ctx->planeHeight= height;
528  if ( ctx->verboseLog )
529  {
530  printf("outputMode: resize egl window to (%d,%d)\n", ctx->planeWidth, ctx->planeHeight );
531  }
532  resizeSurface( ctx, 0, 0, ctx->planeWidth, ctx->planeHeight);
533  }
534  }
535 }
536 
537 static void outputDone( void *data, struct wl_output *output )
538 {
539  UNUSED(data);
540  UNUSED(output);
541 }
542 
543 static void outputScale( void *data, struct wl_output *output, int32_t factor )
544 {
545  UNUSED(data);
546  UNUSED(output);
547  UNUSED(factor);
548 }
549 
550 static const struct wl_output_listener outputListener = {
551  outputGeometry,
552  outputMode,
553  outputDone,
554  outputScale
555 };
556 
557 static void registryHandleGlobal(void *data,
558  struct wl_registry *registry, uint32_t id,
559  const char *interface, uint32_t version)
560 {
561  AppCtx *ctx = (AppCtx*)data;
562  int len;
563 
564  printf("rne-triangle: registry: id %d interface (%s) version %d\n", id, interface, version );
565 
566  len= strlen(interface);
567  if ( (len==6) && !strncmp(interface, "wl_shm", len)) {
568  ctx->shm= (struct wl_shm*)wl_registry_bind(registry, id, &wl_shm_interface, 1);
569  printf("shm %p\n", ctx->shm);
570  wl_shm_add_listener(ctx->shm, &shmListener, ctx);
571  }
572  else if ( (len==13) && !strncmp(interface, "wl_compositor", len) ) {
573  ctx->compositor= (struct wl_compositor*)wl_registry_bind(registry, id, &wl_compositor_interface, 1);
574  printf("compositor %p\n", ctx->compositor);
575  }
576  else if ( (len==7) && !strncmp(interface, "wl_seat", len) ) {
577  ctx->seat= (struct wl_seat*)wl_registry_bind(registry, id, &wl_seat_interface, 4);
578  printf("seat %p\n", ctx->seat);
579  wl_seat_add_listener(ctx->seat, &seatListener, ctx);
580  }
581  else if ( (len==9) && !strncmp(interface, "wl_output", len) ) {
582  ctx->output= (struct wl_output*)wl_registry_bind(registry, id, &wl_output_interface, 2);
583  printf("output %p\n", ctx->output);
584  wl_output_add_listener(ctx->output, &outputListener, ctx);
585  }
586  else if ( (len==15) && !strncmp(interface, "wl_simple_shell", len) ) {
587  if ( ctx->getShell ) {
588  ctx->shell= (struct wl_simple_shell*)wl_registry_bind(registry, id, &wl_simple_shell_interface, 1);
589  printf("shell %p\n", ctx->shell );
590  wl_simple_shell_add_listener(ctx->shell, &shellListener, ctx);
591  }
592  }
593 }
594 
595 static void registryHandleGlobalRemove(void *data,
596  struct wl_registry *registry,
597  uint32_t name)
598 {
599 }
600 
601 static void shellSurfaceId(void *data,
602  struct wl_simple_shell *wl_simple_shell,
603  struct wl_surface *surface,
604  uint32_t surfaceId)
605 {
606  AppCtx *ctx = (AppCtx*)data;
607  char name[32];
608 
609  sprintf( name, "rne-triangle-surface-%x", surfaceId );
610  printf("shell: surface created: %p id %x\n", surface, surfaceId);
611  wl_simple_shell_set_name( ctx->shell, surfaceId, name );
612 }
613 
614 static void shellSurfaceCreated(void *data,
615  struct wl_simple_shell *wl_simple_shell,
616  uint32_t surfaceId,
617  const char *name)
618 {
619  AppCtx *ctx = (AppCtx*)data;
620 
621  printf("shell: surface created: %x name: %s\n", surfaceId, name);
622  ctx->surfaceIdOther= ctx->surfaceIdCurrent;
623  ctx->surfaceIdCurrent= surfaceId;
624  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
625  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
626 }
627 
628 static void shellSurfaceDestroyed(void *data,
629  struct wl_simple_shell *wl_simple_shell,
630  uint32_t surfaceId,
631  const char *name)
632 {
633  AppCtx *ctx = (AppCtx*)data;
634 
635  printf("shell: surface destroyed: %x name: %s\n", surfaceId, name);
636 
637  if ( ctx->surfaceIdCurrent == surfaceId )
638  {
639  ctx->surfaceIdCurrent= ctx->surfaceIdOther;
640  ctx->surfaceIdOther= 0;
641  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
642  }
643  if ( ctx->surfaceIdOther == surfaceId )
644  {
645  ctx->surfaceIdOther= 0;
646  }
647  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
648 }
649 
650 static void shellSurfaceStatus(void *data,
651  struct wl_simple_shell *wl_simple_shell,
652  uint32_t surfaceId,
653  const char *name,
654  uint32_t visible,
655  int32_t x,
656  int32_t y,
657  int32_t width,
658  int32_t height,
659  wl_fixed_t opacity,
660  wl_fixed_t zorder)
661 {
662  AppCtx *ctx = (AppCtx*)data;
663 
664  printf("shell: surface: %x name: %s\n", surfaceId, name);
665  printf("shell: position (%d,%d,%d,%d) visible %d opacity %f zorder %f\n",
666  x, y, width, height, visible, wl_fixed_to_double(opacity), wl_fixed_to_double(zorder) );
667 
668  ctx->surfaceVisible= visible;
669  ctx->surfaceX= x;
670  ctx->surfaceY= y;
671  ctx->surfaceWidth= width;
672  ctx->surfaceHeight= height;
673  ctx->surfaceOpacity= wl_fixed_to_double(opacity);
674  ctx->surfaceZOrder= wl_fixed_to_double(zorder);
675 }
676 
677 static void shellGetSurfacesDone(void *data,
678  struct wl_simple_shell *wl_simple_shell)
679 {
680  AppCtx *ctx = (AppCtx*)data;
681  printf("shell: get all surfaces done\n");
682 }
683 
684 #define NON_BLOCKING_ENABLED (0)
685 #define NON_BLOCKING_DISABLED (1)
686 
687 static void setBlockingMode(int blockingState )
688 {
689  struct termios ttystate;
690  int mask, bits;
691 
692  mask= (blockingState == NON_BLOCKING_ENABLED) ? ~(ICANON|ECHO) : -1;
693  bits= (blockingState == NON_BLOCKING_ENABLED) ? 0 : (ICANON|ECHO);
694 
695  // Obtain the current terminal state and alter the attributes to achieve
696  // the requested blocking behaviour
697  tcgetattr(STDIN_FILENO, &ttystate);
698 
699  ttystate.c_lflag= ((ttystate.c_lflag & mask) | bits);
700 
701  if (blockingState == NON_BLOCKING_ENABLED)
702  {
703  ttystate.c_cc[VMIN]= 1;
704  }
705 
706  tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
707 }
708 
709 static bool isKeyHit()
710 {
711  bool keyHit= false;
712  fd_set fdset;
713  struct timeval tval;
714 
715  // do a non-blocking check to see if any keys
716  // are ready to read from stdin
717  tval.tv_sec= 0;
718  tval.tv_usec= 0;
719  FD_ZERO(&fdset);
720  FD_SET(STDIN_FILENO, &fdset);
721  select(STDIN_FILENO+1, &fdset, NULL, NULL, &tval);
722 
723  keyHit= FD_ISSET(STDIN_FILENO, &fdset);
724 
725  return keyHit;
726 }
727 
728 static void adjustAttribute( AppCtx *ctx, uint32_t sym )
729 {
730  switch( ctx->attribute )
731  {
732  case Attribute_position:
733  switch( sym )
734  {
735  case XKB_KEY_Up:
736  --ctx->surfaceDY;
737  break;
738  case XKB_KEY_Down:
739  ++ctx->surfaceDY;
740  break;
741  case XKB_KEY_Right:
742  ++ctx->surfaceDX;
743  break;
744  case XKB_KEY_Left:
745  --ctx->surfaceDX;
746  break;
747  }
748  break;
749  case Attribute_size:
750  switch( sym )
751  {
752  case XKB_KEY_Up:
753  --ctx->surfaceDHeight;
754  break;
755  case XKB_KEY_Down:
756  ++ctx->surfaceDHeight;
757  break;
758  case XKB_KEY_Right:
759  ++ctx->surfaceDWidth;
760  break;
761  case XKB_KEY_Left:
762  --ctx->surfaceDWidth;
763  break;
764  }
765  break;
766  case Attribute_visibility:
767  switch( sym )
768  {
769  case XKB_KEY_Up:
770  case XKB_KEY_Right:
771  case XKB_KEY_Down:
772  case XKB_KEY_Left:
773  ctx->surfaceVisible= !ctx->surfaceVisible;
774  wl_simple_shell_set_visible( ctx->shell, ctx->surfaceIdCurrent, (ctx->surfaceVisible ? 1 : 0) );
775  break;
776  }
777  break;
778  case Attribute_opacity:
779  switch( sym )
780  {
781  case XKB_KEY_Up:
782  case XKB_KEY_Right:
783  ctx->surfaceOpacity += 0.1;
784  if ( ctx->surfaceOpacity > 1.0 )
785  {
786  ctx->surfaceOpacity= 1.0;
787  }
788  wl_simple_shell_set_opacity( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceOpacity) );
789  break;
790  case XKB_KEY_Down:
791  case XKB_KEY_Left:
792  ctx->surfaceOpacity -= 0.1;
793  if ( ctx->surfaceOpacity < 0.0 )
794  {
795  ctx->surfaceOpacity= 0.0;
796  }
797  wl_simple_shell_set_opacity( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceOpacity) );
798  break;
799  }
800  break;
801  case Attribute_zorder:
802  switch( sym )
803  {
804  case XKB_KEY_Up:
805  case XKB_KEY_Right:
806  ctx->surfaceZOrder += 0.1;
807  if ( ctx->surfaceZOrder > 1.0 )
808  {
809  ctx->surfaceZOrder= 1.0;
810  }
811  wl_simple_shell_set_zorder( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceZOrder) );
812  break;
813  case XKB_KEY_Down:
814  case XKB_KEY_Left:
815  ctx->surfaceZOrder -= 0.1;
816  if ( ctx->surfaceZOrder < 0.0 )
817  {
818  ctx->surfaceZOrder= 0.0;
819  }
820  wl_simple_shell_set_zorder( ctx->shell, ctx->surfaceIdCurrent, wl_fixed_from_double(ctx->surfaceZOrder) );
821  break;
822  }
823  break;
824  }
825 }
826 
827 static void processInputMain( AppCtx *ctx, uint32_t sym )
828 {
829  switch( sym )
830  {
831  case XKB_KEY_Left:
832  case XKB_KEY_Up:
833  case XKB_KEY_Right:
834  case XKB_KEY_Down:
835  if ( ctx->surfaceIdCurrent )
836  {
837  adjustAttribute( ctx, sym );
838  }
839  break;
840  case XKB_KEY_a:
841  ctx->inputState= InputState_attribute;
842  printf("attribute: (p) osition, (s) ize, (v) isible, (o) pacity, (z) order (x) back to main\n");
843  break;
844  case XKB_KEY_s:
845  if ( ctx->surfaceIdCurrent )
846  {
847  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
848  }
849  break;
850  case XKB_KEY_n:
851  if ( ctx->surfaceIdOther )
852  {
853  uint32_t temp= ctx->surfaceIdCurrent;
854  ctx->surfaceIdCurrent= ctx->surfaceIdOther;
855  ctx->surfaceIdOther= temp;
856  printf("shell: surfaceCurrent: %x surfaceOther: %x\n", ctx->surfaceIdCurrent, ctx->surfaceIdOther);
857  wl_simple_shell_get_status( ctx->shell, ctx->surfaceIdCurrent );
858  }
859  break;
860  case XKB_KEY_l:
861  if ( ctx->shell )
862  {
863  printf("get all surfaces:\n");
864  wl_simple_shell_get_surfaces( ctx->shell );
865  }
866  break;
867  case XKB_KEY_r:
868  ctx->planeWidth= (ctx->planeWidth == 1280) ? 640 : 1280;
869  ctx->planeHeight= (ctx->planeHeight == 720) ? 360 : 720;
870  printf("resize egl window to (%d,%d)\n", ctx->planeWidth, ctx->planeHeight );
871  resizeSurface( ctx, 0, 0, ctx->planeWidth, ctx->planeHeight);
872  break;
873  }
874 }
875 
876 static void processInputAttribute( AppCtx *ctx, uint32_t sym )
877 {
878  switch( sym )
879  {
880  case XKB_KEY_p:
881  ctx->attribute= Attribute_position;
882  break;
883  case XKB_KEY_s:
884  ctx->attribute= Attribute_size;
885  break;
886  case XKB_KEY_v:
887  ctx->attribute= Attribute_visibility;
888  break;
889  case XKB_KEY_o:
890  ctx->attribute= Attribute_opacity;
891  break;
892  case XKB_KEY_z:
893  ctx->attribute= Attribute_zorder;
894  break;
895  default:
896  case 'x':
897  break;
898  }
899  ctx->inputState= InputState_main;
900 }
901 
902 static void processInput( AppCtx *ctx, uint32_t sym )
903 {
904  switch( ctx->inputState )
905  {
906  case InputState_main:
907  processInputMain( ctx, sym );
908  break;
909  case InputState_attribute:
910  processInputAttribute( ctx, sym );
911  break;
912  }
913 }
914 
915 static void showUsage()
916 {
917  printf("usage:\n");
918  printf(" rne_triangle [options]\n" );
919  printf("where [options] are:\n" );
920  printf(" --delay <delay> : render loop delay\n" );
921  printf(" --shell : use wl_simple_shell protocol\n" );
922  printf(" --display <name> : wayland display to connect to\n" );
923  printf(" --noframe : don't pace rendering with frame requests\n" );
924  printf(" --noanimate : don't use animation\n" );
925  printf(" -? : show usage\n" );
926  printf("\n" );
927 }
928 
929 static void redraw( void *data, struct wl_callback *callback, uint32_t time )
930 {
931  AppCtx *ctx= (AppCtx*)data;
932 
933  if ( g_log ) printf("redraw: time %u\n", time);
934  wl_callback_destroy( callback );
935 
936  ctx->needRedraw= true;
937 }
938 
939 static struct wl_callback_listener frameListener=
940 {
941  redraw
942 };
943 
944 static void drawFrame( AppCtx *ctx )
945 {
946  if ( ctx->surfaceDX || ctx->surfaceDY || ctx->surfaceDWidth || ctx->surfaceDHeight )
947  {
948  ctx->surfaceX += ctx->surfaceDX;
949  ctx->surfaceY += ctx->surfaceDY;
950  ctx->surfaceWidth += ctx->surfaceDWidth;
951  ctx->surfaceHeight += ctx->surfaceDHeight;
952 
953  wl_simple_shell_set_geometry( ctx->shell, ctx->surfaceIdCurrent,
954  ctx->surfaceX, ctx->surfaceY, ctx->surfaceWidth, ctx->surfaceHeight );
955  }
956 
957  renderGL(ctx);
958 
959  ctx->frameCallback= wl_surface_frame( ctx->surface );
960  wl_callback_add_listener( ctx->frameCallback, &frameListener, ctx );
961 
962  eglSwapBuffers(ctx->eglDisplay, ctx->eglSurfaceWindow);
963 }
964 
965 #define NUM_EVENTS (20)
966 int main( int argc, char** argv)
967 {
968  int nRC= 0;
969  AppCtx ctx;
970  struct sigaction sigint;
971  struct wl_display *display= 0;
972  struct wl_registry *registry= 0;
973  int count;
974  int delay= 16667;
975  const char *display_name= 0;
976  bool paceRendering= true;
977  EGLBoolean swapok;
978 
979  printf("rne_triangle: v1.0\n" );
980 
981  memset( &ctx, 0, sizeof(AppCtx) );
982 
983  for( int i= 1; i < argc; ++i )
984  {
985  if ( !strcmp( (const char*)argv[i], "--delay") )
986  {
987  printf("got delay: i %d argc %d\n", i, argc );
988  if ( i+1 < argc )
989  {
990  int v= atoi(argv[++i]);
991  printf("v=%d\n", v);
992  if ( v > 0 )
993  {
994  delay= v;
995  printf("using delay=%d\n", delay );
996  }
997  }
998  }
999  else if (!strcmp( (const char*)argv[i], "--shell" ) )
1000  {
1001  ctx.getShell= true;
1002  }
1003  else if ( !strcmp( (const char*)argv[i], "--display") )
1004  {
1005  if ( i+1 < argc )
1006  {
1007  ++i;
1008  display_name= argv[i];
1009  }
1010  }
1011  else if (!strcmp( (const char*)argv[i], "--noframe" ) )
1012  {
1013  paceRendering= false;
1014  }
1015  else if (!strcmp( (const char*)argv[i], "--log" ) )
1016  {
1017  g_log= true;
1018  }
1019  else if (!strcmp( (const char*)argv[i], "--noanimate" ) )
1020  {
1021  ctx.noAnimation= true;
1022  }
1023  else if ( !strcmp( (const char*)argv[i], "-?" ) )
1024  {
1025  showUsage();
1026  goto exit;
1027  }
1028  }
1029 
1030  ctx.startTime= currentTimeMillis();
1031 
1032  if ( display_name )
1033  {
1034  printf("calling wl_display_connect for display name %s\n", display_name);
1035  }
1036  else
1037  {
1038  printf("calling wl_display_connect for default display\n");
1039  }
1040  display= wl_display_connect(display_name);
1041  printf("wl_display_connect: display=%p\n", display);
1042  if ( !display )
1043  {
1044  printf("error: unable to connect to primary display\n");
1045  nRC= -1;
1046  goto exit;
1047  }
1048 
1049  printf("calling wl_display_get_registry\n");
1050  registry= wl_display_get_registry(display);
1051  printf("wl_display_get_registry: registry=%p\n", registry);
1052  if ( !registry )
1053  {
1054  printf("error: unable to get display registry\n");
1055  nRC= -2;
1056  goto exit;
1057  }
1058 
1059  ctx.display= display;
1060  ctx.registry= registry;
1061  ctx.planeX= 0;
1062  ctx.planeY= 0;
1063  ctx.planeWidth= 1280;
1064  ctx.planeHeight= 720;
1065  wl_registry_add_listener(registry, &registryListener, &ctx);
1066 
1067  wl_display_roundtrip(ctx.display);
1068 
1069  setupEGL(&ctx);
1070 
1071  ctx.surfaceWidth= 1280;
1072  ctx.surfaceHeight= 720;
1073  ctx.surfaceX= 0;
1074  ctx.surfaceY= 0;
1075 
1076  createSurface(&ctx);
1077 
1078  setupGL(&ctx);
1079 
1080  if ( paceRendering )
1081  {
1082  drawFrame(&ctx);
1083  }
1084 
1085  sigint.sa_handler = signalHandler;
1086  sigemptyset(&sigint.sa_mask);
1087  sigint.sa_flags = SA_RESETHAND;
1088  sigaction(SIGINT, &sigint, NULL);
1089 
1090  setBlockingMode(NON_BLOCKING_ENABLED);
1091 
1092  ctx.inputState= InputState_main;
1093  ctx.attribute= Attribute_position;
1094 
1095  g_running= 1;
1096  while( g_running )
1097  {
1098  if ( wl_display_dispatch( ctx.display ) == -1 )
1099  {
1100  break;
1101  }
1102 
1103  if ( !paceRendering )
1104  {
1105  if ( delay > 0 )
1106  {
1107  usleep(delay);
1108  }
1109  renderGL(&ctx);
1110  eglSwapBuffers(ctx.eglDisplay, ctx.eglSurfaceWindow);
1111  }
1112  else if ( ctx.needRedraw )
1113  {
1114  ctx.needRedraw= false;
1115  drawFrame(&ctx);
1116  }
1117 
1118  if ( ctx.getShell )
1119  {
1120  if ( isKeyHit() )
1121  {
1122  uint32_t sym= XKB_KEY_NoSymbol;
1123  int c= fgetc(stdin);
1124  switch( c )
1125  {
1126  case 0x1B:
1127  c= fgetc(stdin);
1128  if ( c == 0x5B )
1129  {
1130  c= fgetc(stdin);
1131  switch( c )
1132  {
1133  case 0x41: //UP
1134  sym= XKB_KEY_Up;
1135  break;
1136  case 0x42: //DOWN
1137  sym= XKB_KEY_Down;
1138  break;
1139  case 0x43: //RIGHT
1140  sym= XKB_KEY_Right;
1141  break;
1142  case 0x44: // LEFT
1143  sym= XKB_KEY_Left;
1144  break;
1145  }
1146  }
1147  break;
1148  default:
1149  sym= c;
1150  break;
1151  }
1152  processInput(&ctx, sym);
1153 
1154  // Prevent keys from building up while held down
1155  tcflush(STDIN_FILENO,TCIFLUSH);
1156  }
1157  else
1158  {
1159  if ( ctx.surfaceDX || ctx.surfaceDY || ctx.surfaceDWidth || ctx.surfaceDHeight )
1160  {
1161  // Key has been released - reset deltas
1162  ctx.surfaceDX= ctx.surfaceDY= ctx.surfaceDWidth= ctx.surfaceDHeight= 0;
1163  }
1164  }
1165  }
1166  }
1167 
1168 exit:
1169 
1170  printf("rne_triangle: exiting...\n");
1171 
1172  setBlockingMode(NON_BLOCKING_DISABLED);
1173 
1174  if ( ctx.compositor )
1175  {
1176  wl_compositor_destroy( ctx.compositor );
1177  ctx.compositor= 0;
1178  }
1179 
1180  if ( ctx.shell )
1181  {
1182  wl_simple_shell_destroy( ctx.shell );
1183  ctx.shell= 0;
1184  }
1185 
1186  termEGL(&ctx);
1187 
1188  if ( ctx.xkbState )
1189  {
1190  xkb_state_unref( ctx.xkbState );
1191  ctx.xkbState= 0;
1192  }
1193 
1194  if ( ctx.xkbKeymap )
1195  {
1196  xkb_keymap_unref( ctx.xkbKeymap );
1197  ctx.xkbKeymap= 0;
1198  }
1199 
1200  if ( ctx.xkbCtx )
1201  {
1202  xkb_context_unref( ctx.xkbCtx );
1203  ctx.xkbCtx= 0;
1204  }
1205 
1206  if ( ctx.pointer )
1207  {
1208  wl_pointer_destroy(ctx.pointer);
1209  ctx.pointer= 0;
1210  }
1211 
1212  if ( ctx.keyboard )
1213  {
1214  wl_keyboard_destroy(ctx.keyboard);
1215  ctx.keyboard= 0;
1216  }
1217 
1218  if ( ctx.seat )
1219  {
1220  wl_seat_destroy(ctx.seat);
1221  ctx.seat= 0;
1222  }
1223 
1224  if ( ctx.output )
1225  {
1226  wl_output_destroy(ctx.output);
1227  ctx.output= 0;
1228  }
1229 
1230  if ( registry )
1231  {
1232  wl_registry_destroy(registry);
1233  registry= 0;
1234  }
1235 
1236  if ( display )
1237  {
1238  wl_display_disconnect(display);
1239  display= 0;
1240  }
1241 
1242  printf("rne_triangle: exit\n");
1243 
1244  return nRC;
1245 }
1246 
1247 #define RED_SIZE (8)
1248 #define GREEN_SIZE (8)
1249 #define BLUE_SIZE (8)
1250 #define ALPHA_SIZE (8)
1251 #define DEPTH_SIZE (0)
1252 
1253 static bool setupEGL( AppCtx *ctx )
1254 {
1255  bool result= false;
1256  EGLint major, minor;
1257  EGLBoolean b;
1258  EGLint configCount;
1259  EGLConfig *eglConfigs= 0;
1260  EGLint attr[32];
1261  EGLint redSize, greenSize, blueSize, alphaSize, depthSize;
1262  EGLint ctxAttrib[3];
1263  int i;
1264 
1265  /*
1266  * Get default EGL display
1267  */
1268  ctx->eglDisplay = eglGetDisplay((NativeDisplayType)ctx->display);
1269  printf("eglDisplay=%p\n", ctx->eglDisplay );
1270  if ( ctx->eglDisplay == EGL_NO_DISPLAY )
1271  {
1272  printf("error: EGL not available\n" );
1273  goto exit;
1274  }
1275 
1276  /*
1277  * Initialize display
1278  */
1279  b= eglInitialize( ctx->eglDisplay, &major, &minor );
1280  if ( !b )
1281  {
1282  printf("error: unable to initialize EGL display\n" );
1283  goto exit;
1284  }
1285  printf("eglInitiialize: major: %d minor: %d\n", major, minor );
1286 
1287  /*
1288  * Get number of available configurations
1289  */
1290  b= eglGetConfigs( ctx->eglDisplay, NULL, 0, &configCount );
1291  if ( !b )
1292  {
1293  printf("error: unable to get count of EGL configurations: %X\n", eglGetError() );
1294  goto exit;
1295  }
1296  printf("Number of EGL configurations: %d\n", configCount );
1297 
1298  eglConfigs= (EGLConfig*)malloc( configCount*sizeof(EGLConfig) );
1299  if ( !eglConfigs )
1300  {
1301  printf("error: unable to alloc memory for EGL configurations\n");
1302  goto exit;
1303  }
1304 
1305  i= 0;
1306  attr[i++]= EGL_RED_SIZE;
1307  attr[i++]= RED_SIZE;
1308  attr[i++]= EGL_GREEN_SIZE;
1309  attr[i++]= GREEN_SIZE;
1310  attr[i++]= EGL_BLUE_SIZE;
1311  attr[i++]= BLUE_SIZE;
1312  attr[i++]= EGL_DEPTH_SIZE;
1313  attr[i++]= DEPTH_SIZE;
1314  attr[i++]= EGL_STENCIL_SIZE;
1315  attr[i++]= 0;
1316  attr[i++]= EGL_SURFACE_TYPE;
1317  attr[i++]= EGL_WINDOW_BIT;
1318  attr[i++]= EGL_RENDERABLE_TYPE;
1319  attr[i++]= EGL_OPENGL_ES2_BIT;
1320  attr[i++]= EGL_NONE;
1321 
1322  /*
1323  * Get a list of configurations that meet or exceed our requirements
1324  */
1325  b= eglChooseConfig( ctx->eglDisplay, attr, eglConfigs, configCount, &configCount );
1326  if ( !b )
1327  {
1328  printf("error: eglChooseConfig failed: %X\n", eglGetError() );
1329  goto exit;
1330  }
1331  printf("eglChooseConfig: matching configurations: %d\n", configCount );
1332 
1333  /*
1334  * Choose a suitable configuration
1335  */
1336  for( i= 0; i < configCount; ++i )
1337  {
1338  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_RED_SIZE, &redSize );
1339  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_GREEN_SIZE, &greenSize );
1340  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_BLUE_SIZE, &blueSize );
1341  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_ALPHA_SIZE, &alphaSize );
1342  eglGetConfigAttrib( ctx->eglDisplay, eglConfigs[i], EGL_DEPTH_SIZE, &depthSize );
1343 
1344  printf("config %d: red: %d green: %d blue: %d alpha: %d depth: %d\n",
1345  i, redSize, greenSize, blueSize, alphaSize, depthSize );
1346  if ( (redSize == RED_SIZE) &&
1347  (greenSize == GREEN_SIZE) &&
1348  (blueSize == BLUE_SIZE) &&
1349  (alphaSize == ALPHA_SIZE) &&
1350  (depthSize >= DEPTH_SIZE) )
1351  {
1352  printf( "choosing config %d\n", i);
1353  break;
1354  }
1355  }
1356  if ( i == configCount )
1357  {
1358  printf("error: no suitable configuration available\n");
1359  goto exit;
1360  }
1361  ctx->eglConfig= eglConfigs[i];
1362 
1363  ctxAttrib[0]= EGL_CONTEXT_CLIENT_VERSION;
1364  ctxAttrib[1]= 2; // ES2
1365  ctxAttrib[2]= EGL_NONE;
1366 
1367  /*
1368  * Create an EGL context
1369  */
1370  ctx->eglContext= eglCreateContext( ctx->eglDisplay, ctx->eglConfig, EGL_NO_CONTEXT, ctxAttrib );
1371  if ( ctx->eglContext == EGL_NO_CONTEXT )
1372  {
1373  printf( "eglCreateContext failed: %X\n", eglGetError() );
1374  goto exit;
1375  }
1376  printf("eglCreateContext: eglContext %p\n", ctx->eglContext );
1377 
1378  result= true;
1379 
1380 exit:
1381 
1382  if ( eglConfigs )
1383  {
1384  free( eglConfigs );
1385  eglConfigs= 0;
1386  }
1387 
1388  return result;
1389 }
1390 
1391 static void termEGL( AppCtx *ctx )
1392 {
1393  if ( ctx->display )
1394  {
1395  eglMakeCurrent( ctx->eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
1396 
1397  destroySurface( ctx );
1398 
1399  eglTerminate( ctx->eglDisplay );
1400  eglReleaseThread();
1401  }
1402 }
1403 
1404 static bool createSurface( AppCtx *ctx )
1405 {
1406  bool result= false;
1407  EGLBoolean b;
1408 
1409  ctx->surface= wl_compositor_create_surface(ctx->compositor);
1410  printf("surface=%p\n", ctx->surface);
1411  if ( !ctx->surface )
1412  {
1413  printf("error: unable to create wayland surface\n");
1414  goto exit;
1415  }
1416 
1417  ctx->native= wl_egl_window_create(ctx->surface, ctx->planeWidth, ctx->planeHeight);
1418  if ( !ctx->native )
1419  {
1420  printf("error: unable to create wl_egl_window\n");
1421  goto exit;
1422  }
1423  printf("wl_egl_window %p\n", ctx->native);
1424 
1425  /*
1426  * Create a window surface
1427  */
1428  ctx->eglSurfaceWindow= eglCreateWindowSurface( ctx->eglDisplay,
1429  ctx->eglConfig,
1430  (EGLNativeWindowType)ctx->native,
1431  NULL );
1432  if ( ctx->eglSurfaceWindow == EGL_NO_SURFACE )
1433  {
1434  printf("eglCreateWindowSurface: A: error %X\n", eglGetError() );
1435  ctx->eglSurfaceWindow= eglCreateWindowSurface( ctx->eglDisplay,
1436  ctx->eglConfig,
1437  (EGLNativeWindowType)NULL,
1438  NULL );
1439  if ( ctx->eglSurfaceWindow == EGL_NO_SURFACE )
1440  {
1441  printf("eglCreateWindowSurface: B: error %X\n", eglGetError() );
1442  goto exit;
1443  }
1444  }
1445  printf("eglCreateWindowSurface: eglSurfaceWindow %p\n", ctx->eglSurfaceWindow );
1446 
1447  /*
1448  * Establish EGL context for this thread
1449  */
1450  b= eglMakeCurrent( ctx->eglDisplay, ctx->eglSurfaceWindow, ctx->eglSurfaceWindow, ctx->eglContext );
1451  if ( !b )
1452  {
1453  printf("error: eglMakeCurrent failed: %X\n", eglGetError() );
1454  goto exit;
1455  }
1456 
1457  eglSwapInterval( ctx->eglDisplay, 1 );
1458 
1459 exit:
1460 
1461  return result;
1462 }
1463 
1464 static void destroySurface( AppCtx *ctx )
1465 {
1466  if ( ctx->eglSurfaceWindow )
1467  {
1468  eglDestroySurface( ctx->eglDisplay, ctx->eglSurfaceWindow );
1469 
1470  wl_egl_window_destroy( ctx->native );
1471  }
1472  if ( ctx->surface )
1473  {
1474  wl_surface_destroy( ctx->surface );
1475  ctx->surface= 0;
1476  }
1477 }
1478 
1479 static void resizeSurface( AppCtx *ctx, int dx, int dy, int width, int height )
1480 {
1481  wl_egl_window_resize( ctx->native, width, height, dx, dy );
1482 }
1483 
1484 static const char *vert_shader_text =
1485  "uniform mat4 rotation;\n"
1486  "attribute vec4 pos;\n"
1487  "attribute vec4 color;\n"
1488  "varying vec4 v_color;\n"
1489  "void main() {\n"
1490  " gl_Position = rotation * pos;\n"
1491  " v_color = color;\n"
1492  "}\n";
1493 
1494 static const char *frag_shader_text =
1495  "precision mediump float;\n"
1496  "varying vec4 v_color;\n"
1497  "void main() {\n"
1498  " gl_FragColor = v_color;\n"
1499  "}\n";
1500 
1501 static GLuint createShader(AppCtx *ctx, GLenum shaderType, const char *shaderSource )
1502 {
1503  GLuint shader= 0;
1504  GLint shaderStatus;
1505  GLsizei length;
1506  char logText[1000];
1507 
1508  shader= glCreateShader( shaderType );
1509  if ( shader )
1510  {
1511  glShaderSource( shader, 1, (const char **)&shaderSource, NULL );
1512  glCompileShader( shader );
1513  glGetShaderiv( shader, GL_COMPILE_STATUS, &shaderStatus );
1514  if ( !shaderStatus )
1515  {
1516  glGetShaderInfoLog( shader, sizeof(logText), &length, logText );
1517  printf("Error compiling %s shader: %*s\n",
1518  ((shaderType == GL_VERTEX_SHADER) ? "vertex" : "fragment"),
1519  length,
1520  logText );
1521  }
1522  }
1523 
1524  return shader;
1525 }
1526 
1527 static bool setupGL( AppCtx *ctx )
1528 {
1529  bool result= false;
1530  GLuint frag, vert;
1531  GLuint program;
1532  GLint status;
1533 
1534  frag= createShader(ctx, GL_FRAGMENT_SHADER, frag_shader_text);
1535  vert= createShader(ctx, GL_VERTEX_SHADER, vert_shader_text);
1536 
1537  program= glCreateProgram();
1538  glAttachShader(program, frag);
1539  glAttachShader(program, vert);
1540  glLinkProgram(program);
1541 
1542  glGetProgramiv(program, GL_LINK_STATUS, &status);
1543  if (!status)
1544  {
1545  char log[1000];
1546  GLsizei len;
1547  glGetProgramInfoLog(program, 1000, &len, log);
1548  fprintf(stderr, "Error: linking:\n%*s\n", len, log);
1549  goto exit;
1550  }
1551 
1552  glUseProgram(program);
1553 
1554  ctx->gl.pos= 0;
1555  ctx->gl.col= 1;
1556 
1557  glBindAttribLocation(program, ctx->gl.pos, "pos");
1558  glBindAttribLocation(program, ctx->gl.col, "color");
1559  glLinkProgram(program);
1560 
1561  ctx->gl.rotation_uniform= glGetUniformLocation(program, "rotation");
1562 
1563 exit:
1564  return result;
1565 }
1566 
1567 static bool renderGL( AppCtx *ctx )
1568 {
1569  static const GLfloat verts[3][2] = {
1570  { -0.5, -0.5 },
1571  { 0.5, -0.5 },
1572  { 0, 0.5 }
1573  };
1574  static const GLfloat colors[3][4] = {
1575  { 1, 0, 0, 1.0 },
1576  { 0, 1, 0, 1.0 },
1577  { 0, 0, 1, 1.0 }
1578  };
1579  GLfloat angle;
1580  GLfloat rotation[4][4] = {
1581  { 1, 0, 0, 0 },
1582  { 0, 1, 0, 0 },
1583  { 0, 0, 1, 0 },
1584  { 0, 0, 0, 1 }
1585  };
1586  static const uint32_t speed_div = 5;
1587  EGLint rect[4];
1588 
1589  glViewport( 0, 0, ctx->planeWidth, ctx->planeHeight );
1590  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
1591  glClear(GL_COLOR_BUFFER_BIT);
1592 
1593  ctx->currTime= currentTimeMillis();
1594 
1595  angle = ctx->noAnimation ? 0.0 : ((ctx->currTime-ctx->startTime) / speed_div) % 360 * M_PI / 180.0;
1596  rotation[0][0] = cos(angle);
1597  rotation[0][2] = sin(angle);
1598  rotation[2][0] = -sin(angle);
1599  rotation[2][2] = cos(angle);
1600 
1601  glUniformMatrix4fv(ctx->gl.rotation_uniform, 1, GL_FALSE, (GLfloat *) rotation);
1602 
1603  glVertexAttribPointer(ctx->gl.pos, 2, GL_FLOAT, GL_FALSE, 0, verts);
1604  glVertexAttribPointer(ctx->gl.col, 4, GL_FLOAT, GL_FALSE, 0, colors);
1605  glEnableVertexAttribArray(ctx->gl.pos);
1606  glEnableVertexAttribArray(ctx->gl.col);
1607 
1608  glDrawArrays(GL_TRIANGLES, 0, 3);
1609 
1610  glDisableVertexAttribArray(ctx->gl.pos);
1611  glDisableVertexAttribArray(ctx->gl.col);
1612 
1613  GLenum err= glGetError();
1614  if ( err != GL_NO_ERROR )
1615  {
1616  printf( "renderGL: glGetError() = %X\n", err );
1617  }
1618 }
1619 
_AppCtx
Definition: rne-triangle.cpp:136