/*****************************************************************************
 *
 * Nom:                         tracewin.c
 * Desc:                        fonctions de traçage dans les fenetres
 *
 *
 * version                      : $VER: tracewin.c 2.72 (15.08.99)
 *
 * ver2.3: fill background or transparent
 * ver2.3ß3: CyberGraphics support (beta)
 * ver2.3ß4: BugFixed but beta CGX
 * ver2.3ß5: Filled needles(option), no direct CGX support (deleted)
 * ver2.4  : added shadow and middle point drawings
 * ver2.5  : uses rtracker.library
 *         + opens in front of wb and do
 * ver2.6  : can use own defined arrows
 * ver2.7  : added shadow pos & len
 * ver2.71 : display (or not) leds
 * ver2.72 : use user defined colors for leds
 *
 *****************************************************************************
 */ 
#include <exec/memory.h>
#include <graphics/rastport.h>
#include <proto/graphics.h>
#include <proto/exec.h>
#include <math.h>
#include "utils.h"
#include "tracewin.h"
#include "partial.h"
#include <graphics/gfxmacros.h>
#include <intuition/imageclass.h>
#include <images/led.h>
#include <dos/dos.h>
#include <exec/libraries.h>
#include <clib/rtracker_protos.h>
#include <clib/dos_protos.h>
#include <pragmas/rtracker_pragmas.h>
#include <proto/intuition.h>

#ifndef PI
#define PI 3.14159265358979323846
#endif


extern struct Library * RTrackerBase ;

PLANEPTR tmpbitmap ;
USHORT Xplane, Yplane ;

struct pt * ptSec,
          * ptMin,
          * ptHeu ;
ULONG mX, mY ;

void initwin(idWin * prj) {
  void LoadArrow(BPTR file, struct pt ** arrow) ;
  BPTR file ;
  /* initialize the tmp rasport
   */
  int i ;
  
  /* find the center
   */
  mX = prj->backWin.width / 2 ;
  mY = prj->backWin.height / 2 ;
  if (prj->RP1) {
    if(prj->backWin.fill) {
      /* backfill ?
       */
      SetAPen(prj->RP1, prj->backWin.cmap[COL_BAC].reg) ;
      RectFill(prj->RP1, 0, 0, prj->backWin.width-1, prj->backWin.height-1) ;
    }
    SetAPen(prj->RP1, prj->backWin.cmap[COL_TIC].reg) ;                                                       // couleur jaune
    for(i = 0; i < 360; i+=30) {
      /* trace hours tics
      */
      Move(prj->RP1, (LONG)(cos(PI*i/180.0) * (mX-mX/10L)) + mX, (LONG)(sin(PI*i/180.0) * (mY-mY/10L)) + mY) ;
      Draw(prj->RP1, (LONG)(cos(PI*i/180.0) * mX) + mX, (LONG)(sin(PI*i/180.0) * mY) + mY) ;
    }
    
  }
  /* initalisation of arrows
   */
  ptSec = NewAllocVec(sizeof(struct pt), MEMF_PUBLIC) ;
  ptMin = NewAllocVec(sizeof(struct pt), MEMF_PUBLIC) ;
  ptHeu = NewAllocVec(sizeof(struct pt), MEMF_PUBLIC) ;

  /* seconds
   */
  if (file = Open(SFILE, MODE_OLDFILE)) {
    /* new arrow find
     */
    LoadArrow(file, &ptSec) ;
    Close(file) ;
  }else {
    /* use default
     */
    ptSec->points = 2 ;
    ptSec->fill   = FALSE ;
    ptSec->pt_buffer = NULL ; // idem
    ptSec->A = NewAllocVec(ptSec->points * sizeof(ULONG), MEMF_PUBLIC) ;
    ptSec->M = NewAllocVec(ptSec->points * sizeof(float), MEMF_PUBLIC) ;
    ptSec->A[0]   = 360 ;
    ptSec->A[1]   = 180 ;
    ptSec->M[0]   = 130 ;
    ptSec->M[1]   = 20 ;
  }
  ptSec->angle  = ANGLE_S ;
  /* hours
   */
  if (file = Open(HFILE, MODE_OLDFILE)) {
    /* new arrow find
     */
    LoadArrow(file, &ptHeu) ;
    Close(file) ;
  }else {
    ptHeu->points = 5 ;
    ptHeu->fill   = TRUE ;
    ptHeu->pt_buffer = NewAllocMem(10 * ptHeu->points, MEMF_PUBLIC) ;
    ptHeu->A = NewAllocVec(ptHeu->points * sizeof(ULONG), MEMF_PUBLIC) ;
    ptHeu->M = NewAllocVec(ptHeu->points * sizeof(float), MEMF_PUBLIC) ;
    ptHeu->A[0]   = 360 ;
    ptHeu->A[1]   = 260 ;
    ptHeu->A[2]   = 180 ;
    ptHeu->A[3]   = 100 ;
    ptHeu->A[4]   = 360 ;

    ptHeu->M[0]   = 80 ;
    ptHeu->M[1]   = 10 ;
    ptHeu->M[2]   = 12 ;
    ptHeu->M[3]   = 10 ;
    ptHeu->M[4]   = 80 ;
  }
  ptHeu->angle  = ANGLE_H ;
  /* minutes
   */
  if (file = Open(MFILE, MODE_OLDFILE)) {
    /* new arrow find
     */
    LoadArrow(file, &ptMin) ;
    Close(file) ;
  }else {
    ptMin->points =   5 ;
    ptMin->fill   = TRUE ;
    ptMin->pt_buffer = NewAllocMem(10 * ptMin->points, MEMF_PUBLIC) ;
    ptMin->A = NewAllocVec(ptMin->points * sizeof(ULONG), MEMF_PUBLIC) ;
    ptMin->M = NewAllocVec(ptMin->points * sizeof(float), MEMF_PUBLIC) ;
    ptMin->A[0]   = 360 ;
    ptMin->A[1]   = 210 ;
    ptMin->A[2]   = 180 ;
    ptMin->A[3]   = 510 ;
    ptMin->A[4]   = 360 ;

    ptMin->M[0]   =   120 ;
    ptMin->M[1]   =   30 ;
    ptMin->M[2]   =   20 ;
    ptMin->M[3]   =   30 ;
    ptMin->M[4]   =   120 ;

  }
  ptMin->angle  = ANGLE_M ;
  
  prj->ai     = NewAllocMem(sizeof(struct AreaInfo), MEMF_PUBLIC|MEMF_CLEAR) ;

  effacer(prj) ;
  retracer(prj) ;

}

