/* ->c.pic */
/* picture box handling Draw code */


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

#include "os.h"
#include "bbc.h"
#include "h.sprite"
#include "h.wimp"
#include "h.werr"
#include "h.flex"
#include "h.swinos"

#include "h.DrawLevel0"


#include "h.wos"
#include "h.ram"
#include "h.mytrace"
#include "h.file"
#include "h.DrawLib"

#include "h.pic"



/****************************************************************************/
/*                              Render a picture box                        */



void picrend(wimp_box * box,Draw_diag diag,wimp_redrawstr * redrawstr)
{
 Draw_redrawstr r;
 double scale=1.0;
 double sx1=1.0;
 double sx2=1.0;
 Draw_error e;
 int gx0;
 int gy0;
 int gx1; 
 int gy1;
 int ox;
 int oy;
 int  stack;

 if(!diag.length || !diag.data) return;      /* no buffer do nothing */

 stack=0;

 ox=redrawstr->box.x0-redrawstr->scx;
 oy=redrawstr->box.y1-redrawstr->scy;


 gx0=ox+box->x0;  
 gy0=oy-box->y0;  
 gx1=ox+box->x1;  
 gy1=oy-box->y1;


 if(redrawstr->g.x0>gx0) r.g.x0=redrawstr->g.x0;
 else                    r.g.x0=gx0;

 if(redrawstr->g.x1<gx1) r.g.x1=redrawstr->g.x1;
 else                    r.g.x1=gx1;

 if(redrawstr->g.y0>gy0) r.g.y0=redrawstr->g.y0;
 else                    r.g.y0=gy0;

 if(redrawstr->g.y1<gy1) r.g.y1=redrawstr->g.y1;
 else                    r.g.y1=gy1;


 Draw_queryBox(diag, &r.box, TRUE);
 sx1=((double)(gx1-gx0))/((double)(r.box.x1 -r.box.x0 ));
 sx2=((double)(gy1-gy0))/((double)(r.box.y1 -r.box.y0 ));
 if(sx1>sx2) scale=sx2; else scale=sx1;


 r.scx = (r.box.x0 - gx0) + (int)((double)r.box.x0*scale);
 r.scy = (r.box.y1 - gy0) + (int)((double)r.box.y0*scale);


 if(Draw_verify_diag(diag,&e))
 {
  /* Draw a box and set the clipping region */

  bbc_gwindow(r.g.x0,r.g.y0,r.g.x1-deltax,r.g.y1-deltay);

  if(!Draw_render_diag(diag,&r,scale,scale,&e))
  {
   if (e.type == DrawOwnError)
         werr(0,"render failed: code %d at %d\n",
                e.err.draw.code, e.err.draw.location);
      else
        werr(0,"render failed: os error %s\n", e.err.os.errmess);
  }

  bbc_gwindow(redrawstr->g.x0,redrawstr->g.y0,
                     redrawstr->g.x1-deltax,redrawstr->g.y1-deltay);
 }
 else
 {
  werr(0,"verify failed: code %d at %d\n",
                     e.err.draw.code, e.err.draw.location);
 }
}


/***************************************************************************/
/* boot draw file code                                                     */

void picinit(void)
{
 Draw_registerMemoryFunctions(flex_alloc,flex_extend,flex_free);
}


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


int saveasdraw(char * filename)
{ 
 FILE * fp;
 int    realfile;

 if(!drawdiag.length || !drawdiag.data) return(0);

 fp=ropen(filename,"wb");
 if(!fp) return(0);

 rwrite(drawdiag.data,1,drawdiag.length,fp);
 realfile=!ramfp(fp);

 rclose(fp);
 if(realfile) setftype(filename,DRAW);

 return(1);
}



#define DRAWWX 16


int savesprite(char * filename)
{
 int    nosprites=1;
 int    foffset=16;
 int    firstfree;
 int    spritelen;
 char * buff;
 int    realfile;
 FILE * fp;

 fp=ropen(filename,"wb");
 if(!fp) return(0);
 
 buff=spritediag.data;

 spritelen=*((int*)(buff+DRAWWX*4));
 firstfree=spritelen+16;

 rwrite(&nosprites,1,sizeof(int),fp);
 rwrite(&foffset,1,sizeof(int),fp);
 rwrite(&firstfree,1,sizeof(int),fp);

 rwrite(buff+DRAWWX*4,spritelen,1,fp);

 realfile=!ramfp(fp);

 rclose(fp);
 if(realfile) setftype(filename,SPRITE);

 return(1);
}






