1 // LiVES - openGL playback engine
2 // (c) G. Finch 2012 - 2020 <salsaman+lives@gmail.com>
3 // (c) OpenGL effects by Antti Silvast, 2012 <antti.silvast@iki.fi>
4 // released under the GNU GPL 3 or later
5 // see file COPYING or www.gnu.org for details
6 
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <assert.h>
12 #include <errno.h>
13 
14 #include <iostream>
15 
16 #ifndef NEED_LOCAL_WEED
17 #include <weed/weed-plugin.h>
18 #include <weed/weed.h>
19 #include <weed/weed-effects.h>
20 #include <weed/weed-utils.h>
21 #else
22 #include "../../../../libweed/weed-plugin.h"
23 #include "../../../../libweed/weed.h"
24 #include "../../../../libweed/weed-effects.h"
25 #include "../../../../libweed/weed-utils.h"
26 #endif
27 
28 #define USE_LIBWEED
29 #include "videoplugin.h"
30 
31 #include "../../../weed-plugins/weed-plugin-utils.c"
32 
33 ////////////////////////////////////////////////////////////////////////////////////
34 
35 static char plugin_version[64] = "LiVES openGL playback engine version 1.2";
36 
37 static const uint16_t RGBA2RGB[8] =  {1, 0, 2, 1, 3, 2, 0, 3};
38 
39 static boolean(*play_fn)(weed_layer_t *frame, int64_t tc, weed_layer_t *ret);
40 static boolean play_frame_rgba(weed_layer_t *frame, int64_t tc, weed_layer_t *ret);
41 static boolean play_frame_unknown(weed_layer_t *frame, int64_t tc, weed_layer_t *ret);
42 
43 static int palette_list[6];
44 static int mypalette;
45 
46 static boolean inited;
47 
48 static boolean npot;
49 
50 #include <math.h> // for sin and cos
51 
52 #include <sys/time.h> // added to sync to ticks! -AS
53 #include <time.h> // added to sync to ticks! -AS
54 
55 #include <pthread.h>
56 
57 /////////////////////////////////////////////
58 #include <X11/extensions/Xrender.h>
59 #include <X11/Xatom.h>
60 
61 #include "glad_glx.h"
62 
63 //#include <GL/glu.h>
64 
65 typedef struct {
66   unsigned long flags;
67   unsigned long functions;
68   unsigned long decorations;
69   long input_mode;
70   unsigned long status;
71 } MotifWmHints, MwmHints;
72 
73 #define MWM_HINTS_FUNCTIONS     (1L << 0)
74 #define MWM_HINTS_DECORATIONS   (1L << 1)
75 
76 static Atom XA_NET_WM_STATE;
77 static Atom XA_NET_WM_STATE_ADD;
78 static Atom XA_NET_WM_STATE_MAXIMIZED_VERT;
79 static Atom XA_NET_WM_STATE_MAXIMIZED_HORZ;
80 static Atom XA_NET_WM_STATE_FULLSCREEN;
81 static Atom XA_WIN_LAYER;
82 
83 static Display *dpy;
84 
85 static Window xWin;
86 static GLXWindow glxWin;
87 static GLXContext context;
88 
89 static boolean is_direct;
90 static boolean pbo_available;
91 static boolean is_ext;
92 
93 static volatile boolean playing;
94 static volatile boolean rthread_ready;
95 static volatile boolean has_new_texture;
96 static volatile boolean return_ready;
97 
98 static volatile uint8_t *texturebuf;
99 static volatile uint8_t *retdata;
100 static volatile uint8_t *retbuf;
101 
102 static int m_WidthFS;
103 static int m_HeightFS;
104 
105 #define DEF_NBUF 1
106 #define DEF_FPS_MAX 60.
107 
108 #define SL(x) #x
109 #define SE(x) SL(x)
110 
111 static int mode = 0;
112 static int dblbuf = 1;
113 static int nbuf = DEF_NBUF;
114 static boolean fsover = FALSE;
115 static boolean use_pbo = FALSE;
116 
117 static float rquad;
118 
119 static pthread_t rthread;
120 static pthread_mutex_t rthread_mutex = PTHREAD_MUTEX_INITIALIZER;
121 static pthread_mutex_t retthread_mutex = PTHREAD_MUTEX_INITIALIZER;
122 
123 static pthread_cond_t cond;
124 static pthread_mutex_t cond_mutex;
125 
126 static void *render_thread_func(void *data);
127 
128 static boolean ready = false;
129 
WaitForNotify(Display * dpy,XEvent * event,XPointer arg)130 static boolean WaitForNotify(Display *dpy, XEvent *event, XPointer arg) {
131   return (event->type == MapNotify) && (event->xmap.window == (Window) arg);
132 }
133 
134 // size of img inside texture
135 static uint32_t imgRow;
136 static uint32_t imgWidth;
137 static uint32_t imgHeight;
138 static double x_range;
139 static double y_range;
140 
141 // size of texture
142 static  uint32_t texRow;
143 static  uint32_t texWidth;
144 static  uint32_t texHeight;
145 
146 static GLenum m_TexTarget = GL_TEXTURE_2D;
147 
148 static float tfps;
149 
150 static int num_versions = 2; // number of different weed api versions supported
151 static int api_versions[] = {131}; // array of weed api versions supported in plugin
152 static weed_plant_t *plugin_info;
153 
154 static weed_plant_t *params[7];
155 static int zmode;
156 static float zfft0;
157 static char *zsubtitles;
158 
159 typedef struct {
160   int width;
161   int height;
162   boolean fullscreen;
163   uint64_t window_id;
164   int argc;
165   char **argv;
166 } _xparms;
167 
168 static _xparms xparms;
169 
170 typedef struct {
171   int width;
172   int height;
173   uint32_t type;
174   uint32_t typesize;
175 } _texture;
176 
177 static int ntextures;
178 static int ctexture;
179 
180 static _texture *textures;
181 
182 static GLuint *texID;
183 
184 static int type;
185 static int typesize;
186 
187 //////////////////////////////////////////////
188 
glPerspective(GLdouble fovY,GLdouble aspect,GLdouble zNear,GLdouble zFar)189 static void glPerspective(GLdouble fovY, GLdouble aspect, GLdouble zNear, GLdouble zFar) {
190   GLdouble fW, fH;
191   fH = tan(fovY / 360 * M_PI) * zNear;
192   fW = fH * aspect;
193 
194   glFrustum(-fW, fW, -fH, fH, zNear, zFar);
195 }
196 
get_real_tnum(int tnum,bool do_assert)197 static int get_real_tnum(int tnum, bool do_assert) {
198   tnum = ctexture - 1 - tnum;
199   if (tnum < 0) tnum += nbuf;
200   assert(tnum >= 0);
201   if (do_assert) assert(tnum < ntextures);
202   return tnum;
203 }
204 
205 
get_texture_texID(int tnum)206 static int get_texture_texID(int tnum) {
207   tnum = get_real_tnum(tnum, FALSE);
208   return texID[tnum];
209 }
210 
211 
212 /*
213   static int get_texture_width(int tnum) {
214   tnum = get_real_tnum(tnum, TRUE);
215   return textures[tnum].width;
216   }
217 
218 
219   static int get_texture_height(int tnum) {
220   tnum = get_real_tnum(tnum, TRUE);
221   return textures[tnum].height;
222   }
223 
224 
225   static int get_texture_type(int tnum) {
226   tnum = get_real_tnum(tnum, TRUE);
227   return textures[tnum].type;
228   }
229 
230   static int get_texture_typesize(int tnum) {
231   tnum=get_real_tnum(tnum,TRUE);
232   return textures[tnum].type;
233   }
234 */
235 
236 ///////////////////////////////////////////////
237 
238 
module_check_init(void)239 const char *module_check_init(void) {
240   XInitThreads();
241 
242   pbo_available = FALSE;
243 
244   if (GL_ARB_pixel_buffer_object) {
245     pbo_available = TRUE;
246     //use_pbo=TRUE;
247   }
248 
249   play_fn = &play_frame_unknown;
250 
251   inited = false;
252 
253   mypalette = WEED_PALETTE_END;
254 
255   zsubtitles = NULL;
256   plugin_info = NULL;
257 
258   return NULL;
259 }
260 
261 
version(void)262 const char *version(void) {
263   return plugin_version;
264 }
265 
266 
get_description(void)267 const char *get_description(void) {
268   return "The openGL plugin allows faster playback.\n";
269 }
270 
271 
get_capabilities(int palette)272 uint64_t get_capabilities(int palette) {
273   return VPP_CAN_RESIZE | VPP_CAN_RETURN | VPP_LOCAL_DISPLAY | VPP_CAN_LETTERBOX | VPP_CAN_CHANGE_PALETTE;
274 }
275 
276 
get_init_rfx(int intention)277 const char *get_init_rfx(int intention) {
278   return "<define>\\n\
279 |1.7\\n		     \
280 </define>\\n	     \
281 <params>\\n								\
282 mode|_Mode|string_list|0|Normal|Triangle|Rotating|Wobbler|Landscape|Insider|Cube|Turning|Tunnel|Particles|Dissolve\\n \
283 tfps|Max render _Framerate|num2|" SE(DEF_FPS_MAX) "|1.|200.\\n		\
284 nbuf|Number of _texture buffers (ignored)|num0|" SE(DEF_NBUF) "|1|256\\n \
285 dbuf|Use _double buffering|bool|1|0\\n					\
286 fsover|Over-ride _fullscreen setting (for debugging)|bool|0|0\\n	\
287 </params>\\n								\
288 ";
289 }
290 
291 WEED_SETUP_START(200, 200) {
292   // const char *modes[] = {"Normal", "Triangle", "Rotating", "Wobbler", "Landscape", "Insider", "Cube", "Turning",
293   // 		   "Tunnel", "Particles", "Dissolve", NULL};
294 
295   // int palette_list[] = {WEED_PALETTE_RGB24, WEED_PALETTE_RGBA32, WEED_PALETTE_END};
296   // weed_plant_t *in_chantmpls[] = {weed_channel_template_init("in channel 0", 0), NULL};
297   // weed_plant_t *out_chantmpls[] = {weed_channel_template_init("out channel 0", WEED_CHANNEL_OPTIONAL), NULL};
298   // weed_plant_t *in_params[] = {weed_string_list_init("mode", "Trigger _Mode", 0, modes), NULL};
299   // //weed_string_list_init("color", "_Color", 0, patterns), NULL};
300   // weed_plant_t *filter_class = weed_filter_class_init("openGL player", "salsaman", 1, 0, palette_list, init_screen,
301   //                              play_frame, exit_screen, in_chantmpls, out_chantmpls, in_params, NULL);
302 
303   // weed_plugin_info_add_filter_class(plugin_info, filter_class);
304   // weed_plugin_set_package_version(plugin_info, package_version);
305 }
306 WEED_SETUP_END;
307 
308 
get_play_params(weed_bootstrap_f weed_boot)309 const weed_plant_t **get_play_params(weed_bootstrap_f weed_boot) {
310 
311   //   // play params
312   params[0] = weed_integer_init("mode", "Playback _mode", -1, -1, 10);
313   weed_set_int_value(weed_paramtmpl_get_gui(params[0]), "hidden", WEED_TRUE);
314 
315   params[1] = weed_float_init("fft0", "fft value 0", -1., 0., 1.);
316   weed_set_int_value(weed_paramtmpl_get_gui(params[1]), "hidden", WEED_TRUE);
317 
318   params[2] = weed_float_init("fft1", "fft value 1", -1., 0., 1.);
319   weed_set_int_value(weed_paramtmpl_get_gui(params[2]), "hidden", WEED_TRUE);
320 
321   params[3] = weed_float_init("fft2", "fft value 2", -1., 0., 1.);
322   weed_set_int_value(weed_paramtmpl_get_gui(params[3]), "hidden", WEED_TRUE);
323 
324   params[4] = weed_float_init("fft3", "fft value 3", -1., 0., 1.);
325   weed_set_int_value(weed_paramtmpl_get_gui(params[4]), "hidden", WEED_TRUE);
326 
327   params[5] = weed_text_init("subtitles", "_Subtitles", "");
328   weed_set_int_value(weed_paramtmpl_get_gui(params[5]), "hidden", WEED_TRUE);
329 
330   params[6] = NULL;
331 
332   return (const weed_plant_t **)params;
333 }
334 
335 
get_palette_list(void)336 const int *get_palette_list(void) {
337   // return palettes in order of preference, ending with WEED_PALETTE_END
338   palette_list[0] = WEED_PALETTE_RGBA32;
339   palette_list[1] = WEED_PALETTE_RGB24;
340   palette_list[2] = WEED_PALETTE_BGRA32;
341   palette_list[3] = WEED_PALETTE_BGR24;
342   palette_list[4] = WEED_PALETTE_END;
343   return palette_list;
344 }
345 
346 
get_size_for_type(int type)347 static int get_size_for_type(int type) {
348   switch (type) {
349   case GL_RGBA:
350   case GL_BGRA:
351   case GL_SRGB8_ALPHA8:
352     return 4;
353   case GL_RGB:
354   case GL_BGR:
355   case GL_SRGB8:
356     return 3;
357   default:
358     assert(0);
359   }
360 }
361 
362 
set_palette(int palette)363 boolean set_palette(int palette) {
364   pthread_mutex_lock(&rthread_mutex);
365   if (palette == WEED_PALETTE_RGBA32 || palette == WEED_PALETTE_RGB24 ||
366       palette == WEED_PALETTE_BGR24 || palette == WEED_PALETTE_ARGB32 || palette == WEED_PALETTE_BGRA32) {
367     play_fn = &play_frame_rgba;
368     mypalette = palette;
369 
370     type = GL_RGBA;
371     if (mypalette == WEED_PALETTE_RGB24 || mypalette == WEED_PALETTE_BGR24) type = GL_RGB;
372     typesize = get_size_for_type(type);
373     pthread_mutex_unlock(&rthread_mutex);
374 
375     return TRUE;
376   }
377   // invalid palette
378   pthread_mutex_unlock(&rthread_mutex);
379   return FALSE;
380 }
381 
382 
setWindowDecorations(void)383 static void setWindowDecorations(void) {
384   unsigned char *pucData;
385   int iFormat;
386   unsigned long ulItems;
387   unsigned long ulBytesAfter;
388   Atom typeAtom;
389   MotifWmHints newHints;
390 
391   Atom WM_HINTS;
392   boolean set = FALSE;
393 
394   XLockDisplay(dpy);
395   WM_HINTS = XInternAtom(dpy, "_MOTIF_WM_HINTS", True);
396   if (WM_HINTS != None) {
397     XGetWindowProperty(dpy, xWin, WM_HINTS, 0,
398                        sizeof(MotifWmHints) / sizeof(long),
399                        False, AnyPropertyType, &typeAtom,
400                        &iFormat, &ulItems, &ulBytesAfter, &pucData);
401 
402     newHints.flags = MWM_HINTS_DECORATIONS;
403     newHints.decorations = 0;
404 
405     XChangeProperty(dpy, xWin, WM_HINTS, WM_HINTS,
406                     32, PropModeReplace, (unsigned char *) &newHints,
407                     sizeof(MotifWmHints) / sizeof(long));
408 
409     set = TRUE;
410   }
411 
412   /* Now try to set KWM hints */
413   WM_HINTS = XInternAtom(dpy, "KWM_WIN_DECORATION", True);
414   if (WM_HINTS != None) {
415     long KWMHints = 0;
416 
417     XChangeProperty(dpy, xWin, WM_HINTS, WM_HINTS, 32,
418                     PropModeReplace,
419                     (unsigned char *) &KWMHints,
420                     sizeof(KWMHints) / 4);
421     set = TRUE;
422   }
423   /* Now try to set GNOME hints */
424   WM_HINTS = XInternAtom(dpy, "_WIN_HINTS", True);
425   if (WM_HINTS != None) {
426     long GNOMEHints = 0;
427 
428     XChangeProperty(dpy, xWin, WM_HINTS, WM_HINTS, 32,
429                     PropModeReplace,
430                     (unsigned char *) &GNOMEHints,
431                     sizeof(GNOMEHints) / 4);
432     set = TRUE;
433   }
434   /* Finally set the transient hints if necessary */
435   if (!set) {
436     XSetTransientForHint(dpy, xWin, RootWindow(dpy, DefaultScreen(dpy)));
437   }
438   XUnlockDisplay(dpy);
439 }
440 
441 
alwaysOnTop()442 static void alwaysOnTop() {
443   long propvalue = 12;
444   XChangeProperty(dpy, xWin, XA_WIN_LAYER, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&propvalue, 1);
445   XRaiseWindow(dpy, xWin);
446 }
447 
448 
isWindowMapped(void)449 static boolean isWindowMapped(void) {
450   XWindowAttributes attr;
451   XLockDisplay(dpy);
452   XGetWindowAttributes(dpy, xWin, &attr);
453   XUnlockDisplay(dpy);
454   if (attr.map_state != IsUnmapped) {
455     return TRUE;
456   } else {
457     return FALSE;
458   }
459 }
460 
461 
setFullScreen(void)462 static void setFullScreen(void) {
463   XWindowChanges changes;
464   unsigned int valueMask = CWX | CWY | CWWidth | CWHeight;
465 
466   setWindowDecorations();
467 
468   XA_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
469   XA_NET_WM_STATE_ADD = XInternAtom(dpy, "_NET_WM_STATE_ADD", False);
470 
471   XA_NET_WM_STATE_MAXIMIZED_VERT = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
472   XA_NET_WM_STATE_MAXIMIZED_HORZ = XInternAtom(dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
473   XA_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
474 
475   if (isWindowMapped()) {
476     XEvent e;
477 
478     memset(&e, 0, sizeof(e));
479     e.xany.type = ClientMessage;
480     e.xclient.message_type = XA_NET_WM_STATE;
481     e.xclient.format = 32;
482     e.xclient.window = xWin;
483     e.xclient.data.l[0] = XA_NET_WM_STATE_ADD;
484     e.xclient.data.l[1] = XA_NET_WM_STATE_FULLSCREEN;
485     e.xclient.data.l[3] = 0l;
486 
487     XSendEvent(dpy, RootWindow(dpy, 0), 0,
488                SubstructureNotifyMask | SubstructureRedirectMask, &e);
489   } else {
490     int count = 0;
491     Atom atoms[3];
492 
493     atoms[count++] = XA_NET_WM_STATE_FULLSCREEN;
494     atoms[count++] = XA_NET_WM_STATE_MAXIMIZED_VERT;
495     atoms[count++] = XA_NET_WM_STATE_MAXIMIZED_HORZ;
496     XChangeProperty(dpy, xWin, XA_NET_WM_STATE, XA_ATOM, 32,
497                     PropModeReplace, (unsigned char *)atoms, count);
498   }
499 
500   changes.x = 0;
501   changes.y = 0;
502   changes.width = m_WidthFS;
503   changes.height = m_HeightFS;
504   changes.stack_mode = Above;
505   valueMask |= CWStackMode;
506 
507   XMapRaised(dpy, xWin);
508   XConfigureWindow(dpy, xWin, valueMask, &changes);
509   XResizeWindow(dpy, xWin, m_WidthFS, m_HeightFS);
510 
511   alwaysOnTop();
512 }
513 
514 
buffer_free(volatile uint8_t * retbuf)515 static  uint8_t *buffer_free(volatile uint8_t *retbuf) {
516   if (!retbuf) return NULL;
517   weed_free((void *)retbuf);
518   return NULL;
519 }
520 
521 
render_to_mainmem(int type,int row,int window_width,int window_height)522 static uint8_t *render_to_mainmem(int type, int row, int window_width, int window_height) {
523   // copy GL drawing buffer to main mem
524   uint8_t *xretbuf;
525 
526   //framebuffer = xretbuf;   ??
527   // glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, framebuffer);
528   //   glFramebufferTexture2DEXT
529 
530   glPushAttrib(GL_PIXEL_MODE_BIT);
531   glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT);
532 
533   glPixelStorei(GL_PACK_ALIGNMENT, 1); // 4 ???
534   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
535   glPixelStorei(GL_UNPACK_ROW_LENGTH, row);
536 
537   if (1 || !use_pbo) {
538     xretbuf = (uint8_t *)weed_malloc(window_width * window_height * get_size_for_type(type));
539     if (!xretbuf) {
540       glPopClientAttrib();
541       glPopAttrib();
542       return NULL;
543     }
544     //glFinish();
545     glReadPixels(0, 0, window_width, window_height, type, GL_UNSIGNED_BYTE, xretbuf);
546   }
547 
548   ///   glPixelStorei (GL_PACK_ROW_LENGTH, 0);
549   //   glBindFramebufferEXT (GL_FRAMEBUFFER_EXT, 0);
550 
551   ///  check: glBindFramebufferEXT,   glFramebufferRenderbufferEXT,      glDrawBuffers.
552   ///  glBlitFramebufferEXT
553 
554   return xretbuf;
555 }
556 
next_pot(int val)557 static int next_pot(int val) {for (register int i = 2;; i *= 2) if (i >= val) return i;;}
558 
render_to_gpumem_inner(int tnum,int width,int height,int type,volatile uint8_t * texturebuf)559 static void render_to_gpumem_inner(int tnum, int width, int height, int type, volatile uint8_t *texturebuf) {
560   int mipMapLevel = 0;
561   int texID = get_texture_texID(tnum);
562   int intype = type;
563   int xwidth = width / typesize;
564   int btype = GL_UNSIGNED_BYTE;
565 
566   glEnable(m_TexTarget);
567 
568   glBindTexture(m_TexTarget, texID);
569 
570   if (mypalette == WEED_PALETTE_BGR24)
571     intype = GL_BGR;
572 
573   if (mypalette == WEED_PALETTE_BGRA32)
574     intype = GL_BGRA;
575 
576   if (mypalette == WEED_PALETTE_ARGB32) {
577     // needs testing
578     intype = GL_BGRA;
579     btype = GL_UNSIGNED_INT_8_8_8_8_REV;
580   }
581 
582   glTexImage2D(m_TexTarget, mipMapLevel, GL_RGBA, xwidth, height, 0, intype, btype,
583                (const GLvoid *)texturebuf);
584 
585   glGenerateMipmap(m_TexTarget);
586 
587   glDisable(m_TexTarget);
588 
589   tnum = get_real_tnum(tnum, FALSE);
590 
591   // textures[tnum].width = row;
592   // textures[tnum].height = height;
593   // textures[tnum].type = type;
594 }
595 
596 
init_screen(int width,int height,boolean fullscreen,uint64_t window_id,int argc,char ** argv)597 boolean init_screen(int width, int height, boolean fullscreen, uint64_t window_id, int argc, char **argv) {
598   int i;
599   int rc = 0;
600   struct timespec ts;
601 
602   if (mypalette == WEED_PALETTE_END) {
603     fprintf(stderr, "openGL plugin error: No palette was set !\n");
604     return FALSE;
605   }
606 
607   xparms.width = width;
608   xparms.height = height;
609   xparms.fullscreen = fullscreen;
610   xparms.window_id = window_id;
611   xparms.argc = argc;
612   xparms.argv = argv;
613 
614   mode = 0;
615   tfps = DEF_FPS_MAX;
616   nbuf = DEF_NBUF;
617   dblbuf = 1;
618   fsover = FALSE;
619 
620   if (argc > 0) {
621     mode = atoi(argv[0]);
622     if (argc > 1) {
623       tfps = atof(argv[1]);
624       if (argc > 2) {
625         //nbuf = atoi(argv[2]);
626         if (argc > 3) {
627           //dblbuf = atoi(argv[3]);
628           if (argc > 4) {
629             fsover = atoi(argv[4]);
630           }
631         }
632       }
633     }
634   }
635 
636   textures = (_texture *)malloc(nbuf * sizeof(_texture));
637 
638   for (i = 0; i < nbuf; i++) {
639     textures[i].width = textures[i].height = 0;
640   }
641 
642   ntextures = ctexture = 0;
643 
644   playing = TRUE;
645 
646   rthread_ready = FALSE;
647   has_new_texture = FALSE;
648   texturebuf = NULL;
649 
650   /// check for npot
651   if (GLAD_GL_ARB_texture_non_power_of_two) npot = true;
652 
653   imgRow = imgWidth = imgHeight = texRow = texWidth = texHeight = 0;
654 
655   pthread_mutex_init(&cond_mutex, NULL);
656   pthread_cond_init(&cond, NULL);
657 
658   pthread_create(&rthread, NULL, render_thread_func, &xparms);
659 
660   clock_gettime(CLOCK_REALTIME, &ts);
661   ts.tv_sec += 300;
662 
663   // wait for render thread ready
664   pthread_mutex_lock(&cond_mutex);
665   while (!rthread_ready && rc == 0) {
666     rc = pthread_cond_timedwait(&cond, &cond_mutex, &ts);
667   }
668   pthread_mutex_unlock(&cond_mutex);
669 
670   if (!playing || (rc == ETIMEDOUT && !rthread_ready)) {
671     std::cerr << "openGL plugin error: Failed to start render thread" << std::endl;
672     return FALSE;
673   }
674 
675   if (!ready) {
676     ready = true;
677     exit_screen(0, 0);
678     init_screen(width, height, fullscreen, window_id, argc, argv);
679   }
680   return TRUE;
681 }
682 
683 
init_screen_inner(int width,int height,boolean fullscreen,uint64_t window_id,int argc,char ** argv)684 static boolean init_screen_inner(int width, int height, boolean fullscreen, uint64_t window_id, int argc, char **argv) {
685   // screen size is in RGB pixels
686 
687   int renderEventBase;
688   int renderErrorBase;
689   int error;
690 
691   Cursor invisibleCursor;
692   Pixmap bitmapNoData;
693   XColor black;
694   static char noData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
695 
696   int singleBufferAttributess[] = {
697     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
698     GLX_RENDER_TYPE,   GLX_RGBA_BIT,
699     GLX_RED_SIZE,      1,			//	Request a single buffered color buffer
700     GLX_GREEN_SIZE,    1,			//	with the maximum number of color bits
701     GLX_BLUE_SIZE,     1,			//	for each component.
702     GLX_ALPHA_SIZE,    1,
703     None
704   };
705 
706   int doubleBufferAttributes[] = {
707     GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
708     GLX_RENDER_TYPE,   GLX_RGBA_BIT,
709     GLX_DOUBLEBUFFER,  True,		//	Request a double-buffered color buffer with
710     GLX_RED_SIZE,      1,			//	the maximum number of bits per component.
711     GLX_GREEN_SIZE,    1,
712     GLX_BLUE_SIZE,     1,
713     GLX_ALPHA_SIZE,    1,
714     None
715   };
716 
717   XVisualInfo          *vInfo;
718   GLXFBConfig          *fbConfigs = NULL;
719   XEvent                event;
720   XSetWindowAttributes  swa;
721   int                   swaMask;
722   int                   numReturned;
723 
724   if (fsover) fullscreen = FALSE;
725 
726   /* Open a connection to the X server */
727   dpy = XOpenDisplay(NULL);
728 
729   if (!dpy) {
730     fprintf(stderr, "Unable to open a connection to the X server\n");
731     return FALSE;
732   }
733 
734   XLockDisplay(dpy);
735   m_WidthFS = WidthOfScreen(DefaultScreenOfDisplay(dpy));
736   m_HeightFS = HeightOfScreen(DefaultScreenOfDisplay(dpy));
737 
738   XA_WIN_LAYER = XInternAtom(dpy, "_WIN_LAYER", False);
739 
740   if (!XRenderQueryExtension(dpy, &renderEventBase, &renderErrorBase)) {
741     XUnlockDisplay(dpy);
742     fprintf(stderr, "No RENDER extension found!");
743     return FALSE;
744   }
745 
746   swa.event_mask = StructureNotifyMask | ButtonPressMask | KeyPressMask | KeyReleaseMask;
747 
748   if (!inited) {
749     gladLoadGLX(dpy, DefaultScreen(dpy));
750   }
751 
752   if (window_id) {
753     XVisualInfo *xvis;
754     XVisualInfo xvtmpl;
755     XWindowAttributes attr;
756 
757     xWin = (Window) window_id;
758     XGetWindowAttributes(dpy, xWin, &attr);
759     glxWin = xWin;
760 
761     xvtmpl.visual = attr.visual;
762     xvtmpl.visualid = XVisualIDFromVisual(attr.visual);
763 
764     xvis = XGetVisualInfo(dpy, VisualIDMask, &xvtmpl, &numReturned);
765 
766     if (numReturned == 0) {
767       XUnlockDisplay(dpy);
768       fprintf(stderr, "openGL plugin error: No xvis could be set !\n");
769       return FALSE;
770     }
771 
772     context = glXCreateContext(dpy, &xvis[0], 0, GL_TRUE);
773 
774     width = attr.width;
775     height = attr.height;
776 
777     glXGetConfig(dpy, xvis, GLX_DOUBLEBUFFER, &dblbuf);
778     XFree(xvis);
779     is_ext = TRUE;
780   } else {
781     width = fullscreen ? m_WidthFS : width;
782     height = fullscreen ? m_HeightFS : height;
783 
784     if (dblbuf) {
785       /* Request a suitable framebuffer configuration - try for a double
786       ** buffered configuration first */
787       fbConfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy),
788                                     doubleBufferAttributes, &numReturned);
789 
790       if (!fbConfigs) {    /* no double buffered configs available */
791         fbConfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy),
792                                       singleBufferAttributess, &numReturned);
793         dblbuf = 0;
794       }
795     } else {
796       fbConfigs = glXChooseFBConfig(dpy, DefaultScreen(dpy),
797                                     singleBufferAttributess, &numReturned);
798       dblbuf = 0;
799     }
800 
801     if (!fbConfigs) {
802       XUnlockDisplay(dpy);
803       fprintf(stderr, "openGL plugin error: No config could be set !\n");
804       return FALSE;
805     }
806 
807     /* Create an X colormap and window with a visual matching the first
808     ** returned framebuffer config */
809     XLockDisplay(dpy);
810     vInfo = glXGetVisualFromFBConfig(dpy, fbConfigs[0]);
811 
812     if (!vInfo) {
813       XUnlockDisplay(dpy);
814       fprintf(stderr, "openGL plugin error: No vInfo could be got !\n");
815       return FALSE;
816     }
817 
818     swa.colormap = XCreateColormap(dpy, RootWindow(dpy, vInfo->screen),
819                                    vInfo->visual, AllocNone);
820 
821     if (!swa.colormap) {
822       XFree(vInfo);
823       XUnlockDisplay(dpy);
824       fprintf(stderr, "openGL plugin error: No colormap could be set !\n");
825       return FALSE;
826     }
827 
828     swaMask = CWBorderPixel | CWColormap | CWEventMask;
829 
830     swa.border_pixel = 0;
831 
832     xWin = XCreateWindow(dpy, RootWindow(dpy, vInfo->screen), 0, 0,
833                          width, height,
834                          0, vInfo->depth, InputOutput, vInfo->visual,
835                          swaMask, &swa);
836 
837     XFreeColormap(dpy, swa.colormap);
838 
839     if (fullscreen) setFullScreen();
840 
841     XMapRaised(dpy, xWin);
842     if (fullscreen) setFullScreen();
843     XIfEvent(dpy, &event, WaitForNotify, (XPointer) xWin);
844 
845     /* Create a GLX context for OpenGL rendering */
846     context = glXCreateNewContext(dpy, fbConfigs[0], GLX_RGBA_TYPE, NULL, True);
847 
848     /* Create a GLX window to associate the frame buffer configuration
849     ** with the created X window */
850     glxWin = glXCreateWindow(dpy, fbConfigs[0], xWin, NULL);
851 
852     XFree(vInfo);
853     XFree(fbConfigs);
854 
855     black.red = black.green = black.blue = 0;
856 
857     bitmapNoData = XCreateBitmapFromData(dpy, xWin, noData, 8, 8);
858     invisibleCursor = XCreatePixmapCursor(dpy, bitmapNoData, bitmapNoData,
859                                           &black, &black, 0, 0);
860     XDefineCursor(dpy, xWin, invisibleCursor);
861     XFreeCursor(dpy, invisibleCursor);
862 
863     is_ext = FALSE;
864   }
865 
866   glXMakeCurrent(dpy, glxWin, context);
867   XUnlockDisplay(dpy);
868 
869   if (!inited) {
870     gladLoadGL();
871   }
872 
873   error = glGetError();
874   if (error != GL_NO_ERROR) {
875     char const *msg;
876     if (error == GL_INVALID_ENUM)	msg = "GL_INVALID_ENUM";
877     else if (error == GL_INVALID_VALUE) msg = "GL_INVALID_VALUE";
878     else if (error ==    GL_INVALID_OPERATION) msg = "GL_INVALID_OPERATION";
879     else if (error ==    GL_STACK_OVERFLOW)	msg = "GL_STACK_OVERFLOW";
880     else if (error ==    GL_STACK_UNDERFLOW)	msg = "GL_STACK_UNDERFLOW";
881     else if (error ==    GL_OUT_OF_MEMORY)	msg = "GL_OUT_OF_MEMORY";
882     //else if( error ==    GL_INVALID_FRAMEBUFFER_OPERATION_EXT)	msg = "GL_INVALID_FRAMEBUFFER_OPERATION_EXT";
883     else msg = "Unrecognized OpenGL error";
884 
885     fprintf(stderr, "%s in %s(%d)", msg, __FILE__, __LINE__);
886     return FALSE;
887   }
888 
889   if (!inited) {
890     glShadeModel(GL_SMOOTH);
891 
892     glClearDepth(1.0f);
893     glEnable(GL_DEPTH_TEST);
894 
895     glDepthFunc(GL_LEQUAL);
896     glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
897 
898     glPixelStorei(GL_PACK_ALIGNMENT,   1);
899     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
900     glClearColor(0.0, 0.0, 0.0, 0.0);
901     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
902 
903     texID = (GLuint *)malloc(nbuf * sizeof(GLuint));
904     glGenTextures(nbuf, texID);
905   }
906 
907   inited = true;
908 
909   /* OpenGL rendering ... */
910   glClearColor(0.0, 0.0, 0.0, 0.0);
911   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
912 
913   //glFinish();
914   glFlush();
915   if (dblbuf) glXSwapBuffers(dpy, glxWin);
916 
917   glClearColor(0.0, 0.0, 0.0, 0.0);
918   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
919   glFlush();
920 
921   // type = GL_RGBA;
922   // if (mypalette == WEED_PALETTE_RGB24 || mypalette == WEED_PALETTE_BGR24) type = GL_RGB;
923 
924   //typesize = get_size_for_type(type);
925 
926   rquad = 0.;
927 
928   if (glXIsDirect(dpy, context))
929     is_direct = TRUE;
930   else
931     is_direct = FALSE;
932 
933   /*
934     XMapWindow(dpy, xWin);
935     XSync(dpy, xWin);
936     XSetInputFocus(dpy, xWin, RevertToNone, CurrentTime);
937     XSelectInput(dpy, xWin, KeyPressMask | KeyReleaseMask);
938   */
939   return TRUE;
940 }
941 
942 
set_priorities(void)943 static void set_priorities(void) {
944   // prioritise textures so the most recent ones have highest priority
945   // GL should swap oldest out memory and swap newst in memory
946 
947   float pri = 1.;
948   GLclampf *prios = (GLclampf *)malloc(nbuf * sizeof(GLclampf));
949   int idx = ctexture;
950 
951   register int i;
952 
953   for (i = 0; i < nbuf; i++) {
954     prios[i] = 0.;
955   }
956 
957   for (i = 0; i < nbuf; i++) {
958     prios[idx] = pri;
959     idx--;
960     if (idx < 0) idx += nbuf;
961     if (idx > ntextures) break;
962     pri -= 1. / (float)nbuf;
963     if (pri < 0.) pri = 0.;
964   }
965 
966   glPrioritizeTextures(nbuf, texID, prios);
967 
968   free(prios);
969 }
970 
971 
Upload(void)972 static int Upload(void) {
973   XWindowAttributes attr;
974   struct timespec now;
975 
976   int ticks;
977   int texID;
978   int window_width, window_height;
979 
980   float scalex, scaley, offs_x, offs_y;
981   double x_stretch = (double)(imgWidth * typesize) / (double)texRow;
982   double aspect;
983 
984   // scaling for particles
985   float partx, party = 2. / (float)imgHeight;
986   pthread_mutex_lock(&rthread_mutex);
987   if (has_new_texture) {
988     ctexture++;
989     if (ctexture == nbuf) ctexture = 0;
990     if (ntextures < nbuf) ntextures++;
991     has_new_texture = FALSE;
992     render_to_gpumem_inner(0, texRow, texHeight, type, texturebuf);
993     //set_priorities();
994   }
995   pthread_mutex_unlock(&rthread_mutex);
996 
997   aspect = (double)imgWidth / (double)imgHeight;
998   scalex = (float)(imgWidth * typesize) / (float)texRow;
999   scaley = (float)imgHeight / (float)texHeight;
1000   partx = 2. / (float)imgWidth;
1001   party = 2. / (float)imgHeight;
1002 
1003   //if (zmode != -1) mode = zmode;
1004 
1005   if (!return_ready && retbuf) {
1006     retbuf = buffer_free(retbuf);
1007   }
1008 
1009   texID = get_texture_texID(0);
1010 
1011   ////////////////////////////////////////////////////////////
1012   // modes
1013   XLockDisplay(dpy);
1014   XGetWindowAttributes(dpy, xWin, &attr);
1015   XUnlockDisplay(dpy);
1016 
1017   window_width = attr.width;
1018   window_height = attr.height;
1019 
1020   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1021   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1022   glViewport(0, 0, window_width, window_height);
1023 
1024   switch (mode) {
1025   case 0: {
1026     // flat:
1027     glMatrixMode(GL_PROJECTION);
1028     glOrtho(0, 1, 0, 1, -1, 1);
1029     glLoadIdentity();
1030 
1031     glMatrixMode(GL_MODELVIEW);
1032     glLoadIdentity();
1033 
1034     glEnable(m_TexTarget);
1035     glMatrixMode(GL_TEXTURE);
1036     glLoadIdentity();
1037 
1038     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
1039     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
1040 
1041     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1042     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
1043 
1044     //glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1045 
1046     // screen coords go from 0,0 -> 1,1
1047     // tex coords goes from -1, -1 to +1, +1
1048     // img coords also
1049     // texcoord: maps img -> texture
1050     // vertex: maps texture -> screen (e.g. for letterbox, we map to a smaller part of screen)
1051     glClear(GL_COLOR_BUFFER_BIT);
1052     glBindTexture(m_TexTarget, texID);
1053     glBegin(GL_QUADS);
1054     glTexCoord2d(0, 0);
1055     glVertex2d(-x_range, y_range);
1056     glTexCoord2d(0, 1);
1057     glVertex2d(-x_range, -y_range);
1058     glTexCoord2d(x_stretch, 1);
1059     glVertex2d(x_range, -y_range);
1060     glTexCoord2d(x_stretch, 0);
1061     glVertex2d(x_range, y_range);
1062     glEnd();
1063     glDisable(m_TexTarget);
1064   }
1065   break;
1066 
1067   case 1: {
1068     glMatrixMode(GL_PROJECTION);
1069     glLoadIdentity();
1070 
1071     glEnable(GL_DEPTH_TEST);
1072 
1073     glMatrixMode(GL_MODELVIEW);
1074     glLoadIdentity();
1075 
1076     glTranslatef(.0, .0, -1);
1077 
1078     glEnable(m_TexTarget);
1079     glMatrixMode(GL_TEXTURE);
1080     glLoadIdentity();
1081 
1082     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1083     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1084 
1085     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1086     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1087 
1088     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1089 
1090     glBindTexture(m_TexTarget, texID);
1091     glColor4d(1.0, 1.0, 1.0, 1.0);
1092 
1093     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1094 
1095     glBegin(GL_TRIANGLES);                      // Drawing Using Triangles
1096 
1097     glTexCoord2f(0.5 * scalex, 0.0);
1098     glVertex3f(0.0f, 1.0f, 0.0f);               // Top
1099 
1100     glTexCoord2f(0.0, scaley);
1101     glVertex3f(-1.0f, -1.0f, 0.0f);             // Bottom Left
1102 
1103     glTexCoord2f(scalex, scaley);
1104     glVertex3f(1.0f, -1.0f, 0.0f);              // Bottom Right
1105     glEnd();
1106 
1107     glTranslatef(-1.5f, 0.0f, -6.0f);
1108     glEnd();
1109 
1110     glDisable(m_TexTarget);
1111 
1112     glMatrixMode(GL_MODELVIEW);
1113     glDisable(GL_DEPTH_TEST);
1114   }
1115   break;
1116 
1117   case 2: {
1118     glMatrixMode(GL_MODELVIEW);
1119     glLoadIdentity();
1120     glTranslatef(0.0, 0.0, -1.);
1121 
1122     // rotations
1123     glMatrixMode(GL_PROJECTION);                // Select The Projection Matrix
1124     glLoadIdentity();
1125     glPerspective(45.0f, (GLdouble)window_width / (GLdouble)window_height, 0.1f, 100.0f);
1126 
1127     glRotatef(rquad, 0.0f, 0.0f, 1.0f);         // Rotate The Quad On The Z axis
1128 
1129     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1130     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1131 
1132     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1133     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1134 
1135     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1136 
1137     glBindTexture(m_TexTarget, texID);
1138 
1139     glEnable(m_TexTarget);
1140 
1141     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1142 
1143     rquad -= 0.5f;                     // Decrease The Rotation Variable For The Quad
1144 
1145     glBegin(GL_QUADS);
1146 
1147     glTexCoord2f(0.0, 0.0);
1148     glVertex3f(-1.0, 1.1, 0.0);
1149 
1150     glTexCoord2f(scalex, 0.0);
1151     glVertex3f(1.0, 1.1, 0.0);
1152 
1153     glTexCoord2f(scalex, scaley);
1154     glVertex3f(1.0, -1.0, 0.0);
1155 
1156     glTexCoord2f(0.0, scaley);
1157     glVertex3f(-1.0, -1.0, 0.0);
1158 
1159     glEnd();
1160 
1161     glDisable(m_TexTarget);
1162   }
1163   break;
1164 
1165   case 3: {
1166     // wobbler:
1167 
1168     float vx = -1.0, vy = 1.0;
1169     float tx = 0.0, ty;
1170 
1171     float vz;
1172     // time sync
1173     clock_gettime(CLOCK_MONOTONIC, &now);
1174     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1175 
1176     ty = sin(ticks * 0.001) * 0.2;
1177 
1178     glMatrixMode(GL_PROJECTION);  // use the projection mode
1179     glLoadIdentity();
1180     glPerspective(60.0, aspect, 0.01, 1135.0);
1181 
1182     glMatrixMode(GL_MODELVIEW);
1183     glLoadIdentity();
1184     glTranslatef(0.0, 0.0, -1.1);
1185 
1186     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1187     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1188 
1189     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1190     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1191 
1192     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1193 
1194     glBindTexture(m_TexTarget, texID);
1195 
1196     glEnable(m_TexTarget);
1197 
1198     glEnable(GL_DEPTH_TEST);
1199 
1200     // parameters of the wobbler grid: the larger the width and height, the more detailed the effect is
1201 #define WX 160 // grid width
1202 #define WY 160 // grid height
1203 
1204     // precalculate the gaps between grid points
1205 #define VX_PLUS (2.0/WX)
1206 #define VY_PLUS (2.0/WY)
1207 #define TX_PLUS (1.0/WX)
1208 #define TY_PLUS (1.0/WY)
1209 
1210     // parameters for the sin waves
1211 #define TSPD1 0.003 	// speed (in msec)
1212 #define XSPD1 0.01 	// speed (along grid X)
1213 #define YSPD1 0.2 	// speed (along grid Y)
1214 #define A1 0.13 	// amplitute
1215 
1216 #define TSPD2 0.004	// speed (in msec)
1217 #define XSPD2 0.15	// speed (along grid X)
1218 #define YSPD2 0.03	// speed (along grid Y)
1219 #define A2 0.04		// amplitude
1220 
1221     for (int j = 0; j < WY; j++) {
1222       vx = -1.0;
1223       tx = 0.0;
1224       for (int i = 0; i < WX; i++) {
1225         float col = 1.0 - sin(i * 0.05 + j * 0.06) * 1.0;
1226 
1227         glBegin(GL_QUADS);
1228 
1229         glColor3f(col, col, col);
1230 
1231         vz = sin(ticks * TSPD1 + i * XSPD1 + j * YSPD1) * A1 + cos(ticks * TSPD2 + i * XSPD2 + j * YSPD2) * A2;
1232         glTexCoord2f(tx * scalex, ty * scaley);
1233         glVertex3f(vx, vy, vz);
1234 
1235         vz = sin(ticks * TSPD1 + (i + 1) * XSPD1 + j * YSPD1) * A1 + cos(ticks * TSPD2 + (i + 1) * XSPD2 + j * YSPD2) * A2;
1236         col = 1.0 - sin((i + 1) * 0.05 + j * 0.06) * 1.0;
1237         glColor3f(col, col, col);
1238 
1239         glTexCoord2f((tx + TX_PLUS) * scalex, ty * scaley);
1240         glVertex3f(vx + VX_PLUS, vy, vz);
1241 
1242         vz = sin(ticks * TSPD1 + (i + 1) * XSPD1 + (j + 1) * YSPD1) * A1
1243              + cos(ticks * TSPD2 + (i + 1) * XSPD2 + (j + 1) * YSPD2) * A2;
1244         col = 1.0 - sin((i + 1) * 0.05 + (j + 1) * 0.06) * 1.0;
1245         glColor3f(col, col, col);
1246 
1247         glTexCoord2f((tx + TX_PLUS) * scalex, (ty + TY_PLUS) * scaley);
1248         glVertex3f(vx + VX_PLUS, vy - VY_PLUS, vz);
1249 
1250         vz = sin(ticks * TSPD1 + i * XSPD1 + (j + 1) * YSPD1) * A1 + cos(ticks * TSPD2 + i * XSPD2 + (j + 1) * YSPD2) * A2;
1251         col = 1.0 - sin(i * 0.05 + (j + 1) * 0.06) * 1.0;
1252         glColor3f(col, col, col);
1253 
1254         glTexCoord2f(tx * scalex, (ty + TY_PLUS) * scaley);
1255         glVertex3f(vx, vy - VY_PLUS, vz);
1256 
1257         glEnd();
1258 
1259         vx += VX_PLUS;
1260         tx += TX_PLUS;
1261       }
1262       vy -= VY_PLUS;
1263       ty += TY_PLUS;
1264     }
1265     glDisable(m_TexTarget);
1266   }
1267   break;
1268 
1269   case 4: {
1270     // time sync
1271     clock_gettime(CLOCK_MONOTONIC, &now);
1272     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1273 
1274     // landscape:
1275     glMatrixMode(GL_PROJECTION);  // use the projection mode
1276     glLoadIdentity();
1277     glPerspective(60.0, aspect, 0.01, 1135.0);
1278 
1279     glMatrixMode(GL_MODELVIEW);
1280     glLoadIdentity();
1281     glTranslatef(0.0, 0.0, -1.1);
1282 
1283     // tilt the texture to look like a landscape
1284     glRotatef(-60, 1, 0, 0);
1285     // add a little bit of rotating movement
1286     glRotatef(sin(ticks * 0.001) * 15, 0, 1, 1);
1287 
1288     glScalef(1.3, 1.0, 1.0); // make the landscape wide!
1289 
1290     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1291     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1292 
1293     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1294     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1295 
1296     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1297 
1298     glBindTexture(m_TexTarget, texID);
1299 
1300     glEnable(m_TexTarget);
1301 
1302     glEnable(GL_DEPTH_TEST);
1303 
1304     // parameters of the landscape grid: the larger the width and height, the more detailed the effect is
1305 #define WX 160 // grid width
1306 #define WY 160 // grid height
1307 
1308     // precalculate the gaps between grid points
1309 #define VX_PLUS (2.0/WX)
1310 #define VY_PLUS (2.0/WY)
1311 #define TX_PLUS (1.0/WX)
1312 #define TY_PLUS (1.0/WY)
1313 
1314     // sin wave parameters
1315 #define TSPD1 0.003     // speed (in msecs)
1316 #define XSPD1 0.01      // speed (along grid X)
1317 #define YSPD1 0.2       // speed (along grid Y)
1318 #define A12 0.04         // amplitute
1319 
1320 #define TSPD2 0.004     // speed (in msec)
1321 #define XSPD2 0.15      // speed (along grid X)
1322 #define YSPD2 0.03      // speed (along grid Y)
1323 #define A22 0.05         // amplitude
1324 
1325     float vx = -1.0, vy = 1.0;
1326     float tx = 0.0, ty = -(ticks % 4000) * 0.00025;
1327     float vz;
1328 
1329     for (int j = 0; j < WY; j++) {
1330       vx = -1.0;
1331       tx = 0.0;
1332       for (int i = 0; i < WX; i++) {
1333         float col = 1.0 - sin(i * 0.05 + j * 0.06) * 1.0;
1334 
1335         glBegin(GL_QUADS);
1336 
1337         glColor3f(col, col, col);
1338 
1339         vz = sin(ticks * TSPD1 + i * XSPD1 + j * YSPD1) * A12 + cos(ticks * TSPD2 + i * XSPD2 + j * YSPD2) * A22;
1340         glTexCoord2f(tx * scalex, ty * scaley);
1341         glVertex3f(vx, vy, vz);
1342 
1343         vz = sin(ticks * TSPD1 + (i + 1) * XSPD1 + j * YSPD1) * A12 + cos(ticks * TSPD2 + (i + 1) * XSPD2 + j * YSPD2) * A22;
1344         col = 1.0 - sin((i + 1) * 0.05 + j * 0.06) * 1.0;
1345         glColor3f(col, col, col);
1346 
1347         glTexCoord2f((tx + TX_PLUS) * scalex, ty * scaley);
1348         glVertex3f(vx + VX_PLUS, vy, vz);
1349 
1350         vz = sin(ticks * TSPD1 + (i + 1) * XSPD1 + (j + 1) * YSPD1) * A12 + cos(ticks * TSPD2 + (i + 1) * XSPD2 +
1351              (j + 1) * YSPD2) * A22;
1352         col = 1.0 - sin((i + 1) * 0.05 + (j + 1) * 0.06) * 1.0;
1353         glColor3f(col, col, col);
1354 
1355         glTexCoord2f((tx + TX_PLUS) * scalex, (ty + TY_PLUS) * scaley);
1356         glVertex3f(vx + VX_PLUS, vy - VY_PLUS, vz);
1357 
1358         vz = sin(ticks * TSPD1 + i * XSPD1 + (j + 1) * YSPD1) * A12 + cos(ticks * TSPD2 + i * XSPD2 + (j + 1) * YSPD2) * A22;
1359         col = 1.0 - sin(i * 0.05 + (j + 1) * 0.06) * 1.0;
1360         glColor3f(col, col, col);
1361 
1362         glTexCoord2f(tx * scalex, (ty + TY_PLUS) * scaley);
1363         glVertex3f(vx, vy - VY_PLUS, vz);
1364 
1365         glEnd();
1366 
1367         vx += VX_PLUS;
1368         tx += TX_PLUS;
1369       }
1370       vy -= VY_PLUS;
1371       ty += TY_PLUS;
1372     }
1373     glDisable(m_TexTarget);
1374   }
1375 
1376   break;
1377 
1378   case 5: {
1379     // insider:
1380     glMatrixMode(GL_PROJECTION);  // use the projection mode
1381     glLoadIdentity();
1382     glPerspective(60.0, aspect, 0.01, 1135.0);
1383 
1384     glMatrixMode(GL_MODELVIEW);
1385     glLoadIdentity();
1386     glTranslatef(0.0, 0.0, -1.0);
1387 
1388     // time sync
1389     clock_gettime(CLOCK_MONOTONIC, &now);
1390     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1391 
1392     // turn the cube
1393     glRotatef(ticks * 0.07, 0, 1, 0);
1394     glRotatef(ticks * 0.08, 0, 0, 1);
1395     glRotatef(ticks * 0.035, 1, 0, 0);
1396 
1397     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1398     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1399 
1400     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1401     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1402 
1403     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1404 
1405     glBindTexture(m_TexTarget, texID);
1406 
1407     glEnable(m_TexTarget);
1408 
1409     glEnable(GL_DEPTH_TEST);
1410     glEnable(GL_CULL_FACE);
1411 
1412     // draw the cube with the texture
1413     for (int i = 0; i < 6; i++) {
1414       glBegin(GL_QUADS);
1415 
1416       glTexCoord2f(0.0, 0.0);
1417       glVertex3f(-1.0, 1.0, 1.0);
1418 
1419       glTexCoord2f(scalex, 0.0);
1420       glVertex3f(1.0, 1.0, 1.0);
1421 
1422       glTexCoord2f(scalex, scaley);
1423       glVertex3f(1.0, -1.0, 1.0);
1424 
1425       glTexCoord2f(0.0, scaley);
1426       glVertex3f(-1.0, -1.0, 1.0);
1427 
1428       glEnd();
1429       if (i < 3) glRotatef(90, 0, 1, 0);
1430       else if (i == 3) glRotatef(90, 1, 0, 0);
1431       else if (i == 4) glRotatef(180, 1, 0, 0);
1432     }
1433 
1434     glDisable(m_TexTarget);
1435   }
1436 
1437   break;
1438 
1439   case 6: {
1440     // cube:
1441     // time sync
1442     clock_gettime(CLOCK_MONOTONIC, &now);
1443     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1444 
1445     glMatrixMode(GL_PROJECTION);  // use the projection mode
1446     glLoadIdentity();
1447     glPerspective(60.0, aspect, 0.01, 1135.0);
1448 
1449     glMatrixMode(GL_MODELVIEW);
1450     glLoadIdentity();
1451 
1452     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1453     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1454 
1455     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1456     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1457 
1458     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1459 
1460     glBindTexture(m_TexTarget, texID);
1461 
1462     glEnable(m_TexTarget);
1463 
1464     glEnable(GL_DEPTH_TEST);
1465 
1466     // inner + outer cube
1467     for (int k = 0; k < 2; k++) {
1468 
1469       if (k == 1) {
1470         glCullFace(GL_FRONT);
1471         glEnable(GL_CULL_FACE);
1472       }
1473 
1474       glPushMatrix();
1475       glTranslatef(0.0, 0.0, -1.0);
1476 
1477       // turn the cube
1478       glRotatef(ticks * 0.036, 0, 1, 0);
1479       glRotatef(ticks * 0.07, 0, 0, 1);
1480       glRotatef(ticks * 0.08, 1, 0, 0);
1481 
1482       glScalef(1.0 - k * 0.75, 1.0 - k * 0.75, 1.0 - k * 0.75);
1483 
1484       // draw the cube with the texture
1485       for (int i = 0; i < 6; i++) {
1486         glBegin(GL_QUADS);
1487 
1488         glTexCoord2f(0.0, 0.0);
1489         glVertex3f(-1.0, 1.0, 1.0);
1490 
1491         glTexCoord2f(scalex, 0.0);
1492         glVertex3f(1.0, 1.0, 1.0);
1493 
1494         glTexCoord2f(scalex, scaley);
1495         glVertex3f(1.0, -1.0, 1.0);
1496 
1497         glTexCoord2f(0.0, scaley);
1498         glVertex3f(-1.0, -1.0, 1.0);
1499 
1500         glEnd();
1501         if (i < 3) glRotatef(90, 0, 1, 0);
1502         else if (i == 3) glRotatef(90, 1, 0, 0);
1503         else if (i == 4) glRotatef(180, 1, 0, 0);
1504       }
1505 
1506       glPopMatrix();
1507     }
1508     glDisable(m_TexTarget);
1509     glDisable(GL_CULL_FACE);
1510     glCullFace(GL_BACK);
1511   }
1512 
1513   break;
1514 
1515   case 7: {
1516     // turning:
1517     glMatrixMode(GL_PROJECTION);  // use the projection mode
1518     glLoadIdentity();
1519     glPerspective(60.0, aspect, 0.01, 1135.0);
1520 
1521     glMatrixMode(GL_MODELVIEW);
1522     glLoadIdentity();
1523     glTranslatef(0.0, 0.0, -2.3);
1524     // time sync
1525     clock_gettime(CLOCK_MONOTONIC, &now);
1526     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1527 
1528     // turn the cube
1529     glRotatef(cos((ticks % 5000)*M_PI / 5000.0) * 45 + 45, 0, 1, 0);
1530 
1531     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1532     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1533 
1534     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1535     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1536 
1537     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
1538 
1539     glBindTexture(m_TexTarget, texID);
1540 
1541     glEnable(m_TexTarget);
1542 
1543     glEnable(GL_DEPTH_TEST);
1544     glEnable(GL_CULL_FACE);
1545     glCullFace(GL_FRONT);
1546 
1547     // draw the cube with the texture
1548     for (int i = 0; i < 6; i++) {
1549       glBegin(GL_QUADS);
1550 
1551       glTexCoord2f(0.0, 0.0);
1552       glVertex3f(-1.0, 1.0, 1.0);
1553 
1554       glTexCoord2f(scalex, 0.0);
1555       glVertex3f(1.0, 1.0, 1.0);
1556 
1557       glTexCoord2f(scalex, scaley);
1558       glVertex3f(1.0, -1.0, 1.0);
1559 
1560       glTexCoord2f(0.0, scaley);
1561       glVertex3f(-1.0, -1.0, 1.0);
1562 
1563       glEnd();
1564       if (i < 3) glRotatef(90, 0, 1, 0);
1565       else if (i == 3) glRotatef(90, 1, 0, 0);
1566       else if (i == 4) glRotatef(180, 1, 0, 0);
1567     }
1568 
1569     glDisable(m_TexTarget);
1570   }
1571 
1572   break;
1573 
1574   case 8: {
1575     // tunnel:
1576 
1577     float tx = 0.0, ty;
1578     // time sync
1579     clock_gettime(CLOCK_MONOTONIC, &now);
1580     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1581 
1582     ty = (ticks % 2000) * 0.0005;
1583 
1584     glMatrixMode(GL_PROJECTION);  // use the projection mode
1585     glLoadIdentity();
1586     glPerspective(60.0, aspect, 0.01, 1135.0);
1587 
1588     glMatrixMode(GL_MODELVIEW);
1589     glLoadIdentity();
1590     glTranslatef(0.0, 0.0, -1.0);
1591 
1592     glRotatef(5, 0, 1, 0);
1593     glRotatef(ticks * 0.05, 0, 0, 1);
1594     glRotatef(7, 1, 0, 0);
1595 
1596     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1597     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1598 
1599     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1600     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1601 
1602     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1603 
1604     glBindTexture(m_TexTarget, texID);
1605 
1606     glEnable(m_TexTarget);
1607 
1608     glEnable(GL_DEPTH_TEST);
1609 
1610     // parameters of the tunnel grid: the larger the width and height, the more detailed the effect is
1611 #define TR 160 // tunnel radius
1612 #define TD 160 // tunnel depth
1613 
1614     // size on screen
1615 #define SR 2.0 // radius
1616 #define SD 0.4 // depth factor
1617 
1618     // precalculate the gaps between grid points
1619 #define TX_PLUS2 (1.0/WX)
1620 #define TY_PLUS2 (1.0/160)
1621 
1622     for (int j = 0; j < TD; j++) {
1623       tx = 0.0;
1624       for (int i = 0; i < TR; i++) {
1625         float vx = cos(i * 2 * M_PI / TR) * SR;
1626         float vy = sin(i * 2 * M_PI / TR) * SR;
1627         float vz = -j * SD;
1628 
1629         float col = 2.0 - 2.0 * (float)j / TD;
1630 
1631         glColor3f(col, col * 0.92, col * 0.93);
1632         glBegin(GL_QUADS);
1633 
1634         glTexCoord2f(tx * scalex, ty * scaley);
1635         glVertex3f(vx, vy, vz);
1636 
1637         vx = cos((i + 1) * 2 * M_PI / TR) * SR;
1638         vy = sin((i + 1) * 2 * M_PI / TR) * SR;
1639         vz = -j * SD;
1640         glTexCoord2f((tx + TX_PLUS2) * scalex, ty * scaley);
1641         glVertex3f(vx, vy, vz);
1642 
1643         vx = cos((i + 1) * 2 * M_PI / TR) * SR;
1644         vy = sin((i + 1) * 2 * M_PI / TR) * SR;
1645         vz = -(j + 1) * SD;
1646         glTexCoord2f((tx + TX_PLUS2) * scalex, (ty + TY_PLUS2) * scaley);
1647         glVertex3f(vx, vy, vz);
1648 
1649         vx = cos(i * 2 * M_PI / TR) * SR;
1650         vy = sin(i * 2 * M_PI / TR) * SR;
1651         vz = -(j + 1) * SD;
1652         glTexCoord2f(tx * scalex, (ty + TY_PLUS2) * scaley);
1653         glVertex3f(vx, vy, vz);
1654 
1655         glEnd();
1656 
1657         tx += TX_PLUS2;
1658       }
1659       ty += TY_PLUS2;
1660     }
1661     glDisable(m_TexTarget);
1662   }
1663   break;
1664   case 9: {
1665     // particles:
1666 
1667     typedef struct {
1668       float x, y, z; 	// position coordinate
1669       float sx, sy;	// size of the particle square
1670       float vx, vy, vz; // speed
1671       float tx1, ty1, tx2, ty2; // texture position (color)
1672       int start_time; // when was created (tick)
1673       int end_time; 	// when will disappear (tick)
1674     } PARTICLE;
1675 
1676 #define NOT_CREATED -1 	// a flag for a particle that was not created
1677 #define NOF_PARTS 10000  // the number of particles
1678 #define PIXEL_SIZE (window_width / 240 > 0 ? window_width / 240 : 1)	// size of the particle pixels (1.0 = a pixel)
1679 
1680     static PARTICLE parts[NOF_PARTS]; // particle array
1681     static int parts_init = FALSE; // have been inited?
1682     // time sync
1683     clock_gettime(CLOCK_MONOTONIC, &now);
1684     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1685 
1686     if (!parts_init) {
1687       for (int i = 0; i < NOF_PARTS; i++) parts[i].start_time = NOT_CREATED;
1688       parts_init = TRUE;
1689     }
1690 
1691     glMatrixMode(GL_PROJECTION);  // use the projection mode
1692     glLoadIdentity();
1693     glPerspective(60.0, aspect, 0.01, 1135.0);
1694 
1695     glMatrixMode(GL_MODELVIEW);
1696     glLoadIdentity();
1697     glTranslatef(0.0, 0.0, -2.3);
1698 
1699     // turn the plane
1700     float rotx = sin(ticks * M_PI / 5000.0) * 5 - 15;
1701     float roty = sin(ticks * M_PI / 5000.0) * 5 + 45;
1702     float rotz = sin(ticks * M_PI / 5000.0) * 5;
1703 
1704     glRotatef(rotx, 1, 0, 0);
1705     glRotatef(roty, 0, 1, 0);
1706     glRotatef(rotz, 0, 0, 1);
1707 
1708     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1709     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1710 
1711     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1712     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1713 
1714     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1715 
1716     glBindTexture(m_TexTarget, texID);
1717 
1718     glEnable(m_TexTarget);
1719 
1720     glEnable(GL_DEPTH_TEST);
1721 
1722     // draw the emitter with the texture
1723 
1724     glBegin(GL_QUADS);
1725     glColor3f(1, 1, 1);
1726     glTexCoord2f(0.0, 0.0);
1727     glVertex3f(-1.0, 1.0, 0.0);
1728 
1729     glTexCoord2f(scalex, 0.0);
1730     glVertex3f(1.0, 1.0, 0.0);
1731 
1732     glTexCoord2f(scalex, scaley);
1733     glVertex3f(1.0, -1.0, 0.0);
1734 
1735     glTexCoord2f(0.0, scaley);
1736     glVertex3f(-1.0, -1.0, 0.0);
1737 
1738     glEnd();
1739 
1740     // draw the particles
1741 
1742     for (int i = 0; i < NOF_PARTS; i++) {
1743       //int pos;
1744       if ((parts[i].start_time == NOT_CREATED) || (ticks >= parts[i].end_time)) {
1745         parts[i].start_time = ticks;
1746         parts[i].x = (rand() % 2000) / 1000.0 - 1.0;
1747         parts[i].y = (rand() % 2000) / 1000.0 - 1.0;
1748         parts[i].z = 0.0;
1749         parts[i].vx = 0.001 * ((rand() % 2000) / 1000.0 - 1.0);
1750         parts[i].vy = 0.0;
1751         parts[i].vz = 0.01;
1752         parts[i].end_time = 4000 + parts[i].start_time + rand() % 500;
1753 
1754         parts[i].sx = PIXEL_SIZE * partx;
1755         parts[i].sy = PIXEL_SIZE * party;
1756 
1757         parts[i].tx1 = ((parts[i].x + 1.0) / 2.0);
1758         parts[i].ty1 = (1.0 - (parts[i].y + 1.0) / 2.0);
1759         parts[i].tx2 = parts[i].tx1 + parts[i].sx / 2.0;
1760         parts[i].ty2 = parts[i].ty1 + parts[i].sy / 2.0;
1761       }
1762       glBegin(GL_QUADS);
1763 
1764       glTexCoord2f(parts[i].tx1 * scalex, parts[i].ty1 * scaley);
1765       glVertex3f(parts[i].x, parts[i].y, parts[i].z);
1766 
1767       glTexCoord2f(parts[i].tx2 * scalex, parts[i].ty1 * scaley);
1768       glVertex3f(parts[i].x + parts[i].sx, parts[i].y, parts[i].z);
1769 
1770       glTexCoord2f(parts[i].tx2 * scalex, parts[i].ty2 * scaley);
1771       glVertex3f(parts[i].x + parts[i].sx, parts[i].y - parts[i].sy, parts[i].z);
1772 
1773       glTexCoord2f(parts[i].tx1 * scalex, parts[i].ty2 * scaley);
1774       glVertex3f(parts[i].x, parts[i].y - parts[i].sy, parts[i].z);
1775       glEnd();
1776 
1777       parts[i].x += parts[i].vx;
1778       parts[i].y += parts[i].vy;
1779       parts[i].z += parts[i].vz;
1780       parts[i].vy -= 0.0001; // adds a small gravity
1781     }
1782     glDisable(m_TexTarget);
1783   }
1784 
1785   break;
1786 
1787   case 10: {
1788     // dissolve:
1789 
1790     typedef struct {
1791       float x, y, z; 	// position coordinate
1792       float sx, sy;	// size of the particle square
1793       float vx, vy, vz; // speed
1794       float tx1, ty1, tx2, ty2; // texture position (color)
1795       int start_time; // when was created (tick)
1796       int end_time; 	// when will disappear (tick)
1797     } PARTICLE;
1798 
1799 #define NOT_CREATED -1 	// a flag for a particle that was not created
1800 #define NOF_PARTS2 20000  // the number of particles
1801 #define PIXEL_SIZE2 4.0	// size of the particle pixels (1.0 = a pixel)
1802 
1803     static PARTICLE parts[NOF_PARTS2]; // particle array
1804 
1805     static int parts_init = FALSE; // have been inited?
1806     // time sync
1807     clock_gettime(CLOCK_MONOTONIC, &now);
1808     ticks = now.tv_sec * 1000 + now.tv_nsec / 1000000;
1809 
1810     if (!parts_init) {
1811       for (int i = 0; i < NOF_PARTS2; i++) parts[i].start_time = NOT_CREATED;
1812       parts_init = TRUE;
1813     }
1814 
1815     float rotx, roty, rotz;
1816 
1817     glMatrixMode(GL_PROJECTION);  // use the projection mode
1818     glLoadIdentity();
1819     glPerspective(60.0, aspect, 0.01, 1135.0);
1820 
1821     glMatrixMode(GL_MODELVIEW);
1822     glLoadIdentity();
1823     glTranslatef(0.0, 0.0, -2.3);
1824 
1825     // turn the place
1826     rotx = sin(ticks * M_PI / 5000.0) * 5 + 15;
1827     roty = sin(ticks * M_PI / 5000.0) * 15 + 15;
1828     rotz = sin(ticks * M_PI / 5000.0) * 5;
1829 
1830     glRotatef(rotx, 1, 0, 0);
1831     glRotatef(roty, 0, 1, 0);
1832     glRotatef(rotz, 0, 0, 1);
1833 
1834     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1835     glTexParameteri(m_TexTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1836 
1837     glTexParameteri(m_TexTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
1838     glTexParameteri(m_TexTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
1839 
1840     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1841 
1842     glBindTexture(m_TexTarget, texID);
1843 
1844     glEnable(m_TexTarget);
1845 
1846     glEnable(GL_DEPTH_TEST);
1847 
1848     // draw the emitter with the texture
1849     /*
1850       glBegin (GL_QUADS);
1851       glColor3f(1,1,1);
1852       glTexCoord2f (0.0, 0.0);
1853       glVertex3f (-1.0, 1.0, 0.0);
1854 
1855       glTexCoord2f (1.0, 0.0);
1856       glVertex3f (1.0, 1.0, 0.0);
1857 
1858       glTexCoord2f (1.0, 1.0);
1859       glVertex3f (1.0, -1.0, 0.0);
1860 
1861       glTexCoord2f (0.0, 1.0);
1862       glVertex3f (-1.0, -1.0, 0.0);
1863 
1864       glEnd ();
1865     */
1866     // draw the squares
1867 
1868     glEnable(GL_BLEND);
1869     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1870 
1871     for (int i = 0; i < NOF_PARTS2; i++) {
1872       if ((parts[i].start_time == NOT_CREATED) || (ticks >= parts[i].end_time)) {
1873         parts[i].start_time = ticks;
1874         parts[i].x = (rand() % 2000) / 1000.0 - 1.0;
1875         parts[i].y = (rand() % 2000) / 1000.0 - 1.0;
1876         parts[i].z = 0.0;
1877         parts[i].vx = 0.001 * ((rand() % 2000) / 1000.0 - 1.0);
1878         parts[i].vy = 0.001 * ((rand() % 2000) / 1000.0 - 1.0);
1879         parts[i].vz = 0.01;
1880         parts[i].end_time = parts[i].start_time + 500 + rand() % 500;
1881 
1882         parts[i].sx = PIXEL_SIZE2 * partx;
1883         parts[i].sy = PIXEL_SIZE2 * party;
1884 
1885         parts[i].tx1 = ((parts[i].x + 1.0) / 2.0);
1886         parts[i].ty1 = (1.0 - (parts[i].y + 1.0) / 2.0);
1887         parts[i].tx2 = parts[i].tx1 + parts[i].sx / 2.0;
1888         parts[i].ty2 = parts[i].ty1 + parts[i].sy / 2.0;
1889       }
1890       glColor4f(1.0, 1.0, 1.0, 0.5 + (float)(parts[i].end_time - ticks) / (parts[i].end_time - parts[i].start_time));
1891       glBegin(GL_QUADS);
1892 
1893       glTexCoord2f(parts[i].tx1 * scalex, parts[i].ty1 * scaley);
1894       glVertex3f(parts[i].x, parts[i].y, parts[i].z);
1895 
1896       glTexCoord2f(parts[i].tx2 * scalex, parts[i].ty1 * scaley);
1897       glVertex3f(parts[i].x + parts[i].sx, parts[i].y, parts[i].z);
1898 
1899       glTexCoord2f(parts[i].tx2 * scalex, parts[i].ty2 * scaley);
1900       glVertex3f(parts[i].x + parts[i].sx, parts[i].y - parts[i].sy, parts[i].z);
1901 
1902       glTexCoord2f(parts[i].tx1 * scalex, parts[i].ty2 * scaley);
1903       glVertex3f(parts[i].x, parts[i].y - parts[i].sy, parts[i].z);
1904       glEnd();
1905 
1906       parts[i].x += parts[i].vx;
1907       parts[i].y += parts[i].vy;
1908       parts[i].z += parts[i].vz;
1909       parts[i].vy += 0.0004; // adds a small pull up
1910     }
1911     glDisable(m_TexTarget);
1912     glDisable(GL_BLEND);
1913   }
1914   break;
1915   default:
1916     break;
1917   }
1918 
1919   if (dblbuf) glXSwapBuffers(dpy, glxWin);
1920 
1921   if (retdata) {
1922     // copy buffer to retbuf
1923 
1924     pthread_mutex_lock(&retthread_mutex);
1925 
1926     if (retbuf) {
1927       buffer_free(retbuf);
1928     }
1929 
1930     retbuf = render_to_mainmem(type, imgRow, window_width, window_height);
1931     return_ready = TRUE;
1932     pthread_mutex_unlock(&retthread_mutex);
1933 
1934     // tell main thread we are ready
1935     pthread_mutex_lock(&cond_mutex);
1936     pthread_cond_signal(&cond);
1937     pthread_mutex_unlock(&cond_mutex);
1938   }
1939 
1940   // time sync
1941   clock_gettime(CLOCK_MONOTONIC, &now);
1942   return (now.tv_sec * 1000 + now.tv_nsec / 1000000 - ticks) * 1000;
1943 }
1944 
1945 
render_thread_func(void * data)1946 static void *render_thread_func(void *data) {
1947   _xparms *xparms = (_xparms *)data;
1948   int usec = 1000000. / tfps;
1949   int timetowait = usec;
1950 
1951   retbuf = NULL;
1952 
1953   init_screen_inner(xparms->width, xparms->height, xparms->fullscreen, xparms->window_id, xparms->argc, xparms->argv);
1954 
1955   rthread_ready = TRUE;
1956 
1957   pthread_mutex_lock(&cond_mutex);
1958   pthread_cond_signal(&cond);
1959   pthread_mutex_unlock(&cond_mutex);
1960 
1961   while (playing) {
1962     pthread_mutex_lock(&cond_mutex);
1963     while (!has_new_texture && playing) {
1964       pthread_cond_wait(&cond, &cond_mutex);
1965       if (!playing) {
1966         rthread_ready = FALSE;
1967         break;
1968       }
1969     }
1970     pthread_mutex_unlock(&cond_mutex);
1971     if (!playing) break;
1972     Upload();
1973   }
1974 
1975   glXMakeContextCurrent(dpy, 0, 0, 0);
1976   glXDestroyContext(dpy, context);
1977 
1978   if (retbuf) {
1979     buffer_free(retbuf);
1980   }
1981 
1982   retbuf = NULL;
1983 
1984   return NULL;
1985 }
1986 
1987 
play_frame_rgba(weed_layer_t * frame,int64_t tc,weed_layer_t * ret)1988 boolean play_frame_rgba(weed_layer_t *frame, int64_t tc, weed_layer_t *ret) {
1989   //int hsize, int vsize, int xoffs, int yoffs, int *rs, void **pixel_data, void **return_data) {
1990   // within the mutex lock we set imgWidth, imgHwight, texWidth, texHeight, texbuffer
1991   static int otypesize = typesize;
1992   /// until we get libweed-layer
1993   int hsize = weed_channel_get_width(frame);
1994   int vsize = weed_channel_get_height(frame);
1995   int row = weed_channel_get_stride(frame);
1996   int rowz, mwidth;
1997   void **return_data = NULL;
1998   void *pixel_data = weed_channel_get_pixel_data(frame);
1999   register int i;
2000 
2001   if (ret) return_data = weed_get_voidptr_array(ret, WEED_LEAF_PIXEL_DATA, NULL);
2002 
2003   pthread_mutex_lock(&rthread_mutex); // wait for lockout of render thread
2004 
2005   x_range = weed_get_double_value(frame, "x_range", NULL);
2006   y_range = weed_get_double_value(frame, "y_range", NULL);
2007 
2008   imgRow = row; // bytes
2009   imgWidth = hsize;  // pix
2010   imgHeight = vsize;
2011 
2012   rowz = (int)(imgRow / typesize) * typesize;
2013 
2014   if (!npot) {
2015     hsize = next_pot(hsize);
2016     vsize = next_pot(vsize);
2017     if (hsize * typesize > rowz) rowz = hsize * typesize;
2018   }
2019 
2020   if (rowz < imgRow) rowz = (int)((((imgRow >> 1) + typesize - 1) << 1) / typesize) * typesize;
2021 
2022 
2023   if (imgRow != texRow || imgHeight != texHeight || !texturebuf) {
2024     if (texturebuf) weed_free((void *)texturebuf);
2025     texturebuf = (uint8_t *)weed_malloc(rowz * vsize);
2026   }
2027 
2028   texRow = rowz;
2029   texWidth = hsize;
2030   texHeight = vsize;
2031 
2032   if (texRow == imgRow && texHeight >= imgHeight) {
2033     weed_memcpy((void *)texturebuf, pixel_data, imgRow * imgHeight);
2034   } else {
2035     /// !!!!! imgRow is +2 too big after first init_screen / exit_screen !!!!!
2036     for (i = 0; i < imgHeight; i++) {
2037       weed_memcpy((uint8_t *)texturebuf + i * texRow, (uint8_t *)pixel_data + i * imgRow,
2038                   imgWidth * typesize);
2039     }
2040   }
2041 
2042   if (return_data) {
2043     uint8_t *dst, *src;
2044     return_ready = FALSE;
2045     retdata = dst = (uint8_t *)return_data[0]; // host created space for return data
2046 
2047     pthread_mutex_lock(&cond_mutex);
2048     has_new_texture = TRUE;
2049     pthread_cond_signal(&cond);
2050     pthread_mutex_unlock(&cond_mutex);
2051 
2052     pthread_mutex_unlock(&rthread_mutex);
2053 
2054     pthread_mutex_lock(&cond_mutex);
2055     // wait for render thread ready
2056     while (!return_ready) {
2057       pthread_cond_wait(&cond, &cond_mutex);
2058     }
2059     pthread_mutex_unlock(&cond_mutex);
2060 
2061     if (dblbuf) {
2062       //pthread_mutex_lock(&retthread_mutex);
2063       //pthread_mutex_unlock(&rthread_mutex); // render thread - GO !
2064     }
2065 
2066     retdata = NULL;
2067 
2068     //if (texturebuf == (uint8_t *)pixel_data) texturebuf = NULL;
2069     src = (uint8_t *)retbuf + (texHeight - 1) * texWidth;
2070     mwidth = texWidth;
2071     if (mwidth > imgWidth * typesize) mwidth = imgWidth * typesize;
2072     // texture is upside-down compared to image
2073     for (i = 0; i < texHeight; i++) {
2074       weed_memcpy(dst, src, mwidth);
2075       dst += row;
2076       src -= texWidth;
2077     }
2078     weed_free(return_data);
2079   } else {
2080     retdata = NULL;
2081     pthread_mutex_unlock(&rthread_mutex); // re-enable render thread
2082     pthread_mutex_lock(&cond_mutex);
2083     has_new_texture = TRUE;
2084     pthread_cond_signal(&cond);
2085     pthread_mutex_unlock(&cond_mutex);
2086   }
2087   otypesize = typesize;
2088   return TRUE;
2089 }
2090 
2091 
play_frame_unknown(weed_layer_t * frame,int64_t tc,weed_layer_t * ret)2092 boolean play_frame_unknown(weed_layer_t *frame, int64_t tc, weed_layer_t *ret) {
2093   fprintf(stderr, "openGL plugin error: No palette was set !\n");
2094   return FALSE;
2095 }
2096 
2097 
decode_pparams(weed_plant_t ** pparams)2098 void decode_pparams(weed_plant_t **pparams) {
2099   /// not yet implemented
2100   weed_plant_t *ptmpl;
2101   char *pname;
2102   int error, type;
2103 
2104   int i = 0;
2105 
2106   zmode = 0;
2107   zfft0 = 0.;
2108   if (zsubtitles) weed_free(zsubtitles);
2109   zsubtitles = NULL;
2110 
2111   if (!pparams) return;
2112   while (pparams[i]) {
2113     type = weed_plant_get_type(pparams[i]);
2114 
2115     if (type == WEED_PLANT_PARAMETER) {
2116       ptmpl = weed_param_get_template(pparams[i]);
2117       pname = weed_get_string_value(ptmpl, "name", &error);
2118       if (pname) {
2119         if (!strcmp(pname, "mode")) {
2120           zmode = weed_get_int_value(pparams[i], "value", &error);
2121         } else if (!strcmp(pname, "fft0")) {
2122           zfft0 = (float)weed_get_double_value(pparams[i], "value", &error);
2123         } else if (!strcmp(pname, "subtitles")) {
2124           zsubtitles = weed_get_string_value(pparams[i], "value", &error);
2125         }
2126 
2127         weed_free(pname);
2128       }
2129     } else {
2130       // must be an alpha channel
2131     }
2132     i++;
2133   }
2134 }
2135 
2136 
play_frame(weed_layer_t * frame,int64_t tc,weed_layer_t * ret)2137 boolean play_frame(weed_layer_t *frame, int64_t tc, weed_layer_t *ret) {
2138   // call the function which was set in set_palette
2139   //weed_plant_t **pparams = weed_get_plantptr_array(frame, WEED_LEAF_IN_PARAMETERS, NULL);
2140   //if (pparams) decode_pparams(pparams);
2141   return play_fn(frame, tc, ret);
2142 }
2143 
2144 
exit_screen(int16_t mouse_x,int16_t mouse_y)2145 void exit_screen(int16_t mouse_x, int16_t mouse_y) {
2146   playing = FALSE;
2147 
2148   pthread_mutex_lock(&cond_mutex);
2149   /// render thread can exi when we set playing == FALSE. so we need to check for that here else we can hang in pthread_cond_signal (!)
2150   if (rthread_ready) {
2151     pthread_cond_signal(&cond);
2152     pthread_mutex_unlock(&cond_mutex);
2153     pthread_join(rthread, NULL);
2154   } else pthread_mutex_unlock(&cond_mutex);
2155 
2156   if (texturebuf) weed_free((void *)texturebuf);
2157 
2158   free(textures);
2159 
2160   XLockDisplay(dpy);
2161   if (!is_ext) {
2162     XUnmapWindow(dpy, xWin);
2163     XDestroyWindow(dpy, xWin);
2164   }
2165 
2166   XFlush(dpy);
2167 
2168   XUnlockDisplay(dpy);
2169   XCloseDisplay(dpy);
2170   dpy = NULL;
2171 
2172   pthread_mutex_destroy(&cond_mutex);
2173   pthread_cond_destroy(&cond);
2174 }
2175 
2176 
module_unload(void)2177 void module_unload(void) {
2178   if (ntextures > 0) glDeleteTextures(ntextures, texID);
2179   free(texID);
2180   if (zsubtitles != NULL) weed_free(zsubtitles);
2181 }
2182 
2183