#include "demo.h"

int current_scene = -1;
char scene_name[50];

#define BEAT_LEN 21.41

#define FIRST_TRANS trans =

#define SCENE(enum) case enum: set_scene_name(#enum);



// Local prototypes
void fractal_tunnel1(poly_t * poly, int depth, vert_t * base, float arc_w);
void fractal_honeycomb(poly_t * poly, int depth, vert_t * base, float arc_w);
void boxes_fall_in(trans_t * list, int boxes, poly_t ** box, int * order, int mode, int base_delay);
void make_lblock(poly_t * block, int index);
void fractal_triangle(trans_t * list, poly_t ** tri, int * index, int depth, vert_t * base, int sides, float size, float angl_off);
void fractal_tree(trans_t * list, poly_t ** tree, int * index, int depth, vert_t * base, float angl_off, float scale, int flags);



enum
{
  txt_title1,
  txt_title2,

  txt_a,
  txt_suicide_cult,
  txt_production,
  
  txt_presented,
  txt_edison,
  
  txt_code_design,
  txt_hpl,
  
  txt_music,
  txt_modus,
  
  txt_triple,
  txt_no_really,
  txt_dont_do_drugs,
  
  txt_deep_and,
  txt_profound,
  txt_message,
  
  txt_test,
  txt_machinery,
  txt_assassins,
  
  txt_are, txt_we, txt_dead, txt_yet
};

char * strings[] =
{
  [txt_title1] = "I'm 14 and this",
  [txt_title2] = "is cool as SHIT",
  
  [txt_a] = "a",
  [txt_suicide_cult] = "suicide cult",
  [txt_production] = "production",
  
  [txt_code_design] = "code+design",
  [txt_hpl] = "happy pony land",
  
  [txt_music] = "music",
  [txt_modus] = "modus0perandi",
  
  [txt_presented] = "presented at",
  [txt_edison] = "edison 2o19",

  [txt_deep_and] = "deep and",
  [txt_profound] = "profound",
  [txt_message] = "message",
  
  [txt_no_really] = "(no really,",
  [txt_dont_do_drugs] = "don't do drugs)",
  
  [txt_are]  = "are",
  [txt_we]   = "we",
  [txt_dead] = "dead",
  [txt_yet]  = "yet?",
};


#define MAX_TRIPLE_STRINGS 40
char triple_string[] = "1we do not|2care about|3pop idols| | | |1our idols are|245 year old|3sceners| |1with|2no sense|3of fashion| |1who code|265o2|3and do| |4shrooms|5recreationally";

#define MAX_GLOW_STRINGS 50
char glow_string[] = "1we miss the|2glow of CRT|3monitors| | | |4we miss|58 bit sound| | | |1we miss|2living for|3the future| | |2knowing| | |2no| | |2boundaries";

#define GREETZ 11
char * greets[GREETZ] =
{
  "returnsvoid",
  "lazer81355",
  "oddmunds",
  "shozan",
  "jkpl",
  "rs3",
  "#lhasa",
  "miztluren",
  "norska fabler",
  "syntax terror",
  "greetz:",
};

#define KATANA_STRINGS 12
char * katana_string[KATANA_STRINGS] =
{
  "we offer",
  "2professional",
  "assassinations",
  "no questions asked",
  "no hidden fees",
  "2satisfaction",
  "guaranteed!",
  "contact us for",
  "group discount",
  "2premium",
  "alibi service",
  "call now ! ! !"
};

#define MACHINERY_STRINGS 13
char * machinery_string[MACHINERY_STRINGS] =
{
  "high-precision",
  "manufacturing",
  "low tolerances",
  "Nd:YAG 1.o6",
  "micrometer",
  "laser-machined",
  "steel",
  "titanium",
  "aluminium",
  "for all your",
  "engineering needs",
  "call today",
  "for quote"
};



#define STATS_LINES 10
#define STATS_LINE_LEN 100
char stats[STATS_LINES][STATS_LINE_LEN];



void set_scene_name(char * s)
{
  snprintf(scene_name, sizeof(scene_name), "%s", s);
  return;
}



poly_t * puzzle_block[20] =
{
  NULL, NULL, NULL, NULL, NULL,   NULL, NULL, NULL, NULL, NULL,
  NULL, NULL, NULL, NULL, NULL,   NULL, NULL, NULL, NULL, NULL
};
poly_t * big_blocks = NULL;



