~ubuntu-branches/debian/sid/xscreensaver/sid

1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1
/*
1.1.4 by Oliver Grawert
Import upstream version 5.04
2
 * fliptext, Copyright (c) 2005-2007 Jamie Zawinski <jwz@jwz.org>
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software and its
5
 * documentation for any purpose is hereby granted without fee, provided that
6
 * the above copyright notice appear in all copies and that both that
7
 * copyright notice and this permission notice appear in supporting
8
 * documentation.  No representations are made about the suitability of this
9
 * software for any purpose.  It is provided "as is" without express or 
10
 * implied warranty.
11
 */
12
1.1.4 by Oliver Grawert
Import upstream version 5.04
13
#ifdef HAVE_CONFIG_H
14
# include "config.h"
15
#endif /* HAVE_CONFIG_H */
16
17
#include <ctype.h>
18
#include <sys/stat.h>
19
20
#ifndef HAVE_COCOA
21
# include <X11/Intrinsic.h>
22
#endif
23
24
#ifdef HAVE_UNISTD_H
25
# include <unistd.h>
26
#endif
27
28
#ifdef HAVE_UNAME
29
# include <sys/utsname.h>
30
#endif /* HAVE_UNAME */
31
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
32
33
/* Utopia 800 needs 64 512x512 textures (4096x4096 bitmap).
34
   Utopia 720 needs 16 512x512 textures (2048x2048 bitmap).
35
   Utopia 480 needs 16 512x512 textures (2048x2048 bitmap).
36
   Utopia 400 needs  4 512x512 textures (1024x1024 bitmap).
37
   Utopia 180 needs  1 512x512 texture.
38
   Times  240 needs  1 512x512 texture.
39
 */
40
#define DEF_FONT       "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-iso8859-1"
1.1.4 by Oliver Grawert
Import upstream version 5.04
41
#define DEF_COLOR      "#00CCFF"
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
42
43
#define DEFAULTS "*delay:        10000      \n" \
44
		 "*showFPS:      False      \n" \
45
		 "*wireframe:    False      \n" \
46
		 "*font:       " DEF_FONT  "\n" \
47
		 ".foreground: " DEF_COLOR "\n" \
