Пример #1
0
/* Compute a 4D rotation matrix from two unit quaternions. */
static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
{
  double al, be, de, ze, et, th;
  double r00, r01, r02, r12, r22;

  r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
  r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
  r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
  r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
  r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);

  al = atan2(-r12,r22)*180.0/M_PI;
  be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
  de = atan2(-r01,r00)*180.0/M_PI;

  r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
  r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
  r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
  r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
  r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);

  et = atan2(-r12,r22)*180.0/M_PI;
  th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
  ze = atan2(-r01,r00)*180.0/M_PI;

  rotateall(al,be,de,ze,et,-th,m);
}
Пример #2
0
/* Draw a hypertorus projected into 3D.  Note that the spirals appearance
   will only work correctly if numu and numv are set to 64 or any higher
   power of 2.  Similarly, the banded appearance will only work correctly
   if numu and numv are divisible by 4. */
static int hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
                       double vmax, int numu, int numv)
{
  int polys = 0;
  static const GLfloat mat_diff_red[]         = { 1.0, 0.0, 0.0, 1.0 };
  static const GLfloat mat_diff_green[]       = { 0.0, 1.0, 0.0, 1.0 };
  static const GLfloat mat_diff_trans_red[]   = { 1.0, 0.0, 0.0, 0.7 };
  static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
  float p[3], pu[3], pv[3], n[3], mat[4][4];
  int i, j, k, l, m, b, skew;
  double u, v, ur, vr;
  double cu, su, cv, sv;
  double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
  double r, s, t;
  float q1[4], q2[4], r1[4][4], r2[4][4];
  hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];

  rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);

  gltrackball_get_quaternion(hp->trackballs[0],q1);
  gltrackball_get_quaternion(hp->trackballs[1],q2);
  quats_to_rotmat(q1,q2,r2);

  mult_rotmat(r2,r1,mat);

  if (colors != COLORS_COLORWHEEL)
  {
    glColor3fv(mat_diff_red);
    if (display_mode == DISP_TRANSPARENT)
    {
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
    }
    else
    {
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
    }
  }

#if 0 /* #### not working */
# 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/h);
  }