trans_t * init_scene(int chapter)
{
  trans_t * trans = NULL;
  trans_t * tran1 = NULL;
  
  poly_t * poly = NULL;

  int i = 0;
  int j = 0;
  int d = 0;
  int l = 0;

  switch (chapter)
  {
    SCENE(ch_blank)
      first_to_render = last_to_render = NULL;

    if (have_music)
      al_set_audio_stream_playing(music, true);  

    FIRST_TRANS
      new_trans(trans, NULL, 0, 0, 0, 500);
    break;


    
    SCENE(ch_pentagram)
    {
      poly_t * penta  = make_ngon(make_fixpoint(0, 0), 1, 5, 2);
      poly_t * circle = make_ngon(make_fixpoint(0, 0), 1, 50, 1);

      join_edges(penta, circle);

      penta->thicc = 20;
      apply_pal(penta, pal_blood);
        
      first_to_render =
        last_to_render = penta;
      
      FIRST_TRANS
        tran1 = new_trans(trans, &penta->scale, 50, 8.7, 550, 0);
      tran1->curve = CURVE_SQUARE;

      tran1 = new_trans(trans, &penta->origin->angl, 9.25, -0.25, 550, 0);
      tran1->curve = CURVE_RSQUARE;

      new_trans(trans, NULL, 0, 0, 620, 0);
    }
    break;


    
    SCENE(ch_title)
    {
      poly_t * text[2];

      text[0] = make_text(make_fixpoint(0, -1.2), strings[txt_title1]);
      text[1] = make_text(make_fixpoint(0, +1.2), strings[txt_title2]);

      for (i = 0; i < 2; i++)
      {
        text[i]->color = pal[pal_blood].color[0];
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->font = 1;
      }

      first_to_render = text[0];
      last_to_render = text[1];

      l = 1301 - frame;
      
      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, l, 0);

      trans_t * fade = new_trans_c(trans, &bg_color, 0, 0, 0, 200, 0, 0, l - 100, 100);
      fade->curve = CURVE_CUBIC;
    }
    break;


    
    SCENE(ch_tunnel1)
    {
      bg_color = cl_black;
      
      poly_t * tunnel[4];

      tunnel[0] = make_ngon(make_fixpoint(0, 0), 1, 25, 12);
      tunnel[1] = make_ngon(make_fixpoint(0, 0), 1, 24, 11);
      tunnel[2] = make_ngon(make_fixpoint(0, 0), 1, 23, 10);
      tunnel[3] = make_ngon(make_fixpoint(0, 0), 1, 22, 9);
        
      apply_pal(tunnel[0], pal_yellow);
      apply_pal(tunnel[1], pal_magenta);
      apply_pal(tunnel[2], pal_blood);
      apply_pal(tunnel[3], pal_green);
      
      first_to_render = tunnel[0];
      last_to_render = tunnel[3];

      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, 684, 0);

      tunnel[1]->visible = tunnel[2]->visible = tunnel[3]->visible = false;
        
      int cycle = 3;
      int timing = 0;
        
      for (int beat = 0; beat < 32; beat++)
      {
        timing = BEAT_LEN * beat;

        new_trans_i(trans, &tunnel[cycle]->visible, 0, 0, 1, timing);
        cycle = (cycle + 1) % 4;
        new_trans_i(trans, &tunnel[cycle]->visible, 1, 1, 1, timing);

        float extra_push = 0;

        switch (beat % 4)
        {
          case 0: extra_push = 6; break;
          case 1: extra_push = 2; break;
          case 2: extra_push = 0.2; break;
          default: extra_push = 0; break;
        }
        
        tran1 = new_trans(trans, &tunnel[cycle]->scale,
                          17 + beat / 2.0 + extra_push,
                          12 + beat / 2.0 - extra_push / 2.0,
                          BEAT_LEN, timing);
        tran1->curve = CURVE_CUBIC;
      }

      l = BEAT_LEN * 32;
      new_trans(trans, &tunnel[0]->origin->angl, 0, +6.75, l, 0);
      new_trans(trans, &tunnel[1]->origin->angl, 0, +6.75, l, 0);
      new_trans(trans, &tunnel[2]->origin->angl, 0, +6.75, l, 0);
      new_trans(trans, &tunnel[3]->origin->angl, 0, +6.75, l, 0);
    }
    break;


    
    SCENE(ch_boxes1)
    {
      poly_t * box[30];

      int rows = 5;
      float spacing = 20 / rows;
        
      poly_t * handles = make_poly(make_fixpoint(0, 0));
      handles->visible = false;

      for (i = 0; i < rows; i++)
      {
        for (j = 0; j < rows; j++)
        {
          add_cedge(handles,
                    spacing * i - ((float)(rows - 1) / 2.0) * (float)spacing,
                    spacing * j - ((float)(rows - 1) / 2.0) * (float)spacing);
        }
      }

      i = 0;

      for (edge_t * e = handles->first_edge; e; e = e->next)
      {
        box[i] = make_ngon(e->end, 2, 4, 1);
        box[i]->rotation = 0.125;
        box[i]->thicc = 10;
        apply_pal(box[i], pal_yellow);
        box[i]->flicker = true;
          
        i++;
      }

      poly_t * text1;
      poly_t * text2;

      text1 = make_text(clone_vert(box[6]->origin), strings[txt_code_design]);
      text1->color = pal[pal_yellow].color[0];
      text1->text_flags = ALLEGRO_ALIGN_LEFT;
      text1->visible = false;
      text1->origin->y -= 1;
        
      FIRST_TRANS
        new_trans_i(trans, &text1->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text1->visible, 0, 0, 1, 250);
      new_trans(trans, &text1->origin->x, -8.8, -9.4, 250, 0);

      text2 = make_text(clone_vert(box[6]->origin), strings[txt_hpl]);
      text2->color = pal[pal_yellow].color[pal[pal_yellow].colors - 1];
      text2->text_flags = ALLEGRO_ALIGN_LEFT;
      text2->visible = false;
      text2->origin->y += 1;

      new_trans_i(trans, &text2->visible, 1, 1, 1,   80);
      new_trans_i(trans, &text2->visible, 0, 0, 1,   250);
      tran1 = new_trans(trans, &text2->origin->x, -9.4, -8.8, 250, 0);

      box[1]->visible =
        box[6]->visible =
        box[11]->visible =
        box[16]->visible =
        false;

      int out_order[] =
        {
         4, 3, 2,
         9, 8, 7,
         14, 13, 12,
         19, 18, 17,
         24, 23, 22, 21,
         20, 15, 10, 5, 0
        };
        
      boxes_fall_in(trans, 21, box, out_order, 2, 150);

      int in_order[] =
        {
         24, 4, 19, 9, 14,
         8, 18, 23, 3, 13,
         2, 22, 7, 17, 12,
         21,
         20, 15, 10, 5, 0
        };

      boxes_fall_in(trans, 21, box, in_order, 0, 0);
        
      first_to_render = handles;
      last_to_render = text2;
    }
    break;


    
    SCENE(ch_boxes2)
    {
      poly_t * box[30];

      int rows = 5;
      float spacing = 20 / rows;
        
      poly_t * handles = make_poly(make_fixpoint(0, 0));
      handles->visible = false;

      for (i = 0; i < rows; i++)
      {
        for (j = 0; j < rows; j++)
        {
          add_cedge(handles,
                    spacing * i - ((float)(rows - 1) / 2.0) * (float)spacing,
                    spacing * j - ((float)(rows - 1) / 2.0) * (float)spacing);
        }
      }

      i = 0;

      for (edge_t * e = handles->first_edge; e; e = e->next)
      {
        box[i] = make_ngon(e->end, 2, 4, 1);
        box[i]->rotation = 0.125;
        box[i]->thicc = 10;
        apply_pal(box[i], pal_magenta);
        box[i]->flicker = true;
          
        i++;
      }

      poly_t * text1;
      poly_t * text2;

      text1 = make_text(clone_vert(box[18]->origin), strings[txt_music]);
      text1->color = pal[pal_magenta].color[0];
      text1->text_flags = ALLEGRO_ALIGN_RIGHT;
      text1->visible = false;
      text1->origin->y -= 1;
        
      FIRST_TRANS
        new_trans_i(trans, &text1->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text1->visible, 0, 0, 1, 250);
      new_trans(trans, &text1->origin->x, +8.8, +9.4, 250, 0);

      text2 = make_text(clone_vert(box[18]->origin), strings[txt_modus]);
      text2->color = pal[pal_magenta].color[pal[pal_magenta].colors - 1];
      text2->text_flags = ALLEGRO_ALIGN_RIGHT;
      text2->visible = false;
      text2->origin->y += 1;
        
      new_trans_i(trans, &text2->visible, 1, 1, 1, 80);
      new_trans_i(trans, &text2->visible, 0, 0, 1, 250);
      new_trans(trans, &text2->origin->x, +9.4, +8.8, 250, 0);
        
      box[23]->visible =
        box[18]->visible =
        box[13]->visible =
        box[8]->visible =
        false;
                
      int out_order[22] =
        {
         24, 19, 14, 9, 4,
         3,
         2, 7, 12, 17, 22,
         21, 16, 11, 6, 1,
         0, 5, 10, 15, 20
        };
                      
      boxes_fall_in(trans, 21, box, out_order, 2, 150);
        
      int in_order[22] =
        {
         24,
         /*23,*/ 19,
         22, /*18,*/ 14,
         21, 17, /*13,*/ 9,
         20, 16, 12, 4,
         15, 11, 7,  3,
         10, 6,  2,
         5,  1,
        };
        
      boxes_fall_in(trans, 21, box, in_order, 1, 0);

      first_to_render = handles;
      last_to_render = text2;
    }
    break;


    
    SCENE(ch_boxes3)
    {
      poly_t * box[30];
      
      int rows = 5;
      float spacing = 20 / rows;
      
      poly_t * handles = make_poly(make_fixpoint(0, 0));
      handles->visible = false;
      
      for (i = 0; i < rows; i++)
      {
        for (j = 0; j < rows; j++)
        {
          add_cedge(handles,
                    spacing * i - ((float)(rows - 1) / 2.0) * (float)spacing,
                    spacing * j - ((float)(rows - 1) / 2.0) * (float)spacing);
        }
      }
      
      i = 0;
      
      for (edge_t * e = handles->first_edge; e; e = e->next)
      {
        box[i] = make_ngon(e->end, 2, 4, 1);
        box[i]->rotation = 0.125;
        box[i]->thicc = 10;
        apply_pal(box[i], pal_green);
        box[i]->flicker = true;
          
        i++;
      }

      poly_t * text1;
      poly_t * text2;

      text1 = make_text(clone_vert(box[14]->origin), strings[txt_presented]);
      text1->color = pal[pal_green].color[0];
      text1->text_flags = ALLEGRO_ALIGN_CENTER;
      text1->visible = false;
      text1->origin->y -= 1;
          
      FIRST_TRANS
        new_trans_i(trans, &text1->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text1->visible, 0, 0, 1, 200);
      new_trans(trans, &text1->origin->x, +0.5, -0.5, 250, 0);

      text2 = make_text(clone_vert(box[14]->origin), strings[txt_edison]);
      text2->color = pal[pal_green].color[pal[pal_green].colors - 1];
      text2->text_flags = ALLEGRO_ALIGN_CENTER;
      text2->visible = false;
      text2->origin->y += 1;
        
      new_trans_i(trans, &text2->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text2->visible, 0, 0, 1, 200);
      new_trans(trans, &text2->origin->x, -0.5, +0.5, 250, 0);

      box[9]->visible =
        box[14]->visible =
        box[19]->visible = false;
                
      int out_order[] =
        {
         24, 4,
         3, 8, 13, 18, 23,
         22, 17, 12, 7, 2,
         1, 6, 11, 16, 21,
         20, 15, 10, 5, 0
        };
                      
      boxes_fall_in(trans, 22, box, out_order, 2, 80);
        
      int in_order[] =
        {
         4, 24,
         23, 18, 13, 8, 3,
         2, 7, 12, 17, 22,
         21, 16, 11, 6, 1,
         0, 5, 10, 15, 20
        };
        
      boxes_fall_in(trans, 22, box, in_order, 0, 0);

      first_to_render = handles;
      last_to_render = text2;
    }
    break;


    
    SCENE(ch_boxes4)
    {
      poly_t * box[30];

      int rows = 5;
      float spacing = 20 / rows;
        
      poly_t * handles = make_poly(make_fixpoint(0, 0));
      handles->visible = false;

      for (i = 0; i < rows; i++)
      {
        for (j = 0; j < rows; j++)
        {
          add_cedge(handles,
                    spacing * i - ((float)(rows - 1) / 2.0) * (float)spacing,
                    spacing * j - ((float)(rows - 1) / 2.0) * (float)spacing);
        }
      }

      i = 0;

      for (edge_t * e = handles->first_edge; e; e = e->next)
      {
        box[i] = make_ngon(e->end, 2, 4, 1);
        box[i]->rotation = 0.125;
        box[i]->thicc = 10;
        apply_pal(box[i], pal_orange);
        box[i]->flicker = true;
          
        i++;
      }

      poly_t * text1;
      poly_t * text2;
      poly_t * text3;

      text1 = make_text(clone_vert(box[16]->origin), strings[txt_a]);
      text1->color = pal[pal_orange].color[0];
      text1->text_flags = ALLEGRO_ALIGN_CENTER;
      text1->visible = false;
      text1->origin->y = box[5]->origin->y;
      text1->origin->x = box[5]->origin->x;
          
      FIRST_TRANS
        new_trans_i(trans, &text1->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text1->visible, 0, 0, 1, 200);
      new_trans(trans, &text1->origin->y, text1->origin->y, text1->origin->y + 1, 250, 0);
      
      text2 = make_text(clone_vert(box[16]->origin), strings[txt_production]);
      text2->color = pal[pal_orange].color[0];
      text2->text_flags = ALLEGRO_ALIGN_CENTER;
      text2->visible = false;
      text2->origin->y += 1;
        
      new_trans_i(trans, &text2->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text2->visible, 0, 0, 1, 200);
      new_trans(trans, &text2->origin->x, +0.5, -0.5, 250, 0);

      text3 = make_text(clone_vert(box[16]->origin), strings[txt_suicide_cult]);
      text3->color = pal[pal_orange].color[pal[pal_orange].colors - 1];
      text3->text_flags = ALLEGRO_ALIGN_CENTER;
      text3->visible = false;
      text3->origin->y -= 1;
        
      new_trans_i(trans, &text3->visible, 1, 1, 1, 60);
      new_trans_i(trans, &text3->visible, 0, 0, 1, 200);
      new_trans(trans, &text3->origin->x, -0.5, +0.5, 250, 0);

      box[5]->visible =
        box[6]->visible =
        box[11]->visible =
        box[16]->visible =
        false;
                
      int out_order[22] =
        {
         4, 3, 2, 1, 0,
         9, 8, 7,
         14, 13, 12,
         19, 18, 17,
         24, 23, 22, 21, 20,
         15, 10 /*, 5*/
        };
                      
      boxes_fall_in(trans, 21, box, out_order, 2, 120);
        
      int in_order[22] =
        {
         0, /*5,*/
         1,
         2, 7,
         3, 8, 13,
         4, 9,
         14, 19, 24,
         18, 23,
         12, 17, 22,
         21,
         10, 15, 20
        };
        
      boxes_fall_in(trans, 21, box, in_order, 5, 0);

      first_to_render = handles;
      last_to_render = text3;
    }
    break;



    SCENE(ch_ring_spinner)
    {
#define RSPIN_SEGMENTS 9
#define RSPIN_SIDES    19
      
      poly_t * big_spinner = make_ngon(make_fixpoint(0, 0), 6.2, RSPIN_SEGMENTS, 1);
      poly_t * spinner[RSPIN_SEGMENTS];

      {
        edge_t * e = big_spinner->first_edge;
        
        for (i = 0; i < RSPIN_SEGMENTS; i++)
        {
          ASSERT(e != NULL);
          spinner[i] = make_ngon(e->start, 2, RSPIN_SIDES, 1);
          spinner[i]->visible = false;
          e = e->next;
        }
      }

      big_spinner->visible = false;

      l = 4566 - frame;
      if (l < 0) l = 500;
      
      FIRST_TRANS
        new_trans(trans, &big_spinner->origin->angl, 0, -1.1, l, 0);

      poly_t * tri[RSPIN_SIDES];
      edge_t * e[RSPIN_SEGMENTS];
      
      for (int j = 0; j < RSPIN_SEGMENTS; j++)
      {
        e[j] = spinner[j]->first_edge;
        new_trans(trans, &spinner[j]->origin->dist, spinner[j]->origin->dist, spinner[j]->origin->dist + 1, 650, 0);
      }

      for (i = 0; i < RSPIN_SIDES; i++)
      {
        for (int j = 0; j < RSPIN_SEGMENTS; j++)
        {
          ASSERT(e[j] != NULL);
        }

        tri[i] = make_poly(make_fixpoint(0, 0));
        tri[i]->thicc = 2;
        tri[i]->single_color = true;
        tri[i]->color = al_map_rgb(255, 155, 55);

        int color_d = i * 5;
        new_trans_c(trans, &tri[i]->color, 255, 155,  55, 255, 255,  55, 200, color_d);
        new_trans_c(trans, &tri[i]->color, 255, 255,  55, 255, 155, 155, 200, color_d + 200);
        new_trans_c(trans, &tri[i]->color, 255, 155, 155, 255, 155,  55, 200, color_d + 400);

        vert_t * anchor_v[RSPIN_SEGMENTS];

        for (int j = 0; j < RSPIN_SEGMENTS; j++)
          anchor_v[j] = make_anchor(e[j]->start);

        for (int j = 0; j < RSPIN_SEGMENTS; j++)
          add_edge(tri[i], anchor_v[j], anchor_v[(j + 1) % RSPIN_SEGMENTS]);
        
        for (int j = 0; j < RSPIN_SEGMENTS; j++)
          e[j] = e[j]->next;
      }

      new_trans(trans, &spinner[ 0]->rotation, -0.1, -0.6, l, 0);
      new_trans(trans, &spinner[ 1]->rotation, +0.7, -0.3, l, 0);
      new_trans(trans, &spinner[ 2]->rotation, +0.1, +0.1, l, 0);
      new_trans(trans, &spinner[ 3]->rotation, -0.6, +0.9, l, 0);
      new_trans(trans, &spinner[ 4]->rotation, +0.3, -0.7, l, 0);
      new_trans(trans, &spinner[ 5]->rotation, -0.3, +0.7, l, 0);
      new_trans(trans, &spinner[ 6]->rotation, +0.1, -0.2, l, 0);
      new_trans(trans, &spinner[ 7]->rotation, +0.4, +0.6, l, 0);
      new_trans(trans, &spinner[ 8]->rotation, -0.5, +0.9, l, 0);

      poly_t * text[MAX_GLOW_STRINGS];
      char * p = glow_string;

      for (i = 0; i < MAX_GLOW_STRINGS; i++)
      {
        float y = 0;
        
        if      (*p == '1') y = -3;
        else if (*p == '3') y = +3;
        else if (*p == '4') y = -1.5;
        else if (*p == '5') y = +1.5;

        text[i] = make_text(make_fixpoint(0, y), p + 1);
        
        char * next = strchr(p, '|');

        if (next != NULL)
        {
          p = next;
          *p = 0;
          p++;
        }
        
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->visible = false;
        text[i]->font = 1;

        int l = 24;
        d = i * l;
        new_trans_i(trans, &text[i]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, d + l * 4);

        trans_t * color_trans = new_trans_ca(trans, &text[i]->color,
                                             0, 0, 0, 0,
                                             255, 185, 85, 155,
                                             l * 4, d);
        color_trans->curve = CURVE_BUMP;

        if (next == NULL)
          break;
      }

      first_to_render = big_spinner;
      last_to_render = text[i];
    }
    break;

    

    SCENE(ch_triple)
    {
      poly_t * ring[3];
        
      ring[0] = make_ngon(make_fixpoint(0, 0), 9.5, 10, 2);
      ring[1] = make_ngon(make_fixpoint(0, 0), 7.3, 5, 1);
      ring[2] = make_ngon(make_fixpoint(0, 0), 5.5, 10, 1);
        
      for (i = 0; i < 3; i++)
        apply_pal(ring[i], pal_blue);

      l = 450;

      ASSERT(l > 0);
      
      FIRST_TRANS
        new_trans(trans, &ring[0]->origin->angl, -0.4, 0.1, l, 0);
      new_trans(trans, &ring[1]->origin->angl, +0.6, 0.1, l, 0);
      new_trans(trans, &ring[2]->origin->angl, -1.2, 0.1, l, 0);

      for (i = 0; i < 3; i++)
        new_trans(trans, &ring[i]->scale, 0.5, 1.0, l, 0);

      poly_t * text[MAX_TRIPLE_STRINGS];

      char * p = triple_string;

      for (i = 0; i < MAX_TRIPLE_STRINGS; i++)
      {
        float y = 0;

        if      (*p == '1') y = -2;
        else if (*p == '3') y = +2;
        else if (*p == '4') y = -1;
        else if (*p == '5') y = +1;

        text[i] = make_text(make_fixpoint(0, y), (p + 1));
        
        char * next = strchr(p, '|');

        if (next != NULL)
        {
          p = next;
          *p = 0;
          p++;
        }
        
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->visible = false;

        int l = BEAT_LEN - 3;
        d = i * l;
        new_trans_i(trans, &text[i]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, d + l * 4);

        new_trans(trans, &text[i]->origin->x, text[i]->origin->x + 13.0, text[i]->origin->x + 1.5, l, d);
        new_trans(trans, &text[i]->origin->x, text[i]->origin->x + 1.5, text[i]->origin->x - 1.5, l * 2, d + l);
        new_trans(trans, &text[i]->origin->x, text[i]->origin->x - 1.5, text[i]->origin->x - 13.0, l, d + l * 3);

        trans_t * color_trans = new_trans_ca(trans, &text[i]->color,
                                             0, 0, 0, 0,
                                             150, 200, 250, 150,
                                             l * 5, d);
        color_trans->curve = CURVE_BUMP;

        if (next == NULL)
          break;
      }

      first_to_render = ring[0];
      last_to_render = text[i];
    }
    break;



    SCENE(ch_dont_do_drugs)
    {
      poly_t * text[2];
      text[0] = make_text(make_fixpoint(0, -1), strings[txt_no_really]);
      text[1] = make_text(make_fixpoint(0, +1), strings[txt_dont_do_drugs]);
      text[0]->text_flags = text[1]->text_flags = ALLEGRO_ALIGN_CENTER;

      first_to_render = text[0];
      last_to_render = text[1];
      
      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, 50, 0);
    }
    break;


    
    SCENE(ch_katana)
    {
      poly_t * katana = make_poly(make_fixpoint(0, 0));
#include "katana.c"
      
      katana->scale = 80;
      katana->thicc = 2;
      katana->flicker = true;
      
      apply_pal(katana, pal_green);
      
      l = 450;

      FIRST_TRANS
        new_trans(trans, &katana->origin->x, -0.65, +0.65, l, 0);
      
      poly_t * text[KATANA_STRINGS];

      d = 0;

      for (i = 0; i < KATANA_STRINGS; i++)
      {
#define KATANA_FORMAT(index)                                            \
        text[index]->text_flags = ALLEGRO_ALIGN_CENTER;                 \
        text[index]->color = pal[pal_green].color[pal[pal_green].colors / 2]; \
        text[index]->visible = false;                                   \
        new_trans_i(trans, &text[index]->visible, 1, 1, 1, d);          \
        new_trans_i(trans, &text[index]->visible, 0, 0, 1, d + 60);     \
        new_trans(trans, &text[index]->origin->y, text[index]->origin->y + 0.5, text[index]->origin->y + 0.0, 20, d); \
        new_trans(trans, &text[index]->origin->y, text[index]->origin->y,       text[index]->origin->y - 0.5, 20, d + 40); \
        new_trans_ca(trans, &text[index]->color, 0, 0,   0, 0,   0, 255, 0, 255, 30, d); \
        new_trans_ca(trans, &text[index]->color, 0, 255, 0, 255, 0, 0,   0, 0,   30, d + 30);

        if (katana_string[i][0] == '2')
        {
          text[i] = make_text(make_fixpoint(0, 6.5), katana_string[i] + 1);
          KATANA_FORMAT(i);
          i++;
          text[i] = make_text(make_fixpoint(0, 8.5), katana_string[i]);
        }
        else
        {
          text[i] = make_text(make_fixpoint(0, 7.5), katana_string[i]);
        }

        KATANA_FORMAT(i);

        d += 50;
      }
      
      first_to_render = katana;
      last_to_render = text[KATANA_STRINGS - 1];
    }
    break;
    

    
    SCENE(ch_blocks2)
    {
      poly_t * u1;
      poly_t * u2;
      poly_t * w1; // wedge
      poly_t * w2;
        
      u1 = make_poly(make_fixpoint(-1, 0));
      add_cedge(u1, 0, -2);
      add_cedge(u1, +1, -3);
      add_cedge(u1, +1, -1);
      add_cedge(u1, +2, -2);
      add_cedge(u1, +2, -3);
      add_cedge(u1, +3, -4);
      add_cedge(u1, +3, 0);
      add_cedge(u1, 0, 0);
      u1->scale = 2;
        
      w1 = make_poly(make_fixpoint(-1, 0));
      add_cedge(w1, +1, -1);
      add_cedge(w1, +1, -2);
      add_cedge(w1, -1, -2);
      add_cedge(w1, -1, -1);
      add_cedge(w1, -1, +2);
      add_cedge(w1, 0, +1);
      add_cedge(w1, 0, 0);
      w1->scale = 2;

      u2 = clone_poly(u1);
      u2->scale *= -1;
      w2 = clone_poly(w1);
      w2->scale *= -1;
        
      first_to_render = u1;
      last_to_render = w2;

      // Enter
      float f_d = 0;
      float f_l = BEAT_LEN - 1;

      l = 11;
      FIRST_TRANS
        new_trans(trans, &u1->origin->y, -5, -0, l, f_d);
      new_trans(trans, &u2->origin->y, -5, -0, l, f_d);
      new_trans(trans, &w1->origin->y, -7, -2, l, f_d);
      new_trans(trans, &w2->origin->y, -7, -2, l, f_d);
      f_d += f_l;

      new_trans(trans, &u1->origin->x, -1, +0.5, l, f_d);
      new_trans(trans, &u2->origin->x, -1, +0.5, l, f_d);
      new_trans(trans, &w1->origin->x, -1, +0.5, l, f_d);
      new_trans(trans, &w2->origin->x, -1, +0.5, l, f_d);
      f_d += f_l;

      new_trans(trans, &u1->origin->y, 0, +1.5, l, f_d);
      new_trans(trans, &u2->origin->y, 0, +1.5, l, f_d);
      new_trans(trans, &w1->origin->y, -2, -1.5, l, f_d);
      new_trans(trans, &w2->origin->y, -2, -1.5, l, f_d);
      f_d += f_l;

      new_trans(trans, &u1->origin->x, +0.5, -0.5, l, f_d);
      new_trans(trans, &u2->origin->x, +0.5, -0.5, l, f_d);
      new_trans(trans, &w1->origin->x, +0.5, +1.5, l, f_d);
      new_trans(trans, &w2->origin->x, +0.5, +1.5, l, f_d);
      new_trans(trans, &u1->origin->y, +1.5, +2.5, l, f_d);
      new_trans(trans, &u2->origin->y, +1.5, +2.5, l, f_d);
      new_trans(trans, &w1->origin->y, -1.5, -2.5, l, f_d);
      new_trans(trans, &w2->origin->y, -1.5, -2.5, l, f_d);
      f_d += f_l;
        
      new_trans(trans, &w1->origin->y, -2.5, -0.5, l, f_d);
      new_trans(trans, &w2->origin->y, -2.5, -0.5, l, f_d);

      new_trans_c(trans, &bg_color,
                    200, 200, 200,
                    0, 0, 0,
                    20, f_d + l);
      
      f_d += f_l;
            
      new_trans(trans, &u1->scale, 1.8, 2.2, f_d + 21, 0);
      new_trans(trans, &w1->scale, 1.8, 2.2, f_d + 21, 0);
      new_trans(trans, &u2->scale, -1.8, -2.2, f_d + 21, 0);
      new_trans(trans, &w2->scale, -1.8, -2.2, f_d + 21, 0);

    }
    break;

    

    SCENE(ch_spinners)
    {
      poly_t * spinner[4];
      poly_t * arm[4];

      vert_t * center = make_fixpoint(0, 0);

      poly_t * baseplate = make_ngon(center, 9.5, 50, 1);
        
      arm[0] = make_poly(center);
      add_edge(arm[0], clone_vert(arm[0]->origin), make_polar(0, 5.01));
        
      arm[1] = make_poly(arm[0]->first_edge->end);
      add_edge(arm[1], clone_vert(arm[0]->first_edge->end), make_polar(0, 1.81));
        
      arm[2] = make_poly(arm[1]->first_edge->end);
      add_edge(arm[2], clone_vert(arm[1]->first_edge->end), make_polar(0, 0.96));

      spinner[0] = make_ngon(arm[0]->first_edge->end, 4.35, 50, 1);
      spinner[1] = make_ngon(arm[1]->first_edge->end, 2.4, 50, 1);
      spinner[2] = make_ngon(arm[2]->first_edge->end, 1.3, 50, 1);

      baseplate->thicc = spinner[0]->thicc = spinner[1]->thicc = spinner[2]->thicc = 2;

      arm[0]->visible = arm[1]->visible = arm[2]->visible = false;

      trans_t * acc;
      trans_t * acc2;
      trans_t * brake;

      baseplate->rotation =
        arm[0]->first_edge->end->angl = 
        arm[1]->first_edge->end->angl =
        arm[2]->first_edge->end->angl =
        0.25;
        
      baseplate->origin->y = +1.5;
      baseplate->scale = 0.8;
      spinner[0]->scale = 0.8;
      spinner[1]->scale = 0.8;
      spinner[2]->scale = 0.8;

      FIRST_TRANS
        acc = new_trans(trans, &baseplate->rotation, +0.000035, +0.000035, 400, 0);
      acc->vel_f = 0.003;
      acc->inertia = 200;

      brake = new_trans(trans, &baseplate->rotation, -0.00001, -0.00001, 350, 400);
      brake->inertia_chain = acc;
      brake->inertia = 300;

      // Arm 0
      acc = new_trans(trans, &arm[0]->first_edge->end->angl, +0.000035, +0.000035, 400, 0);
      acc->vel_f = 0.003;
      acc->inertia = 200;

      brake = new_trans(trans, &arm[0]->first_edge->end->angl, -0.000016, -0.000016, 350, 400);
      brake->inertia_chain = acc;
      brake->inertia = 300;

      // Arm 1
      acc = new_trans(trans, &arm[1]->first_edge->end->angl, -0.00004, -0.00004, 200, 0);
      acc->vel_f = -0.012;
      acc->inertia = 300;

      brake = new_trans(trans, &arm[1]->first_edge->end->angl, -0.000016, -0.000016, 400, 200);
      brake->inertia_chain = acc;
      brake->inertia = 300;

      acc2 = new_trans(trans, &arm[1]->first_edge->end->angl, +0.00008, +0.00008, 150, 600);
      acc2->inertia_chain = acc;
      acc2->inertia = 300;

      // Arm 2
      acc = new_trans(trans, &arm[2]->first_edge->end->angl, +0.00006, +0.00006, 400, 0);
      acc->vel_f = +0.020;
      acc->inertia = 400;

      acc2 = new_trans(trans, &arm[2]->first_edge->end->angl, -0.00025, -0.00025, 200, 400);
      acc2->inertia_chain = acc;
      acc2->inertia = 200;

      brake = new_trans(trans, &arm[2]->first_edge->end->angl, -0.00002, -0.00002, 150, 600);
      brake->inertia_chain = acc;
      brake->inertia = 200;

      poly_t * text[MACHINERY_STRINGS];

      for (i = 0; i < MACHINERY_STRINGS; i++)
      {
        text[i] = make_text(make_fixpoint(0, -8), machinery_string[i]);
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->color = pal[pal_green].color[pal[pal_green].colors / 2];

        text[i]->visible = false;

        d = 60 + i * 50;
        new_trans_i(trans, &text[i]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, d + 60);
        
        new_trans(trans, &text[i]->origin->x, text[i]->origin->x + 20.0, text[i]->origin->x + 0.0, 20, d);
        new_trans(trans, &text[i]->origin->x, text[i]->origin->x,        text[i]->origin->x - 20.0, 20, d + 40);

        new_trans_c(trans, &text[i]->color, 0, 0, 0, 255, 255, 255, 20, d);
        new_trans_c(trans, &text[i]->color, 255, 255, 255, 0, 0, 0, 20, d + 40);
      }

      first_to_render = baseplate;
      last_to_render  = text[MACHINERY_STRINGS - 1];
    }
    break;

    

    SCENE(ch_blocks_big)
    {
      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, 10, 0);