48
1.1.4 by Oliver Grawert
Import upstream version 5.04
49
# define refresh_fliptext 0
50
# define fliptext_handle_event 0
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
51
#undef countof
52
#define countof(x) (sizeof((x))/sizeof((*x)))
53
54
#undef BELLRAND
55
#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
56
57
#include "xlockmore.h"
1.1.4 by Oliver Grawert
Import upstream version 5.04
58
#include "texfont.h"
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
59
60
#ifdef USE_GL /* whole file */
61
1.1.4 by Oliver Grawert
Import upstream version 5.04
62
/* Should be in <GL/glext.h> */
63
# ifndef  GL_TEXTURE_MAX_ANISOTROPY_EXT
64
#  define GL_TEXTURE_MAX_ANISOTROPY_EXT     0x84FE
65
# endif
66
# ifndef  GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
67
#  define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF
68
# endif
69
70
71
#define DEF_PROGRAM    "xscreensaver-text --cols 0"  /* don't wrap */
72
#define DEF_LINES      "8"
73
#define DEF_FONT_SIZE  "20"
74
#define DEF_COLUMNS    "80"
75
#define DEF_ALIGN      "random"
76
#define DEF_SPEED       "1.0"
77
#define TAB_WIDTH        8
78
79
#define FONT_WEIGHT       14
80
#define KEEP_ASPECT
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
81
82
typedef enum { NEW, HESITATE, IN, LINGER, OUT, DEAD } line_state;
83
typedef enum { SCROLL_BOTTOM, SCROLL_TOP, SPIN } line_anim_type;
84
85
typedef struct { GLfloat x, y, z; } XYZ;
86
87
typedef struct {
88
  char *text;
89
  GLfloat width, height;	/* size */
90
  XYZ from, to, current;	/* start, end, and current position */
91
  GLfloat fth, tth, cth;	/* rotation around Z */
92
93
  int cluster_size;		/* how many lines in this cluster */
94
  int cluster_pos;		/* position of this line in the cluster */
95
96
  line_state state;		/* current motion model */
97
  int step, steps;		/* progress along this path */
98
  GLfloat color[4];
99
100
} line;
101
102
103
typedef struct {
1.1.4 by Oliver Grawert
Import upstream version 5.04
104
  Display *dpy;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
105
  GLXContext *glx_context;
106
107
  texture_font_data *texfont;
108
109
  FILE *pipe;
110
  XtInputId pipe_id;
1.1.4 by Oliver Grawert
Import upstream version 5.04
111
  XtIntervalId pipe_timer;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
112
  Time subproc_relaunch_delay;
113
114
  char *buf;
115
  int buf_size;
116
  int buf_tail;
117
118
  int char_width;         /* in font units */
119
  int line_height;	  /* in font units */
120
  double font_scale;	  /* convert font units to display units */
121
122
  int font_wrap_pixels;   /* in font units (for wrapping text) */
123
124
  int top_margin, bottom_margin;
125
  int left_margin, right_margin;
126
127
  int nlines;
128
  int lines_size;
129
  line **lines;
130
131
  line_anim_type anim_type;
132
  XYZ in, mid, out;
133
  XYZ rotation;
134
  GLfloat color[4];
135
136
} fliptext_configuration;
137
138
139
static fliptext_configuration *scs = NULL;
140
141
static char *program;
142
static int max_lines, min_lines;
143
static float font_size;
144
static int target_columns;
145
static char *alignment_str;
146
static int alignment, alignment_random_p;
147
static GLfloat speed;
148
149
static XrmOptionDescRec opts[] = {
150
  {"-program",     ".program",   XrmoptionSepArg, 0 },
151
  {"-lines",       ".lines",     XrmoptionSepArg, 0 },
152
  {"-size",	   ".fontSize",  XrmoptionSepArg, 0 },
153
  {"-columns",	   ".columns",   XrmoptionSepArg, 0 },
154
  {"-speed",       ".speed",     XrmoptionSepArg, 0 },
155
/*{"-font",        ".font",      XrmoptionSepArg, 0 },*/
1.1.4 by Oliver Grawert
Import upstream version 5.04
156
  {"-alignment",   ".alignment", XrmoptionSepArg, 0 },
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
157
  {"-left",        ".alignment", XrmoptionNoArg,  "Left"   },
158
  {"-right",       ".alignment", XrmoptionNoArg,  "Right"  },
159
  {"-center",      ".alignment", XrmoptionNoArg,  "Center" },
160
};
161
162
static argtype vars[] = {
163
  {&program,        "program",   "Program",    DEF_PROGRAM,   t_String},
164
  {&max_lines,      "lines",     "Integer",    DEF_LINES,     t_Int},
165
  {&font_size,      "fontSize",  "Float",      DEF_FONT_SIZE, t_Float},
166
  {&target_columns, "columns",   "Integer",    DEF_COLUMNS,   t_Int},
167
  {&alignment_str,  "alignment", "Alignment",  DEF_ALIGN,     t_String},
168
  {&speed,	    "speed",     "Speed",      DEF_SPEED,     t_Float},
169
};
170
1.1.4 by Oliver Grawert
Import upstream version 5.04
171
ENTRYPOINT ModeSpecOpt fliptext_opts = {countof(opts), opts, countof(vars), vars, NULL};
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
172
173
174
175
/* Tabs are bad, mmmkay? */
176
177
static char *
178
untabify (const char *string)
179
{
180
  const char *ostring = string;
181
  char *result = (char *) malloc ((strlen(string) * 8) + 1);
182
  char *out = result;
183
  int col = 0;
184
  while (*string)
185
    {
186
      if (*string == '\t')
187
        {
188
          do {
189
            col++;
190
            *out++ = ' ';
191
          } while (col % TAB_WIDTH);
192
          string++;
193
        }
194
      else if (*string == '\r' || *string == '\n')
195
        {
196
          *out++ = *string++;
197
          col = 0;
198
        }
199
      else if (*string == '\010')    /* backspace */
200
        {
201
          if (string > ostring)
202
            out--, string++;
203
        }
204
      else
205
        {
206
          *out++ = *string++;
207
          col++;
208
        }
209
    }
210
  *out = 0;
211
212
  return result;
213
}
214
215
static void
216
strip (char *s, Bool leading, Bool trailing)
217
{
218
  int L = strlen(s);
219
  if (trailing)
220
    while (L > 0 && (s[L-1] == ' ' || s[L-1] == '\t'))
221
      s[L--] = 0;
222
  if (leading)
223
    {
224
      char *s2 = s;
225
      while (*s2 == ' ' || *s2 == '\t')
226
        s2++;
227
      if (s == s2)
228
        return;
229
      while (*s2)
230
        *s++ = *s2++;
231
      *s = 0;
232
    }
233
}
234
235
236

237
/* Subprocess.
238
   (This bit mostly cribbed from phosphor.c)
239
 */
240
241
static void drain_input (fliptext_configuration *sc);
242
243
static void
244
subproc_cb (XtPointer closure, int *source, XtInputId *id)
245
{
246
  fliptext_configuration *sc = (fliptext_configuration *) closure;
247
  drain_input (sc);
248
}
249
250
251
static void
252
launch_text_generator (fliptext_configuration *sc)
253
{
1.1.4 by Oliver Grawert
Import upstream version 5.04
254
  XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
255
  char *oprogram = get_string_resource (sc->dpy, "program", "Program");
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
256
  char *program = (char *) malloc (strlen (oprogram) + 10);
257
  strcpy (program, "( ");
258
  strcat (program, oprogram);
259
  strcat (program, " ) 2>&1");
260
261
  if ((sc->pipe = popen (program, "r")))
262
    {
263
      sc->pipe_id =
264
        XtAppAddInput (app, fileno (sc->pipe),
265
                       (XtPointer) (XtInputReadMask | XtInputExceptMask),
266
                       subproc_cb, (XtPointer) sc);
267
    }
268
  else
269
    {
270
      perror (program);
271
    }
272
}
273
274
275
static void
276
relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
277
{
278
  fliptext_configuration *sc = (fliptext_configuration *) closure;
1.1.4 by Oliver Grawert
Import upstream version 5.04
279
  if (!sc->pipe_timer) abort();
280
  sc->pipe_timer = 0;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
281
  launch_text_generator (sc);
282
}
283
284
285
/* When the subprocess has generated some output, this reads as much as it
286
   can into sc->buf at sc->buf_tail.
287
 */
