//############################################################################
//
// LaserBoy !!!
//
// by James Lehman
// Extra Stimulus Inc.
// james@akrobiz.com
//
// began: October 2003
//
// Copyright 2003 to 2025 James Lehman.
// This source is distributed under the terms of the GNU General Public License.
//
// LaserBoy_segment.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 .
//
//############################################################################
#include "LaserBoy_FLTK_GUI.hpp"
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short from,
LaserBoy_vertex to
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D line constructor, linear steps
int steps = linear_steps(to, from, ( (to.is_lit())
? (p_space->lit_delta_max)
: (p_space->blank_delta_max)
)
);
//------------------------------------------------------------------------
if(steps)
{
LaserBoy_3D_double _to (to), // convert 3D short to 3D double
_from (from),
difference (_to - _from),
delta (difference / steps);
//--------------------------------------------------------------------
reserve(steps);
for(int i = 1; i <= steps; i++)
push_back(LaserBoy_vertex(LaserBoy_3D_short(_from + (delta * i)),
(LaserBoy_color)to,
to.k,
to.c
)
);
}
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short from,
LaserBoy_vertex to,
const u_int& max_d
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D line constructor, linear steps
int steps = linear_steps(to, from, max_d);
//------------------------------------------------------------------------
if(steps)
{
LaserBoy_3D_double _to (to), // convert 3D short to 3D double
_from (from),
difference (_to - _from),
delta (difference / steps);
//--------------------------------------------------------------------
reserve(steps);
for(int i = 1; i <= steps; i++)
push_back(LaserBoy_vertex(LaserBoy_3D_short(_from + (delta * i)),
(LaserBoy_color)to,
to.k,
to.c
)
);
}
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_vertex p0,
LaserBoy_vertex p1,
string font,
string text
)
: vector(),
palette_index (p_space->current_frame().palette_index),
segment_error (LASERBOY_OK)
{ // mono spaced font constructor
//------------------------------------------------------------------------
wstring_convert, char32_t> conv_utf8_utf32;
//------------------------------------------------------------------------
size_t i;
long int bytes_skipped = 0;
LaserBoy_ild_header_count counter;
u32string unicode_char_list;
LaserBoy_frame_set font_frames;
//--------------------------------------------------------------------
font_frames.from_ild_file(font, bytes_skipped, counter);
if(font_frames.get_unicode_index(unicode_char_list))
unicode_char_list = conv_utf8_utf32.from_bytes(string("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"));
//--------------------------------------------------------------------
LaserBoy_real_segment rs(font_frames,
unicode_char_list,
text,
1.0,
p_space->rendered_mono_font_space,
0.07,
p_space->bond_word,
false
);
//--------------------------------------------------------------------
rs *= ((p0 | p1) / rs.width());
rs += LaserBoy_3D_double(p0.x, p0.y, p0.z);
rs.clip();
for(i = 0; i < rs.size(); i++)
{
push_back(LaserBoy_vertex(rs[i]));
if(rs[i].is_color())
{
back().c = p_space->selected_color_index;
back().r = p_space->palette_picker(palette_index)[p_space->selected_color_index].r;
back().g = p_space->palette_picker(palette_index)[p_space->selected_color_index].g;
back().b = p_space->palette_picker(palette_index)[p_space->selected_color_index].b;
}
else if(rs[i].is_black(p_space->black_level))
{
back().c = p_space->palette_picker(palette_index).black;
back().r = 0x00;
back().g = 0x00;
back().b = 0x00;
}
}
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_vertex p0,
LaserBoy_vertex p1,
string font,
string text,
int = 0
)
: vector(),
palette_index (p_space->current_frame().palette_index),
segment_error (LASERBOY_OK)
{ // variable spaced font constructor
//------------------------------------------------------------------------
wstring_convert, char32_t> conv_utf8_utf32;
//------------------------------------------------------------------------
size_t i;
long int bytes_skipped = 0;
LaserBoy_ild_header_count counter;
u32string unicode_char_list;
LaserBoy_frame_set font_frames;
//------------------------------------------------------------------------
font_frames.from_ild_file(font, bytes_skipped, counter);
if(font_frames.get_unicode_index(unicode_char_list))
unicode_char_list = conv_utf8_utf32.from_bytes(string("!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"));
//------------------------------------------------------------------------
LaserBoy_real_segment rs(font_frames,
unicode_char_list,
text,
1.0,
p_space->rendered_vari_font_gap,
p_space->rendered_vari_font_space,
0.07,
p_space->bond_word,
false
);
//----------------------------------------------------------------
rs *= ((p0 | p1) / rs.width());
rs += LaserBoy_3D_double(p0.x, p0.y, p0.z);
rs.clip();
for(i = 0; i < rs.size(); i++)
{
push_back(LaserBoy_vertex(rs[i]));
if(rs[i].is_color())
{
back().c = p_space->selected_color_index;
back().r = p_space->palette_picker(palette_index)[p_space->selected_color_index].r;
back().g = p_space->palette_picker(palette_index)[p_space->selected_color_index].g;
back().b = p_space->palette_picker(palette_index)[p_space->selected_color_index].b;
}
else if(rs[i].is_black(p_space->black_level))
{
back().c = p_space->palette_picker(palette_index).black;
back().r = 0x00;
back().g = 0x00;
back().b = 0x00;
}
}
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short arc_start,
double arc_angle
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D circular arc constructor
while(arc_angle <= 0)
arc_angle += 360;
size_t total_vertices = (size_t)ceil(arc_angle / p_space->rendered_arc_angle);
double arc_step = arc_angle / total_vertices,
radius = center | arc_start, // distance between
y_rotation = atan2(arc_start.z - center.z, arc_start.x - center.x),
z_rotation;
LaserBoy_real_vertex rv(arc_start);
LaserBoy_real_segment rs;
//------------------------------------------------------------------------
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv.blank();
rs.push_back(LaserBoy_real_vertex(rotate_vertex_on_coordinates_y(rv, center, -y_rotation), (LaserBoy_color)rv));
rv.unblank();
//------------------------------------------------------------------------
z_rotation = atan2(rs.back().y - center.y, rs.back().x - center.x);
arc_step *= one_degree; // convert to radians!
for(size_t a = 1; a <= total_vertices; a++)
{
rv.x = radius * cos(a * arc_step + z_rotation) + + center.x;
rv.y = radius * sin(a * arc_step + z_rotation) + + center.y;
rv.z = center.z;
rs += rv;
}
rs.rotate_on_coordinates_y(center, y_rotation);
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short arc_start,
double arc_angle,
double radii_ratio
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D elliptical arc constructor
while(arc_angle <= 0)
arc_angle += 360;
size_t total_vertices = (size_t)ceil(arc_angle / p_space->rendered_arc_angle);
double arc_step = arc_angle / total_vertices,
radius_1 = center | arc_start,
radius_2 = radius_1 * radii_ratio,
y_rotation = atan2(arc_start.z - center.z, arc_start.x - center.x),
z_rotation;
LaserBoy_real_vertex rv(arc_start);
LaserBoy_real_segment rs;
//------------------------------------------------------------------------
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv = rotate_vertex_on_coordinates_y(arc_start, center, -y_rotation);
z_rotation = atan2(rv.y - center.y, rv.x - center.x);
rv.x = radius_1;
rv.y = 0;
rv.z = center.z;
rv.blank();
rs.push_back(LaserBoy_real_vertex(rv + center));
rv.unblank();
arc_step *= one_degree; // convert to radians!
//------------------------------------------------------------------------
for(size_t a = 1; a <= total_vertices; a++)
{
rv.x = radius_1 * cos(a * arc_step) + center.x;
rv.y = radius_2 * sin(a * arc_step) + center.y;
rv.z = center.z;
rs += rv;
}
rs.rotate_on_coordinates_z(center, z_rotation);
rs.rotate_on_coordinates_y(center, y_rotation);
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short first_vertex,
u_int number_of_sides
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D polygon constructor
double arc_step = two_pi / number_of_sides,
radius = center | first_vertex,
y_rotation = atan2(first_vertex.z - center.z, first_vertex.x - center.x),
z_rotation;
LaserBoy_real_vertex rv(first_vertex);
LaserBoy_real_segment rs;
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rs.push_back(LaserBoy_real_vertex(rotate_vertex_on_coordinates_y(rv, center, -y_rotation), (LaserBoy_color)rv));
rv.unblank();
z_rotation = atan2(rs.back().y - center.y, rs.back().x - center.x);
for(u_int a = 1; a <= number_of_sides; a++)
{
rv.x = radius * cos(a * arc_step + z_rotation) + center.x;
rv.y = radius * sin(a * arc_step + z_rotation) + center.y;
rv.z = center.z;
rs += rv;
}
rs.rotate_on_coordinates_y(center, y_rotation);
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
LaserBoy_3D_short first_vertex,
u_int number_of_points,
double ratio
)
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{ // 3D polystar constructor
u_int a;
double arc_step = two_pi / number_of_points,
radius = center | first_vertex,
y_rotation = atan2(first_vertex.z - center.z, first_vertex.x - center.x),
z_rotation;
LaserBoy_real_vertex rv(first_vertex);
LaserBoy_real_segment rs;
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rs.push_back(LaserBoy_real_vertex(rotate_vertex_on_coordinates_y(rv, center, -y_rotation), (LaserBoy_color)rv));
rv.unblank();
z_rotation = atan2(rs.back().y - center.y, rs.back().x - center.x);
for(a = 0; a <= number_of_points - 1; a++)
{
rv.x = radius * cos(a * arc_step + z_rotation) + center.x;
rv.y = radius * sin(a * arc_step + z_rotation) + center.y;
rv.z = center.z;
rs += rv;
rv.x = radius * ratio * cos(a * arc_step + arc_step / 2 + z_rotation) + center.x;
rv.y = radius * ratio * sin(a * arc_step + arc_step / 2 + z_rotation) + center.y;
rv.z = center.z;
rs += rv;
}
rv.x = radius * cos(a * arc_step + z_rotation) + center.x;
rv.y = radius * sin(a * arc_step + z_rotation) + center.y;
rv.z = center.z;
rs += rv;
rs.rotate_on_coordinates_y(center, y_rotation);
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
u_int radius,
u_int rhodonea_numerator,
u_int rhodonea_denominator
) // rhodonea
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{
if(rhodonea_denominator != 0.0)
{
u_int total_vertices;
double arc_step,
arc_angle,
ratio = rhodonea_numerator / (double)rhodonea_denominator;
LaserBoy_real_vertex rv;
LaserBoy_real_segment rs;
arc_angle = rhodonea_denominator / greatest_common_devisor(rhodonea_numerator, rhodonea_denominator) * 360;
total_vertices = (int)ceil(arc_angle / p_space->rendered_arc_angle);
arc_step = arc_angle / total_vertices;
arc_step *= one_degree; // convert to radians!
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv.x = (short)(radius);
rv.y = 0;
rv.z = center.z;
rs.push_back(LaserBoy_real_vertex(rv + center));
rv.unblank();
for(u_int a = 0; a <= total_vertices; a++)
{
rv.x = radius * cos(ratio * a * arc_step) * cos(a * arc_step) + center.x;
rv.y = radius * cos(ratio * a * arc_step) * sin(a * arc_step) + center.y;
rv.z = center.z;
rs += rv;
}
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
else
segment_error = LASERBOY_DIVIDE_BY_ZERO_ERROR;
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(u_int fixed_radius,
LaserBoy_3D_short center,
u_int roller_radius,
int roller_offset
) // epitrochoid and epicycloid when roller_radius == roller_offset
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{
u_int total_vertices;
double arc_angle,
arc_step,
ratio = fixed_radius / (double)roller_radius;
LaserBoy_real_vertex rv;
LaserBoy_real_segment rs;
if( ratio > 0
&& (ratio - (int)ratio) == 0
) // it's a positive int!
arc_angle = 360.0;
else
arc_angle = roller_radius / greatest_common_devisor(fixed_radius, roller_radius) * 360.0;
total_vertices = (u_int)ceil(arc_angle / p_space->rendered_arc_angle);
arc_step = arc_angle / total_vertices;
arc_step *= one_degree; // convert to radians!
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv.x = roller_radius * (ratio + 1) - roller_offset + center.x;
rv.y = center.y;
rv.z = center.z;
rs.push_back(rv);
rv.unblank();
for(u_int a = 0; a <= total_vertices; a++)
{
rv.x = roller_radius * (ratio + 1) * cos(a * arc_step) - roller_offset * cos((ratio + 1) * a * arc_step) + center.x;
rv.y = roller_radius * (ratio + 1) * sin(a * arc_step) - roller_offset * sin((ratio + 1) * a * arc_step) + center.y;
rv.z = center.z;
rs += rv;
}
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(u_int fixed_radius,
u_int roller_radius,
int roller_offset,
LaserBoy_3D_short center
) // hypotrochoid and hypocycloid when roller_radius == roller_offset
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{
u_int total_vertices;
double arc_angle,
arc_step,
ratio = fixed_radius / (double)roller_radius;
LaserBoy_real_vertex rv;
LaserBoy_real_segment rs;
if( ratio > 0
&& (ratio - (int)ratio) == 0
) // it's a positive int!
arc_angle = 360.0;
else
arc_angle = roller_radius / greatest_common_devisor(fixed_radius, roller_radius) * 360.0;
total_vertices = (u_int)ceil(arc_angle / p_space->rendered_arc_angle);
arc_step = arc_angle / total_vertices;
arc_step *= one_degree; // convert to radians!
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv.x = (fixed_radius - roller_radius) + roller_offset + center.x;
rv.y = center.y;
rv.z = center.z;
rs.push_back(rv);
rv.unblank();
for(u_int a = 0; a <= total_vertices; a++)
{
rv.x = (fixed_radius - roller_radius) * cos(a * arc_step) + roller_offset * cos((ratio - 1) * a * arc_step) + center.x;
rv.y = (fixed_radius - roller_radius) * sin(a * arc_step) - roller_offset * sin((ratio - 1) * a * arc_step) + center.y;
rv.z = center.z;
rs += rv;
}
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
LaserBoy_segment::LaserBoy_segment(LaserBoy_3D_short center,
u_int amplitude_x,
u_int amplitude_y,
u_int frequency_x,
u_int frequency_y,
double phase_x,
double phase_y
) // Lissajous curve
: vector(),
palette_index (LASERBOY_ILDA_DEFAULT),
segment_error (LASERBOY_OK)
{
u_int total_vertices;
double arc_angle,
arc_step,
ratio = frequency_x / frequency_x;
LaserBoy_real_vertex rv;
LaserBoy_real_segment rs;
if( ratio > 0
&& (ratio - (int)ratio) == 0
) // it's a positive int!
arc_angle = 360.0;
else
arc_angle = frequency_x / greatest_common_devisor(frequency_y, frequency_x) * 360.0;
total_vertices = (u_int)ceil(arc_angle / p_space->rendered_arc_angle);
arc_step = arc_angle / total_vertices;
arc_step *= one_degree; // convert to radians!
phase_x *= one_degree;
phase_y *= one_degree;
rv.blank();
rv.c = p_space->selected_color_index;
rv.r = p_space->palette_picker(p_space->palette_index)[rv.c].r;
rv.g = p_space->palette_picker(p_space->palette_index)[rv.c].g;
rv.b = p_space->palette_picker(p_space->palette_index)[rv.c].b;
rv.x = amplitude_x * sin(phase_x) + center.x;
rv.y = amplitude_y * sin(phase_y) + center.y;
rv.z = center.z;
rs.push_back(rv);
rv.unblank();
for(u_int a = 0; a <= total_vertices; a++)
{
rv.x = amplitude_x * sin(frequency_x * a * arc_step + phase_x) + center.x;
rv.y = amplitude_y * sin(frequency_y * a * arc_step + phase_y) + center.y;
rv.z = center.z;
rs += rv;
}
rs.clip();
*this = rs;
sync_rgb_and_palette();
}
//############################################################################
size_t LaserBoy_segment::number_of_color_vectors() const
{
size_t count = 0;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
count++;
return count;
}
//############################################################################
size_t LaserBoy_segment::number_of_dark_vectors() const
{
size_t count = 0;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_dark(p_space->black_level))
count++;
return count;
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_front() const
{
if(size() > 1)
{
LaserBoy_3D_short front_;
front_.z = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).z >= front_.z)
front_ = at(i);
return front_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_back() const
{
if(size() > 1)
{
LaserBoy_3D_short back_;
back_.z = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).z <= back_.z)
back_ = at(i);
return back_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_top() const
{
if(size() > 1)
{
LaserBoy_3D_short top_;
top_.y = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).y >= top_.y)
top_ = at(i);
return top_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_bottom() const
{
if(size() > 1)
{
LaserBoy_3D_short bottom_;
bottom_.y = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).y <= bottom_.y)
bottom_ = at(i);
return bottom_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_right() const
{
if(size() > 1)
{
LaserBoy_3D_short right_;
right_.x = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).x >= right_.x)
right_ = at(i);
return right_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::segment_left() const
{
if(size() > 1)
{
LaserBoy_3D_short left_;
left_.x = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).x <= left_.x)
left_ = at(i);
return left_;
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
short LaserBoy_segment::max_x() const
{
if(size() > 1)
{
short max;
max = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).x >= max)
max = at(i).x;
return max;
}
else
return 0;
}
//############################################################################
short LaserBoy_segment::max_y() const
{
if(size() > 1)
{
short max;
max = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).y >= max)
max = at(i).y;
return max;
}
else
return 0;
}
//############################################################################
short LaserBoy_segment::max_z() const
{
if(size() > 1)
{
short max;
max = LASERBOY_MIN_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).z >= max)
max = at(i).z;
return max;
}
else
return 0;
}
//############################################################################
short LaserBoy_segment::min_x() const
{
if(size() > 1)
{
short min;
min = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).x <= min)
min = at(i).x;
return min;
}
else
return 0;
}
//############################################################################
short LaserBoy_segment::min_y() const
{
if(size() > 1)
{
short min;
min = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).y <= min)
min = at(i).y;
return min;
}
else
return 0;
}
//############################################################################
short LaserBoy_segment::min_z() const
{
if(size() > 1)
{
short min;
min = LASERBOY_MAX_SHORT;
for(size_t i = 0; i < size(); i++)
if(at(i).z <= min)
min = at(i).z;
return min;
}
else
return 0;
}
//############################################################################
LaserBoy_3D_short LaserBoy_segment::max_off_axis_xyz() const
{
if(size() > 1)
{
short _x = (max_x() >= abs(min_x())) ? (max_x()) : (abs(min_x())),
_y = (max_y() >= abs(min_y())) ? (max_y()) : (abs(min_y())),
_z = (max_z() >= abs(min_z())) ? (max_z()) : (abs(min_z()));
return LaserBoy_3D_short(_x, _y, _z);
}
else
return LaserBoy_3D_short(0, 0, 0);
}
//############################################################################
double LaserBoy_segment::max_distance_from_origin() const
{
if(size() > 1)
{
double max = 0,
d;
LaserBoy_3D_short origin(0, 0, 0);
for(size_t i = 0; i < size(); i++)
{
d = origin | at(i);
if(d > max)
max = d;
}
return max;
}
else
return 0.0;
}
//############################################################################
double LaserBoy_segment::max_distance_from_origin_xy() const
{
if(size() > 1)
{
double max = 0,
d;
LaserBoy_3D_short origin(0, 0, 0),
vertex;
for(size_t i = 0; i < size(); i++)
{
vertex = at(i);
vertex.z = 0;
d = origin | vertex;
if(d > max)
max = d;
}
return max;
}
else
return 0.0;
}
//############################################################################
double LaserBoy_segment::max_distance_from_origin_zy() const
{
if(size() > 1)
{
double max = 0,
d;
LaserBoy_3D_short origin(0, 0, 0),
vertex;
for(size_t i = 0; i < size(); i++)
{
vertex = at(i);
vertex.x = 0;
d = origin | vertex;
if(d > max)
max = d;
}
return max;
}
else
return 0.0;
}
//############################################################################
double LaserBoy_segment::min_distance_from_origin() const
{
if(size() > 1)
{
double min = 80000,
d;
LaserBoy_3D_short origin(0, 0, 0);
for(size_t i = 0; i < size(); i++)
{
d = origin | at(i);
if(d == 0.0)
return 0.0;
if(d < min)
min = d;
}
return min;
}
else
return 0.0;
}
//############################################################################
double LaserBoy_segment::min_distance_from_origin_xy() const
{
if(size() > 1)
{
double min = 80000,
d;
LaserBoy_3D_short origin(0, 0, 0),
vertex;
for(size_t i = 0; i < size(); i++)
{
vertex = at(i);
vertex.z = 0;
d = origin | vertex;
if(d == 0.0)
return 0.0;
if(d < min)
min = d;
}
return min;
}
else
return 0.0;
}
//############################################################################
u_short LaserBoy_segment::height() const
{
return abs(max_y() - min_y());
}
//############################################################################
u_short LaserBoy_segment::width() const
{
return abs(max_x() - min_x());
}
//############################################################################
u_short LaserBoy_segment::depth() const
{
return abs(max_z() - min_z());
}
//############################################################################
u_short LaserBoy_segment::max_dimension() const
{
u_short max = 0;
if(height() >= max) max = height();
if(width () >= max) max = width ();
if(depth () >= max) max = depth ();
return max;
}
//############################################################################
double LaserBoy_segment::relative_volume() const
{
return (max_dimension() / 65535.0);
}
//############################################################################
double LaserBoy_segment::relative_volume_to_origin() const
{
short max = LASERBOY_MIN_SHORT;
LaserBoy_3D_short vertex = max_off_axis_xyz();
if(abs(vertex.x) >= max) max = abs(vertex.x);
if(abs(vertex.y) >= max) max = abs(vertex.y);
if(abs(vertex.z) >= max) max = abs(vertex.z);
return ((2.0 * max) / 65535.0);
}
//############################################################################
bool LaserBoy_segment::is_closed_polygon() const
{
if( (first_lit_anchor() | last_lit_vector())
<= p_space->insignificant_distance
)
return true;
return false;
}
//############################################################################
bool LaserBoy_segment::segment_passes_through_origin() const
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(vector_passes_through_origin(at(i - 1).as_3D_double(),
at(i).as_3D_double(),
65536.0
)
)
return true;
return false;
}
//############################################################################
void LaserBoy_segment::blank_all_vertices()
{
if(size() > 1)
for(size_t i = 0; i < size(); i++)
at(i).blank();
return;
}
//############################################################################
void LaserBoy_segment::unblank_all_vertices()
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
at(i).unblank();
return;
}
//############################################################################
void LaserBoy_segment::blacken_vertices()
{
if(size() > 1)
for(size_t i = 0; i < size(); i++)
{
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
at(i).c = p_space->palette_picker(palette_index).black;
}
return;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::reverse()
{
int i;
LaserBoy_segment reversed(palette_index, false);
LaserBoy_vertex vertex;
if(size() > 2)
{
reversed.reserve(size());
i = size() - 1;
//----------------------------------------------------------------
vertex = at(i--);
vertex.blank();
reversed.push_back(vertex);
//----------------------------------------------------------------
while(i >= 0)
{
vertex = at(i );
vertex.r = at(i + 1).r;
vertex.g = at(i + 1).g;
vertex.b = at(i + 1).b;
vertex.c = at(i + 1).c;
vertex.k = at(i + 1).k;
reversed.push_back(vertex);
i--; // i goes to -1 !
}
//----------------------------------------------------------------
*this = reversed;
}
else if(size() == 2)
{
//----------------------------------------------------------------
reversed.reserve(2);
vertex = at(1);
vertex.blank();
reversed.push_back(vertex);
vertex = at(0);
vertex.r = at(1).r;
vertex.g = at(1).g;
vertex.b = at(1).b;
vertex.c = at(1).c;
vertex.k = at(1).k;
reversed.push_back(vertex);
*this = reversed;
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::reverse_sub_segment(size_t p1, size_t p2) // vertex indices
{
//------------------------------------------------------------------------
if(size() > 1)
if(p1 != p2)
{
if((int)size() == 2)
reverse();
else
{
size_t i;
LaserBoy_segment segment (palette_index, false),
reversed(palette_index, false);
//----------------------------------------------------------------
if(p2 < p1)
{
i = p1;
p1 = p2 - 1;
p2 = i;
}
//----------------------------------------------------------------
for(i = 0; i < p1; i++)
segment += at(i);
//----------------------------------------------------------------
for(i = p1; i <= p2; i++)
reversed += at(i);
//----------------------------------------------------------------
reversed.reverse();
segment += reversed;
//----------------------------------------------------------------
for(i = p2 + 1; i < size(); i++)
segment += at(i);
//----------------------------------------------------------------
*this = segment;
}
}
//------------------------------------------------------------------------
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::reorder_from(size_t vertex_index)
{
if( vertex_index
&& vertex_index < size()
&& size() > 1
)
{
size_t i;
LaserBoy_segment reordered(palette_index, false);
//----------------------------------------------------------------
for(i = vertex_index; i < size(); i++)
reordered += at(i);
reordered.front().blank();
for(i = 0; i <= vertex_index; i++)
reordered += at(i);
*this = reordered;
//----------------------------------------------------------------
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::randomize_segments()
{
if(number_of_segments() > 1)
{
vector been_here(number_of_segments());
size_t i,
total_segments = number_of_segments(),
random_index = rand() % total_segments;
LaserBoy_segment segment (palette_index, false),
randomized(palette_index, false);
//----------------------------------------------------------------
for(i = 0; i < total_segments; i++)
been_here[i] = false;
//----------------------------------------------------------------
for(i = 0; i < total_segments; i++)
{
while(been_here[random_index])
{
random_index = rand() % total_segments;
}
segment = copy_segment(random_index);
if(rand() % 2)
segment.reverse();
randomized += segment;
been_here[random_index] = true;
}
//----------------------------------------------------------------
*this = randomized;
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::conglomerate_lit_segments()
{
if(number_of_segments() > 1)
{
bool match_found = false;
int i,
j,
least_angle_index;
double angle,
least_angle;
vector match_index;
vector match_index_type;
LaserBoy_segment copy(*this);
LaserBoy_frame frame(palette_index, false);
LaserBoy_frame_set lit_vectors;
//----------------------------------------------------------------
if(p_space->fracture_b4_conglomerate)
copy.fracture_segments();
lit_vectors = copy.explode_segments();
lit_vectors.minimize();
//----------------------------------------------------------------
p_space->p_GUI->display_state("conglomerating segments");
do
{
p_space->p_GUI->display_progress(lit_vectors.number_of_frames());
for(i = 0; i < (int)lit_vectors.number_of_frames(); i++)
{
match_found = false;
match_index.clear();
match_index_type.clear();
for(j = i + 1; j < (int)lit_vectors.number_of_frames(); j++)
{
if( lit_vectors[i].last_lit_vector().as_3D_short()
== lit_vectors[j].first_lit_anchor().as_3D_short()
)
{
match_found = true;
match_index_type.push_back('a');
match_index.push_back(j);
}
else if( lit_vectors[i].last_lit_vector().as_3D_short()
== lit_vectors[j].last_lit_vector().as_3D_short()
)
{
match_found = true;
match_index_type.push_back('b');
match_index.push_back(j);
}
else if( lit_vectors[i].first_lit_anchor().as_3D_short()
== lit_vectors[j].last_lit_vector().as_3D_short()
)
{
match_found = true;
match_index_type.push_back('c');
match_index.push_back(j);
}
else if( lit_vectors[i].first_lit_anchor().as_3D_short()
== lit_vectors[j].first_lit_anchor().as_3D_short()
)
{
match_found = true;
match_index_type.push_back('d');
match_index.push_back(j);
}
} // end for(j = i; j < (int)lit_vectors.number_of_frames(); j++)
//------------------------------------------------------------
angle = pi;
least_angle = pi;
least_angle_index = 0;
//------------------------------------------------------------
if(match_index.size())
{
for(j = 0; j < (int)match_index.size(); j++)
{
switch(match_index_type[j])
{
case 'a':
angle = three_point_angle(lit_vectors[i].last_lit_anchor(),
lit_vectors[i].last_lit_vector(),
lit_vectors[match_index[j]].first_lit_vertex()
);
break;
case 'b':
angle = three_point_angle(lit_vectors[i].last_lit_anchor(),
lit_vectors[i].last_lit_vector(),
lit_vectors[match_index[j]].last_lit_anchor()
);
break;
case 'c':
angle = three_point_angle(lit_vectors[i].first_lit_vertex(),
lit_vectors[i].first_lit_anchor(),
lit_vectors[match_index[j]].last_lit_anchor()
);
break;
case 'd':
angle = three_point_angle(lit_vectors[i].first_lit_vertex(),
lit_vectors[i].first_lit_anchor(),
lit_vectors[match_index[j]].first_lit_vertex()
);
break;
} // end switch(match_index_type[j])
if(angle <= least_angle)
{
least_angle = angle;
least_angle_index = j;
}
} // end for(j = 0; j < (int)match_index.size(); j++)
//--------------------------------------------------------
switch(match_index_type[least_angle_index])
{
case 'a':
break;
case 'b':
lit_vectors[match_index[least_angle_index]].reverse();
break;
case 'c':
lit_vectors.swap_frames(i, match_index[least_angle_index]);
break;
case 'd':
lit_vectors[i].reverse();
break;
} // end switch(match_index_type[least_angle_index])
//--------------------------------------------------------
lit_vectors[i].is_selected = true;
lit_vectors[match_index[least_angle_index]].is_selected = true;
lit_vectors.collapse_selected_frames();
lit_vectors[i].bond_segments();
//--------------------------------------------------------
break;
} // end if(match_found)
//------------------------------------------------------------
} // end for(i = 0; i < (int)lit_vectors.number_of_frames(); i++)
} while(match_found);
//----------------------------------------------------------------
lit_vectors.minimize();
for(i = 0; i < (int)lit_vectors.number_of_frames(); i++)
frame += lit_vectors[i];
*this = frame;
}
return *this;
}
//############################################################################
LaserBoy_segment LaserBoy_segment::shortest_path_of_segments(const LaserBoy_segment& previous_frame)
{
LaserBoy_frame_set segments = explode_segments();
long int j,
points_away,
points_away_temp;
LaserBoy_3D_double _0,
_1,
_2;
//------------------------------------------------------------------------
if(segments.number_of_frames() > 1)
{
vector been_here;
int i,
segments_index,
closest_segment_index = 0;
double temp_distance,
shortest_distance = 1000000.0; // more positive than possible
LaserBoy_segment reordered(palette_index, true);
//----------------------------------------------------------------
reordered.reserve(size());
//----------------------------------------------------------------
for(i = 0; i < (int)segments.number_of_frames(); i++)
{
been_here.push_back(false);
// ---------------------------------------------------------------
temp_distance = segments[i].first_lit_anchor()
| previous_frame.last_lit_vector();
if(temp_distance < shortest_distance)
{
shortest_distance = temp_distance;
closest_segment_index = (i + 1); // can not be zero
}
else if(temp_distance == shortest_distance)
{
if( segments[ (closest_segment_index > 0)
? (closest_segment_index - 1)
: (-(closest_segment_index - 1))
].front_to_back_magnitude()
> segments[i].front_to_back_magnitude()
)
closest_segment_index = (i + 1); // can not be zero
}
// ---------------------------------------------------------------
temp_distance = segments[i].last_lit_vector()
| previous_frame.last_lit_vector();
if(temp_distance < shortest_distance)
{
shortest_distance = temp_distance;
closest_segment_index = -(i + 1);
}
else if(temp_distance == shortest_distance)
{
if( segments[ (closest_segment_index > 0)
? (closest_segment_index - 1)
: (-(closest_segment_index - 1))
].front_to_back_magnitude()
> segments[i].front_to_back_magnitude()
)
closest_segment_index = -(i + 1);
}
} // end for(i = 0; i < segments.number_of_frames(); i++)
//----------------------------------------------------------------
if(closest_segment_index > 0)
{
reordered = segments[closest_segment_index - 1];
been_here[closest_segment_index - 1] = true;
}
else
{
reordered = (segments[(-closest_segment_index) - 1].reverse());
been_here[(-closest_segment_index) - 1] = true;
}
//----------------------------------------------------------------
for(segments_index = 1; segments_index < (int)segments.number_of_frames(); segments_index++)
{
points_away = LONG_MAX;
closest_segment_index = 0;
for(i = 0; i < (int)segments.number_of_frames(); i++)
{
if(!been_here[i])
{
//--------------------------------------------------------
// this end of the next segment
//--------------------------------------------------------
_0 = reordered.last_lit_anchor();
_1 = reordered.last_lit_vector();
_2 = segments[i].first_lit_anchor();
j = reordered.last_lit_anchor_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = reordered.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp = 0;
else if(_0 == _2)
points_away_temp = end_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp = end_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
//--------------------------------------------------------
if((reordered.last_lit_vector() | segments[i].first_lit_anchor()) >= p_space->insignificant_distance)
{
//----------------------------------------------------
points_away_temp += linear_steps(reordered.last_lit_vector(),
segments[i].first_lit_anchor(),
p_space->blank_delta_max
);
//----------------------------------------------------
_0 = reordered.last_lit_vector();
_1 = segments[i].first_lit_anchor();
_2 = segments[i].first_lit_vertex();
j = segments[i].first_lit_vector_index();
while( (_1 == _2)
&& (++j < (int)segments[i].size())
)
_2 = segments[i].at(j);
j = reordered.last_lit_vector_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = reordered.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp += 0;
else if(_0 == _2)
points_away_temp += start_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp += start_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
}
//--------------------------------------------------------
if(points_away_temp < points_away)
{
points_away = points_away_temp;
closest_segment_index = (i + 1);
}
else if(points_away_temp == points_away) // it's a toss up between two positions
{
if( segments[ (closest_segment_index > 0)
? (closest_segment_index - 1)
: (-(closest_segment_index - 1))
].front_to_back_magnitude()
> segments[i].front_to_back_magnitude()
)
{
points_away = points_away_temp;
closest_segment_index = (i + 1);
}
}
//--------------------------------------------------------
// if the next segment ends are far enough apart
//--------------------------------------------------------
if(segments[i].front_to_back_magnitude() >= p_space->insignificant_distance)
{
//----------------------------------------------------
// look at the other end of the next segment
//----------------------------------------------------
_0 = reordered.last_lit_anchor();
_1 = reordered.last_lit_vector();
_2 = segments[i].last_lit_vector();
j = segments[i].last_lit_vector_index();
while( (_1 == _2)
&& (--j >= 0)
)
_2 = segments[i].at(j);
j = reordered.last_lit_anchor_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = reordered.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp = 0;
else if(_0 == _2)
points_away_temp = end_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp = end_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
//----------------------------------------------------
if((reordered.last_lit_vector() | segments[i].last_lit_vector()) >= p_space->insignificant_distance)
{
//------------------------------------------------
points_away_temp += linear_steps(reordered.last_lit_vector(),
segments[i].last_lit_vector(),
p_space->blank_delta_max
);
//------------------------------------------------
_0 = reordered.last_lit_vector();
_1 = segments[i].last_lit_vector();
_2 = segments[i].last_lit_anchor();
j = segments[i].last_lit_anchor_index();
while( (_1 == _2)
&& (++j < (int)segments[i].size())
)
_2 = segments[i].at(j);
j = reordered.last_lit_vector_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = reordered.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp += 0;
else if(_0 == _2)
points_away_temp += start_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp += start_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
}
//----------------------------------------------------
if(points_away_temp < points_away)
{
points_away = points_away_temp;
closest_segment_index = -(i + 1);
}
else if(points_away_temp == points_away) // it's a toss up between two positions
{
if( segments[ (closest_segment_index > 0)
? (closest_segment_index - 1)
: (-(closest_segment_index - 1))
].front_to_back_magnitude()
> segments[i].front_to_back_magnitude()
)
{
points_away = points_away_temp;
closest_segment_index = -(i + 1);
}
}
} // end if the segment ends are far enough apart
}
}
if(closest_segment_index > 0)
{
reordered += segments[closest_segment_index - 1];
been_here[closest_segment_index - 1] = true;
}
else // (closest_segment_index < 0)
{
reordered += (segments[(-closest_segment_index) - 1].reverse());
been_here[(-closest_segment_index) - 1] = true;
}
}
//----------------------------------------------------------------
// while(reordered.back().is_blank())
// reordered.pop_back();
return reordered;
//----------------------------------------------------------------
} // end if(segments.number_of_frames() > 1)
else // there is only one lit segment
{
//--------------------------------------------------------
// this end of the segment
//--------------------------------------------------------
_0 = previous_frame.last_lit_anchor();
_1 = previous_frame.last_lit_vector();
_2 = segments[0].first_lit_anchor();
j = previous_frame.last_lit_anchor_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = previous_frame.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away = 0;
else if(_0 == _2)
points_away = end_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away = end_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
//--------------------------------------------------------
if( ( previous_frame.last_lit_vector()
| segments[0].first_lit_anchor()
)
>= p_space->insignificant_distance
)
{
//----------------------------------------------------
points_away += linear_steps(previous_frame.last_lit_vector(),
segments[0].first_lit_anchor(),
p_space->blank_delta_max
);
//----------------------------------------------------
_0 = previous_frame.last_lit_vector();
_1 = segments[0].first_lit_anchor();
_2 = segments[0].first_lit_vertex();
j = segments[0].first_lit_vector_index();
while( (_1 == _2)
&& (++j < (int)segments[0].size())
)
_2 = segments[0].at(j);
j = previous_frame.last_lit_vector_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = previous_frame.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away += 0;
else if(_0 == _2)
points_away += start_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away += start_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
}
//--------------------------------------------------------
// if the segment ends are far enough apart
//--------------------------------------------------------
if(segments[0].front_to_back_magnitude() >= p_space->insignificant_distance)
{
//----------------------------------------------------
// look at the other end of the segment
//----------------------------------------------------
_0 = previous_frame.last_lit_anchor();
_1 = previous_frame.last_lit_vector();
_2 = segments[0].last_lit_vector();
j = segments[0].last_lit_vector_index();
while( (_1 == _2)
&& (--j >= 0)
)
_2 = segments[0].at(j);
j = previous_frame.last_lit_anchor_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = previous_frame.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp = 0;
else if(_0 == _2)
points_away_temp = end_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp = end_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
//----------------------------------------------------
if((previous_frame.last_lit_vector() | segments[0].last_lit_vector()) >= p_space->insignificant_distance)
{
//------------------------------------------------
points_away_temp += linear_steps(previous_frame.last_lit_vector(),
segments[0].last_lit_vector(),
p_space->blank_delta_max
);
//------------------------------------------------
_0 = previous_frame.last_lit_vector();
_1 = segments[0].last_lit_vector();
_2 = segments[0].last_lit_anchor();
j = segments[0].last_lit_anchor_index();
while( (_1 == _2)
&& (++j < (int)segments[0].size())
)
_2 = segments[0].at(j);
j = previous_frame.last_lit_vector_index();
while( (_0 == _1)
&& (--j >= 0)
)
_0 = previous_frame.at(j);
if( (_0 == _1)
|| (_1 == _2)
)
points_away_temp += 0;
else if(_0 == _2)
points_away_temp += start_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
points_away_temp += start_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
}
//----------------------------------------------------
if(points_away_temp < points_away)
segments[0].reverse();
} // end if the segment ends are far enough apart
return segments[0];
}
}
//############################################################################
void LaserBoy_segment::reduce_blank_vectors()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment minimum_blanking(palette_index, false);
//----------------------------------------------------------------
minimum_blanking.reserve(size());
//----------------------------------------------------------------
minimum_blanking.push_back(front());
for(i = 1; i < size(); i++)
{
if( at(i).is_blank()
&& minimum_blanking.back().is_blank()
)
minimum_blanking.back() = at(i); // the new, last blank
else
minimum_blanking.push_back(at(i));
}
//----------------------------------------------------------------
while(minimum_blanking.size() && minimum_blanking.back().is_blank())
minimum_blanking.pop_back();
*this = minimum_blanking;
}
return;
}
//############################################################################
void LaserBoy_segment::omit_equivalent_vectors()
{
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments;
size_t i,
j;
//----------------------------------------------------------------
fracture_segments();
segments = explode_segments();
segments.minimize();
//----------------------------------------------------------------
for(i = 0; i < segments.number_of_frames() - 1; i++)
{
for(j = i + 1; j < segments.number_of_frames(); j++)
if( segments[i] == segments[j]
|| segments[i] == segments[j].reverse()
)
segments[j].clear();
}
//----------------------------------------------------------------
*this = segments.sum_of_frames();
//----------------------------------------------------------------
}
return;
}
//############################################################################
void LaserBoy_segment::remove_dots()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment no_dots(palette_index, false);
//----------------------------------------------------------------
no_dots.reserve(size());
//----------------------------------------------------------------
no_dots.push_back(front());
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
{
if(at_index_has_magnitude(i))
no_dots.push_back(at(i));
}
//----------------------------------------------------------------
*this = no_dots;
}
return;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::enhance_dots()
{
if(size() > 1)
{
LaserBoy_segment more_dots(palette_index, false);
//----------------------------------------------------------------
more_dots.reserve(size());
//----------------------------------------------------------------
more_dots.push_back(front());
//----------------------------------------------------------------
for(size_t i = 1; i < size(); i++)
{
if( at(i).is_color(p_space->black_level)
&& !at_index_has_magnitude(i)
)
{
for(u_int j = 1; j < (u_int)round(p_space->dwell_on_dot); j++)
more_dots.push_back(at(i));
}
more_dots.push_back(at(i));
}
//----------------------------------------------------------------
*this = more_dots;
}
return LASERBOY_OK;
}
//############################################################################
void LaserBoy_segment::remove_dwell_vertices()
{
if(size() > 2)
{
size_t i;
LaserBoy_segment no_dwell_vertices(palette_index, false);
//----------------------------------------------------------------
no_dwell_vertices.reserve(size());
no_dwell_vertices.push_back(front());
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
if(at(i) != at(i - 1)) // checks color and location
no_dwell_vertices.push_back(at(i));
//----------------------------------------------------------------
*this = no_dwell_vertices;
}
return;
}
//############################################################################
void LaserBoy_segment::remove_short_vectors()
{
if(size() > 2)
{
int i,
index;
LaserBoy_segment no_short_vectors(*this);
//----------------------------------------------------------------
if( p_space->insignificant_distance > 0.00
&& no_short_vectors.size() > 2
)
{
do
{
index = -1;
for(i = no_short_vectors.size() - 2; i > 1; i--)
{
if( no_short_vectors.at(i).is_color(p_space->black_level)
&& no_short_vectors.at(i ).color_of(p_space->black_level)
== no_short_vectors.at(i + 1).color_of(p_space->black_level)
&& (no_short_vectors.at(i) | no_short_vectors.at(i + 1)) <= p_space->insignificant_distance
)
{
index = i;
break;
}
}
if(index != -1)
{
if(index > 1)
no_short_vectors.at(index - 1) = (LaserBoy_3D_short) // just coordinates
no_short_vectors.at(index - 1).blend(no_short_vectors.at(index), 0.50);
no_short_vectors.remove_vertex(index);
}
} while(index != -1);
//----------------------------------------------------------------
*this = no_short_vectors;
}
}
return;
}
//############################################################################
void LaserBoy_segment::reduce_lit_vectors()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment segment_1(palette_index, false),
segment_2(palette_index, false);
//----------------------------------------------------------------
segment_1.reserve(size());
segment_2.reserve(size());
//----------------------------------------------------------------
segment_1.push_back(front());
for(i = 1; i < size(); i++)
{
if(at(i) != segment_1.back())
segment_1.push_back(at(i));
}
//----------------------------------------------------------------
while(segment_1.size() && segment_1.back().is_blank())
segment_1.pop_back();
//----------------------------------------------------------------
if(segment_1.size())
{
segment_2.push_back(segment_1.front());
for(i = 1; i < segment_1.size() - 1; i++)
{
if( ( segment_1.at(i ).color_of(p_space->black_level)
!= segment_1.at(i + 1).color_of(p_space->black_level)
)
|| ( segment_1.vector_angle(i)
> p_space->insignificant_angle
)
)
segment_2.push_back(segment_1.at(i));
}
//----------------------------------------------------------------
segment_2.push_back(segment_1.at(i));
while(segment_2.size() && segment_2.back().is_blank())
segment_2.pop_back();
}
//----------------------------------------------------------------
*this = segment_2;
}
return;
}
//############################################################################
void LaserBoy_segment::impose_bit_resolution()
{
if(size() > 1)
{
for(size_t i = 0; i < size(); i++)
{
at(i).x &= short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_X]];
at(i).y &= short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_Y]];
at(i).z &= short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_Z]];
at(i).r &= (short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_R]] >> 7);
at(i).g &= (short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_G]] >> 7);
at(i).b &= (short_bit_mask[p_space->signal_bit_mask[LASERBOY_CHANNEL_B]] >> 7);
}
}
return;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::reorder_segments(const LaserBoy_segment& previous_frame)
{
LaserBoy_segment reordered = shortest_path_of_segments(previous_frame);
*this = reordered;
return segment_error;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::fracture_segments()
{
if(number_of_lit_vectors() > 1)
{
size_t i;
LaserBoy_segment fractured(palette_index, false);
fractured.reserve(3 * size());
reduce_blank_vectors();
//----------------------------------------------------------------
for(i = 0; i < size(); i++)
{
fractured.push_back(at(i));
fractured.push_back(at(i));
fractured.back().blank();
}
//----------------------------------------------------------------
fractured.pop_back();
fractured.reduce_blank_vectors();
*this = fractured;
}
return segment_error;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::bond_segments()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment bonded(palette_index, false);
//----------------------------------------------------------------
bonded.reserve(size());
bonded.push_back(front());
for(i = 1; i < size() - 1; i++)
{
if( !( at(i).is_blank()
&& ( at(i)
| at(i - 1)
)
<= p_space->insignificant_distance
) )
bonded += at(i);
}
bonded.push_back(back());
//----------------------------------------------------------------
*this = bonded;
}
return LASERBOY_OK;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::add_vertex(size_t vertex_index)
{
if(size() < 2) // there is nothing
{
clear();
reserve(2);
push_back(LaserBoy_vertex());
push_back(LaserBoy_vertex()); // add blank, zero vector
}
else if(vertex_index < size())
{
size_t i;
LaserBoy_segment segment(palette_index, false);
segment.reserve(size() + 1);
if(vertex_index < size() - 1) // not the last vertex
{
for(i = 0; i <= vertex_index; i++)
segment += at(i);
if((at(vertex_index) | at(vertex_index + 1)) > p_space->insignificant_distance)
segment += LaserBoy_vertex(scale_vertex_on_coordinates(at(vertex_index + 1),
at(vertex_index),
LaserBoy_3D_double(0.5, 0.5, 0.5)
),
at(vertex_index + 1), // is an rgb
at(vertex_index + 1).k,
at(vertex_index + 1).c
);
for(i = vertex_index + 1; i < size(); i++)
segment += at(i);
}
else // it is the last vertex
{
segment = *this;
if(p_space->end_vect_to_delta_max)
{
LaserBoy_3D_double vector_scale = (p_space->lit_delta_max / (at(size() - 2) | back()));
LaserBoy_vertex new_vertex = LaserBoy_vertex(scale_vertex_on_coordinates(back(),
at(size() - 2),
vector_scale
),
back(), // is a LaserBoy_color
back().k,
back().c
);
new_vertex += (back() - at(size() - 2));
segment += new_vertex;
}
else
segment += LaserBoy_vertex(scale_vertex_on_coordinates(back(),
at(size() - 2),
LaserBoy_3D_double(2.0, 2.0, 2.0)
),
back(), // is a LaserBoy_color
back().k,
back().c
);
}
*this = segment;
}
return segment_error;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::break_segment(size_t& vertex_index)
{
if( vertex_index > 0
&& vertex_index < size() - 1
&& size() > 1
)
{
size_t i;
LaserBoy_segment segment(palette_index, false);
segment.reserve(size() + 1);
for(i = 0; i <= vertex_index; i++)
segment += at(i);
segment += at(vertex_index);
segment.back().blank();
for(i = vertex_index + 1; i < size(); i++)
segment += at(i);
vertex_index += 2; // changes the value of spider in frame class
*this = segment;
}
return segment_error;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::connect_the_dots(size_t p0, size_t p1) // vertex indices
{
if( p0 != p1
&& p0 < size()
&& p1 < size()
&& ( ( at(p0)
| at(p1)
)
>= p_space->insignificant_distance
)
)
{
push_back(at(p0));
back().blank();
push_back(at(p1));
back().unblank();
back().c = p_space->selected_color_index;
back().r = p_space->palette_picker(p_space->palette_index)[p_space->selected_color_index].r;
back().g = p_space->palette_picker(p_space->palette_index)[p_space->selected_color_index].g;
back().b = p_space->palette_picker(p_space->palette_index)[p_space->selected_color_index].b;
}
return segment_error;
}
//############################################################################
double LaserBoy_segment::vector_angle(size_t vertex_index) const
{
double angle = 0.0;
if(vertex_index != 0)
{
if(size() > 1)
{
int _0 = 0,
_1 = 0,
_2 = 0;
//-----------------------------------------------------------------
if(vertex_index > 0 && vertex_index < size() - 1)
{
_0 = vertex_index - 1;
_1 = vertex_index ;
_2 = vertex_index + 1;
}
//-----------------------------------------------------------------
else if(vertex_index == size() - 1)
{
_0 = size() - 2;
_1 = 0 ;
_2 = 1 ;
}
//----------------------------------------------------------------
angle = delta_angle( at(_0) | at(_2), // distance between vertices 0,2
at(_0) | at(_1),
at(_1) | at(_2)
);
}
}
return angle;
}
//############################################################################
double LaserBoy_segment::total_angle() const
{
double total = 0.0;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
total += vector_angle(i);
return total;
}
//############################################################################
double LaserBoy_segment::max_angle() const
{
double max = 0.0;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
if(max < vector_angle(i))
max = vector_angle(i);
return max;
}
//############################################################################
double LaserBoy_segment::total_magnitude() const
{
double total = 0.0;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
total += (at(i) | at(i + 1));
return total;
}
//############################################################################
double LaserBoy_segment::max_magnitude() const
{
double max = 0.0,
d;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
{
d = (at(i) | at(i + 1));
if(max < d)
max = d;
}
return max;
}
//############################################################################
double LaserBoy_segment::max_color_magnitude() const
{
double max = 0.0,
d;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
if(at(i + 1).is_color(p_space->black_level))
{
d = (at(i) | at(i + 1));
if(max < d)
max = d;
}
return max;
}
//############################################################################
double LaserBoy_segment::max_dark_magnitude() const
{
double max = 0.0,
d;
size_t i;
if(size() > 1)
for(i = 0; i < size() - 1; i++)
if(at(i + 1).is_dark(p_space->black_level))
{
d = (at(i) | at(i + 1));
if(max < d)
max = d;
}
return max;
}
//############################################################################
double LaserBoy_segment::length_in_seconds() const
{
return double(size()) / p_space->sample_rate;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::add_dwell()
{
if(size() > 1)
{
int i,
j,
dwell_vertex_count,
dwell_vertex_total;
LaserBoy_3D_double _0,
_1,
_2;
LaserBoy_vertex vertex,
black_vertex;
LaserBoy_segment angle_optimized(palette_index, false);
//----------------------------------------------------------------
remove_dwell_vertices();
//----------------------------------------------------------------
angle_optimized.push_back(front());
for(i = 1; i < (int)size() - 1; i++)
{
angle_optimized.push_back(at(i));
_0 = at(i - 1);
_1 = at(i);
_2 = at(i + 1);
j = i - 1;
while( (_0 == _1)
&& (--j >= 0)
)
_0 = at(j);
if(_0 == _1)
_0 = 0.0;
if( (_0 == _1)
|| (_1 == _2)
)
dwell_vertex_total = 0;
else
{
if( at(i ).is_lit()
&& at(i + 1).is_blank()
)
{
if(_0 == _2)
dwell_vertex_total = end_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
dwell_vertex_total = end_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
if(dwell_vertex_total)
{
vertex = black_vertex = at(i);
if( p_space->black_dwell_vertices
&& black_vertex.color_of(p_space->black_level) // not blank or black
)
{
black_vertex.c = p_space->palette_picker(palette_index).black;
black_vertex.r =
black_vertex.g =
black_vertex.b = 0x00;
}
for(dwell_vertex_count = 0; dwell_vertex_count < dwell_vertex_total; dwell_vertex_count++)
if(dwell_vertex_count < (int)p_space->lit_dwell_overhang)
angle_optimized.push_back(vertex);
else
angle_optimized.push_back(black_vertex);
}
}
else if( at(i ).is_blank()
&& at(i + 1).is_lit()
)
{
if(_0 == _2)
dwell_vertex_total = start_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
dwell_vertex_total = start_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
if(dwell_vertex_total)
{
vertex = at(i);
vertex.blank();
for(dwell_vertex_count = 0; dwell_vertex_count < dwell_vertex_total; dwell_vertex_count++)
angle_optimized.push_back(vertex);
}
}
else if( at(i ).is_lit()
&& at(i + 1).is_lit()
)
{
if(_0 == _2)
dwell_vertex_total = inline_dwell_vertices(pi,
p_space->sample_rate,
p_space->max_dwell_microsec
);
else
dwell_vertex_total = inline_dwell_vertices(delta_angle(_0 | _2,
_0 | _1,
_1 | _2
),
p_space->sample_rate,
p_space->max_dwell_microsec
);
if(dwell_vertex_total)
{
vertex = black_vertex = at(i);
if( p_space->black_dwell_vertices
&& black_vertex.color_of(p_space->black_level) > 0x00 // not blank or black
)
{
black_vertex.c = p_space->palette_picker(palette_index).black;
black_vertex.r =
black_vertex.g =
black_vertex.b = 0x00;
}
for(dwell_vertex_count = 0; dwell_vertex_count < dwell_vertex_total; dwell_vertex_count++)
if(dwell_vertex_count < (int)p_space->lit_dwell_overhang)
angle_optimized.push_back(vertex);
else
angle_optimized.push_back(black_vertex);
}
}
}
}
angle_optimized.push_back(back());
//----------------------------------------------------------------
*this = angle_optimized;
}
return segment_error;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::add_lit_span_vertices()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment distance_optimized,
line;
//----------------------------------------------------------------
for(i = 0; i < size() - 1; i++)
{
distance_optimized.push_back(at(i));
if( at(i + 1).is_lit()
&& (at(i) | at(i + 1)) > p_space->lit_delta_max
)
{
line = LaserBoy_segment(at(i), at(i + 1));
line.pop_back();
distance_optimized += line;
line.clear();
}
}
distance_optimized.push_back(at(size() - 1));
//----------------------------------------------------------------
distance_optimized.palette_index = palette_index;
*this = distance_optimized;
}
return segment_error;
}
//############################################################################
void LaserBoy_segment::add_lit_span_vertices(const u_int& max_d)
{
if(size() > 1)
{
size_t i;
LaserBoy_segment distance_optimized,
line;
//----------------------------------------------------------------
for(i = 0; i < size() - 1; i++)
{
distance_optimized.push_back(at(i));
if( at(i + 1).is_lit()
&& (at(i) | at(i + 1)) > max_d
)
{
line = LaserBoy_segment(at(i), at(i + 1), max_d);
line.pop_back();
distance_optimized += line;
line.clear();
}
}
distance_optimized.push_back(at(size() - 1));
//----------------------------------------------------------------
distance_optimized.palette_index = palette_index;
*this = distance_optimized;
}
return;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::add_blank_span_vertices()
{
if(size() > 1)
{
size_t i;
LaserBoy_segment distance_optimized,
line;
//----------------------------------------------------------------
for(i = 0; i < size() - 1; i++)
{
distance_optimized.push_back(at(i));
if( at(i + 1).is_blank()
&& (at(i) | at(i + 1)) > p_space->blank_delta_max
)
{
line = LaserBoy_segment(at(i), at(i + 1));
line.remove_vertex(line.size() - 1);
distance_optimized += line;
line.clear();
}
}
distance_optimized.push_back(at(size() - 1));
//----------------------------------------------------------------
distance_optimized.palette_index = palette_index;
*this = distance_optimized;
}
return segment_error;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::flip(u_int plane)
{
if(size() > 1)
{
size_t i;
switch(plane)
{
case 0: // X
for(i = 0; i < size(); i++)
at(i).x = -at(i).x;
break;
//-----------------------------------------------------------------
case 1: // Y
for(i = 0; i < size(); i++)
at(i).y = -at(i).y;
break;
//-----------------------------------------------------------------
case 2: // Z
for(i = 0; i < size(); i++)
at(i).z = -at(i).z;
break;
//-----------------------------------------------------------------
case 3: // X, Y
for(i = 0; i < size(); i++)
{
at(i).x = -at(i).x;
at(i).y = -at(i).y;
}
break;
//-----------------------------------------------------------------
case 4: // X, Y, Z
for(i = 0; i < size(); i++)
at(i) = -at(i);
break;
//-----------------------------------------------------------------
}
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::normalize(double s)
{
if(size() > 1)
{
if(s > 0.0)
{
LaserBoy_real_segment rs(palette_index, false);
rs = to_real_segment(true);
rs.normalize(false);
rs.remove_vertex(0);
rs.remove_vertex(0); // delete the origin vector
*this = rs;
scale_around_origin(s);
}
else
{
LaserBoy_real_segment rs(palette_index, false);
rs = to_real_segment(true);
rs.center();
*this = rs;
}
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::normalize_vectors(double s)
{
if(size() > 1)
{
if(s > 0.0)
{
LaserBoy_real_segment rs(palette_index, false);
rs = to_real_segment(true);
rs.normalize_vectors();
rs.remove_vertex(0);
rs.remove_vertex(0); // delete the origin vector
*this = rs;
scale_around_origin(s);
}
else
{
LaserBoy_real_segment rs(palette_index, false);
rs = to_real_segment(false);
rs.center();
*this = rs;
}
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::normalize_vectors_with_origin(double s)
{
if(size() > 1 && s > 0.0)
{
LaserBoy_real_segment rs(palette_index, false);
rs = to_real_segment(true);
rs.normalize_vectors_with_origin();
rs.remove_vertex(0);
rs.remove_vertex(0); // delete the origin vector
*this = rs;
scale_around_origin(s);
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::quarter_turn(u_int plane, u_int turns)
{
if(size() > 1)
{
size_t i;
u_int j;
short temp;
switch(plane)
{
case 0: // X Y
for(i = 0; i < size(); i++)
for(j = 0; j < turns; j++)
{
temp = -at(i).x;
at(i).x = at(i).y;
at(i).y = temp;
}
break;
//-----------------------------------------------------------------
case 1: // Z Y
for(i = 0; i < size(); i++)
for(j = 0; j < turns; j++)
{
temp = -at(i).z;
at(i).z = at(i).y;
at(i).y = temp;
}
break;
//-----------------------------------------------------------------
case 2: // X Z
for(i = 0; i < size(); i++)
for(j = 0; j < turns; j++)
{
temp = -at(i).x;
at(i).x = at(i).z;
at(i).z = temp;
}
break;
//-----------------------------------------------------------------
}
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::z_order_vertices(unsigned short span)
{
if(size() > 1)
{
size_t i,
step = span / size();
for(i = 0; i < size(); i++)
at(i).z = (short)((i * step) - (span / 2));
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::flatten_z()
{
if(size() > 1)
{
for(size_t i = 0; i < size(); i++)
at(i).z = 0;
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::flat_to_2D()
{
if(size() > 1 && is_flat_in_z())
{
for(size_t i = 0; i < size(); i++)
at(i).z = 0;
}
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::center_x()
{
LaserBoy_real_segment rs = to_real_segment(false);
rs.center_x();
*this = rs;
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::center_y()
{
LaserBoy_real_segment rs = to_real_segment(false);
rs.center_y();
*this = rs;
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::center_z()
{
LaserBoy_real_segment rs = to_real_segment(false);
rs.center_z();
*this = rs;
return *this;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::center()
{
LaserBoy_real_segment rs = to_real_segment(false);
rs.center();
*this = rs;
return *this;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate(LaserBoy_3D_double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double center = centroid_of_coordinates();
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex_on_coordinates(at(i), center, a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex_on_coordinates(at(i), center, a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate(a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_around_origin(LaserBoy_3D_double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex(at(i), a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex(at(i), a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_around_origin(a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_on_coordinates(LaserBoy_3D_double p, LaserBoy_3D_double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex_on_coordinates(at(i), p, a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex_on_coordinates(at(i), p, a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_on_coordinates(p, p, 0, a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_on_coordinates_x(LaserBoy_3D_double p, double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex_on_coordinates_x(at(i), p, a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex_on_coordinates_x(at(i), p, a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_on_coordinates_x(p, a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_on_coordinates_y(LaserBoy_3D_double p, double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex_on_coordinates_y(at(i), p, a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex_on_coordinates_y(at(i), p, a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_on_coordinates_y(p, a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_on_coordinates_z(LaserBoy_3D_double p, double a)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
out_of_bounds |= LaserBoy_bounds_check(rotate_vertex_on_coordinates_z(at(i), p, a), LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
at(i) = rotate_vertex_on_coordinates_z(at(i), p, a);
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_on_coordinates_z(p, a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_around_origin()
{
return rotate_around_origin(p_space->view_angle);
}
//############################################################################
void LaserBoy_segment::ripple(int direction, double amplitude, double freq, double phase)
{
if(size() > 1)
{
size_t i;
switch(direction)
{
case 0: for(i = 0; i < size(); i++) // parellel through x
at(i).z = short(amplitude * (16384.0 / pi) * sin(at(i).x / 32768.0 * two_pi * freq + phase));
break;
//----------------------------------------------------------------
case 1: for(i = 0; i < size(); i++) // parellel through y
at(i).z = short(amplitude * (16384.0 / pi) * sin(at(i).y / 32768.0 * two_pi * freq + phase));
break;
//----------------------------------------------------------------
case 2: for(i = 0; i < size(); i++) // x * y, the egg carton effect
at(i).z = short(amplitude * (16384.0 / pi) * sin(at(i).x * at(i).y / 1073741824.0 * two_pi * freq + phase));
break;
//----------------------------------------------------------------
case 3: for(i = 0; i < size(); i++) // circular, concentric to the origin
at(i).z = short(amplitude * (16384.0 / pi) * sin(sqrt(double(at(i).x * at(i).x + at(i).y * at(i).y)) / 32768.0 * two_pi * freq + phase));
//----------------------------------------------------------------
}
}
return;
}
//############################################################################
LaserBoy_palette LaserBoy_segment::as_color_table() const
{
LaserBoy_palette color_table;
color_table.reserve(size());
if(size() > 1)
for(size_t i = 0; i < size(); i++)
{
if(at(i).is_lit())
color_table.push_back(at(i));
else
color_table.push_back(LaserBoy_color(0,0,0));
}
return color_table;
}
//############################################################################
void LaserBoy_segment::strip_color()
{
palette_index = LASERBOY_ILDA_DEFAULT;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
{
if(at(i).k & LASERBOY_BLANKING_BIT)
{
at(i).c = 0;
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
}
else if(at(i).is_black(p_space->black_level))
{
at(i).c = 64;
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
}
else
{
at(i).c = 55; // LASERBOY_ILDA_DEFAULT white
at(i).r = 255;
at(i).g = 255;
at(i).b = 255;
}
}
p_space->palette_index = LASERBOY_ILDA_DEFAULT;
return;
}
//############################################################################
void LaserBoy_segment::strip_color_rgb(const LaserBoy_color& c)
{
palette_index = LASERBOY_TRUE_COLOR;
for(size_t i = 1; i < size(); i++)
{
if(at(i).is_color(p_space->black_level))
{
at(i).r = c.r;
at(i).g = c.g;
at(i).b = c.b;
}
}
sync_rgb_and_palette();
}
//############################################################################
void LaserBoy_segment::strip_color_or()
{
if(size() > 1)
{
if(palette_index != LASERBOY_TRUE_COLOR) // if it is alread palette
set_rgb_from_palette();
palette_index = LASERBOY_TRUE_COLOR;
for(size_t i = 1; i < size(); i++)
{
at(i).r =
at(i).g =
at(i).b = (at(i).r | at(i).g | at(i).b);
}
best_match_palette(LASERBOY_GRAYS);
}
return;
}
//############################################################################
void LaserBoy_segment::strip_color_avg()
{
if(size() > 1)
{
if(palette_index != LASERBOY_TRUE_COLOR) // if it is alread palette
set_rgb_from_palette();
palette_index = LASERBOY_TRUE_COLOR;
for(size_t i = 1; i < size(); i++)
{
at(i).r =
at(i).g =
at(i).b = ((76 * at(i).r + 150 * at(i).g + 28 * at(i).b) / 254);
}
best_match_palette(LASERBOY_GRAYS);
}
return;
}
//############################################################################
void LaserBoy_segment::to_palette_by_index(int index)
{
if( index != LASERBOY_TRUE_COLOR
&& index != palette_index
&& index < p_space->number_of_palettes()
)
{
palette_index = index;
set_rgb_from_palette();
p_space->palette_index = palette_index;
}
return;
}
//############################################################################
void LaserBoy_segment::to_target_palette_by_index()
{
if( (int)p_space->target_palette_index != LASERBOY_TRUE_COLOR
&& (int)p_space->target_palette_index != palette_index
&& (int)p_space->target_palette_index < p_space->number_of_palettes()
)
{
palette_index = p_space->target_palette_index;
set_rgb_from_palette();
p_space->palette_index = palette_index;
}
return;
}
//############################################################################
void LaserBoy_segment::best_match_palette(int index)
{
if( index != palette_index
&& index < p_space->number_of_palettes()
)
{
if(size() > 1)
{
if(!p_space->allow_lit_black)
convert_black_to_blank();
else
impose_black_level();
for(size_t i = 1; i < size(); i++)
at(i).c = p_space->palette_picker(index).best_match(at(i));
}
palette_index = index;
set_rgb_from_palette();
p_space->palette_index = palette_index;
}
return;
}
//############################################################################
void LaserBoy_segment::best_match_target_palette()
{
if( (int)p_space->target_palette_index != palette_index
&& (int)p_space->target_palette_index < p_space->number_of_palettes()
)
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
at(i).c = p_space->palette_picker(p_space->target_palette_index).best_match(at(i));
palette_index = p_space->target_palette_index;
set_rgb_from_palette();
p_space->palette_index = palette_index;
}
return;
}
//############################################################################
void LaserBoy_segment::convert_black_to_blank()
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
{
if(at(i).is_black(p_space->black_level))
{
at(i).r = 255;
at(i).g = 0;
at(i).b = 0;
at(i).blank();
}
}
return;
}
//############################################################################
void LaserBoy_segment::convert_black_to_color()
{
if(size() > 1)
{
if(palette_index == LASERBOY_TRUE_COLOR)
{
for(size_t i = 1; i < size(); i++)
{
if(at(i).is_black(p_space->black_level))
{
at(i).c = 55;
at(i).r = 255;
at(i).g = 255;
at(i).b = 255;
at(i).unblank();
}
}
}
else
{
for(size_t i = 1; i < size(); i++)
{
if(at(i).is_black(p_space->black_level))
{
at(i).c = p_space->palette_picker(palette_index).white;
at(i).r = p_space->palette_picker(palette_index).at(at(i).c).r;
at(i).g = p_space->palette_picker(palette_index).at(at(i).c).g;
at(i).b = p_space->palette_picker(palette_index).at(at(i).c).b;
at(i).unblank();
}
}
}
}
return;
}
//############################################################################
void LaserBoy_segment::convert_blank_to_black()
{
if(size() > 1)
{
at(0).r = 0;
at(0).g = 0;
at(0).b = 0;
at(0).c = p_space->palette_picker(palette_index).black;
for(size_t i = 1; i < size(); i++) // Leave the zero index blank!
{
if(at(i).is_blank())
{
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
at(i).c = p_space->palette_picker(palette_index).black;
at(i).unblank();
}
}
}
return;
}
//############################################################################
void LaserBoy_segment::set_vertex_to_black(int index)
{
if(size() > 1 && index > 0 && index < (int)size())
{
at(index).r = 0;
at(index).g = 0;
at(index).b = 0;
at(index).c = p_space->palette_picker(palette_index).black;
}
return;
}
//############################################################################
void LaserBoy_segment::impose_black_level()
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
{
if(at(i).as_color().average() < p_space->black_level)
{
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
}
}
return;
}
//############################################################################
void LaserBoy_segment::index_palette(int index_multiple, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
u_char color_index = offset;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
for(size_t i = 1; i < size(); i += index_multiple)
{
for(int j = 0; j < index_multiple; j++)
{
if( (i + j) < size()
&& at(i + j).is_color(p_space->black_level)
)
at(i + j).c = color_index % span + start;
}
color_index++;
}
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::index_segments_palette(int index_multiple, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
u_char color_index = offset;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i += index_multiple)
{
for(int j = 0; j < index_multiple; j++)
if((i + j) < segments.size())
for(size_t k = 0; k < segments[i + j].size(); k++)
if(segments[i + j].at(k).is_color(p_space->black_level))
segments[i + j].at(k).c = color_index % span + start;
color_index++;
}
*this = segments.sum_of_frames();
}
else
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = color_index % span + start;
}
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( (i * span_factor)
/ (double)(size() - 1)
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_x_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( ((at(i).x + 32767) * span_factor)
/ 65535.0
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_y_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( ((at(i).y + 32767) * span_factor)
/ 65535.0
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_z_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( ((at(i).z + 32767) * span_factor)
/ 65535.0
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_radial_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( (at(i).magnitude())
* p_space->recolor_span_factor
/ 32767.0
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_axial_palette(double span_factor, int offset)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = (char)((u_int)( ( (atan2(at(i).y, at(i).x) + two_pi)
* p_space->recolor_span_factor
/ two_pi
* span
) + offset
)
% span
+ start
);
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_segments_palette(double span_factor, int offset)
{
u_char color_index = offset;
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i++)
{
color_index += u_char ( (i * span_factor)
/ (segments.size() - 1)
* span
) % span + start;
for(size_t j = 1; j < segments[i].size(); j++)
if(segments[i].at(j).is_color(p_space->black_level))
segments[i].at(j).c = color_index;
}
*this = segments.sum_of_frames();
}
else
{
for(size_t j = 1; j < size(); j++)
if(at(j).is_color(p_space->black_level))
at(j).c = color_index;
}
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::random_color_vectors_palette(int index_multiple)
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
for(size_t i = 1; i < size(); i += index_multiple)
{
for(int j = 0; j < index_multiple; j++)
{
if( (i + j) < size()
&& at(i + j).is_color(p_space->black_level)
)
at(i + j).c = (rand() % span) + start;
}
}
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::random_color_segments_palette()
{
if(palette_index == LASERBOY_TRUE_COLOR)
palette_index = p_space->target_palette_index;
u_char color_index;
size_t start = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first
+ 1;
//-----------------------------------------------------------------------
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i++)
{
color_index = (rand() % span) + start;
for(size_t j = 1; j < segments[i].size(); j++)
if(segments[i].at(j).is_color(p_space->black_level))
segments[i].at(j).c = color_index;
}
*this = segments.sum_of_frames();
}
else
{
color_index = (rand() % span) + start;
for(size_t j = 1; j < size(); j++)
if(at(j).is_color(p_space->black_level))
at(j).c = color_index;
}
set_rgb_from_palette();
return;
}
//############################################################################
void LaserBoy_segment::index_hues(int index_multiple, int offset)
{
u_short hue_index = offset;
palette_index = LASERBOY_TRUE_COLOR;
for(size_t i = 1; i < size(); i += index_multiple)
{
for(int j = 0; j < index_multiple; j++)
{
if( (i + j) < size()
&& at(i + j).is_color(p_space->black_level)
)
{
hue_index = hue_index % 1530;
at(i + j) = LaserBoy_color(hue_index);
}
}
hue_index++;
}
return;
}
//############################################################################
void LaserBoy_segment::index_segments_hues(int index_multiple, int offset)
{
u_short color_index = offset;
palette_index = LASERBOY_TRUE_COLOR;
//-----------------------------------------------------------------------
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i += index_multiple)
{
for(int j = 0; j < index_multiple; j++)
if((i + j) < segments.size())
for(size_t k = 0; k < segments[i + j].size(); k++)
if(segments[i + j].at(k).is_color(p_space->black_level))
segments[i + j].at(k) = LaserBoy_color(u_short(color_index % 1530));
color_index++;
}
*this = segments.sum_of_frames();
}
else
{
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color(u_short(color_index % 1530));
}
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)(((int)(((i * span_factor) / (double)(size() - 1)) * 1530) + offset) % 1530));
return;
sync_rgb_and_palette();
}
//############################################################################
void LaserBoy_segment::span_x_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)(((int)( ((at(i).x + 32767) * span_factor) / 65535.0
* 1530
)
+ offset
)
% 1530));
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_y_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)(((int)( ((at(i).y + 32767) * span_factor) / 65535.0
* 1530
)
+ offset
)
% 1530));
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_z_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)(((int)( ((at(i).z + 32767) * span_factor) / 65535.0
* 1530
)
+ offset
)
% 1530));
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_radial_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)( (int)( at(i).magnitude()
* p_space->recolor_span_factor
/ 32767.0
* 1530
+ offset
)
% 1530
)
);
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_axial_hues(double span_factor, int offset)
{
palette_index = LASERBOY_TRUE_COLOR;
if(size() > 1)
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i) = LaserBoy_color((u_short)( (int)( (atan2(at(i).y, at(i).x) + two_pi)
* p_space->recolor_span_factor
/ two_pi
* 1530
+ offset
)
% 1530
)
);
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::span_segments_hues(double span_factor, int offset)
{
u_short color_index = offset;
palette_index = LASERBOY_TRUE_COLOR;
//-----------------------------------------------------------------------
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i++)
{
color_index += u_short( (i * span_factor)
/ (segments.size() - 1)
* 1530
) % 1530;
for(size_t j = 1; j < segments[i].size(); j++)
if(segments[i].at(j).is_color(p_space->black_level))
segments[i].at(j) = LaserBoy_color(color_index);
}
*this = segments.sum_of_frames();
}
else
{
for(size_t j = 1; j < size(); j++)
if(at(j).is_color(p_space->black_level))
at(j) = LaserBoy_color(color_index);
}
sync_rgb_and_palette();
return;
}
//############################################################################
void LaserBoy_segment::random_color_vectors_hues(int index_multiple)
{
u_short hue_index = 0;
palette_index = LASERBOY_TRUE_COLOR;
for(size_t i = 1; i < size(); i += index_multiple)
{
hue_index = rand() % 1530;
for(int j = 0; j < index_multiple; j++)
{
if( (i + j) < size()
&& at(i + j).is_color(p_space->black_level)
)
at(i + j) = LaserBoy_color(hue_index);
}
hue_index++;
}
return;
}
//############################################################################
void LaserBoy_segment::random_color_segments_hues()
{
u_short hue_index = 0;
palette_index = LASERBOY_TRUE_COLOR;
if(number_of_segments() > 1)
{
LaserBoy_frame_set segments = explode_segments();
for(size_t i = 0; i < segments.size(); i++)
{
hue_index = rand() % 1530;
for(size_t j = 1; j < segments[i].size(); j++)
if(segments[i].at(j).is_color(p_space->black_level))
segments[i].at(j) = LaserBoy_color(hue_index);
}
*this = segments.sum_of_frames();
}
else
{
hue_index = rand() % 1530;
for(size_t j = 1; j < size(); j++)
if(at(j).is_color(p_space->black_level))
at(j) = LaserBoy_color(hue_index);
}
sync_rgb_and_palette();
return;
}
//############################################################################
LaserBoy_segment& LaserBoy_segment::rotate_colors(int steps)
{
if( palette_index != LASERBOY_TRUE_COLOR
&& size() > 1
)
{
int offset = p_space->palette_picker(palette_index).first,
span = p_space->palette_picker(palette_index).last
- p_space->palette_picker(palette_index).first;
//----------------------------------------------------------------
for(size_t i = 1; i < size(); i++)
if(at(i).is_color(p_space->black_level))
at(i).c = ((at(i).c - offset + steps) % span) + offset;
set_rgb_from_palette();
}
return *this;
}
//############################################################################
bool LaserBoy_segment::find_rgb_in_palette(const LaserBoy_palette& palette)
{
bool all_colors_found = true;
if(size() > 1)
{
size_t i,
j;
vector match(size(), false);
//--------------------------------------------------------------------
for(i = 0; i < size(); i++)
for(j = 0; j < palette.number_of_colors(); j++)
if((LaserBoy_color)at(i) == palette.at(j))
{
at(i).c = (u_char)j;
match[i] = true;
}
//--------------------------------------------------------------------
for(i = 0; i < size(); i++)
all_colors_found &= match[i];
//--------------------------------------------------------------------
}
return all_colors_found;
}
//############################################################################
void LaserBoy_segment::set_rgb_from_palette()
{
if( palette_index != LASERBOY_TRUE_COLOR
&& size() > 1
)
for(size_t i = 0; i < size(); i++)
{
if(at(i).is_color(p_space->black_level))
{
at(i).r = p_space->palette_picker(palette_index)[at(i).c].r;
at(i).g = p_space->palette_picker(palette_index)[at(i).c].g;
at(i).b = p_space->palette_picker(palette_index)[at(i).c].b;
}
else if(at(i).is_black(p_space->black_level))
{
at(i).r = 0;
at(i).g = 0;
at(i).b = 0;
}
}
return;
}
//############################################################################
void LaserBoy_segment::set_palette_to_332()
{
if(size() > 1)
{
front().c = 0x00;
for(size_t i = 1; i < size(); i++)
at(i).c = (at(i).r & 0xe0)
| ((at(i).g & 0xe0) >> 3)
| ((at(i).b & 0xc0) >> 6);
// does NOT set palette_index to LASERBOY_REDUCED_332
}
return;
}
//############################################################################
void LaserBoy_segment::sync_rgb_and_palette()
{
if(size() > 1)
{
if(palette_index == LASERBOY_ILDA_DEFAULT)
{
set_rgb_from_palette();
return;
}
//----------------------------------------------------------------
int i;
if(palette_index != LASERBOY_TRUE_COLOR)
{
set_rgb_from_palette();
for(i = 0; i < p_space->number_of_palettes(); i++)
if(p_space->palette_picker(palette_index).is_in(p_space->palette_picker(i)))
{
best_match_palette(i);
break;
}
return;
}
//----------------------------------------------------------------
size_t j;
LaserBoy_palette palette;
//----------------------------------------------------------------
if(first_lit_vector_index() > -1) // there are lit vectors!
{
palette.push_back((LaserBoy_color)at(first_lit_vector_index()));
//----------------------------------------------------------------
for(i = first_lit_vector_index() + 1; i < (int)size(); i++)
{
for(j = 0; j < palette.number_of_colors(); j++)
if(at(i).is_lit() && (palette[j] == (LaserBoy_color)at(i)))
break;
if( j == palette.number_of_colors()
&& at(i).is_lit()
)
palette.push_back((LaserBoy_color)at(i));
if(palette.number_of_colors() > LASERBOY_PALETTE_MAX) // cannot be reduced to a palette
{
set_palette_to_332(); // palette_index is still LASERBOY_TRUE_COLOR
return;
}
}
//----------------------------------------------------------------
if(palette.is_in(p_space->palette_picker(LASERBOY_ILDA_DEFAULT)))
{
best_match_palette(LASERBOY_ILDA_DEFAULT);
return;
}
else
{
for(i = p_space->number_of_palettes() - 1; i >= 1; i--)
if(palette.is_in(p_space->palette_picker(i)))
{
best_match_palette(i);
return;
}
palette.reorder();
palette.find_factors();
find_rgb_in_palette(palette);
palette.name = GUID8char();
p_space->push_back_palette(palette);
palette_index = p_space->number_of_palettes() - 1;
return;
}
} // end if(first_lit_vector_index() > -1)
//------------------------------------------------------------------------
} // end if(size() > 1)
palette_index = LASERBOY_ILDA_DEFAULT;
return;
}
//############################################################################
void LaserBoy_segment::bit_reduce_to_palette()
{
if(palette_index == LASERBOY_TRUE_COLOR)
{
set_palette_to_332();
palette_index = LASERBOY_REDUCED_332;
set_rgb_from_palette();
}
return;
}
//############################################################################
void LaserBoy_segment::best_reduce_to_palette()
{
if(number_of_color_vectors() >= 1)
{
int local_palette_index;
size_t i,
j;
LaserBoy_palette palette;
//----------------------------------------------------------------
if(!p_space->allow_lit_black)
convert_black_to_blank();
else
impose_black_level();
//----------------------------------------------------------------
palette.push_back((LaserBoy_color)at(first_lit_vector_index()));
//----------------------------------------------------------------
for(i = first_lit_vector_index() + 1; i < size(); i++)
{
for(j = 0; j < palette.number_of_colors(); j++)
if(at(i).is_lit() && (palette[j] == (LaserBoy_color)at(i)))
break;
if( j == palette.number_of_colors()
&& at(i).is_lit()
)
palette.push_back((LaserBoy_color)at(i));
}
//----------------------------------------------------------------
local_palette_index = palette.best_reduction();
if(local_palette_index == -1)
{
palette.name = GUID8char();
p_space->push_back_palette(palette);
best_match_palette(p_space->number_of_palettes() - 1);
}
else
best_match_palette(local_palette_index);
//----------------------------------------------------------------
}
return;
}
//############################################################################
void LaserBoy_segment::promote_to_true_color()
{
if(palette_index != LASERBOY_TRUE_COLOR)
{
sync_rgb_and_palette();
palette_index = LASERBOY_TRUE_COLOR;
}
return;
}
//############################################################################
void LaserBoy_segment::shade(u_char shade) // 0 shade is no change 255 is black
{
if(shade)
{
sync_rgb_and_palette();
if(palette_index != LASERBOY_TRUE_COLOR)
{
LaserBoy_palette palette(p_space->palette_picker(palette_index));
//----------------------------------------------------------------
palette.shade(shade);
//----------------------------------------------------------------
palette.name = GUID8char();
p_space->push_back_palette(palette);
//----------------------------------------------------------------
palette_index = p_space->number_of_palettes() - 1;
set_rgb_from_palette();
}
else
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
{
(at(i).r - shade > 0) ? (at(i).r -= shade) : (at(i).r = 0);
(at(i).g - shade > 0) ? (at(i).g -= shade) : (at(i).g = 0);
(at(i).b - shade > 0) ? (at(i).b -= shade) : (at(i).b = 0);
}
}
}
return;
}
//############################################################################
void LaserBoy_segment::tint(u_char tint) // 0 tint is no change 255 is white
{
if(tint)
{
sync_rgb_and_palette();
if(palette_index != LASERBOY_TRUE_COLOR)
{
LaserBoy_palette palette(p_space->palette_picker(palette_index));
//----------------------------------------------------------------
palette.tint(tint);
//----------------------------------------------------------------
palette.name = GUID8char();
p_space->push_back_palette(palette);
//----------------------------------------------------------------
palette_index = p_space->number_of_palettes() - 1;
set_rgb_from_palette();
}
else
{
if(size() > 1)
for(size_t i = 1; i < size(); i++)
{
(at(i).r + tint < 255) ? (at(i).r += tint) : (at(i).r = 255);
(at(i).g + tint < 255) ? (at(i).g += tint) : (at(i).g = 255);
(at(i).b + tint < 255) ? (at(i).b += tint) : (at(i).b = 255);
}
}
}
return;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::color_from_bmp(const string& file)
{
char file_name[256];
struct LaserBoy_bmp bmp = {0};
strcpy(file_name, (file).c_str());
if(bmp_from_file(&bmp, file_name))
{
color_from_bmp(&bmp);
bmp_free(&bmp);
return LASERBOY_OK;
}
return LASERBOY_FILE_OPEN_FAILED;
}
//############################################################################
void LaserBoy_segment::color_from_bmp(struct LaserBoy_bmp* bmp)
{
if(size() > 1)
{
size_t i;
u_int color,
x_off = 0,
y_off = 0;
double factor = bmp->xres > bmp->yres
? 65535.0 / bmp->xres
: 65535.0 / bmp->yres;
LaserBoy_segment line;
LaserBoy_vertex vertex;
//----------------------------------------------------------------
if(bmp->xres > bmp->yres)
y_off = (bmp->xres - bmp->yres) / 2;
else if(bmp->xres < bmp->yres)
x_off = (bmp->yres - bmp->xres) / 2;
//----------------------------------------------------------------
if(bmp->bpp <= 8)
for(i = 1; i < size(); i++)
{
line.clear();
line.push_back(at(i - 1));
line.push_back(at(i ));
vertex = line.rectangular_center_of();
color = bmp->get_pixel( bmp,
(int)((vertex.x + 32767.0) / factor - x_off),
(int)((vertex.y + 32767.0) / factor - y_off)
);
at(i).r = bmp_get_palette_index_r(bmp, color);
at(i).g = bmp_get_palette_index_g(bmp, color);
at(i).b = bmp_get_palette_index_b(bmp, color);
}
//----------------------------------------------------------------
else
for(i = 1; i < size(); i++)
{
line.clear();
line.push_back(at(i - 1));
line.push_back(at(i ));
vertex = line.rectangular_center_of();
color = bmp->get_pixel( bmp,
(int)((vertex.x + 32767.0) / factor - x_off),
(int)((vertex.y + 32767.0) / factor - y_off)
);
at(i).r = bmp->r_from_rgb(color);
at(i).g = bmp->g_from_rgb(color);
at(i).b = bmp->b_from_rgb(color);
}
//----------------------------------------------------------------
palette_index = LASERBOY_TRUE_COLOR;
sync_rgb_and_palette();
}
return;
}
//############################################################################
LaserBoy_Error_Code LaserBoy_segment::subtract_bmp(const string& file)
{
char file_name[256];
struct LaserBoy_bmp bmp = {0};
strcpy(file_name, (file).c_str());
if(bmp_from_file(&bmp, file_name))
{
subtract_bmp(&bmp);
bmp_free(&bmp);
return LASERBOY_OK;
}
return LASERBOY_FILE_OPEN_FAILED;
}
//############################################################################
void LaserBoy_segment::subtract_bmp(struct LaserBoy_bmp* bmp)
{
if(size() > 1)
{
u_char mask;
size_t i;
u_int pixle_color,
x_off = 0,
y_off = 0;
double factor = bmp->xres > bmp->yres
? 65535.0 / bmp->xres
: 65535.0 / bmp->yres;
LaserBoy_segment line;
LaserBoy_vertex vertex;
//----------------------------------------------------------------
if(bmp->xres > bmp->yres)
y_off = (bmp->xres - bmp->yres) / 2;
else if(bmp->xres < bmp->yres)
x_off = (bmp->yres - bmp->xres) / 2;
//----------------------------------------------------------------
if(bmp->bpp <= 8)
for(i = 1; i < size(); i++)
{
line.clear();
line.push_back(at(i - 1));
line.push_back(at(i ));
vertex = line.rectangular_center_of();
pixle_color = bmp->get_pixel( bmp,
(int)((vertex.x + 32767.0) / factor - x_off),
(int)((vertex.y + 32767.0) / factor - y_off)
);
mask = 255 - bmp_get_palette_index_r(bmp, pixle_color);
(at(i).r - mask > 0) ? (at(i).r -= mask) : (at(i).r = 0);
mask = 255 - bmp_get_palette_index_g(bmp, pixle_color);
(at(i).g - mask > 0) ? (at(i).g -= mask) : (at(i).g = 0);
mask = 255 - bmp_get_palette_index_b(bmp, pixle_color);
(at(i).b - mask > 0) ? (at(i).b -= mask) : (at(i).b = 0);
}
//----------------------------------------------------------------
else
for(i = 1; i < size(); i++)
{
line.clear();
line.push_back(at(i - 1));
line.push_back(at(i ));
vertex = line.rectangular_center_of();
pixle_color = bmp->get_pixel( bmp,
(int)((vertex.x + 32767.0) / factor - x_off),
(int)((vertex.y + 32767.0) / factor - y_off)
);
mask = 255 - bmp->r_from_rgb(pixle_color);
(at(i).r - mask > 0) ? (at(i).r -= mask) : (at(i).r = 0);
mask = 255 - bmp->g_from_rgb(pixle_color);
(at(i).g - mask > 0) ? (at(i).g -= mask) : (at(i).g = 0);
mask = 255 - bmp->b_from_rgb(pixle_color);
(at(i).b - mask > 0) ? (at(i).b -= mask) : (at(i).b = 0);
}
//----------------------------------------------------------------
palette_index = LASERBOY_TRUE_COLOR;
sync_rgb_and_palette();
}
return;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::apply_view()
{
LaserBoy_real_segment rs = to_real_segment(false);
rs.rotate_around_origin(p_space->view_angle );
rs.scale_around_origin (p_space->view_scale );
rs.move (p_space->view_offset * p_space->view_scale);
if(p_space->destructive_clipping)
{
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
else
{
LaserBoy_3D_double max( 32767, 32767, 32767);
LaserBoy_3D_double min(-32767, -32767, -32767);
for(size_t i = 0; i < size(); i++)
if(LaserBoy_bounds_check(rs.at(i), max, min))
return LaserBoy_bounds_check(rs.at(i), max, min);
}
*this = rs;
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::move(LaserBoy_3D_double d)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d;
//----------------------------------------------------------------
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
{
_d = d + at(i).as_3D_double();
out_of_bounds = LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = 0; i < size(); i++)
{
_d = d + at(i).as_3D_double();
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.move(d);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::move()
{
return move(p_space->view_offset);
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale(LaserBoy_3D_double s)
{
return scale_on_coordinates(centroid_of_coordinates(), s);
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale_on_coordinates(LaserBoy_3D_double p, LaserBoy_3D_double s)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double d;
if(!p_space->destructive_clipping)
{
for(i = 0; i < size(); i++)
if(( out_of_bounds
|= LaserBoy_bounds_check(((at(i).as_3D_double() - p) * s) + p, LASERBOY_CUBE)
))
return out_of_bounds;
//----------------------------------------------------------------
for(i = 0; i < size(); i++)
at(i) = ((at(i).as_3D_double() - p) * s) + p;
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.scale_on_coordinates(p, s);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale_around_origin(LaserBoy_3D_double f)
{
if(size() > 1)
{
size_t i;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d;
if(!p_space->destructive_clipping)
{
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
_d = f * at(i).as_3D_double();
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
_d = f * at(i - 1).as_3D_double();
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
}
for(i = 0; i < size(); i++)
{
_d = f * at(i).as_3D_double();
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
rs.scale_around_origin(f);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale_around_origin()
{
return scale_around_origin(p_space->view_scale);
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::rectangular_center_of() const
{
LaserBoy_3D_double center;
if(size() > 1)
{
double max_x = -40000, // more negative than any short
min_x = 40000, // more positive than any short
max_y = -40000,
min_y = 40000,
max_z = -40000,
min_z = 40000;
for(size_t i = 0; i < size(); i++)
{
if(at(i).x > max_x) max_x = at(i).x;
if(at(i).x < min_x) min_x = at(i).x;
if(at(i).y > max_y) max_y = at(i).y;
if(at(i).y < min_y) min_y = at(i).y;
if(at(i).z > max_z) max_z = at(i).z;
if(at(i).z < min_z) min_z = at(i).z;
}
center.x = max_x - ((max_x - min_x) / 2.0);
center.y = max_y - ((max_y - min_y) / 2.0);
center.z = max_z - ((max_z - min_z) / 2.0);
}
return center;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::mean_of_coordinates() const
{
LaserBoy_3D_double mean;
if(size() > 1)
{
mean = front();
for(size_t i = 1; i < size(); i++)
mean += at(i);
mean /= size();
}
return mean;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_coordinates_xy(double& area, LaserBoy_segment& s) const
{
LaserBoy_real_segment rs;
LaserBoy_3D_double c = to_real_segment(false).centroid_of_coordinates_xy(area, rs);
s = rs;
return c;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_coordinates_zy(double& area, LaserBoy_segment& s) const
{
LaserBoy_real_segment rs;
LaserBoy_3D_double c = to_real_segment(false).centroid_of_coordinates_zy(area, rs);
s = rs;
return c;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_coordinates_xz(double& area, LaserBoy_segment& s) const
{
LaserBoy_real_segment rs;
LaserBoy_3D_double c = to_real_segment(false).centroid_of_coordinates_xz(area, rs);
s = rs;
return c;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_coordinates() const
{
return to_real_segment(false).centroid_of_coordinates();
}
//############################################################################
size_t LaserBoy_segment::number_of_segments() const // a segment is a series of lit vertices
{
size_t i,
segment_count = 0;
if(size() > 1)
{
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
while(at(i).is_lit() && i < (size() - 1))
i++;
segment_count++;
}
}
}
return segment_count;
}
//############################################################################
LaserBoy_segment LaserBoy_segment::blend(const LaserBoy_segment& segment, double ratio)
{
if(ratio == 0.0)
return *this;
else if(ratio == 1.0)
return segment;
else if( size() > 1
&& segment.size() > 1
)
{
size_t i,
diff;
LaserBoy_segment this_one(*this),
other_one(segment),
combo;
this_one.convert_blank_to_black();
other_one.convert_blank_to_black();
combo.palette_index = LASERBOY_TRUE_COLOR;
if(this_one.size() > other_one.size())
while(this_one.size() / other_one.size() > 1)
other_one += other_one;
else
while(other_one.size() / this_one.size() > 1)
this_one += this_one;
if(this_one.size() > other_one.size())
{
diff = (this_one.size() - other_one.size());
for(i = 0; i < diff; i++)
other_one += other_one[i];
}
else if(this_one.size() < other_one.size())
{
diff = (other_one.size() - this_one.size());
for(i = 0; i < diff; i++)
this_one += this_one[i];
}
combo.reserve(this_one.size());
for(i = 0; i < this_one.size(); i++)
combo += this_one.at(i).blend(other_one.at(i), ratio);
return combo;
}
else
return *this;
}
//############################################################################
bool LaserBoy_segment::find_segment_at_index(size_t segment_index, size_t& start, size_t& end) const
{ // the first segment is number zero!
if(size() > 1)
{
size_t i;
int segment_count = -1;
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
start = i - 1; // anchor of first lit vector in segment
while(at(i).is_lit() && i < (size() - 1))
i++;
//------------------------------------------------------------
end = i - 1;
if( i == (size() - 1)
&& at(i).is_lit()
)
end = i;
//------------------------------------------------------------
segment_count++;
if(segment_count == (int)segment_index)
return true;
}
} // segment_index out of range
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
start = i - 1;
while(at(i).is_lit() && i < (size() - 1))
i++;
end = i - 1;
if( i == (size() - 1)
&& at(i).is_lit()
)
end = i;
return false; // and set start, end to first segment
}
}
}
//------------------------------------------------------------------------
return false;
}
//############################################################################
bool LaserBoy_segment::find_segment_of_vertex(size_t vertex_index, size_t& start, size_t& end, size_t& segment_index) const
{
start = end = segment_index = 0;
if(size() > 1)
{
size_t i,
segment_count = 0; // the first segment is number zero!
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
start = i - 1;
while(at(i).is_lit() && i < (size() - 1))
i++;
end = i - 1;
if( vertex_index >= start
&& vertex_index <= end
)
{
segment_index = segment_count;
return true;
}
if(vertex_index < start)
{
segment_index = segment_count;
return false;
}
segment_count++;
}
}
}
//------------------------------------------------------------------------
return false;
}
//############################################################################
bool LaserBoy_segment::same_as(const LaserBoy_segment& segment) const
{
LaserBoy_segment s1(*this),
s2(segment);
s1.reduce_blank_vectors();
s1.reduce_lit_vectors();
s1.remove_dwell_vertices();
s2.reduce_blank_vectors();
s2.reduce_lit_vectors();
s2.remove_dwell_vertices();
s2 += s1;
s2.omit_equivalent_vectors();
s2.reduce_blank_vectors();
s2.reduce_lit_vectors();
s2.remove_dwell_vertices();
return (s1.size() == s2.size());
}
//############################################################################
LaserBoy_segment LaserBoy_segment::copy_segment(size_t segment_index) const
{
if(size() > 1)
{
size_t start,
end;
LaserBoy_segment segment(palette_index, false);
find_segment_at_index(segment_index, start, end);
segment.reserve((end - start) + 1);
for(size_t i = start; i <= end; i++)
segment.push_back(at(i));
return segment;
}
return LaserBoy_segment(palette_index, true);
}
//############################################################################
LaserBoy_frame_set LaserBoy_segment::explode_segments() const
{
LaserBoy_frame_set segments;
//------------------------------------------------------------------------
if(size() > 1)
{
size_t i,
j,
start,
end;
LaserBoy_frame frame(palette_index, false);
//----------------------------------------------------------------
for(i = 1; i < size(); i++)
{
if(at(i).is_lit())
{
start = i - 1; // anchor to the first lit vertex
while(at(i).is_lit() && i < (size() - 1))
i++;
//------------------------------------------------------------
end = i - 1;
if( i == (size() - 1)
&& at(i).is_lit()
)
end = i;
//------------------------------------------------------------
frame.clear();
frame.reserve(end - start + 1);
for(j = start; j <= end; j++)
frame += at(j);
segments.push_back(frame);
}
}
}
//------------------------------------------------------------------------
return segments;
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::rectangular_center_of_segment(size_t segment_index) const
{
return (copy_segment(segment_index)).rectangular_center_of();
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::mean_of_coordinates_of_segment(size_t segment_index) const
{
return (copy_segment(segment_index)).mean_of_coordinates();
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_segment_xy(size_t segment_index, double& area, LaserBoy_segment& s) const
{
return (copy_segment(segment_index)).centroid_of_coordinates_xy(area, s);
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_segment_zy(size_t segment_index, double& area, LaserBoy_segment& s) const
{
return (copy_segment(segment_index)).centroid_of_coordinates_zy(area, s);
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_segment_xz(size_t segment_index, double& area, LaserBoy_segment& s) const
{
return (copy_segment(segment_index)).centroid_of_coordinates_xz(area, s);
}
//############################################################################
LaserBoy_3D_double LaserBoy_segment::centroid_of_segment(size_t segment_index) const
{
return (copy_segment(segment_index)).centroid_of_coordinates();
}
//############################################################################
size_t LaserBoy_segment::segment_index_of_vertex(size_t vertex_index) const
{
size_t start, end, segment_index;
find_segment_of_vertex(vertex_index, start, end, segment_index);
return segment_index;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::move_segment(size_t segment_index, LaserBoy_3D_double f)
{
if(size() > 1)
{
size_t i,
start,
end;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d;
find_segment_at_index(segment_index, start, end);
if(!p_space->destructive_clipping)
{
for(i = start; i <= end; i++)
{
_d = f + at(i).as_3D_double();
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = start; i <= end; i++)
{
_d = f + at(i).as_3D_double();
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
for(i = start; i <= end; i++)
rs.at(i) += f;
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_segment(size_t segment_index, LaserBoy_3D_double a)
{
if(size() > 1)
{
size_t i,
start,
end;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d,
center;
find_segment_at_index(segment_index, start, end);
center = centroid_of_segment(segment_index);
if(!p_space->destructive_clipping)
{
for(i = start; i <= end; i++)
{
_d = rotate_vertex_on_coordinates(at(i), center, a);
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = start; i <= end; i++)
{
_d = rotate_vertex_on_coordinates(at(i), center, a);
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
for(i = start; i <= end; i++)
rs.at(i) = rotate_vertex_on_coordinates(rs.at(i), center, a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::rotate_segment_around_origin(size_t segment_index, LaserBoy_3D_double a)
{
if(size() > 1)
{
size_t i,
start,
end;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d;
find_segment_at_index(segment_index, start, end);
if(!p_space->destructive_clipping)
{
for(i = start; i <= end; i++)
{
_d = rotate_vertex(at(i), a);
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_SPHERE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = start; i <= end; i++)
{
_d = rotate_vertex(at(i), a);
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
for(i = start; i <= end; i++)
rs.at(i) = rotate_vertex(rs.at(i), a);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale_segment(size_t segment_index, LaserBoy_3D_double m)
{
if(size() > 1)
{
size_t i,
start,
end;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_short center;
LaserBoy_3D_double _d;
find_segment_at_index(segment_index, start, end);
center = centroid_of_segment(segment_index);
if(!p_space->destructive_clipping)
{
for(i = start; i <= end; i++)
{
_d = scale_vertex_on_coordinates(at(i), center, m);
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = start; i <= end; i++)
{
_d = scale_vertex_on_coordinates(at(i), center, m);
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
for(i = start; i <= end; i++)
rs.at(i) = scale_vertex_on_coordinates(rs.at(i), center, m);
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_Bounds LaserBoy_segment::scale_segment_around_origin(size_t segment_index, LaserBoy_3D_double m)
{
if(size() > 1)
{
size_t i,
start,
end;
LaserBoy_Bounds out_of_bounds = LASERBOY_IN_BOUNDS;
LaserBoy_3D_double _d;
find_segment_at_index(segment_index, start, end);
if(!p_space->destructive_clipping)
{
for(i = start; i <= end; i++)
{
_d = m * at(i).as_3D_double();
out_of_bounds |= LaserBoy_bounds_check(_d, LASERBOY_CUBE);
if(out_of_bounds)
return out_of_bounds;
}
for(i = start; i <= end; i++)
{
_d = m * at(i).as_3D_double();
at(i) = _d;
}
return LASERBOY_IN_BOUNDS;
}
LaserBoy_real_segment rs = to_real_segment(false);
for(i = start; i <= end; i++)
rs.at(i) *= m;
rs.clip();
*this = rs;
return LASERBOY_IN_BOUNDS;
}
return LASERBOY_IN_BOUNDS;
}
//############################################################################
LaserBoy_real_segment LaserBoy_segment::to_real_segment(bool add_origin) const
{
LaserBoy_real_vertex rv;
LaserBoy_real_segment rs;
rs.palette_index = palette_index;
rs.real_segment_error = segment_error;
if(add_origin)
{
rs.reserve(size() + 2);
rs.push_back(rv);
rs.push_back(rv); // origin vector
}
else
rs.reserve(size());
if(size() > 1)
for(size_t i = 0; i < size(); i++)
{
rv.x = at(i).x;
rv.y = at(i).y;
rv.z = at(i).z;
rv.r = at(i).r;
rv.g = at(i).g;
rv.b = at(i).b;
rv.k = at(i).k;
rv.c = at(i).c;
rs.push_back(rv);
}
return rs;
}
//############################################################################
void LaserBoy_segment::to_fstream_wav(std::fstream& out,
LaserBoy_wav_header& header,
bool end_of_frame,
bool unique_frame
)
{
if(size() > 1)
{
size_t i;
for(i = 0; i < size() - 1; i++)
at(i).to_fstream_wav(out,
header,
p_space->signal_bit_mask,
false,
false,
p_space->invert_wav_output
);
at(i).to_fstream_wav(out,
header,
p_space->signal_bit_mask,
end_of_frame,
unique_frame,
p_space->invert_wav_output
);
if(end_of_frame)
header.num_frames++;
}
return;
}
//############################################################################
LaserBoy_segment blank_segment()
{
LaserBoy_segment segment(LASERBOY_ILDA_DEFAULT, false);
segment.reserve(2);
segment.push_back(LaserBoy_vertex(0, 0, 0, 255, 255, 255, 64, 55));
segment.push_back(LaserBoy_vertex(0, 0, 0, 255, 255, 255, 64, 55));
return segment;
}
//############################################################################
//////////////////////////////////////////////////////////////////////////////
//############################################################################