#define LBLOCK_TIME  21
#define LBLOCK_DELAY 12
#define SETUP_LBLOCK(index, start_x, start_y)                           \
      puzzle_block[index] = make_poly(make_fixpoint(start_x, start_y)); \
      new_trans(trans, &puzzle_block[index]->scale, 1.5, 1.7, 250, 0);           
      
#define SETUP_LBLOCK_L(index, start_x, start_y)                         \
      SETUP_LBLOCK(index, start_x, start_y);                            \
      new_trans(trans, &puzzle_block[index]->origin->x,                 \
                puzzle_block[index]->origin->x + 20,                    \
                puzzle_block[index]->origin->x, LBLOCK_TIME, d);        \
      puzzle_block[index]->origin->x += 20;                             \
      d += LBLOCK_DELAY;

#define SETUP_LBLOCK_D(index, start_x, start_y)                         \
      SETUP_LBLOCK(index, start_x, start_y);                            \
      new_trans(trans, &puzzle_block[index]->origin->y,                 \
                puzzle_block[index]->origin->y - 20,                    \
                puzzle_block[index]->origin->y, LBLOCK_TIME, d);        \
      puzzle_block[index]->origin->y -= 20;                             \
      d += LBLOCK_DELAY;

      int d = 0;
      
      SETUP_LBLOCK_L( 0, -5, +5);
      SETUP_LBLOCK_D( 1, -5, +4);
      SETUP_LBLOCK_L( 2, -3, +3);
      SETUP_LBLOCK_L( 3, -2, +5);
      SETUP_LBLOCK_D( 4, -5, +1);
      SETUP_LBLOCK_L( 5, -5, -1);
      SETUP_LBLOCK_D( 6, -3, -1);
      SETUP_LBLOCK_L( 7, -5, -4);
      SETUP_LBLOCK_D( 8, -1, +3);
      SETUP_LBLOCK_L( 9, -0, +5);
      SETUP_LBLOCK_D(10, -1, +1);
      SETUP_LBLOCK_L(11, -2, -3);
      SETUP_LBLOCK_L(12, +1, +3);
      SETUP_LBLOCK_D(13, +3, +5);
      SETUP_LBLOCK_L(14, +3, +2);
      SETUP_LBLOCK_D(15, +1, +1);
      SETUP_LBLOCK_L(16, +0, -2);
      SETUP_LBLOCK_L(17, +0, -3);
      SETUP_LBLOCK_D(18, +3, -1);
      SETUP_LBLOCK_L(19, +2, -3);
      
      for (i = 0; i < 20; i++)
      {
        make_lblock(puzzle_block[i], i);
        puzzle_block[i]->thicc = 1;
      }

      first_to_render = puzzle_block[0];
      last_to_render = puzzle_block[19];
    }
    break;

    

    SCENE(ch_blocks_big_spin)
    {
      big_blocks = make_poly(make_polar(0, 0));

      for (i = 0; i < 20; i++)
      {
        normalize_origin(puzzle_block[i]);
        join_edges(big_blocks, puzzle_block[i]);
      }

      big_blocks = convert_polar(big_blocks, 0, 0);

      big_blocks->thicc = 1;
      big_blocks->scale = 1.7;
      
      first_to_render =
        last_to_render =
        big_blocks;
    }
    break;


    
    SCENE(ch_skull)
    {
      FIRST_TRANS
        new_trans_c(trans, &bg_color,
                    200, 200, 200,
                    0, 0, 0,
                    20, 0);
      
      new_trans(trans, &big_blocks->origin->angl, 0, 0.25, 21, 0);
      new_trans(trans, &big_blocks->origin->y, +0, +15, 50, 28);

      poly_t * skull = make_poly(make_fixpoint(0, +2.1));

#include "skull.c"

      skull->scale = 2.2;
      skull->thicc = 2;
      skull->single_color = true;
      skull->color = al_map_rgb(200, 0, 0);

      new_trans(trans, &skull->origin->y, skull->origin->y - 10, skull->origin->y, 50, 14);
      skull->origin->y -= 10;
              
      int timing = 6958 - frame;

      poly_t * rotator = make_ngon(make_fixpoint(0, 0), 5.5, 15, 1);
      rotator->visible = false;
      new_trans(trans, &rotator->origin->angl, 0, 1.1, timing, 0);

      // fade to red at end; reset by next chapter
      new_trans_c(trans, &bg_color, 0, 0, 0, 200, 0, 0, 50, timing - 50);

      poly_t * skull_polar = convert_polar(skull, 0, 0);
      int skull_index = 0;
      poly_t * last_skull;
            
      for (edge_t * e = rotator->first_edge; e != NULL; e = e->next)
      {
        last_skull = clone_poly(skull_polar);
        last_skull->thicc = 2;
        last_skull->link_angl = true;
        last_skull->rotation = 0.25;
        last_skull->single_color = true;
        last_skull->color = al_map_rgb(200, 0, 0);

        last_skull->origin = e->start;

        last_skull->origin->dist = 16;
        new_trans(trans, &last_skull->origin->dist, last_skull->origin->dist, 5.5, 16, 220 - skull_index * 12);

        skull_index++;
      }

      skull_polar->visible = false;

      skull_polar->origin->angl = 0.1;

      poly_t * text[4];
      vert_t * text_fix = make_fixpoint(0, -2.5);
      
      text[0] = make_text(text_fix, strings[txt_are]);
      text[1] = make_text(text_fix, strings[txt_we]);
      text[2] = make_text(text_fix, strings[txt_dead]);
      text[3] = make_text(text_fix, strings[txt_yet]);

      for (i = 0; i < 4; i++)
      {
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->color = pal[pal_blood].color[0];
        text[i]->visible = false;
        new_trans_i(trans, &text[i]->visible, 1, 1, 1, 150 + i * BEAT_LEN);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, 150 + i * BEAT_LEN + 12);
      }

      first_to_render = big_blocks;
      last_to_render = text[3];
    }
    break;



    SCENE(ch_fractal_trees)
    {
#define TREE_HEAP 1000000
      
      poly_t * tree[TREE_HEAP];
      
      tree[0] = make_ngon(make_fixpoint(0, 0), 0, 5, 1);

#define FTREE_END 8730
      
      int l = FTREE_END - frame;
        
      FIRST_TRANS
        new_trans(trans, &tree[0]->rotation, 0, 0.4, l, 0);

      int index = 1;

      for (edge_t * e = tree[0]->first_edge; e != NULL; e = e->next)
      {
        fractal_tree(trans, tree, &index, 6, e->start, 0, 0.5, 7);
      }

      for (i = 0; i < index; i++)
      {
        tree[i]->thicc = 2;
        apply_pal(tree[i], pal_green);
      }
      
      first_to_render = tree[0];
      last_to_render = tree[index - 1];
    }
    break;
    
    
    
    SCENE(ch_triangles)
    {
      bg_color = cl_black;
      
#define TRIANGLE_HEAP 10000
      
      poly_t * tri[TRIANGLE_HEAP];

      tri[0] = make_ngon(make_fixpoint(0, 0), 0.5, 7, 1);

#define TRIANGLES_END 8080

      l = TRIANGLES_END - frame;
      
      FIRST_TRANS
        new_trans(trans, &tri[0]->rotation, 0, 3.3, l, 0);

      int index = 1;

      for (edge_t * e = tri[0]->first_edge; e != NULL; e = e->next)
        fractal_triangle(trans, tri, &index, 20, e->start, 3, 2, 0);

      first_to_render = tri[0];
      last_to_render  = tri[index - 1];
      
      for (i = 0; i < index; i++)
        tri[i]->thicc = 2;
      
      for (i = 0; i < index; i++)
        apply_pal(tri[i], pal_orange);
    }
    break;



    SCENE(ch_fractal_honeycomb)
    {
      poly = make_poly(make_fixpoint(0, 0));
        
      int sides = 22;
      float arc_w = (float)FULL_CIRCLE / (float)sides;

      for (i = 0; i < sides; i++)
      {
        float angl = arc_w * (float)i;
        fractal_honeycomb(poly, 40, make_polar(angl, 1), arc_w);
      }

      apply_pal(poly, pal_rainbow);
      poly->thicc = 2;

      int section_l = 75;
      d = 0;

      FIRST_TRANS
        new_trans(trans, &poly->scale, 14, 100, section_l, 0);
      new_trans(trans, &poly->scale, 100, 2000, section_l, section_l);
      new_trans(trans, &poly->scale, 2000, 50000, section_l, section_l * 2);
      new_trans(trans, &poly->scale, 50000, 60000, section_l * 2, section_l * 3);

      l = 3871 - frame;

      ASSERT(l > 0);
      
      new_trans(trans, &poly->origin->angl, 0, 1.5, l, 0);

      new_trans(trans, &poly->scale, 60000, 0.000001, section_l * 5, l - section_l * 5 - 5);

      poly_t * text[3];
      text[0] = make_text(make_fixpoint(0, -2), strings[txt_deep_and]);
      text[1] = make_text(make_fixpoint(0,  0), strings[txt_profound]);
      text[2] = make_text(make_fixpoint(0, +2), strings[txt_message]);

      for (i = 0; i < 3; i++)
      {
        text[i]->text_flags = ALLEGRO_ALIGN_CENTER;
        text[i]->color = pal[pal_green].color[19];
        text[i]->visible = false;

        new_trans_i(trans, &text[i]->visible, 1, 1, 1, section_l * 3 + 20);
        new_trans_ca(trans, &text[i]->color,
                     0, 0, 0, 0,
                     0, 150, 0, 255,
                     section_l, section_l * 3 + 20);

        new_trans_i(trans, &text[i]->visible, 0, 0, 1, l - section_l);
        new_trans_ca(trans, &text[i]->color,
                     0, 150, 0, 0,
                     0, 0,   0, 0,
                     section_l, l - section_l - 200);
      }

      first_to_render = poly;
      last_to_render = text[2];
    }
    break;



    SCENE(ch_fish)
    {
      poly_t * fish = make_poly(make_fixpoint(0, 0));

#include "fish.c"
      
      fish->scale = 80;
      fish->thicc = 3;
      
      apply_pal(fish, pal_blue);

      l = 400;
      
      FIRST_TRANS
        new_trans(trans, &fish->scale, 15, 19, l, 0);

      new_trans(trans, &fish->origin->x, -0.3, +0.0, l, 0);
        
      d = 25;
      poly_t * text[GREETZ];
      
      for (int i = 0; i < 10; i++)
      {
        text[i] = make_text(make_fixpoint(+9, -8.5 + i * 1.88888), greets[i]);
        text[i]->visible = false;
        text[i]->text_flags = ALLEGRO_ALIGN_RIGHT;
        
        trans_t * move_trans;
        trans_t * color_trans;

        new_trans_i(trans, &text[i]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, d + 200);
        
        move_trans = new_trans(trans, &text[i]->origin->x, text[i]->origin->x + 5, text[i]->origin->x, 40, d);
        move_trans->curve = CURVE_CUBIC;
        
        color_trans = new_trans_ca(trans, &text[i]->color,
                                   0, 0, 0, 0,
                                   200, 200, 200, 255,
                                   200, d);
        
        color_trans->curve = CURVE_BUMP;

        d += 20;
      }

      // "greetz:"
      {
        d = 0;

        poly_t * greets_text =
          text[10] =
          make_text(make_fixpoint(-8, -8.5), greets[10]);
        
        new_trans_i(trans, &greets_text->visible, 1, 1, 1, d);
        new_trans_i(trans, &greets_text->visible, 0, 0, 1, d + 250);
        
        new_trans_ca(trans, &greets_text->color,
                     0, 0, 0, 0,
                     200, 200, 200, 255,
                     50, d);
        new_trans_ca(trans, &greets_text->color,
                     200, 200, 200, 255,
                     0, 0, 0, 0,
                     50, d + 170);
      }

      first_to_render = fish;
      last_to_render = text[10];
    }
    break;

    
   
    SCENE(ch_seeker)
    {
      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, 0, 0);