288
static void
289
drain_input (fliptext_configuration *sc)
290
{
1.1.4 by Oliver Grawert
Import upstream version 5.04
291
  XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
292
  if (sc->buf_tail < sc->buf_size - 2)
293
    {
294
      int target = sc->buf_size - sc->buf_tail - 2;
295
      int n = (sc->pipe
296
               ? read (fileno (sc->pipe),
297
                       (void *) (sc->buf + sc->buf_tail),
298
                       target)
299
               : 0);
300
      if (n > 0)
301
        {
302
          sc->buf_tail += n;
303
          sc->buf[sc->buf_tail] = 0;
304
        }
305
      else
306
        {
307
          if (sc->pipe)
308
            {
309
              XtRemoveInput (sc->pipe_id);
310
              sc->pipe_id = 0;
311
              pclose (sc->pipe);
312
              sc->pipe = 0;
313
            }
314
315
          /* If the process didn't print a terminating newline, add one. */
316
          if (sc->buf_tail > 1 &&
317
              sc->buf[sc->buf_tail-1] != '\n')
318
            {
319
              sc->buf[sc->buf_tail++] = '\n';
320
              sc->buf[sc->buf_tail] = 0;
321
            }
322
323
          /* Then add one more, just for giggles. */
324
          sc->buf[sc->buf_tail++] = '\n';
325
          sc->buf[sc->buf_tail] = 0;
326
327
          /* Set up a timer to re-launch the subproc in a bit. */
1.1.4 by Oliver Grawert
Import upstream version 5.04
328
          sc->pipe_timer = XtAppAddTimeOut (app, sc->subproc_relaunch_delay,
329
                                            relaunch_generator_timer,
330
                                            (XtPointer) sc);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
331
        }
332
    }
333
}
334
335
336
static int
337
char_width (fliptext_configuration *sc, char c)
338
{
339
  char s[2];
340
  s[0] = c;
341
  s[1] = 0;
342
  return texture_string_width (sc->texfont, s, 0);
343
}
344
345
346
/* Returns a single line of text from the output buffer of the subprocess,
347
   taking into account wrapping, centering, etc.  Returns 0 if no complete
348
   line is currently available.
349
 */
350
static char *
351
get_one_line (fliptext_configuration *sc)
352
{
353
  char *result = 0;
354
  int wrap_pix = sc->font_wrap_pixels;
355
  int col = 0;
356
  int col_pix = 0;
357
358
  char *s = sc->buf;
359
  while (!result)
360
    {
361
      int cw;
362
363
      if (s >= sc->buf + sc->buf_tail)
364
        /* Reached end of buffer before end of line.  Bail. */
365
        return 0;
366
367
      cw = char_width (sc, *s);
368
369
      if (*s == '\r' || *s == '\n' ||
370
          col_pix + cw >= wrap_pix)
371
        {
372
          int L = s - sc->buf;
373
374
          if (*s == '\r' || *s == '\n')
375
            {
376
              if (*s == '\r' && s[1] == '\n')  /* swallow CRLF too */
377
                *s++ = 0;
378
379
              *s++ = 0;
380
            }
381
          else
382
            {
383
              /* We wrapped -- try to back up to the previous word boundary. */
384
              char *s2 = s;
385
              int n = 0;
386
              while (s2 > sc->buf && *s2 != ' ' && *s2 != '\t')
387
                s2--, n++;
388
              if (s2 > sc->buf)
389
                {
390
                  s = s2;
391
                  *s++ = 0;
392
                  L = s - sc->buf;
393
                }
394
            }
395
396
          if (result) abort();
397
          result = (char *) malloc (L+1);
398
          memcpy (result, sc->buf, L);
399
          result[L] = 0;
400
401
          {
402
            char *t = result;
403
            char *ut = untabify (t);
404
            strip (ut, (alignment == 0), 1); /* if centering, strip
405
                                                leading whitespace too */
406
            result = ut;
407
            free (t);
408
          }
409
410
          if (sc->buf_tail > (s - sc->buf))
411
            {
412
              int i = sc->buf_tail - (s - sc->buf);
413
              memmove (sc->buf, s, i);
414
              sc->buf_tail = i;
415
              sc->buf[sc->buf_tail] = 0;
416
            }
417
          else
418
            {
419
              sc->buf_tail = 0;
420
            }
421
422
          sc->buf[sc->buf_tail] = 0;
423
          s = sc->buf;
424
          col = 0;
425
          col_pix = 0;
426
        }
427
      else
428
        {
429
          col++;
430
          col_pix += cw;
431
          if (*s == '\t')
432
            {
433
              int tab_pix = TAB_WIDTH * sc->char_width;
434
              col     = TAB_WIDTH * ((col / TAB_WIDTH) + 1);
435
              col_pix = tab_pix   * ((col / tab_pix)   + 1);
436
            }
437
          s++;
438
        }
439
    }
440
441
  return result;
442
}
443
444
445
static Bool
446
blank_p (const char *s)
447
{
448
  for (; *s; s++)
449
    if (*s != ' ' && *s != '\t' && *s != '\r' && *s != '\n')
450
      return False;
451
  return True;
452
}
453
454
/* Reads some text from the subprocess, and creates and returns a `line'
455
   object.  Adds that object to the lines list.   Returns 0 if no text
456
   available yet.
457
458
   If skip_blanks_p, then keep trying for new lines of text until we
459
   get one that is not empty.
460
 */
