// // 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 /* ** ** ** Misc asm functions from ww lib ** ST - 12/19/2018 1:20PM ** ** ** ** ** ** ** ** ** ** ** */ #include "gbuffer.h" #include "MISC.H" #include "WSA.H" IconCacheClass::IconCacheClass (void) { IsCached =FALSE; SurfaceLost =FALSE; DrawFrequency =0; CacheSurface =NULL; IconSource =NULL; } IconCacheClass::~IconCacheClass (void) { } IconCacheClass CachedIcons[MAX_CACHED_ICONS]; extern "C"{ IconSetType IconSetList[MAX_ICON_SETS]; short IconCacheLookup[MAX_LOOKUP_ENTRIES]; } int CachedIconsDrawn=0; //Counter of number of cache hits int UnCachedIconsDrawn=0; //Counter of number of cache misses BOOL CacheMemoryExhausted; //Flag set if we have run out of video RAM void Invalidate_Cached_Icons (void) {} void Restore_Cached_Icons (void) {} void Register_Icon_Set (void *icon_data , BOOL pre_cache) {}; // // Prototypes for assembly language procedures in STMPCACH.ASM // extern "C" void __cdecl Clear_Icon_Pointers (void) {}; extern "C" void __cdecl Cache_Copy_Icon (void const *icon_ptr ,void * , int) {}; extern "C" int __cdecl Is_Icon_Cached (void const *icon_data , int icon) {return -1;}; extern "C" int __cdecl Get_Icon_Index (void *icon_ptr) {return 0;}; extern "C" int __cdecl Get_Free_Index (void) {return 0;}; extern "C" BOOL __cdecl Cache_New_Icon (int icon_index, void *icon_ptr) {return -1;}; extern "C" int __cdecl Get_Free_Cache_Slot(void) {return -1;} void IconCacheClass::Draw_It (LPDIRECTDRAWSURFACE dest_surface , int x_pixel, int y_pixel, int window_left , int window_top , int window_width , int window_height) {} extern int CachedIconsDrawn; extern int UnCachedIconsDrawn; extern "C" void __cdecl Set_Font_Palette_Range(void const *palette, INT start_idx, INT end_idx) { } /* ;*************************************************************************** ;* VVC::DRAW_LINE -- Scales a virtual viewport to another virtual viewport * ;* * ;* INPUT: WORD sx_pixel - the starting x pixel position * ;* WORD sy_pixel - the starting y pixel position * ;* WORD dx_pixel - the destination x pixel position * ;* WORD dy_pixel - the destination y pixel position * ;* WORD color - the color of the line to draw * ;* * ;* Bounds Checking: Compares sx_pixel, sy_pixel, dx_pixel and dy_pixel * ;* with the graphic viewport it has been assigned to. * ;* * ;* HISTORY: * ;* 06/16/1994 PWG : Created. * ;* 08/30/1994 IML : Fixed clipping bug. * ;*=========================================================================* PROC Buffer_Draw_Line C NEAR USES eax,ebx,ecx,edx,esi,edi */ void __cdecl Buffer_Draw_Line(void *this_object, int sx, int sy, int dx, int dy, unsigned char color) { unsigned int clip_min_x; unsigned int clip_max_x; unsigned int clip_min_y; unsigned int clip_max_y; unsigned int clip_var; unsigned int accum; unsigned int bpr; static int _one_time_init = 0; //clip_tbl DD nada,a_up,a_dwn,nada // DD a_lft,a_lft,a_dwn,nada // DD a_rgt,a_up,a_rgt,nada // DD nada,nada,nada,nada static void *_clip_table [4*4] = {0}; unsigned int int_color = color; unsigned int x1_pixel = (unsigned int) sx; unsigned int y1_pixel = (unsigned int) sy; unsigned int x2_pixel = (unsigned int) dx; unsigned int y2_pixel = (unsigned int) dy; __asm { mov eax,_one_time_init and eax,eax jnz init_done call do_init init_done: //;*================================================================== //;* Take care of find the clip minimum and maximums //;*================================================================== mov ebx,[this_object] xor eax,eax mov [clip_min_x],eax mov [clip_min_y],eax mov eax,[ebx]GraphicViewPortClass.Width mov [clip_max_x],eax add eax,[ebx]GraphicViewPortClass.XAdd add eax,[ebx]GraphicViewPortClass.Pitch mov [bpr],eax mov eax,[ebx]GraphicViewPortClass.Height mov [clip_max_y],eax //;*================================================================== //;* Adjust max pixels as they are tested inclusively. //;*================================================================== dec [clip_max_x] dec [clip_max_y] //;*================================================================== //;* Set the registers with the data for drawing the line //;*================================================================== mov eax,[x1_pixel] //; eax = start x pixel position mov ebx,[y1_pixel] //; ebx = start y pixel position mov ecx,[x2_pixel] //; ecx = dest x pixel position mov edx,[y2_pixel] //; edx = dest y pixel position //;*================================================================== //;* This is the section that "pushes" the line into bounds. //;* I have marked the section with PORTABLE start and end to signify //;* how much of this routine is 100% portable between graphics modes. //;* It was just as easy to have variables as it would be for constants //;* so the global vars ClipMaxX,ClipMinY,ClipMaxX,ClipMinY are used //;* to clip the line (default is the screen) //;* PORTABLE start //;*================================================================== cmp eax,[clip_min_x] jl short clip_it cmp eax,[clip_max_x] jg short clip_it cmp ebx,[clip_min_y] jl short clip_it cmp ebx,[clip_max_y] jg short clip_it cmp ecx,[clip_min_x] jl short clip_it cmp ecx,[clip_max_x] jg short clip_it cmp edx,[clip_min_y] jl short clip_it cmp edx,[clip_max_y] jle short on_screen //;*================================================================== //;* Takes care off clipping the line. //;*================================================================== clip_it: call set_bits xchg eax,ecx xchg ebx,edx mov edi,esi call set_bits mov [clip_var],edi or [clip_var],esi jz short on_screen test edi,esi jne short off_screen shl esi,2 //call [clip_tbl+esi] call [_clip_table+esi] jc clip_it xchg eax,ecx xchg ebx,edx shl edi,2 //call [clip_tbl+edi] call [_clip_table+edi] jmp clip_it on_screen: jmp draw_it off_screen: jmp and_out //;*================================================================== //;* Jump table for clipping conditions //;*================================================================== //clip_tbl DD nada,a_up,a_dwn,nada // DD a_lft,a_lft,a_dwn,nada // DD a_rgt,a_up,a_rgt,nada // DD nada,nada,nada,nada nada: clc ret a_up: mov esi,[clip_min_y] call clip_vert stc ret a_dwn: mov esi,[clip_max_y] neg esi neg ebx neg edx call clip_vert neg ebx neg edx stc ret //;*================================================================== //;* xa'=xa+[(miny-ya)(xb-xa)/(yb-ya)] //;*================================================================== clip_vert: push edx push eax mov [clip_var],edx //; clip_var = yb sub [clip_var],ebx //; clip_var = (yb-ya) neg eax //; eax=-xa add eax,ecx //; (ebx-xa) mov edx,esi //; edx=miny sub edx,ebx //; edx=(miny-ya) imul edx idiv [clip_var] pop edx add eax,edx pop edx mov ebx,esi ret a_lft: mov esi,[clip_min_x] call clip_horiz stc ret a_rgt: mov esi,[clip_max_x] neg eax neg ecx neg esi call clip_horiz neg eax neg ecx stc ret //;*================================================================== //;* ya'=ya+[(minx-xa)(yb-ya)/(xb-xa)] //;*================================================================== clip_horiz: push edx mov [clip_var],ecx //; clip_var = xb sub [clip_var],eax //; clip_var = (xb-xa) sub edx,ebx //; edx = (yb-ya) neg eax //; eax = -xa add eax,esi //; eax = (minx-xa) imul edx //; eax = (minx-xa)(yb-ya) idiv [clip_var] //; eax = (minx-xa)(yb-ya)/(xb-xa) add ebx,eax //; ebx = xa+[(minx-xa)(yb-ya)/(xb-xa)] pop edx mov eax,esi ret //;*================================================================== //;* Sets the condition bits //;*================================================================== set_bits: xor esi,esi cmp ebx,[clip_min_y] //; if y >= top its not up jge short a_not_up or esi,1 a_not_up: cmp ebx,[clip_max_y] //; if y <= bottom its not down jle short a_not_down or esi,2 a_not_down: cmp eax,[clip_min_x] //; if x >= left its not left jge short a_not_left or esi,4 a_not_left: cmp eax,[clip_max_x] //; if x <= right its not right jle short a_not_right or esi,8 a_not_right: ret //;*================================================================== //;* Draw the line to the screen. //;* PORTABLE end //;*================================================================== draw_it: sub edx,ebx //; see if line is being draw down jnz short not_hline //; if not then its not a hline jmp short hline //; do special case h line not_hline: jg short down //; if so there is no need to rev it neg edx //; negate for actual pixel length xchg eax,ecx //; swap x's to rev line draw sub ebx,edx //; get old edx down: push edx push eax mov eax,[bpr] mul ebx mov ebx,eax mov eax,[this_object] add ebx,[eax]GraphicViewPortClass.Offset pop eax pop edx mov esi,1 //; assume a right mover sub ecx,eax //; see if line is right jnz short not_vline //; see if its a vertical line jmp vline not_vline: jg short right //; if so, the difference = length //left: neg ecx //; else negate for actual pixel length neg esi //; negate counter to move left right: cmp ecx,edx //; is it a horiz or vert line jge short horiz //; if ecx > edx then |x|>|y| or horiz //vert: xchg ecx,edx //; make ecx greater and edx lesser mov edi,ecx //; set greater mov [accum],ecx //; set accumulator to 1/2 greater shr [accum],1 //;*================================================================== //;* at this point ... //;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater; //;* esi=adder; accum=accumulator //;* in a vertical loop the adder is conditional and the inc constant //;*================================================================== //vert_loop: add ebx,eax mov eax,[int_color] v_midloop: mov [ebx],al dec ecx jl and_out add ebx,[bpr] sub [accum],edx //; sub the lesser jge v_midloop //; any line could be new add [accum],edi //; add greater for new accum add ebx,esi //; next pixel over jmp v_midloop horiz: mov edi,ecx //; set greater mov [accum],ecx //; set accumulator to 1/2 greater shr [accum],1 //;*================================================================== //;* at this point ... //;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater; //;* esi=adder; accum=accumulator //;* in a vertical loop the adder is conditional and the inc constant //;*================================================================== //horiz_loop: add ebx,eax mov eax,[int_color] h_midloop: mov [ebx],al dec ecx //; dec counter jl and_out //; end of line add ebx,esi sub [accum],edx //; sub the lesser jge h_midloop add [accum],edi //; add greater for new accum add ebx,[bpr] //; goto next line jmp h_midloop //;*================================================================== //;* Special case routine for horizontal line draws //;*================================================================== hline: cmp eax,ecx //; make eax < ecx jl short hl_ac xchg eax,ecx hl_ac: sub ecx,eax //; get len inc ecx push edx push eax mov eax,[bpr] mul ebx mov ebx,eax mov eax,[this_object] add ebx,[eax]GraphicViewPortClass.Offset pop eax pop edx add ebx,eax mov edi,ebx cmp ecx,15 jg big_line mov al,[color] rep stosb //; write as many words as possible jmp short and_out //; get outt big_line: mov al,[color] mov ah,al mov ebx,eax shl eax,16 mov ax,bx test edi,3 jz aligned mov [edi],al inc edi dec ecx test edi,3 jz aligned mov [edi],al inc edi dec ecx test edi,3 jz aligned mov [edi],al inc edi dec ecx aligned: mov ebx,ecx shr ecx,2 rep stosd mov ecx,ebx and ecx,3 rep stosb jmp and_out //;*================================================================== //;* a special case routine for vertical line draws //;*================================================================== vline: mov ecx,edx //; get length of line to draw inc ecx add ebx,eax mov eax,[int_color] vl_loop: mov [ebx],al //; store bit add ebx,[bpr] dec ecx jnz vl_loop jmp and_out do_init: mov edi, offset _clip_table lea esi, nada mov [edi], esi mov [edi+12], esi lea esi, a_up mov [edi+4], esi lea esi, a_dwn mov [edi+8], esi add edi, 16 lea esi, a_lft mov [edi], esi mov [edi+4], esi lea esi, a_dwn mov [edi+8], esi lea esi, nada mov [edi+12], esi add edi, 16 lea esi, a_rgt mov [edi], esi mov [edi+8], esi lea esi, a_up mov [edi+4], esi lea esi, nada mov [edi+12], esi add edi, 16 lea esi, nada mov [edi], esi mov [edi+4], esi mov [edi+8], esi mov [edi+12], esi mov [_one_time_init], 1 ret and_out: } } /* ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Westwood 32 bit Library * ;* * ;* File Name : DRAWLINE.ASM * ;* * ;* Programmer : Phil W. Gorrow * ;* * ;* Start Date : June 16, 1994 * ;* * ;* Last Update : August 30, 1994 [IML] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* VVC::Scale -- Scales a virtual viewport to another virtual viewport * ;* Normal_Draw -- jump loc for drawing scaled line of normal pixel * ;* __DRAW_LINE -- Assembly routine to draw a line * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT INCLUDE ".\drawbuff.inc" INCLUDE ".\gbuffer.inc" CODESEG */ /* ;*************************************************************************** ;* VVC::DRAW_LINE -- Scales a virtual viewport to another virtual viewport * ;* * ;* INPUT: WORD sx_pixel - the starting x pixel position * ;* WORD sy_pixel - the starting y pixel position * ;* WORD dx_pixel - the destination x pixel position * ;* WORD dy_pixel - the destination y pixel position * ;* WORD color - the color of the line to draw * ;* * ;* Bounds Checking: Compares sx_pixel, sy_pixel, dx_pixel and dy_pixel * ;* with the graphic viewport it has been assigned to. * ;* * ;* HISTORY: * ;* 06/16/1994 PWG : Created. * ;* 08/30/1994 IML : Fixed clipping bug. * ;*=========================================================================* PROC Buffer_Draw_Line C NEAR USES eax,ebx,ecx,edx,esi,edi ;*================================================================== ;* Define the arguements that the function takes. ;*================================================================== ARG this_object:DWORD ; associated graphic view port ARG x1_pixel:DWORD ; the start x pixel position ARG y1_pixel:DWORD ; the start y pixel position ARG x2_pixel:DWORD ; the dest x pixel position ARG y2_pixel:DWORD ; the dest y pixel position ARG color:DWORD ; the color we are drawing ;*================================================================== ;* Define the local variables that we will use on the stack ;*================================================================== LOCAL clip_min_x:DWORD LOCAL clip_max_x:DWORD LOCAL clip_min_y:DWORD LOCAL clip_max_y:DWORD LOCAL clip_var:DWORD LOCAL accum:DWORD LOCAL bpr:DWORD ;*================================================================== ;* Take care of find the clip minimum and maximums ;*================================================================== mov ebx,[this_object] xor eax,eax mov [clip_min_x],eax mov [clip_min_y],eax mov eax,[(GraphicViewPort ebx).GVPWidth] mov [clip_max_x],eax add eax,[(GraphicViewPort ebx).GVPXAdd] add eax,[(GraphicViewPort ebx).GVPPitch] mov [bpr],eax mov eax,[(GraphicViewPort ebx).GVPHeight] mov [clip_max_y],eax ;*================================================================== ;* Adjust max pixels as they are tested inclusively. ;*================================================================== dec [clip_max_x] dec [clip_max_y] ;*================================================================== ;* Set the registers with the data for drawing the line ;*================================================================== mov eax,[x1_pixel] ; eax = start x pixel position mov ebx,[y1_pixel] ; ebx = start y pixel position mov ecx,[x2_pixel] ; ecx = dest x pixel position mov edx,[y2_pixel] ; edx = dest y pixel position ;*================================================================== ;* This is the section that "pushes" the line into bounds. ;* I have marked the section with PORTABLE start and end to signify ;* how much of this routine is 100% portable between graphics modes. ;* It was just as easy to have variables as it would be for constants ;* so the global vars ClipMaxX,ClipMinY,ClipMaxX,ClipMinY are used ;* to clip the line (default is the screen) ;* PORTABLE start ;*================================================================== cmp eax,[clip_min_x] jl short ??clip_it cmp eax,[clip_max_x] jg short ??clip_it cmp ebx,[clip_min_y] jl short ??clip_it cmp ebx,[clip_max_y] jg short ??clip_it cmp ecx,[clip_min_x] jl short ??clip_it cmp ecx,[clip_max_x] jg short ??clip_it cmp edx,[clip_min_y] jl short ??clip_it cmp edx,[clip_max_y] jle short ??on_screen ;*================================================================== ;* Takes care off clipping the line. ;*================================================================== ??clip_it: call NEAR PTR ??set_bits xchg eax,ecx xchg ebx,edx mov edi,esi call NEAR PTR ??set_bits mov [clip_var],edi or [clip_var],esi jz short ??on_screen test edi,esi jne short ??off_screen shl esi,2 call [DWORD PTR cs:??clip_tbl+esi] jc ??clip_it xchg eax,ecx xchg ebx,edx shl edi,2 call [DWORD PTR cs:??clip_tbl+edi] jmp ??clip_it ??on_screen: jmp ??draw_it ??off_screen: jmp ??out ;*================================================================== ;* Jump table for clipping conditions ;*================================================================== ??clip_tbl DD ??nada,??a_up,??a_dwn,??nada DD ??a_lft,??a_lft,??a_dwn,??nada DD ??a_rgt,??a_up,??a_rgt,??nada DD ??nada,??nada,??nada,??nada ??nada: clc retn ??a_up: mov esi,[clip_min_y] call NEAR PTR ??clip_vert stc retn ??a_dwn: mov esi,[clip_max_y] neg esi neg ebx neg edx call NEAR PTR ??clip_vert neg ebx neg edx stc retn ;*================================================================== ;* xa'=xa+[(miny-ya)(xb-xa)/(yb-ya)] ;*================================================================== ??clip_vert: push edx push eax mov [clip_var],edx ; clip_var = yb sub [clip_var],ebx ; clip_var = (yb-ya) neg eax ; eax=-xa add eax,ecx ; (ebx-xa) mov edx,esi ; edx=miny sub edx,ebx ; edx=(miny-ya) imul edx idiv [clip_var] pop edx add eax,edx pop edx mov ebx,esi retn ??a_lft: mov esi,[clip_min_x] call NEAR PTR ??clip_horiz stc retn ??a_rgt: mov esi,[clip_max_x] neg eax neg ecx neg esi call NEAR PTR ??clip_horiz neg eax neg ecx stc retn ;*================================================================== ;* ya'=ya+[(minx-xa)(yb-ya)/(xb-xa)] ;*================================================================== ??clip_horiz: push edx mov [clip_var],ecx ; clip_var = xb sub [clip_var],eax ; clip_var = (xb-xa) sub edx,ebx ; edx = (yb-ya) neg eax ; eax = -xa add eax,esi ; eax = (minx-xa) imul edx ; eax = (minx-xa)(yb-ya) idiv [clip_var] ; eax = (minx-xa)(yb-ya)/(xb-xa) add ebx,eax ; ebx = xa+[(minx-xa)(yb-ya)/(xb-xa)] pop edx mov eax,esi retn ;*================================================================== ;* Sets the condition bits ;*================================================================== ??set_bits: xor esi,esi cmp ebx,[clip_min_y] ; if y >= top its not up jge short ??a_not_up or esi,1 ??a_not_up: cmp ebx,[clip_max_y] ; if y <= bottom its not down jle short ??a_not_down or esi,2 ??a_not_down: cmp eax,[clip_min_x] ; if x >= left its not left jge short ??a_not_left or esi,4 ??a_not_left: cmp eax,[clip_max_x] ; if x <= right its not right jle short ??a_not_right or esi,8 ??a_not_right: retn ;*================================================================== ;* Draw the line to the screen. ;* PORTABLE end ;*================================================================== ??draw_it: sub edx,ebx ; see if line is being draw down jnz short ??not_hline ; if not then its not a hline jmp short ??hline ; do special case h line ??not_hline: jg short ??down ; if so there is no need to rev it neg edx ; negate for actual pixel length xchg eax,ecx ; swap x's to rev line draw sub ebx,edx ; get old edx ??down: push edx push eax mov eax,[bpr] mul ebx mov ebx,eax mov eax,[this_object] add ebx,[(GraphicViewPort eax).GVPOffset] pop eax pop edx mov esi,1 ; assume a right mover sub ecx,eax ; see if line is right jnz short ??not_vline ; see if its a vertical line jmp ??vline ??not_vline: jg short ??right ; if so, the difference = length ??left: neg ecx ; else negate for actual pixel length neg esi ; negate counter to move left ??right: cmp ecx,edx ; is it a horiz or vert line jge short ??horiz ; if ecx > edx then |x|>|y| or horiz ??vert: xchg ecx,edx ; make ecx greater and edx lesser mov edi,ecx ; set greater mov [accum],ecx ; set accumulator to 1/2 greater shr [accum],1 ;*================================================================== ;* at this point ... ;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater; ;* esi=adder; accum=accumulator ;* in a vertical loop the adder is conditional and the inc constant ;*================================================================== ??vert_loop: add ebx,eax mov eax,[color] ??v_midloop: mov [ebx],al dec ecx jl ??out add ebx,[bpr] sub [accum],edx ; sub the lesser jge ??v_midloop ; any line could be new add [accum],edi ; add greater for new accum add ebx,esi ; next pixel over jmp ??v_midloop ??horiz: mov edi,ecx ; set greater mov [accum],ecx ; set accumulator to 1/2 greater shr [accum],1 ;*================================================================== ;* at this point ... ;* eax=xpos ; ebx=page line offset; ecx=counter; edx=lesser; edi=greater; ;* esi=adder; accum=accumulator ;* in a vertical loop the adder is conditional and the inc constant ;*================================================================== ??horiz_loop: add ebx,eax mov eax,[color] ??h_midloop: mov [ebx],al dec ecx ; dec counter jl ??out ; end of line add ebx,esi sub [accum],edx ; sub the lesser jge ??h_midloop add [accum],edi ; add greater for new accum add ebx,[bpr] ; goto next line jmp ??h_midloop ;*================================================================== ;* Special case routine for horizontal line draws ;*================================================================== ??hline: cmp eax,ecx ; make eax < ecx jl short ??hl_ac xchg eax,ecx ??hl_ac: sub ecx,eax ; get len inc ecx push edx push eax mov eax,[bpr] mul ebx mov ebx,eax mov eax,[this_object] add ebx,[(GraphicViewPort eax).GVPOffset] pop eax pop edx add ebx,eax mov edi,ebx cmp ecx,15 jg ??big_line mov al,[byte color] rep stosb ; write as many words as possible jmp short ??out ; get outt ??big_line: mov al,[byte color] mov ah,al mov ebx,eax shl eax,16 mov ax,bx test edi,3 jz ??aligned mov [edi],al inc edi dec ecx test edi,3 jz ??aligned mov [edi],al inc edi dec ecx test edi,3 jz ??aligned mov [edi],al inc edi dec ecx ??aligned: mov ebx,ecx shr ecx,2 rep stosd mov ecx,ebx and ecx,3 rep stosb jmp ??out ;*================================================================== ;* a special case routine for vertical line draws ;*================================================================== ??vline: mov ecx,edx ; get length of line to draw inc ecx add ebx,eax mov eax,[color] ??vl_loop: mov [ebx],al ; store bit add ebx,[bpr] dec ecx jnz ??vl_loop ??out: ret ENDP Buffer_Draw_Line */ /* ;*************************************************************************** ;* GVPC::FILL_RECT -- Fills a rectangular region of a graphic view port * ;* * ;* INPUT: WORD the left hand x pixel position of region * ;* WORD the upper x pixel position of region * ;* WORD the right hand x pixel position of region * ;* WORD the lower x pixel position of region * ;* UBYTE the color (optional) to clear the view port to * ;* * ;* OUTPUT: none * ;* * ;* NOTE: This function is optimized to handle viewport with no XAdd * ;* value. It also handles DWORD aligning the destination * ;* when speed can be gained by doing it. * ;* HISTORY: * ;* 06/07/1994 PWG : Created. * ;*=========================================================================* */ /* ;****************************************************************************** ; Much testing was done to determine that only when there are 14 or more bytes ; being copied does it speed the time it takes to do copies in this algorithm. ; For this reason and because 1 and 2 byte copies crash, is the special case ; used. SKB 4/21/94. Tested on 486 66mhz. Copied by PWG 6/7/04. */ #define OPTIMAL_BYTE_COPY 14 void __cdecl Buffer_Fill_Rect(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color) { /* ;*=================================================================== ;* define the arguements that our function takes. ;*=================================================================== ARG this_object:DWORD ; this is a member function ARG x1_pixel:WORD ARG y1_pixel:WORD ARG x2_pixel:WORD ARG y2_pixel:WORD ARG color:BYTE ; what color should we clear to */ void *this_object = thisptr; int x1_pixel = sx; int y1_pixel = sy; int x2_pixel = dx; int y2_pixel = dy; /* ;*=================================================================== ; Define some locals so that we can handle things quickly ;*=================================================================== LOCAL VPwidth:DWORD ; the width of the viewport LOCAL VPheight:DWORD ; the height of the viewport LOCAL VPxadd:DWORD ; the additional x offset of viewport LOCAL VPbpr:DWORD ; the number of bytes per row of viewport */ int VPwidth; int VPheight; int VPxadd; int VPbpr; int local_ebp; // Can't use ebp __asm { ;*=================================================================== ;* save off the viewport characteristics on the stack ;*=================================================================== mov ebx,[this_object] ; get a pointer to viewport mov eax,[ebx]GraphicViewPortClass.Width ; get width from viewport mov ecx,[ebx]GraphicViewPortClass.Height ; get height from viewport mov edx,[ebx]GraphicViewPortClass.XAdd ; get xadd from viewport add edx,[ebx]GraphicViewPortClass.Pitch ; extra pitch of direct draw surface mov [VPwidth],eax ; store the width of locally mov [VPheight],ecx mov [VPxadd],edx add eax,edx mov [VPbpr],eax ;*=================================================================== ;* move the important parameters into local registers ;*=================================================================== mov eax,[x1_pixel] mov ebx,[y1_pixel] mov ecx,[x2_pixel] mov edx,[y2_pixel] ;*=================================================================== ;* Convert the x2 and y2 pixel to a width and height ;*=================================================================== cmp eax,ecx jl no_swap_x xchg eax,ecx no_swap_x: sub ecx,eax cmp ebx,edx jl no_swap_y xchg ebx,edx no_swap_y: sub edx,ebx inc ecx inc edx ;*=================================================================== ;* Bounds check source X. ;*=================================================================== cmp eax, [VPwidth] ; compare with the max jge done ; starts off screen, then later jb short sx_done ; if it's not negative, it's ok ;------ Clip source X to left edge of screen. add ecx, eax ; Reduce width (add in negative src X). xor eax, eax ; Clip to left of screen. sx_done: ;*=================================================================== ;* Bounds check source Y. ;*=================================================================== cmp ebx, [VPheight] ; compare with the max jge done ; starts off screen, then later jb short sy_done ; if it's not negative, it's ok ;------ Clip source Y to top edge of screen. add edx, ebx ; Reduce height (add in negative src Y). xor ebx, ebx ; Clip to top of screen. sy_done: ;*=================================================================== ;* Bounds check width versus width of source and dest view ports ;*=================================================================== push ebx ; save off ebx for later use mov ebx,[VPwidth] ; get the source width sub ebx, eax ; Maximum allowed pixel width (given coordinates). sub ebx, ecx ; Pixel width undershoot. jns short width_ok ; if not signed no adjustment necessary add ecx, ebx ; Reduce width to screen limits. width_ok: pop ebx ; restore ebx to old value ;*=================================================================== ;* Bounds check height versus height of source view port ;*=================================================================== push eax ; save of eax for later use mov eax, [VPheight] ; get the source height sub eax, ebx ; Maximum allowed pixel height (given coordinates). sub eax, edx ; Pixel height undershoot. jns short height_ok ; if not signed no adjustment necessary add edx, eax ; Reduce height to screen limits. height_ok: pop eax ; restore eax to old value ;*=================================================================== ;* Perform the last minute checks on the width and height ;*=================================================================== or ecx,ecx jz done or edx,edx jz done cmp ecx,[VPwidth] ja done cmp edx,[VPheight] ja done ;*=================================================================== ;* Get the offset into the virtual viewport. ;*=================================================================== xchg edi,eax ; save off the contents of eax xchg esi,edx ; and edx for size test mov eax,ebx ; move the y pixel into eax mul [VPbpr] ; multiply by bytes per row add edi,eax ; add the result into the x position mov ebx,[this_object] add edi,[ebx]GraphicViewPortClass.Offset mov edx,esi ; restore edx back to real value mov eax,ecx ; store total width in ecx sub eax,[VPwidth] ; modify xadd value to include clipped sub [VPxadd],eax ; width bytes (subtract a negative number) ;*=================================================================== ; Convert the color byte to a DWORD for fast storing ;*=================================================================== mov al,[color] ; get color to clear to mov ah,al ; extend across WORD mov ebx,eax ; extend across DWORD in shl eax,16 ; several steps mov ax,bx ;*=================================================================== ; If there is no row offset then adjust the width to be the size of ; the entire viewport and adjust the height to be 1 ;*=================================================================== mov esi,[VPxadd] or esi,esi ; set the flags for esi jnz row_by_row_aligned ; and act on them xchg eax,ecx ; switch bit pattern and width mul edx ; multiply by edx to get size xchg eax,ecx ; switch size and bit pattern mov edx,1 ; only 1 line off view port size to do ;*=================================================================== ; Find out if we should bother to align the row. ;*=================================================================== row_by_row_aligned: mov [local_ebp],ecx ; width saved in ebp cmp ecx,OPTIMAL_BYTE_COPY ; is it worth aligning them? jl row_by_row ; if not then skip ;*=================================================================== ; Figure out the alignment offset if there is any ;*=================================================================== mov ebx,edi ; get output position and ebx,3 ; is there a remainder? jz aligned_loop ; if not we are aligned xor ebx,3 ; find number of align bytes inc ebx ; this number is off by one sub [local_ebp],ebx ; subtract from width ;*=================================================================== ; Now that we have the alignment offset copy each row ;*=================================================================== aligned_loop: mov ecx,ebx ; get number of bytes to align rep stosb ; and move them over mov ecx,[local_ebp] ; get number of aligned bytes shr ecx,2 ; convert to DWORDS rep stosd ; and move them over mov ecx,[local_ebp] ; get number of aligned bytes and ecx,3 ; find the remainder rep stosb ; and move it over add edi,esi ; fix the line offset dec edx ; decrement the height jnz aligned_loop ; if more to do than do it jmp done ; we are all done ;*=================================================================== ; If not enough bytes to bother aligning copy each line across a byte ; at a time. ;*=================================================================== row_by_row: mov ecx,[local_ebp] ; get total width in bytes rep stosb ; store the width add edi,esi ; handle the xadd dec edx ; decrement the height jnz row_by_row ; if any left then next line done: } } /* ;*************************************************************************** ;* VVPC::CLEAR -- Clears a virtual viewport instance * ;* * ;* INPUT: UBYTE the color (optional) to clear the view port to * ;* * ;* OUTPUT: none * ;* * ;* NOTE: This function is optimized to handle viewport with no XAdd * ;* value. It also handles DWORD aligning the destination * ;* when speed can be gained by doing it. * ;* HISTORY: * ;* 06/07/1994 PWG : Created. * ;* 08/23/1994 SKB : Clear the direction flag to always go forward. * ;*=========================================================================* */ void __cdecl Buffer_Clear(void *this_object, unsigned char color) { unsigned int local_color = color; __asm { cld ; always go forward mov ebx,[this_object] ; get a pointer to viewport mov edi,[ebx]GraphicViewPortClass.Offset ; get the correct offset mov edx,[ebx]GraphicViewPortClass.Height ; get height from viewport mov esi,[ebx]GraphicViewPortClass.Width ; get width from viewport //push [dword (GraphicViewPort ebx).GVPPitch] ; extra pitch of direct draw surface push [ebx]GraphicViewPortClass.Pitch mov ebx,[ebx]GraphicViewPortClass.XAdd ; esi = add for each line add ebx,[esp] ; Yes, I know its nasty but add esp,4 ; it works! ;*=================================================================== ; Convert the color byte to a DWORD for fast storing ;*=================================================================== mov al,[color] ; get color to clear to mov ah,al ; extend across WORD mov ecx,eax ; extend across DWORD in shl eax,16 ; several steps mov ax,cx ;*=================================================================== ; Find out if we should bother to align the row. ;*=================================================================== cmp esi , OPTIMAL_BYTE_COPY ; is it worth aligning them? jl byte_by_byte ; if not then skip ;*=================================================================== ; Figure out the alignment offset if there is any ;*=================================================================== push ebx dword_aligned_loop: mov ecx , edi mov ebx , esi neg ecx and ecx , 3 sub ebx , ecx rep stosb mov ecx , ebx shr ecx , 2 rep stosd mov ecx , ebx and ecx , 3 rep stosb add edi , [ esp ] dec edx ; decrement the height jnz dword_aligned_loop ; if more to do than do it pop eax jmp done //ret ;*=================================================================== ; If not enough bytes to bother aligning copy each line across a byte ; at a time. ;*=================================================================== byte_by_byte: mov ecx,esi ; get total width in bytes rep stosb ; store the width add edi,ebx ; handle the xadd dec edx ; decrement the height jnz byte_by_byte ; if any left then next line done: } } BOOL __cdecl Linear_Blit_To_Linear( void *this_object, void * dest, int x_pixel, int y_pixel, int dest_x0, int dest_y0, int pixel_width, int pixel_height, BOOL trans) { /* ;*=================================================================== ;* define the arguements that our function takes. ;*=================================================================== ARG this_object :DWORD ; this is a member function ARG dest :DWORD ; what are we blitting to ARG x_pixel :DWORD ; x pixel position in source ARG y_pixel :DWORD ; y pixel position in source ARG dest_x0 :dword ARG dest_y0 :dword ARG pixel_width :DWORD ; width of rectangle to blit ARG pixel_height:DWORD ; height of rectangle to blit ARG trans :DWORD ; do we deal with transparents? ;*=================================================================== ; Define some locals so that we can handle things quickly ;*=================================================================== LOCAL x1_pixel :dword LOCAL y1_pixel :dword LOCAL dest_x1 : dword LOCAL dest_y1 : dword LOCAL scr_ajust_width:DWORD LOCAL dest_ajust_width:DWORD LOCAL source_area : dword LOCAL dest_area : dword */ int x1_pixel; int y1_pixel; int dest_x1; int dest_y1; int scr_adjust_width; int dest_adjust_width; int source_area; int dest_area; __asm { ;This Clipping algorithm is a derivation of the very well known ;Cohen-Sutherland Line-Clipping test. Due to its simplicity and efficiency ;it is probably the most commontly implemented algorithm both in software ;and hardware for clipping lines, rectangles, and convex polygons against ;a rectagular clipping window. For reference see ;"COMPUTER GRAPHICS principles and practice by Foley, Vandam, Feiner, Hughes ; pages 113 to 177". ; Briefly consist in computing the Sutherland code for both end point of ; the rectangle to find out if the rectangle is: ; - trivially accepted (no further clipping test, display rectangle) ; - trivially rejected (return with no action) ; - retangle must be iteratively clipped again edges of the clipping window ; and the remaining retangle is display. ; Clip Source Rectangle against source Window boundaries. mov esi,[this_object] ; get ptr to src xor ecx,ecx ; Set sutherland code to zero xor edx,edx ; Set sutherland code to zero ; compute the difference in the X axis and get the bit signs into ecx , edx mov edi,[esi]GraphicViewPortClass.Width ; get width into register mov ebx,[x_pixel] ; Get first end point x_pixel into register mov eax,[x_pixel] ; Get second end point x_pixel into register add ebx,[pixel_width] ; second point x1_pixel = x + width shld ecx, eax,1 ; the sign bit of x_pixel is sutherland code0 bit4 mov [x1_pixel],ebx ; save second for future use inc edi ; move the right edge by one unit shld edx,ebx,1 ; the sign bit of x1_pixel is sutherland code0 bit4 sub eax,edi ; compute the difference x0_pixel - width sub ebx,edi ; compute the difference x1_pixel - width shld ecx,eax,1 ; the sign bit of the difference is sutherland code0 bit3 shld edx,ebx,1 ; the sign bit of the difference is sutherland code0 bit3 ; the following code is just a repeticion of the above code ; in the Y axis. mov edi,[esi]GraphicViewPortClass.Height ; get height into register mov ebx,[y_pixel] mov eax,[y_pixel] add ebx,[pixel_height] shld ecx,eax,1 mov [y1_pixel ],ebx inc edi shld edx,ebx,1 sub eax,edi sub ebx,edi shld ecx,eax,1 shld edx,ebx,1 ; Here we have the to Sutherland code into cl and dl xor cl,5 ; bit 2 and 0 are complented, reverse then xor dl,5 ; bit 2 and 0 are complented, reverse then mov al,cl ; save code1 in case we have to clip iteratively test dl,cl ; if any bit in code0 and its counter bit jnz real_out ; in code1 is set then the rectangle in outside or al,dl ; if all bit of code0 the counter bit in jz clip_against_dest ; in code1 is set to zero, then all ; end points of the rectangle are ; inside the clipping window ; if we are here the polygon have to be clip iteratively test cl,1000b ; if bit 4 in code0 is set then jz scr_left_ok ; x_pixel is smaller than zero mov [x_pixel],0 ; set x_pixel to cero. scr_left_ok: test cl,0010b ; if bit 2 in code0 is set then jz scr_bottom_ok ; y_pixel is smaller than zero mov [ y_pixel ],0 ; set y_pixel to cero. scr_bottom_ok: test dl,0100b ; if bit 3 in code1 is set then jz scr_right_ok ; x1_pixel is greater than the width mov eax,[esi]GraphicViewPortClass.Width ; get width into register mov [ x1_pixel ],eax ; set x1_pixel to width. scr_right_ok: test dl,0001b ; if bit 0 in code1 is set then jz clip_against_dest ; y1_pixel is greater than the width mov eax,[esi]GraphicViewPortClass.Height ; get height into register mov [ y1_pixel ],eax ; set y1_pixel to height. ; Clip Source Rectangle against destination Window boundaries. clip_against_dest: ; build the destination rectangle before clipping ; dest_x1 = dest_x0 + ( x1_pixel - x_pixel ) ; dest_y1 = dest_y0 + ( y1_pixel - y_pixel ) mov eax,[dest_x0] ; get dest_x0 into eax mov ebx,[dest_y0] ; get dest_y0 into ebx sub eax,[x_pixel] ; subtract x_pixel from eax sub ebx,[y_pixel] ; subtract y_pixel from ebx add eax,[x1_pixel] ; add x1_pixel to eax add ebx,[y1_pixel] ; add y1_pixel to ebx mov [dest_x1],eax ; save eax into dest_x1 mov [dest_y1],ebx ; save eax into dest_y1 ; The followin code is a repeticion of the Sutherland clipping ; descrived above. mov esi,[dest] ; get ptr to src xor ecx,ecx xor edx,edx mov edi,[esi]GraphicViewPortClass.Width ; get width into register mov eax,[dest_x0] mov ebx,[dest_x1] shld ecx,eax,1 inc edi shld edx,ebx,1 sub eax,edi sub ebx,edi shld ecx,eax,1 shld edx,ebx,1 mov edi,[esi]GraphicViewPortClass.Height ; get height into register mov eax,[dest_y0] mov ebx,[dest_y1] shld ecx,eax,1 inc edi shld edx,ebx,1 sub eax,edi sub ebx,edi shld ecx,eax,1 shld edx,ebx,1 xor cl,5 xor dl,5 mov al,cl test dl,cl jnz real_out or al,dl jz do_blit test cl,1000b jz dest_left_ok mov eax,[ dest_x0 ] mov [ dest_x0 ],0 sub [ x_pixel ],eax dest_left_ok: test cl,0010b jz dest_bottom_ok mov eax,[ dest_y0 ] mov [ dest_y0 ],0 sub [ y_pixel ],eax dest_bottom_ok: test dl,0100b jz dest_right_ok mov ebx,[esi]GraphicViewPortClass.Width ; get width into register mov eax,[ dest_x1 ] mov [ dest_x1 ],ebx sub eax,ebx sub [ x1_pixel ],eax dest_right_ok: test dl,0001b jz do_blit mov ebx,[esi]GraphicViewPortClass.Height ; get width into register mov eax,[ dest_y1 ] mov [ dest_y1 ],ebx sub eax,ebx sub [ y1_pixel ],eax ; Here is where we do the actual blit do_blit: cld mov ebx,[this_object] mov esi,[ebx]GraphicViewPortClass.Offset mov eax,[ebx]GraphicViewPortClass.XAdd add eax,[ebx]GraphicViewPortClass.Width add eax,[ebx]GraphicViewPortClass.Pitch mov ecx,eax mul [y_pixel] add esi,[x_pixel] mov [source_area],ecx add esi,eax add ecx,[x_pixel ] sub ecx,[x1_pixel ] mov [scr_adjust_width ],ecx mov ebx,[dest] mov edi,[ebx]GraphicViewPortClass.Offset mov eax,[ebx]GraphicViewPortClass.XAdd add eax,[ebx]GraphicViewPortClass.Width add eax,[ebx]GraphicViewPortClass.Pitch mov ecx,eax mul [ dest_y0 ] add edi,[ dest_x0 ] mov [ dest_area ],ecx add edi,eax mov eax,[ dest_x1 ] sub eax,[ dest_x0 ] jle real_out sub ecx,eax mov [ dest_adjust_width ],ecx mov edx,[ dest_y1 ] sub edx,[ dest_y0 ] jle real_out cmp esi,edi jz real_out jl backupward_blit ; ******************************************************************** ; Forward bitblit test [ trans ],1 jnz forward_Blit_trans ; the inner loop is so efficient that ; the optimal consept no longer apply because ; the optimal byte have to by a number greather than 9 bytes cmp eax,10 jl forward_loop_bytes forward_loop_dword: mov ecx,edi mov ebx,eax neg ecx and ecx,3 sub ebx,ecx rep movsb mov ecx,ebx shr ecx,2 rep movsd mov ecx,ebx and ecx,3 rep movsb add esi,[ scr_adjust_width ] add edi,[ dest_adjust_width ] dec edx jnz forward_loop_dword jmp real_out //ret forward_loop_bytes: mov ecx,eax rep movsb add esi,[ scr_adjust_width ] add edi,[ dest_adjust_width ] dec edx jnz forward_loop_bytes jmp real_out forward_Blit_trans: mov ecx,eax and ecx,01fh lea ecx,[ ecx + ecx * 4 ] neg ecx shr eax,5 lea ecx,[ transp_reference + ecx * 2 ] mov [ y1_pixel ],ecx forward_loop_trans: mov ecx,eax jmp [ y1_pixel ] forward_trans_line: //REPT 32 //local transp_pixel //No REPT in msvc inline assembly. // Save ECX and use as counter instead. ST - 12/19/2018 5:41PM push ecx mov ecx, 32 rept_loop: mov bl,[ esi ] test bl,bl jz transp_pixel mov [ edi ],bl transp_pixel: inc esi inc edi dec ecx //ST - 12/19/2018 5:44PM jnz rept_loop //ST - 12/19/2018 5:44PM pop ecx //ST - 12/19/2018 5:44PM //ENDM transp_reference: dec ecx jge forward_trans_line add esi,[ scr_adjust_width ] add edi,[ dest_adjust_width ] dec edx jnz forward_loop_trans jmp real_out //ret ; ************************************************************************ ; backward bitblit backupward_blit: mov ebx,[ source_area ] dec edx add esi,eax imul ebx,edx std lea esi,[ esi + ebx - 1 ] mov ebx,[ dest_area ] add edi,eax imul ebx,edx lea edi,[ edi + ebx - 1] test [ trans ],1 jnz backward_Blit_trans cmp eax,15 jl backward_loop_bytes backward_loop_dword: push edi push esi lea ecx,[edi+1] mov ebx,eax and ecx,3 ; Get non aligned bytes. sub ebx,ecx ; remove that from the total size to be copied later. rep movsb ; do the copy. sub esi,3 mov ecx,ebx ; Get number of bytes left. sub edi,3 shr ecx,2 ; Do 4 bytes at a time. rep movsd ; do the dword copy. mov ecx,ebx add esi,3 add edi,3 and ecx,03h rep movsb ; finnish the remaining bytes. pop esi pop edi sub esi,[ source_area ] sub edi,[ dest_area ] dec edx jge backward_loop_dword cld jmp real_out //ret backward_loop_bytes: push edi mov ecx,eax ; remove that from the total size to be copied later. push esi rep movsb ; do the copy. pop esi pop edi sub esi,[ source_area ] sub edi,[ dest_area ] dec edx jge backward_loop_bytes cld jmp real_out //ret backward_Blit_trans: mov ecx,eax and ecx,01fh lea ecx,[ ecx + ecx * 4 ] neg ecx shr eax,5 lea ecx,[ back_transp_reference + ecx * 2 ] mov [ y1_pixel ],ecx backward_loop_trans: mov ecx,eax push edi push esi jmp [ y1_pixel ] backward_trans_line: //REPT 32 //local transp_pixel2 //No REPT in msvc inline assembly. // Save ECX and use as counter instead. ST - 12/19/2018 5:41PM push ecx mov ecx, 32 rept_loop2: mov bl,[ esi ] test bl,bl jz transp_pixel2 mov [ edi ],bl transp_pixel2: dec esi dec edi dec ecx //ST - 12/19/2018 5:44PM jnz rept_loop2 //ST - 12/19/2018 5:44PM pop ecx //ST - 12/19/2018 5:44PM //ENDM back_transp_reference: dec ecx jge backward_trans_line pop esi pop edi sub esi,[ source_area ] sub edi,[ dest_area ] dec edx jge backward_loop_trans cld //ret real_out: } } /* ;*************************************************************************** ;* VVC::SCALE -- Scales a virtual viewport to another virtual viewport * ;* * ;* INPUT: * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 06/16/1994 PWG : Created. * ;*=========================================================================* PROC Linear_Scale_To_Linear C NEAR USES eax,ebx,ecx,edx,esi,edi */ // Ran out of registers so had to use ebp. ST - 12/19/2018 6:22PM #pragma warning (push) #pragma warning (disable : 4731) BOOL __cdecl Linear_Scale_To_Linear(void *this_object, void *dest, int src_x, int src_y, int dst_x, int dst_y, int src_width, int src_height, int dst_width, int dst_height, BOOL trans, char *remap) { /* ;*=================================================================== ;* Define the arguements that our function takes. ;*=================================================================== ARG this_object:DWORD ; pointer to source view port ARG dest:DWORD ; pointer to destination view port ARG src_x:DWORD ; source x offset into view port ARG src_y:DWORD ; source y offset into view port ARG dst_x:DWORD ; dest x offset into view port ARG dst_y:DWORD ; dest y offset into view port ARG src_width:DWORD ; width of source rectangle ARG src_height:DWORD ; height of source rectangle ARG dst_width:DWORD ; width of dest rectangle ARG dst_height:DWORD ; width of dest height ARG trans:DWORD ; is this transparent? ARG remap:DWORD ; pointer to table to remap source ;*=================================================================== ;* Define local variables to hold the viewport characteristics ;*=================================================================== local src_x0 : dword local src_y0 : dword local src_x1 : dword local src_y1 : dword local dst_x0 : dword local dst_y0 : dword local dst_x1 : dword local dst_y1 : dword local src_win_width : dword local dst_win_width : dword local dy_intr : dword local dy_frac : dword local dy_acc : dword local dx_frac : dword local counter_x : dword local counter_y : dword local remap_counter :dword local entry : dword */ int src_x0; int src_y0; int src_x1; int src_y1; int dst_x0; int dst_y0; int dst_x1; int dst_y1; int src_win_width; int dst_win_width; int dy_intr; int dy_frac; int dy_acc; int dx_frac; int counter_x; int counter_y; int remap_counter; int entry; __asm { ;*=================================================================== ;* Check for scale error when to or from size 0,0 ;*=================================================================== cmp [dst_width],0 je all_done cmp [dst_height],0 je all_done cmp [src_width],0 je all_done cmp [src_height],0 je all_done mov eax , [ src_x ] mov ebx , [ src_y ] mov [ src_x0 ] , eax mov [ src_y0 ] , ebx add eax , [ src_width ] add ebx , [ src_height ] mov [ src_x1 ] , eax mov [ src_y1 ] , ebx mov eax , [ dst_x ] mov ebx , [ dst_y ] mov [ dst_x0 ] , eax mov [ dst_y0 ] , ebx add eax , [ dst_width ] add ebx , [ dst_height ] mov [ dst_x1 ] , eax mov [ dst_y1 ] , ebx ; Clip Source Rectangle against source Window boundaries. mov esi , [ this_object ] ; get ptr to src xor ecx , ecx xor edx , edx mov edi , [esi]GraphicViewPortClass.Width ; get width into register mov eax , [ src_x0 ] mov ebx , [ src_x1 ] shld ecx , eax , 1 inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 mov edi,[esi]GraphicViewPortClass.Height ; get height into register mov eax , [ src_y0 ] mov ebx , [ src_y1 ] shld ecx , eax , 1 inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 xor cl , 5 xor dl , 5 mov al , cl test dl , cl jnz all_done or al , dl jz clip_against_dest mov bl , dl test cl , 1000b jz src_left_ok xor eax , eax mov [ src_x0 ] , eax sub eax , [ src_x ] imul [ dst_width ] idiv [ src_width ] add eax , [ dst_x ] mov [ dst_x0 ] , eax src_left_ok: test cl , 0010b jz src_bottom_ok xor eax , eax mov [ src_y0 ] , eax sub eax , [ src_y ] imul [ dst_height ] idiv [ src_height ] add eax , [ dst_y ] mov [ dst_y0 ] , eax src_bottom_ok: test bl , 0100b jz src_right_ok mov eax , [esi]GraphicViewPortClass.Width ; get width into register mov [ src_x1 ] , eax sub eax , [ src_x ] imul [ dst_width ] idiv [ src_width ] add eax , [ dst_x ] mov [ dst_x1 ] , eax src_right_ok: test bl , 0001b jz clip_against_dest mov eax , [esi]GraphicViewPortClass.Height ; get width into register mov [ src_y1 ] , eax sub eax , [ src_y ] imul [ dst_height ] idiv [ src_height ] add eax , [ dst_y ] mov [ dst_y1 ] , eax ; Clip destination Rectangle against source Window boundaries. clip_against_dest: mov esi , [ dest ] ; get ptr to src xor ecx , ecx xor edx , edx mov edi , [esi]GraphicViewPortClass.Width ; get width into register mov eax , [ dst_x0 ] mov ebx , [ dst_x1 ] shld ecx , eax , 1 inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 mov edi,[esi]GraphicViewPortClass.Height ; get height into register mov eax , [ dst_y0 ] mov ebx , [ dst_y1 ] shld ecx , eax , 1 inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 xor cl , 5 xor dl , 5 mov al , cl test dl , cl jnz all_done or al , dl jz do_scaling mov bl , dl test cl , 1000b jz dst_left_ok xor eax , eax mov [ dst_x0 ] , eax sub eax , [ dst_x ] imul [ src_width ] idiv [ dst_width ] add eax , [ src_x ] mov [ src_x0 ] , eax dst_left_ok: test cl , 0010b jz dst_bottom_ok xor eax , eax mov [ dst_y0 ] , eax sub eax , [ dst_y ] imul [ src_height ] idiv [ dst_height ] add eax , [ src_y ] mov [ src_y0 ] , eax dst_bottom_ok: test bl , 0100b jz dst_right_ok mov eax , [esi]GraphicViewPortClass.Width ; get width into register mov [ dst_x1 ] , eax sub eax , [ dst_x ] imul [ src_width ] idiv [ dst_width ] add eax , [ src_x ] mov [ src_x1 ] , eax dst_right_ok: test bl , 0001b jz do_scaling mov eax , [esi]GraphicViewPortClass.Height ; get width into register mov [ dst_y1 ] , eax sub eax , [ dst_y ] imul [ src_height ] idiv [ dst_height ] add eax , [ src_y ] mov [ src_y1 ] , eax do_scaling: cld mov ebx , [ this_object ] mov esi , [ebx]GraphicViewPortClass. Offset mov eax , [ebx]GraphicViewPortClass. XAdd add eax , [ebx]GraphicViewPortClass. Width add eax , [ebx]GraphicViewPortClass. Pitch mov [ src_win_width ] , eax mul [ src_y0 ] add esi , [ src_x0 ] add esi , eax mov ebx , [ dest ] mov edi , [ebx]GraphicViewPortClass. Offset mov eax , [ebx]GraphicViewPortClass. XAdd add eax , [ebx]GraphicViewPortClass. Width add eax , [ebx]GraphicViewPortClass. Pitch mov [ dst_win_width ] , eax mul [ dst_y0 ] add edi , [ dst_x0 ] add edi , eax mov eax , [ src_height ] xor edx , edx mov ebx , [ dst_height ] idiv [ dst_height ] imul eax , [ src_win_width ] neg ebx mov [ dy_intr ] , eax mov [ dy_frac ] , edx mov [ dy_acc ] , ebx mov eax , [ src_width ] xor edx , edx shl eax , 16 idiv [ dst_width ] xor edx , edx shld edx , eax , 16 shl eax , 16 mov ecx , [ dst_y1 ] mov ebx , [ dst_x1 ] sub ecx , [ dst_y0 ] jle all_done sub ebx , [ dst_x0 ] jle all_done mov [ counter_y ] , ecx cmp [ trans ] , 0 jnz transparency cmp [ remap ] , 0 jnz normal_remap ; ************************************************************************* ; normal scale mov ecx , ebx and ecx , 01fh lea ecx , [ ecx + ecx * 2 ] shr ebx , 5 neg ecx mov [ counter_x ] , ebx lea ecx , [ ref_point + ecx + ecx * 2 ] mov [ entry ] , ecx outter_loop: push esi push edi xor ecx , ecx mov ebx , [ counter_x ] jmp [ entry ] inner_loop: // REPT not supported for inline asm. ST - 12/19/2018 6:11PM //REPT 32 push ebx //ST - 12/19/2018 6:11PM mov ebx,32 //ST - 12/19/2018 6:11PM rept_loop: mov cl , [ esi ] add ecx , eax adc esi , edx mov [ edi ] , cl inc edi dec ebx //ST - 12/19/2018 6:11PM jnz rept_loop //ST - 12/19/2018 6:11PM pop ebx //ST - 12/19/2018 6:11PM //ENDM ref_point: dec ebx jge inner_loop pop edi pop esi add edi , [ dst_win_width ] add esi , [ dy_intr ] mov ebx , [ dy_acc ] add ebx , [ dy_frac ] jle skip_line add esi , [ src_win_width ] sub ebx , [ dst_height ] skip_line: dec [ counter_y ] mov [ dy_acc ] , ebx jnz outter_loop jmp all_done //ret ; ************************************************************************* ; normal scale with remap normal_remap: mov ecx , ebx mov [ dx_frac ], eax and ecx , 01fh mov eax , [ remap ] shr ebx , 5 imul ecx , - 13 mov [ counter_x ] , ebx lea ecx , [ remapref_point + ecx ] mov [ entry ] , ecx remapoutter_loop: mov ebx , [ counter_x ] push esi mov [ remap_counter ] , ebx push edi xor ecx , ecx xor ebx , ebx jmp [ entry ] remapinner_loop: // REPT not supported for inline asm. ST - 12/19/2018 6:11PM //REPT 32 mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi mov bl , [ esi ] add ecx , [ dx_frac ] adc esi , edx mov cl , [ eax + ebx ] mov [ edi ] , cl inc edi //ENDM remapref_point: dec [ remap_counter ] jge remapinner_loop pop edi pop esi add edi , [ dst_win_width ] add esi , [ dy_intr ] mov ebx , [ dy_acc ] add ebx , [ dy_frac ] jle remapskip_line add esi , [ src_win_width ] sub ebx , [ dst_height ] remapskip_line: dec [ counter_y ] mov [ dy_acc ] , ebx jnz remapoutter_loop jmp all_done //ret ;**************************************************************************** ; scale with trnsparency transparency: cmp [ remap ] , 0 jnz trans_remap ; ************************************************************************* ; normal scale with transparency mov ecx , ebx and ecx , 01fh imul ecx , -13 shr ebx , 5 mov [ counter_x ] , ebx lea ecx , [ trans_ref_point + ecx ] mov [ entry ] , ecx trans_outter_loop: xor ecx , ecx push esi push edi mov ebx , [ counter_x ] jmp [ entry ] trans_inner_loop: // REPT not supported for inline asm. ST - 12/19/2018 6:11PM //REPT 32 push ebx //ST - 12/19/2018 6:11PM mov ebx,32 //ST - 12/19/2018 6:11PM rept_loop2: mov cl , [ esi ] test cl , cl jz trans_pixel mov [ edi ] , cl trans_pixel: add ecx , eax adc esi , edx inc edi dec ebx //ST - 12/19/2018 6:11PM jnz rept_loop2 //ST - 12/19/2018 6:11PM pop ebx //ST - 12/19/2018 6:11PM //ENDM trans_ref_point: dec ebx jge trans_inner_loop pop edi pop esi add edi , [ dst_win_width ] add esi , [ dy_intr ] mov ebx , [ dy_acc ] add ebx , [ dy_frac ] jle trans_skip_line add esi , [ src_win_width ] sub ebx , [ dst_height ] trans_skip_line: dec [ counter_y ] mov [ dy_acc ] , ebx jnz trans_outter_loop jmp all_done //ret ; ************************************************************************* ; normal scale with remap trans_remap: mov ecx , ebx mov [ dx_frac ], eax and ecx , 01fh mov eax , [ remap ] shr ebx , 5 imul ecx , - 17 mov [ counter_x ] , ebx lea ecx , [ trans_remapref_point + ecx ] mov [ entry ] , ecx trans_remapoutter_loop: mov ebx , [ counter_x ] push esi mov [ remap_counter ] , ebx push edi xor ecx , ecx xor ebx , ebx jmp [ entry ] trans_remapinner_loop: // REPT not supported for inline asm. ST - 12/19/2018 6:11PM //REPT 32 // Run out of registers so use ebp push ebp //ST - 12/19/2018 6:11PM mov ebp,32 //ST - 12/19/2018 6:11PM rept_loop3: mov bl , [ esi ] test bl , bl jz trans_pixel2 mov cl , [ eax + ebx ] mov [ edi ] , cl trans_pixel2: add ecx , [ dx_frac ] adc esi , edx inc edi dec ebp //ST - 12/19/2018 6:11PM jnz rept_loop3 //ST - 12/19/2018 6:11PM pop ebp //ST - 12/19/2018 6:11PM //ENDM trans_remapref_point: dec [ remap_counter ] jge trans_remapinner_loop pop edi pop esi add edi , [ dst_win_width ] add esi , [ dy_intr ] mov ebx , [ dy_acc ] add ebx , [ dy_frac ] jle trans_remapskip_line add esi , [ src_win_width ] sub ebx , [ dst_height ] trans_remapskip_line: dec [ counter_y ] mov [ dy_acc ] , ebx jnz trans_remapoutter_loop //ret all_done: } } #pragma warning (pop) unsigned int LastIconset = 0; unsigned int StampPtr = 0; // DD 0 ; Pointer to icon data. unsigned int IsTrans = 0; // DD 0 ; Pointer to transparent icon flag table. unsigned int MapPtr = 0; // DD 0 ; Pointer to icon map. unsigned int IconWidth = 0; // DD 0 ; Width of icon in pixels. unsigned int IconHeight = 0; // DD 0 ; Height of icon in pixels. unsigned int IconSize = 0; // DD 0 ; Number of bytes for each icon data. unsigned int IconCount = 0; // DD 0 ; Number of icons in the set. #if (0) LastIconset DD 0 ; Pointer to last iconset initialized. StampPtr DD 0 ; Pointer to icon data. IsTrans DD 0 ; Pointer to transparent icon flag table. MapPtr DD 0 ; Pointer to icon map. IconWidth DD 0 ; Width of icon in pixels. IconHeight DD 0 ; Height of icon in pixels. IconSize DD 0 ; Number of bytes for each icon data. IconCount DD 0 ; Number of icons in the set. GLOBAL C Buffer_Draw_Stamp:near GLOBAL C Buffer_Draw_Stamp_Clip:near ; 256 color icon system. #endif /* ;*********************************************************** ; INIT_STAMPS ; ; VOID cdecl Init_Stamps(VOID *icondata); ; ; This routine initializes the stamp data. ; Bounds Checking: NONE ; ;* */ extern "C" void __cdecl Init_Stamps(unsigned int icondata) { __asm { pushad // ST - 12/20/2018 10:30AM ; Verify legality of parameter. cmp [icondata],0 je short fini ; Don't initialize if already initialized to this set (speed reasons). mov edi,[icondata] cmp [LastIconset],edi je short fini mov [LastIconset],edi ; Record number of icons in set. movzx eax,[edi]IControl_Type.Count mov [IconCount],eax ; Record width of icon. movzx eax,[edi]IControl_Type.Width mov [IconWidth],eax ; Record height of icon. movzx ebx,[edi]IControl_Type.Height mov [IconHeight],ebx ; Record size of icon (in bytes). mul ebx mov [IconSize],eax ; Record hard pointer to icon map data. mov eax,[edi]IControl_Type.Map add eax,edi mov [MapPtr],eax //nomap: ; Record hard pointer to icon data. mov eax,edi add eax,[edi]IControl_Type.Icons mov [StampPtr],eax ; Record the transparent table. mov eax,edi add eax,[edi]IControl_Type.TransFlag mov [IsTrans],eax fini: popad // ST - 12/20/2018 10:30AM } } /* ;*********************************************************** ;*********************************************************** ; DRAW_STAMP ; ; VOID cdecl Buffer_Draw_Stamp(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap); ; ; This routine renders the icon at the given coordinate. ; ; The remap table is a 256 byte simple pixel translation table to use when ; drawing the icon. Transparency check is performed AFTER the remap so it is possible to ; remap valid colors to be invisible (for special effect reasons). ; This routine is fastest when no remap table is passed in. ;* */ void __cdecl Buffer_Draw_Stamp(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap) { unsigned int modulo = 0; unsigned int iwidth = 0; unsigned char doremap = 0; /* PROC Buffer_Draw_Stamp C near ARG this_object:DWORD ; this is a member function ARG icondata:DWORD ; Pointer to icondata. ARG icon:DWORD ; Icon number to draw. ARG x_pixel:DWORD ; X coordinate of icon. ARG y_pixel:DWORD ; Y coordinate of icon. ARG remap:DWORD ; Remap table. LOCAL modulo:DWORD ; Modulo to get to next row. LOCAL iwidth:DWORD ; Icon width (here for speedy access). LOCAL doremap:BYTE ; Should remapping occur? */ __asm { pushad cmp [icondata],0 je proc_out ; Initialize the stamp data if necessary. mov eax,[icondata] cmp [LastIconset],eax je short noreset push eax call Init_Stamps pop eax // Clean up stack. ST - 12/20/2018 10:42AM noreset: ; Determine if the icon number requested is actually in the set. ; Perform the logical icon to actual icon number remap if necessary. mov ebx,[icon] cmp [MapPtr],0 je short notmap mov edi,[MapPtr] mov bl,[edi+ebx] notmap: cmp ebx,[IconCount] jae proc_out mov [icon],ebx ; Updated icon number. ; If the remap table pointer passed in is NULL, then flag this condition ; so that the faster (non-remapping) icon draw loop will be used. cmp [remap],0 setne [doremap] ; Get pointer to position to render icon. EDI = ptr to destination page. mov ebx,[this_object] mov edi,[ebx]GraphicViewPortClass.Offset mov eax,[ebx]GraphicViewPortClass.Width add eax,[ebx]GraphicViewPortClass.XAdd add eax,[ebx]GraphicViewPortClass.Pitch push eax ; save viewport full width for lower mul [y_pixel] add edi,eax add edi,[x_pixel] ; Determine row modulo for advancing to next line. pop eax ; retrieve viewport width sub eax,[IconWidth] mov [modulo],eax ; Setup some working variables. mov ecx,[IconHeight] ; Row counter. mov eax,[IconWidth] mov [iwidth],eax ; Stack copy of byte width for easy BP access. ; Fetch pointer to start of icon's data. ESI = ptr to icon data. mov eax,[icon] mul [IconSize] mov esi,[StampPtr] add esi,eax ; Determine whether simple icon draw is sufficient or whether the ; extra remapping icon draw is needed. cmp [BYTE PTR doremap],0 je short istranscheck ;************************************************************ ; Complex icon draw -- extended remap. ; EBX = Palette pointer (ready for XLAT instruction). ; EDI = Pointer to icon destination in page. ; ESI = Pointer to icon data. ; ECX = Number of pixel rows. ;;; mov edx,[remap] mov ebx,[remap] xor eax,eax xrowloop: push ecx mov ecx,[iwidth] xcolumnloop: lodsb ;;; mov ebx,edx ;;; add ebx,eax ;;; mov al,[ebx] ; New real color to draw. xlatb or al,al jz short xskip1 ; Transparency skip check. mov [edi],al xskip1: inc edi loop xcolumnloop pop ecx add edi,[modulo] loop xrowloop jmp short proc_out ;************************************************************ ; Check to see if transparent or generic draw is necessary. istranscheck: mov ebx,[IsTrans] add ebx,[icon] cmp [BYTE PTR ebx],0 jne short rowloop ;************************************************************ ; Fast non-transparent icon draw routine. ; ES:DI = Pointer to icon destination in page. ; DS:SI = Pointer to icon data. ; CX = Number of pixel rows. mov ebx,ecx shr ebx,2 mov edx,[modulo] mov eax,[iwidth] shr eax,2 loop1: mov ecx,eax rep movsd add edi,edx mov ecx,eax rep movsd add edi,edx mov ecx,eax rep movsd add edi,edx mov ecx,eax rep movsd add edi,edx dec ebx jnz loop1 jmp short proc_out ;************************************************************ ; Transparent icon draw routine -- no extended remap. ; ES:DI = Pointer to icon destination in page. ; DS:SI = Pointer to icon data. ; CX = Number of pixel rows. rowloop: push ecx mov ecx,[iwidth] columnloop: lodsb or al,al jz short skip1 ; Transparency check. mov [edi],al skip1: inc edi loop columnloop pop ecx add edi,[modulo] loop rowloop ; Cleanup and exit icon drawing routine. proc_out: popad //ret } } /* ;*********************************************************** ; DRAW_STAMP_CLIP ; ; VOID cdecl MCGA_Draw_Stamp_Clip(VOID *icondata, WORD icon, WORD x_pixel, WORD y_pixel, VOID *remap, LONG min_x, LONG min_y, LONG max_x, LONG max_y); ; ; This routine renders the icon at the given coordinate. ; ; The remap table is a 256 byte simple pixel translation table to use when ; drawing the icon. Transparency check is performed AFTER the remap so it is possible to ; remap valid colors to be invisible (for special effect reasons). ; This routine is fastest when no remap table is passed in. ;* */ void __cdecl Buffer_Draw_Stamp_Clip(void const *this_object, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap, int min_x, int min_y, int max_x, int max_y) { unsigned int modulo = 0; unsigned int iwidth = 0; unsigned int skip = 0; unsigned char doremap = 0; /* ARG this_object:DWORD ; this is a member function ARG icondata:DWORD ; Pointer to icondata. ARG icon:DWORD ; Icon number to draw. ARG x_pixel:DWORD ; X coordinate of icon. ARG y_pixel:DWORD ; Y coordinate of icon. ARG remap:DWORD ; Remap table. ARG min_x:DWORD ; Clipping rectangle boundary ARG min_y:DWORD ; Clipping rectangle boundary ARG max_x:DWORD ; Clipping rectangle boundary ARG max_y:DWORD ; Clipping rectangle boundary LOCAL modulo:DWORD ; Modulo to get to next row. LOCAL iwidth:DWORD ; Icon width (here for speedy access). LOCAL skip:DWORD ; amount to skip per row of icon data LOCAL doremap:BYTE ; Should remapping occur? */ __asm { pushad cmp [icondata],0 je proc_out ; Initialize the stamp data if necessary. mov eax,[icondata] cmp [LastIconset],eax je short noreset2 push eax call Init_Stamps pop eax // Clean up stack. ST - 12/20/2018 10:42AM noreset2: ; Determine if the icon number requested is actually in the set. ; Perform the logical icon to actual icon number remap if necessary. mov ebx,[icon] cmp [MapPtr],0 je short notmap2 mov edi,[MapPtr] mov bl,[edi+ebx] notmap2: cmp ebx,[IconCount] jae proc_out mov [icon],ebx ; Updated icon number. ; Setup some working variables. mov ecx,[IconHeight] ; Row counter. mov eax,[IconWidth] mov [iwidth],eax ; Stack copy of byte width for easy BP access. ; Fetch pointer to start of icon's data. ESI = ptr to icon data. mov eax,[icon] mul [IconSize] mov esi,[StampPtr] add esi,eax ; Update the clipping window coordinates to be valid maxes instead of width & height ; , and change the coordinates to be window-relative mov ebx,[min_x] add [max_x],ebx add [x_pixel],ebx ; make it window-relative mov ebx,[min_y] add [max_y],ebx add [y_pixel],ebx ; make it window-relative ; See if the icon is within the clipping window ; First, verify that the icon position is less than the maximums mov ebx,[x_pixel] cmp ebx,[max_x] jge proc_out mov ebx,[y_pixel] cmp ebx,[max_y] jge proc_out ; Now verify that the icon position is >= the minimums add ebx,[IconHeight] cmp ebx,[min_y] jle proc_out mov ebx,[x_pixel] add ebx,[IconWidth] cmp ebx,[min_x] jle proc_out ; Now, clip the x, y, width, and height variables to be within the ; clipping rectangle mov ebx,[x_pixel] cmp ebx,[min_x] jge nominxclip ; x < minx, so must clip mov ebx,[min_x] sub ebx,[x_pixel] add esi,ebx ; source ptr += (minx - x) sub [iwidth],ebx ; icon width -= (minx - x) mov ebx,[min_x] mov [x_pixel],ebx nominxclip: mov eax,[IconWidth] sub eax,[iwidth] mov [skip],eax ; Check for x+width > max_x mov eax,[x_pixel] add eax,[iwidth] cmp eax,[max_x] jle nomaxxclip ; x+width is greater than max_x, so must clip width down mov eax,[iwidth] ; eax = old width mov ebx,[max_x] sub ebx,[x_pixel] mov [iwidth],ebx ; iwidth = max_x - xpixel sub eax,ebx add [skip],eax ; skip += (old width - iwidth) nomaxxclip: ; check if y < miny mov eax,[min_y] cmp eax,[y_pixel] ; if(miny <= y_pixel), no clip needed jle nominyclip sub eax,[y_pixel] sub ecx,eax ; height -= (miny - y) mul [IconWidth] add esi,eax ; icon source ptr += (width * (miny - y)) mov eax,[min_y] mov [y_pixel],eax ; y = miny nominyclip: ; check if (y+height) > max y mov eax,[y_pixel] add eax,ecx cmp eax,[max_y] ; if (y + height <= max_y), no clip needed jle nomaxyclip mov ecx,[max_y] ; height = max_y - y_pixel sub ecx,[y_pixel] nomaxyclip: ; If the remap table pointer passed in is NULL, then flag this condition ; so that the faster (non-remapping) icon draw loop will be used. cmp [remap],0 setne [doremap] ; Get pointer to position to render icon. EDI = ptr to destination page. mov ebx,[this_object] mov edi,[ebx]GraphicViewPortClass.Offset mov eax,[ebx]GraphicViewPortClass.Width add eax,[ebx]GraphicViewPortClass.XAdd add eax,[ebx]GraphicViewPortClass.Pitch push eax ; save viewport full width for lower mul [y_pixel] add edi,eax add edi,[x_pixel] ; Determine row modulo for advancing to next line. pop eax ; retrieve viewport width sub eax,[iwidth] mov [modulo],eax ; Determine whether simple icon draw is sufficient or whether the ; extra remapping icon draw is needed. cmp [BYTE PTR doremap],0 je short istranscheck2 ;************************************************************ ; Complex icon draw -- extended remap. ; EBX = Palette pointer (ready for XLAT instruction). ; EDI = Pointer to icon destination in page. ; ESI = Pointer to icon data. ; ECX = Number of pixel rows. mov ebx,[remap] xor eax,eax xrowloopc: push ecx mov ecx,[iwidth] xcolumnloopc: lodsb xlatb or al,al jz short xskip1c ; Transparency skip check. mov [edi],al xskip1c: inc edi loop xcolumnloopc pop ecx add edi,[modulo] add esi,[skip] loop xrowloopc jmp short proc_out ;************************************************************ ; Check to see if transparent or generic draw is necessary. istranscheck2: mov ebx,[IsTrans] add ebx,[icon] cmp [BYTE PTR ebx],0 jne short rowloopc ;************************************************************ ; Fast non-transparent icon draw routine. ; ES:DI = Pointer to icon destination in page. ; DS:SI = Pointer to icon data. ; CX = Number of pixel rows. mov ebx,ecx mov edx,[modulo] mov eax,[iwidth] ; ; Optimise copy by dword aligning the destination ; loop1c: push eax //rept 3 // No rept in inline asm. ST - 12/20/2018 10:43AM test edi,3 jz aligned movsb dec eax jz finishedit test edi,3 jz aligned movsb dec eax jz finishedit test edi,3 jz aligned movsb dec eax jz finishedit //endm aligned: mov ecx,eax shr ecx,2 rep movsd mov ecx,eax and ecx,3 rep movsb finishedit: add edi,edx add esi,[skip] pop eax dec ebx jnz loop1c jmp short proc_out ;************************************************************ ; Transparent icon draw routine -- no extended remap. ; ES:DI = Pointer to icon destination in page. ; DS:SI = Pointer to icon data. ; CX = Number of pixel rows. rowloopc: push ecx mov ecx,[iwidth] columnloopc: lodsb or al,al jz short skip1c ; Transparency check. mov [edi],al skip1c: inc edi loop columnloopc pop ecx add edi,[modulo] add esi,[skip] loop rowloopc ; Cleanup and exit icon drawing routine. proc_out: popad //ret } } VOID __cdecl Buffer_Draw_Line(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Fill_Rect(void *thisptr, int sx, int sy, int dx, int dy, unsigned char color); VOID __cdecl Buffer_Remap(void * thisptr, int sx, int sy, int width, int height, void *remap); VOID __cdecl Buffer_Fill_Quad(void * thisptr, VOID *span_buff, int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, int color); void __cdecl Buffer_Draw_Stamp(void const *thisptr, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap); void __cdecl Buffer_Draw_Stamp_Clip(void const *thisptr, void const *icondata, int icon, int x_pixel, int y_pixel, void const *remap, int ,int,int,int); void * __cdecl Get_Font_Palette_Ptr ( void ); /* ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Westwood 32 bit Library * ;* * ;* File Name : REMAP.ASM * ;* * ;* Programmer : Phil W. Gorrow * ;* * ;* Start Date : July 1, 1994 * ;* * ;* Last Update : July 1, 1994 [PWG] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * */ VOID __cdecl Buffer_Remap(void * this_object, int sx, int sy, int width, int height, void *remap) { /* PROC Buffer_Remap C NEAR USES eax,ebx,ecx,edx,esi,edi ;*=================================================================== ;* Define the arguements that our function takes. ;*=================================================================== ARG this_object:DWORD ARG x0_pixel:DWORD ARG y0_pixel:DWORD ARG region_width:DWORD ARG region_height:DWORD ARG remap :DWORD ;*=================================================================== ; Define some locals so that we can handle things quickly ;*=================================================================== local x1_pixel : DWORD local y1_pixel : DWORD local win_width : dword local counter_x : dword */ unsigned int x0_pixel = (unsigned int) sx; unsigned int y0_pixel = (unsigned int) sy; unsigned int region_width = (unsigned int) width; unsigned int region_height = (unsigned int) height; unsigned int x1_pixel = 0; unsigned int y1_pixel = 0; unsigned int win_width = 0; unsigned int counter_x = 0; __asm { cmp [ remap ] , 0 jz real_out ; Clip Source Rectangle against source Window boundaries. mov esi , [ this_object ] ; get ptr to src xor ecx , ecx xor edx , edx mov edi , [esi]GraphicViewPortClass.Width ; get width into register mov ebx , [ x0_pixel ] mov eax , [ x0_pixel ] add ebx , [ region_width ] shld ecx , eax , 1 mov [ x1_pixel ] , ebx inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 mov edi,[esi]GraphicViewPortClass.Height ; get height into register mov ebx , [ y0_pixel ] mov eax , [ y0_pixel ] add ebx , [ region_height ] shld ecx , eax , 1 mov [ y1_pixel ] , ebx inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 xor cl , 5 xor dl , 5 mov al , cl test dl , cl jnz real_out or al , dl jz do_remap test cl , 1000b jz scr_left_ok mov [ x0_pixel ] , 0 scr_left_ok: test cl , 0010b jz scr_bottom_ok mov [ y0_pixel ] , 0 scr_bottom_ok: test dl , 0100b jz scr_right_ok mov eax , [esi]GraphicViewPortClass.Width ; get width into register mov [ x1_pixel ] , eax scr_right_ok: test dl , 0001b jz do_remap mov eax , [esi]GraphicViewPortClass.Height ; get width into register mov [ y1_pixel ] , eax do_remap: cld mov edi , [esi]GraphicViewPortClass.Offset mov eax , [esi]GraphicViewPortClass.XAdd mov ebx , [ x1_pixel ] add eax , [esi]GraphicViewPortClass.Width add eax , [esi]GraphicViewPortClass.Pitch mov esi , eax mul [ y0_pixel ] add edi , [ x0_pixel ] sub ebx , [ x0_pixel ] jle real_out add edi , eax sub esi , ebx mov ecx , [ y1_pixel ] sub ecx , [ y0_pixel ] jle real_out mov eax , [ remap ] mov [ counter_x ] , ebx xor edx , edx outer_loop: mov ebx , [ counter_x ] inner_loop: mov dl , [ edi ] mov dl , [ eax + edx ] mov [ edi ] , dl inc edi dec ebx jnz inner_loop add edi , esi dec ecx jnz outer_loop real_out: // ret } } /* ; ************************************************************************** ; ** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S * ; ************************************************************************** ; * * ; * Project Name : WSA Support routines * ; * * ; * File Name : XORDELTA.ASM * ; * * ; * Programmer : Scott K. Bowen * ; * * ; * Last Update :May 23, 1994 [SKB] * ; * * ; *------------------------------------------------------------------------* ; * Functions: * ;* Apply_XOR_Delta -- Apply XOR delta data to a buffer. * ;* Apply_XOR_Delta_To_Page_Or_Viewport -- Calls the copy or the XOR funti* ;* Copy_Delta_buffer -- Copies XOR Delta Data to a section of a page. * ;* XOR_Delta_Buffer -- Xor's the data in a XOR Delta format to a page. * ; * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -* IDEAL P386 MODEL USE32 FLAT */ /* LOCALS ?? ; These are used to call Apply_XOR_Delta_To_Page_Or_Viewport() to setup flags parameter. If ; These change, make sure and change their values in wsa.cpp. DO_XOR equ 0 DO_COPY equ 1 TO_VIEWPORT equ 0 TO_PAGE equ 2 ; ; Routines defined in this module ; ; ; UWORD Apply_XOR_Delta(UWORD page_seg, BYTE *delta_ptr); ; PUBLIC Apply_XOR_Delta_To_Page_Or_Viewport(UWORD page_seg, BYTE *delta_ptr, WORD width, WORD copy) ; ; PROC C XOR_Delta_Buffer ; PROC C Copy_Delta_Buffer ; GLOBAL C Apply_XOR_Delta:NEAR GLOBAL C Apply_XOR_Delta_To_Page_Or_Viewport:NEAR */ #define DO_XOR 0 #define DO_COPY 1 #define TO_VIEWPORT 0 #define TO_PAGE 2 void __cdecl XOR_Delta_Buffer(int nextrow); void __cdecl Copy_Delta_Buffer(int nextrow); /* ;*************************************************************************** ;* APPLY_XOR_DELTA -- Apply XOR delta data to a linear buffer. * ;* AN example of this in C is at the botton of the file commented out. * ;* * ;* INPUT: BYTE *target - destination buffer. * ;* BYTE *delta - xor data to be delta uncompress. * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 05/23/1994 SKB : Created. * ;*=========================================================================* */ unsigned int __cdecl Apply_XOR_Delta(char *target, char *delta) { /* PROC Apply_XOR_Delta C near USES ebx,ecx,edx,edi,esi ARG target:DWORD ; pointers. ARG delta:DWORD ; pointers. */ __asm { ; Optimized for 486/pentium by rearanging instructions. mov edi,[target] ; get our pointers into offset registers. mov esi,[delta] cld ; make sure we go forward xor ecx,ecx ; use cx for loop top_loop: xor eax,eax ; clear out eax. mov al,[esi] ; get delta source byte inc esi test al,al ; check for a SHORTDUMP ; check al incase of sign value. je short_run js check_others ; ; SHORTDUMP ; mov ecx,eax ; stick count in cx dump_loop: mov al,[esi] ;get delta XOR byte xor [edi],al ; xor that byte on the dest inc esi inc edi dec ecx jnz dump_loop jmp top_loop ; ; SHORTRUN ; short_run: mov cl,[esi] ; get count inc esi ; inc delta source do_run: mov al,[esi] ; get XOR byte inc esi run_loop: xor [edi],al ; xor that byte. inc edi ; go to next dest pixel dec ecx ; one less to go. jnz run_loop jmp top_loop ; ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP ; check_others: sub eax,080h ; opcode -= 0x80 jnz do_skip ; if zero then get next word, otherwise use remainder. mov ax,[esi] lea esi,[esi+2] ; get word code in ax test ax,ax ; set flags. (not 32bit register so neg flag works) jle not_long_skip ; ; SHORTSKIP AND LONGSKIP ; do_skip: add edi,eax ; do the skip. jmp top_loop not_long_skip: jz stop ; long count of zero means stop sub eax,08000h ; opcode -= 0x8000 test eax,04000h ; is it a LONGRUN (code & 0x4000)? je long_dump ; ; LONGRUN ; sub eax,04000h ; opcode -= 0x4000 mov ecx,eax ; use cx as loop count jmp do_run ; jump to run code. ; ; LONGDUMP ; long_dump: mov ecx,eax ; use cx as loop count jmp dump_loop ; go to the dump loop. stop: } } /* ;---------------------------------------------------------------------------- ;*************************************************************************** ;* APPLY_XOR_DELTA_To_Page_Or_Viewport -- Calls the copy or the XOR funtion. * ;* * ;* * ;* This funtion is call to either xor or copy XOR_Delta data onto a * ;* page instead of a buffer. The routine will set up the registers * ;* need for the actual routines that will perform the copy or xor. * ;* * ;* The registers are setup as follows : * ;* es:edi - destination segment:offset onto page. * ;* ds:esi - source buffer segment:offset of delta data. * ;* dx,cx,ax - are all zeroed out before entry. * ;* * ;* INPUT: * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 03/09/1992 SB : Created. * ;*=========================================================================* */ void __cdecl Apply_XOR_Delta_To_Page_Or_Viewport(void *target, void *delta, int width, int nextrow, int copy) { /* USES ebx,ecx,edx,edi,esi ARG target:DWORD ; pointer to the destination buffer. ARG delta:DWORD ; pointer to the delta buffer. ARG width:DWORD ; width of animation. ARG nextrow:DWORD ; Page/Buffer width - anim width. ARG copy:DWORD ; should it be copied or xor'd? */ __asm { mov edi,[target] ; Get the target pointer. mov esi,[delta] ; Get the destination pointer. xor eax,eax ; clear eax, later put them into ecx and edx. cld ; make sure we go forward mov ebx,[nextrow] ; get the amount to add to get to next row from end. push it later... mov ecx,eax ; use cx for loop mov edx,eax ; use dx to count the relative column. push ebx ; push nextrow onto the stack for Copy/XOR_Delta_Buffer. mov ebx,[width] ; bx will hold the max column for speed compares ; At this point, all the registers have been set up. Now call the correct function ; to either copy or xor the data. cmp [copy],DO_XOR ; Do we want to copy or XOR je xorfunct ; Jump to XOR if not copy call Copy_Delta_Buffer ; Call the function to copy the delta buffer. jmp didcopy ; jump past XOR xorfunct: call XOR_Delta_Buffer ; Call funtion to XOR the deltat buffer. didcopy: pop ebx ; remove the push done to pass a value. } } /* ;---------------------------------------------------------------------------- ;*************************************************************************** ;* XOR_DELTA_BUFFER -- Xor's the data in a XOR Delta format to a page. * ;* This will only work right if the page has the previous data on it. * ;* This function should only be called by XOR_Delta_Buffer_To_Page_Or_Viewport. * ;* The registers must be setup as follows : * ;* * ;* INPUT: * ;* es:edi - destination segment:offset onto page. * ;* ds:esi - source buffer segment:offset of delta data. * ;* edx,ecx,eax - are all zeroed out before entry. * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 03/09/1992 SB : Created. * ;*=========================================================================* */ void __cdecl XOR_Delta_Buffer(int nextrow) { /* ARG nextrow:DWORD */ __asm { top_loop: xor eax,eax ; clear out eax. mov al,[esi] ; get delta source byte inc esi test al,al ; check for a SHORTDUMP ; check al incase of sign value. je short_run js check_others ; ; SHORTDUMP ; mov ecx,eax ; stick count in cx dump_loop: mov al,[esi] ; get delta XOR byte xor [edi],al ; xor that byte on the dest inc esi inc edx ; increment our count on current column inc edi cmp edx,ebx ; are we at the final column jne end_col1 ; if not the jmp over the code sub edi,edx ; get our column back to the beginning. xor edx,edx ; zero out our column counter add edi,[nextrow] ; jump to start of next row end_col1: dec ecx jnz dump_loop jmp top_loop ; ; SHORTRUN ; short_run: mov cl,[esi] ; get count inc esi ; inc delta source do_run: mov al,[esi] ; get XOR byte inc esi run_loop: xor [edi],al ; xor that byte. inc edx ; increment our count on current column inc edi ; go to next dest pixel cmp edx,ebx ; are we at the final column jne end_col2 ; if not the jmp over the code sub edi,ebx ; get our column back to the beginning. xor edx,edx ; zero out our column counter add edi,[nextrow] ; jump to start of next row end_col2: dec ecx jnz run_loop jmp top_loop ; ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP ; check_others: sub eax,080h ; opcode -= 0x80 jnz do_skip ; if zero then get next word, otherwise use remainder. mov ax,[esi] ; get word code in ax lea esi,[esi+2] test ax,ax ; set flags. (not 32bit register so neg flag works) jle not_long_skip ; ; SHORTSKIP AND LONGSKIP ; do_skip: sub edi,edx ; go back to beginning or row. add edx,eax ; incriment our count on current row recheck3: cmp edx,ebx ; are we past the end of the row jb end_col3 ; if not the jmp over the code sub edx,ebx ; Subtract width from the col counter add edi,[nextrow] ; jump to start of next row jmp recheck3 ; jump up to see if we are at the right row end_col3: add edi,edx ; get to correct position in row. jmp top_loop not_long_skip: jz stop ; long count of zero means stop sub eax,08000h ; opcode -= 0x8000 test eax,04000h ; is it a LONGRUN (code & 0x4000)? je long_dump ; ; LONGRUN ; sub eax,04000h ; opcode -= 0x4000 mov ecx,eax ; use cx as loop count jmp do_run ; jump to run code. ; ; LONGDUMP ; long_dump: mov ecx,eax ; use cx as loop count jmp dump_loop ; go to the dump loop. stop: } } /* ;---------------------------------------------------------------------------- ;*************************************************************************** ;* COPY_DELTA_BUFFER -- Copies XOR Delta Data to a section of a page. * ;* This function should only be called by XOR_Delta_Buffer_To_Page_Or_Viewport. * ;* The registers must be setup as follows : * ;* * ;* INPUT: * ;* es:edi - destination segment:offset onto page. * ;* ds:esi - source buffer segment:offset of delta data. * ;* dx,cx,ax - are all zeroed out before entry. * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 03/09/1992 SB : Created. * ;*=========================================================================* */ void __cdecl Copy_Delta_Buffer(int nextrow) { /* ARG nextrow:DWORD */ __asm { top_loop: xor eax,eax ; clear out eax. mov al,[esi] ; get delta source byte inc esi test al,al ; check for a SHORTDUMP ; check al incase of sign value. je short_run js check_others ; ; SHORTDUMP ; mov ecx,eax ; stick count in cx dump_loop: mov al,[esi] ; get delta XOR byte mov [edi],al ; store that byte on the dest inc edx ; increment our count on current column inc esi inc edi cmp edx,ebx ; are we at the final column jne end_col1 ; if not the jmp over the code sub edi,edx ; get our column back to the beginning. xor edx,edx ; zero out our column counter add edi,[nextrow] ; jump to start of next row end_col1: dec ecx jnz dump_loop jmp top_loop ; ; SHORTRUN ; short_run: mov cl,[esi] ; get count inc esi ; inc delta source do_run: mov al,[esi] ; get XOR byte inc esi run_loop: mov [edi],al ; store the byte (instead of XOR against current color) inc edx ; increment our count on current column inc edi ; go to next dest pixel cmp edx,ebx ; are we at the final column jne end_col2 ; if not the jmp over the code sub edi,ebx ; get our column back to the beginning. xor edx,edx ; zero out our column counter add edi,[nextrow] ; jump to start of next row end_col2: dec ecx jnz run_loop jmp top_loop ; ; By now, we know it must be a LONGDUMP, SHORTSKIP, LONGRUN, or LONGSKIP ; check_others: sub eax,080h ; opcode -= 0x80 jnz do_skip ; if zero then get next word, otherwise use remainder. mov ax,[esi] ; get word code in ax lea esi,[esi+2] test ax,ax ; set flags. (not 32bit register so neg flag works) jle not_long_skip ; ; SHORTSKIP AND LONGSKIP ; do_skip: sub edi,edx ; go back to beginning or row. add edx,eax ; incriment our count on current row recheck3: cmp edx,ebx ; are we past the end of the row jb end_col3 ; if not the jmp over the code sub edx,ebx ; Subtract width from the col counter add edi,[nextrow] ; jump to start of next row jmp recheck3 ; jump up to see if we are at the right row end_col3: add edi,edx ; get to correct position in row. jmp top_loop not_long_skip: jz stop ; long count of zero means stop sub eax,08000h ; opcode -= 0x8000 test eax,04000h ; is it a LONGRUN (code & 0x4000)? je long_dump ; ; LONGRUN ; sub eax,04000h ; opcode -= 0x4000 mov ecx,eax ; use cx as loop count jmp do_run ; jump to run code. ; ; LONGDUMP ; long_dump: mov ecx,eax ; use cx as loop count jmp dump_loop ; go to the dump loop. stop: } } /* ;---------------------------------------------------------------------------- */ /* ;*************************************************************************** ;** 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 : Westwood Library * ;* * ;* File Name : FADING.ASM * ;* * ;* Programmer : Joe L. Bostic * ;* * ;* Start Date : August 20, 1993 * ;* * ;* Last Update : August 20, 1993 [JLB] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT GLOBAL C Build_Fading_Table :NEAR CODESEG ;*********************************************************** ; BUILD_FADING_TABLE ; ; void *Build_Fading_Table(void *palette, void *dest, long int color, long int frac); ; ; This routine will create the fading effect table used to coerce colors ; from toward a common value. This table is used when Fading_Effect is ; active. ; ; Bounds Checking: None ;* */ void * __cdecl Build_Fading_Table(void const *palette, void const *dest, long int color, long int frac) { /* PROC 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. */ int matchvalue = 0; //:DWORD ; Last recorded match value. unsigned char targetred = 0; //BYTE ; Target gun red. unsigned char targetgreen = 0; //BYTE ; Target gun green. unsigned char targetblue = 0; //BYTE ; Target gun blue. unsigned char idealred = 0; //BYTE unsigned char idealgreen = 0; //BYTE unsigned char idealblue = 0; //BYTE unsigned char matchcolor = 0; //:BYTE ; Tentative match color. __asm { cld ; If the source palette is NULL, then just return with current fading table pointer. cmp [palette],0 je fini cmp [dest],0 je fini ; 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 ax,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 ax,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 ax,1 sub dh,ah ; dh = orig - ((orig-target) * fraction) mov [idealblue],dh ; preserve ideal color gun value. ; Sweep through the entire existing palette to find the closest ; matching color. Never matches with color 0. mov eax,[color] mov [matchcolor],al ; Default color (self). mov [matchvalue],-1 ; Ridiculous match value init. mov ecx,255 mov esi,[palette] ; Pointer to original palette. add esi,3 ; BH = color index. mov bh,1 innerloop: ; Recursion through the fading table won't work if a color is allowed ; to remap to itself. Prevent this from occuring. add esi,3 cmp bh,bl je short notclose sub esi,3 xor edx,edx ; Comparison value starts null. mov eax,edx ; 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] ja 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,255 jne mainloop fini: mov eax,[dest] // ret } } /* ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Westwood Library * ;* * ;* File Name : PAL.ASM * ;* * ;* Programmer : Joe L. Bostic * ;* * ;* Start Date : May 30, 1992 * ;* * ;* Last Update : April 27, 1994 [BR] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* Set_Palette_Range -- Sets changed values in the palette. * ;* Bump_Color -- adjusts specified color in specified palette * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * ;********************** Model & Processor Directives ************************ IDEAL P386 MODEL USE32 FLAT ;include "keyboard.inc" FALSE = 0 TRUE = 1 ;****************************** Declarations ******************************** GLOBAL C Set_Palette_Range:NEAR GLOBAL C Bump_Color:NEAR GLOBAL C CurrentPalette:BYTE:768 GLOBAL C PaletteTable:byte:1024 ;********************************** Data ************************************ LOCALS ?? DATASEG CurrentPalette DB 768 DUP(255) ; copy of current values of DAC regs PaletteTable DB 1024 DUP(0) IFNDEF LIB_EXTERNS_RESOLVED VertBlank DW 0 ; !!!! this should go away ENDIF ;********************************** Code ************************************ CODESEG */ extern "C" unsigned char CurrentPalette[768] = {255}; // DB 768 DUP(255) ; copy of current values of DAC regs extern "C" unsigned char PaletteTable[1024] = {0}; // DB 1024 DUP(0) /* ;*************************************************************************** ;* SET_PALETTE_RANGE -- Sets a palette range to the new pal * ;* * ;* INPUT: * ;* * ;* OUTPUT: * ;* * ;* PROTO: * ;* * ;* WARNINGS: This routine is optimized for changing a small number of * ;* colors in the palette. ;* * ;* HISTORY: * ;* 03/07/1995 PWG : Created. * ;*=========================================================================* */ void __cdecl Set_Palette_Range(void *palette) { memcpy(CurrentPalette, palette, 768); Set_DD_Palette(palette); /* PROC Set_Palette_Range C NEAR ARG palette:DWORD GLOBAL Set_DD_Palette_:near GLOBAL Wait_Vert_Blank_:near pushad mov esi,[palette] mov ecx,768/4 mov edi,offset CurrentPalette cld rep movsd ;call Wait_Vert_Blank_ mov eax,[palette] push eax call Set_DD_Palette_ pop eax popad ret */ } /* ;*************************************************************************** ;* Bump_Color -- adjusts specified color in specified palette * ;* * ;* INPUT: * ;* VOID *palette - palette to modify * ;* WORD changable - color # to change * ;* WORD target - color to bend toward * ;* * ;* OUTPUT: * ;* * ;* WARNINGS: * ;* * ;* HISTORY: * ;* 04/27/1994 BR : Converted to 32-bit. * ;*=========================================================================* ; BOOL cdecl Bump_Color(VOID *palette, WORD changable, WORD target); */ BOOL __cdecl Bump_Color(void *pal, int color, int desired) { /* PROC Bump_Color C NEAR USES ebx,ecx,edi,esi ARG pal:DWORD, color:WORD, desired:WORD LOCAL changed:WORD ; Has palette changed? */ short short_color = (short) color; short short_desired = (short) desired; bool changed = false; __asm { mov edi,[pal] ; Original palette pointer. mov esi,edi mov eax,0 mov ax,[short_color] add edi,eax add edi,eax add edi,eax ; Offset to changable color. mov ax,[short_desired] add esi,eax add esi,eax add esi,eax ; Offset to target color. mov [changed],FALSE ; Presume no change. mov ecx,3 ; Three color guns. ; Check the color gun. colorloop: mov al,[BYTE PTR esi] sub al,[BYTE PTR edi] ; Carry flag is set if subtraction needed. jz short gotit mov [changed],TRUE inc [BYTE PTR edi] ; Presume addition. jnc short gotit ; oops, subtraction needed so dec twice. dec [BYTE PTR edi] dec [BYTE PTR edi] gotit: inc edi inc esi loop colorloop movzx eax,[changed] } } /* ;*************************************************************************** ;** 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 : GraphicViewPortClass * ;* * ;* File Name : PUTPIXEL.ASM * ;* * ;* Programmer : Phil Gorrow * ;* * ;* Start Date : June 7, 1994 * ;* * ;* Last Update : June 8, 1994 [PWG] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* VVPC::Put_Pixel -- Puts a pixel on a virtual viewport * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT INCLUDE ".\drawbuff.inc" INCLUDE ".\gbuffer.inc" CODESEG */ /* ;*************************************************************************** ;* VVPC::PUT_PIXEL -- Puts a pixel on a virtual viewport * ;* * ;* INPUT: WORD the x position for the pixel relative to the upper * ;* left corner of the viewport * ;* WORD the y pos for the pixel relative to the upper left * ;* corner of the viewport * ;* UBYTE the color of the pixel to write * ;* * ;* OUTPUT: none * ;* * ;* WARNING: If pixel is to be placed outside of the viewport then * ;* this routine will abort. * ;* * ;* HISTORY: * ;* 06/08/1994 PWG : Created. * ;*=========================================================================* PROC Buffer_Put_Pixel C near USES eax,ebx,ecx,edx,edi */ void __cdecl Buffer_Put_Pixel(void * this_object, int x_pixel, int y_pixel, unsigned char color) { /* ARG this_object:DWORD ; this is a member function ARG x_pixel:DWORD ; x position of pixel to set ARG y_pixel:DWORD ; y position of pixel to set ARG color:BYTE ; what color should we clear to */ __asm { ;*=================================================================== ; Get the viewport information and put bytes per row in ecx ;*=================================================================== mov ebx,[this_object] ; get a pointer to viewport xor eax,eax mov edi,[ebx]GraphicViewPortClass.Offset ; get the correct offset mov ecx,[ebx]GraphicViewPortClass.Height ; edx = height of viewport mov edx,[ebx]GraphicViewPortClass.Width ; ecx = width of viewport ;*=================================================================== ; Verify that the X pixel offset if legal ;*=================================================================== mov eax,[x_pixel] ; find the x position cmp eax,edx ; is it out of bounds jae short done ; if so then get out add edi,eax ; otherwise add in offset ;*=================================================================== ; Verify that the Y pixel offset if legal ;*=================================================================== mov eax,[y_pixel] ; get the y position cmp eax,ecx ; is it out of bounds jae done ; if so then get out add edx,[ebx]GraphicViewPortClass.XAdd ; otherwise find bytes per row add edx,[ebx]GraphicViewPortClass.Pitch ; add in direct draw pitch mul edx ; offset = bytes per row * y add edi,eax ; add it into the offset ;*=================================================================== ; Write the pixel to the screen ;*=================================================================== mov al,[color] ; read in color value mov [edi],al ; write it to the screen done: } } /* ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Support Library * ;* * ;* File Name : cliprect.asm * ;* * ;* Programmer : Julio R Jerez * ;* * ;* Start Date : Mar, 2 1995 * ;* * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* int Clip_Rect ( int * x , int * y , int * dw , int * dh , * ;* int width , int height ) ; * ;* int Confine_Rect ( int * x , int * y , int * dw , int * dh , * ;* int width , int height ) ; * ;* * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT GLOBAL C Clip_Rect :NEAR GLOBAL C Confine_Rect :NEAR CODESEG ;*************************************************************************** ;* Clip_Rect -- clip a given rectangle against a given window * ;* * ;* INPUT: &x , &y , &w , &h -> Pointer to rectangle being clipped * ;* width , height -> dimension of clipping window * ;* * ;* OUTPUT: a) Zero if the rectangle is totally contained by the * ;* clipping window. * ;* b) A negative value if the rectangle is totally outside the * ;* the clipping window * ;* c) A positive value if the rectangle was clipped against the * ;* clipping window, also the values pointed by x, y, w, h will * ;* be modified to new clipped values * ;* * ;* 05/03/1995 JRJ : added comment * ;*=========================================================================* ; int Clip_Rect (int* x, int* y, int* dw, int* dh, int width, int height); * */ extern "C" int __cdecl Clip_Rect ( int * x , int * y , int * w , int * h , int width , int height ) { /* PROC Clip_Rect C near uses ebx,ecx,edx,esi,edi arg x:dword arg y:dword arg w:dword arg h:dword arg width:dword arg height:dword */ __asm { ;This Clipping algorithm is a derivation of the very well known ;Cohen-Sutherland Line-Clipping test. Due to its simplicity and efficiency ;it is probably the most commontly implemented algorithm both in software ;and hardware for clipping lines, rectangles, and convex polygons against ;a rectagular clipping window. For reference see ;"COMPUTER GRAPHICS principles and practice by Foley, Vandam, Feiner, Hughes ; pages 113 to 177". ; Briefly consist in computing the Sutherland code for both end point of ; the rectangle to find out if the rectangle is: ; - trivially accepted (no further clipping test, return the oroginal data) ; - trivially rejected (return with no action, return error code) ; - retangle must be iteratively clipped again edges of the clipping window ; and return the clipped rectangle ; get all four pointer into regisnters mov esi,[x] ; esi = pointer to x mov edi,[y] ; edi = pointer to x mov eax,[w] ; eax = pointer to dw mov ebx,[h] ; ebx = pointer to dh ; load the actual data into reg mov esi,[esi] ; esi = x0 mov edi,[edi] ; edi = y0 mov eax,[eax] ; eax = dw mov ebx,[ebx] ; ebx = dh ; create a wire frame of the type [x0,y0] , [x1,y1] add eax,esi ; eax = x1 = x0 + dw add ebx,edi ; ebx = y1 = y0 + dh ; we start we suthenland code0 and code1 set to zero xor ecx,ecx ; cl = sutherland boolean code0 xor edx,edx ; dl = sutherland boolean code0 ; now we start computing the to suthenland boolean code for x0 , x1 shld ecx,esi,1 ; bit3 of code0 = sign bit of (x0 - 0) shld edx,eax,1 ; bit3 of code1 = sign bit of (x1 - 0) sub esi,[width] ; get the difference (x0 - (width + 1)) sub eax,[width] ; get the difference (x1 - (width + 1)) dec esi dec eax shld ecx,esi,1 ; bit2 of code0 = sign bit of (x0 - (width + 1)) shld edx,eax,1 ; bit2 of code1 = sign bit of (x0 - (width + 1)) ; now we start computing the to suthenland boolean code for y0 , y1 shld ecx,edi,1 ; bit1 of code0 = sign bit of (y0 - 0) shld edx,ebx,1 ; bit1 of code1 = sign bit of (y0 - 0) sub edi,[height] ; get the difference (y0 - (height + 1)) sub ebx,[height] ; get the difference (y1 - (height + 1)) dec edi dec ebx shld ecx,edi,1 ; bit0 of code0 = sign bit of (y0 - (height + 1)) shld edx,ebx,1 ; bit0 of code1 = sign bit of (y1 - (height + 1)) ; Bit 2 and 0 of cl and bl are complemented xor cl,5 ; reverse bit2 and bit0 in code0 xor dl,5 ; reverse bit2 and bit0 in code1 ; now perform the rejection test mov eax,-1 ; set return code to false mov bl,cl ; save code0 for future use test dl,cl ; if any two pair of bit in code0 and code1 is set jnz clip_out ; then rectangle is outside the window ; now perform the aceptance test xor eax,eax ; set return code to true or bl,dl ; if all pair of bits in code0 and code1 are reset jz clip_out ; then rectangle is insize the window. ' ; we need to clip the rectangle iteratively mov eax,-1 ; set return code to false test cl,1000b ; if bit3 of code0 is set then the rectangle jz left_ok ; spill out the left edge of the window mov edi,[x] ; edi = a pointer to x0 mov ebx,[w] ; ebx = a pointer to dw mov esi,[edi] ; esi = x0 mov [dword ptr edi],0 ; set x0 to 0 "this the left edge value" add [ebx],esi ; adjust dw by x0, since x0 must be negative left_ok: test cl,0010b ; if bit1 of code0 is set then the rectangle jz bottom_ok ; spill out the bottom edge of the window mov edi,[y] ; edi = a pointer to y0 mov ebx,[h] ; ebx = a pointer to dh mov esi,[edi] ; esi = y0 mov [dword ptr edi],0 ; set y0 to 0 "this the bottom edge value" add [ebx],esi ; adjust dh by y0, since y0 must be negative bottom_ok: test dl,0100b ; if bit2 of code1 is set then the rectangle jz right_ok ; spill out the right edge of the window mov edi,[w] ; edi = a pointer to dw mov esi,[x] ; esi = a pointer to x mov ebx,[width] ; ebx = the width of the window sub ebx,[esi] ; the new dw is the difference (width-x0) mov [edi],ebx ; adjust dw to (width - x0) jle clip_out ; if (width-x0) = 0 then the clipped retangle ; has no width we are done right_ok: test dl,0001b ; if bit0 of code1 is set then the rectangle jz clip_ok ; spill out the top edge of the window mov edi,[h] ; edi = a pointer to dh mov esi,[y] ; esi = a pointer to y0 mov ebx,[height] ; ebx = the height of the window sub ebx,[esi] ; the new dh is the difference (height-y0) mov [edi],ebx ; adjust dh to (height-y0) jle clip_out ; if (width-x0) = 0 then the clipped retangle ; has no width we are done clip_ok: mov eax,1 ; signal the calling program that the rectangle was modify clip_out: //ret } //ENDP Clip_Rect } /* ;*************************************************************************** ;* Confine_Rect -- clip a given rectangle against a given window * ;* * ;* INPUT: &x,&y,w,h -> Pointer to rectangle being clipped * ;* width,height -> dimension of clipping window * ;* * ;* OUTPUT: a) Zero if the rectangle is totally contained by the * ;* clipping window. * ;* c) A positive value if the rectangle was shifted in position * ;* to fix inside the clipping window, also the values pointed * ;* by x, y, will adjusted to a new values * ;* * ;* NOTE: this function make not attempt to verify if the rectangle is * ;* bigger than the clipping window and at the same time wrap around* ;* it. If that is the case the result is meaningless * ;*=========================================================================* ; int Confine_Rect (int* x, int* y, int dw, int dh, int width, int height); * */ extern "C" int __cdecl Confine_Rect ( int * x , int * y , int w , int h , int width , int height ) { /* PROC Confine_Rect C near uses ebx, esi,edi arg x:dword arg y:dword arg w:dword arg h:dword arg width :dword arg height:dword */ __asm { xor eax,eax mov ebx,[x] mov edi,[w] mov esi,[ebx] add edi,[ebx] sub edi,[width] neg esi dec edi test esi,edi jl x_axix_ok mov eax,1 test esi,esi jl shift_right mov [dword ptr ebx],0 jmp x_axix_ok shift_right: inc edi sub [ebx],edi x_axix_ok: mov ebx,[y] mov edi,[h] mov esi,[ebx] add edi,[ebx] sub edi,[height] neg esi dec edi test esi,edi jl confi_out mov eax,1 test esi,esi jl shift_top mov [dword ptr ebx],0 //ret jmp confi_out shift_top: inc edi sub [ebx],edi confi_out: //ret //ENDP Confine_Rect } } /* ; $Header: //depot/Projects/Mobius/QA/Project/Run/SOURCECODE/REDALERT/WIN32LIB/DrawMisc.cpp#138 $ ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Library routine * ;* * ;* File Name : UNCOMP.ASM * ;* * ;* Programmer : Christopher Yates * ;* * ;* Last Update : 20 August, 1990 [CY] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* * ; ULONG LCW_Uncompress(BYTE *source, BYTE *dest, ULONG length); * ;* * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT GLOBAL C LCW_Uncompress :NEAR CODESEG ; ---------------------------------------------------------------- ; ; Here are prototypes for the routines defined within this module: ; ; ULONG LCW_Uncompress(BYTE *source, BYTE *dest, ULONG length); ; ; ---------------------------------------------------------------- */ #if (0)//ST 5/10/2019 extern "C" unsigned long __cdecl LCW_Uncompress(void *source, void *dest, unsigned long length_) { //PROC LCW_Uncompress C near // // USES ebx,ecx,edx,edi,esi // // ARG source:DWORD // ARG dest:DWORD // ARG length:DWORD //;LOCALS // LOCAL a1stdest:DWORD // LOCAL maxlen:DWORD // LOCAL lastbyte:DWORD // LOCAL lastcom:DWORD // LOCAL lastcom1:DWORD unsigned long a1stdest; unsigned long maxlen; unsigned long lastbyte; //unsigned long lastcom; //unsigned long lastcom1; __asm { mov edi,[dest] mov esi,[source] mov edx,[length_] ; ; ; uncompress data to the following codes in the format b = byte, w = word ; n = byte code pulled from compressed data ; Bit field of n command description ; n=0xxxyyyy,yyyyyyyy short run back y bytes and run x+3 ; n=10xxxxxx,n1,n2,...,nx+1 med length copy the next x+1 bytes ; n=11xxxxxx,w1 med run run x+3 bytes from offset w1 ; n=11111111,w1,w2 long copy copy w1 bytes from offset w2 ; n=11111110,w1,b1 long run run byte b1 for w1 bytes ; n=10000000 end end of data reached ; mov [a1stdest],edi add edx,edi mov [lastbyte],edx cld ; make sure all lod and sto are forward mov ebx,esi ; save the source offset loop_label: mov eax,[lastbyte] sub eax,edi ; get the remaining byte to uncomp jz short out_label ; were done mov [maxlen],eax ; save for string commands mov esi,ebx ; mov in the source index xor eax,eax mov al,[esi] inc esi test al,al ; see if its a short run js short notshort mov ecx,eax ;put count nibble in cl mov ah,al ; put rel offset high nibble in ah and ah,0Fh ; only 4 bits count shr cl,4 ; get run -3 add ecx,3 ; get actual run length cmp ecx,[maxlen] ; is it too big to fit? jbe short rsok ; if not, its ok mov ecx,[maxlen] ; if so, max it out so it dosen't overrun rsok: mov al,[esi] ; get rel offset low byte lea ebx,[esi+1] ; save the source offset mov esi,edi ; get the current dest sub esi,eax ; get relative offset rep movsb jmp loop_label notshort: test al,40h ; is it a length? jne short notlength ; if not it could be med or long run cmp al,80h ; is it the end? je short out_label ; if so its over mov cl,al ; put the byte in count register and ecx,3Fh ; and off the extra bits cmp ecx,[maxlen] ; is it too big to fit? jbe short lenok ; if not, its ok mov ecx,[maxlen] ; if so, max it out so it dosen't overrun lenok: rep movsb mov ebx,esi ; save the source offset jmp loop_label out_label: mov eax,edi sub eax,[a1stdest] jmp label_exit notlength: mov cl,al ; get the entire code and ecx,3Fh ; and off all but the size -3 add ecx,3 ; add 3 for byte count cmp al,0FEh jne short notrunlength xor ecx,ecx mov cx,[esi] xor eax,eax mov al,[esi+2] lea ebx,[esi+3] ;save the source offset cmp ecx,[maxlen] ; is it too big to fit? jbe short runlenok ; if not, its ok mov ecx,[maxlen] ; if so, max it out so it dosen't overrun runlenok: test ecx,0ffe0h jnz dont_use_stosb rep stosb jmp loop_label dont_use_stosb: mov ah,al mov edx,eax shl eax,16 or eax,edx test edi,3 jz aligned mov [edi],eax mov edx,edi and edi,0fffffffch lea edi,[edi+4] and edx,3 dec dl xor dl,3 sub ecx,edx aligned: mov edx,ecx shr ecx,2 rep stosd and edx,3 jz loop_label mov ecx,edx rep stosb jmp loop_label notrunlength: cmp al,0FFh ; is it a long run? jne short notlong ; if not use the code as the size xor ecx,ecx xor eax,eax mov cx,[esi] ; if so, get the size lea esi,[esi+2] notlong: mov ax,[esi] ;get the real index add eax,[a1stdest] ;add in the 1st index lea ebx,[esi+2] ;save the source offset cmp ecx,[maxlen] ;compare for overrun mov esi,eax ;use eax as new source jbe short runok ; if not, its ok mov ecx,[maxlen] ; if so, max it out so it dosen't overrun runok: test ecx,0ffe0h jnz dont_use_movsb rep movsb jmp loop_label dont_use_movsb: lea edx,[edi+0fffffffch] cmp esi,edx ja use_movsb test edi,3 jz aligned2 mov eax,[esi] mov [edi],eax mov edx,edi and edi,0fffffffch lea edi,[edi+4] and edx,3 dec dl xor dl,3 sub ecx,edx add esi,edx aligned2: mov edx,ecx shr ecx,2 and edx,3 rep movsd mov ecx,edx use_movsb: rep movsb jmp loop_label label_exit: mov eax,edi mov ebx,[dest] sub eax,ebx //ret } } #endif /* ;*************************************************************************** ;** C O N F I D E N T I A L --- W E S T W O O D A S S O C I A T E S ** ;*************************************************************************** ;* * ;* Project Name : Westwood 32 bit Library * ;* * ;* File Name : TOPAGE.ASM * ;* * ;* Programmer : Phil W. Gorrow * ;* * ;* Start Date : June 8, 1994 * ;* * ;* Last Update : June 15, 1994 [PWG] * ;* * ;*-------------------------------------------------------------------------* ;* Functions: * ;* Buffer_To_Page -- Copies a linear buffer to a virtual viewport * ;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - * IDEAL P386 MODEL USE32 FLAT TRANSP equ 0 INCLUDE ".\drawbuff.inc" INCLUDE ".\gbuffer.inc" CODESEG ;*************************************************************************** ;* VVC::TOPAGE -- Copies a linear buffer to a virtual viewport * ;* * ;* INPUT: WORD x_pixel - x pixel on viewport to copy from * ;* WORD y_pixel - y pixel on viewport to copy from * ;* WORD pixel_width - the width of copy region * ;* WORD pixel_height - the height of copy region * ;* BYTE * src - buffer to copy from * ;* VVPC * dest - virtual viewport to copy to * ;* * ;* OUTPUT: none * ;* * ;* WARNINGS: Coordinates and dimensions will be adjusted if they exceed * ;* the boundaries. In the event that no adjustment is * ;* possible this routine will abort. If the size of the * ;* region to copy exceeds the size passed in for the buffer * ;* the routine will automatically abort. * ;* * ;* HISTORY: * ;* 06/15/1994 PWG : Created. * ;*=========================================================================* */ extern "C" long __cdecl Buffer_To_Page(int x_pixel, int y_pixel, int pixel_width, int pixel_height, void *src, void *dest) { /* PROC Buffer_To_Page C near USES eax,ebx,ecx,edx,esi,edi ;*=================================================================== ;* define the arguements that our function takes. ;*=================================================================== ARG x_pixel :DWORD ; x pixel position in source ARG y_pixel :DWORD ; y pixel position in source ARG pixel_width :DWORD ; width of rectangle to blit ARG pixel_height:DWORD ; height of rectangle to blit ARG src :DWORD ; this is a member function ARG dest :DWORD ; what are we blitting to ; ARG trans :DWORD ; do we deal with transparents? ;*=================================================================== ; Define some locals so that we can handle things quickly ;*=================================================================== LOCAL x1_pixel :dword LOCAL y1_pixel :dword local scr_x : dword local scr_y : dword LOCAL dest_ajust_width:DWORD LOCAL scr_ajust_width:DWORD LOCAL dest_area : dword */ unsigned long x1_pixel; unsigned long y1_pixel; unsigned long scr_x; unsigned long scr_y; unsigned long dest_ajust_width; unsigned long scr_ajust_width; //unsigned long dest_area; __asm { cmp [ src ] , 0 jz real_out ; Clip dest Rectangle against source Window boundaries. mov [ scr_x ] , 0 mov [ scr_y ] , 0 mov esi , [ dest ] ; get ptr to dest xor ecx , ecx xor edx , edx mov edi , [esi]GraphicViewPortClass.Width ; get width into register mov ebx , [ x_pixel ] mov eax , [ x_pixel ] add ebx , [ pixel_width ] shld ecx , eax , 1 mov [ x1_pixel ] , ebx inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 mov edi, [esi]GraphicViewPortClass.Height ; get height into register mov ebx , [ y_pixel ] mov eax , [ y_pixel ] add ebx , [ pixel_height ] shld ecx , eax , 1 mov [ y1_pixel ] , ebx inc edi shld edx , ebx , 1 sub eax , edi sub ebx , edi shld ecx , eax , 1 shld edx , ebx , 1 xor cl , 5 xor dl , 5 mov al , cl test dl , cl jnz real_out or al , dl jz do_blit test cl , 1000b jz dest_left_ok mov eax , [ x_pixel ] neg eax mov [ x_pixel ] , 0 mov [ scr_x ] , eax dest_left_ok: test cl , 0010b jz dest_bottom_ok mov eax , [ y_pixel ] neg eax mov [ y_pixel ] , 0 mov [ scr_y ] , eax dest_bottom_ok: test dl , 0100b jz dest_right_ok mov eax , [esi]GraphicViewPortClass.Width ; get width into register mov [ x1_pixel ] , eax dest_right_ok: test dl , 0001b jz do_blit mov eax , [esi]GraphicViewPortClass.Height ; get width into register mov [ y1_pixel ] , eax do_blit: cld mov eax , [esi]GraphicViewPortClass.XAdd add eax , [esi]GraphicViewPortClass.Width add eax , [esi]GraphicViewPortClass.Pitch mov edi , [esi]GraphicViewPortClass.Offset mov ecx , eax mul [ y_pixel ] add edi , [ x_pixel ] add edi , eax add ecx , [ x_pixel ] sub ecx , [ x1_pixel ] mov [ dest_ajust_width ] , ecx mov esi , [ src ] mov eax , [ pixel_width ] sub eax , [ x1_pixel ] add eax , [ x_pixel ] mov [ scr_ajust_width ] , eax mov eax , [ scr_y ] mul [ pixel_width ] add eax , [ scr_x ] add esi , eax mov edx , [ y1_pixel ] mov eax , [ x1_pixel ] sub edx , [ y_pixel ] jle real_out sub eax , [ x_pixel ] jle real_out ; ******************************************************************** ; Forward bitblit only //IF TRANSP // test [ trans ] , 1 // jnz forward_Blit_trans //ENDIF ; the inner loop is so efficient that ; the optimal consept no longer apply because ; the optimal byte have to by a number greather than 9 bytes cmp eax , 10 jl forward_loop_bytes forward_loop_dword: mov ecx , edi mov ebx , eax neg ecx and ecx , 3 sub ebx , ecx rep movsb mov ecx , ebx shr ecx , 2 rep movsd mov ecx , ebx and ecx , 3 rep movsb add esi , [ scr_ajust_width ] add edi , [ dest_ajust_width ] dec edx jnz forward_loop_dword jmp real_out //ret forward_loop_bytes: mov ecx , eax rep movsb add esi , [ scr_ajust_width ] add edi , [ dest_ajust_width ] dec edx ; decrement the height jnz forward_loop_bytes // ret //IF TRANSP // // //forward_Blit_trans: // // // mov ecx , eax // and ecx , 01fh // lea ecx , [ ecx + ecx * 4 ] // neg ecx // shr eax , 5 // lea ecx , [ transp_reference + ecx * 2 ] // mov [ y1_pixel ] , ecx // // //forward_loop_trans: // mov ecx , eax // jmp [ y1_pixel ] //forward_trans_line: // REPT 32 // local transp_pixel // mov bl , [ esi ] // inc esi // test bl , bl // jz transp_pixel // mov [ edi ] , bl // transp_pixel: // inc edi // ENDM // transp_reference: // dec ecx // jge forward_trans_line // add esi , [ scr_ajust_width ] // add edi , [ dest_ajust_width ] // dec edx // jnz forward_loop_trans // ret //ENDIF real_out: //ret } } //ENDP Buffer_To_Page //END /* ;*************************************************************************** ;* VVPC::GET_PIXEL -- Gets a pixel from the current view port * ;* * ;* INPUT: WORD the x pixel on the screen. * ;* WORD the y pixel on the screen. * ;* * ;* OUTPUT: UBYTE the pixel at the specified location * ;* * ;* WARNING: If pixel is to be placed outside of the viewport then * ;* this routine will abort. * ;* * ;* HISTORY: * ;* 06/07/1994 PWG : Created. * ;*=========================================================================* PROC Buffer_Get_Pixel C near USES ebx,ecx,edx,edi ARG this_object:DWORD ; this is a member function ARG x_pixel:DWORD ; x position of pixel to set ARG y_pixel:DWORD ; y position of pixel to set */ extern "C" int __cdecl Buffer_Get_Pixel(void * this_object, int x_pixel, int y_pixel) { __asm { ;*=================================================================== ; Get the viewport information and put bytes per row in ecx ;*=================================================================== mov ebx,[this_object] ; get a pointer to viewport xor eax,eax mov edi,[ebx]GraphicViewPortClass.Offset ; get the correct offset mov ecx,[ebx]GraphicViewPortClass.Height ; edx = height of viewport mov edx,[ebx]GraphicViewPortClass.Width ; ecx = width of viewport ;*=================================================================== ; Verify that the X pixel offset if legal ;*=================================================================== mov eax,[x_pixel] ; find the x position cmp eax,edx ; is it out of bounds jae short exit_label ; if so then get out add edi,eax ; otherwise add in offset ;*=================================================================== ; Verify that the Y pixel offset if legal ;*=================================================================== mov eax,[y_pixel] ; get the y position cmp eax,ecx ; is it out of bounds jae exit_label ; if so then get out add edx,[ebx]GraphicViewPortClass.XAdd ; otherwise find bytes per row add edx,[ebx]GraphicViewPortClass.Pitch ; otherwise find bytes per row mul edx ; offset = bytes per row * y add edi,eax ; add it into the offset ;*=================================================================== ; Write the pixel to the screen ;*=================================================================== xor eax,eax ; clear the word mov al,[edi] ; read in the pixel exit_label: //ret //ENDP Buffer_Get_Pixel } }