#define DRAWWORDS 16

void dummysprite(int * buff,int size)
{
 char * p, * q;

 int h,w,xhi,yhi,mode,dx,dy;
 sprite_id   sid;
 sprite_info sinfo;

 /* sprite at offset 64 */

 sid.s.addr=(sprite_area *)(buff+DRAWWORDS);
 sid.tag=sprite_id_addr;
 sprite_readsize((sprite_area *)(buff+DRAWWORDS),&sid,&sinfo);

 w=sinfo.width;
 h=sinfo.height;
 mode=sinfo.mode;

 getdeltas(mode,&dx,&dy);

 xhi=w*256*dx;                         /* draw units */
 yhi=h*256*dy;

 strcpy((char *)buff,"Draw");
 *(buff+1)=201;
 *(buff+2)=0;
 p=(char*)(buff+3);
 q=p+12;
 strcpy(p,"ArcDraw");
 p+=strlen(p);
 for(;p<q;p++) *p=32;

 *(buff+6)=0;
 *(buff+7)=0;
 *(buff+8)=xhi;
 *(buff+9)=yhi;

 *(buff+10)=5;
 *(buff+11)=size;

 *(buff+12)=0;
 *(buff+13)=0;
 *(buff+14)=xhi;
 *(buff+15)=yhi;
}




int xxsaveasdraw(char * filename)
{ 
 FILE * fp;
 int    realfile;

 if(!spritediag.length || !spritediag.data) return(0);

 fp=ropen(filename,"wb");
 if(!fp) return(0);

 rwrite(spritediag.data,1,spritediag.length,fp);
 realfile=!ramfp(fp);

 rclose(fp);
 if(realfile) setftype(filename,DRAW);

 return(1);
}






/* return 1 on success */

int loadsprite(FILE * fp,Draw_diag * diag)
{
 int    nosprites;
 int    firstoff;
 int    firstfree;
 int    spritelen=-1;
 int    read;
 int    sshift;
 int    bytes;
 int    len;
 char * buff;


 rread(&nosprites,1,sizeof(int),fp); /* number of sprites              */
 rread(&firstoff,1,sizeof(int),fp);  /* byte offset to first sprite    */
 rread(&firstfree,1,sizeof(int),fp); /* byte offset to first free word */
 sshift=DRAWWORDS*4;

 if(rerror(fp)) return(0);
 if(rameof(fp)) return(0);

 read=firstoff-16;
 while(read--) rgetc(fp); /* skip to first sprite */

 rread(&spritelen,1,sizeof(int),fp); /* read offset of next sprite */
 if(rerror(fp)) return(0);
 if(rameof(fp)) return(0);

 bytes=(spritelen+sshift+3)&(~0x3);

 if(!diag->data) flex_alloc((flex_ptr)&(diag->data),bytes);
 else            flex_extend((flex_ptr)&(diag->data),bytes);

 if(diag->data) len=flex_size((flex_ptr)&(diag->data));
 else           len=0;
 if(len<bytes) return(0);

 buff=diag->data;

 *((int *)(buff+sshift))=spritelen;

 read=rread(buff+sshift+4,1,spritelen-4,fp);

 if(rerror(fp)) return(0);
 if(read<(spritelen-4)) return(0);

 dummysprite((int*)buff,((spritelen+3)&~3)+24); 

 diag->length=bytes;

 if(windowsopen)  refreshwindow(whandle[SPRITEW]);
 else             opentrace();

 return(1);
}



/* return 1 on success */

int loaddraw(FILE * fp,Draw_diag * diag)
{
 int len;
 int bytes;
 char * buff;

 len=0x2000;
 bytes=0;

 if(!diag->data) flex_alloc((flex_ptr)&(diag->data),bytes);

 while(1)
 {
  flex_extend((flex_ptr)&(diag->data),len);

  if(diag->data) len=flex_size((flex_ptr)&(diag->data));
  else           len=0;
  if(len<=bytes) return(0);

  buff=diag->data;

  bytes+=rread(buff+bytes,1,len-bytes,fp);
  if(rameof(fp)) break;
  if(rerror(fp)) break;
  len+=0x2000;
 }

 if(bytes!=len) flex_extend((flex_ptr)&(diag->data),bytes);

 if(bytes==40) return(0);  /* sizeof null draw file */

 diag->length=bytes;

 if(windowsopen) refreshwindow(whandle[DRAWW]);
 else            opentrace();

 return(1);
}