461
static line *
462
make_line (fliptext_configuration *sc, Bool skip_blanks_p)
463
{
464
  line *ln;
465
  char *s;
466
467
 AGAIN:
468
  s = get_one_line (sc);
469
  if (s && skip_blanks_p && blank_p (s))
470
    {
471
      free (s);
472
      goto AGAIN;
473
    }
474
475
  if (!s) return 0;
476
477
  ln = (line *) calloc (1, sizeof(*ln));
478
  ln->text = s;
479
  ln->state = NEW;
480
  ln->width = sc->font_scale * texture_string_width (sc->texfont, s, 0);
481
  ln->height = sc->font_scale * sc->line_height;
482
1.1.2 by Adam Conrad
Import upstream version 4.23
483
  memcpy (ln->color, sc->color, sizeof(ln->color));
484
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
485
  sc->nlines++;
486
  if (sc->lines_size <= sc->nlines)
487
    {
488
      sc->lines_size = (sc->lines_size * 1.2) + sc->nlines;
489
      sc->lines = (line **)
490
        realloc (sc->lines, sc->lines_size * sizeof(*sc->lines));
491
      if (! sc->lines)
492
        {
493
          fprintf (stderr, "%s: out of memory (%d lines)\n",
494
                   progname, sc->lines_size);
495
          exit (1);
496
        }
497
    }
498
499
  sc->lines[sc->nlines-1] = ln;
500
  return ln;
501
}
502
503
504
/* frees the object and removes it from the list.
505
 */
