#include "alloc.h"
#include "io.h"
#include "fcntl.h"
#include "conio.h"
#include "sys/stat.h"




/*The following are the prototypes for the routine sin FADE.ASM */
void setPal(void far *pal);
void fill_pal(void far *pal,char red,char green,char blue);
void copy_pal(void far *pal,void far *pal_dest);
void sub_palette(void far *pal,void far *pal_dest);
void fade_between_once(void far *pal,void far *pal_dest);


char pal[768];
char pal2[768];



const char *image="image.raw";
const char *palf1="pal1.pal";
const char *palf2="pal2.pal";

int readstuff(const char *filename,void far *buf,unsigned length)
{
   int handle, bytes;


   if ((handle =
      sopen(filename, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1)
   {
      printf("Error Opening File\n");
      exit(1);
   }

   if ((bytes = read(handle, buf, length)) == -1) {
      printf("Read Failed.\n");
      exit(1);
   }
   return 0;
}


void fade_between_screen(void far *pal,void far *paldest)
/* This routine actually morph one palette to another */
{  int n;
   char far *buff,*buff2;
   buff=farmalloc(768*2);
   buff2=farmalloc(768);
   copyPal(paldest,buff2);
   copyPal(pal,buff);
   sub_palette(buff,buff2);
   for(n=0;n<63;++n)
    fade_between_once(buff,buff2);
   farfree(buff2);
   farfree(buff);
}



void main()
{  int n;
   asm{           /* set mode 13h video mode*/
     mov  ax,13h
     int  10h
   }

  /* read 320*200 raw image to video buffer*/

   fill_pal(&pal,0,0,0);  /* fill pal[768] with 0*/
   setPal(&pal);
   readstuff(image,(void far *)0xa0000000,64000);

  /*read palette file */
   readstuff(palf1,&pal,768);
   readstuff(palf2,&pal2,768);

   setPal(&pal);

   getch();

   fade_between_screen(&pal,&pal2);

   getch();

   fade_between_screen(&pal2,&pal);

   getch();

   asm{         /* return to text mode */
     mov ax,3h
     int 10h
   }
   printf("crosfade.exe written by Esak 1994");
}
%TITLE "moduleShell"
;---------------------------------------------------------------------
; CAUTION!
;      This module is written in Ideal model, meaning you need
;      Borland Turbo Assembler to compile it.
;------------------------------------------------------------------------

       IDEAL
       P286
       include "model.inc"

      DATASEG


PAL_SIZE EQU 768


       CODESEG


       PUBLIC   _setpal
       PUBLIC   _sub_palette,_fade_between_once
       PUBLIC   _fill_pal,_copyPal



PROC _setpal
;-----------------------------------------------------------------
; void setpal(void far *pal)
; This function simply updates hardware palette using the data
; stored in char pal[PAL_SIZE]
;  (PAL_SIZE=768)
;-----------------------------------------------------------------
ARG pal:dword

     push      bp
     mov       bp,sp
     push      ds
     push      di
     push      si
     lds      si,[pal]
     call      SETPAL
     pop       si
     pop       di
     pop       ds
     pop       bp
     ret
ENDP _setpal


PROC _sub_palette
;----------------------------------------------------------------------
; sub_palette(void *pal,void far *pal_dest)
; This routine prepares the palettes for fade_between_once()
; function.
; WARNING: pal points to char array of 768*2 bytes, not 768 bytes
;----------------------------------------------------------------------
ARG pal:dword,pal_dest:dword
      push   bp
      mov    bp,sp
      push   ds
      push   di
      push   si

      lds    si,[pal]          ;ds:si points to pal[]
      les    di,[pal_dest]     ;es:di points to pal_dest[]

      mov    cx,PAL_SIZE       ; the following loop is basically
@@l:  lodsb                    ; for(n=0;n<768;++n)
      sub    [es:di],al        ;  pal_dest[n]=pal_dest[n]-pal[n];
      inc    di                ;
      loop   @@l

      mov    cx,PAL_SIZE/2     ; the following loop is equivalent to
      xor    ax,ax
@@l2: mov    [ds:si],ax        ; for(n=0;n<768;++n)
      inc    si                ;  pal[n+PAL_SIZE]=0;
      inc    si
      loop   @@l2

      pop     si
      pop     di
      pop     ds
      pop     bp
      ret
ENDP _sub_palette




PROC _fade_between_once
;-------------------------------------------------------------------
; fade_between_once(void far *pal,void far *pal_dest)
; call sub_palette first
; Which will destroy original values of pal_dest,
;    but it's a necessary step.
; After calling it 63 times,the content of pal[768] will become
; identical to the original values of pal_dest anyway :)
;-------------------------------------------------------------------
ARG  pal:dword,pal_dest:dword
     push   bp
     mov    bp,sp
     push   ds
     push   di
     push   si
     lds    si,[pal]
     les    di,[pal_dest]

     cld
     push   si

      mov     cx,PAL_SIZE
fl2:                         ; increase the value of pallettes
      mov     bl,[es:di]     ; es:di = dest_pal
      cmp     bl,0
      jl      fl4            ; if bl>0 then goto fl4

      add     [PAL_SIZE+si],bl
      jmp     fl3

fl4:  neg     bl
      add     [PAL_SIZE+si],bl
fl5:  cmp     [byte ptr PAL_SIZE+si],63
      jb      fl7
      dec     [byte ptr si]
      sub     [byte ptr PAL_SIZE+si],63
      jmp     fl7

fl3:  cmp     [byte ptr PAL_SIZE+si],63
      jb      fl7      ;
      inc     [byte ptr si] ; increase by one
      sub     [byte ptr PAL_SIZE+si],63
fl7:  inc     di
      inc     si
      loop    fl2


     pop     si
     call    Setpal

     pop     si
     pop     di
     pop     ds
     pop     bp
     ret
ENDP _fade_between_once



;-------------------------------------------------------------------------
; update the hardware palette
; input: ds:si points to palette array
;-------------------------------------------------------------------------


PROC SETPAL
      mov       bh,0               ; bh=# of the first palette color to
				   ; update.
      mov       bl,2               ;This is the loop index.
				   ;In the following codes, we are updating
				   ;128 color at a time. Therefore, we need
				   ;a loop that runs twice in order to update
				   ;all 256 colors.

	mov     cx,128*3         ; di=128(the number of colors to update)*3

PROC SETPAL2
s:
	mov dx, 03DAh               ; CRT controller input status 1 register
v1:
	in    al, dx
	test   al,08h
	jnz    v1                     ; wait until vertical retrace starts
v2:
	in     al, dx
	test   al,08h                 ; wait until vertical retrace ends
		jz     v2

 ;--------- We have done waiting. Now let's update the palette
	mov     al,bh            ; get first color # to process into al
	mov     dx, 03c8h        ; DAC palette index register

	push    cx
	out     dx, al           ; Write the register number to the dac
	inc     dx
	rep     outsb
	pop     cx

	add     bh,128           ; color index=color index+128
	dec     bl
	jnz     s

      ret
;----------------------------------------

ENDP SETPAL2




PROC _fill_pal
;-------------------------------------------------------------
; fill_pal(void far *pal, char red, char green, char blue);
; fills the palette array with the color data given
; does not update hardware palette
;-------------------------------------------------------------
ARG pal:dword, red:byte, green:byte,blue:byte
      push   bp
      mov    bp,sp
      push   di
      les    di,[pal]
      cld
      mov    cx,PAL_SIZE/3
      mov    al,[red]
      mov    ah,[green]
      mov    bl,[blue]
@@fpl:mov    [es:di],al
      mov    [es:di+1],ah
      mov    [es:di+2],bl
      add    di,3
      loop   @@fpl
      pop    di
      pop    bp
      ret
ENDP _fill_pal


PROC _copyPal
;----------------------------------------------------------------
; copyPal(void far *source,void far *dest:dword)
;
; both *source and *dest points to arrays of 768 bytes (chars)
; I know there are C functions out there to copy strings. But
; I wrote this anyway. What the heck, it only took me a minute.
;----------------------------------------------------------------
ARG source:dword,dest:dword
      push   bp
      mov    bp,sp
      push   ds
      push   di
      push   si

      cld
      les    di,[dest]
      lds    si,[source]
      mov    cx,PAL_SIZE
      rep    movsb
      pop    si
      pop    di
      pop    ds
      pop    bp
      ret
ENDP _copyPal

      END                     ; End of module
