;
; 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&c0\vcs\code\2support.asv   5.0   11 Nov 1996 09:40: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


;***************************************************************************
;* 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


if 0

;***************************************************************************
;* 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


;***************************************************************************
;* 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
endif


	DATASEG

TabA	DD 6949350
	DD 4913933
	DD 3474675
	DD 2456966
	DD 1737338
	DD 1228483
	DD 868669
	DD 614242
	DD 434334
	DD 307121
	DD 217167
	DD 153560
	DD 108584
	DD 76780
	DD 54292
	DD 38390
	DD 27146
	DD 19195
	DD 13573
	DD 9598
	DD 6786
	DD 4799
	DD 3393
	DD 2399
	DD 1697
	DD 1200
	DD 848
	DD 600
	DD 424
	DD 300
	DD 212
	DD 150
	DD 106

TabB	DD 154
	DD 218
	DD 309
	DD 437
	DD 618
	DD 874
	DD 1236
	DD 1748
	DD 2472
	DD 3496
	DD 4944
	DD 6992
	DD 9888
	DD 13983
	DD 19775
	DD 27967
	DD 39551
	DD 55933
	DD 79101
	DD 111866
	DD 158203
	DD 223732
	DD 316405
	DD 447465
	DD 632811
	DD 894929
	DD 1265621
	DD 1789859
	DD 2531243
	DD 3579718
	DD 5062486
	DD 7159436
	DD 10124971

	CODESEG

;***********************************************************************************************
;* Square_Root -- Finds the square root of the fixed pointer parameter.                        *
;*                                                                                             *
;* INPUT:   val   -- The fixed point (16:16) value to find the square root of.                 *
;*                                                                                             *
;* OUTPUT:  Returns with the square root of the fixed pointer parameter.                       *
;*                                                                                             *
;* WARNINGS:   none                                                                            *
;*                                                                                             *
;* HISTORY:                                                                                    *
;*   10/04/1995 JLB : Adapted.                                                                 *
;*=============================================================================================*/
;unsigned Square_Root(unsigned val);
	GLOBAL	C Square_Root :NEAR
	PROC	Square_Root C near
	USES	ebx,edx

	bsr ebx,eax
	jz ??zero

	mul [DWORD 4*ebx + OFFSET TabA]
	shrd eax,edx,10h
	add eax, [4*ebx + OFFSET TabB]
??zero:
	ret

	ENDP	Square_Root

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

	END