/*     
      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 "jpeglib.h"
#include <setjmp.h>

#include "mjpeg.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;
}


//$BLG - v5.2.06: Del (No more used - why use it to deliberately corrupt picture ????)
/*
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++)
	{
		//$BLG - v5.2.06: Modif
		//r=tramage((*(buffer++))&255,i,j);
		//g=tramage((*(buffer++))&255,i,j);
		//b=tramage((*(buffer++))&255,i,j);
		r = (*(buffer++)) &255;
		g = (*(buffer++)) &255;
		b = (*(buffer++)) &255;
		
		*(dst++) = b;
		*(dst++) = g;
		*(dst++) = r;
	}
	return 0;
}


//$BLG - v5.2.06: Del (No more used: _stdloadJpg())
/*
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;
}


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);
}


//$BLG - v5.2.06: Del (Unused)
/*
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;
}
*/


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;
}


//$BLG - v5.2.06: Del (Debug commented function ?)
/*
//#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;
}