Logo Search packages:      
Sourcecode: e16 version File versions  Download package

glwin.c

/*
 * Copyright (C) 2007 Kim Woelders
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
#include "E.h"
#include "desktops.h"
#include "eimage.h"
#include "eglx.h"
#include "emodule.h"
#include "eobj.h"
#include "events.h"
#include "ewins.h"
#include "grabs.h"
#include "timers.h"
#include "util.h"

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <X11/keysym.h>

#define ENABLE_DEBUG   1
#if ENABLE_DEBUG
#define Dprintf(fmt...)  do { if(EDebug(EDBUG_TYPE_GLX))Eprintf(fmt); } while(0)
#define D2printf(fmt...) do { if(EDebug(EDBUG_TYPE_GLX)>1)Eprintf(fmt); } while(0)
#else
#define Dprintf(fmt...)
#define D2printf(fmt...)
#endif /* ENABLE_DEBUG */

static struct
{
   char                mode;
} Conf_glwin;

static struct
{
   char                active;
} Mode_glwin;

typedef struct
{
   EObj               *eo;
   char                grabbing;
} GLWindow;

static void         GlwinExit(void);

static GLWindow     GLWin;
static const char  *image = "pix/about.png";

static char         light;    /* Lighting on/off */
static GLfloat      rot_x;    /* X rotation */
static GLfloat      rot_y;    /* Y rotation */
static GLfloat      speed_x;  /* X rotation speed */
static GLfloat      speed_y;  /* Y rotation speed */
static GLfloat      bg_z;     /* Background z */
static double       t0;

#define N_TEXTURES 5
static unsigned int sel_bg;
static unsigned int filter;
static ETexture    *texture[N_TEXTURES];
static int          sel_ewin;

static double
GetDTime(void)
{
   double              t, dt;

   t = GetTime();
   dt = t - t0;

   return dt;
}

static void
TexturesLoad(void)
{
   EImage             *im;

   /* Texture 0 - None */
   texture[0] = NULL;

   if (!texture[1])
     {
      im = ThemeImageLoad(image);
      if (!im)
        {
           Eprintf("Could not load: %s\n", image);
        }
      else
        {
           /* Texture 1 - Filter: None */
           texture[1] = EGlTextureFromImage(im, 0);

           /* Texture 2 - Filter: Linear */
           texture[2] = EGlTextureFromImage(im, 1);

           /* Texture 3 - Mipmap */
           texture[3] = EGlTextureFromImage(im, 2);

           EImageFree(im);
        }
     }

   if (!texture[4])
     {
      /* Texture 4 - BG pixmap */
      texture[4] =
         EGlTextureFromDrawable(DeskGetBackgroundPixmap(DesksGetCurrent()),
                          0);
     }
}

static void
SceneResize(unsigned int width, unsigned int height)
{
   Dprintf("%s\n", __func__);

   glViewport(0, 0, width, height);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glOrtho(0, width, 0, height, -1000.f, 1000.f);
   glMatrixMode(GL_MODELVIEW);
}

static GLfloat      light_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
static GLfloat      light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat      light_position[] = { 0.0f, 0.0f, 2.0f, 1.0f };

static void
SceneInitLight(void)
{
   glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
   glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
   glLightfv(GL_LIGHT1, GL_POSITION, light_position);
   glEnable(GL_LIGHT1);
}

#define L 0.0f
#define R 1.0f
#define T 0.0f
#define B 1.0f

static void
DrawBackground(ETexture * et, GLfloat w, GLfloat h)
{
   if (!et)
      return;

   glBindTexture(et->target, et->texture);

   glBegin(GL_QUADS);
   glNormal3f(0.0f, 0.0f, 1.0f);
   glTexCoord2f(L, B);
   glVertex3f(0, 0, bg_z);
   glTexCoord2f(L, T);
   glVertex3f(0, h, bg_z);
   glTexCoord2f(R, T);
   glVertex3f(w, h, bg_z);
   glTexCoord2f(R, B);
   glVertex3f(w, 0, bg_z);
   glEnd();
}

