/*
 *  Copyright (c) 1995 Andreas Schmitz
 *  All rights reserved.
 *
 *  This is a blanker-module for Garshne-Blanker 3.6
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>
#include <intuition/intuition.h>
#include <intuition/screens.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/intuition_protos.h>

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

#include "/includes.h"

#define WHEEL   0
#define SCRMODE 2

#define PUNKTE 25751

#include "Circles_rev.h"
STATIC const UBYTE VersTag[] = VERSTAG;

VOID Defaults( PrefObject *Prefs )
{
   Prefs[WHEEL].po_Active = 1;
	Prefs[SCRMODE].po_Depth = 4;
}

/* Funktionen um Werte-Tabelle zu erstellen */

int radi(UBYTE a[],int i)
{
   return(a[2*i]*a[2*i]+a[2*i+1]*a[2*i+1]);
}

void quicksort(WORD a[], int l, int r)
{
    int v, i, j;

    WORD farbe1,farbe2,t;

    if (r>l) {

        v=radi((UBYTE *)a,r);
        i=l-1;
        j=r;
        while (1) {

            do {
               i++;
               farbe1=a[i];
            } while (radi((UBYTE *)a,i)<v);

            do {
               j--;
               farbe2=a[j];
            } while (radi((UBYTE *)a,j)>v);

            if (i>=j) break;

            a[i]=farbe2;
            a[j]=farbe1;
        }

        t=a[i];
        a[i]=a[r];
        a[r]=t;

        quicksort(a, l, i-1);
        quicksort(a, i+1, r);

    }
}

void CreateTab(UBYTE *tabelle)
{
   int x,y,anzahl;

   anzahl=0;
   for (x=0;x<255;x++) {
      tabelle[2*anzahl]=(UBYTE)(x+1);
      tabelle[2*anzahl+1]=(UBYTE)(0);
      anzahl++;
      for (y=1;y<=x;y++) {
         if (x*x+y*y<=255*255) {
            tabelle[2*anzahl]=(UBYTE)x;
            tabelle[2*anzahl+1]=(UBYTE)y;
            anzahl++;
         }
      }
   }
   quicksort((WORD *)tabelle,0,anzahl-1);
}

/* Kreis so gross wie es geht zeichnen (auf Farbe 0) */
int kreis_expand1(UBYTE *tabelle,struct RastPort *rp,int cx,int cy)
{
   int i,x,y,back;

   if (ReadPixel(rp,cx,cy)!=0) return(FAILED);
   WritePixel(rp,cx,cy);

   for (i=0;i<PUNKTE;i++) {
      if (i%700==10) {
         if (ContinueBlanking()!=OK) return(UNBLANK);
      }
      x=tabelle[i*2];
      y=tabelle[i*2+1];
      if (y==0) {
         back=ReadPixel(rp,cx+x,cy)+ReadPixel(rp,cx-x,cy);
         if (back>0) break;
         back=ReadPixel(rp,cx,cy+x)+ReadPixel(rp,cx,cy-x);
         if (back>0) break;
         WritePixel(rp,cx+x,cy);
         WritePixel(rp,cx-x,cy);
         WritePixel(rp,cx,cy+x);
         WritePixel(rp,cx,cy-x);
         continue;
      }
      if (x==y) {
         back=ReadPixel(rp,cx+x,cy+y)+ReadPixel(rp,cx+x,cy-y);
         if (back>0) break;
         back=ReadPixel(rp,cx-x,cy+y)+ReadPixel(rp,cx-x,cy-y);
         if (back>0) break;
         WritePixel(rp,cx+x,cy+y);
         WritePixel(rp,cx+x,cy-y);
         WritePixel(rp,cx-x,cy+y);
         WritePixel(rp,cx-x,cy-y);
      }
      else {
         back=ReadPixel(rp,cx+x,cy+y)+ReadPixel(rp,cx+x,cy-y);
         if (back>0) break;
         back=ReadPixel(rp,cx-x,cy+y)+ReadPixel(rp,cx-x,cy-y);
         if (back>0) break;
         back=ReadPixel(rp,cx+y,cy+x)+ReadPixel(rp,cx+y,cy-x);
         if (back>0) break;
         back=ReadPixel(rp,cx-y,cy+x)+ReadPixel(rp,cx-y,cy-x);
         if (back>0) break;
         WritePixel(rp,cx+x,cy+y);
         WritePixel(rp,cx+x,cy-y);
         WritePixel(rp,cx-x,cy+y);
         WritePixel(rp,cx-x,cy-y);
         WritePixel(rp,cx+y,cy+x);
         WritePixel(rp,cx+y,cy-x);
         WritePixel(rp,cx-y,cy+x);
         WritePixel(rp,cx-y,cy-x);
      }
   }
   return(OK);
}

