/*
*/

#define WWIDTH 320
#define WHEIGHT 240

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/interfaces.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>

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


#define fsqr(x) pow(x,2)
#define min(x,y) x<y ? x : y

// Libraries
struct Library *IntuitionBase = NULL;
struct Library *P96Base = NULL;
struct Library *GfxBase = NULL;

// Interfaces
struct IntuitionIFace *IIntuition;
struct P96IFace *IP96;
struct GraphicsIFace *IGraphics;
//struct ExecIFace *IExec;
//struct DOSIFace *IDOS;

struct Window *win = NULL;
struct Screen *scr = NULL;
struct BitMap *bm = NULL;

struct RenderInfo rinf;

int *roots;


/*
** A small routine to open a library and get its default
** interface, and report errors if anything fails.
*/
BOOL getLibIFace( struct Library **libbase, char *libname, int version, struct Interface **ifaceptr )
{
  *libbase = IExec->OpenLibrary( libname, version );
  if( *libbase == NULL )
  {
    printf( "Unable to open '%s' version %d\n", libname, version );
    return FALSE;
  }
  *ifaceptr = IExec->GetInterface( *libbase, "main", 1, NULL );
  if( *ifaceptr == NULL )
  {
    printf( "Unable to get the main interface for '%s'\n", libname );
    return FALSE;
  }
  return TRUE;
}

BOOL init( void )
{
  BPTR h;
  float i;
  int n;
  ULONG mode;

 // if( !getLibIFace( (struct Library **)&IntuitionBase, "intuition.library", 50, (struct Interface **)&IIntuition ) ) return FALSE;
  IntuitionBase = IExec->OpenLibrary("intuition.library",50L);
  IIntuition = (struct IntuitionIFace *) IExec->GetInterface (IntuitionBase,"main",1,NULL);

 //  if( !getLibIFace( (struct Library **)&GfxBase, "graphics.library", 48, (struct Interface **)&IGraphics ) ) return FALSE;
  GfxBase = IExec->OpenLibrary("graphics.library",48L);
  IGraphics = (struct GraphicsIFace *) IExec->GetInterface (GfxBase, "main",1,NULL);


 // if( !getLibIFace( &P96Base, "Picasso96API.library", 2, (struct Interface **)&IP96 ) ) return FALSE;
  P96Base = IExec->OpenLibrary("Picasso96API.library",2L);
  IP96 = (struct P96IFace *) IExec->GetInterface (P96Base,"main",1,NULL);




/*
**  mode = IP96->p96RequestModeIDTags( P96MA_MinWidth, WWIDTH,
**                               P96MA_MinHeight, WHEIGHT,
**                               TAG_DONE );
**  if( !mode ) return FALSE;
**
*/

  bm = IP96->p96AllocBitMap( WWIDTH, WHEIGHT, 24, 0, NULL, RGBFB_R8G8B8 );
  if( !bm ) return FALSE;

  //roots = IExec->AllocVec( WWIDTH*WWIDTH*2*sizeof( int ), MEMF_ANY );

  roots = (int *)IExec->AllocVec( WWIDTH*WWIDTH*2*sizeof( int ), MEMF_ANY );
  if( !roots ) return FALSE;

  for( i=0; i<WWIDTH*WWIDTH*2; i++ )
  {
    n = 265 - (int)sqrt( i );
//    n = 10 + (int)sqrt( i );
    if( n > 255 ) n = 255;
    if( n < 0 ) n = 0;
    roots[(int)i] = n;
  }

/*
**  scr = IIntuition->OpenScreenTags( NULL,
**              SA_DisplayID, mode,
**              SA_Depth,     24,
**              SA_ShowTitle, FALSE,
**              TAG_DONE );
**  if( !scr ) return FALSE;
**
**  win = IIntuition->OpenWindowTags( NULL,
**              WA_Left,         0,
**              WA_Top,          0,
**              WA_InnerWidth,  WWIDTH,
**              WA_InnerHeight, WHEIGHT,
**              WA_Backdrop,    TRUE,
**              WA_Borderless,  TRUE,
**              WA_CustomScreen, scr,
**              WA_Activate,    TRUE,
**              WA_IDCMP,       IDCMP_RAWKEY,
**              TAG_DONE );
**  if( !win ) return FALSE;
*/

  win = IIntuition->OpenWindowTags( NULL,
              WA_Left,         28,
              WA_Top,          28,
              WA_InnerWidth,  WWIDTH,
              WA_InnerHeight, WHEIGHT,
              WA_Title,       "Ooooh!",
              WA_ScreenTitle, "Lights by Peter Gordon (pete@shagged.org)",
              WA_DragBar,     TRUE,
              WA_CloseGadget, TRUE,
              WA_DepthGadget, TRUE,
              WA_Activate,    TRUE,
              WA_IDCMP,       IDCMP_RAWKEY|IDCMP_CLOSEWINDOW,
              TAG_DONE );
  if( !win ) return FALSE;

  return TRUE;
}