506
static void
507
free_line (fliptext_configuration *sc, line *line)
508
{
509
  int i;
510
  for (i = 0; i < sc->nlines; i++)
511
    if (sc->lines[i] == line)
512
      break;
513
  if (i == sc->nlines) abort();
514
  for (; i < sc->nlines-1; i++)
515
    sc->lines[i] = sc->lines[i+1];
516
  sc->lines[i] = 0;
517
  sc->nlines--;
518
519
  free (line->text);
520
  free (line);
521
}
522
523
524
static void
525
draw_line (ModeInfo *mi, line *line)
526
{
527
  int wire = MI_IS_WIREFRAME(mi);
528
  fliptext_configuration *sc = &scs[MI_SCREEN(mi)];
529
530
  if (! line->text || !*line->text ||
531
      line->state == NEW || line->state == HESITATE || line->state == DEAD)
532
    return;
533
534
  glPushMatrix();
535
  glTranslatef (line->current.x, line->current.y, line->current.z);
536
537
  glRotatef (line->cth, 0, 1, 0);
538
539
  if (alignment == 1)
540
    glTranslatef (-line->width, 0, 0);
541
  else if (alignment == 0)
542
    glTranslatef (-line->width/2, 0, 0);
543
544
  glScalef (sc->font_scale, sc->font_scale, sc->font_scale);
545
546
  glColor4f (line->color[0], line->color[1], line->color[2], line->color[3]);
547
548
  if (!wire)
549
    print_texture_string (sc->texfont, line->text);
550
  else
551
    {
552
      int w, h;
553
      char *s = line->text;
554
      char c[2];
555
      c[1]=0;
556
      glDisable (GL_TEXTURE_2D);
557
      glColor3f (0.4, 0.4, 0.4);
558
      while (*s)
559
        {
560
          *c = *s++;
561
          w = texture_string_width (sc->texfont, c, &h);
562
          glBegin (GL_LINE_LOOP);
563
          glVertex3f (0, 0, 0);
564
          glVertex3f (w, 0, 0);
565
          glVertex3f (w, h, 0);
566
          glVertex3f (0, h, 0);
567
          glEnd();
568
          glTranslatef (w, 0, 0);
569
        }
570
    }
571
572
#if 0
573
  glDisable (GL_TEXTURE_2D);
574
  glColor3f (0.4, 0.4, 0.4);
575
  glBegin (GL_LINE_LOOP);
576
  glVertex3f (0, 0, 0);
577
  glVertex3f (line->width/sc->font_scale, 0, 0);
578
  glVertex3f (line->width/sc->font_scale, line->height/sc->font_scale, 0);
579
  glVertex3f (0, line->height/sc->font_scale, 0);
580
  glEnd();
581
  if (!wire) glEnable (GL_TEXTURE_2D);
582
#endif
583
584
  glPopMatrix();
585
586
  mi->polygon_count += strlen (line->text);
587
}
588
589
static void
590
tick_line (fliptext_configuration *sc, line *line)
591
{
1.1.2 by Adam Conrad
Import upstream version 4.23
592
  int stagger = 30;            /* frames of delay between line spin-outs */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
593
  int slide   = 600;           /* frames in a slide in/out */
594
  int linger  = 0;             /* frames to pause with no motion */
1.1.2 by Adam Conrad
Import upstream version 4.23
595
  double i, ii;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
596
597
  if (line->state >= DEAD) abort();
598
  if (++line->step >= line->steps)
599
    {
600
      line->state++;
601
      line->step = 0;
602
603
      if (linger == 0 && line->state == LINGER)
604
        line->state++;
605
1.1.2 by Adam Conrad
Import upstream version 4.23
606
      if (sc->anim_type != SPIN)
607
        stagger *= 2;
608
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
609
      switch (line->state)
610
        {
611
        case HESITATE:			/* entering state HESITATE */
612
          switch (sc->anim_type)
613
            {
614
            case SPIN:
615
              line->steps = (line->cluster_pos * stagger);
616
              break;
617
            case SCROLL_TOP:
618
              line->steps = stagger * (line->cluster_size - line->cluster_pos);
619
              break;
620
            case SCROLL_BOTTOM:
621
              line->steps = stagger * line->cluster_pos;
622
              break;
623
            default:
624
              abort();
625
            }
626
          break;
627
628
        case IN:
1.1.2 by Adam Conrad
Import upstream version 4.23
629
          line->color[3] = 0;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
630
          switch (sc->anim_type)
631
            {
632
            case SCROLL_BOTTOM:		/* entering state BOTTOM IN */
633
              line->from = sc->in;
634
              line->to   = sc->mid;
635
              line->from.y = (sc->bottom_margin -
636
                              (line->height *
637
                               (line->cluster_pos + 1)));
638
              line->to.y += (line->height *
639
                             ((line->cluster_size/2.0) - line->cluster_pos));
640
              line->steps = slide;
641
              break;
642
643
            case SCROLL_TOP:		/* entering state TOP IN */
644
              line->from = sc->in;
645
              line->to   = sc->mid;
646
              line->from.y = (sc->top_margin +
647
                              (line->height *
648
                               (line->cluster_size - line->cluster_pos)));
649
              line->to.y += (line->height *
650
                             ((line->cluster_size/2.0) - line->cluster_pos));
651
              line->steps = slide;
652
              break;
653
654
            case SPIN:			/* entering state SPIN IN */
655
              line->from = sc->in;
656
              line->to   = sc->mid;
657
              line->to.y += (line->height *
658
                             ((line->cluster_size/2.0) - line->cluster_pos));
659
              line->from.y += (line->height *
660
                               ((line->cluster_size/2.0) - line->cluster_pos));
661
662
              line->fth = 270;
663
              line->tth = 0;
664
              line->steps = slide;
665
              break;
666
667
            default:
668
              abort();
669
            }
670
          break;
671
672
        case OUT:
673
          switch (sc->anim_type)
674
            {
675
            case SCROLL_BOTTOM:		/* entering state BOTTOM OUT */
676
              line->from = line->to;
677
              line->to   = sc->out;
678
              line->to.y = (sc->top_margin +
679
                            (line->height *
680
                             (line->cluster_size - line->cluster_pos)));
681
              line->steps = slide;
682
              break;
683
684
            case SCROLL_TOP:		/* entering state TOP OUT */
685
              line->from = line->to;
686
              line->to   = sc->out;
687
              line->to.y = (sc->bottom_margin -
688
                            (line->height *
689
                             (line->cluster_pos + 1)));
690
              line->steps = slide;
691
              break;
692
693
            case SPIN:			/* entering state SPIN OUT */
694
              line->from = line->to;
695
              line->to   = sc->out;
696
              line->to.y += (line->height *
697
                             ((line->cluster_size/2.0) - line->cluster_pos));
698
699
              line->fth = line->tth;
700
              line->tth = -270;
701
              line->steps = slide;
702
              break;
703
704
            default:
705
              abort();
706
            }
707
          break;
708
709
        case LINGER:
710
          line->from = line->to;
711
          line->steps = linger;
712
          break;
713
714
        default:
715
          break;
716
        }
717
718
      line->steps /= speed;
719
    }
720
721
  switch (line->state)
722
    {
723
    case IN:
724
    case OUT:
725
      i = (double) line->step / line->steps;
1.1.2 by Adam Conrad
Import upstream version 4.23
726
727
      /* Move along the path exponentially, slow side towards the middle. */
728
      if (line->state == OUT)
729
        ii = i * i;
730
      else
731
        ii = 1 - ((1-i) * (1-i));
732
733
      line->current.x = line->from.x + (ii * (line->to.x - line->from.x));
734
      line->current.y = line->from.y + (ii * (line->to.y - line->from.y));
735
      line->current.z = line->from.z + (ii * (line->to.z - line->from.z));
736
      line->cth = line->fth + (ii * (line->tth - line->fth));
737
738
      if (line->state == OUT) ii = 1-ii;
739
      line->color[3] = sc->color[3] * ii;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
740
      break;
741
742
    case HESITATE:
743
    case LINGER:
744
    case DEAD:
745
      break;
746
    default:
747
      abort();
748
    }
749
}
750
751
752
/* Start a new cluster of lines going.
753
   Pick their anim type, and in, mid, and out positions.
754
 */
