/* Copyright 1991 by Michael Jansson, All rights reserved.

 NAME:  Spiral 
 USAGE: Spiral <font name> <text string>
 VERSION: 1.0

This is a small program that will display a text file in a corkscrew
fashion. It is a typical example of the use of the vfont.library functions:  
OpenVFont, ChangeVFont, VText, Rotate, SetVFont, FixToInt etc.

The program opens a screen and prints a file, character by character.
The font is never bitmap cached since that font has to be re-mapped, 
i.e. re-calculated to reflect a new size and orientation, after
each character.

*/


#include <intuition/intuition.h>
#include <intuition/screens.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <pragmas/dos.h>
#include <pragmas/exec.h>
#include <pragmas/intuition.h>
#include <pragmas/graphics.h>
#include <vfont/curve.h>
#include <vfont/vfont.h>
#include <clib/vfontlib.pro>
#include <pragmas/vfontlib.pra>
#include <math.h>
#include <stdio.h>
#include <time.h>


/* Some constans. */
#define Deg10   0.174532925
#define FIXPI   205887L
#define TWO_PI	((double)	3.141592653589793))*2.0

/* Some macros. (It's done this way to improve the readability of the code). */
#define RotateFont(font, angle, height)     {VFont req; req.YSize = height; req.XSize = 0; req.AlfaPath = req.UpVector = (FIX)(FIXOFFSET*angle)-FIXPI; ChangeVFont(font, (UBYTE)(VCM_PATH|VCM_UP|VCM_SIZE), &req, (long)FALSE);}
#define MyPutS(str)     Write(Output(), str "\n", (long)strlen(str)+1L)


/* This is the paramater that is used when the font is opened.
   It is very similar to the intuition.library structure TextAttr.
   The TextAttr is distinguished from a TextVAttr (notice the 
   extra "V" in the name) by the one bit flag  VectorFont, which
   corresponds to the sign bit of the ta_YSize field of the TextAttr 
   structure. You may use a plain TextAttr if you are satisfied with
   the default values for the vector font exxtension of the structure
   when you open a font with the OpenVFont function.

   The width or the height may be set to zero to indicate that you
   want the default width or height. The library will then set it so 
   that the proportions will be preseved, e.g. a 32x16 large font class
   opened as a 64x0 large font will be set to be 64x32.
*/
TextVAttr tattr = {
    (UBYTE *)"vwire.font",   /* The name of the class. */
    32,                         /* The height */
    1,                          /* It is a vector font. */
    FS_NORMAL,                  /* The style. */
    FPF_DESIGNED|FPF_DISKFONT,  /* The flags. */
    (UBYTE *)"John",            /* Our name for this font. */
    0,                          /* Use default width. */
/* 
    The next field in this structure is VFlags. It is used to control
    the way the vfont library is managing the desired font. The possible 
    bits are the same that are used by other functions than the OpenVFont
    function. The followilg flags may be used:

    Name                Meaning
    ====                =======
    VFB_MUTE            NOT VNB_DEBUG and NOT VFB_VERBOSE
    VFB_DEBUG           Used for debuging purpose. It will trace all 
                        function calls in the vfont lmbrary on the 
                        serial port. It is not usefull nor recomended
                        use this flag.
    VFB_VERBOSE         Alert the user through a requester when errors
                        occurs. Usefull for small programs that don't
                        want to deal with a lot of user interface stuff.
    VFB_FLUSHCLASS      Indicates that un-used font classes should be 
                        purged from the library. Used by the FlushWhat
                        function.
    VFB_FLUSHFONTS      Same as VFB_FLUSHCLASS, but for font instances. 
                        Note that a lacked font (instance) or a locked 
                        class can not be flushed.
    VFB_MAPPED          Used internally (keep your hands off this bit).
    VFB_EXCLUSIVE       Indicates that font for exlusive use is desired.
                        Opening a non-exlusive font means that it may be 
                        re-used by other clients (programs, task etc). 
                        Changes done to a non-exclusive font affects all 
                        clients since they all use the same font instance.
    VFB_FORCED          Exlusive fonts can be re-opened if this flag is 
                        used. You should have a good reason for re-opening
                        other clients exlusive fonts.
    VFB_NOCONVERT       The library will attempt to build the desired font
                        from what ever class that is available, unless
                        this flag is used.
    VFB_ANYSIZE         The library will look for a class that has exactly
                        the same size as desired, unless this flags is used.
    VFB_NOBITCACHE      A bitmap cache will be devoted to the opened font, 
                        unless this font is used.
*/

    VFB_VERBOSE |               /* Let the library inform the user when error occures. */
    VFB_EXCLUSIVE |             /* Don't let others use the font. */
    VFB_NOBITCACHE |            /* Don't use the bitmap cache. */
    VFB_ANYSIZE                 /* It is okay to load a class at any size. */
};


/* Some intuition structure that is used when opening a screen. */
#define ProgramName (UBYTE *)"Spiral v1.0 - Copyright 1991 by Michael Jansson"
#define width 640L
#define height 512L			/* Change this to 400 for NTSC. */

struct NewScreen newscreen = {
    0,0,width,height,1,         /* Screen dimensions. */
    0,-1,                       /* Pen colors. */
    LACE|HIRES,                 /* View modes. */
    CUSTOMSCREEN,               /* Screen type. */
    NULL,                       /* Default screen font (none). */
    ProgramName,                /* Screen title. */
    NULL,                       /* Gadgets (none). */
    NULL                        /* CustomBitMap (none). */
};

