~ubuntu-branches/ubuntu/trusty/xscreensaver/trusty

« back to all changes in this revision

Viewing changes to hacks/glx/mirrorblob.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2009-11-30 13:33:13 UTC
  • mfrom: (1.1.8 upstream) (2.1.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091130133313-3b5nz2e7hvbb8h3l
Tags: 5.10-3ubuntu1
* Merge with Debian unstable, remaining changes: (LP: #489062)
  - debian/control: add Build-Depends on ubuntu-artwork
  - debian/rules: use /usr/share/backgrounds
  - debian/control: Move xli | xloadimage recommends to suggests
  - debian/split-hacks.config: Use different set of default hacks to Debian
  - debian/source_xscreensaver.py: Add apport hook
  - debian/patches/53_XScreenSaver.ad.in.patch: Use Ubuntu branding

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * 21-Oct-2003:                           Renamed to mirrorblob
19
19
 * 10-Feb-2004:  jon.dowdall@bigpond.com  Added motion blur
20
20
 * 28-Jan-2006:  jon.dowdall@bigpond.com  Big clean up and bug fixes
 
21
 * 13-Apr-2009:  jon.dowdall@gmail.com    Fixed Mac version
21
22
 *
22
23
 * The mirrorblob screensaver draws a pulsing blob on the screen.  Options
23
24
 * include adding a background (via screen_to_texture), texturing the blob,
35
36
#include <math.h>
36
37
 
37
38
#ifdef STANDALONE
38
 
#define DEFAULTS \
39
 
    "*delay:             " DEF_DELAY "\n" \
40
 
    "*showFPS:           " DEF_FPS   "\n" \
41
 
    "*useSHM:              True      \n"
 
39
#define DEFAULTS "*delay:             " DEF_DELAY "\n"                      \
 
40
                 "*showFPS:           " DEF_FPS   "\n"                      \
 
41
                 "*useSHM:              True       \n"                      \
 
42
                 "*desktopGrabber:  xscreensaver-getimage -no-desktop %s\n" \
 
43
                 "*grabDesktopImages:   True  \n"                           \
 
44
                 "*chooseRandomImages:  True  \n"
42
45
 
43
46
# define refresh_mirrorblob 0
44
47
/*
45
48
# define mirrorblob_handle_event 0
46
49
*/
47
 
# include "xlockmore.h"    /* from the xmirrorblob distribution */
 
50
# include "xlockmore.h"
48
51
#else /* !STANDALONE */
49
52
# include "xlock.h"        /* from the xlockmore distribution */
50
53
#endif /* !STANDALONE */
123
126
    {"+texture",          ".blob.texture",          XrmoptionNoArg, "false" },
124
127
    {"-colour",           ".blob.colour",           XrmoptionNoArg, "true" },
125
128
    {"+colour",           ".blob.colour",           XrmoptionNoArg, "false" },
126
 
    {"-offset-texture",   ".blob.offsetTexture",   XrmoptionNoArg, "true" },
127
 
    {"+offset-texture",   ".blob.offsetTexture",   XrmoptionNoArg, "false" },
128
 
    {"-paint-background", ".blob.paintBackground", XrmoptionNoArg, "true" },
129
 
    {"+paint-background", ".blob.paintBackground", XrmoptionNoArg, "false" },
 
129
    {"-offset-texture",   ".blob.offsetTexture",    XrmoptionNoArg, "true" },
 
130
    {"+offset-texture",   ".blob.offsetTexture",    XrmoptionNoArg, "false" },
 
131
    {"-paint-background", ".blob.paintBackground",  XrmoptionNoArg, "true" },
 
132
    {"+paint-background", ".blob.paintBackground",  XrmoptionNoArg, "false" },
130
133
    {"-resolution",       ".blob.resolution",       XrmoptionSepArg, NULL },
131
134
    {"-bumps",            ".blob.bumps",            XrmoptionSepArg, NULL },
132
135
    {"-motion-blur",      ".blob.motionBlur",       XrmoptionSepArg, 0 },
182
185
 "OpenGL mirrorblob", 0, NULL};
183
186
#endif
184
187
 
185
 
 
186
188
/*****************************************************************************
187
189
 * Types used in blob code
188
190
 *****************************************************************************/
189
191
 
190
192
typedef struct
191
193
{
192
 
    GLdouble x, y;
 
194
  GLdouble x, y;
193
195
} Vector2D;
194
196
 
195
197
typedef struct
196
198
{
197
 
    GLdouble x, y, z;
 
199
  GLdouble x, y, z;
198
200
} Vector3D;
199
201
 
200
202
typedef struct
201
203
{
202
 
    GLdouble w;
203
 
    GLdouble x;
204
 
    GLdouble y;
205
 
    GLdouble z;
 
204
  GLdouble w;
 
205
  GLdouble x;
 
206
  GLdouble y;
 
207
  GLdouble z;
206
208
} Quaternion;
207
209
 
208
210
typedef struct
209
211
{
210
 
    GLubyte red, green, blue, alpha;
 
212
  GLubyte red, green, blue, alpha;
211
213
} Colour;
212
214
 
213
215
typedef struct
214
216
{
215
 
    Vector3D initial_position;
216
 
    Vector3D position;
217
 
    Vector3D normal;
 
217
  Vector3D initial_position;
 
218
  Vector3D position;
 
219
  Vector3D normal;
218
220
} Node_Data;
219
221
 
220
222
typedef struct
221
223
{
222
 
    int node1, node2, node3;
223
 
    Vector3D normal;
224
 
    double length1, length2, length3;
 
224
  int node1, node2, node3;
 
225
  Vector3D normal;
 
226
  double length1, length2, length3;
225
227
} Face_Data;
226
228
 
227
229
/* Structure to hold data about bumps used to distortion sphere */
228
230
typedef struct
229
231
{
230
 
    double cx, cy, cpower, csize;
231
 
    double ax, ay, power, size;
232
 
    double mx, my, mpower, msize;
233
 
    double vx, vy, vpower, vsize;
234
 
    Vector3D pos;
 
232
  double cx, cy, cpower, csize;
 
233
  double ax, ay, power, size;
 
234
  double mx, my, mpower, msize;
 
235
  double vx, vy, vpower, vsize;
 
236
  Vector3D pos;
235
237
} Bump_Data;
236
238
 
237
239
/* Vertices of a tetrahedron */
263
265
 
264
266
typedef enum
265
267
{
 
268
  INITIALISING,
266
269
  HOLDING,
267
270
  LOADING,
268
271
  TRANSITIONING
349
352
static void
350
353
reset_projection(int width, int height)
351
354
{
352
 
    glMatrixMode (GL_PROJECTION);
353
 
    glLoadIdentity ();
354
 
    gluPerspective (60.0, 1.0, 1.0, 1024.0 );
355
 
    glMatrixMode (GL_MODELVIEW);
356
 
    glLoadIdentity ();
 
355
  glMatrixMode (GL_PROJECTION);
 
356
  glLoadIdentity ();
 
357
  gluPerspective (60.0, 1.0, 1.0, 1024.0 );
 
358
  glMatrixMode (GL_MODELVIEW);
 
359
  glLoadIdentity ();
357
360
}
358
361
 
359
362
/******************************************************************************
365
368
static inline double
366
369
dot (const Vector3D u, const Vector3D v)
367
370
{
368
 
    return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
 
371
  return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
369
372
}
370
373
 
371
374
/******************************************************************************
377
380
static inline Vector3D
378
381
cross (const Vector3D u, const Vector3D v)
379
382
{
380
 
    Vector3D result;
381
 
 
382
 
    result.x = (u.y * v.z - u.z * v.y);
383
 
    result.y = (u.z * v.x - u.x * v.z);
384
 
    result.z = (u.x * v.y - u.y * v.x);
385
 
 
386
 
    return result;
 
383
  Vector3D result;
 
384
 
 
385
  result.x = (u.y * v.z - u.z * v.y);
 
386
  result.y = (u.z * v.x - u.x * v.z);
 
387
  result.z = (u.x * v.y - u.y * v.x);
 
388
 
 
389
  return result;
387
390
}
388
391
 
389
392
/******************************************************************************
393
396
static inline void
394
397
add (Vector3D *u, const Vector3D v)
395
398
{
396
 
    u->x = u->x + v.x;
397
 
    u->y = u->y + v.y;
398
 
    u->z = u->z + v.z;
 
399
  u->x = u->x + v.x;
 
400
  u->y = u->y + v.y;
 
401
  u->z = u->z + v.z;
399
402
}
400
403
 
401
404
/******************************************************************************
405
408
static inline Vector3D
406
409
subtract (const Vector3D u, const Vector3D v)
407
410
{
408
 
    Vector3D result;
409
 
 
410
 
    result.x = u.x - v.x;
411
 
    result.y = u.y - v.y;
412
 
    result.z = u.z - v.z;
413
 
 
414
 
    return result;
 
411
  Vector3D result;
 
412
 
 
413
  result.x = u.x - v.x;
 
414
  result.y = u.y - v.y;
 
415
  result.z = u.z - v.z;
 
416
 
 
417
  return result;
415
418
}
416
419
 
417
420
/******************************************************************************
421
424
static inline Vector3D
422
425
scale (const Vector3D v, const double s)
423
426
{
424
 
    Vector3D result;
 
427
  Vector3D result;
425
428
    
426
 
    result.x = v.x * s;
427
 
    result.y = v.y * s;
428
 
    result.z = v.z * s;
429
 
    return result;
 
429
  result.x = v.x * s;
 
430
  result.y = v.y * s;
 
431
  result.z = v.z * s;
 
432
  return result;
430
433
}
431
434
 
432
435
/******************************************************************************
436
439
static inline Vector3D
437
440
normalise (const Vector3D v)
438
441
{
439
 
    Vector3D result;
440
 
    double magnitude;
441
 
 
442
 
    magnitude = sqrt (dot(v, v));
443
 
 
444
 
    if (magnitude > 1e-300)
445
 
    {
446
 
        result = scale (v, 1.0 / magnitude);
447
 
    }
448
 
    else
449
 
    {
450
 
        printf("zero\n");
451
 
        result = zero_vector;
452
 
    }
453
 
    return result;
 
442
  Vector3D result;
 
443
  double magnitude;
 
444
 
 
445
  magnitude = sqrt (dot(v, v));
 
446
 
 
447
  if (magnitude > 1e-300)
 
448
    {
 
449
      result = scale (v, 1.0 / magnitude);
 
450
    }
 
451
  else
 
452
    {
 
453
      printf("zero\n");
 
454
      result = zero_vector;
 
455
    }
 
456
  return result;
454
457
}
455
458
 
456
459
/******************************************************************************
460
463
static void
461
464
quaternion_transform (Quaternion q, GLdouble * transform)
462
465
{
463
 
    GLdouble x, y, z, w;
464
 
    x = q.x;
465
 
    y = q.y;
466
 
    z = q.z;
467
 
    w = q.w;
468
 
 
469
 
    transform[0] = (w * w) + (x * x) - (y * y) - (z * z);
470
 
    transform[1] = (2.0 * x * y) + (2.0 * w * z);
471
 
    transform[2] = (2.0 * x * z) - (2.0 * w * y);
472
 
    transform[3] = 0.0;
473
 
 
474
 
    transform[4] = (2.0 * x * y) - (2.0 * w * z);
475
 
    transform[5] = (w * w) - (x * x) + (y * y) - (z * z);
476
 
    transform[6] = (2.0 * y * z) + (2.0 * w * x);
477
 
    transform[7] = 0.0;
478
 
 
479
 
    transform[8] = (2.0 * x * z) + (2.0 * w * y);
480
 
    transform[9] = (2.0 * y * z) - (2.0 * w * x);
481
 
    transform[10] = (w * w) - (x * x) - (y * y) + (z * z);
482
 
    transform[11] = 0.0;
483
 
 
484
 
    transform[12] = 0.0;
485
 
    transform[13] = 0.0;
486
 
    transform[14] = 0.0;
487
 
    transform[15] = (w * w) + (x * x) + (y * y) + (z * z);
 
466
  GLdouble x, y, z, w;
 
467
  x = q.x;
 
468
  y = q.y;
 
469
  z = q.z;
 
470
  w = q.w;
 
471
 
 
472
  transform[0] = (w * w) + (x * x) - (y * y) - (z * z);
 
473
  transform[1] = (2.0 * x * y) + (2.0 * w * z);
 
474
  transform[2] = (2.0 * x * z) - (2.0 * w * y);
 
475
  transform[3] = 0.0;
 
476
 
 
477
  transform[4] = (2.0 * x * y) - (2.0 * w * z);
 
478
  transform[5] = (w * w) - (x * x) + (y * y) - (z * z);
 
479
  transform[6] = (2.0 * y * z) + (2.0 * w * x);
 
480
  transform[7] = 0.0;
 
481
 
 
482
  transform[8] = (2.0 * x * z) + (2.0 * w * y);
 
483
  transform[9] = (2.0 * y * z) - (2.0 * w * x);
 
484
  transform[10] = (w * w) - (x * x) - (y * y) + (z * z);
 
485
  transform[11] = 0.0;
 
486
 
 
487
  transform[12] = 0.0;
 
488
  transform[13] = 0.0;
 
489
  transform[14] = 0.0;
 
490
  transform[15] = (w * w) + (x * x) + (y * y) + (z * z);
488
491
}
489
492
 
490
493
/******************************************************************************
494
497
static inline Vector3D
495
498
vector_transform (Vector3D u, GLdouble * t)
496
499
{
497
 
    Vector3D result;
498
 
 
499
 
    result.x = (u.x * t[0] + u.y * t[4] + u.z * t[8] + 1.0 * t[12]);
500
 
    result.y = (u.x * t[1] + u.y * t[5] + u.z * t[9] + 1.0 * t[13]);
501
 
    result.z = (u.x * t[2] + u.y * t[6] + u.z * t[10] + 1.0 * t[14]);
502
 
 
503
 
    return result;
 
500
  Vector3D result;
 
501
 
 
502
  result.x = (u.x * t[0] + u.y * t[4] + u.z * t[8] + 1.0 * t[12]);
 
503
  result.y = (u.x * t[1] + u.y * t[5] + u.z * t[9] + 1.0 * t[13]);
 
504
  result.z = (u.x * t[2] + u.y * t[6] + u.z * t[10] + 1.0 * t[14]);
 
505
 
 
506
  return result;
504
507
}
505
508
 
506
509
/******************************************************************************
511
514
static Vector3D
512
515
partial (Vector3D node1, Vector3D node2, double distance)
513
516
{
514
 
    Vector3D result;
515
 
    Vector3D rotation_axis;
516
 
    GLdouble transformation[16];
517
 
    double angle;
518
 
    Quaternion rotation;
519
 
 
520
 
    rotation_axis = normalise (cross (node1, node2));
521
 
    angle = acos (dot (node1, node2)) * distance;
522
 
 
523
 
    rotation.x = rotation_axis.x * sin (angle / 2.0);
524
 
    rotation.y = rotation_axis.y * sin (angle / 2.0);
525
 
    rotation.z = rotation_axis.z * sin (angle / 2.0);
526
 
    rotation.w = cos (angle / 2.0);
527
 
 
528
 
    quaternion_transform (rotation, transformation);
529
 
 
530
 
    result = vector_transform (node1, transformation);
531
 
 
532
 
    return result;
 
517
  Vector3D result;
 
518
  Vector3D rotation_axis;
 
519
  GLdouble transformation[16];
 
520
  double angle;
 
521
  Quaternion rotation;
 
522
 
 
523
  rotation_axis = normalise (cross (node1, node2));
 
524
  angle = acos (dot (node1, node2)) * distance;
 
525
 
 
526
  rotation.x = rotation_axis.x * sin (angle / 2.0);
 
527
  rotation.y = rotation_axis.y * sin (angle / 2.0);
 
528
  rotation.z = rotation_axis.z * sin (angle / 2.0);
 
529
  rotation.w = cos (angle / 2.0);
 
530
 
 
531
  quaternion_transform (rotation, transformation);
 
532
 
 
533
  result = vector_transform (node1, transformation);
 
534
 
 
535
  return result;
533
536
}
534
537
 
535
538
/****************************************************************************
536
539
 *
537
 
 * Load a texture.
 
540
 * Callback indicating a texture has loaded
538
541
 */
539
 
 
540
542
static void
541
543
image_loaded_cb (const char *filename, XRectangle *geometry,
542
544
                 int image_width, int image_height, 
573
575
  mp->first_image_p = True;
574
576
}
575
577
 
576
 
 
 
578
/* Load a new file into a texture
 
579
 */
577
580
static void
578
581
grab_texture(ModeInfo *mi, int texture_index)
579
582
{
580
583
  mirrorblobstruct *mp = &Mirrorblob[MI_SCREEN(mi)];
581
 
 
582
 
  mp->waiting_for_image_p = True;
583
 
  mp->mipmap_p = True;
584
 
  load_texture_async (mi->xgwa.screen, mi->window,
585
 
                      *mp->glx_context, 0, 0, mp->mipmap_p, 
586
 
                      mp->textures[texture_index],
587
 
                      image_loaded_cb, mp);
 
584
        
 
585
  {
 
586
    int w = (MI_WIDTH(mi)  / 2) - 1;
 
587
    int h = (MI_HEIGHT(mi) / 2) - 1;
 
588
    if (w <= 10) w = 10;
 
589
    if (h <= 10) h = 10;
 
590
        
 
591
    mp->waiting_for_image_p = True;
 
592
    mp->mipmap_p = True;
 
593
    load_texture_async (mi->xgwa.screen, mi->window,
 
594
                        *mp->glx_context, w, h, mp->mipmap_p, 
 
595
                        mp->textures[texture_index],
 
596
                        image_loaded_cb, mp);
 
597
  }
588
598
}
589
599
 
590
600
/******************************************************************************
595
605
static void
596
606
set_parameters(void)
597
607
{
598
 
    /* In wire frame mode do not draw a texture */
599
 
    if (wireframe)
600
 
    {
601
 
        do_texture = False;
602
 
        blend = 1.0;
603
 
    }
604
 
    
605
 
    /* Need to load textures if either the blob or the backgound has an image */
606
 
    if (do_texture || do_paint_background)
607
 
    {
608
 
        load_textures = True;
609
 
    }
610
 
    else
611
 
    {
612
 
        load_textures = False;
613
 
    }
614
 
    
615
 
    /* If theres no texture don't calculate co-ordinates. */
616
 
    if (!do_texture)
617
 
    {
618
 
        offset_texture = False;
619
 
    }
620
 
    
621
 
    culling = True;
 
608
  /* In wire frame mode do not draw a texture */
 
609
  if (wireframe)
 
610
    {
 
611
      do_texture = False;
 
612
      blend = 1.0;
 
613
    }
 
614
    
 
615
  /* Need to load textures if either the blob or the backgound has an image */
 
616
  if (do_texture || do_paint_background)
 
617
    {
 
618
      load_textures = True;
 
619
    }
 
620
  else
 
621
    {
 
622
      load_textures = False;
 
623
    }
 
624
    
 
625
  /* If theres no texture don't calculate co-ordinates. */
 
626
  if (!do_texture)
 
627
    {
 
628
      offset_texture = False;
 
629
    }
 
630
    
 
631
  culling = True;
622
632
}
623
633
 
624
634
/******************************************************************************
628
638
static void
629
639
initialize_gl(ModeInfo *mi, GLsizei width, GLsizei height)
630
640
{
631
 
    mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
 
641
  mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
632
642
    
633
 
    /* Lighting values */
634
 
    GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
635
 
 
636
 
    GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f };