# endif
#endif

  skew = num_spirals;
  ur = umax-umin;
  vr = vmax-vmin;
  for (i=0; i<numu; i++)
  {
    if ((appearance == APPEARANCE_BANDS ||
         appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
      continue;
    if (display_mode == DISP_WIREFRAME)
      glBegin(GL_QUAD_STRIP);
    else
      glBegin(GL_TRIANGLE_STRIP);
    for (j=0; j<=numv; j++)
    {
      for (k=0; k<=1; k++)
      {
        l = (i+k);
        m = j;
        u = ur*l/numu+umin;
        v = vr*m/numv+vmin;
        if (appearance == APPEARANCE_SPIRALS)
        {
          u += 4.0*skew/numv*v;
          b = ((i/4)&(skew-1))*(numu/(4*skew));
          color(ur*4*b/numu+umin);
        }
        else
        {
          color(u);
        }
        cu = cos(u);
        su = sin(u);
        cv = cos(v);
        sv = sin(v);
        xx[0] = cu;
        xx[1] = su;
        xx[2] = cv;
        xx[3] = sv;
        xxu[0] = -su;
        xxu[1] = cu;
        xxu[2] = 0.0;
        xxu[3] = 0.0;
        xxv[0] = 0.0;
        xxv[1] = 0.0;
        xxv[2] = -sv;
        xxv[3] = cv;
        for (l=0; l<4; l++)
        {
          r = 0.0;
          s = 0.0;
          t = 0.0;
          for (m=0; m<4; m++)
          {
            r += mat[l][m]*xx[m];
            s += mat[l][m]*xxu[m];
            t += mat[l][m]*xxv[m];
          }
          x[l] = r;
          xu[l] = s;
          xv[l] = t;
        }
        if (projection_4d == DISP_4D_ORTHOGRAPHIC)
        {
          for (l=0; l<3; l++)
          {
            p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
            pu[l] = xu[l];
            pv[l] = xv[l];
          }
        }
        else
        {
          s = x[3]+offset4d[3];
          t = s*s;
          for (l=0; l<3; l++)
          {
            r = x[l]+offset4d[l];
            p[l] = r/s+offset3d[l];
            pu[l] = (xu[l]*s-r*xu[3])/t;
            pv[l] = (xv[l]*s-r*xv[3])/t;
          }
        }
        n[0] = pu[1]*pv[2]-pu[2]*pv[1];
        n[1] = pu[2]*pv[0]-pu[0]*pv[2];
        n[2] = pu[0]*pv[1]-pu[1]*pv[0];
        t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
        n[0] /= t;
        n[1] /= t;
        n[2] /= t;
        glNormal3fv(n);
        glVertex3fv(p);
        polys++;
      }
    }
    glEnd();
  }
  polys /= 2;
  return polys;
}
Пример #3
0
/* Draw a 4d embedding of the projective plane projected into 3D. */
static int projective_plane(ModeInfo *mi, double umin, double umax,
                            double vmin, double vmax)
{
  int polys = 0;
  static const GLfloat mat_diff_red[]         = { 1.0, 0.0, 0.0, 1.0 };
  static const GLfloat mat_diff_green[]       = { 0.0, 1.0, 0.0, 1.0 };
  static const GLfloat mat_diff_trans_red[]   = { 1.0, 0.0, 0.0, 0.7 };
  static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
  float p[3], pu[3], pv[3], pm[3], n[3], b[3], mat[4][4];
  int i, j, k, l, m, o;
  double u, v;
  double xx[4], xxu[4], xxv[4], y[4], yu[4], yv[4];
  double q, r, s, t;
  double cu, su, cv2, sv2, cv4, sv4, c2u, s2u;
  float q1[4], q2[4], r1[4][4], r2[4][4];
  projectiveplanestruct *pp = &projectiveplane[MI_SCREEN(mi)];

  if (view == VIEW_WALK || view == VIEW_WALKTURN)
  {
    /* Compute the rotation that rotates the projective plane in 4D without
       the trackball rotations. */
    rotateall4d(pp->zeta,pp->eta,pp->theta,mat);

    u = pp->umove;
    v = pp->vmove;
    cu = cos(u);
    su = sin(u);
    c2u = cos(2.0*u);
    s2u = sin(2.0*u);
    sv2 = sin(0.5*v);
    cv4 = cos(0.25*v);
    sv4 = sin(0.25*v);
    xx[0] = 0.5*s2u*sv4*sv4;
    xx[1] = 0.5*su*sv2;
    xx[2] = 0.5*cu*sv2;
    xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4);
    /* Avoid degenerate tangential plane basis vectors. */
    if (v < FLT_EPSILON)
      v = FLT_EPSILON;
    cv2 = cos(0.5*v);
    sv2 = sin(0.5*v);
    sv4 = sin(0.25*v);
    xxu[0] = c2u*sv4*sv4;
    xxu[1] = 0.5*cu*sv2;
    xxu[2] = -0.5*su*sv2;
    xxu[3] = 0.5*s2u*sv4*sv4;
    xxv[0] = 0.125*s2u*sv2;
    xxv[1] = 0.25*su*cv2;
    xxv[2] = 0.25*cu*cv2;
    xxv[3] = 0.125*(su*su+1.0)*sv2;
    for (l=0; l<4; l++)
    {
      y[l] = (mat[l][0]*xx[0]+mat[l][1]*xx[1]+
              mat[l][2]*xx[2]+mat[l][3]*xx[3]);
      yu[l] = (mat[l][0]*xxu[0]+mat[l][1]*xxu[1]+
               mat[l][2]*xxu[2]+mat[l][3]*xxu[3]);
      yv[l] = (mat[l][0]*xxv[0]+mat[l][1]*xxv[1]+
               mat[l][2]*xxv[2]+mat[l][3]*xxv[3]);
    }
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
    {
      for (l=0; l<3; l++)
      {
        p[l] = y[l]+pp->offset4d[l];
        pu[l] = yu[l];
        pv[l] = yv[l];
      }
    }
    else
    {
      s = y[3]+pp->offset4d[3];
      q = 1.0/s;
      t = q*q;
      for (l=0; l<3; l++)
      {
        r = y[l]+pp->offset4d[l];
        p[l] = r*q;
        pu[l] = (yu[l]*s-r*yu[3])*t;
        pv[l] = (yv[l]*s-r*yv[3])*t;
      }
    }
    n[0] = pu[1]*pv[2]-pu[2]*pv[1];
    n[1] = pu[2]*pv[0]-pu[0]*pv[2];
    n[2] = pu[0]*pv[1]-pu[1]*pv[0];
    t = 1.0/(pp->side*4.0*sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]));
    n[0] *= t;
    n[1] *= t;
    n[2] *= t;
    pm[0] = pu[0]*pp->dumove+pv[0]*pp->dvmove;
    pm[1] = pu[1]*pp->dumove+pv[1]*pp->dvmove;
    pm[2] = pu[2]*pp->dumove+pv[2]*pp->dvmove;
    t = 1.0/(4.0*sqrt(pm[0]*pm[0]+pm[1]*pm[1]+pm[2]*pm[2]));
    pm[0] *= t;
    pm[1] *= t;
    pm[2] *= t;
    b[0] = n[1]*pm[2]-n[2]*pm[1];
    b[1] = n[2]*pm[0]-n[0]*pm[2];
    b[2] = n[0]*pm[1]-n[1]*pm[0];
    t = 1.0/(4.0*sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]));
    b[0] *= t;
    b[1] *= t;
    b[2] *= t;

    /* Compute alpha, beta, delta from the three basis vectors.
           |  -b[0]  -b[1]  -b[2] |
       m = |   n[0]   n[1]   n[2] |
           | -pm[0] -pm[1] -pm[2] |
    */
    pp->alpha = atan2(-n[2],-pm[2])*180/M_PI;
    pp->beta = atan2(-b[2],sqrt(b[0]*b[0]+b[1]*b[1]))*180/M_PI;
    pp->delta = atan2(b[1],-b[0])*180/M_PI;

    /* Compute the rotation that rotates the projective plane in 4D. */
    rotateall(pp->alpha,pp->beta,pp->delta,pp->zeta,pp->eta,pp->theta,mat);

    u = pp->umove;
    v = pp->vmove;
    cu = cos(u);
    su = sin(u);
    s2u = sin(2.0*u);
    sv2 = sin(0.5*v);
    cv4 = cos(0.25*v);
    sv4 = sin(0.25*v);
    xx[0] = 0.5*s2u*sv4*sv4;
    xx[1] = 0.5*su*sv2;
    xx[2] = 0.5*cu*sv2;
    xx[3] = 0.5*(su*su*sv4*sv4-cv4*cv4);
    for (l=0; l<4; l++)
    {
      r = 0.0;
      for (m=0; m<4; m++)
        r += mat[l][m]*xx[m];
      y[l] = r;
    }
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
    {
      for (l=0; l<3; l++)
        p[l] = y[l]+pp->offset4d[l];
    }
    else
    {
      s = y[3]+pp->offset4d[3];
      for (l=0; l<3; l++)
        p[l] = (y[l]+pp->offset4d[l])/s;
    }

    pp->offset3d[0] = -p[0];
    pp->offset3d[1] = -p[1]-DELTAY;
    pp->offset3d[2] = -p[2];
  }
  else
  {
    /* Compute the rotation that rotates the projective plane in 4D,
       including the trackball rotations. */
    rotateall(pp->alpha,pp->beta,pp->delta,pp->zeta,pp->eta,pp->theta,r1);

    gltrackball_get_quaternion(pp->trackballs[0],q1);
    gltrackball_get_quaternion(pp->trackballs[1],q2);
    quats_to_rotmat(q1,q2,r2);

    mult_rotmat(r2,r1,mat);
  }

  /* Project the points from 4D to 3D. */
  for (i=0; i<=NUMV; i++)
  {
    for (j=0; j<=NUMU; j++)
    {
      o = i*(NUMU+1)+j;
      for (l=0; l<4; l++)
      {
        y[l] = (mat[l][0]*pp->x[o][0]+mat[l][1]*pp->x[o][1]+
                mat[l][2]*pp->x[o][2]+mat[l][3]*pp->x[o][3]);
        yu[l] = (mat[l][0]*pp->xu[o][0]+mat[l][1]*pp->xu[o][1]+
                 mat[l][2]*pp->xu[o][2]+mat[l][3]*pp->xu[o][3]);
        yv[l] = (mat[l][0]*pp->xv[o][0]+mat[l][1]*pp->xv[o][1]+
                 mat[l][2]*pp->xv[o][2]+mat[l][3]*pp->xv[o][3]);
      }
      if (projection_4d == DISP_4D_ORTHOGRAPHIC)
      {
        for (l=0; l<3; l++)
        {
          pp->pp[o][l] = (y[l]+pp->offset4d[l])+pp->offset3d[l];
          pu[l] = yu[l];
          pv[l] = yv[l];
        }
      }
      else
      {
        s = y[3]+pp->offset4d[3];
        q = 1.0/s;
        t = q*q;
        for (l=0; l<3; l++)
        {
          r = y[l]+pp->offset4d[l];
          pp->pp[o][l] = r*q+pp->offset3d[l];
          pu[l] = (yu[l]*s-r*yu[3])*t;
          pv[l] = (yv[l]*s-r*yv[3])*t;
        }
      }
      pp->pn[o][0] = pu[1]*pv[2]-pu[2]*pv[1];
      pp->pn[o][1] = pu[2]*pv[0]-pu[0]*pv[2];
      pp->pn[o][2] = pu[0]*pv[1]-pu[1]*pv[0];
      t = 1.0/sqrt(pp->pn[o][0]*pp->pn[o][0]+pp->pn[o][1]*pp->pn[o][1]+
                   pp->pn[o][2]*pp->pn[o][2]);
      pp->pn[o][0] *= t;
      pp->pn[o][1] *= t;
      pp->pn[o][2] *= t;
    }
  }

  if (colors == COLORS_TWOSIDED)
  {
    glColor3fv(mat_diff_red);
    if (display_mode == DISP_TRANSPARENT)
    {
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
    }
    else
    {
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
    }
  }
  glBindTexture(GL_TEXTURE_2D,pp->tex_name);

  if (appearance != APPEARANCE_DIRECTION_BANDS)
  {
    for (i=0; i<NUMV; i++)
    {
      if (appearance == APPEARANCE_DISTANCE_BANDS &&
          ((i & (NUMB-1)) >= NUMB/4) && ((i & (NUMB-1)) < 3*NUMB/4))
        continue;
      if (display_mode == DISP_WIREFRAME)
        glBegin(GL_QUAD_STRIP);
      else
        glBegin(GL_TRIANGLE_STRIP);
      for (j=0; j<=NUMU; j++)
      {
        for (k=0; k<=1; k++)
        {
          l = (i+k);
          m = j;
          o = l*(NUMU+1)+m;
          glNormal3fv(pp->pn[o]);
          glTexCoord2fv(pp->tex[o]);
          if (colors != COLORS_TWOSIDED)
          {
            glColor3fv(pp->col[o]);
            glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,pp->col[o]);
          }
          glVertex3fv(pp->pp[o]);
          polys++;
        }
      }
      glEnd();
    }
  }
  else /* appearance == APPEARANCE_DIRECTION_BANDS */
  {
    for (j=0; j<NUMU; j++)
    {
      if ((j & (NUMB-1)) >= NUMB/2)
        continue;
      if (display_mode == DISP_WIREFRAME)
        glBegin(GL_QUAD_STRIP);
      else
        glBegin(GL_TRIANGLE_STRIP);
      for (i=0; i<=NUMV; i++)
      {
        for (k=0; k<=1; k++)
        {
          l = i;
          m = (j+k);
          o = l*(NUMU+1)+m;
          glNormal3fv(pp->pn[o]);
          glTexCoord2fv(pp->tex[o]);
          if (colors != COLORS_TWOSIDED)
          {
            glColor3fv(pp->col[o]);
            glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,pp->col[o]);
          }
          glVertex3fv(pp->pp[o]);
          polys++;
        }
      }
      glEnd();
    }
  }

  polys /= 2;
  return polys;
}