void LoadArrow(BPTR file, struct pt ** rpoint) {
  ULONG current ;
  ULONG read ;
  ULONG size ;
  LONG  p[2] ;
  LONG A ;
  double a,x,y ;
  struct pt * arrow ;
  arrow = *rpoint ;
  /* get length of file
   */
  size = NULL ;
  do {
    read=Read(file, p,8) ;
    size += read ;
  }while(read) ;
  Seek(file, 0, OFFSET_BEGINNING) ;             /* return to start */
  /* do some init
   */
  arrow->points = size / 8 ;                  /* 8 bytes = 1 point */
  arrow->fill   = TRUE ;
  arrow->pt_buffer = NewAllocMem(10 * arrow->points, MEMF_PUBLIC) ;
  arrow->A = NewAllocVec(arrow->points * sizeof(ULONG), MEMF_PUBLIC) ;
  arrow->M = NewAllocVec(arrow->points * sizeof(float), MEMF_PUBLIC) ;
  current = NULL ;
  /* load points
   */
  do {
    read=Read(file, p, 8) ;                   /* load X & Y coords */
    if (read) {
      x=(double)p[0] ;
      y=(double)p[1] ;
      /* a = length of segment
       */
      a=sqrt((double)(p[0]*p[0]+p[1]*p[1])) ;
      if (y<=0.0)
        x=-x ;
      if (x <= a)
        A = (LONG)(acos(x/a)/PI*180.0) ;
      else
        A = (LONG)(asin(y/x)/PI*180.0) ;
      if (y>0)
        A=A-180;
      A=A+270 ;
      arrow->A[current] = A ;
      arrow->M[current] = a ;
      current++ ;

    }
  }while(read) ;
}

void free_twin(idWin * prj) {
  /* free vertice buffer
   * areainfo and tmpras buffer
   */
  if (ptSec->pt_buffer) NewFreeVec(ptSec->pt_buffer) ;
  if (ptMin->pt_buffer) NewFreeVec(ptMin->pt_buffer) ;
  if (ptHeu->pt_buffer) NewFreeVec(ptHeu->pt_buffer) ;
  if (ptSec->A) NewFreeVec(ptSec->A) ;
  if (ptSec->M) NewFreeVec(ptSec->M) ;
  if (ptMin->A) NewFreeVec(ptMin->A) ;
  if (ptMin->M) NewFreeVec(ptMin->M) ;
  if (ptHeu->A) NewFreeVec(ptHeu->A) ;
  if (ptHeu->M) NewFreeVec(ptHeu->M) ;
  if (prj->ai)         NewFreeVec(prj->ai) ;
}

void reinit_win(idWin * prj) {
  /* in case the window was closed then reopened
   */
  free_twin(prj) ;
  initwin(prj) ;
}