/* Library names. */
#define INTUITION   (UBYTE *)"intuition.library"
#define GRAPHICS    (UBYTE *)"graphics.library"
#define VFONTS      (UBYTE *)"vfont.library"

#define AREABUFFSIZE 1000L
#define AREABUFFSIZE5 5000L

/* Global data. */
UBYTE myBuffer[AREABUFFSIZE5];
struct AreaInfo myArea;
struct TmpRas myTmpRas;
struct NewScreen newscreen;

/* Global data that is allocated/opened. */
struct Library *IntuitionBase = NULL;
struct Library *vFontBase = NULL;
struct Library *GfxBase = NULL;
struct Screen *screen = NULL;
PLANEPTR myPlane = NULL;
UBYTE *buffer = NULL;
VFont *font = NULL;
BPTR file = 0L;
long size = 0;


/*
    This is the function that will release the allocated resources.
*/
void
_abort(void)
{
    if (file)
        Close(file);
	if (buffer)
		FreeMem(buffer, size);
    if (font)
   	    CloseVFont(font);
	if (myPlane)
		FreeRaster(myPlane, width, height);
	if (screen)
		CloseScreen(screen);
    if (vFontBase)
        CloseLibrary(vFontBase);
    if (IntuitionBase)
        CloseLibrary(IntuitionBase);
    if (GfxBase)
        CloseLibrary(GfxBase);
    exit(0L);
}


/*
        The main part of the program.
*/
void
main(int argc, UBYTE **argv)
{
	struct RastPort *RPort;
    double angle = 0.0;
    FIX radius = IntToFix(3);
    LONG t1[3], t2[3];
    Point pos;
    int i = 0;

    /* Process the CLI parameters. */
    if (argc<2) {
        MyPutS("Usage: spiral font file");
        MyPutS("Example: spiral emerald hakdic.txt");
        return;
    }

    /* Open the file. */
    if ((file = Open((UBYTE *)argv[2], (long)MODE_OLDFILE))==NULL) {
        MyPutS("Can't open the that file.");
        _abort();
    }

    /* Check the size of the file. */
    Seek(file, 0L, (long)OFFSET_END);
    size = Seek(file, 0L, (long)OFFSET_BEGINNING);

    /* Allocate a buffer that will fit the whole file. */
    if (!(buffer=AllocMem(size, 0L))) {
        MyPutS("That file is to big to be loaded all at once!");
        _abort();
    }

    /* Read the file into the buffer. */
    if (size!=Read(file, buffer, size)) {
        MyPutS("DOS error while reading file.");
        _abort();
    }
    MyPutS("Text file loaded!");
    Close(file);
    file = 0L;

    /* Set up the requirements for the font. */
    tattr.Name = (UBYTE *)argv[1];

    /* Open the needed libraries. */
    if (!(IntuitionBase = OpenLibrary(INTUITION, 0L))
    || !(GfxBase = OpenLibrary(GRAPHICS, 0L))
    || !(vFontBase = OpenLibrary(VFONTS, 0L))) {
        MyPutS("Can't open the vfont libarary.");
        _abort();
    }

    /* Book keep the starting time. */
    DateStamp(t1);

    /* Open the font. */
    if ((font = OpenVFont(&tattr))==NULL) {
        MyPutS("Didn't manage to load the font.");
        _abort();
    }

    DateStamp(t2);
    printf("Time to load the font: %ld msec\n",(long)(t2[2]-t1[2])*20);

    /* Open a screen. */
    if (!(screen = OpenScreen(&newscreen))) {
        MyPutS("Couldn't open screen.");
        _abort();
    }
	RPort = &screen->RastPort;
    SetDrMd(RPort, (long)JAM1);

	/* Add a TmpRas. */
	if (!(myPlane=AllocRaster(width, height)))
		_abort();
	InitTmpRas(&myTmpRas, myPlane, (long)RASSIZE(width, height));
	RPort->TmpRas = &myTmpRas;

	/* Add a AreaInfo. */
	InitArea(&myArea, myBuffer, AREABUFFSIZE);
	RPort->AreaInfo = &myArea;

    SetVFont(RPort, font);
    ScreenToFront(screen);

    /* Book keep the time. */
    DateStamp(t1);

    /* Do the rendering. */
    while (i<size) {

        /* Clear the screen if we are reaching the edges of the screen. */
        if ((FixToInt(radius)+font->YSize)>(screen->Height/2)) {
            radius = IntToFix(3);
            angle = 0.0;
            SetRast(RPort, 0L);
        }
        radius = radius*101/100;
        angle += Deg10;
        pos.x = 0;
        pos.y = FixToInt(radius);
        Rotate(&pos, 1L, FloatToFix(sin(angle)), FloatToFix(cos(angle)), 0, 0);
        RotateFont(font, angle, FixToInt(radius)/5+2);
        Move(RPort, (long)(pos.x+screen->Width/2), (long)(pos.y+screen->Height/2));
        VText(RPort, &buffer[i++], 1L);
        Chk_Abort();
    }

    /* Report the elapsed time. */
    DateStamp(t2);
    printf("Chars/sec %ld\n",(long)size/((t2[1]-t1[1])*60+(t2[2]-t1[2])/50));

	_abort();
}
