/*************************************************************************
 ***                        POLYDEMO.C                   (JJB TEMPLAR) ***
 *** Date begun: 1/5/89.                                               ***
 *** Last modified: 2/5/89.                                            ***
 ***                3/5/89  -   added area pattern                     ***
 ***                4/5/89  -   added killWB, hid screen title (v1.1)  ***
 *************************************************************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <stdio.h>
#include <math.h>

#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>

#include "doublebuf.h"
#include "polygon.h"
#include "killWB.h"

#define RP  (currentRP)
#define ABS(a)  (((a) < 0) ? (-a):(a))

int     noWBcons = 1;

struct IntuitionBase    *IntuitionBase;
struct GfxBase          *GfxBase;

char    titlebar[] = "PolyDemo - JJB TEMPLAR";
struct Screen       *Screen;
struct Window       *Window;
struct NewScreen    NewScreen = {
    0,0,320,200,2,0,1,NULL,CUSTOMSCREEN,NULL,titlebar,NULL,NULL};
struct NewWindow    NewWindow = {
    0,0,320,200,0,1,RAWKEY,
    SMART_REFRESH|BACKDROP|ACTIVATE|BORDERLESS|RMBTRAP,
    NULL,NULL,titlebar,NULL,NULL,0,0,0,0,CUSTOMSCREEN};

/* As long as resets coords are OK, only need to get polyRAs pointers
 * correct. Just remember to call rotate() before drawing!
 */
edge    resetRA[12] = {
    {90,169,0,0,NULL},{229,169,0,0,NULL},
    {229,30,0,0,NULL},{90,30,0,0,NULL},
    {152,45,0,0,NULL},{167,45,0,0,NULL},
    {167,155,0,0,NULL},{152,155,0,0,NULL},
    {119,78,0,0,NULL},{200,78,0,0,NULL},
    {200,93,0,0,NULL},{119,93,0,0,NULL}};
edge    polyRA[12] = {
    {30,169,289,169,NULL},{289,169,289,30,&polyRA[0]},
    {289,30,30,30,&polyRA[1]},{30,30,30,169,&polyRA[2]},
    {30,169,289,169,NULL},{289,169,289,30,&polyRA[4]},
    {289,30,30,30,&polyRA[5]},{30,30,30,169,&polyRA[6]},
    {30,169,289,169,NULL},{289,169,289,30,&polyRA[8]},
    {289,30,30,30,&polyRA[9]},{30,30,30,169,&polyRA[10]}};
polygon polyp0 = {&polyRA[3]};
polygon polyp1 = {&polyRA[7]};
polygon polyp2 = {&polyRA[11]};
struct template template;
double  angle,angleinc;

UWORD   cmap[4] = {0x000,0x455,0x999,0x700};
UWORD   pattern[16] = {
    0xffff,0xffff,0xe1ff,0xfdff,0xfc3f,0xfdbf,0xfd8f,0xedb7,
    0xf3b7,0xfdaf,0xfe77,0xffb7,0xff87,0xffff,0xc003,0xffff};

int     cleanupcode = 5;    /* For double buffer abort */

void    dolibs();
void    dodisp();
void    subrotate();
void    rotate();
void    redraw();
void    cleanup(int);

void    dolibs() /*======================================================*/
{
    if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L))) {
        printf("ERROR: failed to open graphics.library!\n");
        cleanup(0);
    }
    if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L))) {
        printf("ERROR: failed to open intuition.library!\n");
        cleanup(1);
    }
}

void    dodisp() /*======================================================*/
{
    if (!(Screen = (struct Screen *)OpenScreen(&NewScreen))) {
        printf("ERROR: failed to open screen!\n");
        cleanup(2);
    }
    NewWindow.Screen = Screen;
    LoadRGB4(&Screen->ViewPort,cmap,16);
    if (!(Window = (struct Window *)OpenWindow(&NewWindow))) {
        printf("ERROR: failed to open window!\n");
        cleanup(3);
    }
    ShowTitle(Screen,0);        /* Hide screen title bar */
  /* Need to clean up title bar's appearance */
    SetAPen(Window->RPort,1);
    Move(Window->RPort,0,8);    Draw(Window->RPort,10,8); /* Skip y tail */
    Move(Window->RPort,100,8);  Draw(Window->RPort,319,8);
    Move(Window->RPort,0,9);    Draw(Window->RPort,319,9);
}

void    subrotate(xp,yp) /*==============================================*/
double  *xp,*yp;
{
double  x,y,ix,iy;
    x = *xp;    y = *yp;    x -= 159.5;     y -= 99.5;
    ix = (x * cos(angle)) - (y * sin(angle));
    iy = (x * sin(angle)) + (y * cos(angle));
    ix += 159.5;    iy += 99.5;
    *xp = ix;       *yp = iy;
}

