/*
    This file includes miscellaneous plot functions and logic
    for 3D, used by lorenz.c and line3d.c
    By Tim Wegner and Marc Reinig.
*/

  /* see Fractint.c for a description of the "include"  hierarchy */
#include "port.h"
#include "prototyp.h"
#include "fractype.h"

/* Use these palette indices for red/blue - same on ega/vga */
#define PAL_BLUE    1
#define PAL_RED 2
#define PAL_MAGENTA 3

int whichimage;
int xxadjust1;
int yyadjust1;
int eyeseparation = 0;
int glassestype = 0;
int xshift1;
int yshift1;
int xtrans = 0;
int ytrans = 0;
int red_local_left;
int red_local_right;
int blue_local_left;
int blue_local_right;
int red_crop_left   = 4;
int red_crop_right  = 0;
int blue_crop_left  = 0;
int blue_crop_right = 4;
int red_bright      = 80;
int blue_bright     = 100;

BYTE T_RED;

/* Bresenham's algorithm for drawing line */
void cdecl draw_line (int X1, int Y1, int X2, int Y2, int color)

{               /* uses Bresenham algorithm to draw a line */
    int dX, dY;                     /* vector components */
    int row, col,
        final,                      /* final row or column number */
        G,                  /* used to test for new row or column */
        inc1,           /* G increment when row or column doesn't change */
        inc2;               /* G increment when row or column changes */
    char pos_slope;

    dX = X2 - X1;                   /* find vector components */
    dY = Y2 - Y1;
    pos_slope = (char)(dX > 0);                   /* is slope positive? */
    if (dY < 0)
    pos_slope = (char)!pos_slope;
    if (abs (dX) > abs (dY))                /* shallow line case */
    {
        if (dX > 0)         /* determine start point and last column */
        {
            col = X1;
            row = Y1;
            final = X2;
        }
        else
        {
            col = X2;
            row = Y2;
            final = X1;
        }
        inc1 = 2 * abs (dY);            /* determine increments and initial G */
        G = inc1 - abs (dX);
        inc2 = 2 * (abs (dY) - abs (dX));
        if (pos_slope)
            while (col <= final)    /* step through columns checking for new row */
            {
                (*plot) (col, row, color);
                col++;
                if (G >= 0)             /* it's time to change rows */
                {
                    row++;      /* positive slope so increment through the rows */
                    G += inc2;
                }
                else                        /* stay at the same row */
                    G += inc1;
            }
        else
            while (col <= final)    /* step through columns checking for new row */
            {
                (*plot) (col, row, color);
                col++;
                if (G > 0)              /* it's time to change rows */
                {
                    row--;      /* negative slope so decrement through the rows */
                    G += inc2;
                }
                else                        /* stay at the same row */
                    G += inc1;
            }
    }   /* if |dX| > |dY| */
    else                            /* steep line case */
    {
        if (dY > 0)             /* determine start point and last row */
        {
            col = X1;
            row = Y1;
            final = Y2;
        }
        else
        {
            col = X2;
            row = Y2;
            final = Y1;
        }
        inc1 = 2 * abs (dX);            /* determine increments and initial G */
        G = inc1 - abs (dY);
        inc2 = 2 * (abs (dX) - abs (dY));
        if (pos_slope)
            while (row <= final)    /* step through rows checking for new column */
            {
                (*plot) (col, row, color);
                row++;
                if (G >= 0)                 /* it's time to change columns */
                {
                    col++;  /* positive slope so increment through the columns */
                    G += inc2;
                }
                else                    /* stay at the same column */
                    G += inc1;
            }
        else
            while (row <= final)    /* step through rows checking for new column */
            {
                (*plot) (col, row, color);
                row++;
                if (G > 0)                  /* it's time to change columns */
                {
                    col--;  /* negative slope so decrement through the columns */
                    G += inc2;
                }
                else                    /* stay at the same column */
                    G += inc1;
            }
    }
}   /* draw_line */

#if 0
/* use this for continuous colors later */
void _fastcall plot3dsuperimpose16b(int x,int y,int color)
{
    int tmp;
    if (color != 0)         /* Keeps index 0 still 0 */
    {
        color = colors - color; /*  Reverses color order */
        color = color / 4;
        if(color == 0)
            color = 1;
    }
    color = 3;
    tmp = getcolor(x,y);

    /* map to 4 colors */
    if(whichimage == 1) /* RED */
    {
        if(red_local_left < x && x < red_local_right)
        {
            putcolor(x,y,color|tmp);
            if (Targa_Out)
                targa_color(x, y, color|tmp);
        }
    }
    else if(whichimage == 2) /* BLUE */
        if(blue_local_left < x && x < blue_local_right)
        {
            color = color <<2;
            putcolor(x,y,color|tmp);
            if (Targa_Out)
                targa_color(x, y, color|tmp);
        }
}