637
 
    GLfloat whiteLight0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
638
 
    GLfloat sourceLight0[] = { 0.6f, 0.6f, 0.6f, 1.0f };
639
 
    GLfloat specularLight0[] = { 0.8f, 0.8f, 0.9f, 1.0f };
640
 
 
641
 
    GLfloat lightPos1[] = {0.0f, -500.0f, 500.0f, 1.0f };
642
 
    GLfloat whiteLight1[] = { 0.0f, 0.0f, 0.0f, 1.0f };
643
 
    GLfloat sourceLight1[] = { 0.6f, 0.6f, 0.6f, 1.0f };
644
 
    GLfloat specularLight1[] = { 0.7f, 0.7f, 0.7f, 1.0f };
645
 
 
646
 
    GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
647
 
 
648
 
    GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 0.1 };
649
 
 
650
 
    /* Set the internal parameters based on the configuration settings */
651
 
    set_parameters();
652
 
 
653
 
    /* Set the viewport to the width and heigh of the window */
654
 
    glViewport (0, 0, width, height ); 
655
 
 
656
 
    if (do_antialias)
 
643
  /* Lighting values */
 
644
  GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
 
645
 
 
646
  GLfloat lightPos0[] = {500.0f, 100.0f, 200.0f, 1.0f };
 
647
  GLfloat whiteLight0[] = { 0.0f, 0.0f, 0.0f, 1.0f };
 
648
  GLfloat sourceLight0[] = { 0.6f, 0.6f, 0.6f, 1.0f };
 
649
  GLfloat specularLight0[] = { 0.8f, 0.8f, 0.9f, 1.0f };
 
650
 
 
651
  GLfloat lightPos1[] = {-50.0f, -100.0f, 2500.0f, 1.0f };
 
652
  GLfloat whiteLight1[] = { 0.0f, 0.0f, 0.0f, 1.0f };
 
653
  GLfloat sourceLight1[] = { 0.6f, 0.6f, 0.6f, 1.0f };
 
654
  GLfloat specularLight1[] = { 0.7f, 0.7f, 0.7f, 1.0f };
 
655
 
 
656
  GLfloat specref[] = { 1.0f, 1.0f, 1.0f, 1.0f };
 
657
 
 
658
  GLfloat fogColor[4] = { 0.4, 0.4, 0.5, 0.1 };
 
659
 
 
660
  /* Set the internal parameters based on the configuration settings */
 
661
  set_parameters();
 
662
 
 
663
  /* Set the viewport to the width and heigh of the window */
 
664
  glViewport (0, 0, width, height ); 
 
665
 
 
666
  if (do_antialias)
657
667
    {
658
 
        blend = 1.0;
659
 
        glEnable(GL_LINE_SMOOTH);
660
 
        glEnable(GL_POLYGON_SMOOTH);
 
668
      blend = 1.0;
 
669
      glEnable(GL_LINE_SMOOTH);
 
670
      glEnable(GL_POLYGON_SMOOTH);
661
671
    }
662
672
 
663
 
    /* The blend function is used for trasitioning between two images even when
664
 
     * blend is not selected.
665
 
     */
666
 
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
673
  /* The blend function is used for trasitioning between two images even when
 
674
   * blend is not selected.
 
675
   */
 
676
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
667
677
 
668
 
    if (do_fog)
669
 
    {
670
 
        glEnable(GL_FOG);
671
 
        glFogfv(GL_FOG_COLOR, fogColor);
672
 
        glFogf(GL_FOG_DENSITY, 0.50);
673
 
        glFogf(GL_FOG_START, 15.0);
674
 
        glFogf(GL_FOG_END, 30.0);
675
 
    }
676
 
 
677
 
    /* Set the shading model to smooth (Gouraud shading). */
678
 
    glShadeModel (GL_SMOOTH);
679
 
 
680
 
    /* Set the clear color. */
681
 
    glClearColor( 0, 0, 0, 0 );
682
 
 
683
 
    glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight);
684
 
    glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
685
 
    glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
686
 
    glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
687
 
    glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
688
 
    glEnable (GL_LIGHT0);
689
 
    glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
690
 
    glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
691
 
    glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
692
 
    glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
693
 
    glEnable (GL_LIGHT1);
694
 
    glEnable (GL_LIGHTING);
695
 
 
696
 
    /* Enable color tracking */
697
 
    glEnable (GL_COLOR_MATERIAL);
698
 
 
699
 
    /* Set Material properties to follow glColor values */
700
 
    glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
701
 
 
702
 
    /* Set all materials to have specular reflectivity */
703
 
    glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
704
 
    glMateriali (GL_FRONT, GL_SHININESS, 32);
705
 
 
706
 
    /* Let GL implementation scale normal vectors. */
707
 
    glEnable (GL_NORMALIZE);
708
 
 
709
 
    /* Enable Arrays */
710
 
    if (load_textures)
711
 
    {
712
 
        glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
713
 
        glEnable (GL_TEXTURE_2D);
714
 
 
715
 
        gp->current_texture = 0;
716
 
        glGenTextures (NUM_TEXTURES, gp->textures);
717
 
        grab_texture (mi, gp->current_texture);
718
 
 
719
 
        if (do_texture)
720
 
        {
721
 
            glEnableClientState (GL_TEXTURE_COORD_ARRAY);
722
 
        }
723
 
        glMatrixMode (GL_TEXTURE);
724
 
        glRotated (180.0, 1.0, 0.0, 0.0);
725
 
        glMatrixMode (GL_MODELVIEW);
726
 
    }
727
 
 
728
 
    if (do_colour)
729
 
    {
730
 
        glEnableClientState (GL_COLOR_ARRAY);
731
 
    }
732
 
    glEnableClientState (GL_NORMAL_ARRAY);
733
 
    glEnableClientState (GL_VERTEX_ARRAY);
734
 
 
735
 
    /* Clear the buffer since this is not done during a draw with motion blur */
736
 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
678
  if (do_fog)
 
679
    {
 
680
      glEnable(GL_FOG);
 
681
      glFogfv(GL_FOG_COLOR, fogColor);
 
682
      glFogf(GL_FOG_DENSITY, 0.50);
 
683
      glFogf(GL_FOG_START, 15.0);
 
684
      glFogf(GL_FOG_END, 30.0);
 
685
    }
 
686
 
 
687
  /* Set the shading model to smooth (Gouraud shading). */
 
688
  glShadeModel (GL_SMOOTH);
 
689
 
 
690
  /* Set the clear color. */
 
691
  glClearColor( 0, 0, 0, 0 );
 
692
 
 
693
  glLightModelfv (GL_LIGHT_MODEL_AMBIENT, ambientLight);
 
694
  glLightfv (GL_LIGHT0, GL_AMBIENT, whiteLight0);
 
695
  glLightfv (GL_LIGHT0, GL_DIFFUSE, sourceLight0);
 
696
  glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight0);
 
697
  glLightfv (GL_LIGHT0, GL_POSITION, lightPos0);
 
698
  glEnable (GL_LIGHT0);
 
699
  glLightfv (GL_LIGHT1, GL_AMBIENT, whiteLight1);
 
700
  glLightfv (GL_LIGHT1, GL_DIFFUSE, sourceLight1);
 
701
  glLightfv (GL_LIGHT1, GL_SPECULAR, specularLight1);
 
702
  glLightfv (GL_LIGHT1, GL_POSITION, lightPos1);
 
703
  glEnable (GL_LIGHT1);
 
704
  glEnable (GL_LIGHTING);
 
705
 
 
706
  /* Enable color tracking */
 
707
  glEnable (GL_COLOR_MATERIAL);
 
708
 
 
709
  /* Set Material properties to follow glColor values */
 
710
  glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
 
711
 
 
712
  /* Set all materials to have specular reflectivity */
 
713
  glMaterialfv (GL_FRONT, GL_SPECULAR, specref);
 
714
  glMateriali (GL_FRONT, GL_SHININESS, 32);
 