#define SEEKER_SIDES  12
#define SEEKER_LAYERS 3

      int sides = SEEKER_SIDES;
        
      float arc_w = (float)FULL_CIRCLE / (float)sides;        

      int pie_i = 0;

     
      poly_t * pies[200];
        
      vert_t * divs[6] =
        {
         make_polar(0.25000, 1.3397), // 0
         make_polar(0.16111, 1.8933), // 1
         make_polar(0.11944, 2.7419), // 2
         make_polar(0.10000, 3.6871), // 3
         make_polar(0.08611, 4.6707), // 4
         make_polar(0.07777, 5.6727)  // 5
        };

      int seeker_conf[SEEKER_LAYERS][SEEKER_SIDES] =
        {
         { 11, 13, 11, 12, 11, 12, 11, 12, 12, 11, 11, 13 },
         { 21, 25, 23, 26, 22, 24, 23, 26, 24, 21, 22, 25 },
         { 33, 31, 31, 32, 32, 31, 31, 32, 31, 33, 32, 31 }
        };

      poly_t * ring[SEEKER_LAYERS] =
        {
         make_ngon(make_fixpoint(0, 0), 4, sides, 1),
         make_ngon(make_fixpoint(0, 0), 4, sides, 1),
         make_ngon(make_fixpoint(0, 0), 4, sides, 1)
        };
        
      ring[0]->thicc = ring[1]->thicc = ring[2]->thicc = 2;
      ring[0]->visible = ring[1]->visible = ring[2]->visible = false;

      for (int layer = SEEKER_LAYERS - 1; layer >= 0; layer--)
      {
        edge_t * edge = ring[layer]->first_edge;
          
        for (int side = 0; side < SEEKER_SIDES; side++)
        {
          float angl = arc_w * ((float)side + 0.5);
          poly_t *pie = pies[pie_i++] = make_poly(edge->start);

          edge = edge->next;

          vert_t *bot, *top;

          switch (seeker_conf[layer][side])
          {
            case 11: bot = divs[0]; top = divs[1]; break;
            case 12: bot = divs[0]; top = divs[2]; break;
            case 13: bot = divs[0]; top = divs[3]; break;
            case 21: bot = divs[1]; top = divs[2]; break;
            case 22: bot = divs[1]; top = divs[3]; break;
            case 23: bot = divs[1]; top = divs[4]; break;
            case 24: bot = divs[2]; top = divs[4]; break;
            case 25: bot = divs[3]; top = divs[4]; break;
            case 26: bot = divs[2]; top = divs[3]; break;
            case 31: bot = divs[4]; top = divs[5]; break;
            case 32: bot = divs[3]; top = divs[5]; break;
            case 33: bot = divs[2]; top = divs[5]; break;
          }

          vert_t *bot_a, *bot_b, *top_a, *top_b;

          bot_a = clone_vert(bot);
          bot_b = clone_mirr(bot_a);
          top_a = clone_vert(top);
          top_b = clone_mirr(top_a);
            
          add_edge(pie, bot_a, bot_b);
          add_edge(pie, top_a, top_b);
          add_edge(pie, bot_a, top_a);
          add_edge(pie, bot_b, top_b);
          
          pie->thicc = 3;
          pie->scale = 0.6;
          pie->single_color = true;

          trans_t * move;
          trans_t * rot;
          trans_t * scale;

#define SEEKER_DIST 37
           
          pie->origin->dist = SEEKER_DIST;
            
          scale = new_trans(trans, &pie->scale, 0.4, 0.6, 380, 0);

          scale = new_trans(trans, &pie->scale, 0.6, 20, 260, 380);
          scale->curve = CURVE_CUBIC;

          switch (layer)
          {
            case 0:
              pie->color = al_map_rgb(155, 155, 055);
              
              move = new_trans(trans, &pie->origin->dist, SEEKER_DIST, 7, 80, 0);
              move->curve = CURVE_SQUARE;
              move = new_trans(trans, &pie->origin->dist, 7, 5, 70, 80);
                
              pie->origin->angl = angl + 0.1;
              rot = new_trans(trans, &pie->origin->angl, angl + 0.1, angl - 0.5, 40, 160);
              rot = new_trans(trans, &pie->origin->angl, angl - 0.5, angl, 40, 260);

              rot = new_trans(trans, &pie->origin->angl, angl - 0.5, angl + 0.5, 200, 350);
              break;
                
            case 1:
              pie->color = al_map_rgb(55, 155, 55);
              
              move = new_trans(trans, &pie->origin->dist, SEEKER_DIST, 9, 130, 50);
              move->curve = CURVE_SQUARE;
              move = new_trans(trans, &pie->origin->dist, 9, 5, 70, 180);
                
              pie->origin->angl = angl - 0.5;
              rot = new_trans(trans, &pie->origin->angl, angl - 0.5, angl, 40, 260);

              rot = new_trans(trans, &pie->origin->angl, angl, angl + 1.0, 200, 350);
              break;
                
            case 2:
              pie->color = al_map_rgb(155, 055, 155);
              
              move = new_trans(trans, &pie->origin->dist, SEEKER_DIST, 5, 200, 150);

              rot = new_trans(trans, &pie->origin->angl, angl, angl + 1.0, 200, 350);

              pie->origin->angl = angl;
              break;
          }
        }
      }

      for (int side = 0; side < SEEKER_SIDES; side++)
      {
        new_trans_c(trans, &bg_color, 155, 155, 0, 0, 0, 0, 10, 150);

        new_trans_c(trans, &pies[side + SEEKER_SIDES * 2]->color,
                    0, 0, 0,
                    255, 255, 0,
                    40, 150);

        //
        new_trans_c(trans, &bg_color, 0, 155, 0, 0, 0, 0, 10, 250);

        new_trans_c(trans, &pies[side + SEEKER_SIDES * 2]->color,
                    0, 0, 0,
                    255, 255, 0,
                    40, 250);
        
        new_trans_c(trans, &pies[side + SEEKER_SIDES * 1]->color,
                    0, 0, 0,
                    0, 255, 0,
                    40, 250);

        //
        new_trans_c(trans, &bg_color, 155, 0, 155, 0, 0, 0, 10, 350);
                
        new_trans_c(trans, &pies[side + SEEKER_SIDES * 2]->color,
                    0, 0, 0,
                    255, 255, 0,
                    40, 350);

        new_trans_c(trans, &pies[side + SEEKER_SIDES * 1]->color,
                    0, 0, 0,
                    0, 255, 0,
                    40, 350);
        
        new_trans_c(trans, &pies[side]->color,
                    0, 0, 0,
                    255, 0,   255,
                    40, 350);
      }
      
      // Gate travel
      poly_t * vortex = make_poly(make_fixpoint(0, 0));
        
      sides = 5;
      arc_w = (float)FULL_CIRCLE / (float)sides;
        
      for (i = 0; i < sides; i++)
      {
        float angl = arc_w * (float)i;
        fractal_tunnel1(vortex, 40, make_polar(angl, 1), arc_w);
      }

      vortex->thicc = 2;
      vortex->scale = 2.8;
      vortex->visible = 0;
      vortex->single_color = true;
      vortex->visible = false;
      
      tran1 = new_trans(trans, &vortex->scale, vortex->scale, 160000, 800, 200);
      tran1->curve = CURVE_EXP;

      new_trans_i(trans, &vortex->visible, 1, 1, 1, 350);

      tran1 = new_trans(trans, &vortex->origin->angl, 0, -5, 800, 200);
      tran1->curve = CURVE_RBUMP;

      new_trans_i(trans, &vortex->visible, 1, 1, 1, 400);
      new_trans_c(trans, &vortex->color, 0, 0, 0, 0, 255, 0, 50, 400);

      new_trans(trans, &vortex->thicc, vortex->thicc, 5.0, 400, 400);
      
      new_trans_c(trans, &bg_color, 0, 0, 0, 0, 100, 0, 580, 400);
      new_trans_c(trans, &bg_color, 0, 100, 0, 100, 100, 0, 20, 980);

      first_to_render = ring[0];
      last_to_render = vortex;
    }
    break;


    
    SCENE(ch_fractal_tunnel_out)
    {
      poly = make_poly(make_fixpoint(0, 0));
        
      int sides = 7;
      float arc_w = (float)FULL_CIRCLE / (float)sides;

      for (i = 0; i < sides; i++)
      {
        float angl = arc_w * (float)i;
        fractal_tunnel1(poly, 40, make_polar(angl, 1), arc_w);
      }

      poly->thicc = 2;
      poly->single_color = true;
      poly->color = al_map_rgb(255, 255, 0);

      trans_t * acc;

      FIRST_TRANS
        acc = new_trans(trans, &poly->scale, 5, 180000, 600, 0);
      acc->curve = CURVE_REXP;

#define TUNNEL_OUT_FRAMES 5
      poly_t * frame[TUNNEL_OUT_FRAMES];
      frame[0] = make_ngon(poly->origin, 1.00, 14, 1);
      frame[1] = make_ngon(poly->origin, 1.15, 16, 1);
      frame[2] = make_ngon(poly->origin, 1.30, 17, 1);
      frame[3] = make_ngon(poly->origin, 1.45, 19, 1);
      frame[4] = make_ngon(poly->origin, 1.60, 25, 1);

      for (i = 0; i < TUNNEL_OUT_FRAMES; i++)
      {
        apply_pal(frame[i], pal_yellow);
        acc = new_trans(trans, &frame[i]->scale, 5, 180000, 600, 0);
        acc->curve = CURVE_REXP;
      }

      frame[0]->thicc = 16;
      frame[1]->thicc = 12;
      frame[2]->thicc = 8;
      frame[3]->thicc = 4;
      frame[4]->thicc = 2;

      tran1 = new_trans(trans, &poly->origin->angl, 5, 0, 700, 0);
      tran1->curve = CURVE_RCUBIC;

      tran1 = new_trans(trans, &poly->origin->x, 0, +4, 280, 200);
      tran1->curve = CURVE_EXP;

      tran1 = new_trans(trans, &poly->origin->y, 0, -4, 280, 200);
      tran1->curve = CURVE_EXP;

      poly_t * text[STATS_LINES];
        
      for (int i = 0; i < STATS_LINES; i++)
      {
        stats[i][0] = 0;

        if (i < 5)
        {
          text[i] = make_text(make_fixpoint(-2.2, -5 + i * 2), &stats[i][0]);
          text[i]->text_flags = ALLEGRO_ALIGN_RIGHT;
        }
        else
        {
          text[i] = make_text(make_fixpoint(-1.7, -5 + (i - 5) * 2), &stats[i][0]);
          text[i]->text_flags = ALLEGRO_ALIGN_LEFT;
        }

        text[i]->visible = false;
      }

      for (int i = 0; i < 5; i++)
      {
        d = 525 - i * 20;

        new_trans_c(trans, &text[i]->color, 0, 0, 0, 255, 255, 255, 50, d);
        new_trans_c(trans, &text[i]->color, 255, 255, 255, 0, 0, 0, 50, d + 250);
        
        new_trans_i(trans, &text[i]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i]->visible, 0, 0, 1, d + 300);

        new_trans(trans, &text[i]->origin->x, text[i]->origin->x - 0.4, text[i]->origin->x, 70, d);
        
        new_trans_c(trans, &text[i + 5]->color, 0, 0, 0, 255, 255, 255, 50, d);
        new_trans_c(trans, &text[i + 5]->color, 255, 255, 255, 0, 0, 0, 50, d + 250);
        
        new_trans_i(trans, &text[i + 5]->visible, 1, 1, 1, d);
        new_trans_i(trans, &text[i + 5]->visible, 0, 0, 1, d + 300);

        new_trans(trans, &text[i + 5]->origin->x, text[i + 5]->origin->x + 0.4, text[i + 5]->origin->x, 70, d);
      }

      snprintf(stats[0], sizeof(stats[0]), "%d", used_verts);
      snprintf(stats[1], sizeof(stats[1]), "%d", used_edges);
      snprintf(stats[2], sizeof(stats[2]), "%d", used_polys);
      snprintf(stats[3], sizeof(stats[3]), "%d", used_trans);

      snprintf(stats[5], sizeof(stats[5]), "%s", "vertices");
      snprintf(stats[6], sizeof(stats[6]), "%s", "edges");
      snprintf(stats[7], sizeof(stats[7]), "%s", "shapes");
      snprintf(stats[8], sizeof(stats[8]), "%s", "animations");
      snprintf(stats[9], sizeof(stats[9]), "%s", "frames");

      new_trans_func(trans, format_frame_count, &stats[4], d + 300, 0);

      new_trans_c(trans, &bg_color, 100, 100, 0, 0, 0, 0, 250, 0);
      new_trans(trans, &poly->thicc, 8, 2, 100, 0);
        
      first_to_render = poly;
      last_to_render = text[STATS_LINES - 1];
    }
    break;


    
    SCENE(ch_timer_end)
    {
      l = 10800 - frame;

      FIRST_TRANS
        new_trans(trans, NULL, 0, 0, l, 0);
    }
    break;



    // UNUSED
    SCENE(ch_blocks1)
    {
      bg_color = al_map_rgb(0, 0, 0);
        
      poly_t * l1;
      poly_t * l2;
      poly_t * f1;
      poly_t * f2;

      l1 = make_poly(make_fixpoint(0, 0));
      add_cedge(l1, 0, -3);
      add_cedge(l1, 1, -3);
      add_cedge(l1, 1, -1);
      add_cedge(l1, 2, -1);
      add_cedge(l1, 2, -0);
      add_cedge(l1, 0, -0);
      l1->scale = 2;

      f1 = make_poly(make_fixpoint(0, 0));
      add_cedge(f1, 2, 0);
      add_cedge(f1, 2, 1);
      add_cedge(f1, 0, 1);
      add_cedge(f1, 0, 0);
      f1->scale = 2;

      l2 = clone_poly(l1);
      l2->scale *= -1;
      f2 = clone_poly(f1);
      f2->scale *= -1;
        
      first_to_render = l1;
      last_to_render = f2;

      float f_l = BEAT_LEN;
      float f_d = 0;
        
      // Enter
      l = 11;

      FIRST_TRANS
        new_trans(trans, &l1->origin->y, 5, 0, l, f_d);
      new_trans(trans, &l2->origin->y, 5, 0, l, f_d);
      new_trans(trans, &f1->origin->y, 5, 0, l, f_d);
      new_trans(trans, &f2->origin->y, 5, 0, l, f_d);
      f_d += f_l;

      //l = 12;
      // flats out
      new_trans(trans, &f1->origin->x, 0, 2, l, f_d);
      new_trans(trans, &f2->origin->x, 0, 2, l, f_d);
      f_d += f_l;

      // flats up
      new_trans(trans, &f1->origin->y, 0, -1, l, f_d);
      new_trans(trans, &f2->origin->y, 0, -1, l, f_d);
      f_d += f_l;

      // all horizontal
      new_trans(trans, &l1->origin->x, 0, -2, l, f_d);
      new_trans(trans, &l2->origin->x, 0, -2, l, f_d);
      new_trans(trans, &f1->origin->x, 2, 0, l, f_d);
      new_trans(trans, &f2->origin->x, 2, 0, l, f_d);
      f_d += f_l;

      // switch flats
      // all vertical
      new_trans(trans, &l1->origin->y, 0, +1, l, f_d);
      new_trans(trans, &l2->origin->y, 0, +1, l, f_d);
      new_trans(trans, &f1->origin->y, -1, -2, l, f_d);
      new_trans(trans, &f2->origin->y, -1, -2, l, f_d);
      f_d += f_l;

      // combine
      new_trans(trans, &l1->origin->x, -2, -1.5, l, f_d);
      new_trans(trans, &l2->origin->x, -2, -1.5, l, f_d);
      new_trans(trans, &f1->origin->x, 0, -0.5, l, f_d);
      new_trans(trans, &f2->origin->x, 0, -0.5, l, f_d);
      f_d += f_l;

      new_trans(trans, NULL, 0, 0, d, 0);
        
      new_trans(trans, &l1->scale, 2, 3, f_d + 21, 0);
      new_trans(trans, &l2->scale, -2, -3, f_d + 21, 0);
      new_trans(trans, &f1->scale, -2, -3, f_d + 21, 0);
      new_trans(trans, &f2->scale, 2, 3, f_d + 21, 0);
    }
    break;
    
    

    default:
      last_to_render = first_to_render = NULL;
      return NULL;
  }

  return trans;
}



