;
; Copyright 2020 Electronic Arts Inc.
;
; TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 
; software: you can redistribute it and/or modify it under the terms of 
; the GNU General Public License as published by the Free Software Foundation, 
; either version 3 of the License, or (at your option) any later version.

; TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
; in the hope that it will be useful, but with permitted additional restrictions 
; under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
; distributed with this program. You should have received a copy of the 
; GNU General Public License along with permitted additional restrictions 
; with this program. If not, see [https://github.com/electronicarts/CnC_Remastered_Collection]>.

; $Header:   F:\projects\c&c\vcs\code\support.asv   2.13   16 Oct 1995 16:52:36   JOE_BOSTIC  $
;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D    S T U D I O S        **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Command & Conquer                        *
;*                                                                         *
;*                    File Name : SUPPORT.ASM                              *
;*                                                                         *
;*                   Programmer : Joe L. Bostic                            *
;*                                                                         *
;*                   Start Date : September 23, 1993                       *
;*                                                                         *
;*                  Last Update : May 10, 1994   [JLB]                     *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;*   strtrim -- Remove the trailing white space from a string.             *
;*   Fat_Put_Pixel -- Draws a fat pixel.                                   *
;*   Conquer_Build_Fading_Table -- Builds custom shadow/light fading table.*
;*   Remove_From_List -- Removes a pointer from a list of pointers.        *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *

IDEAL
P386
MODEL USE32 FLAT

INCLUDE "gbuffer.inc"
	DISPLAY	"Command & Conquer assembly support routines."

	CODESEG


;***************************************************************************
;* strtrim -- Remove the trailing white space from a string.               *
;*                                                                         *
;*    Use this routine to remove white space characters from the beginning *
;*    and end of the string.        The string is modified in place by     *
;*    this routine.                                                        *
;*                                                                         *
;* INPUT:   buffer   -- Pointer to the string to modify.                   *
;*                                                                         *
;* OUTPUT:     none                                                        *
;*                                                                         *
;* WARNINGS:   none                                                        *
;*                                                                         *
;* HISTORY:                                                                *
;*   10/07/1992 JLB : Created.                                             *
;*=========================================================================*
; VOID cdecl strtrim(BYTE *buffer);
	global C	strtrim :NEAR
	PROC	strtrim C near
	USES	ax, edi, esi

	ARG	buffer:DWORD		; Pointer to string to modify.

	cmp	[buffer],0
	je	short ??fini

	; Prepare for string scanning by loading pointers.
	cld
	mov	esi,[buffer]
	mov	edi,esi

	; Strip white space from the start of the string.
??looper:
	lodsb
	cmp	al,20h			; Space
	je	short ??looper
	cmp	al,9			; TAB
	je	short ??looper
	stosb

	; Copy the rest of the string.
??gruntloop:
	lodsb
	stosb
	or	al,al
	jnz	short ??gruntloop
	dec	edi
	; Strip the white space from the end of the string.
??looper2:
	mov	[edi],al
	dec	edi
	mov	ah,[edi]
	cmp	ah,20h
	je	short ??looper2
	cmp	ah,9
	je	short ??looper2

??fini:
	ret

	ENDP	strtrim


;***************************************************************************
;* Fat_Put_Pixel -- Draws a fat pixel.                                     *
;*                                                                         *
;*    Use this routine to draw a "pixel" that is bigger than 1 pixel       *
;*    across.  This routine is faster than drawing a similar small shape   *
;*    and faster than calling Fill_Rect.                                   *
;*                                                                         *
;* INPUT:   x,y       -- Screen coordinates to draw the pixel's upper      *
;*                       left corner.                                      *
;*                                                                         *
;*          color     -- The color to render the pixel in.                 *
;*                                                                         *
;*          size      -- The number of pixels width of the big "pixel".    *
;*                                                                         *
;*          page      -- The pointer to a GraphicBuffer class or something *
;*                                                                         *
;* OUTPUT:  none                                                           *
;*                                                                         *
;* WARNINGS:   none                                                        *
;*                                                                         *
;* HISTORY:                                                                *
;*   03/17/1994 JLB : Created.                                             *
;*=========================================================================*
; VOID cdecl Fat_Put_Pixel(long x, long y, long color, long size, void *page)
	global C	Fat_Put_Pixel:NEAR
	PROC	Fat_Put_Pixel C near
	USES	eax, ebx, ecx, edx, edi, esi

	ARG	x:DWORD		; X coordinate of upper left pixel corner.
	ARG	y:DWORD		; Y coordinate of upper left pixel corner.
	ARG	color:DWORD	; Color to use for the "pixel".
	ARG	siz:DWORD	; Size of "pixel" to plot (square).
	ARG	gpage:DWORD	; graphic page address to plot onto

	cmp	[siz],0
	je	short ??exit

	; Set EDI to point to start of logical page memory.
	;*===================================================================
	; Get the viewport information and put bytes per row in ecx
	;*===================================================================
	mov	ebx,[gpage]				; get a pointer to viewport
	mov	edi,[(GraphicViewPort ebx).GVPOffset]	; get the correct offset

	; Verify the the Y pixel offset is legal.
	mov	eax,[y]
	cmp	eax,[(GraphicViewPort ebx).GVPHeight]	;YPIXEL_MAX
	jae	short ??exit
	mov	ecx,[(GraphicViewPort ebx).GVPWidth]
	add	ecx,[(GraphicViewPort ebx).GVPXAdd]
	add	ecx,[(GraphicViewPort ebx).GVPPitch]
	mul	ecx
	add	edi,eax

	; Verify the the X pixel offset is legal.
	
	mov	edx,[(GraphicViewPort ebx).GVPWidth]
	cmp	edx,[x]
	mov	edx,ecx
	jbe	short ??exit
	add	edi,[x]

	; Write the pixel to the screen.
	mov	ebx,[siz]		; Copy of pixel size.
	sub	edx,ebx			; Modulo to reach start of next row.
	mov	eax,[color]
??again:
	mov	ecx,ebx
	rep stosb
	add	edi,edx			; EDI points to start of next row.
	dec	[siz]
	jnz	short ??again

??exit:
	ret

	ENDP	Fat_Put_Pixel


;***************************************************************************
;* Conquer_Build_Fading_Table -- Builds custom shadow/light fading table.  *
;*                                                                         *
;*    This routine is used to build a special fading table for C&C.  There *
;*    are certain colors that get faded to and cannot be faded again.      *
;*    With this rule, it is possible to draw a shadow multiple times and   *
;*    not have it get any lighter or darker.                               *
;*                                                                         *
;* INPUT:   palette  -- Pointer to the 768 byte IBM palette to build from. *
;*                                                                         *
;*          dest     -- Pointer to the 256 byte remap table.               *
;*                                                                         *
;*          color    -- Color index of the color to "fade to".             *
;*                                                                         *
;*          frac     -- The fraction to fade to the specified color        *
;*                                                                         *
;* OUTPUT:  Returns with pointer to the remap table.                       *
;*                                                                         *
;* WARNINGS:   none                                                        *
;*                                                                         *
;* HISTORY:                                                                *
;*   10/07/1992 JLB : Created.                                             *
;*=========================================================================*/
;VOID * cdecl Conquer_Build_Fading_Table(VOID *palette, VOID *dest, long color, long frac);
	global C	Conquer_Build_Fading_Table : NEAR
	PROC	Conquer_Build_Fading_Table C near
	USES	ebx, ecx, edi, esi

	ARG	palette:DWORD
	ARG	dest:DWORD
	ARG	color:DWORD
	ARG	frac:DWORD

	LOCAL	matchvalue:DWORD	; Last recorded match value.
	LOCAL	targetred:BYTE		; Target gun red.
	LOCAL	targetgreen:BYTE	; Target gun green.
	LOCAL	targetblue:BYTE		; Target gun blue.
	LOCAL	idealred:BYTE
	LOCAL	idealgreen:BYTE
	LOCAL	idealblue:BYTE
	LOCAL	matchcolor:BYTE		; Tentative match color.

ALLOWED_COUNT	EQU	16
ALLOWED_START	EQU	256-ALLOWED_COUNT

	cld

	; If the source palette is NULL, then just return with current fading table pointer.
	cmp	[palette],0
	je	??fini1
	cmp	[dest],0
	je	??fini1

	; Fractions above 255 become 255.
	mov	eax,[frac]
	cmp	eax,0100h
	jb	short ??ok
	mov	[frac],0FFh
??ok:

	; Record the target gun values.
	mov	esi,[palette]
	mov	ebx,[color]
	add	esi,ebx
	add	esi,ebx
	add	esi,ebx
	lodsb
	mov	[targetred],al
	lodsb
	mov	[targetgreen],al
	lodsb
	mov	[targetblue],al

	; Main loop.
	xor	ebx,ebx			; Remap table index.

	; Transparent black never gets remapped.
	mov	edi,[dest]
	mov	[edi],bl
	inc	edi

	; EBX = source palette logical number (1..255).
	; EDI = running pointer into dest remap table.
??mainloop:
	inc	ebx
	mov	esi,[palette]
	add	esi,ebx
	add	esi,ebx
	add	esi,ebx

	mov	edx,[frac]
	shr	edx,1
	; new = orig - ((orig-target) * fraction);

	lodsb				; orig
	mov	dh,al			; preserve it for later.
	sub	al,[targetred]		; al = (orig-target)
	imul	dl			; ax = (orig-target)*fraction
	shl	eax,1
	sub	dh,ah			; dh = orig - ((orig-target) * fraction)
	mov	[idealred],dh		; preserve ideal color gun value.

	lodsb				; orig
	mov	dh,al			; preserve it for later.
	sub	al,[targetgreen]	; al = (orig-target)
	imul	dl			; ax = (orig-target)*fraction
	shl	eax,1
	sub	dh,ah			; dh = orig - ((orig-target) * fraction)
	mov	[idealgreen],dh		; preserve ideal color gun value.

	lodsb				; orig
	mov	dh,al			; preserve it for later.
	sub	al,[targetblue]		; al = (orig-target)
	imul	dl			; ax = (orig-target)*fraction
	shl	eax,1
	sub	dh,ah			; dh = orig - ((orig-target) * fraction)
	mov	[idealblue],dh		; preserve ideal color gun value.

	; Sweep through a limited set of existing colors to find the closest
	; matching color.

	mov	eax,[color]
	mov	[matchcolor],al		; Default color (self).
	mov	[matchvalue],-1		; Ridiculous match value init.
	mov	ecx,ALLOWED_COUNT

	mov	esi,[palette]		; Pointer to original palette.
	add	esi,(ALLOWED_START)*3

	; BH = color index.
	mov	bh,ALLOWED_START
??innerloop:

	xor	edx,edx			; Comparison value starts null.

	; Build the comparison value based on the sum of the differences of the color
	; guns squared.
	lodsb
	sub	al,[idealred]
	mov	ah,al
	imul	ah
	add	edx,eax

	lodsb
	sub	al,[idealgreen]
	mov	ah,al
	imul	ah
	add	edx,eax

	lodsb
	sub	al,[idealblue]
	mov	ah,al
	imul	ah
	add	edx,eax
	jz	short ??perfect		; If perfect match found then quit early.

	cmp	edx,[matchvalue]
	jae	short ??notclose
	mov	[matchvalue],edx	; Record new possible color.
	mov	[matchcolor],bh
??notclose:
	inc	bh			; Checking color index.
	loop	??innerloop
	mov	bh,[matchcolor]
??perfect:
	mov	[matchcolor],bh
	xor	bh,bh			; Make BX valid main index again.

	; When the loop exits, we have found the closest match.
	mov	al,[matchcolor]
	stosb
	cmp	ebx,ALLOWED_START-1
	jne	??mainloop

	; Fill the remainder of the remap table with values
	; that will remap the color to itself.
	mov	ecx,ALLOWED_COUNT
??fillerloop:
	inc	bl
	mov	al,bl
	stosb
	loop	??fillerloop

??fini1:
	mov	esi,[dest]
	mov	eax,esi
	ret

	ENDP	Conquer_Build_Fading_Table


;***************************************************************************
;* Remove_From_List -- Removes a pointer from a list of pointers.          *
;*                                                                         *
;*    This low level routine is used to remove a pointer from a list of    *
;*    pointers.  The trailing pointers are moved downward to fill the      *
;*    hole.                                                                *
;*                                                                         *
;* INPUT:   list     -- Pointer to list of pointer.                        *
;*                                                                         *
;*          index    -- Pointer to length of pointer list.                 *
;*                                                                         *
;*          ptr      -- The pointer value to search for and remove.        *
;*                                                                         *
;* OUTPUT:  none                                                           *
;*                                                                         *
;* WARNINGS:   none                                                        *
;*                                                                         *
;* HISTORY:                                                                *
;*   04/11/1994 JLB : Created.                                             *
;*   04/22/1994 JLB : Convert to assembly language.                        *
;*   05/10/1994 JLB : Short pointers now.                                  *
;*=========================================================================*/
;VOID cdecl Remove_From_List(VOID **list, long *index, long ptr);
	global C	Remove_From_List:NEAR
	PROC	Remove_From_List C near
	USES	edi, esi, ecx, eax
	ARG	list:DWORD		; Pointer to list.
	ARG	index:DWORD		; Pointer to count.
	ARG	element:DWORD		; Element to remove.

	; Fetch the number of elements in the list.  If there are no
	; elements, then just exit quickly.
	mov	edi,[index]
	mov	ecx,[edi]
	jcxz	short ??fini2

	; Fetch pointer to list.
	cmp	[list],0
	je	short ??fini2
	mov	edi,[list]

	; Loop through all elements searching for a match.
	mov	eax,[element]
	repne scasd
	jne	short ??fini2		; No match found.

	; Copy all remaining elements down.  If this is the
	; last element in the list then nothing needs to be
	; copied -- just decrement the list size.
	jcxz	short ??nocopy		; No copy necessary.
	mov	esi,edi
	sub	edi,4
	rep movsd

	; Reduce the list count by one.
??nocopy:
	mov	edi,[index]
	dec	[DWORD PTR edi]

??fini2:
	ret

	ENDP	Remove_From_List


; long cdecl Get_EAX();
	global C	Get_EAX :NEAR
	PROC	Get_EAX C near
	ret

	ENDP	Get_EAX

;----------------------------------------------------------------------------

	END
