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

//############################################################################
#include "LaserBoy_color.hpp"
#include "LaserBoy_3D_double.hpp"

//############################################################################
class LaserBoy_real_vertex : public LaserBoy_3D_double, public LaserBoy_color
{
public:
    LaserBoy_real_vertex(const double&  _x = 0,
                         const double&  _y = 0,
                         const double&  _z = 0,
                         const u_char&  _r = 0,
                         const u_char&  _g = 0,
                         const u_char&  _b = 0,
                         const u_char&  _k = LASERBOY_BLANKING_BIT,
                         const u_char&  _c = 0
                        )
                  : LaserBoy_3D_double (_x, _y, _z),
                    LaserBoy_color     (_r, _g, _b),
                    k                  (_k        ),
                    c                  (_c        )             {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex(const LaserBoy_real_vertex& p)
                  : LaserBoy_3D_double (p.x, p.y, p.z),
                    LaserBoy_color     (p.r, p.g, p.b),
                    k                  (p.k          ),
                    c                  (p.c          )          {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex(const LaserBoy_3D_double& f,
                         const LaserBoy_color&     rgb,
                         const u_char&             _k = LASERBOY_BLANKING_BIT,
                         const u_char&             _c = 0
                        )
                  : LaserBoy_3D_double (f  ),
                    LaserBoy_color     (rgb),
                    k                  (_k ),
                    c                  (_c )                    {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex(const LaserBoy_3D_double& f,
                         const u_char&             _c
                        )
                  : LaserBoy_3D_double (f),
                    LaserBoy_color     (0, 0, 0),
                    k                  (LASERBOY_BLANKING_BIT),
                    c                  (_c)                     {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex(const LaserBoy_3D_double& f)
                  : LaserBoy_3D_double (f),
                    LaserBoy_color     (0, 0, 0),
                    k                  (LASERBOY_BLANKING_BIT),
                    c                  (0)                      {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex( const LaserBoy_color& rgb)
                  : LaserBoy_3D_double (0, 0, 0),
                    LaserBoy_color     (rgb),
                    k                  (LASERBOY_BLANKING_BIT),
                    c                  (0)                      {}
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& operator = (const LaserBoy_real_vertex& p)
                    {
                        x = p.x;
                        y = p.y;
                        z = p.z;
                        r = p.r;
                        g = p.g;
                        b = p.b;
                        k = p.k;
                        c = p.c;
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& operator = (const LaserBoy_3D_double& f) // only assign the coordinates
                    {
                        x = f.x;
                        y = f.y;
                        z = f.z;
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex  operator + (const LaserBoy_3D_double& f)
                    {
                        LaserBoy_real_vertex sum(*this);
                        sum.x += f.x;
                        sum.y += f.y;
                        sum.z += f.z;
                        sum.k =  k;
                        sum.c =  c;
                        sum.r =  r;
                        sum.g =  g;
                        sum.b =  b;
                        return sum;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& operator += (const LaserBoy_3D_double& f)
                    {
                        x += f.x;
                        y += f.y;
                        z += f.z;
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex  operator - (const LaserBoy_3D_double& f)
                    {
                        LaserBoy_real_vertex diff(*this);
                        diff.x -= f.x;
                        diff.y -= f.y;
                        diff.z -= f.z;
                        return diff;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& operator -= (const LaserBoy_3D_double& f)
                    {
                        x -= f.x;
                        y -= f.y;
                        z -= f.z;
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& operator *= (const LaserBoy_3D_double& f)
                    {
                        x *= f.x;
                        y *= f.y;
                        z *= f.z;
                        return *this;
                    }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex operator * (const LaserBoy_3D_double& f)
                    {
                        LaserBoy_real_vertex product;
                        product.r = r;
                        product.g = g;
                        product.b = b;
                        product.x = x * f.x;
                        product.y = y * f.y;
                        product.z = z * f.z;
                        product.k = k;
                        product.c = c;
                        return product;
                    }
    //------------------------------------------------------------------------
    bool operator == (const LaserBoy_real_vertex& p) const
            {
                if(    (x != p.x)
                    || (y != p.y)
                    || (z != p.z)
                    || (r != p.r)
                    || (g != p.g)
                    || (b != p.b)
                    || ((k & LASERBOY_BLANKING_BIT) != (p.k & LASERBOY_BLANKING_BIT))
                    || (c != p.c)
                  )
                    return false;
                return true;
            }
    //------------------------------------------------------------------------
    bool operator != (const LaserBoy_real_vertex& p) const
            {
                if(    (x == p.x)
                    && (y == p.y)
                    && (z == p.z)
                    && (r == p.r)
                    && (g == p.g)
                    && (b == p.b)
                    && ((k & LASERBOY_BLANKING_BIT) == (p.k & LASERBOY_BLANKING_BIT))
                    && (c == p.c)
                  )
                    return false;
                return true;
            }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex operator - ()
                    {
                        LaserBoy_real_vertex negative;
                        negative.x = -x;
                        negative.y = -y;
                        negative.z = -z;
                        return negative;
                    }
    //------------------------------------------------------------------------
    bool from_ifstream_txt(ifstream& in, const int& format_1, int& line_number)
        {
            bool   got_data = false;
            int    next_char;
            double number;
            clear_to_token(in, next_char, line_number);
            if(    isdigit(next_char)
                || next_char == '.'
                || next_char == '-'
                || next_char == '+'
              )
            {
                if(get_next_number(in, x, line_number)) // 1
                {
                    got_data = true;
                    if(get_next_number(in, y, line_number)) // 2
                    {
                        // x and y are always the first 2 values.
                        //.................
                        // if there is a z
                        if(    format_1 == LASERBOY_3D_FRAME_RGB
                            || format_1 == LASERBOY_3D_FRAME_HEX
                            || format_1 == LASERBOY_3D_FRAME_PALETTE
                            || format_1 == LASERBOY_3D_FRAME_TABLE
                          )
                        {
                            if(get_next_number(in, z, line_number))
                            {
                                // we just got z!
                            }
                            else
                                return in.good();
                        }
                        else
                            z = 0;
                        //.................
                        // color values
                        // if there is an r g b
                        if(    (    (format_1 == LASERBOY_3D_FRAME_RGB)
                                 || (format_1 == LASERBOY_2D_FRAME_RGB)
                               )
                            && (get_next_number(in, number, line_number))
                          )
                        {
                            if(number == -1) // it's blank
                            {
                                blank();
                                r = g = b = c = 0;
                            }
                            else
                            {
                                unblank();
                                r = (u_char)number;
                                if(get_next_number(in, number, line_number))
                                {
                                    g = (u_char)number;
                                    if(get_next_number(in, number, line_number))
                                        b = (u_char)number;
                                }
                                c = 0;
                            }
                        }
                        //.................
                        // if there is a hex
                        else if(    (    (format_1 == LASERBOY_3D_FRAME_HEX)
                                      || (format_1 == LASERBOY_2D_FRAME_HEX)
                                    )
                                 && (get_next_hex(in, number, line_number))
                               )
                        {
                            if(number == -1) // it's blank
                            {
                                blank();
                                r = g = b = c = 0;
                            }
                            else
                            {
                                unblank();
                                r = (((int)number) & 0x00ff0000) >> 16;
                                g = (((int)number) & 0x0000ff00) >>  8;
                                b = (((int)number) & 0x000000ff)      ;
                                c = 0;
                            }
                        }
                        //.................
                        // else if there is c (color index to palette)
                        else if(    (    (format_1 == LASERBOY_3D_FRAME_PALETTE)
                                      || (format_1 == LASERBOY_2D_FRAME_PALETTE)
                                    )
                                 && (get_next_number(in, number, line_number))
                               )
                        {
                            if(number == -1) // it's blank
                            {
                                blank();
                                r = g = b = c = 0;
                            }
                            else
                            {
                                unblank();
                                c = (u_char)number;
                            }
                        }
                    } // end if(get_next_number(in, number, line_number)) // 2
                } // end if(get_next_number(in, number, line_number)) // 1
            }
            return (in.good() && got_data);
        }
    //------------------------------------------------------------------------
    LaserBoy_real_vertex& blank  () { k |=  LASERBOY_BLANKING_BIT; return *this; }
    LaserBoy_real_vertex& unblank() { k &= ~LASERBOY_BLANKING_BIT; return *this; }
    //------------------------------------------------------------------------
    bool  is_blank    () const { return (bool)(k & LASERBOY_BLANKING_BIT);  }
    bool  is_lit      () const { return !is_blank()                      ;  }
    //------------------------------------------------------------------------
    void  set_unique  ()       { k |=  LASERBOY_UNIQUE_VERTEX;      return; }
    void  clear_unique()       { k &= ~LASERBOY_UNIQUE_VERTEX;      return; }
    bool  is_unique   () const { return (bool)(k & LASERBOY_UNIQUE_VERTEX); }
    //------------------------------------------------------------------------
    bool  is_black    (int black_level = 0) const
            {
                return (    is_lit()
                         && ((r + g + b) <= black_level)
                       );
            }
    //------------------------------------------------------------------------
    bool  is_color    (int black_level = 0) const
            {
                return (    is_lit()
                         && ((r + g + b) > black_level)
                       );
            }
    //------------------------------------------------------------------------
    bool  is_dark     (int black_level = 0) const
            {
                return (    is_blank()
                         || ((r + g + b) <= black_level)
                       );
            }
    //------------------------------------------------------------------------
    LaserBoy_3D_double position() const {  return (LaserBoy_3D_double)(*this); }
    //------------------------------------------------------------------------
    int color() const
            {
                return   is_lit()
                       ? (int)(   r << 16
                                | g <<  8
                                | b
                              )
                       : -1; // is blank
            }
    //------------------------------------------------------------------------
    LaserBoy_color as_LaserBoy_color() const
            {
                return (LaserBoy_color)(*this);
            }
    //------------------------------------------------------------------------
    u_char  k, c;
};

//############################################################################
typedef vector<LaserBoy_real_vertex> LaserBoy_real_segment_base;

//############################################################################
#endif

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