715
 
 
716
  /* Let GL implementation scale normal vectors. */
 
717
  glEnable (GL_NORMALIZE);
 
718
 
 
719
  /* Enable Arrays */
 
720
  if (load_textures)
 
721
    {
 
722
      glLightModeli (GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
 
723
      glEnable (GL_TEXTURE_2D);
 
724
 
 
725
      gp->current_texture = 0;
 
726
      glGenTextures(NUM_TEXTURES, gp->textures);
 
727
      grab_texture(mi, gp->current_texture);
 
728
 
 
729
      glMatrixMode (GL_TEXTURE);
 
730
      glRotated (180.0, 1.0, 0.0, 0.0);
 
731
      glMatrixMode (GL_MODELVIEW);
 
732
    }
 
733
 
 
734
  /* Clear the buffer since this is not done during a draw with motion blur */
 
735
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
737
736
}
738
737
 
739
738
/******************************************************************************
743
742
static void
744
743
set_blob_gl_state(GLdouble alpha)
745
744
{
746
 
    if (do_antialias)
747
 
    {
748
 
        glEnable(GL_LINE_SMOOTH);
749
 
        glEnable(GL_POLYGON_SMOOTH);
750
 
    }
751
 
 
752
 
    if (wireframe)
753
 
    {
754
 
        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
755
 
    }
756
 
    else
757
 
    {
758
 
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
759
 
    }
760
 
 
761
 
    /* The blend function is used for trasitioning between two images even when
762
 
     * blend is not selected.
763
 
     */
764
 
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
745
  if (do_antialias)
 
746
    {
 
747
      glEnable(GL_LINE_SMOOTH);
 
748
      glEnable(GL_POLYGON_SMOOTH);
 
749
    }
 
750
 
 
751
  if (wireframe)
 
752
    {
 
753
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
754
    }
 
755
  else
 
756
    {
 
757
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 
758
    }
 
759
 
 
760
  /* The blend function is used for trasitioning between two images even when
 
761
   * blend is not selected.
 
762
   */
 
763
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
765
764
 
766
 
    /* Culling. */
767
 
    if (culling)
768
 
    {
769
 
        glCullFace (GL_BACK);
770
 
        glEnable (GL_CULL_FACE);
771
 
        glFrontFace (GL_CCW);
772
 
    }
773
 
    else
774
 
    {
775
 
        glDisable (GL_CULL_FACE);
776
 
    }
777
 
    
778
 
    if (blend < 1.0)
779
 
    {
780
 
        glEnable (GL_BLEND);
781
 
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
782
 
        /* Set the default blob colour to off-white. */
783
 
        glColor4d (0.9, 0.9, 1.0, alpha);
784
 
    }
785
 
    else
786
 
    {
787
 
        glDisable(GL_BLEND);
788
 
        glColor4d (0.9, 0.9, 1.0, 1.0);
789
 
    }
790
 
    
791
 
    glEnable(GL_DEPTH_TEST);
792
 
    glEnable(GL_LIGHTING);
 
765
  /* Culling. */
 
766
  if (culling)
 
767
    {
 
768
      glCullFace (GL_BACK);
 
769
      glEnable (GL_CULL_FACE);
 
770
      glFrontFace (GL_CCW);
 
771
    }
 
772
  else
 
773
    {
 
774
      glDisable (GL_CULL_FACE);
 
775
    }
 
776
    
 
777
  if (blend < 1.0)
 
778
    {
 
779
      glEnable (GL_BLEND);
 
780
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
781
      /* Set the default blob colour to off-white. */
 
782
      glColor4d (0.9, 0.9, 1.0, alpha);
 
783
    }
 
784
  else
 
785
    {
 
786
      glDisable(GL_BLEND);
 
787
      glColor4d (0.9, 0.9, 1.0, 1.0);
 
788
    }
 
789
    
 
790
  glEnable(GL_DEPTH_TEST);
 
791
  glEnable(GL_LIGHTING);
793
792
}
794
793
 
795
794
/******************************************************************************
805
804
                int height,
806
805
                int bump_array_size)
807
806
{
808
 
     /* Loop variables */    
809
 
    int i, u, v, node, side, face, base, base2 = 0;
810
 
    int nodes_on_edge = resolution;
811
 
    Vector3D node1, node2, result;
812
 
 
813
 
    if (nodes_on_edge < 2)
814
 
        return -1;
815
 
 
816
 
    gp->num_nodes = 2 * nodes_on_edge * nodes_on_edge - 4 * nodes_on_edge + 4;
817
 
    gp->num_faces = 4 * (nodes_on_edge - 1) * (nodes_on_edge - 1);
818
 
 
819
 
    gp->nodes = (Node_Data *) malloc (gp->num_nodes * sizeof (Node_Data));
820
 
    if (!gp->nodes)
821
 
    {
822
 
        fprintf (stderr, "Couldn't allocate gp->nodes buffer\n");
823
 
        return -1;
824
 
    }
825
 
 
826
 
    gp->faces = (Face_Data *) malloc (gp->num_faces * sizeof (Face_Data));
827
 
    if (!gp->faces)
828
 
    {
829
 
        fprintf (stderr, "Couldn't allocate faces data buffer\n");
830
 
        return -1;
831
 
    }
832
 
 
833
 
    gp->bump_data = (Bump_Data *) malloc (bumps * sizeof (Bump_Data));
834
 
    if (!gp->bump_data)
835
 
    {
836
 
        fprintf(stderr, "Couldn't allocate bump data buffer\n");
837
 
        return -1;
838
 
    }
839
 
 
840
 
    gp->bump_shape = (double *)malloc(bump_array_size * sizeof(double));
841
 
    if (!gp->bump_shape)
842
 
    {
843
 
        fprintf(stderr, "Couldn't allocate bump buffer\n");
844
 
        return -1;
845
 
    }
846
 
 
847
 
    gp->wall_shape = (double *)malloc(bump_array_size * sizeof(double));
848
 
    if (!gp->wall_shape)
849
 
    {
850
 
        fprintf(stderr, "Couldn't allocate wall bump buffer\n");
851
 
        return -1;
852
 
    }
853
 
 
854
 
    gp->dots = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
855
 
    if (!gp->dots)
856
 
    {
857
 
        fprintf(stderr, "Couldn't allocate nodes buffer\n");
858
 
        return -1;
859
 
    }
860
 
    glVertexPointer (3, GL_DOUBLE, 0, (GLvoid *) gp->dots);
861
 
 
862
 
    gp->normals = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
863
 
    if (!gp->normals)
864
 
    {
865
 
        fprintf(stderr, "Couldn't allocate normals buffer\n");
866
 
        return -1;
867
 
    }
868
 
    glNormalPointer (GL_DOUBLE, 0, (GLvoid *) gp->normals);
869
 
 
870
 
    if (do_colour)
871
 
    {
872
 
        gp->colours = (Colour *)malloc(gp->num_nodes * sizeof(Colour));
873
 
        if (!gp->colours)
874
 
        {
875
 
            fprintf(stderr, "Couldn't allocate colours buffer\n");
876
 
            return -1;
877
 
        }
878
 
        glColorPointer (4, GL_UNSIGNED_BYTE, 0, (GLvoid *) gp->colours);
879
 
    }
880
 
 
881
 
    if (do_texture)
882
 
    {
883
 
        gp->tex_coords = (Vector2D *)malloc(gp->num_nodes * sizeof(Vector2D));
884
 
        if (!gp->tex_coords)
885
 
        {
886
 
            fprintf(stderr, "Couldn't allocate gp->tex_coords buffer\n");
887
 
            return -1;
888
 
        }
889
 
        glTexCoordPointer (2, GL_DOUBLE, 0, (GLvoid *) gp->tex_coords);
890
 
    }
891
 
 
892
 
    /* Initialise bump data */
893
 
    for (i = 0; i < bumps; i++)
894
 
    {
895
 
        gp->bump_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
896
 
        gp->bump_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
897
 
        gp->bump_data[i].power = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
898
 
        gp->bump_data[i].size = 0.1 + 0.5 * (((double)random() / (double)RAND_MAX));
899
 
 
900
 
        gp->bump_data[i].pos.x = 1.5 * sin(PI * gp->bump_data[i].ay)
901
 
            * cos(PI *  gp->bump_data[i].ax);
902
 
        gp->bump_data[i].pos.y = 1.5 * cos(PI * gp->bump_data[i].ay);
903
 
        gp->bump_data[i].pos.z = 1.5 * sin(PI * gp->bump_data[i].ay)
904
 
            * sin(PI *  gp->bump_data[i].ax);
905
 
 
906
 
        gp->bump_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
907
 
        gp->bump_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
908
 
        gp->bump_data[i].cpower = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
909
 
        gp->bump_data[i].csize = 0.35; /*0.1 + 0.25 * (((double)random() / (double)RAND_MAX));*/
910
 
 
911
 
        gp->bump_data[i].vx = 0.0;
912
 
        gp->bump_data[i].vy = 0.0;
913
 
        gp->bump_data[i].vpower = 0.0;
914
 
        gp->bump_data[i].vsize = 0.0;
915
 
 
916
 
        gp->bump_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
917
 
        gp->bump_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
918
 
        gp->bump_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
919
 
        gp->bump_data[i].msize = 0.003 * ((double)random() / (double)RAND_MAX);
920
 
    }
921
 
 
922
 
    /* Initialise lookup table of bump strength */
923
 
    for (i = 0; i < bump_array_size; i++)
924
 
    {
925
 
        double xd, xd2;
926
 
        xd = i / (double)bump_array_size;
927
 
 
928
 
        xd2 = 48.0 * xd * xd;
929
 
        gp->bump_shape[i] = 0.1 / (xd2 + 0.1);
930
 
 
931
 
        xd2 = 40.0 * xd * xd * xd * xd;
932
 
        gp->wall_shape[i] = 0.4 / (xd2 + 0.1);
933
 
    }
934
 
 
935
 
    node = 0;
936
 
    face = 0;
937
 
    for (side = 0; side < 4; side++)
