/*->c.DrawLib */

/* Library of functions to make Draw files */


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

#include "h.os"
#include "h.bbc"
#include "h.wimp"
#include "h.wimpt"
#include "h.flex"

#include "h.drawlevel0"

#include "h.BezierArc"

#include "h.wos"

#include "h.ram"

#include "h.DrawLib"


/*****************************************************************************/

char fontname[48]="\1Homerton.Medium";
int  fwidth=600;


#define BORDER 256


#define WIDTH 0


#define DCHUNK 0x1000


static int cpx;       /* x font size in Draw units */
static int cpfx;      /* font painter cpx */
static int cpy;       /* y font size in Draw units */
static int cx=0;
static int cy=0;
static int drawtoff; /* flags the start of the line object */
static int drawfoff; /* flags the start of the text object */
static int textlen;
static int xlo,xhi,ylo,yhi;
static int clinestyle;
static int linecolour;
static int fillcolour;
static int fontfcolour;
static int fontbcolour;

int drawheadersize;

/*****************************************************************************/

void flushdraw(Draw_diag * diag)
{
 int * drawt;

 if(drawtoff)
 {
  drawt=(int*)(diag->data+drawtoff);

/*  dprintf(6,"flush len=%d",(diag->length-drawtoff+4));  */

  *drawt++=(diag->length-drawtoff+4);
  *drawt++=xlo;
  *drawt++=ylo;
  *drawt++=xhi;
  *drawt++=yhi;
 }
}


void closedraw(Draw_diag * diag)
{
 flushdraw(diag);
 drawtoff=0;
}





void startdraw(int x,int y,Draw_diag * diag)
{
 int * buffp;
 int   nelem;
 int   i;

 if(!drawtoff)
 {
  if(!flex_chunk((flex_ptr)&(diag->data),diag->length+68+BORDER,DCHUNK))
  {
   abended=1;
   return;
  }

  buffp=(int*)(diag->data+diag->length);

  xlo=x-2*WIDTH;
  xhi=x+2*WIDTH;
  ylo=y-2*WIDTH;
  yhi=y+2*WIDTH;

  *buffp++=2;
  diag->length+=4;

  drawtoff=diag->length;
  *buffp++=17*4;

  *buffp++=xlo;
  *buffp++=ylo;
  *buffp++=xhi;
  *buffp++=yhi;

  *buffp++=fillcolour;     /* fill colour */
  *buffp++=linecolour;     /* outline colour */
  *buffp++=WIDTH;          /* width */

  *buffp++=1;              /* style */

  diag->length+=9*4;

  *buffp++=0;
  diag->length+=4;

 }
 else
 {
  if(x<xlo) {xlo=x-2*WIDTH;}
  if(x>xhi) {xhi=x+2*WIDTH;}
  if(y<ylo) {ylo=y-2*WIDTH;}
  if(y>yhi) {yhi=y+2*WIDTH;}
 }
}



void vecmove(int x, int y,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 if(cx==x && cy==y && drawtoff) return;

 if(!flex_chunk((flex_ptr)&(diag->data),diag->length+12+BORDER,DCHUNK))
 {
  abended=1;
  return;
 }


 cx=x;
 cy=y;

 closefont(diag);
 startdraw(x,y,diag);
 if(abended) return;

 buffp=(int*)(diag->data+diag->length-4);
 *buffp++=2; /* tag == move */
 *buffp++=x;
 *buffp++=y;
 diag->length+=8;

 *buffp++=0;
 diag->length+=4;
}



void vecdraw(int x,int y,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 if(!flex_chunk((flex_ptr)&(diag->data),diag->length+12+BORDER,DCHUNK))
 {
  abended=1;
  return;
 }

 cx=x;
 cy=y;

 closefont(diag);
 startdraw(x,y,diag);
 if(abended) return;

 buffp=(int*)(diag->data+diag->length-4);
 *buffp++=8; /* tag == draw */
 *buffp++=x;
 *buffp++=y;
 diag->length+=8;

 *buffp++=0;
 diag->length+=4;
}





