/*     
      SCOL ENVIRONMENT . Magma 1.0 . 1997 . Sylvain HUET

         module3d.c : module 3d specifique SCOL
*/



//
// Modifications History
//
//$ LB (13/06/2002) : changed objbitmap access, according to the new objbitmap structure
//
//$LB (17/12/2002) : 16bits to 24bits
//

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

#include "x/Version.h"
#include "x/scolplugin.h"

#include "objstr.h"

#include "objects/bitmap.h"


//#include "../kernel/include/kernel.h"
//#include "winscol.h"
//#include "../kernel/scolpack.h"


#include "lib/jpeg/jpeglib.h"
#include <setjmp.h>

extern int (*SPstorepack)(mmachine m);

/*
char tabconvln8_5[256];
char tabconvln5_8[31];

int	iniTableLn(char *tab,int src,int dest)
{
	int i;
	float x,y,n,np;

	n=src-1;
	np=dest-1;
	MMechostr(MSKDEBUG,"iniTableLn\n");
	for(i=0;i<src;i++)
	{
		y=i;
		x=.4+np*(1+(y/n-1)*log(n)/log(np));
		if ((i==0)||(x<0)) x=0;
		tab[i]=x;
		MMechostr(MSKDEBUG,"%d ",tab[i]);
	}
	MMechostr(MSKDEBUG,"\n");
	return 0;
}
*/
OBJBITMAP_BUFFER getBufferJPEG(mmachine m,int s2,int *x,int *y, int *bpl)
{
    PtrObjVoid OB ;
    PtrObjBitmap B ;

    if ( s2 == NIL ) return NULL;
    OB = ( PtrObjVoid ) MMstart(m,s2>>1);
    if ( OB->Type != OBJ_TYPE_BITMAP << 1 ) return NULL;
    B = ( PtrObjBitmap ) MMstart(m,OB->Buffer>>1);
    *x=B->TailleW;
	*y=B->TailleH;
    *bpl=B->BPL;
	return (OBJBITMAP_BUFFER)B->bits;
}

int tramage(int col,int x,int y)
{
	if (x&1)
	{
		if (y&1) col+=8;
		else col+=2;
	}
	else if (!(y&1)) col+=4;
	if (col>255) col=255;
	return col;
}

int	tramconvert24to24(OBJBITMAP_BUFFER dst, char *buffer,int width,int j)
{
	int i,r,g,b;
	for(i=0;i<width;i++)
	{
		r=tramage((*(buffer++))&255,i,j);
		g=tramage((*(buffer++))&255,i,j);
		b=tramage((*(buffer++))&255,i,j);
		*(dst++) = b;
		*(dst++) = g;
		*(dst++) = r;
	}
	return 0;
}

int	convertRead24to24(OBJBITMAP_BUFFER dst, char *buffer,int width)
{
	int i,r,g,b;
	for(i=0;i<width;i++)
	{
		r=(*(buffer++))&255;
		g=(*(buffer++))&255;
		b=(*(buffer++))&255;
		*(dst++) = b;
		*(dst++) = g;
		*(dst++) = r;
	}
	return 0;
}

int	convertWrite24to24(char *buf, OBJBITMAP_BUFFER dst, int width)
{
	int i,r,g,b;
	for(i=0;i<width;i++)
	{
		b = *(dst++);
		g = *(dst++);
		r = *(dst++);
		*(buf++)=r;*(buf++)=g;*(buf++)=b;
	}
	return 0;
}


struct scol_error_mgr {
  struct jpeg_error_mgr pub;	/* "public" fields */
  jmp_buf setjmp_buffer;	    /* for return to caller */
};
typedef struct scol_error_mgr * scol_error_ptr;

METHODDEF(void) scol_error_exit (j_common_ptr cinfo)
{
  scol_error_ptr scolerr = (scol_error_ptr) cinfo->err;

 /*  (*cinfo->err->output_message) (cinfo);*/
  longjmp(scolerr->setjmp_buffer, 1);
}