static void
DrawQube(ETexture * et, GLfloat x, GLfloat y, GLfloat z, GLfloat w, GLfloat h,
       GLfloat rx, GLfloat ry)
{
   GLfloat             w2, h2, t;

   if (!et)
      return;

   glBindTexture(et->target, et->texture);

   switch (filter)
     {
     default:
     case 0:
      glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      break;
     case 1:
      glTexParameteri(et->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
      glTexParameteri(et->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      break;
     }

   glPushMatrix();

#if 0
   x = round(x);
   y = round(y);
#endif

   glTranslatef(x, y, z);
#if 0
   glScalef(sz, sz, sz);
#endif
   glRotatef(rx, 1.0f, 0.0f, 0.0f); /* Rotate around X axis */
   glRotatef(ry, 0.0f, 1.0f, 0.0f); /* Rotate around Y axis */

   t = 4.0f;
   w2 = round(w / 2.f);
   h2 = round(h / 2.f);

#if 0
   Eprintf("%s: x,y=%.2f,%.2f wxh=%.2fx%.2f\n", __func__, x, y, w2, h2);
#endif

   glBegin(GL_QUADS);
#if 1
   /* Front */
   glNormal3f(0.0f, 0.0f, 1.0f);
   glTexCoord2f(L, B);
   glVertex3f(-w2, -h2, t);
   glTexCoord2f(R, B);
   glVertex3f(w2, -h2, t);
   glTexCoord2f(R, T);
   glVertex3f(w2, h2, t);
   glTexCoord2f(L, T);
   glVertex3f(-w2, h2, t);
#endif
#if 1
   /* Back */
   glNormal3f(0.0f, 0.0f, 1.0f);
   glTexCoord2f(L, B);
   glVertex3f(w2, -h2, -t);
   glTexCoord2f(R, B);
   glVertex3f(-w2, -h2, -t);
   glTexCoord2f(R, T);
   glVertex3f(-w2, h2, -t);
   glTexCoord2f(L, T);
   glVertex3f(w2, h2, -t);
#endif
#if 1
   /* Right */
   glNormal3f(1.0f, 0.0f, 0.0f);
   glTexCoord2f(L, B);
   glVertex3f(w2, -h2, t);
   glTexCoord2f(R, B);
   glVertex3f(w2, -h2, -t);
   glTexCoord2f(R, T);
   glVertex3f(w2, h2, -t);
   glTexCoord2f(L, T);
   glVertex3f(w2, h2, t);
#endif
#if 1
   /* Left */
   glNormal3f(-1.0f, 0.0f, 0.0f);
   glTexCoord2f(L, B);
   glVertex3f(-w2, -h2, -t);
   glTexCoord2f(R, B);
   glVertex3f(-w2, -h2, t);
   glTexCoord2f(R, T);
   glVertex3f(-w2, h2, t);
   glTexCoord2f(L, T);
   glVertex3f(-w2, h2, -t);
#endif
#if 1
   /* Top */
   glNormal3f(0.0f, 1.0f, 0.0f);
   glTexCoord2f(L, B);
   glVertex3f(w2, h2, t);
   glTexCoord2f(R, B);
   glVertex3f(w2, h2, -t);
   glTexCoord2f(R, T);
   glVertex3f(-w2, h2, -t);
   glTexCoord2f(L, T);
   glVertex3f(-w2, h2, t);
#endif
#if 1
   /* Bottom */
   glNormal3f(0.0f, -1.0f, 0.0f);
   glTexCoord2f(L, B);
   glVertex3f(w2, -h2, -t);
   glTexCoord2f(R, B);
   glVertex3f(w2, -h2, t);
   glTexCoord2f(R, T);
   glVertex3f(-w2, -h2, t);
   glTexCoord2f(L, T);
   glVertex3f(-w2, -h2, -t);
#endif
   glEnd();

   glPopMatrix();
}

static void
SceneDraw1(double t, EWin ** ewins, int num)
{
   int                 i, j, k, nx, ny;
   GLfloat             x, y, w, h, dx, dy, sz;
   EObj               *eo;

   w = EobjGetW(GLWin.eo);
   h = EobjGetH(GLWin.eo);
   w = (3 * w) / 4;

   DrawBackground(texture[sel_bg], w, h);

   i = sqrt(w * h / (1.0 * num));
   nx = (w + i - 1) / i;
   if (nx <= 0)
      nx = 1;
   ny = (num + nx - 1) / nx;
   if (ny <= 0)
      ny = 1;
#if 0
   Eprintf("wxh=%fx%f num=%d nx,ny=%d,%d\n", w, h, num, nx, ny);
#endif
   w = EobjGetW(GLWin.eo) / nx;
   h = EobjGetH(GLWin.eo) / ny;

   k = 0;
   for (j = 0; j < ny; j++)
     {
      for (i = 0; i < nx; i++)
        {
           if (k >= num)
            break;
           x = i * w;
           y = j * h;
           eo = EoObj(ewins[k++]);
           dx = 100.0f * exp(-t);
           dx = (fabs(dx) < 1.0) ? 0. : dx * sin(5. * t);
           dy = 100.0f * exp(-t);
           dy = (fabs(dy) < 1.0) ? 0. : dy * cos(5. * t);
           sz = (k == sel_ewin) ? 0.6f : 0.5f;
           DrawQube(EobjGetTexture(eo),
                  dx + (0.5f + i) * w, dy + (0.5f + j) * h, 500.0f,
                  sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
#if 1
           if (k == sel_ewin)
             {
              glColor3f(1., 0., 0.);
              glRectf(x, y, x + w, y + h);
#define X0 x
#define Y0 y
#define W w
#define H h
              glLineWidth(2.);
              glColor3f(0., 1., 0.);
              glBegin(GL_LINE_LOOP);
              glVertex3f(X0, Y0, 0);
              glVertex3f(X0 + W, Y0, 0);
              glVertex3f(X0 + W, Y0 + H, 0);
              glVertex3f(X0, Y0 + H, 0);
              glEnd();
              glColor4f(1., 1., 1., 1.);
             }
#endif
        }
     }
}

static void
SceneDraw2(double t, EWin ** ewins, int num)
{
   static double       t1;
   int                 i;
   GLfloat             w, h, dx, dy, sz, dx1, dy1;
   EObj               *eo;

   w = EobjGetW(GLWin.eo);
   h = EobjGetH(GLWin.eo);

   DrawBackground(texture[sel_bg], w, h);

   for (i = 0; i < num; i++)
     {
      dx1 = (.5 + .3 * cos(t1 + t + (i + .5) * 2. * M_PI / num)) * w;
      dy1 = (.5 - .3 * sin(t1 + t + (i + .5) * 2. * M_PI / num)) * h;

      eo = EoObj(ewins[i]);
      dx = 100.0f * exp(-t);
      dx = (fabs(dx) < 1.0) ? 0. : dx * sin(5. * t);
      dy = 100.0f * exp(-t);
      dy = (fabs(dy) < 1.0) ? 0. : dy * cos(5. * t);
      sz = (i == sel_ewin) ? .5f : 0.3f;
#if 0
      Eprintf("i=%2d dxy1=%8.3f/%8.3f  x,y=%8.3f/%8.3f\n", i,
            dx1, dy1, dx, dy);
#endif
      DrawQube(EobjGetTexture(eo), dx1 + dx, dy1 + dy, 500.0f,
             sz * EobjGetW(eo), sz * EobjGetH(eo), rot_x, rot_y);
     }
}

static EWin       **
GlwinEwins(int *pnum)
{
   int                 i, j, num;
   EWin               *const *ewins;
   EWin              **lst;

   ewins = EwinListGetAll(&num);
   lst = EMALLOC(EWin *, num);

   for (i = j = 0; i < num; i++)
     {
      if (!EoIsShown(ewins[i]))
         continue;
      lst[j++] = ewins[i];
     }
   *pnum = j;

   return lst;
}

static void
SceneDraw(void)
{
   double              t;
   EWin              **ewins;
   int                 num;

   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   glLoadIdentity();

   t = GetDTime();

   ewins = GlwinEwins(&num);

   switch (Conf_glwin.mode)
     {
     default:
      SceneDraw1(t, ewins, num);
      break;
     case 1:
      SceneDraw2(t, ewins, num);
      break;
     }

   glXSwapBuffers(disp, EobjGetXwin(GLWin.eo));

   Efree(ewins);

   rot_x += speed_x;
   rot_y += speed_y;
}

static int
GlwinRun(void *data __UNUSED__)
{
   if (!GLWin.eo)
      return 0;
   SceneDraw();
   return 1;
}

static int
GlwinKeyPress(GLWindow * gw, KeySym key)
{
   switch (key)
     {
     case XK_q:
     case XK_Escape:
      return 1;

     case XK_b:
      sel_bg += 1;
      if (sel_bg >= N_TEXTURES)
         sel_bg = 0;
      break;
     case XK_f:
      filter += 1;
      if (filter >= 2)
         filter = 0;
      break;

     case XK_g:         /* Toggle grabs */
      if (gw->grabbing)
        {
           GrabKeyboardRelease();
           gw->grabbing = 0;
        }
      else
        {
           GrabKeyboardSet(EobjGetWin(gw->eo));
           gw->grabbing = 1;
        }
      break;

     case XK_l:
      light = !light;
      if (!light)
         glDisable(GL_LIGHTING);
      else
         glEnable(GL_LIGHTING);
      break;

     case XK_R:
      bg_z = -2.0f;
      speed_x = 0.0f;
      speed_y = 0.0f;
      break;

     case XK_Page_Up:
      bg_z -= 0.10f;
      break;
     case XK_Page_Down:
      bg_z += 0.10f;
      break;

     case XK_Up:
      speed_x -= 0.10f;
      break;
     case XK_Down:
      speed_x += 0.10f;
      break;
     case XK_Right:
      speed_y += 0.10f;
      break;
     case XK_Left:
      speed_y -= 0.10f;
      break;

     case XK_m:
      Conf_glwin.mode++;
      Conf_glwin.mode %= 2;
      break;

     case XK_n:
      sel_ewin++;
      if (sel_ewin >= 5)
         sel_ewin = 0;
      break;
     case XK_p:
      sel_ewin--;
      if (sel_ewin < 0)
         sel_ewin = 4;
      break;
     }
#define TI(no) ((texture[no]) ? (int)texture[no]->texture : -1)
   Dprintf("bg=%d(%d) filter=%d l=%d  z=%.2f  spx/y=%.2f/%.2f\n",
         sel_bg, TI(sel_bg), filter, light, bg_z, speed_x, speed_y);

   return 0;
}

static void
GlwinEvent(Win win __UNUSED__, XEvent * ev, void *prm)
{
   GLWindow           *gw = (GLWindow *) prm;
   KeySym              key;
   int                 done = 0;

   switch (ev->type)
     {
     default:
      break;
     case EX_EVENT_DAMAGE_NOTIFY:
      return;
     }

   Dprintf("GlwinEvent ev %d\n", ev->type);

   switch (ev->type)
     {
     default:
      break;
     case KeyPress:
      key = XLookupKeysym(&ev->xkey, ev->xkey.state);
      done = GlwinKeyPress(gw, key);
      break;
#if 0
     case EnterNotify:
      GrabKeyboardSet(EobjGetWin(GLWin.eo));
      break;
     case LeaveNotify:
      GrabKeyboardRelease();
      break;
#endif
     case MapNotify:
      GrabKeyboardSet(EobjGetWin(GLWin.eo));
      AnimatorAdd(GlwinRun, NULL);
      break;
#if 0
     case ConfigureNotify:
      if (ev->xconfigure.width == EobjGetW(GLWin.eo) &&
          ev->xconfigure.height == EobjGetH(GLWin.eo))
         break;
      SceneResize(ev->xconfigure.width, ev->xconfigure.height);
      break;
#endif
     }

   if (done)
      GlwinExit();
}

static int
GlwinCreate(const char *title __UNUSED__, int width, int height)
{
   Win                 win;
   int                 x, y;

#if 0
   win = RRoot.win;
#else
   win = VRoot.win;
#endif
   x = ((win->w - width) / 2);
   y = ((win->h - height) / 2);

   GLWin.eo = EobjWindowCreate(EOBJ_TYPE_GLX, x, y, width, height, 0, "GLwin");
   if (!GLWin.eo)
      return -1;
   win = EobjGetWin(GLWin.eo);

   EventCallbackRegister(win, 0, GlwinEvent, &GLWin);

   ESelectInput(win, ExposureMask | KeyPressMask | ButtonPressMask |
            StructureNotifyMask);

   EGlWindowConnect(WinGetXwin(win));

   EobjMap(GLWin.eo, 1);

   t0 = GetTime();

   return 0;
}

static void
GlwinInit(void)
{
   bg_z = -2.0f;
   sel_bg = 0;
   filter = 0;
   sel_ewin = 0;
   light = 0;

   if (GlwinCreate("GLwin", 640, 480))
     {
      Eprintf("Failed to create window\n");
      return;
     }

   Mode_glwin.active = 1;

   TexturesLoad();

   SceneResize(EobjGetW(GLWin.eo), EobjGetW(GLWin.eo));

   SceneInitLight();

   glFlush();
}

static void
GlwinExit(void)
{
   if (!Mode_glwin.active)
      return;

   Dprintf("GlTestExit\n");

   if (GLWin.eo)
     {
      EventCallbackUnregister(EobjGetWin(GLWin.eo), 0, GlwinEvent, &GLWin);
      EobjUnmap(GLWin.eo);
      EobjDestroy(GLWin.eo);
      GLWin.eo = NULL;
     }

#if 0
   unsigned int        i;

   for (i = 0; i < N_TEXTURES; i++)
     {
      EGlTextureDestroy(texture[i]);
      texture[i] = NULL;
     }
#endif

   Mode_glwin.active = 0;
}

/*
 * GLwin Module
 */

static void
GlwinSighan(int sig, void *prm __UNUSED__)
{
   switch (sig)
     {
     case ESIGNAL_START:
      break;

     case ESIGNAL_EXIT:
      GlwinExit();
      break;
     }
}

static void
GlwinIpc(const char *params)
{
   const char         *cmd;

   cmd = params;

   if (!cmd)
     {
      GlwinInit();
     }
#if 0                   /* FIXME - Remove? */
   else if (!strcmp(cmd, "stop"))
     {
      GlwinExit();
     }
#endif
}

static const IpcItem GlwinIpcArray[] = {
   {
    GlwinIpc,
    "glwin", NULL,
    "Glwin functions",
    "  glwin\n"}
   ,
};
#define N_IPC_FUNCS (sizeof(GlwinIpcArray)/sizeof(IpcItem))

static const CfgItem GlwinCfgItems[] = {
   CFG_ITEM_INT(Conf_glwin, mode, 0),
};
#define N_CFG_ITEMS (sizeof(GlwinCfgItems)/sizeof(CfgItem))

/*
 * Module descriptor
 */
const EModule       ModGlwin = {
   "glwin", NULL,
   GlwinSighan,
   {N_IPC_FUNCS, GlwinIpcArray},
   {N_CFG_ITEMS, GlwinCfgItems}
};

Generated by  Doxygen 1.6.0   Back to index