938
 
    {
939
 
        base = node;
940
 
        if (side == 2) 
941
 
        {
942
 
            base2 = node;
943
 
        }
944
 
        /*
945
 
         * The start and end of the for loops below are modified based on the 
946
 
         * side of the tetrahedron that is being calculated to avoid duplication
947
 
         * of the gp->nodes that are on the edges of the tetrahedron. 
948
 
         */
949
 
        for (u = (side > 1); u < (nodes_on_edge - (side > 0)); u++)
950
 
        {
951
 
            node1 = partial (normalise (tetrahedron[side][0]),
952
 
                              normalise (tetrahedron[side][1]),
953
 
                              u / (double) (nodes_on_edge - 1));
954
 
            node2 = partial (normalise (tetrahedron[side][0]),
955
 
                              normalise (tetrahedron[side][2]),
956
 
                              u / (double) (nodes_on_edge - 1));
957
 
 
958
 
            for (v = (side > 1); v <= (u - (side > 2)); v++)
959
 
            {
960
 
                if (u > 0)
961
 
                    result = partial (node1, node2, v / (double) u);
 
807
  /* Loop variables */    
 
808
  int i, u, v, node, side, face, base, base2 = 0;
 
809
  int nodes_on_edge = resolution;
 
810
  Vector3D node1, node2, result;
 
811
 
 
812
  if (nodes_on_edge < 2)
 
813
    return -1;
 
814
 
 
815
  gp->num_nodes = 2 * nodes_on_edge * nodes_on_edge - 4 * nodes_on_edge + 4;
 
816
  gp->num_faces = 4 * (nodes_on_edge - 1) * (nodes_on_edge - 1);
 
817
 
 
818
  gp->nodes = (Node_Data *) malloc (gp->num_nodes * sizeof (Node_Data));
 
819
  if (!gp->nodes)
 
820
    {
 
821
      fprintf (stderr, "Couldn't allocate gp->nodes buffer\n");
 
822
      return -1;
 
823
    }
 
824
 
 
825
  gp->faces = (Face_Data *) malloc (gp->num_faces * sizeof (Face_Data));
 
826
  if (!gp->faces)
 
827
    {
 
828
      fprintf (stderr, "Couldn't allocate faces data buffer\n");
 
829
      return -1;
 
830
    }
 
831
 
 
832
  gp->bump_data = (Bump_Data *) malloc (bumps * sizeof (Bump_Data));
 
833
  if (!gp->bump_data)
 
834
    {
 
835
      fprintf(stderr, "Couldn't allocate bump data buffer\n");
 
836
      return -1;
 
837
    }
 
838
 
 
839
  gp->bump_shape = (double *)malloc(bump_array_size * sizeof(double));
 
840
  if (!gp->bump_shape)
 
841
    {
 
842
      fprintf(stderr, "Couldn't allocate bump buffer\n");
 
843
      return -1;
 
844
    }
 
845
 
 
846
  gp->wall_shape = (double *)malloc(bump_array_size * sizeof(double));
 
847
  if (!gp->wall_shape)
 
848
    {
 
849
      fprintf(stderr, "Couldn't allocate wall bump buffer\n");
 
850
      return -1;
 
851
    }
 
852
 
 
853
        
 
854
  gp->dots = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
 
855
  if (!gp->dots)
 
856
    {
 
857
      fprintf(stderr, "Couldn't allocate nodes buffer\n");
 
858
      return -1;
 
859
    }
 
860
 
 
861
  gp->normals = (Vector3D *)malloc(gp->num_nodes * sizeof(Vector3D));
 
862
  if (!gp->normals)
 
863
    {
 
864
      fprintf(stderr, "Couldn't allocate normals buffer\n");
 
865
      return -1;
 
866
    }
 
867
 
 
868
  gp->colours = (Colour *)malloc(gp->num_nodes * sizeof(Colour));
 
869
  if (!gp->colours)
 
870
    {
 
871
      fprintf(stderr, "Couldn't allocate colours buffer\n");
 
872
      return -1;
 
873
    }
 
874
 
 
875
  gp->tex_coords = (Vector2D *)malloc(gp->num_nodes * sizeof(Vector2D));
 
876
  if (!gp->tex_coords)
 
877
    {
 
878
      fprintf(stderr, "Couldn't allocate gp->tex_coords buffer\n");
 
879
      return -1;
 
880
    }
 
881
 
 
882
        
 
883
  /* Initialise bump data */
 
884
  for (i = 0; i < bumps; i++)
 
885
    {
 
886
      gp->bump_data[i].ax = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
 
887
      gp->bump_data[i].ay = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
 
888
      gp->bump_data[i].power = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
 
889
      gp->bump_data[i].size = 0.1 + 0.5 * (((double)random() / (double)RAND_MAX));
 
890
 
 
891
      gp->bump_data[i].pos.x = 1.5 * sin(PI * gp->bump_data[i].ay)
 
892
        * cos(PI *  gp->bump_data[i].ax);
 
893
      gp->bump_data[i].pos.y = 1.5 * cos(PI * gp->bump_data[i].ay);
 
894
      gp->bump_data[i].pos.z = 1.5 * sin(PI * gp->bump_data[i].ay)
 
895
        * sin(PI *  gp->bump_data[i].ax);
 
896
 
 
897
      gp->bump_data[i].cx = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
 
898
      gp->bump_data[i].cy = 2.0 * (((double)random() / (double)RAND_MAX) - 0.5);
 
899
      gp->bump_data[i].cpower = (5.0 / pow(bumps, 0.75)) * (((double)random() / (double)RAND_MAX) - 0.5);
 
900
      gp->bump_data[i].csize = 0.35; /*0.1 + 0.25 * (((double)random() / (double)RAND_MAX));*/
 
901
 
 
902
      gp->bump_data[i].vx = 0.0;
 
903
      gp->bump_data[i].vy = 0.0;
 
904
      gp->bump_data[i].vpower = 0.0;
 
905
      gp->bump_data[i].vsize = 0.0;
 
906
 
 
907
      gp->bump_data[i].mx = 0.003 * ((double)random() / (double)RAND_MAX);
 
908
      gp->bump_data[i].my = 0.003 * ((double)random() / (double)RAND_MAX);
 
909
      gp->bump_data[i].mpower = 0.003 * ((double)random() / (double)RAND_MAX);
 
910
      gp->bump_data[i].msize = 0.003 * ((double)random() / (double)RAND_MAX);
 
911
    }
 
912
 
 
913
  /* Initialise lookup table of bump strength */
 
914
  for (i = 0; i < bump_array_size; i++)
 
915
    {
 
916
      double xd, xd2;
 
917
      xd = i / (double)bump_array_size;
 
918
 
 
919
      xd2 = 48.0 * xd * xd;
 
920
      gp->bump_shape[i] = 0.1 / (xd2 + 0.1);
 
921
 
 
922
      xd2 = 40.0 * xd * xd * xd * xd;
 
923
      gp->wall_shape[i] = 0.4 / (xd2 + 0.1);
 
924
    }
 
925
 
 
926
  node = 0;
 
927
  face = 0;
 
928
  for (side = 0; side < 4; side++)
 
929
    {
 
930
      base = node;
 
931
      if (side == 2) 
 
932
        {
 
933
          base2 = node;
 
934
        }
 
935
      /*
 
936
       * The start and end of the for loops below are modified based on the 
 
937
       * side of the tetrahedron that is being calculated to avoid duplication
 
938
       * of the gp->nodes that are on the edges of the tetrahedron. 
 
939
       */
 
940
      for (u = (side > 1); u < (nodes_on_edge - (side > 0)); u++)
 
941
        {
 
942
          node1 = partial (normalise (tetrahedron[side][0]),
 
943
                           normalise (tetrahedron[side][1]),
 
944
                           u / (double) (nodes_on_edge - 1));
 
945
          node2 = partial (normalise (tetrahedron[side][0]),
 
946
                           normalise (tetrahedron[side][2]),
 
947
                           u / (double) (nodes_on_edge - 1));
 
948
 
 
949
          for (v = (side > 1); v <= (u - (side > 2)); v++)
 
950
            {
 
951
              if (u > 0)
 
952
                result = partial (node1, node2, v / (double) u);
 
953
              else
 
954
                result = node1;
 
955
 
 
956
              gp->nodes[node].position = normalise (result);
 
957
              gp->nodes[node].initial_position = gp->nodes[node].position;
 
958
              gp->nodes[node].normal = zero_vector;
 
959
              node++;
 
960
            }
 
961
        }
 
962
 
 
963
      /*
 
964
       * Determine which nodes make up each face.  The complexity is caused 
 
965
       * by having to determine the correct nodes for the edges of the
 
966
       * tetrahedron since the common nodes on the edges are only calculated
 
967
       * once (see above).
 
968
       */
 
969
      for (u = 0; u < (nodes_on_edge - 1); u++)
 
970
        {
 
971
          for (v = 0; v <= u; v++)
 
972
            {
 
973
              {
 
974
                if (side < 2)
 
975
                  {
 
976
                    gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
 
977
                    gp->faces[face].node2 =
 
978
                      base + ((u + 1) * (u + 2)) / 2 + v + 1;
 
979
                    gp->faces[face].node3 =
 
980
                      base + ((u + 1) * (u + 2)) / 2 + v;
 
981
 
 
982
                    if ((side == 1) && (u == (nodes_on_edge - 2)))
 
983
                      {
 
984
                        gp->faces[face].node3 =
 
985
                          ((u + 1) * (u + 2)) / 2 +
 
986
                          nodes_on_edge - v - 1;
 
987
                        gp->faces[face].node2 =
 
988
                          ((u + 1) * (u + 2)) / 2 +
 
989
                          nodes_on_edge - v - 2;
 
990
                      }
 
991
                  }
 
992
                else if (side < 3)
 
993
                  {
 
994
                    gp->faces[face].node1 =
 
995
                      base + (((u - 1) * u) / 2) + v - 1;
 
996
                    gp->faces[face].node2 = base + ((u) * (u + 1)) / 2 + v;
 
997
                    gp->faces[face].node3 =
 
998
                      base + ((u) * (u + 1)) / 2 + v - 1;
 
999
 
 
1000
                    if (u == (nodes_on_edge - 2))
 
1001
                      {
 
1002
                        int n = nodes_on_edge - v - 1;
 
1003
                        gp->faces[face].node2 =
 
1004
                          ((nodes_on_edge *
 
1005
                            (nodes_on_edge + 1)) / 2) +
 
1006
                          ((n - 1) * (n + 0)) / 2;
 
1007
                        gp->faces[face].node3 =
 
1008
                          ((nodes_on_edge *
 
1009
                            (nodes_on_edge + 1)) / 2) +
 
1010
                          ((n + 0) * (n + 1)) / 2;
 
1011
                      }
 
1012
                    if (v == 0)
 
1013
                      {
 
1014
                        gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
 
1015
                        gp->faces[face].node3 = (((u + 2) * (u + 3)) / 2) - 1;
 
1016
                      }
 
1017
                  }
962
1018
                else
963
 
                    result = node1;
964
 
 
965
 
                gp->nodes[node].position = normalise (result);
966
 
                gp->nodes[node].initial_position = gp->nodes[node].position;
967
 
                gp->nodes[node].normal = zero_vector;
968
 
                node++;
969
 
            }
970
 
        }
971
 
 
972
 
        /*
973
 
         * Determine which nodes make up each face.  The complexity is caused 
974
 
         * by having to determine the correct nodes for the edges of the
975
 
         * tetrahedron since the common nodes on the edges are only calculated
976
 
         * once (see above).
977
 
         */
978
 
        for (u = 0; u < (nodes_on_edge - 1); u++)
979
 
        {
980
 
            for (v = 0; v <= u; v++)
981
 
            {
982
 
                {
983
 
                    if (side < 2)
984
 
                    {
985
 
                        gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
986
 
                        gp->faces[face].node2 =
987
 
                            base + ((u + 1) * (u + 2)) / 2 + v + 1;
988
 
                        gp->faces[face].node3 =
989
 
                            base + ((u + 1) * (u + 2)) / 2 + v;
990
 
 
991
 
                        if ((side == 1) && (u == (nodes_on_edge - 2)))
992
 
                        {
993
 
                            gp->faces[face].node3 =
994
 
                                ((u + 1) * (u + 2)) / 2 +
995
 
                                nodes_on_edge - v - 1;
996
 
                            gp->faces[face].node2 =
997
 
                                ((u + 1) * (u + 2)) / 2 +
998
 
                                nodes_on_edge - v - 2;
999
 
                        }
1000
 
                    }
1001
 
                    else if (side < 3)
1002
 
                    {
1003
 
                        gp->faces[face].node1 =
1004
 
                            base + (((u - 1) * u) / 2) + v - 1;
1005
 
                        gp->faces[face].node2 = base + ((u) * (u + 1)) / 2 + v;
1006
 
                        gp->faces[face].node3 =
1007
 
                            base + ((u) * (u + 1)) / 2 + v - 1;
1008
 
 
1009
 
                        if (u == (nodes_on_edge - 2))
1010
 
                        {
1011
 
                            int n = nodes_on_edge - v - 1;
1012
 
                            gp->faces[face].node2 =
1013
 
                                ((nodes_on_edge *
1014
 
                                  (nodes_on_edge + 1)) / 2) +
1015
 
                                ((n - 1) * (n + 0)) / 2;
1016
 
                            gp->faces[face].node3 =
1017
 
                                ((nodes_on_edge *
1018
 
                                  (nodes_on_edge + 1)) / 2) +
1019
 
                                ((n + 0) * (n + 1)) / 2;
1020
 
                        }
1021
 
                        if (v == 0)
1022
 
                        {
1023
 
                            gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1024
 
                            gp->faces[face].node3 = (((u + 2) * (u + 3)) / 2) - 1;
1025
 
                        }
1026
 
                    }
1027
 
                    else
1028
 
                    {
1029
 
                        gp->faces[face].node1 =
1030
 
                            base + (((u - 2) * (u - 1)) / 2) + v - 1;
1031
 
                        gp->faces[face].node2 = base + ((u - 1) * u) / 2 + v;
1032
 
                        gp->faces[face].node3 = base + ((u - 1) * u) / 2 + v - 1;
1033
 
 
1034
 
                        if (v == 0)
1035
 
                        {
1036
 
                            gp->faces[face].node1 =
1037
 
                                base2 + ((u * (u + 1)) / 2) - 1;
1038
 
                            gp->faces[face].node3 =
1039
 
                                base2 + ((u + 1) * (u + 2)) / 2 - 1;
1040
 
                        }
1041
 
                        if (u == (nodes_on_edge - 2))
1042
 
                        {
1043
 
                            gp->faces[face].node3 =
1044
 
                                ((nodes_on_edge *
1045
 
                                  (nodes_on_edge + 1)) / 2) +
1046
 
                                ((v + 1) * (v + 2)) / 2 - 1;
1047
 
                            gp->faces[face].node2 =
1048
 
                                ((nodes_on_edge *
1049
 
                                  (nodes_on_edge + 1)) / 2) +
1050
 
                                ((v + 2) * (v + 3)) / 2 - 1;
1051
 
                        }
1052
 
                        if (v == u)
1053
 
                        {
1054
 
                            gp->faces[face].node1 = (u * (u + 1)) / 2;
1055
 
                            gp->faces[face].node2 = ((u + 1) * (u + 2)) / 2;
1056
 
                        }
1057
 
                    }
1058
 
                    face++;
1059
 
                }
1060
 
 
1061
 
                if (v < u)
1062
 
                {
1063
 
                    if (side < 2)
1064
 
                    {
1065
 
                        gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
1066
 
                        gp->faces[face].node2 =
1067
 
                            base + ((u * (u + 1)) / 2) + v + 1;
1068
 
                        gp->faces[face].node3 =
1069
 
                            base + (((u + 1) * (u + 2)) / 2) + v + 1;
1070
 
 
1071
 
                        if ((side == 1) && (u == (nodes_on_edge - 2)))
1072
 
                        {
1073
 
                            gp->faces[face].node3 =
1074
 
                                ((u + 1) * (u + 2)) / 2 +
1075
 
                                nodes_on_edge - v - 2;
1076
 
                        }
1077
 
                    }
1078
 
                    else if (side < 3)
1079
 
                    {
1080
 
                        gp->faces[face].node1 =
1081
 
                            base + ((u * (u - 1)) / 2) + v - 1;
1082
 
                        gp->faces[face].node2 = base + ((u * (u - 1)) / 2) + v;
1083
 
                        gp->faces[face].node3 = base + ((u * (u + 1)) / 2) + v;
1084
 
 
1085
 
                        if (u == (nodes_on_edge - 2))
1086
 
                        {
1087
 
                            int n = nodes_on_edge - v - 1;
1088
 
                            gp->faces[face].node3 =
1089
 
                                ((nodes_on_edge *
1090
 
                                  (nodes_on_edge + 1)) / 2) +
1091
 
                                ((n + 0) * (n - 1)) / 2;
1092
 
                        }
1093
 
                        if (v == 0)
1094
 
                        {
1095
 
                            gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
1096
 
                        }
1097
 
                    }
1098
 
                    else
1099
 
                    {
1100
 
                        gp->faces[face].node1 =
1101
 
                            base + (((u - 2) * (u - 1)) / 2) + v - 1;
1102
 
                        gp->faces[face].node2 =
1103
 
                            base + (((u - 2) * (u - 1)) / 2) + v;
1104
 
                        gp->faces[face].node3 = base + (((u - 1) * u) / 2) + v;
1105
 
 
1106
 
                        if (v == 0)
1107
 
                        {
1108
 
                            gp->faces[face].node1 = base2 + (u * (u + 1)) / 2 - 1;
1109
 
                        }
1110
 
                        if (u == (nodes_on_edge - 2))
1111
 
                        {
1112
 
                            gp->faces[face].node3 =
1113
 
                                ((nodes_on_edge * (nodes_on_edge + 1)) / 2) +
1114
 
                                ((v + 2) * (v + 3)) / 2 - 1;
1115
 
                        }
1116
 
                        if (v == (u - 1))
1117
 
                        {
1118
 
                            gp->faces[face].node2 = (u * (u + 1)) / 2;
1119
 
                        }
1120
 
                    }
1121
 
                    face++;
 
1019
                  {
 
1020
                    gp->faces[face].node1 =
 
1021
                      base + (((u - 2) * (u - 1)) / 2) + v - 1;
 
1022
                    gp->faces[face].node2 = base + ((u - 1) * u) / 2 + v;
 
1023
                    gp->faces[face].node3 = base + ((u - 1) * u) / 2 + v - 1;
 
1024
 
 
1025
                    if (v == 0)
 
1026
                      {
 
1027
                        gp->faces[face].node1 =
 
1028
                          base2 + ((u * (u + 1)) / 2) - 1;
 
1029
                        gp->faces[face].node3 =
 
1030
                          base2 + ((u + 1) * (u + 2)) / 2 - 1;
 
1031
                      }
 
1032
                    if (u == (nodes_on_edge - 2))
 
1033
                      {
 
1034
                        gp->faces[face].node3 =
 
1035
                          ((nodes_on_edge *
 
1036
                            (nodes_on_edge + 1)) / 2) +
 
1037
                          ((v + 1) * (v + 2)) / 2 - 1;
 
1038
                        gp->faces[face].node2 =
 
1039
                          ((nodes_on_edge *
 
1040
                            (nodes_on_edge + 1)) / 2) +
 
1041
                          ((v + 2) * (v + 3)) / 2 - 1;
 
1042
                      }
 
1043
                    if (v == u)
 
1044
                      {
 
1045
                        gp->faces[face].node1 = (u * (u + 1)) / 2;
 
1046
                        gp->faces[face].node2 = ((u + 1) * (u + 2)) / 2;
 
1047
                      }
 
1048
                  }
 
1049
                face++;
 
1050
              }
 
1051
 
 
1052
              if (v < u)
 
1053
                {
 
1054
                  if (side < 2)
 
1055
                    {
 
1056
                      gp->faces[face].node1 = base + ((u * (u + 1)) / 2) + v;
 
1057
                      gp->faces[face].node2 =
 
1058
                        base + ((u * (u + 1)) / 2) + v + 1;
 
1059
                      gp->faces[face].node3 =
 
1060
                        base + (((u + 1) * (u + 2)) / 2) + v + 1;
 
1061
 
 
1062
                      if ((side == 1) && (u == (nodes_on_edge - 2)))
 
1063
                        {
 
1064
                          gp->faces[face].node3 =
 
1065
                            ((u + 1) * (u + 2)) / 2 +
 
1066
                            nodes_on_edge - v - 2;
 
1067
                        }
 
1068
                    }
 
1069
                  else if (side < 3)
 
1070
                    {
 
1071
                      gp->faces[face].node1 =
 
1072
                        base + ((u * (u - 1)) / 2) + v - 1;
 
1073
                      gp->faces[face].node2 = base + ((u * (u - 1)) / 2) + v;
 
1074
                      gp->faces[face].node3 = base + ((u * (u + 1)) / 2) + v;
 
1075
 
 
1076
                      if (u == (nodes_on_edge - 2))
 
1077
                        {
 
1078
                          int n = nodes_on_edge - v - 1;
 
1079
                          gp->faces[face].node3 =
 
1080
                            ((nodes_on_edge *
 
1081
                              (nodes_on_edge + 1)) / 2) +
 
1082
                            ((n + 0) * (n - 1)) / 2;
 
1083
                        }
 
1084
                      if (v == 0)
 
1085
                        {
 
1086
                          gp->faces[face].node1 = (((u + 1) * (u + 2)) / 2) - 1;
 
1087
                        }
 
1088
                    }
 
1089
                  else
 
1090
                    {
 
1091
                      gp->faces[face].node1 =
 
1092
                        base + (((u - 2) * (u - 1)) / 2) + v - 1;
 
1093
                      gp->faces[face].node2 =
 
1094
                        base + (((u - 2) * (u - 1)) / 2) + v;
 
1095
                      gp->faces[face].node3 = base + (((u - 1) * u) / 2) + v;
 
1096
 
 
1097
                      if (v == 0)
 
1098
                        {
 
1099
                          gp->faces[face].node1 = base2 + (u * (u + 1)) / 2 - 1;
 
1100
                        }
 
1101
                      if (u == (nodes_on_edge - 2))
 
1102
                        {
 
1103
                          gp->faces[face].node3 =
 
1104
                            ((nodes_on_edge * (nodes_on_edge + 1)) / 2) +
 
1105
                            ((v + 2) * (v + 3)) / 2 - 1;
 
1106
                        }
 
1107
                      if (v == (u - 1))
 
1108
                        {
 
1109
                          gp->faces[face].node2 = (u * (u + 1)) / 2;
 
1110
                        }
 
1111
                    }
 
1112
                  face++;
1122
1113
                }
1123
1114
            }
1124
1115
        }
1125
1116
    }
1126
1117
 
1127
 
    return 0;
 
1118
  return 0;
1128
1119
}
1129
1120
 
1130
1121
/******************************************************************************
1134
1125
static inline double
1135
1126
length (Vector3D u)
1136
1127
{
1137
 
    return sqrt (u.x * u.x + u.y * u.y + u.z * u.z);
 
1128
  return sqrt (u.x * u.x + u.y * u.y + u.z * u.z);
1138
1129
}
1139
1130
 
1140
1131
/******************************************************************************
1149
1140
          float limit,
1150
1141
          double fade)
1151
1142
{
1152
 
    /* Loop variables */
1153
 
    int i, index, face;
1154
 
    /* position of a node */
1155
 
    Vector3D node;
1156
 
    Vector3D offset;
1157
 
    Vector3D bump_vector;
1158
 
    int dist;
1159
 
 
1160
 
    /* Update position and strength of bumps used to distort the blob */
1161
 
    for (i = 0; i < bumps; i++)
1162
 
    {
1163
 
        gp->bump_data[i].vx += gp->bump_data[i].mx*(gp->bump_data[i].cx - gp->bump_data[i].ax);
1164
 
        gp->bump_data[i].vy += gp->bump_data[i].my*(gp->bump_data[i].cy - gp->bump_data[i].ay);
1165
 
        gp->bump_data[i].vpower += gp->bump_data[i].mpower
1166
 
            * (gp->bump_data[i].cpower - gp->bump_data[i].power);
1167
 
        gp->bump_data[i].vsize += gp->bump_data[i].msize
1168
 
            * (gp->bump_data[i].csize - gp->bump_data[i].size);
1169
 
 
1170
 
        gp->bump_data[i].ax += 0.1 * gp->bump_data[i].vx;
1171
 
        gp->bump_data[i].ay += 0.1 * gp->bump_data[i].vy;
1172
 
        gp->bump_data[i].power += 0.1 * gp->bump_data[i].vpower;
1173
 
        gp->bump_data[i].size += 0.1 * gp->bump_data[i].vsize;
1174
 
 
1175
 
        gp->bump_data[i].pos.x = 1.0 * sin(PI * gp->bump_data[i].ay)
1176
 
            * cos(PI * gp->bump_data[i].ax);
1177
 
        gp->bump_data[i].pos.y = 1.0 * cos(PI * gp->bump_data[i].ay);
1178
 
        gp->bump_data[i].pos.z = 1.0 * sin(PI * gp->bump_data[i].ay)
1179
 
            * sin(PI * gp->bump_data[i].ax);
1180
 
    }
1181
 
 
1182
 
    /* Update calculate new position for each vertex based on an offset from
1183
 
     * the initial position
1184
 
     */
1185
 
    gp->blob_force = zero_vector;
1186
 
    for (index = 0; index < gp->num_nodes; ++index)
1187
 
    {
1188
 
        node = gp->nodes[index].initial_position;
1189
 
        gp->nodes[index].normal = zero_vector;
1190
 
 
1191
 
        offset = zero_vector;
1192
 
        for ( i = 0; i < bumps; i++)
1193
 
        {
1194
 
            bump_vector = subtract(gp->bump_data[i].pos, node);
1195
 
 
1196
 
            dist = bump_array_size * dot(bump_vector, bump_vector) * gp->bump_data[i].size;
1197
 
 
1198
 
            if (dist < bump_array_size)
1199
 
            {
1200
 
                add(&offset, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1201
 
                add(&gp->blob_force, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
1202
 
            }
1203
 
        }
1204
 
 
1205
 
        add(&node, offset);
1206
 
        node = scale(node, zoom);
1207
 
        add(&node, gp->blob_center);
1208
 
 
1209
 
        if (do_walls)
1210
 
        {
1211
 
            if (node.z < -limit) node.z = -limit;
1212
 
            if (node.z > limit) node.z = limit;
1213
 
 
1214
 
            dist = bump_array_size * (node.z + limit) * (node.z + limit) * 0.5;
1215
 
            if (dist < bump_array_size)
1216
 
            {
1217
 
                node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1218
 
                node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1219
 
                gp->blob_force.z += (node.z + limit);
1220
 
            }
1221
 
            else
1222
 
            {
1223
 
                dist = bump_array_size * (node.z - limit) * (node.z - limit) * 0.5;
1224
 
                if (dist < bump_array_size)
1225
 
                {
1226
 
                    node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1227
 
                    node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1228
 
                    gp->blob_force.z -= (node.z - limit);
1229
 
                }
1230
 
 
1231
 
                if (node.y < -limit) node.y = -limit;
1232
 
                if (node.y > limit) node.y = limit;
1233
 
 
1234
 
                dist = bump_array_size * (node.y + limit) * (node.y + limit) * 0.5;
1235
 
                if (dist < bump_array_size)
1236
 
                {
1237
 
                    node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1238
 
                    node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1239
 
                    gp->blob_force.y += (node.y + limit);
1240
 
                }
1241
 
                else
1242
 
                {
1243
 
                    dist = bump_array_size * (node.y - limit) * (node.y - limit) * 0.5;
1244
 
                    if (dist < bump_array_size)
1245
 
                    {
1246
 
                        node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
1247
 
                        node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1248
 
                        gp->blob_force.y -= (node.y - limit);
1249
 
                    }
1250
 
                }
1251
 
 
1252
 
                if (node.x < -limit) node.x = -limit;
1253
 
                if (node.x > limit) node.x = limit;
1254
 
 
1255
 
                dist = bump_array_size * (node.x + limit) * (node.x + limit) * 0.5;
1256
 
                if (dist < bump_array_size)
1257
 
                {
1258
 
                    node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1259
 
                    node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1260
 
                    gp->blob_force.x += (node.x + limit);
1261
 
                }
1262
 
                else
1263
 
                {
1264
 
                    dist = bump_array_size * (node.x - limit) * (node.x - limit) * 0.5;
1265
 
                    if (dist < bump_array_size)
1266
 
                    {
1267
 
                        node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
1268
 
                        node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
1269
 
                        gp->blob_force.x -= (node.x - limit);
1270
 
                    }
1271
 
                }
1272
 
 
1273
 
                if (node.y < -limit) node.y = -limit;
1274
 
                if (node.y > limit) node.y = limit;
1275
 
            }
1276
 
        }
1277
 
        gp->dots[index] = node;
1278
 
    }
1279
 
 
1280
 
    /* Determine the normal for each face */
1281
 
    for (face = 0; face < gp->num_faces; face++)
1282
 
    {
1283
 
        /* Use nodeers to indexed nodes to help readability */
1284
 
        Node_Data *node1 = &gp->nodes[gp->faces[face].node1];
1285
 
        Node_Data *node2 = &gp->nodes[gp->faces[face].node2];
1286
 
        Node_Data *node3 = &gp->nodes[gp->faces[face].node3];
1287
 
 
1288
 
        gp->faces[face].normal = cross(subtract(node2->position, node1->position),
1289
 
                                       subtract(node3->position, node1->position));
 
1143
  /* Loop variables */
 
1144
  int i, index, face;
 
1145
  /* position of a node */
 
1146
  Vector3D node;
 
1147
  Vector3D offset;
 
1148
  Vector3D bump_vector;
 
1149
  int dist;
 
1150
 
 
1151
  /* Update position and strength of bumps used to distort the blob */
 
1152
  for (i = 0; i < bumps; i++)
 
1153
    {
 
1154
      gp->bump_data[i].vx += gp->bump_data[i].mx*(gp->bump_data[i].cx - gp->bump_data[i].ax);
 
1155
      gp->bump_data[i].vy += gp->bump_data[i].my*(gp->bump_data[i].cy - gp->bump_data[i].ay);
 
1156
      gp->bump_data[i].vpower += gp->bump_data[i].mpower
 
1157
        * (gp->bump_data[i].cpower - gp->bump_data[i].power);
 
1158
      gp->bump_data[i].vsize += gp->bump_data[i].msize
 
1159
        * (gp->bump_data[i].csize - gp->bump_data[i].size);
 
1160
 
 
1161
      gp->bump_data[i].ax += 0.1 * gp->bump_data[i].vx;
 
1162
      gp->bump_data[i].ay += 0.1 * gp->bump_data[i].vy;
 
1163
      gp->bump_data[i].power += 0.1 * gp->bump_data[i].vpower;
 
1164
      gp->bump_data[i].size += 0.1 * gp->bump_data[i].vsize;
 
1165
 
 
1166
      gp->bump_data[i].pos.x = 1.0 * sin(PI * gp->bump_data[i].ay)
 
1167
        * cos(PI * gp->bump_data[i].ax);
 
1168
      gp->bump_data[i].pos.y = 1.0 * cos(PI * gp->bump_data[i].ay);
 
1169
      gp->bump_data[i].pos.z = 1.0 * sin(PI * gp->bump_data[i].ay)
 
1170
        * sin(PI * gp->bump_data[i].ax);
 
1171
    }
 
1172
 
 
1173
  /* Update calculate new position for each vertex based on an offset from
 
1174
   * the initial position
 
1175
   */
 
1176
  gp->blob_force = zero_vector;
 
1177
  for (index = 0; index < gp->num_nodes; ++index)
 
1178
    {
 
1179
      node = gp->nodes[index].initial_position;
 
1180
      gp->nodes[index].normal = node;
 
1181
 
 
1182
      offset = zero_vector;
 
1183
      for ( i = 0; i < bumps; i++)
 
1184
        {
 
1185
          bump_vector = subtract(gp->bump_data[i].pos, node);
 
1186
 
 
1187
          dist = bump_array_size * dot(bump_vector, bump_vector) * gp->bump_data[i].size;
 
1188
 
 
1189
          if (dist < bump_array_size)
 
1190
            {
 
1191
              add(&offset, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
 
1192
              add(&gp->blob_force, scale(node, gp->bump_data[i].power * gp->bump_shape[dist]));
 
1193
            }
 
1194
        }
 
1195
 
 
1196
      add(&node, offset);
 
1197
      node = scale(node, zoom);
 
1198
      add(&node, gp->blob_center);
 
1199
 
 
1200
      if (do_walls)
 
1201
        {
 
1202
          if (node.z < -limit) node.z = -limit;
 
1203
          if (node.z > limit) node.z = limit;
 
1204
 
 
1205
          dist = bump_array_size * (node.z + limit) * (node.z + limit) * 0.5;
 
1206
          if (dist < bump_array_size)
 
1207
            {
 
1208
              node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
 
1209
              node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
 
1210
              gp->blob_force.z += (node.z + limit);
 
1211
            }
 
1212
          else
 
1213
            {
 
1214
              dist = bump_array_size * (node.z - limit) * (node.z - limit) * 0.5;
 
1215
              if (dist < bump_array_size)
 
1216
                {
 
1217
                  node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
 
1218
                  node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
 
1219
                  gp->blob_force.z -= (node.z - limit);
 
1220
                }
 
1221
 
 
1222
              if (node.y < -limit) node.y = -limit;
 
1223
              if (node.y > limit) node.y = limit;
 
1224
 
 
1225
              dist = bump_array_size * (node.y + limit) * (node.y + limit) * 0.5;
 
1226
              if (dist < bump_array_size)
 
1227
                {
 
1228
                  node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
 
1229
                  node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
 
1230
                  gp->blob_force.y += (node.y + limit);
 
1231
                }
 
1232
              else
 
1233
                {
 
1234
                  dist = bump_array_size * (node.y - limit) * (node.y - limit) * 0.5;
 
1235
                  if (dist < bump_array_size)
 
1236
                    {
 
1237
                      node.x += (node.x - gp->blob_center.x) * gp->wall_shape[dist];
 
1238
                      node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
 
1239
                      gp->blob_force.y -= (node.y - limit);
 
1240
                    }
 
1241
                }
 
1242
 
 
1243
              if (node.x < -limit) node.x = -limit;
 
1244
              if (node.x > limit) node.x = limit;
 
1245
 
 
1246
              dist = bump_array_size * (node.x + limit) * (node.x + limit) * 0.5;
 
1247
              if (dist < bump_array_size)
 
1248
                {
 
1249
                  node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
 
1250
                  node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
 
1251
                  gp->blob_force.x += (node.x + limit);
 
1252
                }
 
1253
              else
 
1254
                {
 
1255
                  dist = bump_array_size * (node.x - limit) * (node.x - limit) * 0.5;
 
1256
                  if (dist < bump_array_size)
 
1257
                    {
 
1258
                      node.y += (node.y - gp->blob_center.y) * gp->wall_shape[dist];
 
1259
                      node.z += (node.z - gp->blob_center.z) * gp->wall_shape[dist];
 
1260
                      gp->blob_force.x -= (node.x - limit);
 
1261
                    }
 
1262
                }
 
1263
 
 
1264
              if (node.y < -limit) node.y = -limit;
 
1265
              if (node.y > limit) node.y = limit;
 
1266
            }
 
1267
        }
 
1268
      gp->dots[index] = node;
 
1269
    }
 
1270
 
 
1271
  /* Determine the normal for each face */
 
1272
  for (face = 0; face < gp->num_faces; face++)
 
1273
    {
 
1274
      /* Use pointers to indexed nodes to help readability */
 
1275
      int index1 = gp->faces[face].node1;
 
1276
      int index2 = gp->faces[face].node2;
 
1277
      int index3 = gp->faces[face].node3;
 
1278
 
 
1279
      gp->faces[face].normal = cross(subtract(gp->dots[index2], gp->dots[index1]),
 
1280
                                     subtract(gp->dots[index3], gp->dots[index1]));
1290
1281
            
1291
 
        /* Add the normal for the face onto the normal for the verticies of
1292
 
           the face */
1293
 
        add(&node1->normal, gp->faces[face].normal);
1294
 
        add(&node2->normal, gp->faces[face].normal);
1295
 
        add(&node3->normal, gp->faces[face].normal);
 
1282
      /* Add the normal for the face onto the normal for the verticies of
 
1283
         the face */
 
1284
      add(&gp->nodes[index1].normal, gp->faces[face].normal);
 
1285
      add(&gp->nodes[index2].normal, gp->faces[face].normal);
 
1286
      add(&gp->nodes[index3].normal, gp->faces[face].normal);
1296
1287
    }
1297
1288
 
1298
 
    /* Use the normal to set the colour and texture */
1299
 
    if (do_colour || do_texture)
 
1289
  /* Use the normal to set the colour and texture */
 
1290
  if (do_colour || do_texture)
1300
1291
    {
1301
 
        for (index = 0; index < gp->num_nodes; ++index)
 
1292
      for (index = 0; index < gp->num_nodes; ++index)
1302
1293
        {
1303
 
            gp->normals[index] = normalise(gp->nodes[index].normal);
 
1294
          gp->normals[index] = normalise(gp->nodes[index].normal);
1304
1295
   
1305
 
            if (do_colour)
 
1296
          if (do_colour)
1306
1297
            {
1307
 
                gp->colours[index].red = (int)(255.0 * fabs(gp->normals[index].x));
1308
 
                gp->colours[index].green = (int)(255.0 * fabs(gp->normals[index].y));
1309
 
                gp->colours[index].blue = (int)(255.0 * fabs(gp->normals[index].z));
1310
 
                gp->colours[index].alpha = (int)(255.0 * fade);
 
1298
              gp->colours[index].red = (int)(255.0 * fabs(gp->normals[index].x));
 
1299
              gp->colours[index].green = (int)(255.0 * fabs(gp->normals[index].y));
 
1300
              gp->colours[index].blue = (int)(255.0 * fabs(gp->normals[index].z));
 
1301
              gp->colours[index].alpha = (int)(255.0 * fade);
1311
1302
            }
1312
 
            if (do_texture)
 
1303
          if (do_texture)
1313
1304
            {
1314
 
                if (offset_texture)
1315
 
                {
1316
 
                    gp->tex_coords[index].x = gp->dots[index].x * 0.125 + 0.5
1317
 
                        * (1.0 + 0.25 * asin(gp->normals[index].x) / (0.5 * PI));
1318
 
                    gp->tex_coords[index].y = -gp->dots[index].y * 0.125 - 0.5
1319
 
                        * (1.0 + 0.25 * asin(gp->normals[index].y) / (0.5 * PI));
1320
 
                }
1321
 
                else
1322
 
                {
1323
 
                    gp->tex_coords[index].x = 0.5
1324
 
                        * (1.0 + asin(gp->normals[index].x) / (0.5 * PI));
1325
 
                    gp->tex_coords[index].y = -0.5
1326
 
                        * (1.0 + asin(gp->normals[index].y) / (0.5 * PI));
1327
 
                }
1328
 
                /* Adjust the texture co-ordinates to from range 0..1 to
1329
 
                 * 0..width or 0..height as appropriate
1330
 
                 */
1331
 
                gp->tex_coords[index].x *= gp->tex_width[gp->current_texture];
1332
 
                gp->tex_coords[index].y *= gp->tex_height[gp->current_texture];
 
1305
              if (offset_texture)
 
1306
                {
 
1307
                  const float cube_size = 100.0;
 
1308
                  Vector3D eye = {0.0, 0.0, 50.0};
 
1309
                  Vector3D eye_r = normalise(subtract(gp->dots[index], eye));
 
1310
                  Vector3D reference = subtract(eye_r, scale(gp->normals[index], 2.0 * dot(eye_r, gp->normals[index])));
 
1311
                  double x = 0.0;
 
1312
                  double y = 0.0;
 
1313
                  double n, n_min = 10000.0, sign = 1.0;
 
1314
                  if (fabs(reference.z) > 1e-9)
 
1315
                    {
 
1316
                      n = (cube_size - gp->dots[index].z) / reference.z;
 
1317
                      if (n < 0.0)
 
1318
                        {
 
1319
                          n = (-cube_size - gp->dots[index].z) / reference.z;
 
1320
                          sign = 3.0;
 
1321
                        }
 
1322
                      if (n > 0.0)
 
1323
                        {
 
1324
                          x = sign * (gp->dots[index].x + n * reference.x);
 
1325
                          y = sign * (gp->dots[index].y + n * reference.y);
 
1326
                          n_min = n;
 
1327
                        }
 
1328
                    }
 
1329
                  if (fabs(reference.x) > 1e-9)
 
1330
                    {
 
1331
                      n = (cube_size - gp->dots[index].x) / reference.x;
 
1332
                      sign = 1.0;
 
1333
                      if (n < 0.0)
 
1334
                        {
 
1335
                          n = (-cube_size - gp->dots[index].x) / reference.x;
 
1336
                          sign = -1.0;
 
1337
                        }
 
1338
                      if ((n > 0.0) && (n < n_min))
 
1339
                        {
 
1340
                          x = sign * (2.0 * cube_size - (gp->dots[index].z + n * reference.z));
 
1341
                          y = sign * x * (gp->dots[index].y + n * reference.y) / cube_size;
 
1342
                          n_min = n;
 
1343
                        }
 
1344
                    }
 
1345
                  if (fabs(reference.y) > 1e-9)
 
1346
                    {
 
1347
                      n = (cube_size - gp->dots[index].y) / reference.y;
 
1348
                      sign = 1.0;
 
1349
                      if (n < 0.0)
 
1350
                        {
 
1351
                          n = (-cube_size - gp->dots[index].y) / reference.y;
 
1352
                          sign = -1.0;
 
1353
                        }
 
1354
                      if ((n > 0.0) && (n < n_min))
 
1355
                        {
 
1356
                          y = sign * (2.0 * cube_size -( gp->dots[index].z + n * reference.z));
 
1357
                          x = sign * y * (gp->dots[index].x + n * reference.x) / cube_size;
 
1358
                        }
 
1359
                    }
 
1360
                                        
 
1361
                  gp->tex_coords[index].x = 0.5 + x / (cube_size * 6.0);
 
1362
                  gp->tex_coords[index].y = 0.5 - y / (cube_size * 6.0);
 
1363
                }
 
1364
              else
 
1365
                {
 
1366
                  gp->tex_coords[index].x = 0.5
 
1367
                    * (1.0 + asin(gp->normals[index].x) / (0.5 * PI));
 
1368
                  gp->tex_coords[index].y = -0.5
 
1369
                    * (1.0 + asin(gp->normals[index].y) / (0.5 * PI));
 
1370
                }
 
1371
              /* Adjust the texture co-ordinates to from range 0..1 to
 
1372
               * 0..width or 0..height as appropriate
 
1373
               */
 
1374
              gp->tex_coords[index].x *= gp->tex_width[gp->current_texture];
 
1375
              gp->tex_coords[index].y *= gp->tex_height[gp->current_texture];
1333
1376
            }
1334
1377
        }
1335
1378
    }
1336
1379
    
1337
 
    /* Update the center of the whole blob */
1338
 
    add(&gp->blob_velocity, scale (subtract (gp->blob_anchor, gp->blob_center), 1.0 / 80.0));
1339
 
    add(&gp->blob_velocity, scale (gp->blob_force, 0.01 / gp->num_nodes));
1340
 
 
1341
 
    add(&gp->blob_center, scale(gp->blob_velocity, 0.5));
1342
 
 
1343
 
    gp->blob_velocity = scale(gp->blob_velocity, 0.999);
 
1380
  /* Update the center of the whole blob */
 
1381
  add(&gp->blob_velocity, scale (subtract (gp->blob_anchor, gp->blob_center), 1.0 / 80.0));
 
1382
  add(&gp->blob_velocity, scale (gp->blob_force, 0.01 / gp->num_nodes));
 
1383
 
 
1384
  add(&gp->blob_center, scale(gp->blob_velocity, 0.5));
 
1385
 
 
1386
  gp->blob_velocity = scale(gp->blob_velocity, 0.999);
 
1387
}
 
1388
 
 
1389
static void
 
1390
draw_vertex(mirrorblobstruct *gp, int index)
 
1391
{
 
1392
  if (do_colour)
 
1393
    {
 
1394
      glColor3ub(gp->colours[index].red,
 
1395
                 gp->colours[index].green,
 
1396
                 gp->colours[index].blue);
 
1397
    }
 
1398
  if (load_textures)
 
1399
    {
 
1400
      glTexCoord3dv((GLdouble *) &gp->tex_coords[index]);
 
1401
    }
 
1402
  glNormal3dv((GLdouble *) &gp->normals[index]);
 
1403
  glVertex3dv((GLdouble *) &gp->dots[index]);
1344
1404
}
1345
1405
 
1346
1406
/******************************************************************************
1351
1411
static void
1352
1412
draw_blob (mirrorblobstruct *gp)
1353
1413
{
1354
 
    int face;
1355
 
 
1356
 
    glMatrixMode (GL_MODELVIEW);
1357
 
    glLoadIdentity ();
1358
 
 
1359
 
    /* Move down the z-axis. */
1360
 
    glTranslatef (0.0, 0.0, -4.0);
1361
 
 
1362
 
    gltrackball_rotate (gp->trackball);
1363
 
 
1364
 
    /* glColor4ub (255, 0, 0, 128); */
1365
 
    glBegin (GL_TRIANGLES);
1366
 
    for (face = 0; face < gp->num_faces; face++)
1367
 
    {
1368
 
        glArrayElement (gp->faces[face].node1);
1369
 
        glArrayElement (gp->faces[face].node2);
1370
 
        glArrayElement (gp->faces[face].node3);
1371
 
    }
1372
 
    glEnd ();
1373
 
    glLoadIdentity ();
 
1414
  int face;
 
1415
 
 
1416
  glMatrixMode(GL_MODELVIEW);
 
1417
  glLoadIdentity();
 
1418
 
 
1419
  /* Move down the z-axis. */
 
1420
  glTranslatef (0.0, 0.0, -4.0);
 
1421
 
 
1422
  gltrackball_rotate (gp->trackball);
 
1423
 
 
1424
  /* glColor4ub (255, 0, 0, 128); */
 
1425
  glBegin(GL_TRIANGLES);
 
1426
  for (face = 0; face < gp->num_faces; face++)
 
1427
    {
 
1428
      draw_vertex(gp, gp->faces[face].node1);
 
1429
      draw_vertex(gp, gp->faces[face].node2);
 
1430
      draw_vertex(gp, gp->faces[face].node3);
 
1431
    }
 
1432
  glEnd();
 
1433
 
 
1434
#if 0
 
1435
  glBegin(GL_LINES);
 
1436
  for (face = 0; face < gp->num_faces; face++)
 
1437
    {
 
1438
      if (gp->normals[gp->faces[face].node1].z > 0.0)
 
1439
        {
 
1440
          Vector3D end = gp->dots[gp->faces[face].node1];
 
1441
          glVertex3dv((GLdouble *) &end);
 
1442
          add(&end, scale(gp->normals[gp->faces[face].node1], 0.25));
 
1443
          glVertex3dv((GLdouble *) &end);
 
1444
        }
 
1445
    }
 
1446
  glEnd();
 
1447
#endif
 
1448
        
 
1449
  glLoadIdentity();
1374
1450
}
1375
1451
 
1376
1452
/******************************************************************************
1380
1456
static void
1381
1457
draw_background (ModeInfo *mi)
1382
1458
{
1383
 
    mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1384
 
    
1385
 
    glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
1386
 
    glEnable (GL_TEXTURE_2D);
1387
 
    glDisable(GL_LIGHTING);
1388
 
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1389
 
 
1390
 
    /* Reset the projection matrix to make it easier to get the size of the quad
1391
 
     * correct
1392
 
     */
1393
 
    glMatrixMode(GL_PROJECTION);
1394
 
    glPushMatrix();
1395
 
    glLoadIdentity();
1396
 
 
1397
 
    glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
1398
 
 
1399
 
    glBegin (GL_QUADS);
1400
 
    
1401
 
    glTexCoord2f (0.0, 0.0);
1402
 
    glVertex2i (0, 0);
1403
 
    
1404
 
    glTexCoord2f (0.0, gp->tex_height[gp->current_texture]);
1405
 
    glVertex2i (0, MI_HEIGHT(mi));
1406
 
 
1407
 
    glTexCoord2f (gp->tex_width[gp->current_texture], gp->tex_height[gp->current_texture]);
1408
 
    glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
1409
 
 
1410
 
    glTexCoord2f (gp->tex_width[gp->current_texture], 0.0);
1411
 
    glVertex2i (MI_WIDTH(mi), 0);
1412
 
    glEnd();
1413
 
 
1414
 
    glPopMatrix ();
1415
 
    glMatrixMode (GL_MODELVIEW);
1416
 
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
1459
  mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
 
1460
    
 
1461
  glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 
1462
  glEnable (GL_TEXTURE_2D);
 
1463
  glDisable(GL_LIGHTING);
 
1464
  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 
1465
 
 
1466
  /* Reset the projection matrix to make it easier to get the size of the quad
 
1467
   * correct
 
1468
   */
 
1469
  glMatrixMode(GL_PROJECTION);
 
1470
  glPushMatrix();
 
1471
  glLoadIdentity();
 
1472
 
 
1473
  glOrtho(0.0, MI_WIDTH(mi), MI_HEIGHT(mi), 0.0, -1000.0, 1000.0);
 
1474
 
 
1475
  glBegin (GL_QUADS);
 
1476
    
 
1477
  glTexCoord2f (0.0, 0.0);
 
1478
  glVertex2i (0, 0);
 
1479
    
 
1480
  glTexCoord2f (0.0, gp->tex_height[gp->current_texture]);
 
1481
  glVertex2i (0, MI_HEIGHT(mi));
 
1482
 
 
1483
  glTexCoord2f (gp->tex_width[gp->current_texture], gp->tex_height[gp->current_texture]);
 
1484
  glVertex2i (MI_WIDTH(mi), MI_HEIGHT(mi));
 
1485
 
 
1486
  glTexCoord2f (gp->tex_width[gp->current_texture], 0.0);
 
1487
  glVertex2i (MI_WIDTH(mi), 0);
 
1488
  glEnd();
 
1489
 
 
1490
  glPopMatrix ();
 
1491
  glMatrixMode (GL_MODELVIEW);
 
1492
  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
1417
1493
}
1418
1494
 
1419
1495
/******************************************************************************
1423
1499
static GLvoid
1424
1500
draw_scene(ModeInfo * mi)
1425
1501
{
1426
 
    mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
 
1502
  mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1427
1503
    
1428
 
    double fade = 0.0;
1429
 
    double current_time;
1430
 
    check_gl_error ("draw_scene");
1431
 
 
1432
 
    mi->polygon_count = 0;
1433
 
    glColor4d(1.0, 1.0, 1.0, 1.0);
1434
 
 
1435
 
    current_time = double_time();
1436
 
    switch (gp->state)
 
1504
  double fade = 0.0;
 
1505
  double current_time;
 
1506
  check_gl_error ("draw_scene");
 
1507
 
 
1508
  mi->polygon_count = 0;
 
1509
  glColor4d(1.0, 1.0, 1.0, 1.0);
 
1510
 
 
1511
  current_time = double_time();
 
1512
  switch (gp->state)
1437
1513
    {
 
1514
    case INITIALISING:
 
1515
      glColor4d(0.0, 0.0, 0.0, 1.0);
 
1516
      fade = 1.0;
 
1517
      break;
 
1518
 
1438
1519
    case TRANSITIONING:
1439
 
        fade = 1.0 - (current_time - gp->state_start_time) / fade_time;
1440
 
        break;
 
1520
      fade = 1.0 - (current_time - gp->state_start_time) / fade_time;
 
1521
      break;
1441
1522
 
1442
1523
    case LOADING: /* FALL-THROUGH */
1443
1524
    case HOLDING:
1444
 
        fade = 1.0;
1445
 
        break;
1446
 
    }
1447
 
 
1448
 
    /* Set the correct texture, when transitioning this ensures that the first draw
1449
 
     * is the original texture (which has the new texture drawn over it with decreasing
1450
 
     * transparency)
1451
 
     */
1452
 
    if (load_textures)
1453
 
    {
1454
 
        glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1455
 
    }
1456
 
 
1457
 
    glDisable (GL_DEPTH_TEST);
1458
 
    if (do_paint_background)
1459
 
    {
1460
 
        glEnable (GL_TEXTURE_2D);
1461
 
        if (motion_blur > 0.0)
1462
 
        {
1463
 
            glClear(GL_DEPTH_BUFFER_BIT);
1464
 
            glEnable (GL_BLEND);
1465
 
            glColor4d (1.0, 1.0, 1.0, motion_blur);
1466
 
        }
1467
 
        else
1468
 
        {
1469
 
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1470
 
        }
1471
 
        draw_background (mi);
1472
 
        mi->polygon_count++;
1473
 
 
1474
 
        /* When transitioning between two images paint the new image over the old
1475
 
         * image with a varying alpha value to get a smooth fade.
1476
 
         */
1477
 
        if (gp->state == TRANSITIONING)
1478
 
        {
1479
 
            glEnable (GL_BLEND);
1480
 
            /* Select the texture to transition to */
1481
 
            glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1482
 
            glColor4d (1.0, 1.0, 1.0, 1.0 - fade);
1483
 
 
1484
 
            draw_background (mi);
1485
 
            mi->polygon_count++;
1486
 
 
1487
 
            /* Select the original texture to draw the blob */
1488
 
            glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
1489
 
        }
1490
 
        /* Clear the depth buffer bit so the backgound is behind the blob */
1491
 
        glClear(GL_DEPTH_BUFFER_BIT);
1492
 
    }
1493
 
    else if (motion_blur > 0.0)
1494
 
    {
1495
 
        glEnable (GL_BLEND);
1496
 
        glColor4d (0.0, 0.0, 0.0, motion_blur);
1497
 
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
1498
 
        glTranslatef (0.0, 0.0, -4.0);
1499
 
        glRectd (-10.0, -10.0, 10.0, 10.0);
1500
 
        if (wireframe)
1501
 
        {
1502
 
            glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
1503
 
        }
1504
 
        glClear (GL_DEPTH_BUFFER_BIT);
1505
 
    }
1506
 
    else
1507
 
    {
1508
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1509
 
    }
1510
 
 
1511
 
    if (!do_texture)
1512
 
    {
1513
 
        fade = 1.0;
1514
 
        glDisable (GL_TEXTURE_2D);
1515
 
    }
1516
 
 
1517
 
    calc_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE, 2.5, fade * blend);
1518
 
 
1519
 
    set_blob_gl_state(fade * blend);
1520
 
 
1521
 
    if (blend < 1.0)
1522
 
    {
1523
 
        /* Disable the three colour chanels so that only the depth buffer is updated */
1524
 
        glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1525
 
        draw_blob(gp);
1526
 
        mi->polygon_count += gp->num_faces;
1527
 
        glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
1528
 
        glDepthFunc(GL_LEQUAL);
1529
 
    }
1530
 
    glDepthFunc(GL_LEQUAL);
1531
 
    draw_blob(gp);
1532
 
    mi->polygon_count += gp->num_faces;
1533
 
 
1534
 
    /* While transitioning between images draw a second blob with a modified
1535
 
     * alpha value.
1536
 
     */
1537
 
    if (load_textures && (hold_time > 0))
1538
 
    {
1539
 
        switch (gp->state)
1540
 
        {
 
1525
      fade = 1.0;
 
1526
      break;
 
1527
    }
 
1528
 
 
1529
  /* Set the correct texture, when transitioning this ensures that the first draw
 
1530
   * is the original texture (which has the new texture drawn over it with decreasing
 
1531
   * transparency)
 
1532
   */
 
1533
  if (load_textures)
 
1534
    {
 
1535
      glBindTexture(GL_TEXTURE_2D, gp->textures[gp->current_texture]);
 
1536
    }
 
1537
 
 
1538
  glDisable (GL_DEPTH_TEST);
 
1539
  if (do_paint_background)
 
1540
    {
 
1541
      glEnable (GL_TEXTURE_2D);
 
1542
      if (motion_blur > 0.0)
 
1543
        {
 
1544
          glClear(GL_DEPTH_BUFFER_BIT);
 
1545
          glEnable (GL_BLEND);
 
1546
          glColor4d (1.0, 1.0, 1.0, motion_blur);
 
1547
        }
 
1548
      else
 
1549
        {
 
1550
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
1551
        }
 
1552
      draw_background (mi);
 
1553
      mi->polygon_count++;
 
1554
 
 
1555
      /* When transitioning between two images paint the new image over the old
 
1556
       * image with a varying alpha value to get a smooth fade.
 
1557
       */
 
1558
      if (gp->state == TRANSITIONING)
 
1559
        {
 
1560
          glEnable (GL_BLEND);
 
1561
          /* Select the texture to transition to */
 
1562
          glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
 
1563
          glColor4d (1.0, 1.0, 1.0, 1.0 - fade);
 
1564
 
 
1565
          draw_background (mi);
 
1566
          mi->polygon_count++;
 
1567
 
 
1568
          /* Select the original texture to draw the blob */
 
1569
          glBindTexture (GL_TEXTURE_2D, gp->textures[gp->current_texture]);
 
1570
        }
 
1571
      /* Clear the depth buffer bit so the backgound is behind the blob */
 
1572
      glClear(GL_DEPTH_BUFFER_BIT);
 
1573
    }
 
1574
  else if (motion_blur > 0.0)
 
1575
    {
 
1576
      glEnable (GL_BLEND);
 
1577
      glColor4d (0.0, 0.0, 0.0, motion_blur);
 
1578
      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 
1579
      glTranslatef (0.0, 0.0, -4.0);
 
1580
      glRectd (-10.0, -10.0, 10.0, 10.0);
 
1581
      if (wireframe)
 
1582
        {
 
1583
          glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 
1584
        }
 
1585
      glClear(GL_DEPTH_BUFFER_BIT);
 
1586
    }
 
1587
  else
 
1588
    {
 
1589
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
1590
    }
 
1591
 
 
1592
  if (!do_texture)
 
1593
    {
 
1594
      fade = 1.0;
 
1595
      glDisable (GL_TEXTURE_2D);
 
1596
    }
 
1597
 
 
1598
  calc_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE, 2.5, fade * blend);
 
1599
 
 
1600
  set_blob_gl_state(fade * blend);
 
1601
 
 
1602
  if (blend < 1.0)
 
1603
    {
 
1604
      /* Disable the colour chanels so that only the depth buffer is updated */
 
1605
      glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
 
1606
      draw_blob(gp);
 
1607
      mi->polygon_count += gp->num_faces;
 
1608
      glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
 
1609
    }
 
1610
        
 
1611
  glDepthFunc(GL_LEQUAL);
 
1612
  draw_blob(gp);
 
1613
  mi->polygon_count += gp->num_faces;
 
1614
 
 
1615
  /* While transitioning between images draw a second blob with a modified
 
1616
   * alpha value.
 
1617
   */
 
1618
  if (load_textures && (hold_time > 0))
 
1619
    {
 
1620
      switch (gp->state)
 
1621
        {
 
1622
        case INITIALISING:
 
1623
          if (!gp->waiting_for_image_p)
 
1624
            {
 
1625
              gp->state = HOLDING;
 
1626
            }
 
1627
          break;
 
1628
                
1541
1629
        case HOLDING:
1542
 
            if ((current_time - gp->state_start_time) > hold_time)
 
1630
          if ((current_time - gp->state_start_time) > hold_time)
1543
1631
            {
1544
 
                grab_texture(mi, 1 - gp->current_texture);
1545
 
                gp->state = LOADING;
 
1632
              grab_texture(mi, 1 - gp->current_texture);
 
1633
              gp->state = LOADING;
1546
1634
            }
1547
 
            break;
 
1635
          break;
1548
1636
 
1549
1637
        case LOADING:
1550
 
            /* Once the image has loaded move to the TRANSITIONING STATE */
1551
 
            if (!gp->waiting_for_image_p)
 
1638
          /* Once the image has loaded move to the TRANSITIONING STATE */
 
1639
          if (!gp->waiting_for_image_p)
1552
1640
            {
1553
 
                gp->state = TRANSITIONING;
1554
 
                /* Get the time again rather than using the current time so
1555
 
                 * that the time taken by the grab_texture function is not part
1556
 
                 * of the fade time
1557
 
                 */
1558
 
                gp->state_start_time = double_time();
 
1641
              gp->state = TRANSITIONING;
 
1642
              /* Get the time again rather than using the current time so
 
1643
               * that the time taken by the grab_texture function is not part
 
1644
               * of the fade time
 
1645
               */
 
1646
              gp->state_start_time = double_time();
1559
1647
            }
1560
 
            break;        
 
1648
          break;        
1561
1649
 
1562
1650
        case TRANSITIONING:
1563
1651
 
1564
 
            /* If the blob is textured draw over existing blob to fade between
1565
 
             * images
1566
 
             */
1567
 
            if (do_texture)
 
1652
          /* If the blob is textured draw over existing blob to fade between
 
1653
           * images
 
1654
           */
 
1655
          if (do_texture)
1568
1656
            {
1569
 
                /* Select the texture to transition to */
1570
 
                glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
1571
 
                glEnable (GL_BLEND);
 
1657
              /* Select the texture to transition to */
 
1658
              glBindTexture (GL_TEXTURE_2D, gp->textures[1 - gp->current_texture]);
 
1659
              glEnable (GL_BLEND);
1572
1660
                
1573
 
                /* If colour is enabled update the alpha data in the buffer and
1574
 
                 * use that in the blending since the alpha of the incomming
1575
 
                 * verticies will not be correct
1576
 
                 */
1577
 
                if (do_colour)
1578
 
                {
1579
 
                    glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
1580
 
                    glClearColor(0.0, 0.0, 0.0, (1.0 - fade) * blend);
1581
 
                    glClear(GL_COLOR_BUFFER_BIT);
1582
 
                    glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                    
1583
 
                    glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
1584
 
                }
1585
 
                else
1586
 
                {
1587
 
                    glColor4d(0.9, 0.9, 1.0, (1.0 - fade) * blend);
1588
 
                }
1589
 
 
1590
 
                draw_blob (gp);
1591
 
                mi->polygon_count += gp->num_faces;
1592
 
 
1593
 
                if (do_colour)
1594
 
                {
1595
 
                    /* Restore the 'standard' blend functions. */
1596
 
                    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 
1661
              /* If colour is enabled update the alpha data in the buffer and
 
1662
               * use that in the blending since the alpha of the incomming
 
1663
               * verticies will not be correct
 
1664
               */
 
1665
              if (do_colour)
 
1666
                {
 
1667
                  glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
 
1668
                  glClearColor(0.0, 0.0, 0.0, (1.0 - fade) * blend);
 
1669
                  glClear(GL_COLOR_BUFFER_BIT);
 
1670
                  glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);                    
 
1671
                  glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA);
 
1672
                }
 
1673
              else
 
1674
                {
 
1675
                  glColor4d(0.9, 0.9, 1.0, (1.0 - fade) * blend);
 
1676
                }
 
1677
 
 
1678
              draw_blob (gp);
 
1679
              mi->polygon_count += gp->num_faces;
 
1680
 
 
1681
              if (do_colour)
 
1682
                {
 
1683
                  /* Restore the 'standard' blend functions. */
 
1684
                  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1597
1685
                }
1598
1686
            }
1599
1687
            
1600
 
            if ((current_time - gp->state_start_time) > fade_time)
 
1688
          if ((current_time - gp->state_start_time) > fade_time)
1601
1689
            {
1602
 
                gp->state = HOLDING;
1603
 
                gp->state_start_time = current_time;
1604
 
                gp->current_texture = 1 - gp->current_texture;
 
1690
              gp->state = HOLDING;
 
1691
              gp->state_start_time = current_time;
 
1692
              gp->current_texture = 1 - gp->current_texture;
1605
1693
            }
1606
 
            break;
 
1694
          break;
1607
1695
 
1608
1696
        }
1609
1697
    }
1616
1704
ENTRYPOINT void
1617
1705
draw_mirrorblob(ModeInfo * mi)
1618
1706
{
1619
 
    mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
1620
 
    Display    *display = MI_DISPLAY(mi);
1621
 
    Window      window = MI_WINDOW(mi);
1622
 
 
1623
 
    if (!gp->glx_context)
1624
 
        return;
1625
 
 
1626
 
    /* Wait for the first image; for subsequent images, load them in the
1627
 
       background while animating. */
1628
 
    if (gp->waiting_for_image_p && gp->first_image_p)
1629
 
      return;
1630
 
 
1631
 
    glXMakeCurrent(display, window, *(gp->glx_context));
1632
 
    draw_scene(mi);
1633
 
    if (mi->fps_p) do_fps (mi);
1634
 
    glXSwapBuffers(display, window);
 
1707
  mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN(mi)];
 
1708
  Display    *display = MI_DISPLAY(mi);
 
1709
  Window      window = MI_WINDOW(mi);
 
1710
 
 
1711
  if (!gp->glx_context)
 
1712
    return;
 
1713
 
 
1714
  /* Wait for the first image; for subsequent images, load them in the
 
1715
     background while animating. */
 
1716
  if (gp->waiting_for_image_p && gp->first_image_p)
 
1717
    return;
 
1718
 
 
1719
  glXMakeCurrent(display, window, *(gp->glx_context));
 
1720
  draw_scene(mi);
 
1721
  if (mi->fps_p) do_fps (mi);
 
1722
  glFinish();
 
1723
  glXSwapBuffers(display, window);
1635
1724
}
1636
1725
 