/* Kreis so gross wie es geht zeichnen */
int kreis_expand2(UBYTE *tabelle,struct RastPort *rp,int cx,int cy)
{
   int i,x,y,back,farbe;

   farbe=ReadPixel(rp,cx,cy);
   WritePixel(rp,cx,cy);

   for (i=0;i<PUNKTE;i++) {
      if (i%700==10) {
         if (ContinueBlanking()!=OK) return(UNBLANK);
      }
      x=tabelle[i*2];
      y=tabelle[i*2+1];
      if (y==0) {
         back=ReadPixel(rp,cx+x,cy);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-x,cy);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx,cy+x);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx,cy-x);
         if (back!=farbe) break;
         WritePixel(rp,cx+x,cy);
         WritePixel(rp,cx-x,cy);
         WritePixel(rp,cx,cy+x);
         WritePixel(rp,cx,cy-x);
         continue;
      }
      if (x==y) {
         back=ReadPixel(rp,cx+x,cy+y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx+x,cy-y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-x,cy+y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-x,cy-y);
         if (back!=farbe) break;
         WritePixel(rp,cx+x,cy+y);
         WritePixel(rp,cx+x,cy-y);
         WritePixel(rp,cx-x,cy+y);
         WritePixel(rp,cx-x,cy-y);
      }
      else {
         back=ReadPixel(rp,cx+x,cy+y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx+x,cy-y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-x,cy+y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-x,cy-y);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx+y,cy+x);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx+y,cy-x);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-y,cy+x);
         if (back!=farbe) break;
         back=ReadPixel(rp,cx-y,cy-x);
         if (back!=farbe) break;
         WritePixel(rp,cx+x,cy+y);
         WritePixel(rp,cx+x,cy-y);
         WritePixel(rp,cx-x,cy+y);
         WritePixel(rp,cx-x,cy-y);
         WritePixel(rp,cx+y,cy+x);
         WritePixel(rp,cx+y,cy-x);
         WritePixel(rp,cx-y,cy+x);
         WritePixel(rp,cx-y,cy-x);
      }
   }
   if (i==0) return(FAILED);
   return(OK);
}

/* This is the blanker */
LONG Kreise( struct Screen *Scr, SHORT breit, SHORT hoch, UBYTE *tabelle,char whinawh)
{
	struct RastPort *RP = &( Scr->RastPort );
   struct ViewPort *VP = &( Scr->ViewPort );

   int   x,y,colors,
         zeit,
         back,count;

   srand((unsigned)clock());

   colors = (1L << RP->BitMap->Depth);
   SetRGB4( VP, 0, 0, 0, 0 );
	SetRGB4( VP, 1, 0, 0, 0 );
   for (x=2;x<colors;x++) SetRGB4(VP,x,rand()%16,rand()%16,rand()%16);
   colors=colors-2;

   SetOPen(RP,1);
   SetAPen(RP,0);
   RectFill(RP,0,0,breit-1,hoch-1);

	ScreenToFront( Scr );

   zeit=clock()+10;

	while(1) {

   	x=1+rand()%(breit-2);
      y=1+rand()%(hoch-2);

	   SetAPen(RP,2+rand()%colors);

      if (whinawh==0) {
         back=kreis_expand1(tabelle,RP,x,y);
      }
      else {
         back=kreis_expand2(tabelle,RP,x,y);
      }
      if (back==UNBLANK) return(UNBLANK);
      if (back==FAILED) {
         count++;
         if (count>breit*hoch/700) return(OK);
      }
      else {
         count=0;
      }

      if (clock()>zeit) {
         if (ContinueBlanking()!=OK) return(UNBLANK);
         ScreenToFront( Scr );
         zeit=clock()+10;
      }
	}

	return 0;
}

LONG Blank( PrefObject *Prefs )
{
	struct Screen *Scr;
	struct Window *Wnd;
   UBYTE *tabelle;
	LONG RetVal;
   char depth;
	
   tabelle=AllocMem(PUNKTE*2,MEMF_PUBLIC|MEMF_CLEAR);
   if (tabelle==NULL) return FAILED;

   depth=Prefs[SCRMODE].po_Depth;
   if (depth==1) depth=2;

	if( Scr = OpenScreenTags( NULL, SA_Depth, depth,
							 SA_Quiet, TRUE, SA_DisplayID, Prefs[SCRMODE].po_ModeID,
							 SA_Behind, TRUE, SA_Overscan, OSCAN_STANDARD,
							 TAG_DONE ))
	{

      SetRGB4( &( Scr->ViewPort ),0,0,0,0);
		Wnd = BlankMousePointer( Scr );
   	ScreenToFront( Scr );

      CreateTab(tabelle);

		do
			RetVal=Kreise(Scr,Scr->Width,Scr->Height,tabelle,(char)Prefs[WHEEL].po_Active);
		while( RetVal == OK );
		
		UnblankMousePointer( Wnd );
		CloseScreen( Scr );
	}
	else RetVal = FAILED;

   FreeMem(tabelle,PUNKTE*2);

	return RetVal;
}