char *_stdloadJpg(char *name,int *w,int *h)
{
  struct jpeg_decompress_struct cinfo;
  struct scol_error_mgr jerr;

  JSAMPARRAY buffer;		/* Output row buffer */
  int row_stride;		/* physical row width in output buffer */
  OBJBITMAP_BUFFER dst;
  FILE *infile;
  char *bitmap;

  int i,j,length;

  if ((infile=fopen(name,"rb"))==NULL) return NULL;
 
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = scol_error_exit;

  if (setjmp(jerr.setjmp_buffer)) {
	MMechostr(MSKDEBUG,"jpeg : error\n");
/*	MMechostr(MSKDEBUG,jerr.pub.jpeg_message_table[jerr.pub.msg_code]
		,jerr.pub.msg_parm.i[0],jerr.pub.msg_parm.i[1]);
*/
    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    return NULL;
  }
 
  jpeg_create_decompress(&cinfo);

  jpeg_stdio_src(&cinfo, infile);

  jpeg_read_header(&cinfo, TRUE);
  jpeg_start_decompress(&cinfo);
//  MMechostr(MSKDEBUG,"jpeg : %dx%dx%d\n",cinfo.output_width,
//		cinfo.output_height,cinfo.output_components);

  i=cinfo.output_width;
  j=cinfo.output_height;

  *w=i;
  *h=j;

  length=i*j*2;
  bitmap=(char*)malloc(length);
  if (bitmap==NULL)
    {
      MMechostr(MSKDEBUG,"erreur allocation\n");
      fclose(infile);
      return NULL;
    }

  row_stride = cinfo.output_width * cinfo.output_components;

  buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);

  dst = (OBJBITMAP_BUFFER)bitmap;
  dst+=i*(cinfo.output_height-1);

  while (cinfo.output_scanline < cinfo.output_height)
  {
    jpeg_read_scanlines(&cinfo, buffer, 1);
	//$LB (17/12/2002)
    convertRead24to24(dst,buffer[0],cinfo.output_width);
	dst-=i;
  }
  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  fclose(infile);

  return bitmap;
}

struct my_error_mgr {
  struct jpeg_error_mgr pub;	/* "public" fields */

  jmp_buf setjmp_buffer;	/* for return to caller */
};

typedef struct my_error_mgr * my_error_ptr;


METHODDEF(void)
my_error_exit (j_common_ptr cinfo)
{
  my_error_ptr myerr = (my_error_ptr) cinfo->err;

  longjmp(myerr->setjmp_buffer, 1);
}




