/*->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.wos"

#include "h.ram"

#include "h.DrawLib"


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

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



#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;
}





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

 err=NULL;

 if(!drawtoff)
 {
  err=flex_chunke((flex_ptr)&(diag->data),diag->length+68,DCHUNK);

  if(!err)
  {
   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++=0;              /* 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;}
 }

 return(err);
}



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

 err=NULL;

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

 err=flex_chunke((flex_ptr)&(diag->data),diag->length+12,DCHUNK);
 if(!err)
 {
  cx=x;
  cy=y;

  closefont(diag); 
  err=startdraw(x,y,diag);
  if(!err)
  {
   buffp=(int*)(diag->data+diag->length-4);
   *buffp++=2; /* tag == move */
   *buffp++=x;
   *buffp++=y;
   diag->length+=8;

   *buffp++=0;
   diag->length+=4;
  }
 }
 return(err);
}



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


 err=flex_chunke((flex_ptr)&(diag->data),diag->length+12,DCHUNK);
 if(!err)
 {
  cx=x;
  cy=y;

  closefont(diag);
  err=startdraw(x,y,diag);
  if(!err)
  {
   buffp=(int*)(diag->data+diag->length-4);
   *buffp++=8; /* tag == draw */
   *buffp++=x;
   *buffp++=y;
   diag->length+=8;

   *buffp++=0;
   diag->length+=4;
  }
 }
 return(err);
}





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 veclimits(int x,int y)
{
 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;}
}


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


 err=flex_chunke((flex_ptr)&(diag->data),diag->length+28,DCHUNK);
 if(!err)
 {
  cx=x3;
  cy=y3;

  closefont(diag);
           err=startdraw(x3,y3,diag);
  if(!err) err=startdraw(x1,y1,diag);

  if(!err)
  {
   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;
  }
 }
 return(err);
}



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;
}




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

 err=NULL;

 if(!drawfoff)
 {
  err=flex_chunke((flex_ptr)&(diag->data),diag->length+56,DCHUNK);
  if(!err)
  {
   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;
  }
 }
 return(err);
}




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

 closedraw(diag);
 if(drawfoff && (x!=xhi || y!=(ylo+cpy))) closefont(diag);
 err=startfont(x,y,diag);
 if(!err)
 {
  buffp=(int*)(diag->data+diag->length);

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

 return(err);
}







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 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;

 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 */

os_error * opendiag(Draw_diag * diag,int xsize,int ysize)
{
 os_error * err;

 if(diag->data) err=flex_chunke((flex_ptr)&(diag->data),0,DCHUNK);
 else           err=flex_alloce((flex_ptr)&(diag->data),DCHUNK);

 if(!err)
 {
  diag->length=0;
  doopen(diag,xsize,ysize);
 }

 return(err);
}



os_error * mergediag(Draw_diag * dsub,Draw_diag * dmain)
{
 int        extra;
 os_error * err;

 extra=dsub->length-drawheadersize;

 err=flex_chunke((flex_ptr)&(dmain->data),dmain->length+extra,DCHUNK);
 if(!err)
 {
  memcpy(dmain->data+dmain->length,dsub->data+drawheadersize,extra);
  dmain->length+=extra;
 }

 return(err);
}




/* 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);
}



