chiark / gitweb /
Imported Upstream version 1.0.0
[e16] / src / glwin.c
1 /*
2  * Copyright (C) 2007-2008 Kim Woelders
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to
6  * deal in the Software without restriction, including without limitation the
7  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8  * sell copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies of the Software, its documentation and marketing & publicity
13  * materials, and acknowledgment shall be given in the documentation, materials
14  * and software packages that this Software was used.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19  * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #include "E.h"
24 #include "cursors.h"
25 #include "desktops.h"
26 #include "eimage.h"
27 #include "eglx.h"
28 #include "emodule.h"
29 #include "eobj.h"
30 #include "events.h"
31 #include "ewins.h"
32 #include "grabs.h"
33 #include "timers.h"
34 #include "util.h"
35
36 #include <math.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <GL/gl.h>
40 #include <GL/glu.h>
41 #include <GL/glx.h>
42 #include <X11/keysym.h>
43
44 #define ENABLE_DEBUG   1
45 #if ENABLE_DEBUG
46 #define Dprintf(fmt...)  do { if(EDebug(EDBUG_TYPE_GLX))Eprintf(fmt); } while(0)
47 #define D2printf(fmt...) do { if(EDebug(EDBUG_TYPE_GLX)>1)Eprintf(fmt); } while(0)
48 #else
49 #define Dprintf(fmt...)
50 #define D2printf(fmt...)
51 #endif /* ENABLE_DEBUG */
52
53 static struct {
54    char                mode;
55 } Conf_glwin;
56
57 static struct {
58    char                active;
59 } Mode_glwin;
60
61 typedef struct {
62    EObj               *eo;
63    char                grabbing;
64    EWin               *ewin;
65 } GLWindow;
66
67 static void         GlwinExit(void);
68
69 static GLWindow     GLWin;
70 static const char  *image = "pix/about.png";
71
72 static char         light;      /* Lighting on/off */
73 static GLfloat      rot_x;      /* X rotation */
74 static GLfloat      rot_y;      /* Y rotation */
75 static GLfloat      speed_x;    /* X rotation speed */
76 static GLfloat      speed_y;    /* Y rotation speed */
77 static GLfloat      bg_z;       /* Background z */
78 static double       t0, tn;
79
80 #define N_TEXTURES 5
81 static unsigned int sel_bg;
82 static unsigned int filter;
83 static ETexture    *texture[N_TEXTURES];
84 static int          sel_ewin;
85
86 static double
87 GetDTime(void)
88 {
89    double              t, dt;
90
91    t = GetTime();
92    dt = t - t0;
93
94    return dt;
95 }
96
97 static void
98 TexturesLoad(void)
99 {
100    EImage             *im;
101
102    /* Texture 0 - None */
103    texture[0] = NULL;
104
105    if (!texture[1])
106      {
107         im = ThemeImageLoad(image);
108         if (!im)
109           {
110              Eprintf("Could not load: %s\n", image);
111           }
112         else
113           {
114              /* Texture 1 - Filter: None */
115              texture[1] = EGlTextureFromImage(im, 0);
116
117              /* Texture 2 - Filter: Linear */
118              texture[2] = EGlTextureFromImage(im, 1);
119
120              /* Texture 3 - Mipmap */
121              texture[3] = EGlTextureFromImage(im, 2);
122
123              EImageFree(im);
124           }
125      }
126
127    if (!texture[4])
128      {
129         /* Texture 4 - BG pixmap */
130         texture[4] =
131            EGlTextureFromDrawable(DeskGetBackgroundPixmap(DesksGetCurrent()),
132                                   0);
133      }
134 }
135
136 static void
137 SceneResize(unsigned int width, unsigned int height)
138 {
139    Dprintf("SceneResize\n");
140
141    glViewport(0, 0, width, height);
142    glMatrixMode(GL_PROJECTION);
143    glLoadIdentity();
144    glOrtho(0, width, 0, height, -1000.f, 1000.f);
145    glMatrixMode(GL_MODELVIEW);
146 }
147
148 static GLfloat      light_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
149 static GLfloat      light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
150 static GLfloat      light_position[] = { 0.0f, 0.0f, 2.0f, 1.0f };
151
152 static void
153 SceneInitLight(void)
154 {
155    glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
156    glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
157    glLightfv(GL_LIGHT1, GL_POSITION, light_position);
158    glEnable(GL_LIGHT1);
159 }
160
161 #define L 0.0f
162 #define R 1.0f
163 #define T 0.0f
164 #define B 1.0f
165
166 static void
167 DrawBackground(ETexture * et, GLfloat w, GLfloat h)
168 {
169    if (!et)
170       return;
171
172    glBindTexture(et->target, et->texture);
173
174    glBegin(GL_QUADS);
175    glNormal3f(0.0f, 0.0f, 1.0f);
176    glTexCoord2f(L, B);
177    glVertex3f(0, 0, bg_z);
178    glTexCoord2f(L, T);
179    glVertex3f(0, h, bg_z);
180    glTexCoord2f(R, T);
181    glVertex3f(w, h, bg_z);
182    glTexCoord2f(R, B);
183    glVertex3f(w, 0, bg_z);
184    glEnd();
185 }
186
187 static void
188 DrawQube(ETexture * et, GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
189          GLfloat rx, GLfloat ry)
190 {
191    GLfloat             w2, h2, t;
192
193    if (!et)
194       return;
195
196    glBindTexture(et->target, et->texture);
197
198    switch (filter)
199      {
200      default:
201      case 0:
202         glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
203         glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
204         break;
205      case 1:
206         glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
207         glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
208         break;
209      }
210
211    glPushMatrix();
212
213 #if 0
214    x = round(x);
215    y = round(y);
216 #endif
217
218    glTranslatef(x, y, z);
219 #if 0
220    glScalef(sz, sz, sz);
221 #endif
222    glRotatef(rx, 1.0f, 0.0f, 0.0f);     /* Rotate around X axis */
223    glRotatef(ry, 0.0f, 1.0f, 0.0f);     /* Rotate around Y axis */
224
225    t = 4.0f;
226    w2 = round(w / 2.f);
227    h2 = round(h / 2.f);
228
229    glBegin(GL_QUADS);
230 #if 1
231    /* Front */
232    glNormal3f(0.0f, 0.0f, 1.0f);
233    glTexCoord2f(L, B);
234    glVertex3f(-w2, -h2, t);
235    glTexCoord2f(R, B);
236    glVertex3f(w2, -h2, t);
237    glTexCoord2f(R, T);
238    glVertex3f(w2, h2, t);
239    glTexCoord2f(L, T);
240    glVertex3f(-w2, h2, t);
241 #endif
242 #if 1
243    /* Back */
244    glNormal3f(0.0f, 0.0f, 1.0f);
245    glTexCoord2f(L, B);
246    glVertex3f(w2, -h2, -t);
247    glTexCoord2f(R, B);
248    glVertex3f(-w2, -h2, -t);
249    glTexCoord2f(R, T);
250    glVertex3f(-w2, h2, -t);
251    glTexCoord2f(L, T);
252    glVertex3f(w2, h2, -t);
253 #endif
254 #if 1
255    /* Right */
256    glNormal3f(1.0f, 0.0f, 0.0f);
257    glTexCoord2f(L, B);
258    glVertex3f(w2, -h2, t);
259    glTexCoord2f(R, B);
260    glVertex3f(w2, -h2, -t);
261    glTexCoord2f(R, T);
262    glVertex3f(w2, h2, -t);
263    glTexCoord2f(L, T);
264    glVertex3f(w2, h2, t);
265 #endif
266 #if 1
267    /* Left */
268    glNormal3f(-1.0f, 0.0f, 0.0f);
269    glTexCoord2f(L, B);
270    glVertex3f(-w2, -h2, -t);
271    glTexCoord2f(R, B);
272    glVertex3f(-w2, -h2, t);
273    glTexCoord2f(R, T);
274    glVertex3f(-w2, h2, t);
275    glTexCoord2f(L, T);
276    glVertex3f(-w2, h2, -t);
277 #endif
278 #if 1
279    /* Top */
280    glNormal3f(0.0f, 1.0f, 0.0f);
281    glTexCoord2f(L, B);
282    glVertex3f(w2, h2, t);
283    glTexCoord2f(R, B);
284    glVertex3f(w2, h2, -t);
285    glTexCoord2f(R, T);
286    glVertex3f(-w2, h2, -t);
287    glTexCoord2f(L, T);
288    glVertex3f(-w2, h2, t);
289 #endif
290 #if 1
291    /* Bottom */
292    glNormal3f(0.0f, -1.0f, 0.0f);
293    glTexCoord2f(L, B);
294    glVertex3f(w2, -h2, -t);
295    glTexCoord2f(R, B);
296    glVertex3f(w2, -h2, t);
297    glTexCoord2f(R, T);
298    glVertex3f(-w2, -h2, t);
299    glTexCoord2f(L, T);
300    glVertex3f(-w2, -h2, -t);
301 #endif
302    glEnd();
303
304    glPopMatrix();
305 }
306
307 static void
308 SceneDraw2(double t, EWin ** ewins, int num)
309 {
310    int                 i, j, k, nx, ny;
311    GLfloat             x, y, w, h, dx, dy, sz;
312    EObj               *eo;
313
314    w = EobjGetW(GLWin.eo);
315    h = EobjGetH(GLWin.eo);
316    w = (3 * w) / 4;
317
318    DrawBackground(texture[sel_bg], w, h);
319
320    i = sqrt(w * h / (1.0 * num));
321    nx = (w + i - 1) / i;
322    if (nx <= 0)
323       nx = 1;
324    ny = (num + nx - 1) / nx;
325    if (ny <= 0)
326       ny = 1;
327 #if 0
328    Eprintf("wxh=%fx%f num=%d nx,ny=%d,%d\n", w, h, num, nx, ny);
329 #endif
330    w = EobjGetW(GLWin.eo) / nx;
331    h = EobjGetH(GLWin.eo) / ny;
332
333    k = 0;
334    for (j = 0; j < ny; j++)
335      {
336         for (i = 0; i < nx; i++)
337           {
338              if (k >= num)
339                 break;
340              x = i * w;
341              y = j * h;
342              eo = EoObj(ewins[k]);
343              dx = 100.0f * exp(-t);
344              dx = (fabs(dx) < 1.0) ? 0. : dx * sin(5. * t);
345              dy = 100.0f * exp(-t);
346              dy = (fabs(dy) < 1.0) ? 0. : dy * cos(5. * t);
347              sz = (k == sel_ewin) ? 0.6f : 0.5f;
348              DrawQube(EobjGetTexture(eo),
349                       dx + (0.5f + i) * w, dy + (0.5f + j) * h, 500.0f,
350                       sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
351 #if 1
352              if (k == sel_ewin)
353                {
354                   glColor3f(1., 0., 0.);
355                   glRectf(x, y, x + w, y + h);
356 #define X0 x
357 #define Y0 y
358 #define W w
359 #define H h
360                   glLineWidth(2.);
361                   glColor3f(0., 1., 0.);
362                   glBegin(GL_LINE_LOOP);
363                   glVertex3f(X0, Y0, 0);
364                   glVertex3f(X0 + W, Y0, 0);
365                   glVertex3f(X0 + W, Y0 + H, 0);
366                   glVertex3f(X0, Y0 + H, 0);
367                   glEnd();
368                   glColor4f(1., 1., 1., 1.);
369                }
370 #endif
371              k++;
372           }
373      }
374 }
375
376 static void
377 SceneDraw1(double t, EWin ** ewins, int num)
378 {
379    double              t1, arg;
380    int                 i;
381    GLfloat             w, h, dx, dy, sz;
382    EObj               *eo;
383
384    w = EobjGetW(GLWin.eo);
385    h = EobjGetH(GLWin.eo);
386
387    t1 = 2 * M_PI * (-exp(-(20. * (t - tn))) / num);
388
389    DrawBackground(texture[sel_bg], w, h);
390
391    for (i = 0; i < num; i++)
392      {
393         arg = t1 + M_PI / 2. - (i - sel_ewin) * 2. * M_PI / num;
394         dx = (.5 + .3 * cos(arg)) * w;
395         dy = (.5 - .3 * sin(arg)) * h;
396
397         eo = EoObj(ewins[i]);
398         if (i == sel_ewin)
399            sz = 0.5 + .01 * cos(10. * (t - tn));
400         else
401            sz = 0.3;
402         DrawQube(EobjGetTexture(eo), dx, dy, 500.0,
403                  sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
404      }
405 }
406
407 static EWin       **
408 GlwinEwins(int *pnum)
409 {
410    int                 i, j, num;
411    EWin               *const *ewins;
412    EWin              **lst, *ewin;
413
414    ewins = EwinListGetAll(&num);
415    lst = EMALLOC(EWin *, num);
416
417    for (i = j = 0; i < num; i++)
418      {
419         ewin = ewins[i];
420         if (!EoIsShown(ewin))
421            continue;
422         if (ewin->props.skip_focuslist || ewin->props.skip_ext_task)
423            continue;
424         lst[j++] = ewin;
425      }
426    *pnum = j;
427
428    return lst;
429 }
430
431 static void
432 SceneDraw(void)
433 {
434    double              t;
435    EWin              **ewins;
436    int                 num;
437
438    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
439    glLoadIdentity();
440
441    t = GetDTime();
442
443    ewins = GlwinEwins(&num);
444    if (sel_ewin < 0)
445       sel_ewin = num - 1;
446    else if (sel_ewin >= num)
447       sel_ewin = 0;
448    GLWin.ewin = ewins[sel_ewin];
449
450    switch (Conf_glwin.mode)
451      {
452      default:
453         SceneDraw1(t, ewins, num);
454         break;
455      case 1:
456         SceneDraw2(t, ewins, num);
457         break;
458      }
459
460    glXSwapBuffers(disp, EobjGetXwin(GLWin.eo));
461
462    Efree(ewins);
463
464    rot_x += speed_x;
465    rot_y += speed_y;
466 }
467
468 static int
469 GlwinRun(void *data __UNUSED__)
470 {
471    if (!GLWin.eo)
472       return 0;
473    SceneDraw();
474    return 1;
475 }
476
477 static int
478 GlwinKeyPress(GLWindow * gw, KeySym key)
479 {
480    switch (key)
481      {
482      case XK_q:
483      case XK_Escape:
484         return 1;
485
486      case XK_b:
487         sel_bg += 1;
488         if (sel_bg >= N_TEXTURES)
489            sel_bg = 0;
490         break;
491      case XK_f:
492         filter += 1;
493         if (filter >= 2)
494            filter = 0;
495         break;
496
497      case XK_g:         /* Toggle grabs */
498         if (gw->grabbing)
499           {
500              GrabPointerRelease();
501              GrabKeyboardRelease();
502              gw->grabbing = 0;
503           }
504         else
505           {
506              GrabPointerSet(EobjGetWin(gw->eo), ECSR_GRAB, 0);
507              GrabKeyboardSet(EobjGetWin(gw->eo));
508              gw->grabbing = 1;
509           }
510         break;
511
512      case XK_l:
513         light = !light;
514         if (!light)
515            glDisable(GL_LIGHTING);
516         else
517            glEnable(GL_LIGHTING);
518         break;
519
520      case XK_R:
521         bg_z = -2.0f;
522         speed_x = 0.0f;
523         speed_y = 0.0f;
524         break;
525
526      case XK_Page_Up:
527         bg_z -= 0.10f;
528         break;
529      case XK_Page_Down:
530         bg_z += 0.10f;
531         break;
532
533      case XK_Up:
534         speed_x -= 0.10f;
535         break;
536      case XK_Down:
537         speed_x += 0.10f;
538         break;
539      case XK_Right:
540         speed_y += 0.10f;
541         break;
542      case XK_Left:
543         speed_y -= 0.10f;
544         break;
545
546      case XK_m:
547         Conf_glwin.mode++;
548         Conf_glwin.mode %= 2;
549         break;
550
551      case XK_n:
552      case XK_Tab:
553         sel_ewin++;
554         tn = GetDTime();
555         break;
556      case XK_p:
557         sel_ewin--;
558         break;
559
560      case XK_Return:
561         if (!gw->ewin)
562           {
563              Eprintf("No win\n");
564              break;
565           }
566         EwinOpActivate(gw->ewin, OPSRC_USER, Conf.warplist.raise_on_select);
567         return 1;
568      }
569 #define TI(no) ((texture[no]) ? (int)texture[no]->texture : -1)
570    Dprintf("bg=%d(%d) filter=%d l=%d  z=%.2f  spx/y=%.2f/%.2f\n",
571            sel_bg, TI(sel_bg), filter, light, bg_z, speed_x, speed_y);
572
573    return 0;
574 }
575
576 static void
577 GlwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
578 {
579    GLWindow           *gw = (GLWindow *) prm;
580    KeySym              key;
581    int                 done = 0;
582
583    switch (ev->type)
584      {
585      default:
586         break;
587      case EX_EVENT_DAMAGE_NOTIFY:
588         return;
589      }
590
591    Dprintf("GlwinEvent ev %d\n", ev->type);
592
593    switch (ev->type)
594      {
595      default:
596         break;
597      case KeyPress:
598         key = XLookupKeysym(&ev->xkey, ev->xkey.state);
599         done = GlwinKeyPress(gw, key);
600         break;
601 #if 0
602      case EnterNotify:
603         GrabKeyboardSet(EobjGetWin(GLWin.eo));
604         break;
605      case LeaveNotify:
606         GrabKeyboardRelease();
607         break;
608 #endif
609      case MapNotify:
610         GlwinKeyPress(gw, XK_g);
611         AnimatorAdd(GlwinRun, NULL);
612         break;
613 #if 0
614      case ConfigureNotify:
615         if (ev->xconfigure.width == EobjGetW(GLWin.eo) &&
616             ev->xconfigure.height == EobjGetH(GLWin.eo))
617            break;
618         SceneResize(ev->xconfigure.width, ev->xconfigure.height);
619         break;
620 #endif
621      }
622
623    if (done)
624       GlwinExit();
625 }
626
627 static int
628 GlwinCreate(const char *title __UNUSED__, int width, int height)
629 {
630    Win                 win;
631    int                 x, y;
632
633 #if 0
634    win = RROOT;
635 #else
636    win = VROOT;
637 #endif
638    x = ((win->w - width) / 2);
639    y = ((win->h - height) / 2);
640
641    GLWin.eo = EobjWindowCreate(EOBJ_TYPE_GLX, x, y, width, height, 0, "GLwin");
642    if (!GLWin.eo)
643       return -1;
644    win = EobjGetWin(GLWin.eo);
645    GLWin.eo->fade = GLWin.eo->shadow = 1;
646
647    EventCallbackRegister(win, 0, GlwinEvent, &GLWin);
648
649    ESelectInput(win, ExposureMask | KeyPressMask | ButtonPressMask |
650                 StructureNotifyMask);
651
652    EGlWindowConnect(WinGetXwin(win));
653
654    GLWin.grabbing = 0;
655    GLWin.ewin = NULL;
656
657    EobjMap(GLWin.eo, 1);
658
659    t0 = GetTime();
660    tn = -1e6;
661
662    return 0;
663 }
664
665 static void
666 GlwinInit(void)
667 {
668    bg_z = -2.0f;
669    sel_bg = 0;
670    filter = 0;
671    sel_ewin = 0;
672    light = 0;
673
674    if (GlwinCreate("GLwin", 640, 480))
675      {
676         Eprintf("Failed to create window\n");
677         return;
678      }
679
680    Mode_glwin.active = 1;
681
682    TexturesLoad();
683
684    SceneResize(EobjGetW(GLWin.eo), EobjGetW(GLWin.eo));
685
686    SceneInitLight();
687
688    glFlush();
689 }
690
691 static void
692 GlwinExit(void)
693 {
694    if (!Mode_glwin.active)
695       return;
696
697    Dprintf("GlTestExit\n");
698
699    if (GLWin.eo)
700      {
701         EventCallbackUnregister(EobjGetWin(GLWin.eo), 0, GlwinEvent, &GLWin);
702         EobjUnmap(GLWin.eo);
703         EobjDestroy(GLWin.eo);
704         GLWin.eo = NULL;
705      }
706
707 #if 0
708    unsigned int        i;
709
710    for (i = 0; i < N_TEXTURES; i++)
711      {
712         EGlTextureDestroy(texture[i]);
713         texture[i] = NULL;
714      }
715 #endif
716
717    Mode_glwin.active = 0;
718 }
719
720 /*
721  * GLwin Module
722  */
723
724 static void
725 GlwinSighan(int sig, void *prm __UNUSED__)
726 {
727    switch (sig)
728      {
729      case ESIGNAL_START:
730         break;
731
732      case ESIGNAL_EXIT:
733         GlwinExit();
734         break;
735      }
736 }
737
738 static void
739 GlwinIpc(const char *params)
740 {
741    const char         *cmd;
742
743    cmd = params;
744
745    if (!cmd)
746      {
747         GlwinInit();
748      }
749 }
750
751 static const IpcItem GlwinIpcArray[] = {
752    {
753     GlwinIpc,
754     "glwin", NULL,
755     "Glwin functions",
756     "  glwin\n"}
757    ,
758 };
759 #define N_IPC_FUNCS (sizeof(GlwinIpcArray)/sizeof(IpcItem))
760
761 static const CfgItem GlwinCfgItems[] = {
762    CFG_ITEM_INT(Conf_glwin, mode, 0),
763 };
764 #define N_CFG_ITEMS (sizeof(GlwinCfgItems)/sizeof(CfgItem))
765
766 /*
767  * Module descriptor
768  */
769 const EModule       ModGlwin = {
770    "glwin", NULL,
771    GlwinSighan,
772    {N_IPC_FUNCS, GlwinIpcArray},
773    {N_CFG_ITEMS, GlwinCfgItems}
774 };