int LDjpeg (mmachine m)
{
  int s , s2 , l , res ;
  PtrObjVoid O ;
  PtrObjBitmap B ;        
  int R ;        

  struct jpeg_decompress_struct cinfo;
  struct my_error_mgr jerr;
  FILE * infile; /* source file */
  JSAMPARRAY buffer; /* Output row buffer */
  int row_stride; /* physical row width in output buffer */
  char * filename;
  OBJBITMAP_BUFFER dst;
  int bpl;
  int k;

/****************************/
 #ifdef DEBUG_LIB2DOS
   MMechostr (0 , "\nLDjpeg");
#endif
/****************************/

  if (MMget(m,0)==NIL)
  {
	  MMpull(m);
	  MMset(m,0,NIL);
	  return 0;
  }
  filename=MMstartstr(m,MMget(m,0)>>1);


  if ((infile = fopen(filename, "rb")) == NULL)
  {
	  MMechostr(MSKDEBUG,"jpeg : %s introuvable\n",filename);
	  MMpull(m);
	  MMpull(m);
      return MMpush(m,NIL);
  }
 
  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (setjmp(jerr.setjmp_buffer))
  {
	MMechostr(MSKDEBUG,"jpeg : error\n");
	MMechostr(MSKDEBUG,(char*)jerr.pub.jpeg_message_table[jerr.pub.msg_code]
		,jerr.pub.msg_parm.i[0],jerr.pub.msg_parm.i[1]);

    jpeg_destroy_decompress(&cinfo);
    fclose(infile);
    MMpull(m);
    MMpull(m);
    return MMpush(m,NIL);
  }
 
  jpeg_create_decompress(&cinfo);
  jpeg_stdio_src(&cinfo, infile);
  jpeg_read_header(&cinfo, TRUE);
  jpeg_start_decompress(&cinfo);
/*  MMechostr(MSKDEBUG,"jpeg : %dx%dx%d\n",cinfo.output_width,
		cinfo.output_height,cinfo.output_components);
*/
  l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
  s = MMmallocCLR (m,l,TYPETAB) ;
  if ( s == NIL ) return MERRMEM ;
  if ( MMpush(m,(s<<1)+1)) return MERRMEM  ;
  l = ( sizeof ( struct ObjBitmap ) + 3 ) >> 2 ;
  s2 = MMmalloc ( m,l,TYPEBUF ) ;
  if ( s2 == NIL ) return MERRMEM ;
  s = MMpull(m) ;

  O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
  B = ( PtrObjBitmap ) MMstart(m, s2 ) ;
     
  O->Buffer = (s2<<1)+1;
  O->Tab = MMpull(m) ;
  O->Father = NIL ;
  O->Type = OBJ_TYPE_BITMAP << 1 ;

  B->TailleH =cinfo.output_height;
  B->TailleW =cinfo.output_width;
  B->BPP = 24 ;
  B->BytesPP = B->BPP >>3;
  B->handler = ObjBitmap_New ( B , NULL ) ;

  if ( B->bits == NULL )
  {
      MMechostr ( 1 , "Creation of graphical Buffer failed.\n" ) ;
      return MERRMEM ;
  }       
        
  R = B->handler ;
//  MMechostr ( 1 , "££LDjpeg %x %d %d %s\n",B->HBitmap,B->TailleW,B->TailleH,MMstartstr(m,O->Tab>>1)) ;

  if (MMpush(m,s))return MERRMEM;

  dst = (OBJBITMAP_BUFFER)B->bits;
  bpl=B->BPL;

  row_stride = cinfo.output_width * cinfo.output_components;

  buffer = (*cinfo.mem->alloc_sarray)
		((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1);
  k=0;
  while (cinfo.output_scanline < cinfo.output_height)
  {
    jpeg_read_scanlines(&cinfo, buffer, 1);
	//$LB (17/12/2002)
    tramconvert24to24(dst,buffer[0],cinfo.output_width,k++);
	dst+=bpl;
  }

  jpeg_finish_decompress(&cinfo);
  jpeg_destroy_decompress(&cinfo);
  fclose(infile);

  res = OBJcreate(m,OBJTYPBITMAP,(int)R,0,(int)NULL ) ;

/****************************/
 #ifdef DEBUG_LIB2DOS
   MMechostr (0 , "\nLDjpeg end : %d   BPP %d  BytesPP %d    BPL %d    w %d  h %d", B->handler, B->BPP, B->BytesPP, B->BPL, B->TailleW, B->TailleH); 
#endif
/****************************/

  return res ;
}


int SAVEjpeg (mmachine m)
{
  struct jpeg_compress_struct cinfo;
  struct my_error_mgr jerr;
  FILE * outfile; /* source file */
  JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
  int row_stride; /* physical row width in output buffer */
  char * filename;
  OBJBITMAP_BUFFER dst;
  int x,y,bpl,quality;
  char *buf;

  buf=NULL;
  quality=MMpull(m)>>1;
  if ((MMget(m,0)==NIL)||(MMget(m,1)==NIL))
  {
	  MMpull(m);
	  MMset(m,0,NIL);
	  return 0;
  }
  filename=MMstartstr(m,MMpull(m)>>1);

  if ((outfile = fopen(filename, "wb")) == NULL)
  {
	  MMechostr(MSKDEBUG,"jpeg : %s introuvable\n",filename);
	  MMpull(m);
      return MMpush(m,NIL);
  }
  dst=getBufferJPEG(m,MMget(m,0),&x,&y,&bpl);

  cinfo.err = jpeg_std_error(&jerr.pub);
  jerr.pub.error_exit = my_error_exit;

  if (setjmp(jerr.setjmp_buffer))
  {
	MMechostr(MSKDEBUG,"jpeg : error\n");
	MMechostr(MSKDEBUG,(char*)jerr.pub.jpeg_message_table[jerr.pub.msg_code]
		,jerr.pub.msg_parm.i[0],jerr.pub.msg_parm.i[1]);

    jpeg_destroy_compress(&cinfo);
    fclose(outfile);
	if (buf) free(buf);
    MMpull(m);
    return MMpush(m,NIL);
  }

  jpeg_create_compress(&cinfo);
  jpeg_stdio_dest(&cinfo, outfile);

  cinfo.image_width = x; 	/* image width and height, in pixels */
  cinfo.image_height = y;
  cinfo.input_components = 3;		/* # of color components per pixel */
  cinfo.in_color_space = JCS_RGB; 	/* colorspace of input image */
  jpeg_set_defaults(&cinfo);
  jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);

  jpeg_start_compress(&cinfo, TRUE);
  row_stride = x * 3;	/* JSAMPLEs per row in image_buffer */

  buf=(char*)malloc(row_stride);
  if (buf)
  {
	  while (cinfo.next_scanline < cinfo.image_height)
		{
			convertWrite24to24(buf,dst,x);

			row_pointer[0] = buf;
			jpeg_write_scanlines(&cinfo, row_pointer, 1);
			dst+=(bpl);
		}
	  jpeg_finish_compress(&cinfo);
	  MMset(m,0,0);
	  free(buf);
  }
  else MMset(m,0,-1*2);
  fclose(outfile);
  jpeg_destroy_compress(&cinfo);
  return 0;
}