/* called from main when file dropped into our window */
/* return 1 on success                                */

int loadpicbox(char * filename,int filetype,Draw_diag * diag)
{
 FILE * fp;
 int    code=1;

 if((fp=ropen(filename,"rb"))==NULL) return(0);

 hourglasson();

 if(filetype==DRAW) code=loaddraw(fp,diag);
 else               code=loadsprite(fp,diag);

 code&=!rclose(fp);

 if(!code)
 {
  /* did not load file - clean up */
  if(diag->data) flex_free((flex_ptr)&(diag->data));
  diag->length=0;
 }
 hourglassoff();
 return(code);     
}




int spx;
int spy;
int spdx;
int spdy;
int spddx;
int spddy;
int spdrx;
int spdry;
int sposx=600;
int sposy=600;

int spmode;
int spbpp;
int spbitmask;

int spleft;
int spright;
int spwidth;
int spheight;
int sphasmask;
int spmask;
int spimage;

int  palentries;
int  paltab[256];  /* for 1st flash colours in sprite     */


char spname[256];


int loadspritefile(char * filename)
{
 sprite_id       sid;
 sprite_info     sinfo;
 sprite_header * spa;

 strcpy(spname,filename);

 loadpicbox(filename,SPRITE,&spritediag);

 sid.s.addr=(sprite_area *)(spritediag.data+DRAWWORDS*4);
 sid.tag=sprite_id_addr;
 sprite_readsize(sid.s.addr,&sid,&sinfo);

 spx=sinfo.width;
 spy=sinfo.height;
 spmode=sinfo.mode;
 sphasmask=sinfo.mask;

 getdeltas(spmode,&spdx,&spdy);
 getbpp(spmode,&spbpp,&spbitmask);

 sposx=spx*spdx;
 sposy=spy*spdy;

 spdrx=sposx*256;                         /* draw units */
 spdry=sposy*256;

 spddx=spdx*256;
 spddy=spdy*256;

 spa=(sprite_header*)(spritediag.data+DRAWWORDS*4);

 spleft=spa->lbit;
 spright=spa->rbit;


 spwidth=spa->width+1;
 spheight=spa->height+1;
 spimage=spa->image+DRAWWORDS*4;

 if(spa->mask==spa->image) spmask=0;
 else                      spmask=spa->mask+DRAWWORDS*4;


 palentries=(spa->image-sizeof(sprite_header))/8;
 if((palentries > 256) || (palentries < 0)) palentries = 0;
 if(palentries==0)
 {
  /* if there is no palette, we'd like it to look like wimp cols */

  if(spbpp==3)
  {
   palentries=16;
   paltab[0]=0x0;
   paltab[1]=0x10101000;
   paltab[2]=0x20202000;
   paltab[3]=0x30303000;
   paltab[4]=0x4000;
   paltab[5]=0x10105000;
   paltab[6]=0x20206000;
   paltab[7]=0x30307000;
   paltab[8]=0x40000000;
   paltab[9]=0x50101000;
   paltab[10]=0x60202000;
   paltab[11]=0x70303000;
   paltab[12]=0x40004000;
   paltab[13]=0x50105000;
   paltab[14]=0x60206000;
   paltab[15]=0x70307000;
   palentries=16;
  }
  else
  if(spbpp==2)
  {
   paltab[0]=0xffffff00;
   paltab[1]=0xdddddd00;
   paltab[2]=0xbbbbbb00;
   paltab[3]=0x99999900;
   paltab[4]=0x77777700;
   paltab[5]=0x55555500;
   paltab[6]=0x33333300;
   paltab[7]=0x00000000;
   paltab[8]=0x99440000;
   paltab[9]=0x00eeee00;
   paltab[10]=0x00cc0000;
   paltab[11]=0x0000dd00;
   paltab[12]=0xbbeeee00;
   paltab[13]=0x00885500;
   paltab[14]=0x00bbff00;
   paltab[15]=0xffbb0000;
   palentries=16;
  }
  else
  if(spbpp==1)
  {
   paltab[0]=0xffffff00;
   paltab[1]=0xdddddd00;
   paltab[2]=0x99999900;
   paltab[3]=0x00000000;
   palentries=4;
  }
  else
  if(spbpp==0)
  {
   paltab[0]=0xffffff00;
   paltab[1]=0x00000000;
   palentries=2;
  }
 }
 else
 {
  int *from = (int *)(((char *)spa)+sizeof(sprite_header));
                                        /* sprites palette entries       */
  int *to   = paltab;                   /* have 1st & 2nd flash colours  */
                                        /* extract ONLY 1st flash colour */
  int i;

  for (i=palentries; i>0; i--) { *to++ = *from; from += 2; }
 }

/* {
  int i;

  oscli("sp.xx");

  for(i=0;i<16;i++)
     printf("palt=%x\n",paltab[i]);

  oscli("sp.");
 } */

 cleardiag(&drawdiag);

 extent(whandle[SPRITEW],0,-esposy(),esposx(),0);
 extent(whandle[DRAWW],0,-esposy(),esposx(),0);

 reopenw(whandle[SPRITEW]);
 reopenw(whandle[DRAWW]);

 refreshwindow(whandle[DRAWW]);
 refreshwindow(whandle[SPRITEW]);

 return(1);
}