#endif

void _fastcall plot3dsuperimpose16(int x,int y,int color)
{
    int tmp;

    tmp = getcolor(x,y);

    if(whichimage == 1) /* RED */
    {
        color = PAL_RED;
        if(tmp > 0 && tmp != color)
            color = PAL_MAGENTA;
        if(red_local_left < x && x < red_local_right)
        {
            putcolor(x,y,color);
            if (Targa_Out)
                targa_color(x, y, color);
        }
    }
    else if(whichimage == 2) /* BLUE */
        if(blue_local_left < x && x < blue_local_right)
        {
            color = PAL_BLUE;
            if(tmp > 0 && tmp != color)
                color = PAL_MAGENTA;
            putcolor(x,y,color);
            if (Targa_Out)
                targa_color(x, y, color);
        }
}


void _fastcall plot3dsuperimpose256(int x,int y,int color)
{
    int tmp;
    BYTE t_c;

    t_c = (BYTE)(255-color);

    if (color != 0)         /* Keeps index 0 still 0 */
    {
        color = colors - color; /*  Reverses color order */
        if (max_colors == 236)
        color = 1 + color / 21; /*  Maps colors 1-255 to 13 even ranges */
        else
        color = 1 + color / 18; /*  Maps colors 1-255 to 15 even ranges */
    }

    tmp = getcolor(x,y);
    /* map to 16 colors */
    if(whichimage == 1) /* RED */
    {
        if(red_local_left < x && x < red_local_right)
        {
            /* Overwrite prev Red don't mess w/blue */
            putcolor(x,y,color|(tmp&240));
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, color|(tmp&240));
                else
                    targa_writedisk (x+sxoffs, y+syoffs, t_c, 0, 0);
        }
    }
    else if(whichimage == 2) /* BLUE */
        if(blue_local_left < x && x < blue_local_right)
        {
            /* Overwrite previous blue, don't mess with existing red */
            color = color <<4;
            putcolor(x,y,color|(tmp&15));
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, color|(tmp&15));
                else
                {
                    targa_readdisk (x+sxoffs, y+syoffs, &T_RED, (BYTE *)&tmp, (BYTE *)&tmp);
                    targa_writedisk (x+sxoffs, y+syoffs, T_RED, 0, t_c);
                }
        }
}

void _fastcall plotIFS3dsuperimpose256(int x,int y,int color)
{
    int tmp;
    BYTE t_c;

    t_c = (BYTE)(255-color);

    if (color != 0)         /* Keeps index 0 still 0 */
    {
        /* my mind is fried - lower indices = darker colors is EASIER! */
        color = colors - color; /*  Reverses color order */
        if (max_colors == 236)
        color = 1 + color / 21; /*  Maps colors 1-255 to 13 even ranges */
        else
        color = 1 + color / 18; /*  Looks weird but maps colors 1-255 to 15
                    relatively even ranges */
    }

    tmp = getcolor(x,y);
    /* map to 16 colors */
    if(whichimage == 1) /* RED */
    {
        if(red_local_left < x && x < red_local_right)
        {
            putcolor(x,y,color|tmp);
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, color|tmp);
                else
                    targa_writedisk (x+sxoffs, y+syoffs, t_c, 0, 0);
        }
    }
    else if(whichimage == 2) /* BLUE */
        if(blue_local_left < x && x < blue_local_right)
        {
            color = color <<4;
            putcolor(x,y,color|tmp);
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, color|tmp);
                else
                {
                    targa_readdisk (x+sxoffs, y+syoffs, &T_RED, (BYTE *)&tmp, (BYTE *)&tmp);
                    targa_writedisk (x+sxoffs, y+syoffs, T_RED, 0, t_c);
                }
        }
}

void _fastcall plot3dalternate(int x,int y,int color)
{
    BYTE t_c;

    t_c = (BYTE)(255-color);
    /* lorez high color red/blue 3D plot function */
    /* if which image = 1, compresses color to lower 128 colors */

    /* my mind is STILL fried - lower indices = darker colors is EASIER! */
    color = colors - color;
    if((whichimage == 1) && !((x+y)&1)) /* - lower half palette */
    {
        if(red_local_left < x && x < red_local_right)
        {
            putcolor(x,y,color>>1);
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, color>>1);
                else
                    targa_writedisk (x+sxoffs, y+syoffs, t_c, 0, 0);
        }
    }
    else if((whichimage == 2) && ((x+y)&1) ) /* - upper half palette */
    {
        if(blue_local_left < x && x < blue_local_right)
        {
            putcolor(x,y,(color>>1)+(colors>>1));
            if (Targa_Out)
                if (!ILLUMINE)
                    targa_color(x, y, (color>>1)+(colors>>1));
                else
                    targa_writedisk (x+sxoffs, y+syoffs, T_RED, 0, t_c);
        }
    }
}