int LDtga(mmachine m)
{
  int s , s2 , l , res ;
  PtrObjVoid O ;
  PtrObjBitmap B ;        
  int R ;        
  char header[18];

  FILE * infile; /* source file */
  char * filename;
  OBJBITMAP_BUFFER dst;
  int bpl;
  int w,h,i,r,g,b,j,n,k;


/****************************/
 #ifdef DEBUG_LIB2DOS
   MMechostr (0 , "\nLDtga"); 
#endif
/****************************/

  if (MMget(m,0)==NIL)
  {
	  MMpull(m);
	  MMset(m,0,NIL);
	  return 0;
  }
  filename=MMstartstr(m,MMget(m,0)>>1);

  if ((infile = fopen(filename, "rb")) == NULL)
  {
	  MMechostr(MSKDEBUG,"tga : %s introuvable\n",filename);
	  MMpull(m);
	  MMpull(m);
      return MMpush(m,NIL);
  }
  fread(header,1,18,infile);
  if (((header[2]!=2)&&(header[2]!=10))||(header[1])||((header[16]!=32)&&(header[16]!=24)))
  {
	  MMechostr(MSKWARNING,"bad type %d %d %d\n",header[2],header[1],header[16]);
	  fclose(infile);
	  MMpull(m);
	  MMpull(m);
	  return MMpush(m,NIL);
  }
  w=*(short*)&header[12];
  h=*(short*)&header[14];
  MMechostr(MSKDEBUG,"tga : %dx%d\n",w,h);
  if (header[0]) for(i=0;i<header[0];i++) fgetc(infile);

  l = ( sizeof ( struct ObjVoid ) + 3 ) >> 2 ;
  s = MMmallocCLR (m,l,TYPETAB) ;
  if ( s == NIL ) return MERRMEM ;
  if ( MMpush(m,(s<<1)+1)) return MERRMEM  ;
  l = ( sizeof ( struct ObjBitmap ) + 3 ) >> 2 ;
  s2 = MMmalloc ( m,l,TYPEBUF ) ;
  if ( s2 == NIL ) return MERRMEM ;
  s = MMpull(m) ;

  O = ( PtrObjVoid ) MMstart(m, (s>>1) ) ;
  B = ( PtrObjBitmap ) MMstart(m, s2 ) ;
     
  O->Buffer = (s2<<1)+1;
  O->Tab = MMpull(m) ;
  O->Father = NIL ;
  O->Type = OBJ_TYPE_BITMAP << 1 ;

  B->TailleH =h;
  B->TailleW =w;
  B->BPP = 24 ;
  B->BytesPP = B->BPP >>3;
  B->handler = ObjBitmap_New ( B , NULL ) ;
  if ( B->bits == NULL )
  {
      MMechostr ( 1 , "Creation of graphical Buffer failed.\n" ) ;
	  fclose(infile);
	  MMpull(m);
	  return MMpush(m,NIL);
  }       
        
  R = B->handler ;
  if (MMpush(m,s))return MERRMEM;

  dst=(OBJBITMAP_BUFFER)B->bits;
  bpl=B->BPL;

  if (!(header[17]&4))
  {
	  dst+=bpl*(h-1);
	  bpl=-bpl;
  }

  if (header[2]==2) 
  for(i=0;i<w;i++)
  for(j=0;j<h;j++)
  {
	  for(i=0;i<w;i+=3)
	  {
		  b=255&fgetc(infile);
		  g=255&fgetc(infile);
		  r=255&fgetc(infile);
		  if (header[16]==32) fgetc(infile);
		  dst[i]   = b;
		  dst[i+1] = g;
		  dst[i+2] = r;
	  }
	  dst+=bpl;
  }
  else
  {

	  j=0;
	  i=0;
	  while(j<h)
	  {
		  n=255&fgetc(infile);
		  if (n&0x80)
		  {
			  b=255&fgetc(infile);
			  g=255&fgetc(infile);
			  r=255&fgetc(infile);
			  if (header[16]==32) fgetc(infile);

			  for(k=0x7f;k<n;k++)
			  {
				  dst[i++] = b;
				  dst[i++] = g;
				  dst[i++] = r;
				  if (i>=(w*3)) {i=0;j++;dst+=bpl;}
			  }
		  }
		  else for(k=0;k<=n;k++)
		  {
			  b=255&fgetc(infile);
			  g=255&fgetc(infile);
			  r=255&fgetc(infile);
			  if (header[16]==32) fgetc(infile);
			  dst[i++] = b;
			  dst[i++] = g;
			  dst[i++] = r;
			  if (i>=(w*3)) {i=0;j++;dst+=bpl;}
		  }
	  }
  }


  fclose(infile);

  res = OBJcreate(m,OBJTYPBITMAP,(int)R,0,(int)NULL ) ;

/****************************/
 #ifdef DEBUG_LIB2DOS
   MMechostr (0 , "\nLDtga end : %d   BPP %d  BytesPP %d    BPL %d    w %d  h %d", B->handler, B->BPP, B->BytesPP, B->BPL, B->TailleW, B->TailleH); 
#endif
/****************************/

  return res ;
}

