summaryrefslogblamecommitdiffstats
path: root/hacks/glx/cubicgrid.c
blob: 34b6c34aed604b91d1d993ecca680343de4b2dbd (plain) (tree)












































































































































































































































































                                                                                         
/*-
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 *
 * This file is provided AS IS with no warranties of any kind.  The author
 * shall have no liability with respect to the infringement of copyrights,
 * trade secrets or any patents by this file or any part thereof.  In no
 * event will the author be liable for any lost revenue or profits or
 * other special, indirect and consequential damages.
 *
 * Cubic Grid - a 3D lattice. The observer is located in the centre of 
 * a spinning finite lattice. As it rotates, various view-throughs appear and 
 * evolve. A simple idea with interesting results.
 * 
 * Vasek Potocek (Dec-28-2007)
 * vasek.potocek@post.cz
 */

#define DEFAULTS   "*delay:         20000         \n" \
                   "*showFPS:       False         \n" \
                   "*wireframe:     False         \n" \
		   "*suppressRotationAnimation: True\n" \

# define free_cubicgrid 0
# define release_cubicgrid 0
#include "xlockmore.h"

#ifdef USE_GL

#define DEF_SPEED   "1.0"
#define DEF_DIV     "30"
#define DEF_ZOOM    "20"
#define DEF_BIGDOTS "True"

#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))

#include "rotator.h"
#include "gltrackball.h"

/*************************************************************************/

static int ticks;
static float size;
static float speed;
static Bool bigdots;

static argtype vars[] = {
  { &speed,   "speed",   "Speed",   DEF_SPEED,   t_Float },
  { &size,    "zoom",    "Zoom",    DEF_ZOOM,    t_Float },
  { &ticks,   "ticks",   "Ticks",   DEF_DIV,     t_Int },
  { &bigdots, "bigdots", "BigDots", DEF_BIGDOTS, t_Bool },
};

static XrmOptionDescRec opts[] = {
  { "-speed",   ".speed",   XrmoptionSepArg, 0 },
  { "-zoom",    ".zoom",    XrmoptionSepArg, 0 },
  { "-ticks",   ".ticks",   XrmoptionSepArg, 0 },
  { "-bigdots", ".bigdots", XrmoptionNoArg,  "True" },
  { "+bigdots", ".bigdots", XrmoptionNoArg,  "False" },
};

ENTRYPOINT ModeSpecOpt cubicgrid_opts = {countof(opts), opts, countof(vars), vars, NULL};

#ifdef USE_MODULES
ModStruct   cubicgrid_description =
{ "cubicgrid", "init_cubicgrid", "draw_cubicgrid", NULL,
  "draw_cubicgrid", "change_cubicgrid", NULL, &cubicgrid_opts,
  25000, 1, 1, 1, 1.0, 4, "",
  "Shows a rotating 3D lattice from inside", 0, NULL
};
#endif

typedef struct {
  GLXContext    *glx_context;
  GLfloat       ratio;
  GLint         list;

  rotator *rot;
  trackball_state *trackball;
  Bool button_down_p;
  int npoints;
} cubicgrid_conf;

static cubicgrid_conf *cubicgrid = NULL;

static const GLfloat zpos = -18.0;

/*************************************************************************/

ENTRYPOINT Bool
cubicgrid_handle_event (ModeInfo *mi, XEvent *event)
{
  cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];

  if (gltrackball_event_handler (event, cp->trackball,
                                 MI_WIDTH (mi), MI_HEIGHT (mi),
                                 &cp->button_down_p))
    return True;

  return False;
}


static Bool draw_main(ModeInfo *mi)
{
  cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
  double x, y, z;

  glClear(GL_COLOR_BUFFER_BIT);
  glLoadIdentity();

  glRotatef (180, 1, 0, 0);  /* Make trackball track the right way */
  glRotatef (180, 0, 1, 0);

  glTranslatef(0, 0, zpos);

  glScalef(size/ticks, size/ticks, size/ticks);


# ifdef HAVE_MOBILE	/* Keep it the same relative size when rotated. */
  {
    GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
    int o = (int) current_device_rotation();
    if (o != 0 && o != 180 && o != -180)
      glScalef (1/h, 1/h, 1);
  }
# endif

  gltrackball_rotate (cp->trackball);

  get_rotation (cp->rot, &x, &y, &z, !cp->button_down_p);
  glRotatef (-x * 360, 1.0, 0.0, 0.0);
  glRotatef (-y * 360, 0.0, 1.0, 0.0);
  glRotatef (-z * 360, 0.0, 0.0, 1.0);

  glTranslatef(-ticks/2.0, -ticks/2.0, -ticks/2.0);
  glCallList(cp->list);
  return True;
}