void _fastcall plot3dcrosseyedA(int x,int y,int color)
{
   x /= 2;
   y /= 2;
   if(whichimage == 2)
      x += xdots/2;
   if(rowcount >= ydots/2)
      /* hidden surface kludge */
      if(getcolor(x,y) != 0)
         return;
   putcolor(x,y,color);
}

void _fastcall plot3dcrosseyedB(int x,int y,int color)
{
   x /= 2;
   y /= 2;
   if(whichimage == 2)
      x += xdots/2;
   putcolor(x,y,color);
}

void _fastcall plot3dcrosseyedC(int x,int y,int color)
{
   if(rowcount >= ydots/2)
      /* hidden surface kludge */
      if(getcolor(x,y) != 0)
         return;
   putcolor(x,y,color);
}

void plot_setup()
{
    double d_red_bright  = 0;
    double d_blue_bright = 0;
    int i;

    /* set funny glasses plot function */
    switch(glassestype)
    {
    case 1:
        standardplot = plot3dalternate;
        break;

    case 2:
        if(colors == 256)
            if (fractype != IFS3D)
                standardplot = plot3dsuperimpose256;
            else
                standardplot = plotIFS3dsuperimpose256;
        else
            standardplot = plot3dsuperimpose16;
        break;

    case 4: /* crosseyed mode */
        if(sxdots < 2*xdots)
        {
           if(XROT == 0 && YROT == 0)
              standardplot = plot3dcrosseyedA; /* use hidden surface kludge */
           else
              standardplot = plot3dcrosseyedB;
        }
        else if(XROT == 0 && YROT == 0)
           standardplot = plot3dcrosseyedC; /* use hidden surface kludge */
        else
           standardplot = putcolor;
        break;

    default:
        standardplot = putcolor;
        break;
    }

    xshift1 = xshift = (int)((XSHIFT * (double)xdots)/100);
    yshift1 = yshift = (int)((YSHIFT * (double)ydots)/100);

    if(glassestype)
    {
        red_local_left  =   (int)((red_crop_left      * (double)xdots)/100.0);
        red_local_right =   (int)(((100 - red_crop_right) * (double)xdots)/100.0);
        blue_local_left =   (int)((blue_crop_left     * (double)xdots)/100.0);
        blue_local_right =  (int)(((100 - blue_crop_right) * (double)xdots)/100.0);
        d_red_bright    =   (double)red_bright/100.0;
        d_blue_bright   =   (double)blue_bright/100.0;

        switch(whichimage)
        {
        case 1:
            xshift  += (int)((eyeseparation* (double)xdots)/200);
            xxadjust = (int)(((xtrans+xadjust)* (double)xdots)/100);
            xshift1 -= (int)((eyeseparation* (double)xdots)/200);
            xxadjust1 = (int)(((xtrans-xadjust)* (double)xdots)/100);
            if(glassestype == 4 && sxdots >= 2*xdots)
               sxoffs = sxdots / 2 - xdots;
            break;

        case 2:
            xshift  -= (int)((eyeseparation* (double)xdots)/200);
            xxadjust = (int)(((xtrans-xadjust)* (double)xdots)/100);
            if(glassestype == 4 && sxdots >= 2*xdots)
               sxoffs = sxdots / 2;
            break;
        }
    }
    else
        xxadjust = (int)((xtrans* (double)xdots)/100);
    yyadjust = (int)(-(ytrans* (double)ydots)/100);

    if (mapset)
    {
        ValidateLuts(MAP_name); /* read the palette file */
        if(glassestype==1 || glassestype==2)
        {
            if(glassestype == 2 && colors < 256)
            {
                dacbox[PAL_RED  ][0] = 63;
                dacbox[PAL_RED  ][1] =  0;
                dacbox[PAL_RED  ][2] =  0;

                dacbox[PAL_BLUE ][0] =  0;
                dacbox[PAL_BLUE ][1] =  0;
                dacbox[PAL_BLUE ][2] = 63;

                dacbox[PAL_MAGENTA][0] = 63;
                dacbox[PAL_MAGENTA][1] =    0;
                dacbox[PAL_MAGENTA][2] = 63;
            }
            for (i=0;i<256;i++)
            {
                dacbox[i][0] = (BYTE)(dacbox[i][0] * d_red_bright);
                dacbox[i][2] = (BYTE)(dacbox[i][2] * d_blue_bright);
            }
        }
        spindac(0,1); /* load it, but don't spin */
    }
}

