//############################################################################
//
// LaserBoy !!!
//
// by James Lehman
// Extra Stimulus Inc.
// james@akrobiz.com
//
// began: October 2003
//
// Copyright 2003 to 2026 James Lehman.
// This source is distributed under the terms of the GNU General Public License.
//
// LaserBoy_frame_effects.cpp is part of LaserBoy.
//
// LaserBoy is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// LaserBoy is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with LaserBoy. If not, see <http://www.gnu.org/licenses/>.
//
//############################################################################
#include "LaserBoy_FLTK_GUI.hpp"

#define GUI (*(p_space->p_GUI))

//############################################################################
void finish_effect(LaserBoy_frame *p_frame, LaserBoy_frame_set& out)
{
    if(p_space->file_name != LASERBOY_NO_FILE_SAVED)
    {
        if(out.is_ild_busted())
        {
            do
            {
                p_space->display_error("Too many vertices, cannot be saved as ild!");
                GUI.wait_4_Esc();
                p_space->clean_screen();
                if(GUI.display_prompt_and_echo_bool("save as unoptomized LaserBoy wav each frame once ? : y | [any]"))
                {
                    GUI.space->get_file_list(LASERBOY_WAV_SHARE, ".wav");
                    GUI.space->clean_screen();
                    GUI.space->render_space();
                    p_space->file_name.clear();
                    GUI.space->overlay_file_list();
                    p_space->file_name = GUI.display_prompt_and_echo_name("new wav file name", 64);
                    if(p_space->file_name.size() == 0)
                        break;
                    else if(p_space->file_name.size() < 5 || !iends_with(p_space->file_name, p_space->current_extension))
                        p_space->file_name += ".wav";
                    GUI.space->TUI_clue = "saving wav";
                    if(    file_exists(LASERBOY_WAV_SHARE + p_space->file_name)
                        && !GUI.display_prompt_and_echo_bool("file exists! overwrite ? (y | [any])")
                      )
                    {
                        GUI.space->clean_screen();
                        GUI.space->render_space();
                        GUI.space->overlay_file_list();
                        p_space->display_error(LASERBOY_WAV_SHARE + p_space->file_name + " not overwritten! file NOT saved!");
                        GUI.wait_4_Esc();
                        break;
                    }
                    else
                    {
                        if(!out.save_as_wav(LASERBOY_WAV_SHARE + p_space->file_name, false, false))
                        {
                            p_space->display_error(LASERBOY_WAV_SHARE + p_space->file_name + " failed to save");
                            GUI.wait_4_Esc();
                            break;
                        }
                        GUI.space->TUI_clue = "wav saved";
                        GUI.space->clean_screen();
                        GUI.space->render_space();
                        if(!GUI.space->overlay_wav_header_stats(LASERBOY_WAV_SHARE + p_space->file_name))
                            p_space->display_error(LASERBOY_WAV_SHARE + p_space->file_name + " failed to open");
                        else
                            GUI.display_space();
                        GUI.wait_4_Esc();
                        break;
                    }
                }
            } while(0);
        } // end if(out.is_ild_busted())
        else
        {
            bool                      temp_save_as_4_5 = false;
            LaserBoy_ild_header_count counter;
            do
            {
                if(!p_space->save_ild_fmt_4_5 && out.true_color_frames())
                {
                    if(!GUI.display_prompt_and_echo_bool("save ild file containing format-3 ? : y | [any]"))
                    {
                        if(GUI.display_prompt_and_echo_bool("save ild file as format-4 or 5 ? : y | [any]"))
                        {
                            p_space->save_ild_fmt_4_5 = true;
                            temp_save_as_4_5          = true;
                        }
                        else
                        {
                            p_space->display_message("NO ild file saved! see menu x option h");
                            GUI.wait_4_any_key();
                            break;
                        }
                    }
                } // end if(!p_space->save_ild_fmt_4_5 && out.true_color_frames())
                p_space->display_please_wait();
                out.save_as_ild(LASERBOY_ILD_SHARE + p_space->working_subdirectory + p_space->file_name, counter);
                p_space->display_ild_file_stats(counter);
                GUI.wait_4_Esc();
                if(temp_save_as_4_5)
                    p_space->save_ild_fmt_4_5 = false;
                break;
            } while(0);
        }
        if(GUI.display_prompt_and_echo_bool("replace current frame_set with result ? (y | [any])"))
            *(p_space->p_frame_set) = out;
    } // end if(p_space->file_name != LASERBOY_NO_FILE_SAVED)
    else
        *(p_space->p_frame_set) = out;
    return;
}