void boxes_fall_in(trans_t * list, int boxes, poly_t ** box, int * order, int mode, int base_delay)
{
  ASSERT(box != NULL);
  ASSERT(boxes > 0);
  ASSERT(order != NULL);
    
  int l = 14;
  int e = 7;
  int d = base_delay;

  for (int i = 0; i < boxes; i++)
  {
    int index = order[i];

    switch (mode)
    {
      case 0: // in, top-down
        new_trans(list,
                  &box[index]->origin->y,
                  box[index]->origin->y - 20,
                  box[index]->origin->y,
                  l, d);
        
        box[index]->origin->y -= 20;
        break;

      case 1: // in, left-right
        new_trans(list,
                  &box[index]->origin->x,
                  box[index]->origin->x - 20,
                  box[index]->origin->x,
                  l, d);
        
        new_trans(list,
                  &box[index]->origin->angl,
                  -0.3, 0,
                  l, d);
        
        box[index]->origin->x -= 20;
        break;

      case 2: // out, down
        new_trans(list,
                  &box[index]->origin->y,
                  box[index]->origin->y,
                  box[index]->origin->y + 20,
                  l, d);
        break;
        
      case 4: // in, down, spin
        new_trans(list,
                  &box[index]->origin->y,
                  box[index]->origin->y - 20,
                  box[index]->origin->y,
                  l, d);
        
        new_trans(list,
                  &box[index]->origin->angl,
                  1, 0,
                  l, d);
        
        box[index]->origin->y -= 20;
        break;

      case 5: // mix-up
        new_trans(list,
                  &box[index]->origin->x,
                  box[index]->origin->x + 20,
                  box[index]->origin->x,
                  l, d);
        
        box[index]->origin->x += 20;

        new_trans(list,
                  &box[index]->origin->angl,
                  -0.4, 0,
                  l, d);
        break;
    }
    
    d += e;
  }

  return;
}