void shutdown( void )
{
  if( win ) IIntuition->CloseWindow( win );
//  if( scr ) IIntuition->CloseScreen( scr );
  if( roots ) IExec->FreeVec( roots );
  if( bm ) IP96->p96FreeBitMap( bm );
  if( P96Base ) IExec->CloseLibrary( P96Base );
  if( GfxBase ) IExec->CloseLibrary( (struct Library *)GfxBase );
  if( IntuitionBase ) IExec->CloseLibrary( (struct Library *)IntuitionBase );
}

void light( int lx, int ly, int cr, int cg, int cb )
{
  int x,y,c,dx,dy;
  UBYTE *bptr;

  bptr = (UBYTE *)rinf.Memory;

  for( y=0; y<WHEIGHT; y++ )
    for( x=0; x<WWIDTH; x++ )
    {
      dx = lx - x;
      dy = ly - y;
      c = roots[dx*dx+dy*dy];
      *(bptr++) = c>>cr;
      *(bptr++) = c>>cg;
      *(bptr++) = c>>cb;
    }
}

void light_mix( int lx, int ly, int cr, int cg, int cb )
{
  int x,y,c,dx,dy,mc;
  UBYTE *bptr;

  bptr = (UBYTE *)rinf.Memory;

  for( y=0; y<WHEIGHT; y++ )
    for( x=0; x<WWIDTH; x++ )
    {
      dx = lx - x;
      dy = ly - y;
      c = roots[dx*dx+dy*dy];

      mc = *bptr + (c>>cr);
      if( mc > 255 ) mc = 255;
      *(bptr++) = mc;
      mc = *bptr + (c>>cg);
      if( mc > 255 ) mc = 255;
      *(bptr++) = mc;
      mc = *bptr + (c>>cb);
      if( mc > 255 ) mc = 255;
      *(bptr++) = mc;
    }
}

int main( void )
{
  if( init() )
  {
    BOOL done = FALSE;
    ULONG wsig, sigs, lock;
    struct IntuiMessage *msg;
    int x1, y1, x2, y2, x3, y3;
    float c;

    wsig = (1L<<win->UserPort->mp_SigBit);

    while( !done )
    {
      IGraphics->WaitTOF();
      IGraphics->WaitTOF();

      x1 = (int)(sin(c)*120)+160;
      y1 = (int)(cos(c*2.4)*120)+120;
      x2 = (int)(sin(c*3)*120)+160;
      y2 = (int)(cos(-c)*120)+120;
      x3 = (int)(sin(c*-2.9)*120)+160;
      y3 = (int)(cos(c*1.2)*120)+120;

      c += 0.02;

      lock = IP96->p96LockBitMap( bm, (UBYTE *)&rinf, (ULONG)sizeof( struct RenderInfo ) );
      if( lock )
      {
        light(     x1, y1, 0, 2, 2 );
        light_mix( x2, y2, 2, 2, 0 );
        light_mix( x3, y3, 2, 0, 2 );

        IP96->p96UnlockBitMap( bm, lock );
      }

      IGraphics->BltBitMapRastPort( bm, 0, 0, win->RPort, win->BorderLeft, win->BorderTop, WWIDTH, WHEIGHT, 0x0C0 );
      sigs = IExec->SetSignal( 0L, 0L );

      if( sigs & SIGBREAKF_CTRL_C ) done = TRUE;
      if( sigs & wsig )
      {
        while( msg = (struct IntuiMessage *)IExec->GetMsg( win->UserPort ) )
        {
          done = TRUE;
          IExec->ReplyMsg( (struct Message *)msg );
        }
      }
    }
  }

  shutdown();
  return 0;
}