//############################################################################
LaserBoy_Bounds tranz(LaserBoy_frame* p_frame)
{
    int                i;
    double             amplitude = 0,
                       phase = half_pi;
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame.flatten_z();
    frame.minimize(0);
    frame.normalize_vectors(1.00);
    frame.add_lit_span_vertices(200);
    out += frame;
    for(i = 0; i < 60; i++)
    {
        frame.ripple(3, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude += (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(3, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(3, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude -= (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(0, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude += (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(0, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);

    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(0, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude -= (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(1, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude += (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(1, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(1, amplitude, 2, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude -= (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(2, amplitude, 4, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude += (.66 / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(2, amplitude, 4, phase);
        out += frame;
        phase += (two_pi / 61.0);
    }
    for(i = 0; i < 60; i++)
    {
        frame.ripple(2, amplitude, 4, phase);
        out += frame;
        phase += (two_pi / 61.0);
        amplitude -= (.66 / 61.0);
    }
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds outlines(LaserBoy_frame* p_frame)
{
    double              area;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    out += frame;
    out += (frame.to_real_segment(false)).polygon_outline_xy(area);
    out += (frame.to_real_segment(false)).polygon_outline_zy(area);
    out += (frame.to_real_segment(false)).polygon_outline_xz(area);
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds train(LaserBoy_frame* p_frame)
{
    u_int               frame_count       ,
                        vertex_count      ;
    LaserBoy_3D_short   temp_position     ;
    LaserBoy_frame      frame(*p_frame)   ;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    out += frame;
    for(frame_count = 0; frame_count < frame.size(); frame_count++)
    {
        temp_position = frame.front();
        for(vertex_count = 0; vertex_count < frame.size() - 1; vertex_count++)
            frame.at(vertex_count) = frame.at(vertex_count + 1).as_3D_short();
        frame.back() = temp_position;
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds gleam(LaserBoy_frame* p_frame)
{
    u_int               frame_count ,
                        vertex_count,
                        counter     ;
    LaserBoy_frame      frame_1(*p_frame),
                        frame_2(*p_frame);
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame_1.promote_to_true_color();
    frame_2.promote_to_true_color();
    for(frame_count = 0; frame_count < 10; frame_count++)
    {
        frame_2.clear();
        counter = frame_count;
        for(vertex_count = 0; vertex_count < frame_1.size(); vertex_count++)
        {
            frame_2.push_back(frame_1.at(vertex_count));
            if(    frame_1.at(vertex_count).is_color(0)
                && !(counter++ % 10)
              )
            {
                frame_2.push_back(frame_1.at(vertex_count));
                frame_2.back().r =
                frame_2.back().g =
                frame_2.back().b = 255;
                frame_2.push_back(frame_1.at(vertex_count));
                frame_2.back().blank();
            }
        }
        out += frame_2;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds stars(LaserBoy_frame* p_frame) // individual segments must have no size (dots!)
{
    bool               clipping_was  = p_space->destructive_clipping;
    u_int              frame_count   = 0,
                       total_frames  = 0,
                       segment_index = 0;
    LaserBoy_3D_short  d,
                       center;
    LaserBoy_3D_double s(1.1, 1.1, 1.1);
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            if(frame.scale_segment_around_origin(segment_index, s)) // out of bounds
            {
                center = frame.centroid_of_segment(segment_index);
                while(!(d.x = rand() % 5000 - 2500)); //  -2500 to +2500, not zero
                while(!(d.y = rand() % 5000 - 2500));
                while(!(d.z = rand() % 5000 - 2500));
                d -= center;
                frame.move_segment(segment_index, d); // somewhere near the origin
            }
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds flying(LaserBoy_frame* p_frame)
{
    bool               rotate = GUI.display_prompt_and_echo_bool("rotate each frame in XY ? : (y) | [any]"),
                       random = GUI.display_prompt_and_echo_bool("randomly rotate each segment in XY before adding to frame_set ? : (y) | [any]");
    u_int              i,
                       j,
                       total_frames = 0;
    LaserBoy_3D_double d(-5.0, -7.0, -11.0),
                       a(0.0, 0.0, one_degree),
                       s(1.02, 1.02, 1.02);
    LaserBoy_real_segment     rs ;
    LaserBoy_real_segment_set rss;
    LaserBoy_frame_set        out;
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    rss = (p_frame->explode_segments()).to_real_segment_set(true);
    for(i = 0; i < rss.size(); i++)
    {
        rss.at(i) -= rss.at(i).centroid_of_coordinates();
        rss.at(i).normalize_vectors_with_origin();
        while(rss.at(i).segment_passes_through_origin(65536.0))
            rss.at(i).move(d);
        rss.at(i).scale_around_origin(0.007);
    }
    //------------------------------------------------------------------------
    j = 0;
    for(i = 0; i < total_frames; i++)
    {
        if(!(i % 20))
        {
            if(random)
                rss.at(j).rotate_around_origin(LaserBoy_3D_double(0.0, 0.0, random_neg_to_pos_1() * pi));
            rs += (rss.at(j));
            j++;
            if(j >= rss.size())
                j = 0;
        }
        rs.scale_around_origin(s);
        if(rotate)
            rs.rotate_around_origin(a);
        rs.clip();
        out += rs;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds shrink(LaserBoy_frame* p_frame)
{
    u_int              frame_count;
    LaserBoy_3D_double s(0.96, 0.96, 0.96);
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    out += frame;
    for(frame_count = 1; frame_count < 150; frame_count++)
    {
        frame.scale_around_origin(s);
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds zoom(LaserBoy_frame* p_frame)
{
    u_int                   limit = 0;
    LaserBoy_3D_double          s(1.01, 1.01, 1.01),
                                d(-5.0, -7.0, -11.0);
    LaserBoy_real_segment      rs;
    LaserBoy_real_segment_set rss;
    LaserBoy_frame_set        out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    rs = p_frame->to_real_segment(false);
    rs.reduce_blank_vectors();
    rs.reduce_lit_vectors();
    while(rs.segment_passes_through_origin(65536.0))
        rs.move(d);
    rs.clip();
    for(u_int i = 0; i < 30; i++)
        rss += rs;
    //------------------------------------------------------------------------
    while(    (limit < 3500)
           && rs.size()
         )
    {
        rs.scale_around_origin(s);
        rs.clip();
        rss += rs;
        limit++;
    }
    rss.reverse_frame_order();
    out = rss;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds fill(LaserBoy_frame* p_frame)
{
    u_int              i,
                       segment_index;
    LaserBoy_3D_double s;
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    for(segment_index = 0; segment_index < (*p_frame).number_of_segments(); segment_index++)
    {
        frame = (*p_frame).copy_segment(segment_index);
        out += frame;
        s = 0.95;
        for(i = 0; i < 20; i++)
        {
            frame = (*p_frame).copy_segment(segment_index);
            frame.scale_segment(0, s);
            out[out.number_of_frames() - 1] += frame;
            s -= 0.05;
        }
    }
    out.convert_blank_to_black();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds squeez(LaserBoy_frame* p_frame)
{
    u_int              frame_count;
    LaserBoy_3D_double s;
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set temp,
                       out;
    //------------------------------------------------------------------------
    s.x = 0.93;
    s.y = 1.00;
    s.z = 1.00;
    temp += frame;
    for(frame_count = 0; frame_count < 49; frame_count++)
    {
        frame.scale_around_origin(s);
        temp += frame;
    }
    out += temp;
    temp.reverse();
    temp.delete_frame(0);
    out += temp;
    temp.clear();
    //------------------------------------------------------------------------
    s.x = 1.00;
    s.y = 0.93;
    s.z = 1.00;
    frame = *(p_frame);
    temp += frame;
    for(frame_count = 0; frame_count < 49; frame_count++)
    {
        frame.scale_around_origin(s);
        temp += frame;
    }
    out += temp;
    temp.reverse();
    temp.delete_frame(0);
    out += temp;
    temp.clear();
    //------------------------------------------------------------------------
    s.x = 1.00;
    s.y = 1.00;
    s.z = 0.93;
    frame = *(p_frame);
    temp += frame;
    for(frame_count = 0; frame_count < 49; frame_count++)
    {
        frame.scale_around_origin(s);
        temp += frame;
    }
    out += temp;
    temp.reverse();
    temp.delete_frame(0);
    out += temp;
    temp.clear();
    //------------------------------------------------------------------------
    s.x = 0.93;
    s.y = 0.93;
    s.z = 0.93;
    frame = *(p_frame);
    temp += frame;
    for(frame_count = 0; frame_count < 49; frame_count++)
    {
        frame.scale_around_origin(s);
        temp += frame;
    }
    out += temp;
    temp.reverse();
    temp.delete_frame(0);
    out += temp;
    //------------------------------------------------------------------------
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds around(LaserBoy_frame* p_frame)
{
    u_int                     frame_count,
                              segment_index,
                              total_segments;
    LaserBoy_3D_double          a(0, 0, pi/20);
    LaserBoy_real_segment      rs;
    LaserBoy_real_segment_set rss;
    LaserBoy_frame_set        out;
    //------------------------------------------------------------------------
    rs = p_frame->to_real_segment(true);
    rss += rs;
    total_segments = rs.number_of_segments();
    for(segment_index = 0; segment_index < total_segments; segment_index++)
    {
        for(frame_count = 0; frame_count < 10; frame_count++)
        {
            rs.rotate_segment(segment_index, a);
            rss += rs;
        }
    }
    for(segment_index = 0; segment_index < total_segments; segment_index++)
    {
        for(frame_count = 0; frame_count < 10; frame_count++)
        {
            rs.rotate_segment(segment_index, a);
            rss += rs;
        }
    }
    for(frame_count = 0; frame_count < 20; frame_count++)
    {
        for(segment_index = 0; segment_index < total_segments; segment_index++)
            rs.rotate_segment(segment_index, a);
        rss += rs;
    }
    for(frame_count = 0; frame_count < 20; frame_count++)
    {
        for(segment_index = 0; segment_index < total_segments; segment_index++)
            rs.rotate_segment(segment_index, a);
        rss += rs;
    }
    for(frame_count = 0; frame_count < 20; frame_count++)
    {
        for(segment_index = 0; segment_index < total_segments; segment_index++)
            rs.rotate_segment(segment_index, a);
        rss += rs;
    }
    rss.normalize_vectors_with_origin();
    out = rss;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds rotate(LaserBoy_frame* p_frame)
{
    bool                      we_have_output = false;
    u_int                     frame_count,
                              frames_per_rotation = 0;
    LaserBoy_3D_double        a;
    LaserBoy_real_segment     rs;
    LaserBoy_real_segment_set rss;
    LaserBoy_frame_set        out;
    //------------------------------------------------------------------------
    while(frames_per_rotation == 0 || frames_per_rotation == 1 || frames_per_rotation == 2)
    {
        frames_per_rotation = GUI.display_prompt_and_echo_u_int(   "number of frames per rotation [200]"
                                                                 , 200
                                                                 , 65536
                                                               );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    if(GUI.display_prompt_and_echo_bool("rotate once around X ? (y | [any])"))
    {
        rs = p_frame->to_real_segment(true);
        a.x = -pi / (frames_per_rotation / 2);
        a.y = 0;
        a.z = 0;
        for(frame_count = 0; frame_count < frames_per_rotation; frame_count++)
        {
            rss += rs;
            rs.rotate_around_origin(a);
        }
        we_have_output = true;
    }
    if(GUI.display_prompt_and_echo_bool("rotate once around Y ? (y | [any])"))
    {
        rs = p_frame->to_real_segment(true);
        a.x = 0;
        a.y = pi / (frames_per_rotation / 2);
        a.z = 0;
        for(frame_count = 0; frame_count < frames_per_rotation; frame_count++)
        {
            rss += rs;
            rs.rotate_around_origin(a);
        }
        we_have_output = true;
    }
    if(GUI.display_prompt_and_echo_bool("rotate once around Z ? (y | [any])"))
    {
        rs = p_frame->to_real_segment(true);
        a.x = 0;
        a.y = 0;
        a.z = pi / (frames_per_rotation / 2);
        for(frame_count = 0; frame_count < frames_per_rotation; frame_count++)
        {
            rss += rs;
            rs.rotate_around_origin(a);
        }
        we_have_output = true;
    }
    if(!we_have_output || GUI.display_prompt_and_echo_bool("rotate once around X Y & Z ? (y | [any])"))
    {
        rs = p_frame->to_real_segment(true);
        a.x = pi / (frames_per_rotation / 2);
        a.y = pi / (frames_per_rotation / 2);
        a.z = pi / (frames_per_rotation / 2);
        for(frame_count = 0; frame_count < (u_int)(frames_per_rotation * (233.0 / 200.0)); frame_count++)
        {
            rss += rs;
            rs.rotate_around_origin(a);
        }
    }
    rss.normalize_vectors_with_origin();
    out = rss;
    p_space->display_please_wait();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds rock(LaserBoy_frame* p_frame)
{
    int                       i;
    LaserBoy_3D_double        a(0, 0, one_degree);
    LaserBoy_real_segment     rs;
    LaserBoy_real_segment_set rss;
    LaserBoy_frame_set        out;
    //------------------------------------------------------------------------
    for(i = 0; i < 45; i++)
    {
        rs = p_frame->to_real_segment(true);
        rs.rotate_around_origin(a * i);
        rss += rs;
    }
    for(i = 45; i > -45; i--)
    {
        rs = p_frame->to_real_segment(true);
        rs.rotate_around_origin(a * i);
        rss += rs;
    }
    for(i = -45; i < 0; i++)
    {
        rs = p_frame->to_real_segment(true);
        rs.rotate_around_origin(a * i);
        rss += rs;
    }
    rss.normalize_vectors_with_origin();
    out = rss;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds bounce(LaserBoy_frame* p_frame)
{
    bool               clipping_was  = p_space->destructive_clipping;
    u_int              frame_count,
                       total_frames  = 0;
    LaserBoy_Bounds    out_of_bounds;
    LaserBoy_3D_double r;
    LaserBoy_3D_short  d;
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    d.x = short(random_neg_to_pos_1() * 3000);
    d.y = short(random_neg_to_pos_1() * 3000);
    d.z = short(random_neg_to_pos_1() * 3000);
    r.x = random_neg_to_pos_1() * pi/8.0;
    r.y = random_neg_to_pos_1() * pi/8.0;
    r.z = random_neg_to_pos_1() * pi/8.0;
    //------------------------------------------------------------------------
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        frame.rotate(r);
        while((out_of_bounds = frame.move(d)))
        {
            if(    out_of_bounds & LASERBOY_OUT_POS_X
                || out_of_bounds & LASERBOY_OUT_NEG_X
              )
            {
                d.x = -d.x;
                r.x = -r.x;
            }
                //--------------------------------------------
            if(    out_of_bounds & LASERBOY_OUT_POS_Y
                || out_of_bounds & LASERBOY_OUT_NEG_Y
              )
            {
                d.y = -d.y;
                r.y = -r.y;
            }
                //--------------------------------------------
            if(    out_of_bounds & LASERBOY_OUT_POS_Z
                || out_of_bounds & LASERBOY_OUT_NEG_Z
              )
            {
                d.z = -d.z;
                r.z = -r.z;
            }
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds explode(LaserBoy_frame* p_frame)
{
    u_int                       segment_index,
                                total_segments,
                                frame_count   = 0,
                                max_frames    = 1200;
    LaserBoy_real_segment       rs1,
                                rs2;
    LaserBoy_frame_set          out;
    vector<LaserBoy_3D_double>  d;
    vector<LaserBoy_3D_double>  r;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    rs1 = p_frame->to_real_segment(false);
    total_segments = rs1.number_of_segments();
    d.reserve(total_segments);
    r.reserve(total_segments);
    for(segment_index = 0; segment_index < total_segments; segment_index++)
    {
        d.push_back(LaserBoy_3D_double());
        r.push_back(LaserBoy_3D_double());
        d[segment_index].x = short(random_neg_to_pos_1() * 1000);
        d[segment_index].y = short(random_neg_to_pos_1() * 1000);
        d[segment_index].z = short(random_neg_to_pos_1() * 1000);
        r[segment_index].x = random_neg_to_pos_1() * pi/20.0;
        r[segment_index].y = random_neg_to_pos_1() * pi/20.0;
        r[segment_index].z = random_neg_to_pos_1() * pi/20.0;
    }
    //------------------------------------------------------------------------
    out += rs1;
    rs2 = rs1;
    while(rs2.size() > 1 && frame_count < max_frames)
    {
        for(segment_index = 0; segment_index < total_segments; segment_index++)
        {
            rs1.rotate_segment(segment_index, r[segment_index]);
            rs1.move_segment  (segment_index, d[segment_index]);
        }
        rs2 = rs1;
        rs2.clip();
        out += rs2;
        frame_count++;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds spin(LaserBoy_frame* p_frame)
{
    bool                        clipping_was  = p_space->destructive_clipping;
    LaserBoy_frame              frame(*p_frame);
    LaserBoy_frame_set          out;
    u_int                       frame_count,
                                total_frames = 0,
                                segment_index,
                                total_segments = frame.number_of_segments();
    LaserBoy_Bounds             out_of_bounds;
    vector<LaserBoy_3D_short>   d;
    vector<LaserBoy_3D_double>  r;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    d.reserve(total_segments);
    r.reserve(total_segments);
    for(segment_index = 0; segment_index < total_segments; segment_index++)
    {
        d.push_back(LaserBoy_3D_short());
        r.push_back(LaserBoy_3D_double());
        d[segment_index].x = short(random_neg_to_pos_1() * 1000);
        d[segment_index].y = short(random_neg_to_pos_1() * 1000);
        d[segment_index].z = short(random_neg_to_pos_1() * 1000);
        r[segment_index].x = random_neg_to_pos_1() * pi/20.0;
        r[segment_index].y = random_neg_to_pos_1() * pi/20.0;
        r[segment_index].z = random_neg_to_pos_1() * pi/20.0;
    }
    //------------------------------------------------------------------------
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < total_segments; segment_index++)
        {
            frame.rotate_segment(segment_index, r[segment_index]);
            while((out_of_bounds = frame.move_segment(segment_index, d[segment_index])))
            {
                if(    out_of_bounds & LASERBOY_OUT_POS_X
                    || out_of_bounds & LASERBOY_OUT_NEG_X
                  )
                {
                    d[segment_index].x = -d[segment_index].x;
                    r[segment_index].x = -r[segment_index].x;
                }
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Y
                    || out_of_bounds & LASERBOY_OUT_NEG_Y
                  )
                {
                    d[segment_index].y = -d[segment_index].y;
                    r[segment_index].y = -r[segment_index].y;
                }
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Z
                    || out_of_bounds & LASERBOY_OUT_NEG_Z
                  )
                {
                    d[segment_index].z = -d[segment_index].z;
                    r[segment_index].z = -r[segment_index].z;
                }
            }
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds _break(LaserBoy_frame* p_frame)
{
    bool                        clipping_was  = p_space->destructive_clipping;
    LaserBoy_frame              frame(*p_frame);
    LaserBoy_frame_set          out;
    u_int                       frame_count,
                                total_frames = 0,
                                segment_index;
    LaserBoy_Bounds             out_of_bounds;
    vector<LaserBoy_3D_short>   d;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    d.reserve(frame.number_of_segments());
    for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
    {
        d.push_back(LaserBoy_3D_short());
        d[segment_index].x = short((random_01() - 0.5) * 3000);
        d[segment_index].y = short((random_01() - 0.5) * 3000);
        d[segment_index].z = short((random_01() - 0.5) * 3000);
    }
    //------------------------------------------------------------------------
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
            while((out_of_bounds = frame.move_segment(segment_index, d[segment_index])))
            {
                if(    out_of_bounds & LASERBOY_OUT_POS_X
                    || out_of_bounds & LASERBOY_OUT_NEG_X
                  )
                    d[segment_index].x = -(d[segment_index].x);
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Y
                    || out_of_bounds & LASERBOY_OUT_NEG_Y
                  )
                    d[segment_index].y = -(d[segment_index].y);
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Z
                    || out_of_bounds & LASERBOY_OUT_NEG_Z
                  )
                    d[segment_index].z = -(d[segment_index].z);
            }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds rainbow(LaserBoy_frame* p_frame)
{
    int                 i,
                        span =   p_space->current_palette().last
                               - p_space->current_palette().first;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    out += *p_frame;
    for(i = 1; i <= span; i++)
    {
        out[i - 1].rotate_colors(1);
        out += out[i - 1];
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds fade(LaserBoy_frame* p_frame)
{
    int                 i;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    out += frame;
    for(i = 1; i < 256; i++)
    {
        frame = *p_frame;
        frame.shade(i);
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds bleach(LaserBoy_frame* p_frame)
{
    int                 i;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    out += frame;
    for(i = 1; i < 256; i++)
    {
        frame = *p_frame;
        frame.tint(i);
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds move_l2r(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping;
    int                 i,
                        total_frames;
    LaserBoy_3D_short   d;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->destructive_clipping = true;
    total_frames = GUI.display_prompt_and_echo_int(   "number of frames [400]"
                                                    , 400
                                                  );
    p_space->display_please_wait();
    d.x = -131072 / total_frames;
    out += frame;
    for(i = 0; i < (total_frames / 2); i++)
    {
        frame.move(d);
        out += frame;
    }
    out.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    d.x =  131072 / total_frames;
    for(i = 0; i < (total_frames / 2); i++)
    {
        frame.move(d);
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds move_t2b(LaserBoy_frame* p_frame)
{
    bool                clipping_was  = p_space->destructive_clipping;
    int                 i,
                        total_frames;
    LaserBoy_3D_short   d;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->destructive_clipping = true;
    total_frames = GUI.display_prompt_and_echo_int(   "number of frames [400]"
                                                    , 400
                                                  );
    p_space->display_please_wait();
    d.y =  131072 / total_frames;
    out += frame;
    for(i = 0; i < (total_frames / 2); i++)
    {
        frame.move(d);
        out += frame;
    }
    out.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    d.y = -131072 / total_frames;
    for(i = 0; i < (total_frames / 2); i++)
    {
        frame.move(d);
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds wipe(LaserBoy_frame* p_frame)
{
    int                 i,
                        j;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    frame.minimize(0);
    frame.add_lit_span_vertices(100);
    out += frame;
    for(i = 0; i < 100; i++)
    {
        for(j = 0; j < (int)frame.size(); j++)
            if(frame.at(j).x <= (short)((i * 661.98) - 32767.0))
                frame.set_vertex_to_black(j);
        out += frame;
    }
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds radial_wipe(LaserBoy_frame* p_frame)
{
    int                 i,
                        j;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    frame.minimize(0);
    frame.add_lit_span_vertices(100);
    out += frame;
    for(i = 99; i >= 0; i--)
    {
        for(j = 0; j < (int)frame.size(); j++)
            if(frame.at(j).magnitude() >= (i * 468.09))
                frame.set_vertex_to_black(j);
        out += frame;
    }
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds angle_wipe(LaserBoy_frame* p_frame)
{
    int                 i,
                        j;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    frame.minimize(0);
    frame.flip(0);
    frame.add_lit_span_vertices(100);
    out += frame;
    for(i = 99; i >= 0; i--)
    {
        for(j = 0; j < (int)frame.size(); j++)
            if(((atan2(frame.at(j).y, frame.at(j).x) / two_pi) + 0.5) >= (i / 99.0))
                frame.set_vertex_to_black(j);
        out += frame;
    }
    out.minimize();
    out.flip(0);
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds draw(LaserBoy_frame* p_frame)
{
    u_int               i;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame.palette_index = p_frame->palette_index;
    frame += p_frame->front();
    frame += p_frame->front();
    out += frame;
    //------------------------------------------------------------------------
    for(i = 1; i < p_frame->size(); i++)
    {
        frame += p_frame->at(i);
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds wobble(LaserBoy_frame* p_frame)
{
    bool                        clipping_was  = p_space->destructive_clipping;
    LaserBoy_frame              frame(*p_frame);
    LaserBoy_frame_set          out;
    u_int                       loop_count,
                                frame_count,
                                total_frames = 0,
                                segment_index;
    LaserBoy_Bounds             out_of_bounds;
    vector<LaserBoy_3D_double>  a;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->destructive_clipping = false;
    p_space->display_please_wait();
    a.reserve(frame.number_of_segments());
    for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
    {
        a.push_back(LaserBoy_3D_double());
        a[segment_index].x = (random_01() - 0.5) * pi/20;
        a[segment_index].y = (random_01() - 0.5) * pi/20;
        a[segment_index].z = (random_01() - 0.5) * pi/20;
    }
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            loop_count = 0;
            while((out_of_bounds = frame.rotate_segment(segment_index, a[segment_index])))
            {
                if(    out_of_bounds & LASERBOY_OUT_POS_X
                    || out_of_bounds & LASERBOY_OUT_NEG_X
                  )
                    a[segment_index].x = -a[segment_index].x;
                //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Y
                    || out_of_bounds & LASERBOY_OUT_NEG_Y
                  )
                    a[segment_index].y = -a[segment_index].y;
                //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Z
                    || out_of_bounds & LASERBOY_OUT_NEG_Z
                  )
                    a[segment_index].z = -a[segment_index].z;
                //--------------------------------------------
                if(loop_count)
                    return out_of_bounds;
                loop_count++;
            }
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds wiggle(LaserBoy_frame* p_frame)
{
    bool               clipping_was = p_space->destructive_clipping;
    u_int              frame_count,
                       total_frames = 0,
                       segment_index;
    LaserBoy_3D_double d;
    LaserBoy_frame     frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            do
            {
                d.x = (random_01() - 0.5) * 1000;
                d.y = (random_01() - 0.5) * 1000;
                d.z = (random_01() - 0.5) * 1000;
            } while(frame.move_segment(segment_index, d));
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds throb(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping,
                        flip_flop = false;
    u_int               frame_count,
                        total_frames = 0,
                        segment_index;
    double              s;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            do
            {
                if(flip_flop)
                    s = (random_01() / 10 + 0.9); // 0.9 to 1.0
                else
                    s = (random_01() / 10 + 1.0); // 1.0 to 1.1
                flip_flop = !flip_flop;
            } while(frame.scale_segment(segment_index, s));
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds jazz(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping,
                        flip_flop = false;
    u_int               frame_count,
                        total_frames = 0,
                        segment_index;
    double              s;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            do
            {
                if(flip_flop)
                    s = (random_01() / 10 + 0.9); // 0.9 to 1.0
                else
                    s = (random_01() / 10 + 1.0); // 1.0 to 1.1
                flip_flop = !flip_flop;
            } while(frame.scale_segment_around_origin(segment_index, s));
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds bump(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping,
                        flip_flop = false;
    u_int               frame_count,
                        total_frames = 0,
                        segment_index;
    double              s;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            do
            {
                if(flip_flop)
                    s = 0.8;
                else
                    s = 1.2;
                flip_flop = !flip_flop;
            } while(frame.scale_segment_around_origin(segment_index, s));
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds scan(LaserBoy_frame* p_frame)
{
    bool                clipping_was  = p_space->destructive_clipping;
    u_int               frame_count,
                        total_frames = 0,
                        segment_index;
    LaserBoy_Bounds     out_of_bounds;
    LaserBoy_3D_short   d(1200,  666,     0);
    LaserBoy_3D_double  a(   0,    0, pi/30);
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < frame.number_of_segments(); segment_index++)
        {
            frame.rotate_segment(segment_index, a);
            while((out_of_bounds = frame.move_segment(segment_index, d)))
            {
                if(    out_of_bounds & LASERBOY_OUT_POS_X
                    || out_of_bounds & LASERBOY_OUT_NEG_X
                  )
                    d.x = -d.x;
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Y
                    || out_of_bounds & LASERBOY_OUT_NEG_Y
                  )
                    d.y = -d.y;
                    //--------------------------------------------
            }
        }
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds fall(LaserBoy_frame* p_frame)
{
    bool                 clipping_was  = p_space->destructive_clipping;
    LaserBoy_frame       frame(*p_frame);
    LaserBoy_Bounds      out_of_bounds;
    LaserBoy_3D_double   d(0.0, 0.0, 0.0);
    u_int                frame_count,
                         total_frames = 0,
                         segment_index;
    LaserBoy_frame_set   segments = frame.explode_segments(),
                         out;
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < segments.number_of_frames(); segment_index++)
        {
            d.x = (random_01() - 0.5) * 1000; // -500 to +500
            d.y = (random_01() - 1  ) * 1000; // always negative. DOWN!
            d.z = (random_01() - 0.5) * 1000; // -500 to +500
            while((out_of_bounds = segments[segment_index].move(d)))
            {
                if(    out_of_bounds & LASERBOY_OUT_POS_X
                    || out_of_bounds & LASERBOY_OUT_NEG_X
                  )
                        d.x = -d.x;
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_NEG_Y)
                        d.y = LASERBOY_MAX_SHORT - segments[segment_index].segment_top().y;
                    //--------------------------------------------
                if(    out_of_bounds & LASERBOY_OUT_POS_Z
                    || out_of_bounds & LASERBOY_OUT_NEG_Z
                  )
                        d.z = -d.z;
            }
        }
        frame = segments.sum_of_frames();
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds rain(LaserBoy_frame* p_frame)
{
    bool                       clipping_was  = p_space->destructive_clipping;
    LaserBoy_frame             frame(*p_frame);
    LaserBoy_Bounds            out_of_bounds;
    vector<LaserBoy_3D_double> d;
    int                        frame_count,
                               total_frames = 0,
                               segment_index;
    LaserBoy_frame_set         segments = frame.explode_segments(),
                               out;
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    p_space->destructive_clipping = false;
    for(segment_index = 0; segment_index < (int)segments.number_of_frames(); segment_index++)
    {
        d.push_back(LaserBoy_3D_double());
        d.back().y = (random_01() - 1.1) * 400;
    }
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        for(segment_index = 0; segment_index < (int)segments.number_of_frames(); segment_index++)
        {
            while((out_of_bounds = segments[segment_index].move(d[segment_index] * (pow(1.15, ((LASERBOY_MAX_SHORT - segments[segment_index].segment_top().y) / 1000))))))
            {
                if(out_of_bounds & LASERBOY_OUT_NEG_Y)
                {
                    d[segment_index].y = LASERBOY_MAX_SHORT - segments[segment_index].segment_top().y;
                    segments[segment_index].move(d[segment_index]);
                    d[segment_index].y = (random_01() - 1.1) * 400; // always negative. DOWN!
                }
            }
        }
        frame = segments.sum_of_frames();
        out += frame;
    }
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds melt(LaserBoy_frame* p_frame)
{
    int                 frame_count,
                        total_frames = 0,
                        i;
    LaserBoy_frame      frame(*p_frame);
    LaserBoy_frame_set  out;
    //------------------------------------------------------------------------
    while(total_frames == 0 || total_frames == 1)
    {
        total_frames = GUI.display_prompt_and_echo_u_int(   "number of frames [400]"
                                                          , 400
                                                          , 65536
                                                        );
        if(GUI.prompt_escaped)
        {
            p_space->display_error("number of frames must be 2 or more!");
            return LASERBOY_EFFECT_PROMPT_ESC;
        }
    }
    p_space->display_please_wait();
    if(frame.relative_volume() > 0.75)
        frame.normalize_vectors(0.75);
    out += frame;
    for(frame_count = 1; frame_count < total_frames; frame_count++)
    {
        frame.at(0).x = (short)((   frame.back().x  / 10.0
                                  + frame.at(0).x
                                  + frame.at(1).x  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        frame.at(0).y = (short)((   frame.back().y  / 10.0
                                  + frame.at(0).y
                                  + frame.at(1).y  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        frame.at(0).z = (short)((   frame.back().z  / 10.0
                                  + frame.at(0).z
                                  + frame.at(1).z  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        for(i = 1; i < (int)frame.size() - 1; i++)
        {
            frame.at(i).x = (short)((   frame.at(i - 1).x  / 10.0
                                      + frame.at(i).x
                                      + frame.at(i + 1).x  / 10.0
                                    )
                                    / 1.2
                                    + 0.5
                                   );
            frame.at(i).y = (short)((   frame.at(i - 1).y  / 10.0
                                      + frame.at(i).y
                                      + frame.at(i + 1).y  / 10.0
                                    )
                                    / 1.2
                                    + 0.5
                                   );
            frame.at(i).z = (short)((   frame.at(i - 1).z  / 10.0
                                      + frame.at(i).z
                                      + frame.at(i + 1).z  / 10.0
                                    )
                                    / 1.2
                                    + 0.5
                                   );
        }
        frame.back().x = (short)((  frame.at(frame.size() - 2).x  / 10.0
                                  + frame.back().x
                                  + frame.at(0).x  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        frame.back().y = (short)((  frame.at(frame.size() - 2).y  / 10.0
                                  + frame.back().y
                                  + frame.at(0).y  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        frame.back().z = (short)((  frame.at(frame.size() - 2).z  / 10.0
                                  + frame.back().z
                                  + frame.at(0).z  / 10.0
                                )
                                / 1.2
                                + 0.5
                               );
        out += frame;
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds twist(LaserBoy_frame* p_frame)
{
    int                        i,
                               j;
    LaserBoy_real_segment      rs_1,
                               rs_2;
    LaserBoy_real_segment_set  rss;
    LaserBoy_frame             frame(*p_frame);
    LaserBoy_frame_set         out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame.minimize(0);
    frame.normalize_vectors(1.00);
    frame.add_lit_span_vertices(400);
    rs_1 = frame.to_real_segment(false);
    rs_2 = rs_1;
    rss += rs_1;
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)rs_1.size(); j++)
            if(rs_1.at(j).x <= (short)((i * 163.84) - 32767.0))
                rs_1.at(j) = rotate_vertex_around_x(rs_1.at(j), pi/200.0);
        rss += rs_1;
    }
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)rs_1.size(); j++)
            if(rs_1.at(j).x >= (short)((i * 163.84) - 32767.0))
                rs_1.at(j) = rotate_vertex_around_x(rs_1.at(j), pi/200.0);
            else
                rs_1.at(j) = rs_2.at(j); // un-effected frame data!
        rss += rs_1;
    }
    rss.normalize_vectors();
    out = rss;
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds warp(LaserBoy_frame* p_frame)
{
    int                   i,
                          j;
    LaserBoy_Bounds       out_of_bounds = LASERBOY_IN_BOUNDS;
    LaserBoy_3D_double    rotated_coordinate;
    LaserBoy_frame        frame;
    LaserBoy_frame_set    out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    frame = *p_frame;
    frame.normalize_vectors_with_origin(32700.0 / frame.max_distance_from_origin_zy());
    out += frame;
    GUI.display_state("calculating warp");
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)frame.size(); j++)
            if(frame.at(j).magnitude() >= (i * 81.92))
            {
                rotated_coordinate = rotate_vertex_around_x(frame.at(j), pi/200.0);
                out_of_bounds |= LaserBoy_bounds_check(rotated_coordinate, LASERBOY_CUBE);
                if(out_of_bounds)
                    return out_of_bounds;
                else
                    frame.at(j) = rotated_coordinate;
            }
        out += frame;
        GUI.display_progress(800 - i);
    }
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)frame.size(); j++)
            if(frame.at(j).magnitude() <= (i * 81.92))
            {
                rotated_coordinate = rotate_vertex_around_x(frame.at(j), pi/200.0);
                out_of_bounds |= LaserBoy_bounds_check(rotated_coordinate, LASERBOY_CUBE);
                if(out_of_bounds)
                    return out_of_bounds;
                else
                    frame.at(j) = rotated_coordinate;
            }
        out += frame;
        GUI.display_progress(400 - i);
    }
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds swirl(LaserBoy_frame* p_frame)
{
    int                         i,
                                j;
    LaserBoy_frame              frame(*p_frame);
    LaserBoy_real_segment       rs_1,
                                rs_2;
    LaserBoy_real_segment_set   rss;
    LaserBoy_frame_set          out;
    //------------------------------------------------------------------------
    frame.minimize(0);
    frame.normalize_vectors(1.00);
    frame.add_lit_span_vertices(200);
    rs_1 = frame.to_real_segment(false);
    rs_2 = rs_1;
    rss += rs_1;
    GUI.display_state("calculating swirl");
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)rs_1.size(); j++)
            if(rs_1.at(j).magnitude() <= (i * 115.83))
                rs_1.at(j) = rotate_vertex_around_z(rs_1.at(j), pi/200.0);
        rss += rs_1;
        GUI.display_progress(800 - i);
    }
    for(i = 0; i < 400; i++)
    {
        for(j = 0; j < (int)rs_1.size(); j++)
            if(rs_1.at(j).magnitude() >= (i * 115.83))
                rs_1.at(j) = rotate_vertex_around_z(rs_1.at(j), pi/200.0);
            else
                rs_1.at(j) = rs_2.at(j);
        rss += rs_1;
        GUI.display_progress(400 - i);
    }
    rss.normalize_vectors();
    out = rss;
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds half_cylinder(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping;
    int                 i,
                        j;
    LaserBoy_3D_short   d;
    double              angle;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  temp,
                        out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    p_space->destructive_clipping = true;
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = -662;
    temp += frame;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    temp.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = 662;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    //------------------------------------------------------------------------
    for(i = 0; i < (int)temp.number_of_frames(); i++)
    {
        frame.clear();
        for(j = 0; j < (int)temp[i].size(); j++)
        {
            angle = (((temp[i].at(j).x + 32767.0) / 65535.0) * pi) + pi; // pi to 2pi
            frame += LaserBoy_vertex(cos(angle) * 32767.0,
                                     temp[i].at(j).y,
                                     sin(angle) * -32767.0,
                                     temp[i].at(j).r,
                                     temp[i].at(j).g,
                                     temp[i].at(j).b,
                                     temp[i].at(j).k,
                                     temp[i].at(j).c
                                    );
        }
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds cylinder(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping;
    int                 i,
                        j;
    LaserBoy_3D_short   d;
    double              angle;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  temp,
                        out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    p_space->destructive_clipping = true;
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = -662;
    temp += frame;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    temp.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = 662;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    //------------------------------------------------------------------------
    for(i = 0; i < (int)temp.number_of_frames(); i++)
    {
        frame.clear();
        for(j = 0; j < (int)temp[i].size(); j++)
        {
            angle = (((temp[i].at(j).x + 32767.0) / 32767.0) * pi) + pi; // pi to 3pi
            frame += LaserBoy_vertex(cos(angle) * 32767.0,
                                     temp[i].at(j).y,
                                     sin(angle) * -32767.0,
                                     temp[i].at(j).r,
                                     temp[i].at(j).g,
                                     temp[i].at(j).b,
                                     temp[i].at(j).k,
                                     temp[i].at(j).c
                                    );
        }
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds hemisphere(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping;
    int                 i,
                        j;
    LaserBoy_3D_short   d;
    double              angle_theta,
                        angle_row;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  temp,
                        out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    p_space->destructive_clipping = true;
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = -662;
    temp += frame;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    temp.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = 662;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    //------------------------------------------------------------------------
    for(i = 0; i < (int)temp.number_of_frames(); i++)
    {
        frame.clear();
        for(j = 0; j < (int)temp[i].size(); j++)
        {
            angle_theta = (((temp[i].at(j).x + 32767.0) / 65535.0) * pi) + pi; // pi to 2pi
            angle_row   = (((temp[i].at(j).y) / 65535.0) * pi); // -pi to pi
            frame += LaserBoy_vertex(cos(angle_row) * cos(angle_theta) * 32767.0,
                                     sin(angle_row) * 32767.0,
                                     cos(angle_row) * sin(angle_theta) * -32767.0,
                                     temp[i].at(j).r,
                                     temp[i].at(j).g,
                                     temp[i].at(j).b,
                                     temp[i].at(j).k,
                                     temp[i].at(j).c
                                    );
        }
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds sphere(LaserBoy_frame* p_frame)
{
    bool                clipping_was = p_space->destructive_clipping;
    int                 i,
                        j;
    LaserBoy_3D_short   d;
    double              angle_theta,
                        angle_row;
    LaserBoy_frame      frame;
    LaserBoy_frame_set  temp,
                        out;
    //------------------------------------------------------------------------
    p_space->display_please_wait();
    p_space->destructive_clipping = true;
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = -662;
    temp += frame;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    temp.reverse();
    //------------------------------------------------------------------------
    frame = *p_frame;
    frame.flatten_z();
    frame.minimize(0);
    frame.add_lit_span_vertices(200);
    d.x = 662;
    for(i = 0; i < 100; i++)
    {
        frame.move(d);
        temp += frame;
    }
    //------------------------------------------------------------------------
    for(i = 0; i < (int)temp.number_of_frames(); i++)
    {
        frame.clear();
        for(j = 0; j < (int)temp[i].size(); j++)
        {
            angle_theta = (((temp[i].at(j).x + 32767.0) / 32767.0) * pi) + pi; // pi to 4pi
            angle_row   = (((temp[i].at(j).y) / 65535.0) * pi); // -pi to pi
            frame += LaserBoy_vertex(cos(angle_row) * cos(angle_theta) * 32767.0,
                                     sin(angle_row) * 32767.0,
                                     cos(angle_row) * sin(angle_theta) * -32767.0,
                                     temp[i].at(j).r,
                                     temp[i].at(j).g,
                                     temp[i].at(j).b,
                                     temp[i].at(j).k,
                                     temp[i].at(j).c
                                    );
        }
        out += frame;
    }
    //------------------------------------------------------------------------
    p_space->destructive_clipping = clipping_was;
    out.minimize();
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
LaserBoy_Bounds scanner(LaserBoy_frame* p_frame)
{
    int                        i,
                               total_frames;
    double                     span;
    LaserBoy_3D_double         center,
                               max,
                               min;
    LaserBoy_real_segment      rs;
    LaserBoy_real_segment_set  rss;
    LaserBoy_frame_set         out;
    //------------------------------------------------------------------------
    total_frames = GUI.display_prompt_and_echo_int(   "number of frames [400]"
                                                    , 400
                                                  );
    p_space->display_please_wait();
    //------------------------------------------------------------------------
    span = p_frame->width() / (double)total_frames;
    p_frame->reduce_blank_vectors();
    p_frame->reduce_lit_vectors();
    center = LaserBoy_3D_double(p_frame->segment_left().x - (span / 2.0), 0.0, 0.0);
    min.x  =  0.0;
    max.x  =  span;
    min.y  = -32767.0;
    max.y  =  32767.0;
    min.z  = -32767.0;
    max.z  =  32767.0;
    for(i = 0; i < total_frames; i++)
    {
        p_space->p_GUI->display_progress(total_frames - i);
        rs = p_frame->to_real_segment();
        rs.clip_around_coordinate(center, max, min, 65536.0);
        rs  += center;
        rss += rs;
        center.x += span;
    }
    out = rss;
    finish_effect(p_frame, out);
    return LASERBOY_IN_BOUNDS;
}

//############################################################################
void LaserBoy_space::load_frame_effects()
{
    //------------------------------------------------------------------------
    frame_effects.push_back(around);
    frame_effect_names.push_back(string("around"));
    //------------------------------------------------------------------------
    frame_effects.push_back(angle_wipe);
    frame_effect_names.push_back(string("angle_wipe"));
    //------------------------------------------------------------------------
    frame_effects.push_back(bleach);
    frame_effect_names.push_back(string("bleach"));
    //------------------------------------------------------------------------
    frame_effects.push_back(bounce);
    frame_effect_names.push_back(string("bounce"));
    //------------------------------------------------------------------------
    frame_effects.push_back(_break);
    frame_effect_names.push_back(string("break"));
    //------------------------------------------------------------------------
    frame_effects.push_back(bump);
    frame_effect_names.push_back(string("bump"));
    //------------------------------------------------------------------------
    frame_effects.push_back(cylinder);
    frame_effect_names.push_back(string("cylinder"));
    //------------------------------------------------------------------------
    frame_effects.push_back(draw);
    frame_effect_names.push_back(string("draw"));
    //------------------------------------------------------------------------
    frame_effects.push_back(explode);
    frame_effect_names.push_back(string("explode"));
    //------------------------------------------------------------------------
    frame_effects.push_back(fade);
    frame_effect_names.push_back(string("fade"));
    //------------------------------------------------------------------------
    frame_effects.push_back(fall);
    frame_effect_names.push_back(string("fall"));
    //------------------------------------------------------------------------
    frame_effects.push_back(fill);
    frame_effect_names.push_back(string("fill"));
    //------------------------------------------------------------------------
    frame_effects.push_back(flying);
    frame_effect_names.push_back(string("flying"));
    //------------------------------------------------------------------------
    frame_effects.push_back(gleam);
    frame_effect_names.push_back(string("gleam"));
    //------------------------------------------------------------------------
    frame_effects.push_back(half_cylinder);
    frame_effect_names.push_back(string("half_cylinder"));
    //------------------------------------------------------------------------
    frame_effects.push_back(hemisphere);
    frame_effect_names.push_back(string("hemisphere"));
    //------------------------------------------------------------------------
    frame_effects.push_back(jazz);
    frame_effect_names.push_back(string("jazz"));
    //------------------------------------------------------------------------
    frame_effects.push_back(melt);
    frame_effect_names.push_back(string("melt"));
    //------------------------------------------------------------------------
    frame_effects.push_back(move_l2r);
    frame_effect_names.push_back(string("move_l2r"));
    //------------------------------------------------------------------------
    frame_effects.push_back(move_t2b);
    frame_effect_names.push_back(string("move_t2b"));
    //------------------------------------------------------------------------
    frame_effects.push_back(outlines);
    frame_effect_names.push_back(string("outlines"));
    //------------------------------------------------------------------------
    frame_effects.push_back(radial_wipe);
    frame_effect_names.push_back(string("radial_wipe"));
    //------------------------------------------------------------------------
    frame_effects.push_back(rain);
    frame_effect_names.push_back(string("rain"));
    //------------------------------------------------------------------------
    frame_effects.push_back(rainbow);
    frame_effect_names.push_back(string("rainbow"));
    //------------------------------------------------------------------------
    frame_effects.push_back(rotate);
    frame_effect_names.push_back(string("rotate"));
    //------------------------------------------------------------------------
    frame_effects.push_back(rock);
    frame_effect_names.push_back(string("rock"));
    //------------------------------------------------------------------------
    frame_effects.push_back(scan);
    frame_effect_names.push_back(string("scan"));
    //------------------------------------------------------------------------
    frame_effects.push_back(scanner);
    frame_effect_names.push_back(string("scanner"));
    //------------------------------------------------------------------------
    frame_effects.push_back(shrink);
    frame_effect_names.push_back(string("shrink"));
    //------------------------------------------------------------------------
    frame_effects.push_back(sphere);
    frame_effect_names.push_back(string("sphere"));
    //------------------------------------------------------------------------
    frame_effects.push_back(spin);
    frame_effect_names.push_back(string("spin"));
    //------------------------------------------------------------------------
    frame_effects.push_back(squeez);
    frame_effect_names.push_back(string("squeez"));
    //------------------------------------------------------------------------
    frame_effects.push_back(stars);
    frame_effect_names.push_back(string("stars"));
    //------------------------------------------------------------------------
    frame_effects.push_back(swirl);
    frame_effect_names.push_back(string("swirl"));
    //------------------------------------------------------------------------
    frame_effects.push_back(throb);
    frame_effect_names.push_back(string("throb"));
    //------------------------------------------------------------------------
    frame_effects.push_back(train);
    frame_effect_names.push_back(string("train"));
    //------------------------------------------------------------------------
    frame_effects.push_back(tranz);
    frame_effect_names.push_back(string("tranz"));
    //------------------------------------------------------------------------
    frame_effects.push_back(twist);
    frame_effect_names.push_back(string("twist"));
    //------------------------------------------------------------------------
    frame_effects.push_back(warp);
    frame_effect_names.push_back(string("warp"));
    //------------------------------------------------------------------------
    frame_effects.push_back(wiggle);
    frame_effect_names.push_back(string("wiggle"));
    //------------------------------------------------------------------------
    frame_effects.push_back(wipe);
    frame_effect_names.push_back(string("wipe"));
    //------------------------------------------------------------------------
    frame_effects.push_back(wobble);
    frame_effect_names.push_back(string("wobble"));
    //------------------------------------------------------------------------
    frame_effects.push_back(zoom);
    frame_effect_names.push_back(string("zoom"));
    //------------------------------------------------------------------------
    return;
}

//############################################################################
#undef p_space
#undef GUI

//############################################################################
//////////////////////////////////////////////////////////////////////////////
//############################################################################