755
static void
756
reset_lines (ModeInfo *mi)
757
{
758
  fliptext_configuration *sc = &scs[MI_SCREEN(mi)];
759
  int i;
760
  line *prev = 0;
761
  GLfloat minx, maxx, miny, maxy, minz, maxz, maxw, maxh;
762
763
  sc->rotation.x = 5 - BELLRAND(10);
764
  sc->rotation.y = 5 - BELLRAND(10);
765
  sc->rotation.z = 5 - BELLRAND(10);
766
1.1.2 by Adam Conrad
Import upstream version 4.23
767
  switch (random() % 8)
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
768
    {
769
    case 0:  sc->anim_type = SCROLL_TOP;    break;
770
    case 1:  sc->anim_type = SCROLL_BOTTOM; break;
771
    default: sc->anim_type = SPIN;          break;
772
    }
773
774
  minx = sc->left_margin  * 0.9;
775
  maxx = sc->right_margin * 0.9;
776
777
  miny = sc->bottom_margin * 0.9;
778
  maxy = sc->top_margin    * 0.9;
779
780
  minz = sc->left_margin  * 5;
781
  maxz = sc->right_margin * 2;
782
783
  maxw = sc->font_wrap_pixels * sc->font_scale;
784
  maxh = max_lines * sc->line_height * sc->font_scale;
785
 
786
  if (maxw > maxx - minx)
787
    maxw = maxx - minx;
788
  if (maxh > maxy - miny)
789
    maxh = maxy - miny;
790
      
791
  if (alignment_random_p)
792
    alignment = (random() % 3) - 1;
793
794
  if      (alignment == -1) maxx -= maxw;
795
  else if (alignment ==  1) minx += maxw;
796
  else                      minx += maxw/2, maxx -= maxw/2;
797
798
  miny += maxh/2;
799
  maxy -= maxh/2;
800
801
  sc->mid.x = minx + frand (maxx - minx);
1.1.2 by Adam Conrad
Import upstream version 4.23
802
  if (sc->anim_type == SPIN)
803
    sc->mid.y = miny + BELLRAND (maxy - miny);
804
  else
805
    sc->mid.y = miny + frand (maxy - miny);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
806
807
  sc->in.x  = BELLRAND(sc->right_margin * 2) - sc->right_margin;
808
  sc->out.x = BELLRAND(sc->right_margin * 2) - sc->right_margin;
809
810
  sc->in.y  = miny + frand(maxy - miny);
811
  sc->out.y = miny + frand(maxy - miny);
812
813
  sc->in.z  = minz + frand(maxz - minz);
814
  sc->out.z = minz + frand(maxz - minz);
815
816
  sc->mid.z = 0;
817
818
  if (sc->anim_type == SPIN && sc->in.z  > 0) sc->in.z  /= 4;
819
  if (sc->anim_type == SPIN && sc->out.z > 0) sc->out.z /= 4;
820
821
  for (i = 0; i < max_lines; i++)
822
    {
823
      line *line = make_line (sc, (i == 0));
824
      if (!line) break;			/* no text available */
825
      if (i >= min_lines &&
826
          (!line->text || !*line->text))	/* blank after min */
827
        break;
828
    }
829
830
  for (i = 0; i < sc->nlines; i++)
831
    {
832
      line *line = sc->lines[i];
833
      if (!prev)
834
        {
835
          line->from.y = sc->bottom_margin;
836
          line->to.y   = 0;
837
        }
838
      else
839
        {
840
          line->from.y = prev->from.y - prev->height;
841
          line->to.y   = prev->to.y   - prev->height;
842
        }
843
      line->cluster_pos = i;
844
      line->cluster_size = sc->nlines;
845
      prev = line;
846
    }
847
}
848
849
850
static void
851
parse_color (ModeInfo *mi, const char *name, const char *s, GLfloat *a)
852
{
853
  XColor c;
854
  if (! XParseColor (MI_DISPLAY(mi), MI_COLORMAP(mi), s, &c))
855
    {
856
      fprintf (stderr, "%s: can't parse %s color %s", progname, name, s);
857
      exit (1);
858
    }
859
  a[0] = c.red   / 65536.0;
860
  a[1] = c.green / 65536.0;
861
  a[2] = c.blue  / 65536.0;
862
  a[3] = 1.0;
863
}
864
865
866
/* Window management, etc
867
 */
