/*
 * Graphics support for Edinburgh ML.
 *
 * This is at least some sort of a start, intended for use under Windows.
 * see also "flatlib.sml" for associated high-level code.
 *
 *                                                         A C Norman 1994
 */
 
   
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <float.h>

#ifndef transputer
#   include <signal.h>
#endif

#include "globdefs.h"
#include "structs.h"
#include "globvars.h"
#include "io.h"
#include "bcodes.h"
#include "debug.h"

#ifdef __STDC__
#  include <stdlib.h>
#  include <errno.h>
#else
#  include <errno.h>
   extern int errno;
#endif

#ifdef sun
#  define locreg_
#else
#ifdef transputer
   /* BEWARE this next move - it makes all local vars in the fam into
      statics in the transputer, so that the C stack can fit into the
      on-chip RAM. So: NEVER say something like "locreg_ i = 42;"
      anywhere, since this will break things. */
#  define locreg_ static
#else
#  define locreg_ register
#endif
#endif

#define push(a)     *--FAM_AP = (a)
#define push2(a,b)  *--FAM_AP = (a), *--FAM_AP = (b)
#define pop(a)      (a) = *FAM_AP++
#define pop2(a,b)   (a) = *FAM_AP++, (b) = *FAM_AP++;

typedef double transform[3][3];

void mxmul(transform a, transform b, transform c)
{
    int i, k, j;
    for (i=0; i<3; i++)
        for (j=0; j<3; j++)
        {   double r = 0;
            for (k=0; k<3; k++) r += a[i][k] * b[k][j];
            c[i][j] = r;
        }
}

#define Field_(x)  (((Variant *)x) -> field)

#define _pi 3.141592653589793238

#ifndef CWIN

char page[25][50];

void clearpage()
{
    int i, j;
    for (i=0; i<25; i++)
        for (j=0; j<50; j++) page[i][j] = ' ';
}

void showpage()
{
    int i, j;
    putchar('\n');
    for (i=0; i<25; i++)
    {   for (j=0; j<50; j++) putchar(page[i][j]);
        putchar('\n');
    }
}

int charfor(unsigned colour)
{
    if (colour == 0) return '*';
    else return 'a' + (colour % 23);
}

#endif