void veclinecolour(int pal,Draw_diag * diag)
{
 if(pal!=linecolour)
 {
  closedraw(diag);
  linecolour=pal;
 } 
}




void vecfillcolour(int pal,Draw_diag * diag)
{
 if(pal!=fillcolour)
 {
  closedraw(diag);
  fillcolour=pal;
 } 
}






void veccurve(int x1,int y1,int x2,int y2,int x3,int y3,Draw_diag * diag)
{
 int * buffp;

 if(abended) return;

 if(!flex_chunk((flex_ptr)&(diag->data),diag->length+28+BORDER,DCHUNK))
 {
  abended=1;
  return;
 }

 cx=x3;
 cy=y3;

 closefont(diag);
 startdraw(x3,y3,diag);
 startdraw(x2,y2,diag);
 startdraw(x1,y1,diag);
 if(abended) return;

 buffp=(int*)(diag->data+diag->length-4);

 *buffp++=6; /* tag == curve */
 *buffp++=x1;
 *buffp++=y1;
 *buffp++=x2;
 *buffp++=y2;
 *buffp++=x3;
 *buffp++=y3;

 diag->length+=24;

 *buffp++=0;
 diag->length+=4;

}




void vectextsize(int xsize,int ysize,Draw_diag * diag)
{
 if(cpx!=xsize || cpy!=ysize)
 {
  closefont(diag);
  cpx=xsize;
  cpfx=(cpx*1000)/fwidth;
  cpy=ysize;
 }
}




void vectextcolour(int fpal,int bpal,Draw_diag * diag)
{
 if(fontfcolour!=fpal || fontbcolour!=bpal)
 {
  closefont(diag);
  fontfcolour=fpal;
  fontbcolour=bpal;
 }
}





void flushfont(Draw_diag * diag)
{
 int * drawt;

 if(drawfoff)
 {
  drawt=(int*)(diag->data+drawfoff);
  *drawt++=(diag->length-drawfoff+4);
  *drawt++=xlo;
  *drawt++=ylo;
  *drawt++=xhi;
  *drawt++=yhi;
 }
}



void closefont(Draw_diag * diag)
{
 flushfont(diag);
 drawfoff=0;
}




void startfont(int x,int y,Draw_diag * diag)
{
 int * buffp;

 if(!drawfoff)
 {
  if(!flex_chunk((flex_ptr)&(diag->data),diag->length+56+BORDER,DCHUNK))
  {
   abended=1;
   return;
  }

  buffp=(int*)(diag->data+diag->length);

  *buffp++=1;
  diag->length+=4;
  drawfoff=diag->length;
  *buffp++=16*4;

  *buffp++=xlo;
  *buffp++=ylo;
  *buffp++=xhi;
  *buffp++=yhi;

  *buffp++=fontfcolour; /* colour */
  *buffp++=fontbcolour; /* background */
  *buffp++=1;           /* font */
  *buffp++=cpfx;        /* x font size */
  *buffp++=cpy;         /* y font size */

  *buffp++=x;
  *buffp++=y;

  *buffp++=0;           /* zero len string */

  xhi=xlo=x;
  ylo=y-cpy;
  yhi=y+cpy;

  textlen=0;

  diag->length+=13*4;
 }
}




void vecsym(int x,int y,int c,Draw_diag * diag)
{
 int * buffp;

 closedraw(diag);
 if(drawfoff && (x!=xhi || y!=(ylo+cpy))) closefont(diag);
 startfont(x,y,diag);
 if(abended) return;

 buffp=(int*)(diag->data+diag->length);

 *(((char*)buffp)-4+(textlen & 0x3))=c;
 xhi+=cpx;
 textlen++;
 if(!(textlen & 0x3))
 {
  if(!flex_chunk((flex_ptr)&(diag->data),diag->length+4+BORDER,DCHUNK))
  {
   abended=1;
   return;
  }

  *buffp++=0;
  diag->length+=4;
 }
}