void effacer(idWin * prj) {
  /* clean the window
   */
  WaitBlit() ;
  BltBitMapRastPort(prj->RP1->BitMap, 0,0, prj->RP2, 0, 0, prj->backWin.width, prj->backWin.height, 0xc0) ;
}
void retracer(idWin * prj) {
  /* redraw the window
   */
  UWORD patt[]={0x5555,0xaaaa} ;
  UWORD tabVal[2] ;
  tabVal[0] = prj->heu ;
  tabVal[1] = prj->min ;
  if (prj->backWin.leds) {
    /* go draw the leds
     */
    if (prj->im) {
      prj->RP2->BgPen = prj->backWin.lcmap[COL_LBG].reg ;
      SetAttrs(prj->im, IA_FGPen,   prj->backWin.lcmap[COL_LFG].reg,
                        IA_BGPen,   prj->backWin.lcmap[COL_LBG].reg,
                        IA_Width,       prj->backWin.width / 2 ,
                        IA_Height,      prj->backWin.height / 4,
                        LED_Values, tabVal,
                        LED_Pairs,       2,
                        LED_Colon,    TRUE,
                        TAG_DONE) ;
      DrawImage(prj->RP2, prj->im,
                        prj->backWin.width / 4 ,
                        (prj->backWin.height/8) *5) ;

    }
    /* if the led.image can't be loaded
     * then stay silent and go on (that's not so vital)
     */
  }
  if (prj->backWin.drawsha) {
    /* trace the shadows ?
     */
    prj->RP2->AreaPtrn = patt ;
    prj->RP2->AreaPtSz = 1 ; 
    SetDrMd(prj->RP2, JAM1) ;
    SetAPen(prj->RP2, prj->backWin.cmap[COL_BLA].reg) ;
    tracerOmbre(prj, ptHeu, prj->heu, prj->min/2) ;
    tracerOmbre(prj, ptMin, prj->min, NULL) ;
    if (prj->backWin.drawsec) {
      /* draw the seconds
       */
      prj->RP2->LinePtrn = 0xaaaa ;
      tracerOmbre(prj, ptSec, prj->sec, NULL) ;
      prj->RP2->LinePtrn = 0xffff ;
    }
    prj->RP2->AreaPtrn = NULL ; 
  }
  SetAPen(prj->RP2, prj->backWin.cmap[COL_HEU].reg) ;
  tracerAiguilles(prj, ptHeu, prj->heu, prj->min/2) ;
  SetAPen(prj->RP2, prj->backWin.cmap[COL_MIN].reg) ;
  tracerAiguilles(prj, ptMin, prj->min, NULL) ;
  if (prj->backWin.drawsec) {
    SetAPen(prj->RP2, prj->backWin.cmap[COL_SEC].reg) ;
    tracerAiguilles(prj, ptSec, prj->sec, NULL) ;
  }
  if(prj->backWin.drawmpo) {
    /* draw the point
     */
    SetAPen(prj->RP2, prj->backWin.cmap[COL_MPO].reg) ;
    WritePixel(prj->RP2, mX, mY) ;
    WritePixel(prj->RP2, mX-1, mY) ;
    WritePixel(prj->RP2, mX, mY-1) ;
    WritePixel(prj->RP2, mX-1, mY-1) ;
    WritePixel(prj->RP2, mX+1, mY) ;
    WritePixel(prj->RP2, mX, mY+1) ;
    WritePixel(prj->RP2, mX+1, mY+1) ;    
  }

  WaitBlit() ;
  BltBitMapRastPort(prj->RP2->BitMap, 0,0, prj->win->RPort, 0, 0, prj->backWin.width, prj->backWin.height, 0xc0) ;
  GoAhead(prj) ;                             /* go above the workbench window */
}
LONG computeX(ULONG A, float M) {
  LONG x;
  x = mX + (LONG)( cos( PI*((float)A-90.0)/180.0 ) * (float)(M*(float)(mX/150.0))) ;
  return(x) ;
}

LONG computeY(ULONG A, float M) {
  LONG y ;
  y = mY + (LONG)( sin( PI*((float)A-90.0)/180.0 ) * (float)(M*(float)(mY/150.0))) ;
  return(y) ;
}