1.1.4 by Oliver Grawert
Import upstream version 5.04
868
ENTRYPOINT void
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
869
reshape_fliptext (ModeInfo *mi, int width, int height)
870
{
871
  fliptext_configuration *sc = &scs[MI_SCREEN(mi)];
872
  GLfloat h = (GLfloat) height / (GLfloat) width;
873
874
  glViewport (0, 0, (GLint) width, (GLint) height);
875
876
  glMatrixMode(GL_PROJECTION);
877
  glLoadIdentity();
878
  gluPerspective (60.0, 1/h, 0.01, 100.0);
879
880
  glMatrixMode(GL_MODELVIEW);
881
  glLoadIdentity();
882
  gluLookAt( 0.0, 0.0, 2.6,
883
             0.0, 0.0, 0.0,
884
             0.0, 1.0, 0.0);
885
886
  glClear(GL_COLOR_BUFFER_BIT);
887
888
  sc->right_margin = sc->top_margin / h;
889
  sc->left_margin = -sc->right_margin;
890
}
891
892
1.1.4 by Oliver Grawert
Import upstream version 5.04
893
ENTRYPOINT void 
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
894
init_fliptext (ModeInfo *mi)
895
{
896
  int wire = MI_IS_WIREFRAME(mi);
897
898
  fliptext_configuration *sc;
899
900
  if (!scs) {
901
    scs = (fliptext_configuration *)
902
      calloc (MI_NUM_SCREENS(mi), sizeof (fliptext_configuration));
903
    if (!scs) {
904
      fprintf(stderr, "%s: out of memory\n", progname);
905
      exit(1);
906
    }
907
908
    sc = &scs[MI_SCREEN(mi)];
909
    sc->lines = (line **) calloc (max_lines+1, sizeof(char *));
910
  }
911
912
  sc = &scs[MI_SCREEN(mi)];
1.1.4 by Oliver Grawert
Import upstream version 5.04
913
  sc->dpy = MI_DISPLAY(mi);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
914
915
  if ((sc->glx_context = init_GL(mi)) != NULL) {
916
    reshape_fliptext (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
917
  }
918
1.1.4 by Oliver Grawert
Import upstream version 5.04
919
  program = get_string_resource (mi->dpy, "program", "Program");
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
920
921
  {
922
    int cw, lh;
923
    sc->texfont = load_texture_font (MI_DISPLAY(mi), "font");
924
    check_gl_error ("loading font");
925
    cw = texture_string_width (sc->texfont, "n", &lh);
926
    sc->char_width = cw;
927
    sc->line_height = lh;
928
  }
929
930
  if (!wire)
931
    {
932
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
933
      glEnable (GL_BLEND);
934
      glEnable (GL_ALPHA_TEST);
935
      glEnable (GL_TEXTURE_2D);
936
937
      /* "Anistropic filtering helps for quadrilateral-angled textures.
938
         A sharper image is accomplished by interpolating and filtering
939
         multiple samples from one or more mipmaps to better approximate
940
         very distorted textures.  This is the next level of filtering
941
         after trilinear filtering." */
1.1.4 by Oliver Grawert
Import upstream version 5.04
942
      if (strstr ((char *) glGetString(GL_EXTENSIONS),
943
                  "GL_EXT_texture_filter_anisotropic"))
944
      {
945
        GLfloat anisotropic = 0.0;
946
        glGetFloatv (GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &anisotropic);
947
        if (anisotropic >= 1.0)
948
          glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 
949
                           anisotropic);
950
      }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
951
    }
952
  
953
  /* The default font is (by fiat) "18 points".
954
     Interpret the user's font size request relative to that.
955
   */
956
  sc->font_scale = 3 * (font_size / 18.0);
957
958
  if (target_columns <= 2) target_columns = 2;
959
960
  /* Figure out what the wrap column should be, in font-coordinate pixels.
961
     Compute it from the given -columns value, but don't let it be wider
962
     than the screen.
963
   */
964
  {
965
    GLfloat maxw = 110 * sc->line_height / sc->font_scale;  /* magic... */
966
    sc->font_wrap_pixels = target_columns * sc->char_width;
967
    if (sc->font_wrap_pixels > maxw ||
968
        sc->font_wrap_pixels <= 0)
969
      sc->font_wrap_pixels = maxw;
970
  }
971
972
  sc->buf_size = target_columns * max_lines;
973
  sc->buf = (char *) calloc (1, sc->buf_size);
974
975
  sc->subproc_relaunch_delay = 2 * 1000;   /* 2 seconds */
976
977
  alignment_random_p = False;
978
  if (!alignment_str || !*alignment_str ||
979
      !strcasecmp(alignment_str, "left"))
980
    alignment = -1;
981
  else if (!strcasecmp(alignment_str, "center") ||
982
           !strcasecmp(alignment_str, "middle"))
983
    alignment = 0;
984
  else if (!strcasecmp(alignment_str, "right"))
985
    alignment = 1;
986
  else if (!strcasecmp(alignment_str, "random"))
987
    alignment = -1, alignment_random_p = True;
988
989
  else
990
    {
991
      fprintf (stderr,
992
               "%s: alignment must be left/center/right/random, not \"%s\"\n",
993
               progname, alignment_str);
994
      exit (1);
995
    }
996
997
  launch_text_generator (sc);
998
999
  if (max_lines < 1) max_lines = 1;
1000
  min_lines = max_lines * 0.66;
1001
  if (min_lines > max_lines - 3) min_lines = max_lines - 4;
1002
  if (min_lines < 1) min_lines = 1;
1003
1004
  parse_color (mi, "foreground",
1.1.4 by Oliver Grawert
Import upstream version 5.04
1005
               get_string_resource(mi->dpy, "foreground", "Foreground"),
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1006
               sc->color);
1007
1008
  sc->top_margin = (sc->char_width * 100);
1009
  sc->bottom_margin = -sc->top_margin;
1010
  reshape_fliptext (mi, MI_WIDTH(mi), MI_HEIGHT(mi));  /* compute left/right */
1011
}
1012
1013
1.1.4 by Oliver Grawert
Import upstream version 5.04
1014
ENTRYPOINT void
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1015
draw_fliptext (ModeInfo *mi)
1016
{
1017
  fliptext_configuration *sc = &scs[MI_SCREEN(mi)];
1.1.4 by Oliver Grawert
Import upstream version 5.04
1018
/*  XtAppContext app = XtDisplayToApplicationContext (sc->dpy);*/
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1019
  Display *dpy = MI_DISPLAY(mi);
1020
  Window window = MI_WINDOW(mi);
1021
  int i;
1022
1023
  if (!sc->glx_context)
1024
    return;
1025
1.1.4 by Oliver Grawert
Import upstream version 5.04
1026
  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(sc->glx_context));