void vecstring(int x,int y,char * s,Draw_diag * diag)
{
 int * buffp;
 int   len;
 int   slen;

 closedraw(diag);
 closefont(diag);
 startfont(x,y,diag);
 if(abended) return;

 slen=len=strlen(s)+1;
 if(len & 0x3) len=len-(len & 0x3)+4;

 if(!flex_chunk((flex_ptr)&(diag->data),diag->length+len+BORDER,DCHUNK))
 {
  abended=1;
  return;
 }

 buffp=(int*)(diag->data+diag->length-4);
 strcpy(((char*)buffp),s);
 diag->length+=len;

 xhi+=cpx*slen;
 textlen=slen;

 closefont(diag);
}



void vecbackfillcolour(int fillcolour,Draw_diag * diag,int offset)
{
 int * buffp;

 if(!diag->data || diag->length<=offset)
 {
  dprintf(0,"fill failed data=%x length=%d offset=%d",diag->data,
                                   diag->length,offset);
  return;
 }

 buffp=(int*)(diag->data+offset);

/* dprintf(0,"*buff=%d fill=%d offset=%d",*buffp,fillcolour,offset); */

 if(*buffp==2) *(buffp+6)=fillcolour;
 else
 {
  dprintf(0,"miss *buff=%d fill=%d offset=%d",*buffp,fillcolour);
 }
}






void veccircle(int x,int y,int radius,Draw_diag * diag)
{
 bezier_arc_coord centre;
 bezier_arc_coord path[13];
 int              i;

 centre.x=x;
 centre.y=y;

 bezier_arc_circle(centre,radius,path);

 closediag(diag);

 vecmove(path[0].x,path[0].y,diag);
 for(i=1;i<13;i+=3)
  veccurve(path[i].x,path[i].y,path[i+1].x,path[i+1].y,
                                   path[i+2].x,path[i+2].y,diag);

 closediag(diag);
}










void doopen(Draw_diag * diag,int xsize,int ysize)
{
 int * buffp=(int*)diag->data;
 int * buff=buffp;
 int   fnlen;

 strcpy((char*)buffp,"Draw");
 buffp++;
 *buffp++=201;
 *buffp++=0;

 strcpy((char*)buffp,"Trace       ");
 buffp+=3;

 *buffp++=0;
 *buffp++=0;
 *buffp++=xsize;
 *buffp++=ysize;

 /* font table object */

 fnlen=strlen(fontname)+1;
 fnlen=(fnlen/sizeof(int))+((fnlen % sizeof(int))!=0);

 *buffp++=0;
 *buffp++=sizeof(int)*(2+fnlen);
 memset((char*)buffp,0,fnlen*sizeof(int));
 strcpy((char*)buffp,fontname);
 buffp+=fnlen;

 drawtoff=0;
 drawfoff=0;
 abended=0;

 drawheadersize=diag->length=(buffp-buff)*sizeof(int);
}


/*****************************************************************************/


/* trash diag contents */

void cleardiag(Draw_diag * diag)
{
 if(diag->data) flex_free((flex_ptr)&(diag->data));
 diag->length=0;
}


/* create a diag */

void opendiag(Draw_diag * diag,int xsize,int ysize)
{
 if(diag->data)
 {
  if(!flex_chunk((flex_ptr)&(diag->data),BORDER,DCHUNK))
  {
   abended=1;
   return;
  }
 }
 else
 {
  if(!flex_alloc((flex_ptr)&(diag->data),DCHUNK))
  {
   abended=1;
   return;
  }
 }

 diag->length=0;
 doopen(diag,xsize,ysize);
}



/* makes sure that a diag can be rendered */

void validdiag(Draw_diag * diag)
{
/* dprintf(1,"foff=%d toff=%d",drawfoff,drawtoff);  */

 flushdraw(diag);
 flushfont(diag);
}



/* terminates a diag */

void closediag(Draw_diag * diag)
{
 closedraw(diag);
 closefont(diag);
}