int loaddrawfile(char * filename)
{
 loadpicbox(filename,DRAW,&drawdiag);
 return(1);
}





int maskxy(int x,int y)
{
 char * data=spritediag.data+spmask;
 int    bits;
 int    byte;

 if(x<0 || x==spx || y<0 || y==spy) return(-1);

 y=(spy-1)-y;

 data+=y*spwidth*4; /* pointed at line */

 bits=x<<spbpp;
 bits=bits+spleft;
 byte=bits>>3;
 bits=bits & 0x7;

 data+=byte;

 return(((*data)>>bits) & spbitmask);
}




/* return value of pixel */

int pixelxy(int x,int y)
{
 char * data=spritediag.data+spimage;
 int    bits;
 int    byte;
 int    code;

 if(x<0 || x==spx || y<0 || y==spy) return(-1);

/* if(spmask)
 {
  code=maskxy(x,y);
  if(code==0) return(-1);
 } */


 y=(spy-1)-y;

 data+=y*spwidth*4; /* pointed at line */

 bits=x<<spbpp;
 bits=bits+spleft;
 byte=bits>>3;
 bits=bits & 0x7;

 data+=byte;

 return(((*data)>>bits) & spbitmask);
}




/* fill pixel */

void fillpixelxy(int x,int y)
{
 char * data=spritediag.data+spimage;
 int    bits;
 int    byte;

 if(x<0 || x==spx || y<0 || y==spy) return;

 y=(spy-1)-y;

 data+=y*spwidth*4; /* pointed at line */

 bits=x<<spbpp;
 bits=bits+spleft;
 byte=bits>>3;
 bits=bits & 0x7;

 data+=byte;

 *data=*data | (spbitmask << bits);
 *data=*data ^ (1 << bits);
}




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


void writens(char * string,int val)
{
 os_regset rx;

 rx.r[0]=val;
 rx.r[1]=(int)string;
 rx.r[2]=12;

 os_swix(OS_ConvertFixedFileSize,&rx);
}




int infobox(void)
{
 int  handle;
 char string[32];

 if(spname[0]) sprintf(string,"About '%s'",leaf(spname));
 else          strcpy(string,"About this image");

 closedownt(FINFO);
 handle=createwindowsub(FINFO,string);

 writeiconf(handle,1,"Mode %d, %d colours",spmode,1<<(1<<spbpp));

 writens(string,spritediag.length);
 writeicon(handle,4,string);

 writeiconf(handle,5,"%d x %d pixels",spx,spy);


 writens(string,drawdiag.length);
 writeicon(handle,0,string);

 writeiconf(handle,2,"%d x %d OS units",sposx,sposy);

 return(handle);
}






void test(void)
{
 int mode;
 int bpc;

 for(mode=0;mode<128;mode++)
 {
  getdeltas(mode,&spdx,&spdy);
  getbpp(mode,&spbpp,&spbitmask);
  getbpc(mode,&bpc,&spbitmask);


  dprintf(0,"mode=%d ln2bpp=%d bpc=%d dx=%d dy=%d",mode,spbpp,bpc,spdx,spdy);

 }
}