static void init_gl(ModeInfo *mi) 
{
  cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
  int x, y, z;
  float tf = ticks;

  glDrawBuffer(GL_BACK);
  if(bigdots) {
    glPointSize(2.0);
  }
  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  glShadeModel(GL_FLAT);

  cp->list = glGenLists(1);
  glNewList(cp->list, GL_COMPILE);
  if(MI_IS_MONO(mi)) {
    glColor3f(1.0, 1.0, 1.0);
    glBegin(GL_POINTS);
    for(x = 0; x < ticks; x++) {
      for(y = 0; y < ticks; y++) {
        for(z = 0; z < ticks; z++) {
          glVertex3f(x, y, z);
          cp->npoints++;
        }
      }
    }
    glEnd();
  }
  else
  {
    glBegin(GL_POINTS);
    for(x = 0; x < ticks; x++) {
      for(y = 0; y < ticks; y++) {
        for(z = 0; z < ticks; z++) {
          glColor3f(x/tf, y/tf, z/tf);
          glVertex3f(x, y, z);
          cp->npoints++;
        }
      }
    }
    glEnd();
  }
  glEndList();
}

/*************************************************************************/

ENTRYPOINT void reshape_cubicgrid(ModeInfo *mi, int width, int height) 
{
  cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
  int y = 0;
  if(!height) height = 1;
  cp->ratio = (GLfloat)width/(GLfloat)height;

  if (width > height * 3) {   /* tiny window: show middle */
    height = width;
    y = -height/2;
    cp->ratio = (GLfloat)width/(GLfloat)height;
  }

  glViewport(0, y, (GLint) width, (GLint) height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(30.0, cp->ratio, 1.0, 100.0);
  glMatrixMode(GL_MODELVIEW);
  glClear(GL_COLOR_BUFFER_BIT);
}

ENTRYPOINT void init_cubicgrid(ModeInfo *mi) 
{
  cubicgrid_conf *cp;
  MI_INIT(mi, cubicgrid);
  cp = &cubicgrid[MI_SCREEN(mi)];

  if ((cp->glx_context = init_GL(mi)) != NULL) {
    init_gl(mi);
    reshape_cubicgrid(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
  } else {
    MI_CLEARWINDOW(mi);
  }

  {
    double spin_speed = 0.045 * speed;
    double spin_accel = 0.005 * speed;

    cp->rot = make_rotator (spin_speed, spin_speed, spin_speed,
                            spin_accel, 0, True);
    cp->trackball = gltrackball_init (True);
  }
}

ENTRYPOINT void draw_cubicgrid(ModeInfo * mi) 
{
  Display *display = MI_DISPLAY(mi);
  Window window = MI_WINDOW(mi);
  cubicgrid_conf *cp;
  if (!cubicgrid) return;
  cp = &cubicgrid[MI_SCREEN(mi)];
  MI_IS_DRAWN(mi) = True;
  if (!cp->glx_context) return;
  glXMakeCurrent(display, window, *(cp->glx_context));
  if (!draw_main(mi)) {
    MI_ABORT(mi);
    return;
  }
  mi->polygon_count = cp->npoints;
  if (MI_IS_FPS(mi)) do_fps (mi);
  glFlush();
  glXSwapBuffers(display, window);
}

#ifndef STANDALONE
ENTRYPOINT void change_cubicgrid(ModeInfo * mi) 
{
  cubicgrid_conf *cp = &cubicgrid[MI_SCREEN(mi)];
  if (!cp->glx_context) return;
  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(cp->glx_context));
  init_gl(mi);
}
#endif /* !STANDALONE */


XSCREENSAVER_MODULE ("CubicGrid", cubicgrid)

#endif