// Honeycomb
void fractal_honeycomb(poly_t * poly, int depth, vert_t * base, float arc_w)
{
  if (depth == 0)
    return;

  vert_t * end;
  vert_t * t1;
  vert_t * t2;

  end = edge_end(add_edge(poly, base, make_polar(base->angl, base->dist * 0.9)));
  t1  = edge_end(add_edge(poly, end, make_polar(base->angl - arc_w * 0.5, end->dist * 0.88)));
  t2  = edge_end(add_edge(poly, end, make_polar(base->angl + arc_w * 0.5, end->dist * 0.88)));

  fractal_honeycomb(poly, depth - 1, t1, arc_w);

  return;
}



void fractal_tunnel1(poly_t * poly, int depth, vert_t * base, float arc_w)
{
  if (depth == 0)
    return;

  vert_t * end;
  vert_t * t1;
  vert_t * t2;

  end = edge_end(add_edge(poly, base, make_polar(base->angl, base->dist * 0.9)));
  t1  = edge_end(add_edge(poly, end, make_polar(base->angl - arc_w * 0.5, end->dist * 0.88)));
  t2  = edge_end(add_edge(poly, end, make_polar(base->angl + arc_w * 0.5, end->dist * 0.88)));

  fractal_tunnel1(poly, depth - 1, t1, arc_w);

  return;
}