//#include "scol.h"
//#include "listlab.h"
//#include "Winpkg.h"

#define OFFSCOBJ    3


/* definition d'une liste */
#define SIZELIST 2
#define OFFLVAL  0
#define OFFLNEXT 1


int SAVEallbmp(mmachine m)
{
	int p,q,objm;
	PtrObjVoid O ;
	PtrObjBitmap B ;
	char buf[128];

	p=MMgetglobal(m,OFFSCOBJ);
	while(p!=NIL)
	{
		p>>=1;
		q=MMfetch(m,p,OFFLVAL)>>1;
		if ((q!=NIL)&&(MMfetch(m,q,OFFOBJTYP)==OBJTYPBITMAP*2))
		{
			objm=MMfetch(m,q,OFFOBJMAG);
			O = ( PtrObjVoid ) MMstart(m,objm>>1);
			B = ( PtrObjBitmap ) MMstart(m,O->Buffer>>1);
			MMechostr(MSKDEBUG,">BITMAP%d %x %d %d\n",B->BPP,B->handler,B->TailleW,B->TailleH);
			if (O->Tab==NIL) MMechostr(MSKDEBUG,"bitmap is _CRbitmap\n");
			else  MMechostr(MSKDEBUG,"bitmap is _LDbitmap : %s\n",MMstartstr(m,O->Tab>>1));
			MMpush(m,objm);
			GRFileBitmap(m);
			sprintf(buf,"tmpbmp/%x.bmp",B->handler);
			Mpushstrbloc(m,buf);
			SPstorepack(m);
			MMpull(m);
		}
		p=MMfetch(m,p,OFFLNEXT);
	}
	MMechostr(MSKDEBUG,"---Ok\n");
	return MMpush(m,NIL);
}


#define NJPEGPKG 3

char* JPEGname[NJPEGPKG]=
{"_LDjpeg",
 "_SAVEjpeg",
 "_LDtga",
// "SaveAllBitmaps"
};

int (*JPEGfun[NJPEGPKG])(mmachine m)=
{LDjpeg,
 SAVEjpeg,
 LDtga,
// SAVEallbmp
};

int JPEGnarg[NJPEGPKG]=
{2,3,2//,0
};

char* JPEGtype[NJPEGPKG]=
{"fun [Chn P] ObjBitmap",
 "fun [ObjBitmap W I] I",
 "fun [Chn P] ObjBitmap",
// "fun [] I"
};

int SCOLloadJPEG(mmachine m)
{
    int k;

/*	iniTableLn(tabconvln8_5,256,32);*/
    k=PKhardpak(m,"JPEG.pkg",NJPEGPKG,JPEGname,JPEGfun,JPEGnarg,JPEGtype);
    return k;
}