void tracerAiguilles(idWin * prj, struct pt * ptAigu, UBYTE p_time, UBYTE an_inc) {
  /*
   * Trace an arrow
   */
  int i ;
  
  Move(prj->RP2, computeX(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0]),
                 computeY(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0])) ;

  if (!ptAigu->fill || (prj->backWin.filln == 0)) {
    // no fill
    for(i = 0; i<ptAigu->points; i++)
      Draw(prj->RP2, computeX(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i]),
                     computeY(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i])) ;
  }else {
    // fill
    prj->RP2->AreaInfo = prj->ai ;
    InitArea(prj->ai, ptAigu->pt_buffer, ptAigu->points+2) ;
    
    AreaMove(prj->RP2, (SHORT)computeX(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0]),
                       (SHORT)computeY(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0])) ;

    for(i = 0; i < ptAigu->points; i++) 
      AreaDraw(prj->RP2, (SHORT)computeX(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i]),
                         (SHORT)computeY(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i])) ;
      
    AreaEnd(prj->RP2) ;
  }
}
void tracerOmbre(idWin * prj, struct pt * ptAigu, UBYTE p_time, UBYTE an_inc) {
  /* trace arrow shadow
   */
  int i ;
  LONG xoffset,
       yoffset ;
  /*
   * compute the offset of the shadow
   * can be +1 or -1 or 0
   *
   */
  xoffset = prj->backWin.OffXS * (prj->backWin.Slength * ((mX*2 + mY*2) / 2.0))/135.0 ;
  yoffset = prj->backWin.OffYS * (prj->backWin.Slength * ((mX*2 + mY*2) / 2.0))/135.0 ;


  Move(prj->RP2, xoffset+computeX(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0]),
                 yoffset+computeY(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0])) ;


  if (!ptAigu->fill || (prj->backWin.filln == 0)) {
    // no fill
    for(i = 0; i<ptAigu->points; i++)
      Draw(prj->RP2, xoffset+computeX(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i]),
                     yoffset+computeY(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i])) ;
  }else {
    // fill
    prj->RP2->AreaInfo = prj->ai ;
    InitArea(prj->ai, ptAigu->pt_buffer, ptAigu->points+2) ;
    
    AreaMove(prj->RP2, xoffset+computeX(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0]),
                       yoffset+computeY(ptAigu->A[0] + p_time*ptAigu->angle + an_inc, ptAigu->M[0])) ;


    for(i = 0; i < ptAigu->points; i++) 
      AreaDraw(prj->RP2, xoffset+computeX(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i]),
                         yoffset+computeY(ptAigu->A[i] + p_time*ptAigu->angle + an_inc, ptAigu->M[i])) ;

      
    AreaEnd(prj->RP2) ;
  }
}
void init_bitmap(idWin * prj) {
  /* todo: error handling
   */
  int depth ;
  /* initialize tmp rastport and bitmap
   */
  prj->tmpras = NewAllocMem(sizeof(struct TmpRas), MEMF_PUBLIC|MEMF_CLEAR) ;
  prj->RP1 = NewAllocMem(sizeof(struct RastPort), MEMF_PUBLIC) ;
  prj->RP2 = NewAllocMem(sizeof(struct RastPort), MEMF_PUBLIC) ; 
  InitRastPort(prj->RP1) ;
  InitRastPort(prj->RP2) ;
  Xplane = prj->backWin.width ;
  Yplane = prj->backWin.height ; 
  depth = GetBitMapAttr(prj->wb->RastPort.BitMap, BMA_DEPTH) ;
  prj->RP1->BitMap = AllocBitMap(Xplane, Yplane, depth, BMF_CLEAR|BMF_DISPLAYABLE|BMF_MINPLANES, prj->wb->RastPort.BitMap) ;
  prj->RP2->BitMap = AllocBitMap(Xplane, Yplane, depth, BMF_CLEAR|BMF_DISPLAYABLE|BMF_MINPLANES, prj->wb->RastPort.BitMap) ;

  tmpbitmap        = AllocRaster(Xplane, Yplane) ;
  prj->RP2->TmpRas = (struct TmpRas *) InitTmpRas(prj->tmpras, tmpbitmap, RASSIZE(Xplane, Yplane)) ;
  WaitBlit() ;
  BltBitMapRastPort(prj->wb->RastPort.BitMap, prj->backWin.posX, prj->backWin.posY, prj->RP1, 0, 0, prj->backWin.width, prj->backWin.height, 0xc0) ;
}

void free_bitmap(idWin * prj) {
  /* free all bitmaps
   */
  if (prj->tmpras) NewFreeVec(prj->tmpras) ;
  if (tmpbitmap) FreeRaster(tmpbitmap, Xplane, Yplane) ;
  if (prj->RP1 && prj->RP1->BitMap) FreeBitMap(prj->RP1->BitMap) ;
  if (prj->RP2 && prj->RP2->BitMap) FreeBitMap(prj->RP2->BitMap) ;
  if (prj->RP1) NewFreeVec(prj->RP1) ;
  if (prj->RP2) NewFreeVec(prj->RP2) ;
  prj->RP1 = prj->RP2 = NULL ;
}