void fractal_triangle(trans_t * list, poly_t ** tri, int * index, int depth, vert_t * base, int sides, float size, float angl_off)
{
  if (depth == 0)
    return;
  
  ASSERT(*index < TRIANGLE_HEAP);

  vert_t * t1;
  vert_t * t2;
  vert_t * tb;

  poly_t * dest = tri[*index] = make_poly(base);
  (*index)++;

  dest->link_angl = true;
  
  tb = make_polar(0, 0);
  t1 = make_polar(+0.083333 + angl_off, size);
  t2 = make_polar(-0.083333 + angl_off, size);

  add_edge(dest, tb, t1);
  add_edge(dest, tb, t2);
  add_edge(dest, t2, t1);

  float lean = 0.1;
  float shrink = 0.9;

  float mult = 0;

  if (sides == 1)
    mult = +1;
  
  if (sides == 2)
    mult = -1;

  trans_t * trans;
  
  if (mult != 0)
  {
    trans = new_trans(list, &dest->rotation, -0.085 * mult, 0, 300, 0);
    trans->curve = CURVE_SQUARE;

    trans = new_trans(list, &dest->rotation, 0.039 * mult, 0, 200, 300);
    trans->curve = CURVE_RSQUARE;
  }

  if (sides == 1)
  {
    trans = new_trans(list, &dest->rotation, 0.039 * mult, -0.04, 450, 500);
    trans->curve = CURVE_LINEAR;

    trans = new_trans(list, &dest->rotation, -0.04, -0.06, 100, 950);
    trans->curve = CURVE_LINEAR;
  }
  else if (sides == 2)
  {
    trans = new_trans(list, &dest->rotation, 0.039 * mult, -0.07, 300, 500);
    trans->curve = CURVE_SQUARE;

    trans = new_trans(list, &dest->rotation, -0.07, +0.06, 300, 800);
    trans->curve = CURVE_SQUARE;
  }

  trans = new_trans(list, &dest->scale, 1, 0.6, 300, 0);
  new_trans(list, &dest->scale, 0.6, 1.0, 200, 300);
  new_trans(list, &dest->scale, 1.0, 0.6, 250, 500);
  new_trans(list, &dest->scale, 0.6, 0.7, 250, 750);
  
  if (sides == 3 || sides == 2)
    fractal_triangle(list, tri, index, depth - 1, t1, 2, size * shrink, -lean);

  if (sides == 3 || sides == 1)
    fractal_triangle(list, tri, index, depth - 1, t2, 1, size * shrink, +lean);
  
  return;
}