1637
1726
/******************************************************************************
1641
1730
ENTRYPOINT void
1642
1731
reshape_mirrorblob(ModeInfo *mi, int width, int height)
1643
1732
{
1644
 
    glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
1645
 
    reset_projection(width, height);
 
1733
  glViewport( 0, 0, MI_WIDTH(mi), MI_HEIGHT(mi) );
 
1734
  reset_projection(width, height);
1646
1735
}
1647
1736
 
1648
1737
/****************************************************************************
1652
1741
ENTRYPOINT Bool
1653
1742
mirrorblob_handle_event (ModeInfo * mi, XEvent * event)
1654
1743
{
1655
 
    mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN (mi)];
1656
 
 
1657
 
    if (event->xany.type == ButtonPress &&
1658
 
        event->xbutton.button == Button1)
1659
 
    {
1660
 
        gp->button_down = 1;
1661
 
        gltrackball_start (gp->trackball, event->xbutton.x,
1662
 
                           event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
1663
 
        return True;
1664
 
    }
1665
 
    else if (event->xany.type == ButtonRelease &&
1666
 
             event->xbutton.button == Button1)
1667
 
    {
1668
 
        gp->button_down = 0;
1669
 
        return True;
1670
 
    }
1671
 
    else if (event->xany.type == ButtonPress &&
1672
 
             event->xbutton.button == Button4)
1673
 
    {
1674
 
        zoom *= 1.1;
1675
 
        return True;
1676
 
    }
1677
 
    else if (event->xany.type == ButtonPress &&
1678
 
             event->xbutton.button == Button5)
1679
 
    {
1680
 
 
1681
 
        zoom *= 0.9;
1682
 
        return True;
1683
 
    }
1684
 
    else if (event->xany.type == MotionNotify && gp->button_down)
1685
 
    {
1686
 
        gltrackball_track (gp->trackball, event->xmotion.x,
1687
 
                           event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
1688
 
        return True;
1689
 
    }
1690
 
    return False;
 
1744
  mirrorblobstruct *gp = &Mirrorblob[MI_SCREEN (mi)];
 
1745
 
 
1746
  if (event->xany.type == ButtonPress &&
 
1747
      event->xbutton.button == Button1)
 
1748
    {
 
1749
      gp->button_down = 1;
 
1750
      gltrackball_start (gp->trackball, event->xbutton.x,
 
1751
                         event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
 
1752
      return True;
 
1753
    }
 
1754
  else if (event->xany.type == ButtonRelease &&
 
1755
           event->xbutton.button == Button1)
 
1756
    {
 
1757
      gp->button_down = 0;
 
1758
      return True;
 
1759
    }
 
1760
  else if (event->xany.type == ButtonPress &&
 
1761
           event->xbutton.button == Button4)
 
1762
    {
 
1763
      zoom *= 1.1;
 
1764
      return True;
 
1765
    }
 
1766
  else if (event->xany.type == ButtonPress &&
 
1767
           event->xbutton.button == Button5)
 
1768
    {
 
1769
 
 
1770
      zoom *= 0.9;
 
1771
      return True;
 
1772
    }
 
1773
  else if (event->xany.type == MotionNotify && gp->button_down)
 
1774
    {
 
1775
      gltrackball_track (gp->trackball, event->xmotion.x,
 
1776
                         event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
 
1777
      return True;
 
1778
    }
 
1779
  return False;
1691
1780
}
1692
1781
 
1693
1782
/******************************************************************************
1697
1786
ENTRYPOINT void
1698
1787
init_mirrorblob(ModeInfo * mi)
1699
1788
{
1700
 
    int screen = MI_SCREEN(mi);
1701
 
 
1702
 
    mirrorblobstruct *gp;
1703
 
 
1704
 
    if (Mirrorblob == NULL)
 
1789
  int screen = MI_SCREEN(mi);
 
1790
 
 
1791
  mirrorblobstruct *gp;
 
1792
 
 
1793
  if (Mirrorblob == NULL)
1705
1794
    {
1706
 
        if ((Mirrorblob = (mirrorblobstruct *)
1707
 
             calloc(MI_NUM_SCREENS(mi), sizeof (mirrorblobstruct))) == NULL)
 
1795
      if ((Mirrorblob = (mirrorblobstruct *)
 
1796
           calloc(MI_NUM_SCREENS(mi), sizeof (mirrorblobstruct))) == NULL)
1708
1797
        {
1709
 
            return;
 
1798
          return;
1710
1799
        }
1711
1800
    }
1712
 
    gp = &Mirrorblob[screen];
 
1801
  gp = &Mirrorblob[screen];
1713
1802
 
1714
 
    gp->window = MI_WINDOW(mi);
1715
 
    if ((gp->glx_context = init_GL(mi)) != NULL)
1716
 
    {
1717
 
        reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1718
 
        initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1719
 
    }
1720
 
    else
1721
 
    {
1722
 
        MI_CLEARWINDOW(mi);
1723
 
    }
1724
 
    gp->trackball = gltrackball_init ();
 
1803
  gp->window = MI_WINDOW(mi);
 
1804
  if ((gp->glx_context = init_GL(mi)) != NULL)
 
1805
    {
 
1806
      reshape_mirrorblob(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
 
1807
      initialize_gl(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
 
1808
    }
 
1809
  else
 
1810
    {
 
1811
      MI_CLEARWINDOW(mi);
 
1812
    }
 
1813
  gp->trackball = gltrackball_init();
1725
1814
    
1726
 
    initialise_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE);
1727
 
    gp->state_start_time = double_time();
 
1815
  initialise_blob(gp, MI_WIDTH(mi), MI_HEIGHT(mi), BUMP_ARRAY_SIZE);
 
1816
  gp->state = INITIALISING;
 
1817
  gp->state_start_time = double_time();
1728
1818
 
1729
 
    gp->first_image_p = True;
 
1819
  gp->first_image_p = True;
1730
1820
}
1731
1821
 
1732
1822
/******************************************************************************