; ---------------------------------------
;               Flame v1.2
;
;         (C) 1995 Kimmo Roimela
;
;   You may freely use any part of this
;   code in your own programs, provided
;   that you give me partial credit.
;
;   Parts of this program were inspired
;   by Brian Stone's Camp Fire program.
; ---------------------------------------


ideal
p386
model small,C

codeseg

public flame

extrn C buffer_SEG : word
extrn C lookup_SEG : word
extrn C VGA_SEG : word

	HIDDEN	equ	3


;-----------------------------------------------
; flame
;
; Goes through the offscreen buffer,      .R.
; storing the average of pixels marked    ...
; with an A (minus something) into the    .A.
; pixel marked with an R.		  AAA
; The result is also immediately
; written into video memory.
;

proc C flame far
	arg BlockX:word,BlockY:word,BlockWidth:word,BlockHeight:word

	push eax		; Store the registers used.
	push ebx
	push cx
	push si
	push di
	push ds
	push es
	push fs

	; Set up the registers:

	mov si,[BlockY]		; Make di point to the correct location
	mov di,si		; in buffer & video memory:
	shl di,8		; This is just a multiplication by 320...
	shl si,6
	add di,si
	add di,[BlockX]		; ...and this is an addition. :-)
	mov cx,di		; cx always points to the end of the
	add cx,[BlockWidth]    	; line being drawn.
	mov si,[BlockHeight]	; si counts scanlines left to draw.

	; Set up the segment registers:

	mov es,[VGA_SEG]	; es -> video memory
	mov fs,[lookup_SEG]     ; fs -> lookup table
	mov ds,[buffer_SEG]	; ds -> offscreen buffer

	; Now we're all set up for the main loop. Each iteration
	; of the loop calculates the values for four pixels.

loop1:
	; First we'll do the additions, one pixel in each byte of ebx.
	; This is why the maximum color value is 63. :-)

	mov ebx,[di+2*320]
	add ebx,[di+3*320]
	add ebx,[di+3*320+1]
	add ebx,[di+3*320-1]

	; Now we'll divide each byte by four to get the average, ending
	; up with an index into the lookup table in both words of ebx,
	; which we'll then multiply by two to convert them into offsets:

	shr ebx,1		; Shift one right, then zero the LSB:s
	and ebx,07FFE7FFEh	; and some other bits in both words...

	; Now we have the correct offsets into the lookup table and can
	; read the results from there.

	mov ax,[fs:bx]		; Get the first two pixels.
	rol eax,16		; Swap the high & low words of eax & ebx.
	rol ebx,16
	mov ax,[fs:bx]		; Get the other two pixels.
	rol eax,16		; Restore the correct order.

	; Now we've got the new pixel values and all we have to do is
	; write them into the buffer and video memory.

	mov [es:di],eax	        ; Write to video memory.

	add di,4		; While waiting for the memory
	cmp di,cx		; write, check whether we're done.

	mov [ds:di-4],eax	; Write to buffer.

	jne loop1

	sub di,[BlockWidth]	; Move on to the next scanline.
	add di,320
	add cx,320
	dec si
	jne loop1		; All done?

	pop fs			; Restore the registers.
	pop es
	pop ds
	pop di
	pop si
	pop cx
	pop ebx
	pop eax

	ret

endp flame

END