void printPlot(LWord a, transform c, unsigned colour)
{
    LWord w, w1, w2;
    double x, y, z, x1;
    int r, g, b, i, j;
    transform c1, c2;
    switch (PreField_(a))
/*
 * It is vital to keep the codes here in step with the order used in the
 * definition of the "picture" ADT in "flatlib.sml"
 */
    {
/*              circle r          circle: radius r, origin at centre */
case 0:
        w = Field_(a);
        z = real_(w);
#ifdef CWIN
        cwin_circle(colour & 0x7fffffff, z, c);
#else
        b = charfor(colour);
        for (i=0; i<360; i++)
        {   x = _pi*(double)i/180.0;
            y = z * sin(x);
            x = z * cos(x);
            x1 = c[0][0]*x + c[0][1]*y + c[0][2];
            y  = c[1][0]*x + c[1][1]*y + c[1][2];
            x = x1;
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
        }
#endif
        break;

/*              square x          square: side x, origin in middle   */
case 1:
        w = Field_(a);
        z = real_(w);
#ifdef CWIN
        cwin_square(colour & 0x7fffffff, z, c);
#else
        z = z / 2.0;
        b = charfor(colour);
        for (i=-50; i<=50; i++)
        {   x1 = z*(double)i/50.0;
            x  = c[0][0]*x1 + c[0][1]*z + c[0][2];
            y  = c[1][0]*x1 + c[1][1]*z + c[1][2];
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
            x  = c[0][0]*x1 - c[0][1]*z + c[0][2];
            y  = c[1][0]*x1 - c[1][1]*z + c[1][2];
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
            x  = c[0][0]*z + c[0][1]*x1 + c[0][2];
            y  = c[1][0]*z + c[1][1]*x1 + c[1][2];
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
            x  = -c[0][0]*z + c[0][1]*x1 + c[0][2];
            y  = -c[1][0]*z + c[1][1]*x1 + c[1][2];
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
        }
#endif
        break;

/*              paint(c, p)       force colour of entire sub-object  */
case 2:
/*
 * If an enclosing PAINT has set a colour then I ignore this one, so that
 * I get the effect that the outer paint over-rides the inner one.
 */
        if ((colour & 0x80000000) == 0)
        {   w = Field_(a);
            printPlot(rec_(w)[1], c, colour);
        }
        else
        {   w = Field_(a);
            w1 = rec_(w)[0];
            r = cint_(rec_(w1)[0]) & 0xff;
            g = cint_(rec_(w1)[1]) & 0xff;
            b = cint_(rec_(w1)[2]) & 0xff;
            printPlot(rec_(w)[1], c, (b << 16) | (g << 8) | r);
        }
        break;

/*              scale(r, p)       multiply size of object by r       */
case 3:
        w = Field_(a);
        x = real_(rec_(w)[0]);
        for (i=0; i<3; i++)
            for (j=0; j<3; j++)
                c1[i][j] = (i == j) ? 1.0 : 0.0;
        c1[0][0] = x;
        c1[1][1] = x;
        mxmul(c, c1, c2);
        printPlot(rec_(w)[1], c2, colour);
        break;

/*              scalex(r, p)      multiply size in x direction only  */
case 4:
        w = Field_(a);
        x = real_(rec_(w)[0]);
        for (i=0; i<3; i++)
            for (j=0; j<3; j++)
                c1[i][j] = (i == j) ? 1.0 : 0.0;
        c1[0][0] = x;
        mxmul(c, c1, c2);
        printPlot(rec_(w)[1], c2, colour);
        break;

/*              rotate(a, p)      rotate a (degrees, clockwise)      */
case 5:
        w = Field_(a);
        x = real_(rec_(w)[0]);
         x = x * _pi / 180.0;
        y = sin(x);
        x = cos(x);
        for (i=0; i<3; i++)
            for (j=0; j<3; j++)
                c1[i][j] = (i == j) ? 1.0 : 0.0;
        c1[0][0] = x; c1[0][1] = -y;
        c1[1][0] = y; c1[1][1] = x;
        mxmul(c, c1, c2);
        printPlot(rec_(w)[1], c2, colour);
        break;

/*              shift(x, y, p)    translate object by (x, y)         */
case 6:
        w = Field_(a);
        x = real_(rec_(w)[0]);
        y = real_(rec_(w)[1]);
        for (i=0; i<3; i++)
            for (j=0; j<3; j++)
                c1[i][j] = (i == j) ? 1.0 : 0.0;
        c1[0][2] = x;
        c1[1][2] = -y;
        mxmul(c, c1, c2);
        printPlot(rec_(w)[2], c2, colour);
        break;

/*              add(p1, p2)       form composite picture             */
case 7:
        w = Field_(a);
        printPlot(rec_(w)[0], c, colour);
        printPlot(rec_(w)[1], c, colour);
        break;

/*              nullpic           Does not display anything!         */
case 8:
        break;

/*              point             A single, isolated point           */
case 9:
#ifdef CWIN
        cwin_point(colour & 0x7fffffff, c);
#else
        b = charfor(colour);
        x = c[0][2];
        y = c[1][2];
        r = 12 - (int)(5.0*y);
        g = 25 + (int)(10.0*x);
        if (0 <= r && r < 25 &&
            0 <= g && g < 50) page[r][g] = b;
#endif
        break;

/*              line(x)           Horizontal line, length x, centred */
case 10:
        w = Field_(a);
        z = real_(w);
#ifdef CWIN
        cwin_line(colour & 0x7fffffff, z, c);
#else
        b = charfor(colour);
        for (i=-50; i<=50; i++)
        {   x = z * (double)i/100.0;
            x1 = c[0][0]*x + c[0][2];
            y  = c[1][0]*x + c[1][2];
            x = x1;
            r = 12 - (int)(5.0*y);
            g = 25 + (int)(10.0*x);
            if (0 <= r && r < 25 &&
                0 <= g && g < 50) page[r][g] = b;
        }
#endif
        break;
    }
    return;
}

void printADT(LWord a)
{
    if (!Immed_(a) && Tag_(a) == TagPlot)
    {   transform c;
        int i, j;
        for (i=0; i<3; i++)
            for (j=0; j<3; j++)
                c[i][j] = (i == j) ? 1.0 : 0.0;
#ifdef CWIN
        cwin_clear();
#else
        clearpage();
#endif
        printPlot(a, c, 0x80000000);
#ifdef CWIN
        printf("<Picture>");
        cwin_show();
#else
        showpage();
#endif
    }
    else printf("-");  /* Previous dull behaviour */
}

/* end of "plot.c" */