void fractal_tree(trans_t * list, poly_t ** tree, int * index, int depth, vert_t * base, float angl_off, float scale, int flags)
{
  ASSERT(list != NULL);
  ASSERT(tree != NULL);
  ASSERT(index != NULL);
  ASSERT(base != NULL);

  if (depth == 0)
    return;

  poly_t * section = tree[(*index)++] = make_poly(base);

  section->link_angl = true;
  
  vert_t * a[4];
  vert_t * b[4];

  a[0] = make_polar(0, 0);
  b[0] = make_polar(0, 9);

  a[1] = make_polar(0, 3);
  b[1] = make_polar(0.05, 4.6352);
  
  a[2] = make_polar(0, 6);
  b[2] = make_polar(-0.03055, 7.5479);
  
  a[3] = make_polar(0, 9);
  b[3] = make_polar(0.02222, 10.5184);

  for (int i = 0; i < 4; i++)
  {
    a[i]->angl += angl_off;
    b[i]->angl += angl_off;

    a[i]->dist *= scale;
    b[i]->dist *= scale;
    
    add_edge(section, a[i], b[i]);
  }

  int l = FTREE_END - frame;
  
  trans_t * trans;

  trans = new_trans(list, &section->rotation, 0, 0.4, l, 0);
  trans->curve = CURVE_RSQUARE;

  trans = new_trans(list, &section->scale, 0.1, 0.85, l * 0.6, 0);
  trans->curve = CURVE_LINEAR;

  trans = new_trans(list, &b[1]->angl, b[1]->angl, b[1]->angl * 1.3, l, 0);
  trans->curve = CURVE_BUMP;
  
  trans = new_trans(list, &b[2]->angl, b[2]->angl, b[2]->angl * 0.8, l, 0);
  trans->curve = CURVE_BUMP;
  
  trans = new_trans(list, &b[3]->angl, b[3]->angl, b[3]->angl * 1.3, l, 0);
  trans->curve = CURVE_BUMP;
  
  fractal_tree(list, tree, index, depth - 1, b[1], +0.06944, scale * 0.45, 2);

  fractal_tree(list, tree, index, depth - 1, b[3], +0.02, scale * 0.35, 0);

  if (flags & 1)
    fractal_tree(list, tree, index, depth - 1, b[2], -0.06, scale * 0.75, 1);
  else
    fractal_tree(list, tree, index, depth - 1, b[2], -0.06, scale * 0.45, 0);

  return;
}



void make_lblock(poly_t * block, int index)
{
  ASSERT(block != NULL);
  ASSERT((index >= 0) && (index < 20));
  
  switch (index)
  {
    case 0:
      add_cedge(block, +3, +0);
      add_cedge(block, +3, -2);
      add_cedge(block, +1, -2);
      add_cedge(block, +1, -1);
      add_cedge(block, +0, -1);
      add_cedge(block, +0, +0);
      break;
      
    case 1:
    case 2:
    case 10:
      add_cedge(block, +1, +0);
      add_cedge(block, +1, -1);
      add_cedge(block, +2, -1);
      add_cedge(block, +2, -3);
      add_cedge(block, +0, -3);
      add_cedge(block, +0, +0);
      break;

    case 4:
    case 15:
    case 17:
      add_cedge(block, +2, +0);
      add_cedge(block, +2, -1);
      add_cedge(block, +3, -1);
      add_cedge(block, +3, -2);
      add_cedge(block, +0, -2);
      add_cedge(block, +0, +0);
      break;

    case 3:
    case 5:
    case 13:
      add_cedge(block, +2, +0);
      add_cedge(block, +2, -2);
      add_cedge(block, +1, -2);
      add_cedge(block, +1, -3);
      add_cedge(block, +0, -3);
      add_cedge(block, +0, +0);
      break;

    case 7:
    case 16:
      add_cedge(block, +1, +0);
      add_cedge(block, +1, +1);
      add_cedge(block, +3, +1);
      add_cedge(block, +3, -1);
      add_cedge(block, +0, -1);
      add_cedge(block, +0, +0);
      break;

    case 8:
      add_cedge(block, +2, +0);
      add_cedge(block, +2, -3);
      add_cedge(block, +1, -3);
      add_cedge(block, +1, -2);
      add_cedge(block, +0, -2);
      add_cedge(block, +0, +0);
      break;

    case 11:
    case 6:
    case 12:
    case 14:
    case 18:
      add_cedge(block, +1, +0);
      add_cedge(block, +1, +1);
      add_cedge(block, +2, +1);
      add_cedge(block, +2, -2);
      add_cedge(block, +0, -2);
      add_cedge(block, +0, +0);
      break;

    case 9:
      add_cedge(block, +3, +0);
      add_cedge(block, +3, -1);
      add_cedge(block, +2, -1);
      add_cedge(block, +2, -2);
      add_cedge(block, +0, -2);
      add_cedge(block, +0, +0);
      break;

    case 19:
      add_cedge(block, +3, +0);
      add_cedge(block, +3, -2);
      add_cedge(block, +1, -2);
      add_cedge(block, +1, -1);
      add_cedge(block, +0, -1);
      add_cedge(block, +0, +0);
      break;
  }
  
  return;
}



void format_frame_count(void * arg)
{
  snprintf(arg, STATS_LINE_LEN, "%d", frame);
  return;
}
