
/* $Id: flying_ggis.q,v 1.9 2007/09/29 08:50:13 agraef Exp $ */

/* flying_ggis.q: Another variation of the "Flying GGIs" theme. This one uses
   a custom font to render the text and an alpha buffer to make it translucent.
   Say `demo' to run. */

import ggi, system;

// config section; edit the following settings as needed

def // directories to search for font files
  FONT_DIRS = ["/usr/X11R6/lib/X11/fonts/truetype",
	       "/windows/fonts", "/winnt/fonts"],
  // name of font file
  FONT = "times.ttf",
  // for some font types you also have to set a font metric file here
  FONT_METRIC = (),
  // face index (0 will do for most purposes)
  INDEX = 0;

// globals

def WD = 640, HT = 480, BD = 10, SZ = 50, RES = 72,
  PROB = 0.1, MAXN = 5, MAXS = min WD HT/SZ, MINV = 5, MAXV = 15;

// color palette

def COL = map color [0..255], BLACK = hd COL, WHITE = last COL;

color I			= (shr I 5 and 7 * 0xffff div 7,
			   shr I 2 and 7 * 0xffff div 7,
			   I and 3 * 0xffff div 3);

// initialize the display

def VIS = ggi_open (),
  _ = ggi_set_mode VIS (sprintf "%dx%d" (WD,HT)) ||
  ggi_set_flags VIS GGI_FLAG_ASYNC,
  // use a memory visual to reduce flickering
  MEM = ggi_open "memory",
  _ = ggi_set_mode MEM (sprintf "%dx%d.[C24/32].A16" (WD,HT)) ||
  ggi_set_font MEM (search_font FONT) INDEX ||
  ggi_set_font_metrics MEM (search_font FONT_METRIC) ||
  size SZ || fg BLACK 0xffff || bg WHITE 0 || clr;

search_font FONT
= FONT where [FONT|_] = cat (map (glob.(++("/"++FONT))) FONT_DIRS);
= printf "Warning: %s could not be found -- using default font instead\n" FONT
    otherwise;

// adapt the maximum stretch according to the font

def (W,H) = ggi_get_string_size MEM "GGI", MAXS = min (WD/W) (HT/SZ);

// image descriptor: P = position, S = stretch, V = velocity (%), C = color

type Image = image P S V C;

// update the image list

update IMGS		= new (filter valid (map update1 IMGS));

update1 (image P S V C)	= image P (S+V/100) V C;

valid (image P S V C)	= S<=MAXS;

rand MIN MAX		= MIN + random mod (MAX-MIN+1);

new IMGS		= [image (X,Y) 1.0 V C|IMGS]
			    where X = rand BD (WD-BD),
			      Y = rand BD (HT-BD),
			      V = rand MINV MAXV,
			      C = COL!rand 0 254
			    if null IMGS or else
			      (#IMGS < MAXN) and then
			      (random/0xffffffff <= PROB);
			= IMGS otherwise;

// draw the image list

draw IMGS		= clr || do draw1 IMGS || show;

draw1 (image P S V C)	= fg C (round (0xffff/alpha S)) ||
			  size (round (S*SZ)) ||
			  center P "GGI";

alpha S			= 1+(S-1)/(MAXS-1);

// display operations

fg C A			= ggi_set_foreground MEM (append C A);
bg C A			= ggi_set_background MEM (append C A);

clr			= ggi_clear MEM;

show			= ggi_cross_blit MEM (0,0) (WD,HT) VIS (0,0) ||
			  ggi_flush VIS;

size SZ			= ggi_set_char_size MEM SZ RES;

center (X,Y) S		= ggi_puts MEM P S
			    where (W,H) = ggi_get_string_size MEM S,
			      P = (X - W div 2, Y - H div 2);

// main loop

loop IMGS		= ggi_getc VIS || () if ggi_kbhit VIS;
			= draw IMGS || sleep 0.05 || loop (update IMGS)
			    otherwise;

demo			= writes "Hit any key in the GGI window to stop\n" ||
			  flush || loop [];
