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