1027
1028
#if 0
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1029
  if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
1030
    XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
1.1.4 by Oliver Grawert
Import upstream version 5.04
1031
#endif
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1032
1033
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1034
1035
  mi->polygon_count = 0;
1036
1037
  glPushMatrix();
1038
  {
1039
    GLfloat s = 3.0 / (sc->top_margin - sc->bottom_margin);
1040
    glScalef(s, s, s);
1041
  }
1042
1043
  glRotatef (sc->rotation.x, 1, 0, 0);
1044
  glRotatef (sc->rotation.y, 0, 1, 0);
1045
  glRotatef (sc->rotation.z, 0, 0, 1);
1046
1047
#if 0
1048
  glDisable (GL_TEXTURE_2D);
1049
  glColor3f (1,1,1);
1050
  glBegin (GL_LINE_LOOP);
1051
  glVertex3f (sc->left_margin,  sc->top_margin, 0);
1052
  glVertex3f (sc->right_margin, sc->top_margin, 0);
1053
  glVertex3f (sc->right_margin, sc->bottom_margin, 0);
1054
  glVertex3f (sc->left_margin,  sc->bottom_margin, 0);
1055
  glEnd();
1056
  glBegin (GL_LINES);
1057
  glVertex3f (sc->in.x,  sc->top_margin,    sc->in.z);
1058
  glVertex3f (sc->in.x,  sc->bottom_margin, sc->in.z);
1059
  glVertex3f (sc->mid.x, sc->top_margin,    sc->mid.z);
1060
  glVertex3f (sc->mid.x, sc->bottom_margin, sc->mid.z);
1061
  glVertex3f (sc->out.x, sc->top_margin,    sc->out.z);
1062
  glVertex3f (sc->out.x, sc->bottom_margin, sc->out.z);
1063
  glEnd();
1064
  glEnable (GL_TEXTURE_2D);
1065
#endif
1066
1067
  for (i = 0; i < sc->nlines; i++)
1068
    {
1069
      line *line = sc->lines[i];
1070
      draw_line (mi, line);
1071
      tick_line (sc, line);
1072
    }
1073
1074
  for (i = sc->nlines-1; i >= 0; i--)
1075
    {
1076
      line *line = sc->lines[i];
1077
      if (line->state == DEAD)
1078
        free_line (sc, line);
1079
    }
1080
1081
  if (sc->nlines == 0)
1082
    reset_lines (mi);
1083
1084
  glPopMatrix();
1085
1086
  if (mi->fps_p) do_fps (mi);
1087
  glFinish();
1088
  glXSwapBuffers(dpy, window);
1089
}
1090
1.1.4 by Oliver Grawert
Import upstream version 5.04
1091
ENTRYPOINT void
1092
release_fliptext (ModeInfo *mi)
1093
{
1094
  if (scs) {
1095
    int screen;
1096
    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1097
      fliptext_configuration *sc = &scs[screen];
1098
      if (sc->pipe_id)
1099
        XtRemoveInput (sc->pipe_id);
1100
      if (sc->pipe)
1101
        pclose (sc->pipe);
1102
      if (sc->pipe_timer)
1103
        XtRemoveTimeOut (sc->pipe_timer);
1104
1105
      /* #### there's more to free here */
1106
    }
1107
    free (scs);
1108
    scs = 0;
1109
  }
1110
  FreeAllGL(mi);
1111
}
1112
1113
XSCREENSAVER_MODULE ("FlipText", fliptext)
1114
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1115
#endif /* USE_GL */