void    rotate() /*======================================================*/
{
double  x,y;
register int    i,j;

    for (j = 0; j < 12; j++) {
        x = (double)resetRA[j].start[0];
        y = (double)resetRA[j].start[1];
        subrotate(&x,&y);
        polyRA[j].start[0] = (short)x;
        polyRA[j].start[1] = (short)y;
    }

    angle += angleinc;

    for (i = 0; i < 12; i += 4) {
        for (j = 0; j < 3; j++) {
            polyRA[i+j].end[0] = polyRA[i+j+1].start[0];
            polyRA[i+j].end[1] = polyRA[i+j+1].start[1];
        }
        polyRA[i+3].end[0] = polyRA[i].start[0];
        polyRA[i+3].end[1] = polyRA[i].start[1];
    }
}

void    redraw() /*======================================================*/
{
register int    x1,x2,y1,y2;
    x1 = template.cliplo[0]-1;      x2 = template.cliphi[0]+1;
    y1 = template.cliplo[1]-1;      y2 = template.cliphi[1]+1;

    SetAPen(currentRP,0);
    RectFill(currentRP,0,11,319,199);
    SetAPen(currentRP,3);       Move(currentRP,x1,y1);
    Draw(currentRP,x2,y1);      Draw(currentRP,x2,y2);
    Draw(currentRP,x1,y2);      Draw(currentRP,x1,y1);
    datachange = 1;
}

void    main(argc,argv) /*===============================================*/
int     argc;
char    *argv[];
{
struct IntuiMessage *msg;
struct Task *me;
int     loop = 1,size = 1;
char    oldpri;

    if ((argc > 1) && (argv[1][0] == '?')) {
        printf("PolyDemo v1.1 - 4/5/89 - JJB TEMPLAR.\n");
        printf("Just type %s !\n",argv[0]);
        printf("Controls: ESC - terminate,      CSR UP - inc rect   CSR DN - dec rect,\n");
        printf("          CSR LF - turn left,   CSR RT, turn right,\n");
        printf("          NUM + - faster,       NUM - - slower.\n");
        cleanup(-1);
    }

    killWB(1);          /* Turn on Commodore N,M interception */

    dolibs();
    dodisp();

    if (!(template.plane = (unsigned short *)AllocMem(8000,MEMF_CHIP))) {
        printf("ERROR: failed to allocate chip memory!\n");
        cleanup(4);
    }

    me = (struct Task *)FindTask(NULL);
    oldpri = me->tc_Node.ln_Pri;
    SetTaskPri(me,15);

    template.tmodulo = 20;
    template.m1 = 5;    template.m2 = 3;        /* 32 + 8 */
    template.cliplo[0] = 1;     template.cliphi[0] = 318;
    template.cliplo[1] = 12;    template.cliphi[1] = 198;

    doscreenbuf(1);
    equalview();
    SetAfPt(currentRP,pattern,4);
    swapview();
    SetAfPt(currentRP,pattern,4);

    redraw();

    angle = 2 * PI;
    angleinc = PI / 36.0;

    while (loop) {
        rotate();
        SetAPen(RP,1);
        RectFill(RP,template.cliplo[0],template.cliplo[1],template.cliphi[0],template.cliphi[1]);
        SetAPen(RP,2);
        scanpoly(&template,RP,&polyp0);
        SetAPen(RP,3);
        scanpoly(&template,RP,&polyp1);
        scanpoly(&template,RP,&polyp2);
        swapview();
        while (msg = (struct IntuiMessage *)GetMsg(Window->UserPort)) {
            if (msg->Class == RAWKEY) {
                switch (msg->Code) {
                    case (0x45): loop = 0;  break;
                    case (0x4d): if (size < 18) {
                                    size++;
                                    template.cliplo[0] += 8;
                                    template.cliplo[1] += 5;
                                    template.cliphi[0] -= 8;
                                    template.cliphi[1] -= 5;
                                    redraw();
                                 }
                                 break;
                    case (0x4c): if (size > 1) {
                                    size--;
                                    template.cliplo[0] -= 8;
                                    template.cliplo[1] -= 5;
                                    template.cliphi[0] += 8;
                                    template.cliphi[1] += 5;
                                    redraw();
                                 }
                                 break;
                    case (0x4f): if (angleinc > 0.0) angleinc = -angleinc;
                                 break;
                    case (0x4e): if (angleinc < 0.0) angleinc = -angleinc;
                                 break;
                    case (0x5e): if (angleinc > 0.0) angleinc += PI/36.0;
                                 else angleinc -= PI/36.0;
                                 break;
                    case (0x4a): if (ABS(angleinc) <= PI/36.0) break;
                                 if (angleinc > 0.0) angleinc -= PI/36.0;
                                 else angleinc += PI/36.0;
                                 break;
                }
            }
            ReplyMsg((struct Message *)msg);
        }
    }
    SetTaskPri(me,oldpri);

    cleanup(6);
}

void    cleanup(bra) /*=================================================*/
int     bra;
{
    switch (bra) {
        case (6): doscreenbuf(0);
        case (5): FreeMem((UBYTE *)(template.plane),8000);
        case (4): CloseWindow(Window);
        case (3): CloseScreen(Screen);
        case (2): CloseLibrary(IntuitionBase);
        case (1): CloseLibrary(GfxBase);
        case (0): killWB(0);        /* Must remove handler */
        case (-1): break;
    }
